news 2026/9/15 8:57:52

ActivityWatch 自托管时间追踪:本地部署、外部访问与安全加固实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ActivityWatch 自托管时间追踪:本地部署、外部访问与安全加固实践

1. 为什么在时间追踪这件事上,我最终选了 ActivityWatch

先说个背景:我之前做自由职业,每天坐在电脑前十几个小时,但到了月底复盘时,完全说不清时间到底花在哪了。试过手动计时软件,记几天就放弃,因为人一旦忙起来,根本想不起点“开始”和“结束”。后来开始找自动记录工具,才发现这个领域有个经典难题:凡是好用的商业软件,数据都躺在别人服务器上;凡是能本地存数据的,配置门槛又让人劝退。

直到我接触了 ActivityWatch。这是个开源的时间追踪应用,核心思路就是“自动记录”——装上之后,它会通过 watcher 组件默默统计你正在使用哪个应用、浏览哪些网页、在编辑器里写了多久代码,全程不需要手动打卡。因为它是开源的,数据默认存在本地 SQLite 数据库里,隐私完全自己掌控。而且官方提供了浏览器插件、桌面端、移动端多个组件,生态虽然小众但该有的都有。

这篇内容就围绕“本地部署 + 外部访问”展开:我不只讲怎么把 ActivityWatch 跑起来,还会讲清楚外部访问的几种方案怎么选、怎么做安全加固、以及我实际跑了大半年踩过的各种坑。适合三类人看:一是想认真做时间复盘的自由职业者和远程办公族,二是有隐私敏感需求、坚持数据自托管的人,三是刚接触自托管、想找个轻量项目练手的朋友。

2. 部署前的准备:工具选型和架构认知

2.1 为什么是 Docker 部署,而不是直接跑源码

ActivityWatch 官方支持两种运行方式:直接源码运行和 Docker 容器运行。源码方式适合开发调试,因为你能看到全部日志、能改代码,但代价是要装 Python 环境、Node 环境、以及一堆前端构建工具,升级时还要自己处理依赖冲突。我第一回就是源码跑的,折腾了两个小时才把 Web UI 跑起来,后来换成 Docker 重新部署,前后不到五分钟。

如果你的目标只是“用起来”,直接选 Docker。官方镜像已经把服务端和 Web UI 打包好了,数据目录也做了持久化映射,升级时换个镜像标签就行。Docker 方式还有个好处:ActivityWatch 由多个 watcher 进程组成(比如窗口标题监听、浏览器插件、编辑器插件),容器化之后彼此隔离,出问题时单独重启一个容器就可以,不用连坐整个服务。

不过要注意,多数 watcher 组件(如浏览器插件、VS Code 插件)是装在你日常用的电脑上的,不属于 Docker 的管辖范围。Docker 主要跑的是核心服务端 aw-server、aw-webui、aw-watcher-afk 这几个角色,理解清楚这点,后面配置时才不会糊涂。

2.2 ActivityWatch 的核心架构:Watcher、Bucket、Event

在动手部署前,我建议花三分钟理解 ActivityWatch 的数据模型,后面所有配置和排查都围绕它展开。

ActivityWatch 的核心概念有三个:Watcher(采集器)、Bucket(数据桶)、Event(事件)。Watcher 负责从各种来源采集数据,比如 aw-watcher-window 会每秒记录当前活动窗口的标题和应用名,aw-watcher-browser 会通过浏览器插件记录你访问的网址。它每采集到一条数据,就把它写进一个指定的 Bucket,Bucket 相当于一个分类容器,比如“浏览器历史”是一个 bucket,“编辑器活动”是另一个 bucket。而这些具体的数据点就叫 Event,每条 Event 包含一个时间段(start 和 end)以及一段元数据(比如应用名、网页标题)。

我们部署的核心服务端,本质上就是一个接收和存储 Event 的后台服务。Web UI 则负责把这些 Event 聚合成可读的时间线。明白了这套链路,当你发现某个时间段没有数据时,排查方向就清晰了:先看 watcher 有没有在运行,再看数据有没有写入对应的 bucket,最后看 UI 查询有没有报错。

3. 本地部署 ActivityWatch 的完整实操

3.1 使用 Docker Compose 快速拉起服务端

我的部署环境是一台 Ubuntu 22.04 的迷你主机,内网 IP 是 192.168.1.100,Docker 和 Docker Compose 插件都已经装好。如果你还没装 Docker,可以先执行官方一键脚本,这里不赘述。

下面是我一直在用的 docker-compose.yml,直接保存到/opt/activitywatch/docker-compose.yml

version: "3.8" services: activitywatch: image: activitywatch/activitywatch:latest container_name: activitywatch restart: unless-stopped ports: - "5600:5600" volumes: - ./aw-data:/data environment: - AW_DIR=/data - AW_HOST=0.0.0.0

解释几个关键配置:

  • image用的是latest标签。官方在 Docker Hub 上发布的镜像会跟随版本更新,我建议第一次部署用 latest 跑通流程,稳定后固定到一个具体版本号(比如v0.13.0),避免某天升级带来不兼容变化。
  • ports将宿主机的 5600 端口映射到容器内部的 5600。ActivityWatch 默认 Web 端口就是 5600,官方文档里也提到这是不可配置的硬编码端口。
  • volumes把主机的./aw-data目录挂载到容器内的/data,这一步很关键。ActivityWatch 的所有数据库文件都在这个目录里,如果哪天容器崩了,只要这个目录还在,数据就不会丢。
  • environment里设置AW_HOST=0.0.0.0是为了让服务监听所有网卡接口,否则容器内部只有 localhost 能访问,宿主机反而访问不到。

配置写好后,直接执行:

cd /opt/activitywatch docker compose up -d

第一次启动会拉取镜像,等一两分钟。完成后执行docker compose ps,看到状态是 Up 就说明容器跑起来了。这时打开http://192.168.1.100:5600,应该能看到 ActivityWatch 的 Web 界面,左侧菜单有 Dashboard、Timeline、Buckets 等入口。

3.2 初始化与启用常用 Watcher 组件

服务端跑起来只是第一步,真正的数据采集要靠 watcher 客户端。按照使用场景,我把常用 watcher 分成三类:

  1. 桌面端 watcher(必装)aw-watcher-windowaw-watcher-afk。前者记录当前活动窗口标题和应用名,后者监听键盘鼠标的输入事件,用于判断你是否在电脑前。安装方式很简单,直接去 ActivityWatch 官网或 GitHub Release 下载对应系统的安装包即可,Windows 有 exe,macOS 有 pkg,Linux 有 AppImage。
  2. 浏览器插件(强烈推荐):ActivityWatch 官方提供了 Chrome/Firefox 扩展,装上之后需要在插件设置里填上服务端地址。默认填的是http://localhost:5600,如果你像我一样浏览器和服务端不在同一台机器上,这里要改成http://192.168.1.100:5600。改完测试连接,显示 connected 就说明浏览器访问记录可以正常上报。
  3. 编辑器插件(可选):VS Code 有 ActivityWatch 官方扩展,JetBrains 系也有第三方插件。这类插件能记录你具体在哪个文件上花了多少时间,对程序员做项目复盘非常有用。

我见过不少新手装完服务端就以为完事了,实际上电脑上的图标栏根本不会出现任何可见的程序。ActivityWatch 的 watcher 基本都是无界面静默运行的,只有在浏览器插件图标上能看到一个小弹窗。判断运行是否正常的方法是:打开 Web UI 的 Timelines 页面,等一两分钟,如果时间线上开始出现色块,说明数据已成功上报。如果什么都没有,优先检查 watcher 的配置文件和服务端地址有没有写错。

3.3 数据目录、日志与基本验证方法

数据文件都在/opt/activitywatch/aw-data下面,结构大致是这样:

aw-data/ ├── activitywatch/ │ ├── activitywatch.db # 核心数据库 │ ├── ... ├── ...

如果你要备份,只需要把整个aw-data目录压缩存档即可。我每天晚上通过 cron 任务把它增量同步到另一块硬盘,这个后面再细说。

排查问题时看日志是最快的路径。用 Docker 部署时,一条命令就能看到全部日志:

