Browse Source

'message'

machinecat520 1 year ago
commit
0e18c32926
92 changed files with 11499 additions and 0 deletions
  1. 3 0
      education_uni/.gitignore
  2. 16 0
      education_uni/.hbuilderx/launch.json
  3. 36 0
      education_uni/App.vue
  4. 321 0
      education_uni/components/my-coursedetail/my-coursedetail.vue
  5. 125 0
      education_uni/components/my-invite/my-invite.vue
  6. 225 0
      education_uni/components/my-login/my-login.vue
  7. 311 0
      education_uni/components/my-requiredetail/my-requiredetail.vue
  8. 221 0
      education_uni/components/my-userinfo/my-userinfo.vue
  9. 423 0
      education_uni/components/xb-swiper-preview/index.vue
  10. 20 0
      education_uni/index.html
  11. 74 0
      education_uni/main.js
  12. 69 0
      education_uni/manifest.json
  13. 15 0
      education_uni/mixins/compute-distance.js
  14. 142 0
      education_uni/mixins/form-time.js
  15. 36 0
      education_uni/mixins/tabbar-badge.js
  16. 39 0
      education_uni/package-lock.json
  17. 16 0
      education_uni/package.json
  18. 330 0
      education_uni/pages.json
  19. 428 0
      education_uni/pages/home/home.vue
  20. 38 0
      education_uni/pages/message/message.vue
  21. 43 0
      education_uni/pages/my/my.vue
  22. 368 0
      education_uni/pages/student/student.vue
  23. 438 0
      education_uni/pages/teacher/teacher.vue
  24. BIN
      education_uni/static/authorized.png
  25. BIN
      education_uni/static/authorizedd.png
  26. BIN
      education_uni/static/avatar-msg.png
  27. BIN
      education_uni/static/avatar.png
  28. BIN
      education_uni/static/boy.png
  29. 20 0
      education_uni/static/customicons.css
  30. BIN
      education_uni/static/customicons.ttf
  31. BIN
      education_uni/static/girl.png
  32. BIN
      education_uni/static/hot.png
  33. BIN
      education_uni/static/location.png
  34. BIN
      education_uni/static/official_account.jpg
  35. BIN
      education_uni/static/right.png
  36. BIN
      education_uni/static/rightwhite.png
  37. BIN
      education_uni/static/share.jpg
  38. BIN
      education_uni/static/tab_icons/home.png
  39. BIN
      education_uni/static/tab_icons/home_active.png
  40. BIN
      education_uni/static/tab_icons/message.png
  41. BIN
      education_uni/static/tab_icons/message_active.png
  42. BIN
      education_uni/static/tab_icons/my.png
  43. BIN
      education_uni/static/tab_icons/my_active.png
  44. BIN
      education_uni/static/tab_icons/student.png
  45. BIN
      education_uni/static/tab_icons/student_active.png
  46. BIN
      education_uni/static/tab_icons/teacher.png
  47. BIN
      education_uni/static/tab_icons/teacher_active.png
  48. BIN
      education_uni/static/xb-swiper-preview/icon-back.png
  49. 21 0
      education_uni/store/store.js
  50. 68 0
      education_uni/store/user.js
  51. 185 0
      education_uni/subpkg/manager/complaint/manager_complaint.vue
  52. 257 0
      education_uni/subpkg/manager/complaint/manager_complaint_detail.vue
  53. 225 0
      education_uni/subpkg/manager/complaint/manager_complaint_handle.vue
  54. 82 0
      education_uni/subpkg/manager/manager.vue
  55. 185 0
      education_uni/subpkg/manager/suggestion/manager_suggestion.vue
  56. 248 0
      education_uni/subpkg/manager/suggestion/manager_suggestion_detail.vue
  57. 218 0
      education_uni/subpkg/manager/suggestion/manager_suggestion_handle.vue
  58. 166 0
      education_uni/subpkg/my/complaint/my_complaint.vue
  59. 141 0
      education_uni/subpkg/my/complaint/my_complaint_detail.vue
  60. 164 0
      education_uni/subpkg/my/complaint/my_complaint_write.vue
  61. 17 0
      education_uni/subpkg/my/home/my_home_strategy.vue
  62. 179 0
      education_uni/subpkg/my/invitation/my_invitation_receive.vue
  63. 232 0
      education_uni/subpkg/my/invitation/my_invitation_receive_detail.vue
  64. 188 0
      education_uni/subpkg/my/invitation/my_invitation_send.vue
  65. 145 0
      education_uni/subpkg/my/invitation/my_invitation_send_detail.vue
  66. 96 0
      education_uni/subpkg/my/message/my_message_detail.vue
  67. 32 0
      education_uni/subpkg/my/official_account/my_official_account.vue
  68. 117 0
      education_uni/subpkg/my/order/my_order.vue
  69. 339 0
      education_uni/subpkg/my/order/my_order_detail.vue
  70. 60 0
      education_uni/subpkg/my/share/my_share.vue
  71. 134 0
      education_uni/subpkg/my/share/my_share_result.vue
  72. 189 0
      education_uni/subpkg/my/share/my_share_result_order.vue
  73. 220 0
      education_uni/subpkg/my/share/my_share_result_order_detail.vue
  74. 165 0
      education_uni/subpkg/my/suggestion/my_suggestion.vue
  75. 143 0
      education_uni/subpkg/my/suggestion/my_suggestion_detail.vue
  76. 169 0
      education_uni/subpkg/my/suggestion/my_suggestion_write.vue
  77. 127 0
      education_uni/subpkg/my/user/my_user_detail.vue
  78. 276 0
      education_uni/subpkg/student/order/student_order_detail.vue
  79. 647 0
      education_uni/subpkg/student/require/student_require_add.vue
  80. 141 0
      education_uni/subpkg/student/require/student_require_all_detail.vue
  81. 163 0
      education_uni/subpkg/student/require/student_require_my_collect.vue
  82. 68 0
      education_uni/subpkg/student/require/student_require_my_detail.vue
  83. 146 0
      education_uni/subpkg/student/require/student_require_my_publish.vue
  84. 135 0
      education_uni/subpkg/teacher/authentication/teacher_authentication.vue
  85. 356 0
      education_uni/subpkg/teacher/authentication/teacher_authentication_add.vue
  86. 218 0
      education_uni/subpkg/teacher/authentication/teacher_authentication_detail.vue
  87. 543 0
      education_uni/subpkg/teacher/course/teacher_course_add.vue
  88. 150 0
      education_uni/subpkg/teacher/course/teacher_course_all_detail.vue
  89. 180 0
      education_uni/subpkg/teacher/course/teacher_course_my_collect.vue
  90. 67 0
      education_uni/subpkg/teacher/course/teacher_course_my_detail.vue
  91. 139 0
      education_uni/subpkg/teacher/course/teacher_course_my_publish.vue
  92. 1 0
      education_uni/uni.scss

+ 3 - 0
education_uni/.gitignore

@@ -0,0 +1,3 @@
+/node_modules
+/unpackage/dist
+/uni_modules

+ 16 - 0
education_uni/.hbuilderx/launch.json

@@ -0,0 +1,16 @@
+{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
+  // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
+    "version": "0.0",
+    "configurations": [{
+     	"default" : 
+     	{
+     		"launchtype" : "local"
+     	},
+     	"mp-weixin" : 
+     	{
+     		"launchtype" : "local"
+     	},
+     	"type" : "uniCloud"
+     }
+    ]
+}

+ 36 - 0
education_uni/App.vue

@@ -0,0 +1,36 @@
+<script>
+	export default {
+		onLaunch: function() {
+		
+		},
+		onShow: function() {
+		},
+		onHide: function() {
+			console.log('App Hide')
+		},
+		methods: {
+		}
+	}
+</script>
+
+<style lang="scss">
+	/*每个页面公共css */
+	@import '@/uni_modules/uni-scss/index.scss';
+	/* #ifndef APP-NVUE */
+	@import '@/static/customicons.css';
+	// 设置整个项目的背景色
+	page {
+		background-color: #f0f0f0;
+		height: 100%;
+	}
+	uni-page-body,html,body{  
+        height: 100%;  
+    }  
+	/* #endif */
+	.example-info {
+		font-size: 14px;
+		color: #333;
+		padding: 10px;
+	}
+
+</style>

+ 321 - 0
education_uni/components/my-coursedetail/my-coursedetail.vue

@@ -0,0 +1,321 @@
+<template>
+		<view class="contain">
+			<uni-row>
+				<view style="height: 20rpx;"></view>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<view class="contain-item"><text class="contain-text">课程号:</text>{{item.courseId}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :span="15" :push="1">
+					<uni-row>
+						<uni-col>
+							<view class="contain-item"><text class="contain-text">教员ID:</text>{{item.uid}}</view>
+						</uni-col>
+					</uni-row>
+					<uni-row>
+						<uni-col>
+							<view class="contain-item"><text class="contain-text">教员:</text>{{item.name}}</view>
+						</uni-col>
+					</uni-row>
+					<uni-row>
+						<uni-col>
+							<view class="contain-item"><text class="contain-text">教员性别:</text>{{item.sex}}</view>
+						</uni-col>
+					</uni-row>
+					<uni-row>
+						<uni-col>
+							<view class="contain-item"><text class="contain-text">教龄:</text>{{item.teachAge}}年</view>
+						</uni-col>
+					</uni-row>
+					<uni-row>
+						<uni-col>
+							<view class="contain-item"><text class="contain-text">浏览量:</text>{{item.viewedCount}}次</view>
+						</uni-col>
+					</uni-row>
+				</uni-col>
+				<uni-col :span="8">
+					<uni-row>
+						<image class="teachImg" :mode="aspectFit" :src="item.profilePhoto"></image>
+					</uni-row>
+					<uni-row v-if="isShowCollect">
+						<uni-fav :checked="collect" class="favBtn" :circle="true" bg-color="#dd524d"
+											bg-color-checked="#007aff" fg-color="#ffffff" fg-color-checked="#ffffff" @click="collecting" />
+					</uni-row>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<view class="contain-item">
+					<map :longitude="location[1]" :latitude="location[0]" :markers="marker" class="map"></map>
+				</view>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<view class="contain-item"><text class="contain-text">辅导科目:</text>{{item.subject}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<view class="contain-addr-item"><text class="contain-text">教员地址:</text>{{item.location}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<text class="contain-text">课程时间:</text>
+				</uni-col>
+			</uni-row>
+			<view class="tr-container">
+				<view class="tr_1">
+					<text class="th_0" decode="true">&ensp;&ensp;&ensp;&ensp;</text>
+					<text class="th_1">周一</text>
+					<text class="th_1">周二</text>
+					<text class="th_1">周三</text>
+					<text class="th_1">周四</text>
+					<text class="th_1">周五</text>
+					<text class="th_1">周六</text>
+					<text class="th_1">周日</text>
+				</view>
+				<view class="tr_2">
+					<checkbox-group>
+						<view class="th2_0">上午</view>
+						<label v-for="item in timeAM" :key="item.value">
+							<checkbox class="th2_1" :value="item.value" :checked="item.checked" disabled></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+				<view class="tr_2">
+					<checkbox-group>
+						<view class="th2_0">下午</view>
+						<label v-for="item in timePM" :key="item.value">
+							<checkbox class="th2_1" :value="item.value" :checked="item.checked" disabled></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+				<view class="tr_2">
+					<checkbox-group>
+						<view class="th2_0">晚上</view>
+						<label v-for="item in timeEvening" :key="item.value">
+						<checkbox class="th2_1" :value="item.value" :checked="item.checked" disabled></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+			</view>
+			<uni-row>
+				<uni-col :span="12" :push="1">
+					<view class="contain-item"><text class="contain-text">教员类型:</text>{{item.teacherType}}</view>
+				</uni-col>
+				<uni-col :span="12">
+					<view><text class="contain-text">教员学历:</text>{{item.education}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<view class="contain-item"><text class="contain-text">上课方式:</text>{{item.mode}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<view class="contain-item"><text class="contain-text">成功经验:</text>{{item.experience}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<view class="contain-item"><text class="contain-text">自我描述:</text>{{item.introduce}}</view>
+				</uni-col>
+			</uni-row>
+			<view v-if="isShowPrivate">
+				<uni-row>
+					<uni-col :push="1">
+						<view class="contain-item"><text class="contain-text">审核不通过原因:</text>{{item.verifyRefuseReason || '暂无'}}</view>
+					</uni-col>
+				</uni-row>
+				<uni-row>
+					<uni-col :push="1">
+						<view class="contain-item"><text class="contain-text">本课程发布日期:</text>{{item.datetime}}</view>
+					</uni-col>
+				</uni-row>
+			</view>
+			
+			<view class="publish-button-wrapper">
+				<button class="publish-button" @click="publishButton">{{buttonMessage}}</button>
+			</view>
+			
+		</view>
+</template>
+
+<script>
+	import { mapState } from 'vuex';
+	
+	export default {
+		name: 'my-requiredetail',
+		data() {
+			return {
+			};
+		},
+		props: {
+			item: {
+				type: Object
+			},
+			location: {
+				type: Array
+			},
+			marker: {
+				type: Array
+			},
+			timeAM: {
+				type: Array
+			},
+			timePM: {
+				type: Array
+			},
+			timeEvening: {
+				type: Array
+			},
+			collect: {
+				type: Boolean,
+				default: false
+			},
+			isShowCollect: {
+				type: Boolean,
+				default: false
+			},
+			isShowPrivate: {
+				type: Boolean,
+				default: false
+			},
+			buttonMessage: {
+				type: String
+			}
+		},
+		methods: {
+			// 点击收藏
+			collecting() {
+				// 触发外界通过 @click 绑定的 click 事件处理函数
+				this.$emit('collecting')
+			},
+			publishButton() {
+				this.$emit('publishButton')
+			}
+		},
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+
+.contain {
+	//background-color: #FFF2CC;
+	background-color: #f0f0f0;
+	// border-radius: 10%;
+	border-radius: 20rpx;
+	height: 100%;
+	
+	.contain-item {
+		margin-bottom: 20rpx;
+	}
+	
+	.contain-addr-item{
+		margin-bottom: 20rpx;
+		width: 96%;
+	}
+	
+	.contain-text {
+		font-weight: 700;
+		color: #bbb;
+	}
+	
+	.map {
+		width: 100%;
+	}
+}
+.tr-container{
+	    display: flex;
+	    position: relative;
+	    width: 96%;
+	    flex-direction: column;
+	    font-size: 26rpx;
+	    /* border: 1rpx solid gray; */
+	    margin: -10px 20rpx;
+		margin-bottom: 20px;
+	}
+	
+	.tr_1 {
+	    display: flex;
+	    position: relative;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	}
+	.tr_2{
+	    display: block;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	}
+	
+	.th_0,
+	.th_1,
+	.th_2,
+	.th2_0,
+	.th2_1,
+	.th2_2{
+	    width: 12%;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	    border-right: 1rpx solid gray;
+	    border-bottom: 1rpx solid gray;
+	    text-align: center;
+	}
+	
+	.th_0,
+	.th_1,
+	.th_2{
+	    border-top: 1rpx solid gray;
+	}
+	
+	.th_0,
+	.th2_0{
+	    border-left: 1rpx solid gray;
+	}
+	
+	.th2_0{
+	    float: left;
+	    width: 12%;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	    text-align: center;
+	    /* background-color: greenyellow; */
+	}
+	
+	// 底部按钮
+	.publish-button-wrapper{
+		margin-top: 10rpx;
+		height: 130rpx;
+	}	
+	.publish-button {
+		//background-color: #E2F0D9;
+		// background-color: #8FAADC;
+		background-color: #35b882;
+		color: white;
+		width: 200rpx;
+		border-radius: 50rpx;
+		margin-bottom: 60rpx;
+	}
+	
+	/* 教员头像 */
+	.teachImg{
+	    width: 250rpx;
+		height: 250rpx;
+	    border-radius: 20rpx;
+	}
+	
+
+	
+</style>

+ 125 - 0
education_uni/components/my-invite/my-invite.vue

@@ -0,0 +1,125 @@
+<template>
+	<view>
+		<!-- 蒙层 -->
+		<view class="maskWrapper" v-if="isShowInvite">
+		    <view>
+		        <text>请您从下方列表中,选中一条课程或需求信息,作为邀请的具体内容,发给对方!</text>
+		    </view>
+		    <scroll-view class="scrollVertical" scroll-y>
+		        <radio-group class="chooseList">
+					<view v-for="(item, index) in item11" :key="index">
+						<radio class="chooseDetail" @click="clickRadio(item)">
+						    <view class="courseTitle">
+						        <text>课程号</text>
+						        <text class="courseDetail" v-if="item.courseId">{{item.courseId}}</text>
+								<text class="courseDetail" v-if="item.requireId">{{item.requireId}}</text>
+						    </view>
+						    <view class="courseTitle">
+						        <text>辅导科目</text>
+								<text class="courseDetail" v-if="item.subject">{{item.subject}}</text>
+						        <text class="courseDetail" v-else>{{item.subjectBig}}/{{item.subjectSmall}}</text>
+						    </view>
+						</radio>
+					</view>
+		
+		        </radio-group>
+		    </scroll-view>
+		    <view class="commitAndCancel">
+		        <view class="cancel" @click="cancelChosed">取消</view>
+		        <view class="commit" @click="commitChosed">发送</view>
+		    </view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name:"my-invite",
+		data() {
+			return {
+			};
+		},
+		props: {
+			isShowInvite: {
+				type: Boolean,
+				default: false
+			},
+			item11: {
+				type: Array
+			}
+		},
+		methods: {
+			cancelChosed() {
+				this.$emit("cancelChosed")
+			},
+			commitChosed() {
+				this.$emit("commitChosed")
+			},
+			clickRadio(course) {
+				this.$emit("clickRadio", course)
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+/* 以下是蒙层样式 */
+
+.maskWrapper{
+    z-index: 999;    
+    // margin-left: -20rpx;
+    padding-left: 20rpx;
+    position: fixed;
+    height: 55%;
+    bottom: 0;
+    background-color: #D1D1D1;
+    border-top-left-radius: 30rpx;
+    border-top-right-radius: 30rpx;
+}
+/* 可滚动区域 */
+.scrollVertical{
+    height: 76%;
+}
+
+/* 选项区 */
+.chooseList{
+    display: flex;
+    flex-direction: column;
+}
+/* 单个选项样式 */
+.chooseDetail{
+    width: 94%;
+    padding: 10rpx;
+    margin: 10rpx 0;
+    border: 1rpx solid gray;
+    border-radius: 20rpx;
+    background-color: #DEEBF7;
+}
+/* 设置选项与圆圈的距离 */
+.courseTitle{
+    margin-left: 30rpx;
+}
+/* 课程号、辅导科目详情 */
+.courseDetail{
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+/* 底部按钮 */
+.commitAndCancel{
+    display: flex;
+    width: 100%;
+    justify-content: space-around;
+    position: fixed;
+    bottom: 40rpx;
+}
+.cancel,
+.commit{
+    font-size: 40rpx;
+    border: 1rpx solid gray;
+    padding: 10rpx 60rpx;
+    border-radius: 40rpx;
+    background-color: #8FAADC;
+    color: white;
+}
+
+</style>

+ 225 - 0
education_uni/components/my-login/my-login.vue

@@ -0,0 +1,225 @@
+<template>
+		<view class="login-container">
+			<!-- 提示登录的图标 -->
+			<uni-icons type="contact-filled" size="100" color="#AFAFAF"></uni-icons>
+			<!-- 登录按钮 -->
+			<button type="primary" class="btn-login" @click="getToken">一键登录</button>		
+			<!-- 登录提示 -->
+			<view class="tips-text">登录后尽享更多权益</view>
+		</view>
+
+</template>
+
+<script>
+	// 按需导入 mapMutations 辅助函数
+	import { mapMutations, mapState } from 'vuex'
+	
+	export default {
+		computed: {
+			...mapState('m_user', ['recoUID']),
+		},
+		name:"my-login",
+		data() {
+			return {
+				queryObj: {
+					latitude: 0,
+					longitude: 0
+				}
+			};
+		},
+		methods: {
+			// 调用 mapMutations 辅助方法,把 m_user 模块中的 updateUserInfo 映射到当前组件中使用
+			...mapMutations('m_user', ['updateUserInfo', 'updateToken', 'updateLocation']),
+			
+			// 引导用户开启位置权限
+			openSetting() {
+				var that = this
+				wx.showModal({
+					title: '位置信息',
+					content: '开启后将为你推送最近的资源',
+					showCancel: true,
+					cancelText: '取消',
+					cancelColor: '#000000',
+					confirmText: '开启',
+					confirmColor: '#3CC51F',
+					success: res => {
+						if (res.confirm) {
+							wx.openSetting({
+								success(res) {
+									if (res.authSetting['scope.userFuzzyLocation']) {
+										
+										// 获取经纬度
+										wx.getFuzzyLocation({
+											type: 'wgs84',
+											success (res) {
+											   that.queryObj.latitude = res.latitude
+											   that.queryObj.longitude = res.longitude
+											   that.updateLocation(that.queryObj)
+											   that.getLogin()
+											}
+										})
+									}
+								},
+								fail(res) {
+									uni.$showMsg(res)
+								}
+							})
+						} else if(res.cancel) {
+							uni.$showMsg("需要位置权限")
+						}
+					}
+				})
+			},
+			
+			// 调用登录接口,换取永久的 token
+			async getToken() {
+				var that = this
+			
+				// 获取位置信息
+				wx.getSetting({
+					success(res) {
+						if (!res.authSetting['scope.userFuzzyLocation']) {
+							wx.authorize({
+								scope: 'scope.userFuzzyLocation',
+								success() {
+									// 获取经纬度
+									wx.getFuzzyLocation({
+										type: 'wgs84',
+										success (res) {
+										   that.queryObj.latitude = res.latitude
+										   that.queryObj.longitude = res.longitude
+										   that.updateLocation(that.queryObj)
+										   that.getLogin()
+										}
+									})
+								},
+								fail() {
+									// 拒绝后引导用户开启
+									if (wx.openSetting) {
+										that.openSetting()
+									}
+									return
+								}
+							})
+						} else {
+							// 获取经纬度
+							wx.getFuzzyLocation({
+								type: 'wgs84',
+								success (res) {
+								   that.queryObj.latitude = res.latitude
+								   that.queryObj.longitude = res.longitude
+								   that.updateLocation(that.queryObj)
+								   that.getLogin()
+								}
+							})
+							that.getLogin()
+						}
+					}
+				})
+			},
+			
+			// 真正的登录逻辑
+			async getLogin() {
+				
+				// 调用微信登录接口
+				const [err, res] = await uni.login().catch(err => err)
+				// 判断是否 wx.login() 调用失败
+				if (err || res.errMsg !== 'login:ok') return uni.$showError('登录失败!')
+				// 准备参数对象
+				const query = {
+					code: res.code,
+					recoUID: this.recoUID
+				}
+				
+				// 换取 token
+				const { data: loginResult } = await uni.$http.get('/ucenter/mini-program-openid-uid/wxlogin', query)
+				if (loginResult.code === 20000) {
+					uni.$showMsg('登录成功!')
+				}
+				
+				// 更新vuex中的token
+				this.updateToken(loginResult.data.token)
+				
+				// // 将用户的基本信息存储到 vuex 中
+				if (loginResult.data.avatar === '') {
+					loginResult.data.avatar = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/'
+				}
+				const userInfo = {
+					alias: loginResult.data.alias,
+					avatar: loginResult.data.avatar,
+					city: loginResult.data.city,
+					uid: loginResult.data.uid,
+					count: loginResult.data.count,
+					isAdmin: loginResult.data.isAdmin
+				}
+				this.updateUserInfo(userInfo)
+				
+				let SocketTask = wx.connectSocket({
+					url: `${uni.$wsLocation}/education/chat?uid=`+userInfo.uid,
+					success(res) {
+						console.log("开始连接",res)
+						if (userInfo.count == 0) {
+							uni.removeTabBarBadge({
+								index: 2
+							})
+						} else {
+							// 调用 uni.setTabBarBadge() 方法,为购物车设置右上角的徽标
+							uni.setTabBarBadge({
+								index: 2,
+								text: userInfo.count + '', // 注意:text 的值必须是字符串,不能是数字
+							})
+						}
+					}
+				})
+				SocketTask.onMessage( res => {
+					console.log('监听',res.data)
+					userInfo.count++;
+					this.updateUserInfo(userInfo)
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+.login-container {
+	
+	// 登录盒子的样式
+	height: 750rpx;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+	background-color: #E2F0D9;
+	position: relative;
+	overflow: hidden;
+	
+	// 绘制登录盒子底部的半椭圆造型
+	&::after {
+		content: ' ';
+		display: block;
+		position: absolute;
+		width: 100%;
+		height: 40px;
+		left: 0;
+		bottom: 0;
+		background-color: white;
+		border-radius: 100%;
+		transform: translateY(50%);
+	}
+	
+	// 登录按钮的样式
+	.btn-login {
+		width: 90%;
+		border-radius: 100px;
+		margin: 15px 0;
+		background-color: #008000;
+	}
+	
+	// 按钮下方提示消息的样式
+	.tips-text {
+		font-size: 12px;
+		color: gray;
+	}
+}
+</style>

+ 311 - 0
education_uni/components/my-requiredetail/my-requiredetail.vue

@@ -0,0 +1,311 @@
+<template>
+		<view class="contain">
+			<uni-row>
+				<view style="height: 20rpx;"></view>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<view class="contain-item"><text class="contain-text">需求号:</text>{{item.requireId}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<view class="contain-item"><text class="contain-text">学员ID:</text>{{item.uid}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :span="12" :push="1">
+					<view class="contain-item"><text class="contain-text">学员:</text>{{item.name}}</view>
+				</uni-col>
+				<uni-col :span="12">
+					<view><text class="contain-text">学员性别:</text>{{item.sex}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1" :span="18">
+					<view class="contain-item"><text class="contain-text">需求科目:</text>{{item.subjectBig}}/{{item.subjectSmall}}</view>
+				</uni-col>
+				<uni-col :span="6" v-if="isShowCollect">
+					<uni-fav :checked="collect" class="favBtn" :circle="true" bg-color="#dd524d"
+										bg-color-checked="#007aff" fg-color="#ffffff" fg-color-checked="#ffffff" @click="collecting" />
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<view class="contain-item">
+					<map :longitude="location[1]" :latitude="location[0]" :markers="marker" class="map"></map>
+				</view>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<view class="contain-addr-item"><text class="contain-text">学员地址:</text>{{item.locationStr}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<text class="contain-text">课程时间:</text>
+				</uni-col>
+			</uni-row>
+			<view class="tr-container">
+				<view class="tr_1">
+					<text class="th_0" decode="true">&ensp;&ensp;&ensp;&ensp;</text>
+					<text class="th_1">周一</text>
+					<text class="th_1">周二</text>
+					<text class="th_1">周三</text>
+					<text class="th_1">周四</text>
+					<text class="th_1">周五</text>
+					<text class="th_1">周六</text>
+					<text class="th_1">周日</text>
+				</view>
+				<view class="tr_2">
+					<checkbox-group>
+						<view class="th2_0">上午</view>
+						<label v-for="item in timeAM" :key="item.value">
+							<checkbox class="th2_1" :value="item.value" :checked="item.checked" disabled></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+				<view class="tr_2">
+					<checkbox-group>
+						<view class="th2_0">下午</view>
+						<label v-for="item in timePM" :key="item.value">
+							<checkbox class="th2_1" :value="item.value" :checked="item.checked" disabled></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+				<view class="tr_2">
+					<checkbox-group>
+						<view class="th2_0">晚上</view>
+						<label v-for="item in timeEvening" :key="item.value">
+						<checkbox class="th2_1" :value="item.value" :checked="item.checked" disabled></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+			</view>
+			<uni-row>
+				<uni-col :span="12" :push="1">
+					<view class="contain-item"><text class="contain-text">教员类型:</text>{{item.teacherType}}</view>
+				</uni-col>
+				<uni-col :span="12">
+					<view><text class="contain-text">教员学历:</text>{{item.teacherEdu}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :span="12" :push="1">
+					<view class="contain-item"><text class="contain-text">教员性别:</text>{{item.teacherGender}}</view>
+				</uni-col>
+				<uni-col :span="12">
+					<view><text class="contain-text">上课方式:</text>{{item.mode}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :span="12" :push="1">
+					<view class="contain-item"><text class="contain-text">教员头像:</text>{{item.teacherProfilePhoto}}</view>
+				</uni-col>
+				<uni-col :span="12">
+					<view><text class="contain-text">需求金额:</text>{{item.salary}}元</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<view class="contain-expect-item"><text class="contain-text">期望目标:</text>{{item.goal}}</view>
+				</uni-col>
+			</uni-row>
+			<uni-row>
+				<uni-col :push="1">
+					<view class="contain-extra-item"><text class="contain-text">额外要求:</text>{{item.teacherDemanded}}</view>
+				</uni-col>
+			</uni-row>
+			<view v-if="isShowPrivate">
+				<uni-row>
+					<uni-col :push="1">
+						<view class="contain-item"><text class="contain-text">审核不通过原因:</text>{{item.verifyRefuseReason || '暂无'}}</view>
+					</uni-col>
+				</uni-row>
+				<uni-row>
+					<uni-col :push="1">
+						<view class="contain-item"><text class="contain-text">本需求发布日期:</text>{{item.datetime}}</view>
+					</uni-col>
+				</uni-row>
+				<uni-row>
+					<uni-col :push="1">
+						<view class="contain-item"><text class="contain-text">手机号:</text>{{item.phone}}</view>
+					</uni-col>
+				</uni-row>
+				<uni-row>
+					<uni-col :push="1">
+						<view class="contain-item"><text class="contain-text">微信号:</text>{{item.wxid}}</view>
+					</uni-col>
+				</uni-row>
+			</view>
+			<view class="publish-button-wrapper">
+				<button class="publish-button" @click="publishButton">{{buttonMessage}}</button>
+			</view>
+			
+		</view>
+</template>
+
+<script>
+	import { mapState } from 'vuex';
+	
+	export default {
+		name: 'my-requiredetail',
+		data() {
+			return {
+				
+			};
+		},
+		props: {
+			item: {
+				type: Object
+			},
+			location: {
+				type: Array
+			},
+			marker: {
+				type: Array
+			},
+			timeAM: {
+				type: Array
+			},
+			timePM: {
+				type: Array
+			},
+			timeEvening: {
+				type: Array
+			},
+			collect: {
+				type: Boolean,
+				default: false
+			},
+			isShowCollect: {
+				type: Boolean,
+				default: false
+			},
+			isShowPrivate: {
+				type: Boolean,
+				default: false
+			},
+			buttonMessage: {
+				type: String
+			}
+		},
+		methods: {
+			// 点击收藏
+			collecting() {
+				// 触发外界通过 @click 绑定的 click 事件处理函数
+				this.$emit('collecting')
+			},
+			publishButton() {
+				this.$emit('publishButton')
+			}
+		},
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+.contain {
+	//background-color: #FFF2CC;
+	background-color: #F0F0F0;
+	border-radius: 20rpx;
+	height: 100%;
+	
+	.contain-item {
+		margin-bottom: 20rpx;
+	}
+	
+	.contain-addr-item,
+	.contain-expect-item,
+	.contain-extra-item{
+		margin-bottom: 20rpx;
+		width:94%
+	}
+	
+	.contain-text {
+		font-weight: 700;
+		color: #bbb;
+	}
+	
+	.map {
+		width: 100%;
+	}
+}
+.tr-container{
+	    display: flex;
+	    position: relative;
+	    width: 96%;
+	    flex-direction: column;
+	    font-size: 26rpx;
+	    /* border: 1rpx solid gray; */
+	    margin: -10px 20rpx;
+		margin-bottom: 20px;
+	}
+	
+	.tr_1 {
+	    display: flex;
+	    position: relative;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	}
+	.tr_2{
+	    display: block;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	}
+	
+	.th_0,
+	.th_1,
+	.th_2,
+	.th2_0,
+	.th2_1,
+	.th2_2{
+	    width: 12%;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	    border-right: 1rpx solid gray;
+	    border-bottom: 1rpx solid gray;
+	    text-align: center;
+	}
+	
+	.th_0,
+	.th_1,
+	.th_2{
+	    border-top: 1rpx solid gray;
+	}
+	
+	.th_0,
+	.th2_0{
+	    border-left: 1rpx solid gray;
+	}
+	
+	.th2_0{
+	    float: left;
+	    width: 12%;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	    text-align: center;
+	    /* background-color: greenyellow; */
+	}
+	
+	// 底部按钮
+	.publish-button-wrapper{
+		margin-top: 10rpx;
+		height: 130rpx;
+	}
+	
+	.publish-button {
+		//background-color: #E2F0D9;
+		// background-color: #3ED598;
+		background-color: #35b882;
+		width: 200rpx;
+		border-radius: 50rpx;
+		color: white;
+	}
+</style>

+ 221 - 0
education_uni/components/my-userinfo/my-userinfo.vue

@@ -0,0 +1,221 @@
+<template>
+	<view>
+		<uni-card :title="userinfo.alias" :sub-title="userinfo.uid" :thumbnail="userinfo.avatar" @click="toMyDetail"></uni-card>
+		<uni-list>
+			<uni-list-item :show-extra-icon="true" showArrow :extra-icon="OfficialAccountextraIcon" title="关注公众号" link="navigateTo" @click="toOfficialAccount"/>
+			<uni-list-item :show-extra-icon="true" showArrow :extra-icon="MyShareextraIcon" title="分享与返现" link="navigateTo" @click="toMyShare"/>
+			<uni-list-item :show-extra-icon="true" showArrow :extra-icon="MyOrderextraIcon" title="订单" link="navigateTo" @click="toMyOrder"/>
+			<uni-section title="邀请" titleColor="#2BAFF8" type="line">
+				<uni-list>
+					<uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon1" title="发出的邀请" link="navigateTo" @click="sendInvitation"/>
+					<uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon1" title="收到的邀请" link="navigateTo" @click="receivedInvitation"/>
+				</uni-list>
+			</uni-section>
+			<uni-section title="教员" titleColor="#FB748F" type="line">
+				<uni-list>
+					<uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon2" title="教员认证" link="navigateTo" @click="authorize"/>
+					<uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon2" title="发布新的课程" link="navigateTo" @click="toCoursePublish"/>
+					<uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon2" title="已发布的课程" link="navigateTo" @click="coursePublished"/>
+					<uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon2" title="已收藏的课程" link="navigateTo" @click="collectCourses"/>
+				</uni-list>
+			</uni-section>
+			<uni-section title="学员" titleColor="#4cd964" type="line">
+				<uni-list>
+					<uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon3" title="发布新的需求" link="navigateTo" @click="toNeedPublis"/>
+					<uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon3" title="已发布的需求" link="navigateTo" @click="Published"/>
+					<uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon3" title="已收藏的需求" link="navigateTo" @click="collectStuNeeds"/>
+				</uni-list>
+			</uni-section>
+			<uni-section title="投诉与建议" titleColor="#7E7AF8" type="line">
+				<uni-list>
+					<uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon4" title="我的建议" link="navigateTo" @click="toMySuggestion"/>
+					<uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon4" title="我的投诉" link="navigateTo" @click="toMyComplaint"/>
+				</uni-list>
+			</uni-section>
+			<uni-list-item v-if="isAdmin" :show-extra-icon="true" showArrow :extra-icon="extraIcon5" title="管理员专用" link="navigateTo" @click="toManager"/>
+		</uni-list>
+	</view>
+</template>
+
+<script>
+	import { mapState } from 'vuex'
+	
+	export default {
+		name:"my-userinfo",
+		options: {
+			styleIsolation: 'shared', // 解除样式隔离
+		},
+		computed: {
+			...mapState('m_user', ['userinfo'])
+		},
+		data() {
+			return {
+				isAdmin: false,
+				OfficialAccountextraIcon: {
+					color: '#2BAFF8',
+					size: '22',
+					type: 'star-filled'
+				},
+				MyShareextraIcon: {
+					color: '#FB748F',
+					size: '22',
+					type: 'pyq'
+				},
+				MyOrderextraIcon: {
+					color: '#4cd964',
+					size: '22',
+					type: 'fire-filled'
+				},
+				extraIcon1: {
+					color: '#2BAFF8',
+					size: '22',
+					type: 'email-filled'
+				},
+				extraIcon2: {
+					color: '#FB748F',
+					size: '22',
+					type: 'auth-filled'
+				},
+				extraIcon3: {
+					color: '#4cd964',
+					size: '22',
+					type: 'staff-filled'
+				},
+				// 投诉与建议
+				extraIcon4: {
+					color: '#7E7AF8',
+					size: '22',
+					type: 'help-filled'
+				},
+				extraIcon5: {
+					color: '#F1D302',
+					size: '22',
+					type: 'eye-filled'
+				}
+			}
+		},
+		created() {
+			this.isAdmin = this.userinfo.isAdmin === 1 ? true : false
+		},
+		methods: {
+			toMyDetail() {
+				uni.navigateTo({
+					url: '/subpkg/my/user/my_user_detail'
+				})
+			},
+			toOfficialAccount(){
+				uni.navigateTo({
+					url:'/subpkg/my/official_account/my_official_account'
+				})
+			},
+			toMyShare(){
+				uni.navigateTo({
+					url: '/subpkg/my/share/my_share'
+				})
+			},
+			toMyOrder() {
+				uni.navigateTo({
+					url: '/subpkg/my/order/my_order'
+				})
+			},
+			sendInvitation() {
+				uni.navigateTo({
+					url: '/subpkg/my/invitation/my_invitation_send'
+				})
+			},
+			receivedInvitation() {
+				uni.navigateTo({
+					url: '/subpkg/my/invitation/my_invitation_receive'
+				})
+			},
+			collectStuNeeds() {
+				uni.navigateTo({
+					url: '/subpkg/student/require/student_require_my_collect'
+				})
+			},
+			collectCourses() {
+				uni.navigateTo({
+					url: '/subpkg/teacher/course/teacher_course_my_collect'
+				})
+			},
+			authorize() {
+				uni.navigateTo({
+					url: '/subpkg/teacher/authentication/teacher_authentication'
+				})
+			},
+			toCoursePublish() {
+				uni.navigateTo({
+					url: '/subpkg/teacher/course/teacher_course_add'
+				})
+			},
+			coursePublished() {
+				uni.navigateTo({
+					url: '/subpkg/teacher/course/teacher_course_my_publish'
+				})
+			},
+			toNeedPublis() {
+				uni.navigateTo({
+					url: '/subpkg/student/require/student_require_add'
+				})
+			},
+			Published() {
+				uni.navigateTo({
+					url: '/subpkg/student/require/student_require_my_publish'
+				})
+			},
+			toMySuggestion() {
+				uni.navigateTo({
+					url: '/subpkg/my/suggestion/my_suggestion'
+				})
+			},
+			toMyComplaint() {
+				uni.navigateTo({
+					url: '/subpkg/my/complaint/my_complaint'
+				})
+			},
+			toManager() {
+				uni.navigateTo({
+					url:'/subpkg/manager/manager',
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+// 用户头像
+::v-deep .uni-card--border {
+	height: 240rpx;
+}
+
+::v-deep .uni-card .uni-card__header .uni-card__header-avatar {
+	height: 200rpx;
+	width: 200rpx;
+}
+
+::v-deep .uni-card .uni-card__header .uni-card__header-avatar .uni-card__header-avatar-image {
+	height: 200rpx !important;
+	width: 200rpx !important;
+}
+
+::v-deep .uni-card .uni-card__header .uni-card__header-content .uni-card__header-content-title {
+	font-size: 60rpx !important;
+}
+
+::v-deep .uni-card .uni-card__header .uni-card__header-extra .uni-card__header-extra-text {
+	font-size: 60rpx !important;
+}
+
+::v-deep .uni-list-item {
+	font-size: 20px !important;
+	height: 50px;
+}
+</style>

+ 423 - 0
education_uni/components/xb-swiper-preview/index.vue

@@ -0,0 +1,423 @@
+<template>
+  <view class="swiper-content">
+    <view class="hander-top p-lr-32 w-s flex-j-sb--a-ct">
+      <view class="icon-back-wrap"
+            @click="onBack">
+       <image class="icon-back"
+               src="/static/xb-swiper-preview/icon-back.png"
+               mode="widthFix" />
+      </view>
+      <view class="count">{{currentImg + 1}} / {{ imgs.length }}</view>
+    </view>
+  
+	<swiper class="swiper-img"
+            :current="currentImg"
+            :duration="300"
+            @change="changeSwiper">
+      <swiper-item class="swiper-item"
+                   v-for="(item, index) in imgs"
+                   :key="index">
+        <view class="img-page">
+          <movable-area scale-area>
+            <movable-view direction="all"
+                          scale="true"
+                          scale-min="1"
+                          scale-max="4">
+              <image class="max-img"
+                     :src="item"
+                     :lazy-load="true"
+                     mode="aspectFill" />
+            </movable-view>
+          </movable-area>
+        </view>
+      </swiper-item>
+    </swiper>
+    <view class="item-bottom">
+      <scroll-view class="scroll-view_H "
+                   :scroll-x="true"
+                   :scroll-into-view="scrollTopIndex"
+                   :scroll-with-animation="true"
+                   scroll-left="20">
+        <view class="img-page-box scroll-view-item_H"
+              :class="currentImg == index ? 'img-page-checked' : ''"
+              v-for="(item, index) in imgs"
+              :key="index"
+              :id="`scrollToIndex${index}`"
+              @click.stop="toImg(index)">
+          <image class="img"
+                 :src="item"
+                 mode="aspectFill" />
+        </view>
+      </scroll-view>
+    </view>
+
+    <!-- <view class="handle-wrap flex-j-sb--a-ct p-lr-32">
+      <view class="w-64 h-64"
+            @click="isScale = !isScale">
+        <image v-show="isScale"
+               class="w-64 h-64"
+               src="/static/xb-swiper-preview/icon-scale-yes.png"
+               mode="widthFix" />
+        <image v-show="!isScale"
+               class="w-64 h-64"
+               src="/static/xb-swiper-preview/icon-scale.png"
+               mode="widthFix" />
+      </view>
+
+      <view class="w-64 h-64"
+            @click="isCollect = !isCollect">
+        <image v-show="isCollect"
+               class="w-64 h-64"
+               src="/static/xb-swiper-preview/icon-collect-yes.png"
+               mode="widthFix" />
+        <image v-show="!isCollect"
+               class="w-64 h-64"
+               src="/static/xb-swiper-preview/icon-collect.png"
+               mode="widthFix" />
+      </view>
+
+      <view class="w-64 h-64"
+            @click="isLike = !isLike">
+        <image v-show="isLike"
+               class="w-64 h-64"
+               src="/static/xb-swiper-preview/icon-like-yes.png"
+               mode="widthFix" />
+        <image v-show="!isLike"
+               class="w-64 h-64"
+               src="/static/xb-swiper-preview/icon-like.png"
+               mode="widthFix" />
+      </view>
+
+      <image class="w-64 h-64"
+             src="/static/xb-swiper-preview/icon-set-wallpaper-yes.png"
+             mode="widthFix" />
+      <image class="w-64 h-64"
+             src="/static/xb-swiper-preview/icon-share.png"
+             mode="widthFix" />
+      <image class="w-64 h-64"
+             src="/static/xb-swiper-preview/icon-download.png"
+             mode="widthFix" />
+    </view> -->
+
+    <view class="pop"
+          v-if="isPop">
+      <view class="item"
+            @click.stop="share()">分享图片</view>
+      <!-- #ifndef H5 -->
+      <view class="item"
+            @click.stop="saveImg(false)">保存图片</view>
+      <view class="item"
+            @click.stop="saveImg(true)">保存全部图片</view>
+      <!-- #endif -->
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      imgs: [
+      ],
+      currentImg: 0,
+      isPop: false,
+      scrollTopIndex: "",
+
+      isScale: false,
+      isCollect: false,
+      isLike: false,
+    };
+  },
+  created() {
+	this.getSmallPig()
+  },
+  onLoad(options) {
+    // let { imgs, current } = options;
+    // this.imgs = JSON.parse(imgs);
+    // this.currentImg = current;
+  },
+  methods: {
+	async getSmallPig() {
+		const {data: result} = await uni.$http.get('/education/strategy/getSmallPig')
+		this.imgs = result.data.list
+	},
+    changeSwiper(e) {
+      this.currentImg = e.detail.current;
+      // console.log("e", e);
+
+      this.scrollTopIndex = `scrollToIndex${e.detail.current}`;
+    },
+    toImg(index) {
+      this.currentImg = index;
+    },
+    onBack() {
+      uni.navigateBack();
+    },
+    share() {
+      uni.downloadFile({
+        // 下面一行时拼接预览PDF的地址!!!
+        url: this.imgs[this.currentImg],
+        success: function (res) {
+          var filePath = res.tempFilePath;
+          if (!filePath) return;
+          uni.openDocument({
+            filePath: filePath,
+            success: function (res) {
+              console.log(res);
+              console.log("打开文档成功");
+            },
+          });
+        },
+      });
+    },
+    saveImg(isAll = false) {
+      const that = this;
+      if (!isAll) {
+        uni.downloadFile({
+          url: this.imgs[this.currentImg],
+          success: (res) => {
+            if (res.statusCode === 200) {
+              uni.saveImageToPhotosAlbum({
+                filePath: res.tempFilePath,
+                success: function () {
+                  uni.showToast({
+                    icon: "none",
+                    title: "保存成功",
+                  });
+                  that.isPop = false;
+                },
+                fail: function () {},
+              });
+            } else {
+            }
+          },
+        });
+        return;
+      }
+      this.imgs.forEach((item) => {
+        uni.downloadFile({
+          url: item,
+          success: (res) => {
+            if (res.statusCode === 200) {
+              uni.saveImageToPhotosAlbum({
+                filePath: res.tempFilePath,
+                success: function () {
+                  uni.showToast({
+                    icon: "none",
+                    title: "保存全部成功",
+                  });
+                  that.isPop = false;
+                },
+                fail: function () {},
+              });
+            } else {
+            }
+          },
+        });
+      });
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+	.swiper-content{
+		width: 100%;
+		height: 100vh;
+		position: relative;
+	}
+movable-view {
+   display: flex;
+   align-items: center;
+   justify-content: center;
+
+   width: 100%;
+   height: 100%;
+}
+
+movable-area {
+   position: fixed;
+
+   overflow: hidden;
+
+   width: 100%;
+   height: 100%;
+
+   transform: scale();
+}
+
+movable-view image {
+   width: 100%;
+}
+
+uni-image > img {
+   z-index: -1 !important;
+}
+
+.hander-top {
+   position: absolute;
+   z-index: 1000;
+   top: 48rpx;
+   left: 0;
+	display: flex;
+	justify-content: space-between;
+	width: 100%;
+	padding: 0 32rpx;
+	box-sizing: border-box;
+   .icon-back-wrap {
+      width: 64rpx;
+      height: 64rpx;
+	  .icon-back{
+		  width: 64rpx;
+		  height: 64rpx;
+	  }
+   }
+
+   .count {
+      box-sizing: border-box;
+      padding: 8rpx 24rpx;
+
+      color: #fff;
+      border-radius: 24rpx;
+      background: rgba(0, 0, 0, .4);
+
+      font-size: 28rpx;
+   }
+}
+
+.swiper-img {
+   width: 100vw;
+   height: 100vh;
+	
+   background-color: #000;
+
+   .swiper-item {
+      width: 100vw;
+      height: 100vh;
+
+      .img-page {
+         display: flex;
+         align-items: center;
+
+         width: 100vw;
+         height: 100vh;
+
+         .max-img {
+            width: 100%;
+            height: 100%;
+         }
+      }
+   }
+}
+
+.handle-wrap {
+   position: absolute;
+   z-index: 100;
+   bottom: 40rpx;
+   left: 0;
+   
+	width: 100%;
+	display: flex;
+	justify-content: space-between;
+	padding: 32rpx;
+	box-sizing: border-box;
+   image{
+	   width: 64rpx;
+	   height: 64rpx;
+   }
+
+   width: 100%;
+}
+
+.item-bottom {
+   position: fixed;
+   z-index: 9999;
+   bottom: 10rpx;
+   left: 0rpx;
+
+   display: flex;
+   flex-direction: column;
+   justify-content: space-between;
+
+   width: 100vw;
+
+//  height: 200rpx;
+   padding: 30rpx;
+
+   transition: ease-in-out .3s;
+}
+
+.small-list-page {
+   min-height: 60rpx;
+}
+
+.scroll-Y {
+   height: 300rpx;
+}
+
+.scroll-view_H {
+   width: 100%;
+	box-sizing: border-box;
+	padding-right: 32rpx;
+   white-space: nowrap;
+}
+
+.scroll-view-item_H {
+   display: inline-block;
+
+   margin-right: 10rpx;
+
+   transition: ease-in .1s;
+   transform: scale(.8);
+
+   border-radius: 11rpx;
+   background: #c2c2c2;
+
+   &:last-child {
+      margin-right: 0;
+   }
+
+   .img {
+      display: block;
+
+      width: 160rpx;
+      height: 272rpx;
+   }
+}
+
+.img-page-checked {
+   transform: translateY(-28rpx) scale(1);
+}
+
+.pop {
+   position: fixed;
+   z-index: 999999;
+   top: 50%;
+   left: 50%;
+
+   overflow: hidden;
+
+   width: 500rpx;
+
+   transform: translate(-50%, -50%);
+
+   border-radius: 20rpx;
+   background-color: #fff;
+
+   .item {
+      height: 100rpx;
+      padding: 0 50rpx;
+
+      transition: all .2s;
+
+      border-radius: 20rpx;
+
+      line-height: 100rpx;
+
+      &:active {
+         background-color: #eee;
+      }
+   }
+}
+
+</style>

+ 20 - 0
education_uni/index.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <script>
+      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
+        CSS.supports('top: constant(a)'))
+      document.write(
+        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
+        (coverSupport ? ', viewport-fit=cover' : '') + '" />')
+    </script>
+    <title></title>
+    <!--preload-links-->
+    <!--app-context-->
+  </head>
+  <body>
+    <div id="app"><!--app-html--></div>
+    <script type="module" src="/main.js"></script>
+  </body>
+</html>

+ 74 - 0
education_uni/main.js

@@ -0,0 +1,74 @@
+// #ifndef VUE3
+import Vue from 'vue'
+import App from './App'
+
+// 导入 store 的实例对象
+import store from './store/store.js'
+
+// 按需导入 $http 对象
+import { $http } from '@escook/request-miniprogram'
+
+// 在 uni-app 项目中,可以把 $http 挂载到 uni 顶级对象之上,方便全局调用
+uni.$http = $http
+
+// 请求的根路径
+$http.baseUrl = 'https://hometeacher2.natappvip.cc'
+
+uni.$wsLocation = 'wss://hometeacher2.natappvip.cc'
+
+// 封装弹窗的方法
+uni.$showMsg = function (title = '数据加载失败!', duration = 1500) {
+	uni.showToast({
+		title,
+		duration,
+		icon: 'none',
+	})
+}
+
+// 请求拦截器
+$http.beforeRequest = function(options) {
+	uni.showLoading({
+		title: '数据加载中'
+	})
+	this.header = {
+		token: uni.getStorageSync('token')
+	}
+}
+
+// 响应拦截器
+$http.afterRequest = res => {
+	uni.hideLoading()
+	if (!res.data.success) {
+		uni.$showMsg(res.data.message)
+		if (res.data.message === '登录过期,请重新登录') {
+			uni.setStorageSync('token', '')
+			uni.switchTab({
+				url: '/pages/my/my'
+			})
+		}
+	}
+}
+
+Vue.config.productionTip = false
+
+App.mpType = 'app'
+
+const app = new Vue({
+    ...App,
+	// 2. 将 store 挂载到 Vue 实例上
+	store
+})
+app.$mount()
+
+// #endif
+
+// #ifdef VUE3
+import { createSSRApp } from 'vue'
+import App from './App.vue'
+export function createApp() {
+  const app = createSSRApp(App)
+  return {
+    app
+  }
+}
+// #endif

+ 69 - 0
education_uni/manifest.json

@@ -0,0 +1,69 @@
+{
+    "name" : "自选教员",
+    "appid" : "__UNI__8C1D972",
+    "description" : "",
+    "versionName" : "1.0.0",
+    "versionCode" : "100",
+    "transformPx" : false,
+    "app-plus" : {
+        /* 5+App特有相关 */
+        "usingComponents" : true,
+        "nvueCompiler" : "uni-app",
+        "nvueStyleCompiler" : "uni-app",
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        "modules" : {},
+        /* 模块配置 */
+        "distribute" : {
+            /* 应用发布信息 */
+            "android" : {
+                /* android打包配置 */
+                "permissions" : [
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            "ios" : {},
+            /* ios打包配置 */
+            "sdkConfigs" : {}
+        }
+    },
+    /* SDK配置 */
+    "quickapp" : {},
+    /* 快应用特有相关 */
+    "mp-weixin" : {
+        "appid" : "wxf2d10b5ab2b20723",
+        "setting" : {
+            "urlCheck" : false,
+            "es6" : true,
+            "postcss" : true,
+            "minified" : true
+        },
+        "usingComponents" : true,
+        "permission" : {
+            "scope.userFuzzyLocation" : {
+                "desc" : "允许位置信息将为你推荐最近的资源"
+            }
+        },
+        "requiredPrivateInfos" : [ "choosePoi", "getFuzzyLocation", "chooseLocation" ],
+        "lazyCodeLoading" : "requiredComponents"
+    },
+    "vueVersion" : "2"
+}

+ 15 - 0
education_uni/mixins/compute-distance.js

@@ -0,0 +1,15 @@
+export default {
+	methods: {
+		space(lat1, lng1, lat2, lng2) {
+			var radLat1 = lat1 * Math.PI / 180.0;
+			var radLat2 = lat2 * Math.PI / 180.0;
+			var a = radLat1 - radLat2;
+			var b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
+			var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
+					Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
+			s = s * 6378.137;
+			s = Math.round(s * 10000) / 10000;	// 单位千米
+			return s.toFixed(2)	// 保留两位小数
+		},
+	}
+}

+ 142 - 0
education_uni/mixins/form-time.js

@@ -0,0 +1,142 @@
+export default {
+	data() {
+		return {
+			courseWeekday: [],
+			// 上课时间
+			// 上午
+			timeAM: [{
+					value: 'A1',
+					name: '1',
+					checked: false
+
+				},
+				{
+					name: '2',
+					value: 'A2',
+					checked: false
+				},
+				{
+					name: '3',
+					value: 'A3',
+					checked: false
+				},
+				{
+					name: '4',
+					value: 'A4',
+					checked: false
+				},
+				{
+					name: '5',
+					value: 'A5',
+					checked: false
+				},
+				{
+					name: '6',
+					value: 'A6',
+					checked: false
+				},
+				{
+					name: '7',
+					value: 'A7',
+					checked: false
+				}
+			],
+			// 下午
+			timePM: [{
+					value: 'P1',
+					name: '1',
+					checked: false
+				},
+				{
+					name: '2',
+					value: 'P2',
+					checked: false
+				},
+				{
+					name: '3',
+					value: 'P3',
+					checked: false
+				},
+				{
+					name: '4',
+					value: 'P4',
+					checked: false
+				},
+				{
+					name: '5',
+					value: 'P5',
+					checked: false
+				},
+				{
+					name: '6',
+					value: 'P6',
+					checked: false
+				},
+				{
+					name: '7',
+					value: 'P7',
+					checked: false
+				}
+			],
+			// 晚上
+			timeEvening: [{
+					name: '1',
+					value: 'E1',
+					checked: false
+				},
+				{
+					name: '2',
+					value: 'E2',
+					checked: false
+				},
+				{
+					name: '3',
+					value: 'E3',
+					checked: false
+				},
+				{
+					name: '4',
+					value: 'E4',
+					checked: false
+				},
+				{
+					name: '5',
+					value: 'E5',
+					checked: false
+				},
+				{
+					name: '6',
+					value: 'E6',
+					checked: false
+				},
+				{
+					name: '7',
+					value: 'E7',
+					checked: false
+				}
+			],
+		}
+	},
+	methods: {
+		// 上课表格格式化
+		parseCourseWeekday() {
+			for (let i = 0; i < this.courseWeekday.length; i++) {
+				for (let x = 0; x < this.timeAM.length; x++) {
+					if (this.courseWeekday[i] == this.timeAM[x].value) {
+						this.timeAM[x].checked = true
+					}
+				}
+				for (let y = 0; y < this.timePM.length; y++) {
+					if (this.courseWeekday[i] == this.timePM[y].value) {
+						this.timePM[y].checked = true
+					}
+				}
+				for (let z = 0; z < this.timeEvening.length; z++) {
+					if (this.courseWeekday[i] == this.timeEvening[z].value) {
+						this.timeEvening[z].checked = true
+					}
+				}
+			}
+		},
+	}
+}

+ 36 - 0
education_uni/mixins/tabbar-badge.js

@@ -0,0 +1,36 @@
+import {mapState} from 'vuex'
+
+export default {
+	computed: {
+		...mapState('m_user', ['userinfo'])
+	},
+	watch: {
+		// 监听 count 值的变化
+		'userinfo.count': {
+			handler() {
+				// 调用 methods 中的 setBadge 方法,重新为 tabBar 的数字徽章赋值
+				this.setBadge()
+			}
+		},
+	},
+	onShow() {
+		// 在页面刚展示的时候,设置数字徽标
+		this.setBadge()
+	},
+	methods: {
+		setBadge() {
+			if (this.userinfo.count == 0) {
+				uni.removeTabBarBadge({
+					index: 2
+				})
+			} else {
+				// 调用 uni.setTabBarBadge() 方法,为购物车设置右上角的徽标
+				uni.setTabBarBadge({
+					index: 2,
+					text: this.userinfo.count + '', // 注意:text 的值必须是字符串,不能是数字
+				})
+			}
+			
+		}
+	}
+}

+ 39 - 0
education_uni/package-lock.json

@@ -0,0 +1,39 @@
+{
+  "name": "education_uni",
+  "version": "1.0.0",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "education_uni",
+      "version": "1.0.0",
+      "license": "ISC",
+      "dependencies": {
+        "@escook/request-miniprogram": "^0.2.1",
+        "base-64": "^1.0.0"
+      }
+    },
+    "node_modules/@escook/request-miniprogram": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/@escook/request-miniprogram/-/request-miniprogram-0.2.1.tgz",
+      "integrity": "sha512-ueWV5YsaEm/ycQZuEjMiA88GFMhfBQSjy9GrP9omy4xAQajkGTbYIlnhzsDfWzRPmRC1fKmAiKMrCVcgS+SHcQ=="
+    },
+    "node_modules/base-64": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/base-64/-/base-64-1.0.0.tgz",
+      "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="
+    }
+  },
+  "dependencies": {
+    "@escook/request-miniprogram": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/@escook/request-miniprogram/-/request-miniprogram-0.2.1.tgz",
+      "integrity": "sha512-ueWV5YsaEm/ycQZuEjMiA88GFMhfBQSjy9GrP9omy4xAQajkGTbYIlnhzsDfWzRPmRC1fKmAiKMrCVcgS+SHcQ=="
+    },
+    "base-64": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/base-64/-/base-64-1.0.0.tgz",
+      "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="
+    }
+  }
+}

+ 16 - 0
education_uni/package.json

@@ -0,0 +1,16 @@
+{
+  "name": "education_uni",
+  "version": "1.0.0",
+  "main": "main.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [],
+  "author": "",
+  "license": "ISC",
+  "dependencies": {
+    "@escook/request-miniprogram": "^0.2.1",
+    "base-64": "^1.0.0"
+  },
+  "description": ""
+}

+ 330 - 0
education_uni/pages.json

@@ -0,0 +1,330 @@
+{
+	"pages": [{
+		"path": "pages/home/home",
+		"style": {
+			"enablePullDownRefresh": false,
+			"navigationStyle": "custom"
+		}
+	}, {
+		"path": "pages/my/my",
+		"style": {
+			"navigationBarTitleText": "个人中心",
+			"enablePullDownRefresh": false
+		}
+	}, {
+		"path": "pages/teacher/teacher",
+		"style": {
+			"navigationBarTitleText": "找教员",
+			"enablePullDownRefresh": true,
+			"onReachBottomDistance": 150
+		}
+	}, {
+		"path": "pages/student/student",
+		"style": {
+			"navigationBarTitleText": "找学员",
+			"enablePullDownRefresh": true,
+			"onReachBottomDistance": 150
+		}
+	}, {
+		"path": "pages/message/message",
+		"style": {
+			"navigationBarTitleText": "消息",
+			"enablePullDownRefresh": false
+		}
+	}],
+	"subPackages": [{
+		"root": "subpkg",	
+		"pages": [
+			{
+				"path" : "manager/manager",
+				"style" : {
+					"navigationBarTitleText": "管理员专用",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "manager/suggestion/manager_suggestion",
+				"style": {
+					"navigationBarTitleText": "管理建议",
+					"enablePullDownRefresh": true,
+					"onReachBottomDistance": 150
+				}
+			}, {
+				"path" : "manager/suggestion/manager_suggestion_detail",
+				"style" : {
+					"navigationBarTitleText": "管理建议详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "manager/suggestion/manager_suggestion_handle",
+				"style": {
+					"navigationBarTitleText": "管理建议处理",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path" : "manager/complaint/manager_complaint",
+				"style" : {
+					"navigationBarTitleText": "管理投诉",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path" : "manager/complaint/manager_complaint_detail",
+				"style" : {
+					"navigationBarTitleText": "管理投诉详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path" : "manager/complaint/manager_complaint_handle",
+				"style" : {
+					"navigationBarTitleText": "管理投诉处理",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/complaint/my_complaint",
+				"style": {
+					"navigationBarTitleText": "我的投诉",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/complaint/my_complaint_write",
+				"style": {
+					"navigationBarTitleText": "写投诉",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/complaint/my_complaint_detail",
+				"style": {
+					"navigationBarTitleText": "投诉详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/home/my_home_strategy",
+				"style": {
+					"navigationBarTitleText": "攻略详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/invitation/my_invitation_receive",
+				"style": {
+					"navigationBarTitleText": "我收到的邀请",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/invitation/my_invitation_receive_detail",
+				"style": {
+					"navigationBarTitleText": "我收到的邀请详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/invitation/my_invitation_send",
+				"style": {
+					"navigationBarTitleText": "我发出的邀请",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/invitation/my_invitation_send_detail",
+				"style": {
+					"navigationBarTitleText": "我发出的邀请详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/message/my_message_detail",
+				"style": {
+					"navigationBarTitleText": "消息内容",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/official_account/my_official_account",
+				"style": {
+					"navigationBarTitleText": "关注公众号",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/order/my_order_detail",
+				"style": {
+					"navigationBarTitleText": "我的订单详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/order/my_order",
+				"style": {
+					"navigationBarTitleText": "我的订单",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/share/my_share_result_order_detail",
+				"style": {
+					"navigationBarTitleText": "订单返现详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/share/my_share_result_order",
+				"style": {
+					"navigationBarTitleText": "分享成交订单返现",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/share/my_share_result",
+				"style": {
+					"navigationBarTitleText": "分享结果",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/share/my_share",
+				"style": {
+					"navigationBarTitleText": "分享与返现",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/suggestion/my_suggestion",
+				"style": {
+					"navigationBarTitleText": "我的建议",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/suggestion/my_suggestion_write",
+				"style": {
+					"navigationBarTitleText": "写建议",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/suggestion/my_suggestion_detail",
+				"style": {
+					"navigationBarTitleText": "建议详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "my/user/my_user_detail",
+				"style": {
+					"navigationBarTitleText": "编辑账号",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "student/order/student_order_detail",
+				"style": {
+					"navigationBarTitleText": "订单详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "student/require/student_require_add",
+				"style": {
+					"navigationBarTitleText": "新增学员需求",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "student/require/student_require_my_publish",
+				"style": {
+					"navigationBarTitleText": "我发布的学员需求",
+					"enablePullDownRefresh": true,
+					"onReachBottomDistance": 150,
+					"app-plus": {
+						"bounce": "none"
+					}
+				}
+			}, {
+				"path": "student/require/student_require_my_detail",
+				"style": {
+					"navigationBarTitleText": "我的需求详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "student/require/student_require_all_detail",
+				"style": {
+					"navigationBarTitleText": "需求详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "student/require/student_require_my_collect",
+				"style": {
+					"navigationBarTitleText": "我收藏的学员需求"
+				}
+			}, {
+				"path": "teacher/authentication/teacher_authentication_add",
+				"style": {
+					"navigationBarTitleText": "申请教员认证",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "teacher/authentication/teacher_authentication",
+				"style": {
+					"navigationBarTitleText": "我的教员认证",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "teacher/authentication/teacher_authentication_detail",
+				"style": {
+					"navigationBarTitleText": "我的教员认证详情"
+				}
+			}, {
+				"path": "teacher/course/teacher_course_my_publish",
+				"style": {
+					"navigationBarTitleText": "我发布的教员课程",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "teacher/course/teacher_course_add",
+				"style": {
+					"navigationBarTitleText": "新增课程",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "teacher/course/teacher_course_my_detail",
+				"style": {
+					"navigationBarTitleText": "我的课程详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "teacher/course/teacher_course_all_detail",
+				"style": {
+					"navigationBarTitleText": "课程详情",
+					"enablePullDownRefresh": false
+				}
+			}, {
+				"path": "teacher/course/teacher_course_my_collect",
+				"style": {
+					"navigationBarTitleText": "我收藏的课程",
+					"enablePullDownRefresh": false
+				}
+			}
+		]
+	}],
+	"globalStyle": {
+		"navigationBarTextStyle": "black",
+		"navigationBarTitleText": "自选家教",
+		"navigationBarBackgroundColor": "#f0f0f0",
+		"backgroundColor": "#f0f0f0"
+	},
+	"tabBar": {
+		"selectedColor": "#00aa7f",
+		"list": [{
+				"pagePath": "pages/home/home",
+				"text": "首页",
+				"iconPath": "static/tab_icons/home.png",
+				"selectedIconPath": "static/tab_icons/home_active.png"
+			},
+			{
+				"pagePath": "pages/teacher/teacher",
+				"text": "找教员",
+				"iconPath": "static/tab_icons/teacher.png",
+				"selectedIconPath": "static/tab_icons/teacher_active.png"
+			},
+			{
+				"pagePath": "pages/message/message",
+				"text": "消息",
+				"iconPath": "static/tab_icons/message.png",
+				"selectedIconPath": "static/tab_icons/message_active.png"
+			},
+			{
+				"pagePath": "pages/student/student",
+				"text": "找学员",
+				"iconPath": "static/tab_icons/student.png",
+				"selectedIconPath": "static/tab_icons/student_active.png"
+			},
+			{
+				"pagePath": "pages/my/my",
+				"text": "我的",
+				"iconPath": "static/tab_icons/my.png",
+				"selectedIconPath": "static/tab_icons/my_active.png"
+			}
+		]
+	}
+}

+ 428 - 0
education_uni/pages/home/home.vue

@@ -0,0 +1,428 @@
+<template>
+	<view v-if="showTeacher && showStudent">
+		<official-account></official-account>
+
+		<uni-swiper-dot :info="info" :current="current">
+			<swiper class="swiper-box" autoplay circular @change="change">
+				<swiper-item v-for="(item ,index) in info" :key="index">
+					<view class="swiper-item">
+						<image :src="item.url"></image>
+					</view>
+				</swiper-item>
+			</swiper>
+		</uni-swiper-dot>
+
+		<!-- 热门教员区域 -->
+		<view>
+		    <!-- 热门教员 -->
+		    <view class="hotTitle">
+		        <uni-icons type="star" size="20" color="#b2b2b2" ></uni-icons>
+		        <text style	="color:#b2b2b2;font-size: 12px;" >教员</text>
+		    </view>
+			<view v-for="(Info,index) in hotTeacherList" :key="index">
+				<view class="publicItem" @click="goTeacherDetail(Info)">
+					<view class="hotTeacher">
+						<image class="teachImg" :src="Info.profilePhoto"></image>
+						<view class="teachTitle">{{Info.nickname}}教员</view>
+						<view class="publicSex">{{Info.sex}}</view>
+						<view class="teachCollege">{{Info.school}}</view>
+						<view class="teachEdu">{{Info.education}}</view>
+						<view class="teachDistance" v-if="isShowDistance">
+							<uni-icons type="location" color="#3ed598" ></uni-icons>
+							<text>{{Info.kil}}</text>km
+						</view>
+						<view class="teachSubject">{{Info.subject}}</view>
+						<view class="teachYears">教龄 {{Info.teachAge}}</view>
+					</view>	        
+				</view>
+			</view>
+		</view>
+		
+		<!-- 热门学员区域 -->
+		<view>
+		    <!-- 热门学员标题 -->
+		    <view class="hotTitle">
+				<uni-icons type="staff" size="20" color="#b2b2b2" ></uni-icons>
+				<text style	="color:#b2b2b2;font-size: 12px;" >学员</text>
+			</view>
+			
+			<view v-for="(item, index) in hotstuNeed" :key="index">
+				<view class="publicItem" @click="goStudentDetail(item.requireId)">
+					<view class="hotStudent">
+						<template v-if="item.sex === '女'">
+							<image class="teachImg" src="../../static/girl.png"></image>
+						</template>
+						<template v-else>
+							<image class="teachImg" src="../../static/boy.png"></image>
+						</template>
+						
+						<view class="hotStudentText">
+							<view class="studentTitle">{{item.nickname}}学员</view>
+							<view class="publicSex">{{item.sex}}</view>
+							<view class="stuGoal">{{item.goal}}</view>
+							<view class="studentDistance" v-if="isShowDistance">
+								<uni-icons type="location" color="#3ed598" ></uni-icons>
+								<text>{{item.kil}}</text>km
+							</view>
+						</view>
+						<view class="stuSubject">{{item.subjectBig + "/" + item.subjectSmall}}</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		
+		<!-- 攻略 -->
+		<view>
+		    <view class="hotTitle">
+				<uni-icons type="map" size="20"	color="#b2b2b2" ></uni-icons>
+				<text style	="color:#b2b2b2;font-size: 12px;" >攻略</text>
+			</view>
+			
+			<view class="cooperationContent" @click="gotoStrategy">
+				<scroll-view class="cooperationScroll" enable-flex scroll-x>
+					<view class="scrollItem" v-for="(item, index) in strategyImg" :key="index">
+						<image :src="item"></image>
+					</view>
+			   </scroll-view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import badgeMix from '@/mixins/tabbar-badge.js'
+	import computeDistance from '@/mixins/compute-distance.js'
+	import { mapState, mapMutations } from 'vuex'
+	
+	export default {
+		mixins: [badgeMix, computeDistance],
+		computed: {
+			...mapState('m_user', ['location', 'token', 'recoUID'])
+		},
+		data() {
+			return {
+				showTeacher: false,
+				showStudent: false,
+				info: [],
+				current: 0,
+				hotTeacherList: [],
+				hotstuNeed: [],
+				isShowDistance: false,
+				strategyImg: []
+			}
+		},
+		watch: {
+			'token': {
+				handler() {
+					if (this.token !== '') {
+						this.isShowDistance = true
+					} else {
+						this.isShowDistance = false
+					}
+				}
+			}
+		},
+		/**
+		 * 如果是从分享的卡片打开的,则可以取到分享者的uid,否则recomID是undefined
+		 * recoUID为推荐者的uid,当用户作为新用户注册时,如果取到了这个uid,才做为推荐者的uid存入
+		 * 老用户,取到这个uid也不存入了。
+		 */
+		onLoad(options) {
+			 this.updateRecoUID(options.uid) // 久化存储到本地,可在其它页面调用
+			 // console.log("推荐码为:" + this.recoUID)
+			 this.getSwiperList()
+			 this.getStrategyImg()
+		},
+		onShow() {
+			if (this.token !== '') {
+				this.isShowDistance = true
+			}
+			this.hotTeacher()
+			this.hotStudent()
+		},
+		methods: {
+			// 调用 mapMutations 辅助方法,把 m_user 模块中的 updateRecoUID 映射到当前组件中使用
+			...mapMutations('m_user', ['updateRecoUID']),
+			goStudentDetail(id) {
+				uni.navigateTo({
+					url: '/subpkg/student/require/student_require_all_detail?requireId=' + encodeURIComponent(id)
+				})
+			},
+			goTeacherDetail(item) {
+				uni.navigateTo({
+					url: '/subpkg/teacher/course/teacher_course_all_detail?item=' + encodeURIComponent(JSON.stringify(item))
+				})
+			},
+			async hotTeacher() {
+				const { data: result } = await uni.$http.get('/education/home/getHottestTeacher')
+				for (let i = 0; i < result.data.teacher.length; i++) {
+					let arr = result.data.teacher[i].locationAl.split(",")
+					let kil = this.space(arr[0], arr[1], this.location.latitude, this.location.longitude)
+					result.data.teacher[i].kil = kil
+					result.data.teacher[i].nickname = result.data.teacher[i].name.slice(0,1)
+				}
+				this.hotTeacherList = result.data.teacher
+				this.showTeacher = true
+			},
+			async hotStudent(){
+				const { data: result } = await uni.$http.get('/education/home/getHottestStuNeed')
+				for (let i = 0; i < result.data.stuNeed.length; i++) {
+					let arr = result.data.stuNeed[i].locationAl.split(",")
+					let kil = this.space(arr[0], arr[1], this.location.latitude, this.location.longitude)
+					result.data.stuNeed[i].kil = kil
+					result.data.stuNeed[i].nickname = result.data.stuNeed[i].name.slice(0,1) 
+					if (result.data.stuNeed[i].goal.length == 0) {
+						result.data.stuNeed[i].goal = "无"
+					}
+				}
+				this.hotstuNeed = result.data.stuNeed
+				this.showStudent = true
+			},
+			// 获取轮播图列表
+			async getSwiperList() {
+				const {
+					data: result
+				} = await uni.$http.get('/education/swiper/getSwiperList')
+				this.info = result.data.list
+			},
+			// 滑动轮播图触发
+			change(e) {
+				this.current = e.detail.current
+			},
+			gotoStrategy() {
+				uni.navigateTo({
+					url: '/subpkg/my/home/my_home_strategy'
+				})
+			},
+			async getStrategyImg() {
+				const {
+					data: result
+				} = await uni.$http.get('/education/strategy/getBigPig')
+				this.strategyImg = result.data.list
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.swiper-box {
+		height: 500rpx;
+	}
+	
+	.swiper-item {
+		display: block;
+		height: 500rpx;
+		line-height: 500rpx;
+		text-align: center;
+
+		image {
+			width: 100%;
+			height: 100%;
+			display: block;
+			border-radius: 60rpx;
+		}
+	}
+
+	/* 轮播图 */
+	.swWrapper {
+		height: 400rpx;
+	}
+
+	.swImg {
+		width: 100%;
+		height: 400rpx;
+	}
+
+	/* 热门教员、热门学员标题 */
+	.hotTitle {
+		display: flex;
+		margin-top: 5rpx;
+		justify-content: center;
+		align-items: center;
+	}
+	
+	/* 热门教员、热门学员标题前后的线条 */
+	.hotTitle::before {
+		content: "";
+		margin-right: 20rpx;
+		margin-left: 40rpx;
+		height: 1px;
+		border: none;
+		border-top: 1px solid #b2b2b2;
+		flex: 1 1 0rpx;
+	}
+	
+	.hotTitle::after {
+		content: "";
+		margin-right: 40rpx;
+		margin-left: 20rpx;
+		height: 1px;
+		border: none;
+		border-top: 1px solid #b2b2b2;
+		flex: 1 1 0rpx;
+	}
+
+	.scrollItem{
+		margin-right: 20rpx;
+		width: 350rpx;
+	}
+	
+	.scrollItem image{
+		width: 350rpx;
+		height: 300rpx;
+		border-radius: 40rpx;
+	}
+	
+	/* 攻略区 */
+	.cooperationContent{
+		height: 350rpx;
+		margin-left: 20rpx;
+	}
+	
+	/* 攻略图片 */
+	.cooperationScroll{
+		display: flex;
+		height: 300rpx;
+	}
+
+	/* 热门教员、热门学员 */
+	.hotTeacher,
+	.hotStudent{
+		position: relative;
+		display: flex;
+		padding: 10rpx;
+		height: 170rpx;
+		align-items: center;
+	}
+
+	/* 教员、学员头像 */
+	.teachImg,
+	.studentImg{
+		width: 25%;
+		height: 95%;
+		border-radius: 20%;
+	}
+	
+	/* 教员、学员性别 */
+	.publicSex{
+		position: absolute;
+		right: 10rpx;
+		top: 5rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 10rpx;
+		border-radius: 50%;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+	
+	/* teachEdu */
+	.teachEdu{
+		position: absolute;
+		right: 10rpx;
+		top: 60rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 10rpx;
+		border-radius: 30rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+	
+	/* teach课程 */
+	.teachSubject{
+		position: absolute;
+		left: 200rpx;
+		top: 115rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 10rpx;
+		border-radius: 30rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+
+	/* 教龄 */
+	.teachYears{
+		position: absolute;
+		right: 10rpx;
+		top: 115rpx;
+		border: 2px solid  #3ed598;
+		padding: 2rpx 20rpx;
+		border-radius: 30rpx;
+		color: #3ed598;
+		font-size: 12px;
+		font-weight: bold;
+	}
+
+	/* stu课程 */
+	.stuSubject{
+		position: absolute;
+		left: 200rpx;
+		top: 60rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 20rpx;
+		border-radius: 30rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+
+	.teachTitle,
+	.studentTitle{
+		font-size: 14px;
+		position: absolute;
+		left: 200rpx;
+		top: 10rpx;
+		font-weight: bold;
+		color: #6d6d6d;
+	}
+	
+	/* 距离 */
+	.teachDistance,
+	.studentDistance{
+		position: absolute;
+		left: 300rpx;
+		top: 10rpx;
+		font-weight: bold;
+		color: #3ed598;
+		font-size: 12px;
+	}
+	
+	.teachCollege{
+		border: 2px solid #3ed598;
+		border-radius: 30rpx;
+		padding: 0rpx 10rpx;
+		font-size: 12px;
+		position: absolute;
+		left: 200rpx;
+		top: 60rpx;
+		color: #3ed598;
+	}
+		
+	.stuGoal{
+		margin-top: 10rpx;
+		border: 2px solid #3ed598;
+		border-radius: 30rpx;
+		padding: 0rpx 10rpx;
+		font-size: 12px;
+		position: absolute;
+		left: 200rpx;
+		top: 125rpx;
+		color: #3ed598;
+		overflow: hidden;
+		text-overflow: ellipsis;
+		display: -webkit-box;
+		-webkit-box-orient: vertical;
+		-webkit-line-clamp: 1;
+	}
+		
+	/* item */
+	.publicItem{
+		margin: 10rpx 20rpx;
+		// border: 0rpx solid gray;
+		padding: 10rpx 20rpx;
+		border-radius: 30rpx;
+		background-color: #ffffff;
+	}
+</style>

+ 38 - 0
education_uni/pages/message/message.vue

@@ -0,0 +1,38 @@
+<template>
+	<view>
+		<uni-list v-for="(item,index) in list" :key="index">
+			<!-- 头像显示圆点 -->
+			<uni-list-chat clickable="true" :title="item.msgTitle" avatar="/static/avatar-msg.png" :note="item.msgContent" :time="item.datetime" :badge-positon="item.position" badge-text="dot" @click="gotoDetail(item)"></uni-list-chat>
+		</uni-list>
+	</view>
+</template>
+
+<script>
+	import badgeMix from '@/mixins/tabbar-badge.js'
+	export default {
+		mixins: [badgeMix],
+		data() {
+			return {
+				list: {}
+			};
+		},
+		onShow() {
+			this.getMsgList()
+		},
+		methods: {
+			async getMsgList() {
+				const {data: result} = await uni.$http.get('/education/mp-inner-msg/queryMsg')
+				this.list = result.data.list
+			},
+			gotoDetail(item) {
+				uni.navigateTo({
+					url: '/subpkg/my/message/my_message_detail?item='+encodeURIComponent(JSON.stringify(item))
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 43 - 0
education_uni/pages/my/my.vue

@@ -0,0 +1,43 @@
+<template>
+	<view>
+		<!-- 用户未登录时,显示登录组件 -->
+		<my-login v-if="!token && token === ''"></my-login>
+		
+		<!-- 用户登录后,显示用户信息组件 -->
+		<my-userinfo v-else></my-userinfo>
+	</view>
+</template>
+
+<script>
+	import badgeMix from '@/mixins/tabbar-badge.js'
+	import { mapState, mapMutations } from 'vuex'
+	
+	export default {
+		mixins: [badgeMix],
+		computed: {
+			...mapState('m_user', ['token'])
+		},
+		data() {
+			return {
+			};
+		},
+		onReady() {
+			this.findVerifyStatus()
+		},
+		onHide() {
+			this.findVerifyStatus()
+		},
+		methods: {
+			...mapMutations('m_user', ['updateAuthentication']),
+			// 查询是否通过了老师认证
+			async findVerifyStatus() {
+				const { data: result } = await uni.$http.get('/education/teacher-certifications/findVerifyStatus')
+				const message = result.message
+				this.updateAuthentication(message)
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+</style>

+ 368 - 0
education_uni/pages/student/student.vue

@@ -0,0 +1,368 @@
+<template>
+	<view>
+		<view v-for="(item, index) in stuNeeds" :key="index">
+			<view class="publicItem" @click="goDetail(item.requireId)">
+				<view class="hotStudent">
+					<template v-if="item.sex === '女'">
+						<image class="teachImg" src="../../static/girl.png"></image>
+					</template>
+					<template v-else>
+						<image class="teachImg" src="../../static/boy.png"></image>
+					</template>
+					<view class="hotStudentText">
+						<view class="studentTitle">{{item.nickname}}学员</view>
+						<view class="publicSex">{{item.sex}}</view>
+						<view class="stuGoal">{{item.goal}}</view>
+						<view class="studentDistance" v-if="isShowDistance">
+							<uni-icons type="location" color="#3ed598" ></uni-icons>
+							<text>{{item.kil}}</text>km
+						</view>
+					</view>
+					<view class="stuSubject">{{item.subjectBig + "/" + item.subjectSmall}}</view>
+				</view>
+			</view>
+		</view>
+
+		<uni-fab :pattern="pattern" horizontal="left" vertical="bottom" @fabClick="fabClick"></uni-fab>
+	
+		<uni-drawer ref="showRight" mode="left" width="280">
+			<scroll-view style="height: 100%;" scroll-y="true">
+				<uni-section title="条件搜索" type="line"></uni-section>
+				<view class="searchInput" >
+					<uni-data-select v-model="queryObj.sex" :localdata="sexs" placeholder="学员性别" />
+				</view>
+				<view class="searchInput" >
+					<uni-data-select v-model="queryObj.time" :localdata="time" placeholder="上课时间" />
+				</view>
+				<view class="searchInput" >
+					<uni-data-select v-model="queryObj.money" :localdata="money" placeholder="需求金额" />
+				</view>
+				<view class="searchInput" >
+					<uni-data-picker placeholder="课程类别" popup-title="课程大纲-具体课程" v-model="queryObj.subject" :localdata="courseTree" preload="true" />
+				</view>
+				<view class="button-group">
+					<button @click="submit" class="myButton1">搜索</button>
+					<button @click="closeDrawer" class="myButton2">取消</button>
+				</view>
+			</scroll-view>
+		</uni-drawer>
+	</view>
+</template>
+
+<script>
+	import badgeMix from '@/mixins/tabbar-badge.js'
+	import computeDistance from '@/mixins/compute-distance.js'
+	import { mapState } from 'vuex'
+
+	export default {
+		mixins: [badgeMix, computeDistance],
+		computed: {
+			...mapState('m_user', ['location','token'])
+		},
+		data() {
+			return {
+				isShowDistance: false,
+				pattern: {
+					color: '#7A7E83',
+					backgroundColor: '#fff',
+					selectedColor: '#3ed598',
+					buttonColor: '#3ed598',
+					iconColor: '#fff'
+				},
+				stuNeeds: [],
+				queryObj: {
+					pageNum: 1,
+					pageSize: 7,
+					sex: '',
+					time: '',
+					money: '',
+					subject: '1-1',
+					subjectBig: '',
+				},
+				total: 0,
+				isloading: false,
+				// 选择课程
+				courseTree: [{
+						text: '一年级',
+						value: '1-0',
+						children: [{
+								text: '1.1班',
+								value: '1-1'
+							}
+						]
+					}
+				],
+				// 单选性别数据源
+				sexs: [{
+					text: '男',
+					value: '男'
+				}, {
+					text: '女',
+					value: '女'
+				}],
+				time: [{
+					text: '上午',
+					value: '上午'
+				}, {
+					text: '下午',
+					value: '下午'
+				}, {
+					text: '晚上',
+					value: '晚上'
+				}],
+				money: [{
+					text: '100以内',
+					value: '0-100'
+				}, {
+					text: '100到200以内',
+					value: '100-200'
+				}, {
+					text: '200-400以内',
+					value: '200-400'
+				}, {
+					text: '400以上',
+					value: '400-2000'
+				}]
+			};
+		},
+		watch: {
+			'token': {
+				handler() {
+					if (this.token !== '') {
+						this.isShowDistance = true
+						this.stuNeeds = []
+						this.getAllStuNeeds()
+					} else {
+						this.isShowDistance = false
+					}
+				}
+			}
+		},
+		created() {
+			if (this.token !== '') {
+				this.isShowDistance = true
+			}
+			this.getAllStuNeeds(),
+			this.getPriceAndTree()
+		},
+		methods: {
+			// 树形结构的课程和价格表
+			async getPriceAndTree() {
+				const {
+					data: result
+				} = await uni.$http.get('/education/course-price/treeAndPrice')
+				this.courseTree = result.data.treeCourse
+			},
+			submit() {
+				this.$refs.showRight.close();
+				if (this.queryObj.subject !== '1-1') {
+					// 课程科目
+					for (let x = 0; x < this.courseTree.length; x++) {
+						for (let y = 0; y < this.courseTree[x].children.length; y++) {
+							if (this.courseTree[x].children[y].value === this.queryObj.subject) {
+								this.queryObj.subjectBig = this.courseTree[x].value 
+							}
+						}
+					}
+				}
+				this.stuNeeds = []
+				this.getAllStuNeeds()
+			},
+			closeDrawer() {
+				this.$refs.showRight.close();
+				this.queryObj.sex = ''
+				this.queryObj.time = ''
+				this.queryObj.money = ''
+				this.queryObj.subject = '1-1'
+				this.queryObj.subjectBig = ''
+				
+				this.stuNeeds = []
+				this.getAllStuNeeds()
+			},
+			fabClick() {
+				this.$refs.showRight.open();
+			},
+			async getAllStuNeeds(cb) {
+				// 打开节流阀
+				this.isloading = true
+
+				// 发起请求
+				const {
+					data: result
+				} = await uni.$http.post('/education/student-requirements/getAllRequirements', this.queryObj)
+
+				// 关闭节流阀
+				this.isloading = false
+				// 只要数据请求完毕,就立即按需调用 cb 回调函数
+				cb && cb()
+
+				for (let i = 0; i < result.data.list.length; i++) {
+					let arr = result.data.list[i].locationAl.split(",")
+					let kil = this.space(arr[0], arr[1], this.location.latitude, this.location.longitude)
+					result.data.list[i].kil = kil
+					result.data.list[i].nickname = result.data.list[i].name.slice(0,1)
+					if (result.data.list[i].goal.length == 0) {
+						result.data.list[i].goal = "无"
+					}
+				}
+
+				// 新旧拼接
+				this.stuNeeds = [...this.stuNeeds, ...result.data.list]
+				this.total = result.data.total
+			},
+			// 下拉刷新
+			onPullDownRefresh() {
+				if (this.isloading) return
+
+				this.queryObj.pageNum = 1
+				this.total = 0
+				this.stuNeeds = []
+				this.isloading = false
+				this.getAllStuNeeds(() => uni.stopPullDownRefresh())
+			},
+			// 触底事件
+			onReachBottom() {
+				// 判断是否有下一页
+				if (this.queryObj.pageNum * this.queryObj.pageSize >= this.total) return uni.$showMsg('数据加载完毕!')
+
+				// 判断是否正在请求数据
+				if (this.isloading) return
+				this.queryObj.pageNum += 1
+				this.getAllStuNeeds()
+			},
+			goDetail(id) {
+				uni.navigateTo({
+					url: '/subpkg/student/require/student_require_all_detail?requireId=' + encodeURIComponent(id)
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF2CC;
+	}
+</style>
+
+<style lang="scss" scoped>
+
+	.button-group {
+		padding: 100rpx 40rpx;
+		display: flex;
+		justify-content: space-between;
+	}
+
+	.searchInput {
+		margin-bottom: 40rpx;
+	}
+	
+	/* 教员、学员头像 */
+	.teachImg,
+	.studentImg{
+		width: 25%;
+		height: 95%;
+		border-radius: 20%;
+	}
+	
+	.stuSubject{
+		position: absolute;
+		left: 200rpx;
+		top: 60rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 10rpx;
+		border-radius: 30rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+	
+	.studentTitle{
+		font-size: 14px;
+		position: absolute;
+		left: 200rpx;
+		top: 10rpx;
+		font-weight: bold;
+		color: #6d6d6d;
+	}
+	
+	/* 距离 */
+	.studentDistance{
+		position: absolute;
+		left: 300rpx;
+		top: 10rpx;
+		font-weight: bold;
+		color: #3ed598;
+		font-size: 12px;
+	}
+		
+	.stuGoal{
+		border: 2px solid #3ed598;
+		border-radius: 30rpx;
+		padding: 0rpx 10rpx;
+		font-size: 12px;
+		position: absolute;
+		left: 200rpx;
+		top: 115rpx;
+		color: #3ed598;
+		overflow: hidden;
+		text-overflow: ellipsis;
+		display: -webkit-box;
+		-webkit-box-orient: vertical;
+		-webkit-line-clamp: 1;
+	}
+		
+	/* item */
+	.publicItem{
+		margin-left: 20rpx;
+		margin-right: 20rpx;
+		margin-top: 10rpx ;
+		margin-bottom: 10rpx ;
+		// border: 0rpx solid gray;
+		padding: 10rpx 20rpx;
+		border-radius: 30rpx;
+		background-color: #ffffff;
+	}
+	
+	.hotStudent{
+		position: relative;
+		display: flex;
+		padding: 10rpx;
+		height: 170rpx;
+		align-items: center;
+	}
+	
+	/* teachsex */
+	.publicSex{
+		position: absolute;
+		right: 10rpx;
+		top: 5rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 10rpx;
+		border-radius: 50%;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+	
+	.myButton1{
+		// border: 0rpx solid gray;
+		padding: 10rpx 60rpx;
+		border-radius: 50rpx;
+		background-color: #35b882;
+		color: #ffffff;
+		font-size: 14px;
+	}
+	
+	/* myButton1 */
+	.myButton2{
+		// border: 0rpx solid gray;
+		padding: 10rpx 60rpx;
+		border-radius: 50rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 14px;
+	}
+</style>

+ 438 - 0
education_uni/pages/teacher/teacher.vue

@@ -0,0 +1,438 @@
+<template>
+	<view>
+		<view v-for="(item, index) in teacherList" :key="index">
+			<view class="publicItem" @click="toTeachDetail(item)">
+				<view class="itemFather">
+					<image class="teachImg" :src="item.profilePhoto"></image>
+					<view class="teachTitle">{{item.nickname}}教员</view>
+					<view class="publicSex">{{item.sex}}</view>
+					<view class="teachCollege">{{item.school}}</view>
+					<view class="teachEdu">{{item.education}}</view>
+					<view class="teachDistance" v-if="isShowDistance">
+						<uni-icons type="location" color="#3ed598" ></uni-icons>
+						<text>{{item.kil}}</text>km</view>
+					<view class="teachSubject">{{item.subject}}</view>
+					<view class="teachYears">教龄 {{item.teachAge}}</view>
+				</view>
+			</view>
+		</view>
+		
+		<uni-fab :pattern="pattern" horizontal="left" vertical="bottom" @fabClick="fabClick"></uni-fab>
+		
+		<uni-drawer ref="showRight" mode="left" width="280">
+			<scroll-view style="height: 100%;" scroll-y="true">
+				<uni-section title="条件搜索" type="line"></uni-section>
+				<view class="searchInput" >
+					<uni-data-select v-model="queryObject.sex" :localdata="sexs" placeholder="教员性别" />
+				</view>
+				<view class="searchInput" >
+					<uni-data-select v-model="queryObject.time" :localdata="time" placeholder="上课时间" />
+				</view>
+				<view class="searchInput" >
+					<uni-data-select v-model="queryObject.mode" :localdata="modes" placeholder="上课方式" />
+				</view>
+				<view class="searchInput" >
+					<uni-data-picker placeholder="课程类别" popup-title="课程大纲-具体课程" v-model="queryObject.course" :localdata="courseTree" preload="true" />
+				</view>
+				<view class="searchInput" >
+					<uni-data-select v-model="queryObject.identify" :localdata="identifies" placeholder="类型" />
+				</view>
+				<view class="searchInput" >
+					<uni-data-select v-model="queryObject.education" :localdata="educations" placeholder="学历" />
+				</view>
+				<view class="searchInput" >
+					<uni-data-select v-model="queryObject.school" :localdata="schools" placeholder="毕业学校" />
+				</view>
+				<view class="button-group">
+					<button @click="submit" class="myButton1">搜索</button>
+					<button @click="closeDrawer" class="myButton2">取消</button>
+				</view>
+			</scroll-view>
+		</uni-drawer>
+	</view>
+</template>
+
+<script>
+	import computeDistance from '@/mixins/compute-distance.js'
+	import badgeMix from '@/mixins/tabbar-badge.js'
+	import { mapState } from 'vuex'
+	
+	export default {
+		mixins: [badgeMix, computeDistance],
+		computed: {
+			...mapState('m_user', ['location','token'])
+		},
+		options: {
+			styleIsolation: 'shared', // 解除样式隔离
+		},
+		data() {
+			return {
+				isShowDistance: false,
+				// 选择课程
+				courseTree: [{
+						text: '一年级',
+						value: '1-0',
+						children: [{
+								text: '1.1班',
+								value: '1-1'
+							}
+						]
+					}
+				],
+				pattern: {
+					color: '#3ed598',
+					backgroundColor: '#3ed598',
+					selectedColor: '##3ed598',
+					buttonColor: '##3ed598',
+					iconColor: '#fff'
+				},
+				isLoading: false,	// 请求阀
+				// 老师列表
+				teacherList: [],
+				// 查询总数量
+				total: 0, 
+				// 查询对象
+				queryObject: {
+					pageNum: 1,
+					pageSize: 10,
+					course: '1-1',
+					identify: '',
+					education: '',
+					sex: '',
+					school: '',
+					mode: '',
+					time: ''
+				},
+				educations: [{
+					value: '专科在读',
+					text: '专科在读'
+				}, {
+					value: '专科毕业',
+					text: '专科毕业'
+				}, {
+					value: '本科在读',
+					text: '本科在读'
+				}, {
+					value: '本科毕业',
+					text: '本科毕业'
+				}, {
+					value: '硕士在读',
+					text: '硕士在读'
+				}, {
+					value: '硕士毕业',
+					text: '硕士毕业'
+				}, {
+					value: '博士在读',
+					text: '博士在读'
+				}, {
+					value: '博士毕业',
+					text: '博士毕业'
+				}],
+				// 单选老师身份
+				identifies: [{
+					text: '专职教员',
+					value: '专职教员'
+				}, {
+					text: '学生教员',
+					value: '学生教员'
+				}],
+				// 单选性别数据源
+				sexs: [{
+					text: '男',
+					value: '男'
+				}, {
+					text: '女',
+					value: '女'
+				}],
+				time: [{
+					text: '上午',
+					value: '上午'
+				}, {
+					text: '下午',
+					value: '下午'
+				}, {
+					text: '晚上',
+					value: '晚上'
+				}],
+				schools: [{
+					text: '四川大学',
+					value: '四川大学'
+				}, {
+					text: '电子科技大学',
+					value: '电子科技大学'
+				}, {
+					text: '西南交通大学',
+					value: '西南交通大学'
+				}, {
+					text: '四川师范大学',
+					value: '四川师范大学'
+				}, {
+					text: '成都大学',
+					value: '成都大学'
+				}],
+				modes: [{
+					text: '老师上门',
+					value: '老师上门'
+				}, {
+					text: '学员上门',
+					value: '学员上门'
+				}, {
+					text: '线上辅导',
+					value: '线上辅导'
+				}],
+			}
+		},
+		watch: {
+			'token': {
+				handler() {
+					if (this.token !== '') {
+						this.isShowDistance = true
+						this.teacherList = []
+						this.getTeacherList()
+					} else {
+						this.isShowDistance = false
+					}
+				}
+			}
+		},
+		created() {
+			if (this.token !== '') {
+				this.isShowDistance = true
+			}
+			this.getTeacherList()
+			this.getPriceAndTree()
+		},
+		methods: {
+			// 树形结构的课程和价格表
+			async getPriceAndTree() {
+				const {
+					data: result
+				} = await uni.$http.get('/education/course-price/treeAndPrice')
+				this.courseTree = result.data.treeCourse
+			},
+			fabClick() {
+				this.$refs.showRight.open();
+			},
+			submit() {
+				this.$refs.showRight.close();
+				// 课程科目
+				if (this.queryObject.course !== '1-1') {
+					for (let x = 0; x < this.courseTree.length; x++) {
+						for (let y = 0; y < this.courseTree[x].children.length; y++) {
+							if (this.courseTree[x].children[y].value === this.queryObject.course) {
+								this.queryObject.course = this.courseTree[x].value + '/' + this.queryObject.course
+							}
+						}
+					}
+				}
+				this.teacherList = []
+				this.getTeacherList()
+			},
+			closeDrawer() {
+				this.$refs.showRight.close();
+				this.queryObject = {}
+				this.queryObject.pageNum = 1
+				this.queryObject.pageSize = 10
+				this.queryObject.course = '1-1'
+				this.teacherList = []
+				this.getTeacherList()
+			},
+			// 老师细节
+			toTeachDetail(item) {
+				uni.navigateTo({
+					url: '/subpkg/teacher/course/teacher_course_all_detail?item=' + encodeURIComponent(JSON.stringify(item))
+				})
+			},
+			// 获取老师列表
+			async getTeacherList(cb) {
+				// 打开节流阀
+				this.isLoading = true
+				const { data: result } = await uni.$http.post('/education/teacher-courses/showCourse', this.queryObject)
+				this.isLoading = false
+				
+				// 加载完数据执行
+				cb && cb()
+				for (let i = 0; i < result.data.course.length; i++) {
+					let arr = result.data.course[i].locationAl.split(",")
+					let kil = this.space(arr[0], arr[1], this.location.latitude, this.location.longitude)
+					result.data.course[i].kil = kil
+					result.data.course[i].nickname = result.data.course[i].name.slice(0,1)
+				}
+
+				this.teacherList = [...this.teacherList, ...result.data.course]
+				this.total = result.data.count
+			},
+			// 触底事件
+			onReachBottom() {
+				// 判断是否有下一页的数据
+				if (this.queryObject.pageNum * this.queryObject.pageSize >= this.total) return uni.$showMsg('数据加载完毕!')
+
+				// 判断是否正在请求其他数据
+				if (this.isLoading) return
+				this.queryObject.pageNum += 1
+				// 重新获取数据
+				this.getTeacherList()
+			},
+			// 下拉刷新事件
+			onPullDownRefresh() {
+				// 1. 重置关键数据
+				this.queryObject.pageNum = 1
+				this.total = 0
+				this.teacherList = []
+				// 2.重新发起请求
+				this.getTeacherList(() => uni.stopPullDownRefresh())
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		//background-color: #FFF2CC;
+	}
+</style>
+
+<style scoped lang="scss">
+	.itemFather{
+		position: relative;
+		display: flex;
+		padding: 10rpx;
+		height: 170rpx;
+		align-items: center;
+	}
+	
+	.searchInput {
+		margin-bottom: 40rpx;
+	}
+		
+	/* 设置单个教员背景 */
+	.publicItem{
+		margin-left: 20rpx;
+		margin-right: 20rpx;
+		margin-top: 10rpx ;
+		margin-bottom: 10rpx ;
+		// border: 0rpx solid gray;
+		padding: 10rpx 20rpx;
+		border-radius: 30rpx;
+		background-color: #ffffff;
+	}
+	
+	.teachTitle{
+		font-size: 14px;
+		position: absolute;
+		left: 200rpx;
+		top: 10rpx;
+		font-weight: bold;
+		color: #6d6d6d;
+	}
+
+	/* 教员头像 */
+	.teachImg{
+		width: 25%;
+		height: 95%;
+		border-radius: 20%;
+	}
+	
+	/* 距离 */
+	.teachDistance{
+		position: absolute;
+		left: 330rpx;
+		top: 10rpx;
+		font-weight: bold;
+		color: #3ed598;
+		font-size: 12px;
+		
+	}
+	
+	/* teachsex */
+	.publicSex{
+		position: absolute;
+		right: 10rpx;
+		top: 5rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 10rpx;
+		border-radius: 50%;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+	/* teachEdu */
+	.teachEdu{
+		position: absolute;
+		right: 10rpx;
+		top: 60rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 10rpx;
+		border-radius: 30rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+	/* teach课程 */
+	.teachSubject{
+		position: absolute;
+		left: 200rpx;
+		top: 115rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 12rpx;
+		border-radius: 30rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+	
+	/* teach课程 */
+	.teachYears{
+		position: absolute;
+		right: 10rpx;
+		top: 115rpx;
+		border: 2px solid  #3ed598;
+		padding: 5rpx 20rpx;
+		border-radius: 30rpx;
+		color: #3ed598;
+		font-size: 12px;
+		font-weight: bold;
+	}
+	
+	.teachCollege{
+		border: 2px solid #3ed598;
+		border-radius: 30rpx;
+		padding: 0rpx 10rpx;
+		font-size: 12px;
+		position: absolute;
+		left: 200rpx;
+		top: 60rpx;
+		color: #3ed598;
+		
+	}
+
+	.button-group {
+		padding: 100rpx 40rpx;
+		display: flex;
+		justify-content: space-between;
+	}
+	/* myButton1 */
+	.myButton1{
+		// border: 0rpx solid gray;
+		padding: 15rpx 60rpx;
+		border-radius: 50rpx;
+		background-color: #35b882;
+		color: #ffffff;
+		font-size: 14px;
+	}
+	
+	/* myButton1 */
+	.myButton2{
+		// border: 0rpx solid gray;
+		padding: 15rpx 60rpx;
+		border-radius: 50rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 14px;
+	}
+	::v-deep .uni-fab__circle {
+		background-color: #3ed598 !important;
+	}
+</style>

BIN
education_uni/static/authorized.png


BIN
education_uni/static/authorizedd.png


BIN
education_uni/static/avatar-msg.png


BIN
education_uni/static/avatar.png


BIN
education_uni/static/boy.png


+ 20 - 0
education_uni/static/customicons.css

@@ -0,0 +1,20 @@
+@font-face {
+  font-family: "customicons"; /* Project id 2878519 */
+  src:url('/static/customicons.ttf') format('truetype');
+}
+
+.customicons {
+  font-family: "customicons" !important;
+}
+
+.youxi:before {
+  content: "\e60e";
+}
+
+.wenjian:before {
+  content: "\e60f";
+}
+
+.zhuanfa:before {
+  content: "\e610";
+}

BIN
education_uni/static/customicons.ttf


BIN
education_uni/static/girl.png


BIN
education_uni/static/hot.png


BIN
education_uni/static/location.png


BIN
education_uni/static/official_account.jpg


BIN
education_uni/static/right.png


BIN
education_uni/static/rightwhite.png


BIN
education_uni/static/share.jpg


BIN
education_uni/static/tab_icons/home.png


BIN
education_uni/static/tab_icons/home_active.png


BIN
education_uni/static/tab_icons/message.png


BIN
education_uni/static/tab_icons/message_active.png


BIN
education_uni/static/tab_icons/my.png


BIN
education_uni/static/tab_icons/my_active.png


BIN
education_uni/static/tab_icons/student.png


BIN
education_uni/static/tab_icons/student_active.png


BIN
education_uni/static/tab_icons/teacher.png


BIN
education_uni/static/tab_icons/teacher_active.png


BIN
education_uni/static/xb-swiper-preview/icon-back.png


+ 21 - 0
education_uni/store/store.js

@@ -0,0 +1,21 @@
+// 1. 导入 Vue 和 Vuex
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+// 导入用户的 vuex 模块
+import moduleUser from './user.js'
+
+// 2. 将 Vuex 安装为 Vue 的插件
+Vue.use(Vuex)
+
+// 3. 创建 Store 的实例对象
+const store = new Vuex.Store({
+	// TODO:挂载 store 模块
+	modules: {
+		// 挂载用户的 vuex 模块,访问路径为 m_user
+		m_user: moduleUser,
+	},
+})
+
+// 4. 向外共享 Store 的实例对象
+export default store

+ 68 - 0
education_uni/store/user.js

@@ -0,0 +1,68 @@
+export default {
+	// 开启命名空间
+	namespaced: true,
+	
+	// state 数据
+	state: () => ({
+		// 登录成功之后的 token 字符串
+		token: uni.getStorageSync('token') || '',
+		// 用户的基本信息
+		userinfo: JSON.parse(uni.getStorageSync('userinfo') || '{}'),
+		// 老师认证结果
+		authentication: uni.getStorageInfoSync('authentication') || '',
+		// 经纬度
+		location: uni.getStorageSync('location') || '{}',
+		// 推荐人  uid 字符串
+		recoUID: uni.getStorageSync('recoUID') || '',
+	}),
+	// 方法
+	mutations: {
+		// 更新用户的基本信息
+		updateUserInfo(state, userinfo) {
+			state.userinfo = userinfo
+			// 通过 this.commit() 方法,调用 m_user 模块下的 saveUserInfoToStorage 方法,将 userinfo 对象持久化存储到本地
+			this.commit('m_user/saveUserInfoToStorage')
+		},
+		// 将 userinfo 持久化存储到本地
+		saveUserInfoToStorage(state) {
+			uni.setStorageSync('userinfo', JSON.stringify(state.userinfo))
+		},
+		// 更新 token 字符串
+		updateToken(state, token) {
+			state.token = token
+			// 通过 this.commit() 方法,调用 m_user 模块下的 saveTokenToStorage 方法,将 token 字符串持久化存储到本地
+			this.commit('m_user/saveTokenToStorage')
+		},
+		// 将 token 字符串持久化存储到本地
+		saveTokenToStorage(state) {
+			uni.setStorageSync('token', state.token)
+		},
+		// 更新老师认证结果
+		updateAuthentication(state, message) {
+			state.authentication = message
+			this.commit('m_user/saveAuthentication')
+		},
+		// 将老师认证结果存储到本地
+		saveAuthentication(state) {
+			uni.setStorageSync('authentication', state.authentication)
+		},
+		// 更新经纬度
+		updateLocation(state, location) {
+			state.location = location
+			this.commit('m_user/saveLocation')
+		},
+		// 将经纬度存储到本地
+		saveLocation(state) {
+			uni.setStorageSync('location', state.location)
+		},
+		// 更新 recoUID 字符串
+		updateRecoUID(state, recoUID) {
+			state.recoUID = recoUID
+			this.commit('m_user/saveRecoUIDToStorage')
+		},
+		// 将 recoUID 字符串持久化存储到本地
+		saveRecoUIDToStorage(state) {
+			uni.setStorageSync('recoUID', state.recoUID)
+		}
+	},
+}

+ 185 - 0
education_uni/subpkg/manager/complaint/manager_complaint.vue

@@ -0,0 +1,185 @@
+<template>
+	<view>
+	    <!-- 建议列表 -->
+	    <view class="suggestContainer">
+	        <view class="suggest" @click="toSuggestDetail(item)" v-for="(item, index) in complaint" :key="index">
+	            <view class="suggestion">
+	                <view class="suggestHead">
+	                    <view>标题</view>
+	                    <view class="suggestTitle">{{item.complaintTitle}}</view>
+	                </view>
+	                <view class="suggestBody">
+	                    <view>日期</view>
+	                    <view class="suggestContent">{{item.fistDatetime}}</view>
+	                </view>
+	            </view>
+	            <view>
+	                <view class="dispose">{{item.status}}</view>
+	            </view>
+			</view>
+	    </view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				complaint: [],
+				obj: {
+					pageSize: 6,
+					pageNum: 1
+				},
+				total: 0,
+				isloading: false
+			};
+		},
+		onShow(){
+			this.obj.pageNum = 1
+			this.complaint = []
+			this.init();
+		},
+		methods:{
+			async init(cb){
+				// 打开节流阀
+				this.isloading = true
+				const { data: result } =await uni.$http.get('/education/my-complaint/findAllComplaint',this.obj)
+				// 关闭节流阀
+				this.isloading = false
+				// 只要数据请求完毕,就立即按需调用 cb 回调函数
+				cb && cb()
+				this.complaint = [...this.complaint, ...result.data.data]
+				this.total = result.data.count
+			},
+			// 下拉刷新
+			onPullDownRefresh() {
+				if (this.isloading) return
+				this.obj.pageNum = 1
+				this.total = 0
+				this.complaint = []
+				this.isloading = false
+				this.init(() => uni.stopPullDownRefresh())
+			},
+			// 触底事件
+			onReachBottom() {
+				// 判断是否有下一页
+				if (this.obj.pageNum * this.obj.pageSize >= this.total) return uni.$showMsg('数据加载完毕!')
+			
+				// 判断是否正在请求数据
+				if (this.isloading) return
+				this.obj.pageNum += 1
+				this.init()
+			},
+			// 点击建议列表,跳转到对应的建议详情页
+			toSuggestDetail(item){
+				let complaint = JSON.stringify(item)
+				uni.navigateTo({
+					url: '/subpkg/manager/complaint/manager_complaint_detail?item=' + complaint
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+	/* 页面背景 */
+	// page{
+	//     /* height: 100%; */
+	//     /* height: auto !important; */
+	//     background-color: #E2F0D9;
+	// }
+	
+	/* 建议列表区 */
+	.suggestContainer{
+	    height: 100%;
+	    padding-bottom: 120rpx;
+	}
+	
+	/* 单条建议的背景 */
+	.suggest{
+	    display: flex;
+	    padding: 20rpx;
+	    margin: 20rpx 10rpx;
+	    height: 100rpx;
+	    border-radius: 30rpx;
+	    background-color: #FFF;		
+	}
+	
+	/* 单条建议左侧标题和内容摘要 */
+	.suggestion{
+	    width: 75%;
+	}
+	
+	/* 标题和内容摘要布局 */
+	.suggestHead,
+	.suggestBody{
+	    display: flex;
+	}
+	
+	/* 摘要 */
+	.suggestBody{
+	    margin-top: 10rpx;
+	}
+	
+	/* 标题详情和内容详情左边距 */
+	.suggestTitle,
+	.suggestContent{
+	    margin-left: 20rpx;
+	}
+	
+	/* 标题内容详情 */
+	.suggestTitle{
+	    width: 65%;
+	    white-space: nowrap;
+	    overflow: hidden;
+	    text-overflow: ellipsis;
+	}
+	
+	/* 内容摘要详情 */
+	.suggestContent{
+	    width: 80%;
+	    overflow: hidden;
+	    text-overflow: ellipsis;
+	    display: -webkit-box;
+	    -webkit-box-orient: vertical;
+	    -webkit-line-clamp: 2;
+	}
+	
+	/* 处理状态 */
+	.dispose{
+	    font-weight: bold;
+	    color: red;
+	    margin-left: 30rpx;
+	}
+	
+	/* 写建议按钮 */
+	.toWriteSuggestion{
+	    display: flex;
+	    position: relative;
+	    justify-content: center;
+	}
+	.writeSuggestion{
+	    text-align: center;    
+	    position: fixed;
+	    bottom: 0rpx;
+	    width: 100%;
+	    height: 120rpx;
+	    line-height: 120rpx;
+	    background-color: #E2F0D9;
+	}
+	.writeSuggestion text{
+	    background-color: #8FAADC;
+	    font-size: 36rpx;
+	    color: white;
+	    border-radius: 30rpx;
+	    padding: 10rpx 20rpx;
+	}
+</style>

+ 257 - 0
education_uni/subpkg/manager/complaint/manager_complaint_detail.vue

@@ -0,0 +1,257 @@
+<template>
+	 <view>
+		<view class="wrapper">
+		    <view>
+		        <view class="suggestHead">
+		            <text>投诉号</text>
+		            <text class="suggestHeadDetail">{{complaint.id}}</text>
+		        </view>
+		        <view class="suggestHead">
+		            <text>投诉人UID</text>
+		            <text class="suggestHeadDetailID">{{complaint.fromUid}}</text>
+		        </view>
+		        <view class="suggestHead">
+		            <text>处理人UID</text>
+		            <text class="suggestHeadDetailID">{{complaint.processorUid}}</text>
+		        </view>
+		        <view class="suggestHead">
+		            <text>投诉日期</text>
+		            <text class="suggestHeadDetail">{{complaint.fistDatetime}}</text>
+		        </view>
+		    </view>
+		   
+		    <view>
+		        <view class="suggestTitle">
+		            <text>投诉标题</text>
+		            <text class="suggestTitleDetail">{{complaint.complaintTitle}}</text>
+		        </view>
+		        <view class="suggestContent">
+		            <text>投诉内容</text>
+		            <text class="suggestContentDetail">{{complaint.complaintDetail}}</text>
+		        </view>
+		    </view>
+		  
+		    <view>
+		        <view class="handleResult">
+		            <text>处理结果</text>
+		            <text class="handleResultDetail">{{complaint.result}}</text>
+		        </view>
+		        <view class="handleDate">
+		            <text>结案日期</text>
+		            <text class="DateDetail">{{complaint.closetime}}</text>
+		        </view>
+		        <view class="handleStatus">
+		            <text>状态</text>
+		            <text style="width: 50px;" class="handleStatusDetail">{{complaint.status}}</text>
+		        </view>
+				<view class="handleBtn-wrapper">
+					<view class="handleBtn" @click="toHandleSuggest">处理</view>
+				</view>
+				
+		    </view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				complaint: {}
+			};
+		},
+		onLoad(opt){
+			this.complaint = JSON.parse(opt.item);
+			
+			if(this.complaint.result==null){
+				this.complaint.result=" ";
+			}
+			if(this.complaint.closetime==null){
+				this.complaint.closetime = " ";
+			}
+			if(this.complaint.processorUid==null){
+				this.complaint.processorUid = " ";
+			}
+		},
+		methods:{
+			toHandleSuggest(){
+				
+				if(this.complaint.status=="已处理"){
+							
+					uni.showModal({
+					    title: '',
+					    content: '该投诉已被处理'
+					})					
+				
+				}
+				
+				else{
+					uni.request({
+						url: `${uni.$http.baseUrl}/education/my-complaint/handlingComplaint`,
+						data: {
+								"id": this.complaint.id
+							},
+						header: {
+							token: uni.getStorageSync('token')
+						},
+						method: 'POST',
+						success: res => {
+							console.log(res)
+							this.complaint.status = "处理中"
+							let complaint = JSON.stringify(this.complaint)
+							uni.navigateTo({
+								url: '/subpkg/manager/complaint/manager_complaint_handle?item=' + complaint
+							})
+							
+						}
+					})
+				}
+				
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss">
+// page {
+// 	height: 100%;
+// 	background-color: #FFF2CC;
+// }
+
+.wrapper {
+	padding: 20rpx;
+}
+
+/* 建议号、建议人、建议日期 */
+.suggestHead {
+    display: flex;
+    margin-top: 10rpx;
+    padding: 10rpx;
+}
+
+.suggestHeadDetail,
+.suggestHeadDetailID {
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+
+/* 建议人和处理人ID */
+.suggestHeadDetailID {
+    color: #00B0F0;
+    text-decoration: underline;
+}
+
+/* 建议标题 */
+.suggestTitle,
+.suggestContent {
+    margin-top: 40rpx;
+    display: flex;
+}
+
+/* 建议标题内容 */
+.suggestTitleDetail {
+    display: block;
+    width: 70%;
+    height: 120rpx;
+    margin-left: 20rpx;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 3;
+}
+
+/* 建议内容 */
+.suggestContentDetail {
+    display: block;
+    width: 70%;
+    height: 200rpx;
+    margin-left: 20rpx;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 5;
+}
+
+/* 处理结果 */
+.handleResult {
+    margin-top: 60rpx;
+    display: flex;
+}
+
+/* 处理结果详情 */
+.handleResultDetail {
+    display: block;
+    width: 70%;
+    height: 80rpx;
+    margin-left: 20rpx;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 2;
+}
+
+/* 结案日期、处理状态 */
+.handleDate,
+.handleStatus {
+    display: flex;
+    margin-top: 40rpx;
+}
+
+/* 结案日期详情、状态详情 */
+.DateDetail,
+.handleStatusDetail {
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+
+/* 状态详情颜色 */
+.handleStatusDetail {
+    color: red;
+}
+
+/* 开始处理按钮 */
+.handleStart {
+    position: absolute;
+    bottom: 160rpx;
+    width: 200rpx;
+    margin-left: auto;
+    margin-right: auto;
+    left: 0;
+    right: 0;
+}
+
+.handleBtn-wrapper{
+	display: flex;
+	margin-top: 40rpx;
+	// border: 2rpx solid red;
+	height: 100rpx;
+	width: 100%;
+	align-items: center;
+	justify-content: center;
+}
+
+.handleBtn {
+	display: flex;
+   // padding: 10rpx 20rpx;
+	width: 80px;
+	height: 60rpx;
+	line-height: 60rpx;
+	// padding-left: 15px;
+	justify-content: center;
+    border-radius: 30rpx;
+    background-color: #35b882;
+    color: white;
+	margin-left: 20px;
+}
+</style>

+ 225 - 0
education_uni/subpkg/manager/complaint/manager_complaint_handle.vue

@@ -0,0 +1,225 @@
+<template>
+	<view style=" background-color: #F0F0F0; height: 100%;">
+		<!--pages/handleSuggest/handleSuggest.wxml-->
+		
+		<!-- 投诉信息 -->
+		<view class="suggestHead">
+		    <text>投诉号</text>
+		    <text class="suggestHeadDetail">{{complaint.id}}</text>
+		</view>
+		<view class="suggestHead">
+		    <text>投诉人UID</text>
+		    <text class="suggestHeadId">{{complaint.fromUid}}</text>
+		</view>
+		<view class="suggestHead">
+		    <text>处理人UID</text>
+		    <text class="suggestHeadId">{{complaint.processorUid}}</text>
+		</view>
+		<view class="suggestHead">
+		    <text>投诉日期</text>
+		    <text class="suggestHeadDetail">{{complaint.fistDatetime}}</text>
+		</view>
+		<!-- 投诉标题 -->
+		<view class="suggestTitle">
+		    <text class="suggestTitleText">投诉标题</text>
+		    <text class="suggestTitleDetail">{{complaint.complaintTitle}}</text>
+		</view>
+		<!-- 投诉内容 -->
+		<view class="suggestTitle">
+		    <text class="suggestTitleText">投诉内容</text>
+		    <text class="suggestTitleDetail">{{complaint.complaintDetail}}</text>
+		</view>
+		<!-- 结案日期 -->
+		<view class="handleDate">
+		    <text>结案日期</text>
+		    <text class="handleDateDetail">{{complaint.closetime}}</text>
+		</view>
+		<!-- 处理状态 -->
+		<view class="handleStatus">
+		    <text>状态</text>
+		    <text class="handleStatusDetail">{{complaint.status}}</text>
+		</view>
+		<!-- 处理结果 -->
+		<view class="handleResult">
+		    <view class="handleResultTitle">处理结果</view>
+		    <!-- 未处理 -->
+		    <view>
+		        <textarea v-model="result"  class="handleDetail" maxlength="512" placeholder="不超过512个字"></textarea>
+		    </view>
+		</view>
+		<!-- 底部按钮 -->
+		<view class="handleEnd">
+		    <text class="handleClosed" @click="toHandle">结案</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+					complaint: {},
+					result: ""
+			};
+		},
+		onLoad(opt){
+			this.complaint = JSON.parse(opt.item);
+			if(this.complaint.processorUid==null){
+				this.complaint.processorUid = " ";
+			}
+		},
+		methods:{
+			toHandle(){
+				
+				var head = '^[ ]+$';
+				 
+				var re = new RegExp(head);
+				if (re.test(this.result)) {
+				             uni.showModal({
+				                 title: '',
+				                 content: '结果不能为空'
+				             })
+				} 
+				else if(this.result==null || this.result==""){
+					uni.showModal({
+					    title: '',
+					    content: '结果不能为空'
+					})
+				}
+				else{
+				uni.request({
+					url: `${uni.$http.baseUrl}/education/my-complaint/handleComplaint`,
+					data: {
+							"id": this.complaint.id,
+							"result": this.result
+						},
+					header: {
+						token: uni.getStorageSync('token')
+					},
+					method: 'POST',
+					success: res => {
+						uni.$showMsg(res.data.message)
+						uni.navigateBack({
+						     delta: 2,
+						})
+					}
+				})
+				}
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		padding: 20rpx;
+		height: 100%;
+		// background-color: #D4F5E9;
+	}
+</style>
+
+<style lang="scss" scoped>
+/* pages/handleSuggest/handleSuggest.wxss */
+
+/* 设置页面背景 */
+// page{
+//     padding: 20rpx;
+//     height: 100%;
+//     background-color: #FFF2CC;
+// }
+
+/* 顶部的投诉信息 */
+.suggestHead{
+    margin-top: 20rpx;
+}
+/* 顶部投诉信息详情、结案日期详情、状态处理详情 */
+.suggestHeadDetail,
+.suggestHeadId,
+.handleDateDetail,
+.handleStatusDetail{
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+.suggestHeadId{
+    color: #00B0F0;
+    text-decoration: underline;
+}
+
+/* 投诉详情 */
+.suggestTitle{
+    margin-top: 30rpx;
+    display: flex;
+    flex-direction: column;
+}
+/* 标题 */
+.suggestTitleText{
+    text-align: center;
+    font-weight: bold;
+    margin-bottom: 10rpx;
+	
+}
+/* 内容 */
+.suggestTitleDetail{
+    width: 94%;    
+}
+
+/* 结案日期 */
+.handleDate{
+    margin-top: 40rpx;
+}
+
+/* 处理状态 */
+.handleStatus{
+    margin-top: 40rpx;
+}
+.handleStatusDetail{
+    color: red;
+}
+
+/* 处理结果 */
+.handleResult{
+    display: flex;
+    flex-direction: column;
+}
+.handleResultTitle{
+    text-align: center;
+    margin: 20rpx 0;
+    font-weight: bold;
+}
+
+/* 处理结果详情 */
+.handleDetail{
+    padding: 10rpx;
+    background-color: #fff;
+    // border: 1rpx solid gray;
+    border-radius: 20rpx;
+    width: 93%;
+	//margin: auto;
+    //margin-bottom: 40rpx;
+}
+.handleResultDetail{
+    min-height: 200rpx;
+    padding: 10rpx;
+    background-color: #fff;
+    border-radius: 20rpx;
+    width: 93%;
+    margin-bottom: 40rpx;
+}
+
+/* 结案 */
+.handleEnd{
+    display: flex;
+    justify-content: center;
+	margin-top: 40rpx;
+    margin-bottom: 40rpx;
+}
+.handleClosed{
+    background-color: #35b882;
+    font-size: 40rpx;
+    padding: 10rpx 30rpx;
+    border-radius: 40rpx;
+    color: white;
+}
+
+</style>

+ 82 - 0
education_uni/subpkg/manager/manager.vue

@@ -0,0 +1,82 @@
+<template>
+	<view class="manageOrderWrapper">
+	    <!-- 订单管理入口 -->
+	    <view class="manageOrder" @click="toManageOrder">
+	        <view>订单管理</view>
+	        <image class="rightArrow" src="@/static/rightwhite.png"></image>
+	    </view>
+	    <!-- 投诉管理入口 -->
+	    <view class="manageOrder" @click="toHandleComplaint">
+	        <view>投诉管理</view>
+	        <image class="rightArrow" src="@/static/rightwhite.png"></image>
+	    </view>
+	    <!-- 建议管理入口 -->
+	    <view class="manageOrder" @click="toHandleSuggest">
+	        <view>建议管理</view>
+	        <image class="rightArrow" src="@/static/rightwhite.png"></image>
+	    </view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			};
+		},
+		methods: {
+			toHandleComplaint() {
+				uni.navigateTo({
+					url: '/subpkg/manager/complaint/manager_complaint'
+				})
+			},
+			toHandleSuggest() {
+				uni.navigateTo({
+					url: '/subpkg/manager/suggestion/manager_suggestion'
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		padding: 20rpx;
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+// page{
+//     height: 100%;
+//     background-color: #E2F0D9;
+//     padding: 20rpx;
+// }
+
+/* 订单管理 */
+.manageOrderWrapper{
+    width: 96%;
+}
+.manageOrder{
+    display: flex;
+    position: relative;
+    height: 80rpx;
+    background-color: #35b882;
+    align-items: center;
+    padding-left: 20rpx;
+    border-radius: 20rpx;
+    margin-bottom: 20rpx;
+	color: white;
+}
+
+/* 箭头样式 */
+.rightArrow{
+    width: 30rpx;
+    height: 30rpx;
+    position: absolute;
+    right: 60rpx;
+}
+</style>

+ 185 - 0
education_uni/subpkg/manager/suggestion/manager_suggestion.vue

@@ -0,0 +1,185 @@
+<template>
+	<view style="padding-bottom: 10px;">
+	    <!-- 建议列表 -->
+	    <view class="suggestContainer">
+	        <view class="suggest" @click="toSuggestDetail(item)" v-for="(item, index) in suggestion" :key="index">
+	            <view class="suggestion">
+	                <view class="suggestHead">
+	                    <view>标题</view>
+	                    <view class="suggestTitle">{{item.adviseTitle}}</view>
+	                </view>
+	                <view class="suggestBody">
+	                    <view>日期</view>
+	                    <view class="suggestContent">{{item.fistDatetime}}</view>
+	                </view>
+	            </view>
+	            <view>
+	                <view class="dispose">{{item.status}}</view>
+	            </view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				suggestion: [],
+				obj: {
+					pageSize: 6,
+					pageNum: 1
+				},
+				total: 0,
+				isloading: false
+			};
+		},
+		onShow(){
+			this.obj.pageNum = 1
+			this.suggestion = []
+			this.init();
+		},
+		methods:{
+			async init(cb){
+				// 打开节流阀
+				this.isloading = true
+				const { data: result } =await uni.$http.get('/education/my-suggestion/findAllAdvise',this.obj)
+				// 关闭节流阀
+				this.isloading = false
+				// 只要数据请求完毕,就立即按需调用 cb 回调函数
+				cb && cb()
+				this.suggestion = [...this.suggestion, ...result.data.data]
+				this.total = result.data.count;
+			},
+			// 下拉刷新
+			onPullDownRefresh() {
+				if (this.isloading) return
+				this.obj.pageNum = 1
+				this.total = 0
+				this.suggestion = []
+				this.isloading = false
+				this.init(() => uni.stopPullDownRefresh())
+			},
+			// 触底事件
+			onReachBottom() {
+				// 判断是否有下一页
+				if (this.obj.pageNum * this.obj.pageSize >= this.total) return uni.$showMsg('数据加载完毕!')
+			
+				// 判断是否正在请求数据
+				if (this.isloading) return
+				this.obj.pageNum += 1
+				this.init()
+			},
+			// 点击建议列表,跳转到对应的建议详情页
+			toSuggestDetail(item){
+				let suggestion = JSON.stringify(item)
+				uni.navigateTo({
+					url: '/subpkg/manager/suggestion/manager_suggestion_detail?item=' + encodeURIComponent(suggestion)
+				})
+			},
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+	.toWriteSuggestion{
+	    display: flex;
+	    position: relative;
+	    justify-content: center;		
+	}
+	
+	/* 页面背景 */
+	// page{
+	//     /* height: 100%; */
+	//     /* height: auto !important; */
+	//     background-color: #E2F0D9;
+	// }
+	
+	/* 建议列表区 */
+	.suggestContainer{
+	    height: 100%;
+	    padding-bottom: 10rpx;		
+	}
+	
+	/* 单条建议的背景 */
+	.suggest{
+	    display: flex;
+	    padding: 20rpx;
+	    margin: 20rpx 10rpx;
+	    height: 100rpx;
+	    border-radius: 30rpx;
+	    background-color: #FFF;
+	}
+	
+	/* 单条建议左侧标题和内容摘要 */
+	.suggestion{
+	    width: 75%;
+	}
+	
+	/* 标题和内容摘要布局 */
+	.suggestHead,
+	.suggestBody{
+	    display: flex;
+	}
+	
+	/* 摘要 */
+	.suggestBody{
+	    margin-top: 10rpx;
+	}
+	
+	/* 标题详情和内容详情左边距 */
+	.suggestTitle,
+	.suggestContent{
+	    margin-left: 20rpx;
+	}
+	
+	/* 标题内容详情 */
+	.suggestTitle{
+	    width: 65%;
+	    white-space: nowrap;
+	    overflow: hidden;
+	    text-overflow: ellipsis;
+	}
+	
+	/* 内容摘要详情 */
+	.suggestContent{
+	    width: 80%;
+	    overflow: hidden;
+	    text-overflow: ellipsis;
+	    display: -webkit-box;
+	    -webkit-box-orient: vertical;
+	    -webkit-line-clamp: 2;
+	}
+	
+	/* 处理状态 */
+	.dispose{
+	    font-weight: bold;
+	    color: red;
+	    margin-left: 30rpx;
+	}
+	
+	/* 写建议按钮 */
+	.toWriteSuggestion{
+	    display: flex;
+	    position: relative;
+	    justify-content: center;
+	}
+	
+	.writeSuggestion{
+	    background-color: #35b882;
+	    font-size: 35rpx;
+	    color: gray;
+		border: lawngreen solid 1px;
+		padding: 10rpx 20rpx;
+		margin-left: 6px;
+	}
+
+</style>

+ 248 - 0
education_uni/subpkg/manager/suggestion/manager_suggestion_detail.vue

@@ -0,0 +1,248 @@
+<template>
+	 <view class="wrapper">
+		<view>
+		    <view>
+		        <view class="suggestHead">
+		            <text>建议号</text>
+		            <text class="suggestHeadDetail">{{suggestion.id}}</text>
+		        </view>
+		        <view class="suggestHead">
+		            <text>建议人UID</text>
+		            <text class="suggestHeadDetailID">{{suggestion.fromUid}}</text>
+		        </view>
+		        <view class="suggestHead">
+		            <text>处理人UID</text>
+		            <text class="suggestHeadDetailID">{{suggestion.processorUid}}</text>
+		        </view>
+		        <view class="suggestHead">
+		            <text>建议日期</text>
+		            <text class="suggestHeadDetail">{{suggestion.fistDatetime}}</text>
+		        </view>
+		    </view>
+		   
+		    <view>
+		        <view class="suggestTitle">
+		            <text>建议标题</text>
+		            <text class="suggestTitleDetail">{{suggestion.adviseTitle}}</text>
+		        </view>
+		        <view class="suggestContent">
+		            <text>建议内容</text>
+		            <text class="suggestContentDetail">{{suggestion.adviseDetail}}</text>
+		        </view>
+		    </view>
+		  
+		    <view>
+		        <view class="handleResult">
+		            <text>处理结果</text>
+		            <text class="handleResultDetail">{{suggestion.result}}</text>
+		        </view>
+		        <view class="handleDate">
+		            <text>结案日期</text>
+		            <text class="DateDetail">{{suggestion.closetime}}</text>
+		        </view>
+		        <view class="handleStatus">
+		            <text>状态</text>
+		            <text style="width: 50px;" class="handleStatusDetail">{{suggestion.status}}</text>
+		        </view>
+				<view class="handleBtn-wrapper">
+					<view class="handleBtn" @click="toHandleSuggest">处理</view>
+				</view>
+		    </view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				suggestion: {}
+			};
+		},
+		onLoad(opt){
+			this.suggestion = JSON.parse(decodeURIComponent(opt.item));
+			
+			if(this.suggestion.result==null){
+				this.suggestion.result=" ";
+			}
+			if(this.suggestion.closetime==null){
+				this.suggestion.closetime = " ";
+			}
+			if(this.suggestion.processorUid==null){
+				this.suggestion.processorUid = " ";
+			}
+		},
+		methods:{
+			toHandleSuggest(){
+				if(this.suggestion.status=="已处理"){
+							
+					uni.showModal({
+					    title: '',
+					    content: '该建议已被处理'
+					})					
+				}
+				else{
+					uni.request({
+						url: `${uni.$http.baseUrl}/education/my-suggestion/handlingAdvise`,
+						data: {
+								"id": this.suggestion.id
+						},
+						header: {
+							token: uni.getStorageSync('token')
+						},
+						method: 'POST',
+						success: res => {
+							this.suggestion.status = "处理中"
+							let suggestion = JSON.stringify(this.suggestion)
+							uni.navigateTo({
+								url: '/subpkg/manager/suggestion/manager_suggestion_handle?item=' + suggestion
+							})
+						}
+					})
+				}
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+// page {
+// 	height: 100%;
+// 	background-color: #FFF2CC;
+// }
+
+.wrapper {
+	padding: 20rpx;
+}
+
+/* 建议号、建议人、建议日期 */
+.suggestHead {
+    display: flex;
+    margin-top: 10rpx;
+    padding: 10rpx;
+}
+
+.suggestHeadDetail,
+.suggestHeadDetailID {
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+
+/* 建议人和处理人ID */
+.suggestHeadDetailID {
+    color: #00B0F0;
+    text-decoration: underline;
+}
+
+/* 建议标题 */
+.suggestTitle,
+.suggestContent {
+    margin-top: 40rpx;
+    display: flex;
+}
+
+/* 建议标题内容 */
+.suggestTitleDetail {
+    display: block;
+    width: 70%;
+    height: 120rpx;
+    margin-left: 20rpx;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 3;
+}
+
+/* 建议内容 */
+.suggestContentDetail {
+    display: block;
+    width: 70%;
+    height: 200rpx;
+    margin-left: 20rpx;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 5;
+}
+
+/* 处理结果 */
+.handleResult {
+    margin-top: 60rpx;
+    display: flex;
+}
+
+/* 处理结果详情 */
+.handleResultDetail {
+    display: block;
+    width: 70%;
+    height: 80rpx;
+    margin-left: 20rpx;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 2;
+}
+
+/* 结案日期、处理状态 */
+.handleDate,
+.handleStatus {
+    display: flex;
+    margin-top: 40rpx;
+}
+
+/* 结案日期详情、状态详情 */
+.DateDetail,
+.handleStatusDetail {
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+
+/* 状态详情颜色 */
+.handleStatusDetail {
+    color: red;
+}
+
+/* 开始处理按钮 */
+.handleStart {
+    position: absolute;
+    bottom: 160rpx;
+    width: 200rpx;
+    margin-left: auto;
+    margin-right: auto;
+    left: 0;
+    right: 0;
+}
+
+.handleBtn-wrapper{
+	display: flex;
+	margin-top: 40rpx;
+	// border: 2rpx solid red;
+	height: 100rpx;
+	width: 100%;
+	align-items: center;
+	justify-content: center;
+}
+
+.handleBtn {
+	display: flex;
+	width: 80px;
+	height: 60rpx;
+	line-height: 60rpx;
+	justify-content: center;
+    border-radius: 30rpx;
+    background-color: #35b882;
+    color: white;
+	margin-left: 20px;
+}
+</style>

+ 218 - 0
education_uni/subpkg/manager/suggestion/manager_suggestion_handle.vue

@@ -0,0 +1,218 @@
+<template>
+	<view style=" background-color: #F0F0F0; height: 100%;">
+		<!-- 建议信息 -->
+		<view class="suggestHead">
+		    <text>建议号</text>
+		    <text class="suggestHeadDetail">{{suggestion.id}}</text>
+		</view>
+		<view class="suggestHead">
+		    <text>建议人UID</text>
+		    <text class="suggestHeadId">{{suggestion.fromUid}}</text>
+		</view>
+		<view class="suggestHead">
+		    <text>处理人UID</text>
+		    <text class="suggestHeadId">{{suggestion.processorUid}}</text>
+		</view>
+		<view class="suggestHead">
+		    <text>建议日期</text>
+		    <text class="suggestHeadDetail">{{suggestion.fistDatetime}}</text>
+		</view>
+		<!-- 建议标题 -->
+		<view class="suggestTitle">
+		    <text class="suggestTitleText">建议标题</text>
+		    <text class="suggestTitleDetail">{{suggestion.adviseTitle}}</text>
+		</view>
+		<!-- 建议内容 -->
+		<view class="suggestTitle">
+		    <text class="suggestTitleText">建议内容</text>
+		    <text class="suggestTitleDetail">{{suggestion.adviseDetail}}</text>
+		</view>
+		<!-- 结案日期 -->
+		<view class="handleDate">
+		    <text>结案日期</text>
+		    <text class="handleDateDetail">{{suggestion.closetime}}</text>
+		</view>
+		<!-- 处理状态 -->
+		<view class="handleStatus">
+		    <text>状态</text>
+		    <text class="handleStatusDetail">{{suggestion.status}}</text>
+		</view>
+		<!-- 处理结果 -->
+		<view class="handleResult">
+		    <view class="handleResultTitle">处理结果</view>
+		    <!-- 未处理 -->
+		    <view>
+		        <textarea v-model="result"  class="handleDetail" maxlength="512" placeholder="不超过512个字"></textarea>
+		    </view>
+		   
+		</view>
+		<!-- 底部按钮 -->
+		<view class="handleEnd">
+		    <text class="handleClosed" @click="toHandle">结案</text>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+					suggestion: {},
+					result: ""
+			};
+		},
+		onLoad(opt){
+			this.suggestion = JSON.parse(opt.item);
+			if(this.suggestion.processorUid==null){
+				this.suggestion.processorUid = " ";
+			}
+		},
+		methods:{
+			toHandle(){
+				var head = '^[ ]+$';
+				var re = new RegExp(head);
+				if (re.test(this.result)) {
+					 uni.showModal({
+						 title: '',
+						 content: '结果不能为空'
+					 })
+				} 
+				else if(this.result==null || this.result==""){
+					uni.showModal({
+					    title: '',
+					    content: '结果不能为空'
+					})
+				}
+				else{
+				uni.request({
+					url: `${uni.$http.baseUrl}/education/my-suggestion/handleAdvise`,
+					data: {
+							"id": this.suggestion.id,
+							"result": this.result
+						},
+					header: {
+						token: uni.getStorageSync('token')
+					},
+					method: 'POST',
+					success: res => {
+						uni.navigateBack({
+						     delta: 2,
+						})
+					}
+				})
+				}
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		padding: 20rpx;
+		height: 100%;
+		// background-color: #D4F5E9;
+	}
+</style>
+
+<style lang="scss" scoped>
+/* 设置页面背景 */
+// page{
+//     padding: 20rpx;
+//     height: 100%;
+//     background-color: #FFF2CC;
+// }
+
+/* 顶部的建议信息 */
+.suggestHead{
+    margin-top: 20rpx;
+}
+/* 顶部建议信息详情、结案日期详情、状态处理详情 */
+.suggestHeadDetail,
+.suggestHeadId,
+.handleDateDetail,
+.handleStatusDetail{
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+.suggestHeadId{
+    color: #00B0F0;
+    text-decoration: underline;
+}
+
+/* 建议详情 */
+.suggestTitle{
+    margin-top: 30rpx;
+    display: flex;
+    flex-direction: column;
+}
+/* 标题 */
+.suggestTitleText{
+    text-align: center;
+    font-weight: bold;
+    margin-bottom: 10rpx;
+}
+/* 内容 */
+.suggestTitleDetail{
+    width: 94%;    
+}
+
+/* 结案日期 */
+.handleDate{
+    margin-top: 40rpx;
+}
+
+/* 处理状态 */
+.handleStatus{
+    margin-top: 40rpx;
+}
+.handleStatusDetail{
+    color: red;
+}
+
+/* 处理结果 */
+.handleResult{
+    display: flex;
+    flex-direction: column;
+}
+.handleResultTitle{
+    text-align: center;
+    margin: 20rpx 0;
+    font-weight: bold;
+}
+
+/* 处理结果详情 */
+.handleDetail{
+    padding: 10rpx;
+    background-color: #fff;
+    // border: 1rpx solid gray;
+    border-radius: 20rpx;
+    width: 93%;
+	// margin: auto;
+    //margin-bottom: 40rpx;
+}
+.handleResultDetail{
+    min-height: 200rpx;
+    padding: 10rpx;
+    background-color: #fff;
+    border-radius: 20rpx;
+    width: 93%;
+    margin-bottom: 40rpx;
+}
+
+/* 结案 */
+.handleEnd{
+    display: flex;
+    justify-content: center;
+	margin-top: 40rpx;
+    margin-bottom: 40rpx;
+}
+.handleClosed{
+    background-color: #35b882;
+    font-size: 40rpx;
+    padding: 10rpx 30rpx;
+    border-radius: 40rpx;
+    color: white;
+}
+</style>

+ 166 - 0
education_uni/subpkg/my/complaint/my_complaint.vue

@@ -0,0 +1,166 @@
+<template>
+	  <view>
+	      <view class="complaintContainer">
+	          <view class="complaint" @click="toComplaintDetail(item)" v-for="(item, index) in complaint" :key="index">
+	              <view class="complain">
+	                  <view class="complaintHead">
+	                      <view>标题</view>
+	                      <view class="complaintTitle">{{item.complaintTitle}}</view>
+	                  </view>
+	                  <view class="complaintBody">
+	                      <view>内容摘要</view>
+	                      <view class="complaintContent">{{item.complaintDetail}}</view>
+	                  </view>
+	              </view>
+	              <view>
+	                  <view class="dispose">{{item.status}}</view>
+	              </view>
+	          </view>	  
+	      </view>
+	      <!-- 开始写建议按钮 -->
+	      <view class="toWriteComplaint">
+	          <view class="writeComplaint" @click="toWriteComplaint">
+	              <text>写投诉</text>
+	          </view>
+	      </view>
+	  </view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				complaint: [],
+				queryObj: {
+					pageNum: 1,
+					pageSize: 5
+				}
+			};
+		},
+		onShow() {
+			this.init();
+		},
+		methods:{
+			async init(){
+				const { data: result } =await uni.$http.get('/education/my-complaint/findPersonComplaint',this.queryObj)
+				this.complaint = result.data.data;
+			},
+			// 点击建议列表,跳转到对应的建议详情页
+			toComplaintDetail(item){
+				let complaint = JSON.stringify(item)
+				uni.navigateTo({
+					url: '/subpkg/my/complaint/my_complaint_detail?item=' + encodeURIComponent(complaint)
+				})
+			},
+			// 跳转到写建议页面
+			toWriteComplaint(){
+			   uni.navigateTo({
+			   	url: '/subpkg/my/complaint/my_complaint_write'
+			   })
+			}
+			
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;		
+	}
+</style>
+
+<style lang="scss" scoped>
+/* 页面背景 */
+// page{
+//     /* height: 100%; */
+//     /* height: auto !important; */
+//     background-color: #E2F0D9;
+// }
+
+/* 建议列表区 */
+.complaintContainer{
+    height: 100%;
+    padding-bottom: 120rpx;
+}
+
+/* 单条建议的背景 */
+.complaint{
+    display: flex;
+    padding: 20rpx;
+    margin: 20rpx 10rpx;
+    height: 140rpx;
+    border-radius: 30rpx;
+    background-color: #FFF2CC;
+}
+
+/* 单条建议左侧标题和内容摘要 */
+.complain{
+    width: 75%;
+}
+
+/* 标题和内容摘要布局 */
+.complaintHead,
+.complaintBody{
+    display: flex;
+}
+
+/* 摘要 */
+.complaintBody{
+    margin-top: 10rpx;
+}
+
+/* 标题详情和内容详情左边距 */
+.complaintTitle,
+.complaintContent{
+    margin-left: 20rpx;
+    width: 65%;
+}
+
+/* 标题内容详情 */
+.complaintTitle{
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+/* 内容摘要详情 */
+.complaintContent{
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 2;
+}
+
+/* 处理状态 */
+.dispose{
+    font-weight: bold;
+    color: red;
+    margin-left: 30rpx;
+}
+
+/* 写建议按钮 */
+.toWriteComplaint{
+    display: flex;
+    position: relative;
+    justify-content: center;
+}
+.writeComplaint{
+    text-align: center;    
+    position: fixed;
+    bottom: 0rpx;
+    width: 100%;
+    height: 120rpx;
+    line-height: 120rpx;
+    //background-color: #E2F0D9;
+}
+.writeComplaint text{
+    background-color: #35b882;
+    font-size: 36rpx;
+    color: white;
+    border-radius: 30rpx;
+    padding: 10rpx 20rpx;
+}
+</style>

+ 141 - 0
education_uni/subpkg/my/complaint/my_complaint_detail.vue

@@ -0,0 +1,141 @@
+<template>
+	<view class="wrapper">
+		<view>
+		    <view>
+		        <text>投诉号:</text>
+		        <text class="benginTwo">{{complaint.id}}</text>
+		    </view>
+		    <view>
+		        <text>ID:</text>
+		        <text class="benginTwo">{{complaint.fromUid}}</text>
+		    </view>
+		</view>
+		<!-- 处理人ID和处理人昵称 -->
+		<view>
+		    <view>
+		        <text>处理人ID:</text>
+		        <text>{{complaint.processorUid}}</text>
+		    </view>
+		    <view>
+		        <text>处理人昵称:</text>
+		        <text>{{complaint.name}}</text>
+		    </view>
+		</view>
+		<!-- 建议标题和日期 -->
+		<view class="suggestTitleWrapper">
+		    <text class="suggestTtile">投诉标题</text>
+		    <text class="suggestTime">{{complaint.complaintTitle}}</text>
+		</view>
+		<!-- 建议内容 -->
+		<view class="suggestContentWrapper">
+		    <text>投诉内容:</text>
+		    <text>{{complaint.complaintDetail}}</text>
+		</view>
+		<!-- 处理结果 -->
+		<view class="handleResult">
+		    <text>处理结果描述:</text>
+		    <text>{{complaint.result}}</text>
+		</view>
+		<!-- 日期 -->
+		<view class="handleResult">
+		    <text>结案日期时间:</text>
+		    <text class="handleTime">{{complaint.closetime}}</text>
+		</view>
+		<!-- 处理状态 -->
+		<view class="handleStatus">
+		    <text>{{complaint.status}}</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				complaint: {}
+			}
+		},
+		onLoad(opt){
+			this.complaint = JSON.parse(decodeURIComponent(opt.item));
+			if(this.complaint.processorUid==null){
+				this.complaint.processorUid = " ";
+			}
+			if(this.complaint.name==null){
+				this.complaint.name = " ";
+			}
+			if(this.complaint.result==null){
+				this.complaint.result = " ";
+			}
+			if(this.complaint.closetime==null){
+				this.complaint.closetime = " ";
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+		//background-color: #3ED598;
+	}
+</style>
+
+<style lang="scss" scoped>
+/* 设置背景 */
+// page{
+//     background-color: #FFF2CC;
+// 	height: 100%;
+// }
+
+.wrapper {
+	padding: 20rpx;
+}
+
+.benginTwo {
+	margin-left: 10rpx;
+}
+
+/* 建议标题和时间 */
+.suggestTitleWrapper{
+    margin-top: 50rpx;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+/* 单独设置标题 */
+.suggestTtile{
+    font-weight: bold;
+}
+/* 单独设置建议时间 */
+.suggestTime{
+    font-size: 26rpx;
+    color: #A6A6A6;
+}
+
+/* 建议内容 */
+.suggestContentWrapper{
+    margin-top: 40rpx;
+    display: flex;
+    flex-direction: column;
+    height: 600rpx;
+}
+/* 处理结果 */
+.handleResult{
+    margin-top: 30rpx;
+}
+/* 处理时间 */
+.handleTime{
+    font-weight: bold;
+}
+/* 处理状态 */
+.handleStatus{
+    margin: 60rpx 0;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    font-weight: bold;
+    color: red;
+}
+</style>

+ 164 - 0
education_uni/subpkg/my/complaint/my_complaint_write.vue

@@ -0,0 +1,164 @@
+<template>
+	<view>
+		<view>
+		    <!-- 投诉标题 -->
+		    <view class="complaintWrapper">
+		        <text class="complaintTitle">投诉标题</text>
+		        <textarea name="投诉标题" v-model="complaintTitle" cols="30" rows="10" maxlength="50" placeholder="不超过50字" class="titleInput" bindinput="getComplaintTitle"></textarea>
+		    </view>
+		    <!-- 投诉内容 -->
+		    <view class="complaintWrapper">
+		        <text class="complaintTitle">投诉内容</text>
+		        <textarea name="投诉内容" v-model="complaintDetail" cols="30" rows="10" maxlength="512" placeholder="不超过512字" class="contentInput" bindinput="getComplaintContent"></textarea>
+		    </view>
+		</view>
+		<!-- 取消和提交按钮 -->
+		<view class="suggestBtn">
+		    <button class="cancelBtn" @click="toCancel">取消</button> 
+		    <button class="confirmBtn" :disabled="disableButton" @click="toConfirm">提交</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				complaintTitle: "",
+				complaintDetail: "",
+				disableButton: false
+			}
+		},
+		methods: {
+			toCancel(){
+				this.complaintTitle = "";
+				this.complaintDetail = "";
+				uni.navigateBack({
+				     delta: 1,
+				})
+			},
+			toConfirm(){
+				this.disableButton = true
+				var head = '^[ ]+$';
+				var re = new RegExp(head);
+				if (!this.complaintTitle) {
+						uni.showModal({
+				           title: '投诉标题未写',
+				           content: '请补充标题后再重新提交'
+				    })
+				 }
+				 else if (re.test(this.complaintTitle)) {
+					 uni.showModal({
+						 title: '标题不能全为空格',
+						 content: '投诉标题不能全部为空格,请修改投诉标题后再提交'
+					 })
+				} 
+				else if (!this.complaintDetail) {
+					 uni.showModal({
+						 title: '投诉内容未写',
+						 content: '投诉内容不能为空,请补充投诉内容后再提交'
+					 })
+				} 
+				else if (re.test(this.complaintDetail)) {
+					 uni.showModal({
+						 title: '投诉内容不能全部为空格',
+						 content: '投诉内容不能全部为空格,请修改投诉内容后再提交'
+					 })
+				 }
+				else{
+					uni.request({
+						url: `${uni.$http.baseUrl}/education/my-complaint/writeComplaint`,
+						data: {
+								"complaintTitle": this.complaintTitle,
+								"complaintDetail": this.complaintDetail,
+							},
+						header: {
+							token: uni.getStorageSync('token')
+						},
+						method: 'POST',
+						success: res => {
+							uni.$showMsg('投诉成功')
+							setTimeout(() => {
+								uni.navigateBack()
+								this.disableButton = false
+							}, 1000)
+						}
+					})
+				}
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		//background-color: #FFF;
+		// background-color: #D4F5E9;
+	}
+</style>
+<style lang="scss" scoped>
+/* 设置页面背景 */
+// page{
+//     background-color: #E2F0D9;
+//     height: 100%;
+// }
+
+.complaintWrapper{
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    padding: 20rpx;
+}
+/* 标题 */
+.complaintTitle{
+    text-align: center;
+    padding-bottom: 20rpx;
+    font-weight: bold;
+}
+/* 输入的建议标题和内容公共样式 */
+.titleInput,
+.contentInput{
+    width: 93%;
+    padding: 10rpx;
+    /* border: 1rpx solid gray; */
+    border-radius: 20rpx;
+    background-color: #fff;
+}
+/* 建议标题输入框的高度 */
+.titleInput{
+    height: 150rpx;
+}
+
+/* 建议内容输入框的高度 */
+.contentInput{
+    height: 800rpx;
+}
+
+/* 下方按钮 */
+.suggestBtn{
+    display: flex;
+    margin-top: 40rpx;
+    justify-content: space-around;
+}
+
+.confirmBtn,
+.cancelBtn{
+    font-size: 42rpx;
+    height: 85rpx;
+    width: 160rpx;
+    line-height: 85rpx;
+    border-radius: 40rpx;
+    text-align: center;
+    color: white;
+}
+.confirmBtn{
+	background-color: #35b882;
+}
+.cancelBtn{
+	background-color: #3ed598;
+}
+
+
+</style>

+ 17 - 0
education_uni/subpkg/my/home/my_home_strategy.vue

@@ -0,0 +1,17 @@
+<template>
+	<view>
+		<xb-swiper-preview></xb-swiper-preview>
+	</view>
+</template>
+
+<script>
+	import xbSwiperPreview from '@/components/xb-swiper-preview/index.vue'
+	export default {
+		components:{
+		    xbSwiperPreview
+		},
+	}
+</script>
+
+<style>
+</style>

+ 179 - 0
education_uni/subpkg/my/invitation/my_invitation_receive.vue

@@ -0,0 +1,179 @@
+<template>
+	<view style="padding: 0px 30px;margin-top: 5px;">
+		<!-- 顶部对方已读和未读按钮 -->
+		<uni-segmented-control  :current="current" :values="items" @clickItem="onClickItem" styleType="button"
+			activeColor="#6EB312"></uni-segmented-control>
+		<!-- 发出的邀请列表 -->
+		<view v-show="current === 0">
+			<view v-for="(Info,index) in InviteInfoRead" :key="index">
+				<view class="invitationWrapper" @click="invitationDetail(Info)">
+					<view class="invitationTitle">
+						<view>
+							<text>邀请号</text>
+							<text class="invitatinDetail">{{Info.id}}</text>
+						</view>
+						<view class="other">
+							<text>对方</text>
+							<text class="invitatinDetail">{{Info.fromUname}} {{Info.identity}}</text>
+						</view>
+					</view>
+					<view class="invitationContent">
+						<text>邀请内容</text>
+						<text class="invitatinDetail">{{Info.requireDetail}}</text>
+					</view>
+					<view class="invitationDateAndStatus">
+						<view>
+							<text>邀请日期</text>
+							<text class="invitatinDetailOther">{{Info.datetime}}</text>
+						</view>
+						<view class="other">
+							<text>我方状态</text>
+							<text class="invitatinStatus">{{Info.operateStatus}}</text>
+						</view>
+					</view>
+				</view>
+
+			</view>
+		</view>
+		<view v-show="current === 1">
+			<view v-for="(Info,index) in InviteInfoUnRead" :key="index">
+				<view class="invitationWrapper" @click="invitationDetail(Info)">
+					<view class="invitationTitle">
+						<view>
+							<text>邀请号</text>
+							<text class="invitatinDetail">{{Info.id}}</text>
+						</view>
+						<view class="other">
+							<text>对方</text>
+							<text class="invitatinDetail">{{Info.fromUname}} {{Info.identity}}</text>
+						</view>
+					</view>
+					<view class="invitationContent">
+						<text>邀请内容</text>
+						<text class="invitatinDetail">{{Info.requireDetail}}</text>
+					</view>
+					<view class="invitationDateAndStatus">
+						<text>邀请日期</text>
+						<text class="invitatinDetailOther">{{Info.datetime}}</text>
+					</view>
+				</view>
+
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				current: 0,
+				items: ['已读', '未读'],
+				InviteInfoRead: [],
+				InviteInfoUnRead: []
+			};
+		},
+		created() {
+			this.readYes()
+		},
+		methods: {
+			async readYes() {
+				const {
+					data: result
+				} = await uni.$http.get('/education/invite-info/getReceivedInvitationRead')
+				this.InviteInfoRead = result.data.list
+			},
+			async readNo() {
+				const {
+					data: result
+				} = await uni.$http.get('/education/invite-info/getReceivedInvitationUnread')
+				this.InviteInfoUnRead = result.data.list
+			},
+			async invitationDetail(Info) {
+				uni.navigateTo({
+					url: '/subpkg/my/invitation/my_invitation_receive_detail?id='+encodeURIComponent(Info.id)
+				})
+			},
+			onClickItem(e) {
+				if (this.current != e.currentIndex) {
+					this.current = e.currentIndex
+				}
+				if (this.current === 1) {
+					this.readNo()
+				} 
+				if (this.current === 0) {
+					this.readYes()
+				}
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page {
+		padding: 20rpx;
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+<style lang="scss" scoped>
+
+	/* 顶部对方已读和未读按钮 */
+	.read {
+		display: flex;
+		justify-content: space-around;
+	}
+
+	.readDetail {
+		padding: 10rpx 20rpx;
+		border-radius: 30rpx;
+		background-color: #FFF2CC;
+		font-weight: bold;
+	}
+
+	/* 列表样式 */
+	.invitationWrapper {
+		width: 93%;
+		padding: 20rpx;
+		margin-top: 20rpx;
+		border-radius: 20rpx;
+		background-color: #FFF2CC;
+		margin-left: 10rpx;
+	}
+
+	/* 邀请号和对方身份、邀请日期和对方状态 */
+	.invitationTitle,
+	.invitationDateAndStatus {
+		display: flex;
+		position: relative;
+	}
+
+	/* 对方身份 */
+	.other {
+		position: absolute;
+		left: 60%;
+	}
+
+	/* 具体内容的样式 */
+	.invitatinDetail,
+	.invitatinStatus {
+		margin-left: 20rpx;
+		font-weight: bold;
+	}
+
+	.invitatinDetailOther {
+		margin-left: 20rpx;
+		font-weight: bold;
+		font-size: 26rpx;
+	}
+
+	.invitatinStatus {
+		color: red;
+	}
+
+	/* 邀请内容、邀请日期和对方状态 */
+	.invitationContent {
+		margin-top: 10rpx;
+	}
+</style>

+ 232 - 0
education_uni/subpkg/my/invitation/my_invitation_receive_detail.vue

@@ -0,0 +1,232 @@
+<template>
+	<view>
+		<view class="wrapper">
+		    <!-- 上方邀请号和照片 -->
+		    <view class="above">
+		        <view>
+		            <view class="aboveTitle">
+		                <text>邀请号:</text>
+		                <text>{{Info.id}}</text>
+		            </view>
+		            <view class="aboveTitle">
+		                <text>对方:</text>
+		                <text>{{Info.fromUname}}</text>
+		            </view>
+		        </view>
+				<!-- 头像 -->
+				<image v-if="Info.sex === null" class="headerPortrait" mode="widthFix" :src="Info.imgUrl"></image>
+				<image v-else-if="Info.sex === '男' " class="headerPortrait" mode="widthFix" src="/static/boy.png"></image>
+				<image v-else-if="Info.sex === '女' " class="headerPortrait" mode="widthFix" src="/static/girl.png"></image>
+		    </view>
+		     <!-- 中间详细信息 -->
+		     <view>
+		        <view class="midTitle">
+		            <text>对方ID:</text>
+		            <text>{{Info.fromUid}}</text>
+		        </view>
+		        <view class="midTitle">
+		            <text>需求号:</text>
+		            <text class="toLink" @click="toNeedDetail" style="color: rebeccapurple;">{{Info.requireId}}</text>
+		            <text class="needState">{{needState}}</text>
+		        </view>
+		        <view class="midTitle">
+		            <text>课程号:</text>
+		            <text class="toLink" @click="toCourseDetail" style="color: red;">{{Info.courseId}}</text>
+		            <text class="needState">{{courseState}}</text>
+		        </view>
+		        <view class="midTitle">
+		            <text>需求金额:</text>
+		            <text>{{Info.requireSalary}}</text>
+		        </view>
+		        <view class="midTitle">
+		            <text>邀请内容:</text>
+		            <text>{{Info.requireDetail}}</text>
+		        </view>
+		    </view>
+		    <view class="bottomWrapper">
+		        <view class="bottomTitle">
+		            <text>邀请日期:</text>
+		            <text>{{Info.datetime}}</text>
+		        </view>
+		        <view class="bottomTitle">
+		            <text>我方操作状态:</text>
+		            <text class="operateState">{{Info.operateStatus}}</text>
+		        </view>
+		    </view>
+		    <view class="operation" v-if="Info.operateStatus!=='拒绝'&&Info.operateStatus!=='同意'">
+		        <view class="operationRefuseBtn" @click="refuse">拒绝</view>
+		        <view class="operationConfirmBtn" @click="agree">同意</view>
+		    </view>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	import {mapMutations} from 'vuex'
+	export default {
+		data() {
+			return {
+				Info:[],
+			};
+		},
+		onLoad(option) {
+			if (option.id !== undefined) {
+				const id = decodeURIComponent(option.id)
+				this.getInvitationDetail(id)
+				this.toRead(id)
+			}
+		},
+		methods:{
+			toNeedDetail() {
+				uni.navigateTo({
+					url: '/subpkg/student/require/student_require_all_detail?requireId=' + encodeURIComponent(this.Info.requireId)
+				})
+			},
+			toCourseDetail() {
+				uni.navigateTo({
+					url: '/subpkg/teacher/course/teacher_course_all_detail?courseId=' + encodeURIComponent(this.Info.courseId)
+				})
+			},
+			async getInvitationDetail(id) {
+				const { data: result } = await uni.$http.get('/education/invite-info/getInvitationDetail', {inviteId: id})
+				this.Info = result.data.one
+			},
+			async toRead(id){
+				const queryObj = {
+					id
+				}
+				const { data: result } = await uni.$http.get('/education/invite-info/modifyStatusToHold',queryObj)
+			},
+			async refuse(){
+				const queryObj = {
+					id: this.Info.id
+				}
+				const { data: result } = await uni.$http.get('/education/invite-info/refuse',queryObj)
+				if (result.code == 20000) {
+					uni.$showMsg('拒绝邀请成功')
+					this.Info.operateStatus = '拒绝'
+					setTimeout(() => {
+						uni.navigateTo({
+							url: '/subpkg/my/invitation/my_invitation_receive'
+						}, 3000)
+					})
+				}
+			},
+			async agree(){
+				const queryObj = {
+					id: this.Info.id
+				}
+				const { data: result } = await uni.$http.get('/education/invite-info/agree',queryObj)
+				if (result.message == '该需求已锁,请30分钟后查看' || result.message == '该需求已下架' || result.message == '同意失败,请稍后在试' || result.message == '该课程已下架' || result.message == '该课程已锁,请30分钟后查看') {
+					return uni.$showMsg(result.message)
+				} 
+				const identify = result.data.identify
+				if ('教员' === identify) {
+					uni.$showMsg('已通知对方完成支付')
+					this.Info.operateStatus = '同意'
+					setTimeout(() => {
+						
+						uni.navigateTo({
+							url: '/subpkg/my/invitation/my_invitation_receive'
+						}, 3000)
+					})
+				}
+				if ('学员' === identify) {
+					const infos = result.data.info
+					uni.navigateTo({
+						url: '/subpkg/my/order/my_order_detail?orderId=' + encodeURIComponent(infos.orderId)
+					})
+				}			
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+/* 设置背景 */
+.wrapper{
+    width: 100%;
+    height: 100%;
+    //background-color: #FFF2CC;
+    padding: 20rpx;
+}
+
+/* 上方邀请号和照片 */
+.above{
+    display: flex;
+    width: 95%;
+    justify-content: space-between;
+}
+
+/* 上方、中间左侧文字 */
+.aboveTitle,
+.midTitle,
+.bottomTitle{
+    padding-bottom: 20rpx;
+}
+
+/* 设置链接样式 */
+.toLink{
+    color: skyblue;
+    text-decoration: underline;
+}
+
+/* 需求号和课程号状态 */
+.needState{
+    padding-left: 30rpx;
+    color: red;
+    font-weight: bold;
+}
+
+/* 头像 */
+.headerPortrait{
+    width: 200rpx;
+}
+
+/* 设置操作状态字体 */
+.operateState{
+    font-weight: bold;
+    color: red;
+}
+
+.bottomWrapper{
+    margin-top: 140rpx;
+}
+
+/* 底部按钮 */
+.operation{
+    display: flex;
+    justify-content: space-around;
+    margin-top: 120rpx;
+}
+
+/* 按钮 */
+.operationRefuseBtn,
+.operationConfirmBtn{
+    width: 160rpx;
+    height: 60rpx;
+    line-height: 60rpx;
+    text-align: center;
+    // border: 1rpx solid #5B9BD5;
+    border-radius: 30rpx;
+    font-size: 40rpx;
+    // background-color: #5B9BD5;
+    color: white;
+}
+.operationConfirmBtn{
+	background-color: #35b882;
+}
+.operationRefuseBtn{
+	background-color: #3ed598;
+}
+
+</style>

+ 188 - 0
education_uni/subpkg/my/invitation/my_invitation_send.vue

@@ -0,0 +1,188 @@
+<template>
+	<view style="padding: 0px 30px;margin-top: 5px;">
+		<!-- 顶部对方已读和未读按钮 -->
+		<uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" styleType="button" activeColor="#6EB312"></uni-segmented-control>
+		<!-- 发出的邀请列表 -->
+		<view v-show="current === 0">
+			<view v-for="(Info,index) in InviteInfoRead" :key="index">
+				<view class="invitationWrapper" @click="invitationDetail(Info)">
+					<view class="invitationTitle">
+						<view>
+							<text>邀请号</text>
+							<text class="invitatinDetail">{{Info.id}}</text>
+						</view>
+						<view class="other">
+							<text>对方</text>
+							<text class="invitatinDetail">{{Info.toUname}} {{Info.identity === '教员' ? '学员' : '教员'}}</text>
+						</view>
+					</view>
+					<view class="invitationContent">
+						<text>邀请内容</text>
+						<text class="invitatinDetail">{{Info.requireDetail}}</text>
+					</view>
+					<view class="invitationDateAndStatus">
+						<view>
+							<text>邀请日期</text>
+							<text class="invitatinDetailOther">{{Info.datetime}}</text>
+						</view>
+						<view class="other">
+							<text>我方状态</text>
+							<text class="invitatinStatus">{{Info.operateStatus}}</text>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view v-show="current === 1">
+			<view v-for="(Info,index) in InviteInfoUnRead" :key="index">
+				<view class="invitationWrapper" @click="invitationDetail(Info)">
+					<view class="invitationTitle">
+						<view>
+							<text>邀请号</text>
+							<text class="invitatinDetail">{{Info.id}}</text>
+						</view>
+						<view class="other">
+							<text>对方</text>
+							<text class="invitatinDetail">{{Info.toUname}} {{Info.identity === '教员' ? '学员' : '教员'}}</text>
+						</view>
+					</view>
+					<view class="invitationContent">
+						<text>邀请内容</text>
+						<text class="invitatinDetail">{{Info.requireDetail}}</text>
+					</view>
+					<view class="invitationDateAndStatus">
+						<text>邀请日期</text>
+						<text class="invitatinDetailOther">{{Info.datetime}}</text>
+					</view>
+				</view>
+
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	
+	export default {
+		data() {
+			return {
+				current: 1,
+				items: ['对方已读', '对方未读'],
+				InviteInfoRead: [],
+				InviteInfoUnRead: []
+			};
+		},
+		created() {
+			this.readNo()
+		},
+		methods: {
+			async readYes() {
+				const {
+					data: result
+				} = await uni.$http.get('/education/invite-info/getSendedInvitationRead')
+				this.InviteInfoRead = result.data.list
+			},
+			async readNo() {
+				const {
+					data: result
+				} = await uni.$http.get('/education/invite-info/getSendedInvitationUnread')
+				this.InviteInfoUnRead = result.data.list
+			},
+			async invitationDetail(Info) {
+				uni.navigateTo({
+					url: '/subpkg/my/invitation/my_invitation_send_detail?id=' + encodeURIComponent(Info.id)
+				})
+			},
+			onClickItem(e) {
+				if (this.current != e.currentIndex) {
+					this.current = e.currentIndex
+				}
+				if (this.current === 1) {
+					this.readNo()
+				} 
+				if (this.current === 0) {
+					this.readYes()
+				}
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		padding: 20rpx;
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+	// page {
+	// 	padding: 20rpx;
+	// 	height: 100%;
+	// 	background-color: #E2F0D9;
+	// }
+
+	/* 顶部对方已读和未读按钮 */
+	.read {
+		display: flex;
+		justify-content: space-around;
+	}
+
+	.readDetail {
+		padding: 10rpx 20rpx;
+		border-radius: 30rpx;
+		background-color: #FFF2CC;
+		font-weight: bold;
+	}
+
+	/* 列表样式 */
+	.invitationWrapper {
+		width: 93%;
+		padding: 20rpx;
+		margin-top: 20rpx;
+		border-radius: 20rpx;
+		background-color: #FFF2CC;
+		margin-left: 10rpx;
+	}
+
+	/* 邀请号和对方身份、邀请日期和对方状态 */
+	.invitationTitle,
+	.invitationDateAndStatus {
+		display: flex;
+		position: relative;
+	}
+
+	/* 对方身份 */
+	.other {
+		position: absolute;
+		left: 60%;
+	}
+
+	/* 具体内容的样式 */
+	.invitatinDetail,
+	.invitatinStatus {
+		margin-left: 20rpx;
+		font-weight: bold;
+	}
+
+	.invitatinDetailOther {
+		margin-left: 20rpx;
+		font-weight: bold;
+		font-size: 26rpx;
+	}
+	
+	.invitatinStatus {
+		color: red;
+	}
+
+	/* 邀请内容、邀请日期和对方状态 */
+	.invitationContent {
+		margin-top: 10rpx;
+	}
+</style>

+ 145 - 0
education_uni/subpkg/my/invitation/my_invitation_send_detail.vue

@@ -0,0 +1,145 @@
+<template>
+	<view>
+		<view class="wrapper" >
+		    <!-- 上方邀请号和照片 -->
+		    <view class="above">
+		        <view>
+		            <view class="aboveTitle">
+		                <text>邀请号:</text>
+		                <text>{{Info.id}}</text>
+		            </view>
+		            <view class="aboveTitle">
+		                <text>对方:</text>
+		                <text>{{Info.toUname}}</text>
+		            </view>
+		        </view>
+		        <!-- 头像 -->
+		        <image v-if="Info.sex === null" class="headerPortrait" mode="widthFix" :src="Info.imgUrl"></image>
+				<image v-else-if="Info.sex === '男' " class="headerPortrait" mode="widthFix" src="/static/boy.png"></image>
+				<image v-else-if="Info.sex === '女' " class="headerPortrait" mode="widthFix" src="/static/girl.png"></image>
+		    </view>
+		    <!-- 中间详细信息 -->
+		    <view>
+		        <view class="midTitle">
+		            <text>对方ID:</text>
+		            <text>{{Info.toUid}}</text>
+		        </view>
+		        <view class="midTitle">
+		            <text>需求号:</text>
+		            <text class="toLink" @click="toNeedDetail">{{Info.requireId}}</text>
+		        </view>
+		        <view class="midTitle">
+		            <text>课程号:</text>
+		            <text class="toLink" @click="toCourseDetail">{{Info.courseId}}</text>
+		        </view>
+		        <view class="midTitle">
+		            <text>需求金额:</text>
+		            <text>{{Info.requireSalary}}</text>
+		        </view>
+		        <view class="midTitle">
+		            <text>邀请内容:</text>
+		            <text>{{Info.requireDetail}}</text>
+		        </view>
+		    </view>
+		    <view class="bottomWrapper">
+		        <view class="bottomTitle">
+		            <text>邀请日期:</text>
+		            <text>{{Info.datetime}}</text>
+		        </view>
+		        <view class="bottomTitle">
+		            <text>对方阅读状态:</text>
+		            <text class="operateState">{{Info.readStatus}}</text>
+		        </view>
+		        <view class="bottomTitle">
+		            <text>对方操作状态:</text>
+		            <text class="operateState">{{Info.operateStatus}}</text>
+		        </view>
+		    </view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				Info:[],
+			};
+		},
+		onLoad(option) {
+			if (option.id !== undefined) {
+				const id = decodeURIComponent(option.id)
+				this.getInvitationDetail(id)
+			}
+		},
+		methods:{
+			toNeedDetail() {
+				uni.navigateTo({
+					url: '/subpkg/student/require/student_require_all_detail?requireId=' + encodeURIComponent(this.Info.requireId)
+				})
+			},
+			toCourseDetail() {
+				uni.navigateTo({
+					url: '/subpkg/teacher/course/teacher_course_all_detail?courseId=' + encodeURIComponent(this.Info.courseId)
+				})
+			},
+			async getInvitationDetail(id) {
+				const { data: result } = await uni.$http.get('/education/invite-info/getInvitationDetail', {inviteId: id})
+				this.Info = result.data.one
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+/* 设置背景 */
+.wrapper{
+    width: 100%;
+    height: 100%;
+    //background-color: #FFF2CC;
+    padding: 20rpx;
+}
+
+/* 上方邀请号和照片 */
+.above{
+    display: flex;
+    width: 95%;
+    justify-content: space-between;
+}
+
+/* 上方、中间左侧文字 */
+.aboveTitle,
+.midTitle,
+.bottomTitle{
+    padding-bottom: 20rpx;
+}
+
+/* 头像 */
+.headerPortrait{
+    width: 200rpx;
+}
+
+.bottomWrapper{
+    margin-top: 160rpx;
+}
+
+/* 设置链接样式 */
+.toLink{
+    color: skyblue;
+    text-decoration: underline;
+}
+
+/* 设置操作状态字体 */
+.operateState{
+    font-weight: bold;
+    color: red;
+}
+</style>

+ 96 - 0
education_uni/subpkg/my/message/my_message_detail.vue

@@ -0,0 +1,96 @@
+<template>
+	<view class="container">
+		<view class="title">{{msg.msgTitle}}</view>
+		<view class="text1">{{msg.big}}</view>
+		<view class="text2"  @click="gotoInvite" >{{msg.small}}</view>
+	</view>
+</template>
+
+<script>
+	import { mapMutations, mapState } from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_user', ['userinfo'])
+		},
+		data() {
+			return {
+				msg: {}
+			};
+		},
+		onLoad(option) {
+			this.msg = JSON.parse(decodeURIComponent(option.item))
+			let arr = this.msg.msgContent.split(":")
+			this.msg.big = arr[0]
+			this.msg.small = arr[1]
+			
+			if (this.msg.status == '未读') { 
+				this.updateStatus(this.msg.id)
+			}
+		},
+		methods: {
+			...mapMutations('m_user', ['updateUserInfo']),
+			updateStatus(id) {
+				const query = {
+					id
+				}
+				uni.$http.get('/education/mp-inner-msg/updateMsg', query)
+				this.userinfo.count--
+				this.updateUserInfo(this.userinfo)
+			},
+			gotoInvite() {
+				if (this.msg.msgTitle === '支付通知') {
+					uni.navigateTo({
+						url: '/subpkg/my/order/my_order_detail?orderId='+encodeURIComponent(this.msg.small)
+					})
+				} else if (this.msg.msgTitle === '邀请函'){
+					uni.navigateTo({
+						url: '/subpkg/my/invitation/my_invitation_receive_detail?id='+encodeURIComponent(this.msg.small)
+					})
+				} else if (this.msg.msgTitle === '支付成功') {
+					uni.navigateTo({
+						url: '/subpkg/student/order/student_order_detail?orderId='+encodeURIComponent(this.msg.small)
+					})
+				} else if (this.msg.msgTitle === '申请退款') {
+					uni.navigateTo({
+						url: '/subpkg/student/order/student_order_detail?orderId='+encodeURIComponent(this.msg.small)
+					})
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+.container {
+	border-radius: 40rpx;
+	background-color: #fff;
+	height: 40%;
+	margin-left: 20rpx;
+	margin-right: 20rpx;
+    padding: 20px 20px;
+	flex-wrap: wrap;
+}
+
+.title {
+	text-align: center;
+	font-weight: bold;
+	font-size: 35rpx;
+	color: #6d6d6d;
+	padding-bottom: 20px;
+	//margin-bottom: 20px;
+}
+	
+.text1 {
+	//padding-left: 40px;
+	text-align: center;
+	line-height: 30px;
+	font-size: 35rpx;
+}
+	
+.text2 {
+	text-align: center;
+	color: blue;
+	text-decoration: underline;
+	padding-top: 40px;
+}
+</style>

+ 32 - 0
education_uni/subpkg/my/official_account/my_official_account.vue

@@ -0,0 +1,32 @@
+<template>
+	<view class="account">
+		<image show-menu-by-longpress="true" mode="widthFix" src="@/static/official_account.jpg" ></image>
+		<view class="accountText">
+		    长按二维码可关注公众号
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+	}
+</script>
+
+<style>
+page{
+	height: 100%;
+	/* background-color: #FFF; */
+}
+.account{
+	//background-color: #FFF2CC;
+    width: 100%;
+    height: 100%;
+    justify-content: center;
+    text-align: center;
+    //margin-top: 40rpx;
+	padding-top: 40rpx;
+}
+.accountText{
+    margin-top: 40rpx;
+}
+</style>

+ 117 - 0
education_uni/subpkg/my/order/my_order.vue

@@ -0,0 +1,117 @@
+<template>
+	<view>
+		<view class="orderWrapper">
+		    <view class="myOrder" v-for="(item, index) in orders" :key="index">
+		        <view class="orderContent" @click="gotoDetail(item.orderId)">
+		            <view>
+		                <text>订单号</text>
+		                <text class="orderDetail">{{item.orderId}}</text>
+		            </view>
+		            <view class="centerContent">
+						<uni-row>
+							<uni-col :span="14">
+								<text>订单内容</text>
+								<text class="orderDetail">{{item.requireDetail}}</text>
+							</uni-col>
+							<uni-col :span="10">
+								<view>
+								    <text>对方</text>
+								    <text class="orderDetail">{{item.studentName}}</text>
+								</view>
+							</uni-col>
+						</uni-row>
+		            </view>
+		            <view>
+						<uni-row>
+							<uni-col :span="14">
+								<text>订单日期</text>
+								<text class="orderDetail">{{item.date}}</text>
+							</uni-col>
+							<uni-col :span="10">
+								<view>
+								    <text>订单状态</text>
+								    <text class="orderDetailStatus">{{item.status}}</text>
+								</view>
+							</uni-col>
+						</uni-row>
+		            </view>
+		        </view>
+		    </view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				orders: []
+			};
+		},
+		created() {
+			this.getOrdersByUid()
+		},
+		methods: {
+			async getOrdersByUid() {
+				const { data: result } = await uni.$http.get('/payment/order-info/list/uid')
+				this.orders = result.data.list
+				for (let i = 0; i < this.orders.length; i++) {
+					const arr = this.orders[i].datetime.split(" ")
+					this.orders[i].date = arr[0]
+				}
+			},
+			gotoDetail(id) {
+				uni.navigateTo({
+					url: '/subpkg/my/order/my_order_detail?orderId=' + id
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+/* 设置页面背景 */
+.orderWrapper{
+    height: 100%;
+    background-color: #E2F0D9;
+}
+.myOrder{
+    position: relative;
+    display: flex;
+    height: 160rpx;
+    background-color: #FFF2CC;
+    padding-left: 20rpx;
+    font-size: 28rpx;
+    margin: 20rpx;
+    border-radius: 20rpx;
+}
+
+.centerContent {
+	margin: 7px 0;
+}
+
+.orderContent{
+    height: 140rpx;
+	width: 100%;
+    padding: 10rpx 0;
+}
+
+/* 设置活动内容左边距并加粗 */
+.orderDetail,
+.orderDetailStatus{
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+/* 设置订单状态的字体颜色 */
+.orderDetailStatus{
+    color: red;
+}
+</style>

+ 339 - 0
education_uni/subpkg/my/order/my_order_detail.vue

@@ -0,0 +1,339 @@
+<template>
+	<view>
+		<view class="orderWrapper">
+		    <!-- 头部区域:订单号、头像 -->
+		    <view class="orderHead">
+		        <view class="orderHeadTitle">
+		            <view>
+		                <text>订单号</text>
+		                <text class="orderDetail">{{info.orderId}}</text>
+		            </view>
+		            <view>
+		                <text>对方</text>
+		                <text class="orderDetail">{{info.studentName}}学员</text>
+		            </view>
+		        </view>
+		    </view>
+		    <!-- 中部区域:订单详情 -->
+		    <view class="orderMid">
+		        <view>
+		            <text>对方ID</text>
+		            <text class="orderDetail">{{info.studentId}}</text>
+		        </view>
+		        <view>
+		            <text>需求号</text>
+		            <text class="courseNum" @click="toNeedDetail">{{info.requireId}}</text>
+		        </view>
+		        <view>
+		            <text>课程号</text>
+		            <text class="courseNum" @click="toCourseDetail">{{info.courseId}}</text>
+		        </view>
+		        <view>
+		            <text>需求金额</text>
+		            <text class="orderDetail">{{info.requireSalary/100}}</text>
+		        </view>
+		    </view>
+		    <view class="orderBottom">
+		        <view>
+		            <text>订单内容</text>
+		            <text class="orderDetail">{{info.requireDetail}}</text>
+		        </view>
+		        <view>
+		            <text>下单日期</text>
+		            <text class="orderDetail">{{info.datetime}}</text>
+		        </view>
+		        <view>
+		            <text>订单状态</text>
+		            <text class="orderPayStatus">{{info.status}}</text>
+		        </view>
+		    </view>
+			
+			<view v-if="countDown">
+				<uni-countdown :font-size="30" :showDay="false" :hour="0" :minute="minute" :second="second" color="#FFFFFF" background-color="red" />
+			</view>
+		    
+		    <view class="payWrapper">
+		        <view class="paidSucceed" v-if="!pay">
+					<button class="teachPayMent" :disabled="disabled" type="primary" style="border-radius: 40rpx;" @click="paymentButton">{{payment}}</button>
+		        </view>
+				<view class="pay" v-if="observed">
+					<view class="paidSucceed">
+					    <button class="payButton" @click="getPhone" type="primary">查看手机号</button>
+					    <button class="payButton" :disabled="buttonDisabled" @click="applyForRefund" type="warn">{{refundButton}}</button>
+					</view>
+				</view>
+		    </view>
+			<view v-if="showPhone">
+				<text>{{phone}}</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				time: 0,
+				observed: false,
+				buttonDisabled: false,
+				timer: '',
+				refundButton: '申请退款',
+				phone: '',
+				showPhone: false,
+				countDown: true,
+				payment: '教员支付',
+				disabled: false,
+				minute: 0,
+				second: 0,
+				info: {},
+				pay: false, //是否支付
+			};
+		},
+		onLoad(option) {
+			if (option.orderId !== undefined) {
+				this.getOne(option.orderId)
+				this.getCountDown(option.orderId)
+			}
+		},
+		methods: {
+			toNeedDetail() {
+				uni.navigateTo({
+					url: '/subpkg/student/require/student_require_all_detail?requireId=' + encodeURIComponent(this.info.requireId)
+				})
+			},
+			toCourseDetail() {
+				uni.navigateTo({
+					url: '/subpkg/teacher/course/teacher_course_all_detail?courseId=' + encodeURIComponent(this.info.courseId)
+				})
+			},
+			// 发送申请退款消息
+			async applyForRefund() {
+				this.buttonDisabled = true
+				const queryObj = {
+					studentId: this.info.studentId,
+					orderId: this.info.orderId
+				}
+				const {data: result} = await uni.$http.get('/education/mp-inner-msg/notify/refund', queryObj)
+				uni.$showMsg(result.message)
+			},
+			// 获取手机号
+			async getPhone() {
+				const {data: result} = await uni.$http.get('/ucenter/mini-program-openid-uid/getPhoneByUid', {uid: this.info.studentId})
+				this.phone = result.data.phone
+				this.showPhone = true
+			},
+			// 获取订单详情信息
+			async getOne(id) {
+				const {data: result} = await uni.$http.get('/payment/order-info/getOrderInfoByOrderId', {orderId: id})
+				this.info = result.data.one
+				// 判断支付状态
+				if (this.info.status !== '未支付') {
+					this.countDown = false
+					this.pay = true
+				} 
+				if (this.info.status === '未支付' && this.time == -2){
+					this.disabled = true
+					this.info.status = '已超时'
+				}
+				if (this.info.status === '支付成功') {
+					this.observed = true
+				}
+				if (this.info.isRefund === 1) {
+					this.buttonDisabled = true
+				}
+			},
+			// 倒计时
+			async getCountDown(id) {
+				const queryObj = {
+					orderId: id
+				}
+				const { data: result } = await uni.$http.get('/payment/order-info/getCountDown',queryObj)
+				this.time = result.data.time
+				if (this.time != -2) {
+					this.minute = this.time / 60
+					this.second = this.time % 60
+				}
+			},
+			// 支付
+			async paymentButton() {
+				const queryObj = {
+					inviteId: this.info.inviteId
+				}
+				const {data: result} = await uni.$http.get('/payment/wx-pay/jsapi', queryObj)
+				
+				// 微信官方调起支付
+				wx.requestPayment({
+					timeStamp: result.data.timeStamp,
+					nonceStr: result.data.nonceStr,
+					package: 'prepay_id=' + result.data.prepay_id,
+					signType: 'RSA',
+					paySign: result.data.paySign,
+					success: res => {
+						this.timer = setInterval(() => {
+							this.queryOrderStatus()
+						}, 1000)
+					},
+					fail: res => {
+					  wx.showToast({
+						title: '支付失败',
+						icon: 'none',
+						duration: 2000
+					  })
+					}
+				})
+			},
+			queryOrderStatus() {
+				// 验证本地订单状态,并推送消息
+				uni.request({
+				    url: `${uni.$http.baseUrl}/payment/order-info/queryOrderStatus?orderId=` + this.info.orderId, 
+				    success: (res) => {
+				        if (res.data.message === '支付成功') {
+							clearInterval(this.timer)
+							wx.showToast({
+								title: '支付成功',
+								icon: 'none',
+								duration: 2000
+							})
+							
+							this.info.status = '支付成功'
+							this.countDown = false
+							this.pay = true
+						}
+				    }
+				});
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+/* 设置全局边距 */
+.orderWrapper{
+    padding-left: 20rpx;
+    /* background-color: yellowgreen; */
+}
+
+/* 头部区域 */
+.orderHead{
+    display: flex;
+    position: relative;
+    height: 200rpx;
+    padding-top: 20rpx;
+}
+
+/* 头像 */
+.headImg{
+    width: 160rpx;
+    height: 160rpx;
+    border-radius: 30rpx;
+    position: absolute;
+    right: 30rpx;
+}
+
+.orderHeadTitle{
+    display: flex;
+    flex-direction: column;
+    height: 80px;
+    justify-content: space-around;
+}
+
+/* 设置内容样式 */
+.orderDetail,
+.courseNum,
+.orderPayStatus{
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+
+.courseNum{
+    color: #00B0F0;
+    text-decoration: underline;
+}
+
+/* 支付状态字体样式 */
+.orderPayStatus{
+    color: red;
+}
+
+/* 中部区域 */
+.orderMid{
+    height: 220rpx;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-around;
+}
+
+/* 底部区域 */
+.orderBottom{
+    margin-top: 40rpx;
+    height: 260rpx;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-around;
+}
+
+/* 支付倒计时 */
+.orderPay{
+    margin-top: 40rpx;
+    display: flex;
+    align-items: baseline;
+}
+/* 倒计时时间格式 */
+.orderPayTime{
+    padding-left: 20rpx;
+    font-weight: bold;
+    font-size: 40rpx;
+    color: red;    
+}
+
+/* 提醒信息 */
+.warning{
+    display: flex;
+    justify-content: center;    
+    margin-top: 60rpx;
+}
+/* 提醒信息详情 */
+.warningDetail{
+    width: 80%;
+    display: flex;
+    flex-direction: column;
+    font-size: 44rpx;
+    font-weight: bold;
+    color: red;
+}
+
+/* 支付及查看信息按钮居中排列 */
+.payWrapper{
+	margin-top: 40rpx;
+    display: flex;
+    justify-content: center;
+}
+
+.paidSucceed{
+    display: flex;
+    width: 100%;
+    justify-content: space-around;
+}
+
+.teachPayMent{
+	background-color: #35b882;
+}
+
+.payButton{
+	border-radius: 30rpx;
+}
+
+.pay{
+    /* display: flex; */
+    width: 100%;
+}
+</style>

+ 60 - 0
education_uni/subpkg/my/share/my_share.vue

@@ -0,0 +1,60 @@
+<template>
+	<view class="share-container">
+		<form >
+			<view class="share-begin">
+				<button open-type="share" form-type="submit" class="alias-submit" type="primary" >开始分享推荐</button>
+			</view>
+			<view>
+				<button class="alias-submit" type="primary" @click="queryResult" >查看分享结果</button>
+			</view>			
+		</form>
+	</view>
+</template>
+
+<script>
+	import { mapMutations, mapState } from 'vuex'
+	
+	export default {
+		computed: {
+			...mapState('m_user', ['userinfo'])
+		},
+		methods: {
+			/**
+			 * 分享处理函数,可以响应2类事件,1是button,2是右上角的menu中的Send to Chat
+			 * button用法:<button class="forshare" open-type="share">share</button>
+			 * menu用法:不用引入变量,当页面有这个函数时, Send to Chat会启用,否则灰色
+			 * path中的uid=txj123,txj123应该换为真实的用户号,当这个分享的卡片被打开时,小程序可以取到这个号
+			 */
+			onShareAppMessage: function () {
+				//console.log(this.userinfo)
+				return {
+				  title:'来自  ' +  this.userinfo.alias + '  的分享',
+				  path: '/pages/home/home?uid=' + this.userinfo.uid,
+				  imageUrl: '/static/share.jpg',   //自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径,支持PNG及JPG,不传入 imageUrl 则使用默认截图。显示图片长宽比是 5:4
+				}
+			},
+			queryResult:function(){
+				uni.navigateTo({
+					url: '/subpkg/my/share/my_share_result'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.share-container{
+		height: 100%;
+		padding: 0 20rpx;
+		// background-color: #fff;
+	}
+	.share-begin{
+		padding-top: 50rpx;
+		margin-top: -50rpx;
+	}
+	.alias-submit {
+		margin-top: 50rpx;
+		border-radius: 30rpx;
+		background-color: #35b882;
+	}
+</style>

+ 134 - 0
education_uni/subpkg/my/share/my_share_result.vue

@@ -0,0 +1,134 @@
+<template>
+	<view class="share-result-container">
+		<view class="studentWrapper">
+				<view class="studentList" >
+				    <view class="studentLeft">
+				          <text >打开人数</text>
+				    </view>
+				    <view class="studentRight">
+				           <text>{{shareCount}}</text>
+				    </view>
+				</view>
+		</view>
+		<view class="studentWrapper">
+				<view class="studentList" >
+				    <view class="studentLeft">
+				           <text >发布条数</text>
+				    </view>
+				    <view class="studentRight">
+				           <text>{{publishCount}}</text>
+				    </view>
+				</view>
+		</view>
+		<view class="studentWrapper">
+				<view class="studentList"  @click="toShareOrders" >
+				    <view class="studentLeft">
+				          <text >成交条数</text>
+				    </view>
+				    <view class="studentRight">		      
+				           <text>{{orderCount}}</text>
+				    </view>
+					<image class="rightIcon" src="@/static/rightwhite.png"></image>
+				</view>
+		</view>
+	</view>
+</template>
+
+<script>	
+	export default {
+		data() {
+			return {
+				shareCount: 0,
+				publishCount: 0,
+				orderCount: 0
+			};
+		},
+		created() {
+			this.getShareCount()
+			this.getPublishCount()
+			this.getOrderCount()
+		},
+		methods: {
+			// 成功注册的条数
+			async getShareCount() {
+				const { data: result } = await uni.$http.get('/ucenter/mini-program-openid-uid/getShareCount')
+				this.shareCount = result.data.result
+			},
+			// 推荐成功,发布的 课程和需求 条数
+			async getPublishCount() {
+				const { data: result } = await uni.$http.get('/ucenter/mini-program-openid-uid/getSharePublishCount')
+				this.publishCount = result.data.result
+			},
+			// 推荐成功 对应的 未退款的订单条数
+			async getOrderCount() {
+				const { data: result } = await uni.$http.get('/ucenter/mini-program-openid-uid/getShareOrderCount')
+				this.orderCount = result.data.result
+			},
+			toShareOrders(){
+				if (this.orderCount > 0) {
+					uni.navigateTo({
+						url: '/subpkg/my/share/my_share_result_order'
+					})
+				} else{
+					uni.$showMsg("无成交订单!")
+				}
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+	.share-result-container{
+		//height: 100%;
+		//background-color: #FFF2CC;
+		margin-top: 20rpx;
+	}
+.studentWrapper{
+    //height: 100%;
+    //background-color: #E2F0D9;
+    padding-left: 40rpx;
+	padding-right: 40rpx;
+}
+
+.studentList{
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+    padding: 40rpx;
+    border-radius: 40rpx;
+    //background-color: #FFF2CC;
+	// background-color: yellowgreen;
+    margin-bottom: 20rpx;
+	background-color: #35b882;
+	color: white;
+}
+
+/* 左侧部分 */
+.studentLeft{
+	margin-left: 100rpx;
+    font-weight: bold;
+    font-size: 30rpx;
+}
+
+/* 右侧部分定位 */
+.studentRight{
+	margin-right: 150rpx;
+	font-weight: bold;
+	font-size: 32rpx;
+    // color: #FF0000;
+   }
+   .rightIcon{
+	   position: absolute;
+	   left: 85%;
+       height: 30rpx;
+       width: 30rpx;
+   }
+</style>

+ 189 - 0
education_uni/subpkg/my/share/my_share_result_order.vue

@@ -0,0 +1,189 @@
+<template>
+	<view>
+		<view style="padding: 0px 30px;margin-top: 5px;">
+		<!-- 顶部对方已读和未读按钮 -->
+		<uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" styleType="button" activeColor="#6EB312"></uni-segmented-control>
+		<!-- 发出的邀请列表 -->
+		</view>
+		<view v-show="current === 0">
+			<view v-for="(Info,index) in OrderWithdraw" :key="index">
+				<view class="invitationWrapper" @click="gotoDetail(Info.orderId)">
+					<view class="invitationTitle">
+						<view>
+							<text>订单号</text>
+							<text class="invitatinDetail">{{Info.orderId}}</text>
+						</view>
+
+					</view>
+
+					<view class="invitationDateAndStatus">
+						<text>日期</text>
+						<text class="invitatinDetail">{{Info.datetime}}</text>
+						<view class="invitationTitle">
+							<text>状态</text>
+							<text class="invitatinStatus" >{{Info.recoStatus}}</text>
+						</view>
+					</view>
+
+					
+				</view>
+
+			</view>
+		</view>
+		<view v-show="current === 1">
+			<view v-for="(Info,index) in OrderNotWithdraw" :key="index">
+				<view class="invitationWrapper" @click="gotoDetail(Info.orderId)">
+					<view class="invitationTitle">
+						<view>
+							<text>订单号</text>
+							<text class="invitatinDetail">{{Info.orderId}}</text>
+						</view>
+
+					</view>
+
+					<view class="invitationDateAndStatus">
+						<text>日期</text>
+						<text class="invitatinDetail">{{Info.datetime}}</text>
+						<view class="invitationTitle">
+							<text>状态</text>
+							<text class="invitatinStatus" >{{Info.recoStatus}}</text>
+						</view>
+					</view>
+
+					
+				</view>
+
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex'
+	
+	export default {
+		data() {
+			return {
+				current: 1,
+				items: ['已转出', '未转出'],
+				OrderWithdraw: [],
+				OrderNotWithdraw: []
+
+			};
+		},
+		created() {
+			// this.readYes()
+			this.NotWithdraw()
+		},
+		methods: {
+			async Withdraw() {
+				const {
+					data: result
+				} = await uni.$http.get('/payment/order-info/list/recommendUidWithdraw')
+				this.OrderWithdraw = result.data.list
+				//console.log(this.OrderNotWithdraw)
+
+			},
+			async NotWithdraw() {
+				const {
+					data: result
+				} = await uni.$http.get('/payment/order-info/list/recommendUidNotWithdraw')
+				this.OrderNotWithdraw = result.data.list
+				//console.log(this.OrderNotWithdraw)
+
+			},
+			gotoDetail(id) {
+				uni.navigateTo({
+					url: '/subpkg/my_share/share_result/share_order_detail?orderId=' + id
+				})
+			},
+			onClickItem(e) {
+				if (this.current != e.currentIndex) {
+					this.current = e.currentIndex
+				}
+				if (this.current === 1) {
+					this.NotWithdraw()
+				} 
+				if (this.current === 0) {
+					this.Withdraw()
+				}
+			}
+
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+	page {
+		padding: 20rpx;
+		height: 100%;
+		//background-color: #E2F0D9;
+	}
+
+	/* 顶部对方已读和未读按钮 */
+	.read {
+		display: flex;
+		justify-content: space-around;
+	}
+
+	.readDetail {
+		padding: 10rpx 20rpx;
+		border-radius: 30rpx;
+		background-color: #FFF2CC;
+		font-weight: bold;
+	}
+
+	/* 列表样式 */
+	.invitationWrapper {
+		width: 93%;
+		padding: 20rpx;
+		margin-top: 20rpx;
+		border-radius: 20rpx;
+		background-color: #FFF2CC;
+		margin-left: 10rpx;
+	}
+
+	/* 邀请号和对方身份、邀请日期和对方状态 */
+	.invitationTitle,
+	.invitationDateAndStatus {
+		display: flex;
+		//align-items: center;
+		justify-content: space-between;
+
+		//position: relative;
+	}
+
+
+	/* 具体内容的样式 */
+	.invitatinDetail,
+	.invitatinStatus {
+		margin-left: 20rpx;
+		font-weight: bold;
+	}
+
+	.invitatinDetailOther {
+		margin-left: 20rpx;
+		font-weight: bold;
+		font-size: 26rpx;
+	}
+
+	.invitatinStatus {
+		color: red;
+	}
+
+	/* 邀请内容、邀请日期和对方状态 */
+	.invitationContent {
+		margin-top: 10rpx;
+	}
+</style>

+ 220 - 0
education_uni/subpkg/my/share/my_share_result_order_detail.vue

@@ -0,0 +1,220 @@
+<template>
+	<view>
+		<view class="orderWrapper">
+		    <!-- 头部区域:订单号、头像 -->
+		    <view class="orderHead">
+		        <view class="orderHeadTitle">
+		            <view>
+		                <text>订单号</text>
+		                <text class="orderDetail">{{info.orderId}}</text>
+		            </view>
+
+		        </view>
+		    </view>
+		    <!-- 中部区域:订单详情 -->
+		    <view class="orderMid">
+		        <view>
+		            <text>需求号</text>
+		            <text class="courseNum" >{{info.requireId}}</text>
+		        </view>
+		        <view>
+		            <text>课程号</text>
+		            <text class="courseNum" >{{info.courseId}}</text>
+		        </view>
+		    </view>
+		    <view class="orderBottom">
+
+		        <view>
+		            <text>下单日期</text>
+		            <text class="orderDetail">{{info.datetime}}</text>
+		        </view>
+				<view>
+				    <text>返现金额</text>
+				    <text class="orderDetail">{{info.recoCommission/100}}</text>
+				</view>
+				<view>
+				    <text>客户状态</text>
+				    <text class="orderPayStatus">{{info.status}}</text>
+				</view>
+		        <view>
+		            <text>提现状态</text>
+		            <text class="orderPayStatus">{{info.recoStatus}}</text>
+		        </view>
+		    </view>
+			
+
+		    
+		    <view class="payWrapper">
+				<view class="pay" v-if="showWithdrawBtn">
+					<view class="paidSucceed">
+					    <button class="payButton" @click="startWithdraw" type="primary">申请转出</button>
+					</view>
+				</view>
+		    </view>
+
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				info: {},
+				showWithdrawBtn: false,//是否 显示 申请提现 btn
+			};
+		},
+		onLoad(option) {
+			if (option.orderId !== undefined) {
+				this.getOne(option.orderId)
+			}
+		},
+		methods: {
+			// 获取订单信息
+			async getOne(id) {
+				//console.log(id)
+				const queryObj = {
+					orderId: id
+				}
+				const {data: result} = await uni.$http.get('/payment/order-info/getOrderInfoByOrderId', {orderId: id})
+				this.info = result.data.one
+				//console.log(this.info)
+				// 判断支付状态
+				if (this.info.status === '支付成功' && this.info.recoStatus === '未申请') {
+					   this.showWithdrawBtn = true
+				}
+			},
+			startWithdraw(){
+				uni.$showMsg("正在申请 “商户向客户零钱包转帐的功能”,如急需转出,请联系在线客服处理,谢谢!",5000)
+			}
+
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFFFFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+/* 设置全局边距 */
+.orderWrapper{
+    padding-left: 20rpx;
+    /* background-color: yellowgreen; */
+}
+
+/* 头部区域 */
+.orderHead{
+    display: flex;
+    position: relative;
+    height: 200rpx;
+    padding-top: 20rpx;
+}
+
+/* 头像 */
+.headImg{
+    width: 160rpx;
+    height: 160rpx;
+    border-radius: 30rpx;
+    position: absolute;
+    right: 30rpx;
+}
+
+.orderHeadTitle{
+    display: flex;
+    flex-direction: column;
+    height: 80px;
+    justify-content: space-around;
+}
+
+/* 设置内容样式 */
+.orderDetail,
+.courseNum,
+.orderPayStatus{
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+
+.courseNum{
+    color: #00B0F0;
+    //text-decoration: underline;
+}
+
+/* 支付状态字体样式 */
+.orderPayStatus{
+    color: red;
+}
+
+/* 中部区域 */
+.orderMid{
+   // height: 220rpx;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-around;
+}
+
+/* 底部区域 */
+.orderBottom{
+    margin-top: 40rpx;
+    height: 260rpx;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-around;
+}
+
+/* 支付倒计时 */
+.orderPay{
+    margin-top: 40rpx;
+    display: flex;
+    align-items: baseline;
+}
+/* 倒计时时间格式 */
+.orderPayTime{
+    padding-left: 20rpx;
+    font-weight: bold;
+    font-size: 40rpx;
+    color: red;    
+}
+
+/* 提醒信息 */
+.warning{
+    display: flex;
+    justify-content: center;    
+    margin-top: 60rpx;
+}
+/* 提醒信息详情 */
+.warningDetail{
+    width: 80%;
+    display: flex;
+    flex-direction: column;
+    font-size: 44rpx;
+    font-weight: bold;
+    color: red;
+}
+
+/* 支付及查看信息按钮居中排列 */
+.payWrapper{
+	margin-top: 160rpx;
+    display: flex;
+    justify-content: center;
+}
+
+.paidSucceed{
+    display: flex;
+    width: 100%;
+    justify-content: space-around;
+}
+
+.payButton{
+	border-radius: 30rpx;
+}
+
+.pay{
+    /* display: flex; */
+    width: 100%;
+}
+</style>

+ 165 - 0
education_uni/subpkg/my/suggestion/my_suggestion.vue

@@ -0,0 +1,165 @@
+<template>
+	<view>
+	    <!-- 建议列表 -->
+	    <view class="suggestContainer">
+	        <view class="suggest" @click="toSuggestDetail(item)" v-for="(item, index) in suggestion" :key="index">
+	            <view class="suggestion">
+	                <view class="suggestHead">
+	                    <view>标题</view>
+	                    <view class="suggestTitle">{{item.adviseTitle}}</view>
+	                </view>
+	                <view class="suggestBody">
+	                    <view>内容摘要</view>
+	                    <view class="suggestContent">{{item.adviseDetail}}</view>
+	                </view>
+	            </view>
+	            <view>
+	                <view class="dispose">{{item.status}}</view>
+	            </view>
+			</view>
+	    </view>
+	    <!-- 开始写建议按钮 -->
+	    <view class="toWriteSuggestion">
+	        <view class="writeSuggestion" @click="toWriteSuggestion()">
+	            <text>开始写建议</text>
+	        </view>
+	    </view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				suggestion: []				
+			};
+		},
+		onShow(){
+			this.init();
+		},
+		methods:{
+			async init(){
+				const { data: result } =await uni.$http.get('/education/my-suggestion/findPersonAdvise')
+				this.suggestion = result.data.data;
+			},
+			// 点击建议列表,跳转到对应的建议详情页
+			toSuggestDetail(item){
+				let suggestion = JSON.stringify(item)
+				uni.navigateTo({
+					url: '/subpkg/my/suggestion/my_suggestion_detail?item=' + encodeURIComponent(suggestion) 
+				})
+			},
+			// 跳转到写建议页面
+			toWriteSuggestion(){
+			   uni.navigateTo({
+			   	url: '/subpkg/my/suggestion/my_suggestion_write'
+			   })
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+	/* 页面背景 */
+	// page{
+	//     /* height: 100%; */
+	//     /* height: auto !important; */
+	//     background-color: #E2F0D9;
+	// }
+	
+	/* 建议列表区 */
+	.suggestContainer{
+	    height: 100%;
+	    padding-bottom: 120rpx;
+	}
+	
+	/* 单条建议的背景 */
+	.suggest{
+	    display: flex;
+	    padding: 20rpx;
+	    margin: 20rpx 10rpx;
+	    height: 140rpx;
+	    border-radius: 30rpx;
+	    background-color: #FFF2CC;
+	}
+	
+	/* 单条建议左侧标题和内容摘要 */
+	.suggestion{
+	    width: 75%;
+	}
+	
+	/* 标题和内容摘要布局 */
+	.suggestHead,
+	.suggestBody{
+	    display: flex;
+	}
+	
+	/* 摘要 */
+	.suggestBody{
+	    margin-top: 10rpx;
+	}
+	
+	/* 标题详情和内容详情左边距 */
+	.suggestTitle,
+	.suggestContent{
+	    margin-left: 20rpx;
+	}
+	
+	/* 标题内容详情 */
+	.suggestTitle{
+	    width: 65%;
+	    white-space: nowrap;
+	    overflow: hidden;
+	    text-overflow: ellipsis;
+	}
+	
+	/* 内容摘要详情 */
+	.suggestContent{
+	    width: 65%;
+	    overflow: hidden;
+	    text-overflow: ellipsis;
+	    display: -webkit-box;
+	    -webkit-box-orient: vertical;
+	    -webkit-line-clamp: 2;
+	}
+	
+	/* 处理状态 */
+	.dispose{
+	    font-weight: bold;
+	    color: red;
+	    margin-left: 30rpx;
+	}
+	
+	/* 写建议按钮 */
+	.toWriteSuggestion{
+	    display: flex;
+	    position: relative;
+	    justify-content: center;
+	}
+	.writeSuggestion{
+	    text-align: center;    
+	    position: fixed;
+	    bottom: 0rpx;
+	    width: 100%;
+	    height: 120rpx;
+	    line-height: 120rpx;
+	    // background-color: #E2F0D9;
+		
+	}
+	.writeSuggestion text{
+	    // background-color: #8FAADC;
+		background-color: #35b882;
+	    font-size: 36rpx;
+	    color: white;
+	    border-radius: 30rpx;
+	    padding: 10rpx 20rpx;
+	}
+</style>

+ 143 - 0
education_uni/subpkg/my/suggestion/my_suggestion_detail.vue

@@ -0,0 +1,143 @@
+<template>
+	<view class="wrapper">
+		<!-- 建议号和ID -->
+		<view>
+		    <view>
+		        <text>建议号:</text>
+		        <text class="benginTwo">{{suggestion.id}}</text>
+		    </view>
+		    <view>
+		        <text>ID:</text>
+		        <text class="benginTwo">{{suggestion.fromUid}}</text>
+		    </view>
+		</view>
+		<!-- 处理人ID和处理人昵称 -->
+		<view>
+		    <view>
+		        <text>处理人ID:</text>
+		        <text>{{suggestion.processorUid}}</text>
+		    </view>
+		    <view>
+		        <text>处理人昵称:</text>
+		        <text>{{suggestion.name}}</text>
+		    </view>
+		</view>
+		<!-- 建议标题和日期 -->
+		<view class="suggestTitleWrapper">
+		    <text class="suggestTtile">建议标题</text>
+		    <text class="suggestTime">{{suggestion.adviseTitle}}</text>
+		</view>
+		<!-- 建议内容 -->
+		<view class="suggestContentWrapper">
+		    <text>建议内容:</text>
+		    <text>{{suggestion.adviseDetail}}</text>
+		</view>
+		<!-- 处理结果 -->
+		<view class="handleResult">
+		    <text>处理结果描述:</text>
+		    <text>{{suggestion.result}}</text>
+		</view>
+		<!-- 日期 -->
+		<view class="handleResult">
+		    <text>结案日期时间:</text>
+		    <text class="handleTime">{{suggestion.closetime}}</text>
+		</view>
+		<!-- 处理状态 -->
+		<view class="handleStatus">
+		    <text>{{suggestion.status}}</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				suggestion: {}
+			}
+		},
+		onLoad(opt){
+			this.suggestion = JSON.parse(decodeURIComponent(opt.item));
+			if(this.suggestion.processorUid==null){
+				this.suggestion.processorUid = " ";
+			}
+			if(this.suggestion.name==null){
+				this.suggestion.name = " ";
+			}
+			if(this.suggestion.result==null){
+				this.suggestion.result = " ";
+			}
+			if(this.suggestion.closetime==null){
+				this.suggestion.closetime = " ";
+			}
+			
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss">
+/* 设置背景 */
+// page{
+// 	height: 100%;
+// 	background-color: #FFF2CC;
+// }
+
+.wrapper {
+	padding: 20rpx;
+}
+
+.benginTwo {
+	margin-left: 10rpx;
+}
+
+/* 建议标题和时间 */
+.suggestTitleWrapper{
+    margin-top: 50rpx;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+/* 单独设置标题 */
+.suggestTtile{
+    font-weight: bold;
+}
+/* 单独设置建议时间 */
+.suggestTime{
+    font-size: 26rpx;
+    color: #A6A6A6;
+}
+
+/* 建议内容 */
+.suggestContentWrapper{
+    margin-top: 40rpx;
+    display: flex;
+    flex-direction: column;
+    height: 600rpx;
+}
+/* 处理结果 */
+.handleResult{
+    margin-top: 30rpx;
+}
+/* 处理时间 */
+.handleTime{
+    font-weight: bold;
+}
+/* 处理状态 */
+.handleStatus{
+    margin: 60rpx 0;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    font-weight: bold;
+    color: red;
+}
+
+</style>

+ 169 - 0
education_uni/subpkg/my/suggestion/my_suggestion_write.vue

@@ -0,0 +1,169 @@
+<template>
+	<view>
+		<view>
+		    <!-- 建议标题 -->
+		    <view class="suggestWrapper">
+		        <text class="suggestTitle">建议标题</text>
+		        <textarea v-model="adviseTitle" name="建议标题" cols="30" rows="10" maxlength="50" placeholder="不超过50字" class="titleInput"></textarea>
+		    </view>
+		    <!-- 建议内容 -->
+		    <view class="suggestWrapper">
+		        <text class="suggestTitle">建议内容</text>
+		        <textarea v-model="adviseDetail" name="建议内容" cols="30" rows="10" maxlength="512" placeholder="不超过512字" class="contentInput"></textarea>
+		    </view>
+		</view>
+		<!-- 取消和提交按钮 -->
+		<view class="suggestBtn">
+		    <button class="cancelBtn" @click="toCancel">取消</button>
+		    <button class="confirmBtn" :disabled="disableButton" @click="toConfirm">提交</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				adviseTitle: "",
+				adviseDetail: "",
+				disableButton: false
+			}
+		},
+		methods: {
+			toCancel(){
+				this.adviseTitle = "";
+				this.adviseDetail = "";
+				
+				uni.navigateBack({
+				     delta: 1,
+				})
+			},
+			toConfirm(){
+				this.disableButton = true
+				let suggestTitle = this.adviseTitle;
+				let suggestDetail = this.adviseDetail;
+				var head = '^[ ]+$';
+				var re = new RegExp(head);
+				if (!suggestTitle) {
+						uni.showModal({
+				           title: '建议标题未写',
+				           content: '请补充标题后再重新提交'
+				    })
+				} else if (re.test(suggestTitle)) {
+					 uni.showModal({
+						 title: '标题不能全为空格',
+						 content: '建议标题不能全部为空格,请修改建议标题后再提交'
+					 })
+				} else if (!suggestDetail) {
+					 uni.showModal({
+						 title: '建议内容未写',
+						 content: '建议内容不能为空,请补充建议内容后再提交'
+					 })
+				} 
+				else if (re.test(suggestDetail)) {
+					 uni.showModal({
+						 title: '建议内容不能全部为空格',
+						 content: '建议内容不能全部为空格,请修改建议内容后再提交'
+					 })
+				 } else{
+					uni.request({
+						url: `${uni.$http.baseUrl}/education/my-suggestion/writeAdvise`,
+						data: {
+								"adviseTitle": this.adviseTitle,
+								"adviseDetail": this.adviseDetail,
+							},
+						header: {
+							token: uni.getStorageSync('token')
+						},
+						method: 'POST',
+						success: res => {
+							uni.$showMsg('建议成功')
+							setTimeout(() => {
+								uni.navigateBack()
+								this.disableButton = false
+							}, 1000)
+							
+							
+						}
+					})
+					
+				}
+			
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #D4F5E9;
+	}
+</style>
+
+<style lang="scss" scoped>
+/* pages/writeSuggestion/writeSuggestion.wxss */
+
+/* 设置页面背景 */
+// page{
+//     background-color: #E2F0D9;
+//     height: 100%;
+// }
+
+.suggestWrapper{
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    padding: 20rpx;
+}
+/* 标题 */
+.suggestTitle{
+    text-align: center;
+    padding-bottom: 20rpx;
+    font-weight: bold;
+}
+/* 输入的建议标题和内容公共样式 */
+.titleInput,
+.contentInput{
+    width: 93%;
+    padding: 10rpx;
+    /* border: 1rpx solid gray; */
+    border-radius: 20rpx;
+    background-color: #fff;
+}
+/* 建议标题输入框的高度 */
+.titleInput{
+    height: 150rpx;
+}
+
+/* 建议内容输入框的高度 */
+.contentInput{
+    height: 650rpx;
+}
+
+/* 下方按钮 */
+.suggestBtn{
+    display: flex;
+    margin-top: 40rpx;
+    justify-content: space-around;
+}
+
+.confirmBtn,
+.cancelBtn{
+    font-size: 42rpx;
+	height: 85rpx;
+    width: 160rpx;
+	line-height: 85rpx;
+    border-radius: 40rpx;
+    text-align: center;
+    // background-color: #8FAADC;
+    color: white;
+}
+.confirmBtn{
+	background-color: #35b882;
+}
+.cancelBtn{
+	background-color: #3ed598;
+}
+</style>

+ 127 - 0
education_uni/subpkg/my/user/my_user_detail.vue

@@ -0,0 +1,127 @@
+<template>
+	<view class="modifyWrapper">
+		<form>
+			<view class="uni-forms-item">
+				<button class="avatar-wrapper" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
+					<image class="avatar" :src="userinfo.avatar"></image>
+				</button>
+			</view>
+			<view class="uni-forms-item">
+				<input type="text" class="alias-input" maxlength="6" v-model="userinfo.alias" />
+			</view>
+			<view class="uni-forms-item">
+				<button form-type="submit" class="alias-submit" type="primary" @click="formSubmit">确认修改</button>
+			</view>
+			<view class="uni-forms-item">
+				<button class="alias-submit" type="primary" @click="forExit">退出登录</button>
+			</view>
+		</form>
+	</view>
+</template>
+
+<script>
+	import {
+		mapMutations,
+		mapState
+	} from 'vuex'
+
+	export default {
+		computed: {
+			...mapState('m_user', ['userinfo'])
+		},
+		methods: {
+			...mapMutations('m_user', ['updateUserInfo', 'updateToken']),
+			// 选择头像
+			onChooseAvatar(e) {
+				const {
+					avatarUrl
+				} = e.detail
+				this.userinfo.avatar = avatarUrl
+			},
+			formSubmit() {
+				// 上传头像
+				wx.uploadFile({
+					url: uni.$http.baseUrl + '/file/uploading',
+					filePath: this.userinfo.avatar,
+					name: 'file',
+					header: {
+						'token': uni.getStorageSync('token')
+					},
+					success: res => {
+						const result = JSON.parse(res.data)
+						this.userinfo.avatar = result.data.url
+						// 表单提交
+						this.sendFormData()
+					},
+					fail: res => {
+						if (res.errMsg === 'uploadFile:fail createUploadTask:fail file not found') {
+							// 表单提交
+							this.sendFormData()
+						} else {
+							uni.$showMsg('修改头像失败,请重新选择')
+						}
+					}
+				})
+			},
+			// 表单提交
+			sendFormData() {
+				wx.request({
+					url: uni.$http.baseUrl + '/ucenter/mini-program-openid-uid/wxAlias',
+					method: 'GET',
+					data: {
+						alias: this.userinfo.alias,
+						avatar: this.userinfo.avatar
+					},
+					header: {
+						'token': uni.getStorageSync('token') // 默认值
+					},
+					success: res1 => {
+						uni.$showMsg('修改成功!', 3000)
+						// 更新成功
+						// 将数据更新到vuex中
+						this.updateUserInfo(this.userinfo)
+					}
+				})
+			},
+			forExit() {
+				this.updateToken("")
+				// 跳转个人信息页面
+				uni.switchTab({
+					url: '/pages/my/my'
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		padding: 0 20rpx;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+	.modifyWrapper{
+		width: 95%;
+		height: 100%;
+	}
+	.alias-input {
+		height: 100rpx;
+		font-size: 40rpx;
+		// border: 1px solid #aaa;
+		border-radius: 30rpx;
+		padding-left: 10rpx;
+		margin-top: 20rpx;
+		background-color: white;
+	}
+
+	.alias-submit {
+		margin-top: 50rpx;
+		width: 300rpx;
+		border-radius: 50rpx;
+		background-color: #35b882;
+	}
+</style>

+ 276 - 0
education_uni/subpkg/student/order/student_order_detail.vue

@@ -0,0 +1,276 @@
+<template>
+	<view>
+		<view class="orderWrapper">
+		    <!-- 头部区域:订单号、头像 -->
+		    <view class="orderHead">
+		        <view class="orderHeadTitle">
+		            <view>
+		                <text>订单号</text>
+		                <text class="orderDetail">{{info.orderId}}</text>
+		            </view>
+		            <view>
+		                <text>对方</text>
+		                <text class="orderDetail">{{info.teacherName}}教员</text>
+		            </view>
+		        </view>
+		    </view>
+		    <!-- 中部区域:订单详情 -->
+		    <view class="orderMid">
+		        <view>
+		            <text>对方ID</text>
+		            <text class="orderDetail">{{info.teacherId}}</text>
+		        </view>
+		        <view>
+		            <text>需求号</text>
+		            <text class="courseNum" @click="toNeedDetail">{{info.requireId}}</text>
+		        </view>
+		        <view>
+		            <text>课程号</text>
+		            <text class="courseNum" @click="toCourseDetail">{{info.courseId}}</text>
+		        </view>
+		        <view>
+		            <text>需求金额</text>
+		            <text class="orderDetail">{{info.requireSalary/100}}</text>
+		        </view>
+		    </view>
+		    <view class="orderBottom">
+		        <view>
+		            <text>订单内容</text>
+		            <text class="orderDetail">{{info.requireDetail}}</text>
+		        </view>
+		        <view>
+		            <text>支付日期</text>
+		            <text class="orderDetail">{{info.datetime}}</text>
+		        </view>
+		        <view>
+		            <text>订单状态</text>
+		            <text class="orderPayStatus">{{info.status}}</text>
+		        </view>
+		    </view>
+		    
+		    <view class="payWrapper">
+				<view class="pay" v-if="!payment">
+					<view class="paidSucceed">
+					    <button class="payYesButton" @click="getPhone" type="primary">查看手机号</button>
+					    <button class="payNoButton" :disabled="buttonDisabled" @click="applyForRefund" type="warn">{{refundButton}}</button>
+					</view>
+				</view>
+		    </view>
+			<view v-if="showPhone">
+				<text>{{phone}}</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				buttonDisabled: true,
+				timer: '',
+				refundButton: '同意退款',
+				phone: '',
+				showPhone: false,
+				disabled: false,
+				minute: 0,
+				second: 0,
+				info: {},
+				payment: false, //是否退款
+			};
+		},
+		onLoad(option) {
+			if (option.orderId !== undefined) {
+				this.getOne(decodeURIComponent(option.orderId))
+			}
+		},
+		methods: {
+			toNeedDetail() {
+				uni.navigateTo({
+					url: '/subpkg/student/require/student_require_all_detail?requireId=' + encodeURIComponent(this.info.requireId)
+				})
+			},
+			toCourseDetail() {
+				uni.navigateTo({
+					url: '/subpkg/teacher/course/teacher_course_all_detail?courseId=' + encodeURIComponent(this.info.courseId)
+				})
+			},
+			// 申请退款
+			async applyForRefund() {
+				const queryObj = {
+					orderNo: this.info.orderId,
+					reason: '五天内试课不成功'
+				}
+				const {data: result} = await uni.$http.get('/payment/wx-pay/refunds', queryObj)
+				if (result.message === '成功') {
+					this.refundButton = '退款处理中'
+					this.timer = setInterval(() => {
+						this.queryIsRefundOrder()
+					}, 1000)
+				} 
+				
+			},
+			// 获取手机号
+			async getPhone() {
+				const {data: result} = await uni.$http.get('/ucenter/mini-program-openid-uid/getPhoneByUid', {uid: this.info.teacherId})
+				this.phone = result.data.phone
+				this.showPhone = true
+			},
+			// 获取订单信息
+			async getOne(id) {
+				const queryObj = {
+					orderId: id
+				}
+				const {data: result} = await uni.$http.get('/payment/order-info/getOrderInfoByOrderId', queryObj)
+				this.info = result.data.one
+				if (this.info.isRefund === 1) this.buttonDisabled = false
+				if (this.info.status === '已退款') this.payment = true
+			},
+			async queryIsRefundOrder() {
+				const {data: result} = await uni.$http.get('/payment/order-info/queryIsRefundOrder', {orderId: this.info.orderId})
+				if('已退款' === result.message) {
+					this.showPhone = false
+					clearInterval(this.timer)
+					this.payment = true
+					this.info.status = '已退款'
+					uni.$showMsg('退款成功')
+				}
+			}
+			
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+/* 设置全局边距 */
+.orderWrapper{
+    padding-left: 20rpx;
+    /* background-color: yellowgreen; */
+}
+
+/* 头部区域 */
+.orderHead{
+    display: flex;
+    position: relative;
+    height: 200rpx;
+    padding-top: 20rpx;
+}
+
+/* 头像 */
+.headImg{
+    width: 160rpx;
+    height: 160rpx;
+    border-radius: 30rpx;
+    position: absolute;
+    right: 30rpx;
+}
+
+.orderHeadTitle{
+    display: flex;
+    flex-direction: column;
+    height: 80px;
+    justify-content: space-around;
+}
+
+/* 设置内容样式 */
+.orderDetail,
+.courseNum,
+.orderPayStatus{
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+
+.courseNum{
+    color: #00B0F0;
+    text-decoration: underline;
+}
+
+/* 支付状态字体样式 */
+.orderPayStatus{
+    color: red;
+}
+
+/* 中部区域 */
+.orderMid{
+    height: 220rpx;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-around;
+}
+
+/* 底部区域 */
+.orderBottom{
+    margin-top: 40rpx;
+    height: 260rpx;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-around;
+}
+
+/* 支付倒计时 */
+.orderPay{
+    margin-top: 40rpx;
+    display: flex;
+    align-items: baseline;
+}
+/* 倒计时时间格式 */
+.orderPayTime{
+    padding-left: 20rpx;
+    font-weight: bold;
+    font-size: 40rpx;
+    color: red;    
+}
+
+/* 提醒信息 */
+.warning{
+    display: flex;
+    justify-content: center;    
+    margin-top: 60rpx;
+}
+/* 提醒信息详情 */
+.warningDetail{
+    width: 80%;
+    display: flex;
+    flex-direction: column;
+    font-size: 44rpx;
+    font-weight: bold;
+    color: red;
+}
+
+/* 支付及查看信息按钮居中排列 */
+.payWrapper{
+    display: flex;
+    justify-content: center;
+}
+
+.payYesButton,
+.payNoButton{
+	border-radius: 50rpx;
+	color: white;
+}
+.payYesButton{
+	background-color: #35b882;
+}
+.payNoButton{
+	background-color: #3ed598;
+}
+
+.paidSucceed{
+    display: flex;
+    width: 100%;
+    justify-content: space-around;
+}
+
+.pay{
+    /* display: flex; */
+    width: 100%;
+}
+</style>

+ 647 - 0
education_uni/subpkg/student/require/student_require_add.vue

@@ -0,0 +1,647 @@
+<template>
+	<view class="stu-require-container" style="background-color: #f0f0f0;">
+		<uni-forms ref="baseForm" :model="baseFormData" labelWidth="75px" :rules="rules" validateTrigger="bind">
+			<uni-forms-item label="姓名" name="name" required>
+				<uni-easyinput v-model="baseFormData.name" placeholder="请输入姓名" maxlength="4" trim="both" />
+			</uni-forms-item>
+			<uni-forms-item label="手机号" name="phone" required>
+				<button class="getPhone" open-type="getPhoneNumber" type="primary" size="mini"
+					@getphonenumber="getPhoneNumber">获取手机号</button>
+			</uni-forms-item>
+			<uni-forms-item label="微信号" name="wxid" required>
+				<uni-easyinput v-model="baseFormData.wxid" placeholder="微信号(不便接听电话时微信沟通)" maxlength="25"
+					trim="both" />
+			</uni-forms-item>
+			<uni-forms-item label="地址:" name="locationStr" required>
+				<uni-easyinput type="text" v-model="baseFormData.locationStr" @focus="getLocation" maxlength="250" trim="both" />
+			</uni-forms-item>
+			<uni-forms-item label="选择课程" required>
+				<uni-data-picker placeholder="请选择课程" popup-title="课程大纲-具体课程" v-model="baseFormData.subjectSmall" :clearIcon="false"
+					:localdata="courseTree" />
+			</uni-forms-item>
+			<uni-forms-item label="辅导方式" required>
+				<uni-data-checkbox v-model="baseFormData.mode" :localdata="modes" />
+			</uni-forms-item>
+			<uni-forms-item label="学员性别" required>
+				<uni-data-checkbox v-model="baseFormData.sex" :localdata="sexs" />
+			</uni-forms-item>
+			<uni-forms-item label="课时费" name="salary" required :errorMessage="errorPrice">
+				<uni-easyinput v-model="baseFormData.salary" type="number" placeholder="请输入课时金额" />
+			</uni-forms-item>
+			<uni-forms-item label="上课时间" required>
+			</uni-forms-item>
+			<view class="tr-container">
+				<view class="tr_1">
+					<text class="th_0" decode="true">&ensp;&ensp;&ensp;&ensp;</text>
+					<text class="th_1">周一</text>
+					<text class="th_1">周二</text>
+					<text class="th_1">周三</text>
+					<text class="th_1">周四</text>
+					<text class="th_1">周五</text>
+					<text class="th_1">周六</text>
+					<text class="th_1">周日</text>
+				</view>
+				<view class="tr_2">
+					<checkbox-group @change="chechboxChangeAM">
+						<view class="th2_0">上午</view>
+						<label v-for="item in timeAM" :key="item.value">
+							<checkbox class="th2_1" :value="item.value" :checked="item.checked"></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+				<view class="tr_2">
+					<checkbox-group @change="chechboxChangePM">
+						<view class="th2_0">下午</view>
+						<label v-for="item in timePM" :key="item.value">
+						<checkbox class="th2_1" :value="item.value" :checked="item.checked"></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+				<view class="tr_2">
+					<checkbox-group @change="chechboxChangeEvening">
+						<view class="th2_0">晚上</view>
+						<label v-for="item in timeEvening" :key="item.value">
+						<checkbox class="th2_1" :value="item.value" :checked="item.checked"></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+			</view>
+			<uni-forms-item label="期望目标" name="goal">
+				<uni-easyinput type="textarea" v-model="baseFormData.goal" maxlength="100" trim="both" />
+			</uni-forms-item>
+			<uni-forms-item label="教员身份" required>
+				<uni-data-checkbox v-model="baseFormData.teacherType" :localdata="identifies" />
+			</uni-forms-item>
+			<uni-forms-item label="教员学历" required>
+				<uni-data-select v-model="baseFormData.teacherEdu" :localdata="educations" />
+			</uni-forms-item>
+			<uni-forms-item label="教员性别" required>
+				<uni-data-checkbox v-model="baseFormData.teacherGender" :localdata="sexsTeacher" />
+			</uni-forms-item>
+			<uni-forms-item label="教员照片" required>
+				<uni-data-checkbox v-model="baseFormData.teacherProfilePhoto" :localdata="hasPhotoes" />
+			</uni-forms-item>
+			<uni-forms-item label="对教员要求" name="teacherDemanded">
+				<uni-easyinput type="textarea" v-model="baseFormData.teacherDemanded" maxlength="100" trim="both" />
+			</uni-forms-item>
+		</uni-forms>
+		<view class="submitBtnWrapper">
+			<button class="submitBtn" type="primary" @click="submit">提交需求</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { mapState } from 'vuex'
+	
+	export default {
+		computed: {
+			...mapState('m_user', ['userinfo'])
+		},
+		data() {
+			return {
+				loading: false,
+				errorPrice: '',
+				courseAM: [],
+				coursePM: [],
+				courseEV: [],
+				courseWeekday: [],
+				// 表单数据
+				baseFormData: {
+					name: '',
+					phone: '',
+					wxid: '',
+					subjectSmall: '1-1',
+					mode: '教员上门',
+					sex: '男',
+					salary: 0,
+					courseWeekday: [],
+					goal: '',
+					teacherType: '专职教员',
+					teacherEdu: '',
+					teacherGender: '男',
+					teacherProfilePhoto: '有',
+					teacherDemanded: '',
+					locationStr: '',
+					locationAl: ''
+				},
+				coursePrice: [],
+				// 选择课程
+				courseTree: [{
+						text: '一年级',
+						value: '1-0',
+						children: [{
+								text: '1.1班',
+								value: '1-1'
+							}
+						]
+					}
+				],
+				// 单选辅导方式数据源
+				modes: [{
+					text: '教员上门',
+					value: '教员上门'
+				}, {
+					text: '学员上门',
+					value: '学员上门'
+				}, {
+					text: '线上辅导',
+					value: '线上辅导'
+				}],
+				// 单选性别数据源
+				sexs: [{
+					text: '男',
+					value: '男'
+				}, {
+					text: '女',
+					value: '女'
+				}],
+				// 单选老师身份
+				identifies: [{
+					text: '专职教员',
+					value: '专职教员'
+				}, {
+					text: '学生教员',
+					value: '学生教员'
+				}],
+				educations: [{
+					value: '专科在读',
+					text: '专科在读及以上'
+				}, {
+					value: '专科毕业',
+					text: '专科毕业及以上'
+				}, {
+					value: '本科在读',
+					text: '本科在读及以上'
+				}, {
+					value: '本科毕业',
+					text: '本科毕业及以上'
+				}, {
+					value: '硕士在读',
+					text: '硕士在读及以上'
+				}, {
+					value: '硕士毕业',
+					text: '硕士毕业及以上'
+				}, {
+					value: '博士在读',
+					text: '博士在读及以上'
+				}, {
+					value: '博士毕业',
+					text: '博士毕业及以上'
+				}, {
+					value: '不限',
+					text: '不限'
+				}],
+				// 单选老师性别
+				sexsTeacher: [{
+					text: '男',
+					value: '男'
+				}, {
+					text: '女',
+					value: '女'
+				}],
+				// 单选老师有无照片
+				hasPhotoes: [{
+					text: '有',
+					value: '有'
+				}, {
+					text: '无',
+					value: '无'
+				}],
+				// 上课时间
+				// 上午
+				timeAM: [{
+						value: 'A1',
+						name: '1',
+						checked: false
+						
+					},
+					{
+						name: '2',
+						value: 'A2',
+						checked: false
+					},
+					{
+						name: '3',
+						value: 'A3',
+						checked: false
+					},
+					{
+						name: '4',
+						value: 'A4',
+						checked: false
+					},
+					{
+						name: '5',
+						value: 'A5',
+						checked: false
+					},
+					{
+						name: '6',
+						value: 'A6',
+						checked: false
+					},
+					{
+						name: '7',
+						value: 'A7',
+						checked: false
+					}
+				],
+				// 下午
+				timePM: [{
+						value: 'P1',
+						name: '1',
+						checked: false
+					},
+					{
+						name: '2',
+						value: 'P2',
+						checked: false
+					},
+					{
+						name: '3',
+						value: 'P3',
+						checked: false
+					},
+					{
+						name: '4',
+						value: 'P4',
+						checked: false
+					},
+					{
+						name: '5',
+						value: 'P5',
+						checked: false
+					},
+					{
+						name: '6',
+						value: 'P6',
+						checked: false
+					},
+					{
+						name: '7',
+						value: 'P7',
+						checked: false
+					}
+				],
+				// 晚上
+				timeEvening: [{
+						name: '1',
+						value: 'E1',
+						checked: false
+					},
+					{
+						name: '2',
+						value: 'E2',
+						checked: false
+					},
+					{
+						name: '3',
+						value: 'E3',
+						checked: false
+					},
+					{
+						name: '4',
+						value: 'E4',
+						checked: false
+					},
+					{
+						name: '5',
+						value: 'E5',
+						checked: false
+					},
+					{
+						name: '6',
+						value: 'E6',
+						checked: false
+					},
+					{
+						name: '7',
+						value: 'E7',
+						checked: false
+					}
+				],
+				rules: {
+					name: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入姓名',
+						}]
+					},
+					wxid: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入微信号',
+						}, {
+							errorMessage: '请输入正确的微信号',
+							pattern: '^[a-zA-Z][a-zA-Z\\d_-]{5,19}$',
+						}]
+					},
+					salary: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入课时费'
+						}]
+					},
+				}
+			};
+		},
+		onLoad(option) {
+			this.getPriceAndTree()
+			if (option.item !== undefined) {
+				let item = JSON.parse(decodeURIComponent(option.item))
+				this.formatStuNeed(item)
+			}
+		},
+		methods: {
+			// 格式化传递过来的stuneed信息
+			formatStuNeed(item) {
+				item.datetime = null
+				item.deal = null
+				item.deleted = null
+				item.display = null
+				item.id = null
+				item.locked = null
+				item.requireId = null
+				item.uid = null
+				item.verifyRefuseReason = null
+				item.verifyStatus = null
+				
+				this.baseFormData = item
+				this.courseWeekday = item.courseWeekday.split(",")
+				this.baseFormData.courseWeekday = this.courseWeekday
+				for (let i = 0; i < this.courseWeekday.length; i++) {
+					for (let x = 0; x < this.timeAM.length; x++) {
+						if (this.courseWeekday[i] == this.timeAM[x].value) {
+							this.timeAM[x].checked = true
+							this.courseAM.push(this.courseWeekday[i])
+						}
+					}
+					for (let y = 0; y < this.timePM.length; y++) {
+						if (this.courseWeekday[i] == this.timePM[y].value) {
+							this.timePM[y].checked = true
+							this.coursePM.push(this.courseWeekday[i])
+						}
+					}
+					for (let z = 0; z < this.timeEvening.length; z++) {
+						if (this.courseWeekday[i] == this.timeEvening[z].value) {
+							this.timeEvening[z].checked = true
+							this.courseEV.push(this.courseWeekday[i])
+						}
+					}
+				}
+				if (this.courseAM.length > 0) {
+					this.courseAM.push(this.courseAM.join().split(','))
+				}
+				if (this.coursePM.length > 0) {
+					this.coursePM.push(this.coursePM.join().split(','))
+				}
+				if (this.courseEV.length > 0) {
+					this.courseEV.push(this.courseEV.join().split(','))
+				}
+			},
+			// 手机号
+			async getPhoneNumber(e) {
+				if (e.detail.code === undefined) return uni.$showMsg('获取手机号失败!')
+				const query = {
+					code: e.detail.code
+				}
+				const {
+					data: result
+				} = await uni.$http.get('/ucenter/mini-program-openid-uid/wxGetPhone', query)
+				if (result.code === 20000) {
+					this.baseFormData.phone = result.data.phone
+					return uni.$showMsg('获取手机成功!')
+				}
+			},
+			// 树形结构的课程和价格表
+			async getPriceAndTree() {
+				const {
+					data: result
+				} = await uni.$http.get('/education/course-price/treeAndPrice')
+				this.courseTree = result.data.treeCourse
+				this.coursePrice = result.data.coursePrice
+			},
+			// 上午复选框
+			chechboxChangeAM(e) {
+				this.courseAM.push(e.detail.value)
+			},
+			// 下午复选框
+			chechboxChangePM(e) {
+				this.coursePM.push(e.detail.value)
+			},
+			// 晚上复选框
+			chechboxChangeEvening(e) {
+				this.courseEV.push(e.detail.value)
+			},
+			// 获取老师地理位置
+			getLocation() {
+				wx.chooseLocation({
+					success: res => {
+						if (res.errMsg === 'chooseLocation:ok') {
+							this.baseFormData.locationStr = res.address + res.name
+							this.baseFormData.locationAl = res.latitude + ',' + res.longitude
+						} 
+					}
+				})
+			},
+			// 提交
+			submit() {
+				if (this.isLoading) {
+					return uni.$showMsg('操作过快,请耐心等待…')
+				}
+				this.isLoading = true
+				
+				this.baseFormData.courseWeekday = []
+				this.$refs.baseForm.validate().then(res => {
+					if (this.baseFormData.phone === '') return uni.$showMsg('手机号未获取!')
+					if (this.baseFormData.locationStr === '') return uni.$showMsg('请选择地址!')
+					if (this.baseFormData.subjectSmall === '1-1' || this.baseFormData.subjectSmall === '') return uni.$showMsg('请选择课程')
+					if (this.courseAM.length === 0 && this.coursePM.length === 0 && this.courseEV.length === 0 ) return uni.$showMsg('请选择上课时间!')
+					if (this.courseAM[this.courseAM.length - 1] == '' && this.coursePM.length === 0 && this.courseEV.length === 0 ) return uni.$showMsg('请选择上课时间!')
+					if (this.courseAM.length === 0 && this.coursePM[this.coursePM.length - 1] == '' && this.courseEV.length === 0 ) return uni.$showMsg('请选择上课时间!')
+					if (this.courseAM.length === 0 && this.coursePM.length === 0 && this.courseEV[this.courseEV.length - 1] == '' ) return uni.$showMsg('请选择上课时间!')
+					if (this.courseAM[this.courseAM.length - 1] == '' && this.coursePM[this.coursePM.length - 1] == '' && this.courseEV.length === 0 ) return uni.$showMsg('请选择上课时间!')
+					if (this.courseAM[this.courseAM.length - 1] == '' && this.coursePM.length === 0 && this.courseEV[this.courseEV.length - 1] == '' ) return uni.$showMsg('请选择上课时间!')
+					if (this.courseAM.length === 0 && this.coursePM[this.coursePM.length - 1] == '' && this.courseEV[this.courseEV.length - 1] == '' ) return uni.$showMsg('请选择上课时间!')
+					if (this.courseAM[this.courseAM.length - 1] == '' && this.coursePM[this.coursePM.length - 1] == '' && this.courseEV[this.courseEV.length - 1] == '' ) return uni.$showMsg('请选择上课时间!')
+					
+					if (this.courseAM.length > 0) {
+						this.baseFormData.courseWeekday.push(this.courseAM[this.courseAM.length - 1])
+					}
+					if (this.coursePM.length > 0) {
+						this.baseFormData.courseWeekday.push(this.coursePM[this.coursePM.length - 1])
+					}
+					if (this.courseEV.length > 0) {
+						this.baseFormData.courseWeekday.push(this.courseEV[this.courseEV.length - 1])
+					}
+					// 上课时间
+					this.baseFormData.courseWeekday = this.baseFormData.courseWeekday.join()
+					// 末尾为,
+					if (this.baseFormData.courseWeekday.slice(-1) === ',') {
+						this.baseFormData.courseWeekday = this.baseFormData.courseWeekday.substring(0, this.baseFormData.courseWeekday.length - 1)
+					}
+					// 开始为,
+					if (this.baseFormData.courseWeekday.slice(0,1) === ',') {
+						let temp = this.baseFormData.courseWeekday.substring(1, this.baseFormData.courseWeekday.length )
+						this.baseFormData.courseWeekday = temp
+					}
+					
+					// 教员学历
+					if (this.baseFormData.teacherEdu === '') return uni.$showMsg('请选择教员学历!')
+					
+					// 课时费
+					let city = this.userinfo.city
+					for(let i = 0; i < this.coursePrice.length; i++) {
+						if(this.coursePrice[i].courseName === this.baseFormData.subjectSmall) {
+							// console.log(this.coursePrice[i].priceMapping.stu_price_2_l)
+							// 二线城市
+							if (city != '北京' || city != '上海' || city != '广州' || city != '深圳') {
+								// 学生
+								if (this.baseFormData.teacherType === '学生教员') {
+									if (this.coursePrice[i].priceMapping.stu_price_2_l > this.baseFormData.salary || this.baseFormData.salary > this.coursePrice[i].priceMapping.stu_price_2_h) {
+										this.errorPrice = '价格在' + this.coursePrice[i].priceMapping.stu_price_2_l + '~' + this.coursePrice[i].priceMapping.stu_price_2_h + '之间'
+										return uni.$showMsg('请合理选择课时费')
+									}
+								} else {
+									if (this.coursePrice[i].priceMapping.fulltime_price_2_l > this.baseFormData.salary || this.baseFormData.salary > this.coursePrice[i].priceMapping.fulltime_price_2_h) {
+										this.errorPrice = '价格在' + this.coursePrice[i].priceMapping.fulltime_price_2_l + '~' + this.coursePrice[i].priceMapping.fulltime_price_2_h + '元之间'
+										return uni.$showMsg('请合理选择课时费')
+									}
+								}
+							} else {
+								// 学生
+								if (this.baseFormData.teacherType === '学生教员') {
+									if (this.coursePrice[i].priceMapping.stu_price_1_l > this.baseFormData.salary || this.baseFormData.salary > this.coursePrice[i].priceMapping.stu_price_1_h) {
+										this.errorPrice = '价格在' + this.coursePrice[i].priceMapping.stu_price_1_l + '~' + this.coursePrice[i].priceMapping.stu_price_1_h + '之间'
+										return uni.$showMsg('请合理选择课时费')
+									}
+								} else {
+									if (this.coursePrice[i].priceMapping.fulltime_price_1_l > this.baseFormData.salary || this.baseFormData.salary > this.coursePrice[i].priceMapping.fulltime_price_1_h) {
+										this.errorPrice = '价格在' + this.coursePrice[i].priceMapping.fulltime_price_1_l + '~' + this.coursePrice[i].priceMapping.fulltime_price_1_h + '之间'
+										return uni.$showMsg('请合理选择课时费')
+									}
+								}
+							}
+						}
+					}
+					// 课程科目
+					for (let x = 0; x < this.courseTree.length; x++) {
+						for (let y = 0; y < this.courseTree[x].children.length; y++) {
+							if (this.courseTree[x].children[y].value === this.baseFormData.subjectSmall) {
+								this.baseFormData.subjectBig = this.courseTree[x].value
+							}
+						}
+					}
+					uni.request({
+						url: `${uni.$http.baseUrl}/education/student-requirements/publishRequirements`,
+						data: this.baseFormData,
+						header: {
+							token: uni.getStorageSync('token')
+						},
+						method: 'POST',
+						success: res => {
+							uni.$showMsg(res.data.message)
+							setTimeout(() => {
+								uni.navigateBack({
+									delta: 2
+								})
+							}, 1000)
+						}
+					})
+				}).catch(err => {
+					this.isLoading = false
+				})
+				this.isLoading = false
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		//background-color: #FFF2CC;
+	}
+</style>
+
+<style lang="scss" scoped>
+	.stu-require-container{
+		width: 96%;
+		height: 100%;
+		padding-left: 20rpx;
+	}
+	
+	.tr-container{
+	    display: flex;
+	    position: relative;
+	    width: 96%;
+	    flex-direction: column;
+	    font-size: 26rpx;
+	    /* border: 1rpx solid gray; */
+	    margin: -10px 20rpx;
+		margin-bottom: 20px;
+	}
+	
+	.tr_1 {
+	    display: flex;
+	    position: relative;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	}
+	.tr_2{
+	    display: block;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	}
+	
+	.th_0,
+	.th_1,
+	.th_2,
+	.th2_0,
+	.th2_1,
+	.th2_2{
+	    width: 12%;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	    border-right: 1rpx solid gray;
+	    border-bottom: 1rpx solid gray;
+	    text-align: center;
+	}
+	
+	.th_0,
+	.th_1,
+	.th_2{
+	    border-top: 1rpx solid gray;
+	}
+	
+	.th_0,
+	.th2_0{
+	    border-left: 1rpx solid gray;
+	}
+	
+	.th2_0{
+	    float: left;
+	    width: 12%;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	    text-align: center;
+	    /* background-color: greenyellow; */
+	}
+	// 提交按钮样式
+	.submitBtnWrapper{
+		height: 140rpx;
+		align-items: center;
+	}
+	.submitBtn{
+		width: 300rpx;
+		border-radius: 50rpx;
+		// margin-bottom: 40rpx;
+		background-color: #35b882;
+	}
+	// 获取手机号按钮背景颜色
+	.getPhone{
+		background-color: #35b882;
+	}
+</style>

+ 141 - 0
education_uni/subpkg/student/require/student_require_all_detail.vue

@@ -0,0 +1,141 @@
+<template>
+	<view style="background-color: #F0F0F0;">
+		<my-requiredetail v-if="showDetail" :item="item" :location="location" :marker="marker" :timeAM="timeAM" :timePM="timePM" :timeEvening="timeEvening" :collect="collect" :isShowCollect="isShowCollect" buttonMessage="邀请" @collecting="collecting" @publishButton="invite"></my-requiredetail>
+		
+		<my-invite :isShowInvite="isShowInvite" :item11="myCourses" @cancelChosed="cancelChosed" @commitChosed="commitChosed" @clickRadio="clickRadio"></my-invite>
+	</view>
+</template>
+
+<script>
+	import { mapState } from 'vuex'
+	import formTime from '@/mixins/form-time.js'
+	export default {
+		mixins: [formTime],
+		computed: {
+			...mapState('m_user', ['userinfo'])
+		},
+		data() {
+			return {
+				showDetail: false,
+				initeCourse: '',
+				myCourses: [],
+				isShowInvite: false,
+				isShowCollect: true,
+				collect: false,
+				item: {},	// 需求详情
+				location: [],
+				marker: [{
+					id: 1,
+					joinCluster:true,
+					latitude: 0,
+					longitude: 0,
+					width: 40,
+					height: 40,
+					iconPath: '/static/location.png',
+				}],
+			};
+		},
+		onLoad(option) {
+			if (option.requireId !== undefined) {
+				const requireId = decodeURIComponent(option.requireId)
+				this.getStuNeedsDetailById(requireId)
+			}
+			this.getIsCollection()
+		},
+		methods: {
+			// 获取需求详情
+			async getStuNeedsDetailById(id) {
+				const {data: result} = await uni.$http.get('/education/student-requirements/getStuNeedsDetailById', {requireId: id})
+				this.item = result.data.one
+				this.formatForm()
+			},
+			// 上课表格格式化
+			formatForm() {
+				this.location = this.item.locationAl.split(",")
+				this.marker[0].latitude = Number(this.location[0])
+				this.marker[0].longitude = Number(this.location[1])
+				this.courseWeekday = this.item.courseWeekday.split(",")
+				this.parseCourseWeekday()
+				this.showDetail = true
+			},
+			// 查看是否收藏过
+			async getIsCollection() {
+				const { data: result } = await uni.$http.get('/education/my-favorite-needs/findPersonCollect')
+				const list = result.data.requires
+				if (list !== null) {
+					for (let i = 0; i < list.length; i++) {
+						if (this.item.requireId === list[i]) {
+							this.collect = true
+						}
+					}
+				}
+			},
+			// 收藏、取消收藏
+			async collecting() {
+				const queryObj = {
+					requireId: this.item.requireId
+				}
+				if (!this.collect) {
+					const { data: result1 } = await uni.$http.get('/education/my-favorite-needs/collect', queryObj)
+					if (result1.message === '收藏成功') {
+						return this.collect = true
+					}
+					if (result1.message === '收藏失败') {
+						return uni.$showMsg('收藏失败')
+					}
+				} 
+				if (this.collect) {
+					const { data: result } = await uni.$http.get('/education/my-favorite-needs/cancelCollect', queryObj)
+					if (result.message === '取消收藏成功') {
+						return this.collect = false
+					}
+					if (result.message === '取消收藏失败') {
+						return uni.$showMsg('取消收藏失败')
+					}
+				}
+			},
+			invite() {
+				this.isShowInvite = true
+				this.showMyCourse()
+			},
+			async showMyCourse() {
+				const { data: result } = await uni.$http.get('/education/teacher-courses/queryPersonSomeInfo')
+				this.myCourses = result.data.list
+				const name = result.data.name
+				if (this.myCourses !== undefined) {
+					for (let i = 0; i < this.myCourses.length; i++) {
+						this.myCourses[i].fromUname = name
+					}
+				}
+			},
+			cancelChosed() {
+				this.isShowInvite = false
+			},
+			async commitChosed() {
+				if (this.initeCourse === '') return uni.$showMsg('请选择邀请的课程')
+				this.initeCourse.toUid = this.item.uid
+				this.initeCourse.requireId = this.item.requireId
+				this.initeCourse.salary = this.item.salary
+				this.initeCourse.toUname = this.item.name
+				
+				const {data: result} = await uni.$http.post('/education/invite-info/sendInvite', this.initeCourse)
+				uni.$showMsg(result.message)
+				this.isShowInvite = false
+			},
+			clickRadio(item) {
+				this.initeCourse = item
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+</style>

+ 163 - 0
education_uni/subpkg/student/require/student_require_my_collect.vue

@@ -0,0 +1,163 @@
+<template>
+	<view>
+		<view v-for="(item, index) in stuNeeds" :key="index">
+			<view class="publicItem" @click="goDetail(item.requireId)">
+				<view class="hotStudent">
+					<template v-if="item.sex === '女'">
+						<image class="teachImg" src="/static/girl.png"></image>
+					</template>
+					<template v-else>
+						<image class="teachImg" src="/static/boy.png"></image>
+					</template>
+					<view class="hotStudentText">
+						<view class="studentTitle">{{item.name}}学员</view>
+						<view class="publicSex">{{item.sex}}</view>
+						<view class="stuGoal">{{item.goal}}</view>
+						<view class="studentDistance">
+							<uni-icons type="location" color="#3ed598" ></uni-icons>
+							<text>{{item.kil}}</text>km
+						</view>
+					</view>
+					<view class="stuSubject">{{item.subjectBig + "/" + item.subjectSmall}}</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { mapState } from 'vuex'
+	import computeDistance from '@/mixins/compute-distance.js'
+	export default {
+		mixins: [computeDistance],
+		computed: {
+			...mapState('m_user', ['location'])
+		},
+		data() {
+			return {
+				stuNeeds: [],
+			};
+		},
+		onShow() {
+			this.getAllStuNeeds()
+		},
+		methods: {
+			async getAllStuNeeds() {
+				// 发起请求
+				const { data: result } = await uni.$http.get('/education/my-favorite-needs/findPersonCollectInfo')
+				for (let i = 0; i < result.data.list.length; i++) {
+					let arr = result.data.list[i].locationAl.split(",")
+					let kil = this.space(arr[0], arr[1], this.location.latitude, this.location.longitude)
+					result.data.list[i].kil = kil
+					result.data.list[i].name = result.data.list[i].name.slice(0,1)
+				}
+				this.stuNeeds = result.data.list
+			},
+			goDetail(id) {
+				uni.navigateTo({
+					url: '/subpkg/student/require/student_require_all_detail?requireId=' + encodeURIComponent(id) 
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #D4F5E9;
+	}
+</style>
+
+<style lang="scss" scoped>
+/* 教员、学员头像 */
+	.teachImg,
+	.studentImg{
+		width: 25%;
+		height: 95%;
+		border-radius: 20%;
+	}
+		
+	.stuSubject{
+		position: absolute;
+		left: 200rpx;
+		top: 60rpx;
+		border: 0rpx solid gray;
+		padding: 10rpx 20rpx;
+		border-radius: 30rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+	
+	.studentTitle{
+		font-size: 14px;
+		position: absolute;
+		left: 200rpx;
+		top: 10rpx;
+		font-weight: bold;
+		color: #6d6d6d;
+	}
+	
+	/* 距离 */
+	.studentDistance{
+		position: absolute;
+		left: 300rpx;
+		top: 10rpx;
+		font-weight: bold;
+		color: #3ed598;
+		font-size: 12px;
+	}
+		
+	.stuGoal{
+		margin-top: 10rpx;
+		border: 2px solid #3ed598;
+		border-radius: 30rpx;
+		padding: 0rpx 10rpx;
+		font-size: 12px;
+		position: absolute;
+		left: 200rpx;
+		top: 125rpx;
+		color: #3ed598;
+		display: block;//将文本设置为块元素,否则overflow无效
+		overflow: hidden;
+		text-overflow: ellipsis;
+		display: -webkit-box;
+		-webkit-box-orient: vertical;//设置对齐模式为垂直对齐
+		-webkit-line-clamp: 1;//设置要显示的行数
+	}
+		
+	/* item */
+	.publicItem{
+		margin-left: 20rpx;
+		margin-right: 20rpx;
+		margin-top: 10rpx ;
+		margin-bottom: 10rpx ;
+		border: 0rpx solid gray;
+		padding: 10rpx 20rpx;
+		border-radius: 30rpx;
+		background-color: #ffffff;
+	}
+	
+	.hotStudent{
+		position: relative;
+		display: flex;
+		padding: 10rpx;
+		height: 170rpx;
+		align-items: center;
+	}
+	
+	/* teachsex */
+	.publicSex{
+		position: absolute;
+		right: 10rpx;
+		top: 5rpx;
+		border: 0rpx solid gray;
+		padding: 5rpx 10rpx;
+		border-radius: 30rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+</style>

+ 68 - 0
education_uni/subpkg/student/require/student_require_my_detail.vue

@@ -0,0 +1,68 @@
+<template>
+	<view>
+		<my-requiredetail v-if="showDetail" :item="item" :location="location" :marker="marker" :timeAM="timeAM" :timePM="timePM" :timeEvening="timeEvening" :isShowPrivate="isShowPrivate" buttonMessage="以此为模板新发布" @publishButton="publishButton"></my-requiredetail>
+	</view>
+</template>
+
+<script>
+	import formTime from '@/mixins/form-time.js'
+	export default {
+		mixins: [formTime],
+		data() {
+			return {
+				showDetail: false,
+				isShowPrivate: true,
+				item: {},
+				location: [],
+				marker: [{
+					id: 1,
+					joinCluster:true,
+					latitude: 0,
+					longitude: 0,
+					width: 40,
+					height: 40,
+					iconPath: '/static/location.png',
+				}],
+			};
+		},
+		onLoad(option) {
+			if (option.requireId !== undefined) {
+				const requireId = decodeURIComponent(option.requireId)
+				this.getStuNeedDetailById(requireId)
+			}
+		},
+		methods: {
+			// 获取需求详情
+			async getStuNeedDetailById(id) {
+				const {data: result} = await uni.$http.get('/education/student-requirements/getPublishStuNeedsDetailById', {requireId: id})
+				this.item = result.data.one
+				this.formatForm()
+			},
+			// 上课表格格式化
+			formatForm() {
+				this.location = this.item.locationAl.split(",")
+				this.marker[0].latitude = Number(this.location[0])
+				this.marker[0].longitude = Number(this.location[1])
+				this.courseWeekday = this.item.courseWeekday.split(",")
+				this.parseCourseWeekday()
+				this.showDetail = true
+			},
+			publishButton() {
+				uni.navigateTo({
+					url:'/subpkg/student/require/student_require_add?item='+encodeURIComponent(JSON.stringify(this.item))
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+</style>

+ 146 - 0
education_uni/subpkg/student/require/student_require_my_publish.vue

@@ -0,0 +1,146 @@
+<template>
+	<view>
+		<view v-for="(item, index) in requirement" :key="index">
+			<view class="requires" @click="requireDetail(item)">
+				<uni-row class="demo-uni-row">
+					<uni-col offset="1">
+						<view class="requires-col1">需求号:{{item.requireId}}</view>
+					</uni-col>
+				</uni-row>
+				<uni-row class="demo-uni-row">
+					<uni-col offset="1" :span="16">
+						<view class="requires-col2">需求科目:{{item.subjectSmall}}</view>
+					</uni-col>
+					<uni-col :span="7">
+						<view>
+							<button @click.stop="open(item)" size="mini" :type="item.buttonType">{{item.display}}</button>
+						</view>
+					</uni-col>
+				</uni-row>
+				<view class="requires-col3">
+					<uni-row class="demo-uni-row">
+						<uni-col :span="11" offset="1">
+							<view>需求金额:{{item.salary}}</view>
+						</uni-col>
+						<uni-col :span="4" >
+							<view style="color: red;">{{item.verifyStatus}}</view>
+						</uni-col>
+						<uni-col :span="4" >
+							<view style="color: red;">{{item.deal}}</view>
+						</uni-col>
+						<uni-col :span="4" >
+							<view style="color: red;">{{item.locked}}</view>
+						</uni-col>
+					</uni-row>
+				</view>
+			</view>
+		</view>
+		
+		<uni-popup ref="popup" type="message">
+			<uni-popup-message :type="popupType" :message="showMessage" :duration="1000"></uni-popup-message>
+		</uni-popup>
+		
+	</view>
+</template>
+
+<script>
+	import { mapState, mapMutations } from 'vuex'
+	
+	export default {
+		data() {
+			return {
+				requirement: [],	// 需求列表
+				publishCount: 0,	// 上架数量
+				showMessage: '上架成功',
+				popupType: 'success'
+			};
+		},
+		onShow() {
+			this.getPublishCounts()
+		},
+		methods: {
+			// 查询个人上架了多少课程
+			async getPublishCounts() {
+				const { data: result } = await uni.$http.get('/education/student-requirements/getPublishCounts')
+				
+				this.publishCount = result.data.publishCounts
+				let courses = []
+				courses = result.data.list
+				
+				for (let i = 0; i < courses.length; i++) {
+					if (courses[i].display === '上架') {
+						courses[i].display = '下架'
+						courses[i].buttonType = 'warn'
+					} else {
+						courses[i].display = '上架'
+						courses[i].buttonType = 'primary'
+					}
+				}
+				this.requirement = courses
+			},
+			requireDetail(item) {
+				uni.navigateTo({
+					url: '/subpkg/student/require/student_require_my_detail?requireId=' + encodeURIComponent(item.requireId)
+				})
+			},
+			async open(item) {
+				if (item.display === '上架') {
+					if (item.verifyStatus !== '已通过') return uni.$showMsg('审核通过才能上架')
+					if (item.deal === '已成交') return uni.$showMsg('已成交的需求不能上架')
+					if (item.locked === '已锁') return uni.$showMsg('正在锁定的需求不能上架')
+					if (this.publishCount >= 4) return uni.$showMsg('最多发布4个需求')
+				}
+				const queryObj = {
+					display: item.display,
+					requireId: item.requireId
+				}
+				const { data: result } = await uni.$http.get('/education/student-requirements/updatePersonDisplay', queryObj)
+				if (result.code === 20000) {
+					if (item.display === '上架') {
+						item.display = '下架'
+						this.showMessage = '上架成功'
+						this.popupType = 'success'
+						item.buttonType = 'warn'
+						this.publishCount += 1
+						
+					} else if (item.display === '下架') {
+						item.display = '上架'
+						this.showMessage = '下架成功'
+						this.popupType = 'error'
+						item.buttonType = 'primary'
+						this.publishCount -= 1
+					}
+					this.$refs.popup.open('top')
+				}
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+
+.requires {
+	background-color: #FFF2CC;
+	border: 1px solid #41719C;
+	
+	.requires-col1 {
+		margin-top: 15rpx;
+	}
+	
+	.requires-col2 {
+		margin: 15rpx 0;
+	}
+	
+	.requires-col3 {
+		padding-bottom: 15rpx;
+	}
+}
+</style>

+ 135 - 0
education_uni/subpkg/teacher/authentication/teacher_authentication.vue

@@ -0,0 +1,135 @@
+<template>
+	<view>
+		<view v-show="isShow">
+			<view class="requires" @click="requireDetail(item)">
+				<uni-row >
+					<uni-col offset="1">
+						<text class="fontStyle">用户ID:</text>{{item.uid}}
+					</uni-col>
+				</uni-row>
+				<uni-row >
+					<uni-col offset="1">
+						<text class="fontStyle">显示名:</text> {{item.name}} <text>教员</text>
+					</uni-col>
+				</uni-row>
+				<uni-row >
+					<uni-col offset="1">
+						<text class="fontStyle">当前高校:</text>{{item.school}}
+					</uni-col>
+				</uni-row>
+				<uni-row>
+					<uni-col offset="1" :span="11">
+						<text class="fontStyle">当前学历:</text>{{item.education}}
+					</uni-col>
+					<uni-col :span="12">
+						<text class="fontStyle">手机号:</text>{{item.phone}}
+					</uni-col>
+				</uni-row>
+				<uni-row >
+					<uni-col offset="1" :span="18">
+						<text class="fontStyle">微信号:</text>{{item.weixinId}}
+					</uni-col>
+					<uni-col :span="5">
+						<text class="authorize">{{authentication}}</text>
+					</uni-col>
+				</uni-row>
+			</view>
+		</view>
+		
+		<uni-fab  :pattern="pattern" horizontal="left" vertical="bottom" :content="content"
+					direction="horizontal"  @trigger="trigger" />
+	</view>
+</template>
+
+<script>
+	import { mapState, mapMutations } from 'vuex';
+	export default {
+		computed: {
+			...mapState('m_user', ['authentication'])
+		},
+		data() {
+			return {
+				pattern: {
+					color: '#7A7E83',
+					backgroundColor: '#E2F0D9',
+					selectedColor: '#1296db',
+					buttonColor: '#E2F0D9',
+					iconColor: '#000000'
+				},
+				content: [{
+						iconPath: '/static/authorized.png',
+						selectedIconPath: '/static/authorizedd.png',
+						text: '老师认证',
+						active: false
+					}
+				],
+				item: {},
+				isShow: false
+			};
+		},
+		onShow() {
+			this.getPersonAuthorize()
+		},
+		methods: {
+			...mapMutations('m_user', ['updateAuthentication']),
+			// 获取认证信息
+			async getPersonAuthorize() {
+				const { data: result } = await uni.$http.get('/education/teacher-certifications/findInfosByUid')
+				this.item = result.data.one
+				if (this.item == null) {
+					this.updateAuthentication('未申请认证')
+				} else {
+					this.isShow = true
+					if (this.item.verifyRefuseReason == null) {
+						this.item.verifyRefuseReason = '无'
+					}
+					this.updateAuthentication(result.data.one.verifyStatus)
+				}
+				this.content[0].active = false
+			},
+			trigger(e) {
+				this.content[e.index].active = true
+				if (this.authentication === '未申请认证') {
+					uni.navigateTo({
+						url:'/subpkg/teacher/authentication/teacher_authentication_add'
+					})
+				} else if (this.authentication === '审核中') {
+					return uni.$showMsg('正在审核中…')
+				} else if (this.authentication === '已通过') {
+					return uni.$showMsg('你已认证过')
+				} else if (this.authentication === '未通过') {
+					return uni.$showMsg('请修改认证')
+				}
+			},
+			requireDetail(item) {
+				uni.navigateTo({
+					url: '/subpkg/teacher/authentication/teacher_authentication_detail?item=' + encodeURIComponent(JSON.stringify(this.item))
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+.requires {
+	//background-color: #FFF2CC;
+	margin: 0 20rpx;
+	border-radius: 10%;
+	
+	.fontStyle {
+		font-weight: 600;
+	}
+	
+	.authorize {
+		color: red;
+	}
+}
+</style>

+ 356 - 0
education_uni/subpkg/teacher/authentication/teacher_authentication_add.vue

@@ -0,0 +1,356 @@
+<template>
+	<view class="auth-Container" style="background-color: #f0f0f0;">
+		<uni-forms ref="baseForm" :modelValue="baseFormData" labelWidth="75px" :rules="rules" validateTrigger="bind">
+			<uni-forms-item label="真实姓名" name="name" required>
+				<uni-easyinput v-model="baseFormData.name" placeholder="请输入姓名" maxlength="6" trim="both" />
+			</uni-forms-item>
+			<uni-forms-item label="手机号" required>
+				<button class="getPhone" open-type="getPhoneNumber" type="primary" size="mini"
+					@getphonenumber="getPhoneNumber">获取手机号</button>
+			</uni-forms-item>
+			<uni-forms-item label="微信号" name="weixinId" required>
+				<uni-easyinput v-model="baseFormData.weixinId" placeholder="微信号(不便接听电话时微信沟通)" maxlength="25"
+					trim="both" />
+			</uni-forms-item>
+			<uni-forms-item label="英文名" name="englishName">
+				<uni-easyinput v-model="baseFormData.englishName" placeholder="请输入你的英文名" maxlength="25" trim="both" />
+			</uni-forms-item>
+			<uni-forms-item label="身份证号" name="idCard" required>
+				<uni-easyinput v-model="baseFormData.idCard" type="idcard" placeholder="请输入你的身份证号" />
+			</uni-forms-item>
+			<uni-forms-item label="性别" name="sex" required>
+				<uni-data-checkbox v-model="baseFormData.sex" :localdata="sexs" />
+			</uni-forms-item>
+			<uni-forms-item label="身份" name="identify" required>
+				<uni-data-checkbox v-model="baseFormData.identify" :localdata="identifies" />
+			</uni-forms-item>
+			<uni-forms-item label="身份证照片" required>
+				<text style="color: blue;">(说明:需要能看清楚证件号码、日期及头像)</text>
+				<uni-file-picker fileMediatype="image"  :sizeType="sizeType" v-model="idCardFrontByte" :fileExtname="fileExtname" limit="1" title="身份证正面" @select="selectIdCardFront" @delete="deletePhoto" />
+				<uni-file-picker fileMediatype="image"  :sizeType="sizeType" v-model="idCardBackByte" :fileExtname="fileExtname"  limit="1" title="身份证背面" @select="selcetIdCardBack" @delete="deletePhoto" />
+			</uni-forms-item>
+			<uni-forms-item label="学生/毕业证" required>
+				<text style="color: blue;">(已毕业的需要上传毕业证)</text>
+				<uni-file-picker fileMediatype="image"  :sizeType="sizeType" v-model="diplomaPhotoByte" :fileExtname="fileExtname" limit="1" @select="selectDiplomaPhoto" @delete="deletePhoto" />
+			</uni-forms-item>
+			<uni-forms-item label="头像" required>
+				<text style="color: blue;">(说明:只能上传证件照,上传其他照片审核不予通过)</text>
+				<uni-file-picker fileMediatype="image"  :sizeType="sizeType" v-model="profilePhotoByte" :fileExtname="fileExtname" limit="1" @select="selectProfilePhoto" @delete="deletePhoto" />
+			</uni-forms-item>
+			<uni-forms-item label="毕业/就读学校" name="school" required>
+				<uni-easyinput v-model="baseFormData.school" placeholder="请输入学校全称" maxlength="30" trim="both" />
+			</uni-forms-item>
+			<uni-forms-item label="所学专业" name="major" required>
+				<uni-easyinput v-model="baseFormData.major" placeholder="请输入专业名称" maxlength="20" trim="both" />
+			</uni-forms-item>
+			<uni-forms-item label="学历" name="education" required>
+				<uni-data-select v-model="baseFormData.education" :localdata="educations" />
+			</uni-forms-item>
+			<uni-forms-item label="籍贯" name="nativePlace" required>
+				<uni-easyinput v-model="baseFormData.nativePlace" placeholder="xx省xx市xx区" maxlength="30" trim="both" />
+			</uni-forms-item>
+		</uni-forms>
+		<view>
+			<button class="authenticationBtn" type="primary" @click="submit">{{buttonMessage}}</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { mapState, mapMutations } from 'vuex'
+	export default {
+		computed: {
+			...mapState('m_user', ['authentication']),
+		},
+		data() {
+			return {
+				fileExtname: 'png,jpg',
+				sizeType: ['compressed'],
+				idCardFrontByte: [{
+					url: '',
+					extname: '',
+					name: ''
+				}],
+				idCardBackByte: [{
+					url: '',
+					extname: '',
+					name: ''
+				}],
+				profilePhotoByte: [{
+					url: '',
+					extname: '',
+					name: ''
+				}],
+				diplomaPhotoByte: [{
+					url: '',
+					extname: '',
+					name: ''
+				}],
+				buttonMessage: '申请认证',
+				isLoading: false, // 节流阀
+				baseFormData: {
+					name: '',
+					weixinId: '',
+					idCard: '',
+					sex: '男',
+					identify: '专职老师',
+					school: '',
+					major: '',
+					education: '',
+					nativePlace: '',
+					education: '本科在读'
+				},
+				sexs: [{
+					text: '男',
+					value: '男'
+				}, {
+					text: '女',
+					value: '女'
+				}],
+				// 单选老师身份
+				identifies: [{
+					text: '专职老师',
+					value: '专职老师'
+				}, {
+					text: '在校大学生',
+					value: '在校大学生'
+				}],
+				educations: [{
+					value: '专科在读',
+					text: '专科在读'
+				}, {
+					value: '专科毕业',
+					text: '专科毕业'
+				}, {
+					value: '本科在读',
+					text: '本科在读'
+				}, {
+					value: '本科毕业',
+					text: '本科毕业'
+				}, {
+					value: '硕士在读',
+					text: '硕士在读'
+				}, {
+					value: '硕士毕业',
+					text: '硕士毕业'
+				}, {
+					value: '博士在读',
+					text: '博士在读'
+				}, {
+					value: '博士毕业',
+					text: '博士毕业'
+				}],
+				rules: {
+					name: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入姓名',
+						}]
+					},
+					weixinId: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入微信号',
+						}, {
+							errorMessage: '请输入正确的微信号',
+							pattern: '^[a-zA-Z][a-zA-Z\\d_-]{5,19}$',
+						}]
+					},
+					idCard: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入身份证号',
+						}, {
+							errorMessage: '请输入正确的身份证号',
+							pattern: '^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$',
+						}]
+					},
+					school: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入学校全称',
+						}]
+					},
+					major: {
+						rules: [{
+							required: true,
+							errorMessage: '请输入专业名称',
+						}]
+					},
+					nativePlace: {
+						rules: [{
+								required: true,
+								errorMessage: '请输入籍贯',
+							},
+							{
+								pattern: '[\\u4e00-\\u9fa5]+[\\u7701]{1}[\\u4e00-\\u9fa5]+[\\u5E02]{1}[\\u4e00-\\u9fa5]+[\\u53BF|\\u533A]{1}',
+								errorMessage: '请输入正确的格式:xx省xx市xx区/县',
+							}
+						]
+					}
+				}
+			};
+		},
+		onLoad(option) {
+			if (option.item) {
+				this.baseFormData = JSON.parse(decodeURIComponent(option.item))
+				this.buttonMessage = '修改认证'
+				this.getPhotoes()
+			} else {
+				this.idCardFrontByte = [],
+				this.idCardBackByte = [],
+				this.profilePhotoByte = [],
+				this.diplomaPhotoByte = [],
+				this.buttonMessage = '申请认证'
+			}
+		},
+		methods: {
+			...mapMutations('m_user', ['updateAuthentication']),
+			// 获取图片
+			async getPhotoes() {
+				this.diplomaPhotoByte[0].url = this.baseFormData.diplomaPhoto
+				this.diplomaPhotoByte[0].name = 'diplomaPhoto'
+				this.idCardBackByte[0].url = this.baseFormData.idCardBack
+				this.idCardBackByte[0].name = 'idCardBack'
+				this.profilePhotoByte[0].url = this.baseFormData.profilePhoto
+				this.profilePhotoByte[0].name = 'profilePhoto'
+				this.idCardFrontByte[0].url = this.baseFormData.idCardFront
+				this.idCardFrontByte[0].name = 'idCardFront'
+			},
+			// 手机号
+			async getPhoneNumber(e) {
+				if (e.detail.code === undefined) return uni.$showMsg('获取手机号失败!')
+				const query = {
+					code: e.detail.code
+				}
+				const {
+					data: result
+				} = await uni.$http.get('/ucenter/mini-program-openid-uid/wxGetPhone', query)
+				if (result.code === 20000) {
+					this.baseFormData.phone = result.data.phone
+					return uni.$showMsg('获取手机成功!')
+				}
+			},
+			deletePhoto(e) {
+				const photoName = e.tempFile.name
+				this.baseFormData[photoName] = ''
+			},
+			// 上传身份证正面
+			selectIdCardFront(e) {
+				this.getUploadPaths(e, 'this.baseFormData.idCardFront')
+			},
+			// 上传身份证背面
+			selcetIdCardBack(e) {
+				this.getUploadPaths(e, 'this.baseFormData.idCardBack')
+			},
+			// 上传毕业/学生证
+			selectDiplomaPhoto(e) {
+				this.getUploadPaths(e, 'this.baseFormData.diplomaPhoto')
+			},
+			// 上传头像
+			selectProfilePhoto(e) {
+				this.getUploadPaths(e, 'this.baseFormData.profilePhoto')
+			},
+			getUploadPaths(e, item) {
+				if (e.tempFiles[0].size > 2000000) {
+					return uni.$showMsg('图片大小最多2M,超出限制')
+				}
+				var that = this
+				wx.uploadFile({
+					url: uni.$http.baseUrl + '/file/uploading',
+					filePath: e.tempFilePaths[0],
+					name: 'file',
+					header: {
+						token: uni.getStorageSync('token')
+					},
+					success(res) {
+						const result = JSON.parse(res.data)
+						const item1 = item.substring(item.lastIndexOf('.') + 1)
+						that.baseFormData[item1] = result.data.url
+					},
+					fail(res) {
+						if (res.errno === 1001) {
+							uni.$showMsg('只能选择.jpg或者.png的图片')
+						}
+					}
+				})
+			},
+			submit() {
+				if (this.isLoading) {
+					return uni.$showMsg('操作过快,请耐心等待…')
+				}
+				this.isLoading = true
+				this.$refs.baseForm.validate().then(res => {
+					if (this.baseFormData.phone === undefined) return uni.$showMsg('手机号未获取!')
+					if (this.baseFormData.idCardFront === undefined || this.baseFormData.idCardFront === '') return uni.$showMsg('身份证正面未上传!')
+					if (this.baseFormData.idCardBack === undefined || this.baseFormData.idCardBack === '') return uni.$showMsg('身份证背面未上传!')
+					if (this.baseFormData.diplomaPhoto === undefined || this.baseFormData.diplomaPhoto === '') return uni.$showMsg('学生/毕业证未上传!')
+					if (this.baseFormData.profilePhoto === undefined || this.baseFormData.profilePhoto === '') return uni.$showMsg('头像未上传!')
+					if (this.buttonMessage === '修改认证') {
+						const certificationUrl = '/education/teacher-certifications/updateCertificationInfo'
+						this.sendRequest(certificationUrl, 2)
+						
+					} else {
+						const certificationUrl = '/education/teacher-certifications/saveCertificationInfo'
+						this.sendRequest(certificationUrl, 1)
+					}
+				}).catch(err => {
+
+					this.isLoading = false
+				})
+				this.isLoading = false
+			},
+			sendRequest(certificationUrl, count) {
+				uni.request({
+					url: uni.$http.baseUrl + certificationUrl,
+					data: this.baseFormData,
+					header: {
+						token: uni.getStorageSync('token')
+					},
+					method: 'POST',
+					success: res => {
+						this.isLoading = false
+						uni.$showMsg(res.data.message)
+						this.updateAuthentication('审核中')
+						setTimeout(() => {
+							uni.navigateBack({
+								delta: count
+							})
+						}, 1000)
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		//background-color: #FFF2CC;
+	}
+</style>
+
+<style lang="scss" scoped>
+.auth-Container{
+	width: 96%;
+	height: 100%;
+	padding-left: 20rpx;
+}
+
+.warning {
+	color: red
+}
+// 获取手机号按钮背景样式
+.getPhone{
+	background-color: #35b882;
+}
+// 申请认证按钮样式
+.authenticationBtn{
+	width: 260rpx;
+	border-radius: 50rpx;
+	margin-bottom: 40rpx;
+	background-color: #35b882;
+}
+</style>

+ 218 - 0
education_uni/subpkg/teacher/authentication/teacher_authentication_detail.vue

@@ -0,0 +1,218 @@
+<template>
+	<view class="container">
+		<!-- 顶部信息 -->
+		<view class="userInfo">
+		    <view>
+		        <text>用户ID</text>
+		        <text class="userDetail">{{item.uid}}</text>
+		    </view>
+		    <view class="userName">
+		        <text>贵姓</text>
+		        <text class="userDetail">{{item.firstName}}</text>
+		    </view>
+		</view>
+		<view class="userInfo">
+		    <view>
+		        <text>手机号</text>
+		        <text class="userDetail">{{item.phone}}</text>
+		    </view>
+		    <view class="userName">
+		        <text>英文名</text>
+		        <text class="userDetail">{{item.englishName}}</text>
+		    </view>
+		</view>
+		<view class="userInfo">
+		    <text>微信号</text>
+		    <text class="userDetail">{{item.weixinId}}</text>
+		</view>
+		<view class="userInfo">
+		    <text>身份证号</text>
+		    <text class="userDetail">{{item.idCard}}</text>
+		</view>
+		<!-- 照片信息 -->
+		<view class="userImg">
+		    <view class="userImgDetail">
+		        <image class="userImage" :src="item.diplomaPhoto"></image>
+		    </view>
+		    <view class="userImgDetail">
+		        <image class="userImage" :src="item.idCardBack"></image>
+		    </view>
+		    <view class="userImgDetail">
+		        <image class="userImage" :src="item.idCardFront"></image>
+		    </view>
+		    <view class="userImgDetail">
+		        <image class="userImage" :src="item.profilePhoto"></image>
+		    </view>
+		</view>
+		<!-- 高校信息 -->
+		<view class="school">
+		    <text>高校全名</text>
+		    <text class="schoolName">{{item.school}}</text>
+		</view>
+		<!-- 教员性别和专业 -->
+		<view class="teacherSexMajor">
+		    <view>
+		        <text>教员性别</text>
+		        <text class="userDetail">{{item.sex}}</text>
+		    </view>
+		    <view class="teacherMajor">
+				<text>当前学历</text>
+				<text class="userDetail">{{item.education}}</text>
+		    </view>
+		</view>
+		<!-- 籍贯 -->
+		<view class="userInfo">
+		    <text>籍贯</text>
+		    <text class="userDetail">{{item.nativePlace}}</text>
+		</view>
+		<!-- 当前学历 -->
+		<view class="userInfo">
+		    <text>专业</text>
+		    <text class="userDetail">{{item.major}}</text>
+		</view>
+		<!-- 审核状态 -->
+		<view class="audit">
+		    <text>审核状态</text>
+		    <text class="auditDetail">{{item.verifyStatus}}</text>
+		</view>
+		<!-- 审核不通过原因 -->
+		<view class="auditResult">
+		    <text>审核不通过原因</text>
+		    <text class="auditDetail">{{item.verifyRefuseReason}}</text>
+		</view>
+		<!-- 申请日期 -->
+		<view class="applyDate">
+		    <text>申请日期</text>
+		    <text class="userDetail">{{item.datetime}}</text>
+		</view>
+		<!-- 修改认证按钮 -->
+		<view class="modify" @click="modifyAuthorize">
+		    <text class="modifyBtn">修改认证</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { mapState } from 'vuex';
+	
+	export default {
+		computed: {
+			...mapState('m_user', ['authorizePhoto'])
+		},
+		data() {
+			return {
+				item: {}
+			};
+		},
+		onLoad(option) {
+			this.item = JSON.parse(decodeURIComponent(option.item))
+			let arr = this.item.name.split('')
+			if (arr.length <= 3) {
+				this.item.firstName = this.item.name.substring(0,1) 
+			} else {
+				this.item.firstName = this.item.name.substring(0,2)
+			}
+		},
+		methods: {
+			modifyAuthorize() {
+				uni.navigateTo({
+					url: '/subpkg/teacher/authentication/teacher_authentication_add?item=' + encodeURIComponent(JSON.stringify(this.item))
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+.container {
+	//background-color: #FFF2CC;
+	padding-left: 20rpx;
+	height: 100%;
+}
+/* 顶部用户信息、性别和专业 */
+.userInfo,
+.teacherSexMajor{
+    display: flex;
+    margin-top: 16rpx;    
+}
+/* 姓、英文名、专业 */
+.userName,
+.teacherMajor{
+    position: absolute;
+    left: 60%;
+}
+.school{
+    margin-top: 30rpx;
+}
+/* 用户详情、高校名称、审核状态即原因 */
+.userDetail,
+.schoolName,
+.auditDetail{
+    margin-left: 20rpx;
+    font-weight: bold;
+}
+/* 照片信息 */
+.userImg{
+    margin-top: 30rpx;
+    display: flex;
+    flex-wrap: wrap;
+}
+/* 设置边框 */
+.userImgDetail{
+    width: 45%;
+    padding: 10rpx;
+    height: 200rpx;
+    display: flex;
+    border-left: 1rpx solid gray;
+    border-top: 1rpx solid gray;
+}
+/* 偶数照片添加右边框 */
+.userImg :nth-child(even){
+    border-right: 1rpx solid gray;
+}
+/* 第三张照片添加下边框 */
+.userImg :nth-child(3){
+    border-bottom: 1rpx solid gray;
+}
+/* 第四张照片添加下边框 */
+.userImg :nth-child(4){
+    border-bottom: 1rpx solid gray;
+}
+/* 设置照片 */
+.userImage{
+    width: 100%;
+    height: 100%;
+}
+/* 审核状态 */
+.audit{
+    margin-top: 40rpx;
+}
+/* 审核不通过原因、申请日期 */
+.auditResult,
+.applyDate{
+    margin-top: 20rpx;
+}
+
+/* 修改认证按钮 */
+.modify{
+    margin-top: 120rpx;
+    margin-bottom: 60rpx;
+    display: flex;
+    justify-content: center;
+}
+.modifyBtn{
+    font-size: 38rpx;
+    padding: 10rpx 30rpx;
+    border-radius: 40rpx;
+    background-color: #35b882;
+    color: white;
+}
+</style>

+ 543 - 0
education_uni/subpkg/teacher/course/teacher_course_add.vue

@@ -0,0 +1,543 @@
+<template>
+	<view class="course-add-container" style="background-color: #F0F0F0;">
+		<uni-forms ref="baseForm" :model="baseFormData" labelWidth="80px" :rules="rules" labelPosition="top">
+			<uni-forms-item label="授课科目:" required>
+				<uni-data-picker placeholder="选择授课" popup-title="课程大纲-具体课程" v-model="baseFormData.subject" :clearIcon="false" :localdata="courseTree">
+				</uni-data-picker>
+			</uni-forms-item>
+			<uni-forms-item label="授课方式:" name="mode" required>
+				<uni-data-checkbox v-model="baseFormData.mode" :localdata="modes" />
+			</uni-forms-item>
+			<uni-forms-item label="授课时间" required>
+			</uni-forms-item>
+			<view class="tr-container">
+				<view class="tr_1">
+					<text class="th_0" decode="true">&ensp;&ensp;&ensp;&ensp;</text>
+					<text class="th_1">周一</text>
+					<text class="th_1">周二</text>
+					<text class="th_1">周三</text>
+					<text class="th_1">周四</text>
+					<text class="th_1">周五</text>
+					<text class="th_1">周六</text>
+					<text class="th_1">周日</text>
+				</view>
+				<view class="tr_2">
+					<checkbox-group @change="chechboxChangeAM">
+						<view class="th2_0">上午</view>
+						<label v-for="item in timeAM" :key="item.value">
+							<checkbox class="th2_1" :value="item.value" :checked="item.checked"></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+				<view class="tr_2">
+					<checkbox-group @change="chechboxChangePM">
+						<view class="th2_0">下午</view>
+						<label v-for="item in timePM" :key="item.value">
+						<checkbox class="th2_1" :value="item.value" :checked="item.checked"></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+				<view class="tr_2">
+					<checkbox-group @change="chechboxChangeEvening">
+						<view class="th2_0">晚上</view>
+						<label v-for="item in timeEvening" :key="item.value">
+						<checkbox class="th2_1" :value="item.value" :checked="item.checked"></checkbox>
+						</label>
+					</checkbox-group>
+				</view>
+			</view>
+			<uni-forms-item label="教龄:" name="teachAge" required>
+				<uni-number-box v-model="baseFormData.teachAge" :min="1" ></uni-number-box>
+			</uni-forms-item>
+			<uni-forms-item label="老师位置:" name="location" required>
+				<uni-easyinput type="text" v-model="baseFormData.location" @focus="getLocation" maxlength="250" trim="both" />
+			</uni-forms-item>
+			<uni-forms-item label="成功经验:" name="experience" required>
+				<uni-easyinput type="textarea" v-model="baseFormData.experience" maxlength="250" trim="both" />
+			</uni-forms-item>
+			<uni-forms-item label="自我介绍:" name="introduce" required>
+				<uni-easyinput type="textarea" v-model="baseFormData.introduce" maxlength="250" trim="both" />
+			</uni-forms-item>
+		</uni-forms>
+		<view class="button-group">
+			<button class="publishBtn" type="primary" size="default" @click="submit('baseForm')">发布课程</button>
+		</view>
+		
+		<uni-popup ref="alertDialog" type="dialog">
+			<uni-popup-dialog type="info" :confirmText="confirmText" title="温馨提示" :content="authentication" @close="dialogClose" @confirm="dialogConfirm"></uni-popup-dialog>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import { mapState, mapMutations } from 'vuex'
+	
+	export default {
+		computed: {
+			...mapState('m_user', ['authentication'])
+		},
+		data() {
+			return {
+				courseWeekday: [],
+				introduce: '',
+				courseAM: [],
+				coursePM: [],
+				courseEV: [],
+				confirmText: '',
+				// 表单数据
+				baseFormData: {
+					subject: '',
+					mode: [],
+					teachTime: [],
+					teachAge: 1,
+					location: '',
+					experience: '',
+					introduce: '',
+					subjectBig: ''
+				},
+				// 选择课程
+				courseTree: [{
+						text: '一年级',
+						value: '1-0',
+						children: [{
+								text: '1.1班',
+								value: '1'
+							}
+						]
+					}
+				],
+				// 单选授课方式数据源
+				modes: [{
+					text: '老师上门',
+					value: '老师上门'
+				}, {
+					text: '学员上门',
+					value: '学员上门'
+				}, {
+					text: '线上辅导',
+					value: '线上辅导'
+				}],
+				// 上课时间
+				// 上午
+				timeAM: [{
+						value: 'A1',
+						name: '1',
+						checked: false
+						
+					},
+					{
+						name: '2',
+						value: 'A2',
+						checked: false
+					},
+					{
+						name: '3',
+						value: 'A3',
+						checked: false
+					},
+					{
+						name: '4',
+						value: 'A4',
+						checked: false
+					},
+					{
+						name: '5',
+						value: 'A5',
+						checked: false
+					},
+					{
+						name: '6',
+						value: 'A6',
+						checked: false
+					},
+					{
+						name: '7',
+						value: 'A7',
+						checked: false
+					}
+				],
+				// 下午
+				timePM: [{
+						value: 'P1',
+						name: '1',
+						checked: false
+					},
+					{
+						name: '2',
+						value: 'P2',
+						checked: false
+					},
+					{
+						name: '3',
+						value: 'P3',
+						checked: false
+					},
+					{
+						name: '4',
+						value: 'P4',
+						checked: false
+					},
+					{
+						name: '5',
+						value: 'P5',
+						checked: false
+					},
+					{
+						name: '6',
+						value: 'P6',
+						checked: false
+					},
+					{
+						name: '7',
+						value: 'P7',
+						checked: false
+					}
+				],
+				// 晚上
+				timeEvening: [{
+						name: '1',
+						value: 'E1',
+						checked: false
+					},
+					{
+						name: '2',
+						value: 'E2',
+						checked: false
+					},
+					{
+						name: '3',
+						value: 'E3',
+						checked: false
+					},
+					{
+						name: '4',
+						value: 'E4',
+						checked: false
+					},
+					{
+						name: '5',
+						value: 'E5',
+						checked: false
+					},
+					{
+						name: '6',
+						value: 'E6',
+						checked: false
+					},
+					{
+						name: '7',
+						value: 'E7',
+						checked: false
+					}
+				],
+				rules: {
+					subject: {
+						rules: [{
+							required: true,
+							errorMessage: '授课科目不能为空',
+						}]
+					},
+					mode: {
+						rules: [{
+							required: true,
+							errorMessage: '授课方式不能为空',
+						}]
+					},
+					location: {
+						rules: [{
+							required: true,
+							errorMessage: '地理位置不能为空',
+						}]
+					},
+					introduce: {
+						rules: [{
+							required: true,
+							errorMessage: '自我介绍不能为空',
+						}],
+					},
+					teachTime: {
+						rules: [{
+							required: true,
+							errorMessage: '授课时间不能为空',
+						}]
+					},
+					experience: {
+						rules: [{
+							required: true,
+							errorMessage: '成功经验不能为空',
+						}]
+					},
+				}
+			};
+		},
+		onLoad(option) {
+			this.getPriceAndTree(),
+			this.getPersonAuthorize()
+			if (option.item !== undefined) {
+				let item = JSON.parse(decodeURIComponent(option.item))
+				this.formatCourse(item)
+			}
+		},
+		methods: {
+			...mapMutations('m_user', ['updateAuthentication']),
+			// 格式化传递过来的course信息
+			formatCourse(item) {
+				this.baseFormData.mode = item.mode
+				this.baseFormData.teachAge = item.teachAge
+				this.baseFormData.location = item.location
+				this.baseFormData.locationAl = item.locationAl
+				this.baseFormData.experience = item.experience
+				this.baseFormData.introduce = item.introduce
+				this.courseWeekday = item.teachTime.split(",")
+				this.baseFormData.teachTime = this.courseWeekday
+				
+				for (let i = 0; i < this.courseWeekday.length; i++) {
+					for (let x = 0; x < this.timeAM.length; x++) {
+						if (this.courseWeekday[i] == this.timeAM[x].value) {
+							this.timeAM[x].checked = true
+							this.courseAM.push(this.courseWeekday[i])
+						}
+					}
+					for (let y = 0; y < this.timePM.length; y++) {
+						if (this.courseWeekday[i] == this.timePM[y].value) {
+							this.timePM[y].checked = true
+							this.coursePM.push(this.courseWeekday[i])
+						}
+					}
+					for (let z = 0; z < this.timeEvening.length; z++) {
+						if (this.courseWeekday[i] == this.timeEvening[z].value) {
+							this.timeEvening[z].checked = true
+							this.courseEV.push(this.courseWeekday[i])
+						}
+					}
+				}
+				if (this.courseAM.length > 0) {
+					this.courseAM.push(this.courseAM.join().split(','))
+				}
+				if (this.coursePM.length > 0) {
+					this.coursePM.push(this.coursePM.join().split(','))
+				}
+				if (this.courseEV.length > 0) {
+					this.courseEV.push(this.courseEV.join().split(','))
+				}
+			},
+			// 获取认证信息
+			async getPersonAuthorize() {
+				const { data: result } = await uni.$http.get('/education/teacher-certifications/findVerifyStatus')
+				const auth = result.message
+				this.updateAuthentication(auth)
+				if (auth === '审核中') {
+					this.confirmText = '请耐心等待'
+					this.$refs.alertDialog.open()
+				} else if (auth !== '已通过') {
+					this.confirmText = '去认证'
+					this.$refs.alertDialog.open()
+				}
+			},
+
+			// 取消按钮
+			dialogClose() {
+				this.$refs.alertDialog.close()
+				uni.navigateBack()
+			},
+			// 确定按钮
+			dialogConfirm() {
+				this.$refs.alertDialog.close()
+				if (this.authentication === '审核中') {
+					uni.navigateBack()
+				} else if (this.authentication !== '已通过'){
+					uni.navigateTo({
+						url: '/subpkg/teacher/authentication/teacher_authentication'
+					})	
+				}
+			},
+			// 获取老师地理位置
+			getLocation() {
+				wx.chooseLocation({
+					success: res => {
+						if (res.errMsg === 'chooseLocation:ok') {
+							this.baseFormData.location = res.address + res.name
+							this.baseFormData.locationAl = res.latitude + ',' + res.longitude
+						} 
+					}
+				})
+			},
+			// 树形结构的课程和价格表
+			async getPriceAndTree() {
+				const {
+					data: result
+				} = await uni.$http.get('/education/course-price/treeAndPrice')
+				this.courseTree = result.data.treeCourse
+			},
+			// 上午复选框
+			chechboxChangeAM(e) {
+				this.courseAM.push(e.detail.value)
+			},
+			// 下午复选框
+			chechboxChangePM(e) {
+				this.coursePM.push(e.detail.value)
+			},
+			// 晚上复选框
+			chechboxChangeEvening(e) {
+				this.courseEV.push(e.detail.value)
+			},
+			submit(ref) {
+				this.baseFormData.teachTime = []
+				if (this.courseAM.length === 0 && this.coursePM.length === 0 && this.courseEV.length === 0 ) return uni.$showMsg('请选择授课时间!')
+				if (this.courseAM[this.courseAM.length - 1] == '' && this.coursePM.length === 0 && this.courseEV.length === 0 ) return uni.$showMsg('请选择授课时间!')
+				if (this.courseAM.length === 0 && this.coursePM[this.coursePM.length - 1] == '' && this.courseEV.length === 0 ) return uni.$showMsg('请选择授课时间!')
+				if (this.courseAM.length === 0 && this.coursePM.length === 0 && this.courseEV[this.courseEV.length - 1] == '' ) return uni.$showMsg('请选择授课时间!')
+				if (this.courseAM[this.courseAM.length - 1] == '' && this.coursePM[this.coursePM.length - 1] == '' && this.courseEV.length === 0 ) return uni.$showMsg('请选择授课时间!')
+				if (this.courseAM[this.courseAM.length - 1] == '' && this.coursePM.length === 0 && this.courseEV[this.courseEV.length - 1] == '' ) return uni.$showMsg('请选择授课时间!')
+				if (this.courseAM.length === 0 && this.coursePM[this.coursePM.length - 1] == '' && this.courseEV[this.courseEV.length - 1] == '' ) return uni.$showMsg('请选择授课时间!')
+				if (this.courseAM[this.courseAM.length - 1] == '' && this.coursePM[this.coursePM.length - 1] == '' && this.courseEV[this.courseEV.length - 1] == '' ) return uni.$showMsg('请选择授课时间!')
+				
+				if (this.courseAM.length > 0) {
+					this.baseFormData.teachTime.push(this.courseAM[this.courseAM.length - 1])
+				}
+				if (this.coursePM.length > 0) {
+					this.baseFormData.teachTime.push(this.coursePM[this.coursePM.length - 1])
+				}
+				if (this.courseEV.length > 0) {
+					this.baseFormData.teachTime.push(this.courseEV[this.courseEV.length - 1])
+				}
+				// 上课时间
+				this.baseFormData.teachTime = this.baseFormData.teachTime.join()
+				// 末尾为,
+				if (this.baseFormData.teachTime.slice(-1) === ',') {
+					this.baseFormData.teachTime = this.baseFormData.teachTime.substring(0, this.baseFormData.teachTime.length - 1)
+				}
+				// 开始为,
+				if (this.baseFormData.teachTime.slice(0,1) === ',') {
+					let temp = this.baseFormData.teachTime.substring(1, this.baseFormData.teachTime.length )
+					this.baseFormData.teachTime = temp
+				}
+				
+				if (this.baseFormData.subject === '') {
+					return uni.$showMsg('请选择授课科目')
+				} 
+				
+				// 授课科目
+				for (let x = 0; x < this.courseTree.length; x++) {
+					for (let y = 0; y < this.courseTree[x].children.length; y++) {
+						if (this.courseTree[x].children[y].value === this.baseFormData.subject) {
+							this.baseFormData.subjectBig = this.courseTree[x].value + '/' + this.baseFormData.subject
+						}
+					}
+				}
+
+				if (this.baseFormData.location === '') return uni.$showMsg('请输入位置!')
+				
+				this.$refs[ref].validate().then(res => {
+					uni.showLoading({
+						title: '数据加载中'
+					})
+					uni.request({
+						url: `${uni.$http.baseUrl}/education/teacher-courses/publishCourse`,
+						data: JSON.stringify(this.baseFormData),
+						header: {
+							token: uni.getStorageSync('token')
+						},
+						method: 'POST',
+						success: res => {
+							uni.hideLoading()
+							uni.$showMsg(res.data.message)
+							setTimeout(() => {
+								uni.navigateBack({
+									delta: 2
+								})
+							}, 1000)
+						}
+					})
+				}).catch(err =>{
+					return 
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		//background-color: #D4F5E9;
+	}
+</style>
+
+<style lang="scss" scoped>
+	.course-add-container{
+		width: 96%;
+		padding-left: 20rpx;
+	}
+	
+	.tr-container{
+	    display: flex;
+	    position: relative;
+	    width: 96%;
+	    flex-direction: column;
+	    font-size: 26rpx;
+	    /* border: 1rpx solid gray; */
+	    margin: -10px 20rpx;
+		margin-bottom: 20px;
+	}
+	
+	.tr_1 {
+	    display: flex;
+	    position: relative;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	}
+	.tr_2{
+	    display: block;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	}
+	
+	.th_0,
+	.th_1,
+	.th_2,
+	.th2_0,
+	.th2_1,
+	.th2_2{
+	    width: 12%;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	    border-right: 1rpx solid gray;
+	    border-bottom: 1rpx solid gray;
+	    text-align: center;
+	}
+	
+	.th_0,
+	.th_1,
+	.th_2{
+	    border-top: 1rpx solid gray;
+	}
+	
+	.th_0,
+	.th2_0{
+	    border-left: 1rpx solid gray;
+	}
+	
+	.th2_0{
+	    float: left;
+	    width: 12%;
+	    height: 80rpx;
+	    line-height: 80rpx;
+	    text-align: center;
+	    /* background-color: greenyellow; */
+	}
+	
+	.button-group{
+		padding-left: -20rpx;
+		margin-bottom: 40rpx;
+	}
+	
+	// 发布课程按钮
+	.publishBtn{
+		width: 260rpx;
+		border-radius: 50rpx;
+		background-color: #35b882;
+	}
+
+</style>

+ 150 - 0
education_uni/subpkg/teacher/course/teacher_course_all_detail.vue

@@ -0,0 +1,150 @@
+<template>
+	<view>
+		<my-coursedetail v-if="showDetail" :item="course" :location="location" :marker="marker" :timeAM="timeAM" :timePM="timePM" :timeEvening="timeEvening" buttonMessage="邀请" :collect="collect" :isShowCollect="true" @collecting="collecting" @publishButton="invite"></my-coursedetail>
+
+		<my-invite :isShowInvite="isShowInvite" :item11="myNeeds" @cancelChosed="cancelChosed" @commitChosed="commitChosed" @clickRadio="clickRadio"></my-invite>
+	</view>
+</template>
+
+<script>
+	import {mapState} from 'vuex'
+	import formTime from '@/mixins/form-time.js'
+	export default {
+		mixins: [formTime],
+		computed: {
+			...mapState('m_user', ['userinfo'])
+		},
+		data() {
+			return {
+				showDetail: false,
+				isShowInvite: false,
+				initeNeeds: '',
+				myNeeds: [],
+				collect: false,
+				course: {},
+				location: [],
+				marker: [{
+					id: 1,
+					joinCluster:true,
+					latitude: 0,
+					longitude: 0,
+					width: 40,
+					height: 40,
+					iconPath: '/static/location.png',
+				}],
+			};
+		},
+		onLoad(option) {
+			if (option.item !== undefined) {
+				this.course = JSON.parse(decodeURIComponent(option.item))
+				this.getCourseDetailById(this.course.courseId)
+			}
+			if (option.courseId !== undefined) {
+				this.getPersonCourseDetailById(option.courseId)
+			}
+			this.getIsCollection()
+		},
+		methods:{
+			async getPersonCourseDetailById(id) {
+				const {data: result} = await uni.$http.get('/education/teacher-courses/getPersonCourseDetailById', {courseId: id})
+				this.course = result.data.one
+				if (this.course.viewedCount === null) {
+					this.course.viewedCount = 0
+				}
+				this.formatForm()
+			},
+			// 获取课程详情
+			async getCourseDetailById(id) {
+				const {data: result} = await uni.$http.get('/education/teacher-courses/getCourseDetailById', {courseId: id})
+				const item = result.data.one
+				this.course = Object.assign(this.course, item)
+				if (this.course.viewedCount === null) {
+					this.course.viewedCount = 0
+				}
+				this.formatForm()
+			},
+			// 上课表格格式化
+			formatForm() {
+				this.location = this.course.locationAl.split(",")
+				this.marker[0].latitude = Number(this.location[0])
+				this.marker[0].longitude = Number(this.location[1])
+				this.courseWeekday = this.course.teachTime.split(",")
+				this.parseCourseWeekday()
+				this.showDetail = true
+			},
+			// 查看是否收藏过
+			async getIsCollection() {
+				const { data: result } = await uni.$http.get('/education/my-favorite-courses/findPersonCollect')
+				const list = result.data.requires
+				if (list !== null) {
+					for (let i = 0; i < list.length; i++) {
+						if (this.course.courseId === list[i]) {
+							this.collect = true
+						}
+					}
+				}
+			},
+			// 收藏、取消收藏
+			async collecting() {
+				const queryObj = {
+					courseId: this.course.courseId
+				}
+				// 没有收藏过
+				if (!this.collect) {
+					const { data: result1 } = await uni.$http.get('/education/my-favorite-courses/collect', queryObj)
+					if (result1.message === '收藏成功') {
+						return this.collect = true
+					} 
+					if (result1.message === '收藏失败') {
+						return uni.$showMsg('收藏失败')
+					}
+				}
+				// 收藏过
+				if (this.collect) {
+					const { data: result } = await uni.$http.get('/education/my-favorite-courses/cancelCollect', queryObj)
+					if (result.message === '取消收藏成功') {
+						return this.collect = false
+					} else if (result.message === '取消收藏失败') {
+						return uni.$showMsg('取消收藏失败')
+					}
+				}
+			},
+			async showMyStuNeeds() {
+				const { data: result } = await uni.$http.get('/education/student-requirements/queryPersonSomeInfo')
+				this.myNeeds = result.data.list
+			},
+			invite() {
+				this.isShowInvite = true
+				this.showMyStuNeeds()
+			},
+			cancelChosed() {
+				this.isShowInvite = false
+			},
+			async commitChosed() {
+				if (this.initeNeeds === '') return uni.$showMsg('请选择邀请的课程')
+				this.initeNeeds.toUid = this.course.uid
+				this.initeNeeds.courseId = this.course.courseId
+				this.initeNeeds.fromUname = this.initeNeeds.name
+				this.initeNeeds.toUname = this.course.name
+				
+				const {data: result} = await uni.$http.post('/education/invite-info/sendTeacherInvite', this.initeNeeds)
+				uni.$showMsg(result.message)
+				this.isShowInvite = false
+			},
+			clickRadio(item) {
+				this.initeNeeds = item
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+</style>

+ 180 - 0
education_uni/subpkg/teacher/course/teacher_course_my_collect.vue

@@ -0,0 +1,180 @@
+<template>
+	<view>
+		<view v-for="(item, index) in teacherList" :key="index">
+			<view class="publicItem" @click="toTeachDetail(item)">
+				<view class="itemFather">
+					<image class="teachImg" :src="item.profilePhoto"></image>
+					<view class="teachTitle">{{item.name}}教员</view>
+					<view class="publicSex">{{item.sex}}</view>
+					<view class="teachCollege">{{item.school}}</view>
+					<view class="teachEdu">{{item.education}}</view>
+					<view class="teachDistance">
+						<uni-icons type="location" color="#3ed598" ></uni-icons>
+						<text>{{item.kil}}</text>km</view>
+					<view class="teachSubject">{{item.subject}}</view>
+					<view class="teachYears">教龄 {{item.teachAge}}</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { mapState } from 'vuex'
+	import computeDistance from '@/mixins/compute-distance.js'
+	
+	export default {
+		mixins: [computeDistance],
+		computed: {
+			...mapState('m_user', ['location'])
+		},
+		data() {
+			return {
+				// 老师列表
+				teacherList: []
+			}
+		},
+		onShow() {
+			this.getTeacherList()
+		},
+		methods: {
+			// 老师细节
+			toTeachDetail(item) {
+				uni.navigateTo({
+					url: '/subpkg/teacher/course/teacher_course_all_detail?item=' + encodeURIComponent(JSON.stringify(item))
+				})
+			},
+			// 获取老师列表
+			async getTeacherList() {
+				const { data: result } = await uni.$http.get('/education/my-favorite-courses/findPersonCollection')
+				for (let i = 0; i < result.data.course.length; i++) {
+					let arr = result.data.course[i].locationAl.split(",")
+					let kil = this.space(arr[0], arr[1], this.location.latitude, this.location.longitude)
+					result.data.course[i].kil = kil
+					result.data.course[i].name = result.data.course[i].name.slice(0,1)
+				}
+				this.teacherList = result.data.course
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #D4F5E9;
+	}
+</style>
+
+<style scoped lang="scss">
+	.itemFather{
+		position: relative;
+		display: flex;
+		padding: 10rpx;
+		height: 170rpx;
+		align-items: center;
+	}
+		
+	/* 设置单个教员背景 */
+	.publicItem{
+		margin-left: 20rpx;
+		margin-right: 20rpx;
+		margin-top: 10rpx ;
+		margin-bottom: 10rpx ;
+		// border: 0rpx solid gray;
+		padding: 10rpx 20rpx;
+		border-radius: 30rpx;
+		background-color: #ffffff;
+	}
+	
+	.teachTitle{
+		font-size: 14px;
+		position: absolute;
+		left: 200rpx;
+		top: 10rpx;
+		font-weight: bold;
+		color: #6d6d6d;
+	}
+	
+	/* 教员头像 */
+	.teachImg{
+		width: 25%;
+		height: 95%;
+		border-radius: 20%;
+	}
+	
+	/* 距离 */
+	.teachDistance{
+		position: absolute;
+		left: 330rpx;
+		top: 10rpx;
+		font-weight: bold;
+		color: #3ed598;
+		font-size: 12px;
+		
+	}
+	
+	/* teachsex */
+	.publicSex{
+		position: absolute;
+		right: 10rpx;
+		top: 5rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 10rpx;
+		border-radius: 50%;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+	/* teachEdu */
+	.teachEdu{
+		position: absolute;
+		right: 10rpx;
+		top: 60rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 10rpx;
+		border-radius: 30rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+	/* teach课程 */
+	.teachSubject{
+		position: absolute;
+		left: 200rpx;
+		top: 115rpx;
+		// border: 0rpx solid gray;
+		padding: 5rpx 12rpx;
+		border-radius: 30rpx;
+		background-color: #3ed598;
+		color: #ffffff;
+		font-size: 12px;
+	}
+	
+	/* teach课程 */
+	.teachYears{
+		position: absolute;
+		right: 10rpx;
+		top: 115rpx;
+		border: 2px solid  #3ed598;
+		padding: 5rpx 20rpx;
+		border-radius: 30rpx;
+		color: #3ed598;
+		font-size: 12px;
+		font-weight: bold;
+	}
+	
+	.teachCollege{
+		border: 2px solid #3ed598;
+		border-radius: 30rpx;
+		padding: 0rpx 10rpx;
+		font-size: 12px;
+		position: absolute;
+		left: 200rpx;
+		top: 60rpx;
+		color: #3ed598;
+		
+	}
+</style>
+

+ 67 - 0
education_uni/subpkg/teacher/course/teacher_course_my_detail.vue

@@ -0,0 +1,67 @@
+<template>
+	<view>
+		<my-coursedetail v-if="showDetail" :item="course" :location="location" :marker="marker" :timeAM="timeAM" :timePM="timePM" :timeEvening="timeEvening" buttonMessage="以此为模板新发布" :isShowCollect="false" :isShowPrivate="true" @publishButton="publishButton"></my-coursedetail>
+	</view>
+</template>
+
+<script>	
+	import formTime from '@/mixins/form-time.js'
+	export default {
+		mixins: [formTime],
+		data() {
+			return {
+				showDetail: false,
+				course: {},
+				location: [],
+				marker: [{
+					id: 1,
+					joinCluster:true,
+					latitude: 0,
+					longitude: 0,
+					width: 40,
+					height: 40,
+					iconPath: '/static/location.png',
+				}],
+			};
+		},
+		onLoad(option) {			
+			if (option.courseId !== undefined) {
+				const courseId = decodeURIComponent(option.courseId)
+				this.getCourseDetailById(courseId)
+			}
+		},
+		methods:{
+			// 获取课程详情
+			async getCourseDetailById(id) {
+				const {data: result} = await uni.$http.get('/education/teacher-courses/getPersonCourseDetailById', {courseId: id})
+				this.course = result.data.one
+				this.formatForm()
+			},
+			// 上课表格格式化
+			formatForm() {
+				this.location = this.course.locationAl.split(",")
+				this.marker[0].latitude = Number(this.location[0])
+				this.marker[0].longitude = Number(this.location[1])
+				this.courseWeekday = this.course.teachTime.split(",")
+				this.parseCourseWeekday()
+				this.showDetail = true
+			},
+			publishButton() {
+				uni.navigateTo({
+					url:'/subpkg/teacher/course/teacher_course_add?item=' + encodeURIComponent(JSON.stringify(this.course))
+				})
+			}
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style lang="scss" scoped>
+</style>

+ 139 - 0
education_uni/subpkg/teacher/course/teacher_course_my_publish.vue

@@ -0,0 +1,139 @@
+<template>
+	<view>
+		<view v-for="(item, index) in requirement" :key="index">
+			<view class="requires" @click="requireDetail(item.courseId)">
+				<uni-row class="demo-uni-row">
+					<uni-col offset="1">
+						<view class="requires-col1">课程号:{{item.courseId}}</view>
+					</uni-col>
+				</uni-row>
+				<uni-row class="demo-uni-row">
+					<uni-col offset="1" :span="16">
+						<view class="requires-col2">科目:{{item.subject}}</view>
+					</uni-col>
+					<uni-col :span="7">
+						<view>
+							<button @click.stop="open(item)" size="mini" :type="item.buttonType">{{item.display}}</button>
+						</view>
+					</uni-col>
+				</uni-row>
+				<view class="requires-col3">
+					<uni-row class="demo-uni-row">
+						<uni-col :span="4" offset="12">
+							<view style="color: red;">{{item.verifyStatus}}</view>
+						</uni-col>
+						<uni-col :span="4" >
+							<view style="color: red;">{{item.deal}}</view>
+						</uni-col>
+						<uni-col :span="4" >
+							<view style="color: red;">{{item.locked}}</view>
+						</uni-col>
+					</uni-row>
+				</view>
+			</view>
+		</view>
+		
+		<uni-popup ref="popup" type="message">
+			<uni-popup-message :type="popupType" :message="showMessage" :duration="1000"></uni-popup-message>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				requirement: [],
+				showMessage: '上架成功',
+				popupType: 'success',
+				publishCount: 0
+			}
+		},
+		onShow() {
+			this.getPublishCounts()
+		},
+		methods: {
+			// 查询个人上架了多少课程
+			async getPublishCounts() {
+				const { data: result } = await uni.$http.get('/education/teacher-courses/showPersonCourse')
+				this.publishCount = result.data.publishCounts
+				let courses = []
+				courses = result.data.list
+				
+				for (let i = 0; i < courses.length; i++) {
+					if (courses[i].display === '上架') {
+						courses[i].display = '下架'
+						courses[i].buttonType = 'warn'
+					} else {
+						courses[i].display = '上架'
+						courses[i].buttonType = 'primary'
+					}
+				}
+				this.requirement = courses
+			},
+			async open(item) {
+				if (item.display === '上架') {
+					if (item.verifyStatus !== '已通过') return uni.$showMsg('审核通过才能上架')
+					if (item.deal === '已成交') return uni.$showMsg('已成交的课程不能上架')
+					if (item.locked === '已锁') return uni.$showMsg('正在锁定的需求不能上架')
+					if (this.publishCount >= 4) return uni.$showMsg('最多上架4个课程')
+				}
+				const queryObj = {
+					display: item.display,
+					courseId: item.courseId
+				}
+				const { data: result } = await uni.$http.get('/education/teacher-courses/updatePersonDisplay', queryObj)
+				if (result.code === 20000) {
+					if (item.display === '上架') {
+						item.display = '下架'
+						this.showMessage = '上架成功'
+						this.popupType = 'success'
+						item.buttonType = 'warn'
+						this.publishCount += 1
+						
+					} else if (item.display === '下架') {
+						item.display = '上架'
+						this.showMessage = '下架成功'
+						this.popupType = 'error'
+						item.buttonType = 'primary'
+						this.publishCount -= 1
+					}
+					this.$refs.popup.open('top')
+				}
+			},
+			requireDetail(id) {
+				uni.navigateTo({
+					url: '/subpkg/teacher/course/teacher_course_my_detail?courseId=' + encodeURIComponent(id)
+				})
+			},
+		}
+	}
+</script>
+
+<!-- 设置页面背景 -->
+<style lang="scss">
+	page{
+		height: 100%;
+		// background-color: #FFF;
+	}
+</style>
+
+<style scoped lang="scss">
+	.requires {
+		background-color: #FFF2CC;
+		border: 1px solid #41719C;
+		
+		.requires-col1 {
+			margin-top: 15rpx;
+		}
+		
+		.requires-col2 {
+			margin: 15rpx 0;
+		}
+		
+		.requires-col3 {
+			padding-bottom: 15rpx;
+		}
+	}
+
+</style>

+ 1 - 0
education_uni/uni.scss

@@ -0,0 +1 @@
+@import '@/uni_modules/uni-scss/variables.scss';