【底座】前端界面及样式优化,尤其是左树右表界面格外的清晰

This commit is contained in:
小诺
2025-11-09 01:27:15 +08:00
parent 2b509efec3
commit 4f1e5524cc
48 changed files with 2049 additions and 2136 deletions

View File

@@ -101,7 +101,7 @@ export default {
<template>
<s-table ref="tableRef" :columns="columns" :data="loadData" :alert="false" bordered :row-key="(record) => record.id">
<!-- #operator 插槽可以放入一些关于表格的操作,比如新增数据。 -->
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="">
<template #icon><plus-outlined /></template>

View File

@@ -1,51 +1,41 @@
# ResizablePanel 可拖拽调整大小面板组件
# XnResizablePanel 可拖拽调整大小面板组件
一个基于 Vue 3 的可拖拽调整大小的面板组件,支持水平和垂直分割布局。
一个基于 Vue 3 的可拖拽调整大小的面板组件,支持水平和垂直分割布局;并可在小屏自动隐藏左侧与拖拽条(按 `md` 配置)
## 特性
- 🎯 **灵活布局**支持水平row和垂直column分割
- 📏 **尺寸控制**:可设置初始大小、最小值和最大值
- 🎨 **平滑体验**:流畅的拖拽动画和视觉反馈
- 📱 **响应式设计**自适应不同屏幕尺寸
- 📱 **响应式设计**`md` 配置在 `<768px` 自动隐藏左侧与拖拽条
- 🔧 **易于集成**:简单的 API 设计,易于在项目中使用
## 安装
`ResizablePanel` 组件文件复制到你的项目中:
`XnResizablePanel` 组件文件复制到你的项目中:
```
src/components/ResizablePanel/index.vue
src/components/XnResizablePanel/index.vue
```
## 基本用法
### 水平分割布局
### 水平分割布局row
```vue
<template>
<ResizablePanel
direction="row"
:initial-size="300"
:min-size="200"
:max-size="500"
@resize="handleResize"
>
<template #first>
<div class="left-panel">
左侧内容
</div>
</template>
<template #second>
<div class="right-panel">
右侧内容
</div>
</template>
</ResizablePanel>
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
左侧内容
</template>
<template #right>
右侧内容
</template>
</XnResizablePanel>
</template>
<script setup>
import ResizablePanel from '@/components/ResizablePanel/index.vue'
import XnResizablePanel from '@/components/XnResizablePanel/index.vue'
const handleResize = (size) => {
console.log('面板大小变化:', size)
@@ -53,30 +43,32 @@ const handleResize = (size) => {
</script>
```
### 垂直分割布局
### 垂直分割布局column
```vue
<template>
<ResizablePanel
direction="column"
:initial-size="200"
:min-size="100"
:max-size="400"
>
<template #first>
<div class="top-panel">
顶部内容
</div>
<XnResizablePanel direction="column" :initial-size="220" :min-size="120" :max-size="480">
<template #left>
顶部内容
</template>
<template #second>
<div class="bottom-panel">
底部内容
</div>
<template #right>
底部内容
</template>
</ResizablePanel>
</XnResizablePanel>
</template>
```
### 小屏隐藏(`md` 配置)
`md``0` 时,在视口宽度 `<768px` 时自动隐藏左侧与拖拽条,仅显示右侧内容:
```vue
<XnResizablePanel :md="0">
<template #left>左侧内容</template>
<template #right>右侧内容</template>
</XnResizablePanel>
```
## API
### Props
@@ -84,119 +76,86 @@ const handleResize = (size) => {
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `direction` | `String` | `'row'` | 分割方向,可选值:`'row'`(水平)、`'column'`(垂直) |
| `initial-size` | `Number` | `300` | 第一个面板的初始大小px |
| `min-size` | `Number` | `100` | 第一个面板的最小大小px |
| `max-size` | `Number` | `500` | 第一个面板的最大大小px |
| `initial-size` | `Number` | `200` | 左侧(或顶部)面板的初始大小px |
| `min-size` | `Number` | `100` | 左侧(或顶部)面板的最小大小px |
| `max-size` | `Number` | `500` | 左侧(或顶部)面板的最大大小px |
| `md` | `Number` | `null` | 响应式开关:当为 `0` 时,在 `<768px` 隐藏左侧与拖拽条 |
### Events
| 事件名 | 参数 | 说明 |
|--------|------|------|
| `resize` | `(size: number)` | 面板大小变化时触发,参数为第一个面板的当前大小 |
| `resize` | `(size: number)` | 面板大小变化时触发,参数为左侧(或顶部)面板的当前大小 |
### Slots
| 插槽名 | 说明 |
|--------|------|
| `first` | 第一个面板的内容(水平布局时为左侧,垂直布局时为顶部) |
| `second` | 第二个面板的内容(水平布局时为右侧,垂直布局时为底部) |
| `left` | 左侧(或顶部)面板内容 |
| `right` | 右侧(或底部)面板内容 |
## 样式定制
### 暴露方法Expose
组件使用了 CSS 变量,你可以通过覆盖这些变量来自定义样式
```css
.resizable-panel {
/* 分割线颜色 */
--divider-color: #e8e8e8;
/* 分割线悬停颜色 */
--divider-hover-color: #1890ff;
/* 分割线宽度 */
--divider-width: 4px;
/* 过渡动画时间 */
--transition-duration: 0.2s;
}
```
## 高级用法
### 嵌套使用
通过组件引用可以调用以下方法
```vue
<template>
<ResizablePanel direction="row" :initial-size="250">
<template #first>
<div class="sidebar">侧边栏</div>
</template>
<template #second>
<ResizablePanel direction="column" :initial-size="200">
<template #first>
<div class="header">头部</div>
</template>
<template #second>
<div class="content">主要内容</div>
</template>
</ResizablePanel>
</template>
</ResizablePanel>
</template>
```
### 动态控制
```vue
<template>
<div>
<button @click="resetSize">重置大小</button>
<ResizablePanel
ref="panelRef"
direction="row"
:initial-size="panelSize"
@resize="handleResize"
>
<!-- 内容 -->
</ResizablePanel>
</div>
</template>
<script setup>
import { ref } from 'vue'
import XnResizablePanel from '@/components/XnResizablePanel/index.vue'
const panelSize = ref(300)
const panelRef = ref()
const handleResize = (size) => {
panelSize.value = size
function setTo300() {
panelRef.value?.setSize(300)
}
const resetSize = () => {
panelSize.value = 300
// 如果需要强制更新组件,可以使用 key 或其他方法
function logSize() {
console.log(panelRef.value?.getSize())
}
</script>
<template>
<XnResizablePanel ref="panelRef">
<template #left>左侧</template>
<template #right>右侧</template>
</XnResizablePanel>
<button @click="setTo300">设置为 300px</button>
<button @click="logSize">打印当前大小</button>
</template>
```
## 注意事项
## 样式与定制
1. **容器高度**:确保父容器有明确的高度,否则垂直布局可能无法正常工作
2. **最小/最大值**:合理设置 `min-size``max-size`,避免内容被过度压缩
3. **性能优化**:在大量数据或复杂布局中,考虑使用 `v-show` 而不是 `v-if` 来控制面板显示
4. **移动端适配**:在移动设备上,建议增大分割线的触摸区域
默认样式要点:
## 浏览器兼容性
- 左/右(或上/下)面板默认内边距:`24px`
- 拖拽条(横向)宽度:`8px`;(纵向)高度:`8px`
- 拖拽握把居中,胶囊形,内含三点提示;悬停/按下有视觉反馈
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
可覆盖的 CSS 变量(在主题中使用):
## 更新日志
```css
/* 组件内部使用的变量名称 */
.resizable-panel {
--component-background: #fff;
--border-color-base: #e5e7eb; /* Gray-200 */
--primary-color: #1677ff; /* Ant Design 默认蓝 */
}
### v1.0.0
- 初始版本发布
- 支持水平和垂直分割
- 支持拖拽调整大小
- 支持最小/最大值限制
/* 调整拖拽条尺寸或样式 */
.resizer-horizontal { width: 8px; }
.resizer-vertical { height: 8px; }
.resizer-handle { box-shadow: 0 2px 10px rgba(0,0,0,0.06), inset 0 0 0 1px var(--border-color-base); }
/* 修改面板内边距 */
.panel-left, .panel-right { padding: 24px; }
/* 示例:让拖拽条更显眼 */
.resizer:hover .resizer-handle {
box-shadow: 0 4px 14px rgba(0,0,0,0.10), inset 0 0 0 1px var(--primary-color);
}
/* 示例:增大横向握把高度 */
.resizer-horizontal .resizer-handle { height: 32px; }
```

View File

@@ -7,6 +7,7 @@
minWidth: direction === 'row' ? minSize + 'px' : 'auto',
minHeight: direction === 'column' ? minSize + 'px' : 'auto'
}"
v-if="!shouldHideLeft"
>
<slot name="left"></slot>
</div>
@@ -14,7 +15,10 @@
class="resizer"
:class="{ 'resizer-horizontal': direction === 'row', 'resizer-vertical': direction === 'column' }"
@mousedown="startResize"
></div>
v-if="!shouldHideLeft"
>
<div class="resizer-handle"></div>
</div>
<div class="panel-right" :style="{ flex: 1 }">
<slot name="right"></slot>
</div>
@@ -45,6 +49,11 @@
type: String,
default: 'row',
validator: (value) => ['row', 'column'].includes(value)
},
// 合并后的响应式开关:当 md 为 0 时,在 <768px 隐藏左侧与拖拽条
md: {
type: Number,
default: null
}
})
@@ -53,12 +62,21 @@
const leftSize = ref(props.initialSize)
const isResizing = ref(false)
// 监听窗口宽度,用于判断是否在小屏隐藏
const windowWidth = ref(typeof window !== 'undefined' ? window.innerWidth : 1024)
const shouldHideLeft = computed(() => {
// 当 md 为 0 时,在 <768 的视口隐藏左侧与拖拽条
return props.md === 0 && windowWidth.value < 768
})
// 根据方向确定使用的CSS属性
const sizeProperty = computed(() => {
return props.direction === 'row' ? 'width' : 'height'
})
const startResize = (e) => {
if (shouldHideLeft.value) return
isResizing.value = true
document.addEventListener('mousemove', handleResize)
document.addEventListener('mouseup', stopResize)
@@ -93,9 +111,20 @@
document.removeEventListener('mouseup', stopResize)
}
let resizeHandler = null
onMounted(() => {
resizeHandler = () => {
windowWidth.value = window.innerWidth
}
window.addEventListener('resize', resizeHandler)
// 立刻同步一次
resizeHandler()
})
onUnmounted(() => {
document.removeEventListener('mousemove', handleResize)
document.removeEventListener('mouseup', stopResize)
if (resizeHandler) window.removeEventListener('resize', resizeHandler)
})
// 暴露方法供外部调用
@@ -114,8 +143,9 @@
}
.panel-left {
padding: 24px;
overflow: auto;
background: var(--component-background);
background: var(--snowy-background-color);
/* 隐藏滚动条但保持滚动功能 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE 和 Edge */
@@ -126,8 +156,9 @@
}
.panel-right {
padding: 24px;
overflow: auto;
background: var(--component-background);
background: var(--snowy-background-color);
/* 隐藏滚动条但保持滚动功能 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE 和 Edge */
@@ -138,27 +169,93 @@
}
.resizer {
background: var(--border-color-base);
cursor: col-resize;
position: relative;
background: transparent;
user-select: none;
transition: background-color 0.2s;
}
.resizer:hover {
background: var(--primary-color);
transition:
background-color 0.2s,
box-shadow 0.2s;
}
/* 增大可点击区域,居中握把,便于拖拽 */
.resizer-horizontal {
width: 4px;
width: 8px;
cursor: col-resize;
}
.resizer-vertical {
height: 4px;
height: 8px;
cursor: row-resize;
box-shadow:
inset 0 -1px 0 var(--border-color-base),
inset 0 1px 0 var(--border-color-base);
}
.resizer:active {
background: var(--primary-color);
/* 中间握把(胶囊形),提升可拖拽直觉性 */
.resizer-handle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--component-background);
border-radius: 999px;
box-shadow:
0 2px 10px rgba(0, 0, 0, 0.06),
inset 0 0 0 1px var(--border-color-base);
}
/* 横向握把:竖排 3 个点 */
.resizer-horizontal .resizer-handle {
width: 6px;
height: 26px;
}
.resizer-horizontal .resizer-handle::before {
content: '';
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2px;
height: 2px;
background: var(--border-color-base);
border-radius: 50%;
box-shadow:
0 7px 0 0 var(--border-color-base),
0 -7px 0 0 var(--border-color-base);
}
/* 纵向握把:横排 3 个点 */
.resizer-vertical .resizer-handle {
width: 26px;
height: 6px;
}
.resizer-vertical .resizer-handle::before {
content: '';
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2px;
height: 2px;
background: var(--border-color-base);
border-radius: 50%;
box-shadow:
7px 0 0 0 var(--border-color-base),
-7px 0 0 0 var(--border-color-base);
}
/* 悬停与按下反馈 */
.resizer:hover .resizer-handle {
box-shadow:
0 4px 14px rgba(0, 0, 0, 0.1),
inset 0 0 0 1px var(--primary-color);
}
.resizer:active .resizer-handle {
transform: translate(-50%, -50%) scale(0.98);
}
</style>

View File

@@ -191,7 +191,7 @@ a, button, input, textarea {
}
.top-snowy-header {
background: #001529;
background: var(--snowy-background-color);
color: white;
}
.top-snowy-header-light {

View File

@@ -1,5 +1,5 @@
<template>
<a-card :bordered="false" :body-style="{ 'padding-bottom': '0px' }" class="mb-2">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
@@ -23,13 +23,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -38,8 +38,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"

View File

@@ -52,7 +52,7 @@
const treeData = ref([])
// 默认展开的节点(顶级)
const defaultExpandedKeys = ref([0])
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
// 打开抽屉
const onOpen = (record, parentId) => {
visible.value = true

View File

@@ -1,90 +1,84 @@
<template>
<a-row :gutter="10">
<a-col :xs="0" :sm="0" :md="0" :lg="4" :xl="4">
<a-card :bordered="false" :loading="cardLoading" class="left-tree-container">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</a-card>
</a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="20" :xl="20">
<a-card :bordered="false" class="xn-mb10">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="请选择上级字典:" name="parentId">
<a-tree-select
v-model:value="searchFormState.parentId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择上级字典"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="字典名称关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入字典名称关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
</template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false" class="xn-mb10">
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
bordered
:tool-config="toolConfig"
:row-key="(record) => record.id"
:scroll="{ x: 'max-content' }"
>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'level'">
<a-tag color="blue" v-if="record.level">{{ record.level }}</a-tag>
<a-tag color="green" v-else>子级</a-tag>
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)" v-if="hasPerm('bizDictEdit')">编辑</a>
</template>
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="请选择上级字典:" name="parentId">
<a-tree-select
v-model:value="searchFormState.parentId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择上级字典"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="字典名称关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入字典名称关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined />
</template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
bordered
:tool-config="toolConfig"
:row-key="(record) => record.id"
:scroll="{ x: 'max-content' }"
>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'level'">
<a-tag color="blue" v-if="record.level">{{ record.level }}</a-tag>
<a-tag color="green" v-else>子级</a-tag>
</template>
</s-table>
</a-card>
</a-col>
</a-row>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)" v-if="hasPerm('bizDictEdit')">编辑</a>
</template>
</template>
</s-table>
</template>
</XnResizablePanel>
<Form ref="formRef" @successful="formSuccessful()" />
</template>
@@ -118,7 +112,6 @@
// 定义tableDOM
const tableRef = ref(null)
const formRef = ref()
const cardLoading = ref(true)
const searchFormRef = ref()
const searchFormState = ref({})
// 默认展开的节点
@@ -161,16 +154,11 @@
}
// 加载左侧的树
const loadTreeData = () => {
bizDictApi
.dictTree()
.then((res) => {
if (res) {
treeData.value = res
}
})
.finally(() => {
cardLoading.value = false
})
bizDictApi.dictTree().then((res) => {
if (res) {
treeData.value = res
}
})
}
// 点击树查询
const treeSelect = (selectedKeys) => {
@@ -203,7 +191,3 @@
})
}
</script>
<style lang="less" scoped>
</style>

View File

@@ -1,5 +1,5 @@
<template>
<a-card :bordered="false" class="xn-mb10">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
@@ -12,13 +12,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -27,8 +27,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
@@ -40,7 +38,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('bizGroupAdd')">
<template #icon><plus-outlined /></template>

View File

@@ -32,13 +32,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -62,7 +62,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('bizNoticeAdd')">
<template #icon><plus-outlined /></template>

View File

@@ -70,6 +70,7 @@
// 定义机构元素
const treeData = ref([])
const submitLoading = ref(false)
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
// 打开抽屉
const onOpen = (record, parentId) => {

View File

@@ -1,111 +1,105 @@
<template>
<a-row :gutter="10">
<a-col :xs="0" :sm="0" :md="0" :lg="4" :xl="4">
<a-card :bordered="false" :loading="cardLoading" class="left-tree-container">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</a-card>
</a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="20" :xl="20">
<a-card :bordered="false" class="xn-mb10">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="上级机构:" name="parentId">
<a-tree-select
v-model:value="searchFormState.parentId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择上级机构"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="名称">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入名称关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon><SearchOutlined /></template>
查询
</a-button>
<a-button @click="reset">
<template #icon><redo-outlined /></template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:row-key="(record) => record.id"
:tool-config="toolConfig"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<a-space>
<a-button
type="primary"
@click="formRef.onOpen(undefined, searchFormState.parentId)"
v-if="hasPerm('bizOrgAdd')"
>
<template #icon><plus-outlined /></template>
新增
</a-button>
<xn-batch-button
v-if="hasPerm('bizOrgBatchDelete')"
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchOrg"
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="上级机构:" name="parentId">
<a-tree-select
v-model:value="searchFormState.parentId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择上级机构"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-space>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="名称">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入名称关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon><SearchOutlined /></template>
查询
</a-button>
<a-button @click="reset">
<template #icon><redo-outlined /></template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:row-key="(record) => record.id"
:tool-config="toolConfig"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator>
<a-space>
<a-button
type="primary"
@click="formRef.onOpen(undefined, searchFormState.parentId)"
v-if="hasPerm('bizOrgAdd')"
>
<template #icon><plus-outlined /></template>
新增
</a-button>
<xn-batch-button
v-if="hasPerm('bizOrgBatchDelete')"
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchOrg"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('ORG_CATEGORY', record.category) }}
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('ORG_CATEGORY', record.category) }}
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)" v-if="hasPerm('bizOrgEdit')">编辑</a>
<a-divider type="vertical" v-if="hasPerm(['bizOrgEdit', 'bizOrgDelete'], 'and')" />
<a-popconfirm title="删除此机构与下级机构吗" @confirm="removeOrg(record)">
<a-button type="link" danger size="small" v-if="hasPerm('bizOrgDelete')">删除</a-button>
</a-popconfirm>
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)" v-if="hasPerm('bizOrgEdit')">编辑</a>
<a-divider type="vertical" v-if="hasPerm(['bizOrgEdit', 'bizOrgDelete'], 'and')" />
<a-popconfirm title="删除此机构与下级机构吗" @confirm="removeOrg(record)">
<a-button type="link" danger size="small" v-if="hasPerm('bizOrgDelete')">删除</a-button>
</a-popconfirm>
</template>
</s-table>
</a-card>
</a-col>
</a-row>
</template>
</s-table>
</template>
</XnResizablePanel>
<Form ref="formRef" @successful="tableRef.refresh()" />
</template>
@@ -163,7 +157,6 @@
const treeData = ref([])
// 替换treeNode 中 title,key,children
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
const cardLoading = ref(true)
// 表格查询 返回 Promise 对象
const loadData = (parameter) => {
@@ -179,32 +172,26 @@
}
// 加载左侧的树
const loadTreeData = () => {
bizOrgApi
.orgTree()
.then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
bizOrgApi.orgTree().then((res) => {
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
})
}
}
})
}
})
.finally(() => {
cardLoading.value = false
})
}
})
}
// 点击树查询
const treeSelect = (selectedKeys) => {
@@ -233,7 +220,3 @@
})
}
</script>
<style scoped>
</style>

View File

