vue canvas 绘制选定区域 矩形框

news2024/12/15 10:48:57

 客户那边文档相当的多,目前需要协助其将文档转为数据写入数据库,并与其他系统进行数据共享及建设,所以不得不搞一个识别的功能,用户上传PDF文档后,对于关键信息点进行识别入库!

以下为核心代码,直接分享,到中午吃饭时间了,就大概分享一下。

<canvas id="imgCanvas" style="border:1px solid rgb(230,230,230)"></canvas>
initCanvas() {
    let rectArr = []
    let currAreas = []
    let canvasEle = document.getElementById('imgCanvas')
    let elRef = this.$refs.canvaxbox
    // canvasEle.width = elRef.clientWidth
    canvasEle.height = elRef.clientHeight
    canvasEle.width = (210 / 297) * elRef.clientHeight

    let ctx = canvasEle.getContext('2d')
    // 给矩形的设置颜色
    ctx.strokeStyle = '#448ef7'
    this.saveCtx = ctx

    let drawRect = (x1, y1, x2, y2) => {
        let rectWidth = Math.abs(x2 - x1)
        let rectHeight = Math.abs(y2 - y1)
        let endX = Math.min(x1, x2)
        let endY = Math.min(y1, y2)
        // 绘制之前先清空之前实时移动产生的多余的矩形路径
        ctx.clearRect(0, 0, canvasEle.width, canvasEle.height)
        ctx.strokeStyle = '#448ef7'
        // 绘制之前那些存储在 this.drawedAreas 数组中的矩形
        if (this.img) {
            ctx.drawImage(this.img, 0, 0, canvasEle.width, canvasEle.height)
        }

        currAreas = [endX, endY, rectWidth, rectHeight]
        this.drawedAreas.forEach(element => {
            ctx.beginPath();
            ctx.strokeRect(...element)
            ctx.stroke();
        });
        // 开始本次路径
        ctx.beginPath();
        // 绘制本次的矩形路径
        ctx.rect(...currAreas);
        // 开始填充矩形
        ctx.stroke();
    }

    let canvasMoveHandler = (e) => {
        drawRect(rectArr[0], rectArr[1], e.offsetX, e.offsetY)
    }

    let canvasMouseUpHandler = () => {
        this.drawedAreas.push(currAreas)
        canvasEle.removeEventListener('mousemove', canvasMoveHandler)
        canvasEle.removeEventListener('mouseup', canvasMouseUpHandler)
    }
    // 给canvas注册事件按下事件
    let canvasDownHandler = (e) => {
        if (this.toolsIndex == 1) {
            rectArr = [e.offsetX, e.offsetY]
            // 按下的时候需要注册移动事件
            canvasEle.addEventListener('mousemove', canvasMoveHandler)
            // 抬起事件
            canvasEle.addEventListener('mouseup', canvasMouseUpHandler)
        }
    }
    canvasEle.addEventListener('mousedown', canvasDownHandler)
},

以上是核心代码,绑定点击及拖动事件绘制待定区域!

 页面整体代码,包含一些测试数据,我没有删除,你自己进行分析删除即可.

