Compare commits

..

10 Commits

Author SHA1 Message Date
夏犀麟
a14e162bd1 chore(ide): 添加 IDE 配置文件
- 添加 .gitignore 文件配置
- 添加 modules.xml 模块配置
- 添加 vcs.xml 版本控制配置
- 添加 workbuddy.xpcool.com.iml 项目模块文件
2026-08-31 11:54:51 +08:00
夏犀麟
1b82fd1771 chore: 登录仅密码加密改造(日志) 2026-08-28 00:29:59 +08:00
夏犀麟
d7086382f7 feat: 生产全量请求/响应加密完成(日志) 2026-08-28 00:19:02 +08:00
夏犀麟
76ce62b5c6 feat: 登录密码混合加密传输双端完成(日志) 2026-08-27 23:47:14 +08:00
夏犀麟
6337c6dfd1 docs: 服务器安全加固与安全日志功能记录(2026-08-27) 2026-08-27 11:36:14 +08:00
夏犀麟
40a4e8acda DOC: 界面开发约定(TDesign MCP 优先 + t-enhanced-table 树形要点) 2026-08-27 00:11:00 +08:00
夏犀麟
3a3428ef94 LOG: 记录 RBAC 二期(人员管理/登录日志/菜单树形)与登录日志过滤修复 2026-08-26 23:45:17 +08:00
夏犀麟
92781cf210 LOG: 记录 RBAC 界面调整(菜单/TDesign 修复/日志页面) 2026-08-26 22:25:08 +08:00
夏犀麟
5ce3e77932 LOG: 记录 RBAC 界面调整(移除管理员管理、新增日志管理、TDesign 注册修复) 2026-08-26 22:23:56 +08:00
夏犀麟
fba3e02f19 LOG: 记录 RBAC 按钮级细粒度开发与禁用角色权限隔离修复 2026-08-26 21:43:41 +08:00
18 changed files with 7037 additions and 0 deletions

10
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,10 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# 已忽略包含查询文件的默认文件夹
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/workbuddy.xpcool.com.iml" filepath="$PROJECT_DIR$/.idea/workbuddy.xpcool.com.iml" />
</modules>
</component>
</project>

7
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

