在这里插入图片描述

一条派工请求进入地图检索后,页面往往很快会出现一组地点候选。真正容易被忽略的,不是如何把候选列表画出来,而是候选为什么以这个顺序出现,以及界面怎样把服务返回的相关性信息交还给调度人员判断。

以“空调维修、北京站周边、5 km 服务半径”的派工场景为例,关键词相同、中心点相同,不代表每个地点都同样适合承接当前工单。MapKit 返回的 reliability 属于候选项的一部分:它能补充检索结果与当前查询条件的关联信息,却不等同于距离、履约能力、营业状态,更不能直接替代人工派单决定。

这篇文章只解决一个问题:在服务半径检索中,怎样让 reliability 从一个容易被误读的数值,变成可以回查来源、解释选择、保留异常出口的候选字段。
在这里插入图片描述

先把“相关性”放回它应在的位置

它不是派工结论

地点检索至少会同时面对三类信息:

信息层 典型字段 回答的问题 不能回答的问题
请求条件 关键词、中心点、服务半径、语言 本轮想找什么、从哪里找、找多大范围 某个候选一定可派工
服务候选 siteId、名称、地址、坐标、reliability 地图服务返回了什么 候选已经被业务系统接受
人工决定 选中项、补录说明、派工草稿 当前人员依据什么准备继续处理 后台工单已经创建或已经派发

reliability 位于第二层。它和名称、地址一样,首先是本轮检索返回的原始字段。页面可以展示它,也可以把它连同请求条件写入候选档案;但是不能把“相关性较高”翻译成“该服务点已确认可用”。

这个区分看起来克制,却能避免一个很实际的问题:当某个候选地址更接近中心点、但当前无人员覆盖时,相关性并不能替代履约判断;当 reliability 缺省时,页面也不能通过一个自造分数把空值涂成看似完整的排序依据。

候选顺序与人工选择是两件事

页面工程按服务返回顺序保存候选,并在每一行展示序号、名称、地址和相关性。这样做不是为了暗示“第一条必然正确”,而是为了让操作者可以复述本次观察:第几轮请求、服务返回第几条、字段原值是什么、最终选择了哪一条。

一旦页面在本地再次排序,或者只保留被选中的那一项,后续就很难回答两个问题:当前人员是不是跳过了排序更靠前的候选?跳过的依据是距离、营业状态、人工电话确认,还是只是页面状态残留?地图检索是一个候选发现过程,派工才是一个业务决策过程。两者应连接,但不应混成一个状态。

空值也应该被看见

reliability 在候选模型中是可选字段。页面将缺失值展示为“未提供”,而不是使用 0100 或任意默认值。这个细节有三个作用:

  1. 它保留了服务实际返回的完整程度,读者能区分“低相关性”与“未提供相关性”。
  2. 它阻止前端在无来源的情况下生成排序理由。
  3. 它提醒操作者在选择候选时补充其他事实,例如地址、服务半径、现场电话确认或业务规则。

因此,候选字段的目标不是让列表显得更“智能”,而是让每一个显示值都有来源,每一个缺失值都有明确的解释位置。

一次检索应留下哪些可解释的记录

在这里插入图片描述

请求前先冻结本轮条件

地图检索最容易出现的误判,是用户先输入关键词、再切换半径、随后查看旧列表。为了避免这种混淆,页面每次开始检索前都会生成新的轮次,并清空旧候选、旧总数和旧的本地选择状态。

const round = this.searchRound + 1;
this.searchState = `${round} 轮请求中`;
this.searchItems = [];
this.totalCount = '等待服务响应';
this.lastOperation = `SEARCH-${round}`;
this.clearLocalDecision();

const params: site.SearchByTextParams = {
  query: this.keyword,
  location: this.center,
  radius: this.radiusMeters,
  language: 'zh-CN',
  pageIndex: 1,
  pageSize: 5
};

这段代码能说明:本地状态将一次请求绑定到一个新的轮次,且请求参数包含关键词、中心位置和服务半径。它不能说明:远端服务已经接受请求,也不能说明本轮一定会返回候选。只有后续调用成功或失败的结果,才能让状态进入下一阶段。

对调度人员而言,这个轮次不是技术装饰。它是候选档案的主键之一。若没有轮次,5 km 与 10 km 的候选会混在同一个列表里;若没有请求快照,之后看到的相关性数值也无法判断究竟对应哪个关键词和哪个范围。

调整半径意味着废弃旧候选

服务半径改变后,检索条件已经改变。页面会清空候选和总数,提示重新发起请求。此时不应继续选择旧候选,也不应把之前的 reliability 当作新范围下的判断依据。

private toggleRadius(): void {
  this.radiusMeters = this.radiusMeters === 5000 ? 10000 : 5000;
  this.searchItems = [];
  this.totalCount = '等待新半径检索';
  this.searchState = '半径已变更,等待真实检索';
  this.clearLocalDecision();
  this.refreshMapOverlays();
}