<template>
    <div class="app-container" style="padding: 0px;">
        <div class="tool-box flex-row w-100">
            <el-button type="primary" icon="el-icon-upload" @click="uploadVisible = !uploadVisible">上传PDF文档</el-button>
            <el-button type="primary" icon="el-icon-upload2" @click="backOneStep">回退</el-button>
            <el-button type="danger" @click="clearAll">重置</el-button>
            <!-- <el-button size="mini" type="success" @click="savePoints">保存</el-button> -->
        </div>
        <div class="container-view flex-row">
            <div class="left-view flex-row jc-around">
                <div class="cover-view">
                    <el-scrollbar class="w-100 h-100 flex-row">
                        <div class="w-100 flex-col" style="height: auto;background-color:rgb(245,245,245)">
                            <div class="cover-item-view flex-col" v-for="(item, index) in coverList" :key="index"
                                @click="selOneItemAction(index)" v-loading="item.loading">
                                <el-image style="width: 100%; height: auto;background-color:rgb(230,230,230)"
                                    :src="item.url" fit="scale-down"
                                    :class="{ 'border-hi': index == crrentIndex }"></el-image>
                                <span v-if="index < coverList.length - 1" style="height: 5px;display:inline-block"
                                    class="w-100"></span>
                            </div>
                        </div>
                    </el-scrollbar>
                    <div v-if="coverList.length == 0" class="place-text flex-row jc-center">
                        <span class="place-span">未上传文档</span>
                    </div>
                </div>
                <div class="canvas-wrap flex-row jc-center" ref="canvaxbox"
                    v-loading="crrentIndex >= 0 && coverList[crrentIndex].loading">
                    <canvas id="imgCanvas" style="border:1px solid rgb(230,230,230)"></canvas>

                    <div class="view-tools flex-col">
                        <el-tooltip effect="dark" content="全页识别" placement="right">
                            <div class="w-100 flex-row jc-center" style="height: 50%;" @click="reconizerAction(0)">
                                <i class="el-icon-full-screen" style="font-size:20px"
                                    :class="{ 'toolsHili': toolsIndex == 0 }"></i>
                            </div>
                        </el-tooltip>
                        <el-tooltip effect="dark" content="区域识别" placement="right">
                            <div class="w-100 flex-row jc-center"
                                style="height: 50%;border-top:1px solid rgb(200,200,200)" @click="reconizerAction(1)">
                                <i class="el-icon-crop" style="font-size:20px"
                                    :class="{ 'toolsHili': toolsIndex == 1 }"></i>
                            </div>
                        </el-tooltip>
                    </div>
                </div>
            </div>
            <div class="right-view">
                <el-scrollbar class="result-view">
                    <div class="w-100 flex-col" v-for="(item, idex) in resultList">
                        <div class="card-view top-margin">
                            <div class="flex-row jc-end">
                                <i class="el-icon-close" style="font-size: 20px;padding:0px 0px 15px 0px"
                                    @click="closeItem(item)"></i>
                            </div>
                            <el-form :ref="`resultForm-${idex}`" :model="item" label-width="80px" class="w-100">
                                <el-form-item label="字段名称">
                                    <el-input class="w-100" v-model="item.name"></el-input>
                                </el-form-item>
                                <el-form-item label="字段类型">
                                    <el-select class="w-100" v-model="item.optionsValue" placeholder="请选择">
                                        <el-option v-for="btem in item.optionsList" :label="btem.label"
                                            :value="btem.value"></el-option>
                                    </el-select>
                                </el-form-item>
                            </el-form>
                            <div class="flex-row">
                                <span class="el-form-item__label" style="width:80px;">识别结果</span>
                                <span style="width:calc(100% - 100px);font-size:14px;">识别结果</span>
                            </div>
                        </div>
                    </div>
                </el-scrollbar>
            </div>
        </div>

        <!--表单组件-->
        <el-dialog append-to-body :close-on-click-modal="false" :visible.sync="uploadVisible" title="上传PDF文档"
            width="500px">
            <el-upload class="w-100" ref="upload" :limit="1" :before-upload="beforeUpload" :auto-upload="false" drag
                :headers="headers" :on-success="handleSuccess" :on-error="handleError" :action="pdfUploadApi">
                <i class="el-icon-upload"></i>
                <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
                <div class="el-upload__tip" slot="tip">只能上传txt doc pdf ppt pps xlsx xls docx文件,且不超过10M</div>
            </el-upload>
            <div slot="footer" class="dialog-footer">
                <el-button type="text" @click="uploadVisible = false">取消</el-button>
                <el-button :loading="loading" type="primary" @click="doUpload">确认</el-button>
            </div>
        </el-dialog>
    </div>
</template>

