工程业务代码最佳实践

重要通知

基本概况

价值导向

  • 效益至上、效率优先、兼顾成本、发挥个体优势。
  • 实现前端对外交付目标的效益最大化、效率最大化与成本最小化,以及将个体优势发挥在前端价值对外输出上,并具有可持续性与长期性。
  • 效益至上: 人效比与投入产出比的量化输出价值是第一导向。
  • 效率优先: 在效益得到保障的前提下,效率越高,效益产出就越多。
  • 兼顾成本: 在效益与效率得到保障的基础上,成本优化越彻底,效益输出就越多。
  • 倡导充分发挥个体优势,引导个体优势积极发挥到前端团队整体价值对外输出的成果上来。
  • 功劳与成果导向: 以功劳与成果为导向,积极引导苦劳向功劳转化,引导结果向成果输出。苦劳与结果化,是形式主义滋生的本质原因。
  • 功劳: 基于目标共识实现保质保量准时交付目标,或者超质、超量或提前等交付目标。
  • 成果: 对外输出效益覆盖或远远超出对内投入成本,实现有效价值的剩余。
  • 注意事项:规范不是条条框框,不是形式主义,不是为了规范而规范,规范也有时效性与局限性,如果已存在的规范不再符合价值导向,就必须及时砍掉,避免形成历史冗余与负担。

整体目标

设计一个支撑到2030年(2022年起,8年)的ERP前端系统

如何解决ERP前端系统的稳定性与伸缩性问题? 1、代码可靠性:统一前端代码规范与交付共识,弱化个体差异,强化整体价值,积极践行交付。

2、代码稳定性:渐进式推进单元测试Jest或Vitest的覆盖率。

3、系统容错性:采用聚合式系统的架构设计,弱化业务对技术的依赖,大幅度降低系统架构设计的耦合性与冗余性,消除局部业务模块或功能函数的异常错误影响整体系统、视图页面与操作交互的可靠性和稳定性。

4、系统伸缩性:隔离业务与技术之间的依赖,推进"聚合式系统"的架构设计

5、系统稳定性:整合前端异常错误监控系统,对ERP生产环境实时监控,提前把控代码风险,实时处理解决出现的异常错误问题。

如何兼顾ERP前端系统的前端开发效率与质量问题? 全面推行聚合式系统的架构设计:帮助业务开发人员脱离于具体技术的开发实现,通过"数据驱动"与"功能订阅"来实现业务需求的快速交付。

如何解决Vue3生态系统的迭代更新与停止维护带来的风险问题? 1、引入第三方库需要经过评估与审核,尤其是小众且维护不稳定的第三方库,逐步替换淘汰掉小众且维护不稳定的小众库。

2、解耦业务与技术的直接依赖,通过业务按需订阅服务,再由服务定制技术来完成整个业务系统的聚合交付。

如何解决ERP前端系统不依赖个体开发者能力差异与人员变化的问题? 1、规范:强化前端成员的实现规范与交付统一。

2、聚合:践行“聚合式系统”的架构设计与具体实现。

3、优势:将个体的优势发挥到聚合式系统的要素(模块系统)设计实现,从而可以提高其他个体的业务需求对外交付效率。

如何解决ERP前端系统不依赖前端负责人架构设计的变化问题? 1、践行前端团队的"价值导向",弱化个体的非整体价值输出内容。

2、遵循"聚合式系统"的架构设计,实现业务需求、功能实现与技术支撑的独立性与可靠性,避免因为个体的不确定性导致系统的不稳定性问题。

架构: 聚合式设计

聚合式设计的核心在于采用聚合的思想来设计系统,即系统内核 + 基础服务 + 工具箱 + 部件/插件/组件+ 业务模块 + 业务辅助功能。

系统内核

为前端系统运行提供支撑的底层基础环境,当前ERP的前端系统内核是基于Vue3的响应式系统,例如Vue、Vue-router、Pinia等。

基础服务

为业务系统提供的诸如HTTP、Ajax、Fetch、cos-js-sdk-v5腾讯云上传等基础服务。

工具箱

独立提供各种JS功能的函数工具,不依赖具体的技术栈,不引用其他第三方库。

部件

不依赖于Vue3生态系统,提供完整的场景解决方案服务,例如Tinymce编辑器、Echarts可视化工具等。

