<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-cn"><generator uri="https://gohugo.io/" version="0.147.7">Hugo</generator><title type="html">有呀</title><link href="https://nuoea.com/tags/umami/" rel="alternate" type="text/html" title="html"/><link href="https://nuoea.com/tags/umami/index.xml" rel="alternate" type="application/rss+xml" title="rss"/><updated>2026-07-07T04:03:54+00:00</updated><id>https://nuoea.com/tags/umami/</id><entry><title type="html">使用 Umami Api 实现点赞统计</title><link href="https://nuoea.com/use-umami-like/" rel="alternate" type="text/html"/><id>https://nuoea.com/use-umami-like/</id><published>2023-06-14T22:11:46+08:00</published><updated>2023-06-14T22:11:46+08:00</updated><content type="html"><![CDATA[<h2 id="前言">前言</h2>
<p>在写完上篇<a href="https://nuoea.com/use-umami-api">《使用 Umami Api 显示统计数据》</a>之后，越发的觉得Umami非常有意思。于是就继续看了看官方API，一番了解下来之后，发现通过 <code>Track events</code> 可以实现自定义的页面事件统计。灵光一闪，觉得可以用这玩意做个点赞统计。</p>
<h2 id="使用">使用</h2>
<p>使用起来非常简单，只需要在触发事件的元素中加上：</p>
<pre tabindex="0"><code>data-umami-event=&#34;{event-name}&#34;
</code></pre><p>例如：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#f92672">button</span> <span style="color:#a6e22e">id</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Like-button&#34;</span> <span style="color:#a6e22e">data-umami-event</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Like button&#34;</span>&gt;点赞&lt;/<span style="color:#f92672">button</span>&gt;
</span></span></code></pre></div><p>当然，也可以使用 Javascript</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">button</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#39;Like-button&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">button</span>.<span style="color:#a6e22e">onclick</span> <span style="color:#f92672">=</span> () =&gt; <span style="color:#a6e22e">umami</span>.<span style="color:#a6e22e">track</span>(<span style="color:#e6db74">&#39;Like button&#39;</span>);
</span></span></code></pre></div><p>如此一来，Umami就会统计到一个名为 <code>Like button</code> 的事件信息，并为触发次数进行统计。</p>
<h2 id="接口">接口</h2>
<p>已经有了统计的信息，下面只需要通过官方的API接口就能获取到统计的数据了。</p>
<pre tabindex="0"><code>GET /api/websites/{websiteId}/events
</code></pre><p>该接口需要5个参数，分别是：</p>
<ul>
<li>startAt: 起始时间.</li>
<li>endAt: 终止时间.</li>
<li>unit: 时间单位 (year | month | hour | day).</li>
<li>timezone: 时区 (ex. Asia/Shanghai).</li>
<li>url: 连接.</li>
</ul>
<p>请求代码如下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">umiTime</span> <span style="color:#f92672">=</span> Date.<span style="color:#a6e22e">parse</span>(<span style="color:#66d9ef">new</span> Date()); <span style="color:#75715e">//获取当前时间戳
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">pathurl</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">indow</span>.<span style="color:#a6e22e">location</span>.<span style="color:#a6e22e">pathname</span>; <span style="color:#75715e">// 获取当前URL路径
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">umiUrl</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;https://umami.mydomain.com/api/websites/&#34;</span> <span style="color:#f92672">+</span> <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">websiteId</span><span style="color:#f92672">&gt;</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/events?startAt=0&amp;endAt=&#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">umiTime</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;&amp;unit=hour&amp;url=&#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">pathurl</span> <span style="color:#f92672">+</span><span style="color:#e6db74">&#34;&amp;timezone=Asia/Shanghai&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">fetch</span>(<span style="color:#a6e22e">umiUrl</span>,{
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">method</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;GET&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">mode</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;cors&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">cache</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;default&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">headers</span><span style="color:#f92672">:</span> {
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">&#39;Authorization&#39;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Bearer &#39;</span> <span style="color:#f92672">+</span> <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">Token</span><span style="color:#f92672">&gt;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">&#39;Content-Type&#39;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;application/json&#39;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  })
</span></span><span style="display:flex;"><span>  .<span style="color:#a6e22e">then</span>(<span style="color:#a6e22e">res</span> =&gt; <span style="color:#a6e22e">res</span>.<span style="color:#a6e22e">json</span>()).<span style="color:#a6e22e">then</span>(<span style="color:#a6e22e">resdata</span> =&gt; {});
</span></span></code></pre></div><p>请求成功后，获取到的数据如下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>[
</span></span><span style="display:flex;"><span>  { <span style="color:#f92672">&#34;x&#34;</span>: <span style="color:#e6db74">&#34;Like button&#34;</span>, <span style="color:#f92672">&#34;t&#34;</span>: <span style="color:#e6db74">&#34;2023-04-12 22:00:00&#34;</span>, <span style="color:#f92672">&#34;y&#34;</span>: <span style="color:#ae81ff">1</span> },
</span></span><span style="display:flex;"><span>  { <span style="color:#f92672">&#34;x&#34;</span>: <span style="color:#e6db74">&#34;Like button&#34;</span>, <span style="color:#f92672">&#34;t&#34;</span>: <span style="color:#e6db74">&#34;2023-04-12 22:00:00&#34;</span>, <span style="color:#f92672">&#34;y&#34;</span>: <span style="color:#ae81ff">5</span> },
</span></span><span style="display:flex;"><span>  { <span style="color:#f92672">&#34;x&#34;</span>: <span style="color:#e6db74">&#34;Like button&#34;</span>, <span style="color:#f92672">&#34;t&#34;</span>: <span style="color:#e6db74">&#34;2023-04-12 23:00:00&#34;</span>, <span style="color:#f92672">&#34;y&#34;</span>: <span style="color:#ae81ff">4</span> },
</span></span><span style="display:flex;"><span>  { <span style="color:#f92672">&#34;x&#34;</span>: <span style="color:#e6db74">&#34;Like button&#34;</span>, <span style="color:#f92672">&#34;t&#34;</span>: <span style="color:#e6db74">&#34;2023-04-12 23:00:00&#34;</span>, <span style="color:#f92672">&#34;y&#34;</span>: <span style="color:#ae81ff">4</span> },
</span></span><span style="display:flex;"><span>  { <span style="color:#f92672">&#34;x&#34;</span>: <span style="color:#e6db74">&#34;Like button&#34;</span>, <span style="color:#f92672">&#34;t&#34;</span>: <span style="color:#e6db74">&#34;2023-04-13 00:00:00&#34;</span>, <span style="color:#f92672">&#34;y&#34;</span>: <span style="color:#ae81ff">1</span> }
</span></span><span style="display:flex;"><span>]
</span></span></code></pre></div><h2 id="最后">最后</h2>
<p>获取到的数据其实是请求的<code>Url</code>页面中，该事件以时间单位统计的一个数组，如果在参数中选择<code>unit</code>为<code>hour</code>,那么数据将会以小时为单位来分割，每小时的数据为一个对象，以此类推。而我们需要将所有的数据求和来得到我们最终的统计结果。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">groupBy</span>(<span style="color:#a6e22e">arr</span>, <span style="color:#a6e22e">by</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">arr</span>.<span style="color:#a6e22e">reduce</span>((<span style="color:#a6e22e">groups</span>, <span style="color:#a6e22e">item</span>) =&gt; {
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">// 获取 item 的分组的 key
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">key</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">by</span>(<span style="color:#a6e22e">item</span>);
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">// 看看这个组是不是已经存在
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>      <span style="color:#66d9ef">let</span> <span style="color:#a6e22e">group</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">groups</span>.<span style="color:#a6e22e">find</span>(<span style="color:#a6e22e">g</span> =&gt; <span style="color:#a6e22e">g</span>.<span style="color:#a6e22e">key</span> <span style="color:#f92672">===</span> <span style="color:#a6e22e">key</span>);
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">if</span>(<span style="color:#f92672">!</span><span style="color:#a6e22e">group</span>) {
</span></span><span style="display:flex;"><span>          <span style="color:#75715e">// 不存在就创建一个新组
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>          <span style="color:#a6e22e">group</span> <span style="color:#f92672">=</span> {<span style="color:#a6e22e">key</span>, <span style="color:#a6e22e">items</span><span style="color:#f92672">:</span> []};
</span></span><span style="display:flex;"><span>          <span style="color:#a6e22e">groups</span>.<span style="color:#a6e22e">push</span>(<span style="color:#a6e22e">group</span>);
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>      <span style="color:#75715e">// item 放入组中
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>      <span style="color:#a6e22e">group</span>.<span style="color:#a6e22e">items</span>.<span style="color:#a6e22e">push</span>(<span style="color:#a6e22e">item</span>);
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">groups</span>;
</span></span><span style="display:flex;"><span>  }, []);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> <span style="color:#a6e22e">data</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">groupBy</span>(<span style="color:#a6e22e">res</span>, <span style="color:#a6e22e">item</span> =&gt; <span style="color:#a6e22e">item</span>.<span style="color:#a6e22e">x</span>)
</span></span><span style="display:flex;"><span>  .<span style="color:#a6e22e">map</span>(<span style="color:#a6e22e">g</span> =&gt; ({
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">x</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">g</span>.<span style="color:#a6e22e">key</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">t</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">g</span>.<span style="color:#a6e22e">items</span>.<span style="color:#a6e22e">map</span>(<span style="color:#a6e22e">item</span> =&gt; <span style="color:#a6e22e">item</span>.<span style="color:#a6e22e">t</span>),
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">y</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">g</span>.<span style="color:#a6e22e">items</span>.<span style="color:#a6e22e">reduce</span>((<span style="color:#a6e22e">sum</span>, <span style="color:#a6e22e">item</span>) =&gt; <span style="color:#a6e22e">sum</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">item</span>.<span style="color:#a6e22e">y</span>, <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>  }));
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#a6e22e">data</span>);
</span></span></code></pre></div><p>以上。</p>]]></content><category scheme="https://nuoea.com/categories/%E6%8A%98%E8%85%BE" term="%E6%8A%98%E8%85%BE" label="折腾"/><category scheme="https://nuoea.com/tags/umami" term="umami" label="umami"/><category scheme="https://nuoea.com/tags/api" term="api" label="API"/></entry><entry><title type="html">使用 Umami Api 显示统计数据</title><link href="https://nuoea.com/use-umami-api/" rel="alternate" type="text/html"/><id>https://nuoea.com/use-umami-api/</id><published>2023-06-08T11:25:34+08:00</published><updated>2023-06-08T11:25:34+08:00</updated><content type="html"><![CDATA[<h2 id="前言">前言</h2>
<p>最近在大家的疯狂安利下，捣鼓上了这样一款可以部署在Docker上的前端统计应用。特别是木木老师，更是直接放出了<a href="https://immmmm.com/hi-umami-api/"> 《前端调用 Umami API 数据》 </a> 。不得不说，这个应用的可玩性成功的吸引了我的注意。</p>
<p>通过阅读官方的API文档，一番折腾下来，也是成功的在Memos页面中调用了umami统计的浏览数据。于是做个记录。</p>
<h2 id="认证">认证</h2>
<p>如果想要获取Umami的数据，首先需要身份鉴权。</p>
<pre tabindex="0"><code>POST https://umami.mydomain.com/api/auth/login
</code></pre><p>通过上述接口，请求到一个TOKEN。获取任何数据都需要在请求的头部带上这个TOKEN，完成身份的认证。</p>
<p>这一步我的建议是通过API在线请求调试工具去完成，像 <code>POSTMAN</code>、<code>hoppscotch</code></p>
<blockquote>
<p><a href="https://hoppscotch.io/">Hoppscotch</a></p></blockquote>
<p><img class="lozad" data-src="https://i.nuoea.com/img/2023/06/08/1686197391.jpg" alt=""  /></p>
<p>如果请求成功，会返回一个JSON</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-JSON" data-lang="JSON"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;token&#34;</span>: <span style="color:#e6db74">&#34;eyTMjU2IiwiY...4Q0JDLUhWxnIjoiUE_A&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;user&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;id&#34;</span>: <span style="color:#e6db74">&#34;cd33a605-d785-42a1-9365-d6cad3b7befd&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;username&#34;</span>: <span style="color:#e6db74">&#34;your-username&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;createdAt&#34;</span>: <span style="color:#e6db74">&#34;2020-04-20 01:00:00&#34;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>如此一来，就请求到了TOKEN，建议将TOKEN存入 HUGO 里面的 <code>config</code>中，方便后面调用。</p>
<pre tabindex="0"><code>[params.umami]
    url = &#39;https://umami.mydomain.com&#39;
    token = &#39;eyTMjU2IiwiY...4Q0JDLUhWxnIjoiUE_A&#39;
</code></pre><h2 id="浏览数据">浏览数据</h2>
<p>获取文章的阅读数据，可以使用下面的这个API：</p>
<pre tabindex="0"><code>GET https://umami.mydomain.com/api/websites/{websiteId}/metrics
</code></pre><p>参数如下：</p>
<ul>
<li>startAt: 起始时间</li>
<li>endAt: 终止时间</li>
<li>type: url</li>
</ul>
<p>请求代码如下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">umiTime</span> <span style="color:#f92672">=</span> Date.<span style="color:#a6e22e">parse</span>(<span style="color:#66d9ef">new</span> Date()); <span style="color:#75715e">//获取当前时间戳
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">umiUrl</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;https://umami.mydomain.com/api/websites/&#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">bbMemo</span>.<span style="color:#a6e22e">umiId</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/metrics?startAt=0&amp;endAt=&#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">umiTime</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;&amp;type=url&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">fetch</span>(<span style="color:#a6e22e">umiUrl</span>,{
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">method</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;GET&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">mode</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;cors&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">cache</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;default&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">headers</span><span style="color:#f92672">:</span> {
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">&#39;Authorization&#39;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Bearer &#39;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">umami</span>.<span style="color:#a6e22e">token</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">&#39;Content-Type&#39;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;application/json&#39;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  })
</span></span><span style="display:flex;"><span>  .<span style="color:#a6e22e">then</span>(<span style="color:#a6e22e">res</span> =&gt; <span style="color:#a6e22e">res</span>.<span style="color:#a6e22e">json</span>()).<span style="color:#a6e22e">then</span>(<span style="color:#a6e22e">resdata</span> =&gt; {});
</span></span></code></pre></div><p>请求成功后，获取到的数据如下：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-JSON" data-lang="JSON"><span style="display:flex;"><span>[
</span></span><span style="display:flex;"><span>    {<span style="color:#f92672">&#34;x&#34;</span>: <span style="color:#e6db74">&#34;/&#34;</span>, <span style="color:#f92672">&#34;y&#34;</span>: <span style="color:#ae81ff">46</span>}
</span></span><span style="display:flex;"><span>    {<span style="color:#f92672">&#34;x&#34;</span>: <span style="color:#e6db74">&#34;/docs&#34;</span>, <span style="color:#f92672">&#34;y&#34;</span>: <span style="color:#ae81ff">17</span>}
</span></span><span style="display:flex;"><span>    {<span style="color:#f92672">&#34;x&#34;</span>: <span style="color:#e6db74">&#34;/download&#34;</span>, <span style="color:#f92672">&#34;y&#34;</span>: <span style="color:#ae81ff">14</span>}
</span></span><span style="display:flex;"><span>]
</span></span></code></pre></div><p>最后，通过遍历对比JSON中的地址与当前文章的URL地址，就可以获取到对应的浏览数据了。</p>
<h2 id="最后">最后</h2>
<p>官方的API文档里面还有非常多的接口，大家可以根据自己的需求，按照上面的方法去获取自己想要的统计数据，就酱。</p>]]></content><category scheme="https://nuoea.com/categories/%E6%8A%98%E8%85%BE" term="%E6%8A%98%E8%85%BE" label="折腾"/><category scheme="https://nuoea.com/tags/umami" term="umami" label="umami"/><category scheme="https://nuoea.com/tags/api" term="api" label="API"/></entry></feed>