news 2026/9/29 17:13:52

基于Node.js与Vue的毕业设计选题管理系统全栈实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Node.js与Vue的毕业设计选题管理系统全栈实现

说实话,每年毕业季前后,我都会被学弟学妹问同样的问题:“老师我选的题还能改吗?”“这个毕设名额是不是满了?”“到底谁把我这个题抢走了?”如果你们学校还在用Excel汇总选题、靠QQ群接龙选课,那基本就是一团乱账。我做这个基于Node.js + Vue的毕业设计选题管理系统,目的非常朴素——把选题发布、学生申报、教师确认、管理员兜底这条完整流程搬到线上,让所有环节都留痕、可查、不靠人肉统计。

它的核心思路是前后端分离:后端用Node.js的Express提供接口,前端用Vue 3搭页面,MySQL做数据持久化。整篇会从需求拆解讲到数据库设计,再讲Node.js环境配置里那些高频报错、前端关键页面的实现、后端鉴权设计,最后给出一份前后端联调的排查清单。如果你正准备自己做毕设,或者刚入门全栈想找一个能完整落地的小项目练手,这篇直接把能抄的代码、参数和踩坑经验都摊开给你。

1. 先把需求拆干净:这个系统到底要管什么

在做任何代码之前,先把业务方的话翻译成功能。很多毕设项目翻车,不是代码写得烂,是需求没拆透就开始建表。

1.1 三种角色,三种完全不同的操作视角

这个系统的用户不是铁板一块,至少分成三种角色:学生、教师、管理员。

学生关心的是“我能选什么题、哪些还没满、我选了没有”。所以学生端必须提供选题列表、关键词和方向筛选、每人最多选报几个题,以及查看自己申请状态的入口。这里有一个业务细节容易漏:学生选报之后,老师还没确认之前,学生能不能反悔?合理的设计是允许学生在“待审核”状态下撤回申请,一旦老师已经通过,就不能再自行退选,必须要走线下或管理员处理。把这个规则写进需求文档,前端就不会出现“按钮该不该显示”的纠结。

教师关心的则是“我发布了哪些题、每个题被谁选了、我要不要通过”。教师端需要维护自己的题目列表,可以新增选题、修改选题目录、临时关闭某个方向,以及处理学生提交的对接申请。数据上要强调“只看属于我的”,不能把全校的题都铺在老师面前。

管理员是整条链路上的兜底角色。管理员端负责维系比自己级别更高的基础数据:批量导入用户、重置密码、分配导师、查看全局选题进度、发布系统公告,适当情况下还应该能强制干预某条申请。

1.2 选题状态机:一条申请从生到死的完整生命周期

后台系统最忌讳把状态存成字符串然后到处if判断,你要先在脑子里把状态机画出来。

选题本身有生命周期:教师创建后是草稿,确认后变为已发布,期间可以被教师手动关闭,选满之后自动变为已满员,不能继续申报。选报申请也有自己的状态:学生提交后是待审核,教师通过后是已通过,被驳回就是已驳回,学生撤回则是已取消。

状态所属实体含义能触发它的动作
草稿选题老师编辑中,学生不可见创建、编辑未发布
已发布选题学生可以申报教师确认发布
已满员选题达到名额上限,停止申报系统自动变更
已关闭选题教师临时关闭申报教师手动操作
待审核申请学生已提交,等待教师处理学生提交申请
已通过申请老师在规定时间内确认教师通过
已驳回申请老师拒绝,学生可重新选择教师驳回
已取消申请学生撤回申请学生在待审核状态撤回

强烈建议在数据库里用数字或简短字符串存状态码(比如pending、approved),页面展示时统一映射为中文标签。别小看这个规范,我做过的项目里,状态字段直接存“待审核”三个字导致前端报错的情况已经不止一次。

1.3 非功能需求比功能需求更像“坑”

除了上面的业务功能,还得考虑几个非功能性需求,它们不会出现在功能列表里,但直接影响系统能不能用。

第一是并发。选题开放那一刻,全年级几百人同时刷新页面是常态,选报时如果不好好控制并发,就会出现“名额明明还剩1个,却有5个人同时选成功”的灵异事件。这个问题在后面数据库设计部分会单独展开。

第二是数据可追溯。谁在什么时间发布了哪个题目、谁在什么时间通过了哪个学生,这些记录必须查得到。哪怕只是简单的create_time字段,也比什么都没有强。

第三是权限隔离。学生不能看到教师管理后台菜单,教师不能访问管理员的接口。这个要靠后端的角色中间件和前端的路由守卫一起做,缺一环都不行。

2. 技术选型与整体架构:为什么是 Node.js + Vue

很多人在选题时纠结项目要不要用Spring Boot,其实答案是:取决于谁在写代码。一个熟悉前端的学生,用Node.js+Vue做全栈,效率远高于临时抱佛脚学Spring。

2.1 这个项目为什么不适合传统模板渲染

有人可能会问,既然后端都写接口了,为什么不直接用JSP或者Thymeleaf做整体渲染?答案在交互体验上。选题广场需要实时筛选、分页、卡片式展示;教师端要内联编辑题目信息;管理员端要频繁刷新表格数据。这些交互如果用服务端模板渲染,每做一次筛选就要整页刷新,开发效率和用户体验都很难受。

Vue的优势在于数据驱动视图——选题列表变了,页面自动更新;筛选条件变了,重新请求接口然后替换列表数据。再加上Element Plus这种组件库,表格、表单、弹窗都是现成的,能把大量时间节省出来放在业务逻辑上。另外一个不可忽视的原因:Vue对新手非常友好,数据流直观,社区资料多,遇到问题很容易搜到答案。

2.2 目录结构与一次请求的完整流转

这个项目不是单体应用,我会分成server(后端)和web(前端)两个目录,不要把代码混在一个工程里。

选题管理系统/ ├── server/ # Node.js 后端 │ ├── app.js # Express 入口 │ ├── .env # 环境变量(端口、密钥、数据库) │ ├── routes/ # 路由定义 │ │ ├── auth.js # 登录、注册 │ │ ├── topics.js # 选题相关接口 │ │ └── selections.js # 选报相关接口 │ ├── controllers/ # 控制器,处理业务逻辑 │ ├── models/ # 数据库查询封装 │ ├── middleware/ # 鉴权、错误处理中间件 │ └── utils/ # 工具函数 └── web/ # Vue 前端 ├── index.html ├── vite.config.js # 开发代理配置 ├── src/ │ ├── main.js │ ├── router/ # 路由与守卫 │ ├── stores/ # Pinia 状态管理 │ ├── api/ # axios 接口封装 │ ├── views/ # 页面组件 │ └── components/ # 公共组件 └── package.json

一次完整的登录请求是这样流转的:Vue登录页获取用户输入,通过axios发送POST请求到/api/auth/login;后端路由auth.js把请求分发给控制器;控制器校验密码、调用models层查询数据库;拿到用户信息后签一个JWT返回给前端;前端把token存进localStorage,随后在axios拦截器里带上Authorization头。之后每一次请求都走“前端带token → 后端中间件验证身份 → 查询数据 → 返回JSON”这条链路。

3. 数据库设计:五张表把整条选题流程串起来

数据库是这个系统最不能将就的部分。表设计得不好,后面写接口处处别扭;表设计好了,大部分接口其实就是在做查表和改状态。

3.1 用户、选题、选报三张核心表的结构

**用户表(users)**存所有角色,用role字段区分学生、教师、管理员。学生和教师都有学号/工号、姓名、所属学院和专业。密码必须存哈希值,不要存明文。

CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, user_no VARCHAR(20) NOT NULL UNIQUE COMMENT '学号/工号', password_hash VARCHAR(100) NOT NULL, role ENUM('student', 'teacher', 'admin') DEFAULT 'student', name VARCHAR(20) NOT NULL, department VARCHAR(50) COMMENT '学院', major VARCHAR(50) COMMENT '专业', phone VARCHAR(20), email VARCHAR(100), status TINYINT DEFAULT 1 COMMENT '1正常 0禁用', create_time DATETIME DEFAULT CURRENT_TIMESTAMP );

**选题表(topics)**记录教师发布的题目,包含题目名称、简介、具体要求、面向方向、招生名额、当前已选人数、状态。这里有一个非常关键的字段:teacher_id,所有教师接口做修改、删除操作时都必须检查操作人是不是这个teacher_id的主人,否则就会出现A老师改了B老师题目的越权问题。

**选报表(selections)**是学生和选题之间的关联表,核心是status字段,表示申请当前处于什么状态。