@@ -1,111 +1,105 @@
<template>
<a-row :gutter="10">
<a-col :xs="0" :sm="0" :md="0" :lg="4" :xl="4">
<a-card :bordered="false" :loading="cardLoading" class="left-tree-container">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</a-card>
</a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="20" :xl="20">
<a-card :bordered="false" class="xn-mb10">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="机构:" name="orgId">
<a-tree-select
v-model:value="searchFormState.orgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择机构"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入岗位名称关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon><SearchOutlined /></template>
查询
</a-button>
<a-button @click="reset">
<template #icon><redo-outlined /></template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:tool-config="toolConfig"
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<a-space>
<a-button
type="primary"
@click="formRef.onOpen(undefined, searchFormState.orgId)"
v-if="hasPerm('bizPositionAdd')"
>
<template #icon><plus-outlined /></template>
新增
</a-button>
<xn-batch-button
v-if="hasPerm('bizPositionBatchDelete')"
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchPosition"
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="机构:" name="orgId">
<a-tree-select
v-model:value="searchFormState.orgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择机构"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-space>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入岗位名称关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon><SearchOutlined /></template>
查询
</a-button>
<a-button @click="reset">
<template #icon><redo-outlined /></template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:tool-config="toolConfig"
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator>
<a-space>
<a-button
type="primary"
@click="formRef.onOpen(undefined, searchFormState.orgId)"
v-if="hasPerm('bizPositionAdd')"
>
<template #icon><plus-outlined /></template>
新增
</a-button>
<xn-batch-button
v-if="hasPerm('bizPositionBatchDelete')"
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchPosition"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('POSITION_CATEGORY', record.category) }}
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('POSITION_CATEGORY', record.category) }}
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)" v-if="hasPerm('bizPositionEdit')">编辑</a>
<a-divider type="vertical" v-if="hasPerm(['bizPositionEdit', 'bizPositionDelete'], 'and')" />
<a-popconfirm title="确定删除此岗位" @confirm="removeOrg(record)">
<a-button type="link" danger size="small" v-if="hasPerm('bizPositionDelete')">删除</a-button>
</a-popconfirm>
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)" v-if="hasPerm('bizPositionEdit')">编辑</a>
<a-divider type="vertical" v-if="hasPerm(['bizPositionEdit', 'bizPositionDelete'], 'and')" />
<a-popconfirm title="确定删除此岗位" @confirm="removeOrg(record)">
<a-button type="link" danger size="small" v-if="hasPerm('bizPositionDelete')">删除</a-button>
</a-popconfirm>
</template>
</s-table>
</a-card>
</a-col>
</a-row>
</template>
</s-table>
</template>
</XnResizablePanel>
<Form ref="formRef" @successful="tableRef.refresh(true)" />
</template>
@@ -164,7 +158,6 @@
const treeData = ref([])
// 替换treeNode 中 title,key,children
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
const cardLoading = ref(true)
// 表格查询 返回 Promise 对象
const loadData = (parameter) => {
@@ -178,32 +171,26 @@
tableRef.value.refresh(true)
}
// 加载左侧的树
bizOrgApi
.orgTree()
.then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
bizOrgApi.orgTree().then((res) => {
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
})
}
}
})
}
})
.finally(() => {
cardLoading.value = false
})
}
})
// 点击树查询
const treeSelect = (selectedKeys) => {
if (selectedKeys.length > 0) {
@@ -232,6 +219,4 @@
}
</script>
<style scoped>
</style>
<style scoped></style>

View File

@@ -319,6 +319,7 @@
const xnChildUserPageSelectRef = ref()
// 表单数据
const formData = ref({})
const treeFieldNames = { children: 'children', title: 'dictLabel', key: 'id' }
// 打开抽屉
const onOpen = (record, orgId) => {

View File

@@ -1,174 +1,159 @@
<template>
<a-row :gutter="10">
<a-col :xs="0" :sm="0" :md="0" :lg="4" :xl="4">
<a-card :bordered="false" :loading="cardLoading" class="left-tree-container">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</a-card>
</a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="20" :xl="20">
<a-card :bordered="false" class="xn-mb10">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="所属机构" name="orgId">
<a-tree-select
v-model:value="searchFormState.orgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择所属机构"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="关键词">
<a-input
v-model:value="searchFormState.searchKey"
placeholder="请输入姓名或关键词"
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="userStatus" label="人员状态">
<a-select
v-model:value="searchFormState.userStatus"
placeholder="请选择人员状态"
:getPopupContainer="(trigger) => trigger.parentNode"
>
<a-select-option v-for="item in statusData" :key="item.value" :value="item.value">{{
item.label
}}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon><SearchOutlined /></template>
查询
</a-button>
<a-button @click="reset">
<template #icon><redo-outlined /></template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
bordered
:alert="options.alert.show"
:tool-config="toolConfig"
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<a-space>
<a-button
type="primary"
@click="formRef.onOpen(undefined, searchFormState.orgId)"
v-if="hasPerm('bizUserAdd')"
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="所属机构" name="orgId">
<a-tree-select
v-model:value="searchFormState.orgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择所属机构"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入姓名或关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="userStatus" label="人员状态">
<a-select
v-model:value="searchFormState.userStatus"
placeholder="请选择人员状态"
:getPopupContainer="(trigger) => trigger.parentNode"
>
<template #icon><plus-outlined /></template>
<span>增加</span>
</a-button>
<a-button @click="exportBatchUserVerify" v-if="hasPerm('bizUserBatchExport')">
<template #icon><export-outlined /></template>
批量导出
</a-button>
<xn-batch-button
v-if="hasPerm('bizUserBatchDelete')"
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchUser"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'avatar'">
<a-avatar :src="record.avatar" style="margin-bottom: -5px; margin-top: -5px" />
</template>
<template v-if="column.dataIndex === 'gender'">
{{ $TOOL.dictTypeData('GENDER', record.gender) }}
</template>
<template v-if="column.dataIndex === 'userStatus'">
<a-switch
:loading="loading"
:checked="record.userStatus === 'ENABLE'"
@change="editStatus(record)"
v-if="hasPerm('bizUserUpdataStatus')"
/>
<span v-else>{{ $TOOL.dictTypeData('COMMON_STATUS', record.userStatus) }}</span>
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)" v-if="hasPerm('bizUserEdit')">编辑</a>
<a-divider type="vertical" v-if="hasPerm(['bizUserEdit', 'bizUserDelete'], 'and')" />
<a-popconfirm title="确定要删除吗" @confirm="removeUser(record)">
<a-button type="link" danger size="small" v-if="hasPerm('bizUserDelete')">
删除
<a-select-option v-for="item in statusData" :key="item.value" :value="item.value">{{
item.label
}}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon><SearchOutlined /></template>
查询
</a-button>
</a-popconfirm>
<a-divider
type="vertical"
v-if="hasPerm(['bizUserGrantRole', 'bizUserPwdReset', 'bizUserExportUserInfo'])"
/>
<a-dropdown v-if="hasPerm(['bizUserGrantRole', 'bizUserPwdReset', 'bizUserExportUserInfo'])">
<a class="ant-dropdown-link">
更多
<DownOutlined />
</a>
<template #overlay>
<a-menu>
<a-menu-item v-if="hasPerm('bizUserPwdReset')">
<a-popconfirm
title="确定要重置吗"
placement="topRight"
@confirm="resetPassword(record)"
>
<a>重置密码</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item v-if="hasPerm('bizUserGrantRole')">
<a @click="selectRole(record)">授权角色</a>
</a-menu-item>
<a-menu-item v-if="hasPerm('bizUserExportUserInfo')">
<a @click="exportUserInfo(record)">导出信息</a>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
<a-button @click="reset">
<template #icon><redo-outlined /></template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
bordered
:alert="options.alert.show"
:tool-config="toolConfig"
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator>
<a-space>
<a-button
type="primary"
@click="formRef.onOpen(undefined, searchFormState.orgId)"
v-if="hasPerm('bizUserAdd')"
>
<template #icon><plus-outlined /></template>
<span>增加</span>
</a-button>
<a-button @click="exportBatchUserVerify" v-if="hasPerm('bizUserBatchExport')">
<template #icon><export-outlined /></template>
批量导出
</a-button>
<xn-batch-button
v-if="hasPerm('bizUserBatchDelete')"
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchUser"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'avatar'">
<a-avatar :src="record.avatar" style="margin-bottom: -5px; margin-top: -5px" />
</template>
</s-table>
</a-card>
</a-col>
</a-row>
<template v-if="column.dataIndex === 'gender'">
{{ $TOOL.dictTypeData('GENDER', record.gender) }}
</template>
<template v-if="column.dataIndex === 'userStatus'">
<a-switch
:loading="loading"
:checked="record.userStatus === 'ENABLE'"
@change="editStatus(record)"
v-if="hasPerm('bizUserUpdataStatus')"
/>
<span v-else>{{ $TOOL.dictTypeData('COMMON_STATUS', record.userStatus) }}</span>
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)" v-if="hasPerm('bizUserEdit')">编辑</a>
<a-divider type="vertical" v-if="hasPerm(['bizUserEdit', 'bizUserDelete'], 'and')" />
<a-popconfirm title="确定要删除吗" @confirm="removeUser(record)">
<a-button type="link" danger size="small" v-if="hasPerm('bizUserDelete')"> 删除 </a-button>
</a-popconfirm>
<a-divider
type="vertical"
v-if="hasPerm(['bizUserGrantRole', 'bizUserPwdReset', 'bizUserExportUserInfo'])"
/>
<a-dropdown v-if="hasPerm(['bizUserGrantRole', 'bizUserPwdReset', 'bizUserExportUserInfo'])">
<a class="ant-dropdown-link">
更多
<DownOutlined />
</a>
<template #overlay>
<a-menu>
<a-menu-item v-if="hasPerm('bizUserPwdReset')">
<a-popconfirm title="确定要重置吗" placement="topRight" @confirm="resetPassword(record)">
<a>重置密码</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item v-if="hasPerm('bizUserGrantRole')">
<a @click="selectRole(record)">授权角色</a>
</a-menu-item>
<a-menu-item v-if="hasPerm('bizUserExportUserInfo')">
<a @click="exportUserInfo(record)">导出信息</a>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
</template>
</s-table>
</template>
</XnResizablePanel>
<Form ref="formRef" @successful="tableRef.refresh()" />
<xn-role-selector
ref="RoleSelectorPlusRef"
@@ -248,7 +233,6 @@
const RoleSelectorPlusRef = ref()
const selectedRecord = ref({})
const loading = ref(false)
const cardLoading = ref(true)
// 表格查询 返回 Promise 对象
const loadData = (parameter) => {
return bizUserApi.userPage(Object.assign(parameter, searchFormState.value)).then((res) => {
@@ -261,32 +245,26 @@
tableRef.value.refresh(true)
}
// 左侧树查询
bizOrgApi
.orgTree()
.then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
bizOrgApi.orgTree().then((res) => {
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
})
}
}
})
}
})
.finally(() => {
cardLoading.value = false
})
}
})
// 列表选择配置
const options = {
alert: {
@@ -432,7 +410,3 @@
}
}
</script>
<style scoped>
</style>

View File

@@ -34,7 +34,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="clientUserFormRef.onOpen()">
<template #icon><plus-outlined /></template>

View File

@@ -9,7 +9,7 @@
:tool-config="toolConfig"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()">
<template #icon>

View File

@@ -11,7 +11,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" size="small" @click="formRef.onOpen()">
<template #icon><plus-outlined /></template>

View File

@@ -23,7 +23,7 @@
}"
selectable="false"
treeLine
></a-tree-select>
/>
</a-form-item>
<a-form-item label="字典名称:" name="dictLabel">
<a-input v-model:value="formData.dictLabel" placeholder="请输入字典名称" allow-clear />
@@ -69,9 +69,25 @@
const treeData = ref([])
// 默认展开的节点(顶级)
const defaultExpandedKeys = ref([0])
// 定义字典颜色
const dictColorList = ['default','pink', 'red', 'orange', 'green', 'cyan', 'blue', 'purple','gold','geekblue','volcano','magenta','processing','success','error','warning']
const dictColorList = [
'default',
'pink',
'red',
'orange',
'green',
'cyan',
'blue',
'purple',
'gold',
'geekblue',
'volcano',
'magenta',
'processing',
'success',
'error',
'warning'
]
// 打开抽屉
const onOpen = (record, type, parentId) => {

View File

@@ -1,104 +1,97 @@
<template>
<a-row :gutter="10">
<a-col :xs="0" :sm="0" :md="0" :lg="4" :xl="4">
<a-card :bordered="false" :loading="cardLoading" class="left-tree-container">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
>
</a-tree>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</a-card>
</a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="20" :xl="20">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="请选择上级字典:" name="parentId">
<a-tree-select
v-model:value="searchFormState.parentId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择上级字典"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入字典名称关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
</template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="请选择上级字典:" name="parentId">
<a-tree-select
v-model:value="searchFormState.parentId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择上级字典"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入字典名称关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined />
</template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
bordered
:tool-config="toolConfig"
:row-key="(record) => record.id"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<a-button type="primary" @click="formRef.onOpen(undefined, categoryType, searchFormState.parentId)">
<template #icon><plus-outlined /></template>
新增
</a-button>
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
bordered
:tool-config="toolConfig"
:row-key="(record) => record.id"
:scroll="{ x: 'max-content' }"
>
<template #operator>
<a-button type="primary" @click="formRef.onOpen(undefined, categoryType, searchFormState.parentId)">
<template #icon><plus-outlined /></template>
新增
</a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'level'">
<a-tag color="blue" v-if="record.level">{{ record.level }}</a-tag>
<a-tag color="green" v-else>子级</a-tag>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'level'">
<a-tag color="blue" v-if="record.level">{{ record.level }}</a-tag>
<a-tag color="green" v-else>子级</a-tag>
</template>
<template v-if="column.dataIndex === 'dictLabel'">
<a-tag :color="record.dictColor">{{ record.dictLabel }}</a-tag>
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record, categoryType)">编辑</a>
<a-divider type="vertical" />
<a-popconfirm title="删除此字典与下级字典吗" @confirm="remove(record)">
<a-button type="link" danger size="small">删除</a-button>
</a-popconfirm>
</template>
<template v-if="column.dataIndex === 'dictLabel'">
<a-tag :color="record.dictColor">{{ record.dictLabel }}</a-tag>
</template>
</s-table>
</a-card>
</a-col>
</a-row>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record, categoryType)">编辑</a>
<a-divider type="vertical" />
<a-popconfirm title="删除此字典与下级字典吗" @confirm="remove(record)">
<a-button type="link" danger size="small">删除</a-button>
</a-popconfirm>
</template>
</template>
</s-table>
</template>
</XnResizablePanel>
<Form ref="formRef" @successful="formSuccessful()" />
</template>
@@ -139,7 +132,6 @@
// 定义tableDOM
const tableRef = ref(null)
const formRef = ref()
const cardLoading = ref(true)
const searchFormRef = ref()
const searchFormState = ref({})
// 默认展开的节点
@@ -186,12 +178,10 @@
const param = {
category: categoryType.value
}
dictApi.dictTree(param).then((res) => {
if (res) {
treeData.value = res
dictApi.dictTree(param).then((data) => {
if (data) {
treeData.value = data
}
}).finally(() => {
cardLoading.value = false
})
}
// 点击树查询
@@ -237,5 +227,11 @@
</script>
<style scoped lang="less">
// 覆盖 XnResizablePanel 内部两侧面板的内边距
:deep(.panel-left) {
padding: 0 !important;
}
:deep(.panel-right) {
padding: 0 !important;
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<a-card>
<a-card :bordered="false">
<a-tabs size="large" v-model:activeKey="activeKey">
<a-tab-pane v-for="item in tabListNoTitle" :key="item.key" :tab="item.tab">
<category :type="item.key" />

View File

@@ -1,5 +1,5 @@
<template>
<a-card :bordered="false" class="xn-mb10">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
@@ -23,13 +23,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -38,8 +38,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
@@ -51,7 +49,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()">
<template #icon><plus-outlined /></template>
@@ -180,6 +178,3 @@
})
}
</script>
<style scoped>
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div v-if="indexShow">
<a-card :bordered="false" class="xn-mb10">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
@@ -23,13 +23,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -38,8 +38,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
@@ -51,7 +49,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="() => uploadFormRef.openUpload()">
<UploadOutlined />

