Debug-022-el-upload照片上传-整体实现回顾

news2024/9/25 19:22:46

前情概要:

        最近业务里通过el-upload实现一个上传图片的功能,有一些小小的心得分享给各位。一方面是review一下,毕竟实现了很多细小的功能,还有这么多属性、方法(钩子)和碰到的问题,感觉小有成就。另一方面,这个上传图片的功能比较少用,但是确实多数系统都有可能去做的一项功能,时间一久,很多钩子和属性非常容易遗忘,所以这里备份可以便于将来二次利用,温习一下,很多地方又可以直接去CV,也算是为以后提升效率考虑吧(虽然现在把这些在回顾一遍写下来真的超级麻烦,但还是应该有一些匠心精神吧,共勉共勉)。

先分享效果吧:(由于涉及到业务,这里还是以截图的方式吧,先不使用视频)

图1:初始效果

图2:有图片的效果,可以放大、删除、替换

   

html结构(vue3 +elementUI-plus写法)

          <el-upload
            ref="imgREF"    //绑定ref,准备拿实例
            v-model:file-list="imgList" //图片的
            action="#"    //详见下面注释
            accept=".jpg, .jpeg, .png" //接受上传的图片类型
            :limit="1"                //限制上传图片个数
            list-type="picture-card"  
            :auto-upload="false"
            :on-change="handleChangeImg"    //图片改变时的钩子  这里用于图片上传
            :on-exceed="handleExceed"       //图片超出个数限制时的钩子函数
          >
            <el-icon><plus /></el-icon>
            <template #file="{ file }">   //插槽  file是这个图片的信息
              <div style="width: 100%;">
                <el-image class="el-upload-list__item-thumbnail" :src="file.url" fit="contain" />
                <div class="el-upload-list__item-actions flex">
                  <div
                    class="el-upload-list__item-preview"
                    @click="handleImgEnlarge(file)"
                  >
                    <!-- <el-icon><zoom-in /></el-icon> -->
                    <!-- 放大 -->
                    <svg-icon style="width: 22px;height: 22px;" name="device_img_enlarge" />
                  </div>
                  <div
                    class="el-upload-list__item-preview"
                    @click="handleImgDelete(file)"
                  >
                    <!-- 删除 -->
                    <svg-icon style="width: 22px;height: 22px;" name="device_img_delete" />
                  </div>
                  <div
                    class="el-upload-list__item-preview"
                    @click="handleImgReplace(file)"
                  >
                    <!-- 替换 -->
                    <svg-icon style="width: 22px;height: 22px;" name="device_img_replace" />
                  </div>
                </div>
              </div>
            </template>
          </el-upload>


// //elementUI中的upload默认的提交行为是通过actin属性中输入的url链接,提交到指定的服务器上,
但是这种url提交图片的方式,在实际的项目环境中往往是不可取的,我们的服务器会拦截所有的请求,
进行权限控制,密钥检查,请求头分析等安全行为控制。写在这里的url无法实现定义请求参数之类的,
就更不能进行后面的操作了。如果你说放行这个请求不就行了嘛,确实,放行不做任何操作是可以,
真被人攻击了,到时候定责的时候就麻烦了。所以最恰当的方式,就是自定义图片的上传行为。

一、上传图片

代码如下:

const imgREF = ref<UploadInstance>()   //el-upload的实例
const showViewer = ref(false)    // 放大图片<el-image-viewer>的显示与否
const imgList = ref<any>([]) // 图片列表,用于存放用户上传的图片
const urlList = ref<UploadUserFile[]>([]) // 放大查看列表

// 上传图片-文件状态改变   用于判断图片类型和大小
function handleChangeImg(uploadFile:any) {
  console.log('handleChangeImg', uploadFile, imgList.value)
  form.imgRaw = uploadFile.raw
  const uuid = uuidv4()   //给上传到OSS上的文件加后缀id区分相同文件
  // 这里需要encodeURIComponent,不然中文图片在详情回显会报错,可能是加密原因导致
  if (uploadFile.raw!.type === 'image/png')form.imageName = `${encodeURIComponent(uploadFile.name.slice(0, -4))}-${uuid}${uploadFile.name.slice(-4)}`
  if (uploadFile.raw!.type === 'image/jpeg')form.imageName = `${encodeURIComponent(uploadFile.name.slice(0, -5))}-${uuid}${uploadFile.name.slice(-5)}`
  const FILE_TYPES = [
    'image/png',
    'image/jpeg',
  ]
  const rawFile = uploadFile.raw!
  if (!FILE_TYPES.includes(rawFile.type)) {
    imgREF.value!.clearFiles()
    return $message.error('请上传jpg、png、jepg格式文件')
  } else if (rawFile.size / 1024 / 1024 > 5) {
    imgREF.value!.clearFiles()
    return $message.error('图片不超过5MB')
  } else {
    imgList.value = [uploadFile]
  }

  console.log('finally', imgList.value)
}

