Commit 520b7f00 by xiaowenfeng

1、新增了人脸识别模块;

2、新增了路由,并使用hash模式;
parent 49ca98e3
......@@ -9,11 +9,12 @@
},
"dependencies": {
"core-js": "^3.6.5",
"face-api.js": "^0.22.2",
"jquery": "^3.5.1",
"pdfjs-dist": "^2.3.200",
"register-service-worker": "^1.7.1",
"vue": "^2.6.11",
"vue-router": "^3.2.0"
"vue-router": "^3.3.4"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.4.0",
......
No preview for this file type
<template>
<div id="app">
<img
src="./assets/loading-icon.gif"
class="loadingIcon"
v-show="isLoading"
alt="loading"
/>
<div class="pageControll">
<i
:class="['jiantou', 'jiantou-left']"
v-show="pageIndex === 1 ? false : true"
title="上一页"
@click="previous"
>&#xe633;</i
>
<i
:class="['jiantou', 'jiantou-right']"
v-show="pageIndex === pageLength ? false : true"
title="下一页"
@click="next"
>&#xe633;</i
>
</div>
<div class="toolbar">
<div id="toolbarContainer">
<div id="toolbarViewer">
<div id="toolbarViewerLeft">
<div class="splitToolbarButton hiddenSmallView">
<button
:class="[
'toolbarButton',
'pageUp',
pageIndex === 1 ? 'taoolbarCantUse' : ''
]"
title="上一页"
id="previous"
tabindex="13"
data-l10n-id="previous"
@click="previous"
>
<span data-l10n-id="previous_label">上一页</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
<button
:class="[
'toolbarButton',
'pageDown',
pageIndex === pageLength ? 'taoolbarCantUse' : ''
]"
title="下一页"
id="next"
tabindex="14"
data-l10n-id="next"
@click="next"
>
<span data-l10n-id="next_label">下一页</span>
</button>
</div>
<input
type="number"
id="pageNumber"
class="toolbarField pageNumber"
title="页码"
v-model="pageIndex"
size="4"
min="1"
tabindex="15"
data-l10n-id="page"
autocomplete="off"
disabled="disabled"
/>
<span id="numPages" class="toolbarLabel">/ {{ pageLength }}</span>
<button
id="draggrad"
title="抓手工具"
:class="[
'toolbarButton',
'draggrad',
draggradActive ? 'draggradActive' : ''
]"
tabindex="12"
data-l10n-id="findbar"
@click="draggradHandle"
>
<span data-l10n-id="findbar_label">抓手</span>
</button>
</div>
<div id="toolbarViewerMiddle">
<div class="splitToolbarButton">
<button
id="zoomOut"
:class="[
'toolbarButton',
'zoomOut',
this.pageSize <= 0.5 ? 'taoolbarCantUse' : ''
]"
title="缩小"
tabindex="21"
data-l10n-id="zoom_out"
@click="zoomOut(null)"
>
<span data-l10n-id="zoom_out_label">放大</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
<button
id="zoomIn"
:class="[
'toolbarButton',
'zoomIn',
this.pageSize >= 4 ? 'taoolbarCantUse' : ''
]"
title="放大"
tabindex="22"
data-l10n-id="zoom_in"
@click="zoomIn(null)"
>
<span data-l10n-id="zoom_in_label">缩小</span>
</button>
</div>
<span id="scaleSelectContainer" class="dropdownToolbarButton">
<select
id="scaleSelect"
title="缩放选择"
tabindex="23"
data-l10n-id="zoom"
v-model="selected"
@change="changeSelected(selected)"
>
<option
v-for="(item, index) in zoomList"
:key="index"
:value="index"
:disabled="Object.keys(item)[0] === 'custom' ? true : false"
v-show="
Object.keys(item)[0] === 'custom'
? isFirefox
? true
: false
: true
"
>{{ item[Object.keys(item)[0]].page_scale_percent }}</option
>
</select>
</span>
</div>
</div>
</div>
</div>
<div id="page">
<div
id="viewerContainerBox"
@mousedown="drag($event)"
:style="{ cursor: draggradActive ? 'grab' : 'auto' }"
>
<div class="canvasWrapper"></div>
<div id="textLayerDiv" class="textLayer"></div>
</div>
</div>
<router-view></router-view>
</div>
</template>
<script>
import pdfJs from "pdfjs-dist/build/pdf";
import { TextLayerBuilder } from "pdfjs-dist/web/pdf_viewer";
import $ from "jquery";
export default {
data() {
return {
pageIndex: 1, // pdf页码
pageLength: null, // 总页码
startTime: null,
scale: 2, // 缩放比例
borderSize: 9, // viewerContainer容器border大小
shouldRenderHtml: false, // pdf预览时是否需要渲染成html
pageSize: 1,
selected: 2,
pdfUrl: "",
pdf: null,
zoomList: [
{ "0.5": { page_scale_percent: "50%", value: 0.5 } },
{ "0.75": { page_scale_percent: "75%", value: 0.75 } },
{ "1": { page_scale_percent: "100%", value: 1 } },
{ "1.25": { page_scale_percent: "125%", value: 1.25 } },
{ "1.5": { page_scale_percent: "150%", value: 1.5 } },
{ "1.75": { page_scale_percent: "175%", value: 1.75 } },
{ "2": { page_scale_percent: "200%", value: 2 } },
{ "3": { page_scale_percent: "300%", value: 3 } },
{ "4": { page_scale_percent: "400%", value: 4 } },
{ custom: { page_scale_percent: "", value: 1 } }
],
draggradActive: false,
isFirefox: false,
playInitializationData: null,
isLoading: false
};
},
mounted() {
this.isFirefox = navigator.userAgent.indexOf("Firefox") > 1;
this.playInitializationData = window.parent.playInitializationData;
this.LMSPlayInitialize();
this.LMSTrackingInitialize();
// this.LMSCatalogUrl();
this.LMSGetLocationPoint();
this.LMSGetLessonStatus();
this.startTime = new Date().getTime();
pdfJs.GlobalWorkerOptions.workerSrc = require("pdfjs-dist/build/pdf.worker");
this.preview();
},
methods: {
async preview() {
if (this.pdf === null) {
let pdf = await pdfJs.getDocument(
this.pdfUrl === ""
? "http://b2b-flv.qida.com/product/20191105/23386fd7-5551-4fa2-81cc-025945a75eeb/out.pdf"
: this.pdfUrl
);
console.log("获取PDF", pdf);
this.pdf = pdf;
}
this.pageLength = this.pdf._pdfInfo.numPages;
let page = await this.pdf.getPage(this.pageIndex);
const devicePixelRatio = window.devicePixelRatio;
const scale = this.pageSize * this.scale * devicePixelRatio;
const viewport = page.getViewport({ scale: scale });
let { bufferCanvas, textLayerDiv, bodyHeight } = this.initPage(
page,
viewport
);
this.renderCanvas(bufferCanvas, viewport, page);
if (this.shouldRenderHtml) {
let textContent = await page.getTextContent();
this.renderHtml(
textLayerDiv,
page,
scale,
viewport,
bodyHeight,
textContent
);
}
},
initPage(page, viewport) {
$("#page").css("height", $("body").height() - $(".toolbar").height());
let pers = viewport.width / viewport.height;
let canvasWrapper = $(".canvasWrapper");
let viewerContainer = $("#viewerContainerBox");
let textLayerDiv = $("#textLayerDiv");
let bodyHeight = $("#page").height() - this.borderSize * 2;
let pdfHeight = this.pageSize * bodyHeight;
let pdfWidth = this.pageSize * pers * bodyHeight;
let bufferCanvas = document.createElement("canvas");
bufferCanvas.height = viewport.height;
bufferCanvas.width = viewport.width;
viewerContainer.attr("style", "");
viewerContainer.css({
border: this.borderSize + "px solid transparent",
height: pdfHeight,
width: pdfWidth
});
canvasWrapper.css({
height: pdfHeight,
width: pdfWidth
});
$(bufferCanvas).css({
height: pdfHeight,
width: pdfWidth
});
textLayerDiv.css({
height: pdfHeight,
width: pdfWidth
});
return { bufferCanvas, textLayerDiv: textLayerDiv[0], bodyHeight };
},
async renderCanvas(bufferCanvas, viewport, page) {
let bufferContext = bufferCanvas.getContext("2d");
let renderContext = {
canvasContext: bufferContext,
viewport: viewport
};
await page.render(renderContext);
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d");
context.height = bufferCanvas.height;
context.width = bufferCanvas.width;
context.drawImage(
bufferCanvas,
0,
0,
canvas.widgth,
canvas.height,
0,
0,
canvas.width,
canvas.height
);
$(".canvasWrapper").html(bufferCanvas);
},
renderHtml(textLayerDiv, page, scale, viewport, bodyHeight, textContent) {
$("#textLayerDiv").html("");
const textLayer = new TextLayerBuilder({
textLayerDiv: textLayerDiv,
pageIndex: this.pageIndex,
viewport: page.getViewport({
scale: (scale * (this.pageSize * bodyHeight)) / viewport.height
})
});
textLayer.setTextContent(textContent);
textLayer.render();
},
alert(title, msg, boxWidth, autoClose) {
window.parent.$.alert({
title: title,
content: msg,
useBootstrap: false,
boxWidth: boxWidth,
autoClose: autoClose ? "ok|2000" : false,
type: "blue",
// typeAnimated: true,
animation: "top",
closeAnimation: "bottom",
buttons: {
ok: {
text: "ok",
btnClass: "btn-blue"
}
}
});
},
zoomIn(pageSize) {
let result = Number((this.pageSize + 0.05).toFixed(10));
console.log("result:", result);
let currentSize = pageSize ? pageSize : result;
if (currentSize > 4) {
return;
}
this.pageSize = pageSize ? pageSize : result;
this.customPercent();
this.preview();
},
zoomOut(pageSize) {
let result = Number((this.pageSize - 0.05).toFixed(10));
let currentSize = pageSize ? pageSize : result;
if (currentSize < 0.5) {
return;
}
this.pageSize = pageSize ? pageSize : result;
this.customPercent();
this.preview();
},
customPercent() {
let index = this.zoomList.length - 1;
this.selected = index;
let item = this.zoomList[index];
let key = Object.keys(item)[0];
let result = Number((this.pageSize * 100).toFixed(10));
this.zoomList[index][key].page_scale_percent = result + "%";
},
previous() {
if (this.pageIndex === 1) {
return;
}
if (this.isLoading) {
return;
}
this.pageIndex = this.pageIndex - 1;
this.LMSSetLocationPoint();
this.LMSSetLessProgress();
this.LMSSetSessionTime();
this.LMSCommit();
this.preview();
},
next() {
if (this.pageIndex === this.pageLength) {
return;
}
if (this.isLoading) {
return;
}
this.pageIndex = this.pageIndex + 1;
this.LMSSetLocationPoint();
this.LMSSetLessProgress();
this.LMSSetSessionTime();
if (this.pageIndex === this.pageLength) {
this.LMSSetLessonStatus("completed");
}
this.LMSCommit();
this.preview();
},
changeSelected(index) {
let item = this.zoomList[index];
let value = item[Object.keys(item)[0]].value;
if (value > this.pageSize) {
this.zoomOut(value);
} else if (value < this.pageSize) {
this.zoomIn(value);
}
},
draggradHandle() {
this.draggradActive = !this.draggradActive;
},
drag(event) {
if (!this.draggradActive) {
return;
}
let target = event.currentTarget;
let x = $(target).offset().left;
let y = $(target).offset().top;
let e = event || window.event;
let left = e.pageX - x;
let top = e.pageY - y;
$(target).css({
position: "absolute",
left: x,
top: y,
cursor: "grab"
});
document.onmousemove = function(e) {
let x = e.pageX - left;
let y = e.pageY - top;
$(target).css({
left: x,
top: y
});
if (e.preventDefault) {
e.preventDefault();
} else {
window.event.returnValue == false;
}
};
document.onmouseup = function() {
document.onmousemove = null;
document.onmouseup = null;
};
},
LMSPlayInitialize() {
$.ajax({
type: "post",
url: "/play/initialize.do",
data: this.playInitializationData,
dataType: "json",
async: false,
success: data => {
if (data.executeStatus !== 0) {
this.alert(
"提示!",
data.errorMsg + "\n错误代码:" + data.errorCode,
"30%"
);
}
this.pdfUrl = data.values.itemUrl;
}
});
},
LMSTrackingInitialize() {
$.ajax({
type: "post",
url: "/play/tracking/initialize.do",
data: this.playInitializationData,
dataType: "json",
async: false,
success: data => {
if (data.executeStatus !== 0) {
this.alert(
"提示!",
data.errorMsg + "\n错误代码:" + data.errorCode,
"30%"
);
}
if (data.values != undefined) {
this.playInitializationData.attempId = data.values.attempId;
}
}
});
},
LMSGetValueUrl(fn) {
$.ajax({
type: "post",
url: "/play/tracking/element/get.do",
data: this.playInitializationData,
dataType: "json",
async: false,
success: data => {
if (data.executeStatus !== 0) {
this.alert(
"提示!",
data.errorMsg + "\n错误代码:" + data.errorCode,
"30%"
);
}
if (!!fn && typeof fn == "function") {
fn(data);
}
}
});
},
LMSSetValueUrl(fn) {
this.isLoading = true;
$.ajax({
type: "post",
url: "/play/tracking/element/set.do",
data: this.playInitializationData,
dataType: "json",
async: false,
success: data => {
if (data.executeStatus !== 0) {
this.alert(
"提示!",
data.errorMsg + "\n错误代码:" + data.errorCode,
"30%"
);
}
if (!!fn && typeof fn == "function") {
fn(data);
}
},
complete: () => {
setTimeout(() => {
this.isLoading = false;
}, 1500);
}
});
},
LMSCatalogUrl(fn) {
$.ajax({
type: "post",
url: "/play/crs/catalog/get.do",
data: this.playInitializationData,
dataType: "json",
async: false,
success: data => {
if (data.executeStatus !== 0) {
this.alert(
"提示!",
data.errorMsg + "\n错误代码:" + data.errorCode,
"30%"
);
}
if (!!fn && typeof fn == "function") {
fn(data);
}
}
});
},
LMSGetLocationPoint() {
this.playInitializationData.element = "qida.core.lesson_location_point";
this.LMSGetValueUrl(data => {
if (data.values != undefined) {
this.pageIndex = parseInt(
data.values.result === "" || data.values.result === "0"
? 1
: data.values.result
);
}
});
},
LMSSetLocationPoint() {
this.playInitializationData.element = "qida.core.lesson_location_point";
this.playInitializationData.value = this.pageIndex;
this.LMSSetValueUrl();
},
LMSSetLessProgress() {
this.playInitializationData.element = "cmi.core.lesson_progress";
this.playInitializationData.value = parseInt(
(this.pageIndex / this.pageLength) * 100
);
this.LMSSetValueUrl();
},
LMSSetSessionTime() {
this.playInitializationData.element = "cmi.core.session_time";
let currentTime = new Date().getTime();
this.playInitializationData.value = this.timeToFormat(
(currentTime - this.startTime) / 1000
);
this.LMSSetValueUrl();
},
LMSSetLessonStatus(status) {
this.playInitializationData.element = "cmi.core.lesson_status";
this.playInitializationData.value = status;
this.LMSSetValueUrl();
},
LMSGetLessonStatus() {
this.playInitializationData.element = "cmi.core.lesson_status";
this.LMSGetValueUrl();
},
LMSCommit(fn) {
$.ajax({
type: "post",
url: "/play/tracking/commit.do",
data: this.playInitializationData,
dataType: "json",
async: false,
success: data => {
if (data.executeStatus !== 0) {
this.alert(
"提示!",
data.errorMsg + "\n错误代码:" + data.errorCode,
"30%"
);
}
if (!!fn && typeof fn == "function") {
fn(data);
}
}
});
},
timeToFormat(times) {
var result = "00:00:00";
var hour, minute, second;
if (times > 0) {
hour = Math.floor(times / 3600);
if (hour < 10) {
hour = "0" + hour;
}
minute = Math.floor((times - 3600 * hour) / 60);
if (minute < 10) {
minute = "0" + minute;
}
second = Math.floor((times - 3600 * hour - 60 * minute) % 60);
if (second < 10) {
second = "0" + second;
}
result = hour + ":" + minute + ":" + second;
}
return result;
}
}
};
</script>
<style lang="scss">
@import url("./css/viewer.css");
$jiantouPst: 30px;
* {
scrollbar-width: none;
}
#app {
width: 100%;
height: 100%;
position: relative;
}
#page {
width: 100%;
overflow: auto;
}
#viewerContainerBox {
margin: auto;
position: relative;
scrollbar-width: none;
}
.taoolbarCantUse {
opacity: 0.5;
}
.draggradActive {
background-color: rgba(255, 255, 255, 0.4) !important;
}
::-webkit-scrollbar {
display: none;
}
.loadingIcon {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
z-index: 99;
}
.pageControll {
width: 100%;
left: 50%;
top: 50%;
position: absolute;
transform: translate(-50%, -50%);
z-index: 99;
box-sizing: border-box;
}
.jiantou-right {
position: absolute;
right: $jiantouPst;
transform: rotateY(180deg);
cursor: pointer;
opacity: 0.5;
}
.jiantou-left {
position: absolute;
left: $jiantouPst;
cursor: pointer;
opacity: 0.5;
}
.jiantou:hover {
color: #fff;
border: 1px solid #fff;
padding: 0 30px;
background-color: rgba(0, 0, 0, 0.6);
border-radius: 5px;
opacity: 1;
}
</style>
<style lang="scss"></style>
......@@ -5,6 +5,14 @@ import router from "./router";
Vue.config.productionTip = false;
// 根据路由变化设置页面title
router.beforeEach((to, from, next) => {
if (to.meta.title) {
document.title = "企大-" + to.meta.title;
}
next();
});
new Vue({
router,
render: h => h(App)
......
import Vue from "vue";
import VueRouter from "vue-router";
import previewPDF from "../views/PreviewPDF.vue";
import faceDetect from "../views/FaceDetect.vue";
import faceRegister from "../views/FaceRegister.vue";
Vue.use(VueRouter);
const routes = [];
const routes = [
{
path: "/previewPDF",
component: previewPDF,
meta: {
title: "PDF预览"
}
},
{
path: "/faceDetect",
component: faceDetect,
meta: {
title: "人脸识别"
}
},
{
path: "/faceRegister",
component: faceRegister,
meta: {
title: "人脸登记"
}
}
];
const router = new VueRouter({
routes,
mode: "history"
routes
// mode: "history"
});
export default router;
module.exports = {
publicPath: process.env.NODE_ENV === "production" ? "./" : "/",
assetsDir: "static",
outputDir: "previewPDF"
outputDir: "previewPDF",
pwa: {
iconPaths: {
favicon32: "favicon.ico",
favicon16: "favicon.ico",
appleTouchIcon: "favicon.ico",
maskIcon: "favicon.ico",
msTileImage: "favicon.ico"
}
}
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment