实现select的复选、全选、清空、搜寻等性能
<template> <a-spin :spinning="loading" tip="申请中..."> <div class="workCurve"> <x-card> <div slot="content" class="table-page-search-wrapper"> <a-form layout="inline"> <span class="search-form-left" style="width:100%"> <a-row :gutter="0"> <a-col :md="4" :sm="24"> <a-form-item label=""> <a-radio-group v-model="type" style="width:230px" @change="typeChange"> <a-radio value="0"> 投产日期 </a-radio> <a-radio value="1"> 措施日期 </a-radio> </a-radio-group> </a-form-item> </a-col> <a-col :md="4" :sm="12" style="margin-left:20px"> <a-form-item label="拉齐数据"> <a-select :maxTagCount="1" mode="multiple" style="width: 100%;min-width:240px" placeholder="请抉择拉齐数据" v-model="lqData" > <a-select-option v-for="(item, index) in lqOptions" :key="index" :value="item.value">{{ item.name }}</a-select-option> </a-select> </a-form-item> </a-col> <a-col :md="4" :sm="24"> <a-form-item label="向前拉齐点数"> <a-input-number :disabled="type === '0'" v-model="beforeCount" :precision="0" style="width: 100%;" /> </a-form-item> </a-col> <a-col :md="4" :sm="24"> <a-form-item label="向前每段天数"> <a-input-number :disabled="type === '0'" v-model="spanLenth" :precision="0" style="width: 100%;" /> </a-form-item> </a-col> <a-col :md="4" :sm="24"> <a-form-item label="向后拉齐点数"> <a-input-number v-model="afterCount" :precision="0" style="width: 100%;" /> </a-form-item> </a-col> <a-col :md="4" :sm="24"> <a-form-item label="向后每段天数"> <a-input-number v-model="afterDaily" :precision="0" style="width: 100%;" /> </a-form-item> </a-col> <a-col :md="4" :sm="24"> <a-form-item> <a-button type="primary" @click="handleQuery" ><img style="width:12px;margin-right:4px" src="@/assets/search-icon.png" alt="" />查问</a-button > </a-form-item> </a-col> <span class="table-page-search-submitButtons button-group-right"> <a-button type="primary" @click="visible = true">查看数据表</a-button> </span> </a-row> </span> </a-form> </div> </x-card> <div> <a-row :gutter="[5, 5]" type="flex"> <a-col :span="4" flex="240px"> <QkTree ref="qkTree" :type="'well'" :disabledJh="type === '0' ? true : false" :multiple="false" :treeStyle="'height:calc(100vh - 227px)'" :checkable="false" @selectedNode="selectedNodeHandle" ></QkTree> </a-col> <a-col :span="15" flex="calc(100% - 240px - 340px - 10px)" style="width:calc(100% - 240px - 340px - 10px)"> <a-card class="charts-contaniner"> <div class="charts-box"> <curve-chart ref="curveChart"></curve-chart> </div> </a-card> </a-col> <a-col :span="5" flex="340px"> <a-card class="charts-contaniner"> <div style="height: calc(100vh - 395px);overflow: auto;"> <a-tree-select v-if="false" v-model="rightJh" :maxTagCount="1" @change="rightJhChange" :dropdownStyle="{ maxHeight: '300px', overflow: 'auto' }" style="width:100%;margin-bottom:10px" :tree-data="rightTreeData" tree-checkable allowClear :treeDefaultExpandAll="true" :replaceFields="{ children: 'children', title: 'jh', key: 'jh', value: 'jh' }" placeholder="请输出井号前缀并抉择" > </a-tree-select> <a-select style="width:100%;margin-bottom:10px" class="select" mode="multiple" v-model="rightJh" :maxTagCount="1" placeholder="请输出井号前缀并抉择" @change="rightJhChange" > <div slot="dropdownRender" slot-scope="menu"> <div style="padding:4px; cursor: pointer;" @mousedown="e => e.preventDefault()"> <!-- 全选、重置 --> {{ checkAllLoading }} <a-button class="btn" type="primary" style="margin-right:10px" @click="checkAllField" :loading="checkAllLoading" > 全选 </a-button> <a-button class="btn" @click="resetRightJh">重置</a-button> </div> <a-divider style="margin: 4px 0;" /> <VNodes :vnodes="menu" /> </div> <a-select-option v-for="item in dataImport" :key="item.jh" :value="item.jh"> {{ item.jh }} </a-select-option> </a-select> <!-- :show-checked-strategy="SHOW_PARENT" --> <a-table :loading="loadingImport" :scroll="{ y: 'calc(100vh - 495px)' }" :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange, fixed: true, columnWidth: 50 }" :columns="columnsImport" :data-source="rightTableData" bordered size="small" :pagination="false" :rowKey="(record, index) => record.jh" > <span slot="rqStr" slot-scope="text, record"> <a-input :placeholder="''" @change="e => handleChange(e, record.rqStr, 'rqStr')" v-model="record.rqStr" > </a-input> </span> </a-table> </div> <div style="width: 100%;text-align: center;"> <a-button style="margin-top: 15px;" type="primary" @click="handleDownload">模板下载</a-button><br /> <a-upload name="file" :before-upload="beforeUpload" :customRequest="handleUpload" accept=".xls,.xlsx" :showUploadList="false" > <a-button type="primary" style="margin-top: 15px;"> <a-icon type="import" />导入 </a-button> </a-upload> <br /> <a-button style="margin-top: 15px;" type="primary" @click="handleClear">清空</a-button> </div> </a-card> </a-col> </a-row> </div> <a-modal :footer="null" v-model="visible" :width="1200" title="拉齐比照数据" :destroyOnClose="true" @cancel="cancelTableData" @ok="setTableData" > <a-table :columns="columns" size="small" :data-source="data" bordered> <div v-for="col in columns.map(it => it.dataIndex)" :key="col" :slot="col" slot-scope="text, record"> <div> <a-input-number :min="-999999" :max="999999" v-if="record.editable" style="margin: -5px 0;width:100%" :value="text" @change="e => handleChange(e, record.key, col)" /> <template v-else> {{ text }} </template> </div> </div> <template slot="operation" slot-scope="text, record"> <div class="editable-row-operations"> <span v-if="record.editable"> <a @click="() => save(record.key)">保留</a> <a @click="() => cancel(record.key)" style="margin-left:15px">勾销</a> </span> <span v-else> <a :disabled="editingKey !== ''" @click="() => edit(record.key)">编辑</a> </span> </div> </template> </a-table> </a-modal> </div> </a-spin></template><script>import { XCard } from '@/components'import { handleXlsRes } from '@/utils/exportXls.js'import CurveChart from '../components/CurveChart.vue'import QkTree from '@/components/QkTree/index.vue'import _ from 'lodash'import { curveApi, importApi, getTcrqJhListApi, getImportTemplateApi} from '@/api/modular/main/prodIndicator/compair.js'export default { components: { XCard, QkTree, CurveChart, VNodes: { functional: true, render: (h, ctx) => ctx.props.vnodes } }, data() { return { checkAllLoading: false, selectedRowKeys: [], selectedRows: [], lqOptions: [ // 总井数、开井数、日产液量、日产油量、含水、动液面、阶段累计产液、阶段累计产油 { name: '总井数', value: 'zjs' }, { name: '开井数', value: 'kjs' }, { name: '日产液量', value: 'rcyel' }, { name: '日产油量', value: 'rcyl' }, { name: '含水', value: 'hsb' }, { name: '动液面', value: 'dym' }, { name: '阶段累计产液', value: 'ljcyel' }, { name: '阶段累计产油', value: 'ljcyl' } ], lqData: ['zjs', 'kjs', 'rcyel', 'rcyl', 'hsb', 'dym', 'ljcyel', 'ljcyl'], loading: false, mode: ['month', 'month'], month: [], queryParam: {}, columns: [ { title: '阶段号', dataIndex: 'stage', scopedSlots: { customRender: 'stage' } }, { title: '总井数', dataIndex: 'zjs', scopedSlots: { customRender: 'zjs' } }, { title: '开井数', dataIndex: 'kjs', scopedSlots: { customRender: 'kjs' } }, { title: '日产液量', dataIndex: 'rcyel', scopedSlots: { customRender: 'rcyel' } }, { title: '日产油量', dataIndex: 'rcyl', scopedSlots: { customRender: 'rcyl' } }, { title: '动液面(m)', dataIndex: 'dym', scopedSlots: { customRender: 'dym' } }, { title: '含水(%)', dataIndex: 'hsb', scopedSlots: { customRender: 'hsb' } }, { title: '阶段累计产液', dataIndex: 'ljcyel', scopedSlots: { customRender: 'ljcyel' } }, { title: '阶段累计产油', dataIndex: 'ljcyl', scopedSlots: { customRender: 'ljcyl' } } ], wellOptions: [], visible: false, editingKey: '', data: [], cacheData: [], renderData: { xdata: [], data: [] }, chartsYName: [ '总井\n数(口)', '开井\n数(口)', '日产\n液(t)', '日产\n油(t)', '含水\n(%)', '动液\n面(m)', '阶段累计产液', '阶段累计产油' ], //'开井\n数(口)', chartsName: [ { name: '总井数', index: 0, color: '#4b5cc4', type: 'line', key: 'zjs' }, { name: '开井数', index: 1, color: '#0c8918', type: 'line', key: 'kjs' }, { name: '日产液', index: 2, color: '#ff2aff', type: 'line', key: 'rcyel' }, { name: '日产油', index: 3, color: 'red', type: 'line', key: 'rcyl' }, { name: '含水', index: 4, color: '#6fff6f', type: 'line', key: 'hsb' }, { name: '动液面', index: 5, color: '#ffe16b', type: 'line', key: 'dym' }, { name: '阶段累计产液', index: 6, color: '#f05654', type: 'line', key: 'ljcyel' }, { name: '阶段累计产油', index: 7, color: '#c9dd22', type: 'line', key: 'ljcyl' } ], miningStatusData: {}, devHistory: '', maxmonth: 100, tabPosition: 'jzzjg', sliderValue: [0, 0], btnLabel: '锁定距离', isLock: false, intervalDate: 0, monthDate: [], columnsImport: [ { title: '井号', dataIndex: 'jh', align: 'center' }, { title: '日期', dataIndex: 'rqStr', align: 'center', width: 140, scopedSlots: { customRender: 'rqStr' } } ], tcJhList: [], rightJh: [], rightTableData: [], dataImport: [], spanLenth: 1, beforeCount: 1, afterCount: 1, afterDaily: 1, type: '0', loadingImport: false, selectedQk: {}, selectedCw: {} } }, computed: { jhList() { if (this.selectedQk.title && this.selectedQk.qkdm) { if (this.type === '1') { this.loadingImport = true //措施日期,jh取值为左侧树;投产日期,井号list数据为接口返回 let jhArr = _.map(this.selectedQk.children, 'jh') let tableData = [] jhArr.filter(item => { if (!!item) { tableData.push({ jh: item }) } return !!item }) this.loadingImport = false return tableData } } else { if (this.type === '1') { this.$message.warning('请抉择区块') } } return [] }, queryData() { return { beforeCount: this.beforeCount, beforeDaily: this.beforeDaily, afterCount: this.afterCount, afterDaily: this.afterDaily, wellList: this.selectedRows } }, selectedQkInfo() { let arr = [this.selectedQk] return { zyqdm: arr && arr[0] ? arr[0].zyqdm : null, qkdm: arr && arr[0] ? arr[0].qkdm : null, cyddm: arr && arr[0] ? arr[0].cyddm : null } }, rightTreeData() { let arr = [] if (this.dataImport?.length) { arr = [{ jh: '全选', children: this.dataImport }] } return arr } }, methods: { resetRightJh() { this.rightJh = [] this.rightJhChange(this.rightJh) }, checkAllField() { this.checkAllLoading = true let jhArr = [] this.dataImport.forEach(item => { jhArr.push(item.jh) }) this.rightJh = jhArr this.rightJhChange(this.rightJh) }, rightJhChange(val) { console.log(this.checkAllLoading) // console.log(22, val) let arr = [] let arr2 = [] this.dataImport.forEach(iitem => { let obj = val.find(valItem => { return iitem.jh === valItem }) if (!obj) { arr.push(iitem) } else { arr2.push(iitem) } }) this.rightTableData = arr2.concat([]) this.defaultCheckedAll(arr2) //选中以后下拉井号 if (this.checkAllLoading) { // setTimeout(() => { // this.checkAllLoading = false // }, 1000) } }, filterOption(input, option) { return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0 }, typeChange(val) { this.dataImport = [] // 类型变更,表格选中项重置 this.selectedRowKeys = [] this.selectedRows = [] if (this.type === '0') { this.beforeCount = null this.beforeDaily = null this.getTcJhList() //切换时,从新申请 } else { this.beforeCount = 1 this.beforeDaily = 1 this.dataImport = this.jhList this.rightTableData = [] this.defaultCheckedAll([]) } // 重置选中数据 this.rightTableData = [] this.defaultCheckedAll([]) // 重置曲线 this.setCurveData([]) this.data = [] }, onSelectChange(selectedRowKeys, selectedRows) { this.selectedRowKeys = selectedRowKeys this.selectedRows = selectedRows this.rightJh = this.selectedRowKeys //表格抉择内容变更同步批改a-tree-select项 }, getTcJhList() { if (!this.selectedQk.title) { this.tcJhList = [] this.dataImport = [] this.defaultCheckedAll([]) return } // 获取投产日期下所有井号 let params = Object.assign({}, this.queryData, this.selectedQkInfo) // 点击 作业区 和采油队时 提醒用户点击 请抉择区块。 if (!params.qkdm) { this.$message.warning('请抉择区块') return } this.loadingImport = true getTcrqJhListApi(params) .then(res => { this.loadingImport = false if (res.data) { this.tcJhList = res.data this.rightJh = [] this.dataImport = this.tcJhList this.rightTableData = [] this.defaultCheckedAll([]) } else { this.$message.warning(res.message) } }) .catch(() => { this.loadingImport = false }) }, defaultCheckedAll(arr) { let indArr = [] arr.forEach(item => { indArr.push(item.jh) }) // 默认选中全副 this.onSelectChange(indArr, arr) }, selectedNodeHandle(value) { this.selectedQk = value if (this.type === '0') { this.getTcJhList() } else { this.dataImport = this.jhList this.rightTableData = [] this.defaultCheckedAll([]) } }, // 用表格编辑后的数据从新绘制曲线 setTableData() { this.visible = false this.setCurveData(this.data) }, cancelTableData() { this.visible = false this.cancel(this.editingKey) }, handleChange(value, key, column) { const newData = [...this.dataImport] const target = newData.find(item => key === item.key) if (target) { target[column] = value this.dataImport = newData } }, edit(key) { const newData = [...this.data] const target = newData.find(item => key === item.key) this.editingKey = key if (target) { target.editable = true this.data = newData } }, save(key) { const newData = [...this.data] const newCacheData = [...this.cacheData] const target = newData.find(item => key === item.key) const targetCache = newCacheData.find(item => key === item.key) if (target && targetCache) { delete target.editable this.data = newData Object.assign(targetCache, target) this.cacheData = newCacheData } this.editingKey = '' }, cancel(key) { const newData = [...this.data] const target = newData.find(item => key === item.key) this.editingKey = '' if (target) { Object.assign( target, this.cacheData.find(item => key === item.key) ) delete target.editable this.data = newData } }, getCurveData() { let params = Object.assign({}, this.queryData, {}) if (this.type === '0') { params.beforeCount = null params.beforeDaily = null // 向前拉齐点数:禁用,并且不传参置为null // 向前拉齐每段天数:禁用,并且不传参置为null } let _this = this _this.loading = true curveApi(params) .then(res => { if (res.code != 200) { this.$message.warning(res.message) _this.setCurveData([]) _this.data = [] return } if (res.success && res.data.length > 0) { _this.data = res.data for (var m = 0; m < _this.data.length; m++) { _this.data[m]['key'] = m.toString() } _this.cacheData = _this.data.map(item => ({ ...item })) _this.miningStatusData = res.data[0] _this.setCurveData(res.data) } else { _this.setCurveData([]) _this.data = [] } _this.loading = false }) .finally(err => { _this.loading = false }) }, setCurveData(data) { let chartsNameData = [] this.renderData = { xdata: [], data: [], chartsYName: [] } let showCurveData = this.lqData let chartsNameShow = [] let chartsYNameShow = [] showCurveData.forEach((currentItem, index) => { let obj = this.chartsName.find(item => { return item.key === currentItem }) if (obj) { obj.index = index let name = obj.name.length > 3 ? obj.name.slice(0, 3) + '\n' + obj.name.slice(3) : obj.name chartsYNameShow.push(name) chartsNameShow.push(obj) } }) chartsNameData = chartsNameShow this.renderData.chartsYName = chartsYNameShow || this.chartsYName for (var i = 0; i < data.length; i++) { this.renderData.xdata.push('阶段' + data[i].stage) } for (var n = 0; n < chartsNameData.length; n++) { let obj = { name: chartsNameData[n].name, index: chartsNameData[n].index, color: chartsNameData[n].color, type: chartsNameData[n].type, data: [] } for (var i = 0; i < data.length; i++) { let key = chartsNameData[n].key obj.data.push(data[i][key] ? data[i][key] - 0 : 0) } this.renderData.data.push(obj) } this.$refs.curveChart.setData(this.renderData) }, handleQuery() { if (!this.afterCount) { return this.$message.warning('请输出向后拉齐点数') } if (!this.afterDaily) { return this.$message.warning('请输出向后每段天数') } if (!this.selectedRows.length) { return this.$message.warning('井号不能为空') } let flag = true if (this.selectedRows) { this.selectedRows.forEach(item => { if (!item.rqStr) { flag = false } }) } if (!flag) { this.$message.warning('所选井号日期不能为空') return } this.getCurveData() }, // 模板下载 handleDownload() { getImportTemplateApi().then(res => { // handleXlsRes(res) const dataJson = res.data const aLink = document.createElement('a') const blob = new Blob([dataJson], { type: 'application/force-download; charset=UTF-8' }) aLink.href = URL.createObjectURL(blob) aLink.setAttribute('download', '拉齐比照模板.xls') // 设置下载文件名称 aLink.click() }) }, // 导入 beforeUpload(file) { const extension = file.name.substring(file.name.lastIndexOf('.') + 1) if (extension !== 'xlsx' && extension !== 'xls') { this.$message.error('只能上传excel文件') return false } const isLt10M = file.size / 1024 / 1024 < 10 if (!isLt10M) { this.$message.error('大小不能超过10MB!') return false } return extension && isLt10M }, handleUpload(file) { const _this = this const formData = new FormData() formData.append('file', file.file) importApi(formData) .then(response => { if (Object.prototype.toString.call(response.data) === '[object Blob]') { // 先判断是不是blob格局 if (response.data.type.includes('application/json')) { // 判断是不是非凡状况(json) const reader = new FileReader() reader.onload = function() { const res = reader.result const result = JSON.parse(res) // blob格局转成json if (result.code === 200) { // 导出超出限度 _this.$message.success('导入胜利') _this.dataImport = result.data _this.rightTableData = [] _this.defaultCheckedAll([]) } else { _this.$message.error(result.message) } } reader.readAsText(response.data) } else { // 导入格局谬误 handleXlsRes(response) } } }) .catch(e => { // 接管异样 并提醒 _this.$message.error(e.message) }) }, handleClear() { this.dataImport = [] this.rightTableData = [] this.defaultCheckedAll([]) } }, created() {}}</script><style lang="less" scoped>.charts-contaniner { overflow: auto; ul, li { margin: 0; padding: 0; list-style-type: none; } .charts-box { width: 100%; height: calc(100vh - 253px); overflow: hidden; }}.cardContent { min-height: 200px; p { margin-bottom: 6px; color: #1890ff; }}.workCurve { /deep/ .ant-card-body { padding: 12px; } /deep/ .ant-form-item { margin-bottom: 6px; } /deep/ .ant-modal-body { padding: 12px; }}.btnBoxRight { padding-top: 12px; text-align: right; button { margin: 0; }}.bottomTabs { background-color: #fff; padding-top: 8px; /deep/ .ant-radio-button-wrapper { width: 50%; text-align: center; }}/deep/.ant-table-small > .ant-table-content > .ant-table-body { margin: 0 !important;}</style>