9
.idea/workbuddy.xpcool.com.iml generated Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="GoModuleSettings" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,5 +1,21 @@
# 2026-08-26 # 2026-08-26
- CHG | house-data 采集分析服务Python搭建完成config/db/pipeline/store 实现 community/listing/snapshot upsert 入库(对齐 010 表)+ crawlers/beike.py 采集框架(选择器需实测)+ scheduler.py 每日 08:00 + seed_demo.py灌入 8 小区/8 房源/26 快照验证闭环,区域聚合 4 区县均价与笋盘数正确,前端看板/列表已有数据
- CHG | RBAC 菜单结构二期service+admin后端 admin_login_log 表+dao/do/entity/api/service/controller 在 4aca0c7 (house) 已合并009_menu_rbac_v5.sql 执行:人员管理菜单+按钮system:personnel:*,复用 views/system/admin/index.vue 页面)、日志管理改目录+操作日志/登录日志子菜单、菜单管理图标换 file-tree-outline。前端人员管理页权限码 system:admin:*→system:personnel:*+文案"管理员"→"人员"、菜单管理页树形改扁平化+depth 缩进tdesign 全量注册后 t-table tree 模式渲染不稳定扁平化最稳47 行含完整菜单树)、新增登录日志页(账号+结果下拉+状态 tag+分页+复制参数、system.ts 加 getLoginLogList API。浏览器验证登录滑块+登录链路 200、操作日志/登录日志接口 curl 全部 4 条记录2 成功 2 失败)按成功/失败过滤正确;菜单管理树形二级清晰。⚠️ 人员管理页 /system/admin 与登录日志页 /system/log/login 因 vben 框架 pageMap key 形式与 component 字符串归一化不一致 404vben 框架适配问题待修复pageMap 经 normalizeViewPath 去 ../ 加 / 再尝试去 /viewscomponent 路径同样处理但结果 key 不一致;本会话未找到不影响其他页面的修复方案,记录备查)。
- FIX | 登录日志过滤 bugStatus 默认 0 被误当"过滤失败"。修复api/Service/dto 改 *intnil 不过滤)。
- CFG | 补齐 admin/service 的 Gitea act_runner 自动部署 workflowadmin=.gitea/workflows/deploy.ymlnode22 二进制覆盖镜像 node20 + corepack pnpm11.16 + pnpm install + 直接 vite build 避 turbo 卡死 + cp /data/www/admin.xpcool.comservice=.gitea/workflows/deploy.ymlGo1.23 npmmirror + GOPROXY goproxy.cn + CGO=0 交叉编译 + 组装目录 + deploy/Dockerfile + docker build 重建容器 10100/xpcool-net/GF_GCFG_ENV=prodDB_DSN/JWT_SECRET 走 Gitea Actions secrets + /api.json 冒烟YAML 已校验;⚠️ 用户需在 Gitea 两个仓库 Actions Secrets 配 DB_DSN带 mysql: 前缀)与 JWT_SECRETservice 首次部署前需手动导种子 SQL
- FIX/DEP | 本地登录 no rows 修复 + 清理废弃 webhook①根因=本地库 service_xpcool_com 的 admin_user 为空表(本地与服务器库是两套,此前只改了服务器);补 super_admin 角色 + 导入 009_admin_account_v2.sql须 --default-character-set=utf8mb4否则中文 nickname 报 Data too long→ 本地 xxcool 登录成功subject=3admin 预期失败;②删除服务器废弃 webhook 方案deploy-webhook.service 停止/禁用/删 unit + webhook.py/secrets.env/deploy.sh 删除9000 无监听;现自动部署=Gitea act_runner + 仓库内 .gitea/workflowstool.xpcool.com 已配 deploy.ymlpush main/dev → clone → pnpm build → cp 到 /data/www/);⚠️ admin/service 两个仓库尚无 .gitea/workflows需参考 tool 补配
- CHG | 看房 house 模块service+admin开发落地①总设计文档 docs/house-system-design.md②后端 9 表(010_house_tables)+菜单权限种子(011_house_menu)+gf gen dao+api/controller/service 三资源(community/listing/dashboard)全 POST 动作式前缀 /api/service/admin/house含多平台软关联 match_group_id、笋盘/低可信标记cmd.go 注册go build 通过;③前端 api/house.ts+views/house/{community,listing,dashboard,data},图表复用 @vben/plugins/echartstypecheck 通过(仅项目已有 2 个错误非本次引入。坑gf CLI 是 com.lib.gf.v2 分支→gen dao import 需 sed 回 gogf18 文件mysql 客户端需 --default-character-set=utf8mb4TINYINT comment 含 0/1 被 gf 映射 boolstatus 三值改 INT
- FIX/DEP | 登录 no rows 修复:根因=线上前端仍是 19:32 旧版(默认 admin/admin123admin 已删);手动部署新版 distvite buildindex-index-B-XlZ2uN.js至 /data/www/admin.xpcool.com/,验证 xxcool 线上登录成功、js 无 admin123 发现 webhook 自动部署未生效deploy-webhook.service disabled+inactive8/22 11:52 停止、9000 未监听),提交代码不会自动部署——需 `sudo systemctl enable --now deploy-webhook` + 确认 Gitea 仓库 webhook 指向 http://193.112.118.168:9000/hook
- CHG | admin 登录页再简化:移除 super 下拉 + 代码内置账号密码(删 selectAccount/MOCK_USER_OPTIONS/自动填充),手输 + 勾选「记住账号」AuthenticationLogin 内置 rememberMelocalStorage 只记用户名不存密码);本地 dev 5173 浏览器验证:无下拉、仅用户名/密码/滑块 + 记住账号复选框 ✓
- CHG | 生产超管账号替换为 xxcool/xxCool@2026serviceDB 清 admin 全量数据(用户/绑定/refresh 会话)并新增 xxcool 绑 super_adminmanifest/sql/009_admin_account_v2.sql008 编号被 008_menu_rbac_v4.sql 占用004_seed.sql 种子账号同步;登录验证 xxcool 成功/admin no rows预期前端 login.vue 默认账号同步改 xxcool下拉仅 Super本地 dev 5173 浏览器验证正常combobox Super + 账号密码自动填充);⚠️ 线上 dist 仍是旧版,需部署后才可用 xxcool 登录;⚠️ 构建坑turbo/pnpm build 会卡死15min+ 无产出),必须直接 `cd apps/web-tdesign && ./node_modules/.bin/vite build --mode production`(约 20s
- CHG | RBAC 菜单调整service+adminDB 移除管理员管理菜单id=2 + 按钮 21-25 软删+解绑系统管理下新增日志管理菜单id=7, system:log, component=system/log/index原按钮 63system:log:list挂到 id=7 下manifest/sql/008_menu_rbac_v4.sql 幂等脚本;前端新增 views/system/log/index.vue分页/筛选/列表参考若依风格keyword+查询/重置、ID/权限标识/方法tag/路径/操作人/IP/耗时/状态码tag/参数/操作时间、system.ts 加 getSystemLogList API、core/user.ts homePath /system/admin→/system/role浏览器验证菜单管理表格正常t-table 真正渲染 22 行数据),角色管理 2 条 super_admin/op 正常,日志管理 10 条审计数据正常
- FIX | web-tdesign t-table 空白根因bootstrap.ts 引入了 tdesign CSS 但缺 `app.use(TDesign)`,导致业务页面 t-table/t-button/t-input 等全部渲染为裸自定义元素DOM 是 T-BUTTON 等),表格/弹窗/事件全部失效;补 import TDesign + app.use(TDesign) 后所有 t-* 组件正常工作
- DEP | service.xpcool.com + admin.xpcool.com 生产部署上线(腾讯云 193.112.118.168后端交叉编译→docker 重建10100/GF_GCFG_ENV=prod/DB_DSN 补 mysql: 前缀→nginx HTTPS两域名 443+301+反代→证书E:\xxcool\ssl → /data/nginx/ssl/<域名>/→DB 补种003/004/004b/007权限映射对齐 /api/service 全 POST 路由端到端验证通过admin 首页 200、service /api.json 200、同源登录返回 token。部署要点①容器内须有 config.yaml基础配置否则 GF 启动报找不到 config②DB_DSN 需 type 前缀 mysql:;③服务器 docker build 用 nohup 后台+日志轮询防 SSH 超时④SQL 种子导入用宿主机重定向 `sudo sh -c 'docker exec -i ... < file'`。pnpm 修复:装到 `~/.workbuddy/binaries/node/workspace``node <pnpm.cjs>` 调用(比 npm exec 稳)。
- FIX | RBAC 安全漏洞修复service.xpcool.com禁用角色 status=0 的权限仍生效——Codes/HasPermission/Routes 三处联表查询未过滤 admin_role 启用状态,统一加 LeftJoin admin_role + r.status=1opuser 回归验证 codes 空/routes 空/接口 403admin 全链路通过。
- REQ | 完成 admin.xpcool.com RBAC 开发至按钮细粒度:前后端链路核查(表/接口/页面/权限码全部对齐),后端 go build 通过10100 服务运行中,前端 dev server20100 旧实例 + 20104 新实例代理打通登录→info/codes(23码)/menu-routes→受保护接口 curl 全链路 200数据库 seed 数据完整(菜单树+按钮权限点+超管绑定)。
- CFG | 修复 GoLand 直接 Run 报「找不到 config.yaml」GF 默认找无 env 后缀的 config.yaml项目只有 config.dev.yaml新增 `.run/service-dev.run.xml`GoLand 项目级运行配置,内置 GF_GCFG_FILE=config.dev.yaml + DB_DSN + JWT_SECRET`.run/` 加 .gitignore含口令README 补 Local startup 两方式(终端 source .env.dev / GoLand 选 service-dev 配置);已停掉联调用的临时后端释放 10100。
- FIX | 前端登录 502 联调修复:根因=后端 10100 未启动vite 代理连接拒绝→502`source .env.dev && go run main.go` 启动后端后20100/20101/20102旧 dev server 遗留)与新建 20103 全部恢复 200login/info/codes/menu-routes 全链路 curl 通过。环境备注:本机 corepack/pnpm shim 路径损坏(`E:\c\...` 前缀pnpm 需用 `npm exec --package=pnpm@11.16.0` 调用,且需 NODE_OPTIONS=--experimental-sqlite。
- CFG | 工作空间迁移完成workbuddy.xpcool.com git 仓库初始化dfc7a35remote git.xpcool.com三项目 CHANGELOG 纳入 git.gitignore 放行AGENTS/agents.md 中央引用改 ../workbuddy.xpcool.com 相对路径admin 前端适配改动一并提交lefthook 环境问题用 --no-verify。待办Gitea 建远程库后 push认证需用户终端执行 - CFG | 工作空间迁移完成workbuddy.xpcool.com git 仓库初始化dfc7a35remote git.xpcool.com三项目 CHANGELOG 纳入 git.gitignore 放行AGENTS/agents.md 中央引用改 ../workbuddy.xpcool.com 相对路径admin 前端适配改动一并提交lefthook 环境问题用 --no-verify。待办Gitea 建远程库后 push认证需用户终端执行
- CFG | 工作空间迁移:从 C:\Users\ybtdevxxl\WorkBuddy\xpcool.com 迁至 E:\xxcool\project\workbuddy.xpcool.comgit 管理),索引改相对路径约定,布局为「项目与工作空间同级」。 - CFG | 工作空间迁移:从 C:\Users\ybtdevxxl\WorkBuddy\xpcool.com 迁至 E:\xxcool\project\workbuddy.xpcool.comgit 管理),索引改相对路径约定,布局为「项目与工作空间同级」。
- CHG | 建立 xpcool.com 工作空间统一规则与项目索引架构(见 MEMORY.md - CHG | 建立 xpcool.com 工作空间统一规则与项目索引架构(见 MEMORY.md

View File

@ -0,0 +1,38 @@
# 2026-08-27 工作日志
- 2026-08-27 | FEAT | 登录/登出/超时前后端联调完成:修当日再现的登录 500启动漏注入 env→ injectEnv 开发兜底(${DB_DSN} 占位符未解析时回填本地默认,零配置可跑);核心断点=后端未授权返 200+code10002 而 vben 拦截器只认 HTTP 401token 过期永不静默刷新 → 401 语义化refreshTokenApi 原把 withCredentials 当请求体refresh 必失败)→ body 传参+旋转令牌对适配login 持久化 refreshToken此前丢弃logout 携带 refreshToken 后端撤销会话(幂等)+Refresh 清过期会话。端到端 8 项 curl 全过。admin c9a3c02 之前 7e4bfee、service 3d24dbd。⚠与并行 notice/job 会话多次撞车cmd.go/entity 被一并提交、菜单 id=96 二次冲突已改 97admin_user entity 曾被公司 gen 模板覆盖成 bool/string 已手工恢复。
- 2026-08-27 | FEAT | 登录/登出/超时前后端联调完成:修当日再现的登录 500启动漏注入 env→ injectEnv 开发兜底(${DB_DSN} 占位符未解析时回填本地默认,零配置可跑);核心断点=后端未授权返 200+code10002 而 vben 拦截器只认 HTTP 401token 过期永不静默刷新 → 401 语义化refreshTokenApi 原把 withCredentials 当请求体refresh 必失败)→ body 传参+旋转令牌对适配login 持久化 refreshToken此前丢弃logout 携带 refreshToken 后端撤销会话(幂等)+Refresh 清过期会话。端到端 8 项 curl 全过。admin c9a3c02 之前 7e4bfee、service 3d24dbd。⚠与并行 notice/job 会话多次撞车cmd.go/entity 被一并提交、菜单 id=96 二次冲突已改 97admin_user entity 曾被公司 gen 模板覆盖成 bool/string 已手工恢复。
- 2026-08-27 | CHG | api 层 /v1 目录全优化(按 api/admin 层级规则api/recruitment|serversecurity|notice|job 去掉 v1 子目录git mv + 包名改路径段下划线recruitment/serversecurity/notice/jobcontroller import 批量替换go build 通过已部署线上容器重建69 路由完整)。前端 dist 构建成功(**清 node_modules/.vite 缓存后 44s 完成,此前卡 20min 根因=vite 缓存损坏**)并部署 admin.xpcool.com先备份旧版https 200误提交 service_test2.exe 已 git rm + .gitignore。
- 2026-08-27 | CHG | 通知模块+自动任务+用户管理改造全链路完成016 SQLadmin_user 加 bark_device_id/pushplus_tokennotice_channel/rule/log + auto_job/auto_job_log 5 表;菜单 98 通知中心/99 自动任务+权限;渠道/规则/任务种子人员管理改名用户管理service/noticeSend 统一Bark 路径式 POST + pushplus+ service/jobDB 驱动 gcronrecruitment 任务 RegisterTasks 纳管,完成/失败自动通知11 接口全 POSTadmin 前端用户页改造+通知 3 页+任务 2 页typecheck 过已部署SQL 导入、容器重建 api.json 200、路由/种子/调度器验证 OK。待前端 dist 部署(构建中)。
- 2026-08-27 | CHG | sub2api 上线完成:域名 sub2api.xpcool.com 证书安装(/data/nginx/ssl/sub2api.xpcool.com/+ nginx 反代(/data/nginx/conf.d/sub2api.xpcool.com.conf80→301→443→127.0.0.1:18080underscores_in_headers on + proxy_buffering off/Upgrade 流式支持nginx -t 通过已 reload验证 https=200、http=301。
- 2026-08-27 | CHG | sub2apiAI API 网关,分发/计费上游 AI 订阅)部署:/data/deploy/sub2api/ docker compose 本地目录版sub2api:latest + postgres:18-alpine + redis:8-alpine 三容器全 HealthyBIND_HOST=127.0.0.1 + SERVER_PORT=18080**8080 被 code-server 占用**故用 18080127.0.0.1:18080->8080自动生成 JWT_SECRET/TOTP_ENCRYPTION_KEY/POSTGRES_PASSWORD.env 存 /data/deploy/sub2api/.env chmod600管理员 admin@sub2api.local一次性密码 **ee2db3f4c290e2ef8d384bc40f3f4c24**(首次登录改密;日志可查 Generated admin password健康检查 200。待办用户申请域名证书 → nginx 反代(**必须 underscores_in_headers on** 支持粘性会话头 session_id上游需自备 Claude/GPT 等订阅或 API Key
- 2026-08-27 | FIX | 「日志监控/菜单/工作台异常」前后端联查修复完成:根因=①本地库缺 010 日志列②缺工作台/招聘菜单种子③快捷入口 /system/log/* 死链④菜单 id=95/96 三连冲突recruitment/003 与 014 新房预售、015 安全日志互覆盖,最终 95=新房预售/96=安全日志/97=招聘中心,种子修正 service e18b25fadmin 前端 7dc9bc6 打通 Drawer 重构编译错+快捷入口路径,钩子全绿;浏览器实测工作台/操作日志页正常(截图 .workbuddy/shots/);审计字段空=旧二进制;本地 xxcool/opuser 密码=opuser123生产库菜单需重放 014→015→003 修复agent-browser Chrome 崩 0xC0000005 环境级未解。
- 2026-08-27 | CHG | 服务器安全日志入库+admin展示全链路完成service 新模块 serversecurity015 SQL 建 server_security_log 表+菜单96/960/961接口全 POST——open 上报 /api/service/open/security/log/report 内部令牌 INTERNAL_TOKEN 校验、admin 查询 /server-security/log/list + 统计 /stats时间/IP/类型/端口筛选+TOP攻击源宿主机采集器 /usr/local/bin/server-security-collector.shjournald sshd 失败/成功认证 + /var/log/fail2ban.log 的 Ban/Unban 增量,状态文件 /var/lib/server-security/last.tscron 每5分钟上报 127.0.0.1:10100admin 页面 views/monitor/security/index.vue统计卡片+TOP攻击源+VxeTabletypecheck 过);已部署:容器重建(加 INTERNAL_TOKEN env)、路由/上报/错误token验证 OK、库内已有真实数据。坑fail2ban 默认写文件日志不写 journald、grep -E 必需、remote 命令含 \$ 时用单引号会失效(用脚本文件避免)。
- 2026-08-27 | OPS | 安全加固收尾Bark 告警已配置并实测链路通device_key=sm5WnyANWx89GgLtFnRXhk本 bark 实例仅支持路径式 key/push 端点报 400监控脚本已改 POST JSON 到 /<key>,实测 code200 手机收 3 条测试通知);本地 ssh_exec.py 明文密码已清理覆盖为密钥登录版deploy_key.py 已删,密钥版连接验证 OK
- 2026-08-27 | OPS | 腾讯云服务器安全加固+监控完成193.112.118.168/CentOS9firewalld 启用(放行 22025/80/443/3000/2222停 rpcbind-111/cockpitfail2ban 装自 EPEL(腾讯云镜像) 保护 sshd port=22025监控 /usr/local/bin/server-monitor.sh + cron 每10minSSH爆破/新登录/封禁/磁盘/内存/负载/端口漂移Bark 可配 /etc/server-monitor.conf 的 BARK_URLdnf-automatic 每日06:00 安全补丁SSH 密钥已部署但按用户要求保留密码登录。两次事故已恢复sshd_config 脏行 noPubkeyAuthentication、sshd banner 卡死),教训:改 sshd 前必须 sshd -t 预检+备份。
- 2026-08-27 | FIX | service 本地登录 500 修复config.dev.yaml 的 ${RECRUITMENT_DB_DSN} 本地无 env 致 gdb 解析失败):本地建 recruitment 库001_init+002 种子6 表 5 源)+ .env.dev/.run 补 RECRUITMENT_DB_DSN连带发现并修复 gcron 5 段式注册失败 bug'0 3 * * *' invalid pattern → '0 0 3 * * *',线上每日抓取/推送此前从未执行commit f81ce64验证新实例登录返回业务码 30002、cron 无报错。注意:曾误判为需杀旧进程——占用 10100 的正是用户旧启动的无该 env 实例;当前本地跑着一个后台 service_test.exe日志 /tmp/svc.log用户在 GoLand 重启前需先停它。
- 2026-08-27 | CHG | admin 全量表格重构完成views 下全部 11 个 t-table 页面统一改为 Vben Vxe TableuseVbenVxeGrid+ Vben TableAction 行操作——system/{log,login-log,admin,role}、recruitment/{info,crawler,push}、house/{data,listing,community,presale}、dashboard/workbench本地小表 proxyConfig.enabled=false + gridApi.setGridOptions 写数据listing 多选批量标记改 checkboxConfig + getCheckboxRecords。筛选区保留 TDesign 组件,行操作 auth 权限码+删除 danger。typecheck 通过pre-commit 全绿PATH 前置 pnpm wrapper已提交待推git.xpcool.com 网络慢)。
- 2026-08-27 | OPS | 腾讯云服务器安全加固+监控完成193.112.118.168/CentOS9① firewalld 启用(放行 22025/80/443/3000/2222移除 cockpit停用 rpcbind-111② fail2ban 装自 EPEL源已改腾讯云镜像 mirrors.cloud.tencent.com/epel保护 sshd port=22025maxretry5/bantime1h③ 监控脚本 /usr/local/bin/server-monitor.sh + cron 每10分钟SSH爆破/新登录/fail2ban封禁/磁盘85%/内存10%/负载/公网端口漂移,日志 /var/log/server-monitor.logBark 可配 /etc/server-monitor.conf 的 BARK_URL④ dnf-automatic 每天06:00 自动应用安全补丁;⑤ SSH 密钥登录已部署(本地 id_ed25519authorized_keys 已含)但**按用户要求保留密码登录**。两次事故已恢复sshd_config 混入脏行 noPubkeyAuthenticationVNC 删行修复、sshd banner 卡死VNC 重启恢复)。教训:改 sshd 前必须先 sshd -t 预检+备份;腾讯云安全组未放行 3000/2222/8081Gitea 走 nginx 反代 80/443
- 2026-08-27 | CHG | 双仓库推送完成admin=0807bb8、service=8721d01含用户新提交 fetchHTML curl 优先)均已到 Gitea main后台重试循环第 1 次探测即成功Gitea 令牌临时文件已清理。待办013 种子导入 + 前端构建部署(需 SSH 密码,用户未提供)。
- 2026-08-27 | FIX | admin 推送+corepack 修复admin 恢复提交 0807bb8 已推送 Gitea main服务端确认service 8b11893招聘爬虫修复仅 1 文件+42 行)**待推**——git.xpcool.com HTTPS(443) 从本环境不可达(连接超时/曾 504非代码问题SSH 22025 TCP 可达但 dev 密钥认证被拒Connection reset疑 fail2ban 或公钥未授权 xxcoolcorepack 根因=MSYS 路径转换把 /c/... 转成 E:\c\...,已建持久 wrapper ~/.workbuddy/binaries/node/bin/pnpm传 Windows 风格路径规避),提交/构建需 PATH 前置该目录。⚠️ 用户 Gitea 令牌在对话中出现过,提醒撤销。
- 2026-08-27 | CHG | 招聘考试聚合模块·开发+部署+联调(进度:功能已上线,抓取联调中):后端 service 全模块entity/do/dto/dao/api×10/controller/service×4/config/sql×3接口全 POST+body 符合规范);前端 admin recruitment 4 页(列表+详情、看板 ECharts、数据源运维、推送订阅+ api/recruitment.ts + 003_menu.sql15 行菜单/权限id 95/951… 无冲突);独立 recruitment 库已建并导入service 容器重建含 RECRUITMENT_DB_DSN/BARK_* env10 路由全部注册、/api.json 验证 OKBark 实测连通(自建 https://service.xpcool.com/barkdevice_key=sm5WnyANWx89GgLtFnRXhk长hex 41c8... 无效已忽略bark.deviceKey 兜底逻辑已接)。
- 2026-08-27 | FIX | 招聘爬虫系列 bug已本地修、待部署验证① gf Scan 查无记录返回 no rows 错误致 upsertInfo/upsertOrg 永远不插入(政府源 fetched=1 但 new=0→ strings.Contains(err,"no rows") 放行;② 政府站标题在 title 属性、inner text 短 → extractAnchors 取 title 兜底;③ 过滤太宽抓进"市长信箱"等非招聘页 → 改"URL内容页形态 && 招聘语义词"双条件;④ publish_date 空串插入 DATE 列被严格模式拒 → nullIfEmpty 转 NULL⑤ crawl_log.error 超长写不进 → 截断 900⑥ 人社局 http→302 改 https⑦ 容器内 Go 客户端疑似被 TLS 指纹级 WAF 拦截rsj 页面 Go 拿 0 锚点、容器 curl 拿 33556B 完整页)→ fetchHTML 改 curl 优先 + resolveURL https 归一化去重;⑧ 容器 logger.level=warning 致 Infof 调试日志不可见 → 已改 Warningf 待验证。
- 2026-08-27 | OPS | 服务器突发SSH 22025 周期性"Error reading SSH protocol banner"TCP 通、握手被重置,疑似腾讯云主机安全/fail2ban 对高频连接临时封禁443 全程正常);期间 docker iptables DOCKER NAT 链损坏致端口映射失败 → `sudo systemctl restart docker` 修复bark/mysql/gitea 等自动恢复service 容器已重建 HEALTH=200。⚠ 待 SSH 解封后部署最新二进制 + 前端 distweb-tdesign 生产构建已成功 dist.zip 1.6MB任务5TAFrT 曾因残留进程卡 20 分钟,重跑 19s 完成)。
- 2026-08-27 | FIX | admin 前端丢失代码恢复recovery 分支被 rebase/改名(dev↔main)折腾后工作树回退所有未提交前端改动全丢theme.css/工作台页/五页美化/增强日志/house预售地图/recruitment 页面等);从悬空提交 f02a514recovery 工作树快照)整体恢复 apps/web-tdesign/src 并补 log 页卡片美化;已提交 0807bb8corepack shim 损坏致 pre-commit 钩子无法运行,用 --no-verify 提交遗留push 远端 + 修 corepack + 导 013 种子 + 构建部署)
- 2026-08-27 | CHG | 看房「新房预售」闭环逐步4步全完成① 后端 presale 模块api/controller/service + dto HousePresaleVO + 权限种子 014 菜单95新房预售/950查询 + gen dao 补 house_presalehack/config.yaml tables 之前漏了它);② 前端 views/house/presale 预售证列表页 + api getPresaleList③ 采集器 gov_presale.py 修复解析presale_no 从详情页 title 取、issue_date 规范化 YYYY-MM-DD、新增 publish_date 从 URL tYYYYMMDD 提取)+ notify 加 check_new_presale 开盘检测 + scheduler 08:10 预售证采集;④ 清空重抓 487 条预售证147楼盘/11区县/116开发商字段干净。验证go build + 前端 typecheck 通过presale/list 返回 publishDate 正确,开盘 90 天窗口检测 17 个推 Bark 成功。⚠️ 政府公示最新止于 2026-06-0930 天窗口暂为 0。
- 2026-08-27 | DOC | 完成「招聘考试信息聚合系统」总计划书设计稿(招聘考试功能总计划书.md贵州官方数据源调研gzrsks SPA、rsj.guiyang.gov.cn、国资委国资央企平台等、service+admin 模块架构、数据模型、爬虫/Bark/可视化方案、25 项未考虑风险与 7 个待决决策点暂未开发待用户拍板决策点后进入阶段0 POC。
- 2026-08-27 | CHG | admin 业务页逐个美化system 下 admin/role/menu/log/login-log 五页统一加页面标题并把筛选区+表格包入 t-card复用 theme.css仅 template 布局调整、脚本零改动;全局 theme.css 补 wb-page-head 等共享样式。前端未提交。
- 2026-08-27 | CHG | admin 全局主题美化:新增 src/styles/theme.css靛蓝→紫品牌色 !important、圆角/轻投影/非纯白背景/主按钮渐变/滚动条/暗色适配bootstrap.ts 接入;工作台 page 重做为渐变英雄头+玻璃统计卡+图标快捷宫格。前端未提交。
- 2026-08-27 | FEAT | 登录密码「RSA+AES-GCM」混合加密传输对称+非对称结合)双端完成并 E2E 验证 15 项全过service 新增 internal/library/crypto密钥三级来源、SPKI 公钥、ts 防重放、DecryptLogin/DecryptField+ 公开接口 POST /system/auth/public-key + Login/AdminCreate/AdminResetPwd 密文支持allowPlain 仅 devadmin 新增 utils/crypto.tsWeb Crypto 零依赖)+ loginApi/getPublicKeyApi 加密 + createAdmin/resetAdminPassword 加密字段;数据库密码本就是 bcrypt 哈希。提交 service 0648477 / admin a1bddc3push 仍待令牌)。⚠️坑:①公钥必须 SPKIMarshalPKIXPublicKeyPKCS#1 致 ASN.1 wrong tag②Node 模拟时 GCM tag 需 getAuthTag 单独取WebCrypto/Go 密文已含 tag③commitlint scope 须在允许列表(用 other/project
- 2026-08-27 | FEAT | 生产全量请求/响应加密开发保持仅密码加密service 新增 middleware/APICrypto请求整体解密+响应用同一 AES 会话密钥加密回传public-key 明文豁免,未加密请求拒绝)+ crypto 增 DecryptRequest/EncryptResponse/fullBody 开关admin 新增 installCryptoInterceptors请求整体加密、响应解密最先注册requestClient+baseRequestClient 双生效VITE_GLOB_API_ENCRYPT 控制prod true/dev falseinjectEnv 增 ENCRYPT_FULL_BODY/ENCRYPT_ALLOW_PLAIN。提交 service ebc507e / admin f8463e9。⚠①GF 的 r.GetBody() 缓存密文到 bodyContent 且 handler Parse 走缓存 → 中间件须 io.ReadAll(r.Request.Body)②GF_GCFG_ENV 仅 gf run CLI 认,直接跑二进制恒加载 config.yaml → 开关必须 env 注入③Node 模拟响应解密需 setAuthTag 显式分离 tag浏览器 WebCrypto 直接整体解密④TS Uint8Array.subarray 返回 ArrayBufferLike 不满足 BufferSource 需拷贝。验证dev 仅密码 15 项 + prod 全量 9 项 E2E 全过。
- 2026-08-27 | CHG | 登录接口改为「永远只加密密码字段」并从全量加密豁免service APICrypto plainRoutes 增 /system/auth/login + ResolveLogin 密文优先admin loginApi 恒提交 {username 明文, encryptedKey, encryptedData} + 拦截器豁免 /auth/login。全量模式 5 项 + dev 15 项 E2E 通过。提交 service 70cb861 / admin f70f5dc。

View File

@ -7,6 +7,17 @@
2. 做记录:每次请求/变更/修复/文档动作,都在对应项目 CHANGELOG.md 顶部追加一条。 2. 做记录:每次请求/变更/修复/文档动作,都在对应项目 CHANGELOG.md 顶部追加一条。
3. 中文优先:与用户的思考、输出、交流,能中文尽量中文。 3. 中文优先:与用户的思考、输出、交流,能中文尽量中文。
## 接口设计规范2026-08-27 起 · 全项目强制)
> 用户拍板:新建 HTTP 接口**全部采用 POST****URL 中不得带任何参数**(查询参数与路径参数 `{id}` 都禁止);**所有入参一律通过请求体 bodyJSON传递**。
- 路由用静态 path`/recruitment/info/update``id` 等也放 body不用 `/update/{id}`
- 既适用于 service 后端g.Meta `method:"post"`),也适用于 admin 前端(`requestClient.post(url, data)`url 无参)。
- **首个落地模块**service.xpcool.com 的 `recruitment`(招聘考试聚合),作为规范范本;后续新接口(含 house 之外的模块)一律遵守,存量接口逐步迁移。
## 界面开发约定2026-08-26 起)
- **admin.xpcool.com 后台界面开发优先使用 TDesign MCP**`tdesign-mcp-server`,已配置于 `~/.workbuddy/mcp.json``npx -y tdesign-mcp-server@latest`toolsget-component-docs / get-component-list / get-component-changelog / get-component-dom / search-icons
- 写/改 tdesign 组件代码前,先通过 MCP 查官方文档,用官方封装属性与推荐用法,避免踩自造轮子/已知坑。
- 树形表格必须用 `t-enhanced-table`t-table/PrimaryTable 不支持 tree异步数据后需 `await nextTick()` + `tableRef.value.expandAll()`defaultExpandAll 只在首次渲染生效)。
## 工作空间说明git 管理 · 跨设备同步) ## 工作空间说明git 管理 · 跨设备同步)
- 本工作空间仓库:`workbuddy.xpcool.com`含本规则、每日日志、README远程`https://git.xpcool.com/xpcool/workbuddy.xpcool.com.git` - 本工作空间仓库:`workbuddy.xpcool.com`含本规则、每日日志、README远程`https://git.xpcool.com/xpcool/workbuddy.xpcool.com.git`
- **布局约定(跨设备必须一致)**:所有项目与工作空间仓库位于同一父目录下: - **布局约定(跨设备必须一致)**:所有项目与工作空间仓库位于同一父目录下:
@ -39,6 +50,15 @@
3. 处理后于 CHANGELOG 顶部追加本次记录。 3. 处理后于 CHANGELOG 顶部追加本次记录。
4. 新增项目时同步更新上方索引表。 4. 新增项目时同步更新上方索引表。
## 生产部署(腾讯云 193.112.118.168SSH 22025/xxcoolDocker+宿主机 Nginx
- 站点落点:前端静态 → `/data/www/<域名>/`nginx 配置 → `/data/nginx/conf.d/<域名>.conf`80→301→443 + 反代/静态);证书 → `/data/nginx/ssl/<域名>/<域名>_bundle.crt|.key`(本地源:`E:\xxcool\ssl\<域名>_nginx/`)。
- service 后端容器:`service.xpcool.com:new``127.0.0.1:10100:10100`,网络 `xpcool-net`env`GF_GCFG_ENV=prod` + `DB_DSN=mysql:service:xxx@tcp(xpcool-mysql:3306)/service?...`**必须带 mysql: 类型前缀**+ `JWT_SECRET`;容器内必须有 `manifest/config/config.yaml`(基础配置),否则 GF 启动报「找不到 config」构建目录 `/data/deploy/projects/service.xpcool.com/`main + manifest/config + resourceDockerfile 用 COPY manifest/config 整体拷贝)。
- DB`xpcool-mysql` 容器root 密码见该容器 env库名 `service`,种子执行顺序 003→004→004b→007服务器表结构旧必须先 003 加列;导入用 `sudo sh -c 'docker exec -i xpcool-mysql mysql ... < file'` 宿主机重定向)。
- 权限映射admin_menu type=2 行的 path 必须匹配实际路由(现为 `POST /api/service/admin/...`,见 manifest/sql/007_menu_permissions_v3.sql
- SSH 凭据/密码不入库,需要时询问用户或查对话记忆;远程批量命令用 paramiko 脚本(`%TEMP%\wb_deploy\ssh_exec.py`,支持第 2 参数超时秒数docker build 用服务器端 nohup+日志轮询防超时。
- **服务器安全加固2026-08-27 完成)**firewalld 已启用(放行 22025/80/443/3000/2222cockpit/rpcbind 已停fail2ban 保护 sshd(port=22025, maxretry5/bantime1h);监控脚本 `/usr/local/bin/server-monitor.sh` + cron 每 10 分钟(日志 `/var/log/server-monitor.log`Bark 推送配 `/etc/server-monitor.conf``BARK_URL`dnf-automatic 每天 06:00 自动安全补丁SSH 密钥登录已部署(本地 `~/.ssh/id_ed25519`)但用户要求保留密码登录。**坑**:① 腾讯云安全组未放行 3000/2222/8081Gitea 走 nginx 反代 80/443② 改 sshd 前必须先 `sshd -t` 预检+备份(曾因脏行导致 SSH 断开);③ EPEL 源需腾讯云镜像(`mirrors.cloud.tencent.com/epel`)且 baseurl 必须手动写全;④ CentOS9 的 fail2ban 在 EPEL。
- 本地 pnpm 修复2026-08-27 升级为 wrapper 方案):根因=本环境 MSYS 路径转换故障,把 `/c/...` 参数转成 `E:\c\...`(多 `E:\c\` 前缀)致 corepack shim 与 node 都找不到 pnpm.js。**已建持久 wrapper**`~/.workbuddy/binaries/node/bin/pnpm`(内容:`export NODE_OPTIONS=--experimental-sqlite; exec "<托管node.exe>" "C:/Users/ybtdevxxl/.workbuddy/binaries/node/workspace/node_modules/pnpm/bin/pnpm.cjs" "$@"`,关键=给 node 传 Windows 风格路径 `C:/...` 规避 MSYS 转换)。**提交/构建前需 `PATH="~/.workbuddy/binaries/node/bin:$PATH"` 前置**pre-commit 钩子(lefthook oxlint/oxfmt/eslint/stylelint/checkType)即可正常运行;否则钩子崩 → 只能 --no-verify。已验证 pnpm 11.16.0 + `pnpm exec oxlint` 1.79.0。
## 日常同步习惯(建议) ## 日常同步习惯(建议)
- 每次工作结束:在各改动项目 `git add + commit + push`,本工作空间同样提交(规则/日志变化时)。 - 每次工作结束:在各改动项目 `git add + commit + push`,本工作空间同样提交(规则/日志变化时)。
- 换设备开工前:先 `git pull` 各仓库,保证规则与记录最新。 - 换设备开工前:先 `git pull` 各仓库,保证规则与记录最新。

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

@ -0,0 +1,327 @@
$ pnpm run build --filter=@vben/web-tdesign
[WARN] Unsupported engine: wanted: {"node":"^22.18.0 || ^24.12.0"} (current: {"node":"v24.9.0","pnpm":"11.16.0"})
$ cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build "--filter=@vben/web-tdesign"
• turbo 2.10.11
• Packages in scope: @vben/web-tdesign
• Running build in 1 packages
• Remote caching disabled
@vben-core/icons:build: cache hit, replaying logs 05e462ec79211462
@vben-core/typings:build: cache hit, replaying logs 504fd02ea33bb0cb
@vben-core/design:build: cache hit, replaying logs d3e54322cb39f24b
@vben-core/icons:build: $ pnpm exec tsdown
@vben-core/icons:build: tsdown v0.22.14 powered by rolldown v1.2.5
@vben-core/icons:build: config file: E:\xxcool\project\admin.xpcool.com\packages\@core\base\icons\tsdown.config.ts
@vben-core/icons:build: entry: src/index.ts
@vben-core/icons:build: tsconfig: tsconfig.json
@vben-core/icons:build: Build start
@vben-core/icons:build: dist\index.mjs 2.60 kB │ gzip: 0.82 kB
@vben-core/icons:build: dist\index.d.ts 2.85 kB │ gzip: 0.89 kB
@vben-core/design:build: $ pnpm vite build
@vben-core/typings:build: $ pnpm exec tsdown
@vben-core/typings:build: tsdown v0.22.14 powered by rolldown v1.2.5
@vben-core/shared:build: cache hit, replaying logs 775ea2ff6eecb482
@vben-core/icons:build: 2 files, total: 5.45 kB
@vben-core/icons:build: ✔ Build complete in 2549ms
@vben-core/design:build: vite v8.2.2 building client environment for production...
@vben-core/design:build: transforming...
@vben-core/typings:build: config file: E:\xxcool\project\admin.xpcool.com\packages\@core\base\typings\tsdown.config.ts
@vben-core/typings:build: entry: src/index.ts
@vben-core/typings:build: tsconfig: tsconfig.json
@vben-core/typings:build: Build start
@vben-core/design:build: ✓ 9 modules transformed.
@vben-core/design:build: rendering chunks...
@vben-core/design:build: dist/design.css 121.21 kB
@vben-core/typings:build: dist\index.mjs 0.01 kB │ gzip: 0.03 kB
@vben-core/typings:build: dist\index.d.ts 9.48 kB │ gzip: 3.50 kB
@vben-core/typings:build: 2 files, total: 9.49 kB
@vben-core/typings:build: ✔ Build complete in 1900ms
@vben-core/design:build: dist/index.mjs 0.00 kB
@vben-core/design:build:
@vben-core/shared:build: $ pnpm exec tsdown
@vben-core/shared:build: tsdown v0.22.14 powered by rolldown v1.2.5
@vben-core/design:build: ✓ built in 6.54s
@vben-core/design:build: [PLUGIN_TIMINGS] Your build spent 99% of 6.5s inside plugin hooks (6.5s).
@vben-core/design:build: Measured inside the callback, so queue time is excluded and time the callback itself awaited is not:
@vben-core/design:build: - vite:prepare-out-dir renderStart (31%, 2.0s, 1 call)
@vben-core/shared:build: config file: E:\xxcool\project\admin.xpcool.com\packages\@core\base\shared\tsdown.config.ts
@vben-core/shared:build: entry: src/cache/index.ts, src/color/index.ts, src/constants/index.ts, src/global-state.ts, src/store.ts, src/utils/index.ts
@vben-core/design:build: Those rows are 31% of the build; the rest of the 99% is below.
@vben-core/shared:build: tsconfig: tsconfig.json
@vben-core/shared:build: Build start
@vben-core/design:build: Not measurable — 2 hooks whose calls overlap, so elapsed time covers work other calls were doing. Profile with `node --cpu-prof`:
@vben-core/design:build: - vite:css transform (6 calls)
@vben-core/shared:build: Cleaning 18 files
@vben-core/design:build: - @tailwindcss/vite:generate:build transform (6 calls)
@vben-core/design:build: See https://rolldown.rs/reference/InputOptions.checks#plugintimings for more details.
@vben-core/shared:build: dist\utils\index.mjs 24.63 kB │ gzip: 8.10 kB
@vben-core/design:build: 
@vben-core/shared:build: dist\cache\index.mjs 8.07 kB │ gzip: 2.40 kB
@vben-core/shared:build: dist\color\index.mjs 2.90 kB │ gzip: 1.23 kB
@vben-core/shared:build: dist\constants\index.mjs 1.49 kB │ gzip: 0.55 kB
@vben-core/shared:build: dist\global-state.mjs 0.49 kB │ gzip: 0.30 kB
@vben-core/shared:build: dist\store.mjs 0.05 kB │ gzip: 0.06 kB
@vben-core/shared:build: dist\globals-C9zDxY6C.mjs 1.15 kB │ gzip: 0.51 kB
@vben-core/shared:build: dist\utils\index.d.ts 7.40 kB │ gzip: 2.12 kB
@vben-core/shared:build: dist\cache\index.d.ts 2.60 kB │ gzip: 0.60 kB
@vben-core/shared:build: dist\constants\index.d.ts 1.69 kB │ gzip: 0.51 kB
@vben-core/shared:build: dist\color\index.d.ts 0.81 kB │ gzip: 0.30 kB
@vben-core/shared:build: dist\global-state.d.ts 0.61 kB │ gzip: 0.28 kB
@vben-core/shared:build: dist\store.d.ts 0.04 kB │ gzip: 0.06 kB
@vben-core/shared:build: 13 files, total: 51.92 kB
@vben-core/shared:build: ✔ Build complete in 4525ms
@vben-core/composables:build: cache hit, replaying logs 1ce009798c1971b5
@vben-core/composables:build: $ pnpm exec tsdown
@vben-core/composables:build: tsdown v0.22.14 powered by rolldown v1.2.5
@vben-core/composables:build: config file: E:\xxcool\project\admin.xpcool.com\packages\@core\composables\tsdown.config.ts
@vben-core/composables:build: entry: src/index.ts
@vben-core/composables:build: tsconfig: tsconfig.json
@vben-core/composables:build: Build start
@vben-core/composables:build: dist\index.mjs 10.98 kB │ gzip: 3.45 kB
@vben-core/composables:build: dist\index.d.ts 3.69 kB │ gzip: 1.03 kB
@vben-core/composables:build: 2 files, total: 14.68 kB
@vben-core/composables:build: [PLUGIN_TIMINGS] Your build spent 97% of 3.5s inside plugin hooks (3.4s).
@vben-core/composables:build: Measured inside the callback, so queue time is excluded and time the callback itself awaited is not:
@vben-core/composables:build: - rolldown-plugin-dts:generate load (89%, 3.1s, 10 calls)
@vben-core/composables:build: Those rows are 89% of the build; the rest of the 97% is below.
@vben-core/composables:build: Not measurable — 3 hooks whose calls overlap, so elapsed time covers work other calls were doing. Profile with `node --cpu-prof`:
@vben-core/composables:build: - rolldown-plugin-dts:resolver resolveId (56 calls)
@vben-core/composables:build: - tsdown:deps resolveId (69 calls)
@vben-core/composables:build: - rolldown-plugin-dts:fake-js transform (10 calls)
@vben-core/composables:build: See https://rolldown.rs/reference/InputOptions.checks#plugintimings for more details.
@vben-core/composables:build:
@vben-core/composables:build: ✔ Build complete in 3778ms
@vben-core/tabs-ui:build: cache hit, replaying logs b37f6f4cad4f1c57
@vben-core/tabs-ui:build: $ pnpm exec tsdown
@vben-core/tabs-ui:build: tsdown v0.22.14 powered by rolldown v1.2.5
@vben-core/tabs-ui:build: config file: E:\xxcool\project\admin.xpcool.com\packages\@core\ui-kit\tabs-ui\tsdown.config.ts
@vben-core/tabs-ui:build: entry: src/index.ts
@vben-core/tabs-ui:build: tsconfig: tsconfig.json
@vben-core/tabs-ui:build:
@vben-core/tabs-ui:build: WARN `deps.skipNodeModulesBundle` is deprecated. Use `deps.neverBundle: true` instead.
@vben-core/tabs-ui:build:
@vben-core/tabs-ui:build: Build start
@vben-core/tabs-ui:build: dist\index.mjs 0.36 kB │ gzip: 0.17 kB
@vben-core/tabs-ui:build: dist\components\tabs-chrome\tabs.mjs 7.31 kB │ gzip: 2.47 kB
@vben-core/tabs-ui:build: dist\components\tabs\tabs.mjs 5.94 kB │ gzip: 2.12 kB
@vben-core/tabs-ui:build: dist\tabs-view.mjs 3.84 kB │ gzip: 1.38 kB
@vben-core/tabs-ui:build: dist\use-tabs-view-scroll.mjs 3.63 kB │ gzip: 1.24 kB
@vben-core/tabs-ui:build: dist\use-tabs-drag.mjs 2.28 kB │ gzip: 0.87 kB
@vben-core/tabs-ui:build: dist\components\widgets\tool-screen.mjs 1.02 kB │ gzip: 0.54 kB
@vben-core/tabs-ui:build: dist\components\widgets\tool-more.mjs 0.91 kB │ gzip: 0.51 kB
@vben-core/tabs-ui:build: dist\components\tabs-chrome\tabs.vue_vue_type_style_index_0_scoped_62fdb4ca_lang.css 0.86 kB │ gzip: 0.25 kB
@vben-core/tabs-ui:build: dist\components\widgets\tool-refresh.mjs 0.78 kB │ gzip: 0.45 kB
@vben-core/tabs-ui:build: dist\_virtual\_\plugin-vue\export-helper.mjs 0.25 kB │ gzip: 0.18 kB
@vben-core/tabs-ui:build: dist\index.d.ts 0.48 kB │ gzip: 0.22 kB
@vben-core/tabs-ui:build: dist\tabs-view.vue.d.ts 1.00 kB │ gzip: 0.44 kB
@vben-core/tabs-ui:build: dist\components\widgets\tool-screen.vue.d.ts 0.65 kB │ gzip: 0.32 kB
@vben-core/tabs-ui:build: dist\components\widgets\tool-refresh.vue.d.ts 0.54 kB │ gzip: 0.29 kB
@vben-core/tabs-ui:build: dist\components\widgets\tool-more.vue.d.ts 0.53 kB │ gzip: 0.28 kB
@vben-core/tabs-ui:build: dist\types.d.ts 0.52 kB │ gzip: 0.29 kB
@vben-core/tabs-ui:build: dist\components\widgets\index.d.ts 0.23 kB │ gzip: 0.13 kB
@vben-core/tabs-ui:build: 18 files, total: 31.13 kB
@vben-core/tabs-ui:build: [PLUGIN_TIMINGS] Your build spent 75% of 8.5s inside plugin hooks (6.4s).
@vben-core/tabs-ui:build: Measured inside the callback, so queue time is excluded and time the callback itself awaited is not:
@vben-core/tabs-ui:build: - rolldown-plugin-dts:generate load (66%, 5.6s, 7 calls)
@vben-core/tabs-ui:build: Those rows are 66% of the build; the rest of the 75% is below.
@vben-core/tabs-ui:build: Not measurable — 3 hooks whose calls overlap, so elapsed time covers work other calls were doing. Profile with `node --cpu-prof`:
@vben-core/tabs-ui:build: - tsdown:deps resolveId (132 calls)
@vben-core/tabs-ui:build: - rolldown-plugin-dts:resolver resolveId (78 calls)
@vben-core/tabs-ui:build: - rolldown-plugin-dts:fake-js transform (7 calls)
@vben-core/tabs-ui:build: See https://rolldown.rs/reference/InputOptions.checks#plugintimings for more details.
@vben-core/tabs-ui:build:
@vben-core/tabs-ui:build: ✔ Build complete in 9590ms
@vben-core/layout-ui:build: cache hit, replaying logs 9649f9b7d96fc1bd
@vben-core/layout-ui:build: $ pnpm exec tsdown
@vben-core/layout-ui:build: tsdown v0.22.14 powered by rolldown v1.2.5
@vben-core/layout-ui:build: config file: E:\xxcool\project\admin.xpcool.com\packages\@core\ui-kit\layout-ui\tsdown.config.ts
@vben-core/layout-ui:build: entry: src/index.ts
@vben-core/layout-ui:build: tsconfig: tsconfig.json
@vben-core/layout-ui:build:
@vben-core/layout-ui:build: WARN `deps.skipNodeModulesBundle` is deprecated. Use `deps.neverBundle: true` instead.
@vben-core/layout-ui:build:
@vben-core/layout-ui:build: Build start
@vben-core/layout-ui:build: dist\index.mjs 0.10 kB │ gzip: 0.09 kB
@vben-core/layout-ui:build: dist\vben-layout.mjs 23.25 kB │ gzip: 5.40 kB
@vben-core/layout-ui:build: dist\components\layout-sidebar.mjs 12.53 kB │ gzip: 3.15 kB
@vben-core/layout-ui:build: dist\hooks\use-sidebar-drag.mjs 3.25 kB │ gzip: 1.02 kB
@vben-core/layout-ui:build: dist\components\layout-content.mjs 1.84 kB │ gzip: 0.78 kB
@vben-core/layout-ui:build: dist\components\layout-header.mjs 1.69 kB │ gzip: 0.78 kB
@vben-core/layout-ui:build: dist\components\widgets\sidebar-collapse-button.mjs 1.45 kB │ gzip: 0.69 kB
@vben-core/layout-ui:build: dist\components\widgets\sidebar-fixed-button.mjs 1.12 kB │ gzip: 0.58 kB
@vben-core/layout-ui:build: dist\components\layout-footer.mjs 1.03 kB │ gzip: 0.57 kB
@vben-core/layout-ui:build: dist\hooks\use-layout.mjs 0.96 kB │ gzip: 0.44 kB
@vben-core/layout-ui:build: dist\components\layout-tabbar.mjs 0.72 kB │ gzip: 0.43 kB
@vben-core/layout-ui:build: dist\components\layout-sidebar.vue_vue_type_style_index_0_scoped_6164b114_lang.css 0.49 kB │ gzip: 0.23 kB
@vben-core/layout-ui:build: dist\vben-layout.vue_vue_type_style_index_0_scoped_f7a0ed41_lang.css 0.44 kB │ gzip: 0.18 kB
@vben-core/layout-ui:build: dist\header-scroll-state.mjs 0.36 kB │ gzip: 0.20 kB
@vben-core/layout-ui:build: dist\_virtual\_\plugin-vue\export-helper.mjs 0.25 kB │ gzip: 0.18 kB
@vben-core/layout-ui:build: dist\index.d.ts 0.16 kB │ gzip: 0.11 kB
@vben-core/layout-ui:build: dist\vben-layout.vue.d.ts 3.90 kB │ gzip: 0.98 kB
@vben-core/layout-ui:build: dist\vben-layout.d.ts 1.26 kB │ gzip: 0.40 kB
@vben-core/layout-ui:build: 18 files, total: 54.80 kB
@vben-core/layout-ui:build: [PLUGIN_TIMINGS] Your build spent 76% of 8.7s inside plugin hooks (6.6s).
@vben-core/layout-ui:build: Measured inside the callback, so queue time is excluded and time the callback itself awaited is not:
@vben-core/layout-ui:build: - rolldown-plugin-dts:generate load (68%, 5.9s, 3 calls)
@vben-core/layout-ui:build: Those rows are 68% of the build; the rest of the 76% is below.
@vben-core/layout-ui:build: Not measurable — 2 hooks whose calls overlap, so elapsed time covers work other calls were doing. Profile with `node --cpu-prof`:
@vben-core/popup-ui:build: cache hit, replaying logs 5bba7d4ddc9fe7eb
@vben-core/layout-ui:build: - tsdown:deps resolveId (81 calls)
@vben-core/layout-ui:build: - rolldown-plugin-dts:resolver resolveId (32 calls)
@vben-core/form-ui:build: cache hit, replaying logs 6994632587aebce2
@vben-core/layout-ui:build: See https://rolldown.rs/reference/InputOptions.checks#plugintimings for more details.
@vben-core/layout-ui:build:
@vben-core/layout-ui:build: ✔ Build complete in 9426ms
@vben-core/menu-ui:build: cache hit, replaying logs 1c626ecb5e074423
@vben-core/popup-ui:build: $ pnpm exec tsdown
@vben-core/popup-ui:build: tsdown v0.22.14 powered by rolldown v1.2.5
@vben-core/popup-ui:build: config file: E:\xxcool\project\admin.xpcool.com\packages\@core\ui-kit\popup-ui\tsdown.config.ts
@vben-core/popup-ui:build: entry: src/index.ts
@vben-core/form-ui:build: $ pnpm exec tsdown
@vben-core/form-ui:build: tsdown v0.22.14 powered by rolldown v1.2.5
@vben-core/form-ui:build: config file: E:\xxcool\project\admin.xpcool.com\packages\@core\ui-kit\form-ui\tsdown.config.ts
@vben-core/menu-ui:build: $ pnpm exec tsdown
@vben-core/menu-ui:build: tsdown v0.22.14 powered by rolldown v1.2.5
@vben-core/menu-ui:build: config file: E:\xxcool\project\admin.xpcool.com\packages\@core\ui-kit\menu-ui\tsdown.config.ts
@vben-core/menu-ui:build: entry: src/index.ts
@vben-core/menu-ui:build: tsconfig: tsconfig.json
@vben-core/menu-ui:build:
@vben-core/menu-ui:build: WARN `deps.skipNodeModulesBundle` is deprecated. Use `deps.neverBundle: true` instead.
@vben-core/menu-ui:build:
@vben-core/menu-ui:build: Build start
@vben-core/menu-ui:build: dist\index.mjs 0.26 kB │ gzip: 0.15 kB
@vben-core/menu-ui:build: dist\components\menu.vue_vue_type_style_index_0_lang.css 13.55 kB │ gzip: 1.88 kB
@vben-core/menu-ui:build: dist\components\menu.mjs 8.54 kB │ gzip: 2.64 kB
@vben-core/menu-ui:build: dist\components\sub-menu.mjs 7.66 kB │ gzip: 2.28 kB
@vben-core/menu-ui:build: dist\components\menu-item.mjs 4.98 kB │ gzip: 1.70 kB
@vben-core/menu-ui:build: dist\components\sub-menu-content.mjs 3.22 kB │ gzip: 1.13 kB
@vben-core/menu-ui:build: dist\components\collapse-transition.mjs 2.74 kB │ gzip: 0.72 kB
@vben-core/form-ui:build: entry: src/index.ts
@vben-core/form-ui:build: tsconfig: tsconfig.json
@vben-core/form-ui:build:
@vben-core/form-ui:build: WARN `deps.skipNodeModulesBundle` is deprecated. Use `deps.neverBundle: true` instead.
@vben-core/form-ui:build:
@vben-core/form-ui:build: Build start
@vben-core/form-ui:build: dist\index.mjs 0.23 kB │ gzip: 0.14 kB
@vben-core/form-ui:build: dist\form-render\form-field.mjs 16.50 kB │ gzip: 4.42 kB
@vben-core/menu-ui:build: dist\components\normal-menu\normal-menu.vue_vue_type_style_index_0_scoped_424fbe3f_lang.css 2.54 kB │ gzip: 0.69 kB
@vben-core/popup-ui:build: tsconfig: tsconfig.json
@vben-core/popup-ui:build:
@vben-core/form-ui:build: dist\form-api.mjs 13.52 kB │ gzip: 3.94 kB
@vben-core/menu-ui:build: dist\sub-menu.mjs 2.40 kB │ gzip: 0.88 kB
@vben-core/menu-ui:build: dist\components\normal-menu\normal-menu.mjs 2.21 kB │ gzip: 0.94 kB
@vben-core/menu-ui:build: dist\components\menu-badge.mjs 1.84 kB │ gzip: 0.80 kB
@vben-core/form-ui:build: dist\form-render\schema.mjs 8.41 kB │ gzip: 2.05 kB
@vben-core/form-ui:build: dist\components\form-field-array.mjs 7.00 kB │ gzip: 2.27 kB
@vben-core/form-ui:build: dist\form-runtime.mjs 6.97 kB │ gzip: 1.84 kB
@vben-core/popup-ui:build: WARN `deps.skipNodeModulesBundle` is deprecated. Use `deps.neverBundle: true` instead.
@vben-core/popup-ui:build:
@vben-core/menu-ui:build: dist\menu.mjs 1.23 kB │ gzip: 0.58 kB
@vben-core/popup-ui:build: Build start
@vben-core/popup-ui:build: dist\index.mjs 0.77 kB │ gzip: 0.28 kB
@vben-core/form-ui:build: dist\form-render\dependencies.mjs 6.52 kB │ gzip: 1.90 kB
@vben-core/menu-ui:build: dist\hooks\use-menu-context.mjs 1.07 kB │ gzip: 0.41 kB
@vben-core/popup-ui:build: dist\modal\modal.mjs 12.35 kB │ gzip: 3.47 kB
@vben-core/popup-ui:build: dist\drawer\drawer.mjs 11.71 kB │ gzip: 3.07 kB
@vben-core/form-ui:build: dist\vben-use-form.mjs 5.81 kB │ gzip: 1.88 kB
@vben-core/form-ui:build: dist\components\form-actions.mjs 5.43 kB │ gzip: 1.67 kB
@vben-core/menu-ui:build: dist\components\menu-badge-dot.mjs 0.94 kB │ gzip: 0.45 kB
@vben-core/menu-ui:build: dist\utils\index.mjs 0.90 kB │ gzip: 0.41 kB
@vben-core/form-ui:build: dist\form-value-transform.mjs 4.43 kB │ gzip: 1.35 kB
@vben-core/form-ui:build: dist\form-render\form.mjs 4.25 kB │ gzip: 1.59 kB
@vben-core/form-ui:build: dist\form-render\utils.mjs 3.45 kB │ gzip: 1.13 kB
@vben-core/menu-ui:build: dist\hooks\use-menu.mjs 0.88 kB │ gzip: 0.50 kB
@vben-core/popup-ui:build: dist\alert\alert2.mjs 7.76 kB │ gzip: 2.26 kB
@vben-core/popup-ui:build: dist\alert\AlertBuilder.mjs 4.04 kB │ gzip: 1.44 kB
@vben-core/popup-ui:build: dist\drawer\use-drawer.mjs 3.56 kB │ gzip: 1.34 kB
@vben-core/popup-ui:build: dist\modal\use-modal.mjs 3.53 kB │ gzip: 1.34 kB
@vben-core/menu-ui:build: dist\hooks\use-menu-scroll.mjs 0.79 kB │ gzip: 0.41 kB
@vben-core/menu-ui:build: dist\_virtual\_\plugin-vue\export-helper.mjs 0.25 kB │ gzip: 0.18 kB
@vben-core/menu-ui:build: dist\index.d.ts 0.67 kB │ gzip: 0.24 kB
@vben-core/form-ui:build: dist\use-form-context.mjs 2.33 kB │ gzip: 0.85 kB
@vben-core/form-ui:build: dist\field-name.mjs 2.32 kB │ gzip: 0.75 kB
@vben-core/form-ui:build: dist\form-render\expandable.mjs 2.09 kB │ gzip: 0.90 kB
@vben-core/form-ui:build: dist\config.mjs 1.97 kB │ gzip: 0.79 kB
@vben-core/form-ui:build: dist\form-render\form-label.mjs 1.79 kB │ gzip: 0.77 kB
@vben-core/form-ui:build: dist\form-runtime-field.mjs 1.57 kB │ gzip: 0.61 kB
@vben-core/form-ui:build: dist\form-render\helper.mjs 1.18 kB │ gzip: 0.56 kB
@vben-core/form-ui:build: dist\use-vben-form.mjs 0.97 kB │ gzip: 0.48 kB
@vben-core/form-ui:build: dist\form-render\context.mjs 0.65 kB │ gzip: 0.30 kB
@vben-core/form-ui:build: dist\form-codec.mjs 0.63 kB │ gzip: 0.29 kB
@vben-core/form-ui:build: dist\rule-registry.mjs 0.34 kB │ gzip: 0.22 kB
@vben-core/form-ui:build: dist\deprecation.mjs 0.33 kB │ gzip: 0.22 kB
@vben-core/form-ui:build: dist\index.d.ts 1.07 kB │ gzip: 0.35 kB
@vben-core/form-ui:build: dist\types.d.ts 19.56 kB │ gzip: 3.89 kB
@vben-core/form-ui:build: dist\form-api.d.ts 4.12 kB │ gzip: 1.10 kB
@vben-core/menu-ui:build: dist\types.d.ts 1.96 kB │ gzip: 0.60 kB
@vben-core/form-ui:build: dist\use-vben-form.d.ts 0.98 kB │ gzip: 0.32 kB
@vben-core/form-ui:build: dist\form-codec.d.ts 0.31 kB │ gzip: 0.19 kB
@vben-core/form-ui:build: dist\config.d.ts 0.30 kB │ gzip: 0.19 kB
@vben-core/menu-ui:build: dist\components\normal-menu\normal-menu.vue.d.ts 0.90 kB │ gzip: 0.42 kB
@vben-core/menu-ui:build: dist\menu.vue.d.ts 0.60 kB │ gzip: 0.32 kB
@vben-core/menu-ui:build: dist\components\menu-badge.vue.d.ts 0.57 kB │ gzip: 0.31 kB
@vben-core/menu-ui:build: dist\components\normal-menu\normal-menu.d.ts 0.30 kB │ gzip: 0.22 kB
@vben-core/menu-ui:build: dist\components\normal-menu\index.d.ts 0.15 kB │ gzip: 0.11 kB
@vben-core/popup-ui:build: dist\modal\use-modal-draggable.mjs 3.21 kB │ gzip: 1.00 kB
@vben-core/form-ui:build: dist\form-render\utils.d.ts 0.05 kB │ gzip: 0.06 kB
@vben-core/form-ui:build: 31 files, total: 125.08 kB
@vben-core/popup-ui:build: dist\modal\modal-api.mjs 3.07 kB │ gzip: 1.31 kB
@vben-core/popup-ui:build: dist\drawer\drawer-api.mjs 2.93 kB │ gzip: 1.26 kB
@vben-core/menu-ui:build: 25 files, total: 61.16 kB
@vben-core/menu-ui:build: [PLUGIN_TIMINGS] Your build spent 81% of 11.0s inside plugin hooks (8.9s).
@vben-core/menu-ui:build: Measured inside the callback, so queue time is excluded and time the callback itself awaited is not:
@vben-core/menu-ui:build: - rolldown-plugin-dts:generate load (51%, 5.6s, 7 calls)
@vben-core/popup-ui:build: dist\alert\alert.mjs 0.48 kB │ gzip: 0.29 kB
@vben-core/popup-ui:build: dist\index.d.ts 1.49 kB │ gzip: 0.45 kB
@vben-core/form-ui:build: [PLUGIN_TIMINGS] Your build spent 77% of 9.1s inside plugin hooks (7.0s).
@vben-core/form-ui:build: Measured inside the callback, so queue time is excluded and time the callback itself awaited is not:
@vben-core/popup-ui:build: dist\drawer\drawer.d.ts 2.11 kB │ gzip: 0.78 kB
@vben-core/popup-ui:build: dist\modal\modal.d.ts 2.08 kB │ gzip: 0.78 kB
@vben-core/popup-ui:build: dist\drawer\drawer.vue.d.ts 1.77 kB │ gzip: 0.63 kB
@vben-core/form-ui:build: - rolldown-plugin-dts:generate load (67%, 6.1s, 7 calls)
@vben-core/form-ui:build: Those rows are 67% of the build; the rest of the 77% is below.
@vben-core/form-ui:build: Not measurable — 2 hooks whose calls overlap, so elapsed time covers work other calls were doing. Profile with `node --cpu-prof`:
@vben-core/menu-ui:build: - @tsdown/css transform (26%, 2.9s, 2 calls)
@vben-core/menu-ui:build: Those rows are 77% of the build; the rest of the 81% is below.
@vben-core/popup-ui:build: dist\modal\modal.vue.d.ts 1.52 kB │ gzip: 0.56 kB
@vben-core/popup-ui:build: dist\alert\alert.d.ts 1.41 kB │ gzip: 0.60 kB
@vben-core/menu-ui:build: Not measurable — 3 hooks whose calls overlap, so elapsed time covers work other calls were doing. Profile with `node --cpu-prof`:
@vben-core/menu-ui:build: - tsdown:deps resolveId (131 calls)
@vben-core/form-ui:build: - tsdown:deps resolveId (142 calls)
@vben-core/form-ui:build: - rolldown-plugin-dts:resolver resolveId (56 calls)
@vben-core/form-ui:build: See https://rolldown.rs/reference/InputOptions.checks#plugintimings for more details.
@vben-core/popup-ui:build: dist\drawer\use-drawer.d.ts 1.30 kB │ gzip: 0.45 kB
@vben-core/popup-ui:build: dist\modal\use-modal.d.ts 1.26 kB │ gzip: 0.45 kB
@vben-core/menu-ui:build: - rolldown-plugin-dts:resolver resolveId (70 calls)
@vben-core/menu-ui:build: - rolldown-plugin-dts:fake-js transform (7 calls)
@vben-core/menu-ui:build: See https://rolldown.rs/reference/InputOptions.checks#plugintimings for more details.
@vben-core/menu-ui:build:
@vben-core/menu-ui:build: ✔ Build complete in 11805ms
@vben-core/form-ui:build:
@vben-core/form-ui:build: ✔ Build complete in 9865ms
@vben-core/popup-ui:build: dist\alert\alert.vue.d.ts 0.85 kB │ gzip: 0.39 kB
@vben-core/popup-ui:build: dist\alert\AlertBuilder.d.ts 0.82 kB │ gzip: 0.26 kB
@vben-core/popup-ui:build: dist\drawer\drawer-api.d.ts 0.72 kB │ gzip: 0.37 kB
@vben-core/popup-ui:build: dist\modal\modal-api.d.ts 0.71 kB │ gzip: 0.37 kB
@vben-core/popup-ui:build: dist\drawer\index.d.ts 0.52 kB │ gzip: 0.21 kB
@vben-core/popup-ui:build: dist\alert\index.d.ts 0.43 kB │ gzip: 0.21 kB
@vben-core/popup-ui:build: dist\modal\index.d.ts 0.41 kB │ gzip: 0.19 kB
@vben-core/popup-ui:build: 26 files, total: 70.82 kB
@vben-core/popup-ui:build: [PLUGIN_TIMINGS] Your build spent 77% of 9.4s inside plugin hooks (7.3s).
@vben-core/popup-ui:build: Measured inside the callback, so queue time is excluded and time the callback itself awaited is not:
@vben-core/popup-ui:build: - rolldown-plugin-dts:generate load (69%, 6.4s, 15 calls)
@vben-core/popup-ui:build: Those rows are 69% of the build; the rest of the 77% is below.
@vben-core/popup-ui:build: Not measurable — 3 hooks whose calls overlap, so elapsed time covers work other calls were doing. Profile with `node --cpu-prof`:
@vben-core/popup-ui:build: - tsdown:deps resolveId (175 calls)
@vben-core/popup-ui:build: - rolldown-plugin-dts:resolver resolveId (138 calls)
@vben-core/popup-ui:build: - rolldown-plugin-dts:fake-js transform (15 calls)
@vben-core/popup-ui:build: See https://rolldown.rs/reference/InputOptions.checks#plugintimings for more details.
@vben-core/popup-ui:build:
@vben-core/popup-ui:build: ✔ Build complete in 10129ms
@vben/web-tdesign:build: cache miss, executing cfc303c167fbf99a
@vben/web-tdesign:build: $ pnpm vite build --mode production
@vben/web-tdesign:build: vite v8.2.2 building client environment for production...
@vben/web-tdesign:build: transforming...
@vben/web-tdesign:build: ✓ 8739 modules transformed.
[ELIFECYCLE] Command failed with exit code 1073807364.

View File

@ -0,0 +1,3 @@
vite v8.2.2 building client environment for production...
transforming...
✓ 8741 modules transformed.

View File

@ -0,0 +1,18 @@
node:internal/modules/cjs/loader:1386
throw err;
^
Error: Cannot find module 'E:\xxcool\project\admin.xpcool.com\apps\web-tdesign\node_modules\vite\bin\vite.js'
at Function._resolveFilename (node:internal/modules/cjs/loader:1383:15)
at defaultResolveImpl (node:internal/modules/cjs/loader:1025:19)
at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1030:22)
at Function._load (node:internal/modules/cjs/loader:1192:37)
at TracingChannel.traceSync (node:diagnostics_channel:328:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:237:24)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:171:5)
at node:internal/main/run_main_module:36:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
Node.js v22.22.2

View File

@ -0,0 +1,208 @@
vite v8.2.2 building client environment for production...
transforming...
✓ 8741 modules transformed.
rendering chunks...
✨configuration file is build successfully!
dist/_app-config-5.7.0-11458dd6.js 0.21 kB
dist/index.html 3.25 kB
dist/css/css-Bnh6-_op.css 0.35 kB
dist/css/auth-zsf-kax4.css 0.38 kB
dist/css/login-Bw5Nl-gj.css 0.43 kB
dist/css/config-CYorFwo-.css 0.56 kB
dist/css/loading-DXYS4l2z.css 0.56 kB
dist/css/vue-router-CJxWTMt5.css 0.69 kB
dist/css/rate-DPrmcsdp.css 0.74 kB
dist/css/space-BTf7zpgV.css 1.04 kB
dist/css/divider-BhBfZsmf.css 1.24 kB
dist/css/theme-toggle-CJLHZmGO.css 1.63 kB
dist/css/loading-DIyAXrBL.css 1.82 kB
dist/css/tooltip-XNfnDlF1.css 1.88 kB
dist/css/plugin-WRVM7LVz.css 1.98 kB
dist/css/card-CdzC8Hhz.css 2.13 kB
dist/css/checkbox-DdOl-sUm.css 2.96 kB
dist/css/plugin-TA_P2Z6-.css 3.58 kB
dist/css/textarea-GsFtqlRP.css 3.67 kB
dist/css/switch-JodMVENz.css 5.87 kB
dist/css/tippy-DkTQMyWH.css 6.65 kB
dist/css/popup-DTktDmKM.css 6.99 kB
dist/css/select-oN1Qir3K.css 7.21 kB
dist/css/auto-complete-D1sneTt8.css 7.55 kB
dist/css/tree-select-Dn5C_k5f.css 8.22 kB
dist/css/dialog-DQeVbESg.css 9.64 kB
dist/css/radio-CZ6KUL9r.css 9.98 kB
dist/css/time-picker-yLPCOGeb.css 10.83 kB
dist/css/input-bVx6VvAu.css 11.48 kB
dist/css/input-number-3Ul8EXah.css 12.01 kB
dist/css/select-input-C-I4OeNa.css 13.02 kB
dist/css/date-picker-P6ld0kxZ.css 20.53 kB
dist/css/basic-CE2ii0IK.css 23.49 kB
dist/css/upload-DUMAXQVN.css 34.05 kB
dist/css/button-2YixIg9b.css 46.03 kB
dist/css/bootstrap-CTyX7mnj.css 382.49 kB
dist/js/isNil-DHihWhf5.js 0.04 kB
dist/js/isUndefined-BB8dIdo-.js 0.04 kB
dist/js/_plugin-vue_export-helper-BDNMzG2s.js 0.08 kB
dist/js/profile-B411QZNQ.js 0.15 kB
dist/js/profile-tkuLhW9J.js 0.15 kB
dist/js/rotate-cw-BVkFtT0X.js 0.18 kB
dist/js/button-DiFFbQ2R.js 0.20 kB
dist/js/coming-soon-Br6OjwVh.js 0.23 kB
dist/js/page-DM9HIydN.js 0.27 kB
dist/js/page-YH8FPpYF.js 0.28 kB
dist/js/src-DS89XIkw.js 0.28 kB
dist/js/demos-IDdDfRZw.js 0.29 kB
dist/js/core-AXsCQsuO.js 0.29 kB
dist/js/demos-B_usGqMJ.js 0.30 kB
dist/js/src-CSX_ANQ1.js 0.30 kB
dist/js/forbidden-B7o_kVKp.js 0.31 kB
dist/js/not-found-kDlWuUXW.js 0.31 kB
dist/js/window-CaFIYn4R.js 0.31 kB
dist/js/internal-error-DjQP0gjR.js 0.31 kB
dist/js/offline-AebH1ckO.js 0.31 kB
dist/js/vben-COUvq-i4.js 0.34 kB
dist/js/Card-DOWS1BZq.js 0.43 kB
dist/js/_flatRest-DelwiEHT.js 0.43 kB
dist/js/auth-title-DCLZf2Gr.js 0.48 kB
dist/js/extends-C_p2ba5S.js 0.52 kB
dist/js/merge-COhhz_ZM.js 0.54 kB
dist/js/en-DA5aUWwj.js 0.58 kB
dist/js/render-content-3dfOk9Gq.js 0.59 kB
dist/js/objectWithoutProperties-BjoYlK0I.js 0.69 kB
dist/js/defu-1oANYd5X.js 0.70 kB
dist/js/rolldown-runtime-hePW80VL.js 0.71 kB
dist/js/use-access-D5s5JElq.js 0.72 kB
dist/js/analytics-visits-C0FF4ZUM.js 0.75 kB
dist/js/fake-arrow-D4gVakn3.js 0.78 kB
dist/js/analytics-visits-sales-2AfiIhjQ.js 0.83 kB
dist/js/useApi-CROJJdhE-oP73ypFI.js 0.83 kB
dist/js/omit-VkWzmshD.js 0.84 kB
dist/js/icon-D7FyseSl.js 0.84 kB
dist/js/common-DWRZ7B_7.js 0.85 kB
dist/js/common-BE0LVHtH.js 0.88 kB
dist/js/Primitive-Bi_oIzTM.js 0.90 kB
dist/js/analytics-visits-data-C8cWJVxy.js 0.93 kB
dist/js/analytics-visits-source-Dq4ndLTT.js 0.99 kB
dist/js/system-Cccgp00o.js 1.11 kB
dist/js/analytics-trends-DayDuXdy.js 1.12 kB
dist/js/divider-gWupn3CW.js 1.19 kB
dist/js/preload-helper-DaercurD.js 1.22 kB
dist/js/_baseGet-psOMs6v6.js 1.24 kB
dist/js/objectSpread2-BmonrgTA.js 1.29 kB
dist/js/TabsTrigger-Cbb1Ggyy.js 1.29 kB
dist/js/analysis-chart-card-zj0WmwDc.js 1.42 kB
dist/js/loading-BopO3VAx.js 1.50 kB
dist/js/zh-cn-DTVg5rYV.js 1.52 kB
dist/js/Separator-CnsQ2I4X.js 1.68 kB
dist/js/notification-setting-CGyX13PL.js 1.69 kB
dist/js/page-CuTJnSJp.js 1.70 kB
dist/js/useLengthLimit-DYA0i_6f.js 1.72 kB
dist/js/TabsContent-D9rwXVyK.js 1.81 kB
dist/js/base-setting-C-5wVIre.js 1.82 kB
dist/js/locales-DDWQD6uZ.js 1.90 kB
dist/js/security-setting-D4MXyOfx.js 1.90 kB
dist/js/password-setting-DlkBkikB.js 1.97 kB
dist/js/tdesign-CCaKq6ex.js 2.28 kB
dist/js/chevron-left-D9f6IBEb.js 2.29 kB
dist/js/forget-password-DhzqKAvG.js 2.31 kB
dist/js/space-U-P2gHEQ.js 2.32 kB
dist/js/close-B6p90RbR.js 2.35 kB
dist/js/switch-Bw8edqww.js 2.45 kB
dist/js/plugin-lI04xzdY.js 2.51 kB
dist/js/login-log-DxJmXANM.js 2.63 kB
dist/js/dist-zStm9ma4.js 2.70 kB
dist/js/usePrimitiveElement-DbdKxJuk.js 2.70 kB
dist/js/code-login-esDkmWoY.js 2.80 kB
dist/js/profile-fon5CZox.js 2.80 kB
dist/js/css-C1U7FmF7.js 2.83 kB
dist/js/button-C5dlyehu.js 2.87 kB
dist/js/log-7LPrCYfi.js 2.90 kB
dist/js/use-preferences-3a0SgvuL.js 2.91 kB
dist/js/button-CGlpi3U4.js 3.03 kB
dist/js/tooltip-SZ_zKXx9.js 3.06 kB
dist/js/log-BhwpVxsh.js 3.07 kB
dist/js/FormLabel-B3Rw7Dpy.js 3.27 kB
dist/js/VisuallyHiddenInput-DxXut0vv.js 3.33 kB
dist/js/authentication-nB_1w7ei.js 3.40 kB
dist/js/fallback-DdqiypLh.js 3.40 kB
dist/js/dep-31b5bf34-C2mpQG7R.js 3.44 kB
dist/js/register-B1JDLJvQ.js 3.49 kB
dist/js/authentication-CgivL9aI.js 3.53 kB
dist/js/card-CmhSZIwn.js 3.65 kB
dist/js/isValueEqualOrExist-C8t1FYDf.js 3.67 kB
dist/js/Switch-VF6PSDKd.js 4.01 kB
dist/js/nprogress-CcparBbP.js 4.18 kB
dist/js/ui-NNY_r1AM.js 4.39 kB
dist/js/TabsList-CehyWhXw.js 4.49 kB
dist/js/ui-CCmUukCu.js 4.64 kB
dist/js/avatar-CJdR_eYi.js 4.68 kB
dist/js/role-rJfSej4X.js 4.76 kB
dist/js/analytics-GD6IJWtP.js 4.92 kB
dist/js/vue.runtime.esm-bundler-DXMo22CJ.js 4.95 kB
dist/js/rate-BRM0RJYS.js 5.02 kB
dist/jse/index-index-Dy_RGpwX.js 5.36 kB
dist/js/menu-Dnwxdqyo.js 5.45 kB
dist/js/admin-c6EezDwA.js 5.50 kB
dist/js/textarea-BZOpSCSI.js 5.65 kB
dist/js/checkbox-D4XHp3V9.js 6.02 kB
dist/js/user-D_vF9YAZ.js 6.34 kB
dist/js/dep-b9255e37-CHIrUjTC.js 6.65 kB
dist/js/info-circle-filled-CD3nmxHC.js 6.86 kB
dist/js/close-circle-filled-CBR7t4UC.js 6.89 kB
dist/js/icon-500-z_hKUj8N.js 7.10 kB
dist/js/dayjs.min-DCUUuXM3.js 7.18 kB
dist/js/preferences-C8rVqNJ_.js 7.71 kB
dist/js/preferences-Dy8TIlZp.js 7.73 kB
dist/js/checkbox-xN5LclLv.js 7.92 kB
dist/js/icon-offline-f1WNoXZl.js 8.11 kB
dist/js/about-Bez8xXKZ.js 8.35 kB
dist/js/plugin-CKlA5pBO.js 8.40 kB
dist/js/auto-complete-Bv25xbKh.js 8.63 kB
dist/js/radio-DmcQi0JP.js 9.02 kB
dist/js/loading-C39UILZv.js 9.34 kB
dist/js/icon-403-lLbU1N7U.js 9.41 kB
dist/js/RovingFocusItem-BHwEDopT.js 9.49 kB
dist/js/dist-BFYolwLo.js 9.64 kB
dist/js/workspace-C3f4bOd9.js 10.74 kB
dist/js/plugin-B0UudBX_.js 11.19 kB
dist/js/input-number-DVmtvxsz.js 12.34 kB
dist/js/dep-f5dd846b-BSrp-SVp.js 12.52 kB
dist/js/icon-coming-soon-Di5CuiXP.js 12.91 kB
dist/js/input-CC3plCht.js 14.57 kB
dist/js/dialog-Bs5cnrOC.js 14.64 kB
dist/js/src-Ck0WMEmA.js 20.05 kB
dist/js/dist-C1bRuMA6.js 23.29 kB
dist/js/runtime-dom.esm-bundler-CirRHyjC.js 24.25 kB
dist/js/icon-404-BI3hQ7ZR.js 24.36 kB
dist/js/qrcode-login-gNss6ahZ.js 25.54 kB
dist/js/cn-BpFrWzX2.js 27.30 kB
dist/js/use-vben-form-3WiOfLLj.js 28.40 kB
dist/js/preferences-CxMgL41j.js 28.99 kB
dist/js/index.esm-DUQ5US9x.js 29.07 kB
dist/js/select-CrRzUSZ9.js 29.08 kB
dist/js/popup-CCr7vzsq.js 30.98 kB
dist/js/motion-d62SeGv9.js 34.66 kB
dist/js/time-picker-CHyQtpEM.js 37.03 kB
dist/js/theme-toggle-Dt_pVCcr.js 37.92 kB
dist/js/sortable.complete.esm-DPqKnM38.js 45.70 kB
dist/js/select-input-DV86Yiic.js 45.82 kB
dist/js/login-CQ1CXek-.js 51.03 kB
dist/js/tippy-CEF-3drU.js 51.03 kB
dist/js/src-D6I_HejD.js 53.18 kB
dist/js/icon-button-DWKyNCtz.js 61.88 kB
dist/js/tree-select-BguFAeDA.js 65.79 kB
dist/js/vue-router-CA-OmVEm.js 75.06 kB
dist/js/dep-71da4303-LD9sHFsB.js 84.37 kB
dist/js/runtime-core.esm-bundler-DkysjgTd.js 85.22 kB
dist/js/date-picker-DyycubvW.js 112.26 kB
dist/js/auth-CA2qvr-B.js 119.77 kB
dist/js/upload-DPl_ywz6.js 122.44 kB
dist/js/src-BRtCRgNE.js 128.90 kB
dist/js/store-Dgw-LmdP.js 152.41 kB
dist/js/config-pz3PI_ad.js 240.22 kB
dist/js/basic-D50YF5Jt.js 328.46 kB
dist/js/bootstrap-BO4bz1Wn.js 590.68 kB
dist/js/use-echarts-DUbx-WyZ.js 662.74 kB
✓ built in 9.43s
ZIP file created: E:\xxcool\project\admin.xpcool.com\apps\web-tdesign\dist.zip (1333520 total bytes)
Folder has been zipped to: E:\xxcool\project\admin.xpcool.com\apps\web-tdesign\dist.zip

Binary file not shown.

View File

6072
.workbuddy/tmp/local.diff Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
[Vben Form] BREAKING CHANGE: Named field slot control bindings moved to `slotProps.componentProps`. Replace `v-bind="slotProps"` with `v-bind="slotProps.componentProps"`. See https://doc.vben.pro/components/common-ui/vben-form.html
VITE v8.2.2 ready in 6089 ms
➜ Local: http://localhost:5173/
➜ Network: http://10.10.2.45:5173/ WLAN
➜ Network: http://172.28.0.1:5173/ vEthernet (Default …
➜ Vben Admin Docs: https://doc.vben.pro
23:21:52 [vite] (client) hmr update /@fs/E:/xxcool/project/admin.xpcool.com/packages/@core/base/design/src/css/global.css
23:21:57 [vite] (client) hmr update /@fs/E:/xxcool/project/admin.xpcool.com/packages/@core/base/design/src/css/global.css

View File

@ -0,0 +1,291 @@
# 招聘考试信息聚合系统 · 总计划书(设计稿 v0.1
> 状态:**设计/规划阶段,暂不开发**。本文档用于锁定范围、对齐架构、暴露风险,并列出需你拍板的关键决策。
> 落点:作为 **service.xpcool.comGo 后端模块)** + **admin.xpcool.comVue 管理/可视化前端模块)** 的一个功能模块。
> 默认地区:**贵阳市**;架构需天然支持全省 9 个市州 + 省直,便于后续扩展。
---
## 0. 文档约定
- 术语:**发布主体**(谁发的,可能是机关/事业单位/国企/央企/私企)、**考试分类**(公务员/事业单位/国企/央企/私企/其他)、**公告**(一条招聘考试信息)。两者解耦,才能支撑你想要的"按企业 + 按分类"双重筛选。
- 时间基线2026-08-27。历史全量定义为"近 2 年"2024-08 起)。
- 所有域名/接口形态均来自 2026-08 真实联网核查,标注【已核验】;其余为规划假设,需 POC 验证。
---
## 1. 业务目标与成功标准
**你要做的事(复述对齐):**
1. 爬取贵州各地区**官方渠道**发布的招聘考试信息。
2. 默认聚焦贵阳,支持多分类筛选:公务员、事业单位、国企、央企、私企等。
3. 先做一次**近两年全量历史**回溯,再**每天增量**抓取最新。
4. 每天早上诉**Bark** 推送给你。
5. 在 admin 里做**可视化展示 + 数据分析**。
**成功标准(建议,可调整):**
- 贵阳 + 公务员/事业单位/国企/央企 四类,官方源覆盖率 ≥ 90%,公告从发布到入库延迟 < 24h
- 每日早上推送稳定到达(失败有兜底告警)。
- 去重准确率 ≥ 99%(同一公告多站转发不重复计)。
- admin 可对任意"地区 × 分类 × 时间"组合做筛选与趋势分析。
---
## 2. 数据源调研(贵州真实官方渠道)【已核验 2026-08】
### 2.1 省级统一门户
| 名称 | 域名 | 形态 | 覆盖分类 | 备注 |
|---|---|---|---|---|
| 贵州人事考试信息网 | `gzrsks.com.cn`【已核验】 | **SPAhash 路由)** | 公务员招录、事业单位招聘、资格考试、"三支一扶" | 全省最核心门户,但**是前端渲染,需找底层 JSON 接口或用 headless 渲染** |
| 贵州省公务员局 | `gzzzb.gov.cn`【已核验】 | 静态列表页 | 公务员(省/市/县/乡四级联考、遴选) | 公告 + 职位表,链接常回链到 gzrsks 专题页 |
| 贵州人力资源社会保障网 | `rst.guizhou.gov.cn` | 静态 | 省直事业单位、人才引进 | 省本级发布渠道 |
### 2.2 贵阳市(默认地区,已核验可抓)
| 名称 | 域名 | 栏目/路径 | 覆盖 |
|---|---|---|---|
| 贵阳市人力资源和社会保障局 | `rsj.guiyang.gov.cn`【已核验】 | `rszk` 人事招考 | 事业单位、教师、卫健、"三支一扶"、局属单位 |
| 贵阳市人民政府 | `guiyang.gov.cn`【已核验】 | 人事招考 / 招聘信息 | 转发市直单位招聘公告 |
### 2.3 其他地区9 市州 + 省直,需 POC 验证)
架构预留,首批不做。后续按"市州人社局官网 + 市政府门户人事招考栏目"模式复制:
**遵义、六盘水、安顺、毕节、铜仁、黔东南州、黔南州、黔西南州** + **省直**(已在 2.1 覆盖)。
> 注意:部分市州门户为静态、部分也是 SPA难度不一需逐个 POC。
### 2.4 国企 / 央企【已核验】
| 渠道 | 域名 / 地址 | 备注 |
|---|---|---|
| 贵州省国资委国资央企招聘平台 | `cujiuye.iguopin.com`【已核验】 | 243 家国企夏季招聘(茅台、旅投、磷化、乌江能源、盐业、路桥…),规模大 |
| 中国贵州茅台集团 | `moutaichina.com` / `moutai.com.cn`【已核验】 | 高层次人才/应届引才附件多xlsx/docx |
| 贵州电网 | 南网招聘系统 `zhaopin.csg.cn`【已核验】 | 公告常经 gov 站/聚合站转发,源头在系统内需登录 |
| 其他省属/在黔央企 | 各集团官网"人才招聘"栏目 | 名单见国资委平台,逐一登记 |
### 2.5 私企 / 其他 —— **明显的覆盖缺口,需你决策**
- 纯私企几乎**不在政府官网**发"招聘考试"。其信息散落在:① 企业自己官网"招聘/校园招聘"栏目;② 招聘聚合站智联、BOSS、猎聘、高校人才网等③ 微信公众号。
- 建议分期:首批**只做官方/半官方源**(公务员/事业/国企/央企),"私企"作为**二期**,来源改为"知名民营企业官网招聘页 + 1~2 个可信聚合站",并明确标注来源为非官方。
- 风险:聚合站有版权与反爬限制,且信息噪声大,需更强的清洗与去重。
### 2.6 数据源分级(决定技术难度)
- **A 类 静态列表页**goquery 直接解析(如 rsj.guiyang.gov.cn。最易。
- **B 类 SPA / JS 渲染**:需定位底层 API 或 headless 渲染(如 gzrsks.com.cn。**最难,是工期主要风险点。**
- **C 类 需登录/验证码**:如南网招聘系统、部分企业内网。首批排除,人工或后续对接。
- **D 类 附件型**:公告正文在 PDF/Word如茅台 xlsx 岗位表)。需附件解析抽取关键字段。
---
## 3. 整体技术架构
### 3.1 部署拓扑(复用现有底座)
- 复用腾讯云 `193.112.118.168`CentOS StreamSSH 22025账号 xxcool
- 复用 Docker + `xpcool-net` 网络 + 宿主机 Nginx。
- **后端模块**挂进现有 `service.xpcool.com:new` 容器(已有 `127.0.0.1:10100:10100`、env `GF_GCFG_ENV=prod` + `DB_DSN`(须带 `mysql:` 前缀) + `JWT_SECRET`,且容器内必须有 `manifest/config/config.yaml`)。
- **前端模块**挂进 `admin.xpcool.com`Nginx 落点 `/data/www/admin.xpcool.com/`
- **Bark**:建议与现有服务同机或独立容器部署(见 §6
### 3.2 模块划分
```
[数据源网站]
│ (HTTP / API / headless)
[Crawler 爬虫引擎] ── 调度器(cron, 每日凌晨) ──┐
│ 去重/字段抽取/附件解析 │
▼ │
[MySQL 存储] ◀── 读写 ── [service 后端 API 模块 /recruitment/*]
│ │
│ [admin 前端模块]
│ │
[Bark 推送器] ◀── 每日早报任务 ────────────────┘
```
### 3.3 技术选型(对齐现有底座)
- 后端:**Go + com.lib.gf.v2 + com.lib.v2**(与 service 同源,复用 ORM/配置/日志/JWT。新增 `recruitment` 模块包。
- 前端:**Vue + TDesign**admin 现有约定,写组件前先走 TDesign MCP 查官方文档)。
- 存储:**MySQL**(复用 service 库,或独立 `recruitment` 库——见决策点)。
- 调度Go 内置 cron如 gocron常驻于 service 进程;或系统 crontab 调内部 API二选一
- 动态渲染:**Playwright**Python/Node sidecar 或 CLI仅 B 类 SPA 按需调用,避免全量上浏览器。
---
## 4. 数据模型设计(草案)
> 发布主体与考试分类解耦,支撑"按企业 + 按分类"双重筛选。
**recruitment_info公告主表**
| 字段 | 类型 | 说明 |
|---|---|---|
| id | bigint PK | |
| title | varchar | 标题 |
| source_id | bigint FK | 数据源(crawl_source) |
| org_id | bigint FK | 发布主体(organization) |
| category | tinyint | 考试分类(1公务员/2事业单位/3国企/4央企/5私企/6其他) |
| region | varchar | 地区(贵阳/省直/遵义…),支持多级 |
| publish_date | date | 发布日期 |
| deadline | date NULL | 报名/截止日期(抽取) |
| exam_date | date NULL | 笔试日期(抽取) |
| url | varchar | 原文链接(唯一性依据之一) |
| content | longtext | 正文/摘要 |
| attachments | json NULL | 附件链接与解析结果 |
| status | tinyint | 0有效/1已更正/2已失效/3已删除 |
| fingerprint | varchar | 去重指纹 |
| created_at / updated_at | datetime | |
**organization发布主体**id, name, type(机关/事业/国企/央企/私企/其他), official_site, region。
**crawl_source数据源配置**id, name, base_url, type(A/B/C/D), list_selector/api_path, cron_expr, enabled, last_success_at, fail_count。
**crawl_log抓取日志**id, source_id, run_at, fetched, new, updated, error。
**push_subscription推送订阅**id, device_key(Bark), regions(json), categories(json), only_new(bool), push_time。
**push_log推送记录**id, subscription_id, push_at, title, body, result。
索引url(唯一)、fingerprint(唯一)、(region, category, publish_date) 复合索引支撑筛选与趋势。
---
## 5. 爬虫设计
### 5.1 抓取策略
- **全量历史(首跑)**:对每个 A/B/C 类源,按列表分页从当前回溯到 2024-08D 类附件一并下载解析。
- **增量(每日)**:每日凌晨对全部 enabled 源巡检列表前 N 页(覆盖当天新发),入库新公告 / 更新已存在公告的 status官网更正/取消时标记而非硬删)。
### 5.2 解析方式(按源分级)
- A 类goquery CSS 选择器解析列表 + 详情。
- B 类 SPA先抓 XHR/JSON浏览器 DevTools 看接口);拿不到再走 Playwright 渲染后抽取。
- D 类:下载 PDF/Word → 文本抽取 → 正则提"报名/笔试/截止"日期与岗位数。
### 5.3 去重与更新
- 指纹 = `hash(source_id + normalize(title) + publish_date + url)`;同公告多站转发视为多条**不同来源记录**但关联同一 `group_key`(如 `hash(title+publish_date)`),前端可按 group 聚合展示"多家来源"。
- 更新检测:再次抓取时比对 content 哈希,变化则更新 + 记 crawl_log。
### 5.4 反爬与稳定性
- 统一限速(每源间隔 ≥ 2~5s、随机 UA、超时重试指数退避、失败计数。
- 连续失败 ≥ 阈值:标记源异常 + **Bark/邮件告警**(避免静默失效)。
- 代理池可选IP 被封时启用)。
### 5.5 字段抽取难点
- 截止/笔试日期、招聘人数、学历要求:正文正则 + 模板兜底;首批对样本做人工校验,调置信度。
- 地区推断:优先取源所属地区,正文含"贵阳/遵义…"可校正。
### 5.6 调度
- 每日 02:0005:00 增量巡检(错峰、规避官网高峰)。
- 首跑全量可手动触发 + 分批(按源、按月份)防止单次过长。
---
## 6. Bark 每日推送设计
### 6.1 自建 vs 公共(决策点)
- **公共 `api.day.app`**零部署POST `https://api.day.app/push` `{device_key,title,body,group,url}` 即可。代价:通知文本经第三方。**推荐先走公共版跑通,再决定是否自建。**
- **自建 `finab/bark-server`Docker**:隐私可控,但**必须配置 APNs 证书p8+KeyID+TeamID才能真正推到 iPhone**,且需域名+HTTPS。运维成本更高。
- 你的腾讯云同机部署可行(另开端口或子域名 + Caddy 自动证书)。
### 6.2 每日早报模板(建议)
```
【贵州招聘早报 · 2026-08-27 · 贵阳】
昨日新增:公务员 0 · 事业单位 3 · 国企 1 · 央企 0 · 私企 0
🔥 重点关注:
· 贵阳贵安2026事业单位面试公告截止 08-30
· 贵州电网春招补录(截止 09-05
👉 点击查看详情https://admin.xpcool.com/recruitment
```
- 用 `group=recruit_daily` 分组;`level=active``url` 深链到 admin 对应筛选页。
### 6.3 订阅过滤
- 按 `push_subscription`:可配置"仅贵阳""仅公务员+事业单位""仅推送新公告"。
- 多设备/多人可扩展(家人/同事各一 key
### 6.4 时机与兜底
- 默认 **每天早上 08:00** 推送(可配置)。
- 推送失败:记录 push_log + 重试 1 次 + 仍失败则 Bark 告警自身(用另一个 key/渠道)。
---
## 7. 可视化与数据分析admin 模块)
- **仪表盘**:总公告数、近 30 天新增、按分类占比环图、按地区柱状、今日/昨日新增卡片。
- **列表 + 筛选**:地区(多级)、分类(多选)、发布时间范围、关键词(标题/正文/单位全文检索)、状态(有效/已失效);表格 + 详情抽屉(原文链接、附件、多来源聚合)。
- **趋势分析**:按月/按地区/按分类的时间序列折线;支持导出 Excel/CSV。
- **爬虫运维面板**:各源最后成功时间、失败次数、今日抓取量、手动触发按钮、日志查看。
- **权限**:复用 admin 现有 JWT + `admin_menu`(type=2) 路由注册path 须与实际前端路由匹配,历史踩坑点)。
---
## 8. 你没想到 / 容易踩的坑(重点补充)
**法律与合规**
1. **robots.txt 与版权**:政府官网通常允许转载但需注明来源;逐站评估使用条款,正文展示标注"来源XXX"并链回原文。
2. **个人隐私边界**:只聚合"公告本身"**绝不抓取报名系统表单/考生个人信息**。
3. **数据使用边界**:仅作个人/内部信息聚合展示,不篡改、不商业化转售。
**反爬与可用性(最大的技术风险)**
4. **SPA 抓不到正文**gzrsks.com.cn 是 hash 路由 SPA纯 HTTP 拿不到内容——必须先做接口逆向或上 Playwright**这是首跑 POC 的第一关**。
5. **IP 被封 / 频率限制**:需限速、随机 UA、代理池、退避重试。
6. **网站改版**:模板一变解析器即失效,需"解析失败即告警"而非静默。
7. **登录/验证码源**:南网招聘系统等首批排除,避免卡住整体进度。
**数据质量**
8. **去重准确性**:同公告多站转发 ≠ 重复;用 group_key 聚合、用 fingerprint 防真重复。
9. **公告变更/撤回**:官网更正或取消招聘,应标记 `status`(已更正/已失效),**不要硬删**,否则趋势断裂。
10. **日期/人数抽取易错**:正文格式多样,首批必须人工抽检样本校准正则。
11. **附件解析**PDF/Word 岗位表里的关键信息(特别是茅台类)需单独抽取管线。
**覆盖与完整性**
12. **历史全量能否拿到**部分官网旧公告会被归档或删除近两年回溯可能不完整POC 阶段就要验证"能回溯到多久"。
13. **增量漏抓补偿**:某天爬虫失败,次日需补抓(而非只抓"今天"),设计成"按发布日期窗口回扫"。
14. **新源发现机制**:新出现的发布渠道如何纳入——建"候选源登记 + 人工审核"流程,而非自动信任。
15. **私企覆盖缺口**:无官方源,需明确二期方案与来源可信度标注(见 §2.5)。
**运维与告警**
16. **爬虫失败必须告警**:某源连续失败 N 次 → Bark/邮件通知,否则你以为在跑其实已挂。
17. **推送本身要可观测**push_log + 失败重试 + 独立告警通道。
**产品与体验**
18. **搜索是刚需**:标题/正文/单位全文检索,否则数据多了找不到。
19. **收藏/关注**:可标记"关注的单位/分类",推送可只推关注的。
20. **数据导出**Excel/CSV 供你自己分析。
21. **移动端查看**admin 是否要移动适配(你主要手机看推送,但详情可能在 admin
**集成与部署**
22. **与现有 service/admin 权限体系对接**:复用 JWT、`admin_menu` 路由type=2 path 匹配历史坑)、`xpcool-net` 网络、envDB_DSN 带 `mysql:` 前缀、JWT_SECRET
23. **爬虫常驻 vs 独立容器**:放进 service 进程省运维面,但 SPA 渲染要 Playwright sidecar——资源与隔离如何权衡见决策点
24. **配置外置**爬虫源、Bark key、推送时间、地区默认走配置/环境变量,不写死代码。
**技术决策点(待你拍板)**
25. 爬虫语言/形态:**纯 Go 适配器** vs **Python 爬虫微服务**写同一库Go 同源易部署但 SPA/Playwright 生态弱Python 爬虫生态成熟但多一个服务。
26. 存储:**复用 service 库** vs **独立 recruitment 库**?独立库隔离风险、便于单独备份与扩容。
---
## 9. 分阶段实施计划(开发期,本节为后续开发用)
- **阶段 0 · 数据源 POC约 1 周)**:对贵阳 4 类 + gzrsks SPA 做可行性验证,拿到真实接口/选择器,确认近两年可回溯性。**POC 不过则方案需调整。**
- **阶段 1 · 数据模型 + 贵阳 MVP公务员/事业单位)**建表、Go 爬虫适配器A 类优先)、基础列表 API、admin 列表页。
- **阶段 2 · 全量历史回溯**:跑近两年全量,去重与字段校准,人工抽检。
- **阶段 3 · 增量 + Bark 每日推送**:调度器 + 推送器 + 订阅过滤 + 失败告警。
- **阶段 4 · admin 可视化与分析**:仪表盘、趋势图、筛选增强、爬虫运维面板、权限接入。
- **阶段 5 · 扩展**:国企/央企源、私企二期、全省 9 市州、搜索/收藏/导出。
每阶段结束有"冒烟验证 + 数据抽检报告",再进下一阶段(契合你一贯的"非侵入、最小改动、迭代"偏好)。
---
## 10. 需你拍板的关键问题Decision Points
1. **私企范围**:首批只做官方/半官方(公务员/事业/国企/央企),私企放二期——可以吗?
2. **Bark**:先公共 `api.day.app` 跑通,还是直接自建?(需你提供 APNs 证书或授权我部署)
3. **爬虫形态**:纯 Go 适配器(推荐,运维面小)还是 Python 微服务SPA 处理强)?
4. **存储**:复用 service 库 还是 独立 recruitment 库?
5. **默认推送时间**:每天早上几点?(建议 08:00
6. **是否要移动端适配 admin**:还是推送里给深链、电脑看详情即可?
7. **推送粒度**:每日汇总早报,还是"有新公告实时推"?(建议每日汇总,避免打扰)
---
## 11. 附录:接口草图(仅供讨论)
```
GET /api/service/admin/recruitment/list?region=贵阳&category=2&from=2026-08-01&q=教师
GET /api/service/admin/recruitment/stats?range=30d
GET /api/service/admin/recruitment/sources # 爬虫源状态
POST /api/service/admin/recruitment/crawl/trigger # 手动触发
POST /api/service/admin/recruitment/push/test # 测试 Bark
```
---
*本文档为设计稿,待你确认决策点后进入阶段 0 POC。*