Merge branch 'develop' of https://gitee.com/youlaiorg/vue-uniapp-template into develop
This commit is contained in:
76
src/api/system/menu.ts
Normal file
76
src/api/system/menu.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import request from "@/utils/request";
|
||||
// 菜单基础URL
|
||||
const MENU_BASE_URL = "/api/v1/menus";
|
||||
|
||||
const MenuAPI = {
|
||||
/**
|
||||
* 获取当前用户的路由列表
|
||||
* <p/>
|
||||
* 无需传入角色,后端解析token获取角色自行判断是否拥有路由的权限
|
||||
*
|
||||
* @returns 路由列表
|
||||
*/
|
||||
getRoutes() {
|
||||
return request<RouteVO[]>({
|
||||
url: `${MENU_BASE_URL}/routes`,
|
||||
method: "GET",
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取菜单下拉数据源
|
||||
*
|
||||
* @returns 菜单下拉数据源
|
||||
*/
|
||||
getOptions(onlyParent?: boolean) {
|
||||
return request<OptionType[]>({
|
||||
url: `${MENU_BASE_URL}/options`,
|
||||
method: "GET",
|
||||
data: { onlyParent: onlyParent },
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default MenuAPI;
|
||||
|
||||
/** RouteVO,路由对象 */
|
||||
export interface RouteVO {
|
||||
/** 子路由列表 */
|
||||
children: RouteVO[];
|
||||
/** 组件路径 */
|
||||
component?: string;
|
||||
/** 路由属性 */
|
||||
meta?: Meta;
|
||||
/** 路由名称 */
|
||||
name?: string;
|
||||
/** 路由路径 */
|
||||
path?: string;
|
||||
/** 跳转链接 */
|
||||
redirect?: string;
|
||||
}
|
||||
|
||||
/** Meta,路由属性 */
|
||||
export interface Meta {
|
||||
/** 【目录】只有一个子路由是否始终显示 */
|
||||
alwaysShow?: boolean;
|
||||
/** 是否隐藏(true-是 false-否) */
|
||||
hidden?: boolean;
|
||||
/** ICON */
|
||||
icon?: string;
|
||||
/** 【菜单】是否开启页面缓存 */
|
||||
keepAlive?: boolean;
|
||||
/** 路由title */
|
||||
title?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件数据源
|
||||
*/
|
||||
interface OptionType {
|
||||
/** 值 */
|
||||
value: string | number;
|
||||
/** 文本 */
|
||||
label: string;
|
||||
/** 子列表 */
|
||||
children?: OptionType[];
|
||||
}
|
||||
196
src/components/da-tree/changelog.md
Normal file
196
src/components/da-tree/changelog.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# 1.4.2
|
||||
|
||||
新增
|
||||
|
||||
1. 新增`filterValue`属性,支持通过此关键词来搜索并筛选树结构的内容
|
||||
|
||||
# 1.4.1
|
||||
|
||||
修复
|
||||
|
||||
1. 修复单选 onlyRadioLeaf 时末级节点无法选中的 bug
|
||||
|
||||
# 1.4.0
|
||||
|
||||
版本调整
|
||||
|
||||
建议更新,但需要注意,异步数据的时候,后台需返回 leaf 字段来判断是否末项数据
|
||||
|
||||
1. **调整数据项格式,新增 `leaf` 字段,来判断是否为末节点**
|
||||
2. **调整数据项格式,新增 `sort` 字段,来排序节点位置**
|
||||
3. **注意:异步加载数据,当为末项的时候,需要服务端数据返回 `leaf` 字段**
|
||||
4. 新增 `alwaysFirstLoad` ,即异步数据总会在第一次展开节点时,拉取一次后台数据,来比对是否一致
|
||||
5. 拆分 `field` 属性,**注意: 1.5.0 版本后将移除 `field` 属性**
|
||||
6. 新增 `labelField` 同 `field.label`,指定节点对象中某个属性为**标签**字段,默认`label`
|
||||
7. 新增 `valueField` 同 `field.key`,指定节点对象中某个属性为**值**字段,默认`value`
|
||||
8. 新增 `childrenField` 同 `field.children`,指定节点对象中某个属性为**子树节点**字段,默认`children`
|
||||
9. 新增 `disabledField` 同 `field.disabled`,指定节点对象中某个属性为**禁用**字段,默认`disabled`
|
||||
10. 新增 `appendField` 同 `field.append`,指定节点对象中某个属性为**副标签**字段,默认`append`
|
||||
11. 新增 `leafField` 同 `field.label`,指定节点对象中某个属性为**末级节点**字段,默认`leaf`
|
||||
12. 新增 `sortField` 同 `field.label`,指定节点对象中某个属性为**排序**字段,默认`sort`
|
||||
13. 新增 `isLeafFn` ,用来自定义控制数据项的末项
|
||||
14. 更多的项目示例
|
||||
15. 支持单选取消选中
|
||||
16. 修复节点展开时可能存在的 bug
|
||||
17. 修复节点选择可能存在的 bug
|
||||
18. 调整为子节点默认继承父节点禁用属性
|
||||
19. `setExpandedKeys` 添加参数一为 `all` 即可支持一键展开/收起全部节点
|
||||
20. 其它更多优化
|
||||
|
||||
# 1.3.4
|
||||
|
||||
优化
|
||||
|
||||
1. 优化图标字体命名
|
||||
|
||||
# 1.3.3
|
||||
|
||||
优化
|
||||
|
||||
1. 新增方法调用
|
||||
> - 新增`getUncheckedKeys`,返回未选的 key
|
||||
> - 新增`getUncheckedNodes`,返回未选的节点
|
||||
> - 新增`getUnexpandedKeys`,返回未展开的 key
|
||||
> - 新增`getUnexpandedNodes`,返回未展开的节点
|
||||
2. 优化示例项目
|
||||
|
||||
# 1.3.2
|
||||
|
||||
修复
|
||||
|
||||
1. 修复在 APP 真机环境中的报错
|
||||
|
||||
# 1.3.1
|
||||
|
||||
修复
|
||||
|
||||
1. 修复方法`setExpandedKeys`没联动展开上级父子节点
|
||||
|
||||
# 1.3.0
|
||||
|
||||
优化
|
||||
|
||||
1. `field`新增字段 `append` 用于在标签后面显示小提示
|
||||
2. 新增支持点击标签也能选中节点
|
||||
3. 方法`setExpandedKeys`支持加载动态数据
|
||||
4. 修复父节点禁用,则不能展开及图标展开显示
|
||||
5. 修复动态加载数据时,末级节点的 `children` 为 `null` 时仍显示展开图标
|
||||
|
||||
# 1.2.6
|
||||
|
||||
新增
|
||||
|
||||
1. 新增支持主题换色
|
||||
2. 支持单选的`onlyRadioLeaf`为`true`时可点父节点展开/收起
|
||||
3. 优化`expandChecked`调整为不展开无子节点的节点
|
||||
|
||||
# 1.2.5
|
||||
|
||||
新增
|
||||
|
||||
1. 新增 `expandChecked`,控制选择时是否展开当前已选的所有下级节点
|
||||
|
||||
# 1.2.4
|
||||
|
||||
修复
|
||||
|
||||
1. 修复动态数据展开状态异常问题
|
||||
|
||||
# 1.2.3
|
||||
|
||||
新增
|
||||
|
||||
1. 新增 `checkedDisabled`,是否渲染禁用值
|
||||
2. 新增 `packDisabledkey`,是否返回已禁用并选中的 key
|
||||
3. 修复选择父级时,子级已禁用但仍被选中的问题
|
||||
|
||||
# 1.2.2
|
||||
|
||||
优化
|
||||
|
||||
1. 调整动态数据载入处理方式
|
||||
2. 修复节点数据因动态数据引起的状态异常
|
||||
3. 修复初始节点数据默认选中
|
||||
|
||||
# 1.2.1
|
||||
|
||||
修复
|
||||
|
||||
1. 修复切换`选中状态`被重复选中问题
|
||||
2. 修复动态数据引起的重复选择问题
|
||||
|
||||
# 1.2.0
|
||||
|
||||
新增
|
||||
|
||||
1. 新增方法调用
|
||||
> - 新增`setCheckedKeys`,方法设置指定 key 的节点选中状态
|
||||
> - 新增`setExpandedKeys`,方法设置指定 key 的节点展开状态
|
||||
2. 修复小程序重复插槽一直刷报错问题
|
||||
3. 优化展开时,会展开子级所以下级节点
|
||||
|
||||
# 1.1.1
|
||||
|
||||
新增
|
||||
|
||||
1. 新增`data`的`disabled`,支持节点禁用状态
|
||||
2. 新增`field`的`disabled`,可自定`disabled`字段值
|
||||
|
||||
# 1.1.0
|
||||
|
||||
新增
|
||||
|
||||
1. 新增`loadMode`、`loadApi`,支持展开时加载异步数据
|
||||
2. 新增方法调用
|
||||
> - 新增`getCheckedKeys`,方法返回已选的 key
|
||||
> - 新增`getHalfCheckedKeys`,方法返回半选的 key
|
||||
> - 新增`getExpandedKeys`,方法返回已展开的 key
|
||||
> - 新增`getCheckedNodes`,方法返回已选的节点
|
||||
> - 新增`getHalfCheckedNodes`,方法返回半选的节点
|
||||
> - 新增`getExpandedNodes`,方法返回已展开的节点
|
||||
3. 对代码进行重构,更易于后期拓展
|
||||
4. 此次更新后,页面多个的 DaTee 组件间的数据不再关联
|
||||
|
||||
# 1.0.6
|
||||
|
||||
新增
|
||||
|
||||
1. 新增`checkStrictly`,多选模式下选中时是否父子不关联
|
||||
|
||||
# 1.0.5
|
||||
|
||||
修复
|
||||
|
||||
1. 修复多选时已选数据重复问题
|
||||
|
||||
# 1.0.4
|
||||
|
||||
修复
|
||||
|
||||
1. 修复 `change` 事件回调数据的问题
|
||||
|
||||
# 1.0.3
|
||||
|
||||
优化
|
||||
|
||||
1. 优化文档及示例说明
|
||||
|
||||
# 1.0.2
|
||||
|
||||
新增
|
||||
|
||||
1. 新增 `onlyRadioLeaf` ,单选时只允许选中末级
|
||||
2. 优化默认展开及默认选择的展开问题
|
||||
|
||||
# 1.0.1
|
||||
|
||||
新增
|
||||
|
||||
1. 支持展开/收起回调事件`@expand`
|
||||
|
||||
# 1.0.0
|
||||
|
||||
初始版本 1.0.0,基于 Vue3 进行开发,支持单选、多选,兼容各大平台
|
||||
|
||||
1. 支持单选
|
||||
2. 支持多选
|
||||
1206
src/components/da-tree/index.vue
Normal file
1206
src/components/da-tree/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
197
src/components/da-tree/props.ts
Normal file
197
src/components/da-tree/props.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
export default {
|
||||
/**
|
||||
* 树的数据
|
||||
*/
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
/**
|
||||
* 主题色
|
||||
*/
|
||||
themeColor: {
|
||||
type: String,
|
||||
default: "#007aff",
|
||||
},
|
||||
/**
|
||||
* 是否开启多选,默认单选
|
||||
*/
|
||||
showCheckbox: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 默认选中的节点,注意单选时为单个key,多选时为key的数组
|
||||
*/
|
||||
defaultCheckedKeys: {
|
||||
type: [Array, String, Number],
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 是否默认展开全部
|
||||
*/
|
||||
defaultExpandAll: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 默认展开的节点
|
||||
*/
|
||||
defaultExpandedKeys: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 筛选关键词
|
||||
*/
|
||||
filterValue: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
/**
|
||||
* 是否自动展开到选中的节点,默认不展开
|
||||
*/
|
||||
expandChecked: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* (旧)字段对应内容,默认为 {label: 'label',key: 'key', children: 'children', disabled: 'disabled', append: 'append'}
|
||||
* 注意:1.5.0版本后不再兼容
|
||||
*/
|
||||
field: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 标签字段(新,拆分了)
|
||||
*/
|
||||
labelField: {
|
||||
type: String,
|
||||
default: "label",
|
||||
},
|
||||
/**
|
||||
* 值字段(新,拆分了)
|
||||
*/
|
||||
valueField: {
|
||||
type: String,
|
||||
default: "value",
|
||||
},
|
||||
/**
|
||||
* 下级字段(新,拆分了)
|
||||
*/
|
||||
childrenField: {
|
||||
type: String,
|
||||
default: "children",
|
||||
},
|
||||
/**
|
||||
* 禁用字段(新,拆分了)
|
||||
*/
|
||||
disabledField: {
|
||||
type: String,
|
||||
default: "disabled",
|
||||
},
|
||||
/**
|
||||
* 末级节点字段(新,拆分了)
|
||||
*/
|
||||
leafField: {
|
||||
type: String,
|
||||
default: "leaf",
|
||||
},
|
||||
/**
|
||||
* 副标签字段(新,拆分了)
|
||||
*/
|
||||
appendField: {
|
||||
type: String,
|
||||
default: "append",
|
||||
},
|
||||
/**
|
||||
* 排序字段(新,拆分了)
|
||||
*/
|
||||
sortField: {
|
||||
type: String,
|
||||
default: "sort",
|
||||
},
|
||||
/**
|
||||
* Api数据返回后的结果路径,支持嵌套如`data.list`
|
||||
*/
|
||||
resultField: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
isLeafFn: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 是否显示单选图标,默认显示
|
||||
*/
|
||||
showRadioIcon: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/**
|
||||
* 单选时只允许选中末级,默认可随意选中
|
||||
*/
|
||||
onlyRadioLeaf: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 多选时,是否执行父子不关联的任意勾选,默认父子关联
|
||||
*/
|
||||
checkStrictly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 为 true 时,空的 children 数组会显示展开图标
|
||||
*/
|
||||
loadMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 异步加载接口
|
||||
*/
|
||||
loadApi: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 是否总在首次的时候加载一下内容,来比对是否一致
|
||||
*/
|
||||
alwaysFirstLoad: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 是否渲染(操作)禁用值
|
||||
*/
|
||||
checkedDisabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 是否返回已禁用的但已选中的key
|
||||
*/
|
||||
packDisabledkey: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/**
|
||||
* 选择框的位置,可选 left/right
|
||||
*/
|
||||
checkboxPlacement: {
|
||||
type: String,
|
||||
default: "left",
|
||||
},
|
||||
/**
|
||||
* 子项缩进距离,默认40,单位rpx
|
||||
*/
|
||||
indent: {
|
||||
type: Number,
|
||||
default: 40,
|
||||
},
|
||||
};
|
||||
310
src/components/da-tree/readme.md
Normal file
310
src/components/da-tree/readme.md
Normal file
@@ -0,0 +1,310 @@
|
||||
# da-tree
|
||||
|
||||
一个基于 Vue3 的 tree(树)组件,同时支持主题换色,可能是最适合你的 tree(树)组件
|
||||
|
||||
组件一直在更新,遇到问题可在下方讨论。
|
||||
|
||||
`同时更新 Vue2 版本,在此查看 ===>` **[Vue2 版](https://ext.dcloud.net.cn/plugin?id=12692)**
|
||||
|
||||
### 关于使用
|
||||
|
||||
可在右侧的`使用 HBuilderX 导入插件`或`下载示例项目ZIP`,方便快速上手。
|
||||
|
||||
可通过下方的示例及文档说明,进一步了解使用组件相关细节参数。
|
||||
|
||||
插件地址:https://ext.dcloud.net.cn/plugin?id=12384
|
||||
|
||||
### 组件示例
|
||||
|
||||
```jsx
|
||||
<template>
|
||||
<view>多选</view>
|
||||
<view><button @click="doCheckedTree(['2'],true)">全选</button></view>
|
||||
<view><button @click="doCheckedTree(['2'],false)">取消全选</button></view>
|
||||
<view><button @click="doCheckedTree(['211','222'],true)">选中指定节点</button></view>
|
||||
<view><button @click="doCheckedTree(['211','222'],false)">取消选中指定节点</button></view>
|
||||
<view><button @click="doExpandTree('all',true)">展开全部节点</button></view>
|
||||
<view><button @click="doExpandTree('all',false)">收起全部节点</button></view>
|
||||
<view><button @click="doExpandTree(['22','23'],true)">展开节点</button></view>
|
||||
<view><button @click="doExpandTree(['22','23'],false)">收起节点</button></view>
|
||||
<DaTree
|
||||
ref="DaTreeRef"
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
defaultExpandAll
|
||||
showCheckbox
|
||||
:defaultCheckedKeys="defaultCheckedKeysValue"
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange"></DaTree>
|
||||
<view>单选</view>
|
||||
<DaTree
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
defaultExpandAll
|
||||
:defaultCheckedKeys="defaultCheckedKeysValue2"
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange"></DaTree>
|
||||
<view>默认展开指定节点</view>
|
||||
<DaTree
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
showCheckbox
|
||||
:defaultExpandedKeys="defaultExpandKeysValue3"
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange"></DaTree>
|
||||
<view>异步加载数据</view>
|
||||
<DaTree
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
showCheckbox
|
||||
loadMode
|
||||
:loadApi="GetApiData"
|
||||
defaultExpandAll
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange"></DaTree>
|
||||
</template>
|
||||
```
|
||||
|
||||
```js
|
||||
import { defineComponent, ref } from "vue";
|
||||
|
||||
/**
|
||||
* 模拟创建一个接口数据
|
||||
*/
|
||||
function GetApiData(currentNode) {
|
||||
const { key } = currentNode;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
// 模拟返回空数据
|
||||
if (key.indexOf("-") > -1) {
|
||||
return resolve(null);
|
||||
// return resolve([])
|
||||
}
|
||||
|
||||
return resolve([
|
||||
{
|
||||
id: `${key}-1`,
|
||||
name: `行政部X${key}-1`,
|
||||
},
|
||||
{
|
||||
id: `${key}-2`,
|
||||
name: `财务部X${key}-2`,
|
||||
append: "定义了末项数据",
|
||||
leaf: true,
|
||||
},
|
||||
{
|
||||
id: `${key}-3`,
|
||||
name: `资源部X${key}-3`,
|
||||
},
|
||||
{
|
||||
id: `${key}-4`,
|
||||
name: `资源部X${key}-3`,
|
||||
append: "被禁用,无展开图标",
|
||||
disabled: true,
|
||||
},
|
||||
]);
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
import DaTree from "@/components/da-tree/index.vue";
|
||||
export default defineComponent({
|
||||
components: { DaTree },
|
||||
setup() {
|
||||
const DaTreeRef = ref();
|
||||
// key的类型必须对应树数据key的类型
|
||||
const defaultCheckedKeysValue = ref(["211", "222"]);
|
||||
const defaultCheckedKeysValue2 = ref("222");
|
||||
const defaultExpandKeysValue3 = ref(["212", "231"]);
|
||||
const roomTreeData = ref([
|
||||
{
|
||||
id: "2",
|
||||
name: "行政中心",
|
||||
children: [
|
||||
{
|
||||
id: "21",
|
||||
name: "行政部",
|
||||
children: [
|
||||
{
|
||||
id: "211",
|
||||
name: "行政一部",
|
||||
children: null,
|
||||
},
|
||||
{
|
||||
id: "212",
|
||||
name: "行政二部",
|
||||
children: [],
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "22",
|
||||
name: "财务部",
|
||||
children: [
|
||||
{
|
||||
id: "221",
|
||||
name: "财务一部",
|
||||
children: [],
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
id: "222",
|
||||
name: "财务二部",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "23",
|
||||
name: "人力资源部",
|
||||
children: [
|
||||
{
|
||||
id: "231",
|
||||
name: "人力一部",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
id: "232",
|
||||
name: "人力二部",
|
||||
append: "更多示例,请下载示例项目查看",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
function doExpandTree(keys, expand) {
|
||||
DaTreeRef.value?.setExpandedKeys(keys, expand);
|
||||
|
||||
const gek = DaTreeRef.value?.getExpandedKeys();
|
||||
console.log("当前已展开的KEY ==>", gek);
|
||||
}
|
||||
function doCheckedTree(keys, checked) {
|
||||
DaTreeRef.value?.setCheckedKeys(keys, checked);
|
||||
|
||||
const gek = DaTreeRef.value?.getCheckedKeys();
|
||||
console.log("当前已选中的KEY ==>", gek);
|
||||
}
|
||||
function handleTreeChange(allSelectedKeys, currentItem) {
|
||||
console.log("handleTreeChange ==>", allSelectedKeys, currentItem);
|
||||
}
|
||||
function handleExpandChange(expand, currentItem) {
|
||||
console.log("handleExpandChange ==>", expand, currentItem);
|
||||
}
|
||||
return {
|
||||
DaTreeRef,
|
||||
roomTreeData,
|
||||
defaultCheckedKeysValue,
|
||||
defaultCheckedKeysValue2,
|
||||
defaultExpandKeysValue3,
|
||||
handleTreeChange,
|
||||
handleExpandChange,
|
||||
GetApiData,
|
||||
doExpandTree,
|
||||
doCheckedTree,
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
** 更多示例请下载/导入示例项目 ZIP 查看 **
|
||||
|
||||
### 组件参数
|
||||
|
||||
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|
||||
| :------------------ | :------------------------------ | :--------- | :--- | :--------------------------------------------------------------------------- |
|
||||
| data | `Array` | - | 是 | 树的数据 |
|
||||
| themeColor | `String` | `#007aff` | 否 | 主题色,十六进制 |
|
||||
| defaultCheckedKeys | `Array` \| `Number` \| `String` | - | 否 | 默认选中的节点,单选为单个 key,多选为 key 的数组 |
|
||||
| showCheckbox | `Boolean` | `false` | 否 | 是否开启多选,默认单选 |
|
||||
| checkStrictly | `Boolean` | `false` | 否 | 多选时,是否执行父子不关联的任意勾选,默认父子关联 |
|
||||
| showRadioIcon | `Boolean` | `true` | 否 | 是否显示单选图标,默认显示 |
|
||||
| onlyRadioLeaf | `Boolean` | `true` | 否 | 单选时只允许选中末级,默认可随意选中 |
|
||||
| defaultExpandAll | `Boolean` | `false` | 否 | 是否默认展开全部 |
|
||||
| defaultExpandedKeys | `Array` | - | 否 | 默认展开的节点 |
|
||||
| indent | `Number` | `40` | 否 | 子项缩进距离,单位 rpx |
|
||||
| checkboxPlacement | `String` | `left` | 否 | 选择框的位置,可选 left/right |
|
||||
| loadMode | `Boolean` | `false` | 否 | 为 true 时,空的 children 数组会显示展开图标 |
|
||||
| loadApi | `Function` | - | 否 | 选择框的位置,可选 left/right |
|
||||
| checkedDisabled | `Boolean` | `false` | 否 | 是否渲染禁用值,默认不渲染 |
|
||||
| packDisabledkey | `Boolean` | `true` | 否 | 是否返回已禁用的但已选中的 key,默认返回禁用已选值 |
|
||||
| expandChecked | `Boolean` | `false` | 否 | 是否自动展开到选中的节点,默认不展开 |
|
||||
| alwaysFirstLoad | `Boolean` | `false` | 否 | 是否总在首次的时候加载一下内容,默认不加载,否则只有展开末级节点才会加载数据 |
|
||||
| isLeafFn | `Function` | - | 否 | 自定义函数返回来控制数据项的末项 |
|
||||
| field | `Object` | - | 否 | 字段对应内容,格式参考下方(1.5.0 后移除,请用单独的字段匹配) |
|
||||
| labelField | `String` | `label` | 否 | 指定节点对象中某个属性为标签字段,默认`label` |
|
||||
| valueField | `String` | `value` | 否 | 指定节点对象中某个属性为值字段,默认`value` |
|
||||
| childrenField | `String` | `children` | 否 | 指定节点对象中某个属性为子树节点字段,默认`children` |
|
||||
| disabledField | `String` | `disabled` | 否 | 指定节点对象中某个属性为禁用字段,默认`disabled` |
|
||||
| appendField | `String` | `append` | 否 | 指定节点对象中某个属性为副标签字段,默认`append` |
|
||||
| leafField | `String` | `leaf` | 否 | 指定节点对象中某个属性为末级节点字段,默认`leaf` |
|
||||
| sortField | `String` | `sort` | 否 | 指定节点对象中某个属性为排序字段,默认`sort` |
|
||||
| filterValue | `String` | - | 否 | 搜索筛选的关键词,通过输入关键词筛选内容 |
|
||||
|
||||
**field 格式(1.5.0 后移除,请用单独的字段匹配)**
|
||||
|
||||
```js
|
||||
{
|
||||
label: 'label',
|
||||
key: 'key',
|
||||
children: 'children',
|
||||
disabled: 'disabled',
|
||||
append: 'append'
|
||||
}
|
||||
```
|
||||
|
||||
### 组件事件
|
||||
|
||||
| 事件名称 | 回调参数 | 说明 |
|
||||
| :------- | :-------------------------------------- | :-------------- |
|
||||
| change | `(allCheckedKeys, currentItem) => void` | 选中时回调 |
|
||||
| expand | `(expandState, currentItem) => void` | 展开/收起时回调 |
|
||||
|
||||
### 组件方法
|
||||
|
||||
| 方法名称 | 参数 | 说明 |
|
||||
| :------------------ | :--------------- | :------------------------------------------------------------------------------------------------ |
|
||||
| setCheckedKeys | `(keys,checked)` | 设置指定 key 的节点选中/取消选中的状态。注: keys 单选时为 key,多选时为 key 的数组 |
|
||||
| setExpandedKeys | `(keys,expand)` | 设置指定 key 的节点展开/收起的状态,当 keys 为 all 时即代表展开/收起全部。注:keys 为数组或 `all` |
|
||||
| getCheckedKeys | - | 返回已选的 key |
|
||||
| getHalfCheckedKeys | - | 返回半选的 key |
|
||||
| getUncheckedKeys | - | 返回未选的 key |
|
||||
| getCheckedNodes | - | 返回已选的节点 |
|
||||
| getUncheckedNodes | - | 返回未选的节点 |
|
||||
| getHalfCheckedNodes | - | 返回半选的节点 |
|
||||
| getExpandedKeys | - | 返回已展开的 key |
|
||||
| getUnexpandedKeys | - | 返回未展开的 key |
|
||||
| getExpandedNodes | - | 返回已展开的节点 |
|
||||
| getUnexpandedNodes | - | 返回未展开的节点 |
|
||||
|
||||
### 组件版本
|
||||
|
||||
v1.4.2
|
||||
|
||||
### 差异化
|
||||
|
||||
已通过测试
|
||||
|
||||
> - H5 页面
|
||||
> - 微信小程序
|
||||
> - 支付宝、钉钉小程序
|
||||
> - 字节跳动、抖音、今日头条小程序
|
||||
> - 百度小程序
|
||||
> - 飞书小程序
|
||||
> - QQ 小程序
|
||||
> - 京东小程序
|
||||
|
||||
未测试
|
||||
|
||||
> - 快手小程序由于非企业用户暂无演示
|
||||
> - 快应用、360 小程序因 Vue3 支持的原因暂无演示
|
||||
|
||||
### 开发组
|
||||
|
||||
[@CRLANG](https://crlang.com)
|
||||
150
src/components/da-tree/utils.ts
Normal file
150
src/components/da-tree/utils.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
/** 未选 */
|
||||
export const unCheckedStatus = 0;
|
||||
/** 半选 */
|
||||
export const halfCheckedStatus = 1;
|
||||
/** 选中 */
|
||||
export const isCheckedStatus = 2;
|
||||
|
||||
/**
|
||||
* 深拷贝内容
|
||||
* @param originData 拷贝对象
|
||||
* @author crlang(https://crlang.com)
|
||||
*/
|
||||
export function deepClone(originData) {
|
||||
const type = Object.prototype.toString.call(originData);
|
||||
let data;
|
||||
if (type === "[object Array]") {
|
||||
data = [];
|
||||
for (let i = 0; i < originData.length; i++) {
|
||||
data.push(deepClone(originData[i]));
|
||||
}
|
||||
} else if (type === "[object Object]") {
|
||||
data = {};
|
||||
for (const prop in originData) {
|
||||
if (originData.hasOwnProperty(prop)) {
|
||||
// 非继承属性
|
||||
data[prop] = deepClone(originData[prop]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data = originData;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有指定的节点
|
||||
* @param type
|
||||
* @param value
|
||||
* @author crlang(https://crlang.com)
|
||||
*/
|
||||
export function getAllNodes(list, type, value, packDisabledkey = true) {
|
||||
if (!list || list.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const res = [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const item = list[i];
|
||||
if (item[type] === value) {
|
||||
if ((packDisabledkey && item.disabled) || !item.disabled) {
|
||||
res.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有指定的key值
|
||||
* @param type
|
||||
* @param value
|
||||
* @author crlang(https://crlang.com)
|
||||
*/
|
||||
export function getAllNodeKeys(list, type, value, packDisabledkey = true) {
|
||||
if (!list || list.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const res = [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const item = list[i];
|
||||
if (item[type] === value) {
|
||||
if ((packDisabledkey && item.disabled) || !item.disabled) {
|
||||
res.push(item.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.length ? res : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误输出
|
||||
*
|
||||
* @param msg
|
||||
*/
|
||||
export function logError(msg, ...args) {
|
||||
console.error(`DaTree: ${msg}`, ...args);
|
||||
}
|
||||
|
||||
const toString = Object.prototype.toString;
|
||||
|
||||
export function is(val, type) {
|
||||
return toString.call(val) === `[object ${type}]`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否对象(Object)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isObject(val) {
|
||||
return val !== null && is(val, "Object");
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否数字(Number)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isNumber(val) {
|
||||
return is(val, "Number");
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否字符串(String)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isString(val) {
|
||||
return is(val, "String");
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否函数方法(Function)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isFunction(val) {
|
||||
return typeof val === "function";
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否布尔(Boolean)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isBoolean(val) {
|
||||
return is(val, "Boolean");
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否数组(Array)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isArray(val) {
|
||||
return val && Array.isArray(val);
|
||||
}
|
||||
@@ -67,6 +67,18 @@
|
||||
"style": {
|
||||
"navigationBarTitleText": "通知详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/work/role/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "角色管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/work/role/assign-perm",
|
||||
"style": {
|
||||
"navigationBarTitleText": "角色分配权限"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<wd-img-cropper v-model="avatarShow" :img-src="originalSrc" @confirm="handleAvatarConfirm" />
|
||||
|
||||
<!--用户信息编辑弹出框-->
|
||||
<wd-popup v-model="dialog.visible" position="bottom" custom-style="min-height: 200px;">
|
||||
<wd-popup v-model="dialog.visible" position="bottom">
|
||||
<wd-form
|
||||
v-if="dialog.type === DialogType.ACCOUNT"
|
||||
ref="userProfileFormRef"
|
||||
@@ -77,12 +77,12 @@
|
||||
<wd-input
|
||||
v-model="userProfileForm.nickname"
|
||||
label="昵称"
|
||||
label-width="80px"
|
||||
label-width="160rpx"
|
||||
placeholder="请输入昵称"
|
||||
prop="nickname"
|
||||
:rules="rules.nickname"
|
||||
/>
|
||||
<wd-cell title="性别" title-width="80px" center prop="gender" :rules="rules.gender">
|
||||
<wd-cell title="性别" title-width="160rpx" center prop="gender" :rules="rules.gender">
|
||||
<wd-radio-group v-model="userProfileForm.gender" shape="button" class="ef-radio-group">
|
||||
<wd-radio :value="1">男</wd-radio>
|
||||
<wd-radio :value="2">女</wd-radio>
|
||||
@@ -103,7 +103,7 @@
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.oldPassword"
|
||||
label="原密码"
|
||||
label-width="80px"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请输入原密码"
|
||||
@@ -113,7 +113,7 @@
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.newPassword"
|
||||
label="新密码"
|
||||
label-width="80px"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请输入新密码"
|
||||
@@ -123,7 +123,7 @@
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.confirmPassword"
|
||||
label="确认密码"
|
||||
label-width="80px"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请确认新密码"
|
||||
@@ -145,7 +145,7 @@
|
||||
<wd-input
|
||||
v-model="mobileBindingForm.mobile"
|
||||
label="手机号码"
|
||||
label-width="80px"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入手机号码"
|
||||
prop="mobile"
|
||||
@@ -154,7 +154,7 @@
|
||||
<wd-input
|
||||
v-model="mobileBindingForm.code"
|
||||
label="验证码"
|
||||
label-width="80px"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入验证码"
|
||||
prop="code"
|
||||
@@ -185,7 +185,7 @@
|
||||
<wd-input
|
||||
v-model="emailBindingForm.email"
|
||||
label="邮箱"
|
||||
label-width="80px"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入邮箱"
|
||||
prop="email"
|
||||
@@ -194,7 +194,7 @@
|
||||
<wd-input
|
||||
v-model="emailBindingForm.code"
|
||||
label="验证码"
|
||||
label-width="80px"
|
||||
label-width="160rpx"
|
||||
clearable
|
||||
placeholder="请输入验证码"
|
||||
prop="code"
|
||||
@@ -459,8 +459,8 @@ function touchmoveListener(event) {
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.profile-card {
|
||||
padding: 5px;
|
||||
margin-bottom: 12px;
|
||||
padding: 10rpx;
|
||||
margin-bottom: 24rpx;
|
||||
line-height: 1.1;
|
||||
background-color: rgb(255, 255, 255);
|
||||
border-radius: 16px;
|
||||
@@ -494,13 +494,13 @@ function touchmoveListener(event) {
|
||||
}
|
||||
}
|
||||
.edit-form {
|
||||
padding-top: 20px;
|
||||
padding-top: 40rpx;
|
||||
.ef-radio-group {
|
||||
line-height: 1;
|
||||
text-align: left;
|
||||
}
|
||||
.footer {
|
||||
padding: 12px;
|
||||
padding: 24rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -36,6 +36,7 @@ const gridList = reactive([
|
||||
{
|
||||
icon: "/static/icons/role.png",
|
||||
title: "角色管理",
|
||||
url: "/pages/work/role/index",
|
||||
prem: "sys:role:query",
|
||||
},
|
||||
{
|
||||
|
||||
113
src/pages/work/role/assign-perm.vue
Normal file
113
src/pages/work/role/assign-perm.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="p-l-8 p-b-20">
|
||||
<DaTree
|
||||
ref="DaTreeRef"
|
||||
:data="menuPermOptions"
|
||||
:defaultExpandAll="true"
|
||||
:showCheckbox="true"
|
||||
/>
|
||||
</view>
|
||||
<wd-fab v-model:active="showFab" type="primary" position="right-top" direction="bottom">
|
||||
<wd-button custom-class="custom-button" type="primary" @click="doCheckedTree(rootKeys, true)">
|
||||
全 选
|
||||
</wd-button>
|
||||
<wd-button custom-class="custom-button" type="error" @click="doCheckedTree(rootKeys, false)">
|
||||
全不选
|
||||
</wd-button>
|
||||
<wd-button custom-class="custom-button" type="success" @click="doExpandTree('all', true)">
|
||||
全展开
|
||||
</wd-button>
|
||||
<wd-button custom-class="custom-button" type="warning" @click="doExpandTree('all', false)">
|
||||
全收起
|
||||
</wd-button>
|
||||
</wd-fab>
|
||||
<!-- 底部按钮 -->
|
||||
<view class="footer-buttons" style="">
|
||||
<wd-button size="medium" type="primary" block @click="handleAssignPermSubmit">
|
||||
确 定
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import RoleAPI from "@/api/system/role";
|
||||
import MenuAPI from "@/api/system/menu";
|
||||
import DaTree from "@/components/da-tree/index.vue";
|
||||
import { useMessage } from "wot-design-uni";
|
||||
const message = useMessage();
|
||||
|
||||
let roleId = ref<number>(null); // 操作的角色ID
|
||||
const menuPermOptions = ref<OptionType[]>([]); // 所有菜单
|
||||
let rootKeys = ref<number[]>([]); // 根节点数组
|
||||
const DaTreeRef = ref(); // 树引用
|
||||
const showFab = ref(); // 悬浮按钮是否展开
|
||||
|
||||
/**
|
||||
* 分配菜单权限页面数据初始化
|
||||
*/
|
||||
async function initAssignPerm() {
|
||||
// 获取所有的菜单
|
||||
menuPermOptions.value = await MenuAPI.getOptions(false);
|
||||
console.log("menuPermOptions.value", menuPermOptions.value);
|
||||
rootKeys.value = menuPermOptions.value.map((item) => item.value);
|
||||
// 回显角色已拥有的菜单
|
||||
RoleAPI.getRoleMenuIds(roleId.value).then((data) => {
|
||||
const checkedMenuIds = data;
|
||||
console.log("checkedMenuIds=", checkedMenuIds);
|
||||
if (checkedMenuIds && checkedMenuIds.length > 0) {
|
||||
DaTreeRef.value?.setCheckedKeys(checkedMenuIds, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 展开/收起树节点
|
||||
function doExpandTree(keys, expand) {
|
||||
DaTreeRef.value?.setExpandedKeys(keys, expand);
|
||||
showFab.value = false;
|
||||
}
|
||||
// 选中/取消树节点
|
||||
function doCheckedTree(keys, checked) {
|
||||
DaTreeRef.value?.setCheckedKeys(keys, checked);
|
||||
showFab.value = false;
|
||||
}
|
||||
|
||||
// 分配菜单权限提交
|
||||
function handleAssignPermSubmit() {
|
||||
if (roleId.value) {
|
||||
const checkedMenuIds: number[] = DaTreeRef.value?.getCheckedKeys();
|
||||
RoleAPI.updateRoleMenus(roleId.value, JSON.stringify(checkedMenuIds)).then(() => {
|
||||
uni.showToast({ title: "分配权限成功", icon: "success" });
|
||||
uni.navigateBack({ delta: 1 });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onLoad((options: any) => {
|
||||
if (options && options.id) {
|
||||
roleId.value = options.id;
|
||||
}
|
||||
initAssignPerm();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.footer-buttons {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
padding: 20rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
:deep(.custom-button) {
|
||||
box-sizing: border-box;
|
||||
width: 64px !important;
|
||||
min-width: auto !important;
|
||||
height: 32px !important;
|
||||
margin: 8rpx;
|
||||
border-radius: 16px !important;
|
||||
}
|
||||
</style>
|
||||
319
src/pages/work/role/index.vue
Normal file
319
src/pages/work/role/index.vue
Normal file
@@ -0,0 +1,319 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 筛选 -->
|
||||
<wd-drop-menu>
|
||||
<wd-drop-menu-item ref="filterDropMenu" icon="filter" icon-size="18px" title="筛选">
|
||||
<view>
|
||||
<wd-input
|
||||
v-model="queryParams.keywords"
|
||||
label="关键字"
|
||||
type="text"
|
||||
placeholder="请输入关键字"
|
||||
/>
|
||||
<view class="flex-between py-2">
|
||||
<wd-button class="w-20%" type="info" @click="hendleResetQuery">重置</wd-button>
|
||||
<wd-button class="w-70%" @click="handleQuery">确定</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</wd-drop-menu-item>
|
||||
</wd-drop-menu>
|
||||
<!-- 卡片列表 -->
|
||||
<view class="list-container">
|
||||
<wd-card v-for="item in dataList" class="role-card">
|
||||
<template #title>
|
||||
<view class="flex-between">
|
||||
<view class="flex-center">
|
||||
<view class="ml-2">
|
||||
<view class="font-bold">
|
||||
{{ item.name }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<wd-tag v-if="item.status === 1" type="success" plain>正常</wd-tag>
|
||||
<wd-tag v-else-if="item.status === 0" plain>停用</wd-tag>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<wd-cell-group>
|
||||
<wd-cell title="编码" title-width="150rpx" :value="item.code" />
|
||||
<wd-cell title="排序号" title-width="150rpx" :value="item.sort" />
|
||||
</wd-cell-group>
|
||||
|
||||
<template #footer>
|
||||
<view class="flex-between">
|
||||
<view class="text-left">
|
||||
<wd-text text="创建时间:" size="small" class="font-bold" />
|
||||
<wd-text :text="item.createTime" size="small" />
|
||||
</view>
|
||||
<view class="flex-right">
|
||||
<wd-button size="small" plain @click="handleAction(item)">操作</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</wd-card>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<wd-loadmore :state="loadMoreState" @reload="queryPageData" />
|
||||
</view>
|
||||
<!-- 底部按钮 -->
|
||||
<wd-fab
|
||||
position="left-bottom"
|
||||
:expandable="false"
|
||||
customStyle="width: 1rem; height: 1rem; line-height: 1rem;z-index:9"
|
||||
@click="handleOpenDialog(null)"
|
||||
/>
|
||||
|
||||
<wd-popup v-model="dialog.visible" position="bottom" class="yl-popup">
|
||||
<wd-form ref="roleFormRef" :model="formData" :rules="rules">
|
||||
<wd-cell-group border>
|
||||
<wd-input v-model="formData.name" label="角色名称" prop="name" />
|
||||
<wd-input v-model="formData.code" label="角色编码" prop="code" />
|
||||
<wd-select-picker
|
||||
v-model="formData.dataScope"
|
||||
type="radio"
|
||||
label="数据权限"
|
||||
:columns="dataScopeOptions"
|
||||
:align-right="true"
|
||||
prop="dataScope"
|
||||
/>
|
||||
<wd-cell title="状态" prop="status">
|
||||
<wd-switch v-model="formData.status" :active-value="1" :inactive-value="0" />
|
||||
</wd-cell>
|
||||
<wd-cell title="排序" prop="sort">
|
||||
<wd-input-number v-model="formData.sort" />
|
||||
</wd-cell>
|
||||
</wd-cell-group>
|
||||
</wd-form>
|
||||
<view class="footer">
|
||||
<wd-button type="primary" block @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</wd-popup>
|
||||
<wd-message-box />
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import RoleAPI, { RolePageVO, RolePageQuery, RoleForm } from "@/api/system/role";
|
||||
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
|
||||
import { LoadMoreState } from "wot-design-uni/components/wd-loadmore/types";
|
||||
import { DropMenuItemExpose } from "wot-design-uni/components/wd-drop-menu-item/types";
|
||||
import { FormRules } from "wot-design-uni/components/wd-form/types";
|
||||
import { useMessage } from "wot-design-uni";
|
||||
const message = useMessage();
|
||||
|
||||
const loadMoreState = ref<LoadMoreState>("loading");
|
||||
|
||||
const total = ref(0);
|
||||
|
||||
const queryParams = reactive<RolePageQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
keywords: "",
|
||||
});
|
||||
|
||||
/**
|
||||
* 搜索栏
|
||||
*/
|
||||
const filterDropMenu = ref<DropMenuItemExpose>();
|
||||
|
||||
function handleQuery() {
|
||||
filterDropMenu.value?.close();
|
||||
queryParams.pageNum = 1;
|
||||
dataList.value = [];
|
||||
queryPageData();
|
||||
}
|
||||
/**
|
||||
* 重置查询
|
||||
*/
|
||||
const hendleResetQuery = () => {
|
||||
filterDropMenu.value?.close();
|
||||
queryParams.keywords = "";
|
||||
queryParams.pageNum = 1;
|
||||
dataList.value = [];
|
||||
queryPageData();
|
||||
};
|
||||
|
||||
// 角色列表数据
|
||||
const dataList = ref<RolePageVO[]>([]);
|
||||
|
||||
/**
|
||||
* 查询分页数据
|
||||
*/
|
||||
function queryPageData() {
|
||||
loadMoreState.value = "loading";
|
||||
RoleAPI.getPage(queryParams)
|
||||
.then((data) => {
|
||||
dataList.value?.push(...data.list);
|
||||
total.value = data.total;
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("系统异常", e);
|
||||
})
|
||||
.finally(() => {
|
||||
loadMoreState.value = "finished";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 触底事件
|
||||
*/
|
||||
onReachBottom(() => {
|
||||
if (queryParams.pageNum * queryParams.pageSize < total.value) {
|
||||
queryParams.pageNum++;
|
||||
queryPageData();
|
||||
} else {
|
||||
loadMoreState.value = "finished";
|
||||
}
|
||||
});
|
||||
|
||||
// 操作按钮
|
||||
const handleAction = (item: RolePageVO) => {
|
||||
const actions = ["删除", "分配权限", "编辑"];
|
||||
uni.showActionSheet({
|
||||
itemList: actions,
|
||||
success: ({ tapIndex }) => {
|
||||
switch (actions[tapIndex]) {
|
||||
case "删除":
|
||||
handleDelete(item.id);
|
||||
break;
|
||||
case "分配权限":
|
||||
handleAssignPerm(item.id);
|
||||
break;
|
||||
case "编辑":
|
||||
handleOpenDialog(item.id);
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
});
|
||||
|
||||
const dataScopeOptions = ref<Record<string, any>[]>([
|
||||
{ label: "全部数据", value: 0 },
|
||||
{ label: "部门及子部门数据", value: 1 },
|
||||
{ label: "本部门数据", value: 2 },
|
||||
{ label: "本人数据", value: 3 },
|
||||
]);
|
||||
|
||||
const formData = reactive<RoleForm>({});
|
||||
|
||||
const rules: FormRules = {
|
||||
name: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
|
||||
code: [{ required: true, message: "请输入角色编码", trigger: "blur" }],
|
||||
dataScope: [{ required: true, message: "请选择数据权限", trigger: "blur" }],
|
||||
status: [{ required: true, message: "请选择状态", trigger: "change" }],
|
||||
sort: [{ required: true, message: "请输入排序号", trigger: "change" }],
|
||||
};
|
||||
|
||||
const roleFormRef = ref();
|
||||
|
||||
/**
|
||||
* 打开弹窗
|
||||
*/
|
||||
async function handleOpenDialog(id?: number) {
|
||||
dialog.visible = true;
|
||||
formData.id = null;
|
||||
formData.name = "";
|
||||
formData.code = "";
|
||||
formData.dataScope = 0;
|
||||
formData.status = 1;
|
||||
formData.sort = 1;
|
||||
if (id) {
|
||||
RoleAPI.getFormData(id).then((data) => {
|
||||
Object.assign(formData, { ...data });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交保存
|
||||
*/
|
||||
function handleSubmit() {
|
||||
roleFormRef.value.validate().then(({ valid }: { valid: boolean }) => {
|
||||
if (valid) {
|
||||
const roleId = formData.id;
|
||||
if (roleId) {
|
||||
RoleAPI.update(roleId, formData).then(() => {
|
||||
uni.showToast({ title: "修改成功", icon: "success" });
|
||||
dialog.visible = false;
|
||||
queryParams.pageNum = 1;
|
||||
handleQuery();
|
||||
});
|
||||
} else {
|
||||
RoleAPI.add(formData).then(() => {
|
||||
uni.showToast({ title: "添加成功", icon: "success" });
|
||||
dialog.visible = false;
|
||||
queryParams.pageNum = 1;
|
||||
handleQuery();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param id 用户id
|
||||
*/
|
||||
function handleDelete(id: number) {
|
||||
message
|
||||
.confirm({
|
||||
msg: "确认删除角色吗?",
|
||||
title: "提示",
|
||||
})
|
||||
.then(() => {
|
||||
RoleAPI.deleteByIds(id + "").then(() => {
|
||||
uni.showToast({ title: "删除成功", icon: "success" });
|
||||
queryParams.pageNum = 1;
|
||||
handleQuery();
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("点击了取消按钮");
|
||||
});
|
||||
}
|
||||
|
||||
function handleAssignPerm(id: number) {
|
||||
uni.navigateTo({
|
||||
url: "/pages/work/role/assign-perm?id=" + id,
|
||||
});
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.wd-drop-menu .wd-drop-menu__item) {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0 50rpx;
|
||||
}
|
||||
.list-container {
|
||||
.role-card {
|
||||
margin-top: 20rpx;
|
||||
:deep(.wd-cell__wrapper) {
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
:deep(.wd-cell) {
|
||||
padding-right: 10rpx;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.wd-fab__trigger) {
|
||||
width: 80rpx !important;
|
||||
height: 80rpx !important;
|
||||
}
|
||||
.yl-popup {
|
||||
.footer {
|
||||
margin: 30rpx 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user