View File

@@ -1,5 +1,5 @@
<template>
<a-card :bordered="false" :body-style="{ 'padding-bottom': '0px' }" class="mb-2">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="6" :md="6" :lg="6" :xl="6">
@@ -32,13 +32,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -47,8 +47,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
@@ -60,7 +58,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()">
<template #icon><plus-outlined /></template>

View File

@@ -1,5 +1,5 @@
<template>
<a-row :gutter="10">
<a-row :gutter="[10, 10]">
<a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<a-card :bordered="false" title="周统计">
<columnChart />
@@ -11,12 +11,19 @@
</a-card>
</a-col>
</a-row>
<a-card :bordered="false">
<s-table ref="tableRef" :columns="columns" :data="loadData" bordered :row-key="(record) => record.id" :scroll="{ x: 'max-content' }">
<template #operator class="table-operator">
<a-card :bordered="false" class="mt-2">
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
bordered
:row-key="(record) => record.id"
:scroll="{ x: 'max-content' }"
>
<template #operator>
<a-form ref="formRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-col :xs="24" :sm="16" :md="4" :lg="4" :xl="4">
<a-form-item>
<a-radio-group v-model:value="opLogType" button-style="solid">
<a-radio-button
@@ -30,7 +37,7 @@
</a-radio-group>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-col :xs="24" :sm="16" :md="6" :lg="6" :xl="6">
<a-form-item>
<a-space>
<a-input-search

View File

@@ -1,5 +1,5 @@
<template>
<a-row :gutter="10">
<a-row :gutter="[10, 10]">
<a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<a-card :bordered="false" title="周统计">
<lineChart ref="lineChartRef" />
@@ -11,13 +11,19 @@
</a-card>
</a-col>
</a-row>
<a-card :bordered="false">
<s-table ref="tableRef" :columns="columns" :data="loadData" bordered :row-key="(record) => record.id" :scroll="{ x: 'max-content' }">
<template #operator class="table-operator">
<a-card :bordered="false" class="mt-2">
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
bordered
:row-key="(record) => record.id"
:scroll="{ x: 'max-content' }"
>
<template #operator>
<a-form ref="formRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-col :xs="24" :sm="16" :md="4" :lg="4" :xl="4">
<a-form-item>
<a-radio-group v-model:value="visLogType" button-style="solid">
<a-radio-button
@@ -31,7 +37,7 @@
</a-radio-group>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-col :xs="24" :sm="16" :md="6" :lg="6" :xl="6">
<a-form-item>
<a-space>
<a-input-search
@@ -39,7 +45,8 @@
placeholder="请输入名称关键词"
enter-button
allowClear
@search="onSearch"/>
@search="onSearch"
/>
<a-popconfirm title="确定清空登录登出日志吗" @confirm="deleteBatchVisLog()">
<a-button danger>清空</a-button>
</a-popconfirm>

View File

@@ -1,5 +1,5 @@
<template>
<a-card :bordered="false" class="xn-mb10">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
@@ -12,13 +12,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -27,8 +27,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
@@ -40,7 +38,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()"> 发送站内信 </a-button>
<xn-batch-button
@@ -146,7 +144,3 @@
})
}
</script>
<style lang="less" scoped>
</style>

View File

@@ -1,5 +1,5 @@
<template>
<a-card :bordered="false" class="xn-mb10">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
@@ -23,13 +23,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -38,8 +38,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
@@ -51,7 +49,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()">
<template #icon><plus-outlined /></template>
@@ -173,7 +171,3 @@
})
}
</script>
<style lang="less" scoped>
</style>

View File

@@ -22,13 +22,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -75,7 +75,7 @@
</template>
</a-table>
</template>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()">
<template #icon><plus-outlined /></template>

View File

@@ -1,5 +1,5 @@
<template>
<a-card :bordered="false" class="xn-mb10">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
@@ -23,13 +23,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -38,8 +38,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
@@ -51,7 +49,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()">
<template #icon><plus-outlined /></template>
@@ -178,7 +176,3 @@
})
}
</script>
<style scoped>
</style>

View File

@@ -182,6 +182,8 @@
<script setup name="genBasic">
import { required } from '@/utils/formRules'
import genBasicApi from '@/api/gen/genBasicApi'
// 声明组件自定义事件
const emit = defineEmits(['successful'])
const formRef = ref()
// 表单数据
const formData = ref({})
@@ -437,6 +439,8 @@
genBasicApi
.submitForm(formData.value, formData.value.id)
.then((data) => {
// 提交成功后触发成功事件,供父组件监听
emit('successful', data)
resolve(data)
})
.finally(() => {
@@ -455,9 +459,6 @@
})
</script>
<style scoped>
.childAddButton {
margin-bottom: 10px;
}
.form-row {
background-color: var(--item-hover-bg);
margin-left: 0px !important;
@@ -467,7 +468,4 @@
padding-top: 5px;
padding-left: 15px;
}
.form-div {
padding-top: 10px;
}
</style>

View File

@@ -12,7 +12,7 @@
:toolConfig="{ refresh: true, height: true, columnSetting: true, striped: false }"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="openConfig()">
<template #icon><plus-outlined /></template>
@@ -60,7 +60,6 @@
import Steps from './steps.vue'
import GenPreview from './preview.vue'
import genBasicApi from '@/api/gen/genBasicApi'
const tableRef = ref()
const indexShow = ref(true)
const stepsRef = ref()

View File

@@ -1,13 +1,14 @@
<template>
<a-card :bordered="false" class="mb-2">
<div class="steps-card mb-2">
<a-row :gutter="10">
<a-col :xs="0" :sm="0" :md="6" :lg="6" :xl="6"></a-col>
<a-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
<a-steps :current="current">
<a-step v-for="item in steps" :key="item.title" :title="item.title" />
</a-steps>
</a-col>
<a-col :xs="8" :sm="8" :md="8" :lg="8" :xl="8" :offset="4">
<a-space>
<a-col :xs="12" :sm="12" :md="6" :lg="6" :xl="6">
<a-space class="xn-fdr">
<a-form>
<a-row :gutter="10">
<a-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
@@ -17,21 +18,24 @@
</a-col>
<a-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-button :disabled="current === 2" type="primary" @click="next"> &nbsp;&nbsp;&nbsp;&nbsp; </a-button>
<a-button :disabled="current === 2" type="primary" @click="next">
&nbsp;&nbsp;&nbsp;&nbsp;
</a-button>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-button type="primary" danger ghost @click="emit('closed')"> &nbsp;&nbsp;&nbsp;&nbsp; </a-button>
<a-button type="primary" danger ghost @click="emit('closed')">
&nbsp;&nbsp;&nbsp;&nbsp;
</a-button>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-space>
</a-col>
</a-row>
</a-card>
</div>
<div v-if="current === 0">
<basic ref="basicRef" />
@@ -45,11 +49,7 @@
<template #extra>
<a-space size="middle">
<a-button v-if="current > 0" @click="genPreviewRef.onOpen(recordData)">预览</a-button>
<a-button
v-if="current === steps.length - 1"
type="primary"
:loading="submitLoading"
@click="seveGenerate"
<a-button v-if="current === steps.length - 1" type="primary" :loading="submitLoading" @click="seveGenerate"
>生成并关闭</a-button
>
</a-space>
@@ -67,7 +67,7 @@
import genPreview from './preview.vue'
import genBasicApi from '@/api/gen/genBasicApi'
const emit = defineEmits({ closed: null })
const emit = defineEmits({ closed: null, successful: null })
const current = ref(0)
const recordData = ref()
const submitLoading = ref(false)
@@ -95,17 +95,19 @@
.catch(() => {})
current.value--
}
if (current.value === 2) {
configRef.value
.onSubmit(recordData.value)
.then((data) => {
current.value++
})
.catch((err) => {
message.warning(err)
})
current.value--
}
if (current.value === 2) {
configRef.value
.onSubmit(recordData.value)
.then((data) => {
// 配置保存成功后,通知父组件刷新列表
emit('successful', data)
current.value++
})
.catch((err) => {
message.warning(err)
})
current.value--
}
}
// 上一步
const prev = () => {
@@ -160,5 +162,10 @@
})
</script>
<style scoped>
.steps-card {
padding-top: 24px;
padding-left: 24px;
padding-right: 24px;
background: var(--snowy-background-color);
}
</style>

View File

@@ -15,7 +15,7 @@
:row-key="(record) => record.id"
:tool-config="toolConfig"
>
<template #operator class="table-operator">
<template #operator>
<a-button type="primary" @click="buttonForm.onOpen(recordData)">
<template #icon>
<plus-outlined />

View File

@@ -5,10 +5,12 @@
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-form-item>
<a-radio-group v-model:value="module" button-style="solid">
<a-radio-button v-for="module in moduleList"
:key="module.id"
:value="module.id"
@click="moduleClick(module.id)">
<a-radio-button
v-for="module in moduleList"
:key="module.id"
:value="module.id"
@click="moduleClick(module.id)"
>
<component :is="module.icon" />
{{ module.title }}
</a-radio-button>
@@ -28,8 +30,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false" class="mt-2">
<s-table
ref="tableRef"
:columns="columns"
@@ -42,7 +42,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen(undefined, module)">
<template #icon><plus-outlined /></template>

View File

@@ -1,5 +1,5 @@
<template>
<a-card :bordered="false" :body-style="{ 'padding-bottom': '0px' }" class="mb-2">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
@@ -12,13 +12,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -27,8 +27,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
@@ -40,7 +38,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()">
<template #icon>

View File

