前端开发准备
前端使用 Vue 3、TypeScrIPt、Vite 和 Element Plus。
固定运行环境:
node -v
pnpm -v
推荐版本:
Node.js 22.22.3
pnpm 10.34.3
安装依赖:
cd frontend
pnpm install
启动前端:
pnpm run dev
访问地址:
http://localhost:5173
也可以通过 Gradle 启动:
gradle frontend
远程环境配置
本地开发时可通过 .env.local 修改后端访问地址。
code .env.local
示例:
VITE_VUE_APP_BASE_DOMAIN=http://localhost:8080
如果需要连接远程环境:
VITE_VUE_APP_BASE_DOMAIN=http://101.132.73.185:8080
前端项目结构
前端采用“基础应用 + 可移除业务模块”的分层结构。
src/
app/ # 基础应用层,不能静态依赖 modules
api/ # 登录、认证等基础接口
assets/ # 全局样式、图片、字体等静态资源
components/ # 全局通用组件,只能依赖 app/shared/utils 等基础能力
hooks/ # 全局通用 hooks
layout/ # 页面布局、顶部栏、菜单、面包屑
lib/ # 通用前端库或可复用引擎
management/ # 平台内置管理功能:租户、用户、角色、授权、SSO 等
plugins/ # HTTP 请求插件等基础插件
router/ # 基础路由、路由守卫、模块路由自动发现
routes/ # 平台、管理员、工作区管理等基础路由分组
shared/ # 跨业务模块共享的稳定能力
api/ # 共享接口 facade,例如资源查询、用户、授权等
components/ # 跨业务模块复用的通用组件
hooks/ # 跨业务模块复用 hooks
utils/ # 跨业务模块复用工具
store/ # 全局状态
utils/ # 基础工具、http、事件总线、格式化等
views/ # 登录、首页、系统错误页等基础页面
modules/ # 业务模块层,可移除;删除后基础 app 仍需可编译
access-rule/
computer-group/
custom-api/
custom-form/
custom-func/
data-planning/
datasource/
driver-management/
file-center/
global-variables/
home-overview/
lib-package/
message-center/
metadata-page/
realtime-computing/
report/
schedule/
spark-container/
workflow/
分层职责
src/app是基础平台层,放应用启动、布局、基础路由、全局 store、通用组件、通用工具、平台管理和 shared 能力。src/app/management放平台内置管理功能,例如租户、用户、角色、授权和 SSO。src/app/routes放平台、管理员、工作区管理等基础路由分组。src/app/shared放多个业务模块共享的 API、组件、hooks 和工具。src/modules是业务模块层,每个业务模块拥有自己的api、views、routes.ts、index.ts,可按需提供components、config.ts、share-routes.ts。src/services和src/views已废弃,不要重新创建;应用级页面放在src/app/views,业务页面放在src/modules/*/views。
模块标准结构
新增业务模块时,推荐使用以下结构:
src/modules/<module-name>/
api/ # 模块自己的业务接口
views/ # 模块页面
components/ # 模块公开或内部组件
config.ts # 可被其他模块复用的稳定配置,可选
routes.ts # 工作区路由,必需
share-routes.ts # 分享页/公开页路由,可选
index.ts # 模块 public export,必需
工作区路由统一写在:
src/modules/<module-name>/routes.ts
公开分享页路由写在:
src/modules/<module-name>/share-routes.ts
基础路由会通过 src/app/router/module-routes.ts 自动发现模块路由,不需要在基础应用中手动 import 具体业务模块。
Import 规则
基础层规则:
src/app不能静态 import@/modules。src/app/components必须保持通用,不能依赖具体业务模块。- 基础层需要业务模块路由时,由
src/app/router/module-routes.ts自动发现src/modules/*/routes.ts和src/modules/*/share-routes.ts。
业务模块规则:
- 模块内部优先使用相对路径或本模块 public surface。
- 跨模块只能导入对方 public surface。
import { GetWorkflowList } from '@/modules/workflow/api'
import { TypeList } from '@/modules/workflow/config'
import { ZqyFlow } from '@/modules/workflow/components'
import { workflowRoutes } from '@/modules/workflow'
禁止跨模块 deep import 对方内部页面或私有路径:
// 禁止
import WorkItem from '@/modules/workflow/views/work-item/index.vue'
多个模块复用的稳定资源查询放到 src/app/shared/api/resources.ts:
import { GetDatasourceList, GetComputerGroupList } from '@/app/shared/api/resources'
业务模块不要直接 import src/app/management 下的接口。需要用户、授权、租户等平台数据时,先在 src/app/shared/api 暴露 facade:
import { GetUserList } from '@/app/shared/api/user'
import { CheckLicenseStatus } from '@/app/shared/api/license'
应用级能力统一从 @/app 下导入:
import { LoginUserInfo } from '@/app/api'
命名规范
文件和目录统一使用中划线命名。
component-demo/
component-demo.vue
Vue 组件引用统一使用中划线小写模式:
<component-demo></component-demo>
组件开发规范
- 弹窗和抽屉优先使用
src/app/components下已有组件。 - 复用性高、与业务无关的组件放到
src/app/components。 - 业务相关组件放在所属模块的
components目录。 src/app/components不能依赖具体业务模块。- Vue 文件的 script 标签统一使用
<script lang="ts" setup>。 - Vue 文件的 style 标签统一使用 SCSS。
- 样式类名根据模块名命名,尽量使用一个根节点包裹。
src/app/lib中开发的新组件统一使用zqy-组件名形式命名。- 复杂逻辑需要保留必要注释。
列表页面规范
管理类列表页面优先使用 src/app/components/block-table/index.vue。新增或改造列表时,需要保持列表结构、表头、操作栏和批量操作体验一致。
基础布局
- 页面顶部统一使用
Breadcrumb。 - 列表页面根节点使用
zqy-seach-table,并追加当前页面独立类名,例如user-center-page、tenant-list-page。 - 顶部工具栏使用
zqy-table-top,左侧放主操作按钮,右侧放搜索输入框。 - 搜索输入框宽度沿用全局
.zqy-seach .el-input,占位文案使用“请输入 xxx 回车进行搜索”。 - 表格外层使用
zqy-table,表格组件使用BlockTable。 - 加载和网络异常统一使用
LoadingPage包裹表格区域。
表格列
- 表格配置统一维护在页面同级
*.config.ts中,不要把列配置散落在模板里。 colConfigs中操作列固定在右侧,配置fixed:'right'。- 第一列默认由
BlockTable固定在左侧;如页面开启多选,序号列会自动切换为选择列。 - 表头不允许换行。长表头通过列宽或最小宽度承载,必要时使用横向滚动,不要依赖换行展示。
- 列标题必须使用清晰业务名称,避免过长描述;如标题较长,应给足
minWidth。 - 长文本内容开启
showOverflowTooltIP:true。 - 状态列统一使用
el-tag,常用状态颜色:ENABLE:type="success",显示“启用”。DISABLE:type="danger",显示“禁用”。APPLYING或待处理状态:type="warning"。
行操作栏
- 管理列表的行操作栏统一为“主要操作 + 更多”模式。
- 常用主操作只保留一个,例如
编辑;其余操作放入更多下拉。 - 如果没有合适的主操作,操作栏只显示居中的
更多。 - 操作列文字按钮使用
span,不要使用普通el-button挤占表格高度。 - 行操作容器需要水平居中,间距统一:
<template #options="scopeSlot">
<div class="btn-group page-action-group">
<span class="page-action-button" @click="editData(scopeSlot.row)">编辑</span>
<el-dropdown trigger="click" popper-class="page-action-dropdown">
<span class="click-show-more page-action-button">更多</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="changeStatus(scopeSlot.row)">
{{ scopeSlot.row.status === 'ENABLE' ? '禁用' : '启用' }}
</el-dropdown-item>
<el-dropdown-item @click="deleteData(scopeSlot.row)">删除</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
操作栏样式需要按页面类名隔离,避免污染其他页面:
.page-action-group {
justify-content: center;
gap: 16px;
.page-action-button {
display: inline-flex;
align-items: center;
line-height: 1;
font-size: getCssVar('font-size', 'extra-small');
color: getCssVar('color', 'primary');
cursor: pointer;
white-space: nowrap;
}
}
更多操作规范
更多操作统一使用 Element Plus el-dropdown,触发方式为点击:
<el-dropdown trigger="click" popper-class="page-action-dropdown">
<span class="click-show-more page-action-button">更多</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>启用</el-dropdown-item>
<el-dropdown-item>禁用</el-dropdown-item>
<el-dropdown-item>删除</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
下拉样式统一保持紧凑:
.page-action-dropdown {
.el-dropdown-menu {
padding: 4px 0;
min-width: 76px;
}
.el-dropdown-menu__item {
height: 26px;
line-height: 26px;
font-family: Avenir, Helvetica, Arial, sans-serif;
font-size: getCssVar('font-size', 'extra-small');
}
}
更多操作的文案规则:
- 文案必须短、明确,优先使用动宾结构,例如“启用”“禁用”“删除”“修改密码”“复制链接”。
- 管理员相关操作统一使用“设为管理员”“取消管理员”,不要写成“设为平台管理员”“设为租户管理员”“取消租户管理员”等冗长文案。
- 删除、移除等危险操作放在下拉末尾。
- 异步操作需要显示 loading 状态,并在 loading 时禁用重复点击。
- 不要在更多下拉里放与当前行无关的批量操作。
多选和批量操作规范
需要批量处理的管理列表必须支持多选。多选统一使用 BlockTable 的 checkbox 能力。
表格配置:
export const TableConfig: TableConfig = {
tableData: [],
colConfigs,
checkbox: true,
pagination: {
currentPage: 1,
pageSize: 10,
total: 0
},
seqType: 'seq',
loading: false
}
页面模板:
<BlockTable
:table-config="tableConfig"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
@checkbox-change="handleSelectionChange"
/>
批量工具栏规则:
- 选中至少一行后,在
zqy-table-top上方覆盖显示批量操作工具栏。 - 批量工具栏使用绝对定位遮罩覆盖原工具栏,背景为白色,避免顶部按钮和搜索框同时出现。
- 批量操作按钮按业务顺序排列,常用顺序为:
启用、禁用、业务批量操作、删除/移除、取消选择。 取消选择放在最后,不使用主题色强调。- 批量操作必须过滤不适用的数据,并给出明确提示,例如“请选择禁用状态的用户”。
- 批量接口执行期间统一使用
batchLoading,禁用取消选择和重复提交。 - 批量成功后刷新列表,并清空
selectedRows。
状态管理示例:
const selectedRows = ref<any[]>([])
const batchLoading = ref(false)
function handleSelectionChange(records: any[]) {
selectedRows.value = records || []
}
function cancelSelection() {
selectedRows.value = []
tableConfig.tableData = [...tableConfig.tableData]
}
批量遮罩样式示例:
.page-batch-mask {
position: absolute;
z-index: 2;
inset: 0;
display: flex;
align-items: center;
justify-content: flex-start;
padding: 0 20px;
box-sizing: border-box;
background-color: #fff;
}
.page-batch-actions {
display: flex;
align-items: center;
gap: 12px;
}
.page-batch-action {
min-width: 66px;
height: 32px;
line-height: 30px;
border-color: getCssVar('color', 'primary');
color: getCssVar('color', 'primary');
background-color: #fff;
&:hover,
&:focus {
border-color: getCssVar('color', 'primary');
color: #fff;
background-color: getCssVar('color', 'primary');
}
}
Vue 文件组织顺序
为了保证 Vue 代码风格统一,<script setup> 内容推荐按以下顺序组织:
<script lang="ts" setup>
// 顶部统一引入模块插件
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
// 第一部分:接口、路由、store 等声明
interface DemoInterface {
}
const route = useRoute()
// 第二部分:参数声明,ref 在上,reactive 在下
const keyword = ref('')
const object = reactive({})
// 第三部分:props 参数
const props = defineProps<{
modelConfig: ModalConfig
}>()
// 第四部分:计算属性和侦听器
const computedParam = computed(() => {
return ''
})
watch(
() => props.modelConfig.visible,
(newVal) => {
visible.value = newVal
}
)
// 第五部分:函数和事件,统一使用 function 声明
function fun() {}
// 第六部分:生命周期
onMounted(() => {
})
onUnmounted(() => {
})
</script>
架构检查
结构变更后至少运行:
pnpm check:architecture
pnpm build
涉及模块边界、路由发现时运行完整检查:
pnpm check:architecture:full
pnpm build
查看跨模块 public surface 报告:
pnpm check:architecture:report
当前架构检查会阻断以下问题:
src/app静态依赖src/modulessrc/modules直接依赖src/app/management- 直接引用 VIP 源码
- 跨模块 deep import 对方
views或私有路径 - 模块缺少必需的
index.ts或routes.ts - 删除
src/modules后基础应用无法构建
常用调试地址
Swagger:
http://101.132.73.185:8080/swagger-ui/index.html
username: admin
password: admin123
H2 数据库:
http://101.132.73.185:8080/h2-console
jdbc: jdbc:h2:/data/zhiqingyun/GH-2092/h2/data;AUTO_SERVER=TRUE
username: root
password: root123
