From 75a462f8ee30491f05d29ccac1b65d31e835957b Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期三, 20 八月 2025 15:57:14 +0800
Subject: [PATCH] 档案管理调整

---
 src/views/fileManagement/document/index.vue | 1262 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 1,262 insertions(+), 0 deletions(-)

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>

--
Gitblit v1.9.3