loong-component

0.11.24-rc.9 • Public • Published

Loong-Component 组件库

cover

基于 Vue + ElementUI

介绍:

  • 借助快速搭建平台能够快速生成页面;
  • 内置常用一些业务组件,例如列表、编辑表单、查看表单、弹窗等等;
  • 基于elementUI组件二次封装,将参数进行规范统一;
  • 支持动态插槽、绑定事件等;
  • 等等

开发指南

引入与全局配置

安装

yarn add loong-component --save

全局引入

loong-component组件自带了许多常用功能,包括axios的封装引入,element-UI的一些常用组件.

import Vue from "Vue" ;
import loong,{elementUI} from "loong-component";//elementUI引入以及其他公共函数引入
import "loong-component/lib/loong-component.css";

Vue.use(loong,{options})// 引入组件,并进行全局默认配置
Vue.use(elementUI);//项目用了loong组件库,可不需在单独安装elementUI

全局axios封装

组件中统一使用的axios,为了和系统中的axios统一,可以对同一个axios进行统一封装拦截
将原来引用的axios改为import {ljAxios} from "loong-component";即可

options配置参数api:

类型:【Object】
可在全局引入时定义全局的组件参数,该参数定义权重较低,可在单独页面使用中通过对象绑定进行覆盖

options.inputConfig 输入组件配置

类型:【Object】

options.inputConfig.action

类型:【String】
文件上传地址

options.inputConfig.paramName

类型:【String】
文件上传请求时,文件传输的键,默认为file

options.inputConfig.renderFile

类型:【Function】
文件渲染的请求方法,异步方法,返回值为url,name。url需要可以在img标签的src中直接展示
参数:data为当前文件对象

renderFile: async (data) => {
   try {
       if (typeof data === 'string') {
           data = await getAttachment(data);
       }
       let url;
       let ext = "bmp,jpg,png,tif,gif,pcx,tga,exif,fpx,svg,psd,cdr,pcd,dxf,ufo,eps,ai,raw,wmf,webp,avif,apng";
       if (ext.indexOf(data.extension.toLowerCase()) > -1) {
           let responseData = await downloadFile(data.downPath);
           let blob = new Blob([responseData.data])
           url = window.URL.createObjectURL(blob);
           console.log('url :>> ', url);
       }
       return {
           url: url || "??",
           name: `${data.fileName}.${data.extension}`,
           ext: data.extension,
           _file: data
       }
    } catch (e) {
    }
}

options.inputConfig.downloadFile

类型:【Function】
文件下载方法,可定义下载的请求方法
参数:data=文件列表当前对象

async downloadFile(data) {
        let responseData = await downLoadFile({fileId: data.id, fileName: data.name, d: 0}, 'blob');
        let blob = new Blob([responseData.data])
        let downloadElement = document.createElement('a')
        let href = window.URL.createObjectURL(blob); //创建下载的链接
        downloadElement.href = href;
        downloadElement.download = data.name; //下载后文件名
        document.body.appendChild(downloadElement);
        downloadElement.click(); //点击下载
        document.body.removeChild(downloadElement); //下载完成移除元素
        window.URL.revokeObjectURL(href); //释放blob对象
    }

options.list 列表相关配置

类型:【Object】

options.list.renderDataFiltersItems

