index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <style>
  2. </style>
  3. <template>
  4. <div style='height: 100%;'>
  5. <div id='import-header'>
  6. <img src='../assets/images/nav_images.png' alt=''>照片批量上传工具
  7. <button id='exit-btn' @click='logout' title="退出"></button>
  8. </div>
  9. <div id='import-body'>
  10. <div id='import-div'>
  11. <a href='javascript:;' class='file'>
  12. <!-- webkitdirectory-->
  13. <input id='photos' :disabled='uploadDisabled' multiple="true" title=' ' name='files' type='file' v-on:change='importPhotos'/>
  14. <button id='import-btn'>
  15. 上传照片
  16. </button>
  17. </a>
  18. <div id='progressDiv'>
  19. <span>
  20. 成功:
  21. <span style="color:green;">{{successNum}}</span>/{{allNum}}
  22. </span>
  23. <span>
  24. 失败:<span style="color:red;">{{errorNum}}</span>/{{allNum}}
  25. </span>
  26. <span v-show="completeShow" style="color: green;font-weight: bold;">全部处理完成</span>
  27. <span v-show="!completeShow&&(successNum>0||errorNum>0)" style="color: red;font-weight: bold;">处理中...</span>
  28. </div>
  29. </div>
  30. <div id='progress-div'>
  31. <div id='console-panel'>
  32. <div v-for='msgInfo in returnMsgList'>
  33. <p class='console-line' v-if='msgInfo.success'>
  34. <span><img src='../assets/images/icon_sucess.png'></span>
  35. <span>{{msgInfo.fileName}}:{{msgInfo.msg}}</span>
  36. </p>
  37. <p class='console-line' v-if='!msgInfo.success'>
  38. <span><img src='../assets/images/icon_failed.png'></span>
  39. <span>{{msgInfo.fileName}}:{{msgInfo.msg}}</span>
  40. </p>
  41. </div>
  42. </div>
  43. </div>
  44. </div>
  45. </div>
  46. </template>
  47. <script>
  48. const CryptoJS = require('crypto-js');
  49. const Base64 = require('js-base64').Base64;
  50. export default {
  51. data() {
  52. return {
  53. photoQuantityLimit:10000,//单次上传限制
  54. photoList:[],//总的照片队列
  55. photoLine:[],//正在处理的照片队列
  56. concurrency:8,//同时处理的照片数量
  57. returnMsgList:[],//返回信息
  58. successNum:0, //成功数量
  59. errorNum:0, //失败数量
  60. allNum:0, //总数
  61. completeShow:false,
  62. uploadDisabled:false,
  63. seconds:0 // 耗时 秒
  64. }
  65. },
  66. methods: {
  67. init(){
  68. this.photoList = [];
  69. this.photoLine = [];
  70. this.returnMsgList = [];
  71. this.successNum = 0;
  72. this.errorNum = 0;
  73. this.allNum = 0;
  74. this.completeShow = false;
  75. },
  76. importPhotos() {
  77. this.init();
  78. var photos = document.getElementById('photos');
  79. for(var i = 0;i<photos.files.length;i++){
  80. this.photoList.push(photos.files[i]);
  81. }
  82. this.allNum = this.photoList.length;
  83. if(this.allNum > this.photoQuantityLimit){
  84. alert("单次上传文件数量不能大于"+this.photoQuantityLimit+",当前数量为"+this.allNum);
  85. photos.files = null;
  86. return;
  87. }
  88. //初始化this.concurrency个到photoLine中,开始处理
  89. this.photoLine = this.photoList.splice(0,this.concurrency);
  90. for(var i = 0;i<this.photoLine.length;i++){
  91. this.processStudentPhoto(this.photoLine[i]);
  92. }
  93. var _this = this;
  94. /**
  95. * 启动检查,看photoLine中是否有已完成的,如果有,从photoList中取出第一个将其替换
  96. * 队列中一直保持this.concurrency个正在处理的照片
  97. */
  98. var uploadTime = setInterval(function(){
  99. for (let i = 0; i < _this.photoLine.length; i++) {
  100. if (_this.photoLine[i].finished) {
  101. if (_this.photoList.length > 0) {
  102. _this.photoLine[i] = _this.photoList.shift();
  103. _this.processStudentPhoto(_this.photoLine[i]);
  104. }
  105. }
  106. }
  107. if (_this.photoList.length < 1) {
  108. console.log('photoList处理完毕');
  109. clearInterval(uploadTime);
  110. }
  111. },500);
  112. },
  113. processStudentPhoto(photo) {
  114. let photoNameArr = photo.name.split('.');
  115. let fileName = photoNameArr[0];//文件名就是身份证号码
  116. let fileSuffix = photoNameArr[1];//文件后缀
  117. //生成新名称
  118. let md5Hash = CryptoJS.MD5(Base64.encode(photo.name+new Date().getTime())).toString();
  119. let rootOrgId = localStorage.getItem('rootOrgId');
  120. //根据身份证号码查询学生信息
  121. this.$http.get('/api/ecs_core/studentFaceInfo/identityNumber?orgId='+rootOrgId+'&identityNumber='+fileName, {})
  122. .then((response) => {
  123. var studentFaceInfo = response.body;
  124. if (studentFaceInfo.student && studentFaceInfo.student.id) {
  125. this.detectFace(photo).then((res)=>{
  126. if(res.body.faces.length>=1){
  127. let face_token = res.body.faces[0].face_token;
  128. this.getFaceSetToken().then((res)=>{
  129. //var face_set_token = res.bodyText;
  130. var face_set_token = 'ee564a7abbde7f1287f668ddd945ccfa';
  131. this.addFaceToSet(face_set_token, face_token).then((res)=>{
  132. this.saveStudentFaceInfo({
  133. 'studentFaceInfoId':studentFaceInfo.id,
  134. 'studentId':studentFaceInfo.student.id,
  135. 'face_set_token':face_set_token,
  136. 'face_token':face_token,
  137. 'fileName':fileName,
  138. 'file':photo,
  139. 'fileSuffix':fileSuffix,
  140. 'photoNewName':md5Hash+'.'+fileSuffix
  141. });
  142. },(err)=>{
  143. this.finishOne(false,fileName,'addFaceToSet失败',photo);
  144. });
  145. },(err)=>{
  146. this.finishOne(false,fileName,'获取FaceSetToken失败',photo);
  147. });
  148. }else{
  149. this.finishOne(false,fileName,'face++没有检测到人脸',photo);
  150. }
  151. },(err)=>{
  152. this.finishOne(false,fileName,'调用face++检测人脸失败',photo);
  153. });
  154. }else{
  155. this.finishOne(false,fileName,'查询身份证不存在',photo);
  156. }
  157. },(err)=>{
  158. this.finishOne(false,fileName,'根据身份证号码查询失败',photo);
  159. });
  160. },
  161. //保存照片信息
  162. saveStudentFaceInfo(photoInfo){
  163. this.saveImageToUpyun(photoInfo).then((res)=>{
  164. //调用core后台接口,对数据进行保存
  165. if(!photoInfo.studentFaceInfoId){
  166. this.saveStudentFaceInfoByPost(photoInfo);
  167. }else{
  168. this.saveStudentFaceInfoByPut(photoInfo);
  169. }
  170. },(err)=>{
  171. this.finishOne(false,photoInfo.fileName,'saveImageToUpyun失败',photoInfo.file);
  172. });
  173. },
  174. //保存文件至又拍云
  175. saveImageToUpyun(photoInfo){
  176. var url = process.env.VUE_APP_UPYUN_BUCKETURL+'/student_base_photo/'+photoInfo.fileName+'/'+photoInfo.photoNewName;
  177. var authorization = 'Basic '+Base64.encode(process.env.VUE_APP_UPYUN_OPERATOR+':'+process.env.VUE_APP_UPYUN_PASSWORD);
  178. var headers = {headers:{'Authorization':authorization,'Content-Type': 'image/jpeg'}};
  179. return this.$http.put(url,photoInfo.file,headers);
  180. },
  181. //获取faceSetToken
  182. getFaceSetToken(){
  183. return this.$http.get('/api/ecs_core/faceSet/enableFaceSet');
  184. },
  185. //faceToken加入faceSetToken
  186. addFaceToSet(faceset_token,face_token){
  187. let formData_addface = new FormData();
  188. formData_addface.append('api_key', process.env.VUE_APP_FACEPP_API_KEY);
  189. formData_addface.append('api_secret',process.env.VUE_APP_FACEPP_API_SECRET);
  190. formData_addface.append('faceset_token', faceset_token);
  191. formData_addface.append('face_tokens', face_token);
  192. return this.$http.post('/facepp/v3/faceset/addface', formData_addface);
  193. },
  194. //face++分析人脸
  195. detectFace(file){
  196. let fileBlob = new Blob([file]);
  197. let formData_face_token = new FormData();
  198. formData_face_token.append('api_key',process.env.VUE_APP_FACEPP_API_KEY);
  199. formData_face_token.append('api_secret',process.env.VUE_APP_FACEPP_API_SECRET);
  200. formData_face_token.append('image_file', fileBlob);
  201. return this.$http.post('/facepp/v3/detect', formData_face_token);
  202. },
  203. saveStudentFaceInfoByPost(photoInfo){
  204. this.$http.post('/api/ecs_core/studentFaceInfo', {
  205. 'faceSetToken': photoInfo.face_set_token,
  206. 'faceToken': photoInfo.face_token,
  207. 'photoMD5': photoInfo.photoNewName,
  208. 'student': {
  209. 'id': photoInfo.studentId
  210. },
  211. 'createUser':localStorage.getItem('userName'),
  212. 'updateUser':localStorage.getItem('userName'),
  213. 'createType':'IMPORT_TOOL'
  214. }).then((res)=>{
  215. this.finishOne(true,photoInfo.fileName,'处理成功',photoInfo.file);
  216. },(err)=>{
  217. this.finishOne(false,photoInfo.fileName,'saveStudentFaceInfoByPost失败',photoInfo.file);
  218. });
  219. },
  220. saveStudentFaceInfoByPut(photoInfo){
  221. this.$http.put('/api/ecs_core/studentFaceInfo', {
  222. 'faceSetToken': photoInfo.face_set_token,
  223. 'faceToken': photoInfo.face_token,
  224. 'photoMD5': photoInfo.photoNewName,
  225. 'student': {
  226. 'id': photoInfo.studentId
  227. },
  228. 'createUser':localStorage.getItem('userName'),
  229. 'updateUser':localStorage.getItem('userName'),
  230. 'createType':'IMPORT_TOOL'
  231. }).then((res)=>{
  232. this.finishOne(true,photoInfo.fileName,'处理成功',photoInfo.file);
  233. },(err)=>{
  234. this.finishOne(false,photoInfo.fileName,'saveStudentFaceInfoByPut失败',photoInfo.file);
  235. });
  236. },
  237. //成功或失败处理
  238. finishOne(isSuccess,fileName,msg,file){
  239. file.finished = true;
  240. this.returnMsgList.push({'success':isSuccess,'fileName':fileName,'msg':msg});
  241. if(isSuccess){
  242. this.successNum++;
  243. }else{
  244. this.errorNum++;
  245. //如果存在nodejs环境
  246. if(typeof(nodeRequire) != "undefined"){
  247. var fs = nodeRequire("fs");
  248. if(fs){
  249. var errorfilePath = file.path.substring(0,file.path.lastIndexOf("\\"))+"\\errorfiles";
  250. if (!fs.existsSync(errorfilePath)) {
  251. fs.mkdirSync(errorfilePath);
  252. }
  253. var readStream = fs.createReadStream(file.path);
  254. var writeStream = fs.createWriteStream(errorfilePath+"\\"+file.name);
  255. readStream.pipe(writeStream);
  256. fs.appendFile(errorfilePath+'\\errorPhotos.txt',fileName+":"+msg+'\n',function (){});
  257. }
  258. }
  259. }
  260. if(this.errorNum+this.successNum == this.allNum){
  261. var photos = document.getElementById('photos');
  262. photos.files = null;
  263. this.completeShow = true;
  264. }
  265. },
  266. logout() {
  267. localStorage.removeItem("rootOrgId");
  268. localStorage.removeItem("userName");
  269. localStorage.removeItem("user_token");
  270. this.$router.push({path:'/login'});
  271. }
  272. }
  273. };
  274. </script>