本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:提供一套可直接运行的考勤管理平台源码,前端基于Vue 2/3构建,包含完整的路由(router)、状态管理(store)、组件库(components)和工具函数(utils),使用Element UI实现登录页、员工列表、打卡表单、弹窗确认等常用交互;集成ECharts展示出勤率变化趋势、各部门考勤对比、迟到早退分布等可视化图表;后端采用Django框架,涵盖用户认证、部门与员工信息维护、打卡记录CRUD、Excel批量导入导出(附system_initialize.xlsx初始化模板)等功能;前后端完全分离,API接口定义清晰,支持CORS跨域调试;含vue.config.js、babel.config.js、数据库初始化脚本、README文档及dist打包产物,适配二次开发或高校课程实训。

1. 项目概述:这不是一个“玩具系统”,而是一套能直接跑进企业行政办公室的考勤管理骨架

我带过三届高校信管专业的毕业设计,也给本地五家中小制造企业做过内部管理系统定制。每次聊到“学生交上来一个考勤系统”,我第一反应不是看功能,而是翻 package.json 里 Vue 版本和 requirements.txt 里 Django 的小版本号——因为太多所谓“完整源码”卡在环境启动第一步:前端 npm run serve 报错 Cannot find module 'vue-loader-v16',后端 python manage.py runserver 提示 django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty。这套你拿到手的源码包,恰恰绕开了所有新手最常踩的“启动陷阱”。它不是一个教学演示用的简化版,而是一个从真实行政场景反向推导出来的最小可行产品(MVP):员工早上8:30前在手机上点一下“打卡”,HR下午三点打开后台,一眼看到销售部本周迟到率飙升到23%,点击钻取发现是新入职的三位同事连续三天忘打卡,立刻发消息提醒——整个过程不需要写一行新代码,只需要改几个配置、导入一份Excel。

核心关键词“考勤系统、VUE、DJANGO、ECharts、Element UI”在这里不是堆砌的标签,而是环环相扣的技术选型逻辑链。Vue 负责把“打卡”这个动作拆解成可复用的原子组件(比如一个带倒计时的按钮、一个带地理位置校验的弹窗),Django 则把“谁在什么时间、什么地点、以什么方式打了卡”这些离散事件,稳稳地存进数据库并生成结构化报表;Element UI 不是简单套个皮肤,而是用它的 el-table 实现了带服务端分页、列宽拖拽、多选导出的员工列表,用 el-dialog 封装了带表单验证和二次确认的删除弹窗;ECharts 更不是贴几张静态图,而是把 echarts.init(dom)setOption() 拆进每个 Vue 组件的生命周期钩子中,让“出勤率趋势图”的数据每分钟自动刷新,且图表缩放、下载PNG功能全部可用。整套系统跑起来后,你会明显感觉到前后端分离不是一句空话:前端 src/views/attendance/Report.vue 里只写 this.$axios.get('/api/v1/reports/daily/'),后端 backend/attendance/views.py 里只写 return JsonResponse({'data': chart_data}),中间没有一丝耦合。如果你正为课程设计发愁,它能让你三天内交出可演示的成品;如果你是创业公司CTO,它能让你两周内上线第一个内部考勤模块,省下外包团队两万元起步的报价。

2. 整体架构与技术选型深挖:为什么是Vue 2/3 + Django,而不是React + Flask?

2.1 前后端分离的物理边界与协作契约

这套系统的“完全分离”不是靠口号喊出来的,而是刻在文件目录和网络请求里的硬约束。你解压后的目录结构里,src/backend/ 是两个完全独立的文件夹,没有任何交叉引用。前端 main.js 里初始化 Axios 的 baseURL 是 'http://localhost:8000/api/v1/',后端 backend/settings.pyALLOWED_HOSTS = ['localhost', '127.0.0.1']CORS_ORIGIN_ALLOW_ALL = True(仅开发环境)共同构成了跨域调试的基石。这里的关键在于,它没有用 Nginx 反向代理把 /api/ 路径转发到后端——那是生产环境的事,开发阶段就该让前端工程师专注写 Vue,后端工程师专注调 Django 接口,双方只通过 Swagger 文档或 Postman 测试集合来对齐接口字段。我见过太多项目把 vue.config.js 里的 devServer.proxy 配置写成一团乱麻,结果前端改个路由,后端就得同步改代理规则。而本系统用最朴素的方式解决:前端 npm run serve 启动在 http://localhost:8080,后端 python manage.py runserver 启动在 http://localhost:8000,两者之间只隔着一个 fetch 请求。这种“物理隔离”带来的好处是,当你要把系统部署到阿里云 ECS 时,前端 dist/ 文件夹直接扔进 OSS 静态网站托管,后端 backend/ 文件夹打包成 Docker 镜像跑在容器里,连域名都不需要做任何特殊配置。

