test.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. <template>
  2. <view style="position: relative;">
  3. <Headers></Headers>
  4. <view class="project">
  5. <view style="width: 1200px;margin: auto;">{{paper.title}}</view>
  6. </view>
  7. <view class="video-box" id="video-box" @click="takePhoto" v-show="showVideo">
  8. <video id="video" style="width: 100%;height: 100%;" :autoplay="true" :controls="false" :show-center-play-btn="false"></video>
  9. <canvas id="canvas" style="width: 100%;height: 100%;" canvas-id="canvas"></canvas>
  10. </view>
  11. <img :src="imgUrl" ></img>
  12. <view class="project-content ddflex">
  13. <!-- 考试区域 -->
  14. <view class="test-box">
  15. <view class="test-box-title">
  16. <text style="font-weight: bold;margin-right: 10px;">考试题目</text>
  17. <text>{{ cIndex + 1 }}</text><text style="color: #999999;">/{{questTotal}}</text>
  18. </view>
  19. <view class="test-question-box">
  20. <view class="test-question ddflex">
  21. <view>{{ cIndex + 1 }}</view>
  22. <view>【{{getQuestType()}}】</view>
  23. <view>
  24. <rich-text class="hh" :nodes="addTitleType(quest.title,quest.qtype)"></rich-text>
  25. </view>
  26. </view>
  27. <!-- 简答题 -->
  28. <view class="short" v-if="quest.qtype == 4 || quest.qtype == 5">
  29. <textarea
  30. v-model="quest.answerTxt"
  31. maxlength="-1"
  32. ref="inputText"
  33. placeholder="在此输入答案"
  34. placeholder-class="placeholder"
  35. class="text-ans"
  36. @click="intAnswer(qitem, idx)"
  37. ></textarea>
  38. </view>
  39. <view class="test-question-answer" v-else-if="quest.qtype == 1 || quest.qtype == 2 || quest.qtype == 3">
  40. <view class="answer-item ddflex" v-for="(qitem, idx) in quest.questJson" :key="idx" @click="setAnswer(qitem, idx)">
  41. <!-- answer-checked -->
  42. <view :class="qitem.cssStr ? 'answer-checked' : 'answer-unchecked'"></view>
  43. <view class="answer-text ddflex">
  44. <view style="margin-right: 10px;">{{ qitem.num }} </view>
  45. <rich-text class="hh" :nodes="qitem.title"></rich-text>
  46. </view>
  47. </view>
  48. </view>
  49. </view>
  50. <view style="height: 82px;width: 100%;"> </view>
  51. <view class="test-btn-group ddflex">
  52. <view v-if="cIndex != 0" class="test-btn" @click="prev()">上一题</view>
  53. <view v-if="cIndex + 1 != questTotal" class="test-btn" @click="next()">下一题</view>
  54. </view>
  55. </view>
  56. <!-- 答题卡区域 -->
  57. <view class="test-info ddflex">
  58. <view class="test-people ddflex">
  59. <image :src="userInfo.avatar"></image>
  60. <view class="test-people-info ddflex">
  61. <view class="ddflex">
  62. <view class="test-people-label">考生姓名</view>
  63. <view class="fflex">{{userInfo.userName}}</view>
  64. </view>
  65. <view class="ddflex">
  66. <view class="test-people-label">准考证号</view>
  67. <view class="fflex" style="word-break: break-all;">{{userInfo.admissionNo}}</view>
  68. </view>
  69. <view class="ddflex">
  70. <view class="test-people-label">考试科目</view>
  71. <view class="fflex">{{userInfo.cateName}}</view>
  72. </view>
  73. </view>
  74. </view>
  75. <view class="test-date">
  76. <view class="test-date-title">距考试结束还有</view>
  77. <view class="test-date-group ddflex">
  78. <view class="test-date-item">{{times.hour}}</view>
  79. <text class="test-date-symbol">:</text>
  80. <view class="test-date-item">{{times.minutes}}</view>
  81. <text class="test-date-symbol">:</text>
  82. <view class="test-date-item">{{times.seconds}}</view>
  83. </view>
  84. </view>
  85. <view class="test-answer fflex">
  86. <view class="test-answer-title">答题卡</view>
  87. <view class="test-answer-info ddflex">
  88. <view class="">共 {{quests.length}} 题</view>
  89. <view class="test-answer-info-symbol"></view>
  90. <view class="">总计 100 分</view>
  91. </view>
  92. <view class="test-answer-box ddflex">
  93. <view :class="'test-answer-item '+(cIndex == index?'test-answer-item-curActive':item.isSubmit?'test-answer-item-active':'')" v-for="item,index in quests"
  94. @click="toQuestTip(index)">
  95. {{index+1}}
  96. </view>
  97. </view>
  98. <view class="test-answer-number ddflex">
  99. <view class="ddflex">
  100. <view class="test-isanswer"></view>
  101. <view>已做 {{quests.filter(item=>{return item.isSubmit}).length}}</view>
  102. </view>
  103. <view class="ddflex">
  104. <view class="test-unanswer"></view>
  105. <view>未做 {{quests.filter(item=>{return !item.isSubmit}).length}}</view>
  106. </view>
  107. </view>
  108. <view style="height: 82px;"></view>
  109. <view class="submit-btn" @click="open">交 卷</view>
  110. </view>
  111. </view>
  112. </view>
  113. <uni-popup ref="popup" type="bottom" :is-mask-click='false'>
  114. <view class="popup-box" v-if="state==1">
  115. <view class="popup-top ddflex">
  116. <view>您正在结束作答</view>
  117. <image src="/static/images/close.png" v-if="time > 0" @click="close()"></image>
  118. </view>
  119. <!-- {{(quests.filter(item=>{return item.isSubmit}).length<quests.length)?'您还有未完成的考题,是否确定交卷?':'您已完成全部考题,是否确定交卷?'}} -->
  120. <view class="popup-content">{{(quests.filter(item=>{return item.isSubmit}).length < quests.length ? '您还有未完成的考题,是否确定交卷?':'您已完成全部考题,是否确定交卷?')}}</view>
  121. <view class="popup-bottom ddflex">
  122. <view class="popup-btn1" @click="close()" v-if="time > 0">继续考试</view>
  123. <view class="popup-btn2" @click="submit">确定交卷</view>
  124. </view>
  125. </view>
  126. <view class="popup-box" v-if="state==2">
  127. <view class="popup-top ddflex">
  128. <view>考试结果</view>
  129. <image src="/static/images/close.png" @click="close(true)"></image>
  130. </view>
  131. <view class="popup-content" style="margin-top: 23px;">
  132. <view class="chufen-title">{{result.title}}</view>
  133. <view class="chufen-number" :style="result.score>=paper.passScore?'color:green;':''">
  134. {{result.score}}<text style="font-size: 18px;margin-left: 10px;">分</text>
  135. <view style="font-size: 16px;">{{result.score>=paper.passScore?'考试合格':'考试不合格'}}</view>
  136. </view>
  137. </view>
  138. <view class="popup-bottom ddflex" style="margin-top: 30px;margin-bottom: 60px;padding-left: 30px">
  139. <view>
  140. <view class="popup-bottom-label">总题数</view>
  141. <view class="popup-bottom-value">{{result.questToal}}</view>
  142. </view>
  143. <view class="line"></view>
  144. <view>
  145. <view class="popup-bottom-label">考试用时</view>
  146. <view class="popup-bottom-value">
  147. {{timeChangeHMS(result.duration)}}
  148. </view>
  149. </view>
  150. </view>
  151. </view>
  152. </uni-popup>
  153. <Foot></Foot>
  154. </view>
  155. </template>
  156. <script>
  157. const app = getApp();
  158. const req = require('../../utils/request.js');
  159. const utils = require('../../utils/util.js');
  160. const api = require('../../utils/api.js')
  161. import html2canvas from "../../utils/html2canvas.min.js";
  162. export default {
  163. data() {
  164. return {
  165. state:1,
  166. userInfo:{},
  167. paperId: '', //考试题目
  168. paperTitle: '', //考试标题
  169. paperType: '', //1每日一练 2模拟试题 3大厂真题 5企业真题
  170. type: '', //标识类型 1试卷 2章节 3热门考点 4错题集 5高频错题
  171. systems: {},
  172. isMockExam: true, //是否是模拟考试
  173. isShowTip: false, //是否展示温馨提示
  174. isShowSheet: false, //
  175. paper: '', //试卷详情
  176. time: 0, //允许做题的时间
  177. times: 0, //做题时分秒倒计时
  178. quest: '', //当前选中的题目
  179. quests: [], //题目数据
  180. questTotal: 0, //题目条数
  181. cIndex: 0, //当前做题下标
  182. answerTxt: '', //填空题、简答题答案
  183. isGoBack: false,
  184. isShowView: false,
  185. result:null,//考试结果
  186. buffer:null,
  187. video:{src:null},
  188. canvas:null,
  189. ctx:null,
  190. imgUrl:null,
  191. showVideo:false
  192. }
  193. },
  194. onReady() {},
  195. async onLoad(options) {
  196. this.paperId = options.paperId;
  197. console.log(this.userInfo)
  198. // 需要先判断用户是否还能考试
  199. await this.getQuests();
  200. // 摄像头
  201. // const query = uni.createSelectorQuery().in(this);
  202. // this.video = query.select('#video')
  203. // this.canvas = query.select('#canvas');
  204. // this.test()
  205. // 考生信息
  206. this.getUserInfo()
  207. // 考试数据
  208. this.getPaper();
  209. // this.getQuests();
  210. },
  211. onUnload() {
  212. // uni.clearStorageSync();
  213. },
  214. methods: {
  215. // 考试信息
  216. getUserInfo(){
  217. req.getRequest('/api/v3/exam/user/manager/info',{},res=>{
  218. this.userInfo = res
  219. })
  220. },
  221. getQuestType() {
  222. // <!-- 1单选 2多选 3 判断 4 填空 5 简答', -->
  223. var text = '';
  224. switch (this.quest.qtype) {
  225. case 1:
  226. text = '单选题';
  227. break;
  228. case 2:
  229. text = '多选题';
  230. break;
  231. case 3:
  232. text = '判断题';
  233. break;
  234. case 4:
  235. text = '填空题';
  236. break;
  237. case 5:
  238. text = '简答题';
  239. break;
  240. default:
  241. break;
  242. }
  243. return text;
  244. },
  245. stylesText(text){
  246. return utils.preText(text);
  247. },
  248. addTitleType(title, qtype) {
  249. var stitle=this.stylesText(title);
  250. return stitle;
  251. },
  252. //获取考试对象
  253. getPaper() {
  254. var _ts = this;
  255. req.getRequest(api.paper_detail + _ts.paperId, {}, res => {
  256. if (res) {
  257. if (res.time > 0 && _ts.paperType != 3 && _ts.paperType != 5) {
  258. _ts.time = res.time * 60;
  259. _ts.setTime();
  260. }
  261. _ts.paperType = res.paperType * 1;
  262. _ts.paper = res;
  263. }
  264. });
  265. },
  266. getQuests(){
  267. let _ts = this
  268. return new Promise((r,j)=>{
  269. req.getRequest(api.get_exam_question + _ts.paperId,{},quests=>{
  270. console.log(quests)
  271. if (quests && quests.length > 0) {
  272. _ts.questTotal = quests.length;
  273. for (var k = 0; k < quests.length; k++) {
  274. var quest = quests[k];
  275. quest.eitype = _ts.etype;
  276. quest.title = quest.title.replace(/<code class="(.*?)"/gi, '<code class="Java" ');
  277. }
  278. if (_ts.questTotal > 0) {
  279. _ts.quest = _ts.setQuest(quests[0]);
  280. }
  281. _ts.quests = quests;
  282. r()
  283. }else{
  284. uni.showModal({
  285. title:'提示',
  286. content:'您已参加过该考试',
  287. showCancel:false,
  288. success(res) {
  289. if(res.confirm){
  290. uni.reLaunch({
  291. url:'/pages/login/login',
  292. success() {
  293. console.log('您已参加过该考试')
  294. }
  295. })
  296. }
  297. }
  298. })
  299. }
  300. })
  301. })
  302. },
  303. //考试时间倒计时
  304. setTime() {
  305. var _ts = this;
  306. var time = _ts.time;
  307. if (time <= 0) {
  308. //考试时间到,交卷
  309. if (_ts.ptime) {
  310. clearTimeout(_ts.ptime);
  311. }
  312. _ts.open()
  313. // _ts.submitTest();
  314. return;
  315. }
  316. var times = {};
  317. times.hour = _ts.cut22(Math.floor(time / 3600));
  318. var leave2 = time % 3600;
  319. times.minutes = _ts.cut22(Math.floor(leave2 / 60));
  320. var leave3 = leave2 % 60;
  321. times.seconds = _ts.cut22(Math.round(leave3));
  322. _ts.times = times;
  323. _ts.ptime = setTimeout(function() {
  324. _ts.time = time - 1;
  325. _ts.setTime();
  326. }, 1000);
  327. }, //下次继续
  328. // 秒转换时分秒
  329. timeChangeHMS(time){
  330. let _ts = this
  331. var times = {};
  332. times.hour = _ts.cut22(Math.floor(time / 3600));
  333. var leave2 = time % 3600;
  334. times.minutes = _ts.cut22(Math.floor(leave2 / 60));
  335. var leave3 = leave2 % 60;
  336. times.seconds = _ts.cut22(Math.round(leave3));
  337. return times.hour+":"+times.minutes+":"+times.seconds
  338. },
  339. cut22(n) {
  340. n = n.toString();
  341. return n[1] ? n : '0' + n;
  342. },
  343. //将答案和问题转成数组或对象
  344. setQuest(quest) {
  345. console.log('quest.iscv==', quest.iscv);
  346. if (quest.iscv) {
  347. return quest;
  348. }
  349. quest.iscv = true;
  350. var answers = [];
  351. var qjs = [];
  352. try {
  353. var qJsons = JSON.parse(quest.questJson);
  354. if (quest.qtype == 1 || quest.qtype == 3) {
  355. //'单选题'
  356. answers = quest.answerJson ? [quest.answerJson] : [];
  357. } else if (quest.qtype == 2) {
  358. if (quest.answerJson) {
  359. answers = JSON.parse(quest.answerJson);
  360. }
  361. }
  362. for (var m = 0; m < qJsons.length; m++) {
  363. var num = this.getNum(m);
  364. qjs.push({
  365. num: num,
  366. title: qJsons[m],
  367. cssStr: ''
  368. });
  369. }
  370. } catch (e) {}
  371. quest.answerJson = answers;
  372. quest.questJson = qjs;
  373. console.log('下一题中');
  374. quest.answerTxt = '';
  375. this.answerTxt = '';
  376. return quest;
  377. },
  378. getNum: function(ix) {
  379. var keys = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N'];
  380. return keys[ix];
  381. },
  382. intAnswer(item, idx) {
  383. var _ts = this;
  384. var qes = this.quest;
  385. qes.isSubmit = true;
  386. _ts.quest = qes;
  387. },
  388. setAnswer(item, idx) {
  389. // <!-- 1单选 2多选 3 判断 4 填空 5 简答', -->
  390. var _ts = this;
  391. idx = idx + 1;
  392. var qes = this.quest;
  393. /*修改答案选中项*/
  394. var sItems = qes.sItems;
  395. if (qes.qtype == 2) {
  396. var isflg = false;
  397. if (sItems && sItems.length > 0) {
  398. var cidx = sItems.indexOf(idx);
  399. if (cidx > -1) {
  400. sItems.splice(cidx, 1);
  401. isflg = true;
  402. }
  403. } else {
  404. sItems = [];
  405. }
  406. if (!isflg) {
  407. sItems.push(idx);
  408. }
  409. } else if (qes.qtype == 1 || qes.qtype == 3) {
  410. sItems = [idx];
  411. }
  412. qes.sItems = sItems.sort();
  413. qes.isSubmit = true;
  414. //修改Css
  415. qes = _ts.setCss(qes);
  416. _ts.quest = qes;
  417. _ts.quests[_ts.cIndex] = qes;
  418. },
  419. //设置页面选中样式
  420. setCss(qes) {
  421. var qjson = qes.questJson;
  422. var answers = qes.answerJson; //答案
  423. var sItems = qes.sItems;
  424. if (!sItems) {
  425. sItems = [];
  426. }
  427. for (var m = 0; m < qjson.length; m++) {
  428. var qitem = qjson[m];
  429. var cidx = sItems.indexOf(m + 1);
  430. if (cidx > -1) {
  431. qitem.cssStr = ' active';
  432. } else {
  433. qitem.cssStr = '';
  434. }
  435. }
  436. qes.questJson = qjson;
  437. qes.cssStr = ' active';
  438. return qes;
  439. },
  440. //上一题
  441. prev() {
  442. var _ts = this;
  443. var cIndex = _ts.cIndex;
  444. if (cIndex <= 0) {
  445. return;
  446. }
  447. _ts.cIndex = cIndex - 1;
  448. _ts.quest = _ts.setQuest(_ts.quests[_ts.cIndex]);
  449. }, //下一题
  450. next() {
  451. var _ts = this;
  452. var cIndex = _ts.cIndex;
  453. if (cIndex >= _ts.questTotal - 1) {
  454. return;
  455. }
  456. _ts.cIndex = cIndex + 1;
  457. console.log('下一题');
  458. _ts.quest = _ts.setQuest(_ts.quests[_ts.cIndex]);
  459. console.log('下一题后');
  460. console.log('_ts.quest==', _ts.quest);
  461. console.log('_ts.quest.answerTxt==', _ts.quest.answerTxt);
  462. _ts.$forceUpdate();
  463. console.log('quests==', _ts.quests);
  464. },
  465. toQuestTip(index) {
  466. var _ts = this;
  467. _ts.cIndex = index;
  468. _ts.quest = _ts.setQuest(_ts.quests[_ts.cIndex]);
  469. // _ts.closeCeng();
  470. // });
  471. },
  472. //提交
  473. submitQuest() {
  474. var msg = '';
  475. if (this.paperType == 2) {
  476. if (this.times.hour > 0) {
  477. msg = '距离考试结束还剩' + this.times.hour + '小时' + this.times.minutes + '分钟,确定要结束考试吗?';
  478. } else {
  479. if (this.times.minutes > 0) {
  480. msg = '距离考试结束还剩' + this.times.minutes + '分钟,确定要结束考试吗?';
  481. } else {
  482. msg = '确定要交卷结束考试吗?';
  483. }
  484. }
  485. } else {
  486. msg = '确定要交卷结束做题吗?';
  487. }
  488. this.$showModal({ title: '温馨提示', content: msg, cancelText: '继续作答', confirmText: '交卷' })
  489. .then(res => {
  490. this.submitTest();
  491. })
  492. .catch(err => {
  493. // 点击取消按钮的操作
  494. });
  495. },
  496. async submitTest(){
  497. if (!this.paper.isScore) {//手动阅卷
  498. //订阅成绩通知
  499. await requsetmessage.resultsTest().then(res => {});
  500. }
  501. this.submit();
  502. },
  503. //提交考试+答案
  504. submit() {
  505. var _ts = this;
  506. if (_ts.ptime) {
  507. clearTimeout(_ts.ptime);
  508. }
  509. var dataP = {
  510. uniqueId: _ts.paperId,
  511. uniqueType: 1
  512. };
  513. //组装考试题目
  514. dataP.questionList = this.quests.map(it => {
  515. // <!-- 1单选 2多选 3 判断 4 填空 5 简答', -->
  516. var data = {
  517. id: it.id, //记录ID
  518. paperQuestionId: it.pqId, //试卷题目ID
  519. questionId: it.questId //题目ID
  520. };
  521. var answerJson = '';
  522. if (it.qtype == 1 || it.qtype == 3) {
  523. answerJson = it.sItems ? it.sItems.join('') : '';
  524. } else if (it.qtype == 2) {
  525. answerJson = it.sItems ? JSON.stringify(it.sItems) : '';
  526. } else if (it.qtype == 4) {
  527. var list = [];
  528. list.push(it.answerTxt ? it.answerTxt : '');
  529. answerJson = JSON.stringify(list);
  530. } else if (it.qtype == 5) {
  531. answerJson = it.answerTxt ? it.answerTxt : '';
  532. }
  533. data.answerJson = answerJson;
  534. return data;
  535. });
  536. console.log(dataP);
  537. req.postRequest(
  538. api.complete_exam,
  539. dataP,
  540. res => {
  541. if (!_ts.paper.isScore) {//手动阅卷
  542. uni.redirectTo({
  543. url:'/pages/scoreQuery/scoreQuery?paperId='+ _ts.paperId+'&admissionNo='+_ts.userInfo.admissionNo
  544. })
  545. return
  546. } else {//自动阅卷
  547. // uni.redirectTo({
  548. // url: '/learn/result/index?id=' + res.id
  549. // });
  550. this.state=2
  551. this.result = res
  552. }
  553. },
  554. true
  555. );
  556. },
  557. open() {
  558. this.$refs.popup.open('center')
  559. },
  560. close(back) {
  561. this.$refs.popup.close()
  562. if(back){
  563. uni.reLaunch({
  564. url:'/pages/login/login'
  565. })
  566. }
  567. },
  568. takePhoto() {
  569. let _this = this
  570. //获得Canvas对象
  571. const query = uni.createSelectorQuery().in(this);
  572. let video = document.querySelector('video');
  573. let canvas = document.querySelector('canvas')
  574. let ctx = canvas.getContext('2d');
  575. let videoInfo = {}
  576. query.select('video').boundingClientRect(result => {
  577. console.log('videoInfo',result)
  578. videoInfo={
  579. width:result.width,
  580. height:result.height
  581. }
  582. }).exec();
  583. ctx.drawImage(video, 0, 0, videoInfo.width, videoInfo.height);
  584. console.log(this.dataURLtoBlob(canvas.toDataURL(),'11'))
  585. // setTimeout(() => {
  586. // uni.canvasToTempFilePath({
  587. // canvasId: 'canvas',
  588. // destWidth: 60,
  589. // destHeight: 40,
  590. // success: function (res) {
  591. // console.log(res.tempFilePath) //图片路径
  592. // // resolve(res.tempFilePath)
  593. // _this.imgUrl = res.tempFilePath
  594. // },
  595. // fail: function (res) {
  596. // console.log(res.errMsg)
  597. // }
  598. // })
  599. // }, 100)
  600. },
  601. dataURLtoBlob(dataurl) {
  602. var arr = dataurl.split(','),
  603. mime = arr[0].match(/:(.*?);/)[1],
  604. bstr = atob(arr[1]),
  605. n = bstr.length,
  606. u8arr = new Uint8Array(n);//8位无符号整数,长度1个字节
  607. console.log(mime)
  608. while (n--) {
  609. u8arr[n] = bstr.charCodeAt(n);
  610. }
  611. // console.log(JSON.stringify(u8arr));
  612. return new Blob([u8arr], {
  613. type: mime
  614. });
  615. },
  616. base64toFile (dataurl, filename){
  617. var arr = dataurl.split(','),
  618. mime = arr[0].match(/:(.*?);/)[1],
  619. bstr = atob(arr[1]),
  620. n = bstr.length,
  621. u8arr = new Uint8Array(n);
  622. while (n--) {
  623. u8arr[n] = bstr.charCodeAt(n);
  624. }
  625. return new File([u8arr], filename, {
  626. type: mime
  627. });
  628. },
  629. test(){
  630. // var video = document.querySelector('video');
  631. const query = uni.createSelectorQuery().in(this);
  632. var video = query.select('#video')
  633. console.log('video',video)
  634. // 兼容代码
  635. window.URL = (window.URL || window.webkitURL || window.mozURL || window.msURL);
  636. // 获取媒体属性,旧版本浏览器可能不支持mediaDevices,我们首先设置一个空对象
  637. if (navigator.mediaDevices === undefined) {
  638. navigator.mediaDevices = {};
  639. }
  640. console.log('navigator.mediaDevices',navigator.mediaDevices)
  641. // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
  642. // 使用getUserMedia,因为它会覆盖现有的属性。
  643. // 这里,如果缺少getUserMedia属性,就添加它。
  644. if (navigator.mediaDevices.getUserMedia === undefined) {
  645. navigator.mediaDevices.getUserMedia = function(constraints) {
  646. // 首先获取现存的getUserMedia(如果存在)
  647. var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
  648. // 有些浏览器不支持,会返回错误信息
  649. // 保持接口一致
  650. if (!getUserMedia) { //不存在则报错
  651. return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
  652. }
  653. // 否则,使用Promise将调用包装到旧的navigator.getUserMedia
  654. return new Promise(function(resolve, reject) {
  655. getUserMedia.call(navigator, constraints, resolve, reject);
  656. });
  657. }
  658. }
  659. //摄像头调用配置
  660. var mediaOpts = {
  661. audio: false,
  662. video: { facingMode: "user"}
  663. }
  664. let that=this;
  665. navigator.mediaDevices.getUserMedia(mediaOpts).then(function(stream) {
  666. that.mediaStreamTrack = stream;
  667. video = document.querySelector('video');
  668. console.log('video = document.querySelector(video);',video)
  669. // 旧的浏览器可能没有srcObject
  670. if ("srcObject" in video) {
  671. video.srcObject = stream
  672. that.video.srcObject = stream
  673. } else {
  674. // 避免在新的浏览器中使用它,因为它正在被弃用。
  675. video.src = window.URL && window.URL.createObjectURL(stream) || stream
  676. that.video.src = window.URL && window.URL.createObjectURL(stream) || stream
  677. }
  678. video.play();
  679. that.showVideo = true
  680. }).catch(function (err) {
  681. console.log(err)
  682. uni.showModal({
  683. title:'提示',
  684. content:'未找到摄像头',
  685. showCancel:false,
  686. success() {
  687. // uni.navigateBack({
  688. // })
  689. }
  690. })
  691. });
  692. },
  693. },
  694. }
  695. </script>
  696. <style>
  697. @import url('./test.css');
  698. </style>