FranklinWH-ToolBox AI 编程规范与操作规范
项目概览
本项目是 FranklinWH 内部工具箱平台,采用 monorepo 结构(pnpm workspace),包含前端 Web 应用和后端 API 服务。
- 前端:Vue 3 + TypeScript + Vite (rolldown-vite)
- 后端:Go 1.25+ + Fiber v2
- 包管理:pnpm(前端)、Go Modules(后端)
一、项目结构规范
前端目录结构(根目录)
src/
├── assets/ # 静态资源(CSS、图片、数据文件)
├── components/ # 全局通用组件
├── composable/ # Vue Composables(可组合函数)
├── event/ # 全局事件系统(EventEmitter)
├── injection/ # Vue provide/inject 相关
├── layout/ # 布局组件(header、aside、footer、main)
├── router/ # 路由配置、守卫、辅助函数
├── service/ # API 请求层(按业务模块分目录)
├── stores/ # Pinia 状态管理
├── theme/ # 主题配置(light/dark/common)
├── types/ # TypeScript 类型声明
├── typings/ # 全局类型扩展(window.d.ts、vue-router.d.ts)
├── utils/ # 工具函数
├── views/ # 页面视图组件(按业务模块分目录)
├── App.vue # 根组件
└── main.ts # 入口文件
后端目录结构(service/)
service/
├── cmd/ # 脚本(部署、构建、日志查看)
├── cache/ # 缓存层(Redis)
├── config/ # 配置加载(Viper)
├── controllers/ # 控制器层(请求处理、参数校验)
├── database/ # 数据库初始化(MySQL、PostgreSQL、MongoDB)
├── domain/ # 领域模型/实体定义
├── dto/ # 数据传输对象
├── docs/ # Swagger 文档
├── function/ # 功能模块(文件处理等)
├── jobs/ # 后台定时任务
├── logger/ # 日志配置(Zap)
├── middleware/ # 中间件(认证等)
├── models/ # 数据库模型(GORM)
├── networkEvents/ # 网络事件(Evio)
├── repositories/ # 数据访问层(MySQL/PgSQL/MongoDB/Redis/MQTT/API)
├── routes/ # 路由注册
├── scheduler/ # 定时调度器(Cron)
├── services/ # 业务逻辑层
├── task/ # 异步任务队列(Asynq)
├── test/ # 测试文件
└── utils/ # 工具包
二、前端编码规范
2.1 通用格式
| 项目 |
规范 |
| 缩进 |
2 空格 |
| 分号 |
不使用分号 |
| 引号 |
单引号 |
| 行宽 |
100 字符 |
| 行尾 |
LF |
| 尾逗号 |
ES5 风格 |
| 文件末尾 |
保留空行 |
2.2 TypeScript
- 启用严格模式(
strict: true)
- 使用路径别名
@/ 指向 src/
- 优先使用
interface 定义对象类型,type 用于联合类型/工具类型
- 避免
any,必要时使用 unknown 并进行类型收窄
- 导出类型时使用
export type / export interface
2.3 Vue 组件
<template>
<!-- 使用 UnoCSS 原子类 -->
<div class="flex items-center gap-4 p-4">
<NButton @click="handleClick">{{ displayTitle }}</NButton>
</div>
</template>
<script setup lang="ts">
// 1. 第三方库导入
import { NButton } from 'naive-ui'
import { ref, computed, onMounted } from 'vue'
// 2. 内部模块导入
import { useXxxStore } from '@/stores/xxx'
import type { SomeType } from '@/service/xxx/interface'
// 3. 组件选项
defineOptions({
name: 'ComponentName',
})
// 4. Props & Emits
const props = defineProps<{
title: string
count?: number
}>()
const emit = defineEmits<{
update: [value: string]
}>()
// 5. 响应式状态
const loading = ref(false)
// 6. 计算属性
const displayTitle = computed(() => `${props.title} (${props.count ?? 0})`)
// 7. 方法
function handleClick() {
emit('update', 'new value')
}
// 8. 生命周期
onMounted(() => {
// ...
})
</script>
关键约定:
- 使用
<script setup lang="ts"> + Composition API
- 使用
defineOptions({ name: 'XxxPage' }) 定义组件名
- Props 使用
defineProps<T>() 泛型语法
- Emits 使用
defineEmits<T>() 泛型语法
- 不在 template 中使用复杂表达式,提取为 computed 或方法
- 模板中组件使用 PascalCase(如
<NButton>)
2.4 Pinia Store
import { useStorage } from '@vueuse/core'
import { acceptHMRUpdate, defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useXxxStore = defineStore('xxxStore', () => {
// 持久化状态使用 useStorage
const data = useStorage<DataType>('storageKey', defaultValue)
// 非持久化状态使用 ref
const loading = ref(false)
// Getters 使用 computed
const isEmpty = computed(() => data.value.length === 0)
// Actions 使用普通函数
function reset() {
data.value = defaultValue
}
return {
data,
loading,
isEmpty,
reset,
}
})
// HMR 支持(必须)
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useXxxStore, import.meta.hot))
}
2.5 Service 层(API 请求)
每个业务模块在 src/service/ 下创建独立目录,包含:
index.ts — API 函数导出
interface.ts — 请求/响应类型定义
// src/service/moduleName/interface.ts
export interface ModuleItem {
id: string
name: string
createdAt: string
}
// src/service/moduleName/index.ts
import http from '@/service/serverReq'
import type { ModuleItem } from './interface'
const API_List = {
list: '/moduleName/list',
detail: '/moduleName/detail',
}
export const getModuleList = async (page: number, size: number): Promise<ModuleItem[]> => {
return await http.get<ModuleItem[]>(API_List.list, {
params: { page, size },
})
}
export const getModuleDetail = async (id: string): Promise<ModuleItem> => {
return await http.get<ModuleItem>(API_List.detail, {
params: { id },
})
}
2.6 样式规范
- 优先使用 UnoCSS 原子类,避免自定义 CSS
- 暗色模式使用
dark: 前缀变体
- 响应式使用
sm: / md: / lg: / xl: 前缀
- CSS 变量引用使用
var(--xxx) 语法(如 bg-[var(--card-color)])
- 图标使用 UnoCSS Icons(如
i-ph:arrow-up、i-mdi:close)
- 过渡动画使用项目自定义
transition-[property]-duration 规则
2.7 路由
- 路由记录定义在
src/router/record.ts
- 懒加载页面组件:
component: () => import('@/views/xxx/index.vue')
- 页面视图目录使用 kebab-case 命名(如
site-info-manage)
- 路由 name 使用 camelCase(如
siteInfoManage)
三、后端编码规范(Go)
3.1 分层职责
| 层级 |
职责 |
命名规范 |
| routes |
路由注册 |
xxxRoutes.go |
| controllers |
请求处理、参数校验、响应格式化 |
xxxControllers.go |
| services |
业务逻辑编排 |
xxxServices.go |
| repositories |
数据访问(DB/Cache/API/MQTT) |
按数据源分子目录 |
| domain |
领域实体结构定义 |
xxxDomain.go |
| dto |
请求/响应数据传输对象 |
xxxDTO.go |
3.2 路由文件
package routes
import (
"fwh-toolbox-server/controllers"
"github.com/gofiber/fiber/v2"
)
func XxxSetup(api fiber.Router) {
api.Get("/xxx/list", controllers.GetXxxList)
api.Post("/xxx/create", controllers.CreateXxx)
}
3.3 Controller
package controllers
import (
"fwh-toolbox-server/services"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
)
func GetXxxList(c *fiber.Ctx) error {
page := c.QueryInt("page", 1)
size := c.QueryInt("size", 20)
data, err := services.GetXxxList(uint(page), uint(size))
if err != nil {
zap.L().Error("GetXxxList failed.", zap.String("err", err.Error()))
return Error(c, "Get xxx list failed.")
}
return Success(c, data)
}
关键约定:
- 使用统一响应函数:
Success、SuccessPage、Fail、Error、NotFound、Unauthorized、Forbidden
- 参数校验在 Controller 层完成
- 错误日志使用
zap.L() 结构化日志
- 业务错误返回中文/英文描述,不暴露内部错误细节
3.4 Service
package services
import (
"fwh-toolbox-server/repositories"
"go.uber.org/zap"
)
func GetXxxList(page, size uint) (*SomeResult, error) {
data, err := repositories.GetXxxList(page, size)
if err != nil {
zap.L().Error("repositories.GetXxxList failed.",
zap.String("err", err.Error()),
zap.Uint("page", page),
zap.Uint("size", size),
)
return nil, err
}
// 业务逻辑处理...
return result, nil
}
3.5 日志规范
- 使用
go.uber.org/zap 结构化日志
- 日志级别:
Debug < Info < Warn < Error < Fatal
- 错误日志必须包含错误信息和关键上下文参数
- 格式:
zap.L().Error("描述", zap.String("key", value), ...)
3.6 配置管理
- 使用 Viper 读取配置(支持
.env 文件 + 环境变量)
- 配置结构体定义在
config/config.go
- 密码等敏感信息通过环境变量注入,不硬编码
四、通用开发规范
4.1 命名规范
| 类型 |
前端 |
后端 |
| 文件名 |
camelCase.ts / kebab-case.vue |
camelCase.go |
| 变量 |
camelCase |
camelCase |
| 常量 |
UPPER_SNAKE_CASE 或 camelCase |
UPPER_SNAKE_CASE 或 camelCase |
| 函数 |
camelCase |
PascalCase(导出)/ camelCase(私有) |
| 类型/接口 |
PascalCase |
PascalCase |
| 组件 |
PascalCase(.vue 文件名可 index.vue 或 camelCase) |
— |
| CSS 类 |
UnoCSS 原子类 / kebab-case |
— |
| 路由路径 |
kebab-case |
camelCase |
| 目录名 |
kebab-case(views)/ camelCase(service、stores) |
camelCase |
4.2 Git 提交规范
<type>(<scope>): <subject>
type: feat | fix | docs | style | refactor | perf | test | chore | ci
scope: 可选,影响范围(如 frontend, backend, router, store)
subject: 简短描述,不超过 50 字符
4.3 注释规范
五、工具链与命令
前端命令
| 命令 |
用途 |
pnpm dev |
启动开发服务器 |
pnpm build |
类型检查 + 生产构建 |
pnpm test:unit |
运行 Vitest 单元测试 |
pnpm test:e2e |
运行 Playwright E2E 测试 |
pnpm lint |
ESLint 检查 |
pnpm lint:fix |
ESLint 自动修复 |
pnpm format:check |
Prettier 格式检查 |
pnpm format:fix |
Prettier 自动格式化 |
后端命令
| 命令 |
用途 |
go run main.go |
启动服务(在 service/ 目录执行) |
go build -o fwh-toolbox-server |
编译(在 service/ 目录执行) |
go test ./... |
运行测试 |
./cmd/deploy.sh |
部署脚本(在 service/ 目录执行) |
ESLint 配置要点
- 基于
@antfu/eslint-config
- 禁用的规则:
perfectionist/sort-imports、vue/block-order、no-console(开发期)
- 强制 Vue SFC 使用
<script lang="ts"> 或 <script lang="tsx">
- 启用 UnoCSS、Vitest、Playwright 插件支持
六、AI 操作规范
6.1 代码生成
- 生成前端代码时,遵循本项目的 Composition API +
<script setup> 风格
- 使用 Naive UI 组件库,不引入其他 UI 框架
- 样式优先使用 UnoCSS 原子类
- API 请求使用
@/service/serverReq 中封装的 http 实例
- 新页面按
src/views/module-name/index.vue 结构创建
- 新 API 模块按
src/service/moduleName/{index.ts, interface.ts} 结构创建
- Store 使用 setup function 风格 + HMR 热更新支持
- 后端新增接口遵循 routes → controllers → services → repositories 分层
6.2 代码修改
- 修改前先读取相关文件,理解现有实现
- 保持与周围代码一致的风格
- 不随意删除注释掉的代码(可能是有意保留的备选方案)
- 修改前需详细说明修改或创建的内容,获得同意后再写入文件
- 修改后确保通过
pnpm lint 检查
6.3 依赖管理
- 前端使用 pnpm 安装依赖,锁定具体版本
- 后端使用
go get 添加依赖
- 不引入与现有技术栈冲突的库(如不使用 Axios、Element UI、Tailwind CSS)
- 工具函数优先使用
es-toolkit(替代 lodash)
- 日期处理使用
dayjs
- 状态持久化使用
@vueuse/core 的 useStorage
6.4 类型安全
- 所有新增 API 响应必须定义 TypeScript 接口
- 后端 DTO 结构体必须添加 JSON tag
- 避免使用
any、interface{}(Go 中优先使用泛型或具体类型)
6.5 测试
- 单元测试文件放在
src/**/__tests__/ 下
- 使用 Vitest 编写测试,测试文件后缀
.test.ts
- E2E 测试放在
e2e/ 目录,使用 Playwright
- 后端测试放在
service/test/ 目录
6.6 安全注意事项
- 不在代码中硬编码密钥、Token、密码
.env 文件中的敏感配置不应被提交到仓库
- API 请求自动附带 Authorization header(通过拦截器)
- 后端使用 middleware 进行认证校验
6.7 文件操作
- 编辑前端文件时,工作目录为项目根目录
- 编辑后端文件时,注意文件在
service/ 子目录内
- Go 模块路径为
fwh-toolbox-server
- Go import 使用完整模块路径(如
fwh-toolbox-server/controllers)
七、技术栈速查
前端核心依赖
| 库 |
用途 |
版本要求 |
| Vue 3 |
框架 |
^3.5 |
| Naive UI |
UI 组件库 |
^2.44 |
| Pinia |
状态管理 |
^3.0 |
| Vue Router |
路由 |
^5.0 |
| VueUse |
组合式工具 |
^14.x |
| UnoCSS |
原子 CSS |
^66.x |
| @antv/g2 |
图表 |
^5.x |
| es-toolkit |
工具函数 |
^1.x |
| dayjs |
日期处理 |
^1.x |
| monaco-editor |
代码编辑器 |
^0.55 |
后端核心依赖
| 库 |
用途 |
| Fiber v2 |
Web 框架 |
| GORM |
ORM(MySQL/PostgreSQL) |
| mongo-driver |
MongoDB 驱动 |
| go-redis/v9 |
Redis 客户端 |
| zap |
结构化日志 |
| viper |
配置管理 |
| asynq |
异步任务队列 |
| cron/v3 |
定时任务 |
| minio-go |
对象存储 |
| paho.mqtt |
MQTT 客户端 |
| casdoor-go-sdk |
SSO 认证 |
| excelize |
Excel 处理 |
| swag |
Swagger 文档生成 |