From ba01c8bd58bea9acbb98c2097765b939a81b21cd Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期五, 29 八月 2025 17:52:41 +0800
Subject: [PATCH] Merge branch 'refs/heads/dev_huangjin' into dev

---
 src/views/index.vue                                     |    6 
 src/components/DynamicTable/index.vue                   |  402 +++
 src/api/lavorissce/ledger.js                            |   55 
 src/views/lavorissue/ledger/filesDia.vue                |  202 +
 src/views/lavorissue/statistics/index.vue               |  285 ++
 src/views/fileManagement/document/attachmentManager.vue |  426 +++
 src/views/fileManagement/bookshelf/detail.vue           |  110 
 src/api/fileManagement/borrow.js                        |   47 
 src/views/fileManagement/return/index.vue               |  595 ++++
 src/utils/util.js                                       |   33 
 src/views/fileManagement/borrow/index.vue               |  582 ++++
 src/views/fileManagement/statistics/index.vue           |  539 ++++
 src/views/equipmentManagement/ledger/index.vue          |    4 
 src/views/lavorissue/ledger/index.vue                   |  300 ++
 src/api/fileManagement/bookshelf.js                     |  128 +
 src/views/chatHome/chatHomeIndex/MobileChat.vue         |    6 
 src/views/fileManagement/document/index.vue             | 1262 ++++++++++
 src/permission.js                                       |   95 
 src/views/example/DynamicTableExample.vue               |  354 ++
 src/views/fileManagement/bookshelf/index.vue            |  688 +++++
 src/views/inventoryManagement/index.vue                 |  309 ++
 src/api/fileManagement/document.js                      |  189 +
 src/api/fileManagement/statistics.js                    |   75 
 src/views/equipmentManagement/deviceInfo/index.vue      |  190 +
 src/views/lavorissue/ledger/Form.vue                    |  154 +
 src/api/equipmentManagement/deviceInfo.js               |   10 
 src/views/example/SimpleExample.vue                     |  135 +
 src/api/fileManagement/return.js                        |   54 
 src/views/lavorissue/ledger/Modal.vue                   |   70 
 29 files changed, 7,251 insertions(+), 54 deletions(-)