<script>
import { mapGetters } from 'vuex'
import { getToken } from '@/utils/auth'
//https://www.cnblogs.com/IwishIcould/p/18360209
export default {
    components: {},
    mixins: [],
    data() {
        return {
            id: null,
            name: '',
            headers: { 'Authorization': getToken() },
            coverList: [{
                url:'https://gd-hbimg.huaban.com/ba2dd60c93a9ef06595825d48c71e863a58f2cbe3f9f0-EQK5rk_fw1200',
                width:1200,
                height:1697
            },{
                url:'https://gd-hbimg.huaban.com/ba2dd60c93a9ef06595825d48c71e863a58f2cbe3f9f0-EQK5rk_fw1200',
                width:1200,
                height:1697
            },{
                url:'https://gd-hbimg.huaban.com/ba2dd60c93a9ef06595825d48c71e863a58f2cbe3f9f0-EQK5rk_fw1200',
                width:1200,
                height:1697
            },{
                url:'https://gd-hbimg.huaban.com/ba2dd60c93a9ef06595825d48c71e863a58f2cbe3f9f0-EQK5rk_fw1200',
                width:1200,
                height:1697
            },{
                url:'https://gd-hbimg.huaban.com/ba2dd60c93a9ef06595825d48c71e863a58f2cbe3f9f0-EQK5rk_fw1200',
                width:1200,
                height:1697
            },{
                url:'https://gd-hbimg.huaban.com/ba2dd60c93a9ef06595825d48c71e863a58f2cbe3f9f0-EQK5rk_fw1200',
                width:1200,
                height:1697
            }],
            submitData: [
                // {"polygon":{"x1":0,"y1":0,"x2":1920,"y2":0,"x3":1920,"y3":1080,"x4":0,"y4":1080}},
                { "polygon": { "x1": 700, "y1": 273, "x2": 975, "y2": 278, "x3": 1107, "y3": 368, "x4": 718, "y4": 354 } },
                { "polygon": { "x1": 49, "y1": 32, "x2": 183, "y2": 35, "x3": 181, "y3": 100, "x4": 55, "y4": 97 } },
                { "polygon": { "x1": 433, "y1": 250, "x2": 706, "y2": 253, "x3": 707, "y3": 392, "x4": 435, "y4": 393 } },
                {
                    "polygon": {
                        "x1": 45,
                        "y1": 539,
                        "x2": 193,
                        "y2": 538,
                        "x3": 192,
                        "y3": 622,
                        "x4": 41,
                        "y4": 623,
                        "x5": 42,
                        "y5": 623
                    }
                }
            ],
            resultList: [
                {
                    label: '',
                    value: '',
                    optionsValue: '',
                    optionsList: [{
                        label: '常规',
                        value: ''
                    }]
                }, {
                    label: '',
                    value: '',
                    optionsValue: '',
                    optionsList: [{
                        label: '常规',
                        value: ''
                    }]
                }, {
                    label: '',
                    value: '',
                    optionsValue: '0',
                    optionsList: [{
                        label: '常规',
                        value: '0'
                    }]
                }],
            loading: false,
            toolsIndex: 0,
            uploadVisible: false,
            // 所有的矩形信息
            drawedAreas: [],
            crrentIndex: 0
        }
    },
    computed: {
        ...mapGetters([
            'baseApi',
            'pdfUploadApi'
        ]),
        scrollWrapper() {
            return this.$refs.scrollbar.$refs.wrap
        }
    },
    created() {
    },
    mounted() {
        this.initCanvas()

        this.renderImgCanvas(0)
    },
    methods: {
        initCanvas() {
            let rectArr = []
            let currAreas = []
            let canvasEle = document.getElementById('imgCanvas')
            let elRef = this.$refs.canvaxbox
            // canvasEle.width = elRef.clientWidth
            canvasEle.height = elRef.clientHeight
            canvasEle.width = (210 / 297) * elRef.clientHeight

            let ctx = canvasEle.getContext('2d')
            // 给矩形的设置颜色
            ctx.strokeStyle = '#448ef7'
            this.saveCtx = ctx

            let drawRect = (x1, y1, x2, y2) => {
                let rectWidth = Math.abs(x2 - x1)
                let rectHeight = Math.abs(y2 - y1)
                let endX = Math.min(x1, x2)
                let endY = Math.min(y1, y2)
                // 绘制之前先清空之前实时移动产生的多余的矩形路径
                ctx.clearRect(0, 0, canvasEle.width, canvasEle.height)
                ctx.strokeStyle = '#448ef7'
                // 绘制之前那些存储在 this.drawedAreas 数组中的矩形
                if (this.img) {
                    ctx.drawImage(this.img, 0, 0, canvasEle.width, canvasEle.height)
                }

                currAreas = [endX, endY, rectWidth, rectHeight]
                this.drawedAreas.forEach(element => {
                    ctx.beginPath();
                    ctx.strokeRect(...element)
                    ctx.stroke();
                });
                // 开始本次路径
                ctx.beginPath();
                // 绘制本次的矩形路径
                ctx.rect(...currAreas);
                // 开始填充矩形
                ctx.stroke();
            }

            let canvasMoveHandler = (e) => {
                drawRect(rectArr[0], rectArr[1], e.offsetX, e.offsetY)
            }

            let canvasMouseUpHandler = () => {
                this.drawedAreas.push(currAreas)
                canvasEle.removeEventListener('mousemove', canvasMoveHandler)
                canvasEle.removeEventListener('mouseup', canvasMouseUpHandler)
            }
            // 给canvas注册事件按下事件
            let canvasDownHandler = (e) => {
                if (this.toolsIndex == 1) {
                    rectArr = [e.offsetX, e.offsetY]
                    // 按下的时候需要注册移动事件
                    canvasEle.addEventListener('mousemove', canvasMoveHandler)
                    // 抬起事件
                    canvasEle.addEventListener('mouseup', canvasMouseUpHandler)
                }
            }
            canvasEle.addEventListener('mousedown', canvasDownHandler)
        },
        // 上传文件
        doUpload() {
            this.loading = true
            this.$refs.upload.submit()
        },
        beforeUpload(file) {
            let isLt2M = true
            isLt2M = file.size / 1024 / 1024 < 100
            if (!isLt2M) {
                this.loading = false
                this.$message.error('上传文件大小不能超过 100MB!')
            }
            return isLt2M
        },
        handleSuccess(response, file, fileList) {
            this.loading = false
            this.uploadVisible = false
            this.$modal.msgSuccess('上传成功')
            this.$refs.upload.clearFiles()

            response.documents.forEach(p => {
                p.loading = true
                p.url = this.baseApi + "/" + p.url
            })
            this.coverList = response.documents
            this.renderImgCanvas(0)
        },
        // 监听上传失败
        handleError(e, file, fileList) {
            const msg = JSON.parse(e.message)
            this.$notify({
                title: msg.message,
                type: 'error',
                duration: 2500
            })
            this.loading = false
        },
        renderImgCanvas(index) {
            // 计算宽高比
            this.crrentIndex = index
            let canvasEle = document.getElementById('imgCanvas')
            let ww = canvasEle.width // 画布宽度
            let wh = canvasEle.height // 画布高度

            let e = this.coverList.objectAtIndex(index)
            let iw = e.width // 图片宽度
            let ih = e.height // 图片高度

            if (iw / ih < ww / wh) { // 以高为主
                e.ratio = ih / wh
                e.canvasHeight = wh
                e.canvasWidth = wh * iw / ih
            }
            else { // 以宽为主
                e.ratio = iw / ww
                e.canvasWidth = ww
                e.canvasHeight = ww * ih / iw
            }

            // 初始化画布大小
            canvasEle.width = e.canvasWidth
            canvasEle.height = e.canvasHeight

            e.loading = true
            // 图片加载绘制
            let img = document.createElement('img')
            img.src = e.url
            img.onload = () => {
                e.loading = false
                this.saveCtx.drawImage(img, 0, 0, e.canvasWidth, e.canvasHeight)
            }
            this.img = img
        },
        clearAll() { // 清空所有绘制区域
            let canvasEle = document.getElementById('imgCanvas')
            this.saveCtx.clearRect(0, 0, canvasEle.width, canvasEle.height);
            if (this.img) {
                this.saveCtx.drawImage(this.img, 0, 0, canvasEle.width, canvasEle.height)
            }
            this.drawedAreas = []
        },
        savePoints() { // 将画布坐标数据转换成提交数据
            let objectPoints = []
            // "object": [{"polygon": {"x1":700,"y1":273,"x2":975,"y2":278,"x3":1107,"y3":368,"x4":718,"y4":354} }]
            objectPoints = currAreas.map(area => {
                let polygon = {}
                area.forEach((point, i) => {
                    polygon[`x${i + 1}`] = Math.round(point[0] * this.ratio)
                    polygon[`y${i + 1}`] = Math.round(point[1] * this.ratio)
                })
                return {
                    "polygon": polygon
                }
            })
            this.submitData = objectPoints
            console.log('最终提交数据', objectPoints)
        },
        handleScroll(e) {
            const eventDelta = e.wheelDelta || -e.deltaY * 40
            const $scrollWrapper = this.scrollWrapper
            let scrolled = $scrollWrapper.scrollLeft + eventDelta / 4
            $scrollWrapper.scrollLeft = scrolled

            this.$emit("scrolled", scrolled)
        },
        selOneItemAction(index) {
            this.crrentIndex = index
        },
        reconizerAction(tag) {
            this.toolsIndex = tag
            if (tag == 0) {
                this.clearAll()
            }
        },
        backOneStep() {
            let canvasEle = document.getElementById('imgCanvas')
            this.saveCtx.clearRect(0, 0, canvasEle.width, canvasEle.height)
            // 绘制之前那些存储在 this.drawedAreas 数组中的矩形
            if (this.img) {
                this.saveCtx.drawImage(this.img, 0, 0, canvasEle.width, canvasEle.height)
            }
            this.drawedAreas.removeLastObject()
            this.drawedAreas.forEach(element => {
                this.saveCtx.beginPath();
                this.saveCtx.strokeRect(...element)
                this.saveCtx.stroke();
            });
        }
    }
}
</script>