docker compose logs -f activitywatch

正常使用中,日志会定期出现 watcher 心跳和 bucketing 信息。如果看到连不上数据库、端口被占用之类的报错,就按日志提示逐一排除。有一个关键词要记住:heartbeat。ActivityWatch 的 watcher 和服务端之间通过 heartbeat 机制同步状态,正常每 10-30 秒会有一条心跳记录,如果长时间没有心跳,说明某个 watcher 掉线了,需要重启对应组件。

4. 实现外部访问:方案选型与安全加固

4.1 外部访问的需求边界:只看 vs 管理

部署好之后,我不满足于只在局域网内看数据。下班后或者出门在外,想通过手机快速看一眼今天的工时分布,这就需要从外网访问家里的 ActivityWatch。

动手之前,先想清楚一个关键问题:你外部访问的目的是什么?如果只是看数据,我建议降低权限预期——只读就够了。如果希望在外网也能管理 watcher、改配置、删 bucket,那就需要完整的 Web 访问能力。但权限越大,暴露风险越大。ActivityWatch 的 Web UI 默认没有用户认证,谁拿到地址谁就能看,所以外部访问时必须做一层身份验证,不能裸奔。

围绕这个需求,实际可行的方案有四类:

方案原理优点缺点适合场景
反向代理 + HTTPS通过 Nginx/Caddy 暴露 5600 端口,并加基础认证配置简单、可控性强需要公网 IP 或端口映射有公网 IP 的宽带用户
内网穿透工具(frp)通过一台公网服务器转发流量到内网服务不需要公网 IP多一跳、延迟略高没有公网 IP 的普通宽带
异地组网工具(Tailscale/ZeroTier)组建虚拟局域网,像访问内网一样访问服务安全、零公网暴露需要客户端安装个人设备少、追求省心
IPv6 + 端口转发通过 IPv6 地址直连不占用额外服务器移动网络 IPv6 支持不一定好网络环境支持 IPv6 的用户

4.2 推荐方案一:Caddy 反向代理加基础认证

我最终采用的是 Caddy 反向代理方案。选择 Caddy 而不是 Nginx 的原因很直接:Caddy 自动申请和续期 HTTPS 证书,不用手动处理一堆配置。如果你的服务需要通过浏览器插件上报数据,一定要走 HTTPS,否则浏览器插件在非安全上下文里会有各种限制。

Caddy 的核心配置长这样,放在Caddyfile里:

aw.example.com { reverse_proxy 192.168.1.100:5600 basicauth { timeuser $2a$14$...hashvalue... } }

其中aw.example.com替换成你自己的域名,并在 DNS 服务商那里把域名解析到你的公网 IP。basicauth是关键,它用 HTTP 基本认证保护整个站点,访问时需要输入用户名密码。密码 hash 可以用caddy hash-password命令生成:

caddy hash-password --plaintext 'YOUR_STRONG_PASSWORD'

生成的 hash 字符串填到配置里即可。这个方案的好处是:所有流量都经过 HTTPS 加密,认证由 Caddy 统一拦截,ActivityWatch 本身根本不需要感知外部认证的存在,逻辑清晰,后期维护也方便。

4.3 推荐方案二:frp 内网穿透接入

如果你没有公网 IP,frp 是另一套可靠方案。frp 的原理不复杂:你在公网服务器上运行 frps(服务端),在家里的迷你主机上运行 frpc(客户端),frpc 主动连接 frps 建立一个长连接通道,外部流量经由公网服务器转发到内网服务。

frps 的配置(公网服务器端,frps.toml):

bindPort = 7000 auth.token = "YOUR_RANDOM_TOKEN"

frpc 的配置(内网迷你主机端,frpc.toml):

serverAddr = "your-server-ip" serverPort = 7000 auth.token = "YOUR_RANDOM_TOKEN" [[proxies]] name = "activitywatch" type = "tcp" localIP = "127.0.0.1" localPort = 5600 remotePort = 5600

