月度归档: <span>2024 年 6 月</span>
月度归档: 2024 年 6 月

js实现列表转成树的一个有意思的方法

js实现列表转成树的一个有意思的方法

原本以为只完成了一层树,发现这样就能生成整棵树,原因可能与内存中的数据结构有关,没有详细考证,就是感觉很神奇,核心代码其实只有两句

const list2Tree = (list = [])=>{
    if(!list.length){
        return []
    }
    list.forEach(el=>{
        if(list.filter(item => item.pid == el.menuId).length){
            el.children = list.filter(item => item.pid == el.menuId)
        }
    })
    return list.filter(el=>el.menuId == 1)
}

koa2框架获取所有接口列表并通过接口暴露

koa2框架获取所有接口列表并通过接口暴露

router.get('/routesList', async(ctx, next)=>{
//这是唯一需要手动修改的,将路由文件的关键字放到这个数组中,再动态拼接路由文件名,之所以这样处理,是因为这样可以更加灵活地控制返回哪些接口数据
  let routerList = ['menu', 'role', 'user']
  let data = []
  routerList.forEach(el => {
      let filePath = '../routes/' + el + '.route'
      let li = {
        catogory: el,
        list:[]
      }
      li.list.push(...require(filePath).stack.map(i => {
        return {
           methods: i.methods,
           url: i.path
            }   
       }))
       data.push(li)
  });
  ctx.body={
    ...Res[0],
    data:data
  }
})

这样,只要请求 /routesList,便可以得到所有接口的列表,按照路由文件进行了分类,这样便于前端展示,是一个简易版的swagger(只有列表,没有参数信息,没有调试,也没有导出),调试接口的话,完全可以通过apifox等工具实现,又好功能又完善

{
    "status": 0,
    "msg": "成功",
    "data": [
        {
            "catogory": "menu",
            "list": [
                {
                    "methods": [
                        "HEAD",
                        "GET"
                    ],
                    "url": "/menu/getAll"
                },
                {
                    "methods": [
                        "HEAD",
                        "GET"
                    ],
                    "url": "/menu/getMenuTree"
                }
            ]
        },
        {
            "catogory": "role",
            "list": [
                {
                    "methods": [
                        "HEAD",
                        "GET"
                    ],
                    "url": "/role/getAll"
                }
            ]
        }
    ]
}

Koa路由中写一个钩子函数,用于萤石云消息触发钉钉机器人webhook

Koa路由中写一个钩子函数,用于萤石云消息触发钉钉机器人webhook

//钉钉机器人的地址
let webhook = 'https://oapi.dingtalk.com/robot/send?access_token=4dd5cd7xxxxxxxxxxxxxxxxxxxxxxxxxxx'
let whiteList = ['xxxx'] //摄像头序列号白名单,只有在白名单里的才促发报警消息,用于过滤
//获取webhook消息并转发到钉钉机器人
async function sendToDingtalk  (ctx,next) {
    await next()
    ctx.request.body = JSON.parse(ctx.request.body)
    console.log('debugger',ctx.request.body.header)
    console.log('debugger',ctx.request.body)
    let {deviceId, messageTime, channelNo, type, messageId} = ctx.request.body.header
    let {channelName, alarmTime, pictureList } = ctx.request.body.body
    console.log('萤石云消息ID:',messageId)
    let data = null
    if(type=='ys.alarm' &&  whiteList.includes(deviceId) ){
        data =  {
        "msgtype": "markdown",
        "markdown": {
            "title": `【告警消息】${channelName}`, 
            "text": `### 设备名称:${channelName} \n #### 设备序列号:${deviceId} \n #### 通道:${channelNo} \n #### 消息类型:${type} \n #### 时间:${alarmTime} \n ![](${pictureList[0].url})`
            }
        }
    }else if(type=='ys.onoffline'){
        data =  {
        "msgtype": "markdown",
        "markdown": {
            "title": `【上下线消息】${channelName}`, 
            "text": `### 设备名称:${channelName} \n #### 设备序列号:${deviceId} \n #### 通道:${channelNo} \n #### 消息类型:${type} \n #### 时间:${alarmTime}`
            }
        }
    }
    // 判断消息类型,然后发送到钉钉webhook
    if(data != null){
        axios.post(webhook,
           data
        ).then(res=>{
            console.log('钉钉调用成功')
            console.log(res.data)
        }).catch(err=>{
            console.error(err)
        })
    }
    
    ctx.body={
        messageId
    }
}

阿里云ddns ipv6解析程序

阿里云ddns ipv6解析程序