插件

可依赖Vue3的生态系统,立足于具体的业务场景,抽离出的相关服务,例如Lodash等。

组件

依赖于Vue3的生态系统,基于系统的UI通用组件与UI业务组件,例如Element-plus等。

业务模块

实现业务需求的各个相关功能模块。

业务辅助功能

辅助业务功能模块的各种实现。

这个前端个体的PBC

关键字参考

# --------------------------------------- #
# 命名名称规范参考 后缀-suffix 前缀-prefix
# --------------------------------------- #
# 关键字
Backhaul:回传 回程   xxxBackhaulEvent  eventBackhaulConf
 事件回传配置
异步: async  | 同步: sync
> extends:扩展  helpers:辅助  inherit:继承  auxiliary:附属  Tools:工具  alias:别名  ergodic:遍历
> instance:实例  extension:扩展  recursion:递归  deliver:传递  publish:发布  receiver-接收者
> process:进程  thread:线程  coroutine:协程  Fiber:纤维  wrapper:包裹  patch:补丁  decorator:装饰器
> dispatch:派发  compile:编译  parse:解析  appoint:任命  
> Listener:监听器  Watcher:观察者  Observer:观察者  Trigger:触发器  Launcher:发射器  Track:跟踪 轨迹  Tracker:追踪器
> concurrency:并发  scheduler:调度  schedule:计划  patch:补丁  fragment:片段  supense:暂停  performance:性能  yield:协商  launch:唤起
> aggregation:聚合  hydrate:合成  simulate:模拟  Pool:池  Filter:过滤器  Interceptor:拦截器  Detector:检测器
> normalize: 使标准化
+ iterator(迭代器)

# 常用类名
> Basic:基础 | Depend:依赖 | Subject:主体 | 根基:Foundation   temp:临时
> Ancestry:祖先  Parent:父类  Current:当前  Child:子类  Grandson:孙类

# 数据机构
> heap:堆  stack:栈  queue:队列  unit:单元
> hook:钩子

# 常量命名
> WHITE_LIST:白名单  BLACK_LIST:黑名单
> subscript:sub 下标  superscript:sup 上标

# 安全
> timestamp:时间戳

# 公共命名规范
> identifier:标志符

# 运算
> plus:加  minus:减  multiply:乘  divide:除  remainder:余数  decimal:小数  integer:整数  fraction:分数

# 基本操作
> create:创建  add:添加  delete:删除  edit:编辑  remove:移除
> handler:处理器  model:模型  manager:管理器  Factory:工厂  Provider:供应商  Engine:引擎  Service:服务  Task:任务
> Context:上下文

# API命名


# 目录名称 
> function-name

# 文件名称
> file-name.

# CSS命名

项目工程结构规范

具体要求

  • 通用性
  • 统一性
  • 可扩展
  • 可迁移
  • 可升级

代码质量

  • 共识:代码规范。
  • 简洁:实现代码还可不可以删?
  • 注释:输入对象、输出对象、代码结构、实现逻辑等。

命名参考

  • 语义化
  • 结构化
  • 归类化

文件夹与文件名

// 文件夹
xxx-xxx

// 文件名
xxx-xxx.[后缀]

命名规则

1、基本原则: 语义化、结构化、简洁化。 2、一级目录命名规则优先,其他遵循非一级目录命名约定。 3、非对外导出供应其他外部文件引用的变量与函数,视为一般变量与函数,遵循驼峰命名。其中,变量: xxx、xxxXxx等,函数: xxxFunc、xxxXxxFunc等。

前端工程结构

