From 11b40328f7aa7599f89189d0ebcbbdf8773f9e1b Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 21 四月 2026 10:41:41 +0800
Subject: [PATCH] 新疆马铃薯 1.巡检记录添加巡检状态和巡检结果展示字段

---
 src/views/equipmentManagement/ledger/index.vue |  635 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 498 insertions(+), 137 deletions(-)

diff --git a/src/views/equipmentManagement/ledger/index.vue b/src/views/equipmentManagement/ledger/index.vue
index 5555182..8e3fae5 100644
--- a/src/views/equipmentManagement/ledger/index.vue
+++ b/src/views/equipmentManagement/ledger/index.vue
@@ -1,85 +1,191 @@
 <template>
-  <div class="app-container">
-    <el-form :model="filters" :inline="true">
-      <el-form-item label="璁惧鍚嶇О">
+  <div class="app-container ledger-view">
+    <div class="left-panel">
+      <div class="tree-toolbar">
         <el-input
-          v-model="filters.deviceName"
-          style="width: 240px"
-          placeholder="璇疯緭鍏ヨ澶囧悕绉�"
+          v-model="treeKeyword"
+          style="width: calc(100% - 102px)"
+          placeholder="璇疯緭鍏ュ尯鍩熷悕绉�"
           clearable
-          @change="getTableData"
+          prefix-icon="Search"
+          @input="filterTree"
+          @clear="filterTree"
         />
-      </el-form-item>
-      <el-form-item label="瑙勬牸鍨嬪彿">
-        <el-input
+        <el-button type="primary" @click="openAreaDialog('addRoot')">鏂板鍖哄煙</el-button>
+      </div>
+      <div class="tree-actions">
+        <el-button link type="primary" @click="resetTreeSelection">鍏ㄩ儴鍖哄煙</el-button>
+      </div>
+      <el-tree
+        ref="treeRef"
+        v-loading="treeLoading"
+        :data="treeData"
+        :props="treeProps"
+        node-key="id"
+        highlight-current
+        default-expand-all
+        :expand-on-click-node="false"
+        :filter-node-method="filterTreeNode"
+        class="ledger-tree"
+        @node-click="handleTreeNodeClick"
+      >
+        <template #default="{ node, data }">
+          <div class="tree-node">
+            <span class="tree-node-content">
+              <el-icon class="tree-node-icon">
+                <component
+                  :is="
+                    data.children && data.children.length > 0
+                      ? node.expanded
+                        ? 'FolderOpened'
+                        : 'Folder'
+                      : 'Tickets'
+                  "
+                />
+              </el-icon>
+              <span class="tree-node-label">{{ data.areaName }}</span>
+            </span>
+            <div class="tree-node-actions">
+              <el-button link type="primary" @click.stop="openAreaDialog('edit', data)">缂栬緫</el-button>
+              <el-button link type="primary" @click.stop="openAreaDialog('addChild', data)">鏂板</el-button>
+              <el-button
+                v-if="!hasChildren(data)"
+                link
+                type="danger"
+                @click.stop="handleDeleteArea(data)"
+              >
+                鍒犻櫎
+              </el-button>
+            </div>
+          </div>
+        </template>
+      </el-tree>
+    </div>
+
+    <div class="right-panel">
+      <el-form :model="filters" :inline="true">
+        <el-form-item label="璁惧鍚嶇О">
+          <el-input
+            v-model="filters.deviceName"
+            style="width: 200px"
+            placeholder="璇疯緭鍏ヨ澶囧悕绉�"
+            clearable
+            @change="getTableData"
+          />
+        </el-form-item>
+        <el-form-item label="瑙勬牸鍨嬪彿">
+          <el-input
             v-model="filters.deviceModel"
-            style="width: 240px"
+            style="width: 200px"
             placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
             clearable
             @change="getTableData"
-        />
-      </el-form-item>
-      <el-form-item label="渚涘簲鍟�">
-        <el-input
+          />
+        </el-form-item>
+        <el-form-item label="渚涘簲鍟�">
+          <el-input
             v-model="filters.supplierName"
-            style="width: 240px"
+            style="width: 200px"
             placeholder="璇疯緭鍏ヤ緵搴斿晢"
             clearable
             @change="getTableData"
-        />
-      </el-form-item>
-      <el-form-item label="褰曞叆鏃ユ湡:">
-        <el-date-picker v-model="filters.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
-                        placeholder="璇烽�夋嫨" clearable @change="changeDaterange" />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" @click="getTableData">鎼滅储</el-button>
-        <el-button @click="resetFilters">閲嶇疆</el-button>
-      </el-form-item>
-    </el-form>
-    <div class="table_list">
-      <div class="actions">
-        <div></div>
-        <div>
-          <el-button type="primary" @click="add" icon="Plus"> 鏂板 </el-button>
-          <el-button type="info" @click="handleImport" icon="Upload">瀵煎叆</el-button>
-          <el-button @click="handleOut" icon="download">瀵煎嚭</el-button>
-          <el-button
-            type="danger"
-            icon="Delete"
-            :disabled="multipleList.length <= 0"
-            @click="deleteRow(multipleList.map((item) => item.id))"
-          >
-            鎵归噺鍒犻櫎
-          </el-button>
+          />
+        </el-form-item>
+        <el-form-item label="褰曞叆鏃ユ湡">
+          <el-date-picker
+            v-model="filters.entryDate"
+            value-format="YYYY-MM-DD"
+            format="YYYY-MM-DD"
+            type="daterange"
+            placeholder="璇烽�夋嫨"
+            clearable
+            @change="changeDaterange"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+          <el-button @click="handleResetFilters">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+
+      <div class="table_list">
+        <div class="actions">
+          <div class="actions-tip">
+            <span v-if="selectedAreaName">褰撳墠鍖哄煙锛歿{ selectedAreaName }}</span>
+          </div>
+          <div>
+            <el-button type="primary" icon="Plus" @click="add">鏂板</el-button>
+            <el-button type="info" icon="Upload" @click="handleImport">瀵煎叆</el-button>
+            <el-button icon="download" @click="handleOut">瀵煎嚭</el-button>
+            <el-button
+              type="danger"
+              icon="Delete"
+              :disabled="multipleList.length <= 0"
+              @click="deleteRow(multipleList.map((item) => item.id))"
+            >
+              鎵归噺鍒犻櫎
+            </el-button>
+          </div>
         </div>
+        <PIMTable
+          rowKey="id"
+          isSelection
+          :column="columns"
+          :tableData="dataList"
+          :page="{
+            current: pagination.currentPage,
+            size: pagination.pageSize,
+            total: pagination.total,
+          }"
+          @selection-change="handleSelectionChange"
+          @pagination="changePage"
+        />
       </div>
-      <PIMTable
-        rowKey="id"
-        isSelection
-        :column="columns"
-        :tableData="dataList"
-        :page="{
-          current: pagination.currentPage,
-          size: pagination.pageSize,
-          total: pagination.total,
-        }"
-        @selection-change="handleSelectionChange"
-        @pagination="changePage"
-      >
-      </PIMTable>
     </div>
-    <Modal ref="modalRef" @success="getTableData"></Modal>
+
+    <Modal ref="modalRef" @success="getTableData" />
+
+    <el-dialog
+      v-model="areaDialogVisible"
+      :title="areaDialogTitle"
+      width="480px"
+      @close="closeAreaDialog"
+    >
+      <el-form ref="areaFormRef" :model="areaForm" :rules="areaRules" label-width="88px">
+        <el-form-item label="鍖哄煙鍚嶇О" prop="areaName">
+          <el-input v-model="areaForm.areaName" placeholder="璇疯緭鍏ュ尯鍩熷悕绉�" />
+        </el-form-item>
+        <el-form-item label="鎺掑簭" prop="sort">
+          <el-input-number v-model="areaForm.sort" :min="0" :step="1" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input
+            v-model="areaForm.remark"
+            type="textarea"
+            :rows="4"
+            maxlength="200"
+            show-word-limit
+            placeholder="璇疯緭鍏ュ娉�"
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitAreaForm">纭畾</el-button>
+          <el-button @click="closeAreaDialog">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
     <el-dialog v-model="qrDialogVisible" title="浜岀淮鐮�" width="300px" draggable>
