新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于Flask的企业员工日程安排与考勤签到系统开发实践

发布时间:2026/9/26 13:00:47来源:尧图网络
基于Flask的企业员工日程安排与考勤签到系统开发实践
1. 项目全景与需求拆解1.1 这个系统到底解决什么问题先聊点实在的。很多企业到现在还在用微信群接龙、Excel表格、纸质签到本来管理员工日程和考勤。你们别笑我接过好几个真实项目有的公司几十号人每天早上靠行政在群里发消息问“今天谁请假谁外出”下午再挨个统计签到情况错漏百出。人一多信息一乱月底对考勤账目的时候简直是灾难。这个基于Flask的企业员工日程安排签到系统说白了就是把两件事管起来一是员工每天的工作日程安排和查看二是上下班考勤打卡。再往大里说这就是一个轻量级的办公自动化管理系统通过一个网页端平台让员工自己登录、自己登记日程、自己打卡签到管理员在后台看全局数据。不需要装客户端浏览器打开就能用。我当初给一个二十人左右的小团队搭这套系统的时候业务方提了几个硬性需求第一日程要能按日查看每个人能写自己的计划第二签到要简单不能搞人脸识别那种重方案能用就行第三管理员要能看所有人的记录月底能导出统计。听着简单真做起来也有不少细节尤其是日程和签到这两个模块撞在一起的时候时间处理和状态判断就容易出岔子。1.2 为什么用Flask而不是Django或者Spring Boot技术上选择Flask核心原因是轻。你要明白一个逻辑企业内部的办公自动化系统尤其是这种日程加签到的中小规模应用并发量通常不会高到哪里去几十个人同时在线已经是上限了。用重型框架Django自带Admin后台、ORM、迁移工具功能确实全但杀鸡用牛刀学习成本和部署体量都上去了。Spring Boot更不用提Java那套环境配置、打包部署在小团队内部落地的时候能把人折腾死。Flask的优势在于它是一个微框架核心只做路由和视图其他能力通过扩展添加。SQLAlchemy管数据库Jinja2管模板渲染Flask-Login管会话登录哪个需要就装哪个结构非常清晰。对于这个系统来说Flask足够轻量启动快部署简单直接在服务器上跑一个Python进程就能提供服务。再配合SQLite做存储连独立数据库都不用装整个项目干净利落。还有一个很实际的原因Python的生态。pandas可以在月底统计考勤的时候直接读数据做聚合openpyxl可以导出Excel报表Requests可以对接企业微信通知。这些都是Flask项目里顺手就能接进来的能力。换成Java那套实现同样功能要写的代码量翻倍都不止。1.3 三种角色的权限模型设计这个系统我设计了三类角色普通员工、部门管理员、系统管理员。权限模型在项目初期就要想清楚不然后面加功能的时候处处受制。普通员工的操作范围是登录后看到自己的日程列表和签到状态可以新增、编辑、删除自己的日程可以在有效时间窗口内完成签到打卡。部门管理员的权限比普通员工多一块可以查看本部门所有人员的日程安排和签到记录方便协调工作但不能改别人的日程。系统管理员则负责账号管理、全员数据查看、签到时间参数设置。这个分级在设计数据库的时候就要体现在用户表上用一个role字段区分不要做成多个独立表。原因很简单员工升职变成管理员只需要改一个字段不用搬数据。2. 环境准备与项目初始化2.1 Python环境与虚拟环境的坑写Flask项目第一步不是pip install flask而是把Python环境理顺。我推荐直接用Python 3.10以上版本别再守着3.6、3.7了新特性用不上不说很多依赖的新版本已经放弃老Python了。我之前踩过坑系统里装了Python 3.6结果SQLAlchemy 2.0直接装不上被迫降级到1.4白白浪费半天时间。还有一个重点虚拟环境。很多新手图省事直接把包装到全局环境里。等项目多了就开始打架这个项目要Flask 2.3那个项目要Flask 2.0pip install的时候互相覆盖最后哪个项目都跑不起来。我通常每个项目单独建一个虚拟环境python -m venv venv source venv/bin/activate # Windows下是 venv\Scripts\activate激活虚拟环境后pip安装的包全部隔离在这个项目的目录里跟全局环境互不干扰。这是Python项目开发的基本卫生习惯真没必要省这一下。2.2 依赖清单与版本选择这个系统需要的依赖不多核心就这几个Flask 2.3.xWeb框架提供路由、请求处理、模板渲染Flask-SQLAlchemy 3.0.x数据库ORM操作SQLiteFlask-Login用户会话管理处理登录状态WerkzeugFlask自带的依赖用来做密码哈希openpyxl月底导出考勤Excel报表用安装命令一句搞定pip install flask flask-sqlalchemy flask-login openpyxl这里有个经验之谈Flask-Login虽然好用但它的会话管理逻辑有时候会跟自定义逻辑冲突。如果你发现登录状态老是不稳定先检查SECRET_KEY是否设置再检查用户加载回调是否写对。这两个地方是Flask-Login出错的高频区域。2.3 项目目录结构规划我习惯在项目一开始就把目录结构定好避免后面代码越写越乱。这个系统的结构我这样组织office_system/ ├── app.py # 入口文件创建应用实例 ├── models.py # 数据库模型定义 ├── extensions.py # 扩展初始化避免循环引用 ├── config.py # 配置文件 ├── views/ │ ├── __init__.py │ ├── auth.py # 登录注册相关路由 │ ├── schedule.py # 日程管理相关路由 │ └── attendance.py # 签到相关路由 ├── templates/ # Jinja2模板文件 │ ├── base.html │ ├── index.html │ ├── login.html │ ├── schedule.html │ └── attendance.html ├── static/ │ ├── css/ │ └── js/ └── venv/ # 虚拟环境为什么不把所有路由都写在app.py里面因为项目一旦超过三五个路由单文件就会膨胀到几百行改一个地方要翻半天。拆分成多个蓝图Blueprint每个模块自己管自己的路由查找和维护都方便。我见过不少项目功能不大但代码全堆在一个文件里后面接手的人看着都头疼。代码的可维护性从来不是留给自己的是留给三个月后的自己或者下一个同事的。3. 数据库设计与核心模型3.1 三张核心表的关系设计这个系统的核心数据有三块用户、日程、签到。对应的三张表以及它们之间的关系是整个项目的地基必须想清楚再动手。用户表存储账号密码和角色信息。日程表记录员工的工作安排通过user_id关联用户。签到表记录每天的打卡时间和状态同样通过user_id关联用户。为什么要单独建一张签到表我之前遇到过一种偷懒设计在用户表里加一个last_checkin_time字段每天覆盖一次。问题是这只能记录最后一次签到时间历史记录全丢了。月底统计的时候你拿什么数据来做考勤所以签到记录必须是一条条存的每天一条可追溯可统计。具体模型我用SQLAlchemy定义from extensions import db from datetime import datetime from werkzeug.security import generate_password_hash, check_password_hash class User(db.Model): __tablename__ users id db.Column(db.Integer, primary_keyTrue) username db.Column(db.String(80), uniqueTrue, nullableFalse) password_hash db.Column(db.String(128), nullableFalse) role db.Column(db.String(20), defaultemployee) # employee/manager/admin department db.Column(db.String(50), default) created_at db.Column(db.DateTime, defaultdatetime.now) def set_password(self, password): self.password_hash generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) class Schedule(db.Model): __tablename__ schedules id db.Column(db.Integer, primary_keyTrue) user_id db.Column(db.Integer, db.ForeignKey(users.id), nullableFalse) title db.Column(db.String(120), nullableFalse) content db.Column(db.Text, default) schedule_date db.Column(db.Date, nullableFalse) start_time db.Column(db.Time, nullableFalse) end_time db.Column(db.Time, nullableFalse) status db.Column(db.String(20), defaultpending) # pending/done/cancelled created_at db.Column(db.DateTime, defaultdatetime.now) class Checkin(db.Model): __tablename__ checkins id db.Column(db.Integer, primary_keyTrue) user_id db.Column(db.Integer, db.ForeignKey(users.id), nullableFalse) checkin_date db.Column(db.Date, nullableFalse) checkin_time db.Column(db.DateTime, nullableFalse) status db.Column(db.String(20), defaultnormal) # normal/late/leave_early3.2 数据库表设计时容易忽略的三个细节第一日期和时间用Date/Time类型别全用DateTime。日程只需要关心某一天从几点到几点日期跟时间分开存查询的时候好统计。比如“查出今天所有日程”直接用schedule_date today就能过滤不用做字符串截取。第二每个表都加created_at字段。很多人觉得同一个库里建表谁知道哪个字段什么时候加进去的等后面要排查数据问题的时候这个时间戳能帮你快速定位是哪个时间段写入的脏数据。第三外键关系要显式声明并建立索引。我用user_id db.Column(db.Integer, db.ForeignKey(users.id))这样SQLAlchemy在联表查询的时候知道怎么关联。很多初学者为了省事直接存一个user_id字符串完事等要join的时候发现类型对不上或者外键约束写错报错信息又是一堆火星文。3.3 SQLite和MySQL怎么选这个系统我默认用SQLite文件型数据库零配置文件对中小规模办公系统完全够用。SQLite唯一要留意的是并发写的问题多个用户同时写数据的时候可能会返回database is locked错误。Flask应用里有一个配置项可以缓解这个问题SQLALCHEMY_ENGINE_OPTIONS { connect_args: {timeout: 30} }设置超时时间让写操作在冲突时等待而不是立刻报错。如果团队规模超过百人或者预计多台服务器并发访问再考虑换MySQL不迟。到时候只需要改数据库URI和安装一个pymysqlSQLAlchemy的模型代码基本不用动。4. 核心功能实现详解4.1 登录注册模块与密码安全登录注册是一套Web系统的门面也是安全问题最容易出纰漏的地方。很多入门教程里的写法是把密码明文存在数据库里。这在企业内部系统尤其危险因为员工习惯用同一个密码在多个系统里一旦数据库泄露不只是这个系统遭殃。正确做法是使用Werkzeug提供的哈希函数生成密码哈希值存库。我在模型里已经写好了set_password和check_password两个方法调用方式如下from flask import Blueprint, render_template, request, redirect, url_for, flash from flask_login import login_user, logout_user, login_required, current_user from models import User from extensions import db auth_bp Blueprint(auth, __name__) auth_bp.route(/register, methods[GET, POST]) def register(): if request.method POST: username request.form.get(username) password request.form.get(password) existing User.query.filter_by(usernameusername).first() if existing: flash(用户名已存在) return redirect(url_for(auth.register)) user User(usernameusername) user.set_password(password) db.session.add(user) db.session.commit() flash(注册成功请登录) return redirect(url_for(auth.login)) return render_template(register.html) auth_bp.route(/login, methods[GET, POST]) def login(): if request.method POST: username request.form.get(username) password request.form.get(password) user User.query.filter_by(usernameusername).first() if user and user.check_password(password): login_user(user) return redirect(url_for(index)) flash(用户名或密码错误) return render_template(login.html)这里有几个细节值得说。一是用了flask-login的login_user登录之后整个会话里都可以通过current_user拿到当前登录用户不需要自己往session里塞user_id再手动取。二是密码校验成功后才调用login_user失败不能登录。三是所有对外的路由都要记得加login_required装饰器控制访问权限。4.2 日程管理的CRUD与时间冲突判断日程管理的核心操作就是增删改查四个动作。员工登录后看到的是自己当天的日程列表可以选择日期查看不同天的安排。新增日程的时候除了基本的标题和内容还要做好时间段的校验。我之前看过一个案例员工填的日程从下午三点到下午一点结束时间比开始时间还早这种数据进到库里后面做统计的时候就是一颗定时炸弹。因此在保存之前必须先做基础校验from datetime import datetime, time as dtime schedule_bp.route(/schedule/add, methods[POST]) login_required def add_schedule(): title request.form.get(title) content request.form.get(content) schedule_date_str request.form.get(schedule_date) start_str request.form.get(start_time) end_str request.form.get(end_time) if not title or not schedule_date_str or not start_str or not end_str: flash(请填写必填字段) return redirect(url_for(schedule.index)) schedule_date datetime.strptime(schedule_date_str, %Y-%m-%d).date() start_time datetime.strptime(start_str, %H:%M).time() end_time datetime.strptime(end_str, %H:%M).time() if end_time start_time: flash(结束时间必须晚于开始时间) return redirect(url_for(schedule.index)) schedule Schedule( user_idcurrent_user.id, titletitle, contentcontent, schedule_dateschedule_date, start_timestart_time, end_timeend_time ) db.session.add(schedule) db.session.commit() flash(日程添加成功) return redirect(url_for(schedule.index))这里的时间解析用datetime.strptime一定要处理格式不匹配的异常。别以为前端日期控件传回来的格式就一定标准你接手的项目里什么牛鬼蛇神的数据格式都可能出现。4.3 签到功能的业务规则设计签到是这个系统里业务逻辑最微妙的部分。先说几点规则设计的关键思路。第一签到窗口。太早不算数太晚按迟到处理。我设置的规则是工作日早上8点前签到算正常8点到9点签到算迟到9点后签到算缺勤。这个时间参数放在config.py里集中管理后期调整的话不用改业务代码。CHECKIN_START_TIME 07:00 CHECKIN_END_TIME 09:30 CHECKIN_DEADLINE 09:00第二一天只能签到一次。这个限制必须在后端做不能只靠前端按钮disable。实现方式是在写入前先查一下当天有没有记录attendance_bp.route(/checkin, methods[POST]) login_required def do_checkin(): today datetime.now().date() existing Checkin.query.filter_by( user_idcurrent_user.id, checkin_datetoday ).first() if existing: flash(今天已经签到过了) return redirect(url_for(attendance.index)) now datetime.now() now_time now.time() deadline datetime.strptime(config.CHECKIN_DEADLINE, %H:%M).time() status normal if now_time deadline else late checkin Checkin( user_idcurrent_user.id, checkin_datetoday, checkin_timenow, statusstatus ) db.session.add(checkin) db.session.commit() flash(f签到成功状态{正常 if status normal else 迟到}) return redirect(url_for(attendance.index))第三签到不是“点了就算成功”而是“写进数据库才算成功”。前端可以做个动画反馈但真正的状态必须以后端数据库记录为准。4.4 前端页面与Jinja2模板渲染Flask默认的模板引擎是Jinja2写起来非常顺手。模板的核心逻辑是视图函数把数据传给模板模板通过继承和循环来渲染页面。基础模板base.html定义页面骨架具体的页面通过extends继承!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title{% block title %}办公自动化系统{% endblock %}/title link relstylesheet href{{ url_for(static, filenamecss/style.css) }} /head body nav div classcontainer a href{{ url_for(index) }}首页/a {% if current_user.is_authenticated %} a href{{ url_for(schedule.index) }}日程管理/a a href{{ url_for(attendance.index) }}我的签到/a {% if current_user.role ! employee %} a href{{ url_for(attendance.report) }}考勤统计/a {% endif %} a href{{ url_for(auth.logout) }}退出登录/a {% else %} a href{{ url_for(auth.login) }}登录/a a href{{ url_for(auth.register) }}注册/a {% endif %} /div /nav main {% with messages get_flashed_messages() %} {% if messages %} div classflash-messages {% for message in messages %} div classflash-message{{ message }}/div {% endfor %} /div {% endif %} {% endwith %} {% block content %}{% endblock %} /main /body /html日程页面循环渲染列表{% extends base.html %} {% block title %}我的日程{% endblock %} {% block content %} h2我的日程安排/h2 form methodPOST action{{ url_for(schedule.add_schedule) }} input typedate nameschedule_date required input typetime namestart_time required input typetime nameend_time required input typetext nametitle placeholder日程标题 required textarea namecontent placeholder日程内容/textarea button typesubmit添加日程/button /form table thead tr th日期/th th时间段/th th标题/th th内容/th th状态/th th操作/th /tr /thead tbody {% for item in schedules %} tr td{{ item.schedule_date }}/td td{{ item.start_time.strftime(%H:%M) }} - {{ item.end_time.strftime(%H:%M) }}/td td{{ item.title }}/td td{{ item.content }}/td td{{ item.status }}/td td a href{{ url_for(schedule.complete, iditem.id) }}完成/a a href{{ url_for(schedule.delete_schedule, iditem.id) }} onclickreturn confirm(确定删除?)删除/a /td /tr {% endfor %} /tbody /table {% endblock %}Jinja2模板可以用filter比如strftime直接格式化时间对象避免在视图函数里手动拼字符串。模板里还能做条件判断权限不同显示不同操作按钮。5. 完整运行流程梳理5.1 从一个空文件夹到系统跑起来整个项目从开发到本地运行流程是这样的。先把项目目录和环境建好然后在extensions.py里初始化扩展from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager db SQLAlchemy() login_manager LoginManager() login_manager.login_view auth.login在app.py里创建应用实例并注册蓝图from flask import Flask from config import Config from extensions import db, login_manager from models import User def create_app(): app Flask(__name__) app.config.from_object(Config) db.init_app(app) login_manager.init_app(app) from views.auth import auth_bp from views.schedule import schedule_bp from views.attendance import attendance_bp app.register_blueprint(auth_bp) app.register_blueprint(schedule_bp) app.register_blueprint(attendance_bp) login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id)) with app.app_context(): db.create_all() return app app create_app() if __name__ __main__: app.run(debugTrue, host0.0.0.0, port5000)关键点在于db.create_all()要在应用上下文中执行不然SQLAlchemy找不到绑定的数据库实例直接报RuntimeError。很多新手第一次跑项目就在这里卡住报错信息又长又绕其实就少了那一个with app.app_context()环境。5.2 局域网部署与访问流程开发调试用的app.run(debugTrue)只能在本地跑要让局域网内的其他员工也能访问有两个地方要改。第一去掉debug模式。debugTrue会开启调试器别人能通过页面上的调试接口直接执行代码这是生产环境的大忌。第二host参数设置为0.0.0.0监听所有网络接口这样同网段的电脑都能通过你的IP访问。启动后终端会显示局域网地址比如http://192.168.1.100:5000。如果只是内部测试这样已经够了。要是正式部署到服务器上建议加一个gunicorngunicorn -w 4 -b 0.0.0.0:5000 app:app-w 4表示起4个工作进程能够多进程并发处理请求。比app.run()自带的开发服务器靠谱得多也扛得住更大的访问压力。5.3 数据初始化和测试账号的坑系统刚部署上去的时候数据库里是空的没有账号密码大家都登录不进去。我的做法是写一个初始化脚本命令行执行一下就能创建初始管理员账号# init_data.py from app import create_app from extensions import db from models import User app create_app() with app.app_context(): admin User.query.filter_by(usernameadmin).first() if not admin: admin User(usernameadmin, roleadmin, department管理部) admin.set_password(admin123) db.session.add(admin) db.session.commit() print(管理员账号创建成功) else: print(管理员账号已存在)以后要建普通的员工账号可以直接在系统后台注册也可以写一个批量导入脚本读Excel。小团队初期注册功能已经够用了。6. 常见问题与排查技巧实录6.1 登录后跳转异常与找不到endpoint问题Flask项目最常见的错误之一就是BuildError提示找不到对应的endpoint。比如url_for(schedule.index)报错但是你的蓝图中根本没有叫index的视图函数或者路由定义的时候用了别的函数名。排查思路很明确把你蓝图里所有路由都列出来逐个对一下url_for里的视图函数名。Blueprint名字和视图函数名是两个概念url_for用的是“蓝图名.视图函数名”的形式。还有一种情况是login_manager的login_view设置后登录跳转循环出不来。检查一下未登录用户访问受保护页面时Flask-Login是不是把他重定向到登录页登录成功后又跳回原页面。这个逻辑本身是对的但如果登录页自己也加了login_required装饰器就会造成无限重定向。6.2 数据库锁定与新增字段不生效SQLite的database is locked错误多半是多个进程同时写库导致。前面提到了设置connect_args的timeout参数可以缓解但更本质的解决办法是确认Flask应用是不是开了多个实例。如果模型改了字段但是db.create_all()不生效那是因为create_all只负责创建不存在的表不会去修改已存在的表结构。新增字段正确姿势是删掉旧表重新创建或者用Flask-Migrate做迁移。开发初期数据不重要的情况下我一般直接删库重建省事rm -f instance/office.db python init.py记住SQLite数据库文件默认放在instance目录下如果你找不到数据库文件去这个目录看看。6.3 签到状态统计报表导出Excel月底管理员需要导出考勤统计。我的做法是用openpyxl生成Excel文件在内存中生成后通过Flask返回给浏览器下载。from openpyxl import Workbook from openpyxl.utils import get_column_letter from flask import send_file import io attendance_bp.route(/attendance/export) login_required def export_attendance(): if current_user.role employee: return 无权限, 403 month request.args.get(month, datetime.now().strftime(%Y-%m)) wb Workbook() ws wb.active ws.title 考勤记录 ws.append([用户名, 日期, 签到时间, 状态]) start datetime.strptime(month -01, %Y-%m-%d).date() if start.month 12: end datetime(yearstart.year1, month1, day1).date() else: end datetime(yearstart.year, monthstart.month1, day1).date() records Checkin.query.filter( Checkin.checkin_date start, Checkin.checkin_date end ).all() for record in records: user User.query.get(record.user_id) ws.append([ user.username, record.checkin_date, record.checkin_time.strftime(%H:%M:%S), record.status ]) bio io.BytesIO() wb.save(bio) bio.seek(0) return send_file( bio, as_attachmentTrue, download_namef考勤统计_{month}.xlsx, mimetypeapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet )这个Excel导出的坑主要在openpyxl的下载文件名上早期版本用的filename参数新版本改成了download_name。如果下载后文件名是乱码或者没有后缀检查一下Flask版本和send_file参数。另外数据量大的表最好按月份过滤查询别把全量数据一次性拉进来。6.4 部署后样式丢失与图片路径问题开发环境里一切正常部署到服务器上CSS样式全丢了这是Flask项目部署时经常遇到的静态文件问题。排查思路先看浏览器开发者工具的Network面板CSS文件是不是404。如果是404检查模板里引用CSS的方式。用url_for(static, filenamecss/style.css)生成路径别写死成绝对路径。还有一个可能是Flask蓝图中静态文件夹的配置问题或者在服务器反向代理配置中静态文件转发规则没写对。对于部署到Windows服务器上的特别提醒附件路径和上传路径要使用绝对路径别用相对路径。我就遇到过项目部署到Windows服务器后附件保存路径一直报错后来发现是os.path.relpath在不同系统的路径分隔符处理上出的问题改用os.path.abspath后一切正常。6.5 时区与日期边界问题实战记录签到系统里最容易出埋雷的就是日期边界问题。员工晚上11点打卡存进数据库的时间是23:00:00当天判断还正常。但如果有员工凌晨0点以后登录系统看到的是新的一天签到日期直接就跳到第二天了这就跟企业的“自然日”概念冲突了。我的处理方案是所有日期操作都用本地时间不依赖服务器时区。在Python里用datetime.now()获取的就是系统本地时间只要部署的时候把服务器的时区设对一般不会出大问题。但如果系统要跨时区部署建议把所有时间统一存成UTC展示的时候再转换成本地时间。企业内部系统一般不涉及跨时区用本地时间最直观排查也方便。7. 项目复盘与扩展建议最近回看这套系统有几个地方我觉得做得对也有几个地方如果再给我一次机会一定会改掉。做得对的地方是权限模型一开始就设计好了。后期加考勤统计、部门查看功能的时候只需要判断current_user.role就行完全没有重构用户体系。数据库表设计用了外键关联联表查询很顺畅没有出现“一张表存储所有业务”的糟糕设计。可以改进的地方是密码策略太简单。目前只是做了哈希存储没有强制密码复杂度也没有密码过期策略。对于更注重安全的企业环境可以考虑接入邮箱验证码、定期改密提醒。另外一个扩展方向是消息通知。日程到期提醒、签到异常预警这些如果接上企业微信或者邮件通知实用性会提升一大截。我之前在另一个项目里用APScheduler做了定时任务每天下午5点检查第二天有没有日程有的话群发企业微信提醒。参考这个思路你也可以给这个系统加一个通知模块。最后一个建议代码量控制。很多功能的逻辑在视图层就能解决没必要过度设计引入Celery或者Redis这种重型组件。等业务量真正上来再升级不迟中小型办公系统保持简单直接就是最大的优点。这个项目从设计到落地加起来大概花了一周多的业余时间核心代码量并不大但每一个环节都经过实际踩坑和验证。如果你正在搭类似的办公自动化系统照着这个思路走一遍很多弯路都可以提前绕开。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

