博客文章

4.自定义页面以康奈尔笔记格式输出

康奈尔笔记制作

3.github和atomgit的混合使用,哪些是值得注意的?

简单介绍github和atomgit的混合使用,以及遇到的一些问题

2.git与github的使用

简单介绍git与github的使用

1.博客优化笔记

在这里你可以找到如何优化这个网站

7.初次安装AD需要做哪些设置?

……

6.云端一体化的环境变量问题

……

5.云端一体化如何查看云函数日志?

简单记录开发过程中遇到的问题

8.如何用旧电脑搭建自己的服务器?

拥有一个属于自己的服务器个人感觉就很赞,或许这篇文章可以帮到你。

10.如何自定义hugo主题页面输出格式?

有时候需要自定义或在别人的基础上修改页面输出格式,有时候我们缺少的是一种思路,本篇文章就是提供一个清晰的思路,让你可以快速编写出自己的页面。

11.五笔学习

学习五笔

12.使用望言OCR与Aegisub,实现字幕识别、提取和自定义

望言OCR可以帮助你识别视频中的字幕,并导出为.ass字幕文件,然后你可以使用Aegisub进行字幕编辑和自定义。

13.win11安装WSL详细步骤

记录如何使用WSL在win11上安装Linux子系统系统。启动方便快捷,而且可以切换多个Linux发行版本,以及随时删除,占用内存也不大。

14.Win11安装Docker详细教程

描述文章内容

15.win10电脑忘记密码无法登录怎么办

最近再给一个10年前的联想电脑装系统的时候,发现忘记密码了,用户还是管理员(Administrator),将这个问题发给Deepseek后得到了下面的解决办法,为此记录这个过程,经过一番折腾最终也是解决了问题,但是过程很像**重装系统的前半流程**

16.如何给电脑装win10系统

如何给一台老的电脑装win10系统,本文以14年产的Thinkpad联想电脑为例,记录整个过程。

常用的数学表达

常用箭头

常用函数图像公式

2025年4月6日

博客文章 的子部分

4.自定义页面以康奈尔笔记格式输出

Cues

标签/提示 :静态网页,康奈尔笔记,hugo,自定义页面输出格式。

Notes

创建css文件

康奈尔笔记的布局,其中左侧是 “Cues”,右侧是 “Notes”,底部是 “Summary”,您可以使用 Flexbox 的 row 和 column 布局来实现。这里是一个 CSS 示例,它将创建一个两列的布局,左侧为 “Cues”,右侧为 “Notes”,然后在这两列下方是 “Summary”。

首先,创建一个名为 cornell-notes.css 的 CSS 文件,并添加以下样式代码:

.cornell-notes {
  
  border: 1px solid #ccc;
  padding: 20px;
  margin: 20px;
  display: flex;
  flex-wrap: wrap;
}

.cues {
  background-image: url('icon2.svg');
  border-right: 1px solid #080808;
  flex: 1;
  padding-right: 20px;
}

.notes {
  background-image: url('icon1.svg');
  border-left: 1px solid #080808;
  flex: 2;
  padding-left: 20px;
}

.summary {
  width: 100%;
  clear: both; /* 清除浮动,确保摘要部分在下方 */
  padding-top: 20px;
  background-image:url('wwwatercolor.jpg');
  margin-top: 20px;
}

在这个样式中,.cornell-notes 是整个康奈尔笔记的容器,我们使用 display: flex; 和 flex-wrap: wrap; 来创建一个 Flex 容器,允许子元素根据需要换行。.cues 和 .notes 分别设置为容器的子项,并通过 flex 属性来分配空间。.summary 部分使用 width: 100%; 来确保它在 .cues 和 .notes 下方显示,并使用 clear: both; 来清除之前的浮动。

此处分享一个免费的svg网站,bbburst: bbburst bbburst 在这个网站或许你可以找到适合你的背景图,用以装饰自己的康奈尔容器,此处的svg是放在css文件夹下的,所以是直接引用,如果你放在别的的放那么还请使用正确的的路径。

在hugo配置中设置

接下来,确保将 cornell-notes.css 文件放置在 Hugo 站点的 static/css 目录下。然后,在 Hugo 的配置文件 config.toml 中添加对 CSS 文件的引用:

# config.toml
[Params]
  # 其他参数...

[markup]
  [markup.goldmark]
    [markup.goldmark.renderer]
      unsafe = true  # 允许在 Markdown 中使用 HTML  CSS

如果使用的是code打开的项目,那么可以先在code内搜索上面的配置是否已添加,因为部分hugo主题原来就添加了这一配置。

在markdown文档中引用

在 Markdown 文件中,你可以这样使用这些类:

---
title: "康奈尔笔记示例"
---

<link rel="stylesheet" href="/css/cornell-notes.css">  <div class="cornell-notes">    <div class="cues">
## Cues
    - 这里是关键词和提示。
</div>
<div class="notes">
## Notes
  - 这里是详细的笔记内容。
</div>
<div class="summary">
## Summary
 - 这里是笔记的摘要。
</div>
</div>

确保在 Markdown 文件中添加 标签来引入 CSS 文件,并为每个部分使用相应的类。这样,当你构建并查看 Hugo 站点时,康奈尔笔记将以正确的样式显示,其中 “Cues” 在左侧,“Notes” 在右侧,“Summary” 在底部。

Summary

在上面我们学习了如何自定义hugo中页面的输出格式,在引用hugo主题情况下,自定义自己的页面输出格式只需要三点,即创建css文件,在config配置文件中配置相关信息,在markdown中引用。其实我们可以拓展,如果你想创建属于自己的笔记你可以参照上面的方法自制简单的笔记,希望本期内容对你有所帮助。

2025年4月6日

3.github和atomgit的混合使用,哪些是值得注意的?

一台电脑如何使用多个远程仓库?

  • 下载好git,并做好相关的配置
  • 关联github仓库
    • 创建github仓库
    • 克隆仓库到本地
  git clone <你的远程仓库URL>

创建多个 SSH 密钥对涉及到在本地生成多个公钥和私钥文件,并将公钥添加到你想要访问的远程服务器上。以下是详细步骤:

打开终端: 打开你的终端(在 macOS 或 Linux 上)或 Git Bash(在 Windows 上)。

导航到 SSH 目录: 使用 cd 命令切换到你的 SSH 目录,通常是 ~/.ssh。

cd ~/.ssh 生成新的 SSH 密钥对: 使用 ssh-keygen 命令生成新的密钥对。每次运行此命令时,你都可以指定不同的文件名,以便区分不同的密钥对。例如,为 GitHub 生成的密钥对可能命名为 id_rsa_github,为 GitLab 生成的密钥对可能命名为 id_rsa_gitlab。

ssh-keygen -t rsa -b 4096 -C "your_email@example.com" -f id_rsa_github 重复上述步骤,为其他服务生成密钥对,只需更改文件名即可。例如:

ssh-keygen -t rsa -b 4096 -C "another_email@example.com" -f id_rsa_gitlab

-b是指密码的长度是4096,与加密有关,-f表示要创建的ssh有关文件名

在生成密钥时,系统会提示你输入一个文件名来保存新的密钥对。如果你直接按回车键,它将使用默认的文件名(如 id_rsa)。如果你想要为每个服务使用不同的文件名,确保在命令中指定 -f 选项后跟你想要的文件名。

将公钥添加到远程服务器: 生成密钥对后,你需要将公钥(文件名后缀为 .pub)添加到远程服务器的 SSH 密钥管理界面。例如,在 GitHub 上,你可以在 Settings > SSH and GPG keys 部分添加新的公钥。

配置 SSH 配置文件: 为了确保 SSH 使用正确的密钥对连接到正确的服务器,你可以在 .ssh 目录下创建一个名为 config 的文件(如果该文件不存在的话),并为每个服务配置不同的设置。

touch ~/.ssh/config

然后编辑这个文件,添加以下内容:

Host github.com
  User git
  IdentityFile ~/.ssh/id_rsa_github
  IdentitiesOnly yes

Host gitlab.com
  User git
  IdentityFile ~/.ssh/id_rsa_gitlab
  IdentitiesOnly yes

这里的 Host 是你为每个服务设置的别名,User 是 Git 服务的默认用户名(通常是 git),IdentityFile 是你的私钥文件的路径。

测试 SSH 连接: 使用 ssh -T 命令测试与远程服务器的连接。例如:

ssh -T git@github.com
ssh -T git@gitlab.com

如果一切设置正确,你应该会看到一条欢迎消息,表明你已经成功通过 SSH 密钥验证。

