[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"post-use-umami-api-on-nuxt":3},{"success":4,"message":5,"frontmatter":6,"content":13},true,"获取成功",{"slug":7,"title":8,"date":9,"description":10,"tags":11,"published":4},"use-umami-api-on-nuxt","在博客中添加 Umami 数据展示","2025-08-17","使用 Umami API 在 Nuxt 博客中展示访问统计数据。",[12],"笔记","最近，我在使用 **Nuxt** 重构我的博客。在 [关于](\u002Fabout) 页面上，我参考了 [安知鱼](https:\u002F\u002Fblog.anheyu.com\u002Fabout\u002F) 的布局。其中有一个访问数据统计卡片，原本使用的是 51LA。起初我也尝试过在 Nuxt 中添加它，但发现官方挂件在 Nuxt 中不好直接使用。\n\n![安知鱼-访问统计](https:\u002F\u002Fcdn.zhengweixin.top\u002Fblog\u002Fposts\u002F1755409293000_612e9ddb40fe4c3b8f02910c93817ee9.png)\n\n尝试无果后，我想到了自己两年前搭建的 [Umami](https:\u002F\u002Fumami.is\u002F) 统计服务。\n\n## Umami 搭建\n\n我使用的是 Vercel 部署，搭建步骤如下（你也可以选择其他服务商）：\n\n1. Fork 官方 GitHub 仓库 [umami-software\u002Fumami](https:\u002F\u002Fgithub.com\u002Fumami-software\u002Fumami)。\n\n2. 在 Vercel 中创建数据库：\n\n   - 打开 **Storage** 选项卡，创建 PostgreSQL 数据库。\n\n   ![vercel-storage](https:\u002F\u002Fcdn.zhengweixin.top\u002Fblog\u002Fposts\u002F1755409957000_34df58bdbb98404cb8b82dbc55ac356d.png)\n\n3. 新建项目，选择刚 fork 的仓库。\n   - 添加环境变量 `DATABASE_URL`，值为刚创建的数据库地址。例如：\n     ```\n     postgresql:\u002F\u002Fusername:password@localhost:5432\u002Fmydb\n     ```\n\n到这里，Umami 就部署完成了。本文重点不在部署细节，所以这里只简单说明 😺。\n\n## API 简介\n\nUmami 提供了丰富的 API，可参考 [官方文档](https:\u002F\u002Fumami.is\u002Fdocs\u002Fapi\u002Fauthentication)。\n\n| API                                  | 功能           |\n| ------------------------------------ | -------------- |\n| POST \u002Fapi\u002Fauth\u002Flogin                 | 获取用户信息   |\n| GET \u002Fapi\u002Fwebsites\u002F:websiteId         | 获取网站信息   |\n| GET \u002Fapi\u002Fwebsites\u002F:websiteId\u002Fstats   | 获取访问量     |\n| GET \u002Fapi\u002Fwebsites\u002F:websiteId\u002Fmetrics | 获取文章阅读量 |\n\n## 获取 Token\n\n使用 API 之前，需要先获取账号 **Token**。  \n通过 `POST \u002Fapi\u002Fauth\u002Flogin` 发送账号密码即可获取：\n\n```json\n{\n  \"username\": \"your-username\",\n  \"password\": \"your-password\"\n}\n```\n\n返回示例：\n\n```json\n{\n  \"token\": \"Mcfd5PaVC4cMDSJw51j...dvM+gvwvuDw==\",\n  \"user\": {\n    \"id\": \"7d7cf1f3-4d81-4a6b-8257-57a2ee4629a2\",\n    \"username\": \"visitor\",\n    \"createdAt\": \"2025-08-17T03:19:58.646Z\"\n  }\n}\n```\n\n这里分享一个简单的 Python 脚本示例，用于获取 Token：\n\n```python\nimport requests\n\n# Umami API 地址\nUMAMI_URL = 'https:\u002F\u002Fstatistics.zhengweixin.top'\n\n# 账号密码\nUSERNAME = '******'\nPASSWORD = '******'\n\ndef get_token():\n    login_url = f\"{UMAMI_URL}\u002Fapi\u002Fauth\u002Flogin\"\n    payload = {\n        \"username\": USERNAME,\n        \"password\": PASSWORD\n    }\n    headers = {\n        \"Content-Type\": \"application\u002Fjson\"\n    }\n\n    response = requests.post(login_url, json=payload, headers=headers)\n\n    if response.status_code == 200:\n        data = response.json()\n        token = data.get(\"token\")\n        user_info = data.get(\"user\")\n        print(\"Token:\", token)\n        print(\"User info:\", user_info)\n        return token\n    else:\n        print(f\"Failed to get token: {response.status_code} {response.text}\")\n        return None\n\nif __name__ == \"__main__\":\n    get_token()\n\n```\n\n## 在 Nuxt 页面中使用 API\n\n获取到 Token 后，在需要使用的页面中添加如下代码：\n\n```javascript\n\u002F\u002F 配置\nconst UMAMI_URL = 'https:\u002F\u002Fstatistics.zhengweixin.top'; \u002F\u002FUmami链接\nconst WEBSITE_ID = '7441ce23-3587-41b6-8919-e42932fc65d7'; \u002F\u002F站点ID\nconst TOKEN = '你的Token';\nconst CREATED_AT = '2025-08-15T16:00:00.000Z'; \u002F\u002F网站创立时间\n\nconst statsToday = ref(null);\nconst statsYesterday = ref(null);\nconst statsTotal = ref(null);\nconst error = ref(null);\n\nfunction getDayTimestamps(date = new Date()) {\n  const start = new Date(date);\n  start.setHours(0, 0, 0, 0);\n  const end = new Date(start);\n  end.setHours(23, 59, 59, 999);\n  return { start: start.getTime(), end: end.getTime() };\n}\n\nonMounted(async () => {\n  try {\n    const createdAtTs = new Date(CREATED_AT).getTime();\n    const now = Date.now();\n\n    \u002F\u002F 今日\n    const { start: startToday, end: endToday } = getDayTimestamps();\n    statsToday.value = await fetch(`${UMAMI_URL}\u002Fapi\u002Fwebsites\u002F${WEBSITE_ID}\u002Fstats?startAt=${startToday}&endAt=${endToday}`, {\n      headers: { Authorization: `Bearer ${TOKEN}` }\n    }).then(res => res.json());\n\n    \u002F\u002F 昨日\n    const yesterday = new Date();\n    yesterday.setDate(yesterday.getDate() - 1);\n    const { start: startYesterday, end: endYesterday } = getDayTimestamps(yesterday);\n    statsYesterday.value = await fetch(`${UMAMI_URL}\u002Fapi\u002Fwebsites\u002F${WEBSITE_ID}\u002Fstats?startAt=${startYesterday}&endAt=${endYesterday}`, {\n      headers: { Authorization: `Bearer ${TOKEN}` }\n    }).then(res => res.json());\n\n    \u002F\u002F 总量\n    statsTotal.value = await fetch(`${UMAMI_URL}\u002Fapi\u002Fwebsites\u002F${WEBSITE_ID}\u002Fstats?startAt=${createdAtTs}&endAt=${now}`, {\n      headers: { Authorization: `Bearer ${TOKEN}` }\n    }).then(res => res.json());\n\n  } catch (e) {\n    error.value = e.message;\n  }\n});\n```\n\n页面中可用变量：\n\n|                                |              |\n| ------------------------------ | ------------ |\n| statsToday.visitors.value      | 今日访问人数 |\n| statsToday.pageviews.value     | 今日访问量   |\n| statsYesterday.visitors.value  | 昨日访问人数 |\n| statsYesterday.pageviews.value | 昨日访问量   |\n| statsTotal.pageviews.value     | 本月访问总量 |\n| statsTotal.pageviews.value     | 总访问量     |\n"]