<style lang="scss" scoped>
@import "./dicomStyles/aiStyle.scss";

::v-deep {
    .result-view {
        .is-horizontal {
            height: 0px;
            left: 0px;
            display: none;
        }
    }

    .view-content {
        .is-horizontal {
            display: none;
        }

        .el-scrollbar__wrap {
            overflow-x: hidden;
            margin-bottom: 0px !important;
        }

        //横向滚动
        .el-scrollbar__view {
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: center;
        }

        ::-webkit-scrollbar-thumb {
            background-color: #888;
        }

        ::-webkit-scrollbar {
            height: 8px;
        }
    }

    .el-form-item {
        margin-bottom: 10px;
    }

    .el-input__inner {
        border-radius: 0px;
    }

    .el-scrollbar__wrap {
        overflow-x: hidden;
    }


    .el-image-viewer__wrapper {
        top: 55px;
    }

    .el-image__error,
    .el-image__placeholder {
        background: none;
    }

    .el-form-item__label {
        font-weight: 500;
    }

    .el-upload {
        width: 100%;
    }

    .el-upload-dragger {
        width: 100%;
    }
}
</style>

样式文件:

.app-container{
    background-color: rgb(245, 245, 245);
}

.cover-view{
    position: relative;
    width: 180px;
    height: 100%;
    background-color: white;
}