├─ dist                       # 存放打包后的工程文件
├─ env                        # 环境变量
│ ├─ .env                     # 所有环境都构建
│ ├─ .env.local               # 所有环境都构建,但会被git忽略
│ ├─ .env.development         # development环境构建
│ ├─ .env.test                # test环境构建
│ ├─ .env.production          # production环境构建
│ ├─ .env.development.local   # development环境构建,但会被git忽略
│ ├─ .env.production.local    # production环境构建,但会被git忽略
│ ├─ .env.build
│ ├─ .env.build-global
│ ├─ .env.build-test
│ ├─ .env.build-test-global
│ └─ .env.serve.local
├─ builds                     # 构建发布配置与加工
├─ lib                        # 静态链接库
├─ dll                        # 动态链接库
├─ bin                        # 二进制文件
├─ public                     # 公共资源,不参与构建编译流程
│ ├─ images                   # 图片
│ └─ data                     # 数据
├─ src                        # 业务代码
│ ├─ common                   # 公共依赖
│ │ ├─ languages              # 多语言
│ │ └─ permission             # 权限
│ ├─ assets                   # 静态资源,参与构建编译流程
│ │ ├─ images                 # 图片
│ │ ├─ style                  # CSS样式
│ │ └─ themes                 # 主题
│ ├─ components               # 全局UI组件
│ │ ├─ common                 # 公共组件 
│ │ ├─ tools                  # 工具组件
│ │ │ ├─ decorators           # 装饰器
│ ├─ declare                  # TS声明文件
│ ├─ api                      # 网络API接口
│ ├─ interface                # TS接口
│ ├─ constants                # 常量
│ ├─ core                     # 核心库,提供基础服务,不依赖项目技术栈
│ ├─ widgets                  # 部件,不依赖项目技术栈
│ ├─ plugins                  # 插件,依赖项目技术栈
│ ├─ helpers                  # 业务辅助功能,可依赖外部资源
│ ├─ utils                    # 工具箱,纯JS函数无任何依赖
│ ├─ config                   # 视图数据公共配置
│ ├─ store                    # 状态管理
│ ├─ router                   # 路由管理
│ ├─ template                 # 模板,[可选]
│ └─ views:                   # 视图页面
│ │ ├─ page-module            # 视图模块一
│ │ │ ├─ components           # 组件集
│ │ │ │ ├─ add.vue
│ │ │ │ └─ module.vue
│ │ │ ├─ style                # 样式集
│ │ │ │ ├─ index-scoped.scss  # 当前视图作用域
│ │ │ │ └─ index.scss         # 全局作用域
│ │ │ ├─ api.ts               # API接口
│ │ │ ├─ style.scss           # CSS样式
│ │ │ ├─ config.ts            # 配置
│ │ │ ├─ constant.ts          # 常量
│ │ │ ├─ interface.ts         # TS接口
│ │ │ ├─ index.ts             # 页面视图逻辑实现
│ │ │ ├─ list.vue             # 列表页面视图
│ │ │ ├─ index.vue            # 非列表页面视图
│ │ │ └─ Readme.md            # 说明文档
│ │ ├─ page-module            # 视图模块二
│ │ └─ page-module            # 视图模块三
├─ packages:                  # 包
├─ docs:                      # 文档
├─ demo:                      # 代码示例
├─ test:                      # 单元测试
├─ App.vue:                   # 主模板
├─ main.js:                   # 主函数
├─ jsconfig.json
├─ Makefile:                  # 构建编译环境
└─ Readme.md:                 # 工程项目说明文档

common

  • 定位:存放全局使用的基础依赖,例如多语言配置文件languages、权限配置文件permission等。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxCommon规范,其他没有作要求的则遵循一般规范即可。

// 变量
export const xxxCommon = "";

// 函数
export function xxxCommon() {}
  • 引用示例
import { xxxCommon } from '@/common/xxxx';
  • 注意事项:。

components

  • 定位:存放全局使用的组件,包括通用组件与业务组件,遵循复用性、扩展性与可维护性,以及接入成本低,显著提升二次开发效率。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxUI规范,其他没有作要求的则遵循一般规范即可。


  • 引用示例
import { xxxUI } from '@/components/xxxx';
  • 注意事项:。

api

  • 定位:存放全局使用的API接口。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxAPI规范,其他没有作要求的则遵循一般规范即可。

/**
 * 结构:行为 + 内容 + API
 * 
 * 行为: 增-add、删-delete、改-modify、查-get
 * 内容(抽象): 列表-list、详情-detail
 * 内容(具体): 商品列表-goodsList、订单列表-orderList
 */
export function doWhatAPI(data = {}, options = {}) {
  //
}


// 获取...
async function get...API(data = {}, options = {}) {}


// 详情: 通用
export function getDetailAPI(data = {}, options = {}) {};
// 详情: XXX详情
export function getXxxDetailAPI(data = {}, options = {}) {};


