包含关键字 typecho 的文章

一行代码,让官网拥有智能客服

深夜十一点,我习惯性地打开公司官网,想了解最新的产品信息。页面右下角突然弹出一个对话框:"您好,我是智能客服小六子,有什么可以帮您?"

那一刻,我愣住了。这完全不像传统的客服机器人——它准确理解了我的问题,从官网内容中找到了相关解答,甚至还提供了原文链接供我参考。

传统客服的困境

曾几何时,企业官网的客服体验令人沮丧。要么是千篇一律的"您好,请问有什么可以帮您",要么就是漫长的等待人工回复。用户的问题往往石沉大海,而企业也在重复的问答中消耗着人力成本。

更让人头疼的是技术门槛。很多企业想要部署智能客服,却面临着复杂的开发流程、高昂的技术投入。最终,要么放弃,要么选择功能简陋的解决方案。

技术革新的曙光

就在这样的背景下,访答智能客服网页版出现了。它最大的魅力在于——真的只需要一行代码。

我亲眼见证了一家创业公司在五分钟内完成了部署:将生成的代码片段粘贴到官网HTML中,刷新页面,一个功能完整的智能客服就诞生了。没有技术团队介入,没有复杂的配置流程。

智能背后的秘密

访答的核心在于深度优化的中文RAG技术。与传统的关键词匹配不同,它能够理解用户问题的上下文意图,从官网内容中精准提取相关信息。

更令人惊喜的是它的多模态识别能力。官网中的产品图片、参数图表、活动海报,这些视觉信息都能被系统理解并融入回答逻辑。当用户询问产品规格时,客服不仅能提供文字说明,还能关联展示相关的产品图片。

从部署到优化

整个使用流程简单得令人难以置信:输入官网地址,系统自动爬取并构建知识库;生成嵌入代码;粘贴到网站。整个过程一气呵成。

当网站内容更新时,企业只需一键更新知识库,前端界面无需任何改动。这种设计考虑到了企业实际运营中的需求——内容迭代是常态,而技术维护应该尽可能简化。

不仅仅是客服

访答的价值远不止于回答用户问题。它的溯源参考导航功能,让每个回答都有据可循——自动返回官网原文链接,既增强了回答的可信度,也引导用户深度浏览网站。

对于企业而言,这不仅是客服成本的降低,更是品牌形象的提升。一个能够准确理解用户需求、提供专业解答的智能客服,本身就是企业技术实力的展示。

未来的想象

随着技术的不断进步,智能客服正在从"辅助工具"向"核心交互界面"转变。访答的出现,让更多企业能够轻松拥抱这一趋势。

现在,当我再次访问那些部署了智能客服的企业官网时,感受到的不再是冰冷的自动化回复,而是有温度的专业服务。技术,正在让沟通变得更加简单、高效。

或许在不久的将来,"官网是否需要智能客服"将不再是一个选择题,而是企业数字化的基本配置。而访答,正在让这一天提前到来。

前言

802.1X协议的背景

早期的IEEE 802 LAN协议中,只要用户可以接入局域网的控制设备(例如接入交换机),就可以访问局域网中的设备或资源,这无疑是存在安全隐患的。为解决无线局域网的安全问题,IEEE 802委员会提出了802.1X协议。802.1X协议可以控制用户的网络访问权限,防止身份不明或未经授权的用户传输和接收数据。由于802.1X协议的普适性,因此后来也广泛应用于有线局域网。

与其他接入控制机制不同,802.1X协议是通过控制接入端口,实现用户级的接入控制。在802.1X协议中,物理接入端口被划分为“受控端口”和“非受控端口”这两个逻辑端口,用于实现业务与认证的分离。非受控端口主要用于传递EAPOL协议帧,始终处于双向连通状态,保证客户端始终能够发出或接收认证报文;而受控端口用于传递业务报文,因此在授权状态下处于双向连通状态,在非授权状态下不从客户端接收任何报文。

换言之,基于802.1X协议的认证,其最终目的就是确定用户的接入端口是否可用。如果认证成功,那么就打开端口,允许客户端的所有报文通过;如果认证不成功,就保持端口的关闭状态,只允许EAPOL协议帧通过。

<!--more-->

什么时候需要使用802.1X?

通常在新建网络、用户集中或者信息安全要求严格的场景中使用802.1X认证。802.1X认证具有以下优点:

  • 对接入设备的性能要求不高。802.1X协议为二层协议,不需要到达三层,可以有效降低建网成本。
  • 在未授权状态下,不允许与客户端交互业务报文,因此保证了业务安全。

以企业网络为例。员工终端一般需要接入办公网络,安全要求较高,此时推荐使用802.1X认证。

但802.1X认证要求客户端必须安装802.1X客户端软件。在机场、商业中心等公共场所,用户流动性大,终端类型复杂,且安全要求不高,可以使用Portal认证。对于打印机、传真机等哑终端,可以使用MAC认证,以应对哑终端不支持安装802.1X客户端软件,或者不支持输入用户名和密码的情况。

802.1X是如何工作的?

如下图所示,802.1X认证系统为典型的Client/Server结构,包括三个组件:客户端、接入设备和认证服务器。

 title=802.1X系统中的组件

  • 客户端通常是用户终端设备。客户端必须支持局域网上的可扩展认证协议(Extensible Authentication Protocol over LANs,EAPoL),并且安装802.1X客户端软件,从而使用户能够通过启动客户端软件发起802.1X认证。
  • 接入设备通常是支持802.1X协议的网络设备,例如交换机。它为客户端提供接入局域网的端口,该端口可以是物理端口,也可以是逻辑端口。
  • 认证服务器用于实现对用户进行认证、授权和计费,通常为RADIUS服务器。

在用户终端安装802.1X客户端软件后,用户可向接入设备发起认证申请。接入设备和用户终端交互信息后,把用户信息发送到认证服务器进行认证。若认证成功,则接入设备打开与该用户相连的接口,允许其访问网络;若认证失败,则接入设备将不允许其访问网络。

802.1X认证系统使用可扩展认证协议(Extensible Authentication Protocol,EAP)来实现客户端、设备端和认证服务器之间的信息交互。EAP协议可以运行在各种底层,包括数据链路层和上层协议(如UDP、TCP等),而不需要IP地址。因此使用EAP协议的802.1X认证具有良好的灵活性。

  • 在客户端与接入设备之间,EAP协议报文使用EAPoL(EAP over LANs)封装格式,直接承载于LAN环境中。
  • 在接入设备与认证服务器之间,可以采用EAP终结方式或者EAP中继方式交互认证信息。

    • EAP终结方式:接入设备直接解析EAP报文,把报文中的用户认证信息封装到RADIUS报文中,并将RADIUS报文发送给RADIUS服务器进行认证。EAP终结方式的优点是大多数RADIUS服务器都支持PAP和CHAP认证,无需升级服务器;但对接入设备的要求较高,接入设备要从EAP报文中提取客户端认证信息,通过标准的RADIUS协议对这些信息进行封装,且不能支持大多数EAP认证方法(MD5-Challenge除外)。
    • EAP中继方式:接入设备对接收到的EAP报文不作任何处理,直接将EAP报文封装到RADIUS报文中,并将RADIUS报文发送给RADIUS服务器进行认证。EAP中继方式也被称为EAPOR(EAP over Radius)。EAP中继方式的优点是设备端处理更简单,支持更多的认证方法;缺点则是认证服务器必须支持EAP,且处理能力要足够强。

以客户端发送EAPoL-Start报文触发认证为例,EAP中继方式的802.1X认证流程如下图所示。

 title=EAP中继认证流程

  1. 客户端发送EAPoL-Start报文触发802.1X认证。
  2. 接入设备发送EAP请求报文,请求客户端的身份信息。
  3. 客户端程序响应接入设备发出的请求,将身份信息通过EAP响应报文发送给接入设备。
  4. 接入设备将EAP报文封装在RADIUS报文中,发送给认证服务器进行处理。
  5. RADIUS服务器收到接入设备转发的身份信息后,启动和客户端EAP认证方法的协商。RADIUS服务器选择一个EAP认证方法,将认证方法封装在RADIUS报文中,发送给接入设备。
  6. 接入设备收到RADIUS报文,将其中的EAP信息转发给客户端。
  7. 客户端收到EAP信息,解析其中的EAP认证方法。如果支持该认证方法,客户端发送EAP响应报文给接入设备;否则,客户端在EAP响应报文中封装一个支持的EAP认证方法,并发送给接入设备。
  8. 接入设备将报文中的EAP信息封装到RADIUS报文中,并发送RADIUS报文到RADIUS服务器。
  9. RADIUS服务器收到后,如果客户端与服务器选择的认证方法一致,EAP认证方法协商成功,开始认证。以EAP-PEAP认证方法为例,服务器将自己的证书封装到RADIUS报文中,通过接入设备发送给客户端。客户端与RADIUS服务器协商TLS参数,建立TLS隧道。TLS隧道建立完成后,用户信息将通过TLS加密在客户端、接入设备和RADIUS服务器之间传输。
  10. RADIUS服务器完成对客户端身份验证之后,通知接入设备认证成功。
  11. 接入设备向客户端发送认证成功报文,并将端口改为授权状态,允许用户通过该端口访问网络。

以客户端发送EAPoL-Start报文触发认证为例,EAP终结方式的802.1X认证流程如下图所示。

 title=EAP终结认证流程

EAP终结方式与EAP中继方式的认证流程相比,不同之处在于EAP认证方法协商由客户端和设备端完成,之后设备端会把用户信息送给RADIUS服务器,进行相关的认证处理。而在EAP中继方式中,EAP认证方法协商由客户端和服务器完成,设备端只是负责将EAP报文封装在RADIUS报文中透传认证服务器,整个认证处理都由认证服务器来完成。

简介

1. 802.1X认证简介

  • 定义:基于端口的网络接入控制协议(Port-Based NAC)。
  • 优势:工作在二层,不依赖三层IP地址,降低网络建设成本;认证报文与数据报文分离,提高安全性。

2. 系统架构

  • 三大组成部分:

    • 客户端(Supplicant):用户终端设备,运行802.1X客户端软件。
    • 接入设备(Authenticator):如交换机、无线接入点,负责转发认证信息。
    • 认证服务器(Authentication Server):通常为RADIUS服务器,执行认证、授权和计费。

3. 协议与报文

  • EAP协议:可扩展认证协议,支持多种认证方式(EAP-TLS、EAP-TTLS、PEAP等)。
  • EAPoL:在LAN环境中传输EAP报文的封装格式。
  • EAPoR:通过RADIUS传输EAP报文的方式。

