This commit is contained in:
gr
2026-09-24 09:45:44 +08:00
parent dbf474ddd7
commit bd22e5f476
38 changed files with 19152 additions and 0 deletions
+562
View File
@@ -0,0 +1,562 @@
<?php
/**
* AI 数据目录人工审核:数据统计(stats.*)、一诊(firstvisit.*)、企业微信(qywx.*)。
* 字段说明见同目录 README.md。
*
* 审核要点:
* - 统计类接口大多由 Logic 自带 ($params, $adminId, $adminInfo) 并在内部按 DataScopeService 收窄,
* MCP 以同一账号身份调用原控制器,范围与后台页面一致;所有资源都写了 params_allow(白名单),
* 未列出的参数(如 admin_id 别名、ranges、include_filters、_t 等)一律拒绝。
* - perm:以下子接口在原代码里就绑定到页面权限(控制器 hasPagePermission() 或 AuthMiddleware 别名),
* 菜单里没有单独的权限点,这里把 MCP 权限点指向同一个页面权限,避免“永远未登记”:
* firstvisit.conversion/fansDetail → ConversionController::hasPagePermission()(firstvisit.conversion/overview)
* firstvisit.myPatient/orders|progress|assistants|orderDetail → MyPatientController::hasPagePermission()(firstvisit.myPatient/lists)
* firstvisit.wecomPromotion/customerStatistics → AuthMiddleware 获客助手整组绑定 + QywxPromotionOperatorAccess::PAGE_PERMISSION
* stats.selfInput/mediaSourceOptions → AuthMiddleware::matchPermissionAlias(复用自录转化统计/账户消耗列表权限)
* - 末尾几条是扫描误判为 write 的 GET 接口(confirm/sync/upload 等前缀),给出准确结论。
*/
$dateRange = [
'start_date' => '开始日期 YYYY-MM-DD(不传默认今天)',
'end_date' => '结束日期 YYYY-MM-DD(不传同开始日期)',
];
$yejiFilter = [
'dept_ids' => '展示部门ID,多个用逗号分隔;选父部门会展开为其下级部门行(取值见 stats.yejiStats/deptOptions);不传=默认全部“中心”',
'channel_code' => '渠道编码(取值见 stats.yejiStats/channelOptions,如 tag_xxx);不传=不限渠道',
];
$yejiScopeNote = '按当前账号数据范围收窄(受限账号只统计可见员工,部门/医助超出范围时返回空并在 note 说明)。';
return [
// ───────────────────────────── 数据统计 stats.* ─────────────────────────────
'stats.assistantPerformance/overview' => [
'status' => 'open', 'kind' => 'report', 'name' => '医助个人业绩',
'note' => '只统计当前账号本人创建、履约已完成(fulfillment_status=3)且关联诊单的处方业务订单,按订单创建时间;week=最近7天、month=最近30天(均含今天)。',
'params_allow' => [
'time_type' => '时间范围:today 今日 / yesterday 昨日 / week 最近7天 / month 最近30天(默认)/ custom 自定义',
'start_date' => '自定义开始日期 YYYY-MM-DD(time_type=custom 时必填)',
'end_date' => '自定义结束日期 YYYY-MM-DD(time_type=custom 时必填)',
],
],
'stats.autoAssignLog/lists' => [
'status' => 'open', 'kind' => 'list', 'name' => '待分配诊单自动指派日志',
'note' => '后台本身不按数据范围过滤:拥有该权限的账号可看到全部自动指派日志(含患者姓名、手机号快照)。数据由定时任务 tcm:auto-assign-pending 写入,每条待指派诊单一行;action 1=已分配、0=未分配,tier 为医助上月二诊复诊接诊率档位(gt70/60_70/50_60),reason 为分配或不分配原因。',
'params_allow' => [
'run_date' => '执行日期 YYYY-MM-DD(精确匹配)',
'start_date' => '执行日期起 YYYY-MM-DD',
'end_date' => '执行日期止 YYYY-MM-DD',
'start_time' => '记录时间起 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss',
'end_time' => '记录时间止 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss',
'action' => '结果:1 已分配、0 未分配',
'assistant_id' => '分得的医助(后台账号)ID',
'batch_no' => '执行批次号',
'stat_month' => '接诊率统计月份 YYYY-MM',
'keyword' => '患者姓名/手机号/医助姓名模糊匹配;纯数字时同时匹配诊单ID',
'is_rollback' => '是否已回退:1 已回退、0 未回退',
],
],
'stats.commissionSettlement/channelOptions' => [
'status' => 'open', 'kind' => 'report', 'name' => '提成结算 · 渠道选项',
'note' => '启用中的投放渠道(企微标签渠道),按来源分组,供 channel_code 参数取值;不含客户数。',
'params_allow' => [],
],
'stats.commissionSettlement/deptOptions' => [
'status' => 'open', 'kind' => 'report', 'name' => '提成结算 · 部门选项',
'note' => '按当前账号数据范围收窄的部门列表(id、name、pid、完整路径),供 dept_ids 参数取值。',
'params_allow' => [],
],
'stats.commissionSettlement/orderLines' => [
'status' => 'pending', 'kind' => 'report', 'name' => '提成结算 · 核对明细',
'reason' => '明细会对库内缺少签收时间的订单实时调用快递100查询物流并回写轨迹(ExpressTrackingService::syncSignUnixFromLogisticsForPrescriptionOrder,外部接口 + 写库),只读事务下会失败;需提供不回查快递的只读模式后再开放',
],
'stats.commissionSettlement/overview' => [
'status' => 'open', 'kind' => 'report', 'name' => '提成结算业绩汇总',
'note' => 'settlement_month 必填。默认订单池=结算月的上一个自然月创建、履约已完成(默认 fulfillment_status=3)、默认仅系统代开处方的业务订单;签收时间与尾款支付时间均不晚于结算月 7 日 23:59:59 计入“本期提成”,否则“顺延下期”;上期确定业绩时顺延的订单并入本期。传 start_time+end_time 时订单池改为与处方订单列表一致的创建时间段(默认含手动开方)。业绩归属订单创建人,只统计当前账号数据范围内可见医助;签收时间仅用库内物流数据推导,不实时查快递。返回部门/医助/医生三个维度及确认状态 confirm(confirm 按“结算月+渠道+部门筛选”共享,其中 totals_json 是确定人确定时的合计快照,不随查看人的数据范围变化,与后台一致)。',
'params_allow' => [
'settlement_month' => '结算月 YYYY-MM(必填),如 2026-09 表示结算 8 月创建的订单',
'start_time' => '订单创建时间起 YYYY-MM-DD HH:mm:ss(与 end_time 同时传才生效)',
'end_time' => '订单创建时间止 YYYY-MM-DD HH:mm:ss',
'fulfillment_status' => '履约状态,默认 3(已完成)',
'require_system_auto_prescription' => '仅在传 start_time/end_time 时有效:1=只统计系统代开处方',
'dept_ids' => '展示部门ID,多个用逗号分隔(取值见 stats.commissionSettlement/deptOptions)',
'channel_code' => '渠道编码(取值见 stats.commissionSettlement/channelOptions)',
],
],
'stats.conversion/overview' => [
'status' => 'open', 'kind' => 'report', 'name' => '综合转化统计',
'note' => '按当前账号数据范围(可见员工)统计加粉、预约、面诊、成交单数与金额、投放成本(按加粉占比分摊)及各转化率;dimension=dept 返回部门树(include_members=1 时含成员行),assistant/doctor 返回按人统计。time_type:week=最近7天、month=最近30天。结果 lists 为当前页,summary/charts 为汇总。',
'params_allow' => [
'time_type' => '时间范围:today(默认)/ yesterday / week 最近7天 / month 最近30天 / custom 自定义',
'start_date' => '自定义开始日期 YYYY-MM-DD(time_type=custom 时)',
'end_date' => '自定义结束日期 YYYY-MM-DD(time_type=custom 时)',
'dimension' => '统计维度:dept 部门(默认)/ assistant 医助 / doctor 医生',
'dept_id' => '只看某部门(含下级)',
'assistant_id' => '只看某医助(dimension=assistant 时)',
'doctor_id' => '只看某医生(dimension=doctor 时)',
'media_channel_code' => '媒体渠道编码(企微标签渠道)',
'include_members' => '部门维度是否附带成员行:1 是(默认)、0 否',
'page_no' => '页码,默认 1',
'page_size' => '每页条数,默认 15,最大 100',
],
],
'stats.doctorDailyStats/overview' => [
'status' => 'open', 'kind' => 'report', 'name' => '医生日统计',
'note' => '按医生汇总:系统/手动开方数(处方日期)、成交业务订单数与金额(订单创建时间,剔除已取消/拒收/退款)、挂号总数/已完成/过号/取消与挂号率(=成交单数÷总挂号,按预约日期)。医生列表按当前账号数据范围收窄;传 dept_ids 时只统计该部门医助经手的数据并隐藏全 0 医生。未传日期默认今天。',
'params_allow' => $dateRange + $yejiFilter + [
'doctor_id' => '只看某位医生(后台账号ID)',
],
],
'stats.performanceDashboard/overview' => [
'status' => 'open', 'kind' => 'report', 'name' => '数据驾驶舱',
'note' => '首页驾驶舱,服务端按角色收窄:医助=本人、组长=本小组、经理=本部门及下级、管理员=全部;业绩按业务订单创建时间与创建人统计(剔除已取消/拒收/退款),挂号=支付时间内已支付且 0<实收<10 元的订单,预约按预约日期;本月业绩与上月同期比较,趋势固定最近 7 天;排行榜按一中心/二中心规则。',
'params_allow' => [
'ranking_dept_id' => '排行榜部门ID(只能选返回的 filters.ranking_departments 中的部门,否则忽略)',
],
],
// 逐条校验:PersonalAccountCostController::detail() → PersonalAccountCostLogic::detail() → PersonalStatsScopeTrait::assertRecordVisible()(录入人不在可见范围时返回“记录不存在或无权查看”)
'stats.personalAccountCost/detail' => [
'status' => 'open', 'kind' => 'detail', 'guard' => 'builtin', 'name' => '账户消耗录入 · 详情',
'note' => '单条账户消耗录入记录;录入人须在当前账号可见范围内。',
'params_allow' => ['id' => '账户消耗记录ID'],
],
'stats.personalAccountCost/lists' => [
'status' => 'open', 'kind' => 'list', 'name' => '账户消耗录入',
'note' => '员工自录的投放账户消耗,按当前账号数据范围(录入人)过滤;extend.total_amount 为筛选结果金额合计,extend.days_count 为天数。',
'params_allow' => [
'start_date' => '消耗日期起 YYYY-MM-DD',
'end_date' => '消耗日期止 YYYY-MM-DD',
'media_source' => '自媒体来源(精确匹配,取值见 stats.selfInput/mediaSourceOptions)',
'creator_name' => '录入人姓名(模糊)',
'remark' => '备注(模糊)',
'dept_id' => '录入人所在部门ID(含下级)',
],
],
// 逐条校验:PersonalYejiController::detail() → PersonalYejiLogic::detail() → PersonalStatsScopeTrait::assertRecordVisible()
'stats.personalYeji/detail' => [
'status' => 'open', 'kind' => 'detail', 'guard' => 'builtin', 'name' => '员工自录业绩 · 详情',
'note' => '单条员工自录业绩记录;录入人须在当前账号可见范围内。',
'params_allow' => ['id' => '自录业绩记录ID'],
],
'stats.personalYeji/lists' => [
'status' => 'open', 'kind' => 'list', 'name' => '员工自录业绩',
'note' => '员工每日自录的加粉、开口、预约、面诊、成交等数据,按当前账号数据范围(录入人)过滤。',
'params_allow' => [
'start_date' => '业绩日期起 YYYY-MM-DD',
'end_date' => '业绩日期止 YYYY-MM-DD',
'media_source' => '自媒体来源(精确匹配,取值见 stats.selfInput/mediaSourceOptions)',
'creator_name' => '录入人姓名(模糊)',
'creator_id' => '录入人(后台账号)ID',
'remark' => '备注(模糊)',
'dept_id' => '录入人所在部门ID(含下级)',
],
],
'stats.revisitRate/assignLines' => [
'status' => 'open', 'kind' => 'report', 'name' => '复诊接诊率 · 被指派明细',
'note' => '后台本身不按数据范围过滤:拥有该权限的账号可看到二中心全部医助当月被指派的诊单(含患者姓名、手机号)。口径:按指派操作时间落月、非继承指派、医助×诊单去重,剔除名下有拒收/退款订单的诊单;仅统计二中心及其下级部门。不传 assistant_id/dept_id 时返回全部。',
'params_allow' => [
'month' => '统计月份 YYYY-MM(默认本月)',
'dept_ids' => '部门筛选(限二中心子树),多个逗号分隔',
'assistant_id' => '只看某医助',
'dept_id' => '只看某部门分组(0=未分配部门)',
],
],
'stats.revisitRate/deptOptions' => [
'status' => 'open', 'kind' => 'report', 'name' => '复诊接诊率 · 部门选项',
'note' => '二中心及其下级部门(id、pid、name),供 dept_ids 参数取值。',
'params_allow' => [],
],
'stats.revisitRate/overview' => [
'status' => 'open', 'kind' => 'report', 'name' => '复诊接诊率',
'note' => '后台本身不按数据范围过滤:拥有该权限的账号可看到二中心全部医助的数据。口径:当月被指派数=当月非继承指派的医助×诊单(剔除名下有拒收/退款订单的诊单);N 诊单数=当月下单且为该诊单全局第 N 笔计入业绩的业务订单(剔除取消/拒收/退款,诊次跨月累计),归属下单时的持有医助;N 诊接诊率=N 诊单数÷当月被指派数(往月指派当月成交会使比率超过 100%)。按部门→医助分组并有合计行。',
'params_allow' => [
'month' => '统计月份 YYYY-MM(默认本月)',
'dept_ids' => '部门筛选(限二中心子树,含下级),多个逗号分隔',
],
],
'stats.revisitRate/visitOrderLines' => [
'status' => 'open', 'kind' => 'report', 'name' => '复诊接诊率 · N 诊订单明细',
'note' => '后台本身不按数据范围过滤:拥有该权限的账号可看到二中心全部医助的 N 诊订单(含订单号、金额、患者姓名、手机号)。与复诊接诊率“N 诊单数”同口径,可对账。',
'params_allow' => [
'month' => '统计月份 YYYY-MM(默认本月)',
'slot' => '诊次 N(必填,2=二诊,最大 50)',
'dept_ids' => '部门筛选(限二中心子树),多个逗号分隔',
'assistant_id' => '只看某医助',
'dept_id' => '只看某部门分组(0=未分配部门)',
],
],
'stats.selfInput/mediaSourceOptions' => [
'status' => 'open', 'kind' => 'report', 'name' => '自媒体来源选项',
'perm' => 'stats.selfInput/overview',
'note' => '字典“推广渠道”(channels)中启用的来源名称,供 media_source 参数取值。',
'params_allow' => [],
],
'stats.selfInput/overview' => [
'status' => 'open', 'kind' => 'report', 'name' => '自录转化统计',
'note' => '基于员工自录业绩与账户消耗:按录入人数据范围过滤(配置 self_input_stats_view_all_roles 的角色可见全部);没有财务可见权限时不返回账户消耗、现金成本、ROI。time_type:week=最近7天、month=最近30天。lists 为当前页明细,summary 为筛选范围合计。',
'params_allow' => [
'time_type' => '时间范围:today(默认)/ yesterday / week 最近7天 / month 最近30天 / custom 自定义',
'start_date' => '自定义开始日期 YYYY-MM-DD(time_type=custom 时)',
'end_date' => '自定义结束日期 YYYY-MM-DD(time_type=custom 时)',
'media_source' => '自媒体来源(精确匹配,取值见 stats.selfInput/mediaSourceOptions)',
'dept_id' => '录入人所在部门ID(含下级)',
'page_no' => '页码,默认 1',
'page_size' => '每页条数,默认 15,最大 100',
],
],
'stats.yejiStats/appointmentLines' => [
'status' => 'open', 'kind' => 'report', 'name' => '业绩看板 · 预约挂号明细',
'note' => '与业绩看板/医助排行榜“预约诊单”同口径的逐条挂号:预约日期在区间内,状态为已预约/已完成/已过号(不含已取消)。传 assistant_id 看某医助,或传 dept_id 看某部门行(二选一)。' . $yejiScopeNote,
'params_allow' => $dateRange + $yejiFilter + [
'assistant_id' => '医助ID(排行榜行)',
'dept_id' => '部门行ID(看板部门行,0=未归属中心)',
'page' => '页码,默认 1',
'page_size' => '每页条数,默认 20,最大 100',
],
],
'stats.yejiStats/assignLines' => [
'status' => 'open', 'kind' => 'report', 'name' => '业绩看板 · 被指派明细',
'note' => '与业绩看板“被指派数”同口径:区间内非继承的成功指派,按指派操作时间落区间,医助×诊单去重,剔除已删诊单。传 assistant_id 或 dept_id(二选一)。' . $yejiScopeNote,
'params_allow' => $dateRange + $yejiFilter + [
'assistant_id' => '医助ID(排行榜行)',
'dept_id' => '部门行ID(看板部门行)',
'page' => '页码,默认 1',
'page_size' => '每页条数,默认 20,最大 100',
],
],
'stats.yejiStats/channelOptions' => [
'status' => 'open', 'kind' => 'report', 'name' => '业绩看板 · 渠道选项',
'note' => '启用中的投放渠道(企微标签渠道),按来源分组,附带打了该标签的客户数;供 channel_code 参数取值。',
'params_allow' => [],
],
'stats.yejiStats/deptOptions' => [
'status' => 'open', 'kind' => 'report', 'name' => '业绩看板 · 部门选项',
'note' => '按当前账号数据范围收窄的部门列表(id、name、pid、完整路径),供 dept_ids 参数取值。',
'params_allow' => [],
],
'stats.yejiStats/leadLines' => [
'status' => 'open', 'kind' => 'report', 'name' => '业绩看板 · 进线明细',
'note' => '与业绩看板“进线数据”同口径:企业微信添加客户事件(add_external_contact)逐条,按接待员工归属部门行;选渠道时只含带该标签的客户。dept_id 必填(看板部门行)。' . $yejiScopeNote,
'params_allow' => $dateRange + $yejiFilter + [
'dept_id' => '部门行ID(必填)',
'page' => '页码,默认 1',
'page_size' => '每页条数,默认 20,最大 100',
],
],
'stats.yejiStats/leaderboard' => [
'status' => 'open', 'kind' => 'report', 'name' => '业绩看板 · 医助排行榜',
'note' => '按展示部门分表的医助排行:诊金=订单创建人为该医助的业务订单金额(剔除取消/拒收/退款),另有进线、被指派、接诊、成交单、预约诊单、接诊率(元/进线);二中心医助附复诊分项。结果 range_note 有完整口径。' . $yejiScopeNote,
'params_allow' => $dateRange + $yejiFilter,
],
'stats.yejiStats/multi' => [
'status' => 'open', 'kind' => 'report', 'name' => '业绩看板 · 多区间',
'note' => '一次返回本月(1 日至今天)、本周(周一至今天)、今日、昨日四个区间的业绩看板,每个区间与 stats.yejiStats/overview 相同;不支持自定义区间(请用 overview)。' . $yejiScopeNote,
'params_allow' => $yejiFilter,
],
'stats.yejiStats/overview' => [
'status' => 'open', 'kind' => 'report', 'name' => '业绩看板',
'note' => '部门×日期区间:进线=企微添加客户事件(按接待员工部门);被指派数=区间内非继承指派(医助×诊单去重);已完成挂号按预约日期;接诊诊单/成交单数=计入业绩的业务订单条数;合计业绩=业务订单金额,按订单创建时间、剔除已取消(4)/拒收(9)/退款(10),按订单创建人部门归属;投放成本按进线占比分摊,ROI=业绩÷投放成本;复诊只统计二中心。受数据范围限制的账号不显示“未归属中心”行,底栏合计=表内各行之和。结果 channel_filter_note 有完整口径。',
'params_allow' => $dateRange + $yejiFilter,
],
'stats.yejiStats/revisitBreakdown' => [
'status' => 'open', 'kind' => 'report', 'name' => '业绩看板 · 二中心复诊拆解',
'note' => '二中心部门行的复诊业务订单按医助拆解(订单创建人归属);与看板“复诊”列同口径。' . $yejiScopeNote,
'params_allow' => $dateRange + $yejiFilter + [
'dept_id' => '部门行ID(必填,须为二中心子树内的展示行)',
'revisit_slot' => '复诊分项:0=复诊合计(默认),2=复诊2,3=复诊3……',
],
],
'stats.yejiStats/unassignedBreakdown' => [
'status' => 'open', 'kind' => 'report', 'name' => '业绩看板 · 未归属中心拆解',
'note' => '业绩看板“未归属中心”补差按订单创建人拆解(创建人部门无法映射到任何展示中心);受限账号只列可见医助,但 admin_id=0 行(无创建人/无诊单的全站金额)与后台页面一致会显示。',
'params_allow' => $dateRange + [
'dept_ids' => '展示部门ID,多个用逗号分隔(与看板一致)',
],
],
// ───────────────────────────── 一诊 firstvisit.* ─────────────────────────────
'firstvisit.conversion/fansDetail' => [
'status' => 'open', 'kind' => 'list', 'name' => '综合数据转化 · 加粉明细',
'perm' => 'firstvisit.conversion/overview',
'note' => '先查 firstvisit.conversion/overview,再用其中一行作为实体:部门行 entity_type=dept、entity_id=部门ID;成员行 entity_type=member、entity_id=该行 id(形如 M{员工ID}_{部门ID})。实体须在当前账号数据范围内,否则返回空;时间与筛选参数应与总览一致。external_userid 为企微客户标识。',
'params_allow' => [
'entity_type' => '实体类型(必填):dept 部门行 / member 成员行',
'entity_id' => '实体ID(必填):部门ID,或成员行 id(M{员工ID}_{部门ID})',
'time_type' => '时间范围:today(默认)/ yesterday / week 本周 / month 本月 / quarter 本季度 / year 本年 / custom',
'start_date' => '自定义开始日期 YYYY-MM-DD(time_type=custom 时)',
'end_date' => '自定义结束日期 YYYY-MM-DD(time_type=custom 时)',
'dept_id' => '部门筛选(与总览一致)',
'assistant_id' => '员工筛选(与总览一致)',
'media_channel_code' => '企微标签渠道编码(与总览一致)',
],
],
'firstvisit.conversion/overview' => [
'status' => 'open', 'kind' => 'report', 'name' => '一诊综合数据转化',
'note' => '按当前账号数据范围与所选部门/员工取交集:加粉、预约(按预约日期,含已预约/已完成/已过号)、挂号(支付时间内已支付且 0<实收<10 元的订单)、面诊、成交与业绩(业务订单创建时间与创建人,剔除取消/拒收/退款及发生退款的订单),开口数来自个人业绩录入;没有“查看现金成本与ROI”权限时不返回账户消耗、现金成本、ROI。time_type:week=本周(周一起)、month=本月、quarter=本季度、year=本年。',
'params_allow' => [
'time_type' => '时间范围:today(默认)/ yesterday / week 本周 / month 本月 / quarter 本季度 / year 本年 / custom',
'start_date' => '自定义开始日期 YYYY-MM-DD(time_type=custom 时)',
'end_date' => '自定义结束日期 YYYY-MM-DD(time_type=custom 时)',
'dept_id' => '部门ID(只能收窄在数据范围内)',
'assistant_id' => '员工ID(只能收窄在数据范围内)',
'media_channel_code' => '企微标签渠道编码(取值见返回的 filters.media_channels)',
],
],
'firstvisit.doctorDashboard/overview' => [
'status' => 'open', 'kind' => 'report', 'name' => '一诊医生看板',
'note' => '以医生为展示维度:医生本人(仅本人数据范围)只看自己;医助/组长/经理只看数据范围内医助经手患者关联的医生数据;管理员看全部。预约含已预约/已取消/已完成/已过号,面诊=已完成预约;业绩按订单创建时间,排除取消/拒收/全额及部分退款,金额归属开方医生;挂号按支付时间统计 0<实收<10 元的已支付订单。time_type:week=本周、month=本月(默认)。',
'params_allow' => [
'time_type' => '时间范围:today / yesterday / week 本周 / month 本月(默认)/ custom',
'start_date' => '自定义开始日期 YYYY-MM-DD(time_type=custom 时)',
'end_date' => '自定义结束日期 YYYY-MM-DD(time_type=custom 时)',
'dept_id' => '部门ID(只能收窄在数据范围内)',
'doctor_id' => '只看某位医生',
'active_only' => '只含在职医生:1 是(默认)、0 否',
'alert_threshold' => '预警阈值(接诊转化率 %,1~100,默认 15)',
],
],
'firstvisit.myPatient/assistants' => [
'status' => 'open', 'kind' => 'report', 'name' => '我的患者 · 可指派医助',
'perm' => 'firstvisit.myPatient/lists',
'note' => '当前账号数据范围内的在职医助(ID、姓名、账号、部门)。后台还要求账号有诊单“指派”权限 tcm.diagnosis/assign,否则返回权限不足。',
'params_allow' => [],
],
'firstvisit.myPatient/lists' => [
'status' => 'open', 'kind' => 'list', 'name' => '我的患者',
'note' => '范围由 MyPatientLogic::applyScope 决定:医生=本人接诊过(有效挂号)的患者,医助=本人负责的患者,经理/诊室组长等按数据范围,root 看全部。后台已脱敏手机号(phone_masked),不返回身份证号(仅 has_id_card)。按下次预约时间排序;extend.summary 为今天/明天/后天的预约人数。',
'params_allow' => [
'keyword' => '患者姓名/手机号/医助姓名/接诊医生姓名(模糊)',
'status_filter' => '预约状态:unbooked 未预约 / pending_interview 待面诊 / completed 已完成 / missed 已过号',
'start_date' => '预约日期起 YYYY-MM-DD',
'end_date' => '预约日期止 YYYY-MM-DD',
],
],
// 逐条校验:MyPatientController::orderDetail() 先调 guardOrder()(页面权限 + tcm.prescriptionOrder/detail 权限 + MyPatientLogic::canAccessDiagnosis() 校验订单所属患者在“我的患者”范围内),
// 再由 PrescriptionOrderLogic::detail() → canAccessOrder() 二次校验;外部调用标记是 PharmacySubmissionClaimService 名称误匹配,实际只读本地表。
'firstvisit.myPatient/orderDetail' => [
'status' => 'open', 'kind' => 'detail', 'guard' => 'builtin', 'name' => '我的患者 · 订单详情',
'perm' => 'firstvisit.myPatient/lists',
'note' => '处方业务订单详情(含处方、关联支付单、挂号摘要);订单须属于当前账号“我的患者”范围,且账号需有处方订单详情权限 tcm.prescriptionOrder/detail;无药材明细权限时不返回药材。',
'params_allow' => ['id' => '处方业务订单ID'],
],
'firstvisit.myPatient/orders' => [
'status' => 'open', 'kind' => 'list', 'name' => '我的患者 · 订单',
'perm' => 'firstvisit.myPatient/lists',
'note' => '“我的患者”范围内患者的处方业务订单(按患者范围收窄,不按订单创建人);手机号已由后台脱敏。extend.summary:订单数、有效金额(剔除取消/拒收/退款)、待审核数、已完成数、拒收数与拒收率。',
'params_allow' => [
'keyword' => '订单号/患者姓名/手机号/收件人(模糊);纯数字时也匹配订单ID、处方ID、诊单ID',
'prescription_audit_status' => '处方审核:0 待审核、1 已通过、2 已驳回',
'payment_slip_audit_status' => '支付单审核:0 待审核、1 已通过、2 已驳回',
'fulfillment_status' => '履约状态:1 待双审通过、2 待发货、3 已完成、4 已取消、5 已发货、6 已签收、7 进行中、8 暂不制药、9 拒收、10 退款、11 保留药方、12 制药缓发',
'start_date' => '订单创建日期起 YYYY-MM-DD',
'end_date' => '订单创建日期止 YYYY-MM-DD',
],
],
'firstvisit.myPatient/progress' => [
'status' => 'open', 'kind' => 'list', 'name' => '我的患者 · 面诊进度',
'perm' => 'firstvisit.myPatient/lists',
'note' => '“我的患者”范围内的挂号面诊进度(确认、面诊、开方、候诊排队位次);日期默认今天,跨度最长 31 天;手机号已由后台脱敏。extend 含当日排班/号源概览与未来一周排班。',
'params_allow' => [
'keyword' => '患者姓名/手机号/医生/医助姓名(模糊);纯数字时也匹配挂号ID、诊单ID',
'status' => '挂号状态:1 已预约、3 已完成、4 已过号(不传=全部有效状态)',
'start_date' => '预约日期起 YYYY-MM-DD(默认今天)',
'end_date' => '预约日期止 YYYY-MM-DD(默认同开始日期)',
],
],
'firstvisit.registrationStats/overview' => [
'status' => 'open', 'kind' => 'report', 'name' => '一诊挂号统计',
'note' => '按员工(医助)统计:挂号=支付时间内已支付且 0<实收<10 元的订单(按订单创建人);预约=预约日期内已预约/已完成/已过号(优先挂号医助,再回退诊单医助);诊单=业务订单(按创建时间与创建人,排除取消/拒收/退款)。部门与员工筛选只能在当前账号数据范围内收窄;含与上一周期对比与年度目标进度。time_type:week=本周、month=本月。',
'params_allow' => [
'time_type' => '时间范围:today(默认)/ yesterday / week 本周 / month 本月',
'dept_id' => '部门ID(只能收窄在数据范围内)',
'assistant_id' => '员工ID(只能收窄在数据范围内)',
],
],
'firstvisit.wecomPromotion/checkApiPermission' => [
'status' => 'excluded', 'name' => '企业微信获客助手 · 接口权限自检',
'reason' => '获客助手应用配置与接口权限自检,会实时调用企业微信接口,属于系统配置检测',
],
'firstvisit.wecomPromotion/customerStatistics' => [
'status' => 'open', 'kind' => 'report', 'name' => '企业微信获客助手 · 获客客户统计',
'perm' => 'firstvisit.wecomPromotion/overview',
'note' => '获客链接带来的客户及会话统计,按当前账号数据范围(承接成员/链接归属人)及被共享的分流方案收窄;external_userid 已由后台脱敏。数据来自本地同步表,不实时调用企业微信(同步需在后台手动操作)。',
'params_allow' => [
'promotion_link_id' => '本地获客链接ID',
'userid' => '承接成员的企业微信 userid',
'chat_status' => '会话状态:1 已发消息、0 未发消息、2 未知',
'keyword' => '客户标识/成员 userid/成员姓名/链接名称(模糊)',
'page_no' => '页码,默认 1',
'page_size' => '每页条数,默认 20,最大 100',
],
],
'firstvisit.wecomPromotion/overview' => [
'status' => 'excluded', 'name' => '企业微信获客助手 · 配置总览',
'reason' => '获客助手配置页:返回企业微信应用配置状态(corp_id 掩码、agent_id、回调地址)、分流方案/链接/成员配置与网页安装代码,打开时还会回填分流成员(写库);属配置管理,不对 AI 开放',
],
'firstvisit.wecomPromotion/remoteLinkDetail' => [
'status' => 'excluded', 'name' => '企业微信获客助手 · 官方链接详情',
'reason' => '实时调用企业微信获客助手接口拉取链接详情并回写本地链接记录(外部接口 + 写库),属于同步操作',
],
'firstvisit.wecomPromotion/tagOptions' => [
'status' => 'pending', 'name' => '企业微信获客助手 · 企业标签选项',
'reason' => '每次都实时调用企业微信 externalcontact/get_corp_tag_list 取企业标签(外部接口),需改为读本地标签表后再开放;标签及客户数可先用 qywx.customer/tagStats 或 stats.yejiStats/channelOptions 查询',
],
// ───────────────────────────── 企业微信 qywx.* ─────────────────────────────
'qywx.customer/getSyncSettings' => [
'status' => 'excluded', 'name' => '企业微信客户 · 同步设置',
'reason' => '企业微信客户同步设置(自动同步开关、间隔、同步状态),配置类接口不对 AI 开放',
],
'qywx.customer/lists' => [
'status' => 'open', 'kind' => 'list', 'name' => '企业微信客户',
'note' => '后台本身不按数据范围过滤:拥有该权限的账号可看到全部企业微信外部联系人(含跟进人、跟进人备注与描述、标签、添加渠道),请谨慎授权。dedupe_mode=first 按客户首次添加时间筛选(默认),any 按添加事件流水筛选(含老客被其他员工重复添加)。',
'params_allow' => [
'name' => '客户名称(模糊)',
'tag_ids' => '企业标签ID,多个用逗号分隔(命中任一;取值见 qywx.customer/tagStats)',
'follow_user' => '跟进人姓名或企业微信 userid',
'add_time_start' => '添加日期起 YYYY-MM-DD',
'add_time_end' => '添加日期止 YYYY-MM-DD',
'dedupe_mode' => '添加时间口径:first 首次添加(默认)/ any 任意一次添加事件',
'add_way' => '添加方式编号(企业微信 add_way,如 1 扫码、2 搜索手机号、16 获客链接)',
],
],
'qywx.customer/stats' => [
'status' => 'open', 'kind' => 'report', 'name' => '企业微信客户 · 统计',
'note' => '后台本身不按数据范围过滤:全公司企业微信客户总数、今日添加事件数、今日新增客户的跟进人条数、最近同步时间与状态。',
'params_allow' => [],
],
'qywx.customer/tagStats' => [
'status' => 'open', 'kind' => 'report', 'name' => '企业微信客户 · 标签统计',
'note' => '后台本身不按数据范围过滤:全公司当前有效企业标签按分组列出客户数(按客户数倒序),供 tag_ids 参数取值。',
'params_allow' => [],
],
'qywx.customer/todayArrival' => [
'status' => 'open', 'kind' => 'report', 'name' => '企业微信客户 · 今日进入分布',
'note' => '后台本身不按数据范围过滤:今日全公司添加客户事件(add_external_contact)总数、最近一条时间、按小时分布与渠道 state Top5。',
'params_allow' => [],
],
'qywx.customer/todayArrivalList' => [
'status' => 'open', 'kind' => 'report', 'name' => '企业微信客户 · 今日进入明细',
'note' => '后台本身不按数据范围过滤:今日全公司添加客户事件逐条(时间、接待员工、客户名称、渠道 state),按时间倒序分页。',
'params_allow' => [
'page_no' => '页码,默认 1',
'page_size' => '每页条数,默认 20,最大 100',
],
],
'qywx.message/archive_list' => [
'status' => 'pending', 'name' => '企业微信会话存档 · 消息记录',
'reason' => '返回会话存档原文(解密落库的员工与客户聊天内容、原始报文和媒体,可能含患者病情);后台接口不按数据范围过滤,可按任意员工/客户/群查看全部会话,且未找到对应菜单权限点(未登记时后台对任意登录账号放行);需先按本人及数据范围内员工收窄后再开放',
],
'qywx.message/customer_of_staff' => [
'status' => 'open', 'kind' => 'report', 'name' => '企业微信消息 · 员工的客户',
'note' => '后台本身不按数据范围过滤:可查询任意员工(按企业微信 userid)已添加的客户(名称、类型、性别、企业名、unionid),最多 200 条;与企业微信客户列表同源。',
'params_allow' => [
'staff_userid' => '员工企业微信 userid(必填,取值见 qywx.message/staff_list)',
'keyword' => '客户名称(模糊)',
],
],
'qywx.message/pull_archive' => [
'status' => 'excluded', 'name' => '企业微信会话存档 · 手动拉取',
'reason' => '手动触发企业微信会话存档拉取(调用会话存档 SDK、写库、可下载媒体文件),属调试/定时任务类操作',
],
'qywx.message/send_task_list' => [
'status' => 'pending', 'name' => '企业微信群发任务',
'reason' => '后台接口不按数据范围过滤,返回全部员工的群发任务(含消息内容、附件与目标客户 external_userid 列表),且未找到对应菜单权限点;需先登记权限并按创建人/员工数据范围收窄后再开放',
],
'qywx.message/session_list' => [
'status' => 'pending', 'name' => '企业微信会话存档 · 会话列表',
'reason' => '会话列表含每个会话最后一条消息摘要(聊天内容)与客户信息;后台接口不按数据范围过滤,可查看全部员工与客户的会话,且未找到对应菜单权限点;需先按本人及数据范围内员工收窄后再开放',
],
'qywx.message/staff_list' => [
'status' => 'open', 'kind' => 'report', 'name' => '企业微信消息 · 可代发员工',
'note' => '后台本身不按数据范围过滤:已绑定企业微信的全部员工(ID、姓名、企业微信 userid、部门),最多 200 条。',
'params_allow' => [
'keyword' => '员工姓名或企业微信 userid(模糊)',
],
],
// ─────────── 扫描按名称误判为写操作的 GET 接口(不在候选清单内,给出准确结论) ───────────
'stats.commissionSettlement/confirmStatus' => [
'status' => 'open', 'kind' => 'report', 'name' => '提成结算 · 核对确认状态',
'note' => '只读:当前结算月 + 渠道 + 部门筛选组合的核对/确定状态(核对备注、确定人与时间、确定时的合计快照 totals_json),与 stats.commissionSettlement/overview 返回的 confirm 相同;该状态按筛选组合共享,不随查看人数据范围变化(与后台一致)。',
'params_allow' => [
'settlement_month' => '结算月 YYYY-MM(必填)',
'dept_ids' => '展示部门ID,多个用逗号分隔(须与汇总时一致)',
'channel_code' => '渠道编码(须与汇总时一致)',
],
],
'qywx.customer/sync' => [
'status' => 'excluded', 'name' => '企业微信客户 · 同步',
'reason' => '触发后台企业微信客户全量同步进程(调用企业微信接口并写库),写操作',
],
'qywx.message/archive_status' => [
'status' => 'excluded', 'name' => '企业微信会话存档 · 模块状态',
'reason' => '会话存档模块诊断信息(SDK 路径、公钥版本、私钥是否配置),属系统配置信息',
],
'qywx.message/send_task_detail' => [
'status' => 'excluded', 'name' => '企业微信群发 · 送达详情',
'reason' => '实时调用企业微信接口查询群发送达结果并回写任务状态(外部接口 + 写库)',
],
'qywx.message/upload_to_qywx' => [
'status' => 'excluded', 'name' => '企业微信 · 上传素材',
'reason' => '上传文件到企业微信临时素材(外部接口),写操作',
],
];