类型:【Function】
列表数据权限统一管理,对单位、部门、人员进行不同权限数据过滤展示,实现对数据进行过滤. 可参考[网办系统-案件列表]

 async renderDataFiltersItems: (listVue) => {
            const _this = listVue.$parent;
            const user = listVue.$store.state.user;//id depId unitId
            let page = 1;
            let items = [
                {
                    // labelWidth: "60px",
                    elementType: "select",
                    name: "unitId",
                    value: "",
                    clearable: true,
                    filterable: true,
                    options: [],
                    label: "单位",
                    placeholder: "请选择单位",
                    span: 6,
                    width: "100%",
                    event: {
                        change: (e) => {
                            getDepTreeData(e);
                        }
                    }
                },
                {
                    labelWidth: "80px",
                    elementType: "treeSelect",
                    value: [],
                    noOptionsText: '暂无部门数据',
                    placeholder: "请选择部门",
                    label: "部门",
                    name: "depIds",
                    defaultExpandLevel: 999,
                    options: [],
                    clearable: true,
                    zIndex: 3001,
                    appendToBody: true,
                    multiple: true,
                    limit: 1,
                    showCount: true,
                    noChildrenText: "当前无下级部门",
                    // branchNodesFirst: true,
                    valueConsistsOf: "ALL",
                    limitText: (count) => {
                        return `+${count}`
                    },
                    normalizer: (d) => {
                        return {
                            ...d,
                            children: d.sub === null ? [] : d.sub,
                            value: d.id,
                            label: d.name,
                        }
                    },
                    span: 7,
                    width: "100%",
                    event: {
                        input: (value, instanceId) => {
                            page = 1;
                            getLoginUserAvailableUser(value)
                        }
                    }
                },
                {
                    // labelWidth: "60px",
                    elementType: "select",
                    name: "userId",
                    value: "",
                    selectLoadMore: () => {
                        page++;
                        const depItemValue = _this.search.formData.formItems.find(s => s.name === 'depIds')?.value;
                        getLoginUserAvailableUser(depItemValue);
                    },
                    clearable: true,
                    filterable: true,
                    options: [],
                    label: "人员",
                    placeholder: "请选择人员",
                    span: 5,
                    width: "100%",
                },
            ];
            if (_this.search.dataFiltersOverrideItems && _this.search.dataFiltersOverrideItems.length > 0) {
                items = items.map(item => {
                    const overrideItem = _this.search.dataFiltersOverrideItems.find(s => s.name === item.name);
                    if (overrideItem) {
                        item = {
                            ...item,
                            ...overrideItem
                        }
                    }
                    return item
                });
                items = items.filter(s => typeof s.show === 'undefined' || s.show);
            }

            if (_this.search.dataFiltersOverrideCallback && typeof _this.search.dataFiltersOverrideCallback === 'function') {
                items = _this.search.dataFiltersOverrideCallback({
                    items
                });
            }
            _this.search.formData.formItems.unshift(...items);

            //获取部门数据
            let getDepTreeData = async (unitId = null) => {
                if (!_this.search.formData.formItems.find(s => s.name === 'depIds'))
                    return;
                const depsData = await getLoginUserAvailableDepForTreeOptionApi({unitId});
                _this.search.formData.formItems.setOptions("depIds", depsData);
                if (depsData && depsData.length > 0) {
                    let result;
                    if (_this.search.formData.formItems.find(s => s.name === 'depIds')?.multiple) {
                        result = [depsData[0].id];
                        let data = depsData[0];
                        utils.findTreeData(data.sub, result, "id", "sub");
                    } else {
                        result = depsData[0].id;
                    }

                    _this.search.formData.formItems.setValue("depIds", result).setValue('depIds', result, 'name', 'default');

                    //如果部门返回有仅一条数据并且还是当前登录用户的部门时,默认隐藏
                    if (result.length === 1 && depsData[0].id === user.depId && depsData[0].id !== 'all') {
                        _this.search.formData.formItems.setShow("depIds", false);
                    }
                    await getLoginUserAvailableUser(result)
                } else {
                    _this.search.formData.formItems.setValue("depIds", []).setValue('depIds', [], 'name', 'default');
                    _this.search.formData.formItems.setShow("depIds", false);
                    await getLoginUserAvailableUser([])
                }
            };

            //获取当前登录用户可访问用户下拉数据
            let getLoginUserAvailableUser = async (depIds) => {
                if (!_this.search.formData.formItems.find(s => s.name === 'userId'))
                    return;
                let params = {
                    depIds,
                    page: page,
                    limit: 20,
                    unitId: _this.search.formData.formItems.find(s => s.name === 'unitId')?.value
                };
                const userData = await getLoginUserAvailableUserForOptionApi(params);
                const userOption = _this.search.formData.formItems.find(s => s.name === 'userId')?.options;
                let newOptions = userData.list.map(s => {
                    return {label: s.name, value: s.id}
                });
                _this.search.formData.formItems.setOptions("userId", page === 1 ? newOptions : [...userOption, ...newOptions]);
                if (page === 1) {
                    if (newOptions && newOptions.length > 0) {
                        //如果用户返回有仅一条数据并且还是当前登录用户时,默认隐藏
                        if (newOptions.length === 1 && newOptions[0].value === user.id) {
                            _this.search.formData.formItems.setShow("userId", false);
                        }
                        _this.search.formData.formItems.setValue("userId", newOptions[0].value).setValue('userId', newOptions[0].value, 'name', 'default');
                    } else {
                        _this.search.formData.formItems.setValue("userId", "");
                        _this.search.formData.formItems.setShow("userId", false);
                    }
                }
            };

            //初始化
            const unitData = await getLoginUserAvailableUnitForOptionApi({});
            if (unitData && unitData.length > 0) {
                _this.search.formData.formItems.setValue("unitId", unitData[0].id).setValue('unitId', unitData[0].id, 'name', 'default');
                _this.search.formData.formItems.setOptions("unitId", unitData.map(s => {
                    return {label: s.name, value: s.id}
                }))
                let defaultUnitId = unitData[0].id;
                if (unitData.length === 1 && defaultUnitId === user.unitId) {
                    _this.search.formData.formItems.setShow("unitId", false);
                }
                await getDepTreeData(defaultUnitId)
            } else {
                _this.search.formData.formItems.setShow("unitId", false);
                await getDepTreeData()
            }

            listVue.searchLoad = true;
        }