由于网上很多资源没有更新,一些接口阿里云方面已经调整,所以,结合这次自己部署经验,记录如下:
程序没有新增,如果没有记录,请手动添加一条。

# -*- coding: utf-8 -*-
# This file is auto-generated, don't edit it. Thanks.
import sys

from typing import List
from Tea.core import TeaCore
from alibabacloud_alidns20150109.client import Client as Alidns20150109Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_alidns20150109 import models as alidns_20150109_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_util.client import Client as UtilClient
from urllib.request import urlopen

class Sample:
    def __init__(self):
        pass

    @staticmethod
    def create_client(
        access_key_id: str,
        access_key_secret: str,
    ) -> Alidns20150109Client:
        """
        使用AK&SK初始化账号Client
        @param access_key_id:
        @param access_key_secret:
        @return: Client
        @throws Exception
        """
        config = open_api_models.Config(
            # 必填,您的 AccessKey ID,
            access_key_id=access_key_id,
            # 必填,您的 AccessKey Secret,
            access_key_secret=access_key_secret
        )
        # 访问的域名
        config.endpoint = f'alidns.cn-hangzhou.aliyuncs.com'
        return Alidns20150109Client(config)

    @staticmethod
    def main(
        args: List[str],
    ) -> None:
        client = Sample.create_client('key', 'scret') #填写自己的key和密钥,在阿里云申请ram调试账号
        runtime = util_models.RuntimeOptions()
        try:
            ip = urlopen('https://api-ipv6.ip.sb/ip').read()  # 使用IP.SB的接口获取ipv6地址
            ipv6 = str(ip, encoding='utf-8')
            
                    #获取子域名的id信息
            describe_sub_domain_records_request = alidns_20150109_models.DescribeSubDomainRecordsRequest(
                    sub_domain='ipv6.zhangdong.site',
                    type='AAAA'
                ) 
            # 复制代码运行请自行打印 API 的返回值
            resp = client.describe_sub_domain_records_with_options(describe_sub_domain_records_request, runtime)
            # res = UtilClient.to_jsonstring(TeaCore.to_map(resp))
            res = TeaCore.to_map(resp)
            print(res['statusCode'])
            if res['body']['TotalCount'] == 0:
                print("未查到AAAA记录,请新增")
            else:
                Record = res['body']['DomainRecords']['Record'][0]
                if Record['Value'] == ipv6.strip() :
                    print('IPv6地址没变无需更改')
                else:
                     #更新域名信息
                    update_domain_record_request = alidns_20150109_models.UpdateDomainRecordRequest( 
                        rr='ipv6',
                        type='AAAA',
                        value= ipv6,
                        record_id=Record['RecordId'])
                    resp= client.update_domain_record_with_options(update_domain_record_request, runtime)
                    res2 = TeaCore.to_map(resp)
                    if res2['statusCode'] == 200:
                        print("修改域名解析成功")
                    else:
                        print(res2)
        except Exception as error:
            # 如有需要,请打印 error
            UtilClient.assert_as_string(error.message)


if __name__ == '__main__':
    Sample.main(sys.argv[1:])

接着添加一个定时任务即可

特色

webdav服务

webdav服务

使用webdav,可以将网络硬盘加载到本地,用起来非常方便。

webdav服务来自hacdias/webdav,使用go编译的,各端程序都有,用法就是准备一个配置文件,然后启动,如果长久使用,就加入系统服务。

添加服务步骤:

  1. 创建一个webdav.service文件

/etc/systemd/system/下创建webdav.service文件

  1. 编辑文件
[Unit]
Description=WebDAV server
After=network.target

[Service]
Type=simple
User=root
ExecStart=/usr/bin/webdav --config /xxx/webdav.config
Restart=on-failure

[Install]
WantedBy=multi-user.target
  1. 重新加载

sudo systemctl daemon-reload

  1. 设置开机启动

sudo systemctl enable webdav

附:如果windows加载不了可以使用webdav客户端RailDrive


传图片时出现了一个问题,排查了很长时间,总算解决了。

主要本人的部署还是有些麻烦,转了两道,出问题排查起来比较麻烦

“你没有权限来执行此操作”

原因分析:

一是服务器上面没有写权限,但是除了图片,其它文件都可以上传,因此排除

二是raidrive设置了不能同步文件,因为有的nas系统会有这些限制,排查了一下,raidrive没有这些设置

三是服务器域名监听上有问题,因为本人是通过nginx转发代理的后端服务,因此,这一步容易出现图片类的请求被提前解析了,可能导致失败。因此,本人将配置文件中关于图片的路由全部注释,发现上传图片已经正常了。

这样就可以了