所属产品: Mingcedar CONTROL
页面 SDK:快速上手 | Mingcedar
将 HTML 上传到“画面文件”并从运行菜单打开,Runtime 会自动加载 SDK,无需安装 npm 包或添加 script。调用一次 ready(),后续复用返回的 api。
<div class="manual-doc-article manual-doc-article-section"><h2 id="custom-page-tutorial">开发指南: 页面 SDK:快速上手</h2>
使用页面 SDK 读取 Tag、写入设定值并查询报警和趋势。示例适用于原生 HTML 和 Vue;发布前须替换项目点位并核对权限。
<div class="doc-card-list doc-tutorial">
<article class="doc-card">
<h3 id="custom-page-tutorial-item-1">SDK 加载方式</h3>
<p>将 HTML 上传到“画面文件”并从运行菜单打开,Runtime 会自动加载 SDK,无需安装 npm 包或添加 script。调用一次 ready(),后续复用返回的 api。</p>
<div class="manual-code" data-code-language="javascript"><div class="manual-code-toolbar"><span>JavaScript</span><span class="manual-code-tools"><small>JavaScript</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: JavaScript">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#005CC5">HQVISU_CUSTOM_PAGE</span><span style="color:#24292E">.</span><span style="color:#6F42C1">ready</span><span style="color:#24292E">().</span><span style="color:#6F42C1">then</span><span style="color:#24292E">(</span><span style="color:#D73A49">async</span><span style="color:#24292E"> (</span><span style="color:#E36209">api</span><span style="color:#24292E">) </span><span style="color:#D73A49">=></span><span style="color:#24292E"> {</span></span>
<span class="line"><span style="color:#6A737D"> // Use the examples below here. Reuse this api object.</span></span>
<span class="line"><span style="color:#24292E">}).</span><span style="color:#6F42C1">catch</span><span style="color:#24292E">(</span><span style="color:#E36209">error</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> console.</span><span style="color:#6F42C1">error</span><span style="color:#24292E">(error.message));</span></span></code></pre></div>
<p class="doc-step-result"><strong>完成标志</strong> 原生 HTML 将代码放在 body 末尾的 <script> 中,页面元素放在前面。按需选取下文片段放进同一 async 回调,复用 api。独立 Vite 服务器、file:// 和其它网站不提供此运行环境。</p>
<ul class="doc-related-links">
<li><a href="/hqserver/manual/custom-page-sdk/#custom-page-sdk-item-4">引入方式</a></li>
</ul>
</article>
<article class="doc-card">
<h3 id="sdk-expand">声明页面使用的 Tag</h3>
<p>把这段声明放进入口 HTML 的 head。将 <device-code>.<tag-code> 替换成实际完整编码;只读页面把 writableTags 改成 []。Vue 也写在 index.html 中。</p>
<div class="manual-code" data-code-language="html"><div class="manual-code-toolbar"><span>HTML</span><span class="manual-code-tools"><small>HTML</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: HTML">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">script</span><span style="color:#24292E">>window.</span><span style="color:#005CC5">HQVISU_PAGE_META</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> { layoutMode: </span><span style="color:#032F62">"native"</span><span style="color:#24292E"> };</</span><span style="color:#22863A">script</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">script</span><span style="color:#6F42C1"> type</span><span style="color:#24292E">=</span><span style="color:#032F62">"application/json"</span><span style="color:#6F42C1"> id</span><span style="color:#24292E">=</span><span style="color:#032F62">"hqvisu-custom-page"</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E">{</span></span>
<span class="line"><span style="color:#24292E"> "readableTags": ["<device-code>.<tag-code>"],</span></span>
<span class="line"><span style="color:#24292E"> "writableTags": ["<device-code>.<tag-code>"]</span></span>
<span class="line"><span style="color:#24292E">}</span></span>
<span class="line"><span style="color:#24292E"></</span><span style="color:#22863A">script</span><span style="color:#24292E">></span></span></code></pre></div>
<p class="doc-step-result"><strong>完成标志</strong> layoutMode: "native" 让普通 HTML/Vue 按窗口自适应布局。readableTags 是读范围,writableTags 是写范围;声明不会授予账号原本没有的控制权限。</p>
</article>
<article class="doc-card">
<h3 id="custom-page-tutorial-item-4">读取一个 Tag</h3>
<p>添加 <output id="value"></output>,用 ReadTagDouble 读数值,null 指定不可用时的返回值。整数、布尔和文本分别用 ReadTagInteger、ReadTagBoolean、ReadTagString。</p>
<div class="manual-code" data-code-language="javascript"><div class="manual-code-toolbar"><span>JavaScript</span><span class="manual-code-tools"><small>JavaScript</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: JavaScript">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> value</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> api.</span><span style="color:#6F42C1">ReadTagDouble</span><span style="color:#24292E">(</span><span style="color:#032F62">"<device-code>.<tag-code>"</span><span style="color:#24292E">, </span><span style="color:#005CC5">null</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#24292E">document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"value"</span><span style="color:#24292E">).textContent </span><span style="color:#D73A49">=</span><span style="color:#24292E"> value </span><span style="color:#D73A49">??</span><span style="color:#032F62"> "—"</span><span style="color:#24292E">;</span></span></code></pre></div>
<p class="doc-step-result"><strong>完成标志</strong> 读取同步返回已采集的当前值,不会每次调用都去读 PLC。null 显示为“—”,不能当成真实 0。</p>
</article>
<article class="doc-card">
<h3 id="sdk-first-value">值变化时自动刷新</h3>
<p>在 HTML 放一个 <output id="value"></output>,用 subscribe 通知页面刷新。无需 setInterval 反复查询。</p>
<div class="manual-code" data-code-language="javascript"><div class="manual-code-toolbar"><span>JavaScript</span><span class="manual-code-tools"><small>JavaScript</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: JavaScript">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> tag</span><span style="color:#D73A49"> =</span><span style="color:#032F62"> "<device-code>.<tag-code>"</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49">function</span><span style="color:#6F42C1"> renderValue</span><span style="color:#24292E">() {</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> value</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> api.</span><span style="color:#6F42C1">ReadTagDouble</span><span style="color:#24292E">(tag, </span><span style="color:#005CC5">null</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#24292E"> document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"value"</span><span style="color:#24292E">).textContent </span><span style="color:#D73A49">=</span><span style="color:#24292E"> value </span><span style="color:#D73A49">??</span><span style="color:#032F62"> "—"</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">}</span></span>
<span class="line"><span style="color:#6F42C1">renderValue</span><span style="color:#24292E">();</span></span>
<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> stop</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> api.</span><span style="color:#6F42C1">subscribe</span><span style="color:#24292E">([tag], renderValue);</span></span>
<span class="line"><span style="color:#6A737D">// Call stop() when this view is removed.</span></span></code></pre></div>
<p class="doc-step-result"><strong>完成标志</strong> 首次进入立即显示当前值,后续变化自动更新。组件退出时调用 stop()。</p>
</article>
<article class="doc-card">
<h3 id="custom-page-tutorial-item-5">点击按钮写入一次 Tag</h3>
<p>添加 <button id="write" disabled>写入</button> 和 <pre id="result"></pre>。下面写入一次 12.5;换成项目允许的目标值。目标需声明为可写、启用 Tag 控制,并由具有 tag:write 权限的账号操作。</p>
<div class="manual-code" data-code-language="javascript"><div class="manual-code-toolbar"><span>JavaScript</span><span class="manual-code-tools"><small>JavaScript</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: JavaScript">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> button</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"write"</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> output</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"result"</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#24292E">button.disabled </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> !</span><span style="color:#24292E">(api.</span><span style="color:#6F42C1">supports</span><span style="color:#24292E">(</span><span style="color:#032F62">"tag.write"</span><span style="color:#24292E">) </span><span style="color:#D73A49">&&</span><span style="color:#D73A49"> await</span><span style="color:#24292E"> api.auth.</span><span style="color:#6F42C1">hasPermission</span><span style="color:#24292E">(</span><span style="color:#032F62">"tag:write"</span><span style="color:#24292E">));</span></span>
<span class="line"><span style="color:#24292E">button.</span><span style="color:#6F42C1">onclick</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> async</span><span style="color:#24292E"> () </span><span style="color:#D73A49">=></span><span style="color:#24292E"> {</span></span>
<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (button.disabled) </span><span style="color:#D73A49">return</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> tag</span><span style="color:#D73A49"> =</span><span style="color:#032F62"> "<device-code>.<tag-code>"</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (</span><span style="color:#D73A49">!</span><span style="color:#24292E">api.</span><span style="color:#6F42C1">ReadTagQualityGood</span><span style="color:#24292E">(tag)) { output.textContent </span><span style="color:#D73A49">=</span><span style="color:#032F62"> "Tag unavailable"</span><span style="color:#24292E">; </span><span style="color:#D73A49">return</span><span style="color:#24292E">; }</span></span>
<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (</span><span style="color:#D73A49">!</span><span style="color:#6F42C1">confirm</span><span style="color:#24292E">(</span><span style="color:#032F62">"Write 12.5?"</span><span style="color:#24292E">)) </span><span style="color:#D73A49">return</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E"> button.disabled </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49"> try</span><span style="color:#24292E"> {</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> result</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> await</span><span style="color:#24292E"> api.</span><span style="color:#6F42C1">WriteTagDouble</span><span style="color:#24292E">(tag, </span><span style="color:#005CC5">12.5</span><span style="color:#24292E">, { reason: </span><span style="color:#032F62">"Operator setpoint update"</span><span style="color:#24292E"> });</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> done</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> result?.accepted </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> true</span><span style="color:#D73A49"> &&</span><span style="color:#24292E"> result?.status </span><span style="color:#D73A49">===</span><span style="color:#032F62"> "done"</span></span>
<span class="line"><span style="color:#D73A49"> &&</span><span style="color:#24292E"> result?.outcomeUncertain </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> true</span><span style="color:#D73A49"> &&</span><span style="color:#24292E"> result?.operatorVerificationRequired </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> true</span></span>
<span class="line"><span style="color:#D73A49"> &&</span><span style="color:#24292E"> result?.transportOnly </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> true</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E"> output.textContent </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (done </span><span style="color:#D73A49">?</span><span style="color:#032F62"> "Command completed; verify collected value: "</span><span style="color:#D73A49"> :</span><span style="color:#032F62"> "Result unconfirmed; verify before another write: "</span><span style="color:#24292E">)</span></span>
<span class="line"><span style="color:#D73A49"> +</span><span style="color:#005CC5"> JSON</span><span style="color:#24292E">.</span><span style="color:#6F42C1">stringify</span><span style="color:#24292E">(result </span><span style="color:#D73A49">??</span><span style="color:#005CC5"> null</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">catch</span><span style="color:#24292E"> (error) {</span></span>
<span class="line"><span style="color:#24292E"> output.textContent </span><span style="color:#D73A49">=</span><span style="color:#032F62"> "Result unconfirmed: "</span><span style="color:#D73A49"> +</span><span style="color:#24292E"> error.message </span><span style="color:#D73A49">+</span><span style="color:#032F62"> " "</span><span style="color:#D73A49"> +</span><span style="color:#24292E"> (error.commandId </span><span style="color:#D73A49">||</span><span style="color:#24292E"> error.result?.commandId </span><span style="color:#D73A49">||</span><span style="color:#032F62"> ""</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#24292E"> }</span></span>
<span class="line"><span style="color:#6A737D"> // Reconcile the result before another write. Never retry automatically.</span></span>
<span class="line"><span style="color:#24292E">};</span></span></code></pre></div>
<p class="doc-step-result"><strong>完成标志</strong> 整数、布尔用 WriteTagInteger、WriteTagBoolean。本例每页实例仅提交一次,随后禁用按钮;done 仍须核对后续正常采集值。刷新会重置按钮,下次操作前须核对上次结果;需跨刷新阻断时,保存待核对状态。</p>
<ul class="doc-related-links">
<li><a href="/hqserver/manual/custom-page-sdk/#custom-page-sdk-item-14">写入结果核对</a></li>
</ul>
</article>
<article class="doc-card">
<h3 id="custom-page-tutorial-item-6">查询当前报警(一次)</h3>
<p>在 HTML 添加 <div id="alarms"></div> 和 <p id="alarm-status"></p>。getActive 查询当前报警,renderTable 把 items 显示成表格。</p>
<div class="manual-code" data-code-language="javascript"><div class="manual-code-toolbar"><span>JavaScript</span><span class="manual-code-tools"><small>JavaScript</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: JavaScript">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> alarms</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> await</span><span style="color:#24292E"> api.alarms.</span><span style="color:#6F42C1">getActive</span><span style="color:#24292E">({ limit: </span><span style="color:#005CC5">100</span><span style="color:#24292E"> });</span></span>
<span class="line"><span style="color:#24292E">api.</span><span style="color:#6F42C1">renderTable</span><span style="color:#24292E">(</span><span style="color:#032F62">"#alarms"</span><span style="color:#24292E">, alarms.items);</span></span>
<span class="line"><span style="color:#24292E">document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"alarm-status"</span><span style="color:#24292E">).textContent </span><span style="color:#D73A49">=</span><span style="color:#24292E"> alarms.hasMore </span><span style="color:#D73A49">?</span><span style="color:#032F62"> "More records available"</span><span style="color:#D73A49"> :</span><span style="color:#032F62"> ""</span><span style="color:#24292E">;</span></span></code></pre></div>
<p class="doc-step-result"><strong>完成标志</strong> 本例仅查询一次。实时列表用 alarms.subscribe 通知重新查询,不直接追加回调数据;退出时取消订阅。空 items 表示当前范围无报警,hasMore=true 表示仍有记录。其它设备或分组须配置报警范围。</p>
<ul class="doc-related-links">
<li><a href="/hqserver/manual/custom-page-sdk/#custom-page-sdk-item-17">报警范围声明</a></li>
</ul>
</article>
<article class="doc-card">
<h3 id="custom-page-tutorial-item-9">查看最近一小时的历史报警</h3>
<p>添加 <div id="alarm-history"></div> 和 <p id="history-status"></p>。历史报警用 alarms.queryHistory 查询,显示在独立表格中。</p>
<div class="manual-code" data-code-language="javascript"><div class="manual-code-toolbar"><span>JavaScript</span><span class="manual-code-tools"><small>JavaScript</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: JavaScript">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> alarmEnd</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> new</span><span style="color:#6F42C1"> Date</span><span style="color:#24292E">();</span></span>
<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> alarmHistory</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> await</span><span style="color:#24292E"> api.alarms.</span><span style="color:#6F42C1">queryHistory</span><span style="color:#24292E">({</span></span>
<span class="line"><span style="color:#24292E"> start: </span><span style="color:#D73A49">new</span><span style="color:#6F42C1"> Date</span><span style="color:#24292E">(alarmEnd.</span><span style="color:#6F42C1">getTime</span><span style="color:#24292E">() </span><span style="color:#D73A49">-</span><span style="color:#005CC5"> 3600000</span><span style="color:#24292E">).</span><span style="color:#6F42C1">toISOString</span><span style="color:#24292E">(),</span></span>
<span class="line"><span style="color:#24292E"> end: alarmEnd.</span><span style="color:#6F42C1">toISOString</span><span style="color:#24292E">(),</span></span>
<span class="line"><span style="color:#24292E"> limit: </span><span style="color:#005CC5">100</span></span>
<span class="line"><span style="color:#24292E">});</span></span>
<span class="line"><span style="color:#24292E">api.</span><span style="color:#6F42C1">renderTable</span><span style="color:#24292E">(</span><span style="color:#032F62">"#alarm-history"</span><span style="color:#24292E">, alarmHistory.items);</span></span>
<span class="line"><span style="color:#24292E">document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"history-status"</span><span style="color:#24292E">).textContent </span><span style="color:#D73A49">=</span><span style="color:#24292E"> alarmHistory.hasMore </span><span style="color:#D73A49">?</span><span style="color:#032F62"> "More records available"</span><span style="color:#D73A49"> :</span><span style="color:#032F62"> ""</span><span style="color:#24292E">;</span></span></code></pre></div>
</article>
<article class="doc-card">
<h3 id="custom-page-tutorial-item-7">查询趋势数据</h3>
<p>先为 Tag 启用趋势归档,添加 <div id="trend"></div> 和 <p id="trend-status"></p>。下面把最近一小时的分钟平均值显示成表格;将同一份 points 交给图表组件即可画曲线。</p>
<div class="manual-code" data-code-language="javascript"><div class="manual-code-toolbar"><span>JavaScript</span><span class="manual-code-tools"><small>JavaScript</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: JavaScript">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> trendEnd</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> new</span><span style="color:#6F42C1"> Date</span><span style="color:#24292E">();</span></span>
<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> trend</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> await</span><span style="color:#24292E"> api.history.</span><span style="color:#6F42C1">query</span><span style="color:#24292E">({</span></span>
<span class="line"><span style="color:#24292E"> tags: [</span><span style="color:#032F62">"<device-code>.<tag-code>"</span><span style="color:#24292E">],</span></span>
<span class="line"><span style="color:#24292E"> start: </span><span style="color:#D73A49">new</span><span style="color:#6F42C1"> Date</span><span style="color:#24292E">(trendEnd.</span><span style="color:#6F42C1">getTime</span><span style="color:#24292E">() </span><span style="color:#D73A49">-</span><span style="color:#005CC5"> 3600000</span><span style="color:#24292E">).</span><span style="color:#6F42C1">toISOString</span><span style="color:#24292E">(),</span></span>
<span class="line"><span style="color:#24292E"> end: trendEnd.</span><span style="color:#6F42C1">toISOString</span><span style="color:#24292E">(), interval: </span><span style="color:#032F62">"1m"</span><span style="color:#24292E">, aggregate: </span><span style="color:#032F62">"avg"</span></span>
<span class="line"><span style="color:#24292E">});</span></span>
<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> points</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> (trend.items[</span><span style="color:#005CC5">0</span><span style="color:#24292E">]?.points </span><span style="color:#D73A49">||</span><span style="color:#24292E"> []).</span><span style="color:#6F42C1">map</span><span style="color:#24292E">(</span><span style="color:#E36209">point</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> ({</span></span>
<span class="line"><span style="color:#24292E"> time: point.t, value: point.quality </span><span style="color:#D73A49">===</span><span style="color:#032F62"> "good"</span><span style="color:#D73A49"> ?</span><span style="color:#24292E"> point.value </span><span style="color:#D73A49">:</span><span style="color:#005CC5"> null</span></span>
<span class="line"><span style="color:#24292E">}));</span></span>
<span class="line"><span style="color:#24292E">api.</span><span style="color:#6F42C1">renderTable</span><span style="color:#24292E">(</span><span style="color:#032F62">"#trend"</span><span style="color:#24292E">, points);</span></span>
<span class="line"><span style="color:#24292E">document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"trend-status"</span><span style="color:#24292E">).textContent </span><span style="color:#D73A49">=</span><span style="color:#24292E"> trend.effectiveInterval;</span></span></code></pre></div>
<p class="doc-step-result"><strong>完成标志</strong> 无归档时返回空数据;异常质量用 null 保留曲线缺口。effectiveInterval 是实际采样间隔。</p>
</article>
<article class="doc-card">
<h3 id="sdk-scenario-popup">打开设备弹窗</h3>
<p>先在“弹窗模板”保存模板,添加 <button id="open-popup">打开设备</button>,再绑定点击。替换设备编码、模板编码和已声明的 Tag。</p>
<div class="manual-code" data-code-language="javascript"><div class="manual-code-toolbar"><span>JavaScript</span><span class="manual-code-tools"><small>JavaScript</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: JavaScript">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"open-popup"</span><span style="color:#24292E">).</span><span style="color:#6F42C1">onclick</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> () </span><span style="color:#D73A49">=></span><span style="color:#24292E"> {</span></span>
<span class="line"><span style="color:#D73A49"> try</span><span style="color:#24292E"> {</span></span>
<span class="line"><span style="color:#24292E"> api.dialog.</span><span style="color:#6F42C1">openDevicePopup</span><span style="color:#24292E">({</span></span>
<span class="line"><span style="color:#24292E"> plc: </span><span style="color:#032F62">"<device-code>"</span><span style="color:#24292E">,</span></span>
<span class="line"><span style="color:#24292E"> templateCode: </span><span style="color:#032F62">"<popup-template-code>"</span><span style="color:#24292E">,</span></span>
<span class="line"><span style="color:#24292E"> focusTagNames: [</span><span style="color:#032F62">"<device-code>.<tag-code>"</span><span style="color:#24292E">]</span></span>
<span class="line"><span style="color:#24292E"> });</span></span>
<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">catch</span><span style="color:#24292E"> (error) { console.</span><span style="color:#6F42C1">error</span><span style="color:#24292E">(error.message); }</span></span>
<span class="line"><span style="color:#24292E">};</span></span></code></pre></div>
<p class="doc-step-result"><strong>完成标志</strong> 弹窗中的显示、读写、报警和趋势由模板配置决定。调用返回不代表弹窗内写入已完成;实际核对弹窗与目标值。</p>
</article>
<article class="doc-card">
<h3 id="sdk-scenario-navigation">跳转到其它页面</h3>
<p>按目标选择下面一个调用,放在按钮的点击处理函数中。相对路径以当前画面为起点;在 assets 根内可以跳到上级、下级和其它目录。</p>
<div class="manual-code" data-code-language="javascript"><div class="manual-code-toolbar"><span>JavaScript</span><span class="manual-code-tools"><small>JavaScript</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: JavaScript">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">// Use one of these calls in your button's click handler:</span></span>
<span class="line"><span style="color:#24292E">api.navigation.</span><span style="color:#6F42C1">gotoPage</span><span style="color:#24292E">(</span><span style="color:#032F62">"details/equipment.html"</span><span style="color:#24292E">); </span><span style="color:#6A737D">// Child page</span></span>
<span class="line"><span style="color:#24292E">api.navigation.</span><span style="color:#6F42C1">gotoPage</span><span style="color:#24292E">(</span><span style="color:#032F62">"../overview.html"</span><span style="color:#24292E">); </span><span style="color:#6A737D">// Parent page</span></span>
<span class="line"><span style="color:#24292E">api.navigation.</span><span style="color:#6F42C1">gotoPage</span><span style="color:#24292E">(</span><span style="color:#032F62">"/assets/<folder>/index.html"</span><span style="color:#24292E">); </span><span style="color:#6A737D">// Another folder</span></span>
<span class="line"><span style="color:#24292E">api.navigation.</span><span style="color:#6F42C1">openUrl</span><span style="color:#24292E">(</span><span style="color:#032F62">"https://<server-host>/manual"</span><span style="color:#24292E">, { openInNewWindow: </span><span style="color:#005CC5">true</span><span style="color:#24292E"> });</span></span></code></pre></div>
</article>
<article class="doc-card">
<h3 id="sdk-scenario-language">跟随系统切换中英文</h3>
<p>系统顶栏 LANG 已负责切换,不必再加语言按钮。给标题加 id="title",读取当前语言并订阅变化。</p>
<div class="manual-code" data-code-language="javascript"><div class="manual-code-toolbar"><span>JavaScript</span><span class="manual-code-tools"><small>JavaScript</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: JavaScript">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">function</span><span style="color:#6F42C1"> renderText</span><span style="color:#24292E">() {</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> zh</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> api.language.</span><span style="color:#6F42C1">current</span><span style="color:#24292E">().</span><span style="color:#6F42C1">startsWith</span><span style="color:#24292E">(</span><span style="color:#032F62">"zh"</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#24292E"> document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"title"</span><span style="color:#24292E">).textContent </span><span style="color:#D73A49">=</span><span style="color:#24292E"> zh </span><span style="color:#D73A49">?</span><span style="color:#032F62"> "设备总览"</span><span style="color:#D73A49"> :</span><span style="color:#032F62"> "Equipment overview"</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">}</span></span>
<span class="line"><span style="color:#6F42C1">renderText</span><span style="color:#24292E">();</span></span>
<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> stopLanguage</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> api.language.</span><span style="color:#6F42C1">onChange</span><span style="color:#24292E">(renderText);</span></span>
<span class="line"><span style="color:#6A737D">// Call stopLanguage() when this view is removed.</span></span></code></pre></div>
</article>
<article class="doc-card">
<h3 id="tutorial-sdk-vue-component">在 Vue 中使用同一套 API</h3>
<p>Vue 3 项目在 index.html 中添加布局和 Tag 声明,再保存并挂载以下完整只读组件。onMounted 后取得 api;发布到 Runtime 后自动加载 SDK。</p>
<div class="manual-code" data-code-language="vue"><div class="manual-code-toolbar"><span>Vue</span><span class="manual-code-tools"><small>Vue</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: Vue">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">script</span><span style="color:#6F42C1"> setup</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#D73A49">import</span><span style="color:#24292E"> { ref, onMounted, onUnmounted } </span><span style="color:#D73A49">from</span><span style="color:#032F62"> "vue"</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> value</span><span style="color:#D73A49"> =</span><span style="color:#6F42C1"> ref</span><span style="color:#24292E">(</span><span style="color:#005CC5">null</span><span style="color:#24292E">), </span><span style="color:#005CC5">error</span><span style="color:#D73A49"> =</span><span style="color:#6F42C1"> ref</span><span style="color:#24292E">(</span><span style="color:#032F62">""</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#D73A49">let</span><span style="color:#24292E"> stop, disposed </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> false</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#6F42C1">onMounted</span><span style="color:#24292E">(</span><span style="color:#D73A49">async</span><span style="color:#24292E"> () </span><span style="color:#D73A49">=></span><span style="color:#24292E"> {</span></span>
<span class="line"><span style="color:#D73A49"> try</span><span style="color:#24292E"> {</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> api</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> await</span><span style="color:#24292E"> window.</span><span style="color:#005CC5">HQVISU_CUSTOM_PAGE</span><span style="color:#24292E">.</span><span style="color:#6F42C1">ready</span><span style="color:#24292E">();</span></span>
<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (disposed) </span><span style="color:#D73A49">return</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> tag</span><span style="color:#D73A49"> =</span><span style="color:#032F62"> "<device-code>.<tag-code>"</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#6F42C1"> refresh</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> () </span><span style="color:#D73A49">=></span><span style="color:#24292E"> { value.value </span><span style="color:#D73A49">=</span><span style="color:#24292E"> api.</span><span style="color:#6F42C1">ReadTagDouble</span><span style="color:#24292E">(tag, </span><span style="color:#005CC5">null</span><span style="color:#24292E">); };</span></span>
<span class="line"><span style="color:#6F42C1"> refresh</span><span style="color:#24292E">();</span></span>
<span class="line"><span style="color:#24292E"> stop </span><span style="color:#D73A49">=</span><span style="color:#24292E"> api.</span><span style="color:#6F42C1">subscribe</span><span style="color:#24292E">([tag], refresh);</span></span>
<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">catch</span><span style="color:#24292E"> (err) { </span><span style="color:#D73A49">if</span><span style="color:#24292E"> (</span><span style="color:#D73A49">!</span><span style="color:#24292E">disposed) error.value </span><span style="color:#D73A49">=</span><span style="color:#24292E"> err.message; }</span></span>
<span class="line"><span style="color:#24292E">});</span></span>
<span class="line"><span style="color:#6F42C1">onUnmounted</span><span style="color:#24292E">(() </span><span style="color:#D73A49">=></span><span style="color:#24292E"> { disposed </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span><span style="color:#24292E">; </span><span style="color:#6F42C1">stop</span><span style="color:#24292E">?.(); });</span></span>
<span class="line"><span style="color:#24292E"></</span><span style="color:#22863A">script</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">template</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"> <</span><span style="color:#22863A">p</span><span style="color:#6F42C1"> v-if</span><span style="color:#24292E">=</span><span style="color:#032F62">"error"</span><span style="color:#24292E">>{{ error }}</</span><span style="color:#22863A">p</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"> <</span><span style="color:#22863A">output</span><span style="color:#6F42C1"> v-else</span><span style="color:#24292E">>{{ value ?? "—" }}</</span><span style="color:#22863A">output</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"></</span><span style="color:#22863A">template</span><span style="color:#24292E">></span></span></code></pre></div>
<p class="doc-step-result"><strong>完成标志</strong> 设置 Vite base: "./",按原目录上传 dist 内容。卸载只取消组件订阅,不调用 api.destroy()。本例 api 位于 onMounted 内;按钮调用须在组件作用域保存 api,见完整 Vue 写入示例。</p>
<ul class="doc-related-links">
<li><a href="/hqserver/manual/custom-page-sdk/#sdk-vue-component">完整 Vue 写入示例</a></li>
</ul>
</article>
<article class="doc-card">
<h3 id="custom-page-tutorial-item-2">完整 HTML:替换点位后发布</h3>
<p>需要从零开始时复制这个完整只读页,替换两处 Tag 编码。它使用 Runtime 自动提供的 SDK。</p>
<details class="manual-code-disclosure"><summary>展开完整源代码</summary><div class="manual-code" data-code-language="html"><div class="manual-code-toolbar"><span>HTML</span><span class="manual-code-tools"><small>HTML</small><button type="button" data-copy-code data-copied="已复制" data-failed="请选中代码后复制" aria-label="复制代码: HTML">复制代码</button><span class="manual-code-status" role="status"></span></span></div><pre tabindex="0" class="docs-code-block shiki github-light" style="background-color:#fff;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"><!</span><span style="color:#22863A">doctype</span><span style="color:#6F42C1"> html</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">html</span><span style="color:#6F42C1"> lang</span><span style="color:#24292E">=</span><span style="color:#032F62">"en"</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">meta</span><span style="color:#6F42C1"> charset</span><span style="color:#24292E">=</span><span style="color:#032F62">"utf-8"</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">meta</span><span style="color:#6F42C1"> name</span><span style="color:#24292E">=</span><span style="color:#032F62">"viewport"</span><span style="color:#6F42C1"> content</span><span style="color:#24292E">=</span><span style="color:#032F62">"width=device-width, initial-scale=1"</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">title</span><span style="color:#24292E">>Mingcedar live value</</span><span style="color:#22863A">title</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">script</span><span style="color:#6F42C1"> type</span><span style="color:#24292E">=</span><span style="color:#032F62">"application/json"</span><span style="color:#6F42C1"> id</span><span style="color:#24292E">=</span><span style="color:#032F62">"hqvisu-custom-page"</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E">{"readableTags":["<device-code>.<process-tag-code>"],"writableTags":[]}</span></span>
<span class="line"><span style="color:#24292E"></</span><span style="color:#22863A">script</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">script</span><span style="color:#24292E">>window.</span><span style="color:#005CC5">HQVISU_PAGE_META</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> { layoutMode: </span><span style="color:#032F62">"native"</span><span style="color:#24292E"> };</</span><span style="color:#22863A">script</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">h1</span><span style="color:#24292E">>Live value</</span><span style="color:#22863A">h1</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">p</span><span style="color:#6F42C1"> id</span><span style="color:#24292E">=</span><span style="color:#032F62">"status"</span><span style="color:#6F42C1"> role</span><span style="color:#24292E">=</span><span style="color:#032F62">"status"</span><span style="color:#24292E">>Connecting…</</span><span style="color:#22863A">p</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">output</span><span style="color:#6F42C1"> id</span><span style="color:#24292E">=</span><span style="color:#032F62">"value"</span><span style="color:#24292E">>Waiting for data</</span><span style="color:#22863A">output</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">script</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E">(</span><span style="color:#D73A49">async</span><span style="color:#24292E"> () </span><span style="color:#D73A49">=></span><span style="color:#24292E"> {</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> tag</span><span style="color:#D73A49"> =</span><span style="color:#032F62"> "<device-code>.<process-tag-code>"</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> status</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"status"</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> output</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"value"</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> api</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> await</span><span style="color:#005CC5"> HQVISU_CUSTOM_PAGE</span><span style="color:#24292E">.</span><span style="color:#6F42C1">ready</span><span style="color:#24292E">({timeoutMs: </span><span style="color:#005CC5">10000</span><span style="color:#24292E">});</span></span>
<span class="line"><span style="color:#D73A49"> function</span><span style="color:#6F42C1"> refresh</span><span style="color:#24292E">() {</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> quality</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> api.</span><span style="color:#6F42C1">ReadTagQuality</span><span style="color:#24292E">(tag);</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> value</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> api.</span><span style="color:#6F42C1">ReadTagDouble</span><span style="color:#24292E">(tag, </span><span style="color:#005CC5">null</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#24292E"> status.textContent </span><span style="color:#D73A49">=</span><span style="color:#032F62"> "Connected — quality: "</span><span style="color:#D73A49"> +</span><span style="color:#24292E"> quality;</span></span>
<span class="line"><span style="color:#24292E"> output.textContent </span><span style="color:#D73A49">=</span><span style="color:#24292E"> quality </span><span style="color:#D73A49">===</span><span style="color:#032F62"> "good"</span><span style="color:#D73A49"> &&</span><span style="color:#24292E"> value </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> null</span></span>
<span class="line"><span style="color:#D73A49"> ?</span><span style="color:#6F42C1"> String</span><span style="color:#24292E">(value) </span><span style="color:#D73A49">:</span><span style="color:#032F62"> "Unavailable"</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E"> }</span></span>
<span class="line"><span style="color:#D73A49"> const</span><span style="color:#005CC5"> stop</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> api.</span><span style="color:#6F42C1">subscribe</span><span style="color:#24292E">([tag], refresh);</span></span>
<span class="line"><span style="color:#6F42C1"> refresh</span><span style="color:#24292E">();</span></span>
<span class="line"><span style="color:#24292E"> window.</span><span style="color:#6F42C1">addEventListener</span><span style="color:#24292E">(</span><span style="color:#032F62">"pagehide"</span><span style="color:#24292E">, </span><span style="color:#E36209">event</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> {</span></span>
<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (</span><span style="color:#D73A49">!</span><span style="color:#24292E">event.persisted) { </span><span style="color:#6F42C1">stop</span><span style="color:#24292E">(); api.</span><span style="color:#6F42C1">destroy</span><span style="color:#24292E">(); }</span></span>
<span class="line"><span style="color:#24292E"> });</span></span>
<span class="line"><span style="color:#24292E">})().</span><span style="color:#6F42C1">catch</span><span style="color:#24292E">(</span><span style="color:#E36209">error</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> {</span></span>
<span class="line"><span style="color:#24292E"> document.</span><span style="color:#6F42C1">getElementById</span><span style="color:#24292E">(</span><span style="color:#032F62">"status"</span><span style="color:#24292E">).textContent </span><span style="color:#D73A49">=</span><span style="color:#24292E"> error.message;</span></span>
<span class="line"><span style="color:#24292E">});</span></span>
<span class="line"><span style="color:#24292E"></</span><span style="color:#22863A">script</span><span style="color:#24292E">></span></span>
<span class="line"><span style="color:#24292E"></</span><span style="color:#22863A">html</span><span style="color:#24292E">></span></span></code></pre></div></details>
</article>
<article class="doc-card">
<h3 id="custom-page-tutorial-item-3">发布到运行页面</h3>
<ol>
<li>配置中心 → 画面文件:上传 HTML;Vue 上传构建后 dist 的内容并保留目录。</li>
<li>配置中心 → 菜单:选择“页面(直接打开 HTML)”,把入口指向刚上传的 HTML。</li>
<li>从运行菜单打开。先确认 Tag 值,再验证需要的操作;修改后覆盖发布并刷新。</li>
</ol>
</article>
<article class="doc-card">
<h3 id="custom-page-tutorial-item-11">常见问题与排查</h3>
<ul>
<li>HQVISU_CUSTOM_PAGE 未定义:确认从当前 Runtime 的运行菜单打开;独立网页不会自动提供 SDK。</li>
<li>读到 null:核对静态声明、完整 Tag 编码及数据质量。</li>
<li>写入不可用:核对 writableTags、账号权限和 Tag 控制标志;未知结果先核对,不重发。</li>
<li>其他数据类型和选项见 API 参考。</li>
</ul>
<ul class="doc-related-links">
<li><a href="/hqserver/manual/custom-page-sdk/">API 参考</a></li>
</ul>
</article>
<article class="doc-card">
<h3 id="sdk-development-brief">页面交付信息</h3>
<p>开发和验收自写页面时,准备实际 Tag 编码与类型、允许的写入值、页面功能及目标运行菜单。入口 HTML 中的声明须与页面代码一致。</p>
<ul>
<li>记录页面使用的 Tag、报警和历史范围;写入点同时明确账号权限、控制许可和设备允许值。</li>
<li>从运行菜单打开页面,核对 SDK 初始化、GOOD 质量、系统 LANG 切换和组件卸载后的订阅清理。</li>
<li>验证写入回执与后续正常采集值;结果未确认时保留命令标识,下一次操作前先核对。</li>
<li>缺少实际编码、类型或授权范围时,先补全配置再发布。</li>
</ul>
<ul class="doc-related-links">
<li><a href="/hqserver/manual/custom-page-sdk/">API 参考</a></li>
</ul>
</article>
</div>
</div>