197 lines
15 KiB
Markdown
197 lines
15 KiB
Markdown
# 物业AI人力资源系统 MVP 本地启动
|
||
|
||
## 当前仓库
|
||
|
||
- 后端:`backend`,来自 `dromara/RuoYi-Vue-Plus` 的 `5.X` 分支
|
||
- 管理端前端:`frontend`,来自 `CrazyLionCat/plus-ui` 的 `5.X` 分支
|
||
- 用户侧前端:`mobile-uni`,uni-app Vue3 H5 工程;旧 `mobile` 仅保留为 MVP 演示兜底
|
||
|
||
## 本地入口与依赖端口
|
||
|
||
- 管理端前端:`https://wygj-admin.localhost/`
|
||
- uni-app 用户侧:`https://wygj-mobile-uni.localhost/h5/`
|
||
- 后端:`https://wygj-api.localhost/`
|
||
- 固定端口仅用于显式 fallback:`PORTLESS=0 ./scripts/dev.sh` 时后端回退 `http://127.0.0.1:8080/`,旧移动端回退 `http://127.0.0.1:5174/h5/user`
|
||
- MySQL:`127.0.0.1:13306`,数据库 `ry-vue`,账号 `root/root`
|
||
- Redis:`127.0.0.1:16379`,密码 `ruoyi123`
|
||
- MinIO API:`http://127.0.0.1:9000`,Console:`http://127.0.0.1:9001`,账号 `ruoyi / ruoyi123`,默认 bucket `ruoyi`
|
||
- Qdrant REST:`http://127.0.0.1:6333`,默认 collection `aihr_knowledge`
|
||
- 服务端资料导入根目录:`./.data/import`
|
||
|
||
## portless 本地入口
|
||
|
||
本机开发测试优先用 portless 访问稳定域名,避免继续记固定端口:
|
||
|
||
- uni-app 用户侧:`https://wygj-mobile-uni.localhost/h5/`
|
||
- 管理端:`https://wygj-admin.localhost/`
|
||
- 后端 API:`https://wygj-api.localhost`
|
||
|
||
从根目录一次性启动本地依赖、后端、管理端和 uni-app 用户侧:
|
||
|
||
```bash
|
||
./scripts/dev.sh
|
||
```
|
||
|
||
`./scripts/dev.sh` 默认通过 portless 启动后端、管理端和 `mobile-uni`,并由 Docker 启动 MySQL/Redis/MinIO/Qdrant。管理端 Vite 代理读取 `frontend/.env.development` 的 `VITE_APP_PROXY_TARGET=https://wygj-api.localhost`,`mobile-uni` Vite 代理默认指向 `https://wygj-api.localhost`,都不依赖固定 `8080`。如需单独启动后端,可执行:
|
||
|
||
```bash
|
||
portless run --name wygj-api ./scripts/dev-backend.sh
|
||
```
|
||
|
||
重复启动或切换分支时优先使用 `./scripts/dev.sh restart`,停止使用 `./scripts/dev.sh stop`。脚本会递归终止 portless 包装进程及其 Java/Vite 子进程,避免旧后端脱离后继续占用 MySQL 连接池;进程树回归可用 `bash scripts/tests/process-tree.test.sh` 验证。
|
||
|
||
也可以只让 portless 按根目录 `portless.json` 启动前端工程:
|
||
|
||
```bash
|
||
portless
|
||
```
|
||
|
||
旧 `mobile/` 只在显式 `PORTLESS=0 ./scripts/dev.sh` 时作为固定端口兜底启动;后端开发测试优先看 `wygj-api.localhost`,管理端开发测试优先看 `wygj-admin.localhost`,新用户侧开发测试优先看 `wygj-mobile-uni.localhost`。
|
||
|
||
Qdrant 默认本地无需配置;远端或自定义 collection 可用 `AIHR_QDRANT_URL`、`AIHR_QDRANT_COLLECTION`、`AIHR_QDRANT_API_KEY` 覆盖。服务端资料导入根目录可用 `AIHR_IMPORT_ROOT` 或 `-Daihr.import.root` 覆盖。组织人员同步可用 `AIHR_ORG_SYNC_BASE_URL` 指向外部开放平台 `/api/open/v1` 前缀,并配置 `AIHR_ORG_SYNC_ACCESS_TOKEN` 或 `AIHR_ORG_SYNC_CLIENT_ID`/`AIHR_ORG_SYNC_CLIENT_SECRET`;业务请求会用 client secret 生成 HMAC-SHA256 hex 签名。移动端手机号登录的短信模板 ID、阿里云 AccessKey、Secret 和短信签名都通过环境变量注入;本地放根目录 `.env.local`,`scripts/dev-backend.sh` 会自动加载。若开放平台凭证放在 `backend/.env`,启动脚本也会加载该文件,并把 `client_id`/`client_secret` 映射为组织同步实际读取的 `AIHR_ORG_SYNC_CLIENT_ID`/`AIHR_ORG_SYNC_CLIENT_SECRET`。
|
||
|
||
组织同步写入前先运行只读预检:`node scripts/verify-demo-questions.mjs --org-dry-run`。dry-run 不检查或变更本地快照表结构,也不写数据库;输出只包含人数、手机号覆盖、脱敏数、疑似乱码数和警告,不输出员工姓名。只有 `phone_linked` 能覆盖至少 20 名正式试点人员且上游修复疑似乱码后,才切换管理端组织同步为写入模式。
|
||
|
||
正式试点预检必须指定当前批次时间窗,例如:`AIHR_PILOT_START_DATE=2026-07-07 AIHR_PILOT_END_DATE=2026-07-10 AIHR_PILOT_STRICT=true ./scripts/demo-check.sh`。脚本只接受 `YYYY-MM-DD`,只统计窗口内完成的训练、校准和 SOP 评审;人员先按唯一手机号映射到在职组织快照,完训口径为每人至少 10 次已完成对练。
|
||
|
||
管理端正式试点 CSV 也必须显式选择同一批次日期。可用真实 API 验证其日期拒绝、CSV 契约和正式身份范围:`node scripts/verify-demo-questions.mjs --pilot-export --start-date=2026-07-07 --end-date=2026-07-10`。
|
||
|
||
本地 `.env.local` 示例:
|
||
|
||
```bash
|
||
AIHR_SMS_LOGIN_TEMPLATE_ID=SMS_xxxxxx
|
||
ALIYUN_SMS_ACCESS_KEY_ID=xxx
|
||
ALIYUN_SMS_ACCESS_KEY_SECRET=xxx
|
||
ALIYUN_SMS_SIGN_NAME=物业AI助手
|
||
# 演示兜底:非空则不真发短信,验证码固定为该值;dev 默认 123456,prod profile 代码级强制失效
|
||
AIHR_SMS_DEV_FIXED_CODE=123456
|
||
AIHR_ORG_SYNC_BASE_URL=https://wuye.meihe.cc/api/open/v1
|
||
AIHR_ORG_SYNC_ACCESS_TOKEN=
|
||
AIHR_ORG_SYNC_CLIENT_ID=
|
||
AIHR_ORG_SYNC_CLIENT_SECRET=
|
||
AIHR_ORG_SYNC_SIGNING_SECRET=
|
||
# 若放在 backend/.env,也可沿用开放平台字段名:
|
||
# client_id=dn_xxxxxx
|
||
# client_secret=dns_xxxxxx
|
||
# 试点成本闸门:超预算时改 false,chat/asr/tts 会走现有文本兜底
|
||
AIHR_AI_RUNTIME_ENABLED=true
|
||
AIHR_AI_CHAT_ENABLED=true
|
||
AIHR_AI_SPEECH_ENABLED=true
|
||
```
|
||
|
||
`application-dev.yml` 只保留占位和默认值,不提交真实短信密钥。dev 环境不配阿里云短信也能登录移动端:验证码固定 `123456`。
|
||
|
||
## 启动步骤
|
||
|
||
在项目根目录执行:
|
||
|
||
```bash
|
||
./scripts/dev.sh
|
||
```
|
||
|
||
`./scripts/dev.sh` 默认通过 portless 暴露后端、管理端和当前 `mobile-uni` 用户侧。若要显式使用旧端口调试,可执行 `PORTLESS=0 ./scripts/dev.sh`,后端入口为 `http://127.0.0.1:8080/`,管理端入口为 `http://127.0.0.1:5173/`,旧移动端兜底入口为 `http://127.0.0.1:5174/h5/user`。
|
||
|
||
首次启动或需要重建本地 `ry-vue` MVP 数据库时执行:
|
||
|
||
```bash
|
||
./scripts/dev.sh --reset
|
||
```
|
||
|
||
`--reset` 会删除并重建本地 MVP 数据库,只用于本地开发环境。
|
||
|
||
## 默认登录
|
||
|
||
- 租户:`000000`
|
||
- 管理员:`admin / admin123`
|
||
- 测试账号:`test / 666666`、`test1 / 666666`
|
||
|
||
## 品牌资源
|
||
|
||
- 页面标题:`物业AI人力资源系统`
|
||
- 侧栏 Logo:`frontend/src/assets/logo/logo.png`
|
||
|
||
## 已验证的基础链路
|
||
|
||
- MySQL、Redis 与 MinIO 容器健康检查通过
|
||
- Qdrant 容器随本地开发编排启动,供 SOP 知识库向量召回使用
|
||
- `ry_vue_5.X.sql`、`ry_job.sql`、`ry_workflow.sql` 已导入
|
||
- `aihr_knowledge_mysql8.sql`、`aihr_model_mysql8.sql` 已导入;本地库含住宅 SOP seed 片段与模型配置表
|
||
- `aihr_practice_mysql8.sql` 已导入;移动端员工训练记录落 `aihr_practice_session`,用于训练历史、主管待复盘列表和能力画像聚合
|
||
- `aihr_interview_result_mysql8.sql` 已纳入 reset 脚本;AI 面试评分完成后结果落 `aihr_interview_result`
|
||
- `aihr_candidate_material_mysql8.sql` 已纳入;候选人端补充资料文件写 `sys_oss`/MinIO,关系落 `aihr_candidate_material`
|
||
- `aihr_org_snapshot_mysql8.sql` 已纳入 reset 脚本;组织人员本地 seed(2 个住宅项目 22 人,项目经理/主管/一线三层)支撑演示,外部开放组织系统配置完成后用 `POST /api/aihr/org/sync` 拉取 `company/department/employee` 快照并覆盖本地 `aihr_org_snapshot`
|
||
- 本地组织 seed 带演示手机号,可用 `13900000103` 验证员工端自动识别物业管家岗位,用 `13900000202` 验证主管端项目范围
|
||
- SOP 知识库支持 `.txt/.md/.markdown/.pdf/.doc/.docx/.xls/.xlsx/.ppt/.pptx` 上传到 MinIO 后解析入库,接口为 `POST /api/knowledge/doc/upload`,单文件上限 100MB;管理端上传请求单独放宽到 180s,PDF 解析/归类/向量化较慢时不要改全局 axios 超时。资料处理中心异步接口另支持 `.zip`(≤500MB),后台安全解压后逐文件入队;最多 1000 个子文件、解压总量 ≤2GB,不支持嵌套 ZIP
|
||
- 视频(`.mp4/.mov/.avi/.mkv/.webm/.m4v`,≤500MB、≤60 分钟)只走资料处理中心批量导入(异步队列):ffmpeg 抽音轨分段调 asr 转写 + 抽关键帧调 vision 提取画面文字,合并后归类切片入库,片段带 `[mm:ss]` 时间戳;**依赖服务器安装 ffmpeg/ffprobe**(macOS `brew install ffmpeg`,Linux `apt install ffmpeg`)
|
||
- 服务端目录导入接口为 `POST /api/knowledge/doc/import-local-task`,只读取导入根目录下的相对目录,后台逐文件复用同一上传解析链路;`POST /api/knowledge/doc/import-tasks/{id}/cancel` 可取消运行中任务;`POST /api/knowledge/doc/import-local` 保留为同步调试接口。
|
||
- 启用 `aihr_model_config.category='vector'` 的模型配置后,上传会同步写入片段 embedding,并尽力 upsert 到 Qdrant;模型配置页可查看 Qdrant 维度、点数和片段向量数,并在维度不一致时重建索引;未配置或 Qdrant 不可用时只走 MySQL Fulltext/seed fallback,不影响检索。
|
||
- 后端 `ruoyi-admin` 已完成 Maven 打包,并通过 portless 暴露为 `https://wygj-api.localhost/`
|
||
- 前端依赖已安装,Vite 已通过 portless 暴露为 `https://wygj-admin.localhost/`
|
||
- 当前用户侧由 `./scripts/dev.sh` 通过 portless 启动 `mobile-uni`,入口 `https://wygj-mobile-uni.localhost/h5/`;旧移动端兜底仅在 `PORTLESS=0` 调试时启动到 `5174`
|
||
- 移动端手机号登录页已接 `/resource/sms/code` 与 `/auth/mobile/sms-login`;未配置真实 `ALIYUN_SMS_ACCESS_KEY_ID`、`ALIYUN_SMS_ACCESS_KEY_SECRET`、`ALIYUN_SMS_SIGN_NAME`、`AIHR_SMS_LOGIN_TEMPLATE_ID` 时不会发送阿里云短信;手机号不存在时会自动注册为 `app_user`
|
||
- 移动端员工端“开始训练”已复用 `/api/train/practice/start`、`/turn`、`/finish`;移动端请求需带登录返回的 `Authorization` 与 `clientid`;完成后主管端完训人数、“待复盘对练”计数、复盘列表、复盘详情、员工训练历史和能力画像会变化
|
||
- 移动端候选人端“开始面试/面试练习”已复用 `/api/recruit/interview/start`、`/answer`、`/finish`;“补充资料”需带移动端 `Authorization` 与 `clientid`,上传后写 `sys_oss` 和 `aihr_candidate_material`,管理端 `/recruit/interview` 可审核为 `已通过/已驳回`
|
||
- `/dev-api/auth/tenant/list` 与 `/dev-api/auth/code` 已通过前端代理返回 `200`
|
||
- `000000 / admin / admin123` 已通过真实加密登录接口返回 `access_token`
|
||
|
||
Qdrant 单独检查:
|
||
|
||
```bash
|
||
curl -fsS http://127.0.0.1:6333/
|
||
```
|
||
|
||
登录后可检查向量索引状态:
|
||
|
||
```bash
|
||
TOKEN=<登录后 access_token>
|
||
curl -fsS https://wygj-api.localhost/api/knowledge/doc/vector-index-status -H "Authorization: Bearer $TOKEN"
|
||
```
|
||
|
||
## 线上移动端静态发布
|
||
|
||
线上 `peilian.njzhmj.top` 由 Caddy 服务,`/h5*` 映射到服务器 `/opt/wygj/www/h5`,并 fallback 到 `/h5/index.html`。只改移动端静态资源时无需重启后端。
|
||
|
||
```bash
|
||
npm --prefix mobile-uni run build:h5
|
||
ssh YCWY 'ts=$(date +%Y%m%d%H%M%S); mkdir -p /opt/wygj/backups; cp -a /opt/wygj/www/h5 /opt/wygj/backups/h5-$ts; echo /opt/wygj/backups/h5-$ts'
|
||
rsync -az --delete mobile-uni/dist/build/h5/ YCWY:/opt/wygj/www/h5/
|
||
curl -k -s https://peilian.njzhmj.top/h5/ | sed -n '1,20p'
|
||
```
|
||
|
||
## MVP 页面验证
|
||
|
||
登录后侧栏应只展示以下入口:
|
||
|
||
- 首页:`/index`
|
||
- AI面试:`/recruit/interview`
|
||
- 三角色对练:`/train/practice`
|
||
- 案例沉淀:`/knowledge/cases`
|
||
- SOP知识库:`/knowledge/sop`
|
||
- 资料处理:`/knowledge/processing`
|
||
- 系统设置-模型配置:`/system/model`
|
||
|
||
若依默认菜单如“系统管理 / 租户管理 / 系统监控 / 系统工具 / 测试菜单”在当前 MVP 阶段应保持隐藏。
|
||
|
||
## MVP 演示流验证
|
||
|
||
当前已跑通管理端五个本地演示流和移动端员工训练闭环:
|
||
|
||
- AI面试:进入 `/recruit/interview`,点击“生成题目” → 输入真实回答或“填满参考回答” → “完成评分”,应看到新增面试记录;配置 chat 模型时题目和评分都来自真实模型,未配置时使用本地 Rubric。
|
||
- 三角色对练:进入 `/train/practice`,点击“开始对练” → 完成两轮真实或参考回复 → “结束并评分”,应看到“已完成闭环”“导师改写”和新增对练记录。
|
||
- 案例沉淀:进入 `/knowledge/cases`,上传真实语音 → “AI 整理” → “送审” → “入库”,应看到“已完成闭环”和新增案例记录;上传必须先完成 ASR 转写。
|
||
- SOP知识库:进入 `/knowledge/sop`,可上传 txt/md/PDF/Word/Excel/PPT 文档入库;点击“检索” → “生成训练题”,应看到“已完成闭环”、命中数据库 SOP 原文片段和训练题;数据库不可用时页面回退 seed。
|
||
- 资料处理:进入 `/knowledge/processing`,应看到资料总量、解析任务表、处理链路、规则与风险;可用少量文件验证“批量导入/选择目录/服务端导入”。**批量导入走异步队列**:提交即返回,页面出现“本次批量上传”进度面板(排队/加工中/完成/失败 + 单条重试),后台 worker 并发 2 逐条解析入库;暂存目录默认 `./.data/staging`(`aihr.upload.staging` 覆盖)。服务端导入读取 `./.data/import` 下的相对目录,启动后台任务并在页面显示进度,运行中任务可点“取消”;目录导入的重试粒度是同目录重新导入,批量上传的重试粒度是单文件。
|
||
- uni-app 员工端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/user/today/index`,手机号登录(dev 验证码固定 `123456`)。今日页进入问师傅、练习、案例素材和个人页;练习页应能完成开始练习、提交回应、结束评分、每日三题提交,个人页同步训练历史和成长证据包。
|
||
- 移动端登录后若组织快照接口返回 `401/403`,只降级为手动岗位确认,不应清除手机号登录态;岗位确认页仍需允许员工选择“生活顾问”后继续进入业务页。
|
||
- uni-app 主管端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/supervisor/index/index`,应看到团队概览、团队画像、团队预警、指派专项、待复盘和复盘详情;从团队画像派专项后,最近专项应立即回读新记录。
|
||
- uni-app 候选人端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/candidate/index/index`,手机号登录(dev 验证码固定 `123456`)→ “开始面试/面试练习”完成答题评分;“补充资料”选择 PDF/Word/图片后上传,应看到资料状态。Codex 内置浏览器不支持本地文件选择时,用真实 HTTP multipart smoke 代替浏览器文件选择。
|
||
- 真 LLM 激活:在 `/system/model` 给供应商填 api_host/api_key 并启用 `category=chat` 模型后,三角色对练的客户回复与评分即为真实 LLM 生成;再启用 `category=asr/tts`(如硅基流动 SenseVoice/CosyVoice2)语音路径生效。未配置时全链路自动回退 seed。
|
||
|
||
演示前可先跑最小预检:
|
||
|
||
```bash
|
||
./scripts/demo-check.sh
|
||
```
|
||
|
||
完整演示脚本与录屏兜底见 [DEMO_ACCEPTANCE.md](DEMO_ACCEPTANCE.md)。
|