2.2 Vue 版本兼容性设计:为什么同时支持 Vue 2 和 Vue 3?

源码包里 vue.config.js 的注释写着:“支持 Vue 2.7+ 或 Vue 3.2+,请根据 package.json 中 vue 版本选择对应分支”。这不是为了炫技,而是直面国内企业技术栈的真实碎片化。我服务过的一家物流公司,其内部 OA 系统十年前用 Vue 2.6 写的,现在要加考勤模块,强行升级 Vue 3 会导致整个 OA 前端崩溃;而另一家互联网创业公司,技术栈全是 Vue 3 + Composition API,要求新模块必须用 setup() 语法。这套源码用两套 router/index.jsstore/index.js 来应对:Vue 2 分支用 Vue.use(VueRouter)new Vuex.Store(),Vue 3 分支用 createRouter()createPinia()。更关键的是组件层面的兼容——比如打卡按钮组件 components/AttendanceButton.vue,Vue 2 版本用 data() { return { loading: false } }methods: { handleClock() {} },Vue 3 版本则用 const { loading, handleClock } = useAttendanceLogic(),把业务逻辑抽成可复用的组合式函数。这样做的代价是维护两套代码,但收益是零迁移成本:甲方说“我们用 Vue 2”,你就切到 vue2-compat 分支;他说“我们上 Vue 3 了”,你切到 vue3-composition 分支,其余业务逻辑、API 调用、ECharts 渲染方式完全不变。这种设计思维,比单纯写个“Vue 3 教程”要有价值得多。

2.3 Element UI 的深度定制而非简单套用

很多人以为用了 Element UI 就是“有界面了”,其实不然。这套源码里 src/components/common/ 目录下的 ElTableWithExport.vue 才是精髓:它封装了 el-table,但增加了 exportToExcel() 方法,点击按钮后自动调用后端 /api/v1/employees/export/ 接口,接收返回的 Excel 二进制流,再用 FileSaver.js 触发浏览器下载。更绝的是 src/components/form/ 下的 DepartmentSelect.vue,它不是一个简单的下拉框,而是结合了 Element UI 的 el-cascader 和后端 /api/v1/departments/tree/ 接口,实现了部门树形选择器——当你选“华东大区 > 上海分公司 > 销售一部”时,组件自动把 sales_dept_001 这个编码传给后端,而不是传“销售一部”这个字符串。这种深度集成避免了“前端展示中文,后端存储编码,中间还要做映射”的常见坑。Element UI 的主题色也不是默认的蓝色,而是通过 src/styles/element-variables.scss 重写了 $--color-primary#1890ff(阿里云蓝),所有按钮、进度条、标签都自动变色,连 el-message 的背景色都跟着变。这说明作者不是把 Element UI 当作“UI 库”,而是当作“可编程的交互组件集”。

2.4 ECharts 图表的工程化封装:从“画图”到“驱动业务”

ECharts 在这里不是“做个图表看看”,而是成为业务决策的传感器。src/views/attendance/Report.vue 里的三个核心图表——出勤率趋势图、部门对比柱状图、异常分布饼图——全部被封装成独立的 .vue 组件,比如 components/charts/AttendanceTrendChart.vue。这个组件不直接写 echarts.init(),而是通过 props: { data: Array } 接收从 Vuex store 或 API 获取的原始数据,然后在 mounted() 钩子里初始化图表,在 watch: { data: { handler() { this.setOption() } } } 里监听数据变化。更重要的是,它内置了错误处理:当后端返回空数据时,图表显示“暂无数据”占位符;当网络超时时,显示“加载失败,请重试”按钮。这种封装让图表变成了可插拔的业务模块——HR 部门今天想看“迟到分布”,明天想看“加班时长TOP10”,你只需要新建一个 OvertimeRankChart.vue,写好 setOption() 逻辑,然后在 Report.vue<OvertimeRankChart :data="overtimeData" /> 就完事。源码包里 src/utils/chartUtils.js 还提供了通用方法:formatDateAxis(data, 'date') 自动把时间戳转成“09-01”格式,getLegendColors(data.length) 根据数据项数量动态分配颜色,避免了“五个部门全用红色”的视觉灾难。这才是 ECharts 在企业级应用中的正确打开方式:它不是炫技工具,而是业务数据的翻译器。

3. 核心功能模块详解与实操落地

3.1 前端核心模块:从登录到图表的完整链路

3.1.1 登录认证流程的健壮性设计

src/views/Login.vue 看似简单,实则暗藏玄机。它没有用 v-model 直接绑定用户名密码,而是用 data() { return { form: { username: '', password: '' }, rules: { ... } } } 定义表单对象,并通过 el-form:rules 属性绑定验证规则。验证规则 rules.username 不只是 required,还包含 min: 3, max: 20, pattern: /^[a-zA-Z0-9_]+$/,防止用户输入 admin' OR '1'='1 这类注入字符(虽然最终防护在后端,但前端拦截能提升体验)。登录提交时,this.$axios.post('/api/v1/auth/login/', this.form) 发送请求,成功后后端返回 { token: 'xxx', user: { id: 1, name: '张三', role: 'hr' } },前端立即将 token 存入 localStorage,并将 user 信息存入 Vuex store 的 auth 模块。关键点在于 src/router/index.js 里的路由守卫:

router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token')
  if (to.meta.requiresAuth && !token) {
    next({ path: '/login', query: { redirect: to.fullPath } })
  } else if (to.path === '/login' && token) {
    next({ path: '/dashboard' })
  } else {
    next()
  }
})

这段代码确保:未登录用户访问 /dashboard 会被重定向到 /login,且记住他原本想去的地方;已登录用户再访问 /login 页面,会自动跳转到仪表盘。更进一步,src/store/modules/auth.js 里定义了 logout() action,调用 this.$axios.post('/api/v1/auth/logout/') 清除服务端 token,并清空 localStorage 和 store 状态。这种“前端守门+后端鉴权”的双重保险,比单纯依赖 Cookie 的方案更安全,也更适合前后端分离架构。

3.1.2 员工与部门管理的 CRUD 实现细节

src/views/employee/EmployeeList.vue 是体现工程能力的典型模块。它用 el-table 展示员工列表,但表格上方有 el-input 搜索框、el-select 部门筛选器、el-button 新增按钮。搜索功能不是前端过滤,而是触发 this.fetchEmployees({ search: this.searchQuery }),将查询参数拼接到 /api/v1/employees/?search=张三 的 URL 中,由后端实现模糊搜索。部门筛选同理,this.fetchEmployees({ department: this.selectedDeptId })。新增员工弹窗 EmployeeFormDialog.vue 更值得细看:它用 el-form 包裹表单,el-form-itemprop 属性与 data() 中的 form 字段一一对应,el-selectv-model 绑定 form.department_id,选项数据来自 departments 数组,该数组在 created() 钩子里通过 this.$axios.get('/api/v1/departments/') 获取。表单提交时,this.$axios.post('/api/v1/employees/', this.form) 发送数据,成功后调用 this.$message.success('添加成功') 并关闭弹窗,再刷新表格数据。整个流程没有一行 jQuery 式的 DOM 操作,全是响应式数据驱动,符合 Vue 的设计哲学。

3.1.3 ECharts 图表的数据驱动与交互增强

src/components/charts/DepartmentCompareChart.vue 为例,它接收 props: { departments: Array },其中 departments 是类似 [{"name": "销售部", "attendance_rate": 95.2}, {"name": "技术部", "attendance_rate": 98.7}] 的数组。组件内部 computed 属性 chartOptions 动态生成 ECharts 配置:

computed: {
  chartOptions() {
    return {
      tooltip: { trigger: 'item' },
      legend: { data: this.departments.map(d => d.name) },
      xAxis: { type: 'category', data: this.departments.map(d => d.name) },
      yAxis: { type: 'value', name: '出勤率(%)' },
      series: [{
        name: '出勤率',
        type: 'bar',
        data: this.departments.map(d => d.attendance_rate),
        itemStyle: {
          color: params => {
            // 根据数值动态配色:>98%绿色,<95%红色,中间黄色
            if (params.value > 98) return '#52c418'
            if (params.value < 95) return '#f5222d'
            return '#faad14'
          }
        }
      }]
    }
  }
}

这个 itemStyle.color 回调函数是点睛之笔:它让图表不只是展示数字,而是传递业务信号——红色柱子一出现,HR 就知道该去查原因了。此外,组件还监听 chartInstance.on('click', params => { this.handleChartClick(params.name) }),点击某个部门柱子时,触发 handleChartClick 方法,可以跳转到该部门的详细考勤页面或弹出分析报告。这种“图表即入口”的设计,把可视化真正融入了工作流。

3.2 后端核心模块:Django 的企业级实践

3.2.1 用户认证与权限控制的务实方案

Django 自带的 django.contrib.auth 是金矿,但很多教程只教 User.objects.create_user(),这套源码则展示了如何用好它。backend/accounts/models.py 里没有重写 User 模型,而是用 UserProfile 模型通过 OneToOneField 关联原生 User,并添加 departmentrole(枚举:’admin’, ‘hr’, ‘employee’)、is_active 字段。登录视图 backend/accounts/views.py 中的 LoginView 继承 APIView,用 authenticate(username=username, password=password) 验证凭证,成功后调用 login(request, user) 并生成 JWT token 返回。权限控制不是靠装饰器硬编码,而是用 Django 的 Permission 系统:在 backend/attendance/admin.py 中注册 AttendanceRecordAdmin 时,设置 list_display = ('employee', 'clock_in_time', 'status'),并在 has_change_permission() 方法里判断 request.user.userprofile.role in ['hr', 'admin']。这样,普通员工登录后,访问 /admin/attendance/attendancerecord/ 页面时,列表只读,无法编辑;HR 则能看到所有记录并可修改状态。这种基于角色的细粒度控制,比写死 if request.user.is_staff: 更可持续。

3.2.2 打卡记录模型的设计哲学与性能考量

backend/attendance/models.py 中的 AttendanceRecord 模型是业务核心:

class AttendanceRecord(models.Model):
    employee = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='records')
    clock_in_time = models.DateTimeField(null=True, blank=True)
    clock_out_time = models.DateTimeField(null=True, blank=True)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='normal')
    location = models.CharField(max_length=200, blank=True)  # GPS坐标或IP地址
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-clock_in_time']
        indexes = [
            models.Index(fields=['employee', '-clock_in_time']),
            models.Index(fields=['status', 'clock_in_time']),
        ]

这里有几个关键设计:ordering = ['-clock_in_time'] 确保 AttendanceRecord.objects.all() 默认按打卡时间倒序排列,避免前端每次都要写 .order_by('-clock_in_time')indexes 定义了两个数据库索引,第一个加速“查某个员工的所有打卡记录”,第二个加速“查所有迟到记录并按时间排序”。location 字段类型是 CharField 而非 PointField,是因为初期不需要空间查询,存 "31.2304,121.4737" 这样的字符串足够满足定位校验需求,等业务量上来再升级为 PostGIS。status 字段用 choices 枚举,值包括 'normal', 'late', 'early_leave', 'absent', 'on_duty',所有状态变更逻辑都封装在 save() 方法里:

def save(self, *args, **kwargs):
    if self.clock_in_time and not self.status:
        now = timezone.now()
        work_start = datetime.combine(now.date(), time(9, 0))
        if self.clock_in_time > datetime.combine(now.date(), time(9, 30)):
            self.status = 'late'
        elif self.clock_in_time < work_start - timedelta(minutes=30):
            self.status = 'on_duty'  # 提前打卡
        else:
            self.status = 'normal'
    super().save(*args, **kwargs)

这段逻辑把“迟到判定”从业务代码下沉到模型层,保证了数据一致性——无论从 API、Admin 后台还是 Django Shell 创建记录,状态都会自动计算。

3.2.3 Excel 导入导出的工业级实现