-      <div style="text-align:center;">
-        <img :src="qrCodeUrl" alt="浜岀淮鐮�" style="width:200px;height:200px;" />
-        <div style="margin:10px 0;">
+      <div class="qr-dialog">
+        <img :src="qrCodeUrl" alt="浜岀淮鐮�" class="qr-image" />
+        <div class="qr-footer">
           <el-button type="primary" @click="downloadQRCode">涓嬭浇浜岀淮鐮佸浘鐗�</el-button>
         </div>
       </div>
     </el-dialog>
-    
-    <!-- 瀵煎叆瀵硅瘽妗� -->
+
     <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
       <el-upload
         ref="uploadRef"
@@ -97,15 +203,22 @@
         <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
         <template #tip>
           <div class="el-upload__tip text-center">
-            <span>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</span>
-            <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline; margin-left: 5px;" @click="importTemplate">涓嬭浇妯℃澘</el-link>
+            <span>浠呭厑璁稿鍏� xls銆亁lsx 鏍煎紡鏂囦欢銆�</span>
+            <el-link
+              type="primary"
+              :underline="false"
+              style="font-size: 12px; vertical-align: baseline; margin-left: 5px"
+              @click="importTemplate"
+            >
+              涓嬭浇妯℃澘
+            </el-link>
           </div>
         </template>
       </el-upload>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitFileForm">纭� 瀹�</el-button>
-          <el-button @click="upload.open = false">鍙� 娑�</el-button>
+          <el-button type="primary" @click="submitFileForm">纭畾</el-button>
+          <el-button @click="upload.open = false">鍙栨秷</el-button>
         </div>
       </template>
     </el-dialog>
@@ -114,8 +227,14 @@
 
 <script setup>
 import { usePaginationApi } from "@/hooks/usePaginationApi";
-// import { Search } from "@element-plus/icons-vue";
 import { getLedgerPage, delLedger } from "@/api/equipmentManagement/ledger";
+import {
+  getDeviceAreaTree,
+  getDeviceAreaDetail,
+  addDeviceArea,
+  updateDeviceArea,
+  deleteDeviceArea,
+} from "@/api/equipmentManagement/deviceArea";
 import { onMounted, getCurrentInstance, ref, reactive } from "vue";
 import Modal from "./Modal.vue";
 import { ElMessageBox, ElMessage } from "element-plus";
@@ -128,28 +247,47 @@
   name: "璁惧鍙拌处",
 });
 
-// 琛ㄦ牸澶氶�夋閫変腑椤�
 const multipleList = ref([]);
 const { proxy } = getCurrentInstance();
 const modalRef = ref();
+const treeRef = ref();
+const areaFormRef = ref();
+const treeKeyword = ref("");
+const treeLoading = ref(false);
+const treeData = ref([]);
+const selectedAreaName = ref("");
+const areaDialogVisible = ref(false);
+const areaDialogTitle = ref("鏂板鍖哄煙");
+const areaDialogMode = ref("addRoot");
 const qrDialogVisible = ref(false);
 const qrCodeUrl = ref("");
 const qrRowData = ref(null);
+const uploadRef = ref(null);
 
-// 瀵煎叆鐩稿叧
-const uploadRef = ref(null)
+const treeProps = {
+  children: "children",
+  label: "areaName",
+};
+
 const upload = reactive({
-  // 鏄惁鏄剧ず寮瑰嚭灞�
   open: false,
-  // 寮瑰嚭灞傛爣棰�
   title: "",
-  // 鏄惁绂佺敤涓婁紶
   isUploading: false,
-  // 璁剧疆涓婁紶鐨勮姹傚ご閮�
   headers: { Authorization: "Bearer " + getToken() },
-  // 涓婁紶鐨勫湴鍧�
-  url: import.meta.env.VITE_APP_BASE_API + "/device/ledger/import"
-})
+  url: import.meta.env.VITE_APP_BASE_API + "/device/ledger/import",
+});
+
+const areaForm = reactive({
+  id: undefined,
+  areaName: "",
+  parentId: undefined,
+  sort: 0,
+  remark: "",
+});
+
+const areaRules = {
+  areaName: [{ required: true, message: "璇疯緭鍏ュ尯鍩熷悕绉�", trigger: "blur" }],
+};
 
 const {
   filters,
@@ -157,7 +295,6 @@
   dataList,
   pagination,
   getTableData,
-  resetFilters,
   onCurrentChange,
 } = usePaginationApi(
   getLedgerPage,
@@ -165,10 +302,17 @@
     deviceName: undefined,
     deviceModel: undefined,
     supplierName: undefined,
+    entryDate: undefined,
     entryDateStart: undefined,
     entryDateEnd: undefined,
+    areaId: undefined,
+    areaName: undefined,
   },
   [
+    {
+      label: "鎵�鍦ㄥ尯鍩�",
+      prop: "areaName",
+    },
     {
       label: "璁惧鍚嶇О",
       prop: "deviceName",
@@ -205,39 +349,151 @@
       label: "褰曞叆鏃ユ湡",
       prop: "createTime",
       formatData: (v) => {
-        if (!v) return '';
-        // 濡傛灉鍖呭惈鏃跺垎绉掞紝鍙彇鏃ユ湡閮ㄥ垎
-        if (v.includes(' ')) {
-          return v.split(' ')[0];
-        }
-        return v;
+        if (!v) return "";
+        return v.includes(" ") ? v.split(" ")[0] : v;
       },
     },
-		{
-			dataType: "action",
-			label: "鎿嶄綔",
-			align: "center",
-			fixed: 'right',
-			width: 150,
-			operation: [
-				{
-					name: "缂栬緫",
-					clickFun: (row) => {
-						edit(row.id)
-					},
-				},
-				{
-					name: "鐢熸垚浜岀淮鐮�",
-					clickFun: (row) => {
-						showQRCode(row)
-					},
-				},
-			],
-		},
+    {
+      dataType: "action",
+      label: "鎿嶄綔",
+      align: "center",
+      fixed: "right",
+      width: 150,
+      operation: [
+        {
+          name: "缂栬緫",
+          clickFun: (row) => {
+            edit(row.id);
+          },
+        },
+        {
+          name: "鐢熸垚浜岀淮鐮�",
+          clickFun: (row) => {
+            showQRCode(row);
+          },
+        },
+      ],
+    },
   ]
 );
 
