当前位置: 首页 > news >正文

网络云相册实现--nodejs后端+vue3前端

目录

主页面

功能简介

系统简介

api

数据库表结构

代码目录

运行命令

主要代码

server

apis.js

encry.js

mysql.js

upload.js

client3

index.js

完整代码


主页面

功能简介

  • 多用户系统,用户可以在系统中注册、登录及管理自己的账号、相册及照片。

  • 每个用户都可以管理及维护相册,及相册的备注。

  • 每个用户都可以管理及维护照片,及照片的备注。

  • 相册需要可设置是否公开。

  • 照片是可评论的,只有一级评论(不需要评论分级)。

  • 分享界面(前台界面),需要图片放大预览及轮播图功能。

  • 图片删除需要回收站。

系统简介

系统采用前后端分离的方式b-s方式,后台使用nodejs技术,数据库采用MySQL系统。前端使用vue3框架搭建。

后端是负责提供接口(api)

api

用户管理
用户注册(post)/api/userlogin用户名、密码
修改密码(post)/api/userpasswordmodify原始密码、新密码
相册管理
新建相册(get)/api/addalbum相册名及简介
修改相册(get)/api/modifyalbum
移除相册(get)/api/removealbum相册必须为空才可以移除
照片管理
上传照片(*)/api/addpic加上备注
修改(备注)(post)/api/modifyps修改备注
删除照片(get)/api/removepic
评论
新增评论(get)/api/addcomment
移除评论(get) /api/removecomment

数据库表结构

users
id无序号、递增
createAt创建时间
updateAt最后更新时间
username用户名
password密码
pics
id无序号、递增
createAt创建时间
updateAt最后更新时间
url存放图片上传后相对服务器访问的地址(相对地址)
ps图片的备注
removed图片是否被移除
userid照片隶属于哪个用户
albums
id无序号、递增
createAt创建时间
updateAt最后更新时间
title相册名称
ps备注
userid相册隶属于哪个用户
comments
id无序号、递增
createAt创建时间
updateAt最后更新时间
content评论内容
userid发表评论的用户
picid被评论的照片

代码目录

运行命令

后端启动命令:npm start

前端启动命令:npm run dev

主要代码

server

apis.js

