我用Tauri开发的待办效率工具开源了!
开源仓库地址 gitee
Git仓库地址:https://gitee.com/zhanhongzhu/zhanhongzhu.git
应用地址
windows应用地址下载 https://kestrel-task.cn
具体内容
也可以看🎉使用Tauri+vite+koa2+mysql开发了一款待办效率应用 这篇文章。
💻技术栈
- Tauri: Tauri是一个用于构建现代桌面应用程序的工具,结合了Rust、Vue.js和Web技术,提供了强大的跨平台能力。
- Vue3: Vue3是流行的JavaScript框架Vue.js的最新版本,具有更好的性能、更好的TypeScript支持和更多的特性。
- Vite5: Vite是一个现代化的构建工具,Vite5是其最新版本,具有快速的冷启动、热模块替换和原生ES模块支持。
- Koa2: Koa2是一个基于Node.js的轻量级Web框架,使用异步函数处理中间件,提供了简洁而强大的Web开发体验。
- MySQL: MySQL是一个流行的关系型数据库管理系统,具有高性能、可靠性和广泛的应用领域,适用于各种规模的应用程序。
我的待办
快速添加待办任务,快速查看任务进度,摘要等。新增标签,分类,更好管理待办任务。通过标签、分类筛选待办任务,方便快捷。
OKR目标管理
我的想法是通过OKR管理系列的任务,这样每完成一个小任务,就可以关闭一个小任务,直观又方便,等到所有关键的小任务都完成了,整个任务也就完成了。
番茄工作法
主要是一个计时的时钟,可以在专注计时的时候,专注地完成某项任务,快捷方便,使用番茄工作法,选择一个待完成的任务,将番茄时间设为25分钟,也可以选择其他的区间,专注工作,中途不允许做任何与该任务无关的事。时刻保持专注。
日历视图
打开日历界面,通过视图的形式查看公历或农历日历下每个日期的待办提醒或任务事项。也可以在日历视图,添加任务。
MEMO快速记录
为了更好地帮你捕捉想法与灵感,提供了快速记录的输入框。专注记录想法,无需思考标题和排版。控制记录长度,降低记录压力,快速捕捉。
统计功能
展示了每天的待办数,以及每天新增的待办数量。
展示功能点
打包发布版本
脚本命令
"scripts": {"dev": "vite","build": "vite build","preview": "vite preview","tauri": "tauri","pub": "cd build && node ./updateVersion.js && pnpm tauri build && node ./publish.js"}
npm run pub
更新版本号以及更新publicKey
//build/publish.js
import fs from 'fs'
// 读取 tauri.conf.json
const tauriConf = JSON.parse(fs.readFileSync('../src-tauri/tauri.conf.json', 'utf8'));
let newVersion = tauriConf.package.version; //更新的版本号// 读取 update.json
let updateJson = JSON.parse(fs.readFileSync('update.json', 'utf8'));
// 更新 update.json version
updateJson.version = newVersion;//获取版本更新的内容
//签名、版本路径、发版日期
const signature = fs.readFileSync(`../src-tauri/target/release/bundle/msi/kestrel-task_${newVersion}_x64_zh-CN.msi.zip.sig`, 'utf8');
updateJson.platforms['windows-x86_64'].signature = signature;
updateJson.platforms['windows-x86_64'].url = `https://kestrel-task.cn/kestrel-task_${newVersion}_x64_zh-CN.msi.zip`
updateJson.pub_date = new Date();
fs.writeFileSync('update.json', JSON.stringify(updateJson, null, 2));
版本json信息
//build/update.json{"version": "1.0.8","notes": "kestrel-task","pub_date": "2024-03-23T04:23:39.799Z","platforms": {"windows-x86_64": {"signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVSNVRCUit5Zjc1Y3JLV085djl6eTMza2NqMXFIV0paNkl2ckgrTGZTRm9wcEJwcUlkaTBhM2hvN3pSVkRUZXlTZ2NSejJremg2Vklja041VkZmdGlZZ0hxTGVVM2xlL3dFPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNzExMTY3ODE5CWZpbGU6a2VzdHJlbC10YXNrXzEuMC44X3g2NF96aC1DTi5tc2kuemlwCldSWVdwb0dwRU1aQUJ2ckFra2FTMjBkcnZtL0FWU3grd3MzeHZVTDhWRFFFUC9QWkpzdUNvUG9HZXBrVmhWMkoxTkpGc2pkYU5rRHYwcVdHdlk5dkFBPT0K","url": "https://kestrel-task.cn/kestrel-task_1.0.8_x64_zh-CN.msi.zip"}}
}
更新tauri.conf.json版本信息
// build/updateVersion.js
import fs from 'fs' // 读取 tauri.conf.json
const tauriConf = JSON.parse(fs.readFileSync('../src-tauri/tauri.conf.json', 'utf8'));
let version = tauriConf.package.version; //更新的版本号//更新版本号
let versionParts = version.split('.').map(Number);
versionParts[2] += 1;
let newVersion =versionParts.join('.');
// 更新 tauri.conf.json version
tauriConf.package.version = newVersion;
fs.writeFileSync('../src-tauri/tauri.conf.json', JSON.stringify(tauriConf, null, 2));
使用tauri的http模块
此处进行简单的封装,接口请求在控制台无法被查看到。如果觉得不方便,完全可以使用axios库。也是可以的。
import { http } from "@tauri-apps/api";export function request(config) {return new Promise((resolve, reject) => {http.fetch("https://kestrel-task.cn" + config.url, {method: "POST",body: http.Body.json(config.data),headers: {Authorization: token,},}).then((res) => {resolve(res.data.data);}).catch((err) => {reject(err);});});
}
http封装get请求
export function requestGet(config, d) {let url = d ? config.url : "https://kestrel-task.cn" + config.url;return new Promise((resolve, reject) => {http.fetch(url, {method: "get",headers: {Authorization: token,},}).then((res) => {resolve(d ? res.data : res.data.data);}).catch((err) => {reject(err);});});
}
使用封装的request函数
export const login = (data) => {return request({url: "/web/login",method: "post",data,});
};
使用WebviewWindow封装公共的窗口
import { WebviewWindow } from '@tauri-apps/api/window'
import { emit } from '@tauri-apps/api/event'// 创建新窗口
export async function createWin(args) {await emit('win-create', args)
}// 获取窗口
export async function getWin(label) {return await WebviewWindow.getByLabel(label)
}/*** @desc 设置窗口* @param type {string} 'show'|'hide'|'close'|'min'|'max'|'max2min'|'exit'|'relaunch'*/
export async function setWin(type) {await emit('win-' + type)
}// 登录窗口
export async function loginWin() {await createWin({label: 'Login',title: '登录',url: '/login',width: 320,height: 420,resizable: false,alwaysOnTop: true,})
}// ...
/*** @desc 封装新开多窗体*/import {WebviewWindow,appWindow,getAll,getCurrent,
} from "@tauri-apps/api/window";
import { relaunch, exit } from "@tauri-apps/api/process";
import { emit, listen } from "@tauri-apps/api/event";import { setWin } from "./actions.js";// 系统参数配置
export const windowConfig = {label: null, // 窗口唯一labeltitle: "", // 窗口标题url: "", // 路由地址urlwidth: 900, // 窗口宽度height: 640, // 窗口高度minWidth: null, // 窗口最小宽度minHeight: null, // 窗口最小高度x: null, // 窗口相对于屏幕左侧坐标y: null, // 窗口相对于屏幕顶端坐标center: true, // 窗口居中显示resizable: true, // 是否支持缩放maximized: false, // 最大化窗口decorations: true, // 窗口是否无边框及导航条alwaysOnTop: false, // 置顶窗口
};class Windows {constructor() {this.mainWin = null;}// 获取窗口getWin(label) {return WebviewWindow.getByLabel(label);}// 获取全部窗口getAllWin() {return getAll();}// 创建新窗口async createWin(options) {const args = Object.assign({}, windowConfig, options);// 判断窗口是否存在const existWin = getAll().find((w) => w.label == args.label);if (existWin) {if (existWin.label.indexOf("main") == -1) {await existWin?.unminimize();await existWin?.setFocus();return;}await existWin?.close();}// 创建窗口对象let win = new WebviewWindow(args.label, args);// 是否最大化if (args.maximized && args.resizable) {win.maximize();}// 窗口创建完毕/失败win.once("tauri://created", async () => {console.log("window create success!");});win.once("tauri://error", async () => {console.log("window create error!");});}// 开启主进程监听事件async listen() {// 创建新窗体await listen("win-create", (event) => {this.createWin(JSON.parse(event.payload));});// 显示窗体await listen("win-show", async (event) => {if (appWindow.label.indexOf("main") == -1) return;await appWindow.show();await appWindow.unminimize();await appWindow.setFocus();});// 隐藏窗体await listen("win-hide", async (event) => {if (appWindow.label.indexOf("main") == -1) return;await appWindow.hide();});// 退出应用await listen("win-exit", async (event) => {setWin("logout");await exit();});// 重启应用await listen("win-relaunch", async (event) => {await relaunch();});// 主/渲染进程传参await listen("win-setdata", async (event) => {await emit("win-postdata", JSON.parse(event.payload));});}
}export default Windows;
封装Echart组件,便于使用
<template><div ref="MyEcharts" :style="{ height: height, width: width }"></div></template><script>import * as echarts from 'echarts'import T from './echarts-theme-T.js'echarts.registerTheme('T', T)const unwarp = obj => obj && (obj.__v_raw || obj.valueOf() || obj)export default {...echarts,name: 'Charts',props: {// 高度height: { type: String, default: '100%' },// 宽度width: { type: String, default: '100%' },// 是否无数据nodata: { type: Boolean, default: false },// 配置项option: { type: Object, default: () => {} }},data() {return {isActivat: false,myChart: null,MyEcharts:null}},watch: {option: {deep: true,handler(v) {unwarp(this.myChart).setOption(v)}}},computed: {myOptions: function() {return this.option || {}}},activated() {if (!this.isActivat) {this.$nextTick(() => {this.myChart.resize()})}},deactivated() {this.isActivat = false},mounted() {this.isActivat = truethis.$nextTick(() => {this.draw()})},methods: {draw() {const myChart = echarts.init(this.$refs.MyEcharts, 'T')myChart.setOption(this.myOptions)this.myChart = myChartwindow.addEventListener('resize', () => myChart.resize())}}}</script>
echart主题模块
//echarts-theme-T.js
const T = {color: ['#409EFF', '#36CE9E', '#f56e6a', '#626c91', '#edb00d', '#909399'], // 颜色数组grid: { // 网格left: '3%', // 左边距right: '3%', // 右边距bottom: '10', // 下边距top: '40', // 上边距containLabel: true // 包含标签},legend: { // 图例textStyle: { // 文本样式color: '#999' // 颜色},inactiveColor: 'rgba(128,128,128,0.4)' // 不活跃颜色},categoryAxis: { // 类别轴axisLine: { // 轴线show: true, // 显示lineStyle: { // 线条样式color: 'rgba(128,128,128,0.2)', // 颜色width: 1 // 宽度}},axisTick: { // 刻度线show: false, // 不显示lineStyle: { // 线条样式color: '#000' // 颜色}},axisLabel: { // 轴标签color: '#999' // 颜色},splitLine: { // 分隔线show: false, // 不显示lineStyle: { // 线条样式color: ['#eee'] // 颜色}},splitArea: { // 分隔区域show: false, // 不显示areaStyle: { // 区域样式color: ['rgba(255,255,255,0.01)', 'rgba(0,0,0,0.01)'] // 颜色}}},valueAxis: { // 数值轴axisLine: { // 轴线show: false, // 不显示lineStyle: { // 线条样式color: '#999' // 颜色}},splitLine: { // 分隔线show: true, // 显示lineStyle: { // 线条样式color: 'rgba(128,128,128,0.2)' // 颜色}}}
}export default T
封装公共的弹窗组件
<template><el-dialog class="my-dialog" draggable v-bind="$attrs" v-model="modelValue" :modal-append-to-body="modalAppendToBody":append-to-body="appendToBody" :fullscreen="fullscreen" :close-on-click-modal="closeOnClickModal":close-on-press-escape="closeOnPressEscape" :width="comWidth" :top="top" @closed="closed"><template v-slot:title><slot name="title"><span class="my-dialog-title">{{ dialogTitle || ''}}</span></slot></template><div v-loading="loading" class="body-content" :style="{'height':comHeight}"><slot></slot></div><template #footer><div class="dialog-footer" v-if="closeBtn"><el-button type="close" size="small1" @click="closed">关闭</el-button></div></template></el-dialog>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({visible: { type: Boolean, default: false }, // 是否可见loading: { type: Boolean, default: false }, // 是否加载中top: { type: String, default: '20vh' }, // 距离顶部的距离fullscreen: { type: Boolean, default: false }, // 是否全屏size: { type: String, default: 'big' }, // 大小width: { type: [Number, String], default: 0 }, // 宽度height: { type: [Number, String], default: '55vh' }, // 宽度dialogTitle: { type: String, default: '' }, // 弹出框标题modalAppendToBody: { type: Boolean, default: false }, // 是否将弹出框插入到body中appendToBody: { type: Boolean, default: false }, // 是否将内容插入到body中closeOnClickModal: { type: Boolean, default: false }, // 是否在点击模态框时关闭closeOnPressEscape: { type: Boolean, default: false }, // 是否在按下ESC键时关闭dblclickDisabled: { type: Boolean, default: false }, // 是否禁用双击放大closeBtn: { type: Boolean, default: false }, // 关闭按钮},['modelValue']
)const comWidth = computed(() => {if (props.size === 'small') {return props.width || '30%'} else if (props.size === 'middle') {return props.width || '40%'} else if (props.size === 'big') {return props.width || '60%'}return props.width || '40%'
})const comHeight = computed(() => {return props.height || '55vh'
})const emit = defineEmits(['update:modelValue','closed'])
const closed = () => {emit('update:modelValue')emit('closed',false)
}
</script>
封装ResizeObserver函数
主要是监听元素的变化或者窗口的变化。有一部分用到了可以拉伸的左右布局的模块。
//directive/index.js
// 监听元素大小变化的指令
const map = new WeakMap();
const ob = new ResizeObserver((entries) => {for (const entry of entries) {// 获取dom元素的回调const handler = map.get(entry.target);//存在回调函数if (handler) {// 将监听的值给回调函数handler({width: entry.borderBoxSize[0].inlineSize,height: entry.borderBoxSize[0].blockSize,});}}
});export const Resize = {mounted(el, binding) {//将dom与回调的关系塞入mapmap.set(el, binding.value);//监听el元素的变化ob.observe(el);},unmounted(el) {//取消监听ob.unobserve(el);},
};
const directives = { Resize };const registerDirective = (app) => {Object.keys(directives).forEach((key) => {app.directive(key, directives[key]);});
};
export default registerDirective;
公共拖曳布局的函数
主要是用于左右布局宽度的变化,可以使用鼠标进行拖曳,改变左右盒子的高度。
export const useCommon = ()=>{function setLayoutDrag(dragId) {const resize = document.getElementById(dragId)let previousElement = resize.previousSiblinglet nextElement = resize.nextSiblinglet previousTag = previousElement.tagNamelet nextTag = nextElement.tagNameresize.onmousedown = (e) => {const startX = e.clientXconst startY = e.clientYlet type = ''if (previousTag === 'ASIDE' && nextTag === 'MAIN') {type = 'ASIDE-MAIN'} else if (previousTag === 'MAIN' && nextTag === 'ASIDE') {type = 'MAIN-ASIDE'} else if ((previousTag === 'HEADER' && nextTag === 'MAIN') ||(previousTag === 'FOOTER' && nextTag === 'MAIN')) {type = 'HEADER-MAIN'} else if ((previousTag === 'MAIN' && nextTag === 'HEADER') ||(previousTag === 'MAIN' && nextTag === 'FOOTER')) {type = 'MAIN-HEADER'}let initWidth = 0,initHeight = 0if (type === 'ASIDE-MAIN') {initWidth = previousElement.clientWidth // 初始位置} else if (type === 'MAIN-ASIDE') {initWidth = nextElement.clientWidth // 初始位置} else if (type === 'HEADER-MAIN') {initHeight = previousElement.clientHeight} else if (type === 'MAIN-HEADER') {initHeight = nextElement.clientHeight}document.onmousemove = (k) => {const endX = k.clientXconst endY = k.clientYlet moveLen = endX - startX // 横向移动宽度let moveHeight = endY - startY // 纵向移动高度switch (type) {case 'ASIDE-MAIN':let asideMainWidth = initWidth + moveLenif (moveLen < 0) {// 向左移if (asideMainWidth > 400) {// 左侧剩90previousElement.style.width = asideMainWidth + 'px'}} else {// 向右移动if (nextElement.clientWidth > 400) {// 右侧剩90previousElement.style.width = asideMainWidth + 'px'}}breakcase 'MAIN-ASIDE':let mainAsideWidth = initWidth - moveLenif (moveLen < 0) {// 向左移if (previousElement.clientWidth > 400) {// 左侧剩90nextElement.style.width = mainAsideWidth + 'px'}} else {// 向右移动if (mainAsideWidth > 400) {nextElement.style.width = mainAsideWidth + 'px'}}breakcase 'HEADER-MAIN': {let headerMainHeight = initHeight + moveHeightif (moveHeight < 0) {// 向上移if (headerMainHeight > 60) {// 上侧剩90previousElement.style.height = headerMainHeight + 'px'}} else {// 向下移动if (nextElement.clientHeight > 60) {// 下侧剩90previousElement.style.height = headerMainHeight + 'px'}}break}case 'MAIN-HEADER': {let mainHeaderHeight = initHeight - moveHeightif (moveHeight < 0) {// 向上移if (previousElement.clientHeight > 60) {// 左侧剩90nextElement.style.height = mainHeaderHeight + 'px'}} else {// 向下移动if (mainHeaderHeight > 60) {nextElement.style.height = mainHeaderHeight + 'px'}}break}default:}}document.onmouseup = (evt) => {document.onmousemove = nulldocument.onmouseup = nullresize.releaseCapture && resize.releaseCapture()}resize.setCapture && resize.setCapture()return false}}return {setLayoutDrag}
}
公共布局
此处的可以自己查看代码。
invoke调用rust函数,关闭splash
import { invoke } from '@tauri-apps/api/tauri'onMounted(() => {// window.addEventListener('contextmenu', (e) => e.preventDefault(), false)document.addEventListener('DOMContentLoaded', () => {// This will wait for the window to load, but you could// run this function on whatever trigger you wantsetTimeout(() => {invoke('close_splashscreen')}, 1000)})
})
🎉结语 感兴趣的可以试试,有不清楚的问题,关于tauri开发方面的问题,也可以一起交流。欢迎加我:zhan_1337608148。一起成长,一起进步。
相关文章:

我用Tauri开发的待办效率工具开源了!
开源仓库地址 gitee Git仓库地址:https://gitee.com/zhanhongzhu/zhanhongzhu.git 应用地址 windows应用地址下载 https://kestrel-task.cn 具体内容 也可以看🎉使用Taurivitekoa2mysql开发了一款待办效率应用 这篇文章。 💻技术栈 Tauri: Tauri…...

【黑科技】:Laravel 项目性能提升 20 倍
令人激动的黑科技:Laravel 项目性能提升 20 倍 这个项目能够在无需修改任何代码且无需第三方扩展的前提下,将你的 Laravel 项目性能提高 20 倍。它仅依赖于 PHP 原生的 pcntl、posix、fiber 和 sockets。 项目灵感 起因是看到官方发布的 PHP 8.1 更新…...

User Allocation In MEC: A DRL Approach 论文笔记
论文:ICWS 2021 移动边缘计算中的用户分配:一种深度强化学习方法 代码地址:使用强化学习在移动边缘计算环境中进行用户分配 目录 Ⅰ.Introduction II. MOTIVATION-A.验证假设的观察结果 II. MOTIVATION-A Motivating Example 数据驱动…...
leetcode 69. x 的平方根
可以使用二分查找法或牛顿迭代法来实现 LeetCode 问题 69. x 的平方根。下面是使用二分查找法和牛顿迭代法的 C 实现。 二分查找法 #include <iostream>class Solution { public:int mySqrt(int x) {if (x 0) return 0;int left 1, right x, ans 0;while (left <…...

基于词级ngram的词袋模型对twitter数据进行情感分析
按照阿光的项目做出了学习笔记,pytorch深度学习实战项目100例 基于词级ngram的词袋模型对twitter数据进行情感分析 什么是 N 符? N 格是指给定文本或语音样本中 n 个项目的连续序列。这些项目可以是音素、音节、字母、单词或碱基对,具体取…...
Linux-Centos-改密码(单用户登陆)
笔记一: centos7单用户修改root密码 在CentOS 7中,如果您是唯一的用户或者您确信其他用户不会登录,您可以按照以下步骤来修改root密码: 1.重启系统。 2.启动时出现引导界面时,按任意键进入GRUB菜单。 3.选择要启动的内…...

java实现OCR图片识别,RapidOcr开源免费
先看一下识别效果(自我感觉很牛逼),比Tess4J Tesseract省事,这个还需要训练,安装软件、下载语言包什么的 很费事,关键识别率不高 RapidOcr不管文字的横竖,还是斜的都能识别(代码实现…...

PCB工艺边设计准则
在PCB设计时,通常会在电路板的边缘预留一定的空间,这部分空间被称为工艺边。它有助于在生产过程中确保电路板的尺寸和形状的准确性。以使得组装时更加顺畅、便捷。而工艺边的加工,使得线路板上的元件可以精准地与设备对接,从而提高…...

CTF-NSSCTF题单[GKCTF2020]
[GKCTF 2020]CheckIN 这道题目考察:php7-gc-bypass漏洞 打开这道题目,开始以为考察反序列化,但实际并不是,这里直接用$_REQUEST传入了参数便可以利用了。这里出现了一个eval()函数,猜测考察命…...
redis的分片集群(仅供自己参考)
前言:为什么使用分片集群:因为redis的主从和哨兵机制主要是用来解决redis的高并发读的问题,还有redis的高并发的写的问题没有解决。使用分片集群就可以很好的解决redis写的问题,有多个master就可以实现并发的写。同时,…...

自动驾驶-机器人-slam-定位面经和面试知识系列01之常考公式推导(01)
李群李代数扰动bundle adjustment 这个博客系列会分为C STL-面经、常考公式推导和SLAM面经面试题等三个系列进行更新,基本涵盖了自己秋招历程被问过的面试内容(除了实习和学校项目相关的具体细节)。在知乎和牛客也会同步更新,全网…...
netty入门-5 ServerBootstrap与Bootstarp
前言 本来这篇应该紧接着说明Future和Promise。 但是考虑前文第三篇即用到了ServerBootstrap来启动一个服务器,并且我读的闪电侠netty,先写的服务器与客户端启动这部分。索性就先写出来了。主要内容来自闪电侠netty ServerBootstrap ServerBootstrap就…...

JavaEE - Spring Boot 简介
1.Maven 1.1 什么是Maven 翻译过来就是: Maven是⼀个项⽬管理⼯具。基于POM(Project Object Model,项⽬对象模型)的概念,Maven可以通 过⼀⼩段描述信息来管理项⽬的构建,报告和⽂档的项⽬管理⼯具软件。 可以理解为:Maven是一个项目管理工具…...
SwiftUI革新:Xcode UI开发的新纪元
SwiftUI革新:Xcode UI开发的新纪元 SwiftUI作为Apple推出的声明式UI框架,彻底改变了在Xcode中构建用户界面的方式。它不仅简化了代码,还提高了开发效率,并且使得UI设计更加直观和灵活。本文将深入探讨如何在Xcode中使用SwiftUI进…...
22、基于共享内存的数据结构——用十个块来提高并发性
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 为了提高并发性,把…...

【ffmpeg命令入门】实现画中画
文章目录 前言画中画是什么画中画的外观描述效果展示为什么要用画中画应用场景示例 使用FFmpeg添加画中画示例命令参数解释调整嵌入视频的位置调整嵌入视频的大小处理音频 总结 前言 FFmpeg 是一款强大的多媒体处理工具,广泛用于音视频的录制、转换和流处理。它不仅…...
基于 LangChain+LangGraph 来实现一个翻译项目
相信大家在看文档的时候,有时会比较苦恼,比如 AI 相关的文档都是外文,中文文档比较少,看起来会比较吃力,有的时候会看不懂,翻译软件又翻得很乱,完全看不了,今天就基于 LangChain 和 …...
javascript 如何将 json 格式数组转为 excel 表格| sheetJS
案例 // https://unpkg.com/xlsx0.18.5/dist/xlsx.full.min.js function exportXlsx(jsonData, fileName , mine null) {const workbook XLSX.utils.book_new();// 将JSON数组转换成工作表const worksheet XLSX.utils.json_to_sheet(jsonData);// 向工作簿添加工作表XLSX.…...
网页制作技术在未来会如何影响人们的生活?
网页制作技术在未来会如何影响人们的生活? 李升伟 网页制作技术在未来可能会从以下几个方面显著影响人们的生活: 1. 工作与学习方式的变革:远程办公和在线教育将更加普及和高效。通过精心制作的网页,人们能够实现更便捷的协作…...

【计算机网络】网络层——IPv4地址(个人笔记)
学习日期:2024.7.24 内容摘要:IPv4地址,分类编址,子网,无分类编址 IPv4地址概述 在TCP/IP体系中,IP地址是一个最基本的概念,IPv4地址就是给因特网上的每一台主机的每一个接口分配一个在全世界…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...