// 列表: 通用
export function getListAPI(data = {}, options = {}) {};
// 列表: XXX列表
export function getXxxListAPI(data = {}, options = {}) {};


// 添加: 通用,列表中的选项
export function addItemAPI(data = {}, options = {}) {};
// 添加: 列表中的XXX选项
export function addXxxItemAPI(data = {}, options = {}) {};


// 修改: 通用,列表中的选项
export function modifyItemAPI(data = {}, options = {}) {};
// 修改: 列表中的XXX选项
export function modifyXxxItemAPI(data = {}, options = {}) {};


// 删除: 通用,列表中的选项
export function deleteItemAPI(data = {}, options = {}) {};
// 删除: 列表中的XXX选项
export function deleteXxxItemAPI(data = {}, options = {}) {};





// 操作...
async function do...API(data = {}, options = {}) {}
// 导出报告
async function exportReportAPI(data = {}, options = {}) {}
  • 引用示例
import { xxxAPI } from '@/api/xxxx';
  • 注意事项:。

interface

  • 定位:存放全局使用的接口声明(数据结构、字段类型与值等)。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxInterface、xxxEnum、xxxType等规范,其他没有作要求的则遵循一般规范即可。

export interface xxxInterface {}

export enum xxxEnum {
	xxx = xxx
}
  • 引用示例
import { xxxInterface } from '@/interface/xxxx';
import { xxxEnum } from '@/interface/xxxx';
  • 注意事项:。

constants

  • 定位:存放全局使用的常量文件。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循XXX、XXX_XXX规范,其他没有作要求的则遵循一般规范即可。

// 变量
export const XXX = Object.freeze("");
export const XXX_XXX = Object.freeze("");
export const XXX_XXX_XXX = Object.freeze("");

// 函数
export function XXX() {}
  • 引用示例
import { XXX } from "@/constants/xxx";
  • 注意事项:注意引用时对原数据的变动影响问题,建议创建常量前使用Object.freeze()冻结常量声明对象。

core

  • 定位:存放全局使用的基础服务。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxCore规范,其他没有作要求的则遵循一般规范即可。

// 变量
export const xxxCore = "";

// 函数
export function xxxCore() {}
  • 引用示例
import { xxxCore } from '@/core/xxxx';
  • 注意事项:注意基础服务的稳定性,这是系统的基础服务,对系统容易造成相当严重的稳定性问题。

widgets

  • 定位:存放全局使用的部件。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxWidget规范,其他没有作要求的则遵循一般规范即可。

// 变量
export const xxxWidget = "";

// 函数
export function xxxWidget() {}
  • 引用示例
import { xxxWidget } from '@/widgets/xxxx';
  • 注意事项:注意抽象性与高内聚低耦合,不可涉及任何与业务相关的代码。

plugins

  • 定位:存放全局使用的插件。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxPlugin规范,其他没有作要求的则遵循一般规范即可。

// 变量
export const xxxPlugin = "";

// 函数
export function xxxPlugin() {}
  • 引用示例
import { xxxPlugin } from '@/plugins/xxxx';
  • 注意事项:注意抽象性与高内聚低耦合,不可涉及任何与业务相关的代码。

helpers

  • 定位:存放全局使用的业务辅助功能。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxHelper规范,其他没有作要求的则遵循一般规范即可。

// 变量
export const xxxHelper = "";

// 函数
export function xxxHelper() {}
  • 引用示例
import { xxxHelper } from '@/helpers/xxxx';
  • 注意事项:注意抽象性与高内聚低耦合,不可涉及任何与业务相关的代码。

utils

  • 定位:存放全局使用的纯JS工具箱。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxUtil规范,其他没有作要求的则遵循一般规范即可。

// 变量
export const xxxUtil = "";

// 函数
export function xxxUtil() {}
  • 引用示例
import { xxxUtil } from '@/utils/xxxx';
  • 注意事项:这是纯JS实现的工具,禁用引入任何第三方库,以及非本目录中的任何文件。

config

  • 定位:存放全局使用的视图数据配置文件。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxConfig规范,其他没有作要求的则遵循一般规范即可。

├─ config
│ ├─ columns # 存放列表行字段配置
│ └─ searchs # 存放搜索字段配置
// 函数
export function xxxConfig() {
	return {};
}
  • 引用示例
