loading

【新公司】3月完结

新的一个月,新的开始,新的公司,新的环境,冲冲冲,rushB!!!

# flag

  • 晚上不吃饭减肥搞起来
  • 周3周5 6点下班,跑步回家
  • 每天晚上回家刷一道算法题

# 3.31

# 番茄🍅工作法

简单感受了一下,真的很好用。养成习惯,冲冲冲!!!!

# RFM模型

  • 最近一次消费 (Recency)
  • 消费频率 (Frequency)
  • 消费金额 (Monetary)

RFM模型是衡量客户价值和客户创利能力的重要工具和手段。在众多的客户关系管理(CRM)的分析模式中,RFM模型是被广泛提到的。

该机械模型通过一个客户的近期购买行为、购买的总体频率以及花了多少钱

3项指标来描述该客户的价值状况。

# object-position(雪碧图定位很好使)

指定 image 或 video 在容器中的位置。第一个值为 x 坐标位置的值,第二个值为 y 坐标位置的值。表示的方式有:

object-position: 50% 50%;
object-position: right top;
object-position: left bottom;
object-position: 250px 125px;
1
2
3
4

# object-fit

object-fit 属性指定元素的内容应该如何去适应指定容器的高度与宽度。

object-fit 一般用于 img 和 video 标签,一般可以对这些元素进行保留原始比例的剪切、缩放或者直接进行拉伸等。

object-fit: fill(默认,填充整个容器)|contain(原有比例,缩放)|cover(原有比例,放大)|scale-down(等比例缩放)|none|initial|inherit;

# 3.30

# git submoulde

Git Submodule 允许一个git仓库,作为另一个git仓库的子目录,并且保持父项目和子项目相互独立

# chrome 您的连接不是私密连接

保持单签页面不动,直接键盘输入:thisisunsafe 页面会自动刷新,就好了

# 3.29

# Object.entries

返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)

const object1 = {
  a: 'somestring',
  b: 42
};
// Object.entries(object1)   [Array(2), Array(2)]
// 直接for of遍历会报错,Error: object1 is not iterable
用Object.entries包装一下,作用和for in相同
for (const [key, value] of Object.entries(object1)) {
  console.log(`${key}: ${value}`);
}

// expected output:
// "a: somestring"
// "b: 42"
// order is not guaranteed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 项目发布流程

# 前端基础建设与架构学习

准备输出一篇文章

# 3.28

# 逛街

逛完街,回家吵架,美滋滋

# 吵架

逛得自己走累了,忽然不走了

东西没买,说没有逛街的感觉

# 3.27

# 搭建博客

帮别人搭建个博客,结果自动化平台一直有问题,也没查出来,就换成了手动

# 收拾屋子

搬家还有些东西没有搞,简单搞一搞。

# 吵架

女朋友上班,我在家,我没去地铁口(小区门口)接她,被喷。

# 3.26

# onClick函数绑定用()=>{}

原因: react不会自动绑定函数

<Button type="primary" onClick={() => {handleGo("/home")}}>

# ts 为对象动态分配属性

// js可以正常修改, ts修改会报错,没有name
let developer = {};
developer.name = "semlinker";

// 可以这样写: 索引签名
// 也可以使用 TypeScript 内置的工具类型 Record 来定义 Developer 接口
interface LooseObject {
  // 可以接受 key 类型是字符串,值的类型是 any 类型的字段
  [key: string]: any
}
// or
interface LooseObject extends Record<string, any> {}

let developer: LooseObject = {};
developer.name = "semlinker";

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# new URL

new URL("http://192.168.10.2:8888/admin/#/login")
// URL {origin: "http://192.168.10.2:8888", protocol: "http:", username: "", password: "", host: "192.168.10.2:8888", …}
// hash: "#/login"
// host: "192.168.10.2:8888"
// hostname: "192.168.10.2"
// href: "http://192.168.10.2:8888/admin/#/login"
// origin: "http://192.168.10.2:8888"
// password: ""
// pathname: "/admin/"
// port: "8888"
// protocol: "http:"
// search: ""
// searchParams: URLSearchParams {}
// username: ""
// __proto__: URL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 3.25

# 拉钩教育学起来

前端基础建设与架构 30 讲

# 折腾自己的项目

先按照自己异想天开的需求写,不管性能优化,最后再来一波优化方面的。想的很美

# _.isNil(value)

检查 value 是否是 null 或者 undefined

_.isNil(null);
// => true
 
_.isNil(void 0);
// => true
 
_.isNil(NaN);
// => false

1
2
3
4
5
6
7
8
9

# React-classnames库

由于react原生动态添加多个className会报错,简单理解就是个凭接classnames的

classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'
1

# 3.24

# 反思了半天

也不知道都干了啥,短期目标搞起来!

# 节流

一段时间内,只执行一次回调函数。并不是只执行第一次的函数,概念有点搞混淆了

# lodash difference

// _.difference(array, [values])
// array (Array): 要检查的数组。
// [values] (...Array): 排除的值。
_.difference([3, 2, 1], [4, 2]);
// => [3, 1]
1
2
3
4
5

# 3.23

# 算法打卡

实现 strStr() 函数。

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (0开始)。如果不存在,则返回  -1。

示例 1:

输入: haystack = "hello", needle = "ll"
输出: 2
示例 2:

输入: haystack = "aaaaa", needle = "bba"
输出: -1

// 解法一
var strStr = function (haystack, needle) {
    // 双指针
    if (needle === "") return 0;
    for (let i = 0; i < haystack.length; i++) {
        // 先找第一位相等的
        if (haystack[i] === needle[0]) {
            let flag = true;
            for (let j = 1; j < needle.length; j++) {
                if (haystack[i + j] !== needle[j]) {
                    // 如果haystack下一位 和 needle中的不相等,当前i作废,开始下一轮循环
                    flag = false;
                    break;
                }
            }
            // 循环没有break,当前i有效
            if (flag) return i
        }

    }
    // 循环结束没有找到,就没有
    return -1
};
// 解法二
var strStr = function (haystack, needle) {
    if (needle === "") return 0
    for (var i = 0; i < haystack.length; i++) {
        if (haystack[i] === needle[0]) {
            if (haystack.substring(i, i + needle.length) === needle) return i;
        }
    }
    return -1
};
// 解法三
var strStr = function(haystack, needle) {
    return haystack.indexOf(needle)
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# 资源分享文章输出

对自己的资源做一个整理,chrome标签都该处理一下了,各种统计都要处理一遍

# 前端监控

对这块了解的很少

  • 监控系统:日志采集、日志存储、统计与分析、报告和警告
  • 全局错误监听:onerror/error / unhandledrejection (可捕获promise错误) vue: errorHandle react: ErrorBoundary
  • 单点报错:try…catch

# 监听ajax请求

  • window.addEventListener("ajaxLoadStart", () => {console.log('ajaxLoadStart')})
  • window.addEventListener("ajaxLoadEnd", () => {})

# 3.22

# 减肥计划

天气终于晴了,冲冲冲!

  • 早睡,早起学习
  • 早上自行车上班,晚上跑步回家(5KM)
  • 早上不吃,中午一顿,晚上不吃
  • 卸载手机和iPad无用软件
  • 坚持一个月到五一,看看效果

# 缓存优先级

强缓存:主要字段有(expires:date(过期日期)、cache-control: max-age=time(毫秒数,多久之后过期) |no-cache|no-store)。如果expires和cache-control同时存在,cache-control会覆盖expires。建议两个都写,cache-control是http1.1的头字段,expires是http1.0的头字段,都写兼容会好点。

协商缓存:对比缓存Etag和Last-Modified同时存在时,则Etag会覆盖Last-Modified,Last-Modified不会生效。即:ETag优先级 > Last-Modified优先级

http缓存

# 忽略TS报错

报错上一行使用:// @ts-ignore

# react 版本不一致报错

# vue & react 选型

# 3.21

# for in & of

  • in key of value
  • 直接用for of遍历对象会报错,遍历Set类型的对象可以,因为是包含了迭代器

# 辅导

帮别人辅导的同时也能发现自己遗漏的一些知识点,冲冲冲

# 3.20

# $router 和 $route区别

  • router为VueRouter的实例
  • route相当于当前正在跳转的路由对象,可以从里面获取name,path,params,query

# JavaScript 中精度问题以及解决方案

# 解决思路

  • 考虑到每次浮点数运算的偏差非常小(其实不然),可以对结果进行指定精度的四舍五入
  • 将浮点数转为整数运算,再对结果做除法。比如0.1 + 0.2,可以转化为(1*2)/3
  • 把浮点数转化为字符串,模拟实际运算的过程 最佳方式 leetcode有对应的题目

# 3.19

# 制定培训计划

带一个人学习,过段时间看看效果吧

# 删除远端分支

git push origin --delete <branchName>

# React Context

组件树逐层传递,用prop很麻烦,这个时候可以用context

# 创建

const ThemeContext = React.createContext('light');

# Provider

使用一个 Provider 来将当前的 theme 传递给以下的组件树。

<ThemeContext.Provider value="dark">
        <Toolbar />
</ThemeContext.Provider>
1
2
3

# Consumer

指定 contextType 读取当前的 theme context。

React 会往上找到最近的 theme Provider,然后使用它的值。

static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
1
2
3
4

# 3.18

# npm包创建软连接

  • 组件库: npm link npm unlink
  • 项目:npm link 包名称

# 灰度环境

三种理解:

  1. 更新过程可以暂停,停在一个既有新版本又有旧版本的状态,然后选择升级或者回滚

  2. 支持流量比例分配,可以把百分之几的流量分配给一个服务,剩下的给另一个服务

  3. 支持 url 路径流量分配,一个路径下的流量给一个服务,另一个路径流量给另一个服务

Istio 是什么 (opens new window): 开源的服务网格,作为透明的一层接入到现有的分布式应用程序里.流量管理可以用于灰度的控制

有赞灰度发布与蓝绿发布实践 (opens new window)

# 3.17

# PropTypes

import PropTypes from 'prop-types';

  • 常见类型校验:函数(PropTypes.func)
  • PropTypes.func.isRequired 这个 prop 没有被提供时,会打印警告信息。

# lodash merge 手写一个试试?

对象合并,递归合并 sources 来源对象自身和继承的可枚举属性到 object 目标对象,undefined会直接跳过。

var object = {
  'a': [{ 'b': 2 }, { 'd': 4 }]
};
 
var other = {
  'a': [{ 'c': 3 }, { 'e': 5 }]
};
 
_.merge(object, other);
// => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
1
2
3
4
5
6
7
8
9
10

# 3.16

# useCallback

# 定义

返回一个 memoized 回调函数。在依赖参数不变的情况下,返回的回调函数是同一个引用地址

父组件将一个方法传递给子组件,若父组件的其他状态发生变化时,子组件也会跟着渲染多次,会造成性能浪费; usecallback是将父组件传给子组件的方法给缓存下来,只有当 usecallback中的第二个参数状态变化时,子组件才重新渲染;

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);
1
2
3
4
5
6