diff --git a/src/api/equipmentManagement/deviceInfo.js b/src/api/equipmentManagement/deviceInfo.js
new file mode 100644
index 0000000..d71b713
--- /dev/null
+++ b/src/api/equipmentManagement/deviceInfo.js
@@ -0,0 +1,10 @@
+import request from "@/utils/request";
+
+// 鑾峰彇璁惧鍩烘湰淇℃伅
+export function getDeviceInfo(params) {
+  return request({
+    url: "/device/ledger/scanDevice",
+    method: "get",
+    params,
+  });
+}
diff --git a/src/api/fileManagement/bookshelf.js b/src/api/fileManagement/bookshelf.js
new file mode 100644
index 0000000..0a4a748
--- /dev/null
+++ b/src/api/fileManagement/bookshelf.js
@@ -0,0 +1,128 @@
+import request from "@/utils/request";
+
+/**
+ * 涔︽灦绠$悊鐩稿叧API鎺ュ彛
+ * 鍖呭惈浠撳簱绠$悊銆佽揣鏋剁鐞嗐�佸浘涔︾鐞嗙瓑鍔熻兘鐨勬帴鍙�
+ */
+
+/**
+ * 鑾峰彇浠撳簱鍒楄〃
+ * @description 鑾峰彇鎵�鏈変粨搴撶殑鍩烘湰淇℃伅鍒楄〃
+ * @returns {Promise} 杩斿洖浠撳簱鍒楄〃鏁版嵁
+ */
+export function getWarehouseList() {
+  return request({
+    url: "/warehouse/tree",
+    method: "get",
+  });
+}
+
+/**
+ * 鏂板浠撳簱
+ * @description 鍒涘缓鏂扮殑浠撳簱璁板綍
+ * @param {Object} data 浠撳簱淇℃伅瀵硅薄锛屽寘鍚粨搴撳悕绉扮瓑瀛楁
+ * @returns {Promise} 杩斿洖鏂板缁撴灉
+ */
+export function addWarehouse(data) {
+  return request({
+    url: "/warehouse/add",
+    method: "post",
+    data,
+  });
+}
+
+/**
+ * 鏇存柊浠撳簱淇℃伅
+ * @description 淇敼鐜版湁浠撳簱鐨勫熀鏈俊鎭�
+ * @param {Object} data 浠撳簱淇℃伅瀵硅薄锛屽繀椤诲寘鍚粨搴揑D
+ * @returns {Promise} 杩斿洖鏇存柊缁撴灉
+ */
+export function updateWarehouse(data) {
+  return request({
+    url: "/warehouse/update",
+    method: "put",
+    data,
+  });
+}
+
+/**
+ * 鍒犻櫎浠撳簱
+ * @description 鏍规嵁浠撳簱ID鍒犻櫎鎸囧畾鐨勪粨搴撹褰�
+ * @param {string|number} id 浠撳簱ID
+ * @returns {Promise} 杩斿洖鍒犻櫎缁撴灉
+ */
+export function deleteWarehouse(data) {
+  return request({
+    url: `/warehouse/delete/`,
+    method: "delete",
+    data,
+  });
+}
+
+/**
+ * 鑾峰彇璐ф灦鍒楄〃
+ * @description 鏍规嵁浠撳簱ID鑾峰彇璇ヤ粨搴撲笅鐨勬墍鏈夎揣鏋朵俊鎭�
+ * @param {string|number} warehouseId 浠撳簱ID
+ * @returns {Promise} 杩斿洖璐ф灦鍒楄〃鏁版嵁
+ */
+export function getShelfList(warehouseId) {
+  return request({
+    url: `/shelf/list/${warehouseId}`,
+    method: "get",
+  });
+}
+
+/**
+ * 鏂板璐ф灦
+ * @description 鍦ㄦ寚瀹氫粨搴撲笅鍒涘缓鏂扮殑璐ф灦璁板綍
+ * @param {Object} data 璐ф灦淇℃伅瀵硅薄锛屽寘鍚揣鏋跺悕绉般�佸眰鏁般�佸垪鏁扮瓑瀛楁
+ * @returns {Promise} 杩斿洖鏂板缁撴灉
+ */
+export function addShelf(data) {
+  return request({
+    url: "/warehouse/goodsShelves/add",
+    method: "post",
+    data,
+  });
+}
+
+/**
+ * 鏇存柊璐ф灦淇℃伅
+ * @description 淇敼鐜版湁璐ф灦鐨勫熀鏈俊鎭�
+ * @param {Object} data 璐ф灦淇℃伅瀵硅薄锛屽繀椤诲寘鍚揣鏋禝D
+ * @returns {Promise} 杩斿洖鏇存柊缁撴灉
+ */
+export function updateShelf(data) {
+  return request({
+    url: "/warehouse/goodsShelves/update",
+    method: "put",
+    data,
+  });
+}
+
+/**
+ * 鍒犻櫎璐ф灦
+ * @description 鏍规嵁璐ф灦ID鍒犻櫎鎸囧畾鐨勮揣鏋惰褰�
+ * @param {string|number} id 璐ф灦ID
+ * @returns {Promise} 杩斿洖鍒犻櫎缁撴灉
+ */
+export function deleteShelf(id) {
+  return request({
+    url: `/warehouse/goodsShelves/delete/${id}`,
+    method: "delete",
+  });
+}
+
+/**
+ * 鑾峰彇浠撳簱缁撴瀯
+ * @description 鑾峰彇鎸囧畾浠撳簱鐨勫畬鏁寸粨鏋勪俊鎭紝鍖呮嫭璐ф灦銆佸眰鏁般�佸垪鏁扮瓑
+ * @param {string|number} warehouseId 浠撳簱ID
+ * @returns {Promise} 杩斿洖浠撳簱鐨勫畬鏁寸粨鏋勬暟鎹�
+ */
+export function getWarehouseStructure(data) {
+  return request({
+    url: `/warehouse/goodsShelvesRowcol/list`,
+    method: "get",
+    params: data,
+  });
+}
diff --git a/src/api/fileManagement/borrow.js b/src/api/fileManagement/borrow.js
new file mode 100644
index 0000000..1f4c72c
--- /dev/null
+++ b/src/api/fileManagement/borrow.js
@@ -0,0 +1,47 @@
+import request from "@/utils/request";
+
+// 鏂囨。鍊熼槄绠$悊鐩稿叧鎺ュ彛
+
+// 鑾峰彇鏂囨。鍒楄〃锛堢敤浜庡�熼槄涔︾睄閫夋嫨锛�
+export function getDocumentList() {
+  return request({
+    url: "/documentation/list",
+    method: "get",
+  });
+}
+
+// 鍊熼槄鍒嗛〉鏌ヨ
+export function getBorrowList(params) {
+  return request({
+    url: "/documentationBorrowManagement/listPage",
+    method: "get",
+    params: params,
+  });
+}
+
+// 鏂板鍊熼槄
+export function addBorrow(data) {
+  return request({
+    url: "/documentationBorrowManagement/add",
+    method: "post",
+    data: data,
+  });
+}
+
+// 鏇存柊鍊熼槄
+export function updateBorrow(data) {
+  return request({
+    url: "/documentationBorrowManagement/update",
+    method: "put",
+    data: data,
+  });
+}
+
+// 鍒犻櫎鍊熼槄
+export function deleteBorrow(ids) {
+  return request({
+    url: "/documentationBorrowManagement/delete",
+    method: "delete",
+    data: ids,
+  });
+}
diff --git a/src/api/fileManagement/document.js b/src/api/fileManagement/document.js
new file mode 100644
index 0000000..f3d5f4f
--- /dev/null
+++ b/src/api/fileManagement/document.js
@@ -0,0 +1,189 @@
+import request from "@/utils/request";
+
+// 鑾峰彇鍒嗙被鏍�
+export function getCategoryTree() {
+  return request({
+    url: "/warehouse/documentClassification/getList",
+    method: "get",
+  });
+}
+
+// 鏂板鍒嗙被
+export function addCategory(data) {
+  return request({
+    url: "/warehouse/documentClassification/add",
+    method: "post",
+    data: {
+      category: data.category,
+      parentId: data.parentId,
+    },
+  });
+}
+
+// 淇敼鍒嗙被
+export function updateCategory(data) {
+  return request({
+    url: "/warehouse/documentClassification/update",
+    method: "put",
+    data: {
+      id: data.id,
+      category: data.category,
+    },
+  });
+}
+
+// 鍒犻櫎鍒嗙被
+export function deleteCategory(ids) {
+  return request({
+    url: "/warehouse/documentClassification/delete",
+    method: "delete",
+    data: ids,
+  });
+}
+
+// 鑾峰彇鏂囨。鍒楄〃锛堝垎椤碉級
+export function getDocumentList(query) {
+  return request({
+    url: "/documentation/listPage",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鏂板鏂囨。
+export function addDocument(data) {
+  return request({
+    url: "/documentation/add",
+    method: "post",
+    data: data,
+  });
+}
+
+// 淇敼鏂囨。
+export function updateDocument(data) {
+  return request({
+    url: "/documentation/update",
+    method: "put",
+    data: data,
+  });
+}
+
+// 鍒犻櫎鏂囨。
+export function deleteDocument(ids) {
+  return request({
+    url: "/documentation/delete",
+    method: "delete",
+    data: ids,
+  });
+}
+
+// 鑾峰彇鏂囨。璇︽儏
+export function getDocumentDetail(id) {
+  return request({
+    url: "/document/" + id,
+    method: "get",
+  });
+}
+
+// 鎼滅储鏂囨。
+export function searchDocument(query) {
+  return request({
+    url: "/document/search",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鑾峰彇浠撳簱缁撴瀯
+export function getWarehouseStructure() {
+  return request({
+    url: "/document/warehouse/structure",
+    method: "get",
+  });
+}
+
+// 闄勪欢绠$悊鐩稿叧鎺ュ彛
+// 娣诲姞闄勪欢
+export function addDocumentationFile(data) {
+  return request({
+    url: "/documentation/documentationFile/add",
+    method: "post",
+    data: data,
+  });
+}
+
+// 鑾峰彇闄勪欢鍒楄〃
+export function getDocumentationFileList(params) {
+  return request({
+    url: "/documentation/documentationFile/listPage",
+    method: "get",
+    params: params,
+  });
+}
+
+// 鍒犻櫎闄勪欢
+export function deleteDocumentationFile(ids) {
+  return request({
+    url: "/documentation/documentationFile/del",
+    method: "delete",
+    data: ids,
+  });
+}
+
+// 鏂囨。鍊熼槄绠$悊鐩稿叧鎺ュ彛
+export function getBorrowList(params) {
+  return request({
+    url: "/documentationBorrowManagement/listPage",
+    method: "get",
+    params: params,
+  });
+}
+
+export function addBorrow(data) {
+  return request({
+    url: "/documentationBorrowManagement/add",
+    method: "post",
+    data: data,
+  });
+}
+
+export function updateBorrow(data) {
+  return request({
+    url: "/documentationBorrowManagement/update",
+    method: "put",
+    data: data,
+  });
+}
+
+export function deleteBorrow(ids) {
+  return request({
+    url: "/documentationBorrowManagement/delete",
+    method: "delete",
+    data: ids,
+  });
+}
+
+// 缁熻鐩稿叧鎺ュ彛
+// 鑾峰彇鎬讳綋缁熻鏁版嵁
+export function getDocumentationOverview() {
+  return request({
+    url: "/documentation/overview",
+    method: "get",
+  });
+}
+
+// 鑾峰彇鍒嗙被缁熻鏁版嵁
+export function getDocumentationCategoryStats() {
+  return request({
+    url: "/documentation/category",
+    method: "get",
+  });
+}
+
+// 鑾峰彇鐘舵�佺粺璁℃暟鎹�
+export function getDocumentationStatusStats() {
+  return request({
+    url: "/documentation/status",
+    method: "get",
+  });
+}
diff --git a/src/api/fileManagement/return.js b/src/api/fileManagement/return.js
new file mode 100644
index 0000000..2e0c0e7
--- /dev/null
+++ b/src/api/fileManagement/return.js
@@ -0,0 +1,54 @@
+import request from "@/utils/request";
+
+// 鍒嗛〉鏌ヨ褰掕繕璁板綍
+export function getReturnListPage(query) {
+  return request({
+    url: "/documentationBorrowManagement/listPageReturn",
+    method: "get",
+    params: query,
+  });
+}
+
+// 褰掕繕鎿嶄綔
+export function returnDocument(data) {
+  return request({
+    url: "/documentationBorrowManagement/revent",
+    method: "put",
+    data: data,
+  });
+}
+
+// 鍒犻櫎褰掕繕璁板綍
+export function deleteReturn(ids) {
+  return request({
+    url: "/documentationBorrowManagement/reventDelete",
+    method: "delete",
+    data: ids,
+  });
+}
+
+// 鏇存柊鍊熼槄璁板綍
+export function updateBorrow(data) {
+  return request({
+    url: "/documentationBorrowManagement/update",
+    method: "put",
+    data: data,
+  });
+}
+
+// 褰掕繕鏇存柊
+export function reventUpdate(data) {
+  return request({
+    url: "/documentationBorrowManagement/reventUpdate",
+    method: "put",
+    data: data,
+  });
+}
+
+// 鑾峰彇鏂囨。鍒楄〃
+export function getDocumentList() {
+  return request({
+    url: "/documentationBorrowManagement/list",
+    method: "get",
+  });
+}
diff --git a/src/api/fileManagement/statistics.js b/src/api/fileManagement/statistics.js
new file mode 100644
index 0000000..d77375c
--- /dev/null
+++ b/src/api/fileManagement/statistics.js
@@ -0,0 +1,75 @@
+import request from "@/utils/request";
+
+// 鑾峰彇妗f鎬讳綋缁熻
+export function getDocumentStatistics() {
+  return request({
+    url: "/fileManagement/statistics/overview",
+    method: "get",
+  });
+}
+
+// 鑾峰彇妗f鍒嗙被缁熻
+export function getCategoryStatistics() {
+  return request({
+    url: "/fileManagement/statistics/category",
+    method: "get",
+  });
+}
+
+// 鑾峰彇妗f鐘舵�佺粺璁�
+export function getStatusStatistics() {
+  return request({
+    url: "/fileManagement/statistics/status",
+    method: "get",
+  });
+}
+
+// 鑾峰彇妗f鍊熼槄缁熻
+export function getBorrowStatistics() {
+  return request({
+    url: "/fileManagement/statistics/borrow",
+    method: "get",
+  });
+}
+
+// 鑾峰彇妗f骞村害缁熻
+export function getYearStatistics() {
+  return request({
+    url: "/fileManagement/statistics/year",
+    method: "get",
+  });
+}
+
+// 鑾峰彇妗f浣嶇疆缁熻
+export function getLocationStatistics() {
+  return request({
+    url: "/fileManagement/statistics/location",
+    method: "get",
+  });
+}
+
+// 鑾峰彇妗f瓒嬪娍缁熻
+export function getTrendStatistics(params) {
+  return request({
+    url: "/fileManagement/statistics/trend",
+    method: "get",
+    params: params,
+  });
+}
+
+// 鑾峰彇妗f鍊熼槄鎺掕
+export function getBorrowRanking() {
+  return request({
+    url: "/fileManagement/statistics/borrowRanking",
+    method: "get",
+  });
+}
+
+// 鑾峰彇妗f鍒嗙被璇︽儏缁熻
+export function getCategoryDetailStatistics(categoryId) {
+  return request({
+    url: `/fileManagement/statistics/categoryDetail/${categoryId}`,
+    method: "get",
+  });
+}
+
diff --git a/src/api/lavorissce/ledger.js b/src/api/lavorissce/ledger.js
new file mode 100644
index 0000000..f4f710c
--- /dev/null
+++ b/src/api/lavorissce/ledger.js
@@ -0,0 +1,55 @@
+import request from '@/utils/request'
+
+// 鍒嗛〉鏌ヨ
+export function listPage(query) {
+    return request({
+        url: '/lavorIssue/listPage',
+        method: 'get',
+        params: query
+    })
+}
+
+// 鍒嗛〉鏌ヨ
+export function statistics(params) {
+    return request({
+        url: '/lavorIssue/statistics',
+        method: 'get',
+        params
+    })
+}
+
+export function statisticsList(params) {
+    return request({
+        url: '/lavorIssue/statisticsList',
+        method: 'get',
+        params
+    })
+}
+
+// 娣诲姞
+export function add(data) {
+    return request({
+        url: '/lavorIssue/add',
+        method: 'post',
+        data
+    })
+}
+
+// 淇敼
+export function update(data) {
+    return request({
+        url: '/lavorIssue/update',
+        method: 'post',
+        data
+    })
+}
+
+// 鍒犻櫎
+export function deleteLedger(data) {
+    return request({
+        url: '/lavorIssue/delete',
+        method: 'delete',
+        data
+    })
+}
+
diff --git a/src/components/DynamicTable/index.vue b/src/components/DynamicTable/index.vue
new file mode 100644
index 0000000..9da9a3c
--- /dev/null
+++ b/src/components/DynamicTable/index.vue
@@ -0,0 +1,402 @@
+<template>
+  <div class="dynamic-table-container">
+    <el-table
+      ref="tableRef"
+      v-loading="loading"
+      :data="tableData"
+      :border="border"
+      :height="height"
+      :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+      style="width: 100%"
+      @selection-change="handleSelectionChange"
+      @row-click="handleRowClick"
+    >
+      <!-- 閫夋嫨鍒� -->
+      <el-table-column
+        v-if="showSelection"
+        align="center"
+        type="selection"
+        width="55"
+      />
+      
+      <!-- 搴忓彿鍒� -->
+      <el-table-column
+        v-if="showIndex"
+        align="center"
+        label="搴忓彿"
+        type="index"
+        width="60"
+      />
+
+      <!-- 鍥哄畾鍒楋細閮ㄩ棬 -->
+      <el-table-column
+        label="閮ㄩ棬"
+        prop="department"
+        width="120"
+        show-overflow-tooltip
+        align="center"
+      />
+
+      <!-- 鍥哄畾鍒楋細濮撳悕 -->
+      <el-table-column
+        label="濮撳悕"
+        prop="name"
+        width="100"
+        show-overflow-tooltip
+        align="center"
+      />
+
+      <!-- 鍥哄畾鍒楋細宸ュ彿 -->
+      <el-table-column
+        label="宸ュ彿"
+        prop="employeeId"
+        width="100"
+        show-overflow-tooltip
+        align="center"
+      />
+
+      <!-- 鍔ㄦ�佸垪锛氭牴鎹瓧鍏告覆鏌� -->
+      <el-table-column
+        v-for="(dictItem, index) in dynamicColumns"
+        :key="dictItem.value"
+        :label="dictItem.label"
+        :prop="dictItem.value"
+        :width="dictItem.width || 120"
+        show-overflow-tooltip
+        align="center"
+      >
+        <template #default="scope">
+          <!-- 鏍规嵁瀛楀吀绫诲瀷娓叉煋涓嶅悓鐨勬樉绀烘柟寮� -->
+          <template v-if="dictItem.renderType === 'tag'">
+            <el-tag
+              :type="getTagType(scope.row[dictItem.value])"
+              size="small"
+            >
+              {{ getDictValueLabel(dictItem.dictType, scope.row[dictItem.value]) }}
+            </el-tag>
+          </template>
+          <template v-else-if="dictItem.renderType === 'select'">
+            <el-select
+              v-model="scope.row[dictItem.value]"
+              placeholder="璇烽�夋嫨"
+              size="small"
+              @change="handleSelectChange(scope.row, dictItem.value, $event)"
+            >
+              <el-option
+                v-for="option in dictItem.options"
+                :key="option.value"
+                :label="option.label"
+                :value="option.value"
+              />
+            </el-select>
+          </template>
+          <template v-else-if="dictItem.renderType === 'input'">
+            <el-input
+              v-model="scope.row[dictItem.value]"
+              size="small"
+              placeholder="璇疯緭鍏�"
+              @blur="handleInputChange(scope.row, dictItem.value, $event)"
+            />
+          </template>
+          <template v-else>
+            <span>{{ getDictValueLabel(dictItem.dictType, scope.row[dictItem.value]) }}</span>
+          </template>
+        </template>
+      </el-table-column>
+
+      <!-- 鎿嶄綔鍒� -->
+      <el-table-column
+        v-if="showActions"
+        label="鎿嶄綔"
+        width="150"
+        align="center"
+        fixed="right"
+      >
+        <template #default="scope">
+          <el-button
+            type="primary"
+            link
+            size="small"
+            @click="handleEdit(scope.row, scope.$index)"
+          >
+            缂栬緫
+          </el-button>
+          <el-button
+            type="danger"
+            link
+            size="small"
+            @click="handleDelete(scope.row, scope.$index)"
+          >
+            鍒犻櫎
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 鍒嗛〉缁勪欢 -->
+    <div v-if="showPagination" class="pagination-container">
+      <el-pagination
+        v-model:current-page="pagination.current"
+        v-model:page-size="pagination.size"
+        :page-sizes="[10, 20, 50, 100]"
+        :total="pagination.total"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, onMounted, watch } from 'vue'
+import { useDict } from '@/utils/dict'
+
+// 瀹氫箟缁勪欢灞炴��
+const props = defineProps({
+  // 琛ㄦ牸鏁版嵁
+  data: {
+    type: Array,
+    default: () => []
+  },
+  // 瀛楀吀绫诲瀷鏁扮粍锛岀敤浜庡姩鎬佺敓鎴愬垪
+  dictTypes: {
+    type: Array,
+    default: () => []
+  },
+  // 鏄惁鏄剧ず閫夋嫨鍒�
+  showSelection: {
+    type: Boolean,
+    default: false
+  },
+  // 鏄惁鏄剧ず搴忓彿鍒�
+  showIndex: {
+    type: Boolean,
+    default: true
+  },
+  // 鏄惁鏄剧ず鎿嶄綔鍒�
+  showActions: {
+    type: Boolean,
+    default: false
+  },
+  // 鏄惁鏄剧ず鍒嗛〉
+  showPagination: {
+    type: Boolean,
+    default: false
+  },
+  // 琛ㄦ牸楂樺害
+  height: {
+    type: [String, Number],
+    default: 'auto'
+  },
+  // 鏄惁鏄剧ず杈规
+  border: {
+    type: Boolean,
+    default: true
+  },
+  // 鍔犺浇鐘舵��
+  loading: {
+    type: Boolean,
+    default: false
+  },
+  // 鍒嗛〉閰嶇疆
+  pagination: {
+    type: Object,
+    default: () => ({
+      current: 1,
+      size: 10,
+      total: 0
+    })
+  }
+})
+
+// 瀹氫箟浜嬩欢
+const emit = defineEmits([
+  'selection-change',
+  'row-click',
+  'edit',
+  'delete',
+  'select-change',
+  'input-change',
+  'size-change',
+  'current-change'
+])
+
+// 鍝嶅簲寮忔暟鎹�
+const tableRef = ref(null)
+const tableData = ref([])
+
+// 鑾峰彇瀛楀吀鏁版嵁
+const dictData = ref({})
+
+// 鍔ㄦ�佸垪閰嶇疆
+const dynamicColumns = computed(() => {
+  const columns = []
+  
+  props.dictTypes.forEach(dictType => {
+    const dictItems = dictData.value[dictType] || []
+    // 涓烘瘡涓瓧鍏哥被鍨嬪垱寤轰竴涓垪锛岃�屼笉鏄负姣忎釜瀛楀吀椤瑰垱寤哄垪
+    if (dictItems.length > 0) {
+      columns.push({
+        label: getDictLabel(dictType), // 鑾峰彇瀛楀吀绫诲瀷鐨勬樉绀哄悕绉�
+        value: dictType, // 浣跨敤瀛楀吀绫诲瀷浣滀负瀛楁鍚�
+        width: 120,
+        renderType: 'tag', // 榛樿浣跨敤鏍囩鏄剧ず
+        options: dictItems, // 鎻愪緵閫夐」
+        dictType: dictType
+      })
+    }
+  })
+  
+  return columns
+})
+
+// 鑾峰彇瀛楀吀绫诲瀷鐨勬樉绀哄悕绉�
+const getDictLabel = (dictType) => {
+  const labelMap = {
+    'sys_normal_disable': '鐘舵��',
+    'sys_user_level': '绾у埆',
+    'sys_user_position': '鑱屼綅',
+    'sys_yes_no': '鏄惁',
+    'sys_user_sex': '鎬у埆',
+    'sys_lavor_issue': '鍔冲姟闂'  // 娣诲姞鍔冲姟闂瀛楀吀
+  }
+  return labelMap[dictType] || dictType
+}
+
+// 鑾峰彇瀛楀吀鏁版嵁
+const loadDictData = async () => {
+  try {
+    const dictPromises = props.dictTypes.map(async (dictType) => {
+      const { getDicts } = await import('@/api/system/dict/data')
+      const response = await getDicts(dictType)
+      return {
+        type: dictType,
+        data: response.data.map(item => ({
+          label: item.dictLabel,
+          value: item.dictValue,
+          elTagType: item.listClass,
+          elTagClass: item.cssClass
+        }))
+      }
+    })
+    
+    const results = await Promise.all(dictPromises)
+    results.forEach(result => {
+      dictData.value[result.type] = result.data
+    })
+  } catch (error) {
+    console.error('鍔犺浇瀛楀吀鏁版嵁澶辫触:', error)
+    // 濡傛灉瀛楀吀鍔犺浇澶辫触锛屼娇鐢ㄩ粯璁ゆ暟鎹�
+    props.dictTypes.forEach(dictType => {
+      if (!dictData.value[dictType]) {
+        dictData.value[dictType] = []
+      }
+    })
+  }
+}
+
+// 鑾峰彇鏍囩绫诲瀷
+const getTagType = (value) => {
+  // 鏍规嵁鍊艰繑鍥炰笉鍚岀殑鏍囩绫诲瀷
+  if (value === '1' || value === 'true' || value === '鏄�') return 'success'
+  if (value === '0' || value === 'false' || value === '鍚�') return 'danger'
+  if (value === '2' || value === 'warning') return 'warning'
+  return 'info'
+}
+
+// 鑾峰彇瀛楀吀鍊肩殑鏍囩
+const getDictValueLabel = (dictType, value) => {
+  if (!value) return '-'
+  const dictItems = dictData.value[dictType] || []
+  const item = dictItems.find(item => item.value === value)
+  return item ? item.label : value
+}
+
+// 浜嬩欢澶勭悊鍑芥暟
+const handleSelectionChange = (selection) => {
+  emit('selection-change', selection)
+}
+
+const handleRowClick = (row, column, event) => {
+  emit('row-click', row, column, event)
+}
+
+const handleEdit = (row, index) => {
+  emit('edit', row, index)
+}
+
+const handleDelete = (row, index) => {
+  emit('delete', row, index)
+}
+
+const handleSelectChange = (row, prop, value) => {
+  emit('select-change', row, prop, value)
+}
+
+const handleInputChange = (row, prop, event) => {
+  emit('input-change', row, prop, event.target.value)
+}
+
+const handleSizeChange = (size) => {
+  emit('size-change', size)
+}
+
+const handleCurrentChange = (current) => {
+  emit('current-change', current)
+}
+
+// 鐩戝惉鏁版嵁鍙樺寲
+watch(() => props.data, (newData) => {
+  tableData.value = newData
+}, { immediate: true })
+
+// 鐩戝惉瀛楀吀绫诲瀷鍙樺寲
+watch(() => props.dictTypes, () => {
+  loadDictData()
+}, { immediate: true })
+
+// 缁勪欢鎸傝浇鏃跺姞杞藉瓧鍏告暟鎹�
+onMounted(() => {
+  loadDictData()
+})
+
+// 鏆撮湶鏂规硶缁欑埗缁勪欢
+defineExpose({
+  tableRef,
+  getSelection: () => tableRef.value?.getSelectionRows() || [],
+  clearSelection: () => tableRef.value?.clearSelection(),
+  toggleRowSelection: (row, selected) => tableRef.value?.toggleRowSelection(row, selected),
+  setCurrentRow: (row) => tableRef.value?.setCurrentRow(row)
+})
+</script>
+
+<style scoped>
+.dynamic-table-container {
+  width: 100%;
+}
+
+.pagination-container {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+:deep(.el-table .el-table__header-wrapper th) {
+  background-color: #F0F1F5 !important;
+  color: #333333;
+  font-weight: 600;
+}
+
+:deep(.el-table .el-table__body-wrapper td) {
+  padding: 8px 0;
+}
+
+:deep(.el-select) {
+  width: 100%;
+}
+
+:deep(.el-input) {
+  width: 100%;
+}
+</style>
diff --git a/src/permission.js b/src/permission.js
index a7d9f87..5b2566b 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -1,69 +1,76 @@
-import router from './router'
-import { ElMessage } from 'element-plus'
-import NProgress from 'nprogress'
-import 'nprogress/nprogress.css'
-import { getToken } from '@/utils/auth'
-import { isHttp, isPathMatch } from '@/utils/validate'
-import { isRelogin } from '@/utils/request'
-import useUserStore from '@/store/modules/user'
-import useSettingsStore from '@/store/modules/settings'
-import usePermissionStore from '@/store/modules/permission'
+import router from "./router";
+import { ElMessage } from "element-plus";
+import NProgress from "nprogress";
+import "nprogress/nprogress.css";
+import { getToken } from "@/utils/auth";
+import { isHttp, isPathMatch } from "@/utils/validate";
+import { isRelogin } from "@/utils/request";
+import useUserStore from "@/store/modules/user";
+import useSettingsStore from "@/store/modules/settings";
+import usePermissionStore from "@/store/modules/permission";
 
-NProgress.configure({ showSpinner: false })
+NProgress.configure({ showSpinner: false });
 
-const whiteList = ['/login', '/register']
+const whiteList = ["/login", "/register", "/device-info"];
 
 const isWhiteList = (path) => {
-  return whiteList.some(pattern => isPathMatch(pattern, path))
-}
+  return whiteList.some((pattern) => isPathMatch(pattern, path));
+};
 
 router.beforeEach((to, from, next) => {
-  NProgress.start()
+  NProgress.start();
   if (getToken()) {
-    to.meta.title && useSettingsStore().setTitle(to.meta.title)
+    to.meta.title && useSettingsStore().setTitle(to.meta.title);
     /* has token*/
-    if (to.path === '/login') {
-      next({ path: '/' })
-      NProgress.done()
+    if (to.path === "/login") {
+      next({ path: "/" });
+      NProgress.done();
     } else if (isWhiteList(to.path)) {
-      next()
+      next();
     } else {
       if (useUserStore().roles.length === 0) {
-        isRelogin.show = true
+        isRelogin.show = true;
         // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁宸叉媺鍙栧畬user_info淇℃伅
-        useUserStore().getInfo().then(() => {
-          isRelogin.show = false
-          usePermissionStore().generateRoutes().then(accessRoutes => {
-            // 鏍规嵁roles鏉冮檺鐢熸垚鍙闂殑璺敱琛�
-            accessRoutes.forEach(route => {
-              if (!isHttp(route.path)) {
-                router.addRoute(route) // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
-              }
-            })
-            next({ ...to, replace: true }) // hack鏂规硶 纭繚addRoutes宸插畬鎴�
+        useUserStore()
+          .getInfo()
+          .then(() => {
+            isRelogin.show = false;
+            usePermissionStore()
+              .generateRoutes()
+              .then((accessRoutes) => {
+                // 鏍规嵁roles鏉冮檺鐢熸垚鍙闂殑璺敱琛�
+                accessRoutes.forEach((route) => {
+                  if (!isHttp(route.path)) {
+                    router.addRoute(route); // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
+                  }
+                });
+                next({ ...to, replace: true }); // hack鏂规硶 纭繚addRoutes宸插畬鎴�
+              });
           })
-        }).catch(err => {
-          useUserStore().logOut().then(() => {
-            ElMessage.error(err)
-            next({ path: '/' })
-          })
-        })
+          .catch((err) => {
+            useUserStore()
+              .logOut()
+              .then(() => {
+                ElMessage.error(err);
+                next({ path: "/" });
+              });
+          });
       } else {
-        next()
+        next();
       }
     }
   } else {
     // 娌℃湁token
     if (isWhiteList(to.path)) {
       // 鍦ㄥ厤鐧诲綍鐧藉悕鍗曪紝鐩存帴杩涘叆
-      next()
+      next();
     } else {
-      next(`/login?redirect=${to.fullPath}`) // 鍚﹀垯鍏ㄩ儴閲嶅畾鍚戝埌鐧诲綍椤�
-      NProgress.done()
+      next(`/login?redirect=${to.fullPath}`); // 鍚﹀垯鍏ㄩ儴閲嶅畾鍚戝埌鐧诲綍椤�
+      NProgress.done();
     }
   }
-})
+});
 
 router.afterEach(() => {
-  NProgress.done()
-})
+  NProgress.done();
+});
diff --git a/src/utils/util.js b/src/utils/util.js
index 78846dc..be08cc1 100644
--- a/src/utils/util.js
+++ b/src/utils/util.js
@@ -1,4 +1,6 @@
 //闃叉姈
+import dayjs from "dayjs";
+
 export  function debounce(fn) {
     console.log(1)
     let t = null //鍙細鎵ц涓�娆�
@@ -86,7 +88,34 @@
       'aplication/zip': 'zpi',
     }
   }
-
+ export const deepCopySameProperties = (source, target) =>{
+    for (const key in source) {
+        if (target.hasOwnProperty(key)) {
+            if (typeof source[key] === 'object' && source[key] !== null &&
+                typeof target[key] === 'object' && target[key] !== null) {
+                // 閫掑綊澶勭悊瀵硅薄
+                deepCopySameProperties(source[key], target[key]);
+            } else {
+                // 鍩烘湰绫诲瀷鐩存帴璧嬪��
+                target[key] = source[key];
+            }
+        }
+    }
+    return target;
+}
   export function filterArr(arr) {
       return arr.filter(item => item.flag !== false);
-  }
\ No newline at end of file
+  }
+
+ export function getCurrentMonth () {
+    let month = dayjs().month() + 1
+    if (month <= 3) {
+        return '1';
+    } else if (month <= 6) {
+        return '2';
+    } else if (month <= 9) {
+        return '3';
+    } else if (month <= 12) {
+        return '4';
+    }
+}
\ No newline at end of file
diff --git a/src/views/chatHome/chatHomeIndex/MobileChat.vue b/src/views/chatHome/chatHomeIndex/MobileChat.vue
index 5b06e76..adeb5e7 100644
--- a/src/views/chatHome/chatHomeIndex/MobileChat.vue
+++ b/src/views/chatHome/chatHomeIndex/MobileChat.vue
@@ -14,7 +14,7 @@
                 <span class="flash_cursor"></span>
               </template>
               <template v-else>
-                <pre>{{ item.msg }}</pre>
+                <pre style="font-family: none;">{{ item.msg }}</pre>
               </template>
             </div>
             <div class="chat-img" v-if="item.chatType == 1">
@@ -140,7 +140,7 @@
     }
     chatList.value.push(chatMsg)
     let chatGPT = {
-      headImg: headPortrait,
+      headImg: chatGPTHeadImg,
       name: '灏忔櫤',
       time: new Date().toLocaleTimeString(),
       msg: "",
@@ -185,7 +185,7 @@
     uid: '1002'
   })
   chatList.value.push({
-    headImg: chatGPTHeadImg,
+    headImg: headPortrait,
     name: '鍗ч緳',
     time: new Date().toLocaleTimeString(),
     msg: route.query.keyWord,
diff --git a/src/views/equipmentManagement/deviceInfo/index.vue b/src/views/equipmentManagement/deviceInfo/index.vue
new file mode 100644
index 0000000..de162cc
--- /dev/null
+++ b/src/views/equipmentManagement/deviceInfo/index.vue
@@ -0,0 +1,190 @@
+<template>
+  <div class="device-info-container">
+    <div class="page-header">
+      <h1>璁惧淇℃伅</h1>
+      <div class="device-status" :class="deviceStatusClass">
+        {{ deviceStatusText }}
+      </div>
+    </div>
+
+    <div class="info-card">
+      <div class="card-header">鍩烘湰淇℃伅</div>
+      <div class="card-content">
+        <div class="info-row">
+          <span class="label">璁惧鍚嶇О锛�</span>
+          <span class="value">{{ deviceInfo.deviceName }}</span>
+        </div>
+        <div class="info-row">
+          <span class="label">瑙勬牸鍨嬪彿锛�</span>
+          <span class="value">{{ deviceInfo.deviceModel }}</span>
+        </div>
+        <div class="info-row">
+          <span class="label">鐢熶骇鍘傚锛�</span>
+          <span class="value">{{ deviceInfo.supplierName }}</span>
+        </div>
+        <div class="info-row">
+          <span class="label">鍗曚綅锛�</span>
+          <span class="value">{{ deviceInfo.unit }}</span>
+        </div>
+      </div>
+    </div>
+
+         <div class="info-card">
+       <div class="card-header">缁存姢淇℃伅</div>
+       <div class="card-content">
+         <div class="maintenance-info">
+           <div class="maintenance-item">
+             <span class="label">鏈�鍚庣淮鎶わ細</span>
+             <span class="value">{{ deviceInfo.updateTime }}</span>
+           </div>
+           <div class="maintenance-item">
+             <span class="label">涓嬫缁存姢锛�</span>
+             <span class="value">{{ deviceInfo.createTime }}</span>
+           </div>
+           <div class="maintenance-item">
+             <span class="label">缁存姢鐘舵�侊細</span>
+             <span class="value status-normal">{{ deviceInfo.statusText }}</span>
+           </div>
+         </div>
+       </div>
+     </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, computed } from 'vue'
+import { useRoute } from 'vue-router'
+import { ElMessage } from 'element-plus'
+import { 
+  getDeviceInfo, 
+} from '@/api/equipmentManagement/deviceInfo'
+
+const route = useRoute()
+
+const deviceInfo = reactive({
+  deviceName: '',
+  deviceModel: '',
+  supplierName: '',
+  unit: '',
+  statusText:'姝e父',
+  updateTime:'',
+  createTime:''
+})
+
+const deviceStatusClass = computed(() => {
+  return 'status-normal'
+})
+
+const deviceStatusText = computed(() => {
+  return '姝e父'
+})
+
+const fetchDeviceInfo = async (deviceId) => {
+  try {
+    // 鑾峰彇璁惧淇℃伅
+    const deviceResponse = await getDeviceInfo({id:deviceId})
+    if (deviceResponse.code === 200) {
+      Object.assign(deviceInfo, deviceResponse.data)
+    }
+    
+    
+  } catch (error) {
+    
+    ElMessage.warning('浣跨敤妯℃嫙鏁版嵁锛屽疄闄匒PI璋冪敤澶辫触')
+  }
+}
+
+onMounted(() => {
+  const deviceId = route.query.deviceId || route.params.deviceId || ''
+  fetchDeviceInfo(deviceId)
+})
+</script>
+
+<style scoped>
+.device-info-container {
+  min-height: 100vh;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  padding: 20px;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+}
+
+.page-header {
+  background: rgba(255, 255, 255, 0.95);
+  border-radius: 16px;
+  padding: 20px;
+  margin-bottom: 20px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.page-header h1 {
+  margin: 0;
+  color: #2c3e50;
+  font-size: 24px;
+}
+
+.device-status {
+  padding: 8px 16px;
+  border-radius: 20px;
+  font-size: 14px;
+  color: white;
+  background: #52c41a;
+}
+
+.info-card {
+  background: rgba(255, 255, 255, 0.95);
+  border-radius: 16px;
+  margin-bottom: 20px;
+  overflow: hidden;
+}
+
+.card-header {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  color: white;
+  padding: 16px 20px;
+  font-weight: 500;
+}
+
+.card-content {
+  padding: 20px;
+}
+
+.info-row, .maintenance-item {
+  display: flex;
+  margin-bottom: 12px;
+  align-items: center;
+}
+
+.label {
+  width: 100px;
+  color: #666;
+  font-size: 14px;
+}
+
+.value {
+  flex: 1;
+  color: #2c3e50;
+  font-weight: 500;
+}
+
+.status-normal {
+  color: #52c41a;
+}
+
+
+
+@media (max-width: 768px) {
+  .device-info-container {
+    padding: 16px;
+  }
+  
+  .page-header h1 {
+    font-size: 20px;
+  }
+  
+  .label {
+    width: 80px;
+  }
+}
+</style>
diff --git a/src/views/equipmentManagement/ledger/index.vue b/src/views/equipmentManagement/ledger/index.vue
index 428a6d9..28e5ec8 100644
--- a/src/views/equipmentManagement/ledger/index.vue
+++ b/src/views/equipmentManagement/ledger/index.vue
@@ -275,8 +275,8 @@
 };
 
 const showQRCode = async (row) => {
-  // 浣犲彲浠ヨ嚜瀹氫箟浜岀淮鐮佸唴瀹癸紝姣斿 row.id 鎴� row.deviceName
-  const qrContent = JSON.stringify(row); // 鎴� `${row.id}`
+  // 鐩存帴浣跨敤URL锛屼笉瑕佺敤JSON.stringify鍖呰
+  const qrContent = proxy.javaApi + '/device-info?deviceId=' + row.id;
   qrCodeUrl.value = await QRCode.toDataURL(qrContent);
   qrRowData.value = row;
   qrDialogVisible.value = true;
diff --git a/src/views/example/DynamicTableExample.vue b/src/views/example/DynamicTableExample.vue
new file mode 100644
index 0000000..038cd43
--- /dev/null
+++ b/src/views/example/DynamicTableExample.vue
@@ -0,0 +1,354 @@
+<template>
+  <div class="app-container">
+    <div class="search-form">
+      <el-form :inline="true" :model="searchForm">
+        <el-form-item label="閮ㄩ棬">
+          <el-input
+            v-model="searchForm.department"
+            placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�"
+            clearable
+            style="width: 200px"
+          />
+        </el-form-item>
+        <el-form-item label="濮撳悕">
+          <el-input
+            v-model="searchForm.name"
+            placeholder="璇疯緭鍏ュ鍚�"
+            clearable
+            style="width: 200px"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">鎼滅储</el-button>
+          <el-button @click="handleReset">閲嶇疆</el-button>
+          <el-button type="success" @click="handleAdd">鏂板</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <div class="table-container">
+      <DynamicTable
+        ref="dynamicTableRef"
+        :data="tableData"
+        :dict-types="dictTypes"
+        :loading="loading"
+        :show-selection="true"
+        :show-actions="true"
+        :show-pagination="true"
+        :pagination="pagination"
+        height="calc(100vh - 280px)"
+        @selection-change="handleSelectionChange"
+        @edit="handleEdit"
+        @delete="handleDelete"
+        @select-change="handleSelectChange"
+        @input-change="handleInputChange"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+
+    <!-- 鏂板/缂栬緫瀵硅瘽妗� -->
+    <el-dialog
+      v-model="dialogVisible"
+      :title="dialogTitle"
+      width="600px"
+      append-to-body
+    >
+      <el-form
+        ref="formRef"
+        :model="form"
+        :rules="rules"
+        label-width="100px"
+      >
+        <el-form-item label="閮ㄩ棬" prop="department">
+          <el-input v-model="form.department" placeholder="璇疯緭鍏ラ儴闂�" />
+        </el-form-item>
+        <el-form-item label="濮撳悕" prop="name">
+          <el-input v-model="form.name" placeholder="璇疯緭鍏ュ鍚�" />
+        </el-form-item>
+        <el-form-item label="宸ュ彿" prop="employeeId">
+          <el-input v-model="form.employeeId" placeholder="璇疯緭鍏ュ伐鍙�" />
+        </el-form-item>
+        
+        <!-- 鍔ㄦ�佽〃鍗曢」锛氭牴鎹瓧鍏哥敓鎴� -->
+        <el-form-item
+          v-for="dictItem in dynamicFormItems"
+          :key="dictItem.value"
+          :label="dictItem.label"
+          :prop="dictItem.value"
+        >
+          <el-select
+            v-model="form[dictItem.value]"
+            placeholder="璇烽�夋嫨"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="option in dictItem.options"
+              :key="option.value"
+              :label="option.label"
+              :value="option.value"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary" @click="handleSubmit">纭畾</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed, onMounted } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import DynamicTable from '@/components/DynamicTable/index.vue'
+
+// 鍝嶅簲寮忔暟鎹�
+const loading = ref(false)
+const dialogVisible = ref(false)
+const dialogTitle = ref('')
+const editIndex = ref(-1)
+const selectedRows = ref([])
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+  department: '',
+  name: ''
+})
+
+// 琛ㄦ牸鏁版嵁
+const tableData = ref([
+  {
+    id: 1,
+    department: '鎶�鏈儴',
+    name: '寮犱笁',
+    employeeId: 'EMP001',
+    status: '1',
+    level: '2',
+    position: '1'
+  },
+  {
+    id: 2,
+    department: '浜轰簨閮�',
+    name: '鏉庡洓',
+    employeeId: 'EMP002',
+    status: '0',
+    level: '1',
+    position: '2'
+  },
+  {
+    id: 3,
+    department: '璐㈠姟閮�',
+    name: '鐜嬩簲',
+    employeeId: 'EMP003',
+    status: '1',
+    level: '3',
+    position: '1'
+  }
+])
+
+// 瀛楀吀绫诲瀷閰嶇疆
+const dictTypes = ref([
+  'sys_normal_disable', // 鐘舵�佸瓧鍏�
+  'sys_user_level',     // 绾у埆瀛楀吀
+  'sys_user_position'   // 鑱屼綅瀛楀吀
+])
+
+// 鍒嗛〉閰嶇疆
+const pagination = reactive({
+  current: 1,
+  size: 10,
+  total: 0
+})
+
+// 琛ㄥ崟鏁版嵁
+const form = reactive({
+  department: '',
+  name: '',
+  employeeId: '',
+  status: '',
+  level: '',
+  position: ''
+})
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const rules = {
+  department: [
+    { required: true, message: '璇疯緭鍏ラ儴闂�', trigger: 'blur' }
+  ],
+  name: [
+    { required: true, message: '璇疯緭鍏ュ鍚�', trigger: 'blur' }
+  ],
+  employeeId: [
+    { required: true, message: '璇疯緭鍏ュ伐鍙�', trigger: 'blur' }
+  ]
+}
+
+// 鍔ㄦ�佽〃鍗曢」
+const dynamicFormItems = computed(() => {
+  // 杩欓噷鍙互鏍规嵁瀛楀吀鏁版嵁鍔ㄦ�佺敓鎴愯〃鍗曢」
+  return [
+    {
+      label: '鐘舵��',
+      value: 'status',
+      options: [
+        { label: '鍚敤', value: '1' },
+        { label: '绂佺敤', value: '0' }
+      ]
+    },
+    {
+      label: '绾у埆',
+      value: 'level',
+      options: [
+        { label: '鍒濈骇', value: '1' },
+        { label: '涓骇', value: '2' },
+        { label: '楂樼骇', value: '3' }
+      ]
+    },
+    {
+      label: '鑱屼綅',
+      value: 'position',
+      options: [
+        { label: '鍛樺伐', value: '1' },
+        { label: '涓荤', value: '2' },
+        { label: '缁忕悊', value: '3' }
+      ]
+    }
+  ]
+})
+
+// 缁勪欢寮曠敤
+const dynamicTableRef = ref(null)
+const formRef = ref(null)
+
+// 浜嬩欢澶勭悊鍑芥暟
+const handleSearch = () => {
+  // 瀹炵幇鎼滅储閫昏緫
+  console.log('鎼滅储鏉′欢:', searchForm)
+  ElMessage.success('鎼滅储鍔熻兘寰呭疄鐜�')
+}
+
+const handleReset = () => {
+  searchForm.department = ''
+  searchForm.name = ''
+}
+
+const handleAdd = () => {
+  dialogTitle.value = '鏂板鍛樺伐'
+  editIndex.value = -1
+  resetForm()
+  dialogVisible.value = true
+}
+
+const handleEdit = (row, index) => {
+  dialogTitle.value = '缂栬緫鍛樺伐'
+  editIndex.value = index
+  Object.assign(form, row)
+  dialogVisible.value = true
+}
+
+const handleDelete = async (row, index) => {
+  try {
+    await ElMessageBox.confirm('纭畾瑕佸垹闄よ繖鏉¤褰曞悧锛�', '鎻愮ず', {
+      type: 'warning'
+    })
+    
+    tableData.value.splice(index, 1)
+    ElMessage.success('鍒犻櫎鎴愬姛')
+  } catch (error) {
+    // 鐢ㄦ埛鍙栨秷鍒犻櫎
+  }
+}
+
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection
+}
+
+const handleSelectChange = (row, prop, value) => {
+  console.log('閫夋嫨鍙樺寲:', row, prop, value)
+  // 鍙互鍦ㄨ繖閲屽鐞嗘暟鎹洿鏂伴�昏緫
+}
+
+const handleInputChange = (row, prop, value) => {
+  console.log('杈撳叆鍙樺寲:', row, prop, value)
+  // 鍙互鍦ㄨ繖閲屽鐞嗘暟鎹洿鏂伴�昏緫
+}
+
+const handleSizeChange = (size) => {
+  pagination.size = size
+  // 閲嶆柊鍔犺浇鏁版嵁
+}
+
+const handleCurrentChange = (current) => {
+  pagination.current = current
+  // 閲嶆柊鍔犺浇鏁版嵁
+}
+
+const handleSubmit = async () => {
+  try {
+    await formRef.value.validate()
+    
+    if (editIndex.value === -1) {
+      // 鏂板
+      const newRow = {
+        id: Date.now(),
+        ...form
+      }
+      tableData.value.push(newRow)
+      ElMessage.success('鏂板鎴愬姛')
+    } else {
+      // 缂栬緫
+      Object.assign(tableData.value[editIndex.value], form)
+      ElMessage.success('缂栬緫鎴愬姛')
+    }
+    
+    dialogVisible.value = false
+  } catch (error) {
+    console.error('琛ㄥ崟楠岃瘉澶辫触:', error)
+  }
+}
+
+const resetForm = () => {
+  Object.assign(form, {
+    department: '',
+    name: '',
+    employeeId: '',
+    status: '',
+    level: '',
+    position: ''
+  })
+  formRef.value?.resetFields()
+}
+
+// 缁勪欢鎸傝浇鏃跺垵濮嬪寲鏁版嵁
+onMounted(() => {
+  pagination.total = tableData.value.length
+})
+</script>
+
+<style scoped>
+.app-container {
+  padding: 20px;
+}
+
+.search-form {
+  margin-bottom: 20px;
+  padding: 20px;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+}
+
+.table-container {
+  background-color: #fff;
+  border-radius: 4px;
+  padding: 20px;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+</style>
diff --git a/src/views/example/SimpleExample.vue b/src/views/example/SimpleExample.vue
new file mode 100644
index 0000000..fb528eb
--- /dev/null
+++ b/src/views/example/SimpleExample.vue
@@ -0,0 +1,135 @@
+<template>
+  <div class="app-container">
+    <!-- 绠�鍗曠殑鎼滅储鍖哄煙 -->
+    <el-card class="search-card">
+      <el-form :inline="true">
+        <el-form-item label="閮ㄩ棬">
+          <el-input v-model="searchForm.department" placeholder="璇疯緭鍏ラ儴闂�" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">鎼滅储</el-button>
+          <el-button @click="handleReset">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 鍔ㄦ�佽〃鏍� -->
+    <el-card class="table-card">
+      <template #header>
+        <div class="card-header">
+          <span>鍛樺伐淇℃伅琛�</span>
+          <el-button type="primary" size="small" @click="handleAdd">鏂板鍛樺伐</el-button>
+        </div>
+      </template>
+      
+      <DynamicTable
+        :data="tableData"
+        :dict-types="dictTypes"
+        :loading="loading"
+        :show-selection="true"
+        :show-actions="true"
+        height="400px"
+        @selection-change="handleSelectionChange"
+        @edit="handleEdit"
+        @delete="handleDelete"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue'
+import { ElMessage } from 'element-plus'
+import DynamicTable from '@/components/DynamicTable/index.vue'
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+  department: ''
+})
+
+// 琛ㄦ牸鏁版嵁
+const tableData = ref([
+  {
+    id: 1,
+    department: '鎶�鏈儴',
+    name: '寮犱笁',
+    employeeId: 'EMP001',
+    sys_normal_disable: '1',  // 鐘舵��
+    sys_user_level: '2',      // 绾у埆
+    sys_user_position: '1'    // 鑱屼綅
+  },
+  {
+    id: 2,
+    department: '浜轰簨閮�',
+    name: '鏉庡洓',
+    employeeId: 'EMP002',
+    sys_normal_disable: '0',  // 鐘舵��
+    sys_user_level: '1',      // 绾у埆
+    sys_user_position: '2'    // 鑱屼綅
+  }
+])
+
+// 瀛楀吀绫诲瀷
+const dictTypes = ref([
+  'sys_normal_disable', // 鐘舵�侊細鍚敤/绂佺敤
+  'sys_user_level',     // 绾у埆锛氬垵绾�/涓骇/楂樼骇
+  'sys_user_position'   // 鑱屼綅锛氬憳宸�/涓荤/缁忕悊
+])
+
+// 鍔犺浇鐘舵��
+const loading = ref(false)
+
+// 浜嬩欢澶勭悊
+const handleSearch = () => {
+  loading.value = true
+  // 妯℃嫙鎼滅储
+  setTimeout(() => {
+    loading.value = false
+    ElMessage.success('鎼滅储瀹屾垚')
+  }, 1000)
+}
+
+const handleReset = () => {
+  searchForm.department = ''
+}
+
+const handleAdd = () => {
+  ElMessage.info('鏂板鍔熻兘寰呭疄鐜�')
+}
+
+const handleSelectionChange = (selection) => {
+  console.log('閫変腑鐨勮:', selection)
+}
+
+const handleEdit = (row, index) => {
+  ElMessage.info(`缂栬緫绗�${index + 1}琛屾暟鎹甡)
+}
+
+const handleDelete = (row, index) => {
+  ElMessage.warning(`鍒犻櫎绗�${index + 1}琛屾暟鎹甡)
+}
+</script>
+
+<style scoped>
+.app-container {
+  padding: 20px;
+}
+
+.search-card {
+  margin-bottom: 20px;
+}
+
+.table-card {
+  margin-bottom: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+:deep(.el-form-item) {
+  margin-bottom: 0;
+}
+</style>
diff --git a/src/views/fileManagement/bookshelf/detail.vue b/src/views/fileManagement/bookshelf/detail.vue
new file mode 100644
index 0000000..5d7d3ac
--- /dev/null
+++ b/src/views/fileManagement/bookshelf/detail.vue
@@ -0,0 +1,110 @@
+<template>
+  <div class="detail-container">
+    <div class="header">
+      <el-button @click="handleBack" type="primary" size="small">杩斿洖</el-button>
+      <h2>鍥句功璇︽儏</h2>
+    </div>
+    
+    <div class="content" v-loading="loading">
+      <el-card v-if="current">
+        <template #header>
+          <div class="card-header">
+            <span>鍩烘湰淇℃伅</span>
+          </div>
+        </template>
+        
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="鍥句功缂栧彿">{{ current.docNumber }}</el-descriptions-item>
+          <el-descriptions-item label="鍥句功鍚嶇О">{{ current.docName }}</el-descriptions-item>
+          <el-descriptions-item label="鍏ュ簱鏃堕棿">{{ current.createTime }}</el-descriptions-item>
+          <!-- <el-descriptions-item label="褰撳墠浣嶇疆">{{ current.currentLocation }}</el-descriptions-item> -->
+          <el-descriptions-item label="鐘舵��">{{ current.docStatus }}</el-descriptions-item>
+        </el-descriptions>
+        
+        <!-- <div class="additional-info" v-if="current.description">
+          <h4>鍥句功绠�浠�</h4>
+          <p>{{ current.description }}</p>
+        </div> -->
+      </el-card>
+      
+      <el-empty v-else description="鏆傛棤鏁版嵁" />
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+// 瀹氫箟props
+const props = defineProps({
+  current: {
+    type: Object,
+    required: true
+  }
+})
+
+// 瀹氫箟emits
+const emit = defineEmits(['hanldeBack'])
+
+// 鍝嶅簲寮忔暟鎹�
+const loading = ref(false)
+// const bookInfo = ref(null)
+
+// 鏂规硶
+const handleBack = () => {
+  emit('hanldeBack')
+}
+
+</script>
+
+<style scoped>
+.detail-container {
+  padding: 20px;
+  height: 100%;
+  background-color: #f5f5f5;
+}
+
+.header {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20px;
+  background-color: #fff;
+  padding: 15px 20px;
+  border-radius: 4px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.header h2 {
+  margin: 0 0 0 20px;
+  color: #333;
+}
+
+.content {
+  background-color: #fff;
+  border-radius: 4px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.card-header {
+  font-weight: bold;
+  color: #333;
+}
+
+.additional-info {
+  margin-top: 20px;
+  padding-top: 20px;
+  border-top: 1px solid #ebeef5;
+}
+
+.additional-info h4 {
+  margin: 0 0 10px 0;
+  color: #333;
+  font-size: 16px;
+}
+
+.additional-info p {
+  margin: 0;
+  color: #666;
+  line-height: 1.6;
+}
+</style>
diff --git a/src/views/fileManagement/bookshelf/index.vue b/src/views/fileManagement/bookshelf/index.vue
new file mode 100644
index 0000000..2689900
--- /dev/null
+++ b/src/views/fileManagement/bookshelf/index.vue
@@ -0,0 +1,688 @@
+<template>
+  <div class="sample">
+    <div class="main-content" v-if="!isDetail">
+      <div class="search">
+                 <div class="search_thing">
+           <div class="search_label">浠撳簱鍚嶇О锛�</div>
+           <div class="search_input">
+             <el-select v-model="entity.warehouseId" placeholder="閫夋嫨浠撳簱" size="small" @change="warehouseChange">
+               <el-option v-for="item in warehouse" :key="item.id" :label="item.label" :value="item.id">
+               </el-option>
+             </el-select>
+           </div>
+         </div>
+        <div class="search_thing">
+          <div class="search_label">璐ф灦锛�</div>
+          <div class="search_input">
+            <el-select v-model="entity.shelfId" placeholder="閫夋嫨璐ф灦" size="small" @change="handleShelf">
+              <el-option v-for="item in shelf" :key="item.id" :label="item.label" :value="item.id">
+              </el-option>
+            </el-select>
+          </div>
+        </div>
+          <!-- <div class="search_thing">
+           <el-button size="small" @click="handleShelf(entity.shelfId,'')">閲嶇疆</el-button>
+           <el-button size="small" type="primary" @click="handleShelf(entity.shelfId)">鏌ヨ</el-button>
+         </div> -->
+        <div class="btns">
+          <el-button size="small" style="color:#3A7BFA" @click="keepVisible=true">缁存姢</el-button>
+          <el-button size="small" style="color:#3A7BFA" @click="warehouseVisible=true,isEdit=false">娣诲姞浠撳簱</el-button>
+          <el-button size="small" style="color:#3A7BFA" @click="shelvesVisible=true,isEdit=false"
+            :disabled="entity.warehouseId==null">娣诲姞璐ф灦</el-button>
+        </div>
+      </div>
+      <div class="table" v-loading="tableLoading">
+        <table class="tables" style="table-layout:fixed;" v-if="tableList.length>0">
+          <tbody>
+            <tr v-for="(item,index) in tableList" :key="index">
+              <td v-for="(m,i) in item" :key="i" class="content">
+                <h4 v-if="m.row!=undefined">{{ m.row }} - {{ m.col }}</h4>
+                <ul>
+                  <el-tooltip
+                  effect="dark"
+                  placement="top"
+                  v-for="(n,j) in m.documentationDtoList"
+                  :key="j">
+                    <template #content><span>{{ n.docName }}</span>
+                      <span>&nbsp;[{{ n.docNumber }}]</span></template>
+                    <li class="green"
+                      @click="handelDetail(n)">
+                      <i></i>
+                      <span>{{ n.docName }}</span>
+                      <span>&nbsp;[{{ n.docNumber }}] <span :style="{ color: getStatusColor(n.docStatus) }">锛坽{ n.docStatus }}锛�</span></span>
+                    </li>
+                  </el-tooltip>
+                </ul>
+              </td>
+            </tr>
+            <tr>
+              <td v-for="(item,index) in rowList" :key="index" style="background: ghostwhite;height: 20px;">{{ item }}
+              </td>
+            </tr>
+          </tbody>
+        </table>
+        <span v-else style="color: rgb(144, 147, 153);display: inline-block;position: absolute;top: 60%;left: 50%;transform: translate(-50%,-50%);">鏆傛棤鏁版嵁</span>
+      </div>
+    </div>
+    <Detail v-else @hanldeBack="isDetail=false" :current="current" />
+    
+    <!-- 搴撲綅缁存姢瀵硅瘽妗� -->
+    <el-dialog v-model="keepVisible" title="搴撲綅缁存姢" width="350px" :append-to-body="true">
+                                                       <el-tree :data="warehouse" ref="tree" node-key="id"
+           highlight-current v-if="keepVisible"
+           empty-text="鏆傛棤鏁版嵁">
+        <template #default="{ node, data }">
+          <div class="custom-tree-node" style="width: 100%;">
+            <el-row style="width: 100%;display: flex;align-items: center;">
+              <el-col :span="14">
+                <span>
+                  <el-icon v-if="node.level < 2" class="folder-icon">
+                    <FolderOpened />
+                  </el-icon>
+                  <el-icon v-else class="file-icon">
+                    <Document />
+                  </el-icon>
+                  {{ data.label }}
+                </span>
+              </el-col>
+              <el-col :span="10" v-if="node.level<3">
+                <el-button type="link" size="small" :icon="Edit" @click.stop="handleEdit(data,node.level)">
+                </el-button>
+                <el-button type="danger" size="small" :icon="Delete" @click.stop="handleDelete(data,node.level)">
+                </el-button>
+              </el-col>
+            </el-row>
+          </div>
+        </template>
+      </el-tree>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="keepVisible = false">鍙� 娑�</el-button>
+          <el-button type="primary" @click="keepVisible = false" >纭� 瀹�</el-button>
+        </span>
+      </template>
+    </el-dialog>
+    
+    <!-- 浠撳簱鏂板/淇敼瀵硅瘽妗� -->
+    <el-dialog v-model="warehouseVisible" :title="isEdit?'浠撳簱淇敼':'浠撳簱鏂板'" width="350px">
+      <el-row>
+        <el-col class="search_thing" :span="24">
+          <div class="search_label"><span class="required-span">* </span>浠撳簱鍚嶇О锛�</div>
+          <div class="search_input">
+            <el-input v-model="name" size="small" @keyup.enter="confirmWarehouse"></el-input>
+          </div>
+        </el-col>
+      </el-row>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="warehouseVisible = false">鍙� 娑�</el-button>
+          <el-button type="primary" @click="confirmWarehouse" :loading="upLoadWarehouse">纭� 瀹�</el-button>
+        </span>
+      </template>
+    </el-dialog>
+    
+    <!-- 璐ф灦鏂板/淇敼瀵硅瘽妗� -->
+    <el-dialog v-model="shelvesVisible" :title="isEdit?'璐ф灦淇敼':'璐ф灦鏂板'" width="350px">
+      <el-row>
+        <el-col class="search_thing" :span="24">
+          <div class="search_label"><span class="required-span">* </span>璐ф灦鍚嶇О锛�</div>
+          <div class="search_input">
+            <el-input v-model="shelves.name" size="small"></el-input>
+          </div>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col class="search_thing" :span="24">
+          <div class="search_label"><span class="required-span">* </span>璐ф灦灞傛暟锛�</div>
+          <div class="search_input">
+            <el-input v-model="shelves.row" size="small"></el-input>
+          </div>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col class="search_thing" :span="24">
+          <div class="search_label"><span class="required-span">* </span>璐ф灦鍒楁暟锛�</div>
+          <div class="search_input">
+            <el-input v-model="shelves.col" size="small"></el-input>
+          </div>
+        </el-col>
+      </el-row>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="shelvesVisible = false">鍙� 娑�</el-button>
+          <el-button type="primary" @click="confirmShelves" :loading="upLoadShelves">纭� 瀹�</el-button>
+        </span>
+      </template>
+    </el-dialog>
+    
+    
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, watch } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Edit, Delete, FolderOpened, Document } from '@element-plus/icons-vue'
+import { getWarehouseList, addWarehouse, updateWarehouse, deleteWarehouse, getWarehouseStructure, addShelf, updateShelf, deleteShelf } from '@/api/fileManagement/bookshelf'
+import Detail from './detail.vue'
+
+// 鍝嶅簲寮忔暟鎹�
+const entity = reactive({
+  warehouseId: null,
+  shelfId: null
+})
+
+const warehouse = ref([])
+const shelf = ref([])
+const keepVisible = ref(false)
+const warehouseVisible = ref(false)
+const shelvesVisible = ref(false)
+const upLoadWarehouse = ref(false)
+const upLoadShelves = ref(false)
+const tableList = ref([])
+const rowList = ref([])
+const value = ref('')
+const name = ref('')
+const shelves = reactive({})
+const isEdit = ref(false)
+const isDetail = ref(false)
+const currentEdit = ref(null)
+const tableLoading = ref(false)
+const current = ref({})
+
+// 妯℃澘寮曠敤
+const organization = ref(null)
+
+// 鐩戝惉鍣�
+watch(isEdit, (newVal) => {
+  if (!newVal) {
+    Object.keys(shelves).forEach(key => delete shelves[key])
+  }
+})
+
+// 鏂规硶
+
+const selectList = async () => {
+  // 杩欓噷闇�瑕佹浛鎹负瀹為檯鐨凙PI璋冪敤
+  const res = await getWarehouseList()
+  warehouse.value = res.data
+  
+  if (warehouse.value.length == 0) {
+    entity.warehouseId = ''
+    entity.shelfId = ''
+    tableList.value = []
+  }
+  
+           
+  
+  if (!entity.warehouseId && warehouse.value.length > 0) {
+    entity.warehouseId = warehouse.value[0].id
+    warehouseChange(entity.warehouseId)
+    if (shelf.value.length > 0) {
+      entity.shelfId = shelf.value[0].id
+      handleShelf(entity.shelfId)
+    } else {
+      tableList.value = []
+    }
+  } else if (warehouse.value.length > 0) {
+    warehouseChange(entity.warehouseId)
+    if (shelf.value.length > 0) {
+      entity.shelfId = shelf.value[0].id
+      handleShelf(entity.shelfId)
+    } else {
+      tableList.value = []
+    }
+  }
+}
+
+const confirmWarehouse = () => {
+  if (!name.value) {
+    ElMessage.error('璇峰~鍐欎粨搴撳悕绉�')
+    return
+  }
+  upLoadWarehouse.value = true
+  
+  if (currentEdit.value && currentEdit.value.id) {
+    // 淇敼浠撳簱
+    // 杩欓噷闇�瑕佹浛鎹负瀹為檯鐨凙PI璋冪敤
+    updateWarehouse({
+      id: currentEdit.value.id,
+      warehouseName: name.value
+    }).then(res => {
+      upLoadWarehouse.value = false
+      warehouseVisible.value = false
+      currentEdit.value = null
+      ElMessage.success('淇敼鎴愬姛')
+      selectList()
+      name.value = ''
+      warehouseChange(entity.warehouseId)
+    })
+    
+  } else {
+    // 鏂板浠撳簱
+    // 杩欓噷闇�瑕佹浛鎹负瀹為檯鐨凙PI璋冪敤
+    addWarehouse({
+      warehouseName: name.value
+    }).then(res => {
+      upLoadWarehouse.value = false
+      warehouseVisible.value = false
+      ElMessage.success('娣诲姞鎴愬姛')
+      selectList()
+      name.value = ''
+      warehouseChange(entity.warehouseId)
+    })
+  }
+}
+
+const confirmShelves = () => {
+  if (!shelves.name) {
+    ElMessage.error('璇峰~鍐欒揣鏋跺悕绉�')
+    return
+  }
+  if (!shelves.row) {
+    ElMessage.error('璇峰~鍐欒揣鏋跺眰鏁�')
+    return
+  }
+  if (!shelves.col) {
+    ElMessage.error('璇峰~鍐欒揣鏋跺垪鏁�')
+    return
+  }
+  upLoadShelves.value = true
+  
+  if (currentEdit.value && currentEdit.value.id) {
+    // 淇敼
+    updateShelf({
+      id: currentEdit.value.id,
+      name: shelves.name,
+      row: Number(shelves.row),
+      col: Number(shelves.col),
+      warehouseId: entity.warehouseId
+    }).then(res => {
+      upLoadShelves.value = false
+      shelvesVisible.value = false
+      ElMessage.success('淇敼鎴愬姛')
+      selectList()
+      currentEdit.value = {}
+    }).catch(err => {
+      upLoadShelves.value = false
+      shelvesVisible.value = false
+      ElMessage.error('淇敼澶辫触')
+    })
+    
+  } else {
+    // 鏂板
+    // 杩欓噷闇�瑕佹浛鎹负瀹為檯鐨凙PI璋冪敤
+      addShelf({
+      name: shelves.name,
+      row: Number(shelves.row),
+      col: Number(shelves.col),
+      warehouseId: entity.warehouseId
+    }).then(res => {
+      upLoadShelves.value = false
+      shelvesVisible.value = false
+      ElMessage.success('娣诲姞鎴愬姛')
+      selectList()
+      Object.keys(shelves).forEach(key => delete shelves[key])
+    }).catch(err => {
+      upLoadShelves.value = false
+      shelvesVisible.value = false
+      ElMessage.error('娣诲姞澶辫触')
+    })
+  }
+  warehouseChange(entity.warehouseId)
+}
+
+
+
+const handleDelete = (row, level) => {
+  ElMessageBox.confirm('鏄惁鍒犻櫎褰撳墠鏁版嵁?', "璀﹀憡", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning"
+  }).then(() => {
+    if (level == 1) {
+      // 鍒犻櫎浠撳簱
+      deleteWarehouse([row.id]).then(res => {
+        ElMessage.success('鍒犻櫎鎴愬姛')
+        selectList()
+      })
+    } else {
+      // 鍒犻櫎璐ф灦
+      deleteShelf({
+        id: row.id
+      }).then(res => {
+        ElMessage.success('鍒犻櫎鎴愬姛')
+        selectList()
+      })
+    }
+    warehouseChange(entity.warehouseId)
+  }).catch(() => {})
+}
+
+const handleEdit = (data, level) => {
+  isEdit.value = true
+  if (level == 1) {
+    warehouseVisible.value = true
+    currentEdit.value = data
+    name.value = data.label
+  } else {
+    shelvesVisible.value = true
+    currentEdit.value = data
+    Object.assign(shelves, {
+      name: data.label,
+      row: data.row,
+      col: data.col,
+      warehouseId: data.warehouseId
+    })
+  }
+}
+
+const handelDetail = (row) => {
+  current.value = row
+  isDetail.value = true
+}
+
+// 鏍规嵁鏂囨。鐘舵�佽繑鍥炲搴旂殑棰滆壊
+const getStatusColor = (status) => {
+  if (status === '姝e父') {
+    return '#34BD66' // 缁胯壊
+  } else if (status === '鍊熷嚭') {
+    return '#F56C6C' // 绾㈣壊
+  }
+  return '#606266' // 榛樿棰滆壊
+}
+
+const warehouseChange = (val) => {
+tableList.value = []
+let map = warehouse.value.find(a => {
+  return a && a.id === val ? a : null
+})
+if (map && map.children) {
+  shelf.value = map.children
+  entity.shelfId = ''
+} else {
+  shelf.value = []
+}
+currentEdit.value = null
+}
+
+const handleShelf = async(e) => {
+  if (e) {
+    tableLoading.value = true
+    let data = []
+    const res = await getWarehouseStructure({warehouseGoodsShelvesId:e})
+    if(res.code == 200){
+      data = res.data.map(m=>{
+        m.books = m.documentationDtoList|[]
+        return m
+      })
+    }else{
+      ElMessage.error(res.message)
+    }
+    setTimeout(() => {
+      tableLoading.value = false
+      let set = new Set()
+      tableList.value = []
+      let arr = []
+      
+      if (data && data.length > 0) {
+        data.forEach(m => {
+          if (m && m.row && m.col) {
+            set.add(m.col)
+            if (arr.length > 0) {
+              if (arr.find(n => n.row == m.row)) {
+                arr.push(m)
+              } else {
+                tableList.value.push(arr)
+                arr = []
+                arr.push(m)
+              }
+            } else {
+              arr.push(m)
+            }
+          }
+        })
+        
+        if (arr.length > 0) {
+          tableList.value.push(arr)
+        }
+      }
+      
+      rowList.value = []
+      for (let i = 0; i < set.size; i++) {
+        rowList.value.push(`${i + 1} 鍒梎)
+      }
+      console.log(6666, tableList.value,rowList.value,data)
+    }, 1000)
+  }
+}
+
+
+
+// 鐢熷懡鍛ㄦ湡
+onMounted(() => {
+  selectList()
+})
+</script>
+
+<style scoped>
+  .main-content {
+    width: 100%;
+    height: 100%;
+    padding: 20px;
+    box-sizing: border-box;
+  }
+
+  .title {
+    height: 20px;
+    line-height: 20px;
+    margin-bottom: 20px;
+  }
+
+  .search {
+    background-color: #fff;
+    height: 80px;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 0 20px;
+    border-radius: 8px;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    margin-bottom: 20px;
+  }
+
+  .search_thing {
+    display: flex;
+    align-items: center;
+    height: 50px;
+    margin-right: 20px;
+  }
+
+  .search_label {
+    width: 90px;
+    font-size: 14px;
+    text-align: right;
+    color: #606266;
+    font-weight: 500;
+    margin-right: 10px;
+  }
+
+  .search_input {
+    width: 200px;
+  }
+
+  .table {
+    background-color: #fff;
+    width: 100%;
+    height: calc(100% - 100px);
+    padding: 20px;
+    overflow-y: auto;
+    border-radius: 8px;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  }
+
+  .el-form-item {
+    margin-bottom: 16px;
+  }
+
+  .btns {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+  }
+
+  .tables {
+    width: 100%;
+    height: 100%;
+    border-collapse: collapse;
+    border: 1px solid #e4e7ed;
+  }
+
+  .tables th {
+    font-size: 14px;
+    border: 1px solid #e4e7ed;
+    background-color: #fafafa;
+    padding: 8px;
+    font-weight: 500;
+  }
+
+  .tables td {
+    font-size: 12px;
+    text-align: center;
+    vertical-align: top;
+    border: 1px solid #e4e7ed;
+    padding: 8px;
+    box-sizing: border-box;
+    height: 120px;
+    background-color: #fff;
+  }
+
+  .tables ul {
+    list-style-type: none;
+  }
+
+  .tables ul li {
+    border-radius: 3px;
+    padding: 4px 10px;
+    box-sizing: border-box;
+    margin-bottom: 5px;
+    font-size: 12px;
+    display: flex;
+    align-items: center;
+    justify-content: start;
+    color: #333333;
+    cursor: pointer;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+  }
+
+  .tables h4 {
+    color: #999999;
+    font-size: 14px;
+    font-weight: 400;
+    padding: 6px 0;
+  }
+
+  .tables i {
+    display: inline-block;
+    width: 6px;
+    height: 6px;
+    border-radius: 50%;
+    margin-right: 6px;
+  }
+
+  li:hover {
+    background: rgba(58, 123, 250, 0.18);
+  }
+
+  li:hover i {
+    background: #3A7BFA;
+  }
+
+  li:hover .num {
+    color: #3A7BFA;
+  }
+
+  .green {
+    background: #E0F6EA;
+  }
+
+  .green i {
+    background: #34BD66;
+  }
+
+  .green .num {
+    color: #34BD66;
+  }
+
+  .el-dialog {
+    position: relative;
+  }
+
+  .shaoma {
+    display: flex;
+    align-items: center;
+    font-size: 14px;
+    color: #3A7BFA;
+    position: absolute;
+    top: 23px;
+    right: 54px;
+    cursor: pointer;
+  }
+
+  .folder-icon {
+    color: #409eff;
+    font-size: 16px;
+    margin-right: 6px;
+  }
+
+  .file-icon {
+    color: #67c23a;
+    font-size: 16px;
+    margin-right: 6px;
+  }
+
+  .node_i {
+    color: orange;
+    font-size: 18px;
+  }
+
+  .custom-tree-node .el-button {
+    opacity: 0;
+  }
+
+  .custom-tree-node:hover .el-button {
+    opacity: 1;
+  }
+
+  :deep(.el-loading-mask) {
+    z-index: 10;
+  }
+
+  .required-span {
+    color: #f56c6c;
+  }
+
+  .table-row {
+    border-bottom: 1px solid #e4e7ed;
+  }
+
+  .table-row:last-child {
+    border-bottom: none;
+  }
+
+  .column-header {
+    background-color: #fafafa !important;
+    font-weight: 500;
+    color: #606266;
+  }
+
+  .content {
+    transition: background-color 0.2s ease;
+  }
+
+  .content:hover {
+    background-color: #f5f7fa;
+  }
+</style>
diff --git a/src/views/fileManagement/borrow/index.vue b/src/views/fileManagement/borrow/index.vue
new file mode 100644
index 0000000..6875571
--- /dev/null
+++ b/src/views/fileManagement/borrow/index.vue
@@ -0,0 +1,582 @@
+<template>
+  <div class="app-container borrow-view">
+    <!-- 鏌ヨ鍖哄煙 -->
+    <div class="search-container">
+      <el-form :model="searchForm" :inline="true" class="search-form">
+                 <el-form-item label="鍊熼槄鐘舵�侊細">
+           <el-select v-model="searchForm.borrowStatus" placeholder="璇烽�夋嫨鍊熼槄鐘舵��" clearable style="width: 150px">
+             <el-option label="鍊熼槄" value="鍊熼槄" />
+             <el-option label="褰掕繕" value="褰掕繕" />
+           </el-select>
+         </el-form-item>
+        <el-form-item label="鍊熼槄浜猴細">
+          <el-input
+            v-model="searchForm.borrower"
+            placeholder="璇疯緭鍏ュ�熼槄浜�"
+            clearable
+            style="width: 200px"
+          />
+        </el-form-item>
+        <el-form-item label="鍊熼槄鏃ユ湡鑼冨洿锛�">
+          <el-date-picker
+            v-model="searchForm.dateRange"
+            type="daterange"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+            format="YYYY-MM-DD"
+            value-format="YYYY-MM-DD"
+            style="width: 300px"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">
+            <el-icon><Search /></el-icon>
+            鏌ヨ
+          </el-button>
+          <el-button @click="handleReset">
+            <el-icon><Refresh /></el-icon>
+            閲嶇疆
+          </el-button>
+        </el-form-item>
+        <el-form-item style="margin-left: auto;">
+          <el-button type="primary" @click="openBorrowDia('add')">
+            <el-icon><Plus /></el-icon>
+            鏂板鍊熼槄
+          </el-button>
+          <el-button
+            type="danger"
+            @click="handleBatchDelete"
+            :disabled="selectedRows.length === 0"
+          >
+            <el-icon><Delete /></el-icon>
+            鎵归噺鍒犻櫎 ({{ selectedRows.length }})
+          </el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <!-- 琛ㄦ牸鍖哄煙 -->
+    <div class="table-container">
+      <PIMTable
+        :table-data="borrowList"
+        :column="tableColumns"
+        :is-selection="true"
+        :border="true"
+        :table-loading="tableLoading"
+        :page="{
+          current: pagination.currentPage,
+          size: pagination.pageSize,
+          total: pagination.total,
+          layout: 'total, sizes, prev, pager, next, jumper'
+        }"
+        @selection-change="handleSelectionChange"
+        @pagination="handlePagination"
+      />
+    </div>
+
+    <!-- 鍊熼槄鏂板/缂栬緫瀵硅瘽妗� -->
+    <el-dialog
+      v-model="borrowDia"
+      :title="borrowOperationType === 'add' ? '鏂板鍊熼槄' : '缂栬緫鍊熼槄'"
+      width="800px"
+      @close="closeBorrowDia"
+      @keydown.enter.prevent
+    >
+      <el-form
+        :model="borrowForm"
+        label-width="140px"
+        :rules="borrowRules"
+        ref="borrowFormRef"
+      >
+        <el-row :gutter="20">
+          
+        </el-row>
+        
+                 <el-row :gutter="20">
+           <el-col :span="12">
+             <el-form-item label="鍊熼槄浜猴細" prop="borrower">
+               <el-input v-model="borrowForm.borrower" placeholder="璇疯緭鍏ュ�熼槄浜�" />
+             </el-form-item>
+           </el-col>
+           <el-col :span="12">
+             <el-form-item label="鍊熼槄涔︾睄锛�" prop="documentationId">
+               <el-select v-model="borrowForm.documentationId" placeholder="璇烽�夋嫨鍊熼槄涔︾睄" style="width: 100%">
+                 <el-option 
+                   v-for="item in documentList" 
+                   :key="item.id" 
+                   :label="item.docName || item.name" 
+                   :value="item.id"
+                 />
+               </el-select>
+             </el-form-item>
+           </el-col>
+         </el-row>
+        
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鍊熼槄鏃ユ湡锛�" prop="borrowDate">
+              <el-date-picker
+                v-model="borrowForm.borrowDate"
+                type="date"
+                placeholder="閫夋嫨鍊熼槄鏃ユ湡"
+                style="width: 100%"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="搴斿綊杩樻棩鏈燂細" prop="dueReturnDate">
+              <el-date-picker
+                v-model="borrowForm.dueReturnDate"
+                type="date"
+                placeholder="閫夋嫨搴斿綊杩樻棩鏈�"
+                style="width: 100%"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        
+                 <el-row :gutter="20">
+           <el-col :span="24">
+             <el-form-item label="鍊熼槄鐩殑锛�" prop="borrowPurpose">
+               <el-input v-model="borrowForm.borrowPurpose" placeholder="璇疯緭鍏ュ�熼槄鐩殑" />
+             </el-form-item>
+           </el-col>
+         </el-row>
+        
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞锛�" prop="remark">
+              <el-input
+                v-model="borrowForm.remark"
+                type="textarea"
+                :rows="3"
+                placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitBorrowForm">纭</el-button>
+          <el-button @click="closeBorrowDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+import { ElMessageBox, ElMessage } from "element-plus";
+import { Search, Refresh, Plus, Delete } from '@element-plus/icons-vue';
+import PIMTable from '@/components/PIMTable/PIMTable.vue';
+import { getBorrowList, addBorrow, updateBorrow, deleteBorrow, getDocumentList } from '@/api/fileManagement/borrow';
+
+const { proxy } = getCurrentInstance();
+
+// 鍝嶅簲寮忔暟鎹�
+const borrowDia = ref(false);
+const borrowOperationType = ref("");
+const tableLoading = ref(false);
+const borrowList = ref([]);
+const selectedRows = ref([]);
+const documentList = ref([]); // 鏂囨。鍒楄〃锛岀敤浜庡�熼槄涔︾睄閫夋嫨
+
+// 鍒嗛〉鐩稿叧
+const pagination = reactive({
+  currentPage: 1,
+  pageSize: 10,
+  total: 0,
+});
+
+// 鏌ヨ琛ㄥ崟
+const searchForm = reactive({
+  documentationId: "",
+  borrowStatus: "",
+  borrower: "",
+  returnerId: "",
+  dateRange: []
+});
+
+// 鍊熼槄琛ㄥ崟
+const borrowForm = reactive({
+  id: "",
+  documentationId: "",
+  borrower: "",
+  returnerId: "",
+  borrowPurpose: "",
+  borrowDate: "",
+  dueReturnDate: "",
+  returnDate: "",
+  borrowStatus: "",
+  remark: ""
+});
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const borrowRules = reactive({
+  documentationId: [{ required: true, message: "璇烽�夋嫨鍊熼槄涔︾睄", trigger: "change" }],
+  borrower: [{ required: true, message: "璇疯緭鍏ュ�熼槄浜�", trigger: "blur" }],
+  borrowPurpose: [{ required: true, message: "璇疯緭鍏ュ�熼槄鐩殑", trigger: "blur" }],
+  borrowDate: [{ required: true, message: "璇烽�夋嫨鍊熼槄鏃ユ湡", trigger: "change" }],
+  dueReturnDate: [{ required: true, message: "璇烽�夋嫨搴斿綊杩樻棩鏈�", trigger: "change" }],
+  borrowStatus: [{ required: true, message: "璇烽�夋嫨鍊熼槄鐘舵��", trigger: "change" }]
+});
+
+// 琛ㄦ牸鍒楅厤缃�
+const tableColumns = ref([
+  { 
+    label: '鏂囨。鍚嶇О', 
+    prop: 'docName',
+    width: '200',
+  },
+  { label: '鍊熼槄浜�', prop: 'borrower' },
+  { label: '鍊熼槄鐩殑', prop: 'borrowPurpose' },
+  { label: '鍊熼槄鏃ユ湡', prop: 'borrowDate' },
+  { label: '搴斿綊杩樻棩鏈�', prop: 'dueReturnDate' },
+  { 
+    label: '鍊熼槄鐘舵��', 
+    prop: 'borrowStatus', 
+    width: '100',
+    dataType: 'tag',
+    formatData: (params) => {
+      if (params === null || params === undefined || params === '') return '-';
+      return params;
+    },
+         formatType: (params) => {
+       if (params === '褰掕繕') return 'success';
+       if (params === '鍊熼槄') return 'warning';
+       return 'info';
+     }
+  },
+  { label: '澶囨敞', prop: 'remark', width: '150' },
+  { 
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: 'right',
+    width: '150',
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          openBorrowDia('edit', row)
+        },
+      },
+      {
+        name: "鍒犻櫎",
+        type: "text",
+        clickFun: (row) => {
+          handleDelete(row)
+        },
+      },
+    ],
+  }
+]);
+
+// 鍒濆鍖栨暟鎹�
+const initData = async () => {
+  await Promise.all([
+    loadDocumentList(),
+    loadBorrowList()
+  ]);
+};
+
+// 鍔犺浇鏂囨。鍒楄〃
+const loadDocumentList = async () => {
+  try {
+    const res = await getDocumentList();
+    if (res.code === 200) {
+      documentList.value = res.data || [];
+    } else {
+      ElMessage.error(res.msg || "鑾峰彇鏂囨。鍒楄〃澶辫触");
+      documentList.value = [];
+    }
+  } catch (error) {
+    ElMessage.error("鑾峰彇鏂囨。鍒楄〃澶辫触锛岃閲嶈瘯");
+    documentList.value = [];
+  }
+};
+
+// 鍔犺浇鍊熼槄鍒楄〃
+const loadBorrowList = async () => {
+  try {
+    tableLoading.value = true;
+    
+    // 鏋勫缓鏌ヨ鍙傛暟
+    const query = {
+      page: pagination.currentPage,
+      size: pagination.pageSize,
+      documentationId: searchForm.documentationId || undefined,
+      borrowStatus: searchForm.borrowStatus || undefined,
+      borrower: searchForm.borrower || undefined,
+      returnerId: searchForm.returnerId || undefined,
+      entryDateStart: searchForm.dateRange && searchForm.dateRange.length > 0 ? searchForm.dateRange[0] : undefined,
+      entryDateEnd: searchForm.dateRange && searchForm.dateRange.length > 1 ? searchForm.dateRange[1] : undefined
+    };
+    
+    // 绉婚櫎undefined鐨勫弬鏁�
+    Object.keys(query).forEach(key => {
+      if (query[key] === undefined) {
+        delete query[key];
+      }
+    });
+    
+    const res = await getBorrowList(query);
+    if (res.code === 200) {
+      borrowList.value = res.data.records || [];
+      pagination.total = res.data.total || 0;
+    } else {
+      ElMessage.error(res.msg || "鑾峰彇鍊熼槄鍒楄〃澶辫触");
+      borrowList.value = [];
+      pagination.total = 0;
+    }
+    
+    // 閲嶇疆閫夋嫨鐘舵��
+    selectedRows.value = [];
+  } catch (error) {
+    ElMessage.error("鑾峰彇鍊熼槄鍒楄〃澶辫触锛岃閲嶈瘯");
+    borrowList.value = [];
+    pagination.total = 0;
+  } finally {
+    tableLoading.value = false;
+  }
+};
+
+// 鏌ヨ
+const handleSearch = () => {
+  pagination.currentPage = 1;
+  loadBorrowList();
+};
+
+// 閲嶇疆鏌ヨ
+const handleReset = () => {
+  searchForm.documentationId = "";
+  searchForm.borrowStatus = "";
+  searchForm.borrower = "";
+  searchForm.returnerId = "";
+  searchForm.dateRange = [];
+  pagination.currentPage = 1;
+  loadBorrowList();
+  ElMessage.success("鏌ヨ鏉′欢宸查噸缃�");
+};
+
+// 鎵撳紑鍊熼槄寮规
+const openBorrowDia = async (type, data) => {
+  // 鍏堝埛鏂版枃妗e垪琛�
+  await loadDocumentList();
+  
+  borrowOperationType.value = type;
+  borrowDia.value = true;
+  
+  if (type === "edit") {
+    // 缂栬緫妯″紡锛屽姞杞界幇鏈夋暟鎹�
+    Object.assign(borrowForm, data);
+  } else {
+    // 鏂板妯″紡锛屾竻绌鸿〃鍗�
+    Object.keys(borrowForm).forEach(key => {
+      borrowForm[key] = "";
+    });
+         // 璁剧疆榛樿鐘舵��
+     borrowForm.borrowStatus = "鍊熼槄";
+    // 璁剧疆褰撳墠鏃ユ湡涓哄�熼槄鏃ユ湡
+    borrowForm.borrowDate = new Date().toISOString().split('T')[0];
+  }
+};
+
+// 鍏抽棴鍊熼槄寮规
+const closeBorrowDia = () => {
+  proxy.$refs.borrowFormRef.resetFields();
+  borrowDia.value = false;
+};
+
+// 鎻愪氦鍊熼槄琛ㄥ崟
+const submitBorrowForm = () => {
+  proxy.$refs.borrowFormRef.validate(async (valid) => {
+    if (valid) {
+      try {
+        if (borrowOperationType.value === "edit") {
+          // 缂栬緫妯″紡锛屾洿鏂扮幇鏈夋暟鎹�
+          const res = await updateBorrow({
+            borrower:borrowForm.borrower,
+            id: borrowForm.id,
+            borrowPurpose: borrowForm.borrowPurpose,
+            borrowDate: borrowForm.borrowDate,
+            dueReturnDate: borrowForm.dueReturnDate,
+            returnDate: borrowForm.returnDate,
+            remark: borrowForm.remark
+          });
+          
+          if (res.code === 200) {
+            ElMessage.success("缂栬緫鎴愬姛");
+            await loadBorrowList();
+            closeBorrowDia();
+          } else {
+            ElMessage.error(res.msg || "缂栬緫澶辫触");
+          }
+        } else {
+          // 鏂板妯″紡锛屾坊鍔犳柊鏁版嵁
+          const res = await addBorrow({
+            documentationId: borrowForm.documentationId,
+            borrower: borrowForm.borrower,
+            returnerId: borrowForm.returnerId,
+            borrowPurpose: borrowForm.borrowPurpose,
+            borrowDate: borrowForm.borrowDate,
+            dueReturnDate: borrowForm.dueReturnDate,
+            returnDate: borrowForm.returnDate,
+            borrowStatus: borrowForm.borrowStatus,
+            remark: borrowForm.remark
+          });
+          
+          if (res.code === 200) {
+            ElMessage.success("鏂板鎴愬姛");
+            await loadBorrowList();
+            closeBorrowDia();
+          } else {
+            ElMessage.error(res.msg || "鏂板澶辫触");
+          }
+        }
+      } catch (error) {
+        ElMessage.error("鎿嶄綔澶辫触锛岃閲嶈瘯");
+      }
+    }
+  });
+};
+
+// 鍒犻櫎鍊熼槄璁板綍
+const handleDelete = (row) => {
+  ElMessageBox.confirm(
+    `纭畾瑕佸垹闄よ繖鏉″�熼槄璁板綍鍚楋紵`,
+    "鍒犻櫎鎻愮ず",
+    {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }
+  ).then(async () => {
+    try {
+      const res = await deleteBorrow([row.id]);
+      if (res.code === 200) {
+        ElMessage.success("鍒犻櫎鎴愬姛");
+        await loadBorrowList();
+      } else {
+        ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+      }
+    } catch (error) {
+      ElMessage.error("鍒犻櫎澶辫触锛岃閲嶈瘯");
+    }
+  }).catch(() => {
+    ElMessage.info("宸插彇娑堝垹闄�");
+  });
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+  if (selectedRows.value.length === 0) {
+    ElMessage.warning("璇烽�夋嫨瑕佸垹闄ょ殑璁板綍");
+    return;
+  }
+  
+  ElMessageBox.confirm(
+    `纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.value.length} 鏉″�熼槄璁板綍鍚楋紵`,
+    "鎵归噺鍒犻櫎鎻愮ず",
+    {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }
+  ).then(async () => {
+    try {
+      const selectedIds = selectedRows.value.map(row => row.id);
+      const res = await deleteBorrow(selectedIds);
+      if (res.code === 200) {
+        ElMessage.success("鎵归噺鍒犻櫎鎴愬姛");
+        await loadBorrowList();
+      } else {
+        ElMessage.error(res.msg || "鎵归噺鍒犻櫎澶辫触");
+      }
+    } catch (error) {
+      ElMessage.error("鎵归噺鍒犻櫎澶辫触锛岃閲嶈瘯");
+    }
+  }).catch(() => {
+    ElMessage.info("宸插彇娑堝垹闄�");
+  });
+};
+
+// 閫夋嫨鍙樺寲浜嬩欢
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+
+// 澶勭悊鍒嗛〉鍙樺寲
+const handlePagination = (current, size) => {
+  pagination.currentPage = current;
+  pagination.pageSize = size;
+  loadBorrowList();
+};
+
+// 鐢熷懡鍛ㄦ湡
+onMounted(() => {
+  initData();
+});
+</script>
+
+<style scoped>
+.borrow-view {
+  padding: 20px;
+}
+
+.search-container {
+  background: #ffffff;
+  padding: 20px;
+  border-radius: 8px;
+  margin-bottom: 20px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.search-form {
+  margin: 0;
+}
+
+.table-container {
+  background: #ffffff;
+  border-radius: 8px;
+  overflow: hidden;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.empty-data {
+  text-align: center;
+  color: #909399;
+  padding: 40px;
+  font-size: 14px;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+
+:deep(.el-form-item__label) {
+  font-weight: 500;
+  color: #303133;
+}
+
+:deep(.el-input__wrapper) {
+  box-shadow: 0 0 0 1px #dcdfe6 inset;
+}
+
+:deep(.el-input__wrapper:hover) {
+  box-shadow: 0 0 0 1px #c0c4cc inset;
+}
+
+:deep(.el-input__wrapper.is-focus) {
+  box-shadow: 0 0 0 1px #409eff inset;
+}
+</style>
diff --git a/src/views/fileManagement/document/attachmentManager.vue b/src/views/fileManagement/document/attachmentManager.vue
new file mode 100644
index 0000000..a4e1d43
--- /dev/null
+++ b/src/views/fileManagement/document/attachmentManager.vue
@@ -0,0 +1,426 @@
+<template>
+  <el-dialog v-model="dialogVisible" title="闄勪欢绠$悊" width="60%" :before-close="handleClose">
+    <div class="attachment-manager">
+      <!-- 涓婁紶鍖哄煙 -->
+      <div class="upload-section">
+        <el-upload 
+          ref="uploadRef"
+          :action="uploadUrl" 
+          :headers="uploadHeaders"
+          :before-upload="handleBeforeUpload"
+          :on-success="handleUploadSuccess"
+          :on-error="handleUploadError"
+          :on-remove="handleRemove"
+          :file-list="fileList"
+          multiple
+          :limit="10"
+          :show-file-list="false"
+          :data="{documentId: currentDocumentId}"
+          accept=".doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt,.xml,.jpg,.jpeg,.png,.gif,.bmp,.rar,.zip,.7z"
+        >
+          <el-button type="primary" :icon="Plus">涓婁紶闄勪欢</el-button>
+          <template #tip>
+            <div class="el-upload__tip">
+              鏀寔鏍煎紡锛歞oc锛宒ocx锛寈ls锛寈lsx锛宲pt锛宲ptx锛宲df锛宼xt锛寈ml锛宩pg锛宩peg锛宲ng锛実if锛宐mp锛宺ar锛寊ip锛�7z
+              <br>鍗曚釜鏂囦欢澶у皬涓嶈秴杩�50MB
+            </div>
+          </template>
+        </el-upload>
+      </div>
+
+      <!-- 闄勪欢鍒楄〃 -->
+      <div class="attachment-list">
+        <el-table :data="fileList" border height="400px" v-loading="loading">
+          <el-table-column label="搴忓彿" type="index" width="60" align="center" />
+          <el-table-column label="闄勪欢鍚嶇О" prop="name" min-width="200" show-overflow-tooltip />
+          <el-table-column label="鏂囦欢澶у皬" prop="size" width="100" align="center">
+            <template #default="scope">
+              {{ formatFileSize(scope.row.size) }}
+            </template>
+          </el-table-column>
+          <el-table-column label="涓婁紶鏃堕棿" prop="uploadTime" width="160" align="center">
+            <template #default="scope">
+              {{ formatDate(scope.row.uploadTime) }}
+            </template>
+          </el-table-column>
+          <el-table-column label="鐘舵��" prop="status" width="80" align="center">
+            <template #default="scope">
+              <el-tag :type="scope.row.status === 'success' ? 'success' : 'danger'" size="small">
+                {{ scope.row.status === 'success' ? '鎴愬姛' : '澶辫触' }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column fixed="right" label="鎿嶄綔" width="200" align="center">
+            <template #default="scope">
+              <el-button link type="primary" size="small" @click="previewFile(scope.row)">
+                棰勮
+              </el-button>
+              <el-button link type="primary" size="small" @click="downloadFile(scope.row)">
+                涓嬭浇
+              </el-button>
+              <el-button link type="danger" size="small" @click="removeFile(scope.row)">
+                鍒犻櫎
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+
+    <!-- 鏂囦欢棰勮缁勪欢 -->
+    <filePreview ref="filePreviewRef" />
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Plus } from '@element-plus/icons-vue'
+import { getToken } from "@/utils/auth"
+import { addDocumentationFile, getDocumentationFileList, deleteDocumentationFile } from '@/api/fileManagement/document'
+import filePreview from '@/components/filePreview/index.vue'
+
+const props = defineProps({
+  // documentId 閫氳繃 open 浜嬩欢浼犲叆锛屼笉闇�瑕佷綔涓� props
+})
+
+const emit = defineEmits(['update:attachments'])
+
+const dialogVisible = ref(false)
+const loading = ref(false)
+const fileList = ref([])
+const uploadRef = ref()
+const filePreviewRef = ref()
+const currentDocumentId = ref('') // 鍐呴儴绠$悊褰撳墠鏂囨。ID
+
+// 涓婁紶閰嶇疆
+const uploadUrl = import.meta.env.VITE_APP_BASE_API + "/file/upload"
+const uploadHeaders = computed(() => ({
+  Authorization: "Bearer " + getToken()
+}))
+
+// 鎵撳紑寮规
+const open = (attachments = [], documentId = '') => {
+  dialogVisible.value = true
+  currentDocumentId.value = documentId // 璁剧疆褰撳墠鏂囨。ID
+  // 濡傛灉鏈夋枃妗D锛屽垯鍔犺浇闄勪欢鍒楄〃
+  if (documentId) {
+    loadAttachmentList(documentId)
+  } else {
+    fileList.value = attachments || []
+    // total.value = fileList.value.length // Removed total.value
+  }
+  // currentPage.value = 1 // Removed currentPage.value
+}
+
+// 鍔犺浇闄勪欢鍒楄〃
+const loadAttachmentList = async (documentId) => {
+  try {
+    loading.value = true
+    const params = {
+      page: 1, // Always load from page 1
+      size: 1000, // Load all for now
+      documentationId: documentId
+    }
+    
+    const res = await getDocumentationFileList(params)
+    if (res.code === 200) {
+      const records = res.data
+      
+      // 杞崲鏁版嵁鏍煎紡
+      fileList.value = records.map(item => ({
+        id: item.id,
+        name: item.name,
+        size: item.fileSize,
+        url: item.url,
+        uploadTime: item.createTime || item.uploadTime,
+        status: 'success',
+        uid: item.id
+      }))
+      
+      // total.value = totalCount // Removed total.value
+    } else {
+      ElMessage.error(res.msg || '鑾峰彇闄勪欢鍒楄〃澶辫触')
+      fileList.value = []
+      // total.value = 0 // Removed total.value
+    }
+  } catch (error) {
+    console.error('鑾峰彇闄勪欢鍒楄〃澶辫触:', error)
+    ElMessage.error('鑾峰彇闄勪欢鍒楄〃澶辫触')
+    fileList.value = []
+    // total.value = 0 // Removed total.value
+  } finally {
+    loading.value = false
+  }
+}
+
+// 鍏抽棴寮规
+const handleClose = () => {
+  dialogVisible.value = false
+  emit('update:attachments', fileList.value)
+}
+
+// 鏂囦欢涓婁紶鍓嶆牎楠�
+const handleBeforeUpload = (file) => {
+  // 妫�鏌ユ枃浠跺ぇ灏忥紙50MB锛�
+  const isLt50M = file.size / 1024 / 1024 < 50
+  if (!isLt50M) {
+    ElMessage.error('鏂囦欢澶у皬涓嶈兘瓒呰繃50MB!')
+    return false
+  }
+  
+  // 妫�鏌ユ枃浠剁被鍨�
+  const allowedTypes = [
+    'application/msword',
+    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+    'application/vnd.ms-excel',
+    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+    'application/vnd.ms-powerpoint',
+    'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+    'application/pdf',
+    'text/plain',
+    'text/xml',
+    'image/jpeg',
+    'image/png',
+    'image/gif',
+    'image/bmp',
+    'application/x-rar-compressed',
+    'application/zip',
+    'application/x-7z-compressed'
+  ]
+  
+  if (!allowedTypes.includes(file.type)) {
+    ElMessage.error('涓嶆敮鎸佺殑鏂囦欢绫诲瀷!')
+    return false
+  }
+  
+  return true
+}
+
+// 鏂囦欢涓婁紶鎴愬姛
+const handleUploadSuccess = (response, file, fileList) => {
+  console.log('鏂囦欢涓婁紶鎴愬姛鍝嶅簲:', response);
+  console.log('鏂囦欢淇℃伅:', file);
+  
+  if (response.code === 200) {
+    // 鏋勫缓闄勪欢鏁版嵁 - 纭繚姝g‘鑾峰彇URL
+    const attachmentData = {
+      name: file.name,
+      url: response.data.url || response.data.path || response.data.tempPath || file.url,
+      fileSize: file.size,
+      documentationId: currentDocumentId.value
+    };
+    
+    console.log('鏋勫缓鐨勯檮浠舵暟鎹�:', attachmentData);
+    
+    // 璋冪敤淇濆瓨闄勪欢鎺ュ彛
+    saveAttachment(attachmentData, file, fileList);
+  } else {
+    ElMessage.error(response.msg || '鏂囦欢涓婁紶澶辫触')
+  }
+}
+
+// 淇濆瓨闄勪欢淇℃伅
+const saveAttachment = async (attachmentData, file, fileList) => {
+  try {
+    console.log('寮�濮嬩繚瀛橀檮浠讹紝鏁版嵁:', attachmentData);
+    
+    // 纭繚URL瀛楁瀛樺湪涓旀湁鏁�
+    if (!attachmentData.url) {
+      console.error('闄勪欢URL涓虹┖锛屾棤娉曚繚瀛�');
+      ElMessage.error('鏂囦欢URL鑾峰彇澶辫触锛屾棤娉曚繚瀛橀檮浠�');
+      return;
+    }
+    
+    const res = await addDocumentationFile(attachmentData);
+    console.log('淇濆瓨闄勪欢鎺ュ彛鍝嶅簲:', res);
+    
+    if (res.code === 200) {
+      const newFile = {
+        id: res.data.id || Date.now(),
+        name: attachmentData.name,
+        size: attachmentData.fileSize,
+        url: attachmentData.url,
+        uploadTime: new Date().toISOString(),
+        status: 'success',
+        uid: file.uid
+      }
+      
+      console.log('鍒涘缓鐨勬柊鏂囦欢瀵硅薄:', newFile);
+      fileList.push(newFile)
+      ElMessage.success('鏂囦欢涓婁紶骞朵繚瀛樻垚鍔�')
+      
+      // 淇濆瓨鎴愬姛鍚庡埛鏂伴檮浠跺垪琛�
+      if (currentDocumentId.value) {
+        await loadAttachmentList(currentDocumentId.value);
+      }
+    } else {
+      ElMessage.error(res.msg || '淇濆瓨闄勪欢淇℃伅澶辫触')
+      // 淇濆瓨澶辫触鏃剁Щ闄ゆ枃浠�
+      const index = fileList.findIndex(item => item.uid === file.uid)
+      if (index > -1) {
+        fileList.splice(index, 1)
+      }
+    }
+  } catch (error) {
+    console.error('淇濆瓨闄勪欢澶辫触:', error)
+    ElMessage.error('淇濆瓨闄勪欢淇℃伅澶辫触')
+    // 淇濆瓨澶辫触鏃剁Щ闄ゆ枃浠�
+    const index = fileList.findIndex(item => item.uid === file.uid)
+    if (index > -1) {
+      fileList.splice(index, 1)
+    }
+  }
+}
+
+// 鏂囦欢涓婁紶澶辫触
+const handleUploadError = (error, file, fileList) => {
+  console.error('鏂囦欢涓婁紶澶辫触:', error);
+  console.error('澶辫触鐨勬枃浠�:', file);
+  console.error('褰撳墠鏂囦欢鍒楄〃:', fileList);
+  
+  ElMessage.error('鏂囦欢涓婁紶澶辫触锛岃妫�鏌ョ綉缁滆繛鎺ユ垨鏂囦欢鏍煎紡')
+}
+
+// 绉婚櫎鏂囦欢
+const handleRemove = (file, fileList) => {
+  const index = fileList.findIndex(item => item.uid === file.uid)
+  if (index > -1) {
+    fileList.splice(index, 1)
+    // total.value = fileList.length // Removed total.value
+  }
+}
+
+// 鍒犻櫎鏂囦欢
+const removeFile = (file) => {
+  ElMessageBox.confirm(`纭畾瑕佸垹闄ゆ枃浠� "${file.name}" 鍚楋紵`, '鍒犻櫎纭', {
+    confirmButtonText: '纭畾',
+    cancelButtonText: '鍙栨秷',
+    type: 'warning'
+  }).then(async () => {
+    try {
+      // 璋冪敤鍒犻櫎鎺ュ彛
+      const res = await deleteDocumentationFile([file.id]);
+      if (res.code === 200) {
+        // 浠庢湰鍦板垪琛ㄤ腑绉婚櫎
+        const index = fileList.value.findIndex(item => item.id === file.id);
+        if (index > -1) {
+          fileList.value.splice(index, 1);
+        }
+        ElMessage.success('鍒犻櫎鎴愬姛');
+        
+        // 濡傛灉鏈夋枃妗D锛屽埛鏂伴檮浠跺垪琛�
+        if (currentDocumentId.value) {
+          await loadAttachmentList(currentDocumentId.value);
+        }
+      } else {
+        ElMessage.error(res.msg || '鍒犻櫎澶辫触');
+      }
+    } catch (error) {
+      console.error('鍒犻櫎闄勪欢澶辫触:', error);
+      ElMessage.error('鍒犻櫎闄勪欢澶辫触');
+    }
+  }).catch(() => {
+    // 鍙栨秷鍒犻櫎
+  })
+}
+
+// 棰勮鏂囦欢
+const previewFile = (file) => {
+  if (file.url) {
+    filePreviewRef.value.open(file.url)
+  } else {
+    ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曢瑙�')
+  }
+}
+
+// 涓嬭浇鏂囦欢
+const downloadFile = (file) => {
+  if (file.url) {
+    // 鍒涘缓涓嬭浇閾炬帴
+    const link = document.createElement('a')
+    link.href = file.url
+    link.download = file.name
+    document.body.appendChild(link)
+    link.click()
+    document.body.removeChild(link)
+    ElMessage.success('寮�濮嬩笅杞芥枃浠�')
+  } else {
+    ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曚笅杞�')
+  }
+}
+
+// 鏍煎紡鍖栨枃浠跺ぇ灏�
+const formatFileSize = (bytes) => {
+  if (bytes === 0) return '0 B'
+  const k = 1024
+  const sizes = ['B', 'KB', 'MB', 'GB']
+  const i = Math.floor(Math.log(bytes) / Math.log(k))
+  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
+}
+
+// 鏍煎紡鍖栨棩鏈�
+const formatDate = (dateString) => {
+  if (!dateString) return ''
+  const date = new Date(dateString)
+  return date.toLocaleString('zh-CN', {
+    year: 'numeric',
+    month: '2-digit',
+    day: '2-digit',
+    hour: '2-digit',
+    minute: '2-digit'
+  })
+}
+
+// 娴嬭瘯鏂囦欢涓婁紶
+const testUpload = () => {
+  console.log('褰撳墠鏂囨。ID:', currentDocumentId.value);
+  console.log('涓婁紶URL:', uploadUrl);
+  console.log('涓婁紶Headers:', uploadHeaders.value);
+}
+
+// 鏆撮湶鏂规硶
+defineExpose({
+  open,
+  loadAttachmentList,
+  testUpload
+})
+</script>
+
+<style scoped>
+.attachment-manager {
+  padding: 20px;
+}
+
+.upload-section {
+  margin-bottom: 20px;
+  padding: 20px;
+  background-color: #f8f9fa;
+  border-radius: 8px;
+  border: 2px dashed #d9d9d9;
+}
+
+.upload-section:hover {
+  border-color: #409eff;
+}
+
+.attachment-list {
+  margin-bottom: 20px;
+}
+
+.el-upload__tip {
+  margin-top: 10px;
+  color: #666;
+  font-size: 12px;
+  line-height: 1.5;
+}
+
+:deep(.el-upload) {
+  width: 100%;
+}
+
+:deep(.el-upload-dragger) {
+  width: 100%;
+  height: 120px;
+}
+</style>
diff --git a/src/views/fileManagement/document/index.vue b/src/views/fileManagement/document/index.vue
new file mode 100644
index 0000000..7cf352c
--- /dev/null
+++ b/src/views/fileManagement/document/index.vue
@@ -0,0 +1,1262 @@
+<template>
+  <div class="app-container document-view">
+    <div class="left">
+      <div>
+        <el-input
+          v-model="search"
+          style="width: 210px"
+          placeholder="杈撳叆鍏抽敭瀛楄繘琛屾悳绱�"
+          @change="searchFilter"
+          @clear="searchFilter"
+          clearable
+          prefix-icon="Search"
+        />
+        <el-button
+          type="primary"
+          @click="openCategoryDia('addOne')"
+          style="margin-left: 10px"
+          >鏂板鍒嗙被</el-button
+        >
+      </div>
+      <div ref="containerRef">
+        <el-tree
+          ref="tree"
+          v-loading="treeLoad"
+          :data="categoryList"
+          @node-click="handleNodeClick"
+          :expand-on-click-node="false"
+          default-expand-all
+          :default-expanded-keys="expandedKeys"
+          :draggable="true"
+          :filter-node-method="filterNode"
+          :props="{ children: 'children', label: 'category' }"
+          highlight-current
+          node-key="id"
+          style="
+            height: calc(100vh - 190px);
+            overflow-y: scroll;
+            scrollbar-width: none;
+            margin-top: 10px;
+          "
+        >
+          <template #default="{ node, data }">
+            <div class="custom-tree-node">
+              <span class="tree-node-content">
+                <el-icon class="orange-icon">
+                  <component :is="data.children && data.children.length > 0
+                  ? node.expanded ? 'FolderOpened' : 'Folder' : 'Tickets'" />
+                </el-icon>
+                {{ data.category }}
+              </span>
+              <div>
+                <el-button
+                  type="primary"
+                  link
+                  @click="openCategoryDia('edit', data)"
+                >
+                  缂栬緫
+                </el-button>
+                <el-button 
+                  type="primary" 
+                  link 
+                  @click="openCategoryDia('addSub', data)"
+                  v-if="node.level < 2"
+                >
+                  娣诲姞瀛愬垎绫�
+                </el-button>
+                <el-button
+                  v-if="!node.childNodes.length"
+                  style="margin-left: 4px"
+                  type="danger"
+                  link
+                  @click="removeCategory(node, data)"
+                >
+                  鍒犻櫎
+                </el-button>
+              </div>
+            </div>
+          </template>
+        </el-tree>
+      </div>
+    </div>
+    <div class="right">
+      <div style="margin-bottom: 10px" v-if="isShowButton">
+        <el-button type="primary" @click="openDocumentDia('add')">
+          鏂板鏂囨。
+        </el-button>
+        <el-button
+          type="danger"
+          @click="handleDelete"
+          style="margin-left: 10px"
+          plain
+          :disabled="selectedRows.length === 0"
+        >
+          鍒犻櫎 ({{ selectedRows.length }})
+        </el-button>
+      </div>
+      <div class="table-container">
+        
+        <!-- PIMTable 缁勪欢 -->
+        <PIMTable
+          :table-data="documentList"
+          :column="tableColumns"
+          :is-selection="true"
+          :border="true"
+          :table-loading="tableLoading"
+          :page="{
+            current: pagination.currentPage,
+            size: pagination.pageSize,
+            total: pagination.total,
+            layout: 'total, sizes, prev, pager, next, jumper'
+          }"
+          @selection-change="handleSelectionChange"
+          @pagination="handlePagination"
+        />
+      </div>
+    </div>
+
+    <!-- 鍒嗙被鏂板/淇敼瀵硅瘽妗� -->
+    <el-dialog v-model="categoryDia" title="鍒嗙被" width="400px" @keydown.enter.prevent>
+      <el-form
+        :model="categoryForm"
+        label-width="140px"
+        label-position="top"
+        :rules="categoryRules"
+        ref="categoryFormRef"
+      >
+        <el-row :gutter="30">
+          <el-col :span="24" v-if="categoryOperationType === 'addSub'">
+            <el-form-item label="鐖跺垎绫伙細" prop="parentName">
+              <el-input
+                v-model="categoryForm.parentName"
+                placeholder="鐖跺垎绫诲悕绉�"
+                disabled
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="鍒嗙被鍚嶇О锛�" prop="category">
+              <el-input
+                v-model="categoryForm.category"
+                placeholder="璇疯緭鍏ュ垎绫诲悕绉�"
+                clearable
+                @keydown.enter.prevent
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitCategoryForm">纭</el-button>
+          <el-button @click="closeCategoryDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 鏂囨。鏂板/淇敼瀵硅瘽妗� -->
+    <el-dialog
+      v-model="documentDia"
+      :title="documentOperationType === 'add' ? '鏂板鏂囨。' : '缂栬緫鏂囨。'"
+      width="600px"
+      @close="closeDocumentDia"
+      @keydown.enter.prevent
+    >
+      <el-form
+        :model="documentForm"
+        label-width="140px"
+        label-position="top"
+        :rules="documentRules"
+        ref="documentFormRef"
+      >
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鏂囨。鍚嶇О锛�" prop="docName">
+              <el-input v-model="documentForm.docName" placeholder="璇疯緭鍏�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="骞村害锛�" prop="year">
+              <el-date-picker
+                v-model="documentForm.year"
+                type="year"
+                value-format="YYYY"
+                format="YYYY"
+                placeholder="閫夋嫨骞村害"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鏂囨。缂栧彿锛�" prop="docNumber">
+              <el-input v-model="documentForm.docNumber" placeholder="璇疯緭鍏�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璐d换浜猴細" prop="responsiblePerson">
+              <el-input v-model="documentForm.responsiblePerson" placeholder="璇疯緭鍏�" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鏂囨。鍒嗙被锛�" prop="documentClassificationId">
+              <el-select v-model="documentForm.documentClassificationId" placeholder="璇烽�夋嫨鏂囨。鍒嗙被" style="width: 100%">
+                <el-option 
+                  v-for="item in categoryList" 
+                  :key="item.id" 
+                  :label="item.category" 
+                  :value="item.id"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏂囨。鏀剧疆浣嶇疆锛�" prop="warehouseGoodsShelvesRowcolId">
+              <el-tree-select
+                v-model="documentForm.warehouseGoodsShelvesRowcolId"
+                :data="locationTree"
+                placeholder="璇烽�夋嫨鏂囦欢鏀剧疆浣嶇疆"
+                clearable
+                check-strictly
+                :render-after-expand="false"
+                :props="{ children: 'children', label: 'label', value: 'value' }"
+                style="width: 100%"
+                @change="handleLocationChange"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鏂囨。鏃ユ湡锛�" prop="docData">
+              <el-date-picker
+                v-model="documentForm.docData"
+                type="date"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                placeholder="閫夋嫨鏃ユ湡"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="淇濈鏈熼檺锛�" prop="retentionPeriod">
+              <el-select v-model="documentForm.retentionPeriod" placeholder="璇烽�夋嫨">
+                <el-option 
+                  v-for="item in retention_period" 
+                  :key="item.value" 
+                  :label="item.label" 
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="淇濆瘑绾у埆锛�" prop="securityLevel">
+              <el-select v-model="documentForm.securityLevel" placeholder="璇烽�夋嫨">
+                <el-option 
+                  v-for="item in confidentiality_level" 
+                  :key="item.value" 
+                  :label="item.label" 
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍒嗘暟锛�" prop="copyCount">
+              <el-input v-model="documentForm.copyCount" placeholder="璇疯緭鍏�" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="椤垫暟锛�" prop="pageCount">
+              <el-input v-model="documentForm.pageCount" placeholder="璇疯緭鍏�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏂囨。绫诲埆锛�" prop="docCategory">
+              <el-select v-model="documentForm.docCategory" placeholder="璇烽�夋嫨">
+                <el-option 
+                  v-for="item in document_type" 
+                  :key="item.value" 
+                  :label="item.label" 
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鏂囨。绉嶇被锛�" prop="docType">
+              <el-select v-model="documentForm.docType" placeholder="璇烽�夋嫨">
+                <el-option 
+                  v-for="item in document_categories" 
+                  :key="item.value" 
+                  :label="item.label" 
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="绱ф�ョ▼搴︼細" prop="urgencyLevel">
+              <el-select v-model="documentForm.urgencyLevel" placeholder="璇烽�夋嫨">
+                <el-option 
+                  v-for="item in document_urgency" 
+                  :key="item.value" 
+                  :label="item.label" 
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鏂囨。鐘舵�侊細" prop="docStatus">
+              <el-select v-model="documentForm.docStatus" placeholder="璇烽�夋嫨">
+                <el-option 
+                  v-for="item in document_status" 
+                  :key="item.value" 
+                  :label="item.label" 
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞锛�" prop="remark">
+              <el-input 
+                v-model="documentForm.remark" 
+                type="textarea" 
+                :rows="3"
+                placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�" 
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+       </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitDocumentForm">纭</el-button>
+          <el-button @click="closeDocumentDia">鍙栨秷</el-button>
+        </div>
+             </template>
+     </el-dialog>
+             <AttachmentManager ref="attachmentManagerRef" />
+     </div>
+   </template>
+
+<script setup>
+import { ref, reactive, onMounted, getCurrentInstance, toRefs, watch } from "vue";
+import { ElMessageBox, ElMessage } from "element-plus";
+import { ArrowRight, Folder, FolderOpened, Tickets, Document } from '@element-plus/icons-vue';
+import PIMTable from '@/components/PIMTable/PIMTable.vue';
+import { getToken } from "@/utils/auth";
+import { getCategoryTree, addCategory, updateCategory, deleteCategory, getDocumentList, addDocument, updateDocument, deleteDocument, getDocumentDetail, searchDocument, getWarehouseStructure } from '@/api/fileManagement/document'
+import { getWarehouseList } from '@/api/fileManagement/bookshelf'
+import AttachmentManager from './attachmentManager.vue'
+import { useDict } from '@/utils/dict'
+
+const { proxy } = getCurrentInstance();
+const tree = ref(null);
+const containerRef = ref(null);
+
+// 浣跨敤瀛楀吀鏁版嵁
+const { confidentiality_level, document_urgency, document_status, document_type, document_categories, retention_period } = useDict('confidentiality_level', 'document_urgency', 'document_status', 'document_type', 'document_categories', 'retention_period')
+
+// 鐩戝惉瀛楀吀鏁版嵁鍙樺寲
+watch([confidentiality_level, document_urgency, document_status, document_type, document_categories, retention_period], () => {
+  // 瀛楀吀鏁版嵁宸叉洿鏂�
+}, { immediate: true, deep: true });
+
+const categoryDia = ref(false);
+const documentDia = ref(false);
+const categoryOperationType = ref("");
+const documentOperationType = ref("");
+const search = ref("");
+const currentId = ref("");
+const currentParentId = ref("");
+const treeLoad = ref(false);
+const categoryList = ref([]);
+const expandedKeys = ref([]);
+const documentList = ref([]);
+const isShowButton = ref(false);
+const selectedRows = ref([]);
+const selectAll = ref(false);
+const isIndeterminate = ref(false);
+const tableLoading = ref(false);
+const attachmentManagerRef = ref(null);
+
+// 鏂囦欢涓婁紶閰嶇疆
+const upload = reactive({
+  url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
+  headers: { Authorization: "Bearer " + getToken() },
+});
+
+// 浣嶇疆鏍戞暟鎹�
+const locationTree = ref([]);
+
+// 琛ㄦ牸鍒楅厤缃�
+const tableColumns = ref([
+  { label: '鏂囨。鍚嶇О', prop: 'docName', width: '200' },
+  { label: '鏂囨。缂栧彿', prop: 'docNumber', width: '120' },
+  { label: '骞村害', prop: 'year', width: '80' },
+  { label: '璐d换浜�', prop: 'responsiblePerson', width: '100' },
+  { 
+    label: '鏂囨。鏀剧疆浣嶇疆', 
+    prop: 'warehouseGoodsShelvesRowcolId', 
+    width: '150',
+    formatData: (params) => {
+      if (params === null || params === undefined || params === '') return '-';
+      return getLocationName(params);
+    }
+  },
+  { label: '鏂囨。鏃ユ湡', prop: 'docData', width: '120' },
+  { 
+    label: '淇濈鏈熼檺', 
+    prop: 'retentionPeriod', 
+    width: '100',
+    dataType: 'tag',
+    formatData: (params) => {
+      if (params === null || params === undefined || params === '') return '-';
+      if (!retention_period.value || retention_period.value.length === 0) {
+        return params;
+      }
+      const item = retention_period.value.find(item => item.value == params);
+      return item ? item.label : params;
+    },
+    formatType: (params) => {
+      if (params === null || params === undefined || params === '') return 'info';
+      if (!retention_period.value || retention_period.value.length === 0) {
+        return 'info';
+      }
+      const item = retention_period.value.find(item => item.value == params);
+      const validTypes = ['success', 'warning', 'danger', 'info'];
+      return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+    }
+  },
+  { 
+    label: '淇濆瘑绾у埆', 
+    prop: 'securityLevel', 
+    width: '80',
+    dataType: 'tag',
+    formatData: (params) => {
+      if (params === null || params === undefined || params === '') return '-';
+      if (!confidentiality_level.value || confidentiality_level.value.length === 0) {
+        return params;
+      }
+      const item = confidentiality_level.value.find(item => item.value == params);
+      return item ? item.label : params;
+    },
+    formatType: (params) => {
+      if (params === null || params === undefined || params === '') return 'info';
+      if (!confidentiality_level.value || confidentiality_level.value.length === 0) {
+        return 'info';
+      }
+      const item = confidentiality_level.value.find(item => item.value == params);
+      const validTypes = ['success', 'warning', 'danger', 'info'];
+      return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+    }
+  },
+  { label: '鍒嗘暟', prop: 'copyCount', width: '80' },
+  { label: '椤垫暟', prop: 'pageCount', width: '80' },
+  { 
+    label: '鏂囨。绫诲埆', 
+    prop: 'docCategory', 
+    width: '100',
+    dataType: 'tag',
+    formatData: (params) => {
+      if (params === null || params === undefined || params === '') return '-';
+      if (!document_type.value || document_type.value.length === 0) {
+        return params;
+      }
+      const item = document_type.value.find(item => item.value == params);
+      return item ? item.label : params;
+    },
+    formatType: (params) => {
+      if (params === null || params === undefined || params === '') return 'info';
+      if (!document_type.value || document_type.value.length === 0) {
+        return 'info';
+      }
+      const item = document_type.value.find(item => item.value == params);
+      const validTypes = ['success', 'warning', 'danger', 'info'];
+      return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+    }
+  },
+  { 
+    label: '鏂囨。绉嶇被', 
+    prop: 'docType', 
+    width: '100',
+    dataType: 'tag',
+    formatData: (params) => {
+      if (params === null || params === undefined || params === '') return '-';
+      if (!document_categories.value || document_categories.value.length === 0) {
+        return params;
+      }
+      const item = document_categories.value.find(item => item.value == params);
+      return item ? item.label : params;
+    },
+    formatType: (params) => {
+      if (params === null || params === undefined || params === '') return 'info';
+      if (!document_categories.value || document_categories.value.length === 0) {
+        return 'info';
+      }
+      const item = document_categories.value.find(item => item.value == params);
+      const validTypes = ['success', 'warning', 'danger', 'info'];
+      return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+    }
+  },
+  { 
+    label: '绱ф�ョ▼搴�', 
+    prop: 'urgencyLevel', 
+    width: '100',
+    dataType: 'tag',
+    formatData: (params) => {
+      if (params === null || params === undefined || params === '') return '-';
+      if (!document_urgency.value || document_urgency.value.length === 0) {
+        return params;
+      }
+      const item = document_urgency.value.find(item => item.value == params);
+      return item ? item.label : params;
+    },
+    formatType: (params) => {
+      if (params === null || params === undefined || params === '') return 'info';
+      if (!document_urgency.value || document_urgency.value.length === 0) {
+        return 'info';
+      }
+      const item = document_urgency.value.find(item => item.value == params);
+      const validTypes = ['success', 'warning', 'danger', 'info'];
+      return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+    }
+  },
+  { 
+    label: '鏂囨。鐘舵��', 
+    prop: 'docStatus', 
+    width: '100',
+    dataType: 'tag',
+    formatData: (params) => {
+      if (params === null || params === undefined || params === '') return '-';
+      if (!document_status.value || document_status.value.length === 0) {
+        return params;
+      }
+      const item = document_status.value.find(item => item.value == params);
+      return item ? item.label : params;
+    },
+    formatType: (params) => {
+      if (params === null || params === undefined || params === '') return 'info';
+      if (!document_status.value || document_status.value.length === 0) {
+        return 'info';
+      }
+      const item = document_status.value.find(item => item.value == params);
+      const validTypes = ['success', 'warning', 'danger', 'info'];
+      return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+    }
+  },
+  { 
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: 'right',
+    width: '150',
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          openDocumentDia('edit', row)
+        },
+      },
+      {
+        name: "闄勪欢",
+        type: "text",
+        clickFun: (row) => {
+          openAttachment(row)
+        },
+      },
+    ],
+  }
+]);
+
+// 鍒嗙被琛ㄥ崟
+const categoryForm = reactive({
+  category: "",
+  parentId: "",
+  parentName: "",
+});
+
+const categoryRules = reactive({
+  category: [{ required: true, message: "璇疯緭鍏ュ垎绫诲悕绉�", trigger: "blur" }],
+});
+
+// 鏂囨。琛ㄥ崟
+const documentForm = reactive({
+  id: "",
+  documentClassificationId: "",
+  docName: "",
+  docNumber: "",
+  year: "",
+  responsiblePerson: "",
+  warehouseGoodsShelvesRowcolId: "",
+  docData: "",
+  retentionPeriod: "",
+  securityLevel: "",
+  copyCount: "",
+  pageCount: "",
+  docCategory: "",
+  docType: "",
+  urgencyLevel: "",
+  docStatus: "",
+  remark: "",
+  attachments: [], // 鏂板闄勪欢鏁扮粍
+});
+
+const documentRules = reactive({
+  docName: [{ required: true, message: "璇疯緭鍏ユ枃妗e悕绉�", trigger: "blur" }],
+  docNumber: [{ required: true, message: "璇疯緭鍏ユ枃妗g紪鍙�", trigger: "blur" }],
+  year: [{ required: true, message: "璇烽�夋嫨骞村害", trigger: "change" }],
+  documentClassificationId: [{ required: true, message: "璇烽�夋嫨鏂囨。鍒嗙被", trigger: "change" }],
+  warehouseGoodsShelvesRowcolId: [{ required: true, message: "璇烽�夋嫨鏂囨。鏀剧疆浣嶇疆", trigger: "change" }],
+});
+
+// 鍒嗛〉鐩稿叧
+const pagination = reactive({
+  currentPage: 1,
+  pageSize: 10,
+  total: 0,
+});
+
+// 鍒濆鍖栧垎绫绘爲鏁版嵁
+const initCategoryTree = async() => {
+  try {
+    treeLoad.value = true;
+    const res = await getCategoryTree();
+    if (res.code === 200) {
+      categoryList.value = res.data || [];
+      
+      // 璁剧疆灞曞紑鐨勮妭鐐�
+      expandedKeys.value = [];
+      categoryList.value.forEach((item) => {
+        if (item.id) {
+          expandedKeys.value.push(item.id);
+        }
+      });
+    } else {
+      ElMessage.error(res.msg || "鑾峰彇鍒嗙被鏍戝け璐�");
+    }
+  } catch (error) {
+    ElMessage.error("鑾峰彇鍒嗙被鏍戝け璐ワ紝璇烽噸璇�");
+  } finally {
+    treeLoad.value = false;
+  }
+};
+
+// 鍒濆鍖栦粨搴撲綅缃暟鎹�
+const initLocationTree = async() => {
+  try {
+    const res = await getWarehouseList();
+    if (res.code === 200) {
+      // 杞崲鏁版嵁鏍煎紡锛岄�傞厤el-tree-select缁勪欢
+      locationTree.value = transformWarehouseData(res.data || []);
+    } else {
+      ElMessage.error(res.msg || "鑾峰彇浠撳簱浣嶇疆澶辫触");
+    }
+  } catch (error) {
+    ElMessage.error("鑾峰彇浠撳簱浣嶇疆澶辫触锛岃閲嶈瘯");
+  }
+};
+
+// 杞崲浠撳簱鏁版嵁鏍煎紡
+const transformWarehouseData = (data) => {
+  return data.map(item => ({
+    id: item.id,
+    label: item.name || item.warehouseName || item.label,
+    value: item.id,
+    children: item.children ? transformWarehouseData(item.children) : []
+  }));
+};
+
+// 鏍规嵁ID鑾峰彇浣嶇疆鍚嶇О
+const getLocationName = (locationId) => {
+  if (!locationId || !locationTree.value || locationTree.value.length === 0) {
+    return locationId || '-';
+  }
+  
+  const findLocation = (tree, id) => {
+    for (let item of tree) {
+      if (item.value === locationId || item.id === locationId) {
+        return item.label;
+      }
+      if (item.children && item.children.length > 0) {
+        const result = findLocation(item.children, id);
+        if (result) return result;
+      }
+    }
+    return null;
+  };
+  
+  const locationName = findLocation(locationTree.value, locationId);
+  return locationName || locationId;
+};
+
+// 杩囨护鍒嗙被鏍�
+const searchFilter = () => {
+  if (proxy.$refs.tree) {
+    proxy.$refs.tree.filter(search.value);
+  }
+};
+
+// 鎵撳紑鍒嗙被寮规
+const openCategoryDia = (type, data) => {
+  categoryOperationType.value = type;
+  categoryDia.value = true;
+  categoryForm.category = "";
+  categoryForm.parentId ="";
+  categoryForm.parentName = "";
+  
+  if (type === "edit") {
+    categoryForm.category = data.category;
+    // 淇濆瓨褰撳墠缂栬緫鐨勫垎绫籌D
+    currentId.value = data.id;
+  } else if (type === "addSub") {
+    categoryForm.parentId = data.id;
+    categoryForm.parentName = data.category;
+  }
+};
+
+// 鎵撳紑鏂囨。寮规
+const openDocumentDia = (type, data) => {
+  documentOperationType.value = type;
+  documentDia.value = true;
+  
+  if (type === "edit") {
+    // 缂栬緫妯″紡锛屽姞杞界幇鏈夋暟鎹�
+    Object.assign(documentForm, data);
+    documentForm.retentionPeriod = String(documentForm.retentionPeriod)
+    documentForm.securityLevel = String(documentForm.securityLevel)
+    documentForm.docCategory = String(documentForm.docCategory)
+    documentForm.docType = String(documentForm.docType)
+    documentForm.urgencyLevel = String(documentForm.urgencyLevel)
+    documentForm.docStatus = String(documentForm.docStatus)
+    
+    // 鍔犺浇闄勪欢淇℃伅
+    if (data.attachments) {
+      documentForm.attachments = [...data.attachments];
+    } else {
+      documentForm.attachments = [];
+    }
+  } else {
+    // 鏂板妯″紡锛屾竻绌鸿〃鍗�
+    Object.keys(documentForm).forEach(key => {
+      documentForm[key] = "";
+    });
+    documentForm.attachments = []; // 鏂板妯″紡涓嬩篃娓呯┖闄勪欢
+    // 璁剧疆榛樿鍊� - 浣跨敤瀛楀吀鏁版嵁鐨勭涓�涓�夐」浣滀负榛樿鍊�
+    if (document_status.value && document_status.value.length > 0) {
+      documentForm.docStatus = document_status.value[0].value;
+    }
+    if (document_urgency.value && document_urgency.value.length > 0) {
+      documentForm.urgencyLevel = document_urgency.value[0].value;
+    }
+  }
+};
+
+// 鎻愪氦鍒嗙被琛ㄥ崟
+const submitCategoryForm = () => {
+  proxy.$refs.categoryFormRef.validate(async (valid) => {
+    if (valid) {
+      try {
+        if (categoryOperationType.value === "addSub") {
+          // 娣诲姞瀛愬垎绫�
+          const res = await addCategory({
+            category: categoryForm.category,
+            parentId: categoryForm.parentId
+          });
+          if (res.code === 200) {
+            ElMessage.success("娣诲姞瀛愬垎绫绘垚鍔�");
+            // 閲嶆柊鍔犺浇鍒嗙被鏍�
+            await initCategoryTree();
+          } else {
+            ElMessage.error(res.msg || "娣诲姞瀛愬垎绫诲け璐�");
+          }
+        } else if (categoryOperationType.value === "edit") {
+          // 缂栬緫鍒嗙被
+          const res = await updateCategory({
+            id: currentId.value,
+            category: categoryForm.category
+          });
+          if (res.code === 200) {
+            ElMessage.success("缂栬緫鍒嗙被鎴愬姛");
+            // 閲嶆柊鍔犺浇鍒嗙被鏍�
+            await initCategoryTree();
+          } else {
+            ElMessage.error(res.msg || "缂栬緫鍒嗙被澶辫触");
+          }
+        } else {
+          // 鏂板椤剁骇鍒嗙被
+          const res = await addCategory({
+            category: categoryForm.category,
+            parentId: null
+          });
+          if (res.code === 200) {
+            ElMessage.success("鏂板鍒嗙被鎴愬姛");
+            // 閲嶆柊鍔犺浇鍒嗙被鏍�
+            await initCategoryTree();
+          } else {
+            ElMessage.error(res.msg || "鏂板鍒嗙被澶辫触");
+          }
+        }
+        
+        closeCategoryDia();
+      } catch (error) {
+        ElMessage.error("鎿嶄綔澶辫触锛岃閲嶈瘯");
+      }
+    }
+  });
+};
+
+// 鍏抽棴鍒嗙被寮规
+const closeCategoryDia = () => {
+  proxy.$refs.categoryFormRef.resetFields();
+  categoryForm.parentId = "";
+  categoryForm.parentName = "";
+  categoryDia.value = false;
+};
+
+// 鍒犻櫎鍒嗙被
+const removeCategory = (node, data) => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(async () => {
+      try {
+        const res = await deleteCategory([data.id]);
+        if (res.code === 200) {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          // 閲嶆柊鍔犺浇鍒嗙被鏍�
+          await initCategoryTree();
+        } else {
+          ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+        }
+      } catch (error) {
+        ElMessage.error("鍒犻櫎澶辫触锛岃閲嶈瘯");
+      }
+    })
+    .catch(() => {
+      ElMessage("宸插彇娑�");
+    });
+};
+
+// 閫夋嫨鍒嗙被
+const handleNodeClick = (val, node, el) => {
+  // 鍒ゆ柇鏄惁涓哄彾瀛愯妭鐐�
+  isShowButton.value = true;
+  // 鍙湁鍙跺瓙鑺傜偣鎵嶆墽琛屼互涓嬮�昏緫
+  currentId.value = val.id;
+  currentParentId.value = val.parentId;
+  
+  // 娓呯┖閫夋嫨鐘舵��
+  selectedRows.value = [];
+  selectAll.value = false;
+  isIndeterminate.value = false;
+  
+  // 閲嶇疆鍒嗛〉
+  pagination.currentPage = 1;
+  pagination.total = 0;
+  
+  // 鍔犺浇鏂囨。鍒楄〃
+  if (isShowButton.value) {
+    loadDocumentList();
+  } else {
+    // 濡傛灉涓嶆槸鍙跺瓙鑺傜偣锛屾竻绌烘枃妗e垪琛�
+    documentList.value = [];
+  }
+};
+
+// 鎻愪氦鏂囨。琛ㄥ崟
+const submitDocumentForm = () => {
+  proxy.$refs.documentFormRef.validate(async (valid) => {
+    if (valid) {
+      try {
+        // 鏋勫缓鎻愪氦鏁版嵁
+        const submitData = {
+          ...documentForm,
+          // 璁剧疆褰撳墠閫変腑鐨勫垎绫籌D
+          documentClassificationId: currentId.value || documentForm.documentClassificationId,
+          // 娣诲姞闄勪欢淇℃伅
+          // attachments: documentForm.attachments
+        };
+        
+        if (documentOperationType.value === "edit") {
+          // 缂栬緫妯″紡锛屾洿鏂扮幇鏈夋暟鎹�
+          const res = await updateDocument(submitData);
+          if (res.code === 200) {
+            ElMessage.success("缂栬緫鎴愬姛");
+            // 閲嶆柊鍔犺浇鏂囨。鍒楄〃
+            await loadDocumentList();
+            // 鍒锋柊闄勪欢鍒楄〃
+            if (attachmentManagerRef.value && documentForm.id) {
+              attachmentManagerRef.value.loadAttachmentList(documentForm.id);
+            }
+          } else {
+            ElMessage.error(res.msg || "缂栬緫澶辫触");
+          }
+        } else {
+          // 鏂板妯″紡锛屾坊鍔犳柊鏁版嵁
+          const res = await addDocument(submitData);
+          if (res.code === 200) {
+            ElMessage.success("鏂板鎴愬姛");
+            // 閲嶆柊鍔犺浇鏂囨。鍒楄〃
+            await loadDocumentList();
+            // 鍒锋柊闄勪欢鍒楄〃
+            if (attachmentManagerRef.value && res.data && res.data.id) {
+              attachmentManagerRef.value.loadAttachmentList(res.data.id);
+            }
+          } else {
+            ElMessage.error(res.msg || "鏂板澶辫触");
+          }
+        }
+        closeDocumentDia();
+      } catch (error) {
+        ElMessage.error("鎿嶄綔澶辫触锛岃閲嶈瘯");
+      }
+    }
+  });
+};
+
+// 鍏抽棴鏂囨。寮规
+const closeDocumentDia = () => {
+  proxy.$refs.documentFormRef.resetFields();
+  documentDia.value = false;
+  // 娓呯┖琛ㄥ崟鏁版嵁
+  Object.keys(documentForm).forEach(key => {
+    documentForm[key] = "";
+  });
+  documentForm.attachments = []; // 鍏抽棴寮规鏃朵篃娓呯┖闄勪欢
+};
+
+// 澶勭悊浣嶇疆閫夋嫨鍙樺寲
+const handleLocationChange = (value) => {
+  if (value) {
+    // 妫�鏌ラ�夋嫨鐨勬槸鍚︿负鍙跺瓙鑺傜偣
+    const isLeafNode = checkIfLeafNode(locationTree.value, value);
+    if (!isLeafNode) {
+      ElMessage.warning("璇烽�夋嫨鏈�搴曞眰鐨勪綅缃紙濡傦細鏌滃眰锛�");
+      documentForm.warehouseGoodsShelvesRowcolId = "";
+      return;
+    }
+  }
+};
+
+// 妫�鏌ユ槸鍚︿负鍙跺瓙鑺傜偣
+const checkIfLeafNode = (tree, value) => {
+  for (let item of tree) {
+    if (item.value === value || item.id === value) {
+      // 濡傛灉娌℃湁瀛愯妭鐐癸紝鍒欎负鍙跺瓙鑺傜偣
+      return !item.children || item.children.length === 0;
+    }
+    if (item.children && item.children.length > 0) {
+      const result = checkIfLeafNode(item.children, value);
+      if (result !== null) {
+        return result;
+      }
+    }
+  }
+  return null;
+};
+
+// 鍒犻櫎鏂囨。
+const handleDelete = () => {
+  if (selectedRows.value.length > 0) {
+    ElMessageBox.confirm(`纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.value.length} 鏉¤褰曞悧锛焋, "鍒犻櫎鎻愮ず", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(async () => {
+        try {
+          const selectedIds = selectedRows.value.map(row => row.id);
+          const res = await deleteDocument(selectedIds);
+          if (res.code === 200) {
+            ElMessage.success("鍒犻櫎鎴愬姛");
+            // 閲嶆柊鍔犺浇鏂囨。鍒楄〃
+            await loadDocumentList();
+          } else {
+            ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+          }
+        } catch (error) {
+          ElMessage.error("鍒犻櫎澶辫触锛岃閲嶈瘯");
+        }
+      })
+      .catch(() => {
+        ElMessage("宸插彇娑�");
+      });
+  } else {
+    ElMessage.warning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
+  }
+};
+
+// PIMTable 閫夋嫨鍙樺寲浜嬩欢
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+  
+  // 鏇存柊鍏ㄩ�夌姸鎬�
+  const selectedCount = selection.length;
+  const totalCount = documentList.value.length;
+  
+  if (selectedCount === 0) {
+    selectAll.value = false;
+    isIndeterminate.value = false;
+  } else if (selectedCount === totalCount) {
+    selectAll.value = true;
+    isIndeterminate.value = false;
+  } else {
+    selectAll.value = false;
+    isIndeterminate.value = true;
+  }
+};
+
+// 鍔犺浇鏂囨。鍒楄〃
+const loadDocumentList = async () => {
+  try {
+    tableLoading.value = true;
+    
+    // 鏋勫缓鏌ヨ鍙傛暟
+    const query = {
+      page: pagination.currentPage,
+      size: pagination.pageSize,
+      documentClassificationId:currentId.value
+    };
+    
+    const res = await getDocumentList(query);
+    if (res.code === 200) {
+      documentList.value = res.data.records || [];
+      pagination.total = res.data.total || 0;
+    } else {
+      ElMessage.error(res.msg || "鑾峰彇鏂囨。鍒楄〃澶辫触");
+      documentList.value = [];
+      pagination.total = 0;
+    }
+    
+    // 閲嶇疆閫夋嫨鐘舵��
+    selectedRows.value = [];
+    selectAll.value = false;
+    isIndeterminate.value = false;
+  } catch (error) {
+    ElMessage.error("鑾峰彇鏂囨。鍒楄〃澶辫触锛岃閲嶈瘯");
+    documentList.value = [];
+    pagination.total = 0;
+  } finally {
+    tableLoading.value = false;
+  }
+};
+
+// 澶勭悊鍒嗛〉鍙樺寲
+const handlePagination = (current, size) => {
+  pagination.currentPage = current;
+  pagination.pageSize = size;
+  loadDocumentList();
+};
+
+// 璋冪敤tree杩囨护鏂规硶
+const filterNode = (value, data, node) => {
+  if (!value) {
+    return true;
+  }
+  let val = value.toLowerCase();
+  return chooseNode(val, data, node);
+};
+
+// 杩囨护鐖惰妭鐐� / 瀛愯妭鐐�
+const chooseNode = (value, data, node) => {
+  if (data.category && data.category.toLowerCase().indexOf(value) !== -1) {
+    return true;
+  }
+  const level = node.level;
+  if (level === 1) {
+    return false;
+  }
+  let parentData = node.parent;
+  let index = 0;
+  while (index < level - 1) {
+    if (parentData.data.category && parentData.data.category.toLowerCase().indexOf(value) !== -1) {
+      return true;
+    }
+    parentData = parentData.parent;
+    index++;
+  }
+  return false;
+};
+
+// 鎵撳紑闄勪欢
+const openAttachment = (row) => {
+  attachmentManagerRef.value.open([], row.id);
+};
+
+onMounted(() => {
+  initCategoryTree();
+  initLocationTree();
+  
+  // 涓嶅湪鍒濆鍖栨椂鍔犺浇鏂囨。鍒楄〃锛岀瓑寰呯敤鎴烽�夋嫨鍒嗙被鍚庡啀鍔犺浇
+});
+</script>
+
+<style scoped>
+.document-view {
+  display: flex;
+  height: 100%;
+}
+
+.left {
+  width: 380px;
+  padding: 16px;
+  background: #ffffff;
+  border-right: 1px solid #e4e7ed;
+}
+
+.right {
+  width: calc(100% - 380px);
+  padding: 16px;
+  background: #ffffff;
+}
+
+.custom-tree-node {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  padding-right: 8px;
+}
+
+.tree-node-content {
+  display: flex;
+  align-items: center;
+  height: 100%;
+}
+
+.orange-icon {
+  color: orange;
+  font-size: 18px;
+  margin-right: 8px;
+}
+
+.table-container {
+  background: #ffffff;
+  border-radius: 8px;
+  overflow: hidden;
+  position: relative;
+}
+
+.add-row {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  background-color: #f5f7fa;
+  cursor: pointer;
+  transition: background-color 0.2s ease;
+  padding: 12px 16px;
+  margin-bottom: 16px;
+  border-radius: 6px;
+  border: 1px dashed #d9d9d9;
+}
+
+.add-row:hover {
+  background-color: #e4e7ed;
+  border-color: #c0c4cc;
+}
+
+.add-icon {
+  color: #909399;
+  font-size: 16px;
+}
+
+.add-row span {
+  color: #606266;
+  font-size: 14px;
+}
+
+.empty-data {
+  text-align: center;
+  color: #909399;
+  padding: 40px;
+  font-size: 14px;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+
+.operation-column {
+  position: absolute;
+  right: 0;
+  top: 0;
+  width: 120px;
+  background: #ffffff;
+  border-left: 1px solid #e4e7ed;
+  z-index: 1;
+  box-shadow: -2px 0 4px rgba(0, 0, 0, 0.1);
+}
+
+.operation-header {
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  background: #fafafa;
+  border-bottom: 1px solid #e4e7ed;
+  font-weight: 500;
+  color: #606266;
+}
+
+.operation-cell {
+  height: 40px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border-bottom: 1px solid #e4e7ed;
+}
+
+.operation-cell:last-child {
+  border-bottom: none;
+}
+
+.attachment-section {
+  width: 100%;
+}
+
+.attachment-list {
+  margin-bottom: 10px;
+}
+
+.attachment-item {
+  display: flex;
+  align-items: center;
+  padding: 8px 12px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  margin-bottom: 8px;
+}
+
+.file-icon {
+  margin-right: 8px;
+  color: #409eff;
+}
+
+.file-name {
+  flex: 1;
+  color: #606266;
+  font-size: 14px;
+}
+</style>
diff --git a/src/views/fileManagement/return/index.vue b/src/views/fileManagement/return/index.vue
new file mode 100644
index 0000000..a95c8af
--- /dev/null
+++ b/src/views/fileManagement/return/index.vue
@@ -0,0 +1,595 @@
+<template>
+  <div class="app-container return-view">
+    <!-- 鏌ヨ鍖哄煙 -->
+    <div class="search-container">
+      <el-form :model="searchForm" :inline="true" class="search-form">
+        <!-- <el-form-item label="鍊熼槄鐘舵�侊細">
+          <el-select v-model="searchForm.borrowStatus" placeholder="璇烽�夋嫨鍊熼槄鐘舵��" clearable style="width: 150px">
+            <el-option label="鍊熼槄" value="鍊熼槄" />
+            <el-option label="褰掕繕" value="褰掕繕" />
+          </el-select>
+        </el-form-item> -->
+        <el-form-item label="鍊熼槄浜猴細">
+          <el-input
+            v-model="searchForm.borrower"
+            placeholder="璇疯緭鍏ュ�熼槄浜�"
+            clearable
+            style="width: 200px"
+          />
+        </el-form-item>
+        <el-form-item label="褰掕繕浜猴細">
+          <el-input
+            v-model="searchForm.returner"
+            placeholder="璇疯緭鍏ュ綊杩樹汉"
+            clearable
+            style="width: 200px"
+          />
+        </el-form-item>
+        <el-form-item label="褰掕繕鏃ユ湡鑼冨洿锛�">
+          <el-date-picker
+            v-model="searchForm.dateRange"
+            type="daterange"
+            range-separator="鑷�"
+            start-placeholder="寮�濮嬫棩鏈�"
+            end-placeholder="缁撴潫鏃ユ湡"
+            format="YYYY-MM-DD"
+            value-format="YYYY-MM-DD"
+            style="width: 300px"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">
+            <el-icon><Search /></el-icon>
+            鏌ヨ
+          </el-button>
+          <el-button @click="handleReset">
+            <el-icon><Refresh /></el-icon>
+            閲嶇疆
+          </el-button>
+        </el-form-item>
+        <el-form-item style="margin-left: auto;">
+          <el-button type="primary" @click="openReturnDia('add')">
+            <el-icon><Plus /></el-icon>
+            鏂板褰掕繕
+          </el-button>
+          <el-button
+            type="danger"
+            @click="handleBatchDelete"
+            :disabled="selectedRows.length === 0"
+          >
+            <el-icon><Delete /></el-icon>
+            鎵归噺鍒犻櫎 ({{ selectedRows.length }})
+          </el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <!-- 琛ㄦ牸鍖哄煙 -->
+    <div class="table-container">
+      <PIMTable
+        :table-data="returnList"
+        :column="tableColumns"
+        :is-selection="true"
+        :border="true"
+        :table-loading="tableLoading"
+        :page="{
+          current: pagination.currentPage,
+          size: pagination.pageSize,
+          total: pagination.total,
+          layout: 'total, sizes, prev, pager, next, jumper'
+        }"
+        @selection-change="handleSelectionChange"
+        @pagination="handlePagination"
+      />
+    </div>
+
+    <!-- 褰掕繕鏂板/缂栬緫瀵硅瘽妗� -->
+    <el-dialog
+      v-model="returnDia"
+      :title="returnOperationType === 'add' ? '鏂板褰掕繕' : '缂栬緫褰掕繕'"
+      width="800px"
+      @close="closeReturnDia"
+      @keydown.enter.prevent
+    >
+      <el-form
+        :model="returnForm"
+        label-width="140px"
+        :rules="returnRules"
+        ref="returnFormRef"
+      >
+                 <el-row :gutter="20">
+           <el-col :span="12">
+             <el-form-item label="鏂囨。锛�" prop="borrowId">
+               <el-select v-model="returnForm.borrowId" placeholder="璇烽�夋嫨鏂囨。" style="width: 100%" @change="handleDocumentChange">
+                 <el-option 
+                   v-for="item in documentList" 
+                   :key="item.id" 
+                   :label="item.docName || item.name" 
+                   :value="item.id"
+                 />
+               </el-select>
+             </el-form-item>
+           </el-col>
+           <el-col :span="12">
+             <el-form-item label="鍊熼槄浜猴細" prop="borrower">
+               <el-input v-model="returnForm.borrower" placeholder="鍊熼槄浜哄皢鏍规嵁鏂囨。閫夋嫨鑷姩甯﹀嚭" disabled />
+             </el-form-item>
+           </el-col>
+         </el-row>
+        
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="褰掕繕浜猴細" prop="returner">
+              <el-input v-model="returnForm.returner" placeholder="璇疯緭鍏ュ綊杩樹汉" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="褰掕繕鏃ユ湡锛�" prop="returnDate">
+              <el-date-picker
+                v-model="returnForm.returnDate"
+                type="date"
+                placeholder="閫夋嫨褰掕繕鏃ユ湡"
+                style="width: 100%"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        
+                 <el-row :gutter="20">
+           <el-col :span="24">
+             <el-form-item label="搴斿綊杩樻棩鏈燂細" prop="dueReturnDate">
+               <el-date-picker
+                 v-model="returnForm.dueReturnDate"
+                 type="date"
+                 placeholder="搴斿綊杩樻棩鏈熷皢鏍规嵁鏂囨。閫夋嫨鑷姩甯﹀嚭"
+                 style="width: 100%"
+                 format="YYYY-MM-DD"
+                 value-format="YYYY-MM-DD"
+                 disabled
+               />
+             </el-form-item>
+           </el-col>
+         </el-row>
+        
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞璇存槑锛�" prop="remark">
+              <el-input
+                v-model="returnForm.remark"
+                type="textarea"
+                :rows="3"
+                placeholder="璇疯緭鍏ュ娉ㄨ鏄�"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitReturnForm">纭</el-button>
+          <el-button @click="closeReturnDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+import { ElMessageBox, ElMessage } from "element-plus";
+import { Search, Refresh, Plus, Delete } from '@element-plus/icons-vue';
+import PIMTable from '@/components/PIMTable/PIMTable.vue';
+import { getReturnListPage, returnDocument, deleteReturn, getDocumentList, updateBorrow, reventUpdate } from '@/api/fileManagement/return';
+
+const { proxy } = getCurrentInstance();
+
+// 鍝嶅簲寮忔暟鎹�
+const returnDia = ref(false);
+const returnOperationType = ref("");
+const tableLoading = ref(false);
+const returnList = ref([]);
+const selectedRows = ref([]);
+const documentList = ref([]); // 鏂囨。鍒楄〃
+
+// 鍒嗛〉鐩稿叧
+const pagination = reactive({
+  currentPage: 1,
+  pageSize: 10,
+  total: 0,
+});
+
+// 鏌ヨ琛ㄥ崟
+const searchForm = reactive({
+  borrowStatus: "",
+  borrower: "",
+  returner: "",
+  dateRange: []
+});
+
+// 褰掕繕琛ㄥ崟
+const returnForm = reactive({
+  id: "",
+  borrowId: "",
+  borrower: "",
+  returner: "",
+  borrowStatus: "",
+  returnDate: "",
+  dueReturnDate: "",
+  remark: ""
+});
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const returnRules = reactive({
+  borrowId: [{ required: true, message: "璇烽�夋嫨鏂囨。", trigger: "change" }],
+  returner: [{ required: true, message: "璇疯緭鍏ュ綊杩樹汉", trigger: "blur" }],
+  returnDate: [{ required: true, message: "璇烽�夋嫨褰掕繕鏃ユ湡", trigger: "change" }]
+});
+
+// 琛ㄦ牸鍒楅厤缃�
+const tableColumns = ref([
+  { 
+    label: '鏂囨。鍚嶇О', 
+    prop: 'docName',
+    width: '200',
+  },
+  { label: '鍊熼槄浜�', prop: 'borrower' },
+  { label: '褰掕繕浜�', prop: 'returner' },
+  { 
+    label: '鍊熼槄鐘舵��', 
+    prop: 'borrowStatus', 
+    dataType: 'tag',
+    formatData: (params) => {
+      if (params === null || params === undefined || params === '') return '-';
+      return params;
+    },
+    formatType: (params) => {
+      if (params === '褰掕繕') return 'success';
+      if (params === '鍊熼槄') return 'warning';
+      return 'info';
+    }
+  },
+  { label: '褰掕繕鏃ユ湡', prop: 'returnDate' },
+  { label: '搴斿綊杩樻棩鏈�', prop: 'dueReturnDate' },
+  { label: '澶囨敞', prop: 'remark', width: '150' },
+  { 
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: 'right',
+    width: '150',
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          openReturnDia('edit', row)
+        },
+      },
+      {
+        name: "鍒犻櫎",
+        type: "text",
+        clickFun: (row) => {
+          handleDelete(row)
+        },
+      },
+    ],
+  }
+]);
+
+// 鍒濆鍖栨暟鎹�
+const initData = async () => {
+  await Promise.all([
+    loadDocumentList(),
+    loadReturnList()
+  ]);
+};
+
+// 鍔犺浇鏂囨。鍒楄〃
+const loadDocumentList = async () => {
+  try {
+    const res = await getDocumentList();
+    if (res.code === 200) {
+      documentList.value = res.data || [];
+    } else {
+      ElMessage.error(res.msg || "鑾峰彇鏂囨。鍒楄〃澶辫触");
+      documentList.value = [];
+    }
+  } catch (error) {
+    ElMessage.error("鑾峰彇鏂囨。鍒楄〃澶辫触锛岃閲嶈瘯");
+    documentList.value = [];
+  }
+};
+
+// 鍔犺浇褰掕繕鍒楄〃
+const loadReturnList = async () => {
+  try {
+    tableLoading.value = true;
+    
+    // 鏋勫缓鏌ヨ鍙傛暟
+    const query = {
+      page: pagination.currentPage,
+      size: pagination.pageSize,
+      borrowStatus: searchForm.borrowStatus || undefined,
+      borrower: searchForm.borrower || undefined,
+      returner: searchForm.returner || undefined,
+      entryDateStart: searchForm.dateRange && searchForm.dateRange.length > 0 ? searchForm.dateRange[0] : undefined,
+      entryDateEnd: searchForm.dateRange && searchForm.dateRange.length > 1 ? searchForm.dateRange[1] : undefined
+    };
+    
+    // 绉婚櫎undefined鐨勫弬鏁�
+    Object.keys(query).forEach(key => {
+      if (query[key] === undefined) {
+        delete query[key];
+      }
+    });
+    
+    const res = await getReturnListPage(query);
+    if (res.code === 200) {
+      returnList.value = res.data.records || [];
+      pagination.total = res.data.total || 0;
+    } else {
+      ElMessage.error(res.msg || "鑾峰彇褰掕繕鍒楄〃澶辫触");
+      returnList.value = [];
+      pagination.total = 0;
+    }
+    
+    // 閲嶇疆閫夋嫨鐘舵��
+    selectedRows.value = [];
+  } catch (error) {
+    ElMessage.error("鑾峰彇褰掕繕鍒楄〃澶辫触锛岃閲嶈瘯");
+    returnList.value = [];
+    pagination.total = 0;
+  } finally {
+    tableLoading.value = false;
+  }
+};
+
+// 鏌ヨ
+const handleSearch = () => {
+  pagination.currentPage = 1;
+  loadReturnList();
+};
+
+// 閲嶇疆鏌ヨ
+const handleReset = () => {
+  searchForm.borrowStatus = "";
+  searchForm.borrower = "";
+  searchForm.returner = "";
+  searchForm.dateRange = [];
+  pagination.currentPage = 1;
+  loadReturnList();
+  ElMessage.success("鏌ヨ鏉′欢宸查噸缃�");
+};
+
+// 鎵撳紑褰掕繕寮规
+const openReturnDia = (type, data) => {
+  returnOperationType.value = type;
+  returnDia.value = true;
+  
+  if (type === "edit") {
+    // 缂栬緫妯″紡锛屽姞杞界幇鏈夋暟鎹�
+    Object.assign(returnForm, data);
+    // 缂栬緫妯″紡涓嬶紝鏂囨。閫夋嫨鍚庤嚜鍔ㄥ~鍏呭�熼槄浜哄拰搴斿綊杩樻棩鏈�
+    if (returnForm.borrowId) {
+      handleDocumentChange(returnForm.borrowId);
+    }
+  } else {
+    // 鏂板妯″紡锛屾竻绌鸿〃鍗�
+    Object.keys(returnForm).forEach(key => {
+      returnForm[key] = "";
+    });
+    // 璁剧疆榛樿鐘舵��
+    returnForm.borrowStatus = "褰掕繕";
+    // 璁剧疆褰撳墠鏃ユ湡涓哄綊杩樻棩鏈�
+    returnForm.returnDate = new Date().toISOString().split('T')[0];
+  }
+};
+
+// 鍏抽棴褰掕繕寮规
+const closeReturnDia = () => {
+  proxy.$refs.returnFormRef.resetFields();
+  returnDia.value = false;
+};
+
+// 鎻愪氦褰掕繕琛ㄥ崟
+const submitReturnForm = () => {
+  proxy.$refs.returnFormRef.validate(async (valid) => {
+    if (valid) {
+      try {
+                 if (returnOperationType.value === "edit") {
+           // 缂栬緫妯″紡锛岃皟鐢ㄥ綊杩樻洿鏂版帴鍙�
+           const res = await reventUpdate({
+             id: returnForm.id,
+             documentationId: returnForm.documentationId,
+             borrower: returnForm.borrower,
+             returner: returnForm.returner,
+             borrowStatus: returnForm.borrowStatus,
+             returnDate: returnForm.returnDate,
+             dueReturnDate: returnForm.dueReturnDate,
+             remark: returnForm.remark
+           });
+          
+          if (res.code === 200) {
+            ElMessage.success("缂栬緫鎴愬姛");
+            await loadReturnList();
+            closeReturnDia();
+          } else {
+            ElMessage.error(res.msg || "缂栬緫澶辫触");
+          }
+        } else {
+          // 鏂板妯″紡锛岃皟鐢ㄥ綊杩樻帴鍙�
+          const res = await returnDocument({
+            borrowId: returnForm.borrowId,
+            borrower: returnForm.borrower,
+            returner: returnForm.returner,
+            borrowStatus: returnForm.borrowStatus,
+            returnDate: returnForm.returnDate,
+            dueReturnDate: returnForm.dueReturnDate,
+            remark: returnForm.remark
+          });
+          
+          if (res.code === 200) {
+            ElMessage.success("鏂板鎴愬姛");
+            await loadReturnList();
+            closeReturnDia();
+          } else {
+            ElMessage.error(res.msg || "鏂板澶辫触");
+          }
+        }
+      } catch (error) {
+        ElMessage.error("鎿嶄綔澶辫触锛岃閲嶈瘯");
+      }
+    }
+  });
+};
+
+// 鍒犻櫎褰掕繕璁板綍
+const handleDelete = (row) => {
+  ElMessageBox.confirm(
+    `纭畾瑕佸垹闄よ繖鏉″綊杩樿褰曞悧锛焋,
+    "鍒犻櫎鎻愮ず",
+    {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }
+  ).then(async () => {
+    try {
+      const res = await deleteReturn([row.id]);
+      if (res.code === 200) {
+        ElMessage.success("鍒犻櫎鎴愬姛");
+        await loadReturnList();
+      } else {
+        ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+      }
+    } catch (error) {
+      ElMessage.error("鍒犻櫎澶辫触锛岃閲嶈瘯");
+    }
+  }).catch(() => {
+    ElMessage.info("宸插彇娑堝垹闄�");
+  });
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+  if (selectedRows.value.length === 0) {
+    ElMessage.warning("璇烽�夋嫨瑕佸垹闄ょ殑璁板綍");
+    return;
+  }
+  
+  ElMessageBox.confirm(
+    `纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.value.length} 鏉″綊杩樿褰曞悧锛焋,
+    "鎵归噺鍒犻櫎鎻愮ず",
+    {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }
+  ).then(async () => {
+    try {
+      const selectedIds = selectedRows.value.map(row => row.id);
+      const res = await deleteReturn(selectedIds);
+      if (res.code === 200) {
+        ElMessage.success("鎵归噺鍒犻櫎鎴愬姛");
+        await loadReturnList();
+      } else {
+        ElMessage.error(res.msg || "鎵归噺鍒犻櫎澶辫触");
+      }
+    } catch (error) {
+      ElMessage.error("鎵归噺鍒犻櫎澶辫触锛岃閲嶈瘯");
+    }
+  }).catch(() => {
+    ElMessage.info("宸插彇娑堝垹闄�");
+  });
+};
+
+// 閫夋嫨鍙樺寲浜嬩欢
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+
+// 澶勭悊鍒嗛〉鍙樺寲
+const handlePagination = (current, size) => {
+  pagination.currentPage = current;
+  pagination.pageSize = size;
+  loadReturnList();
+};
+
+// 澶勭悊鏂囨。閫夋嫨鍙樺寲
+const handleDocumentChange = (documentId) => {
+  if (documentId) {
+    // 鏍规嵁閫夋嫨鐨勬枃妗D锛屼粠鏂囨。鍒楄〃涓煡鎵惧搴旂殑鏂囨。淇℃伅
+    const selectedDoc = documentList.value.find(doc => doc.id === documentId);
+    if (selectedDoc) {
+      // 鑷姩濉厖鍊熼槄浜哄拰搴斿綊杩樻棩鏈�
+      returnForm.borrower = selectedDoc.borrower || selectedDoc.borrowerName || '';
+      returnForm.dueReturnDate = selectedDoc.dueReturnDate || selectedDoc.expectedReturnDate || '';
+    }
+  } else {
+    // 娓呯┖鐩稿叧瀛楁
+    returnForm.borrower = '';
+    returnForm.dueReturnDate = '';
+  }
+};
+
+// 鐢熷懡鍛ㄦ湡
+onMounted(() => {
+  initData();
+});
+</script>
+
+<style scoped>
+.return-view {
+  padding: 20px;
+}
+
+.search-container {
+  background: #ffffff;
+  padding: 20px;
+  border-radius: 8px;
+  margin-bottom: 20px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.search-form {
+  margin: 0;
+}
+
+.table-container {
+  background: #ffffff;
+  border-radius: 8px;
+  overflow: hidden;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.empty-data {
+  text-align: center;
+  color: #909399;
+  padding: 40px;
+  font-size: 14px;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+
+:deep(.el-form-item__label) {
+  font-weight: 500;
+  color: #303133;
+}
+
+:deep(.el-input__wrapper) {
+  box-shadow: 0 0 0 1px #dcdfe6 inset;
+}
+
+:deep(.el-input__wrapper:hover) {
+  box-shadow: 0 0 0 1px #c0c4cc inset;
+}
+
+:deep(.el-input__wrapper.is-focus) {
+  box-shadow: 0 0 0 1px #409eff inset;
+}
+</style>
diff --git a/src/views/fileManagement/statistics/index.vue b/src/views/fileManagement/statistics/index.vue
new file mode 100644
index 0000000..42b81e4
--- /dev/null
+++ b/src/views/fileManagement/statistics/index.vue
@@ -0,0 +1,539 @@
+<template>
+  <div class="app-container statistics-container">
+
+    <!-- 鎬讳綋缁熻鍗$墖 -->
+    <el-row :gutter="20" class="statistics-cards">
+      <el-col :span="6" v-for="(item, index) in overviewData" :key="index">
+        <el-card class="statistics-card" :class="item.type">
+          <div class="card-content">
+            <div class="card-icon">
+              <el-icon :size="32">
+                <component :is="item.icon" />
+              </el-icon>
+            </div>
+            <div class="card-info">
+              <div class="card-number">
+                <el-skeleton-item v-if="loading" variant="text" style="width: 60px; height: 32px;" />
+                <span v-else>{{ item.value }}</span>
+              </div>
+              <div class="card-label">{{ item.label }}</div>
+            </div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <!-- 鍥捐〃鍖哄煙 -->
+    <el-row :gutter="20" class="charts-section">
+      <el-col :span="12">
+        <el-card class="chart-card">
+          <template #header>
+            <div class="card-header">
+              <span>妗f鍒嗙被缁熻</span>
+            </div>
+          </template>
+          <div class="chart-container">
+            <div ref="categoryChartRef" class="chart"></div>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="12">
+        <el-card class="chart-card">
+          <template #header>
+            <div class="card-header">
+              <span>妗f鐘舵�佺粺璁�</span>
+            </div>
+          </template>
+          <div class="chart-container">
+            <div ref="statusChartRef" class="chart"></div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted, nextTick, onUnmounted } from "vue";
+import { ElMessage } from "element-plus";
+import { Refresh } from "@element-plus/icons-vue";
+import * as echarts from "echarts";
+import { 
+  getDocumentationOverview, 
+  getDocumentationCategoryStats, 
+  getDocumentationStatusStats 
+} from "@/api/fileManagement/document";
+import { 
+  Document, 
+  Folder, 
+  Tickets, 
+  Calendar 
+} from "@element-plus/icons-vue";
+
+// 鍝嶅簲寮忔暟鎹�
+const overviewData = ref([
+  {
+    label: "鎬绘。妗堟暟",
+    value: 0,
+    icon: "Document",
+    type: "primary",
+  },
+  {
+    label: "鍒嗙被鏁伴噺",
+    value: 0,
+    icon: "Folder",
+    type: "success",
+  },
+  {
+    label: "鍊熷嚭妗f",
+    value: 0,
+    icon: "Tickets",
+    type: "warning",
+  },
+  {
+    label: "鏈湀鏂板",
+    value: 0,
+    icon: "Calendar",
+    type: "info",
+  },
+]);
+
+const categoryChartRef = ref(null);
+const statusChartRef = ref(null);
+
+// 鍥捐〃瀹炰緥
+let categoryChart = null;
+let statusChart = null;
+
+// 鍔犺浇鐘舵��
+const loading = ref(false);
+const autoRefreshInterval = ref(null);
+
+// 鑷姩鍒锋柊寮�鍏�
+const autoRefreshEnabled = ref(true);
+
+// 鑷姩鍒锋柊闂撮殧锛�5鍒嗛挓锛�
+const AUTO_REFRESH_INTERVAL = 5 * 60 * 1000;
+
+// 鍚姩鑷姩鍒锋柊
+const startAutoRefresh = () => {
+  if (autoRefreshInterval.value) {
+    clearInterval(autoRefreshInterval.value);
+  }
+  if (autoRefreshEnabled.value) {
+    autoRefreshInterval.value = setInterval(() => {
+      refreshData();
+    }, AUTO_REFRESH_INTERVAL);
+  }
+};
+
+// 鍋滄鑷姩鍒锋柊
+const stopAutoRefresh = () => {
+  if (autoRefreshInterval.value) {
+    clearInterval(autoRefreshInterval.value);
+    autoRefreshInterval.value = null;
+  }
+};
+
+// 鍒囨崲鑷姩鍒锋柊鐘舵��
+const toggleAutoRefresh = (value) => {
+  if (value) {
+    startAutoRefresh();
+  } else {
+    stopAutoRefresh();
+  }
+};
+
+// 鍔犺浇鎬讳綋缁熻鏁版嵁
+const loadOverviewData = async () => {
+  try {
+    const response = await getDocumentationOverview();
+    if (response.code === 200) {
+      const data = response.data;
+      overviewData.value[0].value = data.totalDocsCount || 0;
+      overviewData.value[1].value = data.categoryNumCount || 0;
+      overviewData.value[2].value = data.borrowedDocsCount || 0;
+      overviewData.value[3].value = data.monthlyAddedDocsCount || 0;
+    }
+  } catch (error) {
+    console.error('鍔犺浇鎬讳綋缁熻鏁版嵁澶辫触:', error);
+    ElMessage.error('鍔犺浇鎬讳綋缁熻鏁版嵁澶辫触');
+  }
+};
+
+// 鍔犺浇鍒嗙被缁熻鏁版嵁
+const loadCategoryData = async () => {
+  try {
+    const response = await getDocumentationCategoryStats();
+    if (response.code === 200) {
+      renderCategoryChart(response.data);
+    }
+  } catch (error) {
+    console.error('鍔犺浇鍒嗙被缁熻鏁版嵁澶辫触:', error);
+    ElMessage.error('鍔犺浇鍒嗙被缁熻鏁版嵁澶辫触');
+  }
+};
+
+// 鍔犺浇鐘舵�佺粺璁℃暟鎹�
+const loadStatusData = async () => {
+  try {
+    const response = await getDocumentationStatusStats();
+    if (response.code === 200) {
+      renderStatusChart(response.data);
+    }
+  } catch (error) {
+    console.error('鍔犺浇鐘舵�佺粺璁℃暟鎹け璐�:', error);
+    ElMessage.error('鍔犺浇鐘舵�佺粺璁℃暟鎹け璐�');
+  }
+};
+
+// 鍒锋柊鏁版嵁
+const refreshData = async () => {
+  loading.value = true;
+  try {
+    await Promise.all([
+      loadOverviewData(),
+      loadCategoryData(),
+      loadStatusData()
+    ]);
+    ElMessage.success('鏁版嵁鍒锋柊鎴愬姛');
+  } catch (error) {
+    console.error('鍒锋柊鏁版嵁澶辫触:', error);
+    ElMessage.error('鍒锋柊鏁版嵁澶辫触');
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 鍒濆鍖栧浘琛�
+const initCharts = () => {
+  // 寤惰繜鍒濆鍖栵紝纭繚DOM鍏冪礌宸茬粡娓叉煋
+  setTimeout(() => {
+    if (categoryChartRef.value) {
+      categoryChart = echarts.init(categoryChartRef.value);
+    }
+    
+    if (statusChartRef.value) {
+      statusChart = echarts.init(statusChartRef.value);
+    }
+    
+    // 鍒濆鍖栧畬鎴愬悗鍔犺浇鏁版嵁
+    loadCategoryData();
+    loadStatusData();
+  }, 300);
+};
+
+// 娓叉煋鍒嗙被缁熻鍥捐〃
+const renderCategoryChart = (data) => {
+  if (!categoryChart) return;
+  let newData = data.map(item => {
+    return {
+      name: item.category,
+      value: item.count
+    }
+  })
+  
+  const option = {
+    title: {
+      text: "妗f鍒嗙被鍒嗗竷",
+      left: "center",
+      textStyle: {
+        fontSize: 16,
+        fontWeight: "normal",
+      },
+    },
+    tooltip: {
+      trigger: "item",
+      formatter: "{a} <br/>{b}: {c} ({d}%)",
+    },
+    legend: {
+      orient: "vertical",
+      left: "left",
+      top: "middle",
+    },
+    series: [
+      {
+        name: "妗f鏁伴噺",
+        type: "pie",
+        radius: ["40%", "70%"],
+        center: ["60%", "50%"],
+        data: newData || [
+          { name: "鎶�鏈枃妗�", value: 450 },
+          { name: "绠$悊鏂囨。", value: 320 },
+          { name: "璐㈠姟鏂囨。", value: 280 },
+          { name: "浜轰簨鏂囨。", value: 200 },
+        ],
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 10,
+            shadowOffsetX: 0,
+            shadowColor: "rgba(0, 0, 0, 0.5)",
+          },
+        },
+      },
+    ],
+  };
+  
+  try {
+    categoryChart.setOption(option);
+  } catch (error) {
+    console.error('鍒嗙被鍥捐〃娓叉煋澶辫触:', error);
+  }
+};
+
+// 娓叉煋鐘舵�佺粺璁″浘琛�
+const renderStatusChart = (data) => {
+  if (!statusChart) return;
+  let newData = data.map(item => {
+    return {
+      name: item.docStatus,
+      value: item.count
+    }
+  })
+  const option = {
+    title: {
+      text: "妗f鐘舵�佸垎甯�",
+      left: "center",
+      textStyle: {
+        fontSize: 16,
+        fontWeight: "normal",
+      },
+    },
+    tooltip: {
+      trigger: "item",
+      formatter: "{a} <br/>{b}: {c} ({d}%)",
+    },
+    legend: {
+      orient: "vertical",
+      left: "left",
+      top: "middle",
+    },
+    series: [
+      {
+        name: "妗f鏁伴噺",
+        type: "pie",
+        radius: ["40%", "70%"],
+        center: ["60%", "50%"],
+        roseType: false,
+        data: newData || [
+          { name: "姝e父", value: 1150, itemStyle: { color: "#67C23A" } },
+          { name: "鍊熷嚭", value: 89, itemStyle: { color: "#E6A23C" } },
+          { name: "涓㈠け", value: 8, itemStyle: { color: "#F56C6C" } },
+          { name: "鎹熷潖", value: 4, itemStyle: { color: "#909399" } },
+        ],
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 10,
+            shadowOffsetX: 0,
+            shadowColor: "rgba(0, 0, 0, 0.5)",
+          },
+        },
+      },
+    ],
+  };
+  
+  try {
+    statusChart.setOption(option);
+  } catch (error) {
+    console.error('鐘舵�佸浘琛ㄦ覆鏌撳け璐�:', error);
+  }
+};
+
+onMounted(() => {
+  loadOverviewData();
+  initCharts();
+  startAutoRefresh();
+});
+
+// 缁勪欢鍗歌浇鏃舵竻鐞嗗畾鏃跺櫒
+onUnmounted(() => {
+  stopAutoRefresh();
+});
+</script>
+
+<style scoped>
+.statistics-container {
+  padding: 20px;
+  background-color: #f5f7fa;
+  min-height: 100vh;
+}
+
+.page-header {
+  text-align: center;
+  margin-bottom: 30px;
+  padding: 20px;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  border-radius: 12px;
+  color: white;
+}
+
+.page-header h2 {
+  color: white;
+  margin-bottom: 10px;
+  font-size: 28px;
+  font-weight: 600;
+}
+
+.page-header p {
+  color: rgba(255, 255, 255, 0.9);
+  font-size: 14px;
+  margin: 0 0 15px 0;
+}
+
+.header-controls {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin-top: 10px;
+  gap: 20px;
+}
+
+.refresh-btn {
+  margin-left: 20px;
+}
+
+.statistics-cards {
+  margin-bottom: 30px;
+}
+
+.statistics-card {
+  border-radius: 12px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  transition: all 0.3s ease;
+  border: none;
+  overflow: hidden;
+}
+
+.statistics-card:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+}
+
+.statistics-card.primary {
+  border-left: 4px solid #409EFF;
+  background: linear-gradient(135deg, #409EFF 0%, #36a3f7 100%);
+}
+
+.statistics-card.success {
+  border-left: 4px solid #67C23A;
+  background: linear-gradient(135deg, #67C23A 0%, #85ce61 100%);
+}
+
+.statistics-card.warning {
+  border-left: 4px solid #E6A23C;
+  background: linear-gradient(135deg, #E6A23C 0%, #ebb563 100%);
+}
+
+.statistics-card.info {
+  border-left: 4px solid #909399;
+  background: linear-gradient(135deg, #909399 0%, #a6a9ad 100%);
+}
+
+.card-content {
+  display: flex;
+  align-items: center;
+  padding: 20px;
+}
+
+.card-icon {
+  margin-right: 20px;
+  color: white;
+}
+
+.card-info {
+  flex: 1;
+}
+
+.card-number {
+  font-size: 32px;
+  font-weight: 600;
+  color: white;
+  margin-bottom: 5px;
+}
+
+.card-label {
+  font-size: 14px;
+  color: rgba(255, 255, 255, 0.9);
+}
+
+.charts-section {
+  margin-bottom: 30px;
+}
+
+.chart-card {
+  border-radius: 12px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  border: none;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  font-weight: 600;
+  color: #303133;
+  padding: 15px 20px;
+  border-bottom: 1px solid #ebeef5;
+}
+
+.chart-container {
+  height: 400px;
+  padding: 20px;
+}
+
+.chart {
+  width: 100%;
+  height: 100%;
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+  .statistics-container {
+    padding: 10px;
+  }
+  
+  .page-header {
+    padding: 15px;
+  }
+  
+  .page-header h2 {
+    font-size: 24px;
+  }
+  
+  .header-controls {
+    flex-direction: column;
+    gap: 15px;
+  }
+  
+  .refresh-btn {
+    margin-left: 0;
+  }
+  
+  .statistics-cards .el-col {
+    margin-bottom: 15px;
+  }
+  
+  .charts-section .el-col {
+    margin-bottom: 20px;
+  }
+  
+  .chart-container {
+    height: 300px;
+  }
+}
+
+@media (max-width: 480px) {
+  .page-header h2 {
+    font-size: 20px;
+  }
+  
+  .card-number {
+    font-size: 24px;
+  }
+  
+  .chart-container {
+    height: 250px;
+  }
+}
+</style>
diff --git a/src/views/index.vue b/src/views/index.vue
index 5c23f5e..0e7fdcf 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -68,11 +68,11 @@
 					<li v-for="item in todoList" :key="item.id">
 						<div style="display: flex;flex-direction: column;justify-content: space-between;width: 100%;gap: 20px">
 							<div style="display: flex;justify-content: space-between;align-items: center;">
-								<div class="todo-title">娴佺▼缂栧彿锛歿{item.approveId}}</div>
-								<div class="todo-division">鐢宠閮ㄩ棬锛歿{item.approveDeptName}}</div>
+								<div class="todo-title">寰呭姙缂栧彿锛歿{item.approveId}}</div>
+								<div class="todo-division">閮ㄩ棬锛歿{item.approveDeptName}}</div>
 								<div class="todo-time">{{item.approveTime}}</div>
 							</div>
