|
@@ -1,53 +1,25 @@
|
|
<template>
|
|
<template>
|
|
<div>
|
|
<div>
|
|
- <div class="demo-upload-list" v-for="item in uploadList" :key="item.url">
|
|
|
|
- <template v-if="item.status === 'finished'">
|
|
|
|
- <img :src="item.url + '!/both/100x100'" />
|
|
|
|
- <div class="demo-upload-list-cover">
|
|
|
|
- <Icon
|
|
|
|
- type="ios-eye-outline"
|
|
|
|
- size="30"
|
|
|
|
- @click.native="handleView(item.url)"
|
|
|
|
- ></Icon>
|
|
|
|
- <Icon
|
|
|
|
- type="ios-trash-outline"
|
|
|
|
- size="30"
|
|
|
|
- @click.native="handleRemove(item)"
|
|
|
|
- ></Icon>
|
|
|
|
- </div>
|
|
|
|
- </template>
|
|
|
|
- <template v-else>
|
|
|
|
- <Progress
|
|
|
|
- v-if="item.showProgress"
|
|
|
|
- :percent="item.percentage"
|
|
|
|
- hide-info
|
|
|
|
- ></Progress>
|
|
|
|
- </template>
|
|
|
|
- </div>
|
|
|
|
- <Upload
|
|
|
|
- ref="upload"
|
|
|
|
- v-show="
|
|
|
|
- this.uploadList.length < 6 &&
|
|
|
|
- !(this.uploadList.filter(v => v.status === 'uploading').length > 0)
|
|
|
|
- "
|
|
|
|
- :accept="this.format.map(v => 'image/' + v).join()"
|
|
|
|
- :data="headers"
|
|
|
|
- :show-upload-list="false"
|
|
|
|
- :default-file-list="defaultList2"
|
|
|
|
- :on-success="handleSuccess"
|
|
|
|
- :format="format"
|
|
|
|
- :max-size="5 * 1024"
|
|
|
|
- :on-format-error="handleFormatError"
|
|
|
|
- :on-exceeded-size="handleMaxSize"
|
|
|
|
- :before-upload="handleBeforeUpload"
|
|
|
|
- :action="this.uploadUrl"
|
|
|
|
- type="drag"
|
|
|
|
- style="display: inline-block;width:100px;"
|
|
|
|
- >
|
|
|
|
- <div style="width: 100px;height:100px;line-height: 100px;">
|
|
|
|
- <Icon type="ios-camera" size="40"></Icon>
|
|
|
|
|
|
+ <div class="demo-upload-list" v-for="item in uploadList" :key="item">
|
|
|
|
+ <img :src="item" />
|
|
|
|
+ <div class="demo-upload-list-cover">
|
|
|
|
+ <Icon
|
|
|
|
+ type="ios-eye-outline"
|
|
|
|
+ size="30"
|
|
|
|
+ @click.native="handleView(item)"
|
|
|
|
+ ></Icon>
|
|
|
|
+ <Icon
|
|
|
|
+ type="ios-trash-outline"
|
|
|
|
+ size="30"
|
|
|
|
+ @click.native="handleRemove(item)"
|
|
|
|
+ ></Icon>
|
|
</div>
|
|
</div>
|
|
- </Upload>
|
|
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <div v-if="true" class="demo-upload-list plus" @click="prepareUpload">
|
|
|
|
+ +
|
|
|
|
+ </div>
|
|
|
|
+
|
|
<Modal title="查看图片" v-model="visible" footer-hide>
|
|
<Modal title="查看图片" v-model="visible" footer-hide>
|
|
<img
|
|
<img
|
|
:src="imgUrl"
|
|
:src="imgUrl"
|
|
@@ -66,37 +38,87 @@
|
|
</div>
|
|
</div>
|
|
</Modal>
|
|
</Modal>
|
|
<div>最多上传6张图片</div>
|
|
<div>最多上传6张图片</div>
|
|
|
|
+
|
|
|
|
+ <Modal
|
|
|
|
+ title="上传"
|
|
|
|
+ v-model="uploadModalVisible"
|
|
|
|
+ mask
|
|
|
|
+ footer-hide
|
|
|
|
+ :mask-closable="false"
|
|
|
|
+ :closable="false"
|
|
|
|
+ >
|
|
|
|
+ <div>
|
|
|
|
+ <!-- TODO: 超过6张,不显示二维码 -->
|
|
|
|
+ <div v-if="qrValue" style="display: flex">
|
|
|
|
+ <qrcode
|
|
|
|
+ :value="qrValue"
|
|
|
|
+ :options="{ width: 200 }"
|
|
|
|
+ style="margin-left: -10px;"
|
|
|
|
+ ></qrcode>
|
|
|
|
+ <div style="margin-top: 10px;">
|
|
|
|
+ <div>
|
|
|
|
+ 请使用<span style="font-weight: 900; color: #1E90FF;">微信</span
|
|
|
|
+ >扫描二维码后,在微信小程序上拍照,并上传文件。
|
|
|
|
+ </div>
|
|
|
|
+ <div v-if="qrScanned" style="margin-top: 30px; font-size: 30px;">
|
|
|
|
+ {{ uploaded ? "已上传" : "已扫描" }}
|
|
|
|
+ <Icon type="md-checkmark" />
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div v-else>正在获取二维码...</div>
|
|
|
|
+
|
|
|
|
+ <div class="demo-upload-list" v-for="item in totalList" :key="item">
|
|
|
|
+ <img :src="item" />
|
|
|
|
+ <div class="demo-upload-list-cover">
|
|
|
|
+ <Icon
|
|
|
|
+ type="ios-eye-outline"
|
|
|
|
+ size="30"
|
|
|
|
+ @click.native="handleView(item)"
|
|
|
|
+ ></Icon>
|
|
|
|
+ <Icon
|
|
|
|
+ type="ios-trash-outline"
|
|
|
|
+ size="30"
|
|
|
|
+ @click.native="handleRemoveTotal(item)"
|
|
|
|
+ ></Icon>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <div style="display: flex; justify-content: center">
|
|
|
|
+ <Button @click="modalCloseClicked">关闭</Button>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </Modal>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script>
|
|
<script>
|
|
-import MD5 from "js-md5";
|
|
|
|
|
|
+import VueQrcode from "@chenfengyuan/vue-qrcode";
|
|
|
|
+import { createNamespacedHelpers } from "vuex";
|
|
|
|
+const { mapState } = createNamespacedHelpers("examingHomeModule");
|
|
|
|
|
|
export default {
|
|
export default {
|
|
name: "UploadPhotos",
|
|
name: "UploadPhotos",
|
|
- props: ["defaultList"],
|
|
|
|
|
|
+ // props: ["defaultList", "qrValue"],
|
|
|
|
+ props: {
|
|
|
|
+ examQuestion: Object,
|
|
|
|
+ defaultList: Array,
|
|
|
|
+ qrValue: String,
|
|
|
|
+ },
|
|
data() {
|
|
data() {
|
|
return {
|
|
return {
|
|
- // defaultList: [
|
|
|
|
- // {
|
|
|
|
- // name: "a42bdcc1178e62b4694c830f028db5c0",
|
|
|
|
- // url:
|
|
|
|
- // "https://o5wwk8baw.qnssl.com/a42bdcc1178e62b4694c830f028db5c0/avatar"
|
|
|
|
- // },
|
|
|
|
- // {
|
|
|
|
- // name: "bc7521e033abdd1e92222d733590f104",
|
|
|
|
- // url:
|
|
|
|
- // "https://o5wwk8baw.qnssl.com/bc7521e033abdd1e92222d733590f104/avatar"
|
|
|
|
- // }
|
|
|
|
- // ],
|
|
|
|
imgUrl: "",
|
|
imgUrl: "",
|
|
visible: false,
|
|
visible: false,
|
|
|
|
+ uploadModalVisible: false,
|
|
rotate: 0,
|
|
rotate: 0,
|
|
- defaultList2: [...this.defaultList],
|
|
|
|
|
|
+ // defaultList2: [...this.defaultList],
|
|
uploadList: [],
|
|
uploadList: [],
|
|
|
|
+ totalList: [],
|
|
uploadUrl: "",
|
|
uploadUrl: "",
|
|
headers: {},
|
|
headers: {},
|
|
format: ["jpg", "jpeg", "png"],
|
|
format: ["jpg", "jpeg", "png"],
|
|
|
|
+ qrScanned: false,
|
|
|
|
+ uploaded: false,
|
|
};
|
|
};
|
|
},
|
|
},
|
|
methods: {
|
|
methods: {
|
|
@@ -106,175 +128,68 @@ export default {
|
|
this.visible = true;
|
|
this.visible = true;
|
|
},
|
|
},
|
|
handleRemove(file) {
|
|
handleRemove(file) {
|
|
- const fileList = this.$refs.upload.fileList;
|
|
|
|
- this.$emit("on-photo-removed", file.url);
|
|
|
|
- this.$refs.upload.fileList.splice(fileList.indexOf(file), 1);
|
|
|
|
- },
|
|
|
|
- handleSuccess(res, file) {
|
|
|
|
- file.url = this.resultUrl;
|
|
|
|
- // file.name = "7eb99afb9d5f317c912f08b5212fd69a";
|
|
|
|
- this.$emit("on-photo-added", this.resultUrl);
|
|
|
|
- },
|
|
|
|
- handleFormatError(file) {
|
|
|
|
- this.$Notice.warning({
|
|
|
|
- title: "只接受jpg/jpeg/png图片文件",
|
|
|
|
- desc: file.name,
|
|
|
|
- });
|
|
|
|
|
|
+ // const fileList = this.$refs.upload.fileList;
|
|
|
|
+ this.$emit("on-photo-removed", file);
|
|
|
|
+ // this.$refs.upload.fileList.splice(fileList.indexOf(file), 1);
|
|
},
|
|
},
|
|
- handleMaxSize(file) {
|
|
|
|
- const MAX_UPLOAD_SIZE = 5;
|
|
|
|
- this.$Notice.warning({
|
|
|
|
- title: "文件过大",
|
|
|
|
- desc: file.name + `超过${MAX_UPLOAD_SIZE}M.`,
|
|
|
|
- });
|
|
|
|
|
|
+ handleRemoveTotal(file) {
|
|
|
|
+ // const fileList = this.$refs.upload.fileList;
|
|
|
|
+ // this.$emit("on-photo-removed", file);
|
|
|
|
+ this.totalList.splice(this.totalList.indexOf(file), 1);
|
|
},
|
|
},
|
|
- fileFormatCheck(file, resolve, reject) {
|
|
|
|
- function getMimetype(signature) {
|
|
|
|
- switch (signature) {
|
|
|
|
- case "89504E47":
|
|
|
|
- return "image/png";
|
|
|
|
- case "47494638":
|
|
|
|
- return "image/gif";
|
|
|
|
- case "25504446":
|
|
|
|
- return "application/pdf";
|
|
|
|
- case "FFD8FFDB":
|
|
|
|
- case "FFD8FFE0":
|
|
|
|
- case "FFD8FFE1":
|
|
|
|
- return "image/jpeg";
|
|
|
|
- case "504B0304":
|
|
|
|
- return "application/zip";
|
|
|
|
- case "504B34":
|
|
|
|
- return "application/zip";
|
|
|
|
- default:
|
|
|
|
- return "Unknown filetype";
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const filereader = new FileReader();
|
|
|
|
- let uploads = [];
|
|
|
|
- filereader.onloadend = evt => {
|
|
|
|
- if (evt.target.readyState === FileReader.DONE) {
|
|
|
|
- const uint = new Uint8Array(evt.target.result);
|
|
|
|
- let bytes = [];
|
|
|
|
- uint.forEach(byte => {
|
|
|
|
- bytes.push(byte.toString(16));
|
|
|
|
- });
|
|
|
|
- const hex = bytes.join("").toUpperCase();
|
|
|
|
- uploads.push({
|
|
|
|
- filename: file.name,
|
|
|
|
- filetype: file.type ? file.type : "Unknown/Extension missing",
|
|
|
|
- binaryFileType: getMimetype(hex),
|
|
|
|
- hex: hex,
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- if (
|
|
|
|
- ["image/png", "image/gif", "image/jpeg"].includes(getMimetype(hex))
|
|
|
|
- ) {
|
|
|
|
- resolve();
|
|
|
|
- } else {
|
|
|
|
- console.log("binary file type check: not zip or pdf");
|
|
|
|
- this.$Notice.warning({
|
|
|
|
- title: "文件损坏",
|
|
|
|
- desc: file.name + " 文件无法以 " + "png/jpg/jpeg" + " 格式读取。",
|
|
|
|
- });
|
|
|
|
- this.loadingStatus = false;
|
|
|
|
- reject("作答文件损坏");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
- const blob = file.slice(0, 4);
|
|
|
|
- filereader.readAsArrayBuffer(blob);
|
|
|
|
|
|
+ // handleSuccess(res, file) {
|
|
|
|
+ // // file.url = this.resultUrl;
|
|
|
|
+ // this.$emit("on-photo-added", this.resultUrl);
|
|
|
|
+ // },
|
|
|
|
+ prepareUpload() {
|
|
|
|
+ this.uploadModalVisible = true;
|
|
|
|
+ this.totalList = [...this.uploadList];
|
|
},
|
|
},
|
|
- async handleBeforeUpload(file) {
|
|
|
|
- const result = await new Promise((resolve, reject) =>
|
|
|
|
- this.fileFormatCheck(file, resolve, reject)
|
|
|
|
- );
|
|
|
|
- if (result) {
|
|
|
|
- // this.$Notice.warning({
|
|
|
|
- // title: `最多上传${MAX_UPLOADS_NUM}张照片。`
|
|
|
|
- // });
|
|
|
|
- return Promise.resolve(false);
|
|
|
|
- }
|
|
|
|
- const MAX_UPLOADS_NUM = 6;
|
|
|
|
- const check = this.uploadList.length < MAX_UPLOADS_NUM;
|
|
|
|
- if (!check) {
|
|
|
|
- this.$Notice.warning({
|
|
|
|
- title: `最多上传${MAX_UPLOADS_NUM}张照片。`,
|
|
|
|
- });
|
|
|
|
- // return false;
|
|
|
|
- return Promise.resolve(false);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- function readAsArrayBuffer(file) {
|
|
|
|
- return new Promise(function(resolve) {
|
|
|
|
- var reader = new FileReader();
|
|
|
|
- reader.readAsArrayBuffer(file);
|
|
|
|
- reader.onload = function(e) {
|
|
|
|
- resolve(e.target.result);
|
|
|
|
- };
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const buffer = await readAsArrayBuffer(file);
|
|
|
|
-
|
|
|
|
- // console.log(buffer);
|
|
|
|
- // var view1 = new Uint8Array(buffer);
|
|
|
|
- // console.log(buffer[0], buffer[1], buffer[429721]);
|
|
|
|
- const fileMd5 = MD5(buffer);
|
|
|
|
- // console.log(fileMd5);
|
|
|
|
-
|
|
|
|
- const examRecordDataId = this.$route.params.examRecordDataId - 0;
|
|
|
|
- const order = this.$route.params.order - 0;
|
|
|
|
- const fileSuffix = file.name.split(".").pop();
|
|
|
|
- const params = new URLSearchParams();
|
|
|
|
- params.append("examRecordDataId", examRecordDataId);
|
|
|
|
- params.append("order", order);
|
|
|
|
- params.append("fileSuffix", fileSuffix);
|
|
|
|
- params.append("fileMd5", fileMd5);
|
|
|
|
- const res = await this.$http.post(
|
|
|
|
- "/api/ecs_oe_student/examControl/upyunSignature",
|
|
|
|
- params,
|
|
|
|
- {
|
|
|
|
- examRecordDataId,
|
|
|
|
- order,
|
|
|
|
- fileSuffix,
|
|
|
|
- fileMd5,
|
|
|
|
- },
|
|
|
|
- { headers: { "content-type": "application/x-www-form-urlencoded" } }
|
|
|
|
- );
|
|
|
|
|
|
+ modalCloseClicked() {
|
|
|
|
+ this.uploadModalVisible = false;
|
|
|
|
+ this.$emit("on-photos-reseted", this.totalList);
|
|
|
|
|
|
- // console.log(res);
|
|
|
|
- this.headers = {
|
|
|
|
- policy: res.data.policy,
|
|
|
|
- authorization: res.data.signature,
|
|
|
|
- };
|
|
|
|
- this.uploadUrl = res.data.uploadUrl;
|
|
|
|
- this.resultUrl = res.data.upyunFileDomain + res.data.filePath;
|
|
|
|
- return check;
|
|
|
|
|
|
+ // TODO: 在二维码被扫描,文件没得到之前,提示是否关闭。
|
|
|
|
+ // TODO: 检查是否超过6张
|
|
},
|
|
},
|
|
},
|
|
},
|
|
mounted() {
|
|
mounted() {
|
|
- this.uploadList = this.$refs.upload.fileList;
|
|
|
|
|
|
+ this.uploadList = this.defaultList;
|
|
|
|
+ // this.uploadList.push(
|
|
|
|
+ // ...[
|
|
|
|
+ // "https://o5wwk8baw.qnssl.com/a42bdcc1178e62b4694c830f028db5c0/avatar",
|
|
|
|
+ // "https://o5wwk8baw.qnssl.com/bc7521e033abdd1e92222d733590f104/avatar",
|
|
|
|
+ // ]
|
|
|
|
+ // );
|
|
|
|
+ },
|
|
|
|
+ computed: {
|
|
|
|
+ ...mapState(["questionQrCodeScanned", "pictureAnswer"]),
|
|
},
|
|
},
|
|
watch: {
|
|
watch: {
|
|
- uploadList: {
|
|
|
|
|
|
+ defaultList: {
|
|
handler: function update() {
|
|
handler: function update() {
|
|
- // 禁止同时上传附件
|
|
|
|
- // for (const t of this.uploadList) {
|
|
|
|
- // console.log(t.status);
|
|
|
|
- // }
|
|
|
|
- if (this.uploadList.filter(v => v.status === "uploading").length > 0) {
|
|
|
|
- this.$nextTick(() => {
|
|
|
|
- this.$Spin.show({});
|
|
|
|
- });
|
|
|
|
- } else {
|
|
|
|
- this.$nextTick(() => {
|
|
|
|
- this.$Spin.hide();
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
|
|
+ this.uploadList = this.defaultList;
|
|
},
|
|
},
|
|
deep: true,
|
|
deep: true,
|
|
},
|
|
},
|
|
|
|
+ questionQrCodeScanned(value) {
|
|
|
|
+ // console.log(this.examQuestion.studentAnswer);
|
|
|
|
+ // console.log("watch", value);
|
|
|
|
+ if (value.order === this.examQuestion.order) {
|
|
|
|
+ this.qrScanned = true;
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ pictureAnswer(value) {
|
|
|
|
+ // console.log(this.examQuestion.studentAnswer);
|
|
|
|
+ console.log("watch", value);
|
|
|
|
+ this.uploaded = true;
|
|
|
|
+ if (value.order === this.examQuestion.order) {
|
|
|
|
+ this.totalList.push(...[...new Set(value.fileUrl.split(","))]);
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ components: {
|
|
|
|
+ qrcode: VueQrcode,
|
|
},
|
|
},
|
|
};
|
|
};
|
|
</script>
|
|
</script>
|
|
@@ -297,6 +212,13 @@ export default {
|
|
width: 100%;
|
|
width: 100%;
|
|
height: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
|
|
+.plus {
|
|
|
|
+ font-size: 48px;
|
|
|
|
+}
|
|
|
|
+.plus:hover {
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ color: blueviolet;
|
|
|
|
+}
|
|
.demo-upload-list-cover {
|
|
.demo-upload-list-cover {
|
|
display: none;
|
|
display: none;
|
|
position: absolute;
|
|
position: absolute;
|