puyao 16 uur geleden
bovenliggende
commit
7ead4b2c2b
49 gewijzigde bestanden met toevoegingen van 2124 en 133 verwijderingen
  1. 32 0
      App.vue
  2. 4 1
      api/courseAuto.js
  3. 3 0
      api/courseLook.js
  4. 5 1
      api/manageCompany.js
  5. 21 1
      common/request.js
  6. 2 1
      components/likeProduct.vue
  7. 2 1
      components/tuiProduct.vue
  8. 163 0
      components/yk-screenRecord/yk-screenRecord.vue
  9. 2 2
      manifest.json
  10. 2 2
      pages.json
  11. 55 16
      pages/auth/login.vue
  12. 1 1
      pages/common/launch.vue
  13. 8 6
      pages/home/index.vue
  14. 7 4
      pages/shopping/cart.vue
  15. 4 2
      pages/shopping/confirmOrder.vue
  16. 6 1
      pages/shopping/payOrder.vue
  17. 9 1
      pages/shopping/paymentOrder.vue
  18. 1 1
      pages/shopping/productDetails.vue
  19. 2 2
      pages/user/index.vue
  20. 16 9
      pages_company/order/confirmCompanyOrder.vue
  21. 19 2
      pages_company/order/confirmOrder.vue
  22. 1 1
      pages_company/order/productDetails.vue
  23. 4 3
      pages_company/order/productList.vue
  24. 5 0
      pages_company/storeOrder.vue
  25. 5 0
      pages_company/storeOrderDetail.vue
  26. 5 0
      pages_company/storeProductPackage.vue
  27. 173 2
      pages_company/storeProductPackageDetails.vue
  28. 308 0
      pages_company/voice.vue
  29. 490 0
      pages_company/voiceItem.vue
  30. 248 0
      pages_company/voiceList.vue
  31. 3 1
      pages_company/wechatcode.vue
  32. 17 9
      pages_course/becomeVIP.vue
  33. 65 0
      pages_course/components/courseExpiration.vue
  34. 113 0
      pages_course/components/yk-screenRecord/yk-screenRecord.vue
  35. 1 1
      pages_course/reward.vue
  36. 106 16
      pages_course/video.vue
  37. 76 20
      pages_course/videovip.vue
  38. 2 0
      pages_course/webview.vue
  39. 1 1
      pages_doctor/paymentOrder.vue
  40. 68 3
      pages_manage/components/memberIndex.vue
  41. 1 1
      pages_manage/login.vue
  42. 15 4
      pages_shopping/shopping/confirmPackageOrder.vue
  43. 4 3
      pages_shopping/shopping/productList.vue
  44. 6 1
      pages_user/user/otherPaymentOrder.vue
  45. 6 1
      pages_user/user/otherPaymentOrderRemain.vue
  46. 17 6
      pages_user/user/pay.vue
  47. 6 2
      pages_user/user/paymentOrderRemain.vue
  48. BIN
      static/course_expiration_img.png
  49. 14 4
      store/index.js

+ 32 - 0
App.vue

@@ -12,6 +12,7 @@
 			
 		},
 		onLaunch: function() {
+			this.checkUpdate()
 			// uni.hideTabBar({ animation: true })
 			// uni.$TUIKit = TIM.create({
 			// 	SDKAppID: 1400693126
@@ -89,6 +90,37 @@
 		},
 		 
 		methods: {
+			checkUpdate() {
+				const updateManager = uni.getUpdateManager();
+				updateManager.onCheckForUpdate(function(res) {
+					// 请求完新版本信息的回调
+					console.log('是否有新版本:', res.hasUpdate);
+				});
+				updateManager.onUpdateReady(function() {
+					uni.showModal({
+						title: '更新提示',
+						content: '新版本已经准备好,是否重启小程序?',
+						confirmText: '立即重启',
+						confirmColor: '#2179f5',
+						showCancel: false,
+						success(res) {
+							if (res.confirm) {
+								// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
+								updateManager.applyUpdate();
+							}
+						}
+					});
+				});
+			
+				updateManager.onUpdateFailed(function() {
+					// 新的版本下载失败
+					uni.showModal({
+						title: '更新提示',
+						content: '新版本下载失败,请检查网络后重试。',
+						showCancel: false
+					});
+				});
+			},
 			// TODO:
 			resetLoginData() {
 				// this.globalData.expiresIn = '';

+ 4 - 1
api/courseAuto.js

@@ -91,4 +91,7 @@ export function getConcept() {
  }
  export function complaintRecord(data) {
  	return request('/course_auto/app/user/complaint/record', data, 'POST','application/json;charset=UTF-8');
- }
+ }
+ export function userLoginIp(data) {
+  	 return request('/course_auto/app/wx/userLoginIp?userIp='+data.userIp,data,'PUT','');
+  }

+ 3 - 0
api/courseLook.js

@@ -66,6 +66,9 @@ export function getRealLink(data) {
  export function handleFsUserWx(data) {
  	 return request('/course_uniapp/app/wx/h5/mp/handleFsUserWx',data,'POST','application/json;charset=UTF-8');
  }
+ export function userLoginIp(data) {
+  	 return request('/course_uniapp/app/wx/userLoginIp?userIp='+data.userIp,data,'PUT','');
+  }
  //h5授权登录
  export function H5logoinApp(data,type) {
 	 if(type&&type==1) {

+ 5 - 1
api/manageCompany.js

@@ -249,4 +249,8 @@ export function getprojectChange(data) {
 //生成小程序链接
 export function copyuniLink(data) {
 	return request('/companyapp/app/fs/course/getGotoWxAppLink', data, 'GET', 'application/json;charset=UTF-8');
-}
+}
+  //获取对应的项目编码
+  export function getlinkCode(data) {
+  	return request('/companyapp/app/fs/course/getProjectCode', data, 'GET', 'application/json;charset=UTF-8');
+  }

+ 21 - 1
common/request.js

@@ -1,12 +1,15 @@
 // uni-app请求封装
 import {TOKEN_KEYAuto} from '@/utils/courseTool.js'
+import store from '@/store/index.js'
 export default class Request {
 	http(router, data = {}, method,contentType) {
 		let that = this;
 		//let path = 'http://localhost:7014';
 		// let path = 'https://test.userapp.store.cdwjyyh.com';
-		// let path = 'https://user.test.ylrztop.com/api';
+		// let path = 'http://tf9cc676.natappfree.cc/store';
 		let path = 'https://userapp.schstyl.cn/store'//鸿森堂
+		// let path = 'http://m98d247b.natappfree.cc/store'//鸿森堂(本地)
+		
 		let type = 0
 		uni.setStorageSync('requestPath',path)
 		// uni.showLoading({
@@ -55,6 +58,23 @@ export default class Request {
 				data: data,
 				method: method,
 				success: (res) => {
+					if(type !==0&&(res.data.code == 401 || res.data.code == 4001||res.data.code == 4004)) {
+						store.commit('setCoureLogin', 2);
+						uni.removeStorageSync("userinfos")
+						// uni.removeStorageSync('userInfo');
+						uni.removeStorageSync('TOKEN_WEXIN');
+						if(type==2) {
+							uni.removeStorageSync(TOKEN_KEYAuto)
+						}
+						if(type==1) {
+							uni.removeStorageSync('ManageToken');
+							uni.navigateTo({
+								url:'/pages_manage/login'
+							})
+						}
+						resolve({ code: 401, data: null });
+						return
+					}
 					//收到开发者服务器成功返回的回调函数
 					if(res.data.code==401){//没有权限直接退出到登录界面
 						let pages = getCurrentPages();

+ 2 - 1
components/likeProduct.vue

@@ -37,7 +37,8 @@
 		return {
 			page:{
 				page: 1,
-				pageSize: 10
+				pageSize: 10,
+				appId:wx.getAccountInfoSync().miniProgram.appId,
 			},
 			total:0,
 			list:[],

+ 2 - 1
components/tuiProduct.vue

@@ -37,7 +37,8 @@
 		return {
 			page:{
 				page: 1,
-				pageSize: 10
+				pageSize: 10,
+				appId:wx.getAccountInfoSync().miniProgram.appId,
 			},
 			total:0,
 			list:[],

+ 163 - 0
components/yk-screenRecord/yk-screenRecord.vue

@@ -0,0 +1,163 @@
+<template>
+	<view class="zzc_mol" v-if="isRecording"></view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				isRecording: false
+			}
+		},
+		created() {
+			this.screenInit();
+		},
+		onUnload() {
+			this.AllowScreenshots()
+		},
+		beforeDestroy() {
+			this.AllowScreenshots()
+		},
+		methods: {
+			screenInit() {
+				let _this = this;
+				// #ifdef H5
+				uni.showToast({
+					title: '请在APP或者小程序环境下操作',
+					icon: 'error'
+				})
+				// #endif
+				// #ifndef H5
+				uni.getSystemInfo({
+					success: function(e) {
+						// #ifdef APP-PLUS
+						if (e.platform == 'android') {
+							//注意:一旦开启禁止截屏/录屏后将会全局生效,关闭页面时记得放开允许截屏/录屏
+							_this.NoscreenCapture();
+						} else {
+							//在APP IOS端截屏、录屏暂时没办法实现,可以寻求原生解决
+						}
+						// #endif
+
+						// #ifdef MP-WEIXIN
+						if (e.platform == 'android') {
+							//微信小程序在安卓手机上 禁止截屏/录屏(注意:禁止后录屏动作还是会进行,但录屏后的视频是黑屏的)
+							wx.setVisualEffectOnCapture({
+								visualEffect: 'hidden', //传入 hidden 则表示在截屏/录屏时隐藏屏幕
+								success: (res) => {
+									console.log(res)
+								},
+								fail: (err) => {
+									console.log(err)
+								},
+								complete: (res) => {
+									console.log(res)
+								}
+							})
+						} else {
+							//微信小程序在IOS手机上,注意:目前微信小程序在ios上也只能通过监听录屏状态,然后通过添加view层来进行阻止,截屏暂时无法实现
+							//监听用户录屏事件
+							wx.onScreenRecordingStateChanged(function(res) {
+								if (res.state == 'start') {
+									_this.isRecording = true
+								} else {
+									_this.isRecording = false
+								}
+							})
+							//查询用户是否在录屏
+							wx.getScreenRecordingState({
+								success: (res) => {
+									if (res.state == 'on') {
+										_this.isRecording = true
+									} else if (res.state == 'off') {
+										_this.isRecording = false
+									}
+								},
+								fail: (err) => {
+									_this.isRecording = false
+								}
+							})
+						}
+						// #endif
+					}
+				})
+				// #endif
+			},
+			//安卓端禁止截屏
+			NoscreenCapture() {
+				let osname = plus.os.name;
+				if (osname == "Android") {
+					var activity = plus.android.runtimeMainActivity();
+					plus.android.invoke(plus.android.invoke(activity, "getWindow"), "addFlags", 0x00002000);
+				}
+			},
+			//安卓端允许截屏  
+			AllowScreenshots() {
+				let _this = this;
+				uni.getSystemInfo({
+					success: function(e) {
+						// #ifdef MP-WEIXIN
+						if (e.platform == 'android') {
+							//微信小程序在安卓手机上 禁止截屏/录屏(注意:禁止后录屏动作还是会进行,但录屏后的视频是黑屏的)
+							wx.setVisualEffectOnCapture({
+								visualEffect: 'none', //传入 hidden 则表示在截屏/录屏时隐藏屏幕
+								success: (res) => {
+									console.log(res)
+								},
+								fail: (err) => {
+									console.log(err)
+								},
+								complete: (res) => {
+									console.log(res)
+								}
+							})
+						} else {
+							//微信小程序在IOS手机上,注意:目前微信小程序在ios上也只能通过监听录屏状态,然后通过添加view层来进行阻止,截屏暂时无法实现
+							//监听用户录屏事件
+							wx.onScreenRecordingStateChanged(function(res) {
+								if (res.state == 'start') {
+									_this.isRecording = false
+								} else {
+									_this.isRecording = false
+								}
+							})
+							//查询用户是否在录屏
+							wx.getScreenRecordingState({
+								success: (res) => {
+									if (res.state == 'on') {
+										_this.isRecording = false
+									} else if (res.state == 'off') {
+										_this.isRecording = false
+									}
+								},
+								fail: (err) => {
+									_this.isRecording = false
+								}
+							})
+						}
+						// #endif
+					}
+				})
+				// #ifdef APP-PLUS
+				let osname = plus.os.name;
+				if (osname == "Android") {
+					var activity = plus.android.runtimeMainActivity();
+					plus.android.invoke(plus.android.invoke(activity, "getWindow"), "clearFlags", 0x00002000);
+				}
+				// #endif
+			}
+		}
+	}
+</script>
+
+<style>
+	.zzc_mol {
+		background: #000;
+		width: 100%;
+		height: 100%;
+		position: fixed;
+		z-index: 99999;
+		top: 0;
+		left: 0;
+	}
+</style>

+ 2 - 2
manifest.json

@@ -1,5 +1,5 @@
 {
-    "name" : "鸿森堂便民商城",
+    "name" : "建兴堂",
     "appid" : "__UNI__A8490FA",
     "description" : "",
     "versionName" : "1.0.0",
@@ -52,7 +52,7 @@
     "quickapp" : {},
     /* 小程序特有相关 */
     "mp-weixin" : {
-        "appid" : "wx291619622c3ce89c",
+        "appid" : "wx87221638fa168cc5",
         "setting" : {
             "urlCheck" : false
         },

+ 2 - 2
pages.json

@@ -24,7 +24,7 @@
 		{
 			"path": "pages/home/index",
 			"style": {
-				"navigationBarTitleText": "鸿森堂便民商城",
+				"navigationBarTitleText": "建兴堂",
 				"enablePullDownRefresh": false,
 				"navigationStyle": "custom",
 				"app-plus": {
@@ -1285,7 +1285,7 @@
 	],
 	"globalStyle": {
 		"navigationBarTextStyle": "black",
-		"navigationBarTitleText": "鸿森堂便民商城",
+		"navigationBarTitleText": "建兴堂",
 		"navigationBarBackgroundColor": "#FFFFFF",
 		"backgroundColor": "#FFFFFF"
 	},

+ 55 - 16
pages/auth/login.vue

@@ -5,24 +5,30 @@
       <view class="force-login__content y-f">
 		  <view class="logo">
 		  	<view class="logo-img">
-		  		<image  :src="imgPath+'/app/image/logo.png'"></image>
-		  	</view>
-		  	<view class="title">鸿森堂便民商城</view>
+				<image  :src="imgPath+'/app/image/logo.png'"></image>
+			</view>
+			<view class="title">建兴堂</view>
 		  </view>
         <!-- <open-data class="user-avatar" type="userAvatarUrl"></open-data>
         <open-data class="user-name" type="userNickName"></open-data> -->
         <view class="login-notice">为了提供更优质的服务,请先登录</view>
-		
-		<button
+		<view class="btns">
+			<button
+				class="author-btn"
+				open-type="getPhoneNumber"
+				@getphonenumber="phoneLogin"  >一键授权手机号登录</button>
+			<button class="author-btn" v-if="isAgreement==false" @click="handleAgree()">一键授权手机号登录</button>
+		</view>
+		<!-- <button
 			class="author-btn"
 			open-type="getPhoneNumber"
-			@getphonenumber="phoneLogin"  >手机号一键登录</button>
+			@getphonenumber="phoneLogin"  >手机号一键登录</button> -->
        <button class="close-btn" @tap="back">暂不登录</button>
 		 <view class="tips">
 			 <checkbox  :checked="isAgreement" @click="handleAgreement()" />
 			 <view  @click="handleAgreement()">您同意并接受</view>
-		 	<view class="btn"  @click="openH5('/h5/userAgreement')">《用户协议》</view>
-		 	<view class="btn" @click="openH5('/h5/privacyPolicy')">《隐私保护》</view>
+		 	<view class="btn"  @click="openH5(1)">《用户协议》</view>
+		 	<view class="btn" @click="openH5(2)">《隐私保护》</view>
 		 </view>
       </view>
     </view>
@@ -42,10 +48,13 @@ export default {
 		}
 	},
 	computed: {
-		imgPath() {
-		  return this.$store.state.imgpath
+	    imgPath() {
+	      return this.$store.state.imgpath
+	    },
+		appid() {
+			return this.$store.state.appid
 		},
-	},
+	  },
 	onLoad(option) 
 	{
 		// #ifdef MP-WEIXIN
@@ -77,6 +86,15 @@ export default {
     
 	},
 	methods: {
+		handleAgree(){
+			
+			if(!this.isAgreement){
+			  	uni.showToast({
+			  		icon:'none',
+			  		title: "请先同意协议后再登录",
+			  	});
+			}
+		},
 		checkWeixin(){
 			var ua = window.navigator.userAgent.toLowerCase();
 			if (ua.match(/micromessenger/i) == 'micromessenger') {
@@ -104,10 +122,10 @@ export default {
 			this.isAgreement=!this.isAgreement;
 		},
 		openH5(url){
-			var requestPath = uni.getStorageSync('requestPath');
-			uni.setStorageSync('url',requestPath+url);
+			// var requestPath = uni.getStorageSync('requestPath');
+			// uni.setStorageSync('url',requestPath+url);
 			uni.navigateTo({
-				url: '../home/h5'
+				url: '/pages/home/h5?val='+url
 			})
 		},
 		getCode(){
@@ -162,7 +180,7 @@ export default {
 							   iv: e.mp.detail.iv,
 							   code: code,
 							   userCode:userCode,
-							   appId:wx.getAccountInfoSync().miniProgram.appId,
+							   appId:this.appid
 							})
 							.then( res => {
 								if(res.code==200){
@@ -220,13 +238,34 @@ export default {
 			// uni.switchTab({
 			// 	url: '/pages/home/index'
 			// });
-			uni.navigateBack()
+			uni.navigateBack({
+				delta: 1
+			});
 		}
 	}
 }
 </script>
 
 <style lang="scss">
+	.btns{
+		position: relative;
+		width: 630rpx;
+		height: 80rpx;
+		.author-btn{				
+			z-index:100;
+			position: absolute;
+			width: 630rpx;
+			height: 80rpx;
+			background: linear-gradient(to right, #2BC7B9 0%, #2aa7B9 100%);
+			background: -moz-linear-gradient(to right, #2BC7B9 0%, #2aa7B9 100%);
+			// box-shadow: 0px 7rpx 6rpx 0px rgba(229, 138, 0, 0.22);
+			border-radius: 40rpx;
+			font-size: 30rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			color: rgba(255, 255, 255, 1);
+		}
+	}
 	.logo{
 		display: flex;
 		flex-direction: column;

+ 1 - 1
pages/common/launch.vue

@@ -5,7 +5,7 @@
 				<view class="circle"></view>
 				<image src="/static/logo.jpg"></image>
 			</view>
-			<text class="text">鸿森堂便民商城</text>
+			<text class="text">建兴堂</text>
 		</view>
 	</view>
 </template>

+ 8 - 6
pages/home/index.vue

@@ -8,7 +8,7 @@
 					<!-- 这里是状态栏 -->
 					<view class="status_bar" :style="{height: statusBarHeight}"></view>
 					<view class="top-title">
-						<view class="name">鸿森堂便民商城</view>
+						<view class="name">建兴堂</view>
 						<!-- <view class="dot">•</view><view class="sub-name">七彩互联网医院</view> -->
 					</view>
 					<!-- 搜索框、购物车、客服 -->
@@ -446,9 +446,9 @@
 		},
 		onShareAppMessage(res) {
 			return {
-				title: '鸿森堂-您的专属健康解决方案',
+				title: '建兴堂-您的专属健康解决方案',
 				path: `/pages/common/launch`,
-				imageUrl: this.$store.state.imgpath+'/app/image/logo.png'//分享图标,路径可以是本地文件路径、代码包文件路径或者网络图片路径.支持PNG及JPG。显示图片长宽比是 5:4
+				imageUrl:'/static/logo.jpg'//分享图标,路径可以是本地文件路径、代码包文件路径或者网络图片路径.支持PNG及JPG。显示图片长宽比是 5:4
 			}
 		},
 		onReachBottom() {
@@ -458,9 +458,9 @@
 		//分享到朋友圈
 		onShareTimeline(res) {
 			return {
-				title: '鸿森堂-您的专属健康解决方案',
+				title: '建兴堂-您的专属健康解决方案',
 				query: '', //页面参数
-				imageUrl: this.$store.state.imgpath+'/app/image/logo.png'//分享图标,路径可以是本地文件路径、代码包文件路径或者网络图片路径.支持PNG及JPG。显示图片长宽比是 5:4
+				imageUrl: '/static/logo.jpg'//分享图标,路径可以是本地文件路径、代码包文件路径或者网络图片路径.支持PNG及JPG。显示图片长宽比是 5:4
 			}
 		},
 		computed: {
@@ -800,7 +800,9 @@
 				})
 			},
 			getIndexData() {
-				let data = {};
+				let data = {
+					appId:wx.getAccountInfoSync().miniProgram.appId,
+				};
 				getIndexData(data).then(
 					res => {
 						if (res.code == 200) {

+ 7 - 4
pages/shopping/cart.vue

@@ -64,28 +64,31 @@
 				<view class="btn" @click="submit">结算</view>
 			</view>
 		</view>
-		
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
 <script>
 	import {getCarts,cartNum,delCart} from '@/api/product'
 	import likeProduct from '@/components/likeProduct.vue'
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	export default {
 		components: {
-			likeProduct
+			likeProduct,
+			ykscreenRecord
 		},	
 		data() {
 			return {
-				 
 				totalMoney:0.00,
 				carts:[],
 				checkAll:false,
 			}	
 		},
 		onLoad() {
-			this.getCarts();
  
+		},
+		onShow() {
+			this.getCarts();
 		},
 		onReachBottom() {
 			this.$refs.product.getGoodsProducts();

+ 4 - 2
pages/shopping/confirmOrder.vue

@@ -134,12 +134,13 @@
 			 </view>
 			 
 		</popupBottom>
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
 <script>
 	import {getWeixinOrderTemps} from '@/api/common'
-	
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	import {confirm,computed,create} from '@/api/storeOrder'
 	import { getMyEnableCouponList } from '@/api/coupon'
 	 
@@ -149,7 +150,8 @@
 	export default {
 		components: {
 			EvanSwitch,
-			popupBottom
+			popupBottom,
+			ykscreenRecord
 		},
 		data() {
 			return {

+ 6 - 1
pages/shopping/payOrder.vue

@@ -47,12 +47,17 @@
 		<view class="btn-box">
 			<view class="btn" @click="payOrder()">去支付</view>
 		</view>
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
 <script>
 	import {pay,getStoreOrderById} from '@/api/storeOrder'
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	export default {
+		components:{
+			ykscreenRecord
+		},
 		data() {
 			return {
 				payLimitTime:null,
@@ -113,7 +118,7 @@
 				
 			},
 			payOrder(){
-				var data = {orderId:this.order.id};
+				var data = {orderId:this.order.id,appId:wx.getAccountInfoSync().miniProgram.appId};
 				var that=this;
 				uni.showLoading();
 				pay(data).then(

+ 9 - 1
pages/shopping/paymentOrder.vue

@@ -157,6 +157,7 @@
 				<button  class="share" data-name="shareBtn" open-type="share">分享</button>
 			</view> -->
 		</view>
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
@@ -164,7 +165,11 @@
 	import {getUserInfo} from '@/api/user'
 	import {getStoreConfig} from '@/api/common'
 	import {editPayType,pay,getStoreOrderById,orderBindUser} from '@/api/storeOrder'
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	export default {
+		components:{
+			ykscreenRecord
+		},
 		data() {
 			return {
 				orderId:null,
@@ -333,7 +338,7 @@
 				var data = {
 					orderId:this.order.id,
 					payType:this.order.payType,
-					// appid:wx.getAccountInfoSync().miniProgram.appId
+					appId:wx.getAccountInfoSync().miniProgram.appId
 				};
 				var that=this;
 				uni.showLoading();
@@ -570,6 +575,9 @@
 			align-items: center;
 			justify-content: center;
 			flex-direction: column;
+			position: fixed;
+			width: 100%;
+			bottom: 0rpx;
 			.btn{
 				width: 91.73%;
 				height: 88upx;

+ 1 - 1
pages/shopping/productDetails.vue

@@ -87,7 +87,7 @@
 		<view class="det-box">
 			<view class="title">图文详情</view>
 			<view class="inner">
-				<view  v-html="product.description" style="font-size:0"></view>
+				<view  v-html="product.description" ></view>
 			</view>
 		</view>
 		<!-- 底部按钮 -->

+ 2 - 2
pages/user/index.vue

@@ -129,10 +129,10 @@
 								<image src="https://hst2-1323137866.cos.ap-chongqing.myqcloud.com/shop/images/products_icon.png" mode=""></image>
 								<text class="text">制单管理</text>
 							</view>
-							 <!-- <view class="item no-marin-bottom" @click="toManagerCourse()">
+							 <view class="item no-marin-bottom" @click="toManagerCourse()">
 							 	<image src="https://hst2-1323137866.cos.ap-chongqing.myqcloud.com/shop/images/sale_file.png" mode=""></image>
 							 	<text class="text">销售管理</text>
-							 </view> -->
+							 </view>
 						</view>
 					</view>
 				</view>

+ 16 - 9
pages_company/order/confirmCompanyOrder.vue

@@ -75,30 +75,35 @@
 				carts:[],
 				isAgreement:false,
 				payAmount:null,
-				CompanyUserInfo:uni.getStorageSync('CompanyUserInfo')
-				
+				CompanyUserInfo:uni.getStorageSync('CompanyUserInfo'),
+				packageId:'',
+				isPackage:0
 			}
 		},
 		onLoad(option) {
 			this.orderKey=option.orderKey;
+			if(option.packageId){
+				this.packageId=option.packageId
+				this.isPackage=1
+			}
 			this.getSalesOrder();
 			 
 		},
 		//发送给朋友
 		onShareAppMessage(res) {
 			return {
-				title: "鸿森堂-您的专属健康解决方案",
-				path: '/pages_company/order/confirmOrder?orderKey='+this.orderKey+'&companyUserId='+this.CompanyUserInfo.userId,
-				imageUrl: '/static/logo.jpg' //分享图标,路径可以是本地文件路径、代码包文件路径或者网络图片路径.支持PNG及JPG。显示图片长宽比是 5:4
+				title: this.carts[0].productName,
+				path: '/pages_company/order/confirmOrder?orderKey='+this.orderKey+'&companyUserId='+this.CompanyUserInfo.userId+'&packageId='+this.packageId,
+				imageUrl: this.carts[0].productImage //分享图标,路径可以是本地文件路径、代码包文件路径或者网络图片路径.支持PNG及JPG。显示图片长宽比是 5:4
 			}
 			
 		},
 		//分享到朋友圈
 		onShareTimeline(res) {
 			return {
-				title:"鸿森堂-您的专属健康解决方案",
-				query:'orderKey='+this.orderKey,
-				imageUrl:  '/static/logo.jpg' //分享图标,路径可以是本地文件路径、代码包文件路径或者网络图片路径.支持PNG及JPG。显示图片长宽比是 5:4
+				title:this.carts[0].productName,
+				query:'orderKey='+this.orderKey+'&companyUserId='+this.CompanyUserInfo.userId+'&packageId='+this.packageId,
+				imageUrl:this.carts[0].productImage //分享图标,路径可以是本地文件路径、代码包文件路径或者网络图片路径.支持PNG及JPG。显示图片长宽比是 5:4
 			}
 		},
 		methods: {
@@ -120,7 +125,9 @@
 					if(this.inputTxt==0){
 						this.inputTxt=this.price.totalPrice.toFixed(2)
 					}
-					var data={createOrderKey:this.orderKey,token:uni.getStorageSync('CompanyUserToken'),money:this.inputTxt,payAmount:this.payAmount}
+					var data={createOrderKey:this.orderKey,token:uni.getStorageSync('CompanyUserToken'),
+					isPackage:this.isPackage,
+					money:this.inputTxt,payAmount:this.payAmount}
 					updateSalseOrderMoney(data).then(
 						res => {
 							if(res.code==200){

+ 19 - 2
pages_company/order/confirmOrder.vue

@@ -74,7 +74,8 @@
 					payPrice:0.00,
 				},
 				carts:[],
-				companyUserId:''
+				companyUserId:'',
+				packageId:'',
 			}
 		},
 		onLoad(option) {
@@ -83,6 +84,9 @@
 				this.getOrderCount();
 			}
 			console.log("qxj option:"+JSON.stringify(option));
+			if(option.packageId){
+				this.packageId=option.packageId
+			}
 			this.orderKey=option.orderKey;
 			this.companyUserId=option.companyUserId
 			this.getSalesOrder();
@@ -165,6 +169,17 @@
 			},
 			// 提交订单
 			submitOrder() {
+				if(this.packageId){
+					this.utils.isLogin().then(res => {
+						if(res){
+							uni.navigateTo({
+								url: '/pages_shopping/shopping/confirmPackageOrder?packageId='+
+								this.packageId+"&companyUserId="+this.companyUserId+'&createOrderKey='+this.orderKey
+							})
+						}
+					})
+					return
+				}
 				this.utils.isLogin().then(res => {
 					if(res){
 						var data={createOrderKey:this.orderKey}
@@ -172,7 +187,9 @@
 							res => {
 								if(res.code==200){
 									uni.navigateTo({
-										url: '/pages_shopping/shopping/confirmCreateOrder?type=buy&cartIds='+res.cartIds.toString()+"&companyId="+res.companyId+"&companyUserId="+res.companyUserId+"&createOrderKey="+this.orderKey
+										url: '/pages_shopping/shopping/confirmCreateOrder?type=buy&cartIds='+
+										res.cartIds.toString()+"&companyId="+res.companyId+"&companyUserId="+
+										res.companyUserId+"&createOrderKey="+this.orderKey
 									})
 								}else{
 									uni.showToast({

+ 1 - 1
pages_company/order/productDetails.vue

@@ -76,7 +76,7 @@
 		<view class="det-box">
 			<view class="title">图文详情</view>
 			<view class="inner">
-				<view  v-html="product.description" style="font-size:0"></view>
+				<view  v-html="product.description" ></view>
 			</view>
 		</view>
 		<!-- 底部按钮 -->

+ 4 - 3
pages_company/order/productList.vue

@@ -51,14 +51,14 @@
 					</view>
 					<view class="info-box">
 						<view class="title ellipsis2">{{item.productName}}</view>
-						<view class="intro ellipsis">{{item.productInfo}}</view>
+						<view class="intro ellipsis">{{item.productInfo||""}}</view>
 						<view class="prce-num">
 							<view class="price">
 								<text class="unit">¥</text>
 								<text class="num">{{item.price.toFixed(2)}} </text>
 							</view>
 							<view class="cart-img" @click="navgetTo('../shopping/cart')">
-								<view class="sale">已售 {{item.sales}} {{item.unitName}}</view>
+								<view class="sale">已售 {{item.sales}} {{item.unitName||""}}</view>
 							</view>
 						</view>
 					</view>
@@ -99,7 +99,8 @@
 					priceOrder:null,
 					salesOrder:null,
 					productName:"",
-					token:''
+					token:'',
+					appId:wx.getAccountInfoSync().miniProgram.appId,
 				},
 				mescroll:null,
 				// 上拉加载的配置

+ 5 - 0
pages_company/storeOrder.vue

@@ -61,13 +61,18 @@
 				</view>
 			</view>
 		</mescroll-body>
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
 <script>
 	import {getCompanyStoreOrderList} from '@/api/storeOrder'
 	import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	export default {
+		components:{
+			ykscreenRecord
+		},
 		mixins: [MescrollMixin], 
 		data() {
 			return {

+ 5 - 0
pages_company/storeOrderDetail.vue

@@ -244,13 +244,18 @@
 				</view>
 		  </view>
 		</view>
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
 <script>
 	import {getMyStoreOrderById } from '@/api/storeOrder'
 	import {editOrderMoney} from '@/api/companyOrder.js'
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	export default {
+		components:{
+			ykscreenRecord
+		},
 		data() {
 			return {
 				payMoney:0,

+ 5 - 0
pages_company/storeProductPackage.vue

@@ -67,14 +67,19 @@
 				</view>
 			</view>
 		</mescroll-body>
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
 <script>
 	import {getStoreProductPackage} from '@/api/storeProductPackage.js'
 	import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	export default {
 		mixins: [MescrollMixin], 
+		components:{
+			ykscreenRecord
+		},
 		data() {
 			return {
 				displayMore:false,

+ 173 - 2
pages_company/storeProductPackageDetails.vue

@@ -90,8 +90,11 @@
 				</view>
 				 
 			</view>
-			<view class="btn-box">
+			<!-- <view class="btn-box">
 				<view class="btn buy" @click="buy">立即购买</view>
+			</view> -->
+			<view class="btn-box">
+				<view class="btn buy" @click="dictshow=true">立即制单</view>
 			</view>
 		</view>
 		<view class="message-box" v-if="messageShow">
@@ -101,13 +104,85 @@
 			</view>
 			<view class="btn" @click="showOrder()">查看</view>
 		</view>
+		<!-- 订单类型 -->
+		<view>
+			<u-popup :show="dictshow" @close="closedict" mode="center" :closeOnClickOverlay="false" round="20">
+				<view  class="w600 h500 radius20 ">
+					<view class="p40 justify-end">
+						<u-icon name="close" color="#7c7c7c" size="28" @click="closedict"></u-icon>
+						<!-- <image src="/static/images/close24.png" class="w40 h40" ></image> -->
+					</view>
+					<view class="m20">
+						<view class="justify-start align-center u-border radius20 p20">
+							<view>订单类型:</view>
+							<view class="color6 flex-1" @click="cardshow=true">{{cardvalue?cardvalue:'请选择订单类型'}}</view>
+						</view>
+						<view class="justify-start align-center u-border radius20 p20 mt20 mb60">
+							<view>媒体类型:</view>
+							<view class="color6 flex-1" @click="videoshow=true">{{videovalue?videovalue:'请选择媒体类型'}}</view>
+						</view>
+					</view>
+					<view class="subdict " @click="submitgoods">确认</view>
+				</view>
+			</u-popup>
+		</view>
+		<view>
+			<u-popup :show="cardshow" mode="bottom"  @close="cardshow=!cardshow" :closeOnClickOverlay="true" closeIconPos='top-right'>
+				<view class=" h600">
+					<view class="mb20" style="text-align: center;">
+						<view style="display: inline-block; ">订单类型</view>
+						<u-icon name="close-circle" color="#ccc" size="28"
+						@click="cardshow=!cardshow" style="display: inline-block;float: left;"></u-icon>
+					</view>
+					<view class="justify-start wrap">
+						<view class="p16 mlr4" v-for="(item,index) in cardlist" :key="index">
+							<u-tag :text="item.dictLabel" :plain="!item.checked" type="primary" :name="index"
+									@click="checkboxClick">
+							</u-tag>
+						</view>
+						<view class="base-color-red fs24 bor-red p8 radius8 plr12" v-if="cardlist.length==0">暂无订单类型</view>
+					</view>
+					<view class="centerV">
+						<view @click="getcardid" class="surebtn">确定</view>
+					</view>
+				</view>
+			</u-popup>
+		</view>
+		<view>
+			<u-popup :show="videoshow" mode="bottom"  @close="videoshow=!videoshow" :closeOnClickOverlay="true" closeIconPos='top-right'>
+				<view class="h600">
+					<view class="mb20" style="text-align: center;">
+						<view style="display: inline-block; ">媒体类型</view>
+						<u-icon name="close-circle" color="#ccc" size="28"
+						@click="videoshow=!videoshow" style="display: inline-block;float: left;"></u-icon>
+					</view>
+					<view class="justify-start wrap">
+						<view class="p16 mlr4" v-for="(item,index) in videolist" :key="index">
+							<u-tag :text="item.dictLabel" :plain="!item.checked" type="primary" :name="index"
+									@click="checkboxClickA">
+							</u-tag>
+						</view>
+						<view class="base-color-red fs24 bor-red p8 radius8 plr12" v-if="videolist.length==0">暂无媒体类型</view>
+					</view>
+					<view class="centerV">
+						<view @click="getvideoid" class="surebtn">确定</view>
+					</view>
+				</view>
+			</u-popup>
+		</view>
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
 <script>
 	import {getOrderCount} from '@/api/storeOrder'
+	import {createSalesOrder} from '@/api/companyOrder.js'
 	import {getStoreProductPackageDetails} from '@/api/storeProductPackage'
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	export default {
+		components:{
+			ykscreenRecord
+		},
 		data() {
 			return {
 				count0:0,
@@ -118,7 +193,16 @@
 				products:[],
 				// 当前轮播的图片
 				activeBanner: 1,
-				 
+				//订单类型
+				cardvalue:'',
+				cardid:'',
+				videovalue:'',
+				videoid:'',
+				dictshow:false,
+				cardshow:false,
+				videoshow:false,
+				videolist:{},
+				cardlist:{}
 			};
 		},
 		onLoad(options) {
@@ -167,8 +251,75 @@
 				this.getOrderCount();
 			}
 			this.getStoreProductPackageDetails();
+			const dicts=JSON.parse(uni.getStorageSync('dicts'))
+			this.videolist=dicts.storeOrderMedium.map(item => {
+				return {
+					...item,
+					checked: false,
+				}
+			})
+			this.cardlist=dicts.storeOrderType.map(item => {
+				return {
+					...item,
+					checked: false,
+				}
+			})
 		},
 		methods: {
+			checkboxClickA(name){
+				this.videolist.map((item, index) => {
+				  item.checked = index === name ? true : false;
+				});
+				console.log(name)
+			},
+			getvideoid(){
+				this.videovalue = this.videolist.filter(item => item.checked)
+				.map(v => v.dictLabel).join('')
+				console.log(this.cardvalue)
+				this.videoid = this.videolist.filter(item => item.checked).map(v => v.dictValue).join('')
+				this.videoshow=false
+			},
+			checkboxClick(name){
+				this.cardlist.map((item, index) => {
+				  item.checked = index === name ? true : false;
+				});
+				console.log(name)
+			},
+			getcardid(){
+				this.cardvalue = this.cardlist.filter(item => item.checked)
+				.map(v => v.dictLabel).join('')
+				console.log(this.cardvalue)
+				this.cardid = this.cardlist.filter(item => item.checked).map(v => v.dictValue).join('')
+				this.cardshow=false
+			},
+			submitgoods(){
+				//选择后提交制单
+				var data={
+					token:uni.getStorageSync('CompanyUserToken'),
+					isPackage:1,
+					packageId:this.packageId,
+					orderType:this.cardid,
+					orderMedium:this.videoid
+					}
+				createSalesOrder(data).then(
+					res => {
+						if(res.code==200){
+							uni.navigateTo({
+								url: '/pages_company/order/confirmCompanyOrder?orderKey='+res.orderKey+'&packageId='+this.packageId
+							})
+						}else{
+							uni.showToast({
+								icon:'none',
+								title: "请求失败",
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			closedict(){
+				this.dictshow=!this.dictshow
+			},
 			getOrderCount(){
 				getOrderCount().then(
 					res => {
@@ -262,6 +413,26 @@
 </script>
 
 <style lang="scss">
+	.surebtn{
+		margin: 20rpx 0;
+		background-color: #2BC7B9;
+		color: #fff;
+		width: 80%;
+		text-align: center;
+		padding: 20rpx 0;
+		border-radius: 40rpx;
+	}
+	.subdict{
+		width: 300rpx;
+		height: 80rpx;
+		line-height: 80rpx;
+		background-color: #2BC7B9;
+		border-radius: 200rpx;
+		color: #fff;
+		text-align: center;
+		font-size: 28rpx;
+		margin: 0 auto;
+	}
 	.shop-banner{
 		height: 756upx;
 		background-color: #FFFFFF;

+ 308 - 0
pages_company/voice.vue

@@ -0,0 +1,308 @@
+<template>
+	<view class="container">
+		<view class="textbox">
+			<view class="header-tips">请朗读以下文字</view>
+			<view class="textbox-con" :style="{height: textHeight}">
+				在这片神奇的森林里,小鸟轻快地唱着歌,仿佛在诉说着春天的故事。
+			</view>
+		</view>
+		<view class="voice-footer">
+			<view class="voice-footer-tips">1、选择安静的录音环境,可在房间或车内录音。</view>
+			<view class="voice-footer-tips">2、保持20cm距离,避免手机太远录音不清晰。</view>
+			<view class="voice-footer-tips">3、使用普通话朗读,语速适中,吐字清晰。</view>
+			<view class="voice-footer-btnbox">
+				<view class="btnbox-item" :style="{visibility: voicePath ? 'visible' : 'hidden',color: status=='start' ? '#ccc !important':''}">
+					<view class="iconsbox" @click="playVoice" :style="{borderColor: status=='start' ? '#ccc' :isVoicePlay ? 'red':''}">
+						<u-icon name="volume-fill"  size="30" :color="status=='start' ? '#ccc' :isVoicePlay ? 'red':'#757575'"></u-icon>
+						<!-- <uni-icons type="sound-filled" size="30" :color="status=='start' ? '#ccc' :isVoicePlay ? 'red':'#757575'"></uni-icons> -->
+					</view>
+					<view>试听录音</view>
+				</view>
+				<view class="btnbox-item">
+					<view class="iconsbox iconsbox-voice" :style="{backgroundColor: status=='end' ? 'red':''}" @click="handleRecord">
+						<!-- <uni-icons v-show="status=='stop'|| status=='end'" type="mic-filled" size="35" color="#fff"></uni-icons> -->
+						<u-icon name="mic"  v-show="status=='stop'|| status=='end'" size="35" color="#fff"></u-icon>
+						<image v-show="status=='start'" src="https://obs.jnmyunl.com/fs/20250813/1755047925090.png" mode="aspectFill"></image>
+					</view>
+					<view v-show="status=='stop'">点击录制</view>
+					<view v-show="status=='start'">点击停止</view>
+					<view v-show="status=='end'">重新录制</view> 
+				</view>
+				<view class="btnbox-item" :style="{visibility: voicePath ? 'visible' : 'hidden',color: status=='start' ? '#ccc !important':''}">
+					<button class="iconsbox" :disabled="btnLoading" @click="onSubmit">
+						<!-- <uni-icons type="checkmarkempty" size="30" :color="status=='start' ? '#ccc' : '#757575'"></uni-icons> -->
+						<u-icon name="checkmark" size="30" :color="status=='start' ? '#ccc' : '#757575'"></u-icon>
+					</button>
+					<view>提交</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {addVoicePrintUrl} from '@/api/companyUser'
+	let innerAudioContext = null
+	export default {
+		data() {
+			return {
+				recorderManager: null,
+				// innerAudioContext: null,
+				textHeight: '',
+				statusBarHeight: uni.getSystemInfoSync().statusBarHeight + 'px',
+				screenHeight: uni.getSystemInfoSync().windowHeight + 'px',
+				voicePath: '',
+				status: "stop",
+				isVoicePlay: false,
+				btnLoading: false,
+				companyUserId:null
+			}
+		},
+		onLoad(option) {
+			console.log('==onLoad==',this.recorderManager)
+			// #ifndef H5
+			this.recorderManager = uni.getRecorderManager();
+			innerAudioContext = uni.createInnerAudioContext();
+			this.companyUserId=option.companyUserId
+			let self = this;
+			console.log('==recorderManager22222222==',this.recorderManager)
+			if(this.recorderManager) {
+				console.log('==recorderManager==')
+				this.recorderManager.onStart(()=>{
+					console.log('==start==')
+					this.status = 'start'
+				})
+				this.recorderManager.onStop((res)=> {
+					console.log('recorder stop' + JSON.stringify(res));
+					this.status = 'end'
+					self.voicePath = res.tempFilePath;
+				});
+				this.recorderManager.onError((res)=> {
+					console.log('onError ==' + JSON.stringify(res));
+				});
+			}
+			
+			if(innerAudioContext) {
+				// innerAudioContext.autoplay = true;
+				innerAudioContext.onPlay(() => {
+				  // console.log('开始播放');
+				  this.isVoicePlay = true
+				});
+				innerAudioContext.onStop(() => {
+				  // console.log('停止播放');
+				  this.isVoicePlay = false
+				});
+				innerAudioContext.onEnded(() => {
+				  // console.log('播放结束');
+				  this.isVoicePlay = false
+				});
+				innerAudioContext.onError((res) => {
+					// console.log('播放res',res);
+				  this.isVoicePlay = false
+				});
+				innerAudioContext.onPause(() => {
+				  // console.log('暂停播放');
+				  this.isVoicePlay = false
+				});
+			}
+			// #endif
+		},
+		onReady() {
+			const query = uni.createSelectorQuery().in(this);
+			query
+			  .select(".voice-footer")
+			  .boundingClientRect((data) => {
+				this.textHeight = `calc(${this.screenHeight} - ${data.height}px - ${this.statusBarHeight} - 45px - ${uni.upx2px(120)}px)`
+			  })
+			  .exec();
+		},
+		onHide() {
+			if(innerAudioContext){
+				innerAudioContext.pause();
+			}
+		},
+		onUnload() {
+			this.recorderManager = null
+			if(innerAudioContext) {
+				innerAudioContext.destroy()
+				innerAudioContext = null
+			}
+		},
+		methods: {
+			handleRecord() {
+				console.log('handleRecord',this.status)
+				if(innerAudioContext){
+					innerAudioContext.pause();
+				}
+				if(this.status == 'stop') {
+					this.startRecord()
+				} else if(this.status == 'start') {
+					this.endRecord()
+				} else if(this.status == 'end') {
+					this.startRecord()
+				}
+			},
+			startRecord() {
+				console.log('this.recorderManager',this.recorderManager)
+				// console.log('开始录音');
+				// 声音采集限制10秒
+				this.recorderManager.start({
+					format: 'mp3',
+					duration: 10000
+				});
+			},
+			endRecord() {
+				// console.log('录音结束');
+				this.recorderManager.stop();
+			},
+			playVoice() {
+				console.log(innerAudioContext)
+				if(this.status == "start") return
+				if (this.voicePath) {
+					if(this.isVoicePlay == false) {
+						innerAudioContext.src = this.voicePath;
+						innerAudioContext.play();
+					} else {
+						innerAudioContext.stop();
+					}
+				}
+			},
+			onSubmit() {
+				console.log("==onSubmit=",this.status)
+				if(this.status == "start") return
+				this.btnLoading = true
+				uni.showLoading({
+					title:"提交中..."
+				})
+				uni.uploadFile({
+					url: uni.getStorageSync('requestPath')+'/app/common/uploadOSS', //仅为示例,非真实的接口地址
+					filePath: this.voicePath,
+					name: 'file',
+					success: (uploadFileRes) => {
+						console.log(JSON.parse(uploadFileRes.data).url)
+						console.log(111,this.companyUserId)
+						let voicePrintUrl = JSON.parse(uploadFileRes.data).url
+						addVoicePrintUrl({voicePrintUrl: voicePrintUrl,companyUserId:this.companyUserId}).then(res=>{
+							uni.hideLoading()
+							this.btnLoading = false
+							if(res.code==200){
+								console.log(200,this.companyUserId)
+								uni.showToast({
+									icon:'none',
+									title: '提交成功',
+								});
+							}else{
+								uni.showToast({
+									icon:'none',
+									title: res.msg,
+								});
+							}
+						}).catch(()=>{
+							uni.hideLoading()
+							this.btnLoading = false
+						})
+					},
+					fail: ()=>{
+						uni.hideLoading()
+						this.btnLoading = false
+					}
+				});
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	@mixin u-flex($flexD, $alignI, $justifyC) {
+		display: flex;
+		flex-direction: $flexD;
+		align-items: $alignI;
+		justify-content: $justifyC;
+	}
+	.container {
+		position: relative;
+		.header-tips {
+			padding-bottom: 24rpx;
+			box-sizing: border-box;
+			font-family: PingFang SC, PingFang SC;
+			font-weight: 400;
+			font-size: 24rpx;
+			color: #757575;
+			// color: $mainThemeHColor;
+			text-align: center;
+		}
+		.textbox {
+			padding: 24rpx 50rpx;
+			box-sizing: border-box;
+			&-con {
+				padding: 32rpx;
+				box-sizing: border-box;
+				background-color: #fff;
+				border-radius: 16rpx 16rpx 16rpx 16rpx;
+				font-family: PingFang SC, PingFang SC;
+				font-weight: 500;
+				font-size: 40rpx;
+				color: #222222;
+				overflow-y: auto;
+				line-height: 60rpx;
+				letter-spacing: 4rpx;
+			}
+		}
+		.voice-footer {
+			position: fixed;
+			bottom: 0;
+			left: 0;
+			width: 100%;
+			box-sizing: border-box;
+			&-tips {
+				padding: 0 50rpx;
+				box-sizing: border-box;
+				font-family: PingFang SC, PingFang SC;
+				font-weight: 400;
+				font-size: 24rpx;
+				color: #757575;
+				margin-bottom: 10rpx;
+			}
+		}
+	}
+	.voice-footer-btnbox {
+		@include u-flex(row,flex-end,space-evenly);
+		margin-top: 100rpx;
+		padding: 50rpx 24rpx;
+		background-color: #fff;
+		text-align: center;
+		font-family: PingFang SC, PingFang SC;
+		font-weight: 400;
+		font-size: 30rpx;
+		color: #333;
+		.iconsbox {
+			height: 110rpx;
+			width: 110rpx;
+			margin: 0;
+			margin-bottom: 20rpx;
+			box-sizing: border-box;
+			@include u-flex(row,center,center);
+			border-radius: 50%;
+			background-color: #fff;
+			border: 1rpx solid #CCCCCC;
+			&::after {
+				border: none;
+			}
+			&-voice {
+				height: 150rpx;
+				width: 150rpx;
+				background-color: #FF5C03;
+				border: 1rpx solid #FF5C03;
+				image {
+					height: 60rpx;
+					width: 60rpx;
+				}
+			}
+		}
+		.btnbox-item {
+			flex: 1;
+			@include u-flex(column,center,center);
+		}
+		
+	}
+</style>

+ 490 - 0
pages_company/voiceItem.vue

@@ -0,0 +1,490 @@
+<template>
+	<view class="container">
+		<view class="textbox">
+			<view class="header-tips">请朗读以下文字</view>
+			<view class="textbox-con" :style="{height: textHeight}">{{voiceText || ''}}</view>
+		</view>
+		<view class="voice-footer">
+			<view class="voice-footer-tips">1、选择安静的录音环境,可在房间或车内录音。</view>
+			<view class="voice-footer-tips">2、保持20cm距离,避免手机太远录音不清晰。</view>
+			<view class="voice-footer-tips">3、使用普通话朗读,语速适中,吐字清晰。</view>
+			<view class="voice-footer-btnbox">
+				<view class="tabs" v-if="type!=2">
+					<u-tabs
+						:scrollable="false"
+						:list="tabs"
+						:current="current"
+						lineColor="#FF5C03"
+						@change="tabChange">
+					</u-tabs>
+					<view class="mask" v-if="status=='start'||status=='end'" @click.stop>
+						<view @click.stop="tabclick(0)"></view>
+						<view @click.stop="tabclick(1)"></view>
+					</view>
+				</view>
+				<view class="voice-footer-con">
+					<view class="btnbox-item" :style="{visibility: voicePath ? 'visible' : 'hidden',color: status=='start' ? '#ccc !important':''}">
+						<view class="iconsbox" @click="playVoice" :style="{borderColor: status=='start' ? '#ccc' :isVoicePlay ? 'red':''}">
+							<u-icon name="volume-fill"  size="30" :color="status=='start' ? '#ccc' :isVoicePlay ? 'red':'#757575'"></u-icon>
+							<!-- <uni-icons type="sound-filled" size="30" :color="status=='start' ? '#ccc' :isVoicePlay ? 'red':'#757575'"></uni-icons> -->
+						</view>
+						<view>试听录音</view>
+					</view>
+					<view class="btnbox-item">
+						<view class="iconsbox iconsbox-voice" :style="{backgroundColor: status=='end'|| status=='ok' ? 'red':''}" @click="handleRecord">
+							<view v-show="status=='stop'|| status=='end' || status=='ok'">
+								<view v-show="current==1" class="smallcircle-filled"></view>
+								<u-icon v-show="current!=1" name="mic" size="35" color="#fff"></u-icon>
+							</view>
+							<!-- <uni-icons v-show="status=='stop'|| status=='end' || status=='ok'" :type="current==1?'smallcircle-filled':'mic-filled'" size="35" color="#fff"></uni-icons> -->
+							<image v-show="current!=1&&status=='start'" src="https://obs.jnmyunl.com/fs/20250813/1755047925090.png" mode="aspectFill"></image>
+							<view v-show="current==1&&status=='start'"><u-loading-icon color="#fff"></u-loading-icon></view>
+						</view>
+						<view v-show="status=='stop'">{{current==1?'点击生成':'点击录制'}}</view>
+						<view v-show="status=='start'">{{current==1?'生成中':'点击停止'}}</view>
+						<view v-show="status=='end'|| status=='ok'">{{current==1?'重新生成':'重新录制'}}</view> 
+					</view>
+					<view class="btnbox-item" :style="{visibility: voicePath&&status!='ok'&&current!=1  ? 'visible' : 'hidden',color: status=='start' ? '#ccc !important':''}">
+						<button class="iconsbox" :disabled="btnLoading" @click="onSubmit">
+							<u-icon name="checkmark" size="30" :color="status=='start' ? '#ccc' : '#757575'"></u-icon>
+							<!-- <uni-icons type="checkmarkempty" size="30" :color="status=='start' ? '#ccc' : '#757575'"></uni-icons> -->
+						</button>
+						<view>提交</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {companyUserVoiceNew,companyUserVoice,queryDetail} from '@/api/companyUser'
+	let innerAudioContext = null
+	export default {
+		data() {
+			return {
+				recorderManager: null,
+				// innerAudioContext: null,
+				textHeight: '',
+				statusBarHeight: uni.getSystemInfoSync().statusBarHeight + 'px',
+				screenHeight: uni.getSystemInfoSync().windowHeight + 'px',
+				voicePath: '',
+				status: "stop",
+				isVoicePlay: false,
+				btnLoading: false,
+				tabs:[
+					{
+						id:1,
+						name:'自己录制'
+					},
+					{
+						id:2,
+						name:'AI生成'
+					}
+				],
+				current: 0,
+				id: null,
+				voiceText: '',
+				recordType: 0, // 是否已采集
+				type: 0, // 2表示只能自己录制
+			}
+		},
+		onLoad(option) {
+			this.type = option.type || 0
+			this.recordType = option.recordType || 0
+			this.id = option.id || null
+			this.getDetail()
+			this.initDate()
+		},
+		onHide() {
+			if(innerAudioContext){
+				innerAudioContext.pause();
+			}
+		},
+		onUnload() {
+			this.recorderManager = null
+			if(innerAudioContext) {
+				innerAudioContext.destroy()
+				innerAudioContext = null
+			}
+		},
+		methods: {
+			tabclick(type) {
+				if(type == this.current) return
+				if(this.btnLoading || this.status == 'start') {
+					uni.showToast({
+						title: '生成中,请勿进行其他操作!',
+						icon: 'none'
+					})
+				} else if(this.status == 'end') {
+					const that = this
+					uni.showModal({
+						title: '提示',
+						content: '当亲录制已完成,切换类型需要重新录制,确认切换吗?',
+						success: function (res) {
+							if (res.confirm) {
+								const item = {
+									index: type,
+									...that.tabs[type]
+								}
+								that.tabChange(item)
+							} else if (res.cancel) {
+								console.log('用户点击取消');
+							}
+						}
+					});
+				}
+			},
+			tabChange(item){
+				console.log("tabChange")
+				if(this.current == item.index) return
+				if(this.btnLoading || this.status == 'start') {
+					uni.showToast({
+						title: '生成中,请勿进行其他操作!',
+						icon: 'none'
+					})
+				}
+				this.current = item.index
+				this.recorderManager = null
+				if(innerAudioContext) {
+					innerAudioContext.stop();
+					innerAudioContext.destroy()
+					innerAudioContext = null
+				}
+				this.voicePath = this.recordType == 1 ? this.voicePath : ''
+				this.status = this.recordType == 1 ? this.status : "stop"
+				this.isVoicePlay = false
+				this.btnLoading = false
+				this.initDate()
+			},
+			initDate() {
+				// #ifndef H5
+				this.recorderManager = uni.getRecorderManager();
+				innerAudioContext = uni.createInnerAudioContext();
+				
+				
+				
+				let self = this;
+				if(this.recorderManager) {
+					this.recorderManager.onStart(()=>{
+						this.status = 'start'
+						this.voicePath = ''
+					})
+					this.recorderManager.onStop((res)=> {
+						// console.log('recorder stop' + JSON.stringify(res));
+						this.status = 'end'
+						self.voicePath = res.tempFilePath;
+					});
+				}
+				if(innerAudioContext) {
+					// innerAudioContext.autoplay = true;
+					innerAudioContext.onPlay(() => {
+					  // console.log('开始播放');
+					  this.isVoicePlay = true
+					});
+					innerAudioContext.onStop(() => {
+					  // console.log('停止播放');
+					  this.isVoicePlay = false
+					});
+					innerAudioContext.onEnded(() => {
+					  // console.log('播放结束');
+					  this.isVoicePlay = false
+					});
+					innerAudioContext.onError((res) => {
+					  this.isVoicePlay = false
+					});
+					innerAudioContext.onPause(() => {
+					  // console.log('暂停播放');
+					  this.isVoicePlay = false
+					});
+				}
+				// #endif
+			},
+			handleRecord() {
+				if(innerAudioContext){
+					innerAudioContext.pause();
+				}
+				if(this.current == 1) {
+					if(this.status == 'stop') {
+						this.creatVoice()
+					} else if(this.status == 'start') {
+						uni.showToast({
+							title: '生成中,请勿进行其他操作!',
+							icon: 'none'
+						})
+					} else if(this.status == 'end'||this.status == 'ok') {
+						this.creatVoice()
+					}
+				} else {
+					if(this.status == 'stop') {
+						this.startRecord()
+					} else if(this.status == 'start') {
+						this.endRecord()
+					} else if(this.status == 'end'||this.status == 'ok') {
+						this.startRecord()
+					}
+				}
+			},
+			startRecord() {
+				// console.log('开始录音');
+				this.recorderManager.start({
+					format: 'mp3',
+				});
+			},
+			endRecord() {
+				// console.log('录音结束');
+				this.recorderManager.stop();
+			},
+			playVoice() {
+				if(this.status == "start") return
+				if (this.voicePath) {
+					if(this.isVoicePlay == false) {
+						innerAudioContext.src = this.voicePath;
+						innerAudioContext.play();
+					} else {
+						innerAudioContext.stop();
+					}
+				}
+			},
+			onSubmit() {
+				if(this.status == "start") return
+				this.btnLoading = true
+				uni.showLoading({
+					title:"提交中..."
+				})
+				if(this.current == 1) {
+					this.creatVoice()
+					return
+				}
+				uni.uploadFile({
+					url: uni.getStorageSync('requestPath')+'/app/common/uploadOSS', //仅为示例,非真实的接口地址
+					filePath: this.voicePath,
+					name: 'file',
+					success: (uploadFileRes) => {
+						console.log("companyUserVoiceNew==",JSON.parse(uploadFileRes.data).url)
+						let voicePrintUrl = JSON.parse(uploadFileRes.data).url
+						companyUserVoiceNew({userVoiceUrl: voicePrintUrl,id:this.id,companyUserId:uni.getStorageSync('CompanyUserInfoId')}).then(res=>{
+							uni.hideLoading()
+							this.btnLoading = false
+							if(res.code==200){
+								uni.showToast({
+									icon:'none',
+									title: '提交成功',
+								});
+								uni.$emit('refreshVoiceList')
+								setTimeout(()=>{
+									uni.navigateBack()
+								},2000)
+							}else{
+								uni.showToast({
+									icon:'none',
+									title: res.msg,
+									duration: 2000
+								});
+							}
+						}).catch(()=>{
+							uni.hideLoading()
+							this.btnLoading = false
+						})
+					},
+					fail: ()=>{
+						uni.hideLoading()
+						this.btnLoading = false
+					}
+				});
+			},
+			getDetail() {
+				queryDetail(this.id).then(res=>{
+					if(res.code==200){
+						this.voiceText = res.data.voiceTxt
+						this.recordType = res.data.recordType
+						if(this.recordType == 1) {
+							this.voicePath = res.data.wavUrl||''
+							this.status = 'ok'
+							if(this.voicePath&&this.voicePath.match(/\.mp3$/)) {
+								this.current = 0
+							} else {
+								this.current = 1
+							}
+						}
+						this.$nextTick(()=>{
+							const query = uni.createSelectorQuery().in(this);
+							query
+							  .select(".voice-footer")
+							  .boundingClientRect((data) => {
+								this.textHeight = `calc(${this.screenHeight} - ${data.height}px - ${this.statusBarHeight} - 45px - ${uni.upx2px(120)}px)`
+							  })
+							  .exec();
+						})
+					}else{
+						uni.showToast({
+							icon:'none',
+							title: res.msg,
+						});
+					}
+				})
+			},
+			// 智能生成
+			creatVoice() {
+				if(this.status == "start") return
+				this.btnLoading = true
+				this.status = "start"
+				this.voicePath = ''
+				uni.showLoading({
+					title:"生成中..."
+				})
+				companyUserVoice({
+					id: this.id,
+					companyUserId:uni.getStorageSync('CompanyUserInfoId')
+				}).then(res=>{
+					uni.hideLoading()
+					this.btnLoading = false
+					if(res.code==200){
+						this.status = "end"
+						this.voicePath = res.data.wavUrl
+						uni.showToast({
+							icon:'none',
+							title: '生成成功',
+						});
+						uni.$emit('refreshVoiceList')
+						setTimeout(()=>{
+							uni.navigateBack()
+						},2000)
+					}else{
+						this.status = "stop"
+						uni.showToast({
+							icon:'none',
+							title: res.msg,
+							duration: 2000
+						});
+					}
+				}).catch(()=>{
+					uni.hideLoading()
+					this.btnLoading = false
+					this.status = "stop"
+				})
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	@mixin u-flex($flexD, $alignI, $justifyC) {
+		display: flex;
+		flex-direction: $flexD;
+		align-items: $alignI;
+		justify-content: $justifyC;
+	}
+	.smallcircle-filled {
+		background-color: #fff;
+		width: 70rpx;
+		height: 70rpx;
+		border-radius: 50%;
+	}
+	.tabs {
+		position: relative;
+		width: 100%;
+		.mask {
+			position: absolute;
+			top: 0;
+			left: 0;
+			width: 100%;
+			height: 100%;
+			z-index: 3;
+			@include u-flex(row,flex-start,flex-start);
+			view {
+				flex: 1;
+				height: 100%;
+			}
+		}
+	}
+	.container {
+		position: relative;
+		.header-tips {
+			padding-bottom: 24rpx;
+			box-sizing: border-box;
+			font-family: PingFang SC, PingFang SC;
+			font-weight: 400;
+			font-size: 24rpx;
+			color: #757575;
+			// color: $mainThemeHColor;
+			text-align: center;
+		}
+		.textbox {
+			padding: 24rpx 50rpx;
+			box-sizing: border-box;
+			&-con {
+				padding: 32rpx;
+				box-sizing: border-box;
+				background-color: #fff;
+				border-radius: 16rpx 16rpx 16rpx 16rpx;
+				font-family: PingFang SC, PingFang SC;
+				font-weight: 500;
+				font-size: 40rpx;
+				color: #222222;
+				overflow-y: auto;
+				line-height: 60rpx;
+				letter-spacing: 4rpx;
+			}
+		}
+		.voice-footer {
+			position: fixed;
+			bottom: 0;
+			left: 0;
+			width: 100%;
+			box-sizing: border-box;
+			&-tips {
+				padding: 0 50rpx;
+				box-sizing: border-box;
+				font-family: PingFang SC, PingFang SC;
+				font-weight: 400;
+				font-size: 24rpx;
+				color: #757575;
+				margin-bottom: 10rpx;
+			}
+		}
+	}
+	.voice-footer-btnbox {
+		margin-top: 100rpx;
+		background-color: #fff;
+		text-align: center;
+		font-family: PingFang SC, PingFang SC;
+		font-weight: 400;
+		font-size: 30rpx;
+		color: #333;
+		.voice-footer-con {
+			padding: 50rpx 24rpx;
+			box-sizing: border-box;
+			@include u-flex(row,flex-end,space-evenly);
+		}
+		.iconsbox {
+			height: 110rpx;
+			width: 110rpx;
+			margin: 0;
+			margin-bottom: 20rpx;
+			box-sizing: border-box;
+			@include u-flex(row,center,center);
+			border-radius: 50%;
+			background-color: #fff;
+			border: 1rpx solid #CCCCCC;
+			&::after {
+				border: none;
+			}
+			&-voice {
+				height: 150rpx;
+				width: 150rpx;
+				background-color: #FF5C03;
+				border: 1rpx solid #FF5C03;
+				image {
+					height: 60rpx;
+					width: 60rpx;
+				}
+			}
+		}
+		.btnbox-item {
+			flex: 1;
+			@include u-flex(column,center,center);
+		}
+		
+	}
+</style>

+ 248 - 0
pages_company/voiceList.vue

@@ -0,0 +1,248 @@
+<template>
+	<view class="content">
+		<u-sticky>
+			<view class="tabs">
+				<u-tabs :scrollable="false" :list="tabs" :current="current" lineColor="#FF5C03" @change="tabChange">
+				</u-tabs>
+			</view>
+		</u-sticky>
+		<mescroll-body :bottom="bottom+'px'" ref="mescrollRef" :height="height+'px'" @init="mescrollInit"
+			:down="downOption" :up="upOption" @down="downCallback" @up="upCallback">
+			<view class="list">
+				<view class="list-item" v-for="item in dataList" :key="item.id">
+					<view class="list-top ellipsis2" @click="navTo('./voiceItem?id='+item.id)">{{item.voiceTxt}}</view>
+					<view class="list-cont x-bc">
+						<text class="duration">{{secondsToHoursAndMinutes(item.duration || 0)}}</text>
+						<view class="btns" v-show="current==0" @click="navTo('./voiceItem?type=2&id='+item.id)">录制</view>
+						<view class="btns" v-show="current==1" @click="navTo('./voiceItem?id='+item.id)">录制</view>
+						<view class="btns" v-show="current==2" @click="navTo('./voiceItem?id='+item.id)">详情</view>
+					</view>
+				</view>
+			</view>
+		</mescroll-body>
+		<view class="footer" id="footer-btn" v-show="current==1&&dataList&&dataList.length>0">
+			<button class="footer-btn" @click="handleAllVoice">一键生成所有录制</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
+	import {
+		querySopVoiceList,
+		createUserAllVoice
+	} from '@/api/companyUser'
+	export default {
+		mixins: [MescrollMixin], // 使用mixin
+		data() {
+			return {
+				current: 0,
+				tabs: [
+					{
+						id: 2,
+						name: '声音录制'
+					}, {
+						id: 0,
+						name: '未完成'
+					},
+					{
+						id: 1,
+						name: '已完成'
+					}
+				],
+				mescroll: null,
+				downOption: { //下拉刷新
+					use: true,
+					auto: false // 不自动加载 (mixin已处理第一个tab触发downCallback)
+				},
+				upOption: {
+					onScroll: false,
+					use: true, // 是否启用上拉加载; 默认true
+					page: {
+						pae: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始
+						size: 10 // 每页数据的数量,默认10
+					},
+					noMoreSize: 10, // 配置列表的总数量要大于等于5条才显示'-- END --'的提示
+					textNoMore: "已经到底了",
+					empty: {
+						icon: 'https://cos.his.cdwjyyh.com/fs/20240423/cf4a86b913a04341bb44e34bb4d37aa2.png',
+						tip: '暂无数据'
+					}
+				},
+				dataList: [],
+				height: 0,
+				bottom: 0,
+				companyUserId:null
+			}
+		},
+		onLoad(option) {
+			this.companyUserId=option.companyUserId
+			uni.$on('refreshVoiceList', () => {
+				this.mescroll.resetUpScroll()
+			})
+			
+		},
+		onUnload() {
+			uni.$off('refreshVoiceList')
+		},
+		methods: {
+			getHeight() {
+				this.$nextTick(() => {
+					const query = uni.createSelectorQuery().in(this);
+					query
+						.select("#footer-btn")
+						.boundingClientRect((data) => {
+							if (data) {
+								this.height = uni.getSystemInfoSync().windowHeight - data.height - 44
+								this.bottom = data.height
+							}
+						})
+						.exec();
+				})
+			},
+			secondsToHoursAndMinutes(totalSeconds) {
+				let hours = Math.floor(totalSeconds / 3600);
+				let minutes = Math.floor((totalSeconds % 3600) / 60);
+				let seconds = totalSeconds % 60;
+				hours = hours.toString().padStart(2, '0');
+				minutes = minutes.toString().padStart(2, '0');
+				seconds = seconds.toString().padStart(2, '0');
+				return hours + ':' + minutes + ':' + seconds;
+			},
+			tabChange(item) {
+				if (this.current == item.index) return
+				this.current = item.index
+				this.mescroll.resetUpScroll()
+			},
+			navTo(url) {
+				uni.navigateTo({
+					url: url
+				})
+			},
+			mescrollInit(mescroll) {
+				this.mescroll = mescroll;
+			},
+			/*下拉刷新的回调 */
+			downCallback() {
+				this.mescroll.resetUpScroll()
+			},
+			/*上拉加载的回调*/
+			upCallback(page) {
+				//联网加载数据
+				var that = this;
+				var data = {
+					recordType: this.tabs[this.current].id,
+					pageNum: page.num,
+					pageSize: page.size,
+					companyUserId:this.companyUserId,
+				};
+				querySopVoiceList(data).then(res => {
+					if (res.code == 200) {
+						if (page.num == 1) {
+							that.dataList = res.rows;
+							that.getHeight()
+						} else {
+							that.dataList = that.dataList.concat(res.rows);
+
+						}
+						that.mescroll.endBySize(res.rows.length, res.total);
+
+					} else {
+						uni.showToast({
+							icon: 'none',
+							title: "请求失败",
+						});
+						that.dataList = null;
+						that.mescroll.endErr();
+					}
+				});
+			},
+			handleAllVoice() {
+				createUserAllVoice().then(res => {
+					uni.showToast({
+						icon: 'none',
+						title: res.msg,
+						duration: 2000
+					});
+				})
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	@mixin u-flex($flexD, $alignI, $justifyC) {
+		display: flex;
+		flex-direction: $flexD;
+		align-items: $alignI;
+		justify-content: $justifyC;
+	}
+
+	.content {
+		.tabs {
+			background-color: #fff;
+		}
+
+		.list {
+			width:100%;
+			padding: 15rpx;
+			@include u-flex(column, flex-start, flex-start);
+
+			.list-item {
+				margin-bottom: 15rpx;
+				width:100%;
+				padding: 15rpx;
+				box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.05);
+				background-color: #fff;
+				border-radius: 15rpx;
+				@include u-flex(column, flex-start, flex-start);
+			}
+
+			.list-cont {
+				margin-top: 24rpx;
+				width: 100%;
+			}
+		}
+
+		.duration {
+			box-sizing: border-box;
+			font-family: PingFang SC, PingFang SC;
+			font-weight: 400;
+			font-size: 24rpx;
+			color: #757575;
+		}
+
+		.btns {
+			padding: 10rpx 30rpx;
+			border: 1rpx solid #FF5C03;
+			color: #FF5C03;
+			font-size: 28rpx;
+			border-radius: 30rpx;
+		}
+	}
+
+	.footer {
+		width: 100%;
+		height: 152rpx;
+		padding: 20rpx 24rpx;
+		box-sizing: border-box;
+		position: fixed;
+		bottom: var(--window-bottom);
+		left: 0;
+
+		&-btn {
+			height: 112rpx;
+			background: #FF5C03;
+			border-radius: 112rpx;
+			font-weight: 600;
+			font-size: 34rpx;
+			color: #FFFFFF;
+			line-height: 112rpx;
+			text-align: center;
+
+			&::after {
+				border: none;
+			}
+		}
+	}
+</style>

+ 3 - 1
pages_company/wechatcode.vue

@@ -3,7 +3,7 @@
 		<view class="codeimg">
 			<view v-if="wechatImg!=null" class="centerV">
 				<image :src="wechatImg" style="width: 100%;" mode="aspectFit" :show-menu-by-longpress="true" ></image>
-				<view class="centerV">点击保存图片至本地!</view>
+				<view class="centerV">点击保存或长按图片保存至本地!</view>
 			</view>
 			<view v-else>
 				<image src="https://hst2-1323137866.cos.ap-chongqing.myqcloud.com/shop/images/no_data.png" style="width: 100%;"
@@ -68,6 +68,7 @@
 			},
 			generatecode() {
 				const data = {
+					companyUserId:uni.getStorageSync('companyUserInfoId'),
 					companyId: this.companyId,
 					appId: wx.getAccountInfoSync().miniProgram.appId
 				}
@@ -85,6 +86,7 @@
 			},
 			getcomapycodes() {
 				const data = {
+					companyUserId:uni.getStorageSync('companyUserInfoId'),
 					companyId: this.companyId,
 					appId: wx.getAccountInfoSync().miniProgram.appId
 				}

+ 17 - 9
pages_course/becomeVIP.vue

@@ -81,7 +81,7 @@
 			</view>
 		</u-popup>
 		<!--#endif-->
-		<view class="footer-tips">重庆云联融智提供技术支持</view>
+		<!-- <view class="footer-tips">重庆云联融智提供技术支持</view> -->
 	</view>
 </template>
 
@@ -156,13 +156,21 @@
 			let obj=uni.getStorageSync('TOKEN_KEY');
 			// #endif
 			// let obj=uni.getStorageSync('AppToken');
+			let becomeVip={}
+			if(!option.becomeVip){
+				const keys = decodeURIComponent(Object.keys(option)[0]);
+				becomeVip=JSON.parse(keys.split('becomeVip=')[1])
+				console.log(becomeVip)
+			}else{
+				becomeVip = option.becomeVip ? JSON.parse(decodeURIComponent(option.becomeVip)) : {}
+			}
 			this.isLogin = !!obj;
-			this.companyid = option.companyId || ''
-			this.companyUserId=option.companyUserId || 0
-			this.projectId=option.projectId
-			this.H5course.companyId=option.companyId
-			this.H5course.companyUserId=option.companyUserId
-			this.H5course.projectId=option.projectId
+			this.companyid = becomeVip.companyId || ''
+			this.companyUserId=becomeVip.companyUserId || 0
+			this.projectId=becomeVip.projectId
+			this.H5course.companyId=becomeVip.companyId
+			this.H5course.companyUserId=becomeVip.companyUserId
+			this.H5course.projectId=becomeVip.projectId
 			uni.setStorageSync('H5course',this.H5course)
 			console.log(this.H5course)
 			//#ifdef MP-WEIXIN
@@ -176,10 +184,10 @@
 				return
 			}
 			//#endif
-			if(option.tagids=="null"){
+			if(becomeVip.tagids==null||becomeVip.tagids==''){
 				this.tagIds=[]
 			}else{
-				this.tagIds=option.tagids 
+				this.tagIds=becomeVip.tagids 
 				const arr =this.tagIds.split(",")
 				  .map(item => parseInt(item.trim(), 10))
 				  .filter(num => !isNaN(num)); // 过滤无效转换

+ 65 - 0
pages_course/components/courseExpiration.vue

@@ -0,0 +1,65 @@
+<template>
+	<view class="container-body">
+		<text class="user" v-if="userId">#{{userId}}</text>
+		<image class="kfqrcode" v-if="qrcode" :src="qrcode" show-menu-by-longpress="true"></image>
+		<image v-else src="/static/course_expiration_img.png" mode="aspectFill"></image>
+		<u-parse class="title" :content="msg"></u-parse>
+		<view style="margin-bottom: 10vh;" v-show="code">状态码:{{code}}</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props:['code','qrcode','msg','userId'],
+		data() {
+			return {
+			
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.kfqrcode {
+		height: 460rpx;
+		width: 460rpx;
+	}
+	.container-body {
+		background-color: #fff;
+		position: fixed;
+		top: 0;
+		right: 0;
+		z-index: 9998;
+		justify-content: center;
+		font-family: PingFang SC, PingFang SC;
+		font-weight: 400;
+		font-size: 32rpx;
+		color: #757575;
+		line-height: 48rpx;
+		text-align: center;
+		height: 100vh;
+		width: 100vw;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		.title {
+			font-weight: bold;
+			font-size: 40rpx;
+			color: #1E2F67;
+			margin-bottom: 24rpx;
+			padding: 0 60rpx;
+		}
+		image {
+			width: 428rpx;
+			height: 360rpx;
+			margin-bottom: 30rpx;
+		}
+		.user {
+			position: absolute;
+			right: 24rpx;
+			top: 124rpx;
+			z-index: 9999;
+		}
+	}
+</style>

+ 113 - 0
pages_course/components/yk-screenRecord/yk-screenRecord.vue

@@ -0,0 +1,113 @@
+<template>
+	<view class="zzc_mol" v-if="isRecording"></view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				isRecording: false
+			}
+		},
+		created() {
+			this.screenInit();
+		},
+		onUnload() {
+			this.AllowScreenshots()
+		},
+		methods: {
+			screenInit() {
+				let _this = this;
+				// #ifdef H5
+				uni.showToast({
+					title: '请在APP或者小程序环境下操作',
+					icon: 'error'
+				})
+				// #endif
+				// #ifndef H5
+				uni.getSystemInfo({
+					success: function(e) {
+						// #ifdef APP-PLUS
+						if (e.platform == 'android') {
+							//注意:一旦开启禁止截屏/录屏后将会全局生效,关闭页面时记得放开允许截屏/录屏
+							_this.NoscreenCapture();
+						} else {
+							//在APP IOS端截屏、录屏暂时没办法实现,可以寻求原生解决
+						}
+						// #endif
+
+						// #ifdef MP-WEIXIN
+						if (e.platform == 'android') {
+							//微信小程序在安卓手机上 禁止截屏/录屏(注意:禁止后录屏动作还是会进行,但录屏后的视频是黑屏的)
+							wx.setVisualEffectOnCapture({
+								visualEffect: 'hidden', //传入 hidden 则表示在截屏/录屏时隐藏屏幕
+								success: (res) => {
+									console.log(res)
+								},
+								fail: (err) => {
+									console.log(err)
+								},
+								complete: (res) => {
+									console.log(res)
+								}
+							})
+						} else {
+							//微信小程序在IOS手机上,注意:目前微信小程序在ios上也只能通过监听录屏状态,然后通过添加view层来进行阻止,截屏暂时无法实现
+							//监听用户录屏事件
+							wx.onScreenRecordingStateChanged(function(res) {
+								if (res.state == 'start') {
+									_this.isRecording = true
+								} else {
+									_this.isRecording = false
+								}
+							})
+							//查询用户是否在录屏
+							wx.getScreenRecordingState({
+								success: (res) => {
+									if (res.state == 'on') {
+										_this.isRecording = true
+									} else if (res.state == 'off') {
+										_this.isRecording = false
+									}
+								},
+								fail: (err) => {
+									_this.isRecording = false
+								}
+							})
+						}
+						// #endif
+					}
+				})
+				// #endif
+			},
+			//安卓端禁止截屏
+			NoscreenCapture() {
+				let osname = plus.os.name;
+				if (osname == "Android") {
+					var activity = plus.android.runtimeMainActivity();
+					plus.android.invoke(plus.android.invoke(activity, "getWindow"), "addFlags", 0x00002000);
+				}
+			},
+			//安卓端允许截屏  
+			AllowScreenshots() {
+				let osname = plus.os.name;
+				if (osname == "Android") {
+					var activity = plus.android.runtimeMainActivity();
+					plus.android.invoke(plus.android.invoke(activity, "getWindow"), "clearFlags", 0x00002000);
+				}
+			}
+		}
+	}
+</script>
+
+<style>
+	.zzc_mol {
+		background: #000;
+		width: 100%;
+		height: 100%;
+		position: fixed;
+		z-index: 99999;
+		top: 0;
+		left: 0;
+	}
+</style>

+ 1 - 1
pages_course/reward.vue

@@ -6,7 +6,7 @@
 		<view class="answerPopup-title">恭喜你,回答正确</view>
 		<view class="answerPopup-desc">您有一份奖励待领取哦</view>
 		<view class="answerPopup-btn" @click="handleReceive">领取</view>
-		<view class="footer-tips">重庆云联融智提供技术支持</view>
+		<!-- <view class="footer-tips">重庆云联融智提供技术支持</view> -->
 	</view>
 </template>
 

+ 106 - 16
pages_course/video.vue

@@ -257,6 +257,9 @@
 				<button class="send" @click="handleChatInput">发送</button>
 			</view>
 		</view>
+		<ykscreenRecord></ykscreenRecord>
+		<courseExpiration v-if="showExpiration" :code="resCode" :msg="resMsg" :qrcode="qrcode"
+		:userId="user && user.userId ? user.userId : ''"></courseExpiration>
 	</view>
 </template>
 
@@ -267,6 +270,9 @@
 	import commentBox from "./components/commentBox.vue"
 	import {TOKEN_KEYAuto,generateRandomString} from '@/utils/courseTool.js'
 	import dayjs from 'dayjs';
+	import { mapGetters } from 'vuex';
+	import ykscreenRecord from '@/components/yk-screenRecord/yk-screenRecord.vue'
+	import courseExpiration from './components/courseExpiration.vue'
 	import {
 		getErrMsg,
 		getH5CourseByVideoId,
@@ -278,7 +284,8 @@
 		getIntegralByH5Video,
 		sendReward,
 		loginByMp,
-		getRealLink
+		getRealLink,
+		userLoginIp
 	} from "@/api/courseAuto.js"
 	import {
 		getConfigByKey
@@ -290,9 +297,14 @@
 			descInfo,
 			commentBox,
 			ques,
+			ykscreenRecord,
+			courseExpiration
 		},
 		data() {
 			return {
+				resMsg:'',
+				resCode:"",
+				showExpiration:false,
 				code: '',
 				baseUrl:uni.getStorageSync('requestPath'),
 				// 1 红包 2 积分
@@ -352,6 +364,7 @@
 				// 是否允许拖动进度条
 				videolinkType: 0,
 				ip: null,
+				saveIp:'',
 				checked: true,
 				isFinish: 0, // 是否完课
 				interval: null,
@@ -453,24 +466,42 @@
 			isSpare() {
 				return this.$store.state.isSpare
 			},
+			...mapGetters(['coureLogin']),
+		},
+		watch: {
+		    coureLogin: {
+		      immediate: true,          // 页面一进入就检查一次
+		      handler(val) {
+		        if (val == 2&&this.isLogin) {
+					console.log("看课AppToken失效,请重新登录")
+					this.isLogin = false
+					this.isAddKf = 0
+					this.goLogin()
+		        }
+		      }
+		    }
 		},
 		onLoad(option) {
 			this.getWebviewUrl()
-			if(option.videoitem){
-				this.isOpen = 1
-				this.urlOption=JSON.parse(option.videoitem)
-				this.urlOption = {
-					...this.urlOption,
-					isOpen: 1
+			if(!option.course){
+				if(option.videoitem){
+					this.isOpen = 1
+					this.urlOption=JSON.parse(option.videoitem)
+					this.urlOption = {
+						...this.urlOption,
+						isOpen: 1
+					}
+				}else{
+					this.isOpen = 0
+					const keys = decodeURIComponent(Object.keys(option)[0]);
+					this.urlOption = JSON.parse(keys.split('course=')[1])
 				}
-			}else {
+			}else{
 				this.isOpen = 0
-				console.log(option)
-				this.urlOption = option.course ? JSON.parse(option.course) : {}
-				console.log(this.urlOption)
+				this.urlOption = option.course ? JSON.parse(decodeURIComponent(option.course)) : {}
 			}
 			uni.$on('usercode',(data)=>{
-				if(this.isSpare == 1&&data) {
+				if(data) {
 					this.code=data.code
 					this.goLogin(data)
 				}
@@ -497,6 +528,7 @@
 			this.uuId = generateRandomString(16)
 			if(uni.getStorageSync('auto_userInfo') && JSON.stringify(uni.getStorageSync('auto_userInfo'))!='{}') {
 				this.user = JSON.parse(uni.getStorageSync('auto_userInfo'))
+				this.handleFsUserWxs()
 			} else {
 				this.user = {}
 			}
@@ -553,6 +585,36 @@
 			// #endif
 		},
 		methods: {
+			handleFsUserWxs(){
+				uni.login({
+					provider: "weixin",
+					success: async loginRes => {
+						let code = loginRes.code // 获取开发code
+						handleFsUserWx({
+						   code: code,
+						   appId:this.appid,
+						   userId:this.user.userId
+						})
+						.then( res => {
+							if(res.code==200){
+							}else if(res.code==406){
+								uni.hideLoading();
+								uni.showToast({
+									icon:'none',
+									title: '该用户已成为其他销售会员',
+								});
+							}else{
+								uni.hideLoading();
+								uni.showToast({
+									icon:'none',
+									title: res.msg,
+								});
+							}
+						   
+						 })
+					},
+				})
+			},
 			getWebviewUrl() {
 				var data = {
 					key: 'course.config'
@@ -678,9 +740,21 @@
 					method: 'GET',
 					success: (res) => {
 						this.ip = res.data.ip
+						if(this.isLogin){
+							this.saveIpFun()
+						}
 					}
 				});
 			},
+			saveIpFun() {
+				if(this.ip&&this.saveIp!=this.ip){
+					userLoginIp({userIp:this.ip}).then(res=>{
+						if(res.code==200) {
+							this.saveIp = this.ip
+						}
+					})
+				}
+			},
 			getHeight() {
 				setTimeout(()=>{
 					const query = uni.createSelectorQuery().in(this);
@@ -818,6 +892,11 @@
 									questionOption: JSON.parse(item.question),
 									answer: ''
 								}))
+						}else{
+							uni.showToast({
+								title: res.msg,
+								icon: "none"
+							})
 						}
 						this.getHeight()
 						this.$nextTick(()=>{
@@ -1118,9 +1197,7 @@
 							this.qrcode = res.qrcode
 							this.qrcodeMsg = res.msg
 							this.$refs.kfPopup.open()
-						} else if (res.code == 504) {
-							// 登录
-							// this.goLogin()
+							this.initExpiration(res.msg,res.code)
 						} else if (res.code == 566) {
 							// 官方群发通用链接
 							const url = res.courseLink.realLink.split('?course=')[1]
@@ -1141,11 +1218,18 @@
 								title: res.msg,
 								icon: 'none'
 							});
+							this.initExpiration(res.msg,res.code)
 						}
 					},
 					err => {}
 				);
 			},
+			initExpiration(resMsg,resCode) {
+				if(resCode==401) return;
+				this.resMsg = resMsg
+				this.resCode = resCode
+				this.showExpiration = true
+			},
 			closeKFPop() {
 				this.$refs.kfPopup.close()
 			},
@@ -1231,12 +1315,14 @@
 								}).then(res=>{
 									 uni.hideLoading();
 									 if (res.code == 200) {
+										 this.$store.commit('setCoureLogin', 1);
 										uni.setStorageSync(TOKEN_KEYAuto, res.token);
 										uni.setStorageSync('auto_userInfo', JSON.stringify(res.user));
 										this.user = res.user
 										this.isLogin = true
 										console.log("TOKEN_KEYAuto",TOKEN_KEYAuto)
 										this.getIsAddKf() 
+										this.saveIpFun()
 									 } else {
 										uni.showToast({
 											title: res.msg,
@@ -1268,6 +1354,7 @@
 								this.isLogin = isLogin
 								if(isLogin){
 									this.getIsAddKf() 
+									this.saveIpFun()
 								} else {
 									this.goLogin()
 								}
@@ -1291,6 +1378,7 @@
 									this.isLogin = isLogin
 									if(isLogin){
 										this.getIsAddKf() 
+										this.saveIpFun()
 									} else {
 										this.goLogin()
 									}
@@ -1475,6 +1563,7 @@
 							.then( res => {
 								uni.hideLoading();
 								if(res.code==200){
+									this.getIP()
 									console.log("loginFsUserWx:",res)
 									// this.userinfos=uni.getStorageSync('userinfos')
 									let token = uni.getStorageSync('TOKEN_WEXIN');
@@ -1485,7 +1574,8 @@
 									uni.setStorageSync('auto_userInfo', JSON.stringify(user));
 									this.user = user
 									this.isLogin = true
-									this.getIsAddKf() 
+									this.getIsAddKf()
+									 this.saveIpFun()
 								}else if(res.code==406){
 									uni.showToast({
 										icon:'none',

+ 76 - 20
pages_course/videovip.vue

@@ -247,7 +247,7 @@
 				<view class="submitname" @click="confimrname" :class="nameuser&&avataruser?'subact':'sub'">确定</view>
 			</view>
 		</u-popup>
-		<view class="footer-tips">重庆云联融智提供技术支持</view>
+		<!-- <view class="footer-tips">重庆云联融智提供技术支持</view> -->
 		<!-- footer -->
 		<view class="footer" v-if="videoId">
 			<view class="btns"  >
@@ -268,12 +268,18 @@
 		</view>
 		<u-loading-page :loading="viewload" iconSize="32" loadingColor="#3c9cff" fontSize="24"
 		:loading-text="loadingtext"></u-loading-page>
+		<ykscreenRecord></ykscreenRecord>
+		<courseExpiration v-if="showExpiration" :code="resCode" :msg="resMsg" :qrcode="qrcode"
+		:userId="user && userInfo.userId ? userInfo.userId : ''"></courseExpiration>
 	</view>
 </template>
 
 <script>
 	import { generateRandomString} from "@/utils/common.js"
 	import dayjs from 'dayjs';
+	import { mapGetters } from 'vuex';
+	import ykscreenRecord from '@/components/yk-screenRecord/yk-screenRecord.vue'
+	import courseExpiration from './components/courseExpiration.vue'
 	import {
 		getErrMsg,
 		getH5CourseByVideoId,
@@ -286,14 +292,22 @@
 		sendReward,
 		getRealLink,
 		loginByMiniApp,
-		handleFsUserWx
+		handleFsUserWx,
+		userLoginIp
 	} from "@/api/courseLook.js"
 	import {
 		getConfigByKey
 	} from "@/api/user.js"
 	export default {
+		components:{
+			ykscreenRecord,
+			courseExpiration
+		},
 		data() {
 			return {
+				resMsg:'',
+				resCode:"",
+				showExpiration:false,
 				videoItem:{},
 				viewload:true,
 				loadingtext:"数据加载中...",
@@ -423,6 +437,7 @@
 				projectId:'',
 				showfalse:false,
 				contentmsg:null,
+				saveIp:''
 			}
 		},
 		filters: {
@@ -463,6 +478,20 @@
 			avataruser() {
 				return this.userinfos.avatar
 			},
+			...mapGetters(['coureLogin']),
+		},
+		watch: {
+		    coureLogin: {
+		      immediate: true,          // 页面一进入就检查一次
+		      handler(val) {
+		        if (val == 2&&this.isLogin) {
+					console.log("看课AppToken失效,请重新登录")
+					this.isLogin = false
+					this.isAddKf = 0
+					this.goLogin()
+		        }
+		      }
+		    }
 		},
 		onLoad(option) {
 			this.getWebviewUrl()
@@ -492,7 +521,7 @@
 				const keys = decodeURIComponent(Object.keys(option)[0]);
 				this.urlOption=JSON.parse(keys.split('course=')[1])
 			}else{
-				this.urlOption = option.course ? JSON.parse(option.course) : {}
+				this.urlOption = option.course ? JSON.parse(decodeURIComponent(option.course)) : {}
 			}
 			uni.setStorageSync('H5course',this.urlOption)
 			this.videoId = this.urlOption.videoId
@@ -521,7 +550,7 @@
 		},
 		onShow() {
 			this.userinfos=uni.getStorageSync('userinfos')
-			this.userinfo=uni.getStorageSync('userinfo')
+			this.userInfo=uni.getStorageSync('userInfo')
 			this.tipsOpen = false
 			this.isExpand = true
 			this.uuId = generateRandomString(16)
@@ -532,7 +561,8 @@
 			console.log(AppToken)
 			if(AppToken){
 				// this.isLogin=true
-				if(this.isAddKf == 1&&this.userinfo.userId){
+				this.getIP()
+				if(this.isAddKf == 1&&this.userInfo.userId){
 					console.log(1233)
 					this.getH5CourseVideoDetails()
 				} else{
@@ -550,9 +580,7 @@
 			// }
 		},
 		mounted() {
-			// this.getIP()
 			this.getHeight()
-			
 		},
 		onHide() {
 			// this.player = uni.createVideoContext('video-content-box');
@@ -585,6 +613,28 @@
 			this.clearIntegral()
 		},
 		methods: {
+			getIP() {
+				uni.request({
+					url: 'https://ipinfo.io/json', //仅为示例,并非真实接口地址。
+					method: 'GET',
+					success: (res) => {
+						this.ip = res.data.ip
+						if(this.isLogin){
+							this.saveIpFun()
+						}
+					}
+				});
+			},
+			saveIpFun() {
+				console.log('ip:',res.data.ip)
+				if(this.ip&&this.saveIp!=this.ip){
+					userLoginIp({userIp:this.ip}).then(res=>{
+						if(res.code==200) {
+							this.saveIp = this.ip
+						}
+					})
+				}
+			},
 			getWebviewUrl() {
 				var data = {
 					key: 'course.config'
@@ -602,6 +652,7 @@
 						}
 					})
 			},
+			
 			goLogin(data) {
 				if(data){
 					console.log('huoqu1222',data)
@@ -629,10 +680,10 @@
 									uni.getStorageSync('TOKEN_WEXIN');
 									this.userInfo=uni.getStorageSync('userInfo');
 									this.isLogin = true
-									this.getH5CourseVideoDetails()
-									// setTimeout(()=>{
-									// 	this.getIsAddKf()
-									// },200)
+									this.saveIpFun()
+									setTimeout(()=>{
+										this.getIsAddKf()
+									},200)
 								}else if(res.code==406){
 									uni.hideLoading();
 									uni.showToast({
@@ -970,15 +1021,6 @@
 				this.isFinish=1
 				this.getFinishCourseVideo()
 			},
-			getIP() {
-				uni.request({
-					url: 'https://ipinfo.io/json', //仅为示例,并非真实接口地址。
-					method: 'GET',
-					success: (res) => {
-						this.ip = res.data.ip
-					}
-				});
-			},
 			getHeight() {
 				this.$nextTick(() => {
 					const query = uni.createSelectorQuery().in(this);
@@ -1459,11 +1501,14 @@
 				getIsAddKf(data).then(res => {
 						if (res.code == 200) {
 							this.isLogin = true
+							this.saveIpFun()
 							if(res.data){
 								this.isAddKf = 1
 								if(this.userInfo.userId){
 									this.getH5CourseVideoDetails()
 									console.log(123223)
+								}else{
+									this.goLogin()
 								}
 								
 							}
@@ -1481,6 +1526,7 @@
 								title: "请添加管理员微信,成为会员!",
 								icon: 'none'
 							});
+							this.initExpiration(res.msg,res.code)
 						}else if(res.code==505){
 							this.isAddKf = 0
 							this.qrcode=res.ext
@@ -1489,12 +1535,14 @@
 								title: "管理员开启了会员审核,请等待审核!",
 								icon: 'none'
 							});
+							this.initExpiration(res.msg,res.code)
 						}else if(res.code==406){
 							uni.hideLoading();
 							uni.showToast({
 								icon:'none',
 								title: '该用户已成为其他销售会员',
 							});
+							this.initExpiration(res.msg,res.code)
 						}else if(res.code==504){
 							this.isAddKf = 0
 							this.iskftype=1
@@ -1502,17 +1550,25 @@
 								title: res.msg,
 								icon: 'none'
 							});
+							this.initExpiration(res.msg,res.code)
 						}else {
 							this.isAddKf = 0
 							uni.showToast({
 								title: res.msg,
 								icon: 'none'
 							});
+							this.initExpiration(res.msg,res.code)
 						}
 					},
 					err => {}
 				);
 			},
+			initExpiration(resMsg,resCode) {
+				if(resCode==401) return;
+				this.resMsg = resMsg
+				this.resCode = resCode
+				this.showExpiration = true
+			},
 			closeKFPop() {
 				// this.$refs.kfPopup.close()
 				// this.kfPopup=!this.kfPopup

+ 2 - 0
pages_course/webview.vue

@@ -44,6 +44,7 @@ export default {
 	  },
   },
   methods: {
+	 
 	  loginweixin(datas){
 		 console.log(uni.getStorageSync('H5course'))
 		 const h5course=uni.getStorageSync('H5course')
@@ -58,6 +59,7 @@ export default {
 		  		this.res=res
 		  		uni.hideLoading();
 		  		if (res.code == 200) {
+					this.$store.commit('setCoureLogin', 1);
 		  			console.log(res)
 		  			uni.hideLoading();
 		  			uni.showToast({

+ 1 - 1
pages_doctor/paymentOrder.vue

@@ -99,7 +99,7 @@
 				);
 			},
 			payOrder(){
-				var data = {orderId:this.order.orderId};
+				var data = {orderId:this.order.orderId,appId:wx.getAccountInfoSync().miniProgram.appId};
 				var that=this;
 				uni.showLoading();
 				pay(data).then(

+ 68 - 3
pages_manage/components/memberIndex.vue

@@ -255,10 +255,12 @@
 										<image :src="imgPath+'/app/images/card_icon.png'" mode="aspectFill"
 											style="width: 80rpx; height: 80rpx;margin-top: 20rpx;">
 										</image>
-										<view style="font-weight: bold;margin-bottom: 4px;">生成卡片</view>
-										<view style="font-size: 12px;color: #888;">指导分享轻松转发</view>
+										<view class='u-border radius100 plr20 ptb10' @click="copyPageLink"
+										>复制页面地址</view>
+										<!-- <view style="font-weight: bold;margin-bottom: 4px;">生成卡片</view>
+										<view style="font-size: 12px;color: #888;">指导分享轻松转发</view> -->
 										<!-- #ifdef MP-WEIXIN -->
-										<button open-type="share" class="share">分享卡片</button>
+										<!-- <button open-type="share" class="share">分享卡片</button> -->
 										<!-- #endif -->
 									</view>
 									<!--#ifdef H5-->
@@ -339,6 +341,8 @@
 		getusersales,
 		removebalcklist,
 		getallTags,
+		copyuniLink,
+		getlinkCode,
 		getprojectlist
 	} from "@/api/manageCompany.js";
 	import vipUserItem from "../components/vipUserItem.vue"
@@ -603,6 +607,67 @@
 			}
 		},
 		methods: {
+			getlinkCodes(){
+				getlinkCode().then(res=>{
+					if(res.code){
+						this.projectCode=res.code
+						console.log(this.projectCode)
+						setTimeout(()=>{
+							this.setlnk()
+						},100)
+					}
+				})
+			},
+			setlnk(){
+				let params={
+					companyId: this.user.companyId,
+					companyUserId: this.user.userId,
+					tagids: this.sharetaglist,
+					projectCode: this.projectCode,
+					projectId: this.projectId,
+				}
+				const pages = '/pages_course/becomeVIP?becomeVip='+JSON.stringify(params)
+				console.log(pages)
+				const data={
+					appid:wx.getAccountInfoSync().miniProgram.appId,
+					linkStr:pages
+				}
+				copyuniLink(data).then(res=>{
+					if(res.code==200){
+						uni.hideLoading();
+						setTimeout(() => {
+							uni.setClipboardData({
+								data:res.data,
+								success: () => {
+									uni.showToast({
+										title: '链接已复制',
+										icon: 'none',
+										duration: 2000
+									});
+								},
+								fail: () => {
+									uni.showToast({
+										title: '复制失败',
+										icon: 'none'
+									});
+								}
+							});
+						}, 200)
+					}else{
+						uni.hideLoading();
+						uni.showToast({
+							title: res.msg,
+							icon: 'none'
+						});
+					}
+				})
+			},
+			copyPageLink(){
+				uni.showLoading({
+					title: "处理中..."
+				});
+				this.getlinkCodes()
+			},
 			submitPro() {
 				if (this.projectId == '') {
 					uni.showToast({

+ 1 - 1
pages_manage/login.vue

@@ -28,7 +28,7 @@
 				</view>
 			 </view>
 		 </view>
-		 <view class="footer-tips">重庆云联融智提供技术支持</view>
+		 <!-- <view class="footer-tips">重庆云联融智提供技术支持</view> -->
 	</view>
 </template>
 

+ 15 - 4
pages_shopping/shopping/confirmPackageOrder.vue

@@ -116,6 +116,7 @@
 			 </view>
 			 
 		</popupBottom>
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
@@ -123,13 +124,14 @@
 	import {getWeixinTemps} from '@/api/common'
 	import {confirmPackageOrder,computedPackageOrder,createPackageOrder} from '@/api/storeOrder'
 	import { getMyEnableCouponList } from '@/api/coupon'
-	 
+	 import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	import EvanSwitch from '@/components/evan-switch/evan-switch.vue'
 	import popupBottom from '@/components/px-popup-bottom/px-popup-bottom.vue'
 	export default {
 		components: {
 			EvanSwitch,
-			popupBottom
+			popupBottom,
+			ykscreenRecord
 		},
 		data() {
 			return {
@@ -146,6 +148,8 @@
 				// checked: false,
 				// type:null,
 				// cartIds:null,
+				createOrderKey:'',
+				isPackage:0,
 				form:{
 					// useIntegral:0,
 					orderKey:null,
@@ -156,6 +160,11 @@
 			}
 		},
 		onLoad(option) {
+			if(option.createOrderKey){
+				this.createOrderKey=option.createOrderKey
+				this.isPackage=1
+				console.log(this.createOrderKey)
+			}
 			this.packageId=option.packageId;
 			this.companyUserId=option.companyUserId;
 			this.confirmPackageOrder();
@@ -197,7 +206,8 @@
 				})
 			},
 			confirmPackageOrder(){
-				let data = {packageId:this.packageId,couponUserId:this.couponUserId};
+				let data = {packageId:this.packageId,couponUserId:this.couponUserId,
+				createOrderKey:this.createOrderKey};
 				confirmPackageOrder(data).then(
 					res => {
 						if(res.code==200){
@@ -274,7 +284,8 @@
 				uni.showLoading({
 					title: '正在处理中...'
 				});
-				let data = {couponUserId:this.couponUserId,mark:this.form.mark,orderKey:this.form.orderKey,addressId:this.form.addressId,packageId:this.packageId,companyUserId:this.companyUserId};
+				let data = {couponUserId:this.couponUserId,mark:this.form.mark,orderKey:this.form.orderKey,addressId:this.form.addressId,packageId:this.packageId,
+				companyUserId:this.companyUserId,isPackage:this.isPackage};
 				createPackageOrder(data).then(
 					res => {
 						uni.hideLoading()

+ 4 - 3
pages_shopping/shopping/productList.vue

@@ -41,14 +41,14 @@
 					</view>
 					<view class="info-box">
 						<view class="title ellipsis2">{{item.productName}}</view>
-						<view class="intro ellipsis">{{item.productInfo}}</view>
+						<view class="intro ellipsis">{{item.productInfo||''}}</view>
 						<view class="prce-num">
 							<view class="price">
 								<text class="unit">¥</text>
 								<text class="num">{{item.price.toFixed(2)}} </text>
 							</view>
 							<view class="cart-img" @click="navgetTo('../shopping/cart')">
-								<view class="sale">已售 {{item.sales}} {{item.unitName}}</view>
+								<view class="sale">已售 {{item.sales}} {{item.unitName||''}}</view>
 							</view>
 						</view>
 					</view>
@@ -187,7 +187,8 @@
 					cateId:this.cateId,
 					defaultOrder:this.defaultOrder,
 					page: page.num,
-					pageSize: page.size
+					pageSize: page.size,
+					appId:wx.getAccountInfoSync().miniProgram.appId,
 				};
 				getProducts(data).then(res => {
 					if(res.code==200){

+ 6 - 1
pages_user/user/otherPaymentOrder.vue

@@ -48,12 +48,17 @@
 		<view class="btn-box">
 			<view class="btn" @click="pay()">帮TA支付</view>
 		</view>
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
 <script>
 	import {otherPayment,getStoreOrderById} from '@/api/storeOrder'
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	export default {
+		components:{
+			ykscreenRecord
+		},
 		data() {
 			return {
 				payDelivery:0,
@@ -114,7 +119,7 @@
 				});
 			},
 			otherPayment(code){
-				var data = {orderId:this.order.id,code:code };
+				var data = {orderId:this.order.id,code:code,appId:wx.getAccountInfoSync().miniProgram.appId};
 				var that=this;
 				uni.showLoading();
 				otherPayment(data).then(

+ 6 - 1
pages_user/user/otherPaymentOrderRemain.vue

@@ -52,12 +52,17 @@
 		<view class="btn-box">
 			<view class="btn" @click="pay()">帮TA支付</view>
 		</view>
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
 <script>
 	import {otherPaymentRemain,getStoreOrderById} from '@/api/storeOrder'
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	export default {
+		components:{
+			ykscreenRecord
+		},
 		data() {
 			return {
 				payDelivery:0,
@@ -118,7 +123,7 @@
 				});
 			},
 			otherPaymentRemain(code){
-				var data = {orderId:this.order.id,code:code };
+				var data = {orderId:this.order.id,code:code,appId:wx.getAccountInfoSync().miniProgram.appId};
 				var that=this;
 				uni.showLoading();
 				otherPaymentRemain(data).then(

+ 17 - 6
pages_user/user/pay.vue

@@ -4,7 +4,7 @@
 			<view class="inner">
 				<view class="pay">
 					<view class="title">
-						<text class="name">付款给 鸿森堂便民商城</text>
+						<text class="name">付款给 建兴堂</text>
 						<text class="desc">微信收款</text>
 					</view>
 					<view class="pay-money">
@@ -24,14 +24,18 @@
 		<!-- <view class="ad">
 			<ad unit-id="adunit-a018415a6deb69e8"></ad>
 		</view> -->
-		
+		<ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
 <script>
 	import {payment} from '@/api/payment'
 	import { loginByMiniApp} from '@/api/user'
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	export default {
+		components:{
+			ykscreenRecord
+		},
 		data() {
 			return {
 				companyUserId:null,
@@ -52,13 +56,19 @@
 		 //   	this.companyId=obj.companyId;
 			// this.companyUserId=obj.companyUserId;
 		 //   }
+		 console.log(options)
 			this.companyId=options.companyId;		
 			this.companyUserId=options.companyUserId;
-			this.gologin()
+			const AppToken=uni.getStorageSync('AppToken')
+			console.log(AppToken)
+			if(!AppToken||AppToken==''){
+				console.log(AppToken)
+				this.gologin()
+			}
 		},
 		onShareAppMessage(res) {
 			return {
-				title: '鸿森堂便民商城-收款',
+				title: '建兴堂-收款',
 				path: `/pages_user/user/pay?companyId=`+this.companyId+"&companyUserId="+this.companyUserId
 			}
 		},
@@ -84,7 +94,8 @@
 								}).then(res=>{
 									 uni.hideLoading();
 									 if (res.code == 200) {
-										 
+										 uni.setStorageSync('AppToken',res.token);
+										 uni.setStorageSync('userInfo',res.user);
 									 } else {
 										uni.showToast({
 											title: res.msg,
@@ -141,7 +152,7 @@
 				// });
 			},
 			payment(){
-				var data = {payMoney:this.money,remark:this.desc,companyId:this.companyId,companyUserId:this.companyUserId};
+				var data = {payMoney:this.money,remark:this.desc,companyId:this.companyId,companyUserId:this.companyUserId,appId:wx.getAccountInfoSync().miniProgram.appId};
 				var that=this;
 				uni.showLoading();
 				payment(data).then(

+ 6 - 2
pages_user/user/paymentOrderRemain.vue

@@ -58,14 +58,18 @@
 				<button  class="share" data-name="shareBtn" open-type="share">分享</button>
 			</view> -->
 		</view>
-		 
+		 <ykscreenRecord></ykscreenRecord>
 	</view>
 </template>
 
 <script>
 	import {getUserInfo} from '@/api/user'
 	import {payRemain,getStoreOrderById} from '@/api/storeOrder'
+	import ykscreenRecord from "@/components/yk-screenRecord/yk-screenRecord.vue"
 	export default {
+		components:{
+			ykscreenRecord
+		},
 		data() {
 			return {
 				payDelivery:0.00,
@@ -147,7 +151,7 @@
 				
 			},
 			payOrder(){
-				var data = {orderId:this.order.id,payType:1};
+				var data = {orderId:this.order.id,payType:1,appId:wx.getAccountInfoSync().miniProgram.appId};
 				var that=this;
 				uni.showLoading();
 				payRemain(data).then(

BIN
static/course_expiration_img.png


+ 14 - 4
store/index.js

@@ -8,17 +8,20 @@ import {
 } from '@/api/index.js'
 export default new Vuex.Store({
   state: {
+	  coureLogin: uni.getStorageSync('coureLogin') || 0,
 	 webviewUrl: '',
 	 wsDanmuUrl: 'wss://userapp.cqsft.vip', // 弹幕评论接口地址
 	 //红包领取规则:
 	 answerType: 1, //红包领取规则 0:完课且最后一分钟(第二次无需最后一分钟), 1:按完课百分比答题领红包
 	 isSpare:1, // 0,主要小程序,1:备选
 	 uploadFile: 'https://userapp.cqsft.vip',
-	imgpath: 'https://hst2-1323137866.cos.ap-chongqing.myqcloud.com',//鸿森堂商城图片请求地址
-	// https://hst2-1323137866.cos.ap-chongqing.myqcloud.com/shop  鸿森堂商城图片链接
+	imgpath: 'https://hst2-1323137866.cos.ap-chongqing.myqcloud.com',//建兴堂图片请求地址
+	// https://hst2-1323137866.cos.ap-chongqing.myqcloud.com/shop  建兴堂图片链接
 	// https://hst2-1323137866.cos.ap-chongqing.myqcloud.com/shop
-	logoname:'鸿森堂便民商城',
-	appid:'wx291619622c3ce89c',//鸿森堂
+	logoname:'建兴堂',
+	// appid:'wxe0c36e14e697d8cf',//鸿森堂
+	appid:'wx87221638fa168cc5',//建 兴堂
+	
   },
   mutations: {
     setCount(state, value) {
@@ -29,8 +32,15 @@ export default new Vuex.Store({
     },
 	setWebviewUrl(state, value) {
 		state.webviewUrl = value;
+	},
+	setCoureLogin(state, payload) {
+		uni.setStorageSync('coureLogin', payload);
+		state.coureLogin = payload;
 	}
   },
+  getters: {
+    coureLogin: (state) => state.coureLogin,
+  },
   actions: {
     fetchUser({ commit }) {
       // const res = await uni.request({ url: '/api/user' });