Initial commit: obsidian to gitea
This commit is contained in:
418
study/courses/pm/frontend.md
Normal file
418
study/courses/pm/frontend.md
Normal file
@@ -0,0 +1,418 @@
|
||||
# 招聘试题定制平台 · 手机 APP 页面与 Figma Prompt 设计
|
||||
|
||||
> 面向「业务场景 1:基于手机的招聘代理平台」,这里设计两端:
|
||||
>
|
||||
> * **应聘者 App(Candidate App)**
|
||||
> * **招聘企业 HR App(HR App)**
|
||||
> 平台管理员一般用 Web 后台,这里不再设计移动端。
|
||||
|
||||
---
|
||||
|
||||
## 1. 手机 App 页面信息架构
|
||||
|
||||
### 1.1 应聘者 App(Candidate App)
|
||||
|
||||
> 典型用户路径:登录 → 浏览岗位 → 参加考试 → 查看结果 → 反馈试题。
|
||||
|
||||
1. **C0 欢迎 / 登录 / 注册页**
|
||||
|
||||
* Tab:登录 / 注册
|
||||
* 支持第三方登录(可选)
|
||||
|
||||
2. **C1 岗位列表页(职位发现)**
|
||||
|
||||
* 顶部搜索栏
|
||||
* 筛选条件:技术方向、城市、经验要求等
|
||||
* 卡片:岗位名称、公司名、标签、一个「查看详情 / 去测试」按钮
|
||||
|
||||
3. **C2 岗位详情 & 考试入口页**
|
||||
|
||||
* 展示岗位描述、能力要求、薪资范围(可选)
|
||||
* 显示「本岗位在线测试信息」(题量、时长、截止时间)
|
||||
* 主按钮:「开始在线测试」或「继续测试」
|
||||
|
||||
4. **C3 我的考试列表页**
|
||||
|
||||
* Tab:全部 / 未开始 / 进行中 / 已完成
|
||||
* 每条:岗位名、考试批次、状态、截止时间、入口按钮
|
||||
|
||||
5. **C4 在线考试页(核心)**
|
||||
|
||||
* 顶部固定栏:返回按钮 + 考试标题 + 倒计时
|
||||
* 中部:当前题目
|
||||
|
||||
* 题号、题型、分值
|
||||
* 题干 + 附件区域
|
||||
* 答题控件(单选/多选/文本/代码文本框等)
|
||||
* 底部:
|
||||
|
||||
* 题目导航滑动条(题号圆点,不同状态颜色)
|
||||
* 上一题 / 下一题按钮
|
||||
* 悬浮主按钮:提交试卷(弹出确认对话框)
|
||||
|
||||
6. **C5 考试结果页**
|
||||
|
||||
* 大号分数 + 通过/未通过状态
|
||||
* 子卡片:总分、平均分、排名/百分位(可选)
|
||||
* 能力维度雷达图 / 条形图(可选)
|
||||
* 按钮:「查看详细解析」/「查看题目列表」
|
||||
|
||||
7. **C6 题目解析与反馈页**
|
||||
|
||||
* 顶部:题目 + 正确答案 + 你的答案 + 解析
|
||||
* 底部:反馈卡片
|
||||
|
||||
* 点评:题目是否清晰 / 难度是否合适(星级/表情)
|
||||
* 文本输入框:补充意见
|
||||
* 提交按钮
|
||||
|
||||
8. **C7 个人中心 / 设置页**
|
||||
|
||||
* 基本信息、技能标签展示
|
||||
* 考试历史入口
|
||||
* 通知设置、隐私、退出登录
|
||||
|
||||
---
|
||||
|
||||
### 1.2 招聘企业 HR App(HR App)
|
||||
|
||||
> 偏「移动监控 & 轻量管理」,重分析 / 复盘 / 小改动,而不是在手机上做复杂配置。
|
||||
|
||||
1. **H0 HR 登录 / 切换企业页**
|
||||
|
||||
* 登录、忘记密码
|
||||
* (多租户时)选择企业/组织
|
||||
|
||||
2. **H1 HR 首页仪表盘**
|
||||
|
||||
* 顶部:公司名称 + 通知图标
|
||||
* 核心指标卡片(纵向列表):
|
||||
|
||||
* 今日参加考试人数
|
||||
* 本周通过率
|
||||
* 活跃岗位数
|
||||
* 下方:
|
||||
|
||||
* 最近考试列表(横向卡片轮播)
|
||||
* 「有问题的题目」提醒入口
|
||||
|
||||
3. **H2 岗位列表页**
|
||||
|
||||
* 搜索 + 筛选(状态:招聘中 / 暂停 / 已关闭)
|
||||
* 岗位卡片:岗位名、级别、最近考试人数、通过率
|
||||
* 右下角悬浮按钮:「新建岗位」(进入简化版编辑流程)
|
||||
|
||||
4. **H3 岗位详情页**
|
||||
|
||||
* 基本信息:岗位名称、级别、城市、要求技能标签
|
||||
* 近期考试概览:最近 N 次考试的平均分/通过率
|
||||
* 按钮:
|
||||
|
||||
* 查看全部考试
|
||||
* 编辑岗位(跳 H4)
|
||||
* 预览试卷配置(跳 H5)
|
||||
|
||||
5. **H4 岗位快速编辑页(移动简化版)**
|
||||
|
||||
* 可编辑字段:岗位名称、级别、标签、是否开放招聘等
|
||||
* 考试策略部分仅支持选择已有策略,不在手机上做复杂编辑
|
||||
* 底部:取消 / 保存 按钮
|
||||
|
||||
6. **H5 试卷预览页**
|
||||
|
||||
* 展示系统为该岗位生成的一套样卷
|
||||
* 按题型分组(单选、多选、编程等)
|
||||
* 可「锁定/解锁」某些题目(锁定后 PC 端配置时保留)
|
||||
|
||||
7. **H6 考试结果分析页(移动版)**
|
||||
|
||||
* 顶部筛选条:岗位下拉 + 考试批次 + 时间区间
|
||||
* 上半部分:KPI 卡片(平均分、通过率、参加人数)
|
||||
* 下半部分:
|
||||
|
||||
* 简化图表(柱状图/折线图)
|
||||
* 题目正确率列表(Top 问题 / Bottom 问题)
|
||||
|
||||
8. **H7 题目质量列表页**
|
||||
|
||||
* 列表项:题干摘要、技能标签、质量分、使用次数、状态
|
||||
* 支持按照质量分排序/筛选
|
||||
* 点击进入 H8
|
||||
|
||||
9. **H8 题目质量详情页**
|
||||
|
||||
* 展示具体题目内容、标准答案、解析
|
||||
* 统计:使用次数、正确率、区分度、反馈分
|
||||
* 操作按钮:标记“待修改”、标记“建议淘汰”
|
||||
|
||||
10. **H9 HR 个人设置页**
|
||||
|
||||
* 个人信息、企业信息简略查看
|
||||
* 通知开关
|
||||
* 退出登录
|
||||
|
||||
---
|
||||
|
||||
## 2. 手机端关键页面草图(文字线框)
|
||||
|
||||
### 2.1 C4 在线考试页(Candidate Exam)
|
||||
|
||||
屏幕:手机竖屏(iPhone 15 / 390×844)
|
||||
|
||||
* **顶部固定栏**
|
||||
|
||||
* 左:返回图标(←)
|
||||
* 中:考试标题(单行,超出省略号)
|
||||
* 右:倒计时(红色/醒目字体,例如「53:21」)
|
||||
|
||||
* **中部内容区(Scroll)**
|
||||
|
||||
* 题目信息行:
|
||||
|
||||
* 「第 3 题」+ 标签「单选」「3 分」
|
||||
* 主卡片:
|
||||
|
||||
* 题干文本(可多行)
|
||||
* 若有图片/代码块,在题干下方单独容器显示
|
||||
* 答题控件:
|
||||
|
||||
* 单选:Radio 列表,每个选项为卡片式按钮
|
||||
* 多选:Checkbox 列表
|
||||
* 填空/主观题:多行文本输入框
|
||||
|
||||
* **底部固定区域**
|
||||
|
||||
* 上半:题号导航(水平滑动)
|
||||
|
||||
* 一排圆形按钮:1 2 3 4 5 …
|
||||
* 已答:填充主色;未答:边框灰色;标记:角落有小点
|
||||
* 下半:底部按钮栏
|
||||
|
||||
* 左按钮:「上一题」(次要)
|
||||
* 中按钮:标记/取消标记
|
||||
* 右按钮:「下一题」(主要)
|
||||
* 右上角悬浮按钮或顶部菜单中放「交卷」按钮。
|
||||
|
||||
---
|
||||
|
||||
### 2.2 C5 结果页(Candidate Result)
|
||||
|
||||
* 顶部:大号分数(如「83 分」)+ 状态标签(绿色「通过」/ 红色「未通过」)
|
||||
* 下方两列/纵向卡片:
|
||||
|
||||
* 卡片 1:考试信息(岗位名、日期、用时)
|
||||
* 卡片 2:得分拆分(选择题分数、编程题分数等)
|
||||
* 中部:简化图表/可视化(可在 Figma 中用假图表示)
|
||||
* 底部按钮:
|
||||
|
||||
* 主按钮:「查看题目解析」
|
||||
* 次按钮:「返回岗位列表」
|
||||
|
||||
---
|
||||
|
||||
### 2.3 H1 HR 首页仪表盘(Mobile)
|
||||
|
||||
* 顶部 AppBar:
|
||||
|
||||
* 左:企业 Logo/图标 + 公司名
|
||||
* 右:通知铃铛 + 头像
|
||||
|
||||
* 主内容(纵向 Scroll):
|
||||
|
||||
1. 指标卡片区域(左右滑动或纵向堆叠):
|
||||
|
||||
* 今日参加考试人数
|
||||
* 本周通过率
|
||||
* 活跃岗位数
|
||||
2. 模块「最近考试」:
|
||||
|
||||
* 卡片列表:岗位名 + 时间 + 参加人数 + 通过率
|
||||
3. 模块「有问题的题目」:
|
||||
|
||||
* 小卡片:题干摘要 + “低正确率”“低反馈分”标签
|
||||
* 点击跳转到 H7/H8
|
||||
|
||||
---
|
||||
|
||||
### 2.4 H6 HR 考试结果分析页(Mobile)
|
||||
|
||||
* 顶部筛选条(横向滚动):
|
||||
|
||||
* 下拉:岗位
|
||||
* 下拉:考试批次
|
||||
* 日期选择按钮
|
||||
* 「应用」按钮
|
||||
|
||||
* 主内容:
|
||||
|
||||
* KPI 卡片区域:平均分 / 通过率 / 参加人数(3 个小卡)
|
||||
* 小图表区:
|
||||
|
||||
* 迷你折线图(七天平均分)
|
||||
* 柱状图(分数段人数)
|
||||
* 底部:考生列表(简化表格样式卡片):
|
||||
|
||||
* 姓名、得分、提交时间、详情图标
|
||||
|
||||
---
|
||||
|
||||
## 3. Figma AI / Figma Make Prompt(手机 App 版本)
|
||||
|
||||
> 建议用英文 Prompt,让 Figma 的 AI 更稳定。下面提供:
|
||||
> 1)一个「多屏手机 App Flow」总 prompt;
|
||||
> 2)一个「单屏模板」,方便你逐屏生成。
|
||||
|
||||
---
|
||||
|
||||
### 3.1 全局样式片段(可直接粘在每个 prompt 前)
|
||||
|
||||
```text
|
||||
Design a modern mobile app UI for a recruitment test platform called “SmartHire Test”.
|
||||
|
||||
Platform:
|
||||
- iOS and Android, focus on iPhone 15 size (390 x 844) in portrait.
|
||||
Visual style:
|
||||
- Clean, professional, light theme.
|
||||
- Primary color #2563EB (blue), neutral grays, lots of white space.
|
||||
- Rounded corners (10–16px), soft shadows for cards.
|
||||
- Use a standard mobile tab bar or bottom navigation where it makes sense.
|
||||
Typography similar to SF Pro / Inter / Roboto.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 多屏 Candidate & HR App Flow Prompt(推荐)
|
||||
|
||||
```text
|
||||
You are designing a mobile app for a customizable recruitment test platform called “SmartHire Test”.
|
||||
|
||||
Use iPhone 15 portrait frames (390 x 844).
|
||||
Apply a modern, clean, light theme with primary color #2563EB and rounded cards.
|
||||
|
||||
Create the following screens. Name each frame with the given screen name.
|
||||
|
||||
1. Screen: "C0 Candidate Welcome & Login"
|
||||
- A welcome illustration or simple brand panel at the top.
|
||||
- Tabs or segmented control for "Sign in" and "Sign up".
|
||||
- Email and password fields, "Sign in" primary button, and "Forgot password" link.
|
||||
- Optional third-party login buttons at the bottom.
|
||||
|
||||
2. Screen: "C1 Candidate Job List"
|
||||
- Top app bar with logo "SmartHire Test" and a small profile avatar.
|
||||
- Search bar at the top of the content.
|
||||
- Horizontal chips for filters (e.g. Skills, City, Level).
|
||||
- Vertical list of job cards: each card shows job title, company, tags, and a primary button "View details" or "Take test".
|
||||
|
||||
3. Screen: "C2 Candidate Job Detail"
|
||||
- Job title, company, level, location at the top.
|
||||
- Section for job description and required skills (tags).
|
||||
- Section "Online test for this job" with chips indicating number of questions, duration, and difficulty.
|
||||
- A primary CTA button at the bottom: "Start test" or "Continue test".
|
||||
|
||||
4. Screen: "C3 Candidate Exam List"
|
||||
- Simple tab bar at the top for "All", "Active", "Completed".
|
||||
- List items showing: job title, exam name, status badge, deadline, and a chevron or button to open the exam.
|
||||
|
||||
5. Screen: "C4 Candidate Online Exam"
|
||||
- Fixed top bar with back arrow, exam title in the center, and a countdown timer on the right.
|
||||
- Main scroll area:
|
||||
- Row with "Question 3" label, pill badges for type (Single choice) and score (3 pts).
|
||||
- Card with question text and optional image placeholder.
|
||||
- Answer area: radio buttons or selection cards for options.
|
||||
- Bottom fixed area:
|
||||
- First row: horizontally scrollable question number chips (1, 2, 3, ...), with different states for answered / not answered / flagged.
|
||||
- Second row: three buttons "Previous", "Flag", "Next" (primary on "Next").
|
||||
- A secondary icon or button to "Submit exam" that opens a confirmation dialog.
|
||||
|
||||
6. Screen: "C5 Candidate Result"
|
||||
- Large score display at the top (e.g., "83/100") and a badge indicating Pass or Fail.
|
||||
- Summary cards for "Total score", "Average score", "Percentile" or "Rank".
|
||||
- A simple chart area (score distribution or skill radar) using placeholder graphics.
|
||||
- A section "Question review" with a list of questions and icons for correct / incorrect.
|
||||
- Bottom primary button: "View detailed explanations".
|
||||
|
||||
7. Screen: "C6 Candidate Question Review & Feedback"
|
||||
- Top shows the current question text, correct answer, and the candidate's answer.
|
||||
- Below, a small explanation text block.
|
||||
- At the bottom, a feedback card:
|
||||
- Star rating or 1–5 scale for "Clarity" and "Difficulty".
|
||||
- A multiline text field for additional comments.
|
||||
- Primary button "Submit feedback".
|
||||
|
||||
8. Screen: "H0 HR Login"
|
||||
- Simple login screen for HR users, consistent style with candidate login but with "HR" emphasis in the title.
|
||||
|
||||
9. Screen: "H1 HR Home Dashboard"
|
||||
- Top app bar with company name and notification icon.
|
||||
- A vertical stack of KPI cards: "Today’s test takers", "This week pass rate", "Active positions".
|
||||
- Section "Recent exams": small cards with job title, date, participants, pass rate.
|
||||
- Section "Problematic questions": list items with a short question snippet and a warning badge.
|
||||
|
||||
10. Screen: "H2 HR Job List"
|
||||
- List of job cards with job title, level, status badge, and small stats (last exam participants / pass rate).
|
||||
- Floating action button at the bottom-right: "+" to create a new job.
|
||||
|
||||
11. Screen: "H3 HR Job Detail"
|
||||
- Job header with title, level, and status tag.
|
||||
- Sections:
|
||||
- Basic info (location, department).
|
||||
- Required skills (tags).
|
||||
- Latest exam summary (average score, pass rate).
|
||||
- Buttons at the bottom: "View exams", "Quick edit".
|
||||
|
||||
12. Screen: "H6 HR Exam Analytics"
|
||||
- Filter bar at the top with dropdowns for job and exam batch and a date-range pill.
|
||||
- KPI cards for average score, pass rate, number of candidates.
|
||||
- Simple mini chart (histogram or line chart) to show score distribution.
|
||||
- List of candidate results as cards (name, score, submitted time, chevron for details).
|
||||
|
||||
13. Screen: "H7 HR Question Quality List"
|
||||
- Search bar and filter chips (by skill, difficulty, quality score).
|
||||
- Vertical list of question items: each with a short question text, skill tag, usage count, quality score, and status.
|
||||
- Tapping an item leads to H8.
|
||||
|
||||
14. Screen: "H8 HR Question Quality Detail"
|
||||
- Top: full question text and answer options.
|
||||
- Below: a stats card with usage count, average score, correct rate, discrimination, feedback score.
|
||||
- Actions at the bottom: outlined button "Mark for review", primary button "Suggest deprecation".
|
||||
|
||||
Across all screens:
|
||||
- Use consistent mobile navigation and components.
|
||||
- Use clear hierarchy, spacing, and tappable elements sized for touch.
|
||||
- Create a simple prototype flow: candidate screens connected by a logical path, and HR screens connected separately.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 单屏 Mobile Prompt 模板(可按需复用)
|
||||
|
||||
```text
|
||||
Design a single mobile screen for the “SmartHire Test” app.
|
||||
|
||||
Target device:
|
||||
- iPhone 15 in portrait (390 x 844).
|
||||
|
||||
Visual style:
|
||||
- Modern, clean, light theme.
|
||||
- Primary color #2563EB, neutral gray background, rounded cards.
|
||||
- Typography similar to SF Pro / Inter.
|
||||
|
||||
Screen name: {{SCREEN_NAME}}
|
||||
|
||||
Screen description:
|
||||
{{DETAILED_DESCRIPTION_HERE}}
|
||||
|
||||
Use clear sections and card components. Make all interactive elements touch friendly (at least 44x44 points).
|
||||
```
|
||||
|
||||
示例:如果你只想生成「C4 Candidate Online Exam」这一屏,就把 `{{SCREEN_NAME}}` 换掉,然后写一段 description(你可以直接用我上面 C4 的说明)。
|
||||
|
||||
---
|
||||
|
||||
如果你确认这套 **手机端页面列表 + 草图 + Figma Prompt** 没问题,我可以下一步帮你把:
|
||||
|
||||
-「Web + App 前端设计章节」
|
||||
|
||||
* 和前面系统设计(UML + 数据库 + 算法)
|
||||
|
||||
统一成一份完整的课程项目系统设计报告。
|
||||
85
study/courses/pm/report.figs/.$use-case.drawio.bkp
Normal file
85
study/courses/pm/report.figs/.$use-case.drawio.bkp
Normal file
@@ -0,0 +1,85 @@
|
||||
<mxfile host="Electron" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/28.2.8 Chrome/140.0.7339.240 Electron/38.4.0 Safari/537.36" version="28.2.8">
|
||||
<diagram name="Page-1" id="page-1">
|
||||
<mxGraphModel dx="784" dy="671" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="6" value="配置岗位需求" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="120" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7" value="配置试题策略" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="180" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9" value="在线答题" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="360" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="10" value="查看成绩与统计" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="240" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="11" value="提交试题反馈" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="300" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="12" value="题库管理与题目淘汰" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="420" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="13" value="企业接入与运营配置" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="490" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="14" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=0;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-22" target="6" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="170" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="15" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=0;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-22" target="7" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="170" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="16" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=0;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-22" target="10" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="170" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="17" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=0;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-22" target="11" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="170" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="18" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=1;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-23" target="9" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="650" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="19" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=1;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-23" target="10" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="650" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="20" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=1;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-23" target="11" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="650" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="21" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-27" target="12" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="410" y="490" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="22" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-27" target="13" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="410" y="490" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="dYsEw_TpROWio0KKOCtD-22" value="招聘企业 HR" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" vertex="1" parent="1">
|
||||
<mxGeometry x="130" y="210" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="dYsEw_TpROWio0KKOCtD-23" value="应聘者" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;fillColor=#f0a30a;fontColor=#000000;strokeColor=#BD7000;" vertex="1" parent="1">
|
||||
<mxGeometry x="440" y="295" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="dYsEw_TpROWio0KKOCtD-27" value="平台管理员" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;fillColor=#f0a30a;fontColor=#000000;strokeColor=#BD7000;" vertex="1" parent="1">
|
||||
<mxGeometry x="440" y="450" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
43
study/courses/pm/report.figs/activity.mmd
Normal file
43
study/courses/pm/report.figs/activity.mmd
Normal file
@@ -0,0 +1,43 @@
|
||||
flowchart TD
|
||||
%% ======== 样式定义 ========
|
||||
classDef roleHR fill:#fff7e6,stroke:#fa8c16,stroke-width:1px;
|
||||
classDef roleCandidate fill:#e6fffb,stroke:#13c2c2,stroke-width:1px;
|
||||
classDef roleSystem fill:#f0f5ff,stroke:#2f54eb,stroke-width:1px;
|
||||
|
||||
%% ======== 开始与结束 ========
|
||||
Start([开始])
|
||||
End([结束])
|
||||
|
||||
%% ======== HR 泳道 ========
|
||||
subgraph HRLane[招聘企业 HR]
|
||||
HR1[填写岗位需求<br/>与能力要求]:::roleHR
|
||||
HR2[配置试题策略]:::roleHR
|
||||
HR3[查看考试统计报表]:::roleHR
|
||||
HR4[评价试题质量与效果]:::roleHR
|
||||
end
|
||||
|
||||
%% ======== 平台后端 泳道 ========
|
||||
subgraph SystemLane[平台后端]
|
||||
S1[解析岗位并抽取技能标签]:::roleSystem
|
||||
S2[生成试卷模板]:::roleSystem
|
||||
S3[为候选人实例化试卷]:::roleSystem
|
||||
S4[记录作答过程与答案]:::roleSystem
|
||||
S5[自动评分并生成结果]:::roleSystem
|
||||
S6[更新题目统计指标]:::roleSystem
|
||||
S7[判定题目是否进入淘汰池]:::roleSystem
|
||||
end
|
||||
|
||||
%% ======== 应聘者 泳道 ========
|
||||
subgraph CandLane[应聘者 Candidate]
|
||||
C1[注册 / 登录]:::roleCandidate
|
||||
C2[选择岗位并领取试卷]:::roleCandidate
|
||||
C3[在线作答]:::roleCandidate
|
||||
C4[查看成绩与解析]:::roleCandidate
|
||||
C5[填写试题反馈]:::roleCandidate
|
||||
end
|
||||
|
||||
%% ======== 活动流转 ========
|
||||
Start --> HR1 --> S1 --> S2 --> HR2 --> S3
|
||||
S3 --> C1 --> C2 --> C3 --> S4 --> S5 --> C4 --> C5 --> S6
|
||||
S6 --> HR3 --> HR4 --> S6
|
||||
S6 --> S7 --> End
|
||||
BIN
study/courses/pm/report.figs/activity.png
Normal file
BIN
study/courses/pm/report.figs/activity.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 286 KiB |
114
study/courses/pm/report.figs/class.mmd
Normal file
114
study/courses/pm/report.figs/class.mmd
Normal file
@@ -0,0 +1,114 @@
|
||||
classDiagram
|
||||
class User {
|
||||
+int id
|
||||
+string name
|
||||
+string email
|
||||
+string role // HR, CANDIDATE, ADMIN
|
||||
+datetime createdAt
|
||||
}
|
||||
|
||||
class Company {
|
||||
+int id
|
||||
+string name
|
||||
+string industry
|
||||
+string size
|
||||
}
|
||||
|
||||
class CandidateProfile {
|
||||
+int id
|
||||
+int userId
|
||||
+string degree
|
||||
+int yearsExperience
|
||||
+string skillTags
|
||||
+string resumeUrl
|
||||
}
|
||||
|
||||
class JobPosition {
|
||||
+int id
|
||||
+int companyId
|
||||
+string title
|
||||
+string level
|
||||
+string requiredSkills
|
||||
+string description
|
||||
+string examPolicyId
|
||||
}
|
||||
|
||||
class ExamPolicy {
|
||||
+string id
|
||||
+int totalQuestions
|
||||
+float easyRatio
|
||||
+float mediumRatio
|
||||
+float hardRatio
|
||||
+string typeRatio // JSON: 单选/多选/编程 等比例
|
||||
}
|
||||
|
||||
class Question {
|
||||
+int id
|
||||
+string content
|
||||
+string type
|
||||
+string skillTag
|
||||
+int difficulty
|
||||
+string source // 企业题/通用题
|
||||
+bool isActive
|
||||
}
|
||||
|
||||
class QuestionStats {
|
||||
+int questionId
|
||||
+int usedCount
|
||||
+float avgScore
|
||||
+float correctRate
|
||||
+float discrimination
|
||||
+float feedbackScore
|
||||
+datetime lastUsedAt
|
||||
}
|
||||
|
||||
class ExamTemplate {
|
||||
+int id
|
||||
+int jobId
|
||||
+string policyId
|
||||
+string questionSlots // JSON: 题目占位信息
|
||||
}
|
||||
|
||||
class ExamSession {
|
||||
+int id
|
||||
+int candidateId
|
||||
+int jobId
|
||||
+int templateId
|
||||
+datetime startTime
|
||||
+datetime submitTime
|
||||
+float totalScore
|
||||
+string status // ONGOING / DONE
|
||||
}
|
||||
|
||||
class Answer {
|
||||
+int id
|
||||
+int sessionId
|
||||
+int questionId
|
||||
+string content
|
||||
+float score
|
||||
+float timeTaken
|
||||
}
|
||||
|
||||
class QuestionFeedback {
|
||||
+int id
|
||||
+int questionId
|
||||
+int fromUserId
|
||||
+int sessionId
|
||||
+int rating // 1~5
|
||||
+string comment
|
||||
+datetime createdAt
|
||||
}
|
||||
|
||||
Company "1" o-- "0..*" User : employs
|
||||
User "1" o-- "0..1" CandidateProfile : has
|
||||
Company "1" o-- "0..*" JobPosition : posts
|
||||
JobPosition "1" o-- "0..*" ExamTemplate : uses
|
||||
ExamPolicy "1" o-- "0..*" ExamTemplate : governs
|
||||
|
||||
Question "1" o-- "1" QuestionStats : has
|
||||
ExamTemplate "1" o-- "0..*" ExamSession : instantiates
|
||||
CandidateProfile "1" o-- "0..*" ExamSession : takes
|
||||
ExamSession "1" o-- "0..*" Answer : contains
|
||||
Question "1" o-- "0..*" Answer : answeredIn
|
||||
Question "1" o-- "0..*" QuestionFeedback : receives
|
||||
User "1" o-- "0..*" QuestionFeedback : writes
|
||||
BIN
study/courses/pm/report.figs/class.png
Normal file
BIN
study/courses/pm/report.figs/class.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 370 KiB |
8
study/courses/pm/report.figs/convert.sh
Executable file
8
study/courses/pm/report.figs/convert.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
for f in *.mmd; do
|
||||
base=$(basename "$f" .mmd)
|
||||
echo "Converting $f → figs/${base}.png"
|
||||
mmdc -i "$f" -o "${base}.png" -s 3
|
||||
done
|
||||
|
||||
113
study/courses/pm/report.figs/er.mmd
Normal file
113
study/courses/pm/report.figs/er.mmd
Normal file
@@ -0,0 +1,113 @@
|
||||
erDiagram
|
||||
USER {
|
||||
int id
|
||||
int company_id
|
||||
string name
|
||||
string email
|
||||
string role
|
||||
}
|
||||
|
||||
COMPANY {
|
||||
int id
|
||||
string name
|
||||
string industry
|
||||
string size
|
||||
}
|
||||
|
||||
CANDIDATE_PROFILE {
|
||||
int id
|
||||
int user_id
|
||||
string degree
|
||||
int years_experience
|
||||
string skill_tags
|
||||
string resume_url
|
||||
}
|
||||
|
||||
JOB_POSITION {
|
||||
int id
|
||||
int company_id
|
||||
string title
|
||||
string level
|
||||
string required_skills
|
||||
string description
|
||||
string exam_policy_id
|
||||
}
|
||||
|
||||
EXAM_POLICY {
|
||||
string id
|
||||
int total_questions
|
||||
float easy_ratio
|
||||
float medium_ratio
|
||||
float hard_ratio
|
||||
string type_ratio
|
||||
}
|
||||
|
||||
QUESTION {
|
||||
int id
|
||||
string content
|
||||
string type
|
||||
string skill_tag
|
||||
int difficulty
|
||||
string source
|
||||
bool is_active
|
||||
}
|
||||
|
||||
QUESTION_STATS {
|
||||
int question_id
|
||||
int used_count
|
||||
float avg_score
|
||||
float correct_rate
|
||||
float discrimination
|
||||
float feedback_score
|
||||
datetime last_used_at
|
||||
}
|
||||
|
||||
EXAM_TEMPLATE {
|
||||
int id
|
||||
int job_id
|
||||
string policy_id
|
||||
string question_slots
|
||||
}
|
||||
|
||||
EXAM_SESSION {
|
||||
int id
|
||||
int candidate_id
|
||||
int job_id
|
||||
int template_id
|
||||
datetime start_time
|
||||
datetime submit_time
|
||||
float total_score
|
||||
string status
|
||||
}
|
||||
|
||||
ANSWER {
|
||||
int id
|
||||
int session_id
|
||||
int question_id
|
||||
string content
|
||||
float score
|
||||
float time_taken
|
||||
}
|
||||
|
||||
QUESTION_FEEDBACK {
|
||||
int id
|
||||
int question_id
|
||||
int from_user_id
|
||||
int session_id
|
||||
int rating
|
||||
string comment
|
||||
datetime created_at
|
||||
}
|
||||
|
||||
COMPANY ||--o{ USER : has
|
||||
USER ||--o{ CANDIDATE_PROFILE : has
|
||||
COMPANY ||--o{ JOB_POSITION : posts
|
||||
EXAM_POLICY ||--o{ JOB_POSITION : configures
|
||||
JOB_POSITION ||--o{ EXAM_TEMPLATE : uses
|
||||
EXAM_TEMPLATE ||--o{ EXAM_SESSION : instantiates
|
||||
USER ||--o{ EXAM_SESSION : takes
|
||||
EXAM_SESSION ||--o{ ANSWER : contains
|
||||
QUESTION ||--o{ ANSWER : answered_in
|
||||
QUESTION ||--|| QUESTION_STATS : stats
|
||||
QUESTION ||--o{ QUESTION_FEEDBACK : receives
|
||||
USER ||--o{ QUESTION_FEEDBACK : writes
|
||||
BIN
study/courses/pm/report.figs/er.png
Normal file
BIN
study/courses/pm/report.figs/er.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 401 KiB |
31
study/courses/pm/report.figs/sequence.mmd
Normal file
31
study/courses/pm/report.figs/sequence.mmd
Normal file
@@ -0,0 +1,31 @@
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor HR as 招聘企业HR
|
||||
participant Web as HR Web前端
|
||||
participant ExamSvc as 考试服务
|
||||
participant QSvc as 试题生成服务
|
||||
participant Cand as 应聘者客户端
|
||||
participant Score as 评分服务
|
||||
participant DB as 数据库
|
||||
|
||||
HR ->> Web: 配置岗位与试题策略
|
||||
Web ->> QSvc: 创建/更新试卷模板
|
||||
QSvc ->> DB: 读取题库与统计数据
|
||||
QSvc -->> Web: 返回模板ID
|
||||
|
||||
HR ->> Web: 发布在线考试
|
||||
|
||||
Cand ->> Cand: 注册 / 登录
|
||||
Cand ->> ExamSvc: 请求领取试卷(jobId, candidateId)
|
||||
ExamSvc ->> QSvc: 实例化个性化试卷(templateId, profile)
|
||||
QSvc -->> ExamSvc: 返回题目列表
|
||||
ExamSvc -->> Cand: 下发试卷内容
|
||||
|
||||
Cand ->> ExamSvc: 提交全部答案
|
||||
ExamSvc ->> Score: 发送作答数据
|
||||
Score ->> DB: 读取标准答案与评分规则
|
||||
Score -->> ExamSvc: 返回评分结果
|
||||
ExamSvc ->> DB: 保存成绩与答案明细
|
||||
|
||||
Cand -->> ExamSvc: 查询成绩与解析
|
||||
ExamSvc -->> Cand: 返回成绩、解析与评价入口
|
||||
BIN
study/courses/pm/report.figs/sequence.png
Normal file
BIN
study/courses/pm/report.figs/sequence.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 195 KiB |
91
study/courses/pm/report.figs/struct.drawio
Normal file
91
study/courses/pm/report.figs/struct.drawio
Normal file
@@ -0,0 +1,91 @@
|
||||
<mxfile host="Electron" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/28.2.8 Chrome/140.0.7339.240 Electron/38.4.0 Safari/537.36" version="28.2.8">
|
||||
<diagram name="Page-1" id="KaNmNEmE_Qx5MvW_SbqB">
|
||||
<mxGraphModel dx="1009" dy="863" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-61" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#b0e3e6;strokeColor=#0e8088;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="140" width="680" height="110" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-57" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="250" width="680" height="110" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-56" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#fad9d5;strokeColor=#ae4132;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="570" width="680" height="130" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-55" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="360" width="680" height="210" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-1" value="客户端层" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="295" y="175" width="20" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-2" value="接入层&nbsp;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="300" y="285" width="10" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-3" value="应用服务层&nbsp;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="290" y="442" width="30" height="46" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-4" value="数据层" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="295" y="617.5" width="20" height="35" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-5" value="HR APP 前端<br>Vue / React" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e6fffb;strokeColor=#13c2c2;strokeWidth=2;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="410" y="165" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-6" value="应聘者 APP<br>Candidate App" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e6fffb;strokeColor=#13c2c2;strokeWidth=2;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="770" y="165" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-7" value="API Gateway / ALB
HTTPS 终止 + 负载均衡" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff7e6;strokeColor=#fa8c16;strokeWidth=2;fontSize=12;" vertex="1" parent="1">
|
||||
<mxGeometry x="570" y="275" width="160" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-8" value="Auth Service
认证授权" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0f5ff;strokeColor=#2f54eb;strokeWidth=2;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="380" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-10" value="Question Service
题库管理" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0f5ff;strokeColor=#2f54eb;strokeWidth=2;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="480" y="380" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-54" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="40E4A47yQaY0a98WVuZL-11" target="40E4A47yQaY0a98WVuZL-10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-11" value="Exam Service
考试流程管理" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0f5ff;strokeColor=#2f54eb;strokeWidth=2;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="720" y="380" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-12" value="Scoring Service
自动评分" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0f5ff;strokeColor=#2f54eb;strokeWidth=2;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="720" y="490" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-13" value="ML / Recommend
智能选题与评估" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0f5ff;strokeColor=#2f54eb;strokeWidth=2;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="480" y="490" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-15" value="关系型数据库<br>MySQL / PostgreSQL" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff1f0;strokeColor=#f5222d;strokeWidth=2;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="380" y="600" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-16" value="Redis 缓存" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff1f0;strokeColor=#f5222d;strokeWidth=2;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="520" y="600" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-17" value="S3 对象存储<br>题目附件" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff1f0;strokeColor=#f5222d;strokeWidth=2;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="600" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-18" value="日志 / 分析存储" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff1f0;strokeColor=#f5222d;strokeWidth=2;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="800" y="600" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-26" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;" edge="1" parent="1" source="40E4A47yQaY0a98WVuZL-11" target="40E4A47yQaY0a98WVuZL-12">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;" edge="1" parent="1" source="40E4A47yQaY0a98WVuZL-10" target="40E4A47yQaY0a98WVuZL-13">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-14" value="Admin Console
运营后台" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0f5ff;strokeColor=#2f54eb;strokeWidth=2;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="840" y="380" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-9" value="Job & Company
岗位与企业管理" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f0f5ff;strokeColor=#2f54eb;strokeWidth=2;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="600" y="380" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="40E4A47yQaY0a98WVuZL-62" value="" style="endArrow=none;html=1;rounded=0;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="330" y="700" as="sourcePoint" />
|
||||
<mxPoint x="330" y="140" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
60
study/courses/pm/report.figs/struct.mmd
Normal file
60
study/courses/pm/report.figs/struct.mmd
Normal file
@@ -0,0 +1,60 @@
|
||||
flowchart LR
|
||||
%% ======== 样式定义 ========
|
||||
classDef client fill:#e6fffb,stroke:#13c2c2,stroke-width:1px;
|
||||
classDef gateway fill:#fff7e6,stroke:#fa8c16,stroke-width:1px;
|
||||
classDef service fill:#f0f5ff,stroke:#2f54eb,stroke-width:1px;
|
||||
classDef data fill:#fff1f0,stroke:#f5222d,stroke-width:1px;
|
||||
|
||||
%% ======== 客户端层 ========
|
||||
subgraph Clients[客户端层]
|
||||
HRWeb[HR Web 前端<br/>Vue / React]:::client
|
||||
CandApp[应聘者 Web / APP]:::client
|
||||
end
|
||||
|
||||
%% ======== 接入层 ========
|
||||
subgraph Gateway[接入层]
|
||||
Nginx[Nginx 反向代理<br/>HTTPS 终止 + 负载均衡]:::gateway
|
||||
end
|
||||
|
||||
%% ======== 应用服务层 ========
|
||||
subgraph Services[应用服务层]
|
||||
AuthSvc[Auth Service<br/>认证授权]:::service
|
||||
JobSvc[Job & Company Service<br/>岗位与企业管理]:::service
|
||||
QSvc[Question Service<br/>题库管理]:::service
|
||||
ExamSvc[Exam Service<br/>考试流程管理]:::service
|
||||
ScoreSvc[Scoring Service<br/>自动评分]:::service
|
||||
MLSvc[ML / Recommend Service<br/>智能选题与评估]:::service
|
||||
AdminSvc[Admin Console<br/>运营后台]:::service
|
||||
end
|
||||
|
||||
%% ======== 数据层 ========
|
||||
subgraph DataLayer[数据层]
|
||||
DB[(关系型数据库<br/>MySQL / PostgreSQL)]:::data
|
||||
Cache[(Redis 缓存)]:::data
|
||||
ObjStore[(对象存储<br/>题目附件)]:::data
|
||||
LogStore[(日志 / 分析存储)]:::data
|
||||
end
|
||||
|
||||
%% ======== 连接关系 ========
|
||||
HRWeb --> Nginx
|
||||
CandApp --> Nginx
|
||||
|
||||
Nginx --> AuthSvc
|
||||
Nginx --> JobSvc
|
||||
Nginx --> QSvc
|
||||
Nginx --> ExamSvc
|
||||
Nginx --> AdminSvc
|
||||
|
||||
ExamSvc --> ScoreSvc
|
||||
ExamSvc --> QSvc
|
||||
QSvc --> MLSvc
|
||||
|
||||
AuthSvc --> DB
|
||||
JobSvc --> DB
|
||||
QSvc --> DB
|
||||
ExamSvc --> DB
|
||||
ScoreSvc --> DB
|
||||
|
||||
Services --> Cache
|
||||
Services --> ObjStore
|
||||
Services --> LogStore
|
||||
BIN
study/courses/pm/report.figs/struct.png
Normal file
BIN
study/courses/pm/report.figs/struct.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 173 KiB |
85
study/courses/pm/report.figs/use-case.drawio
Normal file
85
study/courses/pm/report.figs/use-case.drawio
Normal file
@@ -0,0 +1,85 @@
|
||||
<mxfile host="Electron" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/28.2.8 Chrome/140.0.7339.240 Electron/38.4.0 Safari/537.36" version="28.2.8">
|
||||
<diagram name="Page-1" id="page-1">
|
||||
<mxGraphModel dx="706" dy="604" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="6" value="配置岗位需求" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="120" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7" value="配置试题策略" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="180" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9" value="在线答题" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="360" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="10" value="查看成绩与统计" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="240" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="11" value="提交试题反馈" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="300" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="12" value="题库管理与题目淘汰" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="430" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="13" value="企业接入与运营配置" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;fontColor=#232F3E;fontSize=12;strokeColor=#3399FF;strokeWidth=2;" parent="1" vertex="1">
|
||||
<mxGeometry x="250" y="490" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="14" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=0;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-22" target="6" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="170" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="15" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=0;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-22" target="7" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="170" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="16" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=0;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-22" target="10" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="170" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="17" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=0;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-22" target="11" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="170" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="18" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=1;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-23" target="9" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="650" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="19" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=1;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-23" target="10" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="650" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="20" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=1;entryY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-23" target="11" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="650" y="180" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="21" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-27" target="12" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="410" y="490" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="22" style="endArrow=none;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=0.5;exitY=0.5;entryX=1;entryY=0.5;entryDx=0;entryDy=0;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="dYsEw_TpROWio0KKOCtD-27" target="13" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="410" y="490" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="dYsEw_TpROWio0KKOCtD-22" value="招聘企业 HR" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
|
||||
<mxGeometry x="130" y="210" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="dYsEw_TpROWio0KKOCtD-23" value="应聘者" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;fillColor=#f0a30a;fontColor=#000000;strokeColor=#BD7000;" parent="1" vertex="1">
|
||||
<mxGeometry x="440" y="295" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="dYsEw_TpROWio0KKOCtD-27" value="平台管理员" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;fillColor=#f0a30a;fontColor=#000000;strokeColor=#BD7000;" parent="1" vertex="1">
|
||||
<mxGeometry x="440" y="450" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
47
study/courses/pm/report.figs/use-case.mmd
Normal file
47
study/courses/pm/report.figs/use-case.mmd
Normal file
@@ -0,0 +1,47 @@
|
||||
graph LR
|
||||
%% ======== 样式定义 ========
|
||||
classDef actor fill:#fff7e6,stroke:#fa8c16,stroke-width:1px;
|
||||
classDef system fill:#f0f5ff,stroke:#2f54eb,stroke-width:1px;
|
||||
classDef usecase fill:#ffffff,stroke:#595959,stroke-width:1px,rx:20,ry:20;
|
||||
|
||||
%% ======== 系统边界 ========
|
||||
System[招聘试题定制平台]:::system
|
||||
|
||||
%% ======== 参与者(Actors) ========
|
||||
HR(招聘企业 HR):::actor
|
||||
Candidate(应聘者):::actor
|
||||
Admin(平台管理员):::actor
|
||||
|
||||
%% ======== 用例(Use Cases) ========
|
||||
UC_ConfigJob(配置岗位需求):::usecase
|
||||
UC_ConfigPolicy(配置试题策略):::usecase
|
||||
UC_GenerateExam(自动生成试卷):::usecase
|
||||
UC_TakeExam(在线答题):::usecase
|
||||
UC_ViewResult(查看成绩与统计):::usecase
|
||||
UC_Feedback(提交试题反馈):::usecase
|
||||
UC_ManageBank(题库管理与题目淘汰):::usecase
|
||||
UC_ManageTenant(企业接入与运营配置):::usecase
|
||||
|
||||
%% ======== 系统与用例关系 ========
|
||||
System --- UC_ConfigJob
|
||||
System --- UC_ConfigPolicy
|
||||
System --- UC_GenerateExam
|
||||
System --- UC_TakeExam
|
||||
System --- UC_ViewResult
|
||||
System --- UC_Feedback
|
||||
System --- UC_ManageBank
|
||||
System --- UC_ManageTenant
|
||||
|
||||
%% ======== Actor 与 Use Case 关系 ========
|
||||
HR --- UC_ConfigJob
|
||||
HR --- UC_ConfigPolicy
|
||||
HR --- UC_ViewResult
|
||||
HR --- UC_Feedback
|
||||
|
||||
Candidate --- UC_TakeExam
|
||||
Candidate --- UC_ViewResult
|
||||
Candidate --- UC_Feedback
|
||||
|
||||
Admin --- UC_ManageBank
|
||||
Admin --- UC_ManageTenant
|
||||
|
||||
BIN
study/courses/pm/report.figs/use-case.png
Normal file
BIN
study/courses/pm/report.figs/use-case.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 162 KiB |
468
study/courses/pm/report.md
Normal file
468
study/courses/pm/report.md
Normal file
@@ -0,0 +1,468 @@
|
||||
# 基于手机的招聘代理平台系统设计说明书
|
||||
|
||||
## 1 引言
|
||||
|
||||
### 1.1 项目背景
|
||||
|
||||
在互联网招聘场景中,企业普遍面临以下问题:
|
||||
|
||||
* 试题缺乏针对性,无法准确考察岗位所需能力;
|
||||
* 试题缺乏时效性,不能反映最新项目技术栈或业务需求;
|
||||
* 试题的录入与维护成本高,复用性差,题库质量难以持续优化。
|
||||
|
||||
为此,设计并实现一个**招聘试题代理定制服务平台**(下称“本平台”),以“岗位需求 + 项目场景 + 应聘者背景”为驱动,自动生成个性化试题并持续优化题库质量,为多家招聘企业提供 SaaS 级服务。
|
||||
|
||||
### 1.2 设计目标
|
||||
|
||||
* 提供**多角色协同**的在线招聘试题定制与考试平台;
|
||||
* 支持**岗位级别的试卷自动生成**与个性化定制;
|
||||
* 支持**在线答题、自动评分、结果分析**;
|
||||
* 通过**统计与反馈驱动的算法**持续优化题库质量;
|
||||
* 面向多租户企业,以云端部署形式提供服务。
|
||||
|
||||
## 2 业务概述与角色
|
||||
|
||||
### 2.1 业务角色
|
||||
|
||||
1. **招聘企业 HR**
|
||||
|
||||
* 维护岗位信息与能力要求;
|
||||
* 配置试题策略(题量、题型比例、难度分布);
|
||||
* 发布考试、查看统计报表;
|
||||
* 对试题效果给出评价与反馈。
|
||||
|
||||
2. **应聘者 Candidate**
|
||||
|
||||
* 注册/登录平台;
|
||||
* 选择目标岗位,领取并完成在线试卷;
|
||||
* 查看成绩与解析;
|
||||
* 对题目给出主观评价(难度、贴合度、清晰度等)。
|
||||
|
||||
3. **平台管理员 Admin**
|
||||
|
||||
* 审核企业接入与企业题库;
|
||||
* 管理系统题库、试题标签、难度标注;
|
||||
* 监控题目质量与淘汰策略执行;
|
||||
* 管理模型训练与推荐策略。
|
||||
|
||||
4. **内部系统模块(逻辑角色)**
|
||||
|
||||
* **Question Service**:题库管理、题目 CRUD;
|
||||
* **Exam Service**:考试流程管理、会话控制;
|
||||
* **Scoring Service**:自动评分与统计;
|
||||
* **ML / Recommendation Service**:试题生成与质量评估。
|
||||
|
||||
## 3 UML 视图
|
||||
|
||||
### 3.1 用例图(Use Case Diagram)
|
||||
|
||||
<img src="use-case.png" style="zoom: 40%;" />
|
||||
|
||||
### 3.2 核心业务活动图(Activity Diagram)
|
||||
|
||||
<img src="activity.png" style="zoom: 20%;" />
|
||||
|
||||
### 3.3 时序图(Sequence Diagram)
|
||||
|
||||
<img src="sequence.png" style="zoom: 50%;" />
|
||||
|
||||
### 3.4 类图(Class Diagram)
|
||||
|
||||
<img src="class.png" style="zoom: 50%;" />
|
||||
|
||||
### 3.5 ER 图(实体–关系图)
|
||||
|
||||
<img src="er.png" style="zoom: 50%;" />
|
||||
|
||||
## 4 数据结构与数据库设计
|
||||
|
||||
### 4.1 主要数据表概述
|
||||
|
||||
#### 表 `user`
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| ------------- | ------------------- | ---------------------------- |
|
||||
| id (PK) | INT | 用户 ID |
|
||||
| company_id | INT (FK company.id) | 所属公司(应聘者可为空) |
|
||||
| name | VARCHAR | 姓名 |
|
||||
| email | VARCHAR (UNIQUE) | 登录邮箱 |
|
||||
| role | ENUM | `HR` / `CANDIDATE` / `ADMIN` |
|
||||
| password_hash | VARCHAR | 加密后的密码 |
|
||||
| created_at | DATETIME | 注册时间 |
|
||||
|
||||
#### 表 `company`
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| -------- | ------- | -------- |
|
||||
| id (PK) | INT | 公司 ID |
|
||||
| name | VARCHAR | 公司名称 |
|
||||
| industry | VARCHAR | 所属行业 |
|
||||
| size | VARCHAR | 规模(人数区间) |
|
||||
|
||||
#### 表 `candidate_profile`
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| ---------------- | ------------ | ------------ |
|
||||
| id (PK) | INT | 主键 |
|
||||
| user_id (FK) | INT | 对应 `user.id` |
|
||||
| degree | VARCHAR | 学历 |
|
||||
| years_experience | INT | 工作年限 |
|
||||
| skill_tags | JSON/VARCHAR | 技能标签集合 |
|
||||
| resume_url | VARCHAR | 简历文件存储地址 |
|
||||
|
||||
#### 表 `job_position`
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| --------------- | ------------ | --------- |
|
||||
| id (PK) | INT | 岗位 ID |
|
||||
| company_id (FK) | INT | 所属公司 |
|
||||
| title | VARCHAR | 岗位名称 |
|
||||
| level | VARCHAR | 岗位级别 |
|
||||
| required_skills | JSON/VARCHAR | 要求技能标签 |
|
||||
| description | TEXT | 岗位详细说明 |
|
||||
| exam_policy_id | VARCHAR(FK) | 对应考试策略 ID |
|
||||
|
||||
#### 表 `exam_policy`
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| --------------- | ------- | --------------- |
|
||||
| id (PK) | VARCHAR | 策略 ID |
|
||||
| total_questions | INT | 总题量 |
|
||||
| easy_ratio | FLOAT | 容易题比例 |
|
||||
| medium_ratio | FLOAT | 中等题比例 |
|
||||
| hard_ratio | FLOAT | 困难题比例 |
|
||||
| type_ratio | JSON | 题型比例(单选/多选/编程等) |
|
||||
|
||||
#### 表 `question`
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| ---------- | ------- | ------------ |
|
||||
| id (PK) | INT | 题目 ID |
|
||||
| content | TEXT | 题干 |
|
||||
| type | VARCHAR | 题目类型 |
|
||||
| skill_tag | VARCHAR | 技能标签 |
|
||||
| difficulty | INT | 难度等级 1–5 |
|
||||
| source | VARCHAR | 来源(企业题/通用题等) |
|
||||
| is_active | BOOLEAN | 是否在用 |
|
||||
|
||||
#### 表 `question_stats`
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| --------------- | -------- | ---------------- |
|
||||
| question_id(PK) | INT | 对应 `question.id` |
|
||||
| used_count | INT | 被使用次数 |
|
||||
| avg_score | FLOAT | 平均得分 |
|
||||
| correct_rate | FLOAT | 正确率 |
|
||||
| discrimination | FLOAT | 区分度 |
|
||||
| feedback_score | FLOAT | 反馈评分均值 |
|
||||
| last_used_at | DATETIME | 最近使用时间 |
|
||||
|
||||
#### 表 `exam_template`
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| -------------- | ------- | --------- |
|
||||
| id (PK) | INT | 试卷模板 ID |
|
||||
| job_id (FK) | INT | 对应岗位 |
|
||||
| policy_id (FK) | VARCHAR | 对应策略 |
|
||||
| question_slots | JSON | 题目占位或题目列表 |
|
||||
|
||||
#### 表 `exam_session`
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| ------------ | -------- | ------------------ |
|
||||
| id (PK) | INT | 考试会话 ID |
|
||||
| candidate_id | INT | 应聘者(`user.id`) |
|
||||
| job_id | INT | 岗位 ID |
|
||||
| template_id | INT | 使用的模板 ID |
|
||||
| start_time | DATETIME | 开始时间 |
|
||||
| submit_time | DATETIME | 提交时间 |
|
||||
| total_score | FLOAT | 总分 |
|
||||
| status | VARCHAR | `ONGOING` / `DONE` |
|
||||
|
||||
#### 表 `answer`
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| ----------- | ----- | ------- |
|
||||
| id (PK) | INT | 答案 ID |
|
||||
| session_id | INT | 所属考试会话 |
|
||||
| question_id | INT | 对应题目 |
|
||||
| content | TEXT | 作答内容 |
|
||||
| score | FLOAT | 得分 |
|
||||
| time_taken | FLOAT | 作答耗时(秒) |
|
||||
|
||||
#### 表 `question_feedback`
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| ------------ | -------- | -------- |
|
||||
| id (PK) | INT | 反馈 ID |
|
||||
| question_id | INT | 对应题目 |
|
||||
| from_user_id | INT | 反馈人用户 ID |
|
||||
| session_id | INT | 所在考试会话 |
|
||||
| rating | INT | 评分(1–5) |
|
||||
| comment | TEXT | 文本评价 |
|
||||
| created_at | DATETIME | 创建时间 |
|
||||
|
||||
## 5 系统架构与部署设计
|
||||
|
||||
### 5.1 分层架构说明
|
||||
|
||||
1. **客户端层(Clients)**
|
||||
|
||||
* HR Web 前端(Vue/React SPA);
|
||||
* 应聘者 Web/H5/APP;
|
||||
* 通过 HTTPS 调用后端 REST API。
|
||||
|
||||
2. **接入层(Gateway)**
|
||||
|
||||
* Nginx 作为统一入口;
|
||||
* 实现 HTTPS 终止、静态资源分发、反向代理和负载均衡。
|
||||
|
||||
3. **应用服务层(Services)**
|
||||
|
||||
* `Auth Service`:登录、鉴权、Token 管理;
|
||||
* `Job & Company Service`:企业与岗位管理;
|
||||
* `Question Service`:题库管理、统计指标计算;
|
||||
* `Exam Service`:考试流程、会话管理;
|
||||
* `Scoring Service`:客观题 & 主观题自动评分;
|
||||
* `ML / Recommend Service`:试题生成、质量打分、模糊定制;
|
||||
* `Admin Console`:运营后台接口。
|
||||
|
||||
4. **数据层(Data Layer)**
|
||||
|
||||
* 关系型数据库(MySQL/PostgreSQL);
|
||||
* Redis 缓存热点题目、会话状态;
|
||||
* 对象存储存放题目附件、解析文档;
|
||||
* 日志分析存储(ELK/ClickHouse 等)。
|
||||
|
||||
### 5.2 部署/组件图
|
||||
|
||||
<img src="struct.png" style="zoom: 50%;" />
|
||||
|
||||
## 6 核心算法设计
|
||||
|
||||
### 6.1 自适应试题生成算法
|
||||
|
||||
#### 6.1.1 目标
|
||||
|
||||
在满足岗位需求与考试策略(题量、题型、难度分布)的前提下,为特定岗位与候选人生成一套“技能匹配度高、区分度好、不过时”的个性化试卷。
|
||||
|
||||
#### 6.1.2 关键输入
|
||||
|
||||
* `job`:岗位信息(`required_skills`、`level` 等)
|
||||
* `policy`:试题策略(题量、难度比例、题型比例)
|
||||
* `candidate_profile`:候选人画像(技能标签、经验)
|
||||
* `question_bank`:题库(含 `QuestionStats` 统计信息)
|
||||
|
||||
#### 6.1.3 题目综合评分函数
|
||||
|
||||
对题目 `q` 计算综合得分 `score(q)`:
|
||||
|
||||
* `skill_match`:技能匹配度;
|
||||
* `difficulty_fit`:难度适配度;
|
||||
* `freshness`:新鲜度;
|
||||
* `discrimination`:区分度;
|
||||
* `bad_feedback`:负反馈惩罚。
|
||||
|
||||
线性组合示意:
|
||||
|
||||
```text
|
||||
score(q) = w1 * skill_match
|
||||
+ w2 * difficulty_fit
|
||||
+ w3 * freshness
|
||||
+ w4 * discrimination
|
||||
- w5 * bad_feedback
|
||||
```
|
||||
|
||||
#### 6.1.4 伪代码示例
|
||||
|
||||
```python
|
||||
def generate_exam_paper(job, policy, candidate_profile, question_bank):
|
||||
# 1. 抽取岗位 & 候选人技能标签
|
||||
job_skills = extract_skill_tags(job.required_skills)
|
||||
cand_skills = extract_skill_tags(candidate_profile.skill_tags)
|
||||
|
||||
# 2. 候选题集合:技能相关 & 在用
|
||||
candidates = [
|
||||
q for q in question_bank
|
||||
if q.is_active and overlap(q.skill_tag, job_skills | cand_skills)
|
||||
]
|
||||
|
||||
scored_questions = []
|
||||
for q in candidates:
|
||||
stats = q.stats # QuestionStats
|
||||
|
||||
skill_match = jaccard(q.skill_tag, job_skills | cand_skills)
|
||||
difficulty_fit = 1.0 - abs(q.difficulty - target_difficulty(job)) / 4.0
|
||||
freshness = time_decay(now() - stats.last_used_at)
|
||||
discrimination = stats.discrimination
|
||||
bad_feedback = max(0, 1 - stats.feedback_score)
|
||||
|
||||
score = (
|
||||
0.30 * skill_match +
|
||||
0.25 * difficulty_fit +
|
||||
0.15 * freshness +
|
||||
0.25 * discrimination -
|
||||
0.05 * bad_feedback
|
||||
)
|
||||
scored_questions.append((q, score))
|
||||
|
||||
# 3. 按得分排序
|
||||
scored_questions.sort(key=lambda x: x[1], reverse=True)
|
||||
|
||||
# 4. 按策略约束(题型 + 难度 + 数量)筛选
|
||||
selected = []
|
||||
counters = init_counters(policy)
|
||||
|
||||
for q, s in scored_questions:
|
||||
if not satisfy_policy(q, counters, policy):
|
||||
continue
|
||||
selected.append(q)
|
||||
update_counters(q, counters)
|
||||
|
||||
if len(selected) >= policy.total_questions:
|
||||
break
|
||||
|
||||
# 5. 生成试卷模板对象
|
||||
return build_exam_paper_template(job.id, policy.id, selected)
|
||||
```
|
||||
|
||||
### 6.2 自动评分算法
|
||||
|
||||
拆分为客观题与主观题评分。
|
||||
|
||||
#### 6.2.1 客观题评分
|
||||
|
||||
* 单选/判断:完全匹配得满分;
|
||||
* 多选:集合比对,可支持“部分正确部分得分”;
|
||||
* 填空:字符串归一化后精确匹配。
|
||||
|
||||
```python
|
||||
def score_objective_question(question, candidate_answer):
|
||||
correct = question.standard_answer
|
||||
|
||||
if question.type in ("single_choice", "true_false"):
|
||||
return question.full_score if candidate_answer == correct else 0.0
|
||||
|
||||
if question.type == "multi_choice":
|
||||
cand_set = set(candidate_answer)
|
||||
corr_set = set(correct)
|
||||
if cand_set == corr_set:
|
||||
return question.full_score
|
||||
if cand_set.issubset(corr_set):
|
||||
return question.full_score * len(cand_set) / len(corr_set)
|
||||
# 选错选项则记 0 分
|
||||
return 0.0
|
||||
|
||||
if question.type == "blank":
|
||||
return question.full_score if normalize(candidate_answer) == normalize(correct) else 0.0
|
||||
|
||||
return 0.0
|
||||
```
|
||||
|
||||
#### 6.2.2 主观题评分(规则 + 关键词覆盖率)
|
||||
|
||||
简化实现:基于关键词覆盖率进行线性赋分。
|
||||
|
||||
```python
|
||||
def score_subjective_question(question, candidate_answer):
|
||||
tokens = tokenize(candidate_answer) # 分词+规范化
|
||||
key_points = question.key_points # 关键点列表
|
||||
|
||||
hit = sum(1 for k in key_points if k in tokens)
|
||||
coverage = hit / len(key_points) if key_points else 0.0
|
||||
|
||||
return question.full_score * coverage
|
||||
```
|
||||
|
||||
#### 6.2.3 会话总分计算
|
||||
|
||||
```python
|
||||
def score_exam_session(session):
|
||||
total = 0.0
|
||||
for answer in session.answers:
|
||||
q = load_question(answer.question_id)
|
||||
if q.type in ("single_choice", "multi_choice", "true_false", "blank"):
|
||||
s = score_objective_question(q, answer.content)
|
||||
else:
|
||||
s = score_subjective_question(q, answer.content)
|
||||
|
||||
answer.score = s
|
||||
total += s
|
||||
|
||||
session.total_score = total
|
||||
persist_scores(session)
|
||||
return total
|
||||
```
|
||||
|
||||
### 6.3 试题质量评估与淘汰算法
|
||||
|
||||
#### 6.3.1 目标
|
||||
|
||||
根据题目使用情况、得分表现与主观反馈,动态计算题目质量分 `quality_score`。当样本量充足且质量分低于阈值时,将题目标记为淘汰候选。
|
||||
|
||||
#### 6.3.2 伪代码示例
|
||||
|
||||
```python
|
||||
def update_question_statistics(question_id):
|
||||
# 1. 从数据库汇总最新统计信息
|
||||
stats = aggregate_stats_from_answers_and_feedback(question_id)
|
||||
# 包含:used_count, avg_score, correct_rate,
|
||||
# discrimination, feedback_score, last_used_at
|
||||
|
||||
# 2. 计算质量分
|
||||
quality = (
|
||||
0.25 * stats.correct_rate +
|
||||
0.35 * stats.discrimination +
|
||||
0.25 * stats.feedback_score +
|
||||
0.15 * freshness_factor(stats.last_used_at)
|
||||
)
|
||||
|
||||
# 3. 更新统计表
|
||||
save_question_stats(question_id, stats, quality)
|
||||
|
||||
# 4. 判定是否进入淘汰池
|
||||
MIN_USED = 30
|
||||
THRESHOLD = 0.4
|
||||
|
||||
if stats.used_count >= MIN_USED and quality < THRESHOLD:
|
||||
mark_question_as_candidate_for_deprecation(question_id)
|
||||
```
|
||||
|
||||
### 6.4 模糊定制题目推荐算法
|
||||
|
||||
#### 6.4.1 场景
|
||||
|
||||
HR 只输入自然语言岗位描述(如“做高并发订单系统的 Java 后端工程师”),系统自动推荐若干候选题目供其选择。
|
||||
|
||||
#### 6.4.2 思路
|
||||
|
||||
1. 使用文本向量化(TF-IDF 或预训练 Embedding)对岗位描述和题目文本编码;
|
||||
2. 计算岗位向量与题目向量间的余弦相似度;
|
||||
3. 返回相似度最高的 Top-K 题目。
|
||||
|
||||
#### 6.4.3 伪代码
|
||||
|
||||
```python
|
||||
def fuzzy_recommend_questions(job_free_text, question_bank, top_k=50):
|
||||
job_vec = encode_text(job_free_text) # 向量化岗位描述
|
||||
|
||||
scored = []
|
||||
for q in question_bank:
|
||||
q_text = q.content + " " + q.skill_tag
|
||||
q_vec = encode_text(q_text)
|
||||
sim = cosine_similarity(job_vec, q_vec)
|
||||
scored.append((q, sim))
|
||||
|
||||
scored.sort(key=lambda x: x[1], reverse=True)
|
||||
return [q for q, _ in scored[:top_k]]
|
||||
```
|
||||
|
||||
## 7 总结
|
||||
|
||||
本报告从业务角色与流程出发,给出了招聘试题定制平台的完整系统设计方案:
|
||||
|
||||
* **业务层面**:明确 HR、应聘者、平台管理员等角色及其用例;
|
||||
* **模型层面**:通过 UML 用例图、活动图、时序图、类图与 ER 图,刻画系统的结构与行为;
|
||||
* **数据层面**:设计了围绕“岗位–试卷–试题–作答–反馈”的关系型数据库模型;
|
||||
* **架构层面**:采用客户端–接入层–服务层–数据层的分层部署方案,便于扩展与运维;
|
||||
* **算法层面**:给出自适应试题生成、自动评分、试题质量评估与模糊定制等核心算法的伪代码。
|
||||
17
study/courses/pm/考试范围.md
Normal file
17
study/courses/pm/考试范围.md
Normal file
@@ -0,0 +1,17 @@
|
||||
找一个业务场景(业务流程),10+ 业务步骤
|
||||
|
||||
找出每个步骤:什么角色(组织单元)、做什么事
|
||||
|
||||
画两种流程模型:petri 网、带泳道的活动图
|
||||
|
||||
数据库设计:主数据、业务数据、状态数据
|
||||
|
||||
alpha 算法
|
||||
|
||||
排队论计算:Little 公式
|
||||
流程优化(去掉活动依赖、合并活动)
|
||||
|
||||
|
||||
|
||||
> 三类活动:主要活动、支持活动、质量控制活动(可以不画,假设质量理想)
|
||||
|
||||
Reference in New Issue
Block a user