gear.vue 13 KB

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