feat: 完成系统管理模块功能迭代
新增用户、菜单、日志、问题帮助等业务模块,优化角色权限分配功能,新增依赖包与全局组件
This commit is contained in:
1730
docs/功能测试流程文档.md
Normal file
1730
docs/功能测试流程文档.md
Normal file
File diff suppressed because it is too large
Load Diff
333
docs/表格组件使用说明.md
333
docs/表格组件使用说明.md
@@ -18,7 +18,9 @@
|
|||||||
8. [API 文件写法](#8-api-文件写法)
|
8. [API 文件写法](#8-api-文件写法)
|
||||||
9. [旧代码迁移对照](#9-旧代码迁移对照)
|
9. [旧代码迁移对照](#9-旧代码迁移对照)
|
||||||
10. [接口请求错误处理规范](#10-接口请求错误处理规范)
|
10. [接口请求错误处理规范](#10-接口请求错误处理规范)
|
||||||
11. [常见问题排查](#11-常见问题排查)
|
11. [依赖安装规范](#11-依赖安装规范)
|
||||||
|
12. [常见问题排查](#12-常见问题排查)
|
||||||
|
13. [特殊弹出框组件规范](#13-特殊弹出框组件规范)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -860,6 +862,125 @@ useTableButtons({
|
|||||||
|
|
||||||
推荐使用公共 key `page.common.help`(模板中用 `$t(ckey('help'))`)。不传 `help-url` 则不显示。
|
推荐使用公共 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. 路由配置
|
## 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:弹框打开后不显示内容?
|
### Q1:弹框打开后不显示内容?
|
||||||
|
|
||||||
@@ -1197,3 +1348,181 @@ this.fetchData()
|
|||||||
### Q6:表单验证错误提示显示为原始 i18n key?
|
### Q6:表单验证错误提示显示为原始 i18n key?
|
||||||
|
|
||||||
`page-dialog-form` 会通过 `translatedRules` 计算属性自动翻译验证规则的 `message` 字段。确认传入的 `rules.message` 使用了 `this.key()` 传入完整 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)
|
||||||
|
|||||||
@@ -15,6 +15,56 @@
|
|||||||
- 参考文档:[表格组件使用说明.md](file:///d:/code/mes/mes-ui/docs/表格组件使用说明.md)
|
- 参考文档:[表格组件使用说明.md](file:///d:/code/mes/mes-ui/docs/表格组件使用说明.md)
|
||||||
- 参考示例:`src/views/production-master-data/factory-model/factory-area/index.vue`
|
- 参考示例:`src/views/production-master-data/factory-model/factory-area/index.vue`
|
||||||
|
|
||||||
|
#### 1.1 特殊弹出框组件迁移(重要)
|
||||||
|
|
||||||
|
当旧页面中存在**超出 `page-dialog-form` 能力的弹出框**时(权限分配树、批量导入、关联选择器、详情查看、多步骤向导等),必须遵循以下流程:
|
||||||
|
|
||||||
|
##### 第一步:分析旧代码
|
||||||
|
- **仔细阅读旧项目的弹出框代码**,理解其数据结构、交互逻辑、API 调用
|
||||||
|
- 关注旧代码的数据来源路径(如 `row.menu_admin` 直接从列表获取、还是额外调 API)
|
||||||
|
- 记录旧的参数名、method 名,确保迁移时不遗漏
|
||||||
|
|
||||||
|
##### 第二步:提出优化方案
|
||||||
|
迁移时**不能简单照搬旧代码**,必须结合新版能力提出优化:
|
||||||
|
|
||||||
|
| 旧写法 | 优化方向 |
|
||||||
|
|--------|---------|
|
||||||
|
| `el-dialog` 内联在页面中 | 抽离为独立组件 → `components/` |
|
||||||
|
| `sct-base-dialog` + 内联表单 | 独立组件 + `el-drawer`(抽屉式体验更佳) |
|
||||||
|
| 额外调 API 获取数据(如行数据已包含) | 直接从 `row.xxx` 取值,减少请求 |
|
||||||
|
| `setTimeout` 硬编码延迟 | 提出来讨论,结合 `v-if` + `$nextTick` 优化 |
|
||||||
|
| `$parent` / `$refs` 跨组件通信 | 改为 `props` + `$emit` |
|
||||||
|
|
||||||
|
示例:角色权限分配迁移优化方案
|
||||||
|
|
||||||
|
```
|
||||||
|
旧方案 优化方案
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
el-dialog 内联 42 行代码 → 独立 PermDrawer 组件(components/PermDrawer/index.vue)
|
||||||
|
getRoleMenu API 额外请求 → 直接从 row.menu_admin JSON.parse 获取(列表自带)
|
||||||
|
setTimeout 1000ms 关闭 → 保留(树渲染需要等待),但抽取到子组件内部
|
||||||
|
索引页 data 6 个 perm 字段 → 仅 2 个(permVisible + permRole)
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 第三步:按标准实现
|
||||||
|
参考 [表格组件使用说明.md 第 13 节](file:///d:/code/mes/mes-ui/docs/表格组件使用说明.md#13-特殊弹出框组件规范),严格遵循:
|
||||||
|
|
||||||
|
| 规则 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 目录位置 | `src/views/{模块}/{功能}/components/{英文PascalCase}/index.vue` |
|
||||||
|
| 文件夹命名 | 英文 PascalCase,描述功能(如 `PermDrawer`、`ImportDialog`) |
|
||||||
|
| 组件通信 | 父→子 `props`(含 `.sync`),子→父 `$emit('saved')`,禁止 `$parent` / `$refs` |
|
||||||
|
| 主页面数据 | 只存 `visible` Boolean + 业务对象,其余状态在子组件内部 |
|
||||||
|
|
||||||
|
##### 第四步:完整案例
|
||||||
|
|
||||||
|
参考角色权限分配抽屉的完整迁移:
|
||||||
|
- 旧代码:`D:\code\company\SCTMES_MES_V5\vue-app\src\views\system_settings\user_management\role\components\PageMain\index.vue`(`dialogVisibleGive` + `el-tree`)
|
||||||
|
- 新代码:[`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)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
#### 2. i18n 国际化(重要)
|
#### 2. i18n 国际化(重要)
|
||||||
- 使用 `mixins: [i18nMixin('完整i18n前缀')]`,不要在每个页面手动定义 `T` 常量和 `tkey()` 方法
|
- 使用 `mixins: [i18nMixin('完整i18n前缀')]`,不要在每个页面手动定义 `T` 常量和 `tkey()` 方法
|
||||||
- `data()` 中用 `this.key('xxx')` 传完整 i18n key,**不要用 `k()` 提前翻译**(翻译由 page-table / page-dialog-form 内部处理,切换语言自动响应)
|
- `data()` 中用 `this.key('xxx')` 传完整 i18n key,**不要用 `k()` 提前翻译**(翻译由 page-table / page-dialog-form 内部处理,切换语言自动响应)
|
||||||
@@ -64,6 +114,7 @@
|
|||||||
| `page.system_settings.menu_configuration.menu` | `page.system_administration.menu_management.menu_configuration` |
|
| `page.system_settings.menu_configuration.menu` | `page.system_administration.menu_management.menu_configuration` |
|
||||||
| `page.system_settings.system_assistant.operate_log` | `page.system_administration.system_utilities.operation_logs` |
|
| `page.system_settings.system_assistant.operate_log` | `page.system_administration.system_utilities.operation_logs` |
|
||||||
| `page.system_settings.system_assistant.api_log` | `page.system_administration.system_utilities.api_logs` |
|
| `page.system_settings.system_assistant.api_log` | `page.system_administration.system_utilities.api_logs` |
|
||||||
|
| `page.system_settings.system_assistant.problem_help` | `page.system_administration.system_utilities.problem_help` |
|
||||||
| `page.system_settings.system_monitoring.system.login` | `page.system_administration.system_monitoring.login` |
|
| `page.system_settings.system_monitoring.system.login` | `page.system_administration.system_monitoring.login` |
|
||||||
| `page.production_configuration.matetial_model.*` | `page.production_master_data.material_model.*` |
|
| `page.production_configuration.matetial_model.*` | `page.production_master_data.material_model.*` |
|
||||||
| `page.planning_production.production_batch_management.batch` | `page.planning_production.batch_management.batch_list` |
|
| `page.planning_production.production_batch_management.batch` | `page.planning_production.batch_management.batch_list` |
|
||||||
@@ -90,6 +141,16 @@
|
|||||||
- **Columns**:`useTableColumns([...])`
|
- **Columns**:`useTableColumns([...])`
|
||||||
- **Methods**:`fetchData / onSearch / onReset / onPageChange / openAdd / openEdit / onDialogSubmit / handleDelete`
|
- **Methods**:`fetchData / onSearch / onReset / onPageChange / openAdd / openEdit / onDialogSubmit / handleDelete`
|
||||||
- **i18n key 模板**(每个页面至少要有这些):`search / reset / add / edit / delete / operation / add_title / edit_title / code / name / remark / enter_code / enter_name / remark_length / operation_success / confirm / cancel / tip / confirm_delete`
|
- **i18n key 模板**(每个页面至少要有这些):`search / reset / add / edit / delete / operation / add_title / edit_title / code / name / remark / enter_code / enter_name / remark_length / operation_success / confirm / cancel / tip / confirm_delete`
|
||||||
|
- **搜索条件过多时**参考 [表格组件使用说明.md - 场景 8](file:///d:/code/mes/mes-ui/docs/表格组件使用说明.md#场景-8折叠式搜索区搜索条件过多时),使用 `searchExpanded` + `v-show` 实现折叠式搜索区,需额外添加 i18n key:`expand`(展开更多/Expand)、`collapse`(收起/Collapse)
|
||||||
|
|
||||||
|
#### 6.1 依赖安装
|
||||||
|
|
||||||
|
当迁移涉及新的第三方库时:
|
||||||
|
|
||||||
|
1. **包管理器**:本项目使用 **pnpm**,安装命令为 `pnpm add <package-name>`
|
||||||
|
2. **安装前检查**:先在 `package.json` 中确认依赖是否已存在,避免重复安装
|
||||||
|
3. **版本兼容**:确保安装的包支持 Vue 2.x(本项目为 Vue 2.7)
|
||||||
|
4. **参考标准**:[表格组件使用说明.md - 第 11 节](file:///d:/code/mes/mes-ui/docs/表格组件使用说明.md#11-依赖安装规范)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
39947
package-lock.json
generated
39947
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -31,6 +31,7 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lowdb": "^1.0.0",
|
"lowdb": "^1.0.0",
|
||||||
"marked": "^2.1.3",
|
"marked": "^2.1.3",
|
||||||
|
"mavon-editor": "^2.10.4",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"qs": "^6.11.0",
|
"qs": "^6.11.0",
|
||||||
"quill": "^1.3.7",
|
"quill": "^1.3.7",
|
||||||
|
|||||||
42
pnpm-lock.yaml
generated
42
pnpm-lock.yaml
generated
@@ -68,6 +68,9 @@ importers:
|
|||||||
marked:
|
marked:
|
||||||
specifier: ^2.1.3
|
specifier: ^2.1.3
|
||||||
version: 2.1.3
|
version: 2.1.3
|
||||||
|
mavon-editor:
|
||||||
|
specifier: ^2.10.4
|
||||||
|
version: 2.10.4
|
||||||
nprogress:
|
nprogress:
|
||||||
specifier: ^0.2.0
|
specifier: ^0.2.0
|
||||||
version: 0.2.0
|
version: 0.2.0
|
||||||
@@ -2640,6 +2643,9 @@ packages:
|
|||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
cssfilter@0.0.10:
|
||||||
|
resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==}
|
||||||
|
|
||||||
cssnano-preset-default@4.0.8:
|
cssnano-preset-default@4.0.8:
|
||||||
resolution: {integrity: sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==}
|
resolution: {integrity: sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@@ -4492,9 +4498,6 @@ packages:
|
|||||||
json-parse-better-errors@1.0.2:
|
json-parse-better-errors@1.0.2:
|
||||||
resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
|
resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
|
||||||
|
|
||||||
json-parse-even-better-errors@2.3.1:
|
|
||||||
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
|
|
||||||
|
|
||||||
json-schema-traverse@0.4.1:
|
json-schema-traverse@0.4.1:
|
||||||
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
||||||
|
|
||||||
@@ -4590,9 +4593,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==}
|
resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
lines-and-columns@1.2.4:
|
|
||||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
|
||||||
|
|
||||||
load-json-file@4.0.0:
|
load-json-file@4.0.0:
|
||||||
resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==}
|
resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -4726,6 +4726,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
|
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
mavon-editor@2.10.4:
|
||||||
|
resolution: {integrity: sha512-CFsBLkgt/KZBDg+SJYe2fyYv4zClY149PiwpH0rDAiiP4ae1XNs0GC8nBsoTeipsHcebDLN1QMkt3bUsnMDjQw==}
|
||||||
|
|
||||||
md5.js@1.3.5:
|
md5.js@1.3.5:
|
||||||
resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==}
|
resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==}
|
||||||
|
|
||||||
@@ -7115,6 +7118,11 @@ packages:
|
|||||||
xmlchars@2.2.0:
|
xmlchars@2.2.0:
|
||||||
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
|
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
|
||||||
|
|
||||||
|
xss@1.0.15:
|
||||||
|
resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==}
|
||||||
|
engines: {node: '>= 0.10.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
xtend@4.0.2:
|
xtend@4.0.2:
|
||||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||||
engines: {node: '>=0.4'}
|
engines: {node: '>=0.4'}
|
||||||
@@ -10346,6 +10354,8 @@ snapshots:
|
|||||||
|
|
||||||
cssesc@3.0.0: {}
|
cssesc@3.0.0: {}
|
||||||
|
|
||||||
|
cssfilter@0.0.10: {}
|
||||||
|
|
||||||
cssnano-preset-default@4.0.8:
|
cssnano-preset-default@4.0.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
css-declaration-sorter: 4.0.1
|
css-declaration-sorter: 4.0.1
|
||||||
@@ -12725,8 +12735,6 @@ snapshots:
|
|||||||
|
|
||||||
json-parse-better-errors@1.0.2: {}
|
json-parse-better-errors@1.0.2: {}
|
||||||
|
|
||||||
json-parse-even-better-errors@2.3.1: {}
|
|
||||||
|
|
||||||
json-schema-traverse@0.4.1: {}
|
json-schema-traverse@0.4.1: {}
|
||||||
|
|
||||||
json-schema-traverse@1.0.0:
|
json-schema-traverse@1.0.0:
|
||||||
@@ -12820,8 +12828,6 @@ snapshots:
|
|||||||
prelude-ls: 1.1.2
|
prelude-ls: 1.1.2
|
||||||
type-check: 0.3.2
|
type-check: 0.3.2
|
||||||
|
|
||||||
lines-and-columns@1.2.4: {}
|
|
||||||
|
|
||||||
load-json-file@4.0.0:
|
load-json-file@4.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
@@ -12953,6 +12959,10 @@ snapshots:
|
|||||||
|
|
||||||
math-intrinsics@1.1.0: {}
|
math-intrinsics@1.1.0: {}
|
||||||
|
|
||||||
|
mavon-editor@2.10.4:
|
||||||
|
dependencies:
|
||||||
|
xss: 1.0.15
|
||||||
|
|
||||||
md5.js@1.3.5:
|
md5.js@1.3.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
hash-base: 3.0.5
|
hash-base: 3.0.5
|
||||||
@@ -13521,12 +13531,7 @@ snapshots:
|
|||||||
error-ex: 1.3.4
|
error-ex: 1.3.4
|
||||||
json-parse-better-errors: 1.0.2
|
json-parse-better-errors: 1.0.2
|
||||||
|
|
||||||
parse-json@5.2.0:
|
parse-json@5.2.0: {}
|
||||||
dependencies:
|
|
||||||
'@babel/code-frame': 7.29.0
|
|
||||||
error-ex: 1.3.4
|
|
||||||
json-parse-even-better-errors: 2.3.1
|
|
||||||
lines-and-columns: 1.2.4
|
|
||||||
|
|
||||||
parse-passwd@1.0.0: {}
|
parse-passwd@1.0.0: {}
|
||||||
|
|
||||||
@@ -15835,6 +15840,11 @@ snapshots:
|
|||||||
|
|
||||||
xmlchars@2.2.0: {}
|
xmlchars@2.2.0: {}
|
||||||
|
|
||||||
|
xss@1.0.15:
|
||||||
|
dependencies:
|
||||||
|
commander: 2.20.3
|
||||||
|
cssfilter: 0.0.10
|
||||||
|
|
||||||
xtend@4.0.2: {}
|
xtend@4.0.2: {}
|
||||||
|
|
||||||
y18n@4.0.3: {}
|
y18n@4.0.3: {}
|
||||||
|
|||||||
15
src/api/system-administration/api-logs.js
Normal file
15
src/api/system-administration/api-logs.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { request } from '@/api/_service'
|
||||||
|
|
||||||
|
const BASE = 'system_settings/system_assistant/interface_log/'
|
||||||
|
|
||||||
|
export function getInterfaceLogList (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'list',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
method: 'system_settings_system_assistant_interface_log_list',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
67
src/api/system-administration/menu-configuration.js
Normal file
67
src/api/system-administration/menu-configuration.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { request } from '@/api/_service'
|
||||||
|
|
||||||
|
const BASE = 'system_settings/menu_configuration/menu/'
|
||||||
|
|
||||||
|
function apiParams (method, data = {}) {
|
||||||
|
return {
|
||||||
|
method: `system_settings_menu_configuration_menu_${method}`,
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMenuAll (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'all',
|
||||||
|
method: 'get',
|
||||||
|
params: apiParams('all', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMenuList (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'list',
|
||||||
|
method: 'get',
|
||||||
|
params: apiParams('list', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createMenu (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'create',
|
||||||
|
method: 'post',
|
||||||
|
data: apiParams('create', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editMenu (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'edit',
|
||||||
|
method: 'put',
|
||||||
|
data: apiParams('edit', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteMenu (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'delete',
|
||||||
|
method: 'delete',
|
||||||
|
data: apiParams('delete', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateMenuStatus (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'update_status',
|
||||||
|
method: 'put',
|
||||||
|
data: apiParams('update_status', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sortMenu (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'sort',
|
||||||
|
method: 'put',
|
||||||
|
data: apiParams('sort', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
15
src/api/system-administration/operation-logs.js
Normal file
15
src/api/system-administration/operation-logs.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { request } from '@/api/_service'
|
||||||
|
|
||||||
|
const BASE = 'system_settings/system_assistant/operate_log/'
|
||||||
|
|
||||||
|
export function getOperateLogList (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'list',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
method: 'system_settings_system_assistant_operate_log_list',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
149
src/api/system-administration/problem-help.js
Normal file
149
src/api/system-administration/problem-help.js
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
import { request } from '@/api/_service'
|
||||||
|
|
||||||
|
const CATEGORY_BASE = 'system_settings/system_assistant/problem_help/category/'
|
||||||
|
const MARKDOWN_BASE = 'system_settings/system_assistant/problem_help/markdown/'
|
||||||
|
|
||||||
|
export function getCategoryTree (data) {
|
||||||
|
return request({
|
||||||
|
url: CATEGORY_BASE + 'tree',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
method: 'system_settings_system_assistant_problem_category_tree',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setCategoryAdd (data) {
|
||||||
|
return request({
|
||||||
|
url: CATEGORY_BASE + 'add',
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_system_assistant_problem_category_add',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setCategoryUpdate (data) {
|
||||||
|
return request({
|
||||||
|
url: CATEGORY_BASE + 'edit',
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_system_assistant_problem_category_edit',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function delCategory (data) {
|
||||||
|
return request({
|
||||||
|
url: CATEGORY_BASE + 'delete',
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_system_assistant_problem_category_delete',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProblemTree (data) {
|
||||||
|
return request({
|
||||||
|
url: MARKDOWN_BASE + 'tree',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
method: 'system_settings_system_assistant_problem_markdown_tree',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMarkdownDetails (data) {
|
||||||
|
return request({
|
||||||
|
url: MARKDOWN_BASE + 'details',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
method: 'system_settings_system_assistant_problem_markdown_details',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setMarkdownAdd (data) {
|
||||||
|
return request({
|
||||||
|
url: MARKDOWN_BASE + 'add',
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_system_assistant_problem_markdown_add',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setMarkdownEdit (data) {
|
||||||
|
return request({
|
||||||
|
url: MARKDOWN_BASE + 'edit',
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_system_assistant_problem_markdown_edit',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function delMarkdownDetails (data) {
|
||||||
|
return request({
|
||||||
|
url: MARKDOWN_BASE + 'del',
|
||||||
|
method: 'delete',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_system_assistant_problem_markdown_del',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteProblem (data) {
|
||||||
|
return request({
|
||||||
|
url: MARKDOWN_BASE + 'delete',
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
method: 'del.problem.item',
|
||||||
|
platform: 'admin',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function searchMarkdown (data) {
|
||||||
|
return request({
|
||||||
|
url: MARKDOWN_BASE + 'search',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
method: 'system_settings_system_assistant_problem_markdown_search',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRoleAll (data) {
|
||||||
|
return request({
|
||||||
|
url: 'system_settings/user_management/role/list',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
method: 'system_settings_user_management_role_list',
|
||||||
|
platform: 'background',
|
||||||
|
page_size: 9999,
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -10,6 +10,14 @@ function apiParams (method, data = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getRoleAll (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'all',
|
||||||
|
method: 'get',
|
||||||
|
params: apiParams('all', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function getRoleList (data) {
|
export function getRoleList (data) {
|
||||||
return request({
|
return request({
|
||||||
url: BASE + 'list',
|
url: BASE + 'list',
|
||||||
|
|||||||
99
src/api/system-administration/user.js
Normal file
99
src/api/system-administration/user.js
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import { request } from '@/api/_service'
|
||||||
|
|
||||||
|
const BASE = 'system_settings/user_management/user/'
|
||||||
|
|
||||||
|
export function getUserList (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'list',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
method: 'system_settings_user_management_user_list',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createUser (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'create',
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_user_management_user_create',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editUser (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'edit',
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_user_management_user_edit',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteUser (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'delete',
|
||||||
|
method: 'delete',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_user_management_user_delete',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function batchDeleteUser (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'batch_delete',
|
||||||
|
method: 'delete',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_user_management_user_batch_delete',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function enableUser (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'enable',
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_user_management_enable_user',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function disableUser (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'disable',
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_user_management_disable_user',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetUserPwd (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'reset_pwd',
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
method: 'system_settings_user_management_user_reset_pwd',
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -77,6 +77,232 @@
|
|||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"tip": "Tip"
|
"tip": "Tip"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"search": "Search",
|
||||||
|
"reset": "Reset",
|
||||||
|
"index": "No.",
|
||||||
|
"username": "Username",
|
||||||
|
"full_name": "Full Name",
|
||||||
|
"pass_number": "Pass Number",
|
||||||
|
"status": "Status",
|
||||||
|
"enable": "Enabled",
|
||||||
|
"disable": "Disabled",
|
||||||
|
"user_group": "User Group",
|
||||||
|
"login_ip": "Last Login IP",
|
||||||
|
"last_login_time": "Last Login Time",
|
||||||
|
"actions": "Actions",
|
||||||
|
"add": "Add",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"add_title": "Add User",
|
||||||
|
"edit_title": "Edit User",
|
||||||
|
"enter_username": "Please enter username",
|
||||||
|
"enter_name": "Please enter full name",
|
||||||
|
"enter_password": "Please enter password",
|
||||||
|
"enter_confirm_password": "Please confirm password",
|
||||||
|
"enter_pass_number": "Please enter pass number",
|
||||||
|
"password": "Password",
|
||||||
|
"confirm_password": "Confirm Password",
|
||||||
|
"select_user_group": "Please select user group",
|
||||||
|
"select_rows_first": "Please select rows first",
|
||||||
|
"operation_success": "Operation succeeded",
|
||||||
|
"confirm_delete": "Are you sure to delete this user?",
|
||||||
|
"confirm_batch_delete": "Are you sure to batch delete selected users?",
|
||||||
|
"confirm_reset_pwd": "Are you sure to reset this user's password?",
|
||||||
|
"confirm_execute": "Are you sure to execute this operation?",
|
||||||
|
"password_not_match": "Passwords do not match",
|
||||||
|
"password_length": "Length should be 6 to 64 characters",
|
||||||
|
"username_length": "Length should be 3 to 20 characters",
|
||||||
|
"cannot_delete_self": "Cannot delete own account",
|
||||||
|
"cannot_operate_self": "Cannot operate own account",
|
||||||
|
"batch_delete": "Batch Delete",
|
||||||
|
"reset_password": "Reset Password",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"prompt": "Prompt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"menu_management": {
|
||||||
|
"menu_configuration": {
|
||||||
|
"add_top_menu": "Add Top-Level Menu",
|
||||||
|
"expand": "Expand",
|
||||||
|
"collapse": "Collapse",
|
||||||
|
"add": "Add",
|
||||||
|
"enable": "Enable",
|
||||||
|
"disable": "Disable",
|
||||||
|
"delete": "Delete",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"modify": "Edit",
|
||||||
|
"filter": "Filter",
|
||||||
|
"filter_placeholder": "Enter keywords to filter",
|
||||||
|
"parent_menu": "Parent Menu",
|
||||||
|
"parent_menu_placeholder": "Leave blank for top-level menu. Try searching: Home",
|
||||||
|
"menu_name": "Menu Name",
|
||||||
|
"menu_name_placeholder": "Please enter menu name",
|
||||||
|
"menu_alias": "Alias",
|
||||||
|
"menu_alias_placeholder": "Enter menu alias (optional)",
|
||||||
|
"icon": "Icon",
|
||||||
|
"select_menu_icon": "Select Menu Icon",
|
||||||
|
"sort": "No.",
|
||||||
|
"navigation": "Navigation",
|
||||||
|
"link_type": "Link Type",
|
||||||
|
"link_type_module": "Internal Module",
|
||||||
|
"link_type_external": "External URL",
|
||||||
|
"open_type": "Open Method",
|
||||||
|
"open_self": "Same Tab",
|
||||||
|
"open_blank": "New Tab",
|
||||||
|
"url": "URL",
|
||||||
|
"url_placeholder": "Enter link address",
|
||||||
|
"params": "Parameters",
|
||||||
|
"params_placeholder": "Enter URL parameters (optional)",
|
||||||
|
"remark": "Remark",
|
||||||
|
"remark_placeholder": "Enter menu notes (optional)",
|
||||||
|
"add_menu": "Add Menu",
|
||||||
|
"edit_menu": "Edit Menu",
|
||||||
|
"name_required": "Menu name cannot be empty",
|
||||||
|
"name_max_length": "Must be 32 characters or less",
|
||||||
|
"alias_max_length": "Must be 16 characters or less",
|
||||||
|
"must_be_number": "Please enter a valid number",
|
||||||
|
"link_type_required": "Link type cannot be empty",
|
||||||
|
"max_255_length": "Must be 255 characters or less",
|
||||||
|
"operation_success": "Operation successful",
|
||||||
|
"delete_confirm": "Are you sure you want to delete this menu?",
|
||||||
|
"status_change_confirm": "Changing status will affect child/parent menus. Proceed?",
|
||||||
|
"prompt": "Notice",
|
||||||
|
"status": "Status",
|
||||||
|
"admin": "Backend",
|
||||||
|
"pda": "PDA",
|
||||||
|
"navigation_property": "Navigation Property",
|
||||||
|
"navigation_visible": "Visible",
|
||||||
|
"navigation_hidden": "Hidden",
|
||||||
|
"menu_depth": "Menu Level",
|
||||||
|
"query": "Search",
|
||||||
|
"reset": "Reset",
|
||||||
|
"please_select": "Please select"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"system_utilities": {
|
||||||
|
"api_logs": {
|
||||||
|
"id": "ID",
|
||||||
|
"ip": "IP",
|
||||||
|
"interface_name": "Interface Name",
|
||||||
|
"request_method": "Request Method",
|
||||||
|
"response_status": "Response Status",
|
||||||
|
"response_time_ms": "Response Time (ms)",
|
||||||
|
"process_code": "Process Code",
|
||||||
|
"tray_number": "Tray No.",
|
||||||
|
"battery_id": "Battery Barcode",
|
||||||
|
"batch_number": "Batch No.",
|
||||||
|
"process_id": "Process ID",
|
||||||
|
"create_date": "Create Date",
|
||||||
|
"operation": "Operation",
|
||||||
|
"status": "Status",
|
||||||
|
"batch": "Batch",
|
||||||
|
"create_time": "Create Time",
|
||||||
|
"success": "Success",
|
||||||
|
"failure": "Failure",
|
||||||
|
"view_response": "View Response",
|
||||||
|
"response": "Response",
|
||||||
|
"copy_request_content": "Copy Request",
|
||||||
|
"copy_response_content": "Copy Response",
|
||||||
|
"request_body": "Request Body",
|
||||||
|
"response_content": "Response Body",
|
||||||
|
"search": "Search",
|
||||||
|
"reset": "Reset",
|
||||||
|
"operation_success": "Operation succeeded",
|
||||||
|
"placeholder_ip": "Please enter IP",
|
||||||
|
"placeholder_interface_name": "Please enter interface name",
|
||||||
|
"placeholder_status": "Please select status",
|
||||||
|
"placeholder_batch": "Please enter batch",
|
||||||
|
"placeholder_tray_no": "Please enter tray no.",
|
||||||
|
"placeholder_process_code": "Please enter process code",
|
||||||
|
"placeholder_battery_barcode": "Please enter battery barcode",
|
||||||
|
"placeholder_create_time": "Please select time",
|
||||||
|
"expand": "Expand",
|
||||||
|
"collapse": "Collapse"
|
||||||
|
},
|
||||||
|
"operation_logs": {
|
||||||
|
"search": "Search",
|
||||||
|
"reset": "Reset",
|
||||||
|
"expand": "Expand",
|
||||||
|
"collapse": "Collapse",
|
||||||
|
"ip": "IP",
|
||||||
|
"placeholder_ip": "Please enter IP",
|
||||||
|
"operator": "Operator",
|
||||||
|
"placeholder_operator": "Select Operator",
|
||||||
|
"batch": "Batch",
|
||||||
|
"placeholder_batch": "Please enter batch",
|
||||||
|
"tray_no": "Tray No.",
|
||||||
|
"placeholder_tray_no": "Please enter tray no.",
|
||||||
|
"create_time": "Creation Time",
|
||||||
|
"placeholder_time": "Please select time",
|
||||||
|
"success": "Success",
|
||||||
|
"failure": "Failure",
|
||||||
|
"status": "Status",
|
||||||
|
"view_response": "View Response",
|
||||||
|
"operation": "Actions",
|
||||||
|
"response": "Response",
|
||||||
|
"copy_request_content": "Copy Request Content",
|
||||||
|
"copy_response_content": "Copy Response Content",
|
||||||
|
"request_body": "Request Body",
|
||||||
|
"response_content": "Response Content",
|
||||||
|
"action_name": "Action Name",
|
||||||
|
"action_code": "Action Code",
|
||||||
|
"request_path": "Request Path",
|
||||||
|
"create_date": "Creation Date",
|
||||||
|
"id": "ID",
|
||||||
|
"operation_success": "Operation Successful"
|
||||||
|
},
|
||||||
|
"problem_help": {
|
||||||
|
"search_placeholder": "Please enter content",
|
||||||
|
"add_directory": "Add Directory",
|
||||||
|
"add_document": "Add Document",
|
||||||
|
"edit_document": "Edit Document",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"download": "Download",
|
||||||
|
"dialog_edit_title": "Edit Category",
|
||||||
|
"dialog_create_title": "Add Category",
|
||||||
|
"category_name": "Category Name",
|
||||||
|
"placeholder_category_name": "Please enter a category name",
|
||||||
|
"parent_category": "Parent Menu",
|
||||||
|
"top_category": "Root Category",
|
||||||
|
"view_permission": "View Permissions",
|
||||||
|
"please_select": "Please select",
|
||||||
|
"sort": "Sort Order",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"update": "Update",
|
||||||
|
"category_name_required": "Category name cannot be empty",
|
||||||
|
"add_success": "Added successfully",
|
||||||
|
"update_success": "Updated successfully",
|
||||||
|
"title": "Title",
|
||||||
|
"describe": "Description",
|
||||||
|
"type": "Type",
|
||||||
|
"document": "Document",
|
||||||
|
"add": "Add",
|
||||||
|
"enter_title": "Please enter title",
|
||||||
|
"enter_describe": "Please enter description",
|
||||||
|
"edit_success": "Modified successfully",
|
||||||
|
"content_required": "Please enter document content",
|
||||||
|
"file_required": "Please upload a file",
|
||||||
|
"select_parent_menu": "Please select parent menu",
|
||||||
|
"select_role_group": "Please select permission role group",
|
||||||
|
"create_success": "Created successfully",
|
||||||
|
"drag_file_here": "Drag file here, or",
|
||||||
|
"click_upload": "Click to upload",
|
||||||
|
"submitter": "Submitter:",
|
||||||
|
"delete_success": "Deleted successfully!",
|
||||||
|
"operation_success": "Operation successful",
|
||||||
|
"confirm_message": "Are you sure you want to proceed?",
|
||||||
|
"prompt": "Prompt",
|
||||||
|
"confirm_close": "Confirm close?",
|
||||||
|
"select_delete_directory": "Please select a directory to delete first",
|
||||||
|
"select_edit_directory": "Please select a directory to edit first",
|
||||||
|
"upload_failed_retry": "Upload failed, please try again later",
|
||||||
|
"select_document_tip": "Please select a document from the left menu to view"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -77,6 +77,232 @@
|
|||||||
"confirm": "确定",
|
"confirm": "确定",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"tip": "提示"
|
"tip": "提示"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"search": "查询",
|
||||||
|
"reset": "重置",
|
||||||
|
"index": "序号",
|
||||||
|
"username": "账号",
|
||||||
|
"full_name": "姓名",
|
||||||
|
"pass_number": "出入证编号",
|
||||||
|
"status": "状态",
|
||||||
|
"enable": "启用",
|
||||||
|
"disable": "禁用",
|
||||||
|
"user_group": "用户组",
|
||||||
|
"login_ip": "上次登录IP",
|
||||||
|
"last_login_time": "上次登录时间",
|
||||||
|
"actions": "操作",
|
||||||
|
"add": "新 增",
|
||||||
|
"edit": "编 辑",
|
||||||
|
"delete": "删 除",
|
||||||
|
"add_title": "新增用户",
|
||||||
|
"edit_title": "编辑用户",
|
||||||
|
"enter_username": "请输入账号",
|
||||||
|
"enter_name": "请输入姓名",
|
||||||
|
"enter_password": "请输入密码",
|
||||||
|
"enter_confirm_password": "请再次输入密码",
|
||||||
|
"enter_pass_number": "请输入出入证编号",
|
||||||
|
"password": "密码",
|
||||||
|
"confirm_password": "确认密码",
|
||||||
|
"select_user_group": "请选择用户组",
|
||||||
|
"select_rows_first": "请先勾选要操作的数据",
|
||||||
|
"operation_success": "操作成功",
|
||||||
|
"confirm_delete": "确定要删除该用户吗?",
|
||||||
|
"confirm_batch_delete": "确定要批量删除勾选的用户吗?",
|
||||||
|
"confirm_reset_pwd": "确定要重置该用户密码吗?",
|
||||||
|
"confirm_execute": "确定要执行该操作吗?",
|
||||||
|
"password_not_match": "两次输入的密码不一致",
|
||||||
|
"password_length": "长度在 6 到 64 个字符",
|
||||||
|
"username_length": "长度在 3 到 20 个字符",
|
||||||
|
"cannot_delete_self": "不能删除自己的账号",
|
||||||
|
"cannot_operate_self": "不能操作自己的账号",
|
||||||
|
"batch_delete": "批量删除",
|
||||||
|
"reset_password": "重置密码",
|
||||||
|
"confirm": "确定",
|
||||||
|
"cancel": "取消",
|
||||||
|
"prompt": "提示"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"menu_management": {
|
||||||
|
"menu_configuration": {
|
||||||
|
"add_top_menu": "新增顶层菜单",
|
||||||
|
"expand": "展开",
|
||||||
|
"collapse": "收起",
|
||||||
|
"add": "新增",
|
||||||
|
"enable": "启用",
|
||||||
|
"disable": "禁用",
|
||||||
|
"delete": "删除",
|
||||||
|
"confirm": "确定",
|
||||||
|
"cancel": "取消",
|
||||||
|
"modify": "修改",
|
||||||
|
"filter": "过滤",
|
||||||
|
"filter_placeholder": "输入关键词进行过滤",
|
||||||
|
"parent_menu": "上级菜单",
|
||||||
|
"parent_menu_placeholder": "不选择表示顶层菜单 试试搜索:首页",
|
||||||
|
"menu_name": "名称",
|
||||||
|
"menu_name_placeholder": "请输入菜单名称",
|
||||||
|
"menu_alias": "别名",
|
||||||
|
"menu_alias_placeholder": "可输入菜单别名",
|
||||||
|
"icon": "图标",
|
||||||
|
"select_menu_icon": "可选择菜单图标",
|
||||||
|
"sort": "排序",
|
||||||
|
"navigation": "导航",
|
||||||
|
"link_type": "链接类型",
|
||||||
|
"link_type_module": "模块",
|
||||||
|
"link_type_external": "外链",
|
||||||
|
"open_type": "打开方式",
|
||||||
|
"open_self": "当前窗口",
|
||||||
|
"open_blank": "新窗口",
|
||||||
|
"url": "URL",
|
||||||
|
"url_placeholder": "可输入链接地址",
|
||||||
|
"params": "参数",
|
||||||
|
"params_placeholder": "可输入链接参数",
|
||||||
|
"remark": "备注",
|
||||||
|
"remark_placeholder": "可输入菜单备注",
|
||||||
|
"add_menu": "新增菜单",
|
||||||
|
"edit_menu": "编辑菜单",
|
||||||
|
"name_required": "名称不能为空",
|
||||||
|
"name_max_length": "长度不能大于 32 个字符",
|
||||||
|
"alias_max_length": "长度不能大于 16 个字符",
|
||||||
|
"must_be_number": "必须为数字值",
|
||||||
|
"link_type_required": "链接类型不能为空",
|
||||||
|
"max_255_length": "长度不能大于 255 个字符",
|
||||||
|
"operation_success": "操作成功",
|
||||||
|
"delete_confirm": "确定要执行该操作吗?",
|
||||||
|
"status_change_confirm": "状态的切换会影响上下级菜单,是否确认操作?",
|
||||||
|
"prompt": "提示",
|
||||||
|
"status": "状态",
|
||||||
|
"admin": "后台",
|
||||||
|
"pda": "PDA",
|
||||||
|
"navigation_property": "导航属性",
|
||||||
|
"navigation_visible": "可见",
|
||||||
|
"navigation_hidden": "隐藏",
|
||||||
|
"menu_depth": "菜单深度",
|
||||||
|
"query": "查询",
|
||||||
|
"reset": "重置",
|
||||||
|
"please_select": "请选择"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"system_utilities": {
|
||||||
|
"api_logs": {
|
||||||
|
"id": "ID",
|
||||||
|
"ip": "IP",
|
||||||
|
"interface_name": "接口名称",
|
||||||
|
"request_method": "请求方法",
|
||||||
|
"response_status": "响应状态",
|
||||||
|
"response_time_ms": "响应时长(毫秒)",
|
||||||
|
"process_code": "工序编码",
|
||||||
|
"tray_number": "托盘号",
|
||||||
|
"battery_id": "电池条码",
|
||||||
|
"batch_number": "批次号",
|
||||||
|
"process_id": "进程ID",
|
||||||
|
"create_date": "创建日期",
|
||||||
|
"operation": "操作",
|
||||||
|
"status": "状态",
|
||||||
|
"batch": "批次",
|
||||||
|
"create_time": "创建时间",
|
||||||
|
"success": "成功",
|
||||||
|
"failure": "失败",
|
||||||
|
"view_response": "查看响应",
|
||||||
|
"response": "响应",
|
||||||
|
"copy_request_content": "复制请求内容",
|
||||||
|
"copy_response_content": "复制响应内容",
|
||||||
|
"request_body": "请求体",
|
||||||
|
"response_content": "响应内容",
|
||||||
|
"search": "查询",
|
||||||
|
"reset": "重置",
|
||||||
|
"operation_success": "操作成功",
|
||||||
|
"placeholder_ip": "请输入IP",
|
||||||
|
"placeholder_interface_name": "请输入接口名称",
|
||||||
|
"placeholder_status": "请选择状态",
|
||||||
|
"placeholder_batch": "请输入批次",
|
||||||
|
"placeholder_tray_no": "请输入托盘号",
|
||||||
|
"placeholder_process_code": "请输入工序编码",
|
||||||
|
"placeholder_battery_barcode": "请输入电池条码",
|
||||||
|
"placeholder_create_time": "请选择时间",
|
||||||
|
"expand": "展开更多",
|
||||||
|
"collapse": "收起"
|
||||||
|
},
|
||||||
|
"operation_logs": {
|
||||||
|
"search": "查询",
|
||||||
|
"reset": "重置",
|
||||||
|
"expand": "展开更多",
|
||||||
|
"collapse": "收起",
|
||||||
|
"ip": "IP",
|
||||||
|
"placeholder_ip": "请输入IP",
|
||||||
|
"operator": "操作人",
|
||||||
|
"placeholder_operator": "选择操作人",
|
||||||
|
"batch": "批次",
|
||||||
|
"placeholder_batch": "请输入批次",
|
||||||
|
"tray_no": "托盘号",
|
||||||
|
"placeholder_tray_no": "请输入托盘号",
|
||||||
|
"create_time": "创建时间",
|
||||||
|
"placeholder_time": "请选择时间",
|
||||||
|
"success": "成功",
|
||||||
|
"failure": "失败",
|
||||||
|
"status": "状态",
|
||||||
|
"view_response": "查看响应",
|
||||||
|
"operation": "操作",
|
||||||
|
"response": "响应",
|
||||||
|
"copy_request_content": "复制请求内容",
|
||||||
|
"copy_response_content": "复制响应内容",
|
||||||
|
"request_body": "请求体",
|
||||||
|
"response_content": "响应内容",
|
||||||
|
"action_name": "操作动作名称",
|
||||||
|
"action_code": "操作动作编码",
|
||||||
|
"request_path": "请求路径",
|
||||||
|
"create_date": "创建日期",
|
||||||
|
"id": "ID",
|
||||||
|
"operation_success": "操作成功"
|
||||||
|
},
|
||||||
|
"problem_help": {
|
||||||
|
"search_placeholder": "请输入内容",
|
||||||
|
"add_directory": "新增目录",
|
||||||
|
"add_document": "新增文档",
|
||||||
|
"edit_document": "编辑文档",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"download": "下载",
|
||||||
|
"dialog_edit_title": "编辑类型",
|
||||||
|
"dialog_create_title": "新增类型",
|
||||||
|
"category_name": "类型名称",
|
||||||
|
"placeholder_category_name": "请输入类型名称",
|
||||||
|
"parent_category": "上级菜单",
|
||||||
|
"top_category": "顶层目录",
|
||||||
|
"view_permission": "查看权限",
|
||||||
|
"please_select": "请选择",
|
||||||
|
"sort": "序号",
|
||||||
|
"cancel": "取消",
|
||||||
|
"confirm": "确定",
|
||||||
|
"update": "修改",
|
||||||
|
"category_name_required": "分类名称不能为空",
|
||||||
|
"add_success": "添加成功",
|
||||||
|
"update_success": "修改成功",
|
||||||
|
"title": "标题",
|
||||||
|
"describe": "描述",
|
||||||
|
"type": "类型",
|
||||||
|
"document": "文档",
|
||||||
|
"add": "新增",
|
||||||
|
"enter_title": "请输入标题",
|
||||||
|
"enter_describe": "请输入描述",
|
||||||
|
"edit_success": "修改成功",
|
||||||
|
"content_required": "请输入文档编辑内容",
|
||||||
|
"file_required": "请上传文件",
|
||||||
|
"select_parent_menu": "请选择对应上级菜单",
|
||||||
|
"select_role_group": "请选择权限用户组",
|
||||||
|
"create_success": "新增成功",
|
||||||
|
"drag_file_here": "将文件拖到此处,或",
|
||||||
|
"click_upload": "点击上传",
|
||||||
|
"submitter": "提交人:",
|
||||||
|
"delete_success": "删除成功!",
|
||||||
|
"operation_success": "操作成功",
|
||||||
|
"confirm_message": "确定要执行该操作吗?",
|
||||||
|
"prompt": "提示",
|
||||||
|
"confirm_close": "确认关闭?",
|
||||||
|
"select_delete_directory": "请先选择需要删除的目录",
|
||||||
|
"select_edit_directory": "请先选择需要编辑的目录",
|
||||||
|
"upload_failed_retry": "上传失败,请稍后重试",
|
||||||
|
"select_document_tip": "请从左侧菜单选择文档查看"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import 'flex.css'
|
|||||||
import '@/components'
|
import '@/components'
|
||||||
// svg 图标
|
// svg 图标
|
||||||
import '@/assets/svg-icons'
|
import '@/assets/svg-icons'
|
||||||
|
// JSON 树形视图
|
||||||
|
import vueJsonTreeView from 'vue-json-tree-view'
|
||||||
// 国际化
|
// 国际化
|
||||||
import i18n from '@/i18n.js'
|
import i18n from '@/i18n.js'
|
||||||
|
|
||||||
@@ -57,5 +59,7 @@ export default {
|
|||||||
Vue.use(pluginError)
|
Vue.use(pluginError)
|
||||||
Vue.use(pluginLog)
|
Vue.use(pluginLog)
|
||||||
Vue.use(pluginOpen)
|
Vue.use(pluginOpen)
|
||||||
|
// JSON 树形视图组件(tree-view)
|
||||||
|
Vue.use(vueJsonTreeView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,36 @@ export default {
|
|||||||
name: `${pre}user_management-role`,
|
name: `${pre}user_management-role`,
|
||||||
meta: { ...meta, cache: true, title: '角色' },
|
meta: { ...meta, cache: true, title: '角色' },
|
||||||
component: _import('system-administration/user-management/role')
|
component: _import('system-administration/user-management/role')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'user_management/user',
|
||||||
|
name: `${pre}user_management-user`,
|
||||||
|
meta: { ...meta, cache: true, title: '用户' },
|
||||||
|
component: _import('system-administration/user-management/user')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu_configuration/menu',
|
||||||
|
name: `${pre}menu_configuration-menu`,
|
||||||
|
meta: { ...meta, cache: true, title: '菜单配置' },
|
||||||
|
component: _import('system-administration/menu-management/menu-configuration')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'system_assistant/interface_log',
|
||||||
|
name: `${pre}system_assistant-interface_log`,
|
||||||
|
meta: { ...meta, cache: true, title: '接口日志' },
|
||||||
|
component: _import('system-administration/system-utilities/api-logs')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'system_assistant/operate_log',
|
||||||
|
name: `${pre}system_assistant-operate_log`,
|
||||||
|
meta: { ...meta, cache: true, title: '操作日志' },
|
||||||
|
component: _import('system-administration/system-utilities/operation-logs')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'system_assistant/problem_help',
|
||||||
|
name: `${pre}system_assistant-problem_help`,
|
||||||
|
meta: { ...meta, cache: true, title: '问题帮助' },
|
||||||
|
component: _import('system-administration/system-utilities/problem-help')
|
||||||
}
|
}
|
||||||
])('system_settings-')
|
])('system_settings-')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,682 @@
|
|||||||
|
<template>
|
||||||
|
<d2-container>
|
||||||
|
<template #header>
|
||||||
|
<el-form :inline="true" :model="searchForm" ref="searchFormRef" size="mini">
|
||||||
|
<el-form-item :label="$t(key('link_type_module'))" prop="module">
|
||||||
|
<el-radio-group v-model="searchForm.module" @change="handleSearch" size="small">
|
||||||
|
<el-radio-button :label="$t(key('admin'))"></el-radio-button>
|
||||||
|
<el-radio-button :label="$t(key('pda'))"></el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="$t(key('status'))" prop="status">
|
||||||
|
<el-select
|
||||||
|
v-model="searchForm.status"
|
||||||
|
:placeholder="$t(key('please_select'))"
|
||||||
|
style="width: 120px;"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<el-option :label="$t(key('enable'))" :value="1" />
|
||||||
|
<el-option :label="$t(key('disable'))" :value="0" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="$t(key('navigation_property'))" prop="is_navi">
|
||||||
|
<el-select
|
||||||
|
v-model="searchForm.is_navi"
|
||||||
|
:placeholder="$t(key('please_select'))"
|
||||||
|
style="width: 120px;"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<el-option :label="$t(key('navigation_visible'))" :value="1" />
|
||||||
|
<el-option :label="$t(key('navigation_hidden'))" :value="0" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="$t(key('menu_depth'))" prop="level">
|
||||||
|
<el-input-number
|
||||||
|
v-model="searchForm.level"
|
||||||
|
controls-position="right"
|
||||||
|
:min="0"
|
||||||
|
style="width: 100px;"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-search"
|
||||||
|
:disabled="loading"
|
||||||
|
@click="handleSearch"
|
||||||
|
>
|
||||||
|
{{ $t(key('query')) }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button icon="el-icon-refresh" @click="handleReset">
|
||||||
|
{{ $t(key('reset')) }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="menu-config">
|
||||||
|
<el-form :inline="true" size="small" @submit.native.prevent>
|
||||||
|
<el-form-item v-if="auth.create">
|
||||||
|
<el-button
|
||||||
|
icon="el-icon-plus"
|
||||||
|
:disabled="loading"
|
||||||
|
@click="handleCreateTop"
|
||||||
|
>
|
||||||
|
{{ $t(key('add_top_menu')) }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button-group>
|
||||||
|
<el-button icon="el-icon-circle-plus-outline" :disabled="loading" @click="toggleExpand(true)">
|
||||||
|
{{ $t(key('expand')) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button icon="el-icon-remove-outline" :disabled="loading" @click="toggleExpand(false)">
|
||||||
|
{{ $t(key('collapse')) }}
|
||||||
|
</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="$t(key('filter'))">
|
||||||
|
<el-input
|
||||||
|
v-model="filterText"
|
||||||
|
:disabled="loading"
|
||||||
|
:placeholder="$t(key('filter_placeholder'))"
|
||||||
|
prefix-icon="el-icon-search"
|
||||||
|
style="width: 240px;"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="10">
|
||||||
|
<el-tree
|
||||||
|
v-if="hackReset"
|
||||||
|
ref="tree"
|
||||||
|
class="tree-scroll"
|
||||||
|
node-key="menu_id"
|
||||||
|
:data="treeData"
|
||||||
|
:props="treeProps"
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
highlight-current
|
||||||
|
:default-expand-all="isExpandAll"
|
||||||
|
:default-expanded-keys="expanded"
|
||||||
|
draggable
|
||||||
|
:allow-drag="allowDrag"
|
||||||
|
@node-click="handleNodeClick"
|
||||||
|
@node-drop="handleDrop"
|
||||||
|
@node-expand="handleNodeExpand"
|
||||||
|
@node-collapse="handleNodeCollapse"
|
||||||
|
>
|
||||||
|
<span class="custom-tree-node" slot-scope="{ node, data }">
|
||||||
|
<span class="tree-label" :class="{ 'status-disabled': !data.status }">
|
||||||
|
<i v-if="auth.move" class="el-icon-sort move-tree cs-mr-5" />
|
||||||
|
<i v-if="data.icon" :class="'fa fa-' + data.icon" />
|
||||||
|
<i v-else-if="data.children" :class="'el-icon-' + (node.expanded ? 'folder-opened' : 'folder')" />
|
||||||
|
<i v-else class="el-icon-document" />
|
||||||
|
{{ node.label }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="node-actions">
|
||||||
|
<el-button
|
||||||
|
v-if="auth.create"
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
@click.stop="handleAppend(data)"
|
||||||
|
>
|
||||||
|
{{ $t(key('add')) }}
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
v-if="auth.disabled_enable"
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
@click.stop="handleToggleStatus(data)"
|
||||||
|
>
|
||||||
|
{{ data.status ? $t(key('disable')) : $t(key('enable')) }}
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
v-if="auth.delete"
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
@click.stop="handleRemove(data.menu_id)"
|
||||||
|
>
|
||||||
|
{{ $t(key('delete')) }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</el-tree>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :span="14">
|
||||||
|
<el-card v-show="auth.create || auth.edit" class="box-card" shadow="never">
|
||||||
|
<div slot="header">
|
||||||
|
<span>{{ $t(key(formStatus === 'create' ? 'add_menu' : 'edit_menu')) }}</span>
|
||||||
|
<el-button
|
||||||
|
v-if="formStatus === 'create' && auth.create"
|
||||||
|
type="text"
|
||||||
|
:loading="formLoading"
|
||||||
|
style="float: right; padding: 3px 0;"
|
||||||
|
@click="handleCreateSubmit"
|
||||||
|
>
|
||||||
|
{{ $t(key('confirm')) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-else-if="formStatus === 'update' && auth.edit"
|
||||||
|
type="text"
|
||||||
|
:loading="formLoading"
|
||||||
|
style="float: right; padding: 3px 0;"
|
||||||
|
@click="handleUpdateSubmit"
|
||||||
|
>
|
||||||
|
{{ $t(key('modify')) }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
|
||||||
|
<el-form-item :label="$t(key('parent_menu'))" prop="parent_id">
|
||||||
|
<el-cascader
|
||||||
|
v-model="form.parent_id"
|
||||||
|
:placeholder="$t(key('parent_menu_placeholder'))"
|
||||||
|
:key="form.menu_id"
|
||||||
|
:options="treeData"
|
||||||
|
:props="cascaderProps"
|
||||||
|
style="width: 100%;"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item :label="$t(key('menu_name'))" prop="name">
|
||||||
|
<el-input
|
||||||
|
v-model="form.name"
|
||||||
|
:placeholder="$t(key('menu_name_placeholder'))"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item :label="$t(key('menu_alias'))" prop="alias">
|
||||||
|
<el-input
|
||||||
|
v-model="form.alias"
|
||||||
|
:placeholder="$t(key('menu_alias_placeholder'))"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item :label="$t(key('icon'))" prop="icon">
|
||||||
|
<d2-icon-select
|
||||||
|
v-model="form.icon"
|
||||||
|
:user-input="true"
|
||||||
|
:placeholder="$t(key('select_menu_icon'))"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item :label="$t(key('sort'))" prop="sort">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.sort"
|
||||||
|
:min="0"
|
||||||
|
:max="255"
|
||||||
|
style="width: 120px;"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item :label="$t(key('navigation'))" prop="is_navi">
|
||||||
|
<el-switch v-model="form.is_navi" active-value="1" inactive-value="0" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item :label="$t(key('link_type'))" prop="type">
|
||||||
|
<el-radio-group v-model="form.type">
|
||||||
|
<el-radio :label="0">{{ $t(key('link_type_module')) }}</el-radio>
|
||||||
|
<el-radio :label="1">{{ $t(key('link_type_external')) }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item :label="$t(key('open_type'))" prop="target">
|
||||||
|
<el-radio-group v-model="form.target">
|
||||||
|
<el-radio label="_self">{{ $t(key('open_self')) }}</el-radio>
|
||||||
|
<el-radio label="_blank">{{ $t(key('open_blank')) }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-form-item label="URL" prop="url">
|
||||||
|
<el-input
|
||||||
|
v-model="form.url"
|
||||||
|
:placeholder="$t(key('url_placeholder'))"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="$t(key('params'))" prop="params">
|
||||||
|
<el-input
|
||||||
|
v-model="form.params"
|
||||||
|
:placeholder="$t(key('params_placeholder'))"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="$t(key('remark'))" prop="remark">
|
||||||
|
<el-input
|
||||||
|
v-model="form.remark"
|
||||||
|
:placeholder="$t(key('remark_placeholder'))"
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</d2-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import util from '@/libs/util'
|
||||||
|
import { i18nMixin } from '@/composables/useI18n'
|
||||||
|
import { confirmMixin } from '@/composables/useConfirmHandle'
|
||||||
|
import {
|
||||||
|
getMenuList,
|
||||||
|
createMenu,
|
||||||
|
editMenu,
|
||||||
|
deleteMenu,
|
||||||
|
updateMenuStatus,
|
||||||
|
sortMenu
|
||||||
|
} from '@/api/system-administration/menu-configuration'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'system-administration-menu-configuration',
|
||||||
|
mixins: [i18nMixin('page.system_administration.menu_management.menu_configuration'), confirmMixin],
|
||||||
|
data () {
|
||||||
|
const $t = this.$t.bind(this)
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
formLoading: false,
|
||||||
|
treeData: [],
|
||||||
|
module: 'admin',
|
||||||
|
hackReset: true,
|
||||||
|
isExpandAll: false,
|
||||||
|
expanded: [],
|
||||||
|
oldExpanded: [],
|
||||||
|
filterText: '',
|
||||||
|
formStatus: 'create',
|
||||||
|
appendData: {},
|
||||||
|
appendType: '',
|
||||||
|
updateNode: {},
|
||||||
|
auth: {
|
||||||
|
create: true,
|
||||||
|
delete: true,
|
||||||
|
edit: true,
|
||||||
|
disabled_enable: true,
|
||||||
|
move: true
|
||||||
|
},
|
||||||
|
treeProps: {
|
||||||
|
label: 'name',
|
||||||
|
children: 'children'
|
||||||
|
},
|
||||||
|
cascaderProps: {
|
||||||
|
value: 'menu_id',
|
||||||
|
label: 'name',
|
||||||
|
children: 'children',
|
||||||
|
checkStrictly: true,
|
||||||
|
emitPath: false
|
||||||
|
},
|
||||||
|
searchForm: {
|
||||||
|
module: 'admin',
|
||||||
|
status: undefined,
|
||||||
|
is_navi: undefined,
|
||||||
|
level: 0
|
||||||
|
},
|
||||||
|
form: this.getDefaultForm(),
|
||||||
|
rules: {
|
||||||
|
name: [
|
||||||
|
{ required: true, message: $t(this.key('name_required')), trigger: 'blur' },
|
||||||
|
{ max: 32, message: $t(this.key('name_max_length')), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
alias: [
|
||||||
|
{ max: 16, message: $t(this.key('alias_max_length')), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
sort: [
|
||||||
|
{ type: 'number', message: $t(this.key('must_be_number')), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
url: [
|
||||||
|
{ max: 255, message: $t(this.key('max_255_length')), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
params: [
|
||||||
|
{ max: 255, message: $t(this.key('max_255_length')), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
remark: [
|
||||||
|
{ max: 255, message: $t(this.key('max_255_length')), trigger: 'blur' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
filterText (val) {
|
||||||
|
this.$refs.tree && this.$refs.tree.filter(val)
|
||||||
|
this.expanded = this.oldExpanded
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this._validationAuth()
|
||||||
|
this.handleSearch()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getDefaultForm () {
|
||||||
|
return {
|
||||||
|
parent_id: 0,
|
||||||
|
name: '',
|
||||||
|
alias: '',
|
||||||
|
icon: '',
|
||||||
|
remark: '',
|
||||||
|
type: 0,
|
||||||
|
url: '',
|
||||||
|
params: '',
|
||||||
|
target: '_self',
|
||||||
|
is_navi: '0',
|
||||||
|
sort: 50
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_validationAuth () {
|
||||||
|
this.auth.create = this.$permission('/system_settings/menu_configuration/menu/create')
|
||||||
|
this.auth.edit = this.$permission('/system_settings/menu_configuration/menu/edit')
|
||||||
|
this.auth.delete = this.$permission('/system_settings/menu_configuration/menu/delete')
|
||||||
|
this.auth.disabled_enable = this.$permission('/system_settings/menu_configuration/menu/disabled_enable')
|
||||||
|
this.auth.move = this.$permission('/system_settings/menu_configuration/menu/sort')
|
||||||
|
},
|
||||||
|
filterNode (value, data) {
|
||||||
|
if (!value) return true
|
||||||
|
return data.name.indexOf(value) !== -1
|
||||||
|
},
|
||||||
|
toggleExpand (isExpand) {
|
||||||
|
this.filterText = ''
|
||||||
|
this.expanded = []
|
||||||
|
this.hackReset = false
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.isExpandAll = isExpand
|
||||||
|
this.hackReset = true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resetForm () {
|
||||||
|
this.form = this.getDefaultForm()
|
||||||
|
},
|
||||||
|
resetElements (status = 'create') {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.formRef && this.$refs.formRef.clearValidate()
|
||||||
|
})
|
||||||
|
this.formStatus = status
|
||||||
|
this.formLoading = false
|
||||||
|
},
|
||||||
|
handleSearch () {
|
||||||
|
const form = { ...this.searchForm }
|
||||||
|
form.level = form.level <= 0 ? undefined : form.level - 1
|
||||||
|
this.loading = true
|
||||||
|
getMenuList(form)
|
||||||
|
.then(res => {
|
||||||
|
this.module = form.module
|
||||||
|
const menuKey = 'menu_' + form.module
|
||||||
|
const flatList = Array.isArray(res)
|
||||||
|
? res
|
||||||
|
: (res[menuKey] || (res.data && res.data[menuKey]) || [])
|
||||||
|
this.treeData = util.formatDataToTree(flatList)
|
||||||
|
this.filterText = ''
|
||||||
|
this.resetForm()
|
||||||
|
this.resetElements('create')
|
||||||
|
if (this.$refs.tree && this.$refs.tree.getCurrentKey()) {
|
||||||
|
this.$refs.tree.setCurrentKey(null)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleReset () {
|
||||||
|
this.$refs.searchFormRef.resetFields()
|
||||||
|
this.searchForm.module = 'admin'
|
||||||
|
this.searchForm.level = 0
|
||||||
|
this.handleSearch()
|
||||||
|
},
|
||||||
|
handleNodeClick (data) {
|
||||||
|
if (!this.auth.create && !this.auth.edit) return
|
||||||
|
this.updateNode = data
|
||||||
|
this.resetForm()
|
||||||
|
this.resetElements('update')
|
||||||
|
this.form = { ...data, is_navi: String(data.is_navi) }
|
||||||
|
},
|
||||||
|
handleCreateTop () {
|
||||||
|
this.appendType = 'newTopMenu'
|
||||||
|
this.resetForm()
|
||||||
|
this.resetElements('create')
|
||||||
|
if (this.$refs.tree && this.$refs.tree.getCurrentKey()) {
|
||||||
|
this.$refs.tree.setCurrentKey(null)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleAppend (data) {
|
||||||
|
const key = data.menu_id
|
||||||
|
this.handleCreateTop()
|
||||||
|
this.$refs.tree.setCurrentKey(key)
|
||||||
|
this.form.parent_id = key
|
||||||
|
this.appendType = 'newChildMenu'
|
||||||
|
this.appendData = data
|
||||||
|
},
|
||||||
|
appendChildToTree (newNode) {
|
||||||
|
if (!this.appendData.children) {
|
||||||
|
this.$set(this.appendData, 'children', [])
|
||||||
|
}
|
||||||
|
this.appendData.children.push(newNode)
|
||||||
|
},
|
||||||
|
appendTopToTree (newNode) {
|
||||||
|
if (!newNode.children) {
|
||||||
|
this.$set(newNode, 'children', [])
|
||||||
|
}
|
||||||
|
this.treeData.push(newNode)
|
||||||
|
},
|
||||||
|
updateNodeInTree (data) {
|
||||||
|
if (!this.updateNode) return
|
||||||
|
Object.keys(data).forEach(key => {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(this.updateNode, key)) {
|
||||||
|
this.updateNode[key] = data[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.updateNode = {}
|
||||||
|
},
|
||||||
|
handleCreateSubmit () {
|
||||||
|
this.$refs.formRef.validate(valid => {
|
||||||
|
if (!valid) return
|
||||||
|
this.oldExpanded = this.expanded
|
||||||
|
this.formLoading = true
|
||||||
|
createMenu({ ...this.form, module: this.module })
|
||||||
|
.then(res => {
|
||||||
|
let data = res
|
||||||
|
if (data && data.data) data = data.data
|
||||||
|
if (Array.isArray(data) && data.length > 0) data = data[0]
|
||||||
|
|
||||||
|
if (!this.isExpandAll) {
|
||||||
|
this.expanded = [data.parent_id || data.menu_id]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.appendType === 'newChildMenu') {
|
||||||
|
this.appendChildToTree(data)
|
||||||
|
} else if (this.appendType === 'newTopMenu') {
|
||||||
|
this.appendTopToTree(data)
|
||||||
|
}
|
||||||
|
this.appendType = ''
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.formLoading = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleUpdateSubmit () {
|
||||||
|
this.$refs.formRef.validate(valid => {
|
||||||
|
if (!valid) return
|
||||||
|
this.oldExpanded = this.expanded
|
||||||
|
this.formLoading = true
|
||||||
|
editMenu(this.form)
|
||||||
|
.then(() => {
|
||||||
|
this.updateNodeInTree(this.form)
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.formLoading = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async handleRemove (key) {
|
||||||
|
const cancelled = await this.$confirmAction(
|
||||||
|
{
|
||||||
|
message: this.key('delete_confirm'),
|
||||||
|
title: this.key('prompt'),
|
||||||
|
confirmButtonText: this.key('confirm'),
|
||||||
|
cancelButtonText: this.key('cancel')
|
||||||
|
},
|
||||||
|
() => deleteMenu({ menu_id: key })
|
||||||
|
)
|
||||||
|
if (cancelled) return
|
||||||
|
this.$refs.tree.remove(this.$refs.tree.getNode(key))
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
},
|
||||||
|
async handleToggleStatus (data) {
|
||||||
|
const cancelled = await this.$confirmAction(
|
||||||
|
{
|
||||||
|
message: this.key('status_change_confirm'),
|
||||||
|
title: this.key('prompt'),
|
||||||
|
confirmButtonText: this.key('confirm'),
|
||||||
|
cancelButtonText: this.key('cancel')
|
||||||
|
},
|
||||||
|
() => updateMenuStatus({ menu_id: data.menu_id, status: data.status ? 0 : 1 })
|
||||||
|
)
|
||||||
|
if (cancelled) return
|
||||||
|
if (!this.isExpandAll) {
|
||||||
|
const node = this.$refs.tree.getNode(data.menu_id)
|
||||||
|
this.expanded = [node && node.data ? (node.data.parent_id || data.menu_id) : data.menu_id]
|
||||||
|
}
|
||||||
|
this.handleSearch()
|
||||||
|
},
|
||||||
|
handleDrop (draggingNode, dropNode, dropType) {
|
||||||
|
const setMenu = {
|
||||||
|
menu_id: draggingNode.data.menu_id,
|
||||||
|
parent_id: draggingNode.data.parent_id
|
||||||
|
}
|
||||||
|
const indexMenu = []
|
||||||
|
|
||||||
|
if (dropType === 'inner') {
|
||||||
|
setMenu.parent_id = dropNode.key
|
||||||
|
} else {
|
||||||
|
setMenu.parent_id = dropNode.data.parent_id
|
||||||
|
dropNode.parent.childNodes.forEach((value, index) => {
|
||||||
|
indexMenu.push(value.key)
|
||||||
|
value.data.sort = index + 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indexMenu.length > 0) {
|
||||||
|
sortMenu({ menu_sort: indexMenu, ...setMenu })
|
||||||
|
.finally(() => { this.handleSearch() })
|
||||||
|
.catch(() => { this.handleSearch() })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
allowDrag () {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
handleNodeExpand (data) {
|
||||||
|
const exists = this.expanded.some(item => item === data.menu_id)
|
||||||
|
if (!exists) {
|
||||||
|
this.expanded.push(data.menu_id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleNodeCollapse (data) {
|
||||||
|
this.expanded = this.expanded.filter(item => item !== data.menu_id)
|
||||||
|
this._removeChildrenIds(data)
|
||||||
|
},
|
||||||
|
_removeChildrenIds (data) {
|
||||||
|
if (!data.children) return
|
||||||
|
data.children.forEach(item => {
|
||||||
|
const index = this.expanded.indexOf(item.menu_id)
|
||||||
|
if (index >= 0) {
|
||||||
|
this.expanded.splice(index, 1)
|
||||||
|
}
|
||||||
|
this._removeChildrenIds(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.tree-scroll {
|
||||||
|
max-height: 615px;
|
||||||
|
overflow: auto;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tree-node {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-label {
|
||||||
|
i {
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
.fa {
|
||||||
|
font-size: 16px;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-actions {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tree-node:hover .node-actions {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.move-tree {
|
||||||
|
color: #c0c4cc;
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-disabled {
|
||||||
|
color: #c0c4cc;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-card {
|
||||||
|
border-radius: 0;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
:title="$t(`${prefix}.response`)"
|
||||||
|
:visible.sync="visibleProxy"
|
||||||
|
width="700px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@close="onClose"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="4">
|
||||||
|
<el-button type="primary" plain size="mini" @click="copyParam">
|
||||||
|
{{ $t(`${prefix}.copy_request_content`) }}
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="4">
|
||||||
|
<el-button type="primary" plain size="mini" @click="copyResult">
|
||||||
|
{{ $t(`${prefix}.copy_response_content`) }}
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-divider content-position="left">
|
||||||
|
{{ $t(`${prefix}.request_body`) }}
|
||||||
|
</el-divider>
|
||||||
|
<tree-view
|
||||||
|
v-if="paramData"
|
||||||
|
:data="paramData"
|
||||||
|
:options="{ maxDepth: 2 }"
|
||||||
|
style="line-height: 20px; text-align: left;"
|
||||||
|
/>
|
||||||
|
<el-divider content-position="left">
|
||||||
|
{{ $t(`${prefix}.response_content`) }}
|
||||||
|
</el-divider>
|
||||||
|
<tree-view
|
||||||
|
v-if="resultData"
|
||||||
|
:data="resultData"
|
||||||
|
:options="{ maxDepth: 2 }"
|
||||||
|
style="line-height: 20px; text-align: left;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ResponseDialog',
|
||||||
|
props: {
|
||||||
|
visible: { type: Boolean, default: false },
|
||||||
|
paramData: { type: Object, default: null },
|
||||||
|
resultData: { type: Object, default: null },
|
||||||
|
prefix: { type: String, required: true }
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
visibleProxy: {
|
||||||
|
get () { return this.visible },
|
||||||
|
set (val) { this.$emit('update:visible', val) }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onClose () {
|
||||||
|
this.$emit('update:visible', false)
|
||||||
|
},
|
||||||
|
copyToClipboard (data) {
|
||||||
|
const input = document.createElement('input')
|
||||||
|
input.value = JSON.stringify(data)
|
||||||
|
document.body.appendChild(input)
|
||||||
|
input.select()
|
||||||
|
document.execCommand('Copy')
|
||||||
|
input.style.display = 'none'
|
||||||
|
this.$message.success(this.$t(`${this.prefix}.operation_success`))
|
||||||
|
},
|
||||||
|
copyParam () {
|
||||||
|
this.copyToClipboard(this.paramData)
|
||||||
|
},
|
||||||
|
copyResult () {
|
||||||
|
this.copyToClipboard(this.resultData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
<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('interface_name'))">
|
||||||
|
<el-input
|
||||||
|
v-model="search.unit"
|
||||||
|
:placeholder="$t(key('placeholder_interface_name'))"
|
||||||
|
clearable
|
||||||
|
style="width:200px"
|
||||||
|
@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 :label="$t(key('batch'))">
|
||||||
|
<el-input
|
||||||
|
v-model="search.batch"
|
||||||
|
:placeholder="$t(key('placeholder_batch'))"
|
||||||
|
clearable
|
||||||
|
style="width:160px"
|
||||||
|
@keyup.enter.native="onSearch"
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
|
<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('battery_id'))">
|
||||||
|
<el-input
|
||||||
|
v-model="search.battery_id"
|
||||||
|
:placeholder="$t(key('placeholder_battery_barcode'))"
|
||||||
|
clearable
|
||||||
|
style="width:220px"
|
||||||
|
@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>
|
||||||
|
|
||||||
|
<page-table
|
||||||
|
ref="pageTable"
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:loading="loading"
|
||||||
|
:row-buttons="rowButtons"
|
||||||
|
:pagination="pagination"
|
||||||
|
auto-height
|
||||||
|
@page-change="onPageChange"
|
||||||
|
>
|
||||||
|
<template #col-status="{ row }">
|
||||||
|
<span v-if="row.status === 0" style="color: #67c23a;">
|
||||||
|
<i class="el-icon-circle-check" />
|
||||||
|
{{ $t(key('success')) }}
|
||||||
|
</span>
|
||||||
|
<span v-else style="color: #F56C6C;">
|
||||||
|
<i class="el-icon-circle-close" />
|
||||||
|
{{ $t(key('failure')) }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</page-table>
|
||||||
|
|
||||||
|
<response-dialog
|
||||||
|
:visible.sync="respVisible"
|
||||||
|
:param-data="respParam"
|
||||||
|
:result-data="respResult"
|
||||||
|
:prefix="prefix"
|
||||||
|
/>
|
||||||
|
</d2-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useTableColumns } from '@/composables/useTableColumns'
|
||||||
|
import { useTableButtons } from '@/composables/useTableButtons'
|
||||||
|
import { i18nMixin } from '@/composables/useI18n'
|
||||||
|
import { getInterfaceLogList } from '@/api/system-administration/api-logs'
|
||||||
|
import PageTable from '@/components/page-table'
|
||||||
|
import ResponseDialog from './components/ResponseDialog/index.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'system-administration-api-logs',
|
||||||
|
components: { PageTable, ResponseDialog },
|
||||||
|
mixins: [i18nMixin('page.system_administration.system_utilities.api_logs')],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
tableData: [],
|
||||||
|
columns: [],
|
||||||
|
rowButtons: [],
|
||||||
|
pagination: { current: 1, size: 10, total: 0 },
|
||||||
|
search: {
|
||||||
|
ip: '',
|
||||||
|
unit: '',
|
||||||
|
status: undefined,
|
||||||
|
batch: '',
|
||||||
|
tray: '',
|
||||||
|
process_code: '',
|
||||||
|
battery_id: '',
|
||||||
|
time: undefined
|
||||||
|
},
|
||||||
|
respVisible: false,
|
||||||
|
respParam: null,
|
||||||
|
respResult: null,
|
||||||
|
searchExpanded: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
prefix () {
|
||||||
|
return 'page.system_administration.system_utilities.api_logs'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.columns = useTableColumns([
|
||||||
|
{ prop: 'id', label: this.key('id'), width: 65 },
|
||||||
|
{ prop: 'client_ip', label: this.key('ip'), width: 140 },
|
||||||
|
{ prop: 'unit', label: this.key('request_method'), minWidth: 150 },
|
||||||
|
{ prop: 'status', label: this.key('response_status'), slot: 'status', width: 100 },
|
||||||
|
{ prop: 'insterface_time', label: this.key('response_time_ms'), width: 130 },
|
||||||
|
{ prop: 'data1', label: this.key('process_code'), showOverflowTooltip: true, minWidth: 120 },
|
||||||
|
{ prop: 'data2', label: this.key('tray_number'), showOverflowTooltip: true, minWidth: 120 },
|
||||||
|
{ prop: 'data3', label: this.key('battery_id'), showOverflowTooltip: true, minWidth: 130 },
|
||||||
|
{ prop: 'data4', label: this.key('batch_number'), showOverflowTooltip: true, minWidth: 120 },
|
||||||
|
{ prop: 'data5', label: this.key('process_id'), showOverflowTooltip: true, minWidth: 120 },
|
||||||
|
{ prop: 'create_time', label: this.key('create_date'), width: 170 },
|
||||||
|
{ prop: '_actions', label: this.key('operation'), width: 100, fixed: 'right' }
|
||||||
|
], { selectionWidth: 0 })
|
||||||
|
const btns = useTableButtons({
|
||||||
|
row: [
|
||||||
|
{
|
||||||
|
key: 'view',
|
||||||
|
label: this.key('view_response'),
|
||||||
|
icon: 'el-icon-view',
|
||||||
|
auth: '/system_settings/system_assistant/interface_log/view',
|
||||||
|
onClick: this.handleViewResponse
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, this.$permission)
|
||||||
|
this.rowButtons = btns.rowButtons
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchData () {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
...this.search,
|
||||||
|
page_no: this.pagination.current,
|
||||||
|
page_size: this.pagination.size
|
||||||
|
}
|
||||||
|
const res = await getInterfaceLogList(params)
|
||||||
|
const data = Array.isArray(res) ? res : (res.data || [])
|
||||||
|
this.tableData = data
|
||||||
|
this.pagination.total = res.count || data.length
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSearch () {
|
||||||
|
this.pagination.current = 1
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onReset () {
|
||||||
|
this.$refs.searchFormRef.resetFields()
|
||||||
|
this.search.ip = ''
|
||||||
|
this.search.unit = ''
|
||||||
|
this.search.status = undefined
|
||||||
|
this.search.batch = ''
|
||||||
|
this.search.tray = ''
|
||||||
|
this.search.process_code = ''
|
||||||
|
this.search.battery_id = ''
|
||||||
|
this.search.time = undefined
|
||||||
|
this.pagination.current = 1
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onPageChange (page) {
|
||||||
|
this.pagination.current = page.current
|
||||||
|
this.pagination.size = page.size
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
handleViewResponse (row) {
|
||||||
|
try {
|
||||||
|
this.respParam = JSON.parse(row.params || '{}')
|
||||||
|
this.respResult = JSON.parse(row.result || '{}')
|
||||||
|
} catch {
|
||||||
|
this.respParam = row.params || {}
|
||||||
|
this.respResult = row.result || {}
|
||||||
|
}
|
||||||
|
this.respVisible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.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%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
<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('operator'))">
|
||||||
|
<el-select
|
||||||
|
v-model="search.user_id"
|
||||||
|
:placeholder="$t(key('placeholder_operator'))"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
style="width:200px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="u in userList"
|
||||||
|
:key="u.user_id"
|
||||||
|
:value="u.user_id"
|
||||||
|
:label="u.username"
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
|
<div v-show="searchExpanded" class="search-bar__extra">
|
||||||
|
<el-form-item :label="$t(key('batch'))">
|
||||||
|
<el-input
|
||||||
|
v-model="search.batch"
|
||||||
|
:placeholder="$t(key('placeholder_batch'))"
|
||||||
|
clearable
|
||||||
|
style="width:160px"
|
||||||
|
@keyup.enter.native="onSearch"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(key('tray_no'))">
|
||||||
|
<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('create_time'))">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="search.time"
|
||||||
|
type="datetimerange"
|
||||||
|
:placeholder="$t(key('placeholder_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>
|
||||||
|
|
||||||
|
<page-table
|
||||||
|
ref="pageTable"
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:loading="loading"
|
||||||
|
:row-buttons="rowButtons"
|
||||||
|
:pagination="pagination"
|
||||||
|
auto-height
|
||||||
|
@page-change="onPageChange"
|
||||||
|
>
|
||||||
|
<template #col-status="{ row }">
|
||||||
|
<span v-if="row.status === 0" style="color: #67c23a;">
|
||||||
|
<i class="el-icon-circle-check" />
|
||||||
|
{{ $t(key('success')) }}
|
||||||
|
</span>
|
||||||
|
<span v-else style="color: #F56C6C;">
|
||||||
|
<i class="el-icon-circle-close" />
|
||||||
|
{{ $t(key('failure')) }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</page-table>
|
||||||
|
|
||||||
|
<response-dialog
|
||||||
|
:visible.sync="respVisible"
|
||||||
|
:param-data="respParam"
|
||||||
|
:result-data="respResult"
|
||||||
|
:prefix="prefix"
|
||||||
|
/>
|
||||||
|
</d2-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useTableColumns } from '@/composables/useTableColumns'
|
||||||
|
import { useTableButtons } from '@/composables/useTableButtons'
|
||||||
|
import { i18nMixin } from '@/composables/useI18n'
|
||||||
|
import { getOperateLogList } from '@/api/system-administration/operation-logs'
|
||||||
|
import { getUserList } from '@/api/system-administration/user'
|
||||||
|
import PageTable from '@/components/page-table'
|
||||||
|
import ResponseDialog from '../api-logs/components/ResponseDialog/index.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'system-administration-operation-logs',
|
||||||
|
components: { PageTable, ResponseDialog },
|
||||||
|
mixins: [i18nMixin('page.system_administration.system_utilities.operation_logs')],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
tableData: [],
|
||||||
|
columns: [],
|
||||||
|
rowButtons: [],
|
||||||
|
userList: [],
|
||||||
|
pagination: { current: 1, size: 10, total: 0 },
|
||||||
|
search: {
|
||||||
|
ip: '',
|
||||||
|
user_id: undefined,
|
||||||
|
batch: '',
|
||||||
|
tray: '',
|
||||||
|
time: undefined
|
||||||
|
},
|
||||||
|
respVisible: false,
|
||||||
|
respParam: null,
|
||||||
|
respResult: null,
|
||||||
|
searchExpanded: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
prefix () {
|
||||||
|
return 'page.system_administration.system_utilities.operation_logs'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.columns = useTableColumns([
|
||||||
|
{ prop: 'id', label: this.key('id'), width: 65 },
|
||||||
|
{ prop: 'username', label: this.key('operator'), width: 120 },
|
||||||
|
{ prop: 'ip', label: this.key('ip'), width: 140 },
|
||||||
|
{ prop: 'status', label: this.key('status'), slot: 'status', width: 90 },
|
||||||
|
{ prop: 'action_name', label: this.key('action_name'), showOverflowTooltip: true, minWidth: 130 },
|
||||||
|
{ prop: 'action', label: this.key('action_code'), showOverflowTooltip: true, minWidth: 130 },
|
||||||
|
{ prop: 'path', label: this.key('request_path'), showOverflowTooltip: true, minWidth: 180 },
|
||||||
|
{ prop: 'batch', label: this.key('batch'), showOverflowTooltip: true, minWidth: 120 },
|
||||||
|
{ prop: 'tray', label: this.key('tray_no'), showOverflowTooltip: true, minWidth: 120 },
|
||||||
|
{ prop: 'create_time', label: this.key('create_date'), width: 170 },
|
||||||
|
{ prop: '_actions', label: this.key('operation'), width: 100, fixed: 'right' }
|
||||||
|
], { selectionWidth: 0 })
|
||||||
|
const btns = useTableButtons({
|
||||||
|
row: [
|
||||||
|
{
|
||||||
|
key: 'view',
|
||||||
|
label: this.key('view_response'),
|
||||||
|
icon: 'el-icon-view',
|
||||||
|
auth: '/system_settings/system_assistant/operate_log/view',
|
||||||
|
onClick: this.handleViewResponse
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, this.$permission)
|
||||||
|
this.rowButtons = btns.rowButtons
|
||||||
|
this.fetchUsers()
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchUsers () {
|
||||||
|
try {
|
||||||
|
const res = await getUserList({ page_no: 1, page_size: 9999 })
|
||||||
|
this.userList = Array.isArray(res) ? res : (res.data || [])
|
||||||
|
} catch { /* 用户列表加载失败不影响主流程 */ }
|
||||||
|
},
|
||||||
|
async fetchData () {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
...this.search,
|
||||||
|
page_no: this.pagination.current,
|
||||||
|
page_size: this.pagination.size
|
||||||
|
}
|
||||||
|
const res = await getOperateLogList(params)
|
||||||
|
const data = Array.isArray(res) ? res : (res.data || [])
|
||||||
|
this.tableData = data
|
||||||
|
this.pagination.total = res.count || data.length
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSearch () {
|
||||||
|
this.pagination.current = 1
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onReset () {
|
||||||
|
this.$refs.searchFormRef.resetFields()
|
||||||
|
this.search = {
|
||||||
|
ip: '',
|
||||||
|
user_id: undefined,
|
||||||
|
batch: '',
|
||||||
|
tray: '',
|
||||||
|
time: undefined
|
||||||
|
}
|
||||||
|
this.pagination.current = 1
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onPageChange (page) {
|
||||||
|
this.pagination.current = page.current
|
||||||
|
this.pagination.size = page.size
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
handleViewResponse (row) {
|
||||||
|
try {
|
||||||
|
this.respParam = JSON.parse(row.params || '{}')
|
||||||
|
this.respResult = JSON.parse(row.result || '{}')
|
||||||
|
} catch {
|
||||||
|
this.respParam = row.params || {}
|
||||||
|
this.respResult = row.result || {}
|
||||||
|
}
|
||||||
|
this.respVisible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.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%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
:title="textMap[dialogStatus]"
|
||||||
|
:visible.sync="visibleProxy"
|
||||||
|
:append-to-body="true"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
width="600px"
|
||||||
|
@closed="onClosed"
|
||||||
|
>
|
||||||
|
<el-form :model="form" :rules="rules" ref="form" label-width="110px">
|
||||||
|
<el-form-item :label="$t(`${pre}.category_name`)" prop="name">
|
||||||
|
<el-input
|
||||||
|
v-model="form.name"
|
||||||
|
:placeholder="$t(`${pre}.placeholder_category_name`)"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(`${pre}.parent_category`)" prop="parent_id">
|
||||||
|
<el-cascader
|
||||||
|
v-model="form.parent_id"
|
||||||
|
:options="cascaderOptions"
|
||||||
|
:props="{
|
||||||
|
value: 'id',
|
||||||
|
label: 'name',
|
||||||
|
expandTrigger: 'hover',
|
||||||
|
checkStrictly: true
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(`${pre}.view_permission`)" prop="role_ids">
|
||||||
|
<el-select v-model="form.role_ids" multiple :placeholder="$t(`${pre}.please_select`)">
|
||||||
|
<el-option
|
||||||
|
v-for="item in roleList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="String(item.id)"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(`${pre}.sort`)" prop="sort">
|
||||||
|
<el-input-number v-model="form.sort" :min="0" :max="10" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button size="small" @click="close">{{ $t(`${pre}.cancel`) }}</el-button>
|
||||||
|
<el-button type="primary" size="small" :loading="loading" @click="handleSubmit">
|
||||||
|
{{ dialogStatus === 'create' ? $t(`${pre}.confirm`) : $t(`${pre}.update`) }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const TOP_CATEGORY = { id: 0, name: '' }
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CategoryDialog',
|
||||||
|
props: {
|
||||||
|
visible: { type: Boolean, default: false },
|
||||||
|
categoryTree: { type: Array, default: () => [] },
|
||||||
|
roleList: { type: Array, default: () => [] },
|
||||||
|
pre: { type: String, required: true }
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
dialogStatus: 'create',
|
||||||
|
loading: false,
|
||||||
|
editId: null,
|
||||||
|
form: this.getDefaultForm(),
|
||||||
|
rules: {
|
||||||
|
name: [{ required: true, message: this.$t(`${this.pre}.category_name_required`), trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
visibleProxy: {
|
||||||
|
get () { return this.visible },
|
||||||
|
set (val) { this.$emit('update:visible', val) }
|
||||||
|
},
|
||||||
|
textMap () {
|
||||||
|
return {
|
||||||
|
create: this.$t(`${this.pre}.dialog_create_title`),
|
||||||
|
update: this.$t(`${this.pre}.dialog_edit_title`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cascaderOptions () {
|
||||||
|
const top = { ...TOP_CATEGORY, name: this.$t(`${this.pre}.top_category`) }
|
||||||
|
return [top].concat(this.categoryTree)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getDefaultForm () {
|
||||||
|
return { name: undefined, parent_id: undefined, sort: 0, role_ids: [] }
|
||||||
|
},
|
||||||
|
openCreate () {
|
||||||
|
this.dialogStatus = 'create'
|
||||||
|
this.form = this.getDefaultForm()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.form) this.$refs.form.clearValidate()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openEdit (row) {
|
||||||
|
this.dialogStatus = 'update'
|
||||||
|
this.editId = row.id
|
||||||
|
this.form = {
|
||||||
|
name: row.name,
|
||||||
|
parent_id: row.parent_id != null ? [row.parent_id] : [],
|
||||||
|
role_ids: row.role_ids || [],
|
||||||
|
sort: row.sort || 0
|
||||||
|
}
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.form) this.$refs.form.clearValidate()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleSubmit () {
|
||||||
|
this.$refs.form.validate(valid => {
|
||||||
|
if (!valid) return
|
||||||
|
this.loading = true
|
||||||
|
this.$emit('submit', {
|
||||||
|
status: this.dialogStatus,
|
||||||
|
id: this.editId,
|
||||||
|
form: { ...this.form }
|
||||||
|
})
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onClosed () {
|
||||||
|
this.form = this.getDefaultForm()
|
||||||
|
},
|
||||||
|
close () {
|
||||||
|
this.$emit('update:visible', false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
:title="drawerTitle"
|
||||||
|
:visible.sync="visibleProxy"
|
||||||
|
direction="rtl"
|
||||||
|
size="80%"
|
||||||
|
:before-close="handleBeforeClose"
|
||||||
|
>
|
||||||
|
<div v-loading="loading" class="editor-body">
|
||||||
|
<el-form
|
||||||
|
ref="form"
|
||||||
|
label-position="right"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="80px"
|
||||||
|
>
|
||||||
|
<el-form-item :label="$t(`${pre}.title`)" prop="title">
|
||||||
|
<el-input v-model="form.title" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(`${pre}.describe`)" prop="describe">
|
||||||
|
<el-input type="textarea" :maxlength="30" show-word-limit v-model="form.describe" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(`${pre}.parent_category`)" prop="category_id">
|
||||||
|
<el-cascader
|
||||||
|
v-model="form.category_id"
|
||||||
|
:options="categoryTreeData"
|
||||||
|
:props="{
|
||||||
|
value: 'id',
|
||||||
|
label: 'name',
|
||||||
|
expandTrigger: 'hover',
|
||||||
|
checkStrictly: true
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(`${pre}.view_permission`)" prop="role_ids">
|
||||||
|
<el-select v-model="form.role_ids" multiple :placeholder="$t(`${pre}.please_select`)">
|
||||||
|
<el-option
|
||||||
|
v-for="item in roleList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="String(item.id)"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(`${pre}.sort`)" prop="sort">
|
||||||
|
<el-input-number v-model="form.sort" :min="0" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(`${pre}.type`)">
|
||||||
|
<el-radio-group v-model="form.type">
|
||||||
|
<el-radio label="md">{{ $t(`${pre}.document`) }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-show="form.type === 'md'" style="width:100%">
|
||||||
|
<mavon-editor
|
||||||
|
ref="mavon"
|
||||||
|
style="height:500px"
|
||||||
|
v-model="form.markdown"
|
||||||
|
@imgAdd="handleUploadImages"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" :disabled="submitting" @click="handleAdd">
|
||||||
|
{{ $t(`${pre}.add`) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="closeDrawer">{{ $t(`${pre}.cancel`) }}</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mavonEditor } from 'mavon-editor'
|
||||||
|
import 'mavon-editor/dist/css/index.css'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MarkdownEditor',
|
||||||
|
components: { mavonEditor },
|
||||||
|
props: {
|
||||||
|
visible: { type: Boolean, default: false },
|
||||||
|
editData: { type: Object, default: null },
|
||||||
|
categoryTreeData: { type: Array, default: () => [] },
|
||||||
|
roleList: { type: Array, default: () => [] },
|
||||||
|
pre: { type: String, required: true }
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
submitting: false,
|
||||||
|
isEdit: false,
|
||||||
|
editId: null,
|
||||||
|
form: this.getDefaultForm(),
|
||||||
|
rules: {
|
||||||
|
title: [{ required: true, message: this.$t(`${this.pre}.enter_title`), trigger: 'blur' }],
|
||||||
|
describe: [{ required: true, message: this.$t(`${this.pre}.enter_describe`), trigger: 'blur' }],
|
||||||
|
category_id: [{ required: true, message: this.$t(`${this.pre}.select_parent_menu`), trigger: 'blur' }],
|
||||||
|
role_ids: [{ required: true, message: this.$t(`${this.pre}.select_role_group`), trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
visibleProxy: {
|
||||||
|
get () { return this.visible },
|
||||||
|
set (val) { this.$emit('update:visible', val) }
|
||||||
|
},
|
||||||
|
drawerTitle () {
|
||||||
|
return this.isEdit ? this.$t(`${this.pre}.edit_document`) : this.$t(`${this.pre}.add_document`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
visible (val) {
|
||||||
|
if (val && this.editData) {
|
||||||
|
this.isEdit = true
|
||||||
|
this.editId = this.editData.id
|
||||||
|
this.form = {
|
||||||
|
title: this.editData.title,
|
||||||
|
category_id: this.editData.category_id,
|
||||||
|
describe: this.editData.describe,
|
||||||
|
markdown: this.editData.markdown || '',
|
||||||
|
type: this.editData.type || 'md',
|
||||||
|
role_ids: this.editData.role_ids ? this.editData.role_ids.map(String) : [],
|
||||||
|
url: this.editData.url || '',
|
||||||
|
sort: this.editData.sort || 0
|
||||||
|
}
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.form) this.$refs.form.clearValidate()
|
||||||
|
})
|
||||||
|
} else if (val && !this.editData) {
|
||||||
|
this.isEdit = false
|
||||||
|
this.editId = null
|
||||||
|
this.resetForm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getDefaultForm () {
|
||||||
|
return {
|
||||||
|
title: undefined,
|
||||||
|
category_id: undefined,
|
||||||
|
describe: undefined,
|
||||||
|
markdown: '',
|
||||||
|
type: 'md',
|
||||||
|
role_ids: [],
|
||||||
|
url: '',
|
||||||
|
sort: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetForm () {
|
||||||
|
this.form = this.getDefaultForm()
|
||||||
|
this.submitting = false
|
||||||
|
this.isEdit = false
|
||||||
|
this.editId = null
|
||||||
|
},
|
||||||
|
handleAdd () {
|
||||||
|
this.$refs.form.validate(valid => {
|
||||||
|
if (!valid) return
|
||||||
|
if (this.form.type === 'md' && !this.form.markdown) {
|
||||||
|
this.$message.warning(this.$t(`${this.pre}.content_required`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.submitting = true
|
||||||
|
this.$emit('submit', this.isEdit
|
||||||
|
? { id: this.editId, ...this.form }
|
||||||
|
: { ...this.form }
|
||||||
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleBeforeClose (done) {
|
||||||
|
this.$confirm(this.$t(`${this.pre}.confirm_close`))
|
||||||
|
.then(() => {
|
||||||
|
this.resetForm()
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
},
|
||||||
|
closeDrawer () {
|
||||||
|
this.resetForm()
|
||||||
|
this.$emit('update:visible', false)
|
||||||
|
},
|
||||||
|
handleUploadImages (pos, file) {
|
||||||
|
const formdata = new FormData()
|
||||||
|
formdata.append('file', file)
|
||||||
|
formdata.append('type', 'image')
|
||||||
|
axios({
|
||||||
|
url: process.env.VUE_APP_UPLOAD_PATH,
|
||||||
|
method: 'post',
|
||||||
|
data: formdata,
|
||||||
|
headers: { 'Content-Type': 'multipart/form-data' }
|
||||||
|
}).then(url => {
|
||||||
|
this.$refs.mavon.$img2Url(pos, process.env.VUE_APP_PRO_PUBLIC_URL + url.data.url)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.editor-body {
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<template>
|
||||||
|
<div class="custom-menu-tree">
|
||||||
|
<template v-for="item in dataList">
|
||||||
|
<el-menu-item v-if="!item.children" :key="item.id" :index="String(item.id)">
|
||||||
|
<span class="tree-icon">
|
||||||
|
<i v-if="item.type === 'md'" class="el-icon-folder-opened" style="color: rgba(144, 198, 252, 1)" />
|
||||||
|
<i v-else class="el-icon-files" style="color: rgba(144, 198, 252, 1)" />
|
||||||
|
</span>
|
||||||
|
<span class="tree-name" :title="item.name">{{ item.name }}</span>
|
||||||
|
<slot name="menu" :menu-id="item.id" :type="item.type" :file-list="{ url: item.url, name: item.url, file_type: item.file_type }" />
|
||||||
|
</el-menu-item>
|
||||||
|
<el-submenu v-else :key="item.id" :index="String(item.id)">
|
||||||
|
<template slot="title">
|
||||||
|
<i :class="[item.icon]" />
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
<slot name="submenu" :menu-data="item" :menu-id="item.id" />
|
||||||
|
</template>
|
||||||
|
<MenuTree :data-list="item.children">
|
||||||
|
<template slot="menu" scope="ctx">
|
||||||
|
<slot name="menu" :menu-id="ctx.menuId" :type="ctx.type" :file-list="ctx.fileList" />
|
||||||
|
</template>
|
||||||
|
<template slot="submenu" scope="ctx">
|
||||||
|
<slot name="submenu" :menu-data="ctx.menuData" :menu-id="ctx.menuId" />
|
||||||
|
</template>
|
||||||
|
</MenuTree>
|
||||||
|
</el-submenu>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'MenuTree',
|
||||||
|
props: {
|
||||||
|
dataList: { type: Array, default: () => [] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
::v-deep .is-opened > .el-submenu__title {
|
||||||
|
border-left: 3px solid #409EFF;
|
||||||
|
}
|
||||||
|
.tree-name {
|
||||||
|
display: inline-block;
|
||||||
|
width: 58%;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.tree-icon {
|
||||||
|
background: rgba(232, 239, 248, 1);
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
padding: 0 0 2px 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,370 @@
|
|||||||
|
<template>
|
||||||
|
<d2-container>
|
||||||
|
<template #header>
|
||||||
|
<div class="problem-header">
|
||||||
|
<el-input
|
||||||
|
:placeholder="$t(key('search_placeholder'))"
|
||||||
|
v-model="searchTitle"
|
||||||
|
size="mini"
|
||||||
|
clearable
|
||||||
|
style="width:220px"
|
||||||
|
@clear="onClearSearch"
|
||||||
|
@keyup.enter.native="onSearch"
|
||||||
|
>
|
||||||
|
<el-button slot="append" icon="el-icon-search" @click="onSearch" />
|
||||||
|
</el-input>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-plus"
|
||||||
|
style="margin-left:10px"
|
||||||
|
@click="openCategoryCreate"
|
||||||
|
>
|
||||||
|
{{ $t(key('add_directory')) }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-container class="problem-content">
|
||||||
|
<el-aside width="300px" class="problem-aside">
|
||||||
|
<div v-if="searchShow" class="search-result">
|
||||||
|
<el-card
|
||||||
|
v-for="item in searchData"
|
||||||
|
:key="item.id"
|
||||||
|
:body-style="{ padding: '10px' }"
|
||||||
|
shadow="never"
|
||||||
|
>
|
||||||
|
<div class="search-item-title" @click="handleSelect(item.id)">
|
||||||
|
<span class="tree-icon">
|
||||||
|
<i
|
||||||
|
v-if="item.type === 'md'"
|
||||||
|
class="el-icon-folder-opened"
|
||||||
|
style="color: rgba(144, 198, 252, 1)"
|
||||||
|
/>
|
||||||
|
<i v-else class="el-icon-files" style="color: rgba(144, 198, 252, 1)" />
|
||||||
|
</span>
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
|
<div class="search-item-desc">{{ item.describe }}</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="aside-toolbar">
|
||||||
|
<el-button type="primary" size="mini" icon="el-icon-plus" @click="openEditor">
|
||||||
|
{{ $t(key('add_document')) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button type="success" size="mini" icon="el-icon-edit-outline" @click="openCategoryEdit" v-permission="'/setting/aide/problem/set'">
|
||||||
|
{{ $t(key('edit')) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button type="danger" size="mini" icon="el-icon-delete" @click="handleDeleteCategory" v-permission="'/setting/aide/problem/del'">
|
||||||
|
{{ $t(key('delete')) }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-menu
|
||||||
|
class="problem-menu"
|
||||||
|
:unique-opened="true"
|
||||||
|
@select="handleSelect"
|
||||||
|
@open="handleOpen"
|
||||||
|
>
|
||||||
|
<MenuTree :data-list="problemTree">
|
||||||
|
<template slot="menu" scope="ctx">
|
||||||
|
<div class="menu-actions">
|
||||||
|
<el-button
|
||||||
|
v-if="ctx.type === 'file'"
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
@click.stop="handleDownload(ctx.fileList.url, ctx.fileList.file_type)"
|
||||||
|
>
|
||||||
|
{{ $t(key('download')) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button v-if="ctx.type === 'md'" type="text" size="mini" @click.stop="handleEditMarkdown(ctx.menuId)">
|
||||||
|
{{ $t(key('edit')) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button type="text" size="mini" style="margin-left:0" @click.stop="handleDeleteMarkdown(ctx.menuId)">
|
||||||
|
{{ $t(key('delete')) }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MenuTree>
|
||||||
|
</el-menu>
|
||||||
|
</el-aside>
|
||||||
|
|
||||||
|
<el-main class="problem-main">
|
||||||
|
<el-card v-if="docVisible" class="doc-card" shadow="never">
|
||||||
|
<div slot="header" class="doc-header">
|
||||||
|
<h1 style="margin:0">{{ docDetail.title }}</h1>
|
||||||
|
<h6 style="margin:0">
|
||||||
|
{{ docDetail.create_time }}
|
||||||
|
{{ $t(key('submitter')) }}{{ docDetail.admin && docDetail.admin.name }}
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
<d2-markdown :key="markdownKey" :source="docDetail.markdown" />
|
||||||
|
</el-card>
|
||||||
|
<div v-else class="doc-empty">
|
||||||
|
<i class="el-icon-document" style="font-size:64px;color:#dcdfe6" />
|
||||||
|
<p style="color:#909399">{{ $t(key('select_document_tip')) }}</p>
|
||||||
|
</div>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
|
||||||
|
<category-dialog
|
||||||
|
ref="categoryDialog"
|
||||||
|
:visible.sync="categoryVisible"
|
||||||
|
:category-tree="categoryTree"
|
||||||
|
:role-list="roleList"
|
||||||
|
:pre="i18nPrefix"
|
||||||
|
@submit="onCategorySubmit"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<markdown-editor
|
||||||
|
ref="editorDrawer"
|
||||||
|
:visible.sync="editorVisible"
|
||||||
|
:edit-data="editDocData"
|
||||||
|
:category-tree-data="categoryTree"
|
||||||
|
:role-list="roleList"
|
||||||
|
:pre="i18nPrefix"
|
||||||
|
@submit="onEditorSubmit"
|
||||||
|
/>
|
||||||
|
</d2-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { i18nMixin } from '@/composables/useI18n'
|
||||||
|
import {
|
||||||
|
getCategoryTree,
|
||||||
|
setCategoryAdd,
|
||||||
|
setCategoryUpdate,
|
||||||
|
delCategory,
|
||||||
|
getProblemTree,
|
||||||
|
getMarkdownDetails,
|
||||||
|
setMarkdownAdd,
|
||||||
|
setMarkdownEdit,
|
||||||
|
delMarkdownDetails,
|
||||||
|
searchMarkdown,
|
||||||
|
getRoleAll
|
||||||
|
} from '@/api/system-administration/problem-help'
|
||||||
|
import MenuTree from './components/MenuTree/index.vue'
|
||||||
|
import CategoryDialog from './components/CategoryDialog/index.vue'
|
||||||
|
import MarkdownEditor from './components/MarkdownEditor/index.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'system-administration-problem-help',
|
||||||
|
components: { MenuTree, CategoryDialog, MarkdownEditor },
|
||||||
|
mixins: [i18nMixin('page.system_administration.system_utilities.problem_help')],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
searchTitle: '',
|
||||||
|
searchData: [],
|
||||||
|
searchShow: false,
|
||||||
|
categoryTree: [],
|
||||||
|
problemTree: [],
|
||||||
|
roleList: [],
|
||||||
|
selectedMenuId: null,
|
||||||
|
docVisible: false,
|
||||||
|
docDetail: { title: '', create_time: '', admin: {}, markdown: '' },
|
||||||
|
markdownKey: false,
|
||||||
|
categoryVisible: false,
|
||||||
|
editorVisible: false,
|
||||||
|
editDocData: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
i18nPrefix () {
|
||||||
|
return 'page.system_administration.system_utilities.problem_help'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.fetchTree()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchTree () {
|
||||||
|
try {
|
||||||
|
const [catRes, probRes, roleRes] = await Promise.all([
|
||||||
|
getCategoryTree(),
|
||||||
|
getProblemTree(),
|
||||||
|
getRoleAll()
|
||||||
|
])
|
||||||
|
this.categoryTree = catRes.data || []
|
||||||
|
this.problemTree = probRes.data || []
|
||||||
|
this.roleList = Array.isArray(roleRes) ? roleRes : (roleRes.data || [])
|
||||||
|
} catch { /* ignore */ }
|
||||||
|
},
|
||||||
|
onSearch () {
|
||||||
|
if (!this.searchTitle) { this.onClearSearch(); return }
|
||||||
|
searchMarkdown({ title: this.searchTitle }).then(res => {
|
||||||
|
this.searchData = res.data || []
|
||||||
|
this.searchShow = this.searchData.length > 0
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onClearSearch () {
|
||||||
|
this.searchShow = false
|
||||||
|
this.searchData = []
|
||||||
|
},
|
||||||
|
handleOpen (key) {
|
||||||
|
this.selectedMenuId = key
|
||||||
|
},
|
||||||
|
handleSelect (id) {
|
||||||
|
getMarkdownDetails({ id }).then(res => {
|
||||||
|
if (res.data && res.data.type !== 'file') {
|
||||||
|
this.docDetail = res.data
|
||||||
|
this.markdownKey = !this.markdownKey
|
||||||
|
this.docVisible = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleDeleteCategory () {
|
||||||
|
if (!this.selectedMenuId) {
|
||||||
|
this.$message.error(this.$t(this.key('select_delete_directory')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$confirm(this.$t(this.key('confirm_message')), this.$t(this.key('prompt')), { type: 'warning' })
|
||||||
|
.then(() => delCategory({ id: this.selectedMenuId }))
|
||||||
|
.then(() => {
|
||||||
|
this.$message.success(this.$t(this.key('delete_success')))
|
||||||
|
this.fetchTree()
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
},
|
||||||
|
handleEditMarkdown (menuId) {
|
||||||
|
getMarkdownDetails({ id: menuId }).then(res => {
|
||||||
|
if (res.data && res.data.type !== 'file') {
|
||||||
|
this.editDocData = res.data
|
||||||
|
this.editorVisible = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleDeleteMarkdown (menuId) {
|
||||||
|
this.$confirm(this.$t(this.key('confirm_message')), this.$t(this.key('prompt')), { type: 'warning' })
|
||||||
|
.then(() => delMarkdownDetails({ id: menuId }))
|
||||||
|
.then(() => {
|
||||||
|
this.$message.success(this.$t(this.key('delete_success')))
|
||||||
|
this.fetchTree()
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
},
|
||||||
|
handleDownload (url, fileType) {
|
||||||
|
window.open(url, '_blank')
|
||||||
|
},
|
||||||
|
openCategoryCreate () {
|
||||||
|
this.$refs.categoryDialog && this.$refs.categoryDialog.openCreate()
|
||||||
|
this.categoryVisible = true
|
||||||
|
},
|
||||||
|
openCategoryEdit () {
|
||||||
|
if (!this.selectedMenuId) {
|
||||||
|
this.$message.warning(this.$t(this.key('select_edit_directory')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const findNode = (nodes) => {
|
||||||
|
for (const n of nodes) {
|
||||||
|
if (n.id === this.selectedMenuId) return n
|
||||||
|
if (n.children) {
|
||||||
|
const found = findNode(n.children)
|
||||||
|
if (found) return found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const node = findNode(this.categoryTree)
|
||||||
|
if (node) {
|
||||||
|
this.$refs.categoryDialog && this.$refs.categoryDialog.openEdit(node)
|
||||||
|
this.categoryVisible = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCategorySubmit ({ status, id, form }) {
|
||||||
|
const api = status === 'create' ? setCategoryAdd : setCategoryUpdate
|
||||||
|
const data = status === 'create' ? form : { id, ...form }
|
||||||
|
api(data).then(() => {
|
||||||
|
this.$message.success(status === 'create'
|
||||||
|
? this.$t(this.key('add_success'))
|
||||||
|
: this.$t(this.key('update_success')))
|
||||||
|
this.categoryVisible = false
|
||||||
|
this.fetchTree()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openEditor () {
|
||||||
|
this.editDocData = null
|
||||||
|
this.editorVisible = true
|
||||||
|
},
|
||||||
|
onEditorSubmit (form) {
|
||||||
|
const promise = form.id
|
||||||
|
? setMarkdownEdit({ id: form.id, ...form })
|
||||||
|
: setMarkdownAdd(form)
|
||||||
|
promise.then(() => {
|
||||||
|
this.$message.success(this.$t(this.key(form.id ? 'edit_success' : 'create_success')))
|
||||||
|
this.editorVisible = false
|
||||||
|
this.editDocData = null
|
||||||
|
this.fetchTree()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.problem-header {
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
.problem-content {
|
||||||
|
height: calc(100vh - 160px);
|
||||||
|
}
|
||||||
|
.problem-aside {
|
||||||
|
border: solid 1px rgba(240, 240, 240, 1);
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.problem-menu {
|
||||||
|
border-top: solid 1px rgba(240, 240, 240, 1);
|
||||||
|
}
|
||||||
|
.aside-toolbar {
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.aside-toolbar .el-button {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.search-result {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow: auto;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.search-item-title {
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 3px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.search-item-desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
.menu-actions {
|
||||||
|
position: absolute;
|
||||||
|
right: 40px;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.tree-icon {
|
||||||
|
background: rgba(232, 239, 248, 1);
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
padding: 0 0 2px 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.problem-main {
|
||||||
|
border: solid 1px rgba(240, 240, 240, 1);
|
||||||
|
border-left: none;
|
||||||
|
border-radius: 0 4px 4px 0;
|
||||||
|
}
|
||||||
|
.doc-card {
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
.doc-empty {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -14,10 +14,11 @@
|
|||||||
node-key="menu_id"
|
node-key="menu_id"
|
||||||
:data="treeData"
|
:data="treeData"
|
||||||
:props="{ label: 'name', children: 'children' }"
|
:props="{ label: 'name', children: 'children' }"
|
||||||
:default-expand-all="false"
|
:default-expand-all="true"
|
||||||
:expand-on-click-node="false"
|
:expand-on-click-node="true"
|
||||||
:check-strictly="true"
|
:default-checked-keys="checkedMenuIds"
|
||||||
show-checkbox
|
show-checkbox
|
||||||
|
:draggable="true"
|
||||||
@check="onTreeCheck"
|
@check="onTreeCheck"
|
||||||
>
|
>
|
||||||
<span slot-scope="{ node, data }" class="perm-drawer__tree-node">
|
<span slot-scope="{ node, data }" class="perm-drawer__tree-node">
|
||||||
@@ -46,14 +47,14 @@
|
|||||||
import { i18nMixin } from '@/composables/useI18n'
|
import { i18nMixin } from '@/composables/useI18n'
|
||||||
import util from '@/libs/util'
|
import util from '@/libs/util'
|
||||||
import { getMenuAll } from '@/api/menu'
|
import { getMenuAll } from '@/api/menu'
|
||||||
import { giveRoleMenu, getRoleMenu } from '@/api/system-administration/role'
|
import { giveRoleMenu } from '@/api/system-administration/role'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RolePermDrawer',
|
name: 'RolePermDrawer',
|
||||||
mixins: [i18nMixin('page.system_administration.user_management.role')],
|
mixins: [i18nMixin('page.system_administration.user_management.role')],
|
||||||
props: {
|
props: {
|
||||||
visible: { type: Boolean, default: false },
|
visible: { type: Boolean, default: false },
|
||||||
roleId: { type: Number, default: 0 },
|
role: { type: Object, default: () => ({}) },
|
||||||
title: { type: String, default: '' },
|
title: { type: String, default: '' },
|
||||||
confirmText: { type: String, default: '' },
|
confirmText: { type: String, default: '' },
|
||||||
cancelText: { type: String, default: '' },
|
cancelText: { type: String, default: '' },
|
||||||
@@ -84,18 +85,15 @@ export default {
|
|||||||
this.treeReady = false
|
this.treeReady = false
|
||||||
this.treeLoading = true
|
this.treeLoading = true
|
||||||
try {
|
try {
|
||||||
const [menuRes, roleMenuRes] = await Promise.all([
|
const menuRes = await getMenuAll()
|
||||||
getMenuAll()
|
|
||||||
])
|
|
||||||
const menuData = Array.isArray(menuRes) ? menuRes : (menuRes.data || [])
|
const menuData = Array.isArray(menuRes) ? menuRes : (menuRes.data || [])
|
||||||
const roleData = Array.isArray(roleMenuRes) ? roleMenuRes : (roleMenuRes.data || [])
|
this.checkedMenuIds = JSON.parse(this.role.menu_admin || '[]')
|
||||||
this.checkedMenuIds = roleData.map(item => item.menu_id)
|
|
||||||
this.treeData = util.formatDataToTree(menuData)
|
this.treeData = util.formatDataToTree(menuData)
|
||||||
this.treeReady = true
|
this.treeReady = true
|
||||||
await this.$nextTick()
|
setTimeout(() => {
|
||||||
await new Promise(resolve => setTimeout(resolve, 50))
|
this.treeLoading = false
|
||||||
this.$refs.permTree.setCheckedKeys(this.checkedMenuIds)
|
}, 1000)
|
||||||
} finally {
|
} catch {
|
||||||
this.treeLoading = false
|
this.treeLoading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -112,7 +110,7 @@ export default {
|
|||||||
this.submitting = true
|
this.submitting = true
|
||||||
try {
|
try {
|
||||||
const menuIds = this.$refs.permTree.getCheckedKeys()
|
const menuIds = this.$refs.permTree.getCheckedKeys()
|
||||||
await giveRoleMenu({ role_id: this.roleId, role_menu: menuIds })
|
await giveRoleMenu({ role_id: this.role.id, role_menu: menuIds })
|
||||||
this.$message.success(this.$t(this.key('operation_success')))
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
this.visibleProxy = false
|
this.visibleProxy = false
|
||||||
this.$emit('saved')
|
this.$emit('saved')
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
|
|
||||||
<role-perm-drawer
|
<role-perm-drawer
|
||||||
:visible.sync="permVisible"
|
:visible.sync="permVisible"
|
||||||
:role-id="permRole.id"
|
:role="permRole"
|
||||||
:title="key('assign_permissions')"
|
:title="key('assign_permissions')"
|
||||||
:confirm-text="key('confirm')"
|
:confirm-text="key('confirm')"
|
||||||
:cancel-text="key('cancel')"
|
:cancel-text="key('cancel')"
|
||||||
@@ -322,7 +322,7 @@ export default {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await updateRoleStatus({
|
await updateRoleStatus({
|
||||||
ids: rows.map(row => row.id),
|
id: rows.map(row => row.id),
|
||||||
status
|
status
|
||||||
})
|
})
|
||||||
this.$message.success(this.$t(this.key('operation_success')))
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
|||||||
443
src/views/system-administration/user-management/user/index.vue
Normal file
443
src/views/system-administration/user-management/user/index.vue
Normal file
@@ -0,0 +1,443 @@
|
|||||||
|
<template>
|
||||||
|
<d2-container>
|
||||||
|
<template #header>
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-form :inline="true" size="mini">
|
||||||
|
<el-form-item :label="$t(key('username'))">
|
||||||
|
<el-input
|
||||||
|
v-model="search.username"
|
||||||
|
:placeholder="$t(key('enter_username'))"
|
||||||
|
clearable
|
||||||
|
style="width:200px"
|
||||||
|
@keyup.enter.native="onSearch"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(key('full_name'))">
|
||||||
|
<el-input
|
||||||
|
v-model="search.nickname"
|
||||||
|
:placeholder="$t(key('enter_name'))"
|
||||||
|
clearable
|
||||||
|
style="width:200px"
|
||||||
|
@keyup.enter.native="onSearch"
|
||||||
|
/>
|
||||||
|
</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-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<page-table
|
||||||
|
ref="pageTable"
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:loading="loading"
|
||||||
|
:toolbar-buttons="toolbarButtons"
|
||||||
|
:row-buttons="rowButtons"
|
||||||
|
:pagination="pagination"
|
||||||
|
auto-height
|
||||||
|
@page-change="onPageChange"
|
||||||
|
@selection-change="onSelect"
|
||||||
|
>
|
||||||
|
<template #col-status="{ row }">
|
||||||
|
<span v-if="row.status === 1" style="color: #67c23a;">
|
||||||
|
<i class="el-icon-circle-check" />
|
||||||
|
{{ $t(key('enable')) }}
|
||||||
|
</span>
|
||||||
|
<span v-else style="color: #909399;">
|
||||||
|
<i class="el-icon-circle-close" />
|
||||||
|
{{ $t(key('disable')) }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</page-table>
|
||||||
|
|
||||||
|
<page-dialog-form
|
||||||
|
ref="dialogForm"
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
:title="dialogTitle"
|
||||||
|
width="35%"
|
||||||
|
:form-cols="dialogFormCols"
|
||||||
|
:form-data="formData"
|
||||||
|
:rules="dialogRules"
|
||||||
|
label-width="100px"
|
||||||
|
:submitting="submitting"
|
||||||
|
:confirm-text="key('confirm')"
|
||||||
|
:cancel-text="key('cancel')"
|
||||||
|
@submit="onDialogSubmit"
|
||||||
|
@close="onDialogClose"
|
||||||
|
/>
|
||||||
|
</d2-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useTableColumns } from '@/composables/useTableColumns'
|
||||||
|
import { useTableButtons } from '@/composables/useTableButtons'
|
||||||
|
import { i18nMixin } from '@/composables/useI18n'
|
||||||
|
import { confirmMixin } from '@/composables/useConfirmHandle'
|
||||||
|
import { getRoleAll } from '@/api/system-administration/role'
|
||||||
|
import {
|
||||||
|
getUserList,
|
||||||
|
createUser,
|
||||||
|
editUser,
|
||||||
|
deleteUser,
|
||||||
|
batchDeleteUser,
|
||||||
|
enableUser,
|
||||||
|
disableUser,
|
||||||
|
resetUserPwd
|
||||||
|
} from '@/api/system-administration/user'
|
||||||
|
import PageTable from '@/components/page-table'
|
||||||
|
import PageDialogForm from '@/components/page-dialog-form'
|
||||||
|
|
||||||
|
const ownUserId = () => localStorage.getItem('user_id')
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'system-administration-user',
|
||||||
|
components: { PageTable, PageDialogForm },
|
||||||
|
mixins: [i18nMixin('page.system_administration.user_management.user'), confirmMixin],
|
||||||
|
data () {
|
||||||
|
const key = this.key.bind(this)
|
||||||
|
const $t = this.$t.bind(this)
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
submitting: false,
|
||||||
|
tableData: [],
|
||||||
|
selectedRows: [],
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogTitle: '',
|
||||||
|
editId: '',
|
||||||
|
handleType: 'create',
|
||||||
|
search: { username: '', nickname: '' },
|
||||||
|
pagination: { current: 1, size: 10, total: 0 },
|
||||||
|
roleOptions: [],
|
||||||
|
columns: [],
|
||||||
|
toolbarButtons: [],
|
||||||
|
rowButtons: [],
|
||||||
|
baseFormCols: {
|
||||||
|
create: [
|
||||||
|
[{ type: 'input', prop: 'username', label: key('username'), placeholder: key('enter_username'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'password', inputType: 'password', label: key('password'), placeholder: key('enter_password'), clearable: true, showPassword: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'password_confirm', inputType: 'password', label: key('confirm_password'), placeholder: key('enter_confirm_password'), clearable: true, showPassword: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'select', prop: 'role_id', label: key('user_group'), placeholder: key('select_user_group'), clearable: true, style: { width: '90%' }, options: [] }],
|
||||||
|
[{ type: 'input', prop: 'nickname', label: key('full_name'), placeholder: key('enter_name'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'pass_number', label: key('pass_number'), placeholder: key('enter_pass_number'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'select', prop: 'status', label: key('status'), clearable: false, style: { width: '90%' }, options: [{ value: '1', label: $t(key('enable')) }, { value: '0', label: $t(key('disable')) }] }]
|
||||||
|
],
|
||||||
|
edit: [
|
||||||
|
[{ type: 'input', prop: 'username', label: key('username'), placeholder: key('enter_username'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'select', prop: 'role_id', label: key('user_group'), placeholder: key('select_user_group'), clearable: true, style: { width: '90%' }, options: [] }],
|
||||||
|
[{ type: 'input', prop: 'nickname', label: key('full_name'), placeholder: key('enter_name'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'pass_number', label: key('pass_number'), placeholder: key('enter_pass_number'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'select', prop: 'status', label: key('status'), clearable: false, style: { width: '90%' }, options: [{ value: '1', label: $t(key('enable')) }, { value: '0', label: $t(key('disable')) }] }]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
baseRules: {
|
||||||
|
username: [
|
||||||
|
{ required: true, message: key('enter_username'), trigger: 'blur' },
|
||||||
|
{ min: 3, max: 20, message: key('username_length'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
password: [
|
||||||
|
{ required: true, message: key('enter_password'), trigger: 'blur' },
|
||||||
|
{ min: 6, max: 64, message: key('password_length'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
password_confirm: [
|
||||||
|
{ required: true, message: key('enter_confirm_password'), trigger: 'blur' },
|
||||||
|
{ min: 6, max: 64, message: key('password_length'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
role_id: [
|
||||||
|
{ required: true, message: key('select_user_group'), trigger: 'change' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
dialogFormCols () {
|
||||||
|
const cols = this.baseFormCols[this.handleType] || this.baseFormCols.create
|
||||||
|
const roleIdx = this.handleType === 'create' ? 3 : 1
|
||||||
|
if (cols[roleIdx] && cols[roleIdx][0]) {
|
||||||
|
cols[roleIdx][0].options = this.roleOptions
|
||||||
|
}
|
||||||
|
return cols
|
||||||
|
},
|
||||||
|
dialogRules () {
|
||||||
|
if (this.handleType === 'edit') {
|
||||||
|
return {
|
||||||
|
username: this.baseRules.username,
|
||||||
|
role_id: this.baseRules.role_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.baseRules
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.initRoleOptions()
|
||||||
|
this.columns = useTableColumns([
|
||||||
|
{ prop: 'sort', label: this.key('index'), width: 80 },
|
||||||
|
{ prop: 'username', label: this.key('username'), minWidth: 120 },
|
||||||
|
{ prop: 'nickname', label: this.key('full_name'), minWidth: 100 },
|
||||||
|
{ prop: 'pass_number', label: this.key('pass_number'), minWidth: 120 },
|
||||||
|
{ prop: 'status', label: this.key('status'), slot: 'status', width: 100 },
|
||||||
|
{ prop: 'role_name', label: this.key('user_group'), minWidth: 100 },
|
||||||
|
{ prop: 'last_ip', label: this.key('login_ip'), width: 130 },
|
||||||
|
{ prop: 'create_time', label: this.key('last_login_time'), width: 160 },
|
||||||
|
{ prop: '_actions', label: this.key('actions'), width: 240, fixed: 'right' }
|
||||||
|
])
|
||||||
|
const btns = useTableButtons({
|
||||||
|
toolbar: [
|
||||||
|
{
|
||||||
|
key: 'add',
|
||||||
|
label: this.key('add'),
|
||||||
|
icon: 'el-icon-plus',
|
||||||
|
type: 'primary',
|
||||||
|
auth: '/system_settings/user_management/member/create',
|
||||||
|
onClick: this.openAdd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'enable',
|
||||||
|
label: this.key('enable'),
|
||||||
|
icon: 'el-icon-check',
|
||||||
|
type: 'success',
|
||||||
|
auth: '/system_settings/user_management/member/enable',
|
||||||
|
onClick: () => this.batchUpdateStatus(1)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'disable',
|
||||||
|
label: this.key('disable'),
|
||||||
|
icon: 'el-icon-close',
|
||||||
|
type: 'warning',
|
||||||
|
auth: '/system_settings/user_management/member/disable',
|
||||||
|
onClick: () => this.batchUpdateStatus(0)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'batch_delete',
|
||||||
|
label: this.key('batch_delete'),
|
||||||
|
icon: 'el-icon-delete',
|
||||||
|
type: 'danger',
|
||||||
|
auth: '/system_settings/user_management/member/batch-delete',
|
||||||
|
onClick: this.handleBatchDelete
|
||||||
|
}
|
||||||
|
],
|
||||||
|
row: [
|
||||||
|
{
|
||||||
|
key: 'edit',
|
||||||
|
label: this.key('edit'),
|
||||||
|
icon: 'el-icon-edit',
|
||||||
|
auth: '/system_settings/user_management/member/edit',
|
||||||
|
onClick: this.openEdit
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'reset_pwd',
|
||||||
|
label: this.key('reset_password'),
|
||||||
|
icon: 'el-icon-refresh',
|
||||||
|
auth: '/system_settings/user_management/member/reset-pwd',
|
||||||
|
onClick: this.handleResetPwd
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'delete',
|
||||||
|
label: this.key('delete'),
|
||||||
|
icon: 'el-icon-delete',
|
||||||
|
color: 'danger',
|
||||||
|
auth: '/system_settings/user_management/member/delete',
|
||||||
|
onClick: this.handleDelete
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, this.$permission)
|
||||||
|
this.toolbarButtons = btns.toolbarButtons
|
||||||
|
this.rowButtons = btns.rowButtons
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async initRoleOptions () {
|
||||||
|
try {
|
||||||
|
const res = await getRoleAll()
|
||||||
|
const data = Array.isArray(res) ? res : (res.data || [])
|
||||||
|
this.roleOptions = data.map(item => ({ value: item.id, label: item.name }))
|
||||||
|
} catch { /* 忽略 */ }
|
||||||
|
},
|
||||||
|
async fetchData () {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const res = await getUserList({
|
||||||
|
...this.search,
|
||||||
|
page_no: this.pagination.current,
|
||||||
|
page_size: this.pagination.size
|
||||||
|
})
|
||||||
|
const list = Array.isArray(res) ? res : (res.data || [])
|
||||||
|
const total = Array.isArray(res) ? res.length : (res.count || 0)
|
||||||
|
this.tableData = list
|
||||||
|
this.pagination.total = total
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSearch () {
|
||||||
|
this.pagination.current = 1
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onReset () {
|
||||||
|
this.search = { username: '', nickname: '' }
|
||||||
|
this.pagination.current = 1
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onPageChange (page) {
|
||||||
|
this.pagination.current = page.current
|
||||||
|
this.pagination.size = page.size
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onSelect (rows) {
|
||||||
|
this.selectedRows = rows
|
||||||
|
},
|
||||||
|
resetForm () {
|
||||||
|
this.formData = {
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
password_confirm: '',
|
||||||
|
role_id: '',
|
||||||
|
nickname: '',
|
||||||
|
pass_number: '',
|
||||||
|
status: '1'
|
||||||
|
}
|
||||||
|
this.editId = ''
|
||||||
|
},
|
||||||
|
openAdd () {
|
||||||
|
this.handleType = 'create'
|
||||||
|
this.dialogTitle = this.key('add_title')
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.dialogForm && this.$refs.dialogForm.reset()
|
||||||
|
this.resetForm()
|
||||||
|
this.dialogVisible = true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openEdit (row) {
|
||||||
|
this.handleType = 'edit'
|
||||||
|
this.dialogTitle = this.key('edit_title')
|
||||||
|
this.editId = row.user_id
|
||||||
|
this.formData = {
|
||||||
|
username: row.username,
|
||||||
|
role_id: row.role_id,
|
||||||
|
nickname: row.nickname || '',
|
||||||
|
pass_number: row.pass_number || '',
|
||||||
|
status: String(row.status)
|
||||||
|
}
|
||||||
|
this.dialogVisible = true
|
||||||
|
},
|
||||||
|
async onDialogSubmit () {
|
||||||
|
this.submitting = true
|
||||||
|
try {
|
||||||
|
if (this.handleType === 'create') {
|
||||||
|
if (this.formData.password !== this.formData.password_confirm) {
|
||||||
|
this.$message.error(this.$t(this.key('password_not_match')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await createUser(this.formData)
|
||||||
|
} else {
|
||||||
|
await editUser({ ...this.formData, id: this.editId })
|
||||||
|
}
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
this.dialogVisible = false
|
||||||
|
this.fetchData()
|
||||||
|
} finally {
|
||||||
|
this.submitting = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDialogClose () {
|
||||||
|
this.resetForm()
|
||||||
|
},
|
||||||
|
batchUpdateStatus (status) {
|
||||||
|
const uid = ownUserId()
|
||||||
|
const rows = this.selectedRows.filter(row => String(row.user_id) !== uid)
|
||||||
|
if (rows.length === 0 && this.selectedRows.length > 0) {
|
||||||
|
this.$message.warning(this.$t(this.key('cannot_operate_self')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (rows.length === 0) {
|
||||||
|
this.$message.warning(this.$t(this.key('select_rows_first')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const ids = rows.map(row => row.user_id)
|
||||||
|
this.$confirm(
|
||||||
|
this.$t(this.key('confirm_execute')),
|
||||||
|
this.$t(this.key('prompt')),
|
||||||
|
{
|
||||||
|
confirmButtonText: this.$t(this.key('confirm')),
|
||||||
|
cancelButtonText: this.$t(this.key('cancel')),
|
||||||
|
type: 'warning',
|
||||||
|
closeOnClickModal: false
|
||||||
|
}
|
||||||
|
).then(async () => {
|
||||||
|
try {
|
||||||
|
await (status === 1 ? enableUser({ id: ids, status }) : disableUser({ id: ids, status: 0 }))
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
this.fetchData()
|
||||||
|
} catch { /* 拦截器已处理 */ }
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
async handleDelete (row) {
|
||||||
|
if (String(row.user_id) === ownUserId()) {
|
||||||
|
this.$message.warning(this.$t(this.key('cannot_delete_self')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const cancelled = await this.$confirmAction(
|
||||||
|
{ message: this.key('confirm_delete'), title: this.key('prompt') },
|
||||||
|
() => deleteUser({ id: [row.user_id] })
|
||||||
|
)
|
||||||
|
if (cancelled) return
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
this.pagination.current = Math.min(
|
||||||
|
this.pagination.current,
|
||||||
|
Math.ceil((this.pagination.total - 1) / this.pagination.size) || 1
|
||||||
|
)
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
async handleBatchDelete () {
|
||||||
|
const uid = ownUserId()
|
||||||
|
const rows = this.selectedRows.filter(row => String(row.user_id) !== uid)
|
||||||
|
if (rows.length === 0 && this.selectedRows.length > 0) {
|
||||||
|
this.$message.warning(this.$t(this.key('cannot_delete_self')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (rows.length === 0) {
|
||||||
|
this.$message.warning(this.$t(this.key('select_rows_first')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const cancelled = await this.$confirmAction(
|
||||||
|
{ message: this.key('confirm_batch_delete'), title: this.key('prompt') },
|
||||||
|
() => batchDeleteUser({ id: rows.map(row => row.user_id) })
|
||||||
|
)
|
||||||
|
if (cancelled) return
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
async handleResetPwd (row) {
|
||||||
|
try {
|
||||||
|
await this.$confirm(
|
||||||
|
this.$t(this.key('confirm_reset_pwd')),
|
||||||
|
this.$t(this.key('prompt')),
|
||||||
|
{
|
||||||
|
confirmButtonText: this.$t(this.key('confirm')),
|
||||||
|
cancelButtonText: this.$t(this.key('cancel')),
|
||||||
|
type: 'warning',
|
||||||
|
closeOnClickModal: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
await resetUserPwd({ id: row.user_id })
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
} catch { /* 取消或失败 */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search-bar {
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
/deep/ .el-form-item--mini.el-form-item {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -73,8 +73,8 @@ export default {
|
|||||||
return this.aside[key].children.filter(item => {
|
return this.aside[key].children.filter(item => {
|
||||||
const title = item.title || ''
|
const title = item.title || ''
|
||||||
if (title.indexOf('首页') !== -1) return false
|
if (title.indexOf('首页') !== -1) return false
|
||||||
if (item.icon === 'home') return false
|
// if (item.icon === 'home') return false
|
||||||
if (this.$route.path === item.path) return false
|
// if (this.$route.path === item.path) return false
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user