4. 认证流程

  • 触发方式:客户端发送EAPoL-Start,或设备主动发起EAP-Request/Identity。
  • 交互过程:客户端与接入设备交换身份信息,接入设备与RADIUS服务器完成认证。
  • 结果:认证成功则端口进入授权状态,失败则拒绝访问。

5. 授权机制

  • 常见授权参数:

    • VLAN:动态分配用户所属VLAN。
    • ACL:基于访问控制列表限制用户流量。
    • UCL组:按用户组策略进行统一管理。
  • Free-rule:在认证前允许用户访问特定资源(如注册页面)。

6. 高级功能

  • 重认证:周期性或手动触发,确保用户权限实时更新。
  • 下线检测:通过握手报文、ARP探测或RADIUS控制,及时感知用户下线。
  • 定时器控制:包括认证请求超时、MD5挑战超时、静默定时器等,用于优化认证过程。

交换机802.1X配置

Radius环境

  • 将客户机系统+网卡驱动和接入交换机系统更新到最新稳定版本。
  • Radius服务器使用Windows Server 的NPS角色
  • 使用Radius服务器根据用户组/计算机组动态下发VLAN到交换机

AD+Radius服务器搭建:https://songxwn.com/categories/AD/

华为交换机配置802.1X认证

命令配置示例

###阶段1### RADIUS服务器配置

radius-server template NPS-server
# 创建一个名为 NPS-server 的 RADIUS 服务器模板


radius-server shared-key cipher Songxwm.com
# 设置 RADIUS 服务器的共享密钥(加密形式),需与 NPS 服务器配置一致


radius-server authentication 192.168.99.200 1812
# 指定 RADIUS 服务器的 IP 地址和认证端口(默认 1812)



###阶段2### AAA与域配置

aaa
# 进入 AAA 配置模式


authentication-scheme radius
# 创建一个名为 radius 的认证方案


authentication-mode radius
# 设置认证模式为 RADIUS


domain songxwn.local
# 创建一个名为 songxwn.local 的认证域


authentication-scheme radius
# 将该认证域绑定到 radius 认证方案


accounting-scheme default
# 使用默认的计费方案


radius-server NPS-server
# 将该认证域绑定到 NPS-server RADIUS 模板



###阶段3### 802.1X接入配置文件

dot1x-access-profile name dot1x_access_profile
# 创建一个名为 dot1x_access_profile 的 802.1X 接入配置文件



###阶段4### 认证配置文件

authentication-profile name NPS
# 创建一个名为 NPS 的认证配置文件


dot1x-access-profile dot1x_access_profile
# 将 dot1x_access_profile 绑定到 NPS 认证配置文件


access-domain songxwn.local force
# 强制使用 songxwn.local 域进行认证



###阶段5### 接口绑定配置

interface GE2/0/12
# 进入接口 GE2/0/12 的配置模式


port link-type hybrid
# 设置该端口为 hybrid 类型(既可承载接入 VLAN,又可承载业务 VLAN)


authentication-profile NPS
# 在该端口应用 NPS 认证配置文件,实现基于 RADIUS 的 802.1X 认证

来宾VLAN

当用户接入端口但未通过 802.1X 认证时,交换机会自动将其放入一个指定的 VLAN(通常是隔离的网络,只能有限资源,如AD),避免完全断网可认证逃生。

dot1x guest-vlan 20
# 配置来宾 VLAN,编号为 20(可根据实际情况修改)
# 未通过 802.1X 认证的用户将被分配到 VLAN 20

interface GE2/0/12
 port link-type hybrid
 authentication-profile NPS
 dot1x guest-vlan 20
# 在接口 GE2/0/12 上启用来宾 VLAN,当认证失败或超时,用户进入 VLAN 20

锐捷交换机配置802.1X认证

命令示例

## ###阶段1### AAA与RADIUS基础配置

aaa new-model
# 启用 AAA 新模型

aaa accounting update periodic 15
# 设置计费更新周期为 15 分钟

aaa accounting update
# 启用计费更新功能

aaa accounting network account-method start-stop group radius
# 配置网络计费方法,使用 RADIUS,启停方式为 start-stop

aaa accounting network ruijie start-stop group radius
# 创建名为 ruijie 的网络计费方案,使用 RADIUS

aaa authentication dot1x ruijie group radius
# 配置 802.1X 认证方案 ruijie,使用 RADIUS



## ###阶段2### RADIUS服务器组配置


aaa group server radius ruijie
 server 192.168.1.6
# 创建名为 ruijie 的 RADIUS 服务器组,并指定服务器 IP 地址


## ###阶段3### RADIUS服务器参数配置


radius-server host 192.168.1.6 test username test key 0 password
# 配置 RADIUS 服务器主机,测试用户名为 test,密钥为 password

radius-server key 0 password
# 设置 RADIUS 服务器共享密钥(需与服务器端一致)




## ###阶段4### 802.1X认证与计费配置


dot1x accounting ruijie
# 启用 dot1x 计费,使用 ruijie 方案

dot1x authentication ruijie
# 启用 dot1x 认证,使用 ruijie 方案



## ###阶段5### 接口绑定配置

interface GigabitEthernet 2/0/7
 description songxwn.com
# 进入接口 GigabitEthernet 2/0/7,并添加描述

 switchport mode trunk
# 设置端口为 trunk 模式(承载多个 VLAN)

 dot1x port-control auto
# 启用 802.1X 自动端口控制模式

 dot1x dynamic-vlan enable
# 启用动态 VLAN 功能,根据认证结果分配 VLAN

来宾VLAN

当用户接入端口但未通过 802.1X 认证时,交换机会自动将其放入一个指定的 VLAN(通常是隔离的网络,只能有限资源,如AD),避免完全断网可认证逃生。

dot1x guest-vlan 20
# 配置来宾 VLAN,编号为 20(可根据实际情况修改)
# 未通过 802.1X 认证的用户将被分配到 VLAN 20

interface GigabitEthernet 2/0/7
 description songxwn.com
 switchport mode trunk
 dot1x port-control auto
 dot1x dynamic-vlan enable
 dot1x guest-vlan 20
# 在接口上启用来宾 VLAN,当认证失败或超时,用户进入 VLAN 20

报文交互示例下载链接

https://gitlab.com/wireshark/wireshark/-/wikis/uploads/\_\_moin\_import\_\_/attachments/SampleCaptures/eapol-mka.pcap

Wiresharek最新版下载:https://mirrors.tuna.tsinghua.edu.cn/wireshark/win64/Wireshar...

参考文档

https://support.huawei.com/enterprise/zh/doc/EDOC1100086515/d...

https://info.support.huawei.com/info-finder/encyclopedia/zh/R...

https://info.support.huawei.com/info-finder/encyclopedia/zh/8...

运维技术交流群

发送邮件到 ➡️ me@songxwn.com

或者关注WX公众号:网工格物

做电商、产品展示类页面时,总想着给卡片加点 “小心机”?不用复杂的 JS,纯 CSS 就能做出超吸睛的产品卡片悬停效果 —— 卡片展开、图片旋转缩放、文字渐显,整套交互丝滑又高级,今天就把这个实用的小效果分享给大家。

先说说这个效果的核心亮点:

✅ 纯 CSS 实现,无任何 JavaScript 代码,轻量化易部署

✅ 多属性联动过渡:卡片宽度、背景形状、图片位置 / 旋转 / 缩放、文字透明度同步变化

✅ 过渡延迟分层,交互逻辑更有层次感,不显得杂乱

话不多说,直接上完整代码,每一行关键代码都加了注释,新手也能看懂~

完整源码(附详细注释)

HTML 部分

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!-- 适配移动端,保证不同设备显示正常 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS 产品卡片悬停效果</title>
    <!-- 引入外部样式文件 -->
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <!-- 产品卡片核心容器 -->
    <div class="card">
        <!-- 圆形背景容器,--clr自定义属性控制主题色 -->
        <div class="circle" style="--clr: #f40203;">
            <!-- 品牌logo图片 -->
            <img src="cocacola_logo.png" class="logo">
        </div>
        <!-- 产品介绍内容区 -->
        <div class="content">
            <h2>cocacola</h2>
            <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Unde maxime, iste illum dolor dolorum quidem blanditiis vitae, ipsa aspernatur consequatur perspiciatis eum quisquam ipsum quam vero quo, optio eius magni!</p>
            <!-- 跳转按钮 -->
            <a href="#">Explore More</a>
        </div>
        <!-- 产品主图 -->
        <img src="cocacola.png" class="product_img">
    </div>
</body>
</html>

CSS 部分

/* 全局样式重置:清除默认边距、盒模型改为border-box(宽高包含边框内边距) */
*{
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
/* 页面主体样式:居中显示卡片,深色背景突出卡片效果 */
body {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh; /* 占满视口高度 */
  background: #151515;
}
/* 卡片基础样式:相对定位,设置初始宽高和圆角,过渡效果控制整体交互时长 */
.card {
  position: relative; /* 作为子元素绝对定位的参考 */
  width: 350px; /* 初始宽度 */
  height: 350px; /* 初始高度 */
  border-radius: 20px;
  display: flex;
  justify-content: center;
  align-items: center;
  transition: 0.5s; /* 所有过渡属性的基础时长 */
  transition-delay: 0.5s; /* 悬停时延迟触发过渡,增加层次感 */
}
/* 卡片悬停时:宽度扩展,过渡延迟重置 */
.card:hover{
  width: 600px; /* 展开后的宽度 */
  transition-delay: 0.5s;
}
/* 圆形背景容器:绝对定位覆盖整个卡片,居中对齐内容 */
.card .circle {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 20px;
  display: flex;
  justify-content: center;
  align-items: center;
}
/* 圆形背景的伪元素:实现初始圆形背景+发光效果 */
.card .circle::before{
  content: ''; /* 伪元素必须有content */
  position: absolute;
  top: 0;
  left: 0;
  width: 350px; /* 初始圆形宽度,和卡片初始宽高一致 */
  height: 350px;
  border-radius: 50%; /* 圆形 */
  background: #191919; /* 背景色 */
  border: 8px solid var(--clr); /* 边框用自定义主题色 */
  /* 发光效果:两层阴影叠加,增强视觉冲击 */
  filter: drop-shadow(0 0 10px var(--clr)) drop-shadow(0 0 60px var(--clr));
  transition: 0.5s background 0.5s; /* 背景色和形状过渡,分层延迟 */
  transition-delay: 0.75s,1s; /* 悬停时延迟触发,保证交互顺序 */
}
/* 卡片悬停时:伪元素从圆形变矩形,背景色改为主题色 */
.card:hover .circle::before {
  transition-delay: 0.5s; /* 重置延迟,优先触发形状变化 */
  width: 100%; /* 宽度铺满卡片 */
  height: 100%; /* 高度铺满卡片 */
  border-radius: 20px; /* 矩形圆角,和卡片一致 */
  background: var(--clr); /* 背景色替换为主题色 */
}
/* logo图片样式:初始显示,悬停时消失 */
.card .circle .logo {
  position: relative;
  width: 250px;
  transition: 0.5s; /* 过渡时长 */
  transition-delay: 0.5s; /* 悬停时延迟消失 */
}
/* 卡片悬停时:logo缩小至消失 */
.card:hover .circle .logo {
  transform: scale(0); /* 缩放为0,隐藏logo */
  transition-delay: 0s; /* 立即触发,优先消失 */
}
/* 产品主图样式:初始隐藏,定位在卡片中心 */
.card .product_img {
  position: absolute;
  top: 50%;
  left: 50%;
  /* 居中定位:translate(-50%,-50%)配合top/left:50% */
  transform: translate(-50%, -50%) scale(0) rotate(315deg); /* 初始缩放为0+旋转角度,隐藏 */
  height: 300px;
  transition: 0.5s ease-in-out; /* 过渡曲线更丝滑 */
}
/* 卡片悬停时:产品图显示+位移+旋转+缩放 */
.card:hover .product_img {
  transition-delay: 0.75s; /* 延迟触发,等卡片展开后再显示 */
  top: 25%; /* 向上位移 */
  left: 72%; /* 向右位移 */
  height: 500px; /* 放大高度 */
  /* 显示图片+调整旋转角度+缩放至正常大小 */
  transform: translate(-50%, -50%) scale(1) rotate(15deg);
}
/* 文字内容区:初始隐藏(透明+不可见) */
.card .content {
  position: absolute;
  width: 50%; /* 宽度占卡片一半 */
  left: 20%; /* 初始位置偏右 */
  padding: 20px 20px 20px 40px;
  opacity: 0; /* 透明隐藏 */
  transition: 0.5s;
  visibility: hidden; /* 不可见,避免点击交互 */
}
/* 卡片悬停时:文字内容渐显+位移到左侧 */
.card:hover .content {
  transition-delay: 0.75s; /* 延迟触发,和产品图同步显示 */
  opacity: 1; /* 完全不透明 */
  visibility: visible; /* 可见 */
  left: 20px; /* 左移到卡片边缘 */
}
/* 文字样式:白色字体,大写,大号标题 */
.card .content h2{
  color: #fff;
  text-transform: uppercase; /* 大写转换 */
  font-size: 2.5em;
  line-height: 1em;
}
/* 正文样式:白色字体 */
.card .content p {
  color: #fff;
}
/* 按钮样式:白底黑字,圆角,增加点击感 */
.card .content a {
  position: relative;
  color: #111;
  background: #fff;
  padding: 10px 20px;
  border-radius: 10px;
  display: inline-block;
  text-decoration: none; /* 清除下划线 */
  font-weight: 600; /* 加粗 */
  margin-top: 10px;
}

最后想说,好的前端交互不一定需要复杂的代码,把基础的 CSS 属性玩透,就能做出让用户眼前一亮的效果。

如果大家还有想解锁的 CSS 小技巧,欢迎在评论区留言。

本文由mdnice多平台发布




在高铁、体育跳水和破解翻墙技术上,中国称第二没人敢称第一。各位预测一下美版官换梯子用到的技术实现。

从这一期开始,小云将为大家讲解云流管理平台的使用教程。今天,让我们来了解一下云流管理平台中【我的资源】和【云应用管理】功能是如何使用的吧!

一、我的资源

该页面中显示了渲染服务器的总体资源情况,包括服务器总量、云应用数量、流路总数、CPU预警记录、GPU预警记录、内存预警记录、磁盘预警记录等统计信息。

1、通过图像与数据结合的形式,展现了服务器CPU的各项信息,可以查看单台或者全部服务器的资源情况。

2、点击右上角“如何添加资源”可以查看云流渲染服务部署流程,点击“点量云流渲染服务”可以下载该应用,点击相应的操作手册可以直接查看指南,进行点量云流的部署安装。

二、云应用功能

【01云应用列表】

该页面中对已有云应用进行汇总,展示了名称、状态、服务器数量等信息。支持通过应用ID、应用名称等字段对云应用进行搜索,用户可以对云应用进行禁用、编辑等操作。

  • 创建应用
    1、点击<创建应用>,填写应用名称,选择本次流化的应用类型等,选择模板之后需填写码率,选择访问验证方式。有游客模式和登录方式两种。

2、除了基本信息外,也可在高级设置中对应用参数进行修改,包括开启声音、应用模式、随机分配流路等设置,同时页支持对移动端参数进行设置。

3、点击“下一步”,选择该应用所在的服务器,支持选择多台。在选择服务器弹窗中可以查看当前管理平台中全部服务器的信息,包括服务器名称、服务器地址、机房区域。在左上角有相应的“如何添加服务器”的快速教程。选中服务器之后点击“确定”即可保存成功。

4、设置好后点击下一步,选择该应用所在服务器,支持选择多台
(1)如果应用模板为:Unity3D/UE、信创Unity3D/UE、沙盒2、云VR
注意上传应用文件要求为ZIP格式,可选择应用的分发方式:P2P或HTTP。上传成功之后系统会自动识别应用路径和视图路径。

(2)如果上传应用模板为WebGL
在服务器选择完成后,直接输入访问网址,保存后便可生成链接。

(3)如果上传模板为办公模板
在服务器选择完成后,点击“下一步”,应用设置完成之后将会自动生成相应的桌面链接。

5、点击“下一步”进入“流路设置”界面,可基于服务器性能设置流路数和预启动数量。也可针对单台服务器进行个性化设置,设置本服务器的应用路径、视图路径和启动参数,分配本服务器的流路数和预启动数(默认分别小于总流路数和总预启动数)。

6、设置完成之后点击“保存”,云流创建成功。

  • 更新管理
    在云应用列表中,找到<更新状态>,点击下方数字,进入<更新管理>页面,显示该云应用各个服务器的应用更新状态及总体下载状态。

  • 流路管理
    1、点击“最大流路数”列的数字即可进入流路管理页面,显示该云应用各条流路的所属服务器、ip端口、状态等信息,支持对云应用中的各条流路进行启动、停止、删除、编辑、查看地址、添加地址。启动/停止分别对应流路的不同状态,流路只有在线时才可访问。

2、点击“编辑”可以对本流路的配置进行设置

  • 基本配置中可编辑本条流路所属的服务器,对应的云应用,可查看对应云应用的应用详情(应用分组、应用名称、应用识别码、应用模板、应用路径、应用参数、视图进程路径、备注),编辑流路端口;
  • 高级配置中可选择旁观人数(默认表示不限人数)、扬声器、协议类型、访问验证方式、是否允许多人操控、地址访问控制、是否预启动。设置完成之后,点击“保存”即可。

3、点击“添加地址”可对本流路添加新的访问地址,输入用户名、手机号、备注基本信息,输入时长,选择模式:主控、主控(在线时不允许旁观)、旁观(只可观看不可操作,可申请权限),设置完成之后点击“保存”即可。

4、新生成的访问地址可点击流路列表中的“查看地址”进行查看,可对用户进行编辑、删除、生成地址、下线、延期等操作。点击“使用详情”可查看本账号的具体访问情况,包括客户端IP、连接时间、下线时间、过期时间、在线时长。

  • 复制链接
    应用创建成功后,会生成:Web链接+Web二维码、客户端链接+客户端二维码。

1、web链接可直接在浏览器访问;

2、客户端链接需安装点量云打开访问,点量云流可在链接地址悬浮菜单的工具箱中进行下载;

3、复制客户端链接打开客户端,该云应用会自动加入客户端云应用列表中,之后在客户端中可以直接打开。

  • 禁用/编辑/删除/上传应用文件
    操作设置中有对云流进行禁用、编辑、删除等控制,根据需求进行增删即可。

【02 云应用分组管理】

该页面对已有云应用分组进行汇总,展示了云应用分组的组名、关联云应用、备注、创建时间等信息。支持通过组名、备注等字段对云应用分组进行搜索,用户可对分组进行编辑、删除操作。
1、点击“创建云应用组”,输入组名称、备注,上传应用分组展示图(建议尺寸350x170 px,支持jpg/png格式);

2、点击“选择云应用”选择要添加到组内的云应用。选择云应用时支持通过应用名称、应用状态、应用备注对全部的云应用进行搜索。勾选中之后点击“确定”即可保存成功,同一云应用支持属于多个分组;

3、点击“关联云应用”按钮可查看分组中的云应用,可以进行搜索或移除;

4、点击“编辑”按钮可对分组信息和关联云应用进行修改;

5、点击“删除”按钮将会删除分组,同时组内应用的所属分组也会同步删除,云应用不会被删除。

由于昨晚熬夜,今早起来狂炫了一瓶冰镇东鹏,起初一切良好,上了地铁肚子开始隐隐作痛了,想着很快到公司了(四五个站)就忍忍,此时事情开始逐渐失控,肚子开始翻滚了,我是站也不是坐也不是,憋的我额头直冒冷汗想死的心都有了,咬着牙夹紧屁股终于等到下一站停车了立马下车找站内厕所,好在很快找到了,飞奔进去一泻千里。

妈蛋我都做好了最坏的打算了,真他么恐怖啊。mental_boommental_boom

typeoff-banner

大家好,我是 Typeoff 的开发者,也是一个程序员。

我自己每天都在写代码、写注释、写技术文档、写 Prompt 。
Cursor 、Copilot 、ChatGPT 这些工具用得越来越多,但输入本身反而成了效率瓶颈

所以我做了一个更适合编程场景的语音输入工具。

Typeoff 是一个 macOS 上的系统级语音输入工具。
按住键盘上的 Fn 键说话,松开后文字会自动输入到当前光标位置,任何 App 都可以用。

本质上,它是为了让我自己在和 AI 协作编程时更高效。

🚀 它能做什么

  • 按住 Fn 说话,松开自动输入
  • 自动加标点、分段
  • 自动去掉“嗯”“啊”等口头语
  • 支持 60+ 语言
  • 可以说中文输出英文
  • 在 Cluade 、VS Code 、Cursor 等开发工具中也能用

打字大概 60 wpm ,
语音输入可以到 200~240 wpm

写长 Prompt 、写代码说明、整理技术方案时效率提升会比较明显。

🌐 官网地址

https://typeoff.ai

可以直接在官网下载安装 macOS 版本。

💡 版本说明

免费版每周有字数额度。
Pro 版不限字数。

🎁 V2EX 朋友专属

在评论区留下你的邮箱(或私信我邮箱),
我会给你发放 $30 账户余额

这 $30 可以直接兑换 3 个月 Pro 使用时间

名额不限,发完为止。

如果愿意,也欢迎说说你平时最想在哪些编程场景下用语音输入,我会根据反馈继续优化。

有技术问题也欢迎交流。

2026年2月26日,汤阴 —— 豫唐团队今日正式发布其最新力作"豫唐工具集"(Yutang Toolkit),这是一款轻量级、现代化的在线前端开发工具集合平台。该产品采用纯前端技术栈实现,所有工具均在本地浏览器中运行,无需安装、无需上传数据到服务器,为开发者提供安全、高效、隐私保护的使用体验。

创新设计理念,致敬极简美学

豫唐工具集采用"高级商务极简"设计语言,深度致敬 Apple Human Interface Guidelines 与 Notion 设计风格。产品以冷淡灰(#f3f4f6)为背景,纯白(#ffffff)卡片和深炭黑(#111827)文字构建出优雅专业的视觉体验,配合精致的悬浮阴影和动态光球背景,为用户带来前所未有的界面美感。

"我们相信,优秀的工具不仅要有强大的功能,更要有令人愉悦的用户体验,"豫唐团队负责人表示,"豫唐工具集正是这一理念的完美体现。"

五大核心工具,满足多元需求

豫唐工具集v1.0.0版本包含五大核心工具,覆盖前端开发、项目管理和日常办公等多个场景:

ICO图标生成器

支持图片转换与文字生成的在线Favicon制作工具,用户只需拖拽上传即可生成自定义尺寸和样式的ICO图标,完全在本地处理,确保数据安全。

摸鱼神器(Moyu)

这款创新的浏览器工具能够伪装成系统升级界面,支持多种Windows/macOS系统风格,提供全屏沉浸体验。对于需要短暂休息的职场人士来说,这是一个既有趣又实用的小工具。

密码生成器

安全高效的本地随机密码生成器,支持自定义长度和字符类型(大小写字母、数字、特殊符号),一键复制到剪贴板,帮助用户创建强密码,提升账户安全性。

项目管理计算器(EVM)

专为项目经理打造的专业工具,集成挣值管理(EVM)、净现值(NPV)分析及合同费用计算(FPIF/CPFF)功能,助力项目管理者精准把控项目绩效和投资决策。

数独挑战

经典的数独逻辑游戏,提供无限关卡挑战和多难度等级,程序自动生成不同难度的题目,支持计时功能,帮助用户在工作之余锻炼逻辑思维能力。

自主核心技术,开源共享

豫唐工具集包含多项自主开发的核心组件,其中最引人注目的是Snow.js雪花特效引擎。这款独立JavaScript插件具有零配置启动、物理交互(鼠标斥力算法)和高性能渲染(60FPS流畅运行)等特性,可快速复用于其他项目。

此外,项目还实现了响应式磨砂导航栏,采用CSS backdrop-filter技术实现高级磨砂玻璃质感,在移动端和桌面端都能自动切换布局,保持最佳可读性。

技术架构先进,兼容性强

基于原生HTML5、CSS3、JavaScript(ES6+)技术栈,豫唐工具集充分利用现代Web技术的优势,包括Canvas 2D渲染引擎、CSS Variables、Flexbox、Grid布局等。产品兼容Chrome、Firefox、Safari、Edge等主流浏览器的最新版本。

开源免费,即刻体验

豫唐工具集完全开源免费,用户可通过以下方式体验:

用户只需克隆项目或直接双击打开index.html文件,即可立即使用所有工具,无需任何复杂的配置过程。

关于豫唐团队

豫唐团队致力于开发高质量的前端开发工具和解决方案,秉承"让开发更简单,让工作更有趣"的理念,持续为开发者社区贡献优质开源项目。

让开发更简单,让工作更有趣。

Gemini pro ,Chrome ,Windows&Mac ,使用过程中左边栏历史会话会突然崩溃。

右侧进行中的会话也有部分内容不显示。

刷新后恢复正常,但是崩溃过于频繁了,严重影响使用。

梯子还比较稳定,换过几个节点也没用。

不确定是否是 server side bug

求助各位遇到过类似问题吗,怎么解决的?

在之前的文章中,我们从企业软件复杂度长期累积的角度,解释了低代码产生的历史背景。这里将进一步回答一个更为现实的问题:当企业在讨论“低代码”时,究竟在讨论什么?

低代码(Low-Code)一词最早并非诞生于学术论文或软件工程理论,而是最早出现在行业研究机构Forrester于2014年发表的一篇行业研究报告中,其“让人们可以用最少的手工编码就可以快速开发应用,并可以快速配置和部署的一种技术和工具”的定义,仅明确了该技术的价值与核心差异,对技术实现和能力边界持开放态度。在实践中,低代码并不存在一个严格统一、被所有厂商和用户共同接受的定义。不同厂商在产品宣传中对低代码的描述差异极大,有的强调拖拽式页面开发,有的强调业务人员也能开发系统,还有的则将其定位为专业开发者的效率工具。这种差异并非偶然,而是低代码本身处于持续演进过程中的自然结果。

理解低代码的概念与现状,关键不在于寻找一句标准定义,而在于理解其价值主张、抽象方式和工程边界

本章将围绕以下几个问题展开:

  • 为什么低代码首先是一个商业概念,而非单一技术名词
  • 低代码试图解决的核心问题究竟是什么
  • 不同低代码形态之间的本质差异
  • 当前低代码平台在技术能力上的共性与现实边界

第一章 低代码首先是一个商业概念

在讨论低代码解决了什么问题之前,有必要先回答一个更基础、但经常被回避的问题:低代码究竟“是什么”。如果缺乏这一层澄清,低代码很容易被误解为某种界面形态、某类开发技巧,甚至被简单归类为更友好的编程方式。

从企业软件和软件工程体系的整体结构来看,低代码并不是游离在体系之外的新物种,而是位于软件技术栈中一个非常明确的位置。理解这一位置,是理解低代码商业属性的前提。

1.1 从“软件”到“开发工具”的分层视角

如果将企业软件按照抽象层级和职责进行简化分层,大致可以得到如下结构:

  • 软件:直接面向业务用户,承载具体业务流程和业务规则,如 ERP、MES、CRM、报销系统等。
  • 基础软件:为上层软件提供通用运行环境和基础能力,如操作系统、数据库、消息队列、中间件等。
  • 中间件:位于基础软件与应用软件之间,解决通用但非业务特有的问题,如事务管理、服务通信、权限认证、流程引擎、规则引擎等。
  • 开发工具:用于生产软件本身的工具与平台,如编程语言、IDE、框架、脚手架、CI/CD 工具等。

image

图:低代码所属的开发工具在软件分类中的位置

从定位上看,低代码更接近于编程语言、集成开发环境(IDE)、框架和组件的组合体,本质上是面向企业软件开发的生产工具,而非直接交付给业务用户使用的业务系统。这一点非常关键。将低代码理解为“另一种应用软件”,往往会导致以下误判:

  • 用业务系统的标准去要求低代码平台,忽略其工程属性
  • 将低代码的使用效果等同于“最终系统好不好用”,而非“开发方式是否更可控”
  • 将低代码与 ERP、OA 等产品直接对比,得出错误结论

1.2 低代码并非“新技术”,而是“新一代开发工具形态”

进一步细分“开发工具”这一层,可以发现其本身也经历了多次演进。在早期,开发工具以编程语言 + 编译器为核心,如C和gcc;随后出现了包含了调试器、编译器的集成开发环境以及配套的版本管理工具,如Visual Basic和Visual SourceSafe等;再之后是各类框架,如Web 框架、ORM、前后端组件库等等;以及近年热火的DevOps 工具链、自动化流水线等。这些演进虽然围绕着软件开发全生命周期展开,但规模小且过于分散,开发者需要将其组织使用才能发挥最大价值。

事实上,低代码并没有否定上述任何一类工具,而是将其中一部分能力上移并整合。如将部分中间件能力(如流程引擎、规则引擎、权限体系)内建到平台中;然后将部分框架约定(如 CRUD、页面-服务协作模式)固化为模型;最后将大量重复出现的工程结构,从“代码模板”升级为“平台原生能力”,最终形成一种新的工具形态。

从这个角度看,低代码并不是“写代码更少”,而是通过平台化方式,重新定义哪些内容应该由开发者反复实现,哪些内容应该成为开发工具的内建能力。

1.3 为什么说低代码是一个商业概念

既然低代码在技术上可以被理解为新一代开发工具形态,为什么仍然要强调它首先是一个商业概念?低代码的概念与常见技术概念的最大差异在于其并没有约定其技术实现,属于厂商与市场的交汇处的概念,本质上是一种对软件生产方式的重新命名

事实上,在企业软件领域,类似的命名方式并不罕见:

  • ERP 并不是一种具体技术,而是一类围绕“企业资源计划”的软件系统集合
  • BI 不是算法创新,而是对“数据分析决策支持”能力的整体包装
  • 云计算同样不是单点技术突破,而是对计算资源交付方式的重组

低代码亦是如此。它所指向的并非某一项全新的底层技术,也不是由某一项不可替代的底层技术突破所驱动的,而是对既有软件工程能力的重新组合与重新定价。在传统开发工具体系中编程语言、框架和中间件大多是通用技术,一次研发,多处复用。但是企业为软件开发支付的最大成本,并不在工具本身,而在于长期人力投入,这就导致工具厂商很难直接从提升企业开发效率中获取持续收益,创新意愿不高。低代码改变的,正是这一商业结构。通过将大量工程经验、通用能力和约束机制内建为平台能力,并因此向开发团队持续收取费用。这笔费用可以简单理解为帮助开发团队节省开发费用的“分成”。因此,低代码在市场上的表达,天然带有明显的商业语言特征,如降本增效、提升交付速度、降低对关键人员的依赖等等。这些表述并非空洞宣传,而是对低代码商业价值的直接描述。

1.4 低代码的真实定位:开发工具 × 中间件能力 × 管理实践的融合体

综合来看,可以给低代码一个更贴近工程现实的定位描述:低代码是一类以企业软件为目标场景,将中间件能力、工程规范和开发工具深度融合的平台型开发工具。 它既不是单纯的中间件,也不是传统意义上的 IDE,更不是业务系统本身,而是:

  • 向下吸收中间件的通用能力
  • 向上约束应用系统的结构形态
  • 向开发者提供比传统工具更高层级的抽象

正因为处在这一位置,低代码天然具有明显的商业属性。低代码不是为了展示某项技术有多先进,而是为了重塑企业软件开发的成本曲线与组织方式

理解这一点,才能在后续章节中,正确看待低代码的价值边界与适用条件,而不是陷入“它能不能完全替代编码”这一并不存在的二元问题之中。

要放客厅不能太大,机器多了也不好管理,成本也高

所以采用了 ITX 机箱,到处找结果咸鱼找到了霜秋凛然的 3D 打印机箱
显卡外置,4 盘位,可以满足所有需求

正面
侧面

模块化、可复用、开源的 HarmonyOS 快速开发框架

为什么需要 HCompass?

鸿蒙生态正在高速发展,越来越多的开发者投入到 HarmonyOS 应用开发中。但在实际项目中,我们常常面临这些痛点:

  • 每个新项目都要从零搭建基础架构,重复造轮子
  • 网络请求、路由导航、状态管理等通用能力缺乏统一封装
  • 多人协作时代码风格不一致,模块边界模糊
  • 业务功能难以跨项目复用,积累的经验无法沉淀

HCompass 正是为解决这些问题而生。它不是一个 UI 组件库,而是一套完整的应用开发框架 -- 帮你把地基打好,让你专注于业务本身。


核心理念:功能包即积木

HCompass 的核心思想很简单:把应用拆成一个个独立的"功能包",像搭积木一样组合它们。

每个功能包都是一个自包含的业务模块,拥有自己的页面、ViewModel、服务和数据模型。需要登录功能?放入 auth 功能包。需要用户中心?放入 user 功能包。功能包之间通过契约层解耦,互不依赖,随时可以拆卸和替换。

你的应用 = Entry(入口) + 若干功能包(积木)

四层架构,职责分明

HCompass 采用清晰的四层架构设计:

层级职责关键特征
Entry应用入口初始化框架、注册功能包、配置路由
Packages业务功能包独立开发、独立测试、可跨项目复用
Shared共享契约定义服务接口和类型,功能包之间的"协议"
Core框架核心与业务无关的通用能力,可直接迁移到任何项目

这种分层设计带来的好处是:Core 层可以直接复用到你的下一个项目,Packages 层的功能包可以按需组合,Shared 层确保模块之间的通信有据可依。


开箱即用的核心能力

依赖注入(DI)

轻量级 DI 容器,让功能包之间彻底解耦:

// 在 Shared 层定义契约
interface IUserRepository {
  getUserInfo(id: string): Promise<User>;
}

// 在功能包中实现并注册
register<IUserRepository>(ServiceKeys.USER_REPO, new UserRepositoryImpl());

// 在任何地方解析使用
const userRepo = resolve<IUserRepository>(ServiceKeys.USER_REPO);

不再需要硬编码依赖关系,功能包只依赖契约,不依赖具体实现。

导航系统

统一的路由管理,支持路由守卫:

// 路由跳转
NavigationService.push(UserRoutes.PROFILE, { userId: "123" });

// 路由守卫 -- 未登录自动跳转登录页
GuardManager.addGuard(new LoginGuard());

支持登录守卫、权限守卫、条件守卫,灵活组合,按优先级执行。

网络请求

基于 Axios 封装,告别重复的请求模板代码:

// 继承 BaseNetWorkViewModel,自动管理 loading/error/success 状态
@ObservedV2
class UserProfileViewModel extends BaseNetWorkViewModel<User> {
  async fetchData(): Promise<void> {
    await this.request(() => this.userRepo.getUserInfo(this.userId));
  }
}

内置拦截器链、统一错误处理、分页逻辑,你只需关注业务数据。

设计系统

统一的设计令牌,确保 UI 一致性:

// 百分比常量,告别魔法数字
Row() { ... }.width(P100).height(P50)

// 间距组件,统一视觉节奏
Column() {
  Text("标题")
  SpaceVerticalMedium()  // 12vp 间距
  Text("内容")
}

基础父类

三个 ViewModel 基类覆盖 90% 的页面场景:

基类适用场景
BaseViewModel通用页面,提供生命周期管理
BaseNetWorkViewModel网络请求页面,自动处理 loading/error/success
BaseNetWorkListViewModel分页列表页面,内置下拉刷新和上拉加载

实战案例:聚合登录功能包

光说架构不够直观,我们直接看官方实现的 login 功能包 -- 一个支持华为账号一键登录、微信、支付宝、短信验证码的聚合登录模块,完整展示了功能包从契约定义到页面渲染的全流程。

功能包目录结构

packages/login/
├── LoginModule.ets                    # 模块生命周期(DI注册 + 路由 + 守卫)
├── view/
│   ├── LoginPage.ets                  # 主登录页(华为一键登录 + 三方登录)
│   └── SmsLoginPage.ets               # 短信验证码登录页
├── viewmodel/
│   ├── LoginViewModel.ets             # 登录业务逻辑
│   └── SmsLoginViewModel.ets          # 短信登录逻辑
├── components/
│   ├── AnimatedAuthPage.ets           # 认证页面基础布局
│   ├── PhoneInputField.ets            # 手机号输入组件
│   ├── VerificationCodeField.ets      # 验证码输入组件
│   ├── UserAgreement.ets              # 用户协议组件
│   └── ...
├── navigation/
│   ├── LoginNav.ets                   # 登录页导航构建器
│   └── SmsLoginNav.ets                # 短信登录页导航构建器
├── services/
│   └── AuthNavSvcImpl.ets             # 导航服务实现
└── models/
    └── Constant.ets                   # 三方 APP_ID 配置

View / ViewModel / Service / Navigation 各司其职,结构一目了然。

第一步:在 Shared 层定义契约

功能包对外暴露的能力,全部通过 Shared 层的接口契约来声明:

// shared/contracts -- 导航服务契约
export const AUTH_NAV_SVC_KEY: string = "authNavService";

export interface IAuthNavSvc {
  toLogin(): void;       // 跳转登录页
  toSmsLogin(): void;    // 跳转短信登录页
}

// shared/contracts -- 路由常量
export class AuthRoutes {
  static Login = "auth/login";
  static SmsLogin = "auth/sms-login";
}

其他功能包只需要依赖这些接口,不需要知道登录页长什么样、用了哪个 SDK。

第二步:注册模块 -- 一个类搞定 DI、路由、守卫

LoginModule 实现 FeatureModule 接口,框架会在启动时自动调用:

export class LoginModule implements FeatureModule {
  readonly moduleId: string = 'auth';
  readonly moduleName: string = '认证模块';
  readonly version: string = '1.0.0';
  readonly dependencies: string[] = [];

  // 注册服务到 DI 容器
  registerServices(container: Container): void {
    container.register<IAuthNavSvc>(AUTH_NAV_SVC_KEY, () => new AuthNavSvcImpl());
  }

  // 注册页面路由
  registerRoutes(registry: RouteRegistry): void {
    registry.register(AuthRoutes.Login, loginNavBuilderWrapper);
    registry.register(AuthRoutes.SmsLogin, smsLoginNavBuilderWrapper);
  }

  // 注册路由守卫 -- 未登录自动拦截
  registerGuards(navigationService: NavigationService): void {
    navigationService.registerGuard(new AuthGuard());
  }
}

三个方法,把服务注入、路由注册、登录守卫全部声明完毕。当用户访问受保护的页面时,AuthGuard 会自动检查登录状态,未登录则跳转到登录页:

class AuthGuard implements RouteGuard {
  readonly name: string = 'AuthGuard';
  readonly priority: number = 100;  // 优先级最高

  canActivate(context: RouteContext): boolean {
    return getUserState().isLoggedIn();  // 已登录放行,未登录拦截
  }

  onReject(context: RouteContext): void {
    // 拦截后自动跳转登录页
    navigation?.navigateTo(AuthRoutes.Login, context.params);
  }
}

第三步:ViewModel 封装业务逻辑

LoginViewModel 继承 BaseViewModel,集中处理多种登录方式:

@ObservedV2
export default class LoginViewModel extends BaseViewModel {
  @Trace anonymousPhone: string = "";  // 华为账号匿名手机号

  // 华为账号一键登录控制器
  huaweiLoginController: LoginWithHuaweiIDButtonController =
    new LoginWithHuaweiIDButtonController()
      .setAgreementStatus(AgreementStatus.ACCEPTED)
      .onClickLoginWithHuaweiIDButton((error, response) => {
        this.handleLoginWithHuaweiIDButton(error, response);
      });

  // 微信 OAuth 登录
  async onWechatLoginClick(): Promise<void> {
    const share: ShareWxSdk = new ShareWxSdk(APP_ID_WX);
    const res = await share.wechatOAuth("snsapi_userinfo", state, () => {});
    if (res instanceof SendAuthResp) {
      const userInfo = await share.getUserInfo(APP_SECRET_WX, res);
      // 处理登录结果...
    }
  }

  // 支付宝授权登录
  onAlipayLoginClick(): void {
    AFServiceCenter.call(AFService.AFServiceAuth, params);
  }
}

View 层不包含任何业务逻辑,只负责绑定 ViewModel 的状态和方法。

第四步:View 层 -- 声明式 UI 渲染

@ComponentV2
export struct LoginPage {
  @Local private vm: LoginViewModel = new LoginViewModel();

  build(): void {
    AppNavDestination({ viewModel: this.vm }) {
      // Logo
      LogoIcon()

      // 匿名手机号展示
      Text(this.vm.anonymousPhone)

      // 华为账号一键登录按钮
      LoginWithHuaweiIDButton({
        params: { style: Style.BUTTON_CUSTOM, loginType: LoginType.QUICK_LOGIN },
        controller: this.vm.huaweiLoginController,
      })

      // 短信验证码登录
      IBestButton({
        text: $r("app.string.sms_login"),
        onBtnClick: () => {
          getContainer().tryResolve<IAuthNavSvc>(AUTH_NAV_SVC_KEY)?.toSmsLogin();
        }
      })

      // 第三方登录(微信 / 支付宝 / QQ)
      this.buildThirdPartyLogin()

      // 用户协议
      UserAgreement()
    }
  }
}

注意跳转短信登录页时,通过 DI 容器解析 IAuthNavSvc 服务来导航,而不是直接引用目标页面 -- 这就是契约解耦的威力。

第五步:可复用组件沉淀

login 功能包还沉淀了一组可复用的认证 UI 组件:

// AnimatedAuthPage -- 认证页面通用布局,接收自定义内容
@ComponentV2
export struct AnimatedAuthPage {
  @Param title: ResourceStr = "";
  @BuilderParam content: CustomBuilder;

  build(): void {
    LargePaddingVerticalScroll({ fillMaxSize: true }) {
      Text(this.title).fontSize(28).fontWeight(FontWeight.Medium)
      SpaceVerticalXXLarge()
      if (this.content) { this.content(); }
    }
  }
}

// 短信登录页直接复用这个布局
AnimatedAuthPage({ title: $r("app.string.welcome_login") }) {
  PhoneInputField({ ... })
  VerificationCodeField({ ... })
  UserAgreement()
  IBestButton({ text: $r("app.string.login"), ... })
}

PhoneInputFieldVerificationCodeFieldUserAgreement 这些组件,在你开发注册页、找回密码页时可以直接复用。

小结:一个功能包的完整生命周期

Shared 层定义契约(接口 + 路由 + 类型)
        |
LoginModule 注册服务、路由、守卫
        |
ViewModel 封装业务逻辑(华为/微信/支付宝/短信)
        |
View 层声明式渲染(绑定 ViewModel,零业务代码)
        |
可复用组件沉淀(AnimatedAuthPage / PhoneInputField / ...)

这就是 HCompass 功能包的开发范式。每个功能包都遵循同样的模式,新成员看一个包就能上手所有包。


技术栈

技术用途
HarmonyOS NEXT开发平台
ArkTS / ArkUI开发语言与 UI 框架
@ohos/axiosHTTP 请求
@ibestservices/ibest-ui-v2UI 组件库
@ibestservices/ibest-orm数据库 ORM

谁适合使用 HCompass?

  • 独立开发者:快速搭建应用骨架,把精力放在业务创新上
  • 创业团队:统一技术栈和代码规范,降低协作成本
  • 企业开发团队:沉淀业务功能包,跨项目复用,提升交付效率
  • 鸿蒙生态贡献者:以功能包为单位贡献开源模块,共建生态

完善的文档体系

HCompass 提供了基于 VitePress 构建的完整文档站点,涵盖:

  • 快速开始 -- 从零搭建你的第一个 HCompass 应用
  • 架构设计 -- 深入理解四层架构和 MVVM 模式
  • 核心模块 -- DI、导航、网络、组件等每个模块的详细 API 文档
  • 功能包开发 -- 手把手教你创建和发布功能包
  • 最佳实践 -- 代码规范、性能优化、安全指南、状态管理

文档地址:https://hcompass.codelably.com


快速开始

# 克隆项目
git clone https://github.com/codelably/HCompass.git

# 使用 DevEco Studio 打开项目
# 等待依赖同步完成
# 运行 entry 模块即可体验

环境要求:

  • DevEco Studio 5.0+
  • HarmonyOS SDK 最新稳定版
  • Node.js 18.0+

开源协议

HCompass 基于 MIT 协议开源,你可以自由使用、修改和分发。

欢迎通过 Issue 和 Pull Request 参与项目建设,一起让鸿蒙开发更简单。


这不只是教程,是一份完整实录。(实在不会,丢给CC让他帮你安装)

从【以为很简单】到【真的跑通】,每一个报错、每一个坑、每一次修正,我都记下来了。

最终结果:从素材到公众号草稿箱,全链路自动化可用。


🤖 这个系统在做什么?

一句话:给素材 → 自动写文 → 自动排版 → 自动进公众号草稿箱。

系统流程图

我只做三件事:

  1. 写选题与要求(task.md)
  2. 放原始素材(materials.md)
  3. 审稿后点击发布

其余流程由系统自动完成。

这套系统的核心价值在于:把重复劳动交给机器,把创意决策留给人。


🧩 系统组成(最终可用架构)

整个系统由 5 个核心组件构成:

1. Claude Code CLI — 写作引擎

根据 task.md 和 materials.md 生成符合要求的 article.md。这是整个系统的大脑,负责理解需求、提炼素材、生成文章。

2. AGENTS.md — 写作规范

这是稳定输出的关键。AGENTS.md 是一个开放标准,用于指导 AI 编码代理的行为规范。

在内容创作场景中,它定义了写作风格、禁用词汇、排版规则等约束条件,确保 AI 生成的内容始终符合你的品牌调性。

3. KIE API — 图像生成

用于生成文章封面图。KIE.ai 提供了多种 AI 图像生成模型的统一接口,包括 GPT-Image-1、Midjourney、Flux 等,价格比官方更实惠,响应速度快。

4. ImageMagick — 图片处理

负责封面图的裁剪和尺寸处理。微信公众号封面图有特定尺寸要求:大图 900×383px (2.35:1),小图 383×383px (1:1)。

ImageMagick 可以通过命令行快速完成批量裁剪。

5. @wenyan-md/cli — 发布工具

将 Markdown 转换为微信公众号格式并推送到草稿箱。这个工具支持自动上传图片、应用主题样式、处理代码高亮和公式渲染。

技术架构图

完整流程:

素材(task.md + materials.md)

Claude Code CLI 读取 AGENTS.md 规范

生成 article.md

(可选)KIE API 生成封面图

ImageMagick 裁剪为 900×383px

wenyan publish 推送

公众号草稿箱 ✅


🛠 从零到跑通:完整过程

1)先盘点依赖

当时已完成:

  • ✅ Claude Code CLI
  • ✅ Node.js / Python3
  • ✅ ImageMagick

待完成:

  • ❌ 安装 wenyan 发布工具
  • ❌ 配置公众号 AppID/AppSecret
  • ❌ 配置微信 API IP 白名单
  • ❌ 配置 KIE API Key(可选)
  • ❌ 端到端发布测试

2)安装 wenyan(第一个坑)

一开始装错包名:

npm install -g wenyan-cli

报错 404(包不存在)。

正确包名是:

npm install -g @wenyan-md/cli

安装成功(1.0.11)。

**💡 经验:**包名容易搞混,遇到 404 先去 npm 官网确认正确的 package name。


3)公众号配置(第二个坑:命令用错)

一开始以为可以这样配:

wenyan config set appId xxx

wenyan config set appSecret xxx

结果报错:too many arguments

原因:这个版本的 wenyan 不支持这套 config 子命令。

正确方式:用环境变量(示例):

echo 'export WECHAT\_APP\_ID="你的AppID"' >> ~/.zshrc

echo 'export WECHAT\_APP\_SECRET="你的AppSecret"' >> ~/.zshrc

source ~/.zshrc

KIE 也是同理:

echo 'export KIE\_API\_KEY="你的KIE\_API\_KEY"' >> ~/.zshrc

source ~/.zshrc

**⚠️ 安全提醒:**AppSecret 只展示一次,若泄露请立即重置并更新本地环境变量。


4)IP 白名单(最大的坑)

这是我踩得最深的一个坑。

报错:

40164: invalid ip xxx.xxx.xxx.xxx, not in whitelist

**现象:**每次请求显示的出口 IP 都可能变化。

**根因:**VPN/代理自动切换节点导致出口 IP 不固定。

img_v3_02v7_7e0c24d1-eba0-4f9a-93bc-b6480cd4407g.jpg

我最终的解决方案:

① 查询当前出口 IP(通过本地代理):

curl -s --proxy http://127.0.0.1:7890 https://api.ipify.org

② 把返回 IPv4 加到公众号后台「API IP 白名单」

图片

③ 发布时固定走同一代理出口:

HTTPS\_PROXY=http://127.0.0.1:7890 HTTP\_PROXY=http://127.0.0.1:7890 \

wenyan publish -f "./article.md"

然后成功拿到 media_id,文章进入草稿箱。

**💡 经验:**如果你在国内服务器运行,直接用 curl -s https://ipinfo.io/ip 查询出口 IP 即可,不需要代理。


5)验收命令(替代 doctor)

wenyan doctor 在该版本不可用。

可以用渲染命令做最小验收:

echo "# 测试" | wenyan render | head -20

能正常输出 HTML 结构说明本地渲染链路没问题。

再用一次 wenyan publish 验证微信接口链路:

wenyan publish -f "./test-article.md"

image.png

✅ 最终可复用 SOP(精简版)

经过多次踩坑,我总结出这套可直接复用的标准流程:

Step 1:安装工具

npm i -g @wenyan-md/cli

brew install imagemagick  # macOS

