Directus实战-使用篇

本篇文章的实战方向就以本站点功能为导向

文章大部分比较简单,最难理解的地方是决策和角色部分,这部分逻辑和安全令牌等功能结合在一起比较绕,需要好好想一下逻辑。

1、建表

E99e5401 A98e 498a 8a8e 71f9deff0b8d (1)

强烈建议勾选的

  • 创建于 (date_created):

    • 作用: 自动记录这篇文章是哪年哪月哪日几点几分创建的。

    • 为什么建议选: 博客文章肯定需要显示“发布时间”对吧?勾选这个,你每次新建文章,系统自动打上时间戳,前端直接调取显示即可。

  • 更新于 (date_updated):

    • 作用: 只要你修改了这篇文章,系统会自动把这个字段更新为当前最新时间。

    • 为什么建议选: 前端可以用来显示“最后修改于 2026-06-05”。

2. 看你需求勾选的

  • 已存档 (archived):

    • 作用: 相当于“草稿箱”或者“软删除”。

    • 为什么选: 如果你写文章写了一半不想发布,或者想下架一篇文章但不想彻底删除它,勾选这个。你在前端调用 API 时,只需过滤掉被存档的文章即可。

  • 排序 (sort):

    • 作用: 允许你在后台用鼠标拖拽来改变文章的先后顺序。

    • 为什么选: 对于“博客”来说,通常按时间倒序排列就够了,这个可以不勾。但如果你以后建“产品 (Product)”表,强烈建议勾选这个,因为产品经常需要手动调换展示顺序。

3. 可以不勾选的(多用户协作项)

  • 创建自 (user_created) & 更新,由 (user_updated):

    • 作用: 记录是哪个后台账号写了/改了这篇文章。

    • 为什么不选: 因为这是你个人的博客和官网,后台只有你一个人用,不需要记录是谁写的。如果是企业很多人一起管后台,那这个必选。

2、创建字段

在设置里能看到你的模型(表)

Screen Shot 2026 07 11 200241 736

点开表就能进行字段设置

Screen Shot 2026 07 11 200611 127

够简易吧 都不需要你自己设置字段类型了 直接选择就行 不过具体的还需要你自己稍微了解一下

比如我的文章分类字段 category 就是用的下拉列表 

翻译有点让人看不懂 我这边还是建议去使用英文界面

比如富文本编辑器就是”所见即所得“选项,其实就是”WYSIWYG“了啦,不知道怎么翻译的。

Screen Shot 2026 07 11 201036 260

下面基本上都会给你一个Content Translations 翻译选项

这个也好理解

正文是 你好

你在这下面写上翻译 Hello

两种语言两种标识 zh 和 en

当你界面有翻译按键时候 中文就请求zh标识内容 英文就请求en标识内容

Screen Shot 2026 07 11 201843 307

创建好之后保存就可以到内容界面进行添加字段

Screen Shot 2026 07 11 202135 735

 

2、开放 API 读取权限(关键)

 

860c8cb7 86d4 4694 8890 4005f940e729

 

逻辑可以简单理解成

1、你是什么角色(身份)?
2、你的身份你能干什么 ?(应用策略)

比如游客访问api(用户身份),游客只有查看的权限(应用策略),但是管理员用户通过api有更新和删除的权限。

Screen Shot 2026 07 11 203324 792

用户角色里面有个默认的”公开“角色

备注也说明了 不需要token验证

Screen Shot 2026 07 11 203416 951

点进去能看到这个”公开“的角色有一个”图片公开“的策略

这是我自己设置的 因为图片也需要token验证才能获取的话非常容易泄露你的验证令牌 非常不建议这样做

3、API链接

39a79ca1 1910 4edb Bb8f 814213939322

简单来说就是

你创建了 blog 表

你的域名/items/表名 就能获取到你那张表的全部JSON数据

Screen Shot 2026 07 11 204557 757

当然还有别的玩法

比如

https://域名/items/表名?filter[archived][_eq]=false&fields=id,title,article,categore

这种筛选数据的用法

详看Directus的官网文档

逻辑很简单的

 

4、如何添加安全验证的TOKEN令牌?

这个也好搞

第一步:在 Directus 制造“钥匙”并上锁

这个挺方便的,相比起以前的做法

只需要两步

1. 创建一个账号并生成 Token

  1. 登录 Directus 后台

  2. 点击左侧菜单的用户目录

  3. 点击右上角 + 创建用户

  4. 名字随便填,比如叫 Frontend。不需要填邮箱和密码

  5. 最关键的一步: 在用户资料页面往下滚,找到 Token 这一项

  6. 你会发现说保存用户会自动生成TOKEN,保存之后再回来就能看到

微信图片 20260711205442 26 28

2. 创建一个对应权限策略

  1. 设置好对应表的权限
  2. 在底部分配刚刚的账户

Screen Shot 2026 07 11 205949 086

Screen Shot 2026 07 11 205925 261

然后就可以在postman里面进行测试即可

微信图片 20260711210239 27 28

 

完结


相关文章

用 Astro 做工业官网

我用 Astro 做了 LIANXIN 的工业机械官网,里面有产品目录、工厂展示,也接了 Directus 新闻和 AI 产品顾问。做这种网站,很多选择都落在同一个问题上:哪些内容应该直接送到用户面前,哪些功能等用到的时候再启动。 机器图片、参数表、介绍文字适合提前生成;新闻要能随时更新;轮播、咨询和视频又各有自己的交互。把这些边界拆清楚,后面的实现会顺很多。 官网现用的工厂主题海报。来源:LIANXIN 官网。 页面先到,交互按需启动 Astro 比较合我胃口的一点,是它允许我从 HTML 开始组织页面。产品介绍和图片这些内容先渲染出来,需要状态和事件的地方再接 React。装了 React 集成,也不用把整页都做成客户端应用。 本站导航用 client:load,页面加载时就激活;产品轮播用 client:visible,进入视口再加载和水合。两种方式都可以先输出 HTML,区别在于何时让组件在浏览器里运行。具体触发时机可以看 Astro 的客户端指令文档。 FAQ 更进一步,用了项目自己注册的 client:interaction。鼠标移入、触摸按下或键盘聚焦时开始加载。这里有个小坑:用户可能在加载结束前就点了按钮,所以指令会拦住这次点击,等组件就绪再补发。普通链接照常跳转。省 JavaScript 可以,别把第一次点击也省了。 新闻更新走另一条路。列表和详情按请求读取 Directus,首页的最新新闻则交给 server:defer。首页先返回主体和占位内容,新闻区块随后单独请求 HTML。这样 CMS 响应慢一些,也不会拖住整个首页。这部分需要服务端,我用 Node adapter 的 standalone 模式运行站点。 Astro 官方原理图,说明静态页面与动态区块如何分别取得内容。来源:Astro 5.0,&copy; Astro;此图并非本站部署架构图。 产品页和 AI 共用一份资料 产品有不同系列,每个型号又有图片、参数和应用说明。如果这些东西散在页面里,改一项参数就得挨个找。我把产品整理成 TypeScript 数据,再让页面读取它。型号详情用同一份模板,通过 getStaticPaths() 生成路由。 这是详情页里的路径生成部分,省略了导入和页面模板。 export function getStaticPaths() { return products.map((product) => ({ params: { category: product.category, slug: product.slug, }, props: { product, category: getCategory(product.category), }, })); } 参数表读这份数据,页面里的 Product 结构化数据也读它。AI 产品知识同样从这里生成,避免官网改了规格,顾问还在背旧版本。数据模型里保留型号、分类、图片和规格这些明确字段,页面只负责把它们展示出来。 AI 后端是独立的 Cloudflare Worker。它根据问题里的型号、别名和当前页面检索资料,最多选六份交给 DeepSeek,再检查回答附带的来源 ID 是否属于这批资料。浏览器拿到的是回答和对应的站内链接,模型密钥留在 Worker。 这种检索方式规模小、规则直接,适合目前这批产品。它能约束资料来源,不能保证模型每句话都对,具体选型和报价仍要人工确认。另外,共用源文件不等于自动同步上线。产品资料改动后,主站和顾问 Worker 都需要重新构建部署,这个步骤不能漏。 图片讲构图,视频讲时机 工业设备本来就长,外面再套几层大边框,能看清的机器只会越来越小。产品图这里用 object-fit: contain,保留完整外形;标题、卖点和按钮放到旁边,让图片有足够的展示面积。轮播控制留在左右两侧,翻图时不用往下找。 IBM 80E 的展示图,机身轮廓完整保留。来源:LIANXIN 对应型号页。 首页海报则准备了横、竖两版,用 <picture> 按 max-aspect-ratio: 1/1 切换。选图依据是视口形状,竖屏平板也能得到竖版构图。首张海报优先加载,后面的图延迟加载。文案目前也在海报里,换来的排版控制更直接,代价是改文字和做多语言都要重新出图。 视频的处理更干脆。工厂介绍先展示封面,视频地址放进 data-src,点击播放时才赋给 src。访问者只是看看页面,就不用顺手下载一段几分钟的视频。 播放函数中的关键动作如下,省略了加载提示、超时和错误处理。 if (!video.hasAttribute("src")) { video.src = video.dataset.src!; } void video.play(); 这一块用原生 <video> 和一个自定义元素管理播放状态,就够用了。网络慢时显示加载提示,失败后给出重试按钮和原视频链接;离开组件时中止事件监听并暂停视频。用户至少能知道点下去之后发生了什么,也有办法继续操作。

2026/9/7·技术分享
用 Astro 做工业官网

用 Android 做疲劳检测

我做了一个 Android 疲劳提醒应用,用前置摄像头观察闭眼和张嘴,在手机上完成检测。模型接进来以后,真正需要想清楚的是后面的判断。眨一下眼就报警,提醒很快会变成噪声;摄像头看不清了还显示正常,又会让人误解系统的能力。 先把眼睛和嘴巴量出来 项目用的是 ML Kit Face Detection,模型随 APK 打包,安装后不用再等模型下载。它提供人脸轮廓、嘴部关键点和睁眼概率,疲劳规则由应用自己实现。这样检测和判定就能分开,调整持续时间不用动相机代码。 模型负责提取人脸信息,什么时候提醒,由后面的规则决定。插画来自 Google ML Kit 官方文档。 眼睛用 EAR,也就是眼睛的纵横比。从眼轮廓里选六个点,把两段上下眼睑距离相加,再除以两倍眼宽。计算式是 EAR =(上下一组眼睑距离 + 另一组眼睑距离)&divide;(2 &times; 眼宽)。闭眼时高度变小,EAR 通常也会下降。用比例可以减轻人脸远近带来的尺度变化,但侧脸、遮挡和关键点偏移仍然会影响结果。 Google ML Kit 的官方轮廓示例,点图可查看原图。眼睑和嘴唇的点要分清,本文的 MAR 量的是唇外沿。这是官方示例,不是本应用实测截图。图片来源。 嘴巴用 MAR。这个项目取上唇外上沿中心到下唇外下沿中心的距离,除以左右嘴角距离。公式看着简单,取点位置却不能含糊。量唇外沿和量嘴巴内部开口,算出来的数不会一样,网上找到一个阈值直接抄过来,很可能对不上。 眼部还保留了 ML Kit 的睁眼概率,与 EAR 做 OR 判断,任一路满足条件就进入对应计时。概率这一路要求左右眼的值都有效。这样能让两路信号各自参与,但也意味着单路误差就可能触发候选;它们来自同一个检测器,不能当成两套独立证据。嘴部单独判断,眼睛暂时不可用时,有效的 MAR 仍然可以参与检测。 一次越线,还不能算一个动作 单帧只知道这一刻眼睛有多窄、嘴张得有多大。要把眨眼、短暂张嘴和持续动作分开,还得加上时间。当前普通闭眼条件是 EAR &le; 0.22,或两眼概率都有效时任一眼低于 0.35,持续 800 ms 后进入 WARNING。更强的闭眼条件是 0 < EAR < 0.17,或两眼概率都低于 0.35,持续 400 ms 就进入 DANGER,且优先级更高。 哈欠候选用的是双阈值。MAR 超过 0.40 才开始计时,开始后只要不低于 0.35 就继续,累计达到 800 ms 才提醒。假设数值在 0.41、0.39、0.42 之间晃,单一阈值会让计时反复归零。嘴还张着,计时器已经替你闭上了。 代码里的关键分支只有几行。下面节选自判定逻辑,省略了无效值检查和后续计时。 val yawning = mar != null && if (highMarStartMs == null) { mar > config.marYawnEnterThreshold // 0.40 } else { mar >= config.marYawnExitThreshold // 0.35 } 时间取相机帧的时间戳,不取模型回调完成的时刻。否则推理这次慢一点、下次快一点,也会混进动作时长。相邻有效观测间隔超过 1.5 秒时,未完成的计时清零,从当前帧重新开始。中间没有画面,系统就没有依据把两次张嘴拼成一次连续动作。这个间隔也是工程取舍,不能证明采样之间发生了什么。 看不清,就别继续报正常 判定器除了 NORMAL、WARNING 和 DANGER,还留了 DEGRADED。没有人脸、眼嘴信号全部无效,或检测到黑暗画面、相机异常时,就清除未完成计时,显示当前无法可靠检测的原因。NORMAL 也只表示当前有效信号没有达到提醒条件,不能解释成驾驶员一定清醒。 相机侧通过 acquireLatestImage() 取最新分析帧,当前会话已有推理任务时,新帧直接释放,避免越算越落后。停止检测或切到后台时,会话编号递增;旧任务即使晚点返回,也不能覆盖新的状态。重新开始检测后,同样要从新画面重新计时。 声音和振动只由 DANGER 触发,WARNING 只更新界面。危险告警做了约两秒冷却,并用不重放历史事件的 SharedFlow 发送;界面只在前台恢复状态下接收,暂停时停止提示。否则回到应用突然补响一声,提醒的就成了过去的自己。 目前这套实现仍是固定阈值的研究原型,没有个人校准。持续张嘴也可能来自说话,睁眼概率还有正脸角度限制。当前手机端只在模拟器上验证了安装、相机链路和前后台切换,真人识别、覆盖层精度与声音振动还需要目标手机实测。接下来更值得做的是用正常说话、短张嘴、自然哈欠和闭眼录像,在静止环境里检验误报与漏报;这套原型还不能当作经过道路验证的驾驶安全系统。

2026/9/7·技术分享
用 Android 做疲劳检测

MediaPipe 手势识别的几个坑

这次用鲁班猫 3 做了个离线手势识别,系统是 Android 14。摄像头看到手就画出骨架,比个 OK,自动保存一张带骨架的截图。 模型直接用 Google 的 MediaPipe。它已经能找出手部的 21 个关键点,还带七种静态手势分类。自己要处理的是相机、画面坐标,以及识别结果怎么变成实际操作。 模型用现成的 Android 用 Kotlin 写,相机接 CameraX,识别接 MediaPipe Tasks。依赖用这几项。 def cameraxVersion = '1.4.2' implementation "androidx.camera:camera-core:$cameraxVersion" implementation "androidx.camera:camera-camera2:$cameraxVersion" implementation "androidx.camera:camera-lifecycle:$cameraxVersion" implementation 'com.google.mediapipe:tasks-vision:1.0.0' 把官方模型放进 app/src/main/assets,创建识别器时指定这个文件,运行模式设为 LIVE_STREAM,通过回调拿结果。官方 Android 示例已经有完整接法,照着看比从空白工程硬猜快。 模型跟着 APK 一起打包,推理在板子上完成,运行时只需要相机权限。 底图来自 MediaPipe 官方测试图片,这是本项目的板端测试输出。红点是关节点,蓝线标出拇指,其余连线用绿色。 相机别开两路 CameraX 常见的接法是 Preview 显示画面,ImageAnalysis 给模型送帧。但在我这块 RK3576 板子的固件上,两路一起开会卡住。 最后只保留一条 ImageAnalysis,预览和识别共用它。拿到 1920&times;1080 的图像后,处理行步幅,把最长边缩到 640 像素,再统一旋转和镜像,送进模型。 帧策略用 KEEP_ONLY_LATEST。处理不过来就丢旧帧,别让识别排队。当前代码还限制了至少 100 ms 才提交一帧,所以提交速率最高约每秒 10 帧,实际显示速度还得看推理回调。 ImageProxy 用完一定要 close,跳过帧和异常分支也一样。 缓冲区占着不放,相机后面就可能没帧了。 另外,板子上的 CAM0、Android 的 Camera ID 0 和 /dev/video0 要分别核对。这个项目同时检查物理 m00_ 模块、逻辑 ID 0 和当前固件的 FRONT 属性,条件不满足就停。这套映射只针对已经验证过的板子和固件。 骨架为什么会飘 这个问题得从坐标和时间两头查。 坐标上,模型给的是归一化关键点,预览用的却是 centerCrop。图片会先放大,再裁掉超出显示区域的部分。直接拿关键点乘屏幕宽高,当然对不上。 把关键点投到屏幕上,要和预览用同一个缩放比例和裁切偏移。下面的 x、y 是模型返回的归一化坐标,srcW、srcH 是模型输入图像的宽高。 scale = max(viewW / srcW, viewH / srcH) offsetX = (viewW - srcW * scale) / 2 offsetY = (viewH - srcH * scale) / 2 screenX = x * srcW * scale + offsetX screenY = y * srcH * scale + offsetY 这些除法要用浮点数。旋转和镜像也统一在推理前处理,别让预览和模型各算各的方向。 时间上,手已经移走了,上一帧的结果才回来。把旧骨架叠到新画面,多少有点灵魂出窍。 我的处理是从结果回调里取出对应的输入图片,和这次关键点一起更新到界面。画面和骨架必须属于同一帧。 代价是显示会等识别结果,预览流畅度也跟着受限。 还有一个容易漏的判断。分类结果是 None,只代表没认出支持的手势。只要关键点还在,骨架就继续画;没检测到手、结果过期或者切到后台时,再清掉。 OK 截图要防连拍 官方这七种分类没有 OK,我用现有关键点补了一层几何判断。拇指和食指指尖靠近,食指弯曲,另外三根手指伸直,才算匹配。 距离按掌部尺寸归一化,再结合关节角度判断。用固定像素距离的话,手往前伸一点,阈值就不合适了。这里用的是按输入宽高还原后的 2D 坐标,和画面里的骨架保持一致。 然后才是触发控制。视频每帧都可能认出 OK,你一直举着手,就一直存图,相册受不了这个。 判断 当前条件 确认手势 最近最多 5 帧中至少 4 帧强匹配,当前帧也满足,窗口持续至少 300 ms 触发后锁定 保持 OK 只拍一张 允许再拍 离开 OK 至少 600 ms,两次触发至少间隔 1.5 秒 触发条件严一点,保持条件宽一点,减少边界抖动。采样断开超过 400 ms,就清掉旧的观察窗口。这些是当前配置,实际触发时间还受帧率影响。 截图直接合成当前画面和同帧骨架,再用 MediaStore 存成 PNG。只画这两层,状态栏和提示框就不会混进去。编码和写盘放到独立线程,别堵着相机识别。 保存的是当前显示画面的合成图,输入已经缩小过,不能当成传感器原图。 这版配置的还是 Delegate.CPU。RK3576 有 NPU,但应用得接入 RKNN 才用得上。RKNN 的官方流程包括模型转换和运行时接入,前后处理也要重新对齐,光改一个配置没用。

2026/9/7·技术分享
MediaPipe 手势识别的几个坑
听歌