BOSS 直聘仿写项目实战:管理端企业列表与认证审核(前后端闭环)
本文是 Boss-API 系列的「企业审核篇」承接前两篇三端架构总览、求职者管理与忘记密码。前两篇把「人」侧的业务跑通了本篇聚焦「企业」侧最核心的一块管理端怎么拉企业列表、怎么审核认证、审核结果又怎么回流到企业端。涉及今天真实改过的代码后端enterprise_api.py/enterprise_service.py/models/enterprise.py前端boss-manage-ui的request.js/api/enterprise.js/Companies.vue/CertificationList.vue/CertificationAudit.vue以及企业端boss-company-ui的认证页。所有代码均来自联调现场含踩坑记录。一、这个 feature 要解决什么一个招聘平台得让企业来「认证」。整条链路是企业端提交认证资料 ── 写「企业信息表」(t_enterprise_info) │ ▼ 管理端看到待审企业列表 ── 审核员点开详情、看资质材料 │ ▼ 审核通过 / 驳回 ── 写「企业审核表」(t_enterprise_review) 更新企业主表状态 │ ▼ 审核结果回流企业端 ── 企业登录后在认证页看到「已通过 / 已驳回 原因」这里有两张关键表职责完全不同一定要分清楚这也是今天联调时反复澄清的点表谁写什么时候写作用t_enterprise_info企业信息表企业端企业提交认证申请时存营业执照、法人、注册资本等工商资料t_enterprise_review企业审核表管理端审核员点「通过 / 驳回」时存审核结果、驳回原因、审核时间前端页面和它们的关系管理端「企业管理 / 企业认证审核」列表展示的是审核视角的数据管理端审核操作落库到审核表企业端只负责填资料、查自己这份审核结果。二、后端四张表与账号状态枚举1. 模型app/models/enterprise.py一张企业主表 三张扩展表主表用enterprise_id关联其余三张当前实现是IntField关联不是外键约束灵活但要求代码里自己判空classAccountStatus(IntEnum):账号状态NORMAL0# 正常PENDING_AUDIT1# 待审核BANNED2# 封禁REJECTED3# 已驳回审核不通过classEnterprise(Model):企业表主表idfields.IntField(pkTrue)enterprise_namefields.CharField(max_length255)enterprise_codefields.CharField(max_length100,uniqueTrue)# 企业编码account_statusfields.IntEnumField(enum_typeAccountStatus)# 0/1/2/3audit_typefields.IntEnumField(enum_typeAuditType)# 1新认证/2资质更新/3信息变更auth_timefields.DatetimeField(nullTrue)submit_timefields.DatetimeField(nullTrue)# 企业提交认证时间# ... 其余字段classEnterpriseInfo(Model):企业信息表营业执照 / 法人 / 注册资本 / 行业 / 总部地址 ...enterprise_idfields.IntField(nullTrue)unified_social_credit_codefields.CharField(max_length50,uniqueTrue)legal_representativefields.CharField(max_length100)industryfields.ForeignKeyField(models.IndustryPosition,related_nameenterprise_info_list)headquarters_addressfields.CharField(max_length512)# ...classEnterpriseQualification(Model):资质材料表营业执照图片 / 法人身份证正反面 / 联系人 ...enterprise_idfields.IntField(nullTrue)business_license_urlfields.CharField(max_length512,nullTrue)legal_id_front_urlfields.CharField(max_length512,nullTrue)legal_id_back_urlfields.CharField(max_length512,nullTrue)# ...classEnterpriseReview(Model):企业审核表审核结果 / 驳回原因 / 审核时间 / 审核人enterprise_idfields.IntField(nullTrue)review_resultfields.IntField(nullTrue)# 1通过 / 2驳回review_reasonfields.CharField(max_length512,nullTrue)audit_timefields.DatetimeField(nullTrue)audit_userfields.CharField(max_length100,nullTrue)重点AccountStatus有 4 个值0/1/2/3。今天联调时踩过一个大坑——审核驳回后前端枚举只画了 0/1/2 三态导致「已驳回」的企业在列表/详情里状态显示成「未知」。枚举一加全前端映射也要同步加3: 已驳回。2. 三个核心接口app/apis/enterprise_api.pyenterprise_routerAPIRouter(prefix/enterprise,tags[企业管理])enterprise_router.get(/list)# 企业列表管理端/审核页共用asyncdefselect_enterprise_list(page:intQuery(1,ge1),page_size:intQuery(10,ge10,le50),# 注意约束最小 10、最大 50enterprise_name:strQuery(None),submit_time_start:strQuery(None),submit_time_end:strQuery(None),):resawaitEnterpriseService.select_enterprise_list(...)return{code:1,message:查询成功,data:res}enterprise_router.get(/detail/{enterprise_id})# 企业详情含审核记录asyncdefselect_enterprise_by_id(enterprise_id:int):...enterprise_router.post(/review)# 企业审核通过/驳回asyncdefenterprise_review(req:EnterpriseReviewCreateRequest):awaitEnterpriseService.enterprise_review(req)return{code:1,message:审核完成}返回统一用code: 1表示成功——和求职者端一致但和前两篇里管理端求职者查询用的code: 200不一样。这点下文明坑。3. 列表查询enterprise_service.py列表接口要做三件事分页、按需关联三张扩展表、把行业名算出来。关键在industry必须判空否则缺资料的企业会 500staticmethodasyncdefselect_enterprise_list(page,page_size,enterprise_name,submit_time_start,submit_time_end):queryEnterprise.all()ifenterprise_name:queryquery.filter(enterprise_name__icontainsenterprise_name)ifsubmit_time_start:queryquery.filter(submit_time__gtesubmit_time_start)ifsubmit_time_end:queryquery.filter(submit_time__ltesubmit_time_end)total_countawaitquery.count()total_pagemath.ceil(total_count/page_size)rowsawaitquery.offset((page-1)*page_size).limit(page_size)enterprise_list[]forenterpriseinrows:infoawaitEnterpriseInfo.get_or_none(enterprise_identerprise.id).prefetch_related(industry)qualawaitEnterpriseQualification.get_or_none(enterprise_identerprise.id)# 行业名info 或 info.industry 任一为空都不能直接 .nameindustry_nameinfo.industry.nameif(infoandgetattr(info,industry,None))elseNoneenterprise_list.append({enterprise:enterprise,enterpriseinfo:info,enterprise_qualification:qual,industry:industry_name,})return{total_count:total_count,total_page:total_page,page:page,page_size:page_size,enterprise_list:enterprise_list,}前端真正用到的就这几个字段total_count / total_page / page / page_size分页enterprise_name / enterprise_code主表industry行业名enterpriseinfo.headquarters_address总部地址。4. 审核落库enterprise_review—— 写入「企业审核表」这是「审核成功后将数据写企业审核表」的那一步。注意它同时维护审核表和企业主表状态staticmethodasyncdefenterprise_review(req:EnterpriseReviewCreateRequest):enterpriseawaitEnterprise.get_or_none(idreq.enterprise_id)ifenterpriseisNone:raiseException(f企业不存在(enterprise_id{req.enterprise_id}))reviewawaitEnterpriseReview.get_or_none(enterprise_idreq.enterprise_id)ifreviewisNone:awaitEnterpriseReview.create(enterprise_idreq.enterprise_id,review_resultreq.review_result,review_reasonreq.review_reason,remarkreq.remark,audit_timenow(),)else:review.review_resultreq.review_resultorreview.review_result review.review_reasonreq.review_reasonorreview.review_reason review.remarkreq.remarkorreview.remark review.audit_timenow()awaitreview.save()ifreq.review_result1:# 通过enterprise.account_statusAccountStatus.NORMAL enterprise.auth_timenow()elifreq.review_result2:# 驳回enterprise.account_statusAccountStatus.REJECTEDawaitenterprise.save()审核通过 → 主表变「正常」且写认证时间审核驳回 → 主表变「已驳回」。审核结果本身落在t_enterprise_review。前端拿detail接口里的review字段就能知道这家企业处于什么审核状态。三、前端从「写死 mock」到「接真实接口」管理端是 Vue3 Element Plus Vite4请求统一走封装好的request.js由 Vite 的/api代理转发到后端 8000前两篇已讲这里不再展开代理配置。1. 第一步永远是「成功码对齐」utils/request.js今天第一坑响应拦截器原来写if (res.code ! 200) reject(...)但企业接口返回的是code: 1于是所有企业相关请求都被当成失败列表永远拿不到数据。改成和后端约定一致service.interceptors.response.use((response){constresresponse.data// 后端业务约定code 1 表示成功if(res.code!1){if(res.code401){/* 跳登录 */}elseElMessage.error(res.message||请求失败)returnPromise.reject(newError(res.message||Error))}returnres})经验前后端成功码必须一对一定死。本项目里求职者接口、企业接口用code:1前两篇的管理端求职者查询用code:200——同一套前端不同模块约定不同全靠request.js拦截器统一兜底别在业务页面里各写各的。2. 抽一层 APIapi/enterprise.js所有企业接口集中在一个文件页面只调语义化方法不关心 URLimportrequestfrom/utils/requestexportfunctiongetEnterpriseList(params){returnrequest({url:/enterprise/list,method:get,params})}exportfunctiongetEnterpriseDetail(enterpriseId){returnrequest({url:/enterprise/detail/${enterpriseId},method:get})}exportfunctionenterpriseReview(data){returnrequest({url:/enterprise/review,method:post,data})}3. 企业列表页Companies.vue/CertificationList.vue「企业管理」和「企业认证审核」两个列表页都接入同一个/enterprise/list。进页面onMounted就拉数据映射后端返回的嵌套结构constfetchListasync(){loading.valuetruetry{constresawaitgetEnterpriseList({page:query.page,page_size:query.page_size,enterprise_name:query.enterprise_name||undefined,submit_time_start:query.submit_time_start||undefined,submit_time_end:query.submit_time_end||undefined,})constdatares.data tableData.valuedata.enterprise_list||[]// 嵌套数组pagination.totaldata.total_count pagination.currentPagedata.page pagination.pageSizedata.page_size}finally{loading.valuefalse}}onMounted(fetchList)表格列直接吃后端的字段el-table-columnlabel企业名称template#default{ row }{{ row.enterprise.enterprise_name }}/template/el-table-columnel-table-columnlabel企业编码template#default{ row }{{ row.enterprise.enterprise_code }}/template/el-table-columnel-table-columnlabel行业template#default{ row }{{ row.industry || - }}/template/el-table-columnel-table-columnlabel总部地址template#default{ row }{{ row.enterpriseinfo?.headquarters_address || - }}/template/el-table-column注意row.enterpriseinfo?.headquarters_address用了可选链——因为enterpriseinfo可能为null企业没填资料时。这和后端industry判空是一对前后端都要兜底。4. 审核详情页CertificationAudit.vue—— 审核操作 回执点列表里的「审核」路由带enterprise_id跳到详情页先拉detail接口再展示资质材料营业执照 / 法人身份证正反面用el-image预览和「当前审核记录」横幅来自review字段。通过 / 驳回后不再直接跳走而是展示一张回执卡consthandleApproveasync(){awaitElMessageBox.confirm(确定要通过企业${detail.enterprise.enterprise_name}的认证申请吗,审核通过确认)awaitenterpriseReview({enterprise_id:Number(route.params.id),review_result:1,// 通过remark:auditForm.remark||undefined,})buildReceipt(通过)// 展示回执操作/企业/时间 已通知企业}驳回类似多带review_reason。四、打通「管理端审核 → 企业端查看」闭环审核不是管理端自嗨结果得让企业端看到。链路是企业端提交认证 →t_enterprise_info落库主表account_status 1待审核管理端审核通过/驳回 →t_enterprise_review落库 主表状态变0/3企业端登录后认证页用 JWT 里的enterprise_id调GET /enterprise/detail/{id}读review.review_result和account_status决定显示什么// boss-company-ui/.../Certification.vueconstfetchAuthStatusasync(){constidgetEnterpriseIdFromToken()// JWT payload.user_id enterprise_idconst{data}awaitgetEnterpriseDetail(id)constrdata.reviewif(rr.review_result2)showRejected(r.review_reason)// 已驳回 原因elseif(data.enterprise.account_status0||(rr.review_result1))showApproved(data.enterprise.auth_time)elseif(data.enterprise.account_status1)showPending()// 待审核}这样企业被驳回后重新提交、被通过后立即看到认证时间整条审核业务就闭环了。五、本期踩坑合集全是真事成功码不一致所有请求被当失败拦截器按code ! 200判错但企业接口返回code: 1列表永不渲染。前后端成功码必须约定一致本项目企业/求职者接口用1管理端另一查询用200靠拦截器统一兜底。关联查询取到 None 还取属性 → 500enterpriseinfo.industry.name在「缺企业信息 / 行业没关联」时直接AttributeError。列表和详情都要先判空industry_name info.industry.name if (info and info.industry) else None。前端对应用row.enterpriseinfo?.xxx可选链。审核驳回状态没进枚举 → 前端显示「未知」AccountStatus加了REJECTED 3但前端状态映射只画了 0/1/2已驳回企业状态列变「未知」。枚举一改前端三处映射列表 / 详情 / 企业端都要同步加3: 已驳回。孤儿数据导致审核接口 500企业主表记录丢失只剩审核表孤儿记录Enterprise.get_or_none(id)返回None后面enterprise.account_status ...直接AttributeError。修复在enterprise_review/detail里把get_or_none提前、企业不存在就raise Exception(企业不存在)不再触发空指针并清理了孤儿审核记录。列表页残留 mock 数据数据「全部不对」CertificationList.vue企业认证审核列表一度还是写死的假数组auditList里 “某某信息科技有限公司” 之类从不调接口所以页面数据全是假的。排查顺序先看页面用的是不是真实接口、再看接口成功码、再看字段映射、最后看是否 mock 没清。分页参数约束后端page_size约束ge10, le50前端默认 10、可选 [10,20,50]。前端若传 1 或 100 会被后端Query校验直接拒列表拉不到分页。六、整条链路串一遍【企业提交】企业端填表 → POST /enterprise/save → t_enterprise_info t_enterprise_qualification主表 account_status1(待审核) ↓ 【管理端看列表】GET /enterprise/list?pageenterprise_namesubmit_time_* → 分页列表真实数据 ↓ 【管理端审核】点「审核」→ GET /enterprise/detail/{id} 看资质材料 → POST /enterprise/review {review_result:1|2} ↓ 后端写 t_enterprise_review 主表 account_status0(通过)/3(驳回) ↓ 【企业端查看】企业登录 → GET /enterprise/detail/{id} → 读 review.review_result / account_status ↓ 展示已通过(认证时间) / 已驳回(原因) / 待审核七、小结企业侧审核功能本质是「两表分工 一个状态机」两表分工企业信息表t_enterprise_info由企业端写、存资料企业审核表t_enterprise_review由管理端写、存结果。一个状态机企业主表account_status在待审核(1) → 正常(0) / 已驳回(3)之间流转封禁(2) 是运营后续动作。落到代码上还是前两篇反复说的那套范式接口成功码对齐 → 关联查询判空兜底 → 枚举前后端同步 → mock 数据必须清零 → 孤儿/不一致数据提前拦。把企业列表和审核这个闭环吃透一个招聘平台「企业侧」最硬的一块骨头就啃下来了。本文基于真实 FastAPI Vue3 项目整理敏感密钥已脱敏。FastAPI / Tortoise-ORM / Element Plus / Vite 文档以官方最新版为准。

相关新闻

E语言函数参数详解:从基础到高级应用

E语言函数参数详解:从基础到高级应用

1. E语言函数参数基础概念解析E语言作为一门面向中文开发者的编程语言,其函数参数设计充分考虑了中文思维习惯。与主流编程语言相比,E语言的参数传递机制既有相似之处也有独特设计。我们先从最基础的参数定义开始:函数 加法运算(参数1 数值型…

2026/7/29 2:20:11 阅读更多 →
DeepSeek结合ArcGIS Pro批量建库

DeepSeek结合ArcGIS Pro批量建库

要实现基于Excel提供的字段结构模板批量添加字段到GDB数据库要素类的功能,可以使用Python结合ArcPy库来完成。以下是实现步骤和代码示例: 1. 脚本工具箱设计 输入参数: 输入Excel文件路径(包含字段结构模板) 目标GDB数据库路径 目标要素类名称 输出: 在目标GDB数据库中…

2026/7/29 2:19:10 阅读更多 →
【RT-DETR多模态创新改进】ACM 2025顶会 | 全网独家、特征融合创新篇 | 引入DAAttn差异感知注意力融合模块,通过动态调整注意力,使模型更准确地识别关键内容,提高精度、并减少冗余计算

【RT-DETR多模态创新改进】ACM 2025顶会 | 全网独家、特征融合创新篇 | 引入DAAttn差异感知注意力融合模块,通过动态调整注意力,使模型更准确地识别关键内容,提高精度、并减少冗余计算

一、本文介绍 🔥本文给大家介绍使用 DAAttn 差异感知注意力融合模块改进RT-DETR多模态网络模型,模型能够在变化检测任务中更精确地识别目标,尤其是在复杂背景和微小变化的情况下。它能够提高RT-DETR多模态网络模型的精度、鲁棒性,并减少无关噪声的影响,提升小目标和细节…

2026/7/29 2:19:10 阅读更多 →

最新新闻

PUBG罗技鼠标宏压枪脚本:5分钟快速配置终极指南

PUBG罗技鼠标宏压枪脚本:5分钟快速配置终极指南

PUBG罗技鼠标宏压枪脚本:5分钟快速配置终极指南 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 还在为PUBG中难以控制的武器后坐力而…

2026/7/29 2:26:12 阅读更多 →
分布式事务一致性解决方案对比

分布式事务一致性解决方案对比

分布式事务一致性解决方案对比在微服务架构与分布式系统日益普及的今天,业务逻辑往往跨越多个独立的服务与数据库。如何保证跨服务的数据操作具备原子性、一致性、隔离性和持久性(ACID),成为系统设计的关键挑战。分布式事务一致性…

2026/7/29 2:26:12 阅读更多 →
SQL执行计划解读与调优案例

SQL执行计划解读与调优案例

SQL执行计划解读与调优案例在数据库性能优化领域,SQL执行计划无疑是一张至关重要的“地图”与“诊断报告”。它清晰地揭示了数据库优化器如何执行一条SQL语句,包括访问数据的方式、表连接的顺序与算法、过滤条件的应用时机等核心细节。理解并掌握执行计划…

2026/7/29 2:26:12 阅读更多 →
解析2026年HDMI矩阵销售市场:选对厂家,掌握视听新趋势

解析2026年HDMI矩阵销售市场:选对厂家,掌握视听新趋势

在数字化与智能化浪潮席卷各行各业的今天,优质的视听信号管理与传输系统,已经成为会议室、指挥中心、展厅乃至智慧教育场景的“神经中枢”。HDMI矩阵作为其中的关键设备,其市场在2024年已展现出强劲的增长潜力,预计到2026年&#…

2026/7/29 2:26:12 阅读更多 →
从零构建漫威主题激光对抗机器人:Arduino控制与差速转向实战

从零构建漫威主题激光对抗机器人:Arduino控制与差速转向实战

1. 项目缘起:从“玩具”到“工程”的跃迁几年前,我在一个创客展上看到一群孩子围着一台能发射红外光点的履带小车玩得不亦乐乎。那台小车结构简单,动作迟缓,所谓的“攻击”也仅仅是点亮一个LED灯。当时我就在想,如果把…

2026/7/29 2:26:12 阅读更多 →
ESP32-S3 MicroPython人脸检测实战:从固件烧录到算法部署全解析

ESP32-S3 MicroPython人脸检测实战:从固件烧录到算法部署全解析

1. 项目概述:当行空板K10遇上人脸检测最近在捣鼓一块叫行空板K10的开发板,它核心是一颗ESP32-S3芯片,自带摄像头和屏幕,官方主推用Mind图形化编程,但对我这种习惯了代码的老手来说,总想试试它的“硬核”玩法…

2026/7/29 2:25:12 阅读更多 →

日新闻

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:00:23 阅读更多 →
AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础 在上一期「AI编程系列」中,我们学习了如何构建一个基础的 AI 问答系统,通过简单的输入输出让模型回应问题。但现实世界中的 AI 应用往往需要处理更复杂的场景:…

2026/7/29 0:00:23 阅读更多 →
AI智能体开发实战:从工具调用到企业级部署

AI智能体开发实战:从工具调用到企业级部署

1. 从被动问答到主动执行:AI Agent的范式转变过去两年,大语言模型最显著的应用形态是聊天机器人——用户提问,AI回答。但真正的生产力革命发生在2023年下半年:当AI学会主动调用工具完成任务时,生产力工具的历史被彻底改…

2026/7/29 0:00:23 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/28 12:04:22 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/28 8:29:16 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/28 5:03:42 阅读更多 →

月新闻