需要此功能需要在指定页面lj-list组件配置,如下:

<template>
<lj-list use-data-filters></lj-list>
</template>

::: tip 提示 如果需要对过滤下拉框下拉框名称以及不展示等详细配置见lj-list组件使用文档 :::

options.list.parseData

类型:【Function】
列表数据渲染方法,其返回参数为接口请求返回体(经过axios过滤后),需抛出页面所需的total及list

 parseData: (res) => {
            return {
                total: res.total,
                list: res.list
            }
        }

options.list.table

类型:【Object】
完美支持element-UI中表格的所有属性 ,其中属性名已转化为小驼峰形式

table: {
        size: "small",
        border: true,
        rowStyle: () => {
            return {
                fontSize: '14px'
            }
        },
        headerCellStyle: () => {
            return {
                fontSize: '14px'
            }
        },
        listType: "card-apart",//可选值 card-apart|simple,推荐使用前者.前者将查询栏、操作栏、表格栏清晰分层.案件产品目前使用该配置
        searchAlone: true
    }
},

options.permission 权限

类型:【Function】
参数:【el:元素dom】【bind:参数对象】
页面元素的权限控制,如果不满足条件可自行对dom进行删除等动作

1.使用了loong-component组件的,组件内部已经加了v-permission,需要在控制元素的对象中添加permissionCode属性作为权限标识
2.其他元素权限控制需在标签上加上 v-permission="yourPermissionCode"

permission(el, bind) {
    const { value } = bind;
    if (value) {
        // 权限值 需要在系统中心的权限管理添加并在角色管理中配置才生效
        const permissionList = store.state?.permissionList;
        // all表示带有管理员权限
        if (permissionList.find(n => n.code === 'all')) {
            return;
        }
        const routerName = router.app._route.name;
        // 根据路由name来区分页面权限
        const target = permissionList.find(item => (item.code === routerName));
        let permissionValue = new Set();
        if (typeof value === 'string') {
            permissionValue = new Set(value.split(","));
        } else if (typeof value === 'object' && Array.isArray(value)) {
            permissionValue = new Set(value);
        }
        const hasPermission = target?.visibleElementCodes.some(s => permissionValue.has(s));
        if (!hasPermission) {
            el.parentNode && el.parentNode.removeChild(el)
        }
    }
}

options.store 状态管理

类型:【Function】
直接传入项目store,组件内部弹窗内部后期可对项目store进行管理及操作.

完整示例

部分函数及接口定义可钉我(@hzw)获取

//引入
import loongComponent, {elementUI} from 'loong-component'
import 'loong-component/lib/loong-component.css'

const inputConfig = {
    action: uploadFileSrc,//上传地址
    paramName: "webFile",//上传请求键,默认为file
    //转换上传回来的数据
    parseData: (data) => {
        let res = data.data;
        //未登录或登录超时,需要重新登录
        switch (res.code) {
            case setting.responseCode.ok://操作成功
                return data.data.data
            case setting.responseCode.noLogin://需要重新登录(跳转)
            case setting.responseCode.sessionTimeout://需要续签 TODO 暂时不处理
                toLogin();
                break;
            default:
                message.error(res.msg);
                toLogin();
                break;
        }
    },
    //渲染数据
    renderFile: async (data) => {
        try {
            if (typeof data === 'string') {
                data = await getAttachment(data);
            }
            let url;
            let ext = "bmp,jpg,png,tif,gif,pcx,tga,exif,fpx,svg,psd,cdr,pcd,dxf,ufo,eps,ai,raw,wmf,webp,avif,apng";
            if (ext.indexOf(data.extension.toLowerCase()) > -1) {
                let responseData = await downloadFile(data.downPath);
                let blob = new Blob([responseData.data])
                url = window.URL.createObjectURL(blob);
                console.log('url :>> ', url);
            }
            return {
                url: url || "??",
                name: `${data.fileName}.${data.extension}`,
                ext: data.extension,
                _file: data
            }
        } catch (e) {
        }
    },
    // //下载文件
    async downloadFile(data) {
        const responseData = await downloadFile(data._file.downPath);
        const blob = new Blob([responseData.data])
        const href = window.URL.createObjectURL(blob);
        let downloadElement = document.createElement('a')
        downloadElement.href = href;
        downloadElement.download = data.name; //下载后文件名
        document.body.appendChild(downloadElement);
        downloadElement.click(); //点击下载
        document.body.removeChild(downloadElement); //下载完成移除元素
        window.URL.revokeObjectURL(href); //释放blob对象
    }
}


