index.vue 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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:false,
  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. if(!sportType){
  147. uni.showToast({
  148. icon:'error',
  149. title: "请选择运动类型"
  150. })
  151. return;
  152. }
  153. uni.chooseVideo({
  154. sourceType: ['camera', 'album'],
  155. success: (res)=>{
  156. this.uploadSubmit(res.tempFilePath)
  157. },
  158. fail(res) {
  159. uni.showToast({
  160. icon:'none',
  161. title:res.errMsg
  162. })
  163. }
  164. });
  165. },
  166. uploadSubmit(filePath) {
  167. uni.showLoading({
  168. mask:true,
  169. title:"上传中……"
  170. })
  171. const sportType=this.sportType;
  172. const accountName=uni.getStorageSync('phone')
  173. uploadApi({formData:{sportType}, filePath }).then((res) => {
  174. let result=JSON.parse(res);
  175. uni.hideLoading()
  176. if(result.code==="0000"){
  177. updateSportVide({
  178. accountName,
  179. sportType,
  180. sportVedioPath:result.data.sportVedioPath,
  181. sportVedioId:result.data.sportVedioId
  182. }).then((res)=>{
  183. if(res.code===0){
  184. uni.showToast({
  185. icon:'none',
  186. duration:2000,
  187. title: "上传成功,系统正在评分请稍等"
  188. })
  189. this.gradeId=res.data
  190. this.videoSrc=filePath;
  191. }
  192. })
  193. }else{
  194. uni.showToast({
  195. icon:'error',
  196. title: result.msg||"上传失败"
  197. })
  198. }
  199. }).catch((msg) => {
  200. uni.hideLoading()
  201. uni.showToast({
  202. icon:'error',
  203. title: "上传失败"
  204. })
  205. })
  206. },
  207. search(){
  208. let gradeId=this.gradeId;
  209. if(!gradeId){
  210. uni.showToast({
  211. icon:'none',
  212. title:"请先上传视频!"
  213. })
  214. return
  215. }
  216. getSportGradeById({
  217. gradeId
  218. }).then((res)=>{
  219. this.status=1;
  220. this.result=res.data
  221. })
  222. },
  223. videoErrorCallback: function(e) {
  224. uni.showModal({
  225. content: e.target.errMsg,
  226. showCancel: false
  227. })
  228. },
  229. changeMotionType(item){
  230. this.sportType=item.value
  231. },
  232. formateSportRetReport(items){
  233. try{
  234. if(this.isEmpty(items)) return []
  235. return Array.isArray(items)?items:JSON.parse(items)
  236. }catch(e){
  237. return []
  238. }
  239. },
  240. isEmpty(val){
  241. if(val!=="undefined"&&val!==undefined&&val!==""&&val!==null){
  242. return false
  243. }
  244. return true
  245. }
  246. }
  247. }
  248. </script>
  249. <style lang="scss" scoped>
  250. *{
  251. padding: 0;
  252. margin: 0;
  253. }
  254. .wrap{
  255. padding:20rpx;
  256. .title{
  257. height: 40rpx;
  258. font-size: 28rpx;
  259. font-family: PingFang SC;
  260. font-weight: bold;
  261. line-height: 40rpx;
  262. color: #333333;
  263. opacity: 1;
  264. padding:0 0 36rpx 20rpx;
  265. position: relative;
  266. &::after{
  267. width: 12rpx;
  268. height: 28rpx;
  269. background:#2A83EF;
  270. opacity: 1;
  271. border-radius: 6px;
  272. content: "";
  273. display: block;
  274. position: absolute;
  275. left: 0;
  276. top: 8rpx;
  277. }
  278. }
  279. .motionType-conatiner{
  280. .motionType-list{
  281. display: flex;
  282. justify-content: flex-start;
  283. align-items: center;
  284. flex-wrap: wrap;
  285. padding: 0 20rpx 44rpx 20rpx;
  286. .item{
  287. width: 25%;
  288. display: flex;
  289. justify-content:center;
  290. align-items: center;
  291. flex-direction: column;
  292. padding-top: 20rpx;
  293. &:nth-child(-n+4){
  294. padding-top:0;
  295. }
  296. .icon{
  297. display: block;
  298. width: 104rpx;
  299. height: 104rpx;
  300. }
  301. .name{
  302. width: 100%;
  303. font-size: 28rpx;
  304. height: 40rpx;
  305. line-height: 40rpx;
  306. color: #333;
  307. font-weight: bold;
  308. padding-top: 16rpx;
  309. overflow: hidden;
  310. white-space: nowrap;
  311. text-overflow: ellipsis;
  312. text-align: center;
  313. }
  314. }
  315. }
  316. }
  317. .flex-between-center{
  318. display: flex;
  319. justify-content:space-between;
  320. align-items: center;
  321. &.search-conatiner{
  322. padding-bottom: 20rpx;
  323. .custom-select{
  324. width: 300rpx;
  325. }
  326. }
  327. }
  328. .preview{
  329. width: 670rpx;
  330. display: flex;
  331. justify-content: center;
  332. align-items: center;
  333. background-color: #ccc;
  334. height: 300rpx;
  335. margin: 0 auto;
  336. background:#E8E8E8;
  337. opacity: 1;
  338. border-radius: 20rpx;
  339. #video{
  340. width:750rpx;
  341. height: 300rpx;
  342. display: block;
  343. }
  344. }
  345. .content{
  346. padding: 10rpx;
  347. margin-top: 24rpx;
  348. .upload-bt{
  349. width: 446rpx;
  350. height: 66rpx;
  351. line-height: 66rpx;
  352. font-size: 28rpx;
  353. color: #fff;
  354. background-color: #409eff;
  355. border-color: #409eff;
  356. text-align: center;
  357. margin: 0 auto;
  358. border-radius: 42rpx;
  359. }
  360. .search-bt-container{
  361. padding: 24rpx 0 42rpx 0;
  362. }
  363. .search-bt{
  364. width: 446rpx;
  365. height: 66rpx;
  366. line-height: 66rpx;
  367. font-size: 28rpx;
  368. color: #fff;
  369. background-color: #ED834A;
  370. border-color: #ED834A;
  371. text-align: center;
  372. margin: 0 auto;
  373. display: block;
  374. border-radius: 42rpx;
  375. }
  376. .result{
  377. .sportGrade-card{
  378. &{
  379. width: 670rpx;
  380. background-image: url('/static/index/sportGradeBg.png');
  381. background-repeat: no-repeat;
  382. background-size: 100% 100%;
  383. margin: 0 auto 40rpx;
  384. }
  385. .sportGrade{
  386. font-size: 120rpx;
  387. font-family: PingFang SC;
  388. font-weight: bold;
  389. line-height: 168rpx;
  390. color: #FFFFFF;
  391. text-align: center;
  392. .util{
  393. font-size: 32rpx;
  394. font-family: PingFang SC;
  395. font-weight: bold;
  396. line-height: 44rpx;
  397. color: #FFFFFF;
  398. }
  399. }
  400. .text{
  401. width: 90%;
  402. height: 40px;
  403. font-size: 28rpx;
  404. font-family: PingFang SC;
  405. font-weight: 400;
  406. line-height: 40px;
  407. color: #FFFFFF;
  408. text-align: center;
  409. white-space:nowrap;
  410. overflow:hidden;
  411. text-overflow:ellipsis;
  412. margin: 0 auto;
  413. }
  414. }
  415. .text-item{
  416. padding-bottom: 10px;
  417. .explain-title{
  418. height: 40rpx;
  419. font-size: 28rpx;
  420. font-family: PingFang SC;
  421. font-weight: bold;
  422. line-height: 40rpx;
  423. color: #333333;
  424. padding:0 0 24rpx 20rpx;
  425. position: relative;
  426. &::after{
  427. width: 12rpx;
  428. height: 12rpx;
  429. background:#2A83EF;
  430. border-radius: 50%;
  431. content: "";
  432. display: block;
  433. position: absolute;
  434. left: 0;
  435. top: 16rpx;
  436. }
  437. }
  438. .sportVideo{
  439. width:100%;
  440. height: 293rpx;
  441. display: block;
  442. border-radius: 20rpx;
  443. }
  444. }
  445. }
  446. }
  447. }
  448. </style>