# 一个HR

光锥之内皆命运

- Site: https://blog.guohao.asia/

## 从 0 到 1 搭一套 HR 体系：我的推进顺序与判断标准

- Link: https://blog.guohao.asia/hr-system-from-zero-to-one.html
- Published: 2026-10-14T11:36:20+08:00
- Author: null

> **关键词：** HR 体系搭建 / 招聘基线 / 制度落地 / 合规排期 / 组织诊断 / 推进顺序

---

## 一、入职第一个月，我没有先写制度

接手一家区域型企业的 HR 体系，最容易的起点是 ” 先拉一份制度清单，逐项补齐 ”。这个
起点的诱惑很大，因为它看起来最有产出——制度文件是能拿给领导看到的东西。

但我更愿意把第一个月花在另一件事上：**摸清约束。**因为制度写得对不对，不取决于它
完不完整，而取决于它 ** 能不能在这个组织里跑起来**。而 ” 能不能跑起来 ”，取决于三
件事：

 * **谁在执行。**一线管理者的执行能力和时间余量，决定了制度能有多复杂；
 * **组织的真实痛点在哪。**不是我以为的痛点，是大家每天真正卡住的地方；
 * **有没有历史包袱。**既有做法、口头约定、惯例，往往比制度更有约束力。

这三件事搞不清楚，写出来的制度通常只有两种结局：要么挂在墙上，要么给一线添麻烦。**
先摸约束、再定动作**，是后面所有工作的前提。

---

## 二、招聘：先建立基线，再谈渠道

招聘是最容易被 ” 感觉 ” 支配的模块。招不到人，第一反应通常是 ” 渠道不行 ” 或者 ”
我们给的太少 ”。但在换渠道、调薪资之前，我会先把两件事记下来，**做成日常台账**：

 * **触达量**：主动打招呼 / 浏览简历的份数；
 * **响应率**：对方回应并被推进到的比例。

之所以要同时看这两个数，是因为它们指向完全不同的病因：

  |  现象 |  真正的问题 |  该动的动作 |  
   |  触达量下降，响应率 ** 同步下降** |  话术、岗位吸引力或薪资竞争力出问题 |  改文案、调岗位卖点、校准薪酬 |  
 |  触达量下降，响应率 ** 没有下降** |  **这个渠道的简历池已经接近饱和** |  不是加大投入，而是 ** 开辟新渠道** |  
 |  触达量稳定，响应率低 |  匹配度问题——找的人不对 |  重画人才画像、改筛选条件 |

> 第二行是这份台账最值钱的地方：**它把 ” 我不够努力 ” 和 ” 这个池子已经掏空了 ” 
> 区分开了。**没有基线，这两种情况在体感上一模一样——都表现为 ” 越来越难招 ”。

建立基线之后，渠道策略才能从 ” 哪个平台都发一发 ” 变成 ** 分岗分工 **：把中高端岗位
放在以主动寻访为主的平台，把基层服务岗放在内容社区（这里的投递更看人、看完还会直接
私信，转化路径短），再把其余平台作为补充。** 不同岗位用不同渠道，比所有岗位用同一个
渠道有效得多。**

另外留一个自动触发规则，避免自己骗自己：**任一渠道连续两个月触达量明显下滑、而响应
率没有同步下滑，就判定为池子饱和，当月必须启动新渠道试投。**把判断写成规则，就不必
每个月靠心情决定。

---

## 三、制度：先跑通一个最小闭环，再追求完整

制度最容易走偏的地方是——**追求 ” 体系完整 ”**。一份覆盖所有情况的制度，写得越全，
一线越用不起来；用不起来，制度就等于不存在。

我的做法是 ** 先做一个最小的、能闭环的版本**。判断它是否闭环，看三件事：

  **有落地的载体**：附件、表单、审批流——制度要靠工具落地，不能靠记忆；
  **有边界的例外**：至少说清最常见的两种特殊情况怎么处理。
  用一个具体的例子说明 ” 最小闭环 ” 和 ” 完整体系 ” 的区别：试用期管理。**很多企业
  的试用期制度写得很正式，但缺了两样东西——可执行的考核标准和留痕的评估记录**。结果
  是：真到了要解除的时候，手上没有任何能支撑决定的材料。
  所以我把重心放在 ** 把考核表和评估表跑通 ** 上，而不是把制度条款写长：月度考核
  有表、评估有结论、结论有人签字、签完归档。这三步一跑通，试用期管理才算真的成立。**
  制度的价值不在文本里，在痕迹里。**
  ---
  
  ## 四、合规：不是一次改完，而是按优先级排期
  
  接手一个没有专职法务的组织，几乎必然会在第一周就发现一批历史遗留的合规问题。这时
  最危险的动作是 ** 一次性全部提出来**——那会让所有人陷入恐慌，也会让你自己变成一个”
  只会提问题的人 ”。
  我的做法是 ** 先列清单，再排序，然后按排期推进**。排序用两个轴：
    |  轴 |  含义 |  
     |  **暴露概率** |  这件事被员工主张、被稽核或被检查撞上
  的可能性 |  
   |  **后果量级** |  一旦暴露，是补办手续、赔偿，还是直接影响资质 
  |
  高概率 × 高后果的，当月就动；低概率 × 低后果的，放进排期表慢慢补。**关键是让领导
  看到一张有顺序的清单，而不是一堆并列的问题**——前者是方案，后者是压力。
  同时要接受一个现实：**有些问题不能靠 HR 一个部门解决 **。涉及跨部门口径、涉及成本
  决策、涉及外部主管部门的，HR 的职责是** 把事实和风险说清楚、给出可选项，然后推动
  决策**，而不是自己扛下来。
  > 合规工作的产出不是 ” 没有问题 ”，而是 ”**问题被看见了、被排序了、有人在推**“。
  ---
  
  ## 五、组织诊断：先看职责边界，再看编制
  
  一谈到效率问题，最常见的诉求是 ” 人不够，加编制 ”。但编制是成本，不是解法。我习惯
  先问三个问题，顺序不能颠倒：
   * **哪些动作是重复的？**同一件事被两个岗位各做一遍，是最隐蔽的浪费；
   * **哪些职责是没有人认领的？**看起来 ” 大家都管 ” 的事，通常等于没人管；
   * **哪些岗位的边界本身是模糊的？**边界不清的岗位，最容易被临时抽调，也最容易出
     问题。
  这三个问题问完，往往能发现 ** 真正要解决的是职责边界，而不是人数**。只有当职责
  边界清楚之后，” 编制够不够 ” 才是一个有意义的问题——否则加了人，只是把模糊的边界
  变厚。
  把边界画清楚还有一层附带价值：**它让授权变得安全 **。当每个人都清楚自己该做什么、
  不该做什么，管理者才敢真正把权限下放给一线；一线也才敢在自己范围内独立决策。**
  没有边界，就没有授权；没有授权，所有事都会回到负责人桌上。**
  ---
  
  ## 六、一把尺子：我的五步推进法
  
  把上面的做法收拢，其实就是一把固定的尺子。每接手一个新模块，都按同一个顺序走：
    |  步骤 |  动作 |  产出 |  
     |  1 摸约束 |  谁执行、痛点在哪、有什么历史包袱
  |  一份约束清单 |  
   |  2 建基线 |  把现状量化成可对比的台账 |  一本台账，能区分”
  努力不够 ” 和 ” 池子见底 ” |  
   |  3 做最小闭环 |  不求完整，先求 ” 有人用、有
  痕迹、能复盘 ” |  一个跑得起来的动作 |  
   |  4 排序推进 |  按暴露概率 × 后果量
  级排期 |  一张有顺序的清单 |  
   |  5 迭代 |  用台账回头看，调整下一步 |  一个个
  版本，而不是一次到位 |
  这套顺序有一个共同点：**每一步都在减少不确定性，而不是增加工作量。**先看清，再
  动手，最后才是写文档。
  ---
  
  ## 七、一点反思
  
  **一、不要用 ” 我做了多少件事 ” 来证明价值。**刚接手的阶段，最容易陷入 ” 清单越
  拉越长 ” 的忙碌感。但真正被认可的不是条目数量，而是 ** 有没有解决具体问题**。半年
  后回头看，能被记住的往往只有两三件。
  **二、把机制讲清楚，比讲 ” 谁卡住了 ” 更有用。**跨部门协作里，指责某个环节不给
  力是最省力也最没用的表达。有效的方式是 ** 说清机制上缺什么**——缺流程、缺授权、
  缺责任人，而不是缺态度。
  **三、诚实和自贬是两件事。**可以说清还没做完什么，但一定要同时给出计划和时间。
  读者想看到的是 ” 我知道哪里还缺、什么时候补上 ”，而不是 ” 我做得不好 ”。
  HR 的工作大多是慢变量：制度、文化、组织能力，都不会在一个季度内看到结果。也正因为
  如此，**把判断写下来、把过程留成痕迹，比追求短期成果更重要**——这样在很久之后回头
  看时，至少能说清楚：当时为什么这么做。
   * **有明确的动作**：不看制度的人也能一句话说清要做什么；
   * **有落地的载体**：附件、表单、审批流——制度要靠工具落地，不能靠记忆；
   * **有边界的例外**：至少说清最常见的两种特殊情况怎么处理。
  用一个具体的例子说明 ” 最小闭环 ” 和 ” 完整体系 ” 的区别：试用期管理。**很多企业
  的试用期制度写得很正式，但缺了两样东西——可执行的考核标准和留痕的评估记录**。结果
  是：真到了要解除的时候，手上没有任何能支撑决定的材料。
  所以我把重心放在 ** 把考核表和评估表跑通 ** 上，而不是把制度条款写长：月度考核
  有表、评估有结论、结论有人签字、签完归档。这三步一跑通，试用期管理才算真的成立。**
  制度的价值不在文本里，在痕迹里。**
  ---
  
  ## 四、合规：不是一次改完，而是按优先级排期
  
  接手一个没有专职法务的组织，几乎必然会在第一周就发现一批历史遗留的合规问题。这时
  最危险的动作是 ** 一次性全部提出来**——那会让所有人陷入恐慌，也会让你自己变成一个”
  只会提问题的人 ”。
  我的做法是 ** 先列清单，再排序，然后按排期推进**。排序用两个轴：
    |  轴 |  含义 |  
     |  **暴露概率** |  这件事被员工主张、被稽核或被检查撞上
  的可能性 |  
   |  **后果量级** |  一旦暴露，是补办手续、赔偿，还是直接影响资质 
  |
  高概率 × 高后果的，当月就动；低概率 × 低后果的，放进排期表慢慢补。**关键是让领导
  看到一张有顺序的清单，而不是一堆并列的问题**——前者是方案，后者是压力。
  同时要接受一个现实：**有些问题不能靠 HR 一个部门解决 **。涉及跨部门口径、涉及成本
  决策、涉及外部主管部门的，HR 的职责是** 把事实和风险说清楚、给出可选项，然后推动
  决策**，而不是自己扛下来。
  > 合规工作的产出不是 ” 没有问题 ”，而是 ”**问题被看见了、被排序了、有人在推**“。
  ---
  
  ## 五、组织诊断：先看职责边界，再看编制
  
  一谈到效率问题，最常见的诉求是 ” 人不够，加编制 ”。但编制是成本，不是解法。我习惯
  先问三个问题，顺序不能颠倒：
   * **哪些动作是重复的？**同一件事被两个岗位各做一遍，是最隐蔽的浪费；
   * **哪些职责是没有人认领的？**看起来 ” 大家都管 ” 的事，通常等于没人管；
   * **哪些岗位的边界本身是模糊的？**边界不清的岗位，最容易被临时抽调，也最容易出
     问题。
  这三个问题问完，往往能发现 ** 真正要解决的是职责边界，而不是人数**。只有当职责
  边界清楚之后，” 编制够不够 ” 才是一个有意义的问题——否则加了人，只是把模糊的边界
  变厚。
  把边界画清楚还有一层附带价值：**它让授权变得安全 **。当每个人都清楚自己该做什么、
  不该做什么，管理者才敢真正把权限下放给一线；一线也才敢在自己范围内独立决策。**
  没有边界，就没有授权；没有授权，所有事都会回到负责人桌上。**
  ---
  
  ## 六、一把尺子：我的五步推进法
  
  把上面的做法收拢，其实就是一把固定的尺子。每接手一个新模块，都按同一个顺序走：
    |  步骤 |  动作 |  产出 |  
     |  1 摸约束 |  谁执行、痛点在哪、有什么历史包袱
  |  一份约束清单 |  
   |  2 建基线 |  把现状量化成可对比的台账 |  一本台账，能区分”
  努力不够 ” 和 ” 池子见底 ” |  
   |  3 做最小闭环 |  不求完整，先求 ” 有人用、有
  痕迹、能复盘 ” |  一个跑得起来的动作 |  
   |  4 排序推进 |  按暴露概率 × 后果量
  级排期 |  一张有顺序的清单 |  
   |  5 迭代 |  用台账回头看，调整下一步 |  一个个
  版本，而不是一次到位 |
  这套顺序有一个共同点：**每一步都在减少不确定性，而不是增加工作量。**先看清，再
  动手，最后才是写文档。
  ---
  
  ## 七、一点反思
  
  **一、不要用 ” 我做了多少件事 ” 来证明价值。**刚接手的阶段，最容易陷入 ” 清单越
  拉越长 ” 的忙碌感。但真正被认可的不是条目数量，而是 ** 有没有解决具体问题**。半年
  后回头看，能被记住的往往只有两三件。
  **二、把机制讲清楚，比讲 ” 谁卡住了 ” 更有用。**跨部门协作里，指责某个环节不给
  力是最省力也最没用的表达。有效的方式是 ** 说清机制上缺什么**——缺流程、缺授权、
  缺责任人，而不是缺态度。
  **三、诚实和自贬是两件事。**可以说清还没做完什么，但一定要同时给出计划和时间。
  读者想看到的是 ” 我知道哪里还缺、什么时候补上 ”，而不是 ” 我做得不好 ”。
  HR 的工作大多是慢变量：制度、文化、组织能力，都不会在一个季度内看到结果。也正因为
  如此，**把判断写下来、把过程留成痕迹，比追求短期成果更重要**——这样在很久之后回头
  看时，至少能说清楚：当时为什么这么做。

## 零 License 成本，落地一套会员预约与核销系统：一份完整的项目复盘

- Link: https://blog.guohao.asia/membership-booking-system-retrospective.html
- Published: 2026-10-14T11:36:19+08:00
- Author: null

> **关键词：** 开源二开 / Easy!Appointments / 会员预约与核销 / 积分账务 / 企业微
> 信免登 / 零 License 成本 / 抗升级运维

---

## 一、缘起：一个被低估的 ” 小事 ”

事情的起点是一张需求清单，上面只有四条：

 * 会员能在手机上选服务内容、指定教练或美容师；
 * 提交后不直接生效，需要后台人工确认；
 * 到店接受服务后，后台人工核验；
 * 能看数据统计。

看起来很轻。但在真实约束下它并不轻——**约束有三条，而且互相打架**：

 * **没有软件采购预算。**这是一家区域型房地产企业的自有会所，不是独立的商业健身品牌，
   撑不起一套会员 SaaS 的年费，也养不起一支开发团队。
 * **系统得活得久。**上线只是开始，后面还有人要改、要升级。如果做完就锁死，等于给
   自己埋雷。
 * **做这件事的人是我，一个 HR。**没有开发团队，没有测试，没有专职运维。

这三条约束，基本决定了后面所有的技术选择。所以这份复盘真正想讲的不是 ” 我写了多少
代码 ”，而是**“ 在约束之下，我做了哪几个判断 ”**。

---

## 二、第一个判断：买、自己写，还是用开源基座？

三条路，我逐条算过：

  |  路线 |  真实成本 |  致命问题 |  
   |  买商业 SaaS |  年费 + 按人数阶梯涨价 |  预算直接否掉；数据在别人手里，且定制要排队 |  
 |  完全自研 |  一个中型 Web 应用的工作量 |  排班冲突计算、团课容量、时区与假期规则，这些都要从头写一遍 |  
 |  **开源基座 + 二开** |  License 成本 **0**，工作量集中在业务逻辑 |  必须接受它的既有设计，并承担 ” 跟着上游升级 ” 的责任 |

我选了第三条，基座是 **Easy!Appointments 1.6.0**（GPL-3.0，自用无任何授权费用）。
理由是它把最费时、最容易写错的那部分已经做完了：**时段可用性计算、人员排班、冲突
拦截、多人容量**。

这里有一个让工作量骤降的发现：需求里的 ” 人工确认 ” 和 ” 到店核验 ”，**不需要开发
任何新模块 **。这套系统自 1.5 版起支持自定义预约状态，只要把 ” 待确认 ” 设为状态
列表的第一项，它就自动成为所有新预约的初始状态——** 一个配置项，同时实现了 ” 提交
不生效 ” 和 ” 到店核验 ” 两件事**。

> 原本估出来最大的一块开发量（核销台 + 扣次），最后压缩成了 ” 一个只读统计页 ”。

**这是整件事里最省钱的一个判断：先穷尽基座的原生能力，再决定要写什么。**很多 ” 必须
开发 ” 的需求，其实是没把工具摸透。

---

## 三、第二个判断：绝不 fork 核心

业务需求后来变重了：新增了 ” 登录后才能预约 ”” 次卡 ”” 积分余额 ”” 会员等级折扣 ”。
做到这一步，最省事的做法是 ** 直接改它的核心代码**——在原生预约流程里插一段校验，
半小时就能跑通。

我没这么做。因为 ** 改核心代码 = 放弃升级能力**：上游一发新版本，我的改动要么被覆盖（
功能消失），要么和新代码冲突（页面崩掉）。一套要再活三五年的系统，这是不能接受的
负债。

于是定了一条硬约束：**只在官方文件上做 ” 追加式 ” 改动，业务逻辑一律走新增文件 +
钩子（hook）。**最终结算下来，全部改动只落在 **13 处官方文件 ** 上，且每一处都是
最小化的追加。

代价是：不能直接在原生预约页里注入逻辑。补偿办法是把校验挪到外围——**让它先把预约
建出来，我在事件推送之后完成账务动作**，账务不通过就调用接口把预约取消掉并通知客户。

> 用 ” 牺牲一点实现上的顺手 ”，换 ” 永远能升级 ”。这个交换在长期账上是划算的。

---

## 四、第三个判断：积分到底在哪个时点扣？

这是整套系统里最容易出错的地方，也是我最花时间想的一处。三种方案：

  |  方案 |  做法 |  后果 |  
   |  A 预约时直接扣 |  提交即扣减 |  客户一取消就要退款，**退多了退少了都会错账** |  
 |  **B 预约时冻结、核销时扣减** |  先冻结额度，服务完成后正式扣 |  需要处理 ” 冻结未释放 ” 的兜底 |  
 |  C 核销时才扣 |  最省事 |  客户可以 ** 超额预约**——账上没这么多分，却约了一堆 |

选 B。**它是唯一能同时避免 ” 超额预约 ” 和 ” 频繁退款 ” 的做法**，也是电商预售和
酒店预授权的标准模式。

但选完 B 只是开始，真正要补的是一道保险：**事件推送会丢。**网络抖动、服务重启、配置
错误，都可能让 ” 预约创建了，但积分没冻结 ”——而这恰恰就是超额预约的入口。

所以必须配一个 ** 对账补偿任务**：定期扫描 ” 已创建但未冻结 ” 的预约，补做冻结，
补不上就取消并告警。

> 行业里会员账务系统的典型翻车点，从来不是 ” 主流程写错了 ”，而是 ”**只做了一次校
> 验，没设计补偿**“——隐患往往在系统上线后第三周集中爆发。

---

## 五、第四个判断：权限按 ” 岗位 ” 分层，而不是按 ” 人 ”

系统里有四类使用者，权限怎么分？最容易犯的错是 ” 谁需要就给谁开 ”——最后变成谁都能
改数据。我的分法是按 ** 岗位职责性质 ** 切三刀：

  |  层级 |  判定标准 |  包含功能 |  
   |  **管理类**（管理员） |  改的是 ** 规则**，影响所有人 |  等级与积分规则、企业微信绑定、后台设置、数据修正台 |  
 |  **运营类**（物业管家） |  改的是 ** 业务数据**，每日对客发生 |  会员开户、核销台、代客预约、数据统计 |  
 |  **执行岗**（服务人员） |  **只看自己**，不碰他人数据 |  仅自己的排班日历；上述运营类全部排除 |

这套分法其实不是技术判断，是 ** 岗位设计判断 **——** 它和设计一份岗位说明书用的是
同一套逻辑：先划职责边界，再谈授权范围。**想清楚 ” 这个动作改的是规则还是数据 ””
它影响一个人还是一群人 ”，权限表自然就出来了。

另外做了一件事：给管理员单独开了一个 ** 数据修正台**。因为再好的授权边界也挡不住
误操作——管家点错一个按钮，预约就进了不可逆的状态，系统里退不回来，原先只能去改数据
库。有了修正台，管理员能补齐误操作，而且每一次修正都留痕、必须填写理由。