配置完成后,启动 frps 和 frpc,你在公网访问http://your-server-ip:5600就能连回家里的 ActivityWatch 服务了。这个方案的硬伤是:流量要绕道公网服务器,延迟会高一些,但时间追踪这种低频率页面访问完全感受不到差别。注意 frp 本身没有身份认证能力,所以上述两个方案里,我仍然建议你在 ActivityWatch 前面额外套一层 Caddy 做 HTTPS 和认证,或者至少用 frp 自带的auth.token来防止别人蹭你的代理通道。

4.4 安全加固:外部访问必须做的三件事

把服务暴露到公网后,安全这事就不是可选项,而是必选题。我分享三个自己实践中必须做的加固动作。

第一,强制 HTTPS。尤其当你用 Caddy 或 Nginx 反代时,把 HTTP 全部重定向到 HTTPS。道理很简单:时间追踪数据包含你的网页访问记录、应用使用习惯,这些都是相当私密的信息,明文传输等于把隐私直接扔在公网上。

第二,加认证授权。ActivityWatch 自身不提供多用户权限,所以必须在代理层挡一道。除了上面说的 Caddy 基础认证,你也可以用 Authelia 这类开源身份认证中间件做更细粒度的控制。如果嫌麻烦,至少设置一个强密码的 basic auth。

第三,限制来源 IP 和行为。如果条件允许,可以在防火墙规则里只允许特定国家的 IP 段访问,或者限制访问频率。Caddy 可以配合 ratelimit 模块,frp 也能在客户端限制请求频率。我的做法是:只允许常用省份的 IP 段,并且在路由器上做了连接数限制,实测至今没有异常访问记录。

注意:任何暴露到公网的服务都存在被扫描和探测的风险。ActivityWatch 本身是个人级应用,不建议把敏感数据放任在公网裸奔。如果只是想偶尔在外网瞄一眼,优先考虑 Tailscale/ZeroTier 这类组网方案,因为它们默认就不暴露任何公网端口,安全等级比端口转发高一个量级。

5. 日常使用中的问题排查与避坑总结

5.1 浏览器插件常见连接问题

我在实践过程中遇到最多的,不是服务端出问题,而是浏览器插件连不上。典型表现是:插件图标上显示 disconnected,或者数据根本没有浏览器记录。

排查流程我总结成一张速查表:

现象可能原因解决办法
插件测试连接失败服务端地址填错检查填写的地址是否带端口号,是否可访问
局域网内能连、外网连不上反代配置错误或端口未放行检查 Caddy/Nginx 日志、检查云安全组/路由端口映射
插件显示 connected 但没有数据浏览器隐私模式阻止了扩展换个普通窗口测试,或允许扩展在隐私模式下运行
数据延迟很严重Watcher 心跳间隔设置问题默认间隔是 10 秒,一般不需要改;检查服务端负载

还有一个容易踩的坑:Caddy 反代时,浏览器插件走 HTTPS 连接,但 ActivityWatch 内部是 HTTP,需要保证 Caddy 的reverse_proxy正确传递 WebSocket。时间追踪虽然不依赖 WebSocket,但有些第三方插件会用到,建议在 Caddy 的 proxy 配置里加上websocket相关的默认参数,Caddy 2 默认支持自动升级 WebSocket,不需要额外写。

5.2 数据缺失、时间偏移和统计误差

ActivityWatch 的统计不一定完全准确,这是开源工具的常态,理解它的误差来源比抱怨更有效。

数据缺失最常见的原因是 watcher 崩溃或电脑休眠。比如 aw-watcher-window 在 Linux 上依赖 X11 的窗口信息,如果你用的是 Wayland 会话,部分版本会拿不到窗口标题,数据自然就断了。解决办法是切换回 X11,或者用第三方兼容版本。另外,笔记本合盖进入休眠期间没有任何数据,这也是正常的,aw-watcher-afk 会把它归为 away 状态。

时间偏移问题往往是系统时区配置不正确导致的。ActivityWatch 存储的是 UTC 时间戳,Web UI 会根据浏览器时区显示本地时间。如果你的服务器时区设置错了,或者浏览器所在设备时区变了,看到的时间线就会整体偏移。排查方法很简单:直接在容器里执行date看系统时间,再对比 Web UI 上的时区设置。我习惯在 docker-compose.yml 的 environment 里加上TZ=Asia/Shanghai,保证数据库记录的底层时间戳和本地时间一致。

