From 2d3530a7c11557a40807ad7c0b9e302ce6ce3a9f Mon Sep 17 00:00:00 2001
From: hsy <1029150275@qq.com>
Date: 星期五, 28 八月 2026 10:16:32 +0800
Subject: [PATCH] feat: 综合业务模块页面重构与交互完善

---
 src/views/equipmentManagement/ledger/index.vue |  228 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 221 insertions(+), 7 deletions(-)

diff --git a/src/views/equipmentManagement/ledger/index.vue b/src/views/equipmentManagement/ledger/index.vue
index af10532..fbc9869 100644
--- a/src/views/equipmentManagement/ledger/index.vue
+++ b/src/views/equipmentManagement/ledger/index.vue
@@ -1,6 +1,15 @@
 <template>
   <div class="app-container">
     <el-form :model="filters" :inline="true">
+      <el-form-item label="璁惧缂栧彿">
+        <el-input
+          v-model="filters.uniqueCode"
+          style="width: 200px"
+          placeholder="璇疯緭鍏ヨ澶囩紪鍙�"
+          clearable
+          @change="getTableData"
+        />
+      </el-form-item>
       <el-form-item label="璁惧鍚嶇О">
         <el-input
           v-model="filters.deviceName"
@@ -113,6 +122,7 @@
     <!-- 璇︽儏瀵硅瘽妗� -->
     <el-dialog v-model="detailDialogVisible" title="璁惧鍙拌处璇︽儏" width="60%" draggable>
       <el-descriptions :column="2" border>
+        <el-descriptions-item label="璁惧缂栧彿">{{ detailData.uniqueCode }}</el-descriptions-item>
         <el-descriptions-item label="璁惧鍚嶇О">{{ detailData.deviceName }}</el-descriptions-item>
         <el-descriptions-item label="瑙勬牸鍨嬪彿">{{ detailData.deviceModel }}</el-descriptions-item>
         <el-descriptions-item label="璁惧鍝佺墝">{{ detailData.deviceBrand }}</el-descriptions-item>
@@ -148,13 +158,88 @@
         <el-button @click="detailDialogVisible = false">鍏抽棴</el-button>
       </template>
     </el-dialog>