import { xxxConf } from '@/config/columns/xxxx';
import { xxxConf } from '@/config/searchs/xxxx';
  • 注意事项:推荐使用函数,而不是变量,因为很难保障其他引用会存在直接操作更新对象,从而影响其他引用该对象的逻辑,或者使用Object.freeze()冻结。

store(状态管理)

  • 定位:存放全局使用的状态管理文件。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxStore规范,其他没有作要求的则遵循一般规范即可。

// 变量
export const xxxStore = "";

// 函数
export function xxxStore() {}
  • 引用示例
import { xxxStore } from '@/store/xxxx';
  • 注意事项:。

router(路由系统)

  • 定位:存放全局使用的路由配置文件。

  • 命名规则:当前目录中所有对外导出的对象,需要遵循xxxRouter规范,其他没有作要求的则遵循一般规范即可。

// 变量
export const xxxRouter = "";

// 函数
export function xxxRouter() {}
  • 引用示例
import { xxxRouter } from '@/router/xxxx';
  • 注意事项:。

views

服务器工程结构

├─ api                        # API接口集
├─ service                    # 业务逻辑
├─ module
│ ├─ 
│ └─ 
├─ control
├─ plugins                    # 第三方插件
├─ 
├─ 
├─ 
└─ 

文件引用关系规范

├─ A
├─ B
│ ├─ B1
│ ├─ B2
│ │ ├─ B21
│ │ │ ├─ B211
│ │ │ ├─ B212
│ │ ├─ B22
│ │ │ ├─ B221
│ │ │ ├─ B222
│ ├─ B3
│ ├─ B4
│ │ ├─ B41
│ │ ├─ B42
│ ├─ B5
│ └─ B6
├─ C
│ ├─ C1
│ │ └─ input.txt
│ └─ C2
├─ D
└─ E

HTML5最佳实践

严重警告

HTML节点禁止嵌套级数超过10级。

注释规范

JavaScript最佳实践

变量

使用字面量创建变量

const name;
const name = undefined;
const name = null;
const name = true;
const name = 0;
const name = "";
const name = {};
const name = [];
const name = Symbal();

基础命名规范

/*****************************************************
 * Author: 王军
 * Date: 2022-08-16
 * 功能描述: 
 *****************************************************/


/**
 * 常量
 * 英文单词 + _,且已英文单词开头
 */
const COM_COLOR = '';  
const COM_ZOO_COLOR = '';


/**
 * 变量
 * 
 * 字面量
 * 驼峰法来命名(camelCase)
 */
const color = '';
const student = { name: '', sex: '', total: 100, };
// 全局变量 | 大写 (UPPERCASE )
// 常量 (如 PI) | 大写 (UPPERCASE )
// 私有变量
const _varible = '';





// 文件夹 | folder-name

// 文件名 | file-name.xxx

// 行尾使用分号

// 行末逗号

// 空格缩进 | 2个空格符号

// 对象字面量的冒号后加空格,冒号前不加

// 条件语句关键字后加空格
if () {}

函数

命名规则:行为 + 内容 + Fn,采用驼峰命名法。

// 某某功能实现函数
function xxFn() {
  //
}


// 初始化依赖
async function initDependFunc(data = {}) {
  //
}

注释规范

/**
 * 功能描述
 * @param {string} name: 姓名,<必填>,默认为"张三"。
 * @param {string} sex: 性别,<选填>,默认为undefined。
 * @return {Element}
 */
function print(name: string, sex?: string) {
  //
}

JSDoc工具

JSDoc 是一个用于 JavaScript 的API文档生成器。

CSS最佳实践

严重警告

CSS作用域必须审查与限制,避免出现各种非预期的样式污染问题。

类名命名规范

全局类名

全局命名必须有醒目的全局标识,所有非全局类名,必须使用限制性的CSS结构嵌套约束。

.com-xxx {}

组件类名

  • components目录
.component-xxx {}
  • widgets目录
.widget-xxx {}
  • other其他目录
.[other]-xxx {}

页面类名

每一个视图页面的独立类名,具有唯一性,例如views/page-module,则命名为: page-module、page-module-xxx等。

<style type="text/css">
.page-goods {}
.page-order {}
.page-user {}
</style>


