|
@@ -0,0 +1,967 @@
|
|
|
+<template>
|
|
|
+ <el-dialog v-model="Visible" title="新增签章" width="1200" align-center>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="Visible = false">取消</el-button>
|
|
|
+ <el-button
|
|
|
+ v-if="activeName != null && sealFrom.createType != 2"
|
|
|
+ type="primary"
|
|
|
+ @click="submit()"
|
|
|
+ v-loading="opSignatureLoading"
|
|
|
+ >
|
|
|
+ 确认{{ addStatus ? "创建" : "修改" }}
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <el-form
|
|
|
+ v-if="sealFrom.createType != 2"
|
|
|
+ :model="form"
|
|
|
+ ref="signatureFormRef"
|
|
|
+ >
|
|
|
+ <el-form-item
|
|
|
+ label="印章名称:"
|
|
|
+ prop="signatureName"
|
|
|
+ :rules="[{ required: true, message: '请输入印章名称' }]"
|
|
|
+ style="width: 400px"
|
|
|
+ >
|
|
|
+ <el-input v-model="form.signatureName" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item
|
|
|
+ label="签章归属:"
|
|
|
+ prop="signatureAttribution"
|
|
|
+ :rules="[{ required: false, message: '请输入印章名称' }]"
|
|
|
+ style="width: 400px"
|
|
|
+ >
|
|
|
+ <el-select v-model="form.signatureAttribution">
|
|
|
+ <el-option
|
|
|
+ v-for="item in dicts.signature_attribution"
|
|
|
+ :key="item"
|
|
|
+ :label="item.dictLabel"
|
|
|
+ :value="item.dictValue"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ v-if="activeName == '2' && myselfUpload == true"
|
|
|
+ label="工序名称:"
|
|
|
+ :rules="[{ required: true, message: '请输入' }]"
|
|
|
+ style="width: 400px"
|
|
|
+ >
|
|
|
+ <el-input v-model="form.opName" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ v-if="activeName == '3' && myselfUpload == true"
|
|
|
+ label="检验编号:"
|
|
|
+ :rules="[{ required: true, message: '请输入' }]"
|
|
|
+ style="width: 400px"
|
|
|
+ >
|
|
|
+ <el-input v-model="form.jyName" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ v-if="
|
|
|
+ sealFrom.createType == 1 && activeName == '4' && myselfUpload == true
|
|
|
+ "
|
|
|
+ label="环绕字段:"
|
|
|
+ prop="topText"
|
|
|
+ :rules="[{ required: true, message: '请输入' }]"
|
|
|
+ style="width: 400px"
|
|
|
+ >
|
|
|
+ <el-input v-model="form.topText" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ v-if="
|
|
|
+ sealFrom.createType == 1 && activeName == '4' && myselfUpload == true
|
|
|
+ "
|
|
|
+ label="横排字段:"
|
|
|
+ :rules="[{ required: false, message: '请输入' }]"
|
|
|
+ style="width: 400px"
|
|
|
+ >
|
|
|
+ <el-input v-model="form.middleText" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="启用状态:">
|
|
|
+ <el-switch
|
|
|
+ v-model="form.signatureState"
|
|
|
+ active-text="启用"
|
|
|
+ active-value="1"
|
|
|
+ inactive-text="禁用"
|
|
|
+ inactive-value="0"
|
|
|
+ style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <div style="display: flex">
|
|
|
+ <div v-if="editStatus == true" style="margin-right: 20px">
|
|
|
+ <div>原签章内容</div>
|
|
|
+ <img
|
|
|
+ style="width: 150px; height: 150px"
|
|
|
+ :src="imageUrl"
|
|
|
+ v-if="oldUrl"
|
|
|
+ />
|
|
|
+ <span v-else>无内容(请上传后查看效果)</span>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ v-if="
|
|
|
+ myselfUpload != true && (addStatus ? true : editFirst ? false : true)
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <div>现签章内容</div>
|
|
|
+ <img
|
|
|
+ style="width: 150px; height: 150px"
|
|
|
+ :src="newImageUrl"
|
|
|
+ v-if="form.signatureFiles"
|
|
|
+ />
|
|
|
+ <span v-else>无内容(请上传后查看效果)</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 签章区域 -->
|
|
|
+ <div v-if="activeName != null">
|
|
|
+ <el-tabs v-model="activeName" class="demo-tabs" type="card">
|
|
|
+ <el-tab-pane
|
|
|
+ :label="item.dictLabel"
|
|
|
+ :name="item.dictValue"
|
|
|
+ v-for="(item, index) in dicts.signature_type"
|
|
|
+ :key="item"
|
|
|
+ />
|
|
|
+ </el-tabs>
|
|
|
+ <el-switch
|
|
|
+ v-model="myselfUpload"
|
|
|
+ active-text="借用模版"
|
|
|
+ inactive-text="自定义上传"
|
|
|
+ @click="changeMyselfUpload"
|
|
|
+ />
|
|
|
+ <div v-if="myselfUpload">
|
|
|
+ <!-- 人员签章 -->
|
|
|
+ <div
|
|
|
+ v-show="activeName == '1'"
|
|
|
+ style="display: flex; flex-direction: column; align-items: center"
|
|
|
+ >
|
|
|
+ <div class="body">
|
|
|
+ <div>
|
|
|
+ <div>
|
|
|
+ <div
|
|
|
+ class="signature-box"
|
|
|
+ :class="!startSignature ? 'signature-bg' : ''"
|
|
|
+ >
|
|
|
+ <VueSignaturePad
|
|
|
+ ref="signaturePad"
|
|
|
+ :key="startSignature"
|
|
|
+ :images="[
|
|
|
+ { src: 'A.png', x: 0, y: 0 },
|
|
|
+ { src: 'B.png', x: 0, y: 10 },
|
|
|
+ { src: 'C.png', x: 0, y: 20 },
|
|
|
+ ]"
|
|
|
+ :options="options"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="operaBox">
|
|
|
+ <el-button type="primary" @click="undoSignature"
|
|
|
+ >撤销</el-button
|
|
|
+ >
|
|
|
+ <el-button @click="clearSignature">重写</el-button>
|
|
|
+ <el-button type="success" @click="showSignature"
|
|
|
+ >预览</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div class="showBox">
|
|
|
+ <img
|
|
|
+ ref="imgRef"
|
|
|
+ :src="'data:image/png;base64,' + handwritingEl"
|
|
|
+ v-if="handwritingEl"
|
|
|
+ />
|
|
|
+ <span v-else
|
|
|
+ >请先设置手写签名
|
|
|
+ <br />
|
|
|
+ 建议签名铺满书写框
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="operaBox" v-if="handwritingEl">
|
|
|
+ <el-button type="primary" @click="updownPng">下载</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 工序签章 -->
|
|
|
+ <div
|
|
|
+ v-if="activeName == '2'"
|
|
|
+ style="display: flex; flex-direction: column; align-items: center"
|
|
|
+ >
|
|
|
+ <div class="showGJBox">
|
|
|
+ <div v-if="form.opName" ref="GJRef" class="GJBox">
|
|
|
+ {{ form.opName }}
|
|
|
+ </div>
|
|
|
+ <span v-else>请先设置工序名称</span>
|
|
|
+ </div>
|
|
|
+ <div class="operaBox" v-if="form.name">
|
|
|
+ <el-button type="primary" @click="updownGJPng">下载</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 检验签章 -->
|
|
|
+ <div
|
|
|
+ v-if="activeName == '3'"
|
|
|
+ style="display: flex; flex-direction: column; align-items: center"
|
|
|
+ >
|
|
|
+ <div class="showGJBox">
|
|
|
+ <div v-if="form.jyName" ref="JYRef" class="JYBox">
|
|
|
+ 检<span style="margin-left: 20px">{{ form.jyName }}</span>
|
|
|
+ </div>
|
|
|
+ <span v-else>请先设置检验编号</span>
|
|
|
+ </div>
|
|
|
+ <div class="operaBox" v-if="form.name">
|
|
|
+ <el-button type="primary" @click="updownJYPng">下载</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 公章签章 -->
|
|
|
+ <div
|
|
|
+ v-if="activeName == '4'"
|
|
|
+ style="display: flex; flex-direction: column; align-items: center"
|
|
|
+ >
|
|
|
+ <el-radio-group
|
|
|
+ v-model="sealFrom.createType"
|
|
|
+ size="large"
|
|
|
+ @change="createTypeChange"
|
|
|
+ style="margin-bottom: 20px"
|
|
|
+ >
|
|
|
+ <el-radio-button :value="1">模板创建制作</el-radio-button>
|
|
|
+ <el-radio-button :value="2">印模生成工具</el-radio-button>
|
|
|
+ </el-radio-group>
|
|
|
+
|
|
|
+ <div
|
|
|
+ style="display: flex; flex-direction: column; align-items: center"
|
|
|
+ >
|
|
|
+ <div class="seal-make-layout">
|
|
|
+ <div class="template-make" v-if="sealFrom.createType == 1">
|
|
|
+ <el-button
|
|
|
+ type="success"
|
|
|
+ v-loading="uploading"
|
|
|
+ @click="showGZSignature"
|
|
|
+ >预览</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ <div class="seal-upload" v-if="sealFrom.createType == 2">
|
|
|
+ <div v-if="fileList.length == 0" class="upload-before">
|
|
|
+ <el-upload
|
|
|
+ v-model:file-list="fileList"
|
|
|
+ :show-file-list="false"
|
|
|
+ :limit="1"
|
|
|
+ @change="handleChange"
|
|
|
+ :auto-upload="false"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="local-upload pointer"
|
|
|
+ v-if="fileList.length < 1"
|
|
|
+ >
|
|
|
+ <div style="width: 100%">点击上传</div>
|
|
|
+ </div>
|
|
|
+ </el-upload>
|
|
|
+ <div class="prompt">
|
|
|
+ <p style="font-weight: 600">注意:</p>
|
|
|
+ <p>
|
|
|
+ 此模块仅作为工具实现目标效果(旋转、虚化后可导出),如需创建请在模版创建制作。
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="upload-img" v-else>
|
|
|
+ <img
|
|
|
+ :src="uploadSeal"
|
|
|
+ ref="sealRef"
|
|
|
+ @load="imgeLoad"
|
|
|
+ style="height: 100%; display: none"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="SealActions" v-if="fileList.length > 0">
|
|
|
+ <el-row style="margin-top: 10px">
|
|
|
+ <el-col :span="4" class="center">
|
|
|
+ <el-icon size="20"
|
|
|
+ ><RefreshLeft @click="sealActions(-1)"
|
|
|
+ /></el-icon>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="4" class="center">
|
|
|
+ <el-icon size="20"
|
|
|
+ ><RefreshRight @click="sealActions(1)"
|
|
|
+ /></el-icon>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="4" class="center">
|
|
|
+ <el-icon size="20"
|
|
|
+ ><Minus @click="sealActions(-2)"
|
|
|
+ /></el-icon>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="4" class="center">
|
|
|
+ <el-icon size="20"
|
|
|
+ ><Plus @click="sealActions(2)"
|
|
|
+ /></el-icon>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-upload
|
|
|
+ v-model:file-list="fileList"
|
|
|
+ :show-file-list="false"
|
|
|
+ @change="handleChange2"
|
|
|
+ >
|
|
|
+ <el-button type="link">重新上传</el-button>
|
|
|
+ </el-upload>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row style="display: flex; align-items: center">
|
|
|
+ <el-col :span="8">
|
|
|
+ <h4 style="line-height: 32px">旋转角度:</h4>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="16">
|
|
|
+ <el-slider
|
|
|
+ @input="sealRotateChange"
|
|
|
+ v-model="sealOptions.sealRotate"
|
|
|
+ :min="-180"
|
|
|
+ :max="180"
|
|
|
+ />
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row style="display: flex; align-items: center">
|
|
|
+ <el-col :span="8">
|
|
|
+ <h4 style="line-height: 32px">背景透明度:</h4>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="16">
|
|
|
+ <el-slider
|
|
|
+ @input="buildCropperImage"
|
|
|
+ v-model="sealOptions.sealBackground"
|
|
|
+ :min="0"
|
|
|
+ :max="100"
|
|
|
+ />
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="seal-preview">
|
|
|
+ <div class="title">签章预览</div>
|
|
|
+ <div class="seal-preview-img">
|
|
|
+ <img
|
|
|
+ ref="GZRef"
|
|
|
+ :src="'data:image/png;base64,' + sealFrom.sealPreview"
|
|
|
+ style="width: 100%; height: 100%"
|
|
|
+ alt="暂未生成签章"
|
|
|
+ v-if="sealFrom.sealPreview"
|
|
|
+ />
|
|
|
+ <span style="color: #aaa" v-else>暂未生成签章</span>
|
|
|
+ </div>
|
|
|
+ <div class="operaBox" v-if="sealFrom.sealPreview">
|
|
|
+ <el-button type="primary" @click="updownGZPng"
|
|
|
+ >下载</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-else>
|
|
|
+ <!-- //自定义上传 -->
|
|
|
+ <FilesUpload
|
|
|
+ v-model:src="fileUrl"
|
|
|
+ v-model:pdf-list="pdfUrlList"
|
|
|
+ v-model:file-name-list="fileNameList"
|
|
|
+ :generate-pdf="true"
|
|
|
+ @finished="setFileUrl"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-else style="color: red">功能未开放,请联系管理员!</div>
|
|
|
+ </el-dialog>
|
|
|
+</template>
|
|
|
+<script setup>
|
|
|
+import { useDictionaryStore } from "@/store";
|
|
|
+import { VueSignaturePad } from "vue-signature-pad";
|
|
|
+import { useDebounceFn } from "@vueuse/core";
|
|
|
+import html2canvas from "html2canvas";
|
|
|
+import { uploadFileApi } from "@/api/file";
|
|
|
+import Cropper from "cropperjs";
|
|
|
+import "cropperjs/dist/cropper.css";
|
|
|
+import {
|
|
|
+ addSignature,
|
|
|
+ getGenerateSeal,
|
|
|
+ getClipSeal,
|
|
|
+ updateSignature,
|
|
|
+} from "@/api/signature";
|
|
|
+
|
|
|
+const { dicts } = useDictionaryStore();
|
|
|
+const Visible = ref(true);
|
|
|
+const addStatus = ref(false);
|
|
|
+const props = defineProps({
|
|
|
+ editStatus: Boolean,
|
|
|
+ formData: Object,
|
|
|
+ rowObj: Object,
|
|
|
+});
|
|
|
+const form = ref({
|
|
|
+ signatureName: "",
|
|
|
+ signatureFiles: "",
|
|
|
+ signatureAttribution: "",
|
|
|
+});
|
|
|
+const changeMyselfUpload = () => {
|
|
|
+ form.value.signatureFiles = null;
|
|
|
+};
|
|
|
+function base64ToBlob(base64, type = "image/png") {
|
|
|
+ const base64Data = base64.split(",")[1];
|
|
|
+ const byteCharacters = atob(base64Data);
|
|
|
+ const byteNumbers = new Array(byteCharacters.length);
|
|
|
+ for (let i = 0; i < byteCharacters.length; i++) {
|
|
|
+ byteNumbers[i] = byteCharacters.charCodeAt(i);
|
|
|
+ }
|
|
|
+ const byteArray = new Uint8Array(byteNumbers);
|
|
|
+ return new Blob([byteArray], { type: type });
|
|
|
+}
|
|
|
+
|
|
|
+const opSignatureLoading = ref(false);
|
|
|
+const uploading = ref(false);
|
|
|
+const submit = async () => {
|
|
|
+ opSignatureLoading.value = true;
|
|
|
+ try {
|
|
|
+ await signatureFormRef.value.validate(async (valid, fields) => {
|
|
|
+ if (valid) {
|
|
|
+ //入口逻辑判断是否为自定义上传
|
|
|
+ if (myselfUpload.value == false) {
|
|
|
+ //此处为自定义上传
|
|
|
+ if (form.value.signatureFiles) {
|
|
|
+ if (addStatus.value == true) {
|
|
|
+ add(form.value.signatureFiles);
|
|
|
+ } else {
|
|
|
+ edit(form.value.signatureFiles);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ElMessage.warning("请先上传印章!");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ let blob = null;
|
|
|
+ //此处为借用模版创建先生成文件,进行自动进行上传操作,后在提交文件地址完成创建
|
|
|
+ //根据类型选择图片数据进行处理上传
|
|
|
+ switch (activeName.value) {
|
|
|
+ case "1":
|
|
|
+ const { isEmpty, data } = signaturePad.value.saveSignature();
|
|
|
+ if (isEmpty) {
|
|
|
+ message.warning("签名为空,请书写后再进行添加");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const resultImg = data.split(",");
|
|
|
+ blob = base64ToBlob("data:image/png;base64," + resultImg[1]);
|
|
|
+ break;
|
|
|
+ case "2":
|
|
|
+ const chartContainer1 = GJRef.value;
|
|
|
+ const canvas1 = await html2canvas(chartContainer1);
|
|
|
+ const img1 = canvas1.toDataURL("image/png");
|
|
|
+ blob = base64ToBlob(img1);
|
|
|
+ break;
|
|
|
+ case "3":
|
|
|
+ const chartContainer2 = JYRef.value;
|
|
|
+ const canvas2 = await html2canvas(chartContainer2);
|
|
|
+ const img2 = canvas2.toDataURL("image/png");
|
|
|
+ blob = base64ToBlob(img2);
|
|
|
+ break;
|
|
|
+ case "4":
|
|
|
+ const response = await getGenerateSeal({
|
|
|
+ middleText: form.value.middleText,
|
|
|
+ topText: form.value.topText,
|
|
|
+ });
|
|
|
+ blob = base64ToBlob(
|
|
|
+ "data:image/png;base64," + response.data.result.entSeal
|
|
|
+ );
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ const file = new File([blob], "签章文件.png", {
|
|
|
+ type: "image/png",
|
|
|
+ });
|
|
|
+
|
|
|
+ //上传到文件服务器
|
|
|
+ uploadFileApi(file, true)
|
|
|
+ .then((res) => {
|
|
|
+ if (addStatus.value == true) {
|
|
|
+ add(res.data.fileUrl);
|
|
|
+ } else {
|
|
|
+ edit(res.data.fileUrl);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ ElMessage.error(err.message);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ElMessage.error("请检查表单选项");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (e) {
|
|
|
+ ElMessage.error(e);
|
|
|
+ } finally {
|
|
|
+ opSignatureLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+const add = async (url) => {
|
|
|
+ form.value.signatureFiles = url;
|
|
|
+ const { code } = await addSignature({
|
|
|
+ ...form.value,
|
|
|
+ signatureType: activeName.value,
|
|
|
+ });
|
|
|
+ if (code == "200") {
|
|
|
+ ElMessage.success("添加成功");
|
|
|
+ emit("close");
|
|
|
+ }
|
|
|
+};
|
|
|
+const edit = async (url) => {
|
|
|
+ form.value.signatureFiles = url;
|
|
|
+ const { code } = await updateSignature({
|
|
|
+ ...form.value,
|
|
|
+ signatureType: activeName.value,
|
|
|
+ });
|
|
|
+ if (code == "200") {
|
|
|
+ ElMessage.success("添加成功");
|
|
|
+ emit("close");
|
|
|
+ }
|
|
|
+};
|
|
|
+const update = async () => {};
|
|
|
+const oldUrl = ref("");
|
|
|
+const imageUrl = computed(() => {
|
|
|
+ let url = import.meta.env.VITE_APP_UPLOAD_URL + oldUrl.value;
|
|
|
+ return url;
|
|
|
+});
|
|
|
+const newImageUrl = computed(() => {
|
|
|
+ let url = import.meta.env.VITE_APP_UPLOAD_URL + form.value.signatureFiles;
|
|
|
+ return url;
|
|
|
+});
|
|
|
+const activeName = ref(null);
|
|
|
+const emit = defineEmits(["close"]);
|
|
|
+const editFirst = ref(true);
|
|
|
+const setActiveName = () => {
|
|
|
+ if (dicts.signature_type) {
|
|
|
+ activeName.value = dicts.signature_type[0].dictValue;
|
|
|
+ } else {
|
|
|
+ activeName.value = null;
|
|
|
+ }
|
|
|
+};
|
|
|
+const myselfUploadUseHook = () => {
|
|
|
+ //是否自己上传
|
|
|
+ const myselfUpload = ref(false);
|
|
|
+ const fileUrl = ref();
|
|
|
+ const pdfUrlList = ref([]);
|
|
|
+ const fileNameList = ref([]);
|
|
|
+ const setFileUrl = () => {
|
|
|
+ form.value.signatureFiles = fileUrl.value;
|
|
|
+ if (addStatus.value == false) {
|
|
|
+ editFirst.value = false;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return { myselfUpload, fileUrl, pdfUrlList, fileNameList, setFileUrl };
|
|
|
+};
|
|
|
+const { myselfUpload, fileUrl, pdfUrlList, fileNameList, setFileUrl } =
|
|
|
+ myselfUploadUseHook();
|
|
|
+
|
|
|
+const handwritingUseHook = () => {
|
|
|
+ const signaturePad = ref();
|
|
|
+ const signatureFormRef = ref();
|
|
|
+ const startSignature = ref(false);
|
|
|
+ //图片二进制编码
|
|
|
+ const handwritingEl = ref(null);
|
|
|
+ const imgRef = ref(null);
|
|
|
+ const options = ref({
|
|
|
+ penColor: "#000",
|
|
|
+ dotSize: (1 + 4) / 2,
|
|
|
+ minWidth: 1,
|
|
|
+ maxWidth: 4,
|
|
|
+ throttle: 16,
|
|
|
+ minDistance: 5,
|
|
|
+ backgroundColor: "rgba(0,0,0,0)",
|
|
|
+ velocityFilterWeight: 0.5,
|
|
|
+ onBegin: () => {
|
|
|
+ startSignature.value = true;
|
|
|
+ },
|
|
|
+ onEnd: () => {},
|
|
|
+ });
|
|
|
+ function undoSignature() {
|
|
|
+ signaturePad.value.undoSignature();
|
|
|
+ }
|
|
|
+ function clearSignature() {
|
|
|
+ signaturePad.value.clearSignature();
|
|
|
+ startSignature.value = false;
|
|
|
+ }
|
|
|
+ //下载png
|
|
|
+ const updownPng = async () => {
|
|
|
+ const chartContainer = imgRef.value;
|
|
|
+ const canvas = await html2canvas(chartContainer);
|
|
|
+ const img = canvas.toDataURL("image/png");
|
|
|
+ const a = document.createElement("a");
|
|
|
+ a.href = img;
|
|
|
+ a.download = "手写签名.png";
|
|
|
+ a.click();
|
|
|
+ };
|
|
|
+ //展示图片
|
|
|
+ function showSignature() {
|
|
|
+ //获取签名图片
|
|
|
+ const { isEmpty, data } = signaturePad.value.saveSignature();
|
|
|
+ if (isEmpty) {
|
|
|
+ ElMessage.warning("签名为空,请书写后再进行添加");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const resultImg = data.split(",");
|
|
|
+ //将签名图片返给main页面
|
|
|
+ handwritingEl.value = resultImg[1];
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ signaturePad,
|
|
|
+ signatureFormRef,
|
|
|
+ startSignature,
|
|
|
+ handwritingEl,
|
|
|
+ imgRef,
|
|
|
+ options,
|
|
|
+ undoSignature,
|
|
|
+ clearSignature,
|
|
|
+ updownPng,
|
|
|
+ showSignature,
|
|
|
+ };
|
|
|
+};
|
|
|
+const {
|
|
|
+ signaturePad,
|
|
|
+ signatureFormRef,
|
|
|
+ startSignature,
|
|
|
+ handwritingEl,
|
|
|
+ imgRef,
|
|
|
+ options,
|
|
|
+ undoSignature,
|
|
|
+ clearSignature,
|
|
|
+ updownPng,
|
|
|
+ showSignature,
|
|
|
+} = handwritingUseHook();
|
|
|
+
|
|
|
+//工序签章
|
|
|
+const GJUseHook = () => {
|
|
|
+ const GJRef = ref(null);
|
|
|
+ const updownGJPng = async () => {
|
|
|
+ const chartContainer = GJRef.value;
|
|
|
+ const canvas = await html2canvas(chartContainer);
|
|
|
+ const img = canvas.toDataURL("image/png");
|
|
|
+ const a = document.createElement("a");
|
|
|
+ a.href = img;
|
|
|
+ a.download = "手写签名.png";
|
|
|
+ a.click();
|
|
|
+ };
|
|
|
+ return { GJRef, updownGJPng };
|
|
|
+};
|
|
|
+const { GJRef, updownGJPng } = GJUseHook();
|
|
|
+//检验签章
|
|
|
+const JYUseHook = () => {
|
|
|
+ const JYRef = ref(null);
|
|
|
+ const updownJYPng = async () => {
|
|
|
+ const chartContainer = JYRef.value;
|
|
|
+ const canvas = await html2canvas(chartContainer);
|
|
|
+ const img = canvas.toDataURL("image/png");
|
|
|
+ const a = document.createElement("a");
|
|
|
+ a.href = img;
|
|
|
+ a.download = "手写签名.png";
|
|
|
+ a.click();
|
|
|
+ };
|
|
|
+ return { JYRef, updownJYPng };
|
|
|
+};
|
|
|
+const { JYRef, updownJYPng } = JYUseHook();
|
|
|
+//公章签章
|
|
|
+const GZUseHook = () => {
|
|
|
+ const GZRef = ref(null);
|
|
|
+ const fileList = ref([]);
|
|
|
+ const sealCropper = ref();
|
|
|
+ const uploadSeal = ref(null);
|
|
|
+ const sealRef = ref(null);
|
|
|
+ const firstUpload = ref(true);
|
|
|
+ const sealOptions = ref({
|
|
|
+ sealRotate: 0,
|
|
|
+ sealBackground: 50,
|
|
|
+ imageWidth: 400,
|
|
|
+ imageHeight: 400,
|
|
|
+ });
|
|
|
+ function getBase64(file) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const reader = new FileReader();
|
|
|
+ reader.readAsDataURL(file);
|
|
|
+ reader.onload = () => resolve(reader.result);
|
|
|
+ reader.onerror = (error) => reject(error);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ const sealFrom = ref({
|
|
|
+ createType: 1,
|
|
|
+ sealStyle: 1,
|
|
|
+ entpName: "",
|
|
|
+ middleText: "测试印章",
|
|
|
+ sealPreview: false,
|
|
|
+ });
|
|
|
+ function createTypeChange(value) {
|
|
|
+ sealFrom.value.sealPreview = false;
|
|
|
+ }
|
|
|
+ function handleChange(info) {
|
|
|
+ getBase64(info.raw).then((res) => {
|
|
|
+ uploadSeal.value = res;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ const showGZSignature = async () => {
|
|
|
+ uploading.value = true;
|
|
|
+ try {
|
|
|
+ const response = await getGenerateSeal({
|
|
|
+ middleText: form.value.middleText,
|
|
|
+ topText: form.value.topText,
|
|
|
+ });
|
|
|
+ sealFrom.value.sealPreview = response.data.result.entSeal;
|
|
|
+ } finally {
|
|
|
+ uploading.value = false;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ const updownGZPng = async () => {
|
|
|
+ const chartContainer = GZRef.value;
|
|
|
+ const canvas = await html2canvas(chartContainer);
|
|
|
+ const img = canvas.toDataURL("image/png");
|
|
|
+ const a = document.createElement("a");
|
|
|
+ a.href = img;
|
|
|
+ a.download = "签章.png";
|
|
|
+ a.click();
|
|
|
+ };
|
|
|
+ //重新上传印模图片
|
|
|
+ async function handleChange2(info) {
|
|
|
+ firstUpload.value = false;
|
|
|
+ await handleChange(info);
|
|
|
+ }
|
|
|
+
|
|
|
+ //印章图片旋转
|
|
|
+ const sealActions = useDebounceFn((type) => {
|
|
|
+ switch (type) {
|
|
|
+ case -1:
|
|
|
+ sealCropper.value.rotate(-90);
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ sealCropper.value.rotate(90);
|
|
|
+ break;
|
|
|
+ case -2:
|
|
|
+ sealCropper.value.zoom(-0.1);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ sealCropper.value.zoom(0.1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ setTimeout(function () {
|
|
|
+ buildCropperImage();
|
|
|
+ }, 100);
|
|
|
+ }, 500);
|
|
|
+
|
|
|
+ function sealRotateChange(to) {
|
|
|
+ sealCropper.value.rotateTo(to);
|
|
|
+ setTimeout(function () {
|
|
|
+ buildCropperImage();
|
|
|
+ }, 100);
|
|
|
+ }
|
|
|
+ //将上传的图片加载到 图片处理工具中
|
|
|
+ function sealPreviewCropper() {
|
|
|
+ sealCropper.value = new Cropper(sealRef.value, {
|
|
|
+ viewMode: 1,
|
|
|
+ dragMode: "move",
|
|
|
+ preview: ".before",
|
|
|
+ initialAspectRatio: 1,
|
|
|
+ aspectRatio: 1,
|
|
|
+ background: true,
|
|
|
+ autoCrop: true,
|
|
|
+ autoCropArea: 0.7,
|
|
|
+ zoomOnWheel: true,
|
|
|
+ zoomOnTouch: true,
|
|
|
+ cropBoxResizable: false,
|
|
|
+ cropBoxMovable: false,
|
|
|
+ wheelZoomRatio: 0.05,
|
|
|
+ cropend: sealCropend,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ //图片处理完成后调用后端服务进行处理
|
|
|
+ function sealCropend(end) {
|
|
|
+ buildCropperImage();
|
|
|
+ }
|
|
|
+
|
|
|
+ //印模图片加载完成事件
|
|
|
+ function imgeLoad(img) {
|
|
|
+ if (!firstUpload.value) {
|
|
|
+ sealCropper.value.destroy();
|
|
|
+ }
|
|
|
+ sealPreviewCropper();
|
|
|
+ }
|
|
|
+
|
|
|
+ const buildCropperImage = useDebounceFn(async () => {
|
|
|
+ if (!sealCropper.value) {
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ }
|
|
|
+
|
|
|
+ // sealCropper.value.rotateTo(sealOptions.value.sealRotate);
|
|
|
+ const seal = sealCropper.value
|
|
|
+ .getCroppedCanvas({
|
|
|
+ width: sealOptions.value.imageWidth,
|
|
|
+ height: sealOptions.value.imageHeight,
|
|
|
+ imageSmoothingQuality: "high",
|
|
|
+ })
|
|
|
+ .toDataURL("image/jpeg");
|
|
|
+
|
|
|
+ const data = {
|
|
|
+ image: seal.split(",")[1],
|
|
|
+ colorRange: sealOptions.value.sealBackground + 120,
|
|
|
+ };
|
|
|
+ const response = await getClipSeal(data);
|
|
|
+ sealFrom.value.sealPreview = response.data.result.entSeal;
|
|
|
+ });
|
|
|
+ return {
|
|
|
+ GZRef,
|
|
|
+ fileList,
|
|
|
+ sealFrom,
|
|
|
+ sealOptions,
|
|
|
+ sealRef,
|
|
|
+ uploadSeal,
|
|
|
+ handleChange,
|
|
|
+ createTypeChange,
|
|
|
+ updownGZPng,
|
|
|
+ showGZSignature,
|
|
|
+ imgeLoad,
|
|
|
+ handleChange2,
|
|
|
+ sealActions,
|
|
|
+ sealRotateChange,
|
|
|
+ buildCropperImage,
|
|
|
+ };
|
|
|
+};
|
|
|
+const {
|
|
|
+ GZRef,
|
|
|
+ fileList,
|
|
|
+ sealFrom,
|
|
|
+ sealOptions,
|
|
|
+ sealRef,
|
|
|
+ uploadSeal,
|
|
|
+ handleChange,
|
|
|
+ createTypeChange,
|
|
|
+ updownGZPng,
|
|
|
+ showGZSignature,
|
|
|
+ imgeLoad,
|
|
|
+ handleChange2,
|
|
|
+ sealActions,
|
|
|
+ sealRotateChange,
|
|
|
+ buildCropperImage,
|
|
|
+} = GZUseHook();
|
|
|
+onMounted(() => {
|
|
|
+ if (props.editStatus == true) {
|
|
|
+ addStatus.value = false;
|
|
|
+ form.value.signatureName = props.rowObj.signatureName;
|
|
|
+ form.value.signatureState = props.rowObj.signatureState;
|
|
|
+ form.value.signatureType = props.rowObj.signatureType;
|
|
|
+ form.value.signatureAttribution = props.rowObj.signatureAttribution;
|
|
|
+ form.value.signatureFiles = props.rowObj.signatureFiles;
|
|
|
+ form.value.id = props.rowObj.id;
|
|
|
+ oldUrl.value = props.rowObj.signatureFiles;
|
|
|
+ } else {
|
|
|
+ addStatus.value = true;
|
|
|
+ }
|
|
|
+ setActiveName();
|
|
|
+});
|
|
|
+watch(
|
|
|
+ () => Visible.value,
|
|
|
+ (val) => {
|
|
|
+ if (val == false) {
|
|
|
+ emit("close");
|
|
|
+ }
|
|
|
+ }
|
|
|
+);
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.local-upload {
|
|
|
+ width: 160px;
|
|
|
+ height: 160px;
|
|
|
+ padding: 10px;
|
|
|
+ border: 1px dashed rgba(0, 0, 0, 0.3);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-items: center;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.upload-img {
|
|
|
+ width: 200px;
|
|
|
+ height: 200px;
|
|
|
+}
|
|
|
+.upload-before {
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+.upload-before .prompt {
|
|
|
+ flex: 1;
|
|
|
+ height: 100%;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 0 10px 0 20px;
|
|
|
+}
|
|
|
+.signature-box {
|
|
|
+ width: 360px;
|
|
|
+ height: 240px;
|
|
|
+ border: 1px solid #dedede;
|
|
|
+ margin: 0 auto;
|
|
|
+}
|
|
|
+.signature-bg {
|
|
|
+ background: url("@/assets/images/signature-bg.png") no-repeat;
|
|
|
+ background-size: 90% 90%;
|
|
|
+ background-position: 50% 50%;
|
|
|
+}
|
|
|
+.operaBox {
|
|
|
+ text-align: center;
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+.showGJBox {
|
|
|
+ border: 1px solid #dedede;
|
|
|
+ width: 240px;
|
|
|
+ height: 60px;
|
|
|
+ margin: 0 auto;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ display: flex;
|
|
|
+ .GJBox {
|
|
|
+ font-size: 20px;
|
|
|
+ color: red;
|
|
|
+ display: inline;
|
|
|
+ border: 2px solid red;
|
|
|
+ }
|
|
|
+ .JYBox {
|
|
|
+ font-size: 20px;
|
|
|
+ color: red;
|
|
|
+ display: inline;
|
|
|
+ border: 2px solid red;
|
|
|
+ }
|
|
|
+}
|
|
|
+.body {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-evenly;
|
|
|
+ .showBox {
|
|
|
+ width: 360px;
|
|
|
+ height: 240px;
|
|
|
+ border: 1px solid #dedede;
|
|
|
+ margin: 0 auto;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+}
|
|
|
+.seal-make-layout {
|
|
|
+ display: flex;
|
|
|
+
|
|
|
+ .template-make {
|
|
|
+ }
|
|
|
+ .seal-preview {
|
|
|
+ padding-left: 40px;
|
|
|
+ .title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ height: 30px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .seal-upload {
|
|
|
+ padding: 20px 0;
|
|
|
+ width: 442px;
|
|
|
+ }
|
|
|
+ .seal-preview-img {
|
|
|
+ width: 200px;
|
|
|
+ height: 200px;
|
|
|
+ padding: 10px;
|
|
|
+ border: 1px solid #ededed;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|