var express = require('express')
var router = express.Router()
//引入封装的mysql访问函数
const query = require('../utils/mysql')
const encry = require('../utils/encry')
const jwt = require('jsonwebtoken')
const { expressjwt } = require('express-jwt')
const key = 'yuaner'
//引入上传对象
const upload = require('../utils/upload')//用户注册的api
router.post('/userreg', async (req, res) => {//来自url的参数,使用req.query来获取//来自请求体的参数,使用req.body来获取const { username, password } = req.body//判断用户名是否重复const result = await query('select * from users where username=?', [username,])if (result.length > 0) {res.json({flag: false,msg: '用户名已存在',})} else {//插入await query('insert into users (username,password,createAt,updateAt) values (?,?,?,?)',[username, encry(password), new Date(), new Date()])res.json({flag: true,msg: '用户注册成功',})}
})//用户登录
router.post('/userlogin', async (req, res) => {//获取参数const { username, password } = req.bodyconst result = await query('select * from users where username=? and password=?',[username, encry(password)])if (result.length > 0) {res.json({flag: true,msg: '登录成功',token: jwt.sign({ userid: result[0].id }, key, {expiresIn: '10h',}),})} else {res.json({flag: false,msg: '用户名或密码错误',})}
})router.all('*',expressjwt({ secret: key, algorithms: ['HS256'] }),function (req, res, next) {next()}
)/*** 新建相册*/
router.post('/addalbum', async (req, res) => {//获取数据const { title, ps } = req.bodyconst userid = req.auth.useridconst result = await query('select * from albums where title=? and userid=?',[title, userid])if (result.length > 0) {res.json({flag: false,msg: '同名相册已存在',})} else {await query('insert into albums (title,ps,userid,createAt,updateAt) Values(?,?,?,?,?)',[title, ps, userid, new Date(), new Date()])res.json({flag: true,})}
})/*** 修改相册* /modifyalbum* 参数 title ,ps,albumid*/
router.post('/modifyalbum', async (req, res) => {const { title, ps, albumid } = req.body//从token中获取useridconst userid = req.auth.useridconst result = await query('select * from albums where title=? and userid=? and id<>?',[title, userid, Number(albumid)])if (result.length > 0) {res.json({flag: true,msg: '相册名已存在',})} else {//进行修改的查询await query('update albums set title=?,ps=? where id=?', [title,ps,albumid,])res.json({flag: true,msg: '修改成功',})}
})/*** 移除相册* /removealbum* 参数 albumid,userid*//**
router.get('/removealbum', async (req, res) => {//获取参数const { albumid } = req.body //判断当前相册是否为空const result = await query('select COUNT(*) as count from pics where albumid = ?',[albumid])if (result[0].count > 0) {res.json({flag: false,msg: '相册不为空,请先移除所有照片再删除相册',})}await query('delete from albums where id = ?', [albumid])res.json({flag: true,msg: '相册已删除',})
})*/router.get('/removealbum', async (req, res) => {//获取参数let { albumid } = req.queryalbumid = Number(albumid)//获取useridconst userid = req.auth.userid//判断当前相册是否为空const result = await query(//可以限制为1,不用查询很多,此处用'limit 1'进行优化'select * from pics where albumid=? limit 1',[albumid])if (result.length == 0) {//如果为空则删除//删除工作不需要赋值,直接waitawait query('delete from albums where id=? and userid=?', [albumid,userid,])res.json({flag: true,msg: '删除成功!',})}//如果不为空则不能删除else {res.json({flag: false,msg: '相册不为空',})}
})/*** 分页查看相册内的图片列表* /getPiclist* 参数:albumid、pageIndex、pageRecord、、* 需要每一页记录数* 当前页数*/
router.get('/getPicList', async (req, res) => {//获取参数let { albumid, pageIndex, pageRecord } = req.queryconst result = await query('select * from pics where albumid=? and removed =0 ORDER BY updateAt desc limit ?,? ',[Number(albumid),(pageIndex - 1) * pageRecord,Number(pageRecord),])const result2 = await query('select count(*) as t from pics where albumid=? and removed =0 ',[Number(albumid)])res.json({flag: true,result: result,pageCount: Math.ceil(result2[0].t / pageRecord),})
})/*** 获取当前用户的相册列表* /getAlbumList*/ router.get('/getAlbumList', async (req, res) => {//获取参数const { userid } = req.authlet result = await query('select a.id,a.title,a.ps,count(a.id) as t,max(b.url) as url from albums a ' +'left join pics b on a.id = b.albumid ' +'where a.userid=? ' +'group by a.id,a.title,a.ps,a.userid',[Number(userid)])result = result.map(item => {if (!item.url) {item.t = 0 //'/default.jpg' 是 public作为根 // item.url='/default.jpg'}return item})res.json({flag: true,result: result,})
})
/*** 上传图片*/
router.post('/addpic', upload.single('pic'), async (req, res) => {// 图片上传的路径由multer写入req.file对象中const path = req.file.path.split('\\').join('/').slice(6)//除了上传的文件之外,其他的表单数据也被multer存放在req.body中const ps = req.body.ps//userid由token解析得到const albumid = req.body.albumid//存储到数据库中await query('insert into pics (url,ps,removed,albumid,createAt,updateAt) values (?,?,?,?,?,?)',[path, ps, 0, Number(albumid), new Date(), new Date()])res.json({flag: true,msg: '照片添加成功! very good!',})
})/*** 照片删除* 接口地址:deletepic* 客户端参数:picid* 接受客户端参数,将数据库中的记录删除,并返回客户端删除成功* /api/removepic*/
router.get('/deletepic', async (req, res) => {const { picid } = req.query //or const picid =req.query.picidawait query('delete  from pics where id=?',[Number(picid)],res.json({flag: true,msg: '照片删除成功',}))
})/*** 照片放入回收站* 接口地址:removepic* 客户端参数:picid* 接受客户端参数,将数据库中的记录删除,并返回客户端删除成功* /api/removepic*/
router.get('/removepic', async (req, res) => {const { picid } = req.query //or const picid =req.query.picidawait query('update pics set removed=1 where id=?',[picid],res.json({flag: true,msg: '照片已放入回收站',}))
})/*** 修改照片备注* modifyps,ps* 参数picid*/
router.post('/modifyps', async (req, res) => {//获取参数const { picid, ps } = req.body//修改,调用数据库await query('update pics set ps=?,updateAt=? where id=?', [ps,new Date(),Number(picid),])res.json({flag: true,msg: '备注修改成功!',})
})/*** 新增评论* addComment* 参数:content,userid(req.auth)、picid* 类型:post*/router.post('/addComment', async (req, res) => {//获取参数const { picid, content } = req.bodyconst { userid } = req.authawait query('insert into comments (content,createAt,updateAt,userid,picid) values (?,?,?,?,?)',[content, new Date(), new Date(), Number(userid), Number(picid)])res.json({flag: true,msg: '评论成功',})
})/*** 删除评论* deleteComment* 参数:commitid,content,userid(req.auth)* 类型:get* 删除前需保证当前用户是这条评论的发表人才能删除*/
router.get('/deleteComment', async (req, res) => {//获取参数const { commentid } = req.queryconst { userid } = req.authconst result = await query('select a.id from comments a' +' left join pics b ON a.picid=b.id' +' left join albums c ON b.albumid=c.id' +' where a.id=? and (a.userid=? or c.userid=?)',[Number(commentid), Number(userid), Number(userid)])if (result.length > 0) {await query('delete from comments where id=?', [Number(commentid),])res.json({flag: true,msg: '删除成功',})} else {res.json({flag: false,msg: '权限不足',})}// let key=false// const result = await query(//   'delete * from comments where id=? and userid =? limit 1)',//   [Number(userid),Number(commentid)]// )// if(result.length>0){//   key=true// }// if(key==false){//   const result=await query('select *from comment where id=?',[Number(commentid)])//   const picid=result[0].picid// }// res.json({//   flag: true,//   msg: '删除成功',// })
})/*** 评论列表* /getCommentList* 参数:picid、pageIndex、pageRecord* get*/
router.get('/getCommentList', async (req, res) => {//获取参数,需要后续修改,不使用constlet { picid, pageIndex, pageRecord } = req.queryconst result = await query('select * from comments a' +' left join pics b ON a.picid=b.id' +' where picid=? and b.removed=0 order by a.updateAt desc limit ?,? ',[Number(picid),Number(pageIndex - 1) * pageRecord,Number(pageRecord),])res.json({flag: true,result: result,})
})module.exports = router

