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 }} <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