CREATE TABLE selections ( id INT AUTO_INCREMENT PRIMARY KEY, student_id INT NOT NULL, topic_id INT NOT NULL, status ENUM('pending', 'approved', 'rejected', 'canceled') DEFAULT 'pending', apply_time DATETIME DEFAULT CURRENT_TIMESTAMP, handle_time DATETIME NULL, handle_note VARCHAR(255) COMMENT '教师处理意见', UNIQUE KEY uk_student_topic (student_id, topic_id) );

虽然我写的是“五张表”,但实际开发时建议再加公告表(announcements)和学院专业表(departments)。公告用于发布“选题系统明天开放”这类通知;学院专业表用来做筛选器的下拉选项,不要在前端硬编码专业列表,否则后期改数据还得重新发版。

3.2 名额不超卖:用一条 UPDATE 拦住并发

很多新手写选报接口时是这么写的:先查一下selected_count,如果小于max_students就插入一条选报记录,同时把selected_count加1。这个逻辑在低并发下没问题,但放到选题开放那一刻,几百人同时点“申报”,两个请求同时查到剩余名额是1,并且都通过了判断,然后都执行插入,席位就超卖了。

解决方案是把“检查名额”和“占用名额”合并成一条原子操作:

UPDATE topics SET selected_count = selected_count + 1 WHERE id = ? AND selected_count < max_students;

执行完看affectedRows,如果是0说明名额已经被人抢光了,直接返回“该选题名额已满”;如果是1说明本次占座成功,再执行选报记录的插入。这个思路跟火车票抢票是一个道理:不是在客户端排队,而是在数据库层面用条件更新保证不会重复扣减。说句实在话,很多学生做的管理系统根本没有这一行SQL,等真的被并发选报冲击时就会现出原型。

3.3 字段类型与索引的小细节

系统不大,但几个细节还是要注意。用户表的user_no一定要加唯一索引,不然批量导入用户时重复数据会让系统数据变得很脏。选题表的teacher_id加普通索引,教师端“查看我发布的题”是高频查询,没有索引的表数据量到几千条时就会有明显卡顿。选报表的student_id加普通索引,学生端“查看我选了什么”同样高频。日期时间字段能不加时区就别加时区,统一用DATETIME,前端展示时再格式化,省掉一堆时间换算的乱子。

4. Node.js 开发环境搭建与 npm 依赖里那些破事

很多同学第一次接触这个项目,被劝退不是卡在业务逻辑上,而是连环境都搭不起来。说白了,Node.js的安装和npm依赖管理就是第一道鬼门关。

4.1 安装与验证:先别急着双击下一步

去Node.js官网下载LTS版本的安装包,别为了尝鲜装最新版。LTS的含义是长期维护版本,生态兼容性最稳。我见过太多人装了个Node 23然后跑Vite项目各种报错,最后发现是版本太新导致依赖不兼容。

双击安装时一路默认即可,但装完之后不要急着写代码,先打开命令行验证两件事:

node -v npm -v

如果两个命令都能正常输出版本号,说明核心安装成功了。Node.js安装包默认会把node.exe所在的目录加进系统PATH环境变量,所以理论上开个新终端就能直接用。如果你改了安装路径,或者系统里之前装过别的版本导致命令找不到,就需要手动到“系统属性 → 环境变量 → Path”里添加Node安装目录。这一步操作结束后要重新打开终端才能生效,别问我怎么知道的。

另外,npm默认源在海外,下载依赖的速度可能让你怀疑人生。国内项目建议直接换成国内镜像源:

npm config set registry https://registry.npmmirror.com npm config get registry # 验证是否生效

4.2 npm.ps1 无法加载文件的三个解法

这个报错的热度完全在我意料之中:“npm : 无法加载文件 ...\npm.ps1,因为在此系统上禁止运行脚本”。原因一句话讲明白:Windows的PowerShell默认执行策略是Restricted,不允许运行.ps1脚本文件,而npm命令本质是通过npm.ps1脚本去执行的。

解法有三个,按推荐顺序排列:

解法一:修改当前用户的执行策略。用管理员身份打开PowerShell,运行:

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

RemoteSigned意思是本地创建的脚本可以运行,远程下载的脚本必须有数字签名。这个方案一劳永逸,改完就不用再碰这个报错。

解法二:改用CMD。如果你只是想把环境搭起来,直接在文件资源管理器地址栏输入cmd回车,然后在该命令行窗口里运行npm -v,你会发现一切正常。原理很简单:CMD执行npm.cmd,PowerShell执行npm.ps1,执行策略管不到CMD。

