Compare commits
949 Commits
39c0de87b7
...
cssupdate
| Author | SHA1 | Date | |
|---|---|---|---|
| 5fde7159e0 | |||
| 6068efa03f | |||
| 738b293ea2 | |||
| a1be105c31 | |||
| 03374856e4 | |||
| f07741ff19 | |||
| c64450d74c | |||
| e462b38ff9 | |||
| b96021d21d | |||
| 12d6fdc3a6 | |||
| cd3f651a2a | |||
| 1e4b416cac | |||
| e38446f3fd | |||
| 06b9d42ae4 | |||
| 99d78069d5 | |||
| 342a3754aa | |||
| 51e9c8ced1 | |||
| b13d481e1e | |||
| da8f204167 | |||
| c1979da1af | |||
| 1802f57906 | |||
| 3fa3b8fb63 | |||
| fb2b1455bc | |||
| cc497b2ebc | |||
| 2b450a2e9c | |||
| e266e89a97 | |||
| 2a94a7ecec | |||
| 9137335ce3 | |||
| b8946f223a | |||
| 3a8440c2b9 | |||
| c2bba7fb56 | |||
| 052570fefa | |||
| 09b1f9f14c | |||
| 37825f88ba | |||
| 1c7434b591 | |||
| 585da730ea | |||
| 2ecc51d8a9 | |||
| ad7148ccfc | |||
| 1e00db6c97 | |||
| 5ed692a672 | |||
| 5f7156470e | |||
| 3aafcd3f3b | |||
| 9b339d6364 | |||
| 09f9bfd301 | |||
| 910a07ea47 | |||
| c27d529b82 | |||
| b6724c0361 | |||
| d4fa15f671 | |||
| 60229ae058 | |||
| 6cf27d8b9c | |||
| 6ba7181e3f | |||
| 4334c2db66 | |||
| d7e93567d9 | |||
| e19ba6a315 | |||
| a8e7ad2430 | |||
| 55c8762255 | |||
| 43a4f5f706 | |||
| c6cff2e97d | |||
| 5d53c26c5c | |||
| 857bb4ad21 | |||
| b3dfb8655b | |||
| 10c1f86708 | |||
| 62a67bf7a0 | |||
| 4dc4932ac7 | |||
| b99c07ef4a | |||
| f8dc645048 | |||
| 051b4ed7e7 | |||
| 142e29f131 | |||
| 7f58f1ff83 | |||
| 5650ccfb87 | |||
| 439c9073b8 | |||
| f78f164326 | |||
| 5fb2abe818 | |||
| 1f3b646495 | |||
| a1ea5c6752 | |||
| beb86140a6 | |||
| 0d442fb63a | |||
| af139f6bf4 | |||
| 1d79ea5186 | |||
| de02e59b0e | |||
| f4fa5afcfa | |||
| 2c40c95794 | |||
| 70534f2a97 | |||
| 4515939fcf | |||
| b16971e6f1 | |||
| 3840206e7c | |||
| ef1f786417 | |||
| 745671bd33 | |||
| a13ea053e3 | |||
| 0725cd779f | |||
| 47caddad60 | |||
| 5db4263f67 | |||
| 9887bd1045 | |||
| 768e1ed786 | |||
| f211f58068 | |||
| e7e7386054 | |||
| 9c7f2d394b | |||
| a1f1716f5c | |||
| 250f78593a | |||
| 2c0b8161a5 | |||
| 83fa83e00d | |||
| 176b25b631 | |||
| 4b2566b762 | |||
| a25f87de9f | |||
| ec6fa7fe77 | |||
| 0ba299ee05 | |||
| d06002d95c | |||
| 1758fb8995 | |||
| 52259d573c | |||
| a680391d86 | |||
| 0e0ed64b38 | |||
| 5221b43c01 | |||
| a373ee7163 | |||
| 07692a2a29 | |||
| 3c7bdd8ac9 | |||
| db3b704d89 | |||
| 6e3e0d59db | |||
| f8884aa736 | |||
| 8e62d95864 | |||
| 7bf88fd578 | |||
| a4330c1216 | |||
| 6c80dbabeb | |||
| e0009fb8fa | |||
| 66da36a907 | |||
| 702e874e08 | |||
| 7e486e463c | |||
| df482bbcdd | |||
| 7651b056b6 | |||
| 877c8835d9 | |||
| 67865d64cd | |||
| 699e55ffa1 | |||
| 4ca9a84d14 | |||
| ac5d0143ac | |||
| 6434d031ca | |||
| 8f2dbf8798 | |||
| 7a0c3af1e9 | |||
| 7879f7914b | |||
| 99a69bad5f | |||
| 38783d80a0 | |||
| b37ed217cd | |||
| dd687120cc | |||
| 004a007148 | |||
| 5018a59045 | |||
| 8fa1399902 | |||
| e781887d16 | |||
| 55d72124a0 | |||
| 3eda90f2d1 | |||
| 6b815ea414 | |||
| df8001d43e | |||
| 7f8ad55c97 | |||
| 14f0f1609e | |||
| 6c176a1039 | |||
| bffe804a7b | |||
| a9beb0dda6 | |||
| 3c72fa125f | |||
| 81df05e0f9 | |||
| e0fd77837d | |||
| 7344691613 | |||
| fe697df167 | |||
| b743688d99 | |||
| 51b6841a3a | |||
| 768ed5b0fb | |||
| 0c2f96fd49 | |||
| 40c8385776 | |||
| 80c6647a0c | |||
| 187a0affcc | |||
| a35288dd0b | |||
| b36627ec25 | |||
| eb2a98e7fe | |||
| 5c79e33ce1 | |||
| 341e1f54fb | |||
| 78925fbbab | |||
| d9e056972c | |||
| b09f7d1e6f | |||
| ad0f7f4b87 | |||
| 61e4ac1fb3 | |||
| 728730433b | |||
| 3a50a23cfa | |||
| 1dc03040f1 | |||
| 900d73d389 | |||
| 5b69987d6e | |||
| 512c07b5a8 | |||
| 885b86ded9 | |||
| c04b7cae38 | |||
| 3ff0137e4b | |||
| 15c18d5fc1 | |||
| 91b083f0e5 | |||
| a3dccb8b19 | |||
| 974f561c5a | |||
| 8fd52854cc | |||
| b9b865ece0 | |||
| acc39f4580 | |||
| e82c201a2b | |||
| 6927bdbc42 | |||
| 3db7e42e71 | |||
| 12bd511d0b | |||
| 4a52be183c | |||
| 58324ebb33 | |||
| 8ccca36e44 | |||
| d6c7a0f11e | |||
| 858468b72b | |||
| 3eadc5c3eb | |||
| fe324bc62f | |||
| 2329b1bbe6 | |||
| 134c75cc4b | |||
| 3b737b0bd0 | |||
| 2da153e935 | |||
| 271f22ea18 | |||
| 4a56e7e980 | |||
| b3475a7d06 | |||
| 988bdde6f1 | |||
| 456209121e | |||
| 8186a424de | |||
| ebc8c6431a | |||
| 7cbb6adb5d | |||
| 4b8963161f | |||
| eeb79e8c56 | |||
| 2a503cbf68 | |||
| aed2ce4655 | |||
| 70b524ce04 | |||
| db82564148 | |||
| 386cd613ee | |||
| dc8a3dc5da | |||
| 4ec2985468 | |||
| 796231a50e | |||
| 6b082f2de9 | |||
|
|
83287098ee | ||
|
|
b67959163b | ||
| ba04d6d220 | |||
| 457c06948c | |||
| c0b6ddf11b | |||
| a8960c3c81 | |||
| d4be3ff937 | |||
| 751d4ce12d | |||
| 9c6e26ce05 | |||
| 25a55ba9f5 | |||
| b8b8d8d58f | |||
| 31d747a0b0 | |||
| 0025b0a5bb | |||
| 002c4055eb | |||
| 738986d715 | |||
| 673f4d101a | |||
| 553c010dc2 | |||
| c18ba2dbc2 | |||
| 13eec27ea9 | |||
| 84e41958c9 | |||
| 7045bd7b7d | |||
| cbb0699fae | |||
| e1b4266513 | |||
| c109748c79 | |||
| 87b4917120 | |||
| 48e3ec7c2c | |||
| 92679d3ebc | |||
| dc94ec5f5f | |||
| c67ae635d8 | |||
| 4233efe422 | |||
| 28e3e08f86 | |||
| be7f4edff5 | |||
| 3d777043e8 | |||
| 9aafb6321b | |||
| 942a5706ca | |||
| 73b8562d71 | |||
| c3733e24a7 | |||
| eeaa27d0b4 | |||
| a5e20a3840 | |||
| d809690724 | |||
| 447885529e | |||
| 89e46189bd | |||
| 29ea63199c | |||
| 3ef1fc634a | |||
| 4d988c316b | |||
| 9182ed29d9 | |||
| e1388c63b7 | |||
| a0d53c6e0e | |||
| 6603af60ef | |||
| 336f27bc23 | |||
| 65ccd97e32 | |||
| 256975b592 | |||
| 90508c8c37 | |||
| f7ced51c4d | |||
| aee2f81601 | |||
| cc85925f37 | |||
| 8897a3bbda | |||
| 9292e40053 | |||
| 57058dd150 | |||
| 8237fb50ce | |||
| 6e2800f361 | |||
| 8bb323f3f5 | |||
| c85cb4af54 | |||
| 5d4baf4383 | |||
| dbf0a65ee7 | |||
| 46c72f1146 | |||
| 2a1c9f7825 | |||
| 878885377c | |||
| 8841bc9819 | |||
| bde8ef0bb3 | |||
| 8e78f95002 | |||
| 77706e5bcb | |||
| 1100e347bd | |||
| de44890014 | |||
| f970f22539 | |||
| 90c1be254b | |||
| 87c3180229 | |||
| 74942de6db | |||
| 04fb5cd3b1 | |||
| 52a1756d5b | |||
| ecd2602d35 | |||
| 0de7fce26d | |||
| 46b85b090d | |||
| 1074b99bb8 | |||
| 11091d46e9 | |||
| 4836f113fa | |||
| 9b7679af30 | |||
| cc8258c764 | |||
| f8734366f1 | |||
| b625a23856 | |||
| 6d2135b862 | |||
| 927c4c65a9 | |||
| 1295706704 | |||
| 50dade9517 | |||
| 26af0577ad | |||
| ec20bd3741 | |||
| c13fcc2cb9 | |||
| 74e7e145af | |||
| b68c56cfdc | |||
| e60b2a02a1 | |||
| 9a9b714aad | |||
| 9ab935e1ff | |||
| c5e28d153d | |||
| 023ebf775d | |||
| f086dd0239 | |||
| 69e45a8044 | |||
| bdd6a7ba34 | |||
| cbb6bc144b | |||
| 304f7c460d | |||
| 163de38bb2 | |||
| 62baecc835 | |||
| 1dd37485a2 | |||
| 6eca3790d3 | |||
| 61c7d32f50 | |||
| 35e11d7d8f | |||
| 999bb94f70 | |||
| bd9e6009ad | |||
| 47d9be28fa | |||
| e765dd4153 | |||
| 207106c34c | |||
| 2af9f63b83 | |||
| dd3672c93a | |||
| 9fb3d8f874 | |||
| 519160218f | |||
| 81ec4a84a8 | |||
| a29e95a951 | |||
| 239bb64e9a | |||
| 774954c70b | |||
| a3f8668b60 | |||
| 3cb48fd462 | |||
| 778e7180d7 | |||
| 1eecd80340 | |||
| 0ba42e2a20 | |||
| 55e8e914fb | |||
| 37828dafca | |||
| 043bac94ec | |||
| e7b76ea68b | |||
| e9a2165b10 | |||
| 93bf23f307 | |||
| fcd562595d | |||
| 4444875e48 | |||
| 5e8f7549e0 | |||
| f0ea57c19f | |||
| ed8ae64cac | |||
| 4b3f626443 | |||
| d06378e264 | |||
| 0ea2fbeb1f | |||
| cb5f4a6148 | |||
| fed50a9f4c | |||
| d94ceb2a9c | |||
| 307c80e5e9 | |||
| 873d043e45 | |||
| dd328e5b9e | |||
| fb135cd1dc | |||
| 65b1fcd992 | |||
| 7ac132a182 | |||
| 929608b9b9 | |||
| cdd4d0d09f | |||
| 9c4cccbeb0 | |||
| 34866fd9fe | |||
| c9107fce72 | |||
| 4953163892 | |||
| cb87b3203c | |||
| 35329b25e8 | |||
| 6dd714dce7 | |||
| 80dbc75c73 | |||
| e76fcf2822 | |||
| b4b36aa988 | |||
| 20deefdd5f | |||
|
|
475fe19d84 | ||
|
|
eba4a1c96e | ||
| b4903854c1 | |||
| 44057cb26d | |||
| c5f88098f5 | |||
| 9a220bbb97 | |||
| 8ec4fd9dce | |||
|
|
2566538006 | ||
|
|
64ff307d57 | ||
| e7a232ac9c | |||
| 4f3c5fdee2 | |||
| eea5f83afc | |||
| 53086a83d1 | |||
| 96d693af64 | |||
|
|
70266967e1 | ||
|
|
24959571b7 | ||
|
|
5c4aa9e21d | ||
|
|
474ea78de5 | ||
|
|
addf3abae0 | ||
| ed5f6e0642 | |||
| d2bb8fbf01 | |||
| 421d549109 | |||
| a2d03eb0d0 | |||
| 425a438852 | |||
|
|
ac249f0a18 | ||
| 55b45a0aef | |||
| e6733ba338 | |||
| cea787d493 | |||
| a8f3aa3a1b | |||
| c8284568aa | |||
| 306d3faa71 | |||
| 49193a8d52 | |||
| c138bf501e | |||
| 127901d864 | |||
| 5a15210d00 | |||
| 184595ce36 | |||
| 4214331fd3 | |||
| 57aba229cd | |||
| add17eac0c | |||
| 8f9e304294 | |||
| 6bd988f257 | |||
| 0665cccd9d | |||
| 80e4b502d1 | |||
| d522c862c2 | |||
| 8eee103fb6 | |||
|
|
41fc9b81e7 | ||
|
|
414b79c2d8 | ||
| f48f2265d8 | |||
| 50f4e5db55 | |||
| adbfc34f9d | |||
| aa4d5b5f31 | |||
| 0c4c40ce7f | |||
| abef3a7750 | |||
| e746952c11 | |||
| 00f3cda6ac | |||
| a823cfaf91 | |||
| 51d31a1a6d | |||
| b2699a952e | |||
| 5c84e7e390 | |||
| 648fde842c | |||
| e927468965 | |||
| a8f7758f46 | |||
| a79adefd64 | |||
| 76a652661c | |||
|
|
357f1fa4c0 | ||
|
|
c0227d2d4a | ||
| 4779280647 | |||
| 776163bb09 | |||
| 2333dcd188 | |||
| 9f0ad41e8f | |||
| 230114d110 | |||
|
|
0f1e480935 | ||
|
|
e70b793e2b | ||
| a1412898af | |||
| 69fe15b9b6 | |||
| ae8fc70e97 | |||
| 56029236bd | |||
| fa2b67c5b5 | |||
| 38ad0bc700 | |||
|
|
3e8643d1fa | ||
|
|
bd0cde3261 | ||
| 76b987205f | |||
|
|
77bd7e1031 | ||
|
|
65d636177f | ||
| 888fed6390 | |||
|
|
8891017cef | ||
|
|
a0045f2397 | ||
| 01a2bfe4c7 | |||
| dbf693d674 | |||
|
|
e6d851395f | ||
|
|
79d4c4976b | ||
| 20431def5a | |||
| 2c00fb46ad | |||
| 3f3d68c275 | |||
| 3ba64348f5 | |||
| 7c5342a42b | |||
| 433734fe5e | |||
| 7833052186 | |||
| 9c149e7373 | |||
| be359bcb85 | |||
| 7bbb0cd60e | |||
| 93e3ac5d70 | |||
| 8815809b68 | |||
| a89b64d62b | |||
| 978367fd2e | |||
| 4c6643797d | |||
| 9d1f60b998 | |||
| 9fbada3be5 | |||
| d824e694a4 | |||
| dc7db65139 | |||
| c5d450907c | |||
| d2fb349766 | |||
| c238bbc588 | |||
| 28e586b57f | |||
| 1bf60294f0 | |||
| ba0904069c | |||
|
|
c40b4ea632 | ||
|
|
e9e36fa8da | ||
|
|
3db6e21f5a | ||
|
|
7dd1559918 | ||
|
|
455fdfca87 | ||
|
|
0363dfcc1d | ||
|
|
ce795402f2 | ||
| 03dbb3273d | |||
| 2a19ee5317 | |||
|
|
90ef0e44b8 | ||
|
|
86888caaf9 | ||
|
|
c1751410c8 | ||
| ac7c1948ec | |||
| e0ef5d1dfe | |||
| a998237ad2 | |||
| d74b1d78fe | |||
| 9498bde772 | |||
| faa1e27b30 | |||
| 7d8f8f670e | |||
|
|
ce013a9379 | ||
|
|
5faabaa05f | ||
| 0ba655692c | |||
| ad55d14f8e | |||
| 96d05e0d09 | |||
| f8c8092562 | |||
| ee8f5017a5 | |||
| d43892b912 | |||
| b30ec56bec | |||
| 01c14bb718 | |||
| b219ce3ee8 | |||
| 6d9a0f3d06 | |||
| 7273594013 | |||
| a749ae588e | |||
| 0c3af5bdf1 | |||
| 0ea206d460 | |||
|
|
427097d704 | ||
|
|
4882cb26a6 | ||
|
|
6a5e7c0bfc | ||
|
|
bc50e84897 | ||
| 74548ffac9 | |||
| 194d16f4f9 | |||
| 74d7235cd2 | |||
| 1af3b8bbd2 | |||
| cc3b4bb140 | |||
| 91762a9045 | |||
| 3d28b10f89 | |||
| 99ba8449c8 | |||
| b29a8b7f7d | |||
| e23bf4ff31 | |||
| 0cf80dc197 | |||
| e9754efe34 | |||
| dfadeef58c | |||
| a64151dbe6 | |||
| 4329bc056f | |||
| 66275cb3f6 | |||
| 2dd4011067 | |||
| da770b823e | |||
| eb6ead0b9c | |||
| 2423d876d7 | |||
|
|
7a34c2fb07 | ||
|
|
bdbfce8c23 | ||
|
|
d368941d9e | ||
|
|
3ebc455be3 | ||
|
|
8ed90c9c1c | ||
|
|
2dbd13ae85 | ||
| 41c88d3388 | |||
| 68ec2820c1 | |||
| 29003d3386 | |||
| 019e65d7db | |||
| 7ffbc6d173 | |||
|
|
970ff14c22 | ||
|
|
32e8e0ace4 | ||
|
|
3d17bb9225 | ||
|
|
dae2ba254e | ||
|
|
349e53104d | ||
| cc81bc8525 | |||
| 37aed84d88 | |||
| 81e711b993 | |||
| eefc81784f | |||
|
|
64969ea916 | ||
|
|
1e0565cdb6 | ||
|
|
0a0a20ebf9 | ||
|
|
b83a5c665c | ||
| ce5d0244c0 | |||
|
|
306109422f | ||
|
|
cd465f0024 | ||
| 6bdd6c02a9 | |||
| c510e6bc4c | |||
| d807b52f11 | |||
| 7ff7f88708 | |||
| a159313702 | |||
| 768b41aa70 | |||
| 2aaf80ffbd | |||
| a105d575b8 | |||
| d04f7b035a | |||
| efb0dc2042 | |||
| d203a3ad3b | |||
| 67fc583bd3 | |||
| dc8331340f | |||
| 78d8ec5d4a | |||
| e6d32e7575 | |||
| a66f4ca6dc | |||
| f727bcae70 | |||
| 69e9993701 | |||
| eb9b566bcd | |||
| 80c549a72f | |||
| 7f0547ff61 | |||
| 255ad67fe9 | |||
| ee0f9f25e3 | |||
| bfae1a23fc | |||
| 5a576b2da3 | |||
| fc5b64e68b | |||
|
|
8caa362e95 | ||
|
|
4eb972e2d1 | ||
|
|
b44bf2362b | ||
| e201814094 | |||
| fccf4a3fc3 | |||
| a17afcf113 | |||
| b7c79da318 | |||
| caaf9966d4 | |||
| 999c8adc9d | |||
| e648538fe5 | |||
| ab462e88af | |||
| c7f95bba3a | |||
| 1d71ee3548 | |||
| 5dbb434018 | |||
| 31982f2486 | |||
| 1eae15631b | |||
| 76501fedae | |||
| b38879539a | |||
| 10d1bea7bc | |||
| 5c86e0ec74 | |||
| 7b1870a4fb | |||
| b3c9fef907 | |||
| ce49d3d480 | |||
| 039c3a9136 | |||
| aeabb46e44 | |||
| 07687e62b3 | |||
| 4e7623194d | |||
| c2ab16fe33 | |||
| d34a250ac6 | |||
| 0eb715f074 | |||
| e277cd12a8 | |||
| 74788dcf55 | |||
| 7e7ea4dda7 | |||
| 31744ee208 | |||
|
|
9808b1ae25 | ||
| 8e7bb8c51a | |||
| 865193475b | |||
| d5d86679a3 | |||
| cf0b4e4ccf | |||
| 875c178e5f | |||
| 8d1a803359 | |||
| 8dad8dd35f | |||
| 7e4dc980e9 | |||
| 2e27fbde5e | |||
| b74d20279e | |||
| 83a817b9cf | |||
| f9afb177eb | |||
| fa8feaacbd | |||
| 685fcf9686 | |||
| 15cb14d976 | |||
| 9b174c2874 | |||
| df1583e689 | |||
| 5f39cbc30a | |||
| e907583a32 | |||
| d81bce3d09 | |||
| aa3e4e81e6 | |||
| 9e939763fd | |||
| c83ccee13f | |||
| 55f56699e3 | |||
| ec0c2f4702 | |||
| 23d30fb43c | |||
| 7d6331ffd5 | |||
| 24f0973f7a | |||
| fa91ee8351 | |||
| 07a722c000 | |||
| fb5534753a | |||
| 2c172e89a9 | |||
| c3b872ba7b | |||
| 2c1767b03c | |||
| 2a9f8ab28f | |||
| 551313bf23 | |||
| 5936301e82 | |||
| f8aa1495e8 | |||
| d3e3271fbe | |||
| 6f1cf8dc52 | |||
| f7ff91889d | |||
| 1d30d725e2 | |||
| 0bdfed92f3 | |||
| c5bdaa8354 | |||
| dd22f6fc3e | |||
| 1814cc0b9a | |||
| fbd479f69a | |||
| 26b83d2037 | |||
| 941e103258 | |||
| e6e5f260fb | |||
| 2824148ae1 | |||
| d2c755fd0a | |||
| 03b7e0d288 | |||
| abbd36c84d | |||
| 57d414fd0a | |||
| d1fd52361a | |||
| b984f1448a | |||
| 0833636868 | |||
| 14ff19ea93 | |||
| 111b648b36 | |||
| a2dc146130 | |||
| be4001ad4d | |||
| 9874fbc49a | |||
| 0b420601f1 | |||
| 286bb6171c | |||
| c9fc6b95ad | |||
| d798a749dc | |||
| ac022803e4 | |||
| 98754be311 | |||
| 36f4e317cf | |||
| c73981344f | |||
| b16d90c946 | |||
| f809ee2c2b | |||
| fc0d159041 | |||
| 1f11c047f1 | |||
| 08afcd551a | |||
| 73726e10c2 | |||
| 517844bc25 | |||
| 10882f135c | |||
| 22deab0aba | |||
| 033af1cbc6 | |||
| 8196490dad | |||
| 0153020fd0 | |||
| 6ad39e0764 | |||
| c6bc9a19de | |||
| f9125a4024 | |||
| 5eb34aab3b | |||
| 0bfed25aaf | |||
| 40aaca9f4e | |||
| 8eaa5559ef | |||
| 7b8d0b085f | |||
| 106deeb224 | |||
| 03104468a0 | |||
| 53da5b8a99 | |||
| 7b82db2366 | |||
| 336b332572 | |||
| efdff61306 | |||
| 91b401870c | |||
| 036fa21944 | |||
| 3df439ef1b | |||
| 33db39d5b0 | |||
| 2798951f45 | |||
| 0b03e51c12 | |||
| c4b2b005e0 | |||
| 9e48a8b314 | |||
| c849c2db3e | |||
| 95d671c161 | |||
| 237d786cbe | |||
| 40f3f293e3 | |||
| 68f7ed356f | |||
| f671dbbd19 | |||
| ae6a927d45 | |||
| 7ec6f9861f | |||
| 9fcf6d0228 | |||
| 56f4e34d9a | |||
| bbbe28d9e6 | |||
| d9f3b64ae9 | |||
| baa5addc60 | |||
| 63c3f39e7d | |||
| 5696b25705 | |||
| f275c447ac | |||
| 5736e5c757 | |||
| 4c2ea0e11a | |||
| 6efd309160 | |||
| 133650a9ea | |||
| 67c87761a6 | |||
| fb33688dc7 | |||
| 7565fe311d | |||
| 2222db92fa | |||
| 6cd342ea56 | |||
| b97f08f1ac | |||
| 70ed1624f1 | |||
| e008d8d2db | |||
| 7601564d99 | |||
| f06bc9afa1 | |||
| 9a6e7c02ba | |||
| 1121fd3405 | |||
| 6ed3398e87 | |||
| 03110541c5 | |||
| f19927ca33 | |||
| 915dc2fdb2 | |||
| 245c90f31f | |||
| a5168055bf | |||
| d6cf444637 | |||
| 6c5fe7e4da | |||
| 4cbe27668f | |||
| d71f27e64c | |||
| efb6151fc1 | |||
| 900b94ca78 | |||
| 9ac1fe00d9 | |||
| 7305baf66b | |||
| 2445fb7e14 | |||
| 4d43c26a5e | |||
| 36f9c8431b | |||
| e4c600c3e6 | |||
| 783599b3b4 | |||
| 3add58d6ec | |||
| 71b93c3f82 | |||
| a5f35ac4be | |||
| 218d5f0bbe | |||
| e4e5b6583f | |||
| 32ccd0e367 | |||
| 9710a7be12 | |||
| 37c34c9896 | |||
| ca14923a3e | |||
| d797850feb | |||
| 91cb6124a3 | |||
| 7785661837 | |||
| ced7db61b5 | |||
| 8db458523e | |||
| 694199ccd4 | |||
| 825ea45eb7 | |||
| 27c04754aa | |||
| da9feeeb35 | |||
| 073b94d3b9 | |||
| 78933cd7c3 | |||
| e14d348813 | |||
| c2cd2219cc | |||
| 76529d2428 | |||
| b9f52748cf | |||
| e5230f5a3b | |||
| 4cf9354864 | |||
| b50333e558 | |||
| c4b53a7b3f | |||
| 32f5f52c5e | |||
| 1e0004a5c4 | |||
| dbe0a0176e | |||
| ad110bdf7f | |||
| 02f673e259 | |||
| 310e4745f5 | |||
| bae3206689 | |||
| aae1d094c9 | |||
| 58892cf612 | |||
| 2e7c0887ea | |||
| 43630eb20a | |||
| 307bb2bcf4 | |||
| 00539bbe03 | |||
| ed82819d6d | |||
| 76e71741f1 | |||
| 41444abd51 | |||
| 38938628ee | |||
| 7de54e5550 | |||
| e7ea53c78e | |||
| 1ad2f9b016 | |||
| cd98608188 | |||
| d58a5df1fe | |||
| 8d159ebd0f | |||
| b427627f77 | |||
| 3835bdc1cc | |||
| f9f8db24b6 | |||
| 6c1d992046 | |||
| 919e740073 | |||
| c7e1cc5bed | |||
| f9e5f6ceb2 | |||
| fd2d246736 | |||
| b5dae966e6 | |||
| d21a69d99d | |||
| 326da1eba3 | |||
| d13796a549 | |||
| 25bcd0fdf3 | |||
| 4536761024 | |||
| dc752915d1 | |||
| 437f144e79 | |||
| b05c03281d | |||
| ecdb5c1976 | |||
| bc0db74bd7 | |||
| 199ef65cdf | |||
| eaa6781357 | |||
| 99604ebac9 | |||
| 8032e26fd3 | |||
| 084b003abf | |||
| ca40dc3cc8 | |||
| c28363eef6 | |||
| 9e6d1948fc | |||
| 96094004d9 | |||
| a0e90d0a06 | |||
| 27935b529f | |||
| eb3ca0b501 | |||
| 465405261e | |||
| b3c90135fe | |||
| bf5a50cc6a | |||
| 8fc50394fb | |||
| 163c29f57b | |||
| 3cb69bb32a | |||
| 348d51a2c4 | |||
| 61bf631c2d | |||
| 7df84dcbc2 | |||
| 43b4332d57 | |||
| 2bdfb24505 | |||
| 3efff936fa | |||
| 682998aceb | |||
| 7402c0a57f | |||
| c66d7a6761 | |||
| 49eb6a8d3c | |||
| 8a5b1bdaa7 | |||
| af9ab0f4ab | |||
| 202c4a8a2c | |||
| 68a29ca984 | |||
| f2c3200d28 | |||
| aac33677cd | |||
| 25005da55c | |||
| 44710716a9 | |||
| e22b574ad1 | |||
| 2aa3af798c | |||
| f800e5cd8b | |||
| e169da28a8 | |||
| 248f97e5cd | |||
| 1466cde240 | |||
| 89dc6affcd | |||
| aebdb3c799 | |||
| 13d75dcb2c | |||
| e1697fd66d | |||
| fd06b1b1ac | |||
| 5c15fb83e1 | |||
| df0c545b90 | |||
| 8913ec7e5e | |||
| 0ec541ab76 | |||
| cbd0ca2086 | |||
| 14c6a14628 | |||
|
|
e46aabea97 | ||
|
|
c112402c80 | ||
| 1798f6ea8c | |||
| d39df73150 | |||
| 8582d93678 | |||
| 7bfb0cca1e | |||
| 2227390f77 | |||
| d3594feabd | |||
| 1724bf8afb | |||
| 94572876fb | |||
| d469a2c9f2 | |||
| a16e1a0ff1 |
22
.env.dev
22
.env.dev
@@ -1,22 +0,0 @@
|
|||||||
APP_DEBUG = true
|
|
||||||
|
|
||||||
DB_TYPE = mysql
|
|
||||||
DB_HOST = 120.79.27.160
|
|
||||||
DB_NAME = orico-official-website
|
|
||||||
DB_USER = orico-ow
|
|
||||||
DB_PASS = 14Xi17NIK8V2qAXE8oMataHEsaR8lE
|
|
||||||
DB_PORT = 3306
|
|
||||||
DB_CHARSET = utf8mb4
|
|
||||||
DB_PREFIX = ow_
|
|
||||||
|
|
||||||
DEFAULT_LANG = zh-cn
|
|
||||||
|
|
||||||
[JWT]
|
|
||||||
JWT_TTL=3600
|
|
||||||
JWT_REFRESH_TTL=20160
|
|
||||||
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
|
||||||
|
|
||||||
# 后台不需要登录的接口
|
|
||||||
[ADMIN_AUTH]
|
|
||||||
WHITE_LIST[] = v1/user/login
|
|
||||||
WHITE_LIST[] = v1/user/captcha
|
|
||||||
22
.env.local
22
.env.local
@@ -1,22 +0,0 @@
|
|||||||
APP_DEBUG = true
|
|
||||||
|
|
||||||
DB_TYPE = mysql
|
|
||||||
DB_HOST = 127.0.0.1
|
|
||||||
DB_NAME = orico-official-website
|
|
||||||
DB_USER = orico-official-website
|
|
||||||
DB_PASS = 14Xi17NIK8V2qAXE8oMataHEsaR8lE
|
|
||||||
DB_PORT = 3306
|
|
||||||
DB_CHARSET = utf8mb4
|
|
||||||
DB_PREFIX = ow_
|
|
||||||
|
|
||||||
DEFAULT_LANG = zh-cn
|
|
||||||
|
|
||||||
[JWT]
|
|
||||||
JWT_TTL=3600
|
|
||||||
JWT_REFRESH_TTL=20160
|
|
||||||
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
|
||||||
|
|
||||||
# 后台不需要登录的接口
|
|
||||||
[ADMIN_AUTH]
|
|
||||||
WHITE_LIST[] = v1/user/login
|
|
||||||
WHITE_LIST[] = v1/user/captcha
|
|
||||||
95
.example.env
95
.example.env
@@ -1,11 +1,96 @@
|
|||||||
APP_DEBUG = true
|
APP_DEBUG = true
|
||||||
|
|
||||||
DB_TYPE = mysql
|
DB_TYPE = mysql
|
||||||
DB_HOST = 127.0.0.1
|
DB_HOST = localhost
|
||||||
DB_NAME = test
|
DB_NAME = orico-official-website
|
||||||
DB_USER = username
|
DB_USER = orico-ow
|
||||||
DB_PASS = password
|
DB_PASS = 14Xi17NIK8V2qAXE8oMataHEsaR8lE
|
||||||
DB_PORT = 3306
|
DB_PORT = 3306
|
||||||
DB_CHARSET = utf8
|
DB_CHARSET = utf8mb4
|
||||||
|
DB_PREFIX = ow_
|
||||||
|
DB_VERSION = 8
|
||||||
|
|
||||||
DEFAULT_LANG = zh-cn
|
DEFAULT_LANG = zh-cn
|
||||||
|
|
||||||
|
# 前端代理服务器ip(影响使用代理访问情况下的客户端ip获取)
|
||||||
|
PROXY_SERVER_IP[] = 120.79.27.160
|
||||||
|
|
||||||
|
# redis 配置
|
||||||
|
REDIS_HOST = 127.0.0.1
|
||||||
|
REDIS_PORT = 6379
|
||||||
|
REDIS_PASSWORD = ''
|
||||||
|
REDIS_PREFIX = ow:
|
||||||
|
|
||||||
|
[JWT]
|
||||||
|
TTL=3600
|
||||||
|
REFRESH_TTL=20160
|
||||||
|
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
||||||
|
|
||||||
|
# 七牛云存储配置
|
||||||
|
[QINIU_CLOUD]
|
||||||
|
BUCKET = orico-official-website
|
||||||
|
BASE_URL = //ow.static.f2b211.com
|
||||||
|
ACCESS_KEY = dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms
|
||||||
|
SECRET_KEY = KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q
|
||||||
|
|
||||||
|
# 后台不需要登录的接口
|
||||||
|
[ADMIN_AUTH]
|
||||||
|
WHITE_LIST[] = v1/user/login
|
||||||
|
WHITE_LIST[] = v1/user/captcha
|
||||||
|
WHITE_LIST[] = receive_sync/category
|
||||||
|
WHITE_LIST[] = receive_sync/product
|
||||||
|
|
||||||
|
# 不需记录日志的接口
|
||||||
|
[ADMIN_API]
|
||||||
|
IGNORE_LOGGING_LIST[] = v1/OperateLog/index
|
||||||
|
MAX_IMAGE_SIZE = 5mb; # 图片上传最大限制
|
||||||
|
MAX_VIDEO_SIZE = 150mb; # 视频上传最大限制
|
||||||
|
MAX_ATTACHMENT_SIZE = 100mb; # 附件上传最大限制
|
||||||
|
|
||||||
|
# 开放API
|
||||||
|
[OPENAPI]
|
||||||
|
ACCESS_TOKEN_LIFETIME = 3600; # 访问令牌有效期
|
||||||
|
REFRESH_TOKEN_LIFETIME = 1209600; # 刷新令牌有效期
|
||||||
|
RESOURCE_IMAGES_DOMAIN = http://local.orico.com; # 图片资源服务器地址
|
||||||
|
RESOURCE_VIDEOS_DOMAIN = http://local.orico.com; # 视频资源服务器地址
|
||||||
|
|
||||||
|
# 七牛云存储配置
|
||||||
|
[QINUI]
|
||||||
|
BUCKET = orico
|
||||||
|
BASE_URL = http://local.orico.com
|
||||||
|
ACCESS_KEY = 1234567890
|
||||||
|
SECRET_KEY = 1234567890
|
||||||
|
|
||||||
|
# 前台视图模板规则配置
|
||||||
|
[INDEX_VIEW_TPL]
|
||||||
|
# 视图目录
|
||||||
|
# query 规则:URL参数 mtpl=1 表示移动端访问
|
||||||
|
# 例如:http://xxxx.com?mtpl=1
|
||||||
|
# domain 规则:根据特定域名,判断是否移动端访问
|
||||||
|
# 例如:http://mobile.orico.cn
|
||||||
|
RULE = query
|
||||||
|
# query 规则参数名
|
||||||
|
RULE_QUERY_NAME = mtpl
|
||||||
|
# query 规则参数值
|
||||||
|
RULE_QUERY_VALUE = 1
|
||||||
|
# domain 规则协议
|
||||||
|
RULE_DOMAIN_SCHEME[] = http
|
||||||
|
RULE_DOMAIN_SCHEME[] = https
|
||||||
|
# domain 规则域名
|
||||||
|
RULE_DOMAIN_HOST = mobile.orico.cn
|
||||||
|
|
||||||
|
# 前台语言检测配置
|
||||||
|
[INDEX_LANG_DETECT]
|
||||||
|
# 是否启用域名检测方式来检测语言
|
||||||
|
DOMAIN_DETECT = true
|
||||||
|
# 域名规则
|
||||||
|
# 格式:域名=语言
|
||||||
|
# 例如:mobile.orico.cn=zh-cn
|
||||||
|
DOMAIN_RULE[] = orico.cn=zh-cn
|
||||||
|
DOMAIN_RULE[] = orico.com.cn=zh-cn
|
||||||
|
DOMAIN_RULE[] = www.orico.cn=zh-cn
|
||||||
|
DOMAIN_RULE[] = www.orico.com.cn=zh-cn
|
||||||
|
DOMAIN_RULE[] = ow.f2b211.com=zh-cn
|
||||||
|
DOMAIN_RULE[] = orico.cc=en-us
|
||||||
|
DOMAIN_RULE[] = www.orico.cc=en-us
|
||||||
|
DOMAIN_RULE[] = ow.us.f2b211.com=en-us
|
||||||
|
|||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,10 +1,15 @@
|
|||||||
*.log
|
*.log
|
||||||
.env
|
|
||||||
composer.phar
|
composer.phar
|
||||||
composer.lock
|
composer.lock
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
.env
|
||||||
|
.env.dev
|
||||||
|
.env.local
|
||||||
|
.env.prod
|
||||||
|
|
||||||
|
public/dist
|
||||||
|
public/opendoc
|
||||||
/.idea
|
/.idea
|
||||||
/.vscode
|
/.vscode
|
||||||
/vendor
|
/vendor
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ class ExceptionHandle extends Handle
|
|||||||
public function render($request, Throwable $e): Response
|
public function render($request, Throwable $e): Response
|
||||||
{
|
{
|
||||||
// 添加自定义异常处理机制
|
// 添加自定义异常处理机制
|
||||||
|
$request->exception_info = $e;
|
||||||
|
|
||||||
// 其他错误交给系统处理
|
// 其他错误交给系统处理
|
||||||
return parent::render($request, $e);
|
return parent::render($request, $e);
|
||||||
|
|||||||
@@ -4,5 +4,12 @@ namespace app;
|
|||||||
// 应用请求对象类
|
// 应用请求对象类
|
||||||
class Request extends \think\Request
|
class Request extends \think\Request
|
||||||
{
|
{
|
||||||
|
protected $proxyServerIp = [];
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
// 设置前端代理服务器IP地址,让代理访问情况下,正确获取真实客户端IP地址
|
||||||
|
$this->proxyServerIp = env('PROXY_SERVER_IP', ['120.79.27.160']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,135 @@
|
|||||||
<?php
|
<?php
|
||||||
// 这是系统自动生成的公共文件
|
// 这是系统自动生成的公共文件
|
||||||
|
|
||||||
if (!function_exists('array_to_tree')) {
|
if (!function_exists('xlsx_reader')) {
|
||||||
/**
|
/**
|
||||||
* 数组转换为树状结构
|
* 读取Excel数据
|
||||||
* @param array $data 数据
|
* @param string $file Excel文件路径
|
||||||
* @param int $pid 父级ID
|
* @param int $initial_row 初始行
|
||||||
* @param string $with 转换依据字段
|
* @param array $keys_map 列 -> 键 例:['A' => 'name', 'B' => 'age', 'C' => 'sex']
|
||||||
* @param int $level 层级
|
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
function array_to_tree(array $data, int $pid, string $with = 'pid', int $level = 1)
|
function xlsx_reader(string $file, int $initial_row = 1, array $keys_map = []): array
|
||||||
{
|
{
|
||||||
$ret = [];
|
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx');
|
||||||
|
|
||||||
|
// 读取文件
|
||||||
|
$spreadsheet = $reader->load($file);
|
||||||
|
|
||||||
|
// 获取活动sheet
|
||||||
|
$sheet = $spreadsheet->getActiveSheet();
|
||||||
|
|
||||||
|
// 获取最大行
|
||||||
|
$max_row = $sheet->getHighestRow();
|
||||||
|
|
||||||
|
// 获取最大列
|
||||||
|
$max_col = $sheet->getHighestColumn();
|
||||||
|
|
||||||
|
$xlsx_data = [];
|
||||||
|
$first_col = ord('A');
|
||||||
|
$last_col = ord($max_col);
|
||||||
|
for ($row = $initial_row; $row <= $max_row; $row++) {
|
||||||
|
for ($col = $first_col; $col <= $last_col; $col++) {
|
||||||
|
$key = $col_chr = chr($col);
|
||||||
|
if (!empty($keys_map)) {
|
||||||
|
$key = $keys_map[$col_chr] ?? $col_chr;
|
||||||
|
}
|
||||||
|
$xlsx_data[$row][$key] = $sheet->getCell($col_chr . $row)->getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $xlsx_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('xlsx_writer')) {
|
||||||
|
/**
|
||||||
|
* 构建Excel数据
|
||||||
|
* @param array $data 数据 例:[['name'=>'张三','age'=>18, 'sex'=>'男']]
|
||||||
|
* @param array $schema 表头信息 例:['name' => '姓名', 'age' => '年龄', 'sex' => '性别']
|
||||||
|
* @param string $filename 下载文件名称 默认为YmdHis时间
|
||||||
|
* @param string $output 输出方式 php://output 或 文件路径
|
||||||
|
* @return \think\Response
|
||||||
|
*/
|
||||||
|
function xlsx_writer(array|\think\model\Collection $data, array $schema, string $filename = '', string $output = 'php://output'): \think\Response
|
||||||
|
{
|
||||||
|
// 获取Spreadsheet对象
|
||||||
|
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
|
||||||
|
$sheet = $spreadsheet->getActiveSheet();
|
||||||
|
|
||||||
|
// 写入表头
|
||||||
|
$title = array_values($schema);
|
||||||
|
$title_col = 'A';
|
||||||
|
foreach ($title as $value) {
|
||||||
|
// 单元格内容写入
|
||||||
|
$sheet->setCellValue($title_col . '1', $value);
|
||||||
|
$title_col++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入数据
|
||||||
|
$row = 2;
|
||||||
|
$keys = array_keys($schema);
|
||||||
foreach ($data as $item) {
|
foreach ($data as $item) {
|
||||||
if ($item[$with] == $pid) {
|
$data_col = 'A';
|
||||||
$item['level'] = $level;
|
foreach ($keys as $key) {
|
||||||
$children = array_to_tree($data, $item['id'], $with, $level + 1);
|
$sheet->setCellValue($data_col . $row, $item[$key] ?? '');
|
||||||
if ($children) {
|
$data_col++;
|
||||||
$item['children'] = $children;
|
|
||||||
}
|
}
|
||||||
$ret[] = $item;
|
$row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
flush();
|
||||||
|
ob_flush();
|
||||||
|
if ($filename == '') $filename = date('YmdHis');
|
||||||
|
$filename = urlencode($filename);
|
||||||
|
// 文件写入缓冲区
|
||||||
|
\PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx')->save($output);
|
||||||
|
// 从缓冲区获取导出文件,并通过Response返回(解决thinkphp框架的Response无法获取设置的header问题)
|
||||||
|
$file_data = ob_get_clean();
|
||||||
|
$response = \think\Response::create($file_data)->header([
|
||||||
|
'Access-Control-Expose-Headers' => 'Content-Disposition',
|
||||||
|
'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=UTF-8',
|
||||||
|
'Content-Disposition' => 'attachment;filename=' . $filename . '.xlsx',
|
||||||
|
'Cache-Control' => 'max-age=0'
|
||||||
|
]);
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $ret;
|
|
||||||
|
if (!function_exists('strtobytes')) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串转字节
|
||||||
|
* @param string $str_size 字符串 例:'1MB' '2GB'
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
function strtobytes(string $str_size): int
|
||||||
|
{
|
||||||
|
preg_match('/(\d+)(\w+)/', $str_size, $matches);
|
||||||
|
if (!isset($matches[1])) {
|
||||||
|
throw new \Exception('请确认size大小');
|
||||||
|
}
|
||||||
|
if (!isset($matches[2])) {
|
||||||
|
throw new \Exception('请确认单位');
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = intval($matches[1]);
|
||||||
|
$unit = $matches[2];
|
||||||
|
switch (strtolower($unit)) {
|
||||||
|
case 'kb':
|
||||||
|
$size *= 1024;
|
||||||
|
break;
|
||||||
|
case 'mb':
|
||||||
|
$size *= 1024 * 1024;
|
||||||
|
break;
|
||||||
|
case 'gb':
|
||||||
|
$size *= 1024 * 1024 * 1024;
|
||||||
|
break;
|
||||||
|
case 'tb':
|
||||||
|
$size *= 1024 * 1024 * 1024 * 1024;
|
||||||
|
default:
|
||||||
|
throw new \Exception('不支持[' . $unit . ']单位');
|
||||||
|
}
|
||||||
|
return $size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,5 +5,5 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
// 不需要登录验证的接口
|
// 不需要登录验证的接口
|
||||||
'white_list' => env('ADMIN_AUTH.WHITE_LIST', ['v1/user/login','1/user/captcha']),
|
'white_list' => env('ADMIN_AUTH.WHITE_LIST', ['v1/user/login','v1/user/captcha']),
|
||||||
];
|
];
|
||||||
68
app/admin/config/log.php
Normal file
68
app/admin/config/log.php
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | 日志设置
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
return [
|
||||||
|
// 默认日志记录通道
|
||||||
|
'default' => 'MyFileLogger',
|
||||||
|
// 日志记录级别
|
||||||
|
'level' => [],
|
||||||
|
// 日志类型记录的通道 ['error'=>'email',...]
|
||||||
|
'type_channel' => [],
|
||||||
|
// 关闭全局日志写入
|
||||||
|
'close' => false,
|
||||||
|
// 全局日志处理 支持闭包
|
||||||
|
'processor' => null,
|
||||||
|
|
||||||
|
// 日志通道列表
|
||||||
|
'channels' => [
|
||||||
|
'file' => [
|
||||||
|
// 日志记录方式
|
||||||
|
'type' => 'File',
|
||||||
|
// 日志保存目录
|
||||||
|
'path' => '',
|
||||||
|
// 单文件日志写入
|
||||||
|
'single' => false,
|
||||||
|
// 独立日志级别
|
||||||
|
'apart_level' => [],
|
||||||
|
// 最大日志文件数量
|
||||||
|
'max_files' => 0,
|
||||||
|
// 使用JSON格式记录
|
||||||
|
'json' => false,
|
||||||
|
// 日志处理
|
||||||
|
'processor' => null,
|
||||||
|
// 关闭通道日志写入
|
||||||
|
'close' => false,
|
||||||
|
// 日志输出格式化
|
||||||
|
'format' => '[%s][%s] %s',
|
||||||
|
// 是否实时写入
|
||||||
|
'realtime_write' => false,
|
||||||
|
],
|
||||||
|
'MyFileLogger' => [
|
||||||
|
// 日志记录方式
|
||||||
|
'type' => \app\admin\driver\Logger::class,
|
||||||
|
// 日志保存目录
|
||||||
|
'path' => '',
|
||||||
|
// 单文件日志写入
|
||||||
|
'single' => false,
|
||||||
|
// 独立日志级别
|
||||||
|
'apart_level' => [],
|
||||||
|
// 最大日志文件数量
|
||||||
|
'max_files' => 0,
|
||||||
|
// 使用JSON格式记录
|
||||||
|
'json' => false,
|
||||||
|
// 日志处理
|
||||||
|
'processor' => null,
|
||||||
|
// 关闭通道日志写入
|
||||||
|
'close' => false,
|
||||||
|
// 日志输出格式化
|
||||||
|
'format' => '[%s][%s][%s] %s',
|
||||||
|
// 是否实时写入
|
||||||
|
'realtime_write' => false,
|
||||||
|
]
|
||||||
|
// 其它日志通道配置
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
219
app/admin/controller/ReceiveProductSync.php
Normal file
219
app/admin/controller/ReceiveProductSync.php
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller;
|
||||||
|
|
||||||
|
use app\admin\model\v1\LanguageModel;
|
||||||
|
use app\admin\model\v1\ProductCategoryModel;
|
||||||
|
use app\admin\model\v1\ProductModel;
|
||||||
|
use app\admin\model\v1\ProductTcoCategoryModel;
|
||||||
|
use think\facade\Db;
|
||||||
|
|
||||||
|
class Operate_Of_ReceiveSync
|
||||||
|
{
|
||||||
|
const Add = 'add';
|
||||||
|
const Update = 'update';
|
||||||
|
const Enable = 'enable';
|
||||||
|
const Disable = 'disable';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收产品相关同步数据
|
||||||
|
*/
|
||||||
|
class ReceiveProductSync
|
||||||
|
{
|
||||||
|
// 接收产品目录分类同步数据
|
||||||
|
public function category()
|
||||||
|
{
|
||||||
|
$data = request()->post();
|
||||||
|
if (empty($data)) return error('请确认同步数据');
|
||||||
|
|
||||||
|
$validate = validate([
|
||||||
|
'name|分类名称' => 'require',
|
||||||
|
'erp_code|分类ERP编码' => 'require',
|
||||||
|
]);
|
||||||
|
if (!$validate->check($data)) {
|
||||||
|
return error((string)$validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取对应语言ID
|
||||||
|
$lang_id = LanguageModel::where('code', $data['lang'])->value('id');
|
||||||
|
if (empty($lang_id)) {
|
||||||
|
return error('语言不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
Db::startTrans();
|
||||||
|
try {
|
||||||
|
$tco_category_data = [
|
||||||
|
'language_id' => $lang_id,
|
||||||
|
'name' => $data['name'],
|
||||||
|
'tco_id' => $data['tco_id'],
|
||||||
|
'tco_pid' => $data['tco_pid'],
|
||||||
|
'tco_path' => $data['tco_path'],
|
||||||
|
'erp_id' => $data['erp_id'],
|
||||||
|
'erp_pid' => $data['erp_pid'],
|
||||||
|
'erp_code' => $data['erp_code'],
|
||||||
|
'erp_path' => $data['erp_path'],
|
||||||
|
'disabled' => Operate_Of_ReceiveSync::Disable == $data['operate'] ? 1 : 0,
|
||||||
|
'sync_time' => strtotime($data['created_at'])
|
||||||
|
];
|
||||||
|
$tco_category = ProductTcoCategoryModel::language($lang_id)->erpCode($tco_category_data['erp_code'])->find();
|
||||||
|
if (empty($tco_category)) {
|
||||||
|
$tco_category = ProductTcoCategoryModel::create($tco_category_data);
|
||||||
|
if ($tco_category->isEmpty()) {
|
||||||
|
throw new \Exception('产品目录分类创建失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
$category_data = [
|
||||||
|
'language_id' => $lang_id,
|
||||||
|
'unique_id' => uniqid('PRO_CATE_'),
|
||||||
|
'pid' => 0,
|
||||||
|
'path' => '',
|
||||||
|
'name' => $tco_category_data['name'],
|
||||||
|
'icon' => '',
|
||||||
|
'desc' => '',
|
||||||
|
'related_tco_category' => $tco_category['id'],
|
||||||
|
'sort' => 0,
|
||||||
|
'level' => 1,
|
||||||
|
'is_show' => 1,
|
||||||
|
];
|
||||||
|
$tco_parent = ProductTcoCategoryModel::language($lang_id)->tcoId($tco_category['tco_pid'])->find();
|
||||||
|
if (!empty($tco_parent)) {
|
||||||
|
$parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find();
|
||||||
|
if ($parent->isEmpty()) {
|
||||||
|
throw new \Exception('产品分类父级不存在');
|
||||||
|
}
|
||||||
|
$category_data['pid'] = $parent['id'];
|
||||||
|
$category_data['path'] = $parent['path'] . $parent['pid'];
|
||||||
|
$category_data['level'] = $parent['level'] + 1;
|
||||||
|
}
|
||||||
|
$category = ProductCategoryModel::create($category_data);
|
||||||
|
if ($category->isEmpty()) {
|
||||||
|
throw new \Exception('产品分类创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ($tco_category['sync_time'] < $tco_category_data['sync_time']) {
|
||||||
|
$success = $tco_category->save($tco_category_data);
|
||||||
|
if (!$success) {
|
||||||
|
throw new \Exception('产品目录分类更新失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
$category = ProductCategoryModel::language($lang_id)->tcoId($tco_category['id'])->find();
|
||||||
|
if (!empty($category)) {
|
||||||
|
$tco_parent = ProductTcoCategoryModel::language($lang_id)->tcoId($tco_category['tco_pid'])->find();
|
||||||
|
if (!empty($tco_parent)) {
|
||||||
|
$parent = ProductCategoryModel::language($lang_id)->tcoId($tco_parent['id'])->find();
|
||||||
|
if ($parent->isEmpty()) {
|
||||||
|
throw new \Exception('产品分类父级不存在');
|
||||||
|
}
|
||||||
|
$category['pid'] = $parent['id'];
|
||||||
|
$category['path'] = $parent['path'] . $parent['pid'];
|
||||||
|
$category['level'] = $parent['level'] + 1;
|
||||||
|
}
|
||||||
|
if (!$category->save()) {
|
||||||
|
throw new \Exception('产品分类更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Db::commit();
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
Db::rollback();
|
||||||
|
return error(sprintf('%s %s:%d', $th->getMessage(), $th->getFile(), $th->getLine()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('同步成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接收产品同步数据
|
||||||
|
public function product()
|
||||||
|
{
|
||||||
|
$data = request()->post();
|
||||||
|
if (empty($data)) {
|
||||||
|
return error('请确认同步数据');
|
||||||
|
}
|
||||||
|
|
||||||
|
$validate = validate([
|
||||||
|
'spu' => 'require',
|
||||||
|
'name' => 'require',
|
||||||
|
'category_erp_code' => 'require',
|
||||||
|
'lang' => 'require',
|
||||||
|
'created_at' => 'require',
|
||||||
|
]);
|
||||||
|
if (!$validate->check($data)) {
|
||||||
|
return error((string)$validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取对应语言ID
|
||||||
|
$lang_id = LanguageModel::where('code', $data['lang'])->value('id');
|
||||||
|
if (empty($lang_id)) {
|
||||||
|
return error('语言不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 spu_before_modification 存在则根据 spu_before_modification 更新型号
|
||||||
|
$product = null;
|
||||||
|
if (!empty($data['spu_before_modification'])) {
|
||||||
|
$product = ProductModel::language($lang_id)->spu($data['spu_before_modification'])->find();
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(empty($data['spu_before_modification']) && !empty($data['spu']))
|
||||||
|
// 避免 spu_before_modification 更新型号时,人为删除了旧型号导致的新增,从而出现重复型号问题,而进行再次验证
|
||||||
|
|| (!empty($data['spu_before_modification']) && empty($product))
|
||||||
|
) {
|
||||||
|
$product = ProductModel::language($lang_id)->spu($data['spu'])->find();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$product_tco_category = ProductTcoCategoryModel::language($lang_id)->erpCode($data['category_erp_code'])->find();
|
||||||
|
if (empty($product_tco_category)) {
|
||||||
|
throw new \Exception('官网未找到产品目录同步分类');
|
||||||
|
}
|
||||||
|
|
||||||
|
$product_category = ProductCategoryModel::language($lang_id)->tcoId($product_tco_category['id'])->find();
|
||||||
|
if (empty($product_category)) {
|
||||||
|
throw new \Exception('官网未找到产品目录同步分类关联的分类');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($product)) {
|
||||||
|
$product = ProductModel::create([
|
||||||
|
'language_id' => $lang_id,
|
||||||
|
'category_id' => $product_category['id'],
|
||||||
|
'spu' => $data['spu'],
|
||||||
|
'name' => $data['name'],
|
||||||
|
'short_name' => '',
|
||||||
|
'cover_image' => '',
|
||||||
|
'desc' => '',
|
||||||
|
'video_img' => '',
|
||||||
|
'video_url' => '',
|
||||||
|
'is_sale' => 1,
|
||||||
|
'is_new' => 0,
|
||||||
|
'is_hot' => 0,
|
||||||
|
'is_show' => 0,
|
||||||
|
'sort' => 0,
|
||||||
|
'detail' => '',
|
||||||
|
'status' => Operate_Of_ReceiveSync::Disable == $data['operate'] ? -1 : 1,
|
||||||
|
'seo_title' => '',
|
||||||
|
'seo_keywords' => '',
|
||||||
|
'seo_desc' => '',
|
||||||
|
'updated_at' => $data['created_at'],
|
||||||
|
]);
|
||||||
|
if ($product->isEmpty()) {
|
||||||
|
throw new \Exception('产品创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strtotime($product['updated_at']) < strtotime($data['created_at'])) {
|
||||||
|
$product->spu = $data['spu'];
|
||||||
|
$product->name = $data['name'];
|
||||||
|
$product->category_id = $product_category['id'];
|
||||||
|
$product->status = Operate_Of_ReceiveSync::Disable == $data['operate'] ? -1 : 1;
|
||||||
|
if (!$product->save()) {
|
||||||
|
throw new \Exception('产品更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
return error(sprintf('%s %s:%d', $th->getMessage(), $th->getFile(), $th->getLine()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('同步成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
139
app/admin/controller/v1/Agent.php
Normal file
139
app/admin/controller/v1/Agent.php
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\AgentEnterpriseSizeTypeModel;
|
||||||
|
use app\admin\model\v1\AgentModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代理商数据控制器
|
||||||
|
*/
|
||||||
|
class Agent
|
||||||
|
{
|
||||||
|
// 企业规模列表
|
||||||
|
public function enterpriseSizeTypes()
|
||||||
|
{
|
||||||
|
$types = AgentEnterpriseSizeTypeModel::field([
|
||||||
|
'name',
|
||||||
|
'value'
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
return success('获取成功', $types);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'corp_name',
|
||||||
|
'size_type',
|
||||||
|
'created_at',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$agents = AgentModel::field([
|
||||||
|
'id',
|
||||||
|
'ip',
|
||||||
|
'corp_name',
|
||||||
|
'email',
|
||||||
|
'phone',
|
||||||
|
'business_type',
|
||||||
|
'enterprise_size',
|
||||||
|
'address',
|
||||||
|
'message',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->with([
|
||||||
|
'businessType' => function ($query) {
|
||||||
|
$query->field(['name' => 'business_type_name', 'value']);
|
||||||
|
},
|
||||||
|
'enterpriseSizeType' => function ($query) {
|
||||||
|
$query->field(['name' => 'enterprise_size_name', 'value']);
|
||||||
|
}
|
||||||
|
])
|
||||||
|
->withSearch(['corp_name', 'created_at'], [
|
||||||
|
'corp_name' => $param['corp_name'] ?? null,
|
||||||
|
'created_at' => !empty($param['created_at']) ? explode(',', $param['created_at']) : null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->enterpriseSize($param['size_type'] ?? null)
|
||||||
|
->order(['id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page'],
|
||||||
|
])
|
||||||
|
->bindAttr('businessType', ['business_type_name'])
|
||||||
|
->bindAttr('enterpriseSizeType', ['enterprise_size_name'])
|
||||||
|
->hidden(['business_type', 'businessType', 'enterprise_size', 'enterpriseSizeType']);
|
||||||
|
|
||||||
|
return success('获取成功', $agents);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
public function export()
|
||||||
|
{
|
||||||
|
$schema = [
|
||||||
|
'id' => 'ID',
|
||||||
|
'created_at' => '提交时间',
|
||||||
|
'ip' => 'IP',
|
||||||
|
'corp_name' => '公司名称',
|
||||||
|
'email' => '邮箱',
|
||||||
|
'phone' => '手机号',
|
||||||
|
'business_type_name' => '业务类型',
|
||||||
|
'enterprise_size_name' => '企业规模',
|
||||||
|
'address' => '公司地址',
|
||||||
|
'message' => '留言内容'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 获取要导出的代理商数据
|
||||||
|
$agents = $this->getAgentExportData();
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
return xlsx_writer($agents, $schema, '代理商申请列表' . date('YmdHis'));
|
||||||
|
}
|
||||||
|
// 获取要导出的代理商数据
|
||||||
|
private function getAgentExportData()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'corp_name',
|
||||||
|
'size_type',
|
||||||
|
'created_at'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return AgentModel::field([
|
||||||
|
'id',
|
||||||
|
'ip',
|
||||||
|
'corp_name',
|
||||||
|
'email',
|
||||||
|
'phone',
|
||||||
|
'business_type',
|
||||||
|
'enterprise_size',
|
||||||
|
'address',
|
||||||
|
'message',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->with([
|
||||||
|
'businessType' => function ($query) {
|
||||||
|
$query->field(['name' => 'business_type_name', 'value']);
|
||||||
|
},
|
||||||
|
'enterpriseSizeType' => function ($query) {
|
||||||
|
$query->field(['name' => 'enterprise_size_name', 'value']);
|
||||||
|
}
|
||||||
|
])
|
||||||
|
->withSearch(['corp_name', 'created_at'], [
|
||||||
|
'corp_name' => $param['corp_name'] ?? null,
|
||||||
|
'created_at' => !empty($param['created_at']) ? explode(',', $param['created_at']) : null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->enterpriseSize($param['size_type'] ?? null)
|
||||||
|
->order(['id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
->bindAttr('businessType', ['business_type_name'])
|
||||||
|
->bindAttr('enterpriseSizeType', ['enterprise_size_name'])
|
||||||
|
->hidden(['business_type', 'businessType', 'enterprise_size', 'enterpriseSizeType']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,10 @@ namespace app\admin\controller\v1;
|
|||||||
|
|
||||||
use app\admin\model\v1\ArticleModel;
|
use app\admin\model\v1\ArticleModel;
|
||||||
use app\admin\validate\v1\ArticleValidate;
|
use app\admin\validate\v1\ArticleValidate;
|
||||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
|
||||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文章管理控制器
|
||||||
|
*/
|
||||||
class Article
|
class Article
|
||||||
{
|
{
|
||||||
// 文章列表
|
// 文章列表
|
||||||
@@ -16,7 +17,7 @@ class Article
|
|||||||
$param = request()->param([
|
$param = request()->param([
|
||||||
'title',
|
'title',
|
||||||
'category_id',
|
'category_id',
|
||||||
'created_at',
|
'release_time',
|
||||||
'page/d' => 1,
|
'page/d' => 1,
|
||||||
'size/d' => 10,
|
'size/d' => 10,
|
||||||
]);
|
]);
|
||||||
@@ -38,21 +39,17 @@ class Article
|
|||||||
->language(request()->lang_id)
|
->language(request()->lang_id)
|
||||||
->where(function($query) use($param) {
|
->where(function($query) use($param) {
|
||||||
if (isset($param['category_id'])) {
|
if (isset($param['category_id'])) {
|
||||||
|
if (str_contains($param['category_id'], ',') || is_array($param['category_id'])) {
|
||||||
|
$query->whereIn('category_id', $param['category_id']);
|
||||||
|
} else {
|
||||||
$query->where('category_id', '=', $param['category_id']);
|
$query->where('category_id', '=', $param['category_id']);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
->withSearch(['title', 'created_at'], (function() use($param) {
|
->withSearch(['title', 'release_time'], [
|
||||||
$condition = [];
|
'title' => $param['title']??null,
|
||||||
if (isset($param['title'])) {
|
'release_time' => !empty($param['release_time']) ? explode(',', $param['release_time']) : null
|
||||||
$condition['title'] = $param['title'];
|
])
|
||||||
}
|
|
||||||
if (isset($param['created_at'])) {
|
|
||||||
$condition = [
|
|
||||||
'created_at' => explode(',', $param['created_at'])
|
|
||||||
];
|
|
||||||
}
|
|
||||||
return $condition;
|
|
||||||
})())
|
|
||||||
->order('sort', 'desc')
|
->order('sort', 'desc')
|
||||||
->paginate([
|
->paginate([
|
||||||
'page' => $param['page'],
|
'page' => $param['page'],
|
||||||
@@ -62,7 +59,8 @@ class Article
|
|||||||
'category',
|
'category',
|
||||||
'category_id'
|
'category_id'
|
||||||
])
|
])
|
||||||
->bindAttr('category', ['category_name' => 'name']);
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
|
->each(fn($item) => $item->image = thumb($item->image));
|
||||||
|
|
||||||
return success('获取成功', $article);
|
return success('获取成功', $article);
|
||||||
}
|
}
|
||||||
@@ -70,13 +68,18 @@ class Article
|
|||||||
// 文章详情
|
// 文章详情
|
||||||
public function read()
|
public function read()
|
||||||
{
|
{
|
||||||
$article = ArticleModel::withoutField([
|
$article = ArticleModel::with(['category' => function($query) {
|
||||||
|
$query->field(['id', 'name' => 'category_name']);
|
||||||
|
}])
|
||||||
|
->withoutField([
|
||||||
'language_id',
|
'language_id',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
'deleted_at',
|
'deleted_at',
|
||||||
])
|
])
|
||||||
->id(request()->param('id'))
|
->bypk(request()->param('id'))
|
||||||
->find();
|
->find()
|
||||||
|
?->bindAttr('category', ['category_name'])
|
||||||
|
->hidden(['category']);
|
||||||
if (is_null($article)) {
|
if (is_null($article)) {
|
||||||
return error('文章不存在');
|
return error('文章不存在');
|
||||||
}
|
}
|
||||||
@@ -143,7 +146,7 @@ class Article
|
|||||||
return error($validate->getError());
|
return error($validate->getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
$article = ArticleModel::id($id)->find();
|
$article = ArticleModel::bypk($id)->find();
|
||||||
if (is_null($article)) {
|
if (is_null($article)) {
|
||||||
return error('请确认操作对象是否存在');
|
return error('请确认操作对象是否存在');
|
||||||
}
|
}
|
||||||
@@ -154,11 +157,31 @@ class Article
|
|||||||
return success('操作成功');
|
return success('操作成功');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置排序值
|
||||||
|
public function sort()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$sort = request()->post('sort');
|
||||||
|
|
||||||
|
$article = ArticleModel::bypk($id)->find();
|
||||||
|
if (empty($article)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
if ($sort != $article->sort) {
|
||||||
|
$article->sort = $sort;
|
||||||
|
if (!$article->save()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
// 删除文章
|
// 删除文章
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
$id = request()->param('id');
|
$id = request()->param('id');
|
||||||
$article = ArticleModel::id($id)->find();
|
$article = ArticleModel::bypk($id)->find();
|
||||||
if (is_null($article)) {
|
if (is_null($article)) {
|
||||||
return error('请确认操作对象是否存在');
|
return error('请确认操作对象是否存在');
|
||||||
}
|
}
|
||||||
@@ -174,13 +197,13 @@ class Article
|
|||||||
{
|
{
|
||||||
$schema = [
|
$schema = [
|
||||||
'id' => 'ID',
|
'id' => 'ID',
|
||||||
'category_name' => '分类名称',
|
'category_name' => '文章分类',
|
||||||
'title' => '标题',
|
'title' => '文章名称',
|
||||||
'author' => '作者',
|
'author' => '作者',
|
||||||
'source' => '来源',
|
'source' => '来源',
|
||||||
'image' => '封面图片',
|
'image' => '封面图片',
|
||||||
'link' => '外链',
|
'link' => '跳转链接',
|
||||||
'desc' => '描述',
|
'desc' => '文章描述',
|
||||||
'content' => '内容详情',
|
'content' => '内容详情',
|
||||||
'recommend' => '是否推荐',
|
'recommend' => '是否推荐',
|
||||||
'sort' => '排序值',
|
'sort' => '排序值',
|
||||||
@@ -189,7 +212,6 @@ class Article
|
|||||||
'seo_title' => 'seo标题',
|
'seo_title' => 'seo标题',
|
||||||
'seo_keywords' => 'seo关键词',
|
'seo_keywords' => 'seo关键词',
|
||||||
'seo_desc' => 'seo描述',
|
'seo_desc' => 'seo描述',
|
||||||
'enabled' => '是否启用',
|
|
||||||
'release_time' => '发布时间',
|
'release_time' => '发布时间',
|
||||||
'created_at' => '添加时间',
|
'created_at' => '添加时间',
|
||||||
'updated_at' => '最后更新时间'
|
'updated_at' => '最后更新时间'
|
||||||
@@ -198,62 +220,29 @@ class Article
|
|||||||
// 获取导出数据
|
// 获取导出数据
|
||||||
$data = $this->getExportArticleData();
|
$data = $this->getExportArticleData();
|
||||||
|
|
||||||
// 获取Spreadsheet对象
|
// 导出
|
||||||
$spreadsheet = new Spreadsheet();
|
return xlsx_writer($data, $schema, '文章列表' . date('YmdHis'));
|
||||||
$sheet = $spreadsheet->getActiveSheet();
|
|
||||||
|
|
||||||
// 写入表头
|
|
||||||
$title = array_values($schema);
|
|
||||||
$title_col = 'A';
|
|
||||||
foreach ($title as $value) {
|
|
||||||
// 单元格内容写入
|
|
||||||
$sheet->setCellValue($title_col . '1', $value);
|
|
||||||
$title_col++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写入数据
|
|
||||||
$row = 2;
|
|
||||||
$keys = array_keys($schema);
|
|
||||||
foreach ($data as $item) {
|
|
||||||
$data_col = 'A';
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
$sheet->setCellValue($data_col . $row, $item[$key]);
|
|
||||||
$data_col++;
|
|
||||||
}
|
|
||||||
$row++;
|
|
||||||
}
|
|
||||||
|
|
||||||
flush();
|
|
||||||
ob_flush();
|
|
||||||
$filename = date('YmdHms');
|
|
||||||
header('Access-Control-Expose-Headers: Content-Disposition');
|
|
||||||
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; Charset=UTF-8');
|
|
||||||
header('Content-Disposition: attachment;filename=' . $filename . '.xlsx');
|
|
||||||
header('Cache-Control: max-age=0');
|
|
||||||
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
|
|
||||||
$writer->save('php://output');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取文章导出数据
|
// 获取文章导出数据
|
||||||
private function getExportArticleData()
|
private function getExportArticleData()
|
||||||
{
|
{
|
||||||
$server = request()->server();
|
$server = request()->server();
|
||||||
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . config('filesystem.disks.public.url') . '/';
|
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . '/';
|
||||||
$param = request()->param(['title', 'category_id', 'created_at']);
|
$param = request()->param(['title', 'category_id', 'release_time']);
|
||||||
$data = ArticleModel::field([
|
$data = ArticleModel::field([
|
||||||
'*',
|
'*',
|
||||||
'CONCAT("' . $image_host . '", `image`)' => 'image',
|
'image',
|
||||||
'CASE WHEN recommend = 1 THEN "是" ELSE "否" END' => 'recommend',
|
'CASE WHEN recommend = 1 THEN "是" ELSE "否" END' => 'recommend'
|
||||||
'CASE WHEN enabled = 1 THEN "是" ELSE "否" END' => 'enabled',
|
|
||||||
])
|
])
|
||||||
->with('category', function($query) {
|
->with('category', function($query) {
|
||||||
return $query->field(['id', 'name']);
|
return $query->field(['id', 'name']);
|
||||||
})
|
})
|
||||||
->language(request()->lang_id)
|
->language(request()->lang_id)
|
||||||
->categoryNullable($param['category_id']??null)
|
->categoryNullable($param['category_id']??null)
|
||||||
->withSearch(['title', 'created_at'], [
|
->withSearch(['title', 'release_time'], [
|
||||||
'title' => $param['title']??'',
|
'title' => $param['title']??null,
|
||||||
'created_at' => !empty($param['created_at'])?explode(',', $param['created_at']):''
|
'release_time' => !empty($param['release_time'])?explode(',', $param['release_time']):null
|
||||||
])
|
])
|
||||||
->order('sort', 'desc')
|
->order('sort', 'desc')
|
||||||
->select()
|
->select()
|
||||||
@@ -262,7 +251,11 @@ class Article
|
|||||||
'category_id',
|
'category_id',
|
||||||
'category',
|
'category',
|
||||||
])
|
])
|
||||||
->bindAttr('category', ['category_name' => 'name']);
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
|
->each(function ($item) use($image_host) {
|
||||||
|
$item->image = !empty($item->image) ? url_join($image_host, $item->image) : '';
|
||||||
|
return $item;
|
||||||
|
});
|
||||||
|
|
||||||
return $data->toArray();
|
return $data->toArray();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,38 +6,46 @@ namespace app\admin\controller\v1;
|
|||||||
use app\admin\model\v1\ArticleCategoryModel;
|
use app\admin\model\v1\ArticleCategoryModel;
|
||||||
use app\admin\validate\v1\ArticleCategoryValidate;
|
use app\admin\validate\v1\ArticleCategoryValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文章分类管理控制器
|
||||||
|
*/
|
||||||
class ArticleCategory
|
class ArticleCategory
|
||||||
{
|
{
|
||||||
// 分类列表
|
// 分类列表
|
||||||
public function list()
|
public function list()
|
||||||
{
|
{
|
||||||
$param = request()->param(['name' => '']);
|
$param = request()->param([
|
||||||
|
'name' => '',
|
||||||
|
'is_show',
|
||||||
|
]);
|
||||||
$categorys = ArticleCategoryModel::field([
|
$categorys = ArticleCategoryModel::field([
|
||||||
'id',
|
'id',
|
||||||
|
'pid',
|
||||||
'name'
|
'name'
|
||||||
])
|
])
|
||||||
->language(request()->lang_id)
|
->language(request()->lang_id)
|
||||||
->withSearch(['name'], ['name' => $param['name']])
|
->withSearch(['name'], ['name' => $param['name']])
|
||||||
|
->where(function($query) use($param) {
|
||||||
|
if (isset($param['is_show'])) {
|
||||||
|
$query->where('is_show', '=', $param['is_show']);
|
||||||
|
}
|
||||||
|
})
|
||||||
->order('sort', 'asc')
|
->order('sort', 'asc')
|
||||||
->select();
|
->select();
|
||||||
return success('获取成功', $categorys);
|
|
||||||
|
return success('获取成功',array_to_tree($categorys->toArray(), 0, 'pid', 1, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分类分页列表
|
// 分类分页列表
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$param = request()->param([
|
$param = request()->param([
|
||||||
'name',
|
'name'
|
||||||
'page/d' => 1,
|
|
||||||
'limit/d' => 10,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$category = ArticleCategoryModel::withoutField([
|
$category = ArticleCategoryModel::withoutField([
|
||||||
'language_id',
|
'language_id',
|
||||||
'deleted_at',
|
'deleted_at'
|
||||||
'seo_title',
|
|
||||||
'seo_keywords',
|
|
||||||
'seo_desc',
|
|
||||||
])
|
])
|
||||||
->language(request()->lang_id)
|
->language(request()->lang_id)
|
||||||
->where(function($query) use($param) {
|
->where(function($query) use($param) {
|
||||||
@@ -46,20 +54,17 @@ class ArticleCategory
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
->order('sort', 'asc')
|
->order('sort', 'asc')
|
||||||
->paginate([
|
->select();
|
||||||
'page' => $param['page'],
|
|
||||||
'list_rows' => $param['limit']
|
|
||||||
]);
|
|
||||||
|
|
||||||
return success('获取成功', $category);
|
return success('获取成功', array_to_tree($category->toArray(), 0, 'pid', 1, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分类详情
|
// 分类详情
|
||||||
public function read()
|
public function read()
|
||||||
{
|
{
|
||||||
$id = request()->param('id');
|
$id = request()->param('id');
|
||||||
$category = ArticleCategoryModel::where('id', '=', $id)
|
$category = ArticleCategoryModel::withoutField(['language_id', 'deleted_at'])
|
||||||
->withoutField(['language_id', 'deleted_at'])
|
->bypk($id)
|
||||||
->find();
|
->find();
|
||||||
if (is_null($category)) {
|
if (is_null($category)) {
|
||||||
return error('文章分类不存在');
|
return error('文章分类不存在');
|
||||||
@@ -71,17 +76,20 @@ class ArticleCategory
|
|||||||
public function save()
|
public function save()
|
||||||
{
|
{
|
||||||
$post = request()->post([
|
$post = request()->post([
|
||||||
|
'unique_label',
|
||||||
'name',
|
'name',
|
||||||
|
'icon',
|
||||||
|
'pid',
|
||||||
'sort' => 0,
|
'sort' => 0,
|
||||||
'is_show' => 1,
|
'is_show' => 1
|
||||||
'seo_title',
|
|
||||||
'seo_keywords',
|
|
||||||
'seo_desc',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
$data = array_merge($post, [
|
||||||
|
'language_id' => request()->lang_id,
|
||||||
|
'unique_label' => $post['unique_label'] ?? uniqid('BANNER_')
|
||||||
|
]);
|
||||||
$valiate = new ArticleCategoryValidate;
|
$valiate = new ArticleCategoryValidate;
|
||||||
if (!$valiate->check($data)) {
|
if (!$valiate->scene('add')->check($data)) {
|
||||||
return error($valiate->getError());
|
return error($valiate->getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,21 +106,20 @@ class ArticleCategory
|
|||||||
$id = request()->param('id');
|
$id = request()->param('id');
|
||||||
$put = request()->put([
|
$put = request()->put([
|
||||||
'name',
|
'name',
|
||||||
|
'icon',
|
||||||
|
'pid',
|
||||||
'sort',
|
'sort',
|
||||||
'is_show',
|
'is_show'
|
||||||
'seo_title',
|
|
||||||
'seo_keywords',
|
|
||||||
'seo_desc',
|
|
||||||
]);
|
]);
|
||||||
$data = array_merge($put, ['language_id' => request()->lang_id]);
|
$data = array_merge($put, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
$valiate = new ArticleCategoryValidate;
|
$valiate = new ArticleCategoryValidate;
|
||||||
if (!$valiate->check(array_merge($data, ['id' => $id]))) {
|
if (!$valiate->scene('edit')->check(array_merge($data, ['id' => $id]))) {
|
||||||
return error($valiate->getError());
|
return error($valiate->getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
$category = ArticleCategoryModel::where('id', '=', $id)->find();
|
$category = ArticleCategoryModel::bypk($id)->find();
|
||||||
if (is_null($category)) {
|
if (empty($category)) {
|
||||||
return error('请确认操作对象是否存在');
|
return error('请确认操作对象是否存在');
|
||||||
}
|
}
|
||||||
if (!$category->save($data)) {
|
if (!$category->save($data)) {
|
||||||
@@ -122,11 +129,31 @@ class ArticleCategory
|
|||||||
return success('操作成功');
|
return success('操作成功');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置排序值
|
||||||
|
public function sort()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$sort = request()->post('sort');
|
||||||
|
|
||||||
|
$category = ArticleCategoryModel::bypk($id)->find();
|
||||||
|
if (empty($category)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
if ($sort != $category->sort) {
|
||||||
|
$category->sort = $sort;
|
||||||
|
if (!$category->save()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
// 删除分类
|
// 删除分类
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
$id = request()->param('id');
|
$id = request()->param('id');
|
||||||
$category = ArticleCategoryModel::where('id', '=', $id)->find();
|
$category = ArticleCategoryModel::bypk($id)->find();
|
||||||
if (is_null($category)) {
|
if (is_null($category)) {
|
||||||
return error('请确认操作对象是否存在');
|
return error('请确认操作对象是否存在');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ declare (strict_types = 1);
|
|||||||
namespace app\admin\controller\v1;
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
use app\admin\model\v1\ArticleLeaveMessageModel;
|
use app\admin\model\v1\ArticleLeaveMessageModel;
|
||||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
|
||||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文章留言(评论)管理控制器
|
||||||
|
*/
|
||||||
class ArticleLeaveMessage
|
class ArticleLeaveMessage
|
||||||
{
|
{
|
||||||
// 文章留言分页列表
|
// 文章留言分页列表
|
||||||
@@ -56,7 +57,7 @@ class ArticleLeaveMessage
|
|||||||
$id = request()->param('id');
|
$id = request()->param('id');
|
||||||
|
|
||||||
// 审核/反审核
|
// 审核/反审核
|
||||||
$message = ArticleLeaveMessageModel::id($id)->find();
|
$message = ArticleLeaveMessageModel::bypk($id)->find();
|
||||||
if (is_null($message)) {
|
if (is_null($message)) {
|
||||||
return error('请确认操作对象');
|
return error('请确认操作对象');
|
||||||
}
|
}
|
||||||
@@ -75,7 +76,7 @@ class ArticleLeaveMessage
|
|||||||
$id = request()->param('id');
|
$id = request()->param('id');
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
$message = ArticleLeaveMessageModel::id($id)->find();
|
$message = ArticleLeaveMessageModel::bypk($id)->find();
|
||||||
if (is_null($message)) {
|
if (is_null($message)) {
|
||||||
return error('请确认操作对象');
|
return error('请确认操作对象');
|
||||||
}
|
}
|
||||||
@@ -103,40 +104,8 @@ class ArticleLeaveMessage
|
|||||||
// 获取导出数据
|
// 获取导出数据
|
||||||
$data = $this->getExportMessageData();
|
$data = $this->getExportMessageData();
|
||||||
|
|
||||||
// 获取Spreadsheet对象
|
// 导出
|
||||||
$spreadsheet = new Spreadsheet();
|
return xlsx_writer($data, $schema, '文章评论列表' . date('YmdHis'));
|
||||||
$sheet = $spreadsheet->getActiveSheet();
|
|
||||||
|
|
||||||
// 写入表头
|
|
||||||
$title = array_values($schema);
|
|
||||||
$title_col = 'A';
|
|
||||||
foreach ($title as $value) {
|
|
||||||
// 单元格内容写入
|
|
||||||
$sheet->setCellValue($title_col . '1', $value);
|
|
||||||
$title_col++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写入数据
|
|
||||||
$row = 2;
|
|
||||||
$keys = array_keys($schema);
|
|
||||||
foreach ($data as $item) {
|
|
||||||
$data_col = 'A';
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
$sheet->setCellValue($data_col . $row, $item[$key]);
|
|
||||||
$data_col++;
|
|
||||||
}
|
|
||||||
$row++;
|
|
||||||
}
|
|
||||||
|
|
||||||
flush();
|
|
||||||
ob_flush();
|
|
||||||
$filename = date('YmdHms');
|
|
||||||
header('Access-Control-Expose-Headers: Content-Disposition');
|
|
||||||
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; Charset=UTF-8');
|
|
||||||
header('Content-Disposition: attachment;filename=' . $filename . '.xlsx');
|
|
||||||
header('Cache-Control: max-age=0');
|
|
||||||
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
|
|
||||||
$writer->save('php://output');
|
|
||||||
}
|
}
|
||||||
private function getExportMessageData()
|
private function getExportMessageData()
|
||||||
{
|
{
|
||||||
@@ -146,7 +115,7 @@ class ArticleLeaveMessage
|
|||||||
'CASE WHEN is_audited = 1 THEN "已审核" ELSE "未审核" END' => 'is_audited'
|
'CASE WHEN is_audited = 1 THEN "已审核" ELSE "未审核" END' => 'is_audited'
|
||||||
])
|
])
|
||||||
->withJoin(['article' => function($query) use($param) {
|
->withJoin(['article' => function($query) use($param) {
|
||||||
$query->where('article.language_id', '=', $param['lang_id']);
|
$query->where('article.language_id', '=', request()->lang_id);
|
||||||
if (!empty($param['title'])) {
|
if (!empty($param['title'])) {
|
||||||
$query->where('article.title', 'like', '%' . $param['title'] . '%');
|
$query->where('article.title', 'like', '%' . $param['title'] . '%');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ namespace app\admin\controller\v1;
|
|||||||
|
|
||||||
use app\admin\model\v1\ArticleModel;
|
use app\admin\model\v1\ArticleModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文章回收站管理控制器
|
||||||
|
*/
|
||||||
class ArticleTrash
|
class ArticleTrash
|
||||||
{
|
{
|
||||||
// 文章回收站分页列表
|
// 文章回收站分页列表
|
||||||
@@ -24,7 +27,6 @@ class ArticleTrash
|
|||||||
'sort',
|
'sort',
|
||||||
'recommend',
|
'recommend',
|
||||||
'release_time',
|
'release_time',
|
||||||
'enabled',
|
|
||||||
])
|
])
|
||||||
->with('category')
|
->with('category')
|
||||||
->language(request()->lang_id)
|
->language(request()->lang_id)
|
||||||
@@ -37,7 +39,8 @@ class ArticleTrash
|
|||||||
'list_rows' => $param['size']
|
'list_rows' => $param['size']
|
||||||
])
|
])
|
||||||
->hidden(['category_id', 'category'])
|
->hidden(['category_id', 'category'])
|
||||||
->bindAttr('category', ['category_name' => 'name']);
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
|
?->each(fn($item) => $item->image = thumb($item->image));
|
||||||
|
|
||||||
return success('获取成功', $data);
|
return success('获取成功', $data);
|
||||||
}
|
}
|
||||||
@@ -50,7 +53,7 @@ class ArticleTrash
|
|||||||
return error('参数错误');
|
return error('参数错误');
|
||||||
}
|
}
|
||||||
|
|
||||||
$article = ArticleModel::onlyTrashed()->id($id)->find();
|
$article = ArticleModel::onlyTrashed()->bypk($id)->find();
|
||||||
if (is_null($article)) {
|
if (is_null($article)) {
|
||||||
return error('请确认操作对象');
|
return error('请确认操作对象');
|
||||||
}
|
}
|
||||||
@@ -69,7 +72,7 @@ class ArticleTrash
|
|||||||
return error('参数错误');
|
return error('参数错误');
|
||||||
}
|
}
|
||||||
|
|
||||||
$article = ArticleModel::onlyTrashed()->id($id)->find();
|
$article = ArticleModel::onlyTrashed()->bypk($id)->find();
|
||||||
if (is_null($article)) {
|
if (is_null($article)) {
|
||||||
return error('请确认操作对象');
|
return error('请确认操作对象');
|
||||||
}
|
}
|
||||||
|
|||||||
207
app/admin/controller/v1/Attachment.php
Normal file
207
app/admin/controller/v1/Attachment.php
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\AttachmentModel;
|
||||||
|
use app\admin\validate\v1\AttachmentValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件(下载管理)管理控制器
|
||||||
|
*/
|
||||||
|
class Attachment
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 分页数据
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$params = request()->param([
|
||||||
|
'name',
|
||||||
|
'category_id',
|
||||||
|
'created_at',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$attachments = AttachmentModel::field([
|
||||||
|
'id',
|
||||||
|
'image',
|
||||||
|
'name',
|
||||||
|
'category_id',
|
||||||
|
'sort',
|
||||||
|
'recommend',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->with(['category' => function ($query) {
|
||||||
|
$query->field(['id', 'name' => 'category_name']);
|
||||||
|
}])
|
||||||
|
->withSearch(['name', 'created_at'], [
|
||||||
|
'name' => $params['name']??null,
|
||||||
|
'created_at' => !empty($params['created_at']) ? explode(',', $params['created_at']) : null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->categoryId($params['category_id']??null)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $params['size'],
|
||||||
|
'page' => $params['page']
|
||||||
|
])
|
||||||
|
->bindAttr('category', ['category_name'])
|
||||||
|
->hidden(['category_id', 'category'])
|
||||||
|
?->each(fn($item) => $item->image = thumb($item->image));
|
||||||
|
|
||||||
|
return success('获取成功', $attachments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件详情
|
||||||
|
*/
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$attachment = AttachmentModel::with(['category' => function ($query) {
|
||||||
|
$query->field(['id', 'name' => 'category_name']);
|
||||||
|
}])
|
||||||
|
->field([
|
||||||
|
'id',
|
||||||
|
'category_id',
|
||||||
|
'name',
|
||||||
|
'desc',
|
||||||
|
'image',
|
||||||
|
'applicable_to',
|
||||||
|
'support_platform',
|
||||||
|
'attach',
|
||||||
|
'sort',
|
||||||
|
'recommend',
|
||||||
|
'seo_title',
|
||||||
|
'seo_keywords',
|
||||||
|
'seo_desc'
|
||||||
|
])
|
||||||
|
->bypk($id)
|
||||||
|
->find()
|
||||||
|
->bindAttr('category', ['category_name'])
|
||||||
|
->hidden(['category']);
|
||||||
|
if (empty($attachment)) {
|
||||||
|
return error('附件不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件添加
|
||||||
|
*/
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'name',
|
||||||
|
'desc',
|
||||||
|
'category_id',
|
||||||
|
'sort',
|
||||||
|
'recommend',
|
||||||
|
'image',
|
||||||
|
'applicable_to',
|
||||||
|
'support_platform',
|
||||||
|
'attach',
|
||||||
|
'seo_title',
|
||||||
|
'seo_keywords',
|
||||||
|
'seo_desc'
|
||||||
|
]);
|
||||||
|
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
|
$validate = new AttachmentValidate;
|
||||||
|
$data['attach'] = json_decode($data['attach'], true);
|
||||||
|
if (!$validate->scene('create')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachment = AttachmentModel::create($data);
|
||||||
|
if ($attachment->isEmpty()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件更新
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'name',
|
||||||
|
'desc',
|
||||||
|
'category_id',
|
||||||
|
'sort',
|
||||||
|
'recommend',
|
||||||
|
'image',
|
||||||
|
'applicable_to',
|
||||||
|
'support_platform',
|
||||||
|
'attach',
|
||||||
|
'seo_title',
|
||||||
|
'seo_keywords',
|
||||||
|
'seo_desc'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new AttachmentValidate;
|
||||||
|
$put['attach'] = json_decode($put['attach'], true);
|
||||||
|
if (!$validate->scene('update')->check(array_merge($put, ['id' => $id]))) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachment = AttachmentModel::bypk($id)->find();
|
||||||
|
if (empty($attachment)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$attachment->save($put)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置排序值
|
||||||
|
*/
|
||||||
|
public function sort()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$sort = request()->post('sort');
|
||||||
|
|
||||||
|
$validate = new AttachmentValidate;
|
||||||
|
if (!$validate->scene('sort')->check(['sort' => $sort])) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachment = AttachmentModel::bypk($id)->find();
|
||||||
|
if (empty($attachment)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachment->sort = $sort;
|
||||||
|
if (!$attachment->save()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件删除
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$attachment = AttachmentModel::bypk($id)->find();
|
||||||
|
if (empty($attachment)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$attachment->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
193
app/admin/controller/v1/AttachmentCategory.php
Normal file
193
app/admin/controller/v1/AttachmentCategory.php
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\AttachmentCategoryModel;
|
||||||
|
use app\admin\validate\v1\AttachmentCategoryValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件(下载管理)分类管理控制器
|
||||||
|
*/
|
||||||
|
class AttachmentCategory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 列表树形结构
|
||||||
|
*/
|
||||||
|
public function tree()
|
||||||
|
{
|
||||||
|
$params = request()->param([
|
||||||
|
'name',
|
||||||
|
'is_show'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$categorys = AttachmentCategoryModel::field([
|
||||||
|
'id',
|
||||||
|
'pid',
|
||||||
|
'name'
|
||||||
|
])
|
||||||
|
->withSearch(['name'], [
|
||||||
|
'name' => $params['name']??null
|
||||||
|
])
|
||||||
|
->where(function($query) use($params) {
|
||||||
|
if (isset($params['is_show'])) {
|
||||||
|
$query->where('is_show', '=', $params['is_show']);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return success('获取成功', array_to_tree($categorys->toArray(), 0, 'pid', 1, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页数据
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$params = request()->param([
|
||||||
|
'name'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$categorys = AttachmentCategoryModel::field([
|
||||||
|
'id',
|
||||||
|
'pid',
|
||||||
|
'name',
|
||||||
|
'sort',
|
||||||
|
'is_show'
|
||||||
|
])
|
||||||
|
->withSearch(['name'], [
|
||||||
|
'name' => $params['name']??null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return success('获取成功', array_to_tree($categorys->toArray(), 0, 'pid', 1, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件分类详情
|
||||||
|
*/
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$category = AttachmentCategoryModel::withoutField([
|
||||||
|
'language_id',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->bypk($id)
|
||||||
|
->find();
|
||||||
|
if (empty($category)) {
|
||||||
|
return error('分类不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $category);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件分类添加
|
||||||
|
*/
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'pid' => 0,
|
||||||
|
'name',
|
||||||
|
'sort',
|
||||||
|
'is_show'
|
||||||
|
]);
|
||||||
|
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
|
$validate = new AttachmentCategoryValidate;
|
||||||
|
if (!$validate->scene('create')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$category = AttachmentCategoryModel::create($data);
|
||||||
|
if ($category->isEmpty()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件分类更新
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'pid' => 0,
|
||||||
|
'name',
|
||||||
|
'sort',
|
||||||
|
'is_show'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new AttachmentCategoryValidate;
|
||||||
|
if (!$validate->scene('update')->check(array_merge($put, ['id' => $id]))) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$category = AttachmentCategoryModel::bypk($id)->find();
|
||||||
|
if (empty($category)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$category->save($put)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置排序值
|
||||||
|
*/
|
||||||
|
public function sort()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$sort = request()->param('sort');
|
||||||
|
|
||||||
|
$validate = new AttachmentCategoryValidate;
|
||||||
|
if (!$validate->scene('sort')->check(['sort' => $sort])) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$category = AttachmentCategoryModel::bypk($id)->find();
|
||||||
|
if (empty($category)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
$category->sort = $sort;
|
||||||
|
if (!$category->save()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件分类删除
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$category = AttachmentCategoryModel::bypk($id)->find();
|
||||||
|
if (empty($category)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查分类下是否存在附件
|
||||||
|
if (!$category->attachment()->count()) {
|
||||||
|
return error('分类下存在附件,请先删除附件');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$category->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
90
app/admin/controller/v1/AttachmentTrash.php
Normal file
90
app/admin/controller/v1/AttachmentTrash.php
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\AttachmentModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件(下载管理)回收站控制器
|
||||||
|
*/
|
||||||
|
class AttachmentTrash
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 分页数据
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$params = request()->param([
|
||||||
|
'name',
|
||||||
|
'category_id',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$attachments = AttachmentModel::field([
|
||||||
|
'id',
|
||||||
|
'image',
|
||||||
|
'name',
|
||||||
|
'category_id',
|
||||||
|
'sort',
|
||||||
|
'recommend',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->with(['category' => function ($query) {
|
||||||
|
$query->field(['id', 'name' => 'category_name']);
|
||||||
|
}])
|
||||||
|
->withSearch(['name'], [
|
||||||
|
'name' => $params['name']??null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->categoryId($params['category_id']??null)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->onlyTrashed()
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $params['size'],
|
||||||
|
'page' => $params['page']
|
||||||
|
])
|
||||||
|
->bindAttr('category', ['category_name'])
|
||||||
|
->hidden(['category_id', 'category'])
|
||||||
|
?->each(fn($item) => $item->image = thumb($item->image));
|
||||||
|
|
||||||
|
return success('获取成功', $attachments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复操作
|
||||||
|
*/
|
||||||
|
public function restore()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$attachment = AttachmentModel::onlyTrashed()->bypk($id)->find();
|
||||||
|
if (empty($attachment)) {
|
||||||
|
return error("请确认操作对象是否正确");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$attachment->restore()) {
|
||||||
|
return error("操作失败");
|
||||||
|
}
|
||||||
|
return success("操作成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除操作
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$attachment = AttachmentModel::onlyTrashed()->bypk($id)->find();
|
||||||
|
if (empty($attachment)) {
|
||||||
|
return error("请确认操作对象是否正确");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$attachment->force()->delete()) {
|
||||||
|
return error("操作失败");
|
||||||
|
}
|
||||||
|
return success("操作成功");
|
||||||
|
}
|
||||||
|
}
|
||||||
180
app/admin/controller/v1/Banner.php
Normal file
180
app/admin/controller/v1/Banner.php
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\SysBannerModel;
|
||||||
|
use app\admin\validate\v1\SysBannerValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 横幅(分类)模型
|
||||||
|
*/
|
||||||
|
class Banner
|
||||||
|
{
|
||||||
|
// 列表
|
||||||
|
public function list()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'name'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$banners = SysBannerModel::field([
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'at_platform'
|
||||||
|
])
|
||||||
|
->withSearch(['name'], [
|
||||||
|
'name' => $param['name'] ?? null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->enabled()
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
$datas = [];
|
||||||
|
if (!$banners->isEmpty()) {
|
||||||
|
$temp = [];
|
||||||
|
$map = ['pc' => ['id' => -1, 'name' => 'PC端'], 'mobile' => ['id' => -2, 'name' => '移动端']];
|
||||||
|
foreach ($banners as $banner) {
|
||||||
|
if (!isset($temp[$banner->at_platform])) {
|
||||||
|
$temp[$banner->at_platform] = [
|
||||||
|
'id' => $map[$banner->at_platform]['id'] ?? 0,
|
||||||
|
'name' => $map[$banner->at_platform]['name'] ?? '未知平台',
|
||||||
|
'children' => []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$temp[$banner->at_platform]['children'][] = [
|
||||||
|
'id' => $banner->id,
|
||||||
|
'name' => $banner->name
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$datas = array_values($temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $datas);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'name',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$banners = SysBannerModel::field([
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'recommend',
|
||||||
|
'at_platform',
|
||||||
|
'desc',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->withSearch(['name'], [
|
||||||
|
'name' => $param['name'] ?? null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page']
|
||||||
|
]);
|
||||||
|
|
||||||
|
return success('获取成功', $banners);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 详情
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$banner = SysBannerModel::withoutField([
|
||||||
|
'at_page',
|
||||||
|
'unique_label',
|
||||||
|
'language_id',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->bypk($id)
|
||||||
|
->find();
|
||||||
|
if (empty($banner)) {
|
||||||
|
return error('横幅(分类)不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $banner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'name',
|
||||||
|
'desc',
|
||||||
|
'recommend',
|
||||||
|
'unique_label',
|
||||||
|
'at_platform' => 'pc',
|
||||||
|
'status' => 1
|
||||||
|
]);
|
||||||
|
$data = array_merge($post, [
|
||||||
|
'language_id' => request()->lang_id,
|
||||||
|
'unique_label' => $post['unique_label'] ?? uniqid('BANNER_')
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new SysBannerValidate;
|
||||||
|
if (!$validate->scene('add')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$banner = SysBannerModel::create($data);
|
||||||
|
if ($banner->isEmpty()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'name',
|
||||||
|
'desc',
|
||||||
|
'recommend',
|
||||||
|
'at_platform' => 'pc',
|
||||||
|
'status' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new SysBannerValidate;
|
||||||
|
if (!$validate->scene('edit')->check(array_merge($put, ['id' => $id]))) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$banner = SysBannerModel::bypk($id)->find();
|
||||||
|
if (empty($banner)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$banner->save($put)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$banner = SysBannerModel::bypk($id)->find();
|
||||||
|
if (empty($banner)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$banner->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
336
app/admin/controller/v1/BannerItem.php
Normal file
336
app/admin/controller/v1/BannerItem.php
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\exception\InvalidOperateException;
|
||||||
|
use app\admin\model\v1\SysBannerItemModel;
|
||||||
|
use app\admin\model\v1\SysBannerProdCateMappingModel;
|
||||||
|
use app\admin\validate\v1\SysBannerItemValidate;
|
||||||
|
use think\facade\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 横幅数据项控制器
|
||||||
|
*/
|
||||||
|
class BannerItem
|
||||||
|
{
|
||||||
|
// 分页
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'title',
|
||||||
|
'banner_id',
|
||||||
|
'created_at',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$banner_items = SysBannerItemModel::alias('item')
|
||||||
|
->field([
|
||||||
|
'item.id',
|
||||||
|
'item.title',
|
||||||
|
'item.image',
|
||||||
|
'item.sort',
|
||||||
|
'item.status',
|
||||||
|
'item.created_at',
|
||||||
|
'bnr.name' => 'banner_name'
|
||||||
|
])
|
||||||
|
->join('sys_banner bnr', 'bnr.id = item.banner_id')
|
||||||
|
->where('bnr.language_id', '=', request()->lang_id)
|
||||||
|
->where(function($query) use($param){
|
||||||
|
if (!empty($param['banner_id'])) {
|
||||||
|
if (is_array($param['banner_id']) || str_contains($param['banner_id'], ',')) {
|
||||||
|
$query->whereIn('item.banner_id', $param['banner_id']);
|
||||||
|
} else {
|
||||||
|
$query->where('item.banner_id', '=', $param['banner_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($param['title'])) {
|
||||||
|
$query->where('item.title', 'like', "%{$param['title']}%");
|
||||||
|
}
|
||||||
|
if (!empty($param['created_at'])) {
|
||||||
|
$value = explode(',', $param['created_at']);
|
||||||
|
if (count($value) > 1) {
|
||||||
|
if ($value[1] == $value[0]) {
|
||||||
|
$value[1] = date('Y-m-d 23:59:59', strtotime($value[1]));
|
||||||
|
}
|
||||||
|
$query->whereBetweenTime('item.created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('item.created_at', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->order(['item.banner_id' => 'asc', 'item.sort' => 'asc', 'item.id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page']
|
||||||
|
])
|
||||||
|
->each(fn($item) => $item->image = thumb($item->image));
|
||||||
|
|
||||||
|
return success('获取成功', $banner_items);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 详情
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$banner_item = SysBannerItemModel::with('prodMapping.category')
|
||||||
|
->withoutField([
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->append(['rel_prod_cate_id', 'rel_prod_cate_name']) // 绑定产品分类关联模型中字段到父模型中
|
||||||
|
->find($id);
|
||||||
|
if (empty($banner_item)) {
|
||||||
|
return error('横幅不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组装用于前台回显的链接数据
|
||||||
|
$banner_item['link_echo_data'] = System::getEchoDataBySystemPageUrl($banner_item['link_to'], $banner_item['link']);
|
||||||
|
|
||||||
|
return success('获取成功', $banner_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'banner_id',
|
||||||
|
'rel_prod_cate_id',
|
||||||
|
'title',
|
||||||
|
'title_txt_color',
|
||||||
|
'desc',
|
||||||
|
'desc_txt_color',
|
||||||
|
'type',
|
||||||
|
'image',
|
||||||
|
'extra_image',
|
||||||
|
'video',
|
||||||
|
'link_to' => 'custom',
|
||||||
|
'link',
|
||||||
|
'sort',
|
||||||
|
'status' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new SysBannerItemValidate;
|
||||||
|
if (!$validate->scene('add')->check($post)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
SysBannerItemModel::startTrans();
|
||||||
|
try {
|
||||||
|
$banner_item = SysBannerItemModel::create($post);
|
||||||
|
if ($banner_item->isEmpty()) {
|
||||||
|
throw new InvalidOperateException('新增横幅失败');
|
||||||
|
}
|
||||||
|
if (!empty($post['rel_prod_cate_id'])) {
|
||||||
|
$mapping = SysBannerProdCateMappingModel::create([
|
||||||
|
'banner_item_id' => $banner_item->id,
|
||||||
|
'product_category_id' => $post['rel_prod_cate_id']
|
||||||
|
]);
|
||||||
|
if ($mapping->isEmpty()) {
|
||||||
|
throw new InvalidOperateException('新增横幅与产品分类关联失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SysBannerItemModel::commit();
|
||||||
|
} catch (InvalidOperateException $e) {
|
||||||
|
SysBannerItemModel::rollback();
|
||||||
|
return error($e->getMessage());
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
SysBannerItemModel::rollback();
|
||||||
|
Log::error(sprintf('%s:%s %s', $th->getFile(), $th->getLine(), $th->getMessage()));
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'banner_id',
|
||||||
|
'rel_prod_cate_id',
|
||||||
|
'title',
|
||||||
|
'title_txt_color',
|
||||||
|
'desc',
|
||||||
|
'desc_txt_color',
|
||||||
|
'type',
|
||||||
|
'image',
|
||||||
|
'extra_image',
|
||||||
|
'video',
|
||||||
|
'link_to',
|
||||||
|
'link',
|
||||||
|
'sort',
|
||||||
|
'status'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new SysBannerItemValidate;
|
||||||
|
if (!$validate->check(array_merge($put, ['id' => $id]))) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
SysBannerItemModel::startTrans();
|
||||||
|
try {
|
||||||
|
$banner_item = SysBannerItemModel::bypk($id)->find();
|
||||||
|
if (empty($banner_item)) {
|
||||||
|
throw new InvalidOperateException('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
if ($put['type'] == 'video') {
|
||||||
|
unset($put['link']);
|
||||||
|
unset($put['link_to']);
|
||||||
|
}
|
||||||
|
if (!$banner_item->save($put)) {
|
||||||
|
throw new InvalidOperateException('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新关联的产品分类
|
||||||
|
if (!empty($put['rel_prod_cate_id'])) {
|
||||||
|
SysBannerProdCateMappingModel::where('banner_item_id', '=', $id)->delete();
|
||||||
|
$mapping = SysBannerProdCateMappingModel::create([
|
||||||
|
'banner_item_id' => $id,
|
||||||
|
'product_category_id' => $put['rel_prod_cate_id']
|
||||||
|
]);
|
||||||
|
if ($mapping->isEmpty()) {
|
||||||
|
throw new InvalidOperateException('更新横幅与产品分类关联失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SysBannerItemModel::commit();
|
||||||
|
} catch (InvalidOperateException $e) {
|
||||||
|
SysBannerItemModel::rollback();
|
||||||
|
return error($e->getMessage());
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
SysBannerItemModel::rollback();
|
||||||
|
Log::error(sprintf('%s:%s %s', $th->getFile(), $th->getLine(), $th->getMessage()));
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置排序值
|
||||||
|
public function sort()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$sort = request()->param('sort');
|
||||||
|
|
||||||
|
$banner_item = SysBannerItemModel::bypk($id)->find();
|
||||||
|
if (empty($banner_item)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($banner_item->sort != $sort) {
|
||||||
|
$banner_item->sort = $sort;
|
||||||
|
if (!$banner_item->save()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
public function export()
|
||||||
|
{
|
||||||
|
$schema = [
|
||||||
|
'id' => 'ID',
|
||||||
|
'banner_name' => '分类名称',
|
||||||
|
'title' => '横幅名称',
|
||||||
|
'title_txt_color' => '横幅名称字体颜色',
|
||||||
|
'desc' => '描述',
|
||||||
|
'desc_txt_color' => '描述字体颜色',
|
||||||
|
'type' => '前台显示类型',
|
||||||
|
'image' => '图片地址',
|
||||||
|
'extra_image' => '额外图片地址',
|
||||||
|
'video' => '视频地址',
|
||||||
|
'link_to' => '链接类型',
|
||||||
|
'link' => '链接地址',
|
||||||
|
'sort' => '排序值',
|
||||||
|
'status' => '状态',
|
||||||
|
'created_at' => '添加时间'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 获取要导出的横幅项数据
|
||||||
|
$banner_items = $this->getBannerExportData();
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
return xlsx_writer($banner_items, $schema, 'banner列表' . date('YmdHis'));
|
||||||
|
}
|
||||||
|
// 获取导出数据
|
||||||
|
private function getBannerExportData()
|
||||||
|
{
|
||||||
|
$server = request()->server();
|
||||||
|
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . '/';
|
||||||
|
$param = request()->param(['title', 'banner_id', 'created_at']);
|
||||||
|
return SysBannerItemModel::alias('item')
|
||||||
|
->field([
|
||||||
|
'item.id',
|
||||||
|
'banner.name' => 'banner_name',
|
||||||
|
'item.title',
|
||||||
|
'item.title_txt_color',
|
||||||
|
'item.desc',
|
||||||
|
'item.desc_txt_color',
|
||||||
|
'item.type',
|
||||||
|
'item.image',
|
||||||
|
'item.extra_image',
|
||||||
|
'item.video',
|
||||||
|
'item.link_to',
|
||||||
|
'item.link',
|
||||||
|
'item.sort' ,
|
||||||
|
'item.status',
|
||||||
|
'item.created_at'
|
||||||
|
])
|
||||||
|
->join('sys_banner banner', 'banner.id = item.banner_id')
|
||||||
|
->where('banner.language_id', '=', request()->lang_id)
|
||||||
|
->where(function($query) use($param){
|
||||||
|
if (!empty($param['banner_id'])) {
|
||||||
|
if (is_array($param['banner_id']) || str_contains($param['banner_id'], ',')) {
|
||||||
|
$query->whereIn('item.banner_id', $param['banner_id']);
|
||||||
|
} else {
|
||||||
|
$query->where('item.banner_id', '=', $param['banner_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($param['title'])) {
|
||||||
|
$query->where('item.title', 'like', "%{$param['title']}%");
|
||||||
|
}
|
||||||
|
if (!empty($param['created_at'])) {
|
||||||
|
$value = explode(',', $param['created_at']);
|
||||||
|
if (count($value) > 1) {
|
||||||
|
if ($value[1] == $value[0]) {
|
||||||
|
$value[1] = date('Y-m-d 23:59:59', strtotime($value[1]));
|
||||||
|
}
|
||||||
|
$query->whereBetweenTime('item.created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('item.created_at', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->order(['item.sort' => 'asc', 'item.id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
->each(function($item) use($image_host) {
|
||||||
|
$item->image = !empty($item->image) ? url_join($image_host, $item->image) : '';
|
||||||
|
$item->extra_image = !empty($item->extra_image) ? url_join($image_host, $item->extra_image) : '';
|
||||||
|
$item->video = !empty($item->video) ? url_join($image_host, $item->video) : '';
|
||||||
|
return $item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$banner_item = SysBannerItemModel::bypk($id)->find();
|
||||||
|
if (empty($banner_item)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$banner_item->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
120
app/admin/controller/v1/BulkPurchaseInquiry.php
Normal file
120
app/admin/controller/v1/BulkPurchaseInquiry.php
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\BulkPurchaseInquiryModel;
|
||||||
|
use app\admin\model\v1\LanguageModel;
|
||||||
|
use app\admin\model\v1\SysConfigModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量采购询盘控制器
|
||||||
|
*/
|
||||||
|
class BulkPurchaseInquiry
|
||||||
|
{
|
||||||
|
// 采购可选品类
|
||||||
|
public function interested()
|
||||||
|
{
|
||||||
|
$config_name = 'bulk_purchase_inquiry_interested';
|
||||||
|
$config = SysConfigModel::hasWhere('group', function($query) {
|
||||||
|
$query->where('language_id', '=', request()->lang_id);
|
||||||
|
})
|
||||||
|
->byName($config_name)
|
||||||
|
->find();
|
||||||
|
if (empty($config)) {
|
||||||
|
return error('当前选定语言的采购可选品类配置出错');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', explode(',', preg_replace('/\r?\n/', ',', $config->value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'corp_name',
|
||||||
|
'interested',
|
||||||
|
'created_at',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$msgs = BulkPurchaseInquiryModel::field([
|
||||||
|
'id',
|
||||||
|
'ip',
|
||||||
|
'corp_name',
|
||||||
|
'first_name',
|
||||||
|
'last_name',
|
||||||
|
'email',
|
||||||
|
'phone',
|
||||||
|
'interested',
|
||||||
|
'message',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->withSearch(['corp_name', 'interested', 'created_at'], [
|
||||||
|
'corp_name' => $param['corp_name'] ?? null,
|
||||||
|
'interested' => $param['interested'] ?? null,
|
||||||
|
'created_at' => !empty($param['created_at']) ? explode(',', $param['created_at']) : null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return success('获取成功', $msgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
public function export()
|
||||||
|
{
|
||||||
|
$schema = [
|
||||||
|
'id' => 'ID',
|
||||||
|
'created_at' => '提交时间',
|
||||||
|
'ip' => 'IP',
|
||||||
|
'corp_name' => '公司名称',
|
||||||
|
'username' => '姓名',
|
||||||
|
'email' => '邮箱',
|
||||||
|
'phone' => '手机号码',
|
||||||
|
'interested' => '想采购的产品',
|
||||||
|
'message' => '询问内容',
|
||||||
|
];
|
||||||
|
|
||||||
|
// 获取要导出的采购询盘数据
|
||||||
|
$data = $this->getExportData();
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
return xlsx_writer($data, $schema, '批量购买询盘列表' . date('YmdHis'));
|
||||||
|
}
|
||||||
|
// 获取要导出的采购询盘数据
|
||||||
|
private function getExportData()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'corp_name',
|
||||||
|
'interested',
|
||||||
|
'created_at',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return BulkPurchaseInquiryModel::field([
|
||||||
|
'id',
|
||||||
|
'ip',
|
||||||
|
'corp_name',
|
||||||
|
'CONCAT(first_name, last_name)' => 'username',
|
||||||
|
'last_name',
|
||||||
|
'email',
|
||||||
|
'phone',
|
||||||
|
'interested',
|
||||||
|
'message',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->withSearch(['corp_name', 'interested', 'created_at'], [
|
||||||
|
'corp_name' => $param['corp_name'] ?? null,
|
||||||
|
'interested' => $param['interested'] ?? null,
|
||||||
|
'created_at' => !empty($param['created_at']) ? explode(',', $param['created_at']) : null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,9 @@ namespace app\admin\controller\v1;
|
|||||||
use think\facade\Cache;
|
use think\facade\Cache;
|
||||||
use think\facade\Config;
|
use think\facade\Config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码控制器
|
||||||
|
*/
|
||||||
class Captcha
|
class Captcha
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|||||||
29
app/admin/controller/v1/Country.php
Normal file
29
app/admin/controller/v1/Country.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\CountryModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国家列表控制器
|
||||||
|
*/
|
||||||
|
class Country
|
||||||
|
{
|
||||||
|
// 获取国家列表
|
||||||
|
public function list()
|
||||||
|
{
|
||||||
|
$country = CountryModel::field([
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'en_name',
|
||||||
|
])
|
||||||
|
->withSearch(['name'], [
|
||||||
|
'name' => request()->param('name') ?? null
|
||||||
|
])
|
||||||
|
->order(['sort' => 'asc', 'id' => 'asc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return success('获取成功', $country);
|
||||||
|
}
|
||||||
|
}
|
||||||
155
app/admin/controller/v1/Faq.php
Normal file
155
app/admin/controller/v1/Faq.php
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\FaqModel;
|
||||||
|
use app\admin\validate\v1\FaqValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 常见问题控制器
|
||||||
|
*/
|
||||||
|
class Faq
|
||||||
|
{
|
||||||
|
// 分页
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'question',
|
||||||
|
'created_at',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$faqs = FaqModel::field([
|
||||||
|
'id',
|
||||||
|
'image',
|
||||||
|
'question',
|
||||||
|
'recommend',
|
||||||
|
'sort',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->withSearch(['question', 'created_at'], [
|
||||||
|
'question' => $param['question'] ?? null,
|
||||||
|
'created_at' => !empty($param['created_at']) ? explode(',', $param['created_at']) : null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page'],
|
||||||
|
])
|
||||||
|
?->each(fn($item) => $item->image = thumb($item->image));
|
||||||
|
|
||||||
|
return success('获取成功', $faqs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 详情
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$faq = FaqModel::withoutField([
|
||||||
|
'language_id',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at',
|
||||||
|
])
|
||||||
|
->bypk($id)
|
||||||
|
->find();
|
||||||
|
if (empty($faq)) {
|
||||||
|
return error('数据不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $faq);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'question',
|
||||||
|
'image',
|
||||||
|
'recommend',
|
||||||
|
'sort',
|
||||||
|
'answer'
|
||||||
|
]);
|
||||||
|
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
|
$validate = new FaqValidate;
|
||||||
|
if (!$validate->scene('add')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$faq = FaqModel::create($data);
|
||||||
|
if ($faq->isEmpty()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'question',
|
||||||
|
'image',
|
||||||
|
'recommend',
|
||||||
|
'sort',
|
||||||
|
'answer'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new FaqValidate;
|
||||||
|
if (!$validate->scene('edit')->check(array_merge($put, ['id' => $id]))) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$faq = FaqModel::bypk($id)->find();
|
||||||
|
if (empty($faq)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$faq->save($put)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置排序值
|
||||||
|
public function sort()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$sort = request()->post('sort');
|
||||||
|
|
||||||
|
$faq = FaqModel::bypk($id)->find();
|
||||||
|
if (empty($faq)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($faq->sort != $sort) {
|
||||||
|
$faq->sort = $sort;
|
||||||
|
if (!$faq->save()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$faq = FaqModel::bypk($id)->find();
|
||||||
|
if (empty($faq)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$faq->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,74 +3,10 @@ declare (strict_types = 1);
|
|||||||
|
|
||||||
namespace app\admin\controller\v1;
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
use app\admin\model\v1\ImageModel;
|
/**
|
||||||
use Intervention\Image\ImageManager;
|
* 图片管理控制器
|
||||||
use think\facade\Filesystem;
|
*/
|
||||||
|
|
||||||
class Images
|
class Images
|
||||||
{
|
{
|
||||||
// 上传
|
|
||||||
public function upload()
|
|
||||||
{
|
|
||||||
$param = request()->param(['module' => 'unknown']);
|
|
||||||
if (is_null($param)) {
|
|
||||||
return error('请确定请求参数正确');
|
|
||||||
}
|
|
||||||
$file = request()->file('image');
|
|
||||||
if (is_null($file)) {
|
|
||||||
return error('请确定上传对象或字段是否正确');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$validate = validate([
|
|
||||||
'module' => 'require|max:64',
|
|
||||||
'image' => 'fileSize:1048576|fileExt:jpg,jpeg,png,gif'
|
|
||||||
]);
|
|
||||||
if (!$validate->check(['module' => $param['module'], 'image' => $file])) {
|
|
||||||
return error($validate->getError());
|
|
||||||
}
|
|
||||||
|
|
||||||
$storage = config('filesystem.disks.image.url');
|
|
||||||
|
|
||||||
$filemd5 = $file->md5();
|
|
||||||
$filesha1 = $file->sha1();
|
|
||||||
|
|
||||||
$image_model = ImageModel::md5($filemd5)->find();
|
|
||||||
if (is_null($image_model)) {
|
|
||||||
$filename = Filesystem::disk('image')->putFile($param['module'], $file);
|
|
||||||
// 生成缩略图
|
|
||||||
$image_manager = new ImageManager(new \Intervention\Image\Drivers\Gd\Driver());
|
|
||||||
$image = $image_manager->read('.' . $storage . '/' . $filename);
|
|
||||||
$image->scale(200, 200);
|
|
||||||
$idx = strrpos($filename, '.');
|
|
||||||
$thumb_filename = mb_substr($filename, 0, $idx) . '_thumb.' . mb_substr($filename, $idx + 1);
|
|
||||||
$image->save('.' . $storage . '/' . $thumb_filename);
|
|
||||||
|
|
||||||
// 保存图片
|
|
||||||
$image_model = new ImageModel();
|
|
||||||
$image_model->language_id = request()->lang_id;
|
|
||||||
$image_model->module = $param['module'];
|
|
||||||
$image_model->image_path = $filename;
|
|
||||||
$image_model->image_thumb = $thumb_filename;
|
|
||||||
$image_model->image_size = $file->getSize();
|
|
||||||
$image_model->image_type = $file->getOriginalMime();
|
|
||||||
$image_model->image_md5 = $filemd5;
|
|
||||||
$image_model->image_sha1 = $filesha1;
|
|
||||||
if (!$image_model->save()) {
|
|
||||||
return error('上传失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success('操作成功', [
|
|
||||||
'url' => $storage . '/' . $image_model->image_path,
|
|
||||||
'thumb_url' => $storage . '/' . $image_model->image_thumb,
|
|
||||||
'filemd5' => $image_model->image_md5,
|
|
||||||
'filesha1' => $image_model->image_sha1
|
|
||||||
]);
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
return error($th->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return error('上传失败');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ use app\admin\model\v1\LanguageModel;
|
|||||||
use think\facade\Cookie;
|
use think\facade\Cookie;
|
||||||
use think\facade\Log;
|
use think\facade\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语言管理控制器
|
||||||
|
*/
|
||||||
class Language
|
class Language
|
||||||
{
|
{
|
||||||
// 语言列表
|
// 语言列表
|
||||||
@@ -32,7 +35,7 @@ class Language
|
|||||||
public function cutover()
|
public function cutover()
|
||||||
{
|
{
|
||||||
$id = request()->param('id');
|
$id = request()->param('id');
|
||||||
$language = LanguageModel::id($id)->find();
|
$language = LanguageModel::bypk($id)->find();
|
||||||
if (is_null($language)) {
|
if (is_null($language)) {
|
||||||
return error('语言不存在');
|
return error('语言不存在');
|
||||||
}
|
}
|
||||||
|
|||||||
75
app/admin/controller/v1/LeaveMessage.php
Normal file
75
app/admin/controller/v1/LeaveMessage.php
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\LeaveMessageModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 留言记录(联系我们)控制器
|
||||||
|
*/
|
||||||
|
class LeaveMessage
|
||||||
|
{
|
||||||
|
// 分页
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'created_at',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$msgs = LeaveMessageModel::withoutField([
|
||||||
|
'language_id',
|
||||||
|
'user_agent'
|
||||||
|
])
|
||||||
|
->withSearch(['created_at'], [
|
||||||
|
'created_at' => !empty($param['created_at']) ? explode(',', $param['created_at']) : null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page']
|
||||||
|
]);
|
||||||
|
|
||||||
|
return success('获取成功', $msgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
public function export()
|
||||||
|
{
|
||||||
|
$schema = [
|
||||||
|
'created_at' => '提交时间',
|
||||||
|
'id' => 'ID',
|
||||||
|
'name' => '姓名',
|
||||||
|
'email' => '邮箱',
|
||||||
|
'ip' => 'IP',
|
||||||
|
'content' => '留言内容'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 获取留言导出数据
|
||||||
|
$msgs = $this->getLeaveMessageExportData();
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
return xlsx_writer($msgs, $schema, '联系我们列表' . date('YmdHis'));
|
||||||
|
}
|
||||||
|
// 获取留言导出数据
|
||||||
|
private function getLeaveMessageExportData()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'created_at'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return LeaveMessageModel::withoutField([
|
||||||
|
'language_id',
|
||||||
|
'user_agent'
|
||||||
|
])
|
||||||
|
->withSearch(['created_at'], [
|
||||||
|
'created_at' => !empty($param['created_at']) ? explode(',', $param['created_at']) : null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
}
|
||||||
|
}
|
||||||
509
app/admin/controller/v1/Menu.php
Normal file
509
app/admin/controller/v1/Menu.php
Normal file
@@ -0,0 +1,509 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\exception\InvalidOperateException;
|
||||||
|
use app\admin\model\v1\SysMenuAbilityPermissionModel;
|
||||||
|
use app\admin\model\v1\SysMenuModel;
|
||||||
|
use app\admin\validate\v1\SysMenuValidate;
|
||||||
|
use think\facade\Db;
|
||||||
|
use think\facade\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单控制器
|
||||||
|
*/
|
||||||
|
class Menu
|
||||||
|
{
|
||||||
|
// 菜单列表
|
||||||
|
public function list()
|
||||||
|
{
|
||||||
|
$params = request()->param(['title' => '']);
|
||||||
|
|
||||||
|
$menus = SysMenuModel::field([
|
||||||
|
'id',
|
||||||
|
'pid',
|
||||||
|
'title'
|
||||||
|
])
|
||||||
|
->with(['menu_ability_permission'])
|
||||||
|
->withSearch(['title'], [
|
||||||
|
'title' => $params['title'] ?? null
|
||||||
|
])
|
||||||
|
->enabled()
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
->hidden(['menu_ability_permission.menu_id']);
|
||||||
|
|
||||||
|
return success('获取成功', array_to_tree($menus->toArray(), 0, 'pid'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页数据
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$params = request()->param(['title' => '']);
|
||||||
|
|
||||||
|
$menus = SysMenuModel::field([
|
||||||
|
'id',
|
||||||
|
'pid',
|
||||||
|
'icon',
|
||||||
|
'title',
|
||||||
|
'path',
|
||||||
|
'component',
|
||||||
|
'sort',
|
||||||
|
'hidden',
|
||||||
|
'status'
|
||||||
|
])
|
||||||
|
->withSearch(['title'], [
|
||||||
|
'title' => $params['title'] ?? null
|
||||||
|
])
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return success('获取成功', array_to_tree($menus->toArray(), 0, 'pid'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 详情数据
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$menu = SysMenuModel::withoutField([
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->with(['menu_ability_permission'])
|
||||||
|
->bypk($id)
|
||||||
|
->find()
|
||||||
|
->hidden(['menu_ability_permission.menu_id']);
|
||||||
|
if (empty($menu)) {
|
||||||
|
return error('菜单不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增数据
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'pid' => 0,
|
||||||
|
'title',
|
||||||
|
'name',
|
||||||
|
'path',
|
||||||
|
'icon',
|
||||||
|
'redirect',
|
||||||
|
'component',
|
||||||
|
'hidden' => 0,
|
||||||
|
'actived' => 0,
|
||||||
|
'keep_alive' => 0,
|
||||||
|
'sort' => 0,
|
||||||
|
'status' => 1,
|
||||||
|
// $[*].ability_name 能力名称
|
||||||
|
// $[*].permission 权限标志
|
||||||
|
// $[*].sort 排序
|
||||||
|
'menu_ability_permission' => '[]'
|
||||||
|
]);
|
||||||
|
$menu_ability_permission = [];
|
||||||
|
if (!empty($post['menu_ability_permission'])) {
|
||||||
|
$menu_ability_permission = json_decode($post['menu_ability_permission'], true);
|
||||||
|
unset($post['menu_ability_permission']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$validate = new SysMenuValidate;
|
||||||
|
$check_data = array_merge($post, ['menu_ability_permission' => $menu_ability_permission]);
|
||||||
|
if (!$validate->scene('create')->check($check_data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
SysMenuModel::startTrans();
|
||||||
|
try {
|
||||||
|
// 新增菜单
|
||||||
|
$menu = SysMenuModel::create($post);
|
||||||
|
if ($menu->isEmpty()) {
|
||||||
|
throw new InvalidOperateException('新增菜单失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增菜单能力权限
|
||||||
|
if (!empty($menu_ability_permission)) {
|
||||||
|
foreach ($menu_ability_permission as &$item) {
|
||||||
|
$item['menu_id'] = $menu->id;
|
||||||
|
}
|
||||||
|
unset($item);
|
||||||
|
$permission = $menu->menuAbilityPermission()->saveAll($menu_ability_permission);
|
||||||
|
if (empty($permission)) {
|
||||||
|
throw new InvalidOperateException('新增菜单能力权限失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SysMenuModel::commit();
|
||||||
|
} catch (InvalidOperateException $e) {
|
||||||
|
SysMenuModel::rollback();
|
||||||
|
return error($e->getMessage());
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
SysMenuModel::rollback();
|
||||||
|
Log::error($th->getMessage());
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新数据
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'pid' => 0,
|
||||||
|
'title',
|
||||||
|
'name',
|
||||||
|
'path',
|
||||||
|
'icon',
|
||||||
|
'redirect',
|
||||||
|
'component',
|
||||||
|
'hidden' => 0,
|
||||||
|
'actived' => 0,
|
||||||
|
'keep_alive' => 0,
|
||||||
|
'sort' => 0,
|
||||||
|
'status' => 1,
|
||||||
|
// $[*].ability_name 能力名称
|
||||||
|
// $[*].permission 权限标志
|
||||||
|
// $[*].sort 排序
|
||||||
|
'menu_ability_permission' => '[]'
|
||||||
|
]);
|
||||||
|
$menu_ability_permission = [];
|
||||||
|
if (!empty($put['menu_ability_permission'])) {
|
||||||
|
$menu_ability_permission = json_decode($put['menu_ability_permission'], true);
|
||||||
|
unset($put['menu_ability_permission']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$validate = new SysMenuValidate;
|
||||||
|
$check_data = array_merge($put, ['id' => $id, 'menu_ability_permission' => $menu_ability_permission]);
|
||||||
|
if (!$validate->check($check_data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
SysMenuModel::startTrans();
|
||||||
|
try {
|
||||||
|
$menu = SysMenuModel::bypk($id)->find();
|
||||||
|
if ($menu->isEmpty()) {
|
||||||
|
throw new InvalidOperateException('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
// 更新菜单
|
||||||
|
if (!$menu->save($put)) {
|
||||||
|
throw new InvalidOperateException('更新菜单失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新菜单能力权限
|
||||||
|
$exists = SysMenuAbilityPermissionModel::menuId($menu->id)->count();
|
||||||
|
if ($exists) {
|
||||||
|
$deleted = SysMenuAbilityPermissionModel::menuId($menu->id)->delete();
|
||||||
|
if (!$deleted) {
|
||||||
|
throw new InvalidOperateException('删除旧菜单能力权限失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($menu_ability_permission)) {
|
||||||
|
foreach ($menu_ability_permission as &$item) {
|
||||||
|
$item['menu_id'] = $menu->id;
|
||||||
|
}
|
||||||
|
unset($item);
|
||||||
|
|
||||||
|
$permission = (new SysMenuAbilityPermissionModel)->saveAll($menu_ability_permission);
|
||||||
|
if (empty($permission)) {
|
||||||
|
throw new InvalidOperateException('更新菜单能力权限失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SysMenuModel::commit();
|
||||||
|
} catch (InvalidOperateException $e) {
|
||||||
|
SysMenuModel::rollback();
|
||||||
|
return error($e->getMessage());
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
SysMenuModel::rollback();
|
||||||
|
Log::error($th->getMessage());
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导入数据
|
||||||
|
public function import()
|
||||||
|
{
|
||||||
|
// 获取上传文件
|
||||||
|
$file = request()->file('file');
|
||||||
|
if (empty($file)) {
|
||||||
|
return error('请上传文件');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取文件
|
||||||
|
$keys_map = [
|
||||||
|
'A' => 'id',
|
||||||
|
'B' => 'pid',
|
||||||
|
'C' => 'title',
|
||||||
|
'D' => 'name',
|
||||||
|
'E' => 'path',
|
||||||
|
'F' => 'icon',
|
||||||
|
'G' => 'redirect',
|
||||||
|
'H' => 'component',
|
||||||
|
'I' => 'hidden',
|
||||||
|
'J' => 'actived',
|
||||||
|
'K' => 'keep_alive',
|
||||||
|
'L' => 'sort',
|
||||||
|
'M' => 'status',
|
||||||
|
'N' => 'menu_ability_permission'
|
||||||
|
];
|
||||||
|
$xlsx_data = xlsx_reader($file->getRealPath(), 2, $keys_map);
|
||||||
|
if (empty($xlsx_data)) {
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理行序号,防止后续被打乱
|
||||||
|
foreach ($xlsx_data as $row => &$item) {
|
||||||
|
$item['seq_no'] = $row;
|
||||||
|
}
|
||||||
|
unset($item);
|
||||||
|
|
||||||
|
// 数据组装成树形结构,方便处理上下级关系
|
||||||
|
$xlsx_data_tree = array_to_tree($xlsx_data, 0, 'pid');
|
||||||
|
// 处理导入菜单数据
|
||||||
|
$handle_errors = $this->handleImportData($xlsx_data_tree);
|
||||||
|
if (!empty($handle_errors)) {
|
||||||
|
return error(implode(PHP_EOL, $handle_errors));
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
// 处理导入数据
|
||||||
|
private function handleImportData($menus)
|
||||||
|
{
|
||||||
|
$errors = [];
|
||||||
|
$menu_model = new SysMenuModel;
|
||||||
|
$chunks = array_chunk($menus, 100, true);
|
||||||
|
foreach ($chunks as $chunk) {
|
||||||
|
// 执行保存
|
||||||
|
if (!$this->executeReplaceMenu($chunk)) {
|
||||||
|
$errors[] = sprintf('第【%s】行保存失败', implode(',', array_column($chunk, 'seq_no')));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取该批次菜单,以获取新增情况的菜单的id
|
||||||
|
$menus_map = $menu_model->whereIn('name', array_column($chunk, 'name'))->column('id', 'name');
|
||||||
|
foreach ($chunk as &$it) {
|
||||||
|
// 更改菜单的子菜单pid值为新值
|
||||||
|
if (!empty($it['children'])) {
|
||||||
|
foreach ($it['children'] as &$child) {
|
||||||
|
if (isset($menus_map[$child['name']])) {
|
||||||
|
$child['pid'] = $menus_map[$child['name']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($child);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更改菜单能力权限的menu_id
|
||||||
|
if (!empty($it['menu_ability_permission'])) {
|
||||||
|
$menu_ability_permission = json_decode($it['menu_ability_permission'], true);
|
||||||
|
foreach ($menu_ability_permission as &$permission) {
|
||||||
|
if (isset($menus_map[$it['name']])) {
|
||||||
|
$permission['menu_id'] = $menus_map[$it['name']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($permission);
|
||||||
|
$it['menu_ability_permission'] = $menu_ability_permission;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($it);
|
||||||
|
|
||||||
|
// 处理子菜单
|
||||||
|
$childrens = array_reduce(array_column($chunk, 'children'), 'array_merge', []);
|
||||||
|
$handle_errors = $this->handleImportData($childrens);
|
||||||
|
if (!empty($handler_ret)) {
|
||||||
|
$errors = array_merge($errors, $handle_errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新菜单能力权限
|
||||||
|
$menu_ability_permissions = array_reduce(array_column($chunk, 'menu_ability_permission'), 'array_merge', []);
|
||||||
|
if (!empty($menu_ability_permissions)) {
|
||||||
|
// 菜单能力权限模型实例
|
||||||
|
$ability_permission_model = new SysMenuAbilityPermissionModel;
|
||||||
|
// 删除旧的菜单能力权限
|
||||||
|
$menus_id = array_column($menu_ability_permissions, 'menu_id');
|
||||||
|
$exists = $ability_permission_model->whereIn('menu_id', $menus_id)->count();
|
||||||
|
if ($exists) {
|
||||||
|
$deleted = $ability_permission_model->whereIn('menu_id', $menus_id)->delete();
|
||||||
|
if (!$deleted) {
|
||||||
|
$errors[] = sprintf('第【%s】行删除旧菜单能力权限失败', implode(',', array_column($chunk, 'seq_no')));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 保存新的菜单能力权限
|
||||||
|
$ability_updated = $ability_permission_model->saveAll($menu_ability_permissions);
|
||||||
|
if ($ability_updated->isEmpty()) {
|
||||||
|
$errors[] = sprintf('第【%s】行保存新菜单能力权限失败', implode(',', array_column($chunk, 'seq_no')));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
// 组装repalce语句的values
|
||||||
|
private function buildReplaceMenuValues($menu)
|
||||||
|
{
|
||||||
|
return sprintf(
|
||||||
|
'(%d, %d, "%s", "%s", "%s", "%s", "%s", "%s", %d, %d, %d, %d, %d)',
|
||||||
|
$menu['id'],
|
||||||
|
$menu['pid'],
|
||||||
|
$menu['title'],
|
||||||
|
$menu['name'],
|
||||||
|
$menu['path'],
|
||||||
|
$menu['icon'],
|
||||||
|
$menu['redirect'],
|
||||||
|
$menu['component'],
|
||||||
|
$menu['hidden'],
|
||||||
|
$menu['actived'],
|
||||||
|
$menu['keep_alive'],
|
||||||
|
$menu['sort'],
|
||||||
|
$menu['status']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 执行repalce语句
|
||||||
|
private function executeReplaceMenu($menus)
|
||||||
|
{
|
||||||
|
// 获取已存在的菜单
|
||||||
|
$menus_map = SysMenuModel::whereIn('name', array_column($menus, 'name'))->column('id', 'name');
|
||||||
|
|
||||||
|
// 组装保存sql语句
|
||||||
|
$values = [];
|
||||||
|
foreach ($menus as &$it) {
|
||||||
|
if (isset($menus_map[$it['name']])) {
|
||||||
|
$it['id'] = $menus_map[$it['name']];
|
||||||
|
}
|
||||||
|
if ($it['level'] == 1) {
|
||||||
|
$it['pid'] = 0;
|
||||||
|
}
|
||||||
|
$values[] = $this->buildReplaceMenuValues($it);
|
||||||
|
}
|
||||||
|
unset($it);
|
||||||
|
|
||||||
|
return Db::execute(
|
||||||
|
sprintf(
|
||||||
|
'REPLACE INTO %s (
|
||||||
|
`id`,
|
||||||
|
`pid`,
|
||||||
|
`title`,
|
||||||
|
`name`,
|
||||||
|
`path`,
|
||||||
|
`icon`,
|
||||||
|
`redirect`,
|
||||||
|
`component`,
|
||||||
|
`hidden`,
|
||||||
|
`actived`,
|
||||||
|
`keep_alive`,
|
||||||
|
`sort`,
|
||||||
|
`status`
|
||||||
|
) VALUES %s;',
|
||||||
|
(new SysMenuModel)->getTable(),
|
||||||
|
implode(',', $values)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出数据
|
||||||
|
public function export()
|
||||||
|
{
|
||||||
|
$schema = [
|
||||||
|
'id' => '菜单ID',
|
||||||
|
'pid' => '父级ID',
|
||||||
|
'title' => '菜单标题',
|
||||||
|
'name' => '菜单名称',
|
||||||
|
'path' => '菜单路径',
|
||||||
|
'icon' => '菜单图标',
|
||||||
|
'redirect' => '菜单重定向路径',
|
||||||
|
'component' => '菜单组件路径',
|
||||||
|
'hidden' => '是否隐藏',
|
||||||
|
'actived' => '是否激活',
|
||||||
|
'keep_alive' => '是否缓存',
|
||||||
|
'sort' => '排序',
|
||||||
|
'status' => '状态',
|
||||||
|
'menu_ability_permission' => '菜单能力权限'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 获取导出数据
|
||||||
|
$data = $this->getExportMenuData();
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
return xlsx_writer($data, $schema, '菜单列表' . date('YmdHis'), 'php://output', 'file');
|
||||||
|
}
|
||||||
|
private function getExportMenuData()
|
||||||
|
{
|
||||||
|
$param = request()->param(['title' => '']);
|
||||||
|
|
||||||
|
$menus = SysMenuModel::withoutField([
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->with(['menu_ability_permission'])
|
||||||
|
->withSearch(['title'], [
|
||||||
|
'title' => $param['title'] ?? null
|
||||||
|
])
|
||||||
|
->order(['id' => 'asc'])
|
||||||
|
->select()
|
||||||
|
->hidden(['menu_ability_permission.menu_id']);
|
||||||
|
if (!$menus->isEmpty()) {
|
||||||
|
$menus->each(function ($item) {
|
||||||
|
$item->menu_ability_permission = json_encode($item->menu_ability_permission);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return $menus;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置排序值
|
||||||
|
public function sort()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$sort = request()->post('sort');
|
||||||
|
|
||||||
|
$menu = SysMenuModel::bypk($id)->find();
|
||||||
|
if ($menu->isEmpty()) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
$menu->sort = $sort;
|
||||||
|
if (!$menu->save()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除数据
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
SysMenuModel::startTrans();
|
||||||
|
try {
|
||||||
|
$menu = SysMenuModel::bypk($id)->find();
|
||||||
|
if ($menu->isEmpty()) {
|
||||||
|
throw new InvalidOperateException('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
if (!$menu->delete()) {
|
||||||
|
throw new InvalidOperateException('删除菜单失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
SysMenuModel::commit();
|
||||||
|
} catch (InvalidOperateException $e) {
|
||||||
|
SysMenuModel::rollback();
|
||||||
|
return error($e->getMessage());
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
SysMenuModel::rollback();
|
||||||
|
Log::error($th->getMessage());
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
149
app/admin/controller/v1/Navigation.php
Normal file
149
app/admin/controller/v1/Navigation.php
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\SysNavigationModel;
|
||||||
|
use app\admin\validate\v1\NavigationValidate;
|
||||||
|
|
||||||
|
class Navigation
|
||||||
|
{
|
||||||
|
// 列表
|
||||||
|
public function list()
|
||||||
|
{
|
||||||
|
$name = request()->param([
|
||||||
|
'name',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$navs = SysNavigationModel::field([
|
||||||
|
'id',
|
||||||
|
'name'
|
||||||
|
])
|
||||||
|
->withSearch(['name'], ['name' => $name['name']??null])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return success('获取成功', $navs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$name = request()->param([
|
||||||
|
'name',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$navs = SysNavigationModel::field([
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'desc',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->withSearch(['name'], ['name' => $name['name']??null])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $name['size'],
|
||||||
|
'page' => $name['page'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return success('获取成功', $navs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 详情
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$nav = SysNavigationModel::withoutField([
|
||||||
|
'at_page',
|
||||||
|
'unique_label',
|
||||||
|
'language_id',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->bypk($id)
|
||||||
|
->find();
|
||||||
|
if (empty($nav)) {
|
||||||
|
return error('导航不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $nav);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'unique_label' => '',
|
||||||
|
'name',
|
||||||
|
'at_platform' => 'pc',
|
||||||
|
'desc',
|
||||||
|
'status' => 1
|
||||||
|
]);
|
||||||
|
if (empty($post['unique_label'])) {
|
||||||
|
$post['unique_label'] = uniqid("NAV_");
|
||||||
|
}
|
||||||
|
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
|
$validate = new NavigationValidate;
|
||||||
|
if (!$validate->scene('add')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$nav = SysNavigationModel::create($data);
|
||||||
|
if ($nav->isEmpty()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'name',
|
||||||
|
'at_platform' => 'pc',
|
||||||
|
'desc',
|
||||||
|
'status' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new NavigationValidate;
|
||||||
|
if (!$validate->scene('edit')->check(array_merge($put, ['id' => $id]))) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$nav = SysNavigationModel::bypk($id)->find();
|
||||||
|
if (empty($nav)) {
|
||||||
|
return error('请确认要操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$nav->save($put)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$nav = SysNavigationModel::bypk($id)->find();
|
||||||
|
if (empty($nav)) {
|
||||||
|
return error('请确认要操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$nav->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
181
app/admin/controller/v1/NavigationItem.php
Normal file
181
app/admin/controller/v1/NavigationItem.php
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\SysNavigationItemModel;
|
||||||
|
use app\admin\validate\v1\NavigationItemValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航项管理控制器
|
||||||
|
*/
|
||||||
|
class NavigationItem
|
||||||
|
{
|
||||||
|
// 导航列表树
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->get([
|
||||||
|
'name',
|
||||||
|
'nav_id',
|
||||||
|
'created_at'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$navigations = SysNavigationItemModel::alias('item')
|
||||||
|
->field([
|
||||||
|
'item.id',
|
||||||
|
'item.pid',
|
||||||
|
'item.name',
|
||||||
|
'item.sort',
|
||||||
|
'item.blank',
|
||||||
|
'item.status',
|
||||||
|
'item.created_at',
|
||||||
|
'nav.name' => 'nav_name'
|
||||||
|
])
|
||||||
|
->join('sys_navigation nav', 'nav.id = item.nav_id')
|
||||||
|
->where('nav.language_id', '=', request()->lang_id)
|
||||||
|
->where(function($query) use($param) {
|
||||||
|
if (!empty($param['nav_id'])) {
|
||||||
|
$query->where('item.nav_id', '=', $param['nav_id']);
|
||||||
|
}
|
||||||
|
if (!empty($param['name'])) {
|
||||||
|
$query->where('item.name', 'like', "%{$param['name']}%");
|
||||||
|
}
|
||||||
|
if (!empty($param['created_at'])) {
|
||||||
|
$value = explode(',', $param['created_at']);
|
||||||
|
if (count($value) > 1) {
|
||||||
|
if ($value[1] == $value[0]) {
|
||||||
|
$value[1] = date('Y-m-d 23:59:59', strtotime($value[1]));
|
||||||
|
}
|
||||||
|
$query->whereBetweenTime('item.created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('item.created_at', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->order(['item.nav_id' => 'asc', 'item.sort' => 'asc', 'item.id' => 'asc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return success('获取成功', array_to_tree($navigations->toArray(), 0, 'pid'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导航详情
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$nav = SysNavigationItemModel::field([
|
||||||
|
'id',
|
||||||
|
'pid',
|
||||||
|
'name',
|
||||||
|
'nav_id',
|
||||||
|
'sort',
|
||||||
|
'status',
|
||||||
|
'blank',
|
||||||
|
'link_to',
|
||||||
|
'link'
|
||||||
|
])
|
||||||
|
->bypk($id)
|
||||||
|
->find();
|
||||||
|
if (empty($nav)) {
|
||||||
|
return error('导航不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组装用于前台回显的链接数据
|
||||||
|
$nav['link_echo_data'] = System::getEchoDataBySystemPageUrl($nav['link_to'], $nav['link']);
|
||||||
|
|
||||||
|
return success('获取成功', $nav);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导航新增
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'pid',
|
||||||
|
'nav_id',
|
||||||
|
'name',
|
||||||
|
'icon',
|
||||||
|
'link_to' => 'custom',
|
||||||
|
'link',
|
||||||
|
'sort',
|
||||||
|
'blank' => 0,
|
||||||
|
'status' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new NavigationItemValidate;
|
||||||
|
if (!$validate->scene('add')->check($post)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$nav_item = SysNavigationItemModel::create($post);
|
||||||
|
if ($nav_item->isEmpty()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导航更新
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'pid',
|
||||||
|
'nav_id',
|
||||||
|
'name',
|
||||||
|
'icon',
|
||||||
|
'link_to',
|
||||||
|
'link',
|
||||||
|
'sort',
|
||||||
|
'blank' => 0,
|
||||||
|
'status' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new NavigationItemValidate;
|
||||||
|
if (!$validate->scene('edit')->check(array_merge($put, ['id' => $id]))) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$nav_item = SysNavigationItemModel::bypk($id)->find();
|
||||||
|
if (empty($nav_item)) {
|
||||||
|
return error('请确认要操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$nav_item->save($put)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置排序值
|
||||||
|
public function sort()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$sort = request()->post('sort');
|
||||||
|
|
||||||
|
$nav = SysNavigationItemModel::bypk($id)->find();
|
||||||
|
if (empty($nav)) {
|
||||||
|
return error('请确认要操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
$nav->sort = $sort;
|
||||||
|
if (!$nav->save()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导航删除
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$nav = SysNavigationItemModel::bypk($id)->find();
|
||||||
|
if (empty($nav)) {
|
||||||
|
return error('请确认要操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$nav->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
48
app/admin/controller/v1/OperateLog.php
Normal file
48
app/admin/controller/v1/OperateLog.php
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\SysOperateLog;
|
||||||
|
use app\admin\model\v1\SysUserModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志控制器
|
||||||
|
*/
|
||||||
|
class OperateLog
|
||||||
|
{
|
||||||
|
// 分页
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'title',
|
||||||
|
'operator',
|
||||||
|
'created_at',
|
||||||
|
'page/d',
|
||||||
|
'size/d'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$logs = SysOperateLog::field([
|
||||||
|
'SysOperateLog.*',
|
||||||
|
'SysUserModel.username'
|
||||||
|
])
|
||||||
|
->hasWhere('user', function($query) use($param) {
|
||||||
|
if (!empty($param['operator'])) {
|
||||||
|
$query->where('username', 'like', "%{$param['operator']}%");
|
||||||
|
}
|
||||||
|
$query->withTrashed()->field(['id', 'username']);
|
||||||
|
})
|
||||||
|
->withSearch(['title', 'created_at'], [
|
||||||
|
'title' => $param['title'] ?? null,
|
||||||
|
'created_at' => $param['created_at'] ?? null
|
||||||
|
])
|
||||||
|
->order(['id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'] ?? 10,
|
||||||
|
'page' => $param['page'] ?? 1,
|
||||||
|
])
|
||||||
|
->hidden(['user_id', 'user']);
|
||||||
|
|
||||||
|
return success('获取成功', $logs);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,10 +6,13 @@ namespace app\admin\controller\v1;
|
|||||||
use app\admin\model\v1\ProductModel;
|
use app\admin\model\v1\ProductModel;
|
||||||
use app\admin\model\v1\ProductParamsModel;
|
use app\admin\model\v1\ProductParamsModel;
|
||||||
use app\admin\model\v1\ProductRelatedModel;
|
use app\admin\model\v1\ProductRelatedModel;
|
||||||
|
use app\admin\model\v1\ProductSkuAttrModel;
|
||||||
|
use app\admin\model\v1\ProductSkuModel;
|
||||||
use app\admin\validate\v1\ProductValidate;
|
use app\admin\validate\v1\ProductValidate;
|
||||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
|
||||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品管理控制器
|
||||||
|
*/
|
||||||
class Product
|
class Product
|
||||||
{
|
{
|
||||||
// 分页列表
|
// 分页列表
|
||||||
@@ -54,13 +57,14 @@ class Product
|
|||||||
])
|
])
|
||||||
->categoryNullable($param['category_id']??null)
|
->categoryNullable($param['category_id']??null)
|
||||||
->isShowNullable(isset($param['is_show']) ? (bool)$param['is_show'] : null)
|
->isShowNullable(isset($param['is_show']) ? (bool)$param['is_show'] : null)
|
||||||
->order(['sort' => 'asc', 'id' => 'desc'])
|
->order(['sort' => 'asc', 'created_at' => 'desc', 'id' => 'desc'])
|
||||||
->paginate([
|
->paginate([
|
||||||
'list_rows' => $param['size'],
|
'list_rows' => $param['size'],
|
||||||
'page' => $param['page'],
|
'page' => $param['page'],
|
||||||
])
|
])
|
||||||
->bindAttr('category', ['category_name' => 'name'])
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
->hidden(['category_id', 'category']);
|
->hidden(['category_id', 'category'])
|
||||||
|
?->each(fn($item) => $item->cover_image = thumb($item->cover_image));
|
||||||
|
|
||||||
return success('获取成功', $products);
|
return success('获取成功', $products);
|
||||||
}
|
}
|
||||||
@@ -68,14 +72,19 @@ class Product
|
|||||||
// 产品详情
|
// 产品详情
|
||||||
public function read()
|
public function read()
|
||||||
{
|
{
|
||||||
$product = ProductModel::withoutField([
|
$product = ProductModel::with(['category' => function($query) {
|
||||||
|
$query->field(['id', 'name' => 'category_name']);
|
||||||
|
}])
|
||||||
|
->withoutField([
|
||||||
'language_id',
|
'language_id',
|
||||||
'created_at',
|
'created_at',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
'deleted_at'
|
'deleted_at'
|
||||||
])
|
])
|
||||||
->bypk(request()->param('id'))
|
->bypk(request()->param('id'))
|
||||||
->find();
|
->find()
|
||||||
|
->bindAttr('category', ['category_name'])
|
||||||
|
->hidden(['category']);
|
||||||
if (empty($product)) {
|
if (empty($product)) {
|
||||||
return error('产品不存在');
|
return error('产品不存在');
|
||||||
}
|
}
|
||||||
@@ -88,6 +97,15 @@ class Product
|
|||||||
}
|
}
|
||||||
$product->params = implode(PHP_EOL, $params);
|
$product->params = implode(PHP_EOL, $params);
|
||||||
|
|
||||||
|
// 获取sku数据
|
||||||
|
$product->skus = ProductSkuModel::withoutField(['created_at', 'updated_at'])
|
||||||
|
->with(['attrs' => function($query) {
|
||||||
|
$query->hidden(['sku_id']);
|
||||||
|
}])
|
||||||
|
->productId($product->id)
|
||||||
|
->select()
|
||||||
|
->hidden(['id', 'product_id']);
|
||||||
|
|
||||||
// 获取关联产品
|
// 获取关联产品
|
||||||
$product->related = ProductRelatedModel::field([
|
$product->related = ProductRelatedModel::field([
|
||||||
'related_product_id',
|
'related_product_id',
|
||||||
@@ -124,18 +142,20 @@ class Product
|
|||||||
'sort',
|
'sort',
|
||||||
'detail',
|
'detail',
|
||||||
'params' => '',
|
'params' => '',
|
||||||
|
'skus' => '',
|
||||||
'related' => '',
|
'related' => '',
|
||||||
'status' => 1,
|
|
||||||
'seo_title',
|
'seo_title',
|
||||||
'seo_keywords',
|
'seo_keywords',
|
||||||
'seo_desc'
|
'seo_desc'
|
||||||
]);
|
]);
|
||||||
|
$put = array_merge(
|
||||||
|
$put,
|
||||||
|
['skus' => json_decode($put['skus'], true)],
|
||||||
|
['related' => json_decode($put['related'], true)],
|
||||||
|
);
|
||||||
|
|
||||||
$validate = new ProductValidate();
|
$validate = new ProductValidate();
|
||||||
$check_data = array_merge($put, [
|
$check_data = array_merge($put, ['id' => $id, 'language_id' => request()->lang_id]);
|
||||||
'id' => $id,
|
|
||||||
'language_id' => request()->lang_id
|
|
||||||
]);
|
|
||||||
if (!$validate->scene('update')->check($check_data)) {
|
if (!$validate->scene('update')->check($check_data)) {
|
||||||
return error($validate->getError());
|
return error($validate->getError());
|
||||||
}
|
}
|
||||||
@@ -151,7 +171,7 @@ class Product
|
|||||||
// 更新产品参数
|
// 更新产品参数
|
||||||
if ($put['params'] != "") {
|
if ($put['params'] != "") {
|
||||||
ProductParamsModel::productId($id)->delete();
|
ProductParamsModel::productId($id)->delete();
|
||||||
if (preg_match_all('/(\w+):(.[^\n|\r|\r\n]+)/', $put['params'], $match_result)) {
|
if (preg_match_all('/(.+):(.+)/', $put['params'], $match_result)) {
|
||||||
$params = [];
|
$params = [];
|
||||||
for ($i = 0; $i < count($match_result[0]); $i++) {
|
for ($i = 0; $i < count($match_result[0]); $i++) {
|
||||||
$params[] = [
|
$params[] = [
|
||||||
@@ -160,24 +180,92 @@ class Product
|
|||||||
'value' => $match_result[2][$i]
|
'value' => $match_result[2][$i]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
if (!empty($params)) ProductParamsModel::insertAll($params);
|
if (!empty($params)) {
|
||||||
|
ProductParamsModel::insertAll($params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新SKU
|
||||||
|
if (!empty($put['skus'])) {
|
||||||
|
$skus = [];
|
||||||
|
$attrs_group = [];
|
||||||
|
foreach ($put['skus'] as $val) {
|
||||||
|
$skus[] = [
|
||||||
|
'product_id' => $id,
|
||||||
|
'sku' => $val['sku'],
|
||||||
|
'main_image' => $val['main_image'],
|
||||||
|
'photo_album' => $val['photo_album'],
|
||||||
|
'sort' => $val['sort']??0
|
||||||
|
];
|
||||||
|
foreach ($val['attrs'] as $v) {
|
||||||
|
$attrs_group[$val['sku']][] = [
|
||||||
|
'attr_id' => $v['attr_id'],
|
||||||
|
'attr_value' => $v['attr_value']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($skus)) {
|
||||||
|
$sku_model = new ProductSkuModel;
|
||||||
|
// 删除原有SKU
|
||||||
|
$sku_model->productId($id)->delete();
|
||||||
|
// 添加SKU
|
||||||
|
$save_ret = $sku_model->saveAll($skus);
|
||||||
|
if (!$save_ret->isEmpty()) {
|
||||||
|
$sku_map = [];
|
||||||
|
foreach ($save_ret as $val) {
|
||||||
|
$sku_map[$val->sku] = $val->id;
|
||||||
|
}
|
||||||
|
$attrs = [];
|
||||||
|
foreach ($attrs_group as $sku => $sku_attrs) {
|
||||||
|
if (empty($sku_map[$sku])) {
|
||||||
|
unset($attrs_group[$sku]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach ($sku_attrs as $k => $v) {
|
||||||
|
$attrs[] = array_merge($v, ['sku_id' => $sku_map[$sku]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(new ProductSkuAttrModel)->saveAll($attrs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新关联产品
|
// 更新关联产品
|
||||||
if ($put['related'] != "") {
|
if (!empty($put['related'])) {
|
||||||
|
// 删除原有关联产品
|
||||||
ProductRelatedModel::productId($id)->delete();
|
ProductRelatedModel::productId($id)->delete();
|
||||||
$encode_result = json_decode($put['related'], true);
|
// 添加关联产品
|
||||||
if (!empty($encode_result)) {
|
|
||||||
$related = [];
|
$related = [];
|
||||||
foreach ($encode_result as $val) {
|
foreach ($put['related'] as $val) {
|
||||||
$related[] = [
|
$related[] = [
|
||||||
'product_id' => $id,
|
'product_id' => $id,
|
||||||
'related_product_id' => $val['related_product_id'],
|
'related_product_id' => $val['related_product_id'],
|
||||||
'sort' => $val['sort']
|
'sort' => $val['sort']
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
if (!empty($related)) ProductRelatedModel::insertAll($related);
|
if (!empty($related)) {
|
||||||
|
ProductRelatedModel::insertAll($related);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置排序值
|
||||||
|
public function sort()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$sort = request()->post('sort');
|
||||||
|
|
||||||
|
$product = ProductModel::bypk($id)->find();
|
||||||
|
if (empty($product)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
if ($sort != $product->sort) {
|
||||||
|
$product->sort = $sort;
|
||||||
|
if (!$product->save()) {
|
||||||
|
return error('操作失败');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,46 +339,14 @@ class Product
|
|||||||
// 获取导出数据
|
// 获取导出数据
|
||||||
$data = $this->getExportProductData();
|
$data = $this->getExportProductData();
|
||||||
|
|
||||||
// 获取Spreadsheet对象
|
// 导出
|
||||||
$spreadsheet = new Spreadsheet();
|
return xlsx_writer($data, $schema, '产品列表' . date('YmdHis'));
|
||||||
$sheet = $spreadsheet->getActiveSheet();
|
|
||||||
|
|
||||||
// 写入表头
|
|
||||||
$title = array_values($schema);
|
|
||||||
$title_col = 'A';
|
|
||||||
foreach ($title as $value) {
|
|
||||||
// 单元格内容写入
|
|
||||||
$sheet->setCellValue($title_col . '1', $value);
|
|
||||||
$title_col++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写入数据
|
|
||||||
$row = 2;
|
|
||||||
$keys = array_keys($schema);
|
|
||||||
foreach ($data as $item) {
|
|
||||||
$data_col = 'A';
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
$sheet->setCellValue($data_col . $row, $item[$key]??'');
|
|
||||||
$data_col++;
|
|
||||||
}
|
|
||||||
$row++;
|
|
||||||
}
|
|
||||||
|
|
||||||
flush();
|
|
||||||
ob_flush();
|
|
||||||
$filename = date('YmdHms');
|
|
||||||
header('Access-Control-Expose-Headers: Content-Disposition');
|
|
||||||
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; Charset=UTF-8');
|
|
||||||
header('Content-Disposition: attachment;filename=' . $filename . '.xlsx');
|
|
||||||
header('Cache-Control: max-age=0');
|
|
||||||
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
|
|
||||||
$writer->save('php://output');
|
|
||||||
}
|
}
|
||||||
// 获取产品导出数据
|
// 获取产品导出数据
|
||||||
private function getExportProductData()
|
private function getExportProductData()
|
||||||
{
|
{
|
||||||
$server = request()->server();
|
$server = request()->server();
|
||||||
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . config('filesystem.disks.public.url') . '/';
|
$image_host = $server['REQUEST_SCHEME'] . "://" . $server['SERVER_NAME'] . '/';
|
||||||
$param = request()->param([
|
$param = request()->param([
|
||||||
'name',
|
'name',
|
||||||
'spu',
|
'spu',
|
||||||
@@ -304,10 +360,10 @@ class Product
|
|||||||
'spu',
|
'spu',
|
||||||
'name',
|
'name',
|
||||||
'short_name',
|
'short_name',
|
||||||
'CONCAT("' . $image_host . '", `cover_image`)' => 'cover_image',
|
'cover_image',
|
||||||
'desc',
|
'desc',
|
||||||
'CONCAT("' . $image_host . '", `video_img`)' => 'video_img',
|
'video_img',
|
||||||
'CONCAT("' . $image_host . '", `video_url`)' => 'video_url',
|
'video_url',
|
||||||
'CASE WHEN is_new = 1 THEN "是" ELSE "否" END' => 'is_new',
|
'CASE WHEN is_new = 1 THEN "是" ELSE "否" END' => 'is_new',
|
||||||
'CASE WHEN is_hot = 1 THEN "是" ELSE "否" END' => 'is_hot',
|
'CASE WHEN is_hot = 1 THEN "是" ELSE "否" END' => 'is_hot',
|
||||||
'CASE WHEN is_sale = 1 THEN "是" ELSE "否" END' => 'is_sale',
|
'CASE WHEN is_sale = 1 THEN "是" ELSE "否" END' => 'is_sale',
|
||||||
@@ -334,7 +390,18 @@ class Product
|
|||||||
->order(['id' => 'asc'])
|
->order(['id' => 'asc'])
|
||||||
->select()
|
->select()
|
||||||
->bindAttr('category', ['category_name' => 'name'])
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
->hidden(['category_id', 'category']);
|
->hidden(['category_id', 'category'])
|
||||||
|
->each(function($item) use($image_host) {
|
||||||
|
if (!empty($item["cover_image"])) {
|
||||||
|
$item["cover_image"] = url_join($image_host, $item["cover_image"]);
|
||||||
|
}
|
||||||
|
if (!empty($item["video_img"])) {
|
||||||
|
$item["video_img"] = url_join($image_host, $item["video_img"]);
|
||||||
|
}
|
||||||
|
if (!empty($item["video_url"])) {
|
||||||
|
$item["video_url"] = url_join($image_host, $item["video_url"]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (!$products->isEmpty()) {
|
if (!$products->isEmpty()) {
|
||||||
// 产品参数
|
// 产品参数
|
||||||
@@ -365,8 +432,10 @@ class Product
|
|||||||
if (!$product_related->isEmpty()) {
|
if (!$product_related->isEmpty()) {
|
||||||
$related = [];
|
$related = [];
|
||||||
foreach ($product_related as $item) {
|
foreach ($product_related as $item) {
|
||||||
|
if (!empty($item->product)) {
|
||||||
$related[$item['product_id']][] = $item->product->spu;
|
$related[$item['product_id']][] = $item->product->spu;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$products->each(function($product) use($related) {
|
$products->each(function($product) use($related) {
|
||||||
if (empty($related[$product->id])) {
|
if (empty($related[$product->id])) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ use app\admin\model\v1\ProductAttrModel;
|
|||||||
use app\admin\model\v1\ProductAttrPropModel;
|
use app\admin\model\v1\ProductAttrPropModel;
|
||||||
use app\admin\validate\v1\ProductAttrValidate;
|
use app\admin\validate\v1\ProductAttrValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品属性管理控制器
|
||||||
|
*/
|
||||||
class ProductAttr
|
class ProductAttr
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +40,7 @@ class ProductAttr
|
|||||||
'list_rows' => $params['size'],
|
'list_rows' => $params['size'],
|
||||||
'page' => $params['page'],
|
'page' => $params['page'],
|
||||||
]);
|
]);
|
||||||
} else if ('list' == request()->param('scene')) {
|
} else if ('all' == request()->param('scene')) {
|
||||||
$attrs = $attrs->select();
|
$attrs = $attrs->select();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,13 +77,12 @@ class ProductAttr
|
|||||||
public function save()
|
public function save()
|
||||||
{
|
{
|
||||||
$post = request()->post([
|
$post = request()->post([
|
||||||
'attr_type' => 2,
|
'attr_type' => 1,
|
||||||
'attr_name' => '',
|
'attr_name' => '',
|
||||||
'is_system' => 0,
|
'is_system' => 0,
|
||||||
]);
|
]);
|
||||||
$attr = array_merge($post, ['language_id' => request()->lang_id]);
|
$attr = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
// $[*].prop_type
|
|
||||||
// $[*].prop_name
|
// $[*].prop_name
|
||||||
// $[*].prop_value
|
// $[*].prop_value
|
||||||
$props = json_decode(request()->post('props/s', ''), true);
|
$props = json_decode(request()->post('props/s', ''), true);
|
||||||
@@ -134,7 +136,6 @@ class ProductAttr
|
|||||||
]);
|
]);
|
||||||
$attr = array_merge($put, ['language_id' => request()->lang_id]);
|
$attr = array_merge($put, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
// $[*].prop_type
|
|
||||||
// $[*].prop_name
|
// $[*].prop_name
|
||||||
// $[*].prop_value
|
// $[*].prop_value
|
||||||
$props = json_decode(request()->post('props/s', ''), true);
|
$props = json_decode(request()->post('props/s', ''), true);
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ namespace app\admin\controller\v1;
|
|||||||
use app\admin\model\v1\ProductCategoryModel;
|
use app\admin\model\v1\ProductCategoryModel;
|
||||||
use app\admin\validate\v1\ProductCategoryValidate;
|
use app\admin\validate\v1\ProductCategoryValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品分类管理控制器
|
||||||
|
*/
|
||||||
class ProductCategory
|
class ProductCategory
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -14,6 +17,7 @@ class ProductCategory
|
|||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$params = request()->param([
|
$params = request()->param([
|
||||||
|
'is_show',
|
||||||
'keywords' => '',
|
'keywords' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -22,12 +26,18 @@ class ProductCategory
|
|||||||
'pid',
|
'pid',
|
||||||
'name',
|
'name',
|
||||||
'level',
|
'level',
|
||||||
|
'sort',
|
||||||
'is_show'
|
'is_show'
|
||||||
])
|
])
|
||||||
->language(request()->lang_id)
|
->language(request()->lang_id)
|
||||||
->withSearch(['name_nullable'], [
|
->withSearch(['name_nullable'], [
|
||||||
'name_nullable' => $params['keywords']
|
'name_nullable' => $params['keywords']??null
|
||||||
])
|
])
|
||||||
|
->where(function($query) use($params) {
|
||||||
|
if (isset($params['is_show'])) {
|
||||||
|
$query->where('is_show', '=', $params['is_show']);
|
||||||
|
}
|
||||||
|
})
|
||||||
->select();
|
->select();
|
||||||
if ($ret->isEmpty()) {
|
if ($ret->isEmpty()) {
|
||||||
return success('获取成功');
|
return success('获取成功');
|
||||||
@@ -70,18 +80,15 @@ class ProductCategory
|
|||||||
'related_tco_category',
|
'related_tco_category',
|
||||||
'sort',
|
'sort',
|
||||||
'level' => 1,
|
'level' => 1,
|
||||||
'is_show' => 1,
|
'is_show' => 1
|
||||||
'seo_title',
|
|
||||||
'seo_keywords',
|
|
||||||
'seo_desc'
|
|
||||||
]);
|
]);
|
||||||
if (empty($post['unique_id'])) {
|
if (empty($post['unique_id'])) {
|
||||||
$post['unique_id'] = md5(uniqid());
|
$post['unique_id'] = uniqid('PRO_CATE_');
|
||||||
}
|
}
|
||||||
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
$validate = new ProductCategoryValidate;
|
$validate = new ProductCategoryValidate;
|
||||||
if (!$validate->check($data)) {
|
if (!$validate->scene('add')->check($data)) {
|
||||||
return error($validate->getError());
|
return error($validate->getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +98,9 @@ class ProductCategory
|
|||||||
if ($data['pid'] > 0) {
|
if ($data['pid'] > 0) {
|
||||||
$parent = $category->bypk($data['pid'])->find();
|
$parent = $category->bypk($data['pid'])->find();
|
||||||
if (!empty($parent)) {
|
if (!empty($parent)) {
|
||||||
|
if (!empty($parent->path)) {
|
||||||
|
$data['path'] = $parent->path . ',' . $parent->id;
|
||||||
|
}
|
||||||
$data['level'] = $parent->level + 1;
|
$data['level'] = $parent->level + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,10 +126,7 @@ class ProductCategory
|
|||||||
'related_tco_category',
|
'related_tco_category',
|
||||||
'sort',
|
'sort',
|
||||||
'level' => 1,
|
'level' => 1,
|
||||||
'is_show' => 1,
|
'is_show' => 1
|
||||||
'seo_title',
|
|
||||||
'seo_keywords',
|
|
||||||
'seo_desc'
|
|
||||||
]);
|
]);
|
||||||
$data = array_merge($put, [
|
$data = array_merge($put, [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
@@ -141,6 +148,10 @@ class ProductCategory
|
|||||||
if ($data['pid'] != $category->pid) {
|
if ($data['pid'] != $category->pid) {
|
||||||
$parent = ProductCategoryModel::bypk($data['pid'])->find();
|
$parent = ProductCategoryModel::bypk($data['pid'])->find();
|
||||||
if (!empty($parent)) {
|
if (!empty($parent)) {
|
||||||
|
$data['path'] = $parent->id;
|
||||||
|
if (!empty($parent->path)) {
|
||||||
|
$data['path'] = $parent->path . ',' . $data['path'];
|
||||||
|
}
|
||||||
$data['level'] = $parent->level + 1;
|
$data['level'] = $parent->level + 1;
|
||||||
$updated_level = true;
|
$updated_level = true;
|
||||||
}
|
}
|
||||||
@@ -152,21 +163,24 @@ class ProductCategory
|
|||||||
|
|
||||||
// 处理子分类层级
|
// 处理子分类层级
|
||||||
if ($updated_level) {
|
if ($updated_level) {
|
||||||
$this->handle_children($category->id, $data['level']);
|
$this->handle_children($category->id, $data['path'], $data['level']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success('操作成功');
|
return success('操作成功');
|
||||||
}
|
}
|
||||||
private function handle_children($pid, $level)
|
private function handle_children($pid, $path, $level)
|
||||||
{
|
{
|
||||||
$children = ProductCategoryModel::pid($pid)->select();
|
$children = ProductCategoryModel::pid($pid)->select();
|
||||||
if ($children->isEmpty()) {
|
if ($children->isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach ($children as $child) {
|
foreach ($children as $child) {
|
||||||
|
if (!empty($path)) {
|
||||||
|
$child->path = $path. ','. $child->pid;
|
||||||
|
}
|
||||||
$child->level = $level + 1;
|
$child->level = $level + 1;
|
||||||
if ($child->save()) {
|
if ($child->save()) {
|
||||||
$this->handle_children($child->id, $child->level);
|
$this->handle_children($child->id, $child->path, $child->level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
50
app/admin/controller/v1/ProductInquiry.php
Normal file
50
app/admin/controller/v1/ProductInquiry.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\ProductInquiryModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品询盘记录控制器
|
||||||
|
*/
|
||||||
|
class ProductInquiry
|
||||||
|
{
|
||||||
|
// 分页
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'corp_name',
|
||||||
|
'country_name',
|
||||||
|
'created_at',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$msgs = ProductInquiryModel::field([
|
||||||
|
'id',
|
||||||
|
'first_name',
|
||||||
|
'last_name',
|
||||||
|
'email',
|
||||||
|
'phone',
|
||||||
|
'corp_name',
|
||||||
|
'country_name',
|
||||||
|
'industry',
|
||||||
|
'message',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->withSearch(['corp_name', 'country_name', 'created_at'], [
|
||||||
|
'corp_name' => $param['corp_name'] ?? null,
|
||||||
|
'country_name' => $param['country_name'] ?? null,
|
||||||
|
'created_at' => !empty($param['created_at']) ? explode(',', $param['created_at']) : null,
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return success('获取成功', $msgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
357
app/admin/controller/v1/ProductPurchaseLink.php
Normal file
357
app/admin/controller/v1/ProductPurchaseLink.php
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\ProductModel;
|
||||||
|
use app\admin\model\v1\ProductPurchaseLinkModel;
|
||||||
|
use app\admin\model\v1\ProductPurchaseLinkPlatformModel;
|
||||||
|
use app\admin\validate\v1\ProductPurchaseLinkValidate;
|
||||||
|
use think\facade\Db;
|
||||||
|
|
||||||
|
class ProductPurchaseLink
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取购买平台
|
||||||
|
*/
|
||||||
|
public function platforms()
|
||||||
|
{
|
||||||
|
$platforms = ProductPurchaseLinkPlatformModel::withoutField([
|
||||||
|
'language_id',
|
||||||
|
'desc',
|
||||||
|
'sort',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return success('获取成功', $platforms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买链接分页数据
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$params = request()->param([
|
||||||
|
'name' => '',
|
||||||
|
'spu' => '',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$links = ProductModel::alias('pd')
|
||||||
|
->field([
|
||||||
|
'pd.id',
|
||||||
|
'IFNULL(pl.sort, 0)' => 'sort',
|
||||||
|
'pd.spu',
|
||||||
|
'pd.name',
|
||||||
|
'pd.is_show'
|
||||||
|
])
|
||||||
|
->leftJoin('product_purchase_link pl', 'pl.product_id = pd.id')
|
||||||
|
->leftJoin('product_purchase_platform pf', 'pf.id = pl.platform_id')
|
||||||
|
->where(function ($query) use ($params) {
|
||||||
|
$query->where('pd.is_show', '=', 1);
|
||||||
|
if (!empty($params['name'])) {
|
||||||
|
$query->where('pd.name', 'like', '%' . $params['name'] . '%');
|
||||||
|
}
|
||||||
|
if (!empty($params['spu'])) {
|
||||||
|
$query->where('pd.spu', 'like', '%' . $params['spu'] . '%');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->where('pd.language_id', '=', request()->lang_id)
|
||||||
|
->group('pd.id')
|
||||||
|
->order(['sort' => 'asc', 'pd.id' => 'desc'])
|
||||||
|
->hidden(['sort'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $params['size'],
|
||||||
|
'page' => $params['page'],
|
||||||
|
]);
|
||||||
|
if ($links->isEmpty()) {
|
||||||
|
return success('获取成功', []);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取购买链接数据
|
||||||
|
$others = ProductPurchaseLinkModel::alias('pl')
|
||||||
|
->field([
|
||||||
|
'pl.product_id',
|
||||||
|
'pl.platform_id',
|
||||||
|
'pf.platform' => 'platform_name',
|
||||||
|
'pl.id' => 'link_id',
|
||||||
|
'pl.link'
|
||||||
|
])
|
||||||
|
->join('product_purchase_platform pf', 'pf.id = pl.platform_id')
|
||||||
|
->where('pl.language_id', '=', request()->lang_id)
|
||||||
|
->where('pl.product_id', 'in', array_column($links->items(), 'id'))
|
||||||
|
->select();
|
||||||
|
if (!$others->isEmpty()) {
|
||||||
|
$others_map = [];
|
||||||
|
$others_arr = $others->toArray();
|
||||||
|
foreach ($others_arr as $other) {
|
||||||
|
$product_id = $other['product_id'];
|
||||||
|
unset($other['product_id']);
|
||||||
|
$others_map[$product_id][] = $other;
|
||||||
|
}
|
||||||
|
$links->each(function ($item) use ($others_map) {
|
||||||
|
if (!empty($others_map[$item['id']])) {
|
||||||
|
$item['rowspan'] = $others_map[$item['id']];
|
||||||
|
}
|
||||||
|
return $item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取平台数据
|
||||||
|
$platforms = ProductPurchaseLinkPlatformModel::field(['id', 'platform'])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
$platforms_map = [];
|
||||||
|
foreach ($platforms as $k => $v) {
|
||||||
|
$platforms_map[$v['id']] = [
|
||||||
|
'platform_id' => $v['id'],
|
||||||
|
'platform_name' => $v['platform'],
|
||||||
|
'link_id' => 0,
|
||||||
|
'link' => ''
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// 没有购买链接的,补全平台数据
|
||||||
|
$links->each(function ($item) use($platforms_map) {
|
||||||
|
if (empty($item['rowspan'])) {
|
||||||
|
$item['rowspan'] = array_values($platforms_map);
|
||||||
|
} else if (count($item['rowspan']) < count($platforms_map)) {
|
||||||
|
foreach ($item['rowspan'] as $k => $v) {
|
||||||
|
if (!empty($platforms_map[$v['platform_id']])) {
|
||||||
|
unset($platforms_map[$v['platform_id']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$item['rowspan'] = array_merge($item['rowspan'], array_values($platforms_map));
|
||||||
|
}
|
||||||
|
return $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return success('获取成功', $links);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入
|
||||||
|
*/
|
||||||
|
public function import()
|
||||||
|
{
|
||||||
|
$file = request()->file('file');
|
||||||
|
if ($file->getSize() > 20 * 1024 * 1024) {
|
||||||
|
return error('上传文件不能超过20M');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从表格获取数据
|
||||||
|
$xlsx_data = xlsx_reader($file->getRealPath(), 2, ['A' => 'spu', 'B' => 'platform', 'C' => 'link']);
|
||||||
|
|
||||||
|
$platforms_name = array_unique(array_column($xlsx_data, 'platform'));
|
||||||
|
$platforms_map = ProductPurchaseLinkPlatformModel::language(request()->lang_id)
|
||||||
|
->where('platform', 'in', $platforms_name)
|
||||||
|
->column('id', 'platform');
|
||||||
|
|
||||||
|
// 表格中spu的平台重复次数
|
||||||
|
$spu_platform_map = [];
|
||||||
|
foreach ($xlsx_data as $v) {
|
||||||
|
if (!isset($spu_platform_map[$v['spu'] . '_' . $v['platform']])) {
|
||||||
|
$spu_platform_map[$v['spu'] . '_' . $v['platform']] = 0;
|
||||||
|
}
|
||||||
|
$spu_platform_map[$v['spu'] . '_' . $v['platform']]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
$errors = [];
|
||||||
|
$chunks = array_chunk($xlsx_data, 500, true);
|
||||||
|
// 分组验证每行,并组装数据
|
||||||
|
foreach ($chunks as $chunk) {
|
||||||
|
$spus = array_unique(array_column($chunk, 'spu'));
|
||||||
|
$products_map = ProductModel::language(request()->lang_id)
|
||||||
|
->where('spu', 'in', $spus)
|
||||||
|
->column('id', 'spu');
|
||||||
|
|
||||||
|
$items = [];
|
||||||
|
foreach ($chunk as $r => $it) {
|
||||||
|
if (empty($platforms_map[$it['platform']])) {
|
||||||
|
$errors[] = sprintf("第%d行,平台名称错误", $r);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (empty($products_map[$it['spu']])) {
|
||||||
|
$errors[] = sprintf("第%d行,型号不存在", $r);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($spu_platform_map[$it['spu'] . '_' . $it['platform']] > 1) {
|
||||||
|
$errors[] = sprintf("第%d行,型号【%s】和平台【%s】有重复", $r, $it['spu'], $it['platform']);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$items[] = [
|
||||||
|
'language_id' => request()->lang_id,
|
||||||
|
'product_id' => $products_map[$it['spu']],
|
||||||
|
'platform_id' => $platforms_map[$it['platform']],
|
||||||
|
'link' => $it['link'],
|
||||||
|
'sort' => 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (!empty($items)) {
|
||||||
|
$data[] = $items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组装sql,并执行
|
||||||
|
if (!empty($data)) {
|
||||||
|
$link_model = new ProductPurchaseLinkModel();
|
||||||
|
$sql = sprintf(
|
||||||
|
'REPLACE INTO %s (id, language_id, product_id, platform_id, link, sort) VALUES ',
|
||||||
|
$link_model->getTable(),
|
||||||
|
);
|
||||||
|
foreach ($data as $items) {
|
||||||
|
$products_id = array_unique(array_column($items, 'product_id'));
|
||||||
|
$links = $link_model->field([
|
||||||
|
'id',
|
||||||
|
'product_id',
|
||||||
|
'platform_id'
|
||||||
|
])
|
||||||
|
->where('product_id', 'in', $products_id)
|
||||||
|
->select();
|
||||||
|
$links_map = [];
|
||||||
|
if (!$links->isEmpty()) {
|
||||||
|
foreach ($links as $link) {
|
||||||
|
$links_map[$link['product_id'] . '_' . $link['platform_id']] = $link['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$item['id'] = null;
|
||||||
|
if (!empty($links_map[$item['product_id'] . '_' . $item['platform_id']])) {
|
||||||
|
$item['id'] = $links_map[$item['product_id'] . '_' . $item['platform_id']];
|
||||||
|
}
|
||||||
|
$sql .= sprintf(
|
||||||
|
'(%d, %d, %d, %d, "%s", %d),',
|
||||||
|
$item['id'],
|
||||||
|
$item['language_id'],
|
||||||
|
$item['product_id'],
|
||||||
|
$item['platform_id'],
|
||||||
|
$item['link'],
|
||||||
|
$item['sort']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Db::execute(rtrim($sql, ','));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($errors)) {
|
||||||
|
return error(implode(";\n", $errors));
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('导入成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出
|
||||||
|
*/
|
||||||
|
public function export()
|
||||||
|
{
|
||||||
|
$schema = [
|
||||||
|
'spu' => '型号',
|
||||||
|
'platform' => '平台',
|
||||||
|
'link' => '链接'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 获取导出数据
|
||||||
|
$data = $this->getExportLinkData();
|
||||||
|
|
||||||
|
/// 导出
|
||||||
|
return xlsx_writer($data, $schema, '产品购买链接' . date('YmdHis'));
|
||||||
|
}
|
||||||
|
private function getExportLinkData()
|
||||||
|
{
|
||||||
|
$params = request()->param([
|
||||||
|
'name' => '',
|
||||||
|
'spu' => ''
|
||||||
|
]);
|
||||||
|
|
||||||
|
return ProductModel::alias('pd')
|
||||||
|
->field([
|
||||||
|
'pd.spu',
|
||||||
|
'pf.platform',
|
||||||
|
'pl.link'
|
||||||
|
])
|
||||||
|
->leftJoin('product_purchase_link pl', 'pl.product_id = pd.id')
|
||||||
|
->leftJoin('product_purchase_platform pf', 'pf.id = pl.platform_id')
|
||||||
|
->where(function ($query) use ($params) {
|
||||||
|
$query->where('pd.is_show', '=', 1);
|
||||||
|
if (!empty($params['name'])) {
|
||||||
|
$query->where('pd.name', 'like', '%' . $params['name'] . '%');
|
||||||
|
}
|
||||||
|
if (!empty($params['spu'])) {
|
||||||
|
$query->where('pd.spu', 'like', '%' . $params['spu'] . '%');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->where('pd.language_id', '=', request()->lang_id)
|
||||||
|
->order(['pl.sort' => 'asc', 'pl.id' => 'desc', 'pd.id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加购买链接
|
||||||
|
*/
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'link',
|
||||||
|
'product_id',
|
||||||
|
'platform_id'
|
||||||
|
]);
|
||||||
|
$data = [
|
||||||
|
'link' => $post['link'],
|
||||||
|
'language_id' => request()->lang_id,
|
||||||
|
'product_id' => $post['product_id'],
|
||||||
|
'platform_id' => $post['platform_id']
|
||||||
|
];
|
||||||
|
$validate = new ProductPurchaseLinkValidate;
|
||||||
|
if (!$validate->scene('add')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$link = ProductPurchaseLinkModel::create($data);
|
||||||
|
if ($link->isEmpty()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新购买链接
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'link',
|
||||||
|
'platform_id'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'id' => $id,
|
||||||
|
'link' => $put['link'],
|
||||||
|
'language_id' => request()->lang_id,
|
||||||
|
'platform_id' => $put['platform_id']
|
||||||
|
];
|
||||||
|
$validate = new ProductPurchaseLinkValidate;
|
||||||
|
if (!$validate->scene('edit')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$link = ProductPurchaseLinkModel::bypk($data['id'])->find();
|
||||||
|
if (empty($link)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$link->save($data)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
35
app/admin/controller/v1/ProductTcoCategory.php
Normal file
35
app/admin/controller/v1/ProductTcoCategory.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\ProductTcoCategoryModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品 - 产品目录分类控制器
|
||||||
|
*/
|
||||||
|
class ProductTcoCategory
|
||||||
|
{
|
||||||
|
// 分类树
|
||||||
|
public function tree()
|
||||||
|
{
|
||||||
|
$param = request()->param(['name']);
|
||||||
|
|
||||||
|
$categorys = ProductTcoCategoryModel::field([
|
||||||
|
'id',
|
||||||
|
'tco_id',
|
||||||
|
'tco_pid',
|
||||||
|
'name',
|
||||||
|
])
|
||||||
|
->withSearch(['name'], [
|
||||||
|
'name' => $param['name'] ?? null,
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->enabled()
|
||||||
|
->order(['tco_id' => 'asc'])
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
return success('获取成功', array_to_tree($categorys, 0, 'tco_pid', false, true, 'tco_id'));
|
||||||
|
}
|
||||||
|
}
|
||||||
102
app/admin/controller/v1/ProductTrash.php
Normal file
102
app/admin/controller/v1/ProductTrash.php
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\ProductModel;
|
||||||
|
use app\admin\validate\v1\ProductValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品回收站管理控制器
|
||||||
|
*/
|
||||||
|
class ProductTrash
|
||||||
|
{
|
||||||
|
// 产品回回站分页列表
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'name',
|
||||||
|
'spu',
|
||||||
|
'category_id',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new ProductValidate();
|
||||||
|
if (!$validate->scene('trash')->check($param)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$products = ProductModel::field([
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'cover_image',
|
||||||
|
'spu',
|
||||||
|
'category_id',
|
||||||
|
'sort',
|
||||||
|
'is_new',
|
||||||
|
'is_sale',
|
||||||
|
'stock_qty',
|
||||||
|
'status',
|
||||||
|
'created_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->with(['category'])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->withSearch(['name_nullable', 'spu_nullable'], [
|
||||||
|
'name_nullable' => $param['name']??null,
|
||||||
|
'spu_nullable' => $param['spu']??null,
|
||||||
|
])
|
||||||
|
->categoryNullable($param['category_id']??null)
|
||||||
|
->onlyTrashed()
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page'],
|
||||||
|
])
|
||||||
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
|
->hidden(['category_id', 'category'])
|
||||||
|
?->each(fn($item) => $item->cover_image = thumb($item->cover_image));
|
||||||
|
|
||||||
|
return success('获取成功', $products);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复
|
||||||
|
public function restore()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
if (!$id) {
|
||||||
|
return error('参数错误');
|
||||||
|
}
|
||||||
|
|
||||||
|
$product = ProductModel::onlyTrashed()->bypk($id)->find();
|
||||||
|
if (is_null($product)) {
|
||||||
|
return error('请确认操作对象');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$product->restore()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
if (!$id) {
|
||||||
|
return error('参数错误');
|
||||||
|
}
|
||||||
|
|
||||||
|
$product = ProductModel::onlyTrashed()->bypk($id)->find();
|
||||||
|
if (is_null($product)) {
|
||||||
|
return error('请确认操作对象');
|
||||||
|
}
|
||||||
|
if (!$product->force()->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
240
app/admin/controller/v1/Role.php
Normal file
240
app/admin/controller/v1/Role.php
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\exception\InvalidOperateException;
|
||||||
|
use app\admin\model\v1\SysMenuModel;
|
||||||
|
use app\admin\model\v1\SysRoleAuthorityModel;
|
||||||
|
use app\admin\model\v1\SysRoleModel;
|
||||||
|
use app\admin\validate\v1\SysRoleValidate;
|
||||||
|
use think\facade\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色管理控制器
|
||||||
|
*/
|
||||||
|
class Role
|
||||||
|
{
|
||||||
|
// 角色分页
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$params = request()->get([
|
||||||
|
'name',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$roles = SysRoleModel::withoutField([
|
||||||
|
'pid',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->withSearch(['name'], [
|
||||||
|
'name' => $params['name']??null
|
||||||
|
])
|
||||||
|
->order('id', 'desc');
|
||||||
|
if (!request()->has('scene')) {
|
||||||
|
$roles = $roles->paginate([
|
||||||
|
'list_rows' => $params['size'],
|
||||||
|
'page' => $params['page']
|
||||||
|
]);
|
||||||
|
if (!$roles->isEmpty()) {
|
||||||
|
$roles_id = array_column($roles->items(), 'id');
|
||||||
|
$authority = SysMenuModel::alias('menu')
|
||||||
|
->field(['menu.title', 'authority.role_id'])
|
||||||
|
->join('sys_role_authority authority', 'authority.menu_id = menu.id')
|
||||||
|
->whereIn('authority.role_id', $roles_id)
|
||||||
|
->select();
|
||||||
|
if (!empty($authority)) {
|
||||||
|
$authority_map = [];
|
||||||
|
foreach ($authority as $v) {
|
||||||
|
$authority_map[$v['role_id']][] = $v['title'];
|
||||||
|
}
|
||||||
|
$roles->each(function($item) use($authority_map) {
|
||||||
|
$item['authority'] = [];
|
||||||
|
if (isset($authority_map[$item['id']])) {
|
||||||
|
$item['authority'] = array_unique($authority_map[$item['id']]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ('all' == request()->param('scene')) {
|
||||||
|
$roles = $roles->select();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色详情
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$role = SysRoleModel::withoutField([
|
||||||
|
'pid',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->with(['authorities'])
|
||||||
|
->bypk($id)
|
||||||
|
->find()
|
||||||
|
->hidden(['authorities.role_id']);
|
||||||
|
if (empty($role)) {
|
||||||
|
return error('角色不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $role);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色新增
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'name',
|
||||||
|
'desc',
|
||||||
|
// $[*].menu_id
|
||||||
|
// $[*].permissions
|
||||||
|
'menu_permission' => '[]'
|
||||||
|
]);
|
||||||
|
$post['menu_permission'] = json_decode($post['menu_permission'], true);
|
||||||
|
|
||||||
|
$validate = new SysRoleValidate;
|
||||||
|
if (!$validate->scene('create')->check($post)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
SysRoleModel::startTrans();
|
||||||
|
try {
|
||||||
|
$role = SysRoleModel::create($post, ['name', 'desc']);
|
||||||
|
if ($role->isEmpty()) {
|
||||||
|
throw new InvalidOperateException('角色新增失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($post['menu_permission'])) {
|
||||||
|
$permissions = [];
|
||||||
|
foreach ($post['menu_permission'] as $menu) {
|
||||||
|
if (!isset($menu['permissions'])) {
|
||||||
|
$permissions[] = [
|
||||||
|
'role_id' => $role->id,
|
||||||
|
'menu_id' => $menu['menu_id'],
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach ($menu['permissions'] as $permission) {
|
||||||
|
$permissions[] = [
|
||||||
|
'role_id' => $role->id,
|
||||||
|
'menu_id' => $menu['menu_id'],
|
||||||
|
'permission' => $permission
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$authority = (new SysRoleAuthorityModel)->saveAll($permissions);
|
||||||
|
if ($authority->isEmpty()) {
|
||||||
|
throw new InvalidOperateException('角色权限新增失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SysRoleModel::commit();
|
||||||
|
} catch (InvalidOperateException $e) {
|
||||||
|
SysRoleModel::rollback();
|
||||||
|
return error($e->getMessage());
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
SysRoleModel::rollback();
|
||||||
|
Log::error($th->getMessage());
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色更新
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'name',
|
||||||
|
'desc',
|
||||||
|
// $[*].menu_id
|
||||||
|
// $[*].permissions
|
||||||
|
'menu_permission' => '[]'
|
||||||
|
]);
|
||||||
|
$put['menu_permission'] = json_decode($put['menu_permission'], true);
|
||||||
|
|
||||||
|
$validate = new SysRoleValidate;
|
||||||
|
if (!$validate->scene('update')->check(array_merge($put, ['id' => $id]))) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
SysRoleModel::startTrans();
|
||||||
|
try {
|
||||||
|
$role = SysRoleModel::bypk($id)->find();
|
||||||
|
if (empty($role)) {
|
||||||
|
throw new InvalidOperateException('角色不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$role->allowField(['name', 'desc'])->save($put)) {
|
||||||
|
throw new InvalidOperateException('角色更新失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($put['menu_permission'])) {
|
||||||
|
$permissions = [];
|
||||||
|
foreach ($put['menu_permission'] as $menu) {
|
||||||
|
if (!isset($menu['permissions'])) {
|
||||||
|
$permissions[] = [
|
||||||
|
'role_id' => $role->id,
|
||||||
|
'menu_id' => $menu['menu_id'],
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach ($menu['permissions'] as $permission) {
|
||||||
|
$permissions[] = [
|
||||||
|
'role_id' => $role->id,
|
||||||
|
'menu_id' => $menu['menu_id'],
|
||||||
|
'permission' => $permission
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SysRoleAuthorityModel::roleId($role->id)->delete();
|
||||||
|
$authority = (new SysRoleAuthorityModel)->saveAll($permissions);
|
||||||
|
if ($authority->isEmpty()) {
|
||||||
|
throw new InvalidOperateException('角色权限更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SysRoleModel::commit();
|
||||||
|
} catch (InvalidOperateException $e) {
|
||||||
|
SysRoleModel::rollback();
|
||||||
|
return error($e->getMessage());
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
SysRoleModel::rollback();
|
||||||
|
Log::error($th->getMessage());
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色删除
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$role = SysRoleModel::bypk($id)->find();
|
||||||
|
if (empty($role)) {
|
||||||
|
return error('请确认要操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 == $role->is_system) {
|
||||||
|
return error('该角色禁止删除');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$role->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
230
app/admin/controller/v1/SiteConfig.php
Normal file
230
app/admin/controller/v1/SiteConfig.php
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\SysConfigGroupModel;
|
||||||
|
use app\admin\model\v1\SysConfigModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 站酷配置控制器
|
||||||
|
*/
|
||||||
|
class SiteConfig
|
||||||
|
{
|
||||||
|
// 获取配置项
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
// 按语言获取分组
|
||||||
|
$groups = SysConfigGroupModel::field([
|
||||||
|
'id',
|
||||||
|
'name'
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->enabled()
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
if (empty($groups)) {
|
||||||
|
return error('配置分组不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据分组获取配置项
|
||||||
|
$configs = SysConfigModel::field([
|
||||||
|
'id',
|
||||||
|
'group_id',
|
||||||
|
'title',
|
||||||
|
'name',
|
||||||
|
'value',
|
||||||
|
'extra',
|
||||||
|
'type',
|
||||||
|
'remark'
|
||||||
|
])
|
||||||
|
->groupId(array_column($groups, 'id'))
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
->each(function ($item) {
|
||||||
|
// 修改字段为null的输出为空字符串
|
||||||
|
$keys = array_keys($item->toArray());
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
if (is_null($item[$key])) {
|
||||||
|
$item[$key] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $item;
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// 处理附加配置项及联动项
|
||||||
|
$configs = $this->handleExtra($configs);
|
||||||
|
|
||||||
|
// 组合数据
|
||||||
|
$config_group_map = [];
|
||||||
|
foreach ($configs as $config) {
|
||||||
|
$group_id = $config['group_id'];
|
||||||
|
unset($config['group_id']);
|
||||||
|
$config_group_map[$group_id][] = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组合分组和配置项
|
||||||
|
foreach ($groups as &$group) {
|
||||||
|
$group['configs'] = $config_group_map[$group['id']] ?? [];
|
||||||
|
}
|
||||||
|
unset($group);
|
||||||
|
|
||||||
|
return success('获取成功', $groups);
|
||||||
|
}
|
||||||
|
// 处理配置联动项数据
|
||||||
|
private function handleExtra($data)
|
||||||
|
{
|
||||||
|
list($list, $map) = $this->parseExtra($data);
|
||||||
|
return $this->buildExtra($list, $map);
|
||||||
|
}
|
||||||
|
private function parseExtra($data)
|
||||||
|
{
|
||||||
|
$linkage_names = [];
|
||||||
|
foreach ($data as &$val) {
|
||||||
|
if (!empty($val['extra'])) {
|
||||||
|
$extra = explode(PHP_EOL, $val['extra']);
|
||||||
|
$val['extra'] = [];
|
||||||
|
foreach ($extra as $v) {
|
||||||
|
if (preg_match('/^([^:]+):(.*?)(?:\[(.*?)\])?$/i', trim($v), $match)) {
|
||||||
|
$item = [
|
||||||
|
'name' => $match[2],
|
||||||
|
'value' => $match[1],
|
||||||
|
'linkage_names' => [],
|
||||||
|
];
|
||||||
|
if (isset($match[3])) {
|
||||||
|
$item['linkage_names'] = array_map(function ($it) {
|
||||||
|
return str_replace(['"', "'"], '', trim($it));
|
||||||
|
}, explode(',', $match[3]));
|
||||||
|
}
|
||||||
|
$linkage_names = array_merge($linkage_names, $item['linkage_names']);
|
||||||
|
$val['extra'][] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($val);
|
||||||
|
|
||||||
|
$linkage_data = [];
|
||||||
|
foreach ($data as $key => $val) {
|
||||||
|
if (in_array($val['name'], $linkage_names)) {
|
||||||
|
$linkage_data[$val['name']] = $val;
|
||||||
|
unset($data[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$data, $linkage_data];
|
||||||
|
}
|
||||||
|
private function buildExtra($data, $linkage_data)
|
||||||
|
{
|
||||||
|
$ret = [];
|
||||||
|
foreach ($data as $val) {
|
||||||
|
if (!empty($val['extra'])) {
|
||||||
|
foreach ($val['extra'] as &$v) {
|
||||||
|
$linkage_names = $v['linkage_names'];
|
||||||
|
unset($v['linkage_names']);
|
||||||
|
$children = [];
|
||||||
|
foreach ($linkage_names as $name) {
|
||||||
|
if (!empty($linkage_data[$name])) {
|
||||||
|
$children[] = $linkage_data[$name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$v['children'] = $this->handleExtra($children);
|
||||||
|
}
|
||||||
|
unset($v);
|
||||||
|
}
|
||||||
|
$ret[] = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据分组获取配置
|
||||||
|
public function getByGroupUniqueLabel($unique_label)
|
||||||
|
{
|
||||||
|
$configs = SysConfigModel::alias('c')
|
||||||
|
->field([
|
||||||
|
'c.id',
|
||||||
|
'c.title',
|
||||||
|
'c.name',
|
||||||
|
'c.value',
|
||||||
|
])
|
||||||
|
->join(SysConfigGroupModel::getTable(). ' g', 'g.id = c.group_id')
|
||||||
|
->where('g.language_id', '=', request()->lang_id)
|
||||||
|
->where('g.unique_label', '=', $unique_label)
|
||||||
|
->where('g.status', '=', 1)
|
||||||
|
->order(['c.sort' => 'asc', 'c.id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
->each(function ($item) {
|
||||||
|
// 修改字段为null的输出为空字符串
|
||||||
|
$keys = array_keys($item->toArray());
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
if (is_null($item[$key])) {
|
||||||
|
$item[$key] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $item;
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
if (!empty($configs)) {
|
||||||
|
$configs_map = [];
|
||||||
|
foreach ($configs as $cfg) {
|
||||||
|
$current = &$configs_map;
|
||||||
|
|
||||||
|
// 根据name中"."拆分为多维数组
|
||||||
|
$parts = explode('.', $cfg['name']);
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
if (!isset($current[$part])) {
|
||||||
|
$current[$part] = [];
|
||||||
|
}
|
||||||
|
$current = &$current[$part];
|
||||||
|
}
|
||||||
|
$current = [
|
||||||
|
'id' => $cfg['id'],
|
||||||
|
'title' => $cfg['title'],
|
||||||
|
'name' => $cfg['name'],
|
||||||
|
'value' => $cfg['value']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
unset($current);
|
||||||
|
|
||||||
|
return $configs_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新配置
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$put = request()->put();
|
||||||
|
|
||||||
|
if (empty($put)) {
|
||||||
|
return error('参数错误');
|
||||||
|
}
|
||||||
|
|
||||||
|
$validate = \think\facade\Validate::rule([
|
||||||
|
'id' => 'require|integer',
|
||||||
|
'value' => 'max:5120'
|
||||||
|
])
|
||||||
|
->message([
|
||||||
|
'id.require' => '配置项ID不能为空',
|
||||||
|
'id.integer' => '配置项ID必须是整数',
|
||||||
|
'value.max' => '配置值不能超过5120个字符'
|
||||||
|
]);
|
||||||
|
foreach ($put as $val) {
|
||||||
|
if (!$validate->check($val)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$configs = (new SysConfigModel)->saveAll($put);
|
||||||
|
if ($configs->isEmpty()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
171
app/admin/controller/v1/SysConfig.php
Normal file
171
app/admin/controller/v1/SysConfig.php
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\SysConfigGroupModel;
|
||||||
|
use app\admin\model\v1\SysConfigModel;
|
||||||
|
use app\admin\model\v1\SysConfigTypeModel;
|
||||||
|
use app\admin\validate\v1\SysConfigValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置项控制器
|
||||||
|
*/
|
||||||
|
class SysConfig
|
||||||
|
{
|
||||||
|
// 获取分组列表
|
||||||
|
public function groups()
|
||||||
|
{
|
||||||
|
$groups = SysConfigGroupModel::field([
|
||||||
|
'id',
|
||||||
|
'name'
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->enabled()
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return success('获取成功', $groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取配置类型
|
||||||
|
public function types()
|
||||||
|
{
|
||||||
|
$types = SysConfigTypeModel::field([
|
||||||
|
'name',
|
||||||
|
'value'
|
||||||
|
])
|
||||||
|
->order(['sort' => 'asc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return success('获取成功', $types);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置项分页
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'title',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$configs = SysConfigModel::alias('cfg')
|
||||||
|
->field([
|
||||||
|
'cfg.id',
|
||||||
|
'cfg.title',
|
||||||
|
'cfg.name',
|
||||||
|
'cfg.type',
|
||||||
|
'cfg.sort',
|
||||||
|
'grp.name' => 'group_name',
|
||||||
|
'type.name' => 'type_name'
|
||||||
|
])
|
||||||
|
->join('sys_config_group grp', 'grp.id = cfg.group_id')
|
||||||
|
->join('sys_config_type type', 'type.value = cfg.type')
|
||||||
|
->where('grp.language_id', '=', request()->lang_id)
|
||||||
|
->where(function($query) use($param) {
|
||||||
|
if (!empty($param['title'])) {
|
||||||
|
$query->where('cfg.title', 'like', "%{$param['title']}%");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->order(['cfg.group_id' => 'asc', 'cfg.sort' => 'asc', 'cfg.id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page']
|
||||||
|
]);
|
||||||
|
|
||||||
|
return success('获取成功', $configs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置项详情
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$config = SysConfigModel::withoutField([
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->bypk($id)
|
||||||
|
->find();
|
||||||
|
if (empty($config)) {
|
||||||
|
return error('配置项不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置项新增
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'group_id',
|
||||||
|
'title',
|
||||||
|
'name',
|
||||||
|
'value',
|
||||||
|
'extra',
|
||||||
|
'type' => 'text',
|
||||||
|
'sort',
|
||||||
|
'remark'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new SysConfigValidate;
|
||||||
|
if (!$validate->scene('add')->check($post)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = SysConfigModel::create($post);
|
||||||
|
if ($config->isEmpty()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置项更新
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'group_id',
|
||||||
|
'title',
|
||||||
|
'name',
|
||||||
|
'value',
|
||||||
|
'extra',
|
||||||
|
'type' => 'text',
|
||||||
|
'sort',
|
||||||
|
'remark'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new SysConfigValidate;
|
||||||
|
if (!$validate->check(array_merge($put, ['id' => $id]))) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = SysConfigModel::bypk($id)->find();
|
||||||
|
if (empty($config)) {
|
||||||
|
return error('请确认要操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$config->save($put)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置项删除
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$config = SysConfigModel::bypk($id)->find();
|
||||||
|
if (empty($config)) {
|
||||||
|
return error('请确认要操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$config->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
417
app/admin/controller/v1/System.php
Normal file
417
app/admin/controller/v1/System.php
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\ArticleCategoryModel;
|
||||||
|
use app\admin\model\v1\ArticleModel;
|
||||||
|
use app\admin\model\v1\ProductCategoryModel;
|
||||||
|
use app\admin\model\v1\ProductModel;
|
||||||
|
use think\facade\Db;
|
||||||
|
|
||||||
|
class System
|
||||||
|
{
|
||||||
|
// 系统信息
|
||||||
|
public function info()
|
||||||
|
{
|
||||||
|
$mysql_version = Db::query('select version() as version');
|
||||||
|
$info = [
|
||||||
|
[
|
||||||
|
'name' => '操作系统',
|
||||||
|
'value' => PHP_OS
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '运行环境',
|
||||||
|
'value' => $_SERVER["SERVER_SOFTWARE"]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'PHP版本',
|
||||||
|
'value' => PHP_VERSION
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '上传附件限制',
|
||||||
|
'value' => ini_get('upload_max_filesize')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'MySQL版本',
|
||||||
|
'value' => !empty($mysql_version) ? $mysql_version[0]['version'] : '未知'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '最大执行时间',
|
||||||
|
'value' => ini_get('max_execution_time') . 's'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'GD版本',
|
||||||
|
'value' => function_exists('gd_info') ? (gd_info()['GD Version']) : '未知'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '最大占用内存',
|
||||||
|
'value' => ini_get('memory_limit')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '当前时间',
|
||||||
|
'value' => date('Y-m-d H:i:s')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '服务器时区',
|
||||||
|
'value' => function_exists("date_default_timezone_get") ? date_default_timezone_get() : '未知'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '是否开启安全模式',
|
||||||
|
'value' => ini_get('safe_mode') ? 'YES' : 'NO'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '允许打开远程连接',
|
||||||
|
'value' => ini_get("allow_url_fopen") ? 'YES' : 'NO'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'CURL支持',
|
||||||
|
'value' => function_exists('curl_init') ? 'YES' : 'NO'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Zlib支持',
|
||||||
|
'value' => function_exists('gzclose') ? 'YES' : 'NO'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '自身版本',
|
||||||
|
'value' => '1.0.0'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '服务器域名/IP',
|
||||||
|
'value' => $_SERVER['HTTP_HOST'] . '[' . gethostbyname($_SERVER['SERVER_NAME']) . ']'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
return success('获取成功', $info);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组装系统内页面URL
|
||||||
|
public function urls()
|
||||||
|
{
|
||||||
|
$lang_id = request()->lang_id;
|
||||||
|
|
||||||
|
if (request()->has('link_to')) {
|
||||||
|
$param = request()->get([
|
||||||
|
'link_to',
|
||||||
|
'id'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$urls = [];
|
||||||
|
switch ($param['link_to']) {
|
||||||
|
case 'article':
|
||||||
|
$articles = $this->getArticleByCategory($lang_id, $param['id']);
|
||||||
|
$urls = array_map(function($item) {
|
||||||
|
$item['url'] = (string)url('/index/article/detail/' . $item['id']);
|
||||||
|
return $item;
|
||||||
|
}, $articles);
|
||||||
|
break;
|
||||||
|
case 'product':
|
||||||
|
$products = $this->getProductByCategory($lang_id, $param['id']);
|
||||||
|
$urls = array_map(function($item) {
|
||||||
|
$item['url'] = (string)url('/index/product/detail/' . $item['id']);
|
||||||
|
return $item;
|
||||||
|
}, $products);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return error('请确认link_to参数');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return success('获取成功', $urls);
|
||||||
|
} else {
|
||||||
|
// 获取文章分类
|
||||||
|
$article_category = $this->getArticleCategory($lang_id);
|
||||||
|
// 获取产品分类
|
||||||
|
$product_category = $this->getProductCategory($lang_id);
|
||||||
|
|
||||||
|
$urls = [
|
||||||
|
[
|
||||||
|
'name' => '自定义',
|
||||||
|
'link_to' => 'custom',
|
||||||
|
'data' => []
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '文章分类',
|
||||||
|
'link_to' => 'article_category',
|
||||||
|
'data' => array_to_tree(array_map(function($item) {
|
||||||
|
$item['url'] = (string)url('/index/article/index/' . $item['id']);
|
||||||
|
return $item;
|
||||||
|
}, $article_category), 0, 'pid', false, false)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '文章管理',
|
||||||
|
'link_to' => 'article',
|
||||||
|
'data' => array_to_tree($article_category, 0, 'pid', false, false)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '产品分类',
|
||||||
|
'link_to' => 'product_category',
|
||||||
|
'data' => array_to_tree(array_map(function($item) {
|
||||||
|
if ($item['pid'] == 0) {
|
||||||
|
$item['url'] = (string)url('/index/product/category/'. $item['id']);
|
||||||
|
} else {
|
||||||
|
$item['url'] = (string)url('/index/product/subcategory/' . $item['id']);
|
||||||
|
}
|
||||||
|
return $item;
|
||||||
|
}, $product_category), 0, 'pid', false, false)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '产品',
|
||||||
|
'link_to' => 'product',
|
||||||
|
'data' => array_to_tree($product_category, 0, 'pid', false, false)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '其他内页',
|
||||||
|
'link_to' => 'system_page',
|
||||||
|
'data' => self::getSystemOtherPages()
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
return success('获取成功', $urls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 获取文章分类数据
|
||||||
|
private function getArticleCategory($lang_id)
|
||||||
|
{
|
||||||
|
$data = ArticleCategoryModel::field([
|
||||||
|
'id',
|
||||||
|
'pid',
|
||||||
|
'name'
|
||||||
|
])
|
||||||
|
->language($lang_id)
|
||||||
|
->isShow(true)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return $data->toArray();
|
||||||
|
}
|
||||||
|
// 获取产品分类数据
|
||||||
|
private function getProductCategory($lang_id)
|
||||||
|
{
|
||||||
|
$data = ProductCategoryModel::field([
|
||||||
|
'id',
|
||||||
|
'pid',
|
||||||
|
'name'
|
||||||
|
])
|
||||||
|
->language($lang_id)
|
||||||
|
->isShow(true)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return $data->toArray();
|
||||||
|
}
|
||||||
|
// 根据文章分类获取文章
|
||||||
|
private function getArticleByCategory($lang_id, $category_id)
|
||||||
|
{
|
||||||
|
$data = ArticleModel::field([
|
||||||
|
'id',
|
||||||
|
'title' => 'name'
|
||||||
|
])
|
||||||
|
->language($lang_id)
|
||||||
|
->category($category_id)
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return $data->toArray();
|
||||||
|
}
|
||||||
|
// 根据产品分类获取产品
|
||||||
|
private function getProductByCategory($lang_id, $category_id)
|
||||||
|
{
|
||||||
|
$data = ProductModel::field([
|
||||||
|
'id',
|
||||||
|
'name'
|
||||||
|
])
|
||||||
|
->language($lang_id)
|
||||||
|
->category($category_id)
|
||||||
|
->enabled()
|
||||||
|
->isShow(true)
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return $data->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取系统其他内页
|
||||||
|
static private function getSystemOtherPages()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'name' => '首页',
|
||||||
|
'url' => (string)url('/index/index/index')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 2,
|
||||||
|
'name' => '新品上市',
|
||||||
|
'url' => (string)url('/index/product/newpro')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 3,
|
||||||
|
'name' => '附件下载',
|
||||||
|
'url' => (string)url('/index/attachment/index')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 4,
|
||||||
|
'name' => '问答中心',
|
||||||
|
'url' => (string)url('/index/faq/index')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 5,
|
||||||
|
'name' => '关于我们',
|
||||||
|
'url' => '',
|
||||||
|
'children' => [
|
||||||
|
[
|
||||||
|
'id' => 51,
|
||||||
|
'name' => '品牌介绍',
|
||||||
|
'url' => (string)url('/index/aboutus/introduction')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 52,
|
||||||
|
'name' => '品牌故事',
|
||||||
|
'url' => (string)url('/index/aboutus/story')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 53,
|
||||||
|
'name' => '品牌历程',
|
||||||
|
'url' => (string)url('/index/aboutus/mileage')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 54,
|
||||||
|
'name' => '文化介绍',
|
||||||
|
'url' => (string)url('/index/aboutus/culture')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 55,
|
||||||
|
'name' => '售后政策',
|
||||||
|
'url' => (string)url('/index/aboutus/policy')
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 6,
|
||||||
|
'name' => '联系我们',
|
||||||
|
'url' => '',
|
||||||
|
'children' => [
|
||||||
|
[
|
||||||
|
'id' => 61,
|
||||||
|
'name' => '联系我们',
|
||||||
|
'url' => (string)url('/index/contactus/index')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 62,
|
||||||
|
'name' => '留言联系我们',
|
||||||
|
'url' => (string)url('/index/contactus/message')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 63,
|
||||||
|
'name' => '留言成为分销商',
|
||||||
|
'url' => (string)url('/index/contactus/distributor')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 64,
|
||||||
|
'name' => '留言批量购买',
|
||||||
|
'url' => (string)url('/index/contactus/bulkbuy')
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 7,
|
||||||
|
'name' => 'NAS专题',
|
||||||
|
'url' => '',
|
||||||
|
'children' => [
|
||||||
|
[
|
||||||
|
'id' => 71,
|
||||||
|
'name' => '首页',
|
||||||
|
'url' => (string)url('/index/topic/nas/index')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 72,
|
||||||
|
'name' => '产品体验',
|
||||||
|
'url' => (string)url('/index/topic/nas/product')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 73,
|
||||||
|
'name' => '客户合作',
|
||||||
|
'url' => (string)url('/index/topic/nas/cooperation')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 74,
|
||||||
|
'name' => '帮助中心',
|
||||||
|
'url' => (string)url('/index/topic/nas/help')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 75,
|
||||||
|
'name' => '软件下载',
|
||||||
|
'url' => (string)url('/index/topic/nas/download')
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据系统页面url获取回显数据项
|
||||||
|
static public function getEchoDataBySystemPageUrl($link_to, $link)
|
||||||
|
{
|
||||||
|
if ('custom' == $link_to || empty($link)) return [];
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
$params = [];
|
||||||
|
$url = parse_url($link, PHP_URL_QUERY);
|
||||||
|
if (empty($url)) {
|
||||||
|
$parts = explode('/', trim($link, '/'));
|
||||||
|
$params['id'] = (int)str_replace('.html', '', end($parts));
|
||||||
|
} else {
|
||||||
|
parse_str($url, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($link_to) {
|
||||||
|
case 'article_category':
|
||||||
|
if (empty($params['id'])) return [];
|
||||||
|
$data = ArticleCategoryModel::field(['id', 'name'])->bypk($params['id'])->find();
|
||||||
|
break;
|
||||||
|
case 'article':
|
||||||
|
if (empty($params['id'])) return [];
|
||||||
|
$data = ArticleModel::field(['id', 'title' => 'name'])->bypk($params['id'])->find();
|
||||||
|
break;
|
||||||
|
case 'product_category':
|
||||||
|
if (empty($params['id'])) return [];
|
||||||
|
$data = ProductCategoryModel::field(['id', 'name'])->bypk($params['id'])->find();
|
||||||
|
break;
|
||||||
|
case 'product':
|
||||||
|
if (empty($params['id'])) return [];
|
||||||
|
$data = ProductModel::field(['id', 'name'])->bypk($params['id'])->find();
|
||||||
|
break;
|
||||||
|
case 'system_page':
|
||||||
|
$data = self::filterSystemOtherPage(self::getSystemOtherPages(), function($item) use ($params, $link) {
|
||||||
|
if (empty($params['id'])) return $item['url'] == $link;
|
||||||
|
return $item['id'] == $params['id'];
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (empty($data)) return [];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => $data['id'],
|
||||||
|
'name' => $data['name'],
|
||||||
|
'link' => $link
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据条件过滤结果
|
||||||
|
static private function filterSystemOtherPage(array $data, callable $callback): array
|
||||||
|
{
|
||||||
|
foreach ($data as $it) {
|
||||||
|
if ($callback($it)) {
|
||||||
|
return $it;
|
||||||
|
}
|
||||||
|
if (isset($it['children'])) {
|
||||||
|
$child = self::filterSystemOtherPage($it['children'], $callback);
|
||||||
|
if (!empty($child)) {
|
||||||
|
return $child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
475
app/admin/controller/v1/Upload.php
Normal file
475
app/admin/controller/v1/Upload.php
Normal file
@@ -0,0 +1,475 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\SysImageUploadRecordModel;
|
||||||
|
use app\admin\model\v1\SysVideoUploadRecordModel;
|
||||||
|
use app\admin\model\v1\SysAttachmentUploadRecordModel;
|
||||||
|
use Intervention\Image\ImageManager;
|
||||||
|
use Intervention\Image\Typography\FontFactory;
|
||||||
|
use think\facade\Filesystem;
|
||||||
|
use filesystem\Qiniu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传控制器
|
||||||
|
*/
|
||||||
|
class Upload
|
||||||
|
{
|
||||||
|
// 上传图片
|
||||||
|
public function image()
|
||||||
|
{
|
||||||
|
$param = request()->param(['module' => 'unknown']);
|
||||||
|
if (is_null($param)) {
|
||||||
|
return error('请确定请求参数正确');
|
||||||
|
}
|
||||||
|
$file = request()->file('image');
|
||||||
|
if (is_null($file)) {
|
||||||
|
return error('请确定上传对象或字段是否正确');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$max_size = strtobytes(env('ADMIN_API.MAX_IMAGE_SIZE', '1mb'));
|
||||||
|
$validate = validate([
|
||||||
|
'module' => 'require|max:64',
|
||||||
|
'image' => "fileSize:$max_size|fileExt:jpg,jpeg,png,gif,webp"
|
||||||
|
]);
|
||||||
|
if (!$validate->check(['module' => $param['module'], 'image' => $file])) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$storage = config('filesystem.disks.image.url');
|
||||||
|
|
||||||
|
$filemd5 = $file->md5();
|
||||||
|
$filesha1 = $file->sha1();
|
||||||
|
|
||||||
|
// 获取图片上传配置
|
||||||
|
list(
|
||||||
|
'filename_keep' => $filename_keep,
|
||||||
|
'filemd5_unique' => $filemd5_unique,
|
||||||
|
'filetype_to' => $filetype_to,
|
||||||
|
) = $this->getUploadOptions('upload_image');
|
||||||
|
|
||||||
|
// 获取文件大小
|
||||||
|
$file_size = $file->getSize();
|
||||||
|
// 获取文件mime类型
|
||||||
|
$mime_type = $file->getOriginalMime();
|
||||||
|
|
||||||
|
// 是否需要根据文件MD5值检查文件是否已存在
|
||||||
|
$image_model = $filemd5_unique ? SysImageUploadRecordModel::md5($filemd5)->find() : null;
|
||||||
|
if (is_null($image_model)) {
|
||||||
|
// 检查是否需要保留原文件名生成器
|
||||||
|
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
|
||||||
|
|
||||||
|
// 处理图片
|
||||||
|
$image_manager = ImageManager::gd();
|
||||||
|
if ($filetype_to == 'original') {
|
||||||
|
$filename = Filesystem::disk('image')->putFile($param['module'], $file, $name_rule());
|
||||||
|
$image = $image_manager->read('.' . $storage . '/' . $filename);
|
||||||
|
}
|
||||||
|
else if ($filetype_to == 'webp') {
|
||||||
|
$image = $image_manager->read($file->getRealPath());
|
||||||
|
// 转换为webp格式
|
||||||
|
$webp = $image->toWebp(75);
|
||||||
|
$root = config('filesystem.disks.image.root');
|
||||||
|
$filename = $param['module'] . '/' . ($name_rule() ? $name_rule()() : date('Ymd') . '/' . md5((string)time() . random_str(8))) . '.webp';
|
||||||
|
$webp->save($this->checkPath($root . '/' . $filename));
|
||||||
|
// 获取webp文件大小
|
||||||
|
$file_size = $webp->size();
|
||||||
|
// 获取webp文件mime类型
|
||||||
|
$mime_type = $webp->mimetype();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 水印
|
||||||
|
list(
|
||||||
|
'enabled' => $enabled,
|
||||||
|
'type' => $type,
|
||||||
|
'text_options' => $text_options,
|
||||||
|
'image_options' => $image_options
|
||||||
|
) = $this->getWatermarkOptions();
|
||||||
|
if ($enabled) {
|
||||||
|
// 图片水印
|
||||||
|
if ($type == 'IMAGE' && $image_options['image'] != '') {
|
||||||
|
// 读取水印图片
|
||||||
|
$watermark_image = $image_manager->read(public_path() . $image_options['image']);
|
||||||
|
// 缩放水印图片
|
||||||
|
$watermark_image->scale($image_options['width'], $image_options['height']);
|
||||||
|
// 绘制水印图片
|
||||||
|
$image->place(
|
||||||
|
$watermark_image,
|
||||||
|
$image_options['position'],
|
||||||
|
$image_options['offset_x'],
|
||||||
|
$image_options['offset_y'],
|
||||||
|
$image_options['opacity']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 文字水印
|
||||||
|
else if ($type == 'TEXT' && $text_options['txt'] != '') {
|
||||||
|
// 原图宽度
|
||||||
|
$origin_width = $image->width();
|
||||||
|
// 原图高度
|
||||||
|
$origin_height = $image->height();
|
||||||
|
|
||||||
|
$font_factory = new FontFactory(function(FontFactory $font) use($text_options) {
|
||||||
|
// 设置字体
|
||||||
|
$font->filename(public_path() . $text_options['font']);
|
||||||
|
// 设置字体大小
|
||||||
|
$font->size($text_options['size']);
|
||||||
|
// 设置字体颜色及透明度
|
||||||
|
$opacity = $text_options['opacity'] > 0 ? dechex((int)ceil(255 * ($text_options['opacity'] / 100))) : '00';
|
||||||
|
$font->color($text_options['color'] . $opacity);
|
||||||
|
$font->align('left');
|
||||||
|
$font->valign('top');
|
||||||
|
});
|
||||||
|
// 文字尺寸
|
||||||
|
$font_rect = $image->driver()->fontProcessor()->boxSize($text_options['txt'], $font_factory());
|
||||||
|
// 计算偏移量
|
||||||
|
list($offset_x, $offset_y) = $this->scaleTxtOffsetXYByPosition(
|
||||||
|
$text_options['position'],
|
||||||
|
$text_options['offset_x'],
|
||||||
|
$text_options['offset_y'],
|
||||||
|
$origin_width,
|
||||||
|
$origin_height,
|
||||||
|
$font_rect->width(),
|
||||||
|
$font_rect->height()
|
||||||
|
);
|
||||||
|
// 绘制文字
|
||||||
|
$image->text(
|
||||||
|
$text_options['txt'],
|
||||||
|
$offset_x,
|
||||||
|
$offset_y,
|
||||||
|
$font_factory()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$image->save('.'. $storage. '/'. $filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缩略图
|
||||||
|
$image->scale(200, 200);
|
||||||
|
$idx = strrpos($filename, '.');
|
||||||
|
$thumb_filename = mb_substr($filename, 0, $idx) . '_thumb.' . mb_substr($filename, $idx + 1);
|
||||||
|
$image->save('.' . $storage . '/' . $thumb_filename);
|
||||||
|
|
||||||
|
// 保存图片
|
||||||
|
$image_model = new SysImageUploadRecordModel();
|
||||||
|
$image_model->language_id = request()->lang_id;
|
||||||
|
$image_model->module = $param['module'];
|
||||||
|
$image_model->image_path = $storage . '/' . $filename;
|
||||||
|
$image_model->image_thumb = $storage . '/' . $thumb_filename;
|
||||||
|
$image_model->file_size = $file_size;
|
||||||
|
$image_model->file_type = $mime_type;
|
||||||
|
$image_model->file_md5 = $filemd5;
|
||||||
|
$image_model->file_sha1 = $filesha1;
|
||||||
|
if (!$image_model->save()) {
|
||||||
|
return error('上传失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功', [
|
||||||
|
'path' => $image_model->image_path,
|
||||||
|
'thumb_path' => $image_model->image_thumb,
|
||||||
|
'filemd5' => $image_model->file_md5,
|
||||||
|
'filesha1' => $image_model->file_sha1
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
return error($th->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return error('上传失败');
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 检查路径
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function checkPath($path): string
|
||||||
|
{
|
||||||
|
$ok = true;
|
||||||
|
$filename = basename($path);
|
||||||
|
$dirname = dirname($path);
|
||||||
|
if (!is_dir($dirname)) {
|
||||||
|
$ok = @mkdir($dirname, 0755, true);
|
||||||
|
}
|
||||||
|
else if (!is_writable($dirname)) {
|
||||||
|
$ok = @chmod($dirname,0755);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ok) {
|
||||||
|
return $dirname . '/' . $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \Exception("上传目标目录不可用");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 文件名生成回调
|
||||||
|
*
|
||||||
|
* @param \think\file\UploadedFile $file
|
||||||
|
* @return callable
|
||||||
|
*/
|
||||||
|
private function filenameGenerator(\think\file\UploadedFile $file): callable
|
||||||
|
{
|
||||||
|
return fn() => date('Ymd') . '/' . pathinfo($file->getOriginalName(), PATHINFO_FILENAME);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取上传配置
|
||||||
|
*
|
||||||
|
* @param string $module
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getUploadOptions($module)
|
||||||
|
{
|
||||||
|
$config_model = new \app\admin\controller\v1\SiteConfig;
|
||||||
|
$config = $config_model->getByGroupUniqueLabel('upload');
|
||||||
|
$options = data_get($config, $module, []);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'filename_keep' => (int)data_get($options, 'filename_keep.value', 0) == 1,
|
||||||
|
'filemd5_unique' => (int)data_get($options, 'filemd5_unique.value', 0) == 1,
|
||||||
|
'filetype_to' => data_get($options, 'filetype_to.value', 'original'),
|
||||||
|
'save_to' => data_get($options, 'save_to.value', 'local'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取水印配置
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getWatermarkOptions(): array
|
||||||
|
{
|
||||||
|
$config_model = new \app\admin\controller\v1\SiteConfig;
|
||||||
|
$watermark_config = $config_model->getByGroupUniqueLabel('watermark');
|
||||||
|
|
||||||
|
$opacity = data_get($watermark_config, 'watermark_opacity.value', 100);
|
||||||
|
if ($opacity == '') {
|
||||||
|
$opacity = 100;
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'enabled' => data_get($watermark_config, 'watermark_enabled.value', 0) == 1,
|
||||||
|
'type' => data_get($watermark_config, 'watermark_type.value', ''),
|
||||||
|
'text_options' => [
|
||||||
|
'txt' => data_get($watermark_config, 'watermark_text_value.value', ''),
|
||||||
|
'font' => data_get($watermark_config, 'watermark_text_font.value', ''),
|
||||||
|
'size' => (float)data_get($watermark_config, 'watermark_text_size.value', 12)?:12,
|
||||||
|
'color' => data_get($watermark_config, 'watermark_text_color.value', '#000000')?:'#000000',
|
||||||
|
'position' => data_get($watermark_config, 'watermark_position.value', 'top-left')?:'top-left',
|
||||||
|
'offset_x' => (int)data_get($watermark_config, 'watermark_offset_x.value', 0),
|
||||||
|
'offset_y' => (int)data_get($watermark_config, 'watermark_offset_y.value', 0),
|
||||||
|
'opacity' => (int)$opacity,
|
||||||
|
],
|
||||||
|
'image_options' => [
|
||||||
|
'image' => data_get($watermark_config, 'watermark_image_value.value', ''),
|
||||||
|
'width' => (int)data_get($watermark_config, 'watermark_image_width.value')?:null,
|
||||||
|
'height' => (int)data_get($watermark_config, 'watermark_image_height.value')?:null,
|
||||||
|
'position' => data_get($watermark_config, 'watermark_position.value', 'top-left')?:'top-left',
|
||||||
|
'offset_x' => (int)data_get($watermark_config, 'watermark_offset_x.value', 0),
|
||||||
|
'offset_y' => (int)data_get($watermark_config, 'watermark_offset_y.value', 0),
|
||||||
|
'opacity' => (int)$opacity,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 计算文本水印偏移量
|
||||||
|
*
|
||||||
|
* @param string $position
|
||||||
|
* @param integer $offset_x
|
||||||
|
* @param integer $offset_y
|
||||||
|
* @param integer $image_width
|
||||||
|
* @param integer $image_height
|
||||||
|
* @param integer $txt_width
|
||||||
|
* @param integer $txt_height
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function scaleTxtOffsetXYByPosition(string $position, int $offset_x, int $offset_y, int $image_width, int $image_height, int $txt_width, int $txt_height)
|
||||||
|
{
|
||||||
|
switch ($position) {
|
||||||
|
case 'top-left':
|
||||||
|
// top-left:左上角
|
||||||
|
return [$offset_x, $offset_y];
|
||||||
|
case 'top-right':
|
||||||
|
// top-right:右上角
|
||||||
|
return [(int)($image_width-$txt_width-$offset_x), $offset_y];
|
||||||
|
case 'top':
|
||||||
|
// top:上 - 水平居中
|
||||||
|
return [(int)(($image_width-$txt_width+$offset_x)/2), $offset_y];
|
||||||
|
case 'left':
|
||||||
|
// left:左 - 垂直居中
|
||||||
|
return [$offset_x, (int)(($image_height-$txt_height)/2+$offset_y)];
|
||||||
|
case 'center':
|
||||||
|
// center:水平垂直居中
|
||||||
|
return [(int)(($image_width-$txt_width)/2+$offset_x), (int)(($image_height-$txt_height)/2+$offset_y)];
|
||||||
|
case 'right':
|
||||||
|
// right:右 - 垂直居中
|
||||||
|
return [(int)($image_width-$txt_width-$offset_x), (int)(($image_height-$txt_height)/2+$offset_y)];
|
||||||
|
case'bottom':
|
||||||
|
// bottom:下 - 水平居中
|
||||||
|
return [(int)(($image_width-$txt_width+$offset_x)/2), (int)($image_height-$txt_height-$offset_y)];
|
||||||
|
case'bottom-left':
|
||||||
|
// bottom-left:左下角
|
||||||
|
return [$offset_x, (int)($image_height-$txt_height-$offset_y)];
|
||||||
|
case'bottom-right':
|
||||||
|
// bottom-right:右下角
|
||||||
|
return [(int)($image_width-$txt_width-$offset_x), (int)($image_height-$txt_height-$offset_y)];
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException('Invalid position');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传视频
|
||||||
|
*/
|
||||||
|
public function video()
|
||||||
|
{
|
||||||
|
$param = request()->param(['module' => 'unknown']);
|
||||||
|
if (is_null($param)) {
|
||||||
|
return error('请确定请求参数正确');
|
||||||
|
}
|
||||||
|
$file = request()->file('video');
|
||||||
|
if (is_null($file)) {
|
||||||
|
return error('请确定上传对象或字段是否正确');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$max_size = strtobytes(env('ADMIN_API.MAX_VIDEO_SIZE', '100mb'));
|
||||||
|
$validate = validate([
|
||||||
|
'module' => 'require|max:64',
|
||||||
|
'video' => "fileSize:$max_size|fileExt:mp4"
|
||||||
|
]);
|
||||||
|
if (!$validate->check(['module' => $param['module'], 'video' => $file])) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$storage = config('filesystem.disks.video.url');
|
||||||
|
|
||||||
|
$filemd5 = $file->md5();
|
||||||
|
$filesha1 = $file->sha1();
|
||||||
|
|
||||||
|
// 获取视频上传配置
|
||||||
|
list(
|
||||||
|
'filename_keep' => $filename_keep,
|
||||||
|
'filemd5_unique' => $filemd5_unique,
|
||||||
|
'save_to' => $save_to,
|
||||||
|
) = $this->getUploadOptions('upload_video');
|
||||||
|
// 是否需要根据文件MD5值检查文件是否已存在
|
||||||
|
$video = $filemd5_unique ? SysVideoUploadRecordModel::md5($filemd5)->find() : null;
|
||||||
|
if (is_null($video)) {
|
||||||
|
// 保存位置配置 key
|
||||||
|
$disk = 'video';
|
||||||
|
// 检查是否需要保留原文件名
|
||||||
|
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
|
||||||
|
|
||||||
|
// 保存到七牛云
|
||||||
|
if ($save_to == 'qiniu_cloud') {
|
||||||
|
$disk = 'video_qiniu';
|
||||||
|
$storage = config('filesystem.disks.video_qiniu.path_prefix');
|
||||||
|
}
|
||||||
|
$filename = Filesystem::disk($disk)->putFile($param['module'], $file, $name_rule());
|
||||||
|
|
||||||
|
// 组装视频路径
|
||||||
|
$video_path = $storage . '/' . $filename;
|
||||||
|
if ($save_to == 'qiniu_cloud') {
|
||||||
|
$video_path = Filesystem::disk($disk)->url($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存视频
|
||||||
|
$video = new SysVideoUploadRecordModel();
|
||||||
|
$video->language_id = request()->lang_id;
|
||||||
|
$video->module = $param['module'];
|
||||||
|
$video->video_path = $video_path;
|
||||||
|
$video->file_size = $file->getSize();
|
||||||
|
$video->file_type = $file->getOriginalMime();
|
||||||
|
$video->file_md5 = $filemd5;
|
||||||
|
$video->file_sha1 = $filesha1;
|
||||||
|
if (!$video->save()) {
|
||||||
|
return error('上传失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('上传成功', [
|
||||||
|
'path' => $video->video_path,
|
||||||
|
'file_md5' => $video->file_md5,
|
||||||
|
'file_sha1' => $video->file_sha1
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
return error($th->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return error('上传失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件上传
|
||||||
|
*/
|
||||||
|
public function attachment()
|
||||||
|
{
|
||||||
|
$file = request()->file('attachment');
|
||||||
|
if (is_null($file)) {
|
||||||
|
return error('请确定上传对象或字段是否正确');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$max_size = strtobytes(env('ADMIN_API.MAX_ATTACHMENT_SIZE', '100mb'));
|
||||||
|
$validate = validate([
|
||||||
|
'attachment' => "fileSize:$max_size|fileExt:biz,bz,bz2,gz,tgz,zip,rar,7z,doc,docx,xls,xlsx,csv,ppt,pptx,pdf,txt,jpg,jpeg,png,webp,ttf"
|
||||||
|
]);
|
||||||
|
if (!$validate->check(['attachment' => $file])) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$storage = config('filesystem.disks.public.url');
|
||||||
|
|
||||||
|
$filemd5 = $file->md5();
|
||||||
|
$filesha1 = $file->sha1();
|
||||||
|
|
||||||
|
// 获取附件上传配置
|
||||||
|
list(
|
||||||
|
'filename_keep' => $filename_keep,
|
||||||
|
'filemd5_unique' => $filemd5_unique,
|
||||||
|
'save_to' => $save_to
|
||||||
|
) = $this->getUploadOptions('upload_attachment');
|
||||||
|
// 是否需要根据文件MD5值检查文件是否已存在
|
||||||
|
$attachment = $filemd5_unique ? SysAttachmentUploadRecordModel::md5($filemd5)->find() : null;
|
||||||
|
if (is_null($attachment)) {
|
||||||
|
// 保存位置配置 key
|
||||||
|
$disk = 'public';
|
||||||
|
// 检查是否需要保留原文件名
|
||||||
|
$name_rule = fn() => $filename_keep ? $this->filenameGenerator($file) : null;
|
||||||
|
|
||||||
|
// 保存到七牛云
|
||||||
|
if ($save_to == 'qiniu_cloud') {
|
||||||
|
$disk = 'public_qiniu';
|
||||||
|
$storage = config('filesystem.disks.public_qiniu.path_prefix');
|
||||||
|
}
|
||||||
|
$filename = Filesystem::disk($disk)->putFile('attachments', $file, $name_rule());
|
||||||
|
|
||||||
|
// 组装附件路径
|
||||||
|
$attachment_path = $storage . '/' . $filename;
|
||||||
|
if ($save_to == 'qiniu_cloud') {
|
||||||
|
$attachment_path = Filesystem::disk($disk)->url($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存附件
|
||||||
|
$attachment = new SysAttachmentUploadRecordModel();
|
||||||
|
$attachment->language_id = request()->lang_id;
|
||||||
|
$attachment->attachment_path = $attachment_path;
|
||||||
|
$attachment->file_size = $file->getSize();
|
||||||
|
$attachment->file_type = $file->getOriginalMime();
|
||||||
|
$attachment->file_md5 = $filemd5;
|
||||||
|
$attachment->file_sha1 = $filesha1;
|
||||||
|
if (!$attachment->save()) {
|
||||||
|
return error('上传失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('上传成功', [
|
||||||
|
'path' => $attachment->attachment_path,
|
||||||
|
'file_md5' => $attachment->file_md5,
|
||||||
|
'file_sha1' => $attachment->file_sha1
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
return error($th->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return error('上传失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
255
app/admin/controller/v1/User.php
Normal file
255
app/admin/controller/v1/User.php
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\SysMenuModel;
|
||||||
|
use app\admin\model\v1\SysRoleAuthorityModel;
|
||||||
|
use app\admin\model\v1\SysUserLoginLogModel;
|
||||||
|
use app\admin\model\v1\SysUserModel;
|
||||||
|
use app\admin\validate\v1\SysUserValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户管理控制器
|
||||||
|
*/
|
||||||
|
class User
|
||||||
|
{
|
||||||
|
// 获取用户菜单权限
|
||||||
|
public function menu()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$user = SysUserModel::bypk($id)->find();
|
||||||
|
if (empty($user)) {
|
||||||
|
return error('用户不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
$menus = SysMenuModel::alias('menu')->field([
|
||||||
|
'menu.id',
|
||||||
|
'menu.pid',
|
||||||
|
'menu.title',
|
||||||
|
'menu.name',
|
||||||
|
'menu.path',
|
||||||
|
'menu.icon',
|
||||||
|
'menu.redirect',
|
||||||
|
'menu.component',
|
||||||
|
'menu.hidden',
|
||||||
|
'menu.actived',
|
||||||
|
'menu.keep_alive'
|
||||||
|
])
|
||||||
|
->where('menu.status', '=', 1)
|
||||||
|
->whereExists(function($query) use($user) {
|
||||||
|
$query->table((new SysRoleAuthorityModel)->getTable())->alias('authority')
|
||||||
|
->where('authority.role_id', '=', $user->role_id)
|
||||||
|
->where('authority.menu_id = menu.id')
|
||||||
|
->group('authority.menu_id');
|
||||||
|
})
|
||||||
|
->order(['menu.sort' => 'asc', 'menu.id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
if (!$menus->isEmpty()) {
|
||||||
|
$authoritys = SysRoleAuthorityModel::field([
|
||||||
|
'menu_id',
|
||||||
|
'permission'
|
||||||
|
])
|
||||||
|
->roleId($user->role_id)
|
||||||
|
->whereNotNull('permission')
|
||||||
|
->select();
|
||||||
|
$authoritys_map = [];
|
||||||
|
foreach ($authoritys as $val) {
|
||||||
|
$authoritys_map[$val['menu_id']][] = $val['permission'];
|
||||||
|
}
|
||||||
|
$menus->each(function($item) use($authoritys_map) {
|
||||||
|
$meta = [
|
||||||
|
'title' => $item['title'],
|
||||||
|
'icon' => $item['icon'],
|
||||||
|
'isKeepAlive' => !!$item['keep_alive'],
|
||||||
|
'actived' => !!$item['actived'],
|
||||||
|
'permissions' => []
|
||||||
|
];
|
||||||
|
unset($item['title'], $item['icon'], $item['keep_alive'], $item['actived']);
|
||||||
|
if (isset($authoritys_map[$item['id']])) {
|
||||||
|
$meta['permissions'] = $authoritys_map[$item['id']];
|
||||||
|
}
|
||||||
|
$item['hidden'] = !!$item['hidden'];
|
||||||
|
$item['meta'] = $meta;
|
||||||
|
return $item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', array_to_tree($menus->toArray(), 0, 'pid', false));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户分页数据
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$params = request()->get([
|
||||||
|
'username',
|
||||||
|
'status',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$users = SysUserModel::withoutField([
|
||||||
|
'password',
|
||||||
|
'salt',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->with(['role' => function($query) {
|
||||||
|
$query->field(['id', 'name' => 'role_name']);
|
||||||
|
}])
|
||||||
|
->withSearch(['username'], [
|
||||||
|
'username' => $params['username']??null,
|
||||||
|
])
|
||||||
|
->status($params['status']??null)
|
||||||
|
->order('id', 'desc')
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $params['size'],
|
||||||
|
'page' => $params['page'],
|
||||||
|
])
|
||||||
|
->bindAttr('role', ['role_name'])
|
||||||
|
->hidden(['role_id', 'role']);
|
||||||
|
if ($users->isEmpty()) {
|
||||||
|
return success('获取成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询用户最后登录记录
|
||||||
|
$logs = SysUserLoginLogModel::where('id', 'IN', function($query) use($users) {
|
||||||
|
$query->table((new SysUserLoginLogModel)->getTable())
|
||||||
|
->field(['MAX(id)'])
|
||||||
|
->whereIn('user_id', array_column($users->items(), 'id'))
|
||||||
|
->group('user_id');
|
||||||
|
})
|
||||||
|
->column([
|
||||||
|
'ip',
|
||||||
|
'created_at'
|
||||||
|
], 'user_id');
|
||||||
|
if (!empty($logs)) {
|
||||||
|
$users->each(function($item) use($logs) {
|
||||||
|
$item['last_login_ip'] = '';
|
||||||
|
$item['last_login_at'] = '';
|
||||||
|
if (!empty($logs[$item['id']])) {
|
||||||
|
$item['last_login_ip'] = long2ip($logs[$item['id']]['ip']);
|
||||||
|
$item['last_login_at'] = $logs[$item['id']]['created_at'];
|
||||||
|
}
|
||||||
|
return $item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $users);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户详情
|
||||||
|
public function read($id)
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$user = SysUserModel::withoutField([
|
||||||
|
'password',
|
||||||
|
'salt',
|
||||||
|
'delete_disable',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at',
|
||||||
|
])
|
||||||
|
->bypk($id)
|
||||||
|
->find();
|
||||||
|
if (empty($user)) {
|
||||||
|
return error('用户不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户新增
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'username',
|
||||||
|
'password',
|
||||||
|
'repassword',
|
||||||
|
'nickname',
|
||||||
|
'avatar',
|
||||||
|
'mobile',
|
||||||
|
'email',
|
||||||
|
'role_id',
|
||||||
|
'status' => 1,
|
||||||
|
]);
|
||||||
|
$post = array_merge($post, ['salt' => random_str(16)]);
|
||||||
|
|
||||||
|
$validate = new SysUserValidate;
|
||||||
|
if (!$validate->scene('create')->check($post)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$post['password'] = password_with_salt($post['password'], $post['salt']);
|
||||||
|
unset($post['repassword']);
|
||||||
|
$user = SysUserModel::create($post);
|
||||||
|
if ($user->isEmpty()) {
|
||||||
|
return error('新增失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('新增成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户更新
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'username',
|
||||||
|
'password',
|
||||||
|
'repassword',
|
||||||
|
'nickname',
|
||||||
|
'avatar',
|
||||||
|
'mobile',
|
||||||
|
'email',
|
||||||
|
'role_id',
|
||||||
|
'status' => 1,
|
||||||
|
]);
|
||||||
|
$data = array_merge($put, ['id' => $id]);
|
||||||
|
|
||||||
|
$validate = new SysUserValidate;
|
||||||
|
if (!$validate->scene('update')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = SysUserModel::bypk($id)->find();
|
||||||
|
if (empty($user)) {
|
||||||
|
return error('请确认要操作的对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($data['password'])) {
|
||||||
|
$data['salt'] = random_str(16);
|
||||||
|
$data['password'] = password_with_salt($data['password'], $data['salt']);
|
||||||
|
} else {
|
||||||
|
unset($data['password']);
|
||||||
|
}
|
||||||
|
unset($data['repassword']);
|
||||||
|
if (!$user->save($data)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户删除
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$user = SysUserModel::bypk($id)->find();
|
||||||
|
if (empty($user)) {
|
||||||
|
return error('请确认要操作的对象是否存在');
|
||||||
|
}
|
||||||
|
if ($user->delete_disable == 1) {
|
||||||
|
return error('该用户禁止删除');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$user->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,18 +4,21 @@ declare (strict_types = 1);
|
|||||||
namespace app\admin\controller\v1;
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
use app\admin\exception\InvalidLoginException;
|
use app\admin\exception\InvalidLoginException;
|
||||||
use app\admin\model\v1\UserLoginLogModel;
|
use app\admin\model\v1\SysUserLoginLogModel;
|
||||||
use app\admin\model\v1\UserModel;
|
use app\admin\model\v1\SysUserModel;
|
||||||
use app\admin\validate\v1\LoginValidate;
|
use app\admin\validate\v1\LoginValidate;
|
||||||
use thans\jwt\facade\JWTAuth;
|
use thans\jwt\facade\JWTAuth;
|
||||||
use think\facade\Cache;
|
use think\facade\Cache;
|
||||||
|
|
||||||
class Login
|
/**
|
||||||
|
* 用户中心控制器
|
||||||
|
*/
|
||||||
|
class UserCenter
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* 登录验证接口
|
* 登录验证接口
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function login()
|
||||||
{
|
{
|
||||||
// 获取参数
|
// 获取参数
|
||||||
$post = request()->post([
|
$post = request()->post([
|
||||||
@@ -25,7 +28,7 @@ class Login
|
|||||||
'captcha'
|
'captcha'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = new UserModel();
|
$user = new SysUserModel();
|
||||||
$msg = '';
|
$msg = '';
|
||||||
try {
|
try {
|
||||||
// 验证参数
|
// 验证参数
|
||||||
@@ -34,6 +37,7 @@ class Login
|
|||||||
throw new InvalidLoginException($validate->getError());
|
throw new InvalidLoginException($validate->getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($post['captcha'])) {
|
||||||
// 校验验证码
|
// 校验验证码
|
||||||
$code = Cache::get('captcha:token.' . $post['token']);
|
$code = Cache::get('captcha:token.' . $post['token']);
|
||||||
if (!$code) {
|
if (!$code) {
|
||||||
@@ -45,9 +49,10 @@ class Login
|
|||||||
if (!password_verify($post['captcha'], $code)) {
|
if (!password_verify($post['captcha'], $code)) {
|
||||||
throw new InvalidLoginException('验证码错误');
|
throw new InvalidLoginException('验证码错误');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 验证用户
|
// 验证用户
|
||||||
$user = UserModel::usernameOrMobile($post['username'])->find();
|
$user = SysUserModel::usernameOrMobile($post['username'])->find();
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
throw new InvalidLoginException('用户不存在');
|
throw new InvalidLoginException('用户不存在');
|
||||||
}
|
}
|
||||||
@@ -70,7 +75,7 @@ class Login
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 记录登录日志
|
// 记录登录日志
|
||||||
UserLoginLogModel::create([
|
SysUserLoginLogModel::create([
|
||||||
'user_id' => $user['id'],
|
'user_id' => $user['id'],
|
||||||
'ip' => ip2long(request()->ip()),
|
'ip' => ip2long(request()->ip()),
|
||||||
'user_agent' => request()->header('user-agent'),
|
'user_agent' => request()->header('user-agent'),
|
||||||
@@ -81,9 +86,23 @@ class Login
|
|||||||
|
|
||||||
return success('登录成功', [
|
return success('登录成功', [
|
||||||
'uid' => $user['id'],
|
'uid' => $user['id'],
|
||||||
'nickname' => $user['nickname'],
|
'username' => $user['username'],
|
||||||
'avatar' => $user['avatar'],
|
'avatar' => $user['avatar'],
|
||||||
'token' => $token,
|
'token' => $token,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 退出登录
|
||||||
|
public function logout()
|
||||||
|
{
|
||||||
|
$token = request()->header('Authorization');
|
||||||
|
if (\think\helper\Str::startsWith($token, 'Bearer ')) {
|
||||||
|
$token = substr($token, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// token 加入黑名单
|
||||||
|
JWTAuth::invalidate($token);
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
255
app/admin/controller/v1/Video.php
Normal file
255
app/admin/controller/v1/Video.php
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\VideoModel;
|
||||||
|
use app\admin\validate\v1\VideoValidate;
|
||||||
|
use think\facade\Config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频管理控制器
|
||||||
|
*/
|
||||||
|
class Video
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 视频信息分页数据
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$params = request()->param([
|
||||||
|
'name',
|
||||||
|
'category_id',
|
||||||
|
'created_at',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
$videos = VideoModel::field([
|
||||||
|
'id',
|
||||||
|
'image',
|
||||||
|
'name',
|
||||||
|
'category_id',
|
||||||
|
'sort',
|
||||||
|
'recommend',
|
||||||
|
'created_at'
|
||||||
|
])
|
||||||
|
->with(['category' => function ($query) {
|
||||||
|
$query->field(['id', 'name' => 'category_name']);
|
||||||
|
}])
|
||||||
|
->withSearch(['name', 'created_at'], [
|
||||||
|
'name' => $params['name'] ?? null,
|
||||||
|
'created_at' => !empty($params['created_at']) ? explode(",", $params['created_at']) : null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->categoryId($params['category_id'] ?? null)
|
||||||
|
->order(['sort' => 'desc', 'id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $params['size'],
|
||||||
|
'page' => $params['page'],
|
||||||
|
])
|
||||||
|
->bindAttr('category', ['category_name'])
|
||||||
|
->hidden(['category', 'category_id'])
|
||||||
|
?->each(fn($item) => $item->image = thumb($item->image));
|
||||||
|
|
||||||
|
return success('获取成功', $videos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频信息详情
|
||||||
|
*/
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$video = VideoModel::with(['category' => function($query) {
|
||||||
|
$query->field(['id', 'name' => 'category_name']);
|
||||||
|
}])
|
||||||
|
->withoutField([
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->bypk(request()->param('id'))
|
||||||
|
->find()
|
||||||
|
->bindAttr('category', ['category_name'])
|
||||||
|
->hidden(['category']);
|
||||||
|
if (empty($video)) {
|
||||||
|
return error('视频不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $video);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加视频信息
|
||||||
|
*/
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'name',
|
||||||
|
'category_id',
|
||||||
|
'sort',
|
||||||
|
'recommend',
|
||||||
|
'desc',
|
||||||
|
'image',
|
||||||
|
'video',
|
||||||
|
'link',
|
||||||
|
'seo_title',
|
||||||
|
'seo_keywords',
|
||||||
|
'seo_desc'
|
||||||
|
]);
|
||||||
|
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
|
$validate = new VideoValidate;
|
||||||
|
if (!$validate->scene('create')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$video = VideoModel::create($data);
|
||||||
|
if ($video->isEmpty()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新视频信息
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'name',
|
||||||
|
'category_id',
|
||||||
|
'sort',
|
||||||
|
'recommend',
|
||||||
|
'desc',
|
||||||
|
'image',
|
||||||
|
'video',
|
||||||
|
'link',
|
||||||
|
'seo_title',
|
||||||
|
'seo_keywords',
|
||||||
|
'seo_desc'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new VideoValidate;
|
||||||
|
if (!$validate->scene('update')->check(array_merge($put, ['id' => $id]))) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$video = VideoModel::bypk($id)->find();
|
||||||
|
if (empty($video)) {
|
||||||
|
return error('请确认操作对象是不是存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$video->save($put)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置排序值
|
||||||
|
*/
|
||||||
|
public function sort()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$sort = request()->post('sort');
|
||||||
|
|
||||||
|
$validate = new VideoValidate;
|
||||||
|
if (!$validate->scene('sort')->check(['id' => $id, 'sort' => $sort])) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$video = VideoModel::bypk($id)->find();
|
||||||
|
if (empty($video)) {
|
||||||
|
return error('请确认操作对象是不是存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
$video->sort = $sort;
|
||||||
|
if (!$video->save()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出接口
|
||||||
|
*/
|
||||||
|
public function export()
|
||||||
|
{
|
||||||
|
$schema = [
|
||||||
|
'category_name' => '分类',
|
||||||
|
'name' => '视频名称',
|
||||||
|
'desc' => '描述',
|
||||||
|
'image' => '封面图片',
|
||||||
|
'video' => '视频URL',
|
||||||
|
'link' => '外链',
|
||||||
|
'sort' => '排序',
|
||||||
|
'recommend' => '是否推荐',
|
||||||
|
'seo_title' => 'seo标题',
|
||||||
|
'seo_keywords' => 'seo关键词',
|
||||||
|
'seo_desc' => 'seo描述',
|
||||||
|
'created_at' => '创建时间'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 获取导出数据
|
||||||
|
$data = $this->getExportVideoData();
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
return xlsx_writer($data, $schema, '视频列表' . date('YmdHis'));
|
||||||
|
}
|
||||||
|
private function getExportVideoData()
|
||||||
|
{
|
||||||
|
$params = request()->param([
|
||||||
|
'name',
|
||||||
|
'category_id',
|
||||||
|
'created_at'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$domain = request()->domain();
|
||||||
|
return VideoModel::withoutField([
|
||||||
|
'language_id',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
])
|
||||||
|
->with(['category' => function ($query) {
|
||||||
|
$query->field(['id', 'name']);
|
||||||
|
}])
|
||||||
|
->withSearch(['name', 'created_at'], [
|
||||||
|
'name' => $params['name']??null,
|
||||||
|
'created_at' => !empty($params['created_at']) ? explode(',', $params['created_at']) : null,
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->categoryId($params['category_id']??null)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select()
|
||||||
|
->bindAttr('category', ['category_name' => 'name'])
|
||||||
|
->hidden(['category_id', 'category'])
|
||||||
|
->each(function ($item) use($domain) {
|
||||||
|
$item->image = !empty($item->image) ? url_join($domain, $item->image) : '';
|
||||||
|
$item->video = !empty($item->video) ? url_join($domain, $item->video) : '';
|
||||||
|
$item->recommend = $item->recommend == 1 ? '是' : '否';
|
||||||
|
$item->status = $item->status == 1 ? '启用' : '禁用';
|
||||||
|
return $item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频信息删除
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$video = VideoModel::bypk($id)->find();
|
||||||
|
if (empty($video)) {
|
||||||
|
return error('请确认操作对象是不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$video->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
191
app/admin/controller/v1/VideoCategory.php
Normal file
191
app/admin/controller/v1/VideoCategory.php
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\VideoCategoryModel;
|
||||||
|
use app\admin\validate\v1\VideoCategoryValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频分类控制器
|
||||||
|
*/
|
||||||
|
class VideoCategory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 视频分类列表数据
|
||||||
|
*/
|
||||||
|
public function list()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'name' => '',
|
||||||
|
'is_show'
|
||||||
|
]);
|
||||||
|
$categorys = VideoCategoryModel::field([
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
])
|
||||||
|
->withSearch(['name'], [
|
||||||
|
'name' => $param['name']??null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->where(function($query) use($param) {
|
||||||
|
if (isset($param['is_show'])) {
|
||||||
|
$query->where('is_show', '=', $param['is_show']);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return success('获取成功', $categorys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频分类分页数据
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$param = request()->param([
|
||||||
|
'name' => '',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$categorys = VideoCategoryModel::withoutField([
|
||||||
|
'language_id',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'
|
||||||
|
])
|
||||||
|
->withSearch(['name'], [
|
||||||
|
'name' => $param['name']??null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $param['size'],
|
||||||
|
'page' => $param['page'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return success('获取成功', $categorys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频分类详情
|
||||||
|
*/
|
||||||
|
public function read()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$category = VideoCategoryModel::withoutField([
|
||||||
|
'language_id',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'
|
||||||
|
])
|
||||||
|
->bypk($id)
|
||||||
|
->find();
|
||||||
|
if (empty($category)) {
|
||||||
|
return error('分类不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success('获取成功', $category);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频分类添加
|
||||||
|
*/
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
$post = request()->post([
|
||||||
|
'name',
|
||||||
|
'sort',
|
||||||
|
'is_show'
|
||||||
|
]);
|
||||||
|
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||||
|
|
||||||
|
$validate = new VideoCategoryValidate;
|
||||||
|
if (!$validate->scene('create')->check($data)) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$category = new VideoCategoryModel;
|
||||||
|
if (!$category->save($data)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频分类更新
|
||||||
|
*/
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$put = request()->put([
|
||||||
|
'name',
|
||||||
|
'sort',
|
||||||
|
'is_show'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validate = new VideoCategoryValidate;
|
||||||
|
if (!$validate->scene('update')->check(array_merge($put, ['id' => $id]))) {
|
||||||
|
return error($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$category = VideoCategoryModel::bypk($id)->find();
|
||||||
|
if (empty($category)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$category->save($put)) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置视频分类排序值
|
||||||
|
*/
|
||||||
|
public function sort()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
$sort = request()->post('sort');
|
||||||
|
|
||||||
|
$validate = new VideoCategoryValidate;
|
||||||
|
if (!$validate->scene('sort')->check(['id' => $id,'sort' => $sort])) {
|
||||||
|
return error($validate::getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$category = VideoCategoryModel::bypk($id)->find();
|
||||||
|
if (!$category) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
$category->sort = $sort;
|
||||||
|
if (!$category->save()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频分类删除
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$category = VideoCategoryModel::bypk($id)->find();
|
||||||
|
if (!$category) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查该分类下是否存在视频
|
||||||
|
if ($category->video()->count()) {
|
||||||
|
return error('该分类下存在视频,请先删除视频');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$category->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
91
app/admin/controller/v1/VideoTrash.php
Normal file
91
app/admin/controller/v1/VideoTrash.php
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\VideoModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频回收站控制器
|
||||||
|
*/
|
||||||
|
class VideoTrash
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 分页数据
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$params = request()->param([
|
||||||
|
'name',
|
||||||
|
'category_id',
|
||||||
|
'page/d' => 1,
|
||||||
|
'size/d' => 10,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$videos = VideoModel::field([
|
||||||
|
'id',
|
||||||
|
'category_id',
|
||||||
|
'name',
|
||||||
|
'image',
|
||||||
|
'video',
|
||||||
|
'sort',
|
||||||
|
'recommend',
|
||||||
|
'created_at',
|
||||||
|
])
|
||||||
|
->with(['category' => function($query) {
|
||||||
|
$query->field(['id', 'name' => 'category_name']);
|
||||||
|
}])
|
||||||
|
->withSearch(['name'], [
|
||||||
|
'name' => $params['name']??null
|
||||||
|
])
|
||||||
|
->language(request()->lang_id)
|
||||||
|
->categoryId($params['category_id']??null)
|
||||||
|
->onlyTrashed()
|
||||||
|
->order(['sort' => 'asc', 'id' => 'desc'])
|
||||||
|
->paginate([
|
||||||
|
'list_rows' => $params['size'],
|
||||||
|
'page' => $params['page'],
|
||||||
|
])
|
||||||
|
->bindAttr('category', ['category_name'])
|
||||||
|
->hidden(['category_id', 'category'])
|
||||||
|
?->each(fn($item) => $item->image = thumb($item->image));
|
||||||
|
|
||||||
|
return success('获取成功', $videos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复操作
|
||||||
|
*/
|
||||||
|
public function restore()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$video = VideoModel::onlyTrashed()->bypk($id)->find();
|
||||||
|
if (empty($video)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$video->restore()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除操作
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$id = request()->param('id');
|
||||||
|
|
||||||
|
$video = VideoModel::onlyTrashed()->bypk($id)->find();
|
||||||
|
if (empty($video)) {
|
||||||
|
return error('请确认操作对象是否存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$video->force()->delete()) {
|
||||||
|
return error('操作失败');
|
||||||
|
}
|
||||||
|
return success('操作成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
10
app/admin/exception/InvalidOperateException.php
Normal file
10
app/admin/exception/InvalidOperateException.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
namespace app\admin\exception;
|
||||||
|
|
||||||
|
class InvalidOperateException extends \Exception
|
||||||
|
{
|
||||||
|
public function __construct($message = '', $code = 0, ?\Throwable $previous = null)
|
||||||
|
{
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,4 +4,5 @@ return [
|
|||||||
// 登录验证
|
// 登录验证
|
||||||
app\admin\middleware\v1\Auth::class,
|
app\admin\middleware\v1\Auth::class,
|
||||||
app\admin\middleware\v1\RequestId::class,
|
app\admin\middleware\v1\RequestId::class,
|
||||||
|
app\admin\middleware\v1\OperateLog::class,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class Auth extends \thans\jwt\middleware\BaseMiddleware
|
|||||||
// 获取语言信息
|
// 获取语言信息
|
||||||
private function setLanguage($request)
|
private function setLanguage($request)
|
||||||
{
|
{
|
||||||
$code = $request->cookie('lang', 'zh_cn');
|
$code = $request->cookie('lang', 'zh-cn');
|
||||||
$lang = LanguageModel::cache('lang:code.' . $code, 3600, 'lang')
|
$lang = LanguageModel::cache('lang:code.' . $code, 3600, 'lang')
|
||||||
->field(['id', 'name', 'code', 'icon', 'url'])
|
->field(['id', 'name', 'code', 'icon', 'url'])
|
||||||
->withJoin(['country' => ['id', 'name', 'code', 'icon']])
|
->withJoin(['country' => ['id', 'name', 'code', 'icon']])
|
||||||
|
|||||||
72
app/admin/middleware/v1/OperateLog.php
Normal file
72
app/admin/middleware/v1/OperateLog.php
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\middleware\v1;
|
||||||
|
|
||||||
|
use app\admin\model\v1\SysOperateLog;
|
||||||
|
use app\admin\model\v1\SysRestfulApiModel;
|
||||||
|
use think\facade\Cache;
|
||||||
|
|
||||||
|
class OperateLog
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 处理请求
|
||||||
|
*
|
||||||
|
* @param \think\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function handle($request, \Closure $next)
|
||||||
|
{
|
||||||
|
$response = $next($request);
|
||||||
|
|
||||||
|
$restful_api_name_map = Cache::get('sys_restful_api:map:name');
|
||||||
|
if (empty($restful_api_name_map)) {
|
||||||
|
$restful_api_name_map = [];
|
||||||
|
$restful_api = SysRestfulApiModel::cache('sys_restful_api')->select();
|
||||||
|
foreach ($restful_api as $item) {
|
||||||
|
$restful_api_name_map[$item['method'] . '-' . $item['layer'] . '.' . $item['controller'] . '/' . $item['action']] = $item['name'];
|
||||||
|
}
|
||||||
|
Cache::set('sys_restful_api:map:name', $restful_api_name_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 忽略日志记录的Api
|
||||||
|
$ignore_apis = env('ADMIN_API.IGNORE_LOGGING_LIST');
|
||||||
|
$current_api = sprintf("%s/%s/%s", $request->layer(), $request->controller(base:true), $request->action());
|
||||||
|
if (in_array($current_api, $ignore_apis)) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$log = [
|
||||||
|
'user_id' => $request->uid,
|
||||||
|
'title' => $restful_api_name_map[$request->method() . '-' . $request->controller() . '/' . $request->action()] ?? '',
|
||||||
|
'version' => $request->layer(),
|
||||||
|
'method' => $request->method(),
|
||||||
|
'controller' => $request->controller(base: true),
|
||||||
|
'action' => $request->action(),
|
||||||
|
'url' => $request->url(),
|
||||||
|
'ip' => $request->ip(),
|
||||||
|
'params' => json_encode($request->param()),
|
||||||
|
'status' => $response->getCode()
|
||||||
|
];
|
||||||
|
|
||||||
|
if (empty($request->exception_info)) {
|
||||||
|
// 记录正常返回信息
|
||||||
|
$contentDisposition = $response->getHeader('Content-Disposition');
|
||||||
|
if (!empty($contentDisposition) && \think\helper\Str::startsWith($contentDisposition, 'attachment')) {
|
||||||
|
$log['message'] = $contentDisposition;
|
||||||
|
} else {
|
||||||
|
$log['message'] = $response->getData();
|
||||||
|
if (is_array($log['message'])) {
|
||||||
|
$log['message'] = json_encode($log['message'], JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 记录异常返回信息
|
||||||
|
$log['message'] = (string)$request->exception_info;
|
||||||
|
}
|
||||||
|
SysOperateLog::create($log);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/admin/model/v1/AgentBusinessTypeModel.php
Normal file
19
app/admin/model/v1/AgentBusinessTypeModel.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\AgentBusinessTypeBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代理商业务类型模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class AgentBusinessTypeModel extends AgentBusinessTypeBaseModel
|
||||||
|
{
|
||||||
|
// 按语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/admin/model/v1/AgentEnterpriseSizeTypeModel.php
Normal file
19
app/admin/model/v1/AgentEnterpriseSizeTypeModel.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\AgentEnterpriseSizeTypeBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代理商企业规模类型模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class AgentEnterpriseSizeTypeModel extends AgentEnterpriseSizeTypeBaseModel
|
||||||
|
{
|
||||||
|
// 按语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
58
app/admin/model/v1/AgentModel.php
Normal file
58
app/admin/model/v1/AgentModel.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\AgentBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代理商数据模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class AgentModel extends AgentBaseModel
|
||||||
|
{
|
||||||
|
// 关联业务类型
|
||||||
|
public function businessType()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(AgentBusinessTypeModel::class, 'business_type', 'value');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关联企业规模类型
|
||||||
|
public function enterpriseSizeType()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(AgentEnterpriseSizeTypeModel::class, 'enterprise_size', 'value');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按放言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按企业规模查询
|
||||||
|
public function scopeEnterpriseSize($query, $value)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
$query->where('enterprise_size', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据公司名称搜索
|
||||||
|
public function searchCorpNameAttr($query, $value)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
$query->where('corp_name', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据提交时间搜索
|
||||||
|
public function searchCreatedAtAttr($query, $value)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (count($value) > 1) {
|
||||||
|
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('created_at', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,12 @@ class ArticleCategoryModel extends ArticleCategoryBaseModel
|
|||||||
$query->where('language_id', '=', $lang_id);
|
$query->where('language_id', '=', $lang_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据是否显示查询
|
||||||
|
public function scopeIsShow($query, bool $is_show)
|
||||||
|
{
|
||||||
|
$query->where('is_show', '=', (int)$is_show);
|
||||||
|
}
|
||||||
|
|
||||||
// 搜索分类名
|
// 搜索分类名
|
||||||
public function searchNameAttr($query, $value, $data)
|
public function searchNameAttr($query, $value, $data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use think\model\concern\SoftDelete;
|
|||||||
*/
|
*/
|
||||||
class ArticleLeaveMessageModel extends ArticleLeaveMessageBaseModel
|
class ArticleLeaveMessageModel extends ArticleLeaveMessageBaseModel
|
||||||
{
|
{
|
||||||
// 启用软件删除
|
// 启用软删除
|
||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
// 软删除标记数据字段
|
// 软删除标记数据字段
|
||||||
protected $deleteTime = 'deleted_at';
|
protected $deleteTime = 'deleted_at';
|
||||||
@@ -22,12 +22,6 @@ class ArticleLeaveMessageModel extends ArticleLeaveMessageBaseModel
|
|||||||
return $this->belongsTo(ArticleModel::class, 'article_id', 'id');
|
return $this->belongsTo(ArticleModel::class, 'article_id', 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据id查询
|
|
||||||
public function scopeId($query, $value)
|
|
||||||
{
|
|
||||||
$query->where('id', '=', $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 审核状态查询
|
// 审核状态查询
|
||||||
public function scopeIsAudited($query, $is_audited)
|
public function scopeIsAudited($query, $is_audited)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,11 +11,17 @@ use think\model\concern\SoftDelete;
|
|||||||
*/
|
*/
|
||||||
class ArticleModel extends ArticleBaseModel
|
class ArticleModel extends ArticleBaseModel
|
||||||
{
|
{
|
||||||
// 启用软件删除
|
// 启用软删除
|
||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
// 软删除标记数据字段
|
// 软删除标记数据字段
|
||||||
protected $deleteTime = 'deleted_at';
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 写入前,处理发布时间为空情况
|
||||||
|
public static function onBeforeWrite(ArticleModel $article)
|
||||||
|
{
|
||||||
|
$article->release_time = empty($article->release_time) ? null : $article->release_time;
|
||||||
|
}
|
||||||
|
|
||||||
// 关联分类
|
// 关联分类
|
||||||
public function category()
|
public function category()
|
||||||
{
|
{
|
||||||
@@ -25,14 +31,41 @@ class ArticleModel extends ArticleBaseModel
|
|||||||
// 搜索名称
|
// 搜索名称
|
||||||
public function searchTitleAttr($query, $value, $data)
|
public function searchTitleAttr($query, $value, $data)
|
||||||
{
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$query->where('title', 'like', '%' . $value . '%');
|
$query->where('title', 'like', '%' . $value . '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索发布时间
|
// 搜索发布时间
|
||||||
public function searchCreatedAtAttr($query, $value, $data)
|
public function searchReleaseTimeAttr($query, $value, $data)
|
||||||
{
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
if (count($value) == 2) {
|
if (count($value) == 2) {
|
||||||
|
if ($value[0] == $value[1]) {
|
||||||
|
$value[1] = date('Y-m-d 23:59:59', strtotime($value[1]));
|
||||||
|
}
|
||||||
|
$query->whereBetweenTime('release_time', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('release_time', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索新增时间
|
||||||
|
public function searchCreatedAtAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (count($value) == 2) {
|
||||||
|
if ($value[0] == $value[1]) {
|
||||||
|
$value[1] = date('Y-m-d 23:59:59', strtotime($value[1]));
|
||||||
|
}
|
||||||
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
||||||
} else {
|
} else {
|
||||||
$query->whereTime('created_at', '>=', $value[0]);
|
$query->whereTime('created_at', '>=', $value[0]);
|
||||||
@@ -40,12 +73,6 @@ class ArticleModel extends ArticleBaseModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主键查询
|
|
||||||
public function scopeId($query, $value)
|
|
||||||
{
|
|
||||||
$query->where('id', '=', $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 语言查询
|
// 语言查询
|
||||||
public function scopeLanguage($query, $value)
|
public function scopeLanguage($query, $value)
|
||||||
{
|
{
|
||||||
@@ -58,6 +85,10 @@ class ArticleModel extends ArticleBaseModel
|
|||||||
// 分类查询
|
// 分类查询
|
||||||
public function scopeCategory($query, $value)
|
public function scopeCategory($query, $value)
|
||||||
{
|
{
|
||||||
|
if (is_array($value) || str_contains($value, ',')) {
|
||||||
|
$query->whereIn('category_id', $value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
$query->where('category_id', '=', $value);
|
$query->where('category_id', '=', $value);
|
||||||
}
|
}
|
||||||
public function scopeCategoryNullable($query, $value)
|
public function scopeCategoryNullable($query, $value)
|
||||||
@@ -65,6 +96,10 @@ class ArticleModel extends ArticleBaseModel
|
|||||||
if (is_null($value)) {
|
if (is_null($value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (is_array($value) || str_contains($value, ',')) {
|
||||||
|
$query->whereIn('category_id', $value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
$query->where('category_id', '=', $value);
|
$query->where('category_id', '=', $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
app/admin/model/v1/AttachmentCategoryModel.php
Normal file
37
app/admin/model/v1/AttachmentCategoryModel.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\AttachmentCategoryBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件(下载管理)分类模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class AttachmentCategoryModel extends AttachmentCategoryBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 关联附件
|
||||||
|
public function attachment()
|
||||||
|
{
|
||||||
|
return $this->hasMany(AttachmentModel::class, 'category_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询显示状态数据
|
||||||
|
public function scopeIsShow($query, bool $value = true)
|
||||||
|
{
|
||||||
|
$query->where('is_show', '=', (int)$value);
|
||||||
|
}
|
||||||
|
}
|
||||||
67
app/admin/model/v1/AttachmentModel.php
Normal file
67
app/admin/model/v1/AttachmentModel.php
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\AttachmentBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件(下载管理)模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class AttachmentModel extends AttachmentBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// JSON字段
|
||||||
|
protected $json = ['attach'];
|
||||||
|
// 设置JSON数据返回数组
|
||||||
|
protected $jsonAssoc = true;
|
||||||
|
|
||||||
|
// 关联附件分类模型
|
||||||
|
public function category()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(AttachmentCategoryModel::class, 'category_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 名称搜索
|
||||||
|
public function searchNameAttr($query, $value)
|
||||||
|
{
|
||||||
|
if (empty($value)) return;
|
||||||
|
$query->where('name', 'like', '%' . $value . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增时间搜索
|
||||||
|
public function searchCreatedAtAttr($query, $value)
|
||||||
|
{
|
||||||
|
if (empty($value)) return;
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (count($value) > 1) {
|
||||||
|
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('created_at', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分类查询
|
||||||
|
public function scopeCategoryId($query, $value)
|
||||||
|
{
|
||||||
|
if (empty($value)) return;
|
||||||
|
if (is_array($value) || str_contains($value, ',')) {
|
||||||
|
$query->whereIn('category_id', $value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('category_id', '=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
app/admin/model/v1/BulkPurchaseInquiryModel.php
Normal file
46
app/admin/model/v1/BulkPurchaseInquiryModel.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\BulkPurchaseInquiryBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量采购询盘模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class BulkPurchaseInquiryModel extends BulkPurchaseInquiryBaseModel
|
||||||
|
{
|
||||||
|
// 按语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公司名称搜索
|
||||||
|
public function searchCorpNameAttr($query, $value)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
$query->where('corp_name', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兴趣(感兴趣的产品分类)
|
||||||
|
public function searchInterestedAttr($query, $value)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
$query->where('interested', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加时间搜索
|
||||||
|
public function searchCreatedAtAttr($query, $value)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (count($value) > 1) {
|
||||||
|
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('created_at', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,5 +10,10 @@ use app\common\model\CountryBaseModel;
|
|||||||
*/
|
*/
|
||||||
class CountryModel extends CountryBaseModel
|
class CountryModel extends CountryBaseModel
|
||||||
{
|
{
|
||||||
|
// 根据名称搜索
|
||||||
|
public function searchNameAttr($query, $value)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
$query->where('name', 'like', '%' . $value . '%');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
48
app/admin/model/v1/FaqModel.php
Normal file
48
app/admin/model/v1/FaqModel.php
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\FaqBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class FaqModel extends FaqBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 根据语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据问题搜索
|
||||||
|
public function searchQuestionAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('question', 'like', "%$value%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据添加时间搜索
|
||||||
|
public function searchCreatedAtAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (count($value) > 1) {
|
||||||
|
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('created_at', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare (strict_types = 1);
|
|
||||||
|
|
||||||
namespace app\admin\model\v1;
|
|
||||||
|
|
||||||
use app\common\model\ImageBaseModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @mixin \think\Model
|
|
||||||
*/
|
|
||||||
class ImageModel extends ImageBaseModel
|
|
||||||
{
|
|
||||||
// 根据md5获取图片
|
|
||||||
public function scopeMd5($query, $md5)
|
|
||||||
{
|
|
||||||
$query->where('image_md5', '=', $md5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,10 +15,4 @@ class LanguageModel extends LanguageBaseModel
|
|||||||
{
|
{
|
||||||
return $this->belongsTo(CountryModel::class, 'country_id', 'id');
|
return $this->belongsTo(CountryModel::class, 'country_id', 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据id查询
|
|
||||||
public function scopeId($query, $value)
|
|
||||||
{
|
|
||||||
$query->where('id', '=', $value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
35
app/admin/model/v1/LeaveMessageModel.php
Normal file
35
app/admin/model/v1/LeaveMessageModel.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\LeaveMessageBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 留言记录(联系我们)模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class LeaveMessageModel extends LeaveMessageBaseModel
|
||||||
|
{
|
||||||
|
// 根据语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按添加时间搜索
|
||||||
|
public function searchCreatedAtAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (count($value) > 1) {
|
||||||
|
if ($value[0] == $value[1]) {
|
||||||
|
$value[1] = date("Y-m-d 23:59:59", strtotime($value[1]));
|
||||||
|
}
|
||||||
|
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('created_at', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,8 +16,6 @@ class ProductAttrModel extends ProductAttrBaseModel
|
|||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
// 软删除字段
|
// 软删除字段
|
||||||
protected $deleteTime = 'deleted_at';
|
protected $deleteTime = 'deleted_at';
|
||||||
// 修改自动写入时间格式
|
|
||||||
protected $autoWriteTimestamp = 'datetime';
|
|
||||||
|
|
||||||
// 关联属性特征
|
// 关联属性特征
|
||||||
public function props()
|
public function props()
|
||||||
|
|||||||
@@ -12,12 +12,10 @@ use think\model\concern\SoftDelete;
|
|||||||
*/
|
*/
|
||||||
class ProductCategoryModel extends ProductCategoryBaseModel
|
class ProductCategoryModel extends ProductCategoryBaseModel
|
||||||
{
|
{
|
||||||
// 启用软件删除
|
// 启用软删除
|
||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
// 软件字段
|
// 软件字段
|
||||||
protected $deleteTime = 'deleted_at';
|
protected $deleteTime = 'deleted_at';
|
||||||
// 修改自动写入时间格式
|
|
||||||
protected $autoWriteTimestamp = 'datetime';
|
|
||||||
|
|
||||||
// 根据pid查询
|
// 根据pid查询
|
||||||
public function scopePid($query, $pid)
|
public function scopePid($query, $pid)
|
||||||
@@ -31,6 +29,26 @@ class ProductCategoryModel extends ProductCategoryBaseModel
|
|||||||
$query->where('language_id', '=', $value);
|
$query->where('language_id', '=', $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 所属产品目录分类id查询
|
||||||
|
public function scopeTcoId($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('related_tco_category', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据是否显示查询
|
||||||
|
* @param $query
|
||||||
|
* @param \Closure:bool|bool $value
|
||||||
|
*/
|
||||||
|
public function scopeIsShow($query, \Closure|bool $value)
|
||||||
|
{
|
||||||
|
if (is_callable($value)) {
|
||||||
|
$query->where('is_show', '=', $value());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('is_show', '=', (int)$value);
|
||||||
|
}
|
||||||
|
|
||||||
// 搜索分类名称
|
// 搜索分类名称
|
||||||
public function searchNameNullableAttr($query, $value, $data)
|
public function searchNameNullableAttr($query, $value, $data)
|
||||||
{
|
{
|
||||||
|
|||||||
46
app/admin/model/v1/ProductInquiryModel.php
Normal file
46
app/admin/model/v1/ProductInquiryModel.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\ProductInquiryBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品询盘记录模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class ProductInquiryModel extends ProductInquiryBaseModel
|
||||||
|
{
|
||||||
|
// 根据语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按公司名称搜索
|
||||||
|
public function searchCorpNameAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
$query->where('corp_name', 'like', '%'.$value.'%');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按国家名称搜索
|
||||||
|
public function searchCountryNameAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
$query->where('country_name', 'like', '%'.$value.'%');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按提交时间搜索
|
||||||
|
public function searchCreatedAtAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (count($value) > 1) {
|
||||||
|
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('created_at', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,12 +12,10 @@ use think\model\concern\SoftDelete;
|
|||||||
*/
|
*/
|
||||||
class ProductModel extends ProductBaseModel
|
class ProductModel extends ProductBaseModel
|
||||||
{
|
{
|
||||||
// 启用软件删除
|
// 启用软删除
|
||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
// 软件字段
|
// 软件字段
|
||||||
protected $deleteTime = 'deleted_at';
|
protected $deleteTime = 'deleted_at';
|
||||||
// 修改自动写入时间格式
|
|
||||||
protected $autoWriteTimestamp = 'datetime';
|
|
||||||
|
|
||||||
// 分类关联查询
|
// 分类关联查询
|
||||||
public function category()
|
public function category()
|
||||||
@@ -67,8 +65,32 @@ class ProductModel extends ProductBaseModel
|
|||||||
if (is_null($value)) {
|
if (is_null($value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (is_array($value) || str_contains($value, ',')) {
|
||||||
|
$query->whereIn('category_id', $value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
$query->where('category_id', '=', $value);
|
$query->where('category_id', '=', $value);
|
||||||
}
|
}
|
||||||
|
public function scopeCategory($query, $value)
|
||||||
|
{
|
||||||
|
if (is_array($value) || str_contains($value, ',')) {
|
||||||
|
$query->whereIn('category_id', $value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('category_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 规格型号查询
|
||||||
|
public function scopeSpu($query, $spu)
|
||||||
|
{
|
||||||
|
$query->where('spu', '=', $spu);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启用状态查询
|
||||||
|
public function scopeEnabled($query)
|
||||||
|
{
|
||||||
|
$query->where('status', '=', 1);
|
||||||
|
}
|
||||||
|
|
||||||
// 上架状态查询
|
// 上架状态查询
|
||||||
public function scopeIsShowNullable($query, bool|null $value)
|
public function scopeIsShowNullable($query, bool|null $value)
|
||||||
@@ -78,4 +100,8 @@ class ProductModel extends ProductBaseModel
|
|||||||
}
|
}
|
||||||
$query->where('is_show', '=', (int)$value);
|
$query->where('is_show', '=', (int)$value);
|
||||||
}
|
}
|
||||||
|
public function scopeIsShow($query, bool $value)
|
||||||
|
{
|
||||||
|
$query->where('is_show', '=', (int)$value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
app/admin/model/v1/ProductPurchaseLinkModel.php
Normal file
31
app/admin/model/v1/ProductPurchaseLinkModel.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\ProductPurchaseLinkBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品 - 购买链接模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class ProductPurchaseLinkModel extends ProductPurchaseLinkBaseModel
|
||||||
|
{
|
||||||
|
// 关联产品
|
||||||
|
public function product()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ProductModel::class, 'product_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关联平台
|
||||||
|
public function platform()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ProductPurchaseLinkPlatformModel::class, 'platform_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/admin/model/v1/ProductPurchaseLinkPlatformModel.php
Normal file
19
app/admin/model/v1/ProductPurchaseLinkPlatformModel.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\ProductPurchasePlatformBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品 - 采购链接平台模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class ProductPurchaseLinkPlatformModel extends ProductPurchasePlatformBaseModel
|
||||||
|
{
|
||||||
|
// 根据语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
app/admin/model/v1/ProductSkuAttrModel.php
Normal file
15
app/admin/model/v1/ProductSkuAttrModel.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\ProductSkuAttrBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品 - sku属性模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class ProductSkuAttrModel extends ProductSkuAttrBaseModel
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
30
app/admin/model/v1/ProductSkuModel.php
Normal file
30
app/admin/model/v1/ProductSkuModel.php
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\ProductSkuBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品 - sku模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class ProductSkuModel extends ProductSkuBaseModel
|
||||||
|
{
|
||||||
|
// 设置json类型字段
|
||||||
|
protected $json = ['photo_album'];
|
||||||
|
// 设置JSON数据返回数组
|
||||||
|
protected $jsonAssoc = true;
|
||||||
|
|
||||||
|
// 关联产品sku属性
|
||||||
|
public function attrs()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ProductSkuAttrModel::class, 'sku_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所属产品查询
|
||||||
|
public function scopeProductId($query, $id)
|
||||||
|
{
|
||||||
|
$query->where('product_id', '=', $id);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
app/admin/model/v1/ProductTcoCategoryModel.php
Normal file
52
app/admin/model/v1/ProductTcoCategoryModel.php
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\ProductTcoCategoryBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品 - 产品目录分类同步记录模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class ProductTcoCategoryModel extends ProductTcoCategoryBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 根据语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据 tco_id 查询
|
||||||
|
public function scopeTcoId($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('tco_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据ERP Code查询
|
||||||
|
public function scopeErpCode($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('erp_code', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按分类名称搜索
|
||||||
|
public function searchNameAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('name', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只查询启用的
|
||||||
|
public function scopeEnabled($query)
|
||||||
|
{
|
||||||
|
$query->where('disabled', '=', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/admin/model/v1/SysAttachmentUploadRecordModel.php
Normal file
19
app/admin/model/v1/SysAttachmentUploadRecordModel.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysAttachmentUploadRecordBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件上传模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysAttachmentUploadRecordModel extends SysAttachmentUploadRecordBaseModel
|
||||||
|
{
|
||||||
|
// 根据md5获取
|
||||||
|
public function scopeMd5($query, $md5)
|
||||||
|
{
|
||||||
|
$query->where('file_md5', '=', $md5);
|
||||||
|
}
|
||||||
|
}
|
||||||
80
app/admin/model/v1/SysBannerItemModel.php
Normal file
80
app/admin/model/v1/SysBannerItemModel.php
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysBannerItemBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 横幅数据项模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysBannerItemModel extends SysBannerItemBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 要隐藏的字段或关联模型数据字段
|
||||||
|
protected $hidden = ['prodMapping'];
|
||||||
|
|
||||||
|
// 关联分类
|
||||||
|
public function banner()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(SysBannerModel::class, 'banner_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关联相关产品分类中间表模型
|
||||||
|
public function prodMapping()
|
||||||
|
{
|
||||||
|
return $this->hasOne(SysBannerProdCateMappingModel::class, 'banner_item_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从产品分类关联模型中获取id字段
|
||||||
|
public function getRelProdCateIdAttr()
|
||||||
|
{
|
||||||
|
return $this->prodMapping?->category?->id;
|
||||||
|
}
|
||||||
|
// 从产品分类关联模型中获取name字段
|
||||||
|
public function getRelProdCateNameAttr()
|
||||||
|
{
|
||||||
|
return $this->prodMapping?->category?->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按横幅标题搜索
|
||||||
|
public function searchTitleAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('title', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按添加时间搜索
|
||||||
|
public function searchCreatedAtAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (count($value) > 1) {
|
||||||
|
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('created_at', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据横幅id查询
|
||||||
|
public function scopeBannerId($query, $value)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
if (is_array($value) || str_contains($value, ',')) {
|
||||||
|
$query->whereIn('banner_id', $value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('banner_id', '=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
app/admin/model/v1/SysBannerModel.php
Normal file
47
app/admin/model/v1/SysBannerModel.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysBannerBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 横幅模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysBannerModel extends SysBannerBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 按语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
$query->where('language_id', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询启用状态
|
||||||
|
public function scopeEnabled($query)
|
||||||
|
{
|
||||||
|
$query->where('status', '=', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询禁用状态
|
||||||
|
public function scopeDisabled($query)
|
||||||
|
{
|
||||||
|
$query->where('status', '=', -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按名称搜索
|
||||||
|
public function searchNameAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('name', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/admin/model/v1/SysBannerProdCateMappingModel.php
Normal file
19
app/admin/model/v1/SysBannerProdCateMappingModel.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysBannerProdCateMappingBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* banner与产品分类关联表模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysBannerProdCateMappingModel extends SysBannerProdCateMappingBaseModel
|
||||||
|
{
|
||||||
|
// 关联产品分类
|
||||||
|
public function category()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ProductCategoryModel::class, 'product_category_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
31
app/admin/model/v1/SysConfigGroupModel.php
Normal file
31
app/admin/model/v1/SysConfigGroupModel.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysConfigGroupBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统配置分组模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysConfigGroupModel extends SysConfigGroupBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 按语言搜索
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取启用的配置分组
|
||||||
|
public function scopeEnabled($query)
|
||||||
|
{
|
||||||
|
$query->where('status', '=', 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
60
app/admin/model/v1/SysConfigModel.php
Normal file
60
app/admin/model/v1/SysConfigModel.php
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysConfigBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统配置模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysConfigModel extends SysConfigBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 关联分组
|
||||||
|
public function group()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('SysConfigGroupModel', 'group_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关联类型
|
||||||
|
public function type()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('SysConfigTypeModel', 'type', 'value');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按title搜索
|
||||||
|
public function searchTitleAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('title', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按group_id查询
|
||||||
|
public function scopeGroupId($query, $value)
|
||||||
|
{
|
||||||
|
if (is_array($value)) {
|
||||||
|
$query->where('group_id', 'in', $value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('group_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按name查询
|
||||||
|
public function scopeByName($query, $value)
|
||||||
|
{
|
||||||
|
if (is_array($value)) {
|
||||||
|
$query->where('name', 'in', $value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('name', '=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
app/admin/model/v1/SysConfigTypeModel.php
Normal file
15
app/admin/model/v1/SysConfigTypeModel.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysConfigTypeBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置类型模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysConfigTypeModel extends SysConfigTypeBaseModel
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
19
app/admin/model/v1/SysImageUploadRecordModel.php
Normal file
19
app/admin/model/v1/SysImageUploadRecordModel.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysImageUploadRecordBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片上传模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysImageUploadRecordModel extends SysImageUploadRecordBaseModel
|
||||||
|
{
|
||||||
|
// 根据md5获取图片
|
||||||
|
public function scopeMd5($query, $md5)
|
||||||
|
{
|
||||||
|
$query->where('file_md5', '=', $md5);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/admin/model/v1/SysMenuAbilityPermissionModel.php
Normal file
19
app/admin/model/v1/SysMenuAbilityPermissionModel.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysMenuAbilityPermissionBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单能力权限模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysMenuAbilityPermissionModel extends SysMenuAbilityPermissionBaseModel
|
||||||
|
{
|
||||||
|
// 按menu_id查询
|
||||||
|
public function scopeMenuId($query, $value)
|
||||||
|
{
|
||||||
|
return $query->where('menu_id', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
51
app/admin/model/v1/SysMenuModel.php
Normal file
51
app/admin/model/v1/SysMenuModel.php
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysMenuBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysMenuModel extends SysMenuBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 关联菜单能力权限
|
||||||
|
public function menuAbilityPermission()
|
||||||
|
{
|
||||||
|
return $this->hasMany(SysMenuAbilityPermissionModel::class, 'menu_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单标题查询
|
||||||
|
public function searchTitleAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query->where('title', 'like', "%$value%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态查询
|
||||||
|
public function scopeStatus($query, $value)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return $query->where('status', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取启用的菜单
|
||||||
|
public function scopeEnabled($query)
|
||||||
|
{
|
||||||
|
$query->where('status', '=', 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
app/admin/model/v1/SysNavigationItemModel.php
Normal file
46
app/admin/model/v1/SysNavigationItemModel.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysNavigationItemBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航数据模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysNavigationItemModel extends SysNavigationItemBaseModel
|
||||||
|
{
|
||||||
|
// 关联导航
|
||||||
|
public function navigation()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(SysNavigationModel::class, 'nav_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 名称搜索
|
||||||
|
public function searchNameAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (empty($value)) return;
|
||||||
|
$query->where('name', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增时间搜索
|
||||||
|
public function searchCreatedAtAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (empty($value)) return;
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (count($value) > 1) {
|
||||||
|
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('created_at', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导航查询
|
||||||
|
public function scopeNavId($query, $value)
|
||||||
|
{
|
||||||
|
if (empty($value)) return;
|
||||||
|
$query->where('nav_id', '=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
app/admin/model/v1/SysNavigationLinkTypeModel.php
Normal file
15
app/admin/model/v1/SysNavigationLinkTypeModel.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysNavigationLinkTypeBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航链接类型模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysNavigationLinkTypeModel extends SysNavigationLinkTypeBaseModel
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
35
app/admin/model/v1/SysNavigationModel.php
Normal file
35
app/admin/model/v1/SysNavigationModel.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysNavigationBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysNavigationModel extends SysNavigationBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 按语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
if (is_null($value)) return;
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 名称搜索
|
||||||
|
public function searchNameAttr($query, $value)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('name', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
}
|
||||||
66
app/admin/model/v1/SysOperateLog.php
Normal file
66
app/admin/model/v1/SysOperateLog.php
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysOperateLog extends Model
|
||||||
|
{
|
||||||
|
// 表名
|
||||||
|
protected $name = 'sys_operate_log';
|
||||||
|
|
||||||
|
// 主键
|
||||||
|
protected $pk = 'id';
|
||||||
|
|
||||||
|
// 字段信息
|
||||||
|
protected $schema = [
|
||||||
|
'id' => 'int',
|
||||||
|
'user_id' => 'int',
|
||||||
|
'title' => 'string',
|
||||||
|
'version' => 'string',
|
||||||
|
'method' => 'string',
|
||||||
|
'controller' => 'string',
|
||||||
|
'action' => 'string',
|
||||||
|
'url' => 'string',
|
||||||
|
'ip' => 'string',
|
||||||
|
'params' => 'string',
|
||||||
|
'status' => 'int',
|
||||||
|
'message' => 'string',
|
||||||
|
'created_at' => 'datetime'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 关联操作人
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(SysUserModel::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按标题搜索
|
||||||
|
public function searchTitleAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('title', 'like', "%$value%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按操作时间搜索
|
||||||
|
public function searchCreatedAtAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (empty($value)) return;
|
||||||
|
if (is_string($value)) {
|
||||||
|
$value = explode(',', $value);
|
||||||
|
}
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (count($value) == 2) {
|
||||||
|
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('created_at', '>=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
app/admin/model/v1/SysRestfulApiModel.php
Normal file
15
app/admin/model/v1/SysRestfulApiModel.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysRestfulApiBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统接口表模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysRestfulApiModel extends SysRestfulApiBaseModel
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
24
app/admin/model/v1/SysRoleAuthorityModel.php
Normal file
24
app/admin/model/v1/SysRoleAuthorityModel.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysRoleAuthorityBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysRoleAuthorityModel extends SysRoleAuthorityBaseModel
|
||||||
|
{
|
||||||
|
// role_id查询
|
||||||
|
public function scopeRoleId($query, $value)
|
||||||
|
{
|
||||||
|
return $query->where('role_id', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// menu_id查询
|
||||||
|
public function scopeMenuId($query, $value)
|
||||||
|
{
|
||||||
|
return $query->where('menu_id', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
34
app/admin/model/v1/SysRoleModel.php
Normal file
34
app/admin/model/v1/SysRoleModel.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysRoleBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysRoleModel extends SysRoleBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 关联权限
|
||||||
|
public function authorities()
|
||||||
|
{
|
||||||
|
return $this->hasMany(SysRoleAuthorityModel::class, 'role_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色名称搜索
|
||||||
|
public function searchNameAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('name', 'like', "%$value%");
|
||||||
|
}
|
||||||
|
}
|
||||||
14
app/admin/model/v1/SysUserLoginLogModel.php
Normal file
14
app/admin/model/v1/SysUserLoginLogModel.php
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysUserLoginLogBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysUserLoginLogModel extends SysUserLoginLogBaseModel
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
52
app/admin/model/v1/SysUserModel.php
Normal file
52
app/admin/model/v1/SysUserModel.php
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysUserBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysUserModel extends SysUserBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 隐藏字段
|
||||||
|
protected $hidden = ['password', 'salt'];
|
||||||
|
|
||||||
|
// 关联角色
|
||||||
|
public function role()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(SysRoleModel::class, 'role_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户名搜索
|
||||||
|
public function searchUsernameAttr($query, $value)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('username', 'like', "%{$value}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户名查询范围
|
||||||
|
public function scopeUsernameOrMobile($query, $username)
|
||||||
|
{
|
||||||
|
$query->where('username', '=', $username)->whereOr('mobile', '=', $username);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态查询
|
||||||
|
public function scopeStatus($query, $status)
|
||||||
|
{
|
||||||
|
if (empty($status)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('status', '=', $status);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/admin/model/v1/SysVideoUploadRecordModel.php
Normal file
19
app/admin/model/v1/SysVideoUploadRecordModel.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\SysVideoUploadRecordBaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频上传模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class SysVideoUploadRecordModel extends SysVideoUploadRecordBaseModel
|
||||||
|
{
|
||||||
|
// 根据md5查询
|
||||||
|
public function scopeMd5($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('file_md5', '=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare (strict_types = 1);
|
|
||||||
|
|
||||||
namespace app\admin\model\v1;
|
|
||||||
|
|
||||||
use app\common\model\UserLoginLogBaseModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @mixin \think\Model
|
|
||||||
*/
|
|
||||||
class UserLoginLogModel extends UserLoginLogBaseModel
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare (strict_types = 1);
|
|
||||||
|
|
||||||
namespace app\admin\model\v1;
|
|
||||||
|
|
||||||
use app\common\model\UserBaseModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @mixin \think\Model
|
|
||||||
*/
|
|
||||||
class UserModel extends UserBaseModel
|
|
||||||
{
|
|
||||||
// 隐藏字段
|
|
||||||
protected $hidden = ['password', 'salt'];
|
|
||||||
|
|
||||||
// 用户名查询范围
|
|
||||||
public function scopeUsernameOrMobile($query, $username)
|
|
||||||
{
|
|
||||||
return $query->where('username', '=', $username)->whereOr('mobile', '=', $username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
46
app/admin/model/v1/VideoCategoryModel.php
Normal file
46
app/admin/model/v1/VideoCategoryModel.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\VideoCategoryBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频分类模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class VideoCategoryModel extends VideoCategoryBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 关联视频模型
|
||||||
|
public function video()
|
||||||
|
{
|
||||||
|
return $this->hasMany(VideoModel::class, 'category_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分类名称搜索
|
||||||
|
public function searchNameAttr($query, $value)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('name', 'like', '%' . $value . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示状态查询
|
||||||
|
public function scopeIsShow($query, bool $value = true)
|
||||||
|
{
|
||||||
|
$query->where('is_show', '=', (int)$value);
|
||||||
|
}
|
||||||
|
}
|
||||||
71
app/admin/model/v1/VideoModel.php
Normal file
71
app/admin/model/v1/VideoModel.php
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\admin\model\v1;
|
||||||
|
|
||||||
|
use app\common\model\VideoBaseModel;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频信息模型
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class VideoModel extends VideoBaseModel
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
// 软删除字段
|
||||||
|
protected $deleteTime = 'deleted_at';
|
||||||
|
|
||||||
|
// 关联分类
|
||||||
|
public function category()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(VideoCategoryModel::class, 'category_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 名称搜索器
|
||||||
|
public function searchNameAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('name', 'like', '%' . $value . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索发布时间
|
||||||
|
public function searchCreatedAtAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (is_array($value)) {
|
||||||
|
if (count($value) == 2) {
|
||||||
|
if ($value[0] == $value[1]) {
|
||||||
|
$value[1] = date('Y-m-d 23:59:59', strtotime($value[1]));
|
||||||
|
}
|
||||||
|
$query->whereBetweenTime('created_at', $value[0], $value[1]);
|
||||||
|
} else {
|
||||||
|
$query->whereTime('created_at', '>=', $value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 语言查询
|
||||||
|
public function scopeLanguage($query, $value)
|
||||||
|
{
|
||||||
|
$query->where('language_id', '=', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分类查询
|
||||||
|
public function scopeCategoryId($query, $value)
|
||||||
|
{
|
||||||
|
if (empty($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (is_array($value) || str_contains($value, ',')) {
|
||||||
|
$query->whereIn('category_id', $value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$query->where('category_id', '=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,15 @@ use think\facade\Route;
|
|||||||
|
|
||||||
// v1版本路由定义
|
// v1版本路由定义
|
||||||
Route::group('v1', function () {
|
Route::group('v1', function () {
|
||||||
|
// 获取系统信息
|
||||||
|
Route::group('system', function() {
|
||||||
|
// 获取系统信息
|
||||||
|
Route::get('info', 'System/info');
|
||||||
|
|
||||||
|
// 组装系统内页面URL
|
||||||
|
Route::get('urls', 'System/urls');
|
||||||
|
});
|
||||||
|
|
||||||
// 用户模块
|
// 用户模块
|
||||||
Route::group('user', function () {
|
Route::group('user', function () {
|
||||||
// 获取验证码
|
// 获取验证码
|
||||||
@@ -23,9 +32,18 @@ Route::group('v1', function () {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// 登录接口
|
// 登录接口
|
||||||
Route::post('login', 'Login/index');
|
Route::post('login', 'UserCenter/login');
|
||||||
|
|
||||||
|
// 登出接口
|
||||||
|
Route::get('logout', 'UserCenter/logout');
|
||||||
|
|
||||||
|
// 获取用户菜单权限
|
||||||
|
Route::get('{id}/menu', 'User/menu');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 国家模块
|
||||||
|
Route::get('country/list', 'Country/list');
|
||||||
|
|
||||||
// 语言模块
|
// 语言模块
|
||||||
Route::group('language', function () {
|
Route::group('language', function () {
|
||||||
// 语言列表
|
// 语言列表
|
||||||
@@ -38,7 +56,70 @@ Route::group('v1', function () {
|
|||||||
// 图片管理
|
// 图片管理
|
||||||
Route::group('images', function () {
|
Route::group('images', function () {
|
||||||
// 图片上传
|
// 图片上传
|
||||||
Route::post('/:module/upload', 'Images/upload');
|
Route::post('/:module/upload', 'Upload/image');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 视频管理
|
||||||
|
Route::group('video', function () {
|
||||||
|
// 视频上传
|
||||||
|
Route::post('/:module/upload', 'Upload/video');
|
||||||
|
|
||||||
|
// 视频信息列表
|
||||||
|
Route::get('index', 'Video/index');
|
||||||
|
|
||||||
|
// 视频信息详情
|
||||||
|
Route::get('read/:id', 'Video/read');
|
||||||
|
|
||||||
|
// 视频信息添加
|
||||||
|
Route::post('save', 'Video/save');
|
||||||
|
|
||||||
|
// 视频信息更新
|
||||||
|
Route::put('update/:id', 'Video/update');
|
||||||
|
|
||||||
|
// 视频信息设置排序值
|
||||||
|
Route::post('sort/:id', 'Video/sort');
|
||||||
|
|
||||||
|
// 视频信息导出
|
||||||
|
Route::get('export', 'Video/export');
|
||||||
|
|
||||||
|
// 视频信息删除
|
||||||
|
Route::delete('delete/:id', 'Video/delete');
|
||||||
|
|
||||||
|
// 视频分类列表
|
||||||
|
Route::get('categorys', 'VideoCategory/list');
|
||||||
|
|
||||||
|
// 视频分类
|
||||||
|
Route::group('category', function () {
|
||||||
|
// 视频分类分页数据
|
||||||
|
Route::get('index', 'VideoCategory/index');
|
||||||
|
|
||||||
|
// 视频分类详情
|
||||||
|
Route::get('read/:id', 'VideoCategory/read');
|
||||||
|
|
||||||
|
// 视频分类添加
|
||||||
|
Route::post('save', 'VideoCategory/save');
|
||||||
|
|
||||||
|
// 视频分类更新
|
||||||
|
Route::put('update/:id', 'VideoCategory/update');
|
||||||
|
|
||||||
|
// 设置视频分类排序值
|
||||||
|
Route::post('sort/:id', 'VideoCategory/sort');
|
||||||
|
|
||||||
|
// 视频分类删除
|
||||||
|
Route::delete('delete/:id', 'VideoCategory/delete');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 视频回收站
|
||||||
|
Route::group('trash', function () {
|
||||||
|
// 视频回收站分页列表
|
||||||
|
Route::get('index', 'VideoTrash/index');
|
||||||
|
|
||||||
|
// 视频回收站还原
|
||||||
|
Route::get('restore/:id', 'VideoTrash/restore');
|
||||||
|
|
||||||
|
// 视频回收站删除
|
||||||
|
Route::delete('delete/:id', 'VideoTrash/delete');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 文章模块
|
// 文章模块
|
||||||
@@ -55,6 +136,9 @@ Route::group('v1', function () {
|
|||||||
// 文章更新
|
// 文章更新
|
||||||
Route::put('update/:id', 'Article/update');
|
Route::put('update/:id', 'Article/update');
|
||||||
|
|
||||||
|
// 设置排序值
|
||||||
|
Route::post('sort/:id', 'Article/sort');
|
||||||
|
|
||||||
// 文章删除
|
// 文章删除
|
||||||
Route::delete('delete/:id', 'Article/delete');
|
Route::delete('delete/:id', 'Article/delete');
|
||||||
|
|
||||||
@@ -78,6 +162,9 @@ Route::group('v1', function () {
|
|||||||
// 分类更新
|
// 分类更新
|
||||||
Route::put('update/:id', 'ArticleCategory/update');
|
Route::put('update/:id', 'ArticleCategory/update');
|
||||||
|
|
||||||
|
// 设置排序值
|
||||||
|
Route::post('sort/:id', 'ArticleCategory/sort');
|
||||||
|
|
||||||
// 分类删除
|
// 分类删除
|
||||||
Route::delete('delete/:id', 'ArticleCategory/delete');
|
Route::delete('delete/:id', 'ArticleCategory/delete');
|
||||||
});
|
});
|
||||||
@@ -110,6 +197,50 @@ Route::group('v1', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 横幅管理
|
||||||
|
Route::group('banner', function() {
|
||||||
|
// 横幅(分类)列表
|
||||||
|
Route::get('list', 'Banner/list');
|
||||||
|
|
||||||
|
// 横幅(分类)分页
|
||||||
|
Route::get('index', 'Banner/index');
|
||||||
|
|
||||||
|
// 横幅详情
|
||||||
|
Route::get('read/:id', 'Banner/read');
|
||||||
|
|
||||||
|
// 横幅新增
|
||||||
|
Route::post('save', 'Banner/save');
|
||||||
|
|
||||||
|
// 横幅更新
|
||||||
|
Route::put('update/:id', 'Banner/update');
|
||||||
|
|
||||||
|
// 横幅删除
|
||||||
|
Route::delete('delete/:id', 'Banner/delete');
|
||||||
|
|
||||||
|
Route::group('items', function() {
|
||||||
|
// 横幅数据项分页
|
||||||
|
Route::get('index', 'BannerItem/index');
|
||||||
|
|
||||||
|
// 横幅数据项详情
|
||||||
|
Route::get('read/:id', 'BannerItem/read');
|
||||||
|
|
||||||
|
// 横幅数据项新增
|
||||||
|
Route::post('save', 'BannerItem/save');
|
||||||
|
|
||||||
|
// 横幅数据项更新
|
||||||
|
Route::put('update/:id', 'BannerItem/update');
|
||||||
|
|
||||||
|
// 设置数据项排序值
|
||||||
|
Route::post('sort/:id', 'BannerItem/sort');
|
||||||
|
|
||||||
|
// 横幅数据项导出
|
||||||
|
Route::get('export', 'BannerItem/export');
|
||||||
|
|
||||||
|
// 横幅数据项删除
|
||||||
|
Route::delete('delete/:id', 'BannerItem/delete');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// 产品模块
|
// 产品模块
|
||||||
Route::group('product', function () {
|
Route::group('product', function () {
|
||||||
// 产品分页列表
|
// 产品分页列表
|
||||||
@@ -121,6 +252,9 @@ Route::group('v1', function () {
|
|||||||
// 产品更新
|
// 产品更新
|
||||||
Route::put('update/:id', 'Product/update');
|
Route::put('update/:id', 'Product/update');
|
||||||
|
|
||||||
|
// 设置排序值
|
||||||
|
Route::post('sort/:id', 'Product/sort');
|
||||||
|
|
||||||
// 上/下架操作
|
// 上/下架操作
|
||||||
Route::get('updown_shelves/:id', 'Product/updownShelves');
|
Route::get('updown_shelves/:id', 'Product/updownShelves');
|
||||||
|
|
||||||
@@ -131,7 +265,7 @@ Route::group('v1', function () {
|
|||||||
Route::get('export', 'Product/export');
|
Route::get('export', 'Product/export');
|
||||||
|
|
||||||
// 产品属性特征
|
// 产品属性特征
|
||||||
Route::get('attrs', 'ProductAttr/index')->append(['scene' => 'list']);
|
Route::get('attrs', 'ProductAttr/index')->append(['scene' => 'all']);
|
||||||
|
|
||||||
// 产品属性管理
|
// 产品属性管理
|
||||||
Route::group('attr', function () {
|
Route::group('attr', function () {
|
||||||
@@ -152,8 +286,12 @@ Route::group('v1', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 产品分类
|
// 产品分类
|
||||||
|
Route::get('categorys', 'ProductCategory/index');
|
||||||
Route::group('category', function () {
|
Route::group('category', function () {
|
||||||
// 分类列表
|
// tco分类树
|
||||||
|
Route::get('tco/tree', 'ProductTcoCategory/tree');
|
||||||
|
|
||||||
|
// 分类树
|
||||||
Route::get('index', 'ProductCategory/index');
|
Route::get('index', 'ProductCategory/index');
|
||||||
|
|
||||||
// 分类详情
|
// 分类详情
|
||||||
@@ -174,9 +312,316 @@ Route::group('v1', function () {
|
|||||||
// 分类删除
|
// 分类删除
|
||||||
Route::delete('delete/:id', 'ProductCategory/delete');
|
Route::delete('delete/:id', 'ProductCategory/delete');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 产品购买链接
|
||||||
|
Route::group('buypass', function () {
|
||||||
|
// 购买链接平台列表
|
||||||
|
Route::get('platforms', 'ProductPurchaseLink/platforms');
|
||||||
|
|
||||||
|
// 购买链接列表
|
||||||
|
Route::get('index', 'ProductPurchaseLink/index');
|
||||||
|
|
||||||
|
// 购买链接导入
|
||||||
|
Route::post('import', 'ProductPurchaseLink/import');
|
||||||
|
|
||||||
|
// 购买链接导出
|
||||||
|
Route::get('export', 'ProductPurchaseLink/export');
|
||||||
|
|
||||||
|
// 购买链接添加
|
||||||
|
Route::post('save', 'ProductPurchaseLink/save');
|
||||||
|
|
||||||
|
// 购买链接更新
|
||||||
|
Route::put('update/:id', 'ProductPurchaseLink/update');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 产品回收站
|
||||||
|
Route::group('trash', function () {
|
||||||
|
// 产品回收站列表
|
||||||
|
Route::get('index', 'ProductTrash/index');
|
||||||
|
|
||||||
|
// 产品回收站还原
|
||||||
|
Route::get('restore/:id', 'ProductTrash/restore');
|
||||||
|
|
||||||
|
// 产品回收站删除
|
||||||
|
Route::delete('delete/:id', 'ProductTrash/delete');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 附件(下载管理)
|
||||||
|
Route::group('attachment', function () {
|
||||||
|
// 附件(下载管理)上传
|
||||||
|
Route::post('/upload', 'Upload/attachment');
|
||||||
|
|
||||||
|
// 附件(下载管理)列表
|
||||||
|
Route::get('index', 'Attachment/index');
|
||||||
|
|
||||||
|
// 附件(下载管理)详情
|
||||||
|
Route::get('read/:id', 'Attachment/read');
|
||||||
|
|
||||||
|
// 附件(下载管理)新增
|
||||||
|
Route::post('save', 'Attachment/save');
|
||||||
|
|
||||||
|
// 附件(下载管理)更新
|
||||||
|
Route::put('update/:id', 'Attachment/update');
|
||||||
|
|
||||||
|
// 附件(下载管理)设置排序值
|
||||||
|
Route::post('sort/:id', 'Attachment/sort');
|
||||||
|
|
||||||
|
// 附件(下载管理)禁/启用
|
||||||
|
Route::get('enable/:id', 'Attachment/enable');
|
||||||
|
|
||||||
|
// 附件(下载管理)删除
|
||||||
|
Route::delete('delete/:id', 'Attachment/delete');
|
||||||
|
|
||||||
|
// 附件(下载管理)分类列表树
|
||||||
|
Route::get('tree', 'AttachmentCategory/tree');
|
||||||
|
|
||||||
|
// 附件(下载管理)分类
|
||||||
|
Route::group('category', function () {
|
||||||
|
// 附件(下载管理)分类树
|
||||||
|
Route::get('index', 'AttachmentCategory/index');
|
||||||
|
|
||||||
|
// 附件(下载管理)分类详情
|
||||||
|
Route::get('read/:id', 'AttachmentCategory/read');
|
||||||
|
|
||||||
|
// 附件(下载管理)分类新增
|
||||||
|
Route::post('save', 'AttachmentCategory/save');
|
||||||
|
|
||||||
|
// 附件(下载管理)分类更新
|
||||||
|
Route::put('update/:id','AttachmentCategory/update');
|
||||||
|
|
||||||
|
// 附件(下载管理)分类设置排序值
|
||||||
|
Route::post('sort/:id', 'AttachmentCategory/sort');
|
||||||
|
|
||||||
|
// 附件(下载管理)分类删除
|
||||||
|
Route::delete('delete/:id', 'AttachmentCategory/delete');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 附件(下载管理)回收站
|
||||||
|
Route::group('trash', function () {
|
||||||
|
// 附件(下载管理)回收站列表
|
||||||
|
Route::get('index', 'AttachmentTrash/index');
|
||||||
|
|
||||||
|
// 附件(下载管理)回收站还原
|
||||||
|
Route::get('restore/:id', 'AttachmentTrash/restore');
|
||||||
|
|
||||||
|
// 附件(下载管理)回收站删除
|
||||||
|
Route::delete('delete/:id', 'AttachmentTrash/delete');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 用户管理
|
||||||
|
Route::group('user', function() {
|
||||||
|
// 用户分页
|
||||||
|
Route::get('index', 'User/index');
|
||||||
|
|
||||||
|
// 用户详情
|
||||||
|
Route::get('read/:id', 'User/read');
|
||||||
|
|
||||||
|
// 用户新增
|
||||||
|
Route::post('save', 'User/save');
|
||||||
|
|
||||||
|
// 用户更新
|
||||||
|
Route::put('update/:id', 'User/update');
|
||||||
|
|
||||||
|
// 用户删除
|
||||||
|
Route::delete('delete/:id', 'User/delete');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 角色管理
|
||||||
|
Route::get('roles', 'Role/index')->append(['scene' => 'all']); // 角色列表
|
||||||
|
Route::group('role', function() {
|
||||||
|
// 角色分页
|
||||||
|
Route::get('index', 'Role/index');
|
||||||
|
|
||||||
|
// 角色详情
|
||||||
|
Route::get('read/:id', 'Role/read');
|
||||||
|
|
||||||
|
// 角色新增
|
||||||
|
Route::post('save', 'Role/save');
|
||||||
|
|
||||||
|
// 角色更新
|
||||||
|
Route::put('update/:id', 'Role/update');
|
||||||
|
|
||||||
|
// 角色删除
|
||||||
|
Route::delete('delete/:id', 'Role/delete');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 菜单管理
|
||||||
|
// 菜单列表
|
||||||
|
Route::get('menus', 'Menu/list');
|
||||||
|
Route::group('menu', function() {
|
||||||
|
// 菜单分页
|
||||||
|
Route::get('index', 'Menu/index');
|
||||||
|
|
||||||
|
// 菜单详情
|
||||||
|
Route::get('read/:id', 'Menu/read');
|
||||||
|
|
||||||
|
// 菜单新增
|
||||||
|
Route::post('save', 'Menu/save');
|
||||||
|
|
||||||
|
// 菜单更新
|
||||||
|
Route::put('update/:id', 'Menu/update');
|
||||||
|
|
||||||
|
// 菜单导入
|
||||||
|
Route::post('import', 'Menu/import');
|
||||||
|
|
||||||
|
// 菜单导出
|
||||||
|
Route::get('export', 'Menu/export');
|
||||||
|
|
||||||
|
// 设置排序值
|
||||||
|
Route::post('sort/:id', 'Menu/sort');
|
||||||
|
|
||||||
|
// 菜单删除
|
||||||
|
Route::delete('delete/:id', 'Menu/delete');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 导航管理
|
||||||
|
Route::group('navigation', function() {
|
||||||
|
// 列表
|
||||||
|
Route::get('list', 'Navigation/list');
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
Route::get('index', 'Navigation/index');
|
||||||
|
|
||||||
|
// 导航详情
|
||||||
|
Route::get('read/:id', 'Navigation/read');
|
||||||
|
|
||||||
|
// 导航新增
|
||||||
|
Route::post('save', 'Navigation/save');
|
||||||
|
|
||||||
|
// 导航更新
|
||||||
|
Route::put('update/:id', 'Navigation/update');
|
||||||
|
|
||||||
|
// 导航删除
|
||||||
|
Route::delete('delete/:id', 'Navigation/delete');
|
||||||
|
|
||||||
|
Route::group('items', function() {
|
||||||
|
// 导航分页
|
||||||
|
Route::get('index', 'NavigationItem/index');
|
||||||
|
|
||||||
|
// 导航详情
|
||||||
|
Route::get('read/:id', 'NavigationItem/read');
|
||||||
|
|
||||||
|
// 导航新增
|
||||||
|
Route::post('save', 'NavigationItem/save');
|
||||||
|
|
||||||
|
// 导航更新
|
||||||
|
Route::put('update/:id', 'NavigationItem/update');
|
||||||
|
|
||||||
|
// 导航设置排序值
|
||||||
|
Route::post('sort/:id', 'NavigationItem/sort');
|
||||||
|
|
||||||
|
// 导航删除
|
||||||
|
Route::delete('delete/:id', 'NavigationItem/delete');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 问答管理
|
||||||
|
Route::group('faq', function() {
|
||||||
|
// 问答分页
|
||||||
|
Route::get('index', 'Faq/index');
|
||||||
|
|
||||||
|
// 问答详情
|
||||||
|
Route::get('read/:id', 'Faq/read');
|
||||||
|
|
||||||
|
// 问答新增
|
||||||
|
Route::post('save', 'Faq/save');
|
||||||
|
|
||||||
|
// 问答更新
|
||||||
|
Route::put('update/:id', 'Faq/update');
|
||||||
|
|
||||||
|
// 设置问答排序值
|
||||||
|
Route::post('sort/:id', 'Faq/sort');
|
||||||
|
|
||||||
|
// 问答删除
|
||||||
|
Route::delete('delete/:id', 'Faq/delete');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 反馈管理 - 留言记录(联系我们)
|
||||||
|
Route::group('leavemsg', function() {
|
||||||
|
// 留言记录(联系我们)分页
|
||||||
|
Route::get('index', 'LeaveMessage/index');
|
||||||
|
|
||||||
|
// 留言记录(联系我们)导出
|
||||||
|
Route::get('export', 'LeaveMessage/export');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 反馈管理 - 批量采购底盘列表
|
||||||
|
Route::group('bp/inquiry', function() {
|
||||||
|
// 批量采购询盘可选品类
|
||||||
|
Route::get('interested', 'BulkPurchaseInquiry/interested');
|
||||||
|
|
||||||
|
// 批量采购底盘列表分页
|
||||||
|
Route::get('index', 'BulkPurchaseInquiry/index');
|
||||||
|
|
||||||
|
// 批量采购底盘列表导出
|
||||||
|
Route::get('export', 'BulkPurchaseInquiry/export');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 反馈管理 - 代理商申请列表
|
||||||
|
Route::group('agent', function() {
|
||||||
|
// 代理商企业规模类型
|
||||||
|
Route::get('enterprise_size_types', 'Agent/enterpriseSizeTypes');
|
||||||
|
|
||||||
|
// 代理商申请列表分页
|
||||||
|
Route::get('index', 'Agent/index');
|
||||||
|
|
||||||
|
// 代理商申请列表导出
|
||||||
|
Route::get('export', 'Agent/export');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 反馈管理 - 产品询盘列表
|
||||||
|
Route::get('product/inquiry/index', 'ProductInquiry/index');
|
||||||
|
|
||||||
|
// 配置项列表
|
||||||
|
Route::group('config', function() {
|
||||||
|
// 配置分组
|
||||||
|
Route::get('groups', 'SysConfig/groups');
|
||||||
|
|
||||||
|
// 配置类型
|
||||||
|
Route::get('types', 'SysConfig/types');
|
||||||
|
|
||||||
|
// 配置项分页
|
||||||
|
Route::get('index', 'SysConfig/index');
|
||||||
|
|
||||||
|
// 配置项详情
|
||||||
|
Route::get('read/:id', 'SysConfig/read');
|
||||||
|
|
||||||
|
// 配置项新增
|
||||||
|
Route::post('save', 'SysConfig/save');
|
||||||
|
|
||||||
|
// 配置项更新
|
||||||
|
Route::put('update/:id', 'SysConfig/update');
|
||||||
|
|
||||||
|
// 配置项删除
|
||||||
|
Route::delete('delete/:id', 'SysConfig/delete');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 站点配置
|
||||||
|
Route::group('site', function() {
|
||||||
|
Route::group('config', function() {
|
||||||
|
// 站点配置项
|
||||||
|
Route::get('index', 'SiteConfig/index');
|
||||||
|
|
||||||
|
// 站点配置更新
|
||||||
|
Route::put('update', 'SiteConfig/update');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 日志管理
|
||||||
|
Route::group('logs', function() {
|
||||||
|
// 操作日志列表
|
||||||
|
Route::get('operate/index', 'OperateLog/index');
|
||||||
});
|
});
|
||||||
})->prefix('v1.');
|
})->prefix('v1.');
|
||||||
|
|
||||||
|
// 接收产品目录同步数据
|
||||||
|
Route::group('receive_sync', function () {
|
||||||
|
Route::post('category', 'ReceiveProductSync/category');
|
||||||
|
Route::post('product', 'ReceiveProductSync/product');
|
||||||
|
});
|
||||||
|
|
||||||
Route::miss(function() {
|
Route::miss(function() {
|
||||||
return '404 Not Found!';
|
return '404 Not Found!';
|
||||||
});
|
});
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user