# 场景

优化子组件渲染次数

# 区别

useCallback缓存函数的引用,useMemo缓存计算数据的值

useEffect,usecallback,useMemo中都有第二个参数,若第二个参数代表的依赖项发生变化则重新渲染,不变化则不渲染更新

# useMemo

父组件将一个值传递给子组件,若父组件的其他值发生变化时,子组件也会跟着渲染多次,会造成性能浪费; useMemo是将父组件传递给子组件的值缓存起来,只有当 useMemo中的第二个参数状态变化时,子组件才重新渲染;

# CommonJs和Es Module

# 解决什么问题?

  • 解决变量污染问题,每个文件都是独立的作用域,所以不存在变量污染
  • 解决代码维护问题,一个文件里代码非常清晰
  • 解决文件依赖问题,(传统方法不注意顺序引入错,代码全报错)

# CommonJs

  • odule.exports & require
  • 导入的值是拷贝的,所以可以修改拷贝值,和内部互不影响
  • 用的地方声明就可以

# Es Module

  • 单个导出(export)、默认导出(export default)
  • 导入import, import * as x from 'xxx'
  • export导出的值是值的引用,修改会缓存,不可以重新赋值(报错)
  • 只能声明在该文件的最顶部

# 3.15

# static getDerivedStateFromProps(props, state)

getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容

# react forceUpdate

默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果 render() 方法依赖于其他数据,则可以调用 forceUpdate() 强制让组件重新渲染。

调用 forceUpdate() 将致使组件调用 render() 方法,此操作会跳过该组件的 shouldComponentUpdate()

通常你应该避免使用 forceUpdate(),尽量在 render() 中使用 this.props 和 this.state

# react 错误处理生命周期

当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法:

  • static getDeriveStateFormError
  • componentDidCatch

# dubbo

Dubbo(读音[ˈdʌbəʊ])是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。 Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

# React控制元素显示和隐藏

  • 第一种是通过state变量来控制是否渲染元素,类似vue中的v-if。
  • 第二种是通过style控制display属性,类似vue 中的v-show。
  • 第三种是通过动态切换className。

# 3.14

react + ts 项目实战视频学习

# 3.13

react + ts 项目实战视频学习

# 3.12

# react connect

连接React组件与 Redux store

# 小技巧,判断

eg:给某个变量赋值,但是不能小于或者大于1的情况 Math.max(1, state.enthusiasmLevel - 1)

# @types

@types下是一些包的声明文件,ts运行必须要

const user: User = { name: "lucifer" };
1

TypeScript 编译器先在当前编译上下文找 User 的定义。