解法三:通过package.json的scripts运行。很多时候你根本不需要手动执行npm命令,用Vite脚手架创建的项目,直接运行npm run dev内部会调用对应的脚本。但因为脚本链路里也有PowerShell的参与,这个解法并不总是奏效,所以最稳的还是解法一。

4.3 统一依赖版本,避免“我这能跑你那不行”

依赖这关最磨人的不是装不上,而是每个人装出的版本不一样。你本地跑得好好的,代码发给室友跑就报错,十有八九是依赖版本漂移了。

解决方案:锁定大版本。package.json里不要出现^加通配符的情况,直接锁成精确版本,比如"vue": "^3.4.0"这种写法在团队协作里尽量少用。package-lock.json一定要提交到仓库,它记录的是整棵依赖树的具体版本,别人拉下来执行npm install时会安装完全相同的依赖版本,“我这能跑你那不行”的问题能少一大半。

如果你遇到npm install报peer dependency冲突,比如某个组件库要求Vue 3.2以上而你的项目锁了3.0,先别急着乱升级。看一下报错信息里要求的版本范围,再决定是升级主依赖还是改用npm install --legacy-peer-deps跳过严格检查。后者属于临时绕过,拖到后面仍然可能出兼容问题,所以我一般建议能升级就升级。

如果确实需要升级Node.js大版本,也别去官网重装,用nvm-windows做版本管理更省心。装上之后nvm install 20、nvm use 20就能自由切换版本,做多个项目时真的离不开它。

5. Vue 前端:路由、状态管理与选题广场的实现

后端接口写得再完善,前端如果乱成一团,这个系统还是没法用。Vue这部分我会挑三个关键环节讲:路由守卫、接口封装、以及选题广场的交互实现。

5.1 路由守卫 + 动态菜单:三种角色只看到一个入口

系统的路由不能一个角色通吃。学生打开后台应该看到“选题广场”和“我的选题”,教师打开应该看到“题目管理”和“申请审核”,管理员才能看到“用户管理”和“数据概览”。

做法是在路由定义里给每个页面标上允许访问的角色:

{ path: '/topics', name: 'Topics', component: () => import('@/views/student/TopicList.vue'), meta: { roles: ['student', 'admin'] } }

然后在Vue Router的全局前置守卫里做拦截:

router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}') if (!token && to.path !== '/login') { next('/login') } else if (to.meta.roles && !to.meta.roles.includes(userInfo.role)) { next('/403') } else { next() } })

这里的核心逻辑是:没登录只能去登录页,角色不匹配统一跳403。菜单用v-if根据角色的不同渲染不同入口,而路由守卫负责兜底——就算用户猜到了URL路径,没有权限照样进不去。

5.2 选题广场:筛选、分页与防重复提交

选题广场是这个系统真正有业务含金量的页面。它要支持按关键字、按方向、按指导老师筛选,还要分页展示,并且跟后端接口的参数一一对应。

我用Element Plus的表格加卡片混合展示:卡片展示选题名称和简介,详情弹窗展示具体要求。筛选条件变化时重新请求接口,每次请求带这样的参数:

// api/topic.js export function fetchTopics(params) { return request.get('/topics', { params }) } // 页面里的调用 const params = reactive({ keyword: '', category: '', page: 1, pageSize: 10 }) function loadTopics() { fetchTopics(params).then(res => { topicList.value = res.data.list total.value = res.data.total }) }

这里有个实战细节很多人会忽略:学生点击“申报”按钮之后,要立刻禁用按钮并显示loading。否则网络慢的时候学生连点三次,就会发出三个一模一样的选报请求。后端虽然可以靠唯一索引兜底,但前端能拦住的事不要让后端去擦屁股。

我自己的习惯是提交成功之后把按钮文案改成“已申报”,并置灰,状态从后端返回的实际状态为准,不靠前端临时揣测。

5.3 请求拦截器与401统一处理

axios需要统一封装,不能每个页面写一遍请求代码。在utils/request.js里配置拦截器:

request.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) request.interceptors.response.use( res => res.data, err => { if (err.response.status === 401) { localStorage.clear() location.href = '/login' } return Promise.reject(err) } )

拦截器本质上是个总闸门:所有请求自动带token,所有401响应统一踢回登录页。这样业务页面里就不会到处写“清localStorage、跳登录”的重复代码。

6. 后端接口与鉴权:JWT 登录和控制访问范围

前端的壳再漂亮,后端的接口才是业务正确性的保证。重点讲登录的密码处理和角色权限中间件。

6.1 登录接口的实现与密码存储

密码存储是安全底线。我没有直接把数据库里的密码哈希值写进博文,但你可以记住这个原则:绝对不要存明文密码。登录密码校验时用bcryptjs比对哈希值,注册或重置密码时用bcryptjs.hashSync生成新哈希。bcryptjs是纯JavaScript实现,不会像原生bcrypt那样在Windows上需要编译node-gyp,省了一堆折腾。

登录成功的核心操作是签发JWT:

const jwt = require('jsonwebtoken') const token = jwt.sign( { id: user.id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '2h' } )

process.env.JWT_SECRET放在项目的.env文件里,不要硬编码到代码中,更不要传到Git仓库。因为一旦密钥泄露,攻击者可以伪造任意身份的token。有效期建议2小时左右,但学生的使用场景是一顿操作写完就关掉页面,过长反而增加被盗用的风险。

6.2 角色权限中间件:用一个 requireRole 控制所有接口

后端不能只验登录状态,还要验角色。我封装了两个中间件,一个负责验证token,一个负责校验角色:

// middleware/auth.js function authenticate(req, res, next) { const authHeader = req.headers.authorization if (!authHeader) return res.status(401).json({ message: '未登录' }) const token = authHeader.split(' ')[1] try { const payload = jwt.verify(token, process.env.JWT_SECRET) req.user = payload next() } catch { return res.status(401).json({ message: '登录失效' }) } } function requireRole(...roles) { return (req, res, next) => { if (!roles.includes(req.user.role)) { return res.status(403).json({ message: '无权访问' }) } next() } }

使用的时候组合起来:

router.put('/topics/:id', authenticate, requireRole('teacher'), updateTopic)

在updateTopic这个控制器内部,还要再检查一次topic.teacher_id === req.user.id。为什么?因为requireRole只能保证“你是老师”,不能保证“这道题是你的”。不写归属校验,A老师把B老师的题目改成自己的名字发布了,这系统就乱套了。业务越权检查永远要放在同一次请求的最前面执行,不要让未授权的请求进入写库流程。

6.3 后端接口的响应格式与错误处理

给前端返回的数据结构要固定,不要一会儿返回数组一会儿返回对象。我习惯统一为:

{ "code": 200, "data": {}, "message": "ok" }

业务错误统一用code区分,HTTP状态码只表示“请求有没有正常到达后端”。一个全局错误处理中间件负责兜底:

app.use((err, req, res, next) => { console.error(err) res.status(500).json({ code: 500, message: '服务器内部错误' }) })

别小看这一步:没有全局错误处理,数据库一断,Express默认返回的HTML错误页把前端直接打懵,排查半天才知道是SQL问题。

7. 前后端联调的问题排查与实用清单

这个章节是给我自己踩过的坑做结论汇编的。前后端分离项目,接口写好了页面调不通,一半的问题出在联调环境上。

7.1 跨域、端口占用与404三大高频问题

开发时前端跑在5173端口,后端跑在3000端口,浏览器默认会拦截跨域请求。解决办法不是在后端暴力的加cors()就完事,而是用Vite的开发代理把前端的/api请求转发到后端:

// vite.config.js export default defineConfig({ plugins: [vue()], server: { port: 5173, proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true } } } })

配置好代理后,前端请求/api/topics,Vite会悄悄帮忙转发到http://localhost:3000/api/topics,解决了跨域问题。

端口占用也遇到过很多次。后端突然起不来,提示EADDRINUSE: address already in use :::3000,说明有进程占着3000端口。Windows下排查:

netstat -ano | findstr :3000 taskkill /pid PID号 /f

接口404则需要检查两件事:一是路由文件是否在app.js里挂载,比如写了app.use('/api/topics', topicsRouter)但topicsRouter却没有导出,请求自然落到404;二是控制器里是否定了router.get('/', ...),如果你访问的是/api/topics/而不是/api/topics,路径不匹配也会404。

7.2 高频报错速查表

故障现象根本原因解决思路
npm.ps1禁止运行PowerShell执行策略限制Set-ExecutionPolicy RemoteSigned -Scope CurrentUser或改用CMD
Node接口请求跨域报错前端请求被浏览器拦截配置Vite代理或后端启用CORS
数据库连接超时数据库服务未启动或连接参数错误确认MySQL服务,核对.env里的host、端口、密码
选题名额超卖并发下先查后改改用条件UPDATE原子占座
403无权访问角色不匹配或无token检查路由meta.roles与后端requireRole
401登录失效token过期或格式错误重新登录,确认请求头带Bearer前缀
题目A老师改B老师的题缺少归属校验控制器内检查teacher_id === req.user.id
依赖装完项目跑不起来package-lock丢失或版本漂移锁精确版本,提交package-lock.json