encry.js

//导入包
const crypto = require('crypto')//导出一个函数(方法)
module.exports = password => {//创建一个加密对象sha1、md5const encry = crypto.createHash('sha1')//将要加密的字符串存入加密对象中encry.update(password)//将解密后的结果以hex的方式输出,hex就是将数字以字符+数字的方式进行输出return encry.digest('hex')
}

mysql.js

//封装mysql的连接,导出一个执行sql语句并返回结果的函数//先引入mysql的驱动--也就是mysql2      //const用来替代var
const mysql = require(`mysql2`)//创建连接池   {}是存对象的
const pool = mysql.createPool({//极限值connectionLimit: 10, //默认最大的连接数量host: `127.0.0.1`,user: `root`,password: '123456', //填自己的密码database: 'album',
})
//query函数用来执行sql语句
//参数是sql语句及参数    //nodejs是一个弱类型    //lamada表达式
const query = (sql, params) =>new Promise(//promise对象将异步操作包装成可控的结果//resolve,reject两个参数,一个成功,一个失败(resolve, reject) => {//先从连接池中取出一条连接  //异步操作pool.getConnection((err, connection) => {//如果失败。执行reject,表示失败if (err) {reject(err) //拿取连接失败,则直接返回失败} else {connection.query(sql, params, (err, result) => {//查询完成后,无论结果是什么,都不再需要连接//将连接换回连接池connection.release()if (err) {reject(err)} else {resolve(result)}})}})})//导出query函数
module.exports = query

upload.js

//引入multer、fs(读写操作模块)、path(路径模块)、
const multer = require('multer')
const fs = require('fs')
const path = require('path')//创建磁盘存储引擎
const storage = multer.diskStorage({ destination, filename })//创建上传对象
const upload = multer({ storage })//它是上传时目录的生成函数
function destination(req, res, callback) {const date = new Date()//创建动态目录const path = `public/upload/${date.getFullYear()}/${date.getMonth() + 1}`//生成路径fs.mkdirSync(path, { recursive: true })callback(null, path)
}
//用来自动生成随机的不重复的文件名
function filename(req, file, callback) {//file.originalname 是上传文件的原始名//a.jpg a.b.c.jpg//a.b.c.jpg   >['a','b','c','jpg']   扩展名console.log(file)const arr = file.originalname.split('.')const extname = arr[arr.length - 1]const date = new Date()const filename = date.getTime() + Math.random() + '.' + extnamecallback(null, filename)
}module.exports = upload

client3

index.js

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/',//有人访问根,我导向/home(重定向)redirect: '/home',},{path: '/home',name: 'home',component: HomeView,children: [{path: 'albummanage',component: () => import('../views/AlbumManage.vue'),},{path: 'album/:id',component: () => import('../views/PicsView.vue'),},],},{path: '/login',name: 'login',component: () => import('../views/LoginView.vue'),},{path: '/reg',name: 'reg',component: () => import('../views/RegView.vue'),},],
})//全局路由前置守卫
router.beforeEach(async (to, from) => {//从本地存储中尝试获取tokenif (to.name == 'home' && !localStorage.getItem('token')) {return { name: 'login' }}
})
export default router

