VUE element-ui实现表格动态展示、动态删减列、动态排序、动态搜索条件配置、表单组件化。

1、实现效果

 

 

1.1、文件目录

1.2、说明

1、本组件支持列表的表头自定义配置,checkbox实现

2、本组件支持列表列排序,vuedraggable是拖拽插件,上图中字段管理里的拖拽效果 ,需要的话请自行npm install

3、本组件支持查询条件动态配置,穿梭框实现

 2、index.vue(最父级,调用入口)

<template><div class="allCustomer-container"><!-- 给el-row加上mb8 mpc-section 的class--><el-row :gutter="10"><el-col :span="1.5"><el-button type="primary" size="mini" @click="handleInsert">新增</el-button></el-col></el-row><zn-query-form><zn-query-form-top-panel><!-- 字段管理 --><field-management @setColumns="getColumns" :options="options" /><el-popover placement="right" width="650" style="margin-right: 20px" trigger="click"><el-transfer v-model="transfers" :props="{ key: 'name', label: 'label'}" :titles="['待选择', '已选择']" @change="rightcheckchange":data="options" /><el-button type="text" size="mini" slot="reference" style="border: none;font-size: 14px;margin-left: 10px; "><i class="el-icon-s-tools">过滤器</i></el-button></el-popover><!-- 搜索 --><search @up-Search="upSearch" :options="requestParams" /><!-- 筛选条件 --><!-- <filter-tag :tagList="conditionList" @up-table="tableUpdate" /> --><div class="filter-tag ml-10 mr-10"><el-tag @close="conditionClose(index)" style="margin-left: 10px" v-for="(tag, index) in conditionList" :key="index" closable:type="tag.prop"><span>{{ tag.tagLabel }} :</span><span style="color: red">{{ tag.tagValue }}</span></el-tag></div></zn-query-form-top-panel></zn-query-form><zn-filter-table ref="filterTable" :multiple="true" :tableData="tableList" :finallyColumns="finallyColumns" :deatilsPath="deatilsPath"@selectList="getSelect" @fetch-data="fetchData" :key="datekey" @fetch-edit="fetchEdit" @fetch-update="fetchUpdate" @fetch-del="fetchDel"/><zn-pagination v-show="total > 0" :page.sync="queryForm.page" :limit.sync="queryForm.listRows" @pagination="fetchData" :total="total":algin="'right'" /><!-- 添加修改对话框 --><el-dialog :title="title" :visible.sync="open" append-to-body :close-on-click-modal="false"><zn-form ref="dialofForm" :options="options" :resForm="form" :disabled="disabled" :key="diaKey" @dialog-submit="submit" @dialog-cancel="cancel"/></el-dialog></div>
</template><script>import FieldManagement from './components/FieldManagement'import ZnQueryForm from './components/ZnQueryForm'import ZnQueryFormTopPanel from './components/ZnQueryFormTopPanel'import Search from './components/Search'import ZnPagination from './components/ZnPagination'import ZnFilterTable from './components/ZnFilterTable'import ZnForm from './components/ZnForm'export default {name: 'allCustomer',components: {FieldManagement,ZnQueryForm,ZnQueryFormTopPanel,Search,ZnPagination,ZnFilterTable,ZnForm},provide() {return {mark: 'Member', //特定标识,根据业务模块不同,传输的标识也不同,标识由后端定义(或者字典维护)}},data() {return {title: '',open: false,disabled: false,diaKey: Date.now(),form: {},transfers: [],requestParams: [],total: 0,tableList: [],listLoading: false,queryForm: {page: 1,listRows: 10,keywords: '',_filter: {}, //头部筛选},deatilsPath: '/customer/deatils', //表格当前行跳转路径conditionList: [], //自定义筛选条件columns: [], //筛选条件中的数据checkList: [], //筛选条件中选中的数据multipleList: [], //表格复选多选中的数据datekey: Date.now(),options: [{id: 0,name: 'name',label: '姓名',type: 'text',param: '',isShow: true,isValidate: true,exp: '',extra: {icon: 'file-list-line',},},{id: 1,name: 'age',label: '年龄',type: 'number_range',param: '',isShow: true,isValidate: true,exp: 'age',extra: {icon: 'file-list-line',},},{id: 2,name: 'phone_main',label: '主要电话',type: 'text',param: '',isShow: true,isValidate: true,exp: '',extra: {icon: 'file-list-line',columnStyle: 'labelCall',},},{id: 3,name: 'phone_backup',label: '备用电话',type: 'text',param: '',isShow: true,isValidate: false,exp: '',extra: {icon: 'file-list-line',},},{id: 4,name: 'id_card',label: '身份证号',type: 'text',param: '',isShow: true,isValidate: true,exp: '',extra: {icon: 'file-list-line',},},{id: 5,name: 'birth_day',label: '生日',type: 'date_range',param: '',isShow: true,isValidate: true,exp: '',extra: {icon: 'file-list-line',},},{id: 6,name: 'sex',label: '性别',type: 'select',param: [{label: '未知',value: 0,},{label: '男',value: 1,},{label: '女',value: 2,},],isShow: true,isValidate: true,exp: '',extra: {icon: 'file-list-line',},},{id: 7,name: 'type',label: '老人类型',type: 'select',param: [{value: 101,label: '独居',},{value: 102,label: '孤老',},{value: 103,label: '失独',},{value: 104,label: '其他',},],isShow: true,isValidate: true,exp: '',extra: {icon: 'file-list-line',columnStyle: 'labelTags',labelTags: {101: 'table-status-blue',102: 'table-status-brown',103: 'table-status-green',104: 'table-status-yellow',},},},{id: 8,name: 'street',label: '街道',type: 'text',param: '',isShow: true,isValidate: true,exp: 'street',extra: {icon: 'file-list-line',},},{id: 9,name: 'committee',label: '居委',type: 'text',param: '',isShow: true,isValidate: false,exp: '',extra: {icon: 'file-list-line',},},{id: 10,name: 'address',label: '详细地址',type: 'text',param: '',isShow: true,isValidate: false,exp: '',extra: {icon: 'file-list-line',},},{id: 11,name: 'reg_address',label: '户籍地址',type: 'text',param: '',isShow: true,isValidate: true,exp: '',extra: {icon: 'file-list-line',},},{id: 12,name: 'source',label: '来源',type: 'text',param: [],isShow: true,isValidate: false,exp: '',extra: {icon: 'file-list-line',},},{id: 13,name: 'create_time',label: '创建时间',type: 'datetime_range',param: '',isShow: true,isValidate: false,exp: '',extra: {icon: 'file-list-line',},},{id: 14,name: 'update_time',label: '更新时间',type: 'datetime_range',param: '',isShow: true,isValidate: false,exp: '',extra: {icon: 'file-list-line',},},{id: 15,name: 'create_user_id',label: '创建人',type: 'text',param: '',isShow: true,isValidate: false,exp: '',extra: {icon: 'file-list-line',},},{id: 16,name: 'update_user_id',label: '更新人',type: 'text',param: '',isShow: true,isValidate: false,exp: '',extra: {icon: 'file-list-line',},},{id: 17,name: 'enable_flag',label: '启用状态',type: 'radio',param: [{value: 1,label: '启用',},{value: 0,label: '停用',}],isShow: true,isValidate: true,exp: '',extra: {icon: 'file-list-line',},},],}},computed: {finallyColumns() {let list = this.columns.filter((item) => this.checkList.includes(item.label))console.log(list)//这里更新了datekey ,组件就会刷新this.datekey = Date.now()return list},},watch: {},created() {this.fetchData()},mounted() { },methods: {// 新增弹出handleInsert() {this.title = '新增信息';this.open = true;this.disabled = false;this.form = {};//这里更新了diaKey ,组件就会刷新this.diaKey = Date.now()},//详情fetchEdit(data) {this.title = '详情查看';this.open = true;this.disabled = true;this.form = data;//这里更新了diaKey ,组件就会刷新this.diaKey = Date.now()},//修改fetchUpdate(data) {this.title = '修改信息';this.open = true;this.disabled = false;this.form = data;//这里更新了diaKey ,组件就会刷新this.diaKey = Date.now()},//删除fetchDel(data) {this.$confirm('是否确认删除选中的数据项?', "系统提示", {closeOnClickModal: false,confirmButtonText: "确定",cancelButtonText: "取消",type: "warning"}).then(function () {return true;}).then(() => {this.$message({message: '删除成功',type: 'success'});}).catch(function () { });//这里更新了diaKey ,组件就会刷新this.diaKey = Date.now()},//取消cancel(data) {this.open = false},//提交submit(data) {console.log(data)if (data.id != undefined) {this.$message({message: '修改成功',type: 'success'});this.open = false} else {this.$message({message: '新增成功',type: 'success'});this.open = false}this.open = false},rightcheckchange() {this.requestParams = [];for (let i = 0; i < this.transfers.length; i++) {for (let j = 0; j < this.options.length; j++) {if (this.transfers[i] === this.options[j].name) {this.requestParams.push(this.options[j])}}}},// 自定义检索(popover组件(data为对象)和tag组件(data为数组))发射出来的事件tableUpdate(data) {this.$refs.filterTable.tableUpdate(data)},conditionClose(index) {this.conditionList.splice(index, 1) // 关闭条件tag-发射给父组件 删除已选中的},// 请求table数据async fetchData(arr) {this.listLoading = true//根据后端要求格式特殊处理if (Array.isArray(arr) && arr.length > 0) {this.conditionList = arr //筛选tag赋值//调用tag组件this.queryForm._filter = {} //每次进来置空arr.forEach((item) => {this.queryForm._filter[item['fieldName']] = item['value']})}this.tableList = [{id: 1,type: 101,enable_flag: 1,name: '柳倩倩',marital_status: {value: 0,label: '--',},phone_main: '0215567252',phone_backup: '18221274181',id_card: '350583199202224336',birth_day: '1976-03-02',tags: ['123124'],sex: 2,province: '上海市',city: '市辖区',area: '松江区',street: '松江工业区',committee: '松江工业区虚拟社区',address: '泰晤士小镇',reg_address: '户籍',remark: '',status: 1,general_info: '',medical_card: null,blood_type: 'A',health_info: '',physical_condition: null,basic_info: null,allergic_drugs: null,medical_records: null,is_contract: 0,contract_imgs: [],source: '',create_time: '2022-01-18 10:52:45',update_time: '2022-04-06 18:28:28',create_user_id: 0,update_user_id: 0,contract: 1,category: [],frequency: '',service_start: null,service_end: null,service_status: {value: 1,label: '正常',},service_cancel_reason: {value: 0,label: '--',},agent_id: {value: 1,label: 'admin',},age: 46,},{id: 2,type: 102,enable_flag: 1,name: '潘宗磊',marital_status: 0,phone_main: '13822223333',phone_backup: '18817673315',id_card: '34240119881214323X',birth_day: '1988-12-14',tags: ['老人', '身体不便', '高血压'],sex: 2,province: '安徽省',city: '六安市',area: '裕安区',street: '九里亭街道',committee: '泉水村委会',address: '泉水冲',reg_address: '上海市松江区泰晤士小镇',remark: '备注111',status: 1,general_info: '',medical_card: '123123',blood_type: {value: 'AB',label: 'AB',},health_info: '',physical_condition:'<p><font color="#c24f4a"><b><i>正常</i></b></font><span style="font-size: 14px;"></span></p>',basic_info: '<p>11</p>',allergic_drugs: '<p>22</p>',medical_records: '<p>33</p>',is_contract: 0,contract_imgs: [],source: ' -- ',create_time: '2022-01-18 11:01:06',update_time: '2022-04-09 15:38:23',create_user_id: 0,update_user_id: 0,contract: {value: 1,label: '幸福久久',},category: ['2', '3'],frequency: {value: 1,label: '一周两次',},service_start: '2022-04-20',service_end: '2022-04-30',service_status: {value: 2,label: '取消',},service_cancel_reason: {value: 3,label: '搬迁',},agent_id: {value: 1,label: 'admin',},age: 33,},{id: 3,type: 103,enable_flag: 1,name: '宋岩',marital_status: {value: 0,label: '--',},phone_main: '',phone_backup: '13917303249',id_card: '350583199202224336',birth_day: '2022-01-13',tags: [],sex: 1,province: '上海市',city: '市辖区',area: '松江区',street: '岳阳街道',committee: '醉白池社区居委会',address: '新凯城',reg_address: null,remark: '',status: 1,general_info: '',medical_card: null,blood_type: {value: 'A',label: 'A',},health_info: '',physical_condition: null,basic_info: null,allergic_drugs: null,medical_records: null,is_contract: 0,contract_imgs: [],source: ' -- ',create_time: '2022-01-18 11:42:19',update_time: '2022-02-15 15:07:14',create_user_id: 0,update_user_id: 0,contract: {value: 1,label: '幸福久久',},category: [],frequency: {value: '',label: ' -- ',},service_start: null,service_end: null,service_status: {value: 1,label: '正常',},service_cancel_reason: {value: 0,label: '--',},agent_id: {value: 1,label: 'admin',},age: 0,},{id: 4,type: 104,enable_flag: 1,name: '李三',marital_status: 0,phone_main: '',phone_backup: '13917303249',id_card: '350583199202224336',birth_day: '2022-01-04',tags: [],sex: 1,province: '天津市',city: '市辖区',area: '河西区',street: '下瓦房街道',committee: '台北路社区居委会',address: '发达',reg_address: null,remark: '',status: 1,general_info: '',medical_card: null,blood_type: {value: '',label: ' -- ',},health_info: '',physical_condition: null,basic_info: null,allergic_drugs: null,medical_records: null,is_contract: 0,contract_imgs: [],source: ' -- ',create_time: '2022-01-18 12:03:59',update_time: '2022-02-18 17:01:12',create_user_id: 0,update_user_id: 0,contract: {value: 1,label: '幸福久久',},category: [],frequency: {value: '',label: ' -- ',},service_start: null,service_end: null,service_status: {value: 1,label: '正常',},service_cancel_reason: {value: 0,label: '--',},agent_id: {value: 1,label: 'admin',},age: 0,},{id: 5,type: 102,enable_flag: 1,name: '张三',marital_status: 0,phone_main: '',phone_backup: '18221274181',id_card: '51382219941101899X',birth_day: '1994-11-30',tags: [],sex: 1,province: '上海市',city: '市辖区',area: '松江区',street: '中山街道',committee: '中山苑社区居委会',address: '泰晤士小镇卡纳比岛',reg_address: null,remark: '',status: 1,general_info: '',medical_card: null,blood_type: {value: 'O',label: 'O',},health_info: '',physical_condition: null,basic_info: null,allergic_drugs: null,medical_records: null,is_contract: 0,contract_imgs: [],source: ' -- ',create_time: '2022-01-18 12:05:45',update_time: '2022-01-25 17:34:37',create_user_id: 0,update_user_id: 0,contract: {value: 1,label: '幸福久久',},category: [],frequency: {value: '',label: ' -- ',},service_start: null,service_end: null,service_status: {value: 1,label: '正常',},service_cancel_reason: {value: 0,label: '--',},agent_id: {value: 1,label: 'admin',},age: 27,},{id: 6,type: 102,enable_flag: 1,name: '陈情期',marital_status: 0,phone_main: '0215567252',phone_backup: '18817673315',id_card: '350583199202224336',birth_day: '2022-01-05',tags: [],sex: 2,province: '上海市',city: '市辖区',area: '松江区',street: '松江工业区',committee: '松江工业区虚拟社区',address: '新凯城',reg_address: null,remark: '',status: 1,general_info: '',medical_card: null,blood_type: {value: 'A',label: 'A',},health_info: '',physical_condition: null,basic_info: null,allergic_drugs: null,medical_records: null,is_contract: 0,contract_imgs: [],source: ' -- ',create_time: '2022-01-18 14:44:58',update_time: '2022-02-17 14:39:08',create_user_id: 0,update_user_id: 0,contract: {value: 1,label: '幸福久久',},category: [],frequency: {value: '',label: ' -- ',},service_start: null,service_end: null,service_status: {value: 1,label: '正常',},service_cancel_reason: {value: 0,label: '--',},agent_id: {value: 1,label: 'admin',},age: 0,},{id: 7,type: 102,enable_flag: 1,name: '李斯',marital_status: {value: 0,label: '--',},phone_main: '0215567252',phone_backup: '18221274180',id_card: '51382219941101899X',birth_day: '2019-01-18',tags: [],sex: 0,province: '四川省',city: '成都市',area: '锦江区',street: '锦官驿街道',committee: '水井坊社区居委会',address: '卡纳比岛',reg_address: null,remark: '',status: 1,general_info: '',medical_card: null,blood_type: {value: 'A',label: 'A',},health_info: '良好',physical_condition: null,basic_info: null,allergic_drugs: null,medical_records: null,is_contract: 0,contract_imgs: [],source: ' -- ',create_time: '2022-01-18 15:14:29',update_time: '2022-02-19 17:32:08',create_user_id: 0,update_user_id: 0,contract: {value: 1,label: '幸福久久',},category: [],frequency: {value: '',label: ' -- ',},service_start: null,service_end: null,service_status: {value: 1,label: '正常',},service_cancel_reason: {value: 0,label: '--',},agent_id: {value: 1,label: 'admin',},age: 3,},{id: 8,type: 102,enable_flag: 1,name: '李请',marital_status: {value: 0,label: '--',},phone_main: '0215567252',phone_backup: '18221274181',id_card: '350583199202224336',birth_day: '2022-01-04',tags: [],sex: 1,province: '上海市',city: '市辖区',area: '松江区',street: '松江工业区',committee: '松江工业区虚拟社区',address: '泰晤士小镇',reg_address: null,remark: '',status: 1,general_info: '',medical_card: null,blood_type: {value: 'A',label: 'A',},health_info: '',physical_condition: null,basic_info: null,allergic_drugs: null,medical_records: null,is_contract: 0,contract_imgs: [],source: ' -- ',create_time: '2022-01-18 15:42:02',update_time: '2022-01-25 17:33:23',create_user_id: 0,update_user_id: 0,contract: {value: 1,label: '幸福久久',},category: [],frequency: {value: '',label: ' -- ',},service_start: null,service_end: null,service_status: {value: 1,label: '正常',},service_cancel_reason: {value: 0,label: '--',},agent_id: {value: 1,label: 'admin',},age: 0,},{id: 9,type: 102,enable_flag: 1,name: '柳慢慢',marital_status: {value: 0,label: '--',},phone_main: '0215567252',phone_backup: '18221274182',id_card: '350583199202224336',birth_day: '1945-06-05',tags: [],sex: 1,province: '上海市',city: '市辖区',area: '松江区',street: '岳阳街道',committee: '龙潭社区居委会',address: '新凯城',reg_address: null,remark: '',status: 1,general_info: '',medical_card: null,blood_type: {value: 'A',label: 'A',},health_info: '',physical_condition: null,basic_info: null,allergic_drugs: null,medical_records: null,is_contract: 0,contract_imgs: [],source: ' -- ',create_time: '2022-01-18 19:58:02',update_time: '2022-02-16 11:18:17',create_user_id: 0,update_user_id: 0,contract: {value: 1,label: '幸福久久',},category: [],frequency: {value: '',label: ' -- ',},service_start: null,service_end: null,service_status: {value: 1,label: '正常',},service_cancel_reason: {value: 0,label: '--',},agent_id: {value: 1,label: 'admin',},age: 76,},{id: 10,type: 102,enable_flag: 1,name: '小千',marital_status: {value: 0,label: '--',},phone_main: '',phone_backup: '18221274181',id_card: '350583199202224336',birth_day: '2022-01-03',tags: [],sex: 1,province: '上海市',city: '市辖区',area: '松江区',street: '岳阳街道',committee: '龙潭社区居委会',address: '新凯城',reg_address: null,remark: '',status: 1,general_info: '',medical_card: null,blood_type: {value: 'B',label: 'B',},health_info: '',physical_condition: null,basic_info: null,allergic_drugs: null,medical_records: null,is_contract: 0,contract_imgs: [],source: ' -- ',create_time: '2022-01-18 20:00:32',update_time: '2022-01-25 17:33:03',create_user_id: 0,update_user_id: 0,contract: {value: 1,label: '幸福久久',},category: [],frequency: {value: '',label: ' -- ',},service_start: null,service_end: null,service_status: {value: 1,label: '正常',},service_cancel_reason: {value: 0,label: '--',},agent_id: {value: 1,label: 'admin',},age: 0,},],this.total = this.tableList.lengththis.listLoading = false},// 更新搜索字段,更新table数据upSearch(val) {console.log("父页面收到查询条件")this.queryForm = valconsole.log(this.queryForm)this.fetchData()},// 获取多选选中的table数据(需求未出,功能暂留)getSelect(list) {this.multipleList = listalert('list', list)},// 子组件筛选条件返回getColumns(columns, checkList) {this.columns = columnsthis.checkList = checkList},},}
</script><style lang="scss" scoped>.el-button {border: none;margin-bottom: 0;}::v-deep.pop-li {.el-button {color: black !important;}}
</style>

3、FieldManagement组件

<template><el-dropdown class="ml-10 mr-10" trigger="hover"><el-button type="text" size="medium" ><i class="el-icon-tickets">字段管理</i></el-button><el-dropdown-menu slot="dropdown"><el-row :gutter="10" type="flex" class="row-flex"><el-col :span="6"><el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">勾选您要选择的字段</el-checkbox></el-col><el-divider /><el-checkbox-group v-if="options.length > 0" v-model="checkList" @change="handleCheckedChange"><zn-draggable v-bind="dragOptions" :list="options" class="zn-draggable" v-model="options" @sort="dragSort"><el-col :span="24" class="checkbox-group-col" v-for="item in options" :key="item.id"><!-- <zn-icon icon="drag-drop-line" /> --><el-checkbox :label="item.label">{{ item.label }}</el-checkbox></el-col></zn-draggable></el-checkbox-group></el-row></el-dropdown-menu></el-dropdown>
</template><script>import ZnDraggable from 'vuedraggable'export default {name: 'fieldManagement',components: {ZnDraggable,},inject: ['mark'],props: {options: {type: Array, // table数据default: () => [],},},data() {return {checkAll: false,checkList: [],options: [],isIndeterminate: true,}},computed: {dragOptions() {return {animation: 600,group: 'description',}},},watch: {},created() {this.getHeader()},mounted() { },methods: {dragSort(e) {// e.newIndex 为draggable插件给的值this.options[e.newIndex].sort = e.newIndex + 1;// 重新排序this.options.map((item, index) => {item.sort = index + 1;})//对checkList进行排序let sortCheck = [];this.options.map((item) => {if (this.checkList.includes(item.label)) {sortCheck.push(item)}})let checks = []sortCheck.map((item) => {checks.push(item.label)})this.$emit('setColumns', this.options, checks)},// 字段管理的接口是统一的 , 只有业务模块的mark标识不同 , 所以请求就写在了组件里async getHeader() {this.options.map((item) => {if (item.isShow == true) {this.checkList.push(item.label)}})this.checkAll = this.checkList.length === this.options.lengththis.isIndeterminate = this.checkList.length > 0 && this.checkList.length < this.options.lengththis.$emit('setColumns', this.options, this.checkList)},// 操纵全选handleCheckAllChange(val) {if (val) {this.options.map((item) => {this.checkList.push(item.label)})} else {this.checkList = []}this.isIndeterminate = false// 向父组件发送数据this.$emit('setColumns', this.options, this.checkList)},// 单个数据选中handleCheckedChange(value) {let checkedCount = value.lengththis.checkAll = checkedCount === this.options.lengththis.isIndeterminate =checkedCount > 0 && checkedCount < this.options.length// 向父组件发送数据this.$emit('setColumns', this.options, this.checkList)},},}
</script><style lang="scss" scoped>.row-flex {padding: 15px;display: flex;flex-direction: column;}.zn-draggable {display: flex;flex-direction: column;justify-content: flex-start;}.checkbox-group-col {max-height: 100px;overflow-y: auto;.el-checkbox {padding: 3px 0;width: 100%;margin-right: 0;}}
</style>

4、ZnQueryForm组件

<template><el-row class="zn-query-form" :gutter="0"><slot /></el-row></template><script>export default {name: 'ZnQueryForm',}</script><style lang="scss" scoped>@mixin panel {display: flex;flex-wrap: wrap;align-content: center;align-items: center;justify-content: flex-start;min-height: 20px;margin: 0 0 0 0;> .el-button {margin: 0 10px 0 0 !important;}}.zn-query-form {::v-deep {.el-form-item:first-child {margin: 0 0 0 0 !important;}.el-form-item + .el-form-item {margin: 0 0 0 0 !important;.el-button {margin: 0 0 0 10px !important;}}.top-panel {@include panel;}.bottom-panel {@include panel;border-top: 1px solid #dcdfe6;}.left-panel {@include panel;}.right-panel {@include panel;justify-content: flex-end;}}}</style>

5、ZnQueryFormTopPanel组件

<template><el-col :span="24"><div class="top-panel"><slot /></div></el-col></template><script>export default {name: 'ZnQueryFormTopPanel',}</script>

6、Search组件

<template><div><el-form :class="cellStyleForm()" :model="queryParams" ref="queryParams" :inline="true" style="margin-bottom: 10px;"><el-form-item v-for="item in options" :key="item.id" :prop="item.name" style="margin-right: 10px !important"><el-select v-if="item.type === 'select'" v-model="queryParams[item.name]" :placeholder="'请选择'+item.label" @change="handleQuery"clearable filterable><el-option v-for="dict in item.param" :key="dict.value" :label="dict.label" :value="dict.value" /></el-select><!-- date 单个日期--><el-date-picker v-else-if="item.type == 'date'" v-model="queryParams[item.name]" type="date" clearable placeholder="选择日期"value-format="yyyy-MM-dd" @change="handleQuery" /><!-- datetime 日期时间--><el-date-picker v-else-if="item.type == 'datetime'" v-model="queryParams[item.name]" type="datetime" placeholder="选择日期时间"value-format="yyyy-MM-dd HH:mm:ss" @change="handleQuery"></el-date-picker><!-- date_range 日期范围--><el-date-picker v-else-if="item.type == 'date_range'" v-model="queryParams[item.name]" type="daterange" range-separator="至"start-placeholder="开始日期" end-placeholder="结束日期" value-format="yyyy-MM-dd" @change="handleQuery"></el-date-picker><!-- datetime_range 日期时分秒范围--><el-date-picker v-else-if="item.type == 'datetime_range'" v-model="queryParams[item.name]" clearable type="datetimerange"range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" value-format="yyyy-MM-dd HH:mm:ss" @change="handleQuery"></el-date-picker><el-input v-else v-model="queryParams[item.name]" clearable :placeholder="'请输入'+item.label" @clear="handleQuery"></el-input></el-form-item><el-form-item class="option-button" style="right: 20px;" v-if="options.length>0"><el-button type="primary" size="mini" @click="handleQuery">查询</el-button></el-form-item></el-form></div>
</template><script>export default {name: 'Search',components: {},props: {options: {type: Array, // table数据default: () => [],},},data() {return {isActive: false,searchText: '',queryParams: {},}},computed: {},// watch: {//   options: {//     deep: true,//     handler(val) {//       this.getOptions(val)//     }//   },// },created() { },mounted() { },methods: {getOptions(item) {for (let i = 0; i < item.length; i++) {let res = item[i]this.queryParams[res.name] = res.value}},cellStyleForm() {if (this.$refs.queryForm) {this.width = this.$refs.queryForm.$el.clientWidthif (226 * (this.requiredParamList.length + 3) + 40 >= this.width) {return 'mpc-section-zkaw'} else {return 'mpc-section'}} else {return 'mpc-section'}},handleQuery() {console.log(this.queryParams)this.$emit('up-Search', this.queryParams) //改变搜索字段的value},},}
</script><style lang="scss" scoped>.public-search {display: inline-block;overflow: hidden;cursor: pointer;border: 1px solid white;}::v-deep.isActive {border: 1px solid red;transition: all 0.3s ease-in-out;}.mpc-section {background-color: #FFFFFF;height: 40px;margin-left: 0px !important;margin-right: 0px !important;display: flex;align-items: center;}.mpc-section-zkaw {background-color: #FFFFFF;/* height: 62px; */margin-left: 0px !important;margin-right: 0px !important;display: flex;align-items: center;}.option-button {position: absolute;right: 10px;}
</style>

7、ZnPagination组件

<template><div :class="{ hidden: hidden }" class="pagination-container"><el-pagination:style="{'text-align':algin}":background="background":current-page.sync="currentPage":page-size.sync="pageSize":layout="layout":page-sizes="pageSizes":total="total"v-bind="$attrs"@size-change="handleSizeChange"@current-change="handleCurrentChange"/></div></template><script>import { scrollTo } from './utils/scroll-to'export default {name: 'ZnPagination',props: {total: {required: true,type: Number,},page: {type: Number,default: 1,},limit: {type: Number,default: 10,},pageSizes: {type: Array,default() {return [10, 20, 30, 50]},},layout: {type: String,default: 'total, sizes, prev, pager, next, jumper',},background: {type: Boolean,default: true,},autoScroll: {type: Boolean,default: true,},hidden: {type: Boolean,default: false,},algin: {type: String,default: ()=>'center',},},computed: {currentPage: {get() {return this.page},set(val) {this.$emit('update:page', val)},},pageSize: {get() {return this.limit},set(val) {this.$emit('update:limit', val)},},},methods: {handleSizeChange(val) {this.$emit('pagination', { page: this.currentPage, limit: val })if (this.autoScroll) {scrollTo(0, 800)}},handleCurrentChange(val) {this.$emit('pagination', { page: val, limit: this.pageSize })if (this.autoScroll) {scrollTo(0, 800)}},},}</script><style lang="scss" scoped>.pagination-container {background: #fff;}.pagination-container.hidden {display: none;}</style>

8、ZnFilterTable组件

<template><div class="filter-table pt-10 pb-10"><!-- 表格 --><el-table ref="table" :data="tableData" style="width: 100%;" border stripe @selection-change="handleSelectionChange" @row-click="toDeatils":header-cell-style="{'text-align':'center'}"><el-table-column type="selection" width="55" align="center" v-if="multiple"></el-table-column><el-table-column v-for="(item, index) in finallyColumns" :key="item.id" :label="item.label" :align="item.type === 'number_range'?'right':item.type === 'select' || item.type === 'radio'?'center':'left'":prop="item.name" min-width="130" show-overflow-tooltip><!-- <template slot="header"><type-popover :columnIndex="index" :column="item" :filterOptions="item.param" @tableUpdate="tableUpdate"></type-popover></template> --><template #default="{ row }"><!-- 每一列涉及value值判断显示label ,以及状态颜色 --><!-- <span v-if="item.extra.columnStyle == 'labelTags'" :class="item.extra.labelTags[row.type.value]">{{ row.type.label }}</span> --><span v-if="item.type === 'select' || item.type === 'radio'"><el-tag>{{ typeFormat(row[item.name],item.param) }}</el-tag></span><span v-else>{{ row[item.name] }}</span></template></el-table-column><!-- 如有操作列 ↓--><el-table-column label="操作" align="center" width="150" fixed="right"><template slot-scope="scope"><el-button size="mini" type="text" @click="handleSelect(scope.row)">详情</el-button><el-button size="mini" type="text" @click="handleUpdate(scope.row)">修改</el-button><el-button size="mini" type="text" @click="handleDelete(scope.row)" class="mpc_del">删除</el-button></template></el-table-column></el-table></div>
</template>
<script>import TypePopover from './TypePopover'import ZnIcon from './ZnIcon'export default {name: 'ZnFilterTable',components: { TypePopover, ZnIcon },props: {tableData: {type: Array, // table数据default: () => [],},finallyColumns: {type: Array, // table数据default: () => [],},multiple: {type: Boolean, // table数据default: () => false,},deatilsPath: {type: String, // table数据default: () => '',},},data() {return {conditionList: [],multipleSelection: [], //table多选数据}},computed: {},mounted() { },methods: {handleSelectionChange(val) {this.multipleSelection = valthis.$emit('selectList', this.multipleSelection)},handleSelect(item) {this.$emit('fetch-edit', item)},handleUpdate(item) {this.$emit('fetch-update', item)},handleDelete(item) {this.$emit('fetch-del', item)},// 自定义检索(popover组件(data为对象)和tag组件(data为数组))发射出来的事件tableUpdate(data) {console.log(data)let flag = true// 筛选条件如果已经存在,就更新,注意判别传递过来的数据类型// arr.constructor === Arrayif (this.conditionList.length === 0) {this.conditionList.push(data) // 如果没有就添加flag = false} else if (this.conditionList.length > 0) {this.conditionList.forEach((item, index) => {if (item.fieldName == data.fieldName) {item.value = data.valueflag = false}})}if (flag) {this.conditionList.push(data.fieldName) // 如果没有就添加}this.$parent.fetchData(this.conditionList)},toDeatils(row) {if (this.deatilsPath) {this.$router.push({ path: this.deatilsPath, query: row.id })} else {this.$baseMessage('请配置所需要跳转的路径','warning','zn-hey-message-warning')}},// 拨打电话makeACall() {},//类型翻译typeFormat(item, params) {return this.selectType(params, item);},// 回显selectType(datas, value) {var actions = [];Object.keys(datas).some((key) => {if (datas[key].value == ('' + value)) {actions.push(datas[key].label);return true;}})return actions.join('');},},}
</script>
<style scoped lang='scss'>.mpc_del {color: red !important;}/* // 占位,解决点击自己写的自定义筛选 会冒泡到排序 */::v-deep .el-table__column-filter-trigger {display: none !important;}::v-deep.filter-table {/* // table状态标签颜色定义 */[class*='table-status'] {display: inline-block;border-radius: 2px;padding: 0px 12px;}/* // 蓝色 */[class*='table-status-blue'] {background: #e6effb;color: #005bd9;}/* // 棕色 */[class*='table-status-brown'] {background: #fff6ec;color: #ffa336;}/* // 绿色 */[class*='table-status-green'] {background: #e8fff0;color: #00b47e;}/* // 黄色 */[class*='table-status-yellow'] {background: #fffae8;color: #f9c200;}/* // 粉色 */[class*='table-status-pink'] {background: #ffece8;color: #f53f3f;}/* // 白色 */[class*='table-status-white'] {background: #f2f3f5;color: #1d2129;}}
</style>

9、TypePopover组件

<template><!-- 每个table表头的popover --><!-- 注意:逻辑部分尽量不好写到这个组件内,因为这个组件是根据外面table循环创建的,在这里写逻辑会非常影响性能 --><div class="customHeader" style="display: inline-block"><el-popoverplacement="bottom"trigger="click":ref="`popover-${columnIndex}`"><!-- table表头文字显示--><span slot="reference" class="label"><zn-icon :icon="column.extra.icon" />{{ column.label }} &nbsp;<i class="el-icon-arrow-down"></i></span><!-- text 文本 --><div v-if="column.type == 'text'"><el-inputclearablev-model.trim="filterForm.value"placeholder="请输入查询内容"@keyup.native.enter="confirm()"></el-input></div><!-- number 数字框 --><div v-else-if="column.type == 'number'"><el-inputclearableoninput="value=value.replace(/[^0-9.]/g,'')"v-model.trim="filterForm.value"placeholder="请输入数字"@keyup.native.enter="confirm()"></el-input></div><!-- number_range 数字范围--><div v-else-if="column.type == 'number_range'"><el-inputstyle="width: 120px"clearableoninput="value=value.replace(/[^0-9.]/g,'')"v-model.trim="filterForm.value"placeholder="请输入数字"></el-input>-<el-inputstyle="width: 120px"clearableoninput="value=value.replace(/[^0-9.]/g,'')"v-model.trim="spareValue"placeholder="请输入数字"></el-input></div><!-- date 单个日期--><div v-else-if="column.type == 'date'"><el-date-pickerv-model="filterForm.value"type="date"clearableplaceholder="选择日期"value-format="yyyy-MM-dd"/></div><!-- datetime 日期时间--><div v-else-if="column.type == 'datetime'"><el-date-pickerv-model="filterForm.value"type="datetime"placeholder="选择日期时间"value-format="yyyy-MM-dd HH:mm:ss"></el-date-picker></div><!-- date_range 日期范围--><div v-else-if="column.type == 'date_range'"><el-date-pickerv-model="filterForm.value"type="daterange"range-separator="至"start-placeholder="开始日期"end-placeholder="结束日期"value-format="yyyy-MM-dd"></el-date-picker></div><!-- datetime_range 日期时分秒范围--><div v-else-if="column.type == 'datetime_range'"><el-date-pickerv-model="filterForm.value"clearabletype="datetimerange"range-separator="至"start-placeholder="开始日期"end-placeholder="结束日期"value-format="yyyy-MM-dd HH:mm:ss"></el-date-picker></div><!-- select 下拉选择--><div v-else-if="column.type == 'select'"><el-selectv-model="filterForm.value"placeholder="请选择"style="width: 100%"clearable><el-optionv-for="(item, index) in filterOptions":key="index":label="item.label":value="item.value"></el-option></el-select></div><!-- radio 单选--><div v-else-if="column.type == 'radio'"><el-radio-group v-model="filterForm.value"><el-radiov-for="(item, index) in filterOptions":key="index":label="item.value":value="item.value">{{ item.label }}</el-radio></el-radio-group></div><!-- checkBox 多选--><div v-else-if="column.type == 'checkBox'"><el-checkbox-group v-model="checkboxList"><el-checkboxv-for="(item, index) in filterOptions":key="index":label="item.value":value="item.value">{{ item.label }}</el-checkbox></el-checkbox-group></div><!-- confirm 确定框--><div style="text-align: right"><el-button@click="confirm()"type="primary"size="mini"class="confirm">确定</el-button></div></el-popover></div></template><script>import ZnIcon from './ZnIcon'export default {name: 'typePopover',components: {ZnIcon},// column 当前列数据,filterOptions 多选/单选/下拉/数据props: ['column', 'filterOptions', 'columnIndex'],data() {return {filterForm: {tagLabel: this.column.label, //筛选tag label(tag用)tagValue: '', //筛选tag value(tag用)value: '', //所筛选的数据(后端接收用)fieldName: this.column.name, //当前表头字段(后端接收用)},spareValue: '', //备用Value popover里如是两个值的话需要用此来拼接checkboxList: [],}},created() {},methods: {confirm() {let minValue = this.filterForm.value //数值双向绑定  做个闭环赋值let type = this.column.type// 跟后端商定 , 多个值存在时进行判断 , 以filterForm.value一个值为字符串的形式传递// 根据需求做了处理// checkBox和radio和select由于value值的原因需要处理if (type == 'checkBox' || type == 'radio' || type == 'select') {if (type == 'checkBox') {this.filterForm.value = this.checkboxList.join(',')}if (this.column.param && this.column.param.length > 0) {let str = ''this.column.param.forEach((i, t) => {if (type == 'checkBox' && i.value == Number(this.checkboxList[t])) {str = str + i.label}if (type == 'radio' && i.value == Number(this.filterForm.value)) {str = str + i.label}if (type == 'select' && i.value == Number(this.filterForm.value)) {str = str + i.label}})this.filterForm.tagValue = str}}// 数字范围else if (type == 'number_range') {this.filterForm.tagValue =this.filterForm.value + ' - ' + this.spareValuethis.filterForm.value = this.filterForm.value + ',' + this.spareValue} else if (this.filterForm.value == '' && !this.spareValue) {return this.$message.warning('请输入或选择筛选条件')} else {this.filterForm.tagValue = this.filterForm.value //其他类型的赋值给tag用}this.$emit('tableUpdate', this.filterForm) //传递的是对象this.filterForm.value = minValue //数值双向绑定  做个闭环赋值 ,俗称瞒天过海this.$refs['popover-' + this.columnIndex].doClose() // 关闭popover},},}</script><style scoped>.confirm {margin-top: 10px;}/* 禁止双击选中文字 */.label {-moz-user-select: none; /*火狐*/-webkit-user-select: none !important; /*webkit浏览器*/-ms-user-select: none; /*IE10*/-khtml-user-select: none; /*早期浏览器*/user-select: none;}.labelColor {color: #409eff;}.el-icon-arrow-down {cursor: pointer;}.el-checkbox-group {display: flex;justify-content: flex-start;flex-direction: column;max-height: 150px;overflow-y: auto;}</style>

10、ZnIcon组件

<template><divv-if="isExternal":style="styleExternalIcon"class="svg-external-icon zn-icon"v-on="$listeners"/><svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners"><use :xlink:href="iconClass" /></svg>
</template><script>
import { isExternal } from '@/utils/validate'export default {name: 'ZnSvgIcon',props: {iconName: {type: String,default: '',required: true,},className: {type: String,default: '',},},computed: {isExternal() {return isExternal(this.iconName)},iconClass() {return `#icon-${this.iconName}`},svgClass() {if (this.className) {return 'zn-icon ' + this.className} else {return 'zn-icon'}},styleExternalIcon() {return {mask: `url(${this.iconName}) no-repeat 50% 50%`,'-webkit-mask': `url(${this.iconName}) no-repeat 50% 50%`,}},},
}
</script><style scoped>
.zn-icon {width: 1rem;height: 1rem;fill: currentColor;overflow: hidden;font-size: 16px;text-align: center;vertical-align: -3px;cursor: pointer;margin-right: 5px;
}
/* .el-button .zn-icon {width: 1rem;height: 1rem;vertical-align: -2.5px;color: inherit;
} */
.zn-icon:hover path {fill: var(--mainTone);
}.svg-external-icon {background-color: currentColor;mask-size: cover !important;display: inline-block;
}
</style>

11、ZnForm组件

<template><div><el-form ref="form" :model="form" :rules="rules" label-width="80px" size="medium"><el-row><div v-for="item in options" :key="item.id"><el-col :span="12" v-if="item.type === 'select'"><el-form-item :label="item.label" :prop="item.name"><el-select v-model="form[item.name]" :placeholder="'请选择'+item.label" clearable filterable style="width: 100%" :disabled="disabled"><el-option v-for="dict in item.param" :key="dict.value" :label="dict.label" :value="dict.value" /></el-select></el-form-item></el-col><el-col :span="12" v-else-if="item.type === 'radio'"><el-form-item :label="item.label" :prop="item.name"><el-radio-group v-model="form[item.name]" :disabled="disabled"><el-radio v-for="dict in item.param" :key="dict.value" :label="dict.value">{{dict.label}}</el-radio></el-radio-group></el-form-item></el-col><!-- date 单个日期--><el-col :span="12" v-else-if="item.type == 'date' || item.type == 'date_range'"><el-form-item :label="item.label" :prop="item.name"><el-date-picker v-model="form[item.name]" type="date" placeholder="选择日期" value-format="yyyy-MM-dd" style="width: 100%" :disabled="disabled" /></el-form-item></el-col><!-- datetime 日期时间--><el-col :span="12" v-else-if="item.type == 'datetime' || item.type == 'datetime_range'"><el-form-item :label="item.label" :prop="item.name"><el-date-picker v-model="form[item.name]" type="datetime" placeholder="选择日期时间" value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%" :disabled="disabled"></el-date-picker></el-form-item></el-col><el-col :span="12" v-else-if="item.type == 'number_range'"><el-form-item :label="item.label" :prop="item.name"><el-input v-model.number="form[item.name]" clearable :placeholder="'请输入'+item.label" :disabled="disabled"></el-input></el-form-item></el-col><el-col :span="12" v-else><el-form-item :label="item.label" :prop="item.name"><el-input v-model="form[item.name]" clearable :placeholder="'请输入'+item.label" :disabled="disabled"></el-input></el-form-item></el-col></div></el-row></el-form><div slot="footer" class="dialog-footer"><el-button type="primary" @click="submit" v-preventReClick="2000" v-if="!disabled">保 存</el-button><el-button @click="cancel">{{buttonName}}</el-button></div></div>
</template><script>export default {name: 'ZnForm',components: {},props: {options: {type: Array, // table数据default: () => [],},disabled:{type: Boolean,default: () => false},resForm:{type: Object,default: () => {}}},watch: {options: {immediate: true,handler(val) {this.getOptions(val)}},resForm: {immediate: true,handler(val) {this.setValue(val)}},disabled: {immediate: true,handler(val) {this.setButtonName(val)}},},data() {return {buttonName:'取 消',rules: {},form: {},//主键暂存id:undefined,ruleParam: [{ required: true, message: "不能为空", trigger: "blur" },],}},created() {},mounted() {},methods: {//设置按钮名称setButtonName(item){if(item){this.buttonName = '关 闭'}else{this.buttonName = '取 消'}},//form赋值setValue(item){this.form = itemif(item.id !== undefined){this.id = item.id}},//表单校验getOptions(item) {let ruleMap = new Map()for (var i in item) {if (item[i].isValidate === true) {this.ruleParam[0].message = item[i].label + "不能为空"ruleMap.set(item[i].name, this.ruleParam)this.ruleParam = [{ required: true, message: "不能为空", trigger: "blur" },]}}//map转对象this.rules = Object.fromEntries(ruleMap.entries())},// 取消按钮cancel() {this.$emit('dialog-cancel', this.form)this.form = {};},/** 提交按钮 */submit: function () {this.form.id = this.id;this.$refs["form"].validate(valid => {if (valid) {this.$emit('dialog-submit', this.form)this.form = {};}});},}}
</script><style lang="scss" scoped>
</style>

12、utils

12.1、encrypt.js

import JSEncrypt from 'jsencrypt'
import { getPublicKey } from '@/api/publicKey'const privateKey ='MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMFPa+v52FkSUXvcUnrGI/XzW3EpZRI0s9BCWJ3oNQmEYA5luWW5p8h0uadTIoTyYweFPdH4hveyxlwmS7oefvbIdiP+o+QIYW/R4Wjsb4Yl8MhR4PJqUE3RCy6IT9fM8ckG4kN9ECs6Ja8fQFc6/mSl5dJczzJO3k1rWMBhKJD/AgMBAAECgYEAucMakH9dWeryhrYoRHcXo4giPVJsH9ypVt4KzmOQY/7jV7KFQK3x//27UoHfUCak51sxFw9ek7UmTPM4HjikA9LkYeE7S381b4QRvFuf3L6IbMP3ywJnJ8pPr2l5SqQ00W+oKv+w/VmEsyUHr+k4Z+4ik+FheTkVWp566WbqFsECQQDjYaMcaKw3j2Zecl8T6eUe7fdaRMIzp/gcpPMfT/9rDzIQk+7ORvm1NI9AUmFv/FAlfpuAMrdL2n7p9uznWb7RAkEA2aP934kbXg5bdV0R313MrL+7WTK/qdcYxATUbMsMuWWQBoS5irrt80WCZbG48hpocJavLNjbtrjmUX3CuJBmzwJAOJg8uP10n/+ZQzjEYXh+BszEHDuw+pp8LuT/fnOy5zrJA0dO0RjpXijO3vuiNPVgHXT9z1LQPJkNrb5ACPVVgQJBALPeb4uV0bNrJDUb5RB4ghZnIxv18CcaqNIft7vuGCcFBAIPIRTBprR+RuVq+xHDt3sNXdsvom4h49+Hky1b0ksCQBBwUtVaqH6ztCtwUF1j2c/Zcrt5P/uN7IHAd44K0gIJc1+Csr3qPG+G2yoqRM8KVqLI8Z2ZYn9c+AvEE+L9OQY='/*** 最长加密长度* @type {number}*/
const MAX_ENCRYPT_BLOCK = 117
/*** 最长解码长度* @type {number}*/
const MAX_DECRYPT_BLOCK = 128/*** @description RSA加密(支持长字符加密)* @param data* @returns {Promise<{param: PromiseLike<ArrayBuffer>}|*>}*/
export async function encryptedData(data) {let publicKeyconst res = await getPublicKey()publicKey = res.data.publicKeyif (res.data.mockServer) {publicKey = ''}if (publicKey === '') {return data}const encrypt = new JSEncrypt()encrypt.setPublicKey(`-----BEGIN PUBLIC KEY-----${publicKey}-----END PUBLIC KEY-----`)let bufTmp = ''let hexTmp = ''let result = ''const buffer = Buffer.from(JSON.stringify(data))let offSet = 0const inputLen = buffer.lengthwhile (inputLen - offSet > 0) {if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {bufTmp = buffer.slice(offSet, offSet + MAX_ENCRYPT_BLOCK)} else {bufTmp = buffer.slice(offSet, inputLen)}hexTmp = encrypt.encrypt(bufTmp.toString())result += atob(hexTmp)offSet += MAX_ENCRYPT_BLOCK}return btoa(result)
}/*** @description RSA解密(支持长字符解密)* @param data* @returns {PromiseLike<ArrayBuffer>}*/
export function decryptedData(data) {const decrypt = new JSEncrypt()decrypt.setPrivateKey(`-----BEGIN RSA PRIVATE KEY-----${privateKey}-----END RSA PRIVATE KEY-----`)let bufTmp = ''let hexTmp = ''let result = ''const buffer = atob(data)let offSet = 0const inputLen = buffer.lengthwhile (inputLen - offSet > 0) {if (inputLen - offSet > MAX_DECRYPT_BLOCK) {bufTmp = buffer.slice(offSet, offSet + MAX_DECRYPT_BLOCK)} else {bufTmp = buffer.slice(offSet, inputLen)}hexTmp = decrypt.decrypt(btoa(bufTmp))result += hexTmpoffSet += MAX_DECRYPT_BLOCK}return JSON.parse(result)
}

12.2、index.js

/*** @description 格式化时间* @param time* @param cFormat* @returns {string|null}*/
export function parseTime(time, cFormat) {if (arguments.length === 0) {return null}const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'let dateif (typeof time === 'object') {date = time} else {if (typeof time === 'string' && /^[0-9]+$/.test(time)) {time = parseInt(time)}if (typeof time === 'number' && time.toString().length === 10) {time = time * 1000}date = new Date(time)}const formatObj = {y: date.getFullYear(),m: date.getMonth() + 1,d: date.getDate(),h: date.getHours(),i: date.getMinutes(),s: date.getSeconds(),a: date.getDay(),}return format.replace(/{([ymdhisa])+}/g, (result, key) => {let value = formatObj[key]if (key === 'a') {return ['日', '一', '二', '三', '四', '五', '六'][value]}if (result.length > 0 && value < 10) {value = '0' + value}return value || 0})
}/*** @description 格式化时间* @param time* @param option* @returns {string}*/
export function formatTime(time, option) {if (('' + time).length === 10) {time = parseInt(time) * 1000} else {time = +time}const d = new Date(time)const now = Date.now()const diff = (now - d) / 1000if (diff < 30) {return '刚刚'} else if (diff < 3600) {// less 1 hourreturn Math.ceil(diff / 60) + '分钟前'} else if (diff < 3600 * 24) {return Math.ceil(diff / 3600) + '小时前'} else if (diff < 3600 * 24 * 2) {return '1天前'}if (option) {return parseTime(time, option)} else {return (d.getMonth() +1 +'月' +d.getDate() +'日' +d.getHours() +'时' +d.getMinutes() +'分')}
}/*** @description 将url请求参数转为json格式* @param url* @returns {{}|any}*/
export function paramObj(url) {const search = url.split('?')[1]if (!search) {return {}}return JSON.parse('{"' +decodeURIComponent(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"').replace(/\+/g, ' ') +'"}')
}/*** @description 父子关系的数组转换成树形结构数据* @param data* @returns {*}*/
export function translateDataToTree(data) {const parent = data.filter((value) => value.parentId === 'undefined' || value.parentId === null)const children = data.filter((value) => value.parentId !== 'undefined' && value.parentId !== null)const translator = (parent, children) => {parent.forEach((parent) => {children.forEach((current, index) => {if (current.parentId === parent.id) {const temp = JSON.parse(JSON.stringify(children))temp.splice(index, 1)translator([current], temp)typeof parent.children !== 'undefined' ?parent.children.push(current) :(parent.children = [current])}})})}translator(parent, children)return parent
}/*** @description 树形结构数据转换成父子关系的数组* @param data* @returns {[]}*/
export function translateTreeToData(data) {const result = []data.forEach((item) => {const loop = (data) => {result.push({id: data.id,name: data.name,parentId: data.parentId,})const child = data.childrenif (child) {for (let i = 0; i < child.length; i++) {loop(child[i])}}}loop(item)})return result
}/*** @description 10位时间戳转换年月日时分秒* @param time* @returns {string}*/
export function tenBitTimestamp(time) {const date = new Date(time * 1000)const y = date.getFullYear()let m = date.getMonth() + 1m = m < 10 ? '' + m : mlet d = date.getDate()d = d < 10 ? '' + d : dlet h = date.getHours()h = h < 10 ? '0' + h : hlet minute = date.getMinutes()let second = date.getSeconds()minute = minute < 10 ? '0' + minute : minutesecond = second < 10 ? '0' + second : secondreturn y + '年' + m + '月' + d + '日 ' + h + ':' + minute + ':' + second //组合
}
/*** @description 10位时间戳转换时分秒* @param time* @returns {string}*/
export function tenBitTimestampHms(time) {const date = new Date(time * 1000)let h = date.getHours()h = h < 10 ? '0' + h : hlet minute = date.getMinutes()let second = date.getSeconds()minute = minute < 10 ? '0' + minute : minutesecond = second < 10 ? '0' + second : secondreturn h + ':' + minute + ':' + second //组合
}/*** @description 13位时间戳转换* @param time* @returns {string}*/
export function thirteenBitTimestamp(time) {const date = new Date(time / 1)const y = date.getFullYear()let m = date.getMonth() + 1m = m < 10 ? '' + m : mlet d = date.getDate()d = d < 10 ? '' + d : dlet h = date.getHours()h = h < 10 ? '0' + h : hlet minute = date.getMinutes()let second = date.getSeconds()minute = minute < 10 ? '0' + minute : minutesecond = second < 10 ? '0' + second : secondreturn y + '年' + m + '月' + d + '日 ' + h + ':' + minute + ':' + second //组合
}/*** @description 获取随机id* @param length* @returns {string}*/
export function uuid(length = 32) {const num = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'let str = ''for (let i = 0; i < length; i++) {str += num.charAt(Math.floor(Math.random() * num.length))}return str
}/*** @description m到n的随机数* @param m* @param n* @returns {number}*/
export function random(m, n) {return Math.floor(Math.random() * (m - n) + n)
}/*** @description addEventListener* @type {function(...[*]=)}*/
export const on = (function () {return function (element, event, handler, useCapture = false) {if (element && event && handler) {element.addEventListener(event, handler, useCapture)}}
})()/*** @description removeEventListener* @type {function(...[*]=)}*/
export const off = (function () {return function (element, event, handler, useCapture = false) {if (element && event) {element.removeEventListener(event, handler, useCapture)}}
})()/*** @description 数组打乱* @param array* @returns {*}*/
export function shuffle(array) {let m = array.length,t,iwhile (m) {i = Math.floor(Math.random() * m--)t = array[m]array[m] = array[i]array[i] = t}return array
}
/*** @description ele表格序号* @param number* @returns {string}*/
export function indexMethod(index) {return index + 1;
}
/*** @description 获取当前时间并打印* @param null* @returns {string}*/
export function getCurrentTime() {var _this = thislet yy = new Date().getFullYear()let mm = new Date().getMonth() + 1let dd = new Date().getDate()let hh = new Date().getHours()let mf =new Date().getMinutes() < 10 ?'0' + new Date().getMinutes() :new Date().getMinutes()let ss =new Date().getSeconds() < 10 ?'0' + new Date().getSeconds() :new Date().getSeconds()return (_this.gettime =yy + '-' + mm + '-' + dd + ' ' + hh + ':' + mf + ':' + ss)
}
/*** @description 数组里对象根据某个值(包含姓名、字母、数字)排序* @param null* @returns {array}*/
export function compare(data) {let chineseChars = [],chars = [],list = [];data.forEach(item => {// 判断是否为中文if (/^[\u4e00-\u9fa5]*$/.test(item.nickname.charAt(0))) {chineseChars.push(item); // 姓名首字符为中文的} else {chars.push(item); // 姓名首字符非中文的(字母,数字)}});chars.sort((a, b) => a.nickname.charCodeAt(0) - b.nickname.charCodeAt(0));chineseChars.sort((a, b) => a.nickname.localeCompare(b.nickname));list = chars.concat(chineseChars); // list为最终想要的数组return list
}

12.3、preventReClick.js


// 防止多次点击,重复请求
import Vue from 'vue'const preventReClick = Vue.directive('preventReClick', {inserted: function (el, binding) {el.addEventListener('click', () => {if (!el.disabled) {el.disabled = truesetTimeout(() => {el.disabled = false}, binding.value || 3000)}})}
});export default{ preventReClick }

12.4、scroll-to.js

Math.easeInOutQuad = function(t, b, c, d) {t /= d / 2if (t < 1) {return c / 2 * t * t + b}t--return -c / 2 * (t * (t - 2) - 1) + b
}// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
var requestAnimFrame = (function() {return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
})()/*** Because it's so fucking difficult to detect the scrolling element, just move them all* @param {number} amount*/
function move(amount) {document.documentElement.scrollTop = amountdocument.body.parentNode.scrollTop = amountdocument.body.scrollTop = amount
}function position() {return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
}/*** @param {number} to* @param {number} duration* @param {Function} callback*/
export function scrollTo(to, duration, callback) {const start = position()const change = to - startconst increment = 20let currentTime = 0duration = (typeof (duration) === 'undefined') ? 500 : durationvar animateScroll = function() {// increment the timecurrentTime += increment// find the value with the quadratic in-out easing functionvar val = Math.easeInOutQuad(currentTime, start, change, duration)// move the document.bodymove(val)// do the animation unless its overif (currentTime < duration) {requestAnimFrame(animateScroll)} else {if (callback && typeof (callback) === 'function') {// the animation is done so lets callbackcallback()}}}animateScroll()
}

12.5、validate.js

/*** @description 判读是否为外链* @param path* @returns {boolean}*/
export function isExternal(path) {return /^(https?:|mailto:|tel:|\/\/)/.test(path)
}/*** @description 校验密码是否小于6位* @param value* @returns {boolean}*/
export function isPassword(value) {return value.length >= 6
}/*** @description 判断是否为数字* @param value* @returns {boolean}*/
export function isNumber(value) {const reg = /^[0-9]*$/return reg.test(value)
}/*** @description 判断是否是名称* @param value* @returns {boolean}*/
export function isName(value) {const reg = /^[\u4e00-\u9fa5]+$/return reg.test(value)
}/*** @description 判断是否为IP* @param ip* @returns {boolean}*/
export function isIP(ip) {const reg =/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/return reg.test(ip)
}/*** @description 判断是否是传统网站* @param url* @returns {boolean}*/
export function isUrl(url) {const reg =/^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/return reg.test(url)
}/*** @description 判断是否是小写字母* @param value* @returns {boolean}*/
export function isLowerCase(value) {const reg = /^[a-z]+$/return reg.test(value)
}/*** @description 判断是否是大写字母* @param value* @returns {boolean}*/
export function isUpperCase(value) {const reg = /^[A-Z]+$/return reg.test(value)
}/*** @description 判断是否是大写字母开头* @param value* @returns {boolean}*/
export function isAlphabets(value) {const reg = /^[A-Za-z]+$/return reg.test(value)
}/*** @description 判断是否是字符串* @param value* @returns {boolean}*/
export function isString(value) {return typeof value === 'string' || value instanceof String
}/*** @description 判断是否是数组* @param arg*/
export function isArray(arg) {if (typeof Array.isArray === 'undefined') {return Object.prototype.toString.call(arg) === '[object Array]'}return Array.isArray(arg)
}/*** @description 判断是否是端口号* @param value* @returns {boolean}*/
export function isPort(value) {const reg =/^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/return reg.test(value)
}/*** @description 判断是否是手机号* @param value* @returns {boolean}*/
export function isPhone(value) {const reg = /^1\d{10}$/return reg.test(value)
}/*** @description 判断是否是身份证号(第二代)* @param value* @returns {boolean}*/
export function isIdCard(value) {const reg =/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/return reg.test(value)
}/*** @description 判断是否是邮箱* @param value* @returns {boolean}*/
export function isEmail(value) {const reg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/return reg.test(value)
}/*** @description 判断是否中文* @param value* @returns {boolean}*/
export function isChina(value) {const reg = /^[\u4E00-\u9FA5]{0,30}$/return reg.test(value)
}/*** @description 判断是否为空* @param value* @returns {boolean}*/
export function isBlank(value) {return (value === null ||false ||value === '' ||value.trim() === '' ||value.toLocaleLowerCase().trim() === 'null')
}/*** @description 判断是否为固话* @param value* @returns {boolean}*/
export function isTel(value) {const reg =/^(400|800)([0-9\\-]{7,10})|(([0-9]{4}|[0-9]{3})([- ])?)?([0-9]{7,8})(([- 转])*([0-9]{1,4}))?$/return reg.test(value)
}/*** @description 判断是否为数字且最多两位小数* @param value* @returns {boolean}*/
export function isNum(value) {const reg = /^\d+(\.\d{1,2})?$/return reg.test(value)
}/*** @description 判断是否为json* @param value* @returns {boolean}*/
export function isJson(value) {if (typeof value === 'string') {const obj = JSON.parse(value)return !!(typeof obj === 'object' && obj)}return false
}

13、资源地址

https://download.csdn.net/download/askuld/88216937

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/622871.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

将Android应用修改为鸿蒙应用的工作

将Android应用修改为鸿蒙&#xff08;HarmonyOS&#xff09;应用需要进行一系列主要的工作。以下是在进行这一转换过程中可能需要进行的主要工作&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.项目…

Microsoft Excel 直方图

Microsoft Excel 直方图 1. 数据示例2. 打开 EXCEL3. settings4. 单击直方图柱&#xff0c;右键“添加数据标签”References 1. 数据示例 2. 打开 EXCEL 数据 -> 数据分析 -> 直方图 3. settings 输入区域样本值、接受区域分类间距&#xff0c;输出选项选择“新工作表组…

手把手图解教你Java SPI源码分析

原创/朱季谦 我在《Java SPI机制总结系列之开发入门实例》一文当中&#xff0c;分享了Java SPI的玩法&#xff0c;但是这只是基于表面的应用。若要明白其中的原理实现&#xff0c;还需深入到底层源码&#xff0c;分析一番。 这里再重温一下SPI机制的概念&#xff1a;SPI&#…

JS实现网页轮播图

轮播图也称为焦点图&#xff0c;是网页中比较常见的网页特效。 1、页面基本结构&#xff1a; 大盒子focus&#xff0c;里面包含 左右按钮ul 包含很多个li &#xff08;每个li里面包含了图片&#xff09;下面有很多个小圆圈 因为我们想要点击按钮&#xff0c;轮播图左右播放&a…

外部晶振、复位按键、唤醒按键、扩展排针原理图详解

前言&#xff1a;本文对外部晶振、复位按键、唤醒按键、扩展排针原理图详解。本文使用的MCU是GD32F103C8T6 目录 外部晶振原理图 复位按键、唤醒按键原理图 扩展排针部分原理图 ​外部晶振原理图 如下图&#xff0c;两个外部晶振&#xff0c;分别是8M&#xff08;主晶振&a…

【InternLM 大模型实战】第三课

基于 InternLM 和 LangChain 搭建你的知识库 大模型开发范式RAG&#xff08;检索增强生成&#xff09;FINETUNE&#xff08;微调&#xff09; LangChain 简介构建向量数据库加载源文件文档分块文档向量化 搭建知识库助手构建检索问答链RAG方案优化建议 Web Demo 部署动手实战In…

让网页自动化测试更简便,流程图设计工具为您解决痛点

在数字化时代&#xff0c;网页自动化测试已经成为提高工作效率、保证项目质量的重要手段。然而&#xff0c;传统的自动化测试往往需要复杂的编程技能&#xff0c;对非专业人员来说门槛较高。为了解决这个问题&#xff0c;我们向您推荐一款创新的设计工具&#xff0c;它可以通过…

使用numpy处理图片——二值图像

大纲 载入图像灰阶处理二值处理 在《使用numpy处理图片——灰阶影像》一文中&#xff0c;我们将彩色图片转换成灰阶图片。本文将在这个基础上将灰阶图片转换成二值图像。 二值图像就是只有黑白两种颜色的图像。像素最终显示黑还是白&#xff0c;需要有一个判断标准。如果图片太…

基于Token认证的登录功能实现

Session 认证和 Token 认证过滤器和拦截器 上篇文章我们讲到了过滤器和拦截器理论知识以及 SpringBoot 集成过滤器和拦截器&#xff0c;本篇文章我们使用过滤器和拦截器去实现基于 Token 认证的登录功能。 一、登录校验 Filter 实现 1.1、Filter 校验流程图 获得请求 url。判…

Gradle的安装及源替换步骤详解

工具介绍 Gradle是一款强大的构建工具&#xff0c;用于管理项目的依赖关系和构建过程。在使用Gradle之前&#xff0c;我们需要先进行安装&#xff0c;并可能需要更改默认的依赖源&#xff0c;以提高下载速度。下面是一步步的Gradle安装及源替换指南。 第一步&#xff1a…

Repo命令与git的关系

Repo命令与git的关系是很密切的。 我们都知道&#xff0c;git是一个开源的版本控制系统&#xff0c;常用在大型项目的管理上。 我们对repo的使用和了解就比较少了。Repo是一个基于Git构建出来的工具&#xff0c;它的出现不是为了取代Git&#xff0c;而是为了更方便开发者使用Gi…

使用PE信息查看工具和Beyond Compare文件比较工具排查dll库文件版本不对的问题

目录 1、问题说明 2、修改了代码&#xff0c;但安装版本还是有问题 3、使用PE信息查看工具查看音视频库文件&#xff08;二进制&#xff09;的时间戳 4、使用Beyond Compare比较两个库文件的差异 5、找到原因 6、最后 C软件异常排查从入门到精通系列教程&#xff08;专栏…

Python 文本处理库之chardet使用详解

概要 当处理文本数据时&#xff0c;经常会遇到各种不同的字符编码。这可能导致乱码和其他问题&#xff0c;因此需要一种方法来准确识别文本的编码。Python中的chardet库就是为了解决这个问题而设计的&#xff0c;它可以自动检测文本数据的字符编码。本文将深入探讨chardet库的…

git 的安装

git 的安装 在我们开始使用 Git 前&#xff0c;需要将它安装在我们的电脑上。即便已经安装&#xff0c;最好将它升级到最新的版本。 我们可以通过软件包或者其它安装程序来安装&#xff0c;或者下载源码编译安装。 本文只介绍通过在 windows 上安装软件包的方式&#xff0c;其…

大模型实战05——LMDeploy大模型量化部署实践

大模型实战05——LMDeploy大模型量化部署实践 1、大模型部署背景 2、LMDeploy简介 3、动手实践环节——安装、部署、量化 注 笔记内容均为截图 笔记课程视频地址&#xff1a;https://www.bilibili.com/video/BV1iW4y1A77P/?spm_id_from333.788&vd_source2882acf8c823ce…

NLP论文阅读记录 - 2022 | WOS 一种新颖的优化的与语言无关的文本摘要技术

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.前提三.本文方法四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4.6 细粒度分析 五 总结思考 前言 A Novel Optimized Language-Independent Text Summarization Techni…

青动CRM-E售后 售后工单CRM系统 erp系统 带前端小程序全开源可二开

应用介绍 一款基于FastAdminThinkPHP和uniapp开发的CRM售后管理系统&#xff0c;旨在助力企业销售售后全流程精细化、数字化管理&#xff0c;主要功能&#xff1a;客户、合同、工单、任务、报价、产品、库存、出纳、收费&#xff0c;适用于&#xff1a;服装鞋帽、化妆品、机械机…

操作系统复习 七、八章

操作系统复习 七、八章 文章目录 操作系统复习 七、八章第七章 内存管理内存管理的基本要求和原理覆盖与交换连续分配管理方式非连续分配管理方式基本分段存储管理方式段页式管理方式补充 第八章 虚拟内存虚拟内存的基本概念请求分页管理方式易混知识点页面置换算法页面分配策略…

Apollo之原理和使用讲解

文章目录 1 Apollo1.1 简介1.1.1 背景1.1.2 简介1.1.3 特点 1.2 基础模型1.3 Apollo 四个维度1.3.1 application1.3.2 environment1.3.3 cluster1.3.4 namespace 1.4 本地缓存1.5 客户端设计1.5.1 客服端拉取原理1.5.2 配置更新推送实现 1.6 总体设计1.7 可用性考虑 2 操作使用…

Flink-SQL——动态表 (Dynamic Table)

动态表 (Dynamic Table) 文章目录 动态表 (Dynamic Table)DataStream 上的关系查询动态表 & 连续查询(Continuous Query)在流上定义表连续查询更新和追加查询查询限制 表到流的转换总结 SQL 和关系代数在设计时并未考虑流数据。因此&#xff0c;在关系代数(和 SQL)之间几乎…