bearing.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. <template>
  2. <div>
  3. <div class="TopBox">
  4. <div class="rightdiv">
  5. <el-table
  6. ref="multipleTable"
  7. :data="tableData"
  8. tooltip-effect="dark"
  9. style="width: 100%"
  10. height="250"
  11. >
  12. <!-- <el-table-column fixed type="selection" width="55"> </el-table-column> -->
  13. <el-table-column
  14. prop="timeStamp"
  15. label="时间"
  16. align="center"
  17. width="150"
  18. >
  19. </el-table-column>
  20. <el-table-column
  21. prop="samplingFrequency"
  22. label="采样频率(Hz)"
  23. align="center"
  24. >
  25. </el-table-column>
  26. <el-table-column
  27. prop="rotationalSpeed"
  28. label="转速(rpm)"
  29. align="center"
  30. >
  31. </el-table-column>
  32. </el-table>
  33. <div class="fenye">
  34. <p><span>故障状态代码说明:</span>0代表正常,1代表报警,2代表危险</p>
  35. <el-pagination
  36. @current-change="handleCurrentChange"
  37. :current-page="currentPage"
  38. layout="total, prev, pager, next, jumper"
  39. :total="totalCount"
  40. :page-size="20"
  41. small
  42. ></el-pagination>
  43. </div>
  44. </div>
  45. <div class="leftdiv">
  46. <div class="stateBox">
  47. <h4>轴承状态</h4>
  48. <div class="state">
  49. <p :style="{ backgroundColor: bearingStateColors.innerRing }">
  50. 轴承内圈状态
  51. </p>
  52. <p :style="{ backgroundColor: bearingStateColors.outerRing }">
  53. 轴承外圈状态
  54. </p>
  55. <p :style="{ backgroundColor: bearingStateColors.rollingElement }">
  56. 轴承滚动体状态
  57. </p>
  58. <p :style="{ backgroundColor: bearingStateColors.cage }">
  59. 轴承保持架状态
  60. </p>
  61. </div>
  62. <el-button
  63. type="primary"
  64. size="small"
  65. @click="automaticDiagnosis"
  66. class="btn-auto"
  67. >自动诊断</el-button
  68. >
  69. </div>
  70. <div class="Btn">
  71. <div style="height: 200px">
  72. <bing :result="result"> </bing>
  73. </div>
  74. <div class="minp">
  75. <p class="PText">
  76. <span><i class="color1"></i>正常</span
  77. ><span><i class="color2"></i>报警</span
  78. ><span><i class="color3"></i>危险</span>
  79. </p>
  80. <h4>诊断步骤:</h4>
  81. <p>1、选择振动测点与起止时间,点击“查询”;</p>
  82. <p>2、对轴承“参数设置”输入相关信息;</p>
  83. <p>3、点击“自动诊断”输出最终轴承状态结果。</p>
  84. </div>
  85. </div>
  86. </div>
  87. </div>
  88. <div class="bottomBox">
  89. <div class="BtLeft">
  90. <h4>轴承状态趋势图</h4>
  91. <el-empty
  92. v-if="this.xData.length === 0 || this.yData.length === 0"
  93. description="暂无数据"
  94. style="padding: 46px 0"
  95. ></el-empty>
  96. <Eecharts
  97. v-else
  98. style="height: 300px"
  99. :xData="xData"
  100. :yData="yData"
  101. :yNames="[
  102. '轴承内圈状态',
  103. '轴承外圈状态',
  104. '轴承滚动体状态',
  105. '轴承保持架状态',
  106. ]"
  107. yAxisName="轴承故障状态"
  108. ></Eecharts>
  109. </div>
  110. <el-dialog
  111. title="提示"
  112. :visible.sync="dialogVisible"
  113. width="50%"
  114. >
  115. <div class="BtRight">
  116. <h4>参数设置</h4>
  117. <div class="BtRightDiv">
  118. <p class="BtRightP">
  119. 发电机到轴承测点转速传动比<span
  120. ><el-input
  121. v-model="transmissionRatio"
  122. size="small"
  123. v-number-only
  124. ></el-input
  125. ></span>
  126. </p>
  127. <h4>滚动轴承参数输入</h4>
  128. <div class="canshu">
  129. <p class="BtRightP">
  130. <span class="label-text">轴承节圆直径D(mm)</span>
  131. <span
  132. ><el-input
  133. v-model="bearingPitchDiameter"
  134. size="small"
  135. v-number-only
  136. ></el-input
  137. ></span>
  138. </p>
  139. <p class="BtRightP">
  140. <span class="label-text">滚动体直径d(mm)</span>
  141. <span
  142. ><el-input
  143. v-model="rollingElementDiameter"
  144. size="small"
  145. v-number-only
  146. ></el-input
  147. ></span>
  148. </p>
  149. <p class="BtRightP">
  150. <span class="label-text">滚动体个数Z(个)</span>
  151. <span
  152. ><el-input
  153. v-model="rollingElementCount"
  154. size="small"
  155. v-number-only
  156. ></el-input
  157. ></span>
  158. </p>
  159. <p class="BtRightP">
  160. <span class="label-text">接触角α(°)</span>
  161. <span
  162. ><el-input
  163. v-model="contactAngle"
  164. size="small"
  165. v-number-only
  166. ></el-input
  167. ></span>
  168. </p>
  169. </div>
  170. <h4>报警阈值输入</h4>
  171. <div class="canshu">
  172. <p class="BtRightP">
  173. <span class="label-text">振动速度报警阈值(mm/s)</span>
  174. <span
  175. ><el-input
  176. v-model="vibrationSpeedAlarmThreshold"
  177. size="small"
  178. v-number-only
  179. ></el-input
  180. ></span>
  181. </p>
  182. <p class="BtRightP">
  183. <span class="label-text">振动速度危险阈值(mm/s)</span>
  184. <span
  185. ><el-input
  186. v-model="vibrationSpeedDangerThreshold"
  187. size="small"
  188. v-number-only
  189. ></el-input
  190. ></span>
  191. </p>
  192. <p class="BtRightP">
  193. <span class="label-text">包络总值报警阈值(gE)</span>
  194. <span
  195. ><el-input
  196. v-model="envelopeTotalAlarmThreshold"
  197. size="small"
  198. v-number-only
  199. ></el-input
  200. ></span>
  201. </p>
  202. <p class="BtRightP">
  203. <span class="label-text">包络总值危险阈值(gE)</span>
  204. <span
  205. ><el-input
  206. v-model="envelopeTotalDangerThreshold"
  207. size="small"
  208. v-number-only
  209. ></el-input
  210. ></span>
  211. </p>
  212. </div>
  213. </div>
  214. </div>
  215. <div class="dialog-footer">
  216. <el-button type="primary" size="small" @click="submit"
  217. >确定</el-button
  218. >
  219. </div>
  220. </el-dialog>
  221. </div>
  222. </div>
  223. </template>
  224. <script>
  225. import Eecharts from "./Eecharts.vue";
  226. import bing from "./bing.vue";
  227. import { cacheEntryPossiblyAdded } from "plotly.js-dist";
  228. export default {
  229. components: { Eecharts, bing },
  230. props: {
  231. codedata: {
  232. type: Array,
  233. default: () => [],
  234. },
  235. totalCount: {
  236. type: Number,
  237. default: 0,
  238. },
  239. totalPage: {
  240. type: Number,
  241. default: 0,
  242. },
  243. },
  244. data() {
  245. return {
  246. tableData: [],
  247. // 添加新的数据属性用于绑定输入框的值
  248. transmissionRatio: "",
  249. bearingPitchDiameter: "",
  250. rollingElementDiameter: "",
  251. rollingElementCount: "",
  252. contactAngle: "",
  253. vibrationSpeedAlarmThreshold: "",
  254. vibrationSpeedDangerThreshold: "",
  255. envelopeTotalAlarmThreshold: "",
  256. envelopeTotalDangerThreshold: "",
  257. // 分页
  258. currentPage: 1,
  259. total: 1,
  260. xData: [],
  261. yData: [],
  262. // 颜色判断
  263. bearingStateColors: {
  264. innerRing: "#80808057",
  265. outerRing: "#80808057",
  266. rollingElement: "#80808057",
  267. cage: "#80808057",
  268. },
  269. hasError: false, // 标志是否已经显示过错误提示
  270. result: {},
  271. dialogVisible: false,
  272. };
  273. },
  274. created() {},
  275. watch: {
  276. codedata: {
  277. handler(newVal) {
  278. this.tableData = newVal;
  279. },
  280. immediate: true, // 组件创建时立刻执行一次
  281. deep: true, // 如果 codedata 是复杂对象,建议加上
  282. },
  283. },
  284. methods: {
  285. toggleSelection(rows) {
  286. if (rows) {
  287. rows.forEach((row) => {
  288. this.$refs.multipleTable.toggleRowSelection(row);
  289. });
  290. } else {
  291. this.$refs.multipleTable.clearSelection();
  292. }
  293. },
  294. handleSelectionChange(val) {
  295. this.multipleSelection = val;
  296. },
  297. handleCurrentChange(val) {
  298. console.log(`当前页: ${val}`);
  299. this.currentPage = val; // 子组件内部更新当前页
  300. this.$emit("updatePage", this.currentPage); // 通知父组件,把当前页传出去
  301. },
  302. automaticDiagnosis() {
  303. this.dialogVisible = true;
  304. },
  305. submit() {
  306. // 验证必填项
  307. const requiredFields = [
  308. { field: this.transmissionRatio, name: "发动机到轴承测点转速传动比" },
  309. { field: this.bearingPitchDiameter, name: "轴承节圆直径D(mm)" },
  310. { field: this.rollingElementDiameter, name: "滚动体直径d(mm)" },
  311. { field: this.rollingElementCount, name: "滚动体个数Z(个)" },
  312. { field: this.contactAngle, name: "接触角α(°)" },
  313. {
  314. field: this.vibrationSpeedAlarmThreshold,
  315. name: "振动速度报警阈值(mm/s)",
  316. },
  317. {
  318. field: this.vibrationSpeedDangerThreshold,
  319. name: "振动速度危险阈值(mm/s)",
  320. },
  321. {
  322. field: this.envelopeTotalAlarmThreshold,
  323. name: "包络总值报警阈值(gE)",
  324. },
  325. {
  326. field: this.envelopeTotalDangerThreshold,
  327. name: "包络总值危险阈值(gE)",
  328. },
  329. ];
  330. // 记录是否已弹出过错误提示
  331. let hasError = false;
  332. // 只检查必填项的字段是否为空
  333. // for (const { field, name } of requiredFields) {
  334. // if (!field && !hasError) {
  335. // // 弹出提示并标记已经出现错误提示
  336. // this.$message.error(`${name} 是必填项`);
  337. // hasError = true; // 标记已经弹出过错误提示
  338. // return; // 停止执行后续逻辑
  339. // }
  340. // }
  341. // 如果验证通过,继续执行后续逻辑
  342. const newProps = this.tableData.map(() => ({
  343. innerRingFault: Math.floor(Math.random() * 3).toString(),
  344. outerRingFault: Math.floor(Math.random() * 3).toString(),
  345. rollingElementFault: Math.floor(Math.random() * 3).toString(),
  346. cageFault: Math.floor(Math.random() * 3).toString(),
  347. }));
  348. this.tableData.forEach((row, index) => {
  349. this.$set(this.tableData, index, {
  350. ...row,
  351. ...newProps[index], // 用每一行自己生成的随机数
  352. });
  353. });
  354. const faultValues = [
  355. ...this.tableData.map((record) => record.innerRingFault),
  356. ...this.tableData.map((record) => record.outerRingFault),
  357. ...this.tableData.map((record) => record.rollingElementFault),
  358. ...this.tableData.map((record) => record.cageFault),
  359. ];
  360. // 统计各个值出现的次数
  361. const counter = faultValues.reduce((acc, value) => {
  362. acc[value] = (acc[value] || 0) + 1;
  363. return acc;
  364. }, {});
  365. // 构造统计结果对象
  366. this.result = {
  367. 1: counter["0"] || 0,
  368. 2: counter["1"] || 0,
  369. 3: counter["2"] || 0,
  370. };
  371. // 更新颜色状态
  372. const fields = [
  373. { key: "innerRingFault", colorKey: "innerRing" },
  374. { key: "outerRingFault", colorKey: "outerRing" },
  375. { key: "rollingElementFault", colorKey: "rollingElement" },
  376. { key: "cageFault", colorKey: "cage" },
  377. ];
  378. fields.forEach(({ key, colorKey }) => {
  379. const values = newProps.map((item) => Number(item[key]));
  380. const maxVal = Math.max(...values);
  381. let color = "#80808057"; // 默认灰色
  382. if (maxVal === 0) color = "#8AE359"; // 无故障
  383. else if (maxVal === 1) color = "#EECB5F"; // 警告
  384. else if (maxVal === 2) color = "#F7715F"; // 危险
  385. this.bearingStateColors[colorKey] = color; // 更新颜色
  386. });
  387. // 更新趋势图数据
  388. // 更新趋势图数据(用tableData,不是newProps)
  389. this.xData = this.tableData.map((item) => item.timeStamp);
  390. this.yData = fields.map(({ key }) =>
  391. this.tableData.map((item) => Number(item[key]))
  392. );
  393. this.dialogVisible = false;
  394. },
  395. },
  396. };
  397. </script>
  398. <style lang="scss" scoped>
  399. h4 {
  400. margin-bottom: 5px;
  401. font-weight: 600;
  402. }
  403. .TopBox {
  404. height: 280px;
  405. display: flex;
  406. justify-content: space-around;
  407. .leftdiv {
  408. width: 50%;
  409. display: flex;
  410. justify-content: space-around;
  411. .stateBox {
  412. .state {
  413. display: flex;
  414. flex-direction: column;
  415. justify-content: center; /* 整体居中 */
  416. align-items: center;
  417. height: 200px;
  418. gap: 20px; /* 控制间距 */
  419. p {
  420. width: 150px;
  421. height: 40px;
  422. background: rgb(227, 227, 227);
  423. color: rgb(50, 50, 50);
  424. text-align: center;
  425. align-content: center;
  426. font-weight: 600;
  427. }
  428. }
  429. .btn-auto {
  430. margin-top: 10px;
  431. width: 100%;
  432. }
  433. }
  434. .Btn {
  435. width: 50%;
  436. display: flex;
  437. flex-direction: column; /* 垂直排列 */
  438. justify-content: space-between; /* 顶部和底部对齐 */
  439. min-height: 100px; /* 确保容器有足够高度 */
  440. margin: 10px 0;
  441. .PText {
  442. display: flex;
  443. justify-content: space-around;
  444. span {
  445. display: flex;
  446. align-items: center;
  447. i {
  448. width: 30px;
  449. height: 15px;
  450. margin-right: 5px;
  451. }
  452. .color1 {
  453. background-color: #8ae359;
  454. }
  455. .color2 {
  456. background-color: #eecb5f;
  457. }
  458. .color3 {
  459. background-color: #f7715f;
  460. }
  461. }
  462. }
  463. margin: 10px 0;
  464. .minp {
  465. font-size: 12px;
  466. margin-top: auto; /* 自动推到最底部 */
  467. }
  468. }
  469. }
  470. .rightdiv {
  471. width: 50%;
  472. .fenye {
  473. display: flex;
  474. justify-content: space-between;
  475. margin: 5px 0;
  476. font-size: 11px;
  477. line-height: 30px;
  478. span {
  479. font-weight: 600;
  480. }
  481. }
  482. }
  483. }
  484. .bottomBox {
  485. display: flex;
  486. justify-content: space-around;
  487. margin-top: 10px;
  488. .BtLeft {
  489. border: 1px solid rgb(231, 231, 231);
  490. width: 100%;
  491. padding: 10px;
  492. }
  493. .BtRight {
  494. border: 1px solid rgb(231, 231, 231);
  495. padding: 10px;
  496. .BtRightDiv {
  497. padding: 0 10px;
  498. h4 {
  499. font-size: 14px;
  500. }
  501. .BtRightP {
  502. line-height: 30px;
  503. font-size: 12px;
  504. display: flex;
  505. margin-bottom: 5px;
  506. width: 50%;
  507. span {
  508. margin-left: 10px;
  509. .el-input {
  510. width: 100px;
  511. }
  512. }
  513. .label-text {
  514. width: 140px;
  515. }
  516. }
  517. .canshu {
  518. display: flex;
  519. flex-wrap: wrap;
  520. justify-content: space-between;
  521. }
  522. }
  523. }
  524. .dialog-footer {
  525. margin-top: 20px;
  526. text-align: right;
  527. }
  528. }
  529. ::v-deep .el-table__cell {
  530. padding: 2px 0;
  531. font-size: 12px;
  532. }
  533. </style>