uniapp在H5端实现PDF和视频的上传、预览、下载
上传
上传页面
<u-form-item :label="(form.ququ3 == 1 ? '参培' : form.ququ3 == 2 ? '授课' : '') + '证明材料'" prop="ququ6" required><u-button @click="upload" slot="right" type="primary" icon="arrow-upward" text="上传文件" size="small"></u-button></u-form-item><view class="red">只能上传视频和pdf文件(支持.pdf, .mp4, .avi, .ts)</view><view v-for="(item, i) in form.ququ6" :key="i" class="mb-20 flex "><view class="flex_l" @click="preview(item)"><image style="width: 46rpx;height: 46rpx;":src="item.split('.')[item.split('.').length - 1] == 'pdf' ? '/static/pdf.png' : '/static/video.png'"></image><view class="blue ml-20 u-line-1 flex-1 over-hidden">{{ item.split('-')[item.split('-').length - 1] }}</view></view><!-- <view class="blue" @click="preview(item)">预览</view> --></view>import { uploadFile } from '../../common/common'
upload() {uploadFile(6).then(res => {console.log(2222, res)this.form.ququ6 = this.form.ququ6.concat(res)})
},
上传方法
/*** 上传视频和pdf文件* @param {*} count 个数* @returns arr-- 最终结果 ['img','img']*/
export let uploadFile = (count = 1) => {return new Promise((resolve, reject) => {uni.chooseFile({count: count,extension: ['.pdf', '.mp4', '.avi', '.ts'],success: function (res) {uni.showLoading({title: '上传中'})let imgarr = res.tempFilePathslet arr = []imgarr.forEach(item => {uni.uploadFile({url: '/prod-api' + '/file/upload',filePath: item,name: 'file',header: {Authorization: uni.getStorageSync('token') || ''},success: (res) => {console.log(JSON.parse(res.data))arr.push(JSON.parse(res.data).data.url)if (arr.length == imgarr.length) {uni.hideLoading()let arr1 = arr.filter(item => ['pdf', 'mp4', 'avi', 'ts'].includes(item.split('.')[item.split('.').length - 1]))if (arr1.length != arr.length) {uni.showToast({title: '只能上传视频和pdf文件',icon: 'none'})}resolve(arr1)}},fail: () => {uni.showToast({title: '上传失败',icon: 'none'})}});})}});})
}
整个页面静态
<template><view class="ptb-20 plr-30 bg min100"><view class="bg-white radius-20 pd-30"><u--form labelPosition="left" :model="form" :rules="rules" ref="uForm" labelWidth="100"><u-form-item label="培训主题名" prop="ququ1" required><u--input v-model="form.ququ1" disabledColor="#ffffff" placeholder="请输入主题名" border="none"></u--input></u-form-item><u-form-item label="培训分类" prop="ququ2" required @click="showPop(1)"><u--input class="disabled" v-model="form.ququ2" disabled disabledColor="#ffffff" placeholder="请选择培训分类"border="none"></u--input><u-icon slot="right" name="arrow-right"></u-icon></u-form-item><u-form-item label="本人所属类别" prop="ququ3" required><u-radio-group v-model="form.ququ3" placement="row"><u-radio class="mr-20" label="参培人" name='1'></u-radio><u-radio label="授课人" name='2'></u-radio></u-radio-group></u-form-item><u-form-item label="参与地点" prop="ququ4"><u--input v-model="form.ququ4" placeholder="请输入参与地点" border="none"></u--input></u-form-item><u-form-item label="起止日期" prop="ququ5" @click="showPop(2)" required><u--input class="disabled" v-model="form.ququ5" disabled disabledColor="#ffffff" placeholder="请选择起止日期"border="none"></u--input><u-icon slot="right" name="arrow-right"></u-icon></u-form-item><u-form-item :label="(form.ququ3 == 1 ? '参培' : form.ququ3 == 2 ? '授课' : '') + '证明材料'" prop="ququ6" required><u-button @click="upload" slot="right" type="primary" icon="arrow-upward" text="上传文件" size="small"></u-button></u-form-item><view class="red">只能上传视频和pdf文件(支持.pdf, .mp4, .avi, .ts)</view><view v-for="(item, i) in form.ququ6" :key="i" class="mb-20 flex "><view class="flex_l" @click="preview(item)"><image style="width: 46rpx;height: 46rpx;":src="item.split('.')[item.split('.').length - 1] == 'pdf' ? '/static/pdf.png' : '/static/video.png'"></image><view class="blue ml-20 u-line-1 flex-1 over-hidden">{{ item.split('-')[item.split('-').length - 1] }}</view></view><!-- <view class="blue" @click="preview(item)">预览</view> --></view><u-form-item label="备注" prop="ququ7"><u--textarea v-model="form.ququ7" placeholder="请输入备注" maxlength="150" count autoHeightborder="none"></u--textarea></u-form-item></u--form><!-- 下拉选择框 --><u-action-sheet :show="show" :actions="actions" title="请选择" @close="close" @select="confirmSelect"></u-action-sheet><!-- 日历选择范围 --><u-calendar :maxDate="maxDate" :minDate="minDate" monthNum="10" :show="showDate" mode="range" @confirm="confirmDate"@close="close"></u-calendar><view class="flex mt-60"><u-button @click="reset">重置</u-button><u-button type="primary" plain class="mlr-20" @click="save">保存草稿</u-button><u-button type="primary" @click="submit">提交审核</u-button></view></view></view>
</template><script>
import { uploadFile } from '../../common/common'
const d = new Date()
const year = d.getFullYear()
let month = d.getMonth() + 1
month = month < 10 ? `0${month}` : month
const date = d.getDate()
export default {data() {return {show: false,type: null,actions: [],showDate: false, // 日期选择maxDate: `${year}-${month + 1}-${date}`,minDate: `${year}-${month - 8}-${date}`,form: {ququ1: '',ququ2: '',ququ2Id: '',ququ3: '',ququ4: '',ququ5: '',ququ6: [],ququ7: '',},rules: {'ququ1': {required: true,message: '请输入主题名',trigger: ['blur']},'ququ2': {required: true,message: '请选择培训分类',trigger: ['blur', 'change']},'ququ3': {required: true,message: '请选择所属类别',trigger: ['blur', 'change']},'ququ5': {required: true,message: '请选择起止日期',trigger: ['blur', 'change']},},};},onLoad() {},methods: {showPop(type) {this.type = typeif (type == 1) {this.show = truethis.actions = [{name: '培训分类1',id: 1},{name: '培训分类2',id: 2},]} else {this.showDate = true}},close() {this.show = falsethis.showDate = falsethis.type = null},confirmSelect(e) {this.form['ququ2'] = e.namethis.form['ququ2Id'] = e.idthis.$refs.uForm.validateField('ququ2')},confirmDate(e) {console.log(e);this.form['ququ5'] = e[0] + '~' + e[e.length - 1]this.showDate = false},upload() {uploadFile(6).then(res => {console.log(2222, res)this.form.ququ6 = this.form.ququ6.concat(res)})},preview(item) {if (item.split('.')[item.split('.').length - 1] == 'pdf') {uni.navigateTo({url: '/pages/course/pdf?url=' + item})} else {// uni.navigateTo({// url: '/pages/course/video?url=' + item// })window.open(item)}},submit() {this.$refs.uForm.validate().then(res => {if (!this.form.ququ6.length) {uni.$u.toast('请上传证明材料')return}uni.$u.toast('校验通过')this.$http('/system/user/profile', {avatar: this.form}, "post").then(res => {uni.showToast({title: '提交成功',})})}).catch(errors => {uni.$u.toast('校验失败')})},save() {this.$http('/system/user/profile', {avatar: this.form}, "post").then(res => {uni.showToast({title: '保存成功',})})},reset() {this.$refs.uForm.resetFields()},},};
</script><style scoped lang="scss"></style>
预览和下载
预览页面 PDF预览详见
<view class="title-left bold mtb-20">附件记录</view><view v-for="(item, i) in form.ququ6" :key="i" class="mb-20 ml-30 flex"><view class="flex_l" @click="preview(item)"><image style="width: 46rpx;height: 46rpx;":src="item.split('.')[item.split('.').length - 1] == 'pdf' ? '/static/pdf.png' : '/static/video.png'"></image><view class="blue ml-20 u-line-1 flex-1 over-hidden">{{ item.split('-')[item.split('-').length - 1] }}</view></view><view class="green" @click="downLoad(item)">下载</view></view>data() {return {form: {ququ6: ["https://cscec83-learnplatform.oss-cn-shanghai.aliyuncs.com/test/2023-11-27/6a12b9ca-3ae9-435b-b023-0f9c119afad3-1.mp4", "https://cscec83-learnplatform.oss-cn-shanghai.aliyuncs.com/test/2023-11-27/53aa1f60-0735-4203-86b2-c2b8b019e8d9-我的哈哈.pdf"]}}},preview(item) {if (item.split('.')[item.split('.').length - 1] == 'pdf') {uni.navigateTo({url: '/pages/course/pdf?url=' + item})} else {// uni.navigateTo({// url: '/pages/course/video?url=' + item// })window.open(item)}},downLoad(url) {if (url.split('.')[url.split('.').length - 1] == 'pdf') {window.open(url)} else {let xhr = new XMLHttpRequest();xhr.open('GET', url, true);xhr.responseType = 'blob'; // 返回类型blobxhr.onload = function () {if (xhr.readyState === 4 && xhr.status === 200) {let blob = this.response;// 转换一个blob链接let u = window.URL.createObjectURL(new Blob([blob]));let a = document.createElement('a');a.download = url.split('-')[url.split('-').length - 1]; //下载后保存的名称a.href = u;a.style.display = 'none';document.body.appendChild(a);a.click();a.remove();uni.hideLoading();}};xhr.send()}},
详情页面静态
<template><view class="mlr-30 pt-20"><view class="title-left bold mb-20">培训详情</view><u-cell-group :border="false"><u-cell :border="false" title="培训主题名" :value="userInfo.nickName"></u-cell><u-cell :border="false" title="培训分类" :value="userInfo.sex"></u-cell><u-cell :border="false" title="本人所属类别" :value="userInfo.sex == 1 ? '参培人' : '授课人'"></u-cell><u-cell :border="false" title="起止日期" :value="userInfo.phonenumber"></u-cell><u-cell :border="false" title="参与地点" :value="userInfo.nickName"></u-cell><u-cell :border="false" title="提交时间" :value="userInfo.nickName"></u-cell></u-cell-group><view class="title-left bold mtb-20">附件记录</view><view v-for="(item, i) in form.ququ6" :key="i" class="mb-20 ml-30 flex"><view class="flex_l" @click="preview(item)"><image style="width: 46rpx;height: 46rpx;":src="item.split('.')[item.split('.').length - 1] == 'pdf' ? '/static/pdf.png' : '/static/video.png'"></image><view class="blue ml-20 u-line-1 flex-1 over-hidden">{{ item.split('-')[item.split('-').length - 1] }}</view></view><view class="green" @click="downLoad(item)">下载</view></view><view class="title-left bold mb-20">审批详情</view><u-cell-group :border="false"><u-cell :border="false" title="审批状态" :value="userInfo.nickName"></u-cell><u-cell :border="false" title="当前审批人" :value="userInfo.sex"></u-cell></u-cell-group><view class="flex mt-60"><u-button @click="back">返回首页</u-button><u-button type="primary" plain class="mlr-20" @click="edit">修改</u-button><u-button type="primary" @click="revoke">撤回流程</u-button></view></view>
</template><script>
import {mapState
} from 'vuex'
export default {data() {return {form: {ququ6: ["https://cscec83-learnplatform.oss-cn-shanghai.aliyuncs.com/test/2023-11-27/6a12b9ca-3ae9-435b-b023-0f9c119afad3-1.mp4", "https://cscec83-learnplatform.oss-cn-shanghai.aliyuncs.com/test/2023-11-27/53aa1f60-0735-4203-86b2-c2b8b019e8d9-我的哈哈.pdf"]}}},computed: {...mapState(['userInfo']),},onLoad() {// 刷新个人信息this.$store.dispatch('updateUserInfo')this.img = this.userInfo.avatar ? this.userInfo.avatar : '/static/user-default.png'},methods: {preview(item) {if (item.split('.')[item.split('.').length - 1] == 'pdf') {uni.navigateTo({url: '/pages/course/pdf?url=' + item})} else {// uni.navigateTo({// url: '/pages/course/video?url=' + item// })window.open(item)}},downLoad(url) {if (url.split('.')[url.split('.').length - 1] == 'pdf') {window.open(url)} else {let xhr = new XMLHttpRequest();xhr.open('GET', url, true);xhr.responseType = 'blob'; // 返回类型blobxhr.onload = function () {if (xhr.readyState === 4 && xhr.status === 200) {let blob = this.response;// 转换一个blob链接let u = window.URL.createObjectURL(new Blob([blob]));let a = document.createElement('a');a.download = url.split('-')[url.split('-').length - 1]; //下载后保存的名称a.href = u;a.style.display = 'none';document.body.appendChild(a);a.click();a.remove();uni.hideLoading();}};xhr.send()}},revoke() {this.$http('/system/user/profile', {avatar: 1}, "put").then(res => {uni.showToast({title: '撤回成功',})})},edit() {uni.navigateTo({url: './add?id=1'})},back() {uni.navigateBack()}}
}
</script><style lang="scss" scoped>
::v-deep .u-cell__body {padding: 5px 15px !important;
}
</style>
完整的上传视频、上传pdf、上传图片 方法封装(需要传递name、size、时长)
/*** 上传图片* count-- 可选张数* arr-- 最终结果 ['img','img']*/
export let upload = (count = 1) => {console.log(count);return new Promise((resolve, reject) => {uni.chooseImage({count: count,sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有success: function (res) {uni.showLoading({title: '上传中'})let imgarr = res.tempFilePathslet arr = []imgarr.forEach(item => {uni.uploadFile({url: '/prod-api' + '/file/upload',filePath: item,name: 'file',header: {Authorization: uni.getStorageSync('token') || ''},success: (res) => {console.log(JSON.parse(res.data))uni.hideLoading()arr.push(JSON.parse(res.data).data.url)if (arr.length == imgarr.length) {resolve(arr)}},fail: () => {uni.showToast({title: '上传失败',icon: 'none'})}});})}});})
}
/*** 上传pdf文件* @param {*} count 个数* @returns arr-- 最终结果 ['img','img']*/
export let uploadFile = (count = 1) => {return new Promise((resolve, reject) => {uni.chooseFile({count: count,extension: ['.pdf'],success: function (res) {console.log(888, res)uni.showLoading({title: '上传中'})let imgarr = res.tempFileslet arr = []imgarr.forEach(item => {uni.uploadFile({url: '/prod-api' + '/file/appUpload', //接口地址filePath: item.path, // 上传文件参数值name: 'file', // 上传文件参数名formData: { // 额外参数fileName: item.name,size: (item.size / 1024 / 1024).toFixed(2),type: 'pdf',},header: { //请求头Authorization: uni.getStorageSync('token') || ''},success: (res) => {arr.push(JSON.parse(res.data).data)if (arr.length == imgarr.length) {uni.hideLoading()let arr1 = arr.filter(item => 'pdf' == item.fileName.split('.')[item.fileName.split('.').length - 1])if (arr1.length != arr.length) {uni.showToast({title: '只能上传pdf文件',icon: 'none'})}resolve(arr1)}},fail: () => {uni.showToast({title: '上传失败',icon: 'none'})}});})}});})
}
/** 上传视频* arr-- 最终结果 [{img1:'全路径',img2:'半路径'},{img1:'全路径',img2:'半路径'}]*/
export let uploadVideo = () => {return new Promise((resolve, reject) => {uni.chooseVideo({count: 1,success: function (res) {uni.showLoading({title: '上传中'})console.log(111111111111, res)uni.uploadFile({url: '/prod-api' + '/file/appUpload', //接口地址filePath: res.tempFilePath, // 上传文件参数值name: 'file', // 上传文件参数名formData: { // 额外参数,formData传参fileName: res.name,size: (res.size / 1024 / 1024).toFixed(2),duration: res.duration,type: 'video',},header: { //请求头Authorization: uni.getStorageSync('token') || ''},success: (res) => {uni.hideLoading()if (JSON.parse(res.data).code == '200') {resolve(JSON.parse(res.data).data)} else {uni.showToast({title: JSON.parse(res.data).msg,icon: 'none'})}},fail: () => {uni.showToast({title: '上传失败,请重试',icon: 'none'})}});}});})
}
相关文章:

uniapp在H5端实现PDF和视频的上传、预览、下载
上传 上传页面 <u-form-item :label"(form.ququ3 1 ? 参培 : form.ququ3 2 ? 授课 : ) 证明材料" prop"ququ6" required><u-button click"upload" slot"right" type"primary" icon"arrow-upward" t…...
Kafka报错under-replicated partitions
1 under-replicated partitions异常原因 Kafka报错under replicated partitions意味着某些分区的副本数量未达到预期的复制因子。 主要有两种原因, Broker故障 如果某个Kafka Broker发生故障,导致其中一些分区的副本不再可用,那么这些分区就…...
【Python基础】字符集与字符编码
先行了解的知识: 1. 编码和解码 计算机内存储的信息都是二进制表示。 我们看到的英文,数字,汉字等在计算机内如何表示,那就需要编码 计算机内存储的信息需要解析出来,那就是解码 2.字符集与分类 什么是字符集…...
C# AES-128-CBC 加密
一、加密 /// <summary>/// 加密/// </summary>public static string AesEncrypt(string toEncrypt){byte[] toEncryptArray UTF8Encoding.UTF8.GetBytes(toEncrypt);byte[] keyArray UTF8Encoding.UTF8.GetBytes(Key);//注意编码格式(utf8编码 UTF8Encoding)byt…...

【惊喜福利】Docker容器化部署nextcloud网盘,享受高速稳定的文件共享体验!
Docker搭建nextcloud网盘 NextCloud是一款开源网络硬盘系统,它是一个私有、安全且功能完整的文件同步与共享解决方案,可以搭建一套属于自己或团队的云同步网盘。NextCloud的客户端覆盖了各种平台,包括Windows、Mac、Android、iOS、Linux等&am…...

WPF实战项目十九(客户端):修改RestSharp的引用
修改HttpRestClient,更新RestSharp到110.2.0,因为106版本和110版本的代码不一样,所以需要修改下代码 using Newtonsoft.Json; using RestSharp; using System; using System.Threading.Tasks; using WPFProjectShared;namespace WPFProject.S…...

kobs-ng 烧写nand中的uboot
如何获取kobs-ng 我是使用buildroot自动编译的imx-kobs,生成了kobs-ng可执行文件。 使用 kobs-ng 烧写 u-boot 1. flash_erase /dev/mtd0 0 0 //擦除uboot所在分区 2. 挂载 debugfs mount -t debugfs debugfs /sys/kernel/debug 如果不挂载为报以下错误&#x…...

【Java】扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问该用户是否要删除该文件
题目如下 扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问该用户是否要删除该文件 本题是关于文件I/O知识中对文件系统操作的应用,解答的完整代码如下(需要的uu自取)⬇️ 在完整…...

PyQt基础_008_ 按钮类控件QSpinbox
基本操作 import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *class spindemo(QWidget):def __init__(self, parentNone):super(spindemo, self).__init__(parent)self.setWindowTitle("SpinBox 例子")self.resize(300,…...

3D点云目标检测:VoxelNex解读
VoxelNext 通用检测器 vs VoxelNext一、3D稀疏卷积模块1.1、额外的两次下采样消融实验结果代码 1.2、稀疏体素删减消融实验:代码 二、稀疏体素高度压缩代码 三、稀疏预测head 通用检测器 vs VoxelNext 一、3D稀疏卷积模块 1.1、额外的两次下采样 使用通用的3D spa…...

opencv-利用DeepLabV3+模型进行图像分割去除输入图像的背景
分离图像中的人物和背景通常需要一些先进的图像分割技术。GrabCut是一种常见的方法,但是对于更复杂的场景,可能需要使用深度学习模型。以下是使用深度学习模型(如人像分割模型)的示例代码: #导入相关的库 import cv2 …...

中国版的 GPTs:InsCode AI 生成应用
前言 在上一篇文章 《InsCode:这可能是下一代应用开发平台?》中,我们介绍了一个新的应用开发平台 InsCode,它是基于云原生开发环境 云 IDE AI 辅助编程的一站式在线开发平台。 最近,InsCode 又推出了另一种全新的开…...
MySQL 学习笔记(刷题篇)
SQL进阶挑战 聚合分组查询 SQL123 select tag, difficulty, round((sum(score) - max(score) - min(score) ) / (count(score) - 2) ,1) as clip_avg_score from examination_info as ei, exam_record as er where ei.exam_id er.exam_id and ei.tag SQL and ei.diffi…...

windows系统如何配置yarn环境变量
启动前端项目,突然遇到报错: 原因在于没有安装yarn,或没有配置环境变量。 全局安装 yarn 可在vsCode中输入,也可在命令行输入(winR,输入cmd) npm install -g yarn添加环境变量 找到yarn的安…...

视频中的文字水印怎么去除?这三招学会轻松去视频水印
短视频与我们生活,工作息息相关,日常在在刷短视频时,下载保存后发现带有文字logo水印,如果直接拿来进行二次创作,不仅影响观看效果,平台流量还会受限制。怎么去除视频中的文字水印就成为了当下热门话题之一…...

Java项目学生管理系统二查询所有
学生管理 近年来,Java作为一门广泛应用于后端开发的编程语言,具备了广泛的应用领域和丰富的开发资源。在前几天的博客中,我们探讨了如何搭建前后端环境,为接下来的开发工作打下了坚实的基础。今天,我们将进一步扩展我…...
27.Spring如何避免在并发下获取不完整的Bean?
Spring如何避免在并发下获取不完整的Bean? 1、为什么获取不到完整的Bean? 我们知道, 如果spring容器已经加载完了, 那么肯定所有bean都是完整的了, 但如果, spring没有加载完, 在加载的过程中, 构建bean就有可能出现不完整bean的情况 2、如何解决读取到不完整bean的问题. …...

浅析SD-WAN企业组网部署中简化网络运维的关键技术
网络已经成为现代企业不可或缺的基础设施,它为企业提供了连接全球的桥梁。随着全球化和数字化转型的加速推进,企业面临着越来越多的网络挑战和压力。传统的网络组网方式往往无法满足企业规模扩大、分支机构增多、上云服务等需求,导致网络性能…...

【Rust】快速教程——自定义类型、数字转枚举、Cargo运行
前言 超过一定的年龄之后,所谓人生,无非是一个不断丧失的过程而已。宝贵的东西,会像梳子豁了齿一样从手中滑落下去。你所爱的人会一个接着一个,从身旁悄然消逝。——《1Q84》 \;\\\;\\\; 目录 前言自定义类型数字转枚举Cargo.tom…...
python 实现 AIGC 大语言模型中的概率论:生日相同问题的代码场景模拟
对深度学习本质而言,它实际上就是应用复杂的数学模型对输入数据进行建模,最后使用训练好的模型来预测或生成新的数据,因此深度学习的技术本质其实就是数学。随着大语言模型的发展,人工智能的数学本质被进一步封装,从业…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...