culture/src/components/SignatureCanvas.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
culture/src/components/service.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
culture/src/views/strain-library/strain-library-manage/add.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
culture/src/views/strain-library/strain-library-manage/components/AddRecordDialog.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
culture/src/views/strain-library/strain-library-manage/components/StrainDetail.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
culture/src/views/strain-library/validation/chief-cell/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
culture/src/views/strain-library/validation/chief-cell/primitive-cell-detail-dialog.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
culture/src/components/SignatureCanvas.vue
@@ -1,27 +1,11 @@ <template> <el-dialog title="确认签字" :visible.sync="visible" :width="dialogWidth" :close-on-click-modal="false" custom-class="signature-dialog" append-to-body @close="$emit('update:visible', false)" > <el-dialog title="确认签字" :visible.sync="visible" :width="dialogWidth" :close-on-click-modal="false" custom-class="signature-dialog" append-to-body @close="$emit('update:visible', false)"> <div class="signature-container"> <div class="signature-content"> <canvas ref="signatureCanvas" :width="canvasWidth" :height="canvasHeight" @mousedown="startDrawing" @mousemove="draw" @mouseup="stopDrawing" @mouseleave="stopDrawing" @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="stopDrawing" ></canvas> <canvas ref="signatureCanvas" :width="canvasWidth" :height="canvasHeight" @mousedown="startDrawing" @mousemove="draw" @mouseup="stopDrawing" @mouseleave="stopDrawing" @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="stopDrawing"></canvas> </div> <div class="signature-footer"> <el-button type="default" @click="clearCanvas">重置</el-button> @@ -32,6 +16,8 @@ </template> <script> import { customUploadRequest, getFullUrl } from '@/utils/utils' import {editSignPicture} from './service' export default { name: 'SignatureCanvas', props: { @@ -91,11 +77,11 @@ this.context.lineWidth = 2 this.context.lineCap = 'round' this.context.lineJoin = 'round' // 清空画布并绘制虚线边框 this.clearCanvas() }, drawDashedBorder() { const ctx = this.context ctx.setLineDash([5, 5]) @@ -114,16 +100,16 @@ draw(event) { if (!this.isDrawing) return const rect = this.$refs.signatureCanvas.getBoundingClientRect() const x = event.clientX - rect.left const y = event.clientY - rect.top this.context.beginPath() this.context.moveTo(this.lastX, this.lastY) this.context.lineTo(x, y) this.context.stroke() this.lastX = x this.lastY = y this.hasDrawn = true @@ -141,17 +127,17 @@ handleTouchMove(event) { event.preventDefault() if (!this.isDrawing) return const touch = event.touches[0] const rect = this.$refs.signatureCanvas.getBoundingClientRect() const x = touch.clientX - rect.left const y = touch.clientY - rect.top this.context.beginPath() this.context.moveTo(this.lastX, this.lastY) this.context.lineTo(x, y) this.context.stroke() this.lastX = x this.lastY = y this.hasDrawn = true @@ -170,7 +156,7 @@ confirmSignature() { const canvas = this.$refs.signatureCanvas const ctx = this.context // 校验是否签名 if (this.isCanvasBlank()) { this.$message && this.$message.warning('请先确认签名') @@ -178,24 +164,58 @@ } // 保存当前画布内容 const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height) // 先填充背景色 ctx.fillStyle = 'rgba(239, 248, 250, 1)' ctx.fillRect(0, 0, canvas.width, canvas.height) // 创建一个临时画布来保存签名内容 const tempCanvas = document.createElement('canvas') tempCanvas.width = canvas.width tempCanvas.height = canvas.height const tempCtx = tempCanvas.getContext('2d') tempCtx.putImageData(imageData, 0, 0) // 将签名内容绘制到主画布上 ctx.drawImage(tempCanvas, 0, 0) // 导出图片 const signatureImage = canvas.toDataURL('image/png') this.$emit('confirm', 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg') // 导出图片为base64 const base64Data = canvas.toDataURL('image/png'); // base64转blob const blob = this.dataURLtoBlob(base64Data); // 新增:生成带时间戳的文件名 const timestamp = Date.now(); const fileName = `signature_${timestamp}.png`; const file = new File([blob], fileName, { type: blob.type }); // 上传 customUploadRequest({ file, onSuccess: (res) => { // 假设返回的图片路径为 res.url const url = res.msg || res.data || res editSignPicture({ signPicture: res.msg }).then(res => { if (res.code == 200) { this.$message.success('签名成功'); this.$emit('confirm', url); } }) }, onError: (err) => { this.$message && this.$message.error ? this.$message.error('上传签名失败') : alert('上传签名失败'); } }); }, // 新增:base64转blob dataURLtoBlob(dataurl) { const arr = dataurl.split(','); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); }, // 新增方法:判断画布是否为空白 @@ -215,6 +235,7 @@ :deep(.el-dialog__body) { padding: 0; } :deep(.el-dialog) { margin-top: 10vh !important; } @@ -223,12 +244,12 @@ .signature-container { background: #fff; border-radius: 4px; .signature-content { padding: 20px; display: flex; justify-content: center; canvas { border-radius: 4px; background: rgba(239, 248, 250, 1); @@ -236,16 +257,17 @@ height: 100%; } } .signature-footer { padding: 20px; border-top: 1px solid #dcdfe6; display: flex; justify-content: flex-end; gap: 12px; button{ button { width: 150px; } } } </style> </style> culture/src/components/service.js
New file @@ -0,0 +1,10 @@ import axios from '@/utils/request'; // 列表 export const editSignPicture = (data) => { console.log(data) return axios.post('/api/system/user/editSignPicture', { ...data }) } export const queryDetail = (data) => { return axios.get('/system/user/queryDetail',) } culture/src/views/strain-library/strain-library-manage/add.vue
@@ -80,6 +80,7 @@ import SignatureCanvas from '@/components/SignatureCanvas.vue' import { add, edit, getDetail, addBatch } from './service' export default { name: 'StrainLibraryManageAdd', components: { culture/src/views/strain-library/strain-library-manage/components/AddRecordDialog.vue
@@ -29,7 +29,7 @@ </template> <div class="signature-area" :class="{ 'waiting': !formData.handleSignature }"> <template v-if="formData.handleSignature"> <img :src="formData.handleSignature" alt="操作人签字" /> <el-image :src="getFullUrl(formData.handleSignature)" :preview-src-list="[getFullUrl(formData.handleSignature)]" alt="操作人签字" /> </template> <template v-else> <span class="waiting-text">等待确认</span> @@ -48,6 +48,7 @@ <script> import SignatureCanvas from '@/components/SignatureCanvas.vue' import { getFullUrl } from "@/utils/utils"; export default { name: 'AddRecordDialog', components: { SignatureCanvas }, @@ -67,6 +68,11 @@ } }, methods: { getFullUrl(url){ if(url){ return getFullUrl(url); } }, handleClose() { this.$emit('update:visible', false) this.$emit('close') culture/src/views/strain-library/strain-library-manage/components/StrainDetail.vue
@@ -1,14 +1,7 @@ <template> <div> <el-dialog :title="`${title}详情`" :visible.sync="visible" width="70%" :close-on-click-modal="false" custom-class="strain-detail-dialog" @close="$emit('update:visible', false)" @opened="fetchDetail" > <el-dialog :title="`${title}详情`" :visible.sync="visible" width="70%" :close-on-click-modal="false" custom-class="strain-detail-dialog" @close="$emit('update:visible', false)" @opened="fetchDetail"> <div class="strain-info"> <!-- 第一行信息 --> <div class="info-row"> @@ -63,7 +56,7 @@ </div> <div class="record-table"> <div class="table-title">{{title}}出/入库记录</div> <div class="table-title">{{ title }}出/入库记录</div> <el-table :data="detail.records" style="width: 100%"> <el-table-column label="出库/入库"> <template #default="{ row }"> @@ -71,14 +64,16 @@ </template> </el-table-column> <el-table-column prop="boundTime" label="操作时间" /> <el-table-column prop="handleName" label="操作人签字" > <template #default="{row}"> <img :src="row.handleSignature" v-if="row.handleSignature" alt="签字图片" style="max-width: 100px; max-height: 50px;"> <el-table-column prop="handleName" label="操作人签字"> <template #default="{ row }"> <el-image :src="getFullUrl(row.handleSignature)" :preview-src-list="[getFullUrl(row.handleSignature)]" v-if="row.handleSignature" alt="签字图片" style="max-width: 100px; max-height: 50px;" /> </template> </el-table-column> <el-table-column prop="preserveSignature" label="菌种保藏人签字" > <template #default="{row}"> <img :src="row.preserveSignature" v-if="row.preserveSignature" alt="签字图片" style="max-width: 100px; max-height: 50px;"> <el-table-column prop="preserveSignature" label="菌种保藏人签字"> <template #default="{ row }"> <el-image :src="getFullUrl(row.preserveSignature)" :preview-src-list="[getFullUrl(row.preserveSignature)]" v-if="row.preserveSignature" alt="签字图片" style="max-width: 100px; max-height: 50px;" /> </template> </el-table-column> <el-table-column label="状态"> @@ -90,39 +85,27 @@ </el-table-column> <el-table-column label="操作" width="100"> <template #default="{ row }"> <el-button v-if="!row.confirmTime && roleType == 3" style="margin-right: 10px" type="text" @click="handleConfirm(row)">确认</el-button> <el-button type="text" @click="handleView(row)" >详情</el-button > <el-button v-if="!row.confirmTime && roleType == 3" style="margin-right: 10px" type="text" @click="handleConfirm(row)">确认</el-button> <el-button type="text" @click="handleView(row)">详情</el-button> </template> </el-table-column> </el-table> <div class="pagination"> <el-pagination :current-page.sync="currentPage" :page-size="10" layout="total, prev, pager, next" :total="total" @current-change="handlePageChange" /> <el-pagination :current-page.sync="currentPage" :page-size="10" layout="total, prev, pager, next" :total="total" @current-change="handlePageChange" /> </div> </div> </el-dialog> <RecordDetailDialog :visible="visibleRecordDetailDialog" :recordData="recordData" @close="handleDialogClose" @confirm="handleOutbound" :type="dialogType" /> <RecordDetailDialog :visible="visibleRecordDetailDialog" :recordData="recordData" @close="handleDialogClose" @confirm="handleOutbound" :type="dialogType" /> </div> </template> <script> import { getDetailById,confirmWarehousing } from "../service"; import { getDetailById, confirmWarehousing } from "../service"; import { getFullUrl } from "@/utils/utils"; import RecordDetailDialog from "./RecordDetailDialog.vue"; export default { components: { RecordDetailDialog }, @@ -160,16 +143,22 @@ }, methods: { getFullUrl(url){ if (url) { return getFullUrl(url); } }, handleDialogClose() { this.recordData = {}; this.visibleRecordDetailDialog = false; }, fetchDetail() { this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType; this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType; this.query.id = this.detail.id; getDetailById(this.query).then((res) => { console.log('qweqweqwe',res); console.log('qweqweqwe', res); this.detail.records = res.warehousingList?.records || []; this.total = res.warehousingList?.total || 0; this.currentPage = res.warehousingList?.current || 1; @@ -177,7 +166,7 @@ }); }, handleView(row) { this.dialogType = "detail"; this.dialogType = "detail"; this.recordData = row; this.visibleRecordDetailDialog = true; culture/src/views/strain-library/validation/chief-cell/index.vue
@@ -83,7 +83,7 @@ import PrimitiveCellDetailDialog from "./primitive-cell-detail-dialog.vue"; import DetailConditionDialog from "./DetailConditionDialog.vue"; import EditConditionDialog from "./EditConditionDialog.vue"; import moment from "moment"; import { getList, delOne } from "./service"; export default { name: "PrimitiveCell", @@ -123,6 +123,7 @@ }, methods: { handleDetail(row) { row.experimentTime = moment(row.experimentTime).format('YYYY-MM-DD') this.currentDetail = row; this.detailVisible = true; }, culture/src/views/strain-library/validation/chief-cell/primitive-cell-detail-dialog.vue
@@ -57,6 +57,7 @@ </template> <script> export default { name: 'PrimitiveCellDetailDialog', props: {