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