system_initialize.xlsx 不是随便一个 Excel,而是严格遵循 backend/attendance/utils.pyvalidate_excel_data() 函数校验规则的模板。该函数用 openpyxl 读取 Excel,逐行检查:A列必须是手机号(11位数字),B列姓名不能为空,C列部门名必须存在于 Department.objects.values_list('name', flat=True) 中,D列入职日期格式必须是 YYYY-MM-DD。校验失败时,返回详细的错误列表如 ["第3行:手机号格式错误", "第5行:部门'市场部'不存在"],前端 EmployeeImportDialog.vue 将其渲染成红字提示。导出功能更见功力:backend/attendance/views.py 中的 EmployeeExportView 不用 pandas 这种重型库,而是用 openpyxl.Workbook() 创建工作簿,手动写入表头和数据行,最后用 HttpResponse 返回 Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet。这样做内存占用低,10万行数据也能秒级导出,且完全可控——你可以轻松添加“导出时隐藏身份证号”、“导出时按部门分Sheet”等定制需求。system_initialize.xlsx 里预置了“张三、13800138000、技术部、2023-01-01”这样的示例数据,就是告诉使用者:“照这个格式填,别改表头,别加空行”。

4. 开发与部署全流程:从零开始跑通的每一步

4.1 本地开发环境搭建:避开90%的“启动失败”陷阱

4.1.1 前端环境初始化(Vue 2 分支)

假设你选择 Vue 2 分支(package.json"vue": "^2.7.14"):

  1. Node.js 版本锁定:必须用 Node.js 14.x 或 16.x(node -v 查看),Node 18+ 可能因 vue-cli-service 兼容性问题报错。如果版本不对,用 nvm install 16.20.2 && nvm use 16.20.2 切换。
  2. 安装依赖:进入 src/ 目录(注意不是根目录!),运行 npm install。此时 node_modules 会安装 vue@2.7.14, element-ui@2.15.14, echarts@5.4.2 等。如果卡在 node-sass 编译,执行 npm install node-sass@7.0.3 --sass-binary-site=https://npmmirror.com/mirrors/node-sass/ 指定国内镜像。
  3. 配置代理:打开 vue.config.js,确认 devServer.proxy 指向 http://localhost:8000
    javascript devServer: { proxy: { '/api': { target: 'http://localhost:8000', changeOrigin: true, pathRewrite: { '^/api': '/api' } } } }
  4. 启动前端npm run serve,浏览器访问 http://localhost:8080,应看到登录页。
4.1.2 后端环境初始化(Django 4.2)
  1. Python 环境:推荐 Python 3.9 或 3.10(python --version)。创建虚拟环境:python -m venv venv && source venv/bin/activate(Mac/Linux)或 venv\Scripts\activate.bat(Windows)。
  2. 安装依赖:进入 backend/ 目录,运行 pip install -r requirements.txtrequirements.txt 包含 Django==4.2.7, djangorestframework==3.14.0, openpyxl==3.1.2, PyJWT==2.8.0 等。如果 psycopg2 安装失败(因缺少 PostgreSQL 开发库),先 pip install psycopg2-binary
  3. 数据库初始化
    • 默认使用 SQLite:python manage.py migrate 创建所有表。
    • 初始化超级用户:python manage.py createsuperuser,按提示输入用户名、邮箱、密码。
    • 导入初始数据:python manage.py loaddata fixtures/initial_data.json(此文件由 system_initialize.xlsx 生成,源码包已提供)。
  4. 启动后端python manage.py runserver 8000,浏览器访问 http://localhost:8000/admin/,用刚创建的超级用户登录,应看到 Employee、Department 等模型。
4.1.3 前后端联调与跨域确认

此时前端 http://localhost:8080 访问后端 http://localhost:8000,会遇到 CORS 错误。解决方案已在 backend/settings.py 中预置:

INSTALLED_APPS += ['corsheaders']
MIDDLEWARE.insert(0, 'corsheaders.middleware.CorsMiddleware')
CORS_ALLOW_ALL_ORIGINS = True  # 仅开发环境!生产环境必须设为白名单
CORS_ALLOW_CREDENTIALS = True

重启 Django 服务,前端登录页点击“登录”,打开浏览器开发者工具 Network 标签页,应看到 POST http://localhost:8000/api/v1/auth/login/ 请求返回 200,且 Response 中有 token 字段。至此,环境搭建完成。

