14 KiB
14 KiB
交互规范
1、使用中文交互
项目架构概览
技术栈
| 层级 | 技术 |
|---|---|
| 框架 | Vue 3 + TypeScript 5 |
| 构建 | Vite 4 |
| UI 组件库 | Ant Design Vue 3 |
| 状态管理 | Pinia 2 |
| 路由 | Vue Router 4 |
| HTTP | Axios(自定义封装defHttp) |
| 样式 | Less + Windi CSS |
| 国际化 | Vue I18n 9 |
| 基础框架 | Vben Admin(深度定制) |
| 包管理 | pnpm |
注意:本项目与 Vue 3.4.x 不兼容,请保持 Vue ~3.3.4。
目录结构
src/
├── api/ # HTTP 请求模块,按业务域分组
│ └── <domain>/
│ └── <module>/
│ ├── index.ts # 请求函数
│ └── model/ # 请求/响应 TS 类型
├── assets/ # 静态资源、全局样式
├── components/ # 可复用组件(BasicTable、BasicForm、Modal 等)
├── design/ # 全局 Less 主题入口
├── hooks/ # 组合式函数(composables)
├── layouts/ # 布局组件(header、sider、tabs)
├── locales/ # i18n 配置
├── router/ # 路由配置、守卫
├── store/ # Pinia 状态模块
│ └── modules/ # app / user / permission / locale / lock / multipleTab
├── utils/ # 工具函数
│ └── http/axios/ # HTTP 封装核心
└── views/ # 业务页面,按业务域分组
└── <domain>/ # erp / system / workflow / contract / sales ...
路径别名
| 别名 | 指向 |
|---|---|
/@/ |
src/ |
/#/ |
types/ |
/@bpmn/ |
src/views/workflow/design/bpmn/ |
始终使用别名,禁止使用相对路径 ../../。
代码规范
1. Vue 组件
新文件优先使用 <script setup>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
const visible = ref(false);
</script>
存量代码中存在 defineComponent 写法,维护时保持原有风格,新增代码统一用 <script setup>。
文件命名
| 场景 | 规范 | 示例 |
|---|---|---|
| 页面入口 | index.vue |
src/views/system/user/index.vue |
| 弹窗/子组件 | PascalCase | UserModal.vue、DetailDrawer.vue |
| 组合式函数 | camelCase | useUserList.ts |
事件处理函数命名
统一以 handle 开头:handleEdit、handleDelete、handleSubmit。
2. API 模块
每个业务模块的 API 结构:
src/api/<domain>/<module>/
├── index.ts # 导出请求函数
└── model/
└── index.ts # 请求/响应类型定义
示例:
// src/api/erp/purchase/apply/index.ts
import { defHttp } from '/@/utils/http/axios';
import type { ApplyListParams, ApplyListResult } from './model';
enum Api {
List = '/erp/purchase/apply/list',
Save = '/erp/purchase/apply/save',
}
export const getApplyList = (params: ApplyListParams) =>
defHttp.get<ApplyListResult>({ url: Api.List, params });
export const saveApply = (data: ApplyListParams) =>
defHttp.post({ url: Api.Save, data });
- 所有 HTTP 请求必须通过
defHttp,禁止直接使用 axios。 - 接口路径统一用
enum Api管理。 - 错误提示通过
errorMessageMode控制('modal'|'message'|'none')。
3. 状态管理(Pinia)
// src/store/modules/xxx.ts
import { defineStore } from 'pinia';
import { store } from '/@/store';
export const useXxxStore = defineStore({
id: 'app-xxx',
state: () => ({ ... }),
getters: { ... },
actions: { ... },
});
// 在 setup 外使用
export function useXxxStoreWithOut() {
return useXxxStore(store);
}
- Store 命名:
useXxxStore - 需要在 setup 外调用时,导出
useXxxStoreWithOut
4. 表格页面(CRUD 标准模式)
<template>
<PageWrapper>
<BasicTable @register="registerTable">
<template #toolbar>
<a-button type="primary" @click="handleAdd">新增</a-button>
</template>
<template #action="{ record }">
<TableAction :actions="getActions(record)" />
</template>
</BasicTable>
<XxxModal @register="registerModal" @success="reload" />
</PageWrapper>
</template>
<script setup lang="ts">
import { useTable } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { PageWrapper } from '/@/components/Page';
import { TableAction } from '/@/components/Table';
const [registerTable, { reload }] = useTable({
api: getXxxList,
columns,
useSearchForm: true,
formConfig: { schemas },
showTableSetting: true,
bordered: true,
});
const [registerModal, { openModal }] = useModal();
function handleAdd() {
openModal(true, { isUpdate: false });
}
function getActions(record) {
return [
{ label: '编辑', onClick: () => openModal(true, { record, isUpdate: true }) },
{ label: '删除', color: 'error', popConfirm: { title: '确认删除?', confirm: () => handleDelete(record) } },
];
}
</script>
5. 样式规范
- 组件内样式:
<style lang="less" scoped> - 全局主题变量在
src/design/和src/assets/style/theme/中定义 - 工具类优先使用 Windi CSS(如
flex、items-center、mt-4) - 项目自定义主题类前缀:
lng- - 禁止在 scoped 样式中直接穿透 AntD 组件,改用
:deep()
// 正确
:deep(.ant-table-cell) {
padding: 8px;
}
6. TypeScript 规范
- 严格模式已开启(
strict: true),但项目对any较宽松 - API 请求/响应类型放在对应
model/目录 - 通用类型放在
types/目录,通过/#/别名引用 - 变量命名:
ref变量加Ref后缀:visibleRef、loadingRef- computed 可加
ComputedRef后缀
7. 国际化
所有用户可见文本必须通过 i18n:
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
// 使用
t('common.okText')
8. 权限控制
按钮级权限通过 v-auth 指令或 usePermission 控制:
<a-button v-auth="'system:user:add'">新增</a-button>
import { usePermission } from '/@/hooks/web/usePermission';
const { hasPermission } = usePermission();
if (hasPermission('system:user:edit')) { ... }
9. 工作流路由约定
特殊路由格式(在 src/router/routes/basic.ts 中定义):
| 路由 | 用途 |
|---|---|
/flow/:arg1/:arg2/createFlow |
发起流程 |
/flow/:arg1/:arg2/approveFlowPage |
审批流程 |
/form/:module/:id/createForm |
通用表单新建 |
/form/:module/:id/updateForm |
通用表单编辑 |
/flowList/todo |
待办列表 |
10. 提交规范
遵循 Conventional Commits:
feat: 新增功能
fix: 修复 bug
refactor: 重构
style: 样式调整
docs: 文档更新
chore: 构建/工具变更
新增页面检查清单
- 在
src/views/<domain>/下创建目录 - 页面入口为
index.vue,弹窗为XxxModal.vue - API 模块放在
src/api/<domain>/<module>/index.ts - 类型定义放在
model/index.ts - 使用
PageWrapper+BasicTable+useTable+useModal标准结构 - 文本通过
useI18n国际化 - 按钮权限通过
v-auth控制 - 样式使用
<style lang="less" scoped> - 路径使用
/@/别名
代码生成器(generator)规范
目录结构
src/views/generator/
├── codeTemplate/ # 模板管理列表(草稿增删改查)
├── designer/ # 表单设计器演示/测试页
├── dev/ # 代码生成器核心入口
│ ├── choose.vue # 模式选择入口页
│ └── components/
│ ├── DataFirstModal.vue # 数据优先向导
│ ├── CodeFirstModal.vue # 界面优先向导
│ ├── SimpleTemplateModal.vue # 简易模板向导
│ ├── PreviewCodeStep.vue # 代码预览步骤(三种模式共用)
│ └── SelectDatabase.vue # 选择数据库表弹窗
├── desktop/ # 桌面/首页可视化设计器
├── order/ # 示例产物(订单模块演示)
└── print/ # 打印模板设计器
步骤子组件统一放在 /@/components/CreateCodeStep/src/ 下。
三种生成模式
| 维度 | 数据优先 | 界面优先 | 简易模板 |
|---|---|---|---|
designType |
'data' |
'code' |
'template' |
outputConfig.type |
0 |
1 |
2 |
| 起点 | 选数据库表 | 设计表单 | 设计表单(固定 master 库) |
| 表配置字段 | tableConfigs |
tableStructureConfigs |
tableStructureConfigs |
| 生成接口 | dataFirstGeneratorCode |
codeFirstGeneratorCode |
codeFirstGeneratorCode |
| 预览接口 | dataFirstPreviewCode |
codeFirstPreviewCode |
codeFirstPreviewCode |
| 特殊逻辑 | 无 | 自动推导主表名 | 额外判断字段大小写(Oracle/DM 等) |
简易模板本质是界面优先的变体,复用同一套后端生成接口,仅 type 不同。
核心设计模式
1. provide/inject 共享生成状态
父 Modal 通过 provide 下发,子步骤通过 inject 直接读写,禁止 props 层层传递:
provide('generatorConfig', generatorConfig) // 核心配置(reactive)
provide('tableInfo', tableInfo) // 表结构信息
provide('current', current) // 当前步骤索引
provide('designType', 'data') // 生成模式标识
provide('widgetForm', widgetForm) // 表单设计器状态
provide('mainTableName', mainTableName) // 主表名(界面优先/简易模板)
provide('isFieldUpper', isFieldUpper) // 字段大小写(简易模板)
2. ref + defineExpose 控制步骤流转
每个步骤子组件必须暴露 validateStep(),父组件通过 ref 统一调用:
// 子组件
defineExpose({ validateStep, initStep?, getFormData?, editFieldsValue? })
// 父组件
const stepValidate = {
0: () => tableConfigStepRef.value.validateStep(),
1: () => formDesignStepRef.value.validateStep(),
// ...
}
3. 前端本地生成 + 后端补全的混合模式
前端本地 buildCode() 后端接口 previewCode()
───────────────────── ──────────────────────
listCode(列表页) controllerCode(控制器)
formCode(表单页) entityCode(实体类)
apiCode(API 模块)
modelCode(TS 类型)
configJsonCode(路由配置)
4. hiddenComponent 生命周期
// 编辑模板时:从列表剔除,不在设计器中展示
formJson.list = formJson.list.filter(x => x.type !== 'hiddenComponent')
// 正式生成时:重新塞回,参与代码生成
generatorConfig.formJson.list.push(...generatorConfig.formJson.hiddenComponent)
5. 两段式下载
生成接口 → 返回 uuid → downloadCodes(uuid) → 下载 zip
核心数据结构
GeneratorConfig {
databaseId: string | null
listConfig: {
isLeftMenu, queryConfigs, leftMenuConfig,
columnConfigs, buttonConfigs, defaultOrder, isPage
}
tableConfigs: TableConfig[] // 仅数据优先
tableStructureConfigs: [] // 界面优先/简易模板
formJson: FormJson // 表单设计结果
menuConfig: MenuConfig
outputConfig: {
creator, isMenu,
type: 0 | 1 | 2 // 生成模式
}
formEventConfig: FormEventColumnConfig
isDataAuth: boolean
dataAuthList: []
}
类型定义文件:src/api/system/generator/model/index.ts
API 接口
所有接口在 src/api/system/generator/index.ts:
| 函数 | 方法 | 路径 |
|---|---|---|
dataFirstGeneratorCode |
POST | /system/generator/generator-code/data-first |
codeFirstGeneratorCode |
POST | /system/generator/generator-code/code-first |
dataFirstPreviewCode |
POST | /system/generator/preview-code/data-first |
codeFirstPreviewCode |
POST | /system/generator/preview-code/code-first |
saveDraftGeneratorCode |
POST | /system/code-schema |
updateDraftGeneratorCode |
PUT | /system/code-schema |
getCodeTemplateInfo |
GET | /system/code-schema/info |
getCodeTemplateList |
GET | /system/code-schema/page |
deleteCodeTemplate |
DELETE | /system/code-schema |
getMasterInfo |
GET | /system/databaselink/master-info |
batchGeneratorCode |
POST | /system/generator/generator-code/batch |
downloadCodes |
GET | /system/generator/downloadCodes/{uuid} |
功能扩展指南
新增生成模式
- 复制
CodeFirstModal.vue,修改designType和outputConfig.type - 在
choose.vue加入入口卡片 - 在
codeTemplate/index.vue的路由名判断中加入新类型 - 后端新增对应生成/预览接口
新增向导步骤
- 在
/@/components/CreateCodeStep/src/下新建步骤组件,暴露validateStep() - 在主 Modal 的
<a-steps>中加入新步骤 - 在
stepValidate对象中加入对应索引的校验函数 - 在
generatorConfig中加入新步骤的配置字段,并通过provide下发
扩展代码预览输出类型
- 在
FrontCode类型中加入新字段 - 在
PreviewCodeStep.vue的<a-tabs>中加入新 tab - 在
validateStep()中加入非空校验 - 在
buildCode()或previewCode()中补充生成逻辑