> **权限设计的目的不是 ” 防着谁 ”，而是让每个人在自己的边界内可以放心操作。**边界
> 清楚之后，才敢把运营权限真正下放给一线。

---

## 六、落地规模

  |  维度 |  数量 |  
   |  新增控制器 |  7 个 / 2,102 行 |  
 |  新增类库（含计费引擎） |  2 个 / 546 行 |  
 |  新增钩子 |  2 个 / 127 行 |  
 |  新增页面 |  9 个 / 1,475 行 |  
 |  **新增代码合计** |  **约 4,400 行** |  
 |  新增数据表 |  8 张 |  
 |  改动的官方文件 |  **仅 13 处**，全部为追加式 |

另外整站做了 ** 中文锁定**：不只是隐藏语言切换入口，而是在底层把语言固定死（否则
通过地址栏参数或会话仍然能改），同时把邮件通知的语言也固定为中文——否则收到通知的
那个人的语言设置会决定邮件用什么语言发。

---

## 七、真正花时间的地方：让它扛得住升级

开发只占了大概一半时间。另一半全花在一件更少被讨论的事上：**二开系统的长期维护成本。**

症结在这里：二开改动，有一部分必然落在 ** 官方文件 ** 上。上游一发新版本、用覆盖
方式解压，这些改动就 ** 无声无息地消失 **——页面还是好的，功能却没了。其中最危险的
一处是登录拦截：它一旦丢失，任何人打开预约页都能直接下单，而** 界面上完全看不出异常**。

所以我没有靠 ” 升级后记得手动检查 ” 来兜底，而是把它做成了自动化：

 * **守护进程 ** 每 2 秒巡检一遍关键特征，发现任何一处不符，立刻触发恢复；
 * **恢复脚本 ** 是幂等的，把改动写成一份份 ** 声明式补丁**（不是按行号改写，而是
   用唯一上下文锚点定位），可反复执行、不产生重复；
 * 恢复完再复检一次，如果仍然异常就 ** 暂停轮询并告警**，避免每 2 秒空跑刷日志、
   把真问题淹没。

实测结果：把网站文件退回修改前的版本（模拟一次上游升级覆盖），**约 2–3 秒内自动恢复，
无需人工干预**。

过程中还踩到一个很隐蔽的坑，值得单独记一笔：恢复用的文件包里，有 ** 一个文件停留在
旧版本 **，和线上不一致。结果是——恢复脚本一执行，反而把这个文件 ” 打回旧版 ”，日志
里冒出一条莫名其妙的报错。这类漂移是** 无声的 **，只有在主动逐文件比对时才会暴露。
后来专门写了一个一致性检查脚本，并定下规矩：** 只要动过包内文件，必须重新打包并跑
一次比对。**

> **自动化真正的价值不在于 ” 省了几分钟 ”，而在于——它把一件容易被忘记的事，变成了
> 不需要被记住的事。**

---

## 八、结果与三点反思

系统已上线并投入使用，覆盖会员在线预约、后台人工确认、到店核销、会员开户、积分与
次卡账务、数据统计，以及员工侧的免密登录入口（从企业微信工作台直接进入、按角色落到
对应页面）。软件采购成本为 0。

### 反思一：先把工具摸透，再决定写什么

那份 ” 必须开发 ” 的清单，最后有一大半被原生能力接住了。**省下的不是钱，是本可以
避免的维护成本。**

### 反思二：约束不是障碍，是设计输入

“ 零预算 ”” 一个人 ”” 必须能升级 ”，这三条约束看起来都在限制方案，实际上它们 ** 
帮我把选项砍到了正确的那个**。如果没有约束，很可能会选一个看起来更强、但根本维护
不动的方案。

### 反思三：HR 的很多能力是可迁移的

回头看，这个项目里最难的部分——权限分层、误操作兜底的设计、把长期维护成本压到接近
零、以及在动手之前先把 ” 最容易翻车的环节 ” 找出来——**用的都不是编程能力，而是岗位
设计、风险预判和把复杂问题系统化的能力**。这大概是一个 HR 做这类项目时，真正拿得
出手的差异。

至于代码本身，它只是把判断落地的工具。工具可以学，判断需要积累——而这两件事，恰好
都是可以刻意练习的。

## 用腾讯IMA搭建智能简历筛选系统：一份Prompt操作手册带来的效率革命

- Link: https://blog.guohao.asia/%e7%94%a8%e8%85%be%e8%ae%afima%e6%90%ad%e5%bb%ba%e6%99%ba%e8%83%bd%e7%ae%80%e5%8e%86%e7%ad%9b%e9%80%89%e7%b3%bb%e7%bb%9f%ef%bc%9a%e4%b8%80%e4%bb%bdprompt%e6%93%8d%e4%bd%9c%e6%89%8b%e5%86%8c%e5%b8%a6.html
- Published: 2026-07-25T12:36:46+08:00
- Author: null

> **关键词：** 腾讯 IMA / AI 知识库 / 简历自动筛选 / Prompt 工程 / 招聘效率

---

## 一、为什么需要一套简历筛选系统？

作为招聘负责人或 HR，你是否也有这样的体验——

每天打开邮箱，几十份甚至上百份简历扑面而来。你一份份打开，一份份对照岗位 JD，在 ”
看起来还行 ” 和 ” 好像差点意思 ” 之间反复横跳。更麻烦的是，不同面试官对同一份简历
的看法可能完全不同，评估标准难以统一。

痛点总结起来无非四个字：**耗时、主观**。

一份简历从打开到形成初步判断，少说 15 分钟，如果岗位要求复杂，半小时打底。更别说
还要为面试官整理面试要点、准备追问问题——这些往往要再来一轮沟通。

直到我尝试了 ** 腾讯 IMA + 一份精心设计的 Prompt 操作手册**，情况才彻底改变。

---

## 二、腾讯 IMA 是什么？

**腾讯 IMA（Intelligent Management Assistant）** 是腾讯推出的智能知识管理平台。它
最核心的能力是：

> **将文档上传至知识库 → AI 基于知识库内容进行问答和分析**

这意味着，AI 不再依靠自己的 ” 通识 ” 来回答问题，而是 ** 严格基于你提供的资料 **
进行推理。这正是简历筛选场景需要的——AI 必须根据你上传的岗位需求文档来评估候选人，
而不是凭 ” 印象 ” 打分。

---

## 三、核心思路：把 Prompt 写成 ” 操作手册 ”

大多数人写 Prompt 的习惯是 ” 告诉 AI 你要什么 ”。但这种方式在面对复杂任务时，很容易
遗漏关键信息，输出格式也不稳定。

我的做法是：**把 Prompt 写成一份标准操作手册（SOP）**。

你可以把它理解成给新员工看的培训文档——里面写清楚了：

 * **你是谁**（AI 的角色定位）
 * **你要做什么**（分析流程，先做什么后做什么）
 * **具体要求是什么**（岗位的学历门槛、经验要求、技能清单）
 * **输出格式是什么**（报告的模板、表格、评分规则）
 * **特殊情况怎么处理**（简历格式混乱怎么办、知识库里没有岗位怎么办）

这份操作手册被上传到腾讯 IMA 的知识库中。当一份新简历进来时，AI 自动加载知识库中的
手册，逐项执行，最终输出一份完整的评估报告。

---

## 四、操作手册的核心设计

以下是我这份 Prompt 中最关键的几个设计点。

### 1. “ 求职意向优先 ” 匹配策略

大多数人在筛选简历时，会先看候选人的 ** 求职意向**。如果候选人想应聘 A 岗位，你却
拿 B 岗位的要求去衡量他，显然不合适。

所以在操作手册中，我规定了匹配策略：

>  * 先提取简历中的 ” 求职意向（期望岗位）”
>  * 在知识库中查找名称最接近或职责最匹配的岗位
>  * 进行 6 维度评分
>  * **如果匹配度 ≥ 50%，只输出该岗位的分析，不再匹配其他岗位**
>  * 如果匹配度 < 50% 或简历未写明意向，再与其他岗位逐一比对，取前 2 个输出

这个设计避免了信息过载——面试官只需要关注候选人最可能胜任的岗位。

### 2. “6 维度加权评分 ” 评估模型

我不希望 AI 只是笼统地说 ” 这个人不错 ” 或 ” 不太行 ”。所以设计了 6 个维度的量化
评分体系：

  |  维度 |  权重 |  说明 |  
   |  ① 学历门槛 |  10% |  是否符合最低学历要求 |  
 |  ② 工作年限 |  15% |  是否在要求范围内 |  
 |  ③ 技能匹配 |  25% |  核心技能覆盖率（权重最高） |  
 |  ④ 行业经验 |  15% |  是否有同行业经验 |  
 |  ⑤ 项目 / 业务匹配 |  20% |  项目复杂度与业务场景相似度 |  
 |  ⑥ 软性素质 |  15% |  管理能力、沟通能力、稳定性 |

**综合匹配度 = Σ(维度得分 × 权重) / 10 × 100%**

这样既保证了评估的 ** 结构化 **，又通过权重体现了** 不同维度的重要性差异**——技能
匹配权重最高（25%），因为这是岗位胜任的关键；学历权重最低（10%），因为学历只是门槛
而非决定因素。

### 3. “ 需面试核实 ” 标记机制

AI 知识库模式下无法联网搜索，简历中的一些描述（如 ” 行业 Top10 企业 ”、” 国家高新
技术企业 ”、” 管理团队 50 人 ” 等）无法验证。

所以我设计了 ” 需核实描述标记机制 ”：

 * AI 提取简历信息时，同步标记四类需要核实的内容：**企业相关、教育背景、荣誉资质、
   数据类描述**
 * 这些描述在评分时 ** 暂按简历所述计分**（不假设对错）
 * 但在报告的⚠️板块中单独列出，并生成对应的面试追问方向
 * 在面试大纲中，这些核实项被标记为 **P0（必问）**，面试官必须确认

这既保证了评分的相对客观，又不会让 AI 替面试官做 ” 信或不信 ” 的判断。

### 4. 面试问题库自动生成

报告的最后一个板块是面试大纲，这部分我认为是整套输出中最具实用价值的：

 * **基于差距项生成**：每个不匹配项至少生成 2 个面试问题，采用 STAR 原则设计
 * **基于匹配项深挖**：对匹配项追问细节，验证真实性和深度
 * **基于简历疑点提问**：短期任职、职业空档期、职位跳跃等，都有对应的提问模板
 * **优先级分层**：P0 必问（2- 3 个）、P1 重点（2- 3 个）、P2 确认（1- 2 个），总
   问题数控制在 5 - 8 个

面试官拿着这份报告，**不需要再额外准备面试问题**，直接翻到面试大纲部分就能开始面试。

---

## 五、实战输出：一份真实的评估报告

以下是以某 ** 物业经理 ** 岗位为例的评估输出。为保护隐私，已做脱敏处理。

### 📋 简历概览

  |  项目 |  内容 |  
   |  候选人 |  某先生 |  
 |  求职意向 |  物业经理 |  
 |  工作年限 |  17 年 |  
 |  最高学历 |  本科（非统招） |  
 |  核心技能 |  前介管理、多项目管理、物业费收缴、运营品质管理、团队管理 |

### ⚠️ 需面试核实的描述

  |  简历描述 |  核实要点 |  建议追问方向 |  优先级 |  
   |  项目集中交付（交房）全流程经验 |  简历中未明确描述主导过完整的集中交付 |  请举例说明主导过的集中交付项目，扮演角色，组织方式，交付率 |  🔴 P0 |

### 🥇 推荐岗位：物业经理（求职意向）

**综合匹配度：████████░░ 80%**

#### ✅ 匹配项（优势）

 * **行业经验资深：** 17 年物业行业经验，覆盖前介、工程、运营、客服等多条线
 * **管理能力全面：** 具备全周期管理经验，在头部物业公司体现多项目统筹能力
 * **核心指标达成：** 对收缴率、业主满意度有明确负责经验
 * **期望薪资匹配：** 7 千 - 8 千 / 月与岗位薪资范围匹配

#### ❌ 不匹配项 / 差距

 * **同岗位经验年限不足：** 物业经理同岗经验约 6 年（头部公司 A 约 1 年 9 个月 +
   某央企物业约 3 年 1 个月 + 某头部地产旗下物业约 2 年 9 个月），低于要求的 10 
   年
 * **集中交付经验缺失：** 简历未明确描述主导过完整的项目集中交付全流程

#### 📊 各维度评分

  |  维度 |  得分 |  说明 |  
   |  学历门槛 |  10/10 |  本科（非统招）符合要求 |  
 |  工作年限 |  5/10 |  同岗经验 6 年，低于 10 年要求 |  
 |  技能匹配 |  8/10 |  核心技能全面 |  
 |  行业经验 |  10/10 |  一直深耕物业行业 |  
 |  项目 / 业务匹配 |  6/10 |  集中交付经验缺失 |  
 |  软性素质 |  7/10 |  稳定性需面试考察 |

#### ⏳ 稳定性评估

暂未发现短期任职记录（所有任职均≥12 个月），但近 3 段经历均不足 3 年，稳定性需面试
重点关注。

#### 💡 综合建议

**推荐进入面试池。** 行业背景扎实，技能覆盖面广，核心运营能力强。短板（同岗位经验
年限和集中交付经验）需通过面试深度挖掘。

### 🎯 面试大纲：物业经理

#### 考察重点排序

  |  优先级 |  考察方向 |  原因 |  建议时长 |  
   |  🔴 P0 |  项目集中交付实操经验 |  核心职责缺失 |  10min |  
 |  🔴 P0 |  工作经验深度与广度 |  核实物业经理职责的实际承担 |  10min |  
 |  🟡 P1 |  社区多种经营落地能力 |  增值业务要求 |  5min |  
 |  🟢 P2 |  学历信息与离职原因 |  基础确认与稳定性评估 |  5min |

#### 面试问题示例

**P0-1 方向：项目集中交付经验**

> 请描述一次您参与或主导的 ** 项目集中交付（交房）**全过程。您需要说明：项目规模、
> 您的角色、交付方案要点、如何协调多方资源、如何处理突发问题、最终交付率指标。（
> STAR 原则）
>  * **追问点：** 如果偏向 ” 参与 ”，追问 ” 您认为物业经理在集中交付中最重要的三
>    个工作重点是什么？”
>  * **考察意图：** 验证项目交付实操经验，判断风险预判和组织协调能力

**P0-2 方向：工作经验深度**

> 您近一段在某央企物业担任 ” 物业工程经理 ”，上一段在头部物业公司 A 担任 ” 物业运营
> 经理 ”。请举例说明，您在这些岗位上如何实质上履行了物业经理的管理职责？（STAR 原则）
>  * **追问点：** “ 物业经理与工程经理 / 运营经理在能力要求上最大的区别是什么？”
>  * **考察意图：** 判断是否具备全局经营思维

#### 面试评分卡

  |  评估维度 |  评分（1-5） |  记录 |  
   |  专业技能匹配度 |   |   |  
 |  项目经验深度 |   |   |  
 |  沟通表达 |   |   |  
 |  稳定性与职业规划 |   |   |  
 |  文化契合度 |   |   |  
 |  总分 |  /25 |   |  
 |  面试结论 |  □ 通过 □ 待定 □ 不通过 |   |

### 📌 总体结论

  |  是否推荐 |  理由 |  
   |  **推荐面试** |  行业背景扎实，技能覆盖广。在忽略 TOP10 和证书要求后，经验高度匹配。短板需面试挖掘。 |

---

## 六、这套方案的优势

### 🚀 零开发成本

不需要写代码，不需要训练模型，不需要 IT 部门支持。**写好一份 Prompt 文档，上传到
IMA 知识库，即可使用。**

### 📐 评估标准统一

所有简历都由同一套标准（6 维度加权评分）进行评估，避免了不同面试官之间的主观差异。

### 🧠 输出即行动指南

报告不只是 ” 打个分 ”，而是直接输出 ** 面试问题、追问方向、考察意图、评分卡**。面试
官拿到报告就能直接面试，不需要额外准备。

### 🔄 轻松迭代

岗位需求变了？只需要 ** 更新知识库中的操作手册 ** 即可。不涉及程序修改，不涉及系统
配置变更。

### 🛡️ 数据安全

简历信息在 IMA 知识库内处理，不经过第三方平台，适合有数据隐私要求的企业环境。

---

## 七、实用建议

### 1. 操作手册建议用 ” 文档 ” 而非 ” 对话 ”

直接在 IMA 对话框中写 Prompt，容易出现格式丢失、逻辑混乱。建议先在本地写好一份完整
的 Markdown 文档，确认无误后再上传至知识库。

### 2. 区分 ” 忽略条件 ” 与 ” 硬性条件 ”

在实际使用中，有些岗位要求可能过于严格（如 ” 必须 TOP10 企业出身 ”）。可以在操作
手册中明确哪些条件可以忽略，AI 会相应调整匹配策略。但要注意，**忽略的条件必须在报告
中醒目标注**，让面试官知晓录用风险。

### 3. 设置 ” 需核实项 ” 确保诚信底线

这是最重要的一条。AI 无法联网验证，所以必须在 Prompt 中明确要求 AI 标注需要面试官
核实的描述。否则面试官可能会轻信简历中的夸大描述。

### 4. 定期迭代操作手册

随着招聘经验积累，你可能会发现新的评估维度、更有效的面试问题、或更合适的权重分配。
建议每季度复盘一次操作手册，持续优化。

---

## 八、总结

腾讯 IMA + 一份 Prompt 操作手册，本质上是一个 ** 零代码的智能简历筛选系统**。

  |  对比项 |  传统方式 |  本方案 |  
   |  初筛一份简历 |  15~30 分钟 |  1~2 分钟 |  
 |  评估标准一致性 |  依赖个人判断 |  AI 统一标准 |  
 |  面试问题准备 |  另花时间梳理 |  报告自带问题库 |  
 |  迭代成本 |  需培训或改制度 |  改文档即可 |  
 |  开发成本 |  需 IT 支持 |  零代码 |

如果你也在为简历筛选效率发愁，不妨试试这个思路。

> **一份好的 Prompt，就是一份可执行的 SOP。**

---

_本文由实际操作经验整理而成，所用工具为腾讯 IMA。如果你也在用 IMA 或其他 AI 知识
库搭建招聘筛选系统，欢迎留言交流。_

## 关于“粤语保留古音”说法的一点分析

- Link: https://blog.guohao.asia/%e5%85%b3%e4%ba%8e%e7%b2%a4%e8%af%ad%e4%bf%9d%e7%95%99%e5%8f%a4%e9%9f%b3%e8%af%b4%e6%b3%95%e7%9a%84%e4%b8%80%e7%82%b9%e5%88%86%e6%9e%90.html
- Published: 2026-05-07T10:55:44+08:00
- Author: null

一、问题的起点：一个常见的说法

“粤语是唐朝官话”、“粤语最接近古汉语”、“用粤语读唐诗更有韵味”——这些说法在民间广为
流传，甚至被不少人当作常识。支持者通常给出的理由是：粤语保留了入声（-p、-t、- k 
韵尾），而普通话丢失了；粤语有九个声调，更接近中古汉语的声调格局。

 但我在追问中发现，这个说法经不起推敲。

 二、第一个矛盾：唐代人听不懂岭南话

 史料记载，唐代被贬到岭南的士大夫明确表示听不懂当地人的语言。韩愈 819 年被贬潮州，
写“言语不通，画地为字”；柳宗元在柳州需要“问重译”（多次翻译）；刘禹锡在连州把当地
语言比作“鸟语”。

 如果粤语真的是唐代官话，为什么唐代人自己听不懂？支持者可能会说：当时岭南人不讲官话，
讲的是土著语言——这个解释是对的，但带来了一个新问题：既然唐代岭南地区主要通行的是
俚僚语（古壮侗语），而不是汉语，那后来形成的粤语，其“古音”又是从哪来的？

 三、惠能案例：为什么第二代移民就“语音不正”了

 六祖惠能（638-713 年）的父亲是河北范阳人，被流放到岭南新州（今广东新兴）。惠能是
标准的“移民第二代”，但五祖弘忍叫他“獦獠”（对岭南土著的蔑称），他自己也说“生在边方，
语音不正”。

 这是一个关键证据：在初唐时期，一个移民第二代，仅仅因为生活在岭南乡村，就已经被当地
人同化到口音“不正”的程度。这说明当时岭南的汉语移民在人口上不占优势，汉语在当地并
没有扎根。

 那我自然要问：如果初唐的移民第二代就已经“语音不正”了，那后来粤语所谓的“保留古音”
是从哪里来的？总不能说惠能说的“不正”的话，后来变成了“正”的古音吧。

 四、宋代移民与粤语定型

 历史上的解释是：晚唐至宋代，又有大量中原移民南迁，这次规模更大、更集中，加上俚僚