5.3 容器资源占用与长期运行的稳定性

ActivityWatch 的资源占用非常轻量。我的迷你主机配置是 4 核 8GB 内存,ActivityWatch 服务端长期占用大概 150MB 内存、CPU 平时几乎为 0,偶尔查询时爬到 20% 左右。如果你是用低配设备跑,这个负载完全在承受范围内。

长期运行最需要注意的是日志膨胀和数据库增长。Docker 默认会保留所有 stdout 日志,如果 ActivityWatch 天天跑,日志文件会越攒越大。我习惯在 docker-compose.yml 里加上日志轮转配置:

services: activitywatch: ... logging: driver: "json-file" options: max-size: "20m" max-file: "3"

数据库方面,SQLite 文件会随时间增长,但以我半年多的使用量来看,总数据量也就几十 MB,完全不需要手动清理。如果你发现自己某个 bucket 数据量异常大,可以直接在 Web UI 的 Buckets 页面删除那个 bucket,ActivityWatch 会自动重建。

5.4 升级与回滚注意事项

ActivityWatch 的迭代节奏不算快,但偶尔也会有行为变化。升级前务必先备份数据目录,我吃过一次亏:一次性从 0.11 跳到 0.13,升级后旧数据读取正常,但某个 watcher 的 bucket 结构变了,导致时间线显示不完整。

现在我的升级流程固定为:先备份aw-data,再拉取新镜像,启动后访问 Web UI 看 bucket 列表是否完整。如果发现问题,指定旧版本标签重新启动即可回滚。由于数据是独立的,回滚镜像不会影响数据完整性。

6. 数据复盘:让 ActivityWatch 真正发挥价值

6.1 用 API 拉取数据做周报统计

ActivityWatch 提供了完整的 REST API,这意味着你不需要手动去 Web UI 里一个个点,就能把数据变成自己的周报。它的 API 接口地址通常是http://localhost:5600/api/0/

我用一个简单的 Python 脚本,每周自动统计各类应用的使用时长:

import requests import datetime AW_API = "http://192.168.1.100:5600/api/0" start = datetime.datetime.now() - datetime.timedelta(days=7) end = datetime.datetime.now() # 获取窗口活动 bucket buckets = requests.get(f"{AW_API}/buckets?start={start.isoformat()}&end={end.isoformat()}").json() for bucket_id, bucket_info in buckets.items(): if "window" not in bucket_id: continue events = requests.get(f"{AW_API}/buckets/{bucket_id}/events?start={start.isoformat()}&end={end.isoformat()}").json() total_seconds = sum(e["duration"] for e in events) print(f"{bucket_id}: {total_seconds / 3600:.2f} hours")

这个脚本的精髓在最后两行:遍历所有 window bucket,把事件时长累加并按小时输出。输出结果就是你这一周在各类应用上的总耗时。配合列表里的应用名,再自己写个小组装,就能得到一个类似“本周微信 12 小时、浏览器 30 小时、编辑器 25 小时”的分布表。

6.2 数据可视化与自定义看板

官方 Web UI 的 Dashboard 已经具备了基础的分类统计,但如果你想看更多维度,比如“某个项目文件夹对应的编辑器耗时”,就得自己动手。

我的做法是:在 Grafana 里新建一个数据源,通过 ActivityWatch API 把查询结果拉进来。具体方式是写一个 cron 脚本,每 10 分钟从 API 拉一次最新数据写入 MySQL,然后 Grafana 直接查 MySQL。这样就能在手机上随时打开一个漂亮的看板,直观看到当天工作时间、最耗时的应用、以及连续工作多少分钟需要休息。

不过说句大实话,这套联动方案适合喜欢折腾的人。多数用户用官方 Web UI 就足够了,它提供的按标签颜色分类的时间线已经非常直观,没有必要为了“看起来高级”而引入额外组件。

6.3 多设备统一收集与合并

