From d9ed7cc8ec13a59b69bd643a9c3e2ccd907fabd1 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期三, 20 八月 2025 15:36:51 +0800
Subject: [PATCH] 档案管理
---
src/views/fileManagement/document/index.vue | 1262 ++++++++++++++++++
src/views/fileManagement/bookshelf/detail.vue | 110 +
src/api/fileManagement/borrow.js | 47
src/views/fileManagement/bookshelf/index.vue | 688 ++++++++++
src/views/fileManagement/return/index.vue | 599 ++++++++
src/views/fileManagement/borrow/index.vue | 584 ++++++++
src/api/fileManagement/return.js | 54
vite.config.js | 6
src/api/fileManagement/document.js | 164 ++
src/api/fileManagement/bookshelf.js | 128 +
src/views/fileManagement/document/attachmentManager.vue | 426 ++++++
11 files changed, 4,065 insertions(+), 3 deletions(-)
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..49b156e
--- /dev/null
+++ b/src/api/fileManagement/document.js
@@ -0,0 +1,164 @@
+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,
+ });
+}
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/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> [{{ n.docNumber }}]</span></template>
+ <li class="green"
+ @click="handelDetail(n)">
+ <i></i>
+ <span>{{ n.docName }}</span>
+ <span> [{{ 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..9a9ee81
--- /dev/null
+++ b/src/views/fileManagement/borrow/index.vue
@@ -0,0 +1,584 @@
+<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: 'documentationId',
+ width: '200',
+ formatData: (params) => {
+ if (!params) return '-';
+ const doc = documentList.value.find(item => item.id === params);
+ return doc ? (doc.docName || doc.name) : params;
+ }
+ },
+ { 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 = (type, data) => {
+ 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..7a8b27e
--- /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 = !(val.children && val.children.length > 0);
+ // 鍙湁鍙跺瓙鑺傜偣鎵嶆墽琛屼互涓嬮�昏緫
+ 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..80724ea
--- /dev/null
+++ b/src/views/fileManagement/return/index.vue
@@ -0,0 +1,599 @@
+<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 v-if="returnList.length === 0" class="empty-data">
+ 鏆傛棤鏁版嵁
+ </div>
+ </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/vite.config.js b/vite.config.js
index b96c1d4..6d04eb7 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -8,8 +8,8 @@
const { VITE_APP_ENV } = env;
const baseUrl =
VITE_APP_ENV == "development"
- ? "http://114.132.189.42:8092" // 寮�鍙戠幆澧冨悗绔帴鍙�
- : "http://114.132.189.42:8092"; // 鐢熶骇鐜鍚庣鎺ュ彛
+ ? "http://192.168.1.138:7788" // 寮�鍙戠幆澧冨悗绔帴鍙�
+ : "http://114.132.189.42:7003"; // 鐢熶骇鐜鍚庣鎺ュ彛
return {
// 閮ㄧ讲鐢熶骇鐜鍜屽紑鍙戠幆澧冧笅鐨刄RL銆�
@@ -45,7 +45,7 @@
},
// vite 鐩稿叧閰嶇疆
server: {
- port: 80,
+ port: 8001,
host: true,
open: true,
proxy: {
--
Gitblit v1.9.3