<section class="page-goods"></section>
<section class="page-order"></section>
<section class="page-user"></section>

辅助类名

补充作用,必须与限制类名一起使用,禁止独立使用。

  • views/page-module
<style type="text/css">
.page-module.aux-xxx {}
</style>

<section class="page-module aux-xxx"></section>

专用类名

.xxx-wrapper {}
.xxx-layout {}
.xxx- {}
.xxx- {}
.xxx- {}
.xxx- {}
.xxx- {}
.xxx- {}
.xxx- {}

HTML类名

类名结构显著,类名形象有序,充分运用HTML5语义化标签。

  • 页面: views、pages
<template>
  <!-- 页面 -->
  <section class="com-frame page-tools-[unique-name]">
    <!-- 布局 -->
    <div class="layout-[section-name]">

      <!--区域-->
      <div class="section-[container-name]">

        <!--容器-->
        <div class="container-[wrapper-name]">

          <!--包裹-->
          <div class="wrapper-[module-name]">

            <!--模块-->
            <div class="module-[function-name]">

              <!--功能: 事件行为-->
              <div class="function-[name]">
                <!--内嵌直接元素-->
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </section>
</template>
  • 全局组件: components
<template>
  <!--最外层-->
  <section class="com-frame component-[unique-name]">
  </section>
</template>
  • 局部组件: components
<template>
  <!--最外层-->
  <section class="com-frame own-[unique-name]">
  </section>
</template>

传统CSS写法

<style type="text/css">
  
</style>

<section class="section-activity-current-layout">
  <h3 class="abbr-sacl-h3">Limited time sales activities</h3>
</section>

注释规范

TypeScript最佳实践

  • 所有字段必须有注释说明

接口

// 接口
interface ITF_DESCRIBE_NAME {

}

Vue3生态技术栈最佳实践

页面通用结构规范

├─ page-module            # 视图模块一
│ ├─ components           # 组件集,[可选]
│ │ ├─ add.vue            # 示例
│ │ └─ module.vue         
│ ├─ style                # 样式集,[可选]
│ │ ├─ index-scoped.scss  # 当前视图作用域
│ │ └─ index.scss         # 全局作用域
│ ├─ api.ts               # API接口,[可选]
│ ├─ config.ts            # 配置,[可选]
│ ├─ constant.ts          # 常量,[可选]
│ ├─ interface.ts         # TS接口,[可选]
│ ├─ index.ts             # 页面视图逻辑实现,[可选]
│ ├─ list.vue             # 列表页面视图,[可选]
│ ├─ index.vue            # 非列表页面视图,[可选]
│ └─ Readme.md            # 说明文档,[可选]

components


style


api.ts

  • 命名规则: 行为 + 内容 + API
  • 行为: 增-add、删-delete、改-modify、查-query
  • 内容(抽象): 列表-list、详情-detail
  • 内容(具体): 商品列表-goodsList、订单列表-orderList
export function doWhatAPI(data = {}, options = {}) {
  //
}


// 获取列表数据
export function queryListAPI(data = {}, options = {}) {
  //
}


// 获取...
async function query...API(data = {}, options = {}) {}


// 详情: 通用
export function queryDetailAPI(data = {}, options = {}) {};
// 详情: XXX详情
export function queryXxxDetailAPI(data = {}, options = {}) {};


// 列表: 通用
export function queryListAPI(data = {}, options = {}) {};
// 列表: XXX列表
export function queryXxxListAPI(data = {}, options = {}) {};


// 添加: 通用,列表中的选项
export function addItemAPI(data = {}, options = {}) {};
// 添加: 列表中的XXX选项
export function addXxxItemAPI(data = {}, options = {}) {};


// 修改: 通用,列表中的选项
export function modifyItemAPI(data = {}, options = {}) {};
// 修改: 列表中的XXX选项
export function modifyXxxItemAPI(data = {}, options = {}) {};


// 删除: 通用,列表中的选项
export function deleteItemAPI(data = {}, options = {}) {};
// 删除: 列表中的XXX选项
export function deleteXxxItemAPI(data = {}, options = {}) {};





// 操作...
async function do...API(data = {}, options = {}) {}
// 导出报告
async function exportReportAPI(data = {}, options = {}) {}