完整代码

更新ing~

相关文章:

网络云相册实现--nodejs后端+vue3前端

目录 主页面 功能简介 系统简介 api 数据库表结构 代码目录 运行命令 主要代码 server apis.js encry.js mysql.js upload.js client3 index.js 完整代码 主页面 功能简介 多用户系统&#xff0c;用户可以在系统中注册、登录及管理自己的账号、相册及照片。 每…...

【JS】Object.defineProperty与Proxy

一、Object.defineProperty 这里只是简单描述&#xff0c;具体请看另一篇文章&#xff1a;Object.defineProperty。 Object.defineProperty 是 JavaScript 中用于定义或修改对象属性的功能强大的方法。它可以精确地控制属性的行为&#xff0c;如是否可枚举、可配置、可写等。…...

《计算机网络》(第8版)第8章 互联网上的音频/视频服务 复习笔记

第 8 章 互联网上的音频/视频服务 一、概述 1 多媒体信息的特点 多媒体信息&#xff08;包括声音和图像信息&#xff09;最主要的两个特点如下&#xff1a; &#xff08;1&#xff09;多媒体信息的信息量往往很大&#xff1b; &#xff08;2&#xff09;在传输多媒体数据时&a…...

linux进程控制——进程替换——exec函数接口

前言&#xff1a; 本节内容进入linux进程控制板块的最后一个知识点——进程替换。 通过本板块的学习&#xff0c; 我们了解了进程的基本控制方法——进程创建&#xff0c; 进程退出&#xff0c; 进程终止&#xff0c; 进程替换。 进程控制章节和上一节进程概念板块都是在谈进程…...

Apache解析漏洞~CVE-2017-15715漏洞分析

Apache解析漏洞 漏洞原理 # Apache HTTPD 支持一个文件拥有多个后缀&#xff0c;并为不同后缀执行不同的指令。比如如下配置文件&#xff1a; AddType text/html .html AddLanguage zh-CN .cn# 其给 .html 后缀增加了 media-type &#xff0c;值为 text/html &#xff1b;给 …...

Xilinx管脚验证流程及常见问题

1 流程 1.1 新建I/O Planning Project I/O Planning Project中可以不需要RTL的top层.v代码&#xff0c;仅图形化界面即可配置管脚约束XDC文件的生成&#xff1a; Create I/O Ports&#xff1a; 导出XDC文件和自动生成的top_interface.v文件&#xff1a; 1.2 新建test Project …...

格雷厄姆的《聪明的投资者》被誉为“投资圣经”

本杰明格雷厄姆的《聪明的投资者》&#xff08;The Intelligent Investor: A Book of Practical Counsel&#xff09;是投资领域的一部经典之作&#xff0c;被誉为“投资圣经”。以下是对该书的详细解析&#xff1a; 一、书籍基本信息 书名&#xff1a;《聪明的投资者》&…...

TypeScript声明文件

TypeScript声明文件 在JavaScript的生态系统中&#xff0c;随着项目的复杂度和规模不断增加&#xff0c;开发者对于类型安全和代码质量的追求也日益增长。TypeScript&#xff0c;作为JavaScript的一个超集&#xff0c;通过添加静态类型检查和ES6等新特性支持&#xff0c;极大地…...

.NET_WPF_使用Livecharts数据绑定图表

相关概念 LiveCharts 是一个开源的图表库&#xff0c;适用于多种 .NET 平台&#xff0c;包括 WPF、UWP、WinForms 等。LiveCharts 通过数据绑定与 MVVM 模式兼容&#xff0c;使得视图模型可以直接控制图表的显示&#xff0c;无需直接操作 UI 元素。这使得代码更加模块化&#x…...