渠帅势力的瓦解和汉化，汉语才真正在岭南扎根。也就是说，粤语的形成关键期是晚唐到宋，
而不是初唐。

 但这里出现了一个新的矛盾：如果是宋代大量移民带来了中原汉语，那粤语应该接近宋代官话
才对。而且根据南宋周去非《岭外代答》的记载，当时岭南的汉语已经与中原官话“字字有异”，
需要靠翻译才能沟通。

 这说明：粤语在宋代已经与中原官话分道扬镳了，而不是保留了什么。

 五、普通话也保留了古汉语特征

 在讨论这个问题时，支持粤语的人往往只强调粤语“保留”了什么，却闭口不谈普通话“保留”
了什么。事实上，普通话同样保留了古汉语的若干特征，甚至在某些方面比粤语保留得更多。

 1.  声母层级的保留

 普通话的一个典型优势是保留了中古汉语的尖团音区分。中古汉语的“精组”（z、c、s 类）
和“见组”（g、k、h 类）在细音（i、ü韵母）前原本是对立的，这就是所谓的“尖团音”。比如“
尖”（精母）和“兼”（见母）在中古读音不同。普通话至今保持这种区分：“尖”读 jiān，“兼”
读 jiān——等等，普通话也不分。这个例子不对。

 换一个：实际上普通话的尖团音区分已经基本消失，只在部分方言中保留。我的这个论据站不住
脚。

 更好的例子是普通话保留了中古汉语的“平仄”对立格局。中古的四声（平、上、去、入）分为
平和仄（上、去、入为仄）。普通话虽然丢失了入声，但仄声的范畴通过上声和去声得以延续。
在古典诗词的平仄格律中，普通话的一、二声（平）和三、四声（仄）仍然能够识别平仄，
完成格律对仗的要求。粤语在这方面也不差，这个论据也不够有力。

 我承认：在声母层级，普通话说不上比粤语“保留更多”。双方各有得失。

 2.  词汇层级的保留

 在词汇层面，普通话保留了大量古汉语单音节词的使用方式，只不过从口语转移到了书面语。
例如：

·“走”：古汉语中表示“跑”，普通话保留“走马观花”（跑马看花）、“走狗”（跑腿的狗）、“
走笔”（运笔快写）等成语 
·“行”：古汉语中表示“走”，普通话保留“行路”、“步行”、“行踪”·“
食”：普通话保留“食品”、“粮食”、“日食月食”、“食言”等 ·“饮”：普通话保留“饮水思源”、“
冷饮”、“热饮”、“痛饮”

 粤语在口语中更直接地保留了“行”（走）、“食”（吃）、“饮”（喝）等单音节古词，这是事实。
但普通话不是“丢失”了这些词，而是把它们从日常口语提升到了书面和复合词的层面，日常
口语换用了“走”、“吃”、“喝”等演变后的新词。这是语言演变路径的不同，不代表谁更“高级”
或“正宗”。

 3.  语法层级的保留

 在语法层面，普通话保留了古汉语的核心语序：主 - 谓 - 宾（SVO）。粤语在某些句式上
偏离了这个语序。例如双宾语结构：

· 普通话：“给我一本书”（S-V-O1-O2，与古汉语一致）
· 粤语：“畀本书我”（S-V-O2-O1，
宾语顺序颠倒）

 此外，普通话保留了古汉语的“于”字被动句（“受制于人”）和“为”字被动句（“不为所动”），
虽然口语不常用，但书面语完整保留。粤语则发展出了“畀”字被动句（“畀人打咗”），这是
口语中的创新，与古汉语的被动表达方式不同。

 在这个层面，普通话比粤语更接近古汉语。

 4. “入声”問題的重新审视

 支持粤语的人最常拿入声说事。但即使在这点上，也需要更精确的评估。

 中古汉语的入声只占全部音节的 20% 左右，80% 的音节是非入声。一个只覆盖五分之一音节
的特征，拿来作为判断“谁更接近古汉语”的核心标准，这本身就不合理。

 更关键的是：入声在唐诗宋词的主体——近体诗（律诗、绝句）——中，几乎不用来押韵。唐代
近体诗押韵全部用平声字，入声只在古体诗（乐府、歌行等）中使用。说入声是唐音的核心
特征，这本身就是夸大其词。

 而且，即使就入声而论，普通话也不是“完全丢失”，而是发生了“转化”。入声字在普通话中
派入了三声（阴平、阳平、上声、去声），但这种派入是有规律的：古清入字多读去声，古
全浊入字多读阳平。普通话虽然没有塞音韵尾，但通过缩短音长、增加顿挫感的方式处理入
声字，在朗诵实践中形成了一套成熟的补偿机制。

 5.  量化比较的不可能性

 其实，“粤语保留了 x% 的古汉语特征”这种说法本身就是伪命题。古汉语是一个复杂的系统，
有几十个声母、几百个韵母、四个声调（各分阴阳）。要量化“保留比例”，需要给每个特征
分配权重——声母占多少？韵母占多少？声调占多少？词汇占多少？语法占多少？

 这种权重分配是主观的，没有客观标准。支持粤语的人把入声的权重打得极高，把其他特征
的权重压得极低，然后宣称粤语“更接近”。这是选择性比较。

 如果说粤语保留了 20% 的古汉语特征，那普通话保留了哪个比例？根据上述分析，普通话
在语法、词汇（书面层面）、声调格局上都有保留，在入声上有所丢失。硬要量化的话，我不
认为普通话的比例“更高”，但也不承认粤语“高到哪里去”。更准确的表述是：粤语和普通话
保留了古汉语的不同层面，没有哪一个能够全面压倒对方。

 六、一个简单的测试：“各个国家有各个国家的国歌”

 为了验证“粤语保留古音”的说法，我用一个极端的句子做测试：

“各个国家有各个国家的国歌”

 粤语读出来：

· 各 (gok3) vs 国 (gwok3)——几乎同音，只差一个轻微的 w 介音 
· 个 (go3) vs 歌 (go1)——
仅声调不同 · 整句话充满了 g -、gw-、-ok、- o 的高度重复

 这句话用粤语读出来非常绕口，甚至可以说难以流畅朗诵。

 我的问题是：如果唐朝官话读出来也是这个效果，那当时的诗人怎么朗诵作品？听众怎么分辨？
一个口口相传的文学传统，怎么可能建立在这样容易混淆的语音系统上？

 唯一的结论是：唐朝官话读这句话，可能比今天的粤语清晰得多。今天的粤语之所以绕口，
不是因为它保留了古音，而是因为它自己演变出了问题。

 七、《水调歌头》的实测：押韵及格，流畅不及格

 我用苏轼的《水调歌头·明月几时有》进一步测试。

 押韵方面：韵脚字（天、年、寒、间、眠、圆、全、娟）在粤语中韵母高度统一（-in/-yn），
确实比普通话押得更工整。这点我承认粤语有优势。

 但流畅清晰度方面：看这句“月有阴晴圆缺”：

· 月 (jyut6)、圆 (jyun4)、缺 (kyut3)
·“月”和“圆”声母相同（j-），韵腹相同（yu），
区别仅在于一个带 - t 塞音尾，一个带 - n 鼻音尾 · 连续读出来，声母单调，韵母在鼻腔
和喉塞间快速切换，产生明显的绕口感

 普通话读这句话：“月 (yuè)、圆 (yuán)、缺 (quē)”，韵尾分别为 -e、-n、-e，开口度和
音色差异大，流畅清晰，无绕口感。

 我的逻辑推论是：如果宋代官话读“月有阴晴圆缺”也是这种绕口感，这句话就不可能成为流传
千古的名句。口口相传的艺术形式会自然淘汰这种“反流畅”的表达。因此，苏轼时代的宋音，
读这句话必然比今天的粤语流畅清晰得多。

 八、《楚辞》的终极测试

 为了把问题推到更深处，我用《楚辞·湘夫人》做测试：

“帝子降兮北渚，目眇眇兮愁予。袅袅兮秋风，洞庭波兮木叶下。”

 押韵字是“予”和“下”。根据上古音构拟（王力系统），这两个字在上古属于同一个韵部（鱼
部），是可以通押的。

 现在用粤语读：

·“予”读 jyu4
·“下”读 haa6· 没有任何共同发音成分：声母不同、韵母不同、声调不同——完全
不押韵

 普通话读也不押韵。

 但问题在于：如果粤语真的“保留了更多古音”，那它至少应该在读《楚辞》时比普通话更接近
上古的押韵格局。事实是：它和普通话一样，完全无法呈现“予—下”的押韵关系。这说明粤语
保存的所谓“古音”，最远也只能追溯到中古，而无法触及上古。当有人笼统地说“粤语更接近
古汉语”时，这里的“古汉语”如果指的是先秦两汉的上古汉语，那粤语的表现并不比普通话“
更接近”；如果指的是中古汉语，那也只是部分特征更接近，而不是整体。

 九、发展与变更的关系：为什么“保留”不是唯一的价值标准

 前面所有的讨论都假设了一个前提：“保留古音”是一件好事，“更接近古汉语”是一种优势。
但我想追问：这个前提成立吗？

 语言是活的。从上古汉语到中古汉语，从中古汉语到近代汉语，从近代汉语到现代汉语，每一
次演变都是“丢失”了一些旧特征，“获得”了一些新特征。先秦的《诗经》用上古音读，唐代
人已经听不押韵了；唐代的唐诗用中古音读，宋代人已经觉得有些字“走音”了。演变从未停止。

 从这个角度看，“保留古音”这件事本身，并不能天然地等同于“价值更高”。如果保留得越古
越好，那我们应该一直说上古汉语，甚至原始汉藏语——但这显然荒谬。语言的价值在于它当下
的交际功能和文表达力，而不是它存留了多少古代遗迹。

 一个更深刻的问题：为什么我们从来不要求其他领域的“保留”？为什么我们不要求现代医学
保留古代医书的所有药方？为什么我们不要求现代建筑保留古代建筑的榫卯结构？为什么我们
不要求现代法律保留古代的律令条文？

 因为在这些领域，我们默认“发展”是正向的，“变化”是进步的。唯独在语言领域，有一种奇怪
的“厚古薄今”倾向——仿佛越古老就越正宗，越不变就越高级。

 这种倾向如果推到极致，逻辑上会导致什么结果？那就是闭关锁国。不与外界交流，不接受
新事物，不产生新词汇，不发展新语法——这样才能最大程度地“保留古音”。历史上，岭南地区
正是因为地理封闭，才在语言上相对保守。但如果把这个当作优点来歌颂，那等于在说：封闭
是好的，隔绝是好的，不变是好的。

 这显然与现代化、全球化的方向背道而驰。

 事实上，普通话的产生和发展，正是中国从封闭走向开放、从分裂走向统一、从农业社会走向