config.ts


constant.ts

// 选项数组
export const ACTION_LIST = [
  {
    label: "不限",
    value: "1",
  },
  {
    label: "活动",
    value: "2",
  }
];
export const ACTION_LABEL = function (value?: string) {
  const result = ACTION_LIST.filter(
    (item: Record<string, any>) => item.value == String(value)
  );
  return result && result?.[0] ? result[0].label : "-";
};

interface.ts


index.ts


index.vue: 非表格列表

<template>
	<section class="com-frame"></section>
</template>

<script lang="ts" setup>
// 第三方资源类库或插件
import { ref } from 'vue';
import { ElMessage } from 'element-plus';

// 全局资源库
import {} from '@/utils/index';

// 局部资源库
import {} from './api';
import {} from './config';
import {} from './constant';
import {} from './interface';

/**
 * @当前业务
 * 具体逻辑实现代码
 */

// 初始化依赖数据
async function initDependFunc(data = {}) {
	//
};
initDependFunc();
</script>

<!--[可选]: 若不需要则删除-->
<!--全局引入,注意作用域污染问题-->
<style lang="scss">
@import url('./style/index.scss');
</style>

<!--[可选]: 若不需要则删除-->
<!--当前页面作用域-->
<style lang="scss" scoped>
// 引入外部文件,[可选]: 若不需要则删除
@import url('./style/index-scoped.scss');

// 内嵌样式,[可选],不需要则删除
.page-module {
	position: relative;
}
</style>

list.vue: 表格列表


Element-plus规范

parent.vue

<template>
  <dialog 
    v-model="dialogConf.visual"
    @action:submit="actionSubmitEmit"
    @action:confirm="actionConfirmEmit"
    @action:cancel="actionCancelEmit"

    @action:submit="actionEmit"
    @action:confirm="actionEmit"
    @action:cancel="actionEmit"
  />
</template>

<script lang="ts" setup>
  function actionSubmitEmit() {
    //
  }
</script>

对话框 dialog.vue

<!--
	<dialogCommonUI 
		v-model="dialogComonConf.visual" 
		@action:submit="submitBackhaulEvent" 
	/>

	const dialogCommonUI = defineAsyncComponent(() => import('@/components/dialog/common/index.vue'));
-->
<template>
	<el-dialog
		v-model="initModelValue"
		:before-close="closeAction"
		:draggable="true"
		:close-on-click-modal="false"
		:title="initTitle"
		width="900px"
		class="com-erp-dialog component-dialog-common"
	>
		<template #footer>
			<span class="dialog-footer">
				<el-button @click="closeAction">取消</el-button>
				<el-button :loading="submitLoading" type="primary" @click="submitAction">确定</el-button>
			</span>
		</template>
	</el-dialog>
</template>

<script lang="ts" setup>
// 第三方资源类库或插件
import { ref, reactive, computed } from 'vue';
import { ElMessage, ElDialog, ElButton, ElForm, ElFormItem } from 'element-plus';
import { Edit } from '@element-plus/icons-vue';
import type { FormInstance, FormRules } from 'element-plus';

// 全局资源库

// 局部资源库

/**
 * @当前业务
 * 具体逻辑实现代码
 */
const props = defineProps({
	modelValue: {
		type: Boolean,
		default() {
			return false;
		}
	},
	mode: {
		type: String,
		default() {
			return '';
		}
	}
});

const emit = defineEmits([
  'update:modelValue',
  'action:submit',
  'action:confirm',
  'action:cancel', 
  'action:init', 
  "callback"
]);

// 限制重复提交
const submitLoading = ref(false);
const ruleFormRef = ref();

const initValue = computed({
	get: () => props.modelValue,
	set: (val) => {
		emit('update:modelValue', val);
	}
});

const initTitle = computed(() => (props.mode === 'add' ? '创建规则' : '编辑规则'));

// 提交表单
async function submitAction() {
	ElMessage.closeAll();

	if (submitLoading.value) {
		return ElMessage.warning('正在提交中,请不要重复提交!');
	}

	submitLoading.value = true;

	// 提交数据
	// const { status } = await api();
	submitLoading.value = false;
	// if (status !== 0) return;

	closeAction();
	emit('action:submit');
}