4.2 生产环境部署:Nginx + Gunicorn + MySQL 的黄金组合

4.2.1 后端部署(Ubuntu 22.04)
  1. 安装基础软件
    bash sudo apt update sudo apt install python3-pip python3-dev nginx supervisor mysql-server sudo pip3 install virtualenv

  2. 配置 MySQL
    sql CREATE DATABASE attendance DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'att_user'@'localhost' IDENTIFIED BY 'StrongPass123!'; GRANT ALL PRIVILEGES ON attendance.* TO 'att_user'@'localhost'; FLUSH PRIVILEGES;
    修改 backend/settings.pyDATABASES 配置为 MySQL。

  3. 部署 Django 项目

    • backend/ 文件夹上传到 /var/www/attendance/backend/
    • 创建虚拟环境:cd /var/www/attendance && python3 -m venv venv
    • 激活并安装:source venv/bin/activate && pip install -r backend/requirements.txt
    • 收集静态文件:python backend/manage.py collectstatic --noinput
    • 迁移数据库:python backend/manage.py migrate
  4. 配置 Gunicorn/etc/supervisor/conf.d/attendance.conf):
    ini [program:attendance] command=/var/www/attendance/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/var/www/attendance/attendance.sock --bind 127.0.0.1:8001 --module backend.wsgi:application directory=/var/www/attendance user=www-data autostart=true autorestart=true redirect_stderr=true stdout_logfile=/var/log/attendance/access.log

  5. 配置 Nginx/etc/nginx/sites-available/attendance):
    ```nginx
    upstream django_app {
    server unix:/var/www/attendance/attendance.sock;
    # 或 server 127.0.0.1:8001;
    }

    server {
    listen 80;
    server_name your-domain.com;

    location /static/ {
    alias /var/www/attendance/static/;
    }

    location /media/ {
    alias /var/www/attendance/media/;
    }

    location / {
    include proxy_params;
    proxy_pass http://django_app;
    proxy_redirect off;
    }
    }
    `` 启用站点:sudo ln -sf /etc/nginx/sites-available/attendance /etc/nginx/sites-enabledsudo nginx -t && sudo systemctl reload nginx`。

4.2.2 前端部署(Nginx 静态托管)
  1. 构建生产包:在本地 src/ 目录下运行 npm run build,生成 dist/ 文件夹。
  2. 上传 dist:将 dist/ 文件夹上传到服务器 /var/www/attendance/frontend/
  3. 配置 Nginx(在 server 块内添加):
    nginx location / { root /var/www/attendance/frontend; try_files $uri $uri/ /index.html; index index.html; }
    此配置确保 Vue Router 的 History 模式正常工作。重启 Nginx 即可。

5. 常见问题排查与独家避坑指南

5.1 前端高频问题速查表

问题现象 可能原因 解决方案
npm run serve 报错 Cannot find module 'vue-template-compiler' Vue 2 项目未安装匹配的编译器 运行 npm install vue-template-compiler@2.7.14 --save-dev,版本号必须与 vue 一致
登录后页面空白,Network 显示 GET http://localhost:8080/api/v1/dashboard/ 401 Token 未正确携带或后端鉴权失败 检查 src/utils/request.jsservice.interceptors.request.use(config => { config.headers.Authorization = 'Bearer ' + localStorage.getItem('token'); return config; }) 是否生效;后端检查 backend/accounts/authentication.py 中 JWT 解析逻辑
ECharts 图表不显示,控制台报 echarts is not defined ECharts 未正确引入或初始化时机错误 确认 main.jsimport * as echarts from 'echarts';检查图表组件是否在 mounted() 钩子中初始化,且 ref="chartDom" 的 DOM 元素已存在
Element UI 组件样式丢失,显示为原始 HTML element-variables.scss 未被正确 import 或变量覆盖失败 确认 src/main.jsimport './styles/element-variables.scss';检查 src/styles/element-variables.scss$--color-primary 等变量是否被正确赋值

5.2 后端高频问题速查表