@@ -1,10 +1,10 @@
<template>
<a-card :bordered="false" class="xn-mb10">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item label="关键词" name="name">
<a-input v-model:value="searchFormState.name" placeholder="请输入名称关键词"/>
<a-input v-model:value="searchFormState.name" placeholder="请输入名称关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
@@ -12,13 +12,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -27,8 +27,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
@@ -40,11 +38,11 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()">
<template #icon>
<plus-outlined/>
<plus-outlined />
</template>
新增
</a-button>
@@ -61,9 +59,9 @@
<template v-if="column.dataIndex === 'action'">
<a-space>
<a @click="formRef.onOpen(record)">编辑</a>
<a-divider type="vertical"/>
<a-divider type="vertical" />
<a @click="openGroupUserSelector(record)">授权用户</a>
<a-divider type="vertical"/>
<a-divider type="vertical" />
<a-popconfirm title="确定要删除吗" @confirm="deleteSysGroup(record)">
<a-button type="link" danger size="small">删除</a-button>
</a-popconfirm>
@@ -72,7 +70,7 @@
</template>
</s-table>
</a-card>
<Form ref="formRef" @successful="tableRef.refresh()"/>
<Form ref="formRef" @successful="tableRef.refresh()" />
<xn-user-selector
ref="userSelectorRef"
:org-tree-api="selectorApiFunction.orgTreeApi"
@@ -84,116 +82,115 @@
</template>
<script setup name="sysGroupIndex">
import {cloneDeep} from 'lodash-es'
import Form from './form.vue'
import sysGroupApi from '@/api/sys/groupApi'
import { cloneDeep } from 'lodash-es'
import Form from './form.vue'
import sysGroupApi from '@/api/sys/groupApi'
const searchFormState = ref({})
const searchFormRef = ref()
const tableRef = ref()
const formRef = ref()
const toolConfig = {refresh: true, height: true, columnSetting: true, striped: false}
const recordCacheData = ref()
const userSelectorRef = ref()
const columns = [
{
title: '名称',
dataIndex: 'name'
},
{
title: '备注',
dataIndex: 'remark'
},
{
title: '排序码',
dataIndex: 'sortCode'
},
{
title: '创建时间',
dataIndex: 'createTime'
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
fixed: 'right'
}
]
const selectedRowKeys = ref([])
// 列表选择配置
const options = {
alert: {
show: false,
clear: () => {
selectedRowKeys.value = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
}
}
}
const loadData = (parameter) => {
const searchFormParam = cloneDeep(searchFormState.value)
return sysGroupApi.groupPage(Object.assign(parameter, searchFormParam)).then((data) => {
return data
})
}
// 重置
const reset = () => {
searchFormRef.value.resetFields()
tableRef.value.refresh(true)
}
// 删除
const deleteSysGroup = (record) => {
let params = [
const searchFormState = ref({})
const searchFormRef = ref()
const tableRef = ref()
const formRef = ref()
const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
const recordCacheData = ref()
const userSelectorRef = ref()
const columns = [
{
id: record.id
title: '名称',
dataIndex: 'name'
},
{
title: '备注',
dataIndex: 'remark'
},
{
title: '排序码',
dataIndex: 'sortCode'
},
{
title: '创建时间',
dataIndex: 'createTime'
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
fixed: 'right'
}
]
sysGroupApi.groupDelete(params).then(() => {
const selectedRowKeys = ref([])
// 列表选择配置
const options = {
alert: {
show: false,
clear: () => {
selectedRowKeys.value = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
}
}
}
const loadData = (parameter) => {
const searchFormParam = cloneDeep(searchFormState.value)
return sysGroupApi.groupPage(Object.assign(parameter, searchFormParam)).then((data) => {
return data
})
}
// 重置
const reset = () => {
searchFormRef.value.resetFields()
tableRef.value.refresh(true)
})
}
// 批量删除
const deleteBatchSysGroup = (params) => {
sysGroupApi.groupDelete(params).then(() => {
tableRef.value.clearRefreshSelected()
})
}
// 打开用户选择器
const openGroupUserSelector = (record) => {
// 打开人员选择器的时候,缓存一个记录数据
recordCacheData.value = record
// 查询接口,查到这个角色是多少个用户都有它
const param = {
id: record.id
}
sysGroupApi.groupOwnUser(param).then((data) => {
userSelectorRef.value.showUserPlusModal(data)
})
}
// 人员选择器回调
const userCallBack = (value) => {
const param = {
id: recordCacheData.value.id,
grantInfoList: value
}
sysGroupApi.groupGrantUser(param).then(() => {
})
}
// 传递设计器需要的API
const selectorApiFunction = {
orgTreeApi: (param) => {
return sysGroupApi.groupOrgTreeSelector(param).then((data) => {
return Promise.resolve(data)
})
},
userPageApi: (param) => {
return sysGroupApi.groupUserSelector(param).then((data) => {
return Promise.resolve(data)
// 删除
const deleteSysGroup = (record) => {
let params = [
{
id: record.id
}
]
sysGroupApi.groupDelete(params).then(() => {
tableRef.value.refresh(true)
})
}
}
// 批量删除
const deleteBatchSysGroup = (params) => {
sysGroupApi.groupDelete(params).then(() => {
tableRef.value.clearRefreshSelected()
})
}
// 打开用户选择器
const openGroupUserSelector = (record) => {
// 打开人员选择器的时候,缓存一个记录数据
recordCacheData.value = record
// 查询接口,查到这个角色是多少个用户都有它
const param = {
id: record.id
}
sysGroupApi.groupOwnUser(param).then((data) => {
userSelectorRef.value.showUserPlusModal(data)
})
}
// 人员选择器回调
const userCallBack = (value) => {
const param = {
id: recordCacheData.value.id,
grantInfoList: value
}
sysGroupApi.groupGrantUser(param).then(() => {})
}
// 传递设计器需要的API
const selectorApiFunction = {
orgTreeApi: (param) => {
return sysGroupApi.groupOrgTreeSelector(param).then((data) => {
return Promise.resolve(data)
})
},
userPageApi: (param) => {
return sysGroupApi.groupUserSelector(param).then((data) => {
return Promise.resolve(data)
})
}
}
</script>

View File

@@ -1,231 +1,219 @@
<template>
<a-row :gutter="10">
<a-col :xs="0" :sm="0" :md="0" :lg="4" :xl="4">
<a-card :bordered="false" :loading="cardLoading" class="left-tree-container">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE"/>
</a-card>
</a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="20" :xl="20">
<a-card :bordered="false" class="xn-mb10">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="上级组织:" name="parentId">
<a-tree-select
v-model:value="searchFormState.parentId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择上级组织"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="名称">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入名称关键词"/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
</template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<a-space>
<a-button type="primary" @click="formRef.onOpen(undefined, searchFormState.parentId)">
<template #icon>
<plus-outlined/>
</template>
新增
</a-button>
<xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchOrg"
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="上级组织:" name="parentId">
<a-tree-select
v-model:value="searchFormState.parentId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择上级组织"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-space>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="名称">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入名称关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined />
</template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen(undefined, searchFormState.parentId)">
<template #icon>
<plus-outlined />
</template>
新增
</a-button>
<xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchOrg"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('ORG_CATEGORY', record.category) }}
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('ORG_CATEGORY', record.category) }}
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)">编辑</a>
<a-divider type="vertical"/>
<a-popconfirm title="删除此组织与下级组织吗" @confirm="removeOrg(record)">
<a-button type="link" danger size="small">删除</a-button>
</a-popconfirm>
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)">编辑</a>
<a-divider type="vertical" />
<a-popconfirm title="删除此组织与下级组织吗" @confirm="removeOrg(record)">
<a-button type="link" danger size="small">删除</a-button>
</a-popconfirm>
</template>
</s-table>
</a-card>
</a-col>
</a-row>
<Form ref="formRef" @successful="tableRef.refresh()"/>
</template>
</s-table>
</template>
</XnResizablePanel>
<Form ref="formRef" @successful="tableRef.refresh()" />
</template>
<script setup name="sysOrg">
import {Empty} from 'ant-design-vue'
import {isEmpty} from 'lodash-es'
import orgApi from '@/api/sys/orgApi'
import Form from './form.vue'
import { Empty } from 'ant-design-vue'
import { isEmpty } from 'lodash-es'
import orgApi from '@/api/sys/orgApi'
import Form from './form.vue'
const columns = [
{
title: '组织名称',
dataIndex: 'name'
},
{
title: '分类',
dataIndex: 'category'
},
{
title: '排序',
dataIndex: 'sortCode'
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
fixed: 'right'
}
]
const selectedRowKeys = ref([])
// 列表选择配置
const options = {
alert: {
show: false,
clear: () => {
selectedRowKeys.value = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
}
}
}
// 定义tableDOM
const tableRef = ref(null)
const formRef = ref()
const searchFormRef = ref()
const searchFormState = ref({})
// 默认展开的节点
const defaultExpandedKeys = ref([])
const treeData = ref([])
// 替换treeNode 中 title,key,children
const treeFieldNames = {children: 'children', title: 'name', key: 'id'}
const cardLoading = ref(true)
// 表格查询 返回 Promise 对象
const loadData = (parameter) => {
loadTreeData()
return orgApi.orgPage(Object.assign(parameter, searchFormState.value)).then((res) => {
return res
})
}
// 重置
const reset = () => {
searchFormRef.value.resetFields()
tableRef.value.refresh(true)
}
// 加载左侧的树
const loadTreeData = () => {
orgApi.orgTree().then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
}
})
}
}
})
}
// 点击树查询
const treeSelect = (selectedKeys) => {
if (selectedKeys.length > 0) {
searchFormState.value.parentId = selectedKeys.toString()
} else {
delete searchFormState.value.parentId
}
tableRef.value.refresh(true)
}
// 删除
const removeOrg = (record) => {
let params = [
const columns = [
{
id: record.id
title: '组织名称',
dataIndex: 'name'
},
{
title: '分类',
dataIndex: 'category'
},
{
title: '排序',
dataIndex: 'sortCode'
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
fixed: 'right'
}
]
orgApi.orgDelete(params).then(() => {
const selectedRowKeys = ref([])
// 列表选择配置
const options = {
alert: {
show: false,
clear: () => {
selectedRowKeys.value = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
}
}
}
// 定义tableDOM
const tableRef = ref(null)
const formRef = ref()
const searchFormRef = ref()
const searchFormState = ref({})
// 默认展开的节点
const defaultExpandedKeys = ref([])
const treeData = ref([])
// 替换treeNode 中 title,key,children
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
// 表格查询 返回 Promise 对象
const loadData = (parameter) => {
loadTreeData()
return orgApi.orgPage(Object.assign(parameter, searchFormState.value)).then((res) => {
return res
})
}
// 重置
const reset = () => {
searchFormRef.value.resetFields()
tableRef.value.refresh(true)
})
}
// 批量删除
const deleteBatchOrg = (params) => {
orgApi.orgDelete(params).then(() => {
tableRef.value.clearRefreshSelected()
})
}
}
// 加载左侧的树
const loadTreeData = () => {
orgApi.orgTree().then((res) => {
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
}
})
}
}
})
}
// 点击树查询
const treeSelect = (selectedKeys) => {
if (selectedKeys.length > 0) {
searchFormState.value.parentId = selectedKeys.toString()
} else {
delete searchFormState.value.parentId
}
tableRef.value.refresh(true)
}
// 删除
const removeOrg = (record) => {
let params = [
{
id: record.id
}
]
orgApi.orgDelete(params).then(() => {
tableRef.value.refresh(true)
})
}
// 批量删除
const deleteBatchOrg = (params) => {
orgApi.orgDelete(params).then(() => {
tableRef.value.clearRefreshSelected()
})
}
</script>
<style scoped>
</style>

View File