这段代码能证明:半径变化会主动失效当前候选与已选状态,地图覆盖物也会随之刷新。它不能证明:扩大半径后会增加多少结果,或某个旧候选仍然具有同样的相关性。那些结论必须等待新一轮服务返回。

返回字段要原样进入候选模型

检索完成后,页面不会只抽取名称和地址,而是保留候选序号、站点标识、名称、格式化地址、reliability 和坐标。候选序号由当前返回列表的位置生成,reliability 则直接来自服务字段。

const response = await site.searchByText(getContext(this), params);
this.searchItems = (response.sites ?? []).map((item: site.Site, index: number) => ({
  rank: index + 1,
  siteId: item.siteId,
  name: item.name ?? '未提供名称',
  address: item.formatAddress ?? '未提供地址',
  reliability: item.reliability,
  location: item.location
}));
this.totalCount = `${response.totalCount}`;

这段代码能证明:页面工程将 item.reliability 作为候选属性保留,并没有用地址、距离或页面索引替代它。它不能证明:该数值代表何种业务优先级,也不能证明候选背后的门店、人员或库存状态。

这里有一个对审阅很重要的细节:response.sites ?? [] 只保证页面在无候选时仍能正常进入空状态,它不把空数组解释成服务失败。调用成功但没有展示结果、调用异常、地图控制器未就绪,是三个不同的状态,应由不同的提示和下一步处理承接。

用字段档案代替“分数越高越好”的直觉

候选行应同时展示四个判断线索

在可派工候选列表中,每个候选至少保留以下四类线索:

字段 处理方式 对人工判断的价值 使用边界
rank 保留本轮返回顺序 能回查本条在本轮结果中的位置 不是业务优先级
siteId 原样保存 可区分同名地点,方便后续回查 不是用户可读名称
地址与坐标 分别保留 地址便于人工阅读,坐标用于地图聚焦 坐标缺失时不能虚构定位点
reliability 有值展示数值,缺失展示“未提供” 让候选与本轮查询的关联信息可见 不是履约保证、距离或最终选择

页面端有一个很小但关键的格式化方法:

private reliabilityText(value?: number): string {
  return value === undefined ? '未提供' : `${value}`;
}

这段代码能说明:字段是否存在被明确区分,且页面不会为缺失值制造默认分数。它不能说明:“未提供”意味着服务异常,更不能说明该候选没有价值。缺失字段只代表当前返回中没有这个值,选择时仍应结合名称、地址、半径和实际业务约束。

相关性应成为选择理由的一部分,而不是全部

当操作者选择一个候选时,页面会把“第几条真实候选”和“相关性原值”作为本地草稿的理由文本。它把决定的来路写出来,但不代替决定。

private selectedCandidateReason(): string {
  const selected = this.selectedCandidate();
  return selected === undefined ? '' :
    `派工依据:第 ${selected.rank} 条真实候选,相关性 ${this.reliabilityText(selected.reliability)}`;
}

这段代码能证明:选择理由引用的是本轮真实候选的序号与字段值。它不能证明:该候选最终已被派单系统接收,或相关性是唯一、充分的业务依据。

在实际使用中,可以把它和以下信息一起写入人工判断记录:

  • 工单关键词与服务半径;
  • 候选名称、地址和 siteId
  • 相关性值或“未提供”状态;
  • 是否能在地图上聚焦到返回坐标;
  • 选择或跳过该候选的人工原因。

这样,当有人质疑“为什么没有选第一条”时,记录不会只剩一句“相关性低”。它可以明确地说明:候选顺序来自本轮服务返回;人工选择还考虑了本地服务覆盖、地址匹配或其他业务条件;未被服务返回的信息不会被页面擅自补齐。

页面状态如何避免把位置画面误读成搜索结果

底图就绪不等于检索已成功

页面初始化后会创建地图控制器、画出服务中心和服务半径。这个画面能够帮助调度人员理解搜索范围,但它不能证明文本检索已经执行,也不能证明当前地图上已经存在真实候选。

地图的状态和检索的状态应分别阅读:

页面状态 它能说明什么 不能推导什么
地图控制器已就绪 地图组件已返回控制器,覆盖物可以尝试加载 检索服务已成功返回
显示服务中心与半径 当前请求将使用的空间范围可见 圈内一定有可派候选
显示候选标记 当前返回中有坐标字段的候选已被绘制 这些点已完成派工
候选已选中 人工选择了本轮的一个服务候选 后台系统已写入工单

如果一个候选没有 location,页面会保留候选本身,却不把地图中心当作它的坐标。这能避免一种特别隐蔽的错误:列表看起来已经有地址,地图也恰好显示了服务中心,于是读者误以为该候选已经被精确定位。