Step 2:配置环境变量

export WECHAT\_APP\_ID="你的AppID"

export WECHAT\_APP\_SECRET="你的AppSecret"

export KIE\_API\_KEY="你的KIE\_API\_KEY"  # 可选

Step 3:公众号后台配置

  • 启用 AppSecret
  • 添加 API IP 白名单(填实际出口 IPv4)

Step 4:本地渲染测试

echo "# 测试" | wenyan render | head -20

Step 5:发布测试(必要时带代理)

HTTPS\_PROXY=http://127.0.0.1:7890 \

wenyan publish -f "./article.md"

Step 6:到草稿箱确认文章与封面

image.png

🕳️ 坑点总表(实战版)

现象

根因

解决方案

包名错误

npm 404

包名写错

用 @wenyan-md/cli

配置命令错误

too many arguments

版本不支持 config set

改用环境变量

IP 白名单反复失败

40164 invalid ip

代理出口 IP 漂移

固定节点+固定代理端口

封面报错

找不到 cover

frontmatter 缺字段/路径无效

补 cover 且路径有效

doctor 命令不存在

not valid command

该版本无此子命令

用 render + publish 验证

图片尺寸不对

封面显示不全

未按 2.35:1 裁剪

用 ImageMagick 裁剪为 900×383px

踩坑示意图


🎯 关键技术深度解析

AGENTS.md:稳定输出的灵魂

很多人以为 AI 写作就是“丢个 prompt 就行”。

错了。

真正决定质量的,是你的 AGENTS.md。

AGENTS.md 是一个由 Linux 基金会下属的 Agentic AI Foundation 管理的开放标准。它最初是为编码代理设计的,但现在被广泛应用于各种 AI 自动化场景。

它的作用是什么?

把你的部落知识(tribal knowledge)写成机器可读的规范。

就像资深工程师脑子里的那些“潜规则”:

  • 这个项目用什么技术栈
  • 代码风格是什么样的
  • 哪些文件绝对不能碰
  • 测试怎么跑

在内容创作场景中,AGENTS.md 定义的是:

  • 写作风格:口语化程度、段落长度、是否用 emoji
  • 禁用词汇:哪些 AI 味的词绝对不能出现
  • 排版规则:标题层级、引用格式、代码块样式
  • 质量标准:字数范围、数据引用要求、可读性基准

一个好的 AGENTS.md 应该包含:

  1. 可执行命令(Commands first): AI 能直接跑的指令
  2. 具体代码示例(Code examples over explanations):展示什么是好的输出
  3. 明确边界(Clear boundaries):告诉 AI 什么绝对不能做
  4. 技术栈细节(Project knowledge):版本号、文件位置、依赖关系