function closeAction() {
	emit('update:modelValue', false);
}
</script>

<!--全局引入,注意作用域污染问题-->
<style lang="scss">
@import '@/assets/style/dialog.scss';
</style>

<!--当前页面作用域-->
<style lang="scss" scoped>
.component-dialog-common {
}
</style>

父级组件

<template>
  <childUI @action:init="initEmit" />
</template>

<script lang="ts" setup>
// 第三方资源类库或插件


// 局部资源库
import childUI from './child.vue';


/**
 * @当前业务
 * 具体逻辑实现代码
 */
function initEmit() {
  //
}
</script>

表单 form.vue

<template>

</template>

<script lang="ts" setup>
// 第三方资源类库或插件


/**
 * @当前业务
 * 具体逻辑实现代码
 */
const ruleFormRef = ref();

// 验证器
async function formValidater() {
	return new Promise((resolve) => {
		ruleFormRef.value?.validate((valid: boolean) => {
			resolve(valid);
		});
	});
}


const validater = await formValidater();
if (!validater) return;


const emit = defineEmits([
  'update:modalValue', 
  'update:auxiliary', 
  'update:subject', 
  'update:change'
]);

emit('update:change', 'type', { value: '' })


// 子组件回调函数 @action:submit="updateActionEvent"
function updateActionEvent(type = "", data = {}) {
  //
}
</script>

<!--当前页面作用域-->
<style lang="scss" scoped>
</style>

React生态技术栈最佳实践

代码风格规范

单元测试规范

Jest

Vitest

目录、文件夹与文件规范

  • 全局单元测试用例:即工程一级目录,不建议放在这里。
  • 局部单元测试用例:推荐测试用例跟随逻辑代码存放一起。
# 场景一:同一目录下的同级ts或js文件数较多,大于3个
├─ page-module
│ ├─ ——test——
│ │ ├─ a.test.ts
│ │ ├─ b.test.ts
│ │ ├─ c.test.ts
│ │ └─ d.test.ts
│ ├─ a.ts
│ ├─ b.ts
│ ├─ c.ts
│ └─ d.ts


# 场景二:同一目录下的同级ts或js文件数较少,不大于3个
├─ page-module
│ ├─ a.ts
│ ├─ a.test.ts
│ ├─ b.ts
│ └─ b.test.ts

测试用例覆盖规范

node.js规范

文件内容结构

// 第三方资源类库或插件

// 全局资源库

// 局部资源库

/**
 * @当前业务
 * 具体逻辑实现代码
 */
module.exports = async function () {
  console.log("\n");
  // console.log(`|----- 一级目录 -----FILE_URL: ${__filename}`);

  // 初始化程序
  await init();
}


async function init() {
  await Example();
  await RouterConfig();
}


async function Example() {
  //
}

async function RouterConfig() {
  //
}



//暴露 module.exports对象
module.exports = {
  example
}


//暴露exports对象
exports.world = function () {
  console.log('Hello World');
}


async function test() {}
exports.test = test();


const JSON = {
  status: 200,
  message: '',
  data: {},
  list: [],
  extends: {}
}


API接口结构代码

仅限于ERP系统的后端API接口示例。

async function RouterConfig() {
  const suffixPath = "/ttvideo/by/tag/list/";
  const routePpath = TT_BASE_PATH + suffixPath;

  router.get(routePpath, async (ctx, next) => {
    const query = ctx.request.query;
    const headers = ctx.request.header;

    const resDt = {
      status_code: 0,
      status_msg: "success",
      data: {},
      extends: {}
    };

    ctx.body = resDt;
  });

  router.post(routePpath, async (ctx, next) => {
    const body = ctx.request.body;
    const headers = ctx.request.header;

    const resDt = {
      status_code: 0,
      status_msg: "success",
      data: {},
      extends: {}
    };

    ctx.body = resDt;
  });
}


async function getList(params = {}) {
  const { page, limit } = params || {};
  const limitVal = limit || 20;

  const date = dateUtil();
  const uuid = uuidUtil();
  const sinogram = generateRandomSinogramUtil(20);

  const list = [];

  for (let i = 0; i < limitVal; i++) {
    const item = {
      //
    };

    list.push(item);
  }

  return list;
}
Last Updated:
Contributors: 709992523, Eshen