选择候选后才尝试地图聚焦

页面先判断当前是否有已选候选,再检查候选是否带有坐标,最后才使用地图控制器聚焦。这个顺序保证“地图没有动”也有可解释的原因。

if (selected.location === undefined) {
  this.mapFocusState = `已选择 ${selected.name},但 MapKit 未返回该候选坐标,不能定位。`;
  return;
}
if (this.mapController === undefined) {
  this.mapFocusState = `已选择 ${selected.name},地图尚未就绪,待地图初始化后重试。`;
  return;
}
this.mapController.animateCamera(map.newLatLng(selected.location, 15), 350);

这段代码能证明:页面不会在没有候选坐标或没有地图控制器时伪造聚焦成功。它不能证明:地图上看到的地点就是真实履约位置;坐标依然属于当前服务返回,而不是现场签收、人员轨迹或业务台账。

列表和地图必须共享同一轮候选

候选列表与地图标记都从 searchItems 读取。切换半径或开始新一轮检索时,该列表会先清空,因此地图上的候选标记也会消失,直到新结果回来。这种同步关系很重要:地图只展示与当前列表同源的候选,不能把上一轮标记残留在新的查询条件里。

对位置服务开发者来说,这比“地图看起来更丰富”更重要。空间画面有很强的可信感,旧标记一旦被误当成当前检索结果,错误会比普通文本列表更难被察觉。

空返回和失败时,人工回退为什么必须后置

先区分两类没有候选

页面至少应区分以下两种情况:

  1. 调用成功但未收到展示结果:服务已返回,但当前条件下没有可展示候选。
  2. 调用失败:页面记录格式化后的错误信息,不能把任何本地文案包装成服务候选。

两种情况都可以进入人工派工草稿,但草稿里必须保留本轮请求条件和原始状态。这样后续人员知道人工处理是因为“本轮为空”还是“本轮未完成调用”,不会把两种问题混在一起处理。

private canStartManualFallback(): boolean {
  return this.searchState.indexOf('失败') >= 0 ||
    this.searchState.indexOf('未收到') >= 0;
}

这段代码能说明:人工回退不是默认路径,只有失败或未收到结果时才被开启。它不能证明:人工补录的地点来自 MapKit,也不能把人工草稿当成新的地图候选。

成功返回时不应让人工入口覆盖候选

如果真实候选已经返回,页面会提示先选择候选,再生成本地待派工草稿;人工回退入口保持关闭。这样做不是限制调度人员,而是避免一个问题:用户刚得到一组可追溯的候选,却又用无来源的手工地点把列表覆盖,最终无法解释本次地图检索到底产生了什么。

只有当业务确实需要放弃某个候选时,才应在人工说明里明确写出放弃原因,而不是删除候选或篡改其相关性字段。保留原值、记录决定,通常比为了“列表整洁”而只保留最终答案更有价值。

建立可复演的操作路径

下面的操作路径适合用于页面验收或日常排查。它关注的是状态变化,而不是为了得到某个预设地点。

失败

返回空结果

返回候选

填写关键词与服务半径

生成新的检索轮次

调用 MapKit 文本搜索

服务是否返回

记录错误与请求条件

开启人工派工草稿

记录空结果与总数

保留顺序、siteId、地址、reliability、坐标

人工选择候选

候选是否提供坐标

地图聚焦到返回坐标

保留候选并提示不能定位

生成本地待派工草稿

操作一:检查基线状态

进入页面后,先确认关键词、服务半径、检索轮次、总结果和地图状态都是可读的。此时没有任何候选是正常状态;不要把服务中心标记或半径圆形误读为检索结果。

操作二:发起一次不改参数的检索

保持关键词和半径不变,发起一次文本检索。观察页面是否进入“请求中”,随后是否出现成功、空结果或失败。记录轮次、请求时间、总结果和错误摘要。该步骤的目标是确认状态链路,而不是要求服务必须返回固定数量的地点。

操作三:阅读候选字段,不急于选择

若候选返回,逐条查看序号、名称、地址、siteId、相关性和坐标状态。reliability 有值时记录原值,缺失时记录“未提供”。不要用候选序号、服务半径或地图缩放级别替代这个字段。

操作四:选择一个候选并检查聚焦边界

选择一条候选后,检查页面是否保留本轮候选信息与选择理由。若带有坐标且地图控制器已就绪,页面可以聚焦到该坐标;若没有坐标或控制器未返回,应出现明确原因,而不是显示一个看似成功的默认位置。

操作五:改变半径,确认旧结果失效

切换 5 km 与 10 km 服务半径,观察候选列表、总结果和选择状态是否被清空。之后重新检索,再比较新旧轮次。这个步骤验证的是“条件变化后不复用旧候选”,不是比较两个半径谁更优。