💡 最佳实践:

  • 控制在 ≤150 行,太长会稀释信号
  • 用反引号包裹命令,让 AI 能直接复制粘贴
  • 把 AGENTS.md 当代码一样做 code review
  • 当 AI 犯错时,迭代更新规范

我的 AGENTS.md 里写了什么?

  • 禁用“首先、其次、综上所述”等 AI 套话
  • 要求 70% 段落必须是单句(<50 字)
  • 数据必须加粗,引用必须用 > 格式
  • 标题不超过 35 字,必须包含数据+情绪反差

规范写得越细,AI 输出越稳定、越像你自己。

image.png


wenyan-md:从 Markdown 到公众号的最后一公里

wenyan 是一个开源工具,专门解决“Markdown → 微信公众号”这个痛点。

它做了这些事:

  1. 自动转换格式: Markdown 语法 → 微信富文本
  2. 图片自动上传:扫描文章中的图片路径,自动上传到微信素材库
  3. 主题样式应用:支持多种预设主题,也可以自定义 CSS
  4. 代码高亮:自动处理代码块的语法高亮
  5. 公式渲染:支持 LaTeX 数学公式
  6. 推送草稿箱:调用微信 API,直接创建草稿

关键 API 调用链路:

1. 获取 access\_token

POST https://api.weixin.qq.com/cgi-bin/token

2. 上传图片素材

POST https://api.weixin.qq.com/cgi-bin/material/add\_material

3. 创建草稿

POST https://api.weixin.qq.com/cgi-bin/draft/add

citation

wenyan 把这些复杂的 API 调用封装成一个简单的命令:

wenyan publish -f "./article.md"

这就是工程化的力量。


KIE API:多模型图像生成的统一入口

之前生成封面图,我要在不同平台之间切换:

  • Midjourney 要去 Discord
  • DALL-E 要去 OpenAI 后台
  • Stable Diffusion 要自己部署

现在有了 KIE API,一个接口调用所有主流模型。

image.png

支持的模型包括:

  • GPT-Image-1 / 1.5: OpenAI 最新图像模型,文字渲染准确
  • Flux.1 Kontext:开源模型,风格化能力强
  • Midjourney:商业插画首选
  • Nano Banana Pro: YouMind 自研,速度快

价格优势:

KIE 的定价比官方便宜 20-30%,而且按需付费,不需要订阅。

集成方式:

\# 设置 API Key

export KIE\_API\_KEY="your\_api\_key"

\# 生成图片(伪代码示例)

curl -X POST https://api.kie.ai/v1/images/generate \

-H "Authorization: Bearer $KIE\_API\_KEY" \

-d '{"prompt": "...", "model": "gpt-image-1"}'

生成的图片可以直接用 ImageMagick 裁剪:

magick input.jpg -crop 900x383+0+0 cover.jpg


ImageMagick:命令行图片处理的瑞士军刀

ImageMagick 是一个开源的图像处理工具,支持超过 100 种图片格式。

核心命令:

1. 裁剪图片

\# 从左上角裁剪 900×383 的区域

magick input.jpg -crop 900x383+0+0 output.jpg

\# 居中裁剪

magick input.jpg -gravity center -crop 900x383+0+0 output.jpg

2. 调整尺寸

\# 缩放到 900×383(可能变形)

magick input.jpg -resize 900x383 output.jpg

\# 按比例缩放,宽度固定 900px

magick input.jpg -resize 900x output.jpg

3. 批量处理

\# 批量裁剪当前目录所有 jpg

for img in *.jpg; do

magick "$img" -crop 900x383+0+0 "cropped\_$img"

done

💡 实战技巧:

微信公众号封面有大图(2.35:1)和小图(1:1)两种显示形式。如果想同时兼顾,可以做一张 1283×383px 的图:左边 383×383 是小图区域,右边 900×383 是完整大图。


🔄 完整自动化工作流实战

现在把所有组件串起来,看看一篇文章是怎么从 0 到发布的。

场景:我要写一篇“独立开发者搞钱案例”

Step 1:准备素材

创建 task.md:

\# 任务

将 YouTube 视频转换成公众号文章

\# 要求

- 字数 1500-2000

- 风格:信息猎手+卡兹克

- 必须包含数据和 SOP

创建 materials.md:

\# 素材

- YouTube 视频链接:https://youtube.com/watch?v=xxx

- 视频文字稿:(粘贴完整转录文本)

Step 2: Claude 自动写作

claude code --agents ./AGENTS.md \

"读取 task.md 和 materials.md,生成 article.md"

Claude 会:

  1. 读取 AGENTS.md 了解写作规范
  2. 分析 materials.md 提取核心信息
  3. 按照 task.md 的要求生成文章
  4. 输出 article.md
图片

Step 3:生成封面图(可选)

\# 调用 KIE API 生成封面

\# (这里可以用脚本或手动)

\# 裁剪为公众号尺寸

magick cover-raw.jpg -crop 900x383+0+0 cover.jpg

Step 4:发布到草稿箱

wenyan publish -f "./article.md"

Step 5:人工审核

登录公众号后台,在草稿箱中:

  • 检查排版是否正常
  • 确认图片是否都上传成功
  • 微调细节(如果需要)
  • 点击发布

整个流程,除了审核,全部自动化。

从素材到草稿箱,不超过 5 分钟


💡 进阶优化方向

系统跑通后,我又做了一些优化:

1)多平台发布

wenyan 不仅支持微信,还支持知乎、掘金、CSDN 等平台。

可以写一个脚本,一次生成,多平台分发:

\# 发布到微信

wenyan publish -f "./article.md" --platform wechat

\# 发布到知乎

wenyan publish -f "./article.md" --platform zhihu

2)定时发布

结合 cron 或 GitHub Actions,可以实现定时自动发布:

\# .github/workflows/publish.yml

name: Auto Publish

on:

schedule:

- cron: '0 9 * * *'  # 每天早上9点

jobs:

publish:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v2

- run: npm i -g @wenyan-md/cli

- run: wenyan publish -f "./article.md"

env:

WECHAT\_APP\_ID: ${{ secrets.WECHAT\_APP\_ID }}

WECHAT\_APP\_SECRET: ${{ secrets.WECHAT\_APP\_SECRET }}

3)内容质量监控

可以加一个 AI 审核层,在发布前自动检查:

  • 是否有敏感词
  • 字数是否达标
  • 是否有明显的 AI 痕迹
  • 数据引用是否准确

如果不通过,自动打回重写。

4)数据分析闭环

发布后,可以用 n8n 或 Zapier 监控文章数据:

  • 阅读量
  • 点赞数
  • 分享数
  • 用户评论

然后自动生成数据报告,反馈到下一次的 task.md 中,形成闭环优化。


🤔 这套系统值不值得搭?

如果你是:

  • 偶尔写一篇:不必折腾全自动,手动发布更快
  • 每周稳定更新:值得投入 1-2 天搭建
  • 批量产出内容:必须搞,能节省 80% 时间
  • 团队协作:非常值得,统一规范+自动化审核

投入产出比:

  • 搭建时间:1-2 天(包括踩坑)
  • 单篇文章节省时间:30-60 分钟
  • 回本周期:发布 5-10 篇文章后

但工具只是放大器。

真正决定内容质量的,永远是你的 AGENTS.md。

规范写得越细,AI 输出越稳定、越像你自己。

如果你的 AGENTS.md 只有 3 行,那 AI 生成的内容就是 3 行的质量。

如果你的 AGENTS.md 有 150 行细节约束,那 AI 就能生成 150 行质量的内容。

这是一个“垃圾进,垃圾出”(Garbage In, Garbage Out)的系统。

你投入多少,就能收获多少。


🎬 写在最后

这套系统从想法到跑通,我花了整整半天。

踩了很多坑。

但当我第一次看到文章自动出现在草稿箱时,那种成就感是无法替代的。

这不仅仅是一个自动化工具。

它改变了我对内容生产的理解:

从手工作坊 → 流水线工厂。

以前写一篇文章,我要:

  • 找素材(30 分钟)
  • 写初稿(2 小时)
  • 排版(30 分钟)
  • 配图(30 分钟)
  • 上传发布(10 分钟)

总计:3 小时 40 分钟。

现在:

  • 准备素材(10 分钟)
  • 运行脚本(2 分钟)
  • 审稿微调(20 分钟)

总计:32 分钟。

效率提升了 7 倍。

效率对比

更重要的是,我的精力被解放了。

我不再纠结【这个词用得对不对】、【这个段落要不要换行】。

我只需要关注:这个选题值不值得写?这个观点够不够深刻?

工具处理执行,人类负责决策。

这才是 AI 时代内容创作的正确姿势。

如果你也想搭建这样一套系统,我的建议是:

别怕踩坑。

每一个报错,都是你对系统理解更深一层的机会。

每一次调试,都是你把“隐性知识”变成“显性规范”的过程。

当你把所有坑都踩完,你就拥有了一套真正属于自己的内容生产流水线。

而这套流水线,会成为你最大的竞争壁垒。


P. S. 如果你在搭建过程中遇到问题,欢迎留言交流。我会持续更新这套系统的优化方案。

此即未来。

图片

在如今的数字化时代,软件分发面临着严峻的安全挑战。当用户下载未签名的软件时,系统往往会弹出“未知发布者”的安全警告,这极大地影响了软件的口碑与下载转化率。代码签名证书正是解决这一信任难题的基础设施。

一、什么是代码签名证书?

代码签名证书是一种基于公钥基础设施(PKI)技术的数字证书,专门用于软件开发者对其开发的代码(如.exe、.dll、.msi、.zip等文件)进行数字签名。

它的核心功能就像软件的“数字身份证+防伪封条”:

  1. 身份验证:当用户下载软件时,系统会显示发布者的真实名称(如“XX公司”),证明该软件确实出自合法的开发者之手,而非山寨或仿冒品。
  2. 完整性保护:签名技术确保代码自签名后未被恶意篡改或植入病毒。一旦被修改,签名就会破裂,系统会警告用户文件已损坏或不安全。

二、为什么要部署代码签名证书?

在主流操作系统(Windows、macOS)和安全软件严格拦截未知名软件的今天,部署代码签名证书已成为刚需:

  • 消除安装屏障:避免“Windows Defender SmartScreen”或浏览器拦截,提升软件安装成功率。
  • 建立品牌信誉:特别是EV(扩展验证)证书,能让用户第一时间看到绿色标识的企业信息,极大增强信任感。
  • 提升下载转化率:据统计,经过签名的软件下载转化率可提升42%以上。

三、怎么申请代码签名证书?(以JoySSL为例)

申请代码签名证书通常需要经历选择类型、提交验证、获取证书三个步骤。目前,国产自主数字证书品牌JoySSL因其支持国内验证流程、兼容国际标准且提供自动化管理工具,成为众多开发者的新选择。

以下是具体的申请与部署流程:代码签名证书申请入口

1. 选择证书类型

首先,访问JoySSL官网,根据你的身份和需求选择证书:

  • 个人开发者:可选择个人证书或OV证书。
  • 企业用户:推荐OV(组织验证)或EV(扩展验证)证书。EV证书能即时通过微软SmartScreen信誉认证,适合商业化软件。
    注:注册JoySSL账户时,通常可填写推荐码 230970 以获取技术指导或优惠套餐
2. 提交CSR与验证材料
  • 生成CSR:在本地生成密钥对并创建证书签名请求(CSR)。
  • 提交信息:企业用户需提供营业执照、法人身份证等信息。JoySSL支持AI自动识别营业执照,将OV证书签发时间缩短至约2小时。
  • 验证流程:CA机构会通过电话或邮件回访,核实申请意愿(部分EV证书可能涉及视频面签)。
3. 下载证书并签名

审核通过后,下载证书文件(通常为PFX格式,包含私钥)。使用签名工具(如Windows SDK的signtool.exe)对软件进行签名并添加时间戳。

macos26 系统,微信输入法自动更新为最新版后,每次切换输入法都会出现如下弹窗:

即使为在辅助功能里给予权限后,仍然会弹窗;

气愤之下,我将微信输入法卸载了,使用系统自带输入法;
重启系统后,好家伙,切换输入法还是会出现这个弹窗;微信输入法都卸载干净了,找不到残留了。

真令人抓狂,这也太流氓了吧。

大伙谁有经验解决这个问题?

点赞 + 关注 + 收藏 = 学会了

整理了一个NAS小专栏,有兴趣的工友可以关注一下 👉 《NAS邪修》

wxchat 主打文件传输助手本地私有化存储,数据全程不上传第三方。

我这次使用绿联 NAS 部署 wxchat,其他品牌的 NAS 操作步骤大同小异。

在“文件管理”里找个位置(我是在“docker”文件夹里操作),新建一个“wxchat”文件夹。

然后在“wxchat”文件夹下再创建2个文件夹:

  • uploads:以后上传的文件都存到这里。
  • data:数据库文件会存放在这里,也就是聊天记录。

打开“Docker”,切换到「镜像」。

yilan666/wxchat,找到红框那个,点击“下载”。

下载好之后,切换到「本地镜像」,点击它旁边的加号,创建一个容器。

容器配置这边,可以开启“自动重启”。

然后往下滑,在环境变量这里添加3项:

  • DATABASE_PATH:/app/data/wxchat.db
  • UPLOAD_PATH:/app/uploads
  • ACCESS_PASSWORD:密码,建议输入一个复杂点的,但你一定要记得住

再往下滑动,在存储空间这里新增2项,分别指向刚刚你创建的那两个文件夹。权限都是“读写”。

  • /app/data
  • /app/uploads

继续往下滑,配置一个端口号,比如我这里给的是 42906

然后点击“确定“,等项目构建完成后,在浏览器输入 你NAS的IP:42906 就能用了。

首次打开需要输入密码,这个密码就是前面在环境变量里配的那个。

登录后就可以发消息了。文字、图片、其他文件都能发。

而且在手机端也能用。

需要注意的是,iPhone这边下载的图片不是直接存放到相册里的,要在“文件”这个App里的“下载”文件夹里找。


以上就是本文的全部内容啦,有疑问可以在评论区讨论~

想了解更多NAS玩法可以关注《NAS邪修》👏

点赞 + 关注 + 收藏 = 学会了

MD5在线加密 核心JS实现

这篇只讲本工具的核心 JavaScript:把“文本/文件”统一转换成字节序列,计算 MD5,再按用户选择的格式输出。

在线工具网址:https://see-tool.com/md5-encryptor
工具截图:

1)整体数据流:输入 -> 字节 -> MD5 -> 输出

工具的主流程可以概括成四步:

  1. 根据输入格式把内容解析成 Uint8Array
  2. 使用增量 MD5 计算器得到 32 位十六进制摘要字符串
  3. 把十六进制摘要再转换回字节(统一到同一套输出格式化)
  4. hex / hex-space / base64 输出,并可选大写

核心原因是:无论输入来自文本还是文件,最终都要落到“字节”这个中间态,才能保证行为一致。

2)输入解析:parseInput(text, format)

输入格式支持 text / base64 / hex / hex-space,解析函数的目标是:返回一个“要参与 MD5 的字节数组”。

2.1 文本:TextEncoder 直接转 UTF-8 字节

case 'text':
  return new TextEncoder().encode(text)

这里把字符串编码为 UTF-8 字节,确保中文、Emoji 等多字节字符也能稳定计算。

2.2 Base64:atob 还原字节

case 'base64': {
  const binaryString = atob(text.replace(/\s/g, ''))
  const bytes = new Uint8Array(binaryString.length)
  for (let i = 0; i < binaryString.length; i++) {
    bytes[i] = binaryString.charCodeAt(i)
  }
  return bytes
}

关键点:Base64 输入会先清理空白字符,兼容多行粘贴;atob 的结果是“单字节字符串”,需要逐字节转为 Uint8Array

2.3 Hex:去空白 + 校验 + 每两位转一个字节

case 'hex': {
  const hex = text.replace(/\s/g, '')
  if (!/^[0-9a-fA-F]*$/.test(hex)) {
    throw new Error('invalid hex')
  }
  const bytes = new Uint8Array(hex.length / 2)
  for (let i = 0; i < hex.length; i += 2) {
    bytes[i / 2] = parseInt(hex.substr(i, 2), 16)
  }
  return bytes
}

这段实现把十六进制视为“连续的字节流”,中间允许插入空格/换行;只要字符集不在 [0-9a-fA-F] 就直接判错。

2.4 Hex(空格分隔):按 token 解析

case 'hex-space': {
  const parts = text.trim().split(/\s+/)
  const bytesArray = new Uint8Array(parts.length)
  for (let i = 0; i < parts.length; i++) {
    if (!/^[0-9a-fA-F]{1,2}$/.test(parts[i])) {
      throw new Error('invalid hex token')
    }
    bytesArray[i] = parseInt(parts[i], 16)
  }
  return bytesArray
}

这种格式适合处理“每个字节之间用空格分隔”的数据(例如抓包或调试输出)。每个 token 允许 1~2 位十六进制。

3)MD5 计算:统一用 SparkMD5.ArrayBuffer

工具用 spark-md5 做 MD5 计算。它的 ArrayBuffer 版本支持“追加数据”计算,既能处理文本输入,也能用于文件分片。

3.1 文本模式:Uint8Array 直接参与计算

const calculateMD5 = (bytes) => {
  const spark = new SparkMD5.ArrayBuffer()
  spark.append(bytes)
  const hashHex = spark.end()
  return hexToBytes(hashHex)
}

实现里会把最终的 hashHex 再转回字节数组,目的是把“输出格式化”统一为对字节数组操作(hex、base64 都能复用同一套逻辑)。

3.2 十六进制摘要转字节:hexToBytes

const hexToBytes = (hex) => {
  const bytes = new Uint8Array(hex.length / 2)
  for (let i = 0; i < hex.length; i += 2) {
    bytes[i / 2] = parseInt(hex.substr(i, 2), 16)
  }
  return bytes
}

MD5 的摘要是 16 字节(32 个十六进制字符),转换后就是固定长度的 Uint8Array(16)

4)输出格式化:formatOutput(bytes, format)

输出支持:

  • hex:连续 32 位十六进制
  • hex-space:每个字节用空格分隔
  • base64:对 16 字节摘要做 Base64

4.1 先把字节拼成十六进制串

const hexString = Array.from(bytes)
  .map(b => b.toString(16).padStart(2, '0'))
  .join('')

有了 hexStringhexhex-space 都只是在展示层做不同分割。

4.2 hex 与大写开关

case 'hex':
  return uppercase.value ? hexString.toUpperCase() : hexString

4.3 hex-space:每两位插空格

case 'hex-space': {
  const hex = uppercase.value ? hexString.toUpperCase() : hexString
  return hex.match(/.{2}/g).join(' ')
}

4.4 base64:字节转“单字节字符串”再 btoa

case 'base64': {
  const binaryString = String.fromCharCode.apply(null, bytes)
  return btoa(binaryString)
}

这里的 Base64 输出是“对 MD5 摘要(16 字节)”编码后的结果。

5)文件模式:分片读取 + 增量追加

文件模式的核心是:用 FileReader.readAsArrayBuffer 读取文件切片,并把每一片追加到同一个 SparkMD5.ArrayBuffer() 实例中。

const processFile = (file) => {
  fileProgress.value = 0
  const reader = new FileReader()
  const chunkSize = 2 * 1024 * 1024
  let offset = 0
  const spark = new SparkMD5.ArrayBuffer()

  const readNextChunk = () => {
    const slice = file.slice(offset, offset + chunkSize)
    reader.readAsArrayBuffer(slice)
  }

  reader.onload = (e) => {
    const arrayBuffer = e.target.result
    spark.append(arrayBuffer)

    offset += arrayBuffer.byteLength
    fileProgress.value = Math.round((offset / file.size) * 100)

    if (offset < file.size) {
      readNextChunk()
    } else {
      const hashHex = spark.end()
      const hashBytes = hexToBytes(hashHex)
      hashResult.value = formatOutput(hashBytes, outputFormat.value)
      fileProgress.value = 0
    }
  }

  reader.onerror = () => {
    fileProgress.value = 0
  }

  readNextChunk()
}

这段逻辑只做三件事:

  1. 读取切片得到 ArrayBuffer
  2. 追加到 spark
  3. 读完后统一走 formatOutput 输出

进度条的百分比来自 offset / file.size 的比例计算。

6)入口调度:generateHash() 把两种模式收口

工具的“生成”按钮只需要根据当前 tab 分流:

const generateHash = () => {
  if (activeTab.value === 'file') {
    if (!selectedFile) return
    processFile(selectedFile)
    return
  }

  if (!inputText.value) return

  const bytes = parseInput(inputText.value, inputFormat.value)
  const hashBytes = calculateMD5(bytes)
  hashResult.value = formatOutput(hashBytes, outputFormat.value)
}

到这里,文本与文件的差异只剩下“如何拿到输入字节”,后续的 MD5 计算与输出格式化完全复用同一套函数。