现代社会的语言缩影。它吸收了不同方言的精华，简化了繁琐的声调系统，优化了容易混淆
的声韵组合，形成了一套更高效、更清晰、更易学的标准语。这个过程不是“破坏古音”，而是“
语言现代化”的必然代价和必要步骤。

 粤语的所谓“保留”，本质上是历史遗留的地域封闭性的产物——而不是什么文化优越性的证明。

 十、普通话对古诗词的支持：一项被忽视的证据

 在讨论这个问题时，普通话的一个巨大优势往往被刻意忽略：普通话是今天全国通用的标准
语，几乎所有古诗词的朗诵、教学、传播都在普通话框架内进行。这意味着，普通话在实践
层面已经形成了一套完整的古诗词朗诵体系——包括如何处理入声字（缩短音长、增加顿挫感），
如何处理古音与现代音的差异，如何通过语气、停顿、重音来弥补押韵上的小瑕疵。

 粤语的支持者往往只做“纸面对比”，却不做“听觉测试”。他们只说粤语的押韵更工整，却不
说粤语的流畅清晰度有问题；他们只强调入声保留了古音，却不问这种保留是否以牺牲声母
区分为代价。

 更关键的是：普通话朗诵古诗词的审美效果，不是“理论推导”出来的，而是近百年实践中被
亿万听众检验过的。无论是央视的《中国诗词大会》，还是中小学语文课堂，普通话朗诵已经
证明了自己能够传达古诗词的美感。粤语朗诵如果真的有“压倒性优势”，没道理在公共文化
领域完全没有存在感。

 十一、核心结论

 经过以上分析，我得出的结论是：

 1. “粤语保留古音”是一个被夸大的说法。更准确地说，粤语在中古汉语的韵尾和声调格局上比
    普通话保留了更多特征，但在声母层面发生了严重的合并和演变，在语法层面出现了创新，
    导致其在朗诵古代作品时出现流畅清晰度的问题。说它“保留”是片面的，说它“更接近”是选择
    性的。
 2.  普通话同样保留了古汉语的若干特征，语法上更接近古汉语语序，词汇上通过书面语和复合
    词保留了古词，声调格局上维持了平仄对立。没有客观标准可以证明粤语的“保留比例”高于
    普通话——因为“比例”本身就是伪命题。
 3.  粤语不是“活化石”，而是“变异后代”。它不是一个被冻结的古汉语样本，而是一个独立演变
    了 1000 多年的活语言。它保留了某些特征，丢失了另外一些特征，并产生了自己的新特征。
    这既是它的独特性，也恰恰说明它不是古汉语本身。
 4.  没有现代方言可以自称“最接近古汉语”。古汉语已死，所有现代方言都是它的后代，只是
    演变的路径和速度不同。粤语在某些方面更保守，在另一些方面更激进；普通话也是一样。
    说“粤语更接近古汉语”是选择性比较的结果——只比粤语强的地方，不比粤语弱的地方。
 5.  发展和变更是语言的生命线。一味强调对古代语言的保留，逻辑上推演到极端，就是闭关
    锁国、拒绝交流、拒绝发展。普通话的产生和推广，是中国语言现代化的必要步骤；粤语的
    所谓“保留”，本质上是地理封闭性的历史遗留，而不是文化优越性的证明。在全球化、信息
    化的今天，用一种方言的“古旧”来否定全国通用语的“现代”，既不合时宜，也不符合语言发展
    规律。
 6.  朗诵古代作品的审美判断，应同时考虑押韵工整度和流畅清晰度。粤语在押韵上有优势，
    但在流畅清晰度上有明显缺陷；普通话则相反。在公共文化实践中，普通话凭借其通用性和
    完整的朗诵体系，已经证明了自己能够有效传达古诗词的美感。

 十二、对有说服者的回应

 如果有人再对我说“粤语是唐朝官话”，我会直接问：

“那请你用粤语读一下《楚辞》里‘愁予’的‘予’和‘木叶下’的‘下’。这两个字在屈原的时代是
押韵的，但你的粤语读出来完全不押韵。如果粤语真的是古汉语标准音，为什么连《楚辞》
最基本的押韵关系都无法呈现？”

 然后再问第二个问题：

“你总说粤语保留了入声，那请你用粤语读一下‘各个国家有各个国家的国歌’。这句话为什么
这么绕口？唐朝官话读出来也是这个效果吗？如果是，那唐诗怎么流传的？如果不是，那粤语
凭什么自称唐朝官话？”

 第三个问题：

“你说粤语更接近古汉语，那你告诉我，这个‘古汉语’指的是哪个时代？如果是上古（《诗经》《
楚辞》），粤语的表现和普通话一样差；如果是中古（唐诗宋词），粤语押韵好但流畅差，
整体并不比普通话‘更接近’。你到底是拿什么标准得出‘更接近’的结论的？”

 最后一个问题：

“如果说保留古音就是好的，那我们应该一直保留上古音，不说任何新词，不借用任何外来语，
不与外界交流。你真的认为这是值得追求的方向吗？发展和变更是语言的宿命，也是语言的
生命。粤语能活到今天，不是因为它保留了古音，而是因为它一直在变。”

## MediaWiki 扩展：CosPreview

- Link: https://blog.guohao.asia/mediawiki-%e6%89%a9%e5%b1%95%ef%bc%9acospreview.html
- Published: 2025-10-17T10:29:05+08:00
- Author: null