-// 澶氶�夊悗鍋氫粈涔�
+const loadTreeData = async () => {
+  treeLoading.value = true;
+  try {
+    const res = await getDeviceAreaTree();
+    treeData.value = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : [];
+  } finally {
+    treeLoading.value = false;
+  }
+};
+
+const resetAreaForm = () => {
+  areaForm.id = undefined;
+  areaForm.areaName = "";
+  areaForm.parentId = undefined;
+  areaForm.sort = 0;
+  areaForm.remark = "";
+};
+
+const filterTree = () => {
+  treeRef.value?.filter(treeKeyword.value);
+};
+
+const filterTreeNode = (value, data) => {
+  if (!value) {
+    return true;
+  }
+  return String(data.areaName || "").includes(value);
+};
+
+const handleTreeNodeClick = (data) => {
+  filters.areaId = data.id;
+  filters.areaName = data.areaName;
+  selectedAreaName.value = data.areaName || "";
+  getTableData();
+};
+
+const openAreaDialog = async (mode, row) => {
+  areaDialogMode.value = mode;
+  areaDialogTitle.value =
+    mode === "edit" ? "缂栬緫鍖哄煙" : mode === "addChild" ? "鏂板瀛愬尯鍩�" : "鏂板鍖哄煙";
+  resetAreaForm();
+  areaDialogVisible.value = true;
+  if (mode === "addChild") {
+    areaForm.parentId = row.id;
+    areaForm.sort = 0;
+    return;
+  }
+  if (mode === "edit" && row?.id) {
+    const res = await getDeviceAreaDetail(row.id);
+    const detail = res?.data || {};
+    areaForm.id = detail.id;
+    areaForm.areaName = detail.areaName || "";
+    areaForm.parentId = detail.parentId;
+    areaForm.sort = detail.sort ?? 0;
+    areaForm.remark = detail.remark || "";
+  }
+};
+
+const closeAreaDialog = () => {
+  areaDialogVisible.value = false;
+  areaFormRef.value?.resetFields();
+  resetAreaForm();
+};
+
+const submitAreaForm = () => {
+  areaFormRef.value?.validate(async (valid) => {
+    if (!valid) {
+      return;
+    }
+    const submitData = {
+      id: areaForm.id,
+      areaName: areaForm.areaName,
+      parentId: areaForm.parentId,
+      sort: areaForm.sort,
+      remark: areaForm.remark,
+    };
+    const request = areaDialogMode.value === "edit" ? updateDeviceArea : addDeviceArea;
+    const { code } = await request(submitData);
+    if (code === 200) {
+      ElMessage.success(areaDialogMode.value === "edit" ? "淇敼鎴愬姛" : "鏂板鎴愬姛");
+      closeAreaDialog();
+      await loadTreeData();
+    }
+  });
+};
+
+const handleDeleteArea = (row) => {
+  if (hasChildren(row)) {
+    ElMessage.warning("褰撳墠鍖哄煙瀛樺湪涓嬬骇鍖哄煙锛屼笉鑳藉垹闄�");
+    return;
+  }
+  ElMessageBox.confirm("姝ゆ搷浣滃皢鍒犻櫎璇ヨ澶囧尯鍩燂紝鏄惁缁х画锛�", "鎻愮ず", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(async () => {
+    const { code } = await deleteDeviceArea([row.id]);
+    if (code === 200) {
+      ElMessage.success("鍒犻櫎鎴愬姛");
+      if (filters.areaId === row.id) {
+        resetTreeSelection();
+      }
+      await loadTreeData();
+    }
+  });
+};
+
+const hasChildren = (row) => Array.isArray(row?.children) && row.children.length > 0;
+
+const resetTreeSelection = () => {
+  treeRef.value?.setCurrentKey(null);
+  selectedAreaName.value = "";
+  filters.areaId = undefined;
+  filters.areaName = undefined;
+  getTableData();
+};
+
 const handleSelectionChange = (selectionList) => {
   multipleList.value = selectionList;
 };
@@ -245,16 +501,19 @@
 const add = () => {
   modalRef.value.openModal();
 };
+
 const edit = (id) => {
   modalRef.value.loadForm(id);
 };
+
 const changePage = ({ page, limit }) => {
   pagination.currentPage = page;
-	pagination.pageSize = limit;
+  pagination.pageSize = limit;
   onCurrentChange(page);
 };
+
 const deleteRow = (id) => {
-  ElMessageBox.confirm("姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ枃浠�, 鏄惁缁х画?", "鎻愮ず", {
+  ElMessageBox.confirm("姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ暟鎹紝鏄惁缁х画锛�", "鎻愮ず", {
     confirmButtonText: "纭畾",
     cancelButtonText: "鍙栨秷",
     type: "warning",
@@ -281,14 +540,24 @@
   getTableData();
 };
 
+const handleResetFilters = () => {
+  filters.deviceName = undefined;
+  filters.deviceModel = undefined;
+  filters.supplierName = undefined;
+  filters.entryDate = undefined;
+  filters.entryDateStart = undefined;
+  filters.entryDateEnd = undefined;
+  getTableData();
+};
+
 const handleOut = () => {
-  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+  ElMessageBox.confirm("褰撳墠鏌ヨ缁撴灉灏嗚瀵煎嚭锛屾槸鍚︾‘璁ゅ鍑猴紵", "瀵煎嚭", {
     confirmButtonText: "纭",
     cancelButtonText: "鍙栨秷",
     type: "warning",
   })
     .then(() => {
-      proxy.download(`/device/ledger/export`, {}, "璁惧鍙拌处妗f.xlsx");
+      proxy.download("/device/ledger/export", {}, "璁惧鍙拌处妗f.xlsx");
     })
     .catch(() => {
       proxy.$modal.msg("宸插彇娑�");
@@ -296,8 +565,7 @@
 };
 
 const showQRCode = async (row) => {
-  // 鐩存帴浣跨敤URL锛屼笉瑕佺敤JSON.stringify鍖呰
-  const qrContent = proxy.javaApi + '/device-info?deviceId=' + row.id;
+  const qrContent = proxy.javaApi + "/device-info?deviceId=" + row.id;
   qrCodeUrl.value = await QRCode.toDataURL(qrContent);
   qrRowData.value = row;
   qrDialogVisible.value = true;
@@ -310,48 +578,141 @@
   a.click();
 };
 
-// 瀵煎叆鎸夐挳鎿嶄綔
 const handleImport = () => {
-  upload.title = "璁惧鍙拌处瀵煎叆"
-  upload.open = true
-}
+  upload.title = "璁惧鍙拌处瀵煎叆";
+  upload.open = true;
+};
 
-// 涓嬭浇妯℃澘鎿嶄綔
 const importTemplate = () => {
-  proxy.download("/device/ledger/downloadTemplate", {}, `璁惧鍙拌处瀵煎叆妯℃澘_${new Date().getTime()}.xlsx`)
-}
+  proxy.download("/device/ledger/downloadTemplate", {}, `璁惧鍙拌处瀵煎叆妯℃澘_${new Date().getTime()}.xlsx`);
+};
 
-// 鏂囦欢涓婁紶涓鐞�
-const handleFileUploadProgress = (event, file, fileList) => {
-  upload.isUploading = true
-}
+const handleFileUploadProgress = () => {
+  upload.isUploading = true;
+};
 
-// 鏂囦欢涓婁紶鎴愬姛澶勭悊
-const handleFileSuccess = (response, file, fileList) => {
-  upload.open = false
-  upload.isUploading = false
-  proxy.$refs["uploadRef"].handleRemove(file)
-  proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "瀵煎叆缁撴灉", { dangerouslyUseHTMLString: true })
-  getTableData()
-}
+const handleFileSuccess = (response, file) => {
+  upload.open = false;
+  upload.isUploading = false;
+  uploadRef.value?.handleRemove(file);
+  proxy.$alert(
+    "<div style='overflow:auto;overflow-x:hidden;max-height:70vh;padding:10px 20px 0;'>" +
+      response.msg +
+      "</div>",
+    "瀵煎叆缁撴灉",
+    { dangerouslyUseHTMLString: true }
+  );
+  getTableData();
+};
 
-// 鎻愪氦涓婁紶鏂囦欢
 const submitFileForm = () => {
-  proxy.$refs["uploadRef"].submit()
-}
+  uploadRef.value?.submit();
+};
 
-onMounted(() => {
+onMounted(async () => {
+  await loadTreeData();
   getTableData();
 });
 </script>
 
 <style lang="scss" scoped>
-.table_list {
-  margin-top: unset;
+.ledger-view {
+  display: flex;
+  gap: 20px;
 }
+
+.left-panel {
+  width: 320px;
+  min-width: 320px;
+  padding: 16px;
+  background: #fff;
+  border-radius: 4px;
+}
+
+.right-panel {
+  flex: 1;
+  min-width: 0;
+  padding: 16px;
+  background: #fff;
+  border-radius: 4px;
+}
+
+.tree-toolbar {
+  display: flex;
+  gap: 10px;
+  align-items: center;
+  margin-bottom: 8px;
+}
+
+.tree-actions {
+  display: flex;
+  justify-content: flex-end;
+  margin-bottom: 8px;
+}
+
+.ledger-tree {
+  height: calc(100vh - 230px);
+  overflow-y: auto;
+}
+
+.tree-node {
+  flex: 1;
+  min-width: 0;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 8px;
+}
+
+.tree-node-content {
+  display: flex;
+  align-items: center;
+  min-width: 0;
+}
+
+.tree-node-icon {
+  color: #e6a23c;
+  margin-right: 8px;
+  font-size: 18px;
+}
+
+.tree-node-label {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.tree-node-actions {
+  flex-shrink: 0;
+}
+
+.table_list {
+  margin-top: 0;
+}
+
 .actions {
   display: flex;
   justify-content: space-between;
+  align-items: center;
   margin-bottom: 10px;
+  gap: 12px;
+}
+
+.actions-tip {
+  color: #606266;
+  font-size: 14px;
+}
+
+.qr-dialog {
+  text-align: center;
+}
+
+.qr-image {
+  width: 200px;
+  height: 200px;
+}
+
+.qr-footer {
+  margin: 10px 0;
 }
 </style>

--
Gitblit v1.9.3