VideoLocalWindow.vue 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. <template>
  2. <div class="videoContainer">
  3. <video ref="video" autoplay muted playsinline></video>
  4. <div id="timestamp" v-show="false">
  5. {{ datetimeData.date + " " + datetimeData.time }}
  6. </div>
  7. <!-- <el-button @click="startCamera">开启摄像头</el-button>
  8. <el-button @click="stopCamera" :disabled="!isCameraActive"
  9. >关闭摄像头</el-button
  10. > -->
  11. </div>
  12. </template>
  13. <script>
  14. import { GetPersonByFace, GetPersonByFaceBase64 } from "@/API/custom";
  15. import Dayjs from "dayjs";
  16. export default {
  17. props: {
  18. processStep: {
  19. type: String,
  20. require: true,
  21. },
  22. isUpload: {
  23. type: String,
  24. require: false,
  25. },
  26. cameraData: {
  27. type: Object,
  28. default: () => ({}),
  29. },
  30. },
  31. watch: {
  32. processStep: {
  33. handler(step) {
  34. if (step == 0 || step == 9) {
  35. this.startCamera();
  36. } else {
  37. this.stopCamera();
  38. }
  39. },
  40. deep: true,
  41. immediate: true,
  42. },
  43. isUpload: {
  44. handler(val) {
  45. console.log("上传子级开关", val);
  46. if (val) {
  47. this.uploadImage();
  48. } else {
  49. this.isUpload = false;
  50. }
  51. },
  52. deep: true,
  53. immediate: true,
  54. },
  55. },
  56. data() {
  57. return {
  58. isCameraActive: false,
  59. stream: null,
  60. captureInterval: null, // 新增定时器变量
  61. datetimeData: {
  62. date: Dayjs(new Date()).format("YYYY-MM-DD"),
  63. time: Dayjs(new Date()).format("HH:mm:ss"),
  64. week: Dayjs(new Date()).format("dddd"),
  65. },
  66. };
  67. },
  68. methods: {
  69. refreshTime() {
  70. let speed = 1000;
  71. let timer = null;
  72. let theNowTime = () => {
  73. // this.datePersonData.time = Dayjs(new Date()).format('HH:mm:ss')
  74. this.datetimeData.time = Dayjs(new Date()).format("HH:mm:ss");
  75. this.datetimeData.date = Dayjs(new Date()).format("YYYY-MM-DD");
  76. this.datetimeData.week = Dayjs(new Date()).format("dddd");
  77. };
  78. timer = setInterval(theNowTime, speed);
  79. this.$once("hook:beforeDestroy", () => {
  80. clearInterval(timer);
  81. timer = null;
  82. });
  83. },
  84. async startCamera() {
  85. try {
  86. const stream = await navigator.mediaDevices.getUserMedia({
  87. video: {
  88. width: { ideal: 1280 },
  89. height: { ideal: 800 },
  90. facingMode: "user",
  91. },
  92. });
  93. this.stream = stream;
  94. this.isCameraActive = true;
  95. this.$refs.video.srcObject = stream;
  96. if (this.isUpload) {
  97. setTimeout(() => {
  98. this.uploadImage();
  99. }, 1000);
  100. } else {
  101. // 新增定时截图功能
  102. this.captureInterval = setInterval(() => {
  103. this.captureImage();
  104. console.log("截图上传");
  105. }, 2500);
  106. }
  107. } catch (err) {
  108. console.error("摄像头访问错误:", err);
  109. alert(`摄像头访问失败: ${err.message}`);
  110. }
  111. },
  112. stopCamera() {
  113. if (this.stream) {
  114. this.stream.getTracks().forEach((track) => track.stop());
  115. this.isCameraActive = false;
  116. this.$refs.video.srcObject = null;
  117. this.stream = null;
  118. // 停止定时器
  119. if (this.captureInterval) {
  120. clearInterval(this.captureInterval);
  121. this.captureInterval = null;
  122. }
  123. }
  124. },
  125. // 新增截图方法
  126. // async captureImage() {
  127. // const video = this.$refs.video;
  128. // video.currentTime = 1;
  129. // const canvas = document.createElement("canvas");
  130. // canvas.width = video.videoWidth;
  131. // canvas.height = video.videoHeight;
  132. // canvas
  133. // .getContext("2d")
  134. // .drawImage(video, 0, 0, canvas.width, canvas.height);
  135. // // 下载到本地
  136. // // const link = document.createElement("a");
  137. // // link.download = `capture_${new Date()
  138. // // .toISOString()
  139. // // .replace(/[:.]/g, "-")}.png`;
  140. // // link.href = canvas.toDataURL("image/png");
  141. // // link.click();
  142. // // 将canvas转为Blob对象
  143. // canvas.toBlob(async (blob) => {
  144. // if (blob) {
  145. // console.log("blob数据", blob);
  146. // const formData = new FormData();
  147. // formData.append("timestamp", new Date().toISOString());
  148. // formData.append("file", blob, "screenshot.png");
  149. // console.log("上传数据", formData);
  150. // try {
  151. // // const res = await GetPersonByFace(formData);
  152. // // console.log("上传反馈", res);
  153. // // const response = await fetch("System/Person/GetPersonByFace", {
  154. // // method: "POST",
  155. // // body: formData,
  156. // // });
  157. // } catch (err) {
  158. // console.error("上传过程中出错:", err);
  159. // }
  160. // }
  161. // }, "image/png");
  162. // },
  163. async captureImage() {
  164. const video = this.$refs.video;
  165. if (video.paused) return;
  166. const canvas = document.createElement("canvas");
  167. const cropWidth = video.videoWidth * 0.5;
  168. const cropHeight = video.videoHeight * 0.98;
  169. // 设置canvas尺寸为选择区域大小
  170. canvas.width = cropWidth;
  171. canvas.height = cropHeight;
  172. const x = (video.videoWidth - cropWidth) / 2;
  173. const y = (video.videoHeight - cropHeight) / 2;
  174. const ctx = canvas.getContext("2d");
  175. //中心60%区域
  176. ctx.drawImage(
  177. video,
  178. x,
  179. y,
  180. cropWidth,
  181. cropHeight,
  182. 0,
  183. 0,
  184. cropWidth,
  185. cropHeight
  186. );
  187. // canvas.width = video.videoWidth;
  188. // canvas.height = video.videoHeight;
  189. // const ctx = canvas.getContext("2d");
  190. // ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
  191. try {
  192. const base64Data = canvas.toDataURL("image/png");
  193. // console.log("上传数据:Base64", base64Data);
  194. // 替换YOUR_SERVER_URL为你的实际服务器地址
  195. const response = await fetch(
  196. "/yapi/System/Person/GetPersonByFaceBase64",
  197. {
  198. method: "POST",
  199. headers: {
  200. token: localStorage.getItem("token"),
  201. "Content-Type": "application/json",
  202. },
  203. body: JSON.stringify({
  204. data: base64Data,
  205. fileModule: 2,
  206. }),
  207. }
  208. );
  209. const result = await response.json();
  210. // console.log("上传反馈", response, result);
  211. if (result.code === 20000) {
  212. // console.log("服务器返回数据:", result);
  213. this.$emit("output", result.data);
  214. this.uploadImage();
  215. // setTimeout(() => {
  216. // this.stopCamera();
  217. // }, 200);
  218. }
  219. } catch (err) {
  220. console.error("上传过程中出错:", err);
  221. }
  222. },
  223. async uploadImage() {
  224. const video = this.$refs.video;
  225. const canvas = document.createElement("canvas");
  226. const cropWidth = video.videoWidth * 0.5;
  227. const cropHeight = video.videoHeight * 0.98;
  228. // 设置canvas尺寸为选择区域大小
  229. canvas.width = cropWidth;
  230. canvas.height = cropHeight;
  231. const x = (video.videoWidth - cropWidth) / 2;
  232. const y = (video.videoHeight - cropHeight) / 2;
  233. const ctx = canvas.getContext("2d");
  234. //中心60%区域
  235. ctx.drawImage(
  236. video,
  237. x,
  238. y,
  239. cropWidth,
  240. cropHeight,
  241. 0,
  242. 0,
  243. cropWidth,
  244. cropHeight
  245. );
  246. // ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
  247. const timestampDiv = document.getElementById("timestamp");
  248. // 在canvas上绘制时间戳
  249. ctx.font = "24px Arial";
  250. ctx.fillStyle = "white";
  251. ctx.fillText(timestampDiv.textContent, 20, canvas.height - 20);
  252. try {
  253. const base64Data = canvas.toDataURL("image/png");
  254. // console.log("上传数据:Base64", base64Data);
  255. // 替换YOUR_SERVER_URL为你的实际服务器地址
  256. const response = await fetch("/yapi/File/UploadBase64", {
  257. method: "POST",
  258. headers: {
  259. token: localStorage.getItem("token"),
  260. "Content-Type": "application/json",
  261. },
  262. body: JSON.stringify({
  263. data: base64Data,
  264. fileModule: 1,
  265. }),
  266. });
  267. const result = await response.json();
  268. // console.log("上传反馈", response, result);
  269. if (result.code === 20000) {
  270. console.log("服务器上传返回数据:", result);
  271. this.$emit("outputPath", result.data);
  272. setTimeout(() => {
  273. this.stopCamera();
  274. }, 200);
  275. }
  276. this.isUpload = false;
  277. } catch (err) {
  278. console.error("上传过程中出错:", err);
  279. }
  280. },
  281. },
  282. created() {
  283. this.startCamera();
  284. this.refreshTime();
  285. },
  286. beforeDestroy() {
  287. this.stopCamera();
  288. },
  289. };
  290. </script>
  291. <style scoped>
  292. .videoContainer {
  293. position: relative;
  294. width: 50%; /* 容器宽度设为50% */
  295. height: 100%; /* 容器高度设为100% */
  296. margin: 0 auto; /* 居中显示 */
  297. overflow: hidden; /* 隐藏溢出部分 */
  298. }
  299. video {
  300. height: 800px;
  301. width: 1280px;
  302. transform: translate(-25%, 0%);
  303. /* width: 100%;
  304. max-width: 500px; */
  305. background: #000;
  306. }
  307. #timestamp {
  308. position: absolute;
  309. bottom: 20px;
  310. left: 20px;
  311. color: white;
  312. font-size: 24px;
  313. background-color: rgba(0, 0, 0, 0.5);
  314. padding: 5px;
  315. }
  316. </style>