动态文件夹+动态表格+动态表单 vue |
您所在的位置:网站首页 › el-select可编辑 › 动态文件夹+动态表格+动态表单 vue |
动态文件夹+动态表格+表单(DynaActionForm)
使用技术 :Vue2 + element UI 01动态文件夹过滤查询文件夹,动态添加文件夹,可修改文件名,添加子文件夹,删除文件夹 template 添加 文件 {{ node.label }} 保存 取消 复制代码 css ::v-deep .el-tree-node__content { padding: 10px 0; height: auto; } .treeSortList { width: calc(100% - 30px); display: flex; align-items: center; justify-content: space-between; } .treeSortList .doBtn { padding-right: 10px; } .treeSortList .doBtn .el-button--text { color: rgb(61, 61, 61); padding: 5px; } .treeSortList .doBtn .el-button--text i { color: rgb(80, 80, 80); } .treeSortList .doBtn .el-button--text i.el-icon-delete { color: #f3a68e; } 复制代码 js data(){ return{ filterText: "", treeList: [], defaultProps: { children: "children", label: "label", }, showTree: false, //是否点击节点展开树,false 只能点前面三角图标展开 showBtn: [], showEdit: [], editData: [], newAddData: false, } } watch: { filterText(val) { this.$refs.tree.filter(val); }, }, methods:{ filterNode(value, data) { if (!value) return true; return data.label.indexOf(value) !== -1; }, handleCheckChange(data, checked, indeterminate) { console.log(data, checked, indeterminate); }, handlerAppend() { let i = 0; if (this.data) { const newChild = { id: id++, label: "文件" + (Number(this.data.length) + 1), children: [], }; this.treeList.push(newChild); } else { const newChild = { id: id++, label: "文件" + (i + 1), children: [], }; this.treeList.push(newChild); } this.$message({ message: "添加成功,开始编写吧~", type: "success", }); }, //点击树节点 handleNodeClick(data) { if (!this.ifEdit()) { return; } this.showBtn = []; this.$set(this.showBtn, data.id, true); }, append(data) { if (!this.ifEdit()) { return; } const newChild = { id: id++, label: "", children: [] }; if (!data.children) { this.$set(data, "children", []); } data.children.push(newChild); this.newAddData = true; this.$set(this.showEdit, newChild.id, true); }, edit(data) { var localEdit = localStorage.getItem("treeEdit"); var id = data.id; var newlocalData = { [data.id]: data.label }; if (localEdit) { var localData = JSON.parse(localEdit); Object.assign(localData, newlocalData); localData = JSON.stringify(localData); localStorage.setItem("treeEdit", localData); } else { newlocalData = JSON.stringify(newlocalData); localStorage.setItem("treeEdit", newlocalData); } // console.log(localStorage.getItem("treeEdit")); this.showEdit = []; this.$set(this.showEdit, data.id, true); }, remove(node, data) { const parent = node.parent; const children = parent.data.children || parent.data; const index = children.findIndex((d) => d.id === data.id); children.splice(index, 1); }, //保存 save(node, data) { if (data.label == "") { this.$message({ type: "error", message: "请输入完整数据", offset: 70, }); return; } this.newAddData = ""; var localEdit = localStorage.getItem("treeEdit"); if (localEdit) { var localData = JSON.parse(localEdit); delete localData[data.id]; //删除已经取消项 localData = JSON.stringify(localData); localStorage.setItem("treeEdit", localData); //重置缓存 } this.$set(this.showEdit, data.id, false); }, cancel(node, data) { if (this.newAddData) { this.remove(node, data); } var localEdit = localStorage.getItem("treeEdit"); if (localEdit) { var localData = JSON.parse(localEdit); data.label = localData[data.id]; delete localData[data.id]; //删除已经取消项 localData = JSON.stringify(localData); localStorage.setItem("treeEdit", localData); //重置缓存 } this.$set(this.showEdit, data.id, false); }, //判断是否有编辑或增加的项 ifEdit() { if (this.showEdit.indexOf(true) != -1) { this.$message({ type: "error", message: "先保存正在编辑的行", offset: 70, }); return false; } else { return true; } }, } 复制代码 效果展示 02动态表格 - Table/DynamicTable.vue参考网址:blog.csdn.net/coralime/ar… 02-1使用展示 tableHeader 表头的数据 tableData 表格的数据 height 表格的高度 isSelection 是否添加勾选 isIndex 是否需要添加序号列 loading 加载 复制代码tableHeader 表头的数据 --普通模式 tableHeader: [ { label: '姓名', prop: 'name', module: 'text', show: true }, { label: '地址', prop: 'address', module: 'text', show: true, } ], 复制代码 --多级表头 tableHeader: [ { label: '姓名', prop: 'name', module: 'text', show: true }, { label: '地址', prop: 'address', module: 'text', show: true, children: [ { label: '地址1', prop: 'address1', module: 'text', show: true, children: [ { label: '地址1', prop: 'address1', module: 'text', show: true, }, { label: '地址2', prop: 'address2', module: 'text', show: true, } ] }, { label: '地址2', prop: 'address2', module: 'text', show: true, } ] } ], 复制代码 02-2动态表文件 - componebts/Table/DynamicTable.vue import TableColumn from '@/components/Table/TableColumn' export default { name: 'DynamicTable', components: { TableColumn }, props: { // 表格的数据 tableData: { type: Array, required: true }, // 多级表头的数据 tableHeader: { type: Array, required: true }, // 表格的高度 height: { type: String, default: '300' }, // 是否需要添加序号列 isIndex: { type: Boolean }, // 是否添加勾选 isSelection: { type: Boolean }, loading: { type: Boolean, default: false } }, data() { return { tableRefresh: 0 } }, computed: { bindTableColumns() { this.tableRefresh++ return this.tableHeader.filter((column) => column.show); }, }, methods: { // 详情 handleClick(row) { this.$emit('json-click', row) //数据是string类型的需要用到JSON.parse(object)将string类型转换为JSON类型 //row.jsonData的jsonData是后台接口数据所提供的,this.jsonData是容器,用来实现数据绑定显示的:value="jsonData" }, // 行点击事件 handleRowClick(row, column, event) { // 通知调用父组件的row-click事件 // row作为参数传递过去 this.$emit('row-click', row) }, handleSelectionChange(val) { this.$emit('selection-change', val) }, hIndex(index) { // index索引从零开始,index +1即为当前数据序号 this.$options.parent.queryParams.pageNum import DynamicTable from "@/components/Table/DynamicTable.vue" import TrendsFrom from "./TrendsFrom.vue" import LeadingIn from "./LeadingIn.vue" let id = 20; export default { components: { DynamicTable, TrendsFrom, LeadingIn }, data() { return { filterText: "", treeList: [], defaultProps: { children: "children", label: "label", }, showTree: false, //是否点击节点展开树,false 只能点前面三角图标展开 showBtn: [], showEdit: [], editData: [], newAddData: false, // 表格数据 showQueryParams: true, tableHeader: [], loading: false, tableData: [], queryParams: { pageNum: 1, pageSize: 20 }, // 表头添加 ruleForm: { label: '', props: '', value: '', radio: false, childrenArr: [], }, selectShow: false, modules: [{ value: 'text', label: '文字' }, { value: 'textarea', label: '文本域' }, { value: 'password', label: '密码' }, // { // value:'select', // label:'下拉框' // }, { // value: 'image', // label: '图片' // } ], rules: { label: [ { required: true, message: '请填写表头字段', trigger: 'blur' } ], props: [ { required: true, validator: (rule, value, callback) => { var rul = /(?![A-Z]*$)||(?![a-z]*$)/ if (!rul.test(value)) { callback( new Error( '索引必须是大写字母或小写字母以上类型组成!' ) ) } else { callback() } }, trigger: 'blur' } ], }, visible: false, selectionKeys: [], checkedTableColumns: [], total: 0, showJson: false, jsonData: '' }; }, watch: { filterText(val) { this.$refs.tree.filter(val); }, }, computed: { tableDataList() { return this.tableData.slice((this.queryParams.pageNum - 1) * this.queryParams.pageSize, this.queryParams.pageNum * this.queryParams.pageSize) } }, mounted() { this.treeList = [{ id: 1, label: "文件1", children: [ { id: 11, label: "文件1-01", children: [], }, { id: 12, label: "文件1-02", children: [], } ], }, { id: 2, label: "文件2", children: [], }, { id: 3, label: "文件3", children: [], }] }, methods: { filterNode(value, data) { if (!value) return true; return data.label.indexOf(value) !== -1; }, handlerAppend() { let i = 0; if (this.data) { const newChild = { id: id++, label: "文件" + (Number(this.data.length) + 1), children: [], }; this.treeList.push(newChild); } else { const newChild = { id: id++, label: "文件" + (i + 1), children: [], }; this.treeList.push(newChild); } this.$message({ message: "添加成功,开始编写吧~", type: "success", }); }, //点击树节点 handleNodeClick(data) { if (!this.ifEdit()) { return; } this.showBtn = []; // 数组:第一个参数是要修改的数组, 第二个值是修改的下标或字段,第三个是要修改成什么值 // 对象:第一个参数是要修改的对象, 第二个值是修改属性字段,第三个是要修改成什么值 this.$set(this.showBtn, data.id, true); this.getTableData(data.id) // console.log(data) }, append(data) { if (!this.ifEdit()) { return; } const newChild = { id: id++, label: "", children: [] }; if (!data.children) { this.$set(data, "children", []); } data.children.push(newChild); this.newAddData = true; this.$set(this.showEdit, newChild.id, true); }, edit(data) { var localEdit = localStorage.getItem("treeEdit"); var id = data.id; var newlocalData = { [data.id]: data.label }; if (localEdit) { var localData = JSON.parse(localEdit); Object.assign(localData, newlocalData); localData = JSON.stringify(localData); localStorage.setItem("treeEdit", localData); } else { newlocalData = JSON.stringify(newlocalData); localStorage.setItem("treeEdit", newlocalData); } // console.log(localStorage.getItem("treeEdit")); this.showEdit = []; this.$set(this.showEdit, data.id, true); }, remove(node, data) { const parent = node.parent; const children = parent.data.children || parent.data; const index = children.findIndex((d) => d.id === data.id); children.splice(index, 1); }, //保存 save(node, data) { if (data.label == "") { this.$message({ type: "error", message: "请输入完整数据", offset: 70, }); return; } this.newAddData = ""; var localEdit = localStorage.getItem("treeEdit"); if (localEdit) { var localData = JSON.parse(localEdit); delete localData[data.id]; //删除已经取消项 localData = JSON.stringify(localData); localStorage.setItem("treeEdit", localData); //重置缓存 } this.$set(this.showEdit, data.id, false); }, cancel(node, data) { if (this.newAddData) { this.remove(node, data); } var localEdit = localStorage.getItem("treeEdit"); if (localEdit) { var localData = JSON.parse(localEdit); data.label = localData[data.id]; delete localData[data.id]; //删除已经取消项 localData = JSON.stringify(localData); localStorage.setItem("treeEdit", localData); //重置缓存 } this.$set(this.showEdit, data.id, false); }, //判断是否有编辑或增加的项 ifEdit() { if (this.showEdit.indexOf(true) != -1) { this.$message({ type: "error", message: "先保存正在编辑的行", offset: 70, }); return false; } else { return true; } }, getTableData(id) { if (id == 11) { this.tableHeader = [ { id: Math.random(), label: '数量(家)', prop: 'number', module: 'text', show: true }, { id: Math.random(), label: '名称', prop: 'name', module: 'text', show: true, }, { id: Math.random(), label: '详细地址', prop: 'address', module: 'textarea', show: true, }, { id: Math.random(), label: '负责人姓名、电话', prop: 'name_phone', module: 'text', show: true, } ] this.checkedTableColumns = this.tableHeader.map(column => column.prop) } else if (id == 12) { this.tableHeader = [ { id: Math.random(), label: '姓名', prop: 'name', module: 'text', show: true, }, { id: Math.random(), label: '账号', prop: 'account', module: 'text', show: true, }, { id: Math.random(), label: '部门', prop: 'department', module: 'text', show: true, }, { id: Math.random(), label: '职务', prop: 'job', module: 'text', show: true, }, { id: Math.random(), label: '所属规则', prop: 'Owning_rule', module: 'text', show: true, }, { id: Math.random(), label: '概括', prop: 'generalize', // module: 'text', show: true, children: [ { id: Math.random(), label: '应打卡天数(天)', prop: 'day1', module: 'text', show: true, }, { id: Math.random(), label: '实际打卡天数(天)', prop: 'day2', module: 'text', show: true, }, { id: Math.random(), label: '正常天数(天)', prop: 'day3', module: 'text', show: true, }, { id: Math.random(), label: '异常天数(天)', prop: 'day4', module: 'text', show: true, }, { id: Math.random(), label: '标准工作时长(小时)', prop: 'day5', module: 'text', show: true, }, { id: Math.random(), label: '实际工作时长(小时)', prop: 'day6', module: 'text', show: true, }, ] } ] this.checkedTableColumns = this.tableHeader.map(column => column.prop) this.tableData = [{ id: Math.random(), name: '张三', account: '23523', department: '897', job: 'nalvnl', Owning_rule: '23', generalize: '890', day1: '1', day2: '2', day3: '3', day4: '4', day5: '5', day6: '6', }, { id: Math.random(), name: '李四', account: '23523', department: '897', job: 'nalvnl', Owning_rule: '23', generalize: '890', day1: '1', day2: '2', day3: '3', day4: '4', day5: '5', day6: '6', }] } else { this.tableHeader = [] this.tableData = [] this.checkedTableColumns = this.tableHeader.map(column => column.prop) } }, // 搜索 changeQueryParams(val) { }, inputChildren(val) { if (val) { this.ruleForm.childrenArr.push({ key: Date.now(), label: '', prop: '', value: '', }) } else { this.ruleForm.childrenArr = [] } }, // 添加子项 removeDomain(index) { // var index = this.ruleForm.childrenArr.indexOf(item => item.key == domain.key) if (index !== 0) { this.ruleForm.childrenArr.splice(index, 1) } }, addDomain() { this.ruleForm.childrenArr.push({ key: Date.now(), label: '', prop: '', value: '', }); }, // 添加表头 submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { if (this.tableHeader.length == 0) { if (this.ruleForm.label && this.ruleForm.props && this.ruleForm.value) { this.tableHeader.push({ label: this.ruleForm.label, prop: this.ruleForm.props, module: this.ruleForm.value, show: true, radio: this.ruleForm.radio, children: this.ruleForm.childrenArr }) this.ruleForm = this.$options.data.call(this).ruleForm this.visible = false } } else { this.tableHeader.forEach(item => { if (item.label == this.ruleForm.label || item.prop == this.ruleForm.props) { if (item.prop == this.ruleForm.props) { this.$message.error('索引(prop)已存在,换一个索引(prop)填写!'); } else { this.$message.error('字段(label)已存在,换一个字段(label)填写!'); } } else { if (this.ruleForm.label && this.ruleForm.props && this.ruleForm.value) { this.tableHeader.push({ label: this.ruleForm.label, prop: this.ruleForm.props, module: this.ruleForm.value, show: true, radio: this.ruleForm.radio, children: this.ruleForm.childrenArr }) this.ruleForm = this.$options.data.call(this).ruleForm this.visible = false } } }) } this.checkedTableColumns = this.tableHeader.map(column => column.prop) } else { console.log('error submit!!'); return false; } }); }, changeModule(val) { console.log(val) if (val == 'select') { this.selectShow = true } else { this.selectShow = false } }, resetForm(formName) { this.$refs[formName].resetFields(); }, // 添加列表 handlerAddTable() { this.$refs.TrendsFrom.init('添加', this.tableHeader); }, // 修改列表 handlerEditTable() { this.$refs.TrendsFrom.init('修改', this.tableHeader, this.selectionKeys[0]); }, // 删除列表 handlerDelTable() { this.$confirm('此操作将删除该条数据,是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }) .then(() => { // 确定 this.selectionKeys.forEach((sItem, j) => { let key = Object.keys(sItem)[0] let indexKey = this.tableData.findIndex((el) => el[key] == sItem[key]);//找到下标 this.tableData.splice(indexKey, this.selectionKeys.length) }) this.$refs.TableList.$refs.multipleTable.clearSelection() this.total = this.tableData.length // this.queryParams.pageNum = 1 this.$message({ showClose: true, message: '成功' }); }) .catch(() => { // 取消 this.$message({ showClose: true, message: '取消' }); }) }, // 导入表格 handlerLeadingIn() { this.$refs.LeadingIn.init('导入', this.tableHeader, this.tableData); }, setDesc() { // JS-获取到26个英文大写字母(A-Z) const letterArr = [] Array(26).fill('').map((item, index) => { letterArr.push(String.fromCharCode(index + 65)) }) return letterArr }, /** 导出按钮操作 */ handleExport() { let tHeader = [], multiHeader = [], header1 = [], filterPop = [], merges = [], merges1 = [], merges3 = [], merges2 = [], headerRowLength = 1; let flag = this.tableHeader.some(column => { if (column.children && column.children.length > 0) { return true } return false }) if (flag) { const randomAbc = this.setDesc() this.tableHeader.map((column, i) => { if (column.show) { if (column.children && column.children.length > 0) { headerRowLength++ header1.push(column.label) column.children.map((childColumn, j) => { merges2.push(randomAbc[j] + headerRowLength) tHeader.push(childColumn.label) filterPop.push(childColumn.prop) header1.push('') }) } else { merges1.push(randomAbc[i] + headerRowLength) header1.push(column.label) tHeader.push('') filterPop.push(column.prop) } } }) // 二维数组依次递增 表格头部 // tHeader 表格头部最后一级 multiHeader.push(header1) // 合并的行 merges1.forEach(i => { merges2.forEach(j => { if (i.substring(0, 1) == j.substring(0, 1)) { merges.push(i + ':' + j) } }) }) // 合并的列 let len = merges1.length tHeader.forEach((item, o) => { merges3.push(randomAbc[o]) }) merges3.splice(0, len) merges.push(merges3.slice(0, 1)[0] + (headerRowLength - 1) + ':' + merges3.slice(-1)[0] + (headerRowLength - 1)) this.$confirm('确定导出全部数据么?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }) .then(() => { // 确定 this.getXlsxData_many(tHeader, multiHeader, filterPop, merges, this.tableData) this.$message({ showClose: true, message: '下载成功' }); }) .catch(() => { // 取消 this.$message({ showClose: true, message: '取消下载' }); }) } else { this.tableHeader.map((column, i) => { if (column.show) { tHeader.push(column.label) filterPop.push(column.prop) } }) this.$confirm('确定导出全部数据么?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }) .then(() => { // 确定 this.getXlsxData(tHeader, filterPop, this.tableData) this.$message({ showClose: true, message: '下载成功' }); }) .catch(() => { // 取消 this.$message({ showClose: true, message: '取消下载' }); }) } }, // 多行表头下载 getXlsxData_many(tHeader, multiHeader, filterPop, merges, dataT = []) { require.ensure([], () => { const { export_json_to_excel_headerMany } = require('@/excel/Export2Excel.js');// 这里 require 写你的Export2Excel.js的绝对地址 const data = this.formatJson(filterPop, dataT);//格式化 // console.log(tHeader, multiHeader, filterPop, merges, dataT); //这个得说明一下:网上得博客每个不一样,你那我的直接用也是没啥用得,你的理解这个合并是怎么写的:根据你的多级表头,如果没有合并得从上往下写,遇到开始合并单元格的,从左往右得单行写,从上到下,直到写完整 export_json_to_excel_headerMany({ multiHeader, header: tHeader, data, filename: `user_${new Date().getTime()}`, merges, autoWidth: true, }) }) }, // 单行表头下载 getXlsxData(tHeader = [], filterVal = [], dataT = []) { require.ensure([], () => { const { export_json_to_excel } = require('@/excel/Export2Excel.js');// 这里 require 写你的Export2Excel.js的绝对地址 // const tHeader = []; //对应表格输出的title // const filterVal = []; // 对应表格输出的数据 const data = this.formatJson(filterVal, dataT); export_json_to_excel(tHeader, data, `user_${new Date().getTime()}`); //对应下载文件的名字 }) }, formatJson(filterVal, jsonData) { return jsonData.map(v => filterVal.map(j => v[j])) }, // 刷新列表 handlerUpdateTable() { this.loading = true setTimeout(() => { this.tableData = this.$options.data.call(this).tableData this.loading = false }, 200); }, // 显示隐藏列 handleCheckedCitiesChange(value) { this.tableHeader.forEach(column => { // 如果选中,则设置列显示 if (value.includes(column.prop)) { column.show = true; } else { // 如果未选中,则设置列隐藏 column.show = false; } }) }, // 表格数据 handlerConfirm(data, keys) { if (keys) { let key = Object.keys(keys)[0] let indexKey = this.tableData.findIndex((el) => el[key] == keys[key]);//找到下标 this.tableData[indexKey] = data //替换数据 this.$message({ message: '修改成功!', type: 'success' }); } else { this.tableData.push(data) this.$message({ message: '添加成功!', type: 'success' }); } this.total = this.tableData.length }, // 勾选 handlerSelectionChange(val) { // console.log(val) this.selectionKeys = val }, // 分页 handleSizeChange(val) { this.queryParams.pageNum = 1; this.queryParams.pageSize = val; }, handleCurrentChange(val) { this.queryParams.pageNum = val; }, // 日志 handlerJsonClick(row) { this.showJson = true this.jsonData = row }, }, }; ::v-deep .el-tree-node__content { padding: 10px 0; height: auto; } .treeSortList { width: calc(100% - 30px); display: flex; align-items: center; justify-content: space-between; } .treeSortList .doBtn { padding-right: 10px; } .treeSortList .doBtn .el-button--text { color: rgb(61, 61, 61); padding: 5px; } .treeSortList .doBtn .el-button--text i { color: rgb(80, 80, 80); } .treeSortList .doBtn .el-button--text i.el-icon-delete { color: #f3a68e; } .container { height: 100vh; overflow: hidden; display: flex; box-sizing: border-box; .left-con { background-color: #d3dce6; color: #333; // text-align: center; // line-height: 200px; width: 320px; box-sizing: border-box; padding: 20px; overflow-y: scroll; } .right-con { flex: 1; display: flex; flex-direction: column; box-sizing: border-box; .header-con { position: sticky; top: 0; margin-bottom: 10px; padding: 10px; } .content-con { flex: 1; overflow-y: scroll; padding: 10px; .content-con-top { display: flex; margin: 10px 0; justify-content: space-between; .content-con-l {} .content-con-r { display: flex; width: 10%; justify-content: space-between; } } } } } .header-con, .content-con { background-color: #b3c0d1; color: #333; // text-align: center; // line-height: 60px; } .fromCss { .el-form-item { margin-bottom: 0; margin-top: 10px; } } .icon-btn { width: 50px; height: 50px; border: 1px solid #cdcdcd; background: white; border-radius: 25px; overflow: hidden; position: relative; transition: width 0.2s ease-in-out; font-weight: 500; font-family: inherit; margin: 10px auto; } .add-btn:hover { width: 120px; } .add-btn::before, .add-btn::after { transition: width 0.2s ease-in-out, border-radius 0.2s ease-in-out; content: ""; position: absolute; height: 4px; width: 10px; top: calc(50% - 2px); background: seagreen; } .add-btn::after { right: 14px; overflow: hidden; border-top-right-radius: 2px; border-bottom-right-radius: 2px; } .add-btn::before { left: 14px; border-top-left-radius: 2px; border-bottom-left-radius: 2px; } .icon-btn:focus { outline: none; } .btn-txt { opacity: 0; transition: opacity 0.2s; } .add-btn:hover::before, .add-btn:hover::after { width: 4px; border-radius: 2px; } .add-btn:hover .btn-txt { opacity: 1; } .add-icon::after, .add-icon::before { transition: all 0.2s ease-in-out; content: ""; position: absolute; height: 20px; width: 2px; top: calc(50% - 10px); background: seagreen; overflow: hidden; } .add-icon::before { left: 22px; border-top-left-radius: 2px; border-bottom-left-radius: 2px; } .add-icon::after { right: 22px; border-top-right-radius: 2px; border-bottom-right-radius: 2px; } .add-btn:hover .add-icon::before { left: 15px; height: 4px; top: calc(50% - 2px); } .add-btn:hover .add-icon::after { right: 15px; height: 4px; top: calc(50% - 2px); } 复制代码 TrendsFrom.vue 表单新增或修改 取 消 确 定 export default { props: { parentThat: {} }, data() { return { // 表格添加 title: '', dialogFormVisible: false, form: {}, headerData: null, editKeys: null, } }, mounted() { }, methods: { init(title, headerData, keys) { this.dialogFormVisible = true; this.title = title this.headerData = headerData this.editKeys = null // console.log(headerData); if (keys) { this.editKeys = keys this.form = JSON.parse(JSON.stringify(keys)) } }, submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { if (this.editKeys) { this.$emit('handlerConfirm', this.form, this.editKeys) } else { this.$emit('handlerConfirm', this.form) } this.parentThat.$refs.TableList.$refs.multipleTable.clearSelection() this.form = this.$options.data.call(this).form this.dialogFormVisible = false; } else { console.log('error submit!!'); return false; } }); }, resetForm(formName) { this.form = this.$options.data.call(this).form this.dialogFormVisible = false; this.$refs[formName].resetFields(); }, } } .fromCss { display: flex; flex-wrap: wrap; justify-content: space-between; } 复制代码 LeadingIn.vue 导入 将文件拖到此处,或点击上传 是否更新已经存在的数据 仅允许导入xls、xlsx格式文件。下载模板 确 定 取 消 export default { props: { parentThat: {}, }, data() { return { // 表格添加 title: '', dialogFormVisible: false, upload: { // 是否更新已数据 isUploading: false, // 上传的地址 url: process.env.VUE_APP_BASE_API + "/efarmcloud-open-file/api/v1/files/upload" }, XlsxData: [], fileContent: null, headerTable: [], tableData: [], loading:null, } }, methods: { init(title, headerTable, tableData) { this.dialogFormVisible = true; this.title = title this.headerTable = headerTable this.tableData = tableData }, setDesc() { // JS-获取到26个英文大写字母(A-Z) const letterArr = [] Array(26).fill('').map((item, index) => { letterArr.push(String.fromCharCode(index + 65)) }) return letterArr }, /** 下载模板操作 */ importTemplate() { let tHeader = [], multiHeader = [], header1 = [], filterPop = [], merges = [], merges1 = [], merges3 = [], merges2 = [], headerRowLength = 1; // 有69个元素是空的,所以直接进行了截取 let flag = this.headerTable.some(column => { if (column.children && column.children.length > 0) { return true } return false }) if (flag) { const randomAbc = this.setDesc() this.headerTable.map((column, i) => { if (column.show) { if (column.children && column.children.length > 0) { headerRowLength++ header1.push(column.label) column.children.map((childColumn, j) => { merges2.push(randomAbc[j] + headerRowLength) tHeader.push(childColumn.label) filterPop.push(childColumn.prop) header1.push('') }) } else { merges1.push(randomAbc[i] + headerRowLength) header1.push(column.label) tHeader.push('') filterPop.push(column.prop) } } }) // 二维数组依次递增 表格头部 // tHeader 表格头部最后一级 multiHeader.push(header1) // 合并的行 merges1.forEach(i => { merges2.forEach(j => { if (i.substring(0, 1) == j.substring(0, 1)) { merges.push(i + ':' + j) } }) }) // 合并的列 let len = merges1.length tHeader.forEach((item, o) => { merges3.push(randomAbc[o]) }) merges3.splice(0, len) merges.push(merges3.slice(0, 1)[0] + (headerRowLength - 1) + ':' + merges3.slice(-1)[0] + (headerRowLength - 1)) // console.log(filterPop, tHeader, multiHeader, headerRowLength, randomAbc, merges1, merges2, merges, merges3); this.getXlsxData_many(tHeader, multiHeader, filterPop, merges) } else { this.tableHeader.map((column, i) => { if (column.show) { tHeader.push(column.label) filterPop.push(column.prop) } }) this.getXlsxData(tHeader, filterPop) } }, // 多行表头下载 getXlsxData_many(tHeader, multiHeader, filterPop, merges, dataT = []) { require.ensure([], () => { const { export_json_to_excel_headerMany } = require('@/excel/Export2Excel.js');// 这里 require 写你的Export2Excel.js的绝对地址 const data = this.formatJson(filterPop, dataT);//格式化 // console.log(tHeader, multiHeader, filterPop, merges, dataT); //这个得说明一下:网上得博客每个不一样,你那我的直接用也是没啥用得,你的理解这个合并是怎么写的:根据你的多级表头,如果没有合并得从上往下写,遇到开始合并单元格的,从左往右得单行写,从上到下,直到写完整 export_json_to_excel_headerMany({ multiHeader, header: tHeader, data, filename: `user_${new Date().getTime()}`, merges, autoWidth: true, }) }) }, // 单行表头下载 getXlsxData(tHeader = [], filterVal = [], dataT = []) { require.ensure([], () => { const { export_json_to_excel } = require('@/excel/Export2Excel.js');// 这里 require 写你的Export2Excel.js的绝对地址 // const tHeader = []; //对应表格输出的title // const filterVal = []; // 对应表格输出的数据 const data = this.formatJson(filterVal, dataT); console.log(tHeader, data, filterVal, '下载'); export_json_to_excel(tHeader, data, `user_${new Date().getTime()}`); //对应下载文件的名字 }) }, formatJson(filterVal, jsonData) { return jsonData.map(v => filterVal.map(j => v[j])) }, // 核心部分代码(handleChange 和 importfile) handleChange(file) { this.fileContent = file.raw const fileName = file.name const fileType = fileName.substring(fileName.lastIndexOf('.') + 1) if (this.fileContent) { if (fileType === 'xlsx' || fileType === 'xls') { // 判断是否有子项 let flag = this.headerTable.some(column => { if (column.children && column.children.length > 0) { return true } return false }) this.loading = this.$loading({ lock: true, text: 'Loading', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }); if (flag) { this.importFile(this.fileContent, flag) this.loading.close(); } else { this.importFile(this.fileContent, flag) this.loading.close(); } } else { this.$message({ type: 'warning', message: '附件格式错误,请重新上传!' }) } } else { this.$message({ type: 'warning', message: '请上传附件!' }) } }, importFile(obj, bol) { const reader = new FileReader() const _this = this reader.readAsArrayBuffer(obj) reader.onload = function () { const buffer = reader.result const bytes = new Uint8Array(buffer) const length = bytes.byteLength let binary = '' for (let i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]) } const XLSX = require('xlsx') const wb = XLSX.read(binary, { type: 'binary' }) const outData = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) // console.log(outData); const arr = [...outData], newArr = [] arr.map((v, j) => { let list = _this.headerTable.map((s, i) => { let key = Object.keys(v)[i] if (key == s.label) { return { id: Math.random(), [s.prop]: v[key] } } }) let newList = [] list.forEach(item => { if (item) { if (bol) { // 手动填写子项的prop值与对应xlsx 对应的字段 newList.push(item, { day1: v.概括, day2: v.__EMPTY, day3: v.__EMPTY_1, day4: v.__EMPTY_2, day5: v.__EMPTY_3, day6: v.__EMPTY_4, }) } else { newList.push(item) } } }) if (newList.length != 0) { newArr.push(Object.assign(...newList)) } else { if (j < 1 && !bol) { _this.$notify.error({ title: '错误', message: '上传的数据格式不匹配,请重新上传!' }); _this.$refs.uploadRef.clearFiles(); } } }) _this.XlsxData = newArr } }, submitForm(uploadRef) { // console.log(this.XlsxData, this.parentThat._data.tableData, this.upload.isUploading); if (this.upload.isUploading) { this.parentThat._data.tableData = this.XlsxData } else { this.parentThat._data.tableData = this.parentThat._data.tableData.concat(this.XlsxData) } this.parentThat._data.total = this.parentThat._data.tableData.length //数量 this.dialogFormVisible = false; this.$refs[uploadRef].clearFiles(); }, resetForm(uploadRef) { this.dialogFormVisible = false; this.$refs[uploadRef].clearFiles(); }, } } .el-upload__tip { display: flex; flex-direction: column; align-items: center; } 复制代码 技术难点:在已有表头已有数据的情况下,再次添加表头修改数据回显慢,切换页面数据才会显示(不明原因)。 使用前端分页,会导致表格勾选错乱或不显示(解决方案使用computed) computed: { tableDataList() { return this.tableData.slice((this.queryParams.pageNum - 1) * this.queryParams.pageSize, this.queryParams.pageNum * this.queryParams.pageSize) } }, 复制代码删除删掉的永远是首条(由于没有id值,拿到的永远是第一条)(已修改) 表头过多的情况下加载会很慢,导入字符串建议一对一填写,数据缺失或表头样式复杂数据不准确 动态表单或动态表格内用使用或展示根据使用情况进行增减 弹窗样式(居中显示不超过屏幕内含滚动条) // el-dialog高度自适应,内容超出时中间出现滚动条 .common-dialog { display: flex; justify-content: center; align-items: Center; overflow: hidden; .el-dialog:not(.is-fullscreen) { margin-top: 0 !important; } .el-dialog { margin: 0 auto !important; position: relative; .el-dialog__header { position: absolute; left: 0; top: 0; right: 0; width: 100%; height: 60px; z-index: 1; background-color: #fff; } .el-dialog__body { width: 100%; overflow: hidden; overflow-y: auto; max-height: 100vh; //最大高度为视口高度的90% padding-top: 60px; padding-bottom: 100px; z-index: 1; } .el-dialog__footer { position: absolute; left: 0; bottom: 0; right: 0; width: 100%; height: 80px; z-index: 1; background-color: #fff; } } } 复制代码 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |