PequipmentLed.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. <!-- 物联感知设备管理 -->
  2. <template>
  3. <div class="app-container">
  4. <el-form ref="queryRef" :model="queryParams" :inline="true" v-show="showSearch">
  5. <el-form-item label="设备编码" prop="equipmentCode">
  6. <el-input
  7. v-model="queryParams.equipmentCode"
  8. placeholder="请输入设备编码"
  9. clearable
  10. style="width: 220px"
  11. @keyup.enter="handleQuery"
  12. />
  13. </el-form-item>
  14. <el-form-item label="设备名称" prop="equipmentName">
  15. <el-input
  16. v-model="queryParams.equipmentName"
  17. placeholder="请输入设备名称"
  18. clearable
  19. style="width: 220px"
  20. @keyup.enter="handleQuery"
  21. />
  22. </el-form-item>
  23. <el-form-item label="设备型号" prop="equipmentModel">
  24. <el-input
  25. v-model="queryParams.equipmentModel"
  26. placeholder="请输入设备型号"
  27. clearable
  28. style="width: 220px"
  29. @keyup.enter="handleQuery"
  30. />
  31. </el-form-item>
  32. <el-form-item label="制造商" prop="manufacturer">
  33. <el-input
  34. v-model="queryParams.manufacturer"
  35. placeholder="请输入制造商"
  36. clearable
  37. style="width: 220px"
  38. @keyup.enter="handleQuery"
  39. />
  40. </el-form-item>
  41. <el-form-item>
  42. <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
  43. <el-button icon="Refresh" @click="resetQuery">重置</el-button>
  44. </el-form-item>
  45. </el-form>
  46. <el-row :gutter="10" class="mb8">
  47. <el-col :span="1.5">
  48. <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
  49. </el-col>
  50. <el-col :span="1.5">
  51. <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
  52. 修改
  53. </el-button>
  54. </el-col>
  55. <el-col :span="1.5">
  56. <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
  57. 删除
  58. </el-button>
  59. </el-col>
  60. <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
  61. </el-row>
  62. <el-table v-loading="loading" :data="equipmentList" @selection-change="handleSelectionChange">
  63. <el-table-column type="selection" width="55" align="center" />
  64. <el-table-column label="设备编码" align="center" prop="equipmentCode" min-width="140" />
  65. <el-table-column label="设备名称" align="center" prop="equipmentName" min-width="160" show-overflow-tooltip />
  66. <el-table-column label="设备型号" align="center" prop="equipmentModel" min-width="120" />
  67. <el-table-column label="设备类型" align="center" min-width="140">
  68. <template #default="scope">
  69. {{ typeNameMap[scope.row.equipmentTypeId] || scope.row.equipmentTypeId || "-" }}
  70. </template>
  71. </el-table-column>
  72. <el-table-column label="当前状态" align="center" width="110">
  73. <template #default="scope">
  74. <el-tag :type="getStatusTagType(getRowStatus(scope.row.equipmentId))">
  75. {{ getStatusText(getRowStatus(scope.row.equipmentId)) }}
  76. </el-tag>
  77. </template>
  78. </el-table-column>
  79. <el-table-column label="制造商" align="center" prop="manufacturer" min-width="140" show-overflow-tooltip />
  80. <el-table-column label="设备位置" align="center" prop="equipmentLocation" min-width="180" show-overflow-tooltip />
  81. <el-table-column label="维护人员" align="center" prop="maintainer" min-width="100" />
  82. <el-table-column label="操作" align="center" width="300" class-name="small-padding fixed-width">
  83. <template #default="scope">
  84. <el-button link type="primary" icon="View" @click="handleView(scope.row)">详情</el-button>
  85. <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
  86. <el-button link type="warning" icon="Tools" @click="openStatusDialog(scope.row)">状态维护</el-button>
  87. <el-button link type="success" icon="Aim" @click="openTestDialog(scope.row)">测试验证</el-button>
  88. <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
  89. </template>
  90. </el-table-column>
  91. </el-table>
  92. <pagination
  93. v-show="total > 0"
  94. :total="total"
  95. v-model:page="queryParams.pageNum"
  96. v-model:limit="queryParams.pageSize"
  97. @pagination="getList"
  98. />
  99. <el-dialog :title="title" v-model="open" width="860px" append-to-body>
  100. <el-form ref="equipmentRef" :model="form" :rules="rules" label-width="110px">
  101. <el-row :gutter="16">
  102. <el-col :span="12">
  103. <el-form-item label="设备编码" prop="equipmentCode">
  104. <el-input v-model="form.equipmentCode" placeholder="请输入设备编码" />
  105. </el-form-item>
  106. </el-col>
  107. <el-col :span="12">
  108. <el-form-item label="设备名称" prop="equipmentName">
  109. <el-input v-model="form.equipmentName" placeholder="请输入设备名称" />
  110. </el-form-item>
  111. </el-col>
  112. <el-col :span="12">
  113. <el-form-item label="设备型号" prop="equipmentModel">
  114. <el-input v-model="form.equipmentModel" placeholder="请输入设备型号" />
  115. </el-form-item>
  116. </el-col>
  117. <el-col :span="12">
  118. <el-form-item label="设备类型" prop="equipmentTypeId">
  119. <el-select v-model="form.equipmentTypeId" placeholder="请选择设备类型" style="width: 100%">
  120. <el-option
  121. v-for="item in equipmentTypeOptions"
  122. :key="item.typeId"
  123. :label="item.typeName"
  124. :value="item.typeId"
  125. />
  126. </el-select>
  127. </el-form-item>
  128. </el-col>
  129. <el-col :span="12">
  130. <el-form-item label="制造商" prop="manufacturer">
  131. <el-input v-model="form.manufacturer" placeholder="请输入制造商" />
  132. </el-form-item>
  133. </el-col>
  134. <el-col :span="12">
  135. <el-form-item label="生产日期" prop="productionDate">
  136. <el-date-picker
  137. v-model="form.productionDate"
  138. type="date"
  139. value-format="YYYY-MM-DD"
  140. placeholder="请选择生产日期"
  141. style="width: 100%"
  142. />
  143. </el-form-item>
  144. </el-col>
  145. <el-col :span="24">
  146. <el-form-item label="规格参数" prop="equipmentSpec">
  147. <el-input v-model="form.equipmentSpec" placeholder="请输入设备规格参数" />
  148. </el-form-item>
  149. </el-col>
  150. <el-col :span="12">
  151. <el-form-item label="资产价值(元)" prop="assetValue">
  152. <el-input-number v-model="form.assetValue" :precision="2" :step="100" style="width: 100%" />
  153. </el-form-item>
  154. </el-col>
  155. <el-col :span="12">
  156. <el-form-item label="使用年限(年)" prop="useLife">
  157. <el-input-number v-model="form.useLife" :precision="0" :step="1" style="width: 100%" />
  158. </el-form-item>
  159. </el-col>
  160. <el-col :span="24">
  161. <el-form-item label="设备位置" prop="equipmentLocation">
  162. <el-input v-model="form.equipmentLocation" placeholder="请输入设备位置" />
  163. </el-form-item>
  164. </el-col>
  165. <el-col :span="12">
  166. <el-form-item label="经度" prop="longitude">
  167. <el-input-number v-model="form.longitude" :precision="6" :step="0.000001" style="width: 100%" />
  168. </el-form-item>
  169. </el-col>
  170. <el-col :span="12">
  171. <el-form-item label="纬度" prop="latitude">
  172. <el-input-number v-model="form.latitude" :precision="6" :step="0.000001" style="width: 100%" />
  173. </el-form-item>
  174. </el-col>
  175. <el-col :span="12">
  176. <el-form-item label="安装时间" prop="installTime">
  177. <el-date-picker
  178. v-model="form.installTime"
  179. type="datetime"
  180. value-format="YYYY-MM-DD HH:mm:ss"
  181. placeholder="请选择安装时间"
  182. style="width: 100%"
  183. />
  184. </el-form-item>
  185. </el-col>
  186. <el-col :span="12">
  187. <el-form-item label="维护人员" prop="maintainer">
  188. <el-input v-model="form.maintainer" placeholder="请输入维护人员" />
  189. </el-form-item>
  190. </el-col>
  191. <el-col :span="12">
  192. <el-form-item label="联系电话" prop="maintainerPhone">
  193. <el-input v-model="form.maintainerPhone" placeholder="请输入联系电话" />
  194. </el-form-item>
  195. </el-col>
  196. <el-col :span="24">
  197. <el-form-item label="备注" prop="remark">
  198. <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
  199. </el-form-item>
  200. </el-col>
  201. </el-row>
  202. </el-form>
  203. <template #footer>
  204. <div class="dialog-footer">
  205. <el-button type="primary" @click="submitForm">确 定</el-button>
  206. <el-button @click="cancel">取 消</el-button>
  207. </div>
  208. </template>
  209. </el-dialog>
  210. <el-dialog title="设备详情" v-model="detailOpen" width="980px" append-to-body>
  211. <el-descriptions :column="2" border v-if="detailForm.equipmentInfo">
  212. <el-descriptions-item label="设备编码">{{ detailForm.equipmentInfo.equipmentCode || "-" }}</el-descriptions-item>
  213. <el-descriptions-item label="设备名称">{{ detailForm.equipmentInfo.equipmentName || "-" }}</el-descriptions-item>
  214. <el-descriptions-item label="设备型号">{{ detailForm.equipmentInfo.equipmentModel || "-" }}</el-descriptions-item>
  215. <el-descriptions-item label="设备类型">{{ detailForm.typeInfo?.typeName || "-" }}</el-descriptions-item>
  216. <el-descriptions-item label="制造商">{{ detailForm.equipmentInfo.manufacturer || "-" }}</el-descriptions-item>
  217. <el-descriptions-item label="当前状态">{{ getStatusText(detailForm.statusInfo?.currentStatus) }}</el-descriptions-item>
  218. <el-descriptions-item label="设备位置" :span="2">{{ detailForm.equipmentInfo.equipmentLocation || "-" }}</el-descriptions-item>
  219. <el-descriptions-item label="规格参数" :span="2">{{ detailForm.equipmentInfo.equipmentSpec || "-" }}</el-descriptions-item>
  220. <el-descriptions-item label="维护人员">{{ detailForm.equipmentInfo.maintainer || "-" }}</el-descriptions-item>
  221. <el-descriptions-item label="联系电话">{{ detailForm.equipmentInfo.maintainerPhone || "-" }}</el-descriptions-item>
  222. <el-descriptions-item label="安装时间">{{ detailForm.equipmentInfo.installTime || "-" }}</el-descriptions-item>
  223. <el-descriptions-item label="生产日期">{{ detailForm.equipmentInfo.productionDate || "-" }}</el-descriptions-item>
  224. <el-descriptions-item label="备注" :span="2">{{ detailForm.equipmentInfo.remark || "-" }}</el-descriptions-item>
  225. </el-descriptions>
  226. <el-divider content-position="left">关联监测点</el-divider>
  227. <el-table :data="detailForm.pointRelList || []" border>
  228. <el-table-column label="监测点ID" prop="pointId" min-width="200" show-overflow-tooltip />
  229. <el-table-column label="设备ID" prop="equipmentId" min-width="200" show-overflow-tooltip />
  230. </el-table>
  231. <el-divider content-position="left">测试记录</el-divider>
  232. <el-table :data="detailForm.testList || []" border>
  233. <el-table-column label="测试时间" prop="testTime" min-width="170" />
  234. <el-table-column label="测试类型" prop="testType" min-width="120" />
  235. <el-table-column label="测试结果" prop="testResult" width="100" />
  236. <el-table-column label="测试人员" prop="testUser" width="120" />
  237. <el-table-column label="测试详情" prop="testDetail" min-width="220" show-overflow-tooltip />
  238. </el-table>
  239. </el-dialog>
  240. <el-dialog title="设备状态维护" v-model="statusOpen" width="420px" append-to-body>
  241. <el-form label-width="90px">
  242. <el-form-item label="设备名称">
  243. <span>{{ currentRow.equipmentName || "-" }}</span>
  244. </el-form-item>
  245. <el-form-item label="当前状态">
  246. <el-select v-model="statusForm.currentStatus" style="width: 100%">
  247. <el-option
  248. v-for="item in equipmentStatusOptions"
  249. :key="item.value"
  250. :label="item.label"
  251. :value="item.value"
  252. />
  253. </el-select>
  254. </el-form-item>
  255. </el-form>
  256. <template #footer>
  257. <div class="dialog-footer">
  258. <el-button type="primary" @click="submitStatus">确 定</el-button>
  259. <el-button @click="statusOpen = false">取 消</el-button>
  260. </div>
  261. </template>
  262. </el-dialog>
  263. <el-dialog title="设备测试验证" v-model="testOpen" width="520px" append-to-body>
  264. <el-form ref="testRef" :model="testForm" label-width="90px">
  265. <el-form-item label="设备名称">
  266. <span>{{ currentRow.equipmentName || "-" }}</span>
  267. </el-form-item>
  268. <el-form-item label="测试类型">
  269. <el-input v-model="testForm.testType" placeholder="例如:通信测试" />
  270. </el-form-item>
  271. <el-form-item label="测试人员">
  272. <el-input v-model="testForm.testUser" placeholder="请输入测试人员" />
  273. </el-form-item>
  274. <el-form-item label="测试详情">
  275. <el-input v-model="testForm.testDetail" type="textarea" :rows="4" placeholder="请输入测试详情" />
  276. </el-form-item>
  277. </el-form>
  278. <template #footer>
  279. <div class="dialog-footer">
  280. <el-button type="primary" @click="submitTest">确 定</el-button>
  281. <el-button @click="testOpen = false">取 消</el-button>
  282. </div>
  283. </template>
  284. </el-dialog>
  285. </div>
  286. </template>
  287. <script setup>
  288. import { computed, getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
  289. import {
  290. addEquipment,
  291. delEquipment,
  292. getEquipment,
  293. getEquipmentDetail,
  294. listEquipment,
  295. listEquipmentStatusAll,
  296. listEquipmentTypeAll,
  297. testEquipment,
  298. updateEquipment,
  299. updateEquipmentStatus
  300. } from "@/api/pipeNetwork/pdeviceInform";
  301. const { proxy } = getCurrentInstance();
  302. const equipmentList = ref([]);
  303. const equipmentTypeOptions = ref([]);
  304. const equipmentStatusList = ref([]);
  305. const loading = ref(false);
  306. const open = ref(false);
  307. const detailOpen = ref(false);
  308. const statusOpen = ref(false);
  309. const testOpen = ref(false);
  310. const showSearch = ref(true);
  311. const ids = ref([]);
  312. const single = ref(true);
  313. const multiple = ref(true);
  314. const total = ref(0);
  315. const title = ref("");
  316. const currentRow = ref({});
  317. const equipmentStatusOptions = [
  318. { label: "在用", value: 1 },
  319. { label: "闲置", value: 2 },
  320. { label: "维修", value: 3 },
  321. { label: "报废", value: 4 },
  322. { label: "待入库", value: 5 }
  323. ];
  324. const typeNameMap = computed(() => {
  325. return equipmentTypeOptions.value.reduce((acc, item) => {
  326. acc[item.typeId] = item.typeName;
  327. return acc;
  328. }, {});
  329. });
  330. const statusMap = computed(() => {
  331. return equipmentStatusList.value.reduce((acc, item) => {
  332. acc[item.equipmentId] = item;
  333. return acc;
  334. }, {});
  335. });
  336. const data = reactive({
  337. queryParams: {
  338. pageNum: 1,
  339. pageSize: 10,
  340. equipmentCode: undefined,
  341. equipmentName: undefined,
  342. equipmentModel: undefined,
  343. manufacturer: undefined
  344. },
  345. form: {},
  346. detailForm: {},
  347. statusForm: {
  348. currentStatus: 1
  349. },
  350. testForm: {
  351. testType: undefined,
  352. testDetail: undefined,
  353. testUser: undefined
  354. },
  355. rules: {
  356. equipmentCode: [{ required: true, message: "设备编码不能为空", trigger: "blur" }],
  357. equipmentName: [{ required: true, message: "设备名称不能为空", trigger: "blur" }],
  358. equipmentTypeId: [{ required: true, message: "设备类型不能为空", trigger: "change" }]
  359. }
  360. });
  361. const { queryParams, form, detailForm, statusForm, testForm, rules } = toRefs(data);
  362. function createEmptyForm() {
  363. return {
  364. equipmentId: undefined,
  365. equipmentCode: undefined,
  366. equipmentName: undefined,
  367. equipmentModel: undefined,
  368. equipmentSpec: undefined,
  369. manufacturer: undefined,
  370. productionDate: undefined,
  371. equipmentTypeId: undefined,
  372. assetValue: undefined,
  373. useLife: undefined,
  374. longitude: undefined,
  375. latitude: undefined,
  376. equipmentLocation: undefined,
  377. installTime: undefined,
  378. maintainer: undefined,
  379. maintainerPhone: undefined,
  380. remark: undefined
  381. };
  382. }
  383. function getRowStatus(equipmentId) {
  384. return statusMap.value[equipmentId]?.currentStatus;
  385. }
  386. function getStatusText(status) {
  387. const found = equipmentStatusOptions.find((item) => item.value === status);
  388. return found?.label || "未维护";
  389. }
  390. function getStatusTagType(status) {
  391. const map = {
  392. 1: "success",
  393. 2: "info",
  394. 3: "warning",
  395. 4: "danger",
  396. 5: ""
  397. };
  398. return map[status] || "";
  399. }
  400. function getList() {
  401. loading.value = true;
  402. listEquipment(queryParams.value)
  403. .then((response) => {
  404. equipmentList.value = response.records || [];
  405. total.value = response.total || 0;
  406. })
  407. .finally(() => {
  408. loading.value = false;
  409. });
  410. }
  411. function loadAssistData() {
  412. return Promise.all([listEquipmentTypeAll(), listEquipmentStatusAll()]).then(([typeRes, statusRes]) => {
  413. equipmentTypeOptions.value = typeRes.data || [];
  414. equipmentStatusList.value = statusRes.data || [];
  415. });
  416. }
  417. function reset() {
  418. form.value = createEmptyForm();
  419. proxy.resetForm("equipmentRef");
  420. }
  421. function handleQuery() {
  422. queryParams.value.pageNum = 1;
  423. getList();
  424. }
  425. function resetQuery() {
  426. proxy.resetForm("queryRef");
  427. handleQuery();
  428. }
  429. function handleSelectionChange(selection) {
  430. ids.value = selection.map((item) => item.equipmentId);
  431. single.value = selection.length !== 1;
  432. multiple.value = !selection.length;
  433. }
  434. function handleAdd() {
  435. reset();
  436. open.value = true;
  437. title.value = "新增物联感知设备";
  438. }
  439. function handleUpdate(row) {
  440. reset();
  441. const equipmentId = row?.equipmentId || ids.value[0];
  442. if (!equipmentId) {
  443. return;
  444. }
  445. getEquipment(equipmentId).then((response) => {
  446. form.value = { ...createEmptyForm(), ...(response.data || {}) };
  447. open.value = true;
  448. title.value = "修改物联感知设备";
  449. });
  450. }
  451. function handleView(row) {
  452. getEquipmentDetail(row.equipmentId).then((response) => {
  453. detailForm.value = response.data || {};
  454. detailOpen.value = true;
  455. });
  456. }
  457. function cancel() {
  458. open.value = false;
  459. reset();
  460. }
  461. function submitForm() {
  462. proxy.$refs.equipmentRef.validate((valid) => {
  463. if (!valid) {
  464. return;
  465. }
  466. const request = form.value.equipmentId ? updateEquipment(form.value) : addEquipment(form.value);
  467. request.then(() => {
  468. proxy.$modal.msgSuccess(form.value.equipmentId ? "修改成功" : "新增成功");
  469. open.value = false;
  470. Promise.all([getList(), loadAssistData()]);
  471. });
  472. });
  473. }
  474. function handleDelete(row) {
  475. const deleteIds = row?.equipmentId ? [row.equipmentId] : ids.value;
  476. if (!deleteIds.length) {
  477. return;
  478. }
  479. proxy.$modal
  480. .confirm(`是否确认删除选中的 ${deleteIds.length} 台设备?`)
  481. .then(() => Promise.all(deleteIds.map((id) => delEquipment(id))))
  482. .then(() => {
  483. proxy.$modal.msgSuccess("删除成功");
  484. Promise.all([getList(), loadAssistData()]);
  485. });
  486. }
  487. function openStatusDialog(row) {
  488. currentRow.value = row;
  489. statusForm.value.currentStatus = getRowStatus(row.equipmentId) || 1;
  490. statusOpen.value = true;
  491. }
  492. function submitStatus() {
  493. updateEquipmentStatus(currentRow.value.equipmentId, statusForm.value.currentStatus).then(() => {
  494. proxy.$modal.msgSuccess("状态维护成功");
  495. statusOpen.value = false;
  496. loadAssistData();
  497. });
  498. }
  499. function openTestDialog(row) {
  500. currentRow.value = row;
  501. testForm.value = {
  502. testType: "通信测试",
  503. testDetail: undefined,
  504. testUser: undefined
  505. };
  506. testOpen.value = true;
  507. }
  508. function submitTest() {
  509. testEquipment(currentRow.value.equipmentId, testForm.value).then(() => {
  510. proxy.$modal.msgSuccess("测试记录已提交");
  511. testOpen.value = false;
  512. if (detailOpen.value && detailForm.value?.equipmentInfo?.equipmentId === currentRow.value.equipmentId) {
  513. handleView(currentRow.value);
  514. }
  515. });
  516. }
  517. onMounted(() => {
  518. reset();
  519. Promise.all([getList(), loadAssistData()]);
  520. });
  521. </script>