卫星互联网与5G链路预算对比:从频段到拓扑的选型指南 2026/9/27 5:32:01

卫星互联网与5G链路预算对比:从频段到拓扑的选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
搞定音乐网站开发文档撰写模板的5个图解步骤 2026/9/27 5:31:49

搞定音乐网站开发文档撰写模板的5个图解步骤

搞定音乐网站开发文档撰写模板的5个图解步骤 改个需求建站公司拖一周,这种憋屈谁受得了?你明明指着播放器的进度条让前端加个暂停按钮,对方却回你“排期满了,下周再说”。这时候,手里要是有一份标准的音乐网站开发文档撰写模板,再配上清晰的图解步骤,…

阅读更多 →
爱站网长尾关键词挖掘工具下载图解步骤:3招解决网站没流量 2026/9/27 5:31:49

爱站网长尾关键词挖掘工具下载图解步骤:3招解决网站没流量

爱站网长尾关键词挖掘工具下载图解步骤:3招解决网站没流量 网站做好了没人访问,比没建网站更让人崩溃。 你花了三个月做站,代码一行行敲,页面一张张设计,结果上线一周,后台数据一片惨白。别急着骂搜索引擎不给力,大概率是你选错了赛道,或者压根没告…

阅读更多 →
免费白嫖 agnes-3.0-flash:WorkBuddy 和 DSH 接入全记录 2026/9/27 5:31:30

免费白嫖 agnes-3.0-flash:WorkBuddy 和 DSH 接入全记录

最近用上一个免费的模型:agnes-3.0-flash。输入输出都按 0 计费,512K 上下文,单次最多能吐 65,536 token。 先说两个前提,免得你配到一半才发现:一是它按「阶段性优惠」计费,不是承诺永久免费(官…

阅读更多 →
搞懂个人介绍网站内容,避坑建站报价 2026/9/27 5:31:30

搞懂个人介绍网站内容,避坑建站报价

搞懂个人介绍网站内容,避坑建站报价 找建站公司最怕什么?怕被坑高价。很多老板拿着“个人介绍网站内容”的需求去询价,对方张嘴就是几万起,理由五花八门:什么高端定制、什么品牌溢价。其实,一个纯粹的个人展示页,技术门槛并不高。如果你不懂里面的门道…

阅读更多 →
用I2C获取的数据经常卡死的原因 2026/9/27 5:31:30

用I2C获取的数据经常卡死的原因

1.I2C时序容易被程序中的中断给打断,并且程序中多个任务同时运行,对时序要求高,I2C数据就可能卡死时序的概念:通信的时候,什么时间发信号,什么时间发数据,谁先谁后,这一整套先后顺序…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