一句JS代码,实现随机颜色的生成

今天我们只用 一句JS代码&#xff0c;实现随机颜色的生成&#xff0c;首先看一下效果&#xff1a; 每次刷新浏览器背景颜色都不一样 实现此效果的JS函数 &#xff1a; let randomColor () > ...: 定义一个箭头函数randomColor&#xff0c;用于生成一个随机颜色。 Math.ra…...

校园抢课助手【7】-抢课接口限流

在上一节中&#xff0c;该接口已经接受过风控的处理&#xff0c;过滤掉了机器人脚本请求&#xff0c;剩下都是人为的下单请求。为了防止用户短时间内高频率点击抢课链接&#xff0c;海量请求造成服务器过载&#xff0c;这里使用接口限流算法。 先介绍下几种常用的接口限流策略…...

char类型和int类型

一、char类型 在Java中&#xff0c;char&#xff08;字符&#xff09;类型用于表示单个字符&#xff0c;它是基本数据类型之一。以下是关于Java中char类型的一些重要信息&#xff1a; 表示方式&#xff1a; char类型用于存储Unicode字符&#xff0c;占用16位&#xff08;即2个字…...

C++参悟:stl中的比较最大最小操作

stl中的比较最大最小操作 一、概述二、最小值1. min2. min_element 三、最大值1. max2. max_element 四、混合1. minmax2. minmax_element 一、概述 记录这里C11中常用的最小值和最大值的比较函数&#xff0c;最好的参考资料其实就是 https://zh.cppreference.com 最重要的查…...

JAVA读取netCdf文件并绘制热力图

读取netCdf的依赖 <dependency><groupId>ucar</groupId><artifactId>netcdfAll</artifactId><version>5.5.3</version><scope>system</scope><exclusions><exclusion><groupId>org.slf4j</groupId…...

数据结构——八大排序

一.排序的概念和其应用 1.1排序的概念 排序&#xff1a;排列或排序是将一组数据按照一定的规则或顺序重新组织的过程&#xff0c;数据既可以被组织成递增顺序&#xff08;升序&#xff09;&#xff0c;或者递减顺序&#xff08;降序&#xff09;。稳定性&#xff1a;假定在待…...

【Unity】RPG2D龙城纷争(十九)流程与UI界面(终章)

更新日期:2024年8月1日。 项目源码:第五章发布(正式开始游戏逻辑的章节) 索引 简介一、游戏流程1.初始化流程2.开始流程3.关卡流程4.关卡结束流程5.启用所有流程二、UI界面逻辑1.开始界面2.存档界面3.关卡界面DataRegion 数据显示逻辑区域RoundRegion 回合逻辑区域RoleMenu…...

C#类和结构体的区别

1、类class是引用类型&#xff0c;多个引用类型变量的值会互相影响。存储在堆&#xff08;heap&#xff09;上 2、结构体struct是值类型&#xff0c;多个值类型变量的值不会互相影响。存储在栈&#xff08;stack&#xff09;上 类结构关键字classstruct类型引用类型值类型存储…...

【RabbitMQ】RabbitMQ持久化

一、简介 RabbitMQ的持久化机制是一种确保数据在RabbitMQ服务重启或异常情况下不会丢失的重要特性。RabbitMQ的持久化主要包括三个方面的内容&#xff1a;交换器的持久化、队列的持久化、消息的持久化。 二、交换器的持久化 1、实现方式 在RabbitMQ中&#xff0c;实现交换器…...

算法刷题笔记 Kruskal算法求最小生成树(详细算法介绍,详细注释C++代码实现)

文章目录 题目描述基本思路实现代码 题目描述 给定一个n个点m条边的无向图&#xff0c;图中可能存在重边和自环&#xff0c;边权可能为负数。求最小生成树的树边权重之和&#xff0c;如果最小生成树不存在则输出impossible。 最小生成树的概念&#xff1a;给定一张边带权的无向…...

5年经验的软件测试人员,碰到这样的面试题居然会心虚......

我们这边最近的面试机会比较多&#xff0c;但是根据他们的反馈&#xff0c;结束后大部分都没音信了&#xff0c;因为现在企业面试问的非常多&#xff0c;范围非常广&#xff0c;而且开放性的问题很多&#xff0c;很多人即便面试前刷了成百上千道面试题&#xff0c;也很难碰到一…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...