loose.vue 13 KB

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