ActivityWatch 支持多设备数据汇总到同一个服务端。我在公司电脑和家里迷你主机上都装了 watcher,两边的数据通过同一个服务端地址上报。Web UI 上会自动按设备名拆分成不同的 bucket,查询时可以把所有设备的数据合并成一个时间线。

这里有一个细节:每台设备在安装 watcher 时,生成的 device 名默认是主机名。如果你有好几台设备,建议在安装时就把 device 名改成辨识度高的名字,比如work-laptophome-mini。否则后续看数据时,你会分不清哪条时间线是哪台机器上的。这个修改在 Web UI 的 Buckets 页面就能操作,不需要改配置文件。

7. 我持续使用半年后的一些真实体会

如果只看安装部署,ActivityWatch 算不上一款“开箱即用”的工具,它需要你花时间去理解 watcher、bucket 这些概念,也需要你去配置外部访问的安全策略。但它的价值恰恰在这份动手折腾里。商业时间追踪软件给你一个完整闭环,却把数据锁在云端;ActivityWatch 把整个链路摊在你面前,数据、逻辑、扩展点全部透明,你能按照自己的实际需求改造它。

我最满意的一次实践是:有段时间觉得自己每天很忙,但不知道忙什么。跑了一周 ActivityWatch 统计后发现,浏览器时间占比高达 55%,其中视频平台占了三分之一。这个数据让我下意识地调整了工作习惯,把视频类站点挪到另一台闲置设备上,工作电脑只保留生产力工具。第二周再看统计,有效工作时间肉眼可见地涨了一截。这类“原来时间都去哪了”的观察,就是时间追踪工具最大的价值。

回到外部访问这件事,我目前的最终方案是 Caddy + Tailscale 同时跑。Caddy 管公网 HTTPS 访问,Tailscale 管手机和家用设备之间的安全回连。两套方案互不干扰,也不存在单点故障。如果你刚上手,我建议先按最简方案走:Docker 跑服务端、本地浏览器装好插件、局域网内看数据。等完全熟悉了,再考虑反代和外网访问。数据是自己的,服务是自己的,慢慢搭建的过程本身也是自托管乐趣的一部分。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 8:55:48

选行业网站模板别被坑,3个免费工具搞定

选行业网站模板别被坑,3个免费工具搞定 找建站公司报价两万八,自己用免费工具半天搞定?这反差太真实。很多湖北的创业团队负责人都吃过这个亏,花大价钱买的“定制开发”,其实套了个老掉牙的行业网站模板。别被销售话术忽悠,懂行的人都知道,模板是基础,落地能力才是关键。 为什么行业网站模板成了建站首选…

作者头像 李华
网站建设 2026/9/15 8:54:55

如何解决顽固高AI率?实测8款热门降AI工具,附3个核心降AI技巧

如果你的论文AIGC初检在85%以上,你会懂什么叫"顽固":普通工具降一遍掉到60%,再降一遍卡在40%,怎么都压不下去,眼看交稿日期一天天近。我拿一篇初检92%的药学论文实测了8款热门降AI工具,把"顽…

作者头像 李华
网站建设 2026/9/15 8:50:59

网站建设AG实战:搞定域名服务器,3天上线最佳实践

网站建设AG实战:搞定域名服务器,3天上线最佳实践 域名选好了吗?服务器配置看懂了吗?别急,90%的老板在这一步就卡住了。 很多广东的中小企业主找我咨询网站建设AG项目时,第一句话往往是:“老师,我预算够,但域名和服务器太复杂,我怕被坑。”…

作者头像 李华
网站建设 2026/9/15 8:47:17

Vue 3 响应式详解:ref 与 reactive 的底层原理、使用场景与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 8:46:32

重装系统工具实测对比:9款免费U盘制作工具安全与兼容性分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 8:45:35

VCSA安装深度指南:vCenter Server Appliance部署三阶段精解

1. 这不是“点下一步”的安装,而是给vCenter Server Appliance做一次精准手术你搜“VMware vCenter Server Appliance 安装”,页面上大概率会跳出一堆标题党:“5分钟搞定!”、“手把手保姆级教程!”、“小白也能装&…

作者头像 李华