Commit 4059f610 by zhaopanyu

zpy

parent a673af2c
......@@ -251,7 +251,7 @@ export const constantRoutes = [
component: () =>
import("@/views/wellDesign/components/BitDesignRecommendation"),
name: "BitDesignRecommendation",
meta: { title: "钻头设计推荐方案", icon: "tool", noCache: true },
meta: { title: "钻头设计参数推荐", icon: "tool", noCache: true },
},
{
path: "bit-matching",
......
<template>
<div class="drilling-chart-container">
<div class="chart-wrapper">
<el-button type="primary" icon="el-icon-download" size="small" class="export-btn" @click="exportChart"
:disabled="!myChart">
导出图片
</el-button>
<div id="drillingEfficiencyChartdj" class="chart"></div>
</div>
<!-- <div class="optimal-values">
<div class="optimal-item">
<span class="label">机速最优:</span>
......@@ -107,6 +113,13 @@ export default {
// 折线数据必须为数组格式:[[钻速, 进尺], ...]
const targetLine = targetLineData.map(item => [item.speed, item.depth]);
const drillTypes = [...new Set(scatterData.map(item => item.drillType))];
// 定义颜色数组,为不同钻头型号分配不同颜色
const colorPalette = [
'#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de',
'#3ba272', '#fc8452', '#9a60b4', '#ea7ccc', '#ff9f7f',
'#ffdb5c', '#c4ccd3', '#4ea397', '#22c3aa', '#7bd9a5',
'#d0648a', '#f0a1a8', '#f7c369', '#4d79a4', '#e15b64'
];
// 十字线及中心点配置
const crosshairLines = [];
const crosshairCenter = [];
......@@ -169,7 +182,7 @@ export default {
}
},
legend: {
data: ['指标', '钻速均值', '进尺均值', '优化曲线',],
data: ['优化曲线', '钻速均值', '进尺均值'],
top: '10%',
right: '5%'
},
......@@ -185,10 +198,10 @@ export default {
type: 'value',
min: axisRange.xAxis.min,
max: axisRange.xAxis.max,
interval: axisRange.xAxis.interval,
// interval: axisRange.xAxis.interval,
axisLabel: { formatter: '{value} m/h' },
nameLocation: 'center',
nameGap: 30,
nameGap: 50,
axisTick: { show: true },
axisLine: { show: true }
},
......@@ -196,7 +209,7 @@ export default {
name: '进尺m',
type: 'value',
min: axisRange.yAxis.min,
interval: axisRange.yAxis.interval,
// interval: axisRange.yAxis.interval,
nameLocation: 'center',
nameGap: 40,
axisTick: { show: true },
......@@ -232,17 +245,19 @@ export default {
},
...crosshairLines,
...crosshairCenter,
...drillTypes.map(type => ({
...drillTypes.map((type, index) => {
const color = colorPalette[index % colorPalette.length];
return {
name: type,
type: 'scatter',
data: scatter.filter(item => item[2] === type),
symbolSize: 12,
itemStyle: {
color: 'blue',
borderColor: 'red',
borderWidth: 3,
shadowColor: 'red',
shadowBlur: 8
color: color,
borderColor: color,
borderWidth: 2,
shadowColor: color,
shadowBlur: 6
},
label: {
show: true,
......@@ -251,7 +266,8 @@ export default {
fontSize: 10,
color: '#333'
}
}))
};
})
]
};
......@@ -261,6 +277,34 @@ export default {
window.addEventListener('resize', this.resizeHandler);
},
exportChart() {
if (!this.myChart) {
this.$message.warning('图表未初始化,无法导出');
return;
}
try {
// 获取图表的 base64 图片数据
const url = this.myChart.getDataURL({
type: 'png',
pixelRatio: 2, // 提高图片清晰度
backgroundColor: '#fff'
});
// 创建下载链接
const link = document.createElement('a');
link.href = url;
link.download = `钻头钻进能效分析_${this.jh}_${new Date().getTime()}.png`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.$message.success('图片导出成功');
} catch (error) {
console.error('导出图片失败:', error);
this.$message.error('导出图片失败,请重试');
}
},
cleanup() {
if (this.myChart) {
this.myChart.dispose();
......@@ -396,12 +440,26 @@ export default {
opacity: 0.3;
}
.chart {
.chart-wrapper {
position: relative;
width: 100%;
height: calc(100vh - 220px);
min-height: 600px;
}
.chart {
width: 100%;
height: 100%;
}
.export-btn {
position: absolute;
top: 10px;
right: 10px;
z-index: 100;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.data-table {
width: 100%;
margin-top: 20px;
......
......@@ -3,7 +3,13 @@
<div class="chart-layout">
<div id="mainzftdj" class="chart" ref="chartRef"></div>
<aside v-if="legendItems && legendItems.length" class="strata-legend">
<div class="legend-header">层位图例</div>
<div class="legend-header">
<span>层位图例</span>
<el-button class="export-btn" @click="exportChart" :disabled="loading || !myChart" title="导出图表为图片"
icon="el-icon-download" size="small">
导出
</el-button>
</div>
<div class="legend-list">
<div v-for="(item, index) in legendItems" :key="item.name || index" class="legend-item">
<div class="legend-icon" :style="getLegendSwatchStyle(item)"></div>
......@@ -460,7 +466,7 @@ export default {
}
},
grid: {
top: 10,
top: 20,
left: "2%",
right: "3%",
bottom: "10%",
......@@ -610,10 +616,10 @@ export default {
data: xAxisLabels,
axisLabel: {
interval: 0,
rotate: 0,
margin: 12,
rotate: -90,
margin: 30,
align: "center",
fontSize: 13,
fontSize: 12,
color: colors.text,
fontWeight: 500,
formatter: formatLabel
......@@ -691,7 +697,7 @@ export default {
color: colors.text,
fontSize: 13,
fontWeight: 600,
padding: [0, 8, 0, 0]
padding: [0, 8, 0, 55]
},
min: chartConfig.yAxis2.min,
max: chartConfig.yAxis2.max,
......@@ -1088,7 +1094,7 @@ export default {
return;
}
const midX = (pxStart + pxEnd) / 2;
let topY = yTopPx - 30; // 再上移,避免遮挡
let topY = yTopPx - 80; // 再上移,提升显示位置
// 估算标签宽度用于避免与上一个重叠
const fontSize = 12;
......@@ -1185,11 +1191,11 @@ export default {
}
const yTopPx = Math.min(yMinPx, yMaxPx);
const yBottomPx = Math.max(yMinPx, yMaxPx);
// 只在上方画短竖线:长度占绘图区高度的 12%,并限制在 30-120 像素
// 只在上方画短竖线:长度占绘图区高度的 6%,并限制在 15-60 像素
const plotHeight = Math.abs(yBottomPx - yTopPx);
const stemLen = Math.max(30, Math.min(120, plotHeight * 0.12));
const stemLen = Math.max(15, Math.min(60, plotHeight * 0.06));
// 仅保留上方的线:整段都在 top 之上
const extraHead = Math.max(10, Math.min(60, plotHeight * 0.05));
const extraHead = Math.max(6, Math.min(30, plotHeight * 0.03));
const yStemStart = yTopPx - (extraHead + stemLen);
const yStemEnd = yTopPx - 1;
......@@ -1247,36 +1253,6 @@ export default {
zlevel: 10
});
// 顶部段标签:第一个段使用第一个 x 标签,之后每个段用对应中心的标签
const boundaries = [firstEdge];
for (let i = 0; i < centers.length - 1; i++) {
boundaries.push((centers[i] + centers[i + 1]) / 2);
}
const labelY = yStemStart - 8;
for (let i = 0; i < boundaries.length - 1; i++) {
const midX = (boundaries[i] + boundaries[i + 1]) / 2;
const label = String(xAxisLabels[i] ?? '');
const displayLabel = this.formatXAxisLabel(label);
graphics.push({
type: 'text',
position: [midX, labelY],
style: {
text: displayLabel,
fontSize: 12,
fontWeight: 600,
fill: '#333',
backgroundColor: 'rgba(255,255,255,0.85)',
padding: [2, 4],
borderRadius: 4,
align: 'center',
verticalAlign: 'bottom'
},
z: 121,
zlevel: 10,
silent: true,
bounding: 'raw'
});
}
}
const prev = Array.isArray(this.currentGraphicElements) ? this.currentGraphicElements : [];
......@@ -1411,6 +1387,41 @@ export default {
this.myChart.setOption({ graphic: { elements: merged } }, { replaceMerge: ['graphic'] });
}
});
},
// 导出图表为图片
exportChart() {
if (!this.myChart) {
this.$message.warning('图表尚未加载完成,请稍候再试');
return;
}
try {
// 获取图表图片数据
const dataURL = this.myChart.getDataURL({
type: 'png',
pixelRatio: 2, // 提高图片清晰度
backgroundColor: '#fff'
});
// 创建下载链接
const link = document.createElement('a');
const fileName = this.jh ? `直方图_${this.jh}_${new Date().getTime()}.png` : `直方图_${new Date().getTime()}.png`;
link.href = dataURL;
link.download = fileName;
link.style.display = 'none';
// 触发下载
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.$message.success('图表导出成功');
} catch (error) {
console.error('导出图表失败:', error);
this.$message.error('导出图表失败,请稍候再试');
}
}
},
};
......@@ -1460,6 +1471,10 @@ export default {
color: #1f2937;
border-bottom: 1px solid rgba(15, 23, 42, 0.08);
padding-bottom: 8px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.legend-list {
......@@ -1516,6 +1531,41 @@ export default {
opacity: 0.9;
}
/* 导出按钮样式 */
::v-deep .export-btn {
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
color: #fff !important;
border: none !important;
border-radius: 6px !important;
padding: 6px 14px !important;
font-size: 13px !important;
font-weight: 500 !important;
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3) !important;
transition: all 0.3s ease !important;
}
::v-deep .export-btn:hover:not(:disabled) {
background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%) !important;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4) !important;
transform: translateY(-1px) !important;
}
::v-deep .export-btn:active:not(:disabled) {
transform: translateY(0) !important;
box-shadow: 0 2px 6px rgba(59, 130, 246, 0.3) !important;
}
::v-deep .export-btn:disabled {
background: #9ca3af !important;
cursor: not-allowed !important;
opacity: 0.6 !important;
box-shadow: none !important;
}
::v-deep .export-btn .el-icon-download {
color: #fff !important;
}
.well-number-display:hover {
opacity: 1;
}
......@@ -1602,6 +1652,11 @@ export default {
min-height: 300px;
border-radius: 12px;
}
.export-btn {
padding: 4px 8px;
font-size: 12px;
}
}
/* 深色模式支持 */
......
<template>
<div class="drilling-chart-container" v-loading="loading" element-loading-text="加载中..."
element-loading-background="rgba(255, 255, 255, 0.7)">
<div class="chart-wrapper">
<el-button type="primary" icon="el-icon-download" size="small" class="export-btn" @click="exportChart"
:disabled="!myChart">
导出图片
</el-button>
<div id="drillingEfficiencyChartdj" class="chart"></div>
</div>
<!-- <div class="optimal-values">
<div class="optimal-item">
<span class="label">机速最优:</span>
<span class="value">{{ (chartData && chartData.jxzszy) || '--' }}</span>
</div>
<div class="optimal-item">
<div class="optimal-item"></div>
<span class="label">进尺最优:</span>
<span class="value">{{ (chartData && chartData.jczy) || '--' }}</span>
</div>
......@@ -147,6 +153,11 @@ export default {
// 折线数据必须为数组格式:[[钻速, 进尺], ...]
const targetLine = targetLineData.map(item => [item.speed, item.depth]);
const drillTypes = [...new Set(scatterData.map(item => item.drillType))];
const colorPalette = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#14b8a6', '#ec4899', '#6366f1', '#f97316', '#0ea5e9'];
const typeColorMap = drillTypes.reduce((acc, type, index) => {
acc[type] = colorPalette[index % colorPalette.length];
return acc;
}, {});
// 十字线及中心点配置
const crosshairLines = [];
const crosshairCenter = [];
......@@ -224,7 +235,7 @@ export default {
type: 'value',
min: axisRange.xAxis.min,
max: axisRange.xAxis.max,
interval: axisRange.xAxis.interval,
// interval: axisRange.xAxis.interval,
axisLabel: { formatter: '{value} m/h' },
nameLocation: 'center',
nameGap: 30,
......@@ -235,7 +246,7 @@ export default {
name: '进尺m',
type: 'value',
min: axisRange.yAxis.min,
interval: axisRange.yAxis.interval,
// interval: axisRange.yAxis.interval,
nameLocation: 'center',
nameGap: 40,
axisTick: { show: true },
......@@ -271,16 +282,18 @@ export default {
},
...crosshairLines,
...crosshairCenter,
...drillTypes.map(type => ({
...drillTypes.map(type => {
const color = typeColorMap[type];
return {
name: type,
type: 'scatter',
data: scatter.filter(item => item[2] === type),
symbolSize: 12,
itemStyle: {
color: 'blue',
borderColor: 'red',
color,
borderColor: color,
borderWidth: 3,
shadowColor: 'red',
shadowColor: color,
shadowBlur: 8
},
label: {
......@@ -288,9 +301,10 @@ export default {
position: 'top',
formatter: type,
fontSize: 10,
color: '#333'
color
}
}))
};
})
]
};
......@@ -300,6 +314,34 @@ export default {
window.addEventListener('resize', this.resizeHandler);
},
exportChart() {
if (!this.myChart) {
this.$message.warning('图表未初始化,无法导出');
return;
}
try {
// 获取图表的 base64 图片数据
const url = this.myChart.getDataURL({
type: 'png',
pixelRatio: 2, // 提高图片清晰度
backgroundColor: '#fff'
});
// 创建下载链接
const link = document.createElement('a');
link.href = url;
link.download = `钻头钻进能效分析_${this.jh}_${new Date().getTime()}.png`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.$message.success('图片导出成功');
} catch (error) {
console.error('导出图片失败:', error);
this.$message.error('导出图片失败,请重试');
}
},
cleanup() {
if (this.myChart) {
this.myChart.dispose();
......@@ -454,12 +496,26 @@ export default {
opacity: 0.3;
}
.chart {
.chart-wrapper {
position: relative;
width: 100%;
height: calc(100vh - 220px);
min-height: 600px;
}
.chart {
width: 100%;
height: 100%;
}
.export-btn {
position: absolute;
top: 10px;
right: 10px;
z-index: 100;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.table-section {
margin-top: 20px;
padding: 20px;
......
......@@ -4,8 +4,14 @@
<span class="well-label">井号:</span>
<span class="well-number">{{ jh }}</span>
</div>
<div class="chart-wrapper">
<el-button type="primary" icon="el-icon-download" size="small" class="export-btn" @click="exportChart"
:disabled="!myChart">
导出图片
</el-button>
<div id="drillingEfficiencyChart" class="chart"></div>
</div>
</div>
</template>
<script>
......@@ -75,6 +81,11 @@ export default {
// 折线数据必须为数组格式:[[钻速, 进尺], ...]
const targetLine = targetLineData.map(item => [item.speed, item.depth]);
const drillTypes = [...new Set(scatterData.map(item => item.drillType))];
const colorPalette = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#14b8a6', '#ec4899', '#6366f1', '#f97316', '#0ea5e9'];
const typeColorMap = drillTypes.reduce((acc, type, index) => {
acc[type] = colorPalette[index % colorPalette.length];
return acc;
}, {});
// 十字线及中心点配置
const crosshairLines = [];
......@@ -199,16 +210,18 @@ export default {
},
...crosshairLines,
...crosshairCenter,
...drillTypes.map(type => ({
...drillTypes.map(type => {
const color = typeColorMap[type];
return {
name: type,
type: 'scatter',
data: scatter.filter(item => item[2] === type),
symbolSize: 12,
itemStyle: {
color: 'blue',
borderColor: 'red',
color,
borderColor: color,
borderWidth: 3,
shadowColor: 'red',
shadowColor: color,
shadowBlur: 8
},
label: {
......@@ -216,9 +229,10 @@ export default {
position: 'top',
formatter: type,
fontSize: 10,
color: '#333'
color
}
}))
};
})
]
};
......@@ -227,6 +241,34 @@ export default {
window.addEventListener('resize', this.resizeHandler);
},
exportChart() {
if (!this.myChart) {
this.$message.warning('图表未初始化,无法导出');
return;
}
try {
// 获取图表的 base64 图片数据
const url = this.myChart.getDataURL({
type: 'png',
pixelRatio: 2, // 提高图片清晰度
backgroundColor: '#fff'
});
// 创建下载链接
const link = document.createElement('a');
link.href = url;
link.download = `钻头钻进能效分析_${this.jh}_${new Date().getTime()}.png`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.$message.success('图片导出成功');
} catch (error) {
console.error('导出图片失败:', error);
this.$message.error('导出图片失败,请重试');
}
},
cleanup() {
if (this.myChart) {
this.myChart.dispose();
......@@ -384,12 +426,26 @@ export default {
opacity: 0.3;
}
.chart {
.chart-wrapper {
position: relative;
width: 100%;
height: calc(100vh - 230px);
min-height: 600px;
}
.chart {
width: 100%;
height: 100%;
}
.export-btn {
position: absolute;
top: 10px;
right: 10px;
z-index: 100;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
/* 井号显示样式 */
.well-number-display {
position: absolute;
......
<template>
<div class="drilling-time-chart-container" v-loading="loading">
<div v-if="jh" class="well-number-display">
<span class="well-label">井号:</span>
<span class="well-number">{{ jh }}</span>
</div>
<div class="chart-wrapper">
<!-- <el-button type="primary" icon="el-icon-download" size="small" class="export-btn" @click="exportChart"
:disabled="!myChart">
导出图片
</el-button> -->
<div id="drillingTimeChart" class="chart"></div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts';
import { getljqxData } from '@/api/system/cjsjLas';
import { listLjSssjSd } from '@/api/optimization/ljSssjSd';
export default {
name: "DrillingTimeChart",
props: {
jh: {
type: String,
default: ''
}
},
data() {
return {
chartData: null,
myChart: null,
resizeHandler: null,
loading: false
};
},
mounted() {
this.loadChartData();
this.$once('hook:beforeDestroy', this.cleanup);
},
watch: {
jh: {
handler() {
this.loadChartData();
},
immediate: false
}
},
methods: {
loadChartData() {
if (!this.jh) {
return;
}
this.loading = true;
// 获取录井曲线数据和录井整米数据
Promise.all([
getljqxData({ jh: this.jh }),
listLjSssjSd({ jh: this.jh })
]).then(([ljqxRes, ljSssjRes]) => {
this.chartData = this.processData(ljqxRes, ljSssjRes);
this.initChart();
this.loading = false;
}).catch(error => {
console.error('获取数据失败:', error);
this.$message.error('获取数据失败,请重试');
// 如果API失败,使用模拟数据
this.chartData = this.generateMockData();
this.initChart();
this.loading = false;
});
},
processData(ljqxRes, ljSssjRes) {
// 处理录井曲线数据
const processArrayData = (dataList, fieldName) => {
if (!dataList || !Array.isArray(dataList) || dataList.length === 0) {
return [];
}
// 如果数据是对象数组格式 [{dept: xxx, value: xxx}, ...]
if (typeof dataList[0] === 'object' && dataList[0].hasOwnProperty('dept')) {
return dataList.map(item => ({
depth: item.dept || item.depth,
value: item[fieldName] || item.value || item
}));
}
// 如果是普通数组,需要从录井整米数据中获取深度
return dataList.map((value, index) => {
const depth = ljSssjRes && ljSssjRes.rows && ljSssjRes.rows[index]
? ljSssjRes.rows[index].js
: null;
return { depth, value };
}).filter(item => item.depth !== null && item.value !== null && item.value !== undefined);
};
// 处理钻时数据(从录井整米数据中获取)
let drillingTimeData = [];
if (ljSssjRes && ljSssjRes.rows && Array.isArray(ljSssjRes.rows)) {
drillingTimeData = ljSssjRes.rows
.filter(item => item.js !== null && item.js !== undefined && item.zs !== null && item.zs !== undefined)
.map(item => ({
depth: item.js,
value: item.zs
}));
}
// 处理其他数据
const torqueData = processArrayData(ljqxRes.njList, 'nj');
const standpipePressureData = processArrayData(ljqxRes.lyList, 'ly');
const drillingPressureData = processArrayData(ljqxRes.zyList, 'zy');
const rpmData = processArrayData(ljqxRes.zs1List, 'zs1');
// 处理泵冲数据(总泵冲)
let pumpStrokeData = [];
if (ljSssjRes && ljSssjRes.rows && Array.isArray(ljSssjRes.rows)) {
pumpStrokeData = ljSssjRes.rows
.filter(item => item.js !== null && item.js !== undefined && item.zbc !== null && item.zbc !== undefined)
.map(item => ({
depth: item.js,
value: item.zbc
}));
}
return {
drillingTime: drillingTimeData,
torque: torqueData,
standpipePressure: standpipePressureData,
drillingPressure: drillingPressureData,
rpm: rpmData,
pumpStroke: pumpStrokeData
};
},
generateMockData() {
// 生成模拟数据,作为备用
const depthData = [];
const drillingTimeData = [];
const torqueData = [];
const standpipePressureData = [];
const drillingPressureData = [];
const rpmData = [];
const pumpStrokeData = [];
const startDepth = 1695;
const endDepth = 2095;
const step = 1;
for (let depth = startDepth; depth <= endDepth; depth += step) {
depthData.push(depth);
drillingTimeData.push({ depth, value: Math.random() * 15 + 5 });
torqueData.push({ depth, value: Math.random() * 5 + 5 });
standpipePressureData.push({ depth, value: Math.random() * 5 + 10 });
drillingPressureData.push({ depth, value: Math.random() * 50 + 50 });
rpmData.push({ depth, value: Math.random() * 10 + 5 });
pumpStrokeData.push({ depth, value: Math.random() * 20 + 120 });
}
return {
drillingTime: drillingTimeData,
torque: torqueData,
standpipePressure: standpipePressureData,
drillingPressure: drillingPressureData,
rpm: rpmData,
pumpStroke: pumpStrokeData
};
},
initChart() {
if (!this.chartData) {
const chartDom = document.getElementById('drillingTimeChart');
if (chartDom && this.myChart) {
this.myChart.clear();
}
return;
}
const chartDom = document.getElementById('drillingTimeChart');
if (!chartDom) {
console.error('未找到图表容器');
return;
}
if (chartDom.offsetWidth === 0 || chartDom.offsetHeight === 0) {
console.log('容器尺寸为0,200ms后重试');
setTimeout(() => this.initChart(), 200);
return;
}
if (this.myChart) {
this.myChart.dispose();
}
this.myChart = echarts.init(chartDom);
const { drillingTime, torque, standpipePressure, drillingPressure, rpm, pumpStroke } = this.chartData;
// 转换数据格式为 [depth, value] 格式
const convertToChartData = (dataArray) => {
if (!dataArray || !Array.isArray(dataArray)) {
return [];
}
return dataArray
.filter(item => item && item.depth !== null && item.depth !== undefined && item.value !== null && item.value !== undefined)
.map(item => [item.depth, item.value])
.sort((a, b) => a[0] - b[0]); // 按深度排序
};
const drillingTimeChartData = convertToChartData(drillingTime);
console.log(drillingTimeChartData, 'drillingTimeChartData');
const torqueChartData = convertToChartData(torque);
const standpipePressureChartData = convertToChartData(standpipePressure);
const drillingPressureChartData = convertToChartData(drillingPressure);
const rpmChartData = convertToChartData(rpm);
const pumpStrokeChartData = convertToChartData(pumpStroke);
// 计算深度范围
const allDepths = [
...drillingTimeChartData.map(d => d[0]),
...torqueChartData.map(d => d[0]),
...standpipePressureChartData.map(d => d[0]),
...drillingPressureChartData.map(d => d[0]),
...rpmChartData.map(d => d[0]),
...pumpStrokeChartData.map(d => d[0])
].filter(d => d !== null && d !== undefined);
const minDepth = allDepths.length > 0 ? Math.floor(Math.min(...allDepths) / 10) * 10 : 0;
const maxDepth = allDepths.length > 0 ? Math.ceil(Math.max(...allDepths) / 10) * 10 : 1000;
const option = {
title: {
text: '录井钻时图',
left: 'center',
top: 10
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter: (params) => {
if (!params || params.length === 0) {
return '';
}
// 获取深度值(x轴的值)
const depth = params[0].axisValue || (params[0].data && params[0].data[0]) || '';
let result = `井深: ${depth} m<br/>`;
params.forEach(param => {
if (param.value !== null && param.value !== undefined) {
const unit = param.seriesName.includes('钻时') ? 'min/m' :
param.seriesName.includes('扭矩') ? 'kN•m' :
param.seriesName.includes('立压') ? 'MPa' :
param.seriesName.includes('钻压') ? 'kN' :
param.seriesName.includes('转速') ? 'rpm' : '';
result += `${param.seriesName}: ${param.value}${unit ? ' ' + unit : ''}<br/>`;
}
});
return result;
}
},
legend: {
data: ['钻时 (min/m)', '扭矩 (kN•m)', '立压 (MPa)', '钻压 (kN)', '转速 (rpm)', '泵冲'],
top: 40,
right: 50,
icon: 'rect',
itemWidth: 20,
itemHeight: 2,
itemGap: 10
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'value',
name: '井深 (m)',
nameLocation: 'center',
nameGap: 30,
axisLabel: {
formatter: '{value}'
},
min: minDepth,
max: maxDepth
},
yAxis: [
{
type: 'value',
name: '钻时 / 扭矩 / 立压',
position: 'left',
nameLocation: 'center',
nameGap: 50,
axisLabel: {
formatter: '{value}'
},
splitLine: {
show: true,
lineStyle: {
type: 'dashed'
}
}
},
{
type: 'value',
name: '钻压 / 转速 / 泵冲',
position: 'right',
nameLocation: 'center',
nameGap: 50,
axisLabel: {
formatter: '{value}'
},
splitLine: {
show: false
}
}
],
series: [
{
name: '钻时 (min/m)',
type: 'line',
yAxisIndex: 0,
data: drillingTimeChartData,
smooth: true,
lineStyle: {
color: '#ff6e6e',
width: 2,
type: 'solid'
},
symbol: 'none'
},
{
name: '扭矩 (kN•m)',
type: 'line',
yAxisIndex: 0,
data: torqueChartData,
smooth: true,
lineStyle: {
color: '#275081',
width: 2,
type: 'dashed'
},
symbol: 'none'
},
{
name: '立压 (MPa)',
type: 'line',
yAxisIndex: 0,
data: standpipePressureChartData,
smooth: true,
lineStyle: {
color: '#e57113',
width: 2,
type: 'dashed'
},
symbol: 'none'
},
{
name: '钻压 (kN)',
type: 'line',
yAxisIndex: 1,
data: drillingPressureChartData,
smooth: true,
lineStyle: {
color: '#757575',
width: 2,
type: 'solid'
},
symbol: 'none'
},
{
name: '转速 (rpm)',
type: 'line',
yAxisIndex: 1,
data: rpmChartData,
smooth: true,
lineStyle: {
color: '#cda2a1',
width: 2,
type: 'dashed'
},
symbol: 'none'
},
{
name: '泵冲',
type: 'line',
yAxisIndex: 1,
data: pumpStrokeChartData,
smooth: true,
lineStyle: {
color: '#637441',
width: 2,
type: 'solid'
},
symbol: 'none'
}
]
};
this.myChart.setOption(option);
this.resizeHandler = () => this.myChart.resize();
window.addEventListener('resize', this.resizeHandler);
},
exportChart() {
if (!this.myChart) {
this.$message.warning('图表未初始化,无法导出');
return;
}
try {
const url = this.myChart.getDataURL({
type: 'png',
pixelRatio: 2,
backgroundColor: '#fff'
});
const link = document.createElement('a');
link.href = url;
link.download = `录井钻时图_${this.jh}_${new Date().getTime()}.png`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.$message.success('图片导出成功');
} catch (error) {
console.error('导出图片失败:', error);
this.$message.error('导出图片失败,请重试');
}
},
cleanup() {
if (this.myChart) {
this.myChart.dispose();
this.myChart = null;
}
if (this.resizeHandler) {
window.removeEventListener('resize', this.resizeHandler);
this.resizeHandler = null;
}
}
}
};
</script>
<style lang="scss" scoped>
.drilling-time-chart-container {
width: 100%;
height: 100%;
position: relative;
box-sizing: border-box;
}
.well-number-display {
position: absolute;
top: 16px;
left: 16px;
z-index: 5;
background: transparent;
padding: 8px 12px;
display: flex;
align-items: center;
gap: 6px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
transition: all 0.3s ease;
opacity: 0.9;
}
.well-number-display:hover {
opacity: 1;
}
.well-label {
color: #6b7280;
font-size: 13px;
font-weight: 500;
white-space: nowrap;
}
.well-number {
color: #3b82f6;
font-size: 14px;
font-weight: 600;
}
.chart-wrapper {
position: relative;
width: 100%;
height: calc(100vh - 230px);
min-height: 600px;
}
.chart {
width: 100%;
height: 100%;
}
.export-btn {
position: absolute;
top: 10px;
right: 10px;
z-index: 100;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
</style>
<template>
<div class="chart-container">
<div v-if="jh" class="well-number-display">
<span class="well-label">井号:</span>
<span class="well-number">{{ jh }}</span>
</div>
<div class="export-button-container">
<el-button class="export-btn" @click="exportChart" :disabled="loading || !myChart" title="导出图表为图片"
icon="el-icon-download">
导出
</el-button>
</div>
<div class="chart-layout">
<div id="mainzft" class="chart" ref="chartRef"></div>
<aside v-if="legendItems && legendItems.length" class="strata-legend">
<div class="legend-header">层位图例</div>
<div class="legend-list">
<div v-for="(item, index) in legendItems" :key="item.name || index" class="legend-item">
<div class="legend-icon" :style="getLegendSwatchStyle(item)"></div>
<span class="legend-label">{{ item.name || '-' }}</span>
</div>
</div>
</aside>
</div>
<div v-if="loading" class="loading-overlay">
<div class="loading-spinner"></div>
<span>加载中...</span>
</div>
</div>
</template>
<script>
import * as echarts from "echarts";
import { getZft } from "@/api/optimization/initialization";
import { text } from "d3";
export default {
name: "HistogramGraph",
props: {
jh: {
type: String,
default: "",
},
// 美化配置选项
theme: {
type: String,
default: "modern", // modern, elegant, vibrant
validator: value => ["modern", "elegant", "vibrant"].includes(value)
}
},
data() {
return {
mockData: {},
legendItems: [],
myChart: null,
initRetryCount: 0,
maxRetryCount: 5,
resizeObserver: null,
loading: false,
debounceTimer: null,
lastStackedAreas: null,
lastChartConfig: null,
lastXAxisLabels: null,
};
},
computed: {
// 根据主题获取颜色配置
colorScheme() {
const schemes = {
modern: {
primary: "#3B82F6",
secondary: "#10B981",
accent: "#F59E0B",
background: "#F8FAFC",
text: "#1F2937",
border: "#E5E7EB",
gradient: {
start: "#3B82F6",
end: "#1D4ED8"
}
},
elegant: {
primary: "#6366F1",
secondary: "#8B5CF6",
accent: "#EC4899",
background: "#FAFAFA",
text: "#374151",
border: "#D1D5DB",
gradient: {
start: "#6366F1",
end: "#4F46E5"
}
},
vibrant: {
primary: "#EF4444",
secondary: "#06B6D4",
accent: "#F97316",
background: "#FEFEFE",
text: "#111827",
border: "#F3F4F6",
gradient: {
start: "#EF4444",
end: "#DC2626"
}
}
};
return schemes[this.theme];
},
legendPanelWidth() {
return this.legendItems && this.legendItems.length ? 260 : 0;
}
},
watch: {
jh: {
handler(newVal) {
if (newVal) {
this.refreshChart();
}
},
immediate: true
},
legendItems: {
handler() {
this.$nextTick(() => {
const chartDom = this.$refs.chartRef;
if (chartDom) {
this.setChartDimensions(chartDom);
this.performResize();
}
});
},
deep: true
}
},
mounted() {
this.initChart();
this.setupEventListeners();
},
beforeDestroy() {
this.cleanup();
},
methods: {
// 初始化图表
async initChart() {
try {
this.loading = true;
const chartDom = this.$refs.chartRef;
if (!chartDom) {
throw new Error("未找到图表容器 DOM");
}
this.setChartDimensions(chartDom);
// 重试机制优化
if (this.shouldRetry()) {
this.scheduleRetry();
return;
}
this.resetRetryCount();
this.disposeChart();
this.createChart(chartDom);
const mockData = await this.getList();
if (!this.hasValidData(mockData)) {
this.renderEmpty(chartDom);
return;
}
await this.renderRealData(mockData);
} catch (error) {
console.error("图表初始化失败:", error);
this.handleError(error);
} finally {
this.loading = false;
}
},
// 设置图表尺寸
setChartDimensions(chartDom) {
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const containerWidth = this.$el?.clientWidth || viewportWidth;
const rect = this.$el?.getBoundingClientRect();
const topOffset = rect ? rect.top : 0;
const legendWidth = this.legendPanelWidth || 0;
const containerPadding = 20;
const panelGap = legendWidth ? 5 : 0;
const safetyMargin = 12;
const widthPadding = containerPadding + panelGap + legendWidth + safetyMargin;
const availableWidth = Math.max(360, containerWidth - widthPadding);
const verticalPadding = 40;
const heightByViewport = viewportHeight - topOffset - verticalPadding;
const fallbackHeight = this.$el?.clientHeight || viewportHeight;
const availableHeight = Math.max(360, heightByViewport, fallbackHeight - 20);
chartDom.style.width = `${availableWidth}px`;
chartDom.style.height = `${availableHeight}px`;
chartDom.offsetHeight; // 强制重排
},
// 检查是否需要重试
shouldRetry() {
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const availableHeight = viewportHeight - 120;
const availableWidth = viewportWidth - 80;
return (availableWidth <= 0 || availableHeight <= 0) && this.initRetryCount < this.maxRetryCount;
},
// 安排重试
scheduleRetry() {
this.initRetryCount++;
setTimeout(() => this.initChart(), 500);
},
// 重置重试计数
resetRetryCount() {
this.initRetryCount = 0;
},
// 销毁图表
disposeChart() {
if (this.myChart) {
this.myChart.dispose();
}
},
// 创建图表实例
createChart(chartDom) {
this.myChart = echarts.init(chartDom, null, {
renderer: 'canvas',
useDirtyRect: true
});
},
// 检查数据有效性
hasValidData(mockData) {
return mockData &&
mockData.wellData &&
mockData.wellData.depthLine &&
mockData.wellData.depthLine.length > 0;
},
// 设置事件监听器
setupEventListeners() {
window.addEventListener("resize", this.handleResize);
this.observeParentResize();
},
// 清理资源
cleanup() {
window.removeEventListener("resize", this.handleResize);
if (this.myChart) {
this.myChart.dispose();
}
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
},
// 观察父容器大小变化
observeParentResize() {
const parentDom = this.$refs.chartRef?.parentElement;
if (parentDom && window.ResizeObserver) {
this.resizeObserver = new ResizeObserver(() => {
this.debouncedResize();
});
this.resizeObserver.observe(parentDom);
}
},
// 获取数据
async getList() {
try {
const res = await getZft({ jhe: this.jh });
this.mockData = res?.mockData || {};
const legendList = Array.isArray(res?.tlList)
? res.tlList
: Array.isArray(res?.mockData?.tlList)
? res.mockData.tlList
: [];
this.legendItems = legendList;
return this.mockData;
} catch (error) {
console.error("获取数据失败:", error);
throw error;
}
},
// 处理窗口大小变化
handleResize() {
this.debouncedResize();
},
// 防抖处理resize
debouncedResize() {
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
this.debounceTimer = setTimeout(() => {
this.performResize();
}, 200);
},
// 执行resize操作
performResize() {
if (this.myChart) {
const chartDom = this.$refs.chartRef;
if (chartDom) {
this.setChartDimensions(chartDom);
}
this.myChart.resize();
// 重新绘制地层标签,确保在缩放/尺寸变化后位置正确
if (this.lastStackedAreas && this.lastChartConfig && this.lastXAxisLabels) {
this.drawStratumLabels(this.lastStackedAreas, this.lastChartConfig, this.lastXAxisLabels);
}
}
},
// 刷新图表
async refreshChart() {
if (this.myChart) {
await this.initChart();
}
},
// 渲染真实数据
async renderRealData(mockData) {
try {
const { wellData } = mockData;
// 调试信息:打印深度区间数据
if (wellData.depthIntervals && wellData.depthIntervals.length > 0) {
console.log('深度区间数据:', wellData.depthIntervals.map(item => ({
型号: item.x,
尺寸: item.ztcc,
进尺: item.jc,
深度区间: item.interval,
占位: item.placeholder,
计算高度: item.jc !== undefined && item.jc !== null ? item.jc : (item.interval - item.placeholder)
})));
}
const xAxisLabels = wellData.depthLine.map((point) => point.x);
// 优化区域系列处理
const areaSeries = await this.processAreaSeries(wellData.stackedAreas);
const option = {
...this.getDefaultChartOption(),
xAxis: this.createXAxis(xAxisLabels),
yAxis: this.createYAxis(mockData.chartConfig),
series: this.createSeries(wellData, areaSeries)
};
this.myChart.setOption(option, true);
// 确保图表完全渲染后再resize
this.$nextTick(() => {
this.myChart.resize();
// 存储用于重绘的数据并绘制一次
this.lastStackedAreas = wellData.stackedAreas;
this.lastChartConfig = mockData.chartConfig;
this.lastXAxisLabels = xAxisLabels;
this.drawStratumLabels(this.lastStackedAreas, this.lastChartConfig, this.lastXAxisLabels);
});
} catch (error) {
console.error("渲染数据失败:", error);
this.handleError(error);
}
},
// 获取默认图表配置
getDefaultChartOption() {
const colors = this.colorScheme;
return {
title: { text: "", subtext: "" },
aria: { enabled: false },
backgroundColor: colors.background,
tooltip: {
trigger: "axis",
axisPointer: {
type: "cross",
label: { backgroundColor: colors.primary },
crossStyle: { color: colors.border }
},
backgroundColor: 'rgba(255,255,255,0.95)',
borderColor: colors.border,
borderWidth: 1,
textStyle: { color: colors.text },
extraCssText: 'box-shadow: 0 4px 12px rgba(0,0,0,0.15); border-radius: 8px;',
formatter: (params) => {
if (!params || params.length === 0) return '';
const dataIndex = params[0].dataIndex;
const depthInterval = this.mockData?.wellData?.depthIntervals?.[dataIndex];
if (!depthInterval) {
// 如果没有depthInterval数据,使用默认格式
let result = `<div style="font-weight: 600; margin-bottom: 8px; color: ${colors.primary};">${params[0].axisValue}</div>`;
params.forEach(param => {
const color = param.color;
result += `<div style="margin: 4px 0;">
<span style="display: inline-block; width: 10px; height: 10px; background-color: ${color}; border-radius: 50%; margin-right: 8px;"></span>
<span style="font-weight: 500;">${param.seriesName}:</span>
<span style="margin-left: 8px; font-weight: 600;">${param.value}</span>
</div>`;
});
return result;
}
// 显示井号信息
let result = `<div style="font-weight: 600; margin-bottom: 8px; color: ${colors.primary};">${depthInterval.jh || depthInterval.x}</div>`;
// 计算深度区间显示
const startDepth = depthInterval.placeholder || 0;
const height = depthInterval.jc !== undefined && depthInterval.jc !== null
? depthInterval.jc
: (depthInterval.interval - depthInterval.placeholder);
const endDepth = startDepth + height;
const depthRange = `${startDepth}-${endDepth}`;
// 显示详细信息
result += `<div style="margin: 4px 0; padding: 4px 0; border-top: 1px solid ${colors.border};">
<div style="margin: 2px 0;"><span style="font-weight: 500;">型号:</span> <span style="margin-left: 8px; font-weight: 600;">${depthInterval.x || '-'}</span></div>
<div style="margin: 2px 0;"><span style="font-weight: 500;">尺寸:</span> <span style="margin-left: 8px; font-weight: 600;">${depthInterval.ztcc || '-'}</span></div>
<div style="margin: 2px 0;"><span style="font-weight: 500;">进尺m:</span> <span style="margin-left: 8px; font-weight: 600;">${depthInterval.jc !== undefined && depthInterval.jc !== null ? depthInterval.jc : (depthInterval.interval - depthInterval.placeholder)}</span></div>
<div style="margin: 2px 0;"><span style="font-weight: 500;">深度区间:</span> <span style="margin-left: 8px; font-weight: 600;">${depthRange}</span></div>
</div>`;
return result;
}
},
grid: {
top: 10,
left: "4%",
right: "4%",
bottom: "5%",
containLabel: true,
show: false,
},
animation: true,
animationDuration: 1500,
animationEasing: 'cubicOut',
animationDelay: function (idx) {
return idx * 100;
}
};
},
// 处理区域系列
async processAreaSeries(stackedAreas) {
return await Promise.all(
stackedAreas
.filter(area => area.svg !== null)
.map(async (area) => {
let areaStyle = { opacity: 0.6 };
if (area.svg) {
try {
const svgImage = await this.createSvgImage(area.svg);
areaStyle.color = { image: svgImage, repeat: "repeat" };
} catch (error) {
console.error('SVG转换失败:', error);
}
}
return {
name: area.name,
type: "line",
xAxisIndex: 1,
z: -1,
stack: "总量",
symbol: "none",
showSymbol: false,
areaStyle: areaStyle,
lineStyle: { width: 0 },
data: area.points.map((point) => point.y),
};
})
);
},
// 创建X轴配置
createXAxis(xAxisLabels) {
const colors = this.colorScheme;
return [
{
type: "category",
boundaryGap: true,
position: "top",
data: xAxisLabels,
axisLabel: {
interval: 0,
rotate: -90,
margin: 20,
align: "center",
fontSize: 12,
color: colors.text,
fontWeight: 500
},
axisTick: {
alignWithLabel: true,
length: 6,
lineStyle: { color: colors.border }
},
splitLine: { show: false },
axisLine: {
show: true,
lineStyle: {
color: colors.border,
width: 2
}
}
},
{
type: "category",
boundaryGap: false,
position: "top",
show: false,
data: xAxisLabels
},
];
},
// 创建Y轴配置
createYAxis(chartConfig) {
const colors = this.colorScheme;
return [
{
type: "value",
name: "井深(m)",
nameTextStyle: {
color: colors.text,
fontSize: 13,
fontWeight: 600,
padding: [0, 0, 0, 8]
},
min: chartConfig.yAxis.min,
max: chartConfig.yAxis.max,
interval: chartConfig.yAxis.interval,
inverse: true,
axisLabel: {
formatter: "{value}",
fontSize: 12,
color: colors.text,
fontWeight: 500
},
splitLine: {
show: true,
lineStyle: {
color: colors.border,
type: 'dashed',
opacity: 0.3
}
},
axisLine: {
show: true,
lineStyle: {
color: colors.border,
width: 2
}
},
axisTick: {
show: true,
lineStyle: { color: colors.border }
}
},
{
type: "value",
name: "深度(m)",
nameTextStyle: {
color: colors.text,
fontSize: 13,
fontWeight: 600,
padding: [0, 8, 0, 0]
},
min: chartConfig.yAxis2.min,
max: chartConfig.yAxis2.max,
interval: chartConfig.yAxis2.interval,
position: "right",
axisLabel: {
formatter: "{value}",
fontSize: 12,
color: colors.text,
fontWeight: 500
},
splitLine: { show: false },
axisLine: {
show: true,
lineStyle: {
color: colors.border,
width: 2
}
},
axisTick: {
show: true,
lineStyle: { color: colors.border }
}
},
];
},
// 创建系列配置
createSeries(wellData, areaSeries) {
const colors = this.colorScheme;
return [
{
name: "井深数据",
type: "line",
yAxisIndex: 1,
symbol: "circle",
symbolSize: 10,
itemStyle: {
color: colors.accent,
borderColor: '#fff',
borderWidth: 3,
shadowColor: 'rgba(0,0,0,0.2)',
shadowBlur: 8
},
lineStyle: {
color: colors.accent,
width: 3,
type: 'solid',
shadowColor: 'rgba(0,0,0,0.1)',
shadowBlur: 4
},
label: {
show: true,
position: "top",
formatter: "{c}",
fontSize: 13,
fontWeight: 600,
color: colors.accent,
backgroundColor: "rgba(255,255,255,0.95)",
padding: [6, 8],
borderRadius: 6,
borderColor: colors.accent,
borderWidth: 2,
shadowColor: 'rgba(0,0,0,0.1)',
shadowBlur: 4
},
data: wellData.depthLine.map((point) => point.y),
},
{
name: "占位",
type: "bar",
stack: "total",
silent: true,
barWidth: "8%",
itemStyle: {
borderColor: "transparent",
color: "transparent"
},
emphasis: {
itemStyle: {
borderColor: "transparent",
color: "transparent"
}
},
data: wellData.depthIntervals.map((item) => item.placeholder),
},
{
name: "深度区间",
type: "bar",
stack: "total",
barWidth: "6%",
label: {
show: true,
position: 'insideTop',
color: '#fff',
fontSize: 11,
fontWeight: 600,
backgroundColor: "rgba(0,0,0,0.1)",
padding: [2, 3],
borderRadius: 4,
borderColor: 'rgba(255,255,255,0.3)',
borderWidth: 1,
formatter: (params) => {
const di = wellData.depthIntervals[params.dataIndex];
return di && di.ztcc !== undefined ? di.ztcc : params.data;
}
},
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: colors.gradient.start },
{ offset: 1, color: colors.gradient.end }
]
},
borderRadius: [4, 4, 0, 0],
shadowColor: 'rgba(0,0,0,0.2)',
shadowBlur: 8,
shadowOffsetY: 2
},
emphasis: {
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: this.adjustColor(colors.gradient.start, 1.2) },
{ offset: 1, color: this.adjustColor(colors.gradient.end, 1.2) }
]
},
shadowBlur: 12,
shadowOffsetY: 4
}
},
// 使用 jc(进尺)作为柱子的高度,如果没有 jc 则使用 interval - placeholder 计算
data: wellData.depthIntervals.map((item) => {
// 优先使用 jc(进尺),如果没有则计算 interval - placeholder
return item.jc !== undefined && item.jc !== null ? item.jc : (item.interval - item.placeholder);
}),
},
// 底部显示 placeholder 数值的透明条,用于放置底部标签
{
name: '深度区间-底部标签',
type: 'bar',
barGap: '-100%',
barWidth: '6%',
itemStyle: { color: 'transparent', borderColor: 'transparent' },
emphasis: { itemStyle: { color: 'transparent', borderColor: 'transparent' } },
label: {
show: true,
position: 'insideBottom',
color: '#fff',
fontSize: 11,
fontWeight: 600,
backgroundColor: 'rgba(0,0,0,0.1)',
padding: [2, 3],
borderRadius: 4,
borderColor: 'rgba(255,255,255,0.3)',
borderWidth: 1,
distance: 0,
formatter: (params) => {
const di = wellData.depthIntervals[params.dataIndex];
// 显示深度区间,格式为:开始深度-结束深度 或 interval值
if (di && di.placeholder !== undefined && di.jc !== undefined) {
const endDepth = di.placeholder + di.jc;
return `${di.placeholder}-${endDepth}`;
}
return di && di.interval !== undefined ? di.interval : params.data;
}
},
// 使用相同的计算方式,确保标签位置正确
data: wellData.depthIntervals.map((item) => {
return item.jc !== undefined && item.jc !== null ? item.jc : (item.interval - item.placeholder);
})
},
...areaSeries,
];
},
// 颜色调整工具方法
adjustColor(color, factor) {
if (color.startsWith('#')) {
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
const b = parseInt(color.slice(5, 7), 16);
const newR = Math.min(255, Math.round(r * factor));
const newG = Math.min(255, Math.round(g * factor));
const newB = Math.min(255, Math.round(b * factor));
return `rgb(${newR}, ${newG}, ${newB})`;
}
return color;
},
// 渲染空状态
renderEmpty(chartDom) {
const colors = this.colorScheme;
chartDom.innerHTML = `
<div class="empty-state" style="
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: ${colors.text};
font-size: 16px;
background: ${colors.background};
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
">
<div style="
font-size: 48px;
margin-bottom: 16px;
opacity: 0.6;
color: ${colors.primary};
">📊</div>
<div style="
font-size: 18px;
color: ${colors.text};
font-weight: 500;
">暂无数据</div>
<div style="
font-size: 14px;
color: ${colors.text};
opacity: 0.6;
margin-top: 8px;
">请检查数据配置</div>
</div>
`;
},
// 处理错误
handleError(error) {
console.error("图表错误:", error);
},
// 创建SVG图片
createSvgImage(svgString) {
return new Promise((resolve, reject) => {
const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
const svgUrl = URL.createObjectURL(svgBlob);
const img = new Image();
img.onload = () => {
URL.revokeObjectURL(svgUrl);
resolve(img);
};
img.onerror = (e) => {
URL.revokeObjectURL(svgUrl);
reject(e);
};
img.src = svgUrl;
});
},
// 为右侧图例生成纹理样式
getLegendSwatchStyle(item = {}) {
const baseStyle = {
backgroundColor: '#d1d5db',
backgroundRepeat: 'repeat',
backgroundSize: '36px 36px'
};
if (!item?.svg) return baseStyle;
const dataUrl = this.getSvgDataUrl(item.svg);
if (!dataUrl) return baseStyle;
return {
backgroundImage: `url("${dataUrl}")`,
backgroundRepeat: 'repeat',
backgroundSize: '36px 36px',
backgroundColor: 'transparent'
};
},
getSvgDataUrl(svgString) {
if (!svgString || typeof svgString !== 'string') return '';
try {
const compact = svgString.replace(/\s+/g, ' ').trim();
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(compact)}`;
} catch (e) {
console.warn('SVG 编码失败:', e);
return '';
}
},
// 图内层位名称整体去除,仅清理旧元素
drawStratumLabels() {
if (!this.myChart) return;
this.myChart.setOption({ graphic: { elements: [] } });
},
// 导出图表为图片
exportChart() {
if (!this.myChart) {
this.$message.warning('图表尚未加载完成,请稍候再试');
return;
}
try {
// 获取图表图片数据
const dataURL = this.myChart.getDataURL({
type: 'png',
pixelRatio: 2, // 提高图片清晰度
backgroundColor: '#fff'
});
// 创建下载链接
const link = document.createElement('a');
const fileName = this.jh ? `直方图_${this.jh}_${new Date().getTime()}.png` : `直方图_${new Date().getTime()}.png`;
link.href = dataURL;
link.download = fileName;
link.style.display = 'none';
// 触发下载
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.$message.success('图表导出成功');
} catch (error) {
console.error('导出图表失败:', error);
this.$message.error('导出图表失败,请稍候再试');
}
}
},
};
</script>
<style scoped>
/* 容器样式优化 */
.chart-container {
width: 100%;
min-height: calc(100vh - 140px);
padding: 0 10px;
margin: 0;
box-sizing: border-box;
display: flex;
flex-direction: column;
position: relative;
overflow: auto;
animation: fadeIn 0.6s ease-out;
}
.chart-layout {
display: flex;
flex: 1;
width: 100%;
gap: 5px;
align-items: stretch;
justify-content: flex-start;
overflow: hidden;
}
.strata-legend {
width: 240px;
min-width: 240px;
max-height: 100%;
padding: 16px;
border-radius: 16px;
background: #fff;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
border: 1px solid rgba(15, 23, 42, 0.06);
display: flex;
flex-direction: column;
gap: 12px;
}
.legend-header {
font-size: 16px;
font-weight: 600;
color: #1f2937;
border-bottom: 1px solid rgba(15, 23, 42, 0.08);
padding-bottom: 8px;
}
.legend-list {
overflow-y: auto;
flex: 1;
display: flex;
flex-direction: column;
gap: 1px;
padding-right: 4px;
}
.legend-item {
display: flex;
align-items: center;
gap: 5px;
padding: 0 4px;
border-radius: 8px;
transition: background 0.2s ease;
}
.legend-item:hover {
background-color: rgba(59, 130, 246, 0.08);
}
.legend-icon {
width: 40px;
height: 24px;
border-radius: 6px;
border: 1px solid rgba(15, 23, 42, 0.15);
background-color: #d1d5db;
background-size: cover !important;
}
.legend-label {
flex: 1;
font-size: 13px;
font-weight: 500;
color: #1f2937;
}
/* 井号显示样式 */
.well-number-display {
position: absolute;
top: 16px;
left: 16px;
z-index: 5;
background: transparent;
padding: 8px 12px;
display: flex;
align-items: center;
gap: 6px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
transition: all 0.3s ease;
opacity: 0.9;
}
/* 导出按钮样式 */
.export-button-container {
position: absolute;
top: 16px;
right: 16px;
z-index: 5;
}
.export-btn {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
color: #fff;
border: none;
border-radius: 8px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.export-btn:hover:not(:disabled) {
background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
transform: translateY(-1px);
}
.export-btn:active:not(:disabled) {
transform: translateY(0);
box-shadow: 0 2px 6px rgba(59, 130, 246, 0.3);
}
.export-btn:disabled {
background: #9ca3af;
cursor: not-allowed;
opacity: 0.6;
box-shadow: none;
}
.export-btn svg {
width: 16px;
height: 16px;
stroke: currentColor;
}
.well-number-display:hover {
opacity: 1;
}
.well-label {
color: #6b7280;
font-size: 13px;
font-weight: 500;
white-space: nowrap;
}
.well-number {
color: #3b82f6;
font-size: 14px;
font-weight: 600;
}
/* 图表容器样式 */
.chart {
flex: 1;
width: 100%;
max-width: 100%;
height: 100%;
min-height: 400px;
display: block;
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
border: 1px solid rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
transition: all 0.3s ease;
}
.chart:hover {
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
/* transform: translateY(-2px); */
}
/* 加载状态样式 */
.loading-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.95);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10;
border-radius: 16px;
backdrop-filter: blur(10px);
}
.loading-spinner {
width: 48px;
height: 48px;
border: 4px solid #f3f4f6;
border-top: 4px solid #3b82f6;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 16px;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.2);
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 响应式优化 */
@media (max-width: 768px) {
.chart-container {
padding: 0 10px;
}
.chart {
min-height: 300px;
border-radius: 12px;
}
.well-number-display {
top: 8px;
left: 8px;
padding: 6px 10px;
}
.well-label {
font-size: 11px;
}
.well-number {
font-size: 12px;
}
.export-button-container {
top: 8px;
right: 8px;
}
.export-btn {
padding: 6px 12px;
font-size: 12px;
}
.export-btn span {
display: none;
}
.export-btn svg {
width: 18px;
height: 18px;
}
}
/* 深色模式支持 */
@media (prefers-color-scheme: dark) {
.chart {
/* background: linear-gradient(135deg, #1f2937 0%, #111827 100%); */
/* box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); */
border: 1px solid rgba(255, 255, 255, 0.1);
}
/*
.chart:hover {
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
} */
.loading-overlay {
background: rgba(17, 24, 39, 0.95);
}
.well-number-display {
background: transparent;
}
.well-number-display:hover {
background: transparent;
}
.well-label {
color: #6b7280;
}
.well-number {
color: #3b82f6;
}
}
/* 动画效果 */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
\ No newline at end of file
......@@ -4,6 +4,12 @@
<span class="well-label">井号:</span>
<span class="well-number">{{ jh }}</span>
</div>
<div class="export-button-container">
<el-button class="export-btn" @click="exportChart" :disabled="loading || !myChart" title="导出图表为图片"
icon="el-icon-download">
导出
</el-button>
</div>
<div class="chart-layout">
<div id="mainzft" class="chart" ref="chartRef"></div>
<aside v-if="legendItems && legendItems.length" class="strata-legend">
......@@ -1117,4 +1123,53 @@ export default {
transform: translateY(0);
}
}
/* 导出按钮样式 */
.export-button-container {
position: absolute;
top: 16px;
right: 16px;
z-index: 5;
}
.export-btn {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
color: #fff;
border: none;
border-radius: 8px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.export-btn:hover:not(:disabled) {
background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
transform: translateY(-1px);
}
.export-btn:active:not(:disabled) {
transform: translateY(0);
box-shadow: 0 2px 6px rgba(59, 130, 246, 0.3);
}
.export-btn:disabled {
background: #9ca3af;
cursor: not-allowed;
opacity: 0.6;
box-shadow: none;
}
.export-btn svg {
width: 16px;
height: 16px;
stroke: currentColor;
}
</style>
\ No newline at end of file
......@@ -32,6 +32,10 @@
:jh="queryParams.jh" :key="`drillingCurve-${queryParams.jh}`" />
</keep-alive>
</el-tab-pane>
<el-tab-pane label="录井钻时图" name="drillingTimeChart">
<DrillingTimeChart v-if="activeTab === 'drillingTimeChart'" :jh="queryParams.jh"
:key="`drillingTimeChart-${queryParams.jh}`" />
</el-tab-pane>
<el-tab-pane label="井眼轨迹" name="wellboreTrajectory">
<WellboreTrajectory v-if="activeTab === 'wellboreTrajectory'" :jh="queryParams.jh"
:key="`wellboreTrajectory-${queryParams.jh}`" />
......@@ -51,6 +55,7 @@ import LoggingData from './components/LoggingData.vue';
import LoggingCurve from './components/LoggingCurve.vue';
import DrillingData from './components/DrillingData.vue';
import DrillingCurve from './components/DrillingCurve.vue';
import DrillingTimeChart from './components/DrillingTimeChart.vue';
import WellboreTrajectory from './components/WellboreTrajectory.vue';
import WellDepthStructure from './components/WellDepthStructure.vue';
......@@ -64,6 +69,7 @@ export default {
LoggingCurve,
DrillingData,
DrillingCurve,
DrillingTimeChart,
WellboreTrajectory,
WellDepthStructure
},
......
......@@ -39,16 +39,16 @@
<el-table-column type="selection" width="40" align="center" />
<!-- <el-table-column label="序号" align="center" prop="xh" min-width="80" show-overflow-tooltip fixed /> -->
<el-table-column label="井号" align="center" prop="jh" min-width="80" show-overflow-tooltip fixed />
<!-- <el-table-column label="钻头序列号" align="center" prop="ztxlh" min-width="90" show-overflow-tooltip /> -->
<el-table-column label="尺寸mm" align="center" prop="cc" min-width="70" show-overflow-tooltip />
<el-table-column label="开始井深m" align="center" prop="qsjs" min-width="90" show-overflow-tooltip />
<el-table-column label="结束井深m" align="center" prop="zzjs" min-width="90" show-overflow-tooltip />
<!-- <el-table-column label="钻头号" align="center" prop="ztxlh" min-width="90" show-overflow-tooltip /> -->
<el-table-column label="钻头尺寸mm" align="center" prop="cc" min-width="70" show-overflow-tooltip />
<el-table-column label="入井深度m" align="center" prop="qsjs" min-width="90" show-overflow-tooltip />
<el-table-column label="出井井深m" align="center" prop="zzjs" min-width="90" show-overflow-tooltip />
<el-table-column label="进尺m" align="center" prop="jc" min-width="80" show-overflow-tooltip />
<el-table-column label="机械钻速m/h" align="center" prop="jxzs" min-width="80" show-overflow-tooltip />
<!-- <el-table-column label="所钻地层" align="center" prop="szdc" min-width="120" show-overflow-tooltip />
<el-table-column label="厂家" align="center" prop="cj" min-width="90" show-overflow-tooltip />
<el-table-column label="钻头型号" align="center" prop="ztxh" min-width="120" show-overflow-tooltip />
<el-table-column label="IADC号" align="center" prop="iadc" min-width="120" show-overflow-tooltip />
<el-table-column label="IADC号" align="center" prop="iadc" min-width="120" show-overflow-tooltip />
<el-table-column label="下井次数" align="center" prop="xjcs" min-width="120" show-overflow-tooltip />
<el-table-column label="类型" align="center" prop="lx" min-width="120" show-overflow-tooltip />
<el-table-column label="入井新度" align="center" prop="rjxd" min-width="120" show-overflow-tooltip />
......@@ -165,20 +165,20 @@
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="尺寸mm" prop="cc">
<el-input v-model="form.cc" placeholder="请输入尺寸" @input="(val) => handleDecimalInput(val, 'cc')" />
<el-form-item label="钻头尺寸mm" prop="cc">
<el-input v-model="form.cc" placeholder="请输入钻头尺寸" @input="(val) => handleDecimalInput(val, 'cc')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="开始井深m" prop="qsjs">
<el-input v-model="form.qsjs" placeholder="请输入开始井深" @input="(val) => handleDecimalInput(val, 'qsjs')" />
<el-form-item label="入井深度m" prop="qsjs">
<el-input v-model="form.qsjs" placeholder="请输入入井深度" @input="(val) => handleDecimalInput(val, 'qsjs')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结束井深m" prop="zzjs">
<el-input v-model="form.zzjs" placeholder="请输入结束井深" @input="(val) => handleDecimalInput(val, 'zzjs')" />
<el-form-item label="出井井深m" prop="zzjs">
<el-input v-model="form.zzjs" placeholder="请输入出井井深" @input="(val) => handleDecimalInput(val, 'zzjs')" />
</el-form-item>
</el-col>
<el-col :span="8">
......@@ -236,13 +236,53 @@
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="钻头序列号" prop="ztxlh">
<el-input v-model="form.ztxlh" placeholder="请输入钻头序列号" />
<el-form-item label="喷嘴直径4号" prop="pz4">
<el-input v-model="form.pz4" placeholder="请输入喷嘴直径4号" @input="(val) => handleDecimalInput(val, 'pz4')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="喷嘴直径5号" prop="pz5">
<el-input v-model="form.pz5" placeholder="请输入喷嘴直径5号" @input="(val) => handleDecimalInput(val, 'pz5')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="喷嘴直径6号" prop="pz6">
<el-input v-model="form.pz6" placeholder="请输入喷嘴直径6号" @input="(val) => handleDecimalInput(val, 'pz6')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="喷嘴直径7号" prop="pz7">
<el-input v-model="form.pz7" placeholder="请输入喷嘴直径7号" @input="(val) => handleDecimalInput(val, 'pz7')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="喷嘴直径8号" prop="pz8">
<el-input v-model="form.pz8" placeholder="请输入喷嘴直径8号" @input="(val) => handleDecimalInput(val, 'pz8')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="喷嘴直径9号" prop="pz9">
<el-input v-model="form.pz9" placeholder="请输入喷嘴直径9号" @input="(val) => handleDecimalInput(val, 'pz9')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="喷嘴直径10号" prop="pz10">
<el-input v-model="form.pz10" placeholder="请输入喷嘴直径10号"
@input="(val) => handleDecimalInput(val, 'pz10')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="钻头编号" prop="ztxlh">
<el-input v-model="form.ztxlh" placeholder="请输入钻头编号" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="钻头型号" prop="ztxh">
<el-input v-model="form.ztxh" placeholder="请输入钻头型号" />
</el-form-item>
......@@ -261,14 +301,13 @@
</el-cascader>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="IADC号" prop="iadc">
<el-input v-model="form.iadc" placeholder="请输入IADC号" />
<el-form-item label="IADC号" prop="iadc">
<el-input v-model="form.iadc" placeholder="请输入IADC号" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="下井次数" prop="xjcs">
<el-input v-model="form.xjcs" placeholder="请输入下井次数" @input="(val) => handleNumberInput(val, 'xjcs')"
......@@ -281,14 +320,14 @@
@input="(val) => handleDecimalInput(val, 'jcsjhj')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="纯钻进时间" prop="jcsjczj">
<el-input v-model="form.jcsjczj" placeholder="请输入纯钻进时间"
@input="(val) => handleDecimalInput(val, 'jcsjczj')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="起下钻时间" prop="jcsjqxz">
<el-input v-model="form.jcsjqxz" placeholder="请输入起下钻时间"
......@@ -301,14 +340,14 @@
@input="(val) => handleDecimalInput(val, 'jcsjkhy')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="钻压" prop="zy">
<el-input v-model="form.zy" placeholder="请输入钻压" @input="(val) => handleNumberInput(val, 'zy')"
maxlength="3" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="转速" prop="zs">
<el-input v-model="form.zs" placeholder="请输入转速" @input="(val) => handleNumberInput(val, 'zs')"
......@@ -320,14 +359,14 @@
<el-input v-model="form.gj" placeholder="请输入缸径" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="泵速" prop="bs">
<el-input v-model="form.bs" placeholder="请输入泵速" @input="(val) => handleNumberInput(val, 'bs')"
maxlength="3" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="排量" prop="pl">
<el-input v-model="form.pl" placeholder="请输入排量" />
......@@ -338,13 +377,13 @@
<el-input v-model="form.lgby" placeholder="请输入立管泵压" @input="(val) => handleDecimalInput(val, 'lgby')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="钻头压降" prop="ztyj">
<el-input v-model="form.ztyj" placeholder="请输入钻头压降" @input="(val) => handleDecimalInput(val, 'ztyj')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="环空压耗" prop="hkyh">
<el-input v-model="form.hkyh" placeholder="请输入环空压耗" @input="(val) => handleDecimalInput(val, 'hkyh')" />
......@@ -355,13 +394,13 @@
<el-input v-model="form.cjl" placeholder="请输入冲击力" @input="(val) => handleDecimalInput(val, 'cjl')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="喷射速度" prop="pssd">
<el-input v-model="form.pssd" placeholder="请输入喷射速度" @input="(val) => handleDecimalInput(val, 'pssd')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="钻头水功率" prop="ztsgl">
<el-input v-model="form.ztsgl" placeholder="请输入钻头水功率"
......@@ -373,14 +412,14 @@
<el-input v-model="form.bsgl" placeholder="请输入比水功率" @input="(val) => handleDecimalInput(val, 'bsgl')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="上返速度钻杆" prop="sfsdzg">
<el-input v-model="form.sfsdzg" placeholder="请输入上返速度钻杆"
@input="(val) => handleDecimalInput(val, 'sfsdzg')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="上返速度钻铤" prop="sfsdzt">
<el-input v-model="form.sfsdzt" placeholder="请输入上返速度钻铤"
......@@ -393,13 +432,13 @@
@input="(val) => handleDecimalInput(val, 'gllyl')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="牙齿磨损" prop="ycmsqk">
<el-input v-model="form.ycmsqk" placeholder="请输入牙齿磨损" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="轴承磨损" prop="zcmsqk">
<el-input v-model="form.zcmsqk" placeholder="请输入轴承磨损" />
......@@ -410,96 +449,102 @@
<el-input v-model="form.zjmsqk" placeholder="请输入直径磨损" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="备注" prop="bz">
<el-input v-model="form.bz" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="内排齿" prop="npc">
<el-input v-model="form.npc" placeholder="请输入内排齿" />
<el-form-item label="扭矩" prop="nj">
<el-input v-model="form.nj" placeholder="请输入扭矩" @input="(val) => handleDecimalInput(val, 'nj')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="外排齿" prop="wpc">
<el-input v-model="form.wpc" placeholder="请输入外排齿" />
<el-form-item label="钻盘总转数" prop="zpzzs">
<el-input v-model="form.zpzzs" placeholder="请输入钻盘总转数"
@input="(val) => handleDecimalInput(val, 'zpzzs')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="磨损特征" prop="mstz">
<el-input v-model="form.mstz" placeholder="请输入磨损特征" />
<el-form-item label="喷嘴类型" prop="pzlx">
<el-input v-model="form.pzlx" placeholder="请输入喷嘴类型" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="位置" prop="wz">
<el-input v-model="form.wz" placeholder="请输入位置" />
<el-form-item label="钻头价格" prop="ztjg">
<el-input v-model="form.ztjg" placeholder="请输入钻头价格" @input="(val) => handleDecimalInput(val, 'ztjg')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="轴承/密封" prop="zc">
<el-input v-model="form.zc" placeholder="请输入轴承/密封" />
<el-form-item label="入井日期" prop="qsrq">
<el-date-picker clearable v-model="form.qsrq" type="date" value-format="yyyy-MM-dd"
placeholder="请选择入井日期" style="width: 100%;">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="直径" prop="zj">
<el-input v-model="form.zj" placeholder="请输入直径" />
<el-form-item label="起出日期" prop="zzrq">
<el-date-picker clearable v-model="form.zzrq" type="date" value-format="yyyy-MM-dd"
placeholder="请选择起出日期" style="width: 100%;">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="form-section">
<div class="section-title">八参数</div>
<el-row>
<el-col :span="8">
<el-form-item label="起钻原因" prop="qzyy">
<el-input v-model="form.qzyy" placeholder="请输入起钻原因" />
<el-form-item label="内排齿" prop="npc">
<el-input v-model="form.npc" placeholder="请输入内排齿" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="其他特征" prop="qttz">
<el-input v-model="form.qttz" placeholder="请输入其他特征" />
<el-form-item label="外排齿" prop="wpc">
<el-input v-model="form.wpc" placeholder="请输入外排齿" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="扭矩" prop="nj">
<el-input v-model="form.nj" placeholder="请输入扭矩" @input="(val) => handleDecimalInput(val, 'nj')" />
<el-form-item label="磨损特征" prop="mstz">
<el-input v-model="form.mstz" placeholder="请输入磨损特征" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="钻盘总转数" prop="zpzzs">
<el-input v-model="form.zpzzs" placeholder="请输入钻盘总转数"
@input="(val) => handleDecimalInput(val, 'zpzzs')" />
<el-form-item label="位置" prop="wz">
<el-input v-model="form.wz" placeholder="请输入位置" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="入井日期" prop="qsrq">
<el-date-picker clearable v-model="form.qsrq" type="date" value-format="yyyy-MM-dd"
placeholder="请选择入井日期" style="width: 100%;">
</el-date-picker>
<el-form-item label="轴承/密封" prop="zc">
<el-input v-model="form.zc" placeholder="请输入轴承/密封" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="起出日期" prop="zzrq">
<el-date-picker clearable v-model="form.zzrq" type="date" value-format="yyyy-MM-dd"
placeholder="请选择起出日期" style="width: 100%;">
</el-date-picker>
<el-form-item label="直径" prop="zj">
<el-input v-model="form.zj" placeholder="请输入直径" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="喷嘴类型" prop="pzlx">
<el-input v-model="form.pzlx" placeholder="请输入喷嘴类型" />
<el-form-item label="起钻原因" prop="qzyy">
<el-input v-model="form.qzyy" placeholder="请输入起钻原因" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="钻头价格" prop="ztjg">
<el-input v-model="form.ztjg" placeholder="请输入钻头价格" @input="(val) => handleDecimalInput(val, 'ztjg')" />
<el-form-item label="其他特征" prop="qttz">
<el-input v-model="form.qttz" placeholder="请输入其他特征" />
</el-form-item>
</el-col>
<el-col :span="8">
</el-col>
</el-row>
</div>
......@@ -677,10 +722,10 @@ export default {
{ required: true, message: "尺寸不能为空", trigger: "blur" }
],
qsjs: [
{ required: true, message: "开始井深不能为空", trigger: "blur" }
{ required: true, message: "入井深度不能为空", trigger: "blur" }
],
zzjs: [
{ required: true, message: "结束井深不能为空", trigger: "blur" }
{ required: true, message: "出井井深不能为空", trigger: "blur" }
],
jc: [
{ required: true, message: "进尺不能为空", trigger: "blur" }
......
......@@ -14,9 +14,9 @@
<el-form-item label="生产厂家">
<el-input v-model="queryParams.sccj" placeholder="请输入生产厂家" clearable style="width: 150px;" />
</el-form-item>
<el-form-item label="钻头编号">
<!-- <el-form-item label="钻头编号">
<el-input v-model="queryParams.ztbh" placeholder="请输入钻头编号" clearable style="width: 150px;" />
</el-form-item>
</el-form-item> -->
<el-form-item>
<el-button type="primary" @click="onSearch" size="mini">查询</el-button>
<el-button @click="onReset" size="mini">重置</el-button>
......@@ -49,7 +49,7 @@
<el-table :data="tableData" style="width: 100%;" :height="tableHeight" stripe highlight-current-row border
v-loading="loading" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column prop="ztbh" label="钻头编号" width="100" align="center" />
<!-- <el-table-column prop="ztbh" label="钻头编号" width="100" align="center" /> -->
<el-table-column prop="ztcc" label="钻头尺寸mm" align="center" />
<el-table-column prop="ztxh" label="钻头型号" align="center" />
<el-table-column prop="ztlb" label="钻头类别" align="center" />
......@@ -84,11 +84,11 @@
<div class="dialog-card">
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-row :gutter="20">
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item label="钻头编号" prop="ztbh">
<el-input v-model="form.ztbh" />
</el-form-item>
</el-col>
</el-col> -->
<el-col :span="12">
<el-form-item label="钻头尺寸" prop="ztcc">
<el-input v-model="form.ztcc" />
......
......@@ -7,7 +7,7 @@
<div class="test-buttons">
<el-button size="small" type="primary" @click="goToBitDesign">钻头设计参数推荐</el-button>
<el-button size="small" type="success" @click="goToRecommendation">钻头设计推荐方案</el-button>
<el-button size="small" type="success" @click="goToRecommendation">钻头设计参数推荐</el-button>
<el-button size="small" type="warning" @click="goToMatching">钻头匹配</el-button>
<el-button size="small" type="info" @click="goToSelectionInfo">查看选型信息</el-button>
</div>
......
......@@ -1757,7 +1757,7 @@ export default {
const endDepth = kcData ? kcData.jsjs : 0;
console.log(startDepth, 'startDepth');
console.log(endDepth, 'endDepth');
// 跳转到钻头设计推荐方案页面,传递开次信息
// 跳转到钻头设计参数推荐页面,传递开次信息
this.$router.push({
name: 'BitDesignRecommendation',
query: {
......@@ -1780,9 +1780,9 @@ export default {
console.log('开次信息渲染完成');
},
// 跳转到钻头设计推荐方案页面
// 跳转到钻头设计参数推荐页面
goToRecommendation() {
console.log('跳转到钻头设计推荐方案页面')
console.log('跳转到钻头设计参数推荐页面')
// 使用路由跳转到推荐方案页面
this.$router.push({
name: 'BitDesignRecommendation',
......
......@@ -18,7 +18,7 @@
<BitDesign v-if="currentPage === 'main'" @show-recommendation="showRecommendation"
@show-matching="showMatching" @show-selection-info="showSelectionInfo" />
<!-- 钻头设计推荐方案页面 -->
<!-- 钻头设计参数推荐页面 -->
<BitDesignRecommendation v-if="currentPage === 'recommendation'" @match-bit="showMatching" @back="goBack" />
<!-- 钻头匹配页面 -->
......@@ -57,7 +57,7 @@ export default {
// 显示推荐方案页面
showRecommendation() {
this.currentPage = 'recommendation'
this.updateBreadcrumb('钻头设计推荐方案')
this.updateBreadcrumb('钻头设计参数推荐')
this.addToHistory('recommendation')
},
......@@ -99,7 +99,7 @@ export default {
updateBreadcrumb(pageName) {
const breadcrumbMap = {
'main': '钻头设计参数推荐',
'recommendation': '钻头设计推荐方案',
'recommendation': '钻头设计参数推荐',
'matching': '钻头匹配',
'selection-info': '查看选型信息'
}
......@@ -117,7 +117,7 @@ export default {
updateBreadcrumbFromHistory() {
const breadcrumbMap = {
'main': '钻头设计参数推荐',
'recommendation': '钻头设计推荐方案',
'recommendation': '钻头设计参数推荐',
'matching': '钻头匹配',
'selection-info': '查看选型信息'
}
......
......@@ -25,11 +25,11 @@
<!-- 上方推荐方案 -->
<div class="recommendation-section">
<div class="recommendation-panel">
<h3>钻头设计推荐方案</h3>
<h3>钻头设计参数推荐</h3>
<el-table :data="[recommendationData]" border style="width: 100%">
<el-table-column prop="bladeCount" label="刀翼数" min-width="120px" align="center" />
<el-table-column prop="bladeCount" label="刀翼数" min-width="120px" align="center" />
<el-table-column prop="density" label="布齿密度" min-width="120px" align="center" />
<el-table-column prop="toothSize" label="切削齿尺寸" min-width="120px" align="center" />
<el-table-column prop="toothSize" label="切削齿尺寸mm" min-width="120px" align="center" />
<el-table-column prop="negativeAngle" label="切削齿后倾角°" min-width="120px" align="center" />
<el-table-column prop="crownProfile" label="冠状轮廓" min-width="120px" align="center" />
<el-table-column label="操作" align="center" fixed="right" width="250px"
......
......@@ -2,60 +2,34 @@
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="厂家名称" prop="mc">
<el-input
v-model="queryParams.mc"
placeholder="请输入厂家名称"
clearable
@keyup.enter.native="handleQuery"
/>
<el-input v-model="queryParams.mc" placeholder="请输入厂家名称" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:ztxxCj:add']"
>新增</el-button>
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['system:ztxxCj:add']">新增</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="ztxxCjList" @selection-change="handleSelectionChange">
<el-table border v-loading="loading" :data="ztxxCjList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="厂家名称" align="center" prop="mc" />
<el-table-column label="排序" align="center" prop="px" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:ztxxCj:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:ztxxCj:remove']"
>删除</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['system:ztxxCj:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['system:ztxxCj:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 添加或修改厂家信息对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
......@@ -160,7 +134,7 @@ export default {
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
......@@ -202,12 +176,12 @@ export default {
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
this.$modal.confirm('是否确认删除厂家信息编号为"' + ids + '"的数据项?').then(function() {
this.$modal.confirm('是否确认删除厂家信息编号为"' + ids + '"的数据项?').then(function () {
return delZtxxCj(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
}).catch(() => { });
},
/** 导出按钮操作 */
handleExport() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment