feat: 完成系统管理模块功能迭代
新增用户、菜单、日志、问题帮助等业务模块,优化角色权限分配功能,新增依赖包与全局组件
This commit is contained in:
333
docs/表格组件使用说明.md
333
docs/表格组件使用说明.md
@@ -18,7 +18,9 @@
|
||||
8. [API 文件写法](#8-api-文件写法)
|
||||
9. [旧代码迁移对照](#9-旧代码迁移对照)
|
||||
10. [接口请求错误处理规范](#10-接口请求错误处理规范)
|
||||
11. [常见问题排查](#11-常见问题排查)
|
||||
11. [依赖安装规范](#11-依赖安装规范)
|
||||
12. [常见问题排查](#12-常见问题排查)
|
||||
13. [特殊弹出框组件规范](#13-特殊弹出框组件规范)
|
||||
|
||||
---
|
||||
|
||||
@@ -860,6 +862,125 @@ useTableButtons({
|
||||
|
||||
推荐使用公共 key `page.common.help`(模板中用 `$t(ckey('help'))`)。不传 `help-url` 则不显示。
|
||||
|
||||
### 场景 8:折叠式搜索区(搜索条件过多时)
|
||||
|
||||
当搜索条件超过一行时,用 `v-show` + `searchExpanded` 控制额外条件的显隐,避免 header 区域过长。
|
||||
|
||||
**数据定义(`data()` 中)**:
|
||||
|
||||
```js
|
||||
data () {
|
||||
return {
|
||||
searchExpanded: false, // 控制展开/收起
|
||||
// ...其他数据
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**模板结构**:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<d2-container>
|
||||
<template #header>
|
||||
<div class="search-bar">
|
||||
<el-form :inline="true" ref="searchFormRef" size="mini" @submit.native.prevent>
|
||||
<!-- 常用条件:始终可见 -->
|
||||
<el-form-item :label="$t(key('ip'))">
|
||||
<el-input v-model="search.ip" :placeholder="$t(key('placeholder_ip'))"
|
||||
clearable style="width:160px" @keyup.enter.native="onSearch" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('status'))">
|
||||
<el-select v-model="search.status" :placeholder="$t(key('placeholder_status'))"
|
||||
clearable style="width:120px">
|
||||
<el-option :value="200" :label="$t(key('success'))" />
|
||||
<el-option :value="4001" :label="$t(key('failure'))" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 搜索 + 重置 + 展开/收起按钮 -->
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="onSearch">
|
||||
{{ $t(key('search')) }}
|
||||
</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="onReset">
|
||||
{{ $t(key('reset')) }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="!searchExpanded"
|
||||
type="text"
|
||||
icon="el-icon-arrow-down"
|
||||
@click="searchExpanded = true"
|
||||
>
|
||||
{{ $t(key('expand')) }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
type="text"
|
||||
icon="el-icon-arrow-up"
|
||||
@click="searchExpanded = false"
|
||||
>
|
||||
{{ $t(key('collapse')) }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 扩展条件:v-show 控制显隐 -->
|
||||
<div v-show="searchExpanded" class="search-bar__extra">
|
||||
<el-form-item :label="$t(key('tray_number'))">
|
||||
<el-input v-model="search.tray" :placeholder="$t(key('placeholder_tray_no'))"
|
||||
clearable style="width:160px" @keyup.enter.native="onSearch" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('process_code'))">
|
||||
<el-input v-model="search.process_code"
|
||||
:placeholder="$t(key('placeholder_process_code'))"
|
||||
clearable style="width:160px" @keyup.enter.native="onSearch" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('create_time'))">
|
||||
<el-date-picker v-model="search.time" type="datetimerange"
|
||||
:placeholder="$t(key('placeholder_create_time'))"
|
||||
range-separator="-" start-placeholder="" end-placeholder=""
|
||||
value-format="yyyy-MM-dd HH:mm:ss" style="width:340px" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<!-- ... -->
|
||||
</d2-container>
|
||||
</template>
|
||||
```
|
||||
|
||||
**样式**:
|
||||
|
||||
```css
|
||||
.search-bar {
|
||||
padding: 10px 0;
|
||||
}
|
||||
.search-bar .el-form-item--mini.el-form-item {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.search-bar__extra {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
```
|
||||
|
||||
**i18n 附加 key**:
|
||||
|
||||
| key | 中文 | English |
|
||||
|-----|------|---------|
|
||||
| `expand` | 展开更多 | Expand |
|
||||
| `collapse` | 收起 | Collapse |
|
||||
|
||||
**设计要点**:
|
||||
|
||||
1. 常用高频筛选条件放在第一行始终可见(如 IP、状态)
|
||||
2. 低频条件用 `v-show="searchExpanded"` 包裹,默认隐藏
|
||||
3. 展开/收起按钮放在操作按钮组同一行,使用 `type="text"` + 箭头图标
|
||||
4. 折叠时重置不展开,重置只清空 `search` 数据,不改变 `searchExpanded` 状态
|
||||
5. 适用于只读类页面(如日志查看),无需选中框和批量操作
|
||||
|
||||
**完整参考**:[接口日志页](file:///d:/code/mes/mes-ui/src/views/system-administration/system-utilities/api-logs/index.vue)
|
||||
|
||||
---
|
||||
|
||||
## 7. 路由配置
|
||||
@@ -1172,7 +1293,37 @@ this.fetchData()
|
||||
|
||||
---
|
||||
|
||||
## 11. 常见问题排查
|
||||
## 11. 依赖安装规范
|
||||
|
||||
### 包管理器
|
||||
|
||||
本项目使用 **pnpm** 作为包管理器,**禁止使用 npm 或 yarn**。
|
||||
|
||||
### 安装新依赖
|
||||
|
||||
当页面需要额外的第三方库时(如 `mavon-editor`、`vue-json-tree-view` 等),使用:
|
||||
|
||||
```bash
|
||||
pnpm add <package-name>
|
||||
```
|
||||
|
||||
### 常见页面依赖速查
|
||||
|
||||
| 依赖包 | 用途 | 安装命令 |
|
||||
|--------|------|---------|
|
||||
| `mavon-editor` | Markdown 编辑器(问题帮助、文档编辑) | `pnpm add mavon-editor` |
|
||||
| `vue-json-tree-view` | JSON 树形展示(日志查看响应) | 已预装 |
|
||||
| `marked` + `highlight.js` | Markdown 渲染(d2-markdown 组件依赖) | 已预装 |
|
||||
|
||||
### 注意事项
|
||||
|
||||
1. 安装前检查 `package.json` 是否已有该依赖(`vue-json-tree-view`、`marked` 等项目已预装)
|
||||
2. 安装后确认版本兼容性,特别是 Vue 2.x 项目不要安装仅支持 Vue 3 的包
|
||||
3. 若因网络问题安装失败,检查 registry 配置(本项目使用 `npmmirror.com` 镜像)
|
||||
|
||||
---
|
||||
|
||||
## 12. 常见问题排查
|
||||
|
||||
### Q1:弹框打开后不显示内容?
|
||||
|
||||
@@ -1197,3 +1348,181 @@ this.fetchData()
|
||||
### Q6:表单验证错误提示显示为原始 i18n key?
|
||||
|
||||
`page-dialog-form` 会通过 `translatedRules` 计算属性自动翻译验证规则的 `message` 字段。确认传入的 `rules.message` 使用了 `this.key()` 传入完整 key。
|
||||
|
||||
---
|
||||
|
||||
## 13. 特殊弹出框组件规范
|
||||
|
||||
### 适用范围
|
||||
|
||||
当页面需要**超出 `page-dialog-form` 能力的弹出框**时(如权限分配树、多步骤向导、ifream 嵌入、复杂联动表单等),**禁止在 `index.vue` 中直接堆砌内联代码**,必须抽离为独立组件。
|
||||
|
||||
### 目录结构标准
|
||||
|
||||
```
|
||||
src/views/{模块}/{功能}/
|
||||
├── index.vue ← 主页面,只负责引入和组装
|
||||
└── components/ ← 所有额外弹框统一放这里
|
||||
├── PermDrawer/ ← 示例:权限分配抽屉
|
||||
│ └── index.vue
|
||||
├── ImportDialog/ ← 示例:批量导入
|
||||
│ └── index.vue
|
||||
└── DetailDrawer/ ← 示例:详情抽屉
|
||||
└── index.vue
|
||||
```
|
||||
|
||||
### 命名规范
|
||||
|
||||
| 规则 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| 组件文件夹 | **英文 PascalCase**,描述功能 | `PermDrawer`(权限抽屉)、`ImportDialog`(导入弹框)、`DetailDrawer`(详情抽屉) |
|
||||
| 组件入口文件 | 统一 `index.vue` | `PermDrawer/index.vue` |
|
||||
| 组件注册名 | 英文 PascalCase 或 kebab-case 前缀 | `RolePermDrawer`、`role-perm-drawer` |
|
||||
| 禁止 | 中文名、拼音、模糊命名 | ❌ `权限分配/`、❌ `quanxian/`、❌ `Popup/` |
|
||||
|
||||
### 主页面用法(`index.vue`)
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<d2-container>
|
||||
<!-- 搜索区 -->
|
||||
<template #header>...</template>
|
||||
|
||||
<!-- 标准 CRUD 表格 -->
|
||||
<page-table ... />
|
||||
|
||||
<!-- 标准新增/编辑弹框 -->
|
||||
<page-dialog-form ... />
|
||||
|
||||
<!-- 特殊弹框:仅引用 + 传 props,简洁清晰 -->
|
||||
<role-perm-drawer
|
||||
:visible.sync="permVisible"
|
||||
:role="permRole"
|
||||
:title="key('assign_permissions')"
|
||||
:confirm-text="key('confirm')"
|
||||
:cancel-text="key('cancel')"
|
||||
@saved="fetchData"
|
||||
/>
|
||||
</d2-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RolePermDrawer from './components/PermDrawer/index.vue'
|
||||
|
||||
export default {
|
||||
components: { ..., RolePermDrawer },
|
||||
data () {
|
||||
return {
|
||||
permVisible: false,
|
||||
permRole: {} // 只存当前操作行,其余逻辑全在子组件
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openPermDialog (row) {
|
||||
this.permRole = row
|
||||
this.permVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 子组件模板(`components/PermDrawer/index.vue`)
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<el-drawer
|
||||
:visible.sync="visibleProxy"
|
||||
:title="$t(title)"
|
||||
:size="width"
|
||||
:close-on-click-modal="false"
|
||||
direction="rtl"
|
||||
@close="onClose"
|
||||
>
|
||||
<div v-loading="loading">
|
||||
<!-- 业务内容,如 el-tree、el-transfer 等 -->
|
||||
</div>
|
||||
|
||||
<div class="my-drawer__footer">
|
||||
<el-button size="mini" @click="onCancel">{{ $t(cancelText) }}</el-button>
|
||||
<el-button type="primary" size="mini" :loading="submitting" @click="onSubmit">
|
||||
{{ $t(confirmText) }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { i18nMixin } from '@/composables/useI18n'
|
||||
|
||||
export default {
|
||||
name: 'RolePermDrawer',
|
||||
mixins: [i18nMixin('page.xxx.xxx.xxx')],
|
||||
props: {
|
||||
visible: Boolean, // 用 .sync 双向绑定
|
||||
title: String, // 弹框标题(i18n key)
|
||||
confirmText: String, // 确定按钮文本(i18n key)
|
||||
cancelText: String, // 取消按钮文本(i18n key)
|
||||
width: { type: String, default: '360px' }
|
||||
// 业务 props 按需添加,如 role、data 等
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
submitting: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visibleProxy: {
|
||||
get () { return this.visible },
|
||||
set (val) { this.$emit('update:visible', val) }
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible (val) {
|
||||
if (val) { this.init() } // 打开时加载数据
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () { /* 加载数据 */ },
|
||||
onSubmit () {
|
||||
this.submitting = true
|
||||
try {
|
||||
// 提交后
|
||||
this.$emit('saved') // 通知父组件刷新
|
||||
this.visibleProxy = false
|
||||
} finally {
|
||||
this.submitting = false
|
||||
}
|
||||
},
|
||||
onCancel () { this.visibleProxy = false },
|
||||
onClose () { /* 清理状态 */ }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 组件通信约定
|
||||
|
||||
| 方向 | 方式 | 说明 |
|
||||
|------|------|------|
|
||||
| 父 → 子 | `props` | 传递 `visible`(sync)、业务数据对象、i18n key |
|
||||
| 子 → 父 | `$emit` | `@saved` 通知父组件刷新表格,`@closed` 通知关闭完成 |
|
||||
| 避免 | `$parent` / `$refs` | 禁止子组件通过 `$refs.parent.xxx` 访问父组件方法 |
|
||||
|
||||
### 判断标准:何时需要独立组件?
|
||||
|
||||
| 场景 | 使用方案 |
|
||||
|------|---------|
|
||||
| 新增/编辑表单(input + select + textarea) | `page-dialog-form` 即可 |
|
||||
| 权限分配树 | **独立组件** → `components/PermDrawer/` |
|
||||
| 批量导入/导出向导 | **独立组件** → `components/ImportDialog/` |
|
||||
| 关联数据选择器(多选表格) | **独立组件** → `components/SelectorDialog/` |
|
||||
| 详情查看(非编辑) | **独立组件** → `components/DetailDrawer/` |
|
||||
| 复杂多步骤流程 | **独立组件** → `components/FlowWizard/` |
|
||||
|
||||
### 实际案例
|
||||
|
||||
参考完整实现:
|
||||
- 权限分配抽屉:[`src/views/system-administration/user-management/role/components/PermDrawer/index.vue`](file:///d:/code/mes/mes-ui/src/views/system-administration/user-management/role/components/PermDrawer/index.vue)
|
||||
- 主页面引用方式:[`src/views/system-administration/user-management/role/index.vue`](file:///d:/code/mes/mes-ui/src/views/system-administration/user-management/role/index.vue#L79-L87)
|
||||
|
||||
Reference in New Issue
Block a user