-							<div class="todo-division">瀹℃壒浜嬬敱锛歿{item.approveReason}}</div>
+							<div class="todo-division">寰呭姙浜嬬敱锛歿{item.approveReason}}</div>
 						</div>
 					</li>
 				</ul>
diff --git a/src/views/inventoryManagement/index.vue b/src/views/inventoryManagement/index.vue
new file mode 100644
index 0000000..5e97bcb
--- /dev/null
+++ b/src/views/inventoryManagement/index.vue
@@ -0,0 +1,309 @@
+<template>
+	<div class="app-container">
+		<div class="search_form">
+			<div>
+				<span class="search_title">鍙戞斁瀛e害锛�</span>
+				<el-select
+					style="width: 200px;"
+					@change="handleQuery"
+					v-model="searchForm.season"
+					placeholder="璇烽�夋嫨"
+					:clearable="false"
+				>
+					<el-option :label="item.label" :value="item.value" v-for="(item,index) in jidu" :key="item.value" />
+				</el-select>
+				<span class="search_title ml10">鍛樺伐鍚嶇О锛�</span>
+				<el-input
+					v-model="searchForm.staffName"
+					style="width: 240px"
+					placeholder="璇疯緭鍏�"
+					@change="handleQuery"
+					clearable
+					prefix-icon="Search"
+				/>
+				<el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+				>鎼滅储</el-button
+				>
+			</div>
+			<div>
+				<el-button type="primary" @click="add" icon="Plus"> 鏂板 </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>
+			</div>
+		</div>
+		<div class="table_list">
+			<el-table
+				ref="tableRef"
+				v-loading="tableLoading"
+				:data="tableData"
+				border
+				height="calc(100vh - 21em)"
+				:header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+				style="width: 100%"
+				@selection-change="handleSelectionChange"
+			>
+				<!-- 閫夋嫨鍒� -->
+				<el-table-column
+					align="center"
+					type="selection"
+					width="55"
+					fixed="left"
+				/>
+				
+				<!-- 搴忓彿鍒� -->
+				<el-table-column
+					align="center"
+					label="搴忓彿"
+					type="index"
+					width="60"
+					fixed="left"
+				/>
+				
+				<!-- 鍥哄畾鍒楋細濮撳悕 -->
+				<el-table-column
+					label="濮撳悕"
+					prop="staffName"
+					width="100"
+					show-overflow-tooltip
+					align="center"
+					fixed="left"
+				/>
+				
+				<!-- 鍥哄畾鍒楋細宸ュ彿 -->
+				<el-table-column
+					label="宸ュ彿"
+					prop="staffNo"
+					width="100"
+					show-overflow-tooltip
+					align="center"
+					fixed="left"
+				/>
+				
+				<!-- 鍔ㄦ�佸垪锛氭牴鎹瓧鍏告覆鏌� -->
+				<el-table-column
+					v-for="(dictItem, index) in sys_lavor_issue"
+					:key="dictItem.value"
+					:label="dictItem.label"
+					:prop="dictItem.value"
+					show-overflow-tooltip
+				>
+				</el-table-column>
+				
+				<!-- 鎿嶄綔鍒� -->
+				<el-table-column
+					label="鎿嶄綔"
+					width="150"
+					align="center"
+					fixed="right"
+				>
+					<template #default="scope">
+						<el-button
+							type="primary"
+							link
+							size="small"
+							@click="edit(scope.row)"
+						>
+							缂栬緫
+						</el-button>
+						<el-button
+							type="danger"
+							link
+							size="small"
+							:disabled="!!scope.row.adoptedDate"
+							@click="adopted(scope.row)"
+						>
+							棰嗙敤
+						</el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+			<pagination :total="total" layout="total, sizes, prev, pager, next, jumper"
+									:page="page.current" :limit="page.size" @pagination="paginationChange" />
+		</div>
+		<Modal ref="modalRef" @success="handleQuery"></Modal>
+		<files-dia ref="filesDia"></files-dia>
+	</div>
+</template>
+
+<script setup>
+import { ref, onMounted, reactive, toRefs, nextTick, getCurrentInstance } from 'vue'
+import dayjs from "dayjs";
+import Modal from "./Modal.vue";
+import FilesDia from "./filesDia.vue";
+import Pagination from "@/components/Pagination/index.vue";
+import {lavorIssueListPage, deleteLedger, update} from "@/api/lavorissce/ledger.js";
+import {ElMessageBox, ElMessage} from "element-plus";
+const { proxy } = getCurrentInstance();
+import { getCurrentMonth } from "@/utils/util"
+
+const page = ref({
+	current: 1,
+	size: 100,
+})
+const total = ref(0)
+// 鍝嶅簲寮忔暟鎹�
+const tableRef = ref(null)
+const tableData = ref([])
+const tableLoading = ref(false)
+const { sys_lavor_issue } = proxy.useDict("sys_lavor_issue")
+const data = reactive({
+	searchForm: {
+		season: "",
+		staffName: "",
+	},
+});
+const { searchForm } = toRefs(data);
+
+const modalRef = ref();
+const filesDia = ref();
+const multipleList = ref([]);
+const jidu = ref([
+	{
+		value: '1',
+		label: '绗竴瀛e害'
+	},
+	{
+		value: '2',
+		label: '绗簩瀛e害'
+	},
+	{
+		value: '3',
+		label: '绗笁瀛e害'
+	},
+	{
+		value: '4',
+		label: '绗洓瀛e害'
+	}
+])
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+	page.value.current = 1;
+	getList();
+};
+// 鑾峰彇瀛楀吀鏁版嵁
+const getList = async () => {
+	tableLoading.value = true;
+	const params = { ...searchForm.value, ...page.value };
+	lavorIssueListPage(params).then(res => {
+		tableLoading.value = false;
+		tableData.value = res.data.records;
+		total.value = res.data.total;
+	}).catch(err => {
+		tableLoading.value = false;
+	})
+}
+const add = () => {
+	modalRef.value.openModal();
+};
+const edit = (row) => {
+	modalRef.value.loadForm(row);
+};
+const deleteRow = (id) => {
+	ElMessageBox.confirm("姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ暟鎹�, 鏄惁缁х画?", "鎻愮ず", {
+		confirmButtonText: "纭畾",
+		cancelButtonText: "鍙栨秷",
+		type: "warning",
+	}).then(async () => {
+		const { code } = await deleteLedger(id);
+		if (code == 200) {
+			ElMessage({
+				type: "success",
+				message: "鍒犻櫎鎴愬姛",
+			});
+			await getList();
+		}
+	});
+};
+const handleOut = () => {
+	ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+		confirmButtonText: "纭",
+		cancelButtonText: "鍙栨秷",
+		type: "warning",
+	})
+		.then(() => {
+			proxy.download(`/lavorIssue/exportCopy`, {season: searchForm.value.season}, "鍔充繚鍙拌处.xlsx");
+		})
+		.catch(() => {
+			ElMessage.info("宸插彇娑�");
+		});
+};
+const adopted = (row) => {
+	ElMessageBox.confirm("鏄惁纭棰嗙敤?", "鎻愮ず", {
+		confirmButtonText: "纭畾",
+		cancelButtonText: "鍙栨秷",
+		type: "warning",
+	}).then(async () => {
+		const params = {
+			id: row.id,
+			adoptedDate: dayjs().format("YYYY-MM-DD")
+		}
+		const { code } = await update(params);
+		if (code == 200) {
+			ElMessage({
+				type: "success",
+				message: "棰嗙敤鎴愬姛",
+			});
+			await getList();
+		}
+	})
+}
+// 鎵撳紑闄勪欢寮规
+const openFilesFormDia = (row) => {
+	nextTick(() => {
+		filesDia.value?.openDialog( row,'鏀跺叆')
+	})
+};
+// 浜嬩欢澶勭悊鍑芥暟
+const handleSelectionChange = (selection) => {
+	multipleList.value = selection;
+}
+
+const paginationChange = (pagination) => {
+	page.value.current = pagination.page;
+	page.value.size = pagination.limit;
+	getList();
+}
+
+// 缁勪欢鎸傝浇鏃跺姞杞藉瓧鍏告暟鎹�
+onMounted(() => {
+	handleQuery()
+})
+</script>
+
+<style scoped>
+.dynamic-table-container {
+	width: 100%;
+}
+
+.pagination-container {
+	margin-top: 20px;
+	display: flex;
+	justify-content: flex-end;
+}
+
+:deep(.el-table .el-table__header-wrapper th) {
+	background-color: #F0F1F5 !important;
+	color: #333333;
+	font-weight: 600;
+}
+
+:deep(.el-table .el-table__body-wrapper td) {
+	padding: 8px 0;
+}
+
+:deep(.el-select) {
+	width: 100%;
+}
+
+:deep(.el-input) {
+	width: 100%;
+}
+</style>
diff --git a/src/views/lavorissue/ledger/Form.vue b/src/views/lavorissue/ledger/Form.vue
new file mode 100644
index 0000000..7031957
--- /dev/null
+++ b/src/views/lavorissue/ledger/Form.vue
@@ -0,0 +1,154 @@
+<template>
+  <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
+    <el-form-item label="閮ㄩ棬鍚嶇О" prop="deptId">
+      <el-select
+          v-model="form.deptId"
+          placeholder="璇烽�夋嫨"
+          clearable
+          disabled
+      >
+        <el-option :label="item.deptName" :value="item.deptId" v-for="(item,index) in productOptions" :key="deptId" />
+      </el-select>
+        </el-form-item>
+        <el-form-item label="鍛樺伐鍚嶇О" prop="staffId">
+          <el-select
+            v-model="form.staffId"
+            placeholder="璇烽�夋嫨"
+            clearable
+          >
+            <el-option :label="item.staffName" :value="item.id" v-for="(item,index) in personList" :key="id" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鍔充繚绫诲瀷" prop="dictType">
+          <el-select
+              v-model="form.dictType"
+              placeholder="璇烽�夋嫨"
+              clearable
+          >
+            <el-option :label="item.label" :value="item.value" v-for="(item,index) in sys_lavor_issue_type" :key="value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鍔充繚闃插叿" prop="dictId">
+          <el-select
+              v-model="form.dictId"
+              placeholder="璇烽�夋嫨"
+              clearable
+          >
+            <el-option :label="item.label" :value="item.value" v-for="(item,index) in sys_lavor_issue" :key="value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鍙戞斁鏁伴噺" prop="num">
+          <el-input-number :step="1" :min="0" style="width: 100%"
+            v-model="form.num"
+            placeholder="璇疯緭鍏�"
+          />
+        </el-form-item>
+        <el-form-item label="杩涘巶鏃ユ湡" prop="factoryDate">
+          <el-date-picker
+              style="width: 100%"
+              v-model="form.factoryDate"
+              format="YYYY-MM-DD"
+              value-format="YYYY-MM-DD"
+              type="date"
+              placeholder="璇烽�夋嫨鏃ユ湡"
+              clearable
+          />
+        </el-form-item>
+    <el-form-item label="鍙戞斁鏃ユ湡" prop="issueDate">
+      <el-date-picker
+          style="width: 100%"
+          v-model="form.issueDate"
+          format="YYYY-MM-DD"
+          value-format="YYYY-MM-DD"
+          type="date"
+          placeholder="璇烽�夋嫨鏃ユ湡"
+          clearable
+      />
+    </el-form-item>
+        
+  </el-form>
+</template>
+
+<script setup>
+import useFormData from "@/hooks/useFormData";
+import {ref,onMounted} from "vue";
+import useUserStore from "@/store/modules/user";
+import {getStaffOnJob} from "@/api/personnelManagement/onboarding.js";
+import {deepCopySameProperties} from '@/utils/util'
+const userStore = useUserStore();
+import {
+  getDept
+} from "@/api/collaborativeApproval/approvalProcess.js";
+const { proxy } = getCurrentInstance();
+
+
+defineOptions({
+  name: "鏂板鏀跺叆",
+});
+const { sys_lavor_issue } = proxy.useDict("sys_lavor_issue")
+const { sys_lavor_issue_type } = proxy.useDict("sys_lavor_issue_type")
+const formRef = ref(null);
+const productOptions = ref([]);
+const personList = ref([]);
+const formRules = {
+  deptId: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  dictType: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  staffId: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+  dictId: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  num: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  adoptedDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  factoryDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+  issueDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+}
+
+const { form, resetForm } = useFormData({
+  deptId: undefined, //
+  dictType: undefined,
+  staffId: undefined, //
+  dictId: undefined, //
+  num: undefined, //
+  adoptedDate: undefined,
+  factoryDate: undefined,
+  issueDate: undefined,
+});
+const getPersonList = () => {
+  getStaffOnJob().then(res => {
+    personList.value = res.data
+  })
+};
+const loadForm = (data) => {
+  deepCopySameProperties(data, form)
+};
+
+const getProductOptions = () => {
+  getDept().then((res) => {
+    productOptions.value = res.data;
+  });
+}
+// 娓呴櫎琛ㄥ崟鏍¢獙鐘舵��
+const clearValidate = () => {
+  formRef.value?.clearValidate();
+};
+
+// 閲嶇疆琛ㄥ崟鏁版嵁鍜屾牎楠岀姸鎬�
+const resetFormAndValidate = () => {
+  resetForm();
+  clearValidate();
+  form.deptId = userStore.currentDeptId
+  getProductOptions();
+  getPersonList();
+};
+onMounted(() => {
+  form.deptId = userStore.currentDeptId
+  getProductOptions();
+  getPersonList();
+})
+defineExpose({
+  form,
+  resetForm,
+  clearValidate,
+  loadForm,
+  resetFormAndValidate,
+	formRef,
+});
+</script>
diff --git a/src/views/lavorissue/ledger/Modal.vue b/src/views/lavorissue/ledger/Modal.vue
new file mode 100644
index 0000000..5d63236
--- /dev/null
+++ b/src/views/lavorissue/ledger/Modal.vue
@@ -0,0 +1,70 @@
+<template>
+  <el-dialog :title="modalOptions.title" v-model="visible" @close="close" width="30%">
+    <Form ref="formRef"></Form>
+    <template #footer>
+			<el-button type="primary" @click="sendForm" :loading="loading">
+				{{ modalOptions.confirmText }}
+			</el-button>
+      <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { useModal } from "@/hooks/useModal";
+import { add, update } from "@/api/lavorissce/ledger";
+import Form from "./Form.vue";
+import { ElMessage } from "element-plus";
+const { proxy } = getCurrentInstance()
+
+defineOptions({
+  name: "鏀跺叆鏂板缂栬緫",
+});
+
+const emits = defineEmits(["success"]);
+
+const formRef = ref();
+const {
+  id,
+  visible,
+  loading,
+  openModal,
+  modalOptions,
+  handleConfirm,
+  closeModal,
+} = useModal({ title: "鍔充繚鍙拌处" });
+
+const sendForm = () => {
+	proxy.$refs.formRef.$refs.formRef.validate(async valid => {
+		if (valid) {
+			const {code} = id.value
+				? await update({id: id.value, ...formRef.value.form})
+				: await add(formRef.value.form);
+			if (code == 200) {
+				emits("success");
+				ElMessage({message: "鎿嶄綔鎴愬姛", type: "success"});
+				close();
+			} else {
+				loading.value = false;
+			}
+		}
+	})
+};
+
+const close = () => {
+	formRef.value.resetFormAndValidate();
+  closeModal();
+};
+
+const loadForm = async (row) => {
+  openModal(row.id);
+  await nextTick();
+  formRef.value.loadForm(row);
+
+};
+
+defineExpose({
+  openModal,
+  loadForm,
+});
+</script>
diff --git a/src/views/lavorissue/ledger/filesDia.vue b/src/views/lavorissue/ledger/filesDia.vue
new file mode 100644
index 0000000..f752496
--- /dev/null
+++ b/src/views/lavorissue/ledger/filesDia.vue
@@ -0,0 +1,202 @@
+<template>
+  <div>
+    <el-dialog
+        v-model="dialogFormVisible"
+        title="涓婁紶闄勪欢"
+        width="50%"
+        @close="closeDia"
+    >
+      <div style="margin-bottom: 10px;text-align: right">
+        <el-upload
+            v-model:file-list="fileList"
+            class="upload-demo"
+            :action="uploadUrl"
+            :on-success="handleUploadSuccess"
+            :on-error="handleUploadError"
+            name="file"
+            :show-file-list="false"
+            :headers="headers"
+            style="display: inline;margin-right: 10px"
+        >
+          <el-button type="primary">涓婁紶闄勪欢</el-button>
+        </el-upload>
+        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+      </div>
+      <PIMTable
+          rowKey="id"
+          :column="tableColumn"
+          :tableData="tableData"
+          :tableLoading="tableLoading"
+          :isSelection="true"
+          @selection-change="handleSelectionChange"
+          height="500"
+      >
+      </PIMTable>
+			<pagination
+				style="margin: 10px 0"
+				v-show="total > 0"
+				@pagination="paginationSearch"
+				:total="total"
+				:page="page.current"
+				:limit="page.size"
+			/>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="closeDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <filePreview ref="filePreviewRef" />
+  </div>
+</template>
+
+<script setup>
+import {ref} from "vue";
+import {ElMessageBox} from "element-plus";
+import {getToken} from "@/utils/auth.js";
+import filePreview from '@/components/filePreview/index.vue'
+import {
+  fileAdd,
+  fileDel,
+  fileListPage
+} from "@/api/financialManagement/revenueManagement.js";
+import Pagination from "@/components/PIMTable/Pagination.vue";
+const { proxy } = getCurrentInstance()
+const emit = defineEmits(['close'])
+
+const dialogFormVisible = ref(false);
+const currentId = ref('')
+const selectedRows = ref([]);
+const filePreviewRef = ref()
+const tableColumn = ref([
+  {
+    label: "鏂囦欢鍚嶇О",
+    prop: "name",
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    operation: [
+      {
+        name: "涓嬭浇",
+        type: "text",
+        clickFun: (row) => {
+          downLoadFile(row);
+        },
+      },
+      {
+        name: "棰勮",
+        type: "text",
+        clickFun: (row) => {
+          lookFile(row);
+        },
+      }
+    ],
+  },
+]);
+const page = reactive({
+	current: 1,
+	size: 100,
+});
+const total = ref(0);
+const tableData = ref([]);
+const fileList = ref([]);
+const tableLoading = ref(false);
+const accountType = ref('')
+const headers = ref({
+  Authorization: "Bearer " + getToken(),
+});
+const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃
+
+// 鎵撳紑寮规
+const openDialog = (row,type) => {
+  accountType.value = type;
+  dialogFormVisible.value = true;
+  currentId.value = row.id;
+  getList()
+}
+const paginationSearch = (obj) => {
+	page.current = obj.page;
+	page.size = obj.limit;
+	getList();
+};
+const getList = () => {
+  fileListPage({accountId: currentId.value,accountType:accountType.value, ...page}).then(res => {
+    tableData.value = res.data.records;
+		total.value = res.data.total;
+  })
+}
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+
+// 鍏抽棴寮规
+const closeDia = () => {
+  dialogFormVisible.value = false;
+  emit('close')
+};
+// 涓婁紶鎴愬姛澶勭悊
+function handleUploadSuccess(res, file) {
+  // 濡傛灉涓婁紶鎴愬姛
+  if (res.code == 200) {
+    const fileRow = {}
+    fileRow.name = res.data.originalName
+    fileRow.url = res.data.tempPath
+    uploadFile(fileRow)
+  } else {
+    proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+  }
+}
+function uploadFile(file) {
+  file.accountId = currentId.value;
+  file.accountType = accountType.value;
+  fileAdd(file).then(res => {
+    proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+    getList()
+  })
+}
+// 涓婁紶澶辫触澶勭悊
+function handleUploadError() {
+  proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+}
+// 涓嬭浇闄勪欢
+const downLoadFile = (row) => {
+  proxy.$download.name(row.url);
+}
+// 鍒犻櫎
+const handleDelete = () => {
+  let ids = [];
+  if (selectedRows.value.length > 0) {
+    ids = selectedRows.value.map((item) => item.id);
+  } else {
+    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(() => {
+    fileDel(ids).then((res) => {
+      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      getList();
+    });
+  }).catch(() => {
+    proxy.$modal.msg("宸插彇娑�");
+  });
+};
+// 棰勮闄勪欢
+const lookFile = (row) => {
+  filePreviewRef.value.open(row.url)
+}
+
+defineExpose({
+  openDialog,
+});
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/lavorissue/ledger/index.vue b/src/views/lavorissue/ledger/index.vue
new file mode 100644
index 0000000..6b7e5a8
--- /dev/null
+++ b/src/views/lavorissue/ledger/index.vue
@@ -0,0 +1,300 @@
+<template>
+  <div class="app-container">
+    <el-form :model="filters" :inline="true">
+      <el-form-item label="鍙戞斁瀛e害:" prop="season">
+        <el-select
+            style="width: 200px;"
+            @change="handleQuery"
+            v-model="filters.season"
+            placeholder="璇烽�夋嫨"
+            :clearable="false"
+        >
+          <el-option :label="item.label" :value="item.value" v-for="(item,index) in jidu" :key="value" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍛樺伐鍚嶇О:">
+        <el-input
+            v-model="filters.staffName"
+            style="width: 240px"
+            placeholder="璇疯緭鍏�"
+            @change="handleQuery"
+            clearable
+            prefix-icon="Search"
+        />
+      </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 @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>
+        </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"
+      >
+        <template #operation="{ row }">
+          <el-button type="primary" text @click="edit(row)" icon="editPen">
+            缂栬緫
+          </el-button>
+          <el-button type="primary" :disabled="row.adoptedDate ? true : false" text @click="adopted(row)">
+            棰嗙敤
+          </el-button>
+        </template>
+      </PIMTable>
+    </div>
+    <Modal ref="modalRef" @success="getTableData"></Modal>
+    <files-dia ref="filesDia"></files-dia>
+  </div>
+</template>
+
+<script setup>
+import { usePaginationApi } from "@/hooks/usePaginationApi";
+import { listPage,deleteLedger,update } from "@/api/lavorissce/ledger";
+import { onMounted, getCurrentInstance } from "vue";
+import Modal from "./Modal.vue";
+import { ElMessageBox, ElMessage } from "element-plus";
+import dayjs from "dayjs";
+import FilesDia from "./filesDia.vue";
+import { getCurrentMonth } from "@/utils/util"
+
+// 琛ㄦ牸澶氶�夋閫変腑椤�
+const multipleList = ref([]);
+const { proxy } = getCurrentInstance();
+const modalRef = ref();
+const { payment_methods } = proxy.useDict("payment_methods");
+const { income_types } = proxy.useDict("income_types");
+const filesDia = ref()
+
+const {
+  filters,
+  columns,
+  dataList,
+  pagination,
+  getTableData,
+  resetFilters,
+  onCurrentChange,
+} = usePaginationApi(
+    listPage,
+    {
+      staffName: '',
+      season: getCurrentMonth(),
+    },
+    [
+      {
+        label: "鍔充繚鍗曞彿",
+        align: "center",
+        prop: "orderNo",
+      },
+      {
+        label: "鍛樺伐鍚嶇О",
+        align: "center",
+        prop: "staffName",
+      },
+      {
+        label: "鍛樺伐缂栧彿",
+        align: "center",
+        prop: "staffNo"
+      },
+
+      {
+        label: "鍔充繚绫诲瀷",
+        align: "center",
+        prop: "dictTypeName",
+
+      },
+      {
+        label: "鍔充繚闃插叿",
+        align: "center",
+        prop: "dictName",
+
+      },
+      {
+        label: "鍙戞斁鏁伴噺",
+        align: "center",
+        prop: "num",
+
+      },
+      {
+        label: "杩涘巶鏃ユ湡",
+        align: "center",
+        prop: "factoryDate",
+
+      },
+      {
+        label: "鍙戞斁鏃ユ湡",
+        align: "center",
+        prop: "issueDate",
+
+      },
+      {
+        label: "棰嗙敤鏃ユ湡",
+        align: "center",
+        prop: "adoptedDate",
+
+      },
+      {
+        fixed: "right",
+        label: "鎿嶄綔",
+        dataType: "slot",
+        slot: "operation",
+        align: "center",
+        width: "200px",
+      },
+    ]
+);
+
+const jidu = ref([
+  {
+    value: '1',
+    label: '绗竴瀛e害'
+  },
+  {
+    value: '2',
+    label: '绗簩瀛e害'
+  },
+  {
+    value: '3',
+    label: '绗笁瀛e害'
+  },
+  {
+    value: '4',
+    label: '绗洓瀛e害'
+  }
+])
+
+// 澶氶�夊悗鍋氫粈涔�
+const handleSelectionChange = (selectionList) => {
+  multipleList.value = selectionList;
+};
+
+const adopted = (row) => {
+  ElMessageBox.confirm("鏄惁纭棰嗙敤?", "鎻愮ず", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(async () => {
+    const params = {
+      id: row.id,
+      adoptedDate: dayjs().format("YYYY-MM-DD")
+    }
+    const { code } = await update(params);
+    if (code == 200) {
+      ElMessage({
+        type: "success",
+        message: "棰嗙敤鎴愬姛",
+      });
+      getTableData();
+    }
+  })
+}
+
+const add = () => {
+  modalRef.value.openModal();
+};
+const edit = (row) => {
+  modalRef.value.loadForm(row);
+};
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  getTableData();
+};
+const changePage = ({ page, limit }) => {
+  pagination.currentPage = page;
+  pagination.pageSize = limit;
+  onCurrentChange(page);
+};
+const deleteRow = (id) => {
+  ElMessageBox.confirm("姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ暟鎹�, 鏄惁缁х画?", "鎻愮ず", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(async () => {
+    const { code } = await deleteLedger(id);
+    if (code == 200) {
+      ElMessage({
+        type: "success",
+        message: "鍒犻櫎鎴愬姛",
+      });
+      getTableData();
+    }
+  });
+};
+
+const changeDaterange = (value) => {
+  if (value) {
+    filters.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
+    filters.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
+  } else {
+    filters.entryDateStart = undefined;
+    filters.entryDateEnd = undefined;
+  }
+  getTableData();
+};
+
+const handleOut = () => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+      .then(() => {
+        proxy.download(`/lavorIssue/exportCopy`, {season: filters.season}, "鍔充繚鍙拌处.xlsx");
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
+};
+// 鎵撳紑闄勪欢寮规
+const openFilesFormDia = (row) => {
+  nextTick(() => {
+    filesDia.value?.openDialog( row,'鏀跺叆')
+  })
+};
+
+onMounted(() => {
+  filters.entryDate = [
+    dayjs().format("YYYY-MM-DD"),
+    dayjs().add(1, "day").format("YYYY-MM-DD"),
+  ]
+  filters.entryDateStart = dayjs().format("YYYY-MM-DD")
+  filters.entryDateEnd = dayjs().add(1, "day").format("YYYY-MM-DD")
+  getTableData();
+});
+</script>
+
+<style lang="scss" scoped>
+.table_list {
+  margin-top: unset;
+}
+.actions {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 10px;
+}
+</style>
+
diff --git a/src/views/lavorissue/statistics/index.vue b/src/views/lavorissue/statistics/index.vue
new file mode 100644
index 0000000..2c34f67
--- /dev/null
+++ b/src/views/lavorissue/statistics/index.vue
@@ -0,0 +1,285 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <span class="search_title">鍙戞斁瀛e害锛�</span>
+        <el-select
+            style="width: 200px;"
+            @change="handleQuery"
+            v-model="searchForm.season"
+            placeholder="璇烽�夋嫨"
+            @clear="clearSeason"
+            clearable
+            :disabled="searchForm.issueDate ? true : false"
+
+        >
+          <el-option :label="item.label" :value="item.value" v-for="(item,index) in jidu" :key="item.value" />
+        </el-select>
+        <span class="search_title ml10">鍙戞斁鏈堜唤锛�</span>
+        <el-date-picker
+            style="width: 200px;"
+            :disabled="searchForm.season ? true : false"
+            v-model="searchForm.issueDate"
+            @change="handleQuery"
+            @clear="clearIssueDaten"
+            type="month"
+            value-format="YYYY-MM-DD"
+            format="YYYY-MM"
+            placeholder="璇烽�夋嫨鏈堜唤"
+            clearable
+        />
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+        >鎼滅储</el-button
+        >
+        <el-button type="primary" @click="resetHandleQuery" style="margin-left: 10px"
+        >閲嶇疆</el-button
+        >
+      </div>
+      <div>
+        <el-button @click="handleOut" icon="download">瀵煎嚭</el-button>
+      </div>
+    </div>
+    <div class="table_list">
+      <div class="actions">
+        <div class="head" @click="handleQuery(1)">宸查鍙栧姵淇濇暟閲�:{{statisticsObj.ylqNum}}</div>
+        <div class="head" @click="handleQuery(2)">鏈鍙栧姵淇濇暟閲�: {{ statisticsObj.wlqNum }}</div>
+        <div class="head" @click="handleQuery(3)">瓒呮椂宸查鍙栧姵淇濇暟閲�: {{statisticsObj.csylqNum}}</div>
+        <div class="head" @click="handleQuery(4)">瓒呮椂鏈鍙栧姵淇濇暟閲�: {{statisticsObj.cswlqNum}}</div>
+      </div>
+      <el-table
+          ref="tableRef"
+          v-loading="tableLoading"
+          :data="tableData"
+          border
+          height="calc(100vh - 21em)"
+          :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+          style="width: 100%"
+          @selection-change="handleSelectionChange"
+      >
+        <!-- 閫夋嫨鍒� -->
+        <el-table-column
+            align="center"
+            type="selection"
+            width="55"
+            fixed="left"
+        />
+
+        <!-- 搴忓彿鍒� -->
+        <el-table-column
+            align="center"
+            label="搴忓彿"
+            type="index"
+            width="60"
+            fixed="left"
+        />
+
+        <!-- 鍥哄畾鍒楋細濮撳悕 -->
+        <el-table-column
+            label="濮撳悕"
+            prop="staffName"
+            width="100"
+            show-overflow-tooltip
+            align="center"
+            fixed="left"
+        />
+
+        <!-- 鍥哄畾鍒楋細宸ュ彿 -->
+        <el-table-column
+            label="宸ュ彿"
+            prop="staffNo"
+            width="100"
+            show-overflow-tooltip
+            align="center"
+            fixed="left"
+        />
+
+        <!-- 鍔ㄦ�佸垪锛氭牴鎹瓧鍏告覆鏌� -->
+        <el-table-column
+            v-for="(dictItem, index) in sys_lavor_issue"
+            :key="dictItem.value"
+            :label="dictItem.label"
+            :prop="dictItem.value"
+            show-overflow-tooltip
+        >
+        </el-table-column>
+      </el-table>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted, reactive, toRefs, nextTick, getCurrentInstance } from 'vue'
+import dayjs from "dayjs";
+import {statisticsList, statistics} from "@/api/lavorissce/ledger.js";
+import {ElMessageBox, ElMessage} from "element-plus";
+const { proxy } = getCurrentInstance();
+import { getCurrentMonth } from "@/utils/util"
+
+const page = ref({
+  current: 1,
+  size: 100,
+})
+const total = ref(0)
+// 鍝嶅簲寮忔暟鎹�
+const tableRef = ref(null)
+const tableData = ref([])
+const tableLoading = ref(false)
+const { sys_lavor_issue } = proxy.useDict("sys_lavor_issue")
+const data = reactive({
+  searchForm: {
+    season: getCurrentMonth(),
+    issueDate: "",
+    status: 0
+  },
+});
+const { searchForm } = toRefs(data);
+
+const modalRef = ref();
+const filesDia = ref();
+const multipleList = ref([]);
+const jidu = ref([
+  {
+    value: '1',
+    label: '绗竴瀛e害'
+  },
+  {
+    value: '2',
+    label: '绗簩瀛e害'
+  },
+  {
+    value: '3',
+    label: '绗笁瀛e害'
+  },
+  {
+    value: '4',
+    label: '绗洓瀛e害'
+  }
+])
+const clearSeason = () => {
+  console.log("req")
+  searchForm.value.season = ""
+  searchForm.value.issueDate = dayjs().format("YYYY-MM-DD");
+}
+
+const clearIssueDaten = () => {
+  searchForm.value.issueDate = ""
+  searchForm.value.season = getCurrentMonth()
+}
+const statisticsObj = ref({
+  ylqNum: 0,  // 宸查鍙栨暟閲�
+  wlqNum: 0,  // 鏈鍙栨暟閲�
+  csylqNum: 0,  // 瓒呮椂宸查鍙栨暟閲�
+  cswlqNum: 0  // 瓒呮椂鏈鍙栨暟閲�
+})
+const resetHandleQuery = () => {
+  searchForm.value.issueDate = "";
+  searchForm.value.season = getCurrentMonth();
+  handleQuery(0)
+};
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = (status) => {
+  switch (status){
+    case 1:
+      searchForm.value.status = 1
+      break;
+    case 2:
+      searchForm.value.status = 2
+      break;
+    case 3:
+      searchForm.value.status = 3
+      break;
+    case 4:
+      searchForm.value.status = 4
+      break;
+    default:
+      searchForm.value.status = 0
+  }
+  getList();
+  getStatistics();
+};
+
+const getStatistics = () => {
+  statistics(searchForm.value).then(res => {
+    statisticsObj.value.cswlqNum = res.data.cswlqNum
+    statisticsObj.value.csylqNum = res.data.csylqNum
+    statisticsObj.value.ylqNum = res.data.ylqNum
+    statisticsObj.value.wlqNum = res.data.wlqNum
+  })
+}
+// 鑾峰彇瀛楀吀鏁版嵁
+const getList = async () => {
+  tableLoading.value = true;
+  const params = { ...searchForm.value};
+  statisticsList(params).then(res => {
+    tableLoading.value = false;
+    tableData.value = res.data;
+  }).catch(err => {
+    tableLoading.value = false;
+  })
+}
+const handleOut = () => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+      .then(() => {
+        proxy.download(`/lavorIssue/exportCopy`, {season: searchForm.value.season,issueDate: searchForm.value.issueDate}, "鍔充繚鍙拌处.xlsx");
+      })
+      .catch(() => {
+        ElMessage.info("宸插彇娑�");
+      });
+};
+
+// 浜嬩欢澶勭悊鍑芥暟
+const handleSelectionChange = (selection) => {
+  multipleList.value = selection;
+}
+
+// 缁勪欢鎸傝浇鏃跺姞杞藉瓧鍏告暟鎹�
+onMounted(() => {
+  handleQuery()
+})
+</script>
+
+<style scoped>
+.dynamic-table-container {
+  width: 100%;
+}
+
+.pagination-container {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+:deep(.el-table .el-table__header-wrapper th) {
+  background-color: #F0F1F5 !important;
+  color: #333333;
+  font-weight: 600;
+}
+
+:deep(.el-table .el-table__body-wrapper td) {
+  padding: 8px 0;
+}
+
+:deep(.el-select) {
+  width: 100%;
+}
+
+:deep(.el-input) {
+  width: 100%;
+}
+.actions {
+  display: flex;
+  justify-content: space-around;
+  align-items: center;
+  margin-bottom: 30px;
+}
+.head{
+  cursor: pointer;
+  font-size: 18px;
+  font-weight: 600;
+}
+</style>

--
Gitblit v1.9.3