Compare commits
773 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e576000267 | ||
|
|
ae6da83a1a | ||
|
|
bd01e4c94b | ||
|
|
9783ca8506 | ||
|
|
264f6283dc | ||
| acf261b58b | |||
| fde9ba3781 | |||
| 04a65c6932 | |||
| e9333f7859 | |||
| 0a2004e3ce | |||
| b69a147c61 | |||
| 5deae5d846 | |||
| c2c60d01af | |||
| 9d5c393ebe | |||
| 3ec7a9c78e | |||
| 5dc25d1480 | |||
| ad3e7479f4 | |||
| c082ffc884 | |||
| 618cc8cb87 | |||
| 8e91feb616 | |||
| 203b53936f | |||
| f154e2789b | |||
| b4cfb8a5c6 | |||
| 6c874cac48 | |||
| 63eba1d0dc | |||
| 094474b680 | |||
| 0cfe4a8698 | |||
| 60d9b958bc | |||
| 1591e5d057 | |||
| 0c3580768b | |||
| 2793a62628 | |||
| cccd370671 | |||
| ec86d11537 | |||
| 2dea264c51 | |||
| 7dbaf5ca48 | |||
| fb469d5139 | |||
| fbccc01bbc | |||
| 92de396d12 | |||
| a1dbcf8dce | |||
| ad4f2f5ba9 | |||
| da10fca727 | |||
| a934176986 | |||
| c60245fb79 | |||
| 280137b7e2 | |||
| 36440928ae | |||
| b77253b0cb | |||
|
|
d4ba4bc7c2 | ||
|
|
80116c77f6 | ||
| d923330b77 | |||
| 4f41c43d37 | |||
| 45fccc9d57 | |||
| 8f993d0644 | |||
| 587c3c6477 | |||
| 1f631ea65d | |||
| 4d9007c87e | |||
| f4cf15656e | |||
| 55f12a2fb8 | |||
| 2616b916db | |||
| 6ac1dba2b5 | |||
|
|
f6dcb6b71b | ||
| 7e1f5ca820 | |||
| 5342a4d891 | |||
| 602e69007c | |||
| 04bbedf025 | |||
| 6ab2b5f947 | |||
| a64e6827c1 | |||
| 8173bfb6fb | |||
| 599fe5febb | |||
| 8313be513b | |||
| cef1d50833 | |||
| 54db74b033 | |||
| cdb7811133 | |||
|
|
4c91a6a336 | ||
|
|
c6222e0528 | ||
| a7d8bf63ca | |||
| 29180cfb9f | |||
| 02bf07f4da | |||
| 8791d220e6 | |||
| 88ab0d3526 | |||
| 04cc61047a | |||
| 925a8045f4 | |||
| 3c12bafa59 | |||
| f1237de72a | |||
| b1309fae57 | |||
| e45c71ccd0 | |||
| 3e1db9c1a4 | |||
| 6c55b66dde | |||
| e4ecd22c2e | |||
|
|
22d1c6fc46 | ||
|
|
1c095d3fcc | ||
| d49b771101 | |||
| 8ac168023b | |||
| e7090f7cd8 | |||
| 7f581ef763 | |||
|
|
fa05c22efc | ||
|
|
2856fa4785 | ||
| 0a40d4d068 | |||
| 649445f784 | |||
| bdc23982ce | |||
| 45220348d3 | |||
| dfe422345e | |||
| 80cd6363ab | |||
| 0b6e825bbd | |||
| 5dacc784ea | |||
| 68938c7ff0 | |||
| 2722c9915b | |||
| 97a81b6670 | |||
| 61e7e096a4 | |||
|
|
3401c8a5e3 | ||
| 480d419a6c | |||
| 37755d62b1 | |||
| 06e175cd8c | |||
| ddcbc02025 | |||
| 7c63c5e791 | |||
|
|
7bf6336a46 | ||
|
|
50a4e21a99 | ||
|
|
e8d3148937 | ||
|
|
dfdeaec16c | ||
|
|
42fd8d9740 | ||
| 17994928bf | |||
| 5efa1b8764 | |||
| 71b9065f29 | |||
|
|
b1616b716c | ||
|
|
7836450a10 | ||
| cbc97891b8 | |||
| 7a38c34da9 | |||
| 9f06ecbc62 | |||
| 23975e056a | |||
| ac409710d8 | |||
| 2c8de29fcd | |||
| c5a3bc9b58 | |||
| 09d95babd0 | |||
| 584adb63d4 | |||
| 06090fc00b | |||
| fce1bfdb6f | |||
| c10f7b2398 | |||
| b21719aaa0 | |||
|
|
9b19de0ff9 | ||
| 10e5db2cd6 | |||
| 2a25942cdf | |||
|
|
a5864a32ce | ||
| 5d661e1276 | |||
| 8feef06c11 | |||
| dd5fb4f44a | |||
| 57776764f8 | |||
| ce5297145b | |||
| 3c564b600b | |||
| e7ee3fbc9d | |||
| edec70ebbb | |||
| 13cbd1c7cd | |||
| 06524178c7 | |||
| 564084cb02 | |||
| e5777b55bc | |||
| 41134a6266 | |||
| 7e07010f0d | |||
|
|
ac28c3235e | ||
| 2a5443dc4e | |||
| 12f6f27b1a | |||
| 9eebacc47a | |||
| ddc3b70ddf | |||
|
|
bd57a54931 | ||
| 8f3d97ec1c | |||
| 8180c248ac | |||
|
|
a7c1c3a483 | ||
|
|
fce1708f5c | ||
|
|
dd80659044 | ||
| d7de238c38 | |||
| 08bc318875 | |||
| 888f97125b | |||
| c065008da0 | |||
| b2fdfc6227 | |||
| 05585bb980 | |||
| f2863557f9 | |||
| 70ffe5c1eb | |||
| a17ab96395 | |||
| 2466e15659 | |||
|
|
5c889e41c2 | ||
|
|
8ae817ffb3 | ||
| df09fbbd38 | |||
| 842fa7b782 | |||
| a8afb48cf7 | |||
| bbc883a116 | |||
| 216b0d273e | |||
| 361510242c | |||
| 94913d558d | |||
| 9a789db8a7 | |||
| 0f0fa0f4e0 | |||
| 212cbbcb78 | |||
| 9edf5d484f | |||
| 3bae1d1cc0 | |||
| f26a29338a | |||
| 509b216e4c | |||
| bffa726cbf | |||
| a7fb633b89 | |||
| b1ac328d9d | |||
| faaeb7be2b | |||
| d2ddf378bf | |||
| c97798696a | |||
| 0d7c303397 | |||
|
|
3d9db30ba3 | ||
| 66be60d011 | |||
| 928f41112c | |||
| 9d55358d73 | |||
| 2fd2d1d25b | |||
| daa76ada6e | |||
| 09e2bfc605 | |||
| cae3746a7b | |||
| 47a5cd3338 | |||
| 51d2e8357b | |||
| d87027423e | |||
| 592bba132e | |||
| a7b898fe48 | |||
| 3c494d038e | |||
| c226715097 | |||
| 3ba97bca2d | |||
| 7daa4b676d | |||
|
|
88198a62b2 | ||
| a07bc1cc1c | |||
| fd3231db4d | |||
| d011dc4008 | |||
| e43213d9a7 | |||
|
|
9fbfa918e9 | ||
| 04fa4bc334 | |||
| c89f4db529 | |||
|
|
7a49a23128 | ||
| 7b18a92a26 | |||
| 6434605c7a | |||
| c8eea20196 | |||
| 87613e8113 | |||
| 80aef38e7a | |||
| 14ce31262d | |||
| 2e9adb3248 | |||
| 68b954a21e | |||
| 1e4397b5ea | |||
|
|
eac76ca3bf | ||
| 215b17f066 | |||
|
|
719012f075 | ||
| 40d3d423c7 | |||
| 02ac44f389 | |||
| 3b884c0b78 | |||
| 870ee5a6d0 | |||
| a446dfcaa6 | |||
|
|
167bff642e | ||
| 630e35b078 | |||
| bd6fef9f7e | |||
|
|
da885d4965 | ||
| 5394e45ab8 | |||
| d25c285ad6 | |||
|
|
0273e19156 | ||
| e075eeb0d5 | |||
| 54e50de6b1 | |||
| 58d6a8f567 | |||
| 38e9c1d1e5 | |||
| 080b588723 | |||
| 3efcc1d039 | |||
| 0ad12c361d | |||
| 0bfa18eac8 | |||
| 12db4164d0 | |||
| 5d9331c23f | |||
| c247659c6c | |||
| ed08c6a796 | |||
| a769d114bb | |||
| e44b41bf14 | |||
| 6fe8626acb | |||
| 0a6c37019a | |||
| 657b43f739 | |||
| 13c0e3a7f0 | |||
| 72d5448e90 | |||
| 72171fb573 | |||
|
|
bd2d12551a | ||
| 942fc219e2 | |||
|
|
5a6d16afc6 | ||
|
|
16c4e07a86 | ||
|
|
58d5efb655 | ||
| c199ecb9fb | |||
| aa9001edd7 | |||
|
|
377509b62a | ||
|
|
c83a3b2ca3 | ||
|
|
fc034cc653 | ||
| fe72d0706a | |||
| 84fb6838fb | |||
| efd06e0da7 | |||
| 291708e71a | |||
| 9db5ad0052 | |||
| b7946d44c8 | |||
| daac1812bf | |||
|
|
114c9116b1 | ||
|
|
c5d5066ee1 | ||
|
|
a943687afe | ||
|
|
c61e584dea | ||
|
|
9bdad91b7e | ||
| 8684132fc7 | |||
| 7bcd75e6fb | |||
| c10f40f668 | |||
| bbb8705cee | |||
| 65b8af3e3e | |||
| afa0a52898 | |||
|
|
1032340cc2 | ||
| 0e633c40a1 | |||
| 9d0490a253 | |||
|
|
2eaa8337f6 | ||
| 87768bfdf4 | |||
| 36c5b04dbc | |||
| 9945cc1c86 | |||
| 6f320a47bb | |||
|
|
0551379a65 | ||
|
|
f66a570f00 | ||
|
|
5edf97338e | ||
| 0b9712962d | |||
| d03f352169 | |||
| dc20a6e33d | |||
| 1efe8c4aaf | |||
|
|
27b4f41749 | ||
|
|
30bd9da52f | ||
| 74e1938d3c | |||
| 5757846e7c | |||
| 058421bdd7 | |||
| da9bf2304b | |||
| 1a3d2bcf1a | |||
| e0ba874746 | |||
| 7e524039bd | |||
| 2d9bba98a7 | |||
| e849c6cde6 | |||
| 5c60bf91e4 | |||
|
|
dc189aa726 | ||
| 82634ddf97 | |||
| 3f32683d69 | |||
| 5fbef17b86 | |||
| 1cdd2cb02b | |||
| 2a80c8df21 | |||
| 4bee8bf9e4 | |||
| efe1be3929 | |||
| bce9b2d8d2 | |||
| b73b9aad4b | |||
| 8a9fffb3d0 | |||
| 9b758d41d0 | |||
| 9a3bfc784e | |||
| ddc305297f | |||
| 853be5f9de | |||
| 5977f13b91 | |||
| 3f26324747 | |||
| 141e965f95 | |||
| e12dd9e5d7 | |||
| d97ea2f19e | |||
| e3664314d0 | |||
| bfc38d035f | |||
| cef8530a5b | |||
| a6476c359d | |||
| 57f27c2b84 | |||
| 4c8959e3c4 | |||
|
|
a1064f6111 | ||
| 255dbe67e0 | |||
| 994e474532 | |||
| f3e8e12a5a | |||
| 4289ab2709 | |||
| a9dfa26b0d | |||
|
|
c0bfbbfe65 | ||
|
|
f812b4af4d | ||
| 94bb4ce943 | |||
| 7ad99048f4 | |||
| 0eba2c45f5 | |||
| 6f33aa1114 | |||
|
|
4f8a27e518 | ||
|
|
59014f6367 | ||
| 20825fee23 | |||
| bd1393d41c | |||
| a3ac29b28b | |||
| da49b51b3d | |||
| fbd6c3695d | |||
| aa15e9b8d0 | |||
| 91f21409f6 | |||
| 820349877c | |||
|
|
5410b6d248 | ||
| 369647f64f | |||
| 3745c9cb28 | |||
| 45a6b6733f | |||
| 6ab1dc806e | |||
| a678420f4f | |||
| 5100281c1f | |||
| 3a79c85033 | |||
| df513a91fe | |||
|
|
506c794c5d | ||
| 1c908017bb | |||
| 9cbe89007d | |||
| 132ab60d0f | |||
| 0c36801e83 | |||
| f187e7c5b1 | |||
| b162bb8977 | |||
| 75664822e4 | |||
| 009d73ce86 | |||
| 33a90e59f6 | |||
| 63107ece02 | |||
| a75c2dd0fa | |||
| d1a8077eea | |||
|
|
a72a09008f | ||
| 46e67f30a0 | |||
| 7ffb689927 | |||
|
|
13e0b6401c | ||
| 79171758f5 | |||
| 61a999758e | |||
| f624b4d290 | |||
| 9153c20902 | |||
| 5fdcf42336 | |||
| 73313a1532 | |||
| 21cfe73a13 | |||
| 532ef440ce | |||
| 2ff0dbd2a4 | |||
| 58cbceb747 | |||
| 49b64c177f | |||
| f240016e44 | |||
|
|
d3133a8860 | ||
| 6d56c4702b | |||
| 3db0f3bd5b | |||
| 363e2b983e | |||
| 90a26f2e1e | |||
| f931c65b57 | |||
| e64b7fe0ae | |||
| 48e97ed275 | |||
| a2977d0702 | |||
| 78ab1ddc45 | |||
| 7f73afa6b5 | |||
| 208584c34b | |||
| 40d2bef0ba | |||
| b425e709aa | |||
| 3f7de153da | |||
| 99224392a3 | |||
| ab83724056 | |||
| e33a6d5c58 | |||
| 5e2f9df706 | |||
| 1009cb7345 | |||
| e5f80ed017 | |||
| 050c5cf57a | |||
| 3e6c82dd19 | |||
| 15a2dda0fa | |||
| 9c812af394 | |||
| 3379d851c6 | |||
| 535d3f680b | |||
| 2f2dabb82d | |||
| b05d0ff42f | |||
| 4a749fc220 | |||
| 07c089ed29 | |||
| 3483a32d55 | |||
| cb224ab437 | |||
| d8b8c65dfb | |||
| d3fe46f0bc | |||
|
|
1bfb34305f | ||
| bf0cb73946 | |||
| 992eb2b890 | |||
|
|
eb8e772e66 | ||
| fb52f8b04e | |||
| 53e461bc4d | |||
| f251c08982 | |||
| 83ba497d73 | |||
|
|
c20fbcc356 | ||
| bb771b2f6d | |||
|
|
7fbd067e11 | ||
|
|
008c474b76 | ||
| a88ae09628 | |||
| b0eabd9c39 | |||
| adbd98f035 | |||
| f61adaf18b | |||
|
|
d1c6b23aa4 | ||
| c3e006bba8 | |||
| 812298acce | |||
| fd61fcc485 | |||
| 60b7133939 | |||
| 8e46c27af8 | |||
| 4ed64339fa | |||
|
|
d6a9ecd944 | ||
| cafb0ef5bf | |||
| 29b8bad394 | |||
| 9a862f8cce | |||
| 91b2ead3d4 | |||
| 521e40cf3d | |||
| 86ff3c2e94 | |||
| 617a867965 | |||
| b2e0983cf0 | |||
| 27bc6ea89f | |||
| c2413fe8b2 | |||
| ee81e1bb23 | |||
| a6a124d61a | |||
| 1bc8f26724 | |||
| 1c56ccae40 | |||
| 42fea1853d | |||
| 0eb0bcb0ef | |||
| 9655c41492 | |||
| ec7cf224d3 | |||
| 35ecec13ad | |||
| 0adb104c46 | |||
| 54e7b81f1e | |||
| d9d3a7f02a | |||
| e1a7b46b35 | |||
| 4ddd53cec7 | |||
| a8921a0683 | |||
| 6a0c3570f6 | |||
| 781b4cfb96 | |||
| 53ecadf315 | |||
| 18806f13e4 | |||
| 031a08e65c | |||
| ec4c61d758 | |||
| aa9d7d9028 | |||
| 1c204b39df | |||
| 0685143b3a | |||
| 2e86683f41 | |||
| ca64562059 | |||
| d676868cf7 | |||
| 80d84c4a85 | |||
| 71b2b372b1 | |||
| a7d91a8f32 | |||
| e513af4983 | |||
| df6f49caeb | |||
| 3e2249431b | |||
| b9d33bd6e4 | |||
| 8f1cc442ac | |||
| cc2babcd32 | |||
| 8b5868fde6 | |||
| 1d66c44edb | |||
| 6597506435 | |||
| 00a2b7a3af | |||
| 63a6f9b85e | |||
| abd060b530 | |||
| d1eb5c3327 | |||
| abe80eafdc | |||
| 1ee92f698e | |||
| 747b40f9ba | |||
|
|
83fd1b37e2 | ||
|
|
f6ada88026 | ||
| 2a0e193374 | |||
| e0b5487951 | |||
| f20318843e | |||
| 456f2284e9 | |||
| fb64361c64 | |||
| 6bb97b4a1d | |||
|
|
9ad29c3a13 | ||
|
|
20fbd0e2d4 | ||
|
|
eebb3003c7 | ||
|
|
3ed5068dee | ||
| 918a02b201 | |||
| e0ffef25bd | |||
| 419397fc00 | |||
| 9b45135a18 | |||
| f0eb28ab84 | |||
| c416424253 | |||
| e9592920e7 | |||
| c05322a2bf | |||
| 9be3d7096a | |||
| cd715fbf98 | |||
|
|
a796e7622f | ||
|
|
e2d6722ec6 | ||
| 13386303e8 | |||
| c4db5d6719 | |||
|
|
495e39c802 | ||
| dd5d24768b | |||
| 3746a19063 | |||
|
|
9acd05a2cc | ||
| d7a4eef7db | |||
| 346ad4c4df | |||
| 5d570f3108 | |||
| 4a0b3db4e4 | |||
| bc27a83848 | |||
| dd046f645f | |||
| 04a7ba8802 | |||
|
|
b0199c8fd9 | ||
|
|
d2f9bfcb33 | ||
|
|
6391ab458b | ||
| e1f6652672 | |||
|
|
4d1ba82696 | ||
|
|
de2475f39a | ||
| 80ecad0864 | |||
| fa94f9e78d | |||
| 7501c37379 | |||
| f776f994ab | |||
| daf5ffe2c9 | |||
| f4ad871831 | |||
|
|
5be806104f | ||
| 7ec6cba0f0 | |||
| 14abf64e5d | |||
| 661bc2e397 | |||
| 2246fcb621 | |||
| 5ae8e4be78 | |||
|
|
5a1e1848cb | ||
| 3f9b7f9011 | |||
| f47180dfbe | |||
| 2e7e55464d | |||
| 7791648837 | |||
|
|
92e935622a | ||
|
|
ee890c0e80 | ||
| e39d953385 | |||
| 8c6da666d5 | |||
| 29a019b32a | |||
| 8bc9a27ccf | |||
| ed988b99b3 | |||
| c799c97643 | |||
| f9064ddeb4 | |||
| 0c1e566578 | |||
| 94528cfa06 | |||
| 2ab4eb1a7e | |||
| 04c1175cf8 | |||
| 7a5fbd501e | |||
| dd3f793ac2 | |||
| dc153e459e | |||
| 00ad1c3098 | |||
| 6ac425f7de | |||
| 80ae6bdf7e | |||
| 9198837d65 | |||
| 4acba8bedc | |||
| 7f40296f3b | |||
| 0ae84ba12e | |||
| be367ead6e | |||
| 335d8c1e72 | |||
| dd406e4ba6 | |||
| beb07edc73 | |||
| 0eb036e8a5 | |||
| ba86f54369 | |||
| 11544acbad | |||
| 63e94af451 | |||
| 554c7d2be7 | |||
| e3222e906d | |||
| 30a8ceb424 | |||
|
|
304effe93c | ||
| 26931f4200 | |||
| e71c142ea9 | |||
| 7ebd897d57 | |||
| 0ec14cfd9b | |||
| bef0c2d792 | |||
| 08f66803a2 | |||
|
|
6af7bf9d2f | ||
|
|
9013d54add | ||
|
|
fd722b5c82 | ||
|
|
a8e56fe985 | ||
|
|
4953e96415 | ||
| 5b85abd219 | |||
| 7156e34fde | |||
| e903dd2994 | |||
| 549e307b3e | |||
| 390474ea24 | |||
| 43c9cb03d3 | |||
|
|
5eb7e34571 | ||
|
|
d12fb8a12b | ||
| 1991d7eada | |||
| 31a12e566a | |||
| 5c8679d5f9 | |||
| 7e70c9271f | |||
| 6748685712 | |||
| cd7f94e8f2 | |||
|
|
db8a96a664 | ||
|
|
17207b2c87 | ||
| d6de4d5854 | |||
| bcdafbc7cd | |||
|
|
e9e5a0c785 | ||
|
|
21f90e438c | ||
| e1b9f3f220 | |||
| 96d46e6480 | |||
| 6ab0c206c4 | |||
| a4255c3157 | |||
| 39b1690c0a | |||
| 9f4fe95e4d | |||
| 1635482e09 | |||
| 3270aeef06 | |||
|
|
6c80652416 | ||
|
|
c97091db4f | ||
| 1c57cb277b | |||
| e648faba69 | |||
| a663b84fab | |||
| f83ae8df51 | |||
| 1d772e1414 | |||
| 92e9468cb9 | |||
| 5c93eae4ce | |||
| 5d7b6bc59f | |||
| 1825b6c871 | |||
| dee7fdacf2 | |||
| dc7d90c349 | |||
| 9661cdbb2b | |||
|
|
3a4f9927c9 | ||
| 1f4389eb5e | |||
|
|
4a90f4bc1e | ||
|
|
8155a4d160 | ||
| 771a844552 | |||
| 08a609e2a8 | |||
| d16045a1b2 | |||
| 1fc0ae6ac0 | |||
| 08f20bb171 | |||
| 5421145583 | |||
| b7a0dc2545 | |||
| 3bd6df74cc | |||
|
|
190a1d6477 | ||
|
|
cb7f6e9919 | ||
| 5ea20654cc | |||
| 670c8a5653 | |||
| 206a024f4b | |||
| 89d5c86d8b | |||
| 397d5f0182 | |||
| 10bc019866 | |||
| 62620b1dc5 | |||
| ff68ce96af | |||
| 65d933c027 | |||
| 726c746a87 | |||
| c498a3de62 | |||
| d432e54bc8 | |||
| 5b68ee6846 | |||
| 96e7ca1a67 | |||
| 9368ea24ab | |||
| c96cbf8415 | |||
| bab0421b6d | |||
| fccce985b6 | |||
| c675b1ec48 | |||
| 02bda3c71f | |||
| b7ebd66729 | |||
| 76c759c088 | |||
| e4e7444aff | |||
| a8f5f84b20 | |||
| 716d18122f | |||
| 2f19bb7bdc | |||
| 8f8d954bb6 | |||
| 0732acf8c7 | |||
| 6540ac8991 | |||
| 6009885c09 | |||
| 83a8fac0fb | |||
| 0c070154e1 | |||
| 32a3ab3001 | |||
| d0fe340f9d | |||
| 92d2278dfd | |||
| f5c6680c66 | |||
| b5e5a3f12a | |||
| 7869ff4e6a | |||
| 95f4610714 | |||
| 9754b62038 | |||
| 573fff84e4 | |||
|
|
1f1ff3a466 | ||
| 79f2032fde | |||
|
|
f820c25892 | ||
|
|
a4cb59ff9a | ||
| a7b6b44a42 | |||
| 1f126592e1 | |||
| 0f914237bf | |||
| 9a0f5b0e12 | |||
| 9f7e3778ad | |||
| 01540a3144 | |||
| 5e4e8d6389 | |||
| 08579c8aad | |||
| 5ae971e0ac | |||
| 9ae0b7547c | |||
| b2369d1702 | |||
| 8b6c9a7d1e | |||
| 6097e74a9b | |||
| 11b794bf96 | |||
| 2a72de08a4 | |||
| 77fcdc240b | |||
| 6d8dbaa8c4 | |||
| d7b004ae80 | |||
| 1f9a3603d8 | |||
| b8b165c205 | |||
| de2f566bd0 | |||
| 38182da467 | |||
| de0e0be953 | |||
| ef1acd65b7 | |||
| 27dcca6617 | |||
| 2ad94511d0 | |||
| bfdf2cf4a2 | |||
| 4f4ef2cfde | |||
| 222ab1bec7 | |||
| bead5edc86 | |||
| 18caa0ee58 | |||
| 96d8f1e48a | |||
| 3bc24219ed | |||
| 07d5380818 | |||
| cd91dd3cad | |||
| edb235ff0d | |||
| 9ade24768e | |||
| e753c27455 | |||
| 1684e49662 | |||
| 42ea1dde8b | |||
|
|
bb2a0ce177 |
@@ -26,7 +26,7 @@ steps:
|
||||
- mkdir -p ./node_modules
|
||||
- export NODE_MODULES_PATH=`pwd`/node_modules
|
||||
# - npm config set registry https://registry.npmmirror.com
|
||||
#- set NODE_OPTIONS=--openssl-legacy-provider
|
||||
# - set NODE_OPTIONS=--openssl-legacy-provider
|
||||
# - npm install
|
||||
- npm run build
|
||||
- ls /app/build/$DRONE_REPO_NAME/
|
||||
|
||||
11348
package-lock.json
generated
@@ -14,6 +14,7 @@
|
||||
"d3": "^7.8.5",
|
||||
"echarts": "^5.4.2",
|
||||
"element-plus": "^2.6.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"highlight.js": "9.18.5",
|
||||
"jquery": "^3.6.0",
|
||||
"js-cookie": "^3.0.5",
|
||||
@@ -30,7 +31,9 @@
|
||||
"vue-codemirror": "^6.1.1",
|
||||
"vue-json-viewer": "^3.0.4",
|
||||
"vue-router": "^4.1.6",
|
||||
"vuedraggable": "^4.1.0"
|
||||
"vuedraggable": "^4.1.0",
|
||||
"xlsx": "^0.18.5",
|
||||
"xlsx-style-vite": "^0.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@codemirror/lang-java": "^6.0.1",
|
||||
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 64 KiB |
@@ -8,5 +8,6 @@ window.addEventListener('beforeunload', e=>beforeunload(e))
|
||||
const beforeunload = (()=>{
|
||||
const permisstionStore = usePermisstionStroe()
|
||||
permisstionStore.setIsLoadRoutes(true)
|
||||
permisstionStore.setIsSuccessReq()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import request from "@/utils/request.js";
|
||||
|
||||
export const modifyUser=(data)=>{
|
||||
export const initPassword=(data)=>{
|
||||
return request({
|
||||
url:'/admin/user',
|
||||
method:'put',
|
||||
url:'/admin/mosr/user/init/password',
|
||||
method:'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
export const editPassword=(data)=>{
|
||||
return request({
|
||||
url:'/admin/mosr/user/update/password',
|
||||
method:'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 请求数据源适配器list
|
||||
export const getDataAdapterList = (params) => {
|
||||
return request({
|
||||
url: '/custom/query/query/adapter',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
//获取到option列表
|
||||
export const getDataAdapterOpt = () => {
|
||||
return request({
|
||||
url: '/custom/query/query/adapter/option',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 获取数据源适配器详情
|
||||
export const getDataAdapterDetails = (dataAdapterId) => {
|
||||
return request({
|
||||
url: '/custom/query/query/adapter/' + dataAdapterId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增数据源适配器
|
||||
export const addDataAdapter = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/query/adapter',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
//模拟执行适配器函数
|
||||
export const executeAdapterMockData = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/query/adapter/mock/execute',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改数据源适配器
|
||||
export const editDataAdapter = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/query/adapter',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除数据源适配器
|
||||
export const delDataAdapter =(dataAdapterId) => {
|
||||
return request({
|
||||
url: '/custom/query/query/adapter/' + dataAdapterId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 请求数据源管理list
|
||||
export const getDataSourceManageList = (params) => {
|
||||
return request({
|
||||
url: '/custom/query/datasource',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
//获取到option列表
|
||||
export const getDataSourceManageOpt = () => {
|
||||
return request({
|
||||
url: '/custom/query/datasource/option',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 获取数据源管理详情
|
||||
export const getDataSourceManageDetails = (queryDataSourceId) => {
|
||||
return request({
|
||||
url: '/custom/query/datasource/' + queryDataSourceId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 获取数据源管理详情
|
||||
export const getDataSourceType = () => {
|
||||
return request({
|
||||
url: '/custom/query/datasource/option/type',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 获取校验规则option
|
||||
export const getDataSourceOption = () => {
|
||||
return request({
|
||||
url: '/custom/query/datasource/option',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 新增数据源管理
|
||||
export const addDataSourceManage = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/datasource',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改数据源管理
|
||||
export const editDataSourceManage = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/datasource',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除数据源管理
|
||||
export const delDataSourceManage =(queryDataSourceId) => {
|
||||
return request({
|
||||
url: '/custom/query/datasource/' + queryDataSourceId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
export const getEchartsList = (params) => {
|
||||
return request({
|
||||
url: '/custom/query/echarts',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
export const getEchartsDetails = (echartsId) => {
|
||||
return request({
|
||||
url: '/custom/query/echarts/' + echartsId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export const addEcharts = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/echarts',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
export const editEcharts = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/echarts',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
export const delEcharts=(echartsIdList) => {
|
||||
return request({
|
||||
url: '/custom/query/echarts/' + echartsIdList,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取查询页面信息
|
||||
export const getPageInfo = (queryId, params) => {
|
||||
return request({
|
||||
url: '/custom/query/page/' + queryId,
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取到页面数据
|
||||
export const getPageData = (params, data) => {
|
||||
return request({
|
||||
url: '/custom/query/page/data',
|
||||
method: 'post',
|
||||
params: params,
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
export const getSqlInfo = (queryId) => {
|
||||
return request({
|
||||
url: '/custom/query/sql/search/' + queryId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export const previewSql= (data,pageInfo) => {
|
||||
return request({
|
||||
url:'/custom/query/sql/search/preview' ,
|
||||
method: 'put',
|
||||
data,
|
||||
params:pageInfo
|
||||
})
|
||||
}
|
||||
export const saveSqlQueryParams = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/sql/search',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
export const sqlToLine = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/sql/search/publish',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
export const sqlDownLine = (queryId) => {
|
||||
return request({
|
||||
url: '/custom/query/sql/search/cancel/'+queryId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取Sql List
|
||||
export const getSqlList = (params) => {
|
||||
return request({
|
||||
url: '/custom/query/sql/uni',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 获取Sql详情
|
||||
export const getSqlDetails = (sqlId) => {
|
||||
return request({
|
||||
url: '/custom/query/sql/uni/' + sqlId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 新增Sql
|
||||
export const addSql = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/sql/uni',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改Sql
|
||||
export const editSql = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/sql/uni',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除Sql
|
||||
export const delSql =(idList) => {
|
||||
return request({
|
||||
url: '/custom/query/sql/uni/' + idList,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
//获取表格维护列表
|
||||
export const getTableInfo = (params) => {
|
||||
return request({
|
||||
url: '/custom/query/table',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
export const getDynamicTableList = (params) => {
|
||||
return request({
|
||||
url: '/custom/query/dynamic/table',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
//根据数据源获取到表格option信息
|
||||
export const getAssociationTableOption = (datasourceId) => {
|
||||
return request({
|
||||
url: '/custom/query/table/option/' + datasourceId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
//获取表格字段option信息
|
||||
export const getAssociationFieldOption = (tableId) => {
|
||||
return request({
|
||||
url: '/custom/query/table/column/option/' + tableId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 获取详细信息
|
||||
export const getTableDetails = (tableId) => {
|
||||
return request({
|
||||
url: '/custom/query/table/' + tableId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 导入表信息
|
||||
export const addTableInfo= (data) => {
|
||||
return request({
|
||||
url: '/custom/query/table/import',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改自定义查询表格维护
|
||||
export const editTable = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/table',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 同步数据库
|
||||
export const syncDatabase = (tableId) => {
|
||||
return request({
|
||||
url: '/custom/query/table/sync/'+ tableId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除自定义查询表格维护
|
||||
export const delTable=(tableId) => {
|
||||
return request({
|
||||
url: '/custom/query/table/' + tableId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取topo拖拽数据信息
|
||||
export const getTopoDragInfo = (queryId) => {
|
||||
return request({
|
||||
url: '/custom/query/topo/search/' + queryId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
export const saveTopo = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/topo/search',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
export const previewTopo = (data,pageInfo) => {
|
||||
return request({
|
||||
url: '/custom/query/topo/search/preview',
|
||||
method: 'post',
|
||||
data,
|
||||
params:pageInfo,
|
||||
})
|
||||
}
|
||||
export const previewTopologyData = (data,pageInfo) => {
|
||||
return request({
|
||||
url: '/custom/query/topo/search/preview/data',
|
||||
method: 'post',
|
||||
data,
|
||||
params:pageInfo,
|
||||
})
|
||||
}
|
||||
|
||||
export const topoToLine = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/topo/search/publish',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const topoDownLine = (queryId) => {
|
||||
return request({
|
||||
url: '/custom/query/topo/search/cancel/'+queryId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取topoList
|
||||
export const getTopoList = (params) => {
|
||||
return request({
|
||||
url: '/custom/query/topo/uni',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 获取topo详情
|
||||
export const getTopoDetails = (topoId) => {
|
||||
return request({
|
||||
url: '/custom/query/topo/uni/' + topoId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 新增topo
|
||||
export const addTopo = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/topo/uni',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改topo
|
||||
export const editTopo = (data) => {
|
||||
return request({
|
||||
url: '/custom/query/topo/uni',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除topo
|
||||
export const delTopo =(idList) => {
|
||||
return request({
|
||||
url: '/custom/query/topo/uni/' + idList,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
81
src/api/expense-manage/index.js
Normal file
@@ -0,0 +1,81 @@
|
||||
import request from '@/utils/request.js'
|
||||
import axios from "axios";
|
||||
import {getToken} from "@/utils/auth";
|
||||
|
||||
export const addAllocation = (data) => {
|
||||
return request({
|
||||
url:'/workflow/mosr/cost/allocation',
|
||||
method: "post",
|
||||
data
|
||||
});
|
||||
};
|
||||
export const getAllocationDetail = (allocationId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/cost/allocation/info/${allocationId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const getAllocationDetails = (allocationId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/cost/allocation/usr/detail/${allocationId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const getAllocationSummaryDetails = (params) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/cost/allocation/collect',
|
||||
method: "get",
|
||||
params:params
|
||||
});
|
||||
};
|
||||
export const getAllocationProcess = () => {
|
||||
return request({
|
||||
url: '/workflow/mosr/cost/allocation/process',
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const getAllocationDetailList = (params) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/cost/allocation/usr',
|
||||
method: "get",
|
||||
params:params
|
||||
});
|
||||
};
|
||||
export const getResearchUser = () => {
|
||||
return request({
|
||||
url: '/admin/mosr/user/research',
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const getProjectOption = () => {
|
||||
return request({
|
||||
url: '/workflow/mosr/project/implementation/in/implementation/option',
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
|
||||
export const editAllocation = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/cost/allocation/edit',
|
||||
method: "post",
|
||||
data
|
||||
});
|
||||
};
|
||||
export const deleteAllocation = (id) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/cost/allocation/${id}`,
|
||||
method: "delete"
|
||||
});
|
||||
};
|
||||
|
||||
export const shareExportExcel = (allocationId) => {
|
||||
return axios.get(
|
||||
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/cost/allocation/collect/${allocationId}`,
|
||||
{
|
||||
responseType: 'blob',
|
||||
headers: {
|
||||
Authorization: getToken()
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -7,6 +7,7 @@ export const getCodeImg = () => {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export const login = (data) => {
|
||||
return request({
|
||||
url: '/auth/login',
|
||||
@@ -14,6 +15,12 @@ export const login = (data) => {
|
||||
data
|
||||
})
|
||||
}
|
||||
export const switchAccount = (userId) => {
|
||||
return request({
|
||||
url: `/auth/switch/account/${userId}`,
|
||||
method: 'post',
|
||||
})
|
||||
}
|
||||
|
||||
export const getUserInfo = () => {
|
||||
return request({
|
||||
@@ -21,3 +28,9 @@ export const getUserInfo = () => {
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
export const getAuthInfo = () => {
|
||||
return request({
|
||||
url: '/admin/mosr/user/detail/info',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -60,9 +60,31 @@ export const deleteFile = (fileId) => {
|
||||
method: "delete"
|
||||
});
|
||||
};
|
||||
export const downloadFile = (fileId) => {
|
||||
return request({
|
||||
url: '/workflow/process/file/download',
|
||||
method: "get",
|
||||
responseType:'blob',
|
||||
params:{
|
||||
fileId:fileId
|
||||
}
|
||||
});
|
||||
};
|
||||
export const getCompanyOption = () => {
|
||||
return request({
|
||||
url: '/admin/mosr/sub/company/companyOption',
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const deleteDemand = (id) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/requirement/${id}`,
|
||||
method: "delete"
|
||||
});
|
||||
};
|
||||
export const getRequirementStatePerm = () => {
|
||||
return request({
|
||||
url: '/workflow/mosr/requirement/prem/state',
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
|
||||
91
src/api/project-demand/summary/index.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export const fileUp = (url, data) => {
|
||||
return request({
|
||||
url,
|
||||
method: 'post',
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const requirementReported = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/requirement/reported',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
//获取需求上报 流程信息
|
||||
export const getProcessInfo = (specialFund) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/requirement/collect/process/${specialFund}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const getDetail = (projectId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/requirement/collect/info/${projectId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
|
||||
export const resubmitReported = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/requirement/collect/resubmit',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
export const getCollectAttachment = (params) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/requirement/collect/attachments',
|
||||
method: "get",
|
||||
params:params
|
||||
});
|
||||
};
|
||||
export const uploadCollectAttachment= (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/requirement/collect/upload',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
// 年度计划
|
||||
export const addPlan= (data) => {
|
||||
return request({
|
||||
url: '/workflow/annual/plan',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
export const editPlan= (data) => {
|
||||
return request({
|
||||
url: '/workflow/annual/plan',
|
||||
method: "put",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
export const getPlan= (annualPlanId) => {
|
||||
return request({
|
||||
url: `/workflow/annual/plan/info/${annualPlanId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const deletePlan= (annualPlanId) => {
|
||||
return request({
|
||||
url: `/workflow/annual/plan/${annualPlanId}`,
|
||||
method: "delete"
|
||||
});
|
||||
};
|
||||
export const approvePlan= (data) => {
|
||||
return request({
|
||||
url: '/workflow/annual/plan/approve',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
31
src/api/project-manage/attachment.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
|
||||
export const searchFileList = (params) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/attachment/list`,
|
||||
method: "get",
|
||||
params: params
|
||||
});
|
||||
};
|
||||
export const uploadFileList = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/attachment/upload',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
export const searchImplementationFileList = (params) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/attachment/implementation/list',
|
||||
method: "get",
|
||||
params: params
|
||||
});
|
||||
};
|
||||
export const switchAttachmentState = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/project/filing/attachment/switch',
|
||||
method: "post",
|
||||
data
|
||||
});
|
||||
};
|
||||
181
src/api/project-manage/index.js
Normal file
@@ -0,0 +1,181 @@
|
||||
import request from '@/utils/request.js'
|
||||
import axios from "axios";
|
||||
import {getToken} from "@/utils/auth";
|
||||
//项目立项
|
||||
export const getApplyProcess = (projectId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/project/approval/initiation/process/${projectId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const projectApply = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/project/approval/initiation/apply',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
export const getApplyDetail = (ProjectId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/project/approval/info/${ProjectId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
|
||||
export const resubmitApply = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/project/approval/initiation/resubmit',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
export const getInitiationAttachment = (params) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/project/approval/attachments',
|
||||
method: "get",
|
||||
params: params
|
||||
});
|
||||
};
|
||||
//项目实施
|
||||
export const getCheckDetail = (projectId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/project/implementation/info/${projectId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const resubmitCheck = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/project/implementation/resubmit',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
export const projectCheck = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/project/implementation/initiation/check',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
export const getProjectCheckProcess = (projectId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/project/implementation/process/${projectId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
|
||||
export const addLedger = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/expense/ledger',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
export const getTags = (projectId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/attachment/option/${projectId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const getPhaseProcess = () => {
|
||||
return request({
|
||||
url: '/workflow/phase/change/process',
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const submitPhaseChange = (data) => {
|
||||
return request({
|
||||
url: '/workflow/phase/change',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
export const getPhaseDetail = (projectId) => {
|
||||
return request({
|
||||
url: `/workflow/phase/change/info/${projectId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const getPhaseForm = (projectId) => {
|
||||
return request({
|
||||
url: `/workflow/phase/change/from/${projectId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const resubmitPhaseForm = (data) => {
|
||||
return request({
|
||||
url: '/workflow/phase/change/resubmit',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
//项目归档
|
||||
export const getConclusionDetail = (ProjectId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/project/filing/info/${ProjectId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const resubmitConclusion = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/project/filing/resubmit',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
export const projectConclusion = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/project/filing/project/entry',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
export const getProjectConclusionProcess = () => {
|
||||
return request({
|
||||
url: '/workflow/mosr/project/filing/process',
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
//获取前置流程
|
||||
export const getPreProcess = () => {
|
||||
return request({
|
||||
url: '/workflow/details/pre/process',
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const updateLedger = (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/expense/ledger/replenishment',
|
||||
method: "post",
|
||||
data: data
|
||||
});
|
||||
};
|
||||
export const searchUpdateLedgerData = (projectId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/expense/ledger/${projectId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
//
|
||||
// export const searchUpdateLedgerData = (projectId) => {
|
||||
// return request({
|
||||
// url: '/workflow/mosr/expense/ledger/import',
|
||||
// method: "get"
|
||||
// });
|
||||
// };
|
||||
|
||||
export const exportExcel = (data) => {
|
||||
return axios.post(
|
||||
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/project/implementation/export`,
|
||||
data, {
|
||||
responseType: 'blob',
|
||||
headers: {
|
||||
Authorization: getToken()
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
46
src/api/special-fund/index.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
export const getFundDetail = (specialFundId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/special/fund/from/${specialFundId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const getFundDetailProcess = (specialFundId) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/special/fund/info/${specialFundId}`,
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const getFundOption = () => {
|
||||
return request({
|
||||
url: '/workflow/mosr/special/fund/option',
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const getFundProcess = (specialFundId) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/special/fund/process',
|
||||
method: "get"
|
||||
});
|
||||
};
|
||||
export const addFund= (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/special/fund',
|
||||
method: "post",
|
||||
data
|
||||
});
|
||||
};
|
||||
export const resubmitFund= (data) => {
|
||||
return request({
|
||||
url: '/workflow/mosr/special/fund/resubmit',
|
||||
method: "post",
|
||||
data
|
||||
});
|
||||
};
|
||||
export const deleteFund = (id) => {
|
||||
return request({
|
||||
url: `/workflow/mosr/special/fund/${id}`,
|
||||
method: "delete"
|
||||
});
|
||||
};
|
||||
@@ -14,3 +14,9 @@ export const getDepartmentList=(params)=>{
|
||||
params
|
||||
})
|
||||
}
|
||||
export const getCompanyDetail=(companyId)=>{
|
||||
return request({
|
||||
url:`/admin/mosr/sub/company/info/${companyId}`,
|
||||
method:'get'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -18,6 +18,13 @@ export const getConfigDetails = (configId) => {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 获取参数配置表详情
|
||||
export const getConfigByKey = (configKey) => {
|
||||
return request({
|
||||
url: '/admin/config/key/' + configKey,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增参数配置表
|
||||
export const addConfig = (data) => {
|
||||
|
||||
@@ -49,3 +49,10 @@ export const delDictType =(dictTypeId) => {
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
//字典刷新缓存
|
||||
export const refreshDict =() => {
|
||||
return request({
|
||||
url: 'admin/dict/type/refresh',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,6 +15,12 @@ export const getSubCompOpt = () => {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
export const getUserAccount = () => {
|
||||
return request({
|
||||
url: `/admin/mosr/user/account/list`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 查询角色信息
|
||||
export const getRolesOpt = () => {
|
||||
@@ -49,9 +55,9 @@ export const getUserDetail = (userId) => {
|
||||
|
||||
// 操作
|
||||
export const operate = (data, type) => {
|
||||
console.log(type ,'type');
|
||||
if(data.userId && type !== '0') return editUser(data)
|
||||
else if(type == '0') return editUserOA(data)
|
||||
// console.log(type ,'type');
|
||||
if (data.userId && type !== '0') return editUser(data)
|
||||
else if (type == '0') return editUserOA(data)
|
||||
return addUser(data)
|
||||
}
|
||||
|
||||
@@ -179,3 +185,24 @@ export const unbindAllUserByPost = (postId) => {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const bindAccount = (data) => {
|
||||
return request({
|
||||
url: '/admin/mosr/user/bind/account',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
export const getBindAccount = (userId) => {
|
||||
return request({
|
||||
url: `/admin/mosr/user/bind/account/info/${userId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export const checkMatrix = (userId) => {
|
||||
return request({
|
||||
url: `/admin/mosr/user/matrix?userId=` + userId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -60,3 +60,19 @@ export function addProcessDefinition(param) {
|
||||
data: param
|
||||
})
|
||||
}
|
||||
|
||||
export function getTypeOption() {
|
||||
return request({
|
||||
url: "/workflow/process/definition/type/option",
|
||||
method: "get",
|
||||
})
|
||||
}
|
||||
|
||||
export function getFromPerm(processKey) {
|
||||
return request({
|
||||
url: "/workflow/process/definition/from/perm/"+processKey,
|
||||
method: "get",
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
//根据角色或者部门获取到对应的数据
|
||||
export function getUserTree(type,chooseId){
|
||||
export function getUserTree(type, chooseId) {
|
||||
return request({
|
||||
url:`/admin/user/choose/${type}/${chooseId}`,
|
||||
method:'get'
|
||||
url: `/admin/user/choose/${type}/${chooseId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ export function getRole() {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
//获取采取树形控件的部门option
|
||||
export function getDepartmentTree() {
|
||||
return request({
|
||||
@@ -22,3 +23,27 @@ export function getDepartmentTree() {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getMosrUser(params) {
|
||||
return request({
|
||||
url: '/admin/mosr/user/choose',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function getOrganizationStructure(params) {
|
||||
return request({
|
||||
url: '/admin/organizational/structure/choose',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function getOrganizationStructureTree(params) {
|
||||
return request({
|
||||
url: '/admin/organizational/structure/tree',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
BIN
src/assets/kylogo.png
Normal file
|
After Width: | Height: | Size: 183 KiB |
@@ -377,8 +377,8 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
||||
//放大缩小按钮上外边距
|
||||
.scale {
|
||||
margin-top: 10px;
|
||||
z-index: 666;
|
||||
position: absolute;
|
||||
//z-index: 666;
|
||||
//position: static;
|
||||
//top: -20px;
|
||||
}
|
||||
|
||||
@@ -405,7 +405,9 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
||||
.nowrap {
|
||||
white-space: pre
|
||||
}
|
||||
|
||||
.el-empty__description {
|
||||
margin-top: 0!important;
|
||||
}
|
||||
//SvgIcon组件的样式
|
||||
.home-icon {
|
||||
width: 4em;
|
||||
@@ -415,7 +417,13 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
||||
overflow: hidden;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.oran-icon{
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
margin-right: 4px;
|
||||
vertical-align: -0.21em;
|
||||
|
||||
}
|
||||
.svg-icon {
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
@@ -547,4 +555,35 @@ html, body, #app, .el-container, .el-aside, .el-main {
|
||||
position: fixed;
|
||||
bottom: 15px;
|
||||
right: 15px;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.approval-record {
|
||||
//padding-top: 10px;
|
||||
padding-bottom: 30px;
|
||||
position: relative;
|
||||
.approval-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
//justify-content: space-between;
|
||||
|
||||
.diagram {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
float: right;
|
||||
|
||||
.base-title {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
//.el-switch {
|
||||
// margin-left: 15px;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
.process {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
border-radius: 10px;
|
||||
}
|
||||
.logo {
|
||||
height: 106px;
|
||||
height: 65px;
|
||||
background-color: #BEA266;
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
@@ -10,6 +10,13 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
& > img {
|
||||
object-fit: scale-down;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
.port-link{
|
||||
display: block;
|
||||
|
||||
1
src/assets/svg/account.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717294999406" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10473" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M721.7 259.8h140l-196-196v140c0 31 25 56 56 56z" fill="#2c2c2c" p-id="10474"></path><path d="M469.7 749.8c0-146.7 119.3-266 266-266 45.6 0 88.5 11.5 126 31.8V301.8h-140c-54 0-98-44-98-98v-140h-490c-30.9 0-56 25.1-56 56v784c0 30.9 25.1 56 56 56H573c-62.7-48.7-103.3-124.6-103.3-210z m-252-426.5h308c15.5 0 28 12.5 28 28s-12.5 28-28 28h-308c-15.5 0-28-12.5-28-28s12.5-28 28-28z m98 424.1h-98c-15.5 0-28-12.5-28-28s12.5-28 28-28h98c15.5 0 28 12.5 28 28s-12.6 28-28 28z m56-184h-154c-15.5 0-28-12.5-28-28s12.5-28 28-28h154c15.5 0 28 12.5 28 28s-12.6 28-28 28z" fill="#2c2c2c" p-id="10475"></path><path d="M735.7 539.8c-116 0-210 94-210 210s94 210 210 210 210-94 210-210-94.1-210-210-210z m69.1 163.5c12.9 0 23.3 10.5 23.3 23.4 0 12.9-10.4 23.3-23.3 23.3h-46.6v23.3h46.6c12.9 0 23.3 10.4 23.3 23.3s-10.4 23.3-23.3 23.3h-46.6v46.7c0 12.9-10.4 23.3-23.3 23.3s-23.3-10.4-23.3-23.3v-46.7H665c-12.9 0-23.3-10.4-23.3-23.3s10.4-23.3 23.3-23.3h46.6V750H665c-12.9 0-23.3-10.4-23.3-23.3s10.4-23.3 23.3-23.3h37.3l-53.9-53.8c-9.1-9.1-9.1-23.9 0-33 9.1-9.1 23.9-9.1 33 0l53.4 53.3 55.5-53.6c9.2-8.9 24-8.7 33 0.6 9 9.2 8.7 24-0.6 33l-55.5 53.3h37.6z" fill="#2c2c2c" p-id="10476"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
1
src/assets/svg/fee.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295020643" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11515" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M683.604677 560.04317c-28.140302-46.866394-27.62866-47.68502-27.62866-47.685021s-97.007295 27.219346-115.017088-65.797142h-56.178275s-15.451584 93.118817-114.607775 65.592486c-28.651944 47.787349-29.675227 49.219946-29.675227 49.322274 0 0 77.564905 54.234036 0 127.808134l30.08454 49.526931s85.648846-36.940542 113.68682 63.955232h56.894573s17.805136-92.811832 114.198462-65.387829c27.424003-46.866394 27.833317-47.275707 27.833316-47.275707s-72.755471-62.829619 0.409314-130.059358zM511.590687 690.102528c-36.224243 0-65.592485-29.368242-65.592486-65.592485 0-36.224243 29.368242-65.592485 65.592486-65.592485 36.224243 0 65.592485 29.368242 65.592485 65.592485 0 36.224243-29.368242 65.592485-65.592485 65.592485z" fill="#2c2c2c" p-id="11516"></path><path d="M716.554412 255.718597c7.674628-12.791046 14.939942-25.684421 21.898271-38.168482 7.674628-14.121315 13.098031-24.865794 16.065554-31.210153C818.780454 77.462576 755.848506-1.22794 631.92885 35.81493c-12.381733 4.297792-30.903168 10.232837-52.903768 16.27021-13.405016 3.683821-26.912361 6.856001-40.522034 9.618867-15.349256 3.376836-31.005496 5.321075-46.764065 5.730389-11.767763 0-25.991406-1.534926-42.261617-4.40012-32.540422-6.242031-64.466873-15.04227-95.677026-26.093734C228.141101 0 166.437094 76.541621 230.187669 188.386529c2.455881 5.321075 8.80024 17.907465 17.805136 34.280004 9.107225 16.577196 18.930748 33.25672 29.265914 49.833917C116.296193 366.540222 9.874688 533.233137 9.874688 729.089637c0 47.889677 6.242031 95.063056 18.419106 140.701509 1.432597 9.925852 5.116419 22.409913 10.335166 34.075347l1.22794 3.479165 7.879285 22.61457h5.730388c30.596183 42.568602 83.090637 66.820426 146.431898 66.820426h625.32867c92.607175 0 159.836914-51.47117 170.888378-131.389628 11.870091-44.512841 17.702808-90.355951 17.60048-136.301389 0-209.159189-120.747477-386.187269-297.161587-473.37104zM930.727691 852.395323c-6.958329 48.810633-44.717498 77.564905-105.50055 77.564905H199.898471c-48.094334 0-82.476666-18.521435-98.030579-48.810633l-1.330268-2.353552-0.204657-0.818627c-3.274508-7.060658-5.423404-14.632957-6.651344-22.307585-11.153792-41.340662-16.884181-83.909264-16.98651-126.682522 0-183.372439 106.626162-337.78595 263.08624-414.327571l34.791646-16.884181-21.898271-31.824123c-23.637854-34.586989-44.717498-70.811232-63.341261-108.365744-34.893974-61.397022-22.716898-76.439292 43.591885-56.996902 9.925852 3.683821 29.368242 10.02818 52.699111 16.372539 17.907465 4.911762 35.303288 9.004897 51.880484 11.870091 19.851704 3.581493 37.963825 5.525732 54.131707 5.525732 17.293495 0 37.247527-2.455881 59.964425-6.958329 14.4283-2.865194 29.675227-6.549016 45.126811-10.846807 18.82842-5.116419 37.452183-10.846807 55.871291-17.293495 64.262216-19.135405 77.360248-3.069851 42.67093 55.564305-3.888478 7.879285-8.80024 17.702808-15.963226 30.698511-11.870091 21.898271-25.172779 44.512841-39.601079 66.615769L617.398221 286.519436l37.963826 15.144599C825.94344 369.507745 946.690916 533.130808 946.690916 728.987309c0 41.954632-5.525732 83.295293-15.963225 123.408014z m0 0" fill="#2c2c2c" p-id="11517"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
1
src/assets/svg/fee_share.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717294973537" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9231" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M736.3 722.8c-15.9 0-31.5-0.6-46.6-1.8-5.4 19-12.7 37.8-23.7 54.3-9.1 18-21.6 33.8-36.2 47.9 32 5.6 68.5 8.8 106.5 8.8 119.6 0 223.7-31.2 223.7-72.8v-93.6c-46.8 31.2-124.8 57.2-223.7 57.2zM192.5 201.1c7.7 5.2 15.5 10.4 20.7 18.1 7.7 5.2 12.9 12.9 18.1 20.7 2.6 5.2 7.7 10.3 10.4 15.5 5.2 5.2 7.7 10.3 10.3 15.5 2.6 5.2 7.7 12.9 10.3 18.1h173.3c2.6-5.2 7.7-10.3 10.4-18.1 2.6-5.2 5.2-10.3 10.3-15.5 2.6-2.6 5.2-5.2 7.7-10.4 5.2-7.7 10.3-15.5 15.5-20.7 5.2-7.7 12.9-12.9 23.2-20.7 5.2-2.6 10.3-5.2 12.9-10.3 2.6-5.2 5.2-7.7 5.2-12.9s0-7.7-2.6-12.9-5.2-7.7-10.3-10.3c-5.2-2.6-10.3-2.6-12.9-2.6-2.6 0-7.7 2.6-10.4 2.6-2.6 0-7.7 2.6-10.3 5.2-2.6 2.6-7.7 2.6-12.9 2.6s-10.3 0-12.9-2.6c-2.6-2.6-7.7-5.2-10.4-7.7-2.6-2.6-5.2-5.2-10.3-7.7-2.6-2.6-7.7-5.2-12.9-7.7-10.3-5.2-20.7-5.2-25.9-2.6-7.7 2.6-12.9 7.7-20.7 12.9-5.2 5.2-10.3 10.4-12.9 10.4-2.6 0-2.6 2.6-5.2 2.6-2.6-2.6-5.2-2.6-10.3-5.2-2.6-2.6-5.2-2.6-7.7-5.2l-7.7-7.7c-2.6-2.6-10.3-5.2-18.1-7.7-7.7-2.6-15.5 0-23.2 5.2-10.3 5.2-15.5 10.3-20.7 15.5-5.2 5.2-10.3 7.7-18.1 7.7h-15.5c-2.6-2.6-7.7-2.6-12.9-5.2s-10.3-2.6-15.5-2.6c-5.2 0-10.3 0-12.9 2.6-7.7 5.2-10.4 12.9-7.7 23.2 2.2 7.6 7.4 12.7 12.6 17.9z m447.6 393.2c-5.2-28.4-10.3-51.7-20.7-72.4-10.3-20.7-23.2-38.8-36.2-54.3-12.9-15.5-28.4-28.4-41.4-41.4-15.5-12.9-31-25.9-41.4-38.8-10.4-12.9-23.2-23.2-31.1-31.1-10.3-10.3-18.1-20.7-25.9-28.4H257.1c-5.2 10.3-15.5 20.7-23.2 31.1-7.7 10.3-18.1 20.7-28.4 31-10.3 10.3-25.9 23.2-38.8 36.2-15.5 15.5-31 31-46.6 49.1-15.5 18.1-25.9 38.8-36.2 59.5-10.4 20.7-15.5 43.9-18.1 69.8-2.6 25.9-2.6 51.8 2.6 77.6 5.2 23.2 12.9 49.1 28.4 72.4 12.9 23.2 31 46.6 56.9 67.3s51.7 36.2 85.3 49.1c33.7 13 72.6 18.2 116.5 18.2 41.4 0 80.2-5.2 113.8-15.5 33.6-10.4 62.1-25.9 85.3-43.9 23.2-18.1 43.9-38.8 56.9-64.6 15.5-23.2 23.2-51.7 28.4-77.6 2.7-33.8 5.3-64.9 0.2-93.3zM430.5 697.8c15.5 0 23.2 5.2 23.2 18.1 0 5.2 0 10.3-5.2 12.9-2.6 2.6-7.7 2.6-12.9 2.6h-56.9v15.5c0 5.2-2.6 10.3-5.2 15.5-5.2 5.2-10.3 7.7-15.5 5.2-7.7 0-12.9-2.6-15.5-5.2-5.2-2.6-7.7-7.7-7.7-15.5v-15.5h-59.5c-5.2 0-10.3-2.6-12.9-5.2-2.6-2.6-5.2-7.7-5.2-10.3 0-5.2 2.6-7.7 5.2-12.9 2.6-2.6 7.7-5.2 12.9-5.2h57v-28.4h-56.9c-5.2 0-10.3-2.6-12.9-5.2-2.6-2.6-5.2-7.7-5.2-10.4 0-2.6 2.6-7.7 5.2-12.9 2.6-2.6 7.7-5.2 12.9-5.2h56.9v-18.1L303.7 589c-7.7-7.7-12.9-15.5-20.7-20.7l-10.4-12.8c-2.6-2.6-5.2-7.7-7.7-12.9s0-12.9 2.6-18.1c5.2-5.2 10.3-7.7 18.1-5.2 7.7 2.6 12.9 5.2 18.1 10.3 2.6 2.6 5.2 7.7 10.3 12.9l41.4 41.4c10.3-7.7 18.1-15.5 25.9-23.2 7.7-5.2 12.9-12.9 20.7-18.1s10.3-10.3 12.9-12.9c5.2-5.2 10.3-7.7 15.5-7.7s10.4 2.6 15.5 7.7c7.7 7.7 5.2 18.1-7.7 28.4l-15.5 15.6-46.6 46.6v12.9h54.3c7.7 0 12.9 2.6 18.1 5.2 5.2 2.6 5.2 7.7 5.2 12.9s-2.6 10.3-5.2 12.9c-2.6 2.6-7.7 5.2-15.5 5.2h-54.3v28.4h51.8zM736.3 556.4c-16.3 0-31.9-0.6-46.9-1.7 2.8 11.2 5.1 23.1 7.5 36 4.7 25.9 3.4 53.9 1.1 83.9 12.3 1 25.1 1.5 38.2 1.5 119.6 0 208.1-41.6 223.7-83.2v-93.6c-46.7 36.3-124.7 57.1-223.6 57.1zM736.3 337.9c-72.8 3.2-139.7 17.9-181 39.5 10.2 10.5 22.8 21 35.4 31.5 14 14 30.7 28 44.7 44.7 12.6 15 25 32.5 35.5 52 20.4 2.5 42.3 3.9 65.4 3.9 119.6 0 208.1-41.6 223.7-83.2 0-46.8-98.8-88.4-223.7-88.4z" fill="#2c2c2c" p-id="9232"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
1
src/assets/svg/filing.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295344332" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22536" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M0 307.2h66.56l79.36 94.72H870.4L947.2 307.2h76.8v512c0 112.64-92.16 204.8-204.8 204.8H204.8c-112.64 0-204.8-92.16-204.8-204.8V307.2z m340.48 325.12V563.2c0-17.92-15.36-33.28-33.28-33.28s-33.28 15.36-33.28 33.28v102.4c0 17.92 15.36 33.28 33.28 33.28h427.52c17.92 0 33.28-15.36 33.28-33.28v-102.4c0-17.92-15.36-33.28-33.28-33.28s-33.28 15.36-33.28 33.28v69.12H340.48zM102.4 204.8h819.2v69.12L852.48 358.4h-680.96L102.4 273.92V204.8z m0-204.8h819.2v69.12L852.48 153.6h-680.96L102.4 69.12V0z" fill="#3B3B47" p-id="22537"></path></svg>
|
||||
|
After Width: | Height: | Size: 865 B |
1
src/assets/svg/home.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717296104869" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6006" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M554.965333 101.248l406.954667 373.034667a34.133333 34.133333 0 0 1-23.04 59.306666l-40.277333-0.042666v298.666666a85.333333 85.333333 0 0 1-85.333334 85.333334h-597.333333a85.333333 85.333333 0 0 1-85.333333-85.333334v-298.666666h-40.234667a34.133333 34.133333 0 0 1-23.04-59.264l406.912-373.034667a59.733333 59.733333 0 0 1 80.725333 0zM312.448 591.36a42.666667 42.666667 0 0 0 0 60.330667 279.978667 279.978667 0 0 0 395.946667 0 42.666667 42.666667 0 0 0-60.330667-60.330667 194.645333 194.645333 0 0 1-275.242667 0 42.666667 42.666667 0 0 0-60.373333 0z" fill="#2c2c2c" p-id="6007"></path></svg>
|
||||
|
After Width: | Height: | Size: 933 B |
1
src/assets/svg/implementation.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295325359" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="21461" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M854.016 889.514667l-41.642667-43.690667c10.922667-11.605333 25.941333-18.432 41.642667-18.432 32.768 0 59.392-27.989333 59.392-62.122667V144.725333c0-34.133333-26.624-62.122667-59.392-62.122666H263.509333c-32.768 0-59.392 27.989333-59.392 62.122666v5.461334c0 17.066667-6.826667 32.768-17.066666 43.690666L145.408 150.186667v-5.461334C145.408 75.776 197.973333 20.48 263.509333 20.48h591.189334c65.536 0 118.101333 55.296 118.101333 124.245333v620.544c-0.682667 68.949333-53.248 124.245333-118.784 124.245334zM86.016 268.970667v620.544c0 34.133333 26.624 62.122667 59.392 62.122666h591.189333c32.768 0 59.392-27.989333 59.392-62.122666V268.970667c0-34.133333-26.624-62.122667-59.392-62.122667H145.408c-32.768 0-59.392 27.989333-59.392 62.122667z m649.898667-124.245334c65.536 0 118.101333 55.296 118.101333 124.245334v620.544c0 68.266667-53.248 124.245333-118.101333 124.245333H145.408c-65.536 0-118.101333-55.296-118.101333-124.245333V268.970667c0-68.266667 53.248-124.245333 118.101333-124.245334h590.506667z" p-id="21462" fill="#2c2c2c"></path><path d="M735.914667 1024H145.408c-70.997333 0-128.341333-60.074667-128.341333-134.485333V268.970667c0-70.314667 52.565333-129.024 118.784-133.802667 4.096-69.632 60.074667-124.928 127.658666-124.928h591.189334c70.997333 0 128.341333 60.074667 128.341333 134.485333v620.544c0 70.314667-52.565333 129.024-118.784 133.802667-4.778667 70.314667-60.757333 124.928-128.341333 124.928zM135.850667 154.965333c-55.296 4.778667-98.986667 53.930667-98.986667 113.322667v620.544c0 62.805333 48.469333 114.005333 107.861333 114.005333h591.189334c58.026667 0 105.813333-49.152 107.861333-109.909333L805.546667 853.333333v36.181334c0 39.594667-31.402667 72.362667-69.632 72.362666H145.408c-38.229333 0-69.632-32.768-69.632-72.362666V268.970667c0-39.594667 31.402667-72.362667 69.632-72.362667h30.72l-40.277333-41.642667z m9.557333 62.122667c-26.624 0-49.152 23.210667-49.152 51.882667v620.544c0 28.672 21.845333 51.882667 49.152 51.882666h591.189333c26.624 0 49.152-23.210667 49.152-51.882666V268.970667c0-28.672-21.845333-51.882667-49.152-51.882667H145.408z m718.848 619.861333v41.642667c54.613333-5.461333 97.621333-53.930667 97.621333-113.322667V144.725333c0-62.805333-48.469333-114.005333-107.861333-114.005333H263.509333c-55.978667 0-102.4 45.738667-107.178666 103.765333h38.912c4.778667-34.816 33.450667-62.122667 68.949333-62.122666h591.189333c38.229333 0 69.632 32.768 69.632 72.362666v620.544c-1.365333 36.181333-27.306667 66.901333-60.757333 71.68z m-36.864 9.557334l17.066667 17.749333v-25.258667c-6.826667 1.365333-12.288 4.096-17.066667 7.509334zM197.973333 196.608h537.941334c38.229333 0 69.632 32.768 69.632 72.362667v569.344c10.24-10.922667 23.893333-17.749333 38.912-20.48V268.970667c0-62.805333-48.469333-114.005333-107.861334-114.005334H214.357333c-0.682667 15.018667-6.826667 30.037333-16.384 41.642667z m17.749334-62.122667h520.874666c70.997333 0 128.341333 60.074667 128.341334 134.485334v547.498666c21.845333-4.778667 38.912-25.941333 38.912-50.517333v-621.226667c0-28.672-21.845333-51.882667-49.152-51.882666H263.509333c-23.893333 0-43.690667 17.749333-47.786666 41.642666z m-51.882667 20.48l21.845333 23.210667c4.096-6.826667 6.826667-15.018667 7.509334-23.210667H163.84z" fill="#2c2c2c" p-id="21463"></path><path d="M162.474667 289.450667h372.736c17.066667 0 30.72 13.653333 30.72 30.72s-13.653333 30.72-30.72 30.72H162.474667c-17.066667 0-30.72-13.653333-30.72-30.72s13.653333-30.72 30.72-30.72z m559.104 62.122666c-17.066667 0-30.72-13.653333-30.72-30.72s13.653333-30.72 30.72-30.72 30.72 13.653333 30.72 30.72-13.653333 30.72-30.72 30.72zM69.632 434.176h744.789333v62.122667H69.632v-62.122667z" p-id="21464" fill="#2c2c2c"></path><path d="M824.661333 506.538667H59.392V423.936h765.269333v82.602667z m-744.789333-20.48h724.309333v-41.642667H79.872v41.642667z m641.706667-124.245334c-22.528 0-40.96-18.432-40.96-40.96s18.432-40.96 40.96-40.96 40.96 18.432 40.96 40.96-18.432 40.96-40.96 40.96z m0-62.122666c-11.605333 0-20.48 9.557333-20.48 20.48 0 11.605333 9.557333 20.48 20.48 20.48 11.605333 0 20.48-9.557333 20.48-20.48 0-11.605333-8.874667-20.48-20.48-20.48zM535.210667 361.813333H162.474667c-22.528 0-40.96-18.432-40.96-40.96s18.432-40.96 40.96-40.96h372.736c22.528 0 40.96 18.432 40.96 40.96s-18.432 40.96-40.96 40.96z m-372.736-62.122666c-11.605333 0-20.48 9.557333-20.48 20.48 0 11.605333 9.557333 20.48 20.48 20.48h372.736c11.605333 0 20.48-9.557333 20.48-20.48 0-11.605333-9.557333-20.48-20.48-20.48H162.474667z" fill="#2c2c2c" p-id="21465"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
1
src/assets/svg/initiation.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295270657" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16717" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M419.84 952.32c-10.24 0-15.36 0-25.6-5.12l-225.28-61.44c-46.08-15.36-76.8-61.44-61.44-107.52l168.96-640C286.72 92.16 337.92 61.44 384 76.8l230.4 56.32c46.08 10.24 76.8 61.44 61.44 107.52L506.88 885.76c-5.12 25.6-20.48 40.96-40.96 56.32-15.36 5.12-30.72 10.24-46.08 10.24z m-56.32-803.84h-5.12s-5.12 5.12-5.12 10.24l-174.08 640c0 5.12 0 15.36 10.24 15.36l225.28 61.44h10.24s5.12-5.12 5.12-10.24l174.08-640c0-5.12 0-15.36-10.24-15.36l-230.4-61.44c5.12 0 0 0 0 0z" p-id="16718"></path><path d="M604.16 168.96l-225.28-56.32c-25.6-10.24-56.32 5.12-61.44 35.84l-174.08 640c-5.12 25.6 10.24 56.32 35.84 61.44l225.28 61.44c25.6 5.12 56.32-10.24 61.44-35.84l174.08-640c5.12-30.72-10.24-56.32-35.84-66.56z m-128 348.16c-5.12 15.36-20.48 30.72-35.84 30.72h-10.24l-92.16-25.6c-20.48-5.12-35.84-25.6-25.6-51.2 5.12-15.36 20.48-30.72 35.84-30.72h10.24l92.16 25.6c20.48 10.24 30.72 30.72 25.6 51.2zM512 404.48c-5.12 15.36-20.48 25.6-35.84 25.6h-10.24l-97.28-25.6c-20.48-5.12-30.72-25.6-25.6-46.08 5.12-15.36 20.48-30.72 40.96-30.72h10.24l92.16 25.6c20.48 5.12 30.72 25.6 25.6 51.2z m240.64 532.48c-20.48 0-40.96-15.36-40.96-40.96V215.04c0-20.48 15.36-40.96 40.96-40.96s40.96 15.36 40.96 40.96V896c-5.12 25.6-20.48 40.96-40.96 40.96z m87.04-10.24c-5.12 0-15.36-5.12-15.36-15.36V209.92c0-5.12 5.12-15.36 15.36-15.36s15.36 5.12 15.36 15.36v701.44c-5.12 10.24-10.24 15.36-15.36 15.36z m40.96 0c-5.12 0-15.36-5.12-15.36-15.36V209.92c0-5.12 5.12-15.36 15.36-15.36S896 199.68 896 209.92v701.44c0 10.24-5.12 15.36-15.36 15.36z" p-id="16719"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
1
src/assets/svg/oran.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1720946136639" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4221" xmlns:xlink="http://www.w3.org/1999/xlink" width="128.125" height="128"><path d="M992.090881 443.129l-388.66-404.16C579.320881 13.934 546.998881 0.023 512.424881 0.023s-66.896 13.776-91.006 38.946L32.889881 443.129c-40.138 41.728-34.972 77.759-28.348 92.86 4.769 10.731 20.665 40.005 66.63 40.005l56.961 0 0 310.902c0 70.604 50.736 137.104 122.797 137.104l165.454 0L416.383881 694.949c0-35.236-5.298-54.974 30.733-54.974l130.745 0c36.031 0 30.733 19.605 30.733 54.974L608.594881 1024l165.321 0c72.063 0 122.797-66.499 122.797-137.104L896.712881 575.994l56.961 0c45.966 0 61.862-29.407 66.63-40.005C1026.927881 520.888 1032.094881 484.856 992.090881 443.129L992.090881 443.129zM953.676881 512.013 832.601881 512.013l0 374.884c0 35.237-22.784 72.99-58.815 72.99L672.446881 959.887 672.446881 694.949c0-70.604-22.652-118.956-94.717-118.956L446.985881 575.993c-72.063 0-94.717 48.352-94.717 118.956l0 265.069L250.929881 960.018c-36.031 0-58.816-37.754-58.816-72.99L192.113881 512.145 71.038881 512.145c-1.191 0-2.118-4.371-3.047-4.503 2.253-3.843 6.094-13.646 12.452-20.269l388.66-403.895c11.525-12.187 27.95-19.473 43.848-19.34 15.895-0.132 31.262 7.285 42.919 19.34L944.398881 487.24c6.358 6.623 10.199 16.426 12.32 20.269-0.796 0.132-1.856 4.503-3.047 4.503L953.676881 512.013z" fill="#909399" p-id="4222"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
1
src/assets/svg/project.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295208831" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15626" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M179.28 124.787c21.504 0 35.84 14.357 35.84 35.86 0 21.505-14.336 35.86-35.84 35.86-21.524 0-35.86-14.355-35.86-35.86 0-21.503 14.336-35.86 35.86-35.86z m0 358.541c21.504 0 35.84 14.356 35.84 35.86 0 21.524-14.336 35.86-35.84 35.86-21.524 0-35.86-14.336-35.86-35.86 0-21.504 14.336-35.86 35.86-35.86z m0 358.56h143.4c21.525 0 35.86 14.337 35.86 35.84 0 21.525-14.335 35.86-35.86 35.86H179.3c-21.524 0-35.86-14.335-35.86-35.86 0-21.503 14.336-35.84 35.86-35.84z" fill="#2c2c2c" p-id="15627"></path><path d="M888.41 318.163H125.832c-55.678 0.341-85.073-26.102-84.731-81.76V103.745c0.34-55.677 20.82-87.843 76.498-88.204h293.728s6.927-0.261 14.557 0c15.32 0.562 19.195 10.561 19.355 18.512 0.362 17.267 0 8.634 0 26.905 0 2.149-0.803 21.223-22.327 21.745-13.653 0.341-278.187 1.285-278.187 1.285-26.764 0.341-34.133 13.694-34.514 34.495v96.637c0 25.179 7.57 34.656 34.534 34.515h724.691c29.676 0.16 34.676-22.367 34.515-34.535v-96.597c0.924-11.344-4.819-35.58-34.515-35.78 0 0-465.177 0.823-478.77 0-17.83-1.064-22.387-8.071-22.428-20.68-0.06-17.69-0.662-8.574 0-26.183 0.382-9.939-2.61-19.737 22.609-20.28 6.224-0.16 11.284 0 11.284 0H883.21c55.657 0.342 89.59 45.98 89.931 101.658v119.186c0.342 55.657-29.113 82.12-84.73 81.759z m0 351.372H125.832c-55.678 0.342-85.073-26.102-84.731-81.759V455.118c0.34-55.678 20.82-87.843 76.498-88.205h293.728s6.927-0.26 14.557 0c15.32 0.562 19.195 10.562 19.355 18.513 0.362 17.267 0 8.633 0 26.905 0 2.148-0.803 21.223-22.327 21.745-13.653 0.34-278.187 1.285-278.187 1.285-26.764 0.341-34.133 13.693-34.514 34.494v96.638c0 25.178 7.57 34.655 34.534 34.515h724.691c29.676 0.16 34.676-22.368 34.515-34.535v-96.618c0.924-11.344-4.819-35.579-34.515-35.78 0 0-465.177 0.824-478.77 0-17.83-1.064-22.387-8.07-22.428-20.68-0.06-17.69-0.662-8.574 0-26.182 0.382-9.94-2.61-19.738 22.609-20.28 6.224-0.16 11.284 0 11.284 0H883.21c55.657 0.342 89.59 45.98 89.931 101.657v119.186c0.342 55.657-29.113 82.12-84.73 81.76z m0 351.373H125.832c-55.678 0.341-85.073-26.102-84.731-81.76V806.49c0.34-55.677 20.82-87.843 76.498-88.204h293.728s6.927-0.261 14.557 0c15.32 0.562 19.195 10.561 19.355 18.512 0.362 17.268 0 8.634 0 26.905 0 2.149-0.803 21.223-22.327 21.745-13.653 0.341-278.187 1.285-278.187 1.285-26.764 0.342-34.133 13.694-34.514 34.495v96.637c0 25.179 7.57 34.656 34.534 34.515h724.691c29.676 0.16 34.676-22.367 34.515-34.535v-96.617c0.924-11.344-4.819-35.58-34.515-35.78 0 0-465.177 0.823-478.77 0-17.83-1.064-22.387-8.071-22.428-20.68-0.06-17.69-0.662-8.574 0-26.183 0.382-9.939-2.61-19.737 22.609-20.28 6.224-0.16 11.284 0 11.284 0H883.21c55.657 0.342 89.59 45.98 89.931 101.658v119.186c0.342 55.657-29.113 82.12-84.73 81.759z" fill="#2c2c2c" p-id="15628"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
1
src/assets/svg/project_requirement.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295421269" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="23541" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M918.112262 0.279019H282.088283c-57.896458 0-105.050681 43.805995-105.050681 97.656676v53.013624H60.965668C27.762398 150.949319 0.837057 177.874659 0.837057 211.077929v752.653951c0 33.20327 26.925341 60.12861 60.128611 60.12861h736.889373c33.20327 0 60.12861-26.925341 60.12861-60.12861v-33.900817h60.26812c57.896458 0 105.050681-43.805995 105.050681-97.656676V97.935695c-0.13951-53.850681-47.293733-97.656676-105.19019-97.656676zM734.378202 343.751499c0 20.089373-16.183106 36.27248-36.27248 36.272479h-417.133515c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248h417.133515c20.089373 0 36.27248 16.183106 36.27248 36.27248z m0 251.814714c0 20.089373-16.183106 36.27248-36.27248 36.272479h-417.133515c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248h417.133515c20.089373 0 36.27248 16.183106 36.27248 36.27248zM146.345504 879.607629c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248 36.27248 16.183106 36.27248 36.27248c0 19.949864-16.183106 36.27248-36.27248 36.272479z m0-247.768937c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248 36.27248 16.183106 36.27248 36.27248-16.183106 36.27248-36.27248 36.272479z m0-251.814714c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248 36.27248 16.183106 36.27248 36.27248c0 19.949864-16.183106 36.27248-36.27248 36.272479z m551.760218 499.583651h-417.133515c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248h417.133515c20.089373 0 36.27248 16.183106 36.27248 36.27248 0 19.949864-16.183106 36.27248-36.27248 36.272479z m252.512262-47.572752c0 13.671935-14.92752 25.111717-32.505722 25.111717h-60.26812V210.93842c0-33.20327-26.925341-60.12861-60.128611-60.128611H249.582561v-53.013624c0-13.671935 14.92752-25.111717 32.505722-25.111716H917.972752c17.578202 0 32.505722 11.579292 32.505722 25.111716v734.238692z" p-id="23542"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
1
src/assets/svg/requirement.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295441926" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="24673" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M834.021053 560.505263l-56.589474-56.589474c-10.778947-10.778947-26.947368-10.778947-37.726316 0l-245.221052 245.221053c-8.084211 40.421053-13.473684 80.842105-21.557895 118.568421 40.421053-5.389474 80.842105-13.473684 121.263158-21.557895l245.221052-245.221052c8.084211-8.084211 10.778947-21.557895 5.389474-29.642105-5.389474 0-8.084211-5.389474-10.778947-10.778948zM747.789474 673.684211c-10.778947 5.389474-24.252632 5.389474-32.336842-2.694737l-40.421053-40.421053c-5.389474-5.389474-8.084211-16.168421-8.084211-24.252632 2.694737-10.778947 8.084211-18.863158 18.863158-21.557894 10.778947-2.694737 18.863158 0 26.947369 5.389473l37.726316 37.726316c5.389474 5.389474 8.084211 8.084211 8.08421 16.168421 2.694737 10.778947-2.694737 21.557895-10.778947 29.642106z m59.28421-61.978948c-5.389474 8.084211-16.168421 10.778947-26.947368 10.778948-5.389474 0-10.778947-2.694737-16.168421-8.084211L726.231579 576.673684c-2.694737-2.694737-5.389474-8.084211-8.084211-13.473684-2.694737-13.473684 8.084211-29.642105 21.557895-32.336842 8.084211-2.694737 16.168421 0 24.252632 5.389474l32.336842 32.336842 10.778947 10.778947c8.084211 13.473684 8.084211 24.252632 0 32.336842z" p-id="24674"></path><path d="M993.010526 102.4c-5.389474-18.863158-13.473684-37.726316-24.252631-51.2C949.894737 26.947368 925.642105 10.778947 896 2.694737c-10.778947 0-21.557895-2.694737-32.336842-2.694737H146.863158C79.494737 8.084211 28.294737 61.978947 25.6 129.347368v762.610527c2.694737 64.673684 48.505263 118.568421 113.178947 129.347368 5.389474 2.694737 13.473684 2.694737 21.557895 2.694737h706.021053c8.084211 0 16.168421 0 21.557894-2.694737 53.894737-10.778947 97.010526-53.894737 107.789474-107.789474 2.694737-13.473684 2.694737-26.947368 2.694737-43.115789v-727.578947c-2.694737-13.473684-2.694737-26.947368-5.389474-40.421053zM243.873684 223.663158h530.863158c10.778947 0 18.863158 5.389474 24.252632 13.473684 2.694737 5.389474 5.389474 10.778947 5.389473 13.473684 0 13.473684-13.473684 26.947368-26.947368 26.947369H246.568421c-13.473684 0-26.947368-13.473684-26.947368-26.947369s10.778947-26.947368 24.252631-26.947368z m-18.863158 231.747368c5.389474-5.389474 8.084211-8.084211 16.168421-10.778947h296.421053c5.389474 0 10.778947 2.694737 16.168421 5.389474 13.473684 8.084211 16.168421 26.947368 8.084211 37.726315-5.389474 8.084211-13.473684 10.778947-24.252632 10.778948H246.568421c-5.389474 0-10.778947-2.694737-16.168421-5.389474-13.473684-8.084211-16.168421-26.947368-5.389474-37.726316z m164.378948 245.221053c-5.389474 8.084211-13.473684 13.473684-21.557895 13.473684H241.178947c-8.084211 0-16.168421-8.084211-18.863158-13.473684-2.694737-5.389474-2.694737-13.473684-2.694736-18.863158 2.694737-10.778947 13.473684-18.863158 24.252631-21.557895h121.263158c5.389474 0 8.084211 0 13.473684 2.694737 10.778947 8.084211 16.168421 24.252632 10.778948 37.726316z m487.747368-59.284211l-250.610526 250.610527c-5.389474 5.389474-13.473684 8.084211-21.557895 8.08421l-161.68421 26.947369c-13.473684 2.694737-26.947368-5.389474-29.642106-18.863158v-13.473684l29.642106-164.378948c0-5.389474 2.694737-10.778947 5.389473-13.473684 59.284211-59.284211 118.568421-118.568421 177.852632-180.547368l53.894737-53.894737c10.778947-13.473684 24.252632-24.252632 37.726315-32.336842 8.084211-5.389474 18.863158-8.084211 26.947369-8.084211 24.252632-2.694737 48.505263 5.389474 67.368421 21.557895l61.978947 61.978947c10.778947 10.778947 18.863158 21.557895 21.557895 35.031579 8.084211 32.336842 0 61.978947-18.863158 80.842105z" p-id="24675"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
1
src/assets/svg/special_fund.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295133873" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12684" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M568.917333 852.48h-277.703111a27.306667 27.306667 0 0 1-27.306666-27.221333 27.335111 27.335111 0 0 1 27.306666-27.278223h71.111111l99.555556-99.356444 0.824889-0.739556a27.818667 27.818667 0 0 1 3.925333-2.986666H158.606222a53.020444 53.020444 0 0 1-52.963555-52.963556V245.703111a53.020444 53.020444 0 0 1 52.963555-52.963555h659.911111a53.191111 53.191111 0 0 1 53.048889 52.963555v266.268445h-259.982222a42.666667 42.666667 0 0 0-42.666667 42.666666v140.060445H495.786667a20.906667 20.906667 0 0 1 4.664889 3.754666 4.835556 4.835556 0 0 1 1.109333 1.194667l67.384889 67.470222v85.333334z m-114.887111-349.866667v52.849778h52.878222V502.613333h79.274667v-52.849777h-79.274667v-26.396445h79.274667v-52.878222h-54.044444l41.728-42.012445-37.262223-37.262222-55.978666 55.978667-56.064-55.978667-37.546667 37.262222 42.012445 42.012445h-54.044445v52.878222h79.274667v26.396445h-79.274667v52.849777z" p-id="12685" fill="#2c2c2c"></path><path d="M909.482667 583.765333A43.150222 43.150222 0 0 0 866.161778 540.444444h-225.479111a43.150222 43.150222 0 0 0-43.320889 43.320889v226.247111A43.150222 43.150222 0 0 0 640.682667 853.333333h226.247111a43.150222 43.150222 0 0 0 43.320889-43.320889z m-81.464889 104.049778v0.369778a19.484444 19.484444 0 0 1-26.652445 0l-34.446222-33.336889v138.496a18.887111 18.887111 0 0 1-37.774222-0.369778v-139.235555l-35.157333 35.185777a18.602667 18.602667 0 0 1-25.912889-26.652444l65.422222-65.422222a18.488889 18.488889 0 0 1 12.970667-5.176889 19.000889 19.000889 0 0 1 12.600888 4.807111c0.369778 0.739556 1.109333 1.109333 1.479112 1.479111a0.369778 0.369778 0 0 0 0.369777 0.369778l0.369778 0.369778 66.275556 63.687111 0.369777 0.369778a17.664 17.664 0 0 1 0.085334 25.059555z" p-id="12686" fill="#2c2c2c"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
1
src/assets/svg/summary.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295457045" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="25716" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M170.666667 34.133333h659.911111c34.133333 0 68.266667 17.066667 96.711111 39.822223 22.755556 22.755556 34.133333 51.2 34.133333 85.333333V534.755556c-5.688889 11.377778-22.755556 17.066667-34.133333 11.377777-45.511111-22.755556-91.022222-28.444444-142.222222-28.444444-39.822222 0-79.644444 11.377778-119.466667 34.133333-56.888889 34.133333-102.4 85.333333-125.155556 147.911111-22.755556 68.266667-22.755556 142.222222 5.688889 210.488889 5.688889 17.066667 11.377778 28.444444 22.755556 39.822222l5.688889 5.688889c5.688889 5.688889 5.688889 17.066667 0 22.755556-5.688889 5.688889-11.377778 11.377778-22.755556 11.377778H170.666667c-34.133333 0-62.577778-11.377778-85.333334-39.822223-22.755556-22.755556-39.822222-56.888889-34.133333-91.022222V153.6c0-28.444444 5.688889-51.2 22.755556-73.955556 17.066667-28.444444 51.2-51.2 85.333333-56.888888 0 11.377778 5.688889 11.377778 11.377778 11.377777z m73.955555 210.488889c-11.377778 0-17.066667 11.377778-17.066666 17.066667 0 5.688889 0 17.066667 5.688888 22.755555 5.688889 5.688889 11.377778 5.688889 17.066667 5.688889h506.311111c11.377778-5.688889 17.066667-17.066667 17.066667-28.444444s-11.377778-22.755556-22.755556-22.755556H250.311111c0 5.688889-5.688889 5.688889-5.688889 5.688889m5.688889 204.8c-5.688889 0-11.377778 5.688889-17.066667 11.377778-5.688889 11.377778-5.688889 22.755556 0 28.444444 5.688889 5.688889 11.377778 11.377778 17.066667 11.377778h273.066667c5.688889 0 17.066667-5.688889 22.755555-11.377778 5.688889-5.688889 5.688889-17.066667 0-28.444444-5.688889-5.688889-11.377778-11.377778-22.755555-11.377778H250.311111z" fill="#2c2c2c" p-id="25717"></path><path d="M625.777778 989.866667c-11.377778-5.688889-28.444444-11.377778-45.511111-17.066667 17.066667-39.822222 28.444444-73.955556 39.822222-113.777778l45.511111 17.066667c-11.377778 45.511111-22.755556 85.333333-39.822222 113.777778z m5.688889-159.288889v-170.666667h79.644444l-34.133333-51.2 56.888889-17.066667c17.066667 17.066667 28.444444 39.822222 45.511111 62.577778l-17.066667 5.688889h62.577778c17.066667-28.444444 34.133333-51.2 39.822222-68.266667l56.888889 17.066667c-11.377778 17.066667-22.755556 34.133333-39.822222 51.2h79.644444v170.666667h-159.288889c5.688889 5.688889 22.755556 28.444444 51.2 62.577778l-45.511111 34.133333c-17.066667-28.444444-34.133333-51.2-51.2-68.266667l39.822222-28.444444h-164.977777z m56.888889-125.155556v73.955556h216.177777v-73.955556h-216.177777z m56.888888 307.2c-22.755556 0-34.133333-5.688889-45.511111-17.066666-11.377778-11.377778-17.066667-28.444444-17.066666-51.2v-85.333334h51.2v73.955556c0 22.755556 11.377778 34.133333 34.133333 28.444444h56.888889c11.377778 0 22.755556 0 28.444444-5.688889 5.688889-5.688889 11.377778-11.377778 11.377778-17.066666 0-11.377778 5.688889-22.755556 5.688889-39.822223l51.2 17.066667c-5.688889 28.444444-11.377778 45.511111-11.377778 56.888889-5.688889 17.066667-11.377778 22.755556-22.755555 34.133333-11.377778 5.688889-28.444444 11.377778-45.511111 11.377778h-96.711112z m216.177778-34.133333c-22.755556-39.822222-39.822222-73.955556-56.888889-102.4l45.511111-22.755556c22.755556 39.822222 45.511111 73.955556 62.577778 102.4l-51.2 22.755556z" fill="#2c2c2c" p-id="25718"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
407
src/components/AttachmentUpload.vue
Normal file
@@ -0,0 +1,407 @@
|
||||
<template>
|
||||
<el-form :model="formData" ref="applyForm" :rules="rules" :label-position="labelPosition">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item :label="label" prop="attachment" label-width="125">
|
||||
<template v-if="preview&&JSON.stringify(singleFile) !== '{}'&&JSON.stringify(singleFile)!=='null'">
|
||||
<el-button type="primary" link @click="handleDownload(singleFile)" style="font-size: 16px">
|
||||
{{ singleFile ? singleFile?.originalFileName : formData.singleFile?.originalFileName }}
|
||||
</el-button>
|
||||
<el-button type="danger" link @click="deleteSingleFile(singleFile?singleFile:formData.singleFile,1)">删除
|
||||
</el-button>
|
||||
</template>
|
||||
<template
|
||||
v-else-if="!preview||JSON.stringify(singleFile) == '{}'||singleFile==null||formData.singleFile==null">
|
||||
<file-upload @getFile="getAttachment" :multiple="false"
|
||||
:disabled="isSingleFile" ref="fileUploadRef"/>
|
||||
<!-- :showFileList="showFileList" @delete="deleteAttachment"-->
|
||||
<fvTable style="width: 100%;max-height: 80px;" v-if="showSingleTable" height="80" :tableConfig="singleTableConfig"
|
||||
:data="_singleFileValue" :isSettingCol="false" :pagination="false">
|
||||
</fvTable>
|
||||
</template>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="其他文件" label-width="125">
|
||||
<file-upload @getFile="getOtherFile"/>
|
||||
<fvTable style="width: 100%;max-height: 162px;" v-if="showTable" height="162" :tableConfig="tableConfig"
|
||||
:data="allFileList" :isSettingCol="false" :pagination="false">
|
||||
<template #empty>
|
||||
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
|
||||
</template>
|
||||
</fvTable>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import FileUpload from '@/components/FileUpload.vue'
|
||||
import {deleteFile, downloadFile} from "@/api/project-demand";
|
||||
import {ElMessageBox, ElNotification} from "element-plus";
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
showFileList: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: '项目附件'
|
||||
},
|
||||
showTable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showSingleTable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
preview: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
singleList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
otherFileList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
formData: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
labelPosition: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
tag: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(["getAttachment", "getOtherFile","update:singleList"])
|
||||
const tableConfig = reactive({
|
||||
columns: [
|
||||
{
|
||||
prop: 'index',
|
||||
type: 'index',
|
||||
label: '序号',
|
||||
align: 'center',
|
||||
width: '80',
|
||||
},
|
||||
{
|
||||
prop: 'originalFileName',
|
||||
label: '文件名',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'tag',
|
||||
label: '标签',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'size',
|
||||
label: '文件大小',
|
||||
align: 'center',
|
||||
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||
},
|
||||
{
|
||||
prop: 'oper',
|
||||
label: '操作',
|
||||
align: 'center',
|
||||
showOverflowTooltip: false,
|
||||
currentRender: ({row, index}) => {
|
||||
let btn = []
|
||||
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
|
||||
// if (row.newFile) {
|
||||
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
|
||||
// }
|
||||
return (
|
||||
<div style={{width: '100%'}}>
|
||||
{
|
||||
btn.map(item => (
|
||||
<el-button
|
||||
type={item.type}
|
||||
onClick={() => item.func()}
|
||||
link
|
||||
>
|
||||
{item.label}
|
||||
</el-button>
|
||||
))
|
||||
}
|
||||
{
|
||||
row.newFile || props.preview || !props.preview ?
|
||||
<popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
|
||||
// perm={['']}
|
||||
onDelete={() => handleDelete(row)}/>
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const singleTableConfig = reactive({
|
||||
columns: [
|
||||
{
|
||||
prop: 'index',
|
||||
type: 'index',
|
||||
label: '序号',
|
||||
align: 'center',
|
||||
width: '80',
|
||||
},
|
||||
{
|
||||
prop: 'originalFileName',
|
||||
label: '文件名',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'tag',
|
||||
label: '标签',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'size',
|
||||
label: '文件大小',
|
||||
align: 'center',
|
||||
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||
},
|
||||
{
|
||||
prop: 'oper',
|
||||
label: '操作',
|
||||
align: 'center',
|
||||
showOverflowTooltip: false,
|
||||
currentRender: ({row, index}) => {
|
||||
let btn = []
|
||||
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
|
||||
// if (row.newFile) {
|
||||
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
|
||||
// }
|
||||
return (
|
||||
<div style={{width: '100%'}}>
|
||||
{
|
||||
btn.map(item => (
|
||||
<el-button
|
||||
type={item.type}
|
||||
onClick={() => item.func()}
|
||||
link
|
||||
>
|
||||
{item.label}
|
||||
</el-button>
|
||||
))
|
||||
}
|
||||
{
|
||||
row.newFile || props.preview || !props.preview ?
|
||||
<popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
|
||||
// perm={['']}
|
||||
onDelete={() => handleSingleDelete(row)}/>
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const fileUploadRef = ref()
|
||||
const rules = reactive({
|
||||
attachment: [{required: true, message: '请上传附件', trigger: ['blur', 'change']}],
|
||||
})
|
||||
const applyForm = ref()
|
||||
const singleFile = ref(props.formData.singleFile)
|
||||
const isSingleFile = ref(false)
|
||||
const allFileList = ref([])
|
||||
const deleteFileVal = ref({})
|
||||
const singleFileList = ref([])
|
||||
if(localStorage.getItem('singleFile')){
|
||||
singleFile.value = JSON.parse(localStorage.getItem('singleFile'))
|
||||
}
|
||||
const _singleFileValue = computed({
|
||||
get() {
|
||||
return props.singleList;
|
||||
},
|
||||
set(value) {
|
||||
emit('update:singleList', value)
|
||||
}
|
||||
})
|
||||
|
||||
// console.log('_singleFileValue',_singleFileValue.value)
|
||||
const _otherFileListValue = computed({
|
||||
get() {
|
||||
return props.otherFileList;
|
||||
},
|
||||
set(value) {
|
||||
emit('update:otherFileList', value)
|
||||
}
|
||||
})
|
||||
if(_otherFileListValue.value&&_otherFileListValue.value.length>0){
|
||||
_otherFileListValue.value.forEach(item=>{
|
||||
allFileList.value.push(item)
|
||||
})
|
||||
}
|
||||
watch(() => props.showSingleTable, (newVal) => {
|
||||
props.showSingleTable = newVal
|
||||
}, {deep: true})
|
||||
watch(() => props.formData.fileList, (newVal) => {
|
||||
if (props.preview) {
|
||||
newVal?.forEach(item => {
|
||||
allFileList.value.push(item)
|
||||
})
|
||||
}
|
||||
}, {immediate: true})
|
||||
// watch(() => props.otherFileList, (newVal) => {
|
||||
// props.otherFileList=newVal
|
||||
// if (props.preview) {
|
||||
// console.log('newotherFileList', newVal,props.preview,props.formData.fileList)
|
||||
// if (props.formData.fileList === null || props.formData.fileList?.length === 0) {
|
||||
// allFileList.value = newVal
|
||||
// } else {
|
||||
// console.log('props.otherFileList',props.otherFileList)
|
||||
// // props.otherFileList?.forEach(item => {
|
||||
// // allFileList.value.push(item)
|
||||
// // })
|
||||
// }
|
||||
// } else {
|
||||
// allFileList.value = newVal
|
||||
// }
|
||||
// }, {deep: true})
|
||||
watch(() => props.showTable, (newVal) => {
|
||||
props.showTable = newVal
|
||||
}, {deep: true})
|
||||
// watch(() => props.singleList, (newVal) => {
|
||||
// console.log('singleFile', newVal)
|
||||
// singleFileList.value = newVal
|
||||
// }, {deep: true})
|
||||
watch(() => props.formData.singleFile, (newVal) => {
|
||||
// console.log('singleFile', newVal)
|
||||
singleFile.value = newVal
|
||||
props.formData.singleFile=newVal
|
||||
}, {deep: true})
|
||||
watch(() => isSingleFile.value, (newVal) => {
|
||||
isSingleFile.value = newVal
|
||||
}, {deep: true})
|
||||
watch(() => singleFile.value, (newVal) => {
|
||||
singleFile.value = newVal
|
||||
}, {deep: true})
|
||||
const handleDelete = (row, type) => {
|
||||
deleteFile(row.fileId).then(res => {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: res.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
if (res.code === 1000) {
|
||||
if (type === 'single') {
|
||||
_singleFileValue.value.splice(_singleFileValue.value.findIndex((item) => item.fileId === row.fileId), 1);
|
||||
isSingleFile.value = false
|
||||
} else {
|
||||
allFileList.value.splice(allFileList.value.findIndex((item) => item.fileId === row.fileId), 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
const handleSingleDelete = (row) => {
|
||||
// console.log('row',row)
|
||||
// fileUploadRef.value.handleRemove(deleteFileVal.value.id)
|
||||
handleDelete(row, 'single')
|
||||
}
|
||||
const getAttachment = (val) => {
|
||||
// console.log('getAttachment', val)
|
||||
isSingleFile.value = true
|
||||
// deleteFileVal.value=val
|
||||
emit('getAttachment', val)
|
||||
}
|
||||
const compositeParam = (item) => {
|
||||
return {
|
||||
fileId: item.id,
|
||||
size: item.size,
|
||||
originalFileName: item.originalFilename,
|
||||
fileType: item.fileType,
|
||||
url: item.url,
|
||||
newFile: true,
|
||||
tag: props.tag
|
||||
}
|
||||
}
|
||||
const getOtherFile = (val) => {
|
||||
if (props.preview) {
|
||||
allFileList.value.push(compositeParam(val))
|
||||
} else {
|
||||
allFileList.value = _otherFileListValue.value
|
||||
}
|
||||
emit('getOtherFile', val)
|
||||
}
|
||||
const deleteAttachment = (val) => {
|
||||
deleteFile(val).then(res => {
|
||||
if (res.code === 1000) {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: "删除成功",
|
||||
type: 'success'
|
||||
})
|
||||
isSingleFile.value = false
|
||||
singleFile.value = null
|
||||
}
|
||||
});
|
||||
}
|
||||
const deleteSingleFile = (row, type) => {
|
||||
ElMessageBox.confirm(`确认删除名称为${row.originalFileName}的文件吗?`, '系统提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteFile(row.fileId).then(res => {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: res.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
if (res.code === 1000) {
|
||||
isSingleFile.value = false
|
||||
if (type === 1) {
|
||||
singleFile.value = null
|
||||
} else {
|
||||
props.otherFileList.splice(props.otherFileList.findIndex((item) => item.fileId === row.fileId), 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}).catch(() => {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: "用户取消删除! ",
|
||||
type: 'warning'
|
||||
})
|
||||
})
|
||||
}
|
||||
const handleDownload = (row) => {
|
||||
downloadFile(row.fileId).then(res => {
|
||||
const blob = new Blob([res])
|
||||
let a = document.createElement('a')
|
||||
a.href = URL.createObjectURL(blob)
|
||||
a.download = row.originalFileName
|
||||
a.click()
|
||||
})
|
||||
}
|
||||
defineExpose({
|
||||
validate() {
|
||||
return applyForm.value.validate()
|
||||
},
|
||||
clearValidate() {
|
||||
return applyForm.value.clearValidate()
|
||||
},
|
||||
allFileList,
|
||||
singleFile,
|
||||
isSingleFile
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-table--fit ) {
|
||||
height: 300px !important;
|
||||
}
|
||||
</style>
|
||||
111
src/components/DetailComponent/AllocationSummaryDetail.vue
Normal file
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<el-button color="#DED0B2" style="float: right;margin: 0 10px 10px 0" @click="exportExcelHandler">导出</el-button>
|
||||
<el-table ref="table" :data="tableData" style="width: 100%;height: 479px" :show-summary="true" border
|
||||
:summary-method="getSummaries" v-loading="loading" :header-cell-style="{background:'#f5f7fa'}">
|
||||
<el-table-column type="index" label="序号" align="center" width="60"/>
|
||||
<el-table-column prop="projectName" label="项目名称" align="center"/>
|
||||
<el-table-column prop="projectCost" label="费用性质" align="center">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.projectCost !== null">
|
||||
<Tag dictType="project_cost" :value="scope.row.projectCost"/>
|
||||
</div>
|
||||
<div v-else>--</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="researchStage" label="研发阶段" align="center">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.researchStage !== null && scope.row.researchStage !== null && scope.row.researchStage !== undefined">
|
||||
<el-tag effect="plain">{{scope.row.researchStage==1?'开发阶段':'研究阶段'}}</el-tag>
|
||||
</div>
|
||||
<div v-else>--</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="afterTax" label="分摊金额" align="center">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.afterTax !== null">
|
||||
<!-- {{ toThousands(scope.row.afterTax) }}-->
|
||||
{{ scope.row.afterTax }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- <Tag dictType="research_stage" :value="scope.row.researchStage"/>-->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {getAllocationSummaryDetails} from "@/api/expense-manage";
|
||||
import {shareExportExcel} from "@/api/expense-manage";
|
||||
|
||||
const props = defineProps({
|
||||
allocationName :{
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const tableData = ref()
|
||||
const loading = ref(false)
|
||||
const table = ref()
|
||||
const route = useRoute()
|
||||
const getSummaries = (param) => {
|
||||
const {columns, data} = param
|
||||
const sums = []
|
||||
columns.forEach((column, index) => {
|
||||
if (index === 0) {
|
||||
sums[index] = '小计'
|
||||
} else if (index === 4) {
|
||||
const values = data.map((item) => Number(item[column.property]))
|
||||
if (!values.every((value) => Number.isNaN(value))) {
|
||||
sums[index] = `${values.reduce((prev, curr) => {
|
||||
const value = Number(curr)
|
||||
if (!Number.isNaN(value)) {
|
||||
return prev + curr
|
||||
} else {
|
||||
return prev
|
||||
}
|
||||
}, 0)}`
|
||||
sums[index] = parseFloat(sums[index]).toFixed(2)
|
||||
// sums[index] = toThousands(sums[index])
|
||||
} else {
|
||||
sums[index] = '-'
|
||||
}
|
||||
}
|
||||
})
|
||||
return sums
|
||||
}
|
||||
// const exportTable = () => {
|
||||
// const $e = table.value.$el
|
||||
// let $table = $e.querySelector('.el-table__fixed')
|
||||
// if (!$table) {
|
||||
// $table = $e
|
||||
// }
|
||||
// exportExcel($table, (5 + (Object.keys(tableData.value[0]).length - 5) * 5), "四川省国有资产经营投资管理有限责任公司科技创新项目费用分摊表", 2)
|
||||
// }
|
||||
const exportExcelHandler = () => {
|
||||
shareExportExcel(route.query.id).then(res => {
|
||||
console.log(res)
|
||||
let fileName = `科技创新项目费用分摊表-${props.allocationName}.zip`
|
||||
const blob = new Blob([res.data])
|
||||
let a = document.createElement('a')
|
||||
a.href = URL.createObjectURL(blob)
|
||||
a.download = fileName
|
||||
a.click()
|
||||
})
|
||||
}
|
||||
const init = () => {
|
||||
loading.value = true
|
||||
let params = {
|
||||
allocationId: route.query.id
|
||||
}
|
||||
getAllocationSummaryDetails(params).then(res => {
|
||||
tableData.value = res.data
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
init()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
446
src/components/DetailComponent/ApprovalDetail.vue
Normal file
@@ -0,0 +1,446 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-row v-if="type==='execute'">
|
||||
<el-col :span="24">
|
||||
<baseTitle :title="'附件信息'"></baseTitle>
|
||||
</el-col>
|
||||
<el-form :model="attachmentParam" inline style="margin-top: 15px">
|
||||
<el-form-item label="标签" prop="tag">
|
||||
<el-select v-model="attachmentParam.tag" placeholder="请选择标签" clearable filterable style="width: 300px">
|
||||
<el-option
|
||||
v-for="item in tagsOption"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleSearchImplementationFileList" color="#DED0B2">搜索</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<fvTable style="width: 100%;min-height:162px;max-height: 162px" v-if="showAttachmentTable" height="162"
|
||||
:tableConfig="tableConfig"
|
||||
:data="otherAttachmentList" :isSettingCol="false" :pagination="false">
|
||||
<template #empty>
|
||||
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
|
||||
</template>
|
||||
</fvTable>
|
||||
</el-row>
|
||||
|
||||
<baseTitle v-if="type!='phase'" :title="getTagName(type)+getTitleInfo(data.taskId)"></baseTitle>
|
||||
<fvForm :schema="schema" @getInstance="(e)=>form = e"></fvForm>
|
||||
<el-form :model="formData" label-width="auto" style="margin-top: -15px">
|
||||
<file-component :title="getTagName(type)+'附件'" :tag="getTagName(type)"
|
||||
v-model:value="formData.fileList" :processViewer="processViewer"
|
||||
:file-list-show="fileListShow"/>
|
||||
</el-form>
|
||||
<div v-if="data.taskId">
|
||||
<baseTitle title="审核意见"></baseTitle>
|
||||
<el-form-item prop="_value">
|
||||
<el-input
|
||||
v-model="_value"
|
||||
:rows="3"
|
||||
type="textarea"
|
||||
placeholder="请输入审核意见"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="approval-record">
|
||||
<div class="approval-title" style="margin-top: -15px">
|
||||
<baseTitle title="审批记录"></baseTitle>
|
||||
<div class="diagram">
|
||||
<div class="base-title">流程图</div>
|
||||
<el-switch
|
||||
v-model="changeDiagram"
|
||||
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="process">
|
||||
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
|
||||
:operation-list="data.operationList"
|
||||
:state="data.state"/>
|
||||
<process-diagram-viewer v-if="processViewer&&changeDiagram" :id-name="idName?idName:type"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import OperationRender from '@/views/workflow/common/OperationRender.vue'
|
||||
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
|
||||
import {ElLoading, ElNotification} from 'element-plus';
|
||||
import {downloadFile} from "@/api/project-demand";
|
||||
import {searchImplementationFileList} from "@/api/project-manage/attachment";
|
||||
import {getTags} from "@/api/project-manage";
|
||||
|
||||
const attachmentParam = reactive({
|
||||
tag: ''
|
||||
})
|
||||
const tagsOption = ref([])
|
||||
const uploadState = ref(false)
|
||||
const showAttachmentTable = ref(true)
|
||||
const otherAttachmentList = ref([])
|
||||
|
||||
const tableConfig = reactive({
|
||||
columns: [
|
||||
{
|
||||
prop: 'index',
|
||||
type: 'index',
|
||||
label: '序号',
|
||||
align: 'center',
|
||||
width: '80',
|
||||
},
|
||||
{
|
||||
prop: 'originalFileName',
|
||||
label: '文件名',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'tag',
|
||||
label: '标签',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'size',
|
||||
label: '文件大小',
|
||||
align: 'center',
|
||||
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||
},
|
||||
{
|
||||
prop: 'oper',
|
||||
label: '操作',
|
||||
align: 'center',
|
||||
showOverflowTooltip: false,
|
||||
currentRender: ({row, index}) => {
|
||||
return (
|
||||
<div>
|
||||
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const changeDiagram = ref(false)
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
processViewer: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
companyOption: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
fileListShow: {
|
||||
type: String,
|
||||
default: 'READ'
|
||||
},
|
||||
// approval 立项, execute 实施, 归档 archivist
|
||||
type: {
|
||||
type: String,
|
||||
default: 'approval'
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
idName: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
const form = ref()
|
||||
const schema = computed(() => {
|
||||
let arr
|
||||
if (props.type == 'approval') {
|
||||
arr = [
|
||||
{
|
||||
label: '项目负责人',
|
||||
prop: 'projectChargePerson',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: () => (
|
||||
<div>
|
||||
{
|
||||
props.formData.projectChargePerson ?
|
||||
<span>{props.formData.projectChargePerson.name} </span>
|
||||
: <span>{'--'}</span>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: '项目成员',
|
||||
prop: 'projectPersonList',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: () => (
|
||||
<div>
|
||||
{
|
||||
props.formData.projectPersonList ? props.formData.projectPersonList.map(item => {
|
||||
return <span>{item.name} </span>
|
||||
}) : <span>{'--'}</span>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: '前置流程',
|
||||
prop: 'preProcess',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: () => (
|
||||
<div>
|
||||
{
|
||||
props.formData.preProcess ? props.formData.preProcess.map(item => {
|
||||
return <span><a target="_blank" style={{color: '#409EFF', cursor: 'pointer'}}
|
||||
href={props.formData.preProcessBaseUrl + item.requestId}>{item.requestName}</a> </span>
|
||||
}) : <span>{'--'}</span>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: '项目立项附件',
|
||||
prop: 'singleFile',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: () => (
|
||||
<div>
|
||||
{
|
||||
props.formData.singleFile?.originalFileName ?
|
||||
<span
|
||||
style={{color: '#409EFF', cursor: 'pointer'}}
|
||||
onClick={() => handleDownload(props.formData.singleFile)}
|
||||
>
|
||||
{props.formData.singleFile?.originalFileName}
|
||||
</span> :
|
||||
<span>{'--'}</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
)
|
||||
},
|
||||
]
|
||||
} else if (props.type == 'execute') {
|
||||
arr = [
|
||||
{
|
||||
label: '前置流程',
|
||||
prop: 'preProcess',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: () => (
|
||||
<div>
|
||||
{
|
||||
props.formData.preProcess ? props.formData.preProcess.map(item => {
|
||||
return <span><a target="_blank" style={{color: '#409EFF', cursor: 'pointer'}}
|
||||
href={props.formData.preProcessBaseUrl + item.requestId}>{item.requestName}</a> </span>
|
||||
}) : <span>{'--'}</span>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: '项目验收附件',
|
||||
prop: 'singleFile',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: () => (
|
||||
<div>
|
||||
{
|
||||
props.formData.singleFile?.originalFileName ?
|
||||
<span
|
||||
style={{color: '#409EFF', cursor: 'pointer'}}
|
||||
onClick={() => handleDownload(props.formData.singleFile)}
|
||||
>
|
||||
{props.formData.singleFile?.originalFileName}
|
||||
</span> :
|
||||
<span>{'--'}</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
)
|
||||
},
|
||||
]
|
||||
} else if (props.type == 'archivist') {
|
||||
arr = [
|
||||
{
|
||||
label: '项目归档附件',
|
||||
prop: 'singleFile',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: () => (
|
||||
<div>
|
||||
{
|
||||
props.formData.singleFile?.originalFileName ?
|
||||
<span
|
||||
style={{color: '#409EFF', cursor: 'pointer'}}
|
||||
onClick={() => handleDownload(props.formData.singleFile)}
|
||||
>
|
||||
{props.formData.singleFile?.originalFileName}
|
||||
</span> :
|
||||
<span>{'--'}</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
)
|
||||
},
|
||||
]
|
||||
} else if (props.type == 'phase') {
|
||||
arr = [
|
||||
{
|
||||
label: '阶段变更附件',
|
||||
prop: 'singleFile',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: () => (
|
||||
<div>
|
||||
{
|
||||
props.formData.singleFile?.originalFileName ?
|
||||
<span
|
||||
style={{color: '#409EFF', cursor: 'pointer'}}
|
||||
onClick={() => handleDownload(props.formData.singleFile)}
|
||||
>
|
||||
{props.formData.singleFile?.originalFileName}
|
||||
</span> :
|
||||
<span>{'--'}</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
)
|
||||
},
|
||||
]
|
||||
}
|
||||
return arr
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
const emit = defineEmits(['update:value'])
|
||||
const _value = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(val) {
|
||||
emit("update:value", val);
|
||||
}
|
||||
})
|
||||
const getTagsOption = () => {
|
||||
if (!route.query.projectId) return
|
||||
getTags(route.query.projectId).then(res => {
|
||||
if (res.code === 1000) {
|
||||
tagsOption.value = res.data
|
||||
} else {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleSearchImplementationFileList = () => {
|
||||
let params = {
|
||||
targetId: route.query.projectId,
|
||||
targetState: "40"
|
||||
}
|
||||
if (attachmentParam.tag) {
|
||||
tagsOption.value.forEach(item => {
|
||||
if (item.value === attachmentParam.tag) {
|
||||
attachmentParam.tag = item.label
|
||||
}
|
||||
})
|
||||
params.tag = attachmentParam.tag
|
||||
}
|
||||
searchImplementationFileList(params).then(res => {
|
||||
showAttachmentTable.value = false
|
||||
if (res.code === 1000) {
|
||||
otherAttachmentList.value = res.data.fileList
|
||||
uploadState.value = res.data.upload
|
||||
nextTick(() => {
|
||||
showAttachmentTable.value = true
|
||||
})
|
||||
} else {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getTitleInfo = (taskId) => {
|
||||
if (taskId) {
|
||||
return '审批'
|
||||
} else {
|
||||
return '信息'
|
||||
}
|
||||
}
|
||||
const getTagName = (type) => {
|
||||
switch (type) {
|
||||
case 'approval':
|
||||
return '项目立项'
|
||||
case 'execute':
|
||||
return '项目验收'
|
||||
case 'archivist':
|
||||
return '项目归档'
|
||||
case 'phase':
|
||||
return '阶段变更'
|
||||
}
|
||||
}
|
||||
const handleDownload = (row) => {
|
||||
const loading = ElLoading.service({fullscreen: true})
|
||||
downloadFile(row.fileId).then(res => {
|
||||
const blob = new Blob([res])
|
||||
let a = document.createElement('a')
|
||||
a.href = URL.createObjectURL(blob)
|
||||
a.download = row.originalFileName
|
||||
a.click()
|
||||
loading.close()
|
||||
})
|
||||
}
|
||||
watchEffect(() => {
|
||||
Object.keys(props.formData).length && (form.value?.setValues(props.formData))
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// if (props.formData.mode == 'view' && props.type == 'execute') {
|
||||
// handleSearchImplementationFileList()
|
||||
// getTagsOption()
|
||||
// }
|
||||
})
|
||||
|
||||
if (props.formData.mode == 'view' && props.type == 'execute') {
|
||||
handleSearchImplementationFileList()
|
||||
getTagsOption()
|
||||
}
|
||||
watch(() => props.loading, (newVal) => {
|
||||
props.loading = newVal
|
||||
}, {deep: true})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
194
src/components/DetailComponent/CollectionDetail.vue
Normal file
@@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<baseTitle title="需求征集信息" v-if="type!=='singleDetail'"></baseTitle>
|
||||
<el-form :model="formData">
|
||||
<el-row>
|
||||
<el-col :span="6" v-if="type==='singleDetail'">
|
||||
<el-form-item label="征集名称">
|
||||
<span>{{ formData.requirementName }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="征集类型">
|
||||
<span>{{ formData.collectType }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="需求上报截止时间">
|
||||
<span>{{ formData.deadline }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6" v-if="formData.isSpecialFund">
|
||||
<el-form-item label="专项资金名称">
|
||||
<span>{{ formData.specialFund }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="type==='singleDetail'">
|
||||
<el-form-item label="征集公司">
|
||||
<span :class="showExpendClass(showMoreCompany,formData.companyIds)">{{
|
||||
getCompanyName(formData.companyIds)
|
||||
}}</span>
|
||||
<div style="color: #2a99ff;text-align: center;width: 100%;font-size: 15px;cursor: pointer"
|
||||
@click="handleExpend">{{ showExpendText }}
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24">
|
||||
<baseTitle title="征集说明"></baseTitle>
|
||||
<el-form-item>
|
||||
<el-card style="width: 100%">
|
||||
<div v-html="formData.collectExplain">
|
||||
</div>
|
||||
</el-card>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<baseTitle v-if="fileListShow === 'READ' || fileListShow === 'EDIT'" title="附件列表"></baseTitle>
|
||||
<el-col :span="24">
|
||||
<file-component title="" tag="需求征集"
|
||||
v-model:value="formData.fileList" :processViewer="processViewer"
|
||||
:file-list-show="fileListShow"/>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<div v-if="data.taskId">
|
||||
<baseTitle title="审核意见"></baseTitle>
|
||||
<el-form-item prop="_value">
|
||||
<el-input
|
||||
v-model="_value"
|
||||
:rows="3"
|
||||
type="textarea"
|
||||
placeholder="请输入审核意见"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="approval-record">
|
||||
<div class="approval-title">
|
||||
<baseTitle title="审批记录"></baseTitle>
|
||||
<div class="diagram">
|
||||
<div class="base-title">流程图</div>
|
||||
<el-switch
|
||||
v-model="changeDiagram"
|
||||
style="--el-switch-on-color:#BEA266; --el-switch-off-color:#cecdcd"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="process">
|
||||
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
|
||||
:operation-list="data.operationList"
|
||||
:state="data.state"/>
|
||||
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="collectionProcess"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import OperationRender from '@/views/workflow/common/OperationRender.vue'
|
||||
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
|
||||
import {downloadFile} from "@/api/project-demand";
|
||||
|
||||
const emit = defineEmits(['update:value'])
|
||||
const showExpendText = ref('')
|
||||
const showMoreCompany = ref(false)
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
processViewer: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
companyOption: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
fileListShow: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
const changeDiagram = ref(false)
|
||||
const _value = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(val) {
|
||||
emit("update:value", val);
|
||||
}
|
||||
})
|
||||
const getCompanyName = (data) => {
|
||||
if (data) {
|
||||
return data.join(',')
|
||||
}
|
||||
}
|
||||
const handleExpend = () => {
|
||||
showMoreCompany.value = !showMoreCompany.value;
|
||||
showExpendClass(showMoreCompany.value, props.formData.companyIds)
|
||||
}
|
||||
const showExpendClass = (showMoreCompany, data) => {
|
||||
if (!showMoreCompany) {
|
||||
if (data && data.length > 14) {
|
||||
showExpendText.value = '展开'
|
||||
return 'company-style'
|
||||
}
|
||||
} else {
|
||||
showExpendText.value = '收缩'
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
const handleDownload = (row) => {
|
||||
downloadFile(row.fileId).then(res => {
|
||||
const blob = new Blob([res])
|
||||
let a = document.createElement('a')
|
||||
a.href = URL.createObjectURL(blob)
|
||||
a.download = row.originalFileName
|
||||
a.click()
|
||||
})
|
||||
}
|
||||
|
||||
watch(() => props.loading, (newVal) => {
|
||||
props.loading = newVal
|
||||
}, {deep: true})
|
||||
|
||||
watch(() => props.processViewer, (newVal) => {
|
||||
props.processViewer = newVal
|
||||
}, {deep: true})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.el-empty__description) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.company-style {
|
||||
//width: 98%;
|
||||
min-height: 30px;
|
||||
max-height: 60px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 2;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
406
src/components/DetailComponent/CompanyPicker.vue
Normal file
@@ -0,0 +1,406 @@
|
||||
<template>
|
||||
<el-dialog custom-class="custom-dialog" class="border" :border="false" width="1000px" style="height: 676px"
|
||||
:title="title" :show-close="false" :visible.sync="visible" v-model="visible" append-to-body :close-on-click-modal="true" @close="closeDialog">
|
||||
<div class="picker">
|
||||
<div class="candidate" v-loading="loading">
|
||||
<el-input v-model="filterText"
|
||||
clearable placeholder="输入公司进行搜索">
|
||||
<template #append>
|
||||
<el-button @click="getList()">搜索</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<fvCheckbox style="margin-left: 10px" :options="checkOptions" v-model="checkList" @change="checkBoxChange"/>
|
||||
<!-- 人员选择 -->
|
||||
<el-empty :image-size="100" description="似乎没有数据" v-show="dataList.length === 0"/>
|
||||
<el-scrollbar style="height:87%;">
|
||||
<div class="tree">
|
||||
<el-tree :data="dataList" ref="tree" :props="defaultProps" empty-text="" node-key="value"
|
||||
:show-checkbox="showCheckbox" highlight-current default-expand-all
|
||||
:default-checked-keys="defaultChecked" :disabled="disabled"
|
||||
:check-strictly="!checkStrictly" @node-click="(node,check)=>handle(node,check)"
|
||||
@check-change="handleChange" :filter-node-method="filterNode">
|
||||
<template #default="{ node, data }">
|
||||
<div class="tree-node">
|
||||
<div style="display: flex;align-items: center;padding: 3px 0">
|
||||
{{ node.label }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<div class="selected">
|
||||
<div class="count">
|
||||
<span>已选 {{ selectList.length }} 项</span>
|
||||
<span @click="clearSelected">清空</span>
|
||||
</div>
|
||||
<div class="org-items">
|
||||
<el-empty :image-size="100" description="请点击左侧列表选择数据" v-show="selectList.length === 0"/>
|
||||
<div v-for="(selectItem, selectIndex) in selectList" :key="selectIndex" class="org-item">
|
||||
{{ selectItem.label }}
|
||||
<el-icon @click="noSelected(selectItem)" size="20" style="margin-left: 10px;cursor: pointer;">
|
||||
<CircleClose/>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<el-button size="mini" @click="visible = false">取 消</el-button>
|
||||
<el-button size="mini" color="#DED0B2" @click="selectConfirm">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ElMessageBox} from "element-plus";
|
||||
import {getSubCompOpt} from "@/api/user/user";
|
||||
|
||||
const checkList = ref(['1'])
|
||||
const checkStrictly = ref(false)
|
||||
const isExpand = ref('展开')
|
||||
const expandedKeys = ref(['-1']);
|
||||
const checkOptions = ref([
|
||||
{
|
||||
label: isExpand.value,
|
||||
value: '1'
|
||||
},
|
||||
// {
|
||||
// label: '父子联动',
|
||||
// value: '2'
|
||||
// },
|
||||
])
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
multiple: { //是否多选
|
||||
default: true,
|
||||
type: Boolean
|
||||
},
|
||||
showCheckbox: { //是否显示左侧选择框
|
||||
default: true,
|
||||
type: Boolean
|
||||
}
|
||||
});
|
||||
let selectItem = reactive({
|
||||
type: -1,
|
||||
value: "0"
|
||||
});
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const title = ref("请选择");
|
||||
const selectList = ref([]);
|
||||
const filterText = ref("");
|
||||
const dataList = ref([]);
|
||||
const defaultChecked = ref([]);
|
||||
const tree = ref([]);
|
||||
const defaultProps = {
|
||||
value: "value",
|
||||
label: "label",
|
||||
children: "children",
|
||||
disabled: "disabled",
|
||||
};
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const _value = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
});
|
||||
|
||||
watch(() => filterText.value, (newVal) => {
|
||||
tree.value.filter(newVal);
|
||||
});
|
||||
const closeDialog=()=>{
|
||||
console.log('关闭')
|
||||
visible.value=false
|
||||
filterText.value=''
|
||||
}
|
||||
const checkBoxChange = (val) => {
|
||||
checkStrictly.value = val.includes('2')
|
||||
let nodes = tree.value.store.nodesMap
|
||||
if (val.includes('1')) {
|
||||
for (const node in nodes) {
|
||||
nodes[node].expanded = true;
|
||||
}
|
||||
isExpand.value = '折叠'
|
||||
} else {
|
||||
for (const node in nodes) {
|
||||
nodes[node].expanded = false;
|
||||
}
|
||||
isExpand.value = '展开'
|
||||
}
|
||||
}
|
||||
const getList = () => {
|
||||
getSubCompOpt().then(res => {
|
||||
dataList.value = [
|
||||
{
|
||||
label: "所有公司",
|
||||
value: -1,
|
||||
},
|
||||
...res.data
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
//通过关键字过滤树节点
|
||||
const filterNode = (value, data) => {
|
||||
//通过关键字过滤树节点
|
||||
if (!value) return true;
|
||||
return data.label.indexOf(value) !== -1;
|
||||
};
|
||||
//用于用户选择
|
||||
const show = () => {
|
||||
//用于弹开部门选择
|
||||
visible.value = true;
|
||||
selectList.value = _value.value
|
||||
defaultChecked.value = _value.value.map(item => item.value)
|
||||
getList()
|
||||
};
|
||||
|
||||
const updateTreeCheck = (list, flag) => {
|
||||
list.forEach(item => {
|
||||
if (item.value !== -1) {
|
||||
tree.value.setChecked(item, flag)
|
||||
if (item.children !== undefined) {
|
||||
updateTreeCheck(item.children, flag)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleChange = (data, checked) => {
|
||||
if (data.value == -1) {
|
||||
if(checked){
|
||||
updateTreeCheck(dataList.value, false)
|
||||
tree.value.setChecked(data,true);
|
||||
}
|
||||
}
|
||||
if(tree.value.getCheckedKeys().length>1&&tree.value.getCheckedKeys().indexOf(-1)!==-1){
|
||||
tree.value.setChecked(-1,false);
|
||||
}
|
||||
// 左侧有选择框 + 多选
|
||||
if (props.multiple) {
|
||||
//不添加重复的数据到右边
|
||||
for (let i = 0; i < selectList.value.length; i++) {
|
||||
if (selectList.value[i].value === data.value) {
|
||||
selectList.value.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (checked) {
|
||||
// if (data.children === undefined) {
|
||||
selectList.value.push(data);
|
||||
// }
|
||||
} else if (data === "1") {
|
||||
tree.value.setCheckedKeys([]);
|
||||
selectList.value = [];
|
||||
}
|
||||
} else {// 左侧有选择框 + 单选
|
||||
//不添加重复的数据到右边
|
||||
for (let i = 0; i < selectList.value.length; i++) {
|
||||
if (selectList.value[i].value === data.value) {
|
||||
selectList.value.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (checked) {
|
||||
tree.value.setCheckedNodes([data]);
|
||||
selectList.value = [data];
|
||||
} else if (data === "1") {
|
||||
selectList.value = [];
|
||||
tree.value.setCheckedKeys([]);
|
||||
}
|
||||
}
|
||||
};
|
||||
const handle = (node, check) => {
|
||||
if (check.isLeaf !== false) {
|
||||
if (props.multiple) {
|
||||
//不添加重复的数据到右边
|
||||
for (let i = 0; i < selectList.value.length; i++) {
|
||||
if (selectList.value[i].value === node.value) {
|
||||
selectList.value.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
check.checked = true;
|
||||
selectList.value.push(node);
|
||||
} else {
|
||||
check.checked = true;
|
||||
selectList.value = [node];
|
||||
}
|
||||
}
|
||||
// _value.value = selectList.value
|
||||
};
|
||||
const noSelected = (selectItem) => {
|
||||
//左侧无选择框时,右侧显示×
|
||||
for (let i = 0; i < selectList.value.length; i++) {
|
||||
if (selectList.value[i].value === selectItem.value) {
|
||||
tree.value.setChecked(selectList.value[i].value, false);
|
||||
selectList.value.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (props.showCheckbox) {
|
||||
// 左侧有选择框 + 单选
|
||||
if (props.multiple === false) {
|
||||
tree.value.setCheckedKeys([]);
|
||||
}
|
||||
}
|
||||
};
|
||||
const clearSelected = () => {
|
||||
//清空
|
||||
ElMessageBox.confirm("您确定要清空已选中的项?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
if (!props.showCheckbox) {
|
||||
selectList.value = [];
|
||||
} else {
|
||||
handleChange("1");
|
||||
}
|
||||
});
|
||||
};
|
||||
const selectConfirm = () => {
|
||||
//确定按钮
|
||||
emit("ok", selectList.value);
|
||||
dataList.value = []
|
||||
visible.value = false;
|
||||
};
|
||||
defineExpose({
|
||||
show
|
||||
});
|
||||
getList()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$containWidth: 480px;
|
||||
:deep(.tree) {
|
||||
.el-tree-node__content {
|
||||
height: 34px;
|
||||
|
||||
.tree-node {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
//.el-tree-node {
|
||||
// .is-leaf + .el-checkbox .el-checkbox__inner {
|
||||
// display: inline-block;
|
||||
// }
|
||||
//
|
||||
// .el-checkbox .el-checkbox__inner {
|
||||
// display: none;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
.footer {
|
||||
float: right;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.picker {
|
||||
height: 560px;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
|
||||
.candidate {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: $containWidth;
|
||||
height: 100%;
|
||||
border: 1px solid #e8e8e8;
|
||||
|
||||
:deep(.el-input) {
|
||||
height: 40px;
|
||||
|
||||
.el-input__inner, .el-input-group__append {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.selected {
|
||||
right: 0;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: 450px;
|
||||
height: 100%;
|
||||
border: 1px solid #e8e8e8;
|
||||
|
||||
.count {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
display: inline-block;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
margin-bottom: 5px;
|
||||
font-size: 16px;
|
||||
|
||||
> span:nth-child(2) {
|
||||
float: right;
|
||||
color: #c75450;
|
||||
cursor: pointer;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.org-items {
|
||||
overflow-y: auto;
|
||||
height: 90%;
|
||||
|
||||
.el-icon-close {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
cursor: pointer;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.org-item {
|
||||
margin: 0 5px;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
padding: 7px 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
|
||||
&:hover {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
> span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.el-scrollbar .el-scrollbar__wrap {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
float: right;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 16px;
|
||||
background-color: #efefef;
|
||||
}
|
||||
|
||||
</style>
|
||||
255
src/components/DetailComponent/ExpenseDetail.vue
Normal file
@@ -0,0 +1,255 @@
|
||||
<template>
|
||||
<el-button color="#DED0B2" style="float: right;margin: 0 10px 10px 0" @click="exportTable">导出</el-button>
|
||||
<el-table ref="reportTable" :data="tableData" style="width: 100%;height: 479px"
|
||||
:span-method="objectSpanMethod" v-loading="loading">
|
||||
<el-table-column label="四川省国有资产经营投资管理有限责任公司科技创新项目人工成本分摊明细表" align="center">
|
||||
<el-table-column v-for="column in columnInfo" :prop="column.prop" :label="column.label" align="center"
|
||||
:fixed="(!column.children) ? ((column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') ? 'right' : 'left') : false"
|
||||
:width="(column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') ? 160:130">
|
||||
<template #default="scope">
|
||||
<template v-if="column.children">
|
||||
<el-table-column v-for="childColumn in column.children"
|
||||
:prop="column.prop + '.'+ childColumn.prop"
|
||||
:label="childColumn.label"
|
||||
:width="childColumn.prop === 'subtotal' ? 160 : 130">
|
||||
<template #default="columnScope">
|
||||
<template v-if="(tableData.length -1) !== columnScope.$index">
|
||||
{{
|
||||
columnScope.row[column.prop][childColumn.prop] ? columnScope.row[column.prop][childColumn.prop] : '/'
|
||||
}}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ columnScope.row[column.prop][childColumn.prop] }}
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!--分摊金额合计与分摊金额总计计算-->
|
||||
<template
|
||||
v-if="(column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') && (tableData.length -1) !== scope.$index">
|
||||
{{ getTotalSeparation(scope.row, column.prop) }}
|
||||
</template>
|
||||
<template
|
||||
v-else-if="(tableData.length -1) === scope.$index && (column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost')">
|
||||
{{ getTotalSummary(scope.row, column.prop) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ scope.row[column.prop] }}
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="jsx">
|
||||
import {getResearchUser, getAllocationDetails} from "@/api/expense-manage";
|
||||
import {exportExcel} from "@/utils/export-excel";
|
||||
import {ElNotification} from "element-plus";
|
||||
|
||||
const route = useRoute()
|
||||
const tableIns = ref()
|
||||
const reportTable = ref({});
|
||||
const columnInfo = ref([])
|
||||
const monthConcat = new Map()
|
||||
const tableData = ref([])
|
||||
const loading = ref(false)
|
||||
const researchOptions = ref([])
|
||||
|
||||
const objectSpanMethod = ({row, column, rowIndex, columnIndex}) => {
|
||||
if (columnIndex === 0) {
|
||||
if (monthConcat.has(rowIndex)) {
|
||||
return {
|
||||
rowspan: monthConcat.get(rowIndex),
|
||||
colspan: 1,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
rowspan: 0,
|
||||
colspan: 0,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let length = Object.keys(row).length
|
||||
// console.log(length)
|
||||
if (length > 5) {
|
||||
if (concatColumn(columnIndex, length, rowIndex)) {
|
||||
if (rowIndex % 5 === 0) {
|
||||
return {
|
||||
rowspan: 5,
|
||||
colspan: 1,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
rowspan: 0,
|
||||
colspan: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const getTotalSeparation = (row, prop) => {
|
||||
let totalSeparation = 0.00
|
||||
for (let key of Object.keys(row)) {
|
||||
if (key.startsWith('personInfo')) {
|
||||
let value = prop === 'totalSeparation' ? (row[key].separationAmount ? row[key].separationAmount : 0) : row[key].subtotal
|
||||
if ("/" !== value) {
|
||||
try {
|
||||
totalSeparation += parseFloat(value)
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (totalSeparation !== 0) {
|
||||
return totalSeparation.toFixed(2);
|
||||
} else {
|
||||
return "/"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const getTotalSummary = (row, prop) => {
|
||||
let key;
|
||||
if (prop === 'totalSeparation') {
|
||||
key = 'separationAmount'
|
||||
} else {
|
||||
key = 'subtotal'
|
||||
}
|
||||
let result = 0
|
||||
for (const rowKey of Object.keys(row)) {
|
||||
if (rowKey.startsWith('personInfo')) {
|
||||
let value = row[rowKey][key]
|
||||
if (value && "/" !== value) {
|
||||
try {
|
||||
result += parseFloat(value)
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toFixed(2);
|
||||
}
|
||||
|
||||
const concatColumn = (columnIndex, length, rowIndex) => {
|
||||
if (rowIndex === tableData.value.length - 1) {
|
||||
return false
|
||||
}
|
||||
let columnLength = 5 + (length - 5) * 5
|
||||
if (columnIndex === 1
|
||||
|| columnIndex === columnLength - 1) {
|
||||
return true;
|
||||
}
|
||||
for (let i = 0; i < length - 5; i++) {
|
||||
if (columnIndex === 4 + (i * 5)
|
||||
|| columnIndex === 5 + (i * 5)
|
||||
|| columnIndex === 7 + (i * 5)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const init = () => {
|
||||
loading.value = true
|
||||
getAllocationDetails(route.query.id).then(res => {
|
||||
if (res.code !== 1000) {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
columnInfo.value = res.data.columns
|
||||
let tableDataLet = res.data.tableData;
|
||||
let personInfoKey = []
|
||||
columnInfo.value.forEach(item => {
|
||||
if (item.prop.startsWith('personInfo')) {
|
||||
personInfoKey.push(item.prop)
|
||||
}
|
||||
})
|
||||
tableData.value = []
|
||||
let rowIndex = 0;
|
||||
let summary = {
|
||||
month: "",
|
||||
salaryType: '',
|
||||
projectName: "合计",
|
||||
totalSeparation: 10,
|
||||
totalSeparationCost: 10
|
||||
}
|
||||
for (const key of personInfoKey) {
|
||||
summary[key] = {
|
||||
researchDuration: "",
|
||||
separationAmount: 0,
|
||||
subtotal: 0,
|
||||
wagesPayable: "",
|
||||
workday: "",
|
||||
}
|
||||
}
|
||||
tableDataLet.forEach((tableDatum) => {
|
||||
let rowspan = tableDatum.rows.length * 5
|
||||
monthConcat.set(rowIndex, rowspan)
|
||||
rowIndex += rowspan
|
||||
for (const tableDatumElement of tableDatum.rows) {
|
||||
tableData.value = tableData.value.concat(tableDatumElement)
|
||||
let row = tableDatumElement[0]
|
||||
for (const key of personInfoKey) {
|
||||
try {
|
||||
if (row[key].subtotal && '/' !== row[key].subtotal) {
|
||||
summary[key].subtotal += parseFloat(row[key].subtotal)
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
for (const row of tableData.value) {
|
||||
for (const key of personInfoKey) {
|
||||
try {
|
||||
if (row[key].separationAmount && '/' !== row[key].separationAmount) {
|
||||
summary[key].separationAmount += parseFloat(row[key].separationAmount)
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const key of personInfoKey) {
|
||||
summary[key].subtotal = summary[key].subtotal.toFixed(2)
|
||||
summary[key].separationAmount = summary[key].separationAmount.toFixed(2)
|
||||
}
|
||||
monthConcat.set(rowIndex, 1)
|
||||
tableData.value.push(summary)
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const getResearchOptions = async () => {
|
||||
const res = await getResearchUser()
|
||||
researchOptions.value = res.data
|
||||
}
|
||||
const search = (val) => {
|
||||
tableConfig.params = {
|
||||
allocationId: route.query.id,
|
||||
...val
|
||||
}
|
||||
tableIns.value.refresh()
|
||||
}
|
||||
getResearchOptions()
|
||||
init()
|
||||
|
||||
|
||||
const exportTable = () => {
|
||||
const $e = reportTable.value.$el
|
||||
let $table = $e.querySelector('.el-table__fixed')
|
||||
if (!$table) {
|
||||
$table = $e
|
||||
}
|
||||
exportExcel($table, (5 + (Object.keys(tableData.value[0]).length - 5) * 5), "四川省国有资产经营投资管理有限责任公司科技创新项目人工成本分摊明细表", 2)
|
||||
}
|
||||
</script>
|
||||
169
src/components/DetailComponent/FileComponent.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<el-form :label-position="labelAlign">
|
||||
<el-form-item :label="title?'其他文件':''" v-if="fileListShow === 'READ' || fileListShow === 'EDIT'" :label-position="labelAlign" :label-width="title?95:''">
|
||||
<file-upload @getFile="getOtherFile" v-if="fileListShow === 'EDIT'"/>
|
||||
<fvTable style="width: 100%;max-height: 162px;" v-if="processViewer" height="162" :tableConfig="tableConfig"
|
||||
:data="_value" :isSettingCol="false" :pagination="false">
|
||||
<template #empty>
|
||||
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
|
||||
</template>
|
||||
</fvTable>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import {downloadFile, deleteFile} from "@/api/project-demand";
|
||||
import {ElNotification} from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
tag: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
fileListShow: {
|
||||
type: String,
|
||||
default: 'READ'
|
||||
},
|
||||
value: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
processViewer: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
labelAlign: {
|
||||
type: String,
|
||||
default: 'right'
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['update:value'])
|
||||
const tableConfig = reactive({
|
||||
columns: [
|
||||
{
|
||||
prop: 'index',
|
||||
type: 'index',
|
||||
label: '序号',
|
||||
align: 'center',
|
||||
width: 85,
|
||||
},
|
||||
{
|
||||
prop: 'originalFileName',
|
||||
label: '文件名',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'tag',
|
||||
label: '标签',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'size',
|
||||
label: '文件大小',
|
||||
align: 'center',
|
||||
width: 150,
|
||||
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||
},
|
||||
{
|
||||
prop: 'oper',
|
||||
label: '操作',
|
||||
align: 'center',
|
||||
showOverflowTooltip: false,
|
||||
currentRender: ({row, index}) => {
|
||||
let btn = []
|
||||
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
|
||||
// if (row.newFile) {
|
||||
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
|
||||
// }
|
||||
return (
|
||||
<div style={{width: '100%'}}>
|
||||
{
|
||||
btn.map(item => (
|
||||
<el-button
|
||||
type={item.type}
|
||||
onClick={() => item.func()}
|
||||
link>
|
||||
{item.label}
|
||||
</el-button>
|
||||
))
|
||||
}
|
||||
{
|
||||
row.newFile ? <popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
|
||||
perm={['mosr:requirement:del']}
|
||||
onDelete={() => handleDelete(row)}/>
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const _value = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(val) {
|
||||
emit("update:value", val);
|
||||
}
|
||||
})
|
||||
|
||||
const getOtherFile = (val) => {
|
||||
props.processViewer = false
|
||||
let fileObj = compositeParam(val)
|
||||
_value.value.push(fileObj)
|
||||
nextTick(() => {
|
||||
props.processViewer = true
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const compositeParam = (item, type) => {
|
||||
return {
|
||||
fileId: item.id,
|
||||
size: item.size,
|
||||
originalFileName: item.originalFilename,
|
||||
fileType: item.fileType,
|
||||
url: item.url,
|
||||
newFile: true,
|
||||
tag: props.tag
|
||||
}
|
||||
}
|
||||
const handleDownload = (row) => {
|
||||
downloadFile(row.fileId).then(res => {
|
||||
const blob = new Blob([res])
|
||||
let a = document.createElement('a')
|
||||
a.href = URL.createObjectURL(blob)
|
||||
a.download = row.originalFileName
|
||||
a.click()
|
||||
})
|
||||
}
|
||||
const handleDelete = (row) => {
|
||||
deleteFile(row.fileId).then(res => {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: res.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
if (res.code === 1000) {
|
||||
_value.value.splice(_value.value.findIndex((item) => item.fileId === row.fileId), 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
watch(() => props.processViewer, (newVal) => {
|
||||
props.processViewer = newVal
|
||||
}, {deep: true})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.el-table--fit ) {
|
||||
height: 162px !important;
|
||||
}
|
||||
</style>
|
||||
168
src/components/DetailComponent/Opinion.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<!-- <baseTitle title="审核意见"></baseTitle>-->
|
||||
<!-- <fvForm :schema="schema" @getInstance="(e)=>form = e"></fvForm>-->
|
||||
<div class="oper-page-btn">
|
||||
<el-button type="danger" @click="handleReject">驳回</el-button>
|
||||
<el-button color="#DED0B2" @click="handleAgree">同意</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import {ElNotification} from 'element-plus';
|
||||
import {agreeTask, rejectTask} from "@/api/project-demand/index.js";
|
||||
import {useTagsView} from '@/stores/tagsview.js'
|
||||
|
||||
const tagsViewStore = useTagsView()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const props = defineProps({
|
||||
taskId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
formData: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const form = ref()
|
||||
const schema = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: '',
|
||||
prop: 'auditOpinion',
|
||||
component: 'el-input',
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
props: {
|
||||
placeholder: '请输入审核意见',
|
||||
type: 'textarea',
|
||||
rows: 3
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const _value = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(val) {
|
||||
emit("update:value", val);
|
||||
}
|
||||
})
|
||||
const back = () => {
|
||||
switch (route.name) {
|
||||
case 'Initiation/detail':
|
||||
router.push({name: 'Initiation'})
|
||||
break;
|
||||
case 'Filing/detail':
|
||||
router.push({name: 'Filing'})
|
||||
break;
|
||||
case 'Implementation/detail':
|
||||
if (route.query.source === 'home') {
|
||||
router.push('/home')
|
||||
} else {
|
||||
if (route.query.step === '10') {
|
||||
router.push({name: 'Summary'})
|
||||
} else if (route.query.step === '20') {
|
||||
router.push({name: 'Initiation'})
|
||||
} else if (route.query.step === '40') {
|
||||
router.push({name: 'Implementation'})
|
||||
} else if (route.query.step === '50') {
|
||||
router.push({name: 'Filing'})
|
||||
} else if (route.query.step === '00') {
|
||||
router.push({name: 'Requirement'})
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'Summary/detail':
|
||||
if (route.query.source === 'home') {
|
||||
router.push('/home')
|
||||
} else {
|
||||
router.push({name: 'Summary'})
|
||||
}
|
||||
break;
|
||||
case 'Requirement/detail':
|
||||
if (route.query.source === 'home') {
|
||||
router.push('/home')
|
||||
} else {
|
||||
router.push({name: 'Requirement'})
|
||||
}
|
||||
break;
|
||||
case 'Fund/detail':
|
||||
if (route.query.source === 'home') {
|
||||
router.push('/home')
|
||||
} else {
|
||||
router.push({name: 'Fund'})
|
||||
}
|
||||
break;
|
||||
case 'Share/detail':
|
||||
if (route.query.source === 'home') {
|
||||
router.push('/home')
|
||||
} else {
|
||||
router.push({name: 'Expense/share'})
|
||||
}
|
||||
break;
|
||||
case 'Phase/detail':
|
||||
if (route.query.source === 'home') {
|
||||
router.push('/home')
|
||||
} else {
|
||||
router.push({name: 'Implementation'})
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 驳回
|
||||
const handleReject = async () => {
|
||||
// const values = form.value.getValues()
|
||||
if (!_value.value) {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: '请填写审核意见',
|
||||
type: 'warning'
|
||||
})
|
||||
return
|
||||
}
|
||||
const params = {
|
||||
taskId: props.taskId,
|
||||
// ...values
|
||||
auditOpinion: _value.value
|
||||
}
|
||||
// console.log('params', params)
|
||||
const res = await rejectTask(params)
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: res.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||
back()
|
||||
}
|
||||
|
||||
const handleAgree = async () => {
|
||||
// const values = form.value.getValues()
|
||||
const params = {
|
||||
taskId: props.taskId,
|
||||
formData: props.formData,
|
||||
auditOpinion: _value.value
|
||||
}
|
||||
const res = await agreeTask(params)
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: res.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||
back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
763
src/components/DetailComponent/ProjectApply.vue
Normal file
@@ -0,0 +1,763 @@
|
||||
<template>
|
||||
<div class="apply-block">
|
||||
<el-row v-if="title==='check'">
|
||||
<el-col :span="24">
|
||||
<baseTitle :title="'附件信息'"></baseTitle>
|
||||
</el-col>
|
||||
<el-form :model="attachmentParam" inline style="margin-top: 15px">
|
||||
<el-form-item label="标签" prop="tag">
|
||||
<el-select v-model="attachmentParam.tag" placeholder="请选择标签" clearable filterable style="width: 300px">
|
||||
<el-option
|
||||
v-for="item in tagsOption"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleSearch" color="#DED0B2">搜索</el-button>
|
||||
<el-button v-if="uploadState" color="#DED0B2" @click="handleUpload">上传附件</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<fvTable style="width: 100%;min-height:162px;max-height: 162px" v-if="showAttachmentTable" height="162"
|
||||
:tableConfig="tableConfig"
|
||||
:data="otherAttachmentList" :isSettingCol="false" :pagination="false">
|
||||
<template #empty>
|
||||
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
|
||||
</template>
|
||||
</fvTable>
|
||||
</el-row>
|
||||
<baseTitle :title="getTitleName(title)+'信息'"></baseTitle>
|
||||
<el-form :model="localFormData" ref="formRef" label-width="auto" v-if="step!=='50'">
|
||||
<el-row>
|
||||
<el-col :span="24" v-if="title==='apply'">
|
||||
<el-form-item label="项目负责人" :required="true" prop=""
|
||||
label-width="125">
|
||||
<el-button style="margin-right: 10px" color="#DED0B2" @click="handleShowProjectChargePersonTable">
|
||||
<!-- {{ localFormData.projectChargePerson ? '更改' : '请选择' }}-->
|
||||
{{ projectChargePersonUserList.length !== 0 ? '更改' : '请选择' }}
|
||||
</el-button>
|
||||
<div v-for="item in projectChargePersonUserList" :key="item.id" style="margin-right: 5px">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<user-picker :multiple="false" ref="projectChargePersonUserPicker" title="请选择项目负责人"
|
||||
v-model:value="projectChargePersonUserList" @ok="projectChargePersonUserPickerOk"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="title==='apply'">
|
||||
<el-form-item label="项目成员" :required="true" prop=""
|
||||
label-width="125">
|
||||
<el-button color="#DED0B2" style="margin-right: 10px" @click="handleShowProjectPersonTable">
|
||||
<!-- {{ localFormData.projectPersonIds ? '更改' : '请选择' }}-->
|
||||
{{ projectPersonUserList.length !== 0 ? '更改' : getProjectPerson(projectPersonUserList) ? '更改' : '请选择' }}
|
||||
</el-button>
|
||||
<div v-for="item in getProjectPerson(projectPersonUserList)" :key="item.id" style="margin-right: 5px">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<user-picker :multiple="true" ref="projectPersonUserPicker" title="请选择项目成员"
|
||||
v-model:value="projectPersonUserList" @ok="projectPersonUserPickerOk"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="前置流程" :required="preProcessRequired" prop="preProcess" label-width="125">
|
||||
<el-button color="#DED0B2" @click="handleShowPreTable" style="margin-right: 10px">
|
||||
{{
|
||||
localFormData.preProcess && localFormData.preProcess.length > 0 ? '更改' : sessionParams.preProcess && sessionParams.preProcess.length > 0 ? '更改' : '请选择'
|
||||
}}
|
||||
</el-button>
|
||||
<div v-for="item in getRequestName(localFormData.preProcess)" :key="item.requestId">
|
||||
<a :href="item.baseUrl" target="_blank"
|
||||
style="color: #2a99ff;margin-right: 10px;cursor: pointer">{{ item.requestName }}
|
||||
</a>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<!-- v-if="showAttachment"-->
|
||||
<AttachmentUpload ref="attachment" :label="getTitleName(title)+'附件'" :showTable="showTable"
|
||||
v-model:otherFileList="otherFileList" :tag="getTitleName(props.title)"
|
||||
@getAttachment="getAttachment" v-model:singleList="singleList" :showSingleTable="showSingleTable"
|
||||
@getOtherFile="getOtherFile" :showFileList="true" :formData="localFormData"
|
||||
:preview="mode == 'resubmit'"/>
|
||||
<div>
|
||||
<div class="approval-record">
|
||||
<div class="approval-title">
|
||||
<baseTitle title="审批记录" v-if="mode === 'resubmit'"></baseTitle>
|
||||
<div v-else></div>
|
||||
<div class="diagram">
|
||||
<div class="base-title">流程图</div>
|
||||
<el-switch
|
||||
v-model="changeDiagram"
|
||||
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="process">
|
||||
<operation-render v-if="mode === 'resubmit'&&!changeDiagram" :operation-list="data.operationList"
|
||||
:state="data.state"/>
|
||||
<process-diagram-viewer mode="view" :idName="title" v-if="processDiagramViewer&&changeDiagram"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oper-page-btn">
|
||||
<el-button color="#DED0B2" v-if="mode === 'submit'" @click="handleSubmit">提交</el-button>
|
||||
<el-button color="#DED0B2" v-else-if="mode === 'resubmit'" @click="handleSubmit">重新提交</el-button>
|
||||
<el-button @click="handleBack">返回</el-button>
|
||||
</div>
|
||||
<el-dialog v-if="showPreTable" title="前置流程" v-model="showPreTable" width="80%">
|
||||
<el-form :model="preProcessForm" inline @submit.prevent="searchPreProcess">
|
||||
<el-form-item label="请求名称">
|
||||
<el-input v-model="preProcessForm.requestName" placeholder="请输入请求名称" clearable>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button color="#DED0B2" @click="searchPreProcess">搜索</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="preProcessList" v-loading="loading"
|
||||
@select="handleSelect" @select-all="handleSelect" row-key="requestId" ref="preProcessTable">
|
||||
<el-table-column type="selection" width="55" :reserve-selection="true"/>
|
||||
<el-table-column prop="requestId" label="请求id"></el-table-column>
|
||||
<el-table-column prop="requestName" label="请求名称"></el-table-column>
|
||||
<el-table-column prop="lastOperatorName" label="最后操作人名称"></el-table-column>
|
||||
<el-table-column prop="lastOperateTime" label="最后操作时间"></el-table-column>
|
||||
<el-table-column prop="currentNodeName" label="当前节点"></el-table-column>
|
||||
<el-table-column prop="creatorName" label="创建人"></el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间"></el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<!-- <el-button type="primary" @click="choosePreProcess(scope.row)" link>选择</el-button>-->
|
||||
<a :href="scope.row.baseUrl" target="_blank" style="color: #2a99ff;margin-left: 10px">查看流程</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<paging :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[10, 20, 30, 40,50]"
|
||||
:total="total" @changeSize="handleSizeChange" @goPage="handleCurrentChange"/>
|
||||
<div class="oper">
|
||||
<el-button color="#DED0B2" @click="choosePreProcess">确定</el-button>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import OperationRender from '@/views/workflow/common/OperationRender.vue'
|
||||
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
|
||||
import {ElNotification} from "element-plus";
|
||||
import {getTags} from "@/api/project-manage";
|
||||
import {
|
||||
getApplyProcess,
|
||||
getPreProcess,
|
||||
getProjectCheckProcess,
|
||||
getProjectConclusionProcess,
|
||||
projectApply,
|
||||
projectCheck,
|
||||
projectConclusion,
|
||||
resubmitApply,
|
||||
resubmitCheck,
|
||||
resubmitConclusion
|
||||
} from "@/api/project-manage";
|
||||
import {useProcessStore} from '@/stores/processStore.js';
|
||||
import {useTagsView} from '@/stores/tagsview.js'
|
||||
import Paging from "@/components/pagination/index.vue";
|
||||
import UserPicker from "@/views/workflow/process/common/UserPicker.vue";
|
||||
|
||||
import {searchImplementationFileList} from "@/api/project-manage/attachment";
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const changeDiagram = ref(false)
|
||||
const formRef = ref()
|
||||
const showSingleTable = ref(false)
|
||||
const projectChargePersonUserList = ref([])
|
||||
const projectChargePersonUserPicker = ref()
|
||||
const projectPersonUserList = ref([])
|
||||
const projectPersonUserPicker = ref()
|
||||
const singleList = ref([])
|
||||
const tagsOption = ref([])
|
||||
const uploadState = ref(false)
|
||||
const showAttachmentTable = ref(true)
|
||||
const otherAttachmentList = ref([])
|
||||
const attachmentParam = reactive({
|
||||
tag: ''
|
||||
})
|
||||
const tableConfig = reactive({
|
||||
columns: [
|
||||
{
|
||||
prop: 'index',
|
||||
type: 'index',
|
||||
label: '序号',
|
||||
align: 'center',
|
||||
width: '80',
|
||||
},
|
||||
{
|
||||
prop: 'originalFileName',
|
||||
label: '文件名',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'tag',
|
||||
label: '标签',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'size',
|
||||
label: '文件大小',
|
||||
align: 'center',
|
||||
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||
},
|
||||
{
|
||||
prop: 'oper',
|
||||
label: '操作',
|
||||
align: 'center',
|
||||
showOverflowTooltip: false,
|
||||
currentRender: ({row, index}) => {
|
||||
return (
|
||||
<div>
|
||||
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const emit = defineEmits(["getAttachment", "getOtherFile"])
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: 'apply'
|
||||
},
|
||||
showTable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: "view"
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
formData: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
step: {
|
||||
type: String,
|
||||
default: "20"
|
||||
}
|
||||
})
|
||||
const preProcessList = ref([])
|
||||
//暂存数据
|
||||
const currentList = ref([])
|
||||
const preProcessRequired = ref(false)
|
||||
const total = ref(0)
|
||||
const preProcessForm = reactive({
|
||||
requestName: ''
|
||||
})
|
||||
const pageInfo = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
})
|
||||
// const rules = reactive({
|
||||
// preProcess: [{required: true, message: '请选择前置流程', trigger: 'blur'}],
|
||||
// projectChargePerson: [{required: true, message: '请选择项目负责人', trigger: 'blur'}],
|
||||
// projectPerson: [{required: true, message: '请选择项目成员', trigger: 'blur'}],
|
||||
// })
|
||||
const tagsViewStore = useTagsView()
|
||||
const processStore = useProcessStore()
|
||||
const localProjectPerson = ref([])
|
||||
const otherFileList = ref([])
|
||||
const localFormData = ref({
|
||||
projectPersonIds: [],
|
||||
projectChargePerson: null,
|
||||
preProcess: [
|
||||
// {
|
||||
// requestId: null,
|
||||
// requestName: '',
|
||||
// baseUrl: ''
|
||||
// }
|
||||
]
|
||||
})
|
||||
const attachment = ref()
|
||||
const deploymentData = ref({})
|
||||
const showPreTable = ref(false)
|
||||
const showTable = ref(true)
|
||||
const loading = ref(false)
|
||||
const processDiagramViewer = ref(false)
|
||||
const name = ref(router.currentRoute.value.name)
|
||||
const deploymentId = ref()
|
||||
const selectRows = ref([])
|
||||
const projectId = ref(route.query.projectId)
|
||||
const sessionParams = ref({})
|
||||
|
||||
if (localStorage.getItem('preProcess')) {
|
||||
let param = JSON.parse(localStorage.getItem('preProcess'))
|
||||
localFormData.value.preProcess = param
|
||||
sessionParams.value.preProcess = param
|
||||
localStorage.setItem('preProcess', JSON.stringify(param))
|
||||
}
|
||||
if (localStorage.getItem('singleFile')) {
|
||||
let param = JSON.parse(localStorage.getItem('singleFile'))
|
||||
localFormData.value.singleFile = param
|
||||
singleList.value = [param]
|
||||
localStorage.setItem('singleFile', JSON.stringify(param))
|
||||
showSingleTable.value = false
|
||||
nextTick(() => {
|
||||
showSingleTable.value = true
|
||||
})
|
||||
}
|
||||
if (localStorage.getItem('otherFileList')) {
|
||||
let param = JSON.parse(localStorage.getItem('otherFileList'))
|
||||
localFormData.value.otherFileList = param
|
||||
otherFileList.value = param
|
||||
localStorage.setItem('otherFileList', JSON.stringify(param))
|
||||
showTable.value = false
|
||||
nextTick(() => {
|
||||
showTable.value = true
|
||||
})
|
||||
}
|
||||
|
||||
if (localStorage.getItem('projectChargePersonUserList')) {
|
||||
let param = JSON.parse(localStorage.getItem('projectChargePersonUserList'))
|
||||
projectChargePersonUserList.value = param
|
||||
localStorage.setItem('projectChargePersonUserList', JSON.stringify(param))
|
||||
}
|
||||
if (localStorage.getItem('projectPersonUserList')) {
|
||||
let param = JSON.parse(localStorage.getItem('projectPersonUserList'))
|
||||
projectPersonUserList.value = param
|
||||
localProjectPerson.value = param
|
||||
localStorage.setItem('projectPersonUserList', JSON.stringify(param))
|
||||
}
|
||||
const getProjectPerson = (list) => {
|
||||
if (!list || list && list.length === 0) {
|
||||
if (localStorage.getItem('projectPersonUserList')) {
|
||||
let param = JSON.parse(localStorage.getItem('projectPersonUserList'))
|
||||
projectPersonUserList.value = param
|
||||
return projectPersonUserList.value
|
||||
}
|
||||
} else {
|
||||
return list
|
||||
}
|
||||
}
|
||||
const getRequestName = (list) => {
|
||||
if (!list || (list && list.length === 0)) {
|
||||
if (sessionParams.value.preProcess) {
|
||||
return sessionParams.value.preProcess
|
||||
}
|
||||
} else {
|
||||
return list
|
||||
}
|
||||
}
|
||||
const getTagsOption = () => {
|
||||
if (!route.query.projectId) return
|
||||
getTags(route.query.projectId).then(res => {
|
||||
if (res.code === 1000) {
|
||||
tagsOption.value = res.data
|
||||
} else {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleSearch = () => {
|
||||
let params = {
|
||||
targetId: route.query.projectId,
|
||||
targetState: "40"
|
||||
}
|
||||
if (attachmentParam.tag) {
|
||||
tagsOption.value.forEach(item => {
|
||||
if (item.value === attachmentParam.tag) {
|
||||
attachmentParam.tag = item.label
|
||||
}
|
||||
})
|
||||
params.tag = attachmentParam.tag
|
||||
}
|
||||
searchImplementationFileList(params).then(res => {
|
||||
showAttachmentTable.value = false
|
||||
if (res.code === 1000) {
|
||||
otherAttachmentList.value = res.data.fileList
|
||||
uploadState.value = res.data.upload
|
||||
nextTick(() => {
|
||||
showAttachmentTable.value = true
|
||||
})
|
||||
} else {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleUpload = () => {
|
||||
router.push({
|
||||
name: 'Implementation/upload',
|
||||
query: {
|
||||
id: route.query.id,
|
||||
projectId: route.query.projectId,
|
||||
state: route.query.state,
|
||||
step: '40'
|
||||
}
|
||||
})
|
||||
}
|
||||
const getProjectChargePersonUser = () => {
|
||||
if (projectChargePersonUserList.value.length !== 0) {
|
||||
return projectChargePersonUserList.value.map(item => item.name).join()
|
||||
}
|
||||
}
|
||||
const handleSelect = async (selection) => {
|
||||
selectRows.value = selection
|
||||
}
|
||||
const handleCancel = () => {
|
||||
showPreTable.value = false
|
||||
}
|
||||
const searchPreProcess = () => {
|
||||
getPreProcessList()
|
||||
|
||||
}
|
||||
const handleReset = () => {
|
||||
preProcessForm.requestName = ''
|
||||
getPreProcessList()
|
||||
}
|
||||
const handleShowPreTable = () => {
|
||||
showPreTable.value = true
|
||||
getPreProcessList()
|
||||
}
|
||||
const handleShowProjectChargePersonTable = () => {
|
||||
projectChargePersonUserPicker.value.showUserPicker()
|
||||
}
|
||||
const projectChargePersonUserPickerOk = (userList) => {
|
||||
projectChargePersonUserList.value = userList
|
||||
localStorage.setItem('projectChargePersonUserList', JSON.stringify(projectChargePersonUserList.value))
|
||||
}
|
||||
const handleShowProjectPersonTable = () => {
|
||||
projectPersonUserPicker.value.showUserPicker()
|
||||
}
|
||||
|
||||
const projectPersonUserPickerOk = (userList) => {
|
||||
projectPersonUserList.value = userList
|
||||
localStorage.setItem('projectPersonUserList', JSON.stringify(userList))
|
||||
// let userIds = []
|
||||
// for (const user of userList) {
|
||||
// userIds.push(user.id)
|
||||
// }
|
||||
}
|
||||
const getPreProcessList = () => {
|
||||
loading.value = true
|
||||
getPreProcess().then(res => {
|
||||
loading.value = false
|
||||
let searchArray = []
|
||||
let regexPattern = ("%" + preProcessForm.requestName + "%").replace(/%/g, '.*').replace(/_/g, '.');
|
||||
let regex = new RegExp('^' + regexPattern + '$');
|
||||
res.data.filter((item) => {
|
||||
if (regex.test(item.requestName)) {
|
||||
searchArray.push(item)
|
||||
}
|
||||
})
|
||||
// res.data.forEach((item) => {
|
||||
// localFormData.value.preProcess.forEach((item1) => {
|
||||
// if (item.requestId == item1.requestId) {
|
||||
// preProcessTable.value.toggleRowSelection(item)
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
total.value = searchArray.length
|
||||
currentList.value = searchArray
|
||||
preProcessList.value = currentList.value.slice(0, 10)
|
||||
})
|
||||
}
|
||||
const choosePreProcess = () => {
|
||||
let preProcessObj = {}
|
||||
let preProcessArray = []
|
||||
selectRows.value.forEach((item) => {
|
||||
preProcessObj = {
|
||||
requestId: item.requestId,
|
||||
requestName: item.requestName,
|
||||
baseUrl: item.baseUrl
|
||||
}
|
||||
preProcessArray.push(preProcessObj)
|
||||
})
|
||||
localFormData.value.preProcess = preProcessArray
|
||||
showPreTable.value = false
|
||||
localStorage.setItem('preProcess', JSON.stringify(preProcessArray))
|
||||
}
|
||||
|
||||
//切换每页显示条数
|
||||
const handleSizeChange = (val) => {
|
||||
pageInfo.pageSize = val;
|
||||
preProcessList.value = currentList.value.slice((pageInfo.pageNum - 1) * val, pageInfo.pageNum * val)
|
||||
};
|
||||
|
||||
//点击页码进行分页功能
|
||||
const handleCurrentChange = (val) => {
|
||||
pageInfo.pageNum = val;
|
||||
preProcessList.value = currentList.value.slice((val - 1) * pageInfo.pageSize, val * pageInfo.pageSize)
|
||||
};
|
||||
const getTitleName = (type) => {
|
||||
switch (type) {
|
||||
case 'apply':
|
||||
return '项目立项'
|
||||
case 'check':
|
||||
return '项目验收'
|
||||
case 'filing':
|
||||
return '项目归档'
|
||||
}
|
||||
}
|
||||
const handleBack = () => {
|
||||
history.back()
|
||||
}
|
||||
const compositeParam = (item) => {
|
||||
return {
|
||||
fileId: item.id,
|
||||
size: item.size,
|
||||
originalFileName: item.originalFilename,
|
||||
fileType: item.fileType,
|
||||
url: item.url,
|
||||
newFile: true,
|
||||
tag: getTitleName(props.title)
|
||||
}
|
||||
}
|
||||
const getAttachment = (val) => {
|
||||
// console.log('上传文件getAttachment', val)
|
||||
showSingleTable.value = false
|
||||
localFormData.value.singleFile = compositeParam(val)
|
||||
singleList.value.push(compositeParam(val))
|
||||
nextTick(() => {
|
||||
showSingleTable.value = true
|
||||
if (attachment.value.singleFile == null) {
|
||||
attachment.value.validate()
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: '请上传附件',
|
||||
type: 'error'
|
||||
})
|
||||
return;
|
||||
} else {
|
||||
attachment.value.clearValidate()
|
||||
}
|
||||
})
|
||||
|
||||
localStorage.setItem('singleFile', JSON.stringify(compositeParam(val)))
|
||||
}
|
||||
watch(() => singleList.value, (newVal) => {
|
||||
showSingleTable.value = newVal.length !== 0;
|
||||
}, {deep: true})
|
||||
const getOtherFile = (val) => {
|
||||
// console.log('上传文件getOtherFile', val)
|
||||
showTable.value = false
|
||||
let fileObj = compositeParam(val)
|
||||
otherFileList.value.push(fileObj)
|
||||
nextTick(() => {
|
||||
showTable.value = true
|
||||
})
|
||||
|
||||
// localFormData.value.otherFileList = otherFileList.value
|
||||
localStorage.setItem('otherFileList', JSON.stringify(otherFileList.value))
|
||||
}
|
||||
const getFileParam = (item) => {
|
||||
return {
|
||||
fileId: item.fileId,
|
||||
tag: item.tag
|
||||
}
|
||||
}
|
||||
const handleSubmit = async () => {
|
||||
if (deploymentData.value.deploymentName === '重大项目立项' || deploymentData.value.deploymentName === '重大项目验收') {
|
||||
if (localFormData.value.preProcess == undefined) {
|
||||
if (JSON.parse(localStorage.getItem('preProcess'))?.length > 0) {
|
||||
|
||||
} else {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: '请选择前置流程!',
|
||||
type: 'error'
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let files = []
|
||||
if (props.mode === 'resubmit') {
|
||||
attachment.value.allFileList.forEach(item => {
|
||||
files.push(getFileParam(item))
|
||||
})
|
||||
} else {
|
||||
otherFileList.value.forEach(item => {
|
||||
files.push(getFileParam(item))
|
||||
})
|
||||
}
|
||||
if (attachment.value.singleFile == null) {
|
||||
attachment.value.validate()
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: '请上传附件',
|
||||
type: 'error'
|
||||
})
|
||||
return;
|
||||
} else {
|
||||
attachment.value.clearValidate()
|
||||
}
|
||||
let projectPersonIds = []
|
||||
for (const item of projectPersonUserList.value) {
|
||||
projectPersonIds.push(parseInt(item.id))
|
||||
}
|
||||
let params = {
|
||||
deploymentId: deploymentId.value,
|
||||
requirementId: route.query.id,
|
||||
fileList: files,
|
||||
singleFile: attachment.value.singleFile,
|
||||
projectId: projectId.value,
|
||||
preProcess: JSON.stringify(localFormData.value.preProcess)
|
||||
}
|
||||
if (sessionParams.value.preProcess && !localFormData.value.preProcess) {
|
||||
params.preProcess = JSON.stringify(sessionParams.value.preProcess)
|
||||
}
|
||||
// console.log(params.preProcess)
|
||||
let res
|
||||
if (props.step === '20') {
|
||||
if (projectChargePersonUserList.value && projectChargePersonUserList.value.length === 0) {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: '请选择项目负责人!',
|
||||
type: 'error'
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (projectPersonUserList.value && projectPersonUserList.value.length === 0) {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: '请选择项目成员!',
|
||||
type: 'error'
|
||||
})
|
||||
return;
|
||||
}
|
||||
params.projectChargePerson = parseInt(projectChargePersonUserList.value[0].id)
|
||||
params.projectPersonIds = projectPersonIds
|
||||
if (props.mode === 'resubmit') {
|
||||
res = await resubmitApply(params)
|
||||
} else {
|
||||
res = await projectApply(params)
|
||||
}
|
||||
} else if (props.step === '40') {
|
||||
if (props.mode === 'resubmit') {
|
||||
res = await resubmitCheck(params)
|
||||
} else {
|
||||
res = await projectCheck(params)
|
||||
}
|
||||
} else if (props.step === '50') {
|
||||
if (props.mode === 'resubmit') {
|
||||
res = await resubmitConclusion(params)
|
||||
} else {
|
||||
res = await projectConclusion(params)
|
||||
}
|
||||
}
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: res.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
if (res.code === 1000) {
|
||||
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||
if (props.step === '20') {
|
||||
await router.push({
|
||||
name: 'Initiation'
|
||||
})
|
||||
} else if (props.step === '40') {
|
||||
await router.push({
|
||||
name: 'Implementation'
|
||||
})
|
||||
} else if (props.step === '50') {
|
||||
await router.push({
|
||||
name: 'Filing'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
const init = async () => {
|
||||
if (props.title && props.title === 'check') {
|
||||
handleSearch()
|
||||
getTagsOption()
|
||||
}
|
||||
let id = projectId.value
|
||||
if (!id) return;
|
||||
processDiagramViewer.value = false
|
||||
let res
|
||||
if (props.step === '20') {
|
||||
res = await getApplyProcess(id)
|
||||
} else if (props.step === '40') {
|
||||
res = await getProjectCheckProcess(id)
|
||||
} else if (props.step === '50') {
|
||||
res = await getProjectConclusionProcess(id)
|
||||
}
|
||||
if (res.code === 1000) {
|
||||
let data = res.data
|
||||
deploymentId.value = data.deploymentId
|
||||
deploymentData.value = data
|
||||
preProcessRequired.value = data.deploymentName === '重大项目立项' || data.deploymentName === '重大项目验收';
|
||||
processStore.setDesign(data)
|
||||
processStore.runningList.value = data.runningList;
|
||||
processStore.endList.value = data.endList;
|
||||
processStore.noTakeList.value = data.noTakeList;
|
||||
processStore.refuseList.value = data.refuseList;
|
||||
processStore.passList.value = data.passList;
|
||||
nextTick(() => {
|
||||
processDiagramViewer.value = true
|
||||
})
|
||||
} else {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.formData.projectChargePerson == null) {
|
||||
// projectChargePersonUserList.value = []
|
||||
} else {
|
||||
projectChargePersonUserList.value = [props.formData.projectChargePerson]
|
||||
}
|
||||
// console.log('props.formData.projectPersonList',props.formData.projectPersonList)
|
||||
projectPersonUserList.value = props.formData.projectPersonList ? props.formData.projectPersonList : []
|
||||
let flag = Object.keys(props.formData).length && (localFormData.value = props.formData)
|
||||
if (props.formData.projectChargePerson != null) {
|
||||
localFormData.value.projectChargePerson = props.formData.projectChargePerson.id
|
||||
}
|
||||
// if(props.formData.fileList&&props.formData.fileList.length>0){
|
||||
// otherFileList.value=props.formData.fileList
|
||||
// }
|
||||
// localFormData.value.projectPersonIds = []
|
||||
// if (projectPersonUserList.value){
|
||||
// projectPersonUserList.value.forEach(item => {
|
||||
// localFormData.value.projectPersonIds.push(item.id)
|
||||
// })
|
||||
// }
|
||||
// console.log('projectPersonUserList.value',projectPersonUserList.value)
|
||||
return flag
|
||||
})
|
||||
onActivated(() => {
|
||||
init()
|
||||
})
|
||||
onMounted(async () => {
|
||||
await init()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.oper {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
234
src/components/DetailComponent/SpecialFundDetail.vue
Normal file
@@ -0,0 +1,234 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<baseTitle title="专项资金详情"></baseTitle>
|
||||
<el-form :model="formData" ref="form" label-width="auto">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="专项名称">
|
||||
<span>{{ formData.name }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="金额(元)">
|
||||
<span>{{ toThousands(formData.fundAmount) }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="剩余金额(元)">
|
||||
<span>{{ toThousands(formData.residualAmount) }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<baseTitle title="介绍"></baseTitle>
|
||||
<el-col :span="24">
|
||||
<el-form-item>
|
||||
<el-card style="width: 100%">
|
||||
<div v-html="formData.introduce">
|
||||
</div>
|
||||
</el-card>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<baseTitle title="关联项目" v-if="!data.taskId"></baseTitle>
|
||||
<el-col :span="24" v-if="!data.taskId">
|
||||
<el-form-item>
|
||||
<fvTable style="width: 100%;max-height:162px" height="162" v-if="showTable" :tableConfig="projectTable"
|
||||
:data="formData.projects" :isSettingCol="false" :pagination="false">
|
||||
<template #empty>
|
||||
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
|
||||
</template>
|
||||
</fvTable>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<baseTitle title="附件列表"></baseTitle>
|
||||
<el-col :span="24">
|
||||
<el-form-item>
|
||||
<fvTable style="width: 100%;max-height: 162px;" height="162" v-if="showTable" :tableConfig="fileTable"
|
||||
:data="formData.files" :isSettingCol="false" :pagination="false">
|
||||
<template #empty>
|
||||
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
|
||||
</template>
|
||||
</fvTable>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<div v-if="data.taskId">
|
||||
<baseTitle title="审核意见"></baseTitle>
|
||||
<el-form-item prop="auditOpinion">
|
||||
<el-input
|
||||
v-model="formData.auditOpinion"
|
||||
:rows="3"
|
||||
type="textarea"
|
||||
placeholder="请输入审核意见"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="approval-record">
|
||||
<div class="approval-title">
|
||||
<baseTitle title="审批记录"></baseTitle>
|
||||
<div class="diagram">
|
||||
<div class="base-title">流程图</div>
|
||||
<el-switch
|
||||
v-model="changeDiagram"
|
||||
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="process">
|
||||
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
|
||||
:operation-list="data.operationList"
|
||||
:state="data.state"/>
|
||||
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="fundProcess"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
<opinion v-if="data.taskId" :formData="data.formData" :taskId="data.taskId"
|
||||
v-model:value="formData.auditOpinion"></opinion>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import {toThousands} from '@/utils/changePrice.js'
|
||||
import OperationRender from '@/views/workflow/common/OperationRender.vue'
|
||||
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
|
||||
import {downloadFile} from "@/api/project-demand";
|
||||
|
||||
const changeDiagram = ref(false)
|
||||
const emit = defineEmits(['getInfo', "update:formData"])
|
||||
const form = ref()
|
||||
const router = useRouter()
|
||||
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
processViewer: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}, showTable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
const projectTable = reactive({
|
||||
columns: [
|
||||
{
|
||||
prop: 'index',
|
||||
type: 'index',
|
||||
label: '序号',
|
||||
align: 'center',
|
||||
width: '80',
|
||||
},
|
||||
{
|
||||
prop: 'projectName',
|
||||
label: '项目名称',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'specialFundAmount',
|
||||
label: '项目金额',
|
||||
align: 'center',
|
||||
currentRender:({row})=>{
|
||||
return <span>{toThousands(row.specialFundAmount)}</span>
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'startTime',
|
||||
label: '项目时间',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'oper',
|
||||
label: '操作',
|
||||
align: 'center',
|
||||
currentRender: ({row, index}) => {
|
||||
return (
|
||||
<el-button type="primary" link onClick={() => handleView(row)}>查看</el-button>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const fileTable = reactive({
|
||||
columns: [
|
||||
{
|
||||
prop: 'index',
|
||||
type: 'index',
|
||||
label: '序号',
|
||||
align: 'center',
|
||||
width: '80',
|
||||
},
|
||||
{
|
||||
prop: 'originalFileName',
|
||||
label: '文件名',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'tag',
|
||||
label: '标签',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'size',
|
||||
label: '文件大小',
|
||||
align: 'center',
|
||||
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||
},
|
||||
{
|
||||
prop: 'oper',
|
||||
label: '操作',
|
||||
align: 'center',
|
||||
currentRender: ({row, index}) => {
|
||||
return (
|
||||
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const handleView=(row)=>{
|
||||
router.push({
|
||||
name: 'Implementation/detail',
|
||||
query: {
|
||||
id: row.requirementId,
|
||||
projectId: row.projectId,
|
||||
step: '10'
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleDownload = (row) => {
|
||||
downloadFile(row.fileId).then(res => {
|
||||
const blob = new Blob([res])
|
||||
let a = document.createElement('a')
|
||||
a.href = URL.createObjectURL(blob)
|
||||
a.download = row.originalFileName
|
||||
a.click()
|
||||
})
|
||||
}
|
||||
|
||||
watch(() => props.loading, (newVal) => {
|
||||
props.loading = newVal
|
||||
}, {deep: true})
|
||||
|
||||
watch(() => props.processViewer, (newVal) => {
|
||||
props.processViewer = newVal
|
||||
}, {deep: true})
|
||||
watch(() => props.showTable, (newVal) => {
|
||||
props.showTable = newVal
|
||||
}, {deep: true})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.el-table--fit ) {
|
||||
height: 300px !important;
|
||||
}
|
||||
</style>
|
||||
370
src/components/DetailComponent/SummaryDetail.vue
Normal file
@@ -0,0 +1,370 @@
|
||||
<template>
|
||||
<div class="detail-block" v-loading="loading">
|
||||
<baseTitle title="需求上报信息"></baseTitle>
|
||||
<el-form :model="localFormData" ref="summaryForm" :rules="rules">
|
||||
<el-row gutter="50">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<span>{{ localFormData.projectName }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="开始时间" prop="startTime">
|
||||
<span>{{ localFormData.startTime }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="结束时间" prop="endTime">
|
||||
<span>{{ localFormData.endTime }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="项目类型" prop="projectType">
|
||||
<span>{{ filterDict(cacheStore.getDict('project_type'), localFormData.projectType) }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="研发主体" prop="rdSubject">
|
||||
<span>{{ filterDict(cacheStore.getDict('rd_subject'), localFormData.rdSubject) }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出资类型" prop="investmentType">
|
||||
<span>{{ filterDict(cacheStore.getDict('invest_type'), localFormData.investmentType) }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="8">-->
|
||||
<!-- <el-form-item label="项目影响" prop="projectImpact">-->
|
||||
<!-- <span>{{ filterDict(cacheStore.getDict('project_impact'), localFormData.projectImpact) }}</span>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-col>-->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="所属业务板块" prop="businessSegment">
|
||||
<span>{{ filterDict(cacheStore.getDict('business_segment'), localFormData.businessSegment) }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="预期技术标准制定" prop="technicalStandard">
|
||||
<span>{{ filterDict(cacheStore.getDict('technical_standard'), localFormData.technicalStandard) }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="产学研联合" prop="industryUniversityResearch">
|
||||
<span>{{
|
||||
filterDict(cacheStore.getDict('industry_university'), localFormData.industryUniversityResearch)
|
||||
}}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="开展政府申报" prop="governmentDeclaration">
|
||||
<span>{{
|
||||
filterDict(cacheStore.getDict('government_declaration'), localFormData.governmentDeclaration)
|
||||
}}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" v-if="localFormData.isSpecialFund">
|
||||
<el-form-item label="专项资金名称" prop="specialFund">
|
||||
<span>{{
|
||||
localFormData.specialFundId === 0 ? localFormData.specialFund : changeName(fundOption, localFormData.specialFundId)
|
||||
}}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="知识产权状况" prop="intellectualProperty">
|
||||
<span>{{
|
||||
filterDict(cacheStore.getDict('intellectual_property'), localFormData.intellectualProperty)
|
||||
}}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-form-item label="预期成果形式" prop="resultForm">
|
||||
<span>{{ filterDict(cacheStore.getDict('result_form'), localFormData.resultForm) }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<baseTitle title="预期知识产权"></baseTitle>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="发明专利(项)" prop="inventionPatent">
|
||||
<span>{{ localFormData.inventionPatent }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="实用性新型专利(项)" prop="newPatent">
|
||||
<span>{{ localFormData.newPatent }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="软件著作权(项)" prop="softwareCopyright">
|
||||
<span>{{ localFormData.softwareCopyright }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="著作权(项)" prop="copyright">
|
||||
<span>{{ localFormData.copyright }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="其他(项)" prop="other">
|
||||
<span>{{ localFormData.other }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="经济预算(元)" prop="economicEstimate">
|
||||
<span>{{ toThousands(localFormData.economicEstimate) }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="其中申请公司总部科技创新专项资金(元)" prop="specialFundAmount"
|
||||
v-if="localFormData.isSpecialFund">
|
||||
<span>{{ toThousands(localFormData.specialFundAmount) }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="现有业务描述" prop="serviceDescription">
|
||||
<span>{{ localFormData.serviceDescription }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="研发项目关键内容描述" prop="contentDescription">
|
||||
<span>{{ localFormData.contentDescription }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<baseTitle title="需求上报申请书"></baseTitle>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item>
|
||||
<el-button type="primary" link @click="handleDownload(localFormData.singleFile)" style="font-size: 16px">
|
||||
{{ localFormData.singleFile?.originalFileName }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<baseTitle title="附件列表"></baseTitle>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<file-component tag="需求上报"
|
||||
v-model:value="localFormData.fileList" :processViewer="processViewer"
|
||||
:file-list-show="fileListShow"/>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<div v-if="data.taskId||data.state==='4'">
|
||||
<baseTitle title="审核意见"></baseTitle>
|
||||
<el-form-item prop="_value">
|
||||
<el-input
|
||||
v-model="_value"
|
||||
:rows="3"
|
||||
type="textarea"
|
||||
placeholder="请输入审核意见"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="approval-record">
|
||||
<div class="approval-title">
|
||||
<baseTitle title="审批记录"></baseTitle>
|
||||
<div class="diagram">
|
||||
<div class="base-title">流程图</div>
|
||||
<el-switch
|
||||
v-model="changeDiagram"
|
||||
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="process">
|
||||
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
|
||||
:operation-list="data.operationList"
|
||||
:step="'report'"
|
||||
:state="data.state"/>
|
||||
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="summaryProcess"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="oper-page-btn" v-perm="['annual:plan:approve']" v-if="data.state==='4'">
|
||||
<el-button type="danger" @click="handleRejectPlan">驳回年度计划</el-button>
|
||||
<el-button color="#DED0B2" @click="handleAgreePlan">通过年度计划</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import {toThousands} from '@/utils/changePrice.js'
|
||||
import {downloadFile, deleteFile} from "@/api/project-demand";
|
||||
import OperationRender from '@/views/workflow/common/OperationRender.vue'
|
||||
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
|
||||
import {useTagsView} from '@/stores/tagsview.js'
|
||||
import {getFundOption} from "@/api/special-fund";
|
||||
import {useCacheStore} from '@/stores/cache.js'
|
||||
import {getSubCompOpt} from "@/api/user/user";
|
||||
import FileComponent from "./FileComponent.vue";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {approvePlan} from "@/api/project-demand/summary";
|
||||
|
||||
const emit = defineEmits(['update:value'])
|
||||
const tagsViewStore = useTagsView()
|
||||
const cacheStore = useCacheStore()
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: {
|
||||
state: '1'
|
||||
}
|
||||
},
|
||||
processViewer: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
fileListShow: {
|
||||
type: String,
|
||||
default: 'READ'
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
const changeDiagram = ref(false)
|
||||
const localFormData = ref({})
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const fundOption = ref([])
|
||||
const companyOption = ref([])
|
||||
const dictName = ref({})
|
||||
const rules = reactive({
|
||||
auditOpinion: [{required: true, message: '请输入审核意见', trigger: 'blur'}],
|
||||
})
|
||||
const _value = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(val) {
|
||||
emit("update:value", val);
|
||||
}
|
||||
})
|
||||
const handleRejectPlan = async () => {
|
||||
// const values = form.value.getValues()
|
||||
// console.log('route',route.query.projectId)
|
||||
if (!_value.value) {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: '请填写审核意见',
|
||||
type: 'warning'
|
||||
})
|
||||
return
|
||||
}
|
||||
const params = {
|
||||
auditOpinion:_value.value,
|
||||
projectId:parseInt(route.query.projectId),
|
||||
state:false
|
||||
}
|
||||
// console.log('params', params)
|
||||
const res = await approvePlan(params)
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: res.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||
router.push({
|
||||
name: 'Summary'
|
||||
})
|
||||
}
|
||||
const handleAgreePlan = async () => {
|
||||
const params = {
|
||||
auditOpinion:_value.value,
|
||||
projectId:parseInt(route.query.projectId),
|
||||
state:true
|
||||
}
|
||||
// console.log('params', params)
|
||||
const res = await approvePlan(params)
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: res.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||
router.push({
|
||||
name: 'Summary'
|
||||
})
|
||||
}
|
||||
const filterDict = (data, value) => {
|
||||
if (data === undefined || value === undefined) return;
|
||||
let label = ''
|
||||
let result = []
|
||||
if (value instanceof Array) {
|
||||
value.forEach(item1 => {
|
||||
data.find(item => {
|
||||
if (item.value == item1) {
|
||||
result.push(item.label)
|
||||
}
|
||||
})
|
||||
})
|
||||
label = result.map(item => item).join(',')
|
||||
} else {
|
||||
if (data instanceof Array) {
|
||||
data.find(item => {
|
||||
if (item.value == value) {
|
||||
label = item.label
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return label
|
||||
}
|
||||
const getFundOptions = async () => {
|
||||
const resFund = await getFundOption()
|
||||
fundOption.value = resFund.data
|
||||
const res = await getSubCompOpt()
|
||||
companyOption.value = res.data
|
||||
}
|
||||
const changeName = (option, value) => {
|
||||
let name = ''
|
||||
option.forEach(item => {
|
||||
if (item.value == value) {
|
||||
name = item.label
|
||||
}
|
||||
})
|
||||
return name
|
||||
}
|
||||
const handleDownload = (row) => {
|
||||
downloadFile(row.fileId).then(res => {
|
||||
const blob = new Blob([res])
|
||||
let a = document.createElement('a')
|
||||
a.href = URL.createObjectURL(blob)
|
||||
a.download = row.originalFileName
|
||||
a.click()
|
||||
})
|
||||
}
|
||||
|
||||
watch(() => props.processViewer, (newVal) => {
|
||||
props.processViewer = newVal
|
||||
}, {deep: true})
|
||||
|
||||
watch(() => props.loading, (newVal) => {
|
||||
props.loading = newVal
|
||||
}, {deep: true})
|
||||
|
||||
watchEffect(() => {
|
||||
return Object.keys(props.formData).length && (localFormData.value = props.formData)
|
||||
})
|
||||
|
||||
getFundOptions()
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.detail-block {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 0!important;
|
||||
}
|
||||
</style>
|
||||
@@ -4,26 +4,29 @@
|
||||
:headers="headers"
|
||||
:limit="maxSize"
|
||||
with-credentials
|
||||
:multiple="maxSize > 0"
|
||||
:multiple="multiple"
|
||||
:data="uploadParams"
|
||||
:show-file-list="false"
|
||||
:show-file-list="showFileList"
|
||||
:auto-upload="true"
|
||||
:before-upload="beforeUpload"
|
||||
:on-success="handleUploadSuccess"
|
||||
:on-error="uploadError"
|
||||
:before-remove="beforeRemove"
|
||||
:on-remove="handleRemove"
|
||||
>
|
||||
<el-button color="#DED0B2" :loading="loading">上传文件</el-button>
|
||||
<el-button color="#DED0B2" :loading="loading" :disabled="disabled">上传文件</el-button>
|
||||
</el-upload>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ElMessage} from "element-plus";
|
||||
import { ElMessageBox, ElNotification} from "element-plus";
|
||||
import {getToken} from '@/utils/auth'
|
||||
|
||||
const baseURL = import.meta.env.VITE_BASE_URL
|
||||
const uploadFileUrl = ref(baseURL + "/workflow/process/file/upload")
|
||||
const headers = reactive({
|
||||
authorization: getToken()
|
||||
})
|
||||
const disabled = ref(false)
|
||||
const loading = ref(false)
|
||||
const showTable = ref(false)
|
||||
const uploadParams = ref({})
|
||||
@@ -37,10 +40,22 @@ const props = defineProps({
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: 30
|
||||
},
|
||||
showFileList: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(["input", "getFile"])
|
||||
const emit = defineEmits(["input", "getFile", "delete"])
|
||||
const fileList = ref([])
|
||||
const _value = computed({
|
||||
get() {
|
||||
@@ -50,34 +65,44 @@ const _value = computed({
|
||||
emit("input", val);
|
||||
}
|
||||
})
|
||||
const beforeRemove = (file) => {
|
||||
return ElMessageBox.confirm(`确认删除名称为${file.name}的文件吗?`, '系统提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => true)
|
||||
}
|
||||
|
||||
const beforeUpload = (file) => {
|
||||
// const FileExt = file.name.replace(/.+\./, "");
|
||||
// if (['zip', 'rar', 'pdf', 'doc', 'docx', 'xlsx'].indexOf(FileExt.toLowerCase()) === -1) {
|
||||
// ElMessage.warning('请上传后缀名为pdf、doc、docx、xlsx、zip或rar的文件!');
|
||||
// return false;
|
||||
// } else
|
||||
// if (props.maxSize > 0 && file.size / 1024 / 1024 > props.maxSize) {
|
||||
// ElMessage.warning(`每个文件最大不超过 ${props.maxSize}MB`)
|
||||
// } else {
|
||||
const handleRemove = (file) => {
|
||||
emit("delete", file.response.data.id)
|
||||
}
|
||||
const beforeUpload = () => {
|
||||
loading.value = true
|
||||
return true
|
||||
// }
|
||||
}
|
||||
const handleUploadSuccess = (res, file) => {
|
||||
if (res.code !== 1000) {
|
||||
const handleUploadSuccess = (res) => {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.code === 1000 ? '上传成功' : '上传失败',
|
||||
type: res.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
loading.value = false
|
||||
ElMessage.error("上传失败")
|
||||
} else {
|
||||
loading.value = false
|
||||
ElMessage.success("上传成功")
|
||||
}
|
||||
showTable.value = true
|
||||
let data = res.data
|
||||
fileList.value.push(data)
|
||||
emit("getFile", fileList.value)
|
||||
emit("getFile", res.data)
|
||||
}
|
||||
|
||||
const uploadError = () => {
|
||||
loading.value = false
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: "上传失败,请稍后再试!",
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
defineExpose({
|
||||
handleRemove
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -85,4 +110,8 @@ a {
|
||||
font-size: 14px;
|
||||
color: #2a99ff;
|
||||
}
|
||||
|
||||
:deep(.el-upload-list) {
|
||||
width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
||||
117
src/components/ImportExcel.vue
Normal file
@@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<el-upload :file-list="[]"
|
||||
:limit="maxSize"
|
||||
with-credentials
|
||||
:multiple="multiple"
|
||||
:http-request="httpRequestHandle"
|
||||
:data="uploadParams"
|
||||
:auto-upload="true"
|
||||
:show-file-list="false"
|
||||
:before-upload="beforeUpload"
|
||||
:before-remove="beforeRemove"
|
||||
:on-remove="handleRemove"
|
||||
>
|
||||
<el-button color="#DED0B2" style="margin-left: 10px; margin-right: 10px;" :disabled="disabled">导入</el-button>
|
||||
</el-upload>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ElMessageBox, ElNotification} from "element-plus";
|
||||
import {getToken} from '@/utils/auth'
|
||||
import axios from "axios";
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: 30
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
projectId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const baseURL = import.meta.env.VITE_BASE_URL
|
||||
const uploadFileUrl = ref(baseURL + "/workflow/mosr/expense/ledger/import?projectId=" + props.projectId)
|
||||
const headers = reactive({
|
||||
authorization: getToken()
|
||||
})
|
||||
// const loading = ref(false)
|
||||
const uploadParams = ref({})
|
||||
const emit = defineEmits(["input", "getFile", "delete"])
|
||||
const beforeRemove = (file) => {
|
||||
return ElMessageBox.confirm(`确认删除名称为${file.name}的文件吗?`, '系统提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => true)
|
||||
}
|
||||
|
||||
const handleRemove = (file) => {
|
||||
emit("delete", file.response.data.id)
|
||||
}
|
||||
const beforeUpload = () => {
|
||||
// loading.value = true
|
||||
console.log('水电费水电费,beforeUpload')
|
||||
return true
|
||||
}
|
||||
const httpRequestHandle = (param) => {
|
||||
|
||||
let file = param.file
|
||||
axios.post(uploadFileUrl.value, {
|
||||
file: file
|
||||
}, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
...headers
|
||||
}
|
||||
}).then(res => {
|
||||
handleUploadSuccess(res)
|
||||
}).catch(error => {
|
||||
uploadError(error)
|
||||
})
|
||||
}
|
||||
const handleUploadSuccess = (res) => {
|
||||
let data = res.data
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: data.code === 1000 ? '上传成功' : '上传失败',
|
||||
type: data.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
emit("success")
|
||||
}
|
||||
const uploadError = (error) => {
|
||||
// loading.value = false
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: "上传失败,请稍后再试!",
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
defineExpose({
|
||||
handleRemove
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
a {
|
||||
font-size: 14px;
|
||||
color: #2a99ff;
|
||||
}
|
||||
|
||||
</style>
|
||||
107
src/components/NameCircle.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<div style="display: block">
|
||||
<slot name="pre"></slot>
|
||||
<div class="user-audit">
|
||||
<div class="circle-user">
|
||||
<Tooltip :content="user.name" placement="bottom-start" width="45px"/>
|
||||
<div v-if="user.icon"
|
||||
class="el-timeline-item__node" :style="{
|
||||
backgroundColor: user.color
|
||||
}">
|
||||
<el-icon v-if="user.icon" size="15" :class="user.class">
|
||||
<component :is="user.icon"/>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {Loading, Close, CircleCheckFilled, MoreFilled} from '@element-plus/icons-vue'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
hoverTip: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
user: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
|
||||
const init = () => {
|
||||
// for (let user of props.userInfo) {
|
||||
initUser(props.user)
|
||||
// }
|
||||
}
|
||||
|
||||
const initUser = (user) => {
|
||||
let state = user.state
|
||||
//创建节点
|
||||
if (state === 'CREATE') {
|
||||
user["icon"] = CircleCheckFilled
|
||||
user["color"] = "#0bbd87"
|
||||
}
|
||||
//审批通过
|
||||
if (state === 'AGREE' || state === 'AUTO_PASS') {
|
||||
user["icon"] = CircleCheckFilled
|
||||
user["color"] = "#0bbd87"
|
||||
}
|
||||
//审批处理中
|
||||
if (state === 'RUNNING') {
|
||||
user["icon"] = Loading
|
||||
user["color"] = "#f78f5f"
|
||||
user["class"] = 'is-loading'
|
||||
}
|
||||
//拒绝后评论
|
||||
if (state === 'REFUSE') {
|
||||
user["icon"] = Close
|
||||
user["color"] = "#f56c6c"
|
||||
}
|
||||
if (state === 'PASS') {
|
||||
user["icon"] = MoreFilled
|
||||
user["color"] = "#c0c4cc"
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
init()
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.user-audit {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.circle-user {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #ACACAC;
|
||||
position: relative;
|
||||
background-color: #8a7243;
|
||||
color: #fff;
|
||||
.el-timeline-item__node {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -9,7 +9,8 @@
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button :type="btnType" size="mini" v-perm="perm" :disabled="isDisabled" :icon="btnIcon" :plain="isPlain">
|
||||
<!-- v-perm="perm"-->
|
||||
<el-button :type="btnType" size="mini" :disabled="isDisabled" :icon="btnIcon" :plain="isPlain" :link="link">
|
||||
{{ btnText }}
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -24,12 +25,16 @@ const props = defineProps({
|
||||
},
|
||||
btnType: {
|
||||
type: String,
|
||||
default: 'text'
|
||||
default: 'danger'
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
link: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
btnIcon: {
|
||||
type: String,
|
||||
default: ''
|
||||
|
||||
168
src/components/SearchFilesByTag.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<div v-loading="_value">
|
||||
<el-form :model="attachment" inline>
|
||||
<el-form-item label="名称" prop="fileName">
|
||||
<el-input v-model="attachment.fileName" placeholder="请输入附件名称查询" clearable filterable style="width: 300px"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签" prop="tag" v-if="type==='40'">
|
||||
<el-select v-model="attachment.tag" placeholder="请选择标签" clearable filterable style="width: 300px">
|
||||
<el-option
|
||||
v-for="item in tagsOption"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleSearch" color="#DED0B2">搜索</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
<el-button v-if="uploadState" color="#DED0B2" @click="handleUpload">上传附件</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-card style="width: 100%">
|
||||
<fvTable style="width: 100%;max-height: 300px" v-if="showTable" height="300" :tableConfig="tableConfig"
|
||||
:data="fileList" :isSettingCol="false" :pagination="false">
|
||||
<template #empty>
|
||||
<el-empty :image-size="99" description="暂无数据" style="padding: 0"/>
|
||||
</template>
|
||||
</fvTable>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import {downloadFile} from "@/api/project-demand";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {getTags} from "@/api/project-manage";
|
||||
import {computed} from "vue";
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const attachment = reactive({})
|
||||
const emit = defineEmits(['search','update:modelValue'])
|
||||
const props = defineProps({
|
||||
fileList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: '00'
|
||||
},
|
||||
uploadState: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
const tagsOption = ref([])
|
||||
const tableConfig = reactive({
|
||||
columns: [
|
||||
{
|
||||
prop: 'originalFileName',
|
||||
label: '附件名称',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'tag',
|
||||
label: '标签',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'size',
|
||||
label: '文件大小',
|
||||
align: 'center',
|
||||
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||
},
|
||||
{
|
||||
prop: 'createTime',
|
||||
label: '上传时间',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'oper',
|
||||
label: '操作',
|
||||
align: 'center',
|
||||
showOverflowTooltip: false,
|
||||
currentRender: ({row, index}) => {
|
||||
return (
|
||||
<div>
|
||||
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const showTable = ref(true)
|
||||
const _value = computed({
|
||||
get() {
|
||||
return props.loading || ""
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
const getTagsOption = () => {
|
||||
if (!route.query.id) return
|
||||
getTags(route.query.id).then(res => {
|
||||
if (res.code === 1000) {
|
||||
tagsOption.value = res.data
|
||||
} else {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleSearch = () => {
|
||||
emit('search', attachment)
|
||||
}
|
||||
const handleReset=()=>{
|
||||
attachment.fileName=''
|
||||
attachment.tag=null
|
||||
emit('search', {})
|
||||
}
|
||||
const handleUpload = () => {
|
||||
emit('upload')
|
||||
}
|
||||
const handleDownload = (row) => {
|
||||
downloadFile(row.fileId).then(res => {
|
||||
const blob = new Blob([res])
|
||||
let a = document.createElement('a')
|
||||
a.href = URL.createObjectURL(blob)
|
||||
a.download = row.originalFileName
|
||||
a.click()
|
||||
})
|
||||
}
|
||||
watch(() => props.type, (val) => {
|
||||
props.type = val
|
||||
})
|
||||
watch(() => props.fileList, (val) => {
|
||||
showTable.value = false
|
||||
nextTick(() => {
|
||||
showTable.value = true
|
||||
})
|
||||
props.fileList = val
|
||||
})
|
||||
if (props.type === '40') {
|
||||
getTagsOption()
|
||||
}
|
||||
|
||||
onActivated(()=>{
|
||||
if (props.type === '40') {
|
||||
getTagsOption()
|
||||
}
|
||||
handleSearch()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="tag-style">
|
||||
<el-tag v-if="tagConfig.isType" :type="tagConfig.listClass" :effect="tagConfig.theme || 'plain'">
|
||||
<el-tag v-if="tagConfig?.isType" :type="tagConfig?.listClass" :effect="tagConfig?.theme || 'plain'">
|
||||
{{ filterDict(cacheStore.getDict(dictType), value) }}
|
||||
</el-tag>
|
||||
<el-tag v-else :color="tagConfig.listClass" :effect="tagConfig.theme || 'plain'"
|
||||
<el-tag v-else :color="tagConfig?.listClass" :effect="tagConfig?.theme || 'plain'"
|
||||
:class="{'null-tag':filterDict(cacheStore.getDict(dictType), value)===undefined}">
|
||||
{{ filterDict(cacheStore.getDict(dictType), value) }}
|
||||
</el-tag>
|
||||
@@ -31,7 +31,7 @@ const props = defineProps({
|
||||
const tagConfig = ref({})
|
||||
|
||||
const filterDict = (data, value) => {
|
||||
if (!data) return
|
||||
if (!data || value == null) return
|
||||
if (data instanceof Array) {
|
||||
if (value == true || value == false) {
|
||||
tagConfig.value = data.find(item => item.value == value.toString())
|
||||
@@ -45,7 +45,7 @@ const filterDict = (data, value) => {
|
||||
tagConfig.value = data.find(item => item.value == value)
|
||||
}
|
||||
}
|
||||
return tagConfig.value.label
|
||||
return tagConfig.value?.label || '未知'
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
120
src/components/TagAndFileUpload.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<baseTitle title="标签名称"></baseTitle>
|
||||
<el-form :model="formData" ref="tagForm" label-width="auto" :rules="rules">
|
||||
<el-form-item label="标签名称" prop="tagName">
|
||||
<el-input v-model="formData.tagName" placeholder="请输入标签名称" style="width: 300px" v-if="showInput"/>
|
||||
<el-select v-model="formData.tagName" placeholder="请选择标签" clearable filterable style="width: 300px" v-else>
|
||||
<el-option
|
||||
v-for="item in tagsOption"
|
||||
:key="item.label"
|
||||
:label="item.value"
|
||||
:value="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<baseTitle title="其他文件"></baseTitle>
|
||||
<el-card style="width: 100%;margin: 15px 0">
|
||||
<file-upload @getFile="getFiles"/>
|
||||
<fvTable style="width: 100%;max-height: 162px;height: 162px" height="162" v-if="showTable" :tableConfig="tableConfig"
|
||||
:data="fileList" :isSettingCol="false" :pagination="false">
|
||||
<template #empty>
|
||||
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
|
||||
</template>
|
||||
</fvTable>
|
||||
</el-card>
|
||||
<div class="oper-page-btn">
|
||||
<el-button color="#DED0B2" @click="handleSubmit(tagForm)">提交</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
const props = defineProps({
|
||||
tagsOption: {
|
||||
type: Array,
|
||||
default: []
|
||||
}, formData: {
|
||||
type: Array,
|
||||
default: []
|
||||
}, showInput: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
})
|
||||
const rules = reactive({
|
||||
tagName: [{required: true, message: '请输入标签名称', trigger: ['blur', 'change']}],
|
||||
})
|
||||
const tagForm = ref()
|
||||
const showTable = ref(true)
|
||||
const emits = defineEmits(['getFile'])
|
||||
const fileList = ref([])
|
||||
const tableConfig = reactive({
|
||||
columns: [
|
||||
{
|
||||
prop: 'index',
|
||||
type: 'index',
|
||||
label: '序号',
|
||||
align: 'center',
|
||||
width: '80',
|
||||
},
|
||||
{
|
||||
prop: 'originalFileName',
|
||||
label: '附件名称',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
prop: 'tag',
|
||||
label: '标签',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'tag',
|
||||
label: '文件大小',
|
||||
align: 'center',
|
||||
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
|
||||
},
|
||||
{
|
||||
prop: 'oper',
|
||||
label: '操作',
|
||||
align: 'center',
|
||||
currentRender: ({row, index}) => {
|
||||
return (
|
||||
<div>
|
||||
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const compositeParam = (item) => {
|
||||
return {
|
||||
fileId: item.id,
|
||||
size: item.size,
|
||||
originalFileName: item.originalFilename,
|
||||
fileType: item.fileType,
|
||||
url: item.url,
|
||||
newFile: true,
|
||||
tag: formData.value.tagName,
|
||||
}
|
||||
}
|
||||
const getFiles = (val) => {
|
||||
showTable.value = false
|
||||
let fileObj = compositeParam(val)
|
||||
// emit("getFile", fileObj)
|
||||
fileList.value.push(fileObj)
|
||||
nextTick(() => {
|
||||
showTable.value = true
|
||||
})
|
||||
}
|
||||
watch(() => fileList.value, (val) => {
|
||||
fileList.value = val
|
||||
})
|
||||
defineExpose({
|
||||
fileList
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -74,7 +74,7 @@ const props = defineProps({
|
||||
},
|
||||
height:{
|
||||
type: Number,
|
||||
default: 450
|
||||
default: 500
|
||||
}
|
||||
})
|
||||
const content = ref(props.value);
|
||||
|
||||
52
src/components/Tooltip.vue
Normal file
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="props.content"
|
||||
placement="bottom-start"
|
||||
:disabled="isShow"
|
||||
>
|
||||
<div :class="lines?'content-lines':'content'" :style="{width: props.width}" @mouseover="isShowTooltip">
|
||||
<span ref="contentRef">
|
||||
<slot name="content">{{ props.content }}</slot>
|
||||
</span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
content: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%'
|
||||
},
|
||||
lines: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
const contentRef = ref()
|
||||
const isShow = ref(false)
|
||||
const isShowTooltip = () => {
|
||||
isShow.value = props.width > contentRef.value.offsetWidth;
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.content {
|
||||
width: 45px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.content-lines{
|
||||
word-break:break-all;
|
||||
overflow:hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 2;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
49
src/components/organizationalStructure/CompanyDetail.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<baseTitle title="公司详情"></baseTitle>
|
||||
<fv-Form :schema="schema" @getInstance="(e)=>form = e"></fv-Form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {getCompanyDetail} from "@/api/subsidiary";
|
||||
const props=defineProps({
|
||||
value:{
|
||||
type:String,
|
||||
default:''
|
||||
}
|
||||
})
|
||||
const form = ref()
|
||||
const schema = reactive([
|
||||
{
|
||||
label: '公司名称:',
|
||||
prop: 'companyName',
|
||||
},
|
||||
{
|
||||
label: '公司编码:',
|
||||
prop: 'companyCode'
|
||||
},
|
||||
{
|
||||
label: '创建时间:',
|
||||
prop: 'createTime'
|
||||
}
|
||||
])
|
||||
const emit = defineEmits(['update:value'])
|
||||
const _value = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(value) {
|
||||
emit('update:value', value)
|
||||
}
|
||||
})
|
||||
|
||||
const getInfo = async () => {
|
||||
const { data } = await getCompanyDetail(_value.value)
|
||||
form.value.setValues(data)
|
||||
}
|
||||
|
||||
getInfo()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
172
src/components/organizationalStructure/Department.vue
Normal file
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<baseTitle title="公司详情"></baseTitle>
|
||||
<fv-Form :schema="companySchema" @getInstance="(e)=>companyForm = e"></fv-Form>
|
||||
<baseTitle title="部门详情"></baseTitle>
|
||||
<fv-Form :schema="schema" @getInstance="(e)=>form = e"></fv-Form>
|
||||
<UserPicker ref="usrPickershipIds" @ok="editshipIds"></UserPicker>
|
||||
<UserPicker ref="usrPickerHeadIds" @ok="editheadIds"></UserPicker>
|
||||
<UserPicker ref="departmentalDeputyIds" @ok="editdeputyIds"></UserPicker>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import UserPicker from '@/views/workflow/process/common/UserPicker.vue';
|
||||
import Ttsup from '@/views/system/department/components/ToolToShowUserPicker.vue'
|
||||
import {getInfoById,setDeptInfo} from '@/views/system/department/api'
|
||||
const props=defineProps({
|
||||
value:{
|
||||
type:String,
|
||||
default:''
|
||||
}
|
||||
})
|
||||
const form = ref()
|
||||
const companyForm = ref()
|
||||
const usrPickershipIds = ref()
|
||||
const usrPickerHeadIds = ref()
|
||||
const usrPickerDeputyIds = ref()
|
||||
const departmentChargeLeadershipNames = ref()
|
||||
const departmentHeadNames = ref()
|
||||
const departmentalDeputyNames = ref()
|
||||
const departmentChargeLeadershipIds = ref()
|
||||
const departmentHeadIds = ref()
|
||||
const departmentalDeputyIds = ref()
|
||||
const companySchema = reactive([
|
||||
{
|
||||
label: '公司名称:',
|
||||
prop: 'companyName',
|
||||
},
|
||||
{
|
||||
label: '公司编码:',
|
||||
prop: 'companyCode'
|
||||
},
|
||||
{
|
||||
label: '创建时间:',
|
||||
prop: 'createTime'
|
||||
}
|
||||
])
|
||||
const schema = reactive([
|
||||
{
|
||||
label: '部门名字:',
|
||||
prop: 'departmentName',
|
||||
},
|
||||
{
|
||||
label: '部门标志:',
|
||||
prop: 'departmentMark'
|
||||
},
|
||||
{
|
||||
label: '部门分管领导:',
|
||||
prop: 'departmentChargeLeadershipIds',
|
||||
component: ()=><Ttsup modelValue={departmentChargeLeadershipNames.value} onClick={()=>{usrPickershipIds.value.showUserPicker()} } />
|
||||
},
|
||||
{
|
||||
label: '部门负责人:',
|
||||
prop: 'departmentHeadIds',
|
||||
component: ()=><Ttsup modelValue={departmentHeadNames.value} onClick={()=>{usrPickerHeadIds.value.showUserPicker()} } />
|
||||
},
|
||||
{
|
||||
label: '部门副职用户:',
|
||||
prop: 'departmentalDeputyIds',
|
||||
component: ()=><Ttsup modelValue={departmentalDeputyNames.value} onClick={()=>{departmentalDeputyIds.value.showUserPicker()} } />
|
||||
},
|
||||
{
|
||||
label: '创建时间:',
|
||||
prop: 'createTime'
|
||||
}
|
||||
])
|
||||
const emit = defineEmits(['update:value'])
|
||||
const _value = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(value) {
|
||||
emit('update:value', value)
|
||||
}
|
||||
})
|
||||
|
||||
const getInfo = async () => {
|
||||
const { data } = await getInfoById(_value.value)
|
||||
companyForm.value.setValues(data.company)
|
||||
const params = {
|
||||
createTime: data.createTime,
|
||||
departmentMark: data.departmentMark,
|
||||
departmentName: data.departmentName
|
||||
}
|
||||
departmentChargeLeadershipIds.value = data.departmentChargeLeadershipIds
|
||||
departmentHeadIds.value = data.departmentHeadIds
|
||||
departmentalDeputyIds.value = data.departmentalDeputyIds
|
||||
params.departmentChargeLeadershipIds = formatIdsToNames(data.departmentChargeLeadershipIds, data.departmentChargeLeadershipInfo, 'userId', 'nickName')
|
||||
departmentChargeLeadershipNames.value = params.departmentChargeLeadershipIds
|
||||
params.departmentHeadIds = formatIdsToNames(data.departmentHeadIds, data.departmentHeadInfo, 'userId', 'nickName')
|
||||
departmentHeadNames.value = params.departmentHeadIds
|
||||
params.departmentalDeputyIds = formatIdsToNames(data.departmentalDeputyIds, data.departmentalDeputyInfo, 'userId', 'nickName')
|
||||
departmentalDeputyNames.value = params.departmentalDeputyIds
|
||||
form.value.setValues(params)
|
||||
|
||||
}
|
||||
|
||||
getInfo()
|
||||
|
||||
const formatIdsToNames = (ids, infoList, key, viewKey) => {
|
||||
const resArr = []
|
||||
if(!ids?.length) return
|
||||
ids.forEach(item=>{
|
||||
infoList.forEach(v=>{
|
||||
item == v[key] && resArr.push(v[viewKey])
|
||||
})
|
||||
})
|
||||
return resArr.join(',')
|
||||
}
|
||||
|
||||
const editshipIds = (list) => {
|
||||
// console.log("🚀 ~ editshipIds ~ list:", list)
|
||||
const arr = list.map(item=>item.name)
|
||||
departmentChargeLeadershipIds.value = list.map(item=>item.id)
|
||||
departmentChargeLeadershipNames.value = arr.join(',')
|
||||
setDeptmentInfo({
|
||||
departmentChargeLeadershipIds: departmentChargeLeadershipIds.value,
|
||||
departmentalDeputyIds: departmentalDeputyIds.value,
|
||||
departmentHeadIds: departmentHeadIds.value
|
||||
})
|
||||
}
|
||||
|
||||
const editheadIds = (list) => {
|
||||
// console.log("🚀 ~ editshipIds ~ list:", list)
|
||||
const arr = list.map(item=>item.name)
|
||||
departmentHeadIds.value = list.map(item=>item.id)
|
||||
departmentHeadNames.value = arr.join(',')
|
||||
setDeptmentInfo({
|
||||
departmentChargeLeadershipIds: departmentChargeLeadershipIds.value,
|
||||
departmentalDeputyIds: departmentalDeputyIds.value,
|
||||
departmentHeadIds: departmentHeadIds.value
|
||||
})
|
||||
}
|
||||
|
||||
const editdeputyIds = (list) => {
|
||||
// console.log("🚀 ~ editshipIds ~ list:", list)
|
||||
const arr = list.map(item=>item.name)
|
||||
departmentalDeputyIds.value = list.map(item=>item.id)
|
||||
departmentalDeputyNames.value = arr.join(',')
|
||||
setDeptmentInfo({
|
||||
departmentChargeLeadershipIds: departmentChargeLeadershipIds.value,
|
||||
departmentalDeputyIds: departmentalDeputyIds.value,
|
||||
departmentHeadIds: departmentHeadIds.value
|
||||
})
|
||||
}
|
||||
|
||||
const setDeptmentInfo = async ({ departmentChargeLeadershipIds = [], departmentHeadIds = [], departmentalDeputyIds = []}) => {
|
||||
|
||||
const params = {
|
||||
departmentChargeLeadershipIds,
|
||||
departmentHeadIds,
|
||||
departmentalDeputyIds,
|
||||
departmentId: _value.value
|
||||
}
|
||||
const res = await setDeptInfo(params)
|
||||
// console.log(res.data);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
15
src/components/steps/api/index.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export const getBaseInfoApi = (projectId) => {
|
||||
return request({
|
||||
url: '/workflow/details/info/'+projectId,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
export const getMapProjectStateInfo = (projectId, state) => {
|
||||
return request({
|
||||
url: `/workflow/details/${projectId}/${state}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
362
src/components/steps/index.vue
Normal file
@@ -0,0 +1,362 @@
|
||||
<template>
|
||||
<baseTitle title="基础信息"></baseTitle>
|
||||
<fvForm :schema="schema" @getInstance="(e)=>baseForm = e"></fvForm>
|
||||
<div class="steps-box">
|
||||
<el-steps v-if="stepsShow" :active="localActive" finish-status="success">
|
||||
<el-step
|
||||
v-for="(item, index) in localSteps"
|
||||
:key="item.key"
|
||||
:title="item.title"
|
||||
:class="stepClass(index)"
|
||||
@click="handleStep(item.key, index)"
|
||||
|
||||
>
|
||||
<template #icon>
|
||||
<el-icon style="font-size: 20px;" :class="index == localActive ? 'is-active' : 'is-end'"
|
||||
v-if="localStepSuccess.includes(index)">
|
||||
<SuccessFilled/>
|
||||
</el-icon>
|
||||
<el-icon style="font-size: 20px; color: gray;" v-else>
|
||||
<WarningFilled/>
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-step>
|
||||
</el-steps>
|
||||
</div>
|
||||
<!-- 步骤内容 -->
|
||||
<div>
|
||||
<slot name="content" :localActive="localActive"></slot>
|
||||
<!-- <template v-for="(item, index) in stepList" :key="item.key">
|
||||
<component v-if="localActive == index" v-bind="item.props || {}" :is="item.component" />
|
||||
</template> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import {ElLoading, ElNotification} from 'element-plus';
|
||||
import {computed, onMounted, reactive, ref, watchEffect} from 'vue';
|
||||
import {useRoute} from 'vue-router';
|
||||
import {getBaseInfoApi} from './api';
|
||||
|
||||
const props = defineProps({
|
||||
// 步骤对应内容list
|
||||
stepList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
// 当前显示步骤
|
||||
active: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 已完成的工作流步骤
|
||||
stepSuccess: {
|
||||
type: Array,
|
||||
default: ['00']
|
||||
},
|
||||
//直接上报/需求征集
|
||||
reportType: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const emits = defineEmits(['stepChange', 'setDetail'])
|
||||
|
||||
const localData = reactive({})
|
||||
|
||||
const localActive = ref(0) // 当前激活步骤
|
||||
|
||||
const stepsShow = ref(false)
|
||||
|
||||
const localSteps = ref([
|
||||
{
|
||||
title: '需求征集',
|
||||
key: 'collect',
|
||||
},
|
||||
{
|
||||
title: '需求上报',
|
||||
key: 'report',
|
||||
},
|
||||
{
|
||||
title: '项目立项',
|
||||
key: 'approve',
|
||||
},
|
||||
{
|
||||
title: '项目验收',
|
||||
key: 'execute',
|
||||
},
|
||||
{
|
||||
title: '项目归档',
|
||||
key: 'archivist',
|
||||
},
|
||||
// {
|
||||
// title: '项目结项',
|
||||
// key: 'end',
|
||||
// },
|
||||
])
|
||||
|
||||
const baseForm = ref()
|
||||
|
||||
const schema = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: '项目名称',
|
||||
prop: 'projectName',
|
||||
colProps: {
|
||||
span: 8
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '征集公司',
|
||||
prop: 'affiliatedCompany',
|
||||
colProps: {
|
||||
span: 8
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '征集名称',
|
||||
prop: 'requirementName',
|
||||
colProps: {
|
||||
span: 8
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '征集描述',
|
||||
prop: 'collectExplain',
|
||||
colProps: {
|
||||
span: 24
|
||||
}
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
const localStepSuccess = ref([])
|
||||
|
||||
// 格式化详情步骤条
|
||||
const formatProcedure = (data) => {
|
||||
let arr = []
|
||||
if (data instanceof Array) {
|
||||
data.forEach(item => {
|
||||
if (props.reportType === 'direct') {
|
||||
switch (item) {
|
||||
case '10':
|
||||
arr.push(0)
|
||||
break
|
||||
case '20':
|
||||
arr.push(1)
|
||||
break
|
||||
case '40':
|
||||
arr.push(2)
|
||||
break
|
||||
case '50':
|
||||
arr.push(3)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
switch (item) {
|
||||
case '00':
|
||||
arr.push(0)
|
||||
break
|
||||
case '10':
|
||||
arr.push(1)
|
||||
break
|
||||
case '20':
|
||||
arr.push(2)
|
||||
break
|
||||
case '40':
|
||||
arr.push(3)
|
||||
break
|
||||
case '50':
|
||||
arr.push(4)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// 反向格式化
|
||||
const formatReProcedure = (data) => {
|
||||
let arr = []
|
||||
if (data instanceof Array) {
|
||||
data.forEach(item => {
|
||||
switch (item) {
|
||||
case 0:
|
||||
arr.push('00')
|
||||
break
|
||||
case 1:
|
||||
arr.push('10')
|
||||
break
|
||||
case 2:
|
||||
arr.push('20')
|
||||
break
|
||||
// case 3: arr.push('30')
|
||||
// break
|
||||
case 3:
|
||||
arr.push('40')
|
||||
break
|
||||
case 4:
|
||||
arr.push('50')
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const formatActive = (val) => {
|
||||
let newVal
|
||||
if (props.reportType === 'direct') {
|
||||
newVal = val + 1
|
||||
} else {
|
||||
newVal = val
|
||||
}
|
||||
let active = ''
|
||||
newVal == 0 && (active = '00')
|
||||
newVal == 1 && (active = '10')
|
||||
newVal == 2 && (active = '20')
|
||||
// val == 3 && (active = '30')
|
||||
newVal == 3 && (active = '40')
|
||||
newVal == 4 && (active = '50')
|
||||
return active
|
||||
}
|
||||
|
||||
const stepClass = (val) => {
|
||||
if (localStepSuccess.value.includes(val)) {
|
||||
return 'step-success'
|
||||
}
|
||||
return 'step-error'
|
||||
}
|
||||
|
||||
const handleStep = (key, index) => {
|
||||
if (localStepSuccess.value.includes(index)) {
|
||||
let active = ''
|
||||
localActive.value = index
|
||||
if (props.reportType === 'direct') {
|
||||
switch (index) {
|
||||
case 0:
|
||||
active = '10'
|
||||
break
|
||||
case 1:
|
||||
active = '20'
|
||||
break
|
||||
case 2:
|
||||
active = '40'
|
||||
break
|
||||
case 3:
|
||||
active = '50'
|
||||
break
|
||||
}
|
||||
} else {
|
||||
switch (index) {
|
||||
case 0:
|
||||
active = '00'
|
||||
break
|
||||
case 1:
|
||||
active = '10'
|
||||
break
|
||||
case 2:
|
||||
active = '20'
|
||||
break
|
||||
case 3:
|
||||
active = '40'
|
||||
break
|
||||
case 4:
|
||||
active = '50'
|
||||
break
|
||||
}
|
||||
}
|
||||
emits('stepChange', {key, active})
|
||||
return
|
||||
}
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: '不能查看未完成的工作流信息',
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
|
||||
const getBaseInfo = async () => {
|
||||
const loading = ElLoading.service({fullscreen: true})
|
||||
stepsShow.value = false
|
||||
try {
|
||||
const {code, data} = await getBaseInfoApi(route.query.projectId)
|
||||
// console.log('data.procedure', data.procedure, route.query.step)
|
||||
if (route.query.step === '40') {
|
||||
if (data.procedure.indexOf('40') == -1) {
|
||||
data.procedure.push('40')
|
||||
}
|
||||
} else if (route.query.step === '50') {
|
||||
if (data.procedure.indexOf('50') == -1) {
|
||||
data.procedure.push('50')
|
||||
}
|
||||
}
|
||||
localStepSuccess.value = formatProcedure(data.procedure)
|
||||
baseForm.value.setValues(data)
|
||||
emits('setDetail', formatActive(localActive.value))
|
||||
loading.close()
|
||||
nextTick(() => {
|
||||
stepsShow.value = true
|
||||
})
|
||||
} catch {
|
||||
loading.close()
|
||||
nextTick(() => {
|
||||
stepsShow.value = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
getBaseInfo()
|
||||
|
||||
// onActivated(() => {
|
||||
// getBaseInfo()
|
||||
// })
|
||||
watchEffect(() => {
|
||||
localActive.value = props.active
|
||||
})
|
||||
watchEffect(() => {
|
||||
if (props.reportType === 'direct') {
|
||||
let steps = []
|
||||
for (const step of localSteps.value) {
|
||||
if (step.key !== 'collect'){
|
||||
steps.push(step)
|
||||
}
|
||||
}
|
||||
localSteps.value = steps
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.steps-box {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.step-success {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.step-error {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.is-active {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.is-end {
|
||||
color: #BEA266;
|
||||
}
|
||||
|
||||
:deep(.el-step__title.is-success) {
|
||||
color: #A8abb2;
|
||||
}
|
||||
|
||||
:deep(.el-step__head.is-success) {
|
||||
border-color: #A8abb2;
|
||||
}
|
||||
</style>
|
||||
@@ -8,7 +8,7 @@ export const hasPerm = (el, binding, vnode) => {
|
||||
if (value && value instanceof Array && value.length > 0) {
|
||||
const permissiosFlag = value
|
||||
const hasPermission = permisstions.some(permission => {
|
||||
return permissiosFlag[0] === allPermission || permissiosFlag[0] === permission
|
||||
return permission === allPermission || permissiosFlag.includes(permission) || permissiosFlag.includes(allPermission)
|
||||
})
|
||||
if (!hasPermission) {
|
||||
el.parentNode && el.parentNode.removeChild(el)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
v-bind="item.props || {}"
|
||||
v-on="item.on || {}"
|
||||
v-model="form[item.prop]"
|
||||
@keyup.enter.native="getValues"
|
||||
>
|
||||
</component>
|
||||
</template>
|
||||
@@ -66,15 +67,15 @@ const filterConfig = computed(() => {
|
||||
})
|
||||
|
||||
// 搜索功能表单元素默认值
|
||||
const setDefaultFormValues = () => {
|
||||
filterConfig.value.forEach(item => {
|
||||
form.value[item.prop] = item.props?.defaultValue || null
|
||||
})
|
||||
}
|
||||
// const setDefaultFormValues = () => {
|
||||
// filterConfig.value.forEach(item => {
|
||||
// form.value[item.prop] = item.props?.defaultValue || null
|
||||
// })
|
||||
// }
|
||||
|
||||
watchEffect(() => {
|
||||
if (filterConfig.value.length) {
|
||||
setDefaultFormValues()
|
||||
// setDefaultFormValues()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -86,7 +87,7 @@ const getValues = () => {
|
||||
//重置
|
||||
const handleReset = () => {
|
||||
form.value = {}
|
||||
setDefaultFormValues()
|
||||
// setDefaultFormValues()
|
||||
emits('search', form.value)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,17 +7,24 @@
|
||||
v-for="btn in tableConfig.btns"
|
||||
:key="btn.key"
|
||||
:type="btn.type || ''"
|
||||
:color="btn.color || ''"
|
||||
v-perm="btn.auth || ['*:*:*']"
|
||||
@click="handleClickBtns(btn.key)"
|
||||
>
|
||||
{{ btn.name }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 列显示配置 -->
|
||||
<div v-if="isSettingCol">
|
||||
<div v-if="isSettingCol" style="float: right">
|
||||
<el-button v-if="tableConfig.export && tableConfig.export.open" @click="exportTable" color="#DED0B2"
|
||||
style="margin-bottom: 10px">导出
|
||||
</el-button>
|
||||
<el-tooltip effect="dark" content="列配置" placement="bottom">
|
||||
<el-button ref="buttonRef" link>
|
||||
<el-icon size="18"><Setting /></el-icon>
|
||||
<el-icon size="18">
|
||||
<Setting/>
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-popover
|
||||
@@ -28,7 +35,8 @@
|
||||
virtual-triggering
|
||||
trigger="click">
|
||||
<div class="col-setting-checkall">
|
||||
<el-checkbox label="列展示" v-model="localData.allColShow" :indeterminate="localData.indeterminate" @change="changeIsShowAll"></el-checkbox>
|
||||
<el-checkbox label="列展示" v-model="localData.allColShow" :indeterminate="localData.indeterminate"
|
||||
@change="changeIsShowAll"></el-checkbox>
|
||||
</div>
|
||||
<div class="col-setting-list">
|
||||
<el-checkbox-group v-model="localData.checkGroup" @change="changeColShow">
|
||||
@@ -44,7 +52,6 @@
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 表格部分 -->
|
||||
<div class="fv-table">
|
||||
<el-table
|
||||
@@ -95,8 +102,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { requestList } from '../../api/common';
|
||||
import {ElNotification} from 'element-plus';
|
||||
import {requestList} from '../../api/common';
|
||||
import {exportExcel} from "@/utils/export-excel";
|
||||
|
||||
const props = defineProps({
|
||||
//表格配置
|
||||
@@ -125,6 +133,20 @@ const tableInstance = ref()
|
||||
const buttonRef = ref()
|
||||
const popoverRef = ref()
|
||||
|
||||
|
||||
const exportTable = () => {
|
||||
const $e = tableInstance.value.$el
|
||||
let $table = $e.querySelector('.el-table__fixed')
|
||||
if (!$table) {
|
||||
$table = $e
|
||||
}
|
||||
let fileName = ""
|
||||
if (props.tableConfig.export && props.tableConfig.export) {
|
||||
fileName = props.tableConfig.export.fileName
|
||||
}
|
||||
exportExcel($table, Object.keys(localData.list[0]), fileName)
|
||||
}
|
||||
|
||||
const localData = reactive({
|
||||
list: [], // 表格数据
|
||||
query: {
|
||||
@@ -140,15 +162,15 @@ const localData = reactive({
|
||||
checkGroup: []
|
||||
})
|
||||
|
||||
const emits = defineEmits(['headBtnClick', 'selectionChange', 'rowClick', 'rowDblclick', 'getBaseQuery', 'cellClick'])
|
||||
const emits = defineEmits(['headBtnClick', 'selectionChange', 'rowClick', 'rowDblclick', 'getBaseQuery', 'cellClick', 'getTotal'])
|
||||
|
||||
const handleClickBtns = (key) => {
|
||||
emits('headBtnClick', key)
|
||||
}
|
||||
|
||||
const filterColumns = () => {
|
||||
localData.columns = props.tableConfig.columns.map(item=>{
|
||||
if(item.prop) {
|
||||
localData.columns = props.tableConfig.columns.map(item => {
|
||||
if (item.prop) {
|
||||
return {
|
||||
...item
|
||||
}
|
||||
@@ -157,10 +179,10 @@ const filterColumns = () => {
|
||||
}
|
||||
|
||||
const changeIsShowAll = (val) => {
|
||||
if(val) {
|
||||
if (val) {
|
||||
filterColumns()
|
||||
localData.indeterminate = false
|
||||
localData.checkGroup = props.tableConfig.columns.map(item=>item.prop)
|
||||
localData.checkGroup = props.tableConfig.columns.map(item => item.prop)
|
||||
} else {
|
||||
localData.columns.length = 0
|
||||
localData.checkGroup.length = 0
|
||||
@@ -169,10 +191,10 @@ const changeIsShowAll = (val) => {
|
||||
}
|
||||
|
||||
const changeColShow = (val) => {
|
||||
if(val.length == props.tableConfig.columns.length) {
|
||||
if (val.length == props.tableConfig.columns.length) {
|
||||
localData.indeterminate = false
|
||||
localData.allColShow = true
|
||||
} else if(val.length !== props.tableConfig.columns.length && val.length != 0) {
|
||||
} else if (val.length !== props.tableConfig.columns.length && val.length != 0) {
|
||||
localData.allColShow = false
|
||||
localData.indeterminate = true
|
||||
} else {
|
||||
@@ -180,9 +202,9 @@ const changeColShow = (val) => {
|
||||
localData.allColShow = false
|
||||
}
|
||||
const template = []
|
||||
props.tableConfig.columns.forEach(item=>{
|
||||
val.forEach(v=>{
|
||||
if(item.prop == v) {
|
||||
props.tableConfig.columns.forEach(item => {
|
||||
val.forEach(v => {
|
||||
if (item.prop == v) {
|
||||
template.push(item)
|
||||
}
|
||||
})
|
||||
@@ -193,22 +215,43 @@ const changeColShow = (val) => {
|
||||
filterColumns()
|
||||
|
||||
const getList = async () => {
|
||||
const { api, params } = props.tableConfig
|
||||
const {api, params} = props.tableConfig
|
||||
const queryParmas = {...localData.query, ...params}
|
||||
if(api) {
|
||||
if (api) {
|
||||
localData.loading = true
|
||||
try {
|
||||
const { code, data, msg } = await requestList(api, queryParmas)
|
||||
if ( code === 1000 ) {
|
||||
const {code, data, msg} = await requestList(api, queryParmas).then(res=>{
|
||||
// console.log(res)
|
||||
return res
|
||||
})
|
||||
// console.log(code,data,msg)
|
||||
if (code === 1000) {
|
||||
if (data.rows) {
|
||||
localData.list = data.rows
|
||||
} else {
|
||||
localData.list = data
|
||||
}
|
||||
localData.total = data.total
|
||||
emits('getTotal', localData.total)
|
||||
localData.loading = false
|
||||
} else {
|
||||
ElMessage.error(msg)
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: msg,
|
||||
type: 'error'
|
||||
})
|
||||
localData.loading = false
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('请求数据失败')
|
||||
console.log("error",error)
|
||||
if (!error){
|
||||
return
|
||||
}
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: '请求数据失败',
|
||||
type: 'error'
|
||||
})
|
||||
localData.loading = false
|
||||
}
|
||||
} else {
|
||||
@@ -245,13 +288,13 @@ const handleCurrentChange = (val) => {
|
||||
getList()
|
||||
}
|
||||
|
||||
watchEffect(()=>{
|
||||
if(localData.allColShow) {
|
||||
localData.checkGroup = props.tableConfig.columns.map(item=>item.prop)
|
||||
watchEffect(() => {
|
||||
if (localData.allColShow) {
|
||||
localData.checkGroup = props.tableConfig.columns.map(item => item.prop)
|
||||
}
|
||||
})
|
||||
//刷新
|
||||
const refresh = ({resetPage=false}={}) => {
|
||||
const refresh = ({resetPage = false} = {}) => {
|
||||
resetPage ? localData.query.pageNum = 1 : null
|
||||
getList()
|
||||
}
|
||||
@@ -264,30 +307,40 @@ const getQuery = () => {
|
||||
return localData.query
|
||||
}
|
||||
|
||||
defineExpose({ refresh, updateLoading, getQuery, tableInstance })
|
||||
defineExpose({refresh, updateLoading, getQuery, tableInstance})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.col-setting-checkall {
|
||||
border-bottom: 1px solid rgb(210, 210, 213);
|
||||
}
|
||||
|
||||
.col-setting-list {
|
||||
max-height: 45vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.table-head-btn {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.fv-table-btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.fv-table {
|
||||
:deep(.el-tooltip) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition name="fade-transform" type="transition" appear mode="out-in">
|
||||
<div>
|
||||
<template v-if="!route.meta.noCache">
|
||||
<template v-if="route.meta.noCache">
|
||||
<keep-alive>
|
||||
<suspense>
|
||||
<component :is="Component" :key="route.fullPath" />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<el-breadcrumb separator="/">
|
||||
<el-breadcrumb-item v-for="(item, index) in breadcrumbList" :key="item.path">
|
||||
<span v-if="item.meta.noRedirect || index === breadcrumbList.length-1" class="no-redirect">
|
||||
<span v-if="item.meta.noRedirect || index === breadcrumbList.length-1" class="no-redirect font">
|
||||
{{ item.meta.title }}
|
||||
</span>
|
||||
<router-link v-else :to="item.redirect || item.path">
|
||||
<router-link class="font" v-else :to="item.redirect || item.path">
|
||||
{{ item.meta.title }}
|
||||
</router-link>
|
||||
</el-breadcrumb-item>
|
||||
@@ -12,13 +12,13 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import {useRoute, useRouter} from 'vue-router';
|
||||
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
watch(route, ()=> {
|
||||
watch(route, () => {
|
||||
getBreadcrumb()
|
||||
})
|
||||
|
||||
@@ -29,7 +29,7 @@ const breadcrumbList = ref([])
|
||||
const getBreadcrumb = () => {
|
||||
let matched = route.matched.filter(item => item.meta && item.meta.title)
|
||||
const first = matched[0]
|
||||
if(!isDashboard(first)) {
|
||||
if (!isDashboard(first)) {
|
||||
matched = [{path: '/home', meta: {title: '首页'}}].concat(matched)
|
||||
}
|
||||
breadcrumbList.value.length = 0;
|
||||
@@ -39,7 +39,7 @@ const getBreadcrumb = () => {
|
||||
|
||||
const isDashboard = (meta) => {
|
||||
const name = meta && meta.name
|
||||
if(!name) {
|
||||
if (!name) {
|
||||
return
|
||||
}
|
||||
return name.trim().toLocaleLowerCase() === 'Home'.toLocaleLowerCase()
|
||||
@@ -47,3 +47,9 @@ const isDashboard = (meta) => {
|
||||
|
||||
getBreadcrumb()
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.font {
|
||||
// font-size: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<div class="toggle" @click="toggleClick">
|
||||
<component :is="siderbarStore.getSiderBarStatus() ? 'Fold' : 'Expand'" class="icon"></component>
|
||||
</div>
|
||||
<span class="sys-name">科技创新项目管理平台</span>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -13,8 +14,14 @@ const toggleClick = () => {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sys-name {
|
||||
padding: 0 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.toggle{
|
||||
line-height: 65px;
|
||||
border-top-left-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
padding: 0 15px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
|
||||
@@ -3,16 +3,55 @@
|
||||
<Hamburger></Hamburger>
|
||||
<Breadcrumb></Breadcrumb>
|
||||
<div class="right-bar">
|
||||
<bell-socket/>
|
||||
<!-- <bell-socket/>-->
|
||||
<div class="user-box">
|
||||
<div>
|
||||
<!-- <img :src="userInfo.avatar" alt="" @click.stop="handleVisitedP">-->
|
||||
<span @click.stop="handleVisitedP">欢迎回来,{{userInfo.userName}}</span>
|
||||
<div @click.stop="handleVisitedP">
|
||||
<el-avatar>{{ userInfo.nickName }}</el-avatar>
|
||||
<div>{{ userInfo.nickName }}
|
||||
<el-icon style="margin-left: 5px">
|
||||
<ArrowDownBold/>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="person" v-if="visitedP">
|
||||
<ul>
|
||||
<li @click="handleToAuth">个人中心</li>
|
||||
<li @click="handleLogout">退出登录</li>
|
||||
<li>主次账号切换</li>
|
||||
<li class="avatar-li" v-for="item in accountList" @click="accountChange(item.userId)">
|
||||
<el-badge :value="item.taskCount" v-if="item.taskCount!==0">
|
||||
<el-avatar>{{ item.nickName }}</el-avatar>
|
||||
</el-badge>
|
||||
<el-avatar v-else>{{ item.nickName }}</el-avatar>
|
||||
<div class="right-li">
|
||||
<div class="name-line">
|
||||
<span v-if="item.accountType==='0'" class="zhu">主</span>
|
||||
<span class="nickName">{{ item.nickName }}</span>
|
||||
<span :title="item.jobActivityDesc">{{ item.jobActivityDesc }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span :title="item.companyName+'/'+item.departmentName">{{ item.companyName }}/{{
|
||||
item.departmentName
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<el-icon color="#3f89dc" size="20" v-if="item.current">
|
||||
<SuccessFilled/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<!-- <li v-for="item in accountList" :label="item.userName" :value="item.userId"/>-->
|
||||
</li>
|
||||
<li @click="handleToAuth">
|
||||
<el-icon color="gray" size="20" style="margin-right: 5px">
|
||||
<UserFilled/>
|
||||
</el-icon>
|
||||
个人中心
|
||||
</li>
|
||||
<li @click="handleLogout">
|
||||
<el-icon color="gray" size="20" style="margin-right: 5px">
|
||||
<SwitchButton/>
|
||||
</el-icon>
|
||||
退出登录
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -25,14 +64,20 @@ import {useRouter} from 'vue-router';
|
||||
import Breadcrumb from './Breadcrumb.vue';
|
||||
import Hamburger from './Hamburger.vue';
|
||||
import {useAuthStore} from '@/stores/userstore.js'
|
||||
import BellSocket from "./BellSocket.vue";
|
||||
import {getUserInfo} from "../../api/login";
|
||||
import {usePermisstionStroe} from '@/stores/permisstion'
|
||||
import {useTagsView} from '@/stores/tagsview';
|
||||
import {getUserAccount} from "@/api/user/user";
|
||||
import {switchAccount} from "@/api/login";
|
||||
import {setToken} from "../../utils/auth";
|
||||
import {ElNotification} from "element-plus";
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const permisstionStore = usePermisstionStroe()
|
||||
const tagsViewStore = useTagsView()
|
||||
const userInfo = ref({})
|
||||
const visitedP = ref(false)
|
||||
const accountList = ref([])
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
onMounted(() => {
|
||||
setUserInfo()
|
||||
@@ -42,15 +87,36 @@ onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', nullBlockClick)
|
||||
})
|
||||
const setUserInfo = () => {
|
||||
getUserInfo().then(res=>{
|
||||
userInfo.value = res.data.user
|
||||
})
|
||||
userInfo.value = authStore.userinfo
|
||||
}
|
||||
const nullBlockClick = () => {
|
||||
visitedP.value = false
|
||||
}
|
||||
const handleVisitedP = () => {
|
||||
getUserAccount().then(res => {
|
||||
if (res.code !== 1000) {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
accountList.value = res.data
|
||||
nextTick(() => {
|
||||
visitedP.value = !visitedP.value
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const accountChange = (userId) => {
|
||||
switchAccount(userId).then(res => {
|
||||
if (res.code === 1000) {
|
||||
visitedP.value = !visitedP.value
|
||||
authStore.userLogout()
|
||||
setToken(res.data)
|
||||
window.location.href = "/home"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleToAuth = () => {
|
||||
@@ -61,11 +127,34 @@ const handleLogout = () => {
|
||||
visitedP.value = !visitedP.value
|
||||
authStore.userLogout()
|
||||
permisstionStore.removeMenu()
|
||||
permisstionStore.setIsSuccessReq()
|
||||
tagsViewStore.removeAllTagView()
|
||||
router.push('/login')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-avatar--circle) {
|
||||
display: inline-block;
|
||||
line-height: 40px;
|
||||
margin-right: 14px;
|
||||
background-color: #8a7243;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
:deep(.el-badge) {
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
:deep(.el-badge__content.is-fixed) {
|
||||
position: absolute;
|
||||
right: 26px;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
height: 65px;
|
||||
padding: 0 15px 0 0;
|
||||
@@ -74,22 +163,27 @@ const handleLogout = () => {
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
|
||||
.right-bar {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
|
||||
.user-box{
|
||||
.user-box {
|
||||
cursor: pointer;
|
||||
margin-left: 10px;
|
||||
position: relative;
|
||||
>div:first-child{
|
||||
display:flex;
|
||||
|
||||
> div:first-child {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
>span{
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
@@ -101,24 +195,85 @@ const handleLogout = () => {
|
||||
|
||||
|
||||
.person {
|
||||
font-size: 14px;
|
||||
color: #666666;
|
||||
position: absolute;
|
||||
width: 80px;
|
||||
width: 280px;
|
||||
right: 0;
|
||||
z-index: 300;
|
||||
bottom: -70px;
|
||||
padding: 10px 5px;
|
||||
top: 54px;
|
||||
padding: 5px 0;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
box-shadow: 2px 2px 2px 1px rgb(171, 167, 167);
|
||||
|
||||
li {
|
||||
.avatar-li {
|
||||
display: flex;
|
||||
height: 60px;
|
||||
|
||||
.right-li {
|
||||
color: #909090;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.name-line {
|
||||
margin-bottom: 5px;
|
||||
width: 184px;
|
||||
-webkit-line-clamp: 1;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
|
||||
.zhu {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
background-color: #fa0;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nickName {
|
||||
color: #4d7ad8;
|
||||
}
|
||||
|
||||
> span {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
> div:last-child {
|
||||
width: 194px;
|
||||
-webkit-line-clamp: 1;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 0 6px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
|
||||
&:hover {
|
||||
color: #79bbff;
|
||||
color: #666666 !important;
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
|
||||
&:first-child:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<!-- 有子菜单 -->
|
||||
<template v-for="item in menuItem" :key="item.path">
|
||||
<el-sub-menu v-if="item?.children?.length>0 && !item.hidden" :index="item.path">
|
||||
<el-sub-menu v-if="checkMenuItem(item)" :index="item.path">
|
||||
<template #title>
|
||||
<svg-icon :name="item.icon"/>
|
||||
<span>{{ item.title }}</span>
|
||||
@@ -17,7 +17,9 @@
|
||||
</a>
|
||||
</div>
|
||||
<div v-else>
|
||||
<svg-icon :name="item.icon"/>
|
||||
<el-icon>
|
||||
<svg-icon :name="item.icon" class="menu-item-icon"/>
|
||||
</el-icon>
|
||||
<span>{{ item.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -44,5 +46,26 @@ const handleGo = (path) => {
|
||||
}
|
||||
}
|
||||
|
||||
const checkMenuItem = (item) => {
|
||||
let children = item.children
|
||||
let childState = false;
|
||||
if (children){
|
||||
for (let child of children) {
|
||||
if (!child.hidden) {
|
||||
childState = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return item?.children?.length>0 && !item.hidden && childState
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<!-- <style lang="scss" scoped>
|
||||
.menu-item-icon {
|
||||
width: 18px !important;
|
||||
height: 18px !important;
|
||||
margin-left: 0;
|
||||
}
|
||||
</style> -->
|
||||
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div class="logo" ref="logo">
|
||||
<span v-if="!siderbarStore.isCollapse">科研管理平台</span>
|
||||
<img src="../../assets/kylogo.png" alt="">
|
||||
<!-- <span v-if="!siderbarStore.isCollapse">科研管理平台</span> -->
|
||||
<span v-if="!siderbarStore.isCollapse"></span>
|
||||
</div>
|
||||
<el-scrollbar :height="`calc(100vh - ${logoHeight}px)`" style="background-color: #ffffff">
|
||||
<el-menu
|
||||
|
||||
@@ -25,6 +25,36 @@ const router = createRouter({
|
||||
name: 'casLogin',
|
||||
component: () => import('@/views/cas-login/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/projectdetail/mobile',
|
||||
name: 'projectDetailMobile',
|
||||
component: () => import('@/views/project-management/mobledetail/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/fund/mobile',
|
||||
name: 'specialFundDetailMobile',
|
||||
component: () => import('@/views/project-management/mobledetail/SpecialFundDetailMobile.vue')
|
||||
},
|
||||
{
|
||||
path: '/share/mobile',
|
||||
name: 'shareDetailMobile',
|
||||
component: () => import('@/views/project-management/mobledetail/ShareDetailMobile.vue')
|
||||
},
|
||||
{
|
||||
path: '/projectDemand/requirement/moblie',
|
||||
name: 'projectDemandRequirementMoblie',
|
||||
component: () => import('@/views/project-demand/requirement/moblieDetail/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/expenseManagement/share/moblie',
|
||||
name: 'expenseManagementMoblie',
|
||||
component: () => import('@/views/expense-management/share/moblieDetail/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/phase/detail/moblie',
|
||||
name: 'phaseDetailMoblie',
|
||||
component: () => import('@/views/project-management/phaseDetailMoblie/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: 'layout',
|
||||
@@ -52,15 +82,6 @@ const router = createRouter({
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/rapid/gen/edit/:tableId(\\d+)',
|
||||
name: 'genEdit',
|
||||
component: () => import('@/views/rapid/gen/editTable.vue'),
|
||||
meta: {
|
||||
title: '数据库生成配置',
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/workflow/process/edit/:deploymentId',
|
||||
name: 'processEdit',
|
||||
@@ -80,7 +101,7 @@ const router = createRouter({
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/workflow/process/edit',
|
||||
path: '/workflow/process/add',
|
||||
name: 'processAdd',
|
||||
component: () => import('@/views/workflow/process/ProcessEdit.vue'),
|
||||
meta: {
|
||||
@@ -124,53 +145,58 @@ const router = createRouter({
|
||||
breadcrumb: false
|
||||
}
|
||||
},
|
||||
// 项目详情
|
||||
{
|
||||
path: '/custom/query/sql/design/:queryId',
|
||||
name: 'sql',
|
||||
component: () => import('@/views/custom-query/sql/SqlDesign.vue'),
|
||||
path: '/project/management/implementation/implementation/detail',
|
||||
name: 'Implementation/detail',
|
||||
component: () => import('@/views/project-management/implementation/detail.vue'),
|
||||
meta: {
|
||||
title: '自定义sql查询配置',
|
||||
breadcrumb: true
|
||||
title: '项目详情',
|
||||
breadcrumb: false
|
||||
}
|
||||
},
|
||||
// 需求征集详情
|
||||
{
|
||||
path: '/custom/query/data/adapter/design/:queryId',
|
||||
name: 'dataAdapter',
|
||||
component: () => import('@/views/custom-query/data-adapter/DataAdapterDesign.vue'),
|
||||
path: '/project/demand/requirement/requirement/detail',
|
||||
name: 'Requirement/detail',
|
||||
component: () => import('@/views/project-demand/requirement/detail.vue'),
|
||||
meta: {
|
||||
title: '自定义数据适配器',
|
||||
breadcrumb: true
|
||||
title: '需求征集-详情',
|
||||
breadcrumb: false
|
||||
}
|
||||
},
|
||||
// 需求汇总详情
|
||||
{
|
||||
path: '/custom/query/echarts/design/:queryId',
|
||||
name: 'echarts',
|
||||
component: () => import('@/views/custom-query/echarts-editor/EchartsDesign.vue'),
|
||||
path: '/project/demand/summary/summary/detail',
|
||||
name: 'Summary/detail',
|
||||
component: () => import('@/views/project-demand/summary/detail.vue'),
|
||||
meta: {
|
||||
title: '自定义echarts查询配置',
|
||||
breadcrumb: true
|
||||
title: '需求汇总-详情',
|
||||
breadcrumb: false
|
||||
}
|
||||
},
|
||||
// 专项资金详情
|
||||
{
|
||||
path: '/rapid/data/:dsId(\\d+)',
|
||||
name: 'rapid',
|
||||
component: () => import('@/views/rapid/gen/index.vue'),
|
||||
path: '/special/fund/fund/detail',
|
||||
name: 'Fund/detail',
|
||||
component: () => import('@/views/special-fund/detail.vue'),
|
||||
meta: {
|
||||
title: '数据源关联数据',
|
||||
breadcrumb: true
|
||||
title: '专项资金-详情',
|
||||
breadcrumb: false
|
||||
}
|
||||
},
|
||||
// 费用分摊详情
|
||||
{
|
||||
path: '/expense/management/expense/share/share/detail',
|
||||
name: 'Share/detail',
|
||||
component: () => import('@/views/expense-management/share/detail.vue'),
|
||||
meta: {
|
||||
title: '费用分摊-详情',
|
||||
breadcrumb: false
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/topo/design/:queryId',
|
||||
name: 'topEdit',
|
||||
component: () => import('@/views/custom-query/topo/topologyDesign.vue'),
|
||||
meta: {
|
||||
title: 'top',
|
||||
breadcrumb: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/forbidden',
|
||||
name: 'forbidden',
|
||||
@@ -203,7 +229,7 @@ router.beforeEach(async (to, form, next) => {
|
||||
NProgress.done()
|
||||
} else {
|
||||
permisstionStore.setIsLoadRoutes(true)
|
||||
if (permisstionStore.isLoadRoutes && permisstionStore.asyncRouters.length == 0) {
|
||||
if (permisstionStore.isLoadRoutes && !permisstionStore.isSussessReq) {
|
||||
await permisstionStore.setAsyncRouters()
|
||||
await authStore.setUserInfo()
|
||||
next({...to, replace: true})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { defineAsyncComponent, ref } from "vue";
|
||||
import { defineAsyncComponent, ref, toRaw } from "vue";
|
||||
import { getRouters } from "@/api/system/menu";
|
||||
import Layout from '@/layout/index.vue'
|
||||
import ParentView from '@/components/ParentView.vue'
|
||||
@@ -10,6 +10,7 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
|
||||
const asyncRouters = ref([])
|
||||
//定义是否加载路由变量
|
||||
const isLoadRoutes = ref(false)
|
||||
const isSussessReq = ref(false)
|
||||
const menuList = ref([
|
||||
{
|
||||
name: 'home',
|
||||
@@ -21,19 +22,28 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
|
||||
}
|
||||
}
|
||||
])
|
||||
// 二级页面路由list
|
||||
const slRouters = ref([])
|
||||
|
||||
const setIsLoadRoutes = (status) => {
|
||||
return isLoadRoutes.value = status
|
||||
}
|
||||
|
||||
const setIsSuccessReq = () => {
|
||||
return isSussessReq.value = false
|
||||
}
|
||||
const setAsyncRouters = async () => {
|
||||
await getRouters().then(res => {
|
||||
if (res.code === 1000) {
|
||||
const sRouter = JSON.parse(JSON.stringify(res.data))
|
||||
const mData = JSON.parse(JSON.stringify(res.data))
|
||||
asyncRouters.value = formatAsyncRouters(sRouter)
|
||||
console.log(JSON.parse(JSON.stringify(sRouter)), 'sRouter');
|
||||
const firstFormat = setRouterLevel(JSON.parse(JSON.stringify(sRouter)))
|
||||
asyncRouters.value = formatAsyncRouters(JSON.parse(JSON.stringify(firstFormat)))
|
||||
menuList.value = [...menuList.value, ...generateMenu(mData)]
|
||||
addAsyncRouters(asyncRouters.value)
|
||||
isLoadRoutes.value = false
|
||||
isSussessReq.value = true
|
||||
} else {
|
||||
isLoadRoutes.value = true
|
||||
setTimeout(() => setAsyncRouters(), 3000)
|
||||
@@ -41,6 +51,23 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
|
||||
})
|
||||
}
|
||||
|
||||
const setRouterLevel = (routers) => {
|
||||
return routers.filter(item=>{
|
||||
if(item.component === 'Layout') {
|
||||
if(item.children) {
|
||||
item.children.forEach(v=>{
|
||||
if(v.children) {
|
||||
slRouters.value = [...toRaw(slRouters.value), ...v.children]
|
||||
delete v.children
|
||||
}
|
||||
})
|
||||
item.children = [...item.children, ...toRaw(slRouters.value)]
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
const formatAsyncRouters = (routers) => {
|
||||
return routers.filter(route => {
|
||||
if (route.component) {
|
||||
@@ -48,8 +75,7 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
|
||||
route.component = Layout
|
||||
} else if (route.component === 'ParentView') {
|
||||
route.component = ParentView
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
route.component = loadView(route.component)
|
||||
}
|
||||
}
|
||||
@@ -126,8 +152,10 @@ export const usePermisstionStroe = defineStore('permisstion', () => {
|
||||
asyncRouters,
|
||||
menuList,
|
||||
isLoadRoutes,
|
||||
isSussessReq,
|
||||
setAsyncRouters,
|
||||
setIsLoadRoutes,
|
||||
removeMenu
|
||||
removeMenu,
|
||||
setIsSuccessReq
|
||||
}
|
||||
})
|
||||
@@ -39,8 +39,8 @@ export const useProcessStore = defineStore('process', () => {
|
||||
}
|
||||
const delProcess = (delNode) => {
|
||||
processData.value.process.splice(processData.value.process.indexOf(delNode), 1)
|
||||
console.log("删除数据")
|
||||
console.log(processData.value.process)
|
||||
// console.log("删除数据")
|
||||
// console.log(processData.value.process)
|
||||
}
|
||||
|
||||
const getDesign = () => {
|
||||
|
||||
@@ -53,7 +53,11 @@ export const useTagsView = defineStore('tagsView',()=>{
|
||||
//路由到末尾标签页
|
||||
const toLastTagView = (view) => {
|
||||
const lastTagView = view.value.slice(-1)[0]
|
||||
router.push(lastTagView.path)
|
||||
router.push({path: lastTagView.path, query: lastTagView.query})
|
||||
}
|
||||
|
||||
const removeAllTagView = () => {
|
||||
visitedViews.value.length = 0
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -61,6 +65,7 @@ export const useTagsView = defineStore('tagsView',()=>{
|
||||
addVisitedViews,
|
||||
delVisitedViews,
|
||||
delOtherVisitedViews,
|
||||
delViewAndGoView
|
||||
delViewAndGoView,
|
||||
removeAllTagView
|
||||
}
|
||||
})
|
||||
|
||||
@@ -9,7 +9,7 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
const permisstions = ref([])
|
||||
const roles = ref([])
|
||||
const casToken = (token) => {
|
||||
console.log('getToken()!==token',getToken()!==token)
|
||||
// console.log('getToken()!==token',getToken()!==token)
|
||||
let flag=''
|
||||
if(getToken()!==token){//切换token
|
||||
setToken(token)
|
||||
|
||||
9
src/utils/changePrice.js
Normal file
@@ -0,0 +1,9 @@
|
||||
export const toThousands = (num) => {
|
||||
let newNum=Number(num)
|
||||
if (newNum == undefined || newNum == null) return '--';
|
||||
const options = {
|
||||
style: 'currency',
|
||||
currency: 'CNY',
|
||||
};
|
||||
return (newNum).toLocaleString('zh-CN', options)
|
||||
}
|
||||
42
src/utils/date.js
Normal file
@@ -0,0 +1,42 @@
|
||||
export const dateFormat = (time = new Date().getTime(),flag) => { //YYYY年MM月DD日 星期d
|
||||
const _time = time.toString().length > 10 ? time : time * 1000
|
||||
const weekList = ["日","一", "二", "三", "四", "五", "六" ];
|
||||
const date = new Date(_time);
|
||||
const Y = date.getFullYear();
|
||||
const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1);
|
||||
const Mm = (date.getMonth() + 1 < 10 ? (date.getMonth() + 1) : date.getMonth() + 1);
|
||||
const D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
|
||||
const h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours());
|
||||
const m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes());
|
||||
const s = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds());
|
||||
let weekDay = new Date().getDay();
|
||||
const week= weekList[weekDay]
|
||||
// const strDate = `${Y}/${M}/${D} ${h}:${m}:${s}`
|
||||
if(flag){
|
||||
return `${Mm}月`;
|
||||
}else {
|
||||
return `${Y}年${M}月${D}日 星期${week}`;
|
||||
}
|
||||
}
|
||||
export const getNowFormatDate = (flag) => {
|
||||
let date = new Date(),
|
||||
year = date.getFullYear(), //获取完整的年份(4位)
|
||||
month = date.getMonth() + 1, //获取当前月份(0-11,0代表1月)
|
||||
strDate = date.getDate() // 获取当前日(1-31)
|
||||
if (month < 10) month = `0${month}` // 如果月份是个位数,在前面补0
|
||||
if (strDate < 10) strDate = `0${strDate}` // 如果日是个位数,在前面补0
|
||||
if(flag){
|
||||
return `${year}-${month}-${strDate}`
|
||||
}else {
|
||||
return `${year}-${month}`
|
||||
}
|
||||
}
|
||||
export default {
|
||||
dateFormat,
|
||||
getNowFormatDate
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
131
src/utils/export-excel.js
Normal file
@@ -0,0 +1,131 @@
|
||||
import {utils} from "xlsx";
|
||||
import FileSaver from 'file-saver'
|
||||
import XLSX from "xlsx-style-vite";
|
||||
|
||||
/**
|
||||
* 导出excel
|
||||
* @param $table 表格html dom元素
|
||||
* @param columnLength 列长度
|
||||
* @param excelName 导出文件名称
|
||||
* @param bigWidthIndex 更宽列的索引
|
||||
* @param bigWidthArray 更宽列数组索引
|
||||
*/
|
||||
export function exportExcel($table, columnLength, excelName, bigWidthIndex,bigWidthArray) {
|
||||
//从el-table表生成工作簿对象
|
||||
//使用原始的格式,保留表格中的格式如%、小数末尾的0等
|
||||
let workbook = utils.table_to_book($table, {
|
||||
raw: true
|
||||
});
|
||||
//列宽,需要导出的表格有多少列这里的i就小于多少
|
||||
// if(bigWidthArray&&bigWidthArray.length>0){
|
||||
// for (let i = 1; i < columnLength; i++) {
|
||||
// for (let j = 0; j < bigWidthArray.length; j++) {
|
||||
// console.log('bigWidthArray[j]',bigWidthArray[j])
|
||||
// if (i === bigWidthArray[j]) {
|
||||
// workbook.Sheets.Sheet1["!cols"].push({wpx: 300});
|
||||
// }
|
||||
// }
|
||||
// workbook.Sheets.Sheet1["!cols"].push({wpx: 100});
|
||||
// }
|
||||
// }else {
|
||||
for (let i = 1; i < columnLength; i++) {
|
||||
if (i === bigWidthIndex) {
|
||||
workbook.Sheets.Sheet1["!cols"].push({wpx: 300});
|
||||
}
|
||||
workbook.Sheets.Sheet1["!cols"].push({wpx: 100});
|
||||
}
|
||||
// }
|
||||
|
||||
//设置单元格样式
|
||||
for (const key in workbook.Sheets.Sheet1) {
|
||||
if (
|
||||
key !== "!cols" &&
|
||||
key !== "!fullref" &&
|
||||
key !== "!merges" &&
|
||||
key !== "!ref" &&
|
||||
key !== "!rows"
|
||||
) {
|
||||
//这里的s就是具体的样式,如果想设置不一样的样式可以看xlsx-style文档
|
||||
workbook.Sheets.Sheet1[key].s = {
|
||||
//边框
|
||||
border: {
|
||||
top: {style: "thin"},
|
||||
bottom: {style: "thin"},
|
||||
left: {style: "thin",},
|
||||
right: {style: "thin",}
|
||||
},
|
||||
//对齐
|
||||
alignment: {
|
||||
horizontal: "center",
|
||||
vertical: "center",
|
||||
wrapText: true
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
//修改合并单元格样式
|
||||
let arr = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
|
||||
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
|
||||
//由于导出时合并单元格只识别左上角的单元格,合并单元格中其他单元格
|
||||
//并不会存在,所以需要识别合并单元格中除左上角单元格外的单元格并添加
|
||||
//带样式的单元格到其中,不理解可以看四中的第2点。
|
||||
try {
|
||||
|
||||
for (let item of workbook.Sheets.Sheet1["!merges"]) {
|
||||
let style = {
|
||||
border: {
|
||||
top: {style: "thin"},
|
||||
bottom: {style: "thin"},
|
||||
left: {style: "thin",},
|
||||
right: {style: "thin",}
|
||||
},
|
||||
alignment: {
|
||||
horizontal: "center",
|
||||
vertical: "center",
|
||||
wrapText: true
|
||||
}
|
||||
};
|
||||
let merge_s = {t: "s", v: "", s: style};
|
||||
if (item.s.c === item.e.c) {
|
||||
//纵向合并,其中c为字母r为数字
|
||||
let star = item.s.r;
|
||||
let end = item.e.r;
|
||||
for (let i = star + 1; i <= end; i++) {
|
||||
workbook.Sheets.Sheet1[arr[item.s.c] + (i + 1)] = merge_s;
|
||||
}
|
||||
} else {
|
||||
//横向合并
|
||||
let star = item.s.c;
|
||||
let end = item.e.c;
|
||||
for (let i = star; i < end; i++) {
|
||||
workbook.Sheets.Sheet1[arr[i + 1] + Number(item.s.r + 1)] = merge_s;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
|
||||
//将表格数据中的字符串转ArrayBuffer
|
||||
function s2ab(s) {
|
||||
let buf = new ArrayBuffer(s.length);
|
||||
let view = new Uint8Array(buf);
|
||||
for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
|
||||
return buf;
|
||||
}
|
||||
|
||||
//这里的属性可以参考xlsx-style文档
|
||||
let wbout = XLSX.write(workbook, {
|
||||
bookType: "xlsx",
|
||||
bookSST: false,
|
||||
type: "binary"
|
||||
});
|
||||
try {
|
||||
FileSaver.saveAs(
|
||||
new Blob([s2ab(wbout)], {type: "application/octet-stream"}),
|
||||
`${excelName}.xlsx`
|
||||
);
|
||||
} catch (e) {
|
||||
if (typeof console !== "undefined") console.log(e, wbout);
|
||||
}
|
||||
}
|
||||
13
src/utils/matterTree.js
Normal file
@@ -0,0 +1,13 @@
|
||||
export const matterTree = (array,data, id) => {
|
||||
if (id) {
|
||||
data.forEach(item => {
|
||||
if (item.value == id) {
|
||||
array.push(item.label);
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
matterTree(array,item.children,id)
|
||||
}
|
||||
})
|
||||
return array;
|
||||
}
|
||||
}
|
||||
@@ -25,22 +25,31 @@ serveice.interceptors.request.use(config => {
|
||||
})
|
||||
serveice.interceptors.response.use(response => {
|
||||
axiosCanceler.removePendingRequest(response.config)
|
||||
// console.log(response,"response")
|
||||
//二进制数据直接返回
|
||||
if (response.request.responseType === 'blob' || response.request.responseType === 'arraybuffer') {
|
||||
return response.data
|
||||
}
|
||||
// console.log("1")
|
||||
return response.data
|
||||
}, error => {
|
||||
// console.log(error)
|
||||
let response = error.response
|
||||
if (!response) {
|
||||
return Promise.reject()
|
||||
}
|
||||
const status = response.status;
|
||||
if (!status) {
|
||||
return Promise.reject()
|
||||
}
|
||||
switch (status) {
|
||||
case 401:
|
||||
ElMessageBox.confirm('登录状态已过期,请重新登录', '系统提示', {
|
||||
confirmButtonText: '重新登录',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
closeOnClickModal: false
|
||||
}).then(() => {
|
||||
// ElMessageBox.confirm('登录状态已过期,请重新登录', '系统提示', {
|
||||
// confirmButtonText: '重新登录',
|
||||
// cancelButtonText: '取消',
|
||||
// type: 'warning',
|
||||
// closeOnClickModal: false
|
||||
// }).then(() => {
|
||||
removeToken()
|
||||
let path = window.location.pathname;
|
||||
let query = window.location.search
|
||||
@@ -49,12 +58,11 @@ serveice.interceptors.response.use(response => {
|
||||
query: query
|
||||
}))
|
||||
window.location.href = `${window.location.origin}/api/auth/cas/login`
|
||||
})
|
||||
// })
|
||||
return Promise.reject('会话已过期,请重新登录')
|
||||
case 402:
|
||||
break;
|
||||
case 403:
|
||||
console.log(response)
|
||||
ElNotification({
|
||||
title: '系统提示',
|
||||
message: response.data.msg,
|
||||
|
||||
@@ -6,37 +6,91 @@
|
||||
<!-- 标题 -->
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>个人信息</span>
|
||||
<div>个人信息</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="userDetail">
|
||||
<!-- 头像上传 -->
|
||||
<div class="userImg">
|
||||
<el-image class="avatar" :src="userParams.avatar" fit="fill"/>
|
||||
<div class="userInfo_item">
|
||||
<div style="display: flex;align-items: center">
|
||||
<el-icon size="18" style="margin-right: 5px">
|
||||
<User/>
|
||||
</el-icon>
|
||||
用户名:
|
||||
</div>
|
||||
<div>{{ userParams.userName }}</div>
|
||||
</div>
|
||||
<div class="userInfo_item">
|
||||
<el-icon>
|
||||
<UserFilled />
|
||||
<div style="display: flex;align-items: center">
|
||||
<el-icon size="18" style="margin-right: 5px">
|
||||
<User/>
|
||||
</el-icon>
|
||||
用户呢称: <span>{{ userParams.nickName }}</span>
|
||||
用户名称:
|
||||
</div>
|
||||
<div class="userInfo_item"><el-icon>
|
||||
<Iphone />
|
||||
</el-icon>电话号码: <span>{{ userParams.phoneNumber }}</span> </div>
|
||||
<div class="userInfo_item"><el-icon>
|
||||
<Message />
|
||||
</el-icon>用户邮箱:<span>{{ userParams.email }}</span> </div>
|
||||
<div class="userInfo_item"><el-icon>
|
||||
<HomeFilled />
|
||||
</el-icon>所属部门: <span>{{ userParams.city }}</span> </div>
|
||||
<div class="userInfo_item"><el-icon>
|
||||
<OfficeBuilding />
|
||||
</el-icon>所属角色: <span>{{ userParams.createBy }}</span> </div>
|
||||
<div class="userInfo_item"><el-icon>
|
||||
<Calendar />
|
||||
</el-icon>创建日期:<span>{{ userParams.loginDate }}</span> </div>
|
||||
<div>{{ userParams.nickName }}</div>
|
||||
</div>
|
||||
<div class="userInfo_item">
|
||||
<div style="display: flex;align-items: center">
|
||||
<el-icon size="18" style="margin-right: 5px">
|
||||
<Notification/>
|
||||
</el-icon>
|
||||
工号:
|
||||
</div>
|
||||
<div>{{ userParams.workCode }}</div>
|
||||
</div>
|
||||
<div class="userInfo_item">
|
||||
<div style="display: flex;align-items: center">
|
||||
<el-icon size="18" style="margin-right: 5px">
|
||||
<Phone/>
|
||||
</el-icon>
|
||||
电话号码:
|
||||
</div>
|
||||
<div>{{ userParams.mobile }}</div>
|
||||
</div>
|
||||
<div class="userInfo_item">
|
||||
<div style="display: flex;align-items: center">
|
||||
<el-icon size="18" style="margin-right: 5px">
|
||||
<House/>
|
||||
</el-icon>
|
||||
所属公司:
|
||||
</div>
|
||||
<div>{{ userParams.subCompanyName }}</div>
|
||||
</div>
|
||||
<div class="userInfo_item">
|
||||
<div style="display: flex;align-items: center">
|
||||
<el-icon size="18" style="margin-right: 5px">
|
||||
<FolderOpened/>
|
||||
</el-icon>
|
||||
所属部门:
|
||||
</div>
|
||||
<div>{{ userParams.departmentName }}</div>
|
||||
</div>
|
||||
<div class="userInfo_item">
|
||||
<div style="display: flex;align-items: center">
|
||||
<el-icon size="18" style="margin-right: 5px">
|
||||
<Folder/>
|
||||
</el-icon>
|
||||
岗位:
|
||||
</div>
|
||||
<div>{{ userParams.jobActivityDesc }}</div>
|
||||
</div>
|
||||
<div class="userInfo_item">
|
||||
<div style="display: flex;align-items: center">
|
||||
<el-icon size="18" style="margin-right: 5px">
|
||||
<Wallet/>
|
||||
</el-icon>
|
||||
账号类型:
|
||||
</div>
|
||||
<div>{{ userParams.accountType === '0' ? '主账号' : '次账号' }}</div>
|
||||
</div>
|
||||
<div class="userInfo_item">
|
||||
<div style="display: flex;align-items: center">
|
||||
<el-icon size="18" style="margin-right: 5px">
|
||||
<User/>
|
||||
</el-icon>
|
||||
所属角色:
|
||||
</div>
|
||||
<div>{{ belongToRole(userParams.roles) }}</div>
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -45,143 +99,138 @@
|
||||
<!-- 标题 -->
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>基本资料</span>
|
||||
<div>{{ isInitPassword ? '修改密码' : '初始化密码' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-tabs class="demo-tabs" v-model="activeName">
|
||||
<el-tab-pane label="基本资料" name="first" >
|
||||
<el-form
|
||||
:model="userParams"
|
||||
label-width="120px"
|
||||
class="demo-ruleForm"
|
||||
>
|
||||
<el-form-item label="用户昵称" prop="userName" :required="true" style="text-align:left">
|
||||
<el-input v-model="userParams.nickName"/>
|
||||
<el-form label-width="120px" ref="passwordRef" :model="userPassword" :rules="rules">
|
||||
<el-form-item label="旧密码" prop="oldPassword" :required="true" style="text-align:left" v-if="isInitPassword">
|
||||
<el-input placeholder="请输入旧密码" v-model="userPassword.oldPassword" type="password"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号码" :required="true" style="text-align:left">
|
||||
<el-input v-model="userParams.phoneNumber"/>
|
||||
<el-form-item label="新密码" prop="newPassword" :required="true" style="text-align:left">
|
||||
<el-input placeholder="请输入新密码" v-model="userPassword.newPassword" type="password"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱" prop="email" :required="true" style="text-align:left">
|
||||
<el-input v-model="userParams.email"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别" prop="sex">
|
||||
<el-radio-group v-model="userParams.sex">
|
||||
<el-radio label="0">男</el-radio>
|
||||
<el-radio label="1">女</el-radio>
|
||||
</el-radio-group>
|
||||
<el-form-item label="确认密码" prop="confirmPassword" :required="true" style="text-align:left">
|
||||
<el-input placeholder="请确认新密码" v-model="userPassword.confirmPassword" type="password"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submit">保存</el-button>
|
||||
<el-button color="#DED0B2" @click="handleSubmit">提交</el-button>
|
||||
<el-button @click="close">关闭</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="修改密码" name="second">
|
||||
<el-form label-width="120px" :model="userPassword">
|
||||
<el-form-item label="旧密码" :required="true" style="text-align:left">
|
||||
<el-input placeholder="请输入旧密码" v-model="userPassword.oldPassWord"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码" :required="true" style="text-align:left">
|
||||
<el-input placeholder="请输入新密码" v-model="userPassword.newPassWord"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" :required="true" style="text-align:left">
|
||||
<el-input placeholder="请确认新密码" v-model="userPassword.querenPassWord"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submit2">保存</el-button>
|
||||
<el-button @click="close">关闭</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import {getUserInfo} from '@/api/login';
|
||||
import {ref} from "vue";
|
||||
import {modifyUser} from '@/api/auth/auth'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useTagsView } from '@/stores/tagsview.js'
|
||||
var userParams = ref({})
|
||||
var userPassword=ref({
|
||||
oldPassWord:'',
|
||||
newPassWord:'',
|
||||
querenPassWord:''
|
||||
})
|
||||
const activeName = ref('first')
|
||||
import {ElNotification} from 'element-plus'
|
||||
import {useTagsView} from '@/stores/tagsview.js'
|
||||
import {getAuthInfo} from "@/api/login";
|
||||
import {editPassword, initPassword} from "@/api/auth/auth";
|
||||
|
||||
const isInitPassword = ref(false);
|
||||
const userParams = ref({});
|
||||
const passwordRef = ref();
|
||||
const router = useRouter()
|
||||
const userPassword = ref({
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: ''
|
||||
});
|
||||
const tagsViewStore = useTagsView()
|
||||
const getuserinfo=async ()=>{
|
||||
await getUserInfo().then(res=>{
|
||||
userParams.value=res.data.user
|
||||
const validatePasswordComplexity = (rule, value, callback) => {
|
||||
const reg = /^(?=.*[a-zA-Z])(?=.*\d).{1,9}$/; //密码必须是至少包含字母、数字,1-9位
|
||||
if (!reg.test(value)) {
|
||||
callback(new Error("密码必须是至少包含字母、数字,1-9位"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const validatePasswordEquality = (rule, value, callback) => {
|
||||
if (userPassword.value.newPassword != value) {
|
||||
callback(new Error("两次输入密码不一致!"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
const rules = reactive({
|
||||
oldPassword: [
|
||||
{required: true, message: "旧密码不能为空", trigger: ["change", "blur"]},
|
||||
],
|
||||
newPassword: [
|
||||
{required: true, message: "新密码不能为空", trigger: ["change", "blur"]},
|
||||
{
|
||||
required: true,
|
||||
trigger: ["change", "blur"],
|
||||
validator: validatePasswordComplexity
|
||||
}
|
||||
],
|
||||
confirmPassword: [
|
||||
{required: true, message: "确认密码不能为空", trigger: ["change", "blur"]},
|
||||
{
|
||||
required: true,
|
||||
trigger: ["change", "blur"],
|
||||
validator: validatePasswordEquality
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
const getInfo = async () => {
|
||||
await getAuthInfo().then(res => {
|
||||
userParams.value = res.data.user
|
||||
isInitPassword.value = res.data.initPassword
|
||||
})
|
||||
}
|
||||
|
||||
// 修改资料
|
||||
const submit=async ()=>{
|
||||
await modifyUser({
|
||||
userName:userParams.value.userName,
|
||||
nickName:userParams.value.nickName,
|
||||
phoneNumber:userParams.value.phoneNumber,
|
||||
email:userParams.value.email,
|
||||
sex:userParams.value.sex,
|
||||
userId:userParams.value.userId
|
||||
}).then(res=>{
|
||||
console.log(res)
|
||||
})
|
||||
const belongToRole = (roles) => {
|
||||
if (!roles) return;
|
||||
return roles.map(item => item.roleName).join(',')
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
const submit2=async ()=>{
|
||||
await getUserInfo().then( res=>{
|
||||
if(res.data!=''){
|
||||
console.log(res.data.user.password)
|
||||
if (userPassword.value.oldPassWord==res.data.user.password && userPassword.value.newPassWord==userPassword.value.querenPassWord){
|
||||
modifyUser({
|
||||
userName:userParams.value.userName,
|
||||
nickName:userParams.value.nickName,
|
||||
password:userPassword.value.newPassWord,
|
||||
userId:userParams.value.userId
|
||||
}).then(res=>{
|
||||
ElMessage({
|
||||
message: '修改密码成功',
|
||||
type: 'success',
|
||||
const handleSubmit = async () => {
|
||||
if (isInitPassword.value) {
|
||||
editPassword({
|
||||
...userPassword.value
|
||||
}).then(res => {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: res.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
if (res.code === 1000) {
|
||||
passwordRef.value.resetFields()
|
||||
}
|
||||
})
|
||||
}else if(userPassword.value.oldPassWord!=res.data.user.password && userPassword.value.newPassWord==userPassword.value.querenPassWord){
|
||||
ElMessage({
|
||||
message: '旧密码错误',
|
||||
type: 'error',
|
||||
} else {
|
||||
initPassword({
|
||||
newPassword: userPassword.value.newPassword,
|
||||
confirmPassword: userPassword.value.confirmPassword
|
||||
}).then(res => {
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
type: res.code === 1000 ? 'success' : 'error'
|
||||
})
|
||||
}else if(userPassword.value.oldPassWord==res.data.user.password && userPassword.value.newPassWord!=userPassword.value.querenPassWord){
|
||||
ElMessage({
|
||||
message: '新密码与确认密码不同',
|
||||
type: 'error',
|
||||
if (res.code === 1000) {
|
||||
passwordRef.value.resetFields()
|
||||
}
|
||||
})
|
||||
}
|
||||
}else{
|
||||
ElMessage({
|
||||
message: '请求错误',
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
// 关闭
|
||||
const close = () => {
|
||||
tagsViewStore.delVisitedViews({
|
||||
path:"/auth",meta:{hidden: false, title: '个人中心', breadcrumb: true}})
|
||||
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
|
||||
router.push('/')
|
||||
}
|
||||
onMounted(()=>{
|
||||
getuserinfo()
|
||||
onMounted(() => {
|
||||
getInfo()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
body,div {
|
||||
body, div {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -189,6 +238,7 @@ body,div {
|
||||
.my {
|
||||
margin: 0 auto;
|
||||
margin-top: 20px;
|
||||
|
||||
.userDetail {
|
||||
.userImg {
|
||||
height: 170px;
|
||||
@@ -196,6 +246,7 @@ body,div {
|
||||
border-bottom-style: solid;
|
||||
border-color: #daddd2;
|
||||
border-width: 1px;
|
||||
|
||||
.avatar {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
@@ -203,18 +254,23 @@ body,div {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.userInfo_item {
|
||||
display: flex;align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 40px;
|
||||
border-bottom-style: solid;
|
||||
border-color: #daddd2;
|
||||
border-width: 1px;
|
||||
text-align: left;
|
||||
line-height: 40px;
|
||||
//text-align: left;
|
||||
//line-height: 40px;
|
||||
|
||||
}
|
||||
|
||||
.userInfo_item > span {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
//
|
||||
//.userInfo_item > div {
|
||||
// float: right;
|
||||
//}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,71 +0,0 @@
|
||||
<template>
|
||||
<el-form ref="queryForm" class="query-form" :model="queryParams">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="16">
|
||||
<div class="code-editor">
|
||||
<java-code-edit v-model="queryParams.code" :editor-placeholder="'请输入java代码'" :editor-height="250"
|
||||
:tab-size="2"/>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="模拟数据" prop="mockData">
|
||||
<el-input v-model="queryParams.mockData" placeholder="请输入模拟数据" :rows="4" type="textarea" clearable>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-button type="primary" @click="handleSave">保存</el-button>
|
||||
<el-button type="primary" @click="handleExecute">执行</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import JavaCodeEdit from "@/components/codeEdit/JavaCodeEdit.vue";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {executeAdapterMockData, getDataAdapterDetails,editDataAdapter} from "@/api/custom-query/adapter";
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
const router = useRouter();
|
||||
const queryId = reactive(router.currentRoute.value.params.queryId)
|
||||
const queryParams = ref({
|
||||
adapterName:null,
|
||||
type:null,
|
||||
source:"CUSTOM",
|
||||
code: null,
|
||||
mockData: null
|
||||
})
|
||||
|
||||
const getDetails = async () => {
|
||||
await getDataAdapterDetails(queryId).then(res => {
|
||||
if (res.code === 1000) {
|
||||
queryParams.value = res.data
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
getDetails()
|
||||
const handleSave=()=>{
|
||||
editDataAdapter(queryParams.value).then(res => {
|
||||
if (res.code === 1000) {
|
||||
ElMessage.success(res.msg)
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleExecute = () => {
|
||||
executeAdapterMockData(queryParams.value).then(res => {
|
||||
console.log('handleExecute',res)
|
||||
if (res.code === 1000) {
|
||||
ElMessage.success(res.msg)
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,285 +0,0 @@
|
||||
<template>
|
||||
<el-form :model="queryParams" inline class="query-form" ref="queryForm">
|
||||
<el-form-item label="适配器名称" prop="adapterName">
|
||||
<el-input v-model="queryParams.adapterName" placeholder="请输适配器名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="适配器来源" prop="source">
|
||||
<el-select v-model="queryParams.source" placeholder="请选择适配器来源" clearable filterable>
|
||||
<el-option
|
||||
v-for="item in cacheStore.getDict('data_adapter_source')"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="代码类型" prop="type">
|
||||
<el-select v-model="queryParams.type" placeholder="请选择数据适配器代码类型" clearable filterable>
|
||||
<el-option
|
||||
v-for="item in cacheStore.getDict('data_adapter_type')"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getList" :icon="Search">搜索</el-button>
|
||||
<el-button @click="handleReset" :icon="Refresh">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="query-btn">
|
||||
<el-button type="primary" v-perm="['query:adapter:add']" @click="handleAdd" :icon="Plus" plain>新增</el-button>
|
||||
<el-button type="danger" :icon="Delete" v-perm="['query:adapter:del']"
|
||||
@click="handleMoreDelete(adapterIds)" :disabled="disabled" plain>删除
|
||||
</el-button>
|
||||
<el-button type="warning" v-perm="['query:adapter:export']" @click="handleExport" :icon="Download" plain>导出
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="table">
|
||||
<el-table
|
||||
:data="list"
|
||||
row-key="adapterId"
|
||||
:lazy="true"
|
||||
ref="singleTable"
|
||||
v-loading="loading"
|
||||
@select="handleSelect"
|
||||
v-tabh
|
||||
>
|
||||
<el-table-column type="selection" width="55"/>
|
||||
<el-table-column label="序号" type="index" width="60"/>
|
||||
<el-table-column prop="adapterName" label="适配器名称" align="center"/>
|
||||
<el-table-column prop="type" label="代码类型" align="center">
|
||||
<template #default="scope">
|
||||
<tag dict-type="data_adapter_type" :value="scope.row.type"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="source" label="适配器来源" align="center">
|
||||
<template #default="scope">
|
||||
<tag dict-type="data_adapter_source" :value="scope.row.source"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" size="mini" v-perm="['query:adapter:edit']"
|
||||
@click="handleEdit(scope.row.adapterId)" link>编辑
|
||||
</el-button>
|
||||
<el-button type="primary" size="mini"
|
||||
@click="handleDesign(scope.row)" link>设计
|
||||
</el-button>
|
||||
<popover-delete :name="scope.row.adapterName" :type="'适配器'" :perm="['query:adapter:del']"
|
||||
@delete="handleDelete(scope.row.adapterId)"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<paging :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[10, 20, 30, 40,50]"
|
||||
:total="total" @changeSize="handleSizeChange" @goPage="handleCurrentChange"/>
|
||||
<el-dialog v-model="isVisited" :title="title" width="700px">
|
||||
<el-form :model="form" ref="formInstance" class="dialog-form">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="适配器名称" prop="adapterName">
|
||||
<el-input v-model="form.adapterName" placeholder="请输入适配器名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="数据适配器代码类型" prop="type">
|
||||
<el-select v-model="form.type" placeholder="请选择数据适配器代码类型" clearable filterable>
|
||||
<el-option
|
||||
v-for="item in cacheStore.getDict('data_adapter_type')"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="适配器来源" prop="source">
|
||||
<el-select v-model="form.source" placeholder="请选择适配器来源" clearable filterable>
|
||||
<el-option
|
||||
v-for="item in cacheStore.getDict('data_adapter_source')"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit(formInstance)">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
getDataAdapterList,
|
||||
getDataAdapterDetails,
|
||||
addDataAdapter,
|
||||
editDataAdapter,
|
||||
delDataAdapter
|
||||
} from "@/api/custom-query/adapter";
|
||||
import {ElMessage, ElMessageBox} from "element-plus";
|
||||
import {Search, Refresh, Delete, Plus, Edit, Download} from '@element-plus/icons-vue'
|
||||
import Paging from "@/components/pagination/index.vue";
|
||||
import {useCacheStore} from "@/stores/cache";
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
const router = useRouter()
|
||||
const cacheStore = useCacheStore()
|
||||
const queryParams = reactive({
|
||||
adapterName: '',
|
||||
source: '',
|
||||
type: '',
|
||||
})
|
||||
|
||||
const pageInfo = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
})
|
||||
const list = ref([])
|
||||
const queryForm = ref([])
|
||||
const loading = ref(true)
|
||||
const disabled = ref(true)
|
||||
const total = ref()
|
||||
const title = ref('')
|
||||
const isVisited = ref(false)
|
||||
const form = ref()
|
||||
const formInstance = ref()
|
||||
const adapterIds = ref([])
|
||||
const adapterNameList = ref([])
|
||||
//获取数据
|
||||
const getList = async () => {
|
||||
let params = {
|
||||
...queryParams,
|
||||
...pageInfo
|
||||
}
|
||||
loading.value = true
|
||||
getDataAdapterList(params).then(res => {
|
||||
if (res.code === 1000) {
|
||||
list.value = res.data.rows
|
||||
total.value = res.data.total
|
||||
loading.value = false
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
//重置from表单
|
||||
const restFrom = () => {
|
||||
form.value = {
|
||||
adapterName: null,
|
||||
source: "CUSTOM",
|
||||
type: null
|
||||
}
|
||||
}
|
||||
//添加
|
||||
const handleAdd = async () => {
|
||||
restFrom()
|
||||
title.value = "新增数据源适配器"
|
||||
isVisited.value = true
|
||||
nextTick(() => {
|
||||
// 清空校验
|
||||
formInstance.value.clearValidate()
|
||||
})
|
||||
}
|
||||
//修改
|
||||
const handleEdit = async (id) => {
|
||||
restFrom()
|
||||
getDataAdapterDetails(id).then(res => {
|
||||
if (res.code === 1000) {
|
||||
form.value = res.data
|
||||
title.value = "编辑数据源适配器"
|
||||
isVisited.value = true
|
||||
nextTick(() => {
|
||||
// 清空校验
|
||||
formInstance.value.clearValidate()
|
||||
})
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
//设计
|
||||
const handleDesign = (row) => {
|
||||
router.push({path: `/custom/query/data/adapter/design/${row.adapterId}`})
|
||||
}
|
||||
//删除
|
||||
const handleDelete = async (adapterId) => {
|
||||
delDataAdapter(adapterId).then(res => {
|
||||
if (res.code === 1000) {
|
||||
ElMessage.success(res.msg)
|
||||
getList()
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
//多删
|
||||
const handleMoreDelete=(adapterIds)=>{
|
||||
ElMessageBox.confirm(`确认删除名称为${adapterNameList.value}的适配器吗?`, '系统提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
handleDelete(adapterIds)
|
||||
})
|
||||
}
|
||||
//勾选table数据行事件
|
||||
const handleSelect = async (selection) => {
|
||||
if (selection.length !== 0) {
|
||||
disabled.value = false
|
||||
adapterIds.value = selection.map(item => item.adapterId).join()
|
||||
adapterNameList.value = selection.map(item => item.adapterName).join()
|
||||
} else {
|
||||
disabled.value = true
|
||||
}
|
||||
}
|
||||
//取消
|
||||
const handleCancel = () => {
|
||||
restFrom()
|
||||
isVisited.value = false
|
||||
}
|
||||
//提交
|
||||
const handleSubmit = async (instance) => {
|
||||
if (!instance) return
|
||||
instance.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
if (title.value === '新增数据源适配器') {
|
||||
addDataAdapter(form.value).then(res => {
|
||||
if (res.code === 1000) {
|
||||
ElMessage.success(res.msg)
|
||||
getList()
|
||||
isVisited.value = false
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
editDataAdapter(form.value).then(res => {
|
||||
if (res.code === 1000) {
|
||||
ElMessage.success(res.msg)
|
||||
getList()
|
||||
isVisited.value = false
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
getList()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,392 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-form :model="queryParams" inline class="query-form" ref="queryForm">
|
||||
<el-form-item label="数据模型名称" prop="dsName">
|
||||
<el-input v-model="queryParams.dsName" placeholder="请输入数据模型名称" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="数据库名称" prop="dbName">
|
||||
<el-input v-model="queryParams.dbName" placeholder="请输入数据库名称" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="配置类型" prop="configType">
|
||||
<el-select v-model="queryParams.configType" placeholder="请选择配置类型" clearable filterable>
|
||||
<el-option label="主机" value="1"/>
|
||||
<el-option label="JDBC" value="2"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch" :icon="Search">搜索</el-button>
|
||||
<el-button @click="handleReset" :icon="Refresh">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="query-btn">
|
||||
<el-button type="primary" v-perm="['query:source:add']" @click="handleAdd" :icon="Plus" plain>新增</el-button>
|
||||
<el-button type="danger" :icon="Delete" v-perm="['query:source:del']"
|
||||
@click="handleMoreDelete(sourceId,sourceName)" :disabled="disabled" plain>删除
|
||||
</el-button>
|
||||
<el-button type="warning" v-perm="['query:source:export']" @click="handleExport" :icon="Download" plain>导出
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="table">
|
||||
<el-table
|
||||
:data="list"
|
||||
row-key="id"
|
||||
:lazy="true"
|
||||
ref="singleTable"
|
||||
v-loading="loading"
|
||||
@select="handleSelect"
|
||||
v-tabh
|
||||
>
|
||||
<el-table-column type="selection" width="55"/>
|
||||
<el-table-column label="序号" type="index" width="60" align="center"/>
|
||||
<el-table-column prop="dsName" label="数据模型名称" align="center"/>
|
||||
<el-table-column prop="dbName" label="数据库名称" align="center"/>
|
||||
<el-table-column prop="username" label="数据模型用户名" align="center"/>
|
||||
<el-table-column prop="type" label="数据模型类型" align="center"/>
|
||||
<el-table-column prop="confType" label="数据模型配置类型" align="center">
|
||||
<template #default="scope">
|
||||
<tag dict-type="data_source_config" :value="scope.row.configType"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="url" label="数据模型连接地址" align="center">
|
||||
<template #default="scope">
|
||||
<div class="formatterUrl">{{ scope.row.url }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" size="mini" v-perm="['query:source:edit']"
|
||||
@click="handleEdit(scope.row.id)" link>编辑
|
||||
</el-button>
|
||||
<popover-delete :name="scope.row.dsName" :type="'数据模型'" :perm="['query:source:del']"
|
||||
@delete="handleDelete(scope.row.id)"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<paging :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[10, 20, 30, 40,50]"
|
||||
:total="total" @changeSize="handleSizeChange" @goPage="handleCurrentChange"/>
|
||||
<el-dialog v-model="isVisited" :title="title" width="900px">
|
||||
<el-form :model="form" ref="formInstance" :rules="formRules" class="dialog-form" :validate-on-rule-change="false">
|
||||
<el-row>
|
||||
<el-col :span="11">
|
||||
<el-form-item label="数据模型名称" prop="dsName">
|
||||
<el-input v-model="form.dsName" placeholder="请输入数据模型名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11" :offset="2">
|
||||
<el-form-item label="数据模型用户名" prop="username">
|
||||
<el-input v-model="form.username" placeholder="请输入数据模型用户名"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item label="数据模型密码" prop="password">
|
||||
<el-input v-model="form.password" placeholder="请输入数据模型密码"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11" :offset="2">
|
||||
<el-form-item label="数据模型类型" prop="type">
|
||||
<el-select v-model="form.type" placeholder="请选择数据模型类型" filterable @change="handleTypeChange(form.type)">
|
||||
<el-option
|
||||
v-for="typeItem in typeList"
|
||||
:key="typeItem.value"
|
||||
:label="typeItem.label"
|
||||
:value="typeItem.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item label="配置类型" prop="configType">
|
||||
<el-radio-group v-model="form.configType">
|
||||
<el-radio border :label="1">主机</el-radio>
|
||||
<el-radio border :label="2">JDBC</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11" :offset="2" v-if="form.configType === 1">
|
||||
<el-form-item label="数据模型端口" prop="port">
|
||||
<el-input-number v-model="form.port"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11" v-if="form.configType === 1">
|
||||
<el-form-item label="数据模型服务地址" prop="host">
|
||||
<el-input v-model="form.host" placeholder="请输入数据模型服务地址"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11" :offset="2">
|
||||
<el-form-item label="数据库名称" prop="dbName" v-if="form.configType === 1">
|
||||
<el-input v-model="form.dbName" placeholder="请输入数据库名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="form.configType === 2">
|
||||
<el-form-item label="数据模型连接地址" prop="url">
|
||||
<el-input v-model="form.url" :rows="4"
|
||||
type="textarea" placeholder="请输入数据模型连接地址"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="form.configType === 1">
|
||||
<el-form-item label="配置参数" prop="args">
|
||||
<el-input v-model="form.args" :rows="4"
|
||||
type="textarea" placeholder="请输入配置参数"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="服务名称" prop="params.serviceName" v-if="form.type === 'ORACLE' && form.configType===1">
|
||||
<el-input v-model="form.params.serviceName" placeholder="请输入服务名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="命名空间" prop="params.namespace" v-if="form.type === 'POSTGRES' && form.configType===1">
|
||||
<el-input v-model="form.params.namespace" placeholder="请输入命名空间"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit(formInstance)">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
getDataSourceManageList,
|
||||
getDataSourceManageDetails,
|
||||
addDataSourceManage,
|
||||
editDataSourceManage,
|
||||
delDataSourceManage,
|
||||
getDataSourceType
|
||||
} from "@/api/custom-query/datamodel";
|
||||
import {Search, Refresh, Delete, Plus, Edit, Download} from '@element-plus/icons-vue'
|
||||
import {ElMessage, ElMessageBox} from "element-plus";
|
||||
import {downLoadExcel} from "@/utils/downloadZip";
|
||||
import Paging from "@/components/pagination/index.vue";
|
||||
|
||||
//查询参数
|
||||
const queryParams = reactive({
|
||||
dsName: '',
|
||||
dbName: '',
|
||||
type: '',
|
||||
})
|
||||
//页面信息
|
||||
const pageInfo = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
})
|
||||
const disabled = ref(true)
|
||||
const typeList = ref([])
|
||||
const list = ref([])
|
||||
const queryForm = ref([])
|
||||
const loading = ref(true)
|
||||
const total = ref()
|
||||
const sourceId = ref()
|
||||
const sourceName = ref()
|
||||
const singleTable = ref()
|
||||
const title = ref('')
|
||||
const isVisited = ref(false)
|
||||
const form = ref()
|
||||
const formInstance = ref()
|
||||
const formRules = ref({
|
||||
dsName: [{required: true, message: '请输入数据模型名称', trigger: 'blur'}],
|
||||
username: [{required: true, message: '请输入数据模型用户名', trigger: 'blur'}],
|
||||
password: [{required: true, message: '请输入数据模型密码', trigger: 'blur'}],
|
||||
type: [{required: true, message: '请选择数据模型类型', trigger: 'blur'}],
|
||||
configType: [{required: true, message: '请选择配置类型', trigger: 'blur'}],
|
||||
port: [{required: true, message: '请输入数据模型端口', trigger: 'blur'}],
|
||||
host: [{required: true, message: '请输入数据模型服务地址', trigger: 'blur'}],
|
||||
dbName: [{required: true, message: '请输入数据库名称', trigger: 'blur'}],
|
||||
url: [{required: true, message: '请输入数据模型连接地址', trigger: 'blur'}],
|
||||
params: {
|
||||
serviceName: [{required: true, message: '请输入服务名称', trigger: 'blur'}],
|
||||
namespace: [{required: true, message: '请输入命名空间', trigger: 'blur'}]
|
||||
}
|
||||
})
|
||||
const getTypeOption = () => {
|
||||
getDataSourceType().then(res => {
|
||||
typeList.value = res.data
|
||||
})
|
||||
}
|
||||
|
||||
const handleTypeChange = (type) => {
|
||||
if (form.value.configType !== 1) {
|
||||
return;
|
||||
}
|
||||
if (type === 'ORACLE') {
|
||||
form.value.params = {
|
||||
serviceName: ''
|
||||
}
|
||||
}
|
||||
if (type === 'POSTGRES') {
|
||||
form.value.params = {
|
||||
namespace: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//搜索功能
|
||||
const handleSearch = () => {
|
||||
getList()
|
||||
}
|
||||
//重置搜索
|
||||
const handleReset = () => {
|
||||
queryForm.value.resetFields()
|
||||
getList()
|
||||
}
|
||||
//获取数据
|
||||
const getList = async () => {
|
||||
let params = {
|
||||
...queryParams,
|
||||
...pageInfo
|
||||
}
|
||||
loading.value = true
|
||||
getDataSourceManageList(params).then(res => {
|
||||
if (res.code === 1000) {
|
||||
list.value = res.data.rows
|
||||
total.value = res.data.total
|
||||
loading.value = false
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
//重置from表单
|
||||
const restFrom = () => {
|
||||
form.value = {
|
||||
dsName: null,
|
||||
username: null,
|
||||
password: null,
|
||||
host: null,
|
||||
port: 0,
|
||||
type: null,
|
||||
dbName: null,
|
||||
configType: 1,
|
||||
url: null,
|
||||
args: null,
|
||||
params: {}
|
||||
}
|
||||
}
|
||||
//取消
|
||||
const handleCancel = () => {
|
||||
restFrom()
|
||||
isVisited.value = false
|
||||
}
|
||||
//提交
|
||||
const handleSubmit = async (instance) => {
|
||||
if (!instance) return
|
||||
instance.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
if (title.value === '新增数据模型管理') {
|
||||
addDataSourceManage(form.value).then(res => {
|
||||
if (res.code === 1000) {
|
||||
ElMessage.success(res.msg)
|
||||
getList()
|
||||
isVisited.value = false
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
editDataSourceManage(form.value).then(res => {
|
||||
if (res.code === 1000) {
|
||||
ElMessage.success(res.msg)
|
||||
getList()
|
||||
isVisited.value = false
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
//添加
|
||||
const handleAdd = async () => {
|
||||
formRules.value.password[0].required = true
|
||||
restFrom()
|
||||
title.value = "新增数据模型管理"
|
||||
isVisited.value = true
|
||||
nextTick(() => {
|
||||
// 清空校验
|
||||
formInstance.value.clearValidate()
|
||||
})
|
||||
}
|
||||
//修改
|
||||
const handleEdit = async (id) => {
|
||||
restFrom()
|
||||
getDataSourceManageDetails(id).then(res => {
|
||||
if (res.code === 1000) {
|
||||
console.log('res', res.data)
|
||||
formRules.value.password[0].required = false
|
||||
form.value = res.data
|
||||
title.value = "编辑数据模型管理"
|
||||
isVisited.value = true
|
||||
nextTick(() => {
|
||||
// 清空校验
|
||||
formInstance.value.clearValidate()
|
||||
})
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
//导出excel
|
||||
const handleExport = () => {
|
||||
downLoadExcel('/query/query/source/export', {...queryParams})
|
||||
}
|
||||
|
||||
//勾选table数据行的 Checkbox
|
||||
const handleSelect = async (selection) => {
|
||||
if (selection.length !== 0) {
|
||||
disabled.value = false
|
||||
sourceId.value = selection.map(item => item.id).join()
|
||||
sourceName.value = selection.map(item => item.dsName).join()
|
||||
} else {
|
||||
disabled.value = true
|
||||
}
|
||||
}
|
||||
|
||||
//切换每页显示条数
|
||||
const handleSizeChange = async (val) => {
|
||||
pageInfo.pageSize = val
|
||||
await getList()
|
||||
}
|
||||
|
||||
//点击页码进行分页功能
|
||||
const handleCurrentChange = async (val) => {
|
||||
pageInfo.pageNum = val
|
||||
await getList()
|
||||
}
|
||||
//删除
|
||||
const handleDelete = async (id) => {
|
||||
delDataSourceManage(id).then(res => {
|
||||
if (res.code === 1000) {
|
||||
ElMessage.success(res.msg)
|
||||
getList()
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
//多删
|
||||
const handleMoreDelete = (sourceId, sourceName) => {
|
||||
ElMessageBox.confirm(`确认删除名称为${sourceName}的数据模型吗?`, '系统提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
handleDelete(sourceId)
|
||||
})
|
||||
}
|
||||
getTypeOption()
|
||||
getList()
|
||||
</script>
|
||||
<style scoped>
|
||||
.formatterUrl {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
@@ -1,233 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<EchartsEditor :info="initInfo" :line-data="lineChartsItem" :bar-data="barChartsItem" :pie-data="pieChartsItem"
|
||||
:radar-data="radarChartsItem" :radar-indicator="indicator" @getFinalInfo="getFinalInfo"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import EchartsEditor from "./components/EchartsEditor.vue";
|
||||
//入参
|
||||
const lineChartsItem = ref([
|
||||
{
|
||||
id: 1,
|
||||
unit: '年份',
|
||||
type: '',
|
||||
dataType: 'key',
|
||||
color: '',
|
||||
label: '年份',
|
||||
symbol: "",
|
||||
symbolSize: 0,
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
shadowColor: '',//阴影颜色
|
||||
shadowBlur: 0,//图形阴影的模糊大小
|
||||
opacity: 1
|
||||
},
|
||||
data: ['2013', '2014', '2015', '2016', '2017', '2018']
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
unit: '年销量',
|
||||
type: 'line',
|
||||
dataType: 'value',
|
||||
color: '#9a60b4',//图形颜色
|
||||
label: '华北',
|
||||
symbol: "triangle",//标记的图形circle:圆形,rect:矩形,triangle:三角形,diamond:钻石形,roundRect:圆角矩形,pin:圆钉形,arrow:箭头形,none:不显示标记
|
||||
symbolSize: 8,//标记的大小
|
||||
showSymbol: true,//是否显示标记,如果 false 则只有在 tooltip hover 的时候显示。
|
||||
lineStyle: {
|
||||
shadowColor: '',//阴影颜色
|
||||
shadowBlur: 0,//图形阴影的模糊大小
|
||||
opacity: 1//图形透明度
|
||||
},
|
||||
data: [40, 80, 20, 120, 140, 50]
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
unit: '年销量',
|
||||
type: 'line',
|
||||
dataType: 'value',
|
||||
color: '#3ba272',
|
||||
label: '华东',
|
||||
symbol: "circle",
|
||||
symbolSize: 8,
|
||||
showSymbol: true,
|
||||
lineStyle: {
|
||||
shadowColor: '',//阴影颜色
|
||||
shadowBlur: 0,//图形阴影的模糊大小
|
||||
opacity: 1
|
||||
},
|
||||
data: [140, 180, 120, 40, 50, 150]
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
unit: '年销量',
|
||||
type: 'line',
|
||||
dataType: 'value',
|
||||
color: '#5470c6',
|
||||
label: '华南',
|
||||
symbol: "rect",
|
||||
symbolSize: 8,
|
||||
showSymbol: true,
|
||||
lineStyle: {
|
||||
shadowColor: '',//阴影颜色
|
||||
shadowBlur: 0,//图形阴影的模糊大小
|
||||
opacity: 1
|
||||
},
|
||||
data: [110, 143, 68, 90, 120, 130]
|
||||
}
|
||||
])
|
||||
const barChartsItem = ref([
|
||||
{
|
||||
id: 1,
|
||||
unit: '年份',
|
||||
type: '',
|
||||
dataType: 'key',
|
||||
color: '',
|
||||
label: '年份',
|
||||
showBackground: false,
|
||||
backgroundStyle: {
|
||||
color: '',
|
||||
borderWidth: 0,
|
||||
borderColor: '',
|
||||
borderType: 'solid',
|
||||
},
|
||||
data: ['2013', '2014', '2015', '2016', '2017', '2018']
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
unit: '销售金额',
|
||||
type: 'bar',
|
||||
dataType: 'value',
|
||||
color: '#9a60b4',//图形颜色
|
||||
label: '王五',
|
||||
showBackground: true,//是否显示柱条的背景色
|
||||
backgroundStyle: {
|
||||
color: '#e5e2e2',//柱条的颜色
|
||||
borderWidth: 0,//柱条的描边宽度,默认不描边。
|
||||
borderColor: '#000',//柱条的描边颜色
|
||||
borderType: 'dotted',//柱条的描边类型,默认为实线,支持 'dashed', 'dotted'
|
||||
},
|
||||
data: [40, 80, 20, 120, 140, 50]
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
unit: '销售金额',
|
||||
type: 'bar',
|
||||
dataType: 'value',
|
||||
color: '#3ba272',
|
||||
label: '李四',
|
||||
showBackground: true,
|
||||
backgroundStyle: {
|
||||
color: '#e5e2e2',
|
||||
borderWidth: 0,
|
||||
borderColor: '#000',
|
||||
borderType: 'dashed',
|
||||
},
|
||||
data: [140, 180, 120, 40, 50, 150]
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
unit: '销售金额',
|
||||
type: 'bar',
|
||||
dataType: 'value',
|
||||
color: '#2644a4',
|
||||
label: '张三',
|
||||
showBackground: true,
|
||||
backgroundStyle: {
|
||||
color: '#e5e2e2',
|
||||
borderWidth: 0,
|
||||
borderColor: '#000',
|
||||
borderType: 'solid',
|
||||
},
|
||||
data: [110, 143, 68, 90, 120, 130]
|
||||
}
|
||||
])
|
||||
const pieChartsItem = ref([
|
||||
{id: 1, label: '京东', dataType: 'value', value: 335},
|
||||
{id: 2, label: '菜鸟', dataType: 'value', value: 310},
|
||||
{id: 3, label: '总部', dataType: 'value', value: 234},
|
||||
{id: 4, label: '小电商', dataType: 'value', value: 135},
|
||||
])
|
||||
const radarChartsItem = ref([
|
||||
{label: 'Allocated Budget', dataType: 'value', data: [4200, 3000, 20000, 35000, 50000, 18000]},
|
||||
{label: 'Actual Spending', dataType: 'value', data: [5000, 14000, 28000, 26000, 42000, 21000]},
|
||||
])
|
||||
//定义好echarts的配置数据
|
||||
let initInfo = reactive({
|
||||
xValueAxis: [],
|
||||
yValueAxis: [],
|
||||
//echarts配置数据
|
||||
echartsOptions: {
|
||||
//图例
|
||||
legend: {
|
||||
data: [],
|
||||
selected: {},
|
||||
selectedMode: false
|
||||
},
|
||||
//离容器四侧的距离
|
||||
grid: {
|
||||
left: 40, // 左边距
|
||||
right: 60, // 右边距
|
||||
top: 40, // 顶边距
|
||||
bottom: 20, // 底边距
|
||||
// containLabel: true,
|
||||
},
|
||||
//提示框组件
|
||||
tooltip: {
|
||||
show: true,
|
||||
trigger: 'axis'
|
||||
},
|
||||
//工具栏
|
||||
// toolbox: {
|
||||
// feature: {
|
||||
// //重置按钮显示
|
||||
// restore: {
|
||||
// show: true,
|
||||
// title: '重置'
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
//X轴
|
||||
xAxis: {
|
||||
name: '',
|
||||
type: 'category',
|
||||
data: [],
|
||||
axisLine: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
//Y轴
|
||||
yAxis: {
|
||||
name: '',
|
||||
type: 'value',
|
||||
data: [],
|
||||
axisLine: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
radar: {
|
||||
// shape: 'circle',
|
||||
},
|
||||
//配置项
|
||||
series: []
|
||||
}
|
||||
})
|
||||
const indicator= ref([
|
||||
{ name: 'Sales', max: 6500 },
|
||||
{ name: 'Administration', max: 16000 },
|
||||
{ name: 'Information Technology', max: 30000 },
|
||||
{ name: 'Customer Support', max: 38000 },
|
||||
{ name: 'Development', max: 52000 },
|
||||
{ name: 'Marketing', max: 25000 }
|
||||
])
|
||||
//获取到拖拽后的数据
|
||||
const getFinalInfo = (val) => {
|
||||
// console.log('父组件获取最终数据', val)
|
||||
if (val !== undefined) {
|
||||
initInfo = val
|
||||
}
|
||||
}
|
||||
getFinalInfo()
|
||||
</script>
|
||||
@@ -1,538 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="box-card box-card-h">
|
||||
<el-row justify="space-between" class="x-y-axis">
|
||||
<el-text>值轴/{{ boxName }}</el-text>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="boxName+',数据类型必须一致!'"
|
||||
placement="bottom"
|
||||
>
|
||||
<el-icon>
|
||||
<Warning/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-row>
|
||||
<div class="drag-block">
|
||||
<draggable
|
||||
class="list-group"
|
||||
:list="dragList"
|
||||
itemKey="id"
|
||||
:group="group"
|
||||
@start="startDrag"
|
||||
@change="dragChartItem"
|
||||
>
|
||||
<template #item="{ element,index }">
|
||||
<div :id="element.dataType==='value'?'card_'+index:''" tabindex="1"
|
||||
@click.stop="handleClickValueCard(element,index)">
|
||||
<el-card shadow="hover" class="cards x-y-cards"
|
||||
:style="{borderWidth:1,borderColor:element.dataType==='value'?element.color:'#e4e7ed'}">
|
||||
<el-col :span="3">
|
||||
<div>{{ element.label }}</div>
|
||||
</el-col>
|
||||
<el-col :span="13">
|
||||
<div v-if="element.dataType==='value'" class="update-color">
|
||||
<div class="update-color" @click.stop>
|
||||
<span>图形:</span>
|
||||
<el-color-picker v-model="element.color" :color="element.color"
|
||||
@change="changeEchartsColor($event,index)" @active-change="handleActiveChange"/>
|
||||
</div>
|
||||
<div v-if="currentChart==='line'" class="update-color" @click.stop>
|
||||
<span>阴影:</span>
|
||||
<el-color-picker v-model="element.lineStyle.shadowColor" :color="element.lineStyle.shadowColor"
|
||||
@change="changeShadowColor($event,index)" @active-change="handleActiveChange"/>
|
||||
</div>
|
||||
<div v-if="currentChart==='bar'" class="update-color" @click.stop>
|
||||
<span>背景: </span>
|
||||
<el-color-picker v-model="element.backgroundStyle.color" :color="element.backgroundStyle.color"
|
||||
@change="changeBackgroundColor($event,index)" @active-change="handleActiveChange"/>
|
||||
</div>
|
||||
<div v-if="currentChart==='bar'" class="update-color" @click.stop>
|
||||
<span >描边: </span>
|
||||
<el-color-picker v-model="element.backgroundStyle.borderColor" :color="element.backgroundStyle.borderColor"
|
||||
@change="changeBackgroundBorderColor($event,index)" @active-change="handleActiveChange"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="cards-right">
|
||||
<span>{{ element.dataType }}</span>
|
||||
<el-icon size="20" color="red" @click.stop="handleCancelAxis(element,index)"
|
||||
style="cursor: pointer">
|
||||
<CircleClose/>
|
||||
</el-icon>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
const emit = defineEmits(["editBasicSettingList"])
|
||||
const props = defineProps({
|
||||
//box名字
|
||||
boxName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
//可供拖动的选项列表
|
||||
dragOptions: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
//用于拖拽区域存放选项列表
|
||||
dragList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
//用于X轴区域存放拖动的选项
|
||||
xAxisList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
//用于Y轴区域存放拖动的选项
|
||||
yAxisList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
//标记正在拖动选项的数据类型是否value
|
||||
flag: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//获取正在拖动选项的数据类型
|
||||
startDataType: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
//初始化加载echarts函数
|
||||
initCharts: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
//echarts的配置属性
|
||||
chartOption: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
//当前echarts图形
|
||||
currentChart: {
|
||||
type: String,
|
||||
default: 'line'
|
||||
}
|
||||
})
|
||||
//基础设置列表
|
||||
const lineChartBasicSettingList = ref()
|
||||
const barChartBasicSettingList = ref()
|
||||
//选中类型为value的item所处的list列表
|
||||
const valueCardInList = ref([])
|
||||
//简化代码
|
||||
let xList = reactive(props.xAxisList)
|
||||
let yList = reactive(props.yAxisList)
|
||||
let option = reactive(props.chartOption)
|
||||
//路由刷新
|
||||
const reload = inject("reload")
|
||||
//自定义X/Y分组的拖入拖出事件
|
||||
const group = ref({
|
||||
name: 'people',
|
||||
pull: true,
|
||||
put: props.flag === true ? false : (props.boxName === 'X轴' ? () => handleGroupPut(xList, yList) : () => handleGroupPut(yList, xList))
|
||||
})
|
||||
//将改变的数据传到父组件
|
||||
watch(() => lineChartBasicSettingList.value, (newVal) => {
|
||||
emit("getLineChartBasicSettingList", newVal)
|
||||
})
|
||||
//将改变的数据传到父组件
|
||||
watch(() => barChartBasicSettingList.value, (newVal) => {
|
||||
emit("getBarChartBasicSettingList", newVal)
|
||||
})
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', nullBlockClick)
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', nullBlockClick)
|
||||
})
|
||||
/**
|
||||
* 设置chart的lineStyle
|
||||
* @param sItem chartItem
|
||||
* @param opacity 透明度
|
||||
*/
|
||||
const handleChangeLineStyle = (sItem, opacity) => {
|
||||
sItem.lineStyle = {
|
||||
shadowColor: sItem.lineStyle.shadowColor,
|
||||
shadowBlur: sItem.lineStyle.shadowBlur,
|
||||
opacity: opacity
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 用于取消charts选中透明度
|
||||
*/
|
||||
const handleChangeOpacity = (type, item) => {
|
||||
if (props.currentChart === 'line') {
|
||||
option.series.forEach((sItem) => {
|
||||
if (type === 'more') {
|
||||
if (sItem.name === item.label) {
|
||||
handleChangeLineStyle(sItem, 1)
|
||||
} else {
|
||||
handleChangeLineStyle(sItem, 0.2)
|
||||
}
|
||||
} else if (type === 'single') {
|
||||
handleChangeLineStyle(sItem, 1)
|
||||
} else {
|
||||
if (sItem.name !== item.label) {
|
||||
handleChangeLineStyle(sItem, 1)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 点击空白处, 清除选项选中状态
|
||||
*/
|
||||
const nullBlockClick = () => {
|
||||
if (valueCardInList.value.length === 0) return;
|
||||
valueCardInList.value.forEach((aItem, aIndex) => {
|
||||
const card = document.getElementById('card_' + aIndex)
|
||||
card.classList.remove('card-active')
|
||||
})
|
||||
clearBasicSetting()
|
||||
//加载echarts
|
||||
props.initCharts()
|
||||
}
|
||||
/**
|
||||
* 封装自定义X/Y分组的拖入事件
|
||||
* @param aType 传入x/y区域数组
|
||||
* @param bType 传入x/y区域数组
|
||||
* @returns {boolean} 返回 true/false
|
||||
*/
|
||||
const handleGroupPut = (aType, bType) => {
|
||||
let flag = false
|
||||
let aLen = aType.length
|
||||
let bLen = bType.length
|
||||
if (aLen === 0 && bLen === 0) {
|
||||
flag = props.startDataType === 'key';
|
||||
} else if (aLen === 0 && bLen !== 0) {
|
||||
flag = bType[0].dataType === 'key';
|
||||
} else if (aLen !== 0 && bLen !== 0) {
|
||||
const dragType = localStorage.getItem('dragType')
|
||||
flag = props.startDataType === aType[0].dataType;
|
||||
if (dragType === 'key') {
|
||||
flag = aType[0].dataType !== 'value';
|
||||
}
|
||||
}
|
||||
return flag
|
||||
}
|
||||
/**
|
||||
* 封装切换坐标轴数据类型为Category
|
||||
* @param item 拖动的项
|
||||
* @param label 坐标轴名称
|
||||
* @param type 切换x/y轴
|
||||
*/
|
||||
const changeTypeToCategory = (item, label, type) => {
|
||||
let axis
|
||||
if (type === 'xAxis') {
|
||||
axis = option.xAxis
|
||||
} else {
|
||||
axis = option.yAxis
|
||||
}
|
||||
axis.type = 'category'
|
||||
axis.name = label
|
||||
axis.data = item.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装清除坐标轴数据
|
||||
* @param type 标志清除x/y轴
|
||||
*/
|
||||
const clearAxisData = (type) => {
|
||||
let axis
|
||||
if (type === 'xAxis') {
|
||||
axis = option.xAxis
|
||||
} else {
|
||||
axis = option.yAxis
|
||||
}
|
||||
axis.name = ''
|
||||
axis.data = []
|
||||
}
|
||||
/**
|
||||
* 封装key拖入左侧时的重置事件
|
||||
* @param aList x/yList
|
||||
* @param type x/yAxis
|
||||
* @param item 选项item
|
||||
* @param label 选项名
|
||||
*/
|
||||
const restoreChart = (aList, type,item,label) => {
|
||||
let axis
|
||||
if (type === 'xAxis') {
|
||||
axis = option.xAxis
|
||||
} else {
|
||||
axis = option.yAxis
|
||||
}
|
||||
if (aList[0].dataType === 'value') {
|
||||
aList.map((item) => {
|
||||
props.dragOptions.unshift(item)
|
||||
option.legend.selected[item.label] = false
|
||||
})
|
||||
aList.splice(0, aList.length)
|
||||
option.legend.data.splice(0, option.legend.data.length)
|
||||
option.series.splice(0, option.series.length)
|
||||
axis.name = ''
|
||||
option.xAxis.type = 'category'
|
||||
option.yAxis.type = 'value'
|
||||
} else {
|
||||
changeTypeToCategory(item, label, type)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拖拽类型为key的选项事件
|
||||
* @param item 选项item
|
||||
* @param label 选项名
|
||||
*/
|
||||
const dragTypeToKey = (item, label) => {
|
||||
if (xList.length !== 0 && yList.length === 0) {
|
||||
restoreChart(xList, 'xAxis',item,label)
|
||||
clearAxisData('yAxis')
|
||||
} else if (xList.length === 0 && yList.length !== 0) {
|
||||
restoreChart(yList, 'yAxis',item,label)
|
||||
clearAxisData('xAxis')
|
||||
} else if (xList.length === 0 && yList.length === 0) {
|
||||
//移入左侧待选列表
|
||||
clearAxisData('xAxis')
|
||||
clearAxisData('yAxis')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 拖拽类型为value的选项事件
|
||||
* @param label 选项名
|
||||
*/
|
||||
const dragTypeToValue = (label) => {
|
||||
//删除选中选项的图例
|
||||
const legendIndex = option.legend.data.findIndex(object => object === label);
|
||||
option.legend.data.splice(legendIndex, 1)
|
||||
//删除echarts配置项series中符合该拖拽选项的item
|
||||
const objectIndex = option.series.findIndex(object => object.name === label);
|
||||
option.legend.selected[label] = false
|
||||
option.series.splice(objectIndex, 1)
|
||||
if (xList.length === 0) {
|
||||
option.xAxis.name = ''
|
||||
} else if (yList.length === 0) {
|
||||
option.yAxis.name = ''
|
||||
}
|
||||
clearBasicSetting()
|
||||
handleDeleteClassName(xList, yList)
|
||||
}
|
||||
/**
|
||||
* 封装清空基本设置
|
||||
*/
|
||||
const clearBasicSetting=()=>{
|
||||
if(props.currentChart==='line'){
|
||||
lineChartBasicSettingList.value = []
|
||||
handleChangeOpacity('single')
|
||||
}else if(props.currentChart==='bar'){
|
||||
barChartBasicSettingList.value=[]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始拖拽事件
|
||||
* @param event event事件
|
||||
*/
|
||||
const startDrag = (event) => {
|
||||
localStorage.setItem('dragType', event.item._underlying_vm_.dataType)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从X轴/Y轴区域移动选项到左/右侧结束事件
|
||||
* @param event event事件
|
||||
*/
|
||||
const dragChartItem = (event) => {
|
||||
if (event.removed === undefined) return;
|
||||
let item = event.removed.element
|
||||
let label = item.label
|
||||
//拖动key的选项
|
||||
if (item.dataType === "key") {
|
||||
dragTypeToKey(item, label)
|
||||
} else {
|
||||
dragTypeToValue(label)
|
||||
}
|
||||
props.initCharts()
|
||||
localStorage.removeItem('dragType')
|
||||
}
|
||||
|
||||
/**
|
||||
* 选中数据类型为value的点击事件
|
||||
* @param item 点击的选项item
|
||||
* @param index 点击选项的下标
|
||||
*/
|
||||
const handleClickValueCard = (item, index) => {
|
||||
document.addEventListener('click', nullBlockClick)
|
||||
if (item.dataType === 'value' ) {
|
||||
if(props.currentChart === 'line'){
|
||||
changeCardActive(props.dragList, item)
|
||||
lineChartBasicSettingList.value = [item]
|
||||
}else if(props.currentChart === 'bar'){
|
||||
changeCardActive(props.dragList, item)
|
||||
barChartBasicSettingList.value = [item]
|
||||
}
|
||||
}
|
||||
props.initCharts()
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装选中类型为value的数据高亮
|
||||
* @param list x/y区域list
|
||||
* @param item 点击选项的item
|
||||
*/
|
||||
const changeCardActive = (list, item) => {
|
||||
valueCardInList.value = list
|
||||
emit('getCardActiveList',list)
|
||||
if (list.length !== 0 && list[0].dataType === 'value') {
|
||||
handleChangeOpacity('more', item)
|
||||
list.forEach((aItem, aIndex) => {
|
||||
const card = document.getElementById('card_' + aIndex)
|
||||
if (aItem.label === item.label) {
|
||||
card.classList.add('card-active')
|
||||
} else {
|
||||
card.classList.remove('card-active')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础设置: 修改echarts数据颜色
|
||||
* @param val 修改的标记大小
|
||||
* @param index 修改的chart项下标
|
||||
*/
|
||||
const changeEchartsColor = (val, index) => {
|
||||
document.addEventListener('click', nullBlockClick)
|
||||
option.series[index].color = val
|
||||
props.initCharts()
|
||||
}
|
||||
/**
|
||||
* 当选择颜色时移除空白点击事件
|
||||
*/
|
||||
const handleActiveChange = () => {
|
||||
document.removeEventListener('click', nullBlockClick)
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础设置: 修改echarts数据颜色
|
||||
* @param val 修改的标记大小
|
||||
* @param index 修改的chart项下标
|
||||
*/
|
||||
const changeShadowColor = (val, index) => {
|
||||
option.series[index].lineStyle.shadowColor = val
|
||||
props.initCharts()
|
||||
}
|
||||
/**
|
||||
* 基础设置:修改柱条背景颜色
|
||||
* @param val 柱条颜色
|
||||
* @param index 修改的chart项下标
|
||||
*/
|
||||
const changeBackgroundColor = (val, index) => {
|
||||
option.series[index].backgroundStyle.color = val
|
||||
props.initCharts()
|
||||
}
|
||||
/**
|
||||
* 基础设置:修改柱条描边颜色
|
||||
* @param val 柱条描边颜色
|
||||
* @param index 修改的chart项下标
|
||||
*/
|
||||
const changeBackgroundBorderColor = (val, index) => {
|
||||
option.series[index].backgroundStyle.borderColor = val
|
||||
props.initCharts()
|
||||
}
|
||||
/**
|
||||
* 封装从右侧区域拖出事件
|
||||
* @param element 获取点击该拖出的选项事件
|
||||
* @param index 点击该拖出选项的索引
|
||||
* @param aList x/y区域的值
|
||||
* @param bList x/y区域的值
|
||||
* @param aAxis echarts配置项的x/y轴
|
||||
* @param bAxis echarts配置项的x/y轴
|
||||
*/
|
||||
const handleCancel = (element, index, aList, bList, aAxis, bAxis) => {
|
||||
aList.splice(index, 1)
|
||||
props.dragOptions.push(element)
|
||||
if (element.dataType === "key") {
|
||||
aAxis.name = ''
|
||||
aAxis.data = []
|
||||
bAxis.name=''
|
||||
bList.map((item) => {
|
||||
props.dragOptions.unshift(item)
|
||||
option.legend.selected[item.label] = false
|
||||
})
|
||||
bList.splice(0, bList.length)
|
||||
option.legend.data.splice(0, option.legend.data.length)
|
||||
option.series.splice(0, option.series.length)
|
||||
// reload
|
||||
props.initCharts()
|
||||
} else {
|
||||
if (bList.length !== 0 && aList.length === 0) {
|
||||
if (bList[0].dataType === 'key') {
|
||||
aAxis.name = ''
|
||||
} else {
|
||||
bAxis.name = ''
|
||||
}
|
||||
}
|
||||
|
||||
option.legend.data.splice(index, 1)
|
||||
const objectIndex = option.series.findIndex(object => object.name === element.label);
|
||||
option.legend.selected[element.label] = false
|
||||
option.series.splice(objectIndex, 1)
|
||||
props.initCharts()
|
||||
}
|
||||
if(props.currentChart==='line'){
|
||||
handleChangeOpacity('not', element)
|
||||
if (lineChartBasicSettingList.value === undefined) return;
|
||||
lineChartBasicSettingList.value.splice(0, 1)
|
||||
}else if(props.currentChart==='bar'){
|
||||
if (barChartBasicSettingList.value === undefined) return;
|
||||
barChartBasicSettingList.value.splice(0, 1)
|
||||
}
|
||||
// const basicIndex = lineChartBasicSettingList.value.findIndex(object => object.label === element.label)
|
||||
// if (basicIndex !== -1) {
|
||||
// lineChartBasicSettingList.value.splice(basicIndex, 1)
|
||||
// }
|
||||
handleDeleteClassName(aList, bList)
|
||||
props.initCharts()
|
||||
}
|
||||
/**
|
||||
* 拖拽选项后,清除选中选项阴影
|
||||
* @param aList x/y list
|
||||
* @param bList x/y list
|
||||
*/
|
||||
const handleDeleteClassName = (aList, bList) => {
|
||||
let axis = []
|
||||
if (aList.length !== 0 && aList[0].dataType === 'value') {
|
||||
axis = aList
|
||||
} else if (bList.length !== 0 && bList[0].dataType === 'value') {
|
||||
axis = bList
|
||||
}
|
||||
axis.forEach((aItem, aIndex) => {
|
||||
const card = document.getElementById('card_' + aIndex)
|
||||
card.classList.remove('card-active')
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 从右侧x/y轴区域取消选项
|
||||
* @param element 该取消的项
|
||||
* @param index 该取消项的下标
|
||||
*/
|
||||
const handleCancelAxis = (element, index) => {
|
||||
if (props.boxName === 'X轴') {
|
||||
handleCancel(element, index, xList, yList, option.xAxis, option.yAxis)
|
||||
} else {
|
||||
handleCancel(element, index, yList, xList, option.yAxis, option.xAxis)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,307 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="box-card">
|
||||
<div class="drag-block">
|
||||
<draggable
|
||||
class="list-group"
|
||||
:list="dragOptions"
|
||||
itemKey="id"
|
||||
group="people"
|
||||
@start="startDrag"
|
||||
@change="changeChartItem"
|
||||
>
|
||||
<template #item="{element}">
|
||||
<el-card shadow="hover" class="cards">
|
||||
<el-row justify="space-between">
|
||||
<span>{{ element.label }}</span>
|
||||
<span>{{ element.dataType }}</span>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</template>
|
||||
</draggable>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import draggable from 'vuedraggable'
|
||||
import {ElMessage} from "element-plus";
|
||||
|
||||
const emit = defineEmits(["editValueFlag", "editStartDataType"])
|
||||
const props = defineProps({
|
||||
//可供拖动的选项列表
|
||||
dragOptions: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
//echarts的配置属性
|
||||
chartOption: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
//初始化加载echarts函数
|
||||
initCharts: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
//用于X轴区域存放拖动的选项
|
||||
xAxisList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
//用于Y轴区域存放拖动的选项
|
||||
yAxisList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
//当前echarts图形
|
||||
currentChart: {
|
||||
type: String,
|
||||
default: 'line'
|
||||
},
|
||||
//雷达图指示器
|
||||
radarIndicator: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
})
|
||||
//简化代码
|
||||
let xList = reactive(props.xAxisList)
|
||||
let yList = reactive(props.yAxisList)
|
||||
let option = reactive(props.chartOption)
|
||||
let chart = reactive(props.currentChart)
|
||||
//获取正在拖动选项的数据类型
|
||||
const startDragType = ref()
|
||||
//标记正在拖动选项的数据类型是否value
|
||||
const flag = ref(false)
|
||||
//将改变的数据传到父组件
|
||||
watch(() => flag.value, (newVal) => {
|
||||
emit("editValueFlag", newVal)
|
||||
})
|
||||
watch(() => props.currentChart, (newVal) => {
|
||||
chart = newVal
|
||||
})
|
||||
watch(() => startDragType.value, (newVal) => {
|
||||
emit("editStartDataType", newVal)
|
||||
})
|
||||
|
||||
/**
|
||||
* 设置修改后的echarts属性
|
||||
* @param item 拖动的项
|
||||
* @param label 拖拽选项的名称
|
||||
* @returns Object
|
||||
*/
|
||||
const settingChartItem = (item, label) => {
|
||||
if (chart === 'line') {
|
||||
return {
|
||||
id: item.id,//组件 ID
|
||||
name: label,
|
||||
// type: echartsValue.value ? echartsValue.value : item.type,
|
||||
type: chart,
|
||||
data: item.data,
|
||||
smooth: true,
|
||||
color: item.color,
|
||||
symbol: item.symbol,
|
||||
symbolSize: item.symbolSize,
|
||||
showSymbol: item.showSymbol,
|
||||
lineStyle: item.lineStyle,
|
||||
// emphasis: item.emphasis
|
||||
}
|
||||
} else if (chart === 'bar') {
|
||||
return {
|
||||
id: item.id,
|
||||
name: label,
|
||||
type: chart,
|
||||
data: item.data,
|
||||
color: item.color,
|
||||
showBackground: item.showBackground,
|
||||
backgroundStyle: item.backgroundStyle
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 封拖拽数据类型为value
|
||||
* @param item 拖动的项
|
||||
* @param label 拖拽选项的名称
|
||||
* @param selectedObj 图例选中状态表
|
||||
*/
|
||||
const dragValue = (item, label, selectedObj) => {
|
||||
dragChart(item, label, 2)
|
||||
option.legend.data.push(label)
|
||||
let chartItem = settingChartItem(item, label)
|
||||
option.series.push(chartItem)
|
||||
for (const propertyName in selectedObj) {
|
||||
if (propertyName === label) {
|
||||
selectedObj[propertyName] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 封装切换坐标轴数据类型为Category
|
||||
* @param item 拖动的项
|
||||
* @param label 坐标轴名称
|
||||
* @param type 切换x/y轴
|
||||
*/
|
||||
const changeTypeToCategory = (item, label, type) => {
|
||||
let axis
|
||||
if (type === 'xAxis') {
|
||||
axis = option.xAxis
|
||||
} else {
|
||||
axis = option.yAxis
|
||||
}
|
||||
axis.type = 'category'
|
||||
axis.name = item.unit
|
||||
axis.data = item.data
|
||||
}
|
||||
/**
|
||||
* 封装切换坐标轴数据类型为Value
|
||||
* @param item 拖动的项item
|
||||
* @param type 切换x/y轴
|
||||
*/
|
||||
const changeTypeToValue = (item, type) => {
|
||||
let axis
|
||||
if (type === 'xAxis') {
|
||||
axis = option.xAxis
|
||||
} else {
|
||||
axis = option.yAxis
|
||||
}
|
||||
axis.type = 'value'
|
||||
axis.name = item.unit
|
||||
}
|
||||
/**
|
||||
* 封装拖拽选项修改echarts属性
|
||||
* @param item 拖动的项
|
||||
* @param label 拖拽选项的名称
|
||||
* @param index 区分拖的选项数据:1是key,2是value
|
||||
*/
|
||||
const dragChart = (item, label, index) => {
|
||||
if (xList.length !== 0 && yList.length === 0) {
|
||||
// console.log('x轴有值')
|
||||
if (index === 1) {
|
||||
changeTypeToCategory(item, label, 'xAxis')
|
||||
} else {
|
||||
changeTypeToValue(item, 'xAxis')
|
||||
option.yAxis.type = 'category'
|
||||
}
|
||||
} else if (xList.length !== 0 && yList.length !== 0) {
|
||||
// console.log('xy有值')
|
||||
if (xList[0].dataType === 'value') {
|
||||
if (index === 1) {
|
||||
changeTypeToCategory(item, label)
|
||||
}
|
||||
changeTypeToValue(item, 'xAxis')
|
||||
} else if (yList[0].dataType === 'value') {
|
||||
if (index === 1) {
|
||||
changeTypeToCategory(item, label, 'xAxis')
|
||||
}
|
||||
changeTypeToValue(item)
|
||||
}
|
||||
} else if (xList.length === 0 && yList.length !== 0) {
|
||||
// console.log('y轴有值')
|
||||
if (index === 1) {
|
||||
changeTypeToCategory(item, label, 'yAxis')
|
||||
} else {
|
||||
option.xAxis.type = 'category'
|
||||
changeTypeToValue(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 从左侧区域移动选项到右侧
|
||||
* @param event 拖拽成功event事件
|
||||
*/
|
||||
const changeChartItem = (event) => {
|
||||
if (event.removed === undefined) return;
|
||||
let item = event.removed.element
|
||||
if (chart === 'line'||chart === 'bar') {
|
||||
let label = item.label
|
||||
let selectedObj = option.legend.selected
|
||||
if (item.dataType === "key") {
|
||||
dragChart(item, label, 1)
|
||||
} else {
|
||||
if (flag.value) return;
|
||||
dragValue(item, label, selectedObj)
|
||||
}
|
||||
} else if (chart === 'pie') {
|
||||
let arr = []
|
||||
xList.forEach(item => {
|
||||
let obj = {
|
||||
name: item.label,
|
||||
value: item.value
|
||||
}
|
||||
arr.push(obj)
|
||||
})
|
||||
for (const propertyName in option.legend.selected) {
|
||||
if (propertyName === item.label) {
|
||||
option.legend.selected[propertyName] = true
|
||||
}
|
||||
}
|
||||
if (item.dataType !== "key") {
|
||||
option.legend.data.push(item.label)
|
||||
}
|
||||
option.series = [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
data: arr
|
||||
}
|
||||
]
|
||||
} else if (chart === 'radar') {
|
||||
let arr = []
|
||||
xList.forEach(item => {
|
||||
let obj = {
|
||||
name: item.label,
|
||||
value: item.data
|
||||
}
|
||||
arr.push(obj)
|
||||
})
|
||||
console.log('arr',arr)
|
||||
for (const propertyName in option.legend.selected) {
|
||||
if (propertyName === item.label) {
|
||||
option.legend.selected[propertyName] = true
|
||||
}
|
||||
}
|
||||
if (item.dataType !== "key") {
|
||||
option.legend.data.push(item.label)
|
||||
}
|
||||
option.radar={
|
||||
indicator:props.radarIndicator
|
||||
}
|
||||
option.series = [
|
||||
{
|
||||
type: 'radar',
|
||||
data: arr
|
||||
}
|
||||
]
|
||||
}
|
||||
props.initCharts()
|
||||
}
|
||||
|
||||
/**
|
||||
* 左侧区域开始拖拽事件
|
||||
* @param event 开始拖拽的event事件
|
||||
*/
|
||||
const startDrag = (event) => {
|
||||
startDragType.value = event.item._underlying_vm_.dataType
|
||||
if (xList.length === 0 && yList.length === 0) {
|
||||
if (chart === 'line' || chart === 'bar') {
|
||||
if (startDragType.value === "value") {
|
||||
flag.value = true
|
||||
ElMessage({
|
||||
message: '请先拖动数据类型为key的选项到x轴/y轴.',
|
||||
type: 'warning',
|
||||
})
|
||||
} else {
|
||||
flag.value = false
|
||||
}
|
||||
} else if (chart === 'pie') {
|
||||
console.log('拖动饼图')
|
||||
flag.value = false
|
||||
}else if (chart === 'radar') {
|
||||
console.log('拖动雷达')
|
||||
flag.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,307 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="6">
|
||||
<el-col :span="6">
|
||||
<el-select v-model="echartsValue" filterable placeholder="请选择图形状" style="width: 100%" size="large"
|
||||
@change="handleChangeEcharts">
|
||||
<el-option v-for="chartItem in chartType"
|
||||
:key="chartItem.value"
|
||||
:label="chartItem.label"
|
||||
:value="chartItem.value"/>
|
||||
</el-select>
|
||||
<!--左侧选项区域-->
|
||||
<charts-options @editValueFlag="editValueFlag" @editStartDataType="editStartDataType"
|
||||
:drag-options="ChartsItem" :chart-option="option" :init-charts="initChart"
|
||||
:x-axis-list="xValueAxis" :y-axis-list="yValueAxis"
|
||||
:current-chart="echartsValue" :radar-indicator="radarIndicator"/>
|
||||
</el-col>
|
||||
<!--X轴区域-->
|
||||
<el-col :span="9" v-if="echartsValue==='bar'||echartsValue==='line'">
|
||||
<axis-box :box-name="'X轴'" :drag-list="xValueAxis" :drag-options="ChartsItem" :x-axis-list="xValueAxis"
|
||||
:y-axis-list="yValueAxis" :flag="valueFlag"
|
||||
:start-data-type="startDataType" :chart-option="option" :init-charts="initChart"
|
||||
@getLineChartBasicSettingList="getLineChartBasicSettingList"
|
||||
@getBarChartBasicSettingList="getBarChartBasicSettingList" :current-chart="echartsValue"/>
|
||||
</el-col>
|
||||
<!--Y轴区域-->
|
||||
<el-col :span="9" v-if="echartsValue==='bar'||echartsValue==='line'">
|
||||
<axis-box :box-name="'Y轴'" :drag-list="yValueAxis" :drag-options="ChartsItem" :x-axis-list="xValueAxis"
|
||||
:y-axis-list="yValueAxis" :flag="valueFlag"
|
||||
:start-data-type="startDataType" :chart-option="option" :init-charts="initChart"
|
||||
@getLineChartBasicSettingList="getLineChartBasicSettingList"
|
||||
@getBarChartBasicSettingList="getBarChartBasicSettingList" :current-chart="echartsValue"/>
|
||||
</el-col>
|
||||
<el-col :span="9" v-if="echartsValue==='pie'">
|
||||
<pie-box :drag-list="xValueAxis" :init-charts="initChart" :chart-option="option"/>
|
||||
</el-col>
|
||||
<el-col :span="9" v-if="echartsValue==='radar'">
|
||||
<radar-box :drag-list="xValueAxis" :init-charts="initChart" :chart-option="option"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-button @click.stop="saveData">保存</el-button>
|
||||
<el-button v-if="echartsValue==='line'" @click.stop="openAdvancedSettings">高级设置</el-button>
|
||||
<el-row :gutter="6">
|
||||
<el-col :span="16">
|
||||
<div id="container" ref="chart" @click.stop></div>
|
||||
</el-col>
|
||||
<!--基础设置-->
|
||||
<el-col :span="8">
|
||||
<!-- 折线图基础设置-->
|
||||
<line-chart-basic-setting v-if="echartsValue==='line'" :basic-list="lineChartBasicSettingList"
|
||||
:init-charts="initChart"
|
||||
:chart-option="option"/>
|
||||
<!-- 柱状图基础设置-->
|
||||
<bar-chart-basic-setting v-if="echartsValue==='bar'" :basic-list="barChartBasicSettingList"
|
||||
:init-charts="initChart"
|
||||
:chart-option="option"/>
|
||||
<!-- 饼图基础设置-->
|
||||
<!-- <pie-chart-basic-setting v-if="echartsValue==='pie'"/>-->
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!--高级设置-->
|
||||
<!-- 折线图高级设置-->
|
||||
<line-chart-advanced-settings v-if="echartsValue==='line'" ref="advancedSettings" :init-charts="initChart"
|
||||
:chart-option="option"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as echarts from 'echarts'
|
||||
import draggable from 'vuedraggable'
|
||||
import ChartsOptions from "./ChartsOptions.vue";
|
||||
import AxisBox from "./AxisBox.vue";
|
||||
import LineChartBasicSetting from "./lineChart/BasicSetting.vue";
|
||||
import LineChartAdvancedSettings from "./lineChart/AdvancedSettings.vue";
|
||||
import BarChartBasicSetting from "./barChart/BasicSetting.vue";
|
||||
// import PieChartBasicSetting from "./pieChart/BasicSetting.vue";
|
||||
import PieBox from "./pieChart/PieBox.vue";
|
||||
import RadarBox from "./radarChart/RadarBox.vue";
|
||||
// import BarChartAdvancedSettings from "./barChart/AdvancedSettings.vue";
|
||||
|
||||
const emit = defineEmits(["getFinalInfo"])
|
||||
const props = defineProps({
|
||||
info: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
lineData: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
barData: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
pieData: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
radarData: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
radarIndicator: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
})
|
||||
//图形: 1:折线图 2.柱状图 3.饼图
|
||||
const chartType = reactive([
|
||||
{
|
||||
value: 'line',
|
||||
label: '折线图',
|
||||
},
|
||||
{
|
||||
value: 'bar',
|
||||
label: '柱状图',
|
||||
},
|
||||
{
|
||||
value: 'pie',
|
||||
label: '饼图',
|
||||
},
|
||||
{
|
||||
value: 'radar',
|
||||
label: '雷达图',
|
||||
}
|
||||
])
|
||||
//基础设置列表
|
||||
const lineChartBasicSettingList = ref([])
|
||||
const barChartBasicSettingList = ref([])
|
||||
const advancedSettings = ref()
|
||||
//获取父组件传来的初始数据
|
||||
const initInfo = reactive(props.info)
|
||||
//从左侧获取拖动的选项的数据类型
|
||||
const startDataType = ref()
|
||||
//标记从左侧拖动选项数据类型是否是value
|
||||
const valueFlag = ref(false)
|
||||
//简化代码
|
||||
let xValueAxis = reactive(initInfo.xValueAxis)
|
||||
let yValueAxis = reactive(initInfo.yValueAxis)
|
||||
const line_data = reactive(props.lineData)
|
||||
const bar_data = reactive(props.barData)
|
||||
const pie_data = reactive(props.pieData)
|
||||
const radar_data = reactive(props.radarData)
|
||||
let option = reactive(initInfo.echartsOptions)
|
||||
|
||||
//页面左上角select选择框绑定数据
|
||||
const echartsValue = ref('line')
|
||||
//可供拖动的选项列表
|
||||
const ChartsItem = ref([])
|
||||
//获取到container容器实例
|
||||
const chart = ref(null);
|
||||
//定义echarts实例
|
||||
let myEcharts = reactive({});
|
||||
onMounted(() => {
|
||||
if (ChartsItem.value.length === 0) {
|
||||
ChartsItem.value = line_data
|
||||
}
|
||||
//初始化echarts(不显示图)
|
||||
let selectLegend = {}
|
||||
ChartsItem.value.forEach(item => {
|
||||
if (item.dataType !== 'key') {
|
||||
selectLegend[item.label] = false
|
||||
}
|
||||
})
|
||||
option.legend.selected = selectLegend
|
||||
if (echartsValue.value === 'pie'||echartsValue.value === 'radar') {
|
||||
isShowAxisLine(false)
|
||||
} else {
|
||||
isShowAxisLine(true)
|
||||
}
|
||||
//加载echarts
|
||||
initChart();
|
||||
})
|
||||
|
||||
/**
|
||||
* 修改valueFlag
|
||||
* @param val 子组件传的动态值
|
||||
*/
|
||||
const editValueFlag = (val) => {
|
||||
valueFlag.value = val
|
||||
}
|
||||
/**
|
||||
* 修改startDataType
|
||||
* @param str 子组件传的动态值
|
||||
*/
|
||||
const editStartDataType = (str) => {
|
||||
startDataType.value = str
|
||||
}
|
||||
/**
|
||||
* 用于其他组件获取基础设置列表
|
||||
* @param str 子组件传的动态值
|
||||
*/
|
||||
const getLineChartBasicSettingList = (str) => {
|
||||
lineChartBasicSettingList.value = str
|
||||
}
|
||||
/**
|
||||
* 修改option
|
||||
* @param str 子组件传的动态值
|
||||
*/
|
||||
const getBarChartBasicSettingList = (str) => {
|
||||
barChartBasicSettingList.value = str
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 切换echarts图类型事件
|
||||
* @param e event事件
|
||||
*/
|
||||
const handleChangeEcharts = (e) => {
|
||||
if (xValueAxis.length !== 0 || yValueAxis.length !== 0) {
|
||||
|
||||
xValueAxis.map((item) => {
|
||||
ChartsItem.value.unshift(item)
|
||||
option.legend.selected[item.label] = false
|
||||
})
|
||||
xValueAxis.splice(0, xValueAxis.length)
|
||||
yValueAxis.map((item) => {
|
||||
ChartsItem.value.unshift(item)
|
||||
option.legend.selected[item.label] = false
|
||||
})
|
||||
yValueAxis.splice(0, yValueAxis.length)
|
||||
option.legend.data.splice(0, option.legend.data.length)
|
||||
option.series.splice(0, option.series.length)
|
||||
option.xAxis.name = ''
|
||||
option.xAxis.data = []
|
||||
option.xAxis.type = 'category'
|
||||
option.yAxis.name = ''
|
||||
option.yAxis.data = []
|
||||
option.yAxis.type = 'value'
|
||||
initChart()
|
||||
}
|
||||
echartsValue.value = e
|
||||
if (e === 'line') {
|
||||
ChartsItem.value = line_data
|
||||
isShowAxisLine(true)
|
||||
option.radar={}
|
||||
} else if (e === 'bar') {
|
||||
ChartsItem.value = bar_data
|
||||
isShowAxisLine(true)
|
||||
option.radar={}
|
||||
} else if (e === 'pie') {
|
||||
ChartsItem.value = pie_data
|
||||
isShowAxisLine(false)
|
||||
option.radar={}
|
||||
}else if (e === 'radar') {
|
||||
ChartsItem.value = radar_data
|
||||
isShowAxisLine(false)
|
||||
option.radar.indicator = props.radarIndicator
|
||||
}
|
||||
let selectLegend = {}
|
||||
ChartsItem.value.forEach(item => {
|
||||
if (item.dataType !== 'key') {
|
||||
selectLegend[item.label] = false
|
||||
}
|
||||
})
|
||||
option.legend.selected = selectLegend
|
||||
initChart()
|
||||
}
|
||||
/**
|
||||
* 是否显示x/y轴线
|
||||
* @param type
|
||||
*/
|
||||
const isShowAxisLine = (type) => {
|
||||
option.xAxis.axisLine.show = type
|
||||
option.yAxis.axisLine.show = type
|
||||
if (type === false) {
|
||||
option.tooltip.trigger = 'item'
|
||||
} else {
|
||||
option.tooltip.trigger = 'axis'
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 初始化echarts实例方法
|
||||
*/
|
||||
const initChart = () => {
|
||||
console.log('initChartoption', option)
|
||||
//3.初始化container容器
|
||||
myEcharts = echarts.init(chart.value);
|
||||
//5.传入数据
|
||||
myEcharts.setOption(option,true);
|
||||
//图表大小自适应窗口大小变化
|
||||
window.onresize = () => {
|
||||
myEcharts.resize();
|
||||
}
|
||||
//点击事件
|
||||
// myEcharts.on('click', function (params) {
|
||||
// console.log('dddd点击事件', params);
|
||||
// });
|
||||
// myEcharts.restore();
|
||||
localStorage.removeItem('dragType')
|
||||
}
|
||||
/**
|
||||
* 保存数据
|
||||
*/
|
||||
const saveData = () => {
|
||||
console.log('最终initInfo', initInfo)
|
||||
emit("getFinalInfo", initInfo)
|
||||
}
|
||||
/**
|
||||
* 打开高级设置弹框
|
||||
*/
|
||||
const openAdvancedSettings = () => {
|
||||
advancedSettings.value.showDrawer()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
<template>
|
||||
<el-drawer v-model="drawerVisible" direction="rtl">
|
||||
<template #header>
|
||||
<h4>高级设置</h4>
|
||||
</template>
|
||||
<template #default>
|
||||
<el-form :model="settingsForm" class="advanced-setting">
|
||||
<el-form-item label="是否点击图例改变图显示状态">
|
||||
<el-switch active-text="是" inactive-text="否" v-model="settingsForm.isClickLegendToShow"
|
||||
@change="changeIsClickLegend"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否显示提示框组件">
|
||||
<el-switch active-text="是" inactive-text="否" v-model="settingsForm.isShowTooltip"
|
||||
@change="changeIsShowTooltip"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancelSettings">取消</el-button>
|
||||
<el-button type="primary" @click="confirmSettings">确认</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
//初始化加载echarts函数
|
||||
initCharts: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
//echarts的配置属性
|
||||
chartOption: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
})
|
||||
let option = reactive(props.chartOption)
|
||||
//高级设置抽屉是否展开
|
||||
const drawerVisible = ref(false)
|
||||
//高级设置属性
|
||||
const settingsForm = reactive({
|
||||
isClickLegendToShow: option.legend.selectedMode,//打开点击图例改变图显示状态
|
||||
isShowTooltip: option.tooltip.show//是否显示提示框组件
|
||||
})
|
||||
/**
|
||||
* 打开高级设置弹窗
|
||||
*/
|
||||
const showDrawer = () => {
|
||||
drawerVisible.value = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 高级设置: 取消按钮
|
||||
*/
|
||||
const cancelSettings = () => {
|
||||
drawerVisible.value = false
|
||||
}
|
||||
/**
|
||||
* 高级设置: 确认按钮
|
||||
*/
|
||||
const confirmSettings = () => {
|
||||
drawerVisible.value = false
|
||||
props.initCharts()
|
||||
}
|
||||
|
||||
/**
|
||||
* 高级设置:打开点击图例改变图显示状态
|
||||
* @param val
|
||||
*/
|
||||
const changeIsClickLegend = (val) => {
|
||||
option.legend.selectedMode = val
|
||||
}
|
||||
|
||||
/**
|
||||
* 高级设置:是否显示提示框组件
|
||||
* @param val
|
||||
*/
|
||||
const changeIsShowTooltip = (val) => {
|
||||
option.tooltip.show = val
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showDrawer
|
||||
})
|
||||
</script>
|
||||
@@ -1,140 +0,0 @@
|
||||
<template>
|
||||
<el-scrollbar height="450px">
|
||||
<div class="basic-setup" @click.stop>
|
||||
柱状图基本设置
|
||||
</div>
|
||||
<div v-for="(settingItem) in basicList" class="setting" @click.stop>
|
||||
<div class="setting-title">{{ settingItem.label }}</div>
|
||||
<div class="setting-item">
|
||||
<span>显示柱条背景: </span>
|
||||
<el-switch active-text="是" inactive-text="否" v-model="settingItem.showBackground"
|
||||
@change="changeIsShowBackground($event,settingItem)"/>
|
||||
|
||||
</div>
|
||||
<div v-if="settingItem.showBackground!==false">
|
||||
<div class="setting-item">
|
||||
<span>柱条描边宽度: </span>
|
||||
<el-input-number v-model="settingItem.backgroundStyle.borderWidth" :min="0"
|
||||
@change="changeBorderWidth($event,settingItem)"/>
|
||||
</div>
|
||||
|
||||
<!-- <div class="setting-item" v-if="settingItem.backgroundStyle.borderWidth!==0">-->
|
||||
<!-- <span>柱条描边颜色: </span>-->
|
||||
<!-- <el-color-picker v-model="settingItem.backgroundStyle.borderColor"-->
|
||||
<!-- :color="settingItem.backgroundStyle.borderColor"-->
|
||||
<!-- @change="changeBorderColor($event,settingItem)"/>-->
|
||||
<!-- </div>-->
|
||||
<div class="setting-item" v-if="settingItem.backgroundStyle.borderWidth!==0">
|
||||
<span>柱条描边类型: </span>
|
||||
<el-select v-model="settingItem.backgroundStyle.borderType" @change="switchBorderType($event,settingItem)">
|
||||
<el-option
|
||||
v-for="symbolItem in borderTypeList"
|
||||
:key="symbolItem.value"
|
||||
:label="symbolItem.label"
|
||||
:value="symbolItem.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
//基础设置列表
|
||||
basicList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
//初始化加载echarts函数
|
||||
initCharts: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
//echarts的配置属性
|
||||
chartOption: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
})
|
||||
let option = reactive(props.chartOption)
|
||||
//图形标记列表
|
||||
const borderTypeList = ref([
|
||||
{value: 'solid', label: '实线'},
|
||||
{value: 'dashed', label: '虚线'},
|
||||
{value: 'dotted', label: '点线'}
|
||||
])
|
||||
/**
|
||||
* 封装基本设置修改echarts属性事件
|
||||
* @param item 修改的项
|
||||
* @param type option.series中的属性名
|
||||
* @param val 获取修改的值
|
||||
*/
|
||||
const changeSingleParams = (item, type, val) => {
|
||||
option.series.forEach((sItem, sIndex) => {
|
||||
if (sItem.name === item.label) {
|
||||
getSeriesParams(type, sIndex, val)
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 根据changeSingleParams方法传的动态type,封装数据修改事件
|
||||
* @param type option.series中的属性名
|
||||
* @param index 修改某项属性的下标
|
||||
* @param val 获取修改的值
|
||||
*/
|
||||
const getSeriesParams = (type, index, val) => {
|
||||
let seriesItem = option.series[index]
|
||||
switch (type) {
|
||||
case 'showBackground':
|
||||
return seriesItem.showBackground = val
|
||||
case 'color':
|
||||
return seriesItem.backgroundStyle.color = val
|
||||
case 'borderWidth':
|
||||
return seriesItem.backgroundStyle.borderWidth = val
|
||||
case 'borderColor':
|
||||
return seriesItem.backgroundStyle.borderColor = val
|
||||
case 'borderType':
|
||||
return seriesItem.backgroundStyle.borderType = val
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础设置:修改是否显示柱条背景
|
||||
* @param val 是否显示
|
||||
* @param item 修改的chart项
|
||||
*/
|
||||
const changeIsShowBackground = (val, item) => {
|
||||
changeSingleParams(item, 'showBackground', val)
|
||||
props.initCharts()
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础设置:修改柱条描边宽度
|
||||
* @param val 宽度
|
||||
* @param item 修改的chart项
|
||||
*/
|
||||
const changeBorderWidth = (val, item) => {
|
||||
changeSingleParams(item, 'borderWidth', val)
|
||||
props.initCharts()
|
||||
}
|
||||
/**
|
||||
* 基础设置:修改柱条的描边颜色
|
||||
* @param val 颜色
|
||||
* @param item 修改的chart项
|
||||
*/
|
||||
const changeBorderColor = (val, item) => {
|
||||
changeSingleParams(item, 'borderColor', val)
|
||||
props.initCharts()
|
||||
}
|
||||
/**
|
||||
* 基础设置:修改柱条的描边类型
|
||||
* @param val 类型
|
||||
* @param item 修改的chart项
|
||||
*/
|
||||
const switchBorderType = (val, item) => {
|
||||
changeSingleParams(item, 'borderType', val)
|
||||
props.initCharts()
|
||||
}
|
||||
</script>
|
||||
@@ -1,86 +0,0 @@
|
||||
<template>
|
||||
<el-drawer v-model="drawerVisible" direction="rtl">
|
||||
<template #header>
|
||||
<h4>高级设置</h4>
|
||||
</template>
|
||||
<template #default>
|
||||
<el-form :model="settingsForm" class="advanced-setting">
|
||||
<el-form-item label="是否点击图例改变图显示状态">
|
||||
<el-switch active-text="是" inactive-text="否" v-model="settingsForm.isClickLegendToShow"
|
||||
@change="changeIsClickLegend"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否显示提示框组件">
|
||||
<el-switch active-text="是" inactive-text="否" v-model="settingsForm.isShowTooltip"
|
||||
@change="changeIsShowTooltip"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancelSettings">取消</el-button>
|
||||
<el-button type="primary" @click="confirmSettings">确认</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
//初始化加载echarts函数
|
||||
initCharts: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
//echarts的配置属性
|
||||
chartOption: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
})
|
||||
let option = reactive(props.chartOption)
|
||||
//高级设置抽屉是否展开
|
||||
const drawerVisible = ref(false)
|
||||
//高级设置属性
|
||||
const settingsForm = reactive({
|
||||
isClickLegendToShow: option.legend.selectedMode,//打开点击图例改变图显示状态
|
||||
isShowTooltip: option.tooltip.show//是否显示提示框组件
|
||||
})
|
||||
/**
|
||||
* 打开高级设置弹窗
|
||||
*/
|
||||
const showDrawer = () => {
|
||||
drawerVisible.value = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 高级设置: 取消按钮
|
||||
*/
|
||||
const cancelSettings = () => {
|
||||
drawerVisible.value = false
|
||||
}
|
||||
/**
|
||||
* 高级设置: 确认按钮
|
||||
*/
|
||||
const confirmSettings = () => {
|
||||
drawerVisible.value = false
|
||||
props.initCharts()
|
||||
}
|
||||
|
||||
/**
|
||||
* 高级设置:打开点击图例改变图显示状态
|
||||
* @param val
|
||||
*/
|
||||
const changeIsClickLegend = (val) => {
|
||||
option.legend.selectedMode = val
|
||||
}
|
||||
|
||||
/**
|
||||
* 高级设置:是否显示提示框组件
|
||||
* @param val
|
||||
*/
|
||||
const changeIsShowTooltip = (val) => {
|
||||
option.tooltip.show = val
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showDrawer
|
||||
})
|
||||
</script>
|
||||
@@ -1,160 +0,0 @@
|
||||
<template>
|
||||
<el-scrollbar height="450px">
|
||||
<div class="basic-setup" @click.stop>
|
||||
折线图基本设置
|
||||
</div>
|
||||
<div v-for="(settingItem) in basicList" class="setting" @click.stop>
|
||||
<div class="setting-title">{{ settingItem.label }}</div>
|
||||
<!-- <div class="setting-item">-->
|
||||
<!-- <span>图形: </span>-->
|
||||
<!-- <el-select v-model="settingItem.type" @change="switchChart($event,settingItem)">-->
|
||||
<!-- <el-option-->
|
||||
<!-- v-for="chartItem in [{value: 'line',label: '折线图'},{value: 'bar',label: '柱状图'}]"-->
|
||||
<!-- :key="chartItem.value"-->
|
||||
<!-- :label="chartItem.label"-->
|
||||
<!-- :value="chartItem.value"-->
|
||||
<!-- />-->
|
||||
<!-- </el-select>-->
|
||||
<!-- </div>-->
|
||||
<div class="setting-item">
|
||||
<span>显示标记: </span>
|
||||
<el-switch active-text="是" inactive-text="否" v-model="settingItem.showSymbol"
|
||||
@change="changeIsShowSymbol($event,settingItem)"/>
|
||||
|
||||
</div>
|
||||
<div class="setting-item" v-if="settingItem.showSymbol===true">
|
||||
<span>标记: </span>
|
||||
<el-select v-model="settingItem.symbol" @change="switchSymbol($event,settingItem)">
|
||||
<el-option
|
||||
v-for="symbolItem in symbolList"
|
||||
:key="symbolItem.value"
|
||||
:label="symbolItem.label"
|
||||
:value="symbolItem.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="setting-item" v-if="settingItem.showSymbol===true">
|
||||
<span>标记大小: </span>
|
||||
<el-input-number v-model="settingItem.symbolSize" :min="1" @change="changeSymbolSize($event,settingItem)"/>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<span>阴影模糊大小: </span>
|
||||
<el-input-number v-model="settingItem.lineStyle.shadowBlur" :min="0" @change="changeShadowBlur($event,settingItem)"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
//基础设置列表
|
||||
basicList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
//初始化加载echarts函数
|
||||
initCharts: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
//echarts的配置属性
|
||||
chartOption: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
})
|
||||
//图形标记列表
|
||||
const symbolList = ref([
|
||||
{value: 'none', label: '不显示标记'},
|
||||
{value: 'circle', label: '圆形'},
|
||||
{value: 'rect', label: '矩形'},
|
||||
{value: 'triangle', label: '三角形'},
|
||||
{value: 'diamond', label: '钻石形'},
|
||||
{value: 'roundRect', label: '圆角矩形'},
|
||||
{value: 'pin', label: '圆钉形'},
|
||||
{value: 'arrow', label: '箭头形'},
|
||||
])
|
||||
let option = reactive(props.chartOption)
|
||||
|
||||
/**
|
||||
* 封装基本设置修改echarts属性事件
|
||||
* @param item 修改的项
|
||||
* @param type option.series中的属性名
|
||||
* @param val 获取修改的值
|
||||
*/
|
||||
const changeSingleParams = (item, type, val) => {
|
||||
option.series.forEach((sItem, sIndex) => {
|
||||
if (sItem.name === item.label) {
|
||||
getSeriesParams(type, sIndex, val)
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 根据changeSingleParams方法传的动态type,封装数据修改事件
|
||||
* @param type option.series中的属性名
|
||||
* @param index 修改某项属性的下标
|
||||
* @param val 获取修改的值
|
||||
*/
|
||||
const getSeriesParams = (type, index, val) => {
|
||||
let seriesItem = option.series[index]
|
||||
switch (type) {
|
||||
case 'type':
|
||||
return seriesItem.type = val
|
||||
case 'showSymbol':
|
||||
return seriesItem.showSymbol = val
|
||||
case 'symbol':
|
||||
return seriesItem.symbol = val
|
||||
case 'symbolSize':
|
||||
return seriesItem.symbolSize = val
|
||||
case 'shadowBlur':
|
||||
return seriesItem.lineStyle.shadowBlur = val
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 基础设置:是否显示标记
|
||||
* @param val 修改的标记大小
|
||||
* @param item 修改的chart项
|
||||
*/
|
||||
const changeIsShowSymbol = (val, item) => {
|
||||
changeSingleParams(item, 'showSymbol', val)
|
||||
props.initCharts()
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础设置:切换chart的形状
|
||||
* @param val 修改的标记大小
|
||||
* @param item 修改的chart项
|
||||
*/
|
||||
const switchChart = (val, item) => {
|
||||
changeSingleParams(item, 'type', val)
|
||||
props.initCharts()
|
||||
}
|
||||
/**
|
||||
* 基础设置:修改标记
|
||||
* @param val 修改的标记大小
|
||||
* @param item 修改的chart项
|
||||
*/
|
||||
const switchSymbol = (val, item) => {
|
||||
changeSingleParams(item, 'symbol', val)
|
||||
props.initCharts()
|
||||
}
|
||||
/**
|
||||
* 基础设置:修改标记大小
|
||||
* @param val 修改的标记大小
|
||||
* @param item 修改的chart项
|
||||
*/
|
||||
const changeSymbolSize = (val, item) => {
|
||||
changeSingleParams(item, 'symbolSize', val)
|
||||
props.initCharts()
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础设置:修改图形阴影的模糊大小
|
||||
* @param val 修改的阴影的模糊大小
|
||||
* @param item 修改的chart项
|
||||
*/
|
||||
const changeShadowBlur = (val, item) => {
|
||||
changeSingleParams(item, 'shadowBlur', val)
|
||||
props.initCharts()
|
||||
}
|
||||
</script>
|
||||
@@ -1,17 +0,0 @@
|
||||
<template>
|
||||
<el-scrollbar height="450px">
|
||||
<div class="basic-setup" @click.stop>
|
||||
饼图基本设置
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "BasicSetting"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||