Vue.use(loongComponent, {
    //列表相关配置
    list: {
        /**
         * 数据权限过滤
         * @param listVue
         * @return {Promise<void>}
         */
        async renderDataFiltersItems(listVue) {
            const _this = listVue.$parent;
            const user = listVue.$store.state.user;//id depId unitId
            let page = 1;
            let items = [
                {
                    // labelWidth: "60px",
                    elementType: "select",
                    name: "unitId",
                    value: "",
                    clearable: true,
                    filterable: true,
                    options: [],
                    label: "单位",
                    placeholder: "请选择单位",
                    span: 6,
                    width: "100%",
                    event: {
                        change: (e) => {
                            getDepTreeData(e);
                        }
                    }
                },
                {
                    labelWidth: "80px",
                    elementType: "treeSelect",
                    value: [],
                    noOptionsText: '暂无部门数据',
                    placeholder: "请选择部门",
                    label: "部门",
                    name: "depIds",
                    defaultExpandLevel: 999,
                    options: [],
                    clearable: true,
                    zIndex: 3001,
                    appendToBody: true,
                    multiple: true,
                    limit: 1,
                    showCount: true,
                    noChildrenText: "当前无下级部门",
                    // branchNodesFirst: true,
                    valueConsistsOf: "ALL",
                    limitText: (count) => {
                        return `+${count}`
                    },
                    normalizer: (d) => {
                        return {
                            ...d,
                            children: d.sub === null ? [] : d.sub,
                            value: d.id,
                            label: d.name,
                        }
                    },
                    span: 7,
                    width: "100%",
                    event: {
                        input: (value, instanceId) => {
                            page = 1;
                            getLoginUserAvailableUser(value)
                        }
                    }
                },
                {
                    // labelWidth: "60px",
                    elementType: "select",
                    name: "userId",
                    value: "",
                    selectLoadMore: () => {
                        page++;
                        const depItemValue = _this.search.formData.formItems.find(s => s.name === 'depIds')?.value;
                        getLoginUserAvailableUser(depItemValue);
                    },
                    clearable: true,
                    filterable: true,
                    options: [],
                    label: "人员",
                    placeholder: "请选择人员",
                    span: 5,
                    width: "100%",
                },
            ];
            if (_this.search.dataFiltersOverrideItems && _this.search.dataFiltersOverrideItems.length > 0) {
                items = items.map(item => {
                    const overrideItem = _this.search.dataFiltersOverrideItems.find(s => s.name === item.name);
                    if (overrideItem) {
                        item = {
                            ...item,
                            ...overrideItem
                        }
                    }
                    return item
                });
                items = items.filter(s => typeof s.show === 'undefined' || s.show);
            }

            if (_this.search.dataFiltersOverrideCallback && typeof _this.search.dataFiltersOverrideCallback === 'function') {
                items = _this.search.dataFiltersOverrideCallback({
                    items
                });
            }
            _this.search.formData.formItems.unshift(...items);

            //获取部门数据
            let getDepTreeData = async (unitId = null) => {
                if (!_this.search.formData.formItems.find(s => s.name === 'depIds'))
                    return;
                const depsData = await getLoginUserAvailableDepForTreeOptionApi({unitId});
                _this.search.formData.formItems.setOptions("depIds", depsData);
                if (depsData && depsData.length > 0) {
                    let result;
                    if (_this.search.formData.formItems.find(s => s.name === 'depIds')?.multiple) {
                        result = [depsData[0].id];
                        let data = depsData[0];
                        utils.findTreeData(data.sub, result, "id", "sub");
                    } else {
                        result = depsData[0].id;
                    }

                    _this.search.formData.formItems.setValue("depIds", result).setValue('depIds', result, 'name', 'default');

                    //如果部门返回有仅一条数据并且还是当前登录用户的部门时,默认隐藏
                    if (result.length === 1 && depsData[0].id === user.depId && depsData[0].id !== 'all') {
                        _this.search.formData.formItems.setShow("depIds", false);
                    }
                    await getLoginUserAvailableUser(result)
                } else {
                    _this.search.formData.formItems.setValue("depIds", []).setValue('depIds', [], 'name', 'default');
                    _this.search.formData.formItems.setShow("depIds", false);
                    await getLoginUserAvailableUser([])
                }
            };

            //获取当前登录用户可访问用户下拉数据
            let getLoginUserAvailableUser = async (depIds) => {
                if (!_this.search.formData.formItems.find(s => s.name === 'userId'))
                    return;
                let params = {
                    depIds,
                    page: page,
                    limit: 20,
                    unitId: _this.search.formData.formItems.find(s => s.name === 'unitId')?.value
                };
                const userData = await getLoginUserAvailableUserForOptionApi(params);
                const userOption = _this.search.formData.formItems.find(s => s.name === 'userId')?.options;
                let newOptions = userData.list.map(s => {
                    return {label: s.name, value: s.id}
                });
                _this.search.formData.formItems.setOptions("userId", page === 1 ? newOptions : [...userOption, ...newOptions]);
                if (page === 1) {
                    if (newOptions && newOptions.length > 0) {
                        //如果用户返回有仅一条数据并且还是当前登录用户时,默认隐藏
                        if (newOptions.length === 1 && newOptions[0].value === user.id) {
                            _this.search.formData.formItems.setShow("userId", false);
                        }
                        _this.search.formData.formItems.setValue("userId", newOptions[0].value).setValue('userId', newOptions[0].value, 'name', 'default');
                    } else {
                        _this.search.formData.formItems.setValue("userId", "");
                        _this.search.formData.formItems.setShow("userId", false);
                    }
                }
            };

            //初始化
            const unitData = await getLoginUserAvailableUnitForOptionApi({});
            if (unitData && unitData.length > 0) {
                _this.search.formData.formItems.setValue("unitId", unitData[0].id).setValue('unitId', unitData[0].id, 'name', 'default');
                _this.search.formData.formItems.setOptions("unitId", unitData.map(s => {
                    return {label: s.name, value: s.id}
                }))
                let defaultUnitId = unitData[0].id;
                if (unitData.length === 1 && defaultUnitId === user.unitId) {
                    _this.search.formData.formItems.setShow("unitId", false);
                }
                await getDepTreeData(defaultUnitId)
            } else {
                _this.search.formData.formItems.setShow("unitId", false);
                await getDepTreeData()
            }

            listVue.searchLoad = true;
        },
        parseData: ({list, total}) => {
            return {
                total: total,
                list: list
            }
        },
        table: {
            size: "small",
            border: true,
            rowStyle: () => {
                return {
                    fontSize: '14px'
                }
            },
            headerCellStyle: () => {
                return {
                    fontSize: '14px'
                }
            },
        },
        listType: "card-apart",
        searchAlone: true
    },
    inputConfig,
    store: store,
    //权限控制
    //1.使用了loong-component组件的,组件内部已经加了v-permission,无需单独添加,但需加 permissionCode 作为权限标识
    //2.未使用loong-component的,自己需要在标签上添加v-permission自定义属性
    permission(el, bind) {
        const {value} = bind;
        if (value) {
            // 权限值 需要在系统中心的权限管理添加并在角色管理中配置才生效
            const permissionList = store.state?.permissionList;
            // all表示带有管理员权限
            if (permissionList.find(n => n.code === 'all')) {
                return;
            }
            const routerName = router.app._route.name;
            // 根据路由name来区分页面权限
            const target = permissionList.find(item => (item.code === routerName));
            let permissionValue = new Set();
            if (typeof value === 'string') {
                permissionValue = new Set(value.split(","));
            } else if (typeof value === 'object' && Array.isArray(value)) {
                permissionValue = new Set(value);
            }
            const hasPermission = target?.visibleElementCodes.some(s => permissionValue.has(s));
            if (!hasPermission) {
                el.parentNode && el.parentNode.removeChild(el)
            }
        }
    }
});
Vue.use(elementUI);

Readme

Keywords

none

Package Sidebar

Install

npm i loong-component

Weekly Downloads

17

Version

0.11.24-rc.9

License

none

Unpacked Size

24 MB

Total Files

81

Last publish

Collaborators

  • xx576816