<?xml version="1.0" encoding="utf-8"?>
<search> 
  
  
    
    <entry>
      <title>迹录相机：我做了一款面向现场工作记录的微信水印相机</title>
      <link href="/post/27ea7e16.html"/>
      <url>/post/27ea7e16.html</url>
      
        <content type="html"><![CDATA[<p><img src="https://img.nnu.cn/p/6a7e7d946015c.webp"><br>在信息化运维、设备巡检、工程施工、活动保障以及各种现场工作中，拍照留档几乎已经成为一种标准流程。</p><p>但普通照片能够记录的，通常只有当时的画面。</p><p>当这些照片真正进入工作记录、项目归档甚至后续追溯流程以后，经常还需要回答更多问题：</p><ul><li>这张照片是什么时候拍摄的？</li><li>当时具体位于什么位置？</li><li>拍摄时的天气和现场环境如何？</li><li>是谁完成了这次处理？</li><li>属于哪个项目或者哪项工作？</li><li>照片是现场实时拍摄，还是从相册导入后添加的水印？</li><li>照片保存以后有没有被编辑？</li><li>水印内容有没有被重新覆盖或者修改？</li></ul><p>如果只依靠手机系统相机，这些信息往往需要另外整理。</p><p>因此，我开发了一个自己的微信小程序水印相机：</p><h1 id="「现场迹录」"><a href="#「现场迹录」" class="headerlink" title="「现场迹录」"></a>「现场迹录」</h1><p>它的目标并不只是给照片左下角增加一行时间和地点，而是尝试把：</p><p><strong>现场拍摄 → 信息水印 → 自定义模板 → 高清合成 → 来源存证 → 照片验真</strong></p><p>组合成一套相对完整的现场影像记录流程。</p><p>官方网站：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://shuiyin.nnu.cn/</span><br></pre></td></tr></table></figure><p>项目仓库：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://github.com/anyfrees/xianchang-jilu</span><br></pre></td></tr></table></figure><hr><h1 id="一、为什么要重新做一个水印相机"><a href="#一、为什么要重新做一个水印相机" class="headerlink" title="一、为什么要重新做一个水印相机"></a>一、为什么要重新做一个水印相机</h1><p>最初做这个项目的原因其实很简单。</p><p>在日常现场工作中，经常需要留下类似这样的照片记录：<br><img src="https://img.nnu.cn/p/6a7e7cb697833.webp"></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">某单位</span><br><span class="line">信息化运维 · 故障处理</span><br><span class="line"></span><br><span class="line">2026.08.14 09:38:21</span><br><span class="line"></span><br><span class="line">地点：某教学楼设备间</span><br><span class="line">天气：晴 31℃</span><br><span class="line">处理人：运维人员A</span><br><span class="line">故障：交换机端口异常</span><br><span class="line">状态：已处理</span><br></pre></td></tr></table></figure><p><img src="https://img.nnu.cn/p/6a7e7cd52b94e.webp"><br>这种照片最大的价值，并不是“好看”，而是能够快速说明：</p><p><strong>谁，在什么时间、什么地点，完成了什么工作。</strong></p><p>市面上当然已经存在很多成熟的水印相机。<br><img src="https://img.nnu.cn/p/6a7e7ce9abcd7.webp"><br>但真正应用到自己的工作场景以后，我逐渐发现几个问题。</p><h2 id="1-固定模板很难适应不同工作"><a href="#1-固定模板很难适应不同工作" class="headerlink" title="1. 固定模板很难适应不同工作"></a>1. 固定模板很难适应不同工作</h2><p>设备巡检可能需要：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">设备名称</span><br><span class="line">巡检人员</span><br><span class="line">设备状态</span><br><span class="line">巡检结果</span><br></pre></td></tr></table></figure><p>故障处理需要：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">故障类型</span><br><span class="line">处理人员</span><br><span class="line">处理过程</span><br><span class="line">处理结果</span><br></pre></td></tr></table></figure><p>活动保障又可能需要：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">活动名称</span><br><span class="line">保障人员</span><br><span class="line">保障地点</span><br><span class="line">当前状态</span><br></pre></td></tr></table></figure><p><img src="https://img.nnu.cn/p/6a7e7d0d7d94d.webp"><br>如果所有场景都使用同一套固定水印，很快就会出现大量无用字段。</p><p>所以我更希望：</p><blockquote><p>水印本身就是可以设计的。</p></blockquote><hr><p><img src="https://img.nnu.cn/p/6a7e7d1e21313.webp"></p><h2 id="2-“有水印”并不代表“现场拍摄”"><a href="#2-“有水印”并不代表“现场拍摄”" class="headerlink" title="2. “有水印”并不代表“现场拍摄”"></a>2. “有水印”并不代表“现场拍摄”</h2><p>一张照片完全可以：</p><ol><li>从其它地方获取；</li><li>导入水印应用；</li><li>修改时间；</li><li>修改位置；</li><li>添加工作信息；</li><li>再重新导出。</li></ol><p>最终看起来，可能和现场实时拍摄的照片没有明显区别。</p><p>因此：</p><p><strong>有水印 ≠ 现场原拍。</strong><br><img src="https://img.nnu.cn/p/6a7e7d4210de1.webp"><br>这一点后来也成为“现场迹录”继续加入照片来源识别和验真功能的重要原因。</p><hr><h2 id="3-我更想要一个工具，而不是一个内容平台"><a href="#3-我更想要一个工具，而不是一个内容平台" class="headerlink" title="3. 我更想要一个工具，而不是一个内容平台"></a>3. 我更想要一个工具，而不是一个内容平台</h2><p>对于现场工作来说，我更需要的是：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">打开</span><br><span class="line">拍照</span><br><span class="line">填写</span><br><span class="line">保存</span><br><span class="line">结束</span><br></pre></td></tr></table></figure><p>而不是复杂的账号体系、社交功能或者大量与拍照无关的功能。</p><p>因此项目从最开始就比较强调：</p><p><strong>轻量、直接、原生。</strong></p><hr><h1 id="二、现场迹录是什么"><a href="#二、现场迹录是什么" class="headerlink" title="二、现场迹录是什么"></a>二、现场迹录是什么</h1><p>“现场迹录”目前是一套由：</p><p><strong>原生微信小程序 + 官方网站</strong></p><p>组成的现场影像记录工具。</p><p>微信小程序负责实际的：</p><ul><li>相机拍摄</li><li>水印实时预览</li><li>地理位置</li><li>天气信息</li><li>自定义水印</li><li>Logo</li><li>相册导入</li><li>高清照片合成</li><li>照片来源存证</li><li>照片验真</li></ul><p>官方网站则作为项目的 Web 入口，用于承载项目相关的信息和后续服务。<br><img src="https://img.nnu.cn/p/6a7e7d771dc05.webp"><br>官网：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://shuiyin.nnu.cn/</span><br></pre></td></tr></table></figure><p>目前小程序主要包含这些页面：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">camera</span><br><span class="line">card-designer</span><br><span class="line">web-diy</span><br><span class="line">logo-crop</span><br><span class="line">preview</span><br><span class="line">verify</span><br><span class="line">about</span><br></pre></td></tr></table></figure><p>也就是说，它实际上已经不只是一个简单的“拍照页面”。</p><p>项目正在逐渐变成一套围绕：</p><p><strong>现场影像</strong></p><p>展开的工具链。</p><hr><h1 id="三、为什么选择原生微信小程序"><a href="#三、为什么选择原生微信小程序" class="headerlink" title="三、为什么选择原生微信小程序"></a>三、为什么选择原生微信小程序</h1><p>整个项目目前采用原生微信小程序开发。</p><p>主要使用：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">WXML</span><br><span class="line">WXSS</span><br><span class="line">JavaScript</span><br><span class="line">Canvas 2D</span><br></pre></td></tr></table></figure><p>没有使用：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Vue</span><br><span class="line">React</span><br><span class="line">Taro</span><br><span class="line">uni-app</span><br></pre></td></tr></table></figure><p>等跨端框架。</p><p>也没有引入大型第三方 UI 框架。</p><p>对于普通业务应用来说，框架能够明显提升开发效率。</p><p>但相机类小程序比较特殊。</p><p>项目大量依赖微信原生能力，例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Camera</span><br><span class="line">Canvas</span><br><span class="line">定位</span><br><span class="line">方向传感器</span><br><span class="line">相册</span><br><span class="line">文件系统</span><br><span class="line">图片信息</span><br><span class="line">窗口安全区域</span><br></pre></td></tr></table></figure><p>直接使用微信原生 API，反而能够减少中间抽象层。</p><p>另外，项目目前没有 npm 运行依赖。</p><p>整体技术栈保持得比较简单。</p><hr><h1 id="四、实时相机与水印预览"><a href="#四、实时相机与水印预览" class="headerlink" title="四、实时相机与水印预览"></a>四、实时相机与水印预览</h1><p>打开小程序以后，会直接进入相机界面。</p><p>相机页面不仅维护 Camera 状态，同时还会实时维护当前：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">时间</span><br><span class="line">日期</span><br><span class="line">位置</span><br><span class="line">经纬度</span><br><span class="line">天气</span><br><span class="line">海拔</span><br><span class="line">定位精度</span><br><span class="line">备注</span><br><span class="line">Logo</span><br><span class="line">自定义字段</span><br><span class="line">水印方案</span><br></pre></td></tr></table></figure><p>这些数据随后都可以参与水印绘制。</p><p>我希望实现的体验是：</p><blockquote><p>拍摄之前就能够大致看到最终照片是什么样子。</p></blockquote><p>因此水印不是拍完以后才突然出现，而是在 Camera 取景阶段进行实时预览。</p><p>这样用户可以提前判断：</p><ul><li>水印是否挡住主体；</li><li>字体是否太大；</li><li>Logo 是否影响画面；</li><li>当前字段是否合适；</li><li>水印应该放在哪个位置。</li></ul><hr><h1 id="五、时间和日期格式可以自由调整"><a href="#五、时间和日期格式可以自由调整" class="headerlink" title="五、时间和日期格式可以自由调整"></a>五、时间和日期格式可以自由调整</h1><p>虽然时间水印看起来很简单，但不同场景对格式的需求实际上并不完全一样。</p><p>例如时间可以显示：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">14:28</span><br><span class="line">14:28:36</span><br><span class="line">02:28 PM</span><br></pre></td></tr></table></figure><p>日期可以显示：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">2026.08.14</span><br><span class="line">2026-08-14</span><br><span class="line">2026/08/14</span><br><span class="line">2026年08月14日</span><br><span class="line">08月14日</span><br></pre></td></tr></table></figure><p>对于正式的工作归档，可以显示：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">2026.08.14 14:28:36</span><br></pre></td></tr></table></figure><p>而对于偏视觉化的照片，也可以采用：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">08月14日</span><br><span class="line">14:28</span><br></pre></td></tr></table></figure><p>这样的简化样式。</p><p>时间和日期格式会跟随水印方案保存。</p><hr><h1 id="六、自动定位与地点识别"><a href="#六、自动定位与地点识别" class="headerlink" title="六、自动定位与地点识别"></a>六、自动定位与地点识别</h1><p>对于现场工作照片而言：</p><p><strong>位置通常和时间一样重要。</strong></p><p>小程序会调用微信位置能力获取当前位置。</p><p>主要使用：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">getLocation</span><br><span class="line">chooseLocation</span><br></pre></td></tr></table></figure><p>得到经纬度以后，再调用腾讯位置服务进行逆地址解析。</p><p>这里我没有单纯追求显示一个非常长的完整地址。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">某省某市某区某街道某号……</span><br></pre></td></tr></table></figure><p>虽然信息完整，但放在照片上可读性并不好。</p><p>因此更希望优先得到附近具有实际意义的 POI。</p><p>比如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">某学校</span><br><span class="line">某园区</span><br><span class="line">某办公楼</span><br><span class="line">某场馆</span><br><span class="line">某教学楼</span><br></pre></td></tr></table></figure><p>这类名称往往比完整行政地址更适合作为现场照片水印。</p><p>如果自动定位结果不准确，也可以调用微信地图进行手动选点。</p><hr><h1 id="七、天气、海拔和定位精度"><a href="#七、天气、海拔和定位精度" class="headerlink" title="七、天气、海拔和定位精度"></a>七、天气、海拔和定位精度</h1><p>除了位置，我还增加了一些可选现场信息。</p><h2 id="天气"><a href="#天气" class="headerlink" title="天气"></a>天气</h2><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">晴 31℃</span><br></pre></td></tr></table></figure><p>或者：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">多云 28℃</span><br></pre></td></tr></table></figure><p>对于：</p><ul><li>户外施工</li><li>工程巡检</li><li>活动保障</li><li>设备检查</li></ul><p>来说，天气实际上也是现场环境的一部分。</p><hr><h2 id="海拔"><a href="#海拔" class="headerlink" title="海拔"></a>海拔</h2><p>部分场景可以开启：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">海拔 36m</span><br></pre></td></tr></table></figure><p>普通工作可以关闭。</p><p>只有需要时才显示，不强行占用水印空间。</p><hr><h2 id="定位精度"><a href="#定位精度" class="headerlink" title="定位精度"></a>定位精度</h2><p>还可以显示类似：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">定位精度 ±8m</span><br></pre></td></tr></table></figure><p>这项信息对于普通拍照没有太大价值。</p><p>但如果照片被用于现场记录，那么能够知道当前 GPS 定位的大致可信范围，会更严谨一些。</p><hr><h1 id="八、水印不是模板，而是一张可以设计的“卡片”"><a href="#八、水印不是模板，而是一张可以设计的“卡片”" class="headerlink" title="八、水印不是模板，而是一张可以设计的“卡片”"></a>八、水印不是模板，而是一张可以设计的“卡片”</h1><p>这是项目后来变化最大的一部分。</p><p>最开始我也准备像普通水印相机一样：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">模板1</span><br><span class="line">模板2</span><br><span class="line">模板3</span><br><span class="line">模板4</span><br></pre></td></tr></table></figure><p>不断增加固定模板。</p><p>后来发现这种方式很快就会失控。</p><p>因为每增加一种工作场景，就需要再设计一套新模板。</p><p>所以我最终加入了：</p><h1 id="自定义水印卡片设计器"><a href="#自定义水印卡片设计器" class="headerlink" title="自定义水印卡片设计器"></a>自定义水印卡片设计器</h1><p>用户可以自己设计水印。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">某单位</span><br><span class="line"></span><br><span class="line">信息化运维 · 故障处理</span><br><span class="line"></span><br><span class="line">09:42:16</span><br><span class="line">2026.08.14</span><br><span class="line"></span><br><span class="line">地点：某教学楼设备间</span><br><span class="line">处理人：运维人员A</span><br><span class="line">故障：网络异常</span><br><span class="line">状态：已恢复</span><br></pre></td></tr></table></figure><p>设计完成后保存为自己的水印方案。</p><p>下一次打开相机，可以直接调用。</p><hr><h1 id="九、自定义卡片设计器"><a href="#九、自定义卡片设计器" class="headerlink" title="九、自定义卡片设计器"></a>九、自定义卡片设计器</h1><p>设计器支持不同卡片比例。</p><p>包括：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">横向长条</span><br><span class="line">Banner</span><br><span class="line">16:9</span><br><span class="line">4:3</span><br><span class="line">正方形</span><br><span class="line">竖版</span><br><span class="line">自定义比例</span><br></pre></td></tr></table></figure><p>程序会根据水印比例动态计算画布尺寸，而不是简单拉伸图片。</p><p>水印可以包含：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">标题</span><br><span class="line">时间</span><br><span class="line">日期</span><br><span class="line">地点</span><br><span class="line">天气</span><br><span class="line">备注</span><br><span class="line">自定义字段</span><br><span class="line">自定义文字</span><br></pre></td></tr></table></figure><p>每一个字段都可以独立控制：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">位置</span><br><span class="line">字体大小</span><br><span class="line">字体颜色</span><br><span class="line">字重</span><br><span class="line">透明度</span><br><span class="line">阴影</span><br><span class="line">显示 / 隐藏</span><br></pre></td></tr></table></figure><p>另外还加入了：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">拖拽</span><br><span class="line">辅助线</span><br><span class="line">图层</span><br><span class="line">字段排序</span><br><span class="line">撤销</span><br><span class="line">重做</span><br></pre></td></tr></table></figure><p>等编辑能力。</p><p>它现在已经比较接近一个：</p><p><strong>轻量级水印排版工具。</strong></p><hr><h1 id="十、水印背景和装饰层"><a href="#十、水印背景和装饰层" class="headerlink" title="十、水印背景和装饰层"></a>十、水印背景和装饰层</h1><p>如果只是文字叠加，很难形成统一视觉效果。</p><p>因此自定义卡片可以导入自己的背景素材。</p><p>例如不同工作类型可以设计成不同视觉方案：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">故障处理 —— 蓝色</span><br><span class="line">现场巡检 —— 绿色</span><br><span class="line">活动保障 —— 橙色</span><br></pre></td></tr></table></figure><p>背景可以调整：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">透明度</span><br><span class="line">缩放</span><br><span class="line">X 轴位置</span><br><span class="line">Y 轴位置</span><br></pre></td></tr></table></figure><p>同时还存在一个独立的装饰层。</p><p>这样水印实际可以拆成：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">背景</span><br><span class="line">装饰</span><br><span class="line">文字</span><br><span class="line">Logo</span><br></pre></td></tr></table></figure><p>不同层级。</p><p>这样企业、学校、项目组甚至个人，都可以制作自己的水印视觉系统。</p><hr><h1 id="十一、Logo-裁剪与独立调整"><a href="#十一、Logo-裁剪与独立调整" class="headerlink" title="十一、Logo 裁剪与独立调整"></a>十一、Logo 裁剪与独立调整</h1><p>很多工作照片都会使用单位 Logo。</p><p>但是直接选择一张 Logo 图片以后，经常会出现：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">透明区域太大</span><br><span class="line">图片带白边</span><br><span class="line">比例异常</span><br><span class="line">Logo 太大</span><br><span class="line">Logo 太小</span><br></pre></td></tr></table></figure><p>所以项目专门增加了：</p><h1 id="Logo-裁剪"><a href="#Logo-裁剪" class="headerlink" title="Logo 裁剪"></a>Logo 裁剪</h1><p>页面。</p><p>Logo 可以在导入以后先进行裁剪和处理。</p><p>随后在水印中继续调整：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">显示 / 隐藏</span><br><span class="line">大小</span><br><span class="line">比例</span><br><span class="line">位置</span><br><span class="line">显示方式</span><br></pre></td></tr></table></figure><p>这样 Logo 就可以真正融入整个水印设计，而不是简单贴在图片旁边。</p><hr><h1 id="十二、自定义字段和人员预设"><a href="#十二、自定义字段和人员预设" class="headerlink" title="十二、自定义字段和人员预设"></a>十二、自定义字段和人员预设</h1><p>实际工作中，有些内容需要每次改变。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">项目：</span><br><span class="line">负责人：</span><br><span class="line">施工人：</span><br><span class="line">巡检人：</span><br><span class="line">处理人：</span><br><span class="line">设备：</span><br><span class="line">状态：</span><br></pre></td></tr></table></figure><p>如果每拍一张照片都重新输入，会非常麻烦。</p><p>因此设计器中的部分字段可以定义为：</p><p><strong>数据字段。</strong></p><p>例如模板中定义：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">处理人：</span><br></pre></td></tr></table></figure><p>实际拍照时只需要选择：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">运维人员A</span><br></pre></td></tr></table></figure><p>最终生成：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">处理人：运维人员A</span><br></pre></td></tr></table></figure><p>对于一些人员类字段，例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">成员</span><br><span class="line">施工人</span><br><span class="line">现场人员</span><br><span class="line">参会人</span><br><span class="line">负责人</span><br><span class="line">巡检人</span><br><span class="line">处理人</span><br></pre></td></tr></table></figure><p>还支持多选。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">现场人员：工作人员A、工作人员B、工作人员C</span><br></pre></td></tr></table></figure><p>常用人员可以提前作为预设保存。</p><p>这样现场拍摄时就不需要频繁输入文字。</p><hr><h1 id="十三、实时预览不等于最终图片"><a href="#十三、实时预览不等于最终图片" class="headerlink" title="十三、实时预览不等于最终图片"></a>十三、实时预览不等于最终图片</h1><p>相机类应用有一个很容易忽略的问题：</p><p><strong>屏幕看到的东西不能直接当成最终照片。</strong></p><p>如果直接截取 Camera 页面：</p><ul><li>分辨率会降低；</li><li>水印文字可能发虚；</li><li>不同设备屏幕比例会影响结果；</li><li>最终照片尺寸无法保证。</li></ul><p>因此“现场迹录”使用的是：</p><h1 id="Camera-负责取景"><a href="#Camera-负责取景" class="headerlink" title="Camera 负责取景"></a>Camera 负责取景</h1><ul><li></li></ul><h1 id="Canvas-2D-负责最终高清合成"><a href="#Canvas-2D-负责最终高清合成" class="headerlink" title="Canvas 2D 负责最终高清合成"></a>Canvas 2D 负责最终高清合成</h1><p>拍照以后，大致处理流程为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">Camera 拍摄原图</span><br><span class="line">        ↓</span><br><span class="line">读取原始照片尺寸</span><br><span class="line">        ↓</span><br><span class="line">计算输出尺寸</span><br><span class="line">        ↓</span><br><span class="line">Canvas 绘制照片</span><br><span class="line">        ↓</span><br><span class="line">重新计算水印比例和位置</span><br><span class="line">        ↓</span><br><span class="line">绘制背景 / Logo / 文字</span><br><span class="line">        ↓</span><br><span class="line">导出 JPEG</span><br></pre></td></tr></table></figure><p>这意味着最终水印并不是简单截图。</p><p>而是按照原始照片尺寸重新绘制。</p><hr><h1 id="十四、4096px-与大图片内存控制"><a href="#十四、4096px-与大图片内存控制" class="headerlink" title="十四、4096px 与大图片内存控制"></a>十四、4096px 与大图片内存控制</h1><p>手机拍摄照片的分辨率越来越高。</p><p>一些设备拍摄出来的照片甚至可以达到：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">4000px+</span><br></pre></td></tr></table></figure><p>如果直接按照原图尺寸创建超大 Canvas，很容易造成：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">内存占用过高</span><br><span class="line">Canvas 创建失败</span><br><span class="line">应用卡顿</span><br><span class="line">甚至小程序被系统关闭</span><br></pre></td></tr></table></figure><p>因此目前项目会对输出尺寸进行限制。</p><p>照片最长边大致控制在：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">4096px</span><br></pre></td></tr></table></figure><p>再以较高 JPEG 质量导出。</p><p>这样能够在：</p><p><strong>画质</strong></p><p>和：</p><p><strong>移动端内存</strong></p><p>之间取得比较合理的平衡。</p><hr><h1 id="十五、为什么还要支持相册导入"><a href="#十五、为什么还要支持相册导入" class="headerlink" title="十五、为什么还要支持相册导入"></a>十五、为什么还要支持相册导入</h1><p>微信小程序 Camera API 并不能完全替代手机系统相机。</p><p>例如手机系统相机可能拥有：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">HDR</span><br><span class="line">夜景</span><br><span class="line">超广角</span><br><span class="line">长焦</span><br><span class="line">防抖</span><br><span class="line">人像算法</span><br><span class="line">计算摄影</span><br></pre></td></tr></table></figure><p>等能力。</p><p>而微信小程序 Camera 能够控制的硬件能力有限。</p><p>特别是在部分设备上，虽然手机拥有多个物理摄像头，但小程序并不能像系统 Camera 一样自由选择：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">0.5×</span><br><span class="line">1×</span><br><span class="line">3×</span><br><span class="line">5×</span><br></pre></td></tr></table></figure><p>所有物理镜头。</p><p>因此项目保留了：</p><p><strong>相册导入</strong></p><p>能力。</p><p>用户可以：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">系统相机拍摄</span><br><span class="line">       ↓</span><br><span class="line">导入现场迹录</span><br><span class="line">       ↓</span><br><span class="line">添加工作水印</span><br></pre></td></tr></table></figure><p>这样能够利用手机系统相机完整的摄影能力。</p><p>但这里产生了另一个重要问题。</p><hr><h1 id="十六、现场原拍和相册加水印必须区分"><a href="#十六、现场原拍和相册加水印必须区分" class="headerlink" title="十六、现场原拍和相册加水印必须区分"></a>十六、现场原拍和相册加水印必须区分</h1><p>从相册导入的照片，即使最终水印看起来完全一样，也不能被解释成：</p><p><strong>现场实时拍摄。</strong></p><p>因此项目会记录照片来源类型。</p><p>现场 Camera 实时拍摄可以标记为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">live-camera</span><br></pre></td></tr></table></figure><p>而相册导入，则属于：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">album-watermarked</span><br></pre></td></tr></table></figure><p>两种来源在验真页面中会被区别显示。</p><p>例如相册照片会明确显示：</p><blockquote><p>相册照片，后期加水印。</p></blockquote><p>而不会显示：</p><blockquote><p>现场原拍。</p></blockquote><p>我认为这是整个设计中比较重要的一点。</p><p>因为如果连来源都不区分，那么后续的“验真”其实没有太大意义。</p><hr><h1 id="十七、给水印相机加入照片验真"><a href="#十七、给水印相机加入照片验真" class="headerlink" title="十七、给水印相机加入照片验真"></a>十七、给水印相机加入照片验真</h1><p>随着项目继续开发，我后来又增加了：</p><h1 id="照片验真"><a href="#照片验真" class="headerlink" title="照片验真"></a>照片验真</h1><p>页面。</p><p>用户可以重新选择一张“现场迹录”生成的照片进行验证。</p><p>这部分目前并不是简单读取图片 EXIF。</p><p>因为 EXIF：</p><ul><li>很容易被清除；</li><li>可以被修改；</li><li>很多平台转发以后会直接删除。</li></ul><p>因此项目采用的是多种机制组合判断。</p><p>目前涉及：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">SHA-256</span><br><span class="line">Visual Hash</span><br><span class="line">多区域视觉 Hash</span><br><span class="line">Integrity Hash</span><br><span class="line">水印区域 Hash</span><br><span class="line">Blind Watermark</span><br><span class="line">服务端存证</span><br></pre></td></tr></table></figure><p>它们解决的问题并不完全相同。</p><hr><h1 id="十八、SHA-256：判断是不是同一个文件"><a href="#十八、SHA-256：判断是不是同一个文件" class="headerlink" title="十八、SHA-256：判断是不是同一个文件"></a>十八、SHA-256：判断是不是同一个文件</h1><p>照片保存以后，会生成 SHA-256 文件指纹。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">9b1d5c……</span><br></pre></td></tr></table></figure><p>如果文件任何一个字节发生改变，那么 SHA-256 通常就会完全变化。</p><p>因此 SHA-256 非常适合回答：</p><blockquote><p>当前这个文件是不是当初登记的那一份文件？</p></blockquote><p>如果 Hash 完全一致，可以得到非常强的文件完整性结果。</p><p>但是 SHA-256 也存在明显问题。</p><p>例如照片被：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">系统相册重新编码</span><br><span class="line">聊天软件压缩</span><br><span class="line">JPEG 二次编码</span><br></pre></td></tr></table></figure><p>以后，即使肉眼看起来没有任何变化：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SHA256</span><br></pre></td></tr></table></figure><p>仍然会改变。</p><p>所以单纯依赖 SHA-256 是不够的。</p><hr><h1 id="十九、Visual-Hash：判断还是不是那张照片"><a href="#十九、Visual-Hash：判断还是不是那张照片" class="headerlink" title="十九、Visual Hash：判断还是不是那张照片"></a>十九、Visual Hash：判断还是不是那张照片</h1><p>因此还加入了：</p><h1 id="Visual-Hash"><a href="#Visual-Hash" class="headerlink" title="Visual Hash"></a>Visual Hash</h1><p>可以把它简单理解成：</p><p>SHA-256 判断：</p><blockquote><p>文件是否完全相同。</p></blockquote><p>Visual Hash 判断：</p><blockquote><p>视觉内容是不是仍然是那张照片。</p></blockquote><p>例如照片经历：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">JPEG 压缩</span><br><span class="line">尺寸调整</span><br><span class="line">系统重新编码</span><br><span class="line">聊天软件重新编码</span><br></pre></td></tr></table></figure><p>只要主体内容没有明显变化，视觉特征仍有可能匹配。</p><p>因此系统可以进一步区分：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">原始文件完全一致</span><br></pre></td></tr></table></figure><p>和：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">来源匹配，但文件已经重新编码</span><br></pre></td></tr></table></figure><p>而不是简单显示：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">成功</span><br><span class="line">失败</span><br></pre></td></tr></table></figure><hr><h1 id="二十、区域完整性检测"><a href="#二十、区域完整性检测" class="headerlink" title="二十、区域完整性检测"></a>二十、区域完整性检测</h1><p>只比较整张图片的视觉特征仍然不够。</p><p>因为有人完全可能只修改照片一个很小的区域。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">增加马赛克</span><br><span class="line">擦除某个人</span><br><span class="line">修改设备屏幕内容</span><br><span class="line">覆盖一块区域</span><br><span class="line">修改某个数字</span><br></pre></td></tr></table></figure><p>这种情况下：</p><p><strong>整张图片仍然非常相似。</strong></p><p>因此项目又加入了区域完整性特征。</p><p>把图片划分成多个区域以后分别进行特征判断。</p><p>如果发现某些区域和原始存证明显不同，可以返回类似：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CONTENT CHANGED</span><br></pre></td></tr></table></figure><p>并提示：</p><blockquote><p>照片内容可能已经发生修改。</p></blockquote><p>这样就比“整张图看起来差不多”更加严格。</p><hr><h1 id="二十一、Blind-Watermark：隐形来源标记"><a href="#二十一、Blind-Watermark：隐形来源标记" class="headerlink" title="二十一、Blind Watermark：隐形来源标记"></a>二十一、Blind Watermark：隐形来源标记</h1><p>除了肉眼能够看到的水印之外，项目还加入了：</p><h1 id="Blind-Watermark"><a href="#Blind-Watermark" class="headerlink" title="Blind Watermark"></a>Blind Watermark</h1><p>也就是：</p><p><strong>隐形盲水印。</strong></p><p>它不是：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">2026.08.14</span><br><span class="line">某地点</span><br><span class="line">某项目</span><br></pre></td></tr></table></figure><p>这种用户肉眼能够直接看到的文字。</p><p>而是一种隐藏的照片来源标记。</p><p>验真时，小程序会尝试重新提取这个标记。</p><p>如果：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">文件信息</span><br><span class="line">+</span><br><span class="line">图片视觉特征</span><br><span class="line">+</span><br><span class="line">盲水印</span><br><span class="line">+</span><br><span class="line">服务器存证</span><br></pre></td></tr></table></figure><p>都能够相互对应，就能够进一步提高来源判断的可信度。</p><p>如果：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">盲水印存在</span><br></pre></td></tr></table></figure><p>但：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">照片内容完全不匹配</span><br></pre></td></tr></table></figure><p>系统也不会直接判断为正版。</p><p>而是会返回类似：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MARKER DETECTED</span><br></pre></td></tr></table></figure><p>表示：</p><blockquote><p>检测到了迹录标记，但当前照片内容与对应存证并不匹配。</p></blockquote><hr><h1 id="二十二、水印区域本身也需要验证"><a href="#二十二、水印区域本身也需要验证" class="headerlink" title="二十二、水印区域本身也需要验证"></a>二十二、水印区域本身也需要验证</h1><p>还有一种情况更加值得注意。</p><p>照片主体完全不修改，只修改：</p><p><strong>水印。</strong></p><p>例如：</p><p>原本：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">2026.08.14</span><br></pre></td></tr></table></figure><p>被改成：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">2026.08.12</span><br></pre></td></tr></table></figure><p>或者：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">地点：某教学楼</span><br></pre></td></tr></table></figure><p>被改成另外一个地点。</p><p>从图片主体来看，这两张照片几乎完全一样。</p><p>所以项目会单独记录：</p><p><strong>水印区域特征。</strong></p><p>如果主体照片能够匹配，但水印区域发生明显变化，则可以返回：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WATERMARK CHANGED</span><br></pre></td></tr></table></figure><p>提示：</p><blockquote><p>照片来源可能匹配，但是水印内容已经发生变化。</p></blockquote><p>对于工作记录来说，我认为这一点甚至比检测照片主体变化更加重要。</p><p>因为：</p><p><strong>时间、地点、人员和工作内容本身就是照片记录的一部分。</strong></p><hr><h1 id="二十三、为什么转发后的照片不能说“100-未修改”"><a href="#二十三、为什么转发后的照片不能说“100-未修改”" class="headerlink" title="二十三、为什么转发后的照片不能说“100%未修改”"></a>二十三、为什么转发后的照片不能说“100%未修改”</h1><p>这是整个照片验真系统里比较容易产生误解的地方。</p><p>照片经过聊天软件发送以后，平台很可能会重新：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">编码</span><br><span class="line">压缩</span><br><span class="line">调整 JPEG 参数</span><br><span class="line">删除元数据</span><br></pre></td></tr></table></figure><p>因此即使用户什么都没有修改：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">文件 Hash</span><br></pre></td></tr></table></figure><p>也可能和原图完全不同。</p><p>在这种情况下，如果程序仍然直接提示：</p><blockquote><p>照片完全未修改。</p></blockquote><p>其实并不严谨。</p><p>所以系统会出现类似：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">来源已确认</span><br><span class="line">分享后完整性待确认</span><br></pre></td></tr></table></figure><p>这样的状态。</p><p>意思是：</p><p><strong>可以确认照片与某条现场迹录存证存在来源关系。</strong></p><p>但：</p><p><strong>无法继续宣称当前这个重新编码后的文件和原始文件字节级完全一致。</strong></p><p>整个验真系统希望遵循的原则就是：</p><h1 id="能证明多少，就显示多少。"><a href="#能证明多少，就显示多少。" class="headerlink" title="能证明多少，就显示多少。"></a>能证明多少，就显示多少。</h1><p>而不是为了让结果看起来漂亮，就简单显示一个绿色的：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">100%真实</span><br></pre></td></tr></table></figure><hr><h1 id="二十四、验真不是简单的“真”和“假”"><a href="#二十四、验真不是简单的“真”和“假”" class="headerlink" title="二十四、验真不是简单的“真”和“假”"></a>二十四、验真不是简单的“真”和“假”</h1><p>目前验真页面会尝试区分多种情况。</p><p>例如：</p><h2 id="JILU-AUTHENTIC"><a href="#JILU-AUTHENTIC" class="headerlink" title="JILU AUTHENTIC"></a>JILU AUTHENTIC</h2><p>表示：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">文件指纹</span><br><span class="line">盲水印</span><br><span class="line">存证信息</span><br></pre></td></tr></table></figure><p>能够匹配。</p><p>可以认为是迹录相机登记的原始照片。</p><hr><h2 id="JILU-SOURCE-VERIFIED"><a href="#JILU-SOURCE-VERIFIED" class="headerlink" title="JILU SOURCE VERIFIED"></a>JILU SOURCE VERIFIED</h2><p>表示：</p><blockquote><p>来源已经确认，但图片经过系统相册或者其它方式重新编码。</p></blockquote><hr><h2 id="ALBUM-WATERMARKED"><a href="#ALBUM-WATERMARKED" class="headerlink" title="ALBUM WATERMARKED"></a>ALBUM WATERMARKED</h2><p>表示：</p><blockquote><p>这是一张从相册导入后，由现场迹录添加水印的照片。</p></blockquote><p>可以确认：</p><p><strong>经过现场迹录处理。</strong></p><p>但不能把它解释为：</p><p><strong>现场实时拍摄。</strong></p><hr><h2 id="CONTENT-CHANGED"><a href="#CONTENT-CHANGED" class="headerlink" title="CONTENT CHANGED"></a>CONTENT CHANGED</h2><p>表示：</p><blockquote><p>检测到画面部分区域和原始存证存在明显差异。</p></blockquote><hr><h2 id="WATERMARK-CHANGED"><a href="#WATERMARK-CHANGED" class="headerlink" title="WATERMARK CHANGED"></a>WATERMARK CHANGED</h2><p>表示：</p><blockquote><p>主体可能匹配，但水印区域发生变化。</p></blockquote><hr><h2 id="MARKER-DETECTED"><a href="#MARKER-DETECTED" class="headerlink" title="MARKER DETECTED"></a>MARKER DETECTED</h2><p>表示：</p><blockquote><p>检测到迹录盲水印，但照片内容与对应存证不匹配。</p></blockquote><p>这种分级方式比单纯：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">真</span><br><span class="line">假</span><br></pre></td></tr></table></figure><p>更加符合实际情况。</p><hr><h1 id="二十五、照片存证并不意味着上传所有照片"><a href="#二十五、照片存证并不意味着上传所有照片" class="headerlink" title="二十五、照片存证并不意味着上传所有照片"></a>二十五、照片存证并不意味着上传所有照片</h1><p>提到照片验真，很容易让人产生一个误解：</p><blockquote><p>是不是每拍一张照片，都需要把完整原图上传服务器？</p></blockquote><p>目前我的设计思路并不是这样。</p><p>项目更希望存储用于后续验证的：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">文件 Hash</span><br><span class="line">视觉特征</span><br><span class="line">完整性特征</span><br><span class="line">拍摄时间</span><br><span class="line">来源类型</span><br><span class="line">验证编号</span><br><span class="line">必要的水印区域信息</span><br></pre></td></tr></table></figure><p>等验证数据。</p><p>而不是默认把用户所有工作照片集中上传。</p><p>项目目前也已经拆分了：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">contentSecurity</span><br><span class="line">photoProvenance</span><br><span class="line">watermarkContentCheck</span><br></pre></td></tr></table></figure><p>等相关服务逻辑。</p><hr><h1 id="二十六、隐私设计"><a href="#二十六、隐私设计" class="headerlink" title="二十六、隐私设计"></a>二十六、隐私设计</h1><p>水印相机天然会接触到比较敏感的数据。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">相机</span><br><span class="line">照片</span><br><span class="line">经纬度</span><br><span class="line">地理位置</span><br><span class="line">项目名称</span><br><span class="line">人员信息</span><br></pre></td></tr></table></figure><p>因此隐私一直是这个项目必须考虑的问题。</p><p>水印设置、自定义方案以及一部分素材主要保存在小程序本地 Storage。</p><p>对于服务端，只应该提交完成对应功能所必要的数据。</p><p>而且：</p><p><strong>照片来源验证不能成为无限制收集照片内容的理由。</strong></p><p>这是后续开发中仍然需要持续关注的地方。</p><p>本文所有演示内容也已经进行了匿名化处理。</p><p>出现的：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">某单位</span><br><span class="line">某学校</span><br><span class="line">某教学楼</span><br><span class="line">运维人员A</span><br><span class="line">工作人员A</span><br></pre></td></tr></table></figure><p>等均为演示数据，不对应实际人员或者工作地点。</p><hr><h1 id="二十七、手机方向与水印旋转"><a href="#二十七、手机方向与水印旋转" class="headerlink" title="二十七、手机方向与水印旋转"></a>二十七、手机方向与水印旋转</h1><p>相机类小程序还有一个比较麻烦的问题：</p><p><strong>设备方向。</strong></p><p>用户可能：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">竖屏拍摄</span><br><span class="line">左横屏拍摄</span><br><span class="line">右横屏拍摄</span><br></pre></td></tr></table></figure><p>但是不管用户怎么旋转手机，最终水印都应该保持正确阅读方向。</p><p>因此项目会结合设备方向信息计算：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">watermarkRotation</span><br></pre></td></tr></table></figure><p>当设备方向改变时重新计算：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">水印位置</span><br><span class="line">卡片尺寸</span><br><span class="line">Logo 位置</span><br><span class="line">安全边界</span><br></pre></td></tr></table></figure><p>避免出现：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">照片已经横过来了</span><br><span class="line">水印文字还保持竖屏方向</span><br></pre></td></tr></table></figure><p>这种情况。</p><hr><h1 id="二十八、不同手机的安全区域"><a href="#二十八、不同手机的安全区域" class="headerlink" title="二十八、不同手机的安全区域"></a>二十八、不同手机的安全区域</h1><p>微信小程序顶部存在系统胶囊按钮。</p><p>不同型号的：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">iPhone</span><br><span class="line">Android</span><br><span class="line">刘海屏</span><br><span class="line">异形屏</span><br></pre></td></tr></table></figure><p>顶部区域都不完全相同。</p><p>所以相机页面不能把：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">顶部按钮位置</span><br><span class="line">定位卡片位置</span><br><span class="line">缩放按钮</span><br><span class="line">工具栏</span><br></pre></td></tr></table></figure><p>全部写死。</p><p>项目会读取：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wx.<span class="title function_">getMenuButtonBoundingClientRect</span>()</span><br></pre></td></tr></table></figure><p>以及窗口信息，动态计算：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">导航高度</span><br><span class="line">顶部安全区域</span><br><span class="line">工具位置</span><br><span class="line">底部安全距离</span><br></pre></td></tr></table></figure><p>这一点对于沉浸式 Camera 页面非常重要。</p><hr><h1 id="二十九、变焦能力与物理镜头限制"><a href="#二十九、变焦能力与物理镜头限制" class="headerlink" title="二十九、变焦能力与物理镜头限制"></a>二十九、变焦能力与物理镜头限制</h1><p>Camera 会根据真机返回的：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">maxZoom</span><br></pre></td></tr></table></figure><p>动态提供变焦入口。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1×</span><br><span class="line">2×</span><br><span class="line">5×</span><br></pre></td></tr></table></figure><p>如果当前设备不支持某个倍率，相应按钮就会禁用。</p><p>不过需要注意：</p><p>微信小程序提供的 Camera 能力，并不等于系统 Camera。</p><p>例如手机可能拥有：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">0.5× 超广角</span><br><span class="line">1× 主摄</span><br><span class="line">3× 长焦</span><br><span class="line">5× 长焦</span><br></pre></td></tr></table></figure><p>但小程序没有统一公开接口可以自由选择所有物理摄像头。</p><p>所以需要特定镜头时，系统 Camera + 相册导入仍然是更加现实的方案。</p><hr><h1 id="三十、内容安全"><a href="#三十、内容安全" class="headerlink" title="三十、内容安全"></a>三十、内容安全</h1><p>因为用户可以自由编辑：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">标题</span><br><span class="line">项目</span><br><span class="line">人员</span><br><span class="line">地点</span><br><span class="line">备注</span><br><span class="line">自定义字段</span><br></pre></td></tr></table></figure><p>所以内容安全也是必须处理的问题。</p><p>项目已经加入相关文本安全检查机制。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">checkTextSecurity</span><br></pre></td></tr></table></figure><p>在用户保存或者使用部分自定义内容之前进行检查。</p><p>对于公开运行的小程序来说，这是非常必要的。</p><hr><h1 id="三十一、它更适合哪些场景"><a href="#三十一、它更适合哪些场景" class="headerlink" title="三十一、它更适合哪些场景"></a>三十一、它更适合哪些场景</h1><p>虽然它本质上是水印相机，但我并没有打算把它做成普通自拍或者生活打卡工具。</p><p>目前更希望服务的是：</p><h1 id="工作现场。"><a href="#工作现场。" class="headerlink" title="工作现场。"></a>工作现场。</h1><p>比如：</p><h2 id="信息化运维"><a href="#信息化运维" class="headerlink" title="信息化运维"></a>信息化运维</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">网络故障处理</span><br><span class="line">计算机维修</span><br><span class="line">多媒体维护</span><br><span class="line">交换机巡检</span><br><span class="line">无线 AP 巡检</span><br><span class="line">机房巡检</span><br></pre></td></tr></table></figure><hr><h2 id="校园运维"><a href="#校园运维" class="headerlink" title="校园运维"></a>校园运维</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">教室设备检查</span><br><span class="line">设备间巡检</span><br><span class="line">会议保障</span><br><span class="line">考试保障</span><br><span class="line">活动保障</span><br><span class="line">信息化设备维护</span><br></pre></td></tr></table></figure><hr><h2 id="工程施工"><a href="#工程施工" class="headerlink" title="工程施工"></a>工程施工</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">施工前</span><br><span class="line">施工中</span><br><span class="line">施工后</span><br><span class="line">隐蔽工程</span><br><span class="line">设备安装</span><br><span class="line">工程验收</span><br></pre></td></tr></table></figure><hr><h2 id="物业巡检"><a href="#物业巡检" class="headerlink" title="物业巡检"></a>物业巡检</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">消防设备</span><br><span class="line">配电房</span><br><span class="line">空调</span><br><span class="line">电梯</span><br><span class="line">门禁</span><br><span class="line">公共设施</span><br></pre></td></tr></table></figure><hr><h2 id="售后维护"><a href="#售后维护" class="headerlink" title="售后维护"></a>售后维护</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">到场记录</span><br><span class="line">维修记录</span><br><span class="line">设备更换</span><br><span class="line">处理结果</span><br></pre></td></tr></table></figure><hr><h2 id="活动保障"><a href="#活动保障" class="headerlink" title="活动保障"></a>活动保障</h2><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">会场准备</span><br><span class="line">设备调试</span><br><span class="line">网络保障</span><br><span class="line">直播保障</span><br><span class="line">现场值守</span><br></pre></td></tr></table></figure><p>这些场景最大的共同点是：</p><h1 id="照片不仅是一张照片，也是一次工作记录。"><a href="#照片不仅是一张照片，也是一次工作记录。" class="headerlink" title="照片不仅是一张照片，也是一次工作记录。"></a>照片不仅是一张照片，也是一次工作记录。</h1><hr><h1 id="三十二、当前项目结构"><a href="#三十二、当前项目结构" class="headerlink" title="三十二、当前项目结构"></a>三十二、当前项目结构</h1><p>项目目前大致结构如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">xianchang-jilu</span><br><span class="line">│</span><br><span class="line">├─ app.js</span><br><span class="line">├─ app.json</span><br><span class="line">├─ app.wxss</span><br><span class="line">│</span><br><span class="line">├─ assets</span><br><span class="line">│</span><br><span class="line">├─ config</span><br><span class="line">│</span><br><span class="line">├─ utils</span><br><span class="line">│</span><br><span class="line">├─ cloudfunctions</span><br><span class="line">│  │</span><br><span class="line">│  ├─ contentSecurity</span><br><span class="line">│  ├─ photoProvenance</span><br><span class="line">│  └─ watermarkContentCheck</span><br><span class="line">│</span><br><span class="line">└─ pages</span><br><span class="line">   │</span><br><span class="line">   ├─ camera</span><br><span class="line">   ├─ card-designer</span><br><span class="line">   ├─ web-diy</span><br><span class="line">   ├─ logo-crop</span><br><span class="line">   ├─ preview</span><br><span class="line">   ├─ verify</span><br><span class="line">   └─ about</span><br></pre></td></tr></table></figure><p>其中：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">camera</span><br></pre></td></tr></table></figure><p>负责主要的 Camera 和水印逻辑。</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">card-designer</span><br></pre></td></tr></table></figure><p>负责自定义卡片设计。</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">logo-crop</span><br></pre></td></tr></table></figure><p>负责 Logo 素材处理。</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">preview</span><br></pre></td></tr></table></figure><p>负责最终照片预览。</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">verify</span><br></pre></td></tr></table></figure><p>负责照片来源和完整性验证。</p><hr><h1 id="三十三、本地运行需要什么"><a href="#三十三、本地运行需要什么" class="headerlink" title="三十三、本地运行需要什么"></a>三十三、本地运行需要什么</h1><p>如果想自己运行项目，首先需要准备一个微信小程序 AppID。</p><p>然后使用：</p><h1 id="微信开发者工具"><a href="#微信开发者工具" class="headerlink" title="微信开发者工具"></a>微信开发者工具</h1><p>导入项目。</p><p>定位部分需要申请相关接口：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">getLocation</span><br><span class="line">chooseLocation</span><br></pre></td></tr></table></figure><p>同时需要申请腾讯位置服务 WebService API Key。</p><p>用于完成：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">经纬度</span><br><span class="line">   ↓</span><br><span class="line">逆地址解析</span><br><span class="line">   ↓</span><br><span class="line">附近地点 / POI</span><br></pre></td></tr></table></figure><p>腾讯地图 API 域名还需要加入微信小程序：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">request 合法域名</span><br></pre></td></tr></table></figure><p>发布前还必须完成：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">隐私保护指引</span><br><span class="line">摄像头用途说明</span><br><span class="line">定位用途说明</span><br><span class="line">相册相关说明</span><br><span class="line">接口权限审核</span><br></pre></td></tr></table></figure><hr><h1 id="三十四、真机测试比开发者工具重要得多"><a href="#三十四、真机测试比开发者工具重要得多" class="headerlink" title="三十四、真机测试比开发者工具重要得多"></a>三十四、真机测试比开发者工具重要得多</h1><p>相机类小程序无法只依赖微信开发者工具进行验证。</p><p>至少需要：</p><p><strong>一台 iOS 真机</strong></p><p>和：</p><p><strong>一台 Android 真机。</strong></p><p>需要重点测试：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">Camera</span><br><span class="line">定位</span><br><span class="line">地图选点</span><br><span class="line">图片保存</span><br><span class="line">相册导入</span><br><span class="line">权限拒绝</span><br><span class="line">权限恢复</span><br><span class="line">横屏</span><br><span class="line">竖屏</span><br><span class="line">前置摄像头</span><br><span class="line">大尺寸照片</span><br><span class="line">弱网络</span><br><span class="line">GPS 弱信号</span><br></pre></td></tr></table></figure><p>对于 iOS，还要特别关注：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">系统相册重新编码</span><br><span class="line">图片方向</span><br><span class="line">分享以后图片变化</span><br></pre></td></tr></table></figure><p>对于 Android，则需要关注不同厂商：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Camera 实现差异</span><br><span class="line">内存限制</span><br><span class="line">权限实现差异</span><br></pre></td></tr></table></figure><p>这种项目真机兼容性测试的工作量，实际上远高于普通信息展示型小程序。</p><hr><h1 id="三十五、后面还想继续做什么"><a href="#三十五、后面还想继续做什么" class="headerlink" title="三十五、后面还想继续做什么"></a>三十五、后面还想继续做什么</h1><p>“现场迹录”目前仍然处于持续开发阶段。</p><p>后续还有很多可以继续完善的方向。</p><h2 id="1-官方模板库"><a href="#1-官方模板库" class="headerlink" title="1. 官方模板库"></a>1. 官方模板库</h2><p>希望后续提供更多可直接安装的模板。</p><p>比如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">信息化运维</span><br><span class="line">故障处理</span><br><span class="line">设备巡检</span><br><span class="line">工程施工</span><br><span class="line">物业巡检</span><br><span class="line">活动保障</span><br><span class="line">施工记录</span><br><span class="line">验收记录</span><br></pre></td></tr></table></figure><p>用户不需要从零设计。</p><p>直接安装以后修改单位名称和 Logo 即可。</p><hr><h2 id="2-单位统一模板"><a href="#2-单位统一模板" class="headerlink" title="2. 单位统一模板"></a>2. 单位统一模板</h2><p>例如企业或者项目组可以统一维护：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Logo</span><br><span class="line">单位名称</span><br><span class="line">标准颜色</span><br><span class="line">项目名称</span><br><span class="line">标准字段</span><br></pre></td></tr></table></figure><p>现场工作人员只负责填写数据。</p><p>这样同一个项目拍出来的照片能够保持统一风格。</p><hr><h2 id="3-一次任务，多张照片"><a href="#3-一次任务，多张照片" class="headerlink" title="3. 一次任务，多张照片"></a>3. 一次任务，多张照片</h2><p>现实中的巡检通常不会只拍一张照片。</p><p>例如一次设备巡检可能连续拍摄：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">20 张</span><br><span class="line">50 张</span><br><span class="line">甚至更多</span><br></pre></td></tr></table></figure><p>如果每张照片都重新填写：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">项目</span><br><span class="line">人员</span><br><span class="line">地点</span><br><span class="line">任务</span><br></pre></td></tr></table></figure><p>效率会非常低。</p><p>所以后续比较适合加入：</p><h1 id="现场任务"><a href="#现场任务" class="headerlink" title="现场任务"></a>现场任务</h1><p>概念。</p><p>先创建：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">任务名称</span><br><span class="line">项目</span><br><span class="line">人员</span><br><span class="line">地点</span><br></pre></td></tr></table></figure><p>随后拍摄的所有照片自动继承这些信息。</p><hr><h2 id="4-自动生成工作报告"><a href="#4-自动生成工作报告" class="headerlink" title="4. 自动生成工作报告"></a>4. 自动生成工作报告</h2><p>更进一步，可以把：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">照片</span><br><span class="line">拍摄时间</span><br><span class="line">地点</span><br><span class="line">人员</span><br><span class="line">设备</span><br><span class="line">状态</span><br><span class="line">处理结果</span><br></pre></td></tr></table></figure><p>自动整理成：</p><h1 id="现场工作报告"><a href="#现场工作报告" class="headerlink" title="现场工作报告"></a>现场工作报告</h1><p>例如最终导出：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">PDF</span><br><span class="line">Excel</span><br><span class="line">Word</span><br></pre></td></tr></table></figure><p>这样它就不再只是一个：</p><p><strong>水印相机。</strong></p><p>而是进一步变成：</p><p><strong>现场工作记录工具。</strong></p><hr><h2 id="5-继续完善照片验真"><a href="#5-继续完善照片验真" class="headerlink" title="5. 继续完善照片验真"></a>5. 继续完善照片验真</h2><p>照片验真部分仍然有很多值得研究的方向。</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">时间可信度</span><br><span class="line">位置可信度</span><br><span class="line">分享链路识别</span><br><span class="line">多级完整性特征</span><br><span class="line">存证编号</span><br><span class="line">二维码验证</span><br><span class="line">原图与分享图验证</span><br></pre></td></tr></table></figure><p>等等。</p><p>这部分我也会继续根据实际使用情况迭代。</p><hr><h1 id="三十六、关于“照片真实性”的边界"><a href="#三十六、关于“照片真实性”的边界" class="headerlink" title="三十六、关于“照片真实性”的边界"></a>三十六、关于“照片真实性”的边界</h1><p>最后还需要特别说明一点。</p><p>任何一个普通应用都不应该轻易宣称：</p><blockquote><p>一张照片绝对真实。</p></blockquote><p>照片真实性本身涉及非常复杂的链路：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">拍摄设备</span><br><span class="line">操作系统</span><br><span class="line">Camera API</span><br><span class="line">系统时间</span><br><span class="line">GPS</span><br><span class="line">应用逻辑</span><br><span class="line">图片编码</span><br><span class="line">服务端</span><br><span class="line">网络</span><br><span class="line">后期传播</span><br></pre></td></tr></table></figure><p>任何一个环节都可能影响最终结果。</p><p>因此“现场迹录”的目标并不是建立一个所谓：</p><p><strong>绝对可信的数字司法取证系统。</strong></p><p>它更加现实的目标是：</p><blockquote><p>尽可能记录照片从哪里产生，并尽可能判断照片后续是否仍然与原始记录一致。</p></blockquote><p>因此系统会区分：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">现场实时拍摄</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">相册导入后加水印</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">原文件完全一致</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">来源确认但已经重新编码</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">内容疑似修改</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">水印疑似修改</span><br></pre></td></tr></table></figure><p>而不是粗暴地只显示：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">真</span><br></pre></td></tr></table></figure><p>或者：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">假</span><br></pre></td></tr></table></figure><p>我认为一个工具最重要的不是把自己的能力说得有多强，而是：</p><h1 id="清楚说明它能够证明什么，以及不能证明什么。"><a href="#清楚说明它能够证明什么，以及不能证明什么。" class="headerlink" title="清楚说明它能够证明什么，以及不能证明什么。"></a>清楚说明它能够证明什么，以及不能证明什么。</h1><hr><h1 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h1><p>刚开始做“现场迹录”的时候，我只是想做一个：</p><blockquote><p>没有多余功能、可以自己设计水印的微信小程序。</p></blockquote><p>真正开始写以后，却发现一个看似简单的水印相机，背后实际上涉及很多技术问题。</p><p>从：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Camera</span><br></pre></td></tr></table></figure><p>到：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Canvas</span><br></pre></td></tr></table></figure><p>从：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPS</span><br></pre></td></tr></table></figure><p>到：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">逆地址解析</span><br></pre></td></tr></table></figure><p>从：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">自定义水印</span><br></pre></td></tr></table></figure><p>到：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">照片来源存证</span><br></pre></td></tr></table></figure><p>再到：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">SHA-256</span><br><span class="line">Visual Hash</span><br><span class="line">Integrity Hash</span><br><span class="line">Blind Watermark</span><br></pre></td></tr></table></figure><p>项目慢慢从一个简单的：</p><p><strong>照片加水印工具</strong></p><p>发展成了现在这套：</p><h1 id="现场拍摄-→-信息水印-→-高清合成-→-来源存证-→-照片验真"><a href="#现场拍摄-→-信息水印-→-高清合成-→-来源存证-→-照片验真" class="headerlink" title="现场拍摄 → 信息水印 → 高清合成 → 来源存证 → 照片验真"></a>现场拍摄 → 信息水印 → 高清合成 → 来源存证 → 照片验真</h1><p>的完整流程。</p><p>这也是为什么最后给它取名：</p><h1 id="「现场迹录」-1"><a href="#「现场迹录」-1" class="headerlink" title="「现场迹录」"></a>「现场迹录」</h1><p>“迹”，是现场留下的痕迹。</p><p>“录”，是对一次工作过程的记录。</p><p>我希望它最终解决的，不只是：</p><blockquote><p>怎么在照片上加一行文字。</p></blockquote><p>而是：</p><h1 id="如何让每一次现场，都留下更加清晰、规范并且可以追溯的记录。"><a href="#如何让每一次现场，都留下更加清晰、规范并且可以追溯的记录。" class="headerlink" title="如何让每一次现场，都留下更加清晰、规范并且可以追溯的记录。"></a>如何让每一次现场，都留下更加清晰、规范并且可以追溯的记录。</h1><hr><h1 id="项目信息"><a href="#项目信息" class="headerlink" title="项目信息"></a>项目信息</h1><p><strong>项目名称</strong></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">现场迹录</span><br></pre></td></tr></table></figure><p><strong>项目类型</strong></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">原生微信小程序 + 官方网站</span><br></pre></td></tr></table></figure><p><strong>官方网站</strong></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://shuiyin.nnu.cn/</span><br></pre></td></tr></table></figure><p><strong>GitHub</strong></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://github.com/anyfrees/xianchang-jilu</span><br></pre></td></tr></table></figure><p><strong>主要技术</strong></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">WXML</span><br><span class="line">WXSS</span><br><span class="line">JavaScript</span><br><span class="line">Canvas 2D</span><br><span class="line">微信 Camera API</span><br><span class="line">微信定位</span><br><span class="line">腾讯位置服务</span><br><span class="line"></span><br><span class="line">SHA-256</span><br><span class="line">Visual Hash</span><br><span class="line">Integrity Hash</span><br><span class="line">Blind Watermark</span><br><span class="line">照片来源存证</span><br></pre></td></tr></table></figure><p><strong>主要功能</strong></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">实时水印拍摄</span><br><span class="line">时间 / 日期水印</span><br><span class="line">位置水印</span><br><span class="line">天气水印</span><br><span class="line">海拔</span><br><span class="line">定位精度</span><br><span class="line"></span><br><span class="line">自定义字段</span><br><span class="line">自定义水印卡片</span><br><span class="line">Logo</span><br><span class="line">水印背景</span><br><span class="line">人员预设</span><br><span class="line"></span><br><span class="line">相册导入</span><br><span class="line">Canvas 高清合成</span><br><span class="line"></span><br><span class="line">照片来源存证</span><br><span class="line">照片完整性验证</span><br><span class="line">盲水印</span><br><span class="line">照片验真</span><br></pre></td></tr></table></figure><blockquote><p>「现场迹录」目前仍在持续开发和优化中，部分功能、接口、视觉效果以及照片验真策略会随着实际使用情况继续调整。</p></blockquote><blockquote><p>本文出现的单位名称、工作地点、人员姓名和项目数据均已进行匿名化或使用虚构示例，不对应真实人员及实际工作地点。</p></blockquote>]]></content>
      
      
      <categories>
          
          <category> 项目开发 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 微信小程序 </tag>
            
            <tag> JavaScript </tag>
            
            <tag> 水印相机 </tag>
            
            <tag> Canvas </tag>
            
            <tag> 照片验真 </tag>
            
            <tag> 图像处理 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>使用 Cloudflare Workers 部署轻量级 Bitwarden 服务端 NodeWarden</title>
      <link href="/post/c0f27dad.html"/>
      <url>/post/c0f27dad.html</url>
      
        <content type="html"><![CDATA[<p><img src="https://img.nnu.cn/p/6a6af678ed34c.webp"><br>NodeWarden 是一个运行在 Cloudflare Workers 上的轻量级 Bitwarden 兼容服务端。它无需单独购买 VPS，也不用维护 Docker、数据库进程或反向代理，适合希望低成本搭建个人密码库的用户。</p><p>项目提供原创 Web Vault，并兼容常见 Bitwarden 官方客户端，支持密码同步、TOTP、Passkey、附件、Send、实时推送和云端备份等功能。</p><blockquote><p>NodeWarden 是第三方开源项目，与 Bitwarden 官方无关，仅建议用于学习和交流。密码库属于重要数据，请使用高强度主密码、开启两步验证，并定期制作可验证的加密备份。</p></blockquote><h2 id="项目地址"><a href="#项目地址" class="headerlink" title="项目地址"></a>项目地址</h2><ul><li>GitHub：<a href="https://github.com/shuaiplus/NodeWarden">shuaiplus&#x2F;NodeWarden</a></li><li>官方文档：<a href="https://nodewarden.app/zh/">NodeWarden Wiki</a></li><li>Telegram：<a href="https://t.me/nodewarden">频道</a> &#x2F; <a href="https://t.me/nodewarden_chat">群组</a></li></ul><h2 id="功能介绍"><a href="#功能介绍" class="headerlink" title="功能介绍"></a>功能介绍</h2><p>NodeWarden 已实现日常个人密码库所需的大部分功能：</p><ul><li>原创 Web Vault，支持 PWA 安装与离线使用</li><li>兼容 Bitwarden Windows、Linux、移动端及浏览器扩展</li><li>密码登录、Passkey 登录和 API Key 登录</li><li>TOTP、YubiKey、Passkey 两步验证及恢复码</li><li>多设备管理、可信设备和实时推送同步</li><li>密码、文件夹、附件及 Bitwarden Send</li><li>Bitwarden JSON、CSV、ZIP 导入与导出</li><li>WebDAV、S3 兼容存储的定时增量备份</li><li>邀请码注册和多用户使用</li><li>自定义等效域名和全局域名规则</li></ul><p>目前尚未实现组织、集合、成员权限、SSO、SCIM 和企业目录等企业功能。</p><h2 id="已测试客户端"><a href="#已测试客户端" class="headerlink" title="已测试客户端"></a>已测试客户端</h2><table><thead><tr><th>客户端</th><th>支持情况</th></tr></thead><tbody><tr><td>Windows 桌面端</td><td>✅ 已测试</td></tr><tr><td>手机 App</td><td>✅ 已测试</td></tr><tr><td>浏览器扩展</td><td>✅ 已测试</td></tr><tr><td>Linux 桌面端</td><td>✅ 已测试</td></tr><tr><td>macOS 桌面端</td><td>⚠️ 尚未完整验证</td></tr></tbody></table><h2 id="部署前的准备"><a href="#部署前的准备" class="headerlink" title="部署前的准备"></a>部署前的准备</h2><p>开始之前需要准备：</p><ol><li>一个 GitHub 账号；</li><li>一个 Cloudflare 账号；</li><li>一个不少于 32 个字符的随机 <code>JWT_SECRET</code>；</li><li>根据附件需求选择 R2 或 KV 存储。</li></ol><p>NodeWarden 使用以下 Cloudflare 服务：</p><ul><li>Workers：运行服务端接口并提供网页；</li><li>D1：保存用户、密码库密文、附件元数据及配置；</li><li>R2 或 KV：保存附件和 Send 文件；</li><li>Durable Objects：提供实时通知；</li><li>Cron Triggers：执行定时备份任务。</li></ul><h2 id="R2-和-KV-应该怎么选"><a href="#R2-和-KV-应该怎么选" class="headerlink" title="R2 和 KV 应该怎么选"></a>R2 和 KV 应该怎么选</h2><table><thead><tr><th>存储方式</th><th>是否需要绑卡</th><th>单个附件或 Send 文件上限</th><th>免费额度</th><th>适合场景</th></tr></thead><tbody><tr><td>R2</td><td>需要</td><td>默认 100 MB，属于项目软限制</td><td>10 GB</td><td>正式使用，推荐</td></tr><tr><td>KV</td><td>不需要</td><td>25 MiB，Cloudflare 平台限制</td><td>1 GB</td><td>体验或只保存小附件</td></tr></tbody></table><p>如果 Cloudflare 账号可以绑定支付方式，优先选择 R2。KV 部署更简单，但文件大小和容量限制更明显。</p><h2 id="通过-Cloudflare-控制台部署"><a href="#通过-Cloudflare-控制台部署" class="headerlink" title="通过 Cloudflare 控制台部署"></a>通过 Cloudflare 控制台部署</h2><h3 id="1-Fork-项目"><a href="#1-Fork-项目" class="headerlink" title="1. Fork 项目"></a>1. Fork 项目</h3><p>打开 <a href="https://github.com/shuaiplus/NodeWarden">NodeWarden GitHub 仓库</a>，点击右上角的 <code>Fork</code>，将项目复制到自己的 GitHub 账号。</p><h3 id="2-创建-Workers-项目"><a href="#2-创建-Workers-项目" class="headerlink" title="2. 创建 Workers 项目"></a>2. 创建 Workers 项目</h3><p>进入 <a href="https://dash.cloudflare.com/">Cloudflare Workers &amp; Pages</a>，选择通过 GitHub 导入项目，然后选择刚刚 Fork 的 NodeWarden 仓库。</p><h3 id="3-填写构建命令"><a href="#3-填写构建命令" class="headerlink" title="3. 填写构建命令"></a>3. 填写构建命令</h3><p>使用 R2 存储时填写：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 构建命令</span></span><br><span class="line">npm run build</span><br><span class="line"></span><br><span class="line"><span class="comment"># 部署命令</span></span><br><span class="line">npm run deploy</span><br></pre></td></tr></table></figure><p>如果使用 KV 存储，将部署命令改为：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run deploy:kv</span><br></pre></td></tr></table></figure><p>项目中的 <code>wrangler.toml</code> 或 <code>wrangler.kv.toml</code> 会定义所需的资源绑定。Worker 第一次收到请求时会自动初始化 D1 数据库，不需要手动上传 SQL 文件。</p><h3 id="4-配置-JWT-SECRET"><a href="#4-配置-JWT-SECRET" class="headerlink" title="4. 配置 JWT_SECRET"></a>4. 配置 JWT_SECRET</h3><p>部署完成后，进入 Worker 的“设置 → 变量和机密”，新增一个加密 Secret：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">变量名：JWT_SECRET</span><br><span class="line">变量值：不少于 32 个字符的高强度随机字符串</span><br></pre></td></tr></table></figure><p>请勿使用项目示例值，也不要将真实密钥写入 GitHub 仓库、<code>wrangler.toml</code>、日志或截图中。</p><p><code>JWT_SECRET</code> 用于登录令牌、附件和 Send 短期令牌，以及备份配置加密。正式使用后不要随意更换，否则现有登录状态和部分备份设置会失效。</p><h3 id="5-访问并注册管理员"><a href="#5-访问并注册管理员" class="headerlink" title="5. 访问并注册管理员"></a>5. 访问并注册管理员</h3><p>打开 Cloudflare 生成的 Workers 地址。第一次注册的用户会成为管理员，后续用户通常需要邀请码才能注册。</p><p>部分网络环境可能无法正常访问默认的 <code>workers.dev</code> 域名，建议在 Worker 设置中绑定自己的域名。</p><h2 id="使用命令行部署"><a href="#使用命令行部署" class="headerlink" title="使用命令行部署"></a>使用命令行部署</h2><p>如果希望在本地完成部署，可以依次执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/shuaiplus/NodeWarden.git</span><br><span class="line"><span class="built_in">cd</span> NodeWarden</span><br><span class="line"></span><br><span class="line">npm install</span><br><span class="line">npx wrangler login</span><br><span class="line"></span><br><span class="line"><span class="comment"># 默认使用 R2</span></span><br><span class="line">npm run deploy</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或者使用 KV</span></span><br><span class="line">npm run deploy:kv</span><br></pre></td></tr></table></figure><p>部署完成后添加 Secret：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx wrangler secret put JWT_SECRET</span><br></pre></td></tr></table></figure><p>本地开发命令如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># R2 模式</span></span><br><span class="line">npm run dev</span><br><span class="line"></span><br><span class="line"><span class="comment"># KV 模式</span></span><br><span class="line">npm run dev:kv</span><br></pre></td></tr></table></figure><h2 id="隐藏网页密码库"><a href="#隐藏网页密码库" class="headerlink" title="隐藏网页密码库"></a>隐藏网页密码库</h2><p>如果只使用 Bitwarden 官方客户端，不希望公开 Web Vault，可以在 Worker 的“设置 → 变量和机密”中添加普通文本变量：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">变量名：HIDE_WEB_VAULT</span><br><span class="line">变量值：1</span><br></pre></td></tr></table></figure><p>启用后，服务器上的前端页面和静态资源会返回 <code>404 Not Found</code>，但登录、同步、附件、图标和通知等客户端接口仍然可用。删除该变量或把值改为非 <code>1</code> 即可恢复 Web Vault。</p><p>已经安装或被浏览器缓存的 PWA 仍可能继续使用本地前端，因此该设置不能代替设备端的退出登录和缓存清理。</p><h2 id="连接-Bitwarden-客户端"><a href="#连接-Bitwarden-客户端" class="headerlink" title="连接 Bitwarden 客户端"></a>连接 Bitwarden 客户端</h2><p>在 Bitwarden 官方客户端登录页面选择“自托管”或“自定义服务器”，将服务器 URL 设置为 NodeWarden 的完整域名，例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://vault.example.com</span><br></pre></td></tr></table></figure><p>服务器地址末尾不要添加 <code>/api</code>。保存设置后，使用在 NodeWarden 中注册的邮箱和主密码登录即可。</p><h2 id="更新项目"><a href="#更新项目" class="headerlink" title="更新项目"></a>更新项目</h2><p>打开自己 Fork 的 GitHub 仓库，如果页面提示上游存在新提交，依次点击：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Sync fork → Update branch</span><br></pre></td></tr></table></figure><p>同步完成后，Cloudflare 会自动重新构建和部署。更新前建议先创建备份，并确认原有 <code>JWT_SECRET</code>、D1、R2&#x2F;KV 和 Durable Objects 绑定没有被删除。</p><h2 id="安全建议"><a href="#安全建议" class="headerlink" title="安全建议"></a>安全建议</h2><p>密码库服务一旦失守，影响往往远大于普通网站。部署后建议完成以下设置：</p><ul><li>Cloudflare 和 GitHub 账号均开启 Passkey 或硬件密钥两步验证；</li><li>主密码使用从未在其他网站使用过的长随机密码；</li><li>NodeWarden 账号开启两步验证，并离线保存恢复码；</li><li>使用自定义域名并始终通过 HTTPS 访问；</li><li>不要直接启用来源不明的 Fork 或未经检查的自动更新；</li><li>定期导出加密备份，并将备份保存到另一家存储服务；</li><li>定期实际测试备份能否成功恢复；</li><li>不要把主密码、恢复码和 Cloudflare 恢复信息全部只保存在同一个密码库中。</li></ul><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><h3 id="页面提示缺少-JWT-SECRET"><a href="#页面提示缺少-JWT-SECRET" class="headerlink" title="页面提示缺少 JWT_SECRET"></a>页面提示缺少 JWT_SECRET</h3><p>进入 Worker 的变量设置，确认添加的是加密 Secret，名称必须准确写成 <code>JWT_SECRET</code>，值不少于 32 个字符。配置后重新部署或刷新页面。</p><h3 id="默认-Workers-地址无法访问"><a href="#默认-Workers-地址无法访问" class="headerlink" title="默认 Workers 地址无法访问"></a>默认 Workers 地址无法访问</h3><p>部分网络环境无法稳定访问 <code>workers.dev</code>。可以在 Cloudflare Worker 中绑定自己的域名，并确认 DNS 和 HTTPS 证书已经生效。</p><h3 id="上传附件失败"><a href="#上传附件失败" class="headerlink" title="上传附件失败"></a>上传附件失败</h3><p>首先确认已经正确绑定 R2 或 KV。使用 KV 时，单个对象不能超过 25 MiB；如果经常保存附件，建议改用 R2。</p><h3 id="Bitwarden-客户端无法登录"><a href="#Bitwarden-客户端无法登录" class="headerlink" title="Bitwarden 客户端无法登录"></a>Bitwarden 客户端无法登录</h3><p>检查客户端填写的服务器地址是否包含多余的 <code>/api</code>，并确认 <code>/identity/accounts/prelogin</code> 可以正常访问。还需要检查 <code>JWT_SECRET</code>、D1 和 Durable Objects 是否绑定成功。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>NodeWarden 利用 Cloudflare Workers、D1 和 R2&#x2F;KV，将传统密码管理服务端改造成了几乎免运维的 Serverless 应用。它部署简单、成本较低，也能够连接常见 Bitwarden 客户端。</p><p>不过，NodeWarden 是非官方第三方实现，不能因为使用了 Cloudflare 就忽略应用自身的安全风险。正式保存重要数据前，应当了解项目边界，配置强认证和异地加密备份，并谨慎处理每一次更新。</p><h2 id="开源协议与致谢"><a href="#开源协议与致谢" class="headerlink" title="开源协议与致谢"></a>开源协议与致谢</h2><p>NodeWarden 使用 LGPL-3.0 协议开源，其设计和实现参考或使用了以下项目及平台：</p><ul><li><a href="https://bitwarden.com/">Bitwarden</a>：原始设计与官方客户端；</li><li><a href="https://github.com/dani-garcia/vaultwarden">Vaultwarden</a>：服务端实现参考；</li><li><a href="https://workers.cloudflare.com/">Cloudflare Workers</a>：Serverless 运行平台。</li></ul>]]></content>
      
      
      <categories>
          
          <category> 建站教程 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> NodeWarden </tag>
            
            <tag> Bitwarden </tag>
            
            <tag> Cloudflare Workers </tag>
            
            <tag> 密码管理 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>我为 Hexo 博客开发了一款原生微信小程序</title>
      <link href="/post/42f86cf8.html"/>
      <url>/post/42f86cf8.html</url>
      
        <content type="html"><![CDATA[<p><img src="https://img.nnu.cn/p/6a698a7e06ec5.webp"><br>扫码预览效果<br>一直以来，我都在使用 Hexo 维护自己的技术博客。Hexo 很适合组织和发布长期内容，但在手机上阅读时，网页与原生应用之间仍然存在一些体验差距：每次都要打开浏览器、寻找网址，页面加载和导航也很难做到像小程序一样轻便。</p><p>于是，我为自己的博客开发了一款原生微信小程序——<strong>NNU 技术博客小程序</strong>。</p><p>它不是简单地在小程序里套一层网页，而是直接读取 Hexo 生成的文章索引，在小程序端完成解析、分类、搜索和正文渲染。博客仍然负责内容生产，小程序则成为一个更适合移动阅读的新入口。</p><p>项目已经开源：</p><ul><li>GitHub：<a href="https://github.com/anyfrees/nnuwx">anyfrees&#x2F;nnuwx</a></li><li>在线博客：<a href="https://www.nnu.cn/">NNU 技术博客</a></li><li>文章索引：<a href="https://www.nnu.cn/search.xml">search.xml</a></li></ul><h2 id="为什么要做这个小程序"><a href="#为什么要做这个小程序" class="headerlink" title="为什么要做这个小程序"></a>为什么要做这个小程序</h2><p>我希望它解决三个问题。</p><h3 id="让已有博客内容自然进入微信"><a href="#让已有博客内容自然进入微信" class="headerlink" title="让已有博客内容自然进入微信"></a>让已有博客内容自然进入微信</h3><p>重新为小程序维护一套文章数据库，会让内容发布变得非常繁琐。文章在 Hexo 中更新后，还要再上传一次小程序后台，这不仅重复劳动，也容易造成两个平台内容不一致。</p><p>因此，这个小程序不维护独立的文章数据库，而是直接读取 Hexo 输出的 <code>search.xml</code>。只要博客完成发布，小程序下一次刷新时就能获取新内容。</p><h3 id="提供真正适合移动端的阅读界面"><a href="#提供真正适合移动端的阅读界面" class="headerlink" title="提供真正适合移动端的阅读界面"></a>提供真正适合移动端的阅读界面</h3><p>小程序采用原生 WXML、WXSS 和 JavaScript 开发，没有通过 <code>web-view</code> 直接嵌入整个博客。首页、分类、搜索、文章详情、收藏和阅读历史都拥有独立的小程序页面。</p><p>这样可以获得更自然的页面切换、触觉反馈、下拉刷新、图片预览、代码复制和微信分享体验。</p><h3 id="尽量保持简单的部署架构"><a href="#尽量保持简单的部署架构" class="headerlink" title="尽量保持简单的部署架构"></a>尽量保持简单的部署架构</h3><p>项目不需要单独部署内容 API，也不需要额外的数据库。文章、分类和标签来自 Hexo；收藏、搜索记录和阅读历史保存在微信本地存储；评论及浏览数据则复用博客已有的 Twikoo 接口。</p><p>整个数据链路可以概括为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Markdown 文章</span><br><span class="line">     ↓</span><br><span class="line">Hexo 构建并发布博客</span><br><span class="line">     ↓</span><br><span class="line">生成 search.xml 和文章页面</span><br><span class="line">     ↓</span><br><span class="line">微信小程序请求并解析数据</span><br><span class="line">     ↓</span><br><span class="line">首页 / 分类 / 搜索 / 文章详情</span><br></pre></td></tr></table></figure><h2 id="项目定位"><a href="#项目定位" class="headerlink" title="项目定位"></a>项目定位</h2><p>这不是一个通用 CMS，也不是一个带后台管理系统的小程序。它更像是 Hexo 博客的移动阅读客户端。</p><p>内容仍然通过熟悉的 Hexo 工作流维护：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">hexo new post <span class="string">&quot;文章标题&quot;</span></span><br><span class="line">hexo generate</span><br><span class="line">hexo deploy</span><br></pre></td></tr></table></figure><p>小程序只负责读取和展示已经发布的内容，因此不会改变原有博客的写作方式，也不会把文章锁定在微信生态中。</p><h2 id="核心功能"><a href="#核心功能" class="headerlink" title="核心功能"></a>核心功能</h2><h3 id="首页内容聚合"><a href="#首页内容聚合" class="headerlink" title="首页内容聚合"></a>首页内容聚合</h3><p>首页是整个小程序的信息入口，包含文章推荐、分类快捷入口、精选内容和最新文章列表。</p><p>小程序启动后会请求：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://www.nnu.cn/search.xml</span><br></pre></td></tr></table></figure><p>随后解析文章的标题、链接、正文、摘要、日期、作者、分类、标签和封面图，并把结果写入全局数据。页面支持下拉刷新，博客更新后不需要重新发布小程序即可读取最新文章。</p><p>首页还会抓取博客归档页和首页数据，用于补齐更准确的发布日期、文章封面和展示信息。</p><h3 id="即刻短文"><a href="#即刻短文" class="headerlink" title="即刻短文"></a>即刻短文</h3><p>除了正式文章，首页还读取博客的“即刻短文”页面。短内容可以包含文字、图片和音频，小程序会将其整理成适合移动浏览的信息流。</p><p>音频内容使用微信原生音频能力播放，并展示播放状态、进度和时长；图片可以直接调用微信预览界面。</p><p>即刻短文同样接入评论功能，让博客上的轻量动态和小程序保持一致。</p><h3 id="分类与标签"><a href="#分类与标签" class="headerlink" title="分类与标签"></a>分类与标签</h3><p>小程序会从 XML 索引中提取文章分类和标签，不需要在代码里手动录入完整列表。</p><p>分类页根据文章数量动态生成卡片，并通过关键词匹配图标。例如网络、服务器、Docker、NAS、Windows、校园和生活等分类都会尽可能匹配对应视觉符号。</p><p>没有预设图标的分类也不会显示成完全相同的样式：项目会根据分类名称计算稳定的颜色与图标组合，使新增分类仍然能够自然融入界面。</p><p>点击分类或标签后进入独立文章列表。列表按每批 8 篇逐步加载，降低一次渲染大量节点带来的性能压力。</p><h3 id="全文搜索"><a href="#全文搜索" class="headerlink" title="全文搜索"></a>全文搜索</h3><p>搜索功能完全在小程序本地完成，不需要调用搜索服务。</p><p>用户输入关键词后，小程序会在已经解析的文章数据中匹配：</p><ul><li>文章标题；</li><li>正文内容；</li><li>内容摘要；</li><li>分类；</li><li>标签。</li></ul><p>最近使用的搜索词会保存在本机，最多保留 10 条。页面也提供 Docker、NAS、运维、部署和教程等快捷关键词。</p><p>由于搜索基于已下载的 XML 索引，它没有远程搜索接口的额外延迟，也不会把用户的搜索记录发送到服务器。</p><h3 id="原生文章详情页"><a href="#原生文章详情页" class="headerlink" title="原生文章详情页"></a>原生文章详情页</h3><p>文章详情是这个项目投入较多的一部分。Hexo 输出的是面向浏览器的 HTML，而微信小程序的 <code>rich-text</code> 对标签、事件和样式存在不少限制，因此不能直接原样显示。</p><p>当前实现会对正文进行一次专门的转换：</p><ul><li>解码常见 HTML 实体；</li><li>处理 Hexo 高亮代码块；</li><li>为标题、段落、引用和行内代码补充移动端样式；</li><li>让表格支持横向滚动；</li><li>将图片转换为可点击预览的原生节点；</li><li>将链接转换为可点击复制的内容块；</li><li>拆分代码块，支持一键复制和展开长代码；</li><li>根据文章主题色调整引用、链接和代码样式。</li></ul><p>详情页还提供阅读进度、返回顶部、字数统计、预计阅读时间和相关文章推荐。</p><p>相关文章不是随机抽取，而是根据共同分类和标签计算分数：同分类权重更高，同标签作为补充，最终展示关联度最高的文章。</p><h3 id="评论与浏览数据"><a href="#评论与浏览数据" class="headerlink" title="评论与浏览数据"></a>评论与浏览数据</h3><p>小程序复用了博客已有的 Twikoo 服务。目前评论请求通过：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://capi.nnu.cn/</span><br></pre></td></tr></table></figure><p>详情页支持：</p><ul><li>获取文章浏览量；</li><li>获取评论列表和回复；</li><li>发布评论；</li><li>点赞评论；</li><li>显示评论头像；</li><li>使用表情包；</li><li>保存常用昵称和邮箱。</li></ul><p>用户的昵称和邮箱只保存在本机，后续评论时自动填入。头像使用 Cravatar 服务生成，评论表情则通过独立表情接口获取。</p><p>如果评论服务暂时不可用，文章正文仍然可以正常阅读，评论区域会独立显示失败状态，不会阻塞整个详情页。</p><h3 id="收藏与阅读历史"><a href="#收藏与阅读历史" class="headerlink" title="收藏与阅读历史"></a>收藏与阅读历史</h3><p>收藏和历史记录都使用微信小程序本地存储实现，不要求用户登录。</p><p>收藏记录会保存文章 ID、标题、封面、日期、分类和摘要。再次点击收藏按钮即可取消收藏。</p><p>每次打开文章时，小程序会把它加入阅读历史，并自动移除重复记录。历史最多保留 50 条，最近阅读的文章排在最前面。</p><p>这套设计足够简单，也避免了为个人博客额外维护用户系统。不过，它的边界也很明确：更换手机、清理小程序数据或删除小程序后，本地收藏和历史不会自动恢复。</p><h3 id="季节主题与视觉皮肤"><a href="#季节主题与视觉皮肤" class="headerlink" title="季节主题与视觉皮肤"></a>季节主题与视觉皮肤</h3><p>小程序目前提供多套浅色主题：</p><ul><li>自动匹配季节；</li><li>春日薄荷；</li><li>盛夏晴空；</li><li>秋日奶杏；</li><li>冬日雾蓝；</li><li>清透蓝绿；</li><li>经典蓝白。</li></ul><p>自动模式会根据当前季节选择皮肤。每套皮肤都定义了背景、卡片、输入框、正文、品牌色、边框、阴影和导航栏等变量，而不是只简单替换一个主题色。</p><p>页面使用半透明卡片、柔和背景光和自定义底部导航，整体设计目标是清爽、轻盈，并尽量把注意力留给内容。</p><h3 id="个人中心"><a href="#个人中心" class="headerlink" title="个人中心"></a>个人中心</h3><p>“我的”页面用于汇总站点和本地数据，包括：</p><ul><li>文章总数；</li><li>分类总数；</li><li>可验证时显示的总浏览量；</li><li>全站评论数量；</li><li>博客运行时间；</li><li>本地收藏数量；</li><li>本地阅读历史数量；</li><li>当前使用的主题皮肤。</li></ul><p>页面还提供收藏、历史、关于和主题设置入口。</p><h2 id="技术实现"><a href="#技术实现" class="headerlink" title="技术实现"></a>技术实现</h2><h3 id="原生微信小程序"><a href="#原生微信小程序" class="headerlink" title="原生微信小程序"></a>原生微信小程序</h3><p>项目使用微信原生框架开发，主要文件由以下几类组成：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">nnuwx/</span><br><span class="line">├── app.js                 # 全局状态、收藏、历史和统计</span><br><span class="line">├── app.json               # 页面、窗口和 TabBar 配置</span><br><span class="line">├── app.wxss               # 全局样式</span><br><span class="line">├── custom-tab-bar/        # 自定义底部导航</span><br><span class="line">├── components/</span><br><span class="line">│   ├── nav-bar/           # 自定义导航栏</span><br><span class="line">│   └── float-tabbar/      # 浮动导航组件</span><br><span class="line">├── pages/</span><br><span class="line">│   ├── index/             # 首页和即刻短文</span><br><span class="line">│   ├── categories/        # 分类与标签</span><br><span class="line">│   ├── list/              # 分类文章列表</span><br><span class="line">│   ├── search/            # 本地搜索</span><br><span class="line">│   ├── detail/            # 文章详情与评论</span><br><span class="line">│   ├── favorites/         # 收藏</span><br><span class="line">│   ├── history/           # 阅读历史</span><br><span class="line">│   ├── profile/           # 个人中心</span><br><span class="line">│   ├── about/             # 关于页面</span><br><span class="line">│   └── webview/           # 白名单网页内容</span><br><span class="line">├── utils/</span><br><span class="line">│   ├── parser.js          # XML、文章及评论数据解析</span><br><span class="line">│   ├── theme.js           # 主题状态管理</span><br><span class="line">│   ├── theme-config.js    # 皮肤变量</span><br><span class="line">│   ├── category-color.js  # 分类配色</span><br><span class="line">│   ├── icon-color.js      # 动态 SVG 图标着色</span><br><span class="line">│   └── vibrate.js         # 触觉反馈</span><br><span class="line">└── images/                # 图标与本地资源</span><br></pre></td></tr></table></figure><p>项目没有 <code>package.json</code>，也没有依赖第三方小程序组件库。下载源码后可以直接使用微信开发者工具导入。</p><h3 id="XML-数据解析"><a href="#XML-数据解析" class="headerlink" title="XML 数据解析"></a>XML 数据解析</h3><p>Hexo 搜索插件生成的 XML 可能是 RSS，也可能接近 Atom 格式，不同主题和插件生成的字段也不完全一致。</p><p>项目中的解析器同时兼容 <code>&lt;entry&gt;</code> 和 <code>&lt;item&gt;</code>，并对以下字段进行归一化：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">title       → 标题</span><br><span class="line">link/url    → 原文地址</span><br><span class="line">content     → 正文</span><br><span class="line">summary     → 摘要</span><br><span class="line">published   → 发布时间</span><br><span class="line">category    → 分类</span><br><span class="line">tag         → 标签</span><br><span class="line">author      → 作者</span><br></pre></td></tr></table></figure><p>如果文章没有设置封面，小程序会从正文中提取第一张图片；仍然找不到时，再使用预设的兜底图片。</p><p>为了防止每次启动都得到变化的展示数据，当前实现只汇总真实可验证的浏览量。旧版本可能产生的随机统计缓存会被忽略。</p><h3 id="本地状态管理"><a href="#本地状态管理" class="headerlink" title="本地状态管理"></a>本地状态管理</h3><p>项目没有引入状态管理框架，而是使用 <code>App.globalData</code> 保存当前会话的数据：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">globalData</span>: &#123;</span><br><span class="line">  <span class="attr">blogUrl</span>: <span class="string">&#x27;https://www.nnu.cn/search.xml&#x27;</span>,</span><br><span class="line">  <span class="attr">articles</span>: [],</span><br><span class="line">  <span class="attr">categories</span>: [],</span><br><span class="line">  <span class="attr">tags</span>: [],</span><br><span class="line">  <span class="attr">favorites</span>: [],</span><br><span class="line">  <span class="attr">history</span>: [],</span><br><span class="line">  <span class="attr">theme</span>: <span class="string">&#x27;auto&#x27;</span>,</span><br><span class="line">  <span class="attr">themeSkin</span>: <span class="string">&#x27;summer&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>需要持久化的部分通过 <code>wx.setStorageSync()</code> 写入本地。对于个人博客小程序，这种结构足够直观，也降低了维护成本。</p><h2 id="如何运行项目"><a href="#如何运行项目" class="headerlink" title="如何运行项目"></a>如何运行项目</h2><h3 id="1-下载源码"><a href="#1-下载源码" class="headerlink" title="1. 下载源码"></a>1. 下载源码</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/anyfrees/nnuwx.git</span><br></pre></td></tr></table></figure><h3 id="2-使用微信开发者工具导入"><a href="#2-使用微信开发者工具导入" class="headerlink" title="2. 使用微信开发者工具导入"></a>2. 使用微信开发者工具导入</h3><p>打开微信开发者工具，选择“导入项目”，将项目目录指向刚刚下载的 <code>nnuwx</code> 文件夹。</p><p>仓库中的 <code>project.config.json</code> 已将项目类型设置为原生小程序。如果只是本地体验，可以使用测试 AppID；准备正式发布时，应改成自己的小程序 AppID。</p><h3 id="3-修改博客地址"><a href="#3-修改博客地址" class="headerlink" title="3. 修改博客地址"></a>3. 修改博客地址</h3><p>当前源码中的博客域名为：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://www.nnu.cn</span><br></pre></td></tr></table></figure><p>二次使用时，至少需要全局搜索并替换以下地址：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">https://www.nnu.cn/search.xml</span><br><span class="line">https://www.nnu.cn/</span><br><span class="line">https://www.nnu.cn/archives/</span><br><span class="line">https://www.nnu.cn/essay/</span><br><span class="line">https://www.nnu.cn/atom.xml</span><br></pre></td></tr></table></figure><p>同时修改 <code>app.js</code> 中的：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">blogUrl</span>: <span class="string">&#x27;https://你的域名/search.xml&#x27;</span></span><br></pre></td></tr></table></figure><p>如果博客没有“即刻短文”、Twikoo 或赞赏页面，可以隐藏对应入口，或者替换为自己的服务。</p><h3 id="4-确保-Hexo-生成搜索索引"><a href="#4-确保-Hexo-生成搜索索引" class="headerlink" title="4. 确保 Hexo 生成搜索索引"></a>4. 确保 Hexo 生成搜索索引</h3><p>小程序依赖包含正文的 <code>search.xml</code>。Hexo 博客需要安装并配置相应搜索索引插件，例如 <code>hexo-generator-search</code>。</p><p>示例配置思路如下，具体字段请根据所使用的插件版本调整：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">search:</span></span><br><span class="line">  <span class="attr">path:</span> <span class="string">search.xml</span></span><br><span class="line">  <span class="attr">field:</span> <span class="string">post</span></span><br><span class="line">  <span class="attr">content:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><p>生成博客后，直接在浏览器打开下面的地址进行确认：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://你的域名/search.xml</span><br></pre></td></tr></table></figure><p>如果 XML 中只有标题而没有正文，小程序仍然可以显示文章列表，但搜索范围和详情内容会不完整。</p><h3 id="5-配置服务器域名"><a href="#5-配置服务器域名" class="headerlink" title="5. 配置服务器域名"></a>5. 配置服务器域名</h3><p>开发配置中关闭了 URL 校验，方便在开发者工具里调试；正式发布时，这并不能代替微信公众平台的服务器域名配置。</p><p>需要根据实际功能，在“小程序后台 → 开发管理 → 开发设置 → 服务器域名”中添加合法域名，可能包括：</p><ul><li>自己的 Hexo 博客域名；</li><li>Twikoo API 域名；</li><li>评论头像域名；</li><li>表情资源域名；</li><li>文章及封面图片所在域名。</li></ul><p>所有请求地址应使用 HTTPS。若文章引用了多个外部图床，还需要逐一确认微信小程序能否合法加载，或者统一迁移到自己的图床&#x2F;CDN。</p><h3 id="6-修改站点信息"><a href="#6-修改站点信息" class="headerlink" title="6. 修改站点信息"></a>6. 修改站点信息</h3><p>二次使用时，还应修改：</p><ul><li><code>app.json</code> 中的小程序标题；</li><li>关于页面中的博客名称、介绍和作者；</li><li>GitHub、RSS 和博客链接；</li><li>站点图标与 TabBar 图标；</li><li>博客创建时间；</li><li>赞赏二维码及公众号文章地址；</li><li>分享标题和默认分享图。</li></ul><p>修改完成后，在真机上重点测试文章详情、图片预览、代码复制、评论、分享和不同网络环境下的请求表现。</p><h2 id="当前版本的边界"><a href="#当前版本的边界" class="headerlink" title="当前版本的边界"></a>当前版本的边界</h2><p>这个项目最初是围绕 NNU 技术博客开发的，因此目前仍然存在一些站点耦合：</p><ul><li>博客、归档和即刻短文地址写在源码中；</li><li>Twikoo 接口使用 NNU 的服务地址；</li><li>部分快捷入口和分享文案是固定内容；</li><li>赞赏二维码和公众号页面属于站点专属配置；</li><li>外部图片依赖对应域名能够在小程序中访问；</li><li>收藏、历史和搜索记录不会跨设备同步；</li><li>没有独立登录、后台管理和消息推送系统。</li></ul><p>因此，它目前更准确的定位是“可供参考和二次开发的个人博客小程序”，而不是下载后填写一个域名就能适配所有 Hexo 主题的通用模板。</p><h2 id="后续可以改进的方向"><a href="#后续可以改进的方向" class="headerlink" title="后续可以改进的方向"></a>后续可以改进的方向</h2><p>如果继续完善，我计划优先考虑以下方向：</p><h3 id="集中配置"><a href="#集中配置" class="headerlink" title="集中配置"></a>集中配置</h3><p>把博客域名、XML 地址、评论接口、站点信息、赞赏信息和快捷入口集中到一个配置文件，减少全局搜索替换。</p><h3 id="增加缓存策略"><a href="#增加缓存策略" class="headerlink" title="增加缓存策略"></a>增加缓存策略</h3><p>为文章索引增加缓存时间、版本检测和离线兜底，在网络不稳定时优先展示上一次成功获取的内容。</p><h3 id="改进富文本兼容性"><a href="#改进富文本兼容性" class="headerlink" title="改进富文本兼容性"></a>改进富文本兼容性</h3><p>继续完善复杂表格、嵌套列表、数学公式、流程图和更多 Hexo 标签插件的渲染能力。</p><h3 id="提供可选云同步"><a href="#提供可选云同步" class="headerlink" title="提供可选云同步"></a>提供可选云同步</h3><p>在保持免登录模式的同时，可以增加可选的微信云开发同步，让用户在多设备间恢复收藏和阅读历史。</p><h3 id="形成真正的通用模板"><a href="#形成真正的通用模板" class="headerlink" title="形成真正的通用模板"></a>形成真正的通用模板</h3><p>提供清晰的配置文件、初始化脚本、部署检查清单和示例 Hexo 配置，让其他博客作者能更快接入。</p><h2 id="开源说明"><a href="#开源说明" class="headerlink" title="开源说明"></a>开源说明</h2><p>源码托管在 GitHub：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://github.com/anyfrees/nnuwx</span><br></pre></td></tr></table></figure><p>欢迎根据自己的 Hexo 博客进行二次开发。如果发现文章解析、真机样式、域名兼容或评论接口方面的问题，也可以通过 GitHub Issue 提交反馈。</p><p>需要特别说明的是，仓库当前没有独立的许可证文件。在作者补充开源许可证之前，公开可见并不自动等于允许任意复制、修改和再发布；如需将它用于其他公开或商业项目，请先联系确认授权。</p><h2 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h2><p>这个小程序的核心价值，不是把博客网页原封不动地搬进微信，而是在保留 Hexo 内容工作流的基础上，为文章重新设计一套移动阅读体验。</p><p>博客依然是内容的源头，小程序只是新的窗口。文章发布一次，就能同时服务网站和微信用户；收藏、搜索、阅读历史、主题和评论则让这个窗口更接近一款完整的阅读应用。</p><p>对于我来说，它也是一次把长期维护的个人博客继续向前延伸的尝试：不追求复杂的后台和庞大的架构，而是围绕自己的真实使用习惯，把阅读这件事做得更轻、更顺手。</p>]]></content>
      
      
      <categories>
          
          <category> 项目开发 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> Hexo </tag>
            
            <tag> 微信小程序 </tag>
            
            <tag> JavaScript </tag>
            
            <tag> 开源项目 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>Xibo 多媒体信息发布系统详细部署指南</title>
      <link href="/post/6224d08a.html"/>
      <url>/post/6224d08a.html</url>
      
        <content type="html"><![CDATA[<h2 id="一、-系统架构简介"><a href="#一、-系统架构简介" class="headerlink" title="一、 系统架构简介"></a>一、 系统架构简介</h2><p>Xibo 采用典型的“C&#x2F;S架构”：</p><ol><li><strong>CMS 服务端（中心控制台）：</strong> 就是我们要在服务器或 NAS 上通过 Docker 部署的后台服务。它完全免费且不限制终端数量。</li><li><strong>Player 播放端：</strong> 安装在电视、显示器绑定的电脑或安卓盒子上的客户端软件（Windows&#x2F;Linux 版免费，安卓版收费）。</li></ol><h2 id="二、-环境准备"><a href="#二、-环境准备" class="headerlink" title="二、 环境准备"></a>二、 环境准备</h2><p>在服务器上规划一个目录用于存放 Xibo 的配置和挂载数据。建议的目录结构如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">/your/path/xibo-cms/</span><br><span class="line"> ├── docker-compose.yml    # 容器编排文件</span><br><span class="line"> ├── config.env            # 环境变量配置文件</span><br><span class="line"> └── shared/               # 自动生成的持久化数据目录 (数据库、媒体库等)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>通过 SSH 连接到你的服务器，创建并进入该目录：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p xibo-cms</span><br><span class="line"><span class="built_in">cd</span> xibo-cms</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="三、-配置文件详解"><a href="#三、-配置文件详解" class="headerlink" title="三、 配置文件详解"></a>三、 配置文件详解</h2><h3 id="1-docker-compose-yml"><a href="#1-docker-compose-yml" class="headerlink" title="1. docker-compose.yml"></a>1. docker-compose.yml</h3><p>新建 <code>docker-compose.yml</code> 文件。以下是我目前正在使用并验证通过的模板。</p><p><strong>核心改动说明：</strong></p><ul><li>替换了官方容易拉取失败的镜像，使用了自建的私有镜像库（<code>docker.cnb.cool/...</code> 系列）。</li><li><code>cms-web</code> 服务的端口映射改为了 <code>1880:80</code>，避免与服务器上原有的 80 端口（如其他 Web 服务）发生冲突。这表示我们后续将通过 <code>1880</code> 端口来访问系统。</li></ul><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&quot;2.1&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">    <span class="attr">cms-db:</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">docker.cnb.cool/nnu/docker-images-chrom/mysql:8.4_amd64</span></span><br><span class="line">        <span class="attr">volumes:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">&quot;./shared/db:/var/lib/mysql:Z&quot;</span></span><br><span class="line">        <span class="attr">environment:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">MYSQL_DATABASE=cms</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">MYSQL_USER=cms</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">MYSQL_RANDOM_ROOT_PASSWORD=yes</span></span><br><span class="line">        <span class="attr">mem_limit:</span> <span class="string">1g</span></span><br><span class="line">        <span class="attr">env_file:</span> <span class="string">config.env</span></span><br><span class="line">        <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">cms-xmr:</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">ghcr.io/xibosignage/xibo-xmr:1.3</span></span><br><span class="line">        <span class="attr">ports:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">&quot;9505:9505&quot;</span></span><br><span class="line">        <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">        <span class="attr">mem_limit:</span> <span class="string">256m</span></span><br><span class="line">        <span class="attr">env_file:</span> <span class="string">config.env</span></span><br><span class="line">    <span class="attr">cms-web:</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">ghcr.io/xibosignage/xibo-cms:release-4.4.4</span></span><br><span class="line">        <span class="attr">volumes:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">&quot;./shared/cms/custom:/var/www/cms/custom:Z&quot;</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">&quot;./shared/backup:/var/www/backup:Z&quot;</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">&quot;./shared/cms/web/theme/custom:/var/www/cms/web/theme/custom:Z&quot;</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">&quot;./shared/cms/library:/var/www/cms/library:Z&quot;</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">&quot;./shared/cms/web/userscripts:/var/www/cms/web/userscripts:Z&quot;</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">&quot;./shared/cms/ca-certs:/var/www/cms/ca-certs:Z&quot;</span></span><br><span class="line">        <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">        <span class="attr">environment:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">MYSQL_HOST=cms-db</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">XMR_HOST=cms-xmr</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">CMS_USE_MEMCACHED=true</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">MEMCACHED_HOST=cms-memcached</span></span><br><span class="line">        <span class="attr">env_file:</span> <span class="string">config.env</span></span><br><span class="line">        <span class="attr">ports:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">&quot;1880:80&quot;</span></span><br><span class="line">        <span class="attr">mem_limit:</span> <span class="string">1g</span></span><br><span class="line">    <span class="attr">cms-memcached:</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">docker.cnb.cool/nnu/docker-images-chrom/memcached:alpine_amd64</span></span><br><span class="line">        <span class="attr">command:</span> <span class="string">memcached</span> <span class="string">-m</span> <span class="number">15</span></span><br><span class="line">        <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">        <span class="attr">mem_limit:</span> <span class="string">100M</span></span><br><span class="line">    <span class="attr">cms-quickchart:</span></span><br><span class="line">      <span class="attr">image:</span> <span class="string">docker.cnb.cool/nnu/docker-images-chrom/ianw-quickchart:latest_amd64</span></span><br><span class="line">      <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="2-config-env-重要"><a href="#2-config-env-重要" class="headerlink" title="2. config.env (重要)"></a>2. config.env (重要)</h3><p>Xibo 的容器依赖外部环境变量。在同级目录下新建一个 <code>config.env</code> 文件，输入以下内容。</p><blockquote><p><strong>注意：</strong> 必须修改 <code>MYSQL_PASSWORD</code> 为一个强密码，并设置 <code>XIBO_WEB_HOST</code>。</p></blockquote><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 数据库连接密码（由于数据库不对外暴露，此密码主要用于容器间通讯，请设置为字母和数字组合的强密码）</span></span><br><span class="line"><span class="attr">MYSQL_PASSWORD</span>=YourStrongPasswordHere</span><br><span class="line"></span><br><span class="line"><span class="comment"># 邮件发送配置（如果是纯内网使用，可以保持默认）</span></span><br><span class="line"><span class="attr">CMS_SMTP_SERVER</span>=smtp.gmail.com:<span class="number">587</span></span><br><span class="line"><span class="attr">CMS_SMTP_USERNAME</span>=youraccount@gmail.com</span><br><span class="line"><span class="attr">CMS_SMTP_PASSWORD</span>=yourpassword</span><br><span class="line"><span class="attr">CMS_SMTP_USE_TLS</span>=<span class="literal">YES</span></span><br><span class="line"><span class="attr">CMS_SMTP_USE_STARTTLS</span>=<span class="literal">YES</span></span><br><span class="line"><span class="attr">CMS_SMTP_REWRITE_DOMAIN</span>=gmail.com</span><br><span class="line"><span class="attr">CMS_SMTP_HOSTNAME</span>=gmail.com</span><br><span class="line"><span class="attr">CMS_SMTP_FROM_LINE</span>=youraccount@gmail.com</span><br><span class="line"></span><br><span class="line"><span class="comment"># Xibo 系统的访问地址（必须配置）</span></span><br><span class="line"><span class="comment"># 如果是在内网通过 IP 访问，填写内网 IP，例如：XIBO_WEB_HOST=192.168.1.100</span></span><br><span class="line"><span class="comment"># 如果配置了域名，请填写域名。不需要加 http 也不需要加端口号。</span></span><br><span class="line"><span class="attr">XIBO_WEB_HOST</span>=你的服务器IP或域名</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="四、-启动与初始化"><a href="#四、-启动与初始化" class="headerlink" title="四、 启动与初始化"></a>四、 启动与初始化</h2><p>在确认 <code>docker-compose.yml</code> 和 <code>config.env</code> 都准备就绪后，执行以下命令一键启动集群：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up -d</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>第一次启动时，数据库容器（cms-db）需要运行初始化脚本建库建表，Web 容器（cms-web）也会进行一些目录权限和基础数据的初始化。这个过程通常需要 <strong>2~5分钟</strong>，请耐心等待。</p><p>你可以通过以下命令查看实时日志，确认系统是否启动完毕：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker-compose logs -f cms-web</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>当日志中不再有明显的报错，且出现类似 <code>Starting cron</code> 或 <code>ready to handle connections</code> 的字样时，说明启动成功。</p><h2 id="五、-访问后台与修改密码"><a href="#五、-访问后台与修改密码" class="headerlink" title="五、 访问后台与修改密码"></a>五、 访问后台与修改密码</h2><p>系统启动后，打开浏览器，访问你在 <code>docker-compose.yml</code> 中映射的端口（外网端口）：</p><p><strong>访问地址：</strong> <code>http://服务器IP:1880</code></p><p>进入登录界面后，使用官方默认凭证登录：</p><ul><li><strong>默认账号：</strong> <code>xibo_admin</code></li><li><strong>默认密码：</strong> <code>password</code></li></ul><p>处于安全考虑，首次登录成功后，系统会强制要求你立刻修改管理员密码。按照提示设置你的新密码即可。</p><h2 id="六、-部署终端设备（Player）"><a href="#六、-部署终端设备（Player）" class="headerlink" title="六、 部署终端设备（Player）"></a>六、 部署终端设备（Player）</h2><p>CMS 服务端部署完成后，你需要让屏幕连接到它。以免费且易用的 Windows 为例：</p><ol><li>找一台连接了电视机的 Windows 小主机，下载并安装 <a href="https://xibosignage.com/downloads/player/windows">Xibo for Windows</a> 客户端。</li><li>运行 Xibo Player 选项（Xibo Player Options），配置以下信息：</li></ol><ul><li><strong>CMS Address:</strong> <code>http://服务器IP:1880</code></li><li><strong>Key:</strong> 可以在你的 Xibo CMS 网页后台的 <code>Administration</code> -&gt; <code>Settings</code> 中找到你的服务端专属通信密钥。</li><li><strong>Local Library:</strong> 本地存储素材的路径。</li></ul><ol start="3"><li>点击 <code>Save</code> 保存并启动播放器。</li><li>回到 Xibo CMS 网页后台的 <code>Displays</code> (显示器管理) 菜单，你会看到新接入的设备，将其授权（Authorize）即可开始下发节目！</li></ol><hr><blockquote><p>部署多媒体发布系统是一个系统工程，解决完服务端的私有化部署后，接下来的重头戏就是研究 Layout 布局排版和日程下发了。有问题欢迎在评论区交流。</p></blockquote>]]></content>
      
      
      <categories>
          
          <category> 服务部署 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> NAS </tag>
            
            <tag> Docker </tag>
            
            <tag> Xibo </tag>
            
            <tag> 容器化部署 </tag>
            
            <tag> 信息发布 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>忘记 Excel 密码怎么办？两种常见加密的解除方法</title>
      <link href="/post/9082dcc9.html"/>
      <url>/post/9082dcc9.html</url>
      
        <content type="html"><![CDATA[<p>解除 EXCEL 表格的密码保护，首先需要确认你遇到的是哪种类型的密码。通常有两种情况：<strong>“限制编辑”</strong>（可以打开文件，但无法修改内容）和“打开密码”（完全无法打开和查看文件）。</p><p>这两种情况的破解难度和方法完全不同。请务必在操作前<strong>备份原文件</strong>，以免数据损坏。</p><hr><h2 id="情况一：忘记“限制编辑”密码（工作表保护）"><a href="#情况一：忘记“限制编辑”密码（工作表保护）" class="headerlink" title="情况一：忘记“限制编辑”密码（工作表保护）"></a>情况一：忘记“限制编辑”密码（工作表保护）</h2><p>如果文件可以正常打开查看，只是在修改时提示受保护，可以通过修改底层代码的方式轻松移除密码（适用于 <code>.xlsx</code> 格式）。</p><h3 id="步骤（ZIP-压缩包法）："><a href="#步骤（ZIP-压缩包法）：" class="headerlink" title="步骤（ZIP 压缩包法）："></a>步骤（ZIP 压缩包法）：</h3><ol><li><strong>备份文件：</strong> 复制一份你的原 EXCEL 文件，以防万一。</li><li><strong>修改后缀名：</strong> 将文件的扩展名从 <code>.xlsx</code> 改为 <code>.zip</code>。（如果看不到后缀名，请在 Windows 文件资源管理器中勾选“查看” -&gt; “文件扩展名”）。</li><li><strong>打开压缩包：</strong> 双击打开这个 <code>.zip</code> 文件。<br><img src="https://img.nnu.cn/p/6a5ee5b394f62.webp"><br><img src="https://img.nnu.cn/p/6a5ee5d1544f4.webp"><br><img src="https://img.nnu.cn/p/6a5ee5da9d1ee.webp"></li><li><strong>找到目标文件：</strong> 依次进入文件夹 <code>xl</code> -&gt; <code>worksheets</code>。你会看到 <code>sheet1.xml</code>、<code>sheet2.xml</code> 等文件，对应你的各个工作表。</li><li><strong>编辑 XML 文件：</strong></li></ol><ul><li>将被保护的工作表文件（例如 <code>sheet1.xml</code>）拖到桌面。</li><li>右键点击该文件，选择用记事本（Notepad）打开。</li></ul><ol start="6"><li><strong>删除保护代码：</strong></li></ol><ul><li>在记事本中按 <code>Ctrl + F</code> 调出查找功能，搜索 <code>protection</code>。</li><li>你会找到一段类似 <code>&lt;sheetProtection algorithmName=&quot;SHA-512&quot; hashValue=&quot;...&quot; saltValue=&quot;...&quot; spinCount=&quot;100000&quot; sheet=&quot;1&quot; objects=&quot;1&quot; scenarios=&quot;1&quot;/&gt;</code> 的代码。</li><li>将这段 <code>&lt;sheetProtection ... /&gt;</code> <strong>从 <code>&lt;</code> 开始到 <code>/&gt;</code> 结束的全部内容</strong>删除。</li><li>保存并关闭记事本。</li></ul><ol start="7"><li><strong>替换原文件：</strong> 将修改好的 <code>sheet1.xml</code> 拖回刚刚的 <code>.zip</code> 压缩包中，覆盖原文件。</li><li><strong>改回后缀名：</strong> 将文件的扩展名从 <code>.zip</code> 重新改回 <code>.xlsx</code>。</li></ol><p>现在，再次打开这个 EXCEL 文件，你会发现限制编辑的密码已经被彻底解除了。</p><hr><h2 id="情况二：忘记“打开密码”（文件加密）"><a href="#情况二：忘记“打开密码”（文件加密）" class="headerlink" title="情况二：忘记“打开密码”（文件加密）"></a>情况二：忘记“打开密码”（文件加密）</h2><p>如果你在双击打开文件时就被要求输入密码，这种情况破解起来非常困难。从 Excel 2013 开始，微软采用了强 AES 加密算法，几乎不存在“一键秒破”的漏洞。</p><h3 id="可选方案："><a href="#可选方案：" class="headerlink" title="可选方案："></a>可选方案：</h3><ol><li><strong>尝试常用密码：</strong> 这是最有效的方法。回想一下你常用的密码组合，包括生日、手机号、123456、888888、或者常用的平台密码。</li><li><strong>使用密码恢复工具（暴力破解）：</strong></li></ol><ul><li>可以使用第三方软件（如 Advanced Office Password Recovery、PassFab for Excel 等）。</li><li>这些软件通过“字典攻击”或“暴力穷举”不断尝试密码组合。如果你的密码是纯数字或比较短，破解出来的概率很高；如果是复杂的长密码，可能需要数年时间。</li></ul><ol start="3"><li><strong>在线破解服务：</strong> 网上有一些提供在线解除 Excel 密码的网站。</li></ol><ul><li><strong>警告：</strong> 你的文件需要上传到对方的服务器。如果文件包含商业机密、个人隐私或敏感数据，<strong>绝对不要</strong>使用在线服务，以防数据泄露。</li></ul>]]></content>
      
      
      <categories>
          
          <category> 教程 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 破解 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>网站并发压力测试实战指南（基于 JMeter）</title>
      <link href="/post/3a6ef053.html"/>
      <url>/post/3a6ef053.html</url>
      
        <content type="html"><![CDATA[<p>在网站或 API 上线前，我们通常需要知道服务器能同时扛住多少人访问（即“高并发”）。如果只是自己用鼠标疯狂刷新，根本无法模拟真实的压力场景。这时候，我们就需要用到专业的开源压测工具：<strong>JMeter</strong>。</p><p>这篇文章专为零基础小白编写，跟着以下步骤，你将能从零开始，独立完成一次标准、真实的 100 并发压力测试。</p><h2 id="阶段一：环境准备与安装"><a href="#阶段一：环境准备与安装" class="headerlink" title="阶段一：环境准备与安装"></a>阶段一：环境准备与安装</h2><p>JMeter 是一款基于 Java 开发的软件，所以我们需要先配置好基础环境。</p><h3 id="1-安装-Java-环境-JDK"><a href="#1-安装-Java-环境-JDK" class="headerlink" title="1. 安装 Java 环境 (JDK)"></a>1. 安装 Java 环境 (JDK)</h3><ol><li>去 Oracle 官网或搜索下载 <strong>JDK 8</strong> 或更高版本（推荐 JDK 11 或 17）。</li><li>一路点击“下一步”完成安装，并确保配置好了系统的环境变（打开电脑的命令行&#x2F;终端，输入 <code>java -version</code>，如果能输出版本号，说明安装成功）。</li></ol><h3 id="2-下载并启动-JMeter"><a href="#2-下载并启动-JMeter" class="headerlink" title="2. 下载并启动 JMeter"></a>2. 下载并启动 JMeter</h3><ol><li>前往 <a href="https://jmeter.apache.org/download_jmeter.cgi">Apache JMeter 官网</a> 下载最新版的 <code>.zip</code> 压缩包（如 <code>apache-jmeter-5.6.3.zip</code>）。</li><li>将压缩包解压到你的电脑里（建议放在没有中文路径的目录下，例如 <code>D:\jmeter</code>）。</li><li><strong>启动软件</strong>：</li></ol><ul><li><strong>Windows 系统</strong>：进入解压后的 <code>bin</code> 文件夹，双击运行 **<code>jmeter.bat</code>**。</li><li><strong>Mac&#x2F;Linux 系统</strong>：在终端进入 <code>bin</code> 目录，执行 <code>./jmeter.sh</code>。</li></ul><p><img src="https://img.nnu.cn/p/6a585bdbe6500.webp"><br>4. 稍等几秒，你就会看到一个全英文的图形化界面（GUI），这就是我们要配置脚本的地方。</p><hr><p><img src="https://img.nnu.cn/p/6a585c0611e4b.webp"></p><h2 id="阶段二：手把手配置压测脚本-最容易踩坑！"><a href="#阶段二：手把手配置压测脚本-最容易踩坑！" class="headerlink" title="阶段二：手把手配置压测脚本 (最容易踩坑！)"></a>阶段二：手把手配置压测脚本 (最容易踩坑！)</h2><p>我们将以测试某个网址（例如 <code>[https://s.nnu.cn/](https://s.nnu.cn/)</code>）为例，模拟 100 个人同时访问。</p><h3 id="第一步：新建“线程组”（模拟用户）"><a href="#第一步：新建“线程组”（模拟用户）" class="headerlink" title="第一步：新建“线程组”（模拟用户）"></a>第一步：新建“线程组”（模拟用户）</h3><p>线程组的作用是告诉 JMeter 我们要模拟多少个用户，以及怎么模拟。</p><ol><li><p>在左侧树状图的 <strong>Test Plan (测试计划)</strong> 上点击<strong>右键</strong>。</p></li><li><p>依次选择 <strong>Add (添加) -&gt; Threads (Users) -&gt; Thread Group</strong>。</p><blockquote><p>⚠️ <strong>避坑警告：</strong> 一定要选最普通的 <code>Thread Group</code>，千万不要选带 <code>Open Model</code> 字样的，否则脚本会瞬间运行结束，没有任何反应！</p></blockquote></li><li><p>在右侧弹出的界面中，设置以下三个关键数字：</p></li></ol><ul><li><strong>Number of Threads (users):</strong> 填写 <code>100</code>（代表模拟 100 个人）。</li><li><strong>Ramp-up period (seconds):</strong> 填写 <code>10</code>（代表在这 10 秒内，把这 100 个人陆续放进去。千万别填 1，否则瞬间并发会被防火墙当成黑客攻击拦截）。</li><li><strong>Loop Count:</strong> 填写 <code>10</code>（代表每个人重复请求 10 次。这样总计会发送 1000 个请求）。</li></ul><h3 id="第二步：配置-HTTP-请求（告诉工具去访问谁）"><a href="#第二步：配置-HTTP-请求（告诉工具去访问谁）" class="headerlink" title="第二步：配置 HTTP 请求（告诉工具去访问谁）"></a>第二步：配置 HTTP 请求（告诉工具去访问谁）</h3><ol><li>在刚刚建好的 <strong>Thread Group</strong> 上点击<strong>右键</strong>。</li><li>依次选择 <strong>Add -&gt; Sampler -&gt; HTTP Request</strong>。</li><li>在右侧面板填写你要测试的网址，<strong>这是小白最容易填错的地方，必须拆开填</strong>：</li></ol><ul><li><strong>Protocol [http]:</strong> 填写 <code>https</code> （如果没有 s 就填 http）。</li><li><strong>Server Name or IP:</strong> 填写域名，例如 <code>s.nnu.cn</code>。（⚠️<strong>千万不要</strong>带前面的 <code>https://</code>，也<strong>不要</strong>带后面的斜杠 <code>/</code>，且<strong>末尾绝对不能有空格</strong>）。</li><li><strong>Path:</strong> 填写 <code>/</code> （如果是主页就填斜杠。如果是具体页面如 <code>/s/lTFRo4</code>，必须以斜杠开头）。</li></ul><ol start="4"><li><strong>重定向设置：</strong> 找到下方的复选框，<strong>取消勾选</strong> “Redirect Automatically”，<strong>勾选</strong> “Follow Redirects”（跟随重定向），防止请求在中途丢失。</li></ol><h3 id="第三步：伪装成浏览器（防止被拦截）"><a href="#第三步：伪装成浏览器（防止被拦截）" class="headerlink" title="第三步：伪装成浏览器（防止被拦截）"></a>第三步：伪装成浏览器（防止被拦截）</h3><p>很多网站有防爬虫机制，看到是测试工具就会返回 404 错误。我们需要伪装成正常的浏览器。</p><ol><li>在 <strong>Thread Group</strong> 上点击<strong>右键</strong> -&gt; <strong>Add -&gt; Config Element -&gt; HTTP Header Manager</strong>。</li><li>在右侧面板下方点击 <strong>Add (添加)</strong> 按钮，新增一行：</li></ol><ul><li><strong>Name</strong> 框输入：<code>User-Agent</code></li><li><strong>Value</strong> 框输入：<code>Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36</code></li></ul><h3 id="第四步：添加结果查看器（用于调试）"><a href="#第四步：添加结果查看器（用于调试）" class="headerlink" title="第四步：添加结果查看器（用于调试）"></a>第四步：添加结果查看器（用于调试）</h3><ol><li>在 <strong>Thread Group</strong> 上点击<strong>右键</strong> -&gt; **Add -&gt; Listener -&gt; View Results Tree (察看结果树)**。</li><li>点击顶部工具栏绿色的 <strong>Play (启动)</strong> 按钮。</li><li>会弹出提示让你保存脚本。将它保存到桌面上，命名为 <code>test.jmx</code>。</li><li>点击左侧的“察看结果树”，如果看到列表里出现了绿色的盾牌，说明单次请求测试成功！</li></ol><hr><h2 id="阶段三：正式发起高并发压测-命令行模式"><a href="#阶段三：正式发起高并发压测-命令行模式" class="headerlink" title="阶段三：正式发起高并发压测 (命令行模式)"></a>阶段三：正式发起高并发压测 (命令行模式)</h2><blockquote><p>🚨 <strong>官方严厉警告：</strong> <strong>永远不要</strong>在图形化界面里直接进行高并发测试！图形界面极度消耗电脑内存，会导致你的电脑卡死，测出来的数据也会完全不准。图形界面仅仅是用来<strong>写脚本</strong>和<strong>调试单次请求</strong>的。</p></blockquote><p>正确的做法是关闭 JMeter 图形界面，用黑框框（命令行）来跑。</p><h3 id="1-确保输出目录干净"><a href="#1-确保输出目录干净" class="headerlink" title="1. 确保输出目录干净"></a>1. 确保输出目录干净</h3><p>JMeter 在生成测试报告时，如果发现指定的文件夹里已经有旧数据，就会直接报错罢工。<br>因此，在跑测试前，请确保你要保存报告的地方（比如桌面）<strong>没有</strong> <code>result.jtl</code> 文件，也<strong>没有</strong> <code>report</code> 文件夹。如果有，请手动删除它们。</p><h3 id="2-执行压测命令"><a href="#2-执行压测命令" class="headerlink" title="2. 执行压测命令"></a>2. 执行压测命令</h3><ol><li><p>打开终端（Windows 系统建议在桌面空白处右键，选择 <code>Open Git Bash here</code>，或者按 <code>Win+R</code> 输入 <code>cmd</code> 打开命令提示符）。</p></li><li><p>通过 <code>cd</code> 命令进入你刚刚解压的 JMeter 的 <code>bin</code> 目录。例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> D:\jmeter\apache-jmeter-5.6.3\bin</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p>复制并执行以下标准压测命令（请把路径换成你自己电脑里的实际路径）：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Windows 使用 jmeter.bat，Mac/Linux 使用 ./jmeter.sh</span></span><br><span class="line"><span class="comment"># -n: 无界面模式</span></span><br><span class="line"><span class="comment"># -t: 你刚刚保存的脚本文件路径</span></span><br><span class="line"><span class="comment"># -l: 原始数据保存为 jtl 格式</span></span><br><span class="line"><span class="comment"># -e -o: 自动生成 HTML 网页版可视化报告文件夹</span></span><br><span class="line"></span><br><span class="line">./jmeter.bat -n -t <span class="string">&quot;C:\Users\你的电脑用户名\Desktop\test.jmx&quot;</span> -l <span class="string">&quot;C:\Users\你的电脑用户名\Desktop\result.jtl&quot;</span> -e -o <span class="string">&quot;C:\Users\你的电脑用户名\Desktop\report&quot;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p>回车运行后，你会看到屏幕上每隔几秒跳出一行带有 <code>summary</code> 字样的数据。当看到 <code>... end of run</code> 时，恭喜你，压测圆满结束！</p></li></ol><hr><h2 id="阶段四：看懂你的压测报告"><a href="#阶段四：看懂你的压测报告" class="headerlink" title="阶段四：看懂你的压测报告"></a>阶段四：看懂你的压测报告</h2><p>压测结束后，不要去看那个密密麻麻的 <code>.jtl</code> 文件。<br><img src="https://img.nnu.cn/p/6a585b973c4a5.webp"></p><ol><li>直接去你的桌面上，找到刚刚生成的 <strong><code>report</code></strong> 文件夹。</li><li>双击打开里面的 <strong><code>index.html</code></strong> 文件（会自动用你的浏览器打开）。</li><li>这是一个极具专业感的数据大屏，你需要重点关注两项核心指标：</li></ol><ul><li><strong>仪表盘 (Dashboard) -&gt; APDEX (Application Performance Index):</strong> 这个表格里的 **Error % (错误率)**。如果不是 0%，说明服务器在压力下出现了崩溃或拒绝服务。</li><li><strong>吞吐量 (Throughput):</strong> 也就是常说的 <strong>QPS</strong>。代表在你的服务器在没有报错的前提下，每秒最多能处理多少次请求。数字越大，说明你的服务器性能越强悍！</li></ul>]]></content>
      
      
      <categories>
          
          <category> 教程 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 并发测试 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>MoveCar多用户智能挪车系统</title>
      <link href="/post/bb54c662.html"/>
      <url>/post/bb54c662.html</url>
      
        <content type="html"><![CDATA[<h2 id="🚀-阿里云-ESA-边缘安全加速-部署指南"><a href="#🚀-阿里云-ESA-边缘安全加速-部署指南" class="headerlink" title="🚀 阿里云 ESA (边缘安全加速) 部署指南"></a>🚀 阿里云 ESA (边缘安全加速) 部署指南</h2><blockquote><p><strong>核心优势</strong>：利用阿里云全球边缘节点，国内访问极速响应。突破了 ESA 平台 <code>最多 8 次 KV 操作</code> 的底层限制，并通过 <code>KV 配置动态加载</code> 完美解决纯 JS 单文件部署时的环境变量丢失问题。</p></blockquote><h3 id="第一步：准备代码并推送到-Git"><a href="#第一步：准备代码并推送到-Git" class="headerlink" title="第一步：准备代码并推送到 Git"></a>第一步：准备代码并推送到 Git</h3><p>确保您的 GitHub&#x2F;Gitee 仓库中是最新的 <code>movecar.js</code>（终极性能压缩版）。</p><h3 id="第二步：创建-KV-数据库-核心"><a href="#第二步：创建-KV-数据库-核心" class="headerlink" title="第二步：创建 KV 数据库 (核心)"></a>第二步：创建 KV 数据库 (核心)</h3><p>由于我们在阿里云 ESA 上直接运行原生 JS，<strong>所有的配置项都需要直接写在 KV 数据库中</strong>，而不是写在部署界面的“环境变量”里。</p><ol><li>登录阿里云 ESA 控制台，在左侧导航栏选择 <strong>边缘计算 -&gt; KV 存储</strong>。</li><li>点击 <strong>创建命名空间</strong>，名称<strong>必须严格填为</strong>：<code>MOVE_CAR_STATUS</code>。</li></ol><h3 id="第三步：配置用户参数-多用户隔离"><a href="#第三步：配置用户参数-多用户隔离" class="headerlink" title="第三步：配置用户参数 (多用户隔离)"></a>第三步：配置用户参数 (多用户隔离)</h3><p>点击进入刚刚创建的 <code>MOVE_CAR_STATUS</code> 空间，点击 <strong>添加 KV 数据</strong>。<br>系统支持多用户隔离（通过 URL 里的 <code>?u=用户ID</code> 区分）。请按照以下格式添加您的配置：</p><p><strong>如果你只想单人使用（默认配置）：</strong></p><ul><li>键(Key): <code>BARK_URL</code>  👉 值(Value): <code>https://api.day.app/你的Token</code></li><li>键(Key): <code>CAR_TITLE</code> 👉 值(Value): <code>粤B·88888</code><br><em>(如果用 PushPlus，则配置键 <code>PUSHPLUS_TOKEN</code>)</em></li></ul><p><strong>如果你想给全家人使用（例如给 ID 为 <code>xiaowang</code> 的用户配置）：</strong></p><ul><li>键(Key): <code>BARK_URL_XIAOWANG</code>  👉 值(Value): <code>https://api.day.app/小王的Token</code></li><li>键(Key): <code>CAR_TITLE_XIAOWANG</code> 👉 值(Value): <code>京A·99999</code></li><li>键(Key): <code>PHONE_NUMBER_XIAOWANG</code> 👉 值(Value): <code>13800000000</code> (备用电话，可选)</li></ul><blockquote><p>💡 <strong>提示</strong>：ID 必须全部大写。代码会自动根据扫码链接提取 ID 并精确推送给对应的人！</p></blockquote><h3 id="第四步：创建-ESA-边缘应用"><a href="#第四步：创建-ESA-边缘应用" class="headerlink" title="第四步：创建 ESA 边缘应用"></a>第四步：创建 ESA 边缘应用</h3><ol><li>在 ESA 控制台左侧选择 <strong>边缘计算 -&gt; 函数和 Pages</strong>。</li><li>点击 <strong>创建</strong>，选择 <strong>从 Git 仓库拉取</strong>，连接您的代码仓库和分支。</li><li>⚠️ <strong>【防坑必看：配置构建信息】</strong>：<ul><li><strong>框架预设</strong>：选择 <code>None</code> 或 <code>自定义</code>。</li><li><strong>构建命令</strong>：<strong>必须清空！</strong>（删掉里面的内容）。</li><li><strong>输出目录</strong>：<strong>必须清空！</strong> 或填 <code>./</code>。</li><li><strong>入口文件</strong>：填入 <code>movecar.js</code>。</li></ul></li><li>点击“保存并部署”，等待状态变为 <code>100%</code>。</li></ol><h3 id="第五步：绑定域名与路由"><a href="#第五步：绑定域名与路由" class="headerlink" title="第五步：绑定域名与路由"></a>第五步：绑定域名与路由</h3><ol><li>在部署完成的页面，点击顶部的 <strong>域名</strong> 标签。</li><li>添加一条自定义规则，例如：<code>movecar.你的域名.com/*</code>。</li><li>（重要）绑定完成后，为了确保配置生效，可以回到 <strong>部署</strong> 标签，点击一下 <strong>新构建</strong>。</li></ol><h3 id="第六步：生成您的专属挪车码"><a href="#第六步：生成您的专属挪车码" class="headerlink" title="第六步：生成您的专属挪车码"></a>第六步：生成您的专属挪车码</h3><ul><li>默认入口：<code>https://movecar.你的域名.com/</code></li><li>小王专属入口：<code>https://movecar.你的域名.com/?u=xiaowang</code></li></ul><p>把上面属于你的链接，放到 <a href="https://cli.im/">草料二维码</a> 中生成图片，打印贴在车上即可！</p><p>兼容阿里云ESA版本仓库地址：<a href="https://github.com/anyfrees/movecar">https://github.com/anyfrees/movecar</a></p><hr><h2 id="🌐-界面预览"><a href="#🌐-界面预览" class="headerlink" title="🌐 界面预览"></a>🌐 界面预览</h2><p><img src="https://img.nnu.cn/p/69f59dbce18d2.webp"><br><img src="https://img.nnu.cn/p/69f59de9e5569.webp"><br><img src="https://img.nnu.cn/p/69f59e01d4b66.webp"></p><table><thead><tr><th align="center">请求者页面</th><th align="center">车主页面</th></tr></thead><tbody><tr><td align="center"><a href="https://htmlpreview.github.io/?https://github.com/lesnolie/movecar/blob/main/preview-requester.html">🔗 在线预览</a></td><td align="center"><a href="https://htmlpreview.github.io/?https://github.com/lesnolie/movecar/blob/main/preview-owner.html">🔗 在线预览</a></td></tr></tbody></table><hr><h2 id="❓-为什么需要它？"><a href="#❓-为什么需要它？" class="headerlink" title="❓ 为什么需要它？"></a>❓ 为什么需要它？</h2><ul><li>🚗 <strong>被堵车却找不到车主</strong> - 干着急没办法。</li><li>📱 <strong>传统挪车码暴露电话</strong> - 隐私泄露、广告骚扰电话不断。</li><li>😈 <strong>恶意扫码骚扰</strong> - 有人故意反复扫码打扰车主。</li><li>🤔 <strong>路人好奇扫码</strong> - 并不需要挪车却触发了通知。</li></ul><h2 id="✅-这个系统如何解决？"><a href="#✅-这个系统如何解决？" class="headerlink" title="✅ 这个系统如何解决？"></a>✅ 这个系统如何解决？</h2><ul><li>🚀 <strong>多用户架构 (v2.0)</strong> - 一次部署，全家可用。通过 <code>?u=用户ID</code> 区分不同车主。</li><li>🔐 <strong>不暴露电话号码</strong> - 通过微信或 Bark 推送通知联系，完全隐藏真实号。</li><li>📍 <strong>双向位置共享</strong> - 车主可确认请求者是否真的在车旁，避免无效驱奔。</li><li>⏳ <strong>智能频率控制</strong> - <strong>每个用户独立计算</strong> 60秒冷却时间，互不干扰，有效防骚扰。</li><li>🆓 <strong>免费零成本</strong> - 利用 Cloudflare Workers 免费额度，无需服务器，无需备案。</li></ul><hr><h2 id="🔔-为什么推荐推送方式？"><a href="#🔔-为什么推荐推送方式？" class="headerlink" title="🔔 为什么推荐推送方式？"></a>🔔 为什么推荐推送方式？</h2><h3 id="Bark-iOS-推荐"><a href="#Bark-iOS-推荐" class="headerlink" title="Bark (iOS 推荐)"></a>Bark (iOS 推荐)</h3><ul><li>支持「紧急 &#x2F; 重要 &#x2F; 警告」通知级别。</li><li>可自定义通知音效，甚至在<strong>开启勿扰模式</strong>时也能强提醒。</li></ul><h3 id="PushPlus-微信推荐"><a href="#PushPlus-微信推荐" class="headerlink" title="PushPlus (微信推荐)"></a>PushPlus (微信推荐)</h3><ul><li>零门槛，只需微信扫码关注即可接收通知。</li><li>支持 HTML 格式，点击通知即可直接跳转到确认处理页面。</li></ul><hr><h2 id="🔄-使用流程"><a href="#🔄-使用流程" class="headerlink" title="🔄 使用流程"></a>🔄 使用流程</h2><h3 id="请求者（路人）"><a href="#请求者（路人）" class="headerlink" title="请求者（路人）"></a><strong>请求者（路人）</strong></h3><ol><li>扫描车上二维码，进入页面。</li><li>填写留言（如「挡住出口了」）。</li><li><strong>允许获取位置</strong>（若拒绝，系统将强制延迟 30 秒发送，降低恶意扫码动力）。</li><li>点击「通知车主」，等待状态更新。</li></ol><h3 id="车主（您）"><a href="#车主（您）" class="headerlink" title="车主（您）"></a><strong>车主（您）</strong></h3><ol><li>手机即时收到推送通知。</li><li>点击通知进入确认页面，查看请求者位置。</li><li>点击「我已知晓，马上过去」，系统自动同步状态给请求者。</li></ol><hr><h2 id="🛠️-部署教程"><a href="#🛠️-部署教程" class="headerlink" title="🛠️ 部署教程"></a>🛠️ 部署教程</h2><h3 id="第一步：注册-Cloudflare"><a href="#第一步：注册-Cloudflare" class="headerlink" title="第一步：注册 Cloudflare"></a>第一步：注册 Cloudflare</h3><p>打开 <a href="https://dash.cloudflare.com/">dash.cloudflare.com</a> 注册并登录。</p><h3 id="第二步：创建-Worker"><a href="#第二步：创建-Worker" class="headerlink" title="第二步：创建 Worker"></a>第二步：创建 Worker</h3><ol><li>进入「Workers &amp; Pages」 -&gt; 「Create」 -&gt; 「Create Worker」。</li><li>名称填 <code>movecar</code>，点击「Deploy」。</li><li>点击「Edit code」，删除默认代码，将 <strong><code>worker.js</code></strong> 全部内容粘贴进去，点击右上角「Deploy」。</li></ol><h3 id="第三步：配置-KV-存储-必须"><a href="#第三步：配置-KV-存储-必须" class="headerlink" title="第三步：配置 KV 存储 (必须)"></a>第三步：配置 KV 存储 (必须)</h3><ol><li>点击左侧菜单「KV」。</li><li>创建一个命名空间，名称填：<code>MOVE_CAR_STATUS</code>。</li><li>回到你的 Worker -&gt; 「Settings」 -&gt; 「Bindings」。</li><li>添加「KV Namespace」，变量名填 <code>MOVE_CAR_STATUS</code>，选择刚才创建的空间，保存部署。</li></ol><h3 id="第四步：配置环境变量-多用户关键"><a href="#第四步：配置环境变量-多用户关键" class="headerlink" title="第四步：配置环境变量 (多用户关键)"></a>第四步：配置环境变量 (多用户关键)</h3><p>在 Worker 的「Settings」 -&gt; 「Variables and Secrets」中添加：</p><h4 id="1-默认全局变量-可选"><a href="#1-默认全局变量-可选" class="headerlink" title="1. 默认全局变量 (可选)"></a>1. 默认全局变量 (可选)</h4><ul><li><code>BARK_URL</code>：默认推送地址。</li><li><code>PUSHPLUS_TOKEN</code>：默认微信令牌。</li></ul><h4 id="2-用户专属变量-强烈推荐"><a href="#2-用户专属变量-强烈推荐" class="headerlink" title="2. 用户专属变量 (强烈推荐)"></a>2. 用户专属变量 (强烈推荐)</h4><p>**格式：<code>变量名_用户ID</code> (ID需大写)**。例如你的 ID 是 <code>xiaowang</code>：</p><ul><li><code>PUSHPLUS_TOKEN_XIAOWANG</code>：该用户的专属令牌（如PushPlus或者Bark的TOKEN）。</li><li><code>CAR_TITLE_XIAOWANG</code>：显示的车辆&#x2F;车主信息（如：粤B·88888）。</li><li><code>EXTERNAL_URL</code>：填入你的反代备案域名（例如 <a href="https://xx.xxx.com）-（可选，注意：带上https，末尾不要带斜杠">https://xx.xxx.com）-（可选，注意：带上https，末尾不要带斜杠</a>)</li><li><code>PHONE_NUMBER_XIAOWANG</code>：该车主的备用电话-通知车主后没有回应的时候可以直接拨打电话（可选）。</li></ul><h3 id="第五步：绑定域名-可选"><a href="#第五步：绑定域名-可选" class="headerlink" title="第五步：绑定域名 (可选)"></a>第五步：绑定域名 (可选)</h3><p>在「Settings」 -&gt; 「Domains &amp; Routes」中绑定你的自定义域名。</p><hr><h2 id="🎨-制作挪车码"><a href="#🎨-制作挪车码" class="headerlink" title="🎨 制作挪车码"></a>🎨 制作挪车码</h2><h3 id="1-生成链接"><a href="#1-生成链接" class="headerlink" title="1. 生成链接"></a>1. 生成链接</h3><p>你的专属链接为：<code>https://你的域名/?u=你的ID</code><br>例如：<code>https://movecar.xxxx.workers.dev/?u=xiaowang</code></p><h3 id="2-生成二维码"><a href="#2-生成二维码" class="headerlink" title="2. 生成二维码"></a>2. 生成二维码</h3><p>使用 <a href="https://cli.im/">草料二维码</a> 将链接转为二维码下载。</p><h3 id="3-美化与打印"><a href="#3-美化与打印" class="headerlink" title="3. 美化与打印"></a>3. 美化与打印</h3><ul><li>使用 <strong>Midjourney</strong> 或 <strong>ChatGPT (DALL-E)</strong> 生成精美的挪车牌背景。</li><li>将二维码组合排版，添加文字：<strong>「扫码通知车主挪车」</strong>。</li><li>打印、过塑，贴在挡风玻璃处。</li></ul><hr><h2 id="🛡️-安全与隐私"><a href="#🛡️-安全与隐私" class="headerlink" title="🛡️ 安全与隐私"></a>🛡️ 安全与隐私</h2><ul><li><strong>自动清理</strong>：所有位置和状态信息在 1 小时后从 KV 中自动删除。</li><li><strong>并发安全</strong>：v2.0 修复了语法陷阱，支持高并发环境下的稳定运行。</li></ul><h2 id="📄-许可证"><a href="#📄-许可证" class="headerlink" title="📄 许可证"></a>📄 许可证</h2><p>本项目采用 <a href="LICENSE">MIT License</a> 开源。</p><p>开源地址：<a href="https://github.com/nbbk/movecar">https://github.com/nbbk/movecar</a></p>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
          <category> 开源项目 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> Cloudflare Workers </tag>
            
            <tag> 挪车码 </tag>
            
            <tag> 阿里云 ESA </tag>
            
            <tag> 隐私安全 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>一文读懂！Personal Backup 软件中文版使用全攻略，轻松实现数据自动备份</title>
      <link href="/post/4b56f5c7.html"/>
      <url>/post/4b56f5c7.html</url>
      
        <content type="html"><![CDATA[<p><img src="https://img.nnu.cn/p/69e73bd0d8881.webp"></p><h1 id="免费备份神器“Personal-Backup”介绍"><a href="#免费备份神器“Personal-Backup”介绍" class="headerlink" title="免费备份神器“Personal Backup”介绍"></a>免费备份神器“Personal Backup”介绍</h1><p>Personal Backup 是一款由德国开发者 Dr. Jürgen Rathlev 编写的完全免费且功能强大的个人数据备份工具。只需配置好“备份任务”（通常保存为 <code>.buj</code> 格式的文件），软件即可在后台默默守护你的数据，实现全自动的备份流程。今天来详细介绍一下这款软件的核心功能以及它的具体配置方法。</p><p>首先我们来看一下软件的主界面，它的逻辑非常清晰，主要分为源目录（你要备份什么）和目标目录（你要备份到哪里）。<br><img src="https://img.nnu.cn/p/69e73b8822009.webp"><br>通过软件左侧的导航栏，我们可以一步步完成备份计划的制定。</p><h2 id="一、这款软件都能干什么呢？"><a href="#一、这款软件都能干什么呢？" class="headerlink" title="一、这款软件都能干什么呢？"></a>一、这款软件都能干什么呢？</h2><ol><li><strong>本地与外部设备备份</strong>：支持将数据备份到本地硬盘的另一个分区、U盘、移动硬盘等固定或可移动存储设备。</li><li><strong>网络与服务器备份</strong>：支持备份到局域网共享目录（NAS），或者通过 FTP、FTPS 协议备份到远程服务器。</li><li><strong>备份模式丰富</strong>：支持完整备份、更新备份（增量&#x2F;差异），可按时间戳比对文件变化，极大节省存储空间和备份时间。</li><li><strong>压缩与加密</strong>：支持将备份文件打包为 ZIP 格式，并且支持 AES 算法的高强度加密，防止隐私泄露。</li><li><strong>过滤与排除</strong>：可以根据文件类型（后缀名）、文件大小、文件存在时间等条件，灵活排除不需要备份的缓存或临时文件。</li><li><strong>自动化与计划任务</strong>：支持开机备份、关机前提示备份，或利用 Windows 计划任务实现每天&#x2F;每周特定时间的自动备份。<br><img src="https://img.nnu.cn/p/69e73be567d5b.webp"></li></ol><h2 id="二、这个备份任务如何建立？"><a href="#二、这个备份任务如何建立？" class="headerlink" title="二、这个备份任务如何建立？"></a>二、这个备份任务如何建立？</h2><p>软件安装后，如果是英文界面，可以在顶部菜单栏选择“Language”将其切换为简体中文（Chinese Simplified）。接下来我们进入核心配置环节。</p><p>下面介绍几个最核心的设置，其他的进阶选项大家可以根据实际需求自行探索。首先，点击左上角的“新建任务”。</p><p>在弹出的向导或主控面板中，第一步是选择<strong>备份源（要备份的数据）</strong>。在“要备份的目录”区域，点击添加，勾选你想要保护的文件夹（例如工作文档、照片库等）。</p><p>第二步是选择<strong>备份目标（保存到哪里）</strong>。在“目标目录”区域，选择你的移动硬盘或 NAS 路径。强烈建议将数据备份到物理上独立的另一块硬盘中，以免原硬盘损坏导致数据与备份同时丢失。</p><p>第三步是设置<strong>备份模式</strong>。软件提供了多种模式：</p><ul><li><strong>按原目录结构复制</strong>：最直观的方式，目标文件夹里的内容和源文件夹一模一样。</li><li><strong>压缩为 Zip 文件</strong>：节省空间，可以将每次备份打包成一个独立的压缩包。</li></ul><p>如果你希望数据绝对安全，可以在底部的“加密”选项中勾选，并设置一个复杂的密码。</p><p>在“选项”标签页中，可以设置“文件过滤”。比如你不想备份 <code>.tmp</code> 临时文件或巨大的 <code>.mp4</code> 视频，可以在这里添加排除规则。</p><p>设置完成后，点击顶部的“保存任务”，将这个 <code>.buj</code> 配置文件保存到你方便找到的地方。</p><h2 id="三、这个备份文件如何使用并实现自动化？"><a href="#三、这个备份文件如何使用并实现自动化？" class="headerlink" title="三、这个备份文件如何使用并实现自动化？"></a>三、这个备份文件如何使用并实现自动化？</h2><p>任务配置保存好之后，我们就可以让它自动运行了。Personal Backup 提供了极其方便的自动化机制：</p><ol><li><strong>一键手动备份</strong>：你可以在桌面上为刚才保存的 <code>.buj</code> 文件创建一个快捷方式。每次下班前，双击这个快捷方式，软件就会静默开始备份，完成后自动退出。</li><li><strong>使用内置计划任务</strong>：点击软件界面的“计划”图标，可以将其添加到 Windows 的自动计划任务中。例如，设置为“每天下午 18:00”，只要电脑开机，时间一到它就会在后台自动执行。</li><li><strong>随系统登录&#x2F;注销执行</strong>：在软件的偏好设置中，可以开启“随 Windows 启动”。还可以设置在系统注销或关机时触发备份，确保你一天的工作成果在关机前被妥善保存。</li></ol><ul><li>下载地址：<a href="https://personal-backup.rathlev-home.de/index-e.html">https://personal-backup.rathlev-home.de/index-e.html</a></li></ul>]]></content>
      
      
      <categories>
          
          <category> 教程 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 数据备份 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>电子班牌小工具使用说明</title>
      <link href="/post/8a1d473a.html"/>
      <url>/post/8a1d473a.html</url>
      
        <content type="html"><![CDATA[<p><img src="https://bing.nnu.cn/p/682ea0f0c197b.webp"></p><h3 id="目标设备列表管理"><a href="#目标设备列表管理" class="headerlink" title="目标设备列表管理"></a>目标设备列表管理</h3><h4 id="加载列表"><a href="#加载列表" class="headerlink" title="加载列表"></a>加载列表</h4><ul><li>程序启动时自动从本地路径 <strong>用户数据目录下的 ImageSenderData&#x2F;computers.json</strong> 加载已保存的设备列表，<strong>保留列表顺序</strong>。</li></ul><h4 id="添加设备"><a href="#添加设备" class="headerlink" title="添加设备"></a>添加设备</h4><ol><li>点击侧边栏 <strong>添加</strong> 按钮，在弹出对话框输入 <strong>设备名称</strong> 和 <strong>IP地址</strong>（IP需唯一）。  </li><li>添加成功后，自动探测新设备状态。</li></ol><h4 id="删除设备"><a href="#删除设备" class="headerlink" title="删除设备"></a>删除设备</h4><ul><li><strong>单选删除</strong>：  <ol><li>点击设备卡片（紫色高亮选中）。  </li><li>点击 <strong>删除</strong> 按钮，确认后删除。</li></ol></li><li><strong>多选删除</strong>：  <ol><li>勾选设备卡片左侧复选框（绿色边框提示）。  </li><li>点击 <strong>删除</strong> 按钮批量删除。</li></ol></li></ul><h4 id="导入列表"><a href="#导入列表" class="headerlink" title="导入列表"></a>导入列表</h4><ol><li>点击 <strong>导入</strong> 按钮，选择 <strong>.txt 或 .csv</strong> 文本文件。  </li><li>文件格式要求：每行一条记录，格式为 <strong>设备名称,IP地址</strong>（例：一楼大厅,192.168.1.10）。  </li><li>程序自动跳过格式错误或IP已存在的条目，导入后自动探测设备状态。</li></ol><h4 id="导出列表"><a href="#导出列表" class="headerlink" title="导出列表"></a>导出列表</h4><ol><li>点击 <strong>导出</strong> 按钮，选择保存路径和文件名。  </li><li>导出为与导入格式相同的文本文件，用于备份和迁移列表。</li></ol><h4 id="拖动排序"><a href="#拖动排序" class="headerlink" title="拖动排序"></a>拖动排序</h4><ul><li>按住设备卡片（非多选模式）上下拖动调整顺序，<strong>顺序更改自动保存</strong>。</li></ul><h4 id="刷新状态"><a href="#刷新状态" class="headerlink" title="刷新状态"></a>刷新状态</h4><ol><li>点击 <strong>刷新状态</strong> 按钮，通过TCP连接默认端口5000探测设备在线状态。  </li><li>状态指示灯：  <ul><li>🟢 绿色：在线  </li><li>🔴 红色：离线  </li><li>⚪ 灰色：未知&#x2F;探测中</li></ul></li></ol><h3 id="单独发送图片"><a href="#单独发送图片" class="headerlink" title="单独发送图片"></a>单独发送图片</h3><ol><li><strong>选中设备</strong>：从左侧列表中 <strong>单击选中</strong> 状态为 <strong>在线</strong> 的设备。  </li><li><strong>选择图片</strong>：点击 <strong>选择图像</strong> 按钮，选择JPG、PNG、BMP格式图片。  <ul><li>非BMP格式自动转为24位BMP，含中文的文件名自动替换为时间戳命名（后缀保持.bmp）。</li></ul></li><li><strong>预览与发送</strong>：  <ul><li>图片处理完成后显示预览，<strong>开始发送</strong> 按钮变为可用。  </li><li>点击 <strong>开始发送</strong> ，发送详情显示在日志窗口，状态栏显示结果。<br><strong>注意</strong>：仅支持向 <strong>在线设备</strong> 发送图片。</li></ul></li></ol><h3 id="一键恢复-批量发送自定义图片"><a href="#一键恢复-批量发送自定义图片" class="headerlink" title="一键恢复&#x2F;批量发送自定义图片"></a>一键恢复&#x2F;批量发送自定义图片</h3><ol><li>点击侧边栏 <strong>批量操作</strong> 下的 <strong>一键恢复</strong> 按钮。  </li><li>选择包含恢复图片的 <strong>文件夹</strong>，要求：  <ul><li>图片按数字顺序命名（如1.bmp, 2.bmp, 3.bmp）。  </li><li>数字对应列表中设备的 <strong>当前排序ID</strong>（第1个设备接收1.bmp，第2个接收2.bmp，以此类推）。</li></ul></li><li>程序自动向列表中所有设备发送对应图片（不在线设备尝试发送但可能失败），详情显示在日志窗口。</li></ol><h3 id="窗口操作"><a href="#窗口操作" class="headerlink" title="窗口操作"></a>窗口操作</h3><ul><li><strong>右上角按钮</strong>：支持最小化、最大化&#x2F;还原、关闭。  </li><li><strong>移动窗口</strong>：拖动标题栏调整位置。  </li><li><strong>子窗口操作</strong>：“关于”和“日志”页面支持拖动和标准窗口操作（若窗口框架可见）。</li></ul><h3 id="其他提示"><a href="#其他提示" class="headerlink" title="其他提示"></a>其他提示</h3><ol><li><strong>数据存储</strong>：设备列表信息保存至 <strong>ImageSenderData&#x2F;computers.json</strong>。  </li><li><strong>临时文件</strong>：图片处理生成的临时文件自动清理。  </li><li><strong>日志查看</strong>：发送详情显示在“发送日志详情”窗口，10秒后自动关闭或手动点击“确定”关闭。</li></ol>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 班牌 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>EdgeOne+COS对象存储搭建静态网站无法回源的解决方法</title>
      <link href="/post/fdf75660.html"/>
      <url>/post/fdf75660.html</url>
      
        <content type="html"><![CDATA[<p><img src="https://img.nnu.cn/p/668a6258a5969.webp"><br>在使用腾讯云边缘安全加速平台 EdgeOne和COS对象存储搭建静态网站的过程中，遇到一个可能是BUG的问题。本文将详细描述这个问题及其解决方法。</p><h4 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h4><p>在将静态网站部署到腾讯云COS对象存储后，通过配置腾讯边缘加速来加速访问网站资源。然而，在访问网站时，发现有些资源无法正确回源，导致网站无法正常加载。</p><h4 id="问题原因"><a href="#问题原因" class="headerlink" title="问题原因"></a>问题原因</h4><p>经官方后端排查是因为源站从ip&#x2F;域名类型切换至cos类型时没有重置回源端口导致访问cos桶使用了ip&#x2F;域名源站配置的回源端口导致的。</p><h4 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h4><p>解决这个问题的步骤如下：</p><ol><li><p><strong>登录腾讯云管理控制台：</strong><br>访问<a href="https://console.cloud.tencent.com/">腾讯云管理控制台</a>，使用您的账号登录。</p></li><li><p><strong>边缘安全加速平台 EO 配置页面：</strong><br>在控制台首页，找到“站点列表”，点击需要进入的域名。</p></li><li><p><strong>选择域名服务-域名管理：</strong><br>在配置页面，找到您需要修改的加速域名，点击该域名进入详情页面。<br><img src="https://img.nnu.cn/p/668a6368104cb.webp"><br>方案一： <strong>修改端口</strong><br>修改自有源回源端口为443，然后再切换为COS源；</p></li></ol><p>方案二： <strong>删除并重新添加源站：</strong><br>   删除域名，再重新接入域名，将源站直接设置为COS源即可。</p><p> <strong>验证回源是否正常：</strong><br>   配置完成后，等待生效后访问您的网站，检查资源是否能够正常加载即可。</p><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>在使用腾讯云边缘安全加速平台 EdgeOne和COS对象存储搭建静态网站时，如果之前源站端口配置了其它端口，一定要先修改成默认的80和443，否则将无法正确回源。<br>如果在操作过程中遇到其他问题，建议查看腾讯云的官方文档或联系腾讯云客服寻求帮助。</p>]]></content>
      
      
      <categories>
          
          <category> 笔记 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> EdgeOne </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>定期自动备份群晖（Synology）上正常运行的容器可以通过以下步骤来实现，以防止硬盘损坏导致数据丢失</title>
      <link href="/post/e2a0c459.html"/>
      <url>/post/e2a0c459.html</url>
      
        <content type="html"><![CDATA[<p><img src="https://img.nnu.cn/p/6682803aa19d4.webp"><br>定期自动备份群晖（Synology）上正常运行的容器可以通过以下步骤来实现，以防止硬盘损坏导致数据丢失。以下是详细步骤：</p><h3 id="1-使用-Hyper-Backup-进行备份"><a href="#1-使用-Hyper-Backup-进行备份" class="headerlink" title="1. 使用 Hyper Backup 进行备份"></a>1. 使用 Hyper Backup 进行备份</h3><p>Hyper Backup 是群晖提供的一个备份工具，可以用来备份系统配置、文件、文件夹和应用数据。</p><ol><li><p><strong>安装 Hyper Backup</strong>：</p><ul><li>在群晖 DSM 上打开“套件中心”。</li><li>搜索并安装“Hyper Backup”。</li></ul></li><li><p><strong>创建备份任务</strong>：</p><ul><li>打开 Hyper Backup。</li><li>点击左下角的“+”图标，选择“数据备份任务”。</li><li>选择备份目的地（例如，外部硬盘、另一个 NAS、云服务等）。</li><li>在备份任务中选择你想要备份的容器数据文件夹（通常是 Docker 的存储路径）。</li></ul></li><li><p><strong>设置备份计划</strong>：</p><ul><li>在创建备份任务的过程中，设置备份的频率（例如，每天、每周等）。</li><li>配置版本保留策略，以便保留多个备份版本。</li></ul></li></ol><h3 id="2-使用-Docker-容器备份脚本"><a href="#2-使用-Docker-容器备份脚本" class="headerlink" title="2. 使用 Docker 容器备份脚本"></a>2. 使用 Docker 容器备份脚本</h3><p>你可以编写一个脚本来导出和备份运行中的 Docker 容器数据。以下是一个简单的 Bash 脚本示例：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 设定备份路径</span></span><br><span class="line">BACKUP_PATH=<span class="string">&quot;/path/to/backup&quot;</span></span><br><span class="line">DATE=$(<span class="built_in">date</span> +<span class="string">&quot;%Y%m%d%H%M&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建备份目录</span></span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="variable">$&#123;BACKUP_PATH&#125;</span>/<span class="variable">$&#123;DATE&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取所有运行中的容器列表</span></span><br><span class="line">containers=$(docker ps -q)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 备份每个容器</span></span><br><span class="line"><span class="keyword">for</span> container <span class="keyword">in</span> <span class="variable">$&#123;containers&#125;</span></span><br><span class="line"><span class="keyword">do</span></span><br><span class="line">    CONTAINER_NAME=$(docker inspect --format=<span class="string">&#x27;&#123;&#123;.Name&#125;&#125;&#x27;</span> <span class="variable">$container</span> | <span class="built_in">cut</span> -c2-)</span><br><span class="line">    docker <span class="built_in">export</span> <span class="variable">$container</span> &gt; <span class="variable">$&#123;BACKUP_PATH&#125;</span>/<span class="variable">$&#123;DATE&#125;</span>/<span class="variable">$&#123;CONTAINER_NAME&#125;</span>.tar</span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除超过30天的备份（根据需要调整天数）</span></span><br><span class="line">find <span class="variable">$&#123;BACKUP_PATH&#125;</span> -<span class="built_in">type</span> d -mtime +30 -<span class="built_in">exec</span> <span class="built_in">rm</span> -rf &#123;&#125; \;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 记录备份完成时间</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Backup completed at <span class="subst">$(date)</span>&quot;</span> &gt;&gt; <span class="variable">$&#123;BACKUP_PATH&#125;</span>/backup.log</span><br></pre></td></tr></table></figure><h3 id="3-设定定时任务（Cron-Job）"><a href="#3-设定定时任务（Cron-Job）" class="headerlink" title="3. 设定定时任务（Cron Job）"></a>3. 设定定时任务（Cron Job）</h3><p>将上述脚本添加到 Cron Job 中以实现定期自动备份。</p><ol><li><p><strong>编辑 Crontab</strong>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">crontab -e</span><br></pre></td></tr></table></figure></li><li><p><strong>添加定时任务</strong>：<br>例如，设置每天凌晨2点执行备份任务：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">0 2 * * * /path/to/backup_script.sh</span><br></pre></td></tr></table></figure><p>或者<br>. 在群晖控制面板中添加定时任务</p><ol><li>   打开控制面板：<br> •登录到群晖 DSM。<br> •打开“控制面板”。</li><li>   添加定时任务：<br> •选择“任务计划”。<br> •点击“创建”按钮并选择“计划的任务”。<br> •选择“用户自定义脚本”。</li><li>   配置任务：<br> •常规选项：<br> •输入任务名称（例如，“备份 Docker 容器”）。<br> •选择任务用户（通常是 root 用户，以确保有足够权限）。<br> •定时设置：<br> •设置任务的运行频率（例如，每天凌晨 2 点）。<br> •任务设置：<br> •在“任务设置”中，输入以下命令：</li></ol></li></ol><p>&#x2F;bin&#x2F;bash &#x2F;path&#x2F;to&#x2F;backup_script.sh</p><ol start="4"><li>验证脚本执行</li></ol><p>为了确保脚本能正常运行，手动执行脚本并查看输出日志。</p><p>&#x2F;bin&#x2F;bash &#x2F;path&#x2F;to&#x2F;backup_script.sh</p><ol start="5"><li>检查日志和错误</li></ol><p>在“任务计划”中查看任务的日志输出，以确认任务是否成功执行。如果脚本中有任何输出或错误，它们应该记录在任务的日志中。</p><ol start="6"><li>设置邮件通知（可选）</li></ol><p>可以配置邮件通知，以便在任务失败或成功时接收到通知。</p><p>注意事项</p><pre><code>•权限问题：确保运行脚本的用户（如 root）有权访问所有需要的文件和目录。•路径问题：使用绝对路径，避免路径问题。•环境变量：设置必要的环境变量，以确保脚本中的命令可以正常执行。</code></pre><p>通过这些步骤，应该可以在群晖控制面板中成功添加并运行定时任务，确保定期自动备份 Docker 容器的数据。</p><h3 id="4-备份到外部存储"><a href="#4-备份到外部存储" class="headerlink" title="4. 备份到外部存储"></a>4. 备份到外部存储</h3><p>为了进一步提高数据安全性，可以将备份数据存储到外部设备，如外部硬盘或云存储服务。</p><ul><li><strong>外部硬盘</strong>：连接到群晖 NAS 后，通过 Hyper Backup 或脚本将数据备份到外部硬盘。</li><li><strong>云存储</strong>：使用 Hyper Backup 支持的云存储服务（如 Google Drive、Amazon S3 等）进行远程备份。</li></ul><p>通过以上步骤，你可以定期自动备份群晖上正常运行的容器，从而在硬盘损坏时保护数据免于丢失。</p>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> NAS </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>RAID手动导入硬盘</title>
      <link href="/post/8395bc9d.html"/>
      <url>/post/8395bc9d.html</url>
      
        <content type="html"><![CDATA[<h3 id="LSI阵列卡RAID5硬盘手动导入操作步骤"><a href="#LSI阵列卡RAID5硬盘手动导入操作步骤" class="headerlink" title="LSI阵列卡RAID5硬盘手动导入操作步骤"></a>LSI阵列卡RAID5硬盘手动导入操作步骤</h3><p>在运维工作中，经常会遇到RAID5更换硬盘后，硬盘处于unconfigure good状态，此时需要手动将其导入到RAID5中。以下是详细的操作步骤：</p><ol><li><p><strong>进入阵列卡管理界面</strong></p><ul><li>开机时按 <code>Ctrl+H</code> 进入阵列卡管理界面（WebBIOS）。</li></ul><p><img src="https://img.nnu.cn/p/668b47cc52165.webp"></p></li><li><p><strong>启动操作</strong></p><ul><li>在如下界面选择 <code>Start</code> 按钮。<br><img src="https://img.nnu.cn/p/668b47fcd053d.webp"></li></ul></li><li><p><strong>查看硬盘状态</strong></p><ul><li>进入WebBIOS界面后，可以看到所有硬盘状态，发现三块online，一块unconfigured good。<br><img src="https://img.nnu.cn/p/668b482bed396.webp"></li></ul></li><li><p><strong>选择unconfigured good硬盘</strong></p><ul><li>选中unconfigured good硬盘，进入如下界面，然后选择 <code>Replace Missing PD</code>，单击 <code>Go</code>。<br><img src="https://img.nnu.cn/p/668b4848842e2.webp"></li></ul></li><li><p><strong>重建驱动器</strong></p><ul><li>接着选择 <code>Rebuild Drive</code>，单击 <code>Go</code>。<br><img src="https://img.nnu.cn/p/668b4870911f5.webp"></li></ul></li><li><p><strong>返回主界面</strong></p><ul><li>进入如下视图后，选择 <code>Back</code> 回到主界面。<br><img src="https://img.nnu.cn/p/668b48823859a.webp"></li></ul></li><li><p><strong>检查硬盘状态</strong></p><ul><li>此时，三块盘Online，另外一块unconfigured good状态的硬盘变为了Rebuild状态。<br><img src="https://img.nnu.cn/p/668b489f47d0d.webp"></li></ul></li><li><p><strong>重启服务器</strong></p><ul><li>按 <code>Ctrl+Alt+Delete</code> 重启服务器，等待重建完成，所有硬盘都将变为Online。</li></ul></li></ol>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 服务器 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>Windows10/11账户有密码设置开机自动登录</title>
      <link href="/post/e1caaa84.html"/>
      <url>/post/e1caaa84.html</url>
      
        <content type="html"><![CDATA[<h2 id="什么是-Windows-自动登录？"><a href="#什么是-Windows-自动登录？" class="headerlink" title="什么是 Windows 自动登录？"></a>什么是 Windows 自动登录？</h2><p>Windows 自动登录是一项便捷功能，允许用户在启动电脑或从睡眠状态唤醒时无需输入密码或 PIN 码即可直接进入系统。此功能可以显著缩短开机时间并提升使用效率。</p><h3 id="使用场景与潜在风险"><a href="#使用场景与潜在风险" class="headerlink" title="使用场景与潜在风险"></a>使用场景与潜在风险</h3><p>虽然自动登录功能带来了便利，但在以下情况下启用此功能可能会带来安全隐患：</p><ul><li><strong>不推荐在便携设备上启用</strong>：例如笔记本电脑、平板电脑等，因为这些设备经常被携带外出，容易丢失或被盗。</li><li><strong>不推荐在多人共用的电脑上启用</strong>：可能会导致他人未经授权访问你的账户。</li><li><strong>推荐在没有重要数据的虚拟机上启用</strong>：这类环境相对安全，即使启用自动登录也不会有太大风险。</li><li><strong>推荐在仅个人使用的家用电脑上启用</strong>：家用电脑一般不会被陌生人接触，启用自动登录相对安全。</li></ul><p>如果你的 Windows 系统中有多个用户账户，可以只为其中一个账户设置自动登录，从而保持其他主要账户的安全。</p><h3 id="设置-Windows-自动登录的方法"><a href="#设置-Windows-自动登录的方法" class="headerlink" title="设置 Windows 自动登录的方法"></a>设置 Windows 自动登录的方法</h3><p><img src="https://img.nnu.cn/p/6692659379f8b.webp"></p><ol><li>使用快捷键 <code>Windows + R</code> 调出“运行”对话框，输入 <code>netplwiz</code> 打开“用户账户”设置窗口。<br><img src="https://img.nnu.cn/p/6692659f17162.webp"></li><li>在“用户账户”窗口中，取消勾选“要使用本计算机，用户必需输入用户名和密码”，然后点击“应用”按钮。</li><li>弹出“自动登录”对话框，输入账户密码两次，确认无误后点击“确定”即可。</li></ol><p>完成设置后，系统会在登录时自动验证密码，但并不会删除密码。如果你更改了账户密码，需要按照以上步骤重新设置自动登录。</p><p>通过这种方式，可以在保证一定安全性的前提下享受自动登录带来的便利。</p>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 系统 </tag>
            
            <tag> 密码 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>ThinkServer RD、TDx50系列服务器板载SATA RAID</title>
      <link href="/post/dad6c24.html"/>
      <url>/post/dad6c24.html</url>
      
        <content type="html"><![CDATA[<h3 id="BIOS及RAID设置指南"><a href="#BIOS及RAID设置指南" class="headerlink" title="BIOS及RAID设置指南"></a>BIOS及RAID设置指南</h3><h4 id="一、BIOS及RAID设置"><a href="#一、BIOS及RAID设置" class="headerlink" title="一、BIOS及RAID设置"></a>一、BIOS及RAID设置</h4><ol><li><p>启动服务器，在出现 ThinkServer logo 时按 <code>F1</code> 键进入 BIOS。进入 <strong>Advanced Settings</strong> 中的 <strong>SATA Settings</strong>：</p><ul><li>修改 <strong>SATA Mode</strong> 为 <code>RAID</code>。</li><li>修改 <strong>sSATA Mode</strong> 为 <code>IDE</code>。</li></ul><p><img src="https://img.nnu.cn/p/668aa631376fa.webp"></p></li><li><p>进入 <strong>Boot Manager</strong>，修改 <strong>Boot Mode</strong> 为 <code>Auto</code> 或 <code>UEFI Only</code>。</p></li></ol><p><img src="https://img.nnu.cn/p/668aa67ce0f62.webp"></p><ol start="3"><li><p>进入 <strong>Miscellaneous Boot Settings</strong>，修改 <strong>Storage OpROM Policy</strong> 为 <code>UEFI Only</code>。</p><blockquote><p><strong>Storage OpROM Policy</strong> 设置可能随 <strong>Boot Mode</strong> 联动，为灰色不可修改</p></blockquote><p><img src="https://img.nnu.cn/p/668aa67ce0f62.webp"></p></li><li><p>按 <code>F10</code> 键保存并重启服务器，再按 <code>F1</code> 键进入 BIOS。进入 <strong>Boot Manager</strong> 中的 <strong>Adapters and UEFI Drivers</strong>，再找到 <strong>Lenovo ThinkServer RAID 110i</strong> 进入板载 SATA RAID 配置界面。</p></li></ol><p><img src="https://img.nnu.cn/p/668aa6aea4610.webp"></p><ol start="5"><li><p>进入 RAID 110i 配置主界面后有 3 个项目：</p><ul><li><strong>Controller Management</strong> 是对 RAID 110i 控制器进行设置。</li><li><strong>Virtual Drive Management</strong> 是新建 RAID 及查看、调整 RAID 设置。</li><li><strong>Drive Management</strong> 是查看、调整硬盘设置。</li></ul><p><img src="https://img.nnu.cn/p/668aa6c538c1a.webp"></p></li><li><p>先确认硬盘状态是否为可用状态。进入 <strong>Drive Management</strong>，再进入 <strong>Select Drive Operations</strong>。</p><p><img src="https://img.nnu.cn/p/668aa6fe82693.webp"></p></li><li><p>在 <strong>Select Drive</strong> 上按回车，确认 <strong>Select Drive</strong> 框体中是否出现所有硬盘，且硬盘状态都是 <code>Unconfigured Good</code> 状态。</p><p> <img src="https://img.nnu.cn/p/668aa7221fb98.webp"></p></li><li><p>确认完毕后就可以新建 RAID 了。本例以 2 个硬盘配置 RAID1 为例。返回 RAID 110i 配置主界面，进入 <strong>Virtual Drive Management</strong>，再进入 <strong>Create Configuration</strong>。</p><p> <img src="https://img.nnu.cn/p/668aa87b22103.webp"></p></li><li><p>设置 <strong>Select Drive Level</strong> 为 <code>RAID1</code>。（如果要做 RAID5 请至少准备 3 块硬盘）</p><p><img src="https://img.nnu.cn/p/668aabb71a12b.webp"></p></li><li><p>进入 <strong>Select Drivers</strong> 以选择硬盘。</p><p><img src="https://img.nnu.cn/p/668aabc645716.webp"></p></li><li><p>将需要加入 RAID 的硬盘状态修改为 <code>Enabled</code>，然后选择 <strong>Apply Changes</strong> 应用更改。</p><blockquote><p>注意：如果要加入固态硬盘，需要将 <strong>Select Media Type</strong> 修改为 <code>SSD</code>。请勿将机械硬盘和固态硬盘加入同一组 RAID。</p></blockquote><p><img src="https://img.nnu.cn/p/668aabd61131f.webp"></p></li><li><p>提示操作完成，选择 <code>OK</code>。</p><p><img src="https://img.nnu.cn/p/668aabe40de5a.webp"></p></li><li><p>可以对 <strong>Virtual Drive Size</strong> 进行修改以调整 RAID 卷大小，其他项目不需要进行调整，选择 <strong>Save Configuration</strong> 保存 RAID 配置。</p></li></ol><p>   <img src="https://img.nnu.cn/p/668aabf0d13c6.webp"></p><ol start="14"><li><p>提示会抹除硬盘上已有的数据，选择 <code>Yes</code> 继续。</p><p><img src="https://img.nnu.cn/p/668aac04c23ad.webp"></p></li><li><p>提示操作完成，选择 <code>OK</code>。</p><p><img src="https://img.nnu.cn/p/668aabe40de5a.webp"></p></li><li><p>确认新建 RAID 是否正常并快速初始化。</p><blockquote><p>注意：快速初始化会抹除硬盘上的所有数据。如要保留硬盘上的数据，请跳过初始化步骤。</p></blockquote></li><li><p>回到 <strong>Virtual Drive Management</strong>，进入 <strong>Select Virtual Drive Operations</strong>。</p><p><img src="https://img.nnu.cn/p/668aac3082c5f.webp"></p></li><li><p>确认 <strong>Select Virtual Drive</strong> 中的 <code>Virtual Drive #</code> 状态是否是 <code>Optimal</code>。</p><p><img src="https://img.nnu.cn/p/668aac9a8593b.webp"></p></li><li><p>将 <strong>Virtual Drive Operation</strong> 设置为 <code>Fast Initialization</code>。</p><blockquote><p>注意：如果 <strong>Virtual Drive Operations:</strong> 的状态为 <code>Background Initialization</code>，请点选择 <code>Stop Operation</code> 停止后台初始化操作，再执行快速初始化。</p></blockquote><p><img src="https://img.nnu.cn/p/668aaca880f5b.webp"></p></li><li><p>选择 <code>Start Operation</code> 开始执行快速初始化。</p><p><img src="https://img.nnu.cn/p/668aacfbbc5d8.webp"></p></li><li><p>出现确认提示，快速初始化会抹除阵列上的所有数据，选择 <code>Yes</code> 继续。</p></li></ol><p>   <img src="https://img.nnu.cn/p/668aad0f83eb1.webp"></p><ol start="22"><li><p>操作完成，选择 <code>OK</code>。</p><p>快速初始化需要 10 秒左右完成。</p><p><img src="https://img.nnu.cn/p/668aad2dbdd28.webp"></p></li><li><p>最后设置 RAID 卷为启动设备。返回 RAID 110i 配置主界面，进入 <strong>Controller Management</strong>，再进入 <strong>Change Controller Properties</strong>。</p><p><img src="https://img.nnu.cn/p/668aad402065c.webp"></p></li><li><p>设置 <strong>Set Boot Device</strong> 为要安装操作系统的 RAID 卷，如刚刚创建的 <code>Virtual Drive 0</code>。修改完成后选择 <strong>Apply Changes</strong> 以应用修改，并选择 <code>OK</code> 继续。</p><blockquote><p>注意：<strong>Set Boot Device</strong> 默认值为 <code>None</code>，如未设置正确可能导致安装操作系统后无法正常引导启动操作系统。</p></blockquote><p><img src="https://img.nnu.cn/p/668aad5b3c429.webp"></p></li><li><p>RAID 配置到此结束。</p></li></ol><h4 id="相关下载"><a href="#相关下载" class="headerlink" title="相关下载"></a>相关下载</h4><p>最后附上 RD650 RAID 驱动下载页面：<a href="https://datacentersupport.lenovo.com/cn/zc/products/servers/thinkserver/rd650/70d0/70d0cto1ww/pc0e6u6n/downloads/driver-list/component?name=RAID/SAS%20HBA%20Controllers,%20Backplanes,%20Storage%20Expanders/Switches,%20Bootable%20Storage&id=D3C7592B-24B3-4ADE-B3BF-1BAAEF120728">点击下载</a></p>]]></content>
      
      
      <categories>
          
          <category> 笔记 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 服务器 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>Windows远程桌面连接提示：出现身份验证错误，要求的函数不受支持</title>
      <link href="/post/45a3f914.html"/>
      <url>/post/45a3f914.html</url>
      
        <content type="html"><![CDATA[<h3 id="Windows远程桌面连接提示：出现身份验证错误，要求的函数不受支持"><a href="#Windows远程桌面连接提示：出现身份验证错误，要求的函数不受支持" class="headerlink" title="Windows远程桌面连接提示：出现身份验证错误，要求的函数不受支持"></a>Windows远程桌面连接提示：出现身份验证错误，要求的函数不受支持</h3><p>在使用Windows 10系统进行远程桌面连接时，可能会出现以下错误：</p><p>出现身份验证错误，要求的函数不受支持</p><h4 id="错误信息图示："><a href="#错误信息图示：" class="headerlink" title="错误信息图示："></a>错误信息图示：</h4><p><img src="https://img.nnu.cn/p/668cb362938e6.webp"></p><h4 id="解决办法："><a href="#解决办法：" class="headerlink" title="解决办法："></a>解决办法：</h4><ol><li><p><strong>打开运行窗口</strong></p><ul><li>按Windows键+R，或者在CMD命令窗口，输入“运行”，打开运行窗口。</li></ul><p><img src="https://img.nnu.cn/p/668cb37bcd7f9.webp"></p></li><li><p><strong>打开注册表编辑器</strong></p><ul><li>输入<code>regedit</code>，打开注册表编辑器。</li></ul><p><img src="https://img.nnu.cn/p/668cb38eaf3c0.webp"></p></li><li><p><strong>找到路径并创建文件夹项</strong></p><ul><li>找到路径：计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System</li><li>然后在System文件夹内创建文件夹项：\CredSSP\Parameters</li></ul></li><li><p><strong>新建DWORD值</strong></p><ul><li>在Parameters文件夹内，新建 DWORD（32）位值（D），文件名为 <code>AllowEncryptionOracle</code>，值为2。</li></ul></li></ol><p>  <img src="https://img.nnu.cn/p/668cb3a06edb0.webp"></p><ol start="5"><li><strong>重新远程连接</strong><ul><li>这个时候可以重新远程连接一下，发现错误消失，可以正常连接。</li></ul></li></ol>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 系统 </tag>
            
            <tag> 远程 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>zTasker定时任务工具</title>
      <link href="/post/e21f6c96.html"/>
      <url>/post/e21f6c96.html</url>
      
        <content type="html"><![CDATA[<h3 id="一款定时任务工具，在一些场景中可能会用到，今天无意间看到的，收藏备用。以下是作者对软件的介绍。"><a href="#一款定时任务工具，在一些场景中可能会用到，今天无意间看到的，收藏备用。以下是作者对软件的介绍。" class="headerlink" title="一款定时任务工具，在一些场景中可能会用到，今天无意间看到的，收藏备用。以下是作者对软件的介绍。"></a>一款定时任务工具，在一些场景中可能会用到，今天无意间看到的，收藏备用。以下是作者对软件的介绍。</h3><p><strong>zTasker 软件介绍</strong></p><p><strong>一、软件概述</strong></p><p>zTasker 是一个自动化任务工具，其目标是用图形化的方式取代大部分自动化场景操作。</p><p><strong>二、功能特点</strong></p><ol><li>支持 100+种任务类型，30+种定时&#x2F;条件执行方法。<ul><li>任务列表可随意编辑、排列、移动、更改类型，支持任务执行日志和数据备份。</li></ul></li><li>体积小，仅 9M，占用极少资源，运行快速。<ul><li>支持各种定时计划，如秒、分钟、小时、天、周、月、年、指定日期、倒计时、整点半点循环，并支持农历。</li><li>还支持系统条件触发，如系统空闲时间、文件夹监控、CPU|GPU|内存|磁盘占用、硬件、网速、开机延迟、休眠恢复后延迟等条件触发。</li><li>涵盖提醒、关机重启、报时、挡屏休息、文件备份、音量调节、静音，窗口|显示器控制，多媒体、截图、录音录像，程序、进程、服务等操作，更换墙纸，系统清理，网络操作，文本搜索、热键转发等。</li><li>任务可定时、条件或热键触发，灵活组合。</li><li>支持任务日志，方便查看任务执行情况。</li><li>定时&#x2F;热键备份&#x2F;同步文件，文件夹，注册表等，相当于备份软件。</li><li>具备各种监控，如文件夹监控、CPU|GPU|内存|磁盘占用、网速等。</li></ul></li></ol><p><strong>三、安全性</strong></p><p>zTasker 承诺不包含任何恶意代码和木马病毒，不做任何恶意行为。每次发布前会通过火绒&#x2F;360&#x2F;AVG&#x2F;Windows Defender 安全扫描，若系统报毒，属于误报。</p><p><strong>四、常见问题</strong></p><ol><li><p>安装时提示文件被占用</p><ul><li>可能是 360 等安全软件的实时文件扫描所致，可先临时退出这些安全软件或临时关闭文件防护再安装。</li></ul></li><li><p>zTasker 安装目录下 zTaskerUp.exe</p><ul><li>这是 zTasker 的在线升级程序，无需担心。</li></ul></li><li><p>系统无法使用 TTS 语音朗读</p><ul><li>某些国内的特制版系统精简掉了 TTS 语音引擎，请自行搜索安装。若无法解决，可点击下载。</li></ul></li><li><p>电脑锁屏后 zTasker 无法执行</p><ul><li>电脑在电源管理中设置了自动休眠或睡眠，若想锁屏后执行，请先关闭该选项。</li></ul></li><li><p>软件菜单里的静音模式</p><ul><li>静音模式是指把所有设置了声音播放的任务，都关闭声音输出，以免声音干扰。鼠标放到菜单上停一会儿会有提示。</li></ul></li><li><p>zTasker 是否必须管理员权限</p><ul><li>不是必须的。在 1.8 以前版本，开启关闭服务等极少数功能需要管理员身份运行。在 1.8 及以后版本，管理员身份运行本软件不是必须的，少数需要权限认证的任务，会以红字标明，需要的情况下会弹出系统的验证框。</li></ul></li></ol><p><strong>五、技术特色</strong></p><p>zTasker 采用 C++语言构建，采用了插件化架构，大量采用高度复用可维护的设计模式，并优化算法和流程。包含众多强大功能的同时，性能做到了最优化，界面反应速度一流，在家用 PC 机上，可以做到毫秒级启动。</p><p><strong>六、更新状况</strong></p><p>zTasker 会定时更新，修复问题，添加新的更强大的功能。</p><p><strong>七、数据备份</strong></p><p>可以在主菜单-&gt;备份恢复中备份数据。</p><p><strong>八、特殊功能相关</strong></p><ol><li><p>录像或录音文件较大</p><ul><li>可能是选择的编解码器不合适，在高级设置里可以选择编码器。如果还是过大，还可以安装第三方解码器，如 ffdshow 视频编码器，Lame 音频编码器等。</li></ul></li><li><p>定制整点报时声音</p><ul><li>可以，报时设置里选择真人，勾选整点报时使用明星声音。声音文件在安装目录下 Data\Sound\Starts 里，有两个子目录，0 代表女声，1 代表男声。进入 0 或者 1 目录里，看到以 T 开头的很多文件，后面是小时数，可以替换成自己的声音，保持文件名一致即可。</li></ul></li></ol><p>注：本程序在 1.93 之后版本将会尽量避免在升级或者卸载时清除替换的文件，但还是请做好替换文件的备份</p><p><strong>下载地址</strong>：<a href="http://everauto.net:8080/up/">官方软件目录</a></p>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 定时工具 </tag>
            
            <tag> 计划任务 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>一款追求轻量化的开源可视化路由跟踪工具NextTrace</title>
      <link href="/post/1e102ac4.html"/>
      <url>/post/1e102ac4.html</url>
      
        <content type="html"><![CDATA[<p>该类为推荐收藏开源项目，以下是部署说明<br>项目地址：<a href="https://github.com/nxtrace/NTrace-core?tab=readme-ov-file">https://github.com/nxtrace/NTrace-core?tab=readme-ov-file</a></p><h3 id="Before-Using"><a href="#Before-Using" class="headerlink" title="Before Using"></a>Before Using</h3><p>使用 NextTrace 之前，我们建议您先阅读 <a href="https://github.com/nxtrace/NTrace-core/blob/main/README_zh_CN.md#ip-%E6%95%B0%E6%8D%AE%E4%BB%A5%E5%8F%8A%E7%B2%BE%E5%87%86%E5%BA%A6%E8%AF%B4%E6%98%8E">#IP 数据以及精准度说明</a>，在了解您自己的对数据精准度需求以后再进行抉择。</p><h3 id="Automated-Install"><a href="#Automated-Install" class="headerlink" title="Automated Install"></a>Automated Install</h3><ul><li><p>Linux </p><ul><li><p>一键安装脚本</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl nxtrace.org/nt | bash</span><br></pre></td></tr></table></figure></li><li><p>Arch Linux AUR 安装命令</p><ul><li><p>直接下载bin包(仅支持amd64)</p>   <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yay -S nexttrace-bin</span><br></pre></td></tr></table></figure></li><li><p>从源码构建(仅支持amd64)</p>   <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yay -S nexttrace</span><br></pre></td></tr></table></figure></li><li><p>AUR 的构建分别由 ouuan, huyz 维护</p></li></ul></li><li><p>Linuxbrew 安装命令</p><p> 同macOS Homebrew安装方法(homebrew-core版仅支持amd64)</p></li><li><p>Deepin 安装命令</p> <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt install nexttrace</span><br></pre></td></tr></table></figure></li><li><p>Termux 安装命令</p> <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pkg install nexttrace-enhanced</span><br></pre></td></tr></table></figure></li></ul></li><li><p>macOS</p><ul><li>macOS Homebrew 安装命令<ul><li><p>homebrew-core版</p>   <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew install nexttrace</span><br></pre></td></tr></table></figure></li><li><p>本仓库ACTIONS自动构建版(更新更快)</p>   <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew tap nxtrace/nexttrace &amp;&amp; brew install nxtrace/nexttrace/nexttrace</span><br></pre></td></tr></table></figure></li><li><p>homebrew-core 构建由 chenrui333 维护，请注意该版本更新可能会落后仓库Action自动构建版本</p></li></ul></li></ul></li><li><p>Windows</p><ul><li>Windows Scoop 安装命令<ul><li><p>scoop-extras版</p>   <figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">scoop bucket add extras &amp;&amp; scoop install extras/nexttrace</span><br></pre></td></tr></table></figure></li><li><p>scoop-extra 由 soenggam 维护</p></li></ul></li></ul><p>请注意，以上多种安装方式的仓库均由开源爱好者自行维护，不保证可用性和及时更新，如遇到问题请联系仓库维护者解决，或使用本项目官方编译提供的二进制包。</p></li></ul><h3 id="Manual-Install"><a href="#Manual-Install" class="headerlink" title="Manual Install"></a>Manual Install</h3><ul><li><p>下载预编译的可执行程序</p><p>  对于以上方法没有涵盖的用户，请直接前往 <a href="https://www.nxtrace.org/downloads">Release</a> 下载编译后的二进制可执行文件。</p><ul><li><code>Release</code>里面为很多系统以及不同架构提供了编译好的二进制可执行文件，如果没有可以自行编译。</li><li>一些本项目的必要依赖在<code>Windows</code>上<code>Golang</code>底层实现不完全，所以目前<code>NextTrace</code>在<code>Windows</code>平台出于实验性支持阶段。</li></ul></li><li><p>从源码安装</p><p>  您可在自行安装Go &gt;&#x3D; 1.20后，使用以下命令安装</p>  <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go install github.com/nxtrace/NTrace-core@latest</span><br></pre></td></tr></table></figure><p>  <em>由于go.mod文件声明和文件目录冲突的问题，你不能用go install命令安装  <code>NTrace-V1</code> 版本</em><br>  安装后可执行文件在<code>$GOPATH/bin</code>目录下，如果您没有设置<code>GOPATH</code>，则在<code>$HOME/go/bin</code>目录下。<br>  安装后二进制文件名称与项目名称保持一致，你需要将下文中的 <code>nexttrace</code> 命令替换为 <code>NTrace-core</code> 使用<br>  如果你希望与下文命令保持一致，可以在执行 <code>go install</code> 命令后重命名二进制文件</p>  <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mv  $GOPATH/bin/NTrace-core $GOPATH/bin/nexttrace</span><br></pre></td></tr></table></figure></li></ul><h3 id="Get-Started"><a href="#Get-Started" class="headerlink" title="Get Started"></a>Get Started</h3><p><code>NextTrace</code> 默认使用<code>ICMP</code>协议发起<code>TraceRoute</code>请求，该协议同时支持<code>IPv4</code>和<code>IPv6</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># IPv4 ICMP Trace</span></span><br><span class="line">nexttrace 1.0.0.1</span><br><span class="line"><span class="comment"># URL</span></span><br><span class="line">nexttrace http://example.com:8080/index.html?q=1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 表格打印，使用 --table / -t 参数，将实时显示结果</span></span><br><span class="line">nexttrace --table 1.0.0.1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 一个方便供机器读取转化的模式</span></span><br><span class="line">nexttrace --raw 1.0.0.1</span><br><span class="line">nexttrace --json 1.0.0.1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 只进行IPv4/IPv6解析，且当多个IP时自动选择第一个IP</span></span><br><span class="line">nexttrace --ipv4 g.co</span><br><span class="line">nexttrace --ipv6 g.co</span><br><span class="line"></span><br><span class="line"><span class="comment"># IPv6 ICMP Trace</span></span><br><span class="line">nexttrace 2606:4700:4700::1111</span><br><span class="line"></span><br><span class="line"><span class="comment"># 禁用路径可视化 使用 --map / -M 参数</span></span><br><span class="line">nexttrace koreacentral.blob.core.windows.net</span><br><span class="line"><span class="comment"># MapTrace URL: https://api.nxtrace.org/tracemap/html/c14e439e-3250-5310-8965-42a1e3545266.html</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 禁用MPLS显示 使用 --disable-mpls / -e 参数 或 NEXTTRACE_DISABLEMPLS 环境变量</span></span><br><span class="line">nexttrace --disable-mpls example.com</span><br><span class="line"><span class="built_in">export</span> NEXTTRACE_DISABLEMPLS=1</span><br></pre></td></tr></table></figure><p>PS: 路由可视化的绘制模块由 <a href="https://github.com/tsosunchia">@tsosunchia</a> 同学编写，具体代码可在 <a href="https://github.com/tsosunchia/traceMap">tsosunchia&#x2F;traceMap</a> 查看</p><p>需要注意的是，在 LeoMoeAPI 2.0 中，由于新增了了地理位置数据，<strong>我们已经弃用 traceMap 插件中 OpenStreetMap API 的在线查询的部分，并且使用自己数据库内的位置信息</strong>。</p><p>路由可视化功能因为需要每个 Hop 的地理位置坐标，而第三方 API 通常不提供此类信息，所以此功能目前只支持搭配 LeoMoeAPI 使用。</p><p><code>NextTrace</code> 现已经支持快速测试，有一次性测试回程路由需求的朋友可以使用</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 北上广（电信+联通+移动+教育网）IPv4 / IPv6 ICMP 快速测试</span></span><br><span class="line">nexttrace --fast-trace</span><br><span class="line"></span><br><span class="line"><span class="comment"># 也可以使用 TCP SYN 而非 ICMP 进行测试</span></span><br><span class="line">nexttrace --fast-trace --tcp</span><br><span class="line"></span><br><span class="line"><span class="comment"># 也可以通过自定义的IP/DOMAIN列表文件进行快速测试</span></span><br><span class="line">nexttrace --file /path/to/your/iplist.txt</span><br><span class="line"><span class="comment"># 自定义的IP/DOMAIN列表文件格式</span></span><br><span class="line"><span class="comment">## 一行一个IP/DOMAIN + 空格 + 描述信息（可选）</span></span><br><span class="line"><span class="comment">## 例如：</span></span><br><span class="line"><span class="comment">## 106.37.67.1 北京电信</span></span><br><span class="line"><span class="comment">## 240e:928:101:31a::1 北京电信</span></span><br><span class="line"><span class="comment">## bj.10086.cn 北京移动</span></span><br><span class="line"><span class="comment">## 2409:8080:0:1::1</span></span><br><span class="line"><span class="comment">## 223.5.5.5</span></span><br></pre></td></tr></table></figure><p><code>NextTrace</code> 已支持指定网卡进行路由跟踪</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 请注意 Lite 版本此参数不能和快速测试联用，如有需要请使用 enhanced 版本</span></span><br><span class="line"><span class="comment"># 使用 eth0 网卡</span></span><br><span class="line">nexttrace --dev eth0 2606:4700:4700::1111</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用 eth0 网卡IP</span></span><br><span class="line"><span class="comment"># 网卡 IP 可以使用 ip a 或者 ifconfig 获取</span></span><br><span class="line"><span class="comment"># 使用网卡IP进行路由跟踪时需要注意跟踪的IP类型应该和网卡IP类型一致（如都为 IPv4）</span></span><br><span class="line">nexttrace --<span class="built_in">source</span> 204.98.134.56 9.9.9.9</span><br></pre></td></tr></table></figure><p><code>NextTrace</code> 也可以使用<code>TCP</code>和<code>UDP</code>协议发起<code>Traceroute</code>请求，不过目前<code>UDP</code>只支持<code>IPv4</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># TCP SYN Trace</span></span><br><span class="line">nexttrace --tcp www.bing.com</span><br><span class="line"></span><br><span class="line"><span class="comment"># 可以自行指定端口[此处为443]，默认80端口</span></span><br><span class="line">nexttrace --tcp --port 443 2001:4860:4860::8888</span><br><span class="line"></span><br><span class="line"><span class="comment"># UDP Trace</span></span><br><span class="line">nexttrace --udp 1.0.0.1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 可以自行指定端口[此处为5353]，默认33494端口</span></span><br><span class="line">nexttrace --udp --port 5353 1.0.0.1</span><br></pre></td></tr></table></figure><p><code>NextTrace</code>也同样支持一些进阶功能，如 TTL 控制、并发数控制、模式切换等</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 每一跳发送2个探测包</span></span><br><span class="line">nexttrace --queries 2 www.hkix.net</span><br><span class="line"></span><br><span class="line"><span class="comment"># 无并发，每次只发送一个探测包</span></span><br><span class="line">nexttrace --parallel-requests 1 www.hkix.net</span><br><span class="line"></span><br><span class="line"><span class="comment"># 从TTL为5开始发送探测包，直到TTL为10结束</span></span><br><span class="line">nexttrace --first 5 --max-hops 10 www.decix.net</span><br><span class="line"><span class="comment"># 此外还提供了一个ENV，可以设置是否隐匿目的IP</span></span><br><span class="line"><span class="built_in">export</span> NEXTTRACE_ENABLEHIDDENDSTIP=1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 关闭IP反向解析功能</span></span><br><span class="line">nexttrace --no-rdns www.bbix.net</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置载荷大小为1024字节</span></span><br><span class="line">nexttrace --psize 1024 example.com</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置载荷大小以及DF标志进行TCP Trace</span></span><br><span class="line">nexttrace --psize 1024 --dont-fragment --tcp example.com</span><br><span class="line"></span><br><span class="line"><span class="comment"># 特色功能：打印Route-Path图</span></span><br><span class="line"><span class="comment"># Route-Path图示例：</span></span><br><span class="line"><span class="comment"># AS6453 塔塔通信「Singapore『Singapore』」</span></span><br><span class="line"><span class="comment">#  ╭╯</span></span><br><span class="line"><span class="comment">#  ╰AS9299 Philippine Long Distance Telephone Co.「Philippines『Metro Manila』」</span></span><br><span class="line"><span class="comment">#  ╭╯</span></span><br><span class="line"><span class="comment">#  ╰AS36776 Five9 Inc.「Philippines『Metro Manila』」</span></span><br><span class="line"><span class="comment">#  ╭╯</span></span><br><span class="line"><span class="comment">#  ╰AS37963 阿里云「ALIDNS.COM『ALIDNS.COM』」</span></span><br><span class="line">nexttrace --route-path www.time.com.my</span><br><span class="line"><span class="comment"># 禁止色彩输出</span></span><br><span class="line">nexttrace --nocolor 1.1.1.1</span><br><span class="line"><span class="comment"># 或者使用环境变量</span></span><br><span class="line"><span class="built_in">export</span> NO_COLOR=1</span><br></pre></td></tr></table></figure><p><code>NextTrace</code>支持用户自主选择 IP 数据库（目前支持：<code>LeoMoeAPI</code>, <code>IP.SB</code>, <code>IPInfo</code>, <code>IPInsight</code>, <code>IPAPI.com</code>, <code>Ip2region</code>, <code>IPInfoLocal</code>, <code>CHUNZHEN</code>)</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 可以自行指定IP数据库[此处为IP-API.com]，不指定则默认为LeoMoeAPI</span></span><br><span class="line">nexttrace --data-provider ip-api.com</span><br><span class="line"><span class="comment">## 特别的: 其中 ipinfo 和 IPInsight API 对于免费版查询有频率限制，可从这些服务商自行购买服务以解除限制，如有需要可以 clone 本项目添加其提供的 token 自行编译</span></span><br><span class="line"><span class="comment">##        TOKEN填写路径：ipgeo/tokens.go</span></span><br><span class="line"><span class="comment">## 特别的: 对于离线库 IPInfoLocal，请自行下载并命名为 ipinfoLocal.mmdb (可以从这里下载：https://ipinfo.io/signup?ref=free-database-downloads)</span></span><br><span class="line"><span class="comment">##        对于离线库 Ip2region 可NextTrace自动下载，也可自行下载并命名为 ip2region.db</span></span><br><span class="line"><span class="comment">## 另外：由于IP.SB被滥用比较严重，会经常出现无法查询的问题，请知悉。</span></span><br><span class="line"><span class="comment">##      IP-API.com限制调用较为严格，如有查询不到的情况，请几分钟后再试。</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 纯真IP数据库默认使用 http://127.0.0.1:2060 作为查询接口，如需自定义请使用环境变量</span></span><br><span class="line"><span class="built_in">export</span> NEXTTRACE_CHUNZHENURL=http://127.0.0.1:2060</span><br><span class="line"><span class="comment">## 可使用 https://github.com/freshcn/qqwry 自行搭建纯真IP数据库服务</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 也可以通过设置环境变量来指定默认IP数据库</span></span><br><span class="line"><span class="built_in">export</span> NEXTTRACE_DATAPROVIDER=ipinfo</span><br></pre></td></tr></table></figure><p><code>NextTrace</code>支持使用混合参数和简略参数</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Example:</span><br><span class="line">nexttrace --data-provider ip-api.com --max-hops 20 --tcp --port 443 --queries 5 --no-rdns 1.1.1.1</span><br><span class="line">nexttrace -tcp --queries 2 --parallel-requests 1 --table --route-path 2001:4860:4860::8888</span><br><span class="line"></span><br><span class="line">Equivalent to:</span><br><span class="line">nexttrace -d ip-api.com -m 20 -T -p 443 -q 5 -n 1.1.1.1</span><br><span class="line">nexttrace -T -q 2 --parallel-requests 1 -t -P 2001:4860:4860::8888</span><br></pre></td></tr></table></figure><h3 id="全部用法详见-Usage-菜单"><a href="#全部用法详见-Usage-菜单" class="headerlink" title="全部用法详见 Usage 菜单"></a>全部用法详见 Usage 菜单</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line">Usage: nexttrace [-h|--help] [-4|--ipv4] [-6|--ipv6] [-T|--tcp] [-U|--udp]</span><br><span class="line">                 [-F|--fast-trace] [-p|--port &lt;integer&gt;] [-q|--queries</span><br><span class="line">                 &lt;integer&gt;] [--parallel-requests &lt;integer&gt;] [-m|--max-hops</span><br><span class="line">                 &lt;integer&gt;] [-d|--data-provider</span><br><span class="line">                 (Ip2region|ip2region|IP.SB|ip.sb|IPInfo|ipinfo|IPInsight|ipinsight|IPAPI.com|ip-api.com|IPInfoLocal|ipinfolocal|chunzhen|LeoMoeAPI|leomoeapi|disable-geoip)]</span><br><span class="line">                 [--pow-provider (api.nxtrace.org|sakura)] [-n|--no-rdns]</span><br><span class="line">                 [-a|--always-rdns] [-P|--route-path] [-r|--report] [--dn42]</span><br><span class="line">                 [-o|--output] [-t|--table] [--raw] [-j|--json] [-c|--classic]</span><br><span class="line">                 [-f|--first &lt;integer&gt;] [-M|--map] [-e|--disable-mpls]</span><br><span class="line">                 [-v|--version] [-s|--source &quot;&lt;value&gt;&quot;] [-D|--dev &quot;&lt;value&gt;&quot;]</span><br><span class="line">                 [-z|--send-time &lt;integer&gt;] [-i|--ttl-time &lt;integer&gt;]</span><br><span class="line">                 [--timeout &lt;integer&gt;] [--psize &lt;integer&gt;]</span><br><span class="line">                 [_positionalArg_nexttrace_32 &quot;&lt;value&gt;&quot;] [--dot-server</span><br><span class="line">                 (dnssb|aliyun|dnspod|google|cloudflare)] [-g|--language</span><br><span class="line">                 (en|cn)] [--file &quot;&lt;value&gt;&quot;] [-C|--nocolor]</span><br><span class="line"></span><br><span class="line">Arguments:</span><br><span class="line"></span><br><span class="line">  -h  --help                         Print help information</span><br><span class="line">  -4  --ipv4                         Use IPv4 only</span><br><span class="line">  -6  --ipv6                         Use IPv6 only</span><br><span class="line">  -T  --tcp                          Use TCP SYN for tracerouting (default port</span><br><span class="line">                                     is 80)</span><br><span class="line">  -U  --udp                          Use UDP SYN for tracerouting (default port</span><br><span class="line">                                     is 33494)</span><br><span class="line">  -F  --fast-trace                   One-Key Fast Trace to China ISPs</span><br><span class="line">  -p  --port                         Set the destination port to use. With</span><br><span class="line">                                     default of 80 for &quot;tcp&quot;, 33494 for &quot;udp&quot;</span><br><span class="line">  -q  --queries                      Set the number of probes per each hop.</span><br><span class="line">                                     Default: 3</span><br><span class="line">      --parallel-requests            Set ParallelRequests number. It should be</span><br><span class="line">                                     1 when there is a multi-routing. Default:</span><br><span class="line">                                     18</span><br><span class="line">  -m  --max-hops                     Set the max number of hops (max TTL to be</span><br><span class="line">                                     reached). Default: 30</span><br><span class="line">  -d  --data-provider                Choose IP Geograph Data Provider [IP.SB,</span><br><span class="line">                                     IPInfo, IPInsight, IP-API.com, Ip2region,</span><br><span class="line">                                     IPInfoLocal, CHUNZHEN, disable-geoip].</span><br><span class="line">                                     Default: LeoMoeAPI</span><br><span class="line">      --pow-provider                 Choose PoW Provider [api.nxtrace.org,</span><br><span class="line">                                     sakura] For China mainland users, please</span><br><span class="line">                                     use sakura. Default: api.nxtrace.org</span><br><span class="line">  -n  --no-rdns                      Do not resolve IP addresses to their</span><br><span class="line">                                     domain names</span><br><span class="line">  -a  --always-rdns                  Always resolve IP addresses to their</span><br><span class="line">                                     domain names</span><br><span class="line">  -P  --route-path                   Print traceroute hop path by ASN and</span><br><span class="line">                                     location</span><br><span class="line">  -r  --report                       output using report mode</span><br><span class="line">      --dn42                         DN42 Mode</span><br><span class="line">  -o  --output                       Write trace result to file</span><br><span class="line">                                     (RealTimePrinter ONLY)</span><br><span class="line">  -t  --table                        Output trace results as table</span><br><span class="line">      --raw                          An Output Easy to Parse</span><br><span class="line">  -j  --json                         Output trace results as JSON</span><br><span class="line">  -c  --classic                      Classic Output trace results like</span><br><span class="line">                                     BestTrace</span><br><span class="line">  -f  --first                        Start from the first_ttl hop (instead from</span><br><span class="line">                                     1). Default: 1</span><br><span class="line">  -M  --map                          Disable Print Trace Map</span><br><span class="line">  -e  --disable-mpls                 Disable MPLS</span><br><span class="line">  -v  --version                      Print version info and exit</span><br><span class="line">  -s  --source                       Use source src_addr for outgoing packets</span><br><span class="line">  -D  --dev                          Use the following Network Devices as the</span><br><span class="line">                                     source address in outgoing packets</span><br><span class="line">  -z  --send-time                    Set how many [milliseconds] between</span><br><span class="line">                                     sending each packet.. Useful when some</span><br><span class="line">                                     routers use rate-limit for ICMP messages.</span><br><span class="line">                                     Default: 50</span><br><span class="line">  -i  --ttl-time                     Set how many [milliseconds] between</span><br><span class="line">                                     sending packets groups by TTL. Useful when</span><br><span class="line">                                     some routers use rate-limit for ICMP</span><br><span class="line">                                     messages. Default: 50</span><br><span class="line">      --timeout                      The number of [milliseconds] to keep probe</span><br><span class="line">                                     sockets open before giving up on the</span><br><span class="line">                                     connection.. Default: 1000</span><br><span class="line">      --psize                        Set the payload size. Default: 52</span><br><span class="line">      --_positionalArg_nexttrace_32  IP Address or domain name</span><br><span class="line">      --dot-server                   Use DoT Server for DNS Parse [dnssb,</span><br><span class="line">                                     aliyun, dnspod, google, cloudflare]</span><br><span class="line">  -g  --language                     Choose the language for displaying [en,</span><br><span class="line">                                     cn]. Default: cn</span><br><span class="line">      --file                         Read IP Address or domain name from file</span><br><span class="line">  -C  --nocolor                      Disable Colorful Output</span><br><span class="line">      --dont-fragment                Set the Don&#x27;t Fragment bit (IPv4 TCP</span><br><span class="line">                                     only). Default: false</span><br></pre></td></tr></table></figure><h2 id="项目截图"><a href="#项目截图" class="headerlink" title="项目截图"></a>项目截图</h2><p><img src="https://img.nnu.cn/p/669b4799787d7.webp" alt="image"></p><p><img src="https://img.nnu.cn/p/669b47baf1906.webp"></p><h2 id="第三方-IP-数据库-API-开发接口"><a href="#第三方-IP-数据库-API-开发接口" class="headerlink" title="第三方 IP 数据库 API 开发接口"></a>第三方 IP 数据库 API 开发接口</h2><p>NextTrace 所有的的 IP 地理位置 <code>API DEMO</code> 可以参考<a href="https://github.com/nxtrace/NTrace-core/blob/main/ipgeo/">这里</a></p><p>你可以在这里添加你自己的 API 接口，为了 NextTrace 能够正确显示你接口中的内容，请参考 <code>leo.go</code> 中所需要的信息</p><p>✨NextTrace <code>LeoMoeAPI</code> 的后端 Demo</p><p><a href="https://github.com/sjlleo/nexttrace-backend">GitHub - sjlleo&#x2F;nexttrace-backend: NextTrace BackEnd</a></p><p>NextTrace <code>LeoMoeAPI</code>现已使用Proof of Work(POW)机制来防止滥用，其中NextTrace作为客户端引入了powclient库，POW CLIENT&#x2F;SERVER均已开源，欢迎大家使用。(POW模块相关问题请发到对应的仓库)</p><ul><li><a href="https://github.com/tsosunchia/powclient">GitHub - tsosunchia&#x2F;powclient: Proof of Work CLIENT for NextTrace</a></li><li><a href="https://github.com/tsosunchia/powserver">GitHub - tsosunchia&#x2F;powserver: Proof of Work SERVER for NextTrace</a></li></ul><p>对于中国大陆用户，可以使用 <a href="https://natfrp.com/">Nya Labs</a> 提供的位于大陆的POW服务器优化访问速度</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">使用方法任选其一</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">1. 在环境变量中设置</span></span><br><span class="line">export NEXTTRACE_POWPROVIDER=sakura</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">2. 在命令行中设置</span></span><br><span class="line">nexttrace --pow-provider sakura</span><br></pre></td></tr></table></figure>]]></content>
      
      
      <categories>
          
          <category> 网络 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 开源项目 </tag>
            
            <tag> 工具 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>一块硬盘显示红色PD Missing解决办法</title>
      <link href="/post/40e36b33.html"/>
      <url>/post/40e36b33.html</url>
      
        <content type="html"><![CDATA[<h3 id="一块硬盘显示红色PD-Missing解决办法"><a href="#一块硬盘显示红色PD-Missing解决办法" class="headerlink" title="一块硬盘显示红色PD Missing解决办法"></a>一块硬盘显示红色PD Missing解决办法</h3><p>服务器通过Raid技术可以有效增强数据的安全性，但是不代表做了Raid就永远不会出问题，所以数据还是要经常备份的。一般我们最常遇到的问题就是有硬盘亮红灯了，有些时候还会有报警声。但是请不要担心，硬盘亮红灯不代表硬盘一定有故障，需要进入WebBIOS主页查看。</p><h4 id="步骤："><a href="#步骤：" class="headerlink" title="步骤："></a>步骤：</h4><ol><li><strong>进入WebBIOS主页</strong><ul><li>发现一块硬盘显示红色PD Missing状态，同时阵列降级变成了蓝色Degraded状态，此时数据还是可用的，点击【Physical View】进入物理视图。<br><img src="https://img.nnu.cn/p/668ca8895cef5.webp"></li></ul></li><li><strong>查看硬盘状态</strong><ul><li>发现一块黑色硬盘显示Foreign Unconfigured Bad状态，选中该硬盘进入属性页面。<br><img src="https://img.nnu.cn/p/668ca8b4432c9.webp"></li></ul></li><li><strong>检查硬盘属性</strong><ul><li>在属性列表中找到“Media Error”和“Pred Fail Count”两项（如果找不到请点击【Next】翻页），两项都是零，说明硬盘无故障，可以放心使用。<br><img src="https://img.nnu.cn/p/668ca8c9e8d8a.webp"></li></ul></li><li><strong>清除外来配置</strong><ul><li>通过Clear Foreign Configuration，可以解决此问题。<br><img src="https://img.nnu.cn/p/668ca8d5c935a.webp"></li></ul></li><li><strong>更改硬盘状态</strong><ul><li>选择【Make Unconf Good】，点击【GO】执行。<br><img src="https://img.nnu.cn/p/668ca8ebbe435.webp"></li></ul></li><li><strong>返回首页</strong><ul><li>点击【Home】返回首页。<br><img src="https://img.nnu.cn/p/668ca8f96bd18.webp"></li></ul></li><li><strong>扫描设备</strong><ul><li>出现一块蓝色硬盘显示Foreign Unconfigured Good状态，点击【Scan Devices】。<br><img src="https://img.nnu.cn/p/668ca903a1b92.webp"></li></ul></li><li><strong>清除外来配置信息</strong><ul><li>提示发现外来配置信息，选择【Clear】清除。</li><li>提示清除，选择【Yes】。<br><img src="https://img.nnu.cn/p/668ca90e80eda.webp"></li></ul></li><li><strong>重建状态</strong><ul><li>回到WebBIOS主页，报错硬盘现在变成了褐色Rebuild状态。如果您着急使用，请点击【Exit】退出，然后【Ctrl-Alt-Delete】组合键重启服务器，同步过程可以后台进行。建议等同步完成再使用，查看同步进度请点击左下角【PD Progress Info】。<br><img src="https://img.nnu.cn/p/668ca918cafe0.webp"></li></ul></li><li><strong>查看同步进度</strong><ul><li>查看同步进度。<br><img src="https://img.nnu.cn/p/668ca92236f6e.webp"></li></ul></li></ol>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 服务器 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>三十秒让Windwos11右键菜单变回旧版</title>
      <link href="/post/1956cdb5.html"/>
      <url>/post/1956cdb5.html</url>
      
        <content type="html"><![CDATA[<p>将以下内容新建为文本文件，保存后将扩展名改为 <code>.bat</code>，运行即可将 Windows 11 右键菜单恢复成传统模式。</p><h2 id="批处理文件内容"><a href="#批处理文件内容" class="headerlink" title="批处理文件内容"></a>批处理文件内容</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">@echo off</span><br><span class="line">reg.exe add &quot;HKCU\Software\Classes\CLSID\&#123;86ca1aa0-34aa-4e8b-a509-50c905bae2a2&#125;\InprocServer32&quot; /f /ve</span><br><span class="line">taskkill /f /im explorer.exe &amp; start explorer.exe</span><br></pre></td></tr></table></figure>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 系统 </tag>
            
            <tag> 菜单 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>使用Windows内置的DISKPART命令（Windows7及以上版本）</title>
      <link href="/post/b586193b.html"/>
      <url>/post/b586193b.html</url>
      
        <content type="html"><![CDATA[<h3 id="使用Windows内置命令给硬盘写保护"><a href="#使用Windows内置命令给硬盘写保护" class="headerlink" title="使用Windows内置命令给硬盘写保护"></a>使用Windows内置命令给硬盘写保护</h3><p>在Windows系统中，可以使用内置的diskpart命令对硬盘进行写保护设置。以下是详细过程：</p><h4 id="步骤："><a href="#步骤：" class="headerlink" title="步骤："></a>步骤：</h4><ol><li><p><strong>打开diskpart</strong></p><ul><li>按下 <code>Windows键+R</code> 打开运行窗口。</li><li>输入 <code>diskpart</code> 并按回车。<br><img src="https://img.nnu.cn/p/668cbceb9ba77.webp"></li></ul></li><li><p><strong>列出所有磁盘</strong></p><ul><li>在diskpart命令行下输入：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">list vol</span><br></pre></td></tr></table></figure></li><li>这样可以列举出所有磁盘。<br><img src="https://img.nnu.cn/p/668cbd05daa35.webp"></li></ul></li><li><p><strong>选择要设写保护的磁盘</strong></p><ul><li>假设要设写保护的磁盘的第一个分区是D，用命令选中磁盘：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select vol D</span><br></pre></td></tr></table></figure></li></ul></li><li><p><strong>设置写保护</strong></p><ul><li>用下面的命令设置写保护：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">att vol set readonly</span><br></pre></td></tr></table></figure></li></ul></li></ol><h4 id="移除写保护"><a href="#移除写保护" class="headerlink" title="移除写保护"></a>移除写保护</h4><p>知道如何设置写保护后，还需要知道如何去除写保护。请使用以下命令：</p><ol><li><p><strong>选择要取消写保护的磁盘</strong></p><ul><li>在diskpart下输入：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select vol H</span><br></pre></td></tr></table></figure></li></ul></li><li><p><strong>清除写保护</strong></p><ul><li>输入以下命令清除写保护：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">att vol clear readonly</span><br></pre></td></tr></table></figure></li></ul></li></ol><h4 id="拓展：更多命令使用说明"><a href="#拓展：更多命令使用说明" class="headerlink" title="拓展：更多命令使用说明"></a>拓展：更多命令使用说明</h4><ul><li><strong>ACTIVE</strong> – 将选中的分区标记为活动的分区。</li><li><strong>ADD</strong> – 将镜像添加到一个简单卷。</li><li><strong>ASSIGN</strong> – 给所选卷分配一个驱动器号或装载点。</li><li><strong>ATTRIBUTES</strong> – 操纵卷或磁盘属性。</li><li><strong>ATTACH</strong> – 连接虚拟磁盘文件。</li><li><strong>AUTOMOUNT</strong> – 启用和禁用基本卷的自动装载。</li><li><strong>BREAK</strong> – 中断镜像集。</li><li><strong>CLEAN</strong> – 从磁盘清除配置信息或所有信息。</li><li><strong>COMPACT</strong> – 尝试减少文件的物理大小。</li><li><strong>CONVERT</strong> – 在不同的磁盘格式之间转换。</li><li><strong>CREATE</strong> – 创建卷、分区或虚拟磁盘。</li><li><strong>DELETE</strong> – 删除对象。</li><li><strong>DETAIL</strong> – 提供对象详细信息。</li><li><strong>DETACH</strong> – 分离虚拟磁盘文件。</li><li><strong>EXIT</strong> – 退出 DiskPart。</li><li><strong>EXTEND</strong> – 扩展卷。</li><li><strong>EXPAND</strong> – 扩展虚拟磁盘上可用的最大大小。</li><li><strong>FILESYSTEMS</strong> – 显示卷上当前和支持的文件系统。</li><li><strong>FORMAT</strong> – 格式化卷或分区。</li><li><strong>GPT</strong> – 给选择的 GPT 分区分配属性。</li><li><strong>HELP</strong> – 显示命令列表。</li><li><strong>IMPORT</strong> – 导入磁盘组。</li><li><strong>INACTIVE</strong> – 将所选分区标为不活动。</li><li><strong>LIST</strong> – 显示对象列表。</li><li><strong>MERGE</strong> – 将子磁盘与其父磁盘合并。</li><li><strong>ONLINE</strong> – 使当前标为脱机的对象联机。</li><li><strong>OFFLINE</strong> – 使当前标记为联机的对象脱机。</li><li><strong>RECOVER</strong> – 刷新所选包中所有磁盘的状态。尝试恢复无效包中的磁盘，并重新同步具有过时从或奇偶校验数据的镜像卷和 RAID5 卷。</li><li><strong>REM</strong> – 不起任何作用。用来注释脚本。</li><li><strong>REMOVE</strong> – 删除驱动器号或装载点分配。</li><li><strong>REPAIR</strong> – 用失败的成员修复一个 RAID-5 卷。</li><li><strong>RESCAN</strong> – 重新扫描计算机，查找磁盘和卷。</li><li><strong>RETAIN</strong> – 在一个简单卷下放置一个保留分区。</li><li><strong>SAN</strong> – 显示或设置当前启动的操作系统的 SAN 策略。</li><li><strong>SELECT</strong> – 将焦点移动到对象。</li><li><strong>SETID</strong> – 更改分区类型。</li><li><strong>SHRINK</strong> – 减小选定卷。</li><li><strong>UNIQUEID</strong> – 显示或设置磁盘的 GUID 分区表(GPT)标识符或主启动记录(MBR)签名。</li></ul><p>只需要输入对应的命令按 <code>？</code> 即可查看命令的用法说明。</p>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 系统 </tag>
            
            <tag> 还原 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>利用Github Actions 实现自动构建内置服务器和key和API服务的Rustdesk客户端教程</title>
      <link href="/post/e7df69f.html"/>
      <url>/post/e7df69f.html</url>
      
        <content type="html"><![CDATA[<h1 id="利用Github-Actions-实现自动构建内置服务器和key和API服务的Rustdesk客户端教程"><a href="#利用Github-Actions-实现自动构建内置服务器和key和API服务的Rustdesk客户端教程" class="headerlink" title="利用Github Actions 实现自动构建内置服务器和key和API服务的Rustdesk客户端教程"></a>利用Github Actions 实现自动构建内置服务器和key和API服务的Rustdesk客户端教程</h1><p>RustDesk 是一个开源的远程桌面应用，允许用户自建服务器，以替代 TeamViewer 等远程控制软件。为了方便自建服务的用户快速使用Rustdesk，构建内置自己服务器和key的RustDesk 客户端便成为了广大互联网爱好者的需求。</p><p>默认情况下，RustDesk 依赖 hbb_common 作为其基础库，并默认连接到官方服务器。如果你希望使用自己的服务器，则需要修改 hbb_common 代码并让 rustdesk 指向你修改后的 hbb_common 仓库。</p><p>本教程将介绍如何利用Github Actions 实现自动构建内置你服务器和key的Rustdesk客户端。</p><h2 id="1-准备工作"><a href="#1-准备工作" class="headerlink" title="1. 准备工作"></a>1. 准备工作</h2><p>在开始之前，请确保你已经安装了 Git，并且拥有一个 GitHub 账户。建议你对 Git 的基本使用有一定了解，以便顺利完成后续操作。</p><h2 id="2-Fork-Rustdesk仓库"><a href="#2-Fork-Rustdesk仓库" class="headerlink" title="2. Fork Rustdesk仓库"></a>2. Fork Rustdesk仓库</h2><ul><li>rustdesk&#x2F;hbb_common</li><li>rustdesk&#x2F;rustdesk</li></ul><h3 id="2-1-拉取-Fork-后的代码"><a href="#2-1-拉取-Fork-后的代码" class="headerlink" title="2.1 拉取 Fork 后的代码"></a>2.1 拉取 Fork 后的代码</h3><p>请注意，替换仓库地址为你fork后的仓库地址，而不是直接复制我下面的命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 可选：如果需要使用代理</span></span><br><span class="line"><span class="comment"># git config --global http.proxy http://127.0.0.1:10808</span></span><br><span class="line"><span class="comment"># git config --global https.proxy http://127.0.0.1:10808</span></span><br><span class="line"><span class="comment"># 拉取仓库代码到本地 请替换为你fork后的仓库地址</span></span><br><span class="line">git <span class="built_in">clone</span> https://github.com/用户名/hbb_common.git</span><br><span class="line">git <span class="built_in">clone</span> https://github.com/用户名/rustdesk.git</span><br></pre></td></tr></table></figure><p><img src="https://img.nnu.cn/p/67efe93a1907f.webp"></p><h2 id="3-修改-hbb-common代码"><a href="#3-修改-hbb-common代码" class="headerlink" title="3. 修改 hbb_common代码"></a>3. 修改 hbb_common代码</h2><p>打开 hbb_common 仓库下的 src&#x2F;config.rs文件，修改 101-102 行 的默认服务器和密钥为你自己的服务器和密钥。<br><img src="https://img.nnu.cn/p/67efe954200b8.webp"></p><h3 id="3-1-推送修改后的代码"><a href="#3-1-推送修改后的代码" class="headerlink" title="3.1 推送修改后的代码"></a>3.1 推送修改后的代码</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 将修改的代码添加到暂存区</span></span><br><span class="line">git add.</span><br><span class="line"><span class="comment"># 将代码提交到本地仓库</span></span><br><span class="line">git commit -m <span class="string">&quot;修改默认的服务器和 key&quot;</span></span><br><span class="line"><span class="comment"># 将本地仓库代码推送到远程仓库 如果你没有登录过GitHub会要求你登录github</span></span><br><span class="line">git push</span><br></pre></td></tr></table></figure><h3 id="3-2-查看最新提交的-commit-ID"><a href="#3-2-查看最新提交的-commit-ID" class="headerlink" title="3.2 查看最新提交的 commit ID"></a>3.2 查看最新提交的 commit ID</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span> --oneline</span><br></pre></td></tr></table></figure><p>我这里提交后的commit id是b8d80ca，可用于后续验证rustdesk服务器和key是否修改成功。<br><img src="https://img.nnu.cn/p/67efe962c2096.webp"></p><h2 id="4-修改-rustdesk-仓库代码"><a href="#4-修改-rustdesk-仓库代码" class="headerlink" title="4. 修改 rustdesk 仓库代码"></a>4. 修改 rustdesk 仓库代码</h2><p>我们切换到克隆下来的rustdesk代码目录下，按照下面的方式修改子模块地址并更新。</p><h3 id="4-1-更新-gitmodules"><a href="#4-1-更新-gitmodules" class="headerlink" title="4.1 更新 .gitmodules"></a>4.1 更新 .gitmodules</h3><p>打开并编辑 .gitmodules 文件，将 url 替换为你Fork后的 hbb_common 仓库地址。</p><p>比如fork后的仓库地址是<a href="https://github.com/test/hbb_common">https://github.com/test/hbb_common</a> 则将 <a href="https://github.com/rustdesk/hbb_common%E5%9C%B0%E5%9D%80%E6%8D%A2%E4%B8%BA%E5%89%8D%E9%9D%A2%E8%BF%99%E4%B8%AA%E5%9C%B0%E5%9D%80%E5%8D%B3%E5%8F%AF%EF%BC%8C%E8%AE%B0%E4%BD%8F%E6%98%AFhbb_common%E7%9A%84%E5%9C%B0%E5%9D%80%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AFrustdesk%E4%BB%93%E5%BA%93%E7%9A%84%E5%9C%B0%E5%9D%80%E3%80%82">https://github.com/rustdesk/hbb_common地址换为前面这个地址即可，记住是hbb_common的地址，而不是rustdesk仓库的地址。</a><br><img src="https://img.nnu.cn/p/67efe974a762f.webp"></p><h3 id="4-2-更新子模块"><a href="#4-2-更新子模块" class="headerlink" title="4.2 更新子模块"></a>4.2 更新子模块</h3><p>将上面修改好的代码保存，执行下面的命令更新子模块到最新的commit id：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git submodule init</span><br><span class="line">git submodule <span class="built_in">sync</span></span><br><span class="line">git submodule update --remote</span><br></pre></td></tr></table></figure><p><img src="https://img.nnu.cn/p/67efe97e1b0f8.webp"></p><h3 id="4-3-提交并推送代码"><a href="#4-3-提交并推送代码" class="headerlink" title="4.3 提交并推送代码"></a>4.3 提交并推送代码</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git add.</span><br><span class="line">git commit -m <span class="string">&quot;修改子模块仓库地址&quot;</span></span><br><span class="line">git push</span><br></pre></td></tr></table></figure><p><img src="https://img.nnu.cn/p/67efe986f1f2e.webp"></p><h3 id="4-4-确认-Commit-ID-更新"><a href="#4-4-确认-Commit-ID-更新" class="headerlink" title="4.4 确认 Commit ID 更新"></a>4.4 确认 Commit ID 更新</h3><p>代码推送完毕后，进入你Fork 后的 rustdesk 仓库的 libs 目录下，查看 hbb_common 后面的 commit id，确保它是3.2提到的b8d80ca（这个值每个人的是不同的），否则请回到上面的步骤重新检查是否遗漏了了某个操作。<br><img src="https://img.nnu.cn/p/67efe98d91ac2.webp"><br><img src="https://img.nnu.cn/p/67efe997c6a98.webp"></p><h2 id="4-5-修改-API-接口地址（需自建API服务，项目地址：https-github-com-lejianwen-rustdesk-api）"><a href="#4-5-修改-API-接口地址（需自建API服务，项目地址：https-github-com-lejianwen-rustdesk-api）" class="headerlink" title="4.5 修改 API 接口地址（需自建API服务，项目地址：https://github.com/lejianwen/rustdesk-api）"></a>4.5 修改 API 接口地址（需自建API服务，项目地址：<a href="https://github.com/lejianwen/rustdesk-api%EF%BC%89">https://github.com/lejianwen/rustdesk-api）</a></h2><p>打开 <code>rustdesk/src/common.rs</code> 文件，在第 947 行左右找到 API 接口地址的配置项，将其修改为你自己的 API 接口地址。修改完成后，按照以下步骤提交修改：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git add .</span><br><span class="line">git commit -m <span class="string">&quot;修改 API 接口地址&quot;</span></span><br><span class="line">git push</span><br></pre></td></tr></table></figure><p>另外API如果使用SSL协议反代，以下是配置信息：</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">80</span>;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">443</span> ssl http2;</span><br><span class="line">    <span class="attribute">listen</span> [::]:<span class="number">443</span> ssl http2;</span><br><span class="line">    <span class="attribute">listen</span> [::]:<span class="number">80</span>;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">server_name</span> xx.com;</span><br><span class="line">    <span class="attribute">index</span> index.php index.html index.htm default.php default.htm default.html;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">access_log</span> /www/sites/xx.com/log/access.log main;</span><br><span class="line">    <span class="attribute">error_log</span> /www/sites/xx.com/log/<span class="literal">error</span>.log;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">root</span> /usr/share/nginx/html/stop;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># SSL 证书</span></span><br><span class="line">    <span class="attribute">ssl_certificate</span> /www/sites/xx.com/ssl/fullchain.pem;</span><br><span class="line">    <span class="attribute">ssl_certificate_key</span> /www/sites/xx.com/ssl/privkey.pem;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">ssl_protocols</span> TLSv1.<span class="number">3</span> TLSv1.<span class="number">2</span> TLSv1.<span class="number">1</span> TLSv1;</span><br><span class="line">    <span class="attribute">ssl_ciphers</span> ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED;</span><br><span class="line">    <span class="attribute">ssl_prefer_server_ciphers</span> <span class="literal">on</span>;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">ssl_session_cache</span> shared:SSL:<span class="number">10m</span>;</span><br><span class="line">    <span class="attribute">ssl_session_timeout</span> <span class="number">10m</span>;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">add_header</span> Strict-Transport-Security <span class="string">&quot;max-age=31536000&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># HTTP 强制跳转 HTTPS</span></span><br><span class="line">    <span class="comment"># Let&#x27;s Encrypt 验证目录</span></span><br><span class="line">    <span class="section">location</span><span class="regexp"> ^~</span> /.well-known/acme-challenge &#123;</span><br><span class="line">        <span class="attribute">allow</span> all;</span><br><span class="line">        <span class="attribute">root</span> /usr/share/nginx/html;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># RustDesk WebSocket 代理（ID）</span></span><br><span class="line">    <span class="section">location</span> /ws/id &#123;</span><br><span class="line">        <span class="attribute">proxy_pass</span> http://127.0.0.1:21118;</span><br><span class="line">        <span class="attribute">proxy_http_version</span> <span class="number">1</span>.<span class="number">1</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Upgrade <span class="variable">$http_upgrade</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Connection <span class="string">&quot;Upgrade&quot;</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Host <span class="variable">$host</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Real-IP <span class="variable">$remote_addr</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-Proto <span class="variable">$scheme</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># RustDesk WebSocket 代理（Relay）</span></span><br><span class="line">    <span class="section">location</span> /ws/relay &#123;</span><br><span class="line">        <span class="attribute">proxy_pass</span> http://127.0.0.1:21119;</span><br><span class="line">        <span class="attribute">proxy_http_version</span> <span class="number">1</span>.<span class="number">1</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Upgrade <span class="variable">$http_upgrade</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Connection <span class="string">&quot;Upgrade&quot;</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Host <span class="variable">$host</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Real-IP <span class="variable">$remote_addr</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-Proto <span class="variable">$scheme</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">include</span> /www/sites/xx.com/proxy/<span class="regexp">*.conf</span>;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">error_page</span> <span class="number">497</span> https://<span class="variable">$host</span><span class="variable">$request_uri</span>;</span><br><span class="line">    <span class="attribute">proxy_set_header</span> X-Forwarded-Proto https;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">include</span> /www/sites/xx.com/proxy/<span class="regexp">*.conf</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">80</span>;</span><br><span class="line">    <span class="attribute">server_name</span> xx.xx.com;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">if</span> (<span class="variable">$host</span> = xx.xx.com) &#123;</span><br><span class="line">        <span class="attribute">return</span> <span class="number">301</span> https://<span class="variable">$host</span><span class="variable">$request_uri</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">return</span> <span class="number">404</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="5-触发-GitHub-Action-构建"><a href="#5-触发-GitHub-Action-构建" class="headerlink" title="5. 触发 GitHub Action 构建"></a>5. 触发 GitHub Action 构建</h2><h3 id="5-1-创建-Tag"><a href="#5-1-创建-Tag" class="headerlink" title="5.1 创建 Tag"></a>5.1 创建 Tag</h3><p>在本地 rustdesk 仓库中创建一个新 tag，例如 1.3.9，请使用 固定格式 (如 1.3.9 或 v1.3.9)，以便于自动匹配构建规则。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git tag -a 1.3.9 -m <span class="string">&quot;修改内置服务器和 key&quot;</span></span><br></pre></td></tr></table></figure><p><img src="https://img.nnu.cn/p/67efe9a117e39.webp"></p><h3 id="5-2-触发-GitHub-Actions-构建"><a href="#5-2-触发-GitHub-Actions-构建" class="headerlink" title="5.2 触发 GitHub Actions 构建"></a>5.2 触发 GitHub Actions 构建</h3><p>在 rustdesk 仓库中，进入 Actions 页面，点击下面图中的按钮启用自动构建。启用后回到本地rustdesk代码中使用下面的命令将tag推送到Github后将自动开始构建。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push --tags</span><br></pre></td></tr></table></figure><p><img src="https://img.nnu.cn/p/67efe9a9bc5e2.webp"></p><h3 id="5-3-下载构建好的客户端"><a href="#5-3-下载构建好的客户端" class="headerlink" title="5.3 下载构建好的客户端"></a>5.3 下载构建好的客户端</h3><p>Tag推送完毕后会出现下面的构建进度。<br><img src="https://img.nnu.cn/p/67efe9b1468b0.webp"></p><p>等待 Action 执行完成后（时间比较长，一个半小时左右才能全部构建完成），进入 Releases 页面，即可下载构建好的客户端并使用。<br><img src="https://img.nnu.cn/p/67efe9b8d04d1.webp"><br><img src="https://img.nnu.cn/p/67efea28df656.webp"></p>]]></content>
      
      
      <categories>
          
          <category> 笔记 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> rustdesk </tag>
            
            <tag> 远程工具 </tag>
            
            <tag> 客户但 </tag>
            
            <tag> 编程 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>使用哈希值配置Hexo永久url固定地址</title>
      <link href="/post/7632aacf.html"/>
      <url>/post/7632aacf.html</url>
      
        <content type="html"><![CDATA[<p>以下是具体步骤：</p><h3 id="1-安装-hexo-abbrlink-插件"><a href="#1-安装-hexo-abbrlink-插件" class="headerlink" title="1. 安装 hexo-abbrlink 插件"></a>1. 安装 <code>hexo-abbrlink</code> 插件</h3><p>首先，确保安装了 <code>hexo-abbrlink</code> 插件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-abbrlink --save</span><br></pre></td></tr></table></figure><h3 id="2-配置-Hexo-自动生成哈希值"><a href="#2-配置-Hexo-自动生成哈希值" class="headerlink" title="2.配置 Hexo 自动生成哈希值"></a>2.配置 Hexo 自动生成哈希值</h3><ol><li><p><strong>安装必要的模块</strong></p><p>如果还没有安装 <code>crc</code> 模块，请先安装：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install crc</span><br></pre></td></tr></table></figure></li><li><p><strong>创建 Hexo 插件脚本</strong></p><p>在 <code>scripts</code> 目录（如果没有，请创建一个）下创建一个新文件 <code>generate-crc32.js</code>，并将以下内容复制到该文件中：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> matter = <span class="built_in">require</span>(<span class="string">&#x27;gray-matter&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> crc32 = <span class="built_in">require</span>(<span class="string">&#x27;crc&#x27;</span>).<span class="property">crc32</span>;</span><br><span class="line"></span><br><span class="line">hexo.<span class="property">extend</span>.<span class="property">filter</span>.<span class="title function_">register</span>(<span class="string">&#x27;before_generate&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> postsDir = path.<span class="title function_">join</span>(hexo.<span class="property">source_dir</span>, <span class="string">&#x27;_posts&#x27;</span>);</span><br><span class="line"></span><br><span class="line">  fs.<span class="title function_">readdir</span>(postsDir, <span class="function">(<span class="params">err, files</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (err) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;Error reading posts directory:&#x27;</span>, err);</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    files.<span class="title function_">forEach</span>(<span class="function"><span class="params">file</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> filePath = path.<span class="title function_">join</span>(postsDir, file);</span><br><span class="line">      <span class="keyword">const</span> content = fs.<span class="title function_">readFileSync</span>(filePath, <span class="string">&#x27;utf8&#x27;</span>);</span><br><span class="line">      <span class="keyword">const</span> &#123; data, <span class="attr">content</span>: postContent &#125; = <span class="title function_">matter</span>(content);</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 生成 crc32 哈希值</span></span><br><span class="line">      <span class="keyword">const</span> hash = <span class="title function_">crc32</span>(data.<span class="property">title</span>).<span class="title function_">toString</span>(<span class="number">16</span>);</span><br><span class="line">      data.<span class="property">abbrlink</span> = hash;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">const</span> newContent = matter.<span class="title function_">stringify</span>(postContent, data);</span><br><span class="line">      fs.<span class="title function_">writeFileSync</span>(filePath, newContent, <span class="string">&#x27;utf8&#x27;</span>);</span><br><span class="line"></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Generated CRC32 for <span class="subst">$&#123;file&#125;</span>: <span class="subst">$&#123;hash&#125;</span>`</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li><li><p><strong>配置 <code>_config.yml</code></strong></p><p>在 Hexo 的 <code>_config.yml</code> 文件中添加或更新以下配置：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">abbrlink:</span></span><br><span class="line">  <span class="attr">alg:</span> <span class="string">crc32</span>  <span class="comment"># 使用 crc32 算法</span></span><br><span class="line">  <span class="attr">rep:</span> <span class="string">hex</span>    <span class="comment"># 生成的链接格式为 16 进制</span></span><br></pre></td></tr></table></figure><p>配置永久链接格式：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">permalink:</span> <span class="string">posts/:abbrlink.html</span></span><br></pre></td></tr></table></figure></li><li><p><strong>重新生成站点</strong></p><p>现在，每次运行 <code>hexo generate</code> 或 <code>hexo server</code> 时，Hexo 都会在生成内容之前自动执行脚本，生成并添加哈希值到文章的 <code>front-matter</code> 中。</p><p>运行以下命令来清理并重新生成站点：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hexo clean</span><br><span class="line">hexo generate</span><br></pre></td></tr></table></figure><p>然后部署：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo deploy</span><br></pre></td></tr></table></figure></li></ol>]]></content>
      
      
      <categories>
          
          <category> 笔记 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> HEXO </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>兄弟dcp7180dn墨粉盒清零步骤</title>
      <link href="/post/2487bfd.html"/>
      <url>/post/2487bfd.html</url>
      
        <content type="html"><![CDATA[<h3 id="兄弟DCP7180DN墨粉盒清零步骤"><a href="#兄弟DCP7180DN墨粉盒清零步骤" class="headerlink" title="兄弟DCP7180DN墨粉盒清零步骤"></a>兄弟DCP7180DN墨粉盒清零步骤</h3><ol><li><p><strong>打开打印机的前盖</strong><br><img src="https://img.nnu.cn/p/668b3e338e7f8.webp"></p></li><li><p><strong>按住“OK”按钮</strong></p><ul><li><p>持续按住“OK”按钮三到五秒钟，液晶显示屏将显示“更换硒鼓”。<br><img src="https://img.nnu.cn/p/668b3e5ac4aa5.webp"></p></li><li><p>如果需要对鼓架进行清零操作，根据提示操作。若对墨粉盒进行清零，继续下一步。</p></li></ul></li><li><p><strong>按下“启动”按钮</strong></p><ul><li>按下带有绿色徽标的“启动”按钮。</li></ul></li><li><p><strong>清除显示内容</strong></p><ul><li>按下“启动”按钮后，液晶显示屏上的内容将被清除，不显示任何内容。</li></ul></li><li><p><strong>调整数字显示</strong></p><ul><li>按“向上”或“+”按钮，显示屏将显示一个数字。继续按按钮，数字将增加直到显示“11”。</li><li>如果按多了，可以按“向下”或“-”按钮减少数字。</li></ul></li><li><p><strong>确认并复位</strong></p><ul><li>按“OK”按钮，液晶屏上将显示“接受”字样。</li><li>复位前盖，墨粉盒清零完成。</li></ul></li></ol>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 打印机 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>关于Microsoft 365企业版管理员二步验证丢失删除的方法</title>
      <link href="/post/1af6dd1d.html"/>
      <url>/post/1af6dd1d.html</url>
      
        <content type="html"><![CDATA[<h3 id="二步验证丢失原因是管理员更换手机后，Authenticator软件备份还原后发现Microsoft365的二步验证令牌丢失，导致输入密码后无法进行二步验证登录。管理员账号只有一个的情况下会导致无法自行删除二步验证。这种情况请按照以下方法进行快速处理。"><a href="#二步验证丢失原因是管理员更换手机后，Authenticator软件备份还原后发现Microsoft365的二步验证令牌丢失，导致输入密码后无法进行二步验证登录。管理员账号只有一个的情况下会导致无法自行删除二步验证。这种情况请按照以下方法进行快速处理。" class="headerlink" title="二步验证丢失原因是管理员更换手机后，Authenticator软件备份还原后发现Microsoft365的二步验证令牌丢失，导致输入密码后无法进行二步验证登录。管理员账号只有一个的情况下会导致无法自行删除二步验证。这种情况请按照以下方法进行快速处理。"></a>二步验证丢失原因是管理员更换手机后，Authenticator软件备份还原后发现Microsoft365的二步验证令牌丢失，导致输入密码后无法进行二步验证登录。管理员账号只有一个的情况下会导致无法自行删除二步验证。这种情况请按照以下方法进行快速处理。</h3><p>管理员登录卡在登录验证的界面</p><p><img src="https://img.nnu.cn/p/66aae774a12a5.webp"></p><p>这里需要联系Microsoft 365企业版支持团队。这里进行一个<a href="https://signup.microsoft.com/get-started/signup?products=7bb264e9-90b3-41b5-a0df-202db874ea3a&mproducts=CFQ7TTC0LFLX:0022&fmproducts=CFQ7TTC0LFLX:0022&culture=zh-cn&country=cn&ali=1">试用订阅</a> 按表单提交进入试用订阅后，点击右下角<strong>需要帮助</strong>按钮<br><img src="https://img.nnu.cn/p/66aae98898e16.webp"><br>输入二步验证丢失<br><img src="https://img.nnu.cn/p/66aae9aebb7d5.webp"><br>选择联系<strong>技术支持人员</strong><br><img src="https://img.nnu.cn/p/66aae9e080cda.webp"><br>按照表单提示填写问题信息，最后点击<strong>联系我</strong>等待官方恢复工单处理解决即可，一般工作日24小时内能处理完成。（注意：联系信息必须为丢失二步认证的辅助邮箱及手机号，用于验证管理员账户的所有权）</p>]]></content>
      
      
      <categories>
          
          <category> 笔记 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> Microsoft365 </tag>
            
            <tag> 两部验证 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>在iPad上使用Hexo并生成文章</title>
      <link href="/post/2cf432d4.html"/>
      <url>/post/2cf432d4.html</url>
      
        <content type="html"><![CDATA[<h3 id="所需工具"><a href="#所需工具" class="headerlink" title="所需工具"></a>所需工具</h3><ol><li><strong>应用程序</strong>：<ul><li><strong>iSH</strong>：一个Linux shell模拟器，可以运行大多数标准的Linux命令。</li><li><strong>Text Editor</strong>：例如Textastic、iA Writer或任何你喜欢的代码编辑器。</li><li><strong>Git客户端</strong>：例如Working Copy，用于将Hexo生成的静态文件推送到远程服务器（如GitHub Pages）。</li></ul></li></ol><h3 id="安装和配置Hexo"><a href="#安装和配置Hexo" class="headerlink" title="安装和配置Hexo"></a>安装和配置Hexo</h3><ol><li><p><strong>安装iSH并配置</strong>：</p><ul><li>从App Store安装iSH。</li><li>打开iSH，输入以下命令以更新包列表和安装Node.js、npm以及Git：<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">apk update</span><br><span class="line">apk add nodejs npm git</span><br></pre></td></tr></table></figure></li></ul></li><li><p><strong>安装Hexo</strong>：</p><ul><li>使用npm安装Hexo：<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g hexo-cli</span><br></pre></td></tr></table></figure></li></ul></li><li><p><strong>初始化Hexo项目</strong>：</p><ul><li>创建一个新的Hexo项目：<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">hexo init my-blog</span><br><span class="line"><span class="built_in">cd</span> my-blog</span><br><span class="line">npm install</span><br></pre></td></tr></table></figure></li></ul></li></ol><h3 id="创建和生成文章"><a href="#创建和生成文章" class="headerlink" title="创建和生成文章"></a>创建和生成文章</h3><ol><li><p><strong>创建新文章</strong>：</p><ul><li>在iSH中，使用以下命令创建新文章：<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo new <span class="string">&quot;My First Post&quot;</span></span><br></pre></td></tr></table></figure></li><li>这将在<code>source/_posts</code>目录下生成一个新的Markdown文件。</li></ul></li><li><p><strong>编辑文章</strong>：</p><ul><li>使用iSH中的<code>ls</code>命令找到新文章的Markdown文件路径，例如：<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> <span class="built_in">source</span>/_posts</span><br></pre></td></tr></table></figure></li><li>打开你的文本编辑器（例如Textastic）并编辑这个文件。</li></ul></li><li><p><strong>生成静态文件</strong>：</p><ul><li>在iSH中，使用以下命令生成静态文件：<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo generate</span><br></pre></td></tr></table></figure></li></ul></li></ol><h3 id="部署博客"><a href="#部署博客" class="headerlink" title="部署博客"></a>部署博客</h3><ol><li><p><strong>配置部署</strong>：</p><ul><li>编辑Hexo配置文件<code>_config.yml</code>，添加你的部署信息。例如，如果你使用GitHub Pages，配置如下：<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">deploy:</span></span><br><span class="line">  <span class="attr">type:</span> <span class="string">git</span></span><br><span class="line">  <span class="attr">repo:</span> <span class="string">https://github.com/yourusername/yourrepo.git</span></span><br><span class="line">  <span class="attr">branch:</span> <span class="string">gh-pages</span></span><br></pre></td></tr></table></figure></li></ul></li><li><p><strong>部署博客</strong>：</p><ul><li>使用以下命令部署你的博客：<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo deploy</span><br></pre></td></tr></table></figure></li><li>如果需要使用Git客户端（例如Working Copy）推送更改，可以将生成的<code>public</code>文件夹内容推送到你的远程仓库。</li></ul></li></ol><p>通过上述步骤，就可以在iPad上成功安装并使用Hexo创建和发布博客文章。</p>]]></content>
      
      
      <categories>
          
          <category> 笔记 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> HEXO </tag>
            
            <tag> iPad </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>夏普BP-M2522R打印机电脑USB连接不上的解决方法</title>
      <link href="/post/53fca32d.html"/>
      <url>/post/53fca32d.html</url>
      
        <content type="html"><![CDATA[<h3 id="夏普BP-M2522R打印机电脑USB连接不上的解决方法"><a href="#夏普BP-M2522R打印机电脑USB连接不上的解决方法" class="headerlink" title="夏普BP-M2522R打印机电脑USB连接不上的解决方法"></a>夏普BP-M2522R打印机电脑USB连接不上的解决方法</h3><h4 id="操作步骤："><a href="#操作步骤：" class="headerlink" title="操作步骤："></a>操作步骤：</h4><p><img src="https://img.nnu.cn/p/668b43a40fb10.webp"></p><ol><li><p><strong>进入维修模式</strong></p><ul><li>在开机状态下，依次按 <code># * C *</code> 键。</li></ul></li><li><p><strong>选择菜单</strong></p><ul><li>按 <code>26</code> 后按 <code>开始</code>。</li></ul></li><li><p><strong>进入设置</strong></p><ul><li>按 <code>50</code> 后按 <code>开始</code>，进入如下图所示界面。</li></ul></li><li><p><strong>修改USB设置</strong></p><ul><li>按方向键选择 <code>3. USB DEVICE</code>，将数值从 <code>0</code> 改为 <code>1</code>，按 <code>开始</code> 保存即可。</li></ul></li></ol>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 打印机 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>夏普打印机出现发生错误代码H5-01</title>
      <link href="/post/64d4b504.html"/>
      <url>/post/64d4b504.html</url>
      
        <content type="html"><![CDATA[<p>夏普打印机错误代码H5-01通常是由于多次卡纸，程序自动将机器锁定。以下是解决方法：</p><h3 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h3><ol><li>确保卡纸已清理完毕。</li><li>在面板上依次键入：<code>CA # * C *</code></li><li>进入管理界面。</li><li>在管理界面中，按数字键 <code>14</code>，然后按下“开始”键。这将进入错误清除选项。</li><li>按照提示操作。</li><li>操作完毕后，按“开始”键，打印机将自动重启。</li></ol><p>操作完成后，打印机应恢复正常使用。</p>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 打印机 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>宇视平台添加告警联动</title>
      <link href="/post/b203714c.html"/>
      <url>/post/b203714c.html</url>
      
        <content type="html"><![CDATA[<h3 id="宇视平台设置告警联动实现实况上墙轮切"><a href="#宇视平台设置告警联动实现实况上墙轮切" class="headerlink" title="宇视平台设置告警联动实现实况上墙轮切"></a>宇视平台设置告警联动实现实况上墙轮切</h3><p>通过区域布防和人体移动检测，实现监控实况上墙轮切。以下是宇视平台的设置步骤：</p><h4 id="前提条件"><a href="#前提条件" class="headerlink" title="前提条件"></a>前提条件</h4><p>单个监控摄像头设置中需要配置并启用相关参数。</p><h4 id="步骤："><a href="#步骤：" class="headerlink" title="步骤："></a>步骤：</h4><ol><li><p><strong>登录平台</strong></p><ul><li>使用管理员账号登录宇视平台。</li></ul></li><li><p><strong>进入系统设置</strong></p><ul><li>在右上角，点击“系统设置”。</li><li>在业务管理中选择“告警配置”。<br><img src="https://img.nnu.cn/p/668cba19b1982.webp"></li></ul></li><li><p><strong>选择告警联动</strong></p><ul><li>选择“告警联动”。<br><img src="https://img.nnu.cn/p/668cba39cce26.webp"></li></ul></li><li><p><strong>选择联动区域</strong></p><ul><li>在左侧资源栏中，选择需要联动的区域展开。</li><li>选择视频类告警源展开。<br><img src="https://img.nnu.cn/p/668cba39cce26.webp"></li></ul></li><li><p><strong>选择摄像头</strong></p><ul><li>选中需要联动的摄像头名称展开。</li><li>双击打开运动检测告警。<br><img src="https://img.nnu.cn/p/668cba53cb780.webp"></li></ul></li><li><p><strong>设置联动</strong></p><ul><li>在上方选择“联动实况到监视器”。<br><img src="https://img.nnu.cn/p/668cba794d34d.webp"></li></ul></li><li><p><strong>配置动作</strong></p><ul><li>选择“配置动作”。<br><img src="https://img.nnu.cn/p/668cba883ab12.webp"></li></ul></li><li><p><strong>添加设备</strong></p><ul><li>选择需要添加的设备名称，单击选择增加到列表。<br><img src="https://img.nnu.cn/p/668cbaab15459.webp"></li></ul></li><li><p><strong>选择本域</strong></p><ul><li>双击左侧最上方“本域”。<br><img src="https://img.nnu.cn/p/668cbabb13db6.webp"></li></ul></li><li><p><strong>设置监视器数据源</strong></p><ul><li>点击切换为监视器数据源。<br><img src="https://img.nnu.cn/p/668cbad3c9916.webp"></li></ul></li><li><p><strong>选择屏幕墙位置</strong></p><ul><li>点击上方需要上屏幕墙的位置，增加到列表。</li><li>分屏选择方位的分屏的数量。<br><img src="https://img.nnu.cn/p/668cbae2d4d46.webp"></li></ul></li><li><p><strong>确认并保存</strong></p><ul><li>确认并保存设置，即可完成添加。</li></ul></li></ol>]]></content>
      
      
      <categories>
          
          <category> 笔记 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 监控 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>将压缩包变成一张图片存储</title>
      <link href="/post/4df257b.html"/>
      <url>/post/4df257b.html</url>
      
        <content type="html"><![CDATA[<h3 id="将压缩包变成一张图片存储"><a href="#将压缩包变成一张图片存储" class="headerlink" title="将压缩包变成一张图片存储"></a>将压缩包变成一张图片存储</h3><h4 id="步骤："><a href="#步骤：" class="headerlink" title="步骤："></a>步骤：</h4><ol><li><strong>准备工作</strong><ul><li>将压缩包和一张图片放进同一个文件夹。<br><img src="https://img.nnu.cn/p/668cb629270f3.webp"></li></ul></li><li><strong>打开CMD窗口</strong><ul><li>在Windows 10系统中，右击左下角选择“运行”。<br><img src="https://img.nnu.cn/p/668cb6adcdfae.webp"></li><li>输入<code>CMD</code>，打开CMD窗口。<br><img src="https://img.nnu.cn/p/668cb6bc7167a.webp"></li></ul></li><li><strong>导航到文件夹目录</strong><ul><li>假设演示的文件存放在D盘的0vk文件夹中，输入<code>cd d:\0vk</code>导航到该文件夹目录。<br><img src="https://img.nnu.cn/p/668cb734936e2.webp"></li></ul></li><li><strong>执行合并命令</strong><ul><li>输入以下命令并回车：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">copy /b 图片名称.jpg /b + 压缩包名称.rar /b 目标文件名称.jpg</span><br></pre></td></tr></table></figure></li><li>这将生成一张包含压缩包内容的图片。<br><img src="https://img.nnu.cn/p/668cb7418ba53.webp"></li></ul></li><li><strong>使用和还原</strong><ul><li>生成的文件可以正常作为图片查看。<br><img src="https://img.nnu.cn/p/668cb750820fa.webp"></li><li>需要时，可以将文件后缀名修改为<code>.rar</code>，或者直接使用压缩包程序打开，以恢复为压缩包。</li></ul></li></ol><h4 id="示例："><a href="#示例：" class="headerlink" title="示例："></a>示例：</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">copy /b example.jpg /b + archive.rar /b combined.jpg</span><br></pre></td></tr></table></figure><p>以下是制作完成的文件<br><img src="https://img.nnu.cn/p/668cb76d10f0b.webp"></p>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 图片 </tag>
            
            <tag> 压缩包 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>接触器自锁接线方法</title>
      <link href="/post/54b97e14.html"/>
      <url>/post/54b97e14.html</url>
      
        <content type="html"><![CDATA[<h3 id="接触器自锁接线方法"><a href="#接触器自锁接线方法" class="headerlink" title="接触器自锁接线方法"></a>接触器自锁接线方法</h3><p>在讲解接触器自锁的接线方法前，先了解接触器的原理及常开常闭触点的知识是必要的。以下是详细说明：</p><h4 id="接触器的原理和构造"><a href="#接触器的原理和构造" class="headerlink" title="接触器的原理和构造"></a>接触器的原理和构造</h4><p>380伏交流接触器有三个主触头，即电源进线和负载端出线。进线分别是三相火线L1、L2和L3，负载端出线分别是T1、T2和T3，接触器主触头进线和出线上下一一对应，即L1对应T1，L2对应T2，L3对应T3，主触头在接触器不吸合的状态下是常开状态。</p><p>常开是指触点是断开的、不联通的，常闭是指触点是联通的，这两个概念需要充分理解。</p><p>接触器还有一个常开辅助触头，也就是右方的第四个接触器触点，上下也是一一对应，接触器不吸合一直是常开状态。辅助触头的作用是辅助按钮控制接触器，而主触头的作用是控制负载端，所以分为主触头和辅助触头。</p><p><img src="https://img.nnu.cn/p/668b40b471bce.webp"></p><h4 id="接触器自锁接线方法-1"><a href="#接触器自锁接线方法-1" class="headerlink" title="接触器自锁接线方法"></a>接触器自锁接线方法</h4><p>接触器怎样才能吸合运转呢？答案是：只有让接触器线圈通电，接触器才会吸合。交流接触器线圈电压有220伏的、也有380伏的，线圈电压接线的两个触点分别是A1和A2。也就是说，线圈A1和A2只要有电，形成220伏或者380伏电压接触器就会吸合。</p><p><img src="https://img.nnu.cn/p/668b40d989694.webp"></p><p>线圈的位置在接触器的后方中间，它的作用是在通电以后产生电磁。在接触器前方中间的位置处有块衔铁，接触器线圈产生电磁以后开始吸住前方衔铁，而衔铁又推动接触器主触头和辅助触头的上下触点，因此接触器的常开触点变为常闭触点，常闭触点会变为常开触点。</p><p><img src="https://img.nnu.cn/p/668b411c2b8b7.webp"></p><p>用接触器自锁的主触头触点和辅助触头触点都是常开触点，因此在接触器吸合以后，它的触点都将变为常闭触点。也就是指：接触器上方四个触点和下方四个触点联通，联通以后接触器负载端带电并开始运转，线圈断电以后不产生电磁，所以也就吸不住衔铁。而线圈和衔铁中间还有一个弹簧，会自动把线圈和衔铁弹回到原来位置，因此接触器常闭状态又回到了之前的常开的状态，接触器上方和下方触点断开，负载停止运转。这就是接触器的原理。</p><h4 id="按钮接线"><a href="#按钮接线" class="headerlink" title="按钮接线"></a>按钮接线</h4><p>按钮都有一组常开和一组常闭，停止按钮需要接常闭触点，启动按钮需要接常开触点。按钮按下后常开变为常闭，常闭变为常开，按钮松开后常开和常闭又会回到原来的位置。</p><h4 id="接触器自锁电路图"><a href="#接触器自锁电路图" class="headerlink" title="接触器自锁电路图"></a>接触器自锁电路图</h4><p>接触器自锁电路图还有很多元件，如热继电器、断路器、指示灯等等，以后会一一讲解。今天我们主要学习自锁接线，考虑到大家的理解状况，我们去掉接触器元件，只讲解接触器自锁。</p><p>380伏接触器自锁主触头接线上方三个接三相电源，下方接负载端。线圈A1和接触器L1联通，也就是说线圈A1长带电。我们通过控制接触器线圈A2电源来达到控制接触器的目的，电源L3经过断路器或熔断器到达停止按钮，停止按钮要接常闭触点，也就是一直联通的。</p><p>随后，电源到达启动按钮常开点，启动按钮常开点出来到达接触器辅助触头上方，又联通接触器线圈A2。</p><p>接下来，启动按钮常开上线又分出一根线到达接触器辅助触头下方。这根线十分重要，因为停止按钮接的是常闭，不按它将一直处于联通状态，因此辅助触头下方是常带电的。</p><p><img src="https://img.nnu.cn/p/668b413a97d56.webp"></p><h4 id="自锁原理"><a href="#自锁原理" class="headerlink" title="自锁原理"></a>自锁原理</h4><p>按下启动按钮使它从常开变为常闭，因此，电源通过辅助触头上方到达线圈A2处。这时线圈A1和A2形成了380伏电源，所以接触器开始吸合，接触器上下触点联通，电动机开始运转。但是如果松开启动按钮，它又随之变为常开，处于断电状态，接触器不能正常运行，这时接触器辅助触头下方触点长带电就起到作用了。</p><p>因为按下启动按钮时接触器已经吸合，辅助触头也已经吸合，辅助触头下方电源也开始给线圈A2送电，所以启动按钮松开时，辅助触头下方还在送电，接触器就形成了自锁。而按下停止按钮使得电源断电接触器断开，因此辅助触头下方电源起不到作用。</p><p>以上就是接触器自锁的原理。</p><h4 id="电路图说明"><a href="#电路图说明" class="headerlink" title="电路图说明"></a>电路图说明</h4><p><img src="https://img.nnu.cn/p/668b41e557e79.webp"></p><p>明白了实物接线以后，我们就很容易理解电路图了。下图右方是接触器自锁电路图，A、B、C 分别为电表三相火线电源，QF为开关，KM为接触器，FU为熔断器，带方口的KM为接触器线圈电源。按钮的位置相连的需要接常闭，分开的需要接常开。圆圈M是负载电动机。可根据实物接线图并结合自锁电路图综合理解。</p>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 电气 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>一文读懂！无人值守应答文件制作及使用全攻略，轻松实现系统自动安装</title>
      <link href="/post/d41eccae.html"/>
      <url>/post/d41eccae.html</url>
      
        <content type="html"><![CDATA[<h1 id="无人值守应答文件“AutoUnattend-xml”或“Unattend-xml”介绍"><a href="#无人值守应答文件“AutoUnattend-xml”或“Unattend-xml”介绍" class="headerlink" title="无人值守应答文件“AutoUnattend.xml”或“Unattend.xml”介绍"></a>无人值守应答文件“AutoUnattend.xml”或“Unattend.xml”介绍</h1><p>一个名为“AutoUnattend.xml”或“Unattend.xml”的文件，即无人值守应答文件。只需将这个文件放到相应的位置，在系统安装的过程中即可实现过程全自动。今天来详细介绍一下这个文件以及它的制作方法。</p><p>首先我们来看一下一个标准的应答文件结构，使用浏览器打开这个xml文件。</p><p>下图中，我框出来的7个部分就是安装系统的7个阶段。每个阶段的各种设置，都可以通过应答文件实现，比如输入密钥、设置用户名等等。</p><p><img src="https://img.nnu.cn/p/6800c9065b93d.webp"></p><h2 id="一、这几个阶段都在干什么呢？"><a href="#一、这几个阶段都在干什么呢？" class="headerlink" title="一、这几个阶段都在干什么呢？"></a>一、这几个阶段都在干什么呢？</h2><ol><li><strong>offlineServicing</strong>：此阶段无人参与，主要有安装语言包、更新、驱动等，因此无需设置。</li><li><strong>windowsPE</strong>：包括分区、格式化硬盘等操作，并将install.wim展开到Windows分区。</li><li><strong>generalize</strong>：通用化设置，删除Windows给定安装的特定配置数据。例如，在 generalize 配置阶段中，会将唯一的安全 ID (SID) 和其他硬件特定的设置从映像中删除。这一阶段也不用了解太多，系统封装时会用到。</li><li><strong>specialize</strong>：进行一些特定的设置，比如网络设置、区域设置以及域信息等。</li><li><strong>auditSystem</strong>：审核模式下才会运行，一般是OEM厂商在审核模式下对安装进行测试，此阶段不需要了解。</li><li><strong>auditUser</strong>：审核模式下才会运行，一般是OEM厂商在审核模式下安装附加设备驱动程序、应用程序和其他更新，主要是用户环境的设置，此阶段不需要了解。</li><li><strong>oobeSystem</strong>：此阶段称之为“欢迎使用Windows”，对用户初次体验旗舰应用的设置进行配置，比如设置账户名、密码、语言、区域、时间等等。</li></ol><h2 id="二、这个文件如何制作？"><a href="#二、这个文件如何制作？" class="headerlink" title="二、这个文件如何制作？"></a>二、这个文件如何制作？</h2><p>通常可以使用微软官方工具ADK，但是体积太大，为了制作这个文件实在是没有必要大动干戈。好在有一个网站，可以在线生成应答文件，地址：</p><p><a href="https://schneegans.de/windows/unattend-generator">https://schneegans.de/windows/unattend-generator</a></p><p>这是一个英文网站，可以使用浏览器自带的翻译功能或者翻译插件将其翻译成中文。</p><p><img src="https://img.nnu.cn/p/6800c920aeb35.webp"></p><p>下面介绍几个常用的设置，其他可以根据需要自行设置。首先要设置一下显示语言“Chinese Simplified（简体中文）”。</p><p><img src="https://img.nnu.cn/p/6800c9312b583.webp"></p><p>处理器架构，可以多选，适用于不同架构的处理器。安装设置中，勾选下面的选项，可以绕过Windows11硬件要求的检查（需要注意，它这里仅仅是添加了几个注册表，并不能适用于所有版本的Windows11，有的仍然无法绕过）、允许没有互联网的情况下安装Windows11。</p><p><img src="https://img.nnu.cn/p/6800c93b14232.webp"></p><p>设置计算机名称</p><p><img src="https://img.nnu.cn/p/6800c94115eb1.webp"></p><p>分区格式化这里，我建议不做任何设置，保持默认。也就是说，安装系统的时候虽说是无人值守，但这一步仍然建议手动操作，以免设置错误导致硬盘数据丢失。</p><p><img src="https://img.nnu.cn/p/6800c948a1acf.webp"></p><p>Windows版本设置，这里选择想要安装的版本即可，密钥无需设置，它会使用内置的默认密钥。当然如果你有正版密钥，也是可以设置的。</p><p><img src="https://img.nnu.cn/p/6800c95077ab1.webp"></p><p>设置本地账户名和密码。</p><p><img src="https://img.nnu.cn/p/6800c956e9301.webp"></p><p>如果你想要用微软账户登录也可以勾选，安装系统过程中它会提示你输入微软账户和密码。<br>如果想用本地账户登录，但又暂时不想设置用户名，也可以勾选下面选项，等到安装系统的过程中，它会提示你进行设置。</p><p><img src="https://img.nnu.cn/p/6800c96189831.webp"></p><p>其他的一些个性化设置，例如开始菜单和任务栏、禁用Windows Defender、颜色主题、移除内置应用等等，自定义项目特别多，根据需要自行设置吧。不知道的就保持默认。</p><p><img src="https://img.nnu.cn/p/6800c9680ef0f.webp"><br><img src="https://img.nnu.cn/p/6800c96f25eae.webp"><br><img src="https://img.nnu.cn/p/6800c975abbe9.webp"><br><img src="https://img.nnu.cn/p/6800c97cbcb56.webp"></p><p>设置完成后，拉到网页最下方，点击“Download .xml file”下载。</p><p><img src="https://img.nnu.cn/p/6800c9832b021.webp"></p><h2 id="三、这个文件如何使用？"><a href="#三、这个文件如何使用？" class="headerlink" title="三、这个文件如何使用？"></a>三、这个文件如何使用？</h2><p>下载后名称为“autounattend.xml”，也可以自行将其改名为“unattend.xml”，两个名字的用法不同：</p><ol><li><strong>autounattend.xml</strong>：使用软碟通等软件将ISO镜像打开，将autoUnattend.xml放到ISO镜像的根目录，保存即可。或者不用修改ISO镜像，直接把这个文件放到U盘的根目录，安装系统时只要插上U盘，则会自动搜索。</li><li><strong>unattend.xml</strong>：集成到install.wim里面。首先使用dism命令将wim映像挂载到某个目录（比如win11）下，然后将unattend.xml放到win10\Windows\Panther下，最后再次使用dism命令卸载并重新生成wim映像。这里仅简要提示，具体方法就不介绍了。</li></ol>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 系统安装 </tag>
            
            <tag> 自动化 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>群晖备份的容器该如何恢复</title>
      <link href="/post/9dbb6944.html"/>
      <url>/post/9dbb6944.html</url>
      
        <content type="html"><![CDATA[<p><img src="https://img.nnu.cn/p/668280a7aa9f8.webp"><br>要从备份中恢复 Docker 容器，有几个步骤需要遵循。以下是详细的恢复步骤，包括如何解压备份文件、重新导入容器数据以及重新启动容器。</p><h3 id="1-准备工作"><a href="#1-准备工作" class="headerlink" title="1. 准备工作"></a>1. 准备工作</h3><p>确保你有访问备份文件的权限，并确认备份文件的路径。</p><h3 id="2-停止现有容器"><a href="#2-停止现有容器" class="headerlink" title="2. 停止现有容器"></a>2. 停止现有容器</h3><p>在恢复之前，最好停止现有的相关容器以避免冲突。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker stop &lt;container_name&gt;</span><br><span class="line">docker <span class="built_in">rm</span> &lt;container_name&gt;</span><br></pre></td></tr></table></figure><h3 id="3-解压备份文件"><a href="#3-解压备份文件" class="headerlink" title="3. 解压备份文件"></a>3. 解压备份文件</h3><p>找到备份文件并将其解压到指定目录。</p><p>假设备份文件路径为 <code>/path/to/backup/202306150200/container_name.tar</code>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /path/to/restore/container_name</span><br><span class="line">tar -xvf /path/to/backup/202306150200/container_name.tar -C /path/to/restore/container_name</span><br></pre></td></tr></table></figure><h3 id="4-导入容器数据"><a href="#4-导入容器数据" class="headerlink" title="4. 导入容器数据"></a>4. 导入容器数据</h3><p>使用解压后的数据重新创建 Docker 容器。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker import /path/to/restore/container_name/container_name.tar restored_container_name</span><br></pre></td></tr></table></figure><h3 id="5-重新启动容器"><a href="#5-重新启动容器" class="headerlink" title="5. 重新启动容器"></a>5. 重新启动容器</h3><p>使用导入的数据启动新的容器实例。如果需要原有的设置和配置，最好在启动时指定这些选项。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --name restored_container_name &lt;additional_docker_run_options&gt; restored_container_name</span><br></pre></td></tr></table></figure><h3 id="详细步骤示例"><a href="#详细步骤示例" class="headerlink" title="详细步骤示例"></a>详细步骤示例</h3><p>假设备份文件路径为 <code>/path/to/backup/202306150200/nginx.tar</code>，并希望恢复一个名为 <code>restored_nginx</code> 的容器：</p><h4 id="1-停止并删除现有的-Nginx-容器"><a href="#1-停止并删除现有的-Nginx-容器" class="headerlink" title="1. 停止并删除现有的 Nginx 容器"></a>1. 停止并删除现有的 Nginx 容器</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker stop nginx</span><br><span class="line">docker <span class="built_in">rm</span> nginx</span><br></pre></td></tr></table></figure><h4 id="2-解压备份文件"><a href="#2-解压备份文件" class="headerlink" title="2. 解压备份文件"></a>2. 解压备份文件</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /path/to/restore/nginx</span><br><span class="line">tar -xvf /path/to/backup/202306150200/nginx.tar -C /path/to/restore/nginx</span><br></pre></td></tr></table></figure><h4 id="3-导入容器数据"><a href="#3-导入容器数据" class="headerlink" title="3. 导入容器数据"></a>3. 导入容器数据</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker import /path/to/restore/nginx/nginx.tar restored_nginx</span><br></pre></td></tr></table></figure><h4 id="4-启动新容器"><a href="#4-启动新容器" class="headerlink" title="4. 启动新容器"></a>4. 启动新容器</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --name restored_nginx -p 80:80 restored_nginx</span><br></pre></td></tr></table></figure><h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h3><ul><li><strong>持久化数据</strong>：如果容器使用了卷（volumes）进行数据持久化，确保这些卷的数据也被备份和恢复。例如，数据库容器通常会将数据存储在卷中，需要单独备份和恢复。</li><li><strong>网络配置</strong>：恢复容器时可能需要重新配置网络设置。</li><li><strong>环境变量和配置文件</strong>：确保在重新启动容器时使用了原有的环境变量和配置文件。</li></ul><h3 id="完整恢复示例脚本"><a href="#完整恢复示例脚本" class="headerlink" title="完整恢复示例脚本"></a>完整恢复示例脚本</h3><p>可以编写一个脚本来自动化恢复过程：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 设定变量</span></span><br><span class="line">BACKUP_PATH=<span class="string">&quot;/path/to/backup/202306150200&quot;</span></span><br><span class="line">CONTAINER_NAME=<span class="string">&quot;nginx&quot;</span></span><br><span class="line">RESTORE_PATH=<span class="string">&quot;/path/to/restore/<span class="variable">$&#123;CONTAINER_NAME&#125;</span>&quot;</span></span><br><span class="line">RESTORED_CONTAINER_NAME=<span class="string">&quot;restored_<span class="variable">$&#123;CONTAINER_NAME&#125;</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 停止并删除现有容器</span></span><br><span class="line">docker stop <span class="variable">$&#123;CONTAINER_NAME&#125;</span></span><br><span class="line">docker <span class="built_in">rm</span> <span class="variable">$&#123;CONTAINER_NAME&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建恢复目录并解压备份文件</span></span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="variable">$&#123;RESTORE_PATH&#125;</span></span><br><span class="line">tar -xvf <span class="variable">$&#123;BACKUP_PATH&#125;</span>/<span class="variable">$&#123;CONTAINER_NAME&#125;</span>.tar -C <span class="variable">$&#123;RESTORE_PATH&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 导入容器数据</span></span><br><span class="line">docker import <span class="variable">$&#123;RESTORE_PATH&#125;</span>/<span class="variable">$&#123;CONTAINER_NAME&#125;</span>.tar <span class="variable">$&#123;RESTORED_CONTAINER_NAME&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动新容器</span></span><br><span class="line">docker run -d --name <span class="variable">$&#123;RESTORED_CONTAINER_NAME&#125;</span> -p 80:80 <span class="variable">$&#123;RESTORED_CONTAINER_NAME&#125;</span></span><br></pre></td></tr></table></figure><p>通过这些步骤，你可以从备份中恢复 Docker 容器，确保数据和服务的可用性。</p>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 群晖 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>群晖手动开启PHP Redis.so扩展</title>
      <link href="/post/7202ae72.html"/>
      <url>/post/7202ae72.html</url>
      
        <content type="html"><![CDATA[<p><img src="https://img.nnu.cn/p/66828122be1d6.webp"><br>群晖安装PHP后PHP Redis扩展默认是不开启的，需要我们手动去开启。</p><p>群晖控制面板开启SSH访问，通过工具进入SSH命令行，我使用的是CRT。</p><p>我使用的是PHP8.2，PHP版本不同，安装的位置及目录都有区别，请使用PHP探针确认具体目录。</p><p>新建一个php文件，内容如下：</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="title function_ invoke__">phpinfo</span>();</span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure><p>通过网址访问这个文件即可看到目录路径<br><img src="https://img.nnu.cn/p/668280dcca288.webp"><br>参考图，图片来自网络</p><p>确定好后先sudo -i进入root模式，然后使用vi编辑</p><p>vi &#x2F;volume2&#x2F;@appstore&#x2F;PHP8.2&#x2F;misc&#x2F;php-fpm.ini</p><p>在末尾添加</p><p><code>[Redis] extension = redis.so</code></p><p>修改完保存，然后使用命令：sudo synopkg restart PHP8.2 重启PHP服务即可。</p><p>默认模块文件存放位置: &#x2F;volume2&#x2F;@appstore&#x2F;PHP8.2&#x2F;usr&#x2F;local&#x2F;lib&#x2F;php82&#x2F;modules&#x2F;</p>]]></content>
      
      
      <categories>
          
          <category> 笔记 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> Redis </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>解决 Windows 7 系统下 Edge/Chrome 浏览器提示不再支持 Windows 7 的提示</title>
      <link href="/post/66377e97.html"/>
      <url>/post/66377e97.html</url>
      
        <content type="html"><![CDATA[<p>每次打开 Edge 或 Chrome 浏览器，都会出现提示不再支持 Windows 7 的烦人提醒，可以使用以下注册表进行解决。</p><h4 id="Google-Chrome-浏览器："><a href="#Google-Chrome-浏览器：" class="headerlink" title="Google Chrome 浏览器："></a>Google Chrome 浏览器：</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Windows Registry Editor Version 5.00</span><br><span class="line"></span><br><span class="line">[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome]</span><br><span class="line">&quot;SuppressUnsupportedOSWarning&quot;=dword:00000001</span><br></pre></td></tr></table></figure><h4 id="Microsoft-Edge-浏览器："><a href="#Microsoft-Edge-浏览器：" class="headerlink" title="Microsoft Edge 浏览器："></a>Microsoft Edge 浏览器：</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Windows Registry Editor Version 5.00</span><br><span class="line"></span><br><span class="line">[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge]</span><br><span class="line">&quot;SuppressUnsupportedOSWarning&quot;=dword:00000001</span><br></pre></td></tr></table></figure><h4 id="操作步骤："><a href="#操作步骤：" class="headerlink" title="操作步骤："></a>操作步骤：</h4><ol><li>将上述代码分别复制到文本文件中。</li><li>将文本文件保存为 <code>.txt</code> 格式。</li><li>将文件后缀重命名为 <code>.reg</code>。</li><li>双击运行生成的 <code>.reg</code> 文件，按照提示完成注册表修改。</li></ol>]]></content>
      
      
      <categories>
          
          <category> 笔记 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 更新 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>锐捷POE交换机接监控丢包掉线卡顿问题解决</title>
      <link href="/post/f243baf0.html"/>
      <url>/post/f243baf0.html</url>
      
        <content type="html"><![CDATA[<h2 id="巡检中发现有部分监控画面非常卡顿，经过排查发现是交换机广播导致的，解决办法如下："><a href="#巡检中发现有部分监控画面非常卡顿，经过排查发现是交换机广播导致的，解决办法如下：" class="headerlink" title="巡检中发现有部分监控画面非常卡顿，经过排查发现是交换机广播导致的，解决办法如下："></a>巡检中发现有部分监控画面非常卡顿，经过排查发现是交换机广播导致的，解决办法如下：</h2><h3 id="可网管交换机使用以下命令"><a href="#可网管交换机使用以下命令" class="headerlink" title="可网管交换机使用以下命令"></a>可网管交换机使用以下命令</h3><p>视频卡，丢包严重，可以把接口的广播跟组播预制关闭掉</p><p><code>rujie（config-if）#no storm-control broadcast</code></p><h3 id="傻瓜交换机处理"><a href="#傻瓜交换机处理" class="headerlink" title="傻瓜交换机处理"></a>傻瓜交换机处理</h3><p>用傻瓜交换机监控很卡，丢包严重，可以把流控开关拨到off那边，重启交换机试试</p>]]></content>
      
      
      <categories>
          
          <category> 网络 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 监控卡顿 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>秒禁 Win+L 锁屏！注册表一键解决方案</title>
      <link href="/post/544453e.html"/>
      <url>/post/544453e.html</url>
      
        <content type="html"><![CDATA[<p>通过 <strong>.reg 文件</strong> 来禁用 <strong>Win + L</strong>（锁定计算机）快捷键，可以按照以下方法操作：  </p><h3 id="方法-1：使用注册表文件（-reg）禁用-Win-L"><a href="#方法-1：使用注册表文件（-reg）禁用-Win-L" class="headerlink" title="方法 1：使用注册表文件（.reg）禁用 Win + L"></a><strong>方法 1：使用注册表文件（.reg）禁用 Win + L</strong></h3><ol><li><p><strong>创建一个 <code>.reg</code> 文件</strong>（如 <code>disable_win_l.reg</code>），内容如下：  </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Windows Registry Editor Version 5.00</span><br><span class="line"></span><br><span class="line">[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]</span><br><span class="line">&quot;DisableLockWorkstation&quot;=dword:00000001</span><br></pre></td></tr></table></figure><ul><li>这个注册表项会阻止 <code>Win + L</code> 锁定计算机。</li></ul></li><li><p><strong>双击运行该 <code>.reg</code> 文件</strong>，并确认导入注册表。  </p></li><li><p><strong>重启电脑</strong> 使更改生效。</p></li></ol><h3 id="方法-2：恢复-Win-L-功能（撤销禁用）"><a href="#方法-2：恢复-Win-L-功能（撤销禁用）" class="headerlink" title="方法 2：恢复 Win + L 功能（撤销禁用）"></a><strong>方法 2：恢复 Win + L 功能（撤销禁用）</strong></h3><p>如果你想重新启用 <code>Win + L</code>，可以创建并运行以下 <code>.reg</code> 文件：  </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Windows Registry Editor Version 5.00</span><br><span class="line"></span><br><span class="line">[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]</span><br><span class="line">&quot;DisableLockWorkstation&quot;=-</span><br></pre></td></tr></table></figure><ul><li>运行后，<code>Win + L</code> 将恢复正常。</li></ul><h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a><strong>注意事项</strong></h3><ul><li><strong>管理员权限</strong>：运行 <code>.reg</code> 文件需要管理员权限。  </li><li><strong>企业&#x2F;学校电脑</strong>：如果电脑受组策略管理，注册表修改可能被覆盖。  </li><li><strong>Win + R 禁用</strong>：如果你想同时禁用 <code>Win + R</code>，可以使用类似的注册表方法（如 <code>NoRun</code> 键值）。</li></ul>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 系统 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>东芝打印机屏幕上显示（请求维修C449）</title>
      <link href="/post/43c873f1.html"/>
      <url>/post/43c873f1.html</url>
      
        <content type="html"><![CDATA[<p>按 <code>08</code> 开机-输入 <code>2002</code> 开始然后将数值改为 <code>0</code> ，按 <strong>ok</strong> ,按开始，关机开机。</p><h3 id="如果未恢复，可能灯泡存在故障。"><a href="#如果未恢复，可能灯泡存在故障。" class="headerlink" title="如果未恢复，可能灯泡存在故障。"></a>如果未恢复，可能灯泡存在故障。</h3>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 打印机 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>关于联想云桌面网络引导报错（Error 0x3e11618e）解决</title>
      <link href="/post/d4d5de6b.html"/>
      <url>/post/d4d5de6b.html</url>
      
        <content type="html"><![CDATA[<p><img src="https://img.nnu.cn/p/66827c8ca9ac4.webp"></p><h4 id="开机网络启动报如下图错误提示"><a href="#开机网络启动报如下图错误提示" class="headerlink" title="开机网络启动报如下图错误提示"></a>开机网络启动报如下图错误提示</h4><p><img src="https://img.nnu.cn/p/66827e3dad582.webp"><br>原因为底层DHCP地址问题导致，检查DHCP配置IP是否正确，修正后重启服务即可解决。<br><img src="https://img.nnu.cn/p/66827e4fbcb9a.webp"><br>系统设置-DCHP(设置）<br><img src="https://img.nnu.cn/p/66827e5dbe322.webp"></p>]]></content>
      
      
      <categories>
          
          <category> 笔记 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 联想云课堂 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>微软免费 1500 款开源 3D Emoji表情</title>
      <link href="/post/f8dd2162.html"/>
      <url>/post/f8dd2162.html</url>
      
        <content type="html"><![CDATA[<p><img src="https://img.nnu.cn/p/668aa3b814e3f.webp"></p><h3 id="微软3D-Emoji创作者可免费使用"><a href="#微软3D-Emoji创作者可免费使用" class="headerlink" title="微软3D Emoji创作者可免费使用"></a>微软3D Emoji创作者可免费使用</h3><p>微软在去年发布的 Windows 11 中发布了微软 Emoji 库，并于今年 2 月份在 Microsoft Teams 中发布了 3D 版本，但是微软最初并没有打算将其开源。</p><p>目前，微软已经将其 Emoji 库（拥有 1538 个 Emoji）中的大部分 Emoji 已开源，以供用户使用。<br><img src="https://img.nnu.cn/p/668aa40d1797f.webp"><br>这些表情看起来非常的具有活力，焕然一新，更加让人眼前一亮。<br><img src="https://img.nnu.cn/p/668aa45c06dc7.webp"><br>微软希望此举将鼓励创作者在表情符号领域展现更丰富的创造力和包容性。</p><p>新表情的人物皮肤有不同的肤色，基本每个人物表情都有6款肤色，可以满足创造者大部分需求了！</p><p>并且创造者们还可以在Figma上自定义肤色、颜色、饱和度等，大黄脸表情都有4种样式，除了3D风格，还有可编辑的线性emoji表情。<br>微软希望创作者探索其表情符号的更多使用方式。弗里德曼解释道：“在微软内部，我们是一个小团队，只能做这么多或看到这么多。我们渴望让更多人参与进来，帮助我们看到并做更多的事情，将 Emoji 带到我们无法预见的地方”。<br>微软新表情github地址：<a href="https://github.com/microsoft/fluentui-emoji">https://github.com/microsoft/fluentui-emoji</a></p><h3 id="可以自己做成博客的评论表情包等等，后面抽空自己做一个。"><a href="#可以自己做成博客的评论表情包等等，后面抽空自己做一个。" class="headerlink" title="可以自己做成博客的评论表情包等等，后面抽空自己做一个。"></a>可以自己做成博客的评论表情包等等，后面抽空自己做一个。</h3>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> 表情包 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>Frp跨平台桌面客户端</title>
      <link href="/post/f59aee00.html"/>
      <url>/post/f59aee00.html</url>
      
        <content type="html"><![CDATA[<p><strong>客户端名称：Frpc-Desktop</strong></p><p>🎉 发现一个 Frp Client 跨平台桌面端，作者已经发布到了v1.0.3 版本，感觉还可以推荐收藏备用。</p><p><strong>作者更新里程碑</strong></p><ul><li>2024-07-17: 发布 v1.0.3 版本 修复已知 bug 增加开机自启 增加删除 frp 版本</li><li>2024-01-29: 发布 v1.0.2 版本 增加 Linux 客户端和代理模式</li><li>2023-12-01: 发布 v1.0.1 版本</li><li>2023-11-28: 发布 v1.0 版本</li></ul><p><strong>图片演示</strong> </p><h3 id="主界面"><a href="#主界面" class="headerlink" title="主界面"></a>主界面</h3><p><img src="https://img.nnu.cn/p/66a72e7d3b359.webp"></p><h3 id="列表"><a href="#列表" class="headerlink" title="列表"></a>列表</h3><p><img src="https://img.nnu.cn/p/66a72ea9651de.webp"></p><h3 id="版本下载"><a href="#版本下载" class="headerlink" title="版本下载"></a>版本下载</h3><p><img src="https://img.nnu.cn/p/66a72ee1ef55d.webp"></p><h3 id="日志"><a href="#日志" class="headerlink" title="日志"></a>日志</h3><p><img src="https://img.nnu.cn/p/66a72f10633be.webp"></p><p><strong>图像化界面上手简单</strong></p><p>项目地址：<a href="https://github.com/luckjiawei/frpc-desktop?tab=readme-ov-file">https://github.com/luckjiawei/frpc-desktop?tab=readme-ov-file</a></p>]]></content>
      
      
      <categories>
          
          <category> 资料 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> Frp客户端 </tag>
            
            <tag> 内网穿透 </tag>
            
        </tags>
      
    </entry>
    
    
    
    <entry>
      <title>实现全站图片使用avif格式，并优化不兼容avif的配置</title>
      <link href="/post/e67e4c6c.html"/>
      <url>/post/e67e4c6c.html</url>
      
        <content type="html"><![CDATA[<h3 id="本站使用EO来显示avif"><a href="#本站使用EO来显示avif" class="headerlink" title="本站使用EO来显示avif"></a>本站使用EO来显示avif</h3><p>腾讯的边缘安全加速平台 EO平台是我们现在常用的全站加速方式之一，边缘安全加速平台 EO的媒体加速是限时免费的。</p><p>示例：<a href="https://example.com/1.jpg">https://example.com/1.jpg</a></p><h3 id="对于不兼容的avif格式浏览器使用以下js代码实现切换至webp格式"><a href="#对于不兼容的avif格式浏览器使用以下js代码实现切换至webp格式" class="headerlink" title="对于不兼容的avif格式浏览器使用以下js代码实现切换至webp格式"></a>对于不兼容的avif格式浏览器使用以下js代码实现切换至webp格式</h3><p>为了确保处理懒加载图片，我们需要确保观察到所有图片加载事件，并在图片加载完成后替换它们的 URL。这可以通过监听 load 事件来实现。下面是代码，结合了 MutationObserver 和 load 事件监听：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;DOMContentLoaded&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;DOM content loaded&quot;</span>); <span class="comment">// 检查DOM是否加载完成</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// 从页面中提取所有带有 AVIF 参数的图片链接</span></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">getAllAvifImages</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> images = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;img&#x27;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Array</span>.<span class="title function_">from</span>(images).<span class="title function_">filter</span>(<span class="function"><span class="params">img</span> =&gt;</span> img.<span class="property">src</span>.<span class="title function_">includes</span>(<span class="string">&#x27;&#x27;</span>));</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 检测浏览器是否支持AVIF格式</span></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">supportsAvif</span>(<span class="params">url</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function"><span class="params">resolve</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> avif = <span class="keyword">new</span> <span class="title class_">Image</span>();</span><br><span class="line">      avif.<span class="property">src</span> = url;</span><br><span class="line">      avif.<span class="property">onload</span> = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;AVIF supported&quot;</span>);</span><br><span class="line">        <span class="title function_">resolve</span>(<span class="literal">true</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">      avif.<span class="property">onerror</span> = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;AVIF not supported&quot;</span>);</span><br><span class="line">        <span class="title function_">resolve</span>(<span class="literal">false</span>);</span><br><span class="line">      &#125;;</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 替换图片URL中的 avif 参数为 webp</span></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">replaceAvifWithWebp</span>(<span class="params">images</span>) &#123;</span><br><span class="line">    images.<span class="title function_">forEach</span>(<span class="function"><span class="params">img</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (img.<span class="property">src</span>.<span class="title function_">includes</span>(<span class="string">&#x27;&#x27;</span>)) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Replacing AVIF with WebP for image:&quot;</span>, img.<span class="property">src</span>);</span><br><span class="line">        img.<span class="property">src</span> = img.<span class="property">src</span>.<span class="title function_">replace</span>(<span class="string">&#x27;&#x27;</span>, <span class="string">&#x27;?eo-img.format=webp&#x27;</span>);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;New image src:&quot;</span>, img.<span class="property">src</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> firstAvifImage = <span class="title function_">getAllAvifImages</span>()[<span class="number">0</span>]; <span class="comment">// 获取第一个带有AVIF参数的图片</span></span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;First AVIF Image:&quot;</span>, firstAvifImage); <span class="comment">// 输出第一个AVIF图片</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (firstAvifImage) &#123;</span><br><span class="line">    <span class="title function_">supportsAvif</span>(firstAvifImage.<span class="property">src</span>).<span class="title function_">then</span>(<span class="function"><span class="params">supported</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (!supported) &#123;</span><br><span class="line">        <span class="keyword">const</span> images = <span class="title function_">getAllAvifImages</span>();</span><br><span class="line">        <span class="title function_">replaceAvifWithWebp</span>(images);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 使用 MutationObserver 监控 DOM 的变化</span></span><br><span class="line">        <span class="keyword">const</span> observer = <span class="keyword">new</span> <span class="title class_">MutationObserver</span>(<span class="function"><span class="params">mutations</span> =&gt;</span> &#123;</span><br><span class="line">          mutations.<span class="title function_">forEach</span>(<span class="function"><span class="params">mutation</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (mutation.<span class="property">addedNodes</span>.<span class="property">length</span>) &#123;</span><br><span class="line">              mutation.<span class="property">addedNodes</span>.<span class="title function_">forEach</span>(<span class="function"><span class="params">node</span> =&gt;</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (node.<span class="property">tagName</span> === <span class="string">&#x27;IMG&#x27;</span> &amp;&amp; node.<span class="property">src</span>.<span class="title function_">includes</span>(<span class="string">&#x27;&#x27;</span>)) &#123;</span><br><span class="line">                  <span class="title function_">replaceAvifWithWebp</span>([node]);</span><br><span class="line">                &#125;</span><br><span class="line">              &#125;);</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;);</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        observer.<span class="title function_">observe</span>(<span class="variable language_">document</span>.<span class="property">body</span>, &#123;</span><br><span class="line">          <span class="attr">childList</span>: <span class="literal">true</span>,</span><br><span class="line">          <span class="attr">subtree</span>: <span class="literal">true</span></span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 监听所有懒加载图片的load事件</span></span><br><span class="line">        <span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;load&#x27;</span>, <span class="function"><span class="params">event</span> =&gt;</span> &#123;</span><br><span class="line">          <span class="keyword">if</span> (event.<span class="property">target</span>.<span class="property">tagName</span> === <span class="string">&#x27;IMG&#x27;</span> &amp;&amp; event.<span class="property">target</span>.<span class="property">src</span>.<span class="title function_">includes</span>(<span class="string">&#x27;&#x27;</span>)) &#123;</span><br><span class="line">            <span class="title function_">replaceAvifWithWebp</span>([event.<span class="property">target</span>]);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;, <span class="literal">true</span>);</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;AVIF images will be used.&quot;</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;No AVIF images found on the page.&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>]]></content>
      
      
      <categories>
          
          <category> 笔记 </category>
          
      </categories>
      
      
        <tags>
            
            <tag> HEXO </tag>
            
        </tags>
      
    </entry>
    
    
  
  
</search>