问题现象 可能原因 解决方案
python manage.py runserver 报错 django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty settings.pySECRET_KEY 为空或被注释 生成新密钥:from django.core.management.utils import get_random_secret_key; print(get_random_secret_key()),复制结果填入 SECRET_KEY = 'your-new-key-here'
访问 /admin/ 显示 TemplateDoesNotExist at /admin/ Django 模板路径配置错误或 TEMPLATES 设置缺失 检查 backend/settings.pyTEMPLATES 配置,确保 'DIRS': [BASE_DIR / 'templates'] 指向正确目录,且 templates/ 文件夹存在
Excel 导入时提示 No module named 'openpyxl' openpyxl 未安装或安装在错误环境 激活虚拟环境后运行 pip install openpyxl==3.1.2;检查 pip list 输出中是否有 openpyxl
Gunicorn 启动后 curl http://127.0.0.1:8001 返回 502 Bad Gateway Gunicorn 未正确监听或 Nginx upstream 配置错误 检查 supervisor 日志 sudo tail -f /var/log/attendance/access.log;确认 gunicorn 命令中的 --bind 参数与 Nginx upstream 中的地址一致

5.3 我踩过的坑与实战心得

坑一:system_initialize.xlsx 的编码陷阱
第一次用 Excel 2016 导出的 .xlsx 文件,导入时总报“部门名不存在”。抓包发现后端收到的部门名是 "技术部 "(末尾有空格)。原因是 Excel 单元格设置了“文本对齐:右对齐”,导致 openpyxl 读取时保留了不可见空格。解决方案:在 validate_excel_data() 函数中,对所有字符串字段调用 .strip(),即 row[1].value.strip()。这个细节在任何 Django 教程里都不会提,但却是企业数据导入的日常。

坑二:ECharts 在 v-if 切换时的销毁问题
Report.vuev-if="activeTab === 'trend'" 控制图表显示,切换 Tab 时图表消失,再切回来一片空白。原因是 v-if 移除了 DOM,echarts.dispose() 未被调用,再次 init() 时 canvas 已被销毁。解决方案:改用 v-show,或在 beforeDestroy()(Vue 2)/ onBeforeUnmount()(Vue 3)钩子中显式调用 chartInstance.dispose()。源码包里 AttendanceTrendChart.vue 已采用后者,这是保障图表稳定性的必做功课。

坑三:Django Admin 的批量操作性能雪崩
在 Admin 中勾选 1000 条打卡记录点“删除”,页面卡死。原因是 Django 默认对每条记录执行 delete(),触发 1000 次数据库查询。解决方案:在 backend/attendance/admin.py 中重写 delete_queryset() 方法,用 queryset.delete() 执行单次 SQL 删除。源码包已实现此优化,删除 10 万条记录只需 2 秒。

坑四:生产环境 collectstatic 的权限问题
python manage.py collectstatic 报错 Permission denied: '/var/www/attendance/static'。这是因为 www-data 用户无权写入该目录。解决方案:sudo chown -R www-data:www-data /var/www/attendance/static,并确保 STATIC_ROOT = '/var/www/attendance/static'settings.py 中指向此路径。这个坑会让部署卡在最后一步,务必提前检查。

最后再分享一个小技巧:如果你想快速测试某个 API 接口,不必每次都启前后端。直接用 curl 模拟请求:

# 测试登录
curl -X POST http://localhost:8000/api/v1/auth/login/ \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"123456"}'

# 测试获取员工列表(需带Token)
curl -X GET http://localhost:8000/api/v1/employees/ \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

这种“命令行驱动开发”的方式,能帮你瞬间定位问题是出在前端、网络,还是后端逻辑,比在浏览器里点来点去高效十倍。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:提供一套可直接运行的考勤管理平台源码,前端基于Vue 2/3构建,包含完整的路由(router)、状态管理(store)、组件库(components)和工具函数(utils),使用Element UI实现登录页、员工列表、打卡表单、弹窗确认等常用交互;集成ECharts展示出勤率变化趋势、各部门考勤对比、迟到早退分布等可视化图表;后端采用Django框架,涵盖用户认证、部门与员工信息维护、打卡记录CRUD、Excel批量导入导出(附system_initialize.xlsx初始化模板)等功能;前后端完全分离,API接口定义清晰,支持CORS跨域调试;含vue.config.js、babel.config.js、数据库初始化脚本、README文档及dist打包产物,适配二次开发或高校课程实训。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

更多推荐