如果找不到,则会去 node_modules 中的@types (默认情况,目录可以修改,后面会提到)目录下去寻找对应包名的模块声明文件。

# typeRoots

用来指定默认的类型声明文件查找路径,默认为node_modules/@types, 指定typeRoots后,TypeScript 编译器会从指定的路径去引入声明文件

# types

TypeScript 编译器会默认引入typeRoot下所有的声明文件,但是有时候我们并不希望全局引入所有定义,而是仅引入部分模块。这种情景下可以通过types指定模块名只引入我们想要的模块,比如以下只会引入 jquery 的声明文件

{
  "compilerOptions": {
    "types": ["jquery"]
  }
}
1
2
3
4
5

# Enzyme

Enzyme是React生态系统里一个通用工具,它方便了针对组件的行为编写测试

# ts 断言

当你比类型检查器更清楚一个表达式的类型的时候,你可以通过这种方式通知TypeScript。

ReactDOM.render(
  <Hello name="TypeScript" enthusiasmLevel={10} />,
  document.getElementById('root') as HTMLElement
);
1
2
3
4

# 纯函数

即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。

# 副作用

阮一峰:所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。 函数式编程强调没有"副作用",意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。

在函数式编程的教材中,如下的行为是称之为副作用的:

  • 修改一个变量
  • 修改一个对象的字段值
  • 抛出异常
  • 在控制台显示信息、从控制台接收输入
  • 在屏幕上显示(GUI)
  • 读写文件、网络、数据库。

# import

静态的import 语句用于导入由另一个模块导出的绑定。无论是否声明了 strict mode ,导入的模块都运行在严格模式下。在浏览器中,import 语句只能在声明了 type="module" 的 script 的标签中使用。

还有一个类似函数的动态 import(),它不需要依赖 type="module" 的script标签。

# 导入整个模块

import * as myModule from '/modules/my-module.js';

// 调用
myModule.doAllTheAmazingThings();
1
2
3
4

# 导入时重命名多个接口

import {
  reallyReallyLongModuleMemberName as shortName,
  anotherLongModuleName as short
} from '/modules/my-module.js';
1
2
3
4

# 动态导入

关键字import可以像调用函数一样来动态的导入模块。以这种方式调用,将返回一个 promise。

import('/modules/my-module.js')
  .then((module) => {
    // Do something with the module.
  });
  // or
let module = await import('/modules/my-module.js');
1
2
3
4
5
6

# 3.11

# Array.map 生成节点

项目很多节点都是 map 生成的,想着 map 返回的是一个数组,怎么就变成节点了呢,试了一下,还真的是