.cover-item-view{
    width: 100%;
    height: auto;
}

.tool-box {
    width: 100%;
    height: 54px;
    padding: 5px 30px;
    border-bottom: 5px solid rgb(245, 245, 245);
    background-color: white;
}


.toolsHili{
    color: #0286df;
}

.view-tools{
    position: absolute;
    left: 0px;
    top: calc(50% - 50px);
    width: 34px;
    height: 100px;
    background-color: white;
    border-top-right-radius: 10px;
    border-bottom-right-radius: 10px;
    border: 1px solid rgb(200,200,200);
    border-left: none;
}

.container-view{
    width: 100%;
    height: calc(100% - 64px);
}

.left-view{
    position: relative;
    width: 70%;
    height: 100%;
    background-color: rgb(245, 245, 245);
}


.right-view{
    width: 30%;
    height: 100%;
}

.flex-row{
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    align-items: center;
}

.jc-end{
    justify-content: flex-end;
}

.jc-center{
    justify-content: center;
    align-items: center;
}


.jc-around{
    justify-content: space-around;
}


.jc-between{
    justify-content: space-between;
}

.result-view{
    position: relative;
    width: 100%;
    height: 100%;

    background-color: rgb(245, 245, 245)
}

.flex-col{
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    align-items: center;
}