@@ -1,229 +1,217 @@
<template>
<a-row :gutter="10">
<a-col :xs="0" :sm="0" :md="0" :lg="4" :xl="4">
<a-card :bordered="false" :loading="cardLoading" class="left-tree-container">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE"/>
</a-card>
</a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="20" :xl="20">
<a-card :bordered="false" class="xn-mb10">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="组织:" name="orgId">
<a-tree-select
v-model:value="searchFormState.orgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择组织"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入职位名称关键词"/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
</template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<a-space>
<a-button type="primary" @click="formRef.onOpen(undefined, searchFormState.orgId)">
<template #icon>
<plus-outlined/>
</template>
新增
</a-button>
<xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchPosition"
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="组织:" name="orgId">
<a-tree-select
v-model:value="searchFormState.orgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择组织"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-space>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入职位名称关键词" />
</a-form-item>
</a-col>
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined />
</template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen(undefined, searchFormState.orgId)">
<template #icon>
<plus-outlined />
</template>
新增
</a-button>
<xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchPosition"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('POSITION_CATEGORY', record.category) }}
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('POSITION_CATEGORY', record.category) }}
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)">编辑</a>
<a-divider type="vertical"/>
<a-popconfirm title="确定删除此职位" @confirm="removeOrg(record)">
<a-button type="link" danger size="small">删除</a-button>
</a-popconfirm>
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)">编辑</a>
<a-divider type="vertical" />
<a-popconfirm title="确定删除此职位" @confirm="removeOrg(record)">
<a-button type="link" danger size="small">删除</a-button>
</a-popconfirm>
</template>
</s-table>
</a-card>
</a-col>
</a-row>
<Form ref="formRef" @successful="tableRef.refresh(true)"/>
</template>
</s-table>
</template>
</XnResizablePanel>
<Form ref="formRef" @successful="tableRef.refresh(true)" />
</template>
<script setup name="sysPosition">
import {Empty} from 'ant-design-vue'
import {isEmpty} from 'lodash-es'
import positionApi from '@/api/sys/positionApi'
import orgApi from '@/api/sys/orgApi'
import Form from './form.vue'
import { Empty } from 'ant-design-vue'
import { isEmpty } from 'lodash-es'
import positionApi from '@/api/sys/positionApi'
import orgApi from '@/api/sys/orgApi'
import Form from './form.vue'
const columns = [
{
title: '职位名称',
dataIndex: 'name'
},
{
title: '分类',
dataIndex: 'category'
},
{
title: '排序',
dataIndex: 'sortCode'
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
fixed: 'right'
}
]
const selectedRowKeys = ref([])
// 列表选择配置
const options = {
alert: {
show: false,
clear: () => {
selectedRowKeys.value = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
}
}
}
// 定义tableDOM
const tableRef = ref(null)
const formRef = ref()
const searchFormRef = ref()
const searchFormState = ref({})
// 默认展开的节点
const defaultExpandedKeys = ref([])
const treeData = ref([])
// 替换treeNode 中 title,key,children
const treeFieldNames = {children: 'children', title: 'name', key: 'id'}
const cardLoading = ref(true)
// 表格查询 返回 Promise 对象
const loadData = (parameter) => {
return positionApi.positionPage(Object.assign(parameter, searchFormState.value)).then((res) => {
return res
})
}
// 重置
const reset = () => {
searchFormRef.value.resetFields()
tableRef.value.refresh(true)
}
// 加载左侧的树
orgApi.orgTree().then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
}
})
}
}
})
// 点击树查询
const treeSelect = (selectedKeys) => {
if (selectedKeys.length > 0) {
searchFormState.value.orgId = selectedKeys.toString()
} else {
delete searchFormState.value.orgId
}
tableRef.value.refresh(true)
}
// 删除
const removeOrg = (record) => {
let params = [
const columns = [
{
id: record.id
title: '职位名称',
dataIndex: 'name'
},
{
title: '分类',
dataIndex: 'category'
},
{
title: '排序',
dataIndex: 'sortCode'
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
fixed: 'right'
}
]
positionApi.positionDelete(params).then(() => {
const selectedRowKeys = ref([])
// 列表选择配置
const options = {
alert: {
show: false,
clear: () => {
selectedRowKeys.value = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
}
}
}
// 定义tableDOM
const tableRef = ref(null)
const formRef = ref()
const searchFormRef = ref()
const searchFormState = ref({})
// 默认展开的节点
const defaultExpandedKeys = ref([])
const treeData = ref([])
// 替换treeNode 中 title,key,children
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
// 表格查询 返回 Promise 对象
const loadData = (parameter) => {
return positionApi.positionPage(Object.assign(parameter, searchFormState.value)).then((res) => {
return res
})
}
// 重置
const reset = () => {
searchFormRef.value.resetFields()
tableRef.value.refresh(true)
}
// 加载左侧的树
orgApi.orgTree().then((res) => {
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
}
})
}
}
})
}
// 批量删除
const deleteBatchPosition = (params) => {
positionApi.positionDelete(params).then(() => {
tableRef.value.clearRefreshSelected()
})
}
// 点击树查询
const treeSelect = (selectedKeys) => {
if (selectedKeys.length > 0) {
searchFormState.value.orgId = selectedKeys.toString()
} else {
delete searchFormState.value.orgId
}
tableRef.value.refresh(true)
}
// 删除
const removeOrg = (record) => {
let params = [
{
id: record.id
}
]
positionApi.positionDelete(params).then(() => {
tableRef.value.refresh(true)
})
}
// 批量删除
const deleteBatchPosition = (params) => {
positionApi.positionDelete(params).then(() => {
tableRef.value.clearRefreshSelected()
})
}
</script>
<style scoped>
</style>

View File

@@ -8,7 +8,7 @@
:row-key="(record) => record.id"
:tool-config="toolConfig"
>
<template #operator class="table-operator">
<template #operator>
<a-button type="primary" @click="buttonForm.onOpen(recordData)">
<template #icon>
<plus-outlined />

View File

@@ -8,7 +8,7 @@
:row-key="(record) => record.id"
:tool-config="toolConfig"
>
<template #operator class="table-operator">
<template #operator>
<a-button type="primary" @click="fieldForm.onOpen(recordData)">
<template #icon>
<plus-outlined />

View File

@@ -35,11 +35,7 @@
allow-clear
tree-default-expand-all
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'title',
value: 'id'
}"
:field-names="treeFieldNames"
selectable="false"
tree-line
@change="parentChange(formData.parentId)"
@@ -159,6 +155,7 @@
// 默认展开的节点(顶级)
const defaultExpandedKeys = ref([0])
const submitLoading = ref(false)
const treeFieldNames = { children: 'children', label: 'title', value: 'id' }
// 模块ID
const moduleId = ref('')
// 打开抽屉

View File

@@ -5,10 +5,12 @@
<a-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<a-form-item>
<a-radio-group v-model:value="moduleType" button-style="solid">
<a-radio-button v-for="module in moduleTypeList"
:key="module.id"
:value="module.id"
@click="moduleClick(module.id)">
<a-radio-button
v-for="module in moduleTypeList"
:key="module.id"
:value="module.id"
@click="moduleClick(module.id)"
>
<component :is="module.icon" />
{{ module.title }}
</a-radio-button>
@@ -28,8 +30,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false" class="mt-2">
<s-table
ref="tableRef"
:columns="columns"
@@ -42,7 +42,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen(undefined, moduleType)">
<template #icon><plus-outlined /></template>

View File

@@ -1,5 +1,5 @@
<template>
<a-card :bordered="false" :body-style="{ 'padding-bottom': '0px' }" class="mb-2">
<a-card :bordered="false">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
@@ -12,13 +12,13 @@
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
<redo-outlined />
</template>
重置
</a-button>
@@ -27,8 +27,6 @@
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
@@ -40,7 +38,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()">
<template #icon><plus-outlined /></template>

View File