function Example() {
  const arr = [
    { name: "JJ", company: "youzan" },
    { name: "KK", company: "ali" },
    { name: "XY", company: "weiyi" },
    { name: "SQ", company: "dxy" },
  ];
  return (
    <>
      {arr.map((v, i) => {
        return <h3 key={i}>{v.name}</h3>;
      })}
    </>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# React.Fragment

简单理解就是对标签进行分组,简写<> </>,不支持 key 或属性

class Columns extends React.Component {
  render() {
    return (
      <>
        <td>Hello</td>
        <td>World</td>
      </>
    );
  }
}
1
2
3
4
5
6
7
8
9
10

# node bff

之前在微医根本不会接触到这些东西,第一次搞,有点懵。。。

有赞这边,我接触的两个 pc 项目都用 node 去包装了一层接口,后端只需要提供com.youzan.xxxx.xxxx.server以及后端的一个方法名称,前端用 node 去包装一个接口,暴露给静态应用使用。省去了很多后端的活,很多人接触的都是后端直接给个 api 的形式。用 bff,我们前端可以自己去包装接口,后端只需要提供业务逻辑方法即可。

# ts never 类型

项目代码中很多结构的写法,比如

fetchXXX().then(({ a = [], b = {}, c = 0 } = {}) => {
  // b.x = 1; 报错,编辑器提示说never类型不允许赋值number,网上查说可以用 b['x'],试了没用
  this.setState({
    dataA: a,
    dataB: b,
    dataC: c,
  });
});
1
2
3
4
5
6
7
8

还没解决,记录下来问大佬们

# 3.10

# 项目熟悉

流程上和上家公司有部分相似,慢慢适应,接了一个小活,有事情干了,冲冲冲

# React.FC<>

React 的组件可以定义为 函数(React.FC<>)或 class(继承 React.Component) 的形式。

  • React.FC 是函数式组件,是在 TypeScript 使用的一个泛型,FC 就是 FunctionComponent 的缩写,事实上 React.FC 可以写成 React.FunctionComponent
const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
  <div>{message}</div>
);
1
2
3
  • 使用 React.FC 来写 React 组件的时候,是不能用 setState 的,取而代之的是 useState()、useEffect 等 Hook API
  • React.FC 包含了 PropsWithChildren 的泛型

# 3.9 入职

# 新人报道,流水账

  • 9:30 来了好多特警,查的挺严的。貌似是因为买家和卖家的问题,闹到了有赞。
  • 9:30 - 11:00 新人培训,各种账号,流程
  • 11:30 - 13:30 工位搞搞
  • 13:30 下午继续培训
  • 发笔记本:M1 的 Mac Book Pro
  • IT 小哥相关介绍
  • 合同相关
  • 最后一个小活动 团队活动:所有新人一起拍个抖音视频 个人活动:找有伴(导师),TL,HRBP,有缘人拍合照,发到公司全员群

# 技术相关

react17 + typescript 边学边写,压力比较大,成长应该也是最快的,冲冲冲。

# 3.8

搬家 + 收拾家

体检报告出来了,验血有个指标 ALT 的,正常 50 以内,我是 95,解读是过度劳累,差点猝死。。。

# 3.7

上午体检,下午搬家

# 3.6

# 找房

上周末看过一次,没找到合适的。这次带女朋友一块看的,本来决定租自如的。晚上回去又看到一个转租的,就约了下,还不错,就签了。

一个没毕业的妹子转租的,中间为了 50%的转租费,扯了一会,小姐姐人挺好,我运气也不错。

# 3.5

在微医的最后一天,还要开技术评审。溜了溜了

# 算法打卡

287. 寻找重复数 (opens new window)

给定一个包含  n + 1 个整数的数组  nums ,其数字都在 1 到 n  之间(包括 1 和 n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。

var findDuplicate = function(nums) {
  let map = new Map();
  nums.forEach((v) => {
    if (!map.get(v)) {
      map.set(v, 1);
    } else {
      map.set(v, map.get(v) + 1);
    }
  });
  let res = 0;
  map.forEach((v, k, map) => {
    if (v > 1) {
      res = k;
    }
  });
  return res;
};
console.log(findDuplicate([3, 1, 3, 4, 2]));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 3.4

# Map.prototype.forEach()

function logMapElements(value, key, map) {
  console.log(`m[${key}] = ${value}`);
}
1
2
3

# React hooks

React hooks: not magic, just arrays

简单理解 hooks 工作原理是创建了两个一一对应的数组,如果使用 if 判断就会导致对应关系出错

# 删除排序数组中的重复项

给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

leetcode26 (opens new window)

// 双指针i j 一般用与解决双重循环对比问题
// 如果两者不相等,就交换位置
function removeDuplicates(nums: number[]): number {
  let i: number = 0;
  for (let j: number = 1; j < nums.length; j++) {
    if (nums[j] !== nums[i]) {
      i++;
      nums[i] = nums[j];
    }
  }
  return i + 1;
}
1
2
3
4
5
6
7
8
9
10
11
12

# 3.3

# ts 基础文章

基础部分大概总结完了,项目用到了在看,冲冲冲

# 3.2

# react 项目打包路径问题

package.json 中添加"homepage": "./", 与'dependencies' 同级

# nrm

npm 源管理器

  • npm install -g nrm
  • 列出可选择的源:nrm ls
  • 切换使用的源:nrm use npm
  • 添加一个源:nrm add <registry> <url>
  • 删除一个源:nrm del <registry>
  • 测试源速度:nrm test

# craco npm 包

使用 create-react-app 创建项目,不想 eject 项目但想对项目中 wepback 进行自定义配置的时候使用搞这个,项目根目录新建 craco.config.js 进行配置

参考文章:使用 craco 配置基于 create-react-app 的开发环境 (opens new window)

# 双问号操作符 ??

?? 替换||的运算符(只有 undefined 和 null 会返回默认值),并提供默认值;

> undefined ?? 'default'
'default'
> null ?? 'default'
'default'
> false ?? 'default'
false
> '' ?? 'default'
''
> 0 ?? 'default'
0
1
2
3
4
5
6
7
8
9
10

# 可选链操作符 ?.

let arr = res && res.data && res.data.list;
// 等同于
let arr = res?.data?.list;
1
2
3

# 3.1

# ts 学习

见 ts 学习笔记

# react + ts his 系统开发

练手的过程遇到很多问题,继续冲冲冲,演示地址:俊劫 his 系统 (opens new window)

最近更新时间: 2021/05/01 17:06:28
最近更新
01
2023/02/08 00:00:00
02
2023/01/03 00:00:00
03
2022/12/21 00:00:00