Compare commits
2508 Commits
master
...
feature/vi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5dbdbe778 | ||
|
|
de190a9076 | ||
|
|
efdb76ff0c | ||
|
|
a0d348748c | ||
|
|
3c499a1f8d | ||
|
|
df498efd2f | ||
|
|
6561f31e2d | ||
|
|
f0edad2b97 | ||
|
|
37e37540f8 | ||
|
|
8312807917 | ||
|
|
b52c178051 | ||
|
|
8c0f9451b7 | ||
|
|
0a262cbb25 | ||
|
|
e7fb16bd70 | ||
|
|
41810a8b80 | ||
|
|
53ee346ba0 | ||
|
|
fbfa584d55 | ||
|
|
2d834a57d5 | ||
|
|
a8041026a9 | ||
|
|
e6c3c1c857 | ||
|
|
37df0942ff | ||
|
|
3f51798bc1 | ||
|
|
85e34eda3d | ||
|
|
329f7562db | ||
|
|
a80efb09c0 | ||
|
|
122d12fec0 | ||
|
|
17bc8ad651 | ||
|
|
587028883a | ||
|
|
79bfd71a8e | ||
|
|
8aae3b84a5 | ||
|
|
238a6807ac | ||
|
|
49bd61c376 | ||
|
|
5dac5a8829 | ||
|
|
35e612d35c | ||
|
|
21fcd206db | ||
|
|
dd81c894e0 | ||
|
|
3b7ee0c6cc | ||
|
|
bdc0f0861f | ||
|
|
a694d33a9c | ||
|
|
a92123566d | ||
|
|
8fbdee3a22 | ||
|
|
583b210687 | ||
|
|
378c634c4a | ||
|
|
3f9deb61f0 | ||
|
|
154506ec6e | ||
|
|
320f9b9948 | ||
|
|
8b1669ccfc | ||
|
|
5eaada7828 | ||
|
|
6c3686232c | ||
|
|
34672ebfda | ||
|
|
371ec0c8dd | ||
|
|
7e974c8de3 | ||
|
|
c153846191 | ||
|
|
13a56c373c | ||
|
|
91c4e94609 | ||
|
|
78d6d9d52d | ||
|
|
0df75a6dfa | ||
|
|
18d00de5fc | ||
|
|
1ff28c6969 | ||
|
|
f49e5cd8a7 | ||
|
|
8a0a805af1 | ||
|
|
a3da9bacb0 | ||
|
|
c0de94aca9 | ||
|
|
7500bf286e | ||
|
|
e3937d2ed6 | ||
|
|
f3b799c56f | ||
|
|
0e250bbaba | ||
|
|
69b9001a99 | ||
|
|
0682de1644 | ||
|
|
70e455b88d | ||
|
|
9a575cff69 | ||
|
|
d14371d7dc | ||
|
|
b0bd16a53b | ||
|
|
00796025a6 | ||
|
|
59804f5891 | ||
|
|
ac6d877af9 | ||
|
|
e3824895b8 | ||
|
|
ffe6dc3c8f | ||
|
|
492af31f57 | ||
|
|
302391894b | ||
|
|
16c4b2dfa7 | ||
|
|
baed2d91b7 | ||
|
|
f7964ebe60 | ||
|
|
960f5c4940 | ||
|
|
c4214725be | ||
|
|
0ee41d9046 | ||
|
|
dc9e2278cc | ||
|
|
c3f7b017f5 | ||
|
|
e2cae6f692 | ||
|
|
e9f63c464f | ||
|
|
ba2d83dd43 | ||
|
|
609eb457d8 | ||
|
|
9e85d12824 | ||
|
|
037547a1d4 | ||
|
|
f641de929f | ||
|
|
322cd677b2 | ||
|
|
83722c8b7d | ||
|
|
deed632085 | ||
|
|
ef00fa435c | ||
|
|
1e5b01a446 | ||
|
|
ad3e7b5f7e | ||
|
|
3fb0b4bec0 | ||
|
|
ebcb37cdf6 | ||
|
|
82063280f7 | ||
|
|
eddd56a0de | ||
|
|
fc7f522524 | ||
|
|
418cc69634 | ||
|
|
40a73c2a34 | ||
|
|
040cef5028 | ||
|
|
a275e873fa | ||
|
|
9961da1d25 | ||
|
|
7032ea6e4f | ||
|
|
ab2207b109 | ||
|
|
1f1dc5eec8 | ||
|
|
b0b3193457 | ||
|
|
ffc5682a36 | ||
|
|
347bd16bb1 | ||
|
|
c3f6fbbffe | ||
|
|
d5b104fefd | ||
|
|
b879c1b0c4 | ||
|
|
23c5d65e0f | ||
|
|
bad3028a83 | ||
|
|
86dbba831f | ||
|
|
52d60210c7 | ||
|
|
15eb67168f | ||
|
|
c08514c60f | ||
|
|
1711b37750 | ||
|
|
d5c1bfe913 | ||
|
|
c4bee85e6f | ||
|
|
509379e704 | ||
|
|
84aa2f5f62 | ||
|
|
277029ad85 | ||
|
|
6861f7f754 | ||
|
|
5132d41b14 | ||
|
|
53f9434f53 | ||
|
|
cb57ac7b48 | ||
|
|
e404cc1417 | ||
|
|
bcec48bdbf | ||
|
|
188d0ed258 | ||
|
|
a9a466cca5 | ||
|
|
ff8120d1b5 | ||
|
|
e4707cb090 | ||
|
|
3d13fd5d54 | ||
|
|
54c79d94fb | ||
|
|
bcabbb8a6a | ||
|
|
98f732a7cf | ||
|
|
9c47fb9a16 | ||
|
|
5ba4df87fb | ||
|
|
6b173f2c29 | ||
|
|
55da7871ee | ||
|
|
bd67f05f91 | ||
|
|
f871cefbad | ||
|
|
83b7bdef8d | ||
|
|
46124ecf9c | ||
|
|
97181c4e8d | ||
|
|
bf1348fa63 | ||
|
|
c5b2b233b2 | ||
|
|
36e189f569 | ||
|
|
43976b674a | ||
|
|
c9c552bd4a | ||
|
|
7b0a7bf741 | ||
|
|
1c41f96f04 | ||
|
|
bd228bcd91 | ||
|
|
fbb9271966 | ||
|
|
6598c138c0 | ||
|
|
01a9997c86 | ||
|
|
605599efc4 | ||
|
|
25ca7f4027 | ||
|
|
f28e915c4a | ||
|
|
3d386d76e4 | ||
|
|
b001ef0bd5 | ||
|
|
73a26d8560 | ||
|
|
fa37a9cfc0 | ||
|
|
b33faf19f7 | ||
|
|
09d96a3c95 | ||
|
|
eb2d76de61 | ||
|
|
4f6d6b9e77 | ||
|
|
c0302ce05c | ||
|
|
c06d38bb5f | ||
|
|
9bd1f380be | ||
|
|
caeaccef37 | ||
|
|
9bd9a1375c | ||
|
|
e2c7e81482 | ||
|
|
c6f3552c56 | ||
|
|
215e13d19d | ||
|
|
5aead81caa | ||
|
|
37b470cc6c | ||
|
|
01fd644312 | ||
|
|
cb3f7da491 | ||
|
|
1ce37c38af | ||
|
|
f8dbd96dc2 | ||
|
|
61716196cd | ||
|
|
9bf8f4f754 | ||
|
|
8229258af4 | ||
|
|
a12a2b2d72 | ||
|
|
dc1075f865 | ||
|
|
fe14f74288 | ||
|
|
75f2349e76 | ||
|
|
c6a515554f | ||
|
|
4aa1d4259d | ||
|
|
5d9ea10cb0 | ||
|
|
d1b6b69807 | ||
|
|
068af5e40e | ||
|
|
067410f636 | ||
|
|
8a7867d6ea | ||
|
|
ab531d3b08 | ||
|
|
11ce529591 | ||
|
|
bc1a226039 | ||
|
|
8934545c00 | ||
|
|
a8056ae1ca | ||
|
|
c4ca30768b | ||
|
|
1f4081e2bb | ||
|
|
8d4d986332 | ||
|
|
55cbd9c60c | ||
|
|
697b561cac | ||
|
|
868149e480 | ||
|
|
488e2298de | ||
|
|
5c60f1ffb7 | ||
|
|
b957c92533 | ||
|
|
941b7c80d4 | ||
|
|
2ee8676c4e | ||
|
|
6b0852bbbc | ||
|
|
8eda688d37 | ||
|
|
6d90c17ed3 | ||
|
|
3b467c3e51 | ||
|
|
567bde994f | ||
|
|
efd7d00fa9 | ||
|
|
8d245eea07 | ||
|
|
8e9db3ddf8 | ||
|
|
1dacec1de0 | ||
|
|
f005576cb6 | ||
|
|
a01f1cb547 | ||
|
|
c9e74b7a8c | ||
|
|
3e03d087b2 | ||
|
|
3452420e52 | ||
|
|
f321fc8986 | ||
|
|
59a4be64b5 | ||
|
|
22b51bf673 | ||
|
|
31d641fdab | ||
|
|
81b309fa1c | ||
|
|
9816eca8a2 | ||
|
|
f75885415c | ||
|
|
2e90b6adf0 | ||
|
|
845db90a35 | ||
|
|
192277c870 | ||
|
|
53e318a27c | ||
|
|
4189b41a2f | ||
|
|
d32f771452 | ||
|
|
1ddb0a1149 | ||
|
|
02a30ee546 | ||
|
|
a1c0de83f0 | ||
|
|
875301eb1d | ||
|
|
8e352fa027 | ||
|
|
874e8fa677 | ||
|
|
ce6b11f384 | ||
|
|
ee64166f8c | ||
|
|
f1fc975d79 | ||
|
|
988c3b4c91 | ||
|
|
068c039d47 | ||
|
|
af109a9060 | ||
|
|
f11e892232 | ||
|
|
0c279f3d2e | ||
|
|
2d2da59305 | ||
|
|
f448d214b5 | ||
|
|
d918bbe8b3 | ||
|
|
edcd2c19f1 | ||
|
|
ef38382da9 | ||
|
|
e3b9eca251 | ||
|
|
41faad8172 | ||
|
|
8695290834 | ||
|
|
7d9ec29847 | ||
|
|
efc1a5a0b0 | ||
|
|
5008d89ee4 | ||
|
|
8b8e5885a0 | ||
|
|
f834d71ca5 | ||
|
|
a701d94402 | ||
|
|
1a262d8859 | ||
|
|
ef6009f0cc | ||
|
|
aca483c7a0 | ||
|
|
f1a289ca05 | ||
|
|
c5e68bed86 | ||
|
|
6c8071aa83 | ||
|
|
6ac0b993ba | ||
|
|
0d18199cdf | ||
|
|
b532e9ce90 | ||
|
|
2cb1dc69df | ||
|
|
be079b0615 | ||
|
|
d91e5ed550 | ||
|
|
20455c96d3 | ||
|
|
f595909d73 | ||
|
|
0d77f909b8 | ||
|
|
b87c13c233 | ||
|
|
11ff8c8405 | ||
|
|
791e4d829b | ||
|
|
201cc49865 | ||
|
|
ea622b0378 | ||
|
|
e66d26f195 | ||
|
|
ab23f91b7c | ||
|
|
31231817b6 | ||
|
|
61ba2521e4 | ||
|
|
d34889997b | ||
|
|
e96726b8de | ||
|
|
84c679941c | ||
|
|
f794bc6ab0 | ||
|
|
471d00b47c | ||
|
|
fe44893e15 | ||
|
|
b6cab0818c | ||
|
|
3bd3fb4950 | ||
|
|
e0e0329cfe | ||
|
|
4abe2b7bf5 | ||
|
|
ec70dc13bc | ||
|
|
19c20944e4 | ||
|
|
e5d1e8eb55 | ||
|
|
a1b4574bae | ||
|
|
720adb7e86 | ||
|
|
b8c7e03f29 | ||
|
|
2a8d1f17a5 | ||
|
|
9d0047e071 | ||
|
|
fb491446c7 | ||
|
|
3f4633677b | ||
|
|
d7f0b63eb9 | ||
|
|
32eaae40d7 | ||
|
|
36f516c037 | ||
|
|
663ddc8386 | ||
|
|
253d90b15a | ||
|
|
94b86e2a0b | ||
|
|
b3f0ed96e9 | ||
|
|
9e6532194f | ||
|
|
c5e2bef011 | ||
|
|
4b3e287a5f | ||
|
|
b89e7db2a2 | ||
|
|
0dcc74b567 | ||
|
|
5b128adddb | ||
|
|
17f59a1954 | ||
|
|
9b24504528 | ||
|
|
aafcec25fb | ||
|
|
8f1c25043d | ||
|
|
26f5483182 | ||
|
|
4cd600d285 | ||
|
|
ac1d17c216 | ||
|
|
4f62c5cb9d | ||
|
|
658a29853b | ||
|
|
a35a78ef00 | ||
|
|
6d3fe01c99 | ||
|
|
aa6579d040 | ||
|
|
d57890c0a9 | ||
|
|
cf99b2730a | ||
|
|
9997f732dc | ||
|
|
3329cd4bf1 | ||
|
|
f16f3457dd | ||
|
|
2282183509 | ||
|
|
5cb525d9a2 | ||
|
|
7f82c5b4cf | ||
|
|
f4d64555d0 | ||
|
|
7813ddb003 | ||
|
|
3eff2139dc | ||
|
|
b5c85e0031 | ||
|
|
8d727d4f39 | ||
|
|
b2002d5989 | ||
|
|
4f357b1dd4 | ||
|
|
d85ab06f68 | ||
|
|
f0099ecd92 | ||
|
|
d5a20de52b | ||
|
|
7101bdff2c | ||
|
|
2831c8b5af | ||
|
|
d896db5d4d | ||
|
|
59db5a1568 | ||
|
|
7dc3032824 | ||
|
|
28bba07f22 | ||
|
|
5da0f4b651 | ||
|
|
07fac1c94e | ||
|
|
f1f8b2bf93 | ||
|
|
f89deadcb2 | ||
|
|
bd3ef507cc | ||
|
|
12c6d325ce | ||
|
|
7063fd5cd9 | ||
|
|
e051460e31 | ||
|
|
4413821d1b | ||
|
|
0eb642a625 | ||
|
|
04beb515d0 | ||
|
|
5996377c2d | ||
|
|
74c47dcba0 | ||
|
|
db07381bbd | ||
|
|
a170cf7b1f | ||
|
|
156bdba217 | ||
|
|
34afcbf84e | ||
|
|
aae17797b7 | ||
|
|
65e49790e8 | ||
|
|
0ab2a0f5b7 | ||
|
|
d9e1f83d05 | ||
|
|
cf18beb6dc | ||
|
|
fe09fa4983 | ||
|
|
7a310007b1 | ||
|
|
f5abfa0084 | ||
|
|
d7b7de09f7 | ||
|
|
c1131c0b54 | ||
|
|
2f05a88e56 | ||
|
|
b804a7e5aa | ||
|
|
73080b55f8 | ||
|
|
5e5e0d9b57 | ||
|
|
552c6888e5 | ||
|
|
d650dedcb6 | ||
|
|
e85ef5ff6f | ||
|
|
2d53a8a31d | ||
|
|
12bb196de3 | ||
|
|
a29a934e95 | ||
|
|
8aee36e808 | ||
|
|
0fa2950bb7 | ||
|
|
68e26624be | ||
|
|
c29d493159 | ||
|
|
837c31abeb | ||
|
|
1836d989ca | ||
|
|
d1c92c569f | ||
|
|
d58b590200 | ||
|
|
b5a0522fb9 | ||
|
|
62f92569b3 | ||
|
|
6d50374606 | ||
|
|
4b67e33ae9 | ||
|
|
a5bc5689a3 | ||
|
|
bd410a9559 | ||
|
|
351667a8a0 | ||
|
|
1c40a78bae | ||
|
|
d388123410 | ||
|
|
2d307db6ce | ||
|
|
09974cb43b | ||
|
|
ed9a206ad6 | ||
|
|
8317137068 | ||
|
|
edda197051 | ||
|
|
5e91aee82e | ||
|
|
1bfe8afc8b | ||
|
|
a6cd4d2578 | ||
|
|
c6f7d4e449 | ||
|
|
ea4f22c2b9 | ||
|
|
a50c9ce240 | ||
|
|
0f03dc9d04 | ||
|
|
4b4baf4952 | ||
|
|
baccd4505b | ||
|
|
7ee49a5367 | ||
|
|
6522a101ea | ||
|
|
f114c9497a | ||
|
|
20c61297c6 | ||
|
|
2bf8c5d150 | ||
|
|
8b133291a4 | ||
|
|
980f8e1f5a | ||
|
|
0cec1b0a20 | ||
|
|
1e64e12d49 | ||
|
|
f529e4bb32 | ||
|
|
c8a3e74ae5 | ||
|
|
a2fa966ccd | ||
|
|
7d0fd6b907 | ||
|
|
6b1797e36d | ||
|
|
9764c831d7 | ||
|
|
53bf46fac5 | ||
|
|
fb8ea2a195 | ||
|
|
cebe4ce80f | ||
|
|
031faeff50 | ||
|
|
422dcdc6be | ||
|
|
7d63ea0c19 | ||
|
|
ad8f080643 | ||
|
|
44bd3c95c3 | ||
|
|
86451a245f | ||
|
|
d12705b4f6 | ||
|
|
0e96395d98 | ||
|
|
cef8dad5f0 | ||
|
|
5c7e2e4098 | ||
|
|
b8401c34c9 | ||
|
|
da8e8f0d65 | ||
|
|
92f8fd0af8 | ||
|
|
e3626ea7ba | ||
|
|
7c3620eea1 | ||
|
|
dd4b58312e | ||
|
|
d87c947ca1 | ||
|
|
83580d9ef3 | ||
|
|
8db4f1bb30 | ||
|
|
2c1430b88a | ||
|
|
7a0d0322da | ||
|
|
67b9c61eef | ||
|
|
37ea4d4db6 | ||
|
|
bcd90e0706 | ||
|
|
108c486240 | ||
|
|
489b39f9e6 | ||
|
|
6e3f72092c | ||
|
|
292b4720e3 | ||
|
|
eb408e0bfb | ||
|
|
83a30fda7d | ||
|
|
88ac20bbcd | ||
|
|
e73641d6de | ||
|
|
d57fd8a7a2 | ||
|
|
62752263c0 | ||
|
|
2f5aba907e | ||
|
|
2a924caacd | ||
|
|
8eb0c51937 | ||
|
|
9693df6e26 | ||
|
|
f8105d5422 | ||
|
|
2f351dbd68 | ||
|
|
7ee368e6db | ||
|
|
a75c2d254f | ||
|
|
86b1349a46 | ||
|
|
5219ca9a3f | ||
|
|
f67bdea66f | ||
|
|
7cf7d41c23 | ||
|
|
d046ca1dd6 | ||
|
|
e02aad528e | ||
|
|
b0f0e693aa | ||
|
|
59d0a80043 | ||
|
|
0d5a9fed10 | ||
|
|
3e87d2afca | ||
|
|
acb8bd9d1c | ||
|
|
52485cb63e | ||
|
|
8e31b662ce | ||
|
|
a632cefb3b | ||
|
|
96b7c8bbeb | ||
|
|
9c61fde48d | ||
|
|
065e474c86 | ||
|
|
9e0f38c0e3 | ||
|
|
7dd7e6483c | ||
|
|
0dc6a67f9f | ||
|
|
4a3063bd8c | ||
|
|
efb7ebeeee | ||
|
|
792d270446 | ||
|
|
59f8671e90 | ||
|
|
da929c20a2 | ||
|
|
4be5825cf1 | ||
|
|
e9d5e63a3e | ||
|
|
cd76b41ba7 | ||
|
|
53daf5309b | ||
|
|
0b0b15fd55 | ||
|
|
d8f13f09c5 | ||
|
|
fc7067cff3 | ||
|
|
0ec77d5a48 | ||
|
|
9d36bbbf06 | ||
|
|
6a09277e2b | ||
|
|
fa6ea7a9b3 | ||
|
|
1b55f8d643 | ||
|
|
4e3632e4b5 | ||
|
|
de03942d0e | ||
|
|
6bfc039364 | ||
|
|
21e1fa71b8 | ||
|
|
4db8628b87 | ||
|
|
b784d81020 | ||
|
|
62b5ff4458 | ||
|
|
324edf7569 | ||
|
|
c17cebfe2a | ||
|
|
33e38db789 | ||
|
|
1c2381c9b1 | ||
|
|
071bd9daf5 | ||
|
|
5d2c1279d8 | ||
|
|
bb7406c7c9 | ||
|
|
36ccc9ace2 | ||
|
|
d8c652762a | ||
|
|
10ded04b7d | ||
|
|
9587b1acfe | ||
|
|
a08aca7afe | ||
|
|
7a0ae3143b | ||
|
|
b29ddfc2fc | ||
|
|
555a888ab7 | ||
|
|
27afc15796 | ||
|
|
d601b1d4c2 | ||
|
|
844fad5301 | ||
|
|
1c9490427b | ||
|
|
f80c5a3b41 | ||
|
|
fbd7680927 | ||
|
|
392ba406bc | ||
|
|
0e15dca25b | ||
|
|
d53bc8fe20 | ||
|
|
3d1e68b29d | ||
|
|
2c00ad961c | ||
|
|
6ecad30626 | ||
|
|
9ccf4e2a3b | ||
|
|
6de41e883a | ||
|
|
584eec0e78 | ||
|
|
3624b48511 | ||
|
|
47ce4ba424 | ||
|
|
39f5bcbd5a | ||
|
|
d7568eb799 | ||
|
|
0f3276ceca | ||
|
|
ef6855c3a6 | ||
|
|
fdf441c8e8 | ||
|
|
d4bb5d2de0 | ||
|
|
bc1f9ba4cb | ||
|
|
024cb5831b | ||
|
|
84bf07717a | ||
|
|
cc211cd22b | ||
|
|
b117cf9d51 | ||
|
|
8341473672 | ||
|
|
d021781d75 | ||
|
|
059da71d6d | ||
|
|
52c62f7955 | ||
|
|
352ae43faa | ||
|
|
361792c48d | ||
|
|
2b248b0177 | ||
|
|
d923fd5420 | ||
|
|
92d5b99384 | ||
|
|
315d852eaf | ||
|
|
e1760adf4e | ||
|
|
f69550c015 | ||
|
|
393846b836 | ||
|
|
18e4ffa7a1 | ||
|
|
0056a31dcb | ||
|
|
40ebb8630a | ||
|
|
d51918b713 | ||
|
|
51d2b8eaf9 | ||
|
|
1605d280b8 | ||
|
|
7ae4e92a93 | ||
|
|
d5fe146cec | ||
|
|
f239508b87 | ||
|
|
a6924dac90 | ||
|
|
9ea41700c7 | ||
|
|
09cced8bc3 | ||
|
|
4b893b6c49 | ||
|
|
6eb7b5d13d | ||
|
|
781c0f1543 | ||
|
|
b9964d64b0 | ||
|
|
6896dfd197 | ||
|
|
e0221ae9ee | ||
|
|
d212d1ea1f | ||
|
|
513db9b4b9 | ||
|
|
4b93111ae0 | ||
|
|
bfa2985b2f | ||
|
|
0ac30e762e | ||
|
|
d5fadfc498 | ||
|
|
7b3fcef56e | ||
|
|
a9e4aae662 | ||
|
|
0a154f0c1f | ||
|
|
a59a96b092 | ||
|
|
ed30be74bc | ||
|
|
96aec2e69f | ||
|
|
6e5a1c3921 | ||
|
|
aa846b62a7 | ||
|
|
b5ae298ee9 | ||
|
|
a3cb513b57 | ||
|
|
54127cc668 | ||
|
|
3e466e01cb | ||
|
|
47b681c99d | ||
|
|
a1ca224a98 | ||
|
|
07bc1389c1 | ||
|
|
9292429c8c | ||
|
|
356758a184 | ||
|
|
d979943852 | ||
|
|
8a7d6f746f | ||
|
|
6deb734d94 | ||
|
|
e55e0fc2cc | ||
|
|
d8817261ca | ||
|
|
8e04ec040a | ||
|
|
05db88644c | ||
|
|
90ab2dec01 | ||
|
|
16128af70f | ||
|
|
1a3827e541 | ||
|
|
cc283155a1 | ||
|
|
a751e3e70b | ||
|
|
3b58dec324 | ||
|
|
503416902c | ||
|
|
1c54bac79c | ||
|
|
ff322874e2 | ||
|
|
03bd52194b | ||
|
|
17e2d3b12a | ||
|
|
834132fec2 | ||
|
|
e7e69d72e3 | ||
|
|
98762e996c | ||
|
|
11e8588e0d | ||
|
|
0ac92994bc | ||
|
|
3ac9250f38 | ||
|
|
340e40b6d1 | ||
|
|
87215e6352 | ||
|
|
d3aa3eef94 | ||
|
|
7db8828e0b | ||
|
|
25b4572ec8 | ||
|
|
5f208c4510 | ||
|
|
c378806112 | ||
|
|
dd9394b9eb | ||
|
|
169c3afc06 | ||
|
|
4567edbd5f | ||
|
|
387b25c678 | ||
|
|
918b88e5e2 | ||
|
|
b66d14f53e | ||
|
|
c7c72ddd26 | ||
|
|
c03be59b18 | ||
| 6b80930bc0 | |||
|
|
768304bf9d | ||
|
|
3e2a01339d | ||
|
|
7b70dafbaf | ||
|
|
62248f1ac6 | ||
|
|
ddc87afed2 | ||
|
|
531f1a55fd | ||
|
|
db71cb58d3 | ||
|
|
345f1c10b0 | ||
|
|
f95dc9adcc | ||
|
|
3dce3cd497 | ||
|
|
fb44d8888a | ||
|
|
ca38041eec | ||
|
|
2dbdc7a4c4 | ||
|
|
942078e3fd | ||
|
|
5bc5bf0672 | ||
|
|
307f835cec | ||
|
|
a5bfb77e2a | ||
|
|
fd755fa58a | ||
|
|
318b7d7748 | ||
|
|
ffd792acaa | ||
|
|
7f76715aeb | ||
|
|
c09236b06f | ||
|
|
00142f0935 | ||
|
|
190afb8d9d | ||
|
|
447a9703ac | ||
|
|
7235fd4834 | ||
|
|
dc44b85d69 | ||
|
|
db8b9b82da | ||
|
|
abc33595df | ||
|
|
bf29282de6 | ||
|
|
1b07cef1d5 | ||
|
|
dd8ba7e3ce | ||
|
|
d862c250fa | ||
|
|
8ebac73812 | ||
|
|
e941dda29c | ||
|
|
f74ca9402a | ||
|
|
08f8739a80 | ||
|
|
4066e61fba | ||
|
|
55be902080 | ||
|
|
2c2bc040ca | ||
|
|
a3f5bc03d0 | ||
|
|
2f1e902885 | ||
|
|
bf6d86bf4e | ||
|
|
95ac3d55ae | ||
|
|
733e873785 | ||
|
|
a0b90c4299 | ||
|
|
3ab05fc552 | ||
|
|
1c44c9e776 | ||
|
|
f34a0ac163 | ||
|
|
570256341d | ||
|
|
6e8b6b41df | ||
|
|
94ee820ace | ||
|
|
3080718d95 | ||
|
|
b35314bf83 | ||
|
|
1dbe9c1a2b | ||
|
|
241395d610 | ||
|
|
2062bc6160 | ||
|
|
41687a386b | ||
|
|
c1c046971e | ||
|
|
b25222b93e | ||
|
|
ea85e1c82b | ||
|
|
8fe7970b81 | ||
|
|
2a4d9b2b1c | ||
|
|
0736ea98d0 | ||
|
|
81a61c4ec4 | ||
|
|
c5d3b941dc | ||
|
|
9a2623232c | ||
|
|
96f565bbe4 | ||
|
|
231717f862 | ||
|
|
ca02cfc24e | ||
|
|
8e94580b56 | ||
|
|
3fdc528ffe | ||
|
|
35de4f51de | ||
|
|
3e5427633a | ||
|
|
05ff4c5a0e | ||
|
|
ff8491c0f3 | ||
|
|
fbb77ace5d | ||
|
|
438a24101d | ||
|
|
e6fe7b224b | ||
|
|
a407d007be | ||
|
|
d4534c7dca | ||
|
|
2b3925abf0 | ||
|
|
1fb21fdbd3 | ||
|
|
0a49f98892 | ||
|
|
a4348368e0 | ||
|
|
0dfe3125c7 | ||
|
|
c924ed7c71 | ||
|
|
ccb99b00c1 | ||
|
|
c67633eda5 | ||
|
|
55a7cd8624 | ||
|
|
b2600d0de5 | ||
|
|
f550ae832b | ||
|
|
6d338b8324 | ||
|
|
92645d9c17 | ||
|
|
6d75362672 | ||
|
|
d5ecc2579b | ||
|
|
6dab0e1f72 | ||
|
|
d24898b558 | ||
|
|
fc220c7868 | ||
|
|
33294ac8e7 | ||
|
|
07ca7dc8a7 | ||
|
|
3365fcb1ef | ||
|
|
fa7c5428c5 | ||
|
|
c9dc8940ed | ||
|
|
e20e479697 | ||
|
|
c752a1c92b | ||
|
|
05af474916 | ||
|
|
b4e54b8fdc | ||
|
|
0b89f4c0a1 | ||
|
|
70e1337980 | ||
|
|
4b04209e62 | ||
|
|
0d31afa0a5 | ||
|
|
893ec0efc9 | ||
|
|
47d44a94b8 | ||
|
|
a1ee74f4c8 | ||
|
|
61bacc2742 | ||
|
|
6c581378e8 | ||
|
|
d819783b21 | ||
|
|
a0cf4601b7 | ||
|
|
3a39248f9c | ||
|
|
f8f4c2ffec | ||
|
|
94331d6ba0 | ||
|
|
34dd2fcbcc | ||
|
|
53d0350259 | ||
|
|
d510da6e71 | ||
|
|
eda3252c95 | ||
|
|
c353a19fe5 | ||
|
|
15877d15f4 | ||
|
|
8ee4054eff | ||
|
|
94e27be64b | ||
|
|
10e658af76 | ||
|
|
c93c5b6c93 | ||
|
|
b7dfd189a0 | ||
|
|
58c3d89297 | ||
|
|
49aa0a6276 | ||
|
|
e71d1fcf12 | ||
|
|
a09048af63 | ||
|
|
f446104dda | ||
|
|
c17018ae9d | ||
|
|
69509c43f1 | ||
|
|
8a25040a26 | ||
|
|
aaf7631ef3 | ||
|
|
a134902bd6 | ||
|
|
768c0759ac | ||
|
|
442296a414 | ||
|
|
90ab577eb1 | ||
|
|
bf799bdd93 | ||
|
|
0debe23873 | ||
|
|
79e06e38ae | ||
|
|
d94fdb9f86 | ||
|
|
6d35edee98 | ||
|
|
45cde1e2e7 | ||
|
|
b63cd4b427 | ||
|
|
97d5c51a12 | ||
|
|
1ea7bf16f2 | ||
|
|
3a7506e0f6 | ||
|
|
09bc287157 | ||
|
|
99555c3924 | ||
|
|
82d93a1266 | ||
|
|
0913a70ac7 | ||
|
|
75d1f34b5d | ||
|
|
8424a06217 | ||
|
|
67d3ad9bca | ||
|
|
bcef93975e | ||
|
|
cf6610153f | ||
|
|
e46dc98f58 | ||
|
|
261a6c6ffa | ||
|
|
4eb47552b3 | ||
|
|
a4ac8060ba | ||
|
|
4d99866e39 | ||
|
|
f6d36a132d | ||
|
|
97c43de5ce | ||
|
|
4bcf08213f | ||
|
|
1643123b77 | ||
|
|
48a6abc8b0 | ||
|
|
ffcd58a34a | ||
|
|
7eb409548b | ||
|
|
81701253cd | ||
|
|
89bcc1c27b | ||
|
|
f39003c785 | ||
|
|
a2c7c4628d | ||
|
|
7b2a394d9c | ||
|
|
5916681635 | ||
|
|
b578e07243 | ||
|
|
a73749b450 | ||
|
|
c27a19a06b | ||
|
|
234b9f34d5 | ||
|
|
93f1523caa | ||
|
|
b22c153f3d | ||
|
|
2a416e8177 | ||
|
|
3bca9a4865 | ||
|
|
b0457b8161 | ||
|
|
16aaa2e95a | ||
|
|
be0c55de75 | ||
|
|
e0d1860aaa | ||
|
|
a73d93c1ca | ||
|
|
9ce09b38de | ||
|
|
ad856bfaae | ||
|
|
f17b80abba | ||
|
|
9b36b9de6d | ||
|
|
479163c50e | ||
|
|
305345a955 | ||
|
|
4414bd3416 | ||
|
|
c5d1030940 | ||
|
|
b0ea8c451b | ||
|
|
61217e07b8 | ||
|
|
79efa10aa1 | ||
|
|
63286e3f48 | ||
|
|
5f853d5ac3 | ||
|
|
6abe23d791 | ||
|
|
4e36387bb2 | ||
|
|
fd03bba979 | ||
|
|
a084961c0b | ||
|
|
150760f6ce | ||
|
|
59931236ba | ||
|
|
fd5f976dcf | ||
|
|
932733839f | ||
|
|
4fc53f7519 | ||
|
|
f71e163e0a | ||
|
|
18c7277d7b | ||
|
|
829e2f5ab8 | ||
|
|
79c6636fb2 | ||
|
|
5403db62fa | ||
|
|
425db08622 | ||
|
|
0e7f0b4d26 | ||
|
|
697b0a5eaf | ||
|
|
364f042e9b | ||
|
|
da259ebec6 | ||
|
|
dbca23bb6d | ||
|
|
64eafa988b | ||
|
|
355a0fe50e | ||
|
|
46c5474b4e | ||
|
|
23d677bc82 | ||
|
|
5eaf8f996a | ||
|
|
733871805a | ||
|
|
86dbce3da8 | ||
|
|
d4ab166fe0 | ||
|
|
0705687d12 | ||
|
|
246aaee5b1 | ||
|
|
ca4a465312 | ||
|
|
e4ce3d7c45 | ||
|
|
b90cc9065f | ||
|
|
69ea4af045 | ||
|
|
7e89712bd9 | ||
|
|
dfa29e1677 | ||
|
|
aef1ebc8c9 | ||
|
|
5d656a9e65 | ||
|
|
e04acbcf5b | ||
|
|
1f7e2b4d84 | ||
|
|
d6d2e7b909 | ||
|
|
7de09aa195 | ||
|
|
6835f1da50 | ||
|
|
2004368c90 | ||
|
|
ec41626868 | ||
|
|
d1acd1de71 | ||
|
|
f6d8a737df | ||
|
|
37e16f5795 | ||
|
|
d5d5fa6055 | ||
|
|
6ec577f14d | ||
|
|
9300dac087 | ||
|
|
3f25e3a753 | ||
|
|
5dc1ba2230 | ||
|
|
208b440c86 | ||
|
|
8bc6655ec7 | ||
|
|
d2bec8554d | ||
|
|
7453962f52 | ||
|
|
4b518445ef | ||
|
|
f9d5e51222 | ||
|
|
5b94b47e02 | ||
|
|
1464cfa2de | ||
|
|
e4d1e85156 | ||
|
|
8998e9a664 | ||
|
|
97d29d0d7e | ||
|
|
a4d48f643b | ||
|
|
5d4a8af8d7 | ||
|
|
0f221d2f9d | ||
|
|
322d0cb479 | ||
|
|
e91d1f73dc | ||
|
|
036ee91533 | ||
|
|
71049f7f65 | ||
|
|
f39746e303 | ||
|
|
c0d890a0a8 | ||
|
|
d0e18eb2f6 | ||
|
|
82535aff40 | ||
|
|
65fb4ac65b | ||
|
|
93d0e0aafe | ||
|
|
1eb9c532f3 | ||
|
|
b4446a24a6 | ||
|
|
3174382666 | ||
|
|
e8c8c1cba6 | ||
|
|
92890111ee | ||
|
|
9b35506181 | ||
|
|
73f300cd7a | ||
|
|
3dd57db73b | ||
|
|
a2925da21b | ||
|
|
2f79210970 | ||
|
|
c3d92c18d0 | ||
|
|
ae24b4d6b4 | ||
|
|
61de1da32d | ||
|
|
70557adefd | ||
|
|
7894fb68f8 | ||
|
|
409fcd6f44 | ||
|
|
61fed1f99f | ||
|
|
32aae8fe4f | ||
|
|
74e34e52e8 | ||
|
|
4b9bd8ffa8 | ||
|
|
018b926c6c | ||
|
|
1355ef7509 | ||
|
|
a076c7b331 | ||
|
|
195c6e3aa6 | ||
|
|
046b1d0c5a | ||
|
|
b6a686a021 | ||
|
|
bc8cc63d17 | ||
|
|
db406eb8fa | ||
|
|
c1010119aa | ||
|
|
a0cc85027c | ||
|
|
1db79c53a0 | ||
|
|
39f6cb1ff2 | ||
|
|
55e3ab0612 | ||
|
|
84954bcc84 | ||
|
|
a0c2bf8f67 | ||
|
|
bd2b066e9a | ||
|
|
7d99c2fb5f | ||
|
|
6d3984654c | ||
|
|
64202161dd | ||
|
|
6f14126a2e | ||
|
|
f757852ac4 | ||
|
|
f38eff6564 | ||
|
|
92516a7753 | ||
|
|
890cbaa0b9 | ||
|
|
376a4778b8 | ||
|
|
cc46a5a9c8 | ||
|
|
e8439fe40a | ||
|
|
3464798fd9 | ||
|
|
5a730afb99 | ||
|
|
46596b6d57 | ||
|
|
8a0141bf2d | ||
|
|
869d9a4635 | ||
|
|
6eb9dd2ee6 | ||
|
|
47024dde2a | ||
|
|
f764b37c8a | ||
|
|
85324959a0 | ||
|
|
6298eeaae3 | ||
|
|
c398a354b9 | ||
|
|
abe2f9892e | ||
|
|
8744f115cf | ||
|
|
cf4ae0bc58 | ||
|
|
4cb734cbe0 | ||
|
|
a4e7a9ff30 | ||
|
|
572f155bf5 | ||
|
|
99ef026ff0 | ||
|
|
86a1128d9a | ||
|
|
38f3ecc288 | ||
|
|
ec29f1dc11 | ||
|
|
c186b95ae7 | ||
|
|
d5fa92d90f | ||
|
|
6f5a918bd1 | ||
|
|
96ad4ac999 | ||
|
|
efc3252c1b | ||
|
|
197201d923 | ||
|
|
8baf806758 | ||
|
|
192af31223 | ||
|
|
dc2e2ff079 | ||
|
|
97759ee9d2 | ||
|
|
ea42e0e53a | ||
|
|
b85a5a9cfb | ||
|
|
001fc94d95 | ||
|
|
5f8fff9943 | ||
|
|
476dec8d17 | ||
|
|
0a815cbb35 | ||
|
|
74b98805a5 | ||
|
|
b5d7ee5c58 | ||
|
|
d970a443ce | ||
|
|
22cbb0c6bf | ||
|
|
a23dc0b0cd | ||
|
|
7bbeb88804 | ||
|
|
27f9d4740d | ||
|
|
c0c5cd79ee | ||
|
|
a6c9430a42 | ||
|
|
b468befe67 | ||
|
|
b6bcf204f5 | ||
|
|
7bc5f87471 | ||
|
|
bb46e123fe | ||
|
|
e99ea5b2de | ||
|
|
40dfa8686b | ||
|
|
731389d4a2 | ||
|
|
2174909bb8 | ||
|
|
bd512c3caa | ||
|
|
7c13051ce1 | ||
|
|
bfde95f6ca | ||
|
|
9861b4718e | ||
|
|
861e7c688f | ||
|
|
4f0178c627 | ||
|
|
2f612a074c | ||
|
|
11eda3d90b | ||
|
|
c78a75718a | ||
|
|
ee93320cad | ||
|
|
35fcde4dca | ||
|
|
054f8b8a50 | ||
|
|
8f79d72950 | ||
|
|
3ba4c9089c | ||
|
|
471609f59c | ||
|
|
ffcd6f2943 | ||
|
|
abdeeef32f | ||
|
|
fa64373189 | ||
|
|
10cb930034 | ||
|
|
ab3e8ad93f | ||
|
|
a45e5a8844 | ||
|
|
91f8c77e34 | ||
|
|
98a228e644 | ||
|
|
bc9a255a3f | ||
|
|
5c3e626df1 | ||
|
|
4db2c45c4a | ||
|
|
c921eec601 | ||
|
|
ab146f9a69 | ||
|
|
48b3839eca | ||
|
|
7e19978d7a | ||
|
|
050f76c1be | ||
| f4873d924f | |||
| 6fedce8dac | |||
| 9f4c44d75d | |||
|
|
f0e3aaa3ab | ||
|
|
9521730bae | ||
|
|
ac99e83459 | ||
|
|
3ce7f47a6b | ||
|
|
c430bbf467 | ||
|
|
ea36a748c8 | ||
| 2c5542d985 | |||
| 722d861dfd | |||
| 5ea1728dbb | |||
|
|
53a4e5ea27 | ||
| 6a75a3470f | |||
| 8600eb20bc | |||
|
|
2074d29e55 | ||
|
|
9283c0c283 | ||
|
|
b25f4ff713 | ||
|
|
17c74dd956 | ||
| e0bb149e44 | |||
| f81e56feab | |||
|
|
4b994d76e9 | ||
| 426ce5f49a | |||
| 460a2b0ab7 | |||
|
|
9c0685e4ff | ||
| 3abcf75a3f | |||
| 01e1bc3d7a | |||
| 4d1df90887 | |||
| e687a6b572 | |||
|
|
53a185fec6 | ||
|
|
74adde5a40 | ||
|
|
03d990f8b5 | ||
| d52d2b352d | |||
| 41bc5e8750 | |||
| f796fbc536 | |||
| c6a9856689 | |||
| 6359ceecb3 | |||
| f2bcbffde4 | |||
| 8bdc53d7ca | |||
| d697c5213f | |||
| b7104acd58 | |||
| b84d3bec66 | |||
| d2264c90d1 | |||
| 1d0de7a9c5 | |||
|
|
cce3c47466 | ||
|
|
a01d79fe2f | ||
| 283fb8767d | |||
| 9baf7fe2ef | |||
| 4ff43d632e | |||
|
|
49dabf912c | ||
| 2fe01ec7cf | |||
| 7250ff3a45 | |||
| 832be3f1ec | |||
| 69347cde15 | |||
| f384b4c73d | |||
|
|
0c2b0c6733 | ||
|
|
a49fb6016b | ||
|
|
0370ea61d9 | ||
|
|
25bdc08ede | ||
|
|
e2583c25f9 | ||
|
|
d01a7b58fa | ||
|
|
d3cb80666e | ||
|
|
a52c3a1eca | ||
|
|
38fcdfdb70 | ||
|
|
2360db1924 | ||
|
|
9baf96b0c2 | ||
|
|
44e8683cd5 | ||
|
|
9efa58ad49 | ||
|
|
71631bf2ca | ||
|
|
22e7c83a74 | ||
|
|
2a6563a6c1 | ||
|
|
fe15dcdad9 | ||
|
|
bff298f5c9 | ||
|
|
53d7b3fc85 | ||
|
|
893a75c582 | ||
|
|
86c8722638 | ||
|
|
d1e3e69006 | ||
|
|
8719b9d851 | ||
|
|
7cc8b5be93 | ||
|
|
b095835e62 | ||
|
|
8cc46723f0 | ||
|
|
4f52add246 | ||
|
|
867ab92be8 | ||
|
|
e36ebca88c | ||
|
|
e854868514 | ||
|
|
4ec129a695 | ||
|
|
99e8432ea7 | ||
|
|
31b3e6c670 | ||
|
|
459485c83b | ||
|
|
5a14c5373b | ||
|
|
0c25c114d0 | ||
|
|
23edcd62d9 | ||
|
|
7db829566c | ||
|
|
7feea057bc | ||
|
|
52da9be2fc | ||
|
|
fb33d84784 | ||
|
|
506e4d5dac | ||
|
|
b16b5d5e6c | ||
|
|
96c2a69872 | ||
|
|
9bcbb2c851 | ||
|
|
d0b56ba0d1 | ||
|
|
a72cbd4811 | ||
|
|
0c69a922a5 | ||
|
|
285fc7aaa9 | ||
|
|
d04eb1a4a7 | ||
|
|
00a1adaf82 | ||
|
|
ec93e7cc0d | ||
|
|
f4f23b4814 | ||
|
|
8002d58294 | ||
|
|
222789a438 | ||
|
|
6ede9e8871 | ||
|
|
178d254bf8 | ||
|
|
8f01e046e0 | ||
|
|
99a9433c92 | ||
|
|
9ff75ba4b5 | ||
|
|
e90f40671d | ||
|
|
6ee61ae682 | ||
|
|
669b56c5f9 | ||
|
|
f42f6a165d | ||
|
|
586f3746ad | ||
|
|
f134ee8f26 | ||
|
|
e036ae13aa | ||
|
|
3d27008b40 | ||
|
|
2aa6092938 | ||
|
|
3e036b221f | ||
|
|
2d2865213e | ||
|
|
9497074b72 | ||
|
|
19a18e34a5 | ||
|
|
e72ffbf7d0 | ||
|
|
a0c547c510 | ||
|
|
761c93541b | ||
|
|
9d73267f8b | ||
|
|
a6a38ef099 | ||
|
|
c997a099dc | ||
|
|
46044e21fc | ||
|
|
04648a7ac6 | ||
|
|
babbb28d07 | ||
|
|
64a98b4712 | ||
|
|
6291f35dca | ||
|
|
fcf81210fe | ||
|
|
89271cd829 | ||
|
|
1f8810ad22 | ||
|
|
034961e472 | ||
|
|
831175383f | ||
|
|
17788948fd | ||
|
|
05a6149cd1 | ||
|
|
56c72397c1 | ||
|
|
48df62ac7b | ||
|
|
1da5d7aab5 | ||
|
|
143a3f1996 | ||
|
|
9857d683cf | ||
|
|
a184ca666e | ||
|
|
61b86011cc | ||
|
|
fac5ed82bb | ||
|
|
5e5d0b4308 | ||
|
|
67dab486e3 | ||
|
|
7ed3cc17a1 | ||
|
|
d94bdc362d | ||
|
|
67ba57b994 | ||
|
|
e326cf1f55 | ||
|
|
9410f2586a | ||
|
|
8a06fa7b2c | ||
|
|
d40905e60b | ||
|
|
5a850b066a | ||
|
|
dff04e7289 | ||
|
|
a053a01777 | ||
|
|
c90615b313 | ||
|
|
8134ef2516 | ||
|
|
b3b85f65fd | ||
|
|
c71a44d7f1 | ||
|
|
d671d5fc8b | ||
|
|
a6dfe82012 | ||
|
|
202ff931bd | ||
|
|
a8e6cb1710 | ||
|
|
4e8670dcfa | ||
|
|
8c3735fd6e | ||
|
|
f4f7963fff | ||
|
|
6e5de10982 | ||
|
|
427f890aa1 | ||
|
|
3607bc86e9 | ||
|
|
d7dc92ff4a | ||
|
|
19453c366a | ||
|
|
8779b59856 | ||
|
|
00afdc8f0a | ||
|
|
f84c90dbf7 | ||
|
|
f06cc9b112 | ||
|
|
eb1f4a4a4e | ||
|
|
72485b4ab9 | ||
|
|
9f3b8d7416 | ||
|
|
a6f4458327 | ||
|
|
492a64ffb4 | ||
|
|
58bf9d0050 | ||
|
|
3dbf097447 | ||
|
|
def72781e7 | ||
|
|
ae749f9b25 | ||
|
|
4a7a8b204f | ||
|
|
b29694352d | ||
|
|
15bdd4951d | ||
|
|
7b949beaac | ||
|
|
cf84815c54 | ||
|
|
698fd5f5f2 | ||
|
|
f0a3cf91ad | ||
|
|
f106c220e3 | ||
|
|
8502f94796 | ||
|
|
61e30c8dbe | ||
|
|
4a138c52a6 | ||
|
|
2ef7f2a91d | ||
|
|
4d16c8c2cc | ||
|
|
63649d631f | ||
|
|
87c0493629 | ||
|
|
09d107514b | ||
|
|
8cf11b7167 | ||
|
|
0c7c690af1 | ||
|
|
499dcfb026 | ||
|
|
cf2e255253 | ||
|
|
446facac7e | ||
|
|
bf8bd66b85 | ||
|
|
db814b24de | ||
|
|
5c309c0321 | ||
|
|
0e2c0cb3b5 | ||
|
|
5b1fc1317d | ||
|
|
dc1d009dad | ||
|
|
dcfa2eeada | ||
|
|
4b5d7459f4 | ||
|
|
5da70389cc | ||
|
|
c4b6b382ad | ||
|
|
f8b0290497 | ||
|
|
c4d579a301 | ||
|
|
f05c9703c5 | ||
|
|
966a94483a | ||
|
|
8f1ef4dc7e | ||
|
|
67d29e2a89 | ||
|
|
d9f873a399 | ||
|
|
55afb5b471 | ||
|
|
f8cfb45fa2 | ||
|
|
4875195a90 | ||
|
|
3d6b1c9b7c | ||
|
|
999e1c895e | ||
|
|
ecb6a02a46 | ||
|
|
a0c42b0053 | ||
|
|
c429617241 | ||
|
|
38de1f36f2 | ||
|
|
c46a1c7e26 | ||
|
|
7e63f5d911 | ||
|
|
67166d2b25 | ||
|
|
fa8967084c | ||
|
|
8ef80e4f0d | ||
|
|
645034f0af | ||
|
|
7bedfeca11 | ||
|
|
fd2bbcb344 | ||
|
|
8a31e47e7b | ||
|
|
f557e5222c | ||
|
|
5b2b5eb799 | ||
|
|
c1aa8bfa1d | ||
|
|
a5859f0077 | ||
|
|
b386c5d952 | ||
|
|
7c0874b7b3 | ||
|
|
821236713c | ||
|
|
d0ed71cf8f | ||
|
|
a02e127a42 | ||
|
|
43f1e688e1 | ||
|
|
ec853d63f1 | ||
|
|
43b3e253b6 | ||
|
|
abed0e85dd | ||
|
|
3398d39e11 | ||
|
|
510f9f14b1 | ||
|
|
3c8104554a | ||
|
|
ce55f3db03 | ||
|
|
5da77df064 | ||
|
|
f3c3b00367 | ||
|
|
32398ece08 | ||
|
|
bf3eda9a10 | ||
|
|
4de7b17f57 | ||
|
|
8165380828 | ||
|
|
11465a2190 | ||
|
|
dc27ac30e9 | ||
|
|
478b4025a7 | ||
|
|
037da98f84 | ||
|
|
5dadee4a3a | ||
|
|
aea786945f | ||
|
|
fb93f70776 | ||
|
|
d5acaec0ba | ||
|
|
cbd022aed3 | ||
|
|
80617aada2 | ||
|
|
bd62cf7b8b | ||
|
|
3241623df2 | ||
|
|
3b89905b0b | ||
|
|
b929880b7a | ||
|
|
f5ea57d30c | ||
|
|
42a386c38a | ||
|
|
faf2742b68 | ||
|
|
c227b0ec34 | ||
|
|
0a767cef46 | ||
|
|
e37efe0ce0 | ||
|
|
b5b797bab5 | ||
|
|
dbdb0601f3 | ||
|
|
fbd6a41acf | ||
|
|
21fe0d1b25 | ||
|
|
2bafd745b7 | ||
|
|
8eaef01fb7 | ||
|
|
58bbec13fe | ||
|
|
6bd1423e57 | ||
|
|
2e92a69c4d | ||
|
|
e67d711db3 | ||
|
|
9900189039 | ||
|
|
0a30b0b091 | ||
|
|
a480902ce6 | ||
|
|
7c413fa9b2 | ||
|
|
35e1dd482e | ||
|
|
4da06c2b26 | ||
|
|
9f0f41554b | ||
|
|
546e3dd993 | ||
|
|
4d1368ea62 | ||
|
|
f40382b6d1 | ||
|
|
b3ec72ac6c | ||
|
|
a9aa0c32e8 | ||
|
|
4780045b21 | ||
|
|
6294795ab5 | ||
|
|
8911edde23 | ||
|
|
b6b3266a3e | ||
|
|
2d75d69b1e | ||
|
|
3dad000a72 | ||
|
|
5e5fc139de | ||
|
|
6db56c17a7 | ||
|
|
f831af9f88 | ||
|
|
c181c821c1 | ||
|
|
8962d5c1ad | ||
|
|
71ca1ebd4b | ||
|
|
1bfcccaaec | ||
|
|
1ed3d03e5b | ||
|
|
b14c36ce16 | ||
|
|
fe10a5870c | ||
|
|
3c8988afe2 | ||
|
|
3e7057e189 | ||
|
|
b10bc5209c | ||
|
|
49a2d392ad | ||
|
|
8f4c2a21b9 | ||
|
|
ab3bece353 | ||
|
|
e84081c42c | ||
|
|
d50b295bc7 | ||
|
|
725b1eea0c | ||
|
|
2785af1829 | ||
|
|
723fbdce2a | ||
|
|
31a3290a7b | ||
|
|
27ab36b3ce | ||
|
|
94f5713f89 | ||
|
|
4675ebf883 | ||
|
|
5478611712 | ||
|
|
395bc26bb1 | ||
|
|
df0ac93042 | ||
|
|
1a616bc084 | ||
|
|
e6f0c7f004 | ||
|
|
10f1ffbe4e | ||
|
|
ae5f41df8c | ||
|
|
026cabbc16 | ||
|
|
e960e95e06 | ||
|
|
d80c3c6092 | ||
|
|
28d917645d | ||
|
|
f4c15159d1 | ||
|
|
826fb5f4dd | ||
|
|
6c338a5dd4 | ||
|
|
6aa4d5a6d8 | ||
|
|
abd55bd413 | ||
|
|
a1d439104e | ||
|
|
087165af50 | ||
|
|
d0daec7694 | ||
|
|
de2eff8ce6 | ||
|
|
195a1d460d | ||
|
|
a7f9c41667 | ||
|
|
eed93b27b4 | ||
|
|
92853d3f5e | ||
|
|
47c52e3ef7 | ||
|
|
4c4240e3c8 | ||
|
|
2d35cdc95a | ||
|
|
30f28a4941 | ||
|
|
b1d93bb65f | ||
|
|
8f0f4e7106 | ||
|
|
45a1f53627 | ||
|
|
f3e003dfd6 | ||
|
|
ace4a8314b | ||
|
|
780a912b57 | ||
|
|
ad0040260e | ||
|
|
34631c0668 | ||
|
|
d4ee80b802 | ||
|
|
efd0842832 | ||
|
|
78c9c2a40c | ||
|
|
746927e826 | ||
|
|
1089e784db | ||
|
|
bfd7c20187 | ||
|
|
c955e7016c | ||
|
|
0ead6bdffb | ||
|
|
352c573251 | ||
|
|
4b20cd2dee | ||
|
|
d7b59ba7e1 | ||
|
|
d79cb21929 | ||
|
|
4db6925d38 | ||
|
|
30047204e1 | ||
|
|
76154527ef | ||
|
|
8879a71b51 | ||
|
|
a3dac13b53 | ||
|
|
5c8e207a57 | ||
|
|
8aae62c071 | ||
|
|
84f60ce32f | ||
|
|
64c1ae7656 | ||
|
|
ca3fbd9a89 | ||
|
|
a54d30684d | ||
|
|
cd21fd3e73 | ||
|
|
2d4edcfc21 | ||
|
|
2611a72508 | ||
|
|
c4b597c409 | ||
|
|
92dfebc1d4 | ||
|
|
0eb5036b11 | ||
|
|
52c854661a | ||
|
|
f160760526 | ||
|
|
68d5b27194 | ||
|
|
e37950d54b | ||
|
|
8f0670265b | ||
|
|
a0e2cfc6cf | ||
|
|
b0b03d00d4 | ||
|
|
66826caf94 | ||
|
|
9281f18ecb | ||
|
|
82778173bb | ||
|
|
8fe222ba4b | ||
|
|
88775a9bdb | ||
|
|
c2b9333e29 | ||
|
|
29fdd4a222 | ||
|
|
8650c0dd09 | ||
|
|
c5c1645054 | ||
|
|
4ce4dd0a3c | ||
|
|
3503c2314d | ||
|
|
9e8e1788fb | ||
|
|
d484770b2f | ||
|
|
e6cb2bf706 | ||
|
|
110c909c50 | ||
|
|
ee58c2b938 | ||
|
|
5160f82b65 | ||
|
|
9f21513075 | ||
|
|
8505c995ed | ||
|
|
5712a7e111 | ||
|
|
374a6a1ddf | ||
|
|
208e6de3e4 | ||
|
|
87231fdb1f | ||
|
|
760db2bb82 | ||
|
|
b1ffe2afde | ||
|
|
7640fe085b | ||
|
|
dd901c005d | ||
|
|
7808526ee7 | ||
|
|
c94fe15ced | ||
|
|
ce5cb61eb4 | ||
|
|
cc87206dbc | ||
|
|
708342d09b | ||
|
|
464c5d5663 | ||
|
|
60bd0b1dff | ||
|
|
40efa96ba1 | ||
|
|
fe3a637255 | ||
|
|
a8db0542d7 | ||
|
|
c2d9aa6d06 | ||
|
|
476bc5c74d | ||
|
|
1ae5558c65 | ||
|
|
8abfcb0e55 | ||
|
|
06240d2b09 | ||
|
|
d9701c366d | ||
|
|
c33eb0e6f2 | ||
|
|
5f116d6984 | ||
|
|
d84400e89b | ||
|
|
0bbb816f3f | ||
|
|
3400df5fd4 | ||
|
|
9e44eddddf | ||
|
|
4dad5e1ab2 | ||
|
|
627b4e15cb | ||
|
|
ed9ac12226 | ||
|
|
195dca851c | ||
|
|
8589cbe29a | ||
|
|
ea63a41b47 | ||
|
|
76986d7803 | ||
|
|
cbdc4a8b65 | ||
|
|
3ca0ba0f11 | ||
|
|
3d805694bc | ||
|
|
26d3d1e7a7 | ||
|
|
6ce2044471 | ||
|
|
6f99497129 | ||
|
|
ba92b068d8 | ||
|
|
18a7fead0b | ||
|
|
111e10b434 | ||
|
|
934c2b0a78 | ||
|
|
c50141a411 | ||
|
|
5c339ccdfa | ||
|
|
54f71407ad | ||
|
|
3fe0c5ab05 | ||
|
|
b86cb09212 | ||
|
|
a77aff56aa | ||
|
|
fff005a6a1 | ||
|
|
e686914023 | ||
|
|
97ab7c1204 | ||
|
|
12873f180c | ||
|
|
941641f917 | ||
|
|
797342111f | ||
|
|
199a75971f | ||
|
|
3ea9d7e23e | ||
|
|
f478cb6606 | ||
|
|
99be5be77d | ||
|
|
0b0bd5729c | ||
|
|
9e10f2b77c | ||
|
|
18d2614b13 | ||
|
|
26177d03d4 | ||
|
|
af7e1c72a4 | ||
|
|
bd65a54b2c | ||
|
|
d4c11d65e6 | ||
|
|
6bbc40ef41 | ||
|
|
26f96dd6b1 | ||
|
|
d2f1b25b67 | ||
|
|
afe315af26 | ||
|
|
c84bb0fbdc | ||
|
|
f45692df45 | ||
|
|
7bcf923c64 | ||
|
|
1ddf31185c | ||
|
|
1b290214f6 | ||
|
|
07e4320b23 | ||
|
|
433ff4476f | ||
|
|
900ff5ce83 | ||
|
|
edbf34a2e3 | ||
|
|
f55b55e406 | ||
|
|
9282baa7fa | ||
|
|
30ecf5b154 | ||
|
|
25fddf63db | ||
|
|
59d1e952d5 | ||
|
|
a6dafbff38 | ||
|
|
b3b46e6724 | ||
|
|
7291113d2f | ||
|
|
d0bc1c1508 | ||
|
|
2c5026145d | ||
|
|
729d644e8b | ||
|
|
5364c2571a | ||
|
|
f0c1efb4b1 | ||
|
|
39ff23507b | ||
|
|
f4514c087b | ||
|
|
4f5cea34b3 | ||
|
|
19e3b730db | ||
|
|
d8e4916bbc | ||
|
|
9039ece985 | ||
|
|
7ef72ab71e | ||
|
|
01248798a7 | ||
|
|
16db054fb9 | ||
|
|
fd104efd54 | ||
|
|
9f2343075a | ||
|
|
ba709d089c | ||
|
|
f2c152a3fc | ||
|
|
872d05f47a | ||
|
|
b9159b8e15 | ||
|
|
e67e0fbb82 | ||
|
|
af65ba44ab | ||
|
|
a93b78de4f | ||
|
|
585b2fcf85 | ||
|
|
fa608965ba | ||
|
|
fee4c0c28f | ||
|
|
63ce994265 | ||
|
|
214ced7029 | ||
|
|
fffb87b45f | ||
|
|
8099941802 | ||
|
|
5f4b48eba7 | ||
|
|
92249196a4 | ||
|
|
458b03dd0c | ||
|
|
82bfdc6c3c | ||
|
|
8d354eee32 | ||
|
|
38c5ae5e25 | ||
|
|
77625d872f | ||
|
|
091a2761cf | ||
|
|
dff68edcbb | ||
|
|
2ffc1d06cf | ||
|
|
2fe8814dce | ||
|
|
9ee83ea972 | ||
|
|
7879070993 | ||
|
|
0af394b0ed | ||
|
|
53397bcdbf | ||
|
|
36bde01ed9 | ||
|
|
0df2fcbee3 | ||
|
|
721a351708 | ||
|
|
057c45869a | ||
|
|
fa6ccb5cde | ||
|
|
1384f7495c | ||
|
|
c3be9537bd | ||
|
|
c41730e9a4 | ||
|
|
cb2aa2c46a | ||
|
|
dcbe39d228 | ||
|
|
edf03dbb5d | ||
|
|
f2508c5823 | ||
|
|
66fad244d9 | ||
|
|
fcb6bbf956 | ||
|
|
41dc57f1ac | ||
|
|
0c484a0092 | ||
|
|
610631133a | ||
|
|
7f2d6942dc | ||
|
|
f1d34435e5 | ||
|
|
ecc1500d50 | ||
|
|
22fe4f6373 | ||
|
|
2f21766b4f | ||
|
|
6fe2cafabb | ||
|
|
975e4599d1 | ||
|
|
071666f0fe | ||
|
|
7940cffc3c | ||
|
|
93b1a3a69d | ||
|
|
4c8c8d5ab8 | ||
|
|
aa426ef1da | ||
|
|
0563fbe718 | ||
|
|
a61fd5656e | ||
|
|
4718b60941 | ||
|
|
61f8d7fea4 | ||
|
|
af674d4324 | ||
|
|
905db58f57 | ||
|
|
b16720420d | ||
|
|
74f84fe07b | ||
|
|
cdd570fae0 | ||
|
|
65b407e744 | ||
|
|
37f54ace01 | ||
|
|
77fbf07625 | ||
|
|
7bcc4469cc | ||
|
|
9f485e897a | ||
|
|
5274499468 | ||
|
|
99ac6ffbad | ||
|
|
192e143b5c | ||
|
|
6fc8928032 | ||
|
|
d06b22878c | ||
|
|
117153324f | ||
|
|
505b41fbd6 | ||
|
|
8c21b368bd | ||
|
|
961993ae2b | ||
|
|
047279fe16 | ||
|
|
ebce7fab92 | ||
|
|
8975cdf0f6 | ||
|
|
39170c953c | ||
|
|
b6e200f635 | ||
|
|
a183f874b4 | ||
|
|
f3be7e21c9 | ||
|
|
920847b105 | ||
|
|
e3aef2c7f2 | ||
|
|
2fb2334e1d | ||
|
|
31935a80b9 | ||
|
|
e303901262 | ||
|
|
5883f4123e | ||
|
|
38b46442aa | ||
|
|
93faabe2f5 | ||
|
|
f9b623b538 | ||
|
|
22113c33ed | ||
|
|
55a0e44d79 | ||
|
|
66093030c2 | ||
|
|
4d30281c5b | ||
|
|
b9d07f88c8 | ||
|
|
fcc4518cb1 | ||
|
|
8fee098a0a | ||
|
|
29c6d31eca | ||
|
|
914f1bc4fd | ||
|
|
22e6340ba9 | ||
|
|
1552fa3ba9 | ||
|
|
7dbc4146a5 | ||
|
|
dd4e0e1260 | ||
|
|
e4398f80df | ||
|
|
ac0ca2966a | ||
|
|
66fd58a69d | ||
|
|
9d3378bc93 | ||
|
|
ff72b0f104 | ||
|
|
813f299ad1 | ||
|
|
5ff593ee0a | ||
|
|
2237b065c3 | ||
|
|
7a667e6f2b | ||
|
|
04e043cf9d | ||
|
|
6ce01389c8 | ||
|
|
15555a9304 | ||
|
|
375574a901 | ||
|
|
7cc8089813 | ||
|
|
26aa5377c5 | ||
|
|
7a3e6ceb8f | ||
|
|
57ceab5d13 | ||
|
|
27445b1bba | ||
|
|
a0f8e79c85 | ||
|
|
e86d35858c | ||
|
|
3031392f89 | ||
|
|
c79fc16b0a | ||
|
|
252ead5945 | ||
|
|
0d7f0ad424 | ||
|
|
22d951a7b2 | ||
|
|
3feed4ee0f | ||
|
|
cbdbae2c57 | ||
|
|
c58c7140d0 | ||
|
|
f0aa42b8f3 | ||
|
|
05e92437c8 | ||
|
|
eda06af5c4 | ||
|
|
5d8cdf3bb6 | ||
|
|
e98d1babd2 | ||
|
|
7a87dd25d2 | ||
|
|
7bcee2b1b6 | ||
|
|
57a9d329ba | ||
|
|
8936a026df | ||
|
|
727d05f861 | ||
|
|
d6201819c1 | ||
|
|
e1a89b5d78 | ||
|
|
b15eca92a4 | ||
|
|
08a7208cc4 | ||
|
|
9c0019087b | ||
|
|
349a869311 | ||
|
|
02d6343d8e | ||
|
|
3880e8bc0f | ||
|
|
570c6cf82c | ||
|
|
1a7e06f480 | ||
|
|
70aa2ef31e | ||
|
|
a251149452 | ||
|
|
9d1e81b492 | ||
|
|
4ac2f5a134 | ||
|
|
c6b293d4bd | ||
|
|
2e7adce3db | ||
|
|
30965d9bdf | ||
|
|
19e82479e4 | ||
|
|
6d7492cebe | ||
|
|
6f5d6c6ee7 | ||
|
|
e887776b57 | ||
|
|
6f1b930a54 | ||
|
|
6618bc07cb | ||
|
|
9fefb8fe7e | ||
|
|
1b70874b25 | ||
|
|
54f35593d3 | ||
|
|
d2244a049c | ||
|
|
a64d93f2e6 | ||
|
|
1188f2532e | ||
|
|
f32f109095 | ||
|
|
f20a2d8146 | ||
|
|
d6ca31c7b1 | ||
|
|
adac56a1c1 | ||
|
|
f01a37a883 | ||
|
|
3c7983bf65 | ||
|
|
c0a7716606 | ||
|
|
04b2f02a13 | ||
|
|
47c22cb822 | ||
|
|
c01c66c8ca | ||
|
|
00bd53dd3a | ||
|
|
d9ba2bc1c5 | ||
|
|
8790f07496 | ||
|
|
7381b11f0f | ||
|
|
5b668855f3 | ||
|
|
7c187894b3 | ||
|
|
6818260611 | ||
|
|
0f96320a9b | ||
|
|
73bfdcb4c3 | ||
|
|
835502ba9f | ||
|
|
6f395305bf | ||
|
|
6a70b457de | ||
|
|
82d8c9a826 | ||
|
|
1c884e1b1b | ||
|
|
da306f69ea | ||
|
|
fd7897694c | ||
|
|
0eddd90703 | ||
|
|
0da9b78a13 | ||
|
|
3c44b2580d | ||
|
|
82b11cd362 | ||
|
|
0369ac26db | ||
|
|
1f17f126d0 | ||
|
|
cb60468d0e | ||
|
|
05d923b924 | ||
|
|
f52201095f | ||
|
|
cbc608e3dd | ||
|
|
845019c1c3 | ||
|
|
c5fa3901e1 | ||
|
|
769e12aac1 | ||
|
|
40f8cf4984 | ||
|
|
916129957e | ||
|
|
5086a196f8 | ||
|
|
28a466a5d4 | ||
|
|
4370c8d923 | ||
|
|
85b51faa89 | ||
|
|
f71db402d3 | ||
|
|
ce01784c46 | ||
|
|
502239ac2e | ||
|
|
397cde8383 | ||
|
|
164203adab | ||
|
|
829f03e68c | ||
|
|
c228161701 | ||
|
|
9fa1d90c15 | ||
|
|
9fa78fa280 | ||
|
|
864dca4525 | ||
|
|
0e9ef44843 | ||
|
|
86eaa9178e | ||
|
|
01a10159ff | ||
|
|
58e8f0fd71 | ||
|
|
016eb5a75c | ||
|
|
e78cc0cbe5 | ||
|
|
f1f928dd39 | ||
|
|
0c403ae92b | ||
|
|
6f66cc7503 | ||
|
|
1365cea288 | ||
|
|
be19bc7005 | ||
|
|
f47e6c9acb | ||
|
|
3982ed8b04 | ||
|
|
0a50030333 | ||
|
|
4ec69ad495 | ||
|
|
b3cd8f7a88 | ||
|
|
6b873efacf | ||
|
|
2c16718a9c | ||
|
|
01c843cde1 | ||
|
|
4922c3cb2b | ||
|
|
bb6a28867e | ||
|
|
741680265a | ||
|
|
efcec7ac90 | ||
|
|
aae44c489e | ||
|
|
70e733a7b5 | ||
|
|
39c459c04c | ||
|
|
94f7cb748d | ||
|
|
6803ec7670 | ||
|
|
815bee9dcc | ||
|
|
3884316d22 | ||
|
|
4106c48877 | ||
|
|
dfd9282d01 | ||
|
|
5c32b8e240 | ||
|
|
3cd4954d6c | ||
|
|
2503ee1947 | ||
|
|
09cf11a5fc | ||
|
|
e98949990a | ||
|
|
5f78476130 | ||
|
|
3c424b63ff | ||
|
|
745a22a8e2 | ||
|
|
6b96dfe939 | ||
|
|
fd76ce7ac1 | ||
|
|
d98b1ae982 | ||
|
|
8a9e591316 | ||
|
|
2a8c3cd45f | ||
|
|
8c400f9168 | ||
|
|
3dbc129e46 | ||
|
|
99fc7cf835 | ||
|
|
54e7daea44 | ||
|
|
aa39a450e4 | ||
|
|
89a564c2dd | ||
|
|
c80ef26ad5 | ||
|
|
512e30a84b | ||
|
|
2491c8e906 | ||
|
|
1df841804a | ||
|
|
fe66924093 | ||
|
|
3f9b98d32c | ||
|
|
aecc216dc1 | ||
|
|
165df7ee8a | ||
|
|
c6839f602a | ||
|
|
5fd231cf2f | ||
|
|
a634abfbef | ||
|
|
31a496e6b3 | ||
|
|
ea52e27e77 | ||
|
|
18edb3aebc | ||
|
|
cce0956e6e | ||
|
|
a41dac0467 | ||
|
|
4a8896a16c | ||
|
|
bec0762630 | ||
|
|
20a6f55368 | ||
|
|
71a0c5e638 | ||
|
|
df0324f904 | ||
|
|
b8e464e299 | ||
|
|
c8cb33b723 | ||
|
|
5acedc6aac | ||
|
|
40b6043eed | ||
|
|
724b52c538 | ||
|
|
8b89646069 | ||
|
|
57564bcc1c | ||
|
|
f7d5efd4ae | ||
|
|
f29d9e15c8 | ||
|
|
a4c6fc3175 | ||
|
|
41ca00537a | ||
|
|
b571982b11 | ||
|
|
7d31bbe3d0 | ||
|
|
76af1c2d14 | ||
|
|
9a68f2ec8a | ||
|
|
f1e49518e9 | ||
|
|
ae4e5e3e78 | ||
|
|
2cd8f476b6 | ||
|
|
badf483642 | ||
|
|
2af7808ccc | ||
|
|
cb6cf2e19f | ||
|
|
2ea4771df4 | ||
|
|
567a0ba434 | ||
|
|
5374862df7 | ||
|
|
6a5d923739 | ||
|
|
fb6fee0ae2 | ||
|
|
a90dfd3037 | ||
|
|
9654b024b2 | ||
|
|
14abe686a4 | ||
|
|
d1a7c2fd17 | ||
|
|
de30d29b53 | ||
|
|
2645898031 | ||
|
|
d6fc0e005f | ||
|
|
ebcb526f60 | ||
|
|
2900c27c70 | ||
|
|
7a85950d29 | ||
|
|
e98fd640fa | ||
|
|
0ad5cc6fd3 | ||
|
|
312f09a06e | ||
|
|
b007cd13df | ||
|
|
ab6624266c | ||
|
|
01bec4be03 | ||
|
|
69371730b2 | ||
|
|
f04f01bdba | ||
|
|
52f1b5d0ed | ||
|
|
7f44ee66fd | ||
|
|
407d8d4baa | ||
|
|
8440693bbd | ||
|
|
dc1bfcb1bb | ||
|
|
9c0f4324da | ||
|
|
22855cf70e | ||
|
|
bd5de25e4b | ||
|
|
e6d8b3c6c8 | ||
|
|
e91b292d8b | ||
|
|
a558bbdfe5 | ||
|
|
9781699c2b | ||
|
|
2e48b7c427 | ||
|
|
fe9df9d2c5 | ||
|
|
07569481f1 | ||
|
|
ac52cd0d59 | ||
|
|
c452f12eb9 | ||
|
|
571babf236 | ||
|
|
296de1c452 | ||
|
|
394917d3ff | ||
|
|
20fc23d183 | ||
|
|
af9f54b06a | ||
|
|
d66067c1f1 | ||
|
|
f8e1535a52 | ||
|
|
4f10fa559a | ||
|
|
eb769a93a1 | ||
|
|
b1cbf09a50 | ||
|
|
b7a1d77fc1 | ||
|
|
3f4a61090f | ||
|
|
c2d156cc16 | ||
|
|
6a472a0092 | ||
|
|
e71a1f5d69 | ||
|
|
13f0c0ba15 | ||
|
|
5b88c90de0 | ||
|
|
05e9e882f0 | ||
|
|
196c1b112e | ||
|
|
0568882c64 | ||
|
|
aff3830463 | ||
|
|
f701080b71 | ||
|
|
92c9a5c1c2 | ||
|
|
b26d8f71f6 | ||
|
|
bce382fcc1 | ||
|
|
e2ca682872 | ||
|
|
b148035c40 | ||
|
|
7a9acdb7c1 | ||
|
|
8d8bb29f13 | ||
|
|
602b4f06ef | ||
|
|
2d45ddf2be | ||
|
|
d37554d317 | ||
|
|
e95360fc81 | ||
|
|
be95736987 | ||
|
|
b4d98ab335 | ||
|
|
979128036c | ||
|
|
3dcf5d23c4 | ||
|
|
a74a7c7b1d | ||
|
|
d982651545 | ||
|
|
664c0e7751 | ||
|
|
18ad905525 | ||
|
|
769fa6b534 | ||
|
|
8a06bea864 | ||
|
|
0c55497fb3 | ||
|
|
636e396303 | ||
|
|
3c0a4c9372 | ||
|
|
e7b02865fc | ||
|
|
99b451ac8e | ||
|
|
145c1bb2d2 | ||
|
|
33d69091f8 | ||
|
|
48fa10a21b | ||
|
|
6e0c8efbf4 | ||
|
|
db27bfd8f2 | ||
|
|
2a43a20531 | ||
|
|
958c7107ce | ||
|
|
d734a5063c | ||
|
|
9ca98d43ee | ||
|
|
211d3f9ac7 | ||
|
|
b5e1cfb4fa | ||
|
|
72cff8560b | ||
|
|
1caf337e60 | ||
|
|
b279d2ef2b | ||
|
|
2fec5f513e | ||
|
|
65cca6165c | ||
|
|
75c1c0d478 | ||
|
|
9d4ef66fa5 | ||
|
|
80adcac8b8 | ||
|
|
69aca8781d | ||
|
|
4a8944cc83 | ||
|
|
0297cb2187 | ||
|
|
69131b57f7 | ||
|
|
9c700ae28f | ||
|
|
b90376286c | ||
|
|
b3992b98a9 | ||
|
|
4baae80558 | ||
|
|
fda3bf95f1 | ||
|
|
9e54a0e47e | ||
|
|
c14ad320e3 | ||
|
|
e544551627 | ||
|
|
ba6160f7e2 | ||
|
|
9e4ebbf29d | ||
|
|
5c02f3702b | ||
|
|
01ff6c00be | ||
|
|
b45557e366 | ||
|
|
8b5e387806 | ||
|
|
2296fe413b | ||
|
|
6135040b52 | ||
|
|
158e3ae50e | ||
|
|
5e29b75f20 | ||
|
|
c77259734a | ||
|
|
775eba0b0b | ||
|
|
de8c4a6fc7 | ||
|
|
a792483409 | ||
|
|
271b24ade6 | ||
|
|
185f4174d8 | ||
|
|
dc0d258b3f | ||
|
|
d6800add0c | ||
|
|
952e264949 | ||
|
|
0a832e3c4b | ||
|
|
15c1d01b29 | ||
|
|
555cd377ac | ||
|
|
b4178e1e49 | ||
|
|
31aba06df6 | ||
|
|
6e8e9dfe52 | ||
|
|
91441487ed | ||
|
|
faa7a42ed1 | ||
|
|
41c95db700 | ||
|
|
408eb40cc9 | ||
|
|
ac4811c507 | ||
|
|
a53adf001f | ||
|
|
23ae3efec1 | ||
|
|
25900aab78 | ||
|
|
58b712cda4 | ||
|
|
6a53c29da5 | ||
|
|
a7ab45c070 | ||
|
|
e7c90dbe7e | ||
|
|
cd8aef1c06 | ||
|
|
55b6b0c94a | ||
|
|
d74989f048 | ||
|
|
5b458e177d | ||
|
|
a03563f3ed | ||
|
|
32f80734fb | ||
|
|
4d62b19ebe | ||
|
|
7ddfd8d394 | ||
|
|
f1231284d6 | ||
|
|
f8d5828960 | ||
|
|
4bba3674f6 | ||
|
|
392411fbbc | ||
|
|
920484cbd6 | ||
|
|
0f3ca3bc4e | ||
|
|
c31eb17b14 | ||
|
|
252752e5d4 | ||
|
|
42e76152b6 | ||
|
|
f31c158bf3 | ||
|
|
5b10416a14 | ||
|
|
661c393ab3 | ||
|
|
a533a2c845 | ||
|
|
9b0130e3a7 | ||
|
|
18406063a9 | ||
|
|
04fe86fe28 | ||
|
|
143f583ea5 | ||
|
|
75bf4c48a2 | ||
|
|
6c09a8a464 | ||
|
|
85fefcb74b | ||
|
|
f56d427d0d | ||
|
|
5d6a962a36 | ||
|
|
9d4bd598f8 | ||
|
|
f557ad2d86 | ||
|
|
ff40e53f99 | ||
|
|
a084f65663 | ||
|
|
aa73246705 | ||
|
|
e40058b688 | ||
|
|
44f563d94e | ||
|
|
6da2c9de38 | ||
|
|
0ec0d2444c | ||
|
|
bd925ea426 | ||
|
|
8ea705ba54 | ||
|
|
b7327e5613 | ||
|
|
2dd0c6dfe1 | ||
|
|
11df20b022 | ||
|
|
2226b3733b | ||
|
|
ad69011405 | ||
|
|
f091321ac7 | ||
|
|
ca29a77dd2 | ||
|
|
bfbb21228e | ||
|
|
f18f98f3ea | ||
|
|
354db2f937 | ||
|
|
3a52cbb083 | ||
|
|
37ec666235 | ||
|
|
a8bad5b96f | ||
|
|
f01a900c3d | ||
|
|
cab34aa178 | ||
|
|
c685f3c081 | ||
|
|
75840e02a4 | ||
|
|
40412844ed | ||
|
|
565fb6fcb2 | ||
|
|
dde67c0626 | ||
|
|
ff312a5b1d | ||
|
|
afcfd6caa8 | ||
|
|
41e5b2665a | ||
|
|
7d8e50d5c8 | ||
|
|
327d38f356 | ||
|
|
e0e4385e35 | ||
|
|
ec9ef47eb6 | ||
|
|
b8e09562b1 | ||
|
|
8d0b8d17a0 | ||
|
|
befcbf25c8 | ||
|
|
b818df0599 | ||
|
|
ac37668cd6 | ||
|
|
bace1def3d | ||
|
|
9715c28362 | ||
|
|
0d2fb84436 | ||
|
|
2e729a3394 | ||
|
|
ac8957511b | ||
|
|
f4adb2fab0 | ||
|
|
97ae55bc1f | ||
|
|
9ab95599ab | ||
|
|
b967fbd71a | ||
|
|
eca0aeb263 | ||
|
|
7f56764456 | ||
|
|
bdfc9cf3c7 | ||
|
|
3f27a09ffa | ||
|
|
0de774d55e | ||
|
|
58eceb751a | ||
|
|
27e24ee0be | ||
|
|
65710e72bb | ||
|
|
b73b7e9c61 | ||
|
|
4b5e0d70b8 | ||
|
|
3ffcd119f7 | ||
|
|
12134cff51 | ||
|
|
55634c2b4d | ||
|
|
ca9913726e | ||
|
|
662527611f | ||
|
|
d0666073b6 | ||
|
|
decf828911 | ||
|
|
8903d4553a | ||
|
|
281af87870 | ||
|
|
bbf3cc1c6c | ||
|
|
22dc407215 | ||
|
|
a86910bc6e | ||
|
|
ad0161d8e7 | ||
|
|
ed9d612e23 | ||
|
|
fb6a398380 | ||
|
|
77c480cf89 | ||
|
|
c09b2a01d5 | ||
|
|
2aea462902 | ||
|
|
d4d686b9d1 | ||
|
|
74c4e9613b | ||
|
|
c3eb1db619 | ||
|
|
3e51259802 | ||
|
|
16622b5649 | ||
|
|
b82cf2a0e1 | ||
|
|
252ea72212 | ||
|
|
06839ecf21 | ||
|
|
446f80d5fd | ||
|
|
4f1f6fb229 | ||
|
|
6734034782 | ||
|
|
f18e443338 | ||
|
|
41857e98ac | ||
|
|
8f7cd4fbcc | ||
|
|
8a28963138 | ||
|
|
75b7d3d79a | ||
|
|
27ad71a856 | ||
|
|
b5e65c4086 | ||
|
|
a4e1dde375 | ||
|
|
a22e8fa0d5 | ||
|
|
6328209ffc | ||
|
|
4de93ae3b4 | ||
|
|
d3bc288558 | ||
|
|
742281f807 | ||
|
|
d6146ef600 | ||
|
|
a3b633f510 | ||
|
|
296fedb89d | ||
|
|
89cad98a82 | ||
|
|
4499445db6 | ||
|
|
76484f4b95 | ||
|
|
4cbe34c08c | ||
|
|
945a087f1b | ||
|
|
56e73bf7ad | ||
|
|
1013f2b29c | ||
|
|
1020513f13 | ||
|
|
2fee0695a1 | ||
|
|
5d2c90bbab | ||
|
|
4f5b1e65aa | ||
|
|
57b048cba0 | ||
|
|
454d77a0df | ||
|
|
309a75a7c8 | ||
|
|
a0a34eb431 | ||
|
|
1c60cc9403 | ||
|
|
f1ba40f33a | ||
|
|
1e406154d3 | ||
|
|
01b59534fe | ||
|
|
73be1b2646 | ||
|
|
34abb465d2 | ||
|
|
f22eb9a004 | ||
|
|
42255fa183 | ||
|
|
17ac94b44a | ||
|
|
a744f90b35 | ||
|
|
1f4bd475ef | ||
|
|
60bd2ad03d | ||
|
|
929408e1e5 | ||
|
|
dd7ba62505 | ||
|
|
cb9edd72d6 | ||
|
|
94dca3d6c4 | ||
|
|
f7add33031 | ||
|
|
b33e9f8b85 | ||
|
|
f2fd618255 | ||
|
|
f8d2ac641e | ||
|
|
9d8f35581c | ||
|
|
a6300e7163 | ||
|
|
bba329a41c | ||
|
|
0014d989a0 | ||
|
|
2765b66115 | ||
|
|
ae2b788a65 | ||
|
|
087bd470ec | ||
|
|
a8e0988970 | ||
|
|
18b60f9fa2 | ||
|
|
ef4c0d20e5 | ||
|
|
a9046bb89a | ||
|
|
1a611ae18e | ||
|
|
31df5592bf | ||
|
|
11150f2eea | ||
|
|
1d2510f465 | ||
|
|
53df0f957c | ||
|
|
d6c3c2b130 | ||
|
|
539311d192 | ||
|
|
52b742f503 | ||
|
|
83674cf6bb | ||
|
|
63dd7c0fd7 | ||
|
|
99f1cbd934 | ||
|
|
f29d742a49 | ||
|
|
41d5eba0bb | ||
|
|
390288d0f4 | ||
|
|
ee39c87bf7 | ||
|
|
bd4861e4c1 | ||
|
|
115cd0b4ae | ||
|
|
ce8be993fe | ||
|
|
c857a9af4d | ||
|
|
f692f1eca2 | ||
|
|
2fd57b9404 | ||
|
|
585d896cc3 | ||
|
|
2cd746f1d1 | ||
|
|
8b56199ce7 | ||
|
|
cd09934080 | ||
|
|
4a7895b0e2 | ||
|
|
4253d7eb8e | ||
|
|
cee0a1112f | ||
|
|
053467032d | ||
|
|
a7b261a734 | ||
|
|
816c6505d7 | ||
|
|
17d08ef94c | ||
|
|
009a1a98df | ||
|
|
abf728c500 | ||
|
|
9ec03075eb | ||
|
|
9b5a92d113 | ||
|
|
75b9400571 | ||
|
|
d141f4a908 | ||
|
|
5370e51f8a | ||
|
|
ef9f3c6517 | ||
|
|
8756b51ab8 | ||
|
|
b355aa642c | ||
|
|
27f4a48e92 | ||
|
|
18182ea5a1 | ||
|
|
6ec6c4a73e | ||
|
|
ac46ebb348 | ||
|
|
aa1f45e10a | ||
|
|
5e51bfaaa4 | ||
|
|
14578a575e | ||
|
|
298c5b9f8a | ||
|
|
e93f2d9d42 | ||
|
|
6e7d0dd8b2 | ||
|
|
b89ab13f2d | ||
|
|
196daf7860 | ||
|
|
c39483fb3e | ||
|
|
720a36c8de | ||
|
|
f48f191273 | ||
|
|
3b3a728b7d | ||
|
|
d42606f99a | ||
|
|
14da3b1a52 | ||
|
|
4a33e17110 | ||
|
|
bdee85e334 | ||
|
|
376034d4c4 | ||
|
|
d8a9b2df48 | ||
|
|
bba21ea9f4 | ||
|
|
0dc5f5d7b2 | ||
|
|
5ad75b217f | ||
|
|
4ae1b1ec2e | ||
|
|
72269da46f | ||
|
|
37cfd3fd46 | ||
|
|
5c8af74966 | ||
|
|
de1035eb08 | ||
|
|
563e15136c | ||
|
|
49bc304960 | ||
|
|
ca7d06b6a6 | ||
|
|
1553352c88 | ||
|
|
87deb83ed5 | ||
|
|
3bff647de9 | ||
|
|
d826f0b095 | ||
|
|
49f6fd00d8 | ||
|
|
a0c77542ea | ||
|
|
5d1211ba7a | ||
|
|
40dfe9e804 | ||
|
|
224caa595d | ||
|
|
16c8a24163 | ||
|
|
bc5c90ca47 | ||
|
|
c239b6aa04 | ||
|
|
c2dd5e8d29 | ||
|
|
302674273a | ||
|
|
f9cfba00bc | ||
|
|
1ed59569e6 | ||
|
|
a2208f04c3 | ||
|
|
242bc9a759 | ||
|
|
980b461d59 | ||
|
|
9a7399c2b9 | ||
|
|
def00addab | ||
|
|
b8767dfe76 | ||
|
|
543ed3d746 | ||
|
|
d4749cbe7a | ||
|
|
4f10eb59a9 | ||
|
|
cf3dc96e0b | ||
|
|
96072cf9b0 | ||
|
|
56ba5a5a89 | ||
|
|
0833e55c9d | ||
|
|
2f1896b7c4 | ||
|
|
b0021631b4 | ||
|
|
65779c1fec | ||
|
|
defaa13849 | ||
|
|
751679be2f | ||
|
|
f95d7e54f3 | ||
|
|
11a897c366 | ||
|
|
b711509609 | ||
|
|
a2be11dee6 | ||
|
|
7ee751973a | ||
|
|
dc8baff6d3 | ||
|
|
7204db7887 | ||
|
|
a2ba873ee0 | ||
|
|
178d7e77a2 | ||
|
|
24673e87ca | ||
|
|
48774e5853 | ||
|
|
704498ed13 | ||
|
|
75594e3e54 | ||
|
|
ffbe06071f | ||
|
|
2a23f72102 | ||
|
|
b75a945a7a | ||
|
|
ec5ab626d9 | ||
|
|
96eae682c0 | ||
|
|
a6d286d62d | ||
|
|
3964cc2769 | ||
|
|
543b247d72 | ||
|
|
92f5b6789e | ||
|
|
6e03eaebe4 | ||
|
|
b0b5796ece | ||
|
|
627d688c2d | ||
|
|
062af00b20 | ||
|
|
f59c178d65 | ||
|
|
aeab27e00c | ||
|
|
d9fed5e75f | ||
|
|
fd260eaefb | ||
|
|
6b1e4556d8 | ||
|
|
59c9757ca3 | ||
|
|
7a4fb1146e | ||
|
|
19e26af1a4 | ||
|
|
c760419680 | ||
|
|
0575dcadda | ||
|
|
ed55273d5a | ||
|
|
7c3f031e6e | ||
|
|
c83712640a | ||
|
|
2526a22e38 | ||
|
|
0dc777d02b | ||
|
|
47e0b485ab | ||
|
|
9dc6dbb4b7 | ||
|
|
c32e22ac80 | ||
|
|
931eca4fb3 | ||
|
|
ae5cc0e0a4 | ||
|
|
5fe29a09fb | ||
|
|
354750e04a | ||
|
|
b70dba7144 | ||
|
|
b1e80ec0ca | ||
|
|
0b6c9ed68b | ||
|
|
2a88c51405 | ||
|
|
fe582353bb | ||
|
|
32dfdc495c | ||
|
|
72e4300677 | ||
|
|
d21e874718 | ||
|
|
a0e5ca3656 | ||
|
|
63b12899f0 | ||
|
|
91c49e48d7 | ||
|
|
a2e9a4831a | ||
|
|
238f9e5538 | ||
|
|
35a2b6f11d | ||
|
|
947e07a1f3 | ||
|
|
5f0769868f | ||
|
|
c3650e0b9c | ||
|
|
7527cdc8c2 | ||
|
|
9d8cd07b8a | ||
|
|
dbf81a44e9 | ||
|
|
c30278f104 | ||
|
|
af0903a979 | ||
|
|
3188da1ad3 | ||
|
|
5134ae67f1 | ||
|
|
eb05a503ac | ||
|
|
6f0f5d40b0 | ||
|
|
79b0a142cf | ||
|
|
6892ecf6df | ||
|
|
fc76fd16fc | ||
|
|
0cb223e80b | ||
|
|
942a8c4106 | ||
|
|
2e10daef30 | ||
|
|
fee27b681b | ||
|
|
9e7c39103f | ||
|
|
7d15d4a1cb | ||
|
|
3ce4c2f542 | ||
|
|
f6ec0d0d96 | ||
|
|
0ed6cdb32e | ||
|
|
e39d41ec1a | ||
|
|
5464e830af | ||
|
|
e4af824c41 | ||
|
|
af161676dd | ||
|
|
62681fee0c | ||
|
|
45ae210236 | ||
|
|
0dbbbc40d3 | ||
|
|
a8dff862d2 |
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
/package-lock.json
|
||||
/lib
|
||||
.prettierrc
|
||||
/oms/dist/
|
||||
/project/*/index.js
|
||||
/project/*/dist
|
||||
6
.npmrc
Normal file
6
.npmrc
Normal file
@@ -0,0 +1,6 @@
|
||||
registry=http://192.168.1.87:4873/
|
||||
email=aixianling@sinoecare.com
|
||||
always-auth=true
|
||||
_auth="YWRtaW46YWRtaW4xMjM="
|
||||
package-lock=false
|
||||
|
||||
5
core/.npmignore
Normal file
5
core/.npmignore
Normal file
@@ -0,0 +1,5 @@
|
||||
apps/
|
||||
index.js
|
||||
*.map
|
||||
vcapps.import.js
|
||||
dist/
|
||||
288
core/apps/AppAccount/AppAccount.vue
Normal file
288
core/apps/AppAccount/AppAccount.vue
Normal file
@@ -0,0 +1,288 @@
|
||||
<template>
|
||||
<section class="AppAccount">
|
||||
<ai-list>
|
||||
<ai-title slot="title" title="账号管理" isShowBottomBorder>
|
||||
<template #rightBtn>
|
||||
<el-button size="small" type="primary" icon="iconfont iconUpdate_Files" @click="syncDept">同步部门</el-button>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template #left>
|
||||
<ai-address-book-menu :instance="instance" @select="handleSelect"/>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-title :title="tableTitle"/>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" :disabled="!ids.toString()" @click="batchAllot">功能分配</el-button>
|
||||
<el-button size="small" icon="iconfont iconUpdate_Files" @click="syncMembers">同步成员</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" placeholder="搜索姓名、手机号" v-model="search.name" clearable
|
||||
v-throttle="() => {page.current = 1, getTableData()}"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
|
||||
@getList="getTableData" :col-configs="colConfigs" :dict="dict"
|
||||
@selection-change="v=>ids=v.filter(e=>e.sysUserId).map(e=>e.sysUserId)">
|
||||
<el-table-column slot="name" label="姓名" width="180px">
|
||||
<el-row type="flex" align="middle" slot-scope="{row}">
|
||||
<el-image class="avatar" :src="row.avatar" :preview-src-list="[row.avatar]">
|
||||
<el-image slot="error" src="https://cdn.cunwuyun.cn/dvcp/h5/defaultAvatar.png" alt=""/>
|
||||
</el-image>
|
||||
<div>{{ row.name }}</div>
|
||||
</el-row>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" align="center" label="操作" fixed="right" width="160px">
|
||||
<el-row type="flex" justify="center" align="middle" slot-scope="{row}">
|
||||
<el-button v-if="$permissions('admin_sysuser_distribute')&&!!row.sysUserId"
|
||||
type="text" @click="appAllot(row)">功能分配
|
||||
</el-button>
|
||||
</el-row>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<!--功能分配-->
|
||||
<ai-dialog title="功能分配" :visible.sync="dialog" width="800px" @open="initDialogData" @onConfirm="updateAccount">
|
||||
<el-form ref="updateAccountForm" :model="dialogForm" :rules="rules" size="small"
|
||||
label-width="120px">
|
||||
<el-form-item required label="角色" prop="roleId">
|
||||
<el-select size="small" placeholder="请选择角色" :value="dialogForm.roleId" filterable
|
||||
v-model="dialogForm.roleId" clearable>
|
||||
<el-option v-for="(op,i) in accountRoles" :key="i" :label="op.name" :value="op.id"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="行政地区" prop="areaId">
|
||||
<ai-area-select v-model="dialogForm.areaId" always-show :instance="instance"
|
||||
clearable @fullname="v=>dialogForm.areaFullName=v"
|
||||
@name="v=>dialogForm.areaName=v"
|
||||
:disabledLevel="disabledLevel"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="党组织" prop="organizationId" v-if="user.info.organizationId">
|
||||
<el-cascader :options="partyOrgOps" v-model="dialogForm.organizationId"
|
||||
:props="cascaderProps" :show-all-levels="false" clearable/>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="职务" prop="position">-->
|
||||
<!-- <el-input placeholder="请输入职务" v-model="dialogForm.position" clearable/>-->
|
||||
<!-- </el-form-item>-->
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import AiAddressBookMenu from "../../components/AiAddressBookMenu";
|
||||
|
||||
export default {
|
||||
name: "AppAccount",
|
||||
components: {AiAddressBookMenu},
|
||||
label: "账号管理(村微版)",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
cascaderProps() {
|
||||
return {
|
||||
value: 'id',
|
||||
checkStrictly: true,
|
||||
emitPath: false
|
||||
}
|
||||
},
|
||||
partyOrgOps() {
|
||||
let initData = JSON.parse(JSON.stringify(this.optionsParty)),
|
||||
ops = initData.filter(e => !e.parentId)
|
||||
ops.map(e => this.addChild(e, initData))
|
||||
return ops
|
||||
},
|
||||
colConfigs() {
|
||||
return [
|
||||
{type: 'selection', align: 'center'},
|
||||
{label: "姓名", slot: "name"},
|
||||
{label: "职务", prop: "position", align: 'center', width: "120px"},
|
||||
{label: "部门", prop: "departmentNames", align: 'center', width: "120px"},
|
||||
{label: "联系方式", prop: "mobile", align: 'center', width: "120px"},
|
||||
{label: "账号状态", prop: "status", dict: "wxUserStatus", width: "120px"},
|
||||
{label: "账号角色", prop: "roleName", width: "120px", align: '120px'},
|
||||
{label: "地区", prop: "areaName", width: "120px"},
|
||||
{label: "党组织", prop: "organizationName", align: 'center', width: "120px"},
|
||||
{slot: "options"}
|
||||
]
|
||||
},
|
||||
tableTitle() {
|
||||
return this.condition ? this.condition + `(${this.page.total})` : '请选择组织或标签'
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
name: [{required: true, message: "请填写姓名"}],
|
||||
// organizationId: [{required: true, message: "请选择党组织"}],
|
||||
// unitId: [{required: true, message: "请选择单位"}],
|
||||
areaId: [{required: true, message: '请选择地区', trigger: 'change'}],
|
||||
roleId: [{required: true, message: "请选择角色"}],
|
||||
phone: [{required: true, message: "请输入手机号码"}]
|
||||
}
|
||||
},
|
||||
disabledLevel() {
|
||||
return this.user.info.areaList?.length || 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
condition: "",
|
||||
accountRoles: [],
|
||||
page: {current: 1, size: 10, total: 0},
|
||||
dialog: false,
|
||||
dialogForm: {},
|
||||
optionsParty: [],
|
||||
tableData: [],
|
||||
search: {name: ""},
|
||||
ids: [],
|
||||
lock: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTableData() {
|
||||
this.instance.post("/app/wxcp/wxuser/list", null, {
|
||||
params: {...this.page, ...this.search}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data?.records
|
||||
this.page.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSelect(v) {
|
||||
if (v.type == 0) {
|
||||
//选择部门
|
||||
let {id: departmentId, name} = v
|
||||
this.condition = name
|
||||
this.search = {departmentId}
|
||||
} else if (v.type == 1) {
|
||||
//选择标签
|
||||
let {id: tagIds, tagname: name} = v
|
||||
this.condition = name
|
||||
this.search = {tagIds}
|
||||
}
|
||||
this.page.current = 1
|
||||
this.getTableData()
|
||||
},
|
||||
initDialogData() {
|
||||
//用于优化初始化数据
|
||||
this.getAccountRoles()
|
||||
this.searchSysAll()
|
||||
},
|
||||
getAccountRoles() {
|
||||
this.accountRoles.length == 0 && this.instance.post("/admin/role-acc/list-all").then(res => {
|
||||
if (res?.data) {
|
||||
this.accountRoles = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
batchAllot() {
|
||||
this.dialog = true
|
||||
this.dialogForm = {areaId: this.user.info.areaId, sysUserIds: this.ids}
|
||||
},
|
||||
appAllot(row) {
|
||||
this.dialog = true
|
||||
this.dialogForm = JSON.parse(JSON.stringify({
|
||||
...row,
|
||||
sysUserIds: [row.sysUserId],
|
||||
areaId: row.areaId || this.user.info.areaId
|
||||
}));
|
||||
},
|
||||
// 获取党组织树形
|
||||
searchSysAll() {
|
||||
if (this.user.info.organizationId && this.optionsParty.length == 0) {
|
||||
this.instance.post('/app/partyOrganization/queryPartyOrganizationServiceList').then((res) => {
|
||||
if (res?.data) {
|
||||
res.data = res.data.map(a => {
|
||||
return {...a, label: a.name}
|
||||
});
|
||||
this.optionsParty = res.data.filter(e => !e.parentId)
|
||||
this.optionsParty.map(t => this.addChild(t, res.data));
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
// 修改
|
||||
updateAccount() {
|
||||
this.$refs.updateAccountForm.validate(v => {
|
||||
if (v) {
|
||||
if (this.lock) return this.$message.error("请勿多次提交!")
|
||||
this.lock = true
|
||||
this.instance.post("/app/wxcp/wxuser/empower", this.dialogForm).then(res => {
|
||||
this.lock = false
|
||||
if (res?.code == 0) {
|
||||
this.dialog = false;
|
||||
this.$message.success("修改成功")
|
||||
this.getTableData();
|
||||
} else {
|
||||
this.$message.error(res?.msg)
|
||||
}
|
||||
}).catch(() => {
|
||||
this.lock = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
syncMembers() {
|
||||
const {departmentId = 1} = this.search;
|
||||
let loading = this.$loading({
|
||||
text: "正在同步成员...",
|
||||
spinner: 'el-icon-loading',
|
||||
background: "rgba(0,0,0,.8)"
|
||||
})
|
||||
this.instance.post(`/app/wxcp/wxdepartment/syncUser`, null, {
|
||||
timeout: 1000000,
|
||||
params: {departmentId}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success('同步成功')
|
||||
this.getList()
|
||||
}
|
||||
}).finally(() => loading.close())
|
||||
},
|
||||
syncDept() {
|
||||
let loading = this.$loading({
|
||||
text: "正在同步部门...",
|
||||
spinner: 'el-icon-loading',
|
||||
background: "rgba(0,0,0,.8)"
|
||||
})
|
||||
this.instance.post(`/app/wxcp/wxdepartment/syncDepart`).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success('同步成功')
|
||||
this.getTree()
|
||||
}
|
||||
}).finally(() => loading.close())
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.dict.load('wxUserStatus')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAccount {
|
||||
height: 100%;
|
||||
|
||||
::v-deep .avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
::v-deep .ai-list__content--left {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
::v-deep .el-form {
|
||||
.el-cascader {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
35
core/apps/AppAccountRole/AppAccountRole.vue
Normal file
35
core/apps/AppAccountRole/AppAccountRole.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<section class="AppAccountRole">
|
||||
<add-account-role v-if="showDetail"/>
|
||||
<account-role-list v-else/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AddAccountRole from "./addAccountRole";
|
||||
import AccountRoleList from "./accountRoleList";
|
||||
|
||||
export default {
|
||||
name: "AppAccountRole",
|
||||
label: "账号角色管理",
|
||||
props: {
|
||||
instance: Function
|
||||
},
|
||||
components: {AccountRoleList, AddAccountRole},
|
||||
computed: {
|
||||
showDetail() {
|
||||
return this.$route.hash == "#add"
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
let {instance} = this
|
||||
return {instance}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAccountRole {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
372
core/apps/AppAccountRole/accountRoleList.vue
Normal file
372
core/apps/AppAccountRole/accountRoleList.vue
Normal file
@@ -0,0 +1,372 @@
|
||||
<template>
|
||||
<ai-list class="accountRoleList">
|
||||
<ai-title slot="title" title="账号角色管理" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-circle-plus"
|
||||
@click="$router.push({hash:'#add'})"
|
||||
v-if="$permissions('admin_sysaccountrole_add')"
|
||||
>添加
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="el-icon-delete"
|
||||
class="delete-btn del-btn-list"
|
||||
@click="allDelete"
|
||||
:disabled="!Boolean(multipleSelection.length)"
|
||||
v-if="$permissions('admin_sysaccountrole_del')"
|
||||
>删除
|
||||
</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
size="small"
|
||||
v-model="searchInfo"
|
||||
placeholder="角色名称"
|
||||
clearable
|
||||
@keyup.enter.native="mhSearch()"
|
||||
prefix-icon="iconfont iconSearch"
|
||||
/>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="iconfont iconSearch"
|
||||
@click="mhSearch()"
|
||||
>查询
|
||||
</el-button
|
||||
>
|
||||
<el-button
|
||||
icon="el-icon-refresh-right"
|
||||
style="padding: 8px 13.5px"
|
||||
@click="resetConditon"
|
||||
>重置
|
||||
</el-button
|
||||
>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
@selection-change="handleSelectionChange"
|
||||
header-cell-class-name="table-header"
|
||||
tooltip-effect="light"
|
||||
max-height="calc(100% - 80px)"
|
||||
row-class-name="table-row"
|
||||
cell-class-name="table-cell"
|
||||
>
|
||||
<el-table-column type="selection" width="55"/>
|
||||
<el-table-column prop="name" label="角色名" width="300"/>
|
||||
<el-table-column label="权限明细" prop="appRoleList">
|
||||
<template slot-scope="scope">
|
||||
<el-tooltip
|
||||
content="更多角色用户请点击详情按钮"
|
||||
placement="top"
|
||||
effect="light"
|
||||
v-if="scope.row.appRoleList.length > 3"
|
||||
>
|
||||
<span>{{ scope.row.appRoleListHtml }}</span>
|
||||
</el-tooltip>
|
||||
<span
|
||||
v-for="(item, index) in scope.row.appRoleList"
|
||||
:key="index"
|
||||
v-else
|
||||
>
|
||||
<span>{{ item.appName }}-</span>
|
||||
<span>{{ item.name }};</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" align="center">
|
||||
<template class="operation_icon" slot-scope="scope">
|
||||
<el-button
|
||||
type="text"
|
||||
size="small"
|
||||
@click="beforeCopy(scope.row)"
|
||||
v-if="$permissions('admin_sysaccountrole_add')"
|
||||
>复制角色
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
size="small"
|
||||
@click="detailShow(scope.row)"
|
||||
v-if="$permissions('admin_sysaccountrole_detail')"
|
||||
>详情
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
size="small"
|
||||
@click="edit(scope.row)"
|
||||
v-if="$permissions('admin_sysaccountrole_edit')"
|
||||
>编辑
|
||||
</el-button
|
||||
>
|
||||
<el-button
|
||||
type="text"
|
||||
size="small"
|
||||
@click="beforeDelete(scope.row)"
|
||||
v-if="$permissions('admin_sysaccountrole_del')"
|
||||
>删除
|
||||
</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<div slot="empty" class="no-data"></div>
|
||||
</el-table>
|
||||
<div class="pagination">
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
background
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
layout="total,prev, pager, next,sizes, jumper"
|
||||
:total="total"
|
||||
/>
|
||||
</div>
|
||||
<el-dialog
|
||||
class="editStyle"
|
||||
:visible.sync="copyDialog"
|
||||
width="520px"
|
||||
@close="dataInit()"
|
||||
title="复制角色"
|
||||
>
|
||||
<el-form :model="form" label-width="80px">
|
||||
<el-form-item
|
||||
label="角色名"
|
||||
:rules="[{ required: true, message: '', trigger: 'blur' }]"
|
||||
>
|
||||
<el-input
|
||||
v-model="roleName"
|
||||
placeholder="请输入..."
|
||||
size="small"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" style="text-align: center">
|
||||
<el-button
|
||||
style="width: 92px"
|
||||
size="small"
|
||||
class="delete-btn"
|
||||
@click="copyDialog = false"
|
||||
>取消
|
||||
</el-button
|
||||
>
|
||||
<el-button
|
||||
style="width: 92px"
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="copyFn()"
|
||||
:disabled="!Boolean(roleName)"
|
||||
>确认
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<ai-dialog title="账号角色详情" :visible.sync="viewShow" customFooter>
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="账号角色名称" :value="row.name"/>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="权限信息">
|
||||
<template #content>
|
||||
<div
|
||||
class="view_info"
|
||||
v-for="(item, index) in row.appRoleList"
|
||||
:key="index"
|
||||
>
|
||||
<i class="iconfont iconProlife" style="color: #999"/>
|
||||
{{ [item.appName, item.name].join(" / ") }}
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<template #footer>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="edit(row)"
|
||||
v-if="$permissions('admin_sysaccountrole_edit')"
|
||||
>编辑角色
|
||||
</el-button>
|
||||
</template>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: "accountRoleList",
|
||||
inject:{
|
||||
instance:{}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchInfo: "",
|
||||
pageSize: 10,
|
||||
tableData: [],
|
||||
multipleSelection: [],
|
||||
total: 0,
|
||||
pageNum: 1,
|
||||
row: {},
|
||||
deleteIds: [],
|
||||
copyDialog: false,
|
||||
roleName: "",
|
||||
viewShow: false,
|
||||
titleDel: "",
|
||||
form: {},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getTableList() {
|
||||
this.tableData = [];
|
||||
this.instance.post(`/admin/role-acc/page`, null, {
|
||||
params: {
|
||||
pageSize: this.pageSize,
|
||||
pageNum: this.pageNum,
|
||||
roleName: this.searchInfo,
|
||||
},
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records;
|
||||
this.total = res.data.total;
|
||||
if (this.tableData.length) {
|
||||
this.tableData.map((item) => {
|
||||
if (item.appRoleList.length > 3) {
|
||||
item.appRoleListHtml = `${item.appRoleList[0].appName}-${item.appRoleList[0].name};${item.appRoleList[1].appName}-${item.appRoleList[1].name};${item.appRoleList[2].appName}-${item.appRoleList[2].name};`;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
dataInit() {
|
||||
this.deleteIds = [];
|
||||
this.multipleSelection = [];
|
||||
this.row = {};
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.deleteIds = [];
|
||||
this.multipleSelection = val;
|
||||
this.multipleSelection.forEach((e) => {
|
||||
this.deleteIds.push(e.id);
|
||||
});
|
||||
},
|
||||
allDelete() {
|
||||
this.titleDel = "确定要执行删除操作吗?";
|
||||
this.deleteRole();
|
||||
},
|
||||
beforeDelete(row) {
|
||||
this.deleteIds = [];
|
||||
this.row = row;
|
||||
this.titleDel = "确定需要删除该角色吗?";
|
||||
this.deleteIds.push(row.id);
|
||||
this.deleteRole();
|
||||
},
|
||||
|
||||
beforeCopy(row) {
|
||||
this.row = row;
|
||||
this.copyDialog = true;
|
||||
},
|
||||
detailShow(row) {
|
||||
this.row = row;
|
||||
this.viewShow = true;
|
||||
},
|
||||
edit(row) {
|
||||
this.$router.push({
|
||||
hash: "#add",
|
||||
query: {
|
||||
info: row,
|
||||
},
|
||||
});
|
||||
},
|
||||
copyFn() {
|
||||
let crr = [];
|
||||
let appRoleList = this.row.appRoleList;
|
||||
appRoleList.forEach((e) => {
|
||||
crr.push(e.id);
|
||||
});
|
||||
this.instance.post(`/admin/role-acc/modify?appRoles=${crr}`, null, {
|
||||
params: {
|
||||
roleName: this.roleName,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message({message: "复制成功", type: "success"});
|
||||
this.copyDialog = false;
|
||||
this.pageNum = 1;
|
||||
this.getTableList();
|
||||
}
|
||||
});
|
||||
},
|
||||
deleteRole() {
|
||||
this.$confirm(this.titleDel, {
|
||||
type: "error",
|
||||
})
|
||||
.then(() => {
|
||||
this.instance
|
||||
.post(`/admin/role-acc/del?ids=${this.deleteIds}`, null, {})
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success("删掉角色成功");
|
||||
this.getTableList();
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
});
|
||||
},
|
||||
mhSearch() {
|
||||
this.pageNum = 1;
|
||||
this.getTableList();
|
||||
},
|
||||
// 重置
|
||||
resetConditon() {
|
||||
this.pageNum = 1;
|
||||
this.searchInfo = "";
|
||||
this.getTableList();
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.pageSize = val;
|
||||
this.getTableList();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.pageNum = val;
|
||||
this.getTableList();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getTableList();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.accountRoleList {
|
||||
height: 100%;
|
||||
|
||||
::v-deep.ai-card {
|
||||
box-shadow: none;
|
||||
border: 1px solid #eee;
|
||||
|
||||
.aibar {
|
||||
height: 40px;
|
||||
background: #f3f6f9;
|
||||
}
|
||||
|
||||
.ai-card__body {
|
||||
padding: 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.view_info {
|
||||
color: #333;
|
||||
padding-left: 20px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.info-title {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
170
core/apps/AppAccountRole/addAccountRole.vue
Normal file
170
core/apps/AppAccountRole/addAccountRole.vue
Normal file
@@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<section class="addAccountRole">
|
||||
<ai-detail>
|
||||
<ai-title slot="title" :title="pageTitle" isShowBottomBorder isShowBack @onBackClick="$router.push({})"/>
|
||||
<template #content>
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form size="small" label-width="120px">
|
||||
<el-form-item required label="账号角色名称">
|
||||
<el-input clearable v-model="roleName" placeholder="请输入..."/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="角色信息(必选)">
|
||||
<template #content>
|
||||
<el-form size="small" label-width="120px">
|
||||
<el-form-item required label="角色列表">
|
||||
<div class="roleList">
|
||||
<p class="input">
|
||||
<el-input placeholder="请输入..." size="small" v-model="filterText" suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
<el-button icon="iconfont iconDelete" size="small" @click="filterText=''">清空</el-button>
|
||||
</p>
|
||||
<div class="tree_list">
|
||||
<el-tree
|
||||
class="filter-tree"
|
||||
:data="roleList"
|
||||
show-checkbox
|
||||
:props="defaultProps"
|
||||
default-expand-all
|
||||
:check-strictly="true"
|
||||
node-key="id"
|
||||
:default-checked-keys="defaultId"
|
||||
:filter-node-method="filterNode"
|
||||
ref="tree">
|
||||
</el-tree>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="toAppRole">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">保存</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "addAccountRole",
|
||||
inject: {instance: {}},
|
||||
data() {
|
||||
return {
|
||||
roleName: '',
|
||||
id: '',
|
||||
roleList: [],
|
||||
searchVal: '',
|
||||
defaultProps: {
|
||||
children: 'roles',
|
||||
label: 'name'
|
||||
},
|
||||
treeList: [],
|
||||
defaultId: [],
|
||||
filterText: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isAdd() {
|
||||
return !this.$route.query?.info?.id
|
||||
},
|
||||
pageTitle() {
|
||||
return this.isAdd ? "新增账号角色" : "编辑账号角色"
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.tree.filter(val);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getAppList();
|
||||
if (JSON.stringify(this.$route.query) != '{}') {
|
||||
this.roleName = this.$route.query.info.name;
|
||||
this.id = this.$route.query.info.id;
|
||||
this.$route.query.info.appRoleList.forEach(e => {
|
||||
this.defaultId.push(e.id)
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//查询下拉列表
|
||||
getAppList() {
|
||||
this.instance.post(`/admin/role-app/list-all`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.roleList = res.data;
|
||||
this.roleList.forEach(e => {
|
||||
e.disabled = true;
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data.name.indexOf(value) !== -1;
|
||||
},
|
||||
confirm() {
|
||||
let crr = [];
|
||||
let arrCheckList = [];
|
||||
arrCheckList = this.$refs.tree.getCheckedKeys();
|
||||
for (let i = 0; i < arrCheckList.length; i++) {
|
||||
crr.push(arrCheckList[i]);
|
||||
}
|
||||
if (!this.roleName) {
|
||||
this.$message.error('请输入账号角色名称')
|
||||
return;
|
||||
}
|
||||
if (crr.length == 0) {
|
||||
this.$message.error('请选择角色列表')
|
||||
return;
|
||||
}
|
||||
this.instance.post(`/admin/role-acc/modify?appRoles=${crr}`, null, {
|
||||
params: {
|
||||
roleName: this.roleName,
|
||||
id: this.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message({message: '保存成功', type: 'success'});
|
||||
this.toAppRole()
|
||||
}
|
||||
})
|
||||
},
|
||||
//取消 返回
|
||||
toAppRole() {
|
||||
this.$router.push({})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.addAccountRole {
|
||||
height: 100%;
|
||||
|
||||
.roleList {
|
||||
display: inline-block;
|
||||
width: 340px;
|
||||
height: 420px;
|
||||
background-color: #fcfcfc;
|
||||
border-radius: 2px;
|
||||
border: solid 1px #d0d4dc;
|
||||
|
||||
.input {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 5px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tree_list {
|
||||
height: 370px;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
156
core/apps/AppDictionary/AppDictionary.vue
Normal file
156
core/apps/AppDictionary/AppDictionary.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<section class="AppDictionary">
|
||||
<ai-list v-if="!showDetail">
|
||||
<ai-title slot="title" title="数据字典" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" size="small" icon="iconfont iconAdd" @click="addDict"
|
||||
v-if="$permissions('admin_sysdictionary_add')">添加
|
||||
</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" v-model="search.condition" placeholder="数据项" clearable
|
||||
@change="page.current=1,getDicts()" prefix-icon="iconfont iconSearch"/>
|
||||
<el-button type="primary" size="small" icon="iconfont iconSearch"
|
||||
@click="page.current=1,getDicts()">查询
|
||||
</el-button>
|
||||
<el-button size="small" icon="el-icon-refresh-right" @click="resetSearch">重置</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<el-table size="mini" :data="dictList" header-cell-class-name="table-header" tooltip-effect="light"
|
||||
row-class-name="table-row" cell-class-name="table-cell" @expand-change="getDictInfo">
|
||||
<el-table-column type="expand">
|
||||
<el-row slot-scope="{row}" type="flex" align="middle" style="flex-wrap: wrap">
|
||||
<el-tag v-for="(op,i) in row.detail||[]" :key="i" style="margin: 4px">{{ op.dictValue }}|{{ op.dictName }}
|
||||
{{ op.dictColor ? '| ' + op.dictColor : '' }}
|
||||
</el-tag>
|
||||
</el-row>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="数据项" prop="code"/>
|
||||
<el-table-column align="center" label="数据项名称" prop="name"/>
|
||||
<el-table-column align="center" label="操作">
|
||||
<div slot-scope="{row}">
|
||||
<el-button type="text" @click="openDetail(row.id)" v-text="'编辑'"
|
||||
v-if="$permissions('admin_sysdictionary_edit')"/>
|
||||
<el-button type="text" @click="handleDelete(row.id)" v-text="'删除'"
|
||||
v-if="$permissions('admin_sysdictionary_del')"/>
|
||||
</div>
|
||||
</el-table-column>
|
||||
<div slot="empty" class="no-data"></div>
|
||||
</el-table>
|
||||
<div class="pagination">
|
||||
<el-pagination background :current-page.sync="page.current" :total="page.total"
|
||||
layout="total,prev, pager, next,sizes, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
:page-size="page.size"
|
||||
:page-sizes="[10, 20, 50, 100,200]"
|
||||
@current-change="getDicts"/>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
<dict-detail v-else :instance="instance" :permissions="permissions"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DictDetail from "./dictDetail";
|
||||
|
||||
export default {
|
||||
name: "AppDictionary",
|
||||
components: {DictDetail},
|
||||
label: "数据字典",
|
||||
props: {
|
||||
instance: Function,
|
||||
permissions: Function
|
||||
},
|
||||
computed: {
|
||||
showDetail() {
|
||||
return this.$route.hash == "#add"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page: {
|
||||
current: 1,
|
||||
total: 0,
|
||||
size: 10
|
||||
},
|
||||
search: {
|
||||
condition: ""
|
||||
},
|
||||
dictList: [],
|
||||
id: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resetSearch() {
|
||||
this.page.current = 1;
|
||||
this.search.condition = '';
|
||||
this.getDicts();
|
||||
},
|
||||
getDicts() {
|
||||
this.instance.post("/admin/dictionary/queryDictList", null, {
|
||||
params: {
|
||||
...this.page,
|
||||
name: this.search.condition
|
||||
}
|
||||
}).then(res => {
|
||||
this.dictList = res.data.records.map(e => {
|
||||
return {...e, detail: []}
|
||||
})
|
||||
this.page.total = res.data.total
|
||||
})
|
||||
},
|
||||
addDict() {
|
||||
this.$router.push({hash: "#add"})
|
||||
},
|
||||
handleDelete(id) {
|
||||
this.$confirm("确定要删除该数据项吗?", {
|
||||
type: "error"
|
||||
}).then(() => {
|
||||
this.instance.post("/admin/dictionary/deleteDict", null, {
|
||||
params: {id}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.getDicts();
|
||||
this.$message.success("删除成功!")
|
||||
}
|
||||
})
|
||||
}).catch(() => 0)
|
||||
},
|
||||
openDetail(id) {
|
||||
this.$router.push({query: {id}, hash: "#add"})
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.page.size = val;
|
||||
this.getDicts();
|
||||
},
|
||||
getDictInfo(row) {
|
||||
if (row.detail.length) {
|
||||
row.detail = []
|
||||
} else {
|
||||
this.getDict(row.id).then(res => {
|
||||
if (res && res.data) {
|
||||
row.detail = res.data.dictionaryDetails || []
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
getDict(dictionaryId) {
|
||||
return this.instance.post("/admin/dictionary/queryDictDetail", null, {
|
||||
params: {dictionaryId}
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getDicts()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppDictionary {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
202
core/apps/AppDictionary/dictDetail.vue
Normal file
202
core/apps/AppDictionary/dictDetail.vue
Normal file
@@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<section class="dictDetail">
|
||||
<ai-detail>
|
||||
<ai-title slot="title" title="字典信息" isShowBottomBorder isShowBack @onBackClick="$router.push({})"/>
|
||||
<template #content>
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form ref="dictDetailForm" :model="form" :rules="rules" size="small" label-width="110px">
|
||||
<el-form-item required label="数据项:" prop="code">
|
||||
<el-input v-model="form.code" style="width: 259px;" clearable
|
||||
placeholder="请输入..."/>
|
||||
</el-form-item>
|
||||
<el-form-item required label="数据项名称:" prop="name">
|
||||
<el-input v-model="form.name" style="width: 259px;" clearable
|
||||
placeholder="请输入..."/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="数据值" v-if="$route.query.id">
|
||||
<template #right>
|
||||
<el-button type="text" icon="iconfont iconAdd"
|
||||
@click="form.dictionaryDetails.push({name:'',value:'',editable:true})"> 添加
|
||||
</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<el-table border :data="form.dictionaryDetails" header-cell-class-name="table-header"
|
||||
cell-class-name="table-cell">
|
||||
<el-table-column align="center" label="值">
|
||||
<div slot-scope="{row}">
|
||||
<el-input size="small" v-if="row.editable" v-model="row.value" clearable/>
|
||||
<span v-else>{{ row.dictValue }}</span>
|
||||
</div>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="描述">
|
||||
<div slot-scope="{row}">
|
||||
<el-input size="small" v-if="row.editable" v-model="row.name" clearable/>
|
||||
<span v-else>{{ row.dictName }}</span>
|
||||
</div>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="颜色">
|
||||
<div slot-scope="{row}">
|
||||
<el-color-picker v-if="row.editable" v-model="row.dictColor" size="medium"></el-color-picker>
|
||||
<span v-else>{{ row.dictColor || '未设置' }}</span>
|
||||
</div>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="操作" width="109px">
|
||||
<div slot-scope="{row,$index}">
|
||||
<section v-if="row.editable">
|
||||
<el-button style="color: #2EA222" type="text" icon="iconfont iconCorrect"
|
||||
@click="addDict(row)"/>
|
||||
<el-button style="color: #f46" type="text" icon="iconfont iconClean"
|
||||
@click="cancelEdit(row,$index)"/>
|
||||
</section>
|
||||
<section v-else>
|
||||
<el-button class="dict-detail-operation" type="text" icon="iconfont iconEdit"
|
||||
@click="editDetail(row)"/>
|
||||
<el-button class="dict-detail-operation" type="text" icon="iconfont iconDelete"
|
||||
@click="delDictValue(row.id)"/>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="$router.push({})">返回</el-button>
|
||||
<el-button type="primary" @click="modifyDict">保存</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "dictDetail",
|
||||
props: {
|
||||
instance: Function,
|
||||
permissions: Function
|
||||
},
|
||||
computed: {
|
||||
rules() {
|
||||
return {
|
||||
code: [
|
||||
{required: true, message: "请填写数据项"}
|
||||
],
|
||||
name: [
|
||||
{required: true, message: "请填写数据项名称"}
|
||||
],
|
||||
// dictionaryDetails: [
|
||||
// {
|
||||
// validator: (r, v, cb) => {
|
||||
// if (v.every(item => item.dictName && item.dictValue)) {
|
||||
// cb()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
code: "",
|
||||
name: "",
|
||||
dictionaryDetails: []
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.$route.query.id) this.getDict()
|
||||
},
|
||||
methods: {
|
||||
getDict() {
|
||||
this.instance.post("/admin/dictionary/queryDictDetail", null, {
|
||||
params: {dictionaryId: this.$route.query.id}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
res.data.dictionaryDetails = res.data.dictionaryDetails.map(d => {
|
||||
return {
|
||||
...d,
|
||||
editable: false,
|
||||
name: "",
|
||||
value: ""
|
||||
}
|
||||
})
|
||||
this.form = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
delDictValue(id) {
|
||||
this.$confirm("是否要删除该字典值", {
|
||||
type: 'error'
|
||||
}).then(() => {
|
||||
this.instance.post("/admin/dictionary/deletevalue", null, {
|
||||
params: {id}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("删除成功!")
|
||||
this.getDict()
|
||||
}
|
||||
})
|
||||
}).catch(() => 0)
|
||||
},
|
||||
editDetail(row) {
|
||||
row.editable = true
|
||||
row.name = row.dictName
|
||||
row.value = row.dictValue
|
||||
},
|
||||
addDict(row) {
|
||||
row.dictValue = row.value
|
||||
row.dictName = row.name
|
||||
row.dictionaryId = this.form.id
|
||||
this.instance.post("/admin/dictionary/updateDetail", row).then(res => {
|
||||
row.editable = false
|
||||
row = res.data.data
|
||||
this.$message.success("提交成功!")
|
||||
})
|
||||
},
|
||||
cancelEdit(row, index) {
|
||||
if (row.id) {
|
||||
row.editable = false
|
||||
} else {
|
||||
this.form.dictionaryDetails.splice(index, 1)
|
||||
}
|
||||
},
|
||||
modifyDict() {
|
||||
this.$refs.dictDetailForm.validate(v => {
|
||||
if (v) {
|
||||
this.instance.post("/admin/dictionary/updateDict", this.form).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("提交成功!")
|
||||
this.$router.push({})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dictDetail {
|
||||
height: 100%;
|
||||
|
||||
::v-deep .el-table__row {
|
||||
|
||||
.el-input__inner {
|
||||
padding: 0 30px;
|
||||
border: none;
|
||||
text-align: center;
|
||||
background: #ddd;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
35
core/apps/AppMenuManager/AppMenuManager.vue
Normal file
35
core/apps/AppMenuManager/AppMenuManager.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<section class="AppMenuManager">
|
||||
<component :is="currentPage" v-bind="$props"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from "./list";
|
||||
import IntroPage from "./introPage";
|
||||
|
||||
export default {
|
||||
name: "AppMenuManager",
|
||||
components: {IntroPage, List},
|
||||
label: "菜单管理",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: {default: () => ({})}
|
||||
},
|
||||
computed: {
|
||||
currentPage() {
|
||||
const {hash} = this.$route
|
||||
return hash == "#intro" ? IntroPage : List
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.dict.load("menuType", "yesOrNo")
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppMenuManager {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
96
core/apps/AppMenuManager/introPage.vue
Normal file
96
core/apps/AppMenuManager/introPage.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<section class="introPage">
|
||||
<ai-detail :list="!edit">
|
||||
<ai-title slot="title" title="引导页配置" isShowBottomBorder isShowBack @onBackClick="$router.push({})">
|
||||
<template #rightBtn>
|
||||
<ai-edit-btn @edit="edit=true,getConfigs()" @cancel="edit=false" @submit="submit"/>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template #content>
|
||||
<el-form v-if="edit" :model="form" ref="IntroForm" size="small" :rules="rules" label-width="120px">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form-item label="副标题" prop="subtitle">
|
||||
<el-input v-model="form.subtitle" clearable placeholder="请输入"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作示例链接" prop="operationExamples">
|
||||
<el-input v-model="form.operationExamples" clearable placeholder="请输入"/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="引导内容">
|
||||
<template #content>
|
||||
<el-form-item label-width="0" prop="guideContent">
|
||||
<ai-editor :instance="instance" v-model="form.guideContent" placeholder="请输入" action="/oms/api/file/add" :params="{withoutToken:true}"/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</ai-card>
|
||||
</el-form>
|
||||
<ai-intro v-else :id="$route.query.id" v-bind="$props"/>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AiEditBtn from "../../components/AiEditBtn";
|
||||
|
||||
export default {
|
||||
name: "introPage",
|
||||
components: {AiEditBtn},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: {default: () => ({})}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
rules: {
|
||||
subtitle: {required: true, message: "请输入副标题"},
|
||||
guideContent: {required: true, message: "请输入引导内容"},
|
||||
},
|
||||
edit: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getConfigs() {
|
||||
const {id} = this.$route.query
|
||||
this.instance.post("/admin/sysappguideconfig/queryDetailById", null, {
|
||||
params: {id}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.form = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
submit(cb) {
|
||||
this.$refs.IntroForm.validate(v => {
|
||||
if (v) {
|
||||
const {form, $route: {query: {id}}} = this
|
||||
this.instance.post("/admin/sysappguideconfig/addOrUpdate", {...form, id}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("提交成功!")
|
||||
cb()
|
||||
this.edit = false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.introPage {
|
||||
height: 100%;
|
||||
|
||||
::v-deep.ai-detail__content--wrapper {
|
||||
min-height: 100%;
|
||||
|
||||
&.list {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
268
core/apps/AppMenuManager/list.vue
Normal file
268
core/apps/AppMenuManager/list.vue
Normal file
@@ -0,0 +1,268 @@
|
||||
<template>
|
||||
<section class="list">
|
||||
<ai-list>
|
||||
<ai-title slot="title" title="菜单配置" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" icon="el-icon-circle-plus" @click="addRootMenu">添加一级目录</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" v-model="search" clearable @change="$refs.MenuTree.filter(search)"
|
||||
placeholder="菜单名称"/>
|
||||
<el-button icon="iconfont iconResetting" @click="getData">刷新</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<el-row type="flex" class="headerRow">
|
||||
<div class="menuName" v-text="`菜单名称`"/>
|
||||
<el-row type="flex" align="middle" class="info">
|
||||
<div class="style" v-text="`图标`"/>
|
||||
<div class="type" v-text="`菜单类型`"/>
|
||||
<div class="component" v-text="`应用模块`"/>
|
||||
<div class="status" v-text="`是否显示`"/>
|
||||
<div class="showIndex" v-text="`排序`"/>
|
||||
</el-row>
|
||||
<div class="operation" v-text="`操作`"/>
|
||||
</el-row>
|
||||
<el-scrollbar>
|
||||
<el-tree ref="MenuTree" :data="treeData" :props="{children:'subSet'}" highlight-current node-key="id"
|
||||
:filter-node-method="handleSearch">
|
||||
<el-row type="flex" align="middle" slot-scope="{node,data}" class="menuItem">
|
||||
<div class="menuName" v-text="data.name"/>
|
||||
<el-row type="flex" align="middle" class="info">
|
||||
<div class="style" :class="data.style"/>
|
||||
<div class="type" v-text="dict.getLabel('menuType',data.type)"/>
|
||||
<div class="component" v-text="data.component"/>
|
||||
<div class="status" v-text="dict.getLabel('yesOrNo',data.status)"/>
|
||||
<div class="showIndex" v-text="data.showIndex"/>
|
||||
</el-row>
|
||||
<el-row type="flex" align="middle" class="operation">
|
||||
<div v-if="node.isLeaf" class="opBtn del" v-text="`删除`" @click="handleDelete(data)"/>
|
||||
<div v-if="data.component&&data.type==1" class="opBtn" v-text="`引导页`" @click="$router.push({hash:'#intro',query:{id:data.id}})"/>
|
||||
<div v-if="data.type<2" class="opBtn" v-text="`添加下级`" @click="addMenu(data)"/>
|
||||
<div class="opBtn" v-text="`编辑`" @click="handleEdit(data)"/>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-tree>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
</ai-list>
|
||||
<ai-dialog :visible.sync="dialog" title="菜单设置" width="500px" @onConfirm="handleSubmit"
|
||||
@closed="form={},selected={}">
|
||||
<el-form ref="MenuForm" :model="form" size="small" label-width="100px" :rules="rules">
|
||||
<el-form-item label="菜单名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单类型" prop="type">
|
||||
<ai-select v-model="form.type" clearable :selectList="dict.getDict('menuType')"/>
|
||||
</el-form-item>
|
||||
<template v-if="form.type==0">
|
||||
<el-form-item label="菜单图标" prop="style">
|
||||
<el-input v-model="form.style" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template v-if="form.type==1">
|
||||
<el-form-item label="路由名" prop="route">
|
||||
<span v-text="form.route||'提交保存后会自动生成'"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单应用" prop="component">
|
||||
<el-input v-model="form.component" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="路径(path)" prop="path">
|
||||
<el-input v-model="form.path" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template v-if="form.type==2">
|
||||
<el-form-item label="权限码" prop="permission">
|
||||
<el-input v-model="form.permission" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-form-item label="显示菜单" prop="status">
|
||||
<ai-select v-model="form.status" clearable :selectList="dict.getDict('yesOrNo')"/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type<2" label="排序" prop="showIndex">
|
||||
<el-input v-model="form.showIndex" placeholder="请输入" clearable/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "list",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: {default: () => ({})}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
treeData: [],
|
||||
dialog: false,
|
||||
form: {},
|
||||
selected: {},
|
||||
rules: {
|
||||
name: [{required: true, message: "请输入 菜单名称"}],
|
||||
type: [{required: true, message: "请选择 菜单类型"}],
|
||||
status: [{required: true, message: "请选择 显示菜单"}],
|
||||
showIndex: [{required: true, message: "请输入 排序"}],
|
||||
permission: [{required: true, message: "请输入 权限码"}],
|
||||
},
|
||||
search: ""
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
return this.instance.post("/admin/menu/menuTree").then(res => {
|
||||
if (res?.data) {
|
||||
this.treeData = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSubmit() {
|
||||
this.$refs.MenuForm.validate(v => {
|
||||
if (v) {
|
||||
this.instance.post("/admin/menu/addOrUpdate", this.form).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("提交成功!")
|
||||
this.dialog = false
|
||||
if (!!this.form.id) {
|
||||
let node = this.$refs.MenuTree.getNode(this.form)
|
||||
node.data = this.form
|
||||
} else if (!!this.form.parentId) {
|
||||
this.$refs.MenuTree.append(this.form, this.selected)
|
||||
} else this.getData()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(data) {
|
||||
let {id} = data
|
||||
this.$confirm("是否要删除该菜单").then(() => {
|
||||
this.instance.post("/admin/menu/delete", null, {
|
||||
params: {id}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("删除成功!")
|
||||
this.dialog = false
|
||||
this.$refs.MenuTree.remove(data)
|
||||
}
|
||||
})
|
||||
}).catch(() => 0)
|
||||
},
|
||||
addRootMenu(row) {
|
||||
this.dialog = true
|
||||
this.selected = row
|
||||
},
|
||||
addMenu(row) {
|
||||
this.dialog = true
|
||||
this.form = {parentId: row.id}
|
||||
this.selected = row
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.dialog = true
|
||||
this.form = JSON.parse(JSON.stringify(row))
|
||||
this.selected = row
|
||||
},
|
||||
handleSearch(value, data) {
|
||||
if (!value) return true;
|
||||
return data.name.indexOf(value) !== -1;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getData()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list {
|
||||
height: 100%;
|
||||
|
||||
::v-deep .ai-list__content--right-wrapper {
|
||||
height: calc(100% - 10px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.el-tree {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 14px;
|
||||
|
||||
.menuItem {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.el-tree-node:nth-of-type(2n) {
|
||||
background: rgba(#26f, .05);
|
||||
}
|
||||
|
||||
.el-tree-node__content {
|
||||
border-bottom: 1px solid #d0d4dc;
|
||||
}
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
.el-scrollbar__wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.headerRow {
|
||||
background: #f3f4f5;
|
||||
color: #666;
|
||||
font-weight: bold;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
|
||||
.menuName {
|
||||
padding-left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
gap: 16px;
|
||||
text-align: center;
|
||||
|
||||
.showIndex, .status, .type, .style {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.component {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.operation {
|
||||
width: 300px;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
text-align: center;
|
||||
|
||||
.opBtn {
|
||||
cursor: pointer;
|
||||
width: 60px;
|
||||
|
||||
font-size: 14px;
|
||||
color: #26f;
|
||||
|
||||
&.del {
|
||||
color: #f46;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menuName {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
36
core/apps/AppQyWxConfig/AppQyWxConfig.vue
Normal file
36
core/apps/AppQyWxConfig/AppQyWxConfig.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<section class="AppQyWxConfig">
|
||||
<component :is="currentPage" v-bind="$props"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from "./list";
|
||||
import ThemeSetting from "./themeSetting";
|
||||
|
||||
export default {
|
||||
name: "AppQyWxConfig",
|
||||
components: {ThemeSetting, List},
|
||||
label: "企业微信配置",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
computed: {
|
||||
currentPage() {
|
||||
const {hash} = this.$route
|
||||
return hash == "#theme" ? ThemeSetting : List
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.dict.load("yesOrNo", "themeWeb", 'themeMp', "themeWxwork")
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppQyWxConfig {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
74
core/apps/AppQyWxConfig/components/AiSelectCard.vue
Normal file
74
core/apps/AppQyWxConfig/components/AiSelectCard.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<section class="AiSelectCard" flex>
|
||||
<div class="checkCard" v-for="op in list" :key="op[props.value]" :class="{checked:op.dictValue==value}">
|
||||
<el-image :src="op.thumb"/>
|
||||
<el-row type="flex" class="bottomPane">
|
||||
<b class="label fill" v-text="op[props.label]"/>
|
||||
<el-button type="text" @click.stop="$emit('change',op[props.value])">使用</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "AiSelectCard",
|
||||
model: {
|
||||
prop: "value",
|
||||
event: "change"
|
||||
},
|
||||
props: {
|
||||
value: {default: ""},
|
||||
ops: {default: () => []},
|
||||
type: {default: "web"},
|
||||
dict: String,
|
||||
prop: {default: () => ({})}
|
||||
},
|
||||
computed: {
|
||||
list: v => (v.dict ? v.$dict.getDict(v.dict) : v.ops || []).map(e => ({
|
||||
...e,
|
||||
thumb: `https://cdn.cunwuyun.cn/theme/thumb/${v.type}_${e[v.props.value]}.png`
|
||||
})),
|
||||
props: v => ({value: 'dictValue', label: 'dictName', ...v.prop})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AiSelectCard {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
|
||||
.checkCard {
|
||||
width: 360px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.label {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
&.checked:before {
|
||||
position: absolute;
|
||||
content: "应用中";
|
||||
top: 16px;
|
||||
left: 16px;
|
||||
z-index: 9;
|
||||
padding: 8px 16px;
|
||||
background: rgba(#000, .7);
|
||||
color: #fff;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.bottomPane {
|
||||
height: 48px;
|
||||
align-items: center;
|
||||
padding: 0 16px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
485
core/apps/AppQyWxConfig/list.vue
Normal file
485
core/apps/AppQyWxConfig/list.vue
Normal file
@@ -0,0 +1,485 @@
|
||||
<template>
|
||||
<section class="list">
|
||||
<ai-list>
|
||||
<ai-title slot="title" title="企业微信配置" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" @click="add" icon="iconfont iconAdd">新增</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" placeholder="搜索名称" v-model="search.name" clearable
|
||||
@clear="page.current = 1,search.name = '', getTableData()"
|
||||
v-throttle="() => {page.current = 1, getTableData()}"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
|
||||
@getList="getTableData" :col-configs="colConfigs">
|
||||
<el-table-column type="expand" slot="expand">
|
||||
<template slot-scope="{row}">
|
||||
<ai-wrapper>
|
||||
<ai-info-item labelWidth="200px" v-for="op in desConfigs" :key="op.prop" :value="row[op.prop]"
|
||||
v-bind="op"/>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="status" align="center" label="状态" width="150">
|
||||
<template v-slot="{ row }">
|
||||
<el-switch v-model="row.status" @change="onChange(row)" active-value="1" inactive-value="0"
|
||||
active-color="#5088FF" inactive-color="#D0D4DC"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="miniappStatus" align="center" label="小程序状态" width="150">
|
||||
<template v-slot="{ row }">
|
||||
<el-switch v-model="row.miniappStatus" @change="onMiniappStatusChange(row)" active-value="1"
|
||||
inactive-value="0"
|
||||
active-color="#5088FF" inactive-color="#D0D4DC"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" align="center" label="操作" width="400">
|
||||
<el-row type="flex" justify="center" align="middle" slot-scope="{row}">
|
||||
<el-button type="text" @click="detail(row)">详情</el-button>
|
||||
<el-button type="text" @click="del(row)">删除</el-button>
|
||||
<el-button type="text" @click="handleSystemInfo(row.id)">系统信息</el-button>
|
||||
<el-button type="text" @click="handlePush(row.id)">推送随手拍样式</el-button>
|
||||
<el-button type="text" @click="handleTheme(row.id)">主题样式</el-button>
|
||||
</el-row>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<ai-dialog title="新增" :visible.sync="dialog" width="800px" @onConfirm="confirm">
|
||||
<el-form ref="form" :model="dialogForm" :rules="rules" size="small" label-width="180px">
|
||||
<el-form-item required label="名称" prop="name">
|
||||
<el-input v-model.trim="dialogForm.name" placeholder="请输入名称" show-word-limit maxlength="100"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="企业微信ID" prop="corpId">
|
||||
<el-input v-model.trim="dialogForm.corpId" placeholder="请输入企业微信ID" show-word-limit maxlength="32"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="企业微信通讯录SECRET" prop="corpAddressBookSecret">
|
||||
<el-input v-model.trim="dialogForm.corpAddressBookSecret" placeholder="请输入企业微信通讯录SECRET" show-word-limit
|
||||
maxlength="64"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="企业微信AESKEY" prop="corpAeskey">
|
||||
<el-input v-model.trim="dialogForm.corpAeskey" placeholder="请输入企业微信AESKEY" show-word-limit
|
||||
maxlength="64"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="企业微信AGENTID" prop="corpAgentId">
|
||||
<el-input v-model.trim="dialogForm.corpAgentId" placeholder="请输入企业微信AGENTID" show-word-limit
|
||||
maxlength="100"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="随手拍AGENTID" prop="clapAgentId">
|
||||
<el-input v-model.trim="dialogForm.clapAgentId" placeholder="请输入随手拍AGENTID" show-word-limit
|
||||
maxlength="100"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="企业微信SECRET" prop="corpSecret">
|
||||
<el-input v-model.trim="dialogForm.corpSecret" placeholder="请输入企业微信SECRET" show-word-limit
|
||||
maxlength="255"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="企业微信TOKEN" prop="corpToken">
|
||||
<el-input v-model.trim="dialogForm.corpToken" placeholder="请输入企业微信TOKEN" show-word-limit
|
||||
maxlength="32"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="小程序APPID" prop="miniappAppid">
|
||||
<el-input v-model.trim="dialogForm.miniappAppid" placeholder="请输入小程序APPID" show-word-limit
|
||||
maxlength="32"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="小程序SECRET" prop="miniappSecret">
|
||||
<el-input v-model.trim="dialogForm.miniappSecret" placeholder="请输入小程序SECRET" show-word-limit
|
||||
maxlength="32"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="企微访问域名" prop="dvcpUrl">
|
||||
<el-input v-model.trim="dialogForm.dvcpUrl" placeholder="请输入企微访问域名" show-word-limit maxlength="128">
|
||||
<template slot="prepend">Http://</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="web访问域名" prop="webUrl">
|
||||
<el-input v-model.trim="dialogForm.webUrl" placeholder="请输入web访问域名" show-word-limit maxlength="128">
|
||||
<template slot="prepend">Http://</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="地区" prop="areaId">
|
||||
<ai-area-select :instance="instance" v-model="dialogForm.areaId" alwaysShow
|
||||
@name="(e)=>dialogForm.areaName=e"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="地图中心点" prop="lat">
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="showMap=true">设置地点</el-button>
|
||||
<div v-if="dialogForm.lat">{{ dialogForm.address }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model.trim="dialogForm.status">
|
||||
<el-radio label="1">启用</el-radio>
|
||||
<el-radio label="0">禁用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="小程序状态" prop="miniappStatus">
|
||||
<el-radio-group v-model.trim="dialogForm.miniappStatus">
|
||||
<el-radio label="1">启用</el-radio>
|
||||
<el-radio label="0">禁用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="系统配置信息" prop="systemInfo">
|
||||
<el-input type="textarea" :rows="2" placeholder="请输入系统配置信息" v-model="dialogForm.systemInfo"
|
||||
maxlength="50000"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
<ai-dialog title="地图" :visible.sync="showMap" @opened="initMap" width="800px" class="mapDialog"
|
||||
@onConfirm="selectMap">
|
||||
<div id="map"></div>
|
||||
<el-input id="searchPlaceInput" size="medium" class="searchPlaceInput" clearable v-model="searchPlace"
|
||||
autocomplete="on"
|
||||
@change="placeSearch.search(searchPlace)">
|
||||
<el-button type="primary" slot="append" @click="placeSearch.search(searchPlace)">搜索</el-button>
|
||||
</el-input>
|
||||
<div id="searchPlaceOutput"/>
|
||||
</ai-dialog>
|
||||
<ai-dialog title="系统信息设置" :visible.sync="sysInfoDialog" width="600px" @onConfirm="submitSystemInfo"
|
||||
@closed="sysInfo={}">
|
||||
<el-form size="small" label-width="140px">
|
||||
<el-form-item label="页签标题">
|
||||
<el-input v-model="sysInfo.title" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="系统标题">
|
||||
<el-input v-model="sysInfo.fullTitle" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="logo">
|
||||
<el-input v-model="sysInfo.logo" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="登录页左上角标题">
|
||||
<el-input v-model="sysInfo.name" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="登录页副标题">
|
||||
<el-input type="textarea" rows="5" v-model="sysInfo.desc" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="版权所有">
|
||||
<el-input v-model="sysInfo.recordDesc" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备案号">
|
||||
<el-input v-model="sysInfo.recordNo" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备案跳转链接">
|
||||
<el-input v-model="sysInfo.recordURL" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="框架版本">
|
||||
<!--edition :版本,标准版:standard、上架版:saas-->
|
||||
<el-input v-model="sysInfo.edition" placeholder="请输入..." clearable/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import AMapLoader from "@amap/amap-jsapi-loader"
|
||||
|
||||
export default {
|
||||
name: "list",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
colConfigs() {
|
||||
return [
|
||||
{slot: 'expand'},
|
||||
{prop: "name", label: "名称"},
|
||||
{prop: "corpId", label: "企业微信ID", width: 180},
|
||||
{slot: "status",},
|
||||
{slot: "miniappStatus"},
|
||||
{prop: "createTime", label: "创建时间"},
|
||||
{slot: "options"},
|
||||
]
|
||||
},
|
||||
desConfigs() {
|
||||
let isLine = true
|
||||
return [
|
||||
{prop: "corpAddressBookSecret", label: "企业微信通讯录SECRET", width: 200},
|
||||
{prop: "corpAgentId", label: "企业微信AGENTID", width: 150},
|
||||
{prop: "corpSecret", label: "企业微信SECRET", isLine},
|
||||
{prop: "corpToken", label: "企业微信TOKEN", width: 150},
|
||||
{prop: "corpAeskey", label: "企业微信AESKEY", width: 150},
|
||||
{prop: "miniappAppid", label: "小程序APPID", width: 150},
|
||||
{prop: "miniappSecret", label: "小程序SECRET", width: 150},
|
||||
{prop: "areaId", label: "地区编码", width: 150, isLine},
|
||||
{prop: "lat", label: "纬度", width: 100},
|
||||
{prop: "lng", label: "经度", width: 100},
|
||||
{prop: "address", label: "中心点", width: 100, isLine},
|
||||
{prop: "webUrl", label: "管理端地址", width: 100},
|
||||
{prop: "dvcpUrl", label: "企微端地址", width: 100},
|
||||
]
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
name: [{required: true, message: "请填写名称"}],
|
||||
corpId: [{required: true, message: "请填写企业微信ID"}],
|
||||
corpAddressBookSecret: [{required: true, message: "请填写企业微信通讯录SECRET"}],
|
||||
corpAeskey: [{required: true, message: "请填写企业微信AESKEY"}],
|
||||
corpAgentId: [{required: true, message: "请填写企业微信AGENTID"}],
|
||||
corpSecret: [{required: true, message: "请填写企业微信SECRET"}],
|
||||
corpToken: [{required: true, message: "请填写企业微信TOKEN"}],
|
||||
miniappAppid: [{required: true, message: "请填写小程序APPID"}],
|
||||
miniappSecret: [{required: true, message: "请填写小程序SECRET"}],
|
||||
dvcpUrl: [{required: true, message: "请填写企微访问域名"}],
|
||||
webUrl: [{required: true, message: "请填写web访问域名"}],
|
||||
status: [{required: true, message: "请选择状态", trigger: "change"}],
|
||||
miniappStatus: [{required: true, message: "请选择小程序状态", trigger: "change"}],
|
||||
areaId: [{required: true, message: "请选择地区", trigger: "change"}],
|
||||
lat: [{required: true, message: "请选择中心点"}],
|
||||
systemInfo: [{required: true, message: "请输入系统配置信息"}],
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page: {current: 1, size: 10, total: 0},
|
||||
dialog: false,
|
||||
showMap: false,
|
||||
map: null,
|
||||
placeSearch: null,
|
||||
placeDetail: {},
|
||||
searchPlace: "",
|
||||
dialogForm: {},
|
||||
tableData: [],
|
||||
search: {
|
||||
name: ""
|
||||
},
|
||||
sysInfo: {},
|
||||
sysInfoDialog: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectMap() {
|
||||
Object.keys(this.placeDetail).map(e => this.dialogForm[e] = this.placeDetail[e]);
|
||||
this.showMap = false;
|
||||
},
|
||||
initMap() {
|
||||
AMapLoader.load({
|
||||
key: 'b553334ba34f7ac3cd09df9bc8b539dc',
|
||||
version: '2.0',
|
||||
plugins: ['AMap.PlaceSearch', 'AMap.AutoComplete', 'AMap.Geocoder'],
|
||||
}).then(AMap => {
|
||||
this.map = new AMap.Map('map', {
|
||||
resizeEnable: true,
|
||||
zooms: [6, 20],
|
||||
center: [116.394681, 39.910283],
|
||||
zoom: 11
|
||||
})
|
||||
this.placeSearch = new AMap.PlaceSearch({map: this.map})
|
||||
new AMap.AutoComplete({
|
||||
input: "searchPlaceInput",
|
||||
output: 'searchPlaceOutput',
|
||||
}).on('select', e => {
|
||||
if (e?.poi) {
|
||||
this.placeSearch.setCity(e.poi.adcode);
|
||||
this.movePosition(e.poi.location)
|
||||
}
|
||||
})
|
||||
this.map.on('click', e => {
|
||||
new AMap.Geocoder().getAddress(e.lnglat, (sta, res) => {
|
||||
if (res?.regeocode) {
|
||||
this.placeDetail = {
|
||||
lng: e.lnglat?.lng,
|
||||
lat: e.lnglat?.lat,
|
||||
address: res.regeocode.formattedAddress
|
||||
}
|
||||
}
|
||||
})
|
||||
this.movePosition(e.lnglat)
|
||||
})
|
||||
})
|
||||
},
|
||||
movePosition(center) {
|
||||
if (this.map) {
|
||||
this.map.clearMap()
|
||||
this.map.panTo(center)
|
||||
this.map.add([
|
||||
new AMap.Marker({
|
||||
position: center,
|
||||
clickable: true
|
||||
})
|
||||
])
|
||||
this.map.setFitView()
|
||||
}
|
||||
},
|
||||
onChange(row) {
|
||||
this.instance.post(`/app/appdvcpconfig/setStatus`, null, {
|
||||
params: {
|
||||
id: row.id,
|
||||
status: row.status
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(+row.status ? '已启用' : '已禁用');
|
||||
this.getTableData();
|
||||
}
|
||||
})
|
||||
},
|
||||
onMiniappStatusChange(row) {
|
||||
this.instance.post(`/app/appdvcpconfig/setMiniappStatus`, null, {
|
||||
params: {
|
||||
id: row.id,
|
||||
status: row.miniappStatus
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(+row.miniappStatus ? '已启用' : '已禁用');
|
||||
this.getTableData();
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
add() {
|
||||
this.dialogForm = {};
|
||||
this.dialog = true;
|
||||
},
|
||||
del(row) {
|
||||
this.$confirm("是否要删除?").then(_ => {
|
||||
this.instance.post("/app/appdvcpconfig/delete", null, {
|
||||
params: {
|
||||
ids: row.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success("删除成功");
|
||||
this.dialog = false;
|
||||
this.getTableData();
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
detail(row) {
|
||||
this.instance.post("/app/appdvcpconfig/detail", null, {
|
||||
params: {
|
||||
id: row.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res && res.data) {
|
||||
this.dialogForm = {...res.data};
|
||||
this.dialog = true;
|
||||
}
|
||||
})
|
||||
},
|
||||
getTableData() {
|
||||
this.instance.post("/app/appdvcpconfig/list", null, {
|
||||
params: {...this.page, ...this.search}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data?.records
|
||||
this.page.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
confirm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.instance.post("/app/appdvcpconfig/addOrUpdate", {
|
||||
...this.dialogForm,
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(this.dialogForm.id ? "修改成功" : "新增成功");
|
||||
this.dialog = false;
|
||||
this.getTableData();
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSystemInfo(id) {
|
||||
this.sysInfoDialog = true
|
||||
this.getSystemInfo(id)
|
||||
},
|
||||
getSystemInfo(id) {
|
||||
this.instance.post("/app/appdvcpconfig/getSystemInfo", null, {
|
||||
params: {id}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.sysInfo = JSON.parse(res.data)
|
||||
this.sysInfo.id = id
|
||||
}
|
||||
})
|
||||
},
|
||||
submitSystemInfo() {
|
||||
let {id} = this.sysInfo
|
||||
this.instance.post("/app/appdvcpconfig/updateSystemInfo", this.sysInfo, {params: {id}}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("提交成功!")
|
||||
this.sysInfoDialog = false
|
||||
}
|
||||
})
|
||||
},
|
||||
handlePush(id) {
|
||||
this.instance.post("/app/appclapeventinfo/setAppWorkbench", null, {params: {id}}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("推送成功!")
|
||||
}
|
||||
})
|
||||
},
|
||||
handleTheme(id) {
|
||||
this.$router.push({hash: "#theme", query: {id}})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTableData()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list {
|
||||
height: 100%;
|
||||
|
||||
|
||||
::v-deep .mapDialog {
|
||||
.el-dialog__body {
|
||||
padding: 0;
|
||||
|
||||
.ai-dialog__content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ai-dialog__content--wrapper {
|
||||
padding: 0 !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#map {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.searchPlaceInput {
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
top: 30px;
|
||||
left: 25px;
|
||||
}
|
||||
|
||||
#searchPlaceOutput {
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
left: 25px;
|
||||
height: initial;
|
||||
top: 80px;
|
||||
background: white;
|
||||
z-index: 250;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
|
||||
.auto-item {
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
83
core/apps/AppQyWxConfig/themeSetting.vue
Normal file
83
core/apps/AppQyWxConfig/themeSetting.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<section class="themeSetting">
|
||||
<ai-detail list>
|
||||
<ai-title slot="title" title="主题样式" isShowBottomBorder isShowBack @back="cancel">
|
||||
<template #rightBtn>
|
||||
<span class="mar-r8" v-text="'灰色滤镜'"/>
|
||||
<el-switch size="mini" v-model="form.enableGreyFilter" name="灰色滤镜" border active-value="1" inactive-value="0"/>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template #content>
|
||||
<el-form size="small" :model="form" ref="ThemeForm">
|
||||
<ai-title title="WEB后台"/>
|
||||
<ai-select-card dict="themeWeb" v-model="form.colorScheme.web"/>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="submit">提交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AiSelectCard from "./components/AiSelectCard";
|
||||
|
||||
export default {
|
||||
name: "themeSetting",
|
||||
components: {AiSelectCard},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {enableGreyFilter: '0', colorScheme: {}}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDetail() {
|
||||
const {id} = this.$route.query
|
||||
this.instance.post("/app/appdvcpconfig/detail", null, {params: {id}}).then(res => {
|
||||
if (res?.data) {
|
||||
let {colorScheme, enableGreyFilter} = res.data
|
||||
colorScheme = JSON.parse(colorScheme) || {web: 'blue'}
|
||||
this.form = {colorScheme, enableGreyFilter}
|
||||
}
|
||||
})
|
||||
},
|
||||
cancel() {
|
||||
return this.$router.push({})
|
||||
},
|
||||
submit() {
|
||||
this.$refs.ThemeForm.validate(v => {
|
||||
if (v) {
|
||||
let {colorScheme} = this.form
|
||||
colorScheme = JSON.stringify(colorScheme)
|
||||
this.instance.post("/app/appdvcpconfig/updateSysColorScheme", {...this.form, colorScheme}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("保存成功!")
|
||||
this.cancel().then(() => location.reload())
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getDetail()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.themeSetting {
|
||||
height: 100%;
|
||||
|
||||
.mar-r8 {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
443
core/apps/AppRightsManager/AppRightsManager.vue
Normal file
443
core/apps/AppRightsManager/AppRightsManager.vue
Normal file
@@ -0,0 +1,443 @@
|
||||
<template>
|
||||
<section class="AppRightsManager">
|
||||
<ai-list v-if="!showDetail">
|
||||
<ai-title slot="title" title="权限管理" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<ai-select placeholder="请选择应用" v-model="search.appId" :selectList="appList"
|
||||
@change="searchList"/>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
size="small"
|
||||
v-model="search.roleName"
|
||||
placeholder="角色名称"
|
||||
clearable
|
||||
@change="searchList()"
|
||||
suffix-icon="iconfont iconSearch"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button size="small" type="primary" icon="iconfont iconAdd"
|
||||
@click="$router.push({hash:'#add'})"
|
||||
v-if="$permissions('admin_sysapprole_add')">
|
||||
添加
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
icon="iconfont iconDelete"
|
||||
:disabled="!multipleSelection.length"
|
||||
class="del-btn-list"
|
||||
@click="deleteApp('all')"
|
||||
v-if="$permissions('admin_sysapprole_del')"
|
||||
>删除
|
||||
</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="adminList" :colConfigs="colConfigs" :total="total" :current.sync="page.pageNum"
|
||||
:size.sync="page.pageSize"
|
||||
@getList="getTableData" :col-configs="colConfigs" :dict="dict"
|
||||
@selection-change="v=>multipleSelection=v">
|
||||
<el-table-column label="角色用户" slot="users" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tooltip
|
||||
effect="light"
|
||||
placement="top"
|
||||
:disabled="scope.row.users.length <= 2"
|
||||
content="更多角色用户请点击详情按钮">
|
||||
<span v-if="scope.row.users.length">
|
||||
{{
|
||||
scope.row.users
|
||||
.slice(0, 2)
|
||||
.map((e) => e.name + "(" + e.phone + ")")
|
||||
.join(";")
|
||||
}}
|
||||
<span v-if="scope.row.users.length > 2">...</span>
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" fixed="right" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-button type="text" @click="beforeCopy(row)" v-if="$permissions('admin_sysapprole_edit')">复制
|
||||
</el-button>
|
||||
<el-button type="text" @click="viewApp(row)" v-if="$permissions('admin_sysapprole_detail')">详情
|
||||
</el-button>
|
||||
<el-button type="text" @click="openRightsGraph(row)" v-if="$permissions('admin_sysapprole_detail')">关系图
|
||||
</el-button>
|
||||
<el-button type="text" @click="toAddAppRole(row)" v-if="$permissions('admin_sysapprole_edit')">编辑
|
||||
</el-button>
|
||||
<el-button type="text" @click="deleteApp(row)" v-if="$permissions('admin_sysapprole_del')">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<ai-dialog
|
||||
title="应用角色详情"
|
||||
:visible.sync="viewShow"
|
||||
width="600px"
|
||||
customFooter>
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="应用角色名称" :value="viewInfo.name"/>
|
||||
<ai-info-item label="应用名称" :value="viewInfo.appName"/>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="权限信息">
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item :label="viewInfo.appName" isLine>
|
||||
{{ roleList.map(e => e.label).join('、') }}
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="角色账号">
|
||||
<template #right>
|
||||
<span style="text-align: right; color: #999"
|
||||
>共<span
|
||||
style="color: #26f"
|
||||
v-text="userList.length"
|
||||
/>个账号</span
|
||||
>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="datail-table-body" v-if="userList.length">
|
||||
<div class="datail-item" v-for="(item, index) in userList" :key="index">
|
||||
<span class="item-name">{{ item.name }}</span>
|
||||
<span style="color: #999">{{ item.phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<template #footer>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="toAddAppRole(viewInfo)"
|
||||
v-if="$permissions('admin_sysapprole_edit')"
|
||||
>编辑角色
|
||||
</el-button>
|
||||
</template>
|
||||
</ai-dialog>
|
||||
<ai-dialog title="权限关系图" :visible.sync="rightsGraph" class="rightsGraphDialog" customFooter>
|
||||
<rights-graph :instance="instance" :dict="dict" :app="selectApp"/>
|
||||
<el-button slot="footer" @click="rightsGraph=false">关闭</el-button>
|
||||
</ai-dialog>
|
||||
<!--复制角色-->
|
||||
<el-dialog
|
||||
class="editStyle"
|
||||
:visible.sync="copyDialog"
|
||||
width="520px"
|
||||
@close="dataInit()"
|
||||
title="复制角色">
|
||||
<el-form :model="form" label-width="80px">
|
||||
<el-form-item label="角色名" :rules="[{ required: true, message: '', trigger: 'blur' }]">
|
||||
<el-input
|
||||
v-model="editName"
|
||||
placeholder="请输入..."
|
||||
size="small"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" style="text-align: center">
|
||||
<el-button
|
||||
style="width: 92px"
|
||||
size="small"
|
||||
@click="copyDialog = false"
|
||||
>取消
|
||||
</el-button
|
||||
>
|
||||
<el-button
|
||||
style="width: 92px"
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="copyFn()"
|
||||
:disabled="!editName"
|
||||
>
|
||||
确认
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
<rights-add v-else :instance="instance" :dict="dict" :permissions="permissions"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RightsAdd from "./rightsAdd";
|
||||
import RightsGraph from "./rightsGraph";
|
||||
|
||||
export default {
|
||||
name: "AppRightsManager",
|
||||
components: {RightsGraph, RightsAdd},
|
||||
label: "权限管理",
|
||||
provide() {
|
||||
return {
|
||||
top: this
|
||||
}
|
||||
},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
actions: {
|
||||
default: () => ({
|
||||
list: '/admin/role-app/page',
|
||||
apps: '/admin/role-app/list-all',
|
||||
delete: '/admin/role-app/del',
|
||||
detail: '/admin/role-app/queryById-checked',
|
||||
modify: '/admin/role-app/modify',
|
||||
})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
colConfigs() {
|
||||
return [
|
||||
{type: "selection"},
|
||||
{label: "应用", prop: "appName", width: '120px'},
|
||||
{label: "角色名", prop: "name", width: '100px'},
|
||||
{label: "用户数量", prop: "roleCount", align: 'center', width: '80px'},
|
||||
{slot: "users"},
|
||||
{slot: "options"}
|
||||
]
|
||||
},
|
||||
showDetail() {
|
||||
return this.$route.hash == "#add"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page: {pageNum: 1, pageSize: 10},
|
||||
search: {appId: '', roleName: ''},
|
||||
adminList: [], //列表数据
|
||||
total: 0,
|
||||
appList: [], //下拉选择列表
|
||||
multipleSelection: [],
|
||||
delShow: false,
|
||||
delParams: "",
|
||||
delIds: [],
|
||||
viewShow: false,
|
||||
viewInfo: {},
|
||||
roleList: [], //详情权限列表
|
||||
row: {},
|
||||
copyDialog: false,
|
||||
titleDel: "",
|
||||
form: {},
|
||||
editName: "",
|
||||
userList: [],
|
||||
rightsGraph: false,
|
||||
selectApp: {}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getTableData();
|
||||
this.getAppList();
|
||||
},
|
||||
methods: {
|
||||
//查询table列表
|
||||
getTableData() {
|
||||
this.adminList = [];
|
||||
this.instance.post(this.actions.list, null, {
|
||||
params: {...this.page, ...this.search}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.total = res.data.total;
|
||||
this.adminList = res.data.records;
|
||||
}
|
||||
})
|
||||
},
|
||||
//查询下拉列表
|
||||
getAppList() {
|
||||
this.instance.post(this.actions.apps).then(res => {
|
||||
if (res?.data) {
|
||||
this.appList = res.data?.map(e => ({dictName: e.name, dictValue: e.id}))
|
||||
}
|
||||
})
|
||||
},
|
||||
//查询
|
||||
searchList() {
|
||||
this.page.pageNum = 1;
|
||||
this.getTableData();
|
||||
},
|
||||
//添加按钮
|
||||
toAddAppRole(item) {
|
||||
this.$router.push({
|
||||
hash: "#add",
|
||||
query: {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
appId: item.appId,
|
||||
},
|
||||
});
|
||||
},
|
||||
//删除
|
||||
deleteApp(e) {
|
||||
if (e == "all") {
|
||||
this.multipleSelection.map((item) => {
|
||||
this.delIds.push(item.id);
|
||||
});
|
||||
this.delParams = `ids=${this.delIds}`;
|
||||
this.titleDel = "确定要执行删除操作吗?";
|
||||
} else {
|
||||
this.delParams = `ids=${e.id}`;
|
||||
this.titleDel = "确定需要删除该角色吗?";
|
||||
}
|
||||
this.$confirm(this.titleDel, {
|
||||
type: "error",
|
||||
}).then(() => {
|
||||
this.instance.post(`${this.actions.delete}?${this.delParams}`).then(res => {
|
||||
if (res?.msg == "success") {
|
||||
this.getTableData();
|
||||
} else {
|
||||
this.$message.error(res.msg);
|
||||
}
|
||||
});
|
||||
}).catch(() => 0);
|
||||
},
|
||||
//查看信息
|
||||
viewApp(e) {
|
||||
this.userList = e.users;
|
||||
this.viewInfo = e;
|
||||
this.viewShow = true;
|
||||
this.getRowInfo(this.viewInfo.appId, this.viewInfo.id);
|
||||
},
|
||||
//查询 row 信息
|
||||
getRowInfo(appId, id) {
|
||||
this.roleList = [];
|
||||
this.instance.post(`${this.actions.detail}?id=${appId}&roleId=${id}`)
|
||||
.then(res => {
|
||||
if (res?.data) {
|
||||
this.roleList = res.data.list.filter(e => e.checked)
|
||||
}
|
||||
})
|
||||
},
|
||||
//复制
|
||||
beforeCopy(row) {
|
||||
this.row = row;
|
||||
this.copyDialog = true;
|
||||
this.getRowInfo(this.row.appId, this.row.id);
|
||||
},
|
||||
//确认复制
|
||||
copyFn() {
|
||||
let crr = [];
|
||||
let appRoleList = this.roleList;
|
||||
for (let i = 0; i < appRoleList.length; i++) {
|
||||
if (appRoleList[i].checked) {
|
||||
crr.push(appRoleList[i].id);
|
||||
if (appRoleList[i].list.length) {
|
||||
for (let j = 0; j < appRoleList[i].list.length; j++) {
|
||||
if (appRoleList[i].list[j].checked) {
|
||||
crr.push(appRoleList[i].list[j].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.instance.post(`${this.actions.modify}?menus=${crr}`, null, {
|
||||
params: {
|
||||
roleName: this.editName,
|
||||
appId: this.row.appId,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message({message: "复制成功", type: "success"});
|
||||
this.copyDialog = false;
|
||||
this.searchList()
|
||||
}
|
||||
});
|
||||
},
|
||||
dataInit() {
|
||||
this.multipleSelection = [];
|
||||
this.row = {};
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
openRightsGraph(row) {
|
||||
this.rightsGraph = true
|
||||
this.selectApp = row
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppRightsManager {
|
||||
height: 100%;
|
||||
|
||||
|
||||
::v-deep .ai-dialog {
|
||||
.ai-card {
|
||||
box-shadow: none;
|
||||
border: 1px solid #eee;
|
||||
|
||||
.aibar {
|
||||
height: 40px;
|
||||
background: #f3f6f9;
|
||||
}
|
||||
|
||||
.ai-card__body {
|
||||
padding: 0 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .rightsGraphDialog {
|
||||
.el-dialog__body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ai-dialog__content {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .datail-table-body {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.datail-item {
|
||||
flex-shrink: 0;
|
||||
width: 50%;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
width: 102px;
|
||||
padding-left: 16px;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.datail-item:nth-of-type(2n - 1) {
|
||||
border-right: 1px solid rgba(208, 212, 220, 1);
|
||||
width: calc(50% - 1px);
|
||||
}
|
||||
}
|
||||
|
||||
.padd-l0 {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
.pad-l16 {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
</style>
|
||||
195
core/apps/AppRightsManager/rightsAdd.vue
Normal file
195
core/apps/AppRightsManager/rightsAdd.vue
Normal file
@@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<ai-detail class="rightsAdd">
|
||||
<ai-title :title="addTitle" slot="title" isShowBottomBorder isShowBack @onBackClick="back"/>
|
||||
<template #content>
|
||||
<el-form size="small" ref="rightsForm" :model="form" label-width="120px" :rules="rules">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form-item label="应用角色名称" prop="roleName">
|
||||
<el-input v-model="form.roleName" placeholder="请输入应用角色名称" clearable/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="权限信息">
|
||||
<template #content>
|
||||
<el-form-item label="应用" prop="appId">
|
||||
<ai-select placeholder="请选择应用" v-model="form.appId" :selectList="top.appList"
|
||||
@change="getPermissions"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限列表" prop="menus" v-if="form.appId">
|
||||
<div class="roleList">
|
||||
<el-input v-model="filterText" placeholder="请输入..." clearable suffix-icon="iconfont iconSearch"
|
||||
@change="$refs.tree.filter(filterText)" :validate-event="false"/>
|
||||
<div class="tree_list">
|
||||
<el-tree class="filter-tree" ref="roleTree"
|
||||
:data="roleList"
|
||||
show-checkbox
|
||||
:props="defaultProps"
|
||||
default-expand-all
|
||||
:check-strictly="false"
|
||||
node-key="id"
|
||||
:default-checked-keys="form.menus"
|
||||
:filter-node-method="filterNode"
|
||||
@check="handleMenusSelect"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</ai-card>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="back()">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">保存</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "rightsAdd",
|
||||
inject: ['top'],
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
roleName: '',
|
||||
id: '',
|
||||
appList: [],
|
||||
roleList: [],
|
||||
defaultProps: {
|
||||
children: 'list',
|
||||
label: 'name'
|
||||
},
|
||||
treeList: [],
|
||||
filterText: '',
|
||||
msgTitle: '添加',
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.isEdit) {
|
||||
let {id, appId, name: roleName} = this.$route.query
|
||||
this.form = {appId, menus: [], id, roleName}
|
||||
this.getPermissions()
|
||||
this.msgTitle = '编辑'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isEdit() {
|
||||
return this.$route.query.id
|
||||
},
|
||||
addTitle() {
|
||||
return this.isEdit ? '编辑应用角色' : '新增应用角色'
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
roleName: {required: true, message: '请输入应用角色名称'},
|
||||
appId: {required: true, message: '请选择应用'},
|
||||
menus: {required: true, message: '请选择权限列表内容'},
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data.name.indexOf(value) !== -1;
|
||||
},
|
||||
//应用名称选择 获取权限列表
|
||||
getId(data) {
|
||||
if (data.list.length) {
|
||||
data.list.forEach(item => {
|
||||
this.getId(item)
|
||||
})
|
||||
} else {
|
||||
if (data.checked) {
|
||||
this.form.menus?.push(data.id)
|
||||
}
|
||||
}
|
||||
},
|
||||
getPermissions() {
|
||||
this.filterText = ''
|
||||
let {appId: id, id: roleId} = this.form
|
||||
this.instance.post(this.top.actions.detail, null, {
|
||||
params: {id, roleId}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.roleList = [res.data];
|
||||
if (this.isEdit) {
|
||||
this.roleList.forEach(e => this.getId(e))
|
||||
}
|
||||
this.roleList = this.roleList.filter(item => !(item.component && item.isApp == 0 && item.isMenu == 0))
|
||||
}
|
||||
})
|
||||
},
|
||||
handleMenusSelect(node, selected) {
|
||||
this.$set(this.form, 'menus', [...selected?.checkedKeys])
|
||||
this.$refs.rightsForm.validateField('menus')
|
||||
},
|
||||
//保存提交
|
||||
confirm() {
|
||||
this.$refs.rightsForm.validate(v => {
|
||||
if (v) {
|
||||
let menus = [this.$refs.roleTree?.getHalfCheckedKeys(), this.$refs.roleTree?.getCheckedKeys()]?.flat()?.toString()
|
||||
this.instance.post(this.top.actions.modify, null, {
|
||||
params: {...this.form, menus}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success(`${this.msgTitle}应用角色成功`)
|
||||
this.back()
|
||||
this.top.searchList()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
//取消 返回
|
||||
back() {
|
||||
this.$router.push({})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.rightsAdd {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
.el-form-item {
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.is-error {
|
||||
.roleList {
|
||||
border-color: #f46;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.roleList {
|
||||
background-color: #fcfcfc;
|
||||
border-radius: 2px;
|
||||
border: solid 1px #d0d4dc;
|
||||
padding: 8px;
|
||||
|
||||
.input {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 5px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tree_list {
|
||||
padding: 5px;
|
||||
height: 370px;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
192
core/apps/AppRightsManager/rightsGraph.vue
Normal file
192
core/apps/AppRightsManager/rightsGraph.vue
Normal file
@@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<section class="rightsGraph">
|
||||
<div id="RightGraph"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from "echarts";
|
||||
|
||||
export default {
|
||||
name: "rightsGraph",
|
||||
inject: ['top'],
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
app: Object
|
||||
},
|
||||
computed: {
|
||||
graphData() {
|
||||
let data = [...this.users, ...this.nodes].map(e => {
|
||||
if (e.x) {
|
||||
return e
|
||||
} else return {...e, ...this.renderPosition(e)}
|
||||
})
|
||||
return [
|
||||
{
|
||||
data,
|
||||
links: this.links,
|
||||
categories: data.map(e => e.category).flat().map(name => ({name}))
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
graph: null,
|
||||
nodes: [],
|
||||
links: [],
|
||||
users: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
graphData: {
|
||||
deep: true, handler() {
|
||||
this.refreshGraph()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initGraph() {
|
||||
let dom = document.querySelector("#RightGraph")
|
||||
if (dom) {
|
||||
this.graph = echarts.init(dom)
|
||||
this.graph.setOption({
|
||||
tooltip: {},
|
||||
series: [
|
||||
{
|
||||
type: 'graph',
|
||||
layout: 'none',
|
||||
roam: true,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'right',
|
||||
formatter: '{b}'
|
||||
},
|
||||
labelLayout: {
|
||||
hideOverlap: true,
|
||||
},
|
||||
scaleLimit: {
|
||||
min: 0.4,
|
||||
max: 4
|
||||
},
|
||||
lineStyle: {
|
||||
color: 'target',
|
||||
curveness: 0.1
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'adjacency',
|
||||
lineStyle: {
|
||||
width: 5
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
this.graph.on('click', this.handleNodeClick)
|
||||
}
|
||||
},
|
||||
refreshGraph() {
|
||||
this.graph?.setOption({
|
||||
series: this.graphData
|
||||
})
|
||||
},
|
||||
getAppRoles(role) {
|
||||
if (role) {
|
||||
this.nodes.push({...role, category: '应用角色', value: "应用角色", symbolSize: 15})
|
||||
} else this.instance.post(this.top.actions.list, null, {
|
||||
params: {pageSize: 999}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
res.data.records.map(e => {
|
||||
this.getUsers(e.users, e.id)
|
||||
this.nodes.push({...e, category: '应用角色', value: "应用角色"})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
getUsers(pending, source) {
|
||||
pending?.map(e => {
|
||||
if (!this.users.some(u => u.id == e.phone)) {
|
||||
this.users.push({id: e.phone, name: e.name, symbolSize: 5, category: '用户', value: "用户"})
|
||||
}
|
||||
this.links.push({source, target: e.phone})
|
||||
})
|
||||
},
|
||||
getPermissions({appId: id, id: roleId, name: category, dataIndex}) {
|
||||
const addNodes = (list, source, category, pos) => {
|
||||
list?.map(e => {
|
||||
let node = {
|
||||
...e,
|
||||
symbolSize: 5,
|
||||
category,
|
||||
value: e.list?.length > 0 ? "应用" : "权限",
|
||||
}
|
||||
node = {...node, ...this.renderPosition(pos || node)}
|
||||
this.nodes.splice(dataIndex, 0, node)
|
||||
this.links.push({source, target: e.id})
|
||||
addNodes(e.list, e.id, e.label, node)
|
||||
})
|
||||
}
|
||||
id && this.instance.post(this.top.actions.detail, null, {
|
||||
params: {id, roleId}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
addNodes(res.data.list, roleId, category)
|
||||
}
|
||||
})
|
||||
},
|
||||
handleNodeClick(v) {
|
||||
let {data: role, dataIndex} = v
|
||||
if (!this.nodes.some(e => e.category == role?.name)) {
|
||||
role && this.getPermissions({...role, dataIndex})
|
||||
}
|
||||
},
|
||||
renderPosition(node) {
|
||||
node = JSON.parse(JSON.stringify(node))
|
||||
let pos = {x: 0, y: 0}
|
||||
if (node?.x) {
|
||||
pos.x = Math.max(this.graph?.getWidth() / 3 * 2, node.x) + 100 + Math.random() * 50
|
||||
pos.y = node.y + Math.random() * 100 - 50
|
||||
} else if (node.value == '应用角色') {
|
||||
pos.x = this.graph?.getWidth() / 3 - 200 + Math.random() * 200
|
||||
pos.y = this.graph?.getHeight() / 2 - 100 + Math.random() * 200
|
||||
} else if (node.value == '应用') {
|
||||
pos.x = this.graph?.getWidth() / 3 * 2 - 100 + Math.random() * 100
|
||||
pos.y = Math.random() * this.graph?.getHeight()
|
||||
} else if (node.value == '用户') {
|
||||
pos.x = Math.random() * 50
|
||||
pos.y = Math.random() * this.graph?.getHeight()
|
||||
} else {
|
||||
pos.x = this.graph?.getWidth() - 100 + Math.random() * 100
|
||||
pos.y = Math.random() * this.graph?.getHeight()
|
||||
}
|
||||
return pos
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getAppRoles(this.app)
|
||||
if (this.app?.id) {
|
||||
this.getUsers(this.app.users, this.app.id)
|
||||
this.getPermissions(this.app)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.initGraph()
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rightsGraph {
|
||||
height: 100%;
|
||||
|
||||
::v-deep #RightGraph {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 500px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
211
core/apps/AppSystemAccount/AppSystemAccount.vue
Normal file
211
core/apps/AppSystemAccount/AppSystemAccount.vue
Normal file
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<section class="AppSystemAccount">
|
||||
<ai-list>
|
||||
<ai-title slot="title" title="账号管理" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="dialog=true">添加</el-button>
|
||||
<!-- <el-button type="primary" :disabled="!ids.toString()" @click="batchAllot">功能分配</el-button>-->
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" placeholder="搜索姓名、手机号" v-model="search.condition" clearable
|
||||
@change="page.pageNum=1,getTableData()"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.pageNum" :size.sync="page.pageSize"
|
||||
@getList="getTableData" :col-configs="colConfigs" :dict="dict"
|
||||
@selection-change="v=>ids=v.map(e=>e.id)">
|
||||
<el-table-column slot="name" label="姓名" width="180px">
|
||||
<el-row type="flex" align="middle" slot-scope="{row}">
|
||||
<el-image class="avatar" :src="row.avatar" :preview-src-list="[row.avatar]">
|
||||
<el-image slot="error" src="https://cdn.cunwuyun.cn/dvcp/h5/defaultAvatar.png" alt=""/>
|
||||
</el-image>
|
||||
<div>{{ row.name }}</div>
|
||||
</el-row>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" align="center" label="操作" fixed="right" width="160px">
|
||||
<el-row type="flex" justify="center" align="middle" slot-scope="{row}">
|
||||
<el-button type="text" @click="appAllot(row)">功能分配</el-button>
|
||||
<el-button type="text" @click="handleDelete(row.id)">删除</el-button>
|
||||
</el-row>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<!--添加账号、功能分配-->
|
||||
<ai-dialog :title="dialogTitle" :visible.sync="dialog" width="600px" @open="initDialogData"
|
||||
@onConfirm="updateAccount" @closed="dialogForm={}">
|
||||
<el-form ref="updateAccountForm" :model="dialogForm" :rules="rules" size="small"
|
||||
label-width="120px">
|
||||
<el-form-item required label="姓名" prop="name">
|
||||
<el-input v-model.trim="dialogForm.name" placeholder="请输入..." clearable
|
||||
:maxLength="15"/>
|
||||
</el-form-item>
|
||||
<el-form-item required label="手机号码" prop="phone">
|
||||
<el-input v-model.trim="dialogForm.phone" placeholder="请输入..." clearable
|
||||
:maxLength="11" :disabled="isEdit"/>
|
||||
</el-form-item>
|
||||
<el-form-item required label="角色" prop="roleId">
|
||||
<el-select size="small" placeholder="请选择角色" :value="dialogForm.roleId" filterable
|
||||
v-model="dialogForm.roleId" clearable>
|
||||
<el-option v-for="(op,i) in accountRoles" :key="i" :label="op.name" :value="op.id"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="行政地区" prop="areaId">
|
||||
<ai-area-get v-model="dialogForm.areaId" :instance="instance" @select="handleAreaSelect"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "AppSystemAccount",
|
||||
label: "账号管理",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
cascaderProps() {
|
||||
return {
|
||||
value: 'id',
|
||||
checkStrictly: true,
|
||||
emitPath: false
|
||||
}
|
||||
},
|
||||
isEdit() {
|
||||
return !!this.dialogForm.id
|
||||
},
|
||||
dialogTitle() {
|
||||
return this.isEdit ? '功能分配' : '添加账号'
|
||||
},
|
||||
colConfigs() {
|
||||
return [
|
||||
// {type: 'selection', align: 'center'},
|
||||
{label: "姓名", slot: "name"},
|
||||
{label: "联系方式", prop: "phone", align: 'center'},
|
||||
{label: "角色", prop: "roleName", align: 'center'},
|
||||
{label: "地区", prop: "areaName"},
|
||||
{slot: "options"}
|
||||
]
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
name: [{required: true, message: "请填写姓名"}],
|
||||
// organizationId: [{required: true, message: "请选择党组织"}],
|
||||
// unitId: [{required: true, message: "请选择单位"}],
|
||||
// areaId: [{required: true, message: '请选择地区', trigger: 'change'}],
|
||||
roleId: [{required: true, message: "请选择角色"}],
|
||||
phone: [{required: true, message: "请输入手机号码"}]
|
||||
}
|
||||
},
|
||||
disabledLevel() {
|
||||
return this.user.info.areaList?.length || 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
accountRoles: [],
|
||||
page: {pageNum: 1, pageSize: 10, total: 0},
|
||||
dialog: false,
|
||||
dialogForm: {},
|
||||
tableData: [],
|
||||
search: {condition: ""},
|
||||
ids: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getTableData() {
|
||||
this.instance.post("/admin/user/page", null, {
|
||||
params: {...this.page, ...this.search}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data?.records
|
||||
this.page.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
initDialogData() {
|
||||
//用于优化初始化数据
|
||||
this.getAccountRoles()
|
||||
},
|
||||
getAccountRoles() {
|
||||
this.accountRoles.length == 0 && this.instance.post("/admin/role/list-all").then(res => {
|
||||
if (res?.data) {
|
||||
this.accountRoles = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
batchAllot() {
|
||||
this.dialog = true
|
||||
this.dialogForm = {areaId: this.user.info.areaId, ids: this.ids}
|
||||
},
|
||||
appAllot(row) {
|
||||
this.dialog = true
|
||||
this.dialogForm = JSON.parse(JSON.stringify({
|
||||
...row,
|
||||
areaId: row.areaId || this.user.info.areaId
|
||||
}));
|
||||
},
|
||||
// 修改
|
||||
updateAccount() {
|
||||
this.$refs.updateAccountForm.validate(v => {
|
||||
if (v) {
|
||||
this.instance.post("/admin/user/addOrEdit", this.dialogForm).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.dialog = false;
|
||||
this.$message.success("提交成功")
|
||||
this.getTableData();
|
||||
} else {
|
||||
this.$message.error(res?.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(ids) {
|
||||
this.$confirm("是否要删除该账号?").then(() => {
|
||||
this.instance.post("/admin/user/del", null, {
|
||||
params: {ids}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.getTableData();
|
||||
this.$message.success("删除成功!");
|
||||
}
|
||||
})
|
||||
}).catch(() => 0)
|
||||
},
|
||||
handleAreaSelect(v) {
|
||||
this.dialogForm.areaName = v?.[0]?.label
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTableData()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppSystemAccount {
|
||||
height: 100%;
|
||||
|
||||
::v-deep .avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
::v-deep .el-form {
|
||||
.el-cascader, .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
193
core/apps/AppUserInfo/AppUserInfo.vue
Normal file
193
core/apps/AppUserInfo/AppUserInfo.vue
Normal file
@@ -0,0 +1,193 @@
|
||||
<template>
|
||||
<section class="AppUserInfo">
|
||||
<ai-detail>
|
||||
<ai-title slot="title" title="个人中心" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<ai-card title="个人资料">
|
||||
<template #right>
|
||||
<span style="color:#999" v-text="'(如需修改基本信息,请联系管理员)'"/>
|
||||
</template>
|
||||
<template #content>
|
||||
<el-row type="flex" justify="space-between">
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="姓名" :value="user.info.name"/>
|
||||
<ai-info-item label="手机号码" :value="user.info.phone"/>
|
||||
<ai-info-item label="角色" :value="user.info.roleName"/>
|
||||
<ai-info-item label="部门" :value="user.info.departName"/>
|
||||
<ai-info-item label="职位" :value="user.info.position"/>
|
||||
</ai-wrapper>
|
||||
<ai-avatar :value="user.info.avatar" :editable="false"/>
|
||||
</el-row>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="数据权限">
|
||||
<template #right>
|
||||
<span style="color:#999" v-text="'(如需修改基本信息,请联系管理员)'"/>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="所属地区" :value="user.info.areaList.join('')" isLine/>
|
||||
<ai-info-item label="所属党组织" :value="user.info.organizationName" isLine/>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="密码设置">
|
||||
<template #right>
|
||||
<el-button type="text" @click="submitForm">保存</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<el-form :model="form" ref="ruleForm" :rules="rules" label-width="100px" size="small">
|
||||
<el-form-item label="绑定手机:" prop="phone">
|
||||
<el-row type="flex" align="middle">
|
||||
<span>{{ user.info.phone }}</span>
|
||||
<el-button type="primary" style="margin-left: 8px" @click="getCode(user.info.phone,true)"
|
||||
:disabled="codeBtn">获取验证码
|
||||
<span v-if="num>0&&codeBtn" style="color:red;">({{ num }}s)</span>
|
||||
</el-button>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item label="验证码:" prop="code">
|
||||
<el-input v-model.trim="form.code" clearable placeholder="请输入短信验证码"/>
|
||||
<el-input style="position: fixed; bottom: -9999px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码:" prop="pass">
|
||||
<el-input type="password" auto-complete="new-password" v-model.trim="form.pass" clearable
|
||||
placeholder="8-16位,需要包含字母和数字及特殊字符(~!@#$%^&*,.?_-)"
|
||||
show-password/>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码:" prop="checkPass">
|
||||
<el-input type="password" auto-complete="new-password" placeholder="再次输入密码"
|
||||
v-model.trim="form.checkPass" clearable
|
||||
show-password/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapMutations, mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "AppUserInfo",
|
||||
label: "个人中心",
|
||||
props: {
|
||||
instance: Function,
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
rules() {
|
||||
const validatePass = (rule, value, callback) => {
|
||||
const reg = /^(?=.*\d)(?=.*[a-zA-Z])(?=.*[~!@#$%^&*,.?_-])[\da-zA-Z~!@#$%^&*,.?_-]{8,16}$/;
|
||||
if (!reg.test(value)) {
|
||||
callback(new Error('数字和字母及特殊字符(~!@#$%^&*,.?_-)组合,长度8到16位'));
|
||||
} else {
|
||||
if (this.form.checkPass !== '') {
|
||||
this.$refs.ruleForm.validateField('checkPass');
|
||||
}
|
||||
callback();
|
||||
}
|
||||
}
|
||||
return {
|
||||
currentPass: [
|
||||
{required: true, message: '请填写当前密码', trigger: 'blur'}
|
||||
],
|
||||
code: [
|
||||
{required: true, message: '请填写验证码', trigger: 'blur'}
|
||||
],
|
||||
pass: [
|
||||
{validator: validatePass, trigger: 'blur', required: true}
|
||||
],
|
||||
checkPass: [
|
||||
{
|
||||
validator: (r, v, cb) => v ? v != this.form.pass ? cb('两次输入密码不一致') : cb() : cb('请再次输入密码'),
|
||||
trigger: 'blur',
|
||||
required: true
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
timer: null,
|
||||
codeBtn: false,
|
||||
num: 60,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SignOut']),
|
||||
getCode(phone, flag) {
|
||||
const TEL_REGEXP = /^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\d{8}$/;
|
||||
if (TEL_REGEXP.test(phone)) {
|
||||
this.instance.post(`/admin/user/checkPhone`, null, {
|
||||
params: {phone, flag}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success("请查看手机短信!");
|
||||
this.timer = setInterval(() => {
|
||||
if (this.num > 0) {
|
||||
this.codeBtn = true;
|
||||
this.num--;
|
||||
} else if (this.num == 0) {
|
||||
this.codeBtn = false;
|
||||
this.num = 60;
|
||||
clearInterval(this.timer);
|
||||
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
} else {
|
||||
this.$message.error("验证码发送失败!");
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
} else {
|
||||
this.$message.error("手机号格式错误!");
|
||||
}
|
||||
|
||||
},
|
||||
submitForm() {
|
||||
this.$refs.ruleForm.validate(v => {
|
||||
if (v) {
|
||||
let {pass: newPwd, code} = this.form
|
||||
this.instance.post(`/admin/user/update-pwd`, null, {
|
||||
params: {
|
||||
phone: this.user.info.phone,
|
||||
newPwd, code
|
||||
}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$confirm("村微提醒您,更换密码成功!", {
|
||||
showCancelButton: false
|
||||
}).then(() => this.SignOut()).catch(() => 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppUserInfo {
|
||||
height: 100%;
|
||||
|
||||
::v-deep .ai-list__content--wrapper {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
::v-deep .el-input__inner {
|
||||
|
||||
-webkit-text-security: disc !important;
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
248
core/components/AiAddressBookMenu.vue
Normal file
248
core/components/AiAddressBookMenu.vue
Normal file
@@ -0,0 +1,248 @@
|
||||
<template>
|
||||
<section class="AiAddressBookMenu">
|
||||
<div class="tabsPane">
|
||||
<h2 v-for="tab in tabs" :key="tab.name" :class="{tabActive:current==tab.name}"
|
||||
@click="handleTabClick(tab)">{{ tab.label }}</h2>
|
||||
</div>
|
||||
<div class="contentPane">
|
||||
<el-input :placeholder="`请输入${currentTab.label}名称`"
|
||||
size="small" v-model="search" suffix-icon="iconfont iconSearch"
|
||||
@change="handleSearchChange"/>
|
||||
<div v-if="isTagType" class="addressBook-left__tags">
|
||||
<div @click="selected=item" v-for="(item, index) in tags" :key="index"
|
||||
class="addressBook-left__tags--item"
|
||||
:class="{'addressBook-left__tags--item-active':selected.id == item.id}">
|
||||
<span>{{ item.tagname }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="AiAddressBookMenu-wrapper" v-else>
|
||||
<div class="AiAddressBookMenu-tree">
|
||||
<el-tree
|
||||
ref="tree"
|
||||
node-key="id"
|
||||
highlight-current
|
||||
:filter-node-method="handleTreeFilter"
|
||||
:props="defaultProps" :data="list"
|
||||
:default-expanded-keys="treeRoot"
|
||||
@current-change="v=>selected=v">
|
||||
<div class="tree-container" slot-scope="{ data }">
|
||||
<span>{{ data.name }}</span>
|
||||
</div>
|
||||
</el-tree>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 通讯录选择器
|
||||
*/
|
||||
export default {
|
||||
name: "AiAddressBookMenu",
|
||||
props: {
|
||||
instance: Function,
|
||||
},
|
||||
computed: {
|
||||
tabs() {
|
||||
return [
|
||||
{label: "组织架构", name: 0},
|
||||
{label: "标签", name: 1}
|
||||
]
|
||||
},
|
||||
currentTab() {
|
||||
return this.tabs.find(e => e.name == this.current) || {}
|
||||
},
|
||||
isTagType() {
|
||||
return this.current == 1
|
||||
},
|
||||
defaultProps() {
|
||||
return {
|
||||
children: 'children',
|
||||
label: 'name'
|
||||
}
|
||||
},
|
||||
tags() {
|
||||
return this.list?.filter(e => !this.search || e.tagname?.indexOf(this.search) > -1)
|
||||
},
|
||||
treeRoot() {
|
||||
let root = this.list?.[0]
|
||||
return root ? [root?.id] : []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
current: 0,
|
||||
search: "",
|
||||
list: [],
|
||||
origin: [],
|
||||
selected: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selected(v) {
|
||||
v && this.$emit('select', {...v, type: this.current})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleTabClick(tab) {
|
||||
this.current = tab.name
|
||||
this.isTagType ? this.getTags() : this.getUnits()
|
||||
this.$emit('tabClick')
|
||||
},
|
||||
handleTreeFilter(v, data) {
|
||||
return data?.name?.indexOf(v) > -1
|
||||
},
|
||||
handleSearchChange(v) {
|
||||
if (this.isTagType) {
|
||||
} else {
|
||||
this.$refs.tree?.filter(v)
|
||||
}
|
||||
},
|
||||
handleTagClick(tag) {
|
||||
this.$emit('tag', tag)
|
||||
this.selected = tag
|
||||
},
|
||||
getUnits() {
|
||||
this.instance.post(`/app/wxcp/wxdepartment/listAll`).then(res => {
|
||||
if (res?.data) {
|
||||
this.list = res.data?.filter(e => !e.parentid)
|
||||
this.list.map(p => this.addChild(p, res.data, {parent: 'parentid'}))
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tree.setCurrentKey(res.data[0].id)
|
||||
this.$emit('select', res.data[0])
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
getTags() {
|
||||
this.instance.post(`/app/wxcp/wxtag/listAll`).then(res => {
|
||||
if (res?.data) {
|
||||
this.origin = JSON.parse(JSON.stringify(res.data))
|
||||
this.list = res?.data
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getUnits()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AiAddressBookMenu {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #FAFAFB;
|
||||
.tabsPane {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background: #ffffff;
|
||||
|
||||
h2 {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
line-height: 40px;
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-bottom: 2px solid transparent;
|
||||
|
||||
&.tabActive {
|
||||
color: #2266FF;
|
||||
border-bottom: 2px solid #2266FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.AiAddressBookMenu-wrapper {
|
||||
height: calc(100% - 32px);
|
||||
.AiAddressBookMenu-tree {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.contentPane {
|
||||
height: calc(100% - 56px);
|
||||
margin: 8px;
|
||||
overflow: auto;
|
||||
|
||||
.addressBook-left__tags--item {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 40px;
|
||||
padding: 0 8px 0 16px;
|
||||
color: #222222;
|
||||
|
||||
&.addressBook-left__tags--item-active, &:hover {
|
||||
background: #E8EFFF;
|
||||
color: #2266FF;
|
||||
|
||||
i, span {
|
||||
color: #2266FF;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
color: #8e9ebf;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
::v-deep .el-tree {
|
||||
width: 100%;
|
||||
margin-top: 4px;
|
||||
background: transparent;
|
||||
width: fit-content;
|
||||
min-width: 100%;
|
||||
|
||||
.el-tree-node__content {
|
||||
display: inline-flex;
|
||||
min-width: 100%;
|
||||
height: 32px;
|
||||
|
||||
&:hover {
|
||||
background: #E8EFFF;
|
||||
color: #222222;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.is-current > .el-tree-node__content {
|
||||
background: #2266FF;
|
||||
|
||||
&:hover {
|
||||
background: #2266FF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
35
core/components/AiDrag.vue
Normal file
35
core/components/AiDrag.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<section class="AiDrag">
|
||||
<vue-draggable-resizable v-bind="$attrs">
|
||||
<slot/>
|
||||
</vue-draggable-resizable>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import 'vue-draggable-resizable/dist/VueDraggableResizable.css'
|
||||
import VueDraggableResizable from 'vue-draggable-resizable'
|
||||
|
||||
export default {
|
||||
name: "AiDrag",
|
||||
components: {VueDraggableResizable},
|
||||
props: {
|
||||
type: {default: "show"} //show:只拖拽
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AiDrag {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
|
||||
::v-deep.vdr {
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
33
core/components/AiEditBtn.vue
Normal file
33
core/components/AiEditBtn.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<section class="AiEditBtn">
|
||||
<el-button v-if="!edit" type="text" @click="handleOper('edit')">编辑</el-button>
|
||||
<template v-else>
|
||||
<el-button type="text" @click="handleOper('submit')">保存</el-button>
|
||||
<el-button type="text" @click="handleOper('cancel')">取消</el-button>
|
||||
</template>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "AiEditBtn",
|
||||
data() {
|
||||
return {
|
||||
edit: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleOper(event) {
|
||||
if (event != "submit") {
|
||||
this.edit = !this.edit
|
||||
this.$emit(event)
|
||||
} else this.$emit(event, () => this.edit = !this.edit)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AiEditBtn {
|
||||
}
|
||||
</style>
|
||||
45
core/index.js
Normal file
45
core/index.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 系统业务模块
|
||||
* @param Vue 外部接入Vue
|
||||
* @param params showList:打印加载的应用;apps:加载的应用文件名数组
|
||||
*/
|
||||
|
||||
const install = function (Vue, params) {
|
||||
if (install.installed) return Promise.resolve()
|
||||
else {
|
||||
// 遍历工作控件内的应用
|
||||
let apps = []
|
||||
let contexts = require.context('.', true, /\.(\/.+)\/App[^\/]+\.vue$/)
|
||||
if (contexts) {
|
||||
contexts.keys().map(e => {
|
||||
if (contexts(e).default) {
|
||||
if (params?.apps) {
|
||||
if (params?.apps.includes(contexts(e).default.name)) {
|
||||
apps.push(contexts(e).default)
|
||||
Vue.component(contexts(e).default.name, contexts(e).default)
|
||||
}
|
||||
} else {
|
||||
apps.push(contexts(e).default)
|
||||
Vue.component(contexts(e).default.name, contexts(e).default)
|
||||
}
|
||||
}
|
||||
})
|
||||
// apps.map(e=>{
|
||||
// console.log(e.name,e.label)
|
||||
// })
|
||||
!!params?.showList && console.log(apps.map(e => e.name))
|
||||
}
|
||||
return Promise.resolve(apps)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 判断是否是直接引入文件
|
||||
if (typeof window !== 'undefined' && window.Vue) {
|
||||
install(window.Vue)
|
||||
}
|
||||
|
||||
export default {
|
||||
// 导出的对象必须具有 install,才能被 Vue.use() 方法安装
|
||||
install
|
||||
}
|
||||
12
core/package.json
Normal file
12
core/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "dvcp-core",
|
||||
"description": "系统业务模块",
|
||||
"version": "1.0.13",
|
||||
"main": "dist/dvcp-core.common.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"publishConfig": {
|
||||
"registry": "http://cli.sinoecare.net"
|
||||
}
|
||||
}
|
||||
122
examples/App.vue
Normal file
122
examples/App.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<header-nav v-if="showTools" title="web端产品库">
|
||||
<template #right>
|
||||
<div @click="showTools=false">隐藏工具栏</div>
|
||||
<div @click="handleLogin">点此登录</div>
|
||||
</template>
|
||||
</header-nav>
|
||||
<el-row class="fill mar-t48" type="flex">
|
||||
<slider-nav v-if="showTools"/>
|
||||
<main-content class="fill"/>
|
||||
</el-row>
|
||||
<div v-if="dialog" class="sign-box">
|
||||
<ai-sign style="margin: auto" :instance="$request" :action="{login}"
|
||||
visible @login="getToken" :showScanLogin="false"/>
|
||||
</div>
|
||||
<el-button type="info" v-if="!showTools" class="fixedBtn" @click="showTools=true">显示工具栏</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SliderNav from "./components/sliderNav";
|
||||
import MainContent from "./components/mainContent";
|
||||
import HeaderNav from "./components/headerNav";
|
||||
import {mapActions, mapMutations, mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {HeaderNav, MainContent, SliderNav},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
login() {
|
||||
let url = '/auth/oauth/token';
|
||||
/project\/sass/g.test(location.pathname) && (url += "?corpId=ww596787bb70f08288")
|
||||
return url
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: false,
|
||||
showTools: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setToken', 'setFinanceUser']),
|
||||
...mapActions(['getUserInfo']),
|
||||
getToken(params) {
|
||||
if (params.access_token) {
|
||||
this.setToken([params.token_type, params.access_token].join(' '))
|
||||
this.dialog = false
|
||||
this.$message.success("登录成功,正在刷新页面...")
|
||||
location.reload()
|
||||
} else this.$message.error(params.msg || "登录失败!")
|
||||
|
||||
},
|
||||
handleLogin() {
|
||||
this.$request.delete("/auth/token/logout").finally(() => {
|
||||
this.dialog = true
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
wx = jWeixin
|
||||
if (this.user.token) this.getUserInfo().then(() => {
|
||||
if (/^\/project\/xiushan/.test(location.pathname)) {
|
||||
this.setFinanceUser()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mar-t48 {
|
||||
margin-top: 48px;
|
||||
}
|
||||
|
||||
#app {
|
||||
font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
color: #2c3e50;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.fixedBtn {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 60px;
|
||||
opacity: 0;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.sign-box {
|
||||
z-index: 99;
|
||||
margin: -10px;
|
||||
display: flex;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
BIN
examples/assets/building.png
Normal file
BIN
examples/assets/building.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
examples/assets/file.png
Normal file
BIN
examples/assets/file.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
273
examples/components/headerNav.vue
Normal file
273
examples/components/headerNav.vue
Normal file
@@ -0,0 +1,273 @@
|
||||
<template>
|
||||
<div class="headerNav navBg">
|
||||
<div style="position: relative">
|
||||
<ai-icon type="logo" :icon="'iconcunwei'"/>
|
||||
<ai-icon type="logo" :icon="'iconcunwei'" class="textShadow"/>
|
||||
</div>
|
||||
<span class="headerTitle">{{ title }}<div class="textShadow" v-html="title"/></span>
|
||||
<el-row type="flex" align="middle" class="toolbar">
|
||||
<slot v-if="$slots.right" name="right"/>
|
||||
</el-row>
|
||||
<el-dropdown @visible-change="v=>isClick=v" @command="doMenu" class="rightDropdown">
|
||||
<el-row type="flex" align="middle">
|
||||
<el-avatar :src="user.info.avatar">
|
||||
{{ defaultAvatar }}
|
||||
</el-avatar>
|
||||
<span>{{ [user.info.name, user.info.roleName].join(" - ") }}</span>
|
||||
<i :class="dropdownIcon"/>
|
||||
</el-row>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="user">用户中心</el-dropdown-item>
|
||||
<el-dropdown-item command="signOut">退出</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: 'headerNav',
|
||||
props: {
|
||||
title: {default: ""}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isClick: false,
|
||||
drawer: false,//抽屉
|
||||
count: 0,
|
||||
filesList: [],
|
||||
fileName: '',
|
||||
badgeNum: 0,
|
||||
dvOptions: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
dropdownIcon() {
|
||||
return this.isClick ? 'el-icon-caret-top' : 'el-icon-caret-bottom'
|
||||
},
|
||||
defaultAvatar() {
|
||||
return this.user.info.name?.slice(-2) || "无名"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 获取最新的安卓、ios下载二维码
|
||||
doMenu(comm) {
|
||||
switch (comm) {
|
||||
case 'signOut':
|
||||
//登出
|
||||
this.$confirm("是否要登出?", {type: "warning"}).then(() => {
|
||||
this.$store.commit("SignOut")
|
||||
}).catch(() => {
|
||||
})
|
||||
break;
|
||||
case 'user':
|
||||
this.$router.push({name: "个人中心"})
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.headerNav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 48px;
|
||||
position: fixed;
|
||||
z-index: 99;
|
||||
height: 48px;
|
||||
padding-left: 24px;
|
||||
box-sizing: border-box;
|
||||
top: 0;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
|
||||
.AiIcon {
|
||||
font-size: 38px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
background: linear-gradient(180deg, #FFFFFF 0%, #CCDBF6 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.headerTitle {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 24px;
|
||||
color: #FFF;
|
||||
line-height: 28px;
|
||||
background: linear-gradient(180deg, #FFFFFF 0%, #CCDBF6 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
font-weight: bold;
|
||||
margin-left: 8px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.textShadow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
text-shadow: 0 2px 0 #384DC3;
|
||||
color: transparent;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
::v-deep.toolbar {
|
||||
gap: 12px;
|
||||
margin-right: 32px;
|
||||
|
||||
& > div {
|
||||
padding: 0 12px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: rgba(#fff, .8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-dropdown {
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
color: #fff;
|
||||
padding: 0 12px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(46, 51, 68, .15);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.el-image {
|
||||
margin: 12px 0 12px 16px;
|
||||
}
|
||||
|
||||
|
||||
.rightDropdown {
|
||||
font-size: 12px;
|
||||
padding: 0 16px;
|
||||
height: 48px;
|
||||
background: rgba(#fff, .1);
|
||||
|
||||
.el-row {
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .downLoad_main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.search_top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.infinite-list {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.infinite-list-item {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(208, 212, 220, 1);
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 30px;
|
||||
|
||||
.svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.middle {
|
||||
flex: 1;
|
||||
|
||||
.fileName {
|
||||
color: #333333;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
p:nth-child(2) {
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
|
||||
span {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
span:nth-child(2) {
|
||||
border-right: solid 1px #999999;
|
||||
}
|
||||
|
||||
span:nth-child(3) {
|
||||
border-right: solid 1px #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
width: 90px;
|
||||
text-align: center;
|
||||
|
||||
span {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
i {
|
||||
display: block;
|
||||
width: 50px;
|
||||
color: #5088FF;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #8888;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
163
examples/components/mainContent.vue
Normal file
163
examples/components/mainContent.vue
Normal file
@@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<section class="mainContent">
|
||||
<el-tabs class="layout" type="card" :value="currentTab" @tab-click="handleTabClick"
|
||||
@tab-remove="handleTabRemove">
|
||||
<el-tab-pane label="默认页" class="layoutItem">
|
||||
<ai-empty>欢迎使用村微产品库</ai-empty>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-for="op in tabs" :key="op.name" :closable="op.name!='工作台'" :name="op.name" :label="op.label" lazy>
|
||||
<router-view v-if="currentTab==op.name"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "mainContent",
|
||||
computed: {
|
||||
...mapState(['apps']),
|
||||
currentTab() {
|
||||
let {name, query, hash} = this.$route
|
||||
return [name?.replace(query?.id, ''), query?.id, hash].join("") || "0"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tabs: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
this.getTabs("route")
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleTabClick({name}) {
|
||||
let {name: route, query, hash} = this.tabs.find(e => e.name == name),
|
||||
exps = []
|
||||
query.id && exps.push(query.id)
|
||||
hash && exps.push(hash)
|
||||
let reg = new RegExp(`(${exps.join("|")})`, 'g')
|
||||
this.$router.push({name: route.replace(reg, ''), query, hash})
|
||||
},
|
||||
handleTabRemove(id = this.currentTab) {
|
||||
let tabs = JSON.parse(JSON.stringify(this.tabs)),
|
||||
index = tabs?.findIndex(e => id == e.name)
|
||||
if (id == this.currentTab) {
|
||||
let next = tabs?.[index + 1] || tabs?.[index - 1]
|
||||
next ? this.handleTabClick(next) : this.$router.push({path: '/'})
|
||||
}
|
||||
this.tabs.splice(index, 1)
|
||||
},
|
||||
getTabs(from) {
|
||||
let {name, query, hash} = this.$route
|
||||
console.log(`getTabs>>>>>>>>>%s>>>>>>>%s`, from, name)
|
||||
let tab = this.tabs.find(e => e.name == this.currentTab),
|
||||
tabName = [name, query?.id, hash].join("")
|
||||
if (tab) {
|
||||
} else if (!name) {
|
||||
} else if (tabName) {
|
||||
let menu = this.apps.find(e => e.name == name)
|
||||
this.tabs.push({name: tabName, query, hash, label: menu?.label})
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getTabs("created")
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mainContent {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
::v-deep.layout {
|
||||
height: 100%;
|
||||
background: #F5F6F9;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
& > .el-tabs__header {
|
||||
margin-bottom: 0;
|
||||
background: linear-gradient(180deg, #FCFCFC 0%, #E0E2E4 100%);
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
border: none;
|
||||
|
||||
.el-tabs__nav {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-tabs__item {
|
||||
padding: 0 8px 0 12px;
|
||||
text-align: left;
|
||||
min-width: 130px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
border: none;
|
||||
color: #555;
|
||||
font-size: 12px;
|
||||
|
||||
& + .el-tabs__item {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.el-icon-close {
|
||||
float: right;
|
||||
width: auto;
|
||||
height: 100%;
|
||||
line-height: 36px;
|
||||
background: transparent;
|
||||
font-size: 16px;
|
||||
color: #89b;
|
||||
|
||||
&:hover {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
border: 1px solid #D8DCE3;
|
||||
border-bottom: none;
|
||||
border-radius: 4px 4px 0 0;
|
||||
background: #F5F6F9;
|
||||
color: #222;
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
content: " ";
|
||||
width: 1px;
|
||||
background: #D8DCE3;
|
||||
height: 24px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-tabs__content {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
.el-tab-pane {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
262
examples/components/sliderNav.vue
Normal file
262
examples/components/sliderNav.vue
Normal file
@@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<section class="sliderNav">
|
||||
<el-input class="searchApp" size="small" v-model="searchApp" placeholder="搜索应用" clearable
|
||||
prefix-icon="iconfont iconSearch" @change="recordSearch"/>
|
||||
<el-scrollbar class="ai-menu">
|
||||
<div v-for="(item,i) in navs" :key="i">
|
||||
<div class="rootMenu" :class="{isActive:menuPath.includes(item.name)}"
|
||||
@click.stop="openKidMenu(item)">
|
||||
<i class="prep-icon" :class="item.style||'iconfont iconloudongmoxing'"/>
|
||||
<span class="menuName fill" v-text="item.label"/>
|
||||
<el-badge type="warning" :hidden="!item.project" :value="item.project"/>
|
||||
<i v-if="item.children" class="iconfont" :class="arrowIcon(item.showChildren)"/>
|
||||
</div>
|
||||
<div class="kidMenu" v-if="item.showChildren" @click.stop>
|
||||
<div class="kidPane">
|
||||
<div class="submenu wrap" flex v-for="menu in item.children" :key="menu.name">
|
||||
<b v-text="menu.label" :class="{menuBtn:menu.type==1,current:menuPath.includes(menu.name)}"
|
||||
@click="handleSelect(menu)"/>
|
||||
<div class="menuBtn" v-for="kid in menu.children" :key="kid.name" v-text="kid.label"
|
||||
@click="handleSelect(kid)"
|
||||
:class="{current:menuPath.includes(kid.name)}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider"/>
|
||||
</el-scrollbar>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "sliderNav",
|
||||
data() {
|
||||
return {
|
||||
searchApp: "",
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user', 'apps']),
|
||||
navs() {
|
||||
let reg = new RegExp(`.*${this.searchApp?.replace(/-/g,'')||''}.*`, 'gi')
|
||||
return (this.apps || []).filter(e => !this.searchApp || reg?.test(e.name) || reg?.test(e.label)).map(e => {
|
||||
if (/\/project\//.test(e.path)) {
|
||||
e.project = e.path.replace(/.*project\/([^\/]+)\/.+/, '$1')
|
||||
} else if (/\/core\//.test(e.path)) {
|
||||
e.project = "core"
|
||||
}
|
||||
return e
|
||||
})
|
||||
},
|
||||
isConsoleRoute() {
|
||||
return this.$route.name == "工作台"
|
||||
},
|
||||
menuPath() {
|
||||
let paths = [], current = this.apps?.find(e => e.name == this.$route.name)
|
||||
const findParent = name => {
|
||||
let menu = this.apps?.find(e => e.name == name)
|
||||
if (menu) {
|
||||
paths.push(menu.name)
|
||||
if (!!menu.parentId) findParent(menu.parentId)
|
||||
}
|
||||
}
|
||||
if (current) {
|
||||
findParent(current.name)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openKidMenu(parent) {
|
||||
if (parent.children) {
|
||||
parent.showChildren = !parent.showChildren
|
||||
} else {
|
||||
this.handleSelect(parent)
|
||||
}
|
||||
},
|
||||
handleSelect(item) {
|
||||
if (!item.path) return
|
||||
if (item.name == this.$route.name) {
|
||||
//避免同一路由跳转的BUG vue-router官方BUG
|
||||
} else {
|
||||
let {name, path} = item
|
||||
if (/\?app=/.test(path)) {
|
||||
this.goto({name, query: {app: path.replace(/.+\?app=/, '')}})
|
||||
} else if (/\?moduleId=/.test(path)) {
|
||||
this.goto({name, query: {moduleId: path.replace(/.+\?moduleId=/, '')}})
|
||||
} else {
|
||||
this.goto({name})
|
||||
}
|
||||
}
|
||||
},
|
||||
goto(item) {
|
||||
this.$router.push(item)
|
||||
},
|
||||
subMenuIcon(flag) {
|
||||
return flag ? 'iconfont iconArrow_Down' : "iconfont iconArrow_Right"
|
||||
},
|
||||
arrowIcon(v) {
|
||||
return v ? "iconArrow_Down" : "iconArrow_Right"
|
||||
},
|
||||
recordSearch() {
|
||||
localStorage.setItem("searchApp", this.searchApp)
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.searchApp = localStorage.getItem("searchApp") || ""
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.sliderNav {
|
||||
min-width: 200px;
|
||||
height: 100%;
|
||||
transition: width .1s;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
border-right: 1px solid #e5e5e5;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
background: #EFF1F4;
|
||||
color: #222;
|
||||
position: relative;
|
||||
|
||||
.kidMenu {
|
||||
padding: 0 16px;
|
||||
background: #EFF1F4;
|
||||
|
||||
.rootName {
|
||||
font-size: 20px;
|
||||
color: #333;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.kidPane {
|
||||
font-size: 13px;
|
||||
|
||||
.submenu {
|
||||
margin-top: 8px;
|
||||
width: 100%;
|
||||
color: #aaa;
|
||||
|
||||
& > b {
|
||||
width: 100%;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
& > * {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.menuBtn {
|
||||
display: block;
|
||||
width: 50%;
|
||||
cursor: pointer;
|
||||
line-height: 32px;
|
||||
color: #333;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:hover {
|
||||
color: #26f;
|
||||
}
|
||||
|
||||
&.current {
|
||||
color: #26f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rootMenu {
|
||||
padding: 0 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0px -1px 0px 0px #D8DCE3 inset, 0px 1px 0px 0px #FFF inset, -1px 0px 0px 0px #E5E5E5 inset;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
|
||||
.iconfont {
|
||||
color: #89B;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
&.isActive {
|
||||
color: #26f;
|
||||
|
||||
.iconfont {
|
||||
color: #26f !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #26f;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ai-menu {
|
||||
padding-left: 0;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
.el-scrollbar__wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .searchApp {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
padding: 0 16px;
|
||||
box-shadow: 0px -1px 0px 0px #E5E5E5 inset;
|
||||
|
||||
.el-input__inner {
|
||||
border: none;
|
||||
background: inherit;
|
||||
padding: 0 28px;
|
||||
}
|
||||
|
||||
.el-input__prefix {
|
||||
left: 16px;
|
||||
|
||||
.iconSearch {
|
||||
font-size: 20px;
|
||||
width: fit-content;
|
||||
color: #89B;
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
color: #aaa;
|
||||
border-top: 1px solid #ddd;
|
||||
position: relative;
|
||||
font-size: 12px;
|
||||
margin: 16px 16px 32px;
|
||||
|
||||
&:before {
|
||||
content: "到达底部";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 0 16px;
|
||||
background: #EFF1F4;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
34
examples/main.js
Normal file
34
examples/main.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import Vue from 'vue';
|
||||
import App from './App.vue';
|
||||
import ui from 'element-ui';
|
||||
import router from './router/router';
|
||||
import axios from './router/axios';
|
||||
import utils from './utils';
|
||||
import vcUI from 'dvcp-ui';
|
||||
import 'dvcp-ui/lib/styles/common.scss';
|
||||
import 'dvcp-ui/lib/dvcp-ui.css';
|
||||
import store from './store';
|
||||
import dataV from '@jiaminghi/data-view';
|
||||
import dvui from '../project/dvui/entries'
|
||||
|
||||
Vue.use(ui);
|
||||
Vue.use(vcUI);
|
||||
Vue.use(dvui)
|
||||
//富文本编辑器配置
|
||||
Vue.config.productionTip = false;
|
||||
Object.keys(utils).map((e) => (Vue.prototype[e] = utils[e]));
|
||||
Vue.prototype.$request = axios
|
||||
const app = new Vue({
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
});
|
||||
let theme = null
|
||||
store.dispatch('getSystem').then(({colorScheme}) => {
|
||||
theme = JSON.parse(colorScheme || null)
|
||||
Vue.prototype.$theme = theme?.web || "blue"
|
||||
return import(`dvcp-ui/lib/styles/theme.${theme?.web}.scss`).catch(() => 0)
|
||||
}).finally(() => {
|
||||
!theme ? app.$mount('#app') : import(`dvcp-ui/lib/styles/common.scss`).finally(() => app.$mount('#app'))
|
||||
})
|
||||
|
||||
49
examples/router/autoRoutes.js
Normal file
49
examples/router/autoRoutes.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import store from "../store";
|
||||
import appEntry from "../views/appEntry";
|
||||
import {waiting} from "../utils";
|
||||
import router from "./router";
|
||||
import axios from "./axios";
|
||||
|
||||
export default {
|
||||
routes: [],
|
||||
init() {
|
||||
//约束正则式
|
||||
store.commit("cleanApps")
|
||||
this.routes = []
|
||||
// 自动化本工程应用
|
||||
return this.loadApps()
|
||||
},
|
||||
loadApps() {
|
||||
//新App的自动化格式
|
||||
let apps = require.context('../../packages/', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/, 'lazy'),
|
||||
projects = require.context('../../project/', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/, 'lazy')
|
||||
const promise = (mods, base) => Promise.all(mods.keys().map(path => mods(path).then(file => {
|
||||
if (file.default) {
|
||||
let {name, label} = file.default,
|
||||
addApp = {
|
||||
name: path.replace(/\.\/?(vue)?/g, '')?.split("/").join("_"), label: label || name,
|
||||
path: `/${base}${path.replace(/\.(\/.+\/App.+)\.vue$/, '$1')}`,
|
||||
component: appEntry,
|
||||
module: file.default
|
||||
}
|
||||
waiting.setContent(`加载${name}...`)
|
||||
router.addRoute(addApp)
|
||||
//命名规范入口文件必须以App开头
|
||||
return store.commit("addApp", addApp)
|
||||
} else return 0
|
||||
})))
|
||||
waiting.init({innerHTML: '应用加载中..'})
|
||||
Promise.all([
|
||||
promise(apps, "packages"),
|
||||
promise(projects, "project")
|
||||
]).then(() => {
|
||||
axios.post("/node/wechatapps/addOrUpdate", {
|
||||
type: "web",
|
||||
list: this.routes().map(({path: libPath, label, module: {name}, name: id}) => ({
|
||||
id, type: 'web', libPath, label, name
|
||||
}))
|
||||
}, {baseURL: "/ns"}).catch(() => 0)
|
||||
waiting.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
28
examples/router/axios.js
Normal file
28
examples/router/axios.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import instance from 'dvcp-ui/lib/js/request'
|
||||
import {Message} from 'element-ui'
|
||||
|
||||
let baseURLs = {
|
||||
production: "/",
|
||||
development: '/lan'
|
||||
}
|
||||
instance.defaults.baseURL = baseURLs[process.env.NODE_ENV]
|
||||
instance.interceptors.request.use(config => {
|
||||
if (config.url.startsWith("/node")) {
|
||||
config.baseURL = "/ns"
|
||||
} else if (/\/project\/beta/.test(location.pathname)) {
|
||||
config.baseURL = "/wg"
|
||||
} else if (/\/project\/sass/.test(location.pathname)) {
|
||||
config.baseURL = "/saas"
|
||||
} else if (/\/xiushan/.test(location.pathname)) {
|
||||
config.baseURL = "/xsjr"
|
||||
} else if (/project\/oms/.test(location.pathname)) {
|
||||
config.baseURL = "/omsapi"
|
||||
} else if (/#url-/.test(location.hash)) {
|
||||
config.baseURL = location.hash.replace(/#url-/, '/')
|
||||
}
|
||||
if (["/xsjr", "/omsapi"].includes(config.baseURL)) {
|
||||
config.url = config.url.replace(/(app|auth|admin)\//, "")
|
||||
}
|
||||
return config
|
||||
}, error => Message.error(error))
|
||||
export default instance
|
||||
18
examples/router/router.js
Normal file
18
examples/router/router.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import VueRouter from 'vue-router'
|
||||
import autoRoutes from './autoRoutes'
|
||||
import Vue from "vue";
|
||||
|
||||
autoRoutes.init()
|
||||
Vue.use(VueRouter)
|
||||
export default new VueRouter({
|
||||
mode: 'history',
|
||||
hashbang: false,
|
||||
routes: [{path: "/", redirect: "/v", name: "产品库", component: import('../App')}],
|
||||
scrollBehavior(to) {
|
||||
if (to.hash) {
|
||||
return {
|
||||
selector: to.hash
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
28
examples/store/index.js
Normal file
28
examples/store/index.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import preState from 'vuex-persistedstate'
|
||||
import * as modules from "dvcp-ui/lib/js/modules"
|
||||
import axios from "../router/axios";
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
apps: []
|
||||
},
|
||||
mutations: {
|
||||
addApp(state, app) {
|
||||
state.apps.push(app)
|
||||
},
|
||||
cleanApps(state) {
|
||||
state.apps = []
|
||||
},
|
||||
setFinanceUser(state) {
|
||||
axios.post("appfinancialorganizationuser/checkUser").then(res => {
|
||||
state.user.financeUser = res.data
|
||||
}).catch(() => 0)
|
||||
}
|
||||
},
|
||||
modules,
|
||||
plugins: [preState()]
|
||||
})
|
||||
101
examples/utils/index.js
Normal file
101
examples/utils/index.js
Normal file
@@ -0,0 +1,101 @@
|
||||
import {MessageBox} from 'element-ui'
|
||||
import store from '../store'
|
||||
import tools from 'dvcp-ui/lib/js/utils'
|
||||
|
||||
const addChildParty = (parent, pending) => {
|
||||
let doBeforeCount = pending.length
|
||||
parent["children"] = parent["children"] || []
|
||||
pending.map((e, index, arr) => {
|
||||
if (e.partyOrgParentId == parent.partyOrgId) {
|
||||
parent.children.push(e)
|
||||
arr.splice(index, 1)
|
||||
addChildParty(parent, arr)
|
||||
}
|
||||
})
|
||||
if (parent.children.length == 0) {
|
||||
delete parent.children
|
||||
}
|
||||
if (pending.length > 0 && doBeforeCount > pending.length) {
|
||||
parent.children.map(c => addChildParty(c, pending))
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 封装提示框
|
||||
*/
|
||||
|
||||
|
||||
const $confirm = (content, options) => {
|
||||
return MessageBox.confirm(content, {
|
||||
type: "warning",
|
||||
confirmButtonText: "确认",
|
||||
center: true,
|
||||
title: "提示",
|
||||
dangerouslyUseHTMLString: true,
|
||||
...options
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装权限判断方法
|
||||
*/
|
||||
|
||||
|
||||
const $permissions = flag => {
|
||||
const buttons = store.state.user.info.buttons
|
||||
if (buttons) return buttons.some(b => b.id == flag || b.permission == flag)
|
||||
else return false
|
||||
}
|
||||
|
||||
const $decimalCalc = (...arr) => {
|
||||
//确认提升精度
|
||||
let decimalLengthes = arr.map(e => {
|
||||
let index = ("" + e).indexOf(".")
|
||||
return ("" + e).length - index
|
||||
})
|
||||
let maxDecimal = Math.max(...decimalLengthes), precision = Math.pow(10, maxDecimal)
|
||||
//计算
|
||||
let intArr = arr.map(e => (Number(e) || 0) * precision)
|
||||
//返回计算值
|
||||
return intArr.reduce((t, a) => t + a) / precision
|
||||
}
|
||||
export const waiting = {
|
||||
init(ops, count) {
|
||||
if (document.body) {
|
||||
let div = document.createElement('div')
|
||||
div.id = "ai-waiting"
|
||||
div.className = "el-loading-mask is-fullscreen"
|
||||
div.style.zIndex = '202204271710'
|
||||
div.style.textAlign = 'center'
|
||||
div.style.lineHeight = '100vh'
|
||||
div.style.color = '#26f'
|
||||
div.style.fontSize = '20px'
|
||||
div.style.background = 'rgba(255,255,255,.8)'
|
||||
div.style.backdropFilter = 'blur(6px)'
|
||||
document.body.appendChild(div)
|
||||
} else if (count < 10) {
|
||||
setTimeout(() => this.init(ops, ++count), 500)
|
||||
}
|
||||
},
|
||||
getDom() {
|
||||
return document.querySelector('#ai-waiting')
|
||||
},
|
||||
setContent(html) {
|
||||
let div = this.getDom()
|
||||
div.innerHTML = html
|
||||
},
|
||||
close() {
|
||||
let div = this.getDom()
|
||||
div.parentElement.removeChild(div)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
...tools,
|
||||
addChildParty,
|
||||
$confirm,
|
||||
$permissions,
|
||||
$decimalCalc,
|
||||
$waiting: waiting
|
||||
}
|
||||
|
||||
|
||||
37
examples/views/appEntry.vue
Normal file
37
examples/views/appEntry.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<section class="appEntry">
|
||||
<component v-if="app" :is="app" :instance="$request" :dict="$dict" :permissions="$permissions"/>
|
||||
<ai-empty v-else>无法找到应用文件</ai-empty>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "appEntry",
|
||||
label: "应用库-应用",
|
||||
computed: {
|
||||
...mapState(['apps']),
|
||||
app() {
|
||||
let app = this.apps.find(e => e.name == this.$route.name)
|
||||
return app ? app.module : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.appEntry {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
|
||||
& > * {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
13
examples/views/index.vue
Normal file
13
examples/views/index.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "index"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
15
index.html
Normal file
15
index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>村务云应用库-展示页面</title>
|
||||
<script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js" referrerpolicy="origin"></script>
|
||||
<script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js" referrerpolicy="origin"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/examples/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
36
package.json
Normal file
36
package.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "dvcp-vite-webapps",
|
||||
"private": false,
|
||||
"version": "0.0.0",
|
||||
"main": "lib/dvcp-vite-webapps.umd.js",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"preview": "vite preview",
|
||||
"lib": "vite build --outDir lib --emptyOutDir&&npm unpublish --force&&npm publish",
|
||||
"lib:core": "vue-cli-service build --target lib --dest core/dist core/index.js --name vc-app-core&&npm unpublish --force&&npm publish",
|
||||
"lib:project": "node project/build.js",
|
||||
"lib:all": "node project/allProject.js&&npm unpublish --workspaces --force&&npm publish --workspaces",
|
||||
"ui": "npm i dvcp-ui@latest"
|
||||
},
|
||||
"workspaces": [
|
||||
"project/*"
|
||||
],
|
||||
"devDependencies": {
|
||||
"v-viewer": "^1.6.4",
|
||||
"vite": "^2.9.5",
|
||||
"vite-plugin-vue2": "^2.0.0",
|
||||
"vue": "^2.6.14",
|
||||
"vue-router": "^3.3.4",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vuex-persistedstate": "^3.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"dvcp-dv-ui": "^2.0.1",
|
||||
"dvcp-ui": "^1.42.2",
|
||||
"element-ui": "^2.15.8",
|
||||
"mp4box": "^0.4.1",
|
||||
"print-js": "^1.0.63",
|
||||
"sass": "^1.51.0",
|
||||
"vue-draggable-resizable": "^2.3.0"
|
||||
}
|
||||
}
|
||||
58
packages/bigscreen/designer/components/preview.vue
Normal file
58
packages/bigscreen/designer/components/preview.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<section class="preview">
|
||||
<ai-dv-wrapper :views="[{label: '返回'}]" :theme="config.theme" @change="$router.back()" v-if="screenId" :title="info.name">
|
||||
<ai-dv-background
|
||||
:theme="config.theme"
|
||||
v-if="config.length || config.theme === '1'"
|
||||
:src="config.theme === '1' ? 'https://cdn.cunwuyun.cn/dvcp/dv/img/dj-bg.png' : config.backgroundImage[0].url">
|
||||
</ai-dv-background>
|
||||
<app-gigscreen-viewer :urlPrefix="urlPrefix" :instance="instance" :dict="dict" :id="screenId"/>
|
||||
</ai-dv-wrapper>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppGigscreenViewer from "../../viewer/AppGigscreenViewer";
|
||||
|
||||
export default {
|
||||
name: "preview",
|
||||
components: {AppGigscreenViewer},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
urlPrefix: {
|
||||
type: String,
|
||||
default: '/app'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
screenId: v => v.$route.query.id
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
config: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDvData() {
|
||||
let {id} = this.$route.query
|
||||
this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenDetailById?id=${id}`).then(res => {
|
||||
if (res?.data) {
|
||||
this.info = res.data
|
||||
this.config = JSON.parse(res.data.config).dashboard
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getDvData()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.preview {
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div class="doc-circulation ailist-wrapper">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List'
|
||||
import Add from './components/Add'
|
||||
|
||||
export default {
|
||||
name: 'AppConvenienceAddressBook',
|
||||
label: '便民通讯录',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List
|
||||
},
|
||||
|
||||
mounted () {
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (data) {
|
||||
if (data.type === 'Add') {
|
||||
this.component = 'Add'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'list') {
|
||||
this.component = 'List'
|
||||
this.params = data.params
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (data.isRefresh) {
|
||||
this.$refs.component.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.doc-circulation {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
132
packages/conv/AppConvenienceAddressBook/components/Add.vue
Normal file
132
packages/conv/AppConvenienceAddressBook/components/Add.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<ai-detail>
|
||||
<template slot="title">
|
||||
<ai-title :title="params.id ? '编辑通讯录' : '添加通讯录'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form ref="CBookForm" class="ai-form" :model="form" label-width="110px" label-position="right">
|
||||
<el-form-item label="地区" style="width: 100%;" prop="codeName">
|
||||
<span style="color: #666;">{{ form.areaName }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%" label="名称" prop="name" :rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]">
|
||||
<el-input size="small" placeholder="请输入名称" show-word-limit v-model="form.name" :maxlength="30"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%" label="类型" prop="type" :rules="[{ required: true, message: '请输入类型', trigger: 'change' }]">
|
||||
<el-input size="small" placeholder="请输入类型" v-model="form.type"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%" label="电话" prop="phone" :rules="[{required: true, validator: regPhone, trigger: 'blur' }]">
|
||||
<el-input size="small" placeholder="请输入电话" show-word-limit maxlength="11" v-model="form.phone"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 100%;" label="是否公开" prop="isPublic" :rules="[{ required: true, message: '请选择是否公开', trigger: 'change' }]">
|
||||
<el-radio-group v-model="form.isPublic">
|
||||
<el-radio label="1">是</el-radio>
|
||||
<el-radio label="0">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">提交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Add',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
var regPhone = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
return callback(new Error('请输入电话'))
|
||||
} else {
|
||||
const reg = /^[0-9]{3,11}$/
|
||||
if (reg.test(value)) {
|
||||
callback()
|
||||
} else {
|
||||
return callback(new Error('请输入正确的电话号码'))
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
info: {},
|
||||
form: {
|
||||
areaId: '',
|
||||
name: '',
|
||||
areaName: '',
|
||||
phone: '',
|
||||
isPublic: '1',
|
||||
type: '',
|
||||
},
|
||||
id: '',
|
||||
regPhone,
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
if (this.params && this.params.areaId && !this.params.id) {
|
||||
this.form.areaId = this.params.areaId
|
||||
this.form.areaName = this.params.areaName
|
||||
}
|
||||
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appconvenientaddressbook/queryDetailById?id=${id}`).then(res => {
|
||||
if (res?.data) {
|
||||
this.form = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onClose () {
|
||||
this.form.explain = ''
|
||||
},
|
||||
|
||||
confirm () {
|
||||
this.$refs.CBookForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post(`/app/appconvenientaddressbook/addOrUpdate`, {
|
||||
...this.form,
|
||||
id: this.params.id || ''
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
438
packages/conv/AppConvenienceAddressBook/components/List.vue
Normal file
438
packages/conv/AppConvenienceAddressBook/components/List.vue
Normal file
@@ -0,0 +1,438 @@
|
||||
<template>
|
||||
<ai-list class="villagecode">
|
||||
<template slot="title">
|
||||
<ai-title title="便民通讯录" isShowBottomBorder></ai-title>
|
||||
</template>
|
||||
<template #left>
|
||||
<div class="villagecode-left">
|
||||
<div class="villagecode-left__title">
|
||||
<h2>地区</h2>
|
||||
</div>
|
||||
<div class="addressBook-left__list">
|
||||
<div class="addressBook-left__list--title">
|
||||
<el-input
|
||||
class="addressBook-left__list--search"
|
||||
size="mini"
|
||||
clearable
|
||||
placeholder="请输入地区名称"
|
||||
v-model="unitName"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</div>
|
||||
<el-tree
|
||||
:filter-node-method="filterNode"
|
||||
ref="tree"
|
||||
:props="defaultProps"
|
||||
node-key="id"
|
||||
:data="areaTree"
|
||||
highlight-current
|
||||
:current-node-key="search.areaId"
|
||||
:default-expanded-keys="defaultExpanded"
|
||||
:default-checked-keys="defaultChecked"
|
||||
@current-change="onTreeChange">
|
||||
</el-tree>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
<template #left>
|
||||
<el-button size="small" type="primary" :disabled="isShowAdd" icon="iconfont iconAdd" @click="toAdd('')">添加
|
||||
</el-button>
|
||||
<ai-import :instance="instance" :dict="dict" type="appconvenientaddressbook" name="便民通讯录"
|
||||
@success="getList()">
|
||||
<el-button icon="iconfont iconImport">导入</el-button>
|
||||
</ai-import>
|
||||
<ai-download :instance="instance" url="/app/appconvenientaddressbook/export" :params="search" fileName="便民通讯录"
|
||||
:disabled="tableData.length == 0">
|
||||
<el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button>
|
||||
</ai-download>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.name"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入名称/电话/类型"
|
||||
clearable
|
||||
@clear="search.current = 1, search.name = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
style="margin-top: 6px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="isPublic" label="是否公开" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-switch
|
||||
v-model="row.isPublic"
|
||||
active-value="1"
|
||||
@change="e => onChange(row.id, e)"
|
||||
inactive-value="0">
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" width="120px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toAdd(row.id)">编辑</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
name: '',
|
||||
areaId: ''
|
||||
},
|
||||
defaultExpanded: [],
|
||||
defaultChecked: [],
|
||||
areaTree: [],
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'name'
|
||||
},
|
||||
currIndex: -1,
|
||||
total: 10,
|
||||
colConfigs: [
|
||||
{prop: 'name', label: '名称', align: 'left'},
|
||||
{prop: 'type', label: '类型', align: 'center'},
|
||||
{prop: 'phone', label: '电话', align: 'center'},
|
||||
{prop: 'createTime', align: 'center', label: '创建时间'},
|
||||
{slot: 'isPublic', label: '是否公开', align: 'center'}
|
||||
],
|
||||
areaName: '',
|
||||
unitName: '',
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
isShowAdd() {
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
unitName(val) {
|
||||
this.$refs.tree.filter(val)
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.search.areaId = this.user.info.areaId
|
||||
this.areaName = this.user.info.areaName
|
||||
this.getTree()
|
||||
this.getList()
|
||||
|
||||
this.$nextTick(() => {
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appconvenientaddressbook/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onChange(id) {
|
||||
this.instance.post(`/app/appconvenientaddressbook/enable?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('修改成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
filterNode(value, data) {
|
||||
if (!value) return true
|
||||
return data.name.indexOf(value) !== -1
|
||||
},
|
||||
|
||||
onTreeChange(e) {
|
||||
this.search.areaId = e.id
|
||||
this.areaName = e.name
|
||||
this.search.current = 1
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
getTree() {
|
||||
this.instance.post(`/admin/area/queryAllArea?id=${this.user.info.areaId}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
let parent = res.data.map(v => {
|
||||
v.label = v.name
|
||||
v.children = []
|
||||
|
||||
return v
|
||||
}).filter(e => !e.parentid)[0]
|
||||
this.defaultExpanded = [parent.id]
|
||||
this.defaultChecked = [parent.id]
|
||||
this.search.areaId = parent.id
|
||||
this.addChild(parent, res.data)
|
||||
this.areaTree = [parent]
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tree.setCurrentKey(parent.id)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
addChild(parent, list) {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (list[i].parentId === parent.id) {
|
||||
parent.children.push(list[i])
|
||||
}
|
||||
}
|
||||
|
||||
if (list.length > 0) {
|
||||
parent['children'].map(v => this.addChild(v, list))
|
||||
}
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appconvenientaddressbook/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
toAdd(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
areaName: this.areaName,
|
||||
id: id || '',
|
||||
areaId: this.search.areaId
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.villagecode {
|
||||
.table-tags {
|
||||
.el-tag {
|
||||
margin-right: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.addressBook-left__list {
|
||||
height: calc(100% - 40px);
|
||||
padding: 8px 8px;
|
||||
overflow: auto;
|
||||
|
||||
.addressBook-left__tags--item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 40px;
|
||||
padding: 0 8px 0 16px;
|
||||
color: #222222;
|
||||
|
||||
&.addressBook-left__tags--item-active, &:hover {
|
||||
background: #E8EFFF;
|
||||
color: #2266FF;
|
||||
|
||||
i, span {
|
||||
color: #2266FF;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
color: #8e9ebf;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.addressBook-left__list--title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.addressBook-left__list--search {
|
||||
flex: 1;
|
||||
|
||||
::v-deep input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.el-button {
|
||||
width: 84px;
|
||||
flex-shrink: 1;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
::v-deep .el-tree {
|
||||
background: transparent;
|
||||
|
||||
.el-tree-node__expand-icon.is-leaf {
|
||||
color: transparent !important;
|
||||
}
|
||||
|
||||
.el-tree-node__content > .el-tree-node__expand-icon {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.el-tree-node__content {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.el-tree__empty-text {
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.el-tree-node__children .el-tree-node__content {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.el-tree-node__content:hover {
|
||||
background: #E8EFFF;
|
||||
color: #222222;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.is-current > .el-tree-node__content {
|
||||
&:hover {
|
||||
background: #2266FF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
background: #2266FF;
|
||||
|
||||
span {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ai-list__content--left {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.villagecode-left {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
background: #FAFAFB;
|
||||
|
||||
.villagecode-left__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
padding: 0 16px;
|
||||
background: #fff;
|
||||
|
||||
h2 {
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.villagecode-left__list {
|
||||
height: calc(100% - 40px);
|
||||
padding: 8px 0;
|
||||
overflow: auto;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
padding: 0 24px;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
border-right: 2px solid transparent;
|
||||
background: transparent;
|
||||
|
||||
&:hover {
|
||||
color: #2266FF;
|
||||
background: #E8EFFF;
|
||||
}
|
||||
|
||||
&.left-active {
|
||||
color: #2266FF;
|
||||
border-color: #2266FF;
|
||||
background: #E8EFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ai-list__content--right {
|
||||
|
||||
.ai-list__content--right-wrapper {
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.message-info__img {
|
||||
font-size: 0;
|
||||
width: 144px;
|
||||
height: 144px;
|
||||
}
|
||||
</style>
|
||||
87
packages/conv/AppDeviceConfig/AppDeviceConfig.vue
Normal file
87
packages/conv/AppDeviceConfig/AppDeviceConfig.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<ai-list class="AppDeviceConfig">
|
||||
<template slot="title">
|
||||
<ai-title title="设备配置" :isShowBottomBorder="false" :fullname.sync="areaName" v-model="areaId" :instance="instance" @change="onAreaChange"></ai-title>
|
||||
</template>
|
||||
<template slot="tabs">
|
||||
<el-tabs v-model="currIndex">
|
||||
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label">
|
||||
<component :areaId="areaId" :ref="String(i)" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance" :dict="dict" :permissions="permissions"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import eyeList from './components/eyeList.vue'
|
||||
import videoList from './components/videoList.vue'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AppDeviceConfig',
|
||||
label: '设备配置',
|
||||
|
||||
components: {
|
||||
eyeList,
|
||||
videoList,
|
||||
},
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
tabs () {
|
||||
const tabList = [
|
||||
{label: '千里眼', name: 'eyeList', comp: eyeList, permission: ''},
|
||||
{label: '视联网', name: 'videoList', comp: videoList, permission: ''}
|
||||
]
|
||||
|
||||
return tabList
|
||||
}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
currIndex: '0',
|
||||
component: 'eyeList',
|
||||
params: {},
|
||||
areaId: '',
|
||||
areaName: ''
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.areaId = this.user.info.areaId
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (data) {
|
||||
this.component = data.type
|
||||
this.params = data.params
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (data.isRefresh) {
|
||||
this.$refs.component.getList()
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
onAreaChange () {
|
||||
this.$refs[this.currIndex][0].changeArea()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppDeviceConfig {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
237
packages/conv/AppDeviceConfig/components/eyeList.vue
Normal file
237
packages/conv/AppDeviceConfig/components/eyeList.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<ai-list class="eyeList" isTabs>
|
||||
<template slot="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template #left>
|
||||
<el-button type="primary" icon="iconfont iconAdd" size="small" @click="add('添加设备配置', {})">添加</el-button>
|
||||
<el-button icon="el-icon-delete" class="delete-btn del-btn-list" :disabled="!ids.length" @click="remove(ids)">删除</el-button>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.condition"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入CorpId"
|
||||
clearable
|
||||
@change="getList"
|
||||
@clear="search.current = 1, search.condition = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
v-loading="loading"
|
||||
style="margin-top: 16px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList"
|
||||
@selection-change="v=>ids=v.map(e=>e.id)">
|
||||
<el-table-column slot="options" width="140px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="add('编辑设备配置', row)">编辑</el-button>
|
||||
<el-button type="text" @click="refresh(row)">刷新</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="flag" align="center" label="状态" width="100">
|
||||
<template v-slot="{ row }">
|
||||
<el-switch v-model="row.flag" @change="onChange(row)" active-value="1" inactive-value="0"
|
||||
active-color="#5088FF" inactive-color="#D0D4DC"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<ai-dialog :title="dialogTitle" :visible.sync="dialog" width="800px" @onConfirm="addForm" @closed="dialogForm={}">
|
||||
<el-form ref="addForm" :model="dialogForm" :rules="rules" size="small" label-width="160px">
|
||||
<el-form-item label="CorpId" prop="corpId">
|
||||
<el-input v-model.trim="dialogForm.corpId" placeholder="请输入..." clearable :maxLength="50"/>
|
||||
</el-form-item>
|
||||
<el-form-item required label="状态">
|
||||
<el-radio-group v-model="dialogForm.flag">
|
||||
<el-radio :label="0">关闭</el-radio>
|
||||
<el-radio :label="1">开启</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="AppId">
|
||||
<el-input v-model.trim="dialogForm.appId" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="RSA">
|
||||
<el-input v-model.trim="dialogForm.rsa" placeholder="请输入..." clearable :maxLength="5000" type="textarea" :rows="5"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="SECRET">
|
||||
<el-input v-model.trim="dialogForm.secret" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="TOKEN">
|
||||
<el-input v-model.trim="dialogForm.token" placeholder="请输入..." clearable :maxLength="200" type="textarea" :rows="2"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="结点ids">
|
||||
<el-input v-model.trim="dialogForm.orgIds" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="版本号">
|
||||
<el-input v-model.trim="dialogForm.version" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="大喇叭账号">
|
||||
<el-input v-model.trim="dialogForm.dlbName" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="大喇叭密码">
|
||||
<el-input v-model.trim="dialogForm.dlbPwd" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="大喇叭Token">
|
||||
<el-input v-model.trim="dialogForm.dlbToken" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'eyeList',
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
areaId: String
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
condition: '',
|
||||
size: 10,
|
||||
},
|
||||
ids: [],
|
||||
tableData: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
dialog: false,
|
||||
dialogTitle: '',
|
||||
dialogForm: {}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
param () {
|
||||
return this.search
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
corpId: [{required: true, message: "请输入CorpId"}],
|
||||
}
|
||||
},
|
||||
colConfigs() {
|
||||
return [
|
||||
{type: "selection"},
|
||||
{ prop: 'corpId', label: 'CorpId', fixed: 'left', width: 220 },
|
||||
{ slot: 'flag', align: 'center', label: '状态', fixed: 'left', width: 120 },
|
||||
{ prop: 'appId', align: 'center', label: 'AppId', width: 240 },
|
||||
{ prop: 'rsa', align: 'center', label: 'RSA', width: 240 },
|
||||
{ prop: 'secret', align: 'center', label: 'SECRET', width: 180 },
|
||||
{ prop: 'token', align: 'center', label: 'TOKEN', width: 120 },
|
||||
{ prop: 'orgIds', align: 'center', label: '结点ids', width: 120 },
|
||||
{ prop: 'version', align: 'center', label: '版本号', width: 120 },
|
||||
{ prop: 'dlbName', align: 'center', label: '大喇叭账号', width: 140 },
|
||||
{ prop: 'dlbPwd', align: 'center', label: '大喇叭密码', width: 140 },
|
||||
{ prop: 'dlbToken', align: 'center', label: '大喇叭Token', width: 180 },
|
||||
{ prop: 'createTime', align: 'center', label: '创建时间', fixed: 'right', width: 180 },
|
||||
{ slot: 'options'},
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getListInit() {
|
||||
this.search.current = 1
|
||||
this.getList()
|
||||
},
|
||||
getList () {
|
||||
this.instance.post(`/app/appzyaccountconfig/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
type: 0
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
this.loading = false
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appzyaccountconfig/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
add(title, item) {
|
||||
this.dialog = true
|
||||
this.dialogTitle = title
|
||||
this.dialogForm = item
|
||||
if(title == '添加设备配置') {
|
||||
this.dialogForm.flag = 1
|
||||
this.dialogForm.version = '1.0.0'
|
||||
}
|
||||
},
|
||||
addForm() {
|
||||
this.$refs.addForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.dialogForm.type = 0
|
||||
this.instance.post(`/app/appzyaccountconfig/addOrUpdate`, this.dialogForm).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(`${this.dialogForm.id ? '编辑成功' : '添加成功'}`)
|
||||
this.getListInit()
|
||||
this.dialog = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
refresh(row) {
|
||||
this.$confirm('确定刷新该数据token?').then(() => {
|
||||
this.instance.post(`/app/appzyaccountconfig/initQlyToken?id=${row.id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('刷新成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
onChange(row) {
|
||||
this.instance.post(`/app/appzyaccountconfig/setFlag`, null, {
|
||||
params: {
|
||||
id: row.id,
|
||||
flag: row.flag
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(+row.flag ? '已启用' : '已禁用');
|
||||
this.getList();
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
224
packages/conv/AppDeviceConfig/components/videoList.vue
Normal file
224
packages/conv/AppDeviceConfig/components/videoList.vue
Normal file
@@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<ai-list class="videoList" isTabs>
|
||||
<template slot="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template #left>
|
||||
<el-button type="primary" icon="iconfont iconAdd" size="small" @click="add('添加设备配置', {})">添加</el-button>
|
||||
<el-button icon="el-icon-delete" class="delete-btn del-btn-list" :disabled="!Boolean(ids.length)" @click="remove(ids)">删除</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.condition"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入CorpId"
|
||||
clearable
|
||||
@change="getList"
|
||||
@clear="search.current = 1, search.condition = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
v-loading="loading"
|
||||
style="margin-top: 16px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList"
|
||||
@selection-change="v=>ids=v.map(e=>e.id)">
|
||||
<el-table-column slot="options" width="140px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="add('编辑设备配置', row)">编辑</el-button>
|
||||
<el-button type="text" @click="refresh(row)">刷新</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="flag" align="center" label="状态" width="100">
|
||||
<template v-slot="{ row }">
|
||||
<el-switch v-model="row.flag" @change="onChange(row)" active-value="1" inactive-value="0"
|
||||
active-color="#5088FF" inactive-color="#D0D4DC"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<ai-dialog :title="dialogTitle" :visible.sync="dialog" width="800px" @onConfirm="addForm" @closed="dialogForm={}">
|
||||
<el-form ref="addForm" :model="dialogForm" :rules="rules" size="small" label-width="160px">
|
||||
<el-form-item label="CorpId" prop="corpId">
|
||||
<el-input v-model.trim="dialogForm.corpId" placeholder="请输入..." clearable :maxLength="50"/>
|
||||
</el-form-item>
|
||||
<el-form-item required label="状态">
|
||||
<el-radio-group v-model="dialogForm.flag">
|
||||
<el-radio :label="0">关闭</el-radio>
|
||||
<el-radio :label="1">开启</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户ID">
|
||||
<el-input v-model.trim="dialogForm.slwUserId" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="地区编码">
|
||||
<el-input v-model.trim="dialogForm.slwAreaId" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="TOKEN">
|
||||
<el-input v-model.trim="dialogForm.slwToken" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="大喇叭账号">
|
||||
<el-input v-model.trim="dialogForm.dlbName" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="大喇叭密码">
|
||||
<el-input v-model.trim="dialogForm.dlbPwd" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="大喇叭Token">
|
||||
<el-input v-model.trim="dialogForm.dlbToken" placeholder="请输入..." clearable :maxLength="50" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'eyeList',
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
areaId: String
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
condition: '',
|
||||
size: 10,
|
||||
},
|
||||
ids: [],
|
||||
tableData: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
dialog: false,
|
||||
dialogTitle: '',
|
||||
dialogForm: {}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
param () {
|
||||
return this.search
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
corpId: [{required: true, message: "请输入CorpId"}],
|
||||
}
|
||||
},
|
||||
colConfigs() {
|
||||
return [
|
||||
{type: "selection"},
|
||||
{ prop: 'corpId', label: 'CorpId', fixed: 'left', width: 220 },
|
||||
{ slot: 'flag', align: 'center', label: '状态', fixed: 'left', width: 120 },
|
||||
{ prop: 'slwUserId', align: 'center', label: '用户ID', width: 180 },
|
||||
{ prop: 'slwAreaId', align: 'center', label: '地区编码', width: 180 },
|
||||
{ prop: 'slwToken', align: 'center', label: 'TOKEN', width: 220 },
|
||||
{ prop: 'dlbName', align: 'center', label: '大喇叭账号', width: 140 },
|
||||
{ prop: 'dlbPwd', align: 'center', label: '大喇叭密码', width: 140 },
|
||||
{ prop: 'dlbToken', align: 'center', label: '大喇叭Token', width: 180 },
|
||||
{ prop: 'createTime', align: 'center', label: '创建时间', width: 180 },
|
||||
{ slot: 'options'},
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getListInit() {
|
||||
this.search.current = 1
|
||||
this.getList()
|
||||
},
|
||||
getList () {
|
||||
this.instance.post(`/app/appzyaccountconfig/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
type: 1
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
this.loading = false
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appzyaccountconfig/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
add(title, item) {
|
||||
this.dialog = true
|
||||
this.dialogTitle = title
|
||||
this.dialogForm = item
|
||||
if(title == '添加设备配置') {
|
||||
this.dialogForm.flag = 1
|
||||
}
|
||||
},
|
||||
addForm() {
|
||||
this.$refs.addForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.dialogForm.type = 1
|
||||
this.instance.post(`/app/appzyaccountconfig/addOrUpdate`, this.dialogForm).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(`${this.dialogForm.id ? '编辑成功' : '添加成功'}`)
|
||||
this.getListInit()
|
||||
this.dialog = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
refresh(row) {
|
||||
this.$confirm('确定刷新该数据token?').then(() => {
|
||||
this.instance.post(`/app/appzyaccountconfig/initSlwToken?id=${row.id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('刷新成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
onChange(row) {
|
||||
this.instance.post(`/app/appzyaccountconfig/setFlag`, null, {
|
||||
params: {
|
||||
id: row.id,
|
||||
flag: row.flag
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(+row.flag ? '已启用' : '已禁用');
|
||||
this.getList();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
62
packages/conv/AppHealthReport/AppHealthReport.vue
Normal file
62
packages/conv/AppHealthReport/AppHealthReport.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div class="AppHealthReport">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List.vue'
|
||||
import Detail from './components/Detail.vue'
|
||||
|
||||
export default {
|
||||
name: 'AppHealthReport',
|
||||
label: '健康上报',
|
||||
|
||||
components: {
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (data) {
|
||||
if (data.type === 'Detail') {
|
||||
this.component = 'Detail'
|
||||
this.isShowDetail = true
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'list') {
|
||||
this.component = 'List'
|
||||
this.params = data.params
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (data.isRefresh) {
|
||||
this.$refs.component.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppHealthReport {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
316
packages/conv/AppHealthReport/components/Detail.vue
Normal file
316
packages/conv/AppHealthReport/components/Detail.vue
Normal file
@@ -0,0 +1,316 @@
|
||||
<template>
|
||||
<ai-detail isHasSidebar>
|
||||
<template slot="title">
|
||||
<ai-title title="详情" isShowBack isShowBottomBorder @onBackClick="cancel(true)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<AiSidebar :tabTitle="tabList" v-model="currIndex"></AiSidebar>
|
||||
<div v-show="currIndex === 0">
|
||||
<ai-card title="基本信息" v-show="currIndex === 0">
|
||||
<template #content>
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="姓名" :value="info.name"></ai-info-item>
|
||||
<ai-info-item label="上报时间" :value="info.createTime"></ai-info-item>
|
||||
<ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item>
|
||||
<ai-info-item label="所属地区" :value="info.areaName"></ai-info-item>
|
||||
<ai-info-item label="详细地址" isLine :value="info.address"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
</div>
|
||||
<ai-card title="每日上报" v-show="currIndex === 1">
|
||||
<template #content>
|
||||
<ai-table
|
||||
class="detail-table__table"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="options" width="140px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<ai-dialog
|
||||
:visible.sync="isShow"
|
||||
width="890px"
|
||||
customFooter
|
||||
title="上报详情">
|
||||
<ai-bar title="健康状况"></ai-bar>
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="当前体温">
|
||||
<span :style="{color: reportInfo.temperature > 37.3 ? '#FF4466' : '#42D784'}">{{ reportInfo.temperature }}℃</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="14天内是否接触新冠确诊或疑似患者">
|
||||
<span :style="{color: reportInfo.touchInFourteen === '0' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicTouchInFourteen', reportInfo.touchInFourteen) }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="当前健康状况" isLine>
|
||||
<span :style="{color: !reportInfo.isHealth ? '#42D784' : '#FF4466'}">{{ reportInfo.healthName }}</span>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
<ai-bar title="核酸检测信息"></ai-bar>
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="检测日期">
|
||||
<span>{{ reportInfo.checkTime && reportInfo.checkTime.split(' ')[0] }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="检测结果">
|
||||
<span :style="{color: reportInfo.checkResult === '0' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicRecentTestResult', reportInfo.checkResult) }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="健康码状态">
|
||||
<span :style="{color: (reportInfo.healthCode === '0' || reportInfo.healthCode === '1') ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicHealthCode', reportInfo.healthCode) }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="已接种疫苗次数">
|
||||
<span>{{ $dict.getLabel('epidemicVaccineTime', reportInfo.vaccine) }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="本人健康码截图" isLine>
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
v-model="reportInfo.checkPhoto"
|
||||
disabled
|
||||
:limit="9">
|
||||
</ai-uploader>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="isShow = false">关闭</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-card>
|
||||
<div v-show="currIndex === 2">
|
||||
<ai-card title="异常处理">
|
||||
<template #right>
|
||||
<el-button type="primary" v-if="info.status === '0'" @click="release">解除异常</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="姓名" :value="info.name"></ai-info-item>
|
||||
<ai-info-item label="填报时间" :value="info.createTime"></ai-info-item>
|
||||
<ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item>
|
||||
<ai-info-item label="手机号码" :value="info.phone"></ai-info-item>
|
||||
<ai-info-item label="异常状况" isLine>
|
||||
<span :style="{color: info.unusual ? 'red' : '#333'}">{{ info.unusual || '-' }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="异常解除人" v-if="info.releaseName && info.status === '1'" :value="info.releaseName"></ai-info-item>
|
||||
<ai-info-item label="异常解除时间" v-if="info.releaseTime && info.status === '1'" :value="info.releaseTime"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="异常情况记录">
|
||||
<template #right>
|
||||
<el-button type="primary" v-if="info.status === '0'" @click="isShowAdd = true">添加记录</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-table
|
||||
:tableData="recordList"
|
||||
:col-configs="recordConfigs"
|
||||
:total="recordTotal"
|
||||
:current.sync="recordSerch.current"
|
||||
:size.sync="recordSerch.size"
|
||||
@getList="getRecordList">
|
||||
<el-table-column slot="options" width="120px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowAdd"
|
||||
width="800px"
|
||||
@close="form.content = ''"
|
||||
title="添加异常记录"
|
||||
@onConfirm="onConfirm">
|
||||
<el-form class="ai-form" label-width="120px" :model="form" ref="form">
|
||||
<el-form-item label="异常记录" prop="content" style="width: 100%;" :rules="[{ required: true, message: '请输入异常记录' }]">
|
||||
<el-input type="textarea" :rows="5" :maxlength="500" v-model="form.content" clearable placeholder="请输入异常记录" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Detail',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
total: 0,
|
||||
info: {},
|
||||
id: '',
|
||||
isShowAdd: false,
|
||||
recordTotal: 0,
|
||||
recordSerch: {
|
||||
current: 1,
|
||||
size: 10
|
||||
},
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10
|
||||
},
|
||||
form: {
|
||||
content: ''
|
||||
},
|
||||
recordConfigs: [
|
||||
{prop: 'content', label: '异常记录', align: 'center' },
|
||||
{prop: 'createTime', label: '创建时间', align: 'center'},
|
||||
{prop: 'createUserName', label: '记录人', align: 'center' }
|
||||
],
|
||||
reportInfo: {},
|
||||
isShow: false,
|
||||
currIndex: 0,
|
||||
tableData: [],
|
||||
recordList: [],
|
||||
colConfigs: [
|
||||
{prop: 'createTime', label: '上报日期', align: 'center', dateFormat: 'YYYY-MM-DD'},
|
||||
{prop: 'status', label: '健康状态', align: 'center', formart: v => v === '0' ? '异常' : '正常' }
|
||||
],
|
||||
tabList: ['基本信息', '每日上报', '异常处理']
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.dict.load(['epidemicRecentHealth', 'epidemicRecentTravel', 'epidemicTouchInFourteen', 'epidemicMemberType', 'epidemicRecentTestResult']).then(() => {
|
||||
this.getInfo(this.params.id)
|
||||
this.getList()
|
||||
this.getRecordList()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appepidemicreportmember/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
this.currIndex = 0
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getRecordList () {
|
||||
this.instance.post(`/app/appepidemicunusuallog/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
recordId: this.params.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.recordList = res.data.records
|
||||
this.recordTotal = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onConfirm() {
|
||||
this.$refs.form.validate(v => {
|
||||
if (v) {
|
||||
this.instance.post('/app/appepidemicunusuallog/addOrUpdate', {
|
||||
...this.form,
|
||||
recordId: this.params.id
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.isShowAdd = false
|
||||
this.getRecordList(this.params.id)
|
||||
this.$message.success('添加成功!')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
release () {
|
||||
this.$confirm('确定解除异常?').then(() => {
|
||||
this.instance.post(`/app/appepidemicreportmember/release`, {
|
||||
id: this.params.id
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('解除异常成功!')
|
||||
this.currIndex = 0
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appepidemicunusuallog/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getRecordList(this.params.id)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.instance.post(`/app/appepidemichealthreport/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.reportInfo = res.data
|
||||
this.reportInfo.checkPhoto = JSON.parse(res.data.checkPhoto)
|
||||
let healthName = ''
|
||||
this.reportInfo.isHealth = false
|
||||
res.data.health.split(',').forEach(v => {
|
||||
if (v > 0) {
|
||||
this.reportInfo.isHealth = true
|
||||
}
|
||||
healthName = healthName + this.dict.getLabel('epidemicRecentHealth', v)
|
||||
})
|
||||
this.reportInfo.healthName = healthName
|
||||
|
||||
this.isShow = true
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getList () {
|
||||
this.instance.post(`/app/appepidemichealthreport/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
memberId: this.params.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
293
packages/conv/AppHealthReport/components/List.vue
Normal file
293
packages/conv/AppHealthReport/components/List.vue
Normal file
@@ -0,0 +1,293 @@
|
||||
<template>
|
||||
<ai-list class="list">
|
||||
<ai-title slot="title" title="健康上报" v-if="search.areaId" isShowBottomBorder :instance="instance" :disabledLevel="disabledLevel" isShowArea v-model="search.areaId" @change="changeArea"></ai-title>
|
||||
<template slot="content">
|
||||
<div class="statistics-top">
|
||||
<div class="statistics-top__item">
|
||||
<span>上报人数</span>
|
||||
<h2 style="color: #2266FF;">{{ info.total }}</h2>
|
||||
</div>
|
||||
<div class="statistics-top__item">
|
||||
<span>今日上报</span>
|
||||
<h2 style="color: #22AA99;">{{ info.today }}</h2>
|
||||
</div>
|
||||
<div class="statistics-top__item">
|
||||
<span>今日未报</span>
|
||||
<h2 style="color: #F8B425">{{ info.unReport }}</h2>
|
||||
</div>
|
||||
<div class="statistics-top__item">
|
||||
<span>今日异常</span>
|
||||
<h2 style="color: red">{{ info.unusual }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template #left>
|
||||
<ai-select
|
||||
v-model="search.checkResult"
|
||||
clearable
|
||||
placeholder="请选择检查结果"
|
||||
:selectList="dict.getDict('epidemicRecentTestResult')"
|
||||
@change="search.current = 1, getList()">
|
||||
</ai-select>
|
||||
<ai-select
|
||||
v-model="search.today"
|
||||
clearable
|
||||
placeholder="今日是否上报"
|
||||
:selectList="dictList"
|
||||
@change="search.current = 1, getList()">
|
||||
</ai-select>
|
||||
<ai-download :instance="instance" url="/app/appepidemicreportmember/export" :params="search" fileName="健康上报" :disabled="tableData.length == 0">
|
||||
<el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button>
|
||||
</ai-download>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.name"
|
||||
size="small"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
@clear="search.current = 1, search.name = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
v-loading="loading"
|
||||
style="margin-top: 16px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="healthCode" align="center" label="健康码">
|
||||
<template slot-scope="{ row }">
|
||||
<ai-uploader
|
||||
v-if="row.healthCode"
|
||||
:instance="instance"
|
||||
:value="JSON.parse(row.healthCode)"
|
||||
disabled
|
||||
:limit="1">
|
||||
</ai-uploader>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" width="140px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
name: '',
|
||||
checkResult: '',
|
||||
areaId: '',
|
||||
today: ''
|
||||
},
|
||||
dictList: [{
|
||||
dictName: '否',
|
||||
dictValue: '0'
|
||||
}, {
|
||||
dictName: '是',
|
||||
dictValue: '1'
|
||||
}],
|
||||
info: {},
|
||||
colConfigs: [
|
||||
{ prop: 'name', label: '姓名' },
|
||||
{ prop: 'phone', align: 'center', label: '手机号码' },
|
||||
{ prop: 'areaName', align: 'center', label: '所属地区', width: '200px' },
|
||||
{ prop: 'reportTime', align: 'center', label: '上报时间', width: '200px' },
|
||||
{
|
||||
prop: 'vaccine',
|
||||
align: 'center',
|
||||
label: '已接种情况',
|
||||
render: (h, {row}) => {
|
||||
return h('span', {
|
||||
style: {
|
||||
}
|
||||
}, row.today === '0' ? '-' : (row.vaccine || 0 + '次'))
|
||||
}
|
||||
},
|
||||
{ prop: 'healthCode', align: 'center', label: '健康码', formart: v => v ? this.dict.getLabel('epidemicHealthCode', v) : '-' },
|
||||
{ prop: 'checkTime', align: 'center', label: '核酸日期', formart: v => v ? v.split(' ')[0] : '-' },
|
||||
{ prop: 'checkResult', align: 'center', label: '检测结果', formart: v => v ? this.dict.getLabel('epidemicRecentTestResult', v) : '-' },
|
||||
{
|
||||
prop: 'status',
|
||||
align: 'center',
|
||||
label: '健康状态',
|
||||
render: (h, {row}) => {
|
||||
return h('span', {
|
||||
style: {
|
||||
color: row.status === '0' ? 'red' : '#333'
|
||||
}
|
||||
}, row.today === '0' ? '-' : (row.status === '0' ? '异常' : '正常'))
|
||||
}
|
||||
},
|
||||
{ prop: 'today', align: 'center', label: '今日上报', formart: v => v === '0' ? '未上报' : '已上报' },
|
||||
],
|
||||
tableData: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
disabledLevel: 0
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
param () {
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.disabledLevel = this.user.info.areaList.length - 1
|
||||
this.search.areaId = this.user.info.areaId
|
||||
this.loading = true
|
||||
this.dict.load(['epidemicTouchInFourteen', 'epidemicRecentHealth', 'epidemicRecentTestResult', 'epidemicHealthCode', 'epidemicVaccineTime']).then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
this.instance.post(`/app/appepidemicreportmember/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
this.loading = false
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
this.getTotalInfo()
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appepidemicreportmember/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getTotalInfo()
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
changeArea () {
|
||||
this.search.current = 1
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getList()
|
||||
this.getTotalInfo()
|
||||
})
|
||||
},
|
||||
|
||||
getTotalInfo () {
|
||||
this.instance.post(`/app/appepidemicreportmember/statistic`, null, {
|
||||
params: {
|
||||
areaId: this.search.areaId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.info = res.data
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.list {
|
||||
::v-deep .ai-list__content {
|
||||
padding: 0!important;
|
||||
|
||||
.ai-list__content--right-wrapper {
|
||||
background: transparent!important;
|
||||
box-shadow: none!important;
|
||||
margin: 0!important;
|
||||
padding: 12px 16px 12px!important;
|
||||
}
|
||||
}
|
||||
.statistics-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
& > div {
|
||||
flex: 1;
|
||||
height: 96px;
|
||||
line-height: 1;
|
||||
margin-right: 20px;
|
||||
padding: 16px 24px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
border-radius: 4px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
color: #888888;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 16px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
54
packages/conv/AppReportAiWill/AppReportAtWill.vue
Normal file
54
packages/conv/AppReportAiWill/AppReportAtWill.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<section class="AppReportAtWill">
|
||||
<component ref="component" :is="currentPage" @change="onChange" :params="params" :instance="instance" :dict="dict"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List'
|
||||
import Detail from './components/Detail'
|
||||
import Setting from './components/Setting'
|
||||
|
||||
export default {
|
||||
name: 'AppReportAtWill',
|
||||
label: '随手拍',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentPage() {
|
||||
let {hash, query: {id}} = this.$route
|
||||
return hash == "#Setting" ? Setting :
|
||||
!!id ? Detail : List
|
||||
}
|
||||
},
|
||||
components: {
|
||||
List,
|
||||
Detail,
|
||||
Setting
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange(data) {
|
||||
this.$router.push({query: data.params, hash: data.type == "Setting" ? "#Setting" : ""})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.AppReportAtWill {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
572
packages/conv/AppReportAiWill/components/Detail.vue
Normal file
572
packages/conv/AppReportAiWill/components/Detail.vue
Normal file
@@ -0,0 +1,572 @@
|
||||
<template>
|
||||
<ai-detail class="reportAtWillDetail" v-loading="isLoading">
|
||||
<template #title>
|
||||
<ai-title title="随手拍详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
<template #rightBtn>
|
||||
<div class="title-btns">
|
||||
<el-button type="primary" icon="iconfont iconPerson_Transfered" @click="isShowForward = true" v-if="detail.eventStatus < 2">指派事件</el-button>
|
||||
<el-button type="primary" icon="iconfont iconRegister" @click="isShowAdd = true" v-if="detail.eventStatus < 2">处理事件</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</ai-title>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="detail-content__wrapper">
|
||||
<ai-card class="detail-content__wrapper--left" title="基础信息">
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="上报人员" :value="detail.name"></ai-info-item>
|
||||
<ai-info-item label="当前状态" :value="dict.getLabel('clapEventStatus', detail.eventStatus)"></ai-info-item>
|
||||
<ai-info-item label="联系方式">{{ detail.phone }}</ai-info-item>
|
||||
<ai-info-item label="上报时间">{{ detail.createTime }}</ai-info-item>
|
||||
<ai-info-item label="事件类型">{{ detail.groupName }}</ai-info-item>
|
||||
<ai-info-item label="事件描述" isLine>{{ detail.content }}</ai-info-item>
|
||||
<ai-info-item label="现场照片" isLine>
|
||||
<ai-uploader :instance="instance" disabled v-model="detail.files"></ai-uploader>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="所属网格">{{ detail.girdName }}</ai-info-item>
|
||||
<ai-info-item label="事件位置" isLine>
|
||||
<div id="map" style="width: 500px; height: 280px;"></div>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<div class="rightZone">
|
||||
<ai-card title="办理进度">
|
||||
<template #content>
|
||||
<el-steps direction="vertical" :active="1">
|
||||
<el-step
|
||||
v-for="(item, i) in processList"
|
||||
:key="i"
|
||||
:title="item.systemExplain"
|
||||
:description="item.doTime">
|
||||
<template #title>
|
||||
<h2 class="step-title" style="font-weight: 500; font-size: 14px;">
|
||||
{{ item.systemExplain }}
|
||||
</h2>
|
||||
</template>
|
||||
<template #description>
|
||||
<p style="color: #888; margin: 0 4px 10px 0; font-size: 14px;">{{ item.doTime }}</p>
|
||||
<div style="color: #444;margin-bottom: 10px;" v-if="item.doExplain">{{ item.doExplain }}</div>
|
||||
<ai-uploader :instance="instance" disabled v-model="item.files"></ai-uploader>
|
||||
</template>
|
||||
</el-step>
|
||||
</el-steps>
|
||||
</template>
|
||||
</ai-card>
|
||||
</div>
|
||||
</div>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowAdd"
|
||||
width="800px"
|
||||
title="事件处理"
|
||||
@closed="onClose"
|
||||
@onConfirm="handleEvent">
|
||||
<el-form class="ai-form" label-width="120px" :model="form" ref="form">
|
||||
<el-form-item label="事件分类" prop="groupId" style="width: 100%;" :rules="[{ required: true, message: '请选择事件分类' }]">
|
||||
<ai-select
|
||||
v-model="form.groupId"
|
||||
placeholder="请选择事件分类"
|
||||
:selectList="dictList">
|
||||
</ai-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="处理结果" prop="eventStatus" style="width: 100%;" :rules="[{ required: true, message: '请选择处理结果' }]">
|
||||
<el-radio-group v-model="form.eventStatus">
|
||||
<el-radio label="2">已办结</el-radio>
|
||||
<el-radio label="3">已拒绝</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="处理意见" prop="content" style="width: 100%;" :rules="[{ required: true, message: '请输入处理意见' }]">
|
||||
<el-input type="textarea" :rows="5" :maxlength="500" v-model="form.content" clearable placeholder="请输入处理意见" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图片" prop="files" style="width: 100%;">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
isShowTip
|
||||
v-model="form.files"
|
||||
:limit="9">
|
||||
</ai-uploader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowForward"
|
||||
width="800px"
|
||||
@close="onClose"
|
||||
title="事件指派"
|
||||
@onConfirm="onForwardConfirm">
|
||||
<el-form class="ai-form" label-width="120px" :model="forwardForm" ref="forwardForm">
|
||||
<el-form-item label="转交" prop="name" style="width: 100%;" :rules="[{ required: true, message: '请选择网格员或网格' }]">
|
||||
<el-input disabled size="small" v-model="forwardForm.name" clearable placeholder="请选择网格员或网格">
|
||||
<template slot="append">
|
||||
<el-button @click="getGirdList().then(()=>isShowUser=true )">选择</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="办理意见" prop="content" style="width: 100%;" :rules="[{ required: true, message: '请输入办理意见' }]">
|
||||
<el-input type="textarea" :rows="5" :maxlength="500" v-model="forwardForm.content" clearable placeholder="请输入办理意见" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图片" prop="files" style="width: 100%;">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
v-model="forwardForm.files"
|
||||
isShowTip
|
||||
:limit="9">
|
||||
</ai-uploader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowUser"
|
||||
width="800px"
|
||||
title="选择网格或网格员"
|
||||
@onConfirm="onConfirm">
|
||||
<div class="grid-wrapper">
|
||||
<el-input
|
||||
style="margin-bottom: 10px;"
|
||||
size="small"
|
||||
placeholder="请输入网格名称/网格员姓名/网格员电话"
|
||||
v-model="name" @change="$refs.tree.filter(name)"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
<el-tree
|
||||
:filter-node-method="filterNode"
|
||||
ref="tree"
|
||||
:props="defaultProps"
|
||||
node-key="id"
|
||||
:data="tree"
|
||||
highlight-current
|
||||
@current-change="onTreeChange">
|
||||
<div class="tree-container" slot-scope="{ data }">
|
||||
<div class="tree-container__user">
|
||||
<div class="tree-user__item">
|
||||
<span>{{ data.isUser ? `${data.name}-${data.phone}` : data.girdName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tree>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AMapLoader from '@amap/amap-jsapi-loader'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Detail',
|
||||
props: ['dict', 'instance'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
forwardForm: {
|
||||
content: '',
|
||||
girdId: '',
|
||||
girdName: '',
|
||||
girdMemberId: '',
|
||||
girdMemberName: '',
|
||||
name: ''
|
||||
},
|
||||
isLoading: true,
|
||||
name: '',
|
||||
detail: {},
|
||||
isShowUser: false,
|
||||
eventList: [],
|
||||
isShowAdd: false,
|
||||
userList: [],
|
||||
processList: [],
|
||||
dictList: [],
|
||||
defaultProps: {
|
||||
label: 'girdName'
|
||||
},
|
||||
isShowForward: false,
|
||||
tree: [],
|
||||
gridInfo: {},
|
||||
form: {
|
||||
files: [],
|
||||
groupId: '',
|
||||
groupName: '',
|
||||
content: [],
|
||||
eventStatus: '2'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created() {
|
||||
this.getDict()
|
||||
this.dict.load('clapEventStatus').then(() => {
|
||||
this.getDetail()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getDetail() {
|
||||
this.instance.post('/app/appclapeventinfo/queryDetailById', null, {
|
||||
params: {id: this.$route.query.id}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.detail = res.data
|
||||
this.processList = res.data.processList
|
||||
this.form.groupId = res.data.groupId
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.initMap()
|
||||
})
|
||||
this.isLoading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
getGirdList() {
|
||||
return this.instance.post(`/app/appgirdinfo/listAllByTop`).then(res => {
|
||||
if (res?.data) {
|
||||
return this.tree = this.formatList([res.data])
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onClose() {
|
||||
this.form.files = []
|
||||
this.form.groupId = ''
|
||||
this.form.groupName = ''
|
||||
this.form.content = ''
|
||||
this.form.eventStatus = ''
|
||||
this.forwardForm.content = ''
|
||||
this.forwardForm.girdId = ''
|
||||
this.forwardForm.girdName = ''
|
||||
this.forwardForm.girdMemberId = ''
|
||||
this.forwardForm.girdMemberName = ''
|
||||
this.forwardForm.name = ''
|
||||
},
|
||||
|
||||
formatList(list) {
|
||||
for (let item of list) {
|
||||
item.children = [item.girdList, item.girdMemberList?.map(e => ({
|
||||
...e, isUser: true, girdName: item.girdName,
|
||||
girdId: item.id
|
||||
})) || []].flat()
|
||||
if (item.girdList?.length > 0) {
|
||||
this.formatList(item.girdList)
|
||||
}
|
||||
}
|
||||
return list
|
||||
},
|
||||
|
||||
filterNode(value, data) {
|
||||
if (!value) return true
|
||||
|
||||
return (data.girdName && data.girdName.indexOf(value) !== -1) || (data.name && data.name.indexOf(value) !== -1) || (data.name && data.phone.indexOf(value) !== -1)
|
||||
},
|
||||
|
||||
onTreeChange(e) {
|
||||
this.gridInfo = e
|
||||
},
|
||||
|
||||
onForwardConfirm() {
|
||||
this.$refs.forwardForm.validate(v => {
|
||||
if (v) {
|
||||
this.instance.post('/app/appclapeventinfo/transferByManager', {
|
||||
...this.forwardForm,
|
||||
id: this.$route.query.id
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.isShowForward = false
|
||||
this.getDetail()
|
||||
this.$message.success('转交成功!')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onConfirm() {
|
||||
if (this.gridInfo.userId) {
|
||||
this.forwardForm.girdId = this.gridInfo.girdId
|
||||
this.forwardForm.girdName = this.gridInfo.girdName
|
||||
this.forwardForm.girdMemberId = this.gridInfo.id
|
||||
this.forwardForm.girdMemberName = this.gridInfo.name
|
||||
} else {
|
||||
this.forwardForm.girdId = this.gridInfo.id
|
||||
}
|
||||
this.forwardForm.girdName = this.gridInfo.girdName
|
||||
this.forwardForm.name = `${this.gridInfo.girdName}${this.gridInfo.name ? '-' + this.gridInfo.name : ''}`
|
||||
this.isShowUser = false
|
||||
},
|
||||
getDict() {
|
||||
this.instance.post(`/app/appclapeventgroup/list?current=1&size=100000`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.dictList = res.data.records.map(v => {
|
||||
return {
|
||||
dictValue: v.id,
|
||||
dictName: v.groupName
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
close() {
|
||||
this.$confirm('确定关闭该事件?').then(() => {
|
||||
this.instance.post(`/app/appmininotice/delete?ids=${this.$route.query.id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
cancel(isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
},
|
||||
|
||||
onChange(e) {
|
||||
this.instance.post(`/app/appvillagerintegralrule/list?size=1000&classification=${e}&ruleStatus=1`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form.ruleId = ''
|
||||
this.eventList = res.data.records
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
initMap() {
|
||||
let {lng, lat} = this.detail
|
||||
let center = [lng, lat]
|
||||
AMapLoader.load({
|
||||
key: 'b553334ba34f7ac3cd09df9bc8b539dc',
|
||||
version: '2.0'
|
||||
}).then(AMap => {
|
||||
let map = new AMap.Map('map', {
|
||||
center,
|
||||
zoom: 14
|
||||
})
|
||||
let marker = new AMap.Marker({
|
||||
position: new AMap.LngLat(lng, lat),
|
||||
title: this.detail.address
|
||||
})
|
||||
map.add(marker)
|
||||
})
|
||||
},
|
||||
|
||||
handleEvent() {
|
||||
this.$refs.form.validate(v => {
|
||||
if (v) {
|
||||
this.instance.post('/app/appclapeventinfo/finishByManager', {
|
||||
...this.form,
|
||||
groupName: this.dictList.filter(v => v.dictValue === this.form.groupId)[0].dictName,
|
||||
id: this.$route.query.id
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.isShowAdd = false
|
||||
this.getDetail()
|
||||
this.$message.success('处理成功!')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.reportAtWillDetail {
|
||||
height: 100%;
|
||||
|
||||
.grid-wrapper {
|
||||
min-height: 360px;
|
||||
}
|
||||
|
||||
.title-btns {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
::v-deep .el-tree {
|
||||
background: transparent;
|
||||
|
||||
.el-tree-node__expand-icon.is-leaf {
|
||||
color: transparent !important;
|
||||
}
|
||||
|
||||
.el-tree-node__content > .el-tree-node__expand-icon {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.el-tree-node__content {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.el-tree__empty-text {
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.el-tree-node__children .el-tree-node__content {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.el-tree-node__content:hover {
|
||||
background: #E8EFFF;
|
||||
color: #222222;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.is-current > .el-tree-node__content {
|
||||
&:hover {
|
||||
background: #2266FF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
background: #2266FF;
|
||||
|
||||
span {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-steps {
|
||||
::v-deep .el-step__icon {
|
||||
font-size: 12px;
|
||||
color: #555555;
|
||||
border-color: #d0d4dc;
|
||||
}
|
||||
|
||||
::v-deep .el-step__head.is-finish {
|
||||
.el-step__icon.is-text {
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
background: #2266ff;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-step__line {
|
||||
background-color: #d0d4dc;
|
||||
}
|
||||
}
|
||||
|
||||
.imgs {
|
||||
font-size: 0;
|
||||
|
||||
img {
|
||||
width: 108px;
|
||||
height: 108px;
|
||||
margin-right: 4px;
|
||||
margin-bottom: 4px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&:nth-of-type(2n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .report-dialog {
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-step__head.is-process {
|
||||
color: #555;
|
||||
border-color: #555;
|
||||
}
|
||||
|
||||
::v-deep .is-finish h2 {
|
||||
color: #2266ff;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.detail-content__wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
.detail-content__wrapper--left {
|
||||
flex: 1;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ai-detail__content {
|
||||
background: #f3f6f9;
|
||||
|
||||
.ai-detail__content--wrapper {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
|
||||
& > .el-card {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.rightZone {
|
||||
width: 400px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-card {
|
||||
.el-card__header {
|
||||
padding: 12px 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.el-card__body {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
#amap {
|
||||
width: 466px;
|
||||
height: 232px;
|
||||
}
|
||||
|
||||
.el-steps {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.imgFormItem > .el-form-item__content {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
&:before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.el-image__inner {
|
||||
width: 82px;
|
||||
height: 82px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
149
packages/conv/AppReportAiWill/components/List.vue
Normal file
149
packages/conv/AppReportAiWill/components/List.vue
Normal file
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<ai-list>
|
||||
<template #title>
|
||||
<ai-title title="随手拍" isShowBottomBorder>
|
||||
<el-button type="primary" slot="rightBtn" @click="toSetting">设置</el-button>
|
||||
</ai-title>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<ai-select
|
||||
v-model="search.eventStatus"
|
||||
clearable
|
||||
placeholder="处理状态"
|
||||
:selectList="dict.getDict('clapEventStatus')"
|
||||
@change="search.current = 1, getList()">
|
||||
</ai-select>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.content"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入内容描述/上报居民/联系方式"
|
||||
clearable
|
||||
@change="getList"
|
||||
@clear="search.current = 1, search.content = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :colConfigs="colConfigs" :total="total" :current.sync="search.current" :size.sync="search.size" @getList="getList">
|
||||
<el-table-column slot="options" label="操作" fixed="right" width="120" align="center">
|
||||
<div class="table-options" slot-scope="{row}">
|
||||
<el-button type="text" title="详情" @click="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" title="删除" @click="handleDelete(row.id)">删除</el-button>
|
||||
</div>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'List',
|
||||
label: "随手拍",
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
userList: [],
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
eventStatus: '',
|
||||
content: ''
|
||||
},
|
||||
total: 0,
|
||||
tableData: [],
|
||||
content: '',
|
||||
id: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
colConfigs() {
|
||||
return [
|
||||
{prop: 'content', label: '内容描述', width: '300px'},
|
||||
{prop: 'groupName', label: '事件类型', align: 'center'},
|
||||
{prop: 'girdName', label: '所属网格', align: 'center'},
|
||||
{prop: 'createTime', label: '上报时间', align: 'center'},
|
||||
{prop: 'name', label: '上报居民', align: 'center'},
|
||||
{prop: 'phone', label: '联系方式', align: 'center'},
|
||||
{prop: 'eventStatus', label: '处理状态', align: 'center', formart: v => this.dict.getLabel('clapEventStatus', v)},
|
||||
{prop: 'processTime', label: '处理时长', align: 'center'},
|
||||
{slot: 'options'}
|
||||
]
|
||||
},
|
||||
|
||||
handleStatusOps() {
|
||||
return this.dict.getDict("reportAtWillHandleStatus").map(e => ({label: e.dictName, value: e.dictValue}))
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.dict.load('clapEventStatus').then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appclapeventinfo/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toDetail(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toSetting() {
|
||||
this.$emit('change', {
|
||||
type: 'Setting',
|
||||
params: {
|
||||
id: ''
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(ids) {
|
||||
this.$confirm("是否要进行删除?").then(() => {
|
||||
this.instance.post("/app/appclapeventinfo/delete", null, {
|
||||
params: {ids}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("删除成功!")
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}).catch(() => 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
178
packages/conv/AppReportAiWill/components/Setting.vue
Normal file
178
packages/conv/AppReportAiWill/components/Setting.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<ai-list class="notice">
|
||||
<template slot="title">
|
||||
<ai-title isShowBack isShowBottomBorder title="事件类型" @onBackClick="cancel(false)"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
<template #left>
|
||||
<el-button size="small" type="primary" icon="iconfont iconAdd" @click="isShowAdd = true">添加事件类型</el-button>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.groupName"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入事件类型名称"
|
||||
clearable
|
||||
@change="getList"
|
||||
@clear="search.current = 1, search.groupName = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
style="margin-top: 6px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="tags" label="标签">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-tags">
|
||||
<el-tag type="info" v-for="(item, index) in row.tags" size="small" :key="index">{{ item }}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" width="120px" fixed="right" label="操作" align="center">
|
||||
<div class="table-options" slot-scope="{ row }">
|
||||
<el-button type="text" @click="edit(row)">编辑</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowAdd"
|
||||
width="780px"
|
||||
height="580px"
|
||||
:title="id ? '编辑事件类型' : '添加事件类型'"
|
||||
@close="onClose"
|
||||
@onConfirm="onConfirm">
|
||||
<el-form ref="form" class="ai-form" :model="form" label-width="110px" label-position="right">
|
||||
<el-form-item label="事件类型" prop="groupName" style="width: 100%;" :rules="[{ required: true, message: '请输入事件类型名称', trigger: 'blur' }]">
|
||||
<el-input size="small" :maxlength="10" show-word-limit placeholder="请输入事件类型名称" v-model="form.groupName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="showIndex" style="width: 100%;" :rules="[{ required: true, message: '请输入排序', trigger: 'blur' }]">
|
||||
<el-input-number size="small" v-model="form.showIndex" :min="1" :max="100" label="请输入排序"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
groupName: ''
|
||||
},
|
||||
form: {
|
||||
groupName: '',
|
||||
showIndex: ''
|
||||
},
|
||||
id: '',
|
||||
isShowAdd: false,
|
||||
total: 0,
|
||||
colConfigs: [
|
||||
{prop: 'groupName', label: '事件类型', align: 'left'},
|
||||
{prop: 'showIndex', label: '排序', align: 'center'},
|
||||
{slot: 'options', label: '操作'}
|
||||
],
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appclapeventgroup/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
edit (e) {
|
||||
this.id = e.id
|
||||
this.form.groupName = e.groupName
|
||||
this.form.showIndex = ''
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.isShowAdd = true
|
||||
})
|
||||
},
|
||||
|
||||
onClose () {
|
||||
this.id = ''
|
||||
this.form.showIndex = ''
|
||||
this.form.groupName = ''
|
||||
},
|
||||
|
||||
onConfirm () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post(`/app/appclapeventgroup/addOrUpdate`, {
|
||||
...this.form,
|
||||
id: this.id || null
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('添加成功')
|
||||
this.isShowAdd = false
|
||||
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appclapeventgroup/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
105
packages/conv/AppReturnHomeRegister/AppReturnHomeRegister.vue
Normal file
105
packages/conv/AppReturnHomeRegister/AppReturnHomeRegister.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<ai-list class="AppReturnHomeRegister" v-if="!isShowDetail">
|
||||
<template slot="title">
|
||||
<ai-title title="返乡登记" :isShowBottomBorder="false" :fullname.sync="areaName" v-model="areaId" :instance="instance" @change="onAreaChange"></ai-title>
|
||||
</template>
|
||||
<template slot="tabs">
|
||||
<el-tabs v-model="currIndex">
|
||||
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label">
|
||||
<component :areaId="areaId" :ref="String(i)" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance" :dict="dict" :permissions="permissions"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
</ai-list>
|
||||
<Detail v-else-if="component === 'Detail'" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></Detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List.vue'
|
||||
import Detail from './components/Detail.vue'
|
||||
import AbnormalList from './components/AbnormalList.vue'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AppReturnHomeRegister',
|
||||
label: '返乡登记',
|
||||
|
||||
components: {
|
||||
List,
|
||||
Detail,
|
||||
AbnormalList
|
||||
},
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
tabs () {
|
||||
const tabList = [
|
||||
{label: '返乡登记', name: 'List', comp: List, permission: ''},
|
||||
// {label: '历史异常人员', name: 'AbnormalList', comp: AbnormalList, permission: ''}
|
||||
]
|
||||
|
||||
return tabList
|
||||
}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
activeName: 'JoinEvent',
|
||||
currIndex: '0',
|
||||
component: 'List',
|
||||
params: {},
|
||||
areaId: '',
|
||||
isShowDetail: false,
|
||||
areaName: ''
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.areaId = this.user.info.areaId
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (data) {
|
||||
if (data.type === 'Detail') {
|
||||
this.component = 'Detail'
|
||||
this.isShowDetail = true
|
||||
this.params = data.params
|
||||
}
|
||||
if (data.type === 'AbnormalList') {
|
||||
this.component = 'AbnormalList'
|
||||
this.isShowDetail = false
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'List') {
|
||||
this.component = 'List'
|
||||
this.isShowDetail = false
|
||||
this.params = data.params
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (data.isRefresh) {
|
||||
this.$refs.component.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onAreaChange () {
|
||||
this.$refs[this.currIndex][0].changeArea()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppReturnHomeRegister {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
200
packages/conv/AppReturnHomeRegister/components/AbnormalList.vue
Normal file
200
packages/conv/AppReturnHomeRegister/components/AbnormalList.vue
Normal file
@@ -0,0 +1,200 @@
|
||||
<template>
|
||||
<ai-list isTabs>
|
||||
<template slot="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template #left>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
clearable
|
||||
placeholder="请选择健康状态"
|
||||
:selectList="dictList"
|
||||
@change="search.current = 1, getList()">
|
||||
</ai-select>
|
||||
<ai-download :instance="instance" url="/app/appepidemicbackhomerecord/export" :params="param" fileName="返乡登记" :disabled="tableData.length == 0">
|
||||
<el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button>
|
||||
</ai-download>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.name"
|
||||
size="small"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
@clear="search.current = 1, search.name = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
v-loading="loading"
|
||||
style="margin-top: 16px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="options" width="140px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'AbnormalList',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
name: '',
|
||||
arriveAreaId: '',
|
||||
status: ''
|
||||
},
|
||||
dictList: [{
|
||||
dictName: '异常',
|
||||
dictValue: '0'
|
||||
}, {
|
||||
dictName: '正常',
|
||||
dictValue: '1'
|
||||
}],
|
||||
info: {},
|
||||
colConfigs: [
|
||||
{ prop: 'name', label: '姓名' },
|
||||
{ prop: 'phone', align: 'center', label: '手机号码' },
|
||||
{ prop: 'startTime', align: 'center', label: '出发时间', formart: v => v.substr(0, v.length - 3) },
|
||||
{
|
||||
prop: 'startAreaName',
|
||||
align: 'center',
|
||||
label: '出发地区'
|
||||
},
|
||||
{ prop: 'arriveTime', align: 'center', label: '到达时间', formart: v => v.substr(0, v.length - 3) },
|
||||
{
|
||||
prop: 'arriveAreaName',
|
||||
align: 'center',
|
||||
label: '到达地区'
|
||||
},
|
||||
{ prop: 'checkTime', align: 'center', label: '核酸日期', formart: v => v.split(' ')[0] },
|
||||
{
|
||||
prop: 'status',
|
||||
align: 'center',
|
||||
label: '健康状态',
|
||||
render: (h, {row}) => {
|
||||
return h('span', {
|
||||
style: {
|
||||
color: row.status === '0' ? 'red' : '#333'
|
||||
}
|
||||
}, row.status === '0' ? '异常' : '正常')
|
||||
}
|
||||
}
|
||||
],
|
||||
ids: [],
|
||||
tableData: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
disabledLevel: 0
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
param () {
|
||||
return this.search
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.disabledLevel = this.user.info.areaList.length - 1
|
||||
this.search.arriveAreaId = this.user.info.areaId
|
||||
this.loading = true
|
||||
this.dict.load(['marriageType', 'marriagePersonType', 'modeType']).then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
this.instance.post(`/app/appepidemicbackhomerecord/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
this.loading = false
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
this.getTotalInfo()
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
changeArea () {
|
||||
this.search.current = 1
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getList()
|
||||
this.getTotalInfo()
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appepidemicbackhomerecord/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getTotalInfo()
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
getTotalInfo () {
|
||||
this.instance.post(`/app/appepidemicbackhomerecord/statistic`, null, {
|
||||
params: {
|
||||
areaId: this.search.arriveAreaId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.info = res.data
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
279
packages/conv/AppReturnHomeRegister/components/Detail.vue
Normal file
279
packages/conv/AppReturnHomeRegister/components/Detail.vue
Normal file
@@ -0,0 +1,279 @@
|
||||
<template>
|
||||
<ai-detail isHasSidebar>
|
||||
<template slot="title">
|
||||
<ai-title title="返乡登记详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<AiSidebar :tabTitle="tabList" v-model="currIndex"></AiSidebar>
|
||||
<div v-show="currIndex === 0">
|
||||
<ai-card title="基本信息" v-show="currIndex === 0">
|
||||
<template #content>
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="姓名" :value="info.name"></ai-info-item>
|
||||
<ai-info-item label="填报时间" :value="info.createTime"></ai-info-item>
|
||||
<ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item>
|
||||
<ai-info-item label="手机号码" :value="info.phone"></ai-info-item>
|
||||
<ai-info-item label="人员类别" isLine>
|
||||
<span :style="info.type == 0 ? 'color:#42D784;' : 'color:#f46;'">{{dict.getLabel('epidemicMemberType', info.type)}}</span>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="行程信息">
|
||||
<template #content>
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="出发时间" :value="info.startTime"></ai-info-item>
|
||||
<ai-info-item label="出发地区" >
|
||||
<span :style="{color: info.denger == 1 ? '#FF4466' : '#333'}">{{info.startAreaName}} </span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="出发地址" isLine :value="info.startAddress"></ai-info-item>
|
||||
<ai-info-item label="出行方式" :value="dict.getLabel('epidemicRecentTravel', info.travelType)"></ai-info-item>
|
||||
<ai-info-item label="行程描述" isLine :value="info.description"></ai-info-item>
|
||||
<ai-info-item label="到达时间" :value="info.arriveTime"></ai-info-item>
|
||||
<ai-info-item label="到达地区" :value="info.arriveAreaName"></ai-info-item>
|
||||
<ai-info-item label="返乡地址" isLine :value="info.arriveAddress"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="健康状况">
|
||||
<template #content>
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="当前体温">
|
||||
<span :style="info.temperature >= 37.3 ? 'color:#f46;' : ''">{{ info.temperature + '℃' }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="14天内是否接触新冠确诊或疑似患者">
|
||||
<span :class="'color-'+info.touchInFourteen">{{$dict.getLabel('epidemicTouchInFourteen', info.touchInFourteen)}}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="当前健康状况">
|
||||
<span></span>
|
||||
<span v-for="(item, index) in info.health" :key="index" :style="item != 0 ? 'color:#FF4466;' : ''"><span v-if="index>0">;</span>{{$dict.getLabel('epidemicRecentHealth', item)}}</span>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="核酸检测">
|
||||
<template #content>
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="检测日期" :value="info.checkTime && info.checkTime.split(' ')[0]"></ai-info-item>
|
||||
<ai-info-item label="检测结果">
|
||||
<span :style="info.checkResult == 1 ? 'color:#f46;' : 'color:#42D784;'">{{$dict.getLabel('epidemicRecentTestResult', info.checkResult)}}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="本人健康码截图" isLine>
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
v-model="info.checkPhoto"
|
||||
disabled
|
||||
:limit="9">
|
||||
</ai-uploader>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
</div>
|
||||
<div v-show="currIndex === 1">
|
||||
<ai-card title="异常处理">
|
||||
<template #right>
|
||||
<el-button type="primary" v-if="info.status === '0'" @click="release">解除异常</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="姓名" :value="info.name"></ai-info-item>
|
||||
<ai-info-item label="填报时间" :value="info.createTime"></ai-info-item>
|
||||
<ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item>
|
||||
<ai-info-item label="手机号码" :value="info.phone"></ai-info-item>
|
||||
<ai-info-item label="人员类别" isLine :value="dict.getLabel('epidemicMemberType', info.type)"></ai-info-item>
|
||||
<ai-info-item label="异常状况" isLine>
|
||||
<span :style="{color: info.unusual ? 'red' : '#333'}">{{ info.unusual || '-' }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="异常解除人" v-if="info.releaseName && info.status === '1'" :value="info.releaseName"></ai-info-item>
|
||||
<ai-info-item label="异常解除时间" v-if="info.releaseTime && info.status === '1'" :value="info.releaseTime"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="异常情况记录">
|
||||
<template #right>
|
||||
<el-button type="primary" v-if="info.status === '0'" @click="isShow = true">添加记录</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="options" width="120px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-dialog
|
||||
:visible.sync="isShow"
|
||||
width="800px"
|
||||
@close="form.content = ''"
|
||||
title="添加异常记录"
|
||||
@onConfirm="onConfirm">
|
||||
<el-form class="ai-form" label-width="120px" :model="form" ref="form">
|
||||
<el-form-item label="异常记录" prop="content" style="width: 100%;" :rules="[{ required: true, message: '请输入异常记录' }]">
|
||||
<el-input type="textarea" :rows="5" :maxlength="500" v-model="form.content" clearable placeholder="请输入异常记录" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Detail',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
total: 0,
|
||||
info: {},
|
||||
id: '',
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10
|
||||
},
|
||||
form: {
|
||||
content: ''
|
||||
},
|
||||
isShow: false,
|
||||
currIndex: 0,
|
||||
tableData: [],
|
||||
colConfigs: [
|
||||
{prop: 'content', label: '异常记录', align: 'center' },
|
||||
{prop: 'createTime', label: '创建时间', align: 'center'},
|
||||
{prop: 'createUserName', label: '记录人', align: 'center' }
|
||||
],
|
||||
tabList: ['基本信息', '异常处理']
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.$dict.load(['epidemicRecentHealth', 'epidemicRecentTravel', 'epidemicTouchInFourteen', 'epidemicMemberType', 'epidemicRecentTestResult']).then(() => {
|
||||
this.getInfo(this.params.id)
|
||||
})
|
||||
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appepidemicbackhomerecord/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
this.info.checkPhoto = res.data.checkPhoto ? JSON.parse(res.data.checkPhoto) : []
|
||||
let healthName = ''
|
||||
this.info.isHealth = false
|
||||
res.data.health.split(',').forEach(v => {
|
||||
if (v > 0) {
|
||||
this.info.isHealth = true
|
||||
}
|
||||
healthName = healthName + this.$dict.getLabel('epidemicRecentHealth', v)
|
||||
})
|
||||
this.info.healthName = healthName
|
||||
this.info.health = this.info.health.split(',')
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
release () {
|
||||
this.$confirm('确定解除异常?').then(() => {
|
||||
this.instance.post(`/app/appepidemicbackhomerecord/release?recordId=${this.params.id}`, {
|
||||
id: this.params.id
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('解除异常成功!')
|
||||
this.currIndex = 0
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appepidemicunusuallog/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onConfirm() {
|
||||
this.$refs.form.validate(v => {
|
||||
if (v) {
|
||||
this.instance.post('/app/appepidemicunusuallog/addOrUpdate', {
|
||||
...this.form,
|
||||
recordId: this.params.id
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.isShow = false
|
||||
this.getList()
|
||||
this.$message.success('添加成功!')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getList () {
|
||||
this.instance.post(`/app/appepidemicunusuallog/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
recordId: this.params.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel () {
|
||||
this.$emit('change', {
|
||||
type: 'List',
|
||||
isRefresh: true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.color-0{
|
||||
color: #42D784;
|
||||
}
|
||||
.color-1{
|
||||
color: #f46;
|
||||
}
|
||||
.color-2{
|
||||
color: #1365DD;
|
||||
}
|
||||
</style>
|
||||
273
packages/conv/AppReturnHomeRegister/components/List.vue
Normal file
273
packages/conv/AppReturnHomeRegister/components/List.vue
Normal file
@@ -0,0 +1,273 @@
|
||||
<template>
|
||||
<ai-list class="list" isTabs>
|
||||
<template slot="content">
|
||||
<div class="statistics-top">
|
||||
<div class="statistics-top__item">
|
||||
<span>返乡人数</span>
|
||||
<h2 style="color: #2266FF;">{{ info.total }}</h2>
|
||||
</div>
|
||||
<div class="statistics-top__item">
|
||||
<span>今日新增返乡</span>
|
||||
<h2 style="color: #22AA99;">{{ info.today }}</h2>
|
||||
</div>
|
||||
<div class="statistics-top__item">
|
||||
<span>异常人数</span>
|
||||
<h2 style="color: #F8B425">{{ info.unusual }}</h2>
|
||||
</div>
|
||||
<div class="statistics-top__item">
|
||||
<span>今日异常人数</span>
|
||||
<h2 style="color: red">{{ info.todayUnusual }}</h2>
|
||||
</div>
|
||||
<div class="statistics-top__item">
|
||||
<span>异常处理</span>
|
||||
<h2 style="color: red">{{ info.release }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template #left>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
clearable
|
||||
placeholder="请选择健康状态"
|
||||
:selectList="dictList"
|
||||
@change="search.current = 1, getList()">
|
||||
</ai-select>
|
||||
<ai-download :instance="instance" url="/app/appepidemicbackhomerecord/export" :params="param" fileName="返乡登记" :disabled="tableData.length == 0">
|
||||
<el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button>
|
||||
</ai-download>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.name"
|
||||
size="small"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
@clear="search.current = 1, search.name = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
v-loading="loading"
|
||||
style="margin-top: 16px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="options" width="140px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
areaId: String
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
name: '',
|
||||
status: ''
|
||||
},
|
||||
dictList: [{
|
||||
dictName: '异常',
|
||||
dictValue: '0'
|
||||
}, {
|
||||
dictName: '正常',
|
||||
dictValue: '1'
|
||||
}],
|
||||
info: {},
|
||||
colConfigs: [
|
||||
{ prop: 'name', label: '姓名' },
|
||||
{ prop: 'phone', align: 'center', label: '手机号码' },
|
||||
{ prop: 'startTime', align: 'center', label: '出发时间', formart: v => v.substr(0, v.length - 3) },
|
||||
{
|
||||
prop: 'startAreaName',
|
||||
align: 'center',
|
||||
label: '出发地区'
|
||||
},
|
||||
{ prop: 'arriveTime', align: 'center', label: '到达时间', formart: v => v.substr(0, v.length - 3) },
|
||||
{
|
||||
prop: 'arriveAreaName',
|
||||
align: 'center',
|
||||
label: '到达地区'
|
||||
},
|
||||
{ prop: 'checkTime', align: 'center', label: '核酸日期', formart: v => v.split(' ')[0] },
|
||||
{
|
||||
prop: 'status',
|
||||
align: 'center',
|
||||
label: '健康状态',
|
||||
render: (h, {row}) => {
|
||||
return h('span', {
|
||||
style: {
|
||||
color: row.status === '0' ? 'red' : '#333'
|
||||
}
|
||||
}, row.status === '0' ? '异常' : '正常')
|
||||
}
|
||||
}
|
||||
],
|
||||
ids: [],
|
||||
tableData: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
disabledLevel: 0
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
param () {
|
||||
return this.search
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.disabledLevel = this.user.info.areaList.length - 1
|
||||
this.loading = true
|
||||
this.dict.load(['marriageType', 'marriagePersonType', 'modeType']).then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
this.instance.post(`/app/appepidemicbackhomerecord/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
arriveAreaId: this.areaId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
this.loading = false
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
this.getTotalInfo()
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
changeArea () {
|
||||
this.search.current = 1
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getList()
|
||||
this.getTotalInfo()
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appepidemicbackhomerecord/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getTotalInfo()
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
getTotalInfo () {
|
||||
this.instance.post(`/app/appepidemicbackhomerecord/statistic`, null, {
|
||||
params: {
|
||||
areaId: this.search.arriveAreaId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.info = res.data
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.list {
|
||||
::v-deep .ai-list__content {
|
||||
padding: 0!important;
|
||||
|
||||
.ai-list__content--right-wrapper {
|
||||
background: transparent!important;
|
||||
box-shadow: none!important;
|
||||
margin: 0!important;
|
||||
padding: 0 0 0!important;
|
||||
}
|
||||
}
|
||||
.statistics-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
& > div {
|
||||
flex: 1;
|
||||
height: 96px;
|
||||
line-height: 1;
|
||||
margin-right: 20px;
|
||||
padding: 16px 24px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
border-radius: 4px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
color: #888888;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 16px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
65
packages/conv/AppRiskArea/AppRiskArea.vue
Normal file
65
packages/conv/AppRiskArea/AppRiskArea.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<div class="doc-circulation ailist-wrapper">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :moduleName="moduleName" :moduleId="moduleId" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List'
|
||||
import Add from './components/Add'
|
||||
|
||||
export default {
|
||||
name: 'AppRiskArea',
|
||||
label: '风险配置',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
moduleId: '',
|
||||
include: [],
|
||||
moduleName: ''
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (data) {
|
||||
if (data.type === 'Add') {
|
||||
this.component = 'Add'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'list') {
|
||||
this.component = 'List'
|
||||
this.params = data.params
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (data.isRefresh) {
|
||||
this.$refs.component.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.doc-circulation {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
154
packages/conv/AppRiskArea/components/Add.vue
Normal file
154
packages/conv/AppRiskArea/components/Add.vue
Normal file
@@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<ai-detail class="content-add">
|
||||
<template slot="title">
|
||||
<ai-title :title="params.id ? '编辑风险区域' : '添加风险区域'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form class="ai-form" :model="form" label-width="120px" ref="form">
|
||||
<el-form-item prop="areaId" style="width: 100%;" label="选择地区" :rules="[{required: true, message: '请选择地区', trigger: 'change'}]">
|
||||
<ai-area-select clearable @fullname="v => form.areaName = v" always-show :instance="instance" v-model="form.areaId"></ai-area-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="风险等级" style="width: 100%;" prop="level" :rules="[{required: true, message: '请选择风险等级', trigger: 'change'}]">
|
||||
<ai-select
|
||||
v-model="form.level"
|
||||
clearable
|
||||
placeholder="请选择风险等级"
|
||||
:selectList="dict.getDict('epidemicDangerousAreaLevel')">
|
||||
</ai-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">提交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'Add',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object,
|
||||
moduleName: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
info: {},
|
||||
form: {
|
||||
level: '',
|
||||
areaId: '',
|
||||
areaName: ''
|
||||
},
|
||||
id: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created () {
|
||||
this.dict.load('epidemicDangerousAreaLevel').then(() => {
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appepidemicdangerousarea/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
confirm () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post(`/app/appepidemicdangerousarea/addOrUpdate`, {
|
||||
...this.form
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content-add {
|
||||
.video {
|
||||
width: 640px;
|
||||
height: 360px;
|
||||
border-radius: 4px;
|
||||
border: 1px dashed #D0D4DC;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
span:nth-child(2) {
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
display: inline-block;
|
||||
font-size: 40px;
|
||||
color: #2266FF;
|
||||
}
|
||||
}
|
||||
|
||||
.tips {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
line-height: 26px;
|
||||
}
|
||||
}
|
||||
|
||||
.video-com {
|
||||
width: 640px;
|
||||
height: 360px;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
margin-top: -40px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
141
packages/conv/AppRiskArea/components/List.vue
Normal file
141
packages/conv/AppRiskArea/components/List.vue
Normal file
@@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<ai-list class="notice">
|
||||
<template slot="title">
|
||||
<ai-title title="风险区域配置" isShowBottomBorder></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
<template #left>
|
||||
<ai-select
|
||||
v-model="search.level"
|
||||
clearable
|
||||
placeholder="请选择风险等级"
|
||||
:selectList="dict.getDict('epidemicDangerousAreaLevel')"
|
||||
@change="search.current = 1, getList()">
|
||||
</ai-select>
|
||||
<el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.province"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="省级名称/市级名称/区级名称"
|
||||
clearable
|
||||
@clear="search.current = 1, search.province = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
style="margin-top: 6px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="options" width="140px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toAdd(row.id)">编辑</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
moduleName: String
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
level: '',
|
||||
province: ''
|
||||
},
|
||||
currIndex: -1,
|
||||
areaList: [],
|
||||
total: 10,
|
||||
colConfigs: [
|
||||
{ prop: 'province', label: '省级', align: 'left', width: '200px' },
|
||||
{ prop: 'city', label: '市级', align: 'center' },
|
||||
{ prop: 'district', label: '区级', align: 'center' },
|
||||
{ prop: 'town', label: '镇级', align: 'center' },
|
||||
{ prop: 'village', label: '村级', align: 'center' },
|
||||
{ prop: 'level', label: '等级', align: 'center', formart: v => this.dict.getLabel('epidemicDangerousAreaLevel', v) },
|
||||
{ prop: 'createTime', label: '设置时间', align: 'center' },
|
||||
{ prop: 'createUserName', label: '添加人', align: 'center' },
|
||||
{ slot: 'options', label: '操作', align: 'center' }
|
||||
],
|
||||
areaName: '',
|
||||
unitName: '',
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created() {
|
||||
this.dict.load('epidemicDangerousAreaLevel').then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appepidemicdangerousarea/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appepidemicdangerousarea/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
toAdd(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.notice {
|
||||
}
|
||||
</style>
|
||||
205
packages/conv/AppVaccination/AppVaccination.vue
Normal file
205
packages/conv/AppVaccination/AppVaccination.vue
Normal file
@@ -0,0 +1,205 @@
|
||||
<template>
|
||||
<section class="AppVaccination">
|
||||
<ai-list v-if="!showDetail">
|
||||
<ai-title slot="title" title="疫苗接种" isShowBottomBorder isShowArea v-model="areaId" :instance="instance"
|
||||
@change="page.current=1,getTableData()"/>
|
||||
<template #blank>
|
||||
<el-row type="flex">
|
||||
<div class="dataPane" v-for="(op,i) in dataPanes" :key="i">
|
||||
{{ [op.label, op.v].join(" ") }}
|
||||
</div>
|
||||
</el-row>
|
||||
<div class="mainPane">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<ai-select placeholder="接种状况" v-model="search.inoculationType" @change="page.current=1,getTableData()"
|
||||
:selectList="dict.getDict('vaccineInoculationType')"/>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input placeholder="姓名/身份证/联系方式"
|
||||
v-model="search.name"
|
||||
size="small"
|
||||
clearable
|
||||
@clear="page.current = 1,search.name = '', getTableData()"
|
||||
v-throttle="() => {page.current = 1, getTableData()}"
|
||||
suffix-icon="iconfont iconSearch"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="$router.push({hash:'#add'})">添加</el-button>
|
||||
<el-button icon="iconfont iconDelete" :disabled="!ids.length" @click="handleDelete(ids)">删除</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<ai-import :instance="instance" :dict="dict" name="疫苗接种" suffixName="xlsx"
|
||||
type="appvaccineinoculationuser" @onSuccess="resetSearch"/>
|
||||
<ai-download url="/app/appvaccineinoculationuser/export" :params="{...search,areaId,ids:ids.toString()}"
|
||||
:instance="instance" fileName="疫苗接种导出文件"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :colConfigs="colConfigs" :total="page.total" :current.sync="page.current"
|
||||
:size.sync="page.size" @getList="getTableData" :dict="dict"
|
||||
@selection-change="v=>ids=v.map(e=>e.id)">
|
||||
<el-table-column slot="vaccinationDate" label="接种日期" align="center" class-name="vaccinationDate">
|
||||
<el-table-column label="第一次" align="center" prop="firstDate"/>
|
||||
<el-table-column label="第二次" align="center" prop="secondDate"/>
|
||||
<el-table-column label="第三次" align="center" prop="thirdDate"/>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right">
|
||||
<template slot-scope="{row:{id}}">
|
||||
<el-button type="text" @click="$router.push({hash:'#add',query:{id}})">编辑</el-button>
|
||||
<el-button type="text" @click="handleDelete(id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
<add-vaccination v-else :dict="dict" :instance="instance"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import AddVaccination from "./addVaccination";
|
||||
|
||||
export default {
|
||||
name: "AppVaccination",
|
||||
components: {AddVaccination},
|
||||
label: "疫苗接种",
|
||||
provide() {
|
||||
return {
|
||||
top: this
|
||||
}
|
||||
},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
areaId: "",
|
||||
page: {current: 1, size: 10, total: 0},
|
||||
search: {inoculationType: "", name: ""},
|
||||
ids: [],
|
||||
tableData: [],
|
||||
staData: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
showDetail() {
|
||||
return this.$route.hash == "#add"
|
||||
},
|
||||
dataPanes() {
|
||||
return [
|
||||
{label: "总接种人数", v: this.staData.zjzrs || 0},
|
||||
{label: "已接种第一针人数", v: this.staData.yjzdyzrs || 0},
|
||||
{label: "已接种第二针人数", v: this.staData.yjzdezrs || 0},
|
||||
{label: "已接种第三针人数", v: this.staData.yjzdszrs || 0},
|
||||
]
|
||||
},
|
||||
colConfigs() {
|
||||
return [
|
||||
{type: "selection", align: 'center'},
|
||||
{label: "姓名", prop: "name", align: 'center'},
|
||||
{label: "性别", prop: "sex", dict: 'sex', align: 'center'},
|
||||
{label: "出生日期", prop: "birthday", align: 'center'},
|
||||
{
|
||||
label: "身份证号", width: "160px", align: 'center',
|
||||
render: (h, {row}) => h('span', null, this.idCardNoUtil.hideId(row.idNumber))
|
||||
},
|
||||
{label: "所属地区", prop: "areaName", align: 'center'},
|
||||
{label: "住址", prop: "address", width: "200px", align: 'center'},
|
||||
{label: "联系方式", prop: "phone", align: 'center'},
|
||||
{slot: 'vaccinationDate'},
|
||||
{slot: "options"},
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.areaId = JSON.parse(JSON.stringify(this.user.info.areaId))
|
||||
this.dict.load('sex', 'vaccineInoculationType')
|
||||
this.getTableData()
|
||||
},
|
||||
methods: {
|
||||
getStaData() {
|
||||
this.instance.post(`/app/appvaccineinoculationuser/countByAreaId`, null, {
|
||||
params: {areaId: this.areaId}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.staData = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
getTableData() {
|
||||
this.page.current == 1 && this.getStaData()
|
||||
this.instance.post(`/app/appvaccineinoculationuser/list`, null, {
|
||||
params: {...this.search, ...this.page, areaId: this.areaId}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.page.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(ids) {
|
||||
ids = ids?.toString()
|
||||
this.$confirm("确定要删除该条数据吗?").then(() => {
|
||||
this.instance.post(`/app/appvaccineinoculationuser/delete`, null, {
|
||||
params: {ids}
|
||||
}).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("删除成功!");
|
||||
this.getTableData();
|
||||
}
|
||||
})
|
||||
}).catch(() => 0)
|
||||
},
|
||||
resetSearch() {
|
||||
this.page.current = 1
|
||||
this.search = {}
|
||||
this.getTableData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppVaccination {
|
||||
height: 100%;
|
||||
|
||||
::v-deep .dataPane {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
border-radius: 2px;
|
||||
margin-bottom: 16px;
|
||||
margin-right: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 60px;
|
||||
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .mainPane {
|
||||
background: #fff;
|
||||
padding: 12px 16px;
|
||||
box-shadow: 0 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
|
||||
.vaccinationDate {
|
||||
border-bottom: 1px solid #D0D4DC;
|
||||
}
|
||||
|
||||
.ai-table__header {
|
||||
padding: 2px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
235
packages/conv/AppVaccination/addVaccination.vue
Normal file
235
packages/conv/AppVaccination/addVaccination.vue
Normal file
@@ -0,0 +1,235 @@
|
||||
<template>
|
||||
<section class="addVaccination">
|
||||
<ai-detail>
|
||||
<ai-title slot="title" :title="addTitle" isShowBottomBorder
|
||||
isShowBack @onBackClick="back"/>
|
||||
<template #content>
|
||||
<el-form size="small" :model="form" ref="vaccinationForm" :rules="rules" label-width="100px">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form-item label="受种人姓名" prop="name">
|
||||
<el-row type="flex" align="middle">
|
||||
<el-input placeholder="请输入" v-model="form.name" :disabled="isEdit" clearable
|
||||
style="margin-right: 8px"/>
|
||||
<ai-person-select v-if="!isEdit" :instance="instance" @selectPerson="handleSelectPerson"/>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证号码" prop="idNumber">
|
||||
<ai-id v-model="form.idNumber" @change="getInfoByIdNumber" :disabled="isEdit"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别" prop="sex">
|
||||
<ai-select disabled v-model="form.sex" :selectList="dict.getDict('sex')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生日期" prop="birthday">
|
||||
<el-date-picker v-model="form.birthday" type="date" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系方式" prop="phone">
|
||||
<el-input v-model="form.phone" placeholder="请输入"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属地区" isLine prop="areaId">
|
||||
<ai-area-select :instance="instance" v-model="form.areaId" always-show @name="v=>form.areaName=v"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="住址" isLine prop="address">
|
||||
<el-input v-model="form.address" placeholder="请输入"/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="接种情况">
|
||||
<template #right>
|
||||
<el-button icon="iconfont iconAdd" type="text" @click="dialog=true">添加</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<el-form-item isLine label-width="0">
|
||||
<ai-table :tableData="form.detailList" :colConfigs="colConfigs" :isShowPagination="false" :dict="dict">
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right">
|
||||
<template v-slot="{row,$index}">
|
||||
<el-button type="text" @click="handleEdit(row,$index)">编辑</el-button>
|
||||
<el-button type="text" @click="handleDelete($index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</ai-card>
|
||||
</el-form>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="back">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">提交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
<ai-dialog :visible.sync="dialog" title="接种情况" @closed="dialogForm={}" @onConfirm="handleConfirm">
|
||||
<el-form ref="appvaccineinoculationuser" size="small" :model="dialogForm" label-width="100px" :rules="rules">
|
||||
<el-form-item label="接种次数" prop="type">
|
||||
<ai-select v-model="dialogForm.type" :selectList="dict.getDict('vaccineType')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="接种日期" prop="vaccinateDate">
|
||||
<el-date-picker v-model="dialogForm.vaccinateDate" value-format="yyyy-MM-dd"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="接种人员" prop="vaccinatePerson">
|
||||
<el-input v-model="dialogForm.vaccinatePerson"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="生产企业" prop="createCompany">
|
||||
<el-input v-model="dialogForm.createCompany"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="接种单位" prop="vaccinateUnit">
|
||||
<el-input v-model="dialogForm.vaccinateUnit"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "addVaccination",
|
||||
inject: ['top'],
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {detailList: []},
|
||||
dialog: false,
|
||||
dialogForm: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
isEdit() {
|
||||
return !!this.$route.query.id
|
||||
},
|
||||
addTitle() {
|
||||
return this.isEdit ? '编辑疫苗接种人员' : '新增疫苗接种人员'
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
vaccinateDate: {required: true, message: "请选择 接种日期"},
|
||||
type: {required: true, message: "请选择 接种次数",},
|
||||
areaId: [
|
||||
{required: true, message: "请选择 所属地区"},
|
||||
{trigger:'blur',validator: (r, v, cb) => /0{3}$/g.test(v) ? cb('请选择到村/社区') : cb()}
|
||||
],
|
||||
name: {required: true, message: "请填写 受种人姓名"},
|
||||
idNumber: {required: true, message: "请填写 身份号码"},
|
||||
sex: {required: true, message: "请填写 性别"},
|
||||
birthday: {required: true, message: "请填写 出生日期"},
|
||||
phone: {required: true, message: "请填写 联系方式"},
|
||||
}
|
||||
},
|
||||
colConfigs() {
|
||||
return [
|
||||
{label: "类型", align: 'center', prop: "type", dict: 'vaccineType'},
|
||||
{label: "接种日期", align: 'center', prop: "vaccinateDate"},
|
||||
{label: "接种人员", align: 'center', prop: "vaccinatePerson"},
|
||||
{label: "生产企业", align: 'center', prop: "createCompany"},
|
||||
{label: "接种单位", align: 'center', prop: "vaccinateUnit"},
|
||||
{slot: "options"}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
this.$router.push({})
|
||||
},
|
||||
getDetail() {
|
||||
let {id} = this.$route.query
|
||||
if (id) {
|
||||
this.instance.post("/app/appvaccineinoculationuser/queryDetailById", null, {
|
||||
params: {id}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.form = res.data
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$set(this.form,'areaId',JSON.parse(JSON.stringify(this.top.areaId)))
|
||||
}
|
||||
},
|
||||
handleSubmit() {
|
||||
this.$refs.vaccinationForm?.validate(v => {
|
||||
if (v) {
|
||||
this.instance.post("/app/appvaccineinoculationuser/addOrUpdate", this.form).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.$message.success("提交成功!")
|
||||
this.top.resetSearch()
|
||||
this.back()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleEdit(row, index) {
|
||||
this.dialogForm = JSON.parse(JSON.stringify({...row, index}))
|
||||
this.dialog = true
|
||||
},
|
||||
handleConfirm() {
|
||||
this.$refs.appvaccineinoculationuser.validate(v => {
|
||||
if (v) {
|
||||
if (this.dialogForm.index > -1) {
|
||||
this.form.detailList.splice(this.dialogForm.index, 1, this.dialogForm)
|
||||
} else {
|
||||
this.form.detailList.push(this.dialogForm)
|
||||
}
|
||||
this.dialog = false
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSelectPerson(v) {
|
||||
let {name, idNumber, phone, currentAreaId:areaId, currentAddress:address} = v
|
||||
this.form = {...this.form, name, idNumber, phone, areaId, address}
|
||||
},
|
||||
getInfoByIdNumber(code) {
|
||||
if (this.idCardNoUtil.checkIdCardNo(code)) {
|
||||
let info = this.idCardNoUtil.getIdCardInfo(code)
|
||||
this.form.sex = this.dict.getValue('sex', info.gender)
|
||||
this.form.birthday = info.birthday
|
||||
this.$forceUpdate()
|
||||
}
|
||||
},
|
||||
handleDelete(index) {
|
||||
this.$confirm("是否要删除该条数据?").then(() => this.form.detailList.splice(index, 1)).catch(() => 0)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.dict.load('vaccineType')
|
||||
this.getDetail()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.addVaccination {
|
||||
height: 100%;
|
||||
|
||||
::v-deep .ai-card__body, .el-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ai-card {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
width: 50%;
|
||||
|
||||
&[isLine] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.el-date-editor {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-button {
|
||||
.iconfont {
|
||||
color: inherit
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
111
packages/conv/AppVillageActivity/AppVillageActivity.vue
Normal file
111
packages/conv/AppVillageActivity/AppVillageActivity.vue
Normal file
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<ai-list v-if="!isShowDetail">
|
||||
<template slot="title">
|
||||
<ai-title title="居民活动" :isShowBottomBorder="false" :isShowArea="currIndex === '0'" :fullname.sync="areaName" v-model="areaId" :instance="instance" @change="onAreaChange"></ai-title>
|
||||
</template>
|
||||
<template slot="tabs">
|
||||
<el-tabs v-model="currIndex">
|
||||
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label">
|
||||
<component :areaId="areaId" :ref="String(i)" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance" :dict="dict" :permissions="permissions"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
</ai-list>
|
||||
<Add v-else-if="componentName === 'Add'" :areaName="areaName" :areaId="areaId" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></Add>
|
||||
<Detail v-else-if="componentName === 'Detail'" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></Detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List.vue'
|
||||
import Statistics from './components/Statistics'
|
||||
import Add from './components/Add'
|
||||
import Detail from './components/Detail'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AppVillageActivity',
|
||||
label: '居民活动',
|
||||
|
||||
components: {
|
||||
List,
|
||||
Add,
|
||||
Detail,
|
||||
Statistics
|
||||
},
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
tabs () {
|
||||
const tabList = [
|
||||
{label: '活动管理', name: 'List', comp: List, permission: ''},
|
||||
{label: '报到数据', name: 'Statistics', comp: Statistics, permission: ''}
|
||||
].filter(item => {
|
||||
return true
|
||||
})
|
||||
|
||||
return tabList
|
||||
}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
activeName: 'JoinEvent',
|
||||
currIndex: '0',
|
||||
componentName: '',
|
||||
params: {},
|
||||
areaName: '',
|
||||
areaId: '',
|
||||
isShowDetail: false
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.areaId = this.user.info.areaId
|
||||
if (this.$route.query.id) {
|
||||
this.componentName = this.$route.query?.type
|
||||
this.params = {id: this.$route.query?.id}
|
||||
this.isShowDetail = true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onAreaChange () {
|
||||
if (this.currIndex === '0') {
|
||||
this.$nextTick(() => {
|
||||
this.$refs[this.currIndex][0].getList()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onChange (data) {
|
||||
if (data.type === 'list') {
|
||||
this.componentName = 'List'
|
||||
this.isShowDetail = false
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'Detail') {
|
||||
this.componentName = 'Detail'
|
||||
this.isShowDetail = true
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'Add') {
|
||||
this.componentName = 'Add'
|
||||
this.isShowDetail = true
|
||||
this.params = data.params
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
166
packages/conv/AppVillageActivity/components/Add.vue
Normal file
166
packages/conv/AppVillageActivity/components/Add.vue
Normal file
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<ai-detail>
|
||||
<template slot="title">
|
||||
<ai-title :title="params.id ? '编辑居民活动' : '添加居民活动'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="活动信息">
|
||||
<template #content>
|
||||
<el-form class="ai-form" :model="form" label-width="120px" ref="form">
|
||||
<el-form-item label="活动标题" style="width: 100%;" prop="title" :rules="[{required: true, message: '请输入活动标题', trigger: 'blur'}]">
|
||||
<el-input type="input" size="small" v-model="form.title" clearable placeholder="请输入活动标题..." maxlength="60" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="areaId" style="width: 100%;" label="发布地区" :rules="[{required: true, message: '请选择发布地区', trigger: 'change'}]">
|
||||
<ai-area-select @fullname="e => form.areaName = e" clearable always-show :instance="instance" v-model="form.areaId" :disabled-level="disabledLevel"></ai-area-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="beginTime" label="活动开始时间" :rules="[{required: true, message: '活动开始时间', trigger: 'change'}]">
|
||||
<el-date-picker
|
||||
style="width: 100%"
|
||||
v-model="form.beginTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
size="small"
|
||||
placeholder="活动开始时间">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item prop="endTime" label="活动结束时间" :rules="[{required: true, message: '活动结束时间', trigger: 'change'}]">
|
||||
<el-date-picker
|
||||
v-model="form.endTime"
|
||||
style="width: 100%"
|
||||
type="datetime"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="活动开始时间">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="活动地点" style="width: 100%;" prop="address" :rules="[{required: true, message: '请输入活动地点题', trigger: 'blur'}]">
|
||||
<el-input type="input" size="small" v-model="form.address" clearable placeholder="请输入活动地点题" maxlength="30" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系人" prop="contactPerson" :rules="[{required: true, message: '请输入联系人', trigger: 'blur'}]">
|
||||
<el-input type="input" size="small" v-model="form.contactPerson" clearable placeholder="请输入联系人" maxlength="30" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话" prop="contactPhone" :rules="[{required: true, message: '请输入联系电话', trigger: 'blur'}]">
|
||||
<el-input type="input" size="small" v-model="form.contactPhone" clearable placeholder="请输入联系电话" maxlength="30" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="活动介绍" style="width: 100%;" prop="content" :rules="[{required: true, message: '请输入内容', trigger: 'change'}]">
|
||||
<ai-editor v-model="form.content" :instance="instance"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="缩略图" style="width: 100%;" prop="url" :rules="[{required: true, message: '请上传缩略图', trigger: 'change'}]">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
isShowTip
|
||||
v-model="form.url"
|
||||
:limit="1">
|
||||
</ai-uploader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">提交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'Add',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object,
|
||||
areaId: String,
|
||||
areaName: String
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
info: {},
|
||||
form: {
|
||||
title: '',
|
||||
content: '',
|
||||
areaId: '',
|
||||
areaName: '',
|
||||
beginTime: '',
|
||||
endTime: '',
|
||||
address: '',
|
||||
contactPerson: '',
|
||||
contactPhone: '',
|
||||
url: []
|
||||
},
|
||||
id: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created () {
|
||||
this.form.areaId = this.areaId
|
||||
this.form.areaName = this.areaName
|
||||
this.disabledLevel = this.user.info.areaList.length
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appvillageactivityinfo/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form = res.data
|
||||
this.form.url = res.data.url ? JSON.parse(res.data.url) : []
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
confirm () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
const nowTime = new Date().getTime()
|
||||
const beginTime = new Date(this.form.beginTime).getTime()
|
||||
const endTime = new Date(this.form.endTime).getTime()
|
||||
|
||||
if (beginTime < nowTime) {
|
||||
return this.$message.error('活动开始时间不能早于当前时间')
|
||||
}
|
||||
if (endTime < beginTime) {
|
||||
return this.$message.error('活动结束时间不能早于活动开始时间')
|
||||
}
|
||||
|
||||
this.instance.post(`/app/appvillageactivityinfo/addOrUpdate`, {
|
||||
...this.form,
|
||||
url: this.form.url.length ? JSON.stringify([{
|
||||
url: this.form.url[0].url
|
||||
}]) : ''
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
136
packages/conv/AppVillageActivity/components/Detail.vue
Normal file
136
packages/conv/AppVillageActivity/components/Detail.vue
Normal file
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<ai-detail isHasSidebar>
|
||||
<template slot="title">
|
||||
<ai-title title="详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<AiSidebar :tabTitle="tabList" v-model="currIndex"></AiSidebar>
|
||||
<ai-card title="基本信息" v-show="currIndex === 0">
|
||||
<template #content>
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="活动标题" isLine :value="info.title"></ai-info-item>
|
||||
<ai-info-item label="发布地区" isLine :value="info.areaName"></ai-info-item>
|
||||
<ai-info-item label="活动开始时间" :value="info.beginTime"></ai-info-item>
|
||||
<ai-info-item label="活动结束时间" :value="info.endTime"></ai-info-item>
|
||||
<ai-info-item label="活动地点" isLine :value="info.address"></ai-info-item>
|
||||
<ai-info-item label="联系人" :value="info.contactPerson"></ai-info-item>
|
||||
<ai-info-item label="联系电话" :value="info.contactPhone"></ai-info-item>
|
||||
<ai-info-item label="活动介绍" isLine>
|
||||
<AiArticle :value="info.content"></AiArticle>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="缩略图">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
disabled
|
||||
v-model="info.url"
|
||||
:limit="1">
|
||||
</ai-uploader>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="报名情况" v-show="currIndex === 1">
|
||||
<template #content>
|
||||
<ai-table
|
||||
class="detail-table__table"
|
||||
:border="true"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
:stripe="false"
|
||||
@getList="getList">
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="活动动态" v-show="currIndex === 2">
|
||||
<template #content>
|
||||
<Dynamic :instance="instance" :dict="dict" :id="params.id" v-show="currIndex === 2"></Dynamic>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dynamic from './Dynamic'
|
||||
export default {
|
||||
name: 'Detail',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
components: {
|
||||
Dynamic
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
total: 0,
|
||||
info: {},
|
||||
id: '',
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10
|
||||
},
|
||||
currIndex: 0,
|
||||
tableData: [],
|
||||
colConfigs: [
|
||||
{prop: 'name', label: '报名人员名称', align: 'center' },
|
||||
{prop: 'createTime', label: '报名时间', align: 'center'},
|
||||
{prop: 'phone', label: '联系方式', align: 'center' }
|
||||
],
|
||||
tabList: ['基本信息', '报名情况', '活动动态']
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
this.getList(this.params.id)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appvillageactivityinfo/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
this.info.url = res.data.url ? JSON.parse(res.data.url) : []
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getList (id) {
|
||||
this.instance.post(`/app/appvillageactivityuser/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
activityId: id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
238
packages/conv/AppVillageActivity/components/Dynamic.vue
Normal file
238
packages/conv/AppVillageActivity/components/Dynamic.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<div class="bbs">
|
||||
<div v-if="list.length">
|
||||
<div class="bbs-title">
|
||||
<span>共</span>
|
||||
<i>{{ list.length }}</i>
|
||||
<span>条动态</span>
|
||||
</div>
|
||||
<div class="bbs-item" v-for="(item, index) in list" :key="index">
|
||||
<div class="bbs-item__info">
|
||||
<div class="bbs-item__info--top">
|
||||
<div class="left">
|
||||
<img :src="item.avatar" />
|
||||
<h2>{{ item.name }}</h2>
|
||||
</div>
|
||||
<i>{{ item.createTime }}</i>
|
||||
</div>
|
||||
<div class="bbs-item__info--content">
|
||||
<p>{{ item.content }}</p>
|
||||
<ai-uploader v-if="item.images && item.images.length" :instance="instance" :value="item.images" :limit="9" disabled></ai-uploader>
|
||||
<!-- <div class="text-button" @click="remove(item.id)">删除动态</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ai-empty class="empty" v-else></ai-empty>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Add',
|
||||
|
||||
props: {
|
||||
id: String,
|
||||
instance: Function
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
list: []
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getInfo(this.id)
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appvillageactivitypost/list?size=1000&activityId=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.list = res.data.records.map(v => {
|
||||
return {
|
||||
...v,
|
||||
images: v.images ? JSON.parse(v.images) : []
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appvillageactivitypost/delete?id=${id}`).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.bbs {
|
||||
padding-top: 16px;
|
||||
|
||||
::v-deep .ai-detail__content {
|
||||
background: #F3F6F9;
|
||||
}
|
||||
|
||||
::v-deep .ai-empty__bg {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.text-button {
|
||||
cursor: pointer;
|
||||
color: #5088FF;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.bbs-replay {
|
||||
margin-top: 16px;
|
||||
padding: 0 16px;
|
||||
background: #F5F6F7;
|
||||
|
||||
.bbs-replay__item {
|
||||
padding: 16px 0;
|
||||
border-bottom: 1px solid #DDDDDD;
|
||||
|
||||
.text-button {
|
||||
margin-left: 48px;
|
||||
}
|
||||
|
||||
& > p {
|
||||
line-height: 19px;
|
||||
margin: 8px 0 8px 48px;
|
||||
font-size: 14px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.bbs-replay__item--top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
|
||||
.right-user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #333333;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
i {
|
||||
padding: 0 4px;
|
||||
font-style: normal;
|
||||
font-size: 14px;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #999999;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bbs-item__info {
|
||||
.bbs-item__info--content {
|
||||
padding-left: 64px;
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #333333;
|
||||
margin-bottom: 10px;
|
||||
line-height: 19px;
|
||||
}
|
||||
}
|
||||
|
||||
.bbs-item__info--top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
padding-left: 16px;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #333333;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
color: #999999;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bbs-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 56px;
|
||||
line-height: 1;
|
||||
margin: 0 0 16px;
|
||||
padding: 0px 16px;
|
||||
background: #FFFFFF;
|
||||
color: #333333;
|
||||
font-size: 16px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #D8E0E8;
|
||||
|
||||
i {
|
||||
padding: 0 4px;
|
||||
color: #5088FF;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.bbs-item {
|
||||
margin-bottom: 16px;
|
||||
padding: 16px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #D8E0E8;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
268
packages/conv/AppVillageActivity/components/List.vue
Normal file
268
packages/conv/AppVillageActivity/components/List.vue
Normal file
@@ -0,0 +1,268 @@
|
||||
<template>
|
||||
<ai-list class="AppPetitionManage" isTabs>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
<template slot="left">
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="toAdd('')">发布活动</el-button>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="活动状态"
|
||||
:selectList="dict.getDict('villageActivityStatus')">
|
||||
</ai-select>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.title"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入活动名称"
|
||||
clearable
|
||||
@change="getList"
|
||||
@clear="search.current = 1, search.name = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
ref="aitableex"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
v-loading="isLoading"
|
||||
@getList="getList">
|
||||
<el-table-column slot="options" width="180px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" @click="toAdd(row.id)" :disabled="row.status === '1' || row.status === '2'">编辑</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
areaId: String
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
title: '',
|
||||
status: ''
|
||||
},
|
||||
isLoading: false,
|
||||
ids: [],
|
||||
total: 10,
|
||||
colConfigs: [
|
||||
{ prop: 'title', label: '活动名称', align: 'left' },
|
||||
{
|
||||
prop: 'areaName', label: '活动地区', align: 'center' ,
|
||||
render: (h, params) => {
|
||||
return h('span', {
|
||||
}, params.row.areaName)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'status', label: '活动状态', align: 'center',
|
||||
render: (h, params) => {
|
||||
return h('span', {
|
||||
}, this.dict.getLabel('villageActivityStatus', params.row.status))
|
||||
}
|
||||
},
|
||||
{ prop: 'realNum', label: '报名人数', align: 'center' },
|
||||
{
|
||||
prop: 'beginTime', width: '300px', label: '活动时间', align: 'center',
|
||||
render: (h, params) => {
|
||||
return h('span', {
|
||||
}, params.row.beginTime + ' - ' + params.row.endTime)
|
||||
}
|
||||
},
|
||||
{ slot: 'options', label: '操作', align: 'center' }
|
||||
],
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created () {
|
||||
this.isLoading = true
|
||||
this.dict.load(['villageActivityStatus']).then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appvillageactivityinfo/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
areaId: this.areaId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
|
||||
this.isLoading = false
|
||||
} else {
|
||||
this.isLoading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
toAdd (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appvillageactivityinfo/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-tags {
|
||||
.el-tag {
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
border: 1px solid #D0D4DC;
|
||||
background: #F3F4F7;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: #222222;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tags {
|
||||
.tag-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: 30px;
|
||||
padding-top: 30px;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
|
||||
&:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.el-tag {
|
||||
margin-right: 8px;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
h2 {
|
||||
width: 88px;
|
||||
margin-right: 40px;
|
||||
text-align: right;
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
text-align: right;
|
||||
img {
|
||||
position: relative;
|
||||
top: 4px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
}
|
||||
|
||||
.userinfo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
|
||||
.userinfo-right__top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.userinfo-right__bottom {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
font-style: normal;
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
margin-right: 8px;
|
||||
color: #222222;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #3C7FC8;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
661
packages/conv/AppVillageActivity/components/Statistics.vue
Normal file
661
packages/conv/AppVillageActivity/components/Statistics.vue
Normal file
@@ -0,0 +1,661 @@
|
||||
<template>
|
||||
<ai-list class="statistics" isTabs style="width: 100%" v-loading="loading">
|
||||
<template #left>
|
||||
<div class="villagecode-left">
|
||||
<div class="villagecode-left__title">
|
||||
<h2>地区</h2>
|
||||
</div>
|
||||
<div class="addressBook-left__list">
|
||||
<div class="addressBook-left__list--title">
|
||||
<el-input
|
||||
class="addressBook-left__list--search"
|
||||
size="mini"
|
||||
clearable
|
||||
placeholder="请输入地区名称"
|
||||
v-model="unitName"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</div>
|
||||
<el-tree
|
||||
:filter-node-method="filterNode"
|
||||
ref="tree"
|
||||
:props="defaultProps"
|
||||
node-key="id"
|
||||
:data="areaTree"
|
||||
highlight-current
|
||||
:current-node-key="areaId"
|
||||
:default-expanded-keys="defaultExpanded"
|
||||
:default-checked-keys="defaultChecked"
|
||||
@current-change="onTreeChange">
|
||||
</el-tree>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="近12个月居民参与活动人数统计">
|
||||
<template #content>
|
||||
<div class="chart1" style="height: 300px; width: 100%;"></div>
|
||||
<ai-empty v-if="false" style="height: 148px;"></ai-empty>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="活动统计">
|
||||
<template #right>
|
||||
<el-date-picker
|
||||
v-model="time1"
|
||||
type="month"
|
||||
size="small"
|
||||
:clearable="false"
|
||||
@change="getInfo"
|
||||
value-format="yyyy-MM"
|
||||
placeholder="请选择月份">
|
||||
</el-date-picker>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="middle">
|
||||
<div class="left">
|
||||
<div class="left-item">
|
||||
<h2>活动发布数量</h2>
|
||||
<div>
|
||||
<span style="color: rgb(34, 102, 255);">{{ info['活动发布数量'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="left-item">
|
||||
<h2>活动报名人数</h2>
|
||||
<div>
|
||||
<span style="color: rgb(34, 170, 153);">{{ info['活动报名人数'] || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="left-item">
|
||||
<h2>发布动态条数</h2>
|
||||
<div>
|
||||
<span style="color: rgb(248, 180, 37);">{{ info['发布动态条数'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="left-item">
|
||||
<h2>发布动态人员占比</h2>
|
||||
<div>
|
||||
<span style="color: red;">{{ info['发布动态人员占比'] }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<h2>居民参与类型占比</h2>
|
||||
<div class="right-chart">
|
||||
<div class="chart2" style="height: 200px; width: 100%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="村民参与活动记录">
|
||||
<template #right>
|
||||
<el-date-picker
|
||||
v-model="time2"
|
||||
type="month"
|
||||
size="small"
|
||||
:clearable="false"
|
||||
@change="getInfo"
|
||||
value-format="yyyy-MM"
|
||||
placeholder="请选择月份">
|
||||
</el-date-picker>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-table
|
||||
style="margin-top: 12px;"
|
||||
:border="true"
|
||||
tableSize="small"
|
||||
:total="total"
|
||||
:tableData="list"
|
||||
:col-configs="colConfigs"
|
||||
:isShowPagination="false"
|
||||
:stripe="false"
|
||||
@getList="getInfo">
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import * as echarts from 'echarts'
|
||||
export default {
|
||||
name: 'Statistics',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
chart1: null,
|
||||
info: {},
|
||||
chartWidth: '',
|
||||
loading: false,
|
||||
defaultExpanded: [],
|
||||
defaultChecked: [],
|
||||
areaTree: [],
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'name'
|
||||
},
|
||||
total: 0,
|
||||
colConfigs: [
|
||||
{ prop: 'name', label: '姓名', align: 'left' },
|
||||
{ prop: 'gender', label: '性别', align: 'center', formart: v => this.dict.getLabel('sex', v) },
|
||||
{ prop: 'num1', label: '报名次数', align: 'center' },
|
||||
{ prop: 'num2', label: '发布动态条数', align: 'center' }
|
||||
],
|
||||
time1: '',
|
||||
time2: '',
|
||||
chart2: '',
|
||||
currIndex: -1,
|
||||
list: [],
|
||||
unitName: '',
|
||||
areaId: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
watch: {
|
||||
unitName (val) {
|
||||
this.$refs.tree.filter(val)
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.time1 = this.$moment(new Date()).format('YYYY-MM')
|
||||
this.time2 = this.$moment(new Date()).format('YYYY-MM')
|
||||
this.areaId = this.user.info.areaId
|
||||
this.areaName = this.user.info.areaName
|
||||
this.getTree()
|
||||
this.loading = true
|
||||
this.$nextTick(() => {
|
||||
this.chart1 = echarts.init(document.querySelector('.chart1'))
|
||||
this.chart2 = echarts.init(document.querySelector('.chart2'))
|
||||
window.addEventListener('resize', this.onResize)
|
||||
|
||||
this.dict.load('sex').then(() => {
|
||||
this.getInfo()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
window.removeEventListener('resize', this.onResize)
|
||||
},
|
||||
|
||||
methods: {
|
||||
onResize () {
|
||||
this.chart1.resize()
|
||||
},
|
||||
|
||||
onTreeChange (e) {
|
||||
this.areaId = e.id
|
||||
this.areaName = e.name
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getInfo()
|
||||
})
|
||||
},
|
||||
|
||||
filterNode(value, data) {
|
||||
if (!value) return true
|
||||
return data.name.indexOf(value) !== -1
|
||||
},
|
||||
|
||||
getTree () {
|
||||
this.instance.post(`/admin/area/queryAllArea?id=${this.user.info.areaId}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
let parent = res.data.map(v => {
|
||||
v.label = v.name
|
||||
v.children = []
|
||||
|
||||
return v
|
||||
}).filter(e => !e.parentid)[0]
|
||||
this.defaultExpanded = [parent.id]
|
||||
this.defaultChecked = [parent.id]
|
||||
this.areaId = parent.id
|
||||
this.addChild(parent, res.data)
|
||||
this.areaTree = [parent]
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tree.setCurrentKey(parent.id)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
addChild (parent, list) {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (list[i].parentId === parent.id) {
|
||||
parent.children.push(list[i])
|
||||
}
|
||||
}
|
||||
|
||||
if (list.length > 0) {
|
||||
parent['children'].map(v => this.addChild(v, list))
|
||||
}
|
||||
},
|
||||
|
||||
getInfo () {
|
||||
this.loading = true
|
||||
this.instance.post(`/app/appvillageactivityinfo/statistic?areaId=${this.areaId}&time1=${this.time1 || ''}&time2=${this.time2 || '-'}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.info = res.data.total
|
||||
this.initChart1(res.data.twelve)
|
||||
this.initChart2(res.data.gender)
|
||||
this.list = res.data.rank || []
|
||||
this.loading = false
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
initChart2 (data) {
|
||||
const values = data && Object.keys(data).map(v => {
|
||||
return {
|
||||
value: data[v],
|
||||
name: v
|
||||
}
|
||||
}) || []
|
||||
let option = {
|
||||
tooltip: {
|
||||
trigger: 'item'
|
||||
},
|
||||
legend: {
|
||||
right: '5%',
|
||||
top: 'center',
|
||||
orient: 'vertical'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center'
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: '20',
|
||||
color: '#2266FF'
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
emphasis: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
},
|
||||
normal:{
|
||||
label:{
|
||||
show: true,
|
||||
formatter: '{b} : {c} ({d}%)'
|
||||
},
|
||||
labelLine :{show:true}
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
color: ['#2266FF', '#22AA99', '#F8B425'],
|
||||
data: values
|
||||
}
|
||||
]
|
||||
}
|
||||
this.chart2.setOption(option)
|
||||
},
|
||||
|
||||
initChart1 (data) {
|
||||
const x = data ? data.map(v => v.time) : []
|
||||
let option = {
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
type: "plain"
|
||||
},
|
||||
grid: {
|
||||
left: '10px',
|
||||
right: '28px',
|
||||
bottom: '14px',
|
||||
top: '30px',
|
||||
containLabel: true
|
||||
},
|
||||
color: ['#2266FF', '#22AA99', '#F8B425'],
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
axisLabel: {
|
||||
align: 'center',
|
||||
padding: [2, 0, 0, 0],
|
||||
interval: 0,
|
||||
fontSize: 14,
|
||||
color: '#666666'
|
||||
},
|
||||
boundaryGap: false,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#E1E5EF'
|
||||
}
|
||||
},
|
||||
data: x
|
||||
},
|
||||
yAxis: {
|
||||
axisTick: {
|
||||
length: 0,
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle:{
|
||||
color: ['#E1E5EF'],
|
||||
width: 1,
|
||||
type: 'solid'
|
||||
}
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: '#666666',
|
||||
align: 'left'
|
||||
},
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666666'
|
||||
},
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '活动报名人数',
|
||||
type: 'line',
|
||||
data: data.map(v => v.total)
|
||||
},
|
||||
{
|
||||
name: '发布动态人数',
|
||||
type: 'line',
|
||||
data: data.map(v => v.active)
|
||||
}
|
||||
]
|
||||
}
|
||||
this.chart1.setOption(option)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.statistics {
|
||||
padding: 0!important;
|
||||
::v-deep .ai-list__content--right-wrapper {
|
||||
background: transparent!important;
|
||||
box-shadow: none!important;
|
||||
padding: 0 0 0!important;
|
||||
}
|
||||
|
||||
::v-deep .ai-list {
|
||||
padding: 0!important;
|
||||
}
|
||||
|
||||
.middle {
|
||||
display: flex;
|
||||
height: 220px;
|
||||
|
||||
& > div {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.right {
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
padding-right: 20px;
|
||||
|
||||
.left-item {
|
||||
width: calc((100% - 10px) / 2);
|
||||
padding: 16px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
background: #f9f9f9;
|
||||
-webkit-box-shadow: 0 4px 6px -2px rgb(15 15 21 / 15%);
|
||||
box-shadow: 0 4px 6px -2px rgb(15 15 21 / 15%);
|
||||
border-radius: 4px;
|
||||
|
||||
&:nth-of-type(2n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 16px;
|
||||
color: #888;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 1.5em;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.addressBook-left__list {
|
||||
height: calc(100% - 40px);
|
||||
padding: 8px 8px;
|
||||
overflow: auto;
|
||||
|
||||
.addressBook-left__tags--item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 40px;
|
||||
padding: 0 8px 0 16px;
|
||||
color: #222222;
|
||||
|
||||
&.addressBook-left__tags--item-active, &:hover {
|
||||
background: #E8EFFF;
|
||||
color: #2266FF;
|
||||
|
||||
i, span {
|
||||
color: #2266FF;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
color: #8e9ebf;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.addressBook-left__list--title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.addressBook-left__list--search {
|
||||
flex: 1;
|
||||
::v-deep input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.el-button {
|
||||
width: 84px;
|
||||
flex-shrink: 1;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
::v-deep .el-tree {
|
||||
background: transparent;
|
||||
|
||||
.el-tree-node__expand-icon.is-leaf {
|
||||
color: transparent!important;
|
||||
}
|
||||
|
||||
.el-tree-node__content > .el-tree-node__expand-icon {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.el-tree-node__content {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.el-tree__empty-text {
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.el-tree-node__children .el-tree-node__content {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.el-tree-node__content:hover {
|
||||
background: #E8EFFF;
|
||||
color: #222222;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.is-current > .el-tree-node__content {
|
||||
&:hover {
|
||||
background: #2266FF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
background: #2266FF;
|
||||
|
||||
span {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ai-list__content--left {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.villagecode-left {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
background: #FAFAFB;
|
||||
|
||||
.villagecode-left__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
padding: 0 16px;
|
||||
background: #fff;
|
||||
|
||||
h2 {
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.villagecode-left__list {
|
||||
height: calc(100% - 40px);
|
||||
padding: 8px 0;
|
||||
overflow: auto;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
padding: 0 24px;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
border-right: 2px solid transparent;
|
||||
background: transparent;
|
||||
|
||||
&:hover {
|
||||
color: #2266FF;
|
||||
background: #E8EFFF;
|
||||
}
|
||||
|
||||
&.left-active {
|
||||
color: #2266FF;
|
||||
border-color: #2266FF;
|
||||
background: #E8EFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ai-list__content--right {
|
||||
|
||||
.ai-list__content--right-wrapper {
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.statistics-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
& > div {
|
||||
flex: 1;
|
||||
height: 96px;
|
||||
line-height: 1;
|
||||
margin-right: 20px;
|
||||
padding: 16px 24px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
border-radius: 4px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
color: #888888;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
63
packages/conv/AppVillageAlbum/AppVillageAlbum.vue
Normal file
63
packages/conv/AppVillageAlbum/AppVillageAlbum.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="AppVillageAlbum">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List.vue'
|
||||
import Add from './components/Add'
|
||||
|
||||
export default {
|
||||
name: 'AppVillageAlbum',
|
||||
label: '乡村相册',
|
||||
|
||||
components: {
|
||||
List,
|
||||
Add
|
||||
},
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
currIndex: '0',
|
||||
component: 'List',
|
||||
params: {},
|
||||
areaId: '',
|
||||
isShowDetail: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (data) {
|
||||
if (data.type === 'list') {
|
||||
this.component = 'List'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'detail') {
|
||||
this.component = 'Detail'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'add') {
|
||||
this.component = 'Add'
|
||||
this.params = data.params
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppVillageAlbum {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
123
packages/conv/AppVillageAlbum/components/Add.vue
Normal file
123
packages/conv/AppVillageAlbum/components/Add.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<ai-detail>
|
||||
<template slot="title">
|
||||
<ai-title :title="params.id ? '编辑本村相册' : '添加本村相册'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form class="ai-form" :model="form" label-width="120px" ref="form">
|
||||
<el-form-item label="相册主题" style="width: 100%;" prop="type"
|
||||
:rules="[{required: true, message: '请选择相册主题', trigger: 'blur'}]">
|
||||
<ai-select
|
||||
v-model="form.type"
|
||||
placeholder="请选择相册主题"
|
||||
:selectList="dict.getDict('villagePictureAlbumType')">
|
||||
</ai-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="areaId" style="width: 100%;" label="发布地区"
|
||||
:rules="[{required: true, pattern: /([^0]\d{2}|0[^0]\d|0\d[^0])$/, message: '请选择到村', trigger: 'change'}]">
|
||||
<ai-area-select @fullname="v => form.areaName = v" clearable always-show :instance="instance"
|
||||
v-model="form.areaId" :disabled-level="disabledLevel"></ai-area-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="图片" style="width: 100%;" prop="urlList" :rules="[{required: true, message: '请上传图片'}]">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
v-model="form.urlList"
|
||||
:limit="9">
|
||||
</ai-uploader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">提交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Add',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
form: {
|
||||
areaName: '',
|
||||
areaId: '',
|
||||
urlList: []
|
||||
},
|
||||
cropOps: {
|
||||
width: "336px",
|
||||
height: "210px"
|
||||
},
|
||||
id: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created() {
|
||||
this.form.areaId = this.user.info.areaId
|
||||
this.disabledLevel = this.user.info.areaList.length
|
||||
this.dict.load(['villagePictureAlbumType'])
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo(id) {
|
||||
this.instance.post(`/app/appcountrysidetourism/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
confirm() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post(`/app/appvillagepicturealbum/addPictures`, {
|
||||
...this.form,
|
||||
id: this.params.id,
|
||||
urlList: this.form.urlList.map(v => v.url)
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel(isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
538
packages/conv/AppVillageAlbum/components/List.vue
Normal file
538
packages/conv/AppVillageAlbum/components/List.vue
Normal file
@@ -0,0 +1,538 @@
|
||||
<template>
|
||||
<ai-list class="list">
|
||||
<template slot="title">
|
||||
<ai-title title="乡村相册" isShowBottomBorder :instance="instance" :disabledLevel="disabledLevel" isShowArea v-model="search.areaId" @change="changeArea"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<ai-select
|
||||
v-model="search.type"
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="请选择相册主题"
|
||||
:selectList="dict.getDict('villagePictureAlbumType')">
|
||||
</ai-select>
|
||||
<el-date-picker
|
||||
v-model="search.timeTag"
|
||||
type="month"
|
||||
size="small"
|
||||
@change="search.current = 1, getList()"
|
||||
value-format="yyyy-MM"
|
||||
placeholder="请选择日期">
|
||||
</el-date-picker>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<div v-loading="loading">
|
||||
<div class="form-list__list">
|
||||
<div class="list-item list-add" @click="toAdd('')">
|
||||
<span class="iconfont iconAdd"></span>
|
||||
<h2>添加相片</h2>
|
||||
</div>
|
||||
<div class="list-item" v-for="(item, index) in list" :key="index">
|
||||
<div class="list-item__img">
|
||||
<img :src="item.url" @click="prevImg(index)">
|
||||
</div>
|
||||
<div class="list-item__bottom">
|
||||
<div class="left">
|
||||
<span class="tag">{{ dict.getLabel('villagePictureAlbumType', item.type) }}</span>
|
||||
<span>{{ item.createUserName }}</span>
|
||||
</div>
|
||||
<i>{{ item.createTime }}</i>
|
||||
</div>
|
||||
<div class="list-item__operate">
|
||||
<el-button
|
||||
type="text"
|
||||
icon="iconfont iconExported"
|
||||
class="list-item__operate--item"
|
||||
@click="downloadImg(item.url, dict.getLabel('villagePictureAlbumType', item.type))">
|
||||
下载
|
||||
</el-button>
|
||||
<el-button
|
||||
@click="remove(item.id)"
|
||||
type="text"
|
||||
icon="iconfont iconDelete"
|
||||
class="list-item__operate--item">
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="images" v-viewer="{movable: true}" v-show="false">
|
||||
<img v-for="(item, index) in imgList" :src="item" :key="index" alt="">
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import Viewer from 'v-viewer'
|
||||
import Vue from 'vue'
|
||||
Vue.use(Viewer)
|
||||
|
||||
export default {
|
||||
name: 'FormList',
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
areaId: String
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
areaId: '',
|
||||
size: 1000000,
|
||||
type: '',
|
||||
timeTag: ''
|
||||
},
|
||||
isShowAdd: false,
|
||||
form: {
|
||||
},
|
||||
list: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
id: '',
|
||||
disabledLevel: 0
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
imgList () {
|
||||
return this.list.map(v => v.url)
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.loading = true
|
||||
this.disabledLevel = this.user.info.areaList.length - 1
|
||||
this.search.areaId = this.user.info.areaId
|
||||
this.dict.load(['villagePictureAlbumType']).then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
changeArea () {
|
||||
this.loading = true
|
||||
this.search.current = 1
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
prevImg (index) {
|
||||
const viewer = this.$el.querySelector('.images').$viewer
|
||||
viewer.view(index)
|
||||
},
|
||||
|
||||
getList () {
|
||||
this.instance.post(`/app/appvillagepicturealbum/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.list = res.data.records
|
||||
this.total = res.data.total
|
||||
this.loading = false
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定删除该相片?').then(() => {
|
||||
this.instance.post(`/app/appvillagepicturealbum/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
downloadImg (url, name) {
|
||||
let image = new Image()
|
||||
image.setAttribute('crossOrigin', 'anonymous')
|
||||
image.onload = function() {
|
||||
let canvas = document.createElement('canvas')
|
||||
canvas.width = image.width
|
||||
canvas.height = image.height
|
||||
let context = canvas.getContext('2d')
|
||||
context.drawImage(image, 0, 0, image.width, image.height)
|
||||
let url = canvas.toDataURL("image/png")
|
||||
let a = document.createElement("a")
|
||||
let event = new MouseEvent("click")
|
||||
a.download = name
|
||||
a.href = url
|
||||
a.dispatchEvent(event)
|
||||
}
|
||||
image.src = url
|
||||
},
|
||||
|
||||
toStop (id) {
|
||||
this.$confirm('确定停止该表单?').then(() => {
|
||||
this.instance.post(`/app/appquestionnairetemplate/stopRelease?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('停止成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
showShare (info, isPreview) {
|
||||
this.loading = true
|
||||
this.info = info
|
||||
|
||||
this.instance.post(`/app/appquestionnairetemplate/queryQrCode?id=${info.id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.info.linkUrl = res.data.linkUrl
|
||||
this.info.qrCodeUrl = res.data.qrCodeUrl
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (isPreview) {
|
||||
this.isShowPreview = true
|
||||
this.info.linkUrl = `${res.data.linkUrl}&preview=true#form`
|
||||
} else {
|
||||
this.isShowSuccess = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
toAdd (id) {
|
||||
this.$emit('change', {
|
||||
type: 'add',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.list {
|
||||
::v-deep .ai-list__content {
|
||||
width: 100%;
|
||||
.ai-list__content--right {
|
||||
width: 100%!important;
|
||||
|
||||
.ai-list__content--right-wrapper {
|
||||
padding: 0!important;
|
||||
background: transparent!important;
|
||||
box-shadow: none!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep.el-pager {
|
||||
li.active + li {
|
||||
border-left: 1px solid #D0D4DC;
|
||||
}
|
||||
}
|
||||
|
||||
.newPagination {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 64px;
|
||||
padding: 0 40px!important;
|
||||
|
||||
.el-pagination {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
::v-deep .el-pager li.active {
|
||||
background-color: #fff !important;
|
||||
color: #2266FF !important;
|
||||
border-color: #2266FF;
|
||||
}
|
||||
|
||||
::v-deep .el-pager li {
|
||||
background-color: #fff;
|
||||
border: solid 1px #d0d4dc;
|
||||
margin-left: 8px;
|
||||
border-radius: 4px !important;
|
||||
line-height: 26px !important;
|
||||
}
|
||||
|
||||
.paginationPre {
|
||||
display: flex;
|
||||
height: 28px;
|
||||
line-height: 1;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
align-items: center;
|
||||
|
||||
.pagination-btns {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #2266FF !important;
|
||||
|
||||
::v-deep span, ::v-deep div {
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
color: #2266FF !important;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.paginationPre-total {
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
|
||||
label {
|
||||
padding: 0 2px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
& > * + * {
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
::v-deep .el-pagination button, .el-pagination span:not([class*=suffix]) {
|
||||
line-height: 1 !important;
|
||||
}
|
||||
|
||||
::v-deep.el-checkbox {
|
||||
padding-left: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.el-checkbox__input, .el-checkbox__inner {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
min-width: 0 !important;
|
||||
line-height: 1 !important;
|
||||
}
|
||||
|
||||
.el-checkbox__label {
|
||||
font-size: 12px;
|
||||
color: #222222;
|
||||
height: auto !important;
|
||||
line-height: 1 !important;
|
||||
padding-left: 3px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-list__list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 8px;
|
||||
|
||||
.list-item {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
padding: 18px 16px 16px;
|
||||
|
||||
.list-item__img {
|
||||
width: 100%;
|
||||
height: 140px;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 140px;
|
||||
object-fit: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.list-item__operate {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.list-item__operate {
|
||||
display: none;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 52px;
|
||||
text-align: center;
|
||||
background: #F7F8FA;
|
||||
|
||||
& > div {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
::v-deep .el-button {
|
||||
margin-left: 0;
|
||||
padding: 0;
|
||||
i {
|
||||
color: #8899BB;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.el-button + .el-button {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
span {
|
||||
margin-left: 0;
|
||||
color: #555555;
|
||||
font-size: 12px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&.is-disabled {
|
||||
i {
|
||||
color: #8899BB;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #555555;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-item__operate--item {
|
||||
flex: 1;
|
||||
|
||||
&:hover {
|
||||
::v-deep i, ::v-deep span {
|
||||
color: #2266FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-item__bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #888888;
|
||||
font-size: 12px;
|
||||
|
||||
i {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.tag {
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
margin-right: 8px;
|
||||
padding: 0 6px;
|
||||
border-radius: 4px;
|
||||
background: #42D784;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 22px;
|
||||
color: #333333;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.list-item__user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 12px;
|
||||
color: #888888;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
|
||||
& > div:first-child {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.list-item__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 14px;
|
||||
|
||||
h2 {
|
||||
color: #2EA222;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
span {
|
||||
width: 64px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-add {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
font-size: 32px;
|
||||
color: #8899bb;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #555555;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
& > div {
|
||||
width: calc((100% - 60px) / 4);
|
||||
height: 216px;
|
||||
margin: 0 20px 20px 0;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 2px;
|
||||
|
||||
&:nth-of-type(4n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<div class="doc-circulation ailist-wrapper">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List'
|
||||
import Add from './components/Add'
|
||||
import Detail from './components/Detail'
|
||||
|
||||
export default {
|
||||
name: 'AppVillagerDiscussion',
|
||||
label: '居民议事',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
mounted () {
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (data) {
|
||||
if (data.type === 'Add') {
|
||||
this.component = 'Add'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'Detail') {
|
||||
this.component = 'Detail'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'list') {
|
||||
this.component = 'List'
|
||||
this.params = data.params
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (data.isRefresh) {
|
||||
this.$refs.component.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.doc-circulation {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
248
packages/conv/AppVillagerDiscussion/components/Add.vue
Normal file
248
packages/conv/AppVillagerDiscussion/components/Add.vue
Normal file
@@ -0,0 +1,248 @@
|
||||
<template>
|
||||
<ai-detail>
|
||||
<template slot="title">
|
||||
<ai-title :title="params.id ? '编辑居民议事' : '添加居民议事'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<el-form class="ai-form" :model="form" label-width="120px" ref="form">
|
||||
<el-form-item label="主题" style="width: 100%;" prop="content" :rules="[{required: true, message: '请输入主题', trigger: 'blur'}]">
|
||||
<el-input type="textarea" :rows="5" v-model="form.content" clearable placeholder="请输入主题..." :maxlength="500" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="areaId" style="width: 100%;" label="发布地区" :rules="[{required: true, message: '请选择到村', trigger: 'change'}]">
|
||||
<ai-area-select @fullname="v => form.areaName = v" clearable always-show :instance="instance" v-model="form.areaId" :disabled-level="disabledLevel"></ai-area-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="议事截止时间" prop="discussDeadline" :rules="[{required: true, message: '请选择议事截止时间', trigger: 'change'}]">
|
||||
<el-date-picker
|
||||
v-model="form.discussDeadline"
|
||||
type="datetime"
|
||||
style="width: 100%;"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="选择议事截止时间">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="公示截止时间" prop="publicityDeadline">
|
||||
<el-date-picker
|
||||
v-model="form.publicityDeadline"
|
||||
size="small"
|
||||
style="width: 100%;"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="选择公示截止时间">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="议事类型" prop="type" :rules="[{required: true, message: '请选择议事类型', trigger: 'change'}]">
|
||||
<el-radio-group v-model="form.type">
|
||||
<el-radio :label="item.dictValue" v-for="(item, index) in dict.getDict('discussType')" :key="index">{{ item.dictName }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === '1'" class="vite-form__item" style="width: 100%;" label="投票选项" prop="voteItems" :rules="[{required: true, message: '请添加投票选项', trigger: 'change'}]">
|
||||
<draggable
|
||||
v-model="form.voteItems"
|
||||
:animation="340"
|
||||
group="select">
|
||||
<el-form-item class="move-item" style="width: 100%" label-width="80px" :label="'选项' + (index + 1)" v-for="(item, index) in form.voteItems" :key="'选项' + (index + 1)">
|
||||
<div class="form-flex">
|
||||
<el-input show-word-limit style="width:400px" v-model="item.content" :maxlength="200" size="small" placeholder="请输入选项"></el-input>
|
||||
<el-button type="danger" size="small" @click="removeVote(index)">删除</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</draggable>
|
||||
<el-button type="primary" size="small" @click="addVote">添加选项</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === '1'" label="是否匿名投票" prop="anonymous" :rules="[{required: true, message: '请选择是否匿名投票', trigger: 'change'}]">
|
||||
<el-switch
|
||||
v-model="form.anonymous"
|
||||
active-value="1"
|
||||
inactive-value="0">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.type === '1'" label="投票方式" prop="voteType" :rules="[{required: true, message: '请选择投票方式', trigger: 'change'}]">
|
||||
<el-radio-group v-model="form.voteType">
|
||||
<el-radio label="0">单选</el-radio>
|
||||
<el-radio label="1">多选</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="图片" style="width: 100%;" prop="images">
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
isShowTip
|
||||
v-model="form.images"
|
||||
:limit="9">
|
||||
</ai-uploader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="confirm" :loading="isLoading">提交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'Add',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
components: {
|
||||
draggable
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
info: {},
|
||||
form: {
|
||||
content: '',
|
||||
areaId: '',
|
||||
areaName: '',
|
||||
anonymous: '0',
|
||||
discussDeadline: '',
|
||||
publicityDeadline: '',
|
||||
type: '0',
|
||||
voteType: '0',
|
||||
voteItems: [],
|
||||
anonymity: '1',
|
||||
images: []
|
||||
},
|
||||
isLoading: false,
|
||||
keys: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
|
||||
id: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created () {
|
||||
this.form.areaId = this.user.info.areaId
|
||||
this.form.areaName = this.user.info.areaName
|
||||
this.disabledLevel = this.user.info.areaList.length
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appvillagediscuss/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form = res.data
|
||||
this.form.content = res.data.title
|
||||
this.form.images = res.data.images ? JSON.parse(res.data.images) : []
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
addVote () {
|
||||
if (this.form.voteItems > 7) {
|
||||
return this.$message.error('选项不能大于7个')
|
||||
}
|
||||
|
||||
this.form.voteItems.push({
|
||||
content: ''
|
||||
})
|
||||
},
|
||||
|
||||
removeVote (index) {
|
||||
this.form.voteItems.splice(index, 1)
|
||||
},
|
||||
|
||||
confirm () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
const endTime = new Date(this.form.discussDeadline).getTime()
|
||||
const endPublicityTime = this.form.publicityDeadline ? new Date(this.form.publicityDeadline).getTime() : 0
|
||||
const nowTime = new Date().getTime()
|
||||
if (endTime - nowTime < 0) {
|
||||
return this.$message.error('议事截止时间不能早于当前时间')
|
||||
}
|
||||
|
||||
if (endPublicityTime && endPublicityTime - endTime < 0) {
|
||||
return this.$message.error('公示截止时间不能早于议事截止时间')
|
||||
}
|
||||
|
||||
if (this.form.type === '1' && this.form.voteItems.length < 2) {
|
||||
return this.$message.error('投票选项不能少于2')
|
||||
}
|
||||
|
||||
if (this.form.type === '1') {
|
||||
this.form.voteItems = this.form.voteItems.map((v, index) => {
|
||||
return {
|
||||
content: v.content,
|
||||
item: this.keys[index]
|
||||
}
|
||||
})
|
||||
|
||||
for (let v of this.form.voteItems) {
|
||||
if (!v.content) {
|
||||
return this.$message.error(`请输入选项${v.item}的内容`)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.isLoading = true
|
||||
this.instance.post(`/app/appvillagediscuss/addOrUpdate`, {
|
||||
...this.form,
|
||||
createUserId: this.user.info.id,
|
||||
createUserName: this.user.info.name,
|
||||
images: this.form.images.length ? JSON.stringify(this.form.images) : '',
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.isLoading = false
|
||||
this.cancel(true)
|
||||
}, 300)
|
||||
}
|
||||
}).catch(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.move-item {
|
||||
::v-deep .el-form-item__label {
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
.vite-form__item {
|
||||
.form-flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.el-button {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
::v-deep .el-form-item__content {
|
||||
margin-left: 0!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
278
packages/conv/AppVillagerDiscussion/components/Detail.vue
Normal file
278
packages/conv/AppVillagerDiscussion/components/Detail.vue
Normal file
@@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<ai-detail isHasSidebar>
|
||||
<template slot="title">
|
||||
<ai-title title="居民议事详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<AiSidebar :tabTitle="tabList" v-model="currIndex" @change="onChange"></AiSidebar>
|
||||
<ai-card title="议题信息" v-show="currIndex === 0">
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="主题" :value="info.content" isLine></ai-info-item>
|
||||
<ai-info-item label="发布地区" :value="info.areaName" isLine></ai-info-item>
|
||||
<ai-info-item label="议事截止时间" :value="info.discussDeadline"></ai-info-item>
|
||||
<ai-info-item label="公示截止时间" :value="info.publicityDeadline"></ai-info-item>
|
||||
<ai-info-item label="议事类型" :value="dict.getLabel('discussType', info.type)" isLine></ai-info-item>
|
||||
<ai-info-item label="是否匿名投票" v-if="info.type === '1'" :value="info.anonymous === '1' ? '是' : '否'"></ai-info-item>
|
||||
<ai-info-item label="投票方式" v-if="info.type === '1'" :value="info.voteType === '0' ? '单选' : '多选'"></ai-info-item>
|
||||
<ai-info-item label="图片" isLine>
|
||||
<ai-uploader
|
||||
:instance="instance"
|
||||
disabled
|
||||
v-model="info.images"
|
||||
:limit="9">
|
||||
</ai-uploader>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="意见征集" v-if="info.type === '0'" v-show="currIndex === 1">
|
||||
<template #right>
|
||||
<el-button type="primary" size="small" v-if="user.info.id === info.createUserId && info.status === '0'" @click="isShowAdd = true">发表意见</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-table
|
||||
class="detail-table__table"
|
||||
:border="true"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
:stripe="false"
|
||||
@getList="getList">
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="投票统计" v-show="currIndex === 1 && info.type === '1'">
|
||||
<template #content>
|
||||
<h2 class="detail-title">选项</h2>
|
||||
<ai-wrapper>
|
||||
<ai-info-item :label="item.item + ':'" :value="item.content" isLine v-for="(item, index) in info.voteItems" :key="index"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
<div class="chart" style="width: 800px; height: 240px; margin: 0 auto;"></div>
|
||||
<ai-table
|
||||
class="detail-table__table"
|
||||
:border="true"
|
||||
:tableData="tableData"
|
||||
:col-configs="voteColConfigs"
|
||||
:total="total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
:stripe="false"
|
||||
@getList="getList">
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowAdd"
|
||||
width="680px"
|
||||
height="580px"
|
||||
title="发表意见"
|
||||
@close="onClose"
|
||||
@onConfirm="onConfirm">
|
||||
<el-form ref="form" class="ai-form" :model="form" label-width="110px" label-position="right">
|
||||
<el-form-item label="发表意见" prop="content" style="width: 100%;" :rules="[{ required: true, message: '请发表你的观点和意见', trigger: 'blur' }]">
|
||||
<el-input size="small" type="textarea" :rows="5" show-word-limit :maxlength="140" placeholder="请发表你的观点和意见" v-model="form.content"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'Detail',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
info: {},
|
||||
id: '',
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10
|
||||
},
|
||||
isShowAdd: false,
|
||||
form: {
|
||||
content: ''
|
||||
},
|
||||
total: 0,
|
||||
currIndex: 0,
|
||||
tableData: [],
|
||||
colConfigs: [
|
||||
{prop: 'content', label: '发言内容', align: 'center'},
|
||||
{prop: 'suport', label: '获赞次数', align: 'center'},
|
||||
{prop: 'createTime', label: '发言时间', align: 'center'},
|
||||
{prop: 'createUserId', label: '发言身份', align: 'center', formart: v => v === this.info.createUserId ? '话事人' : '居民'}
|
||||
],
|
||||
type: '',
|
||||
statistic: {},
|
||||
tabList: ['议题信息', '意见征集']
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
voteColConfigs () {
|
||||
return [
|
||||
{prop: 'createTime', label: '投票时间', align: 'center'},
|
||||
{
|
||||
prop: 'userName',
|
||||
label: '发言人',
|
||||
align: 'center',
|
||||
render: (h, { row }) => {
|
||||
return h('span', {}, this.info.anonymous === '1' ? '居民' : `${row.userName}${row.phone ? '-' + row.phone : ''}`)
|
||||
}
|
||||
},
|
||||
{prop: 'item', label: '投票选项', align: 'center'}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getInfo(this.params.id)
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (e) {
|
||||
if (e === 1 && this.info.type === '1') {
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.initChart(this.statistic)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appvillagediscuss/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
this.info.images = res.data.images ? JSON.parse(res.data.images) : []
|
||||
this.type = res.data.type
|
||||
this.getList()
|
||||
|
||||
if (res.data.type === '1') {
|
||||
this.statistic = res.data.statistic
|
||||
this.tabList = ['议题信息', '投票表决']
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getList() {
|
||||
this.instance.post(`${this.type === '0' ? '/app/appvillagediscussmessage/list' : '/app/appvillagediscussvote/list'}`, null, {
|
||||
params: {
|
||||
discussId: this.params.id,
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
initChart(data) {
|
||||
this.chart = echarts.init(document.querySelector('.chart'))
|
||||
const option = {
|
||||
tooltip: {},
|
||||
color: ['#2896FF', '#09DBFE', '#61FDB9', '#FFBB69', '#8429FF', '#ea7ccc'],
|
||||
legend: {
|
||||
right: '5%',
|
||||
top: 'center',
|
||||
orient: 'vertical',
|
||||
formatter: function(name) {
|
||||
let data = option.series[0].data
|
||||
let total = 0
|
||||
let tarValue = 0
|
||||
for (let i = 0, l = data.length; i < l; i++) {
|
||||
total += data[i].value
|
||||
if (data[i].name == name) {
|
||||
tarValue = data[i].value
|
||||
}
|
||||
}
|
||||
let p = total === 0 ? 0 : (tarValue / total * 100).toFixed(0)
|
||||
return name + ':' + tarValue + '票' + ' ' + p + '%'
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
data: Object.keys(data).map(v => {
|
||||
return {
|
||||
value: data[v],
|
||||
name: v
|
||||
}
|
||||
}),
|
||||
label : {
|
||||
normal : {
|
||||
formatter: '{b}:({d}%)',
|
||||
textStyle : {
|
||||
fontWeight : 'normal',
|
||||
fontSize : 15
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
this.chart.setOption(option)
|
||||
},
|
||||
|
||||
onConfirm () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post(`/app/appvillagediscussmessage/addOrUpdate`, {
|
||||
...this.form,
|
||||
discussId: this.params.id,
|
||||
createUserId: this.user.info.name,
|
||||
createUserName: this.user.info.id,
|
||||
avatar: this.user.info.avatar
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('添加成功')
|
||||
this.isShowAdd = false
|
||||
this.search.current = 1
|
||||
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onClose () {
|
||||
this.form.content = ''
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.detail-title {
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
174
packages/conv/AppVillagerDiscussion/components/List.vue
Normal file
174
packages/conv/AppVillagerDiscussion/components/List.vue
Normal file
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<ai-list class="notice">
|
||||
<template slot="title">
|
||||
<ai-title title="居民议事" isShowBottomBorder isShowArea v-model="search.areaId" :instance="instance" @change="search.current = 1, getList()"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
<template #left>
|
||||
<ai-select placeholder="请选择议事类型" v-model="search.type" clearable @change="search.current = 1, getList()" :selectList="dict.getDict('discussType')"></ai-select>
|
||||
<ai-select placeholder="请选择发布状态" v-model="search.status" clearable @change="search.current = 1, getList()" :selectList="dict.getDict('discussStatus')"></ai-select>
|
||||
<el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">发起议事</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.title"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current=1,getList()}"
|
||||
placeholder="请输入议事主题"
|
||||
clearable
|
||||
@clear="search.current = 1, search.title = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
style="margin-top: 6px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="tags" label="标签">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-tags">
|
||||
<el-tag type="info" v-for="(item, index) in row.tags" size="small" :key="index">{{ item }}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" width="160px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" title="详情" @click="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" title="取消公示" @click="changeStatus(row)" :disabled="row.status !== '1'">结束公示</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
status: '',
|
||||
type: '',
|
||||
title: '',
|
||||
areaId: ''
|
||||
},
|
||||
currIndex: -1,
|
||||
areaList: [],
|
||||
total: 10,
|
||||
colConfigs: [
|
||||
{ prop: 'content', label: '议事主题', align: 'left', width: '200px' },
|
||||
{ prop: 'type', label: '议事类型', align: 'center', formart: v => this.dict.getLabel('discussType', v) },
|
||||
{ prop: 'createUserName', label: '话事人', align: 'center' },
|
||||
{ prop: 'msgCountTotal', label: '观点数量', align: 'center', formart: v => v === 0 ? '-' : v },
|
||||
{ prop: 'voteCount', label: '投票数量', align: 'center', formart: v => v === 0 ? '-' : v },
|
||||
{ prop: 'status', label: '发布状态', align: 'center', formart: v => this.dict.getLabel('discussStatus', v) },
|
||||
{ prop: 'createTime', label: '发布时间', align: 'center' },
|
||||
{ slot: 'options', label: '操作', align: 'center' }
|
||||
],
|
||||
areaName: '',
|
||||
unitName: '',
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created () {
|
||||
this.search.areaId = this.user.info.areaId
|
||||
this.dict.load(['discussType', 'discussStatus']).then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appvillagediscuss/listUp`, null, {
|
||||
params: {
|
||||
type: 0,
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records.map(v => {
|
||||
return {
|
||||
...v,
|
||||
content: v.content || v.title
|
||||
}
|
||||
})
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
changeStatus (item) {
|
||||
this.$confirm('是否要结束公示', {type: 'warning'}).then(() => {
|
||||
this.instance.post('/app/appvillagediscuss/finishPublic', {
|
||||
status: '2',
|
||||
id: item.id
|
||||
}).then(res => {
|
||||
if (res && res.code == 0) {
|
||||
this.$message.success('结束公示成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appvillagediscuss/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toAdd(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.notice {
|
||||
}
|
||||
</style>
|
||||
40
packages/conv/AppWeddingsFunerals/AppWeddingsFunerals.vue
Normal file
40
packages/conv/AppWeddingsFunerals/AppWeddingsFunerals.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="AppWeddingsFunerals">
|
||||
<List
|
||||
slot="content"
|
||||
:instance="instance"
|
||||
:dict="dict"
|
||||
:permissions="permissions">
|
||||
</List>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List.vue'
|
||||
|
||||
export default {
|
||||
name: 'AppWeddingsFunerals',
|
||||
label: '婚丧嫁娶',
|
||||
|
||||
components: {
|
||||
List
|
||||
},
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppWeddingsFunerals {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
210
packages/conv/AppWeddingsFunerals/components/List.vue
Normal file
210
packages/conv/AppWeddingsFunerals/components/List.vue
Normal file
@@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<ai-list class="list">
|
||||
<ai-title slot="title" title="婚丧嫁娶" isShowBottomBorder></ai-title>
|
||||
<template slot="content">
|
||||
<div class="statistics-top">
|
||||
<div class="statistics-top__item">
|
||||
<span>活动登记数量</span>
|
||||
<h2 style="color: #2266FF;">{{ info['丧礼登记数量'] }}</h2>
|
||||
</div>
|
||||
<div class="statistics-top__item">
|
||||
<span>干部参与和操办登记数量</span>
|
||||
<h2 style="color: #22AA99;">{{ info['干部参与和操办登记数量'] }}</h2>
|
||||
</div>
|
||||
<div class="statistics-top__item">
|
||||
<span>婚礼登记数量</span>
|
||||
<h2 style="color: #F8B425">{{ info['婚礼登记数量'] }}</h2>
|
||||
</div>
|
||||
<div class="statistics-top__item">
|
||||
<span>丧礼登记数量</span>
|
||||
<h2 style="color: red">{{ info['丧礼登记数量'] }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template #left>
|
||||
<el-button icon="iconfont iconDelete" size="small" @click="removeAll" :disabled="ids.length == 0">删除 </el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.name"
|
||||
size="small"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
@clear="search.current = 1, search.name = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
v-loading="loading"
|
||||
style="margin-top: 16px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@selection-change="v => (ids = v.map((e) => e.id))"
|
||||
@getList="getList">
|
||||
<el-table-column slot="options" width="120px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
name: ''
|
||||
},
|
||||
info: {},
|
||||
colConfigs: [
|
||||
{ type: 'selection' },
|
||||
{ prop: 'name', label: '事主姓名' },
|
||||
{ prop: 'phone', align: 'center', label: '联系电话' },
|
||||
{ prop: 'type', align: 'center', label: '类型', formart: v => this.dict.getLabel('marriageType', v) },
|
||||
{ prop: 'modeType', align: 'center', label: '方式', formart: v => this.dict.getLabel('modeType', v) },
|
||||
{ prop: 'personType', align: 'center', label: '人员性质', formart: v => this.dict.getLabel('marriagePersonType', v) },
|
||||
{ prop: 'createTime', align: 'center', label: '发布时间' }
|
||||
],
|
||||
ids: [],
|
||||
tableData: [],
|
||||
total: 0,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.dict.load(['marriageType', 'marriagePersonType', 'modeType']).then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.loading = true
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
this.instance.post(`/app/appmarriagefuneralinfo/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
this.loading = false
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
this.getTotalInfo()
|
||||
},
|
||||
|
||||
getTotalInfo () {
|
||||
this.instance.post(`/app/appmarriagefuneralinfo/queryDataStatistics`).then(res => {
|
||||
if (res.code == 0) {
|
||||
let info = {}
|
||||
|
||||
res.data.forEach(v => {
|
||||
info[v.name] = v.v1
|
||||
})
|
||||
|
||||
this.info = info
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appmarriagefuneralinfo/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
removeAll() {
|
||||
var id = this.ids.join(',')
|
||||
this.remove(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.list {
|
||||
::v-deep .ai-list__content {
|
||||
padding: 0!important;
|
||||
|
||||
.ai-list__content--right-wrapper {
|
||||
background: transparent!important;
|
||||
box-shadow: none!important;
|
||||
margin: 0!important;
|
||||
padding: 12px 16px 12px!important;
|
||||
}
|
||||
}
|
||||
.statistics-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
& > div {
|
||||
flex: 1;
|
||||
height: 96px;
|
||||
line-height: 1;
|
||||
margin-right: 20px;
|
||||
padding: 16px 24px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
border-radius: 4px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
color: #888888;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 16px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<keep-alive include="gmScore">
|
||||
<component :is="currentPage" v-bind="$props" @change="onChange"/>
|
||||
</keep-alive>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gridScoreManage from "./components/gridScoreManage.vue"
|
||||
import gridScoreRules from "./components/gridScoreRules.vue"
|
||||
import gridScoreStatistics from './components/gridScoreStatistics.vue'
|
||||
import gridScoreDetail from './components/gridScoreDetail.vue'
|
||||
import gmScore from './components/gmScore.vue'
|
||||
|
||||
export default {
|
||||
name: 'AppGridMemberScore',
|
||||
label: "网格员积分",
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
},
|
||||
|
||||
computed: {
|
||||
currentPage() {
|
||||
let {hash} = this.$route
|
||||
return hash == "#gridScoreDetail" ? gridScoreDetail :
|
||||
hash == "#gridScoreRules" ? gridScoreRules :
|
||||
hash == "#gridScoreStatistics" ? gridScoreStatistics :
|
||||
hash == "#gridScoreManage" ? gridScoreManage : gmScore
|
||||
}
|
||||
},
|
||||
components: {
|
||||
gmScore,
|
||||
gridScoreManage,
|
||||
gridScoreRules,
|
||||
gridScoreStatistics,
|
||||
gridScoreDetail,
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange(data) {
|
||||
let {type, params: query} = data,
|
||||
hash = ["gridScoreManage", "gridScoreRules","gridScoreStatistics"].includes(type) ? "" : "#" + type
|
||||
this.$router.push({hash, query})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppGridMemberScore {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<ai-list class="AppGridMemberScore">
|
||||
<template slot="title">
|
||||
<ai-title title="网格员积分" :isShowBottomBorder="false" :instance="instance" >
|
||||
<template slot="sub">
|
||||
<div>网格员可通过完成某些任务获取一定数量的积分,积分可去兑换相应的奖励。</div>
|
||||
</template>
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="tabs">
|
||||
<el-tabs v-model="currIndex">
|
||||
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label">
|
||||
<component :is="tab.comp" v-if="currIndex === String(i)" :ref="tab.name" v-on="$listeners"
|
||||
:areaId="areaId" :instance="instance" :dict="dict" :permissions="permissions"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import girdScoreManage from "./gridScoreManage.vue"
|
||||
import gridScoreRules from "./gridScoreRules.vue"
|
||||
import gridScoreStatistics from './gridScoreStatistics.vue'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AppGridMemberScore',
|
||||
label: "网格员积分",
|
||||
components: {
|
||||
girdScoreManage,
|
||||
gridScoreRules,
|
||||
gridScoreStatistics
|
||||
},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
currIndex: "0",
|
||||
areaId: '',
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
tabs() {
|
||||
return [
|
||||
{
|
||||
label: "积分管理",
|
||||
name: "girdScoreManage",
|
||||
comp: girdScoreManage,
|
||||
permission: "",
|
||||
},
|
||||
{
|
||||
label: "积分规则",
|
||||
name: "gridScoreRules",
|
||||
comp: gridScoreRules,
|
||||
permission: "",
|
||||
},
|
||||
{
|
||||
label: "积分统计",
|
||||
name: "gridScoreStatistics",
|
||||
comp: gridScoreStatistics,
|
||||
permission: "",
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.areaId = this.user.info.areaId
|
||||
// this.$dict.load("")
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppGridMemberScore {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,341 @@
|
||||
<template>
|
||||
<section class="gridScoreDetail">
|
||||
<ai-title slot="title" title="网格员积分详情" isShowBottomBorder :isShowBack="true" @onBackClick="cancel(false)"/>
|
||||
<el-row style="margin-top: 20px;">
|
||||
<div class="card_list">
|
||||
<div class="card">
|
||||
<h2>姓名</h2>
|
||||
<p class="color1">{{ data.userName }}</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>积分余额</h2>
|
||||
<p class="color2">{{ data.integral || 0 }}</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>已用积分</h2>
|
||||
<p class="color3">{{ data.usedIntegral || 0 }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row class="echertsBox" style="margin-bottom: 16px">
|
||||
<div class="title">
|
||||
<h4>事件汇总</h4>
|
||||
<div class="timecSelect">
|
||||
时间:<el-date-picker size="small" value-format="yyyy-MM-dd" @change="timeChange" v-model="timeList" type="daterange" range-separator="至" :start-placeholder="startPla" :end-placeholder="endPla"></el-date-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bar_Box">
|
||||
<div id="chartDom" style="height: 230px; width: 100%;" v-show="xData.length && yData.length"></div>
|
||||
<ai-empty style="height: 200px; width: 100%;" v-show="!xData.length && !yData.length"></ai-empty>
|
||||
</div>
|
||||
</el-row>
|
||||
<ai-card>
|
||||
<ai-title slot="title" title="余额变动明细"/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<ai-select v-model="search.type" placeholder="请选择类型" @change="search.current=1,getIntegralChange()"
|
||||
:selectList="dict.getDict('integralType')"/>
|
||||
</template>
|
||||
<template #right>
|
||||
<ai-download :instance="instance" :url="`/app/appintegraluser/changeIntegralExport?id=${$route.query.id}`" :params="search" fileName="网格员余额变动明细"
|
||||
:disabled="tableData.length == 0">
|
||||
<el-button size="small">导出</el-button>
|
||||
</ai-download>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="total" :current.sync="search.current" :size.sync="search.size"
|
||||
@getList="getIntegralChange" :col-configs="colConfigs" :dict="dict">
|
||||
<el-table-column slot="changeIntegral" label="变动积分" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.integralType == 3">{{ row.changeIntegral | formatTime }}</span>
|
||||
<span v-if="row.integralType == 0">{{ row.integralCalcType == 0 ? '-' : '+' }}{{ row.changeIntegral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="integralType" label="类型" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.integralType == 0">积分调整</span>
|
||||
<span v-else>{{ row.eventType }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="eventDesc" label='事件' align="center" width="400px" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.integralType == 0">{{ row.eventDesc }}</span>
|
||||
<span v-else>{{ row.eventName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from "dayjs";
|
||||
import * as echarts from 'echarts';
|
||||
export default {
|
||||
name: "gridScoreDetail",
|
||||
data() {
|
||||
return {
|
||||
myChart: null,
|
||||
tableData: [],
|
||||
search: {
|
||||
name: '',
|
||||
girdId: '',
|
||||
type: '',
|
||||
current: 1,
|
||||
size: 10,
|
||||
},
|
||||
total: 0,
|
||||
girdList: [],
|
||||
timeList: [],
|
||||
data: {},
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
xData: [],
|
||||
yData: [],
|
||||
startPla: '',
|
||||
endPla: ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
},
|
||||
|
||||
computed: {
|
||||
colConfigs() {
|
||||
return [
|
||||
{ prop: "doTime", label: '时间', align: "left", width: "200px" },
|
||||
{ slot: "integralType", label: '类型', align: "center", width: "240px", dict:"integralType"},
|
||||
{ slot: "changeIntegral"},
|
||||
{ prop: "nowIntegral", label: '剩余积分', align: "center",width: "200px" },
|
||||
{ slot: "eventDesc"},
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$dict.load('integralType').then(() => {
|
||||
this.getDetail()
|
||||
this.getIntegralChange()
|
||||
this.getEventSummary()
|
||||
let nowTime = dayjs().format('YYYY-MM-DD')
|
||||
let timeAgo = dayjs().subtract(29, 'day').format('YYYY-MM-DD')
|
||||
this.startPla = timeAgo
|
||||
this.endPla = nowTime
|
||||
})
|
||||
|
||||
},
|
||||
methods: {
|
||||
// 详情
|
||||
getDetail() {
|
||||
this.instance.post(`/app/appintegraluser/girdDetail`,null,{
|
||||
params: {
|
||||
id: this.$route.query.id
|
||||
}
|
||||
}).then(res=>{
|
||||
if(res?.data) {
|
||||
this.data = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 事件汇总
|
||||
getEventSummary() {
|
||||
this.instance.post(`/app/appintegraluser/eventSummary`,null,{
|
||||
params: {
|
||||
id: this.$route.query.id,
|
||||
startTime: this.startTime,
|
||||
endTime: this.endTime,
|
||||
}
|
||||
}).then(res=>{
|
||||
if(res?.data) {
|
||||
this.xData = res.data.map(x=> x.eventName)
|
||||
this.yData = res.data.map(y=> y.totalIntegral)
|
||||
this.getColEcherts(this.xData, this.yData)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 余额变动明细
|
||||
getIntegralChange() {
|
||||
this.instance.post(`/app/appintegraluser/getChangeDetail`, null, {
|
||||
params: {
|
||||
...this.search, //积分类型
|
||||
total: this.total,
|
||||
id: this.$route.query.id,
|
||||
}
|
||||
}).then(res => {
|
||||
if(res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
timeChange() {
|
||||
if(this.timeList.length) {
|
||||
this.startTime = this.timeList[0]
|
||||
this.endTime = this.timeList[1]
|
||||
this.getEventSummary()
|
||||
}
|
||||
},
|
||||
|
||||
getColEcherts(xData, yData) {
|
||||
let chartDom = document.getElementById('chartDom');
|
||||
chartDom.style.width = window.innerWidth - 335 + "px";
|
||||
this.myChart = echarts.init(chartDom);
|
||||
this.myChart.setOption({
|
||||
dataZoom: [
|
||||
{
|
||||
type: "slider",
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
},
|
||||
],
|
||||
grid: {
|
||||
left: '16px',
|
||||
right: '28px',
|
||||
bottom: '14px',
|
||||
top: '30px',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: xData,
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: yData,
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#5087ec",
|
||||
label: {
|
||||
show: true, //开启显示
|
||||
position: 'top', //在上方显示
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: '#666'
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
barWidth: 20,
|
||||
barGap: '20%',
|
||||
}
|
||||
]
|
||||
}, true);
|
||||
window.addEventListener("resize", this.onResize)
|
||||
},
|
||||
|
||||
onResize() {
|
||||
this.myChart.resize()
|
||||
},
|
||||
|
||||
cancel(isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'gridScoreManage',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
filters: {
|
||||
formatTime(num) {
|
||||
if(num > 0) {
|
||||
return '+' + num
|
||||
} else {
|
||||
return num
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getColEcherts()
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
window.removeEventListener('resize', this.onResize)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gridScoreDetail {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
overflow-y: scroll;
|
||||
.card_list {
|
||||
display: flex;
|
||||
.card {
|
||||
flex: 1;
|
||||
height: 96px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15,15,21,0.1500);
|
||||
border-radius: 4px;
|
||||
margin-right: 20px;
|
||||
padding: 16px 24px;
|
||||
box-sizing: border-box;
|
||||
h2 {
|
||||
color: #888888;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
p {
|
||||
margin-top: 8px;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.color1 {
|
||||
color: #2891FF;
|
||||
}
|
||||
.color2 {
|
||||
color: #22AA99;
|
||||
}
|
||||
.color3 {
|
||||
color: #F8B425;
|
||||
}
|
||||
}
|
||||
.card:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
.echertsBox {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15,15,21,0.1500);
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
h4 {
|
||||
color: #222222;
|
||||
font-style: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.bar_Box {
|
||||
width: 100%;
|
||||
#chartDom {
|
||||
width: 100%;
|
||||
height: 230px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,361 @@
|
||||
<template>
|
||||
<section class="gridScoreManage">
|
||||
<ai-list>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" size="small" icon="iconfont iconAdd" @click="changeIntegral('',0)"> 批量调整积分</el-button>
|
||||
<el-cascader ref="cascader1" clearable v-model="girdIdList" :options="girdOptions" placeholder="所属网格" size="small"
|
||||
:props="defaultProps" :show-all-levels="false" @change="gridChange"></el-cascader>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" placeholder="姓名" v-model="search.userName" clearable
|
||||
@clear="current = 1, search.userName = '', getTableData()" suffix-icon="iconfont iconSearch"
|
||||
v-throttle="() => {(current = 1), getTableData();}"/>
|
||||
<ai-download :instance="instance" url="/app/appintegraluser/girdIntegralExport" :params="search" fileName="网格员积分"
|
||||
:disabled="tableData.length == 0">
|
||||
<el-button size="small">导出</el-button>
|
||||
</ai-download>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="total" :current.sync="current" :size.sync="size"
|
||||
@getList="getTableData()" :col-configs="colConfigs" :dict="dict" @sort-change="changeTableSort">
|
||||
|
||||
|
||||
<el-table-column slot="options" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" @click="changeIntegral(row,1)">调整积分</el-button>
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<ai-dialog
|
||||
title="调整积分"
|
||||
:visible.sync="dialog"
|
||||
:destroyOnClose="true"
|
||||
width="720px"
|
||||
@onConfirm="onConfirm"
|
||||
@closed="form={},chooseUserList=[]">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="选择人员" prop="ids">
|
||||
<ai-person-select :instance="instance" :customClicker="true" :chooseUserList="chooseUserList"
|
||||
url="/app/appgirdmemberinfo/list" headerTitle="网格员列表"
|
||||
:isMultiple="true" dialogTitle="选择" @selectPerson="selectPerson" class="aipersonselect">
|
||||
<template name="option" v-slot:option="{ item }">
|
||||
<span class="iconfont iconProlife">{{ item.name }}</span>
|
||||
<ai-id mode="show" :show-eyes="false" :value="item.idNumber"/>
|
||||
</template>
|
||||
</ai-person-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="调整说明" prop="eventDesc">
|
||||
<el-input v-model.trim="form.eventDesc" placeholder="请输入..." type="textarea" :rows="4" show-word-limit
|
||||
maxlength="100"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="上传凭证">
|
||||
<ai-uploader :instance="instance" fileType="file" v-model="form.file" :limit="1"></ai-uploader>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="integralCalcType">
|
||||
<ai-select v-model="form.integralCalcType" :selectList="dict.getDict('integralCalcType')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="积分" prop="integral">
|
||||
<el-input v-model.trim="form.integral" placeholder="请输入正数" size="small"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
export default {
|
||||
name: "gridScoreManage",
|
||||
label: "积分管理",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
userName: '',
|
||||
girdId: '',
|
||||
current: 1,
|
||||
size: 10,
|
||||
sortFiled: '',
|
||||
sortRule: '',
|
||||
},
|
||||
girdIdList: [],
|
||||
tableData: [],
|
||||
size: 10,
|
||||
total: 0,
|
||||
current: 1,
|
||||
girdList: [],
|
||||
form: {
|
||||
ids: [],
|
||||
eventDesc: "",
|
||||
enclosure: "", // 附件
|
||||
integralCalcType: "",
|
||||
integral: '',
|
||||
file: [],
|
||||
},
|
||||
personList: [],
|
||||
dialog: false,
|
||||
girdOptions: [],
|
||||
defaultProps: {
|
||||
label: 'girdName',
|
||||
value: 'id',
|
||||
checkStrictly: true,
|
||||
},
|
||||
chooseUserList: [],
|
||||
flag: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$dict.load('integralCalcType')
|
||||
this.getTableData()
|
||||
this.getGridList()
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
colConfigs() {
|
||||
return [
|
||||
{ prop: "userName", label: '姓名', align: "left", },
|
||||
{ prop: "girdName", label: '所属网格' },
|
||||
{ prop: "integral", label: '积分余额', align: "center", sortable: "custom" },
|
||||
{ prop: "totalIntegral", label: '累计积分', align: "center", sortable: "custom" },
|
||||
{ prop: "usedIntegral", label: '已用积分', align: "center", sortable: "custom" },
|
||||
{ slot: "options" },
|
||||
]
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
ids: [{required: true, message: '请选择人员', trigger: 'blur'}],
|
||||
eventDesc: [{required: true, message: '请输入调整说明', trigger: 'blur'}],
|
||||
integralCalcType: [{required: true, message: '请选择类型', trigger: 'change'}],
|
||||
integral: [{required: true, message: '请输入积分', trigger: 'blur' },
|
||||
{pattern: /^([1-9]\d*|0)(\.\d{1,2})?$/, message: '请输入正数且最多只能保留两位小数'}],
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getTableData() {
|
||||
this.instance.post(`/app/appintegraluser/integralManager`,null,{
|
||||
params: {
|
||||
...this.search,
|
||||
current: this.current,
|
||||
size: this.size,
|
||||
total: this.total
|
||||
}
|
||||
}).then(res => {
|
||||
if(res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
selectPerson(val) {
|
||||
if (val) {
|
||||
this.personList = val
|
||||
this.form.ids = [...this.personList.map(e => e.id)]
|
||||
} else {
|
||||
this.form.ids = this.chooseUserList.map(e => e.id)
|
||||
}
|
||||
},
|
||||
changeIntegral(row,type) {
|
||||
if(type==0) {
|
||||
this.dialog = true
|
||||
} else if(type ==1) {
|
||||
this.chooseUserList = [{
|
||||
id: row.userId,
|
||||
name: row.userName
|
||||
}]
|
||||
this.form.ids = this.chooseUserList.map(e => e.id)
|
||||
this.dialog = true
|
||||
}
|
||||
},
|
||||
getGridList() {
|
||||
this.instance.post(`/app/appgirdinfo/listAll3`).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.girdOptions = this.toTree(res.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 转树形结构
|
||||
toTree(data) {
|
||||
let result = [];
|
||||
if (!Array.isArray(data)) {
|
||||
return result
|
||||
}
|
||||
let map = {};
|
||||
data.forEach(item => {
|
||||
map[item.id] = item;
|
||||
});
|
||||
data.forEach(item => {
|
||||
let parent = map[item.parentGirdId];
|
||||
if (parent) {
|
||||
(parent.children || (parent.children = [])).push(item);
|
||||
} else {
|
||||
result.push(item);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
gridChange(val) {
|
||||
this.girdIdList = val
|
||||
this.search.girdId = val?.[val.length - 1]
|
||||
this.$refs.cascader1.dropDownVisible = false;
|
||||
this.getTableData()
|
||||
},
|
||||
|
||||
changeTableSort(col) {
|
||||
if(col.prop === 'integral') { // 剩余积分
|
||||
this.search.sortFiled = 0
|
||||
if(col.order === 'ascending') {
|
||||
this.search.sortRule = true
|
||||
} else if(col.order === 'descending') {
|
||||
this.search.sortRule = false
|
||||
} else if(col.order === null) {
|
||||
this.search.sortRule = ''
|
||||
}
|
||||
} else if(col.prop === 'totalIntegral') { // 累计积分
|
||||
this.search.sortFiled = 1
|
||||
if(col.order === 'ascending') {
|
||||
this.search.sortRule = true
|
||||
} else if(col.order === 'descending') {
|
||||
this.search.sortRule = false
|
||||
} else if(col.order === null) {
|
||||
this.search.sortRule = ''
|
||||
}
|
||||
} else if(col.prop === 'usedIntegral') { // 已用积分
|
||||
this.search.sortFiled = 2
|
||||
if(col.order === 'ascending') {
|
||||
this.search.sortRule = true
|
||||
} else if(col.order === 'descending') {
|
||||
this.search.sortRule = false
|
||||
} else if(col.order === null) {
|
||||
this.search.sortRule = ''
|
||||
}
|
||||
}
|
||||
this.getTableData()
|
||||
},
|
||||
|
||||
onConfirm() {
|
||||
if(this.flag) return
|
||||
|
||||
if(this.form.file?.length) {
|
||||
this.form.enclosure = this.form.file[0].url
|
||||
}
|
||||
this.$refs.form.validate((valid)=> {
|
||||
if(valid) {
|
||||
this.flag = true
|
||||
this.instance.post(`/app/appintegraluser/changeIntegral`,{
|
||||
ids: this.form.ids,
|
||||
eventDesc: this.form.eventDesc,
|
||||
enclosure: this.form.enclosure, // 附件
|
||||
integralCalcType: this.form.integralCalcType,
|
||||
integral: this.form.integral,
|
||||
}).then(res => {
|
||||
if(res?.code == 0) {
|
||||
this.$message.success('调整积分成功')
|
||||
setTimeout(() =>{
|
||||
this.dialog = false
|
||||
this.getTableData()
|
||||
this.flag = false
|
||||
}, 600)
|
||||
} else {
|
||||
this.flag = false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
toDetail(id) {
|
||||
this.$emit('change', {
|
||||
type: 'gridScoreDetail',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gridScoreManage {
|
||||
height: 100%;
|
||||
|
||||
::v-deep .ai-dialog .ai-dialog__content {
|
||||
max-height: 600px!important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.userlist {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.userlist, .user {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.user {
|
||||
position: relative;
|
||||
width: 70px;
|
||||
text-align: center;
|
||||
|
||||
.remove-icon {
|
||||
position: absolute;
|
||||
right: 7px;
|
||||
top: -4px;
|
||||
line-height: 1;
|
||||
padding: 6px 0;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: crimson;
|
||||
}
|
||||
}
|
||||
|
||||
img, h2 {
|
||||
display: block;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
margin: 0 auto 4px;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
background-color: $primaryColor;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .selectCont .pagination {
|
||||
width: 100%!important;
|
||||
background: pink;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,482 @@
|
||||
<template>
|
||||
<section class="gridScoreRules">
|
||||
<!-- v-if="permissions('app_appvillagerintegralrule_detail')" -->
|
||||
<ai-list>
|
||||
<template slot="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="dialog = true"> 添加</el-button>
|
||||
<el-cascader size="small" v-model="systemRuleIdList" :options="rulesOps" placeholder="请选择事件/类型" clearable :props="rulesProps"
|
||||
@change="handleTypeSearch" ref="eventTypeSearch"/>
|
||||
<ai-select v-model="search.status" @change="(page.current = 1), getList()" placeholder="请选择状态" :selectList="$dict.getDict('integralRuleStatus')">
|
||||
</ai-select>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :col-configs="colConfigs" :total="page.total" :dict="dict" :current.sync="page.current" :size.sync="page.size"
|
||||
@getList="getList()">
|
||||
<el-table-column slot="integral" label="分值" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<!-- <span v-if="row.integralValueType == 1">
|
||||
{{ row.integralStart > 0 ? "+" + row.integralStart : row.integralStart }}~{{ row.integralEnd > 0 ? "+" + row.integralEnd : row.integralEnd }}
|
||||
</span> -->
|
||||
<span>{{ row.integral > 0 ? "+" : "" }}{{ row.integral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right" width="200">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="changeStatus(row.id, 0)" v-if="row.status == 1">停用</el-button>
|
||||
<el-button type="text" @click="changeStatus(row.id, 1)" v-else>启用</el-button>
|
||||
<el-button type="text" @click="toEdit(row)">编辑</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<!-- <ai-empty v-else>暂无应用权限</ai-empty> -->
|
||||
<ai-dialog :title="dialogTitle" :visible.sync="dialog" @onConfirm="onConfirm" @closed="closed" width="900px" @open="beforeSelectTree">
|
||||
<div class="form_div">
|
||||
<el-form ref="DialogForm" :model="form" :rules="formRules" size="small" label-suffix=":" label-width="150px">
|
||||
<el-form-item label="事件类型" prop="systemRuleId">
|
||||
<el-cascader v-model="form.systemRuleId" ref="cascaderArr" :props="etOps" clearable placeholder="请选择" @change="handleTypeForm" :options="rulesOps"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="自定义事件" v-if="form.systemRuleId == '自定义'" prop="ruleName" :required="form.systemRuleId == '自定义'">
|
||||
<el-input placeholder="请输入,周期范围内,不填写表示不限制" v-model="form.ruleName" clearable maxlength="10" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="规则">
|
||||
<div>常规</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- <el-form-item label="规则" prop="ruleType" v-if="form.ruleType>-1" required>
|
||||
<el-row type="flex" justify="space-between">
|
||||
<div v-text="$dict.getLabel('integralRuleRuleType',form.ruleType)"/>
|
||||
<el-button v-if="form.ruleType==1" type="text" icon="iconfont iconAdd"
|
||||
@click="form.ladderRule.push({viewCount:null,integral:null})">添加
|
||||
</el-button>
|
||||
</el-row>
|
||||
<el-table v-if="form.ruleType==1" :data="form.ladderRule" size="mini" border stripe>
|
||||
<el-table-column label="查看人数(人)" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-input class="tableInput" v-model.number="row.viewCount" clearable placeholder="请输入"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="获得积分(分)" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-input class="tableInput" v-model="row.integral" clearable placeholder="请输入" type="number"
|
||||
@keyup.native="row.integral=checkIntegral(row.integral)"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template slot-scope="{$index}">
|
||||
<el-button type="text" @click="handleDelete($index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item label="周期范围" prop="scoringCycle">
|
||||
<ai-select v-model="form.scoringCycle" :selectList="$dict.getDict('integralRuleScoringCycle')"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="奖励次数">
|
||||
<el-input type="number" placeholder="请输入,周期范围内,不填写表示不限制" v-model.number="form.numberLimit" clearable/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="积分分值" prop="integral">
|
||||
<el-input placeholder="请输入" v-model="form.integral" clearable/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="有效范围" prop="validRangeType" required>
|
||||
<el-radio-group v-model="form.validRangeType">
|
||||
<el-radio label="0">全局</el-radio>
|
||||
<el-radio label="1">指定网格</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="生效网格" :prop="form.validRangeType == 1 ? 'validRangeData' : ''"
|
||||
:rules="[{ required: true, message: '请选择生效网格', trigger: 'change' }, ]" v-if="form.validRangeType == 1">
|
||||
<ai-dialog-btn dialogTitle="选择网格" append-to-body @onConfirm="getCheckedTree" :customFooter="false" :text="girdInfoList.length ? '重新选择' : '请选择'">
|
||||
<div class="grid">
|
||||
<el-tree :data="treeObj.treeList" :props="treeObj.defaultProps" node-key="id" :expand-on-click-node="false">
|
||||
<template slot-scope="{data}">
|
||||
<el-row class="fill" type="flex" @click.native.stop="handleTreeChecked(data)">
|
||||
<div class="fill" v-text="data.girdName"/>
|
||||
<div class="iconfont iconSuccess color-primary mar-r8" v-if="data.checked"/>
|
||||
</el-row>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
</ai-dialog-btn>
|
||||
|
||||
<div v-if="girdInfoList.length">
|
||||
<span v-for="(e,index) in girdNameList" :key="index" class="mar-r8" v-text="e"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "gridScoreRules",
|
||||
label: "积分规则",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
},
|
||||
data() {
|
||||
var validcode = (rule, value, callback) => {
|
||||
if (value) {
|
||||
if (value != 0) {
|
||||
if (!/^([+-]?([1-9]{1}\d*)|(0{1}))(\.\d{1,2})?$/.test(value)) {
|
||||
callback(new Error('请输入积分分值,可输入正数、负数、最多保留两位小数'))
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('请输入有效的积分分值'));
|
||||
}
|
||||
} else {
|
||||
callback(new Error('请输入积分分值'));
|
||||
}
|
||||
}
|
||||
return {
|
||||
search: {
|
||||
status: "",
|
||||
systemRuleId: "",
|
||||
ruleName: ""
|
||||
},
|
||||
systemRuleIdList: [],
|
||||
page: {current: 1, size: 10, total: 0},
|
||||
colConfigs: [
|
||||
{
|
||||
prop: "parentRuleName",
|
||||
label: "类型",
|
||||
dict: "integralRuleEventType",
|
||||
},
|
||||
{prop: "ruleName", label: "事件", dict: "integralRuleEvent"},
|
||||
{prop: "ruleType", label: "规则", dict: "integralRuleRuleType"},
|
||||
{
|
||||
prop: "scoringCycle",
|
||||
label: "周期范围",
|
||||
dict: "integralRuleScoringCycle",
|
||||
render: (h, {row}) => {
|
||||
return h(
|
||||
"span",
|
||||
{},
|
||||
row.numberLimit.length
|
||||
? $dict.getLabel("integralRuleScoringCycle", row.scoringCycle)
|
||||
: $dict.getLabel("integralRuleScoringCycle", row.scoringCycle) +
|
||||
row.numberLimit +
|
||||
"次"
|
||||
);
|
||||
},
|
||||
},
|
||||
{slot: "integral", label: "积分分值", align: "center"},
|
||||
{
|
||||
prop: "validRangeType",
|
||||
label: "有效范围",
|
||||
formart: (v) => (v == 0 ? "全局" : "指定网格"),
|
||||
},
|
||||
{
|
||||
prop: "status",
|
||||
label: "状态",
|
||||
align: "center",
|
||||
width: 96,
|
||||
dict: "integralRuleStatus",
|
||||
},
|
||||
{slot: "options", label: "操作", align: "center"},
|
||||
],
|
||||
tableData: [],
|
||||
dialog: false,
|
||||
form: {
|
||||
ruleType: "0",
|
||||
systemRuleId: "",
|
||||
ruleName: "",
|
||||
scoringCycle: "",
|
||||
numberLimit: "",
|
||||
integral: "",
|
||||
validRangeType: "0",
|
||||
validRangeData: "",
|
||||
},
|
||||
formRules: {
|
||||
systemRuleId: [
|
||||
{required: true, message: "请选择事件/类型", trigger: "change"},
|
||||
],
|
||||
ruleName: [
|
||||
{required: true, message: "请输入自定义事件", trigger: "change"},
|
||||
],
|
||||
scoringCycle: [
|
||||
{required: true, message: "请选择周期范围", trigger: "change"},
|
||||
],
|
||||
integral: [{required: true, validator: validcode, trigger: "blur"},],
|
||||
validRangeType: [
|
||||
{required: true, message: "请选择有效范围", trigger: "change"},
|
||||
],
|
||||
},
|
||||
rulesOps: [],
|
||||
rulesProps: {
|
||||
label: "ruleName",
|
||||
value: "id",
|
||||
checkStrictly: true,
|
||||
},
|
||||
radio: 0,
|
||||
treeObj: {
|
||||
treeList: [],
|
||||
defaultProps: {
|
||||
label: "girdName",
|
||||
value: "id",
|
||||
children: 'children',
|
||||
isLeaf: 'leaf'
|
||||
},
|
||||
},
|
||||
treeSelected: {},
|
||||
girdInfoList: [],
|
||||
rulueType: "0",
|
||||
girdNameList: [],
|
||||
list: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.$dict.load("integralRuleStatus", "integralRuleRuleType", "integralRuleScoringCycle",
|
||||
"integralRuleEvent", "integralRuleEventType").then(() => {
|
||||
this.getList();
|
||||
this.getRulesList();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance
|
||||
.post(`/app/appintegralrule/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
...this.page,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records;
|
||||
this.page.total = res.data.total;
|
||||
}
|
||||
});
|
||||
},
|
||||
closed() {
|
||||
this.form = {
|
||||
ruleType: "0",
|
||||
systemRuleId: "",
|
||||
ruleName: "",
|
||||
scoringCycle: "",
|
||||
numberLimit: "",
|
||||
integral: "",
|
||||
validRangeType: "0",
|
||||
validRangeData: "",
|
||||
};
|
||||
this.girdInfoList = []
|
||||
this.treeSelected = {}
|
||||
},
|
||||
toEdit(row) {
|
||||
this.form = {...row}
|
||||
if (this.form?.validRangeData) {
|
||||
this.girdInfoList = JSON.parse(this.form.validRangeData)
|
||||
this.girdNameList = this.girdInfoList.map(e => e.girdName)
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.dialog = true;
|
||||
});
|
||||
},
|
||||
remove(id) {
|
||||
this.$confirm("删除后不可恢复,是否要删除该规则?", {
|
||||
type: "error",
|
||||
}).then(() => {
|
||||
this.instance
|
||||
.post(`/app/appintegralrule/delete?ids=${id}`)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success("删除成功!");
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
changeStatus(id, status) {
|
||||
let text = status == 1 ? "启用" : "停用";
|
||||
this.$confirm(`确定${text}该条规则?`).then(() => {
|
||||
this.instance
|
||||
.post(`/app/appintegralrule/enableStatus?id=${id}`)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(`${text}成功!`);
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
onConfirm() {
|
||||
this.$refs.DialogForm.validate((valid) => {
|
||||
if (valid) {
|
||||
let formData = this.$copy(this.form);
|
||||
// formData.ladderRule = JSON.stringify(formData.ladderRule)
|
||||
formData.integral = formData.integral || 0;
|
||||
this.instance
|
||||
.post(`/app/appintegralrule/addOrUpdate`, formData)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(
|
||||
`${this.isEdit ? "编辑成功" : "添加成功"}`
|
||||
);
|
||||
this.dialog = false;
|
||||
this.getList();
|
||||
this.closed();
|
||||
this.girdInfoList = []
|
||||
this.girdNameList = []
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
handleTypeSearch(v) {
|
||||
this.systemRuleIdList = v
|
||||
this.search.systemRuleId = v?.[v.length - 1];
|
||||
this.search.ruleName = this.$refs.eventTypeSearch.getCheckedNodes()[0]?.label
|
||||
this.page.current = 1;
|
||||
this.$refs.eventTypeSearch.dropDownVisible = false;
|
||||
this.getList();
|
||||
},
|
||||
handleTypeForm(v) {
|
||||
if (this.dialog) {
|
||||
this.form.systemRuleId = v?.[v.length - 1];
|
||||
}
|
||||
},
|
||||
handleDelete(i) {
|
||||
this.$confirm("是否要删除该规则?")
|
||||
.then(() => {
|
||||
this.form.ladderRule.splice(i, 1);
|
||||
})
|
||||
.catch(() => 0);
|
||||
},
|
||||
checkIntegral(v) {
|
||||
return /\.\d{2,}$/.test(v) ? Math.abs(v).toFixed(1) : Math.abs(v);
|
||||
},
|
||||
getRulesList() {
|
||||
this.instance
|
||||
.post(`/app/appintegralsystemrule/list?current=1&sizes=3000`)
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.rulesOps = this.toTree(res.data.records);
|
||||
this.rulesOps.push({
|
||||
ruleName: "自定义",
|
||||
id: "自定义",
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 转树形结构
|
||||
toTree(data) {
|
||||
let result = [];
|
||||
if (!Array.isArray(data)) {
|
||||
return result;
|
||||
}
|
||||
let map = {};
|
||||
data.forEach((item) => {
|
||||
map[item.id] = item;
|
||||
});
|
||||
data.forEach((item) => {
|
||||
let parent = map[item.parentRuleId];
|
||||
if (parent) {
|
||||
(parent.children || (parent.children = [])).push(item);
|
||||
} else {
|
||||
result.push(item);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
getCheckedTree() {
|
||||
const selected = Object.values(this.treeSelected)
|
||||
if (!selected.length) {
|
||||
return this.$message.error("请选择网格");
|
||||
}
|
||||
|
||||
this.girdInfoList = selected.map((item) => {
|
||||
return {...item, checkType: true};
|
||||
});
|
||||
let validRangeData = selected.map((e) => ({id: e.id, girdName: e.girdName}))
|
||||
this.girdNameList = validRangeData.map(e => e.girdName)
|
||||
this.form.validRangeData = JSON.stringify(validRangeData)
|
||||
},
|
||||
beforeSelectTree() {
|
||||
this.instance.post(`/app/appgirdinfo/listAll3`, null, null).then((res) => {
|
||||
if (res?.data) {
|
||||
this.list = res.data.map(e => ({...e, checked: !!this.girdInfoList.find(s => s.id == e.id)}))
|
||||
this.girdInfoList.map(e => this.treeSelected[e.id] = e)
|
||||
this.treeObj.treeList = this.$arr2tree(this.list, {parent: 'parentGirdId'})
|
||||
}
|
||||
});
|
||||
},
|
||||
handleTreeChecked(data) {
|
||||
this.list.forEach(v => {
|
||||
return {
|
||||
...v,
|
||||
checked: false
|
||||
}
|
||||
})
|
||||
data.checked = !data.checked
|
||||
if (data.checked) {
|
||||
this.treeSelected[data.id] = data
|
||||
} else {
|
||||
delete this.treeSelected[data.id]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isEdit() {
|
||||
return !!this.form.id;
|
||||
},
|
||||
dialogTitle() {
|
||||
return this.isEdit ? "编辑积分规则" : "添加积分规则";
|
||||
},
|
||||
etOps() {
|
||||
return {
|
||||
value: "id",
|
||||
label: "ruleName",
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gridScoreRules {
|
||||
height: 100%;
|
||||
background: #f3f6f9;
|
||||
|
||||
::v-deep .ai-list__content--right {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// ::v-deep .searchRightZone {
|
||||
// display: flex;
|
||||
// }
|
||||
|
||||
::v-deep .ai-dialog {
|
||||
.el-cascader {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tableInput {
|
||||
& > input {
|
||||
text-align: center;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,653 @@
|
||||
<template>
|
||||
<section class="gridScoreStatistics">
|
||||
<el-row class="overallStatistics">
|
||||
<div class="title">
|
||||
<p>总体统计</p>
|
||||
<div class="title_right">
|
||||
<div>
|
||||
<span v-for="(item,index) in timeCheck" :key="index" :class="type == index? 'active':''"
|
||||
@click="timeChange(index)">{{ item }}</span>
|
||||
</div>
|
||||
<el-cascader ref="cascader1" v-model="girdArr" :options="girdOptions" placeholder="所属网格" size="small"
|
||||
:props="defaultProps" :show-all-levels="false" @change="gridChange" clearable></el-cascader>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card_list">
|
||||
<div class="card">
|
||||
<h2>积分余额汇总
|
||||
<el-tooltip
|
||||
placement="right"
|
||||
style="width: 16px;"
|
||||
content="截止目前所有网格员剩余可用积分余额的总和">
|
||||
<i class="el-icon-warning-outline"></i>
|
||||
</el-tooltip>
|
||||
</h2>
|
||||
<p class="color1">{{ data.nowIntegral || 0 }}</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>发放积分</h2>
|
||||
<p class="color1">{{ data.addIntegral || 0 }}</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>消耗积分</h2>
|
||||
<p class="color1">{{ data.reduceIntegral || 0 }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="echertsBox">
|
||||
<div class="left_Box">
|
||||
<p>个人积分排行</p>
|
||||
<div>
|
||||
<div id="chart1" style="height: 300px; width: 100%;" v-show="userSortListX.length && userSortListY.length"></div>
|
||||
<ai-empty v-show="!userSortListX.length && !userSortListY.length" style="height: 200px; width: 100%;" id="empty"></ai-empty>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right_Box">
|
||||
<p>网格积分排行</p>
|
||||
<div>
|
||||
<div id="chart2" style="height: 300px; width: 100%;" v-show="girdSortListX.length && girdSortListY.length"></div>
|
||||
<ai-empty v-show="!girdSortListX.length && !girdSortListY.length" style="height: 200px; width: 100%;" id="empty"></ai-empty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<ai-card>
|
||||
<ai-title slot="title" title="积分明细"/>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-cascader ref="cascader2" v-model="girdIdArr" :options="girdOptions" placeholder="所属网格" size="small"
|
||||
:props="defaultProps" :show-all-levels="false" clearable @change="gridChangeOpt"></el-cascader>
|
||||
<ai-select v-model="search.integralType" placeholder="请选择类型" @change="current=1, getTableData()"
|
||||
:selectList="dict.getDict('integralType')"/>
|
||||
<el-date-picker v-model="time" size="small" type="daterange" value-format="yyyy-MM-dd"
|
||||
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" @change="onChange">
|
||||
</el-date-picker>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input size="small" placeholder="请输入姓名" v-model="search.userName" clearable
|
||||
@clear="current = 1, search.userName = '', getTableData()" suffix-icon="iconfont iconSearch"
|
||||
v-throttle="() => {(current = 1), getTableData();}" />
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="total" :current.sync="current" :size.sync="size"
|
||||
@getList="getTableData" :col-configs="colConfigs" :dict="dict">
|
||||
<el-table-column slot="eventDesc" label='事件' align="center" width="400px" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.integralRuleId">{{ row.integralRuleName }}</span>
|
||||
<span v-else>{{ row.eventDesc }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="integralType" label="类型" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.integralRuleId">{{ row.eventType }}</span>
|
||||
<span v-else>{{ row.integralRuleName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="changeIntegral" label="积分变动" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.integralType == 3">{{ row.changeIntegral | formatTime }}</span>
|
||||
<span v-if="row.integralType == 0">{{ row.integralCalcType == 0 ? '-' : '+' }}{{ row.changeIntegral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" @click="open(row.id)">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-card>
|
||||
|
||||
<el-dialog title="详情" :visible.sync="dialog" customFooter width="700">
|
||||
<ai-detail>
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="姓名" :value="details.integralUserName" />
|
||||
<ai-info-item label="所属网格" :value="details.girdName"/>
|
||||
<ai-info-item label="事件" isLine :value="details.eventDesc">
|
||||
<span v-if="details.integralRuleId">{{ details.integralRuleName }}</span>
|
||||
<span v-else>{{ details.eventDesc }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="时间" isLine :value="details.createTime"/>
|
||||
<ai-info-item label="积分变动" v-if="details.integralType == 3">
|
||||
{{ details.changeIntegral | formatTime }}
|
||||
</ai-info-item>
|
||||
<ai-info-item label="积分变动" v-if="details.integralType == 0">
|
||||
{{ details.changeIntegral > 0 ? '+' : '-' }}{{ details.changeIntegral }}
|
||||
</ai-info-item>
|
||||
<ai-info-item label="积分余额" :value="details.nowIntegral"/>
|
||||
<ai-info-item label="凭证" isLine v-if="fileDownLoad.length">
|
||||
<ai-file-list :fileList="fileDownLoad" style="width: 200px;" :fileOps="{name: 'name'}"></ai-file-list>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-detail>
|
||||
<span slot="footer" class="dialog-footer" center>
|
||||
<el-button @click="dialog = false" style="width: 92px">关闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<ai-dialog :visible.sync="dialogDate" title="选择时间" width="500px" customFooter>
|
||||
<el-date-picker v-model="timeList" size="small" type="daterange" value-format="yyyy-MM-dd"
|
||||
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
<el-button slot="footer" @click="selectDete" type="primary">确认</el-button>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex"
|
||||
import * as echarts from 'echarts';
|
||||
export default {
|
||||
name: "gridScoreStatistics",
|
||||
label: "积分统计",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
myChart1: null,
|
||||
myChart2: null,
|
||||
tableData: [],
|
||||
search: {
|
||||
current: 1,
|
||||
userName: '',
|
||||
girdId: '',
|
||||
integralType: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
},
|
||||
girdIdArr:[],
|
||||
total: 0,
|
||||
size: 10,
|
||||
current: 1,
|
||||
girdList: [],
|
||||
time: [],
|
||||
timeCheck: ['昨日','近7天','近30天','自定义'],
|
||||
dialog: false,
|
||||
dialogDate: false,
|
||||
timeList: [],
|
||||
type: '1',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
data: {},
|
||||
girdId: '',
|
||||
girdArr: [],
|
||||
girdOptions: [],
|
||||
defaultProps: {
|
||||
label: 'girdName',
|
||||
value: 'id',
|
||||
children: 'children',
|
||||
checkStrictly: true,
|
||||
},
|
||||
details: {},
|
||||
fileDownLoad: [],
|
||||
userSortListX: [],
|
||||
userSortListY: [],
|
||||
girdSortListX: [],
|
||||
girdSortListY: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
colConfigs() {
|
||||
return [
|
||||
{ prop: "integralUserName", label: '姓名', align: "left", width: "200px" },
|
||||
{ prop: "girdName", label: '所属网格', align: "center", width: "180px" },
|
||||
{ slot: "eventDesc"},
|
||||
{ slot: "integralType", label: '类型' },
|
||||
{ slot: "changeIntegral", label: '积分变动', align: "center", },
|
||||
{ prop: "nowIntegral", label: '剩余积分', align: "center", },
|
||||
{ prop: "createTime", label: '时间', align: "center", },
|
||||
{ slot: "options" }
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$dict.load('epidemicDangerousAreaLevel','integralType','integralRuleEvent','integralRuleEventType').then(() => {
|
||||
this.getStatistics()
|
||||
this.getGridList()
|
||||
this.getRanking()
|
||||
this.getTableData()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 统计接口
|
||||
getStatistics() {
|
||||
this.instance.post('/app/appintegraluser/allGirdIntegral',null, {
|
||||
params: {
|
||||
type: this.type,
|
||||
girdId: this.girdId,
|
||||
startTime: this.startTime,
|
||||
endTime: this.endTime,
|
||||
}
|
||||
}).then(res => {
|
||||
if(res?.data) {
|
||||
this.data = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 人员、网格排行
|
||||
getRanking() {
|
||||
this.instance.post('/app/appintegraluser/userAndGirdIntegralSort',null,{
|
||||
params: {
|
||||
type: this.type,
|
||||
girdId: this.girdId,
|
||||
startTime: this.startTime,
|
||||
endTime: this.endTime
|
||||
}
|
||||
}).then((res) => {
|
||||
if(res?.data) {
|
||||
this.userSortListX = res.data.userSortList.map(e=> e.userName).reverse()
|
||||
this.userSortListY = res.data.userSortList.map(e=> e.changeIntegral).reverse()
|
||||
this.girdSortListX = res.data.girdSortList.map(e=> e.girdName).reverse()
|
||||
this.girdSortListY = res.data.girdSortList.map(e=> e.changeIntegral).reverse()
|
||||
this.getColEcherts1(this.userSortListX,this.userSortListY)
|
||||
this.getColEcherts2(this.girdSortListX,this.girdSortListY)
|
||||
}
|
||||
})
|
||||
},
|
||||
// 积分明细
|
||||
getTableData() {
|
||||
this.instance.post('/app/appintegraluser/girdIntegralDetail',null,{
|
||||
params: {
|
||||
...this.search,
|
||||
current: this.current,
|
||||
size: this.size,
|
||||
total: this.total,
|
||||
}
|
||||
}).then(res => {
|
||||
if(res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
gridChangeOpt(val) {
|
||||
this.girdIdArr = val
|
||||
this.search.girdId = val?.[val.length - 1]
|
||||
this.$refs.cascader2.dropDownVisible = false;
|
||||
this.getTableData()
|
||||
},
|
||||
|
||||
getColEcherts1(xData,yData) {
|
||||
let chartDom1 = document.getElementById('chart1');
|
||||
chartDom1.style.width = (window.innerWidth - 435) / 2 + "px";
|
||||
this.myChart1 = echarts.init(chartDom1);
|
||||
this.myChart1.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '16px',
|
||||
right: '28px',
|
||||
bottom: '14px',
|
||||
top: '16px',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
boundaryGap: [0, 0.01],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: xData,
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
|
||||
series: [
|
||||
{
|
||||
data: yData,
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#5087ec",
|
||||
label: {
|
||||
show: true, //开启显示
|
||||
position: 'right', //在上方显示
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: '#666'
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
barWidth: 10,
|
||||
barGap: '20%',
|
||||
}
|
||||
]
|
||||
}, true);
|
||||
window.addEventListener("resize", this.onResize)
|
||||
},
|
||||
getColEcherts2(xData,yData) {
|
||||
let chartDom2 = document.getElementById('chart2');
|
||||
chartDom2.style.width = (window.innerWidth - 435) / 2 + "px";
|
||||
this.myChart2 = echarts.init(chartDom2);
|
||||
this.myChart2.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '16px',
|
||||
right: '28px',
|
||||
bottom: '14px',
|
||||
top: '16px',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
boundaryGap: [0, 0.01],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: xData,
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
triggerEvent: true,
|
||||
//设置文本过长超出隐藏...表示
|
||||
axisLabel:{
|
||||
margin: 8,
|
||||
formatter: function(params){
|
||||
var val=""
|
||||
if(params.length > 8) {
|
||||
val = params.substr(0,8)+'...'
|
||||
return val
|
||||
} else {
|
||||
return params;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: yData,
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#5087ec",
|
||||
label: {
|
||||
show: true, //开启显示
|
||||
position: 'right', //在右方显示
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: '#666'
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
barWidth: 10,
|
||||
barGap: '20%',
|
||||
}
|
||||
]
|
||||
}, true);
|
||||
window.addEventListener("resize", this.onResize2)
|
||||
// this.extension(this.myChart2)
|
||||
},
|
||||
onResize1() {
|
||||
this.myChart1.resize()
|
||||
},
|
||||
onResize2() {
|
||||
this.myChart2.resize()
|
||||
},
|
||||
gridChange(val) {
|
||||
this.girdArr = val
|
||||
this.girdId = val?.[val.length - 1]
|
||||
this.$refs.cascader1.dropDownVisible = false;
|
||||
this.getStatistics()
|
||||
this.getRanking()
|
||||
},
|
||||
// 所有网格
|
||||
getGridList() {
|
||||
this.instance.post(`/app/appgirdinfo/listAll3`).then((res) => {
|
||||
if (res?.code == 0) {
|
||||
this.girdOptions = this.toTree(res.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 转树形结构
|
||||
toTree(data) {
|
||||
let result = [];
|
||||
if (!Array.isArray(data)) {
|
||||
return result
|
||||
}
|
||||
let map = {};
|
||||
data.forEach(item => {
|
||||
map[item.id] = item;
|
||||
});
|
||||
data.forEach(item => {
|
||||
let parent = map[item.parentGirdId];
|
||||
if (parent) {
|
||||
(parent.children || (parent.children = [])).push(item);
|
||||
} else {
|
||||
result.push(item);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
timeChange(index) {
|
||||
if(index == 3) {
|
||||
this.dialogDate = true
|
||||
}
|
||||
this.type = index
|
||||
this.getStatistics()
|
||||
this.getRanking()
|
||||
},
|
||||
|
||||
open(id) {
|
||||
this.dialog = true
|
||||
this.getDetail(id)
|
||||
},
|
||||
|
||||
onChange(val) {
|
||||
this.search.startTime = val?.[0]
|
||||
this.search.endTime = val?.[1]
|
||||
this.getTableData()
|
||||
},
|
||||
|
||||
getDetail(id) {
|
||||
this.instance.post(`/app/appintegraldetail/queryDetailById?id=${id}`).then(res=> {
|
||||
if(res?.data) {
|
||||
this.details = res.data
|
||||
if(res.data.enclosure) {
|
||||
let str = res.data.enclosure.split('/')
|
||||
this.fileDownLoad = [{
|
||||
url:res.data.enclosure,
|
||||
name: str?.[str.length - 1]
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
selectDete() {
|
||||
if(!this.timeList || !this.timeList.length) {
|
||||
return this.$message.error('请选择自定义时间');
|
||||
}
|
||||
this.startTime = this.timeList?.[0]
|
||||
this.endTime = this.timeList?.[1]
|
||||
this.dialogDate = false
|
||||
this.getStatistics()
|
||||
this.getRanking()
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
filters: {
|
||||
formatTime(num) {
|
||||
if(num > 0) {
|
||||
return '+' + num
|
||||
} else {
|
||||
return num
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getColEcherts1()
|
||||
this.getColEcherts2()
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
window.removeEventListener('resize', this.onResize1)
|
||||
window.removeEventListener('resize', this.onResize2)
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gridScoreStatistics {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding-top: 20px;
|
||||
.overallStatistics {
|
||||
width: 100%;
|
||||
margin-bottom: 16px;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
background: #FFF;
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
p {
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #222222;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.title_right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
span {
|
||||
display: inline-block;
|
||||
width: 70px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
margin-right: 8px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.active {
|
||||
color: #2266FF;
|
||||
border: 1px solid #2266FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card_list {
|
||||
display: flex;
|
||||
.card {
|
||||
flex: 1;
|
||||
height: 96px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
margin-right: 20px;
|
||||
padding: 16px 24px;
|
||||
box-sizing: border-box;
|
||||
h2 {
|
||||
color: #888888;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
p {
|
||||
margin-top: 8px;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.color1 {
|
||||
color: #2891FF;
|
||||
}
|
||||
.color2 {
|
||||
color: #22AA99;
|
||||
}
|
||||
.color3 {
|
||||
color: #F8B425;
|
||||
}
|
||||
}
|
||||
.card:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
.echertsBox {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
background: #FFF;
|
||||
display: flex;
|
||||
.left_Box {
|
||||
margin-right: 16px;
|
||||
flex: 1;
|
||||
}
|
||||
.right_Box {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.left_Box,
|
||||
.right_Box {
|
||||
background: #F9F9F9;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15,15,21,0.1500);
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
#chart1,
|
||||
#chart2 {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
p {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// .chartCss {
|
||||
// position: absolute;
|
||||
// color: black;
|
||||
// background:white;
|
||||
// font-family: Aril;
|
||||
// font-size: 12px;
|
||||
// padding: 5px;
|
||||
// display: inline;
|
||||
// }
|
||||
|
||||
::v-deep .el-dialog__footer {
|
||||
text-align: center;
|
||||
}
|
||||
::v-deep .el-dialog__header {
|
||||
border-bottom: 1px solid #DDD;
|
||||
}
|
||||
::v-deep .ai-detail {
|
||||
background: #FFF;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div class="AppHealthReport">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List.vue'
|
||||
import Detail from './components/Detail.vue'
|
||||
|
||||
export default {
|
||||
name: 'AppIntegralAudit',
|
||||
label: '积分审核',
|
||||
|
||||
components: {
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (data) {
|
||||
if (data.type === 'Detail') {
|
||||
this.component = 'Detail'
|
||||
this.isShowDetail = true
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'list') {
|
||||
this.component = 'List'
|
||||
this.params = data.params
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (data.isRefresh) {
|
||||
this.$refs.component.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppHealthReport {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
239
packages/conv/creditScore/AppIntegralAudit/components/Detail.vue
Normal file
239
packages/conv/creditScore/AppIntegralAudit/components/Detail.vue
Normal file
@@ -0,0 +1,239 @@
|
||||
<template>
|
||||
<ai-detail class="audit">
|
||||
<template slot="title">
|
||||
<ai-title title="详情" isShowBack isShowBottomBorder @onBackClick="cancel(true)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="申请人" :value="info.residentName"></ai-info-item>
|
||||
<ai-info-item label="申请时间" :value="info.createTime"></ai-info-item>
|
||||
<!-- <ai-info-item label="积分类型" :value="dict.getLabel('atWillReportType', info.applyIntegralType)"></ai-info-item> -->
|
||||
<ai-info-item label="申请描述" :value="info.description" isLine></ai-info-item>
|
||||
<ai-info-item label="联系电话" isLine :value="info.residentPhone"></ai-info-item>
|
||||
<ai-info-item label="图片" isLine>
|
||||
<ai-uploader v-model="info.applyFiles" disabled></ai-uploader>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="处理结果" v-if="info.auditStatus !== '0'">
|
||||
<div slot="content" style="margin-top: 16px;margin-bottom:24px">
|
||||
<ai-wrapper
|
||||
label-width="120px">
|
||||
<ai-info-item label="审核结果" :value="info.auditStatus === '1' ? '通过' : '拒绝'" isLine></ai-info-item>
|
||||
<ai-info-item label="审核意见" v-if="info.auditStatus === '2'" isLine :value="info.auditOpinion"></ai-info-item>
|
||||
<!-- <ai-info-item label="积分规则类别" v-if="info.auditStatus === '1'" :value="dict.getLabel('atWillReportType', info.auditIntegralType)"></ai-info-item>-->
|
||||
<!-- <ai-info-item label="积分规则事项" v-if="info.auditStatus === '1'" :value="info.auditRuleName"></ai-info-item>-->
|
||||
<ai-info-item label="积分调整" isLine v-if="info.auditStatus === '1'"
|
||||
:value="(info.auditIntegral >= 0 ? info.auditIntegral : info.auditIntegral) + '分'"></ai-info-item>
|
||||
<ai-info-item label="审核人" :value="info.auditUserName"></ai-info-item>
|
||||
<ai-info-item label="审核时间" :value="info.auditTime"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
</div>
|
||||
</ai-card>
|
||||
<ai-dialog
|
||||
:visible.sync="isShow"
|
||||
width="800px"
|
||||
@close="onClose"
|
||||
title="事件审核"
|
||||
@onConfirm="onConfirm">
|
||||
<el-form class="ai-form" label-width="120px" :model="form" ref="form">
|
||||
<el-form-item label="是否通过审核" prop="pass" style="width: 100%;" :rules="[{ required: true, message: '请选择是否通过审核' }]">
|
||||
<el-radio-group v-model="form.pass" @change="onStatusChange">
|
||||
<el-radio label="0">否</el-radio>
|
||||
<el-radio label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.pass === '1'" label="积分调整" prop="auditIntegral" style="width: 100%;" :rules="[{ required: true, message: '请输入积分调整' }]">
|
||||
<el-input v-model.number="form.auditIntegral" clearable placeholder="请输入积分调整" @keyup.native="form.auditIntegral=Math.abs(form.auditIntegral)"/>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item v-if="form.pass === '1'" label="积分规则类别" prop="auditRuleId" style="width: 100%;" :rules="[{ required: true, message: '' }]">-->
|
||||
<!-- <div class="flex-warpper">-->
|
||||
<!-- <el-form-item label-width="0" prop="auditIntegralType" :rules="[{ required: true, message: '请选择积分规则类别' }]">-->
|
||||
<!-- <ai-select-->
|
||||
<!-- v-model="form.auditIntegralType"-->
|
||||
<!-- clearable-->
|
||||
<!-- style="width: 180px;"-->
|
||||
<!-- placeholder="请选择积分规则类别"-->
|
||||
<!-- :selectList="dict.getDict('atWillReportType')"-->
|
||||
<!-- @change="onChange">-->
|
||||
<!-- </ai-select>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item style="margin: 0 10px;" prop="auditRuleId" :rules="[{ required: true, message: '请选择积分规则事项' }]">-->
|
||||
<!-- <ai-select-->
|
||||
<!-- v-model="form.auditRuleId"-->
|
||||
<!-- clearable-->
|
||||
<!-- style="width: 180px;"-->
|
||||
<!-- placeholder="请选择积分规则事项"-->
|
||||
<!-- :selectList="ruleList">-->
|
||||
<!-- </ai-select>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <span>{{ integralText }}</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- </el-form-item>-->
|
||||
<el-form-item label="审核意见" v-if="form.pass === '0'" prop="opinion" style="width: 100%;" :rules="[{ required: true, message: '请输入审核意见' }]">
|
||||
<el-input type="textarea" :rows="5" :maxlength="200" v-model="form.opinion" clearable placeholder="请输入审核意见" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="isShow = true" v-if="info.auditStatus === '0'">审核</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Detail',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
const validatorRules = function (rule, value, callback) {
|
||||
if (value === '') {
|
||||
callback(new Error('请输入联系方式'))
|
||||
} else if (!/^1\d{10}$/.test(value)) {
|
||||
callback(new Error('手机号格式错误'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
total: 0,
|
||||
info: {
|
||||
auditStatus: '0'
|
||||
},
|
||||
id: '',
|
||||
isShow: false,
|
||||
form: {
|
||||
auditIntegralType: '',
|
||||
auditRuleId: '',
|
||||
opinion: '',
|
||||
pass: ''
|
||||
},
|
||||
ruleList: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
integralText() {
|
||||
if (!this.form.auditRuleId) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const integral = this.ruleList.filter(v => v.dictValue === this.form.auditRuleId)[0].integral
|
||||
|
||||
return integral >= 0 ? `+${integral}分` : `${integral}分`
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.dict.load(['atWillReportType', 'auditStatus']).then(() => {
|
||||
this.getInfo(this.params.id)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo(id) {
|
||||
this.instance.post(`/app/appvillagerintegraldeclare/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onStatusChange() {
|
||||
this.$refs.form.clearValidate()
|
||||
},
|
||||
|
||||
onClose() {
|
||||
this.form.auditIntegralType = ''
|
||||
this.form.auditRuleId = ''
|
||||
this.form.pass = ''
|
||||
this.form.opinion = ''
|
||||
this.id = ''
|
||||
},
|
||||
|
||||
onConfirm() {
|
||||
this.$refs.form.validate(v => {
|
||||
if (v) {
|
||||
this.instance.post('/app/appvillagerintegraldeclare/examine', null, {
|
||||
params: {
|
||||
...this.form,
|
||||
id: this.params.id,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.isShow = false
|
||||
this.getInfo(this.params.id)
|
||||
this.$message.success('审核成功!')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onChange(e) {
|
||||
this.form.auditRuleId = ''
|
||||
this.instance.post(`/app/appvillagerintegralrule/list?size=1000&classification=${e}`).then(res => {
|
||||
if (res?.code == 0) {
|
||||
this.ruleList = res.data.records.filter(v => v.ruleStatus === '1').map(v => {
|
||||
return {
|
||||
dictName: v.ruleName,
|
||||
dictValue: v.id,
|
||||
ruleName: v.ruleName,
|
||||
integral: v.integral
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel(isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.audit {
|
||||
.flex-warpper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
::v-deep .el-form-item .el-form-item__content {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
::v-deep .ai-select {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
::v-deep .el-form-item {
|
||||
width: auto;
|
||||
margin-bottom: 0;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
237
packages/conv/creditScore/AppIntegralAudit/components/List.vue
Normal file
237
packages/conv/creditScore/AppIntegralAudit/components/List.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<ai-list class="list">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="积分审核"
|
||||
v-if="search.areaId"
|
||||
isShowBottomBorder
|
||||
:instance="instance"
|
||||
:disabledLevel="disabledLevel"
|
||||
isShowArea
|
||||
v-model="search.areaId"
|
||||
@change="changeArea">
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<ai-select
|
||||
v-model="search.applyIntegralType"
|
||||
clearable
|
||||
placeholder="请选择积分类型"
|
||||
:selectList="dict.getDict('atWillReportType')"
|
||||
@change="search.current = 1, getList()">
|
||||
</ai-select>
|
||||
<ai-select
|
||||
v-model="search.auditStatus"
|
||||
clearable
|
||||
placeholder="请选择审核状态"
|
||||
:selectList="dict.getDict('auditStatus')"
|
||||
@change="search.current = 1, getList()">
|
||||
</ai-select>
|
||||
<el-date-picker
|
||||
value-format="yyyy-MM-dd"
|
||||
v-model="search.createTimeStart"
|
||||
type="date"
|
||||
size="small"
|
||||
unlink-panels
|
||||
placeholder="选择开始日期"
|
||||
@change="search.current = 1, getList()" />
|
||||
<el-date-picker
|
||||
value-format="yyyy-MM-dd"
|
||||
v-model="search.createTimeEnd"
|
||||
type="date"
|
||||
size="small"
|
||||
unlink-panels
|
||||
placeholder="选择结束日期"
|
||||
@change="search.current = 1, getList()" />
|
||||
</template>
|
||||
<template #right>
|
||||
<el-input
|
||||
v-model="search.residentName"
|
||||
size="small"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
@clear="search.current = 1, search.residentName = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
v-loading="loading"
|
||||
style="margin-top: 8px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="options" width="120px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
residentName: '',
|
||||
applyIntegralType: '',
|
||||
areaId: '',
|
||||
auditStatus: '',
|
||||
createTimeStart: '',
|
||||
createTimeEnd: ''
|
||||
},
|
||||
dictList: [{
|
||||
dictName: '否',
|
||||
dictValue: '0'
|
||||
}, {
|
||||
dictName: '是',
|
||||
dictValue: '1'
|
||||
}],
|
||||
info: {},
|
||||
colConfigs: [
|
||||
{ prop: 'residentName', label: '申请人' },
|
||||
{ prop: 'residentPhone', align: 'center', label: '联系电话' },
|
||||
{ prop: 'createTime', align: 'center', label: '申请时间' },
|
||||
{ prop: 'applyIntegralType', align: 'center', label: '积分类型', formart: v => this.dict.getLabel('atWillReportType', v) },
|
||||
{ prop: 'auditStatus', align: 'center', label: '状态', formart: v => v ? this.dict.getLabel('auditStatus', v) : '-' },
|
||||
{ prop: 'auditUserName', align: 'center', label: '审批人' },
|
||||
{ prop: 'auditTime', align: 'center', label: '审批时间' }
|
||||
],
|
||||
tableData: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
disabledLevel: 0
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
param () {
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.disabledLevel = this.user.info.areaList.length - 1
|
||||
this.search.areaId = this.user.info.areaId
|
||||
this.loading = true
|
||||
this.dict.load(['atWillReportType', 'auditStatus']).then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
this.instance.post(`/app/appvillagerintegraldeclare/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
this.loading = false
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id: id || ''
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
changeArea () {
|
||||
this.search.current = 1
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.list {
|
||||
::v-deep .ai-list__content {
|
||||
padding: 0!important;
|
||||
|
||||
.ai-list__content--right-wrapper {
|
||||
background: transparent!important;
|
||||
box-shadow: none!important;
|
||||
margin: 0!important;
|
||||
padding: 12px 16px 12px!important;
|
||||
}
|
||||
}
|
||||
.statistics-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
& > div {
|
||||
flex: 1;
|
||||
height: 96px;
|
||||
line-height: 1;
|
||||
margin-right: 20px;
|
||||
padding: 16px 24px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
border-radius: 4px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
color: #888888;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 16px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
76
packages/conv/creditScore/AppScoreManage/AppScoreManage.vue
Normal file
76
packages/conv/creditScore/AppScoreManage/AppScoreManage.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<ai-list>
|
||||
<template slot="title">
|
||||
<ai-title title="积分维护" :isShowBottomBorder="false" :instance="instance" :isShowArea="true" v-model="areaId"
|
||||
@change="changeArea"></ai-title>
|
||||
</template>
|
||||
<template slot="tabs">
|
||||
<el-tabs v-model="currIndex">
|
||||
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label">
|
||||
<component :is="tab.comp" v-if="currIndex === String(i)" :ref="tab.name"
|
||||
:areaId="areaId" :instance="instance" :dict="dict" :permissions="permissions"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pointsDeclaration from "./pointsDeclaration.vue"
|
||||
import pointsDetails from "./pointsDetails.vue"
|
||||
import pointsAppeal from './pointsAppeal'
|
||||
import {mapState} from 'vuex'
|
||||
import scoreChange from "./scoreChange";
|
||||
|
||||
export default {
|
||||
name: 'AppScoreManage',
|
||||
label: "积分维护",
|
||||
components: {pointsDeclaration, pointsDetails, pointsAppeal, scoreChange},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
tabs() {
|
||||
return [
|
||||
{
|
||||
label: "积分明细",
|
||||
name: "pointsDetails",
|
||||
comp: pointsDetails,
|
||||
permission: "app_apppartyfee_statistics",
|
||||
},
|
||||
{
|
||||
label: "积分调整",
|
||||
name: "scoreChange",
|
||||
comp: scoreChange,
|
||||
permission: "",
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.areaId = this.user.info.areaId
|
||||
this.dict.load("integralCalcType")
|
||||
},
|
||||
methods: {
|
||||
changeArea() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs[this.tabs[Number(this.currIndex)].name][0].getList()
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: "pointsDeclaration",
|
||||
currIndex: '0',
|
||||
areaId: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
611
packages/conv/creditScore/AppScoreManage/pointsAppeal.vue
Normal file
611
packages/conv/creditScore/AppScoreManage/pointsAppeal.vue
Normal file
@@ -0,0 +1,611 @@
|
||||
<template>
|
||||
<section class="pointsDeclaration">
|
||||
<ai-list isTabs>
|
||||
<template slot="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template slot="left">
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="onAdd" v-if="$permissions('app_appvillagerintegraldeclare_edit')">代申诉</el-button>
|
||||
<el-button icon="iconfont iconEdit" @click="batchAduit()" :disabled="!Boolean(selectionList.length)" v-if="$permissions('app_appvillagerintegraldeclare_edit')">批量审核</el-button>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="page.current = 1, getList()"
|
||||
placeholder="发布状态"
|
||||
:selectList="dict.getDict('integralDeclareStatus')">
|
||||
</ai-select>
|
||||
<div class="times_div">
|
||||
<p class="times">申诉时间</p>
|
||||
<el-date-picker
|
||||
v-model="search.declareTimeStart"
|
||||
type="date"
|
||||
size="small"
|
||||
@change="page.current = 1,getList()"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="开始日期">
|
||||
</el-date-picker>
|
||||
<el-date-picker
|
||||
v-model="search.declareTimeEnd"
|
||||
type="date"
|
||||
size="small"
|
||||
@change="page.current = 1,getList()"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.familyName"
|
||||
class="search-input"
|
||||
size="mini"
|
||||
placeholder="申诉人/申诉对象/..."
|
||||
clearable
|
||||
v-throttle="() => {page.current = 1, getList()}"
|
||||
@clear="page.current = 1, getList()"
|
||||
suffix-icon="iconfont iconSearch" />
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="page.total"
|
||||
:current.sync="page.current"
|
||||
:size.sync="page.size"
|
||||
@getList="getList"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column slot="selection" type="selection" width="55" :selectable="(row, index)=>{
|
||||
if(row.status==0){
|
||||
return true
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
}"></el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span
|
||||
class="iconfont iconEdit icon-color89B"
|
||||
v-if="row.status === '0'&&$permissions('app_appvillagerintegraldeclare_edit')"
|
||||
title="编辑"
|
||||
@click="toEdit(row)"
|
||||
></span>
|
||||
<span
|
||||
class="iconfont iconShow icon-color89B"
|
||||
v-if="row.status !== '0'&&$permissions('app_appvillagerintegraldeclare_detail')"
|
||||
title="详情"
|
||||
@click="toEdit(row)"
|
||||
></span>
|
||||
<!-- <span
|
||||
class="iconfont iconDelete icon-color89B"
|
||||
v-if="$permissions('app_appofficialdocumentinfo_del')"
|
||||
title="删除"
|
||||
@click="remove(row.id)"
|
||||
></span> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<ai-dialog
|
||||
title="积分代申诉"
|
||||
:visible.sync="dialog.visibleAdd"
|
||||
:customFooter="true"
|
||||
:destroyOnClose="true"
|
||||
width="720px"
|
||||
@close="init('ruleForm')"
|
||||
>
|
||||
<div class="form_div">
|
||||
<el-form
|
||||
ref="ruleForm"
|
||||
:model="dialogInfo"
|
||||
:rules="formRules"
|
||||
size="small"
|
||||
label-suffix=":"
|
||||
label-width="140px"
|
||||
>
|
||||
<el-form-item label="代申诉家庭" prop="users">
|
||||
<ai-person-select :customClicker="true" :isMultiple="true" :chooseUserList.sync="dialogInfo.users" :instance="instance" url="/app/appvillagerintegralfamilymember/list" >
|
||||
<template name="option" v-slot:option="{ item }">
|
||||
<span class="iconfont iconProlife">{{ item.name }}</span>
|
||||
<ai-id mode="show" :show-eyes="false" :value="item.idNumber" />
|
||||
</template>
|
||||
</ai-person-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="代申诉说明" prop="declareDescription">
|
||||
<el-input type="textarea" :rows="3" placeholder="请输入…" maxlength="100" show-word-limit v-model="dialogInfo.declareDescription"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="照片" prop="fileList">
|
||||
<div class="upload">
|
||||
<ai-uploader :instance="instance" v-model="dialogInfo.fileList" :limit="9" ></ai-uploader>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="dialog.visibleAdd=false" size="medium">取消</el-button>
|
||||
<el-button @click="declare('ruleForm')" type="primary" size="medium">提交</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
<ai-dialog
|
||||
title="申诉审核"
|
||||
:visible.sync="dialog.visibleDetail"
|
||||
:customFooter="true"
|
||||
:destroyOnClose="true"
|
||||
width="720px"
|
||||
@close="init('rules')"
|
||||
>
|
||||
<div class="form_content" v-if="!isBatch">
|
||||
<div class="form_flex form_info">
|
||||
<div>
|
||||
<span class="form_label">申诉人:</span>
|
||||
<span class="form_value">{{rowInfo.declareName}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="form_label">申诉对象:</span>
|
||||
<span class="form_value">{{rowInfo.declareObjName}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="form_label">户主:</span>
|
||||
<span class="form_value">{{rowInfo.familyName}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form_info">
|
||||
<span class="form_label">申诉说明:</span>
|
||||
<span class="form_value">{{rowInfo.declareDescription}}</span>
|
||||
</div>
|
||||
<div class="form_info">
|
||||
<span class="form_label">申诉时间:</span>
|
||||
<span class="form_value">{{rowInfo.declareTime}}</span>
|
||||
</div>
|
||||
<div class="form_info">
|
||||
<span class="form_label">照片:</span>
|
||||
<span class="form_value">
|
||||
<ai-uploader :disabled="true" :instance="instance" v-model="rowInfo.fileList" :limit="9" ></ai-uploader>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form_div">
|
||||
<el-form
|
||||
ref="rules"
|
||||
:model="dialogDetail"
|
||||
:rules="formRules"
|
||||
size="small"
|
||||
label-suffix=":"
|
||||
v-show="rowInfo.status==0"
|
||||
label-width="90px"
|
||||
>
|
||||
<el-form-item label="类型" prop="doType">
|
||||
<el-radio-group v-model="dialogDetail.doType" @change="changeDoType">
|
||||
<el-radio label="1">加分</el-radio>
|
||||
<el-radio label="0">扣分</el-radio>
|
||||
<el-radio label="2">拒绝</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="事项" prop="ruleId" v-if='dialogDetail.doType!=2'>
|
||||
<el-select v-model="dialogDetail.ruleId" placeholder="请选择..." @change="ruleChange">
|
||||
<el-option
|
||||
v-for="(item,i) in rulesList"
|
||||
:key="i"
|
||||
:label="item.ruleName"
|
||||
:value="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="积分" prop="doIntegral" v-if='dialogDetail.doType!=2'>
|
||||
<el-col :span="1.5" style="margin-right: 8px;">{{dialogDetail.doType==0? '减少' :'增加'}}</el-col>
|
||||
<el-col :span="6" style="margin-right: 8px;width:120px;"><el-input type="number" v-model="dialogDetail.doIntegral" :placeholder="placeholder" :disabled="integralEdit"></el-input></el-col>
|
||||
<el-col :span="1" style="margin-right: 8px;">分</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注说明">
|
||||
<el-input type="textarea" :rows="3" maxlength="100" placeholder="请输入…" show-word-limit v-model="dialogDetail.remark"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<ai-wrapper
|
||||
label-width="70px"
|
||||
v-if="rowInfo.status!=0"
|
||||
:columnsNumber="1">
|
||||
<ai-info-item label="类型:"><span :style="{color:colorList[rowInfo.status]}" >{{dict.getLabel('integralDeclareStatus', rowInfo.status)}}</span></ai-info-item>
|
||||
<ai-info-item label="事项:" v-if='rowInfo.doType!=2'><span >{{rowInfo.ruleName}}</span></ai-info-item>
|
||||
<ai-info-item label="积分:" v-if='rowInfo.doType!=2'>{{rowInfo.doType==0? '减少' :'增加'}}<span style="color:#2266FF">{{Math.abs(rowInfo.doIntegral)}}</span>分</ai-info-item>
|
||||
<ai-info-item label="备注说明:"><span>{{rowInfo.remark||'-'}}</span></ai-info-item>
|
||||
</ai-wrapper>
|
||||
</div>
|
||||
<div class="dialog-footer" slot="footer" v-if="rowInfo.status==0">
|
||||
<el-button @click="dialog.visibleDetail=false" size="medium">取消</el-button>
|
||||
<el-button @click="onConfirm('rules')" type="primary" size="medium">提交</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex';
|
||||
export default {
|
||||
name: "pointsAppeal",
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
bizType:String,
|
||||
areaId:String
|
||||
},
|
||||
|
||||
data() {
|
||||
var integral = (rule, value, callback) => {
|
||||
if (value) {
|
||||
if (/^[1-9]\d*$/.test(value)) {
|
||||
if(!this.integralEdit){
|
||||
if(Number(value)>=this.sectionNum.min&&Number(value)<=this.sectionNum.max){
|
||||
callback();
|
||||
}else{
|
||||
callback(new Error(`请输入${this.sectionNum.min}至${this.sectionNum.max}之间的正整数积分`));
|
||||
}
|
||||
}else{
|
||||
callback();
|
||||
}
|
||||
|
||||
} else {
|
||||
callback(new Error('请输入正整数'));
|
||||
}
|
||||
} else {
|
||||
callback(new Error('请输入正整数'));
|
||||
}
|
||||
};
|
||||
return {
|
||||
search: {
|
||||
status:'',
|
||||
familyName:'',
|
||||
declareTimeStart:null,
|
||||
declareTimeEnd:null
|
||||
},
|
||||
page:{
|
||||
current: 1,
|
||||
size: 10,
|
||||
total:0
|
||||
},
|
||||
colConfigs: [
|
||||
{ slot: "selection", label: "", align: "center" },
|
||||
{ prop: "declareName", label: "申诉人", align: "center" },
|
||||
{ prop: "declareObjName", label: "申诉对象", align: "center",hide:this.bizType==1 },
|
||||
{
|
||||
prop: "familyName",
|
||||
label: "户主",
|
||||
},
|
||||
{
|
||||
prop: "declareDescription",
|
||||
label: "申诉说明",
|
||||
align: "left",
|
||||
width:300
|
||||
},
|
||||
{
|
||||
prop: "declareTime",
|
||||
label: "申诉时间",
|
||||
align: "left",
|
||||
width:150
|
||||
},
|
||||
{
|
||||
prop: "declareName",
|
||||
label: "操作人",
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
prop: "status",
|
||||
label: "状态",
|
||||
align: "center",
|
||||
render: (h, {row}) => {
|
||||
return h('span', {style: {color: this.dict.getColor('integralDeclareStatus', row.status)}}, this.dict.getLabel('integralDeclareStatus', row.status))
|
||||
},
|
||||
},
|
||||
{ slot: "options", label: "操作", align: "center" },
|
||||
],
|
||||
tableData: [],
|
||||
dialog: {
|
||||
visibleAdd: false,
|
||||
visibleDetail: false,
|
||||
title:'积分代申诉'
|
||||
},
|
||||
dialogInfo: {
|
||||
users: [],
|
||||
reportIds:[],
|
||||
declareDescription: "",
|
||||
fileList: [],
|
||||
},
|
||||
dialogDetail: {
|
||||
doType: '1',
|
||||
ruleId: '',
|
||||
doIntegral: '',
|
||||
remark: '',
|
||||
aduitIds:[],
|
||||
ruleName:''
|
||||
},
|
||||
isBatch:false,
|
||||
rulesList:[],
|
||||
rowInfo:{},
|
||||
formRules: {
|
||||
users: [{ required: true, message: "请选择人员", trigger: "change" },],
|
||||
declareDescription: [{ required: true, message: "代申诉说明", trigger: "blur" }],
|
||||
// fileList: [{ required: true, message: "请上传照片", trigger: "blur" },],
|
||||
ruleId: [{ required: true, message: "请选择事项", trigger: "blur" }],
|
||||
doIntegral: [{ required: true, validator: integral, trigger: "blur" }],
|
||||
doType:[{ required: true, message: "请选择类型", trigger: "change" }]
|
||||
},
|
||||
selectionList:[],
|
||||
integralEdit:false,
|
||||
sectionNum:{
|
||||
min:null,
|
||||
max:null
|
||||
},
|
||||
placeholder:'请输入...'
|
||||
};
|
||||
},
|
||||
computed:{
|
||||
colorList(){
|
||||
return {
|
||||
'0':'#FF8822',
|
||||
'1':'#2EA222',
|
||||
'2':'#FF4466'
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.dict
|
||||
.load([
|
||||
'integralDeclareStatus',
|
||||
'integralDeclareDoType'
|
||||
]).then(() => {
|
||||
this.getList();
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appvillagerintegraldeclare/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
...this.page,
|
||||
bizType:this.bizType,
|
||||
areaId:this.areaId
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records;
|
||||
this.page.total = res.data.total;
|
||||
}
|
||||
});
|
||||
},
|
||||
handleSelectionChange(val){
|
||||
this.selectionList=val
|
||||
this.dialogDetail.aduitIds=[];
|
||||
val.forEach(e=>{
|
||||
this.dialogDetail.aduitIds.push(e.id);
|
||||
})
|
||||
},
|
||||
// getSelect(val){
|
||||
// for(let e of val){
|
||||
// this.dialogInfo.reportIds.push(e.id)
|
||||
// }
|
||||
// },
|
||||
getColor(status){
|
||||
return this.dict.getColor('integralDeclareStatus', status)
|
||||
},
|
||||
onChange(val){
|
||||
|
||||
},
|
||||
declare(formName){
|
||||
this.dialogInfo.reportIds=[];
|
||||
for(let e of this.dialogInfo.users){
|
||||
this.dialogInfo.reportIds.push(e.id)
|
||||
};
|
||||
this.$refs[formName].validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post("/app/appvillagerintegraldeclare/addOrUpdate", {
|
||||
...this.dialogInfo,
|
||||
bizType:this.bizType
|
||||
}, null).then(res => {
|
||||
if (res.code==0) {
|
||||
this.dialog.visibleAdd=false;
|
||||
this.getList();
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
init(formName){
|
||||
this.$refs[formName].clearValidate();
|
||||
this.dialogDetail = {
|
||||
doType: '1',
|
||||
ruleId: '',
|
||||
doIntegral: '',
|
||||
remark: '',
|
||||
aduitIds:[],
|
||||
ruleName:''
|
||||
}
|
||||
this.dialogInfo= {
|
||||
users: [],
|
||||
reportIds:[],
|
||||
declareDescription: "",
|
||||
fileList: [],
|
||||
};
|
||||
this.rulesList = [];
|
||||
},
|
||||
//批量审核
|
||||
batchAduit(){
|
||||
this.isBatch=true;
|
||||
this.rowInfo.status=0;
|
||||
this.dialog.visibleDetail = true;
|
||||
this.getRules('1')
|
||||
},
|
||||
getRowDetail(row){
|
||||
this.instance.post(`/app/appvillagerintegraldeclare/queryDetailById`, null, {
|
||||
params: {
|
||||
id:row.id
|
||||
},
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.rowInfo = {...res.data}
|
||||
this.dialog.visibleDetail = true;
|
||||
this.dialogDetail.aduitIds=[];
|
||||
this.dialogDetail.aduitIds.push(row.id);
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
toEdit(row) {
|
||||
this.isBatch=false;
|
||||
this.getRowDetail(row);
|
||||
this.getRules('1')
|
||||
},
|
||||
changeDoType(val){
|
||||
this.dialogDetail.ruleId="";
|
||||
this.dialogDetail.ruleName = "";
|
||||
this.dialogDetail.doIntegral = "";
|
||||
this.placeholder = '请输入...';
|
||||
this.$refs.rules.clearValidate();
|
||||
this.getRules(val)
|
||||
},
|
||||
ruleChange(val){
|
||||
let item = this.rulesList.find(e => e.id == val);
|
||||
this.dialogDetail.doIntegral='';
|
||||
this.$refs.rules.clearValidate();
|
||||
if(item){
|
||||
//固定区间
|
||||
this.dialogDetail.ruleName = item.ruleName;
|
||||
if(item.integralValueType==0){
|
||||
this.dialogDetail.doIntegral = Math.abs(item.integral);
|
||||
this.integralEdit = true;
|
||||
}else{
|
||||
this.integralEdit = false;
|
||||
if(Math.abs(item.integralEnd)>Math.abs(item.integralStart)){
|
||||
this.sectionNum.min = Math.abs(item.integralStart);
|
||||
this.sectionNum.max = Math.abs(item.integralEnd);
|
||||
}else{
|
||||
this.sectionNum.max = Math.abs(item.integralStart);
|
||||
this.sectionNum.min = Math.abs(item.integralEnd);
|
||||
}
|
||||
this.placeholder = `${this.sectionNum.min}~${this.sectionNum.max}`
|
||||
}
|
||||
}
|
||||
},
|
||||
//事项查询
|
||||
getRules(integralType){
|
||||
this.instance.post(`/app/appvillagerintegralrule/list`, null, {
|
||||
params: {
|
||||
integralType,
|
||||
size:10000000
|
||||
},
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.rulesList = res.data.records.filter(e=> e.ruleStatus == 1);
|
||||
}
|
||||
});
|
||||
},
|
||||
remove(id) {
|
||||
this.$confirm("确定删除该公文及其相关的流转信息?").then(() => {
|
||||
this.instance
|
||||
.post(`/app/appofficialdocumentinfo/delete?ids=${id}`)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success("删除成功!");
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
onReset() {
|
||||
Object.keys(this.search).forEach(e => {
|
||||
this.search[e] = "";
|
||||
});
|
||||
this.search.declareTimeStart = null;
|
||||
this.search.declareTimeEnd = null;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
onAdd() {
|
||||
this.dialog.visibleAdd = true;
|
||||
},
|
||||
|
||||
onConfirm(formName) {
|
||||
this.$refs[formName].validate(v =>{
|
||||
if(v){
|
||||
this.instance.post("/app/appvillagerintegraldeclare/aduit", {
|
||||
...this.dialogDetail,
|
||||
}, null).then(res => {
|
||||
if (res.code==0) {
|
||||
this.dialog.visibleDetail=false;
|
||||
this.$message.success("提交成功!");
|
||||
this.dialogDetail.aduitIds=[];
|
||||
this.getList();
|
||||
}
|
||||
})
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.pointsDeclaration {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background: #f3f6f9;
|
||||
.times_div{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.times{
|
||||
display: block;
|
||||
width: 72px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
background: #F5F5F5;
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
font-size: 14px;
|
||||
color:#666666;
|
||||
}
|
||||
}
|
||||
.form_content{
|
||||
border-bottom:1px solid #eee;
|
||||
.form_flex{
|
||||
display: flex;
|
||||
div{
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.form_info{
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.form_label{
|
||||
display: inline-block;
|
||||
color: #999;
|
||||
vertical-align: top;
|
||||
}
|
||||
.form_value{
|
||||
display: inline-block;
|
||||
color: #333;
|
||||
width: calc(100% - 80px);
|
||||
}
|
||||
}
|
||||
.form_div{
|
||||
padding-top:24px;
|
||||
}
|
||||
.status-0 {
|
||||
color: #ff8822;
|
||||
}
|
||||
|
||||
.status-1 {
|
||||
color: #2266ff;
|
||||
}
|
||||
|
||||
.status-2 {
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
603
packages/conv/creditScore/AppScoreManage/pointsDeclaration.vue
Normal file
603
packages/conv/creditScore/AppScoreManage/pointsDeclaration.vue
Normal file
@@ -0,0 +1,603 @@
|
||||
<template>
|
||||
<section class="pointsDeclaration">
|
||||
<ai-list isTabs>
|
||||
<template slot="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template slot="left">
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="onAdd" v-if="$permissions('app_appvillagerintegraldeclare_edit')">代申报</el-button>
|
||||
<el-button icon="iconfont iconEdit" @click="batchAduit()" :disabled="!Boolean(selectionList.length)"v-if="$permissions('app_appvillagerintegraldeclare_edit')">批量审核</el-button>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="page.current = 1, getList()"
|
||||
placeholder="发布状态"
|
||||
:selectList="dict.getDict('integralDeclareStatus')">
|
||||
</ai-select>
|
||||
<div class="times_div">
|
||||
<p class="times">申报时间</p>
|
||||
<el-date-picker
|
||||
v-model="search.declareTimeStart"
|
||||
type="date"
|
||||
size="small"
|
||||
@change="page.current = 1,getList()"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="开始日期">
|
||||
</el-date-picker>
|
||||
<el-date-picker
|
||||
v-model="search.declareTimeEnd"
|
||||
type="date"
|
||||
size="small"
|
||||
@change="page.current = 1,getList()"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.familyName"
|
||||
class="search-input"
|
||||
size="mini"
|
||||
placeholder="申诉人/申诉对象/..."
|
||||
clearable
|
||||
v-throttle="() => {page.current = 1, getList()}"
|
||||
@clear="page.current = 1, getList()"
|
||||
suffix-icon="iconfont iconSearch" />
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="page.total"
|
||||
:current.sync="page.current"
|
||||
:size.sync="page.size"
|
||||
@getList="getList"
|
||||
@selection-change="handleSelectionChange">
|
||||
<el-table-column slot="selection" type="selection" width="55" :selectable="(row, index)=>{
|
||||
if(row.status==0){
|
||||
return true
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
}"></el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button
|
||||
type="text"
|
||||
:disabled="row.status === '0' || $permissions('app_appvillagerintegraldeclare_edit')"
|
||||
title="编辑"
|
||||
@click="toEdit(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
:disabled="$permissions('app_appvillagerintegraldeclare_detail')"
|
||||
title="详情"
|
||||
@click="toEdit(row)">
|
||||
详情
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<ai-dialog
|
||||
title="积分代申报"
|
||||
:visible.sync="dialog.visibleAdd"
|
||||
:customFooter="true"
|
||||
:destroyOnClose="true"
|
||||
width="720px"
|
||||
@close="init('ruleForm')">
|
||||
<div class="form_div">
|
||||
<el-form
|
||||
ref="ruleForm"
|
||||
:model="dialogInfo"
|
||||
:rules="formRules"
|
||||
size="small"
|
||||
label-suffix=":"
|
||||
label-width="140px">
|
||||
<el-form-item label="代申报家庭" prop="users">
|
||||
<ai-person-select :customClicker="true" :isMultiple="true" :chooseUserList.sync="dialogInfo.users" :instance="instance" url="/app/appvillagerintegralfamilymember/list" >
|
||||
<template name="option" v-slot:option="{ item }">
|
||||
<span class="iconfont iconProlife">{{ item.name }}</span>
|
||||
<ai-id mode="show" :show-eyes="false" :value="item.idNumber" />
|
||||
</template>
|
||||
</ai-person-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="代申报说明" prop="declareDescription">
|
||||
<el-input type="textarea" :rows="3" placeholder="请输入…" maxlength="100" show-word-limit v-model="dialogInfo.declareDescription"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="照片" prop="fileList">
|
||||
<div class="upload">
|
||||
<ai-uploader :instance="instance" v-model="dialogInfo.fileList" :limit="9" ></ai-uploader>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="dialog.visibleAdd=false" size="medium">取消</el-button>
|
||||
<el-button @click="declare('ruleForm')" type="primary" size="medium">提交</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
<ai-dialog
|
||||
title="申报审核"
|
||||
:visible.sync="dialog.visibleDetail"
|
||||
:customFooter="true"
|
||||
:destroyOnClose="true"
|
||||
width="720px"
|
||||
@close="init('rules')">
|
||||
<div class="form_content" v-if="!isBatch">
|
||||
<div class="form_flex form_info">
|
||||
<div>
|
||||
<span class="form_label">申报人:</span>
|
||||
<span class="form_value">{{rowInfo.declareName}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="form_label">申报对象:</span>
|
||||
<span class="form_value">{{rowInfo.declareObjName}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="form_label">户主:</span>
|
||||
<span class="form_value">{{rowInfo.familyName}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form_info">
|
||||
<span class="form_label">申报说明:</span>
|
||||
<span class="form_value">{{rowInfo.declareDescription}}</span>
|
||||
</div>
|
||||
<div class="form_info">
|
||||
<span class="form_label">申报时间:</span>
|
||||
<span class="form_value">{{rowInfo.declareTime}}</span>
|
||||
</div>
|
||||
<div class="form_info">
|
||||
<span class="form_label">照片:</span>
|
||||
<span class="form_value">
|
||||
<ai-uploader :disabled="true" :instance="instance" v-model="rowInfo.fileList" :limit="9" ></ai-uploader>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form_div">
|
||||
<el-form
|
||||
ref="rules"
|
||||
:model="dialogDetail"
|
||||
:rules="formRules"
|
||||
size="small"
|
||||
label-suffix=":"
|
||||
v-show="rowInfo.status==0"
|
||||
label-width="90px"
|
||||
>
|
||||
<el-form-item label="类型" prop="doType">
|
||||
<el-radio-group v-model="dialogDetail.doType" @change="changeDoType">
|
||||
<el-radio label="1">加分</el-radio>
|
||||
<el-radio label="0">扣分</el-radio>
|
||||
<el-radio label="2">拒绝</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="事项" prop="ruleId" v-if='dialogDetail.doType!=2'>
|
||||
<el-select v-model="dialogDetail.ruleId" placeholder="请选择..." @change="ruleChange">
|
||||
<el-option
|
||||
v-for="(item,i) in rulesList"
|
||||
:key="i"
|
||||
:label="item.ruleName"
|
||||
:value="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="积分" prop="doIntegral" v-if='dialogDetail.doType!=2'>
|
||||
<el-col :span="1.5" style="margin-right: 8px;">{{dialogDetail.doType==0? '减少' :'增加'}}</el-col>
|
||||
<el-col :span="6" style="margin-right: 8px;width:120px;"><el-input type="number" v-model="dialogDetail.doIntegral" :placeholder="placeholder" :disabled="integralEdit"></el-input></el-col>
|
||||
<el-col :span="1" style="margin-right: 8px;">分</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注说明">
|
||||
<el-input type="textarea" :rows="3" maxlength="100" placeholder="请输入…" show-word-limit v-model="dialogDetail.remark"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<ai-wrapper
|
||||
label-width="70px"
|
||||
v-if="rowInfo.status!=0"
|
||||
:columnsNumber="1">
|
||||
<ai-info-item label="类型:"><span :style="{color:colorList[rowInfo.status]}" >{{dict.getLabel('integralDeclareStatus', rowInfo.status)}}</span></ai-info-item>
|
||||
<ai-info-item label="事项:" v-if='rowInfo.doType!=2'><span >{{rowInfo.ruleName}}</span></ai-info-item>
|
||||
<ai-info-item label="积分:" v-if='rowInfo.doType!=2'>{{rowInfo.doType==0? '减少' :'增加'}}<span style="color:#2266FF">{{Math.abs(rowInfo.doIntegral)}}</span>分</ai-info-item>
|
||||
<ai-info-item label="备注说明:"><span>{{rowInfo.remark||'-'}}</span></ai-info-item>
|
||||
</ai-wrapper>
|
||||
</div>
|
||||
<div class="dialog-footer" slot="footer" v-if="rowInfo.status==0">
|
||||
<el-button @click="dialog.visibleDetail=false" size="medium">取消</el-button>
|
||||
<el-button @click="onConfirm('rules')" type="primary" size="medium">提交</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex';
|
||||
export default {
|
||||
name: "pointsDeclaration",
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
bizType:String,
|
||||
areaId:String
|
||||
},
|
||||
|
||||
data() {
|
||||
var integral = (rule, value, callback) => {
|
||||
if (value) {
|
||||
if (/^[1-9]\d*$/.test(value)) {
|
||||
if(!this.integralEdit){
|
||||
if(Number(value)>=this.sectionNum.min&&Number(value)<=this.sectionNum.max){
|
||||
callback();
|
||||
}else{
|
||||
callback(new Error(`请输入${this.sectionNum.min}至${this.sectionNum.max}之间的正整数积分`));
|
||||
}
|
||||
}else{
|
||||
callback();
|
||||
}
|
||||
|
||||
} else {
|
||||
callback(new Error('请输入正整数'));
|
||||
}
|
||||
} else {
|
||||
callback(new Error('请输入正整数'));
|
||||
}
|
||||
};
|
||||
return {
|
||||
search: {
|
||||
status:'',
|
||||
familyName:'',
|
||||
declareTimeStart:null,
|
||||
declareTimeEnd:null
|
||||
},
|
||||
page:{
|
||||
current: 1,
|
||||
size: 10,
|
||||
total:0
|
||||
},
|
||||
colConfigs: [
|
||||
{ slot: "selection", label: "" },
|
||||
{ prop: "declareName", label: "申报人", align: "center" },
|
||||
{ prop: "declareObjName", label: "申报对象", align: "center",hide:this.bizType==1 },
|
||||
{
|
||||
prop: "familyName",
|
||||
label: "户主",
|
||||
},
|
||||
{
|
||||
prop: "declareDescription",
|
||||
label: "申诉说明",
|
||||
align: "left",
|
||||
width:300
|
||||
},
|
||||
{
|
||||
prop: "declareTime",
|
||||
label: "申报时间",
|
||||
align: "left",
|
||||
width:150
|
||||
},
|
||||
{
|
||||
prop: "declareName",
|
||||
label: "操作人",
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
prop: "status",
|
||||
label: "状态",
|
||||
align: "center",
|
||||
render: (h, {row}) => {
|
||||
return h('span', {style: {color: this.dict.getColor('integralDeclareStatus', row.status)}}, this.dict.getLabel('integralDeclareStatus', row.status))
|
||||
},
|
||||
},
|
||||
{ slot: "options", label: "操作", align: "center" },
|
||||
],
|
||||
tableData: [],
|
||||
dialog: {
|
||||
visibleAdd: false,
|
||||
visibleDetail: false,
|
||||
title:'积分代申报'
|
||||
},
|
||||
dialogInfo: {
|
||||
users: [],
|
||||
reportIds:[],
|
||||
declareDescription: "",
|
||||
fileList: [],
|
||||
},
|
||||
dialogDetail: {
|
||||
doType: '1',
|
||||
ruleId: '',
|
||||
doIntegral: '',
|
||||
remark: '',
|
||||
aduitIds:[],
|
||||
ruleName:''
|
||||
},
|
||||
isBatch:false,
|
||||
rulesList:[],
|
||||
rowInfo:{},
|
||||
formRules: {
|
||||
users: [{ required: true, message: "请选择人员", trigger: "change" },],
|
||||
declareDescription: [{ required: true, message: "代申报说明", trigger: "blur" }],
|
||||
// fileList: [{ required: true, message: "请上传照片", trigger: "blur" },],
|
||||
ruleId: [{ required: true, message: "请选择事项", trigger: "blur" }],
|
||||
doIntegral: [{ required: true, validator: integral, trigger: "blur" }],
|
||||
doType:[{ required: true, message: "请选择类型", trigger: "change" }]
|
||||
},
|
||||
selectionList:[],
|
||||
integralEdit:false,
|
||||
sectionNum:{
|
||||
min:null,
|
||||
max:null
|
||||
},
|
||||
placeholder:'请输入...'
|
||||
};
|
||||
},
|
||||
computed:{
|
||||
colorList(){
|
||||
return {
|
||||
'0':'#FF8822',
|
||||
'1':'#2EA222',
|
||||
'2':'#FF4466'
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.dict
|
||||
.load([
|
||||
'integralDeclareStatus',
|
||||
'integralDeclareDoType'
|
||||
]).then(() => {
|
||||
this.getList();
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appvillagerintegraldeclare/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
...this.page,
|
||||
bizType:this.bizType,
|
||||
areaId:this.areaId
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records;
|
||||
this.page.total = res.data.total;
|
||||
}
|
||||
});
|
||||
},
|
||||
handleSelectionChange(val){
|
||||
this.selectionList=val
|
||||
this.dialogDetail.aduitIds=[];
|
||||
val.forEach(e=>{
|
||||
this.dialogDetail.aduitIds.push(e.id);
|
||||
})
|
||||
},
|
||||
// getSelect(val){
|
||||
// for(let e of val){
|
||||
// this.dialogInfo.reportIds.push(e.id)
|
||||
// }
|
||||
// },
|
||||
getColor(status){
|
||||
return this.dict.getColor('integralDeclareStatus', status)
|
||||
},
|
||||
onChange(val){
|
||||
|
||||
},
|
||||
declare(formName){
|
||||
this.dialogInfo.reportIds=[];
|
||||
for(let e of this.dialogInfo.users){
|
||||
this.dialogInfo.reportIds.push(e.id)
|
||||
};
|
||||
this.$refs[formName].validate((valid) => {
|
||||
if (valid) {
|
||||
this.instance.post("/app/appvillagerintegraldeclare/addOrUpdate", {
|
||||
...this.dialogInfo,
|
||||
bizType:this.bizType
|
||||
}, null).then(res => {
|
||||
if (res.code==0) {
|
||||
this.dialog.visibleAdd=false;
|
||||
this.getList();
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
init(formName){
|
||||
this.$refs[formName].clearValidate();
|
||||
this.dialogDetail = {
|
||||
doType: '1',
|
||||
ruleId: '',
|
||||
doIntegral: '',
|
||||
remark: '',
|
||||
aduitIds:[],
|
||||
ruleName:''
|
||||
}
|
||||
this.dialogInfo= {
|
||||
users: [],
|
||||
reportIds:[],
|
||||
declareDescription: "",
|
||||
fileList: [],
|
||||
};
|
||||
this.rulesList = [];
|
||||
},
|
||||
//批量审核
|
||||
batchAduit(){
|
||||
this.isBatch=true;
|
||||
this.rowInfo.status=0;
|
||||
this.dialog.visibleDetail = true;
|
||||
this.getRules('1')
|
||||
},
|
||||
getRowDetail(row){
|
||||
this.instance.post(`/app/appvillagerintegraldeclare/queryDetailById`, null, {
|
||||
params: {
|
||||
id:row.id
|
||||
},
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.rowInfo = {...res.data}
|
||||
this.dialog.visibleDetail = true;
|
||||
this.dialogDetail.aduitIds=[];
|
||||
this.dialogDetail.aduitIds.push(row.id);
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
toEdit(row) {
|
||||
this.isBatch=false;
|
||||
this.getRowDetail(row);
|
||||
this.getRules('1')
|
||||
},
|
||||
changeDoType(val){
|
||||
this.dialogDetail.ruleId="";
|
||||
this.dialogDetail.ruleName = "";
|
||||
this.dialogDetail.doIntegral = "";
|
||||
this.placeholder = '请输入...';
|
||||
this.$refs.rules.clearValidate();
|
||||
this.getRules(val)
|
||||
},
|
||||
ruleChange(val){
|
||||
let item = this.rulesList.find(e => e.id == val);
|
||||
this.dialogDetail.doIntegral='';
|
||||
this.$refs.rules.clearValidate();
|
||||
if(item){
|
||||
//固定区间
|
||||
this.dialogDetail.ruleName = item.ruleName;
|
||||
if(item.integralValueType==0){
|
||||
this.dialogDetail.doIntegral = Math.abs(item.integral);
|
||||
this.integralEdit = true;
|
||||
}else{
|
||||
this.integralEdit = false;
|
||||
if(Math.abs(item.integralEnd)>Math.abs(item.integralStart)){
|
||||
this.sectionNum.min = Math.abs(item.integralStart);
|
||||
this.sectionNum.max = Math.abs(item.integralEnd);
|
||||
}else{
|
||||
this.sectionNum.max = Math.abs(item.integralStart);
|
||||
this.sectionNum.min = Math.abs(item.integralEnd);
|
||||
}
|
||||
this.placeholder = `${this.sectionNum.min}~${this.sectionNum.max}`
|
||||
}
|
||||
}
|
||||
},
|
||||
//事项查询
|
||||
getRules(integralType){
|
||||
this.instance.post(`/app/appvillagerintegralrule/list`, null, {
|
||||
params: {
|
||||
integralType,
|
||||
size:10000000
|
||||
},
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.rulesList = res.data.records.filter(e=> e.ruleStatus == 1);
|
||||
}
|
||||
});
|
||||
},
|
||||
remove(id) {
|
||||
this.$confirm("确定删除该公文及其相关的流转信息?").then(() => {
|
||||
this.instance
|
||||
.post(`/app/appofficialdocumentinfo/delete?ids=${id}`)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success("删除成功!");
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
onReset() {
|
||||
Object.keys(this.search).forEach(e => {
|
||||
this.search[e] = "";
|
||||
});
|
||||
this.search.declareTimeStart = null;
|
||||
this.search.declareTimeEnd = null;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
onAdd() {
|
||||
this.dialog.visibleAdd = true;
|
||||
},
|
||||
|
||||
onConfirm(formName) {
|
||||
this.$refs[formName].validate(v =>{
|
||||
if(v){
|
||||
this.instance.post("/app/appvillagerintegraldeclare/aduit", {
|
||||
...this.dialogDetail,
|
||||
}, null).then(res => {
|
||||
if (res.code==0) {
|
||||
this.dialog.visibleDetail=false;
|
||||
this.$message.success("提交成功!");
|
||||
this.dialogDetail.aduitIds=[];
|
||||
this.getList();
|
||||
}
|
||||
})
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.pointsDeclaration {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background: #f3f6f9;
|
||||
.times_div{
|
||||
.times{
|
||||
display: block;
|
||||
width: 72px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
background: #F5F5F5;
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
font-size: 14px;
|
||||
color:#666666;
|
||||
}
|
||||
}
|
||||
.form_content{
|
||||
border-bottom:1px solid #eee;
|
||||
.form_flex{
|
||||
display: flex;
|
||||
div{
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.form_info{
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.form_label{
|
||||
display: inline-block;
|
||||
color: #999;
|
||||
vertical-align: top;
|
||||
}
|
||||
.form_value{
|
||||
display: inline-block;
|
||||
color: #333;
|
||||
width: calc(100% - 80px);
|
||||
}
|
||||
}
|
||||
.form_div{
|
||||
padding-top:24px;
|
||||
}
|
||||
.status-0 {
|
||||
color: #ff8822;
|
||||
}
|
||||
|
||||
.status-1 {
|
||||
color: #2266ff;
|
||||
}
|
||||
|
||||
.status-2 {
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
219
packages/conv/creditScore/AppScoreManage/pointsDetails.vue
Normal file
219
packages/conv/creditScore/AppScoreManage/pointsDetails.vue
Normal file
@@ -0,0 +1,219 @@
|
||||
<template>
|
||||
<section class="pointsDetails">
|
||||
<ai-list isTabs>
|
||||
<template slot="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template slot="left">
|
||||
<el-date-picker size="small" v-model="searchDotime" type="daterange" range-separator="至" @change="timeChange"
|
||||
start-placeholder="开始日期" end-placeholder="结束日期" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd"></el-date-picker>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.familyName"
|
||||
class="search-input"
|
||||
size="small"
|
||||
placeholder="对象、户主、事件类型"
|
||||
clearable
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
@clear="search.current = 1, getList()"
|
||||
suffix-icon="iconfont iconSearch"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total" :dict="dict"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="changeIntegral" label="积分" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span>{{ row.integralCalcType == 1 ? '+' : '-' }}{{ row.changeIntegral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right" width="120">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button
|
||||
type="text"
|
||||
title="详情"
|
||||
:disabled="!$permissions('app_appvillagerintegraldetail_detail')"
|
||||
@click="viewItem(row)">
|
||||
详情
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<ai-dialog title="详情" :visible.sync="dialog" :customFooter="true" :destroyOnClose="true" width="720px">
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="户主:" :value="dialogInfo.familyName"/>
|
||||
<ai-info-item label="对象:" :value="dialogInfo.residentName"/>
|
||||
<ai-info-item label="事件:" :value="dialogInfo.eventDesc" isLine/>
|
||||
<ai-info-item label="时间:" :value="dialogInfo.doTime" isLine/>
|
||||
<ai-info-item label="积分:">
|
||||
{{ dialogInfo.changeIntegral >= 0 ? '增加' : '减少' }}
|
||||
<span style="color:#26f" v-text="Math.abs(dialogInfo.changeIntegral)"/>分
|
||||
</ai-info-item>
|
||||
<ai-info-item label="积分余额:" :value="dialogInfo.nowIntegral"/>
|
||||
</ai-wrapper>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="dialog=false">关闭</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "pointsDeclaration",
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
areaId: String
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
searchDotime: [],
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
familyName: '',
|
||||
doTimeStart: null,
|
||||
doTimeEnd: null
|
||||
},
|
||||
total: 10,
|
||||
colConfigs: [
|
||||
{prop: "residentName", label: "对象", width: 160},
|
||||
{prop: "familyName", label: "户主", align: "center", width: 160},
|
||||
{prop: "eventDesc", label: "事件", "show-overflow-tooltip": true, width: 420},
|
||||
{prop: "doTime", label: "时间", width: 200},
|
||||
{prop: "type", label: "类型", width: 100, dict: "integralDetailType"},
|
||||
{slot: "changeIntegral", label: "积分", width: 100},
|
||||
{slot: "options", label: "操作", align: "center"},
|
||||
],
|
||||
tableData: [],
|
||||
dialog: false,
|
||||
dialogInfo: {},
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$dict
|
||||
.load([
|
||||
"integralDeclareDoType",
|
||||
"integralDetailType",
|
||||
])
|
||||
.then(() => {
|
||||
this.getList();
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appvillagerintegraldetail/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
areaId: this.areaId,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records;
|
||||
this.total = res.data.total;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
timeChange() {
|
||||
if (this.searchDotime) {
|
||||
this.search.doTimeStart = this.searchDotime[0]
|
||||
this.search.doTimeEnd = this.searchDotime[1]
|
||||
} else {
|
||||
this.search.doTimeStart = null
|
||||
this.search.doTimeEnd = null
|
||||
}
|
||||
this.search.current = 1
|
||||
this.getList()
|
||||
},
|
||||
|
||||
viewItem(row) {
|
||||
this.dialog = true
|
||||
this.instance.post(`/app/appvillagerintegraldetail/queryDetailById?id=${row.id}`, null, {}).then((res) => {
|
||||
if (res?.data) {
|
||||
this.dialogInfo = res.data
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onReset() {
|
||||
this.search.current = 1
|
||||
this.search.doTimeStart = null
|
||||
this.search.doTimeEnd = null
|
||||
this.search.familyName = ''
|
||||
this.searchDotime = []
|
||||
this.getList();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.pointsDetails {
|
||||
height: 100%;
|
||||
background: #f3f6f9;
|
||||
overflow: auto;
|
||||
|
||||
.form_content {
|
||||
.form_flex {
|
||||
display: flex;
|
||||
|
||||
div {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.form_info {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.form_label {
|
||||
display: inline-block;
|
||||
color: #999;
|
||||
vertical-align: top;
|
||||
width: 70px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.form_value {
|
||||
display: inline-block;
|
||||
color: #333;
|
||||
width: calc(100% - 70px);
|
||||
// img {
|
||||
// width: 100px;
|
||||
// height: 100px;
|
||||
// margin: 0 8px 8px 0;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
.form_div {
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.status-0 {
|
||||
color: #FF4466;
|
||||
}
|
||||
|
||||
.status-1 {
|
||||
color: #2EA222;
|
||||
}
|
||||
|
||||
.status-2 {
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
147
packages/conv/creditScore/AppScoreManage/scoreChange.vue
Normal file
147
packages/conv/creditScore/AppScoreManage/scoreChange.vue
Normal file
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div class="scoreChange">
|
||||
<ai-list isTabs>
|
||||
<template slot="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template slot="left">
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="dialog=true"
|
||||
:disabled="!permissions('app_appvillagerintegraldetail_change')">添加
|
||||
</el-button>
|
||||
<ai-import :instance="instance" :dict="dict" name="积分调整" type="appvillagerintegraldetail"
|
||||
v-if="permissions('app_appvillagerintegraldetail_change')" @success="getList"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="page.total" :dict="dict"
|
||||
:current.sync="page.current"
|
||||
:size.sync="page.size"
|
||||
@getList="getList">
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<ai-dialog
|
||||
title="添加积分调整"
|
||||
:visible.sync="dialog"
|
||||
:destroyOnClose="true"
|
||||
width="720px"
|
||||
@onConfirm="onConfirm"
|
||||
@closed="form={}">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="选择人员" prop="residentId">
|
||||
<ai-person-select :instance="instance" :customClicker="true"
|
||||
:url="'/app/appresident/list?areaId=' + user.info.areaId"
|
||||
:isMultiple="false" dialogTitle="选择" @selectPerson="selectPerson">
|
||||
<template name="option" v-slot:option="{ item }">
|
||||
<span class="iconfont iconProlife">{{ item.name }}</span>
|
||||
<ai-id mode="show" :show-eyes="false" :value="item.idNumber"/>
|
||||
</template>
|
||||
</ai-person-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="调整说明" prop="eventDesc">
|
||||
<el-input v-model.trim="form.eventDesc" placeholder="请输入..." type="textarea" :rows="4" show-word-limit
|
||||
maxlength="100"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="integralCalcType">
|
||||
<ai-select v-model="form.integralCalcType" :selectList="dict.getDict('integralCalcType')"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="积分" prop="changeIntegral">
|
||||
<el-input v-model.trim.num="form.changeIntegral" placeholder="请输入正数" size="small"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="jsx">
|
||||
import {mapState} from "vuex"
|
||||
|
||||
export default {
|
||||
name: "scoreChange",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
areaId: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
page: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 10
|
||||
},
|
||||
form: {},
|
||||
dialog: false,
|
||||
personList: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(["user"]),
|
||||
rules() {
|
||||
return {
|
||||
residentId: [{required: true, message: '请选择人员', trigger: 'blur'},],
|
||||
eventDesc: [{required: true, message: '请输入调整说明', trigger: 'blur'},],
|
||||
integralCalcType: [{required: true, message: '请选择类型', trigger: 'change'},],
|
||||
changeIntegral: [{required: true, validator: (r, v, cb) => v > 0 ? cb() : cb("请输入正数")}],
|
||||
}
|
||||
},
|
||||
colConfigs() {
|
||||
return [
|
||||
{prop: "residentName", label: "姓名"},
|
||||
{prop: "eventDesc", label: "调整说明"},
|
||||
{prop: "integralCalcType", label: "类型", dict: "integralCalcType", align: 'center'},
|
||||
{prop: "changeIntegral", label: "积分", align: "center", render: (h, {row}) => h('p',{textAlign:'center'}, `${row.integralCalcType > 0 ? '+' : '-'}${row.changeIntegral}`)},
|
||||
{prop: "doTime", label: "操作时间"},
|
||||
{prop: "createUserName", label: "操作人", align: "center"},
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectPerson(val) {
|
||||
if (val) {
|
||||
this.form.residentId = val.id
|
||||
this.personList = [{...val}]
|
||||
} else {
|
||||
this.form.residentId = ""
|
||||
this.personList = []
|
||||
}
|
||||
},
|
||||
onConfirm() {
|
||||
this.$refs['form'].validate(valid => {
|
||||
if (valid) {
|
||||
this.instance.post(`/app/appvillagerintegraldetail/changeIntegral`, this.form).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success("添加成功")
|
||||
this.dialog = false
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
getList() {
|
||||
this.instance.post(`/app/appvillagerintegraldetail/list`, null, {
|
||||
params: {...this.page, areaId: this.areaId, type: 0}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.page.total = res.data.total
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.scoreChange {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
328
packages/conv/creditScore/scoreFamily/AppScoreFamily.vue
Normal file
328
packages/conv/creditScore/scoreFamily/AppScoreFamily.vue
Normal file
@@ -0,0 +1,328 @@
|
||||
<template>
|
||||
<section class="scoreFamily">
|
||||
<ai-list v-show="!detailShow">
|
||||
<template slot="title">
|
||||
<ai-title title="家庭积分" :isShowBottomBorder="true" :instance="instance" :isShowArea="true" @change="getList()" v-model="areaId"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template slot="left">
|
||||
<el-select size="small" v-model="searchObj.isPositive" placeholder="积分是否大于0" clearable @change="page.current = 1,getList()">
|
||||
<el-option
|
||||
v-for="(item,i) in isPositiveList"
|
||||
:key="i"
|
||||
:label="item.dictName"
|
||||
:value="item.dictValue">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="searchObj.con"
|
||||
size="small"
|
||||
placeholder="户主姓名"
|
||||
v-throttle="() => {page.current = 1, getList()}"
|
||||
@clear="page.current = 1, searchObj.con = '', getList()"
|
||||
clearable
|
||||
suffix-icon="iconfont iconSearch" />
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-search-bar class="mt10">
|
||||
<template slot="left">
|
||||
<ai-download :instance="instance" type="primary" url="/app/appvillagerintegraldetail/listExport" :params="params" fileName="家庭积分"></ai-download>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="page.total"
|
||||
ref="aitableex"
|
||||
:current.sync="page.current"
|
||||
:size.sync="page.size"
|
||||
@getList="getList">
|
||||
<el-table-column label="操作" slot="options" fixed="right" align="center" width="180">
|
||||
<template v-slot="{row}">
|
||||
<div class="table-options">
|
||||
<el-button type="text" title="家庭成员" @click="familyMember(row)" :disabled="!$permissions('app_appvillagerintegralfamilymember_edit')">家庭成员</el-button>
|
||||
<el-button type="text" :disabled="!$permissions('app_appvillagerintegralfamily_detail')" title="详情" @click="goDetail(row)">详情</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<detail v-if="detailShow" @goBack="goBack" :detailInfo='detailInfo' :instance='instance' :dict='dict'></detail>
|
||||
<ai-dialog class="family-list"
|
||||
title="成员列表"
|
||||
:visible.sync="addMemberVisible"
|
||||
:customFooter="true"
|
||||
:destroyOnClose="true"
|
||||
width="780px">
|
||||
<ai-table
|
||||
:tableData="familyList"
|
||||
:col-configs="familycolConfigs"
|
||||
:total="familyPage.total"
|
||||
:current.sync="familyPage.current"
|
||||
:size.sync="familyPage.size"
|
||||
:isShowPagination="false"
|
||||
@getList="familyMember(rowInfo)">
|
||||
<el-table-column label="与户主关系" slot="householdRelation" align="center" width="120">
|
||||
<template v-slot="{row}">
|
||||
<span v-if="row.householdName == 1">户主</span>
|
||||
<span v-else>{{dict.getLabel('householdRelation', row.householdRelation)}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" slot="personType" align="center" width="120">
|
||||
<template v-slot="{row}">户籍居民</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="身份证号" slot="idNumber" align="center" width="165">
|
||||
<template v-slot="{row}">
|
||||
<ai-id mode="show" :show-eyes="false" :value="row.idNumber"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="addMemberVisible=false" size="medium">关 闭</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex';
|
||||
import detail from './detail'
|
||||
|
||||
export default {
|
||||
name: 'AppScoreFamily',
|
||||
label: "家庭积分",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
components: {detail},
|
||||
data() {
|
||||
return {
|
||||
areaId: '',
|
||||
searchObj: {
|
||||
personType: '',
|
||||
villageGroup: '',
|
||||
status: '',
|
||||
con: '',
|
||||
isPositive: '',
|
||||
},
|
||||
isPositiveList: [{
|
||||
dictName: '是',
|
||||
dictValue: '1'
|
||||
}, {
|
||||
dictName: '否',
|
||||
dictValue: '0'
|
||||
}],
|
||||
page: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
},
|
||||
familyPage: {
|
||||
current: 1,
|
||||
size: 100,
|
||||
total: 0
|
||||
},
|
||||
exportParams: {},
|
||||
tableData: [],
|
||||
dialog: {
|
||||
title: '添加家庭',
|
||||
visible: false
|
||||
},
|
||||
dialogInfo: {
|
||||
personType: '0',
|
||||
name: '',
|
||||
idNumber: '',
|
||||
phone: '',
|
||||
villageGroup: '',
|
||||
status: '',
|
||||
areaId: '',
|
||||
householdRelation: '',
|
||||
avatar: ''
|
||||
},
|
||||
addMemberVisible: false,
|
||||
detailShow: false,
|
||||
personUrl: '',
|
||||
familyList: [],
|
||||
familyId: '',
|
||||
detailInfo: {},
|
||||
rowInfo: {}
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
params () {
|
||||
return {
|
||||
...this.searchObj,
|
||||
areaId: this.areaId,
|
||||
exportType: 0
|
||||
}
|
||||
},
|
||||
colConfigs() {
|
||||
return [
|
||||
{
|
||||
prop: 'name',
|
||||
label: '户主',
|
||||
},
|
||||
{
|
||||
prop: 'phone',
|
||||
align: 'center',
|
||||
label: '联系电话',
|
||||
},
|
||||
{
|
||||
prop: 'householdAreaName',
|
||||
align: 'center',
|
||||
label: '所在村',
|
||||
},
|
||||
{
|
||||
prop: 'familyIntegral',
|
||||
align: 'center',
|
||||
label: '家庭积分',
|
||||
},
|
||||
{
|
||||
prop: 'familyUsedIntegral',
|
||||
align: 'center',
|
||||
label: '已用积分',
|
||||
},
|
||||
{
|
||||
prop: 'familySurplusIntegral',
|
||||
align: 'center',
|
||||
label: '剩余积分',
|
||||
},
|
||||
{
|
||||
prop: 'familyNum',
|
||||
align: 'center',
|
||||
label: '成员数',
|
||||
},
|
||||
]
|
||||
},
|
||||
familycolConfigs() {
|
||||
return [
|
||||
// {
|
||||
// prop: 'householdRelation',
|
||||
// align: 'center',
|
||||
// label: '与户主关系',
|
||||
// render(h, {row}) {
|
||||
// return h('span', {}, _.$dict.getLabel('householdRelation', row.householdRelation))
|
||||
// }
|
||||
// },
|
||||
{
|
||||
slot: 'householdRelation',
|
||||
},
|
||||
{
|
||||
prop: 'residentType',
|
||||
align: 'center',
|
||||
label: '类型',
|
||||
formart: v => this.dict.getLabel('residentType', v)
|
||||
},
|
||||
{
|
||||
prop: 'name',
|
||||
align: 'center',
|
||||
label: '姓名',
|
||||
},
|
||||
{
|
||||
prop: 'idNumber',
|
||||
align: 'center',
|
||||
slot: 'idNumber',
|
||||
label: '身份证号',
|
||||
width: 165,
|
||||
},
|
||||
{
|
||||
prop: 'phone',
|
||||
align: 'center',
|
||||
label: '联系电话',
|
||||
width: 120,
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.areaId = this.user.info.areaId;
|
||||
this.dict.load('integralVillageGroup', 'integralRuleStatus', 'householdRelation', 'residentType');
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post("/app/appresident/familyIntegral", null, {
|
||||
params: {
|
||||
...this.searchObj,
|
||||
...this.page,
|
||||
areaId: this.areaId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.page.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
familyMember(row) {
|
||||
this.rowInfo = {...row}
|
||||
this.familyId = row.id;
|
||||
this.instance.post(`/app/appresident/detail?id=${row.id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.familyList = res.data.family;
|
||||
this.familyPage.total = res.data.family.length;
|
||||
this.addMemberVisible = true;
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
goBack() {
|
||||
this.detailShow = false;
|
||||
},
|
||||
goDetail(row) {
|
||||
this.detailInfo = {...row};
|
||||
this.detailShow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.scoreFamily {
|
||||
height: 100%;
|
||||
background: #f3f6f9;
|
||||
overflow: auto;
|
||||
|
||||
.form_div {
|
||||
width: 380px;
|
||||
}
|
||||
|
||||
.add_btn {
|
||||
color: #5088FF;
|
||||
font-size: 14px;
|
||||
line-height: 36px;
|
||||
text-align: right;
|
||||
|
||||
span {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span:nth-child(2) {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.iconAll_Profile {
|
||||
padding: 0 8px;
|
||||
}
|
||||
.family-list{
|
||||
::v-deep .el-table--small{
|
||||
font-size: 14px!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
144
packages/conv/creditScore/scoreFamily/detail.vue
Normal file
144
packages/conv/creditScore/scoreFamily/detail.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<ai-detail class="family_detail">
|
||||
<template slot="title">
|
||||
<ai-title title="余额明细" :isShowBack="true" :isShowBottomBorder="true" @onBackClick="$emit('goBack')"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<div class="detail-info">
|
||||
<div class="detail-info__item">
|
||||
<h2>户主</h2>
|
||||
<span>{{ detailInfo.name }}</span>
|
||||
</div>
|
||||
<div class="detail-info__item">
|
||||
<h2>累计积分</h2>
|
||||
<span style="color: #2266FF;">{{ detailInfo.familyIntegral || 0 }}</span>
|
||||
</div>
|
||||
<div class="detail-info__item">
|
||||
<h2>剩余积分</h2>
|
||||
<span style="color: #2266FF;">{{ detailInfo.familySurplusIntegral || 0 }}</span>
|
||||
</div>
|
||||
<div class="detail-info__item">
|
||||
<h2>已消费</h2>
|
||||
<span>{{ detailInfo.familyUsedIntegral || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<ai-card title="余额变动明细">
|
||||
<template slot="right">
|
||||
<ai-download
|
||||
:instance="instance"
|
||||
url="/app/appvillagerintegraldetail/export"
|
||||
:disabled="!Boolean(tableData.length)"
|
||||
:params="{familyId:detailInfo.id,type}"
|
||||
fileName="余额变动明细">
|
||||
<el-button type="text" icon="iconfont iconExported">导出</el-button>
|
||||
</ai-download>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<ai-select v-model="type" placeholder="请选择类型" @change="page.current=1,getList()"
|
||||
:selectList="dict.getDict('integralDetailType')"/>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :col-configs="colConfigs"
|
||||
:total="page.total" border :dict="dict" :current.sync="page.current" :size.sync="page.size" @getList="getList"/>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'balance',
|
||||
props: {
|
||||
detailInfo: {
|
||||
type: Object,
|
||||
require: true
|
||||
},
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
page: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
},
|
||||
type: "",
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.dict.load('integralDetailType')
|
||||
this.getList()
|
||||
},
|
||||
computed: {
|
||||
colConfigs() {
|
||||
return [
|
||||
{prop: 'doTime', label: '时间', width: 200},
|
||||
{prop: "type", label: "类型", dict: "integralDetailType", align: 'center'},
|
||||
{prop: 'changeIntegral', align: 'center', label: '变动积分', render: (h, {row}) => h('p', `${row.integralCalcType == 1 ? '+' : '-'}${row.changeIntegral}`)},
|
||||
{prop: 'nowIntegral', align: 'center', label: '剩余积分'},
|
||||
{prop: 'eventDesc', label: '事件', width: 500}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post('/app/appvillagerintegraldetail/list', null, {
|
||||
params: {...this.page, familyId: this.detailInfo.id, type: this.type}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.page.total = res.data.total
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.family_detail {
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
|
||||
.detail-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.detail-info__item {
|
||||
flex: 1;
|
||||
height: 96px;
|
||||
margin-right: 20px;
|
||||
padding: 16px 24px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
border-radius: 4px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 8px;
|
||||
color: #888888;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
408
packages/conv/creditScore/scorePersonal/AppScorePersonal.vue
Normal file
408
packages/conv/creditScore/scorePersonal/AppScorePersonal.vue
Normal file
@@ -0,0 +1,408 @@
|
||||
<template>
|
||||
<section class="scoreFamily">
|
||||
<ai-list v-show="!detailShow">
|
||||
<template slot="title">
|
||||
<ai-title title="个人积分" :isShowBottomBorder="true" :instance="instance" :isShowArea="true" @change="getList()" v-model="areaId"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template slot="left">
|
||||
<el-select size="small" v-model="searchObj.householdName" placeholder="是否户主" clearable @change="page.current = 1,getList()">
|
||||
<el-option
|
||||
v-for="(item,i) in householdNameList"
|
||||
:key="i"
|
||||
:label="item.dictName"
|
||||
:value="item.dictValue">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-select size="small" v-model="searchObj.isPositive" placeholder="积分是否大于0" clearable @change="page.current = 1,getList()">
|
||||
<el-option
|
||||
v-for="(item,i) in isPositiveList"
|
||||
:key="i"
|
||||
:label="item.dictName"
|
||||
:value="item.dictValue">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="searchObj.con"
|
||||
size="small"
|
||||
placeholder="个人姓名"
|
||||
v-throttle="() => {page.current = 1, getList()}"
|
||||
@clear="page.current = 1, searchObj.con = '', getList()"
|
||||
clearable
|
||||
suffix-icon="iconfont iconSearch" />
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-search-bar class="mt10">
|
||||
<template slot="left">
|
||||
<ai-download :instance="instance" type="primary" url="/app/appvillagerintegraldetail/listExport?exportType=1" :params="params" fileName="个人积分"></ai-download>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="page.total"
|
||||
style="margin-top: 12px;"
|
||||
:current.sync="page.current"
|
||||
:size.sync="page.size"
|
||||
@getList="getList">
|
||||
<el-table-column label="操作" slot="options" fixed="right" align="center" width="180">
|
||||
<template v-slot="{row}">
|
||||
<div class="table-options">
|
||||
<el-button type="text" title="家庭成员" @click="familyMember(row)" :disabled="!$permissions('app_appvillagerintegralfamilymember_edit')">家庭成员</el-button>
|
||||
<el-button type="text" :disabled="!$permissions('app_appvillagerintegralfamily_detail')" title="详情" @click="goDetail(row)">详情</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<detail v-if="detailShow" @goBack="goBack" :detailInfo='detailInfo' :instance='instance' :dict='dict'></detail>
|
||||
<ai-dialog class="family-list"
|
||||
title="成员列表"
|
||||
:visible.sync="addMemberVisible"
|
||||
:customFooter="true"
|
||||
:destroyOnClose="true"
|
||||
width="780px">
|
||||
<ai-table
|
||||
:tableData="familyList"
|
||||
:col-configs="familycolConfigs"
|
||||
:total="familyPage.total"
|
||||
:current.sync="familyPage.current"
|
||||
:size.sync="familyPage.size"
|
||||
:isShowPagination="false"
|
||||
tableSize="small"
|
||||
@getList="familyMember(rowInfo)">
|
||||
<el-table-column label="与户主关系" slot="householdRelation" align="center" width="120">
|
||||
<template v-slot="{row}">
|
||||
<span v-if="row.householdIdNumber == row.idNumber">户主</span>
|
||||
<span v-else>{{dict.getLabel('householdRelation', row.householdRelation)}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="身份证号" slot="idNumber" align="center" width="165">
|
||||
<template v-slot="{row}">
|
||||
<ai-id mode="show" :show-eyes="false" :value="row.idNumber"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="addMemberVisible=false" size="medium">关 闭</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex';
|
||||
import detail from './detail'
|
||||
|
||||
export default {
|
||||
name: 'AppScorePersonal',
|
||||
label: "个人积分",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
components: {detail},
|
||||
data() {
|
||||
return {
|
||||
areaId: '',
|
||||
searchObj: {
|
||||
householdName: '',
|
||||
con: '',
|
||||
isPositive: ''
|
||||
},
|
||||
householdNameList: [{
|
||||
dictName: '是',
|
||||
dictValue: '1'
|
||||
}, {
|
||||
dictName: '否',
|
||||
dictValue: '0'
|
||||
}],
|
||||
isPositiveList: [{
|
||||
dictName: '是',
|
||||
dictValue: '1'
|
||||
}, {
|
||||
dictName: '否',
|
||||
dictValue: '0'
|
||||
}],
|
||||
page: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
},
|
||||
familyPage: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
},
|
||||
exportParams: {},
|
||||
tableData: [],
|
||||
dialog: {
|
||||
title: '添加家庭',
|
||||
visible: false
|
||||
},
|
||||
dialogInfo: {
|
||||
personType: '0',
|
||||
name: '',
|
||||
idNumber: '',
|
||||
phone: '',
|
||||
villageGroup: '',
|
||||
status: '',
|
||||
areaId: '',
|
||||
householdRelation: '',
|
||||
avatar: ''
|
||||
},
|
||||
addMemberVisible: false,
|
||||
detailShow: false,
|
||||
personUrl: '',
|
||||
familyList: [],
|
||||
familyId: '',
|
||||
detailInfo: {},
|
||||
rowInfo: {}
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
params () {
|
||||
return {
|
||||
...this.searchObj,
|
||||
areaId: this.areaId,
|
||||
exportType: 1
|
||||
}
|
||||
},
|
||||
colConfigs() {
|
||||
return [
|
||||
{
|
||||
prop: 'name',
|
||||
label: '姓名',
|
||||
},
|
||||
{
|
||||
prop: 'phone',
|
||||
align: 'center',
|
||||
label: '联系电话',
|
||||
},
|
||||
{
|
||||
prop: 'residentType',
|
||||
align: 'center',
|
||||
label: '类型',
|
||||
formart: v => this.dict.getLabel('residentType', v)
|
||||
},
|
||||
{
|
||||
prop: 'householdAreaName',
|
||||
align: 'center',
|
||||
label: '所在村'
|
||||
},
|
||||
{
|
||||
prop: 'personalIntegral',
|
||||
align: 'center',
|
||||
label: '个人积分',
|
||||
},
|
||||
{
|
||||
prop: 'personalUsedIntegral',
|
||||
align: 'center',
|
||||
label: '已用积分',
|
||||
},
|
||||
{
|
||||
prop: 'householdName',
|
||||
align: 'center',
|
||||
label: '是否户主',
|
||||
formart: v => v === '1' ? '是' : '否'
|
||||
}
|
||||
]
|
||||
},
|
||||
familycolConfigs() {
|
||||
return [
|
||||
{
|
||||
prop: 'householdRelation',
|
||||
align: 'center',
|
||||
slot: 'householdRelation',
|
||||
label: '与户主关系',
|
||||
width: 165,
|
||||
},
|
||||
|
||||
// {
|
||||
// prop: 'householdRelation',
|
||||
// align: 'center',
|
||||
// label: '与户主关系',
|
||||
// render(h, {row}) {
|
||||
// return h('span', {}, _.$dict.getLabel('householdRelation', row.householdRelation))
|
||||
// }
|
||||
// },
|
||||
{
|
||||
prop: 'residentType',
|
||||
align: 'center',
|
||||
label: '类型',
|
||||
formart: v => this.dict.getLabel('residentType', v)
|
||||
},
|
||||
{
|
||||
prop: 'name',
|
||||
align: 'center',
|
||||
label: '姓名',
|
||||
},
|
||||
{
|
||||
prop: 'idNumber',
|
||||
align: 'center',
|
||||
slot: 'idNumber',
|
||||
label: '身份证号',
|
||||
width: 165,
|
||||
},
|
||||
{
|
||||
prop: 'phone',
|
||||
align: 'center',
|
||||
label: '联系电话',
|
||||
width: 120,
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
formRules() {
|
||||
let IdNumberPass = (rule, value, callback) => {
|
||||
if (value) {
|
||||
console.log(this.idCardNoUtil);
|
||||
if (this.idCardNoUtil.checkIdCardNo(value)) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("身份证号格式错误"));
|
||||
}
|
||||
} else {
|
||||
callback(new Error("请输入身份证号"));
|
||||
}
|
||||
};
|
||||
if (this.dialog.title.indexOf('家庭') != -1) {
|
||||
|
||||
return {
|
||||
personType: [{required: true, message: "请选择类型", trigger: 'change'}],
|
||||
name: [{required: true, message: "请填写户主", trigger: 'change'}],
|
||||
idNumber: [{required: true, validator: IdNumberPass, trigger: 'change'}],
|
||||
phone: [{required: true, message: "请填写联系电话", trigger: 'blur'}],
|
||||
villageGroup: [{required: true, message: "请选择所属组", trigger: 'change'}],
|
||||
status: [{required: true, message: "请选择状态", trigger: 'change'}],
|
||||
householdRelation: [{required: true, message: "请选择与户主关系", trigger: 'change'}]
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
personType: [{required: true, message: "请选择类型", trigger: 'change'}],
|
||||
name: [{required: true, message: "请填写户主", trigger: 'change'}],
|
||||
idNumber: [{required: true, validator: IdNumberPass, trigger: 'change'}],
|
||||
villageGroup: [{required: true, message: "请选择所属组", trigger: 'change'}],
|
||||
status: [{required: true, message: "请选择状态", trigger: 'change'}],
|
||||
householdRelation: [{required: true, message: "请选择与户主关系", trigger: 'change'}]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.areaId = this.user.info.areaId;
|
||||
this.dict.load( 'integralRuleStatus', 'householdRelation', 'residentType');
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post("/app/appresident/personalIntegral", null, {
|
||||
params: {
|
||||
...this.searchObj,
|
||||
...this.page,
|
||||
areaId: this.areaId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records.map(v => {
|
||||
return v
|
||||
})
|
||||
this.page.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
typeChange(val) {
|
||||
val == '0' ? this.personUrl = '/app/appresident/list?fileStatus=0' : this.personUrl = '/app/apprecurrentpopulation/list?fileStatus=0';
|
||||
this.dialogInfo.name = "";
|
||||
this.dialogInfo.idNumber = "";
|
||||
this.dialogInfo.phone = "";
|
||||
this.dialogInfo.avatar = "";
|
||||
this.dialogInfo.areaId = "";
|
||||
},
|
||||
add() {
|
||||
this.dialog.visible = true;
|
||||
this.dialog.title = '添加家庭';
|
||||
},
|
||||
addFamily() {
|
||||
this.dialog.visible = true;
|
||||
this.dialog.title = '添加成员';
|
||||
},
|
||||
|
||||
init(formName) {
|
||||
this.$refs[formName].clearValidate();
|
||||
Object.keys(this.dialogInfo).forEach(e => {
|
||||
this.dialogInfo[e] = ''
|
||||
})
|
||||
this.dialogInfo.personType = '0';
|
||||
this.personUrl = '';
|
||||
},
|
||||
|
||||
familyMember (row) {
|
||||
this.instance.post(`/app/appresident/detail?id=${row.id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.familyList = res.data.family
|
||||
this.familyPage.total = res.data.family.length
|
||||
this.addMemberVisible = true
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
goBack() {
|
||||
this.detailShow = false;
|
||||
},
|
||||
|
||||
goDetail(row) {
|
||||
this.detailInfo = {...row};
|
||||
this.detailShow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.scoreFamily {
|
||||
height: 100%;
|
||||
background: #f3f6f9;
|
||||
overflow: auto;
|
||||
|
||||
.form_div {
|
||||
width: 380px;
|
||||
}
|
||||
|
||||
.add_btn {
|
||||
color: #5088FF;
|
||||
font-size: 14px;
|
||||
line-height: 36px;
|
||||
text-align: right;
|
||||
|
||||
span {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span:nth-child(2) {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.iconAll_Profile {
|
||||
padding: 0 8px;
|
||||
}
|
||||
.family-list{
|
||||
::v-deep .el-table--small{
|
||||
font-size: 14px!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
168
packages/conv/creditScore/scorePersonal/detail.vue
Normal file
168
packages/conv/creditScore/scorePersonal/detail.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<ai-detail class="family_detail">
|
||||
<template slot="title">
|
||||
<ai-title title="个人积分明细" :isShowBack="true" :isShowBottomBorder="true" @onBackClick="$emit('goBack')"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<div class="detail-info">
|
||||
<div class="detail-info__item">
|
||||
<h2>姓名</h2>
|
||||
<span>{{ info.name }}</span>
|
||||
</div>
|
||||
<div class="detail-info__item">
|
||||
<h2>个人积分</h2>
|
||||
<span style="color: #2266FF;">{{ info.personalIntegral || 0 }}</span>
|
||||
</div>
|
||||
<div class="detail-info__item">
|
||||
<h2>已用积分</h2>
|
||||
<span style="color: #2266FF;">{{ info.personalUsedIntegral || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<ai-card title="余额变动明细">
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<ai-select v-model="type" placeholder="请选择类型" @change="page.current=1,getList()" :selectList="dict.getDict('integralDetailType')"/>
|
||||
</template>
|
||||
<template #right>
|
||||
<ai-download
|
||||
:instance="instance"
|
||||
url="/app/appvillagerintegraldetail/export"
|
||||
:disabled="!Boolean(tableData.length)"
|
||||
:params="{residentId:detailInfo.id,type}"
|
||||
fileName="余额变动明细">
|
||||
<el-button type="text" icon="iconfont iconExported">导出</el-button>
|
||||
</ai-download>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :col-configs="colConfigs"
|
||||
:total="page.total" border :dict="dict" :current.sync="page.current" :size.sync="page.size" @getList="getList"/>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'balance',
|
||||
|
||||
props: {
|
||||
detailInfo: {
|
||||
type: Object,
|
||||
require: true
|
||||
},
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
page: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
},
|
||||
info: {},
|
||||
type: '',
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.dict.load('integralDetailType')
|
||||
this.getList()
|
||||
},
|
||||
computed: {
|
||||
colConfigs() {
|
||||
return [
|
||||
{prop: 'doTime', label: '时间', width: 200},
|
||||
{prop: "type", label: "类型", dict: "integralDetailType", align: 'center'},
|
||||
{prop: 'changeIntegral', align: 'center', label: '变动积分', render: (h, {row}) => h('p', `${row.integralCalcType == 1 ? '+' : '-'}${row.changeIntegral}`)},
|
||||
{prop: 'nowIntegral', align: 'center', label: '剩余积分'},
|
||||
{prop: 'eventDesc', label: '事件', width: 500}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appresident/detail?id=${this.detailInfo.id}`).then(res => {
|
||||
if (res?.data) {
|
||||
this.info = res.data.resident
|
||||
let {type, info: {id: residentId}} = this
|
||||
this.instance.post(`/app/appvillagerintegraldetail/IntegralList`, null, {
|
||||
params: {...this.page, queryType: 1, type, residentId}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.page.total = res.data.total
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.family_detail {
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
|
||||
.detail-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.detail-info__item {
|
||||
flex: 1;
|
||||
height: 96px;
|
||||
margin-right: 20px;
|
||||
padding: 16px 24px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
border-radius: 4px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 8px;
|
||||
color: #888888;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.iconExported {
|
||||
color: #5088FF;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.info {
|
||||
padding: 16px 0 16px 0;
|
||||
}
|
||||
|
||||
.do_type {
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.fs-14 {
|
||||
::v-deep .el-table--small {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
303
packages/conv/creditScore/scoreRules/AppScoreRules.vue
Normal file
303
packages/conv/creditScore/scoreRules/AppScoreRules.vue
Normal file
@@ -0,0 +1,303 @@
|
||||
<template>
|
||||
<section class="AppScoreRules">
|
||||
<ai-list v-if="permissions('app_appvillagerintegralrule_detail')">
|
||||
<template slot="title">
|
||||
<ai-title title="积分规则" isShowBottomBorder></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar bottomBorder>
|
||||
<template slot="left">
|
||||
<el-cascader size="small" v-model="search.eventType" placeholder="请选择事件/类型" clearable
|
||||
:props="{...etOps,checkStrictly:true}" @change="handleTypeSearch" ref="eventTypeSearch"/>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="page.current = 1, getList()"
|
||||
placeholder="请选择状态"
|
||||
:selectList="dict.getDict('integralRuleStatus')">
|
||||
</ai-select>
|
||||
</template>
|
||||
<template slot="right">
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-search-bar style="margin-top: 16px;">
|
||||
<template #left>
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="dialog=true">添加</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="page.total" :dict="dict"
|
||||
:current.sync="page.current"
|
||||
:size.sync="page.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="integral" label="分值" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span
|
||||
v-if="row.integralValueType == 1">
|
||||
{{ row.integralStart > 0 ? '+' + row.integralStart : row.integralStart }} ~ {{ row.integralEnd > 0 ? '+' + row.integralEnd : row.integralEnd }}
|
||||
</span>
|
||||
<span v-else>{{ row.integral > 0 ? '+' : '' }}{{ row.integral }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right" width="200">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" :disabled="!permissions('app_appvillagerintegralrule_edit')" @click="changeStatus(row.id, 0)" v-if="row.status == 1">
|
||||
停用
|
||||
</el-button>
|
||||
<el-button type="text" :disabled="!permissions('app_appvillagerintegralrule_edit')" @click="changeStatus(row.id, 1)" v-else>启用</el-button>
|
||||
<el-button type="text" :disabled="!permissions('app_appvillagerintegralrule_edit')" @click="toEdit(row)">编辑</el-button>
|
||||
<el-button type="text" :disabled="!permissions('app_appvillagerintegralrule_del')" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
<ai-empty v-else>暂无应用权限</ai-empty>
|
||||
<ai-dialog :title="dialogTitle" :visible.sync="dialog" @onConfirm="onConfirm" @closed="form={ladderRule: []}" width="700px">
|
||||
<div class="form_div">
|
||||
<el-form ref="DialogForm" :model="form" :rules="formRules" size="small" label-suffix=":" label-width="100px">
|
||||
<el-form-item label="事件/类型" prop="eventType">
|
||||
<el-cascader v-model="form.eventType" :props="etOps" clearable placeholder="请选择" @change="handleTypeForm"
|
||||
:options="cacheOps"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="规则" prop="ruleType" v-if="form.ruleType>-1" required>
|
||||
<el-row type="flex" justify="space-between">
|
||||
<div v-text="dict.getLabel('integralRuleRuleType',form.ruleType)"/>
|
||||
<el-button v-if="form.ruleType==1" type="text" icon="iconfont iconAdd"
|
||||
@click="form.ladderRule.push({viewCount:null,integral:null})">添加
|
||||
</el-button>
|
||||
</el-row>
|
||||
<el-table v-if="form.ruleType==1" :data="form.ladderRule" size="mini" border stripe>
|
||||
<el-table-column label="查看人数(人)" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-input class="tableInput" v-model.number="row.viewCount" clearable placeholder="请输入"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="获得积分(分)" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-input class="tableInput" v-model="row.integral" clearable placeholder="请输入" type="number"
|
||||
@keyup.native="row.integral=checkIntegral(row.integral)"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template slot-scope="{row,$index}">
|
||||
<el-button type="text" @click="handleDelete($index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
<el-form-item label="周期范围" prop="scoringCycle">
|
||||
<ai-select v-model="form.scoringCycle" :selectList="dict.getDict('integralRuleScoringCycle')"/>
|
||||
</el-form-item>
|
||||
<template v-if="form.ruleType==0">
|
||||
<el-form-item label="奖励次数" prop="numberLimit">
|
||||
<el-input placeholder="请输入,周期范围内,不填写表示不限制" v-model.number="form.numberLimit" clearable/>
|
||||
</el-form-item>
|
||||
<el-form-item label="积分分值" prop="integral">
|
||||
<el-input placeholder="请输入" v-model="form.integral" clearable/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "AppScoreRules",
|
||||
label: "积分规则",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
computed: {
|
||||
isEdit() {
|
||||
return !!this.form.id
|
||||
},
|
||||
dialogTitle() {
|
||||
return this.isEdit ? "编辑积分规则" : "添加积分规则"
|
||||
},
|
||||
etOps() {
|
||||
return {
|
||||
lazy: true,
|
||||
value: "dictValue",
|
||||
label: "dictName",
|
||||
lazyLoad: (node, resolve) => {
|
||||
if (node.level == 0) resolve(this.dict.getDict('integralRuleEvent'))
|
||||
else if (node.level == 1) {
|
||||
let dict = 'integralRuleEvent' + node.value
|
||||
this.dict.load(dict).then(() => {
|
||||
let nodes = this.dict.getDict(dict).map(e => ({...e, leaf: true}))
|
||||
resolve(nodes)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: {status: "", eventType: null},
|
||||
page: {current: 1, size: 10, total: 0},
|
||||
colConfigs: [
|
||||
{prop: "event", label: "事件", dict: "integralRuleEvent"},
|
||||
{prop: "type", label: "类型", dict: "integralRuleEventType"},
|
||||
{prop: "ruleType", label: "规则", dict: "integralRuleRuleType"},
|
||||
{prop: "scoringCycle", label: "周期范围", dict: "integralRuleScoringCycle"},
|
||||
{prop: "status", label: "状态", align: "center", width: 96, dict: "integralRuleStatus"},
|
||||
{slot: "options", label: "操作", align: "center"},
|
||||
],
|
||||
tableData: [],
|
||||
dialog: false,
|
||||
form: {ladderRule: []},
|
||||
formRules: {
|
||||
eventType: [{required: true, message: "请选择事件/类型", trigger: "change"}],
|
||||
scoringCycle: [{required: true, message: "请选择周期范围", trigger: "change"}],
|
||||
integral: [{required: true, pattern: /^\d*[.\d]\d?$/, message: "请输入积分分值,最多保留一位小数"}],
|
||||
numberLimit: [{pattern: /^\d*$/, message: "请输入正整数"}]
|
||||
},
|
||||
cacheOps: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.dict.load("integralRuleStatus", "integralRuleRuleType", 'integralRuleScoringCycle', 'integralRuleEvent', 'integralRuleEventType').then(() => {
|
||||
this.getList();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.instance.post(`/app/appvillagerintegralrule/list`, null, {
|
||||
params: {...this.search, ...this.page},
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records;
|
||||
this.page.total = res.data.total;
|
||||
}
|
||||
});
|
||||
},
|
||||
toEdit(row) {
|
||||
this.form = this.$copy(row)
|
||||
let {ladderRule, event, type} = this.form,
|
||||
dict = 'integralRuleEvent' + event
|
||||
this.dict.load(dict).then(() => {
|
||||
this.form.eventType = [event, type]
|
||||
this.form.ladderRule = JSON.parse(ladderRule || "[]")
|
||||
this.cacheOps = this.dict.getDict('integralRuleEvent').map(e => {
|
||||
if (e.dictValue == event) {
|
||||
e.children = this.dict.getDict(dict).map(d => ({...d, leaf: true}))
|
||||
}
|
||||
return e
|
||||
})
|
||||
this.$nextTick(() => {
|
||||
this.dialog = true
|
||||
})
|
||||
})
|
||||
},
|
||||
remove(id) {
|
||||
this.$confirm("删除后不可恢复,是否要删除该事项?", {
|
||||
type: 'error'
|
||||
}).then(() => {
|
||||
this.instance
|
||||
.post(`/app/appvillagerintegralrule/delete?ids=${id}`)
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success("删除成功!");
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
changeStatus(id, status) {
|
||||
let text = status == 1 ? '启用' : '停用'
|
||||
this.$confirm(`确定${text}该条规则?`).then(() => {
|
||||
this.instance.post(`/app/appvillagerintegralrule/enableOrDisable?id=${id}`).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(`${text}成功!`)
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
onReset() {
|
||||
this.page.current = 1
|
||||
this.search.classification = ""
|
||||
this.search.integralType = ""
|
||||
this.search.ruleStatus = ""
|
||||
this.getList();
|
||||
},
|
||||
onConfirm() {
|
||||
if(this.form.ruleType==1 && !this.form.ladderRule.length) {
|
||||
return this.$message.error('请添加规则')
|
||||
}
|
||||
this.$refs.DialogForm.validate((valid) => {
|
||||
if (valid) {
|
||||
let formData = this.$copy(this.form)
|
||||
formData.ladderRule = JSON.stringify(formData.ladderRule)
|
||||
formData.integral = formData.integral || 0
|
||||
this.instance.post(`/app/appvillagerintegralrule/addOrUpdate`, formData).then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success(`${this.isEdit ? '编辑成功' : '添加成功'}`)
|
||||
this.onReset()
|
||||
this.dialog = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
handleTypeSearch(v) {
|
||||
this.search.event = v?.[0]
|
||||
this.search.type = v?.[1]
|
||||
this.page.current = 1
|
||||
this.$refs.eventTypeSearch.dropDownVisible = false
|
||||
this.getList()
|
||||
},
|
||||
handleTypeForm(v) {
|
||||
if (this.dialog) {
|
||||
this.form.event = v?.[0]
|
||||
this.form.type = v?.[1]
|
||||
this.form.ruleType = !this.form.event ? null : this.form.event == 3 ? 1 : 0
|
||||
}
|
||||
},
|
||||
handleDelete(i) {
|
||||
this.$confirm("是否要删除该规则?").then(() => {
|
||||
this.form.ladderRule.splice(i, 1)
|
||||
}).catch(() => 0)
|
||||
},
|
||||
checkIntegral(v) {
|
||||
return /\.\d{2,}$/.test(v) ? Math.abs(v).toFixed(1) : Math.abs(v)
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppScoreRules {
|
||||
height: 100%;
|
||||
background: #f3f6f9;
|
||||
|
||||
::v-deep .ai-list__content--right {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
::v-deep .ai-dialog {
|
||||
.el-cascader {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tableInput {
|
||||
& > input {
|
||||
text-align: center;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user