真实高质量低代码商业项目前端后端运维管理系统

架构师课程笔记

需求分析

架构师课程的组成

  • 业务相关 - 完成慕课乐高项目
    • 前端开发
    • 后端开发
    • 和开发相关的流程- 单元测试,部署,上线等
  • 研发相关
    • 脚手架
    • 组件平台
    • 监控平台等

需求等资源

需求分类

  • 模版
    • 模版列表
    • 使用模版创建
  • 用户
    • 获取验证码
    • 手机登录
    • 获取用户信息
  • 作品
    • 创建
      • 字体修改
      • 内容缩放
      • 内容拖拽
    • 保存
    • 发布
    • 获取作品列表以及信息
    • 分享到 H5
  • 渠道
    • 获取渠道
    • 创建渠道
    • 删除渠道

技术架构设计

需要几个项目

  • 前后端分离项目
  • 前端(SPA 项目,使用 Vue 或者 React) - lego
  • 后端 - lego-backend
    • RESTful API
    • H5 页面 SSR (Server side rendering)
  • 组件库 - lego-components

核心问题分析

抓住关键问题:海报,或者说是作品是整个系统的核心也是难点。

海报的组成

  • 背景,由图片或者纯色组成。
  • 元素
    • 由各种不同的元素(组件)组成。
    • 一部分属性界定它的位置(position)。
    • 一部分属性界定它的展示(looks)。

扩展性 - 场景设计

  • 海报添加对应的背景音乐
  • 新的组件类型 - 比如说当前日期

本课程完成的文档:https://imooc-lego.yuque.com/books/share/dc22e979-74b0-4e88-a04b-1b0e93ec0ef5?# 《技术方案》

复杂项目

业务的复杂度

  • 交互的复杂性,拖拽、改变字体等
  • 数据结构和状态的复杂性
  • 多项目互相依赖的复杂性
  • 打包
  • 性能优化
  • 第三方库使用和调研以及二次开发

流程的复杂度

  • git flow
  • lint 工具
  • 单元测试
  • commit 信息
  • PR review
  • CI/CD

简单分析一下 B 端的需求

只是简要的分析。从页面上分,会分为这几个页面。

首页

  • 导航条 未登录和已登录
    • 未登录 显示登录按钮
    • 已登录 显示 创建设计,我的作品,还有下拉菜单(个人设置和登出)
  • 展示列表
    • 图片
    • 标题
    • 作者信息 和 使用人数
    • Hover 显示创建按钮
  • 搜索
    • 搜索以后有清空按钮
  • 点击更多展示列表(每页展示 8 条)
  • 我的作品 (展示四条 右侧到我的作品页面)

登录

  • 发送验证码
  • 登录
    • 表单验证

模版详情页

  • 展示 图片 二维码 标题 作者
  • 使用该模版创建
  • 下载图片

我的作品

  • 作品或者模版列表
    • 编辑
    • 统计
    • 删除
    • 转赠
    • 下载图片
  • 搜索
  • 翻页

编辑器

  • 左 组件面板 - 可以添加到编辑器中的组件类型
    • 文本
    • 图形
    • 形状
  • 中 编辑器区域 - 从左侧添加的组件都会呈现到编辑器中
    • 点击选中
    • 拖动改变位置
    • 拖动改变大小
    • 快捷键
    • 右键菜单
  • 右 属性编辑面板 - 可以编辑中间组件的属性以及其他功能
    • 元素属性,详细的在实现的时候在讨论
    • 图层面板 隐藏显示 锁定解锁 拖动排序
    • 背景设置
  • 顶部 - 保存,发布,预览和设置
    • 点击保存
    • 点击预览 弹框
      • 左侧显示预览
      • 右侧设置标题,描述和头图,
    • 发布 - 弹框
      • 左侧显示截图
      • 右侧显示默认渠道,并且可以进行编辑
  • 其他 - 不属于界面上的一些功能(定时保存 ,退出前提示等等)

技术选型

node

版本: v16.13.0

可以使用 nvm 进行切换 node 版本

nvm 网站:https://github.com/nvm-sh/nvm

TypeScript

版本:v5.1.6

安装:npm i typescript -g

编译:tsc <文件名.ts>

基础数据类型

let flag: boolean = false
let age: number = 10
let str: string = 'hello'
let u: undefined = undefined
let n: null = null
let num: number = undefined
let notSure: any = 4 // 任何类型
notSure = 'word'

数组和元祖

// 数组
let arr: number[] = [1, 2, 3] // 数字类型的数组,只能添加数字类型

// 元祖
let arr2: [number, string] = [1, '2'] // 第一位为数字,第二位为字符串
// 但是在上面不能写超过 2 个,但可以通过 push 添加这两种类型,其他的不行
arr2.push(3)

interface 接口

  • 对对象的形状进行描述
  • Duck Typeing(鸭子类型)

不会编译到 JS 中,只是在 TS 中类型检查

interface Person {
readonly id: number // 只读属性
name: string
age?: number // 可选属性
}
const userInfo: Person = {
id: 1,
name: 'ranup',
age: 18
}

Function 函数

在 JS 中函数是一等公民

// 函数声明
function add(a: number, b: number, z?: number): number {
return typeof z === 'number' ? a + b + z : a + b
}
// 函数表达式
const add1 = (a: number, b: number, z?: number): number => {
return typeof z === 'number' ? a + b + z : a + b
}
// 赋值
const sum1: (a: number, b: number, z?: number) => number = add
// 接口类型
interface ISum {
(a: number, b: number, z?: number): number
}
// 赋值
const sum2: ISum = add1

联合类型(union type)