操作六:检查人工回退门槛

在成功返回候选时,人工回退不应覆盖现有候选。在失败或空返回时,人工草稿应保留当前请求轮次与原因,但不创建虚构地点。这样,人工处理可以继续,地图服务的实际状态也不会被掩盖。

常见错误与排查

reliability 当成距离

相关性字段不是距离字段。即使某个候选的相关性显示较高,也不能据此推断它离中心点最近;距离、路线、服务范围和相关性属于不同维度。页面若需要距离或路径判断,应由对应能力和字段单独提供,不应从 reliability 推导。

给缺失值补一个默认分数

使用 0100 或“满分”填补缺失值,会让读者无法区分“服务明确返回了这个数”与“页面为视觉完整添加了数”。正确做法是保留“未提供”,并把人工判断依据写在草稿说明中。

半径变化后仍显示旧候选

如果半径已经修改,候选列表、选中状态和地图标记仍然存在,当前页面就无法说明它们属于哪个查询条件。处理策略不是强行刷新显示文本,而是使旧候选失效,等待新的检索轮次返回。

把地图聚焦当成地点确认

地图能聚焦到一条候选坐标,只说明当前返回中存在坐标,且页面成功调用了地图控制器。它不能证明服务点已经接受工单、坐标符合现场入口,或人员真的能够到达。位置展示与业务确认应分别记录。

成功列表出现后立即开放人工补录

成功返回的候选具有明确来源。若此时直接开放人工补录并覆盖列表,页面就丢掉了最重要的回查基础。正确顺序是先选择真实候选;确需人工决定时,保留候选原值并写明为什么没有采用它。

FAQ

Q:reliability 越高,是否就应该自动选中?

不应该。它只能作为当前查询与候选关系的一项线索。是否派工还可能取决于地址、服务时段、人员覆盖、业务规则和人工确认。页面应展示并记录该字段,但不应让它单独触发业务决定。

Q:候选返回顺序能不能在前端重新排序?

可以做明确的业务排序,但不能悄悄改写服务返回顺序。若业务确实需要按距离、营业状态或内部评分排序,应另外保存排序规则、输入字段和排序后的结果;原始 rank 与原始 reliability 仍应保留,便于审阅。

Q:没有 reliability 的候选是否应该直接隐藏?

不应仅因为字段缺失就隐藏。该候选仍可能具有有效名称、地址或坐标。更合适的做法是显示“未提供”,并让人工选择时补充其他判断依据。隐藏会把“字段缺失”误写成“候选不存在”。

Q:文本检索成功但没有候选,是否等于地图故障?

不等于。它表示本轮调用完成,但没有获得可展示的候选。应保留关键词、半径、轮次和总数,再按页面设计进入人工派工草稿。只有调用异常时,才应按错误状态排查配置、网络或服务条件。

Q:页面显示候选标记,能否直接认为地点坐标已被业务确认?

不能。标记来自本轮返回的坐标字段,只能说明页面使用该字段进行了可视化。业务确认还需要独立的工单、现场或组织内资料支持,不能由一张地图画面反推。

必要条件|安装与配置操作手册

第1步:准备SDK和构建工具

在 DevEco Studio 的 SDK Manager 安装 HarmonyOS 6.1.1 API 24,使用项目自带 Hvigor 构建 entry 模块。

在这里插入图片描述
在这里插入图片描述

第2步:确认Kit引入

按本文代码检查对应 Kit:ArkWeb 使用 WebView/Download API,Camera 使用 CameraKit,ImageSource 使用图像模块,MapKit 使用 MapKit,Notification 使用 NotificationKit,AI字幕使用 SpeechKit,通行证识别使用 VisionKit。

第3步:登记模块和页面

确认页面出现在 entry/src/main/resources/base/profile/main_pages.json,并核对 module.json5 的 Stage、设备类型和权限声明。

第4步:完成设备权限

首次运行前申请本文所需权限。Camera 页面申请 CAMERA,AI字幕页面申请 MICROPHONE;权限被拒绝时先处理授权状态,不能直接创建会话或组件。

第5步:确认系统能力和硬件

在 API 24 设备或模拟器确认本文需要的摄像头、麦克风、地图服务、视觉识别或文件读取能力,能力检查通过后再执行页面操作。

在这里插入图片描述

第6步:配置 MapKit(仅MapKit文章)

在 AppGallery Connect 创建或选择项目,添加与 app.json5/工程包名一致的应用,核对签名证书指纹,进入服务管理开通 MapKit,并按控制台要求完成应用服务凭据/授权配置。只保留服务开关、包名和脱敏项目标识的截图;不得把 App ID、Client ID、API 密钥或证书私钥写入文章或源码。完成控制台配置后再验证地图初始化和检索回调。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