[CosPreview](https://blog.guohao.asia/wp-content/themes/wordpress-theme-puock-2.8.16/inc/go.php?to=aHR0cHM6Ly9naXRodWIuY29tL2l0Zmt5YmIvQ29zUHJldmlldw==)
是一个用于在 MediaWiki 页面中嵌入腾讯云对象存储（COS）文档预览功能的扩展。它通过
COS 的文档转换服务，将存储在 COS 中的文件（如 Excel、Word、PDF 等）转换为 HTML 预
览页面，并直接在 wiki 中显示。

** 主要功能 **：

 *  支持多种文档格式的预览（基于腾讯云 COS 的转换能力）。
 *  简单易用的标签语法，只需指定 COS 参数即可嵌入预览。
 *  无需额外服务器处理，依赖腾讯云 COS 的 CDN 和转换服务。

##  安装说明

###  前提条件

 *  确保您的 MediaWiki 版本兼容（建议 MediaWiki 1.35+）。
 *  您需要拥有腾讯云 COS 账户，并已配置存储桶（Bucket）、获取访问 ID 和区域信息。

 1.  开通腾讯云对象存储：[https://curl.qcloud.com/YnAsmg0H](https://blog.guohao.asia/wp-content/themes/wordpress-theme-puock-2.8.16/inc/go.php?to=aHR0cHM6Ly9jdXJsLnFjbG91ZC5jb20vWW5Bc21nMEg=)
 2.  创建【存储桶】⌊MediaWiki 扩展：CosPreview⌉

 *  在腾讯云 COS 中启用文档预览功能（可能需要额外配置，参考腾讯云文档）。
 *  进入存储桶，开启【文档处理功能】⌊MediaWiki 扩展：CosPreview⌉

###  安装步骤

 1.  下载或克隆 CosPreview 扩展代码，将其上传至 MediaWiki 的 `extensions` 目录并解压（
    如果使用 Git，可克隆到该目录）。
 2.  在 MediaWiki 的配置文件 `LocalSettings.php` 中添加以下代码以启用扩展：

    ```language-default
       wfLoadExtension('CosPreview');
    ```

 3.  可选：如果需要全局配置 COS 参数（如默认区域或 ID），可以在 `LocalSettings.php`
    中添加额外设置（具体参数请参考扩展文档）。
 4.  保存文件并运行 MediaWiki 的更新脚本（例如，通过访问 `https://your-wiki/mw-config/`
    或使用命令行工具）。

##  使用说明

###  基本用法

 在 MediaWiki 页面的 wikitext 中，使用 `<cospreview>` 标签插入文档预览。标签支持
以下属性：

 * `id`（必需）：腾讯云 COS 的存储桶 ID 或 CDN 标识符，例如 `"cdn-1253443493"`。
 * `path`（必需）：文件在 COS 存储桶中的路径，例如 `"picgo/202411201059195.xlsx"`。
 * `region`（必需）：COS 存储桶所在的区域，例如 `"ap-beijing"`（北京区域）。

** 示例 **：

    ```language-default
    <cospreview id="cdn-1253443493" path="picgo/202411201059195.xlsx" region="ap-beijing" />
    ```

 这将在页面中嵌入一个预览区域，显示指定 Excel 文件的内容。

###  参数详解

 * **id**：对应腾讯云 COS 存储桶的唯一标识符。您可以在腾讯云控制台的存储桶详情中
   找到该值。
 * **path**：文件的完整路径，包括文件夹和文件名。确保文件已上传到 COS 并具有公共
   读取权限（或通过 COS 预览服务访问）。
 * **region**：COS 存储桶的区域代码，例如 `ap-beijing`（北京）、`ap-shanghai`（上海）
   等。完整区域列表请参考腾讯云文档。

###  更多示例

 *  预览 Word 文档：

    ```language-default
      <cospreview id="my-bucket-id" path="documents/report.docx" region="ap-shanghai" />
    ```

 *  预览 PDF 文件：

    ```language-default
      <cospreview id="cdn-123456789" path="files/manual.pdf" region="ap-guangzhou" />
    ```

###  注意事项

 *  确保 COS 文件可公开访问或已配置预览权限，否则预览可能失败。
 *  扩展依赖腾讯云 COS 服务，请确保您的 COS 账户余额充足或服务未过期。
 *  如果预览不显示，检查 MediaWiki 错误日志或 COS 控制台以排查问题。
 *  该扩展仅提供预览嵌入功能，文件上传和管理需通过腾讯云 COS 单独处理。

##  支持与贡献

 如果您遇到问题或想贡献代码，请访问 [GitHub 项目页面 ](https://blog.guohao.asia/wp-content/themes/wordpress-theme-puock-2.8.16/inc/go.php?to=aHR0cHM6Ly9naXRodWIuY29tL2l0Zmt5YmIvQ29zUHJldmlldw==)
提交 Issue 或 Pull Request。

---

## English Version (For Reference)

# MediaWiki Extension: CosPreview

[CosPreview](https://blog.guohao.asia/wp-content/themes/wordpress-theme-puock-2.8.16/inc/go.php?to=aHR0cHM6Ly9naXRodWIuY29tL2l0Zmt5YmIvQ29zUHJldmlldw==)
is a MediaWiki extension that allows embedding document previews from Tencent Cloud
Object Storage (COS). It converts files stored in COS (e.g., Excel, Word, PDF) into
HTML previews using COS’s document processing service and displays them directly
in wiki pages.

**Features**:

 * Supports preview for multiple document formats (via Tencent Cloud COS conversion).
 * Simple tag-based syntax to embed previews by specifying COS parameters.
 * No additional server processing required; relies on Tencent Cloud COS CDN and
   conversion services.

## Installation

### Prerequisites

 * Ensure your MediaWiki version is compatible (recommended: MediaWiki 1.35+).
 * You need a Tencent Cloud COS account with a configured bucket, access ID, and
   region information.
 * Enable document preview in Tencent Cloud COS (may require additional setup; refer
   to Tencent Cloud documentation).

### Steps

 1. Download or clone the CosPreview extension code and upload it to the `extensions`
    directory of your MediaWiki installation, then unzip it (if using Git, clone into
    this directory).
 2. Add the following code to your MediaWiki configuration file `LocalSettings.php`
    to enable the extension:

    ```language-default
       wfLoadExtension('CosPreview');
    ```

 3. Optional: For global configuration of COS parameters (e.g., default region or ID),
    add additional settings in `LocalSettings.php` (refer to extension documentation
    for details).
 4. Save the file and run MediaWiki’s update script (e.g., via `https://your-wiki/mw-
    config/` or command-line tools).

## Usage

### Basic Usage

In MediaWiki wikitext, use the `<cospreview>` tag to insert a document preview. 
The tag supports the following attributes:

 * `id` (required): The bucket ID or CDN identifier from Tencent Cloud COS, e.g.,`"
   cdn-1253443493"`.
 * `path` (required): The file path within the COS bucket, e.g., `"picgo/202411201059195.
   xlsx"`.
 * `region` (required): The region of the COS bucket, e.g., `"ap-beijing"` (Beijing
   region).

**Example**:

    ```language-default
    <cospreview id="cdn-1253443493" path="picgo/202411201059195.xlsx" region="ap-beijing" />
    ```

This will embed a preview area in the page showing the content of the specified 
Excel file.

### Parameter Details

 * **id**: The unique identifier for your Tencent Cloud COS bucket. You can find
   this value in the bucket details in the Tencent Cloud console.
 * **path**: The full path to the file, including folders and filename. Ensure the
   file is uploaded to COS and has public read access (or is accessible via COS 
   preview services).
 * **region**: The region code of the COS bucket, e.g., `ap-beijing` (Beijing), `
   ap-shanghai` (Shanghai). For a full list, refer to Tencent Cloud documentation.

### More Examples

 * Preview a Word document:

    ```language-default
      <cospreview id="my-bucket-id" path="documents/report.docx" region="ap-shanghai" />
    ```

 * Preview a PDF file:

    ```language-default
      <cospreview id="cdn-123456789" path="files/manual.pdf" region="ap-guangzhou" />
    ```

### Notes

 * Ensure the COS file is publicly accessible or has preview permissions enabled;
   otherwise, the preview may fail.
 * The extension relies on Tencent Cloud COS services; make sure your COS account
   has sufficient balance and services are active.
 * If the preview does not appear, check MediaWiki error logs or the Tencent Cloud
   console for troubleshooting.
 * This extension only provides preview embedding; file upload and management must
   be handled separately via Tencent Cloud COS.

## Support & Contribution

If you encounter issues or want to contribute, please visit the [GitHub project page](https://blog.guohao.asia/wp-content/themes/wordpress-theme-puock-2.8.16/inc/go.php?to=aHR0cHM6Ly9naXRodWIuY29tL2l0Zmt5YmIvQ29zUHJldmlldw==)
to submit an Issue or Pull Request.

##  Gravatar 验证

- Link: https://blog.guohao.asia/gravatar-%e9%aa%8c%e8%af%81.html
- Published: 2025-10-15T11:33:45+08:00
- Author: null

* [Gravatar](https://blog.guohao.asia/wp-content/themes/wordpress-theme-puock-2.8.16/inc/go.php?to=aHR0cHM6Ly9ncmF2YXRhci5jb20vaGFydmV5OXVv)

 * [Gravatar](https://blog.guohao.asia/wp-content/themes/wordpress-theme-puock-2.8.16/inc/go.php?to=aHR0cHM6Ly9ncmF2YXRhci5jb20vaGFydmV5OXVv)

## 网站改版升级：更快、更稳、更简洁

- Link: https://blog.guohao.asia/%e7%bd%91%e7%ab%99%e6%94%b9%e7%89%88%e5%8d%87%e7%ba%a7%ef%bc%9a%e6%9b%b4%e5%bf%ab%e3%80%81%e6%9b%b4%e7%a8%b3%e3%80%81%e6%9b%b4%e7%ae%80%e6%b4%81.html
- Published: 2025-09-25T11:04:14+08:00
- Author: null

大家好！最近我对个人网站进行了一次全面的改版升级，目的是为了解决长期以来困扰我的
一些问题。如果你之前访问过我的网站，可能会注意到一些变化；如果是新朋友，那么欢迎
来到这个全新的空间！

##  为什么需要改版？

 原来的网站完全基于 WordPress 搭建，为了保持首页的版式和功能，我使用了大量的建站
插件。虽然这些插件在初期帮助我快速实现了设计效果，但也带来了一些明显的弊端：

 * ** 运行速度慢 **：插件越多，网站加载时间越长，影响用户体验。
 * ** 访问延迟高 **：特别是对于移动端用户，页面响应不够流畅。
 * ** 兼容性问题 **：每次 WordPress 或插件更新时，总有可能出现冲突，导致网站临时
   宕机或功能异常。

 这些问题不仅让我作为站长头疼，也可能影响了大家的浏览体验。因此，我决定对网站架构
进行一次彻底的优化。

##  改版的具体变化

 本次改版的核心思路是“动静分离”：将动态内容和静态内容拆分开，以提升整体性能。

 1. ** 全新主页入口 ** 现在，网站的主页（二级域名 `guohao.asia`）采用纯 HTML + CSS 
    的静态部署方式。这样做的好处是页面加载速度极快，且几乎不存在兼容性风险。无论是电脑
    还是手机访问，都能获得一致的流畅体验。
 2. ** 博客系统保留并优化 ** 我的个人博客部分依旧基于 WordPress，但现已迁移至三级域
    名 `blog.guohao.asia`。通过 WordPress 提供的 REST API，主页与博客实现了无缝对接，
    既保留了 WordPress 强大的内容管理功能，又避免了插件冗余。
 3. ** 文章链接更新 ** 所有历史文章都完好保留，但访问链接需要稍作调整：原链接前需加上`
    blog` 改为三级域名。例如，原来的 `guohao.asia/post-name` 现在变为 `blog.guohao.
    asia/post-name`。如果你收藏了某些旧链接，只需简单修改即可继续访问。

##  改版带来的好处

 这次改版后，最直观的提升包括：

 * ** 速度显著加快 **：由于减少了插件依赖，页面加载时间大幅缩短。
 * ** 稳定性增强 **：静态主页几乎无需维护，博客系统也因插件精简而更稳定。
 * ** 用户体验优化 **：无论是浏览主页还是阅读博客，操作都更加顺畅。

 当然，改版过程中我也遇到了一些技术挑战，比如数据迁移和链接重定向的处理，但最终的
结果让我非常满意。如果你在访问过程中遇到任何问题，欢迎随时通过博客的留言功能告诉
我！

##  写在最后

 网站优化是一个持续的过程，这次改版只是第一步。未来我还会继续关注性能和数据安全，
为大家提供更优质的内容和服务。如果你对这次改版有任何建议或想法，也欢迎在评论区分享
交流。

 感谢大家的支持，希望新网站能给你带来更好的体验！

---

## 世界，您好！

- Link: https://blog.guohao.asia/hello-world.html
- Published: 2025-09-19T14:33:40+08:00
- Author: null

欢迎使用 WordPress。这是您的第一篇文章。编辑或删除它，然后开始写作吧！

## 使用ExcelVBA审计钉钉原始打卡记录(代码优化)

- Link: https://blog.guohao.asia/%e4%bd%bf%e7%94%a8excelvba%e5%ae%a1%e8%ae%a1%e9%92%89%e9%92%89%e5%8e%9f%e5%a7%8b%e6%89%93%e5%8d%a1%e8%ae%b0%e5%bd%95%e4%bb%a3%e7%a0%81%e4%bc%98%e5%8c%96.html
- Published: 2025-08-30T10:07:32+08:00
- Author: null

```language-default
    Sub FindMultiUserDevicesWithCount()
        ' 声明变量
        Dim wsSource As Worksheet, wsResult As Worksheet
        Dim dict As Object ' 用于存储设备号和对应的员工集合
        Dim lastRow As Long, i As Long
        Dim deviceID As String, employeeName As String
        Dim key As Variant, empKey As Variant
        Dim outputRow As Long
        Dim nameList As String

        ' 设置源数据工作表 (假设数据在原始记录)
        On Error Resume Next
        Set wsSource = ThisWorkbook.Worksheets("原始记录")
        On Error GoTo 0

        If wsSource Is Nothing Then
            MsgBox "找不到工作表' 原始记录 '，请修改代码中的工作表名称。", vbExclamation
            Exit Sub
        End If

        ' 创建或清空结果工作表
        Application.DisplayAlerts = False
        On Error Resume Next
        ThisWorkbook.Worksheets("异常设备报告").Delete
        On Error GoTo 0
        Application.DisplayAlerts = True

        Set wsResult = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
        wsResult.Name = "异常设备报告"

        ' 在结果表创建标题
        With wsResult
            .Range("A1").Value = "设备编号"
            .Range("B1").Value = "使用员工数量"
            .Range("C1").Value = "使用员工名单及打卡次数"
            .Range("D1").Value = "设备持有人"
            .Range("E1").Value = "代打卡员工"
            .Range("A1:E1").Font.Bold = True
            .Columns("A:E").AutoFit
        End With

        outputRow = 2 '从第 2 行开始输出结果' 创建字典对象来存储数据
        Set dict = CreateObject("Scripting.Dictionary")

        ' 找出源数据的最后一行 (使用 P 列确定行数)
        lastRow = wsSource.Cells(wsSource.Rows.Count, "P").End(xlUp).Row

        ' 检查是否有数据
        If lastRow < 2 Then
            wsResult.Cells(2, 1).Value = "源数据表中没有找到有效数据。"
            wsResult.Columns("A:E").AutoFit
            wsResult.Activate
            Exit Sub
        End If

        ' 遍历所有数据行 (假设第 1 行是标题，从第 2 行开始)
        For i = 2 To lastRow
            On Error Resume Next ' 防止类型转换错误
            deviceID = Trim(CStr(wsSource.Cells(i, "P").Value)) ' P 列是设备号
            employeeName = Trim(CStr(wsSource.Cells(i, "A").Value)) ' A 列是员工姓名
            On Error GoTo 0

            ' 跳过空设备号或空姓名的行
            If deviceID = ""Or employeeName ="" Then GoTo NextRow

            ' 如果字典中没有这个设备号，则添加一个新字典
            If Not dict.Exists(deviceID) Then
                dict.Add deviceID, CreateObject("Scripting.Dictionary")
            End If

            ' 如果该设备号的字典中没有这个员工，则添加并初始化计数为 1
            If Not dict(deviceID).Exists(employeeName) Then
                dict(deviceID).Add employeeName, 1
            Else
                ' 如果已存在，则计数加 1
                dict(deviceID)(employeeName) = dict(deviceID)(employeeName) + 1
            End If

    NextRow:
        Next i

        ' 遍历字典，找出使用员工数 > 1 的设备
        For Each key In dict.Keys
            If dict(key).Count > 1 Then
                ' 输出到结果表
                wsResult.Cells(outputRow, 1).Value = key ' 设备号
                wsResult.Cells(outputRow, 2).Value = dict(key).Count '员工数量' 将员工姓名和打卡次数集合连接成一个字符串
                nameList = ""
                For Each empKey In dict(key).Keys
                    nameList = nameList & empKey & "(" & dict(key)(empKey) & "次 ),"
                Next empKey

                ' 去掉最后一个逗号和空格
                If Len(nameList) > 0 Then
                    nameList = Left(nameList, Len(nameList) - 2)
                End If

                wsResult.Cells(outputRow, 3).Value = nameList '员工名单及打卡次数' 新增功能：识别设备持有人和代打卡员工
                Dim maxCount As Long
                Dim holder As String
                Dim proxyEmployees As String

                ' 找出打卡次数最多的员工
                maxCount = 0
                holder = ""
                For Each empKey In dict(key).Keys
                    If dict(key)(empKey) > maxCount Then
                        maxCount = dict(key)(empKey)
                        holder = empKey
                    End If
                Next

                ' 构建代打卡员工名单（包含打卡次数）proxyEmployees = ""
                For Each empKey In dict(key).Keys
                    If empKey <> holder Then
                        proxyEmployees = proxyEmployees & empKey & "(" & dict(key)(empKey) & "次 ),"
                    End If
                Next

                ' 去掉最后一个逗号和空格
                If Len(proxyEmployees) > 0 Then
                    proxyEmployees = Left(proxyEmployees, Len(proxyEmployees) - 2)
                End If

                ' 写入持有人和代打卡员工信息
                wsResult.Cells(outputRow, 4).Value = holder & "(" & maxCount & "次)"
                wsResult.Cells(outputRow, 5).Value = proxyEmployees

                outputRow = outputRow + 1
            End If
        Next key

        ' 如果没有找到异常设备，提示用户
        If outputRow = 2 Then
            wsResult.Cells(2, 1).Value = "未发现一个设备对应多个员工的情况。"
        Else
            ' 对结果表进行排序（按员工数量降序）With wsResult
                If outputRow > 2 Then
                    .Range("A1:E" & outputRow - 1).Sort Key1:=.Range("B2"), Order1:=xlDescending, Header:=xlYes
                End If
            End With
        End If

        ' 自动调整列宽
        wsResult.Columns("A:E").AutoFit
        wsResult.Activate ' 切换到结果工作表

        MsgBox "分析完成！共找到" & (outputRow - 2) & "个异常设备。结果已输出到工作表【异常设备报告】。", vbInformation
    End Sub
    ```

###  主要功能：

 * ** 数据源处理 **：从名为“原始记录”的工作表中读取数据，其中设备编号位于 P 列，
   员工姓名位于 A 列。
 * ** 数据统计 **：使用字典对象高效地统计每个设备编号对应的员工及其打卡次数。
 * ** 报告生成 **：创建一个名为“异常设备报告”的新工作表，列出所有异常设备（即被多个
   员工使用的设备），包括以下信息：
 * ** 设备编号 **：设备的唯一标识。
 * ** 使用员工数量 **：使用该设备的员工总数。
 * ** 使用员工名单及打卡次数 **：列出所有使用该设备的员工姓名及其打卡次数（例如：
   张三 (5 次), 李四 (3 次)）。
 * ** 设备持有人 **：打卡次数最多的员工（被视为主要使用者）。
 * ** 代打卡员工 **：其他使用该设备的员工（可能涉及代打卡行为）。
 * ** 排序和格式化 **：报告按员工数量降序排序，并自动调整列宽以便阅读。
 * ** 用户反馈 **：运行完成后，显示消息框提示找到的异常设备数量。

###  适用场景：

 *  企业考勤系统分析，检测异常打卡行为。
 *  设备使用审计，确保设备分配合规。
 *  人力资源或安全管理，防止代打卡或未授权设备使用。

###  如何使用：

 1.  确保 Excel 工作簿中有一个名为“原始记录”的工作表，且包含员工姓名（A 列）和设备编号（
    P 列）数据。
 2.  在 Excel 中运行此宏（通过 VBA 编辑器或按钮触发）。
 3.  宏将自动生成“异常设备报告”工作表，并提供分析结果。

## Excel VBA 审计钉钉原始打卡记录(优化版代码)

- Link: https://blog.guohao.asia/excel-vba-%e5%ae%a1%e8%ae%a1%e9%92%89%e9%92%89%e5%8e%9f%e5%a7%8b%e6%89%93%e5%8d%a1%e8%ae%b0%e5%bd%95%e4%bc%98%e5%8c%96%e7%89%88%e4%bb%a3%e7%a0%81.html
- Published: 2025-08-29T11:45:14+08:00
- Author: null

```language-default
    Sub FindMultiUserDevicesWithCount()
        ' 声明变量
        Dim wsSource As Worksheet, wsResult As Worksheet
        Dim dict As Object ' 用于存储设备号和对应的员工集合
        Dim lastRow As Long, i As Long
        Dim deviceID As String, employeeName As String
        Dim key As Variant, empKey As Variant
        Dim outputRow As Long
        Dim nameList As String

        ' 设置源数据工作表 (假设数据在原始记录)
        On Error Resume Next
        Set wsSource = ThisWorkbook.Worksheets("原始记录")
        On Error GoTo 0

        If wsSource Is Nothing Then
            MsgBox "找不到工作表' 原始记录 '，请修改代码中的工作表名称。", vbExclamation
            Exit Sub
        End If

        ' 创建或清空结果工作表
        Application.DisplayAlerts = False
        On Error Resume Next
        ThisWorkbook.Worksheets("异常设备报告").Delete
        On Error GoTo 0
        Application.DisplayAlerts = True

        Set wsResult = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
        wsResult.Name = "异常设备报告"

        ' 在结果表创建标题
        With wsResult
            .Range("A1").Value = "设备编号"
            .Range("B1").Value = "使用员工数量"
            .Range("C1").Value = "使用员工名单及打卡次数"
            .Range("A1:C1").Font.Bold = True
            .Columns("A:C").AutoFit
        End With

        outputRow = 2 '从第 2 行开始输出结果' 创建字典对象来存储数据
        Set dict = CreateObject("Scripting.Dictionary")

        ' 找出源数据的最后一行 (使用 P 列确定行数)
        lastRow = wsSource.Cells(wsSource.Rows.Count, "P").End(xlUp).Row

        ' 检查是否有数据
        If lastRow < 2 Then
            wsResult.Cells(2, 1).Value = "源数据表中没有找到有效数据。"
            wsResult.Columns("A:C").AutoFit
            wsResult.Activate
            Exit Sub
        End If

        ' 遍历所有数据行 (假设第 1 行是标题，从第 2 行开始)
        For i = 2 To lastRow
            On Error Resume Next ' 防止类型转换错误
            deviceID = Trim(CStr(wsSource.Cells(i, "P").Value)) ' P 列是设备号
            employeeName = Trim(CStr(wsSource.Cells(i, "A").Value)) ' A 列是员工姓名
            On Error GoTo 0

            ' 跳过空设备号或空姓名的行
            If deviceID = ""Or employeeName ="" Then GoTo NextRow

            ' 如果字典中没有这个设备号，则添加一个新字典
            If Not dict.Exists(deviceID) Then
                dict.Add deviceID, CreateObject("Scripting.Dictionary")
            End If

            ' 如果该设备号的字典中没有这个员工，则添加并初始化计数为 1
            If Not dict(deviceID).Exists(employeeName) Then
                dict(deviceID).Add employeeName, 1
            Else
                ' 如果已存在，则计数加 1
                dict(deviceID)(employeeName) = dict(deviceID)(employeeName) + 1
            End If

    NextRow:
        Next i

        ' 遍历字典，找出使用员工数 > 1 的设备
        For Each key In dict.Keys
            If dict(key).Count > 1 Then
                ' 输出到结果表
                wsResult.Cells(outputRow, 1).Value = key ' 设备号
                wsResult.Cells(outputRow, 2).Value = dict(key).Count '员工数量' 将员工姓名和打卡次数集合连接成一个字符串
                nameList = ""
                For Each empKey In dict(key).Keys
                    nameList = nameList & empKey & "(" & dict(key)(empKey) & "次 ),"
                Next empKey

                ' 去掉最后一个逗号和空格
                If Len(nameList) > 0 Then
                    nameList = Left(nameList, Len(nameList) - 2)
                End If

                wsResult.Cells(outputRow, 3).Value = nameList ' 员工名单及打卡次数
                outputRow = outputRow + 1
            End If
        Next key

        ' 如果没有找到异常设备，提示用户
        If outputRow = 2 Then
            wsResult.Cells(2, 1).Value = "未发现一个设备对应多个员工的情况。"
        Else
            ' 对结果表进行排序（按员工数量降序）With wsResult
                If outputRow > 2 Then
                    .Range("A1:C" & outputRow - 1).Sort Key1:=.Range("B2"), Order1:=xlDescending, Header:=xlYes
                End If
            End With
        End If

        ' 自动调整列宽
        wsResult.Columns("A:C").AutoFit
        wsResult.Activate ' 切换到结果工作表

        MsgBox "分析完成！共找到" & (outputRow - 2) & "个异常设备。结果已输出到工作表【异常设备报告】。", vbInformation
    End Sub
    ```