(1) 打印uploadFile

        这一点对我来说很重要,我需要根据打印中得到的文件信息去判断文件的大小,类型是否正确,对于新手来讲还是十分必要的,在你没把握的情况下。

图3 

上传图片打印的uploadFile里有全部的文件信息。 真正的文件是其中的raw,但是这里我这里整体存下来,因为之后会使用uploadFile的url字段

(2)判断类型和大小

根据uploadFile中的raw中的type字段和size字段就可以判断大小。

图片类型:需求上需要我们上传什么类型,我们就先准备好一个变量存储在一个数组,上传文件的时候拿type中的类型和数组中我们允许的类型去比对即可,不对就抛错。

图片大小:这里大小单位存的应该是字节,需求上需要限制图片大小不超过5MB,所以先除以1024换算成KB,再除以1024换算成MB,小于5MB即可,否则抛错。

需要注意的是:这里是需要调用upload实例上的方法imgREF.value!.clearFiles()去清理掉上传的文件,因为这个上传文件的动作不会被阻止,就算没有使用:on-change="handleChangeImg"这个方法,文件同样会被上传。哪怕你校验了文件的格式,需要代码手动清理掉,打印一下imgREF.value实例看一下:直接调用即可。

图4

满足所有校验之后,最后把uploadFile放入imgList数组中。这一步就完成了

二、放大图片

(1)页面部分el-upload中使用插槽

        这块页面布局可以参考element-plus官网上的关于el-upload的自定义缩略图这一部分案例。饿了么基于 Vue 2.x 和Vue3.x版本的写法会有一点不同,但我觉的对诸位问题不大。稍作调整即可。
       

(2)逻辑代码

  <el-image-viewer
    v-if="showViewer"
    :url-list="urlList"
    @close="closeViewer"
  />



// 放大查看图片
function handleImgEnlarge(file:any) {
  urlList.value = [imgList.value[0].url]
  console.log('handlePictureCardPreview', imgList.value)
  showViewer.value = true
}



function closeViewer() {
  console.log('closeViewer')
  showViewer.value = false
}

 如果只是实现el-image的图片放大预览,那么在el-image的话是有这个属性在的,即:preview-src-list,只要配了这个属性就可以开启图片预览功能,它的值是图片链接的数组。但是这里不行,因为放大的逻辑是在“放大镜”按钮上。好在百度一下找到了另一种实现方式,就是使用

 <el-image-viewer>标签,但是在官网上没有实例去给我们参考,藏得位置也比较深。

图5 

        百度参考了一下前人的经验和代码,写了一个确实是没问题的。几个比较重要的特性就是预览显示的时机,关闭还有数据绑定,这几个文档上就有。

        饿了么做的预览模式还是很不错的,效果如下。支持放大,缩小,一比一还原,旋转,还有一点居然可以实现拖拽移动。这是我优先考虑使用el-image(el-image-viewer)的原因。而在饿了么官网上el-upload那一节“自定义缩略图”示例中,是使用el-dialog弹窗完成的放大功能,显然没有image的预览模式好。

图6

下图是官网的放大方式:用的是dialog,显然没有上一种好使。

图7

三、删除图片

// 删除图片
function handleImgDelete(file:any) {
  urlList.value = []
  imgREF.value!.clearFiles()
}

       

 图8

        这里通过ref拿到el-upload的实例之后使用上面的clearFiles()方法即可。这里还需要注意的是清除放大展示图片的的urlList数组,因为我们需求上是只能上传一个图片,这里不删除,那么放大功能会保留之前的图片。

四、替换图片

        这个功能我印象里是花了一点时间的。建议各位先看“十二、钩子函数的使用”。

先上代码:

// 当超出限制时,执行的钩子函数  这里用以替换照片的功能
function handleExceed(files:any) {
  console.log('handleExceed', files)
  const FILE_TYPES = [
    'image/png',
    'image/jpeg',
  ]
  const rawFile = files[0]!
  // 替换之前需要校验照片格式,但是这里先不删除原照片
  if (!FILE_TYPES.includes(rawFile.type)) {
    // imgREF.value!.clearFiles()
    return $message.error('请上传jpg、png、jepg格式文件')
  } else if (rawFile.size / 1024 / 1024 > 5) {
    // imgREF.value!.clearFiles()
    return $message.error('图片不超过5MB')
  } else {
    // 满足前两个条件,则删除原照片,上传新照片
    imgREF.value!.clearFiles()
    const file = files[0] as UploadRawFile
    file.uid = genFileId()
    imgREF.value!.handleStart(file)
    urlList.value = [rawFile]
    console.log('finallyhandleExceed', imgList.value)
  }
}

// 替换图片
function handleImgReplace(file:any) {
  onUploadImgLocal(file)
}

// 手动调取图片本地上传入口
function onUploadImgLocal(row:any) {
  console.log('importBillExcel', row)
  const input = document.createElement('input')
  input.type = 'file'
  input.accept = '.jpeg, .png,  .jpg' // 限制选择的文件类型为 .jpg, .png,  .jpg
  input.style.display = 'none'
  document.body.appendChild(input)
  input.click()
  input.onchange = (e:any) => {
    const file = e.target.files[0] // 获取文件对象
    console.log('eeeeee', e, file)
    handleExceed([file])
  }
}

       上面就是执行替换的方法。其实是不需要onUploadImgLocal唤起上传文件的功能的,但是需求上限制上传图片为1张,上传完毕的时候,必须要把默认上传图片的那个样式隐藏掉,就是最上方初始效果的那种图。此时,页面没有入口再次唤起上传文件,所以有了onUploadImgLocal这个方法。

        当执行完上传文件的动作后,代码上我再次执行handleExceed方法(注意这里的传参格式),这里的file是第二次需要上传的文件,在handleExceed中也同样需要对文件二次校验一遍。满足所有打条件后,先删掉上一张图片,再去执行handleStart(官网上你可以看看el-upload的示例:“覆盖前一个文件”)这个动作,这个也是官网提供的以方法的形式手动上传文件(图片),将第二张图片上传给el-upload。至此就会完成替换功能。

五、上传图片至OSS

阿里云对象存储服务(Object Storage Service,简称OSS)为您提供基于网络的数据 存取服务

        我们项目中的方式是将图片或者文件上传到OSS上,获取到链接之后,传递给后端,详情页回显也是通过调用oss方法根据URL路径去回显的。

当然前提是已经在阿里OSS上配好了项目路径(这个我们这是交给后端),如果你想知道具体方式,可以参考下面两篇博文:

手把手教你使用阿里云对象存储 OSS服务上传文件-保姆级!_阿里云oss上传-CSDN博客

前端、后端上传文件到OSS,简明记录_前端上传文件到oss-CSDN博客

如果你们已经有了一个oss存放目录,那么我们可以参考oss上的示例方法,我是参考这里的示例去上传文件的

如何使用Browser.js SDK简单上传文件_对象存储(OSS)-阿里云帮助中心

// 首先要npm install ali-oss
//初始化
const client = new OSS({
        // yourRegion填写Bucket所在地域。以华东1(杭州)为例,yourRegion填写为oss-cn-hangzhou。
        region: "yourRegion",
        // 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
        accessKeyId: "yourAccessKeyId",
        accessKeySecret: "yourAccessKeySecret",
        // 从STS服务获取的安全令牌(SecurityToken)。
        stsToken: "yourSecurityToken",
        // 填写Bucket名称。
        bucket: "examplebucket",
});

//accessKeyId和accessKeySecret写你们项目中申请好的,bucket也需要使用OSS中我们自定义的项目地址名称


// OSS
const result = await client.put(`/device/install/imge_${form.imageName}`, form.imgRaw)
console.log('oss', result)

图9

打印成功上传oss后返回的result。 这里面的URL字段是关键,需要存储至后端,这是回显图片的关键,由于我之前保存给后端使用的是name,会有一些问题,比如需要处理中文名称的问题

六、详情回显图片

        一般新增过后,系统会有“详情页”去回显上传过的图片信息。这里我原来也是调用oss上提供的方法去回显。

Browser.js SDK图片处理_对象存储(OSS)-阿里云帮助中心

中最后我提到过。如果存给后端的是返回响应中的url,在回显时可以直接使用这个url链接,将其传给子组件中的el-image组件中即可回显照片。

七、上传图片大小 类型个数限制

        这个参考“一、上传图片”中的步骤(2),其实只要你能拿到文件的file,就可以拿到大小,类型,就可以做这些限制。个数限制是用的el-upload中的limit属性。

八、上传图片的默认入口隐藏

一个css样式即可实现:关键是通过F12找到图1的位置,然后把它disable:none掉。

并且这里需要配合监听,考虑一下隐藏的时机:上传过一张照片就隐藏,没有照片才显示。

// 这里监听imgList图片的个数,看是否隐藏上传图片的默认入口
watchEffect(() => {
  const elements = document.querySelectorAll('.el-upload--picture-card')
  if (imgList.value.length) {
    // 遍历所有匹配的元素并设置 display 为 none
    elements.forEach((element) => {
      element.style.display = 'none'
    })
  } else {
    elements.forEach((element) => {
      element.style.display = ''
    })
  }
})

九、操作el-upload的实例

el-upload实例上的方法倒不是很多,我们用到了其中两个。不像el-table和el-tree可能有十几个。

十一、中文名称图片时使用encodeURIComponent()方法对中文名称编码进行处理

这里讲两个bug:

(1)在最初实现上传图片的功能时,我取oss响应的name,如果有中文名称的图片时,我发现回显的时候URL中会出现乱码,怀疑是公司加密的原因,因此使用了encodeURIComponent()去转义。但是如果直接使用oss响应的URL字段,名称会被自动转义,不必使用此方法。

(2)每次在上传照片的时候(on-change中)需要给照片的name添加唯一标识,这里使用uuid去拼接。不然如果两次上传oss的图片不一样,但是名称类型一致,后一项会覆盖前一项,导致第一次的照片也变成第二次上传的照片了。

  const uuid = uuidv4()
  // 存一份图片名称
  form.imageName = `${uuid}-${uploadFile.name}`

十二、钩子函数的使用

 官方文档中:

        还是有很多钩子的,我曾经都试过,可能是我的使用方式或者是时机不对,有一些钩子没有使用成功。这里还是着重介绍用到的钩子吧:

on-change:这个基本上是必用的钩子,这里能拿到上传的文件或者图片的全部信息去进行校验工作。

        当你上传了文件,成功时就会执行这个方法,也是在这个钩子中执行的“七、上传图片大小 类型个数限制”主要功能。

on-exceed:当超出限制时,执行的钩子函数。

        如果上传的文件超出了你在el-upload中设置的limit,那么会触发这个钩子。正好可以利用这个钩子执行替换功能。(官网上你可以看看el-upload的示例:“覆盖前一个文件”,用的就是这个钩子)详细的替换功能可以再回到“四、钩子函数的使用

十三、手动调用图片本地上传入口

// 手动调取图片本地上传入口
function onUploadImgLocal(row:any) {
  console.log('importBillExcel', row)
  const input = document.createElement('input')
  input.type = 'file'
  input.accept = '.jpeg, .png,  .jpg' // 限制选择的文件类型为 .jpg, .png,  .jpg
  input.style.display = 'none'
  document.body.appendChild(input)
  input.click()
  input.onchange = (e:any) => {
    const file = e.target.files[0] // 获取文件对象
    console.log('eeeeee', e, file)
    handleExceed([file])
  }
}

TODO:这一块之后我再补充一下技术盲区(在我的另一篇博文中)。

十四、新增中没有上传图片时,详情中el-image使用占位符给空状态图片站位

 详情页面,没有上传图片的时候的占位符

        <!-- 安装照片 -->
        <el-image
          v-if="item.type === 'img'"
          style="width: 120px; height: 120px;"
          :src="imgUrl"
          :zoom-rate="1.2"
          :max-scale="7"
          :min-scale="0.2"
          :preview-src-list="[imgUrl]"
          fit="cover"
        >
          <!-- 没有上传图片或者报错时的占位符 -->
          <template #error>
            <div class="image-slot">
              <div style="width: 120px; height: 120px;background: #efefef;">
                <div style="padding-top: 40px;margin-left: 15px;">
                  暂未上传照片
                </div>
              </div>
            </div>
          </template>
        </el-image>

十五、需要注意的小点

(1)on-change和on-exceed中的形参不同,前者是file,后者是[file]
(2)vue2和vue3的饿了吗UI可能有一些写法不同,需要注意
(3)handleStart指令其实是会触发on-change钩子的,所以在on-exceed去校验这一步应该还是可以优化的
(4)image-viewer 的使用
(5)变量的更新需要注意
    const imgList = ref<any>([]) // 图片列表
    const urlList = ref<UploadUserFile[]>([]) // 放大查看列表
    const imgREF = ref<UploadInstance>()   //方便拿el-upload的实例

(6)业务上这次是只能上传一张照片,如果是多个照片的情况该当如何处理?需要考虑什么?

        

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

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

相关文章

Swing中如何实现快捷键绑定和修改

在许许多多市面上常见的桌面软件中, 可以使用快捷键操作&#xff0c; 比如像微信一样,使用AltA 可以打开截图窗口&#xff0c;如果不习惯于AltA按键时&#xff0c;还可以打开设置去修改。 如果在swing中也想实现一个快捷键绑定和修改的操作&#xff0c;那么应该如何操作&#…

《计算机操作系统》(第4版)第8章 磁盘存储器的管理 复习笔记

第8章 磁盘存储器的管理 一 、外存的组织方式 1. 连续组织方式(连续分配方式) (1)概述 ①定义 连续组织方式要求为每一个文件分配一组相邻接的盘块。磁盘空间的联系组织方式如图8-1所示。 ②记录方法 在目录项的“文件物理地址”字段中记录该文件第一个记录所在的盘块号和文件…

【Docker深入浅出】Docker引擎架构介绍

文章目录 一. docker引擎介绍1. Docker daemon&#xff1a;实现Docker API&#xff0c;通过API管理容器2. containerd&#xff1a;负责容器的生命周期3. runc&#xff1a;用于创建和启动容器 二. 启动容器的过程1. 启动过程2. docker daemon的维护不会影响到运行中的容器3. shi…

依靠 VPN 生存——探索 VPN 后利用技术

执行摘要 在这篇博文中,Akamai 研究人员强调了被忽视的 VPN 后利用威胁;也就是说,我们讨论了威胁行为者在入侵 VPN 服务器后可以用来进一步升级入侵的技术。 我们的发现包括影响 Ivanti Connect Secure 和 FortiGate VPN 的几个漏洞。 除了漏洞之外,我们还详细介绍了一组…

C语言试题(含答案解析)

单选 1.下面C程序的运行结果为&#xff08;&#xff09; int main(void) {printf("%d", B < A);return 0; }A.编译错误 B.1 C.0 D.运行错误 A’的ascii码值为65&#xff0c;‘B’的ascii码值为66&#xff0c;‘B’<‘A’是不成立的&#xff0c;返回0&#xf…

spring学习(1)

目录 一、是什么 二、IOC思想 2.1 IOC创建对象的方式 三、Spring的配置 3.1 别名 3.2 Bean的配置 3.3 import 四、DI依赖注入 4.1 构造器注入 4.2 Set方式注入【重点】 4.3 拓展方式注入 五、Bean的自动装配 5.1 byName自动装配 5.2 byType自动装配 5.3 注解实现…

Vue小知识大杂烩

一、Vue组件的三大部分&#xff1a;template、Script、Style template --> 组件的模板结构 写html的地方 注意&#xff1a;<template> 是 vue 提供的容器标签&#xff0c;只起到包裹性质的作用&#xff0c;它不会被渲染为真正的 DOM 元素。 script -> 组件的…

超声波清洗机什么牌子值得入手? 清洁力好的超声波清洗机推荐

对于眼镜佩戴人士而言&#xff0c;超声波清洗机无疑是清洁神器&#xff01;它凭借高频振动技术&#xff0c;能深入眼镜的每一细微处及手洗难以触及的缝隙&#xff0c;有效清除顽固污渍&#xff0c;不仅大幅提高清洁效率&#xff0c;而且清洁质量远胜传统方法。随着超声波清洗机…

Linux下快速搭建七日杀官方私人服务器教程

今天给大家分享一下七日杀的个人开服教程&#xff0c;本教程基于Linux系统开发&#xff0c;推荐有一定基础的小伙伴尝试&#xff01;如果你没有Linux的基础但实在想开的小伙伴可以根据以下教程一步步进行操作&#xff0c;后续这边也会上架对应视频操作 架设前准备&#xff1a; …

Redis篇三:在Ubuntu下安装Redis

文章目录 1. 安装Redis2. 更改Redis的IP3. 使用redis自带的客户端来连接服务器4. Redis的客户端介绍 1. 安装Redis sudo apt install redis2. 更改Redis的IP 刚安装的Redis的ip是一个本地环回的ip&#xff0c;也就是只能由当前主机上的客户端进行访问&#xff0c;跨主机就访问…

IO进程线程 0823作业

作业 创建子父进程&#xff0c;子进程将1.txt内容拷贝到2.txt中&#xff0c;父进程将3.txt内容拷贝到4.txt中。 #include <myhead.h> int main(int argc, const char *argv[]) {pid_t ID;ID fork();if(ID > 0){int fd1;fd1 open("./3.txt",O_RDONLY);if(…

js 键盘监听 组合键

今天分享如何快速实现js快捷键监听 所需环境&#xff1a; 浏览器js 实现目标 mac/win兼容&#xff0c;一套代码&#xff0c;多个平台支持快捷键监听/单按键监听事件是否冒泡可设置使用方式简单快速挂载与卸载4行代码实现组合键监听 代码原理 把键盘监听事件挂载在documen…

c#-DataGridView控件实现分页

有时候我们需要进行分页显示&#xff0c;第一方面是在大数据量下可以降低卡顿&#xff0c;另一方面也是方便查找。 首先划重点&#xff0c;如果卡顿&#xff0c;不要用单元格填充的方式去刷新&#xff0c;用绑定数据源的方式比较高效&#xff01; 下面重点讲如何使用数据源绑定…

正式收官!阿里云携手优酷,用AI重塑影视IP创新边界

影视行业的新一轮创作风潮&#xff0c;将由AI掀起。 GPT和Sora等先进AI模型的出现&#xff0c;带动影视行业进入一场前所未有的创意变革。当前&#xff0c;在角色创作、脚本生成、营销策略等方面&#xff0c;AI已经展现了强大的潜力。而作为影视创作的“灵魂”&#xff0c;影视…

重新审视 ChatGPT 和 Elasticsearch:RAG 真正将应用程序紧密结合在一起

作者&#xff1a;来自 Elastic Jeff Vestal 关注博客 ChatGPT 和 Elasticsearch&#xff1a;OpenAI 遇到私人数据。 在此博客中&#xff0c;你将了解如何&#xff1a; 创建 Elasticsearch Serverless 项目创建推理端点以使用 ELSER 生成嵌入使用语义文本字段进行自动分块并调…

SpringBoot如何进行全局异常处理?

1.为什么需要全局异常处理&#xff1f; 在日常开发中&#xff0c;为了不抛出异常堆栈信息给前端页面&#xff0c;每次编写Controller层代码都要尽可能的catch住所有service层、dao层等异常&#xff0c;代码耦合性较高&#xff0c;且不美观&#xff0c;不利于后期维护。 应用场…

基于java的少儿编程网上报名系统+vue

TOC ssm006基于java的少儿编程网上报名系统vue 研究背景 近年来&#xff0c;随着网络技术的不断发展&#xff0c;越来越多人在网站查询各种信息&#xff0c;少儿编程网上报名系统对用户和管理员都有很大帮助&#xff0c;少儿编程网上报名系统通过和数据库管理系软件协作来实…

基于STM32开发的智能安防报警系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化传感器数据采集与处理报警控制与通知Wi-Fi通信与远程监控应用场景 家庭安防管理商铺和办公室的智能安防常见问题及解决方案 常见问题解决方案结论 1. 引言 随着智能家居和物联网技…

拟合的置信区间

目标图: 图片来源:Fig. 4e from Arwani, Ruth Theresia, et al. "Stretchable ionic–electronic bilayer hydrogel electronics enable in situ detection of solid-state epidermal biomarkers." Nature Materials (2024): 1-8. 1. 数据输入 假设原始数据如下:…

书生大模型实战营第三期基础岛第二课——8G 显存玩转书生大模型 Demo

8G 显存玩转书生大模型 Demo 基础任务进阶作业一&#xff1a;进阶作业二&#xff1a; 基础任务 使用 Cli Demo 完成 InternLM2-Chat-1.8B 模型的部署&#xff0c;并生成 300 字小故事&#xff0c;记录复现过程并截图。 创建conda环境 # 创建环境 conda create -n demo pytho…