let numberOrString: string | number = 12
// 访问共有的属性或方法
console.log(numberOrString.toString())
console.log(numberOrString.valueOf())
// 字符长度是 string 的属性,那改怎么办呢?
// 方法1,类型断言
function getLength(value: string | number): number {
const str = value as string
if (str.length) {
return str.length
} else {
const num = value as number
return num.toString().length
}
}
// 方法2,类型保护(type guard)
function getLength2(value: string | number): number {
if (typeof value === 'string') {
return value.length
} else {
return value.toString().length
}
}

枚举(enum)

一系列常量

// 枚举成员赋值从0开始递增
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right, // 3
custom = 100, // 100
custom1 // 101
}
console.log(Direction.Up) // 0
console.log(Direction[0]) // 'Up

// 字符串枚举,常量枚举
enum Direction1 {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT'
}
const value = 'UP'
if (value === Direction1.Up) {
console.log('go up')
}

泛型

介绍

泛型就是指在定义函数,接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

function echoValue<T>(value: T): T {
return value
}

echoValue('str')
echoValue(2)

替换数组位置

function changeArr<T, U>(arr: [T, U]): [U, T] {
return [arr[1], arr[0]]
}

const res = changeArr([1, 'str'])
console.log(res) // [ 'str', 1 ]

约束泛型

约束为数组
function echoWithArr<T>(arr: T[]): number {
return arr.length
}

const res = echoWithArr([1, 'str'])
// const res2 = echoWithArr('str') // 类型“string”的参数不能赋给类型“unknown[]”的参数
console.log(res) // 2
约束为包含 length
interface IWithLength {
length: number
}

function echoWithLength<T extends IWithLength> (value: T): number {
return value.length
}

const res1 = echoWithLength([1, 'str'])
const res2 = echoWithLength('str')
const res3 = echoWithLength({ length: 10 })
console.log(res1, res2, res3) // 2 3 10
约束类
class Queue<T> {
private data: T[] = []
push(item:T) {
return this.data.push(item)
}
pop() {
return this.data.shift()
}
}

const queue1 = new Queue<number>()
const queue2 = new Queue<string>()
queue1.push(1)
queue2.push('1')
const res1 = queue1.pop()
const res2 = queue2.pop()
if (res1) {
console.log(res1.toFixed())
}
if (res2) {
console.log(res2.length)
}
约束 interface
interface IObj<T, U> {
key: T
value: U
}
const p1: IObj<string, number> = { key: 'zhangsan', value: 18 }
const p2: IObj<number, string> = { key: 20, value: 'lisi' }
约束数组
const arr1: number[] = [1, 2, 3, 4, 5]
const arr2: Array<number> = [1, 2, 3, 4, 5]
const arr3: Array<string> = ['1', '2', '3', '4', '5']

类型别名

const num1: (a: number, b: number) => number = (a, b) => a + b
type FunType = (a: number, b: number) => number
const num2: FunType = (a, b) => a + b

字符串字面量

const str: 'zhangsan' = 'zhangsan'

type Directions = 'up' | 'down' | 'left' | 'right'
const toWhere: Directions = 'up'

交叉类型

interface IName {
name: string;
}
type IPerson = IName & { age: number }
const user: IPerson = { name: '张三', age: 18 }

技术选型

  • Vue3
  • TypeScript
  • ESLint
  • Ant Design Vue
  • Vue Router
  • Vuex

项目生成

使用 Imooc CLI 新建项目,视频作者封装的脚手架

不是针对某个前端框架的脚手架,而是一个大而全更加针对业务的脚手架

  • 支持各种模版, 可扩展性
  • 云构建
  • 预发布和正式发布
  • 项目回滚
  • 远程 Git 操作

安装:npm i @imooc-cli/core -g
需要依赖 npm:npm i cnpm -g
创建项目:imooc-cli init

项目会自动检测,如果在 .vue 文件中检测了 let a = 1,但在 .ts 文件中未检测

可以点击 ESLint 插件的设置按钮,选择它的 setting.json 文件,添加:"eslint.validate": ["typescript"]

ESLint 自动修复错误,方法:

  • 法1:VSCode 快捷键:Ctrl + Shift + P,弹出框中输入ESLint: 选择,ESLint:Fix all auto-fixable Problems
  • 法2:在 ESLint 插件设置中设置保存自动修正,代码:"editor.codeActionsOnSave": {"source.fixAll.eslint": true}

perttier

格式化代码:

  • VSCode 快捷键:Ctrl + Shift + P,弹出框中输入Format 选择,Format Document(快捷键:Shift + Alt + F)

编写流程

  1. 使用 ImoocCli 搭建项目,配置 ESLint、Prettier
    1. 通过在 .ts、.vue 文件中添加 let a = 1 来验证 ts 是否可以正常工作
    2. 随意修改代码后保存,看 prettier 的保存自动格式化是否生效
  2. 安装 Ant-design-vue 编写 首页、拆分模版、单个模板页的整个页面 和 编辑页页面大致结构搭建
  3. 安装 Vue-router、编写路由,实现首页logo、首页模板、单个模板等页的跳转逻辑
  4. 编写 meta,实现根据 meta 显示不同的页面信息(是否有 header、footer)
    • 法1:路由均为一级路由,使用 meta 的方式来进行判断
    • 法2:将 index 设为一级路由,home 和 templateDetail 页面设置为其的子路由。
  5. 安装 Vuex,完成:登录、登出 功能,使用 Module 分割 user 和 template 的数据。
  6. 业务组件 LText 编写。业务组件属性和表单组件的显示和实时更新。支持vNode的在 vue template 中显示。