@@ -65,7 +65,7 @@
// 定义机构元素
const treeData = ref([])
const submitLoading = ref(false)
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
// 打开抽屉
const onOpen = (record, category, orgId) => {
visible.value = true

View File

@@ -1,137 +1,130 @@
<template>
<a-row :gutter="10">
<a-col :xs="0" :sm="0" :md="0" :lg="4" :xl="4">
<a-card :bordered="false" :loading="cardLoading" class="left-tree-container">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
>
</a-tree>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</a-card>
</a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="20" :xl="20">
<a-card :bordered="false" class="xn-mb10">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="组织:" name="categoryOrOrgId">
<a-tree-select
v-model:value="searchFormState.categoryOrOrgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择组织"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
@change="onCategoryOrOrgIdSelect"
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入角色名称关键词"></a-input>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
</template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<a-space>
<a-button
type="primary"
@click="formRef.onOpen(undefined, searchFormState.category, searchFormState.orgId)"
>
<template #icon><plus-outlined /></template>
新增角色
</a-button>
<xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchRole"
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item label="组织:" name="categoryOrOrgId">
<a-tree-select
v-model:value="searchFormState.categoryOrOrgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择组织"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
@change="onCategoryOrOrgIdSelect"
/>
</a-space>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" label="关键词">
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入角色名称关键词"></a-input>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined />
</template>
查询
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined />
</template>
重置
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator>
<a-space>
<a-button
type="primary"
@click="formRef.onOpen(undefined, searchFormState.category, searchFormState.orgId)"
>
<template #icon><plus-outlined /></template>
新增角色
</a-button>
<xn-batch-button
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchRole"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('ROLE_CATEGORY', record.category) }}
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'category'">
{{ $TOOL.dictTypeData('ROLE_CATEGORY', record.category) }}
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)">编辑</a>
<a-divider type="vertical" />
<a-popconfirm title="确定删除此角色" @confirm="removeOrg(record)">
<a-button type="link" danger size="small">删除</a-button>
</a-popconfirm>
<a-divider type="vertical" />
<a-dropdown>
<a class="ant-dropdown-link">
授权
<DownOutlined />
</a>
<template #overlay>
<a-menu>
<a-menu-item>
<a @click="grantResourceFormRef.onOpen(record)">授权资源</a>
</a-menu-item>
<a-menu-item>
<a @click="grantMobileResourceFormRef.onOpen(record)">授权移动端资源</a>
</a-menu-item>
<a-menu-item>
<a @click="grantPermissionFormRef.onOpen(record)">授权权限</a>
</a-menu-item>
<a-menu-item>
<a @click="openRoleUserSelector(record)">授权用户</a>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)">编辑</a>
<a-divider type="vertical" />
<a-popconfirm title="确定删除此角色" @confirm="removeOrg(record)">
<a-button type="link" danger size="small">删除</a-button>
</a-popconfirm>
<a-divider type="vertical" />
<a-dropdown>
<a class="ant-dropdown-link">
授权
<DownOutlined />
</a>
<template #overlay>
<a-menu>
<a-menu-item>
<a @click="grantResourceFormRef.onOpen(record)">授权资源</a>
</a-menu-item>
<a-menu-item>
<a @click="grantMobileResourceFormRef.onOpen(record)">授权移动端资源</a>
</a-menu-item>
<a-menu-item>
<a @click="grantPermissionFormRef.onOpen(record)">授权权限</a>
</a-menu-item>
<a-menu-item>
<a @click="openRoleUserSelector(record)">授权用户</a>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
</s-table>
</a-card>
</a-col>
</a-row>
</template>
</s-table>
</template>
</XnResizablePanel>
<grantResourceForm ref="grantResourceFormRef" @successful="tableRef.refresh()" />
<grantMobileResourceForm ref="grantMobileResourceFormRef" @successful="tableRef.refresh()" />
<grantPermissionForm ref="grantPermissionFormRef" @successful="tableRef.refresh()" />
@@ -205,7 +198,6 @@
const treeData = ref([])
// 替换treeNode 中 title,key,children
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
const cardLoading = ref(true)
// 记录数据
const recordCacheData = ref({})
@@ -226,7 +218,6 @@
}
// 加载左侧的树
orgApi.orgTree().then((res) => {
cardLoading.value = false
if (res !== null) {
// 树中插入全局角色类型
const globalRoleType = [
@@ -281,10 +272,6 @@
delete searchFormState.value.category
}
}
// 可伸缩列
const handleResizeColumn = (w, col) => {
col.width = w
}
// 删除
const removeOrg = (record) => {
let params = [
@@ -336,7 +323,3 @@
}
}
</script>
<style scoped>
</style>

View File

@@ -119,62 +119,62 @@
</a-col>
</a-row>
<div :key="positionInfo" v-for="(positionInfo, index) in formData.positionJson">
<a-row :gutter="10">
<a-col :xs="24" :sm="24" :md="7" :lg="7" :xl="7">
<a-form-item
:name="['positionJson', index, 'orgId']"
:rules="{ required: true, message: '请选择组织' }"
>
<a-tree-select
v-model:value="positionInfo.orgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择组织"
allow-clear
tree-default-expand-all
:tree-data="treeData"
:tree-default-expanded-keys="treeDefaultExpandedKeys"
:field-names="{ children: 'children', label: 'name', value: 'id' }"
@select="childOrgSelect(positionInfo, 0, index)"
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="24" :md="7" :lg="7" :xl="7">
<a-form-item
:name="['positionJson', index, 'positionId']"
:rules="{ required: true, message: '请选择职位' }"
>
<xn-page-select
ref="xnChildPositionPageSelectRef"
v-model:value="positionInfo.positionId"
placeholder="请选择职位"
allow-clear
:page-function="selectApiFunction.childPositionSelector"
:echo-function="selectApiFunction.echoPosition"
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="24" :md="7" :lg="7" :xl="7">
<a-form-item :name="['positionJson', index, 'directorId']">
<xn-page-select
ref="xnChildUserPageSelectRef"
v-model:value="positionInfo.directorId"
placeholder="请选择主管"
allow-clear
:page-function="selectApiFunction.childUserSelector"
:echo-function="selectApiFunction.echoUser"
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="24" :md="3" :lg="3" :xl="3">
<a-form-item>
<a-button type="primary" danger ghost @click="delDomains(index)" size="small">
<DeleteOutlined />
移除
</a-button>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="10">
<a-col :xs="24" :sm="24" :md="7" :lg="7" :xl="7">
<a-form-item
:name="['positionJson', index, 'orgId']"
:rules="{ required: true, message: '请选择组织' }"
>
<a-tree-select
v-model:value="positionInfo.orgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择组织"
allow-clear
tree-default-expand-all
:tree-data="treeData"
:tree-default-expanded-keys="treeDefaultExpandedKeys"
:field-names="treeFieldNames"
@select="childOrgSelect(positionInfo, 0, index)"
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="24" :md="7" :lg="7" :xl="7">
<a-form-item
:name="['positionJson', index, 'positionId']"
:rules="{ required: true, message: '请选择职位' }"
>
<xn-page-select
ref="xnChildPositionPageSelectRef"
v-model:value="positionInfo.positionId"
placeholder="请选择职位"
allow-clear
:page-function="selectApiFunction.childPositionSelector"
:echo-function="selectApiFunction.echoPosition"
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="24" :md="7" :lg="7" :xl="7">
<a-form-item :name="['positionJson', index, 'directorId']">
<xn-page-select
ref="xnChildUserPageSelectRef"
v-model:value="positionInfo.directorId"
placeholder="请选择主管"
allow-clear
:page-function="selectApiFunction.childUserSelector"
:echo-function="selectApiFunction.echoUser"
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="24" :md="3" :lg="3" :xl="3">
<a-form-item>
<a-button type="primary" danger ghost @click="delDomains(index)" size="small">
<DeleteOutlined />
移除
</a-button>
</a-form-item>
</a-col>
</a-row>
</div>
</a-form-item>
</a-tab-pane>
@@ -210,7 +210,7 @@
/>
</a-form-item>
</a-col>
<!-- <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<!-- <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<a-form-item label="通信地址:" name="mailingAddress">
<a-textarea
v-model:value="formData.mailingAddress"
@@ -319,6 +319,7 @@
const xnChildUserPageSelectRef = ref()
// 表单数据
const formData = ref({})
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
// 打开抽屉
const onOpen = (record, orgId) => {

View File

@@ -1,186 +1,174 @@
<template>
<a-row :gutter="10">
<a-col :xs="0" :sm="0" :md="0" :lg="4" :xl="4">
<a-card :bordered="false" :loading="cardLoading" class="left-tree-container">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE"/>
</a-card>
</a-col>
<a-col :xs="24" :sm="24" :md="24" :lg="20" :xl="20">
<a-card :bordered="false" class="xn-mb10">
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item :label="$t('user.userOrg')" name="orgId">
<a-tree-select
v-model:value="searchFormState.orgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
:placeholder="$t('user.placeholderUserOrg')"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" :label="$t('common.searchKey')">
<a-input
v-model:value="searchFormState.searchKey"
:placeholder="$t('user.placeholderNameAndSearchKey')"
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="userStatus" :label="$t('user.userStatus')">
<a-select
v-model:value="searchFormState.userStatus"
:placeholder="$t('user.placeholderUserStatus')"
:getPopupContainer="(trigger) => trigger.parentNode"
>
<a-select-option v-for="item in statusData" :key="item.value" :value="item.value">
{{ item.label }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined/>
</template>
{{ $t('common.searchButton') }}
</a-button>
<a-button @click="reset">
<template #icon>
<redo-outlined/>
</template>
{{ $t('common.resetButton') }}
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
bordered
:alert="options.alert.show"
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<a-space>
<a-button type="primary" @click="formRef.onOpen(undefined, searchFormState.orgId)">
<template #icon>
<plus-outlined/>
</template>
<span>{{ $t('common.addButton') }}{{ $t('model.user') }}</span>
</a-button>
<a-button @click="ImpExpRef.onOpen()">
<template #icon>
<import-outlined/>
</template>
<span>{{ $t('common.imports') }}</span>
</a-button>
<a-button @click="exportBatchUserVerify">
<template #icon>
<export-outlined/>
</template>
{{ $t('user.batchExportButton') }}
</a-button>
<xn-batch-button
:buttonName="$t('common.batchRemoveButton')"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchUser"
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
<a-row :gutter="10">
<a-col :xs="24" :sm="8" :md="8" :lg="0" :xl="0">
<a-form-item :label="$t('user.userOrg')" name="orgId">
<a-tree-select
v-model:value="searchFormState.orgId"
class="xn-wd"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
:placeholder="$t('user.placeholderUserOrg')"
allow-clear
:tree-data="treeData"
:field-names="{
children: 'children',
label: 'name',
value: 'id'
}"
selectable="false"
tree-line
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'avatar'">
<a-avatar :src="record.avatar" style="margin-bottom: -5px; margin-top: -5px"/>
</template>
<template v-if="column.dataIndex === 'gender'">
{{ $TOOL.dictTypeData('GENDER', record.gender) }}
</template>
<template v-if="column.dataIndex === 'userStatus'">
<a-switch :loading="loading" :checked="record.userStatus === 'ENABLE'"
@change="editStatus(record)"/>
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)">{{ $t('common.editButton') }}</a>
<a-divider type="vertical"/>
<a-popconfirm :title="$t('user.popConfirmDeleteUser')" placement="topRight"
@confirm="removeUser(record)">
<a-button type="link" danger size="small">
{{ $t('common.removeButton') }}
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="searchKey" :label="$t('common.searchKey')">
<a-input
v-model:value="searchFormState.searchKey"
:placeholder="$t('user.placeholderNameAndSearchKey')"
/>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item name="userStatus" :label="$t('user.userStatus')">
<a-select
v-model:value="searchFormState.userStatus"
:placeholder="$t('user.placeholderUserStatus')"
:getPopupContainer="(trigger) => trigger.parentNode"
>
<a-select-option v-for="item in statusData" :key="item.value" :value="item.value">
{{ item.label }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<a-form-item>
<a-space>
<a-button type="primary" @click="tableRef.refresh(true)">
<template #icon>
<SearchOutlined />
</template>
{{ $t('common.searchButton') }}
</a-button>
</a-popconfirm>
<a-divider type="vertical"/>
<a-dropdown>
<a class="ant-dropdown-link">
{{ $t('common.more') }}
<DownOutlined/>
</a>
<template #overlay>
<a-menu>
<a-menu-item>
<a-popconfirm
:title="$t('user.popConfirmResatUserPwd')"
placement="topRight"
@confirm="resetPassword(record)"
>
<a>{{ $t('user.resetPassword') }}</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item>
<a @click="selectRole(record)">{{ $t('user.grantRole') }}</a>
</a-menu-item>
<a-menu-item>
<a @click="grantResourceFormRef.onOpen(record)">{{
$t('user.grantResource')
}}</a>
</a-menu-item>
<a-menu-item>
<a @click="grantPermissionFormRef.onOpen(record)">{{
$t('user.grantPermission')
}}</a>
</a-menu-item>
<a-menu-item>
<a @click="exportUserInfo(record)">{{ $t('user.exportUserInfo') }}</a>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
<a-button @click="reset">
<template #icon>
<redo-outlined />
</template>
{{ $t('common.resetButton') }}
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:expand-row-by-click="true"
bordered
:alert="options.alert.show"
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen(undefined, searchFormState.orgId)">
<template #icon>
<plus-outlined />
</template>
<span>{{ $t('common.addButton') }}{{ $t('model.user') }}</span>
</a-button>
<a-button @click="ImpExpRef.onOpen()">
<template #icon>
<import-outlined />
</template>
<span>{{ $t('common.imports') }}</span>
</a-button>
<a-button @click="exportBatchUserVerify">
<template #icon>
<export-outlined />
</template>
{{ $t('user.batchExportButton') }}
</a-button>
<xn-batch-button
:buttonName="$t('common.batchRemoveButton')"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchUser"
/>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'avatar'">
<a-avatar :src="record.avatar" style="margin-bottom: -5px; margin-top: -5px" />
</template>
</s-table>
</a-card>
</a-col>
</a-row>
<Form ref="formRef" @successful="tableRef.refresh()"/>
<template v-if="column.dataIndex === 'gender'">
{{ $TOOL.dictTypeData('GENDER', record.gender) }}
</template>
<template v-if="column.dataIndex === 'userStatus'">
<a-switch :loading="loading" :checked="record.userStatus === 'ENABLE'" @change="editStatus(record)" />
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="formRef.onOpen(record)">{{ $t('common.editButton') }}</a>
<a-divider type="vertical" />
<a-popconfirm :title="$t('user.popConfirmDeleteUser')" placement="topRight" @confirm="removeUser(record)">
<a-button type="link" danger size="small">
{{ $t('common.removeButton') }}
</a-button>
</a-popconfirm>
<a-divider type="vertical" />
<a-dropdown>
<a class="ant-dropdown-link">
{{ $t('common.more') }}
<DownOutlined />
</a>
<template #overlay>
<a-menu>
<a-menu-item>
<a-popconfirm
:title="$t('user.popConfirmResatUserPwd')"
placement="topRight"
@confirm="resetPassword(record)"
>
<a>{{ $t('user.resetPassword') }}</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item>
<a @click="selectRole(record)">{{ $t('user.grantRole') }}</a>
</a-menu-item>
<a-menu-item>
<a @click="grantResourceFormRef.onOpen(record)">{{ $t('user.grantResource') }}</a>
</a-menu-item>
<a-menu-item>
<a @click="grantPermissionFormRef.onOpen(record)">{{ $t('user.grantPermission') }}</a>
</a-menu-item>
<a-menu-item>
<a @click="exportUserInfo(record)">{{ $t('user.exportUserInfo') }}</a>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
</template>
</s-table>
</template>
</XnResizablePanel>
<Form ref="formRef" @successful="tableRef.refresh()" />
<xn-role-selector
ref="RoleSelectorPlusRef"
:org-tree-api="selectorApiFunction.orgTreeApi"
@@ -190,265 +178,257 @@
:role-global="true"
@onBack="roleBack"
/>
<ImpExp ref="ImpExpRef"/>
<grantResourceForm ref="grantResourceFormRef" @successful="tableRef.refresh()"/>
<grantPermissionForm ref="grantPermissionFormRef" @successful="tableRef.refresh()"/>
<ImpExp ref="ImpExpRef" />
<grantResourceForm ref="grantResourceFormRef" @successful="tableRef.refresh()" />
<grantPermissionForm ref="grantPermissionFormRef" @successful="tableRef.refresh()" />
</template>
<script setup name="sysUser">
import {message, Empty} from 'ant-design-vue'
import {isEmpty} from 'lodash-es'
import tool from '@/utils/tool'
import downloadUtil from '@/utils/downloadUtil'
import userApi from '@/api/sys/userApi'
import orgApi from '@/api/sys/orgApi'
import Form from './form.vue'
import ImpExp from './impExp.vue'
import GrantResourceForm from './grantResourceForm.vue'
import GrantPermissionForm from './grantPermissionForm.vue'
import { message, Empty } from 'ant-design-vue'
import { isEmpty } from 'lodash-es'
import tool from '@/utils/tool'
import downloadUtil from '@/utils/downloadUtil'
import userApi from '@/api/sys/userApi'
import orgApi from '@/api/sys/orgApi'
import Form from './form.vue'
import ImpExp from './impExp.vue'
import GrantResourceForm from './grantResourceForm.vue'
import GrantPermissionForm from './grantPermissionForm.vue'
const columns = [
{
title: '头像',
dataIndex: 'avatar',
align: 'center'
},
{
title: '账号',
dataIndex: 'account',
ellipsis: true
},
{
title: '姓名',
dataIndex: 'name'
},
{
title: '性别',
dataIndex: 'genderName'
},
{
title: '手机',
dataIndex: 'phone',
ellipsis: true
},
{
title: '机构',
dataIndex: 'orgName',
ellipsis: true
},
{
title: '职位',
dataIndex: 'positionName',
ellipsis: true
},
{
title: '状态',
dataIndex: 'userStatus'
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
fixed: 'right'
}
]
const statusData = tool.dictList('COMMON_STATUS')
const searchFormRef = ref()
const defaultExpandedKeys = ref([])
const searchFormState = ref({})
const tableRef = ref(null)
const treeData = ref([])
const selectedRowKeys = ref([])
const treeFieldNames = {children: 'children', title: 'name', key: 'id'}
const formRef = ref(null)
const RoleSelectorPlusRef = ref()
const selectedRecord = ref({})
const loading = ref(false)
const cardLoading = ref(true)
const ImpExpRef = ref()
const grantResourceFormRef = ref()
const grantPermissionFormRef = ref()
// 表格查询 返回 Promise 对象
const loadData = (parameter) => {
return userApi.userPage(Object.assign(parameter, searchFormState.value)).then((res) => {
return res
})
}
// 左侧树查询
orgApi.orgTree().then((res) => {
cardLoading.value = false
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
}
})
}
}
})
// 列表选择配置
const options = {
alert: {
show: false,
clear: () => {
selectedRowKeys.value = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
}
}
}
// 重置
const reset = () => {
searchFormRef.value.resetFields()
tableRef.value.refresh(true)
}
// 点击树查询
const treeSelect = (selectedKeys) => {
if (selectedKeys.length > 0) {
searchFormState.value.orgId = selectedKeys.toString()
} else {
delete searchFormState.value.orgId
}
tableRef.value.refresh(true)
}
// 修改状态
const editStatus = (record) => {
loading.value = true
if (record.userStatus === 'ENABLE') {
userApi
.userDisableUser(record)
.then(() => {
tableRef.value.refresh()
})
.finally(() => {
loading.value = false
})
} else {
userApi
.userEnableUser(record)
.then(() => {
tableRef.value.refresh()
})
.finally(() => {
loading.value = false
})
}
}
// 删除用户
const removeUser = (record) => {
let params = [
const columns = [
{
id: record.id
title: '头像',
dataIndex: 'avatar',
align: 'center'
},
{
title: '账号',
dataIndex: 'account',
ellipsis: true
},
{
title: '姓名',
dataIndex: 'name'
},
{
title: '性别',
dataIndex: 'genderName'
},
{
title: '手机',
dataIndex: 'phone',
ellipsis: true
},
{
title: '机构',
dataIndex: 'orgName',
ellipsis: true
},
{
title: '职位',
dataIndex: 'positionName',
ellipsis: true
},
{
title: '状态',
dataIndex: 'userStatus'
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
fixed: 'right'
}
]
userApi.userDelete(params).then(() => {
tableRef.value.refresh()
})
}
// 批量导出校验并加参数
const exportBatchUserVerify = () => {
if ((selectedRowKeys.value.length < 1) & !searchFormState.value.searchKey & !searchFormState.value.userStatus) {
message.warning('请输入查询条件或勾选要导出的信息')
const statusData = tool.dictList('COMMON_STATUS')
const searchFormRef = ref()
const defaultExpandedKeys = ref([])
const searchFormState = ref({})
const tableRef = ref(null)
const treeData = ref([])
const selectedRowKeys = ref([])
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
const formRef = ref(null)
const RoleSelectorPlusRef = ref()
const selectedRecord = ref({})
const loading = ref(false)
const ImpExpRef = ref()
const grantResourceFormRef = ref()
const grantPermissionFormRef = ref()
// 表格查询 返回 Promise 对象
const loadData = (parameter) => {
return userApi.userPage(Object.assign(parameter, searchFormState.value)).then((res) => {
return res
})
}
if (selectedRowKeys.value.length > 0) {
const params = {
userIds: selectedRowKeys.value
.map((m) => {
return m
// 左侧树查询
orgApi.orgTree().then((res) => {
if (res !== null) {
treeData.value = res
if (isEmpty(defaultExpandedKeys.value)) {
// 默认展开2级
treeData.value.forEach((item) => {
// 因为0的顶级
if (item.parentId === '0') {
defaultExpandedKeys.value.push(item.id)
// 取到下级ID
if (item.children) {
item.children.forEach((items) => {
defaultExpandedKeys.value.push(items.id)
})
}
}
})
.join()
}
}
})
// 列表选择配置
const options = {
alert: {
show: false,
clear: () => {
selectedRowKeys.value = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
}
}
exportBatchUser(params)
return
}
if (searchFormState.value.searchKey || searchFormState.value.userStatus) {
// 重置
const reset = () => {
searchFormRef.value.resetFields()
tableRef.value.refresh(true)
}
// 点击树查询
const treeSelect = (selectedKeys) => {
if (selectedKeys.length > 0) {
searchFormState.value.orgId = selectedKeys.toString()
} else {
delete searchFormState.value.orgId
}
tableRef.value.refresh(true)
}
// 修改状态
const editStatus = (record) => {
loading.value = true
if (record.userStatus === 'ENABLE') {
userApi
.userDisableUser(record)
.then(() => {
tableRef.value.refresh()
})
.finally(() => {
loading.value = false
})
} else {
userApi
.userEnableUser(record)
.then(() => {
tableRef.value.refresh()
})
.finally(() => {
loading.value = false
})
}
}
// 删除用户
const removeUser = (record) => {
let params = [
{
id: record.id
}
]
userApi.userDelete(params).then(() => {
tableRef.value.refresh()
})
}
// 批量导出校验并加参数
const exportBatchUserVerify = () => {
if ((selectedRowKeys.value.length < 1) & !searchFormState.value.searchKey & !searchFormState.value.userStatus) {
message.warning('请输入查询条件或勾选要导出的信息')
}
if (selectedRowKeys.value.length > 0) {
const params = {
userIds: selectedRowKeys.value
.map((m) => {
return m
})
.join()
}
exportBatchUser(params)
return
}
if (searchFormState.value.searchKey || searchFormState.value.userStatus) {
const params = {
searchKey: searchFormState.value.searchKey,
userStatus: searchFormState.value.userStatus
}
exportBatchUser(params)
}
}
// 批量导出
const exportBatchUser = (params) => {
userApi.userExport(params).then((res) => {
downloadUtil.resultDownload(res)
tableRef.value.clearSelected()
})
}
// 批量删除
const deleteBatchUser = (params) => {
userApi.userDelete(params).then(() => {
tableRef.value.clearRefreshSelected()
})
}
// 打开角色选择器
const selectRole = (record) => {
selectedRecord.value = record
// 查询到已有角色并转为ids的格式给角色选择器
const param = {
id: record.id
}
userApi.userOwnRole(param).then((data) => {
RoleSelectorPlusRef.value.showModel(data)
})
}
// 角色选择回调
const roleBack = (value) => {
let params = {
id: selectedRecord.value.id,
roleIdList: []
}
if (value.length > 0) {
value.forEach((item) => {
params.roleIdList.push(item)
})
}
userApi.grantRole(params).then(() => {})
}
// 重置用户密码
const resetPassword = (record) => {
userApi.userResetPassword(record).then(() => {})
}
// 导出用户信息
const exportUserInfo = (record) => {
const params = {
searchKey: searchFormState.value.searchKey,
userStatus: searchFormState.value.userStatus
id: record.id
}
exportBatchUser(params)
}
}
// 批量导出
const exportBatchUser = (params) => {
userApi.userExport(params).then((res) => {
downloadUtil.resultDownload(res)
tableRef.value.clearSelected()
})
}
// 批量删除
const deleteBatchUser = (params) => {
userApi.userDelete(params).then(() => {
tableRef.value.clearRefreshSelected()
})
}
// 打开角色选择器
const selectRole = (record) => {
selectedRecord.value = record
// 查询到已有角色并转为ids的格式给角色选择器
const param = {
id: record.id
}
userApi.userOwnRole(param).then((data) => {
RoleSelectorPlusRef.value.showModel(data)
})
}
// 角色选择回调
const roleBack = (value) => {
let params = {
id: selectedRecord.value.id,
roleIdList: []
}
if (value.length > 0) {
value.forEach((item) => {
params.roleIdList.push(item)
userApi.userExportUserInfo(params).then((res) => {
downloadUtil.resultDownload(res)
})
}
userApi.grantRole(params).then(() => {
})
}
// 重置用户密码
const resetPassword = (record) => {
userApi.userResetPassword(record).then(() => {
})
}
// 导出用户信息
const exportUserInfo = (record) => {
const params = {
id: record.id
// 传递设计器需要的API
const selectorApiFunction = {
orgTreeApi: (param) => {
return userApi.userOrgTreeSelector(param).then((data) => {
return Promise.resolve(data)
})
},
rolePageApi: (param) => {
return userApi.userRoleSelector(param).then((data) => {
return Promise.resolve(data)
})
}
}
userApi.userExportUserInfo(params).then((res) => {
downloadUtil.resultDownload(res)
})
}
// 传递设计器需要的API
const selectorApiFunction = {
orgTreeApi: (param) => {
return userApi.userOrgTreeSelector(param).then((data) => {
return Promise.resolve(data)
})
},
rolePageApi: (param) => {
return userApi.userRoleSelector(param).then((data) => {
return Promise.resolve(data)
})
}
}
</script>
<style scoped>
</style>

View File

@@ -97,7 +97,7 @@
:row-selection="options.rowSelection"
:scroll="{ x: 'max-content' }"
>
<template #operator class="table-operator">
<template #operator>
<a-space>
<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('${classNameFirstLower}Add')">
<template #icon><plus-outlined /></template>