index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. <template>
  2. <view class="wrap">
  3. <view class="motionType-conatiner">
  4. <view class="title">选择运动类型</view>
  5. <div class="motionType-list">
  6. <div class="item" v-for="(item,index) in motionType" :key="index" @click="changeMotionType(item)">
  7. <image class="icon" :src="sportType===item.value?item.selectedIconPath:item.icon"></image>
  8. <view class="name">{{item.text}}</view>
  9. </div>
  10. </div>
  11. </view>
  12. <div class="preview-conatiner">
  13. <view class="title">上传视频</view>
  14. <view class="preview">
  15. <video v-if="videoSrc" id="video" :src="videoSrc" @error="videoErrorCallback" controls></video>
  16. <uni-icons color="#AEAEAE" type="videocam-filled" size="70" v-else></uni-icons>
  17. </view>
  18. </div>
  19. <view class="content">
  20. <button class="upload-bt" @click="upload">上传视频</button>
  21. <view class="search-bt-container" v-if="!isEmpty(gradeId)">
  22. <button class="search-bt" @click="search" size="mini">
  23. <uni-icons type="search" size="12" color="#fff"></uni-icons>
  24. <text>查询评分结果</text>
  25. </button>
  26. </view>
  27. <view class="result" v-if="status===1">
  28. <view class="title">识别结果</view>
  29. <view class="result-conatiner">
  30. <h3>{{!isEmpty(result.sportGrade)?'':'正在评分中请稍后重试'}}</h3>
  31. <view class="collapse-item-content" v-if="!isEmpty(result.sportGrade)">
  32. <div class="sportGrade-card">
  33. <div class="sportGrade">
  34. <text>{{result.sportGrade}}</text>
  35. <text class="util">分</text>
  36. </div>
  37. <view class="text">{{result.sportSuggestion}}</view>
  38. </div>
  39. <view class="text" >
  40. <view class="text-item" v-for="(item,key) in formateSportRetReport(result.sportRetReport)" :key="key">
  41. <view class="explain-title">{{item.explain}}</view>
  42. <video class="sportVideo" :src="item.url"></video>
  43. </view>
  44. </view>
  45. </view>
  46. </view>
  47. </view>
  48. </view>
  49. <getPhone ref="getPhone" v-if="!isLogin" showByPlatform />
  50. </view>
  51. </template>
  52. <script>
  53. import {setToken} from '@/libs/auth.js'
  54. import getPhone from '@/components/getPhone.vue'
  55. import {uploadApi} from '@/api/upload.js'
  56. import {updateSportVide,getSportGradeById,login} from '@/api/user.js'
  57. export default {
  58. data() {
  59. return {
  60. collapseVal:['0'],
  61. videoSrc: '',
  62. status:0,
  63. iscollapse:false,
  64. gradeId:undefined,
  65. result:{sportGrade:undefined},
  66. isLogin:true,
  67. sportType:undefined,
  68. motionType:[
  69. {
  70. value: "0000",
  71. text: "引体向上",
  72. icon:'/static/index/ytxs.png',
  73. selectedIconPath:'/static/index/ytxsCk.png'
  74. },
  75. {
  76. value: "0001",
  77. text: "仰卧起坐",
  78. icon:'/static/index/ywqz.png',
  79. selectedIconPath:'/static/index/ywqzCk.png'
  80. },
  81. {
  82. value: "0002",
  83. text: "跳远",
  84. icon:'/static/index/ty.png',
  85. selectedIconPath:'/static/index/tyCk.png'
  86. },
  87. {
  88. value: "0003",
  89. text: "坐位体前屈",
  90. icon:'/static/index/tqq.png',
  91. selectedIconPath:'/static/index/tqqCk.png'
  92. },
  93. {
  94. value: "0004",
  95. text: "健身动作",
  96. icon:'/static/index/jsdz.png',
  97. selectedIconPath:'/static/index/jsdzCk.png'
  98. },
  99. {
  100. value: "0005",
  101. text: "高抬腿",
  102. icon:'/static/index/gtt.png',
  103. selectedIconPath:'/static/index/gttCk.png'
  104. },
  105. {
  106. value: "0006",
  107. text: "排球垫球",
  108. icon:'/static/index/pqdq.png',
  109. selectedIconPath:'/static/index/pqdqCk.png'
  110. },
  111. {
  112. value: "0007",
  113. text: "足球垫球",
  114. icon:'/static/index/zqdq.png',
  115. selectedIconPath:'/static/index/zqdqCk.png'
  116. }
  117. ]
  118. }
  119. },
  120. components:{
  121. getPhone
  122. },
  123. onShow() {
  124. // this.initPhoneModal()
  125. },
  126. destroyed() {
  127. this.status=0;
  128. this.videoSrc="";
  129. this.result={}
  130. this.gradeId=undefined
  131. },
  132. methods: {
  133. initPhoneModal(){
  134. const accountName=uni.getStorageSync('phone')
  135. if(!accountName){
  136. this.isLogin=false
  137. this.$nextTick(()=>{
  138. this.$refs['getPhone'].isAuthorize=false
  139. })
  140. }else{
  141. this.isLogin=true
  142. }
  143. },
  144. upload(){
  145. const sportType=this.sportType
  146. const accountName=uni.getStorageSync('phone')
  147. if(!accountName){
  148. this.isLogin=false
  149. this.$nextTick(()=>{
  150. this.$refs['getPhone'].isAuthorize=false
  151. })
  152. return
  153. }
  154. if(!sportType){
  155. uni.showToast({
  156. icon:'error',
  157. title: "请选择运动类型"
  158. })
  159. return;
  160. }
  161. uni.chooseVideo({
  162. sourceType: ['camera', 'album'],
  163. success: (res)=>{
  164. this.uploadSubmit(res.tempFilePath)
  165. },
  166. fail(res) {
  167. uni.showToast({
  168. icon:'none',
  169. title:res.errMsg
  170. })
  171. }
  172. });
  173. },
  174. uploadSubmit(filePath) {
  175. uni.showLoading({
  176. mask:true,
  177. title:"上传中……"
  178. })
  179. const sportType=this.sportType;
  180. const accountName=uni.getStorageSync('phone')
  181. uploadApi({formData:{sportType}, filePath }).then((res) => {
  182. let result=JSON.parse(res);
  183. uni.hideLoading()
  184. if(result.code==="0000"){
  185. updateSportVide({
  186. accountName,
  187. sportType,
  188. sportVedioPath:result.data.sportVedioPath,
  189. sportVedioId:result.data.sportVedioId
  190. }).then((res)=>{
  191. if(res.code===0){
  192. uni.showToast({
  193. icon:'none',
  194. duration:2000,
  195. title: "上传成功,系统正在评分请稍等"
  196. })
  197. this.gradeId=res.data
  198. this.videoSrc=filePath;
  199. }
  200. })
  201. }else{
  202. uni.showToast({
  203. icon:'error',
  204. title: result.msg||"上传失败"
  205. })
  206. }
  207. }).catch((msg) => {
  208. uni.hideLoading()
  209. uni.showToast({
  210. icon:'error',
  211. title: "上传失败"
  212. })
  213. })
  214. },
  215. search(){
  216. let gradeId=this.gradeId;
  217. if(!gradeId){
  218. uni.showToast({
  219. icon:'none',
  220. title:"请先上传视频!"
  221. })
  222. return
  223. }
  224. getSportGradeById({
  225. gradeId
  226. }).then((res)=>{
  227. this.status=1;
  228. this.result=res.data
  229. })
  230. },
  231. videoErrorCallback: function(e) {
  232. uni.showModal({
  233. content: e.target.errMsg,
  234. showCancel: false
  235. })
  236. },
  237. changeMotionType(item){
  238. this.sportType=item.value
  239. },
  240. formateSportRetReport(items){
  241. try{
  242. if(this.isEmpty(items)) return []
  243. return Array.isArray(items)?items:JSON.parse(items)
  244. }catch(e){
  245. return []
  246. }
  247. },
  248. isEmpty(val){
  249. if(val!=="undefined"&&val!==undefined&&val!==""&&val!==null){
  250. return false
  251. }
  252. return true
  253. }
  254. },
  255. onShareAppMessage() {
  256. return {
  257. title: 'GOOMove',
  258. path: '/pages/index/index'
  259. }
  260. },
  261. onShareTimeline() {
  262. return {
  263. title: 'GOOMove',
  264. path: '/pages/index/index'
  265. }
  266. }
  267. }
  268. </script>
  269. <style lang="scss" scoped>
  270. *{
  271. padding: 0;
  272. margin: 0;
  273. }
  274. .wrap{
  275. padding:20rpx;
  276. .title{
  277. height: 40rpx;
  278. font-size: 28rpx;
  279. font-family: PingFang SC;
  280. font-weight: bold;
  281. line-height: 40rpx;
  282. color: #333333;
  283. opacity: 1;
  284. padding:0 0 36rpx 20rpx;
  285. position: relative;
  286. &::after{
  287. width: 12rpx;
  288. height: 28rpx;
  289. background:#2A83EF;
  290. opacity: 1;
  291. border-radius: 6px;
  292. content: "";
  293. display: block;
  294. position: absolute;
  295. left: 0;
  296. top: 8rpx;
  297. }
  298. }
  299. .motionType-conatiner{
  300. .motionType-list{
  301. display: flex;
  302. justify-content: flex-start;
  303. align-items: center;
  304. flex-wrap: wrap;
  305. padding: 0 20rpx 44rpx 20rpx;
  306. .item{
  307. width: 25%;
  308. display: flex;
  309. justify-content:center;
  310. align-items: center;
  311. flex-direction: column;
  312. padding-top: 20rpx;
  313. &:nth-child(-n+4){
  314. padding-top:0;
  315. }
  316. .icon{
  317. display: block;
  318. width: 104rpx;
  319. height: 104rpx;
  320. }
  321. .name{
  322. width: 100%;
  323. font-size: 28rpx;
  324. height: 40rpx;
  325. line-height: 40rpx;
  326. color: #333;
  327. font-weight: bold;
  328. padding-top: 16rpx;
  329. overflow: hidden;
  330. white-space: nowrap;
  331. text-overflow: ellipsis;
  332. text-align: center;
  333. }
  334. }
  335. }
  336. }
  337. .flex-between-center{
  338. display: flex;
  339. justify-content:space-between;
  340. align-items: center;
  341. &.search-conatiner{
  342. padding-bottom: 20rpx;
  343. .custom-select{
  344. width: 300rpx;
  345. }
  346. }
  347. }
  348. .preview{
  349. width: 670rpx;
  350. display: flex;
  351. justify-content: center;
  352. align-items: center;
  353. background-color: #ccc;
  354. height: 300rpx;
  355. margin: 0 auto;
  356. background:#E8E8E8;
  357. opacity: 1;
  358. border-radius: 20rpx;
  359. #video{
  360. width:750rpx;
  361. height: 300rpx;
  362. display: block;
  363. }
  364. }
  365. .content{
  366. padding: 10rpx;
  367. margin-top: 24rpx;
  368. .upload-bt{
  369. width: 446rpx;
  370. height: 66rpx;
  371. line-height: 66rpx;
  372. font-size: 28rpx;
  373. color: #fff;
  374. background-color: #409eff;
  375. border-color: #409eff;
  376. text-align: center;
  377. margin: 0 auto;
  378. border-radius: 42rpx;
  379. }
  380. .search-bt-container{
  381. padding: 24rpx 0 42rpx 0;
  382. }
  383. .search-bt{
  384. width: 446rpx;
  385. height: 66rpx;
  386. line-height: 66rpx;
  387. font-size: 28rpx;
  388. color: #fff;
  389. background-color: #ED834A;
  390. border-color: #ED834A;
  391. text-align: center;
  392. margin: 0 auto;
  393. display: block;
  394. border-radius: 42rpx;
  395. }
  396. .result{
  397. .sportGrade-card{
  398. &{
  399. width: 670rpx;
  400. background-image: url('/static/index/sportGradeBg.png');
  401. background-repeat: no-repeat;
  402. background-size: 100% 100%;
  403. margin: 0 auto 40rpx;
  404. }
  405. .sportGrade{
  406. font-size: 120rpx;
  407. font-family: PingFang SC;
  408. font-weight: bold;
  409. line-height: 168rpx;
  410. color: #FFFFFF;
  411. text-align: center;
  412. .util{
  413. font-size: 32rpx;
  414. font-family: PingFang SC;
  415. font-weight: bold;
  416. line-height: 44rpx;
  417. color: #FFFFFF;
  418. }
  419. }
  420. .text{
  421. width: 90%;
  422. height: 40px;
  423. font-size: 28rpx;
  424. font-family: PingFang SC;
  425. font-weight: 400;
  426. line-height: 40px;
  427. color: #FFFFFF;
  428. text-align: center;
  429. white-space:nowrap;
  430. overflow:hidden;
  431. text-overflow:ellipsis;
  432. margin: 0 auto;
  433. }
  434. }
  435. .text-item{
  436. padding-bottom: 10px;
  437. .explain-title{
  438. height: 40rpx;
  439. font-size: 28rpx;
  440. font-family: PingFang SC;
  441. font-weight: bold;
  442. line-height: 40rpx;
  443. color: #333333;
  444. padding:0 0 24rpx 20rpx;
  445. position: relative;
  446. &::after{
  447. width: 12rpx;
  448. height: 12rpx;
  449. background:#2A83EF;
  450. border-radius: 50%;
  451. content: "";
  452. display: block;
  453. position: absolute;
  454. left: 0;
  455. top: 16rpx;
  456. }
  457. }
  458. .sportVideo{
  459. width:100%;
  460. height: 293rpx;
  461. display: block;
  462. border-radius: 20rpx;
  463. }
  464. }
  465. }
  466. }
  467. }
  468. </style>