.top-margin{
    margin-top: 15px;
}


.card-view{
    width: 90%;
    background-color: white;
    padding: 15px;
    border-radius: 10px;
}


.w-100{
    width: 100%;
}

.h-100{
    height: 100%;
}


.view-content{
    width: 100%;
    height: calc(100% - 10px);
}

.canvas-wrap {
    position: relative;
    width: calc(100% - 190px);
    height: 100%;

    background-color: white;
}

.place-text{
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

.place-span
{
    font-size: 15px;
    color: #666666;
}


.border-hi{
    border: 1px solid #0286df;
}


.canvas-view{
    position: absolute;
    left: 0;
    top: 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2259892.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Pro Git#3] 远程仓库 | ssh key | .gitignore配置

目录 1. 分布式版本控制系统的概念 2. 实际使用中的“中央服务器” 3. 远程仓库的理解 4. 新建远程仓库 5. 克隆远程仓库 6. 设置SSH Key 实验 一、多用户协作与公钥管理 二、克隆后的本地与远程分支对应 三、向远程仓库推送 四、拉取远程仓库更新 五、配置Git忽略…

【Python网络爬虫笔记】11- Xpath精准定位元素

目录 一、Xpath 在 Python 网络爬虫中的作用&#xff08;一&#xff09;精准定位元素&#xff08;二&#xff09;应对动态网页&#xff08;三&#xff09;数据结构化提取 二、Xpath 的常用方法&#xff08;一&#xff09;节点选取&#xff08;二&#xff09;谓词筛选&#xff0…

Spark执行计划解析后是如何触发执行的?

在前一篇Spark SQL 执行计划解析源码分析中&#xff0c;笔者分析了Spark SQL 执行计划的解析&#xff0c;很多文章甚至Spark相关的书籍在讲完执行计划解析之后就开始进入讲解Stage切分和调度Task执行&#xff0c;每个概念之间没有强烈的关联&#xff0c;因此这中间总感觉少了点…

java抽奖系统登录下(四)

6.4 关于登录 最简单的登录&#xff1a; 1、web登录页填写登录信息&#xff0c;前端发送登录信息到后端&#xff1b; 2、后端接受登录信息&#xff0c;并校验。校验成功&#xff0c;返回成功结果。 这种登录会出现一个问题&#xff0c;用户1成功登录之后&#xff0c;获取到后台…

基于米尔全志T527开发板的OpenCV进行手势识别方案

本文将介绍基于米尔电子MYD-LT527开发板&#xff08;米尔基于全志T527开发板&#xff09;的OpenCV手势识别方案测试。 摘自优秀创作者-小火苗 米尔基于全志T527开发板 一、软件环境安装 1.安装OpenCV sudo apt-get install libopencv-dev python3-opencv 2.安装pip sudo apt…

【传感器技术】第6章 压电式传感器,压电材料,压电效应,电压放大器

关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…

AI 智能体(AI Agent)到底什么原理?能干什么事情

智能体应用有哪些&#xff1f; 智能体在千行百业中有着广泛的应用&#xff0c;目前已经在 600 多个项目落地和探索&#xff0c;广泛应用于政府与公共事业、交通、工业、能源、金融、医疗、科研等行业。智能体是模拟人类智能的计算机系统&#xff0c;能自主感知环境、智能决策并…

力扣-图论-12【算法学习day.62】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非…

智慧政务数据中台建设及运营解决方案

数据中台&#xff1a;政府数字化转型的引擎 数据中台作为政府数字化转型的核心驱动力&#xff0c;起源于美军的作战体系&#xff0c;强调高效、灵活与强大。它不仅促进了政府决策的科学性&#xff0c;还推动了政府服务的精细化与智能化。 数据中台的应用场景&#xff1a;数字…

如何使mysql数据库ID从0开始编号——以BiCorpus为例

BiCorpus是北京语言大学韩林涛老师研制一款在线语料库网站&#xff0c;可以通过上传tmx文件&#xff0c;实现在线检索功能&#xff0c;程序在github上开源免费&#xff0c;深受广大网友的喜欢。 在使用过程中&#xff0c;我发现我上传的语言资产经历修改后&#xff0c;mysql的…

开启第二阶段---蓝桥杯

一、12.10--数据类型的范围及转化 今天是刚开始&#xff0c;一天一道题 对于这道题我想要记录的是Java中的整数默认是 int 类型&#xff0c;如果数值超出了 int 的范围&#xff0c;就会发生溢出错误。为了避免这个问题&#xff0c;可以将数字表示为 long 类型&#xff0c;方法…

使用 Database Tools 实现高效数据查询的十大 IntelliJ IDEA 快捷键

得益于 IntelliJ IDEA Ultimate 的 Database Tools&#xff08;数据库工具&#xff09;中的专用 SQL 查询控制台&#xff0c;您无需离开 IDE 即可轻松修改连接到您的 Java 应用程序的任何数据库中的数据&#xff0c;以及从这些数据库中提取数据。 查询控制台具有 SQL 语句特定的…

【蓝桥杯选拔赛真题93】Scratch青蛙过河 第十五届蓝桥杯scratch图形化编程 少儿编程创意编程选拔赛真题解析

目录 Scratch青蛙过河 一、题目要求 编程实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 1、思路分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 5、python资料 Scr…

minio 分布式文件管理

一、minio 是什么&#xff1f; MinIO构建分布式文件系统&#xff0c;MinIO 是一个非常轻量的服务,可以很简单的和其他应用的结合使用&#xff0c;它兼容亚马逊 S3 云存储服务接口&#xff0c;非常适合于存储大容量非结构化的数据&#xff0c;例如图片、视频、日志文件、备份数…

华为FreeBuds Pro 4丢了如何找回?(附查找功能使用方法)

华为FreeBuds Pro 4查找到底怎么用&#xff1f;华为FreeBuds Pro 4有星闪精确查找和离线查找&#xff0c;离线查找功能涵盖播放铃声、导航定位、星闪精确查找、上线通知、丢失模式、遗落提醒等。星闪精确查找是离线查找的子功能&#xff0c;当前仅华为FreeBuds Pro 4充电盒支持…

深度学习:基于MindSpore的极简风大模型微调

什么是PEFT&#xff1f;What is PEFT&#xff1f; PEFT(Parameter Efficient Fine-Tuning)是一系列让大规模预训练模型高效适应于新任务或新数据集的技术。 PEFT在保持大部分模型权重冻结&#xff0c;只修改或添加一小部份参数。这种方法极大得减少了计算量和存储开销&#x…

【一本通】最小圈

【一本通】最小圈 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 对于一张有向图&#xff0c;要你求图中最小圈的平均值最小是多少&#xff0c;即若一个圈经过k个节点&#xff0c;那么一个圈的平均值为圈上k条边权的和除以k&#xff0c;现要…

ansible自动化运维(四)jinjia2模板

Jinjia2模板 前面说到playbook组成的时候&#xff0c;有介绍到template模块&#xff0c;而template模块对模板文件进行渲染时&#xff0c;使用的就是jinja2模板引擎&#xff0c;jinja2本身就是基于python的模板引擎&#xff0c;所以下面先来了解一下jinjia2模板的一些用法 基…

【USB-HID】“自动化键盘“

这里写目录标题 【USB-HID】"自动化键盘"1. 前言2. 框架3. 实现3.1 模拟键盘按键输入 【USB-HID】“自动化键盘” 1. 前言 最近从朋友那了解了一种"自动化键盘"&#xff0c;能够通过上位机录制按键脚本&#xff0c;然后执行脚本&#xff0c;实现物理键盘…

使用ECK 快速部署 Elasticsearch 集群 + Kibana

部署 ECK [2.12] 安装说明 ElasticCloudonKubernetes(ECK)是一个 Elasticsearch Operator&#xff0c;但远不止于此。ECK 使用 Kubernetes Operator 模式构建而成&#xff0c;需要安装在您的 Kubernetes 集群内&#xff1b; 借助 Elastic Cloud on Kubernetes (ECK)&#xff0…