当我有连个github账户时,当我用同一台电脑推送的时候如何区分是那个推送的

推荐文章

答案:

首先是克隆下来两个项目一个为test_A,一个为test_B,假设有一个账户是A,另一个是B,而且A账户的邮箱是设置为全局的,即用了这条命令:

git config --global user.name "A"

git config --global user.email A@qq.com
#假设这里的邮箱是QQ

那么在在text_A中不作任何修改,在text_B中添加如下命令即可:

git config  user.name "B"

git config user.email B@qq.com
#假设这里的邮箱是QQ

遇到的一些问题

问题一


解决Git上传代码error: failed to push some refs to ‘xxx‘hint:(e.g., ‘git pull …‘) before pushing again错误


推荐文章

问题二


【Git】错误:权限被拒绝(公钥)(Permission denied (publickey).)


推荐文章2)

问题三


解决Git上传代码error: failed to push some refs to ‘xxx‘hint:(e.g., ‘git pull …‘) before pushing again错误


推荐文章

附件

2.git与github的使用

网页链接

原文章链接

1、使用git commi -m “……“时报错: Your branch is up to date with ‘origin/master‘

今天在提交项目的时候报了这个错误,在网上查了解决办法,有的说创建新的分支可以解决,但我的不行。

最后我的解决办法是先退出git base here,再重新进入,下面是具体步骤:

  • 先使用git add .
  • 接着使用git status -s查看我更改的文件,也是我要推送的文件,如果前面的有M和??,那么久重新更新文件,然后重复上面的步骤;
  • 发现前面的M是绿色的后就可以使用git commit -m "文件备注"
  • 然后推送就可以了git push origin main

AndroidStudio中的grable下载很慢,如何解决?

参考地址

这里的关键命令是git status -s,我现在搞不懂这个错误产生的原因……

虚拟机连接不上网络,没有分配ENS33

参考链接

浏览器突然无法访问某些网站,之前可以突然不行。

解决办法: 11 11

在浏览器中关闭,使用安全的 DNS 指定如何查找网站的网络地址,然后就可以访问了,原因我还没弄清楚。

AndroidStudio中为什么不建议使用case R.id.generate判断,而是使用if(v.getId() == R.id.generate)

1.当使用Switch语句写如下代码时,

switch (v.getId()){
            case R.id.generate:

                break;
            case R.id.add:

                break;
        }

(红色表示报错)如果报错android studio报错constant expression required, 可以把Switch语句换成if-else语句即

Ifv.getId() == R.id.generate
{
……
}else ifv.getId() == R.id.add{
……
}

这样就可以了。来源以及具体原因: https://blog.csdn.net/weixin_43912621/article/details/106178388

附件

1.博客优化笔记

代码分制表

< tabs title="file name" >,< /tabs >结尾; 然后里面写以% tab title="code name" style="info" color="blue " %,% /tab %结尾 他们都需要用{{}}括起来

{{< tabs title="hello." >}}
//代码块一
{{% tab title="py" %}}
    ```markdown
    **这里写代码**
    ```
{{% /tab %}}
//代码块二
{{% tab title="sh" %}}
    ```markdown
    **这里写代码**
    ```
{{% /tab %}}

{{< /tabs >}}

显示附件文件

在双花括号里写:attachments color="fuchsia" icon="fab fa-hackerrank",即可,

    {{% attachments color="fuchsia" icon="fab fa-hackerrank" %}}

——————————————————分割线

不论是创建首页页面,还是左边框的选项,归根结底它们都是“目录”,从根上说,你需要创建一个目录然后在目录里面创建一个.md文件来装这个目录或说显示这个目录的内容。

首页的创建

创建首页使用了命令

    hugo new --kind home _index.md

而后产生的页面,它自动生成头文件

    +++
    archetype = "home"
    title = ""
    +++

值得注意的是,如果你用命令

    hugo new site myblog

创建了一个myblog的目录,那么你在里面操作hugo new –kind home _index.md的时候,用于显示首页的文件**_index.md**会自动产生在content文件里。

创建章节的方法

使用命令:

    hugo new <chapter>/<name>/_index.md

或者:

    hugo new <chapter>/<name>.md

在创建章节的时候需要加上alwaysopen = false,如下面的例子:

        +++
        alwaysopen = false
        archetype = "chapter"
        title = "2.AndroidStudio"
        weight = 20
        +++

在标题前面显示图标

    +++
    menuPre = "<i class='fab fa-github'></i> "
    +++

添加这个后的效果如下:

效果图 效果图

最新技术文章

{{ partial "post-card.html" (dict "path" "log/7.初次安装AD需要做哪些设置?.md") }}
物联网安全架构

#13 物联网网络安全论

探讨边缘计算环境下的安全防护体系...

发布于 2024-03-12 | 分类:网络安全

附件

7.初次安装AD需要做哪些设置?

设置自动保存

打开程序点击系统设置,如下图:

系统设置 系统设置

按照下图步骤设置自动保存,每10分钟保存一次(你也可以设置成其他的,但不建议设置太小或太大比如1分钟或者30分钟)

设置自动保存 设置自动保存

设置单一’'表示负信号

按照下图设置

在这里插入图片描述 在这里插入图片描述

负信号表示 负信号表示

最终效果 最终效果

设置复制自动增加 设置复制自动增加

复制自动增加 复制自动增加

复制不自动增加 复制不自动增加

设置显示对话框

我设置前

名字重叠 名字重叠

未设置前 未设置前

当把上面的打钩后

设置后 设置后

在这里插入图片描述 在这里插入图片描述

[外链图片转存中…(img-ZngLHveL-1719559556141)]

在这里插入图片描述 在这里插入图片描述

在这里插入图片描述 在这里插入图片描述

在这里插入图片描述 在这里插入图片描述

按住shift+h可以显示和关闭

[外链图片转存中…(img-bxjUhYCS-1719559556142)]

在这里插入图片描述 在这里插入图片描述

[外链图片转存中…(img-qKvH9IRn-1719559556142)] 在这里插入图片描述 在这里插入图片描述

[外链图片转存中…(img-HAD9BmgV-1719559556142)]

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

在这里插入图片描述 在这里插入图片描述

6.云端一体化的环境变量问题

参数context 与环境变量有关,不管是系统还是用户自定义的都用这个来获取,获取方式:context.env

  • 先部署云函数到远端,然后在去远端添加环境变量,然后在本地运行虚拟机查看。

负载均衡的四种方式

  • 随机
  • 轮询
  • 最少连接数
  • 最短响应时间

延迟时长的重试策略

  • zero:一旦云函数调用失败,则调用,中间不等待
  • constant:调用失败等一段时间
  • jittered:调用失败等一段时间,再次调用,如果失败等待时间以指数增长

熔断

设置一定的条件,满足条件后会执行熔断。熔断后云函数不在提供服务。

e e

附件

5.云端一体化如何查看云函数日志?

调用云函数的时候我们总有输入输出结果不符合自己预期的时候,这个时候查看日志很重要!!在云端一体化开发过程中,我们可以通过下面的方式解决这一问题:

首先参数event的输出以JSON格式输出,这样方便阅读,下面有一段代码,

云函数代码如下:

import { stringify } from "querystring";
let myHandler = async function (event, context, callback, logger) {
  logger.info(JSON.stringify(event));
  const name = event.body.name
  callback({
    code: 200,
    message: `Hello ${name}.`
  });
};

export { myHandler };

获取信息的ets文件如下:

import cloud from '@hw-agconnect/cloud';
@Entry
@Component
struct MyIndex {
  @State message: string = ''
  @State name:string = ''

