From 5dda5e32e980fc4bfc466158157ab82858a409a9 Mon Sep 17 00:00:00 2001
From: yaowanxin <3588231647@qq.com>
Date: 星期一, 08 九月 2025 09:42:45 +0800
Subject: [PATCH] Merge remote-tracking branch 'refs/remotes/origin/dev-DHDC' into ywx
---
src/views/index.vue | 6
public/DHDCico.ico | 0
src/components/DynamicTable/index.vue | 402 ++
src/api/lavorissce/ledger.js | 55
src/views/lavorissue/ledger/filesDia.vue | 202 +
src/views/lavorissue/statistics/index.vue | 285 +
src/views/fileManagement/document/attachmentManager.vue | 426 ++
.env.staging | 4
src/views/fileManagement/bookshelf/detail.vue | 110
src/api/fileManagement/borrow.js | 47
src/views/fileManagement/return/index.vue | 595 ++++
src/layout/components/Sidebar/Logo.vue | 2
src/utils/util.js | 33
src/views/fileManagement/borrow/index.vue | 582 ++++
index.html | 388 +-
src/views/fileManagement/statistics/index.vue | 539 +++
src/assets/indexViews/DHDCLogo.png | 0
src/views/equipmentManagement/ledger/index.vue | 4
src/views/lavorissue/ledger/index.vue | 300 ++
vite.config.js | 4
src/api/fileManagement/bookshelf.js | 128
src/views/inventoryManagement/dispatchLog/index.vue | 590 ++++
src/assets/logo/敦煌鼎诚.png | 0
src/views/chatHome/chatHomeIndex/MobileChat.vue | 6
src/views/fileManagement/document/index.vue | 1262 ++++++++
src/permission.js | 95
src/views/example/DynamicTableExample.vue | 354 ++
src/views/fileManagement/bookshelf/index.vue | 688 ++++
src/assets/indexViews/DHDCView.png | 0
src/views/inventoryManagement/issueManagement/index.vue | 2
src/api/fileManagement/document.js | 189 +
.env.development | 4
src/api/fileManagement/statistics.js | 75
src/views/equipmentManagement/deviceInfo/index.vue | 190 +
src/views/lavorissue/ledger/Form.vue | 154 +
src/views/login.vue | 4
src/api/collaborativeApproval/noticeManagement.js | 77
src/main.js | 2
src/api/equipmentManagement/deviceInfo.js | 10
package.json | 2
.env.production | 4
src/views/example/SimpleExample.vue | 135
src/api/fileManagement/return.js | 54
src/views/collaborativeApproval/noticeManagement/index.vue | 518 +-
src/views/lavorissue/ledger/Modal.vue | 70
45 files changed, 8,026 insertions(+), 571 deletions(-)
diff --git a/.env.development b/.env.development
index 1a63995..68fafb1 100644
--- a/.env.development
+++ b/.env.development
@@ -1,8 +1,8 @@
# 椤甸潰鏍囬
-VITE_APP_TITLE = 鑺浜戯紙绠$悊淇℃伅绯荤粺锛�
+VITE_APP_TITLE = 鏁︾厡榧庤瘹绠$悊淇℃伅绯荤粺
# 寮�鍙戠幆澧冮厤缃�
VITE_APP_ENV = 'development'
-# 鑺浜戯紙绠$悊淇℃伅绯荤粺锛�/寮�鍙戠幆澧�
+# 鏁︾厡榧庤瘹绠$悊淇℃伅绯荤粺/寮�鍙戠幆澧�
VITE_APP_BASE_API = '/dev-api'
diff --git a/.env.production b/.env.production
index fa28cfc..09b308d 100644
--- a/.env.production
+++ b/.env.production
@@ -1,10 +1,10 @@
# 椤甸潰鏍囬
-VITE_APP_TITLE = 鑺浜戯紙绠$悊淇℃伅绯荤粺锛�
+VITE_APP_TITLE = 鏁︾厡榧庤瘹绠$悊淇℃伅绯荤粺
# 鐢熶骇鐜閰嶇疆
VITE_APP_ENV = 'production'
-# 鑺浜戯紙绠$悊淇℃伅绯荤粺锛�/鐢熶骇鐜
+# 鏁︾厡榧庤瘹绠$悊淇℃伅绯荤粺/鐢熶骇鐜
VITE_APP_BASE_API = '/prod-api'
# 鏄惁鍦ㄦ墦鍖呮椂寮�鍚帇缂╋紝鏀寔 gzip 鍜� brotli
diff --git a/.env.staging b/.env.staging
index 468abb3..6ace3a2 100644
--- a/.env.staging
+++ b/.env.staging
@@ -1,10 +1,10 @@
# 椤甸潰鏍囬
-VITE_APP_TITLE = 鑺浜戯紙绠$悊淇℃伅绯荤粺锛�
+VITE_APP_TITLE = 鏁︾厡榧庤瘹绠$悊淇℃伅绯荤粺
# 鐢熶骇鐜閰嶇疆
VITE_APP_ENV = 'staging'
-# 鑺浜戯紙绠$悊淇℃伅绯荤粺锛�/鐢熶骇鐜
+# 鏁︾厡榧庤瘹绠$悊淇℃伅绯荤粺/鐢熶骇鐜
VITE_APP_BASE_API = '/stage-api'
# 鏄惁鍦ㄦ墦鍖呮椂寮�鍚帇缂╋紝鏀寔 gzip 鍜� brotli
diff --git a/index.html b/index.html
index c72b2b8..b45cb21 100644
--- a/index.html
+++ b/index.html
@@ -1,215 +1,217 @@
<!DOCTYPE html>
<html>
-
-<head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <meta name="renderer" content="webkit">
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
- <link rel="icon" href="/favicon.ico">
- <title>鑺浜戯紙绠$悊淇℃伅绯荤粺锛�</title>
- <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
- <style>
- html,
- body,
- #app {
- height: 100%;
- margin: 0px;
- padding: 0px;
- }
-
- .chromeframe {
- margin: 0.2em 0;
- background: #ccc;
- color: #000;
- padding: 0.2em 0;
- }
-
- #loader-wrapper {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 999999;
- }
-
- #loader {
- display: block;
- position: relative;
- left: 50%;
- top: 50%;
- width: 150px;
- height: 150px;
- margin: -75px 0 0 -75px;
- border-radius: 50%;
- border: 3px solid transparent;
- border-top-color: #FFF;
- -webkit-animation: spin 2s linear infinite;
- -ms-animation: spin 2s linear infinite;
- -moz-animation: spin 2s linear infinite;
- -o-animation: spin 2s linear infinite;
- animation: spin 2s linear infinite;
- z-index: 1001;
- }
-
- #loader:before {
- content: "";
- position: absolute;
- top: 5px;
- left: 5px;
- right: 5px;
- bottom: 5px;
- border-radius: 50%;
- border: 3px solid transparent;
- border-top-color: #FFF;
- -webkit-animation: spin 3s linear infinite;
- -moz-animation: spin 3s linear infinite;
- -o-animation: spin 3s linear infinite;
- -ms-animation: spin 3s linear infinite;
- animation: spin 3s linear infinite;
- }
-
- #loader:after {
- content: "";
- position: absolute;
- top: 15px;
- left: 15px;
- right: 15px;
- bottom: 15px;
- border-radius: 50%;
- border: 3px solid transparent;
- border-top-color: #FFF;
- -moz-animation: spin 1.5s linear infinite;
- -o-animation: spin 1.5s linear infinite;
- -ms-animation: spin 1.5s linear infinite;
- -webkit-animation: spin 1.5s linear infinite;
- animation: spin 1.5s linear infinite;
- }
-
-
- @-webkit-keyframes spin {
- 0% {
- -webkit-transform: rotate(0deg);
- -ms-transform: rotate(0deg);
- transform: rotate(0deg);
+ <head>
+ <meta charset="utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+ <meta name="renderer" content="webkit" />
+ <meta
+ name="viewport"
+ content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
+ />
+ <link rel="icon" href="/DHDCico.ico" />
+ <title>鏁︾厡榧庤瘹绠$悊淇℃伅绯荤粺</title>
+ <!--[if lt IE 11
+ ]><script>
+ window.location.href = "/html/ie.html";
+ </script><!
+ [endif]-->
+ <style>
+ html,
+ body,
+ #app {
+ height: 100%;
+ margin: 0px;
+ padding: 0px;
}
- 100% {
- -webkit-transform: rotate(360deg);
- -ms-transform: rotate(360deg);
- transform: rotate(360deg);
- }
- }
-
- @keyframes spin {
- 0% {
- -webkit-transform: rotate(0deg);
- -ms-transform: rotate(0deg);
- transform: rotate(0deg);
+ .chromeframe {
+ margin: 0.2em 0;
+ background: #ccc;
+ color: #000;
+ padding: 0.2em 0;
}
- 100% {
- -webkit-transform: rotate(360deg);
- -ms-transform: rotate(360deg);
- transform: rotate(360deg);
+ #loader-wrapper {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 999999;
}
- }
+ #loader {
+ display: block;
+ position: relative;
+ left: 50%;
+ top: 50%;
+ width: 150px;
+ height: 150px;
+ margin: -75px 0 0 -75px;
+ border-radius: 50%;
+ border: 3px solid transparent;
+ border-top-color: #fff;
+ -webkit-animation: spin 2s linear infinite;
+ -ms-animation: spin 2s linear infinite;
+ -moz-animation: spin 2s linear infinite;
+ -o-animation: spin 2s linear infinite;
+ animation: spin 2s linear infinite;
+ z-index: 1001;
+ }
- #loader-wrapper .loader-section {
- position: fixed;
- top: 0;
- width: 51%;
- height: 100%;
- background: #7171C6;
- z-index: 1000;
- -webkit-transform: translateX(0);
- -ms-transform: translateX(0);
- transform: translateX(0);
- }
+ #loader:before {
+ content: "";
+ position: absolute;
+ top: 5px;
+ left: 5px;
+ right: 5px;
+ bottom: 5px;
+ border-radius: 50%;
+ border: 3px solid transparent;
+ border-top-color: #fff;
+ -webkit-animation: spin 3s linear infinite;
+ -moz-animation: spin 3s linear infinite;
+ -o-animation: spin 3s linear infinite;
+ -ms-animation: spin 3s linear infinite;
+ animation: spin 3s linear infinite;
+ }
- #loader-wrapper .loader-section.section-left {
- left: 0;
- }
+ #loader:after {
+ content: "";
+ position: absolute;
+ top: 15px;
+ left: 15px;
+ right: 15px;
+ bottom: 15px;
+ border-radius: 50%;
+ border: 3px solid transparent;
+ border-top-color: #fff;
+ -moz-animation: spin 1.5s linear infinite;
+ -o-animation: spin 1.5s linear infinite;
+ -ms-animation: spin 1.5s linear infinite;
+ -webkit-animation: spin 1.5s linear infinite;
+ animation: spin 1.5s linear infinite;
+ }
- #loader-wrapper .loader-section.section-right {
- right: 0;
- }
+ @-webkit-keyframes spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ -ms-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ -ms-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+ }
- .loaded #loader-wrapper .loader-section.section-left {
- -webkit-transform: translateX(-100%);
- -ms-transform: translateX(-100%);
- transform: translateX(-100%);
- -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
- transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
- }
+ @keyframes spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ -ms-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
- .loaded #loader-wrapper .loader-section.section-right {
- -webkit-transform: translateX(100%);
- -ms-transform: translateX(100%);
- transform: translateX(100%);
- -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
- transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
- }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ -ms-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+ }
- .loaded #loader {
- opacity: 0;
- -webkit-transition: all 0.3s ease-out;
- transition: all 0.3s ease-out;
- }
+ #loader-wrapper .loader-section {
+ position: fixed;
+ top: 0;
+ width: 51%;
+ height: 100%;
+ background: #7171c6;
+ z-index: 1000;
+ -webkit-transform: translateX(0);
+ -ms-transform: translateX(0);
+ transform: translateX(0);
+ }
- .loaded #loader-wrapper {
- visibility: hidden;
- -webkit-transform: translateY(-100%);
- -ms-transform: translateY(-100%);
- transform: translateY(-100%);
- -webkit-transition: all 0.3s 1s ease-out;
- transition: all 0.3s 1s ease-out;
- }
+ #loader-wrapper .loader-section.section-left {
+ left: 0;
+ }
- .no-js #loader-wrapper {
- display: none;
- }
+ #loader-wrapper .loader-section.section-right {
+ right: 0;
+ }
- .no-js h1 {
- color: #222222;
- }
+ .loaded #loader-wrapper .loader-section.section-left {
+ -webkit-transform: translateX(-100%);
+ -ms-transform: translateX(-100%);
+ transform: translateX(-100%);
+ -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
+ transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
+ }
- #loader-wrapper .load_title {
- font-family: 'Open Sans';
- color: #FFF;
- font-size: 19px;
- width: 100%;
- text-align: center;
- z-index: 9999999999999;
- position: absolute;
- top: 60%;
- opacity: 1;
- line-height: 30px;
- }
+ .loaded #loader-wrapper .loader-section.section-right {
+ -webkit-transform: translateX(100%);
+ -ms-transform: translateX(100%);
+ transform: translateX(100%);
+ -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
+ transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
+ }
- #loader-wrapper .load_title span {
- font-weight: normal;
- font-style: italic;
- font-size: 13px;
- color: #FFF;
- opacity: 0.5;
- }
- </style>
-</head>
+ .loaded #loader {
+ opacity: 0;
+ -webkit-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out;
+ }
-<body>
- <div id="app">
- <div id="loader-wrapper">
- <div id="loader"></div>
- <div class="loader-section section-left"></div>
- <div class="loader-section section-right"></div>
- <div class="load_title">姝e湪鍔犺浇绯荤粺璧勬簮锛岃鑰愬績绛夊緟</div>
+ .loaded #loader-wrapper {
+ visibility: hidden;
+ -webkit-transform: translateY(-100%);
+ -ms-transform: translateY(-100%);
+ transform: translateY(-100%);
+ -webkit-transition: all 0.3s 1s ease-out;
+ transition: all 0.3s 1s ease-out;
+ }
+
+ .no-js #loader-wrapper {
+ display: none;
+ }
+
+ .no-js h1 {
+ color: #222222;
+ }
+
+ #loader-wrapper .load_title {
+ font-family: "Open Sans";
+ color: #fff;
+ font-size: 19px;
+ width: 100%;
+ text-align: center;
+ z-index: 9999999999999;
+ position: absolute;
+ top: 60%;
+ opacity: 1;
+ line-height: 30px;
+ }
+
+ #loader-wrapper .load_title span {
+ font-weight: normal;
+ font-style: italic;
+ font-size: 13px;
+ color: #fff;
+ opacity: 0.5;
+ }
+ </style>
+ </head>
+
+ <body>
+ <div id="app">
+ <div id="loader-wrapper">
+ <div id="loader"></div>
+ <div class="loader-section section-left"></div>
+ <div class="loader-section section-right"></div>
+ <div class="load_title">姝e湪鍔犺浇绯荤粺璧勬簮锛岃鑰愬績绛夊緟</div>
+ </div>
</div>
- </div>
- <script type="module" src="/src/main.js"></script>
-</body>
-
-</html>
\ No newline at end of file
+ <script type="module" src="/src/main.js"></script>
+ </body>
+</html>
diff --git a/package.json b/package.json
index a2507f4..ac73018 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "ruoyi",
"version": "3.8.9",
- "description": "鑺浜戯紙绠$悊淇℃伅绯荤粺锛�",
+ "description": "鏁︾厡榧庤瘹绠$悊淇℃伅绯荤粺",
"author": "鑻ヤ緷",
"license": "MIT",
"type": "module",
diff --git a/public/DHDCico.ico b/public/DHDCico.ico
new file mode 100644
index 0000000..b4c4363
--- /dev/null
+++ b/public/DHDCico.ico
Binary files differ
diff --git a/src/api/collaborativeApproval/noticeManagement.js b/src/api/collaborativeApproval/noticeManagement.js
index fa1caec..0f4e8b3 100644
--- a/src/api/collaborativeApproval/noticeManagement.js
+++ b/src/api/collaborativeApproval/noticeManagement.js
@@ -2,68 +2,51 @@
// 鏌ヨ鍏憡鍒楄〃
export function listNotice(query) {
- return request({
- url: '/collaborativeApproval/notice/list',
- method: 'get',
- params: query
- })
+ return request({
+ url: '/collaborativeApproval/notice/page',
+ method: 'get',
+ params: query
+ })
}
// 鏌ヨ鍏憡璇︾粏
export function getNotice(noticeId) {
- return request({
- url: '/collaborativeApproval/notice/' + noticeId,
- method: 'get'
- })
+ return request({
+ url: '/collaborativeApproval/notice/' + noticeId,
+ method: 'get'
+ })
}
// 鏂板鍏憡
export function addNotice(data) {
- return request({
- url: '/collaborativeApproval/notice',
- method: 'post',
- data: data
- })
+ return request({
+ url: '/collaborativeApproval/notice/add',
+ method: 'post',
+ data: data
+ })
}
// 淇敼鍏憡
export function updateNotice(data) {
- return request({
- url: '/collaborativeApproval/notice',
- method: 'put',
- data: data
- })
+ return request({
+ url: '/collaborativeApproval/notice/update',
+ method: 'put',
+ data: data
+ })
}
// 鍒犻櫎鍏憡
-export function delNotice(noticeId) {
- return request({
- url: '/collaborativeApproval/notice/' + noticeId,
- method: 'delete'
- })
+export function delNotice(ids) {
+ return request({
+ url: '/collaborativeApproval/notice/' + ids,
+ method: 'delete',
+ })
}
-// 鎵归噺鍒犻櫎鍏憡
-export function delNoticeBatch(noticeIds) {
- return request({
- url: '/collaborativeApproval/notice/batch',
- method: 'delete',
- data: noticeIds
- })
-}
-
-// 鍙戝竷鍏憡
-export function publishNotice(noticeId) {
- return request({
- url: '/collaborativeApproval/notice/publish/' + noticeId,
- method: 'put'
- })
-}
-
-// 涓嬬嚎鍏憡
-export function offlineNotice(noticeId) {
- return request({
- url: '/collaborativeApproval/notice/offline/' + noticeId,
- method: 'put'
- })
+// 鑾峰彇鍏憡鏁伴噺
+export function getCount() {
+ return request({
+ url: '/collaborativeApproval/notice/count',
+ method: 'get',
+ })
}
diff --git a/src/api/equipmentManagement/deviceInfo.js b/src/api/equipmentManagement/deviceInfo.js
new file mode 100644
index 0000000..d71b713
--- /dev/null
+++ b/src/api/equipmentManagement/deviceInfo.js
@@ -0,0 +1,10 @@
+import request from "@/utils/request";
+
+// 鑾峰彇璁惧鍩烘湰淇℃伅
+export function getDeviceInfo(params) {
+ return request({
+ url: "/device/ledger/scanDevice",
+ method: "get",
+ params,
+ });
+}
diff --git a/src/api/fileManagement/bookshelf.js b/src/api/fileManagement/bookshelf.js
new file mode 100644
index 0000000..0a4a748
--- /dev/null
+++ b/src/api/fileManagement/bookshelf.js
@@ -0,0 +1,128 @@
+import request from "@/utils/request";
+
+/**
+ * 涔︽灦绠$悊鐩稿叧API鎺ュ彛
+ * 鍖呭惈浠撳簱绠$悊銆佽揣鏋剁鐞嗐�佸浘涔︾鐞嗙瓑鍔熻兘鐨勬帴鍙�
+ */
+
+/**
+ * 鑾峰彇浠撳簱鍒楄〃
+ * @description 鑾峰彇鎵�鏈変粨搴撶殑鍩烘湰淇℃伅鍒楄〃
+ * @returns {Promise} 杩斿洖浠撳簱鍒楄〃鏁版嵁
+ */
+export function getWarehouseList() {
+ return request({
+ url: "/warehouse/tree",
+ method: "get",
+ });
+}
+
+/**
+ * 鏂板浠撳簱
+ * @description 鍒涘缓鏂扮殑浠撳簱璁板綍
+ * @param {Object} data 浠撳簱淇℃伅瀵硅薄锛屽寘鍚粨搴撳悕绉扮瓑瀛楁
+ * @returns {Promise} 杩斿洖鏂板缁撴灉
+ */
+export function addWarehouse(data) {
+ return request({
+ url: "/warehouse/add",
+ method: "post",
+ data,
+ });
+}
+
+/**
+ * 鏇存柊浠撳簱淇℃伅
+ * @description 淇敼鐜版湁浠撳簱鐨勫熀鏈俊鎭�
+ * @param {Object} data 浠撳簱淇℃伅瀵硅薄锛屽繀椤诲寘鍚粨搴揑D
+ * @returns {Promise} 杩斿洖鏇存柊缁撴灉
+ */
+export function updateWarehouse(data) {
+ return request({
+ url: "/warehouse/update",
+ method: "put",
+ data,
+ });
+}
+
+/**
+ * 鍒犻櫎浠撳簱
+ * @description 鏍规嵁浠撳簱ID鍒犻櫎鎸囧畾鐨勪粨搴撹褰�
+ * @param {string|number} id 浠撳簱ID
+ * @returns {Promise} 杩斿洖鍒犻櫎缁撴灉
+ */
+export function deleteWarehouse(data) {
+ return request({
+ url: `/warehouse/delete/`,
+ method: "delete",
+ data,
+ });
+}
+
+/**
+ * 鑾峰彇璐ф灦鍒楄〃
+ * @description 鏍规嵁浠撳簱ID鑾峰彇璇ヤ粨搴撲笅鐨勬墍鏈夎揣鏋朵俊鎭�
+ * @param {string|number} warehouseId 浠撳簱ID
+ * @returns {Promise} 杩斿洖璐ф灦鍒楄〃鏁版嵁
+ */
+export function getShelfList(warehouseId) {
+ return request({
+ url: `/shelf/list/${warehouseId}`,
+ method: "get",
+ });
+}
+
+/**
+ * 鏂板璐ф灦
+ * @description 鍦ㄦ寚瀹氫粨搴撲笅鍒涘缓鏂扮殑璐ф灦璁板綍
+ * @param {Object} data 璐ф灦淇℃伅瀵硅薄锛屽寘鍚揣鏋跺悕绉般�佸眰鏁般�佸垪鏁扮瓑瀛楁
+ * @returns {Promise} 杩斿洖鏂板缁撴灉
+ */
+export function addShelf(data) {
+ return request({
+ url: "/warehouse/goodsShelves/add",
+ method: "post",
+ data,
+ });
+}
+
+/**
+ * 鏇存柊璐ф灦淇℃伅
+ * @description 淇敼鐜版湁璐ф灦鐨勫熀鏈俊鎭�
+ * @param {Object} data 璐ф灦淇℃伅瀵硅薄锛屽繀椤诲寘鍚揣鏋禝D
+ * @returns {Promise} 杩斿洖鏇存柊缁撴灉
+ */
+export function updateShelf(data) {
+ return request({
+ url: "/warehouse/goodsShelves/update",
+ method: "put",
+ data,
+ });
+}
+
+/**
+ * 鍒犻櫎璐ф灦
+ * @description 鏍规嵁璐ф灦ID鍒犻櫎鎸囧畾鐨勮揣鏋惰褰�
+ * @param {string|number} id 璐ф灦ID
+ * @returns {Promise} 杩斿洖鍒犻櫎缁撴灉
+ */
+export function deleteShelf(id) {
+ return request({
+ url: `/warehouse/goodsShelves/delete/${id}`,
+ method: "delete",
+ });
+}
+
+/**
+ * 鑾峰彇浠撳簱缁撴瀯
+ * @description 鑾峰彇鎸囧畾浠撳簱鐨勫畬鏁寸粨鏋勪俊鎭紝鍖呮嫭璐ф灦銆佸眰鏁般�佸垪鏁扮瓑
+ * @param {string|number} warehouseId 浠撳簱ID
+ * @returns {Promise} 杩斿洖浠撳簱鐨勫畬鏁寸粨鏋勬暟鎹�
+ */
+export function getWarehouseStructure(data) {
+ return request({
+ url: `/warehouse/goodsShelvesRowcol/list`,
+ method: "get",
+ params: data,
+ });
+}
diff --git a/src/api/fileManagement/borrow.js b/src/api/fileManagement/borrow.js
new file mode 100644
index 0000000..1f4c72c
--- /dev/null
+++ b/src/api/fileManagement/borrow.js
@@ -0,0 +1,47 @@
+import request from "@/utils/request";
+
+// 鏂囨。鍊熼槄绠$悊鐩稿叧鎺ュ彛
+
+// 鑾峰彇鏂囨。鍒楄〃锛堢敤浜庡�熼槄涔︾睄閫夋嫨锛�
+export function getDocumentList() {
+ return request({
+ url: "/documentation/list",
+ method: "get",
+ });
+}
+
+// 鍊熼槄鍒嗛〉鏌ヨ
+export function getBorrowList(params) {
+ return request({
+ url: "/documentationBorrowManagement/listPage",
+ method: "get",
+ params: params,
+ });
+}
+
+// 鏂板鍊熼槄
+export function addBorrow(data) {
+ return request({
+ url: "/documentationBorrowManagement/add",
+ method: "post",
+ data: data,
+ });
+}
+
+// 鏇存柊鍊熼槄
+export function updateBorrow(data) {
+ return request({
+ url: "/documentationBorrowManagement/update",
+ method: "put",
+ data: data,
+ });
+}
+
+// 鍒犻櫎鍊熼槄
+export function deleteBorrow(ids) {
+ return request({
+ url: "/documentationBorrowManagement/delete",
+ method: "delete",
+ data: ids,
+ });
+}
diff --git a/src/api/fileManagement/document.js b/src/api/fileManagement/document.js
new file mode 100644
index 0000000..f3d5f4f
--- /dev/null
+++ b/src/api/fileManagement/document.js
@@ -0,0 +1,189 @@
+import request from "@/utils/request";
+
+// 鑾峰彇鍒嗙被鏍�
+export function getCategoryTree() {
+ return request({
+ url: "/warehouse/documentClassification/getList",
+ method: "get",
+ });
+}
+
+// 鏂板鍒嗙被
+export function addCategory(data) {
+ return request({
+ url: "/warehouse/documentClassification/add",
+ method: "post",
+ data: {
+ category: data.category,
+ parentId: data.parentId,
+ },
+ });
+}
+
+// 淇敼鍒嗙被
+export function updateCategory(data) {
+ return request({
+ url: "/warehouse/documentClassification/update",
+ method: "put",
+ data: {
+ id: data.id,
+ category: data.category,
+ },
+ });
+}
+
+// 鍒犻櫎鍒嗙被
+export function deleteCategory(ids) {
+ return request({
+ url: "/warehouse/documentClassification/delete",
+ method: "delete",
+ data: ids,
+ });
+}
+
+// 鑾峰彇鏂囨。鍒楄〃锛堝垎椤碉級
+export function getDocumentList(query) {
+ return request({
+ url: "/documentation/listPage",
+ method: "get",
+ params: query,
+ });
+}
+
+// 鏂板鏂囨。
+export function addDocument(data) {
+ return request({
+ url: "/documentation/add",
+ method: "post",
+ data: data,
+ });
+}
+
+// 淇敼鏂囨。
+export function updateDocument(data) {
+ return request({
+ url: "/documentation/update",
+ method: "put",
+ data: data,
+ });
+}
+
+// 鍒犻櫎鏂囨。
+export function deleteDocument(ids) {
+ return request({
+ url: "/documentation/delete",
+ method: "delete",
+ data: ids,
+ });
+}
+
+// 鑾峰彇鏂囨。璇︽儏
+export function getDocumentDetail(id) {
+ return request({
+ url: "/document/" + id,
+ method: "get",
+ });
+}
+
+// 鎼滅储鏂囨。
+export function searchDocument(query) {
+ return request({
+ url: "/document/search",
+ method: "get",
+ params: query,
+ });
+}
+
+// 鑾峰彇浠撳簱缁撴瀯
+export function getWarehouseStructure() {
+ return request({
+ url: "/document/warehouse/structure",
+ method: "get",
+ });
+}
+
+// 闄勪欢绠$悊鐩稿叧鎺ュ彛
+// 娣诲姞闄勪欢
+export function addDocumentationFile(data) {
+ return request({
+ url: "/documentation/documentationFile/add",
+ method: "post",
+ data: data,
+ });
+}
+
+// 鑾峰彇闄勪欢鍒楄〃
+export function getDocumentationFileList(params) {
+ return request({
+ url: "/documentation/documentationFile/listPage",
+ method: "get",
+ params: params,
+ });
+}
+
+// 鍒犻櫎闄勪欢
+export function deleteDocumentationFile(ids) {
+ return request({
+ url: "/documentation/documentationFile/del",
+ method: "delete",
+ data: ids,
+ });
+}
+
+// 鏂囨。鍊熼槄绠$悊鐩稿叧鎺ュ彛
+export function getBorrowList(params) {
+ return request({
+ url: "/documentationBorrowManagement/listPage",
+ method: "get",
+ params: params,
+ });
+}
+
+export function addBorrow(data) {
+ return request({
+ url: "/documentationBorrowManagement/add",
+ method: "post",
+ data: data,
+ });
+}
+
+export function updateBorrow(data) {
+ return request({
+ url: "/documentationBorrowManagement/update",
+ method: "put",
+ data: data,
+ });
+}
+
+export function deleteBorrow(ids) {
+ return request({
+ url: "/documentationBorrowManagement/delete",
+ method: "delete",
+ data: ids,
+ });
+}
+
+// 缁熻鐩稿叧鎺ュ彛
+// 鑾峰彇鎬讳綋缁熻鏁版嵁
+export function getDocumentationOverview() {
+ return request({
+ url: "/documentation/overview",
+ method: "get",
+ });
+}
+
+// 鑾峰彇鍒嗙被缁熻鏁版嵁
+export function getDocumentationCategoryStats() {
+ return request({
+ url: "/documentation/category",
+ method: "get",
+ });
+}
+
+// 鑾峰彇鐘舵�佺粺璁℃暟鎹�
+export function getDocumentationStatusStats() {
+ return request({
+ url: "/documentation/status",
+ method: "get",
+ });
+}
diff --git a/src/api/fileManagement/return.js b/src/api/fileManagement/return.js
new file mode 100644
index 0000000..2e0c0e7
--- /dev/null
+++ b/src/api/fileManagement/return.js
@@ -0,0 +1,54 @@
+import request from "@/utils/request";
+
+// 鍒嗛〉鏌ヨ褰掕繕璁板綍
+export function getReturnListPage(query) {
+ return request({
+ url: "/documentationBorrowManagement/listPageReturn",
+ method: "get",
+ params: query,
+ });
+}
+
+// 褰掕繕鎿嶄綔
+export function returnDocument(data) {
+ return request({
+ url: "/documentationBorrowManagement/revent",
+ method: "put",
+ data: data,
+ });
+}
+
+// 鍒犻櫎褰掕繕璁板綍
+export function deleteReturn(ids) {
+ return request({
+ url: "/documentationBorrowManagement/reventDelete",
+ method: "delete",
+ data: ids,
+ });
+}
+
+// 鏇存柊鍊熼槄璁板綍
+export function updateBorrow(data) {
+ return request({
+ url: "/documentationBorrowManagement/update",
+ method: "put",
+ data: data,
+ });
+}
+
+// 褰掕繕鏇存柊
+export function reventUpdate(data) {
+ return request({
+ url: "/documentationBorrowManagement/reventUpdate",
+ method: "put",
+ data: data,
+ });
+}
+
+// 鑾峰彇鏂囨。鍒楄〃
+export function getDocumentList() {
+ return request({
+ url: "/documentationBorrowManagement/list",
+ method: "get",
+ });
+}
diff --git a/src/api/fileManagement/statistics.js b/src/api/fileManagement/statistics.js
new file mode 100644
index 0000000..d77375c
--- /dev/null
+++ b/src/api/fileManagement/statistics.js
@@ -0,0 +1,75 @@
+import request from "@/utils/request";
+
+// 鑾峰彇妗f鎬讳綋缁熻
+export function getDocumentStatistics() {
+ return request({
+ url: "/fileManagement/statistics/overview",
+ method: "get",
+ });
+}
+
+// 鑾峰彇妗f鍒嗙被缁熻
+export function getCategoryStatistics() {
+ return request({
+ url: "/fileManagement/statistics/category",
+ method: "get",
+ });
+}
+
+// 鑾峰彇妗f鐘舵�佺粺璁�
+export function getStatusStatistics() {
+ return request({
+ url: "/fileManagement/statistics/status",
+ method: "get",
+ });
+}
+
+// 鑾峰彇妗f鍊熼槄缁熻
+export function getBorrowStatistics() {
+ return request({
+ url: "/fileManagement/statistics/borrow",
+ method: "get",
+ });
+}
+
+// 鑾峰彇妗f骞村害缁熻
+export function getYearStatistics() {
+ return request({
+ url: "/fileManagement/statistics/year",
+ method: "get",
+ });
+}
+
+// 鑾峰彇妗f浣嶇疆缁熻
+export function getLocationStatistics() {
+ return request({
+ url: "/fileManagement/statistics/location",
+ method: "get",
+ });
+}
+
+// 鑾峰彇妗f瓒嬪娍缁熻
+export function getTrendStatistics(params) {
+ return request({
+ url: "/fileManagement/statistics/trend",
+ method: "get",
+ params: params,
+ });
+}
+
+// 鑾峰彇妗f鍊熼槄鎺掕
+export function getBorrowRanking() {
+ return request({
+ url: "/fileManagement/statistics/borrowRanking",
+ method: "get",
+ });
+}
+
+// 鑾峰彇妗f鍒嗙被璇︽儏缁熻
+export function getCategoryDetailStatistics(categoryId) {
+ return request({
+ url: `/fileManagement/statistics/categoryDetail/${categoryId}`,
+ method: "get",
+ });
+}
+
diff --git a/src/api/lavorissce/ledger.js b/src/api/lavorissce/ledger.js
new file mode 100644
index 0000000..f4f710c
--- /dev/null
+++ b/src/api/lavorissce/ledger.js
@@ -0,0 +1,55 @@
+import request from '@/utils/request'
+
+// 鍒嗛〉鏌ヨ
+export function listPage(query) {
+ return request({
+ url: '/lavorIssue/listPage',
+ method: 'get',
+ params: query
+ })
+}
+
+// 鍒嗛〉鏌ヨ
+export function statistics(params) {
+ return request({
+ url: '/lavorIssue/statistics',
+ method: 'get',
+ params
+ })
+}
+
+export function statisticsList(params) {
+ return request({
+ url: '/lavorIssue/statisticsList',
+ method: 'get',
+ params
+ })
+}
+
+// 娣诲姞
+export function add(data) {
+ return request({
+ url: '/lavorIssue/add',
+ method: 'post',
+ data
+ })
+}
+
+// 淇敼
+export function update(data) {
+ return request({
+ url: '/lavorIssue/update',
+ method: 'post',
+ data
+ })
+}
+
+// 鍒犻櫎
+export function deleteLedger(data) {
+ return request({
+ url: '/lavorIssue/delete',
+ method: 'delete',
+ data
+ })
+}
+
diff --git a/src/assets/indexViews/DHDCLogo.png b/src/assets/indexViews/DHDCLogo.png
new file mode 100644
index 0000000..139bdd1
--- /dev/null
+++ b/src/assets/indexViews/DHDCLogo.png
Binary files differ
diff --git a/src/assets/indexViews/DHDCView.png b/src/assets/indexViews/DHDCView.png
new file mode 100644
index 0000000..7d3e8af
--- /dev/null
+++ b/src/assets/indexViews/DHDCView.png
Binary files differ
diff --git "a/src/assets/logo/\346\225\246\347\205\214\351\274\216\350\257\232.png" "b/src/assets/logo/\346\225\246\347\205\214\351\274\216\350\257\232.png"
new file mode 100644
index 0000000..139bdd1
--- /dev/null
+++ "b/src/assets/logo/\346\225\246\347\205\214\351\274\216\350\257\232.png"
Binary files differ
diff --git a/src/components/DynamicTable/index.vue b/src/components/DynamicTable/index.vue
new file mode 100644
index 0000000..9da9a3c
--- /dev/null
+++ b/src/components/DynamicTable/index.vue
@@ -0,0 +1,402 @@
+<template>
+ <div class="dynamic-table-container">
+ <el-table
+ ref="tableRef"
+ v-loading="loading"
+ :data="tableData"
+ :border="border"
+ :height="height"
+ :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+ style="width: 100%"
+ @selection-change="handleSelectionChange"
+ @row-click="handleRowClick"
+ >
+ <!-- 閫夋嫨鍒� -->
+ <el-table-column
+ v-if="showSelection"
+ align="center"
+ type="selection"
+ width="55"
+ />
+
+ <!-- 搴忓彿鍒� -->
+ <el-table-column
+ v-if="showIndex"
+ align="center"
+ label="搴忓彿"
+ type="index"
+ width="60"
+ />
+
+ <!-- 鍥哄畾鍒楋細閮ㄩ棬 -->
+ <el-table-column
+ label="閮ㄩ棬"
+ prop="department"
+ width="120"
+ show-overflow-tooltip
+ align="center"
+ />
+
+ <!-- 鍥哄畾鍒楋細濮撳悕 -->
+ <el-table-column
+ label="濮撳悕"
+ prop="name"
+ width="100"
+ show-overflow-tooltip
+ align="center"
+ />
+
+ <!-- 鍥哄畾鍒楋細宸ュ彿 -->
+ <el-table-column
+ label="宸ュ彿"
+ prop="employeeId"
+ width="100"
+ show-overflow-tooltip
+ align="center"
+ />
+
+ <!-- 鍔ㄦ�佸垪锛氭牴鎹瓧鍏告覆鏌� -->
+ <el-table-column
+ v-for="(dictItem, index) in dynamicColumns"
+ :key="dictItem.value"
+ :label="dictItem.label"
+ :prop="dictItem.value"
+ :width="dictItem.width || 120"
+ show-overflow-tooltip
+ align="center"
+ >
+ <template #default="scope">
+ <!-- 鏍规嵁瀛楀吀绫诲瀷娓叉煋涓嶅悓鐨勬樉绀烘柟寮� -->
+ <template v-if="dictItem.renderType === 'tag'">
+ <el-tag
+ :type="getTagType(scope.row[dictItem.value])"
+ size="small"
+ >
+ {{ getDictValueLabel(dictItem.dictType, scope.row[dictItem.value]) }}
+ </el-tag>
+ </template>
+ <template v-else-if="dictItem.renderType === 'select'">
+ <el-select
+ v-model="scope.row[dictItem.value]"
+ placeholder="璇烽�夋嫨"
+ size="small"
+ @change="handleSelectChange(scope.row, dictItem.value, $event)"
+ >
+ <el-option
+ v-for="option in dictItem.options"
+ :key="option.value"
+ :label="option.label"
+ :value="option.value"
+ />
+ </el-select>
+ </template>
+ <template v-else-if="dictItem.renderType === 'input'">
+ <el-input
+ v-model="scope.row[dictItem.value]"
+ size="small"
+ placeholder="璇疯緭鍏�"
+ @blur="handleInputChange(scope.row, dictItem.value, $event)"
+ />
+ </template>
+ <template v-else>
+ <span>{{ getDictValueLabel(dictItem.dictType, scope.row[dictItem.value]) }}</span>
+ </template>
+ </template>
+ </el-table-column>
+
+ <!-- 鎿嶄綔鍒� -->
+ <el-table-column
+ v-if="showActions"
+ label="鎿嶄綔"
+ width="150"
+ align="center"
+ fixed="right"
+ >
+ <template #default="scope">
+ <el-button
+ type="primary"
+ link
+ size="small"
+ @click="handleEdit(scope.row, scope.$index)"
+ >
+ 缂栬緫
+ </el-button>
+ <el-button
+ type="danger"
+ link
+ size="small"
+ @click="handleDelete(scope.row, scope.$index)"
+ >
+ 鍒犻櫎
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 鍒嗛〉缁勪欢 -->
+ <div v-if="showPagination" class="pagination-container">
+ <el-pagination
+ v-model:current-page="pagination.current"
+ v-model:page-size="pagination.size"
+ :page-sizes="[10, 20, 50, 100]"
+ :total="pagination.total"
+ layout="total, sizes, prev, pager, next, jumper"
+ @size-change="handleSizeChange"
+ @current-change="handleCurrentChange"
+ />
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { ref, computed, onMounted, watch } from 'vue'
+import { useDict } from '@/utils/dict'
+
+// 瀹氫箟缁勪欢灞炴��
+const props = defineProps({
+ // 琛ㄦ牸鏁版嵁
+ data: {
+ type: Array,
+ default: () => []
+ },
+ // 瀛楀吀绫诲瀷鏁扮粍锛岀敤浜庡姩鎬佺敓鎴愬垪
+ dictTypes: {
+ type: Array,
+ default: () => []
+ },
+ // 鏄惁鏄剧ず閫夋嫨鍒�
+ showSelection: {
+ type: Boolean,
+ default: false
+ },
+ // 鏄惁鏄剧ず搴忓彿鍒�
+ showIndex: {
+ type: Boolean,
+ default: true
+ },
+ // 鏄惁鏄剧ず鎿嶄綔鍒�
+ showActions: {
+ type: Boolean,
+ default: false
+ },
+ // 鏄惁鏄剧ず鍒嗛〉
+ showPagination: {
+ type: Boolean,
+ default: false
+ },
+ // 琛ㄦ牸楂樺害
+ height: {
+ type: [String, Number],
+ default: 'auto'
+ },
+ // 鏄惁鏄剧ず杈规
+ border: {
+ type: Boolean,
+ default: true
+ },
+ // 鍔犺浇鐘舵��
+ loading: {
+ type: Boolean,
+ default: false
+ },
+ // 鍒嗛〉閰嶇疆
+ pagination: {
+ type: Object,
+ default: () => ({
+ current: 1,
+ size: 10,
+ total: 0
+ })
+ }
+})
+
+// 瀹氫箟浜嬩欢
+const emit = defineEmits([
+ 'selection-change',
+ 'row-click',
+ 'edit',
+ 'delete',
+ 'select-change',
+ 'input-change',
+ 'size-change',
+ 'current-change'
+])
+
+// 鍝嶅簲寮忔暟鎹�
+const tableRef = ref(null)
+const tableData = ref([])
+
+// 鑾峰彇瀛楀吀鏁版嵁
+const dictData = ref({})
+
+// 鍔ㄦ�佸垪閰嶇疆
+const dynamicColumns = computed(() => {
+ const columns = []
+
+ props.dictTypes.forEach(dictType => {
+ const dictItems = dictData.value[dictType] || []
+ // 涓烘瘡涓瓧鍏哥被鍨嬪垱寤轰竴涓垪锛岃�屼笉鏄负姣忎釜瀛楀吀椤瑰垱寤哄垪
+ if (dictItems.length > 0) {
+ columns.push({
+ label: getDictLabel(dictType), // 鑾峰彇瀛楀吀绫诲瀷鐨勬樉绀哄悕绉�
+ value: dictType, // 浣跨敤瀛楀吀绫诲瀷浣滀负瀛楁鍚�
+ width: 120,
+ renderType: 'tag', // 榛樿浣跨敤鏍囩鏄剧ず
+ options: dictItems, // 鎻愪緵閫夐」
+ dictType: dictType
+ })
+ }
+ })
+
+ return columns
+})
+
+// 鑾峰彇瀛楀吀绫诲瀷鐨勬樉绀哄悕绉�
+const getDictLabel = (dictType) => {
+ const labelMap = {
+ 'sys_normal_disable': '鐘舵��',
+ 'sys_user_level': '绾у埆',
+ 'sys_user_position': '鑱屼綅',
+ 'sys_yes_no': '鏄惁',
+ 'sys_user_sex': '鎬у埆',
+ 'sys_lavor_issue': '鍔冲姟闂' // 娣诲姞鍔冲姟闂瀛楀吀
+ }
+ return labelMap[dictType] || dictType
+}
+
+// 鑾峰彇瀛楀吀鏁版嵁
+const loadDictData = async () => {
+ try {
+ const dictPromises = props.dictTypes.map(async (dictType) => {
+ const { getDicts } = await import('@/api/system/dict/data')
+ const response = await getDicts(dictType)
+ return {
+ type: dictType,
+ data: response.data.map(item => ({
+ label: item.dictLabel,
+ value: item.dictValue,
+ elTagType: item.listClass,
+ elTagClass: item.cssClass
+ }))
+ }
+ })
+
+ const results = await Promise.all(dictPromises)
+ results.forEach(result => {
+ dictData.value[result.type] = result.data
+ })
+ } catch (error) {
+ console.error('鍔犺浇瀛楀吀鏁版嵁澶辫触:', error)
+ // 濡傛灉瀛楀吀鍔犺浇澶辫触锛屼娇鐢ㄩ粯璁ゆ暟鎹�
+ props.dictTypes.forEach(dictType => {
+ if (!dictData.value[dictType]) {
+ dictData.value[dictType] = []
+ }
+ })
+ }
+}
+
+// 鑾峰彇鏍囩绫诲瀷
+const getTagType = (value) => {
+ // 鏍规嵁鍊艰繑鍥炰笉鍚岀殑鏍囩绫诲瀷
+ if (value === '1' || value === 'true' || value === '鏄�') return 'success'
+ if (value === '0' || value === 'false' || value === '鍚�') return 'danger'
+ if (value === '2' || value === 'warning') return 'warning'
+ return 'info'
+}
+
+// 鑾峰彇瀛楀吀鍊肩殑鏍囩
+const getDictValueLabel = (dictType, value) => {
+ if (!value) return '-'
+ const dictItems = dictData.value[dictType] || []
+ const item = dictItems.find(item => item.value === value)
+ return item ? item.label : value
+}
+
+// 浜嬩欢澶勭悊鍑芥暟
+const handleSelectionChange = (selection) => {
+ emit('selection-change', selection)
+}
+
+const handleRowClick = (row, column, event) => {
+ emit('row-click', row, column, event)
+}
+
+const handleEdit = (row, index) => {
+ emit('edit', row, index)
+}
+
+const handleDelete = (row, index) => {
+ emit('delete', row, index)
+}
+
+const handleSelectChange = (row, prop, value) => {
+ emit('select-change', row, prop, value)
+}
+
+const handleInputChange = (row, prop, event) => {
+ emit('input-change', row, prop, event.target.value)
+}
+
+const handleSizeChange = (size) => {
+ emit('size-change', size)
+}
+
+const handleCurrentChange = (current) => {
+ emit('current-change', current)
+}
+
+// 鐩戝惉鏁版嵁鍙樺寲
+watch(() => props.data, (newData) => {
+ tableData.value = newData
+}, { immediate: true })
+
+// 鐩戝惉瀛楀吀绫诲瀷鍙樺寲
+watch(() => props.dictTypes, () => {
+ loadDictData()
+}, { immediate: true })
+
+// 缁勪欢鎸傝浇鏃跺姞杞藉瓧鍏告暟鎹�
+onMounted(() => {
+ loadDictData()
+})
+
+// 鏆撮湶鏂规硶缁欑埗缁勪欢
+defineExpose({
+ tableRef,
+ getSelection: () => tableRef.value?.getSelectionRows() || [],
+ clearSelection: () => tableRef.value?.clearSelection(),
+ toggleRowSelection: (row, selected) => tableRef.value?.toggleRowSelection(row, selected),
+ setCurrentRow: (row) => tableRef.value?.setCurrentRow(row)
+})
+</script>
+
+<style scoped>
+.dynamic-table-container {
+ width: 100%;
+}
+
+.pagination-container {
+ margin-top: 20px;
+ display: flex;
+ justify-content: flex-end;
+}
+
+:deep(.el-table .el-table__header-wrapper th) {
+ background-color: #F0F1F5 !important;
+ color: #333333;
+ font-weight: 600;
+}
+
+:deep(.el-table .el-table__body-wrapper td) {
+ padding: 8px 0;
+}
+
+:deep(.el-select) {
+ width: 100%;
+}
+
+:deep(.el-input) {
+ width: 100%;
+}
+</style>
diff --git a/src/layout/components/Sidebar/Logo.vue b/src/layout/components/Sidebar/Logo.vue
index 898085b..a04d3ff 100644
--- a/src/layout/components/Sidebar/Logo.vue
+++ b/src/layout/components/Sidebar/Logo.vue
@@ -16,7 +16,7 @@
<script setup>
import { ref, computed, onMounted, watch } from 'vue'
import useUserStore from '@/store/modules/user'
-import defaultLogo from '@/assets/logo/logo.png' // 瀵煎叆榛樿logo
+import defaultLogo from '@/assets/logo/鏁︾厡榧庤瘹.png' // 瀵煎叆榛樿logo
defineProps({
collapse: {
diff --git a/src/main.js b/src/main.js
index ef6b2a4..ef7b341 100644
--- a/src/main.js
+++ b/src/main.js
@@ -76,7 +76,7 @@
app.config.globalProperties.addDateRange = addDateRange;
app.config.globalProperties.selectDictLabel = selectDictLabel;
app.config.globalProperties.selectDictLabels = selectDictLabels;
-app.config.globalProperties.javaApi = "http://114.132.189.42:7004";
+app.config.globalProperties.javaApi = "http://114.132.189.42:9033";
app.config.globalProperties.HaveJson = (val) => {
return JSON.parse(JSON.stringify(val));
};
diff --git a/src/permission.js b/src/permission.js
index a7d9f87..5b2566b 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -1,69 +1,76 @@
-import router from './router'
-import { ElMessage } from 'element-plus'
-import NProgress from 'nprogress'
-import 'nprogress/nprogress.css'
-import { getToken } from '@/utils/auth'
-import { isHttp, isPathMatch } from '@/utils/validate'
-import { isRelogin } from '@/utils/request'
-import useUserStore from '@/store/modules/user'
-import useSettingsStore from '@/store/modules/settings'
-import usePermissionStore from '@/store/modules/permission'
+import router from "./router";
+import { ElMessage } from "element-plus";
+import NProgress from "nprogress";
+import "nprogress/nprogress.css";
+import { getToken } from "@/utils/auth";
+import { isHttp, isPathMatch } from "@/utils/validate";
+import { isRelogin } from "@/utils/request";
+import useUserStore from "@/store/modules/user";
+import useSettingsStore from "@/store/modules/settings";
+import usePermissionStore from "@/store/modules/permission";
-NProgress.configure({ showSpinner: false })
+NProgress.configure({ showSpinner: false });
-const whiteList = ['/login', '/register']
+const whiteList = ["/login", "/register", "/device-info"];
const isWhiteList = (path) => {
- return whiteList.some(pattern => isPathMatch(pattern, path))
-}
+ return whiteList.some((pattern) => isPathMatch(pattern, path));
+};
router.beforeEach((to, from, next) => {
- NProgress.start()
+ NProgress.start();
if (getToken()) {
- to.meta.title && useSettingsStore().setTitle(to.meta.title)
+ to.meta.title && useSettingsStore().setTitle(to.meta.title);
/* has token*/
- if (to.path === '/login') {
- next({ path: '/' })
- NProgress.done()
+ if (to.path === "/login") {
+ next({ path: "/" });
+ NProgress.done();
} else if (isWhiteList(to.path)) {
- next()
+ next();
} else {
if (useUserStore().roles.length === 0) {
- isRelogin.show = true
+ isRelogin.show = true;
// 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁宸叉媺鍙栧畬user_info淇℃伅
- useUserStore().getInfo().then(() => {
- isRelogin.show = false
- usePermissionStore().generateRoutes().then(accessRoutes => {
- // 鏍规嵁roles鏉冮檺鐢熸垚鍙闂殑璺敱琛�
- accessRoutes.forEach(route => {
- if (!isHttp(route.path)) {
- router.addRoute(route) // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
- }
- })
- next({ ...to, replace: true }) // hack鏂规硶 纭繚addRoutes宸插畬鎴�
+ useUserStore()
+ .getInfo()
+ .then(() => {
+ isRelogin.show = false;
+ usePermissionStore()
+ .generateRoutes()
+ .then((accessRoutes) => {
+ // 鏍规嵁roles鏉冮檺鐢熸垚鍙闂殑璺敱琛�
+ accessRoutes.forEach((route) => {
+ if (!isHttp(route.path)) {
+ router.addRoute(route); // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
+ }
+ });
+ next({ ...to, replace: true }); // hack鏂规硶 纭繚addRoutes宸插畬鎴�
+ });
})
- }).catch(err => {
- useUserStore().logOut().then(() => {
- ElMessage.error(err)
- next({ path: '/' })
- })
- })
+ .catch((err) => {
+ useUserStore()
+ .logOut()
+ .then(() => {
+ ElMessage.error(err);
+ next({ path: "/" });
+ });
+ });
} else {
- next()
+ next();
}
}
} else {
// 娌℃湁token
if (isWhiteList(to.path)) {
// 鍦ㄥ厤鐧诲綍鐧藉悕鍗曪紝鐩存帴杩涘叆
- next()
+ next();
} else {
- next(`/login?redirect=${to.fullPath}`) // 鍚﹀垯鍏ㄩ儴閲嶅畾鍚戝埌鐧诲綍椤�
- NProgress.done()
+ next(`/login?redirect=${to.fullPath}`); // 鍚﹀垯鍏ㄩ儴閲嶅畾鍚戝埌鐧诲綍椤�
+ NProgress.done();
}
}
-})
+});
router.afterEach(() => {
- NProgress.done()
-})
+ NProgress.done();
+});
diff --git a/src/utils/util.js b/src/utils/util.js
index 78846dc..be08cc1 100644
--- a/src/utils/util.js
+++ b/src/utils/util.js
@@ -1,4 +1,6 @@
//闃叉姈
+import dayjs from "dayjs";
+
export function debounce(fn) {
console.log(1)
let t = null //鍙細鎵ц涓�娆�
@@ -86,7 +88,34 @@
'aplication/zip': 'zpi',
}
}
-
+ export const deepCopySameProperties = (source, target) =>{
+ for (const key in source) {
+ if (target.hasOwnProperty(key)) {
+ if (typeof source[key] === 'object' && source[key] !== null &&
+ typeof target[key] === 'object' && target[key] !== null) {
+ // 閫掑綊澶勭悊瀵硅薄
+ deepCopySameProperties(source[key], target[key]);
+ } else {
+ // 鍩烘湰绫诲瀷鐩存帴璧嬪��
+ target[key] = source[key];
+ }
+ }
+ }
+ return target;
+}
export function filterArr(arr) {
return arr.filter(item => item.flag !== false);
- }
\ No newline at end of file
+ }
+
+ export function getCurrentMonth () {
+ let month = dayjs().month() + 1
+ if (month <= 3) {
+ return '1';
+ } else if (month <= 6) {
+ return '2';
+ } else if (month <= 9) {
+ return '3';
+ } else if (month <= 12) {
+ return '4';
+ }
+}
\ No newline at end of file
diff --git a/src/views/chatHome/chatHomeIndex/MobileChat.vue b/src/views/chatHome/chatHomeIndex/MobileChat.vue
index 5b06e76..adeb5e7 100644
--- a/src/views/chatHome/chatHomeIndex/MobileChat.vue
+++ b/src/views/chatHome/chatHomeIndex/MobileChat.vue
@@ -14,7 +14,7 @@
<span class="flash_cursor"></span>
</template>
<template v-else>
- <pre>{{ item.msg }}</pre>
+ <pre style="font-family: none;">{{ item.msg }}</pre>
</template>
</div>
<div class="chat-img" v-if="item.chatType == 1">
@@ -140,7 +140,7 @@
}
chatList.value.push(chatMsg)
let chatGPT = {
- headImg: headPortrait,
+ headImg: chatGPTHeadImg,
name: '灏忔櫤',
time: new Date().toLocaleTimeString(),
msg: "",
@@ -185,7 +185,7 @@
uid: '1002'
})
chatList.value.push({
- headImg: chatGPTHeadImg,
+ headImg: headPortrait,
name: '鍗ч緳',
time: new Date().toLocaleTimeString(),
msg: route.query.keyWord,
diff --git a/src/views/collaborativeApproval/noticeManagement/index.vue b/src/views/collaborativeApproval/noticeManagement/index.vue
index daa4cd7..16cee35 100644
--- a/src/views/collaborativeApproval/noticeManagement/index.vue
+++ b/src/views/collaborativeApproval/noticeManagement/index.vue
@@ -2,30 +2,30 @@
<div class="app-container">
<!-- 鎼滅储琛ㄥ崟 -->
<div class="search_form">
- <div>
- <span class="search_title">鍏憡鏍囬锛�</span>
- <el-input
- v-model="searchForm.noticeTitle"
- style="width: 240px"
- placeholder="璇疯緭鍏ュ叕鍛婃爣棰樻悳绱�"
- @change="handleQuery"
- clearable
- :prefix-icon="Search"
- />
- <span class="search_title ml10">鍏憡绫诲瀷锛�</span>
- <el-select v-model="searchForm.noticeType" clearable @change="handleQuery" style="width: 240px">
- <el-option label="鏀惧亣閫氱煡" value="1" />
- <el-option label="璁惧缁翠慨閫氱煡" value="2" />
- </el-select>
- <span class="search_title ml10">鐘舵�侊細</span>
- <el-select v-model="searchForm.status" clearable @change="handleQuery" style="width: 240px">
- <el-option label="鑽夌" value="0" />
- <el-option label="宸插彂甯�" value="1" />
- <el-option label="宸蹭笅绾�" value="2" />
- </el-select>
- <el-button type="primary" @click="handleQuery" style="margin-left: 10px">鎼滅储</el-button>
- <el-button @click="resetQuery" style="margin-left: 10px">閲嶇疆</el-button>
- </div>
+ <!-- <div>-->
+ <!-- <span class="search_title">鍏憡鏍囬锛�</span>-->
+ <!-- <el-input-->
+ <!-- v-model="searchForm.title"-->
+ <!-- style="width: 240px"-->
+ <!-- placeholder="璇疯緭鍏ュ叕鍛婃爣棰樻悳绱�"-->
+ <!-- @change="handleQuery"-->
+ <!-- clearable-->
+ <!-- :prefix-icon="Search"-->
+ <!-- />-->
+ <!-- <span class="search_title ml10">鍏憡绫诲瀷锛�</span>-->
+ <!-- <el-select v-model="searchForm.type" clearable @change="handleQuery" style="width: 240px">-->
+ <!-- <el-option label="鏀惧亣閫氱煡" :value="1"/>-->
+ <!-- <el-option label="璁惧缁翠慨閫氱煡" :value="2"/>-->
+ <!-- </el-select>-->
+ <!-- <span class="search_title ml10">鐘舵�侊細</span>-->
+ <!-- <el-select v-model="searchForm.status" clearable @change="handleQuery" style="width: 240px">-->
+ <!-- <el-option label="鑽夌" :value="0"/>-->
+ <!-- <el-option label="宸插彂甯�" :value="1"/>-->
+ <!-- <el-option label="宸蹭笅绾�" :value="2"/>-->
+ <!-- </el-select>-->
+ <!-- <el-button type="primary" @click="handleQuery" style="margin-left: 10px">鎼滅储</el-button>-->
+ <!-- <el-button @click="resetQuery" style="margin-left: 10px">閲嶇疆</el-button>-->
+ <!-- </div>-->
<div>
<el-button type="primary" @click="openForm('add')">鏂板鍏憡</el-button>
<el-button type="danger" plain @click="handleDelete" :disabled="!selectedIds.length">鍒犻櫎</el-button>
@@ -35,22 +35,24 @@
<!-- 閫氱煡鍏憡鏉� -->
<div class="notice-board">
<!-- 鏀惧亣閫氱煡鍖哄煙 -->
- <div class="notice-section" v-if="holidayNotices.length > 0">
+ <div class="notice-section" v-if="holidayNoticeCount > 0">
<div class="section-header">
<h3>馃搮 鏀惧亣閫氱煡</h3>
- <span class="section-count">{{ holidayNotices.length }}鏉�</span>
+ <span class="section-count">{{ holidayNoticeCount }}鏉�</span>
</div>
<div class="notice-cards">
- <div
- v-for="notice in holidayNotices"
- :key="notice.id"
- class="notice-card holiday-card"
- :class="{ 'urgent': notice.priority === '3' }"
+ <div
+ v-for="notice in holidayNotices"
+ :key="notice.id"
+ class="notice-card holiday-card"
+ :class="{ 'urgent': notice.priority === '3' }"
>
<div class="card-header">
<div class="card-title">
- <el-icon class="holiday-icon"><Calendar /></el-icon>
- {{ notice.noticeTitle }}
+ <el-icon class="holiday-icon">
+ <Calendar/>
+ </el-icon>
+ {{ notice.title }}
</div>
<div class="card-actions">
<el-button link type="primary" @click="handleEdit(notice)">缂栬緫</el-button>
@@ -58,7 +60,7 @@
</div>
</div>
<div class="card-content">
- <p>{{ notice.noticeContent }}</p>
+ <p>{{ notice.content }}</p>
</div>
<div class="card-footer">
<div class="card-meta">
@@ -70,35 +72,47 @@
</span>
</div>
<div class="card-info">
- <span class="creator">{{ notice.createBy }}</span>
+ <span class="creator">{{ notice.createUserName }}</span>
<span class="time">{{ notice.createTime }}</span>
</div>
</div>
<div class="card-remark" v-if="notice.remark">
- <el-icon><InfoFilled /></el-icon>
+ <el-icon>
+ <InfoFilled/>
+ </el-icon>
<span>{{ notice.remark }}</span>
</div>
</div>
</div>
</div>
+
+ <pagination
+ v-if="holidayNoticePage.total > 0"
+ :total="holidayNoticePage.total"
+ :page="holidayNoticePage.current"
+ :limit="holidayNoticePage.size"
+ @pagination="handleHolidayNoticeCurrentChange"
+ />
<!-- 璁惧缁翠慨閫氱煡鍖哄煙 -->
- <div class="notice-section" v-if="maintenanceNotices.length > 0">
+ <div class="notice-section" v-if="maintenanceNoticeCount > 0">
<div class="section-header">
<h3>馃敡 璁惧缁翠慨閫氱煡</h3>
- <span class="section-count">{{ maintenanceNotices.length }}鏉�</span>
+ <span class="section-count">{{ maintenanceNoticeCount }}鏉�</span>
</div>
<div class="notice-cards">
- <div
- v-for="notice in maintenanceNotices"
- :key="notice.id"
- class="notice-card maintenance-card"
- :class="{ 'urgent': notice.priority === '3' }"
+ <div
+ v-for="notice in maintenanceNotices"
+ :key="notice.id"
+ class="notice-card maintenance-card"
+ :class="{ 'urgent': notice.priority === '3' }"
>
<div class="card-header">
<div class="card-title">
- <el-icon class="maintenance-icon"><Tools /></el-icon>
- {{ notice.noticeTitle }}
+ <el-icon class="maintenance-icon">
+ <Tools/>
+ </el-icon>
+ {{ notice.title }}
</div>
<div class="card-actions">
<el-button link type="primary" @click="handleEdit(notice)">缂栬緫</el-button>
@@ -106,7 +120,7 @@
</div>
</div>
<div class="card-content">
- <p>{{ notice.noticeContent }}</p>
+ <p>{{ notice.content }}</p>
</div>
<div class="card-footer">
<div class="card-meta">
@@ -118,44 +132,54 @@
</span>
</div>
<div class="card-info">
- <span class="creator">{{ notice.createBy }}</span>
+ <span class="creator">{{ notice.createUserName }}</span>
<span class="time">{{ notice.createTime }}</span>
</div>
</div>
<div class="card-remark" v-if="notice.remark">
- <el-icon><InfoFilled /></el-icon>
+ <el-icon>
+ <InfoFilled/>
+ </el-icon>
<span>{{ notice.remark }}</span>
</div>
</div>
</div>
</div>
+ <pagination
+ v-if="maintenanceNoticePage.total > 0"
+ :total="maintenanceNoticePage.total"
+ :page="maintenanceNoticePage.current"
+ :limit="maintenanceNoticePage.size"
+ @pagination="handleMaintenanceNoticeCurrentChange"
+ />
+
<!-- 绌虹姸鎬� -->
- <div class="empty-state" v-if="filteredNotices.length === 0">
- <el-empty description="鏆傛棤閫氱煡鍏憡" />
+ <div class="empty-state" v-if="holidayNotices.length === 0 && maintenanceNotices.length === 0">
+ <el-empty description="鏆傛棤閫氱煡鍏憡"/>
</div>
</div>
<!-- 鏂板/缂栬緫瀵硅瘽妗� -->
- <el-dialog
- :title="dialogTitle"
- v-model="dialogVisible"
- width="800px"
- append-to-body
- @close="resetForm"
+ <el-dialog
+ :title="dialogTitle"
+ v-model="dialogVisible"
+ width="800px"
+ append-to-body
+ @close="resetForm"
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="12">
- <el-form-item label="鍏憡鏍囬" prop="noticeTitle">
- <el-input v-model="form.noticeTitle" placeholder="璇疯緭鍏ュ叕鍛婃爣棰�" />
+ <el-form-item label="鍏憡鏍囬" prop="title">
+ <el-input v-model="form.title" placeholder="璇疯緭鍏ュ叕鍛婃爣棰�"/>
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="鍏憡绫诲瀷" prop="noticeType">
- <el-select v-model="form.noticeType" placeholder="璇烽�夋嫨鍏憡绫诲瀷" style="width: 100%">
- <el-option label="鏀惧亣閫氱煡" value="1" />
- <el-option label="璁惧缁翠慨閫氱煡" value="2" />
+ <el-form-item label="鍏憡绫诲瀷" prop="type">
+ <el-select v-model="form.type" placeholder="璇烽�夋嫨鍏憡绫诲瀷" style="width: 100%">
+ <el-option label="鏀惧亣閫氱煡" :value="1"/>
+ <el-option label="璁惧缁翠慨閫氱煡" :value="2"/>
</el-select>
</el-form-item>
</el-col>
@@ -164,18 +188,18 @@
<el-col :span="12">
<el-form-item label="鐘舵��">
<el-radio-group v-model="form.status">
- <el-radio value="0">鑽夌</el-radio>
- <el-radio value="1">宸插彂甯�</el-radio>
- <el-radio value="2">宸蹭笅绾�</el-radio>
+ <el-radio :value="0">鑽夌</el-radio>
+ <el-radio :value="1">宸插彂甯�</el-radio>
+ <el-radio :value="2">宸蹭笅绾�</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="浼樺厛绾�">
<el-select v-model="form.priority" placeholder="璇烽�夋嫨浼樺厛绾�" style="width: 100%">
- <el-option label="鏅��" value="1" />
- <el-option label="閲嶈" value="2" />
- <el-option label="绱ф��" value="3" />
+ <el-option label="鏅��" :value="1"/>
+ <el-option label="閲嶈" :value="2"/>
+ <el-option label="绱ф��" :value="3"/>
</el-select>
</el-form-item>
</el-col>
@@ -184,12 +208,12 @@
<el-col :span="24">
<el-form-item label="鍏憡鍐呭" prop="noticeContent">
<el-input
- v-model="form.noticeContent"
- type="textarea"
- :rows="6"
- placeholder="璇疯緭鍏ュ叕鍛婂唴瀹�"
- maxlength="500"
- show-word-limit
+ v-model="form.content"
+ type="textarea"
+ :rows="6"
+ placeholder="璇疯緭鍏ュ叕鍛婂唴瀹�"
+ maxlength="500"
+ show-word-limit
/>
</el-form-item>
</el-col>
@@ -198,12 +222,12 @@
<el-col :span="24">
<el-form-item label="澶囨敞">
<el-input
- v-model="form.remark"
- type="textarea"
- :rows="3"
- placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�"
- maxlength="200"
- show-word-limit
+ v-model="form.remark"
+ type="textarea"
+ :rows="3"
+ placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�"
+ maxlength="200"
+ show-word-limit
/>
</el-form-item>
</el-col>
@@ -220,45 +244,51 @@
</template>
<script setup>
-import { Search, Calendar, Tools, InfoFilled } from "@element-plus/icons-vue";
-import { onMounted, ref, reactive, toRefs, computed } from "vue";
-import { ElMessage, ElMessageBox } from "element-plus";
+import {Search, Calendar, Tools, InfoFilled} from "@element-plus/icons-vue";
+import {onMounted, ref, reactive, toRefs, computed} from "vue";
+import {ElMessage, ElMessageBox} from "element-plus";
import useUserStore from "@/store/modules/user";
+import {
+ addNotice,
+ delNotice,
+ getCount,
+ listNotice,
+ updateNotice
+} from "../../../api/collaborativeApproval/noticeManagement.js";
+import pagination from "../../../components/PIMTable/Pagination.vue";
const userStore = useUserStore();
// 鍝嶅簲寮忔暟鎹�
const data = reactive({
searchForm: {
- noticeTitle: "",
- noticeType: "",
- status: "",
+ title: "",
+ type: undefined,
+ status: undefined,
},
form: {
id: undefined,
- noticeTitle: "",
- noticeType: "",
- noticeContent: "",
- status: "0",
- priority: "1",
+ title: "",
+ type: null,
+ content: "",
+ status: 0,
+ priority: 1,
remark: "",
- createBy: "",
- createTime: "",
},
rules: {
- noticeTitle: [
- { required: true, message: "鍏憡鏍囬涓嶈兘涓虹┖", trigger: "blur" }
+ title: [
+ {required: true, message: "鍏憡鏍囬涓嶈兘涓虹┖", trigger: "blur"}
],
- noticeType: [
- { required: true, message: "璇烽�夋嫨鍏憡绫诲瀷", trigger: "change" }
+ type: [
+ {required: true, message: "璇烽�夋嫨鍏憡绫诲瀷", trigger: "change"}
],
- noticeContent: [
- { required: true, message: "鍏憡鍐呭涓嶈兘涓虹┖", trigger: "blur" }
+ content: [
+ {required: true, message: "鍏憡鍐呭涓嶈兘涓虹┖", trigger: "blur"}
]
}
});
-const { searchForm, form, rules } = toRefs(data);
+const {searchForm, form, rules} = toRefs(data);
// 椤甸潰鐘舵��
const dialogVisible = ref(false);
@@ -266,127 +296,28 @@
const selectedIds = ref([]);
const formRef = ref();
-// 妯℃嫙鏁版嵁 - 鏍规嵁娉曞畾鑺傚亣鏃ヨ璁�
-const mockData = [
- {
- id: 1,
- noticeTitle: "2024骞存槬鑺傛斁鍋囬�氱煡",
- noticeType: "1",
- priority: "2",
- status: "1",
- noticeContent: "鏍规嵁鍥藉姟闄㈠姙鍏巺閫氱煡锛�2024骞存槬鑺傛斁鍋囧畨鎺掑涓嬶細2鏈�10鏃ワ紙鍒濅竴锛夎嚦2鏈�17鏃ワ紙鍒濆叓锛夋斁鍋囪皟浼戯紝鍏�8澶┿��2鏈�4鏃ワ紙鏄熸湡鏃ワ級銆�2鏈�18鏃ワ紙鏄熸湡鏃ワ級涓婄彮銆傝鍚勯儴闂ㄦ彁鍓嶅仛濂藉伐浣滃畨鎺掋��",
- remark: "鏀惧亣鏈熼棿璇蜂繚鎸佹墜鏈虹晠閫氾紝濡傛湁绱ф�ヤ簨鍔″強鏃惰仈绯�",
- createBy: "浜轰簨閮�",
- createTime: "2024-01-15 10:30:00"
- },
- {
- id: 2,
- noticeTitle: "2024骞存竻鏄庤妭鏀惧亣閫氱煡",
- noticeType: "1",
- priority: "1",
- status: "1",
- noticeContent: "鏍规嵁鍥藉姟闄㈠姙鍏巺閫氱煡锛�2024骞存竻鏄庤妭鏀惧亣瀹夋帓濡備笅锛�4鏈�4鏃ワ紙鏄熸湡鍥涳級鑷�4鏈�6鏃ワ紙鏄熸湡鍏級鏀惧亣璋冧紤锛屽叡3澶┿��4鏈�7鏃ワ紙鏄熸湡鏃ワ級涓婄彮銆�",
- remark: "璇峰悇閮ㄩ棬鍋氬ソ鍊肩彮瀹夋帓锛岀‘淇濊妭鏃ユ湡闂村悇椤瑰伐浣滄甯歌繍杞�",
- createBy: "琛屾斂閮�",
- createTime: "2024-01-14 14:20:00"
- },
- {
- id: 3,
- noticeTitle: "2024骞村姵鍔ㄨ妭鏀惧亣閫氱煡",
- noticeType: "1",
- priority: "1",
- status: "1",
- noticeContent: "鏍规嵁鍥藉姟闄㈠姙鍏巺閫氱煡锛�2024骞村姵鍔ㄨ妭鏀惧亣瀹夋帓濡備笅锛�5鏈�1鏃ワ紙鏄熸湡涓夛級鑷�5鏈�5鏃ワ紙鏄熸湡鏃ワ級鏀惧亣璋冧紤锛屽叡5澶┿��4鏈�28鏃ワ紙鏄熸湡鏃ワ級銆�5鏈�11鏃ワ紙鏄熸湡鍏級涓婄彮銆�",
- remark: "鏀惧亣鍓嶈鍏抽棴鐢垫簮锛岄攣濂介棬绐楋紝娉ㄦ剰瀹夊叏",
- createBy: "琛屾斂閮�",
- createTime: "2024-01-13 09:15:00"
- },
- {
- id: 4,
- noticeTitle: "2024骞寸鍗堣妭鏀惧亣閫氱煡",
- noticeType: "1",
- priority: "1",
- status: "1",
- noticeContent: "鏍规嵁鍥藉姟闄㈠姙鍏巺閫氱煡锛�2024骞寸鍗堣妭鏀惧亣瀹夋帓濡備笅锛�6鏈�8鏃ワ紙鏄熸湡鍏級鑷�6鏈�10鏃ワ紙鏄熸湡涓�锛夋斁鍋囪皟浼戯紝鍏�3澶┿��6鏈�11鏃ワ紙鏄熸湡浜岋級涓婄彮銆�",
- remark: "绁濆ぇ瀹剁鍗堣妭蹇箰锛岄槚瀹跺垢绂忥紒",
- createBy: "琛屾斂閮�",
- createTime: "2024-01-12 16:30:00"
- },
- {
- id: 5,
- noticeTitle: "2024骞翠腑绉嬭妭鏀惧亣閫氱煡",
- noticeType: "1",
- priority: "1",
- status: "1",
- noticeContent: "鏍规嵁鍥藉姟闄㈠姙鍏巺閫氱煡锛�2024骞翠腑绉嬭妭鏀惧亣瀹夋帓濡備笅锛�9鏈�15鏃ワ紙鏄熸湡鏃ワ級鑷�9鏈�17鏃ワ紙鏄熸湡浜岋級鏀惧亣璋冧紤锛屽叡3澶┿��9鏈�14鏃ワ紙鏄熸湡鍏級涓婄彮銆�",
- remark: "涓浣宠妭锛岀澶у鍥㈠渾缇庢弧锛屽垢绂忓畨搴凤紒",
- createBy: "琛屾斂閮�",
- createTime: "2024-01-11 11:20:00"
- },
- {
- id: 6,
- noticeTitle: "2024骞村浗搴嗚妭鏀惧亣閫氱煡",
- noticeType: "1",
- priority: "2",
- status: "1",
- noticeContent: "鏍规嵁鍥藉姟闄㈠姙鍏巺閫氱煡锛�2024骞村浗搴嗚妭鏀惧亣瀹夋帓濡備笅锛�10鏈�1鏃ワ紙鏄熸湡浜岋級鑷�10鏈�7鏃ワ紙鏄熸湡涓�锛夋斁鍋囪皟浼戯紝鍏�7澶┿��9鏈�29鏃ワ紙鏄熸湡鏃ワ級銆�10鏈�12鏃ワ紙鏄熸湡鍏級涓婄彮銆�",
- remark: "鍥藉簡鏈熼棿璇峰悇閮ㄩ棬鍋氬ソ鍊肩彮瀹夋帓锛岀‘淇濆畨鍏ㄧǔ瀹�",
- createBy: "琛屾斂閮�",
- createTime: "2024-01-10 15:45:00"
- },
- {
- id: 7,
- noticeTitle: "A杞﹂棿鐢熶骇绾垮勾搴︽淇�氱煡",
- noticeType: "2",
- priority: "2",
- status: "1",
- noticeContent: "A杞﹂棿鐢熶骇绾垮皢浜�2024骞�1鏈�20鏃ワ紙鍛ㄥ叚锛夎繘琛屽勾搴︽淇淮鎶わ紝棰勮鍋滃伐8灏忔椂銆傛淇唴瀹瑰寘鎷細璁惧娓呮磥銆佹鼎婊戜繚鍏汇�佸畨鍏ㄨ缃鏌ョ瓑銆傝鐢熶骇閮ㄩ棬鎻愬墠璋冩暣鐢熶骇璁″垝銆�",
- remark: "缁翠慨鏈熼棿璇风浉鍏充汉鍛橀厤鍚堬紝纭繚妫�淇伐浣滃畨鍏ㄩ『鍒╄繘琛�",
- createBy: "璁惧閮�",
- createTime: "2024-01-14 14:20:00"
- },
- {
- id: 8,
- noticeTitle: "B杞﹂棿璁惧棰勯槻鎬х淮鎶ら�氱煡",
- noticeType: "2",
- priority: "1",
- status: "1",
- noticeContent: "B杞﹂棿鍏抽敭璁惧灏嗕簬2024骞�1鏈�25鏃ヨ繘琛岄闃叉�х淮鎶わ紝棰勮鍋滃伐4灏忔椂銆傜淮鎶ゅ唴瀹瑰寘鎷細璁惧妫�鏌ャ�侀浂浠舵洿鎹€�佹�ц兘娴嬭瘯绛夈�傝鐩稿叧閮ㄩ棬閰嶅悎銆�",
- remark: "缁存姢瀹屾垚鍚庡皢杩涜璇曡繍琛岋紝纭繚璁惧姝e父杩愯",
- createBy: "璁惧閮�",
- createTime: "2024-01-13 09:15:00"
- }
-];
// 璁$畻灞炴��
const filteredNotices = computed(() => {
let filtered = [...mockData];
-
+
if (searchForm.value.noticeTitle) {
- filtered = filtered.filter(item =>
- item.noticeTitle.includes(searchForm.value.noticeTitle)
+ filtered = filtered.filter(item =>
+ item.noticeTitle.includes(searchForm.value.noticeTitle)
);
}
if (searchForm.value.noticeType) {
- filtered = filtered.filter(item =>
- item.noticeType === searchForm.value.noticeType
+ filtered = filtered.filter(item =>
+ item.noticeType === searchForm.value.noticeType
);
}
if (searchForm.value.status !== "") {
- filtered = filtered.filter(item =>
- item.status === searchForm.value.status
+ filtered = filtered.filter(item =>
+ item.status === searchForm.value.status
);
}
-
+
return filtered;
-});
-
-const holidayNotices = computed(() => {
- return filteredNotices.value.filter(notice => notice.noticeType === "1");
-});
-
-const maintenanceNotices = computed(() => {
- return filteredNotices.value.filter(notice => notice.noticeType === "2");
});
// 鏂规硶瀹氫箟
@@ -396,19 +327,19 @@
const resetQuery = () => {
searchForm.value = {
- noticeTitle: "",
- noticeType: "",
+ title: "",
+ type: "",
status: ""
};
};
const getPriorityText = (priority) => {
- const priorityMap = { "1": "鏅��", "2": "閲嶈", "3": "绱ф��" };
+ const priorityMap = {"1": "鏅��", "2": "閲嶈", "3": "绱ф��"};
return priorityMap[priority] || "鏅��";
};
const getStatusText = (status) => {
- const statusMap = { "0": "鑽夌", "1": "宸插彂甯�", "2": "宸蹭笅绾�" };
+ const statusMap = {"0": "鑽夌", "1": "宸插彂甯�", "2": "宸蹭笅绾�"};
return statusMap[status] || "鏈煡";
};
@@ -417,14 +348,12 @@
dialogTitle.value = "鏂板鍏憡";
form.value = {
id: undefined,
- noticeTitle: "",
- noticeType: "",
- noticeContent: "",
- status: "0",
- priority: "1",
+ title: "",
+ type: undefined,
+ content: "",
+ status: 0,
+ priority: 1,
remark: "",
- createBy: userStore.name || "褰撳墠鐢ㄦ埛",
- createTime: new Date().toLocaleString()
};
}
dialogVisible.value = true;
@@ -432,29 +361,24 @@
const handleEdit = (row) => {
dialogTitle.value = "缂栬緫鍏憡";
- form.value = { ...row };
+ form.value = {...row};
dialogVisible.value = true;
-};
-
-const handleSelectionChange = (selection) => {
- selectedIds.value = selection.map(item => item.id);
};
const handleDelete = (id) => {
ElMessageBox.confirm(
- "纭鍒犻櫎杩欐潯鍏憡鍚楋紵",
- "鎻愮ず",
- {
- confirmButtonText: "纭畾",
- cancelButtonText: "鍙栨秷",
- type: "warning"
- }
+ "纭鍒犻櫎杩欐潯鍏憡鍚楋紵",
+ "鎻愮ず",
+ {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning"
+ }
).then(() => {
- const index = mockData.findIndex(item => item.id === id);
- if (index > -1) {
- mockData.splice(index, 1);
+ delNotice(id).then(res => {
ElMessage.success("鍒犻櫎鎴愬姛");
- }
+ resetTable()
+ })
});
};
@@ -463,25 +387,83 @@
if (valid) {
if (form.value.id) {
// 缂栬緫妯″紡
- const index = mockData.findIndex(item => item.id === form.value.id);
- if (index > -1) {
- mockData[index] = { ...form.value };
- }
- ElMessage.success("淇敼鎴愬姛");
+ updateNotice(form.value).then(res => {
+ ElMessage.success("淇敼鎴愬姛");
+ resetTable()
+ })
} else {
// 鏂板妯″紡
- const newId = Math.max(...mockData.map(item => item.id)) + 1;
- const newNotice = {
- ...form.value,
- id: newId,
- createTime: new Date().toLocaleString()
- };
- mockData.unshift(newNotice);
- ElMessage.success("鏂板鎴愬姛");
+ addNotice(form.value).then(res => {
+ ElMessage.success("鏂板鎴愬姛");
+ resetTable()
+ })
}
dialogVisible.value = false;
}
});
+};
+
+const holidayNoticeCount = ref()
+const maintenanceNoticeCount = ref()
+const fetchCount = () => {
+ getCount().then(res => {
+ holidayNoticeCount.value = res.data.filter(item => {
+ return item.type === 1
+ })[0].count;
+ maintenanceNoticeCount.value = res.data.filter(item => {
+ return item.type === 2
+ })[0].count;
+ });
+}
+
+const holidayNotices = ref([])
+const maintenanceNotices = ref([])
+const holidayNoticePage = ref({
+ total: 0,
+ current: 1,
+ size: 6
+})
+
+const maintenanceNoticePage = ref({
+ total: 0,
+ current: 1,
+ size: 6
+})
+
+const fetchHolidayNotices = () => {
+ listNotice({...holidayNoticePage.value, type: 1}).then(res => {
+ holidayNotices.value = res.data.records
+ holidayNoticePage.value.total = res.data.total
+ });
+};
+
+const fetchMaintenanceNotices = () => {
+ listNotice({...holidayNoticePage.value, type: 2}).then(res => {
+ maintenanceNotices.value = res.data.records
+ maintenanceNoticePage.value.total = res.data.total
+ });
+};
+
+const handleHolidayNoticeCurrentChange = (val) => {
+ holidayNoticePage.value.size = val.limit
+ holidayNoticePage.value.current = val.page
+ fetchHolidayNotices()
+};
+
+const handleMaintenanceNoticeCurrentChange = (val) => {
+ maintenanceNoticePage.value.size = val.limit
+ maintenanceNoticePage.value.current = val.page
+ fetchMaintenanceNotices()
+};
+
+const resetTable = () => {
+ holidayNoticePage.value.current = 1
+ holidayNoticePage.value.size = 6
+ maintenanceNoticePage.value.current = 1
+ maintenanceNoticePage.value.size = 6
+ fetchHolidayNotices()
+ fetchMaintenanceNotices()
+ fetchCount()
};
const resetForm = () => {
@@ -490,7 +472,9 @@
// 鐢熷懡鍛ㄦ湡
onMounted(() => {
- // 椤甸潰鍔犺浇瀹屾垚
+ fetchCount()
+ fetchHolidayNotices()
+ fetchMaintenanceNotices()
});
</script>
@@ -645,13 +629,35 @@
font-weight: 500;
}
-.priority-1 { background: #f0f9ff; color: #0369a1; }
-.priority-2 { background: #fef3c7; color: #d97706; }
-.priority-3 { background: #fef2f2; color: #dc2626; }
+.priority-1 {
+ background: #f0f9ff;
+ color: #0369a1;
+}
-.status-0 { background: #f3f4f6; color: #6b7280; }
-.status-1 { background: #d1fae5; color: #059669; }
-.status-2 { background: #fef3c7; color: #d97706; }
+.priority-2 {
+ background: #fef3c7;
+ color: #d97706;
+}
+
+.priority-3 {
+ background: #fef2f2;
+ color: #dc2626;
+}
+
+.status-0 {
+ background: #f3f4f6;
+ color: #6b7280;
+}
+
+.status-1 {
+ background: #d1fae5;
+ color: #059669;
+}
+
+.status-2 {
+ background: #fef3c7;
+ color: #d97706;
+}
.card-info {
display: flex;
@@ -692,12 +698,12 @@
.notice-cards {
grid-template-columns: 1fr;
}
-
+
.search_form {
flex-direction: column;
gap: 15px;
}
-
+
.search_form > div {
width: 100%;
}
diff --git a/src/views/equipmentManagement/deviceInfo/index.vue b/src/views/equipmentManagement/deviceInfo/index.vue
new file mode 100644
index 0000000..de162cc
--- /dev/null
+++ b/src/views/equipmentManagement/deviceInfo/index.vue
@@ -0,0 +1,190 @@
+<template>
+ <div class="device-info-container">
+ <div class="page-header">
+ <h1>璁惧淇℃伅</h1>
+ <div class="device-status" :class="deviceStatusClass">
+ {{ deviceStatusText }}
+ </div>
+ </div>
+
+ <div class="info-card">
+ <div class="card-header">鍩烘湰淇℃伅</div>
+ <div class="card-content">
+ <div class="info-row">
+ <span class="label">璁惧鍚嶇О锛�</span>
+ <span class="value">{{ deviceInfo.deviceName }}</span>
+ </div>
+ <div class="info-row">
+ <span class="label">瑙勬牸鍨嬪彿锛�</span>
+ <span class="value">{{ deviceInfo.deviceModel }}</span>
+ </div>
+ <div class="info-row">
+ <span class="label">鐢熶骇鍘傚锛�</span>
+ <span class="value">{{ deviceInfo.supplierName }}</span>
+ </div>
+ <div class="info-row">
+ <span class="label">鍗曚綅锛�</span>
+ <span class="value">{{ deviceInfo.unit }}</span>
+ </div>
+ </div>
+ </div>
+
+ <div class="info-card">
+ <div class="card-header">缁存姢淇℃伅</div>
+ <div class="card-content">
+ <div class="maintenance-info">
+ <div class="maintenance-item">
+ <span class="label">鏈�鍚庣淮鎶わ細</span>
+ <span class="value">{{ deviceInfo.updateTime }}</span>
+ </div>
+ <div class="maintenance-item">
+ <span class="label">涓嬫缁存姢锛�</span>
+ <span class="value">{{ deviceInfo.createTime }}</span>
+ </div>
+ <div class="maintenance-item">
+ <span class="label">缁存姢鐘舵�侊細</span>
+ <span class="value status-normal">{{ deviceInfo.statusText }}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, computed } from 'vue'
+import { useRoute } from 'vue-router'
+import { ElMessage } from 'element-plus'
+import {
+ getDeviceInfo,
+} from '@/api/equipmentManagement/deviceInfo'
+
+const route = useRoute()
+
+const deviceInfo = reactive({
+ deviceName: '',
+ deviceModel: '',
+ supplierName: '',
+ unit: '',
+ statusText:'姝e父',
+ updateTime:'',
+ createTime:''
+})
+
+const deviceStatusClass = computed(() => {
+ return 'status-normal'
+})
+
+const deviceStatusText = computed(() => {
+ return '姝e父'
+})
+
+const fetchDeviceInfo = async (deviceId) => {
+ try {
+ // 鑾峰彇璁惧淇℃伅
+ const deviceResponse = await getDeviceInfo({id:deviceId})
+ if (deviceResponse.code === 200) {
+ Object.assign(deviceInfo, deviceResponse.data)
+ }
+
+
+ } catch (error) {
+
+ ElMessage.warning('浣跨敤妯℃嫙鏁版嵁锛屽疄闄匒PI璋冪敤澶辫触')
+ }
+}
+
+onMounted(() => {
+ const deviceId = route.query.deviceId || route.params.deviceId || ''
+ fetchDeviceInfo(deviceId)
+})
+</script>
+
+<style scoped>
+.device-info-container {
+ min-height: 100vh;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ padding: 20px;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+}
+
+.page-header {
+ background: rgba(255, 255, 255, 0.95);
+ border-radius: 16px;
+ padding: 20px;
+ margin-bottom: 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.page-header h1 {
+ margin: 0;
+ color: #2c3e50;
+ font-size: 24px;
+}
+
+.device-status {
+ padding: 8px 16px;
+ border-radius: 20px;
+ font-size: 14px;
+ color: white;
+ background: #52c41a;
+}
+
+.info-card {
+ background: rgba(255, 255, 255, 0.95);
+ border-radius: 16px;
+ margin-bottom: 20px;
+ overflow: hidden;
+}
+
+.card-header {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ color: white;
+ padding: 16px 20px;
+ font-weight: 500;
+}
+
+.card-content {
+ padding: 20px;
+}
+
+.info-row, .maintenance-item {
+ display: flex;
+ margin-bottom: 12px;
+ align-items: center;
+}
+
+.label {
+ width: 100px;
+ color: #666;
+ font-size: 14px;
+}
+
+.value {
+ flex: 1;
+ color: #2c3e50;
+ font-weight: 500;
+}
+
+.status-normal {
+ color: #52c41a;
+}
+
+
+
+@media (max-width: 768px) {
+ .device-info-container {
+ padding: 16px;
+ }
+
+ .page-header h1 {
+ font-size: 20px;
+ }
+
+ .label {
+ width: 80px;
+ }
+}
+</style>
diff --git a/src/views/equipmentManagement/ledger/index.vue b/src/views/equipmentManagement/ledger/index.vue
index 428a6d9..28e5ec8 100644
--- a/src/views/equipmentManagement/ledger/index.vue
+++ b/src/views/equipmentManagement/ledger/index.vue
@@ -275,8 +275,8 @@
};
const showQRCode = async (row) => {
- // 浣犲彲浠ヨ嚜瀹氫箟浜岀淮鐮佸唴瀹癸紝姣斿 row.id 鎴� row.deviceName
- const qrContent = JSON.stringify(row); // 鎴� `${row.id}`
+ // 鐩存帴浣跨敤URL锛屼笉瑕佺敤JSON.stringify鍖呰
+ const qrContent = proxy.javaApi + '/device-info?deviceId=' + row.id;
qrCodeUrl.value = await QRCode.toDataURL(qrContent);
qrRowData.value = row;
qrDialogVisible.value = true;
diff --git a/src/views/example/DynamicTableExample.vue b/src/views/example/DynamicTableExample.vue
new file mode 100644
index 0000000..038cd43
--- /dev/null
+++ b/src/views/example/DynamicTableExample.vue
@@ -0,0 +1,354 @@
+<template>
+ <div class="app-container">
+ <div class="search-form">
+ <el-form :inline="true" :model="searchForm">
+ <el-form-item label="閮ㄩ棬">
+ <el-input
+ v-model="searchForm.department"
+ placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�"
+ clearable
+ style="width: 200px"
+ />
+ </el-form-item>
+ <el-form-item label="濮撳悕">
+ <el-input
+ v-model="searchForm.name"
+ placeholder="璇疯緭鍏ュ鍚�"
+ clearable
+ style="width: 200px"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleSearch">鎼滅储</el-button>
+ <el-button @click="handleReset">閲嶇疆</el-button>
+ <el-button type="success" @click="handleAdd">鏂板</el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+
+ <div class="table-container">
+ <DynamicTable
+ ref="dynamicTableRef"
+ :data="tableData"
+ :dict-types="dictTypes"
+ :loading="loading"
+ :show-selection="true"
+ :show-actions="true"
+ :show-pagination="true"
+ :pagination="pagination"
+ height="calc(100vh - 280px)"
+ @selection-change="handleSelectionChange"
+ @edit="handleEdit"
+ @delete="handleDelete"
+ @select-change="handleSelectChange"
+ @input-change="handleInputChange"
+ @size-change="handleSizeChange"
+ @current-change="handleCurrentChange"
+ />
+ </div>
+
+ <!-- 鏂板/缂栬緫瀵硅瘽妗� -->
+ <el-dialog
+ v-model="dialogVisible"
+ :title="dialogTitle"
+ width="600px"
+ append-to-body
+ >
+ <el-form
+ ref="formRef"
+ :model="form"
+ :rules="rules"
+ label-width="100px"
+ >
+ <el-form-item label="閮ㄩ棬" prop="department">
+ <el-input v-model="form.department" placeholder="璇疯緭鍏ラ儴闂�" />
+ </el-form-item>
+ <el-form-item label="濮撳悕" prop="name">
+ <el-input v-model="form.name" placeholder="璇疯緭鍏ュ鍚�" />
+ </el-form-item>
+ <el-form-item label="宸ュ彿" prop="employeeId">
+ <el-input v-model="form.employeeId" placeholder="璇疯緭鍏ュ伐鍙�" />
+ </el-form-item>
+
+ <!-- 鍔ㄦ�佽〃鍗曢」锛氭牴鎹瓧鍏哥敓鎴� -->
+ <el-form-item
+ v-for="dictItem in dynamicFormItems"
+ :key="dictItem.value"
+ :label="dictItem.label"
+ :prop="dictItem.value"
+ >
+ <el-select
+ v-model="form[dictItem.value]"
+ placeholder="璇烽�夋嫨"
+ style="width: 100%"
+ >
+ <el-option
+ v-for="option in dictItem.options"
+ :key="option.value"
+ :label="option.label"
+ :value="option.value"
+ />
+ </el-select>
+ </el-form-item>
+ </el-form>
+
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="handleSubmit">纭畾</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed, onMounted } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import DynamicTable from '@/components/DynamicTable/index.vue'
+
+// 鍝嶅簲寮忔暟鎹�
+const loading = ref(false)
+const dialogVisible = ref(false)
+const dialogTitle = ref('')
+const editIndex = ref(-1)
+const selectedRows = ref([])
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+ department: '',
+ name: ''
+})
+
+// 琛ㄦ牸鏁版嵁
+const tableData = ref([
+ {
+ id: 1,
+ department: '鎶�鏈儴',
+ name: '寮犱笁',
+ employeeId: 'EMP001',
+ status: '1',
+ level: '2',
+ position: '1'
+ },
+ {
+ id: 2,
+ department: '浜轰簨閮�',
+ name: '鏉庡洓',
+ employeeId: 'EMP002',
+ status: '0',
+ level: '1',
+ position: '2'
+ },
+ {
+ id: 3,
+ department: '璐㈠姟閮�',
+ name: '鐜嬩簲',
+ employeeId: 'EMP003',
+ status: '1',
+ level: '3',
+ position: '1'
+ }
+])
+
+// 瀛楀吀绫诲瀷閰嶇疆
+const dictTypes = ref([
+ 'sys_normal_disable', // 鐘舵�佸瓧鍏�
+ 'sys_user_level', // 绾у埆瀛楀吀
+ 'sys_user_position' // 鑱屼綅瀛楀吀
+])
+
+// 鍒嗛〉閰嶇疆
+const pagination = reactive({
+ current: 1,
+ size: 10,
+ total: 0
+})
+
+// 琛ㄥ崟鏁版嵁
+const form = reactive({
+ department: '',
+ name: '',
+ employeeId: '',
+ status: '',
+ level: '',
+ position: ''
+})
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const rules = {
+ department: [
+ { required: true, message: '璇疯緭鍏ラ儴闂�', trigger: 'blur' }
+ ],
+ name: [
+ { required: true, message: '璇疯緭鍏ュ鍚�', trigger: 'blur' }
+ ],
+ employeeId: [
+ { required: true, message: '璇疯緭鍏ュ伐鍙�', trigger: 'blur' }
+ ]
+}
+
+// 鍔ㄦ�佽〃鍗曢」
+const dynamicFormItems = computed(() => {
+ // 杩欓噷鍙互鏍规嵁瀛楀吀鏁版嵁鍔ㄦ�佺敓鎴愯〃鍗曢」
+ return [
+ {
+ label: '鐘舵��',
+ value: 'status',
+ options: [
+ { label: '鍚敤', value: '1' },
+ { label: '绂佺敤', value: '0' }
+ ]
+ },
+ {
+ label: '绾у埆',
+ value: 'level',
+ options: [
+ { label: '鍒濈骇', value: '1' },
+ { label: '涓骇', value: '2' },
+ { label: '楂樼骇', value: '3' }
+ ]
+ },
+ {
+ label: '鑱屼綅',
+ value: 'position',
+ options: [
+ { label: '鍛樺伐', value: '1' },
+ { label: '涓荤', value: '2' },
+ { label: '缁忕悊', value: '3' }
+ ]
+ }
+ ]
+})
+
+// 缁勪欢寮曠敤
+const dynamicTableRef = ref(null)
+const formRef = ref(null)
+
+// 浜嬩欢澶勭悊鍑芥暟
+const handleSearch = () => {
+ // 瀹炵幇鎼滅储閫昏緫
+ console.log('鎼滅储鏉′欢:', searchForm)
+ ElMessage.success('鎼滅储鍔熻兘寰呭疄鐜�')
+}
+
+const handleReset = () => {
+ searchForm.department = ''
+ searchForm.name = ''
+}
+
+const handleAdd = () => {
+ dialogTitle.value = '鏂板鍛樺伐'
+ editIndex.value = -1
+ resetForm()
+ dialogVisible.value = true
+}
+
+const handleEdit = (row, index) => {
+ dialogTitle.value = '缂栬緫鍛樺伐'
+ editIndex.value = index
+ Object.assign(form, row)
+ dialogVisible.value = true
+}
+
+const handleDelete = async (row, index) => {
+ try {
+ await ElMessageBox.confirm('纭畾瑕佸垹闄よ繖鏉¤褰曞悧锛�', '鎻愮ず', {
+ type: 'warning'
+ })
+
+ tableData.value.splice(index, 1)
+ ElMessage.success('鍒犻櫎鎴愬姛')
+ } catch (error) {
+ // 鐢ㄦ埛鍙栨秷鍒犻櫎
+ }
+}
+
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection
+}
+
+const handleSelectChange = (row, prop, value) => {
+ console.log('閫夋嫨鍙樺寲:', row, prop, value)
+ // 鍙互鍦ㄨ繖閲屽鐞嗘暟鎹洿鏂伴�昏緫
+}
+
+const handleInputChange = (row, prop, value) => {
+ console.log('杈撳叆鍙樺寲:', row, prop, value)
+ // 鍙互鍦ㄨ繖閲屽鐞嗘暟鎹洿鏂伴�昏緫
+}
+
+const handleSizeChange = (size) => {
+ pagination.size = size
+ // 閲嶆柊鍔犺浇鏁版嵁
+}
+
+const handleCurrentChange = (current) => {
+ pagination.current = current
+ // 閲嶆柊鍔犺浇鏁版嵁
+}
+
+const handleSubmit = async () => {
+ try {
+ await formRef.value.validate()
+
+ if (editIndex.value === -1) {
+ // 鏂板
+ const newRow = {
+ id: Date.now(),
+ ...form
+ }
+ tableData.value.push(newRow)
+ ElMessage.success('鏂板鎴愬姛')
+ } else {
+ // 缂栬緫
+ Object.assign(tableData.value[editIndex.value], form)
+ ElMessage.success('缂栬緫鎴愬姛')
+ }
+
+ dialogVisible.value = false
+ } catch (error) {
+ console.error('琛ㄥ崟楠岃瘉澶辫触:', error)
+ }
+}
+
+const resetForm = () => {
+ Object.assign(form, {
+ department: '',
+ name: '',
+ employeeId: '',
+ status: '',
+ level: '',
+ position: ''
+ })
+ formRef.value?.resetFields()
+}
+
+// 缁勪欢鎸傝浇鏃跺垵濮嬪寲鏁版嵁
+onMounted(() => {
+ pagination.total = tableData.value.length
+})
+</script>
+
+<style scoped>
+.app-container {
+ padding: 20px;
+}
+
+.search-form {
+ margin-bottom: 20px;
+ padding: 20px;
+ background-color: #f5f5f5;
+ border-radius: 4px;
+}
+
+.table-container {
+ background-color: #fff;
+ border-radius: 4px;
+ padding: 20px;
+}
+
+.dialog-footer {
+ text-align: right;
+}
+</style>
diff --git a/src/views/example/SimpleExample.vue b/src/views/example/SimpleExample.vue
new file mode 100644
index 0000000..fb528eb
--- /dev/null
+++ b/src/views/example/SimpleExample.vue
@@ -0,0 +1,135 @@
+<template>
+ <div class="app-container">
+ <!-- 绠�鍗曠殑鎼滅储鍖哄煙 -->
+ <el-card class="search-card">
+ <el-form :inline="true">
+ <el-form-item label="閮ㄩ棬">
+ <el-input v-model="searchForm.department" placeholder="璇疯緭鍏ラ儴闂�" clearable />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleSearch">鎼滅储</el-button>
+ <el-button @click="handleReset">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ </el-card>
+
+ <!-- 鍔ㄦ�佽〃鏍� -->
+ <el-card class="table-card">
+ <template #header>
+ <div class="card-header">
+ <span>鍛樺伐淇℃伅琛�</span>
+ <el-button type="primary" size="small" @click="handleAdd">鏂板鍛樺伐</el-button>
+ </div>
+ </template>
+
+ <DynamicTable
+ :data="tableData"
+ :dict-types="dictTypes"
+ :loading="loading"
+ :show-selection="true"
+ :show-actions="true"
+ height="400px"
+ @selection-change="handleSelectionChange"
+ @edit="handleEdit"
+ @delete="handleDelete"
+ />
+ </el-card>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue'
+import { ElMessage } from 'element-plus'
+import DynamicTable from '@/components/DynamicTable/index.vue'
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+ department: ''
+})
+
+// 琛ㄦ牸鏁版嵁
+const tableData = ref([
+ {
+ id: 1,
+ department: '鎶�鏈儴',
+ name: '寮犱笁',
+ employeeId: 'EMP001',
+ sys_normal_disable: '1', // 鐘舵��
+ sys_user_level: '2', // 绾у埆
+ sys_user_position: '1' // 鑱屼綅
+ },
+ {
+ id: 2,
+ department: '浜轰簨閮�',
+ name: '鏉庡洓',
+ employeeId: 'EMP002',
+ sys_normal_disable: '0', // 鐘舵��
+ sys_user_level: '1', // 绾у埆
+ sys_user_position: '2' // 鑱屼綅
+ }
+])
+
+// 瀛楀吀绫诲瀷
+const dictTypes = ref([
+ 'sys_normal_disable', // 鐘舵�侊細鍚敤/绂佺敤
+ 'sys_user_level', // 绾у埆锛氬垵绾�/涓骇/楂樼骇
+ 'sys_user_position' // 鑱屼綅锛氬憳宸�/涓荤/缁忕悊
+])
+
+// 鍔犺浇鐘舵��
+const loading = ref(false)
+
+// 浜嬩欢澶勭悊
+const handleSearch = () => {
+ loading.value = true
+ // 妯℃嫙鎼滅储
+ setTimeout(() => {
+ loading.value = false
+ ElMessage.success('鎼滅储瀹屾垚')
+ }, 1000)
+}
+
+const handleReset = () => {
+ searchForm.department = ''
+}
+
+const handleAdd = () => {
+ ElMessage.info('鏂板鍔熻兘寰呭疄鐜�')
+}
+
+const handleSelectionChange = (selection) => {
+ console.log('閫変腑鐨勮:', selection)
+}
+
+const handleEdit = (row, index) => {
+ ElMessage.info(`缂栬緫绗�${index + 1}琛屾暟鎹甡)
+}
+
+const handleDelete = (row, index) => {
+ ElMessage.warning(`鍒犻櫎绗�${index + 1}琛屾暟鎹甡)
+}
+</script>
+
+<style scoped>
+.app-container {
+ padding: 20px;
+}
+
+.search-card {
+ margin-bottom: 20px;
+}
+
+.table-card {
+ margin-bottom: 20px;
+}
+
+.card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+:deep(.el-form-item) {
+ margin-bottom: 0;
+}
+</style>
diff --git a/src/views/fileManagement/bookshelf/detail.vue b/src/views/fileManagement/bookshelf/detail.vue
new file mode 100644
index 0000000..5d7d3ac
--- /dev/null
+++ b/src/views/fileManagement/bookshelf/detail.vue
@@ -0,0 +1,110 @@
+<template>
+ <div class="detail-container">
+ <div class="header">
+ <el-button @click="handleBack" type="primary" size="small">杩斿洖</el-button>
+ <h2>鍥句功璇︽儏</h2>
+ </div>
+
+ <div class="content" v-loading="loading">
+ <el-card v-if="current">
+ <template #header>
+ <div class="card-header">
+ <span>鍩烘湰淇℃伅</span>
+ </div>
+ </template>
+
+ <el-descriptions :column="2" border>
+ <el-descriptions-item label="鍥句功缂栧彿">{{ current.docNumber }}</el-descriptions-item>
+ <el-descriptions-item label="鍥句功鍚嶇О">{{ current.docName }}</el-descriptions-item>
+ <el-descriptions-item label="鍏ュ簱鏃堕棿">{{ current.createTime }}</el-descriptions-item>
+ <!-- <el-descriptions-item label="褰撳墠浣嶇疆">{{ current.currentLocation }}</el-descriptions-item> -->
+ <el-descriptions-item label="鐘舵��">{{ current.docStatus }}</el-descriptions-item>
+ </el-descriptions>
+
+ <!-- <div class="additional-info" v-if="current.description">
+ <h4>鍥句功绠�浠�</h4>
+ <p>{{ current.description }}</p>
+ </div> -->
+ </el-card>
+
+ <el-empty v-else description="鏆傛棤鏁版嵁" />
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+// 瀹氫箟props
+const props = defineProps({
+ current: {
+ type: Object,
+ required: true
+ }
+})
+
+// 瀹氫箟emits
+const emit = defineEmits(['hanldeBack'])
+
+// 鍝嶅簲寮忔暟鎹�
+const loading = ref(false)
+// const bookInfo = ref(null)
+
+// 鏂规硶
+const handleBack = () => {
+ emit('hanldeBack')
+}
+
+</script>
+
+<style scoped>
+.detail-container {
+ padding: 20px;
+ height: 100%;
+ background-color: #f5f5f5;
+}
+
+.header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+ background-color: #fff;
+ padding: 15px 20px;
+ border-radius: 4px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.header h2 {
+ margin: 0 0 0 20px;
+ color: #333;
+}
+
+.content {
+ background-color: #fff;
+ border-radius: 4px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.card-header {
+ font-weight: bold;
+ color: #333;
+}
+
+.additional-info {
+ margin-top: 20px;
+ padding-top: 20px;
+ border-top: 1px solid #ebeef5;
+}
+
+.additional-info h4 {
+ margin: 0 0 10px 0;
+ color: #333;
+ font-size: 16px;
+}
+
+.additional-info p {
+ margin: 0;
+ color: #666;
+ line-height: 1.6;
+}
+</style>
diff --git a/src/views/fileManagement/bookshelf/index.vue b/src/views/fileManagement/bookshelf/index.vue
new file mode 100644
index 0000000..2689900
--- /dev/null
+++ b/src/views/fileManagement/bookshelf/index.vue
@@ -0,0 +1,688 @@
+<template>
+ <div class="sample">
+ <div class="main-content" v-if="!isDetail">
+ <div class="search">
+ <div class="search_thing">
+ <div class="search_label">浠撳簱鍚嶇О锛�</div>
+ <div class="search_input">
+ <el-select v-model="entity.warehouseId" placeholder="閫夋嫨浠撳簱" size="small" @change="warehouseChange">
+ <el-option v-for="item in warehouse" :key="item.id" :label="item.label" :value="item.id">
+ </el-option>
+ </el-select>
+ </div>
+ </div>
+ <div class="search_thing">
+ <div class="search_label">璐ф灦锛�</div>
+ <div class="search_input">
+ <el-select v-model="entity.shelfId" placeholder="閫夋嫨璐ф灦" size="small" @change="handleShelf">
+ <el-option v-for="item in shelf" :key="item.id" :label="item.label" :value="item.id">
+ </el-option>
+ </el-select>
+ </div>
+ </div>
+ <!-- <div class="search_thing">
+ <el-button size="small" @click="handleShelf(entity.shelfId,'')">閲嶇疆</el-button>
+ <el-button size="small" type="primary" @click="handleShelf(entity.shelfId)">鏌ヨ</el-button>
+ </div> -->
+ <div class="btns">
+ <el-button size="small" style="color:#3A7BFA" @click="keepVisible=true">缁存姢</el-button>
+ <el-button size="small" style="color:#3A7BFA" @click="warehouseVisible=true,isEdit=false">娣诲姞浠撳簱</el-button>
+ <el-button size="small" style="color:#3A7BFA" @click="shelvesVisible=true,isEdit=false"
+ :disabled="entity.warehouseId==null">娣诲姞璐ф灦</el-button>
+ </div>
+ </div>
+ <div class="table" v-loading="tableLoading">
+ <table class="tables" style="table-layout:fixed;" v-if="tableList.length>0">
+ <tbody>
+ <tr v-for="(item,index) in tableList" :key="index">
+ <td v-for="(m,i) in item" :key="i" class="content">
+ <h4 v-if="m.row!=undefined">{{ m.row }} - {{ m.col }}</h4>
+ <ul>
+ <el-tooltip
+ effect="dark"
+ placement="top"
+ v-for="(n,j) in m.documentationDtoList"
+ :key="j">
+ <template #content><span>{{ n.docName }}</span>
+ <span> [{{ 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..6875571
--- /dev/null
+++ b/src/views/fileManagement/borrow/index.vue
@@ -0,0 +1,582 @@
+<template>
+ <div class="app-container borrow-view">
+ <!-- 鏌ヨ鍖哄煙 -->
+ <div class="search-container">
+ <el-form :model="searchForm" :inline="true" class="search-form">
+ <el-form-item label="鍊熼槄鐘舵�侊細">
+ <el-select v-model="searchForm.borrowStatus" placeholder="璇烽�夋嫨鍊熼槄鐘舵��" clearable style="width: 150px">
+ <el-option label="鍊熼槄" value="鍊熼槄" />
+ <el-option label="褰掕繕" value="褰掕繕" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鍊熼槄浜猴細">
+ <el-input
+ v-model="searchForm.borrower"
+ placeholder="璇疯緭鍏ュ�熼槄浜�"
+ clearable
+ style="width: 200px"
+ />
+ </el-form-item>
+ <el-form-item label="鍊熼槄鏃ユ湡鑼冨洿锛�">
+ <el-date-picker
+ v-model="searchForm.dateRange"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ style="width: 300px"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleSearch">
+ <el-icon><Search /></el-icon>
+ 鏌ヨ
+ </el-button>
+ <el-button @click="handleReset">
+ <el-icon><Refresh /></el-icon>
+ 閲嶇疆
+ </el-button>
+ </el-form-item>
+ <el-form-item style="margin-left: auto;">
+ <el-button type="primary" @click="openBorrowDia('add')">
+ <el-icon><Plus /></el-icon>
+ 鏂板鍊熼槄
+ </el-button>
+ <el-button
+ type="danger"
+ @click="handleBatchDelete"
+ :disabled="selectedRows.length === 0"
+ >
+ <el-icon><Delete /></el-icon>
+ 鎵归噺鍒犻櫎 ({{ selectedRows.length }})
+ </el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+
+ <!-- 琛ㄦ牸鍖哄煙 -->
+ <div class="table-container">
+ <PIMTable
+ :table-data="borrowList"
+ :column="tableColumns"
+ :is-selection="true"
+ :border="true"
+ :table-loading="tableLoading"
+ :page="{
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ total: pagination.total,
+ layout: 'total, sizes, prev, pager, next, jumper'
+ }"
+ @selection-change="handleSelectionChange"
+ @pagination="handlePagination"
+ />
+ </div>
+
+ <!-- 鍊熼槄鏂板/缂栬緫瀵硅瘽妗� -->
+ <el-dialog
+ v-model="borrowDia"
+ :title="borrowOperationType === 'add' ? '鏂板鍊熼槄' : '缂栬緫鍊熼槄'"
+ width="800px"
+ @close="closeBorrowDia"
+ @keydown.enter.prevent
+ >
+ <el-form
+ :model="borrowForm"
+ label-width="140px"
+ :rules="borrowRules"
+ ref="borrowFormRef"
+ >
+ <el-row :gutter="20">
+
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鍊熼槄浜猴細" prop="borrower">
+ <el-input v-model="borrowForm.borrower" placeholder="璇疯緭鍏ュ�熼槄浜�" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍊熼槄涔︾睄锛�" prop="documentationId">
+ <el-select v-model="borrowForm.documentationId" placeholder="璇烽�夋嫨鍊熼槄涔︾睄" style="width: 100%">
+ <el-option
+ v-for="item in documentList"
+ :key="item.id"
+ :label="item.docName || item.name"
+ :value="item.id"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鍊熼槄鏃ユ湡锛�" prop="borrowDate">
+ <el-date-picker
+ v-model="borrowForm.borrowDate"
+ type="date"
+ placeholder="閫夋嫨鍊熼槄鏃ユ湡"
+ style="width: 100%"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="搴斿綊杩樻棩鏈燂細" prop="dueReturnDate">
+ <el-date-picker
+ v-model="borrowForm.dueReturnDate"
+ type="date"
+ placeholder="閫夋嫨搴斿綊杩樻棩鏈�"
+ style="width: 100%"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="24">
+ <el-form-item label="鍊熼槄鐩殑锛�" prop="borrowPurpose">
+ <el-input v-model="borrowForm.borrowPurpose" placeholder="璇疯緭鍏ュ�熼槄鐩殑" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="24">
+ <el-form-item label="澶囨敞锛�" prop="remark">
+ <el-input
+ v-model="borrowForm.remark"
+ type="textarea"
+ :rows="3"
+ placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitBorrowForm">纭</el-button>
+ <el-button @click="closeBorrowDia">鍙栨秷</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+import { ElMessageBox, ElMessage } from "element-plus";
+import { Search, Refresh, Plus, Delete } from '@element-plus/icons-vue';
+import PIMTable from '@/components/PIMTable/PIMTable.vue';
+import { getBorrowList, addBorrow, updateBorrow, deleteBorrow, getDocumentList } from '@/api/fileManagement/borrow';
+
+const { proxy } = getCurrentInstance();
+
+// 鍝嶅簲寮忔暟鎹�
+const borrowDia = ref(false);
+const borrowOperationType = ref("");
+const tableLoading = ref(false);
+const borrowList = ref([]);
+const selectedRows = ref([]);
+const documentList = ref([]); // 鏂囨。鍒楄〃锛岀敤浜庡�熼槄涔︾睄閫夋嫨
+
+// 鍒嗛〉鐩稿叧
+const pagination = reactive({
+ currentPage: 1,
+ pageSize: 10,
+ total: 0,
+});
+
+// 鏌ヨ琛ㄥ崟
+const searchForm = reactive({
+ documentationId: "",
+ borrowStatus: "",
+ borrower: "",
+ returnerId: "",
+ dateRange: []
+});
+
+// 鍊熼槄琛ㄥ崟
+const borrowForm = reactive({
+ id: "",
+ documentationId: "",
+ borrower: "",
+ returnerId: "",
+ borrowPurpose: "",
+ borrowDate: "",
+ dueReturnDate: "",
+ returnDate: "",
+ borrowStatus: "",
+ remark: ""
+});
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const borrowRules = reactive({
+ documentationId: [{ required: true, message: "璇烽�夋嫨鍊熼槄涔︾睄", trigger: "change" }],
+ borrower: [{ required: true, message: "璇疯緭鍏ュ�熼槄浜�", trigger: "blur" }],
+ borrowPurpose: [{ required: true, message: "璇疯緭鍏ュ�熼槄鐩殑", trigger: "blur" }],
+ borrowDate: [{ required: true, message: "璇烽�夋嫨鍊熼槄鏃ユ湡", trigger: "change" }],
+ dueReturnDate: [{ required: true, message: "璇烽�夋嫨搴斿綊杩樻棩鏈�", trigger: "change" }],
+ borrowStatus: [{ required: true, message: "璇烽�夋嫨鍊熼槄鐘舵��", trigger: "change" }]
+});
+
+// 琛ㄦ牸鍒楅厤缃�
+const tableColumns = ref([
+ {
+ label: '鏂囨。鍚嶇О',
+ prop: 'docName',
+ width: '200',
+ },
+ { label: '鍊熼槄浜�', prop: 'borrower' },
+ { label: '鍊熼槄鐩殑', prop: 'borrowPurpose' },
+ { label: '鍊熼槄鏃ユ湡', prop: 'borrowDate' },
+ { label: '搴斿綊杩樻棩鏈�', prop: 'dueReturnDate' },
+ {
+ label: '鍊熼槄鐘舵��',
+ prop: 'borrowStatus',
+ width: '100',
+ dataType: 'tag',
+ formatData: (params) => {
+ if (params === null || params === undefined || params === '') return '-';
+ return params;
+ },
+ formatType: (params) => {
+ if (params === '褰掕繕') return 'success';
+ if (params === '鍊熼槄') return 'warning';
+ return 'info';
+ }
+ },
+ { label: '澶囨敞', prop: 'remark', width: '150' },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ fixed: 'right',
+ width: '150',
+ operation: [
+ {
+ name: "缂栬緫",
+ type: "text",
+ clickFun: (row) => {
+ openBorrowDia('edit', row)
+ },
+ },
+ {
+ name: "鍒犻櫎",
+ type: "text",
+ clickFun: (row) => {
+ handleDelete(row)
+ },
+ },
+ ],
+ }
+]);
+
+// 鍒濆鍖栨暟鎹�
+const initData = async () => {
+ await Promise.all([
+ loadDocumentList(),
+ loadBorrowList()
+ ]);
+};
+
+// 鍔犺浇鏂囨。鍒楄〃
+const loadDocumentList = async () => {
+ try {
+ const res = await getDocumentList();
+ if (res.code === 200) {
+ documentList.value = res.data || [];
+ } else {
+ ElMessage.error(res.msg || "鑾峰彇鏂囨。鍒楄〃澶辫触");
+ documentList.value = [];
+ }
+ } catch (error) {
+ ElMessage.error("鑾峰彇鏂囨。鍒楄〃澶辫触锛岃閲嶈瘯");
+ documentList.value = [];
+ }
+};
+
+// 鍔犺浇鍊熼槄鍒楄〃
+const loadBorrowList = async () => {
+ try {
+ tableLoading.value = true;
+
+ // 鏋勫缓鏌ヨ鍙傛暟
+ const query = {
+ page: pagination.currentPage,
+ size: pagination.pageSize,
+ documentationId: searchForm.documentationId || undefined,
+ borrowStatus: searchForm.borrowStatus || undefined,
+ borrower: searchForm.borrower || undefined,
+ returnerId: searchForm.returnerId || undefined,
+ entryDateStart: searchForm.dateRange && searchForm.dateRange.length > 0 ? searchForm.dateRange[0] : undefined,
+ entryDateEnd: searchForm.dateRange && searchForm.dateRange.length > 1 ? searchForm.dateRange[1] : undefined
+ };
+
+ // 绉婚櫎undefined鐨勫弬鏁�
+ Object.keys(query).forEach(key => {
+ if (query[key] === undefined) {
+ delete query[key];
+ }
+ });
+
+ const res = await getBorrowList(query);
+ if (res.code === 200) {
+ borrowList.value = res.data.records || [];
+ pagination.total = res.data.total || 0;
+ } else {
+ ElMessage.error(res.msg || "鑾峰彇鍊熼槄鍒楄〃澶辫触");
+ borrowList.value = [];
+ pagination.total = 0;
+ }
+
+ // 閲嶇疆閫夋嫨鐘舵��
+ selectedRows.value = [];
+ } catch (error) {
+ ElMessage.error("鑾峰彇鍊熼槄鍒楄〃澶辫触锛岃閲嶈瘯");
+ borrowList.value = [];
+ pagination.total = 0;
+ } finally {
+ tableLoading.value = false;
+ }
+};
+
+// 鏌ヨ
+const handleSearch = () => {
+ pagination.currentPage = 1;
+ loadBorrowList();
+};
+
+// 閲嶇疆鏌ヨ
+const handleReset = () => {
+ searchForm.documentationId = "";
+ searchForm.borrowStatus = "";
+ searchForm.borrower = "";
+ searchForm.returnerId = "";
+ searchForm.dateRange = [];
+ pagination.currentPage = 1;
+ loadBorrowList();
+ ElMessage.success("鏌ヨ鏉′欢宸查噸缃�");
+};
+
+// 鎵撳紑鍊熼槄寮规
+const openBorrowDia = async (type, data) => {
+ // 鍏堝埛鏂版枃妗e垪琛�
+ await loadDocumentList();
+
+ borrowOperationType.value = type;
+ borrowDia.value = true;
+
+ if (type === "edit") {
+ // 缂栬緫妯″紡锛屽姞杞界幇鏈夋暟鎹�
+ Object.assign(borrowForm, data);
+ } else {
+ // 鏂板妯″紡锛屾竻绌鸿〃鍗�
+ Object.keys(borrowForm).forEach(key => {
+ borrowForm[key] = "";
+ });
+ // 璁剧疆榛樿鐘舵��
+ borrowForm.borrowStatus = "鍊熼槄";
+ // 璁剧疆褰撳墠鏃ユ湡涓哄�熼槄鏃ユ湡
+ borrowForm.borrowDate = new Date().toISOString().split('T')[0];
+ }
+};
+
+// 鍏抽棴鍊熼槄寮规
+const closeBorrowDia = () => {
+ proxy.$refs.borrowFormRef.resetFields();
+ borrowDia.value = false;
+};
+
+// 鎻愪氦鍊熼槄琛ㄥ崟
+const submitBorrowForm = () => {
+ proxy.$refs.borrowFormRef.validate(async (valid) => {
+ if (valid) {
+ try {
+ if (borrowOperationType.value === "edit") {
+ // 缂栬緫妯″紡锛屾洿鏂扮幇鏈夋暟鎹�
+ const res = await updateBorrow({
+ borrower:borrowForm.borrower,
+ id: borrowForm.id,
+ borrowPurpose: borrowForm.borrowPurpose,
+ borrowDate: borrowForm.borrowDate,
+ dueReturnDate: borrowForm.dueReturnDate,
+ returnDate: borrowForm.returnDate,
+ remark: borrowForm.remark
+ });
+
+ if (res.code === 200) {
+ ElMessage.success("缂栬緫鎴愬姛");
+ await loadBorrowList();
+ closeBorrowDia();
+ } else {
+ ElMessage.error(res.msg || "缂栬緫澶辫触");
+ }
+ } else {
+ // 鏂板妯″紡锛屾坊鍔犳柊鏁版嵁
+ const res = await addBorrow({
+ documentationId: borrowForm.documentationId,
+ borrower: borrowForm.borrower,
+ returnerId: borrowForm.returnerId,
+ borrowPurpose: borrowForm.borrowPurpose,
+ borrowDate: borrowForm.borrowDate,
+ dueReturnDate: borrowForm.dueReturnDate,
+ returnDate: borrowForm.returnDate,
+ borrowStatus: borrowForm.borrowStatus,
+ remark: borrowForm.remark
+ });
+
+ if (res.code === 200) {
+ ElMessage.success("鏂板鎴愬姛");
+ await loadBorrowList();
+ closeBorrowDia();
+ } else {
+ ElMessage.error(res.msg || "鏂板澶辫触");
+ }
+ }
+ } catch (error) {
+ ElMessage.error("鎿嶄綔澶辫触锛岃閲嶈瘯");
+ }
+ }
+ });
+};
+
+// 鍒犻櫎鍊熼槄璁板綍
+const handleDelete = (row) => {
+ ElMessageBox.confirm(
+ `纭畾瑕佸垹闄よ繖鏉″�熼槄璁板綍鍚楋紵`,
+ "鍒犻櫎鎻愮ず",
+ {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }
+ ).then(async () => {
+ try {
+ const res = await deleteBorrow([row.id]);
+ if (res.code === 200) {
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ await loadBorrowList();
+ } else {
+ ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+ }
+ } catch (error) {
+ ElMessage.error("鍒犻櫎澶辫触锛岃閲嶈瘯");
+ }
+ }).catch(() => {
+ ElMessage.info("宸插彇娑堝垹闄�");
+ });
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+ if (selectedRows.value.length === 0) {
+ ElMessage.warning("璇烽�夋嫨瑕佸垹闄ょ殑璁板綍");
+ return;
+ }
+
+ ElMessageBox.confirm(
+ `纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.value.length} 鏉″�熼槄璁板綍鍚楋紵`,
+ "鎵归噺鍒犻櫎鎻愮ず",
+ {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }
+ ).then(async () => {
+ try {
+ const selectedIds = selectedRows.value.map(row => row.id);
+ const res = await deleteBorrow(selectedIds);
+ if (res.code === 200) {
+ ElMessage.success("鎵归噺鍒犻櫎鎴愬姛");
+ await loadBorrowList();
+ } else {
+ ElMessage.error(res.msg || "鎵归噺鍒犻櫎澶辫触");
+ }
+ } catch (error) {
+ ElMessage.error("鎵归噺鍒犻櫎澶辫触锛岃閲嶈瘯");
+ }
+ }).catch(() => {
+ ElMessage.info("宸插彇娑堝垹闄�");
+ });
+};
+
+// 閫夋嫨鍙樺寲浜嬩欢
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+
+// 澶勭悊鍒嗛〉鍙樺寲
+const handlePagination = (current, size) => {
+ pagination.currentPage = current;
+ pagination.pageSize = size;
+ loadBorrowList();
+};
+
+// 鐢熷懡鍛ㄦ湡
+onMounted(() => {
+ initData();
+});
+</script>
+
+<style scoped>
+.borrow-view {
+ padding: 20px;
+}
+
+.search-container {
+ background: #ffffff;
+ padding: 20px;
+ border-radius: 8px;
+ margin-bottom: 20px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.search-form {
+ margin: 0;
+}
+
+.table-container {
+ background: #ffffff;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.empty-data {
+ text-align: center;
+ color: #909399;
+ padding: 40px;
+ font-size: 14px;
+}
+
+.dialog-footer {
+ text-align: right;
+}
+
+:deep(.el-form-item__label) {
+ font-weight: 500;
+ color: #303133;
+}
+
+:deep(.el-input__wrapper) {
+ box-shadow: 0 0 0 1px #dcdfe6 inset;
+}
+
+:deep(.el-input__wrapper:hover) {
+ box-shadow: 0 0 0 1px #c0c4cc inset;
+}
+
+:deep(.el-input__wrapper.is-focus) {
+ box-shadow: 0 0 0 1px #409eff inset;
+}
+</style>
diff --git a/src/views/fileManagement/document/attachmentManager.vue b/src/views/fileManagement/document/attachmentManager.vue
new file mode 100644
index 0000000..a4e1d43
--- /dev/null
+++ b/src/views/fileManagement/document/attachmentManager.vue
@@ -0,0 +1,426 @@
+<template>
+ <el-dialog v-model="dialogVisible" title="闄勪欢绠$悊" width="60%" :before-close="handleClose">
+ <div class="attachment-manager">
+ <!-- 涓婁紶鍖哄煙 -->
+ <div class="upload-section">
+ <el-upload
+ ref="uploadRef"
+ :action="uploadUrl"
+ :headers="uploadHeaders"
+ :before-upload="handleBeforeUpload"
+ :on-success="handleUploadSuccess"
+ :on-error="handleUploadError"
+ :on-remove="handleRemove"
+ :file-list="fileList"
+ multiple
+ :limit="10"
+ :show-file-list="false"
+ :data="{documentId: currentDocumentId}"
+ accept=".doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt,.xml,.jpg,.jpeg,.png,.gif,.bmp,.rar,.zip,.7z"
+ >
+ <el-button type="primary" :icon="Plus">涓婁紶闄勪欢</el-button>
+ <template #tip>
+ <div class="el-upload__tip">
+ 鏀寔鏍煎紡锛歞oc锛宒ocx锛寈ls锛寈lsx锛宲pt锛宲ptx锛宲df锛宼xt锛寈ml锛宩pg锛宩peg锛宲ng锛実if锛宐mp锛宺ar锛寊ip锛�7z
+ <br>鍗曚釜鏂囦欢澶у皬涓嶈秴杩�50MB
+ </div>
+ </template>
+ </el-upload>
+ </div>
+
+ <!-- 闄勪欢鍒楄〃 -->
+ <div class="attachment-list">
+ <el-table :data="fileList" border height="400px" v-loading="loading">
+ <el-table-column label="搴忓彿" type="index" width="60" align="center" />
+ <el-table-column label="闄勪欢鍚嶇О" prop="name" min-width="200" show-overflow-tooltip />
+ <el-table-column label="鏂囦欢澶у皬" prop="size" width="100" align="center">
+ <template #default="scope">
+ {{ formatFileSize(scope.row.size) }}
+ </template>
+ </el-table-column>
+ <el-table-column label="涓婁紶鏃堕棿" prop="uploadTime" width="160" align="center">
+ <template #default="scope">
+ {{ formatDate(scope.row.uploadTime) }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鐘舵��" prop="status" width="80" align="center">
+ <template #default="scope">
+ <el-tag :type="scope.row.status === 'success' ? 'success' : 'danger'" size="small">
+ {{ scope.row.status === 'success' ? '鎴愬姛' : '澶辫触' }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column fixed="right" label="鎿嶄綔" width="200" align="center">
+ <template #default="scope">
+ <el-button link type="primary" size="small" @click="previewFile(scope.row)">
+ 棰勮
+ </el-button>
+ <el-button link type="primary" size="small" @click="downloadFile(scope.row)">
+ 涓嬭浇
+ </el-button>
+ <el-button link type="danger" size="small" @click="removeFile(scope.row)">
+ 鍒犻櫎
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+ </div>
+
+ <!-- 鏂囦欢棰勮缁勪欢 -->
+ <filePreview ref="filePreviewRef" />
+ </el-dialog>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Plus } from '@element-plus/icons-vue'
+import { getToken } from "@/utils/auth"
+import { addDocumentationFile, getDocumentationFileList, deleteDocumentationFile } from '@/api/fileManagement/document'
+import filePreview from '@/components/filePreview/index.vue'
+
+const props = defineProps({
+ // documentId 閫氳繃 open 浜嬩欢浼犲叆锛屼笉闇�瑕佷綔涓� props
+})
+
+const emit = defineEmits(['update:attachments'])
+
+const dialogVisible = ref(false)
+const loading = ref(false)
+const fileList = ref([])
+const uploadRef = ref()
+const filePreviewRef = ref()
+const currentDocumentId = ref('') // 鍐呴儴绠$悊褰撳墠鏂囨。ID
+
+// 涓婁紶閰嶇疆
+const uploadUrl = import.meta.env.VITE_APP_BASE_API + "/file/upload"
+const uploadHeaders = computed(() => ({
+ Authorization: "Bearer " + getToken()
+}))
+
+// 鎵撳紑寮规
+const open = (attachments = [], documentId = '') => {
+ dialogVisible.value = true
+ currentDocumentId.value = documentId // 璁剧疆褰撳墠鏂囨。ID
+ // 濡傛灉鏈夋枃妗D锛屽垯鍔犺浇闄勪欢鍒楄〃
+ if (documentId) {
+ loadAttachmentList(documentId)
+ } else {
+ fileList.value = attachments || []
+ // total.value = fileList.value.length // Removed total.value
+ }
+ // currentPage.value = 1 // Removed currentPage.value
+}
+
+// 鍔犺浇闄勪欢鍒楄〃
+const loadAttachmentList = async (documentId) => {
+ try {
+ loading.value = true
+ const params = {
+ page: 1, // Always load from page 1
+ size: 1000, // Load all for now
+ documentationId: documentId
+ }
+
+ const res = await getDocumentationFileList(params)
+ if (res.code === 200) {
+ const records = res.data
+
+ // 杞崲鏁版嵁鏍煎紡
+ fileList.value = records.map(item => ({
+ id: item.id,
+ name: item.name,
+ size: item.fileSize,
+ url: item.url,
+ uploadTime: item.createTime || item.uploadTime,
+ status: 'success',
+ uid: item.id
+ }))
+
+ // total.value = totalCount // Removed total.value
+ } else {
+ ElMessage.error(res.msg || '鑾峰彇闄勪欢鍒楄〃澶辫触')
+ fileList.value = []
+ // total.value = 0 // Removed total.value
+ }
+ } catch (error) {
+ console.error('鑾峰彇闄勪欢鍒楄〃澶辫触:', error)
+ ElMessage.error('鑾峰彇闄勪欢鍒楄〃澶辫触')
+ fileList.value = []
+ // total.value = 0 // Removed total.value
+ } finally {
+ loading.value = false
+ }
+}
+
+// 鍏抽棴寮规
+const handleClose = () => {
+ dialogVisible.value = false
+ emit('update:attachments', fileList.value)
+}
+
+// 鏂囦欢涓婁紶鍓嶆牎楠�
+const handleBeforeUpload = (file) => {
+ // 妫�鏌ユ枃浠跺ぇ灏忥紙50MB锛�
+ const isLt50M = file.size / 1024 / 1024 < 50
+ if (!isLt50M) {
+ ElMessage.error('鏂囦欢澶у皬涓嶈兘瓒呰繃50MB!')
+ return false
+ }
+
+ // 妫�鏌ユ枃浠剁被鍨�
+ const allowedTypes = [
+ 'application/msword',
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'application/vnd.ms-excel',
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'application/vnd.ms-powerpoint',
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'application/pdf',
+ 'text/plain',
+ 'text/xml',
+ 'image/jpeg',
+ 'image/png',
+ 'image/gif',
+ 'image/bmp',
+ 'application/x-rar-compressed',
+ 'application/zip',
+ 'application/x-7z-compressed'
+ ]
+
+ if (!allowedTypes.includes(file.type)) {
+ ElMessage.error('涓嶆敮鎸佺殑鏂囦欢绫诲瀷!')
+ return false
+ }
+
+ return true
+}
+
+// 鏂囦欢涓婁紶鎴愬姛
+const handleUploadSuccess = (response, file, fileList) => {
+ console.log('鏂囦欢涓婁紶鎴愬姛鍝嶅簲:', response);
+ console.log('鏂囦欢淇℃伅:', file);
+
+ if (response.code === 200) {
+ // 鏋勫缓闄勪欢鏁版嵁 - 纭繚姝g‘鑾峰彇URL
+ const attachmentData = {
+ name: file.name,
+ url: response.data.url || response.data.path || response.data.tempPath || file.url,
+ fileSize: file.size,
+ documentationId: currentDocumentId.value
+ };
+
+ console.log('鏋勫缓鐨勯檮浠舵暟鎹�:', attachmentData);
+
+ // 璋冪敤淇濆瓨闄勪欢鎺ュ彛
+ saveAttachment(attachmentData, file, fileList);
+ } else {
+ ElMessage.error(response.msg || '鏂囦欢涓婁紶澶辫触')
+ }
+}
+
+// 淇濆瓨闄勪欢淇℃伅
+const saveAttachment = async (attachmentData, file, fileList) => {
+ try {
+ console.log('寮�濮嬩繚瀛橀檮浠讹紝鏁版嵁:', attachmentData);
+
+ // 纭繚URL瀛楁瀛樺湪涓旀湁鏁�
+ if (!attachmentData.url) {
+ console.error('闄勪欢URL涓虹┖锛屾棤娉曚繚瀛�');
+ ElMessage.error('鏂囦欢URL鑾峰彇澶辫触锛屾棤娉曚繚瀛橀檮浠�');
+ return;
+ }
+
+ const res = await addDocumentationFile(attachmentData);
+ console.log('淇濆瓨闄勪欢鎺ュ彛鍝嶅簲:', res);
+
+ if (res.code === 200) {
+ const newFile = {
+ id: res.data.id || Date.now(),
+ name: attachmentData.name,
+ size: attachmentData.fileSize,
+ url: attachmentData.url,
+ uploadTime: new Date().toISOString(),
+ status: 'success',
+ uid: file.uid
+ }
+
+ console.log('鍒涘缓鐨勬柊鏂囦欢瀵硅薄:', newFile);
+ fileList.push(newFile)
+ ElMessage.success('鏂囦欢涓婁紶骞朵繚瀛樻垚鍔�')
+
+ // 淇濆瓨鎴愬姛鍚庡埛鏂伴檮浠跺垪琛�
+ if (currentDocumentId.value) {
+ await loadAttachmentList(currentDocumentId.value);
+ }
+ } else {
+ ElMessage.error(res.msg || '淇濆瓨闄勪欢淇℃伅澶辫触')
+ // 淇濆瓨澶辫触鏃剁Щ闄ゆ枃浠�
+ const index = fileList.findIndex(item => item.uid === file.uid)
+ if (index > -1) {
+ fileList.splice(index, 1)
+ }
+ }
+ } catch (error) {
+ console.error('淇濆瓨闄勪欢澶辫触:', error)
+ ElMessage.error('淇濆瓨闄勪欢淇℃伅澶辫触')
+ // 淇濆瓨澶辫触鏃剁Щ闄ゆ枃浠�
+ const index = fileList.findIndex(item => item.uid === file.uid)
+ if (index > -1) {
+ fileList.splice(index, 1)
+ }
+ }
+}
+
+// 鏂囦欢涓婁紶澶辫触
+const handleUploadError = (error, file, fileList) => {
+ console.error('鏂囦欢涓婁紶澶辫触:', error);
+ console.error('澶辫触鐨勬枃浠�:', file);
+ console.error('褰撳墠鏂囦欢鍒楄〃:', fileList);
+
+ ElMessage.error('鏂囦欢涓婁紶澶辫触锛岃妫�鏌ョ綉缁滆繛鎺ユ垨鏂囦欢鏍煎紡')
+}
+
+// 绉婚櫎鏂囦欢
+const handleRemove = (file, fileList) => {
+ const index = fileList.findIndex(item => item.uid === file.uid)
+ if (index > -1) {
+ fileList.splice(index, 1)
+ // total.value = fileList.length // Removed total.value
+ }
+}
+
+// 鍒犻櫎鏂囦欢
+const removeFile = (file) => {
+ ElMessageBox.confirm(`纭畾瑕佸垹闄ゆ枃浠� "${file.name}" 鍚楋紵`, '鍒犻櫎纭', {
+ confirmButtonText: '纭畾',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning'
+ }).then(async () => {
+ try {
+ // 璋冪敤鍒犻櫎鎺ュ彛
+ const res = await deleteDocumentationFile([file.id]);
+ if (res.code === 200) {
+ // 浠庢湰鍦板垪琛ㄤ腑绉婚櫎
+ const index = fileList.value.findIndex(item => item.id === file.id);
+ if (index > -1) {
+ fileList.value.splice(index, 1);
+ }
+ ElMessage.success('鍒犻櫎鎴愬姛');
+
+ // 濡傛灉鏈夋枃妗D锛屽埛鏂伴檮浠跺垪琛�
+ if (currentDocumentId.value) {
+ await loadAttachmentList(currentDocumentId.value);
+ }
+ } else {
+ ElMessage.error(res.msg || '鍒犻櫎澶辫触');
+ }
+ } catch (error) {
+ console.error('鍒犻櫎闄勪欢澶辫触:', error);
+ ElMessage.error('鍒犻櫎闄勪欢澶辫触');
+ }
+ }).catch(() => {
+ // 鍙栨秷鍒犻櫎
+ })
+}
+
+// 棰勮鏂囦欢
+const previewFile = (file) => {
+ if (file.url) {
+ filePreviewRef.value.open(file.url)
+ } else {
+ ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曢瑙�')
+ }
+}
+
+// 涓嬭浇鏂囦欢
+const downloadFile = (file) => {
+ if (file.url) {
+ // 鍒涘缓涓嬭浇閾炬帴
+ const link = document.createElement('a')
+ link.href = file.url
+ link.download = file.name
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+ ElMessage.success('寮�濮嬩笅杞芥枃浠�')
+ } else {
+ ElMessage.warning('鏂囦欢鍦板潃鏃犳晥锛屾棤娉曚笅杞�')
+ }
+}
+
+// 鏍煎紡鍖栨枃浠跺ぇ灏�
+const formatFileSize = (bytes) => {
+ if (bytes === 0) return '0 B'
+ const k = 1024
+ const sizes = ['B', 'KB', 'MB', 'GB']
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
+}
+
+// 鏍煎紡鍖栨棩鏈�
+const formatDate = (dateString) => {
+ if (!dateString) return ''
+ const date = new Date(dateString)
+ return date.toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit'
+ })
+}
+
+// 娴嬭瘯鏂囦欢涓婁紶
+const testUpload = () => {
+ console.log('褰撳墠鏂囨。ID:', currentDocumentId.value);
+ console.log('涓婁紶URL:', uploadUrl);
+ console.log('涓婁紶Headers:', uploadHeaders.value);
+}
+
+// 鏆撮湶鏂规硶
+defineExpose({
+ open,
+ loadAttachmentList,
+ testUpload
+})
+</script>
+
+<style scoped>
+.attachment-manager {
+ padding: 20px;
+}
+
+.upload-section {
+ margin-bottom: 20px;
+ padding: 20px;
+ background-color: #f8f9fa;
+ border-radius: 8px;
+ border: 2px dashed #d9d9d9;
+}
+
+.upload-section:hover {
+ border-color: #409eff;
+}
+
+.attachment-list {
+ margin-bottom: 20px;
+}
+
+.el-upload__tip {
+ margin-top: 10px;
+ color: #666;
+ font-size: 12px;
+ line-height: 1.5;
+}
+
+:deep(.el-upload) {
+ width: 100%;
+}
+
+:deep(.el-upload-dragger) {
+ width: 100%;
+ height: 120px;
+}
+</style>
diff --git a/src/views/fileManagement/document/index.vue b/src/views/fileManagement/document/index.vue
new file mode 100644
index 0000000..7cf352c
--- /dev/null
+++ b/src/views/fileManagement/document/index.vue
@@ -0,0 +1,1262 @@
+<template>
+ <div class="app-container document-view">
+ <div class="left">
+ <div>
+ <el-input
+ v-model="search"
+ style="width: 210px"
+ placeholder="杈撳叆鍏抽敭瀛楄繘琛屾悳绱�"
+ @change="searchFilter"
+ @clear="searchFilter"
+ clearable
+ prefix-icon="Search"
+ />
+ <el-button
+ type="primary"
+ @click="openCategoryDia('addOne')"
+ style="margin-left: 10px"
+ >鏂板鍒嗙被</el-button
+ >
+ </div>
+ <div ref="containerRef">
+ <el-tree
+ ref="tree"
+ v-loading="treeLoad"
+ :data="categoryList"
+ @node-click="handleNodeClick"
+ :expand-on-click-node="false"
+ default-expand-all
+ :default-expanded-keys="expandedKeys"
+ :draggable="true"
+ :filter-node-method="filterNode"
+ :props="{ children: 'children', label: 'category' }"
+ highlight-current
+ node-key="id"
+ style="
+ height: calc(100vh - 190px);
+ overflow-y: scroll;
+ scrollbar-width: none;
+ margin-top: 10px;
+ "
+ >
+ <template #default="{ node, data }">
+ <div class="custom-tree-node">
+ <span class="tree-node-content">
+ <el-icon class="orange-icon">
+ <component :is="data.children && data.children.length > 0
+ ? node.expanded ? 'FolderOpened' : 'Folder' : 'Tickets'" />
+ </el-icon>
+ {{ data.category }}
+ </span>
+ <div>
+ <el-button
+ type="primary"
+ link
+ @click="openCategoryDia('edit', data)"
+ >
+ 缂栬緫
+ </el-button>
+ <el-button
+ type="primary"
+ link
+ @click="openCategoryDia('addSub', data)"
+ v-if="node.level < 2"
+ >
+ 娣诲姞瀛愬垎绫�
+ </el-button>
+ <el-button
+ v-if="!node.childNodes.length"
+ style="margin-left: 4px"
+ type="danger"
+ link
+ @click="removeCategory(node, data)"
+ >
+ 鍒犻櫎
+ </el-button>
+ </div>
+ </div>
+ </template>
+ </el-tree>
+ </div>
+ </div>
+ <div class="right">
+ <div style="margin-bottom: 10px" v-if="isShowButton">
+ <el-button type="primary" @click="openDocumentDia('add')">
+ 鏂板鏂囨。
+ </el-button>
+ <el-button
+ type="danger"
+ @click="handleDelete"
+ style="margin-left: 10px"
+ plain
+ :disabled="selectedRows.length === 0"
+ >
+ 鍒犻櫎 ({{ selectedRows.length }})
+ </el-button>
+ </div>
+ <div class="table-container">
+
+ <!-- PIMTable 缁勪欢 -->
+ <PIMTable
+ :table-data="documentList"
+ :column="tableColumns"
+ :is-selection="true"
+ :border="true"
+ :table-loading="tableLoading"
+ :page="{
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ total: pagination.total,
+ layout: 'total, sizes, prev, pager, next, jumper'
+ }"
+ @selection-change="handleSelectionChange"
+ @pagination="handlePagination"
+ />
+ </div>
+ </div>
+
+ <!-- 鍒嗙被鏂板/淇敼瀵硅瘽妗� -->
+ <el-dialog v-model="categoryDia" title="鍒嗙被" width="400px" @keydown.enter.prevent>
+ <el-form
+ :model="categoryForm"
+ label-width="140px"
+ label-position="top"
+ :rules="categoryRules"
+ ref="categoryFormRef"
+ >
+ <el-row :gutter="30">
+ <el-col :span="24" v-if="categoryOperationType === 'addSub'">
+ <el-form-item label="鐖跺垎绫伙細" prop="parentName">
+ <el-input
+ v-model="categoryForm.parentName"
+ placeholder="鐖跺垎绫诲悕绉�"
+ disabled
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item label="鍒嗙被鍚嶇О锛�" prop="category">
+ <el-input
+ v-model="categoryForm.category"
+ placeholder="璇疯緭鍏ュ垎绫诲悕绉�"
+ clearable
+ @keydown.enter.prevent
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitCategoryForm">纭</el-button>
+ <el-button @click="closeCategoryDia">鍙栨秷</el-button>
+ </div>
+ </template>
+ </el-dialog>
+
+ <!-- 鏂囨。鏂板/淇敼瀵硅瘽妗� -->
+ <el-dialog
+ v-model="documentDia"
+ :title="documentOperationType === 'add' ? '鏂板鏂囨。' : '缂栬緫鏂囨。'"
+ width="600px"
+ @close="closeDocumentDia"
+ @keydown.enter.prevent
+ >
+ <el-form
+ :model="documentForm"
+ label-width="140px"
+ label-position="top"
+ :rules="documentRules"
+ ref="documentFormRef"
+ >
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鏂囨。鍚嶇О锛�" prop="docName">
+ <el-input v-model="documentForm.docName" placeholder="璇疯緭鍏�" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="骞村害锛�" prop="year">
+ <el-date-picker
+ v-model="documentForm.year"
+ type="year"
+ value-format="YYYY"
+ format="YYYY"
+ placeholder="閫夋嫨骞村害"
+ style="width: 100%"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鏂囨。缂栧彿锛�" prop="docNumber">
+ <el-input v-model="documentForm.docNumber" placeholder="璇疯緭鍏�" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="璐d换浜猴細" prop="responsiblePerson">
+ <el-input v-model="documentForm.responsiblePerson" placeholder="璇疯緭鍏�" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鏂囨。鍒嗙被锛�" prop="documentClassificationId">
+ <el-select v-model="documentForm.documentClassificationId" placeholder="璇烽�夋嫨鏂囨。鍒嗙被" style="width: 100%">
+ <el-option
+ v-for="item in categoryList"
+ :key="item.id"
+ :label="item.category"
+ :value="item.id"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鏂囨。鏀剧疆浣嶇疆锛�" prop="warehouseGoodsShelvesRowcolId">
+ <el-tree-select
+ v-model="documentForm.warehouseGoodsShelvesRowcolId"
+ :data="locationTree"
+ placeholder="璇烽�夋嫨鏂囦欢鏀剧疆浣嶇疆"
+ clearable
+ check-strictly
+ :render-after-expand="false"
+ :props="{ children: 'children', label: 'label', value: 'value' }"
+ style="width: 100%"
+ @change="handleLocationChange"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鏂囨。鏃ユ湡锛�" prop="docData">
+ <el-date-picker
+ v-model="documentForm.docData"
+ type="date"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ placeholder="閫夋嫨鏃ユ湡"
+ style="width: 100%"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="淇濈鏈熼檺锛�" prop="retentionPeriod">
+ <el-select v-model="documentForm.retentionPeriod" placeholder="璇烽�夋嫨">
+ <el-option
+ v-for="item in retention_period"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="淇濆瘑绾у埆锛�" prop="securityLevel">
+ <el-select v-model="documentForm.securityLevel" placeholder="璇烽�夋嫨">
+ <el-option
+ v-for="item in confidentiality_level"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍒嗘暟锛�" prop="copyCount">
+ <el-input v-model="documentForm.copyCount" placeholder="璇疯緭鍏�" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="椤垫暟锛�" prop="pageCount">
+ <el-input v-model="documentForm.pageCount" placeholder="璇疯緭鍏�" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鏂囨。绫诲埆锛�" prop="docCategory">
+ <el-select v-model="documentForm.docCategory" placeholder="璇烽�夋嫨">
+ <el-option
+ v-for="item in document_type"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鏂囨。绉嶇被锛�" prop="docType">
+ <el-select v-model="documentForm.docType" placeholder="璇烽�夋嫨">
+ <el-option
+ v-for="item in document_categories"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="绱ф�ョ▼搴︼細" prop="urgencyLevel">
+ <el-select v-model="documentForm.urgencyLevel" placeholder="璇烽�夋嫨">
+ <el-option
+ v-for="item in document_urgency"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鏂囨。鐘舵�侊細" prop="docStatus">
+ <el-select v-model="documentForm.docStatus" placeholder="璇烽�夋嫨">
+ <el-option
+ v-for="item in document_status"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="24">
+ <el-form-item label="澶囨敞锛�" prop="remark">
+ <el-input
+ v-model="documentForm.remark"
+ type="textarea"
+ :rows="3"
+ placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitDocumentForm">纭</el-button>
+ <el-button @click="closeDocumentDia">鍙栨秷</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ <AttachmentManager ref="attachmentManagerRef" />
+ </div>
+ </template>
+
+<script setup>
+import { ref, reactive, onMounted, getCurrentInstance, toRefs, watch } from "vue";
+import { ElMessageBox, ElMessage } from "element-plus";
+import { ArrowRight, Folder, FolderOpened, Tickets, Document } from '@element-plus/icons-vue';
+import PIMTable from '@/components/PIMTable/PIMTable.vue';
+import { getToken } from "@/utils/auth";
+import { getCategoryTree, addCategory, updateCategory, deleteCategory, getDocumentList, addDocument, updateDocument, deleteDocument, getDocumentDetail, searchDocument, getWarehouseStructure } from '@/api/fileManagement/document'
+import { getWarehouseList } from '@/api/fileManagement/bookshelf'
+import AttachmentManager from './attachmentManager.vue'
+import { useDict } from '@/utils/dict'
+
+const { proxy } = getCurrentInstance();
+const tree = ref(null);
+const containerRef = ref(null);
+
+// 浣跨敤瀛楀吀鏁版嵁
+const { confidentiality_level, document_urgency, document_status, document_type, document_categories, retention_period } = useDict('confidentiality_level', 'document_urgency', 'document_status', 'document_type', 'document_categories', 'retention_period')
+
+// 鐩戝惉瀛楀吀鏁版嵁鍙樺寲
+watch([confidentiality_level, document_urgency, document_status, document_type, document_categories, retention_period], () => {
+ // 瀛楀吀鏁版嵁宸叉洿鏂�
+}, { immediate: true, deep: true });
+
+const categoryDia = ref(false);
+const documentDia = ref(false);
+const categoryOperationType = ref("");
+const documentOperationType = ref("");
+const search = ref("");
+const currentId = ref("");
+const currentParentId = ref("");
+const treeLoad = ref(false);
+const categoryList = ref([]);
+const expandedKeys = ref([]);
+const documentList = ref([]);
+const isShowButton = ref(false);
+const selectedRows = ref([]);
+const selectAll = ref(false);
+const isIndeterminate = ref(false);
+const tableLoading = ref(false);
+const attachmentManagerRef = ref(null);
+
+// 鏂囦欢涓婁紶閰嶇疆
+const upload = reactive({
+ url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
+ headers: { Authorization: "Bearer " + getToken() },
+});
+
+// 浣嶇疆鏍戞暟鎹�
+const locationTree = ref([]);
+
+// 琛ㄦ牸鍒楅厤缃�
+const tableColumns = ref([
+ { label: '鏂囨。鍚嶇О', prop: 'docName', width: '200' },
+ { label: '鏂囨。缂栧彿', prop: 'docNumber', width: '120' },
+ { label: '骞村害', prop: 'year', width: '80' },
+ { label: '璐d换浜�', prop: 'responsiblePerson', width: '100' },
+ {
+ label: '鏂囨。鏀剧疆浣嶇疆',
+ prop: 'warehouseGoodsShelvesRowcolId',
+ width: '150',
+ formatData: (params) => {
+ if (params === null || params === undefined || params === '') return '-';
+ return getLocationName(params);
+ }
+ },
+ { label: '鏂囨。鏃ユ湡', prop: 'docData', width: '120' },
+ {
+ label: '淇濈鏈熼檺',
+ prop: 'retentionPeriod',
+ width: '100',
+ dataType: 'tag',
+ formatData: (params) => {
+ if (params === null || params === undefined || params === '') return '-';
+ if (!retention_period.value || retention_period.value.length === 0) {
+ return params;
+ }
+ const item = retention_period.value.find(item => item.value == params);
+ return item ? item.label : params;
+ },
+ formatType: (params) => {
+ if (params === null || params === undefined || params === '') return 'info';
+ if (!retention_period.value || retention_period.value.length === 0) {
+ return 'info';
+ }
+ const item = retention_period.value.find(item => item.value == params);
+ const validTypes = ['success', 'warning', 'danger', 'info'];
+ return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+ }
+ },
+ {
+ label: '淇濆瘑绾у埆',
+ prop: 'securityLevel',
+ width: '80',
+ dataType: 'tag',
+ formatData: (params) => {
+ if (params === null || params === undefined || params === '') return '-';
+ if (!confidentiality_level.value || confidentiality_level.value.length === 0) {
+ return params;
+ }
+ const item = confidentiality_level.value.find(item => item.value == params);
+ return item ? item.label : params;
+ },
+ formatType: (params) => {
+ if (params === null || params === undefined || params === '') return 'info';
+ if (!confidentiality_level.value || confidentiality_level.value.length === 0) {
+ return 'info';
+ }
+ const item = confidentiality_level.value.find(item => item.value == params);
+ const validTypes = ['success', 'warning', 'danger', 'info'];
+ return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+ }
+ },
+ { label: '鍒嗘暟', prop: 'copyCount', width: '80' },
+ { label: '椤垫暟', prop: 'pageCount', width: '80' },
+ {
+ label: '鏂囨。绫诲埆',
+ prop: 'docCategory',
+ width: '100',
+ dataType: 'tag',
+ formatData: (params) => {
+ if (params === null || params === undefined || params === '') return '-';
+ if (!document_type.value || document_type.value.length === 0) {
+ return params;
+ }
+ const item = document_type.value.find(item => item.value == params);
+ return item ? item.label : params;
+ },
+ formatType: (params) => {
+ if (params === null || params === undefined || params === '') return 'info';
+ if (!document_type.value || document_type.value.length === 0) {
+ return 'info';
+ }
+ const item = document_type.value.find(item => item.value == params);
+ const validTypes = ['success', 'warning', 'danger', 'info'];
+ return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+ }
+ },
+ {
+ label: '鏂囨。绉嶇被',
+ prop: 'docType',
+ width: '100',
+ dataType: 'tag',
+ formatData: (params) => {
+ if (params === null || params === undefined || params === '') return '-';
+ if (!document_categories.value || document_categories.value.length === 0) {
+ return params;
+ }
+ const item = document_categories.value.find(item => item.value == params);
+ return item ? item.label : params;
+ },
+ formatType: (params) => {
+ if (params === null || params === undefined || params === '') return 'info';
+ if (!document_categories.value || document_categories.value.length === 0) {
+ return 'info';
+ }
+ const item = document_categories.value.find(item => item.value == params);
+ const validTypes = ['success', 'warning', 'danger', 'info'];
+ return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+ }
+ },
+ {
+ label: '绱ф�ョ▼搴�',
+ prop: 'urgencyLevel',
+ width: '100',
+ dataType: 'tag',
+ formatData: (params) => {
+ if (params === null || params === undefined || params === '') return '-';
+ if (!document_urgency.value || document_urgency.value.length === 0) {
+ return params;
+ }
+ const item = document_urgency.value.find(item => item.value == params);
+ return item ? item.label : params;
+ },
+ formatType: (params) => {
+ if (params === null || params === undefined || params === '') return 'info';
+ if (!document_urgency.value || document_urgency.value.length === 0) {
+ return 'info';
+ }
+ const item = document_urgency.value.find(item => item.value == params);
+ const validTypes = ['success', 'warning', 'danger', 'info'];
+ return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+ }
+ },
+ {
+ label: '鏂囨。鐘舵��',
+ prop: 'docStatus',
+ width: '100',
+ dataType: 'tag',
+ formatData: (params) => {
+ if (params === null || params === undefined || params === '') return '-';
+ if (!document_status.value || document_status.value.length === 0) {
+ return params;
+ }
+ const item = document_status.value.find(item => item.value == params);
+ return item ? item.label : params;
+ },
+ formatType: (params) => {
+ if (params === null || params === undefined || params === '') return 'info';
+ if (!document_status.value || document_status.value.length === 0) {
+ return 'info';
+ }
+ const item = document_status.value.find(item => item.value == params);
+ const validTypes = ['success', 'warning', 'danger', 'info'];
+ return item && validTypes.includes(item.elTagType) ? item.elTagType : 'info';
+ }
+ },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ fixed: 'right',
+ width: '150',
+ operation: [
+ {
+ name: "缂栬緫",
+ type: "text",
+ clickFun: (row) => {
+ openDocumentDia('edit', row)
+ },
+ },
+ {
+ name: "闄勪欢",
+ type: "text",
+ clickFun: (row) => {
+ openAttachment(row)
+ },
+ },
+ ],
+ }
+]);
+
+// 鍒嗙被琛ㄥ崟
+const categoryForm = reactive({
+ category: "",
+ parentId: "",
+ parentName: "",
+});
+
+const categoryRules = reactive({
+ category: [{ required: true, message: "璇疯緭鍏ュ垎绫诲悕绉�", trigger: "blur" }],
+});
+
+// 鏂囨。琛ㄥ崟
+const documentForm = reactive({
+ id: "",
+ documentClassificationId: "",
+ docName: "",
+ docNumber: "",
+ year: "",
+ responsiblePerson: "",
+ warehouseGoodsShelvesRowcolId: "",
+ docData: "",
+ retentionPeriod: "",
+ securityLevel: "",
+ copyCount: "",
+ pageCount: "",
+ docCategory: "",
+ docType: "",
+ urgencyLevel: "",
+ docStatus: "",
+ remark: "",
+ attachments: [], // 鏂板闄勪欢鏁扮粍
+});
+
+const documentRules = reactive({
+ docName: [{ required: true, message: "璇疯緭鍏ユ枃妗e悕绉�", trigger: "blur" }],
+ docNumber: [{ required: true, message: "璇疯緭鍏ユ枃妗g紪鍙�", trigger: "blur" }],
+ year: [{ required: true, message: "璇烽�夋嫨骞村害", trigger: "change" }],
+ documentClassificationId: [{ required: true, message: "璇烽�夋嫨鏂囨。鍒嗙被", trigger: "change" }],
+ warehouseGoodsShelvesRowcolId: [{ required: true, message: "璇烽�夋嫨鏂囨。鏀剧疆浣嶇疆", trigger: "change" }],
+});
+
+// 鍒嗛〉鐩稿叧
+const pagination = reactive({
+ currentPage: 1,
+ pageSize: 10,
+ total: 0,
+});
+
+// 鍒濆鍖栧垎绫绘爲鏁版嵁
+const initCategoryTree = async() => {
+ try {
+ treeLoad.value = true;
+ const res = await getCategoryTree();
+ if (res.code === 200) {
+ categoryList.value = res.data || [];
+
+ // 璁剧疆灞曞紑鐨勮妭鐐�
+ expandedKeys.value = [];
+ categoryList.value.forEach((item) => {
+ if (item.id) {
+ expandedKeys.value.push(item.id);
+ }
+ });
+ } else {
+ ElMessage.error(res.msg || "鑾峰彇鍒嗙被鏍戝け璐�");
+ }
+ } catch (error) {
+ ElMessage.error("鑾峰彇鍒嗙被鏍戝け璐ワ紝璇烽噸璇�");
+ } finally {
+ treeLoad.value = false;
+ }
+};
+
+// 鍒濆鍖栦粨搴撲綅缃暟鎹�
+const initLocationTree = async() => {
+ try {
+ const res = await getWarehouseList();
+ if (res.code === 200) {
+ // 杞崲鏁版嵁鏍煎紡锛岄�傞厤el-tree-select缁勪欢
+ locationTree.value = transformWarehouseData(res.data || []);
+ } else {
+ ElMessage.error(res.msg || "鑾峰彇浠撳簱浣嶇疆澶辫触");
+ }
+ } catch (error) {
+ ElMessage.error("鑾峰彇浠撳簱浣嶇疆澶辫触锛岃閲嶈瘯");
+ }
+};
+
+// 杞崲浠撳簱鏁版嵁鏍煎紡
+const transformWarehouseData = (data) => {
+ return data.map(item => ({
+ id: item.id,
+ label: item.name || item.warehouseName || item.label,
+ value: item.id,
+ children: item.children ? transformWarehouseData(item.children) : []
+ }));
+};
+
+// 鏍规嵁ID鑾峰彇浣嶇疆鍚嶇О
+const getLocationName = (locationId) => {
+ if (!locationId || !locationTree.value || locationTree.value.length === 0) {
+ return locationId || '-';
+ }
+
+ const findLocation = (tree, id) => {
+ for (let item of tree) {
+ if (item.value === locationId || item.id === locationId) {
+ return item.label;
+ }
+ if (item.children && item.children.length > 0) {
+ const result = findLocation(item.children, id);
+ if (result) return result;
+ }
+ }
+ return null;
+ };
+
+ const locationName = findLocation(locationTree.value, locationId);
+ return locationName || locationId;
+};
+
+// 杩囨护鍒嗙被鏍�
+const searchFilter = () => {
+ if (proxy.$refs.tree) {
+ proxy.$refs.tree.filter(search.value);
+ }
+};
+
+// 鎵撳紑鍒嗙被寮规
+const openCategoryDia = (type, data) => {
+ categoryOperationType.value = type;
+ categoryDia.value = true;
+ categoryForm.category = "";
+ categoryForm.parentId ="";
+ categoryForm.parentName = "";
+
+ if (type === "edit") {
+ categoryForm.category = data.category;
+ // 淇濆瓨褰撳墠缂栬緫鐨勫垎绫籌D
+ currentId.value = data.id;
+ } else if (type === "addSub") {
+ categoryForm.parentId = data.id;
+ categoryForm.parentName = data.category;
+ }
+};
+
+// 鎵撳紑鏂囨。寮规
+const openDocumentDia = (type, data) => {
+ documentOperationType.value = type;
+ documentDia.value = true;
+
+ if (type === "edit") {
+ // 缂栬緫妯″紡锛屽姞杞界幇鏈夋暟鎹�
+ Object.assign(documentForm, data);
+ documentForm.retentionPeriod = String(documentForm.retentionPeriod)
+ documentForm.securityLevel = String(documentForm.securityLevel)
+ documentForm.docCategory = String(documentForm.docCategory)
+ documentForm.docType = String(documentForm.docType)
+ documentForm.urgencyLevel = String(documentForm.urgencyLevel)
+ documentForm.docStatus = String(documentForm.docStatus)
+
+ // 鍔犺浇闄勪欢淇℃伅
+ if (data.attachments) {
+ documentForm.attachments = [...data.attachments];
+ } else {
+ documentForm.attachments = [];
+ }
+ } else {
+ // 鏂板妯″紡锛屾竻绌鸿〃鍗�
+ Object.keys(documentForm).forEach(key => {
+ documentForm[key] = "";
+ });
+ documentForm.attachments = []; // 鏂板妯″紡涓嬩篃娓呯┖闄勪欢
+ // 璁剧疆榛樿鍊� - 浣跨敤瀛楀吀鏁版嵁鐨勭涓�涓�夐」浣滀负榛樿鍊�
+ if (document_status.value && document_status.value.length > 0) {
+ documentForm.docStatus = document_status.value[0].value;
+ }
+ if (document_urgency.value && document_urgency.value.length > 0) {
+ documentForm.urgencyLevel = document_urgency.value[0].value;
+ }
+ }
+};
+
+// 鎻愪氦鍒嗙被琛ㄥ崟
+const submitCategoryForm = () => {
+ proxy.$refs.categoryFormRef.validate(async (valid) => {
+ if (valid) {
+ try {
+ if (categoryOperationType.value === "addSub") {
+ // 娣诲姞瀛愬垎绫�
+ const res = await addCategory({
+ category: categoryForm.category,
+ parentId: categoryForm.parentId
+ });
+ if (res.code === 200) {
+ ElMessage.success("娣诲姞瀛愬垎绫绘垚鍔�");
+ // 閲嶆柊鍔犺浇鍒嗙被鏍�
+ await initCategoryTree();
+ } else {
+ ElMessage.error(res.msg || "娣诲姞瀛愬垎绫诲け璐�");
+ }
+ } else if (categoryOperationType.value === "edit") {
+ // 缂栬緫鍒嗙被
+ const res = await updateCategory({
+ id: currentId.value,
+ category: categoryForm.category
+ });
+ if (res.code === 200) {
+ ElMessage.success("缂栬緫鍒嗙被鎴愬姛");
+ // 閲嶆柊鍔犺浇鍒嗙被鏍�
+ await initCategoryTree();
+ } else {
+ ElMessage.error(res.msg || "缂栬緫鍒嗙被澶辫触");
+ }
+ } else {
+ // 鏂板椤剁骇鍒嗙被
+ const res = await addCategory({
+ category: categoryForm.category,
+ parentId: null
+ });
+ if (res.code === 200) {
+ ElMessage.success("鏂板鍒嗙被鎴愬姛");
+ // 閲嶆柊鍔犺浇鍒嗙被鏍�
+ await initCategoryTree();
+ } else {
+ ElMessage.error(res.msg || "鏂板鍒嗙被澶辫触");
+ }
+ }
+
+ closeCategoryDia();
+ } catch (error) {
+ ElMessage.error("鎿嶄綔澶辫触锛岃閲嶈瘯");
+ }
+ }
+ });
+};
+
+// 鍏抽棴鍒嗙被寮规
+const closeCategoryDia = () => {
+ proxy.$refs.categoryFormRef.resetFields();
+ categoryForm.parentId = "";
+ categoryForm.parentName = "";
+ categoryDia.value = false;
+};
+
+// 鍒犻櫎鍒嗙被
+const removeCategory = (node, data) => {
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(async () => {
+ try {
+ const res = await deleteCategory([data.id]);
+ if (res.code === 200) {
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ // 閲嶆柊鍔犺浇鍒嗙被鏍�
+ await initCategoryTree();
+ } else {
+ ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+ }
+ } catch (error) {
+ ElMessage.error("鍒犻櫎澶辫触锛岃閲嶈瘯");
+ }
+ })
+ .catch(() => {
+ ElMessage("宸插彇娑�");
+ });
+};
+
+// 閫夋嫨鍒嗙被
+const handleNodeClick = (val, node, el) => {
+ // 鍒ゆ柇鏄惁涓哄彾瀛愯妭鐐�
+ isShowButton.value = true;
+ // 鍙湁鍙跺瓙鑺傜偣鎵嶆墽琛屼互涓嬮�昏緫
+ currentId.value = val.id;
+ currentParentId.value = val.parentId;
+
+ // 娓呯┖閫夋嫨鐘舵��
+ selectedRows.value = [];
+ selectAll.value = false;
+ isIndeterminate.value = false;
+
+ // 閲嶇疆鍒嗛〉
+ pagination.currentPage = 1;
+ pagination.total = 0;
+
+ // 鍔犺浇鏂囨。鍒楄〃
+ if (isShowButton.value) {
+ loadDocumentList();
+ } else {
+ // 濡傛灉涓嶆槸鍙跺瓙鑺傜偣锛屾竻绌烘枃妗e垪琛�
+ documentList.value = [];
+ }
+};
+
+// 鎻愪氦鏂囨。琛ㄥ崟
+const submitDocumentForm = () => {
+ proxy.$refs.documentFormRef.validate(async (valid) => {
+ if (valid) {
+ try {
+ // 鏋勫缓鎻愪氦鏁版嵁
+ const submitData = {
+ ...documentForm,
+ // 璁剧疆褰撳墠閫変腑鐨勫垎绫籌D
+ documentClassificationId: currentId.value || documentForm.documentClassificationId,
+ // 娣诲姞闄勪欢淇℃伅
+ // attachments: documentForm.attachments
+ };
+
+ if (documentOperationType.value === "edit") {
+ // 缂栬緫妯″紡锛屾洿鏂扮幇鏈夋暟鎹�
+ const res = await updateDocument(submitData);
+ if (res.code === 200) {
+ ElMessage.success("缂栬緫鎴愬姛");
+ // 閲嶆柊鍔犺浇鏂囨。鍒楄〃
+ await loadDocumentList();
+ // 鍒锋柊闄勪欢鍒楄〃
+ if (attachmentManagerRef.value && documentForm.id) {
+ attachmentManagerRef.value.loadAttachmentList(documentForm.id);
+ }
+ } else {
+ ElMessage.error(res.msg || "缂栬緫澶辫触");
+ }
+ } else {
+ // 鏂板妯″紡锛屾坊鍔犳柊鏁版嵁
+ const res = await addDocument(submitData);
+ if (res.code === 200) {
+ ElMessage.success("鏂板鎴愬姛");
+ // 閲嶆柊鍔犺浇鏂囨。鍒楄〃
+ await loadDocumentList();
+ // 鍒锋柊闄勪欢鍒楄〃
+ if (attachmentManagerRef.value && res.data && res.data.id) {
+ attachmentManagerRef.value.loadAttachmentList(res.data.id);
+ }
+ } else {
+ ElMessage.error(res.msg || "鏂板澶辫触");
+ }
+ }
+ closeDocumentDia();
+ } catch (error) {
+ ElMessage.error("鎿嶄綔澶辫触锛岃閲嶈瘯");
+ }
+ }
+ });
+};
+
+// 鍏抽棴鏂囨。寮规
+const closeDocumentDia = () => {
+ proxy.$refs.documentFormRef.resetFields();
+ documentDia.value = false;
+ // 娓呯┖琛ㄥ崟鏁版嵁
+ Object.keys(documentForm).forEach(key => {
+ documentForm[key] = "";
+ });
+ documentForm.attachments = []; // 鍏抽棴寮规鏃朵篃娓呯┖闄勪欢
+};
+
+// 澶勭悊浣嶇疆閫夋嫨鍙樺寲
+const handleLocationChange = (value) => {
+ if (value) {
+ // 妫�鏌ラ�夋嫨鐨勬槸鍚︿负鍙跺瓙鑺傜偣
+ const isLeafNode = checkIfLeafNode(locationTree.value, value);
+ if (!isLeafNode) {
+ ElMessage.warning("璇烽�夋嫨鏈�搴曞眰鐨勪綅缃紙濡傦細鏌滃眰锛�");
+ documentForm.warehouseGoodsShelvesRowcolId = "";
+ return;
+ }
+ }
+};
+
+// 妫�鏌ユ槸鍚︿负鍙跺瓙鑺傜偣
+const checkIfLeafNode = (tree, value) => {
+ for (let item of tree) {
+ if (item.value === value || item.id === value) {
+ // 濡傛灉娌℃湁瀛愯妭鐐癸紝鍒欎负鍙跺瓙鑺傜偣
+ return !item.children || item.children.length === 0;
+ }
+ if (item.children && item.children.length > 0) {
+ const result = checkIfLeafNode(item.children, value);
+ if (result !== null) {
+ return result;
+ }
+ }
+ }
+ return null;
+};
+
+// 鍒犻櫎鏂囨。
+const handleDelete = () => {
+ if (selectedRows.value.length > 0) {
+ ElMessageBox.confirm(`纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.value.length} 鏉¤褰曞悧锛焋, "鍒犻櫎鎻愮ず", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(async () => {
+ try {
+ const selectedIds = selectedRows.value.map(row => row.id);
+ const res = await deleteDocument(selectedIds);
+ if (res.code === 200) {
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ // 閲嶆柊鍔犺浇鏂囨。鍒楄〃
+ await loadDocumentList();
+ } else {
+ ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+ }
+ } catch (error) {
+ ElMessage.error("鍒犻櫎澶辫触锛岃閲嶈瘯");
+ }
+ })
+ .catch(() => {
+ ElMessage("宸插彇娑�");
+ });
+ } else {
+ ElMessage.warning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
+ }
+};
+
+// PIMTable 閫夋嫨鍙樺寲浜嬩欢
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+
+ // 鏇存柊鍏ㄩ�夌姸鎬�
+ const selectedCount = selection.length;
+ const totalCount = documentList.value.length;
+
+ if (selectedCount === 0) {
+ selectAll.value = false;
+ isIndeterminate.value = false;
+ } else if (selectedCount === totalCount) {
+ selectAll.value = true;
+ isIndeterminate.value = false;
+ } else {
+ selectAll.value = false;
+ isIndeterminate.value = true;
+ }
+};
+
+// 鍔犺浇鏂囨。鍒楄〃
+const loadDocumentList = async () => {
+ try {
+ tableLoading.value = true;
+
+ // 鏋勫缓鏌ヨ鍙傛暟
+ const query = {
+ page: pagination.currentPage,
+ size: pagination.pageSize,
+ documentClassificationId:currentId.value
+ };
+
+ const res = await getDocumentList(query);
+ if (res.code === 200) {
+ documentList.value = res.data.records || [];
+ pagination.total = res.data.total || 0;
+ } else {
+ ElMessage.error(res.msg || "鑾峰彇鏂囨。鍒楄〃澶辫触");
+ documentList.value = [];
+ pagination.total = 0;
+ }
+
+ // 閲嶇疆閫夋嫨鐘舵��
+ selectedRows.value = [];
+ selectAll.value = false;
+ isIndeterminate.value = false;
+ } catch (error) {
+ ElMessage.error("鑾峰彇鏂囨。鍒楄〃澶辫触锛岃閲嶈瘯");
+ documentList.value = [];
+ pagination.total = 0;
+ } finally {
+ tableLoading.value = false;
+ }
+};
+
+// 澶勭悊鍒嗛〉鍙樺寲
+const handlePagination = (current, size) => {
+ pagination.currentPage = current;
+ pagination.pageSize = size;
+ loadDocumentList();
+};
+
+// 璋冪敤tree杩囨护鏂规硶
+const filterNode = (value, data, node) => {
+ if (!value) {
+ return true;
+ }
+ let val = value.toLowerCase();
+ return chooseNode(val, data, node);
+};
+
+// 杩囨护鐖惰妭鐐� / 瀛愯妭鐐�
+const chooseNode = (value, data, node) => {
+ if (data.category && data.category.toLowerCase().indexOf(value) !== -1) {
+ return true;
+ }
+ const level = node.level;
+ if (level === 1) {
+ return false;
+ }
+ let parentData = node.parent;
+ let index = 0;
+ while (index < level - 1) {
+ if (parentData.data.category && parentData.data.category.toLowerCase().indexOf(value) !== -1) {
+ return true;
+ }
+ parentData = parentData.parent;
+ index++;
+ }
+ return false;
+};
+
+// 鎵撳紑闄勪欢
+const openAttachment = (row) => {
+ attachmentManagerRef.value.open([], row.id);
+};
+
+onMounted(() => {
+ initCategoryTree();
+ initLocationTree();
+
+ // 涓嶅湪鍒濆鍖栨椂鍔犺浇鏂囨。鍒楄〃锛岀瓑寰呯敤鎴烽�夋嫨鍒嗙被鍚庡啀鍔犺浇
+});
+</script>
+
+<style scoped>
+.document-view {
+ display: flex;
+ height: 100%;
+}
+
+.left {
+ width: 380px;
+ padding: 16px;
+ background: #ffffff;
+ border-right: 1px solid #e4e7ed;
+}
+
+.right {
+ width: calc(100% - 380px);
+ padding: 16px;
+ background: #ffffff;
+}
+
+.custom-tree-node {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 14px;
+ padding-right: 8px;
+}
+
+.tree-node-content {
+ display: flex;
+ align-items: center;
+ height: 100%;
+}
+
+.orange-icon {
+ color: orange;
+ font-size: 18px;
+ margin-right: 8px;
+}
+
+.table-container {
+ background: #ffffff;
+ border-radius: 8px;
+ overflow: hidden;
+ position: relative;
+}
+
+.add-row {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ background-color: #f5f7fa;
+ cursor: pointer;
+ transition: background-color 0.2s ease;
+ padding: 12px 16px;
+ margin-bottom: 16px;
+ border-radius: 6px;
+ border: 1px dashed #d9d9d9;
+}
+
+.add-row:hover {
+ background-color: #e4e7ed;
+ border-color: #c0c4cc;
+}
+
+.add-icon {
+ color: #909399;
+ font-size: 16px;
+}
+
+.add-row span {
+ color: #606266;
+ font-size: 14px;
+}
+
+.empty-data {
+ text-align: center;
+ color: #909399;
+ padding: 40px;
+ font-size: 14px;
+}
+
+.dialog-footer {
+ text-align: right;
+}
+
+.operation-column {
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 120px;
+ background: #ffffff;
+ border-left: 1px solid #e4e7ed;
+ z-index: 1;
+ box-shadow: -2px 0 4px rgba(0, 0, 0, 0.1);
+}
+
+.operation-header {
+ height: 40px;
+ line-height: 40px;
+ text-align: center;
+ background: #fafafa;
+ border-bottom: 1px solid #e4e7ed;
+ font-weight: 500;
+ color: #606266;
+}
+
+.operation-cell {
+ height: 40px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-bottom: 1px solid #e4e7ed;
+}
+
+.operation-cell:last-child {
+ border-bottom: none;
+}
+
+.attachment-section {
+ width: 100%;
+}
+
+.attachment-list {
+ margin-bottom: 10px;
+}
+
+.attachment-item {
+ display: flex;
+ align-items: center;
+ padding: 8px 12px;
+ background-color: #f5f7fa;
+ border-radius: 4px;
+ margin-bottom: 8px;
+}
+
+.file-icon {
+ margin-right: 8px;
+ color: #409eff;
+}
+
+.file-name {
+ flex: 1;
+ color: #606266;
+ font-size: 14px;
+}
+</style>
diff --git a/src/views/fileManagement/return/index.vue b/src/views/fileManagement/return/index.vue
new file mode 100644
index 0000000..a95c8af
--- /dev/null
+++ b/src/views/fileManagement/return/index.vue
@@ -0,0 +1,595 @@
+<template>
+ <div class="app-container return-view">
+ <!-- 鏌ヨ鍖哄煙 -->
+ <div class="search-container">
+ <el-form :model="searchForm" :inline="true" class="search-form">
+ <!-- <el-form-item label="鍊熼槄鐘舵�侊細">
+ <el-select v-model="searchForm.borrowStatus" placeholder="璇烽�夋嫨鍊熼槄鐘舵��" clearable style="width: 150px">
+ <el-option label="鍊熼槄" value="鍊熼槄" />
+ <el-option label="褰掕繕" value="褰掕繕" />
+ </el-select>
+ </el-form-item> -->
+ <el-form-item label="鍊熼槄浜猴細">
+ <el-input
+ v-model="searchForm.borrower"
+ placeholder="璇疯緭鍏ュ�熼槄浜�"
+ clearable
+ style="width: 200px"
+ />
+ </el-form-item>
+ <el-form-item label="褰掕繕浜猴細">
+ <el-input
+ v-model="searchForm.returner"
+ placeholder="璇疯緭鍏ュ綊杩樹汉"
+ clearable
+ style="width: 200px"
+ />
+ </el-form-item>
+ <el-form-item label="褰掕繕鏃ユ湡鑼冨洿锛�">
+ <el-date-picker
+ v-model="searchForm.dateRange"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ style="width: 300px"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleSearch">
+ <el-icon><Search /></el-icon>
+ 鏌ヨ
+ </el-button>
+ <el-button @click="handleReset">
+ <el-icon><Refresh /></el-icon>
+ 閲嶇疆
+ </el-button>
+ </el-form-item>
+ <el-form-item style="margin-left: auto;">
+ <el-button type="primary" @click="openReturnDia('add')">
+ <el-icon><Plus /></el-icon>
+ 鏂板褰掕繕
+ </el-button>
+ <el-button
+ type="danger"
+ @click="handleBatchDelete"
+ :disabled="selectedRows.length === 0"
+ >
+ <el-icon><Delete /></el-icon>
+ 鎵归噺鍒犻櫎 ({{ selectedRows.length }})
+ </el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+
+ <!-- 琛ㄦ牸鍖哄煙 -->
+ <div class="table-container">
+ <PIMTable
+ :table-data="returnList"
+ :column="tableColumns"
+ :is-selection="true"
+ :border="true"
+ :table-loading="tableLoading"
+ :page="{
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ total: pagination.total,
+ layout: 'total, sizes, prev, pager, next, jumper'
+ }"
+ @selection-change="handleSelectionChange"
+ @pagination="handlePagination"
+ />
+ </div>
+
+ <!-- 褰掕繕鏂板/缂栬緫瀵硅瘽妗� -->
+ <el-dialog
+ v-model="returnDia"
+ :title="returnOperationType === 'add' ? '鏂板褰掕繕' : '缂栬緫褰掕繕'"
+ width="800px"
+ @close="closeReturnDia"
+ @keydown.enter.prevent
+ >
+ <el-form
+ :model="returnForm"
+ label-width="140px"
+ :rules="returnRules"
+ ref="returnFormRef"
+ >
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鏂囨。锛�" prop="borrowId">
+ <el-select v-model="returnForm.borrowId" placeholder="璇烽�夋嫨鏂囨。" style="width: 100%" @change="handleDocumentChange">
+ <el-option
+ v-for="item in documentList"
+ :key="item.id"
+ :label="item.docName || item.name"
+ :value="item.id"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍊熼槄浜猴細" prop="borrower">
+ <el-input v-model="returnForm.borrower" placeholder="鍊熼槄浜哄皢鏍规嵁鏂囨。閫夋嫨鑷姩甯﹀嚭" disabled />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="褰掕繕浜猴細" prop="returner">
+ <el-input v-model="returnForm.returner" placeholder="璇疯緭鍏ュ綊杩樹汉" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="褰掕繕鏃ユ湡锛�" prop="returnDate">
+ <el-date-picker
+ v-model="returnForm.returnDate"
+ type="date"
+ placeholder="閫夋嫨褰掕繕鏃ユ湡"
+ style="width: 100%"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="24">
+ <el-form-item label="搴斿綊杩樻棩鏈燂細" prop="dueReturnDate">
+ <el-date-picker
+ v-model="returnForm.dueReturnDate"
+ type="date"
+ placeholder="搴斿綊杩樻棩鏈熷皢鏍规嵁鏂囨。閫夋嫨鑷姩甯﹀嚭"
+ style="width: 100%"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ disabled
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="20">
+ <el-col :span="24">
+ <el-form-item label="澶囨敞璇存槑锛�" prop="remark">
+ <el-input
+ v-model="returnForm.remark"
+ type="textarea"
+ :rows="3"
+ placeholder="璇疯緭鍏ュ娉ㄨ鏄�"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitReturnForm">纭</el-button>
+ <el-button @click="closeReturnDia">鍙栨秷</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+import { ElMessageBox, ElMessage } from "element-plus";
+import { Search, Refresh, Plus, Delete } from '@element-plus/icons-vue';
+import PIMTable from '@/components/PIMTable/PIMTable.vue';
+import { getReturnListPage, returnDocument, deleteReturn, getDocumentList, updateBorrow, reventUpdate } from '@/api/fileManagement/return';
+
+const { proxy } = getCurrentInstance();
+
+// 鍝嶅簲寮忔暟鎹�
+const returnDia = ref(false);
+const returnOperationType = ref("");
+const tableLoading = ref(false);
+const returnList = ref([]);
+const selectedRows = ref([]);
+const documentList = ref([]); // 鏂囨。鍒楄〃
+
+// 鍒嗛〉鐩稿叧
+const pagination = reactive({
+ currentPage: 1,
+ pageSize: 10,
+ total: 0,
+});
+
+// 鏌ヨ琛ㄥ崟
+const searchForm = reactive({
+ borrowStatus: "",
+ borrower: "",
+ returner: "",
+ dateRange: []
+});
+
+// 褰掕繕琛ㄥ崟
+const returnForm = reactive({
+ id: "",
+ borrowId: "",
+ borrower: "",
+ returner: "",
+ borrowStatus: "",
+ returnDate: "",
+ dueReturnDate: "",
+ remark: ""
+});
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const returnRules = reactive({
+ borrowId: [{ required: true, message: "璇烽�夋嫨鏂囨。", trigger: "change" }],
+ returner: [{ required: true, message: "璇疯緭鍏ュ綊杩樹汉", trigger: "blur" }],
+ returnDate: [{ required: true, message: "璇烽�夋嫨褰掕繕鏃ユ湡", trigger: "change" }]
+});
+
+// 琛ㄦ牸鍒楅厤缃�
+const tableColumns = ref([
+ {
+ label: '鏂囨。鍚嶇О',
+ prop: 'docName',
+ width: '200',
+ },
+ { label: '鍊熼槄浜�', prop: 'borrower' },
+ { label: '褰掕繕浜�', prop: 'returner' },
+ {
+ label: '鍊熼槄鐘舵��',
+ prop: 'borrowStatus',
+ dataType: 'tag',
+ formatData: (params) => {
+ if (params === null || params === undefined || params === '') return '-';
+ return params;
+ },
+ formatType: (params) => {
+ if (params === '褰掕繕') return 'success';
+ if (params === '鍊熼槄') return 'warning';
+ return 'info';
+ }
+ },
+ { label: '褰掕繕鏃ユ湡', prop: 'returnDate' },
+ { label: '搴斿綊杩樻棩鏈�', prop: 'dueReturnDate' },
+ { label: '澶囨敞', prop: 'remark', width: '150' },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ fixed: 'right',
+ width: '150',
+ operation: [
+ {
+ name: "缂栬緫",
+ type: "text",
+ clickFun: (row) => {
+ openReturnDia('edit', row)
+ },
+ },
+ {
+ name: "鍒犻櫎",
+ type: "text",
+ clickFun: (row) => {
+ handleDelete(row)
+ },
+ },
+ ],
+ }
+]);
+
+// 鍒濆鍖栨暟鎹�
+const initData = async () => {
+ await Promise.all([
+ loadDocumentList(),
+ loadReturnList()
+ ]);
+};
+
+// 鍔犺浇鏂囨。鍒楄〃
+const loadDocumentList = async () => {
+ try {
+ const res = await getDocumentList();
+ if (res.code === 200) {
+ documentList.value = res.data || [];
+ } else {
+ ElMessage.error(res.msg || "鑾峰彇鏂囨。鍒楄〃澶辫触");
+ documentList.value = [];
+ }
+ } catch (error) {
+ ElMessage.error("鑾峰彇鏂囨。鍒楄〃澶辫触锛岃閲嶈瘯");
+ documentList.value = [];
+ }
+};
+
+// 鍔犺浇褰掕繕鍒楄〃
+const loadReturnList = async () => {
+ try {
+ tableLoading.value = true;
+
+ // 鏋勫缓鏌ヨ鍙傛暟
+ const query = {
+ page: pagination.currentPage,
+ size: pagination.pageSize,
+ borrowStatus: searchForm.borrowStatus || undefined,
+ borrower: searchForm.borrower || undefined,
+ returner: searchForm.returner || undefined,
+ entryDateStart: searchForm.dateRange && searchForm.dateRange.length > 0 ? searchForm.dateRange[0] : undefined,
+ entryDateEnd: searchForm.dateRange && searchForm.dateRange.length > 1 ? searchForm.dateRange[1] : undefined
+ };
+
+ // 绉婚櫎undefined鐨勫弬鏁�
+ Object.keys(query).forEach(key => {
+ if (query[key] === undefined) {
+ delete query[key];
+ }
+ });
+
+ const res = await getReturnListPage(query);
+ if (res.code === 200) {
+ returnList.value = res.data.records || [];
+ pagination.total = res.data.total || 0;
+ } else {
+ ElMessage.error(res.msg || "鑾峰彇褰掕繕鍒楄〃澶辫触");
+ returnList.value = [];
+ pagination.total = 0;
+ }
+
+ // 閲嶇疆閫夋嫨鐘舵��
+ selectedRows.value = [];
+ } catch (error) {
+ ElMessage.error("鑾峰彇褰掕繕鍒楄〃澶辫触锛岃閲嶈瘯");
+ returnList.value = [];
+ pagination.total = 0;
+ } finally {
+ tableLoading.value = false;
+ }
+};
+
+// 鏌ヨ
+const handleSearch = () => {
+ pagination.currentPage = 1;
+ loadReturnList();
+};
+
+// 閲嶇疆鏌ヨ
+const handleReset = () => {
+ searchForm.borrowStatus = "";
+ searchForm.borrower = "";
+ searchForm.returner = "";
+ searchForm.dateRange = [];
+ pagination.currentPage = 1;
+ loadReturnList();
+ ElMessage.success("鏌ヨ鏉′欢宸查噸缃�");
+};
+
+// 鎵撳紑褰掕繕寮规
+const openReturnDia = (type, data) => {
+ returnOperationType.value = type;
+ returnDia.value = true;
+
+ if (type === "edit") {
+ // 缂栬緫妯″紡锛屽姞杞界幇鏈夋暟鎹�
+ Object.assign(returnForm, data);
+ // 缂栬緫妯″紡涓嬶紝鏂囨。閫夋嫨鍚庤嚜鍔ㄥ~鍏呭�熼槄浜哄拰搴斿綊杩樻棩鏈�
+ if (returnForm.borrowId) {
+ handleDocumentChange(returnForm.borrowId);
+ }
+ } else {
+ // 鏂板妯″紡锛屾竻绌鸿〃鍗�
+ Object.keys(returnForm).forEach(key => {
+ returnForm[key] = "";
+ });
+ // 璁剧疆榛樿鐘舵��
+ returnForm.borrowStatus = "褰掕繕";
+ // 璁剧疆褰撳墠鏃ユ湡涓哄綊杩樻棩鏈�
+ returnForm.returnDate = new Date().toISOString().split('T')[0];
+ }
+};
+
+// 鍏抽棴褰掕繕寮规
+const closeReturnDia = () => {
+ proxy.$refs.returnFormRef.resetFields();
+ returnDia.value = false;
+};
+
+// 鎻愪氦褰掕繕琛ㄥ崟
+const submitReturnForm = () => {
+ proxy.$refs.returnFormRef.validate(async (valid) => {
+ if (valid) {
+ try {
+ if (returnOperationType.value === "edit") {
+ // 缂栬緫妯″紡锛岃皟鐢ㄥ綊杩樻洿鏂版帴鍙�
+ const res = await reventUpdate({
+ id: returnForm.id,
+ documentationId: returnForm.documentationId,
+ borrower: returnForm.borrower,
+ returner: returnForm.returner,
+ borrowStatus: returnForm.borrowStatus,
+ returnDate: returnForm.returnDate,
+ dueReturnDate: returnForm.dueReturnDate,
+ remark: returnForm.remark
+ });
+
+ if (res.code === 200) {
+ ElMessage.success("缂栬緫鎴愬姛");
+ await loadReturnList();
+ closeReturnDia();
+ } else {
+ ElMessage.error(res.msg || "缂栬緫澶辫触");
+ }
+ } else {
+ // 鏂板妯″紡锛岃皟鐢ㄥ綊杩樻帴鍙�
+ const res = await returnDocument({
+ borrowId: returnForm.borrowId,
+ borrower: returnForm.borrower,
+ returner: returnForm.returner,
+ borrowStatus: returnForm.borrowStatus,
+ returnDate: returnForm.returnDate,
+ dueReturnDate: returnForm.dueReturnDate,
+ remark: returnForm.remark
+ });
+
+ if (res.code === 200) {
+ ElMessage.success("鏂板鎴愬姛");
+ await loadReturnList();
+ closeReturnDia();
+ } else {
+ ElMessage.error(res.msg || "鏂板澶辫触");
+ }
+ }
+ } catch (error) {
+ ElMessage.error("鎿嶄綔澶辫触锛岃閲嶈瘯");
+ }
+ }
+ });
+};
+
+// 鍒犻櫎褰掕繕璁板綍
+const handleDelete = (row) => {
+ ElMessageBox.confirm(
+ `纭畾瑕佸垹闄よ繖鏉″綊杩樿褰曞悧锛焋,
+ "鍒犻櫎鎻愮ず",
+ {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }
+ ).then(async () => {
+ try {
+ const res = await deleteReturn([row.id]);
+ if (res.code === 200) {
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ await loadReturnList();
+ } else {
+ ElMessage.error(res.msg || "鍒犻櫎澶辫触");
+ }
+ } catch (error) {
+ ElMessage.error("鍒犻櫎澶辫触锛岃閲嶈瘯");
+ }
+ }).catch(() => {
+ ElMessage.info("宸插彇娑堝垹闄�");
+ });
+};
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+ if (selectedRows.value.length === 0) {
+ ElMessage.warning("璇烽�夋嫨瑕佸垹闄ょ殑璁板綍");
+ return;
+ }
+
+ ElMessageBox.confirm(
+ `纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.value.length} 鏉″綊杩樿褰曞悧锛焋,
+ "鎵归噺鍒犻櫎鎻愮ず",
+ {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }
+ ).then(async () => {
+ try {
+ const selectedIds = selectedRows.value.map(row => row.id);
+ const res = await deleteReturn(selectedIds);
+ if (res.code === 200) {
+ ElMessage.success("鎵归噺鍒犻櫎鎴愬姛");
+ await loadReturnList();
+ } else {
+ ElMessage.error(res.msg || "鎵归噺鍒犻櫎澶辫触");
+ }
+ } catch (error) {
+ ElMessage.error("鎵归噺鍒犻櫎澶辫触锛岃閲嶈瘯");
+ }
+ }).catch(() => {
+ ElMessage.info("宸插彇娑堝垹闄�");
+ });
+};
+
+// 閫夋嫨鍙樺寲浜嬩欢
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+
+// 澶勭悊鍒嗛〉鍙樺寲
+const handlePagination = (current, size) => {
+ pagination.currentPage = current;
+ pagination.pageSize = size;
+ loadReturnList();
+};
+
+// 澶勭悊鏂囨。閫夋嫨鍙樺寲
+const handleDocumentChange = (documentId) => {
+ if (documentId) {
+ // 鏍规嵁閫夋嫨鐨勬枃妗D锛屼粠鏂囨。鍒楄〃涓煡鎵惧搴旂殑鏂囨。淇℃伅
+ const selectedDoc = documentList.value.find(doc => doc.id === documentId);
+ if (selectedDoc) {
+ // 鑷姩濉厖鍊熼槄浜哄拰搴斿綊杩樻棩鏈�
+ returnForm.borrower = selectedDoc.borrower || selectedDoc.borrowerName || '';
+ returnForm.dueReturnDate = selectedDoc.dueReturnDate || selectedDoc.expectedReturnDate || '';
+ }
+ } else {
+ // 娓呯┖鐩稿叧瀛楁
+ returnForm.borrower = '';
+ returnForm.dueReturnDate = '';
+ }
+};
+
+// 鐢熷懡鍛ㄦ湡
+onMounted(() => {
+ initData();
+});
+</script>
+
+<style scoped>
+.return-view {
+ padding: 20px;
+}
+
+.search-container {
+ background: #ffffff;
+ padding: 20px;
+ border-radius: 8px;
+ margin-bottom: 20px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.search-form {
+ margin: 0;
+}
+
+.table-container {
+ background: #ffffff;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.empty-data {
+ text-align: center;
+ color: #909399;
+ padding: 40px;
+ font-size: 14px;
+}
+
+.dialog-footer {
+ text-align: right;
+}
+
+:deep(.el-form-item__label) {
+ font-weight: 500;
+ color: #303133;
+}
+
+:deep(.el-input__wrapper) {
+ box-shadow: 0 0 0 1px #dcdfe6 inset;
+}
+
+:deep(.el-input__wrapper:hover) {
+ box-shadow: 0 0 0 1px #c0c4cc inset;
+}
+
+:deep(.el-input__wrapper.is-focus) {
+ box-shadow: 0 0 0 1px #409eff inset;
+}
+</style>
diff --git a/src/views/fileManagement/statistics/index.vue b/src/views/fileManagement/statistics/index.vue
new file mode 100644
index 0000000..42b81e4
--- /dev/null
+++ b/src/views/fileManagement/statistics/index.vue
@@ -0,0 +1,539 @@
+<template>
+ <div class="app-container statistics-container">
+
+ <!-- 鎬讳綋缁熻鍗$墖 -->
+ <el-row :gutter="20" class="statistics-cards">
+ <el-col :span="6" v-for="(item, index) in overviewData" :key="index">
+ <el-card class="statistics-card" :class="item.type">
+ <div class="card-content">
+ <div class="card-icon">
+ <el-icon :size="32">
+ <component :is="item.icon" />
+ </el-icon>
+ </div>
+ <div class="card-info">
+ <div class="card-number">
+ <el-skeleton-item v-if="loading" variant="text" style="width: 60px; height: 32px;" />
+ <span v-else>{{ item.value }}</span>
+ </div>
+ <div class="card-label">{{ item.label }}</div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+
+ <!-- 鍥捐〃鍖哄煙 -->
+ <el-row :gutter="20" class="charts-section">
+ <el-col :span="12">
+ <el-card class="chart-card">
+ <template #header>
+ <div class="card-header">
+ <span>妗f鍒嗙被缁熻</span>
+ </div>
+ </template>
+ <div class="chart-container">
+ <div ref="categoryChartRef" class="chart"></div>
+ </div>
+ </el-card>
+ </el-col>
+
+ <el-col :span="12">
+ <el-card class="chart-card">
+ <template #header>
+ <div class="card-header">
+ <span>妗f鐘舵�佺粺璁�</span>
+ </div>
+ </template>
+ <div class="chart-container">
+ <div ref="statusChartRef" class="chart"></div>
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+</template>
+
+<script setup>
+import { ref, onMounted, nextTick, onUnmounted } from "vue";
+import { ElMessage } from "element-plus";
+import { Refresh } from "@element-plus/icons-vue";
+import * as echarts from "echarts";
+import {
+ getDocumentationOverview,
+ getDocumentationCategoryStats,
+ getDocumentationStatusStats
+} from "@/api/fileManagement/document";
+import {
+ Document,
+ Folder,
+ Tickets,
+ Calendar
+} from "@element-plus/icons-vue";
+
+// 鍝嶅簲寮忔暟鎹�
+const overviewData = ref([
+ {
+ label: "鎬绘。妗堟暟",
+ value: 0,
+ icon: "Document",
+ type: "primary",
+ },
+ {
+ label: "鍒嗙被鏁伴噺",
+ value: 0,
+ icon: "Folder",
+ type: "success",
+ },
+ {
+ label: "鍊熷嚭妗f",
+ value: 0,
+ icon: "Tickets",
+ type: "warning",
+ },
+ {
+ label: "鏈湀鏂板",
+ value: 0,
+ icon: "Calendar",
+ type: "info",
+ },
+]);
+
+const categoryChartRef = ref(null);
+const statusChartRef = ref(null);
+
+// 鍥捐〃瀹炰緥
+let categoryChart = null;
+let statusChart = null;
+
+// 鍔犺浇鐘舵��
+const loading = ref(false);
+const autoRefreshInterval = ref(null);
+
+// 鑷姩鍒锋柊寮�鍏�
+const autoRefreshEnabled = ref(true);
+
+// 鑷姩鍒锋柊闂撮殧锛�5鍒嗛挓锛�
+const AUTO_REFRESH_INTERVAL = 5 * 60 * 1000;
+
+// 鍚姩鑷姩鍒锋柊
+const startAutoRefresh = () => {
+ if (autoRefreshInterval.value) {
+ clearInterval(autoRefreshInterval.value);
+ }
+ if (autoRefreshEnabled.value) {
+ autoRefreshInterval.value = setInterval(() => {
+ refreshData();
+ }, AUTO_REFRESH_INTERVAL);
+ }
+};
+
+// 鍋滄鑷姩鍒锋柊
+const stopAutoRefresh = () => {
+ if (autoRefreshInterval.value) {
+ clearInterval(autoRefreshInterval.value);
+ autoRefreshInterval.value = null;
+ }
+};
+
+// 鍒囨崲鑷姩鍒锋柊鐘舵��
+const toggleAutoRefresh = (value) => {
+ if (value) {
+ startAutoRefresh();
+ } else {
+ stopAutoRefresh();
+ }
+};
+
+// 鍔犺浇鎬讳綋缁熻鏁版嵁
+const loadOverviewData = async () => {
+ try {
+ const response = await getDocumentationOverview();
+ if (response.code === 200) {
+ const data = response.data;
+ overviewData.value[0].value = data.totalDocsCount || 0;
+ overviewData.value[1].value = data.categoryNumCount || 0;
+ overviewData.value[2].value = data.borrowedDocsCount || 0;
+ overviewData.value[3].value = data.monthlyAddedDocsCount || 0;
+ }
+ } catch (error) {
+ console.error('鍔犺浇鎬讳綋缁熻鏁版嵁澶辫触:', error);
+ ElMessage.error('鍔犺浇鎬讳綋缁熻鏁版嵁澶辫触');
+ }
+};
+
+// 鍔犺浇鍒嗙被缁熻鏁版嵁
+const loadCategoryData = async () => {
+ try {
+ const response = await getDocumentationCategoryStats();
+ if (response.code === 200) {
+ renderCategoryChart(response.data);
+ }
+ } catch (error) {
+ console.error('鍔犺浇鍒嗙被缁熻鏁版嵁澶辫触:', error);
+ ElMessage.error('鍔犺浇鍒嗙被缁熻鏁版嵁澶辫触');
+ }
+};
+
+// 鍔犺浇鐘舵�佺粺璁℃暟鎹�
+const loadStatusData = async () => {
+ try {
+ const response = await getDocumentationStatusStats();
+ if (response.code === 200) {
+ renderStatusChart(response.data);
+ }
+ } catch (error) {
+ console.error('鍔犺浇鐘舵�佺粺璁℃暟鎹け璐�:', error);
+ ElMessage.error('鍔犺浇鐘舵�佺粺璁℃暟鎹け璐�');
+ }
+};
+
+// 鍒锋柊鏁版嵁
+const refreshData = async () => {
+ loading.value = true;
+ try {
+ await Promise.all([
+ loadOverviewData(),
+ loadCategoryData(),
+ loadStatusData()
+ ]);
+ ElMessage.success('鏁版嵁鍒锋柊鎴愬姛');
+ } catch (error) {
+ console.error('鍒锋柊鏁版嵁澶辫触:', error);
+ ElMessage.error('鍒锋柊鏁版嵁澶辫触');
+ } finally {
+ loading.value = false;
+ }
+};
+
+// 鍒濆鍖栧浘琛�
+const initCharts = () => {
+ // 寤惰繜鍒濆鍖栵紝纭繚DOM鍏冪礌宸茬粡娓叉煋
+ setTimeout(() => {
+ if (categoryChartRef.value) {
+ categoryChart = echarts.init(categoryChartRef.value);
+ }
+
+ if (statusChartRef.value) {
+ statusChart = echarts.init(statusChartRef.value);
+ }
+
+ // 鍒濆鍖栧畬鎴愬悗鍔犺浇鏁版嵁
+ loadCategoryData();
+ loadStatusData();
+ }, 300);
+};
+
+// 娓叉煋鍒嗙被缁熻鍥捐〃
+const renderCategoryChart = (data) => {
+ if (!categoryChart) return;
+ let newData = data.map(item => {
+ return {
+ name: item.category,
+ value: item.count
+ }
+ })
+
+ const option = {
+ title: {
+ text: "妗f鍒嗙被鍒嗗竷",
+ left: "center",
+ textStyle: {
+ fontSize: 16,
+ fontWeight: "normal",
+ },
+ },
+ tooltip: {
+ trigger: "item",
+ formatter: "{a} <br/>{b}: {c} ({d}%)",
+ },
+ legend: {
+ orient: "vertical",
+ left: "left",
+ top: "middle",
+ },
+ series: [
+ {
+ name: "妗f鏁伴噺",
+ type: "pie",
+ radius: ["40%", "70%"],
+ center: ["60%", "50%"],
+ data: newData || [
+ { name: "鎶�鏈枃妗�", value: 450 },
+ { name: "绠$悊鏂囨。", value: 320 },
+ { name: "璐㈠姟鏂囨。", value: 280 },
+ { name: "浜轰簨鏂囨。", value: 200 },
+ ],
+ emphasis: {
+ itemStyle: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: "rgba(0, 0, 0, 0.5)",
+ },
+ },
+ },
+ ],
+ };
+
+ try {
+ categoryChart.setOption(option);
+ } catch (error) {
+ console.error('鍒嗙被鍥捐〃娓叉煋澶辫触:', error);
+ }
+};
+
+// 娓叉煋鐘舵�佺粺璁″浘琛�
+const renderStatusChart = (data) => {
+ if (!statusChart) return;
+ let newData = data.map(item => {
+ return {
+ name: item.docStatus,
+ value: item.count
+ }
+ })
+ const option = {
+ title: {
+ text: "妗f鐘舵�佸垎甯�",
+ left: "center",
+ textStyle: {
+ fontSize: 16,
+ fontWeight: "normal",
+ },
+ },
+ tooltip: {
+ trigger: "item",
+ formatter: "{a} <br/>{b}: {c} ({d}%)",
+ },
+ legend: {
+ orient: "vertical",
+ left: "left",
+ top: "middle",
+ },
+ series: [
+ {
+ name: "妗f鏁伴噺",
+ type: "pie",
+ radius: ["40%", "70%"],
+ center: ["60%", "50%"],
+ roseType: false,
+ data: newData || [
+ { name: "姝e父", value: 1150, itemStyle: { color: "#67C23A" } },
+ { name: "鍊熷嚭", value: 89, itemStyle: { color: "#E6A23C" } },
+ { name: "涓㈠け", value: 8, itemStyle: { color: "#F56C6C" } },
+ { name: "鎹熷潖", value: 4, itemStyle: { color: "#909399" } },
+ ],
+ emphasis: {
+ itemStyle: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: "rgba(0, 0, 0, 0.5)",
+ },
+ },
+ },
+ ],
+ };
+
+ try {
+ statusChart.setOption(option);
+ } catch (error) {
+ console.error('鐘舵�佸浘琛ㄦ覆鏌撳け璐�:', error);
+ }
+};
+
+onMounted(() => {
+ loadOverviewData();
+ initCharts();
+ startAutoRefresh();
+});
+
+// 缁勪欢鍗歌浇鏃舵竻鐞嗗畾鏃跺櫒
+onUnmounted(() => {
+ stopAutoRefresh();
+});
+</script>
+
+<style scoped>
+.statistics-container {
+ padding: 20px;
+ background-color: #f5f7fa;
+ min-height: 100vh;
+}
+
+.page-header {
+ text-align: center;
+ margin-bottom: 30px;
+ padding: 20px;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ border-radius: 12px;
+ color: white;
+}
+
+.page-header h2 {
+ color: white;
+ margin-bottom: 10px;
+ font-size: 28px;
+ font-weight: 600;
+}
+
+.page-header p {
+ color: rgba(255, 255, 255, 0.9);
+ font-size: 14px;
+ margin: 0 0 15px 0;
+}
+
+.header-controls {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-top: 10px;
+ gap: 20px;
+}
+
+.refresh-btn {
+ margin-left: 20px;
+}
+
+.statistics-cards {
+ margin-bottom: 30px;
+}
+
+.statistics-card {
+ border-radius: 12px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ transition: all 0.3s ease;
+ border: none;
+ overflow: hidden;
+}
+
+.statistics-card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+}
+
+.statistics-card.primary {
+ border-left: 4px solid #409EFF;
+ background: linear-gradient(135deg, #409EFF 0%, #36a3f7 100%);
+}
+
+.statistics-card.success {
+ border-left: 4px solid #67C23A;
+ background: linear-gradient(135deg, #67C23A 0%, #85ce61 100%);
+}
+
+.statistics-card.warning {
+ border-left: 4px solid #E6A23C;
+ background: linear-gradient(135deg, #E6A23C 0%, #ebb563 100%);
+}
+
+.statistics-card.info {
+ border-left: 4px solid #909399;
+ background: linear-gradient(135deg, #909399 0%, #a6a9ad 100%);
+}
+
+.card-content {
+ display: flex;
+ align-items: center;
+ padding: 20px;
+}
+
+.card-icon {
+ margin-right: 20px;
+ color: white;
+}
+
+.card-info {
+ flex: 1;
+}
+
+.card-number {
+ font-size: 32px;
+ font-weight: 600;
+ color: white;
+ margin-bottom: 5px;
+}
+
+.card-label {
+ font-size: 14px;
+ color: rgba(255, 255, 255, 0.9);
+}
+
+.charts-section {
+ margin-bottom: 30px;
+}
+
+.chart-card {
+ border-radius: 12px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ border: none;
+}
+
+.card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-weight: 600;
+ color: #303133;
+ padding: 15px 20px;
+ border-bottom: 1px solid #ebeef5;
+}
+
+.chart-container {
+ height: 400px;
+ padding: 20px;
+}
+
+.chart {
+ width: 100%;
+ height: 100%;
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+ .statistics-container {
+ padding: 10px;
+ }
+
+ .page-header {
+ padding: 15px;
+ }
+
+ .page-header h2 {
+ font-size: 24px;
+ }
+
+ .header-controls {
+ flex-direction: column;
+ gap: 15px;
+ }
+
+ .refresh-btn {
+ margin-left: 0;
+ }
+
+ .statistics-cards .el-col {
+ margin-bottom: 15px;
+ }
+
+ .charts-section .el-col {
+ margin-bottom: 20px;
+ }
+
+ .chart-container {
+ height: 300px;
+ }
+}
+
+@media (max-width: 480px) {
+ .page-header h2 {
+ font-size: 20px;
+ }
+
+ .card-number {
+ font-size: 24px;
+ }
+
+ .chart-container {
+ height: 250px;
+ }
+}
+</style>
diff --git a/src/views/index.vue b/src/views/index.vue
index 5c23f5e..0e7fdcf 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -68,11 +68,11 @@
<li v-for="item in todoList" :key="item.id">
<div style="display: flex;flex-direction: column;justify-content: space-between;width: 100%;gap: 20px">
<div style="display: flex;justify-content: space-between;align-items: center;">
- <div class="todo-title">娴佺▼缂栧彿锛歿{item.approveId}}</div>
- <div class="todo-division">鐢宠閮ㄩ棬锛歿{item.approveDeptName}}</div>
+ <div class="todo-title">寰呭姙缂栧彿锛歿{item.approveId}}</div>
+ <div class="todo-division">閮ㄩ棬锛歿{item.approveDeptName}}</div>
<div class="todo-time">{{item.approveTime}}</div>
</div>
- <div class="todo-division">瀹℃壒浜嬬敱锛歿{item.approveReason}}</div>
+ <div class="todo-division">寰呭姙浜嬬敱锛歿{item.approveReason}}</div>
</div>
</li>
</ul>
diff --git a/src/views/inventoryManagement/dispatchLog/index.vue b/src/views/inventoryManagement/dispatchLog/index.vue
index 504074e..997fb15 100644
--- a/src/views/inventoryManagement/dispatchLog/index.vue
+++ b/src/views/inventoryManagement/dispatchLog/index.vue
@@ -19,6 +19,7 @@
<!-- <el-button type="primary" @click="openForm('add')">鏂板</el-button> -->
<el-button @click="handleOut">瀵煎嚭</el-button>
<el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+ <el-button type="primary" plain @click="handlePrint">鎵撳嵃</el-button>
</div>
</div>
<div class="table_list">
@@ -36,6 +37,12 @@
>
<el-table-column align="center" type="selection" width="55" />
<el-table-column align="center" label="搴忓彿" type="index" width="60" />
+ <el-table-column
+ label="鍑哄簱缂栧彿"
+ prop="code"
+ min-width="250"
+ show-overflow-tooltip
+ />
<el-table-column
label="鍑哄簱鏃ユ湡"
prop="createTime"
@@ -128,6 +135,120 @@
@pagination="paginationChange"
/>
</div>
+
+ <!-- 鎵撳嵃棰勮寮圭獥 -->
+ <el-dialog
+ v-model="printPreviewVisible"
+ title="鎵撳嵃棰勮"
+ width="90%"
+ :close-on-click-modal="false"
+ class="print-preview-dialog"
+ >
+ <div class="print-preview-container">
+ <div class="print-preview-header">
+ <el-button type="primary" @click="executePrint">鎵ц鎵撳嵃</el-button>
+ <el-button @click="printPreviewVisible = false">鍏抽棴棰勮</el-button>
+ </div>
+ <div class="print-preview-content">
+ <div v-if="printData.length === 0" style="text-align: center; padding: 50px; color: #999;">
+ 鏆傛棤鎵撳嵃鏁版嵁
+ </div>
+ <div v-else style="text-align: center; padding: 10px; color: #666; font-size: 14px; background: #e8f4fd; margin-bottom: 10px;">
+ 鍏� {{ printData.length }} 鏉℃暟鎹緟鎵撳嵃
+ </div>
+ <div v-for="(item, index) in printData" :key="index" class="print-page">
+ <div class="delivery-note">
+ <div class="header">
+ <div class="company-name">榧庤瘹鐟炲疄涓氭湁闄愯矗浠诲叕鍙�</div>
+ <div class="document-title">闆跺敭鍙戣揣鍗�</div>
+ </div>
+
+ <div class="info-section">
+ <div class="info-row">
+ <div>
+ <span class="label">鍙戣揣鏃ユ湡锛�</span>
+ <span class="value">{{ formatDate(item.createTime) }}</span>
+ </div>
+ <div>
+
+ <span class="label">瀹㈡埛鍚嶇О锛�</span>
+ <span class="value">{{ item.supplierName || '寮犵埍鏈�' }}</span>
+ </div>
+ </div>
+ <div class="info-row">
+ <span class="label">鍗曞彿锛�</span>
+ <span class="value">{{ item.code }}</span>
+ </div>
+ </div>
+
+ <div class="table-section">
+ <table class="product-table">
+ <thead>
+ <tr>
+ <th>浜у搧鍚嶇О</th>
+ <th>瑙勬牸鍨嬪彿</th>
+ <th>鍗曚綅</th>
+ <th>鍗曚环</th>
+ <th>闆跺敭鏁伴噺</th>
+ <th>闆跺敭閲戦</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>{{ item.productCategory || '鐮傜伆鐮�' }}</td>
+ <td>{{ item.specificationModel || '鏍囧噯' }}</td>
+ <td>{{ item.unit || '鍧�' }}</td>
+ <td>{{ item.taxInclusiveUnitPrice || '0' }}</td>
+ <td>{{ item.inboundNum || '2000' }}</td>
+ <td>{{ item.taxInclusiveTotalPrice || '0' }}</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td class="label">鍚堣</td>
+ <td class="total-value"></td>
+ <td class="total-value"></td>
+ <td class="total-value"></td>
+ <td class="total-value">{{ item.inboundNum || '2000' }}</td>
+ <td class="total-value">{{ item.taxInclusiveTotalPrice || '0' }}</td>
+ </tr>
+ </tfoot>
+ </table>
+ </div>
+
+ <div class="footer-section">
+ <div class="footer-row">
+ <div class="footer-item">
+ <span class="label">鏀惰揣鐢佃瘽锛�</span>
+ <span class="value"></span>
+ </div>
+ <div class="footer-item">
+ <span class="label">鏀惰揣浜猴細</span>
+ <span class="value"></span>
+ </div>
+ <div class="footer-item address-item">
+ <span class="label">鏀惰揣鍦板潃锛�</span>
+ <span class="value address-value"></span>
+ </div>
+ </div>
+ <div class="footer-row">
+ <div class="footer-item">
+ <span class="label">鎿嶄綔鍛橈細</span>
+ <span class="value">{{ userStore.nickname || '鎾曞紑鍓�' }}</span>
+ </div>
+ <div class="footer-item">
+ <span class="label">鎵撳嵃鏃ユ湡锛�</span>
+ <span class="value">{{ formatDateTime(new Date()) }}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </el-dialog>
+
+
</div>
</template>
@@ -136,7 +257,6 @@
import { ref } from "vue";
import { ElMessageBox } from "element-plus";
import useUserStore from "@/store/modules/user";
-import { userListNoPage } from "@/api/system/user.js";
import {
getStockOutPage,
delStockOut,
@@ -146,19 +266,18 @@
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const selectedRows = ref([]);
-const userList = ref([]);
const tableLoading = ref(false);
-const productList = ref([])
const page = reactive({
current: 1,
size: 100,
});
const total = ref(0);
-const fileList = ref([]);
+
+// 鎵撳嵃鐩稿叧
+const printPreviewVisible = ref(false);
+const printData = ref([]);
// 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
-const operationType = ref("");
-const dialogFormVisible = ref(false);
const data = reactive({
searchForm: {
supplierName: "",
@@ -268,6 +387,296 @@
proxy.$modal.msg("宸插彇娑�");
});
};
+
+// 鎵撳嵃鍔熻兘
+const handlePrint = () => {
+ if (selectedRows.value.length === 0) {
+ proxy.$modal.msgWarning("璇烽�夋嫨瑕佹墦鍗扮殑鏁版嵁");
+ return;
+ }
+ printData.value = [...selectedRows.value];
+ console.log('鎵撳嵃鏁版嵁:', printData.value);
+ printPreviewVisible.value = true;
+};
+
+// 鎵ц鎵撳嵃
+const executePrint = () => {
+ console.log('寮�濮嬫墽琛屾墦鍗帮紝鏁版嵁鏉℃暟:', printData.value.length);
+ console.log('鎵撳嵃鏁版嵁:', printData.value);
+
+ // 鍒涘缓涓�涓柊鐨勬墦鍗扮獥鍙�
+ const printWindow = window.open('', '_blank', 'width=800,height=600');
+
+ // 鏋勫缓鎵撳嵃鍐呭
+ let printContent = `
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="UTF-8">
+ <title>鎵撳嵃棰勮</title>
+ <style>
+ body {
+ margin: 0;
+ padding: 0;
+ font-family: "SimSun", serif;
+ background: white;
+ }
+ .print-page {
+ width: 200mm;
+ height: 75mm;
+ padding: 10mm;
+ padding-left: 20mm;
+ background: white;
+ box-sizing: border-box;
+ page-break-after: always;
+ page-break-inside: avoid;
+ }
+ .print-page:last-child {
+ page-break-after: avoid;
+ }
+ .delivery-note {
+ width: 100%;
+ height: 100%;
+ font-size: 12px;
+ line-height: 1.2;
+ display: flex;
+ flex-direction: column;
+ color: #000;
+ }
+ .header {
+ text-align: center;
+ margin-bottom: 8px;
+ }
+ .company-name {
+ font-size: 18px;
+ font-weight: bold;
+ margin-bottom: 4px;
+ }
+ .document-title {
+ font-size: 16px;
+ font-weight: bold;
+ }
+ .info-section {
+ margin-bottom: 8px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+ .info-row {
+ line-height: 20px;
+ }
+ .label {
+ font-weight: bold;
+ width: 60px;
+ font-size: 12px;
+ }
+ .value {
+ margin-right: 20px;
+ min-width: 80px;
+ font-size: 12px;
+ }
+ .table-section {
+ margin-bottom: 40px;
+ // flex: 0.6;
+ }
+ .product-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #000;
+ }
+ .product-table th, .product-table td {
+ border: 1px solid #000;
+ padding: 6px;
+ text-align: center;
+ font-size: 12px;
+ line-height: 1.4;
+ }
+ .product-table th {
+ font-weight: bold;
+ }
+ .total-value {
+ font-weight: bold;
+ }
+ .footer-section {
+ margin-top: auto;
+ }
+ .footer-row {
+ display: flex;
+ margin-bottom: 3px;
+ line-height: 22px;
+ justify-content: space-between;
+ }
+ .footer-item {
+ display: flex;
+ margin-right: 20px;
+ }
+ .footer-item .label {
+ font-weight: bold;
+ width: 80px;
+ font-size: 12px;
+ }
+ .footer-item .value {
+ min-width: 80px;
+ font-size: 12px;
+ }
+ .address-item .address-value {
+ min-width: 200px;
+ }
+ @media print {
+ body {
+ margin: 0;
+ padding: 0;
+ }
+ .print-page {
+ margin: 0;
+ padding: 10mm;
+ /* padding-left: 20mm; */
+ page-break-inside: avoid;
+ page-break-after: always;
+ }
+ .print-page:last-child {
+ page-break-after: avoid;
+ }
+ }
+ </style>
+ </head>
+ <body>
+ `;
+
+ // 涓烘瘡鏉℃暟鎹敓鎴愭墦鍗伴〉闈�
+ printData.value.forEach((item, index) => {
+ printContent += `
+ <div class="print-page">
+ <div class="delivery-note">
+ <div class="header">
+ <div class="company-name">榧庤瘹鐟炲疄涓氭湁闄愯矗浠诲叕鍙�</div>
+ <div class="document-title">闆跺敭鍙戣揣鍗�</div>
+ </div>
+
+ <div class="info-section">
+ <div class="info-row">
+ <div>
+ <span class="label">鍙戣揣鏃ユ湡锛�</span>
+ <span class="value">${formatDate(item.createTime)}</span>
+ </div>
+ <div>
+ <span class="label">瀹㈡埛鍚嶇О锛�</span>
+ <span class="value">${item.supplierName || '寮犵埍鏈�'}</span>
+ </div>
+ </div>
+ <div class="info-row">
+ <span class="label">鍗曞彿锛�</span>
+ <span class="value">${item.code || ''}</span>
+ </div>
+ </div>
+
+ <div class="table-section">
+ <table class="product-table">
+ <thead>
+ <tr>
+ <th>浜у搧鍚嶇О</th>
+ <th>瑙勬牸鍨嬪彿</th>
+ <th>鍗曚綅</th>
+ <th>鍗曚环</th>
+ <th>闆跺敭鏁伴噺</th>
+ <th>闆跺敭閲戦</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>${item.productCategory || '鐮傜伆鐮�'}</td>
+ <td>${item.specificationModel || '鏍囧噯'}</td>
+ <td>${item.unit || '鍧�'}</td>
+ <td>${item.taxInclusiveUnitPrice || '0'}</td>
+ <td>${item.inboundNum || '2000'}</td>
+ <td>${item.taxInclusiveTotalPrice || '0'}</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td class="label">鍚堣</td>
+ <td class="total-value"></td>
+ <td class="total-value"></td>
+ <td class="total-value"></td>
+ <td class="total-value">${item.inboundNum || '2000'}</td>
+ <td class="total-value">${item.taxInclusiveTotalPrice || '0'}</td>
+ </tr>
+ </tfoot>
+ </table>
+ </div>
+
+ <div class="footer-section">
+ <div class="footer-row">
+ <div class="footer-item">
+ <span class="label">鏀惰揣鐢佃瘽锛�</span>
+ <span class="value"></span>
+ </div>
+ <div class="footer-item">
+ <span class="label">鏀惰揣浜猴細</span>
+ <span class="value"></span>
+ </div>
+ <div class="footer-item address-item">
+ <span class="label">鏀惰揣鍦板潃锛�</span>
+ <span class="value address-value"></span>
+ </div>
+ </div>
+ <div class="footer-row">
+ <div class="footer-item">
+ <span class="label">鎿嶄綔鍛橈細</span>
+ <span class="value">${userStore.nickname || '鎾曞紑鍓�'}</span>
+ </div>
+ <div class="footer-item">
+ <span class="label">鎵撳嵃鏃ユ湡锛�</span>
+ <span class="value">${formatDateTime(new Date())}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ `;
+ });
+
+ printContent += `
+ </body>
+ </html>
+ `;
+
+ // 鍐欏叆鍐呭鍒版柊绐楀彛
+ printWindow.document.write(printContent);
+ printWindow.document.close();
+
+ // 绛夊緟鍐呭鍔犺浇瀹屾垚鍚庢墦鍗�
+ printWindow.onload = () => {
+ setTimeout(() => {
+ printWindow.print();
+ printWindow.close();
+ printPreviewVisible.value = false;
+ }, 500);
+ };
+};
+
+
+
+// 鏍煎紡鍖栨棩鏈�
+const formatDate = (dateString) => {
+ if (!dateString) return getCurrentDate();
+ const date = new Date(dateString);
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, "0");
+ const day = String(date.getDate()).padStart(2, "0");
+ return `${year}/${month}/${day}`;
+};
+
+// 鏍煎紡鍖栨棩鏈熸椂闂�
+const formatDateTime = (date) => {
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, "0");
+ const day = String(date.getDate()).padStart(2, "0");
+ const hours = String(date.getHours()).padStart(2, "0");
+ const minutes = String(date.getMinutes()).padStart(2, "0");
+ const seconds = String(date.getSeconds()).padStart(2, "0");
+ return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
+};
// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
function getCurrentDate() {
const today = new Date();
@@ -281,4 +690,171 @@
});
</script>
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.print-preview-dialog {
+ .el-dialog__body {
+ padding: 0;
+ max-height: 80vh;
+ overflow-y: auto;
+ }
+}
+
+.print-preview-container {
+ .print-preview-header {
+ padding: 15px;
+ border-bottom: 1px solid #e4e7ed;
+ text-align: center;
+
+ .el-button {
+ margin: 0 10px;
+ }
+ }
+
+ .print-preview-content {
+ padding: 20px;
+ background-color: #f5f5f5;
+ min-height: 400px;
+}
+}
+
+.print-page {
+ width: 220mm;
+ height: 90mm;
+ padding: 10mm;
+ margin: 0 auto;
+ background: white;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+ margin-bottom: 10px;
+ box-sizing: border-box;
+}
+
+.delivery-note {
+ width: 100%;
+ height: 100%;
+ font-family: "SimSun", serif;
+ font-size: 10px;
+ line-height: 1.2;
+ display: flex;
+ flex-direction: column;
+}
+
+.header {
+ text-align: center;
+ margin-bottom: 8px;
+
+ .company-name {
+ font-size: 18px;
+ font-weight: bold;
+ margin-bottom: 4px;
+ }
+
+ .document-title {
+ font-size: 16px;
+ font-weight: bold;
+ }
+}
+
+.info-section {
+ margin-bottom: 8px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .info-row {
+ line-height: 20px;
+
+ .label {
+ font-weight: bold;
+ width: 60px;
+ font-size: 14px;
+ }
+
+ .value {
+ margin-right: 20px;
+ min-width: 80px;
+ font-size: 14px;
+ }
+ }
+}
+
+.table-section {
+ margin-bottom: 4px;
+ flex: 1;
+
+ .product-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #000;
+
+ th, td {
+ border: 1px solid #000;
+ padding: 6px;
+ text-align: center;
+ font-size: 14px;
+ line-height: 1.4;
+ }
+
+ th {
+ font-weight: bold;
+ }
+
+ .total-label {
+ text-align: right;
+ font-weight: bold;
+ }
+
+ .total-value {
+ font-weight: bold;
+ }
+ }
+}
+
+.footer-section {
+ .footer-row {
+ display: flex;
+ margin-bottom: 3px;
+ line-height: 20px;
+ justify-content: space-between;
+
+ .footer-item {
+ display: flex;
+ margin-right: 20px;
+
+ .label {
+ font-weight: bold;
+ width: 80px;
+ font-size: 14px;
+ }
+
+ .value {
+ min-width: 80px;
+ font-size: 14px;
+ }
+
+ &.address-item {
+ .address-value {
+ min-width: 200px;
+ }
+ }
+ }
+ }
+}
+
+@media print {
+ .app-container {
+ display: none;
+ }
+
+ .print-page {
+ box-shadow: none;
+ margin: 0;
+ padding: 10mm;
+ padding-left: 20mm;
+ page-break-inside: avoid;
+ page-break-after: always;
+ }
+ .print-page:last-child {
+ page-break-after: avoid;
+ }
+}
+</style>
diff --git a/src/views/inventoryManagement/issueManagement/index.vue b/src/views/inventoryManagement/issueManagement/index.vue
index 4240bef..7a1363c 100644
--- a/src/views/inventoryManagement/issueManagement/index.vue
+++ b/src/views/inventoryManagement/issueManagement/index.vue
@@ -196,7 +196,7 @@
// 鎻愪氦琛ㄥ崟
const submitForm = () => {
let num = Number(form.value.inboundQuantity)
- if(num < 1 || num > currentRowNum.value){
+ if(num <= 0 || num > currentRowNum.value){
return proxy.$modal.msgWarning("璇峰~鍏ユ湁鏁堟暟瀛�")
}
proxy.$refs["formRef"].validate(valid => {
diff --git a/src/views/lavorissue/ledger/Form.vue b/src/views/lavorissue/ledger/Form.vue
new file mode 100644
index 0000000..7031957
--- /dev/null
+++ b/src/views/lavorissue/ledger/Form.vue
@@ -0,0 +1,154 @@
+<template>
+ <el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
+ <el-form-item label="閮ㄩ棬鍚嶇О" prop="deptId">
+ <el-select
+ v-model="form.deptId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ disabled
+ >
+ <el-option :label="item.deptName" :value="item.deptId" v-for="(item,index) in productOptions" :key="deptId" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鍛樺伐鍚嶇О" prop="staffId">
+ <el-select
+ v-model="form.staffId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ >
+ <el-option :label="item.staffName" :value="item.id" v-for="(item,index) in personList" :key="id" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鍔充繚绫诲瀷" prop="dictType">
+ <el-select
+ v-model="form.dictType"
+ placeholder="璇烽�夋嫨"
+ clearable
+ >
+ <el-option :label="item.label" :value="item.value" v-for="(item,index) in sys_lavor_issue_type" :key="value" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鍔充繚闃插叿" prop="dictId">
+ <el-select
+ v-model="form.dictId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ >
+ <el-option :label="item.label" :value="item.value" v-for="(item,index) in sys_lavor_issue" :key="value" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鍙戞斁鏁伴噺" prop="num">
+ <el-input-number :step="1" :min="0" style="width: 100%"
+ v-model="form.num"
+ placeholder="璇疯緭鍏�"
+ />
+ </el-form-item>
+ <el-form-item label="杩涘巶鏃ユ湡" prop="factoryDate">
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.factoryDate"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨鏃ユ湡"
+ clearable
+ />
+ </el-form-item>
+ <el-form-item label="鍙戞斁鏃ユ湡" prop="issueDate">
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.issueDate"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨鏃ユ湡"
+ clearable
+ />
+ </el-form-item>
+
+ </el-form>
+</template>
+
+<script setup>
+import useFormData from "@/hooks/useFormData";
+import {ref,onMounted} from "vue";
+import useUserStore from "@/store/modules/user";
+import {getStaffOnJob} from "@/api/personnelManagement/onboarding.js";
+import {deepCopySameProperties} from '@/utils/util'
+const userStore = useUserStore();
+import {
+ getDept
+} from "@/api/collaborativeApproval/approvalProcess.js";
+const { proxy } = getCurrentInstance();
+
+
+defineOptions({
+ name: "鏂板鏀跺叆",
+});
+const { sys_lavor_issue } = proxy.useDict("sys_lavor_issue")
+const { sys_lavor_issue_type } = proxy.useDict("sys_lavor_issue_type")
+const formRef = ref(null);
+const productOptions = ref([]);
+const personList = ref([]);
+const formRules = {
+ deptId: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+ dictType: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+ staffId: [{ required: true, trigger: "blur", message: "璇疯緭鍏�" }],
+ dictId: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+ num: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+ adoptedDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+ factoryDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+ issueDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨" }],
+}
+
+const { form, resetForm } = useFormData({
+ deptId: undefined, //
+ dictType: undefined,
+ staffId: undefined, //
+ dictId: undefined, //
+ num: undefined, //
+ adoptedDate: undefined,
+ factoryDate: undefined,
+ issueDate: undefined,
+});
+const getPersonList = () => {
+ getStaffOnJob().then(res => {
+ personList.value = res.data
+ })
+};
+const loadForm = (data) => {
+ deepCopySameProperties(data, form)
+};
+
+const getProductOptions = () => {
+ getDept().then((res) => {
+ productOptions.value = res.data;
+ });
+}
+// 娓呴櫎琛ㄥ崟鏍¢獙鐘舵��
+const clearValidate = () => {
+ formRef.value?.clearValidate();
+};
+
+// 閲嶇疆琛ㄥ崟鏁版嵁鍜屾牎楠岀姸鎬�
+const resetFormAndValidate = () => {
+ resetForm();
+ clearValidate();
+ form.deptId = userStore.currentDeptId
+ getProductOptions();
+ getPersonList();
+};
+onMounted(() => {
+ form.deptId = userStore.currentDeptId
+ getProductOptions();
+ getPersonList();
+})
+defineExpose({
+ form,
+ resetForm,
+ clearValidate,
+ loadForm,
+ resetFormAndValidate,
+ formRef,
+});
+</script>
diff --git a/src/views/lavorissue/ledger/Modal.vue b/src/views/lavorissue/ledger/Modal.vue
new file mode 100644
index 0000000..5d63236
--- /dev/null
+++ b/src/views/lavorissue/ledger/Modal.vue
@@ -0,0 +1,70 @@
+<template>
+ <el-dialog :title="modalOptions.title" v-model="visible" @close="close" width="30%">
+ <Form ref="formRef"></Form>
+ <template #footer>
+ <el-button type="primary" @click="sendForm" :loading="loading">
+ {{ modalOptions.confirmText }}
+ </el-button>
+ <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
+ </template>
+ </el-dialog>
+</template>
+
+<script setup>
+import { useModal } from "@/hooks/useModal";
+import { add, update } from "@/api/lavorissce/ledger";
+import Form from "./Form.vue";
+import { ElMessage } from "element-plus";
+const { proxy } = getCurrentInstance()
+
+defineOptions({
+ name: "鏀跺叆鏂板缂栬緫",
+});
+
+const emits = defineEmits(["success"]);
+
+const formRef = ref();
+const {
+ id,
+ visible,
+ loading,
+ openModal,
+ modalOptions,
+ handleConfirm,
+ closeModal,
+} = useModal({ title: "鍔充繚鍙拌处" });
+
+const sendForm = () => {
+ proxy.$refs.formRef.$refs.formRef.validate(async valid => {
+ if (valid) {
+ const {code} = id.value
+ ? await update({id: id.value, ...formRef.value.form})
+ : await add(formRef.value.form);
+ if (code == 200) {
+ emits("success");
+ ElMessage({message: "鎿嶄綔鎴愬姛", type: "success"});
+ close();
+ } else {
+ loading.value = false;
+ }
+ }
+ })
+};
+
+const close = () => {
+ formRef.value.resetFormAndValidate();
+ closeModal();
+};
+
+const loadForm = async (row) => {
+ openModal(row.id);
+ await nextTick();
+ formRef.value.loadForm(row);
+
+};
+
+defineExpose({
+ openModal,
+ loadForm,
+});
+</script>
diff --git a/src/views/lavorissue/ledger/filesDia.vue b/src/views/lavorissue/ledger/filesDia.vue
new file mode 100644
index 0000000..f752496
--- /dev/null
+++ b/src/views/lavorissue/ledger/filesDia.vue
@@ -0,0 +1,202 @@
+<template>
+ <div>
+ <el-dialog
+ v-model="dialogFormVisible"
+ title="涓婁紶闄勪欢"
+ width="50%"
+ @close="closeDia"
+ >
+ <div style="margin-bottom: 10px;text-align: right">
+ <el-upload
+ v-model:file-list="fileList"
+ class="upload-demo"
+ :action="uploadUrl"
+ :on-success="handleUploadSuccess"
+ :on-error="handleUploadError"
+ name="file"
+ :show-file-list="false"
+ :headers="headers"
+ style="display: inline;margin-right: 10px"
+ >
+ <el-button type="primary">涓婁紶闄勪欢</el-button>
+ </el-upload>
+ <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+ </div>
+ <PIMTable
+ rowKey="id"
+ :column="tableColumn"
+ :tableData="tableData"
+ :tableLoading="tableLoading"
+ :isSelection="true"
+ @selection-change="handleSelectionChange"
+ height="500"
+ >
+ </PIMTable>
+ <pagination
+ style="margin: 10px 0"
+ v-show="total > 0"
+ @pagination="paginationSearch"
+ :total="total"
+ :page="page.current"
+ :limit="page.size"
+ />
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button @click="closeDia">鍙栨秷</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ <filePreview ref="filePreviewRef" />
+ </div>
+</template>
+
+<script setup>
+import {ref} from "vue";
+import {ElMessageBox} from "element-plus";
+import {getToken} from "@/utils/auth.js";
+import filePreview from '@/components/filePreview/index.vue'
+import {
+ fileAdd,
+ fileDel,
+ fileListPage
+} from "@/api/financialManagement/revenueManagement.js";
+import Pagination from "@/components/PIMTable/Pagination.vue";
+const { proxy } = getCurrentInstance()
+const emit = defineEmits(['close'])
+
+const dialogFormVisible = ref(false);
+const currentId = ref('')
+const selectedRows = ref([]);
+const filePreviewRef = ref()
+const tableColumn = ref([
+ {
+ label: "鏂囦欢鍚嶇О",
+ prop: "name",
+ },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ operation: [
+ {
+ name: "涓嬭浇",
+ type: "text",
+ clickFun: (row) => {
+ downLoadFile(row);
+ },
+ },
+ {
+ name: "棰勮",
+ type: "text",
+ clickFun: (row) => {
+ lookFile(row);
+ },
+ }
+ ],
+ },
+]);
+const page = reactive({
+ current: 1,
+ size: 100,
+});
+const total = ref(0);
+const tableData = ref([]);
+const fileList = ref([]);
+const tableLoading = ref(false);
+const accountType = ref('')
+const headers = ref({
+ Authorization: "Bearer " + getToken(),
+});
+const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃
+
+// 鎵撳紑寮规
+const openDialog = (row,type) => {
+ accountType.value = type;
+ dialogFormVisible.value = true;
+ currentId.value = row.id;
+ getList()
+}
+const paginationSearch = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+};
+const getList = () => {
+ fileListPage({accountId: currentId.value,accountType:accountType.value, ...page}).then(res => {
+ tableData.value = res.data.records;
+ total.value = res.data.total;
+ })
+}
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+
+// 鍏抽棴寮规
+const closeDia = () => {
+ dialogFormVisible.value = false;
+ emit('close')
+};
+// 涓婁紶鎴愬姛澶勭悊
+function handleUploadSuccess(res, file) {
+ // 濡傛灉涓婁紶鎴愬姛
+ if (res.code == 200) {
+ const fileRow = {}
+ fileRow.name = res.data.originalName
+ fileRow.url = res.data.tempPath
+ uploadFile(fileRow)
+ } else {
+ proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+ }
+}
+function uploadFile(file) {
+ file.accountId = currentId.value;
+ file.accountType = accountType.value;
+ fileAdd(file).then(res => {
+ proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+ getList()
+ })
+}
+// 涓婁紶澶辫触澶勭悊
+function handleUploadError() {
+ proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+}
+// 涓嬭浇闄勪欢
+const downLoadFile = (row) => {
+ proxy.$download.name(row.url);
+}
+// 鍒犻櫎
+const handleDelete = () => {
+ let ids = [];
+ if (selectedRows.value.length > 0) {
+ ids = selectedRows.value.map((item) => item.id);
+ } else {
+ proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+ return;
+ }
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }).then(() => {
+ fileDel(ids).then((res) => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ getList();
+ });
+ }).catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+// 棰勮闄勪欢
+const lookFile = (row) => {
+ filePreviewRef.value.open(row.url)
+}
+
+defineExpose({
+ openDialog,
+});
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/lavorissue/ledger/index.vue b/src/views/lavorissue/ledger/index.vue
new file mode 100644
index 0000000..6b7e5a8
--- /dev/null
+++ b/src/views/lavorissue/ledger/index.vue
@@ -0,0 +1,300 @@
+<template>
+ <div class="app-container">
+ <el-form :model="filters" :inline="true">
+ <el-form-item label="鍙戞斁瀛e害:" prop="season">
+ <el-select
+ style="width: 200px;"
+ @change="handleQuery"
+ v-model="filters.season"
+ placeholder="璇烽�夋嫨"
+ :clearable="false"
+ >
+ <el-option :label="item.label" :value="item.value" v-for="(item,index) in jidu" :key="value" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鍛樺伐鍚嶇О:">
+ <el-input
+ v-model="filters.staffName"
+ style="width: 240px"
+ placeholder="璇疯緭鍏�"
+ @change="handleQuery"
+ clearable
+ prefix-icon="Search"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+ <el-button @click="resetFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ <div class="table_list">
+ <div class="actions">
+ <div></div>
+ <div>
+ <el-button type="primary" @click="add" icon="Plus"> 鏂板 </el-button>
+<!-- <el-button @click="handleOut" icon="download">瀵煎嚭</el-button>-->
+ <el-button
+ type="danger"
+ icon="Delete"
+ :disabled="multipleList.length <= 0"
+ @click="deleteRow(multipleList.map((item) => item.id))"
+ >
+ 鎵归噺鍒犻櫎
+ </el-button>
+ </div>
+ </div>
+ <PIMTable
+ rowKey="id"
+ isSelection
+ :column="columns"
+ :tableData="dataList"
+ :page="{
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ total: pagination.total,
+ }"
+ @selection-change="handleSelectionChange"
+ @pagination="changePage"
+ >
+ <template #operation="{ row }">
+ <el-button type="primary" text @click="edit(row)" icon="editPen">
+ 缂栬緫
+ </el-button>
+ <el-button type="primary" :disabled="row.adoptedDate ? true : false" text @click="adopted(row)">
+ 棰嗙敤
+ </el-button>
+ </template>
+ </PIMTable>
+ </div>
+ <Modal ref="modalRef" @success="getTableData"></Modal>
+ <files-dia ref="filesDia"></files-dia>
+ </div>
+</template>
+
+<script setup>
+import { usePaginationApi } from "@/hooks/usePaginationApi";
+import { listPage,deleteLedger,update } from "@/api/lavorissce/ledger";
+import { onMounted, getCurrentInstance } from "vue";
+import Modal from "./Modal.vue";
+import { ElMessageBox, ElMessage } from "element-plus";
+import dayjs from "dayjs";
+import FilesDia from "./filesDia.vue";
+import { getCurrentMonth } from "@/utils/util"
+
+// 琛ㄦ牸澶氶�夋閫変腑椤�
+const multipleList = ref([]);
+const { proxy } = getCurrentInstance();
+const modalRef = ref();
+const { payment_methods } = proxy.useDict("payment_methods");
+const { income_types } = proxy.useDict("income_types");
+const filesDia = ref()
+
+const {
+ filters,
+ columns,
+ dataList,
+ pagination,
+ getTableData,
+ resetFilters,
+ onCurrentChange,
+} = usePaginationApi(
+ listPage,
+ {
+ staffName: '',
+ season: getCurrentMonth(),
+ },
+ [
+ {
+ label: "鍔充繚鍗曞彿",
+ align: "center",
+ prop: "orderNo",
+ },
+ {
+ label: "鍛樺伐鍚嶇О",
+ align: "center",
+ prop: "staffName",
+ },
+ {
+ label: "鍛樺伐缂栧彿",
+ align: "center",
+ prop: "staffNo"
+ },
+
+ {
+ label: "鍔充繚绫诲瀷",
+ align: "center",
+ prop: "dictTypeName",
+
+ },
+ {
+ label: "鍔充繚闃插叿",
+ align: "center",
+ prop: "dictName",
+
+ },
+ {
+ label: "鍙戞斁鏁伴噺",
+ align: "center",
+ prop: "num",
+
+ },
+ {
+ label: "杩涘巶鏃ユ湡",
+ align: "center",
+ prop: "factoryDate",
+
+ },
+ {
+ label: "鍙戞斁鏃ユ湡",
+ align: "center",
+ prop: "issueDate",
+
+ },
+ {
+ label: "棰嗙敤鏃ユ湡",
+ align: "center",
+ prop: "adoptedDate",
+
+ },
+ {
+ fixed: "right",
+ label: "鎿嶄綔",
+ dataType: "slot",
+ slot: "operation",
+ align: "center",
+ width: "200px",
+ },
+ ]
+);
+
+const jidu = ref([
+ {
+ value: '1',
+ label: '绗竴瀛e害'
+ },
+ {
+ value: '2',
+ label: '绗簩瀛e害'
+ },
+ {
+ value: '3',
+ label: '绗笁瀛e害'
+ },
+ {
+ value: '4',
+ label: '绗洓瀛e害'
+ }
+])
+
+// 澶氶�夊悗鍋氫粈涔�
+const handleSelectionChange = (selectionList) => {
+ multipleList.value = selectionList;
+};
+
+const adopted = (row) => {
+ ElMessageBox.confirm("鏄惁纭棰嗙敤?", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }).then(async () => {
+ const params = {
+ id: row.id,
+ adoptedDate: dayjs().format("YYYY-MM-DD")
+ }
+ const { code } = await update(params);
+ if (code == 200) {
+ ElMessage({
+ type: "success",
+ message: "棰嗙敤鎴愬姛",
+ });
+ getTableData();
+ }
+ })
+}
+
+const add = () => {
+ modalRef.value.openModal();
+};
+const edit = (row) => {
+ modalRef.value.loadForm(row);
+};
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+ getTableData();
+};
+const changePage = ({ page, limit }) => {
+ pagination.currentPage = page;
+ pagination.pageSize = limit;
+ onCurrentChange(page);
+};
+const deleteRow = (id) => {
+ ElMessageBox.confirm("姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ暟鎹�, 鏄惁缁х画?", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }).then(async () => {
+ const { code } = await deleteLedger(id);
+ if (code == 200) {
+ ElMessage({
+ type: "success",
+ message: "鍒犻櫎鎴愬姛",
+ });
+ getTableData();
+ }
+ });
+};
+
+const changeDaterange = (value) => {
+ if (value) {
+ filters.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
+ filters.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
+ } else {
+ filters.entryDateStart = undefined;
+ filters.entryDateEnd = undefined;
+ }
+ getTableData();
+};
+
+const handleOut = () => {
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ proxy.download(`/lavorIssue/exportCopy`, {season: filters.season}, "鍔充繚鍙拌处.xlsx");
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+// 鎵撳紑闄勪欢寮规
+const openFilesFormDia = (row) => {
+ nextTick(() => {
+ filesDia.value?.openDialog( row,'鏀跺叆')
+ })
+};
+
+onMounted(() => {
+ filters.entryDate = [
+ dayjs().format("YYYY-MM-DD"),
+ dayjs().add(1, "day").format("YYYY-MM-DD"),
+ ]
+ filters.entryDateStart = dayjs().format("YYYY-MM-DD")
+ filters.entryDateEnd = dayjs().add(1, "day").format("YYYY-MM-DD")
+ getTableData();
+});
+</script>
+
+<style lang="scss" scoped>
+.table_list {
+ margin-top: unset;
+}
+.actions {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+}
+</style>
+
diff --git a/src/views/lavorissue/statistics/index.vue b/src/views/lavorissue/statistics/index.vue
new file mode 100644
index 0000000..2c34f67
--- /dev/null
+++ b/src/views/lavorissue/statistics/index.vue
@@ -0,0 +1,285 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <div>
+ <span class="search_title">鍙戞斁瀛e害锛�</span>
+ <el-select
+ style="width: 200px;"
+ @change="handleQuery"
+ v-model="searchForm.season"
+ placeholder="璇烽�夋嫨"
+ @clear="clearSeason"
+ clearable
+ :disabled="searchForm.issueDate ? true : false"
+
+ >
+ <el-option :label="item.label" :value="item.value" v-for="(item,index) in jidu" :key="item.value" />
+ </el-select>
+ <span class="search_title ml10">鍙戞斁鏈堜唤锛�</span>
+ <el-date-picker
+ style="width: 200px;"
+ :disabled="searchForm.season ? true : false"
+ v-model="searchForm.issueDate"
+ @change="handleQuery"
+ @clear="clearIssueDaten"
+ type="month"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM"
+ placeholder="璇烽�夋嫨鏈堜唤"
+ clearable
+ />
+ <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+ >鎼滅储</el-button
+ >
+ <el-button type="primary" @click="resetHandleQuery" style="margin-left: 10px"
+ >閲嶇疆</el-button
+ >
+ </div>
+ <div>
+ <el-button @click="handleOut" icon="download">瀵煎嚭</el-button>
+ </div>
+ </div>
+ <div class="table_list">
+ <div class="actions">
+ <div class="head" @click="handleQuery(1)">宸查鍙栧姵淇濇暟閲�:{{statisticsObj.ylqNum}}</div>
+ <div class="head" @click="handleQuery(2)">鏈鍙栧姵淇濇暟閲�: {{ statisticsObj.wlqNum }}</div>
+ <div class="head" @click="handleQuery(3)">瓒呮椂宸查鍙栧姵淇濇暟閲�: {{statisticsObj.csylqNum}}</div>
+ <div class="head" @click="handleQuery(4)">瓒呮椂鏈鍙栧姵淇濇暟閲�: {{statisticsObj.cswlqNum}}</div>
+ </div>
+ <el-table
+ ref="tableRef"
+ v-loading="tableLoading"
+ :data="tableData"
+ border
+ height="calc(100vh - 21em)"
+ :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+ style="width: 100%"
+ @selection-change="handleSelectionChange"
+ >
+ <!-- 閫夋嫨鍒� -->
+ <el-table-column
+ align="center"
+ type="selection"
+ width="55"
+ fixed="left"
+ />
+
+ <!-- 搴忓彿鍒� -->
+ <el-table-column
+ align="center"
+ label="搴忓彿"
+ type="index"
+ width="60"
+ fixed="left"
+ />
+
+ <!-- 鍥哄畾鍒楋細濮撳悕 -->
+ <el-table-column
+ label="濮撳悕"
+ prop="staffName"
+ width="100"
+ show-overflow-tooltip
+ align="center"
+ fixed="left"
+ />
+
+ <!-- 鍥哄畾鍒楋細宸ュ彿 -->
+ <el-table-column
+ label="宸ュ彿"
+ prop="staffNo"
+ width="100"
+ show-overflow-tooltip
+ align="center"
+ fixed="left"
+ />
+
+ <!-- 鍔ㄦ�佸垪锛氭牴鎹瓧鍏告覆鏌� -->
+ <el-table-column
+ v-for="(dictItem, index) in sys_lavor_issue"
+ :key="dictItem.value"
+ :label="dictItem.label"
+ :prop="dictItem.value"
+ show-overflow-tooltip
+ >
+ </el-table-column>
+ </el-table>
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { ref, onMounted, reactive, toRefs, nextTick, getCurrentInstance } from 'vue'
+import dayjs from "dayjs";
+import {statisticsList, statistics} from "@/api/lavorissce/ledger.js";
+import {ElMessageBox, ElMessage} from "element-plus";
+const { proxy } = getCurrentInstance();
+import { getCurrentMonth } from "@/utils/util"
+
+const page = ref({
+ current: 1,
+ size: 100,
+})
+const total = ref(0)
+// 鍝嶅簲寮忔暟鎹�
+const tableRef = ref(null)
+const tableData = ref([])
+const tableLoading = ref(false)
+const { sys_lavor_issue } = proxy.useDict("sys_lavor_issue")
+const data = reactive({
+ searchForm: {
+ season: getCurrentMonth(),
+ issueDate: "",
+ status: 0
+ },
+});
+const { searchForm } = toRefs(data);
+
+const modalRef = ref();
+const filesDia = ref();
+const multipleList = ref([]);
+const jidu = ref([
+ {
+ value: '1',
+ label: '绗竴瀛e害'
+ },
+ {
+ value: '2',
+ label: '绗簩瀛e害'
+ },
+ {
+ value: '3',
+ label: '绗笁瀛e害'
+ },
+ {
+ value: '4',
+ label: '绗洓瀛e害'
+ }
+])
+const clearSeason = () => {
+ console.log("req")
+ searchForm.value.season = ""
+ searchForm.value.issueDate = dayjs().format("YYYY-MM-DD");
+}
+
+const clearIssueDaten = () => {
+ searchForm.value.issueDate = ""
+ searchForm.value.season = getCurrentMonth()
+}
+const statisticsObj = ref({
+ ylqNum: 0, // 宸查鍙栨暟閲�
+ wlqNum: 0, // 鏈鍙栨暟閲�
+ csylqNum: 0, // 瓒呮椂宸查鍙栨暟閲�
+ cswlqNum: 0 // 瓒呮椂鏈鍙栨暟閲�
+})
+const resetHandleQuery = () => {
+ searchForm.value.issueDate = "";
+ searchForm.value.season = getCurrentMonth();
+ handleQuery(0)
+};
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = (status) => {
+ switch (status){
+ case 1:
+ searchForm.value.status = 1
+ break;
+ case 2:
+ searchForm.value.status = 2
+ break;
+ case 3:
+ searchForm.value.status = 3
+ break;
+ case 4:
+ searchForm.value.status = 4
+ break;
+ default:
+ searchForm.value.status = 0
+ }
+ getList();
+ getStatistics();
+};
+
+const getStatistics = () => {
+ statistics(searchForm.value).then(res => {
+ statisticsObj.value.cswlqNum = res.data.cswlqNum
+ statisticsObj.value.csylqNum = res.data.csylqNum
+ statisticsObj.value.ylqNum = res.data.ylqNum
+ statisticsObj.value.wlqNum = res.data.wlqNum
+ })
+}
+// 鑾峰彇瀛楀吀鏁版嵁
+const getList = async () => {
+ tableLoading.value = true;
+ const params = { ...searchForm.value};
+ statisticsList(params).then(res => {
+ tableLoading.value = false;
+ tableData.value = res.data;
+ }).catch(err => {
+ tableLoading.value = false;
+ })
+}
+const handleOut = () => {
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ proxy.download(`/lavorIssue/exportCopy`, {season: searchForm.value.season,issueDate: searchForm.value.issueDate}, "鍔充繚鍙拌处.xlsx");
+ })
+ .catch(() => {
+ ElMessage.info("宸插彇娑�");
+ });
+};
+
+// 浜嬩欢澶勭悊鍑芥暟
+const handleSelectionChange = (selection) => {
+ multipleList.value = selection;
+}
+
+// 缁勪欢鎸傝浇鏃跺姞杞藉瓧鍏告暟鎹�
+onMounted(() => {
+ handleQuery()
+})
+</script>
+
+<style scoped>
+.dynamic-table-container {
+ width: 100%;
+}
+
+.pagination-container {
+ margin-top: 20px;
+ display: flex;
+ justify-content: flex-end;
+}
+
+:deep(.el-table .el-table__header-wrapper th) {
+ background-color: #F0F1F5 !important;
+ color: #333333;
+ font-weight: 600;
+}
+
+:deep(.el-table .el-table__body-wrapper td) {
+ padding: 8px 0;
+}
+
+:deep(.el-select) {
+ width: 100%;
+}
+
+:deep(.el-input) {
+ width: 100%;
+}
+.actions {
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+ margin-bottom: 30px;
+}
+.head{
+ cursor: pointer;
+ font-size: 18px;
+ font-weight: 600;
+}
+</style>
diff --git a/src/views/login.vue b/src/views/login.vue
index 5300637..968a932 100644
--- a/src/views/login.vue
+++ b/src/views/login.vue
@@ -181,8 +181,8 @@
<style lang='scss' scoped>
.login {
height: 100%;
- background-image: url("../assets/images/login-background.png");
- background-size: cover;
+ background-image: url("../assets/indexViews/DHDCView.png");
+ background-size: 100% 100%;
position: relative;
}
.title {
diff --git a/vite.config.js b/vite.config.js
index 3e5d9bc..061360c 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -9,7 +9,7 @@
const baseUrl =
VITE_APP_ENV == "development"
? "http://114.132.189.42:8089" // 寮�鍙戠幆澧冨悗绔帴鍙�
- : "http://114.132.189.42:7003"; // 鐢熶骇鐜鍚庣鎺ュ彛
+ : "http://114.132.189.42:9032"; // 鐢熶骇鐜鍚庣鎺ュ彛
return {
// 閮ㄧ讲鐢熶骇鐜鍜屽紑鍙戠幆澧冧笅鐨刄RL銆�
@@ -45,7 +45,7 @@
},
// vite 鐩稿叧閰嶇疆
server: {
- port: 80,
+ port: 8001,
host: true,
open: true,
proxy: {
--
Gitblit v1.9.3