7.3 一点部署上的提醒

系统本地跑通之后,如果要把node server跑起来对外提供服务,不要裸跑node app.js。用pm2做进程守护,npm install -g pm2,然后pm2 start app.js --name topic-system。哪怕进程崩溃,pm2也会自动把它拉起来。MySQL连接配置上,不要用localhost混合127.0.0.1,选一个,两个指向的socket方式不同,有时候就会莫名其妙连不上。

这个选题管理系统做下来,我的一个深刻体会是:系统的复杂度不在代码行数,而在业务规则是否理清、并发场景是否考虑、角色边界是否收紧。很多人写管理系统,界面堆得很满,但没有状态机、没有越权控制、没有并发保护,上线一用就露馅。如果你正在做类似的系统,把我的这几条经验用进去,答辩时老师问“为什么这么设计”,你至少能讲出三层道理。多说一句,真到了开放选题那天,数据库并发扛住了、权限没出乱子、学生反馈“系统用起来顺手”,那一刻你会觉得前面调的那些npm报错、跨域问题,都值了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 17:13:22

MATLAB实现Gamma回归预测:正数右偏数据的GLM解决方案

做数据回归预测的朋友&#xff0c;应该都被“正数右偏”这类响应变量折磨过&#xff1a;保险赔付金额、医疗费用、设备维修工时、订单缺货天数&#xff0c;全都严格大于零&#xff0c;分布明显右偏&#xff0c;而且均值越大波动越大。拿普通线性回归硬套&#xff0c;预测值动不…

作者头像 李华
网站建设 2026/9/29 17:12:38

最长回文子串详解:中心扩展、动态规划与Manacher算法

1. 先看清第 5 题在问什么&#xff1a;不是“判断回文”&#xff0c;而是“找全部回文中最长的那段” 刷 LeetCode Hot 100 的同学应该都有这样的体验&#xff1a;第 5 题“最长回文子串”看起来人畜无害&#xff0c;毕竟判断一个字符串是不是回文&#xff0c;谁都会写——左右…

作者头像 李华
网站建设 2026/9/29 17:11:53

如何用自定义Skill实现AI一键出片:从脚本到成片的自动化工作流

1. 为什么我想做一个"一键出片"的skill上个月&#xff0c;一个做在线教育的客户找到我&#xff0c;说手上有几十个知识点要快速变成短视频&#xff0c;投放视频号和小红书。按传统流程找人写脚本、找配音、找剪辑&#xff0c;一条三分钟的视频没个两三天根本下不来&a…

作者头像 李华
网站建设 2026/9/29 17:11:41

.NET MAUI富文本编辑实战:Telerik RadEditor接入与踩坑指南

做 .NET 业务系统开发这些年&#xff0c;我越来越确认一件事&#xff1a;越不起眼的需求&#xff0c;做起来越容易让人怀疑人生。就拿“输入和编辑多行文本”来说&#xff0c;需求方往往一句话——“给用户一个能编辑多段文字的区域&#xff0c;最好支持加粗、列表、调整格式”…

作者头像 李华
网站建设 2026/9/29 17:11:41

AI投资飙升,部署成熟度仅1%:企业AI落地的真相与破局路径

过去一年里&#xff0c;几乎每个和我聊企业数字化的CIO都会先说同一句&#xff1a;AI预算不是问题&#xff0c;问题是钱花出去之后&#xff0c;系统什么时候能安安稳稳地跑在业务线上。公开数据也印证了这种焦虑——AI投资在直线飙升&#xff0c;从算力采购到大模型API调用量都…

作者头像 李华
网站建设 2026/9/29 17:11:38

110kV环网继电保护课程设计:短路电流计算与距离保护整定

简介&#xff1a;一份面向电气工程及自动化、电力系统继电保护方向学生的110KV输电线路保护课程设计报告&#xff0c;完整覆盖系统电气主接线分析、全站元件参数梳理、短路电流计算与保护方案设计的完整流程。报告以某110KV系统为例&#xff0c;详细列出了发电机、输电线路、变…

作者头像 李华