  build() {
    Row() {
      Column() {
        TextInput({placeholder:'请输入姓名'})
          .onChange(value => {
            this.name = value
          })
        Button('使用云端一体化')
          .fontSize(20)
          .onClick(async ()=>{
            const result = await cloud.callFunction({
              name:'login',//云函数的名字
              version:'$latest',
              params:{name:this.name}
            })
            this.message=result.getValue().message
          })
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .height('100%')
  }
}

function函数的说明:

  • 触发条件:
    • HTTP请求,
    • 云数据库插入,
    • 云存储
  • 参数含义:
    • 输入信息(),
    • 执行时上下文信息(环境变量),
    • 输出(返回结果给调用者),
    • 记录日志()

此处做了这样的处理使得日志输出以JSON格式输出:


logger.info(JSON.stringify(event))

当遇到问题时,去官方的开发论坛搜索相关内容, 此处我想实现输入一个名字,然后让云端函数以不同的方式输出,比如:


你好,张三

你好,李四


但是现在输出的是:你好,%&*%%

解决办法:

查看event参数说明

jietu1 jietu1

再去CAG官网选择云监控—>日志服务

截图2 截图2

然后复制右边的内容,放到一个json文件夹,用编译器(比如VScode)打开,并调整格式(如果用的是VScode,请使用shift+alt+F调整json格式)如下:

{
    "path": "login-$latest",
    "httpMethod": "POST",

    "headers": 
    {
        "user-agent": "libcurl-agent/1.0",
        "x-forwarded-for": "115.46.239.151, 10.135.135.154, 10.134.64.11",
        "x-forwarded-port": "443",
        "accept": "*/*",
        "accept-encoding": "gzip",
        "agcgw-trigger-authtype": "apigw-client",
        "host": "10.14.4.31",
        "content-type": "application/json;charset=UTF-8",
        "packagename": "com.itwcx.test",
        "appid": "5765880207853994135",
        "authorization": "SDK-HMAC-SHA256 containPath=false,containBody=false,containQuery=false,accessId=m7rTGQ2uNvyq1AGfJFLo,timestamp=1711175951586,signedHeaders=appid;productid,signature=44fe3b4da7d80ec9dfee07ca3747c448e94254b5454fef87f468150089f38623",
        "x-forwarded-host": "10.14.4.31",
        "appversion": "1.0.0",
        "sdkplatformversion": "3.2.0.0",
        "sdktype": "TS",
        "content-length": "19",
        "x-real-ip": "10.134.64.11",
        "sdkversion": "1.0.0",
        "x-forwarded-proto": "https",
        "sdkservicename": "agconnect-cloud",
        "x-trace-id": "f09f1070-6d7b-46a9-875d-bfb2bc4bfdb9",
        "productid": "388421841222044287",
        "sdkplatform": "OpenHarmony"
    },

    "queryStringParameters": "",
    "queryParameters": null,
    "body": "{\"name\":\"zhangsan\"}",
    "isBase64Encoded": false,
    "pathVariable": null
}

此处我们只查看参数event的HTTP请求的相关说明:

比较官网的event参数格式与自己日志打印的格式,看看有什么不同

截图3 截图3

截图4 截图4

观察可知问题出在body这个参数,参数是json格式,而日志打印的是字符格式,我们需要把字符格式转换成json格式,做如下操作:

import { stringify } from "querystring";
let myHandler = async function (event, context, callback, logger) {
  logger.info(JSON.stringify(event));
  const obj = JSON.parse(event.body)
  const name = obj.name
  callback({
    code: 200,
    message: `Hello ${name}.`
  });
};

export { myHandler };

上面的代码中


const obj = JSON.parse(event.body)
const name = obj.name

就是转换操作。

认证服务

登录页面的实现

截图7 截图7

登录验证代码:

import { AuthMode,Login } from '@hw-agconnect/auth-component'
import { AuthUser } from '@hw-agconnect/cloud'
import router from '@ohos.router'
@Entry
@Component
struct MyLogin {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Login({
          modes:[AuthMode.PHONE_VERIFY_CODE],
          onSuccess:(usr:AuthUser) =>{
              router.pushUrl({url:'page/MyWelcome'})
          }
        }){
          Button('登录')
        }
      }
      .width('100%')
    }
    .height('100%')
  }
}

12 12

页面登录获取验证码

import { Auth, VerifyCodeAction } from '@hw-agconnect/cloud';
import cloud from '@hw-agconnect/cloud'
import hilog from '@ohos.hilog'
import router from '@ohos.router';
@Entry
@Component

struct MyLogin {
  @State countDown: number = 10
//用一个变量来获取setinterval的ID
  intervalId:number = 0 //因为这个变量与页面显示无关所以不用@State注释
  @State verifyCodeButtonEnable:boolean = false
  @State verifyCodeButtonText:string ='获取验证码'
  @State phoneNumber: string = ''
  @State verifyCode:string = '输入验证码'

  //定时器代码
  waiting(){
    this.verifyCodeButtonEnable = false
    this.verifyCodeButtonText = `${this.countDown}s`//在一点击时,就显示10S
    this.intervalId = setInterval(() => { //要知道定时器结束没有需要知道它的返回结果,这个结果可以通过setinterval的ID获取。
      this.verifyCodeButtonText = `${this.countDown}s`//将倒计时显示出来
      if(this.countDown < 0){
        //如果减到0,清楚定时器
        clearInterval(this.intervalId)//得到返回结果后清楚定时器
        this.countDown = 10
        this.intervalId = 0
        this.verifyCodeButtonText = '获取验证码'//倒计时结束时回复
        this.verifyCodeButtonEnable = true //当点击时按键不可用
        return //不需要再往下继续执行了,所以return
      }
      this.countDown--
    },1000)//每隔1秒减一次
  }
   judgement(){
     if(this.phoneNumber.length === 11){
       this.verifyCodeButtonEnable=true
     }else {
       this.verifyCodeButtonEnable=false
     }
   }
  async sending_verifyCode(){
    try { //调用方式异步调用
      await cloud.auth().requestVerifyCode({
        verifyCodeType: {
          kind: 'phone',
          phoneNumber: this.phoneNumber,
          countryCode: '86'
        },
        action: VerifyCodeAction.REGISTER_LOGIN, //验证的方式
        lang: 'zh_CN',
        sendInterval: 10
      })
      hilog.info(0,'VerifCode','Success')
    } catch (e) {
      AlertDialog.show({ title: '错误', message: '验证码失败' })//弹窗内容
      hilog.info(0,'VerifCode',JSON.stringify(e))
    }
  }
  async login_verify(){
    try {
      const result  = await cloud.auth().signIn({ //定义一个变量来接收它的返回结果,返回的是result,在通过result.gitUsr获取用户信息
        credentialInfo: {
          kind: 'phone',
          countryCode: '86',
          phoneNumber: this.phoneNumber,
          verifyCode: this.verifyCode
        }
      })
      const user = result.getUser()
      AppStorage.SetOrCreate('user',user)//存储用户到 AppStorage
      hilog.info(0,'Login','Success')
      router.replaceUrl({ url: 'pages/MyLoginLignOut' })
    } catch (e) {
      AlertDialog.show({title:'错误',message:'登陆失败'})
      hilog.info(0,'Login',JSON.stringify(e))
    }
  }


  build() {
    Row() {
      Column() {
        TextInput({placeholder:'请输入手机号'})
          .type(InputType.Number)
          .onChange(values =>{
          this.phoneNumber = values
            this.judgement()//点击获取验证码时,判断按键是否可用
        })
       Row(){
         TextInput({placeholder:'验证码'})
           .width('70%')
           .onChange(value =>{
             this.verifyCode=value
           })
         Button(this.verifyCodeButtonText)
           .width('30%')
           .enabled(this.verifyCodeButtonEnable)//该属性是控制按键是否可用
           .onClick(async () =>{ //所在方法加async
             this.waiting()
             this.sending_verifyCode()
           })
       }
        .width('100%')
        Button('登录')
          .enabled(this.phoneNumber.length === 11 && this.verifyCode.length === 6)//手机号11位,且验证码六位时点击登录才有效
          .onClick(async ()=>{
            this.login_verify()
          })

      }
      .width('100%')

    }
    .height('100%')
  }

}

登录后跳转到的页面:

import cloud ,{AuthUser}from "@hw-agconnect/cloud"
import hilog from '@ohos.hilog'
import router from '@ohos.router'
@Entry
@Component
struct MyLoginLignOut {
  @State photoUrl:string = '' //存储头像路径
  @State displayName:string = '' //存储用户昵称
  @StorageLink('user') user:AuthUser = null //定义一个AuthUser的类型来获取用户存的值,('user')叫存储对象名,是在另一个页面定义的名字
aboutToAppear(){//build渲染前就运行
  //1.cloud.auth().getCurrentUser()
  //2.appStorage
  this.displayName = this.user.getDisplayName()//获取用户,间接通过用户拿到用户头像等数据。
  this.photoUrl = this.user.getPhotoUrl()
}
  build() {
    Row() {
      Column() {
        Row(){
          Image(this.photoUrl?this.photoUrl:$r('app.media.app_icon'))
            .width(80)
            .height(80)
            .onClick(()=>{
              this.photoUrl= 'https://img.btstu.cn/api/images/5a2a5d5560223.jpg'
            })
        }.width('100%')
        .justifyContent(FlexAlign.Center)
        .padding({bottom:70})


        TextInput({placeholder:'设置昵称',text:this.displayName})
          .fontSize(25)
          .fontWeight(FontWeight.Bold)
          .onChange(value =>{
            this.displayName = value
          })
        Button('保存')
          .margin({top:10,bottom:10})
          .width(90)
          .onClick(async ()=>{//保存图片与用户名

            try {
              await this.user.updateProfile({//保存头像、用户名
                displayName: this.displayName,
                photoUrl: this.photoUrl
              })
              hilog.info(0,'updateProfile','Success')
            } catch (e) {
              hilog.info(0,'updateProfile',JSON.stringify(e))
            }
          })
        Button('登出')
          .margin({top:10,bottom:10})
          .width(90)
          .onClick(async ()=>{
            try {
              await cloud.auth().signOut()
              hilog.info(0,'SignOut','Success')
              router.replaceUrl({url:'pages/MyLogin'})
            } catch (e) {
              hilog.info(0,'SignOut',JSON.stringify(e))
            }
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

个人设置中心

import cloud, { AuthUser } from '@hw-agconnect/cloud'
import router from '@ohos.router'
import hilog from '@ohos.hilog'
import picker from '@ohos.file.picker'

@Entry
@Component
struct MyIndex {
  @State photoUrl: string = '' //存储头像路径
  @State displayName: string = '' //存储用户昵称
  @StorageLink('user') user: AuthUser = null //定义一个AuthUser的类型来获取用户存的值,('user')叫存储对象名,是在另一个页面定义的名字
  @State uploading: boolean = false//用户控制图片是否可以点击,上传时不可以点击
  @State uploadingText: string = '0%'//上传进度

  aboutToAppear() {  //build渲染前就运行
    // 1. cloud.auth().getCurrentUser()
    // 2. AppStorage
    this.displayName = this.user?.getDisplayName()//获取用户,间接通过用户拿到用户头像等数据。加问号是因为在aboutToAppear运行时是无法获取用户名或图片等信息的
    this.photoUrl = this.user?.getPhotoUrl()
  }

  build() {
    Row() {
      Column({ space: 10 }) {
        Stack() {//Stack该属性让它所包含的组件重叠
          Image(this.photoUrl ? this.photoUrl : $r('app.media.user_dark'))
            .width(70)
            .height(70)
            .borderRadius(70)
            .enabled(!this.uploading)
            .onComplete(()=>{
              this.uploading = false
            })
            .onClick(async () => {
              // this.photoUrl = '网络图片的地址'
              try {
                // 1. 从相簿中选照片
                const options = new picker.PhotoSelectOptions()
                options.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE//媒体类型:视频还是图片
                options.maxSelectNumber = 1//最大选择个数
                const result = await new picker.PhotoViewPicker().select(options)//把参数传给下面的方法,把结果传给result
                hilog.info(0, 'Upload', `Picker Success ${result.photoUris[0]}`)
                this.uploading = true
                // 2. 调云存储 api 上传照片
                await cloud.storage().upload({
                  localPath: result.photoUris[0],//本地图片路径
                  cloudPath: `test/${this.user.getUid()}.jpg`,//云存储那边存储的路径
                  onUploadProgress: event => {
                    const percent = Math.floor(100 * event.loaded / event.total)//获取上传的百分比,event.loaded:已上传的自己数,event.total:总的自己数,Math.floor:舍弃小数点
                    this.uploadingText = `${percent}%`  //数值更新到uploadingText
                  }
                })
                hilog.info(0, 'Upload', 'Upload Success')
                // 3. 获取上传照片的网络地址
                const url = await cloud.storage().getDownloadURL(`test/${this.user.getUid()}.jpg`)//获取公网地址,拿到图片在网络上的地址
                this.photoUrl = `${url}&ts=${new Date().getTime()}`//这个里做这个处理是因为,图片被缓存起来了,上传的时候如果只是给云存储的地址,那么在传第二张图片到云存储后,photoUrl再获取时,因为图片地址不变照片也不会改变,它会缓存起来,而在图片后面加上一个时间图片就不在被缓存。
                // this.uploading = false
                hilog.info(0, 'Upload', `url: ${url}`)
              } catch (e) {
                hilog.error(0, 'Upload', JSON.stringify(e))
              }
            })
          if (this.uploading) {
            // 显示上传进度
            Text(this.uploadingText)
              .width(70)
              .height(70)
              .borderRadius(70)
              .fontColor('white')
              .backgroundColor('black')
              .opacity(0.6)
              .fontSize(24)
              .fontWeight(FontWeight.Bolder)
              .textAlign(TextAlign.Center)//文字对齐方式
          }
        }


        TextInput({ placeholder: '请设置昵称', text: this.displayName })
          .width('50%')
          .onChange(value => {
            this.displayName = value
          })
        Button(`保存`)
          .onClick(async () => {
            try {
              await this.user.updateProfile({
                displayName: this.displayName,
                photoUrl: this.photoUrl
              })
              hilog.info(0, 'updateProfile', 'Success')
            } catch (e) {
              hilog.error(0, 'updateProfile', JSON.stringify(e))
            }
          })
        Button(`登出`)
          .onClick(async () => {
            try {
              await cloud.auth().signOut()
              hilog.info(0, 'SignOut', 'Success')
              router.replaceUrl({ url: 'pages/MyLoginCustom' })
            } catch (e) {
              hilog.error(0, 'SignOut', JSON.stringify(e))
            }
          })

      }
      .width('100%')
    }
    .height('100%')
  }
}

登录页面

import { Auth, VerifyCodeAction } from '@hw-agconnect/cloud';
import cloud from '@hw-agconnect/cloud'
import hilog from '@ohos.hilog'
import router from '@ohos.router';
@Entry
@Component

struct MyLogin {
  @State countDown: number = 10
//用一个变量来获取setinterval的ID
  intervalId:number = 0 //因为这个变量与页面显示无关所以不用@State注释
  @State verifyCodeButtonEnable:boolean = false
  @State verifyCodeButtonText:string ='获取验证码'
  @State phoneNumber: string = ''
  @State verifyCode:string = '输入验证码'
  private mainPage = `pages/StudentPage`

  async aboutToAppear() {
    try {
      const user = await cloud.auth().getCurrentUser()//获取当前认证用户
      if (user != null) {//获取用户是否为空,如果用户已经断开会话,则下一次进入时间走时登录流程
        AppStorage.SetOrCreate('user', user) // 如果会话未断开,不走登录流程,而是吧用户数据存到AppStorage
        router.replaceUrl({ url: this.mainPage })
      }
    } catch (e) {
      hilog.error(0, 'Login', JSON.stringify(e))
    }
  }
  //定时器代码
  waiting(){
    this.verifyCodeButtonEnable = false
    this.verifyCodeButtonText = `${this.countDown}s`//在一点击时,就显示10S
    this.intervalId = setInterval(() => { //要知道定时器结束没有需要知道它的返回结果,这个结果可以通过setinterval的ID获取。
      this.verifyCodeButtonText = `${this.countDown}s`//将倒计时显示出来
      if(this.countDown < 0){
        //如果减到0,清楚定时器
        clearInterval(this.intervalId)//得到返回结果后清楚定时器
        this.countDown = 10
        this.intervalId = 0
        this.verifyCodeButtonText = '获取验证码'//倒计时结束时回复
        this.verifyCodeButtonEnable = true //当点击时按键不可用
        return //不需要再往下继续执行了,所以return
      }
      this.countDown--
    },1000)//每隔1秒减一次
  }
   judgement(){
     if(this.phoneNumber.length === 11){
       this.verifyCodeButtonEnable=true
     }else {
       this.verifyCodeButtonEnable=false
     }
   }
  async sending_verifyCode(){
    try { //调用方式异步调用
      await cloud.auth().requestVerifyCode({
        verifyCodeType: {
          kind: 'phone',
          phoneNumber: this.phoneNumber,
          countryCode: '86'
        },
        action: VerifyCodeAction.REGISTER_LOGIN, //验证的方式
        lang: 'zh_CN',
        sendInterval: 10
      })
      hilog.info(0,'VerifCode','Success')
    } catch (e) {
      AlertDialog.show({ title: '错误', message: '验证码失败' })//弹窗内容
      hilog.info(0,'VerifCode',JSON.stringify(e))
    }
  }
  async login_verify(){
    try {
      const result  = await cloud.auth().signIn({ //定义一个变量来接收它的返回结果,返回的是result,在通过result.gitUsr获取用户信息
        credentialInfo: {
          kind: 'phone',
          countryCode: '86',
          phoneNumber: this.phoneNumber,
          verifyCode: this.verifyCode
        }
      })
      const user = result.getUser()
      AppStorage.SetOrCreate('user',user)//存储用户到 AppStorage
      hilog.info(0,'Login','Success')
      router.replaceUrl({ url: 'pages/MyLoginLignOut' })
    } catch (e) {
      AlertDialog.show({title:'错误',message:'登陆失败'})
      hilog.info(0,'Login',JSON.stringify(e))
    }
  }


  build() {
    Row() {
      Column() {
        TextInput({placeholder:'请输入手机号'})
          .type(InputType.Number)
          .onChange(values =>{
          this.phoneNumber = values
            this.judgement()//点击获取验证码时,判断按键是否可用
        })
       Row(){
         TextInput({placeholder:'验证码'})
           .width('70%')
           .onChange(value =>{
             this.verifyCode=value
           })
         Button(this.verifyCodeButtonText)
           .width('30%')
           .enabled(this.verifyCodeButtonEnable)//该属性是控制按键是否可用
           .onClick(async () =>{ //所在方法加async
             this.waiting()
             this.sending_verifyCode()
           })
       }
        .width('100%')
        Button('登录')
          .enabled(this.phoneNumber.length === 11 && this.verifyCode.length === 6)//手机号11位,且验证码六位时点击登录才有效
          .onClick(async ()=>{
            this.login_verify()
          })

      }
      .width('100%')

    }
    .height('100%')
  }

}

希望文档对你有所帮助。

附件

8.如何用旧电脑搭建自己的服务器?

拥有一个属于自己的服务器个人感觉就很赞,我最初是在不买公网IP情况下,用一台电脑做服务器,然后另外一台电脑可以远程访问,部署网站,然后别人可以访问这个网站,这样一个功能。如果你也有这样的想法还请阅读下去,希望自己的经验对你有所帮助。

所需设备

一台旧电脑,一台目前在使用的电脑。

在旧电脑上安装natapp程序

在百度上搜索NATAPP,或点击这个链接:NATAPP,

网站首页面 网站首页面

进入网站后先简单注册一下用户,顺便实名认证一下,因为买隧道会提示需要实名,接着点击首页下载自己的电脑系统对应版本,我的是Windows(下面的测试也是基于Windows)

下载页面 下载页面

下载好后解压文件,得到如下图程序:

下载页面 下载页面

在解压文件下新建一个文件: config.ini,做好这一步后我们去购买免费的隧道,如下图:

下载页面 下载页面

点击网站的文档,然后点击教程/文档里的 使用本地配置文件config.ini 文章,

下载页面 下载页面

然后复制里面的配置信息:

下载页面 下载页面

#将本文件放置于natapp同级目录 程序将读取 [default] 段
#在命令行参数模式如 natapp -authtoken=xxx 等相同参数将会覆盖掉此配置
#命令行参数 -config= 可以指定任意config.ini文件
[default]
authtoken=                      #对应一条隧道的authtoken
clienttoken=                    #对应客户端的clienttoken,将会忽略authtoken,若无请留空,
log=none                        #log 日志文件,可指定本地文件, none=不做记录,stdout=直接屏幕输出 ,默认为none
loglevel=ERROR                  #日志等级 DEBUG, INFO, WARNING, ERROR 默认为 DEBUG
http_proxy=                     #代理设置 如 http://10.123.10.10:3128 非代理上网用户请务必留空

在字段authtoken后面值在我的隧道配置里可以找到,如下:

下载页面 下载页面

复制下图authtoken的值填到config.ini文件里

下载页面 下载页面

我这边演示的效果如下:

下载页面 下载页面 下载页面 下载页面

完成上面的操作后,我们运行NATAPP程序,结果如下:

下载页面 下载页面

你会得到一个随机的网址,这个网址指向你的本地端口,当你有网站挂载到本地端口时,你就可以通过网址访问到你的本地端口网址,内网外网都可以,但是这个网址每一次运行都会不一样,这点需要注意,然后就是端口的设置,看下图:

下载页面 下载页面

我这里写的的端口是1313,如果你网站运行后不在1313,例如你运行网站后,本地的网站启动端口是8080.那你就把这个地方的1313改为8080就可以了。

下面我们举个例子看看,假设我现在我需要外网的网友访问我挂在在自己电脑本地的网站,那们在做好上面的操作后我先去启动自己的网站,这里使用hugo的网站模版,用code程序打开网站模版,然后调出终端,在终端输入命令 hugo server ,表示启动网站,如下图:

下载页面 下载页面

然后去复制刚才运行NATAPP程序后的网站,在浏览器中打开,我们先试一下局域网能不能访问,结果如下:

下载页面 下载页面

将网站发给自己的朋友,测试外网是否可以访问,

下载页面 下载页面

结果是外网可以正常可以访问。

下载页面 下载页面

那么到这里你的电脑其实就充当了一台服务器,将网站放到了你电脑上,只要你的电脑保持开机状态那么别人就可以一直访问你的网站,或许NATAPP网站还有别的有趣功能,所以你不妨去摸索摸索,所不定可以找到多次启动NATAPP指向你本地的网址不变,你也就不用每次启动后都要发新的网址给对方了。

那么其实到这里就差不多了,但是我们还需要用一台电脑控制另一台电脑,简而言之就是电脑的远程登录,其实电脑远程登录有许多的方法,这里我需要借助一个来实现内网穿透,其实上面的旧电脑变服务器也是使用了内网穿透,

附件

10.如何自定义hugo主题页面输出格式?

**声明:**需要注意文章只提供思路,当处理一些复杂问题时可能需要变换思路,所以请根据自身情况选择是否阅读本篇文章。

因本人没学过go语言,所以大部分代码都交由AI编写,不排除代码可能存在隐患。

接下来我以自己使用的hugo-theme-relearn主题为例,讲解如何自定义康奈尔笔记页面输出格式。(hugo-theme-relearn主题

工程目录结构

your-blog/
├── archetypes/
│   └── cornell-notes.md        # 笔记原型模板
├── layouts/
│   ├── cornell-notes/
│   │   └── views/
│   │       └── article.html    # 页面布局模板
│   ├── partials/
│   │   ├── cornell-notes.html  # 内容输出逻辑
│   │   └── custom-header.html  # 自定义样式表
│   └── shortcodes/
│       ├── cues.html           # 左侧标签短代码
│       ├── notes.html          # 右侧内容短代码
│       └── summary.html        # 底部总结短代码
└── static/
    └── images/
        └── cornell-img/
            ├── icon1.svg       # 右侧装饰图标
            ├── icon2.svg       # 左侧装饰图标
            └── watermark.jpg   # 底部背景图

功能实现全流程

具体需求

我想输出一个左侧写标签,右侧写内容,最底下显示写总结的“康奈尔笔记”页面,使用命令:

hugo new --kind cornell-notes learning/algorithm/_index.md

创建.md文档后,md文件自动展示为如下格式:

  +++
  title = "{{ replace .Name "-" " " | title }}"
  type = "cornell-notes"
  date = {{ .Date }}
  draft = true
  +++

  {{% cues %}}
  写标签区域

  {{% /cues %}}

  {{% notes %}}
  写内容区域
  {{% /notes %}}

  {{% summary %}}
  总结区域
  {{% /summary %}}

当识别到短代码{{% cues %}}时,将{{% cues %}} {{% /cues %}}中的内容显示在标签一侧,剩下的依次类推。

样式定义

注意:假设自己的主题目录为your-blog,那么接下来的文件创建都该目录下,可参考目录结构

创建 layouts/partials/custom-header.html遇到没有的目录或文件请自行创建,下同,所以不再提示!!

<style>
/* 康奈尔笔记容器 */
.cornell-notes {
  padding: 20px;
  margin: 15px 0;
  display: flex;
  flex-wrap: wrap;
  background: #f9f9f9;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

/* 左侧标签区 */
.cues {
  background: url('/images/cornell-img/icon2.svg') no-repeat 95% 20px;
  border-right: 2px dashed #ccc;
  flex: 1;
  padding-right: 25px;
  min-width: 250px;
}

/* 右侧内容区 */
.notes {
  background: url('/images/cornell-img/icon1.svg') no-repeat 5% 20px;
  border-left: 2px dashed #ccc;
  flex: 2;
  padding-left: 25px;
  min-width: 300px;
}

/* 底部总结区 */
.summary {
  width: 100%;
  clear: both;
  padding: 20px;
  margin-top: 20px;
  background: url('/images/cornell-img/watermark.jpg') center/cover;
  border-radius: 6px;
  position: relative;
}

/* 响应式适配 */
@media (max-width: 768px) {
  .cornell-notes {
    flex-direction: column;
  }
  .cues, .notes {
    border: none;
    padding: 15px 0;
  }
}
</style>

短代码开发

​1.​左侧标签区​​ (layouts/shortcodes/cues.html):

{{ $scratch := .Page.Scratch >}}
{{ $scratch.Set "cuesContent" ( .Inner | markdownify ) }}

2.右侧内容区:(layouts/shortcodes/notes.html):

{{ $scratch := .Page.Scratch }}
{{ $scratch.Set "notesContent" ( .Inner | markdownify ) }}

3.底部总结区:(layouts/shortcodes/summary.html):

{{ $scratch := .Page.Scratch }}
{{ $scratch.Set "summaryContent" ( .Inner | markdownify ) }}

页面样式

创建页面样式 layouts/partials/cornell-notes.html

<div class="cornell-content">
  /*{{/* 初始化存储空间 */}}
  {{ .Scratch.Delete "cuesContent" }}
  {{ .Scratch.Delete "notesContent" }}
  {{ .Scratch.Delete "summaryContent" }}*/
  
  {{/* 触发短代码解析 */}}
  {{ $dummy := .Content }}
  
  {{/* 结构化输出 */}}
  <div class="cues-section">
    {{ with .Scratch.Get "cuesContent" }}
      <div class="cues-header">📌 关键标签</div>
      <div class="cues-body">{{ . | safeHTML }}</div>
    {{ else }}
      <div class="warning">⚠️ 未检测到标签内容</div>
    {{ end }}
  </div>

  <div class="notes-section">
    {{ with .Scratch.Get "notesContent" }}
      <div class="notes-header">📝 学习记录</div>
      <div class="notes-body">{{ . | safeHTML }}</div>
    {{ else }}
      <div class="warning">⚠️ 未检测到笔记内容</div>
    {{ end }}
  </div>

  <div class="summary-section">
    {{ with .Scratch.Get "summaryContent" }}
      <div class="summary-header">✨ 学习总结</div>
      <div class="summary-body">{{ . | safeHTML }}</div>
    {{ else }}
      <div class="warning">⚠️ 未检测到总结内容</div>
    {{ end }}
  </div>
</div>

页面内容输出逻辑

创建 layouts/cornell-notes/views/article.html

<article class="cornell-notes">
  {{ partial "cornell-notes.html" . }}
</article>

此处就是系统将自动调用了我们之前写的layouts/partials/cornell-notes.html文件,将内容输出到这个容器中。

实际效果如下alt text alt text

为了丰富页面你可以设置标题、页脚等显示样式,这些你使用的主题一般会提供,如我这里的:

<article class="cornell-notes">
  <header class="headline">
    {{partial "content-header.html" .}}
  </header>
  {{partial "heading-pre.html" .}}{{partial "heading.html" .}}{{partial "heading-post.html" .}}
  {{partial "cornell-notes.html" .}}

  <footer class="footline">
    {{partial "content-footer.html" .}}
  </footer>
</article>

代码说明如下(都是基于我使用的主题,可不看):

1.从上而下,article容器的class值为cornell-notes,这个值在layouts/partials/custom-header.html中,这是之前编写页面布局时写的,此处调用该cornell-notes样式:

<article class="cornell-notes">

alt text alt text

2.编写内容顶栏代码,如果项目未提供就自己创建一个,同样放地,放在layouts/partials/custom-header.html中,因此次使用主题自带故不再创建。当然,你也可以选择不写。

<header class="headline">
    {{partial "content-header.html" .}}
  </header>

对于标题设置:

{{partial "heading-pre.html" .}}{{partial "heading.html" .}}{{partial "heading-post.html" .}}

页脚设置:

<footer class="footline">
    {{partial "content-footer.html" .}}
  </footer>

依实际需求而定,可写可不写

3.总而言之,如果你只是输出之前需求的页面,那么可以只写这句代码:

<article class="cornell-notes">
  {{ partial "cornell-notes.html" . }}//就加了这句
</article>

{{ partial "cornell-notes.html" . }}这里就是去调用我们之前写的layouts/partials/cornell-notes.html文件,将内容输出到这个容器中。还记得吗?这个文件是我们写完短代码后写的文件,目的是将内容按照要求输出。

原型模板创建

我们在创建页面时,如果使用命令:

hugo new --kind cornell-notes log/cornell-notes/_index.md

这个命令会自动创建一个archetypes/cornell-notes.md模型的文件,实现这一操作你需要先创建layouts/cornell-notes/views/article.html,这一操作在上面已经完成,接下来只需要创建archetypes/cornell-notes.md文件即可。值得注意的是无论是命令、还是layouts、archetypes文件下,都提到了cornell-notes这个名字,所以创建时留意名字需要相同

这里小结这一思路:

  • layouts/[fileName]/views/article.html中编写页面输出逻辑。
  • layouts/[fileName].md中编写文件模版
  • 使用命令hugo new --kind [fileName] [path]生成模版文件

接下来是详细操作:

1.创建archetypes/cornell-notes.md文件:

  +++
  title = "{{ replace .Name "-" " " | title }}"
  type = "cornell-notes"
  date = {{ .Date }}
  draft = true
  +++

  {{% cues %}}
  写标签区域

  {{% /cues %}}

  {{% notes %}}
  写内容区域
  {{% /notes %}}

  {{% summary %}}
  总结区域
  {{% /summary %}}

2.使用方式

​​生成模版文件​​:

hugo new --kind cornell-notes learning/algorithm/_index.md

实际效果图:

alt text alt text

需要注意的是写模版文件的时候是依据你个人需求而定的,例如创建layouts/[fileName]/views/article.html这样的文件,在有些主题可能是layouts/partials/[fileName]/article.html,又如,此处md文件头部模版为:

+++
  title = "{{ replace .Name "-" " " | title }}"
  type = "cornell-notes"
  date = {{ .Date }}
  +++

而有些则是以:

  ---
    title = "{{ replace .Name "-" " " | title }}"
    archetype = "cornell-notes"
    date = {{ .Date }}
  ---

旨在告诉你编写形式各不相同,所以清楚这一思路即可。要避免这些坑请结合主题的说明文档帮助查看

总结

最后的最后做个总结,要想自定义hugo主题页面输出格式,你可以按照如下步骤展开:

  • 确定需求,不会写代码让AI完成。
  • 如果有需要请编写段代码。
  • 编写输出逻辑,如果不会还请求助社区、AI等。
  • 编写页面模板,参照以上思路,同时参考自己hugo主题的文档说明

12.使用望言OCR与Aegisub,实现字幕识别、提取和自定义

效果图

  • 使用望言OCR alt text alt text
  • Aegisub alt text alt text

简介

望言OCR是一款强大的OCR工具,可以帮助你识别视频中的字幕,并导出为.ass字幕文件。然后,你可以使用Aegisub进行字幕编辑和自定义。

说明

  1. 使用望言OCR注意两个点:
  • 资金问题。想用免费版推荐v1.2.0版本,对于长视频速度可能会慢一些,支持的语言以及功能也比较少。如果想快速识别,体验更多功能,比如多语言识别,推荐使用付费版,如v1.3.0版本。
  • 显卡要求。GitHub上作者提到使用3060级别显卡。以我个人的为例,在免费版的情况下,N显卡3050ti也可以轻松应对7分钟视频,大概花费1分钟,如果显卡性能较差,识别速度会慢很多。

更多推荐去GitHub上浏览查看:https://github.com/nhjydywd/SubtitleOCR

  1. Aegisub使用说明:
  • Aegisub是一款强大的字幕编辑软件,可以帮助你编辑和自定义字幕。你可以使用Aegisub来调整字幕的位置、大小、颜色、字体等属性,还可以添加特效和动画效果。
  • Aegisub的安装和使用非常简单,只需要下载安装包,然后按照提示进行安装即可。安装完成后,你可以打开Aegisub,然后导入字幕文件,进行编辑和自定义。

下载

13.win11安装WSL详细步骤

记录如何使用WSL在win11上安装Linux子系统。启动方便快捷,而且可以切换多个Linux发行版本,以及随时删除,占用内存也不大。

先决条件

检查CPU虚拟化是否开启

alt text alt text

打开启用或关闭Windows功能

  • 开启虚拟机平台(如果有)
  • 开启适用于Linux的Windows子系统

alt text alt text

使用WSL安装Linux子系统

(1)打开powershell,安装子系统

wsl --install --web-download

如果有提示重启,重启即可。

(2)查看下载内容:

wsl --list

适用于 Linux 的 Windows 子系统分发:
Ubuntu (默认)

(3)第一次启动Linux子系统,创建用户并设置密码。

wsl -d Ubuntu #启动Ubuntu

exit #退出Ubuntu

(4)安装其他Linux发行版

wsl --list --online #查看可安装版本
wsl --install -d Debian #安装Debian

(5)设置默认启动的Linux发行版

默认启动的版本使用wsl --list -v查看当前安装的版本,前面有*号的就是默认版本,更改的方法是:

wsl --set-default [Linux发行版名称]

简单的启动与关闭方式

关闭powershell,再次打开,展开命令提示符,可以快速启动Linux子系统。

alt text alt text

关闭也很简单,点击启动页面的X号即可。 alt text alt text

wsl.config与.wslconfig的配置

(1)wsl.config

  • 作用:用于配置 WSL 内部(即 Linux 子系统内)的行为,比如挂载方式、自动挂载的驱动器、网络等。
  • 位置:位于每个 WSL 发行版的 Linux 根目录下的 /etc/wsl.conf 文件(注意不是 Windows 下的 wsl.config)。
  • 生效范围:只影响当前 Linux 发行版。
  • 此次配置内容(有其他配置,详细看官网文档):
[boot]
systemd=true #启动时自动挂载驱动器

(2).wslconfig

  • 作用:用于配置 WSL2 虚拟机的全局行为,比如分配给 WSL2 的内存、CPU 数量、交换空间等。
  • 位置:位于 Windows 用户主目录下(如 C:\Users\你的用户名.wslconfig)。
  • 生效范围:影响所有 WSL2 发行版(全局设置)。
  • 此次配置(有其他配置,详细看官网文档):
[wsl2]
networkingMode=mirrored #网络模式为桥接模式,使电脑IP地址与Linux子系统IP地址一致

这样你的 Windows 和 WSL2 子系统会使用相同的网络(IP 地址段),WSL2 的网络行为会更像物理机或虚拟机桥接,方便与局域网其他设备通信。

卸载Linux子系统

wsl --list -v #查看当前安装的版本
wsl --unregister [Linux发行版名称]

更改Ubuntu存储路径(通过 wsl –import 手动指定路径)

#查看当前安装的版本
wsl --list -v 

# 导出发行版(如Ubuntu)到tar文件
wsl --export Ubuntu D:\wsl-images\ubuntu.tar

# 注销原始发行版(释放默认路径)
wsl --unregister Ubuntu

# 重新导入到自定义路径(例如 D:\wsl\ubuntu)
wsl --import Ubuntu D:\wsl\ubuntu D:\wsl-images\ubuntu.tar --version 2

可能出现的问题,Ubuntu图标不显示,启动windows时报错找到一个带有无效"icon" 的配置文件。将该配置文件默认为无图标。确保设置"icon" 时,该值是图像的有效文件路径。 alt text alt text

解决办法:

(1)打开powershell,点击设置: alt text alt text

(2)按照如下图选择图标路径(一般情况下,启动过一次导出的Ubuntu,导出的目录下会有该图标,如果没有请自己添加一个) alt text alt text

卸载Linux子系统、WSL和相关组件

卸载Linux相关子系统的方法参考上文提到的卸载linux子系统

卸载好后进入Microsoft Store商店————>库,搜索Linux删除应用残留。如下图: alt text alt text

或者使用命令删除:

Get-AppxPackage *Ubuntu* | Remove-AppxPackage  # 以 Ubuntu 为例

卸载WSL功能模块

1.关闭 WSL 和虚拟机平台​

# 关闭 WSL 功能(需重启)
dism.exe /online /disable-feature /featurename:Microsoft-Windows-Subsystem-Linux

# 关闭虚拟机平台(影响 Hyper-V/安卓子系统)
dism.exe /online /disable-feature /featurename:VirtualMachinePlatform

2.​​移除 Windows 可选功能​

按 Win+R 输入 optionalfeatures → 取消勾选:

  • ​适用于 Linux 的 Windows 子系统​​;
  • ​虚拟机平台​。

清理残留文件

1.​​删除用户级数据​

# 删除 WSL 虚拟机文件(占用最大)
rm -Recurse -Force "$env:USERPROFILE\AppData\Local\Packages\*Linux*"

# 清理系统级数据
rm -Recurse -Force "$env:ProgramData\Microsoft\Windows\WindowsApps\*Linux*"

2.​​清理磁盘镜像文件​​,手动删除 WSL 虚拟硬盘文件(默认位置):

%USERPROFILE%\AppData\Local\Packages\CanonicalGroupLimited*\LocalState\ext4.vhdx

验证是否卸载干净

# 检查 WSL 状态
wsl --status  # 应提示“未安装 WSL”

# 检查残留进程
Get-Process *wsl*  # 无结果即为成功

参考资料

【1】WSL 文档 【2】超详细的WSL教程:Windows上的Linux子系统.mp4

14.Win11安装Docker详细教程

写在前

本篇文章参考了B站UP的视频,视频链接:【B站】

什么是 Docker?

Docker 是一个开源的容器化平台,用于打包、分发和运行应用程序。它可以把应用及其所有依赖(如代码、运行环境、库等)打包到一个“容器”中,使应用能够在任何支持 Docker 的环境中快速、一致地运行。

Docker 的主要用途:

  • 环境隔离:每个容器都是独立的,互不影响,避免“在我电脑上能跑”的问题。
  • 快速部署:应用和环境一次打包,到处运行,极大简化部署流程。
  • 持续集成/持续交付(CI/CD):方便自动化测试、构建和部署。
  • 资源高效:容器比虚拟机更轻量,启动速度快,占用资源少。
  • 微服务架构:每个服务可以单独打包成容器,方便扩展和维护。

简单来说,Docker 让开发、测试、部署应用变得更简单、更高效、更可靠。

下载 Docker desktop

下载链接:【GitHub仓库】

安装 Docker desktop

方法1:下载后点击exe直接安装,默认安装在C盘。

方法2:自定义安装路径

下载的安装包名字为docker_desktop_installer_windows_x86_64.exe,则使用下面的命令安装:

start /w "" "docker_desktop_installer_windows_x86_64.exe" install --installation-dir=D:\Docker

然后等待安装完成即可。

配置 Docker desktop

alt text alt text

添加如下代码:

{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://docker.1panel.live",
    "https://hub.rat.dev"
  ]
}

测试案例1:hello-world

打开cmd/powershell,输入如下命令:

docker run hello-world

显示Hello from Docker!,说明安装成功:

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

测试案例2:安装nginx:alpine

打开cmd/powershell,输入如下命令:

docker run -d -p 8080:80 --name my-nginx nginx:alpine

注意:为了防止端口冲突,可以先检擦下8080端口是否被占用:

netstat -ano | findstr :8080

如果显示LISTENING,则说明被占用,你可以关掉该端口:

#强制终止 PID,下面的 11432 是监听的进程号
taskkill /PID 11432 /F

# 验证端口是否释放
netstat -ano | findstr :8080

或者改用别的端口,如果你已经先执行了docker run -d -p 8080:80 --name my-nginx nginx:alpine,那么建议你先关闭容器,接着删除容器,然后重新指定别的端口。

然后打开浏览器,输入http://localhost:8080 ,页面会显示nginx的欢迎页面。

一些基本操作命令

docker pull 镜像名  # 下载镜像
docker run -it 镜像名 # 运行镜像
docker ps -a         # 查看所有容器
docker start 容器id  # 启动容器


docker stop 容器id   # 停止容器
docker rm 容器id     # 删除容器
docker rmi 镜像id    # 删除镜像,停止和删除容器后才能删除镜像

对于启动的容器,可以使用dockerUI界面进行管理,如运行,停止,删除等操作。如下图: alt text alt text

15.win10电脑忘记密码无法登录怎么办

简介

最近再给一个10年前的联想电脑装系统的时候,发现忘记密码了,用户还是管理员(Administrator),将这个问题发给Deepseek后得到了下面的解决办法,为此记录这个过程,经过一番折腾最终也是解决了问题,但是过程很像重装系统的前半流程

本文的解决的重置密码,最终需要进入下面这个界面,然后点击修复计算机(R),如果你有别的办法进入下面这个页面,请直接跳到本篇文章打开命令提示符进行设置,然后继续操作。 alt text alt text

涉及工具

  • 2台电脑:忘记密码的电脑,一台可以正常登录的电脑;
  • 大于8G的U盘(U盘内有数据要提前备份);
  • win10安装媒体:下载地址 alt text alt text

操作步骤

前面已经提到有部分流程与重装系统流程类似,说的就是下面的内容

运行重置工具

(1)点击下载好的MediaCreationTool.exe,并同意条款。 alt text alt text alt text alt text

(2)选择为另一台电脑创建安装介质(U盘、DVD或ISO文件),并下一步。 alt text alt text

(3)下面三项需要根据你的实际情况选择,然后点击下一步: alt text alt text

(4)选择U盘(选择ISO文件也可以),并点击下一步,这一步需要很长一段时间,耐心等待即可。 alt text alt text

(5)选择U盘,点击下一步 alt text alt text

进入重置密码界面

(1)选择从U盘启动

将制作好的U盘插入忘记密码的电脑,重启电脑,按住F12(电脑品牌不同按键不同),在当前的 ​​Boot Menu​​ 界面中,选择U盘启动(​​USB HDD: AI Mass Storage)。

alt text alt text

(2)进入Windows安装/修复界面​​

  • 等待U盘加载完成后,会进入 ​​Windows安装界面​​(蓝底白字),不用选择直接下一步。 alt text alt text
  • ​不要点击“安装”​​!直接点击左下角的 ​​“修复计算机”​​(Repair your computer)。 alt text alt text

[注:若未显示“修复计算机”,重启后重复步骤1]

打开命令提示符进行设置

(1)在修复界面选择:

​​疑难解答(Troubleshoot) → 高级选项(Advanced Options) → 命令提示符(Command Prompt)​ alt text alt text

(2)执行密码重置操作​​

​​替换系统工具(Utilman.exe)​​,输入以下命令,将“轻松使用”按钮替换为命令提示符:

copy c:\windows\system32\utilman.exe c:\
copy c:\windows\system32\cmd.exe c:\windows\system32\utilman.exe

(完成后会提示“已复制1个文件”)

(3)重启电脑

输入如下命令重启电脑:

wpeutil reboot

通过“轻松使用”图标重置密码

​​ 在登录界面右下角,点击 ​​“轻松使用”图标​​(图标为一个小人和时钟)。此时会弹出命令提示符窗口,输入命令重置密码(替换 username 和 newpassword):

net user username newpassword

#例如
net user John 123456

恢复系统文件(重要!)

​​ 登录成功后,以管理员身份打开 ​​新的命令提示符​​(搜索 cmd → 右键以管理员运行)。输入命令还原被替换的文件:

copy c:\utilman.exe c:\windows\system32\utilman.exe

(提示覆盖时输入 Y 确认)

可能出现的问题以及解决

​(1)​U盘启动后直接进入安装界面,没有“修复计算机”选项​​:

  • 重启后重新选择U盘启动,在安装界面仔细寻找左下角的“修复计算机”。
  • 若仍不显示,可能是U盘制作问题,需重新下载官方镜像并制作安装U盘。

​(2)​命令执行后提示“拒绝访问”​​:

  • 确保从修复环境的命令提示符操作(步骤3),而非普通系统内的CMD。 ​ (3)​重置密码后仍无法登录​​:

  • 检查用户名是否输入正确(区分大小写),或尝试启用隐藏管理员账户:

net user Administrator /active:yes

16.如何给电脑装win10系统

目录

简介

如何给一台老的联想笔记本电脑装win10系统,记录整个详细过程,以及遇到的坑,希望对想重装系统的朋友有帮助。

准备工具

Ventoy和Rufus有什么区别?

工具 多系统支持 操作便捷性 兼容性 适用场景
Ventoy 支持 很方便 很好 多系统/频繁更换ISO
Rufus 不支持 一般 极好 单一系统/极致兼容

小结:

  • 想要一个U盘放多个系统镜像,推荐 Ventoy。
  • 只做单一系统启动盘、追求极致兼容性,推荐 Rufus。

此处因为我的电脑太旧了,为确保能成功安装,所以选择Refus制作(vertoy也会介绍如何使用)。

具体操作步骤

制作启动盘

生成镜像文件

如你已有ISO镜像文件,请跳过这个步骤。

(1)运行下载好的MediaCreationTool.exe,同意条款后继续下一步: alt text alt text alt text alt text

(2)选择为另一台电脑创建安装介质(U盘、DVD或ISO文件),并下一步: alt text alt text

(3)下面三项需要根据你的实际情况选择,然后点击下一步: alt text alt text

(4)选择ISO文件(U盘这项我没选,不知道可不可行) alt text alt text

(5)选择镜像文件保存位置。可以直接保存到U盘,也可以选择其他位置,然后点击下一步(这一步需要花费一点时间,请耐性等待): alt text alt text

使用rufus制作启动盘

点击下载好的rufus.exe,做好如图设置,然后点击开始alt text alt text

等待制作完成。

使用ventoy制作启动盘

(1)将镜像文件复制到U盘根目录下。

(2)配置vertoy,安装工具到U盘: alt text alt text

至此,U盘制作完成,接下来就是进入重装系统。

重启电脑

插入忘记密码的那台电脑,重启电脑,按住F12(电脑品牌不同启动不同)。在当前的 ​​Boot Menu​​ 界面中,选择U盘启动(​​USB HDD: AI Mass Storage): alt text alt text

  • 如果选择的是ventoy,则会进入下面的界面: 按下L键,设置语言为中文,显示如下: alt text alt text 点击镜像文件,选择以正常模式启动alt text alt text

然后会跳到​​Windows安装界面​​(蓝底白字)。

  • 如果选择的是rufus,则会直接跳到​​Windows安装界面​​(蓝底白字):

进入Windows安装界面

(1)安装设置

等待画面跳转到 ​​Windows安装界面​​(蓝底白字),按需求选择(我这里默认)直接下一步。 alt text alt text

​点击“现在安装”​​! alt text alt text

(3)选择仅安装Windows,并创建分区

这里因为是重装系统,根据提示信息可知选择第二项: alt text alt text

选择磁盘,并点击删除,注意:这一操作将导致数据被删除,如有需要,请一定要提前备份好数据原始数据。 alt text alt text

以图片中的为例,删除后磁盘总量变为220G,此时选择该磁盘,然后点击下方的新建分区,输入如102400MB,点击应用。 alt text alt text

此时会为你创建三个分区,分别为:

  • 系统分区:100MB
  • MSR(保留):16MB
  • 主分区:99.9GB
  • 未分配空间:123.6GB

未分配空间可以等装完系统后,再进入电脑磁盘管理进行分配。

以上磁盘分配好后,选择主分区磁盘,并点击先一步。后面按照提示操作即可,这里就不再赘述。

遇到的问题

在上面点击 “现在安装” 可能会跳转到一个提示页面,提示:找不到任何设备驱动程序。请确保安装介质包含正确的驱动程序,然后单击“确定”,如下图所示: alt text alt text

这里有三个可能的原因

  • 1.缺少存储控制器驱动
    • Windows安装程序未包含你电脑主板芯片组(如Intel RST/VMD或AMD SATA/RAID驱动)的驱动程序,导致无法识别硬盘或SSD
    • 但是一般电脑要是能识别U盘,那说明驱动没问题。(个人猜测)
  • 2.安装介质问题
    • 制作的U盘有问题,导致无法识别。
  • 3.USB接口兼容性问题
    • U盘接口与电脑USB接口不兼容,导致无法识别。

解决办法

由于缺少驱动这一点需要下载合适的 ​SATA/RAID驱动​​,这部分个人目前没有办法提供相关帮助,此处只提供针对第二、第三种问题的解决办法。

  • 1.更换USB接口(推荐!)
    • 将U盘插入主板背面的 ​​USB 2.0接口​​(黑色接口),避免使用USB 3.0(蓝色接口)。
    • 推荐先尝试这种办法。
  • 2.重新制作U盘
    • 重新制作U盘或选择别的工具重新制作,如rufus,然后重新安装。
  • 3.更换硬盘模式
    • 重启电脑,按F2/del进入BIOS,找到 ​​SATA Mode/Storage Options​​;
    • 将模式从 ​​RAID/VMD​​ 改为 ​​AHCI​​(兼容性更好);
    • 保存设置并重启,重新尝试安装。

总结

以上就是重装系统的流程,主要分为三步:

  • 1.制作启动盘(需要相关工具与镜像文件)
  • 2.进入Windows安装界面
  • 3.清除原始数据(记得备份),选择安装系统。

以上如有错误,欢迎指正,希望本篇文章对你有帮助。