+
+    <!-- 鐘舵�佸彉鏇村璇濇 -->
+    <el-dialog v-model="statusDialog.visible" title="璁惧鐘舵�佸彉鏇寸敵璇�" width="500px" draggable>
+      <el-form label-width="100px">
+        <el-form-item label="褰撳墠鐘舵��">
+          <el-tag :type="statusDialog.row?.status == 1 ? 'success' : 'danger'">
+            {{ statusDialog.row?.status == 1 ? '鍚敤' : '鍋滅敤' }}
+          </el-tag>
+        </el-form-item>
+        <el-form-item label="鐩爣鐘舵��" required>
+          <el-radio-group v-model="statusDialog.targetStatus">
+            <el-radio :label="1">鍚敤</el-radio>
+            <el-radio :label="0">鍋滅敤</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="鍙樻洿鍘熷洜" required>
+          <el-input type="textarea" :rows="3" v-model="statusDialog.reason" placeholder="璇疯緭鍏ョ姸鎬佸彉鏇村師鍥�" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="statusDialog.visible = false">鍙栨秷</el-button>
+        <el-button type="primary" :loading="statusDialog.loading" @click="submitStatusChange">鎻愪氦瀹℃壒</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 鐘舵�佸彉鏇磋褰曞璇濇 -->
+    <el-dialog v-model="recordDialog.visible" title="璁惧鐘舵�佸彉鏇磋褰�" width="800px" draggable>
+      <el-table v-loading="recordDialog.loading" :data="recordDialog.list" border>
+        <el-table-column label="鍙樻洿鏃堕棿" prop="createTime" width="160" />
+        <el-table-column label="鍘熺姸鎬�" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.originalStatus == 1 ? 'success' : 'danger'">
+              {{ scope.row.originalStatus == 1 ? '鍚敤' : '鍋滅敤' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鐩爣鐘舵��" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.targetStatus == 1 ? 'success' : 'danger'">
+              {{ scope.row.targetStatus == 1 ? '鍚敤' : '鍋滅敤' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鍙樻洿鍘熷洜" prop="reason" show-overflow-tooltip />
+        <el-table-column label="鐢宠浜�" prop="createUserName" width="100" />
+        <el-table-column label="瀹℃壒鐘舵��" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.approvalStatus === 'PENDING'" type="warning">瀹℃壒涓�</el-tag>
+            <el-tag v-else-if="scope.row.approvalStatus === 'APPROVED'" type="success">宸查�氳繃</el-tag>
+            <el-tag v-else-if="scope.row.approvalStatus === 'REJECTED'" type="danger">宸查┏鍥�</el-tag>
+            <span v-else>{{ scope.row.approvalStatus }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="椹冲洖鍘熷洜" prop="rejectReason" show-overflow-tooltip>
+          <template #default="scope">
+            <span v-if="scope.row.approvalStatus === 'REJECTED'">{{ scope.row.rejectReason || '--' }}</span>
+            <span v-else>--</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div style="display: flex; justify-content: flex-end; margin-top: 15px;">
+        <el-pagination
+          v-model:current-page="recordDialog.queryParams.pageNum"
+          v-model:page-size="recordDialog.queryParams.pageSize"
+          :total="recordDialog.total"
+          layout="total, prev, pager, next"
+          @current-change="getRecordList"
+        />
+      </div>
+      <template #footer>
+        <el-button @click="recordDialog.visible = false">鍏抽棴</el-button>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
 import { usePaginationApi } from "@/hooks/usePaginationApi";
-// import { Search } from "@element-plus/icons-vue";
 import { getLedgerPage, delLedger, getLedgerById } from "@/api/equipmentManagement/ledger";
+import { listStatusChangeRecord } from "@/api/device/statusChangeRecord";
+import { saveApprovalInstance } from "@/api/officeProcessAutomation/approvalInstance";
+import { listApprovalTemplate, getApprovalTemplateDetail, TEMPLATE_TYPE_CUSTOM } from "@/api/officeProcessAutomation/approvalTemplate";
 import { onMounted, getCurrentInstance, ref, reactive } from "vue";
 import Modal from "./Modal.vue";
 import { ElMessageBox, ElMessage } from "element-plus";
@@ -204,6 +289,7 @@
 } = usePaginationApi(
   getLedgerPage,
   {
+    uniqueCode: undefined,
     deviceName: undefined,
     deviceModel: undefined,
     supplierName: undefined,
@@ -211,6 +297,10 @@
     entryDateEnd: undefined,
   },
   [
+    {
+      label: "璁惧缂栧彿",
+      prop: "uniqueCode",
+    },
     {
       label: "璁惧鍚嶇О",
       prop: "deviceName",
@@ -240,18 +330,34 @@
       prop: "number",
     },
     {
+      label: "璁惧鐘舵��",
+      prop: "status",
+      width: 100,
+      dataType: "tag",
+      formatData: (v) => v == 1 ? '鍚敤' : '鍋滅敤',
+      formatType: (v) => v == 1 ? 'success' : 'danger',
+    },
+    {
+      label: "鍚敤鏃ユ湡",
+      prop: "activationDate",
+      width: 120,
+      formatData: (v) => {
+        if (!v) return '';
+        if (v.includes(' ')) return v.split(' ')[0];
+        return v;
+      },
+    },
+    {
       label: "褰曞叆浜�",
       prop: "createUser",
     },
     {
-      label: "褰曞叆鏃ユ湡",
-      prop: "createTime",
+      label: "寤烘。鏃ユ湡",
+      prop: "filingDate",
+      width: 120,
       formatData: (v) => {
         if (!v) return '';
-        // 濡傛灉鍖呭惈鏃跺垎绉掞紝鍙彇鏃ユ湡閮ㄥ垎
-        if (v.includes(' ')) {
-          return v.split(' ')[0];
-        }
+        if (v.includes(' ')) return v.split(' ')[0];
         return v;
       },
     },
@@ -266,6 +372,18 @@
           name: "璇︽儏",
           clickFun: (row) => {
             handleDetail(row);
+          },
+        },
+        {
+          name: "鐘舵�佸彉鏇�",
+          clickFun: (row) => {
+            openStatusChange(row);
+          },
+        },
+        {
+          name: "鍙樻洿璁板綍",
+          clickFun: (row) => {
+            openRecordDialog(row);
           },
         },
 				{
@@ -303,6 +421,102 @@
     detailDialogVisible.value = true;
   }
 };
+
+const statusDialog = reactive({ visible: false, row: null, targetStatus: 1, reason: '', loading: false });
+
+const openStatusChange = (row) => {
+  statusDialog.row = row;
+  statusDialog.targetStatus = row.status == 1 ? 0 : 1; 
+  statusDialog.reason = '';
+  statusDialog.visible = true;
+};
+
+const submitStatusChange = async () => {
+  if (!statusDialog.reason.trim()) {
+    ElMessage.error("璇峰~鍐欑姸鎬佸彉鏇村師鍥�");
+    return;
+  }
+  if (statusDialog.targetStatus === statusDialog.row.status) {
+    ElMessage.warning("鐩爣鐘舵�佷笌褰撳墠鐘舵�佷竴鑷�");
+    return;
+  }
+  statusDialog.loading = true;
+  try {
+    const listRes = await listApprovalTemplate(TEMPLATE_TYPE_CUSTOM);
+    const templates = listRes.data?.records || listRes.data || [];
+    const tpl = templates.find(t => t.businessType === 19 && (t.enabled === 1 || t.enabled === true));
+    if (!tpl) {
+      ElMessage.error("鏈壘鍒板惎鐢ㄧ殑璁惧鐘舵�佸彉鏇村鎵规ā鏉�");
+      return;
+    }
+    const detailRes = await getApprovalTemplateDetail(tpl.id);
+    const detail = detailRes.data;
+    
+    const payload = {
+      templateId: detail.id,
+      templateName: detail.templateName,
+      businessType: 19,
+      templateSnapshot: JSON.stringify(detail),
+      title: `璁惧鐘舵�佸彉鏇村鎵� - ${statusDialog.row.deviceName}`,
+      reason: statusDialog.reason,
+      businessId: statusDialog.row.id,
+      formConfig: JSON.stringify({
+        targetStatus: statusDialog.targetStatus,
+        targetStatusName: statusDialog.targetStatus == 1 ? '鍚敤' : '鍋滅敤',
+        deviceId: statusDialog.row.id,
+        deviceName: statusDialog.row.deviceName,
+        reason: statusDialog.reason
+      }),
+      flowNodes: detail.flowNodes || []
+    };
+    
+    const res = await saveApprovalInstance(payload);
+    if (res.code === 200) {
+      ElMessage.success("宸插彂璧风姸鎬佸彉鏇村鎵�");
+      statusDialog.visible = false;
+      getTableData();
+    }
+  } catch (error) {
+    console.error(error);
+  } finally {
+    statusDialog.loading = false;
+  }
+};
+
+const recordDialog = reactive({
+  visible: false,
+  loading: false,
+  list: [],
+  total: 0,
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    deviceId: null
+  }
+});
+
+const openRecordDialog = (row) => {
+  recordDialog.queryParams.deviceId = row.id;
+  recordDialog.queryParams.pageNum = 1;
+  recordDialog.visible = true;
+  getRecordList();
+};
+
+const getRecordList = async () => {
+  recordDialog.loading = true;
+  try {
+    const res = await listStatusChangeRecord(recordDialog.queryParams);
+    if (res.code === 200) {
+      recordDialog.list = res.data.records;
+      recordDialog.total = res.data.total;
+    }
+  } catch (error) {
+    console.error(error);
+  } finally {
+    recordDialog.loading = false;
+  }
+};
+
 const changePage = ({ page, limit }) => {
   pagination.currentPage = page;
 	pagination.pageSize = limit;

--
Gitblit v1.9.3