jgkl.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  1. <script setup>
  2. import {computed, onMounted, ref, watch} from "vue";
  3. import {AlertTriangle, Plus, RefreshCw, Search, Trash2, Wifi, WifiOff,} from "lucide-vue-next";
  4. import {ElMessage, ElMessageBox} from "element-plus";
  5. import request from "@/utils/request.js";
  6. import {getDicts} from "@/api/system/dict/data.js";
  7. import EchartsTyp from "@/components/baseEcharts/index.vue";
  8. import pieChart from "@/components/baseEcharts/pieChart.vue";
  9. import riEcharts from "@/components/baseEcharts/riEcharts.vue";
  10. // Data
  11. const deviceArr = ref([]);
  12. const search = ref({
  13. deviceName: "",
  14. });
  15. const loading = ref(false);
  16. const total = ref(0);
  17. const currentPage = ref(1);
  18. const pageSize = ref(10);
  19. const deviceType = ref({});
  20. const PieChartDataTwo = ref([]);
  21. const flipDataMonthly = ref([]);
  22. const waterImmersionMonthly = ref([]);
  23. const waterLevelMonthly = ref([]);
  24. const flipDataDay = ref([]);
  25. const waterImmersionDay = ref([]);
  26. const waterLevelDay = ref([]);
  27. const DagiveanalarmDate = ref([]);
  28. // 预览对话框
  29. const previewDialogVisible = ref(false);
  30. const currentDevice = ref({});
  31. // 编辑对话框
  32. const editDialogVisible = ref(false);
  33. const editForm = ref({
  34. id: "",
  35. deviceName: "",
  36. location: "",
  37. remarks: "",
  38. });
  39. // 新增对话框
  40. const addDialogVisible = ref(false);
  41. const addForm = ref({
  42. deviceName: "",
  43. deviceNumber: "",
  44. type: "1", // 默认值为1,根据之前的查询条件
  45. model: "",
  46. location: "",
  47. remarks: "",
  48. });
  49. const addFormRules = {
  50. deviceName: [{required: true, message: "请输入设备名称", trigger: "blur"}],
  51. deviceNumber: [{required: true, message: "请输入设备编号", trigger: "blur"}],
  52. model: [{required: true, message: "请输入设备型号", trigger: "blur"}],
  53. type: [{required: true, message: "请输入设备类型", trigger: "blur"}],
  54. };
  55. const addFormRef = ref(null);
  56. // 多选相关
  57. const multipleSelection = ref([]);
  58. const hasSelected = computed(() => multipleSelection.value.length > 0);
  59. // Methods
  60. const getAllDeviceInfo = async () => {
  61. loading.value = true;
  62. try {
  63. const arr = [
  64. {
  65. column: "type",
  66. type: "eq",
  67. value: "1",
  68. },
  69. ];
  70. if (search.value.deviceName) {
  71. arr.push({
  72. column: "device_name",
  73. type: "like",
  74. value: search.value.deviceName,
  75. });
  76. }
  77. const res = await request.get("/base/devices/findByPage", {
  78. params: {
  79. conditionJson: encodeURIComponent(JSON.stringify(arr)),
  80. pageNum: currentPage.value,
  81. pageSize: pageSize.value,
  82. },
  83. });
  84. if (res.code !== 200) {
  85. ElMessage.error(res.msg);
  86. return;
  87. }
  88. deviceArr.value = res.data.records;
  89. total.value = res.data.total;
  90. } catch (error) {
  91. ElMessage.error("获取设备数据失败");
  92. console.error(error);
  93. } finally {
  94. loading.value = false;
  95. }
  96. };
  97. // 工具方法:生成标准化时间范围
  98. const generateYearDateRange = () => {
  99. const currentYear = new Date().getFullYear();
  100. return {
  101. start: `${currentYear}-01-01 00:00:00`,
  102. end: `${currentYear}-${String(new Date().getMonth() + 1).padStart(2, "0")}-${String(
  103. new Date().getDate()
  104. ).padStart(2, "0")} 23:59:59`,
  105. };
  106. };
  107. // 工具方法:创建通用查询条件
  108. const createCondition = (column, status, dateRange) => [
  109. {column: column, type: "ne", value: status},
  110. {
  111. column: "create_time",
  112. type: "between",
  113. value: `${dateRange.start},${dateRange.end}`,
  114. },
  115. ];
  116. // 核心请求方法
  117. const fetchAlarmData = async (condition) => {
  118. const {data} = await request.get("/manholeData/getAll", {
  119. params: {
  120. conditionJson: encodeURIComponent(JSON.stringify(condition)),
  121. },
  122. });
  123. return data;
  124. };
  125. // 获取饼图数据法
  126. const getyearAllDeviceInfo = () => {
  127. try {
  128. const {start, end} = generateYearDateRange();
  129. // 定义报警类型配置
  130. const alarmTypes = [
  131. {column: "alarm_status", name: "翻转"},
  132. {column: "water_infiltration_alarm_status", name: "水浸"},
  133. {column: "water_level_alarm_status", name: "水位"},
  134. ];
  135. // 并行发送所有请求
  136. Promise.all(
  137. alarmTypes.map(async ({column}) =>
  138. fetchAlarmData(createCondition(column, "0", {start, end}))
  139. )
  140. )
  141. .then((res) => {
  142. PieChartDataTwo.value = res.map((res, index) => {
  143. return {
  144. value: res.length,
  145. name: alarmTypes[index].name,
  146. };
  147. });
  148. })
  149. .catch((error) => {
  150. ElMessage.error("获取数据失败");
  151. });
  152. // 构建图表数据
  153. } catch (error) {
  154. ElMessage.error("获取设备数据失败");
  155. console.error("API Error:", error);
  156. } finally {
  157. loading.value = false;
  158. }
  159. };
  160. //获取报警月统计数据
  161. const getobtainMonthlyData = async () => {
  162. loading.value = true;
  163. try {
  164. const {start, end} = generateYearDateRange();
  165. const res = await request.get("/manholeData/getMonthlyDataCount", {
  166. params: {
  167. startDate: start,
  168. endDate: end,
  169. },
  170. });
  171. if (res.code !== 200) {
  172. ElMessage.error(res.msg);
  173. return;
  174. }
  175. flipDataMonthly.value = res.data.alarm_status;
  176. waterImmersionMonthly.value = res.data.water_infiltration_alarm_status;
  177. waterLevelMonthly.value = res.data.water_level_alarm_status;
  178. } catch (error) {
  179. ElMessage.error("获取报警月统计数据失败");
  180. console.error(error);
  181. } finally {
  182. loading.value = false;
  183. }
  184. };
  185. //获取报警日统计数据
  186. const getobtainDayData = async () => {
  187. loading.value = true;
  188. try {
  189. const {start, end} = generateYearDateRange();
  190. const res = await request.get("/manholeData/getDailyDataCountThisMonth", {});
  191. if (res.code !== 200) {
  192. ElMessage.error(res.msg);
  193. return;
  194. }
  195. const array = [...Array(res.data.alarm_status.length).keys()].map((i) => i + 1);
  196. DagiveanalarmDate.value = array;
  197. flipDataDay.value = res.data.alarm_status;
  198. waterImmersionDay.value = res.data.water_infiltration_alarm_status;
  199. waterLevelDay.value = res.data.water_level_alarm_status;
  200. } catch (error) {
  201. ElMessage.error("获取报警月统计数据失败");
  202. console.error(error);
  203. } finally {
  204. loading.value = false;
  205. }
  206. };
  207. getobtainDayData();
  208. getobtainMonthlyData();
  209. getyearAllDeviceInfo();
  210. const handleSearch = () => {
  211. currentPage.value = 1;
  212. getAllDeviceInfo();
  213. };
  214. const handleReset = () => {
  215. search.value.deviceName = "";
  216. currentPage.value = 1;
  217. getAllDeviceInfo();
  218. };
  219. const handleSizeChange = (val) => {
  220. pageSize.value = val;
  221. getAllDeviceInfo();
  222. };
  223. const handleCurrentChange = (val) => {
  224. currentPage.value = val;
  225. getAllDeviceInfo();
  226. };
  227. // Format date
  228. const formatDate = (dateString) => {
  229. if (!dateString) return "-";
  230. const date = new Date(dateString);
  231. return date.toLocaleString();
  232. };
  233. // Watch for search changes
  234. watch(
  235. () => search.value.deviceName,
  236. (newVal, oldVal) => {
  237. if (newVal === "" && oldVal !== "") {
  238. handleSearch();
  239. }
  240. }
  241. );
  242. // 预览设备信息
  243. const handlePreview = async (id) => {
  244. try {
  245. const res = await request.get("/base/devices/getById/" + id);
  246. if (res.code !== 200) {
  247. ElMessage.error(res.msg);
  248. return;
  249. }
  250. currentDevice.value = res.data;
  251. previewDialogVisible.value = true;
  252. } catch (error) {
  253. ElMessage.error("获取设备详情失败");
  254. console.error(error);
  255. }
  256. };
  257. // 打开编辑对话框
  258. const openEditDialog = async (id) => {
  259. try {
  260. const res = await request.get("/base/devices/getById/" + id);
  261. if (res.code !== 200) {
  262. ElMessage.error(res.msg);
  263. return;
  264. }
  265. editForm.value = {
  266. id: res.data.id,
  267. deviceName: res.data.deviceName,
  268. location: res.data.location,
  269. remarks: res.data.remarks,
  270. };
  271. editDialogVisible.value = true;
  272. } catch (error) {
  273. ElMessage.error("获取设备详情失败");
  274. console.error(error);
  275. }
  276. };
  277. // 提交编辑表单
  278. const handleEdit = async () => {
  279. try {
  280. const res = await request.post("/base/devices/update", editForm.value);
  281. if (res.code !== 200) {
  282. ElMessage.error(res.msg);
  283. return;
  284. }
  285. ElMessage.success("修改成功");
  286. editDialogVisible.value = false;
  287. getAllDeviceInfo(); // 刷新列表
  288. } catch (error) {
  289. ElMessage.error("修改设备信息失败");
  290. console.error(error);
  291. }
  292. };
  293. // 打开新增对话框
  294. const openAddDialog = () => {
  295. addForm.value = {
  296. deviceName: "",
  297. deviceNumber: "",
  298. type: "1",
  299. model: "",
  300. location: "",
  301. remarks: "",
  302. };
  303. addDialogVisible.value = true;
  304. };
  305. // 提交新增表单
  306. const handleAdd = async () => {
  307. if (!addFormRef.value) return;
  308. addFormRef.value.validate(async (valid) => {
  309. if (!valid) return;
  310. try {
  311. const res = await request.post("/base/devices/save", addForm.value);
  312. if (res.code !== 200) {
  313. ElMessage.error(res.msg);
  314. return;
  315. }
  316. ElMessage.success("新增设备成功");
  317. addDialogVisible.value = false;
  318. getAllDeviceInfo(); // 刷新列表
  319. } catch (error) {
  320. ElMessage.error("新增设备失败");
  321. console.error(error);
  322. }
  323. });
  324. };
  325. // 处理多选
  326. const handleSelectionChange = (val) => {
  327. multipleSelection.value = val;
  328. };
  329. // 删除单个设备
  330. const handleDelete = async (id) => {
  331. try {
  332. await ElMessageBox.confirm("确认删除该设备吗?此操作不可恢复", "警告", {
  333. confirmButtonText: "确认",
  334. cancelButtonText: "取消",
  335. type: "warning",
  336. });
  337. const res = await request.delete("/base/devices/delete", {
  338. data: [id],
  339. });
  340. if (res.code !== 200) {
  341. ElMessage.error(res.msg);
  342. return;
  343. }
  344. ElMessage.success("删除成功");
  345. getAllDeviceInfo(); // 刷新列表
  346. } catch (error) {
  347. if (error !== "cancel") {
  348. ElMessage.error("删除设备失败");
  349. console.error(error);
  350. }
  351. }
  352. };
  353. // 批量删除设备
  354. const handleBatchDelete = async () => {
  355. if (multipleSelection.value.length === 0) {
  356. ElMessage.warning("请至少选择一个设备");
  357. return;
  358. }
  359. try {
  360. await ElMessageBox.confirm(
  361. `确认删除选中的 ${multipleSelection.value.length} 个设备吗?此操作不可恢复`,
  362. "警告",
  363. {
  364. confirmButtonText: "确认",
  365. cancelButtonText: "取消",
  366. type: "warning",
  367. }
  368. );
  369. const ids = multipleSelection.value.map((item) => item.id);
  370. const res = await request.delete("/base/devices/delete", {
  371. data: ids,
  372. });
  373. if (res.code !== 200) {
  374. ElMessage.error(res.msg);
  375. return;
  376. }
  377. ElMessage.success("批量删除成功");
  378. getAllDeviceInfo(); // 刷新列表
  379. } catch (error) {
  380. if (error !== "cancel") {
  381. ElMessage.error("批量删除设备失败");
  382. console.error(error);
  383. }
  384. }
  385. };
  386. const getDeviceType = async () => {
  387. const res = await getDicts("device_type");
  388. if (res.code !== 200) {
  389. ElMessage.error(res.msg);
  390. return;
  391. }
  392. deviceType.value = res.data?.reduce((acc, cur) => {
  393. acc[cur.dictValue] = cur.dictLabel;
  394. return acc;
  395. }, {});
  396. // console.log(deviceType.value);
  397. };
  398. onMounted(() => {
  399. getAllDeviceInfo();
  400. getDeviceType();
  401. });
  402. </script>
  403. <template>
  404. <div class="device-table-container p-4">
  405. <!-- Header with search -->
  406. <div class="mb-4 flex justify-between items-center">
  407. <div class="text-xl font-bold">设备管理</div>
  408. <div class="flex gap-2">
  409. <el-input
  410. v-model="search.deviceName"
  411. placeholder="搜索设备名称"
  412. class="w-64"
  413. clearable
  414. @keyup.enter="handleSearch"
  415. >
  416. <template #prefix>
  417. <Search class="w-4 h-4 text-gray-400"/>
  418. </template>
  419. </el-input>
  420. <el-button type="primary" @click="handleSearch" class="flex items-center">
  421. <Search class="w-4 h-4 mr-1"/>
  422. 搜索
  423. </el-button>
  424. <el-button @click="handleReset" class="flex items-center">
  425. <RefreshCw class="w-4 h-4 mr-1"/>
  426. 重置
  427. </el-button>
  428. </div>
  429. </div>
  430. <!-- 操作按钮 -->
  431. <div class="mb-4 flex justify-between">
  432. <div class="flex gap-2">
  433. <el-button type="primary" @click="openAddDialog" class="flex items-center">
  434. <Plus class="w-4 h-4 mr-1"/>
  435. 新增设备
  436. </el-button>
  437. <el-button
  438. type="danger"
  439. :disabled="!hasSelected"
  440. @click="handleBatchDelete"
  441. class="flex items-center"
  442. >
  443. <Trash2 class="w-4 h-4 mr-1"/>
  444. 批量删除
  445. </el-button>
  446. <span class="ml-2 text-gray-500 flex items-center" v-if="hasSelected">
  447. 已选择 {{ multipleSelection.length }} 项
  448. </span>
  449. </div>
  450. </div>
  451. <div>
  452. <el-card shadow="hover" class="mb-4">
  453. <template #header>
  454. <div class="flex justify-between items-center">
  455. <span class="font-bold">井盖统计</span>
  456. </div>
  457. </template>
  458. <div class="grid grid-cols-1 md:grid-cols-3 gap-4 h-100">
  459. <div class="stat-card bg-blue-50 p-4 rounded-lg h-100">
  460. <div class="text-blue-500 text-lg font-medium">报警年统计</div>
  461. <div class="h-80">
  462. <!-- <EchartsTyp></EchartsTyp> -->
  463. <pieChart :message="PieChartDataTwo"></pieChart>
  464. </div>
  465. </div>
  466. <div class="stat-card bg-green-50 p-4 rounded-lg h-100">
  467. <div class="text-green-500 text-lg font-medium">报警月统计</div>
  468. <EchartsTyp
  469. :flipData="flipDataMonthly"
  470. :waterImmersion="waterImmersionMonthly"
  471. :waterLevel="waterLevelMonthly"
  472. ></EchartsTyp>
  473. </div>
  474. <div class="stat-card bg-red-50 p-4 rounded-lg h-100">
  475. <div class="text-red-500 text-lg font-medium">报警日统计</div>
  476. <riEcharts
  477. :flipData="flipDataDay"
  478. :waterImmersion="waterImmersionDay"
  479. :waterLevel="waterLevelDay"
  480. :DagiveanalarmDate="DagiveanalarmDate"
  481. ></riEcharts>
  482. </div>
  483. </div>
  484. </el-card>
  485. </div>
  486. <!-- Table -->
  487. <el-table
  488. :data="deviceArr"
  489. border
  490. stripe
  491. style="width: 100%"
  492. v-loading="loading"
  493. class="mb-4"
  494. @selection-change="handleSelectionChange"
  495. >
  496. <el-table-column type="selection" width="55" align="center"/>
  497. <el-table-column type="index" label="序号" width="60" align="center"/>
  498. <el-table-column
  499. prop="deviceName"
  500. label="设备名称"
  501. min-width="150"
  502. show-overflow-tooltip
  503. />
  504. <el-table-column
  505. prop="deviceNumber"
  506. label="设备编号"
  507. min-width="150"
  508. show-overflow-tooltip
  509. />
  510. <el-table-column prop="model" label="型号" min-width="150" show-overflow-tooltip/>
  511. <el-table-column prop="type" label="类型" min-width="120" show-overflow-tooltip>
  512. <template #default="{ row }">
  513. {{ deviceType[row.type] }}
  514. </template>
  515. </el-table-column>
  516. <el-table-column
  517. prop="location"
  518. label="位置"
  519. min-width="150"
  520. show-overflow-tooltip
  521. />
  522. <el-table-column label="在线状态" width="120" align="center">
  523. <template #default="scope">
  524. <div class="flex items-center justify-center">
  525. <span
  526. v-if="scope.row.onlineStatus === 1"
  527. class="flex items-center text-green-500"
  528. >
  529. <Wifi class="w-4 h-4 mr-1"/>
  530. 在线
  531. </span>
  532. <span v-else class="flex items-center text-gray-500">
  533. <WifiOff class="w-4 h-4 mr-1"/>
  534. 离线
  535. </span>
  536. </div>
  537. </template>
  538. </el-table-column>
  539. <el-table-column label="告警状态" width="120" align="center">
  540. <template #default="scope">
  541. <el-tag
  542. :type="scope.row.alarmStatus === 0 ? 'success' : 'danger'"
  543. effect="dark"
  544. >
  545. <div class="flex items-center">
  546. <AlertTriangle v-if="scope.row.alarmStatus === 1" class="w-4 h-4 mr-1"/>
  547. {{ scope.row.alarmStatus === 0 ? "正常" : "告警" }}
  548. </div>
  549. </el-tag>
  550. </template>
  551. </el-table-column>
  552. <el-table-column
  553. prop="remarks"
  554. label="备注"
  555. min-width="150"
  556. show-overflow-tooltip
  557. />
  558. <el-table-column label="创建时间" min-width="180" show-overflow-tooltip>
  559. <template #default="scope">
  560. {{ formatDate(scope.row.createTime) }}
  561. </template>
  562. </el-table-column>
  563. <el-table-column label="更新时间" min-width="180" show-overflow-tooltip>
  564. <template #default="scope">
  565. {{ formatDate(scope.row.updateTime) }}
  566. </template>
  567. </el-table-column>
  568. <el-table-column label="操作" fixed="right" width="220" align="center">
  569. <template #default="scope">
  570. <el-button type="primary" link size="small" @click="handlePreview(scope.row.id)"
  571. >预览
  572. </el-button
  573. >
  574. <el-button
  575. type="primary"
  576. link
  577. size="small"
  578. @click="openEditDialog(scope.row.id)"
  579. >编辑
  580. </el-button
  581. >
  582. <el-button type="danger" link size="small" @click="handleDelete(scope.row.id)"
  583. >删除
  584. </el-button
  585. >
  586. </template>
  587. </el-table-column>
  588. </el-table>
  589. <!-- Pagination -->
  590. <div class="flex justify-end">
  591. <el-pagination
  592. v-model:current-page="currentPage"
  593. v-model:page-size="pageSize"
  594. :page-sizes="[10, 20, 50, 100]"
  595. layout="total, sizes, prev, pager, next, jumper"
  596. :total="total"
  597. @size-change="handleSizeChange"
  598. @current-change="handleCurrentChange"
  599. background
  600. />
  601. </div>
  602. <!-- 预览对话框 -->
  603. <el-dialog v-model="previewDialogVisible" title="设备详情" width="50%">
  604. <el-descriptions :column="2" border>
  605. <el-descriptions-item label="设备名称">{{
  606. currentDevice.deviceName
  607. }}
  608. </el-descriptions-item>
  609. <el-descriptions-item label="设备编号">{{
  610. currentDevice.deviceNumber
  611. }}
  612. </el-descriptions-item>
  613. <el-descriptions-item label="类型">{{
  614. deviceType[currentDevice.type]
  615. }}
  616. </el-descriptions-item>
  617. <el-descriptions-item label="位置">{{
  618. currentDevice.location
  619. }}
  620. </el-descriptions-item>
  621. <el-descriptions-item label="型号">{{
  622. currentDevice.model
  623. }}
  624. </el-descriptions-item>
  625. <el-descriptions-item label="在线状态">
  626. <span
  627. v-if="currentDevice.onlineStatus === 1"
  628. class="flex items-center text-green-500"
  629. >
  630. <Wifi class="w-4 h-4 mr-1"/>
  631. 在线
  632. </span>
  633. <span v-else class="flex items-center text-gray-500">
  634. <WifiOff class="w-4 h-4 mr-1"/>
  635. 离线
  636. </span>
  637. </el-descriptions-item>
  638. <el-descriptions-item label="告警状态">
  639. <el-tag
  640. :type="currentDevice.alarmStatus === 0 ? 'success' : 'danger'"
  641. effect="dark"
  642. >
  643. <div class="flex items-center">
  644. <AlertTriangle
  645. v-if="currentDevice.alarmStatus === 1"
  646. class="w-4 h-4 mr-1"
  647. />
  648. {{ currentDevice.alarmStatus === 0 ? "正常" : "告警" }}
  649. </div>
  650. </el-tag>
  651. </el-descriptions-item>
  652. <el-descriptions-item label="备注" :span="2">{{
  653. currentDevice.remarks
  654. }}
  655. </el-descriptions-item>
  656. <el-descriptions-item label="创建时间" :span="2"
  657. >{{ formatDate(currentDevice.createTime) }}
  658. </el-descriptions-item>
  659. <el-descriptions-item label="更新时间" :span="2"
  660. >{{ formatDate(currentDevice.updateTime) }}
  661. </el-descriptions-item>
  662. </el-descriptions>
  663. <template #footer>
  664. <span class="dialog-footer">
  665. <el-button @click="previewDialogVisible = false">关闭</el-button>
  666. </span>
  667. </template>
  668. </el-dialog>
  669. <!-- 编辑对话框 -->
  670. <el-dialog v-model="editDialogVisible" title="编辑设备" width="40%">
  671. <el-form :model="editForm" label-width="100px">
  672. <el-form-item label="设备名称">
  673. <el-input v-model="editForm.deviceName" placeholder="请输入设备名称"/>
  674. </el-form-item>
  675. <el-form-item label="位置">
  676. <el-input
  677. v-model="editForm.location"
  678. placeholder="请输入位置 例如(xxxxx-xxxxx)"
  679. />
  680. </el-form-item>
  681. <el-form-item label="备注">
  682. <el-input v-model="editForm.remarks" type="textarea" placeholder="请输入备注"/>
  683. </el-form-item>
  684. </el-form>
  685. <template #footer>
  686. <span class="dialog-footer">
  687. <el-button @click="editDialogVisible = false">取消</el-button>
  688. <el-button type="primary" @click="handleEdit">确认</el-button>
  689. </span>
  690. </template>
  691. </el-dialog>
  692. <!-- 新增对话框 -->
  693. <el-dialog v-model="addDialogVisible" title="新增设备" width="40%">
  694. <el-form
  695. ref="addFormRef"
  696. :model="addForm"
  697. :rules="addFormRules"
  698. label-width="100px"
  699. >
  700. <el-form-item label="设备名称" prop="deviceName">
  701. <el-input v-model="addForm.deviceName" placeholder="请输入设备名称"/>
  702. </el-form-item>
  703. <el-form-item label="设备编号" prop="deviceNumber">
  704. <el-input v-model="addForm.deviceNumber" placeholder="请输入设备编号"/>
  705. </el-form-item>
  706. <el-form-item label="型号" prop="model">
  707. <el-input v-model="addForm.model" placeholder="请输入型号"/>
  708. </el-form-item>
  709. <el-form-item label="类型" prop="model">
  710. <el-select v-model="addForm.type" placeholder="请输入设备型号">
  711. <el-option
  712. v-for="(item, index) in deviceType"
  713. :key="item.value"
  714. :label="item"
  715. :value="index"
  716. :disabled="index !== '1'"
  717. />
  718. </el-select>
  719. </el-form-item>
  720. <el-form-item label="位置">
  721. <el-input
  722. v-model="addForm.location"
  723. placeholder="请输入位置 例如(xxxxx-xxxxx)"
  724. />
  725. </el-form-item>
  726. <el-form-item label="备注">
  727. <el-input v-model="addForm.remarks" type="textarea" placeholder="请输入备注"/>
  728. </el-form-item>
  729. </el-form>
  730. <template #footer>
  731. <span class="dialog-footer">
  732. <el-button @click="addDialogVisible = false">取消</el-button>
  733. <el-button type="primary" @click="handleAdd">确认</el-button>
  734. </span>
  735. </template>
  736. </el-dialog>
  737. </div>
  738. </template>
  739. <style scoped>
  740. .device-table-container {
  741. background-color: #fff;
  742. border-radius: 8px;
  743. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  744. }
  745. </style>