diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts
index 0d68571..a969c9a 100644
--- a/docs/.vitepress/config.mts
+++ b/docs/.vitepress/config.mts
@@ -32,7 +32,8 @@ export default withMermaid({
sidebar: {
'/Web/': [routers[0]],
'/DevOps/': [routers[1]],
- '/Others/': [routers[2]]
+ '/Practice/': [routers[2]],
+ '/Others/': [routers[3]]
},
socialLinks: [
diff --git a/docs/.vitepress/theme/router/index.ts b/docs/.vitepress/theme/router/index.ts
index e72d629..00bb6f1 100644
--- a/docs/.vitepress/theme/router/index.ts
+++ b/docs/.vitepress/theme/router/index.ts
@@ -6,7 +6,13 @@ export const routers = [
text: '🌿 Vue',
items: [
{ text: 'Vue3-Common', link: '/Web/Vue/Vue3-Common' },
- { text: 'Vue3架构原理', link: '/Web/Vue/Vue3-Architecture' }
+ { text: 'Vue3架构原理', link: '/Web/Vue/Vue3-Architecture' },
+ { text: 'JavaScript知识点整理', link: '/Web/Vue/JavaScript-Guide' },
+ { text: '前端包管理器', link: '/Web/Vue/Package' },
+ { text: 'Vite核心原理', link: '/Web/Vue/Vite-Principle' },
+ { text: '浏览器渲染全流程解析', link: '/Web/Vue/Browser-Process' },
+ { text: 'Element Plus 上传器', link: '/Web/Vue/ElUpload' },
+ { text: 'Element Plus 表格组件', link: '/Web/Vue/ElTable' },
]
},
{
@@ -43,6 +49,14 @@ export const routers = [
{ text: 'SQL高阶用法', link: '/Web/MySQL/SQL-Advance' }
]
},
+ {
+ text: '📶 Network',
+ items: [
+ { text: '网络编程简介', link: '/Web/Network/Summary' },
+ { text: '.Net Core实现', link: '/Web/Network/NetCore' },
+ { text: 'Mqtt简介与使用', link: '/Web/Network/Mqtt' }
+ ]
+ },
{
text: '📱 Flutter',
items: [
@@ -55,11 +69,6 @@ export const routers = [
{
text: '🔄 其他',
items: [
- { text: 'JavaScript知识点整理', link: '/Web/Others/JavaScript-Guide' },
- { text: '前端包管理器', link: '/Web/Others/Package' },
- { text: 'Vite核心原理', link: '/Web/Others/Vite-Principle' },
- { text: '浏览器渲染全流程解析', link: '/Web/Others/Browser-Process' },
- { text: 'Element Plus 上传器', link: '/Web/Others/ElUpload' },
{ text: 'RustFS简介和使用', link: '/Web/Others/RustFS' },
{ text: 'AList简介和使用', link: '/Web/Others/AList' },
{ text: 'InfluxDB简介和使用', link: '/Web/Others/InfluxDB' },
@@ -79,6 +88,22 @@ export const routers = [
{ text: 'Linux命令', link: '/DevOps/LinuxCommand' }
]
},
+ {
+ text: '🏗️ 项目实战',
+ items: [
+ {
+ text: '🏢 公司项目',
+ items: [
+ { text: '埃学习', link: '/Practice/Company/Learn' }
+ ]
+ },
+ {
+ text: '👤 个人项目',
+ items: [
+ ]
+ },
+ ]
+ },
{
text: '🔄 其他',
items: [
diff --git a/docs/DevOps/index.md b/docs/DevOps/index.md
index 3bdbe65..0821e44 100644
--- a/docs/DevOps/index.md
+++ b/docs/DevOps/index.md
@@ -1,10 +1,10 @@
---
layout: doc
-title: DevOps
+title: 运维部署
---
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/Practice/Company/Learn.md b/docs/Practice/Company/Learn.md
new file mode 100644
index 0000000..3729e40
--- /dev/null
+++ b/docs/Practice/Company/Learn.md
@@ -0,0 +1,68 @@
+---
+ title: 埃学习
+ date: 2026-05-27
+---
+
+# 一、项目背景
+ 为解决企业内部线下培训成本高、进度难追踪的问题,开发了一套企业在线学习平台,用于员工课程学习、在线考试、培训计划管理与数据统计分析,已全面接入企业微信工作台。
+
+# 二、系统架构
+
+# 三、核心模块
+## 3.1 员工端
+1. 课程学习(视频播放、进度记录、课程评论)
+2. 在线考试(随机试卷、自动阅卷)
+3. 学习记录和统计
+
+## 3.2 管理员端
+1. 课程管理(视频上传、章节管理)
+2. 培训计划管理(按部门/岗位下发)
+3. 考试与题库管理
+4. 人员与组织管理
+5. 员工学习数据统计
+
+# 四、技术栈
+| 层级 | 技术 |
+|---|---|
+| **前端** | Vue 3、Element Plus、Vue Router、Pinia、DPlayer (视频播放)、@vue-office (文档预览)、ECharts (数据可视化)|
+| **后端** | Spring Boot 3、Spring MVC、Sa-Token (鉴权)、MyBatis-Plus |
+| **中间件** | Redis、企业微信 SDK |
+| **存储** | MySQL 8.0 (业务数据)、AList (视频/文件资源存储) |
+| **视频处理** | Java JAVE 2 (FFmpeg 封装,视频压缩转码) |
+| **运维** | Docker、Fluent Bit (日志采集)、OpenObserver (日志可视化) |
+
+# 五、难点/亮点
+## 5.1 公网视频播放卡顿
+* 问题
+ 服务器公网带宽小,高清视频并发播放严重卡顿。
+
+* 方案
+ 上传视频后,使用JAVE2调用FFmpeg将视频统一压缩为720p的清晰度视频。
+
+* 效果
+ 视频体积减少60%+,公网环境播放流畅。
+
+## 5.2 学习进度防作弊
+* 问题
+ 员工学习视频课程时,可通过拖动进度条快速完成课程,无法真实反映学习行为,存在“刷课”风险。
+
+* 方案
+ 根据管理员设定的课程学习时长,在员工学习时,启动定时器;每分钟会保存学习时长至数据库中,下次学习时,直接跳转至上次学习进度;课程是否完成已定时器结束为准。
+
+* 效果
+ 有效防止通过拖拽进度条刷课,保证学习时长真实可信;同时支持断点续学,避免重复学习,满足企业培训考核与合规审计要求。
+
+## 5.3 学习计划通知
+* 问题
+ 培训计划、考试通知无法及时触达员工,导致培训参与率低、管理成本高。
+
+* 方案
+ 在发布培训计划时,调用企业微信消息推送接口,自动向指定员工发送应用消息通知;结合定时任务,对未完成培训的人员进行周期性提醒。
+
+* 效果
+ 培训通知实时触达,未读提醒显著提高培训完成率;管理员无需手动维护人员信息,降低了系统运维成本。
+
+# 六、成果
+1. 平台全面替代线下培训,年度培训计划完成率由 60% 提升至 95% 以上,满足了企业合规培训要求。
+2. 过视频压缩方案解决了公网带宽瓶颈,结合企业微信自动化通知,大幅降低人工催办成本,整体培训运营成本下降约 40%。
+3. 实现了学习进度防作弊与学习记录全跟踪,为公司提供精准的数据统计报表,支撑人才盘点与绩效评估。
diff --git a/docs/Practice/index.md b/docs/Practice/index.md
new file mode 100644
index 0000000..8c32826
--- /dev/null
+++ b/docs/Practice/index.md
@@ -0,0 +1,10 @@
+---
+layout: doc
+title: 项目实战
+---
+
+
+
+
\ No newline at end of file
diff --git a/docs/Web/Network/Mqtt.md b/docs/Web/Network/Mqtt.md
new file mode 100644
index 0000000..f1b9b09
--- /dev/null
+++ b/docs/Web/Network/Mqtt.md
@@ -0,0 +1,56 @@
+---
+ title: Mqtt简介与使用
+ date: 2026-05-27
+---
+
+# 一、简介
+ MQTT(Message Queuing Telemetry Transport) 是一种 轻量级物联网通信协议,基于 发布 / 订阅(Pub/Sub) 模式。
+
+## 1.1 核心概念
+1. Broker:消息服务器
+2. Client:发布或订阅消息的设备 / 程序
+3. Topic: 消息主题(路径形式)
+4. Publish:发布消息
+5. Subscribe:订阅消息
+6. QoS:服务质量等级(0 / 1 / 2)
+
+## 1.2 工作方式
+```text
+[设备A] --发布--> TopicA --> [Broker] --> TopicA --> [设备B]
+```
+
+# 二、安装
+ [EMQX](https://www.emqx.com/zh) Enterprise 是基于开源 EMQX 扩展的企业级 MQTT 物联网消息接入平台,完全兼容 MQTT v3.1.1 / v5.0。
+
+## 2.1 docker安装
+```yml
+services:
+ emqx:
+ image: emqx/emqx-enterprise:5.10.0
+ container_name: emqx
+ ports:
+ - "1883:1883"
+ - "8083:8083"
+ - "8084:8084"
+ - "8883:8883"
+ - "18083:18083"
+ restart: always
+```
+
+ 启动容器后,输入ip:18083,默认账号密码为admin/public。
+
+# 三、消息规范
+## 3.1 Topic
+```text
+////
+```
+
+ 例如`iot/thermostat/dev001/status/online`、`iot/thermostat/dev001/cmd/set_mode`。
+
+## 通配符
+1. +:单层通配符,例如:iot/+/dev001/telemetry/+
+2. #:多层通配符,只能放在topic末尾,例如:iot/thermostat/dev001/#
+
+::: tip
+使用+通配符时,必须严格满足层级要求,例如,如果topic是5层,那么iot/+将无法匹配到消息
+:::
\ No newline at end of file
diff --git a/docs/Web/Network/NetCore.md b/docs/Web/Network/NetCore.md
new file mode 100644
index 0000000..dec36fa
--- /dev/null
+++ b/docs/Web/Network/NetCore.md
@@ -0,0 +1,311 @@
+---
+ title: .Net Core实现
+ date: 2026-05-27
+---
+
+# 一、.Net Core实现
+## 1.1 SuperSocket
+ [SuperSocket](https://www.supersocket.net/)是一个轻量级, 跨平台而且可扩展的 .Net/Mono Socket 服务器程序框架。可以轻松构建TCP、UDP、WebSocket服务器。
+
+## 1.2 安装依赖
+ NuGut安装SuperSocket、SuperSocket.WebSocket和SuperSocket.WebSocket.Server 2.0及以上版本。
+
+## 1.3 配置文件
+ appsettings.json
+```json
+{
+ "serverOptions": {
+ "TcpServer": {
+ "name": "TcpServer",
+ "listeners": [
+ {
+ "ip": "Any",
+ "port": 4040
+ }
+ ]
+ },
+ "WebSocketServer": {
+ "name": "WebSocket",
+ "listeners": [
+ {
+ "ip": "Any",
+ "port": 5050
+ }
+ ]
+ }
+ },
+ "Mqtt": {
+ "Host": "127.0.0.1",
+ "Port": 1883,
+ "ClientId": "MqttClient",
+ "Topics": [
+ "test/topic1",
+ "test/topic2"
+ ]
+ }
+}
+```
+
+## 1.4 主程序
+ program.cs
+```cs
+var host = Host.CreateDefaultBuilder(args)
+ .ConfigureServices((context, services) =>
+ {
+ services.AddSingleton, TcpPackageHandler>();
+ services.AddSingleton();
+
+ // 1. 注入 MQTT 配置
+ services.Configure(context.Configuration.GetSection("Mqtt"));
+ // 2. 注册 MQTT 客户端
+ services.AddSingleton(serviceProvider => new MqttClientFactory().CreateMqttClient());
+ // 3. 注册 MQTT 后台服务
+ services.AddHostedService();
+ })
+ .AsMultipleServerHostBuilder()
+ .AddServer(builder =>
+ {
+ builder.ConfigureServerOptions((ctx, config) => config.GetSection("TcpServer"));
+ })
+ .AddWebSocketServer(builder =>
+ {
+ builder
+ .UseWebSocketMessageHandler(async (session, package) =>
+ {
+ using var scope = session.Server.ServiceProvider.CreateScope();
+ var handler = scope.ServiceProvider.GetRequiredService();
+
+ await handler.HandleAsync(session, package);
+ })
+ .ConfigureServerOptions((ctx, config) => config.GetSection("WebSocketServer"));
+ })
+ .ConfigureLogging(logging => logging.ClearProviders())
+ .UseNLog()
+ .Build();
+
+await host.RunAsync();
+```
+
+ 通过.AsMultipleServerHostBuilder()可以构造多服务器实例。
+
+# 二、 TCP服务器
+## 2.1 协议数据
+```cs
+///
+/// 协议数据结构 示例:65 6D 00 05 00 01 68 65 6C 6C 6F
+///
+/// 帧头标识
+/// 数据长度
+/// 数据类型
+/// 数据内容
+///
+record ProtocolFrame(
+ ushort Magic,
+ ushort Length,
+ ushort Type,
+ byte[] Payload
+);
+```
+
+ 可以根据实际情况自定义消息格式。
+
+## 2.2 协议解析
+```cs
+class BinaryPipelineFilter : FixedHeaderPipelineFilter
+{
+ ///
+ /// 固定头长度
+ ///
+ public BinaryPipelineFilter() : base(6)
+ {
+ }
+
+ ///
+ /// 从包头中解析出 Body 长度
+ ///
+ /// 字节流
+ /// Body 长度
+ protected override int GetBodyLengthFromHeader(ref ReadOnlySequence buffer)
+ {
+ var reader = new SequenceReader(buffer);
+
+ // 读取前2字节 → magic
+ reader.TryReadBigEndian(out ushort magic);
+
+ // 再读2字节 → Length
+ reader.TryReadBigEndian(out ushort length);
+
+ // 再读2字节 → Type
+ reader.TryReadBigEndian(out ushort type);
+
+ // 校验帧头
+ if (magic != 0x656D)
+ {
+ throw new Exception("非法帧头");
+ }
+
+ // 限制长度
+ if (length == 0 || length > 8192)
+ {
+ throw new Exception("非法长度");
+ }
+
+ // 返回 Payload 长度
+ return length;
+ }
+
+ ///
+ /// 把完整字节包 → 转换成 ProtocolFrame
+ ///
+ /// 字节流
+ /// ProtocolFrame
+ protected override ProtocolFrame DecodePackage(ref ReadOnlySequence buffer)
+ {
+ var reader = new SequenceReader(buffer);
+
+ // 读取前2字节 → magic
+ reader.TryReadBigEndian(out ushort magic);
+
+ // 再读2字节 → Length
+ reader.TryReadBigEndian(out ushort length);
+
+ // 再读2字节 → Type
+ reader.TryReadBigEndian(out ushort type);
+
+ var payload = buffer.Slice(6, length).ToArray();
+
+ // 构造ProtocolFrame
+ return new ProtocolFrame(magic, length, type, payload);
+ }
+}
+```
+
+ 根据协议数据ProtocolFrame来解包。
+
+## 2.3 消息处理
+```cs
+class TcpPackageHandler(ILogger logger) : IPackageHandler
+{
+ private readonly ILogger _logger = logger;
+
+ public async ValueTask Handle(IAppSession session, ProtocolFrame package, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation($"Magic={package.Magic:X4}, Type={package.Type}, Len={package.Length}");
+ await session.SendAsync(package.Payload, cancellationToken);
+ }
+}
+```
+
+## 2.4 TCPService
+```cs
+class TcpService(IServiceProvider serviceProvider, IOptions serverOptions) : SuperSocketService(serviceProvider, serverOptions)
+{
+}
+```
+
+# 三、Websocket服务器
+## 3.1 消息处理
+```cs
+class WebSocketMessageHandler(ILogger logger)
+{
+ private readonly ILogger _logger = logger;
+
+ public async ValueTask HandleAsync(WebSocketSession session, WebSocketPackage package)
+ {
+ _logger.LogInformation($"[WebSocket] {package.Message}");
+ await session.SendAsync("ok");
+ }
+}
+```
+
+# 四、 MQTT服务器
+## 4.1 MqttService
+```cs
+class MqttService(IMqttClient mqttClient, IOptions settings, ILogger logger) : BackgroundService
+{
+ private readonly IMqttClient _mqttClient = mqttClient;
+ private readonly MqttSettings _settings = settings.Value;
+ private readonly ILogger _logger = logger;
+ private MqttClientOptions? _mqttOptions;
+
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ // 构建连接配置
+ _mqttOptions = new MqttClientOptionsBuilder()
+ .WithClientId($"{_settings.ClientId}_{Guid.NewGuid():N}")
+ .WithTcpServer(_settings.Host, _settings.Port)
+ .WithCleanSession()
+ .Build();
+
+ _mqttClient.ConnectedAsync += OnConnectedAsync;
+ _mqttClient.DisconnectedAsync += OnDisconnectedAsync;
+ _mqttClient.ApplicationMessageReceivedAsync += HandleMessage;
+
+ _logger.LogInformation("[MQTT] 正在连接到服务器 {Host}:{Port}...", _settings.Host, _settings.Port);
+
+ await _mqttClient.ConnectAsync(_mqttOptions, stoppingToken);
+
+ // 等待程序停止
+ await Task.Delay(Timeout.Infinite, stoppingToken);
+ }
+
+ public async Task OnConnectedAsync(MqttClientConnectedEventArgs arg)
+ {
+ _logger.LogInformation("[MQTT] 已成功连接到服务器");
+
+ // 连接成功后订阅主题
+ foreach (var topic in _settings.Topics)
+ {
+ await _mqttClient.SubscribeAsync(topic, MqttQualityOfServiceLevel.AtLeastOnce);
+ _logger.LogInformation($"[MQTT] 已订阅主题:{topic}");
+ }
+
+ await Task.CompletedTask;
+ }
+
+ public async Task OnDisconnectedAsync(MqttClientDisconnectedEventArgs arg)
+ {
+ _logger.LogError("[MQTT] 连接失败,原因:{Reason}", arg.Reason);
+
+ await Task.CompletedTask;
+ }
+
+ public async Task HandleMessage(MqttApplicationMessageReceivedEventArgs arg)
+ {
+ var topic = arg.ApplicationMessage.Topic;
+ var payload = Encoding.UTF8.GetString(arg.ApplicationMessage.Payload);
+
+ _logger.LogInformation($"\n[MQTT] 收到消息\n主题:{topic}\n内容:{payload}\n");
+
+ await Task.CompletedTask;
+ }
+
+ public async Task PublishAsync(string topic, string payload, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ var message = new MqttApplicationMessageBuilder()
+ .WithTopic(topic)
+ .WithPayload(payload)
+ .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
+ .Build();
+
+ await _mqttClient.PublishAsync(message, cancellationToken);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "[MQTT] 发布消息到主题 {Topic} 失败", topic);
+ return false;
+ }
+ }
+
+ public override async Task StopAsync(CancellationToken stoppingToken)
+ {
+ await _mqttClient.DisconnectAsync();
+ await base.StopAsync(stoppingToken);
+ }
+}
+```
+
+ 需要实现后台服务接口一直运行。
\ No newline at end of file
diff --git a/docs/Web/Others/Netword-Program.md b/docs/Web/Network/Summary.md
similarity index 76%
rename from docs/Web/Others/Netword-Program.md
rename to docs/Web/Network/Summary.md
index 271c883..1479feb 100644
--- a/docs/Web/Others/Netword-Program.md
+++ b/docs/Web/Network/Summary.md
@@ -634,310 +634,3 @@ Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= # 服务器加密后的密
| 固定头部 | 必选,2 字节起,包含消息类型(如发布、订阅)、QoS 等级、是否保留消息等标识。 |
| 可变头部 | 可选,仅部分消息类型(如发布、订阅)需要,包含主题名、消息 ID 等信息。 |
| 负载 | 可选,消息的实际内容(如 JSON 字符串、二进制数据),例如 {"temperature": 25}。 |
-
-# 五、.Net Core实现
-## 5.1 SuperSocket
- [SuperSocket](https://www.supersocket.net/)是一个轻量级, 跨平台而且可扩展的 .Net/Mono Socket 服务器程序框架。可以轻松构建TCP、UDP、WebSocket服务器。
-
-## 5.2 安装依赖
- NuGut安装SuperSocket、SuperSocket.WebSocket和SuperSocket.WebSocket.Server 2.0及以上版本。
-
-## 5.3 配置文件
- appsettings.json
-```json
-{
- "serverOptions": {
- "TcpServer": {
- "name": "TcpServer",
- "listeners": [
- {
- "ip": "Any",
- "port": 4040
- }
- ]
- },
- "WebSocketServer": {
- "name": "WebSocket",
- "listeners": [
- {
- "ip": "Any",
- "port": 5050
- }
- ]
- }
- },
- "Mqtt": {
- "Host": "127.0.0.1",
- "Port": 1883,
- "ClientId": "MqttClient",
- "Topics": [
- "test/topic1",
- "test/topic2"
- ]
- }
-}
-```
-
-## 5.3 主程序
- program.cs
-```cs
-var host = Host.CreateDefaultBuilder(args)
- .ConfigureServices((context, services) =>
- {
- services.AddSingleton, TcpPackageHandler>();
- services.AddSingleton();
-
- // 1. 注入 MQTT 配置
- services.Configure(context.Configuration.GetSection("Mqtt"));
- // 2. 注册 MQTT 客户端
- services.AddSingleton(serviceProvider => new MqttClientFactory().CreateMqttClient());
- // 3. 注册 MQTT 后台服务
- services.AddHostedService();
- })
- .AsMultipleServerHostBuilder()
- .AddServer(builder =>
- {
- builder.ConfigureServerOptions((ctx, config) => config.GetSection("TcpServer"));
- })
- .AddWebSocketServer(builder =>
- {
- builder
- .UseWebSocketMessageHandler(async (session, package) =>
- {
- using var scope = session.Server.ServiceProvider.CreateScope();
- var handler = scope.ServiceProvider.GetRequiredService();
-
- await handler.HandleAsync(session, package);
- })
- .ConfigureServerOptions((ctx, config) => config.GetSection("WebSocketServer"));
- })
- .ConfigureLogging(logging => logging.ClearProviders())
- .UseNLog()
- .Build();
-
-await host.RunAsync();
-```
-
- 通过.AsMultipleServerHostBuilder()可以构造多服务器实例。
-
-## 5.4 TCP服务器
-### 5.4.1 协议数据
-```cs
-///
-/// 协议数据结构 示例:65 6D 00 05 00 01 68 65 6C 6C 6F
-///
-/// 帧头标识
-/// 数据长度
-/// 数据类型
-/// 数据内容
-///
-record ProtocolFrame(
- ushort Magic,
- ushort Length,
- ushort Type,
- byte[] Payload
-);
-```
-
- 可以根据实际情况自定义消息格式。
-
-### 5.4.2 协议解析
-```cs
-class BinaryPipelineFilter : FixedHeaderPipelineFilter
-{
- ///
- /// 固定头长度
- ///
- public BinaryPipelineFilter() : base(6)
- {
- }
-
- ///
- /// 从包头中解析出 Body 长度
- ///
- /// 字节流
- /// Body 长度
- protected override int GetBodyLengthFromHeader(ref ReadOnlySequence buffer)
- {
- var reader = new SequenceReader(buffer);
-
- // 读取前2字节 → magic
- reader.TryReadBigEndian(out ushort magic);
-
- // 再读2字节 → Length
- reader.TryReadBigEndian(out ushort length);
-
- // 再读2字节 → Type
- reader.TryReadBigEndian(out ushort type);
-
- // 校验帧头
- if (magic != 0x656D)
- {
- throw new Exception("非法帧头");
- }
-
- // 限制长度
- if (length == 0 || length > 8192)
- {
- throw new Exception("非法长度");
- }
-
- // 返回 Payload 长度
- return length;
- }
-
- ///
- /// 把完整字节包 → 转换成 ProtocolFrame
- ///
- /// 字节流
- /// ProtocolFrame
- protected override ProtocolFrame DecodePackage(ref ReadOnlySequence buffer)
- {
- var reader = new SequenceReader(buffer);
-
- // 读取前2字节 → magic
- reader.TryReadBigEndian(out ushort magic);
-
- // 再读2字节 → Length
- reader.TryReadBigEndian(out ushort length);
-
- // 再读2字节 → Type
- reader.TryReadBigEndian(out ushort type);
-
- var payload = buffer.Slice(6, length).ToArray();
-
- // 构造ProtocolFrame
- return new ProtocolFrame(magic, length, type, payload);
- }
-}
-```
-
- 根据协议数据ProtocolFrame来解包。
-
-### 5.4.3 消息处理
-```cs
-class TcpPackageHandler(ILogger logger) : IPackageHandler
-{
- private readonly ILogger _logger = logger;
-
- public async ValueTask Handle(IAppSession session, ProtocolFrame package, CancellationToken cancellationToken)
- {
- _logger.LogInformation($"Magic={package.Magic:X4}, Type={package.Type}, Len={package.Length}");
- await session.SendAsync(package.Payload, cancellationToken);
- }
-}
-```
-
-### 5.4.4 TCPService
-```cs
-class TcpService(IServiceProvider serviceProvider, IOptions serverOptions) : SuperSocketService(serviceProvider, serverOptions)
-{
-}
-```
-
-## 5.5 Websocket服务器
-### 5.5.1 消息处理
-```cs
-class WebSocketMessageHandler(ILogger logger)
-{
- private readonly ILogger _logger = logger;
-
- public async ValueTask HandleAsync(WebSocketSession session, WebSocketPackage package)
- {
- _logger.LogInformation($"[WebSocket] {package.Message}");
- await session.SendAsync("ok");
- }
-}
-```
-
-## 5.6 MQTT服务器
-### 5.6 MqttService
-```cs
-class MqttService(IMqttClient mqttClient, IOptions settings, ILogger logger) : BackgroundService
-{
- private readonly IMqttClient _mqttClient = mqttClient;
- private readonly MqttSettings _settings = settings.Value;
- private readonly ILogger _logger = logger;
- private MqttClientOptions? _mqttOptions;
-
- protected override async Task ExecuteAsync(CancellationToken stoppingToken)
- {
- // 构建连接配置
- _mqttOptions = new MqttClientOptionsBuilder()
- .WithClientId($"{_settings.ClientId}_{Guid.NewGuid():N}")
- .WithTcpServer(_settings.Host, _settings.Port)
- .WithCleanSession()
- .Build();
-
- _mqttClient.ConnectedAsync += OnConnectedAsync;
- _mqttClient.DisconnectedAsync += OnDisconnectedAsync;
- _mqttClient.ApplicationMessageReceivedAsync += HandleMessage;
-
- _logger.LogInformation("[MQTT] 正在连接到服务器 {Host}:{Port}...", _settings.Host, _settings.Port);
-
- await _mqttClient.ConnectAsync(_mqttOptions, stoppingToken);
-
- // 等待程序停止
- await Task.Delay(Timeout.Infinite, stoppingToken);
- }
-
- public async Task OnConnectedAsync(MqttClientConnectedEventArgs arg)
- {
- _logger.LogInformation("[MQTT] 已成功连接到服务器");
-
- // 连接成功后订阅主题
- foreach (var topic in _settings.Topics)
- {
- await _mqttClient.SubscribeAsync(topic, MqttQualityOfServiceLevel.AtLeastOnce);
- _logger.LogInformation($"[MQTT] 已订阅主题:{topic}");
- }
-
- await Task.CompletedTask;
- }
-
- public async Task OnDisconnectedAsync(MqttClientDisconnectedEventArgs arg)
- {
- _logger.LogError("[MQTT] 连接失败,原因:{Reason}", arg.Reason);
-
- await Task.CompletedTask;
- }
-
- public async Task HandleMessage(MqttApplicationMessageReceivedEventArgs arg)
- {
- var topic = arg.ApplicationMessage.Topic;
- var payload = Encoding.UTF8.GetString(arg.ApplicationMessage.Payload);
-
- _logger.LogInformation($"\n[MQTT] 收到消息\n主题:{topic}\n内容:{payload}\n");
-
- await Task.CompletedTask;
- }
-
- public async Task PublishAsync(string topic, string payload, CancellationToken cancellationToken = default)
- {
- try
- {
- var message = new MqttApplicationMessageBuilder()
- .WithTopic(topic)
- .WithPayload(payload)
- .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
- .Build();
-
- await _mqttClient.PublishAsync(message, cancellationToken);
- return true;
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "[MQTT] 发布消息到主题 {Topic} 失败", topic);
- return false;
- }
- }
-
- public override async Task StopAsync(CancellationToken stoppingToken)
- {
- await _mqttClient.DisconnectAsync();
- await base.StopAsync(stoppingToken);
- }
-}
-```
-
- 需要实现后台服务接口一直运行。
\ No newline at end of file
diff --git a/docs/Web/Others/Browser-Process.md b/docs/Web/Vue/Browser-Process.md
similarity index 100%
rename from docs/Web/Others/Browser-Process.md
rename to docs/Web/Vue/Browser-Process.md
diff --git a/docs/Web/Vue/ElTable.md b/docs/Web/Vue/ElTable.md
new file mode 100644
index 0000000..fae4a35
--- /dev/null
+++ b/docs/Web/Vue/ElTable.md
@@ -0,0 +1,202 @@
+---
+ title: Element Plus 表格组件
+ date: 2026-05-27
+---
+
+# 一、加载中
+```vue
+
+
+
+```
+
+::: tip
+要配合pinia存储使用,获取数据前将loading置为true,完成后置为false。
+:::
+
+# 二、展开行
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+ 通过类型expand和插槽props实现,可以展示任意格式数据。
+ 增加表格的`row-key`、`expand-row-key`属性可以实现只展开某一行功能。
+
+# 三、排序和筛选
+```vue
+
+
+
+
+
+
+
+
+```
+
+ 在`el-table-column`中添加`sortable`即可实现排序功能。
+ 在`el-table-column`中添加`filters`和`filter-method`实现筛选功能。
+ `filters`为原始数据中该字段下的所有值,并转为指定格式,也可以自定义筛选字段。
+
+# 四、表头搜索
+```vue
+
+
+
+
+
+
+
+
+
+
+
+```
+
+ 表头搜索主要利用`header`插槽和`el-popover`组件实现。
\ No newline at end of file
diff --git a/docs/Web/Others/ElUpload.md b/docs/Web/Vue/ElUpload.md
similarity index 100%
rename from docs/Web/Others/ElUpload.md
rename to docs/Web/Vue/ElUpload.md
diff --git a/docs/Web/Others/JavaScript-Guide.md b/docs/Web/Vue/JavaScript-Guide.md
similarity index 100%
rename from docs/Web/Others/JavaScript-Guide.md
rename to docs/Web/Vue/JavaScript-Guide.md
diff --git a/docs/Web/Others/Package.md b/docs/Web/Vue/Package.md
similarity index 100%
rename from docs/Web/Others/Package.md
rename to docs/Web/Vue/Package.md
diff --git a/docs/Web/Others/Vite-Principle.md b/docs/Web/Vue/Vite-Principle.md
similarity index 99%
rename from docs/Web/Others/Vite-Principle.md
rename to docs/Web/Vue/Vite-Principle.md
index 4a84c8f..486ed6c 100644
--- a/docs/Web/Others/Vite-Principle.md
+++ b/docs/Web/Vue/Vite-Principle.md
@@ -1,5 +1,5 @@
---
- title: 前端包管理器
+ title: Vite核心原理
date: 2025-12-13
---
diff --git a/docs/index.md b/docs/index.md
index 43417ae..f011f51 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -13,8 +13,11 @@ hero:
text: Web平台
link: /Web/
- theme: brand
- text: DevOps
+ text: 运维部署
link: /DevOps/
+ - theme: brand
+ text: 项目实战
+ link: /Practice/
features:
- title: 🚀 技术分享