VortMall 技术指南
开发规范
开发规范
1. 代码风格
1.1 格式化(Prettier)
- 统一使用 Prettier 做代码格式化,避免手工调整风格。
- 配置文件:
.prettierrc.jsontabWidth: 4printWidth: 160semi: truesingleQuote: false(统一双引号)trailingComma: noneendOfLine: lf
- 命令:
npm run format(对src/执行写入式格式化)
1.2 代码规范检查(ESLint)
- 配置文件:
eslint.config.ts(flat config) - 启用规则集:
eslint-plugin-vue:flat/essential@vue/eslint-config-typescript:recommended@vue/eslint-config-prettier/skip-formatting:跳过与 Prettier 冲突的格式化规则
- 忽略目录:
dist/、dist-ssr/、coverage/ - 命令:
npm run lint(默认带--fix --cache)
1.3 类型检查(TypeScript / vue-tsc)
- 类型检查命令:
npm run type-check(vue-tsc --build) - 严格构建:
npm run build:strict(先类型检查,再构建) - 路径别名:
@/* -> src/*(见tsconfig.json/tsconfig.app.json)
1.4 开发/构建脚本(Vite)
npm run dev:本地开发npm run build:构建产物npm run preview:本地预览构建产物
1.5 换行、编码、尾空格(EditorConfig)
- 配置文件:
.editorconfig - 统一约束:
charset = utf-8trim_trailing_whitespace = trueend_of_line = lf
2. 命名与文件组织
2.1 命名规范
- 变量 / 函数:
camelCase - 类型:
PascalCase(UserInfo、PaginatedResult) - 组件:
PascalCase(UserCard.vue、LoginAgreement.vue) - 常量:
UPPER_SNAKE_CASE(仅对真正的常量使用)
2.2 文件与目录命名
- 页面目录(views):业务域用
kebab-case(如admin-merchant/、after-sales/) - 页面文件:
- 入口页统一
Index.vue - 详情页用
Detail.vue(如需要) - 表单页用
Form.vue(如需要)
- 入口页统一
- 组件文件:统一
PascalCase.vue - Hook / Composable 文件:
useXxx.ts(如useCrudPage.ts、useTenantPath.ts) - 导出聚合:目录
index.ts作为统一出口(如components/common/**/index.ts、stores/index.ts) - 禁止项:
- 文件名包含空格(例如
xxx copy.vue) - 文件名包含
copy、new等临时标记
- 文件名包含空格(例如
2.3 导入约定
- 路径优先用别名:
@/xxx,避免../../..。 - 类型导入:优先
import type { ... } from "..."。 - 环境变量读取:只从
import.meta.env读取。
3. Vue 组件开发规范
3.1 SFC 写法
- 默认使用:
<script setup lang="ts"> - 页面/组件命名:使用
defineOptions({ name: "Xxx" })(便于调试/KeepAlive/埋点) - Props / Emits:
- props 命名使用
camelCase(模板中可使用kebab-case) - 需要默认值的 props 必须给默认值
- props 命名使用
3.2 组件自动导入(Vort UI)
- 组件自动导入由
unplugin-vue-components+ 自定义解析器VortResolver实现(见vite.config.ts、src/components/vort/resolver.ts)。 - 允许两种写法(无需手动 import):
<vort-button />(kebab-case)<VortButton />(PascalCase)
- 类型声明文件:自动生成到
src/components.d.ts(不要手改,避免被覆盖)。
3.3 Teleport 挂载点
- 根组件
App.vue内提供#vort-teleport-container作为统一挂载点,弹层类组件应优先挂载到该容器,确保层级与 CSS 变量继承一致。
4. 路由规范(Vue Router)
4.1 路由组织
- 路由入口:
src/router/index.ts - 路由守卫:
src/router/guards.ts - 模块路由:
src/router/routes/**
4.2 多租户 URL 约定
- 多租户解析工具:
src/utils/business/tenant.ts - 关键原则:
- URL 是唯一上下文源:优先从 URL 解析
tenantId与adminType(token 解码后得到shop/vendor/...) - 需要租户的端必须在 URL 中同时包含
tenantId与adminType token,缺失视为旧链接并重定向 - 导航拼接租户前缀时使用
resolveTenantPath()/buildTenantPath(),不要手写字符串拼接
- URL 是唯一上下文源:优先从 URL 解析
4.3 路由守卫约定
- 白名单路由(无需登录):
/login - 未登录:无
accessToken时跳转/login - 动态菜单加载:首次进入需要按权限加载菜单并注入路由(由
menus相关 store/util 实现)
5. 状态管理规范(Pinia)
5.1 Store 组织
- store 入口:
src/stores/index.ts - 模块 store:
src/stores/modules/*.ts - 推荐写法:
defineStore("xxx", () => { ... })(Composition API store)
5.2 持久化与运行时上下文
- 使用
pinia-plugin-persistedstate。 - 仅持久化可跨标签共享的最小数据(当前约定:
accessToken、userInfo)。 - adminType 以 URL 为准:
- 不依赖 localStorage 的
adminType残留值 afterHydrate后从 URL 同步到 store
- 不依赖 localStorage 的
- 每标签页隔离的数据(例如店铺/供应商运行时信息)使用
sessionStorage,并以tenantId + adminType作为 key 维度隔离。
6. 请求与接口规范(Axios)
6.1 统一请求入口
- 统一封装:
src/api/request.ts - 再导出入口:
src/utils/request.ts(禁止绕开封装直接使用 axios)
6.2 环境变量与 baseURL
baseURL由环境变量拼接:VITE_BASE_URLVITE_REQUEST_URL_PREFIX(可被单次请求config.prefix覆盖)
6.3 环境变量清单(项目实际读取)
- 路由 base:
VITE_BASE_DIR(用于createWebHistory与 Vitebase) - 请求 base:
VITE_BASE_URL - 请求前缀:
VITE_REQUEST_URL_PREFIX - 默认登录账号(平台端):
VITE_DEFAULT_USER_NAMEVITE_DEFAULT_USER_PASSWORD
- 默认登录账号(商户端/门店端):
VITE_DEFAULT_STORE_NAMEVITE_DEFAULT_STORE_PASSWORD
6.3 请求头约定
satoken:从localStorage.accessToken读取X-ADMIN-TYPE:从 store 读取,URL 兜底X-ClIENT-TYPE:固定为admin- 多租户 header:
X-Shop-Id:商户端/门店端X-Vendor-Id:供应商端
6.4 FormData 上传
config.data为FormData时不手动设置Content-Type,避免 boundary 丢失。
6.5 响应结构与错误处理
- 统一响应结构(
src/types/api.d.ts):code: numbermessage: stringdata: T
- 成功条件:
code === 0 - 失败条件:
code > 0- 统一 reject,错误对象至少包含
code/message/data
- 统一 reject,错误对象至少包含
- 登录失效:
code === 401或 HTTP401/403:触发登出流程(userStore.logout())
- 禁止项:
- 页面中重复写
try/catch + toast逻辑(优先复用封装与统一提示) - 在业务层随意吞掉错误(除非明确标注“额外数据获取,不影响主流程”)
- 页面中重复写
7. 业务 Hook / 组合式函数规范
7.1 Hook 目录与职责
src/hooks/:面向页面/业务场景的 Hook(如useCrudPage、useDialogForm)src/composables/:更通用的组合式工具(如租户路径处理)
7.2 useCrudPage 约定(列表页统一模式)
useCrudPage负责:- 分页参数(
page/size)与列表加载 - 搜索提交与重置
- 表格排序
- 选中行与批量操作
- 分页参数(
- 失败提示使用
@/components/vort/message,避免各页自行实现重复提示逻辑。
8. 样式规范(Tailwind / SCSS / Less)
8.1 全局样式入口
src/assets/styles/index.css- Tailwind v4:
@import "tailwindcss"; - 动画库:
@import "tw-animate-css"; @theme inline/ CSS 变量作为主题映射基础
- Tailwind v4:
src/theme/index.scss- Vort 主题变量与全局覆盖(配合
variables.scss)
- Vort 主题变量与全局覆盖(配合
8.2 新增样式优先级
- 优先:Tailwind 工具类(与 CSS 变量配合)
- 需要全局一致时:写入
src/theme/index.scss - 仅影响当前组件时:
<style scoped>,跨组件覆盖使用:deep() - Less 使用场景:既有页面已使用
<style lang="less" scoped>,新增保持与页面一致即可
9. 注释与可维护性
9.1 注释风格
- 对外导出的函数/工具/复杂逻辑使用 JSDoc(含
@param、@returns、示例)。 - 注释目标:
- 解释“为什么这么做”(why),而不是重复代码本身(what)。
9.2 错误类型与 unknown
catch (error)后优先以unknown处理,再做最小必要的类型收窄/断言。- 避免把
any作为默认方案(除非在封装层做兼容兜底)。
10. 图片与截图(文档配图)
- 建议放置目录:
docs/文章文档/assets/ - 命名建议:
yyyyMMdd_模块_主题.png(例如20260128_登录_验证码流程.png)
大纲
开发规范
1. 代码风格
1.1 格式化(Prettier)
1.2 代码规范检查(ESLint)
1.3 类型检查(TypeScript / vue-tsc)
1.4 开发/构建脚本(Vite)
1.5 换行、编码、尾空格(EditorConfig)
2. 命名与文件组织
2.1 命名规范
2.2 文件与目录命名
2.3 导入约定
3. Vue 组件开发规范
3.1 SFC 写法
3.2 组件自动导入(Vort UI)
3.3 Teleport 挂载点
4. 路由规范(Vue Router)
4.1 路由组织
4.2 多租户 URL 约定
4.3 路由守卫约定
5. 状态管理规范(Pinia)
5.1 Store 组织
5.2 持久化与运行时上下文
6. 请求与接口规范(Axios)
6.1 统一请求入口
6.2 环境变量与 baseURL
6.3 环境变量清单(项目实际读取)
6.3 请求头约定
6.4 FormData 上传
6.5 响应结构与错误处理
7. 业务 Hook / 组合式函数规范
7.1 Hook 目录与职责
7.2 useCrudPage 约定(列表页统一模式)
8. 样式规范(Tailwind / SCSS / Less)
8.1 全局样式入口
8.2 新增样式优先级
9. 注释与可维护性
9.1 注释风格
9.2 错误类型与 unknown
10. 图片与截图(文档配图)
赣公网安备36010902001041号