spectrogramchartsNew.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. <template>
  2. <div>
  3. <!-- ECharts 图表容器 -->
  4. <div class="line-chart" ref="chart"></div>
  5. <div class="control-panel">
  6. <!-- 频率范围 -->
  7. <div class="box full-row">
  8. <div class="panel-block">
  9. <span class="label1">频率</span>
  10. <el-input v-model="freqMin" size="mini" placeholder="下限" />
  11. <span>~</span>
  12. <el-input v-model="freqMax" size="mini" placeholder="上限" />
  13. <el-button size="mini" type="primary" @click="handleFreqRange">
  14. 应用
  15. </el-button>
  16. </div>
  17. </div>
  18. </div>
  19. <div class="control-panel">
  20. <!-- 手动标注 -->
  21. <div class="panel-block">
  22. <span class="label1">标注</span>
  23. <el-input v-model="manualFreq" size="mini" placeholder="频率" />
  24. <el-input v-model="multiple" size="mini" placeholder="倍频" />
  25. <el-button size="mini" type="success" @click="handleMark"
  26. >标注</el-button
  27. >
  28. </div>
  29. <!-- 光标(单选) -->
  30. <div class="panel-block">
  31. <span class="label">光标</span>
  32. <div class="btn-group">
  33. <span
  34. v-for="item in GBcheckList"
  35. :key="item.val"
  36. :class="['btn', checkedGB.includes(item.val) ? 'active' : '']"
  37. @click="selectCursor(item.val)"
  38. >
  39. {{ item.val }}
  40. </span>
  41. </div>
  42. </div>
  43. <!-- 特征选择(四分类) -->
  44. <div class="feature-grid">
  45. <div
  46. class="feature-item"
  47. v-for="group in featureGroups"
  48. :key="group.type"
  49. >
  50. <div class="label">{{ group.label }}</div>
  51. <el-select
  52. v-model="selectedMap[group.type]"
  53. multiple
  54. collapse-tags
  55. size="small"
  56. placeholder="请选择"
  57. :disabled="!group.children.length"
  58. @change="handleFeatureChange"
  59. >
  60. <el-option
  61. v-for="item in group.children"
  62. :key="item"
  63. :label="item"
  64. :value="item"
  65. />
  66. </el-select>
  67. </div>
  68. </div>
  69. <!-- 特征值(多选) -->
  70. <!-- <div class="panel-block full-width">
  71. <span class="label">特征 </span>
  72. <el-cascader
  73. v-model="selectedFeatures"
  74. :options="cascaderOptions"
  75. :props="cascaderProps"
  76. collapse-tags
  77. clearable
  78. placeholder="请选择特征"
  79. size="small"
  80. @change="handleCascaderChange"
  81. />
  82. </div> -->
  83. </div>
  84. </div>
  85. </template>
  86. <script>
  87. import axios from "axios";
  88. import * as echarts from "echarts";
  89. import cursorReferenceMixin from "./spectrogramcharts/cursorReferenceMixin";
  90. import Bdgb from "./spectrogramcharts/Bdgb";
  91. import Xdgb from "./spectrogramcharts/Xdgb";
  92. import Tjgb from "./spectrogramcharts/Tjgb";
  93. export default {
  94. name: "TimedomainCharts",
  95. mixins: [cursorReferenceMixin, Bdgb, Xdgb, Tjgb],
  96. props: {
  97. currentIndex: {
  98. type: Number,
  99. default: 0,
  100. },
  101. activeIndex: {
  102. type: Number,
  103. default: 0,
  104. },
  105. ids: {
  106. type: Array,
  107. default: () => [],
  108. },
  109. spectrumListTwo: {
  110. type: Object,
  111. default: () => ({}),
  112. },
  113. currentRow: {
  114. type: Object,
  115. default: () => ({}),
  116. },
  117. windCode: {
  118. type: String,
  119. default: "",
  120. },
  121. },
  122. data() {
  123. return {
  124. freqMin: "",
  125. freqMax: "",
  126. manualFreq: "",
  127. multiple: 1,
  128. manualMarks: [],
  129. chartInstance: null,
  130. option: null,
  131. // TZshow: false,
  132. BGshow: false,
  133. PXshow: false,
  134. spectrumList: {},
  135. GBcheckList: [
  136. { val: "添加光标", checked: false, disabled: false },
  137. { val: "谐波光标", checked: false, disabled: false },
  138. { val: "边带光标", checked: false, disabled: false },
  139. { val: "移动峰值", checked: false, disabled: false },
  140. ],
  141. PXcheckList: [
  142. { val: "转速频率", checked: false },
  143. { val: "内圈故障频率", checked: false },
  144. { val: "外圈故障频率", checked: false },
  145. { val: "滚动体故障频率", checked: false },
  146. { val: "保持架频率", checked: false },
  147. { val: "叶片频率", checked: false },
  148. ],
  149. featureGroups: [
  150. {
  151. label: "轴承故障",
  152. type: "bearing",
  153. children: ["GEN-DE BPFO", "GEN-DE BPFI", "GEN-DE BSF", "GEN-DE FTF"],
  154. },
  155. {
  156. label: "转动基频",
  157. type: "rotation",
  158. children: ["转速频率"],
  159. },
  160. {
  161. label: "结构频率",
  162. type: "structure",
  163. children: ["叶片频率"],
  164. },
  165. {
  166. label: "齿轮特征",
  167. type: "gear",
  168. children: [],
  169. },
  170. ],
  171. featureKeyMap: {
  172. "GEN-DE BPFO": "BPFO",
  173. "GEN-DE BPFI": "BPFI",
  174. "GEN-DE BSF": "BSF",
  175. "GEN-DE FTF": "FTF",
  176. 转速频率: "Fr",
  177. 叶片频率: "B3P",
  178. },
  179. // 每个分类单独存
  180. selectedMap: {
  181. bearing: [],
  182. rotation: [],
  183. structure: [],
  184. gear: [],
  185. },
  186. // 最终统一给图表用
  187. checkedFeatures: [],
  188. selectedFeatures: [],
  189. cascaderProps: {
  190. multiple: true, // 多选
  191. checkStrictly: false, // 不能选父节点(只选叶子)
  192. emitPath: true, // 返回路径(重要)
  193. },
  194. Fr: [],
  195. BPFI: [],
  196. BPFO: [],
  197. BSF: [],
  198. FTF: [],
  199. B3P: [],
  200. checkedGB: [],
  201. checkedValues: [],
  202. };
  203. },
  204. computed: {
  205. cascaderOptions() {
  206. return this.featureGroups.map((group) => ({
  207. label: group.label,
  208. value: group.label,
  209. children: group.children.map((item) => ({
  210. label: item,
  211. value: item,
  212. })),
  213. }));
  214. },
  215. },
  216. watch: {
  217. spectrumListTwo(newValue) {
  218. this.spectrumList = newValue;
  219. if (this.chartInstance) {
  220. this.updateChart(this.spectrumList.y, this.spectrumList.x);
  221. }
  222. },
  223. spectrumList: {
  224. handler(newValue) {
  225. if (!newValue) return;
  226. if (this.chartInstance) {
  227. this.updateChart(newValue.y, newValue.x);
  228. }
  229. },
  230. deep: true,
  231. },
  232. },
  233. beforeDestroy() {
  234. if (this.chartInstance) {
  235. this.chartInstance.getZr().off("dblclick", this.handleDoubleClick);
  236. this.chartInstance
  237. .getZr()
  238. .off("mousemove", this.handleSidebandCursorMove);
  239. this.chartInstance.dispose();
  240. }
  241. },
  242. mounted() {
  243. this.$nextTick(() => {
  244. setTimeout(() => {
  245. this.initializeChart();
  246. this.getTime();
  247. }, 500);
  248. });
  249. },
  250. methods: {
  251. handleFeatureChange() {
  252. // 1️⃣ 汇总所有选中的特征
  253. const allSelected = Object.values(this.selectedMap).flat();
  254. this.checkedFeatures = allSelected;
  255. // 2️⃣ 更新图表
  256. this.updateFeatureLinesByGroup();
  257. },
  258. // handleCascaderChange(val) {
  259. // // val 示例:
  260. // // [
  261. // // ["轴承故障", "GEN-DE BPFO"],
  262. // // ["转动基频", "转速频率"]
  263. // // ]
  264. // // 👉 只取最后一层(真正的特征)
  265. // this.checkedFeatures = val.map((item) => item[item.length - 1]);
  266. // this.updateFeatureLines();
  267. // },
  268. selectCursor(val) {
  269. // 单选逻辑
  270. if (this.checkedGB.includes(val)) {
  271. this.checkedGB = [];
  272. } else {
  273. this.checkedGB = [val];
  274. }
  275. const isMoveChecked = this.checkedGB.includes("移动峰值");
  276. const isSidebandChecked = this.checkedGB.includes("边带光标");
  277. const isHarmonicChecked = this.checkedGB.includes("谐波光标");
  278. isMoveChecked ? this.handleMoveCursor() : this.removeCursor();
  279. isSidebandChecked
  280. ? this.enableSidebandCursor()
  281. : this.disableSidebandCursor();
  282. isHarmonicChecked
  283. ? this.enableHarmonicCursor()
  284. : this.disableHarmonicCursor();
  285. },
  286. initializeChart() {
  287. const chartDom = this.$refs.chart;
  288. if (chartDom && !this.chartInstance) {
  289. this.chartInstance = echarts.init(chartDom);
  290. this.chartInstance.getZr().on("dblclick", this.handleDoubleClick);
  291. }
  292. this.$nextTick(() => {
  293. if (this.chartInstance && this.spectrumList.y && this.spectrumList.x) {
  294. this.updateChart(this.spectrumList.y, this.spectrumList.x);
  295. }
  296. });
  297. },
  298. toggleFeature(val) {
  299. const index = this.checkedValues.indexOf(val);
  300. if (index > -1) {
  301. this.checkedValues.splice(index, 1);
  302. } else {
  303. this.checkedValues.push(val);
  304. }
  305. this.handleCheckChange(); // 复用你原逻辑
  306. },
  307. handleFreqRange() {
  308. const min = Number(this.freqMin);
  309. const max = Number(this.freqMax);
  310. if (isNaN(min) || isNaN(max)) return;
  311. this.chartInstance.setOption({
  312. xAxis: { min, max },
  313. });
  314. },
  315. handleMark() {
  316. const freq = Number(this.manualFreq);
  317. const multiple = Number(this.multiple) || 1;
  318. if (isNaN(freq)) return;
  319. const marks = [];
  320. for (let i = 1; i <= multiple; i++) {
  321. marks.push({
  322. xAxis: freq * i,
  323. val: `${i}x`,
  324. });
  325. }
  326. this.manualMarks = marks;
  327. this.renderManualMarks();
  328. },
  329. // 特征值
  330. handleCheckChange() {
  331. this.PXcheckList.forEach((item) => {
  332. item.checked = this.checkedValues.includes(item.val);
  333. });
  334. this.updateFeatureLines();
  335. },
  336. renderManualMarks() {
  337. const option = this.chartInstance.getOption();
  338. const manualSeries = {
  339. id: "MANUAL_MARK",
  340. type: "line",
  341. markLine: {
  342. symbol: ["none", "none"],
  343. lineStyle: {
  344. color: "#ff0000",
  345. width: 2,
  346. type: "dashed",
  347. },
  348. label: {
  349. formatter: ({ data }) => data.val,
  350. },
  351. data: this.manualMarks,
  352. },
  353. };
  354. this.chartInstance.setOption({
  355. series: [
  356. ...option.series.filter((s) => s.id !== "MANUAL_MARK"),
  357. manualSeries,
  358. ],
  359. });
  360. },
  361. updateFeatureLinesByGroup() {
  362. if (!this.spectrumList) return;
  363. const featureLines = {
  364. Fr: [],
  365. BPFI: [],
  366. BPFO: [],
  367. BSF: [],
  368. FTF: [],
  369. B3P: [],
  370. };
  371. this.checkedFeatures.forEach((featureName) => {
  372. const key = this.featureKeyMap[featureName];
  373. if (!key) return;
  374. switch (key) {
  375. case "Fr":
  376. featureLines.Fr = this.spectrumList.fn_Gen || [];
  377. break;
  378. case "BPFI":
  379. featureLines.BPFI = this.spectrumList.BPFI || [];
  380. break;
  381. case "BPFO":
  382. featureLines.BPFO = this.spectrumList.BPFO || [];
  383. break;
  384. case "BSF":
  385. featureLines.BSF = this.spectrumList.BSF || [];
  386. break;
  387. case "FTF":
  388. featureLines.FTF = this.spectrumList.FTF || [];
  389. break;
  390. case "B3P":
  391. featureLines.B3P = Array.isArray(this.spectrumList.B3P)
  392. ? this.spectrumList.B3P
  393. : this.spectrumList.B3P
  394. ? [{ Xaxis: this.spectrumList.B3P, val: "3P" }]
  395. : [];
  396. break;
  397. }
  398. });
  399. this.renderFeatureSeries(featureLines);
  400. },
  401. updateFeatureLines() {
  402. const newFeatureLines = {
  403. Fr: this.checkedValues.includes("转速频率")
  404. ? this.spectrumList.fn_Gen
  405. : [],
  406. BPFI: this.checkedValues.includes("内圈故障频率")
  407. ? this.spectrumList.BPFI
  408. : [],
  409. BPFO: this.checkedValues.includes("外圈故障频率")
  410. ? this.spectrumList.BPFO
  411. : [],
  412. BSF: this.checkedValues.includes("滚动体故障频率")
  413. ? this.spectrumList.BSF
  414. : [],
  415. FTF: this.checkedValues.includes("保持架频率")
  416. ? this.spectrumList.FTF
  417. : [],
  418. B3P: this.checkedValues.includes("叶片频率")
  419. ? Array.isArray(this.spectrumList.B3P)
  420. ? this.spectrumList.B3P
  421. : [{ Xaxis: this.spectrumList.B3P, val: "3P" }]
  422. : [],
  423. };
  424. if (this.chartInstance) {
  425. const currentOption = this.chartInstance.getOption();
  426. // 获取现有的光标系列
  427. const cursorLineSeries =
  428. currentOption.series.find((s) => s.id === "CURSOR_LINE_SERIES") || {};
  429. const cursorPointSeries =
  430. currentOption.series.find((s) => s.id === "CURSOR_POINT_SERIES") ||
  431. {};
  432. const cursorHighLineSeries =
  433. currentOption.series.find((s) => s.id === "PEAK_REFERENCE_LINE") ||
  434. {};
  435. // 生成新的特征值系列
  436. const featureSeries = this.generateSeries(newFeatureLines);
  437. this.chartInstance.setOption(
  438. {
  439. series: [
  440. currentOption.series[0], // 主数据系列
  441. ...featureSeries.slice(1), // 新的特征值系列
  442. cursorLineSeries, // 保留光标线系列
  443. cursorPointSeries, // 保留光标点系列
  444. cursorHighLineSeries, // 保留峰值参考线
  445. ],
  446. },
  447. { replaceMerge: ["series"] },
  448. );
  449. }
  450. },
  451. generateSeries(featureLines) {
  452. const createMarkLine = (dataSource, color) => ({
  453. type: "line",
  454. markLine: {
  455. silent: false,
  456. lineStyle: { color, type: "dashed", width: 1 },
  457. symbol: ["none", "none"],
  458. label: {
  459. show: true,
  460. position: "end",
  461. formatter: ({ data }) => data.val,
  462. },
  463. emphasis: {
  464. lineStyle: { color: "#FF6A00", width: 2 },
  465. label: {
  466. show: true,
  467. formatter: ({ value }) => `特征值: ${value}`,
  468. color: "#000",
  469. },
  470. },
  471. data: dataSource.map(({ Xaxis, val }) => ({ xAxis: Xaxis, val })),
  472. },
  473. });
  474. const markLines = [
  475. { data: featureLines.Fr, color: "#A633FF" },
  476. { data: featureLines.BPFI, color: "#23357e" },
  477. { data: featureLines.BPFO, color: "#42a0ae" },
  478. { data: featureLines.BSF, color: "#008080" },
  479. { data: featureLines.FTF, color: "#af254f" },
  480. { data: featureLines.B3P, color: "#FFD700" },
  481. ].map(({ data, color }) => createMarkLine(data, color));
  482. return [
  483. {
  484. name: "数据系列",
  485. type: "line",
  486. data: this.spectrumList.x.map((x, i) => [x, this.spectrumList.y[i]]),
  487. symbol: "none",
  488. lineStyle: { color: "#162961", width: 1 },
  489. itemStyle: { color: "#162961", borderColor: "#fff", borderWidth: 1 },
  490. large: true,
  491. },
  492. ...markLines,
  493. ];
  494. },
  495. updateChart(data, labels) {
  496. if (
  497. !this.chartInstance ||
  498. !Array.isArray(labels) ||
  499. !Array.isArray(data) ||
  500. labels.length !== data.length
  501. ) {
  502. console.error("Invalid data or labels");
  503. return;
  504. }
  505. const createMarkLine = (dataSource, color) => ({
  506. type: "line",
  507. markLine: {
  508. silent: false,
  509. lineStyle: { color, type: "solid", width: 2 },
  510. symbol: ["none", "none"],
  511. label: {
  512. show: true,
  513. position: "end",
  514. formatter: ({ data }) => data.val,
  515. },
  516. emphasis: {
  517. lineStyle: { color: "#FF6A00", width: 4 },
  518. label: {
  519. show: true,
  520. formatter: ({ value }) => `特征值: ${value}`,
  521. color: "#000",
  522. backgroundColor: "#FFF",
  523. padding: [2, 4],
  524. borderRadius: 3,
  525. fontSize: 12,
  526. },
  527. },
  528. data: dataSource.map(({ Xaxis, val }) => ({ xAxis: Xaxis, val })),
  529. },
  530. });
  531. const markLines = [
  532. { data: this.Fr, color: "#A633FF" },
  533. { data: this.BPFI, color: "#23357e" },
  534. { data: this.BPFO, color: "#42a0ae" },
  535. { data: this.BSF, color: "#008080" },
  536. { data: this.FTF, color: "#af254f" },
  537. { data: this.B3P, color: "#FFD700" },
  538. ].map(({ data, color }) => createMarkLine(data, color));
  539. const option = {
  540. grid: {
  541. left: 60, // 原来是100,适当缩小左右边距
  542. right: 20,
  543. top: 80, // 给推拽条和坐标轴腾出空间
  544. // top: 60,
  545. },
  546. // title: { text: this.spectrumList.title, left: "center" },
  547. toolbox: {
  548. right: 10,
  549. top: 40, // 👈 工具栏在最上面
  550. feature: {
  551. dataZoom: { yAxisIndex: "none" },
  552. restore: {},
  553. saveAsImage: {},
  554. },
  555. },
  556. xAxis: {
  557. type: "value",
  558. name: this.spectrumList.xaxis,
  559. nameLocation: "center",
  560. nameTextStyle: {
  561. fontSize: 14,
  562. color: "#333",
  563. padding: [15, 0, 0, 0], // 增加X轴标题和轴线的距离
  564. },
  565. axisLabel: {
  566. margin: 1, // 增加数值标签和轴线的间距
  567. formatter: (value) => value,
  568. },
  569. },
  570. yAxis: {
  571. type: "value",
  572. name: this.spectrumList.yaxis,
  573. nameTextStyle: {
  574. fontSize: 14,
  575. color: "#333",
  576. padding: [10, 0, 0, 0],
  577. },
  578. },
  579. tooltip: {
  580. trigger: "axis",
  581. formatter: ([
  582. {
  583. value: [x, y],
  584. },
  585. ]) => `X: ${x}<br/>Y: ${y}`,
  586. axisPointer: { type: "line" },
  587. },
  588. dataZoom: [
  589. { type: "inside", start: 0, end: 10 },
  590. {
  591. type: "slider",
  592. start: 0,
  593. end: 10,
  594. handleSize: "80%",
  595. showDataShadow: false,
  596. top: 10, // 👈 放到顶部
  597. height: 20, // 👈 控制高度(可选)
  598. },
  599. ],
  600. series: [
  601. {
  602. name: "数据系列",
  603. type: "line",
  604. data: labels.map((x, i) => [x, data[i]]),
  605. symbol: "none",
  606. lineStyle: { color: "#162961", width: 1 },
  607. itemStyle: {
  608. color: "#162961",
  609. borderColor: "#fff",
  610. borderWidth: 1,
  611. },
  612. large: true,
  613. progressive: 2000,
  614. },
  615. ...markLines,
  616. ],
  617. };
  618. this.chartInstance.setOption(option);
  619. },
  620. renderFeatureSeries(featureLines) {
  621. if (!this.chartInstance) return;
  622. const currentOption = this.chartInstance.getOption();
  623. // 保留光标
  624. const cursorLineSeries =
  625. currentOption.series.find((s) => s.id === "CURSOR_LINE_SERIES") || {};
  626. const cursorPointSeries =
  627. currentOption.series.find((s) => s.id === "CURSOR_POINT_SERIES") || {};
  628. const cursorHighLineSeries =
  629. currentOption.series.find((s) => s.id === "PEAK_REFERENCE_LINE") || {};
  630. const featureSeries = this.generateSeries(featureLines);
  631. this.chartInstance.setOption(
  632. {
  633. series: [
  634. currentOption.series[0], // 主线
  635. ...featureSeries.slice(1),
  636. cursorLineSeries,
  637. cursorPointSeries,
  638. cursorHighLineSeries,
  639. ],
  640. },
  641. { replaceMerge: ["series"] },
  642. );
  643. },
  644. // 获取数据
  645. getTime() {
  646. this.$emit("handleLoading", null, true, this.activeIndex);
  647. const params = {
  648. ids: this.ids,
  649. windCode: this.windCode,
  650. analysisType: "frequency",
  651. };
  652. axios
  653. .post("/AnalysisMulti/analysis/frequency", params)
  654. .then((res) => {
  655. this.spectrumList = { ...JSON.parse(res.data) };
  656. console.log(this.spectrumList, "频谱图数据1");
  657. const XrmsValue = this.spectrumList?.Xrms;
  658. this.$emit("updateXrms", XrmsValue);
  659. // 拉完数据后,如果已有选中项,自动渲染
  660. this.$nextTick(() => {
  661. this.updateFeatureLinesByGroup();
  662. });
  663. })
  664. .catch((error) => {
  665. console.error(error);
  666. })
  667. .finally(() => {
  668. this.$emit("handleLoading", this.currentRow, false, this.activeIndex);
  669. });
  670. },
  671. Show(value) {
  672. const stateMap = {
  673. 1: { TZshow: true, BGshow: false, PXshow: false },
  674. 2: { TZshow: false, BGshow: true, PXshow: false },
  675. 3: { TZshow: false, BGshow: false, PXshow: true },
  676. };
  677. if (stateMap[value]) {
  678. this.TZshow = value === "1" ? !this.TZshow : false;
  679. this.BGshow = value === "2" ? !this.BGshow : false;
  680. this.PXshow = value === "3" ? !this.PXshow : false;
  681. }
  682. },
  683. },
  684. };
  685. </script>
  686. <style lang="scss" scoped>
  687. .line-chart {
  688. width: 100%;
  689. height: 320px;
  690. }
  691. .FD {
  692. width: 100%;
  693. height: 1px;
  694. position: relative;
  695. }
  696. .eigenvalue {
  697. position: absolute;
  698. top: 60px;
  699. right: 0;
  700. font-size: 10px;
  701. width: 146px;
  702. border: 1px solid rgb(182, 182, 182);
  703. padding: 5px;
  704. background: #fff;
  705. z-index: 99;
  706. border-radius: 5px;
  707. h5 {
  708. line-height: 16px;
  709. height: 16px;
  710. }
  711. }
  712. .eigenvalue--first {
  713. width: 100px;
  714. }
  715. .control-panel {
  716. display: flex;
  717. flex-wrap: wrap;
  718. justify-content: space-between;
  719. gap: 12px;
  720. padding: 8px 12px;
  721. background: #f5f7fa;
  722. border: 1px solid #ddd;
  723. border-radius: 6px;
  724. margin-bottom: 10px;
  725. }
  726. /* 🌟 关键:独占一行 */
  727. .full-row {
  728. width: 100%;
  729. .panel-block {
  730. width: 45%;
  731. }
  732. }
  733. .panel-block {
  734. display: flex;
  735. align-items: center;
  736. gap: 6px;
  737. }
  738. .label {
  739. font-size: 12px;
  740. color: #666;
  741. }
  742. .label1 {
  743. font-size: 12px;
  744. color: #666;
  745. display: inline-block;
  746. width: 75px;
  747. }
  748. .btn-group {
  749. display: flex;
  750. gap: 6px;
  751. }
  752. .btn {
  753. padding: 2px 8px;
  754. font-size: 12px;
  755. border: 1px solid #ccc;
  756. border-radius: 3px;
  757. cursor: pointer;
  758. }
  759. .btn.active {
  760. background: #409eff;
  761. color: #fff;
  762. }
  763. .full-width {
  764. width: 100%;
  765. }
  766. .el-cascader {
  767. font-size: 12px;
  768. }
  769. .el-cascader__tags {
  770. max-width: 240px;
  771. overflow: hidden;
  772. }
  773. .feature-grid {
  774. display: grid;
  775. grid-template-columns: repeat(4, 1fr); // 两列布局
  776. gap: 10px;
  777. width: 100%;
  778. }
  779. .feature-item {
  780. display: flex;
  781. align-items: center;
  782. gap: 6px;
  783. }
  784. .el-select {
  785. flex: 1;
  786. }
  787. </style>