Compare commits
	
		
			1762 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | d50cb09d98 | ||
|  | ed1fc2b718 | ||
|  | bcd540914a | ||
|  | b9b70ea740 | ||
|  | 1de1e3b6d6 | ||
|  | 549dc9f18e | ||
|  | 7274566ef7 | ||
|  | ba3b2ba0e1 | ||
|  | 025f42bf76 | ||
|  | 9528bf2553 | ||
|  | 0d20009d04 | ||
|  | f83091b0e6 | ||
|  | 65459954ad | ||
|  | 924fefcc0e | ||
|  | 9162649d9d | ||
|  | ad36c17f3c | ||
|  | 28fdd13012 | ||
|  | fd73698c48 | ||
|  | 137891332a | ||
|  | 59e072ed47 | ||
|  | b77882a574 | ||
|  | 10cbef1f57 | ||
|  | 991114848a | ||
|  | 1efe6010a2 | ||
|  | b1a4952d61 | ||
|  | 5b36d282c4 | ||
|  | 3b6a1cad2b | ||
|  | 35b1e13ef6 | ||
|  | 06b56c1222 | ||
|  | dbf9cbf6ba | ||
|  | 6c02405a9a | ||
|  | 326a4ad428 | ||
|  | e9cb4064e6 | ||
|  | e346ef8f91 | ||
|  | 3bf4ef345b | ||
|  | cf91fcf886 | ||
|  | 74a4a8f563 | ||
|  | fe0024e748 | ||
|  | 22ea9dd3df | ||
|  | 70f5dc8f9f | ||
|  | ed0ef469f2 | ||
|  | 9071d7e36b | ||
|  | 5db2205403 | ||
|  | c937d24154 | ||
|  | 5b5f87afc3 | ||
|  | 59d9cbeb10 | ||
|  | 21ee09cc44 | ||
|  | 7cef941dea | ||
|  | 16be1d099b | ||
|  | 36fad97ad8 | ||
|  | 4efa046f0c | ||
|  | 9994004c0c | ||
|  | 79c0c5b3b3 | ||
|  | b04a8eaf01 | ||
|  | 5e8feea477 | ||
|  | 22f6e8ca28 | ||
|  | fd06b222a6 | ||
|  | fb32135755 | ||
|  | bd702517fd | ||
|  | d46c73777e | ||
|  | 43dab0bf8e | ||
|  | f6dc75f553 | ||
|  | cc3c6b4de4 | ||
|  | 74be1fcd11 | ||
|  | 56ae839500 | ||
|  | 5f6131d132 | ||
|  | 6daf7e03bf | ||
|  | c53f60c9d3 | ||
|  | cc34079add | ||
|  | c87d720c7f | ||
|  | 6c318233e4 | ||
|  | 9ffcd953c4 | ||
|  | 57ea58d8b7 | ||
|  | e7649cb79d | ||
|  | a70fd383ff | ||
|  | 0943831ccb | ||
|  | 6563cc883f | ||
|  | ea30d6fbde | ||
|  | 329dcf52c2 | ||
|  | fa74319438 | ||
|  | b6ff60be56 | ||
|  | abdf94fc5e | ||
|  | 55dfca0a74 | ||
|  | 13e6985469 | ||
|  | 44d950048d | ||
|  | 989e1dbd92 | ||
|  | 2daa6a6e15 | ||
|  | e284353fb3 | ||
|  | 9bba55fde2 | ||
|  | b7dadf70fd | ||
|  | 8892201095 | ||
|  | 325de69bf3 | ||
|  | a50ddb8807 | ||
|  | 6d9a27a06d | ||
|  | cdefdbf526 | ||
|  | 06ee2ca8a9 | ||
|  | b60b2786c2 | ||
|  | e907e21409 | ||
|  | 4f8c6b82cd | ||
|  | 0789bda44f | ||
|  | f637e8c943 | ||
|  | 0b77d16f3c | ||
|  | b1b44cf4fc | ||
|  | ee0cf5f8fe | ||
|  | 9ab2944681 | ||
|  | 57efaad1d7 | ||
|  | 525e0d6c93 | ||
|  | 4f02c6ec90 | ||
|  | 6f00159b55 | ||
|  | b3d720e94f | ||
|  | feb0782b5c | ||
|  | 7dec8870b9 | ||
|  | 45da9df43c | ||
|  | f1d1859d99 | ||
|  | 9138a1b1e9 | ||
|  | 7952757394 | ||
|  | 41a4560aba | ||
|  | 52075116cb | ||
|  | 77b798764b | ||
|  | 379c4d59a9 | ||
|  | 172e375cc8 | ||
|  | 17afe15196 | ||
|  | f2b336d306 | ||
|  | 9167b4f1f1 | ||
|  | 8e389a2afc | ||
|  | 1a67e725af | ||
|  | 77216cbc13 | ||
|  | 38f2404ef3 | ||
|  | fc8720fc40 | ||
|  | 41b36c7784 | ||
|  | b1002fca35 | ||
|  | 1b14f88546 | ||
|  | e29c5e5695 | ||
|  | e08fcafa6b | ||
|  | 2a88b48ce5 | ||
|  | fba1619d04 | ||
|  | 11a2b54373 | ||
|  | db5233f3ff | ||
|  | 38265dc4ff | ||
|  | 250b854388 | ||
|  | b777d3ee4d | ||
|  | 4e07b5c13e | ||
|  | 217a687c95 | ||
|  | ad7e1c3bad | ||
|  | d637a86dab | ||
|  | 72248fee11 | ||
|  | 0c13c8a477 | ||
|  | 46875570e1 | ||
|  | 24c95403e6 | ||
|  | 02fc32def7 | ||
|  | 669a358195 | ||
|  | c37e2ad191 | ||
|  | a1b7d92a74 | ||
|  | ca75c39a58 | ||
|  | cfda1e98c2 | ||
|  | 446dc2c135 | ||
|  | 45fc07c4fe | ||
|  | a8206c8d90 | ||
|  | 73996e1394 | ||
|  | c68b06be58 | ||
|  | f43b985c4b | ||
|  | 573f5b3cfd | ||
|  | 56d292c0d2 | ||
|  | 1a8f516821 | ||
|  | a5933a18f9 | ||
|  | 4590a99466 | ||
|  | a7821904da | ||
|  | 264d2e0063 | ||
|  | 423f584474 | ||
|  | 1be5ca3cce | ||
|  | a997a3089c | ||
|  | 4cfbe99918 | ||
|  | ff3c38e9aa | ||
|  | 42f26c92c1 | ||
|  | a759c7aacf | ||
|  | 988ee9bd91 | ||
|  | b395a44e70 | ||
|  | 2c975543be | ||
|  | 1b1a55028f | ||
|  | 04eac7ef28 | ||
|  | 50668bb5a2 | ||
|  | cfc7bf3307 | ||
|  | 225498b24d | ||
|  | 366e575d79 | ||
|  | 53068a8aa4 | ||
|  | 52d35acf05 | ||
|  | 0aa45ef8fa | ||
|  | fc817fd6aa | ||
|  | e631366934 | ||
|  | 2a12b0d5fc | ||
|  | 0c93015806 | ||
|  | 28d6b3c9a9 | ||
|  | 54661dec73 | ||
|  | 50a70380bd | ||
|  | 7596a1f709 | ||
|  | 7cdb62180b | ||
|  | 97cd5bd4e9 | ||
|  | e7fb22d06d | ||
|  | e2e3f35e17 | ||
|  | d0727f8991 | ||
|  | 1a773d10fc | ||
|  | 263f42d51c | ||
|  | 84b265d219 | ||
|  | 316763e63b | ||
|  | 8cb39d4fdf | ||
|  | 8f6434c393 | ||
|  | e750f68fc0 | ||
|  | 69c99d94c5 | ||
|  | 080206c1c5 | ||
|  | 9bc3e453c0 | ||
|  | d719644038 | ||
|  | a7f282691f | ||
|  | 2105225998 | ||
|  | 0ade3a59f1 | ||
|  | 301863e05c | ||
|  | a00aa55617 | ||
|  | ba4904a9cb | ||
|  | efb18515f5 | ||
|  | 8a6b586503 | ||
|  | 21ccd9ff81 | ||
|  | 07212f3ac7 | ||
|  | 1975b8748c | ||
|  | d24b4beed4 | ||
|  | 0fc3742e9e | ||
|  | fed5beabd1 | ||
|  | 3a8c561a52 | ||
|  | 45d7f9b699 | ||
|  | 1c9f135ec3 | ||
|  | 7b9574a35a | ||
|  | a0cec7c024 | ||
|  | c49339487d | ||
|  | 78b7eec935 | ||
|  | d29d8f8bff | ||
|  | a9bdc76bcc | ||
|  | 17e6db28d1 | ||
|  | 3ec42eb891 | ||
|  | 61941cf978 | ||
|  | 816cb42c28 | ||
|  | 1230f98b7b | ||
|  | 143e11cdf4 | ||
|  | 3a2938e1a7 | ||
|  | 5a8aea6776 | ||
|  | e43006a636 | ||
|  | aa7caf498b | ||
|  | 537d27db17 | ||
|  | db7faeac8a | ||
|  | 690d5374cc | ||
|  | 1d4a80ebd6 | ||
|  | e982b33d50 | ||
|  | fe8384f1d7 | ||
|  | ae0952da7d | ||
|  | 05aa12f68d | ||
|  | 5752b4d07f | ||
|  | 1709494bff | ||
|  | 47d149fc1d | ||
|  | 44afde131d | ||
|  | e5c5e4584b | ||
|  | 7822e34287 | ||
|  | fab3ee32d0 | ||
|  | 63cd10ccbf | ||
|  | dbb6706b21 | ||
|  | c8a547eaad | ||
|  | 618e076f4d | ||
|  | 307f6c347d | ||
|  | 648ce504d6 | ||
|  | ccb14e0716 | ||
|  | 7e10885ecd | ||
|  | 631ac14395 | ||
|  | d15c4f89a1 | ||
|  | eea08ecd44 | ||
|  | 466d6583aa | ||
|  | c43dde986e | ||
|  | 4d201bd197 | ||
|  | 26c2d675d7 | ||
|  | 98367e1551 | ||
|  | 0d06f67599 | ||
|  | 5a655f74f8 | ||
|  | 802a10993f | ||
|  | f7a003fdc5 | ||
|  | 4a50280483 | ||
|  | ed69018562 | ||
|  | 96e9cfe264 | ||
|  | 5dbee7114c | ||
|  | 9e4cd4a6f4 | ||
|  | b9c70b6e2e | ||
|  | 2b07fd4f3e | ||
|  | 760f84798a | ||
|  | 816e6947e5 | ||
|  | 84e5dc0354 | ||
|  | 32b82f80db | ||
|  | 8f5e79bf0b | ||
|  | 9b92f788ad | ||
|  | 9bc6083780 | ||
|  | 16ef081acc | ||
|  | bd7cf65ca1 | ||
|  | 03932a6d31 | ||
|  | e61437d5eb | ||
|  | 2bc9fd2121 | ||
|  | 34f318d3f8 | ||
|  | efc13f3ef7 | ||
|  | b92d1c8ab0 | ||
|  | 8861aede74 | ||
|  | cdc53044d0 | ||
|  | fed4c57a18 | ||
|  | bfe7e13d47 | ||
|  | 16c9d7c021 | ||
|  | ab4e0e512c | ||
|  | dfed065f71 | ||
|  | c0e4e2d0f7 | ||
|  | 02631bc1ac | ||
|  | ad049fa113 | ||
|  | 6d78632498 | ||
|  | 8d5dc33873 | ||
|  | c9bc7ddb92 | ||
|  | f301c9c0cd | ||
|  | 9e1ae78371 | ||
|  | 3234e8acce | ||
|  | 44e4545b16 | ||
|  | f09d09262b | ||
|  | df15c4429c | ||
|  | fe19a491b8 | ||
|  | 0caf427c5e | ||
|  | 4fe2e26490 | ||
|  | f2223b1973 | ||
|  | 31060f34f4 | ||
|  | 56a9b9871c | ||
|  | 2e69a79bce | ||
|  | e74fa78bcb | ||
|  | ae6a3030fd | ||
|  | 05199221b8 | ||
|  | 4df8dba8d6 | ||
|  | 4aa5f362a9 | ||
|  | 36e599f972 | ||
|  | 4635459e99 | ||
|  | 014f131577 | ||
|  | cdf5d072f3 | ||
|  | 87521f1e6e | ||
|  | a146bbbd5a | ||
|  | da25a3750e | ||
|  | 1f6e518300 | ||
|  | e5a1b35146 | ||
|  | db24ea6af7 | ||
|  | 7e88eb8ee8 | ||
|  | e9521466f3 | ||
|  | bea687d5f9 | ||
|  | bc15d74c34 | ||
|  | c04284d8c6 | ||
|  | 3b43f28a44 | ||
|  | 3f88c7a958 | ||
|  | e2cda5b27d | ||
|  | c07f8884aa | ||
|  | 50372f014d | ||
|  | c3e0f4878a | ||
|  | 8c62d50bcb | ||
|  | 75e6c5004f | ||
|  | 35451cb5b6 | ||
|  | 69529ec0b1 | ||
|  | c3f87b9d32 | ||
|  | 4c3f246e23 | ||
|  | 5bd15e121d | ||
|  | 893662e893 | ||
|  | 0d3aa3effb | ||
|  | edea95a1e6 | ||
|  | 0464729d35 | ||
|  | 6ee800c0d4 | ||
|  | fd23cb1ea3 | ||
|  | 6fcd895447 | ||
|  | 10ecea0829 | ||
|  | 1836b271aa | ||
|  | f82ce583fe | ||
|  | c0f1a6e2ab | ||
|  | 02538d4506 | ||
|  | 910a3d1039 | ||
|  | d24cd8728a | ||
|  | 1ec01e97ec | ||
|  | 7002c8014e | ||
| c4330f00ac | |||
| d61ee360ec | |||
|  | af15635c9a | ||
|  | f1a25179a4 | ||
|  | 2202896efd | ||
|  | 032b2ec9ea | ||
|  | 5739b832f7 | ||
|  | 9cae289354 | ||
|  | 64cbe9e04d | ||
|  | 01dbb6695b | ||
|  | e15bf73657 | ||
|  | 8c99ddafed | ||
|  | 915214df2b | ||
|  | e42eee9def | ||
|  | ada042974b | ||
|  | 3fff4143d4 | ||
|  | e6fdb98bce | ||
|  | 6968050c6a | ||
|  | 4194829fc0 | ||
|  | d201cebd7d | ||
|  | ee02cc8f73 | ||
|  | eaab46eb76 | ||
|  | 98d266845a | ||
|  | 7cd67ad3ba | ||
|  | 05276b4082 | ||
|  | 3db4ac231b | ||
|  | 1203c9610a | ||
|  | fc20375848 | ||
|  | da1918084c | ||
|  | e46e2f38db | ||
|  | 6402952351 | ||
|  | 9a18db7f99 | ||
|  | 7bea38ba79 | ||
|  | ded46304b5 | ||
|  | b2ee7fafac | ||
|  | 61e513f45b | ||
|  | 9958eef8b8 | ||
|  | edd2cdf632 | ||
|  | 44d5b8eac1 | ||
|  | 800df96c01 | ||
|  | 11c52de53d | ||
|  | 971ed77531 | ||
|  | ebba4508cf | ||
|  | cab1ccc026 | ||
|  | d159fcd9da | ||
|  | e2520ca60f | ||
|  | 3e3cc5693d | ||
|  | 61e524a689 | ||
|  | 740b87821a | ||
|  | 0c92fdfa86 | ||
|  | 7bd8c1f2d4 | ||
|  | 2f37357bf1 | ||
|  | e6c36b2a80 | ||
|  | e1c46b7630 | ||
|  | 77bca8d43c | ||
|  | 6e3aee6a2e | ||
|  | 56956f178d | ||
|  | 051627f53b | ||
|  | 009128e068 | ||
|  | 7df86b8163 | ||
|  | d83143a783 | ||
|  | 82169094e4 | ||
|  | 19cfe66262 | ||
|  | d90217a137 | ||
|  | 26e83e82d3 | ||
|  | 657a9e26c7 | ||
|  | 72d6d7905e | ||
|  | a35ca752af | ||
|  | be4696a85b | ||
|  | 101663ddda | ||
|  | 714f64676a | ||
|  | 5eb32723bb | ||
|  | edc50dccb8 | ||
|  | 037c6347e3 | ||
|  | 047d4d1314 | ||
|  | a456758156 | ||
|  | 98e236f1a0 | ||
|  | d773a26630 | ||
|  | 439ed3807e | ||
|  | b4fa9f84c3 | ||
|  | b3e13b82b4 | ||
|  | 9927d7f880 | ||
|  | 56e4f29746 | ||
|  | ba9279e304 | ||
|  | cc4a891975 | ||
|  | ba47b50ab3 | ||
|  | 56973ca021 | ||
|  | e26e962ba3 | ||
|  | 6ce684dc82 | ||
|  | 9bdad39418 | ||
|  | caf9f2da13 | ||
|  | 020439f8e8 | ||
|  | 2d6407c02f | ||
|  | 7d67d5863e | ||
|  | 2538a7ecf7 | ||
|  | 766b4182fd | ||
|  | 913917b54d | ||
|  | 6e027df792 | ||
|  | 4bdb61249b | ||
|  | b92caedf40 | ||
|  | 73f9f00b53 | ||
|  | 7655976861 | ||
|  | 5b93ef80c6 | ||
|  | 3072dc10d1 | ||
|  | 7ec0f7c45f | ||
|  | cd109e8e6d | ||
|  | 82682b6810 | ||
|  | bf8e77b80e | ||
|  | ba9210e1d0 | ||
|  | 7d8b7f22c6 | ||
|  | 7d1d375240 | ||
|  | c55c9dd009 | ||
|  | 8cbc367985 | ||
|  | c33fb7b223 | ||
|  | c749753673 | ||
|  | c683d3770c | ||
|  | 5c7fc681ec | ||
|  | 94d54f85fd | ||
|  | fe9ff22748 | ||
|  | c08d40d471 | ||
|  | 4ba8594b28 | ||
|  | 39067e6285 | ||
|  | 5e08712676 | ||
|  | faf187f1c6 | ||
|  | 02cadf6395 | ||
|  | ed1c2a6df2 | ||
|  | 9df0e30f96 | ||
|  | 7e0acdafbf | ||
|  | 731816ca11 | ||
|  | d51ae093cb | ||
|  | cc02dcb810 | ||
|  | 772d1f0a82 | ||
|  | 80f062ffc9 | ||
|  | 7709422b02 | ||
|  | f3686f378a | ||
|  | d7c9e7dd60 | ||
|  | 0ab3423283 | ||
|  | dc1aa5d8b3 | ||
|  | 6fa5beef6f | ||
|  | 9e3ba31ef1 | ||
|  | 997fe953a8 | ||
|  | 214f92bf05 | ||
|  | d9bbbb86d3 | ||
|  | 38731f3d63 | ||
|  | ac119bc734 | ||
|  | 72b2edc0d4 | ||
|  | 0b9928e1e0 | ||
|  | 913ffd6b9c | ||
|  | 416d32d901 | ||
|  | 1fbc5e2448 | ||
|  | 8a896f2289 | ||
|  | f44191578c | ||
|  | 1e24554662 | ||
|  | 7907123692 | ||
|  | f26491ed65 | ||
|  | c812fec5a5 | ||
|  | 65d8f71ea0 | ||
|  | 14533338aa | ||
|  | 0533937e25 | ||
|  | 878999c441 | ||
|  | ba95e159f3 | ||
|  | 805adb7639 | ||
|  | 0e92e929a9 | ||
|  | 3fd7aca320 | ||
|  | c5861c685a | ||
|  | de6e2c5841 | ||
|  | 01beff42b0 | ||
|  | 8dc45d7f0f | ||
|  | bc2dae4a9b | ||
|  | 1812afed13 | ||
|  | 526830773a | ||
|  | 0eaa844afd | ||
|  | 2a77cc8234 | ||
|  | 63dd7e08f1 | ||
|  | 528867ac54 | ||
|  | daefc25b4b | ||
|  | 8c89b3b418 | ||
|  | 67cc563c32 | ||
|  | 4bee766850 | ||
|  | 63b1851029 | ||
|  | 3c898889ce | ||
|  | fc48cb8ac5 | ||
|  | 38a020f9a7 | ||
|  | 5d8ade3a3a | ||
|  | 66a9c4aa3d | ||
|  | defbf3ab35 | ||
|  | a5f5c2905b | ||
|  | 30edb83bb2 | ||
|  | 333da16a4a | ||
|  | 28e4c2ed74 | ||
|  | 72bbb32bc2 | ||
|  | 4b3175165a | ||
|  | 0a95af96f5 | ||
|  | a732e4aecb | ||
|  | d77a4d202e | ||
|  | 3e0f6f7e6f | ||
|  | f8bfd88de1 | ||
|  | e56b9fbd86 | ||
|  | b69af7117c | ||
|  | 06d6255d97 | ||
|  | 5481602d07 | ||
|  | 21b71bb0c1 | ||
|  | 2ec0060bbc | ||
|  | 4de065d59e | ||
|  | 872df25f34 | ||
|  | 315e8ffec7 | ||
|  | 1c91aead97 | ||
|  | 8bf723cc55 | ||
|  | 4288d70f0a | ||
|  | 16a4337d88 | ||
|  | 10b0acdc5f | ||
|  | 8a687ede4a | ||
|  | 214faad467 | ||
|  | f2d13e2345 | ||
|  | 351fadae18 | ||
|  | ea391f6f68 | ||
|  | f599a222f2 | ||
|  | f7b6afeb95 | ||
|  | 4794ccedad | ||
|  | 79b964055a | ||
|  | 891d8bfaf5 | ||
|  | a43d375d3e | ||
|  | b4e5b3f71b | ||
|  | 9629d39d9d | ||
|  | 75eb5e7434 | ||
|  | 9ef17f5680 | ||
|  | 7da51f065a | ||
|  | 595712b66e | ||
|  | 53b9e36fe8 | ||
|  | f78b48057e | ||
|  | 410d0e70e0 | ||
|  | 2eb5df3759 | ||
|  | 77a88dba26 | ||
|  | 6027a46ee9 | ||
|  | 73d84875c3 | ||
|  | 2f98f6bc09 | ||
|  | b3a06a51fa | ||
|  | 88f5f4279f | ||
|  | 60dd3f3d8c | ||
|  | 79a49298e2 | ||
|  | bcdb4946e4 | ||
|  | 9f85ccc4f2 | ||
|  | 5206203caa | ||
|  | 0fe811958d | ||
|  | 6d4f30f737 | ||
|  | 6e49980aee | ||
|  | e3abdef57b | ||
|  | e28dc75ddb | ||
|  | 0f11adea01 | ||
|  | 606215280b | ||
|  | 1789b78c19 | ||
|  | 3a633c2f96 | ||
|  | fe8bf9a588 | ||
|  | 49dae77888 | ||
|  | d8979960db | ||
|  | c6c7acc220 | ||
|  | 774ec8cc7b | ||
|  | 946af98c4a | ||
|  | 801db611c6 | ||
|  | 617eb16ba2 | ||
|  | b345e1bd13 | ||
|  | 8ca8de8aef | ||
|  | 56c227ee78 | ||
|  | f454b9a1e0 | ||
|  | 7ab4fba5eb | ||
|  | 7df6e54fe8 | ||
|  | aa8db2b2ea | ||
|  | f0553e0f14 | ||
|  | 56d8c0582b | ||
|  | 807faa4229 | ||
|  | 6118aa6b54 | ||
|  | 61477d2fb8 | ||
|  | 65802d4de8 | ||
|  | f68f9be4c8 | ||
|  | 69ddc602ef | ||
|  | 272a3942b1 | ||
|  | cc74aa11af | ||
|  | f8a4b96048 | ||
|  | 4e8d540655 | ||
|  | 88cc2e9e9f | ||
|  | e098bbbf9d | ||
|  | ebb738e41b | ||
|  | d29d2110dc | ||
|  | 901fc767fb | ||
|  | 3fcc993913 | ||
|  | b6b589fcd7 | ||
|  | bacb186def | ||
|  | 877c29965c | ||
|  | 967c73f98a | ||
|  | 9f6f44812e | ||
|  | 2c69fc946b | ||
|  | b7d30b366a | ||
|  | 142496beb3 | ||
|  | 97d9f8dab2 | ||
|  | 99e5cfea09 | ||
|  | 5b81a23bb8 | ||
|  | 42a332b76c | ||
|  | 062b2f6039 | ||
|  | 05f593e87c | ||
|  | 1a52a6acee | ||
|  | 954290d26d | ||
|  | 089e993308 | ||
|  | 6c7b5d45da | ||
|  | 49d43d14e6 | ||
|  | 7647f30a4c | ||
|  | e0955038d2 | ||
|  | 6e5e935cfe | ||
|  | df8ef261a9 | ||
|  | 80a3286a05 | ||
|  | 15e63d4232 | ||
|  | 03b60d3bbe | ||
|  | 549196de75 | ||
|  | ac2933a781 | ||
|  | e10373abc4 | ||
|  | eb5fb2970e | ||
|  | a828fc8ee6 | ||
|  | d693017b39 | ||
|  | e9cba488e5 | ||
|  | 4d3691c17e | ||
|  | df5d4f0380 | ||
|  | b84814c461 | ||
|  | cb885fa456 | ||
|  | 32871fdc1b | ||
|  | 0a47f48e81 | ||
|  | 0f568046c5 | ||
|  | 42e406ff82 | ||
|  | 599c10cd7d | ||
|  | 513bf04185 | ||
|  | 8aaba442af | ||
|  | ae7fe3f5b5 | ||
|  | 6bcd9c870a | ||
|  | 27c23f77e5 | ||
|  | d3df5cb76e | ||
|  | 7dd5b13695 | ||
|  | 4503abe419 | ||
|  | d2941ceb96 | ||
|  | d5cdacddff | ||
|  | 5ea84f0c5f | ||
|  | 11395c003f | ||
|  | c00768252b | ||
|  | 7ccd4fccdf | ||
|  | ec8bb6daf0 | ||
|  | 1c16eb3f62 | ||
|  | b718727544 | ||
|  | 02abd08424 | ||
|  | 5698bfb695 | ||
|  | b3bb77dfc0 | ||
|  | 782f632892 | ||
|  | d53e5f3b4b | ||
|  | cf996ed83d | ||
|  | c276a3f908 | ||
|  | 5e7bae967e | ||
|  | 235f4127be | ||
|  | d358301e5d | ||
|  | cad15c95ff | ||
|  | 608c8e917f | ||
|  | 29a03f52a3 | ||
|  | 85c65143ff | ||
|  | 1e8eb71954 | ||
|  | ccbaf345df | ||
|  | 0ab6121473 | ||
|  | caa650d8a7 | ||
|  | f489726c47 | ||
|  | afa4582961 | ||
|  | ad5e9cee56 | ||
|  | cb8c39f89e | ||
|  | 4f49a8ce3a | ||
|  | 393358c432 | ||
|  | e7c2ab3ff8 | ||
|  | 2ee5920d9e | ||
|  | 4c052eee8c | ||
|  | c7ed3c81ea | ||
|  | 2df5e5fc35 | ||
|  | 58f44dc9b5 | ||
|  | 8331e08401 | ||
|  | 14466882a8 | ||
|  | 4a0391157d | ||
|  | b4b63e86b0 | ||
|  | 3d3a9608aa | ||
|  | 9918f1eec9 | ||
|  | c1ca841f28 | ||
|  | 43cee8bd0f | ||
|  | 43b7aa757b | ||
|  | 17543b1fca | ||
|  | 2168403b2f | ||
|  | 78d6862d9f | ||
|  | 4abfb9f7bf | ||
|  | bd03d5b95e | ||
|  | a3e1694d4f | ||
|  | a6593379af | ||
|  | 447b718db4 | ||
|  | 4c980ce920 | ||
|  | 62c0878bf1 | ||
|  | 571b877853 | ||
|  | 2fee1d638f | ||
|  | 21d86f4f91 | ||
|  | ac42fe7953 | ||
|  | ca0563e470 | ||
|  | 79abba1c1b | ||
|  | cbb91f554e | ||
|  | 6429df786a | ||
|  | 8a5d5fd2a2 | ||
|  | 33a36a881c | ||
|  | def27eb80d | ||
|  | d66df7a089 | ||
|  | aa9b19fe1a | ||
|  | 541fe7645c | ||
|  | 4a1c602495 | ||
|  | 8c52ababf9 | ||
|  | 714ffbb869 | ||
|  | 0cec708363 | ||
|  | 4fc404df50 | ||
|  | 30c8744a0d | ||
|  | 0d119f91fc | ||
|  | a3e0d9e3a8 | ||
|  | c363287d0d | ||
|  | f5cb84d57a | ||
|  | d07437523e | ||
|  | 7876c45df5 | ||
|  | 126ab7a0e5 | ||
|  | 56dacf0dad | ||
|  | 91e69675dc | ||
|  | 65940485a9 | ||
|  | c6c303f281 | ||
|  | ed44e1d430 | ||
|  | 02a90196ef | ||
|  | 7fd68e9935 | ||
|  | 759640bca4 | ||
|  | e879ea68d8 | ||
|  | 653d90b266 | ||
|  | f0d4c65315 | ||
|  | 0644a6a800 | ||
|  | 79aa21a14a | ||
|  | 936d1d9cb8 | ||
|  | 7ae6d4dcc2 | ||
|  | 7317e67369 | ||
|  | 81c828ad22 | ||
|  | 2409a6110b | ||
|  | 731d76a8c5 | ||
|  | 60114bf14d | ||
|  | ad8ebab5d4 | ||
|  | 902c1009bd | ||
|  | 4a1fb16a3e | ||
|  | 1b92c5437e | ||
|  | 489c855972 | ||
|  | c22400eab4 | ||
|  | 0016b8da5d | ||
|  | 6237891af9 | ||
|  | 8ef0f6292e | ||
|  | a36f3741bf | ||
|  | c739dae4f9 | ||
|  | ae600dc2c3 | ||
|  | 14ffbe81f7 | ||
|  | bce5db8e41 | ||
|  | fb117a21c5 | ||
|  | c27f9b673c | ||
|  | a69e27ca79 | ||
|  | f67a710539 | ||
|  | 2a5fa63b4b | ||
|  | 284c8bd02b | ||
|  | 99982a9b21 | ||
|  | 17b87fce22 | ||
|  | 5d782ea172 | ||
|  | 7b27d4c1f5 | ||
|  | f5dc0ef5d5 | ||
|  | 0faf89c232 | ||
|  | 336d1cc48f | ||
|  | 392f27f94f | ||
|  | bf819648d2 | ||
|  | 4ef3723d03 | ||
|  | 2b3258c63a | ||
|  | 23fa2e3140 | ||
|  | d237e7a72b | ||
|  | 2e09cd71a0 | ||
|  | 07141014a9 | ||
|  | 4ed2ba92c5 | ||
|  | 77f78ac6ee | ||
|  | 39cc46e910 | ||
|  | 1ab10e6f96 | ||
|  | 021cc97145 | ||
|  | 0a241dd286 | ||
|  | 96c50e6832 | ||
|  | 24a7e8c19a | ||
|  | eb63f3c9c2 | ||
|  | 797ff30800 | ||
|  | de4f337f93 | ||
|  | 77c65c4e80 | ||
|  | c4959fabdf | ||
|  | 38d7beff8f | ||
|  | 015935b7f4 | ||
|  | 920180d95b | ||
|  | eaa92c2dfe | ||
|  | 3d1614e99a | ||
|  | b5c9963de2 | ||
|  | 9106ec7547 | ||
|  | 03de4e4f7e | ||
|  | 48003ffaa3 | ||
|  | 875c056075 | ||
|  | 9a8227e43c | ||
|  | bb744c49b9 | ||
|  | 8cb77ebeee | ||
|  | a319b5decc | ||
|  | d4acc37880 | ||
| d63c013d1f | |||
|  | e175e62ccd | ||
|  | 608dfb53ba | ||
|  | 7251b599db | ||
|  | 05dda2bad2 | ||
|  | b7433bdd55 | ||
|  | 825ae8e41b | ||
|  | 06ac9ae4fd | ||
|  | 88d29e99f2 | ||
|  | 6005ae2b48 | ||
|  | 02501453a8 | ||
|  | fcbf8c05f4 | ||
|  | 80d6ab63f4 | ||
|  | f18b450eca | ||
|  | 3c84a52d7d | ||
|  | 6b7fd4f9b0 | ||
|  | 2e22f1a494 | ||
|  | 15304b84c3 | ||
|  | 4c6f3322cc | ||
|  | 08dd7fe4c7 | ||
|  | 1249c4b0bb | ||
|  | cee13c878e | ||
|  | b9b77193e3 | ||
|  | 73cf15b05f | ||
|  | 080b20e9de | ||
|  | 7ceadac5ea | ||
|  | 5cfb9dac19 | ||
|  | b40ee95b48 | ||
|  | a8d35407ae | ||
|  | 3a56a8c6cc | ||
|  | b0f5da59f1 | ||
|  | 4617698596 | ||
|  | 445c615477 | ||
|  | 20d4a5de01 | ||
|  | cf21392f70 | ||
|  | 95aa779de1 | ||
|  | f70e222118 | ||
|  | 1ece40a1ff | ||
|  | d6d5e06f49 | ||
|  | 96ded5c44e | ||
|  | 774d67c060 | ||
|  | 53f74ed7ab | ||
|  | 5316234edf | ||
|  | f7a0502ab1 | ||
|  | 0b745a0745 | ||
|  | 1cb5da5e52 | ||
|  | 09c1251070 | ||
|  | 72a63e1fdc | ||
|  | 7f61b1927e | ||
|  | 73d1822777 | ||
|  | 2b26005104 | ||
|  | e4f09cc777 | ||
|  | 7dca509968 | ||
|  | 8005d5186a | ||
|  | 3ae8441ccd | ||
|  | 630fb6a04c | ||
|  | 23b00586cc | ||
|  | 2689583c1e | ||
|  | d9f9910b0f | ||
|  | fd70bd5491 | ||
|  | 36d9e72cdc | ||
|  | 65597e4826 | ||
|  | 20c8d9c8ec | ||
|  | 8f0131dfc7 | ||
|  | b11adc40c8 | ||
|  | 6545570ecd | ||
|  | a6841cb380 | ||
|  | 2974eb27d9 | ||
|  | 43ca3a10c8 | ||
|  | 0c2fae8b95 | ||
|  | 449261a490 | ||
|  | ccdd76c5d2 | ||
|  | b213baf57a | ||
|  | 75af293c60 | ||
|  | 78ae2fedcc | ||
|  | 683f8d5071 | ||
|  | 3f0aa73fad | ||
| d8054b3138 | |||
| c5a8cc406e | |||
| 9a14338548 | |||
|  | e4ce1885f8 | ||
|  | e5d42a0d5f | ||
|  | 36c9c1d466 | ||
|  | 26e9ed8011 | ||
| fd58336719 | |||
| 78b75e153a | |||
| f7eccff38d | |||
| 2caaedd7c5 | |||
| 7b501528fb | |||
| e421f3bd30 | |||
|  | 3c59ee2c87 | ||
|  | a5b3b0a115 | ||
|  | 803f3d52a5 | ||
|  | face324b7c | ||
|  | ce180ca6e1 | ||
|  | 7d4a0422cb | ||
|  | c3e7ca5fa0 | ||
|  | e6f016e9cd | ||
|  | 2bcba1bdd4 | ||
|  | 2d2dc39df0 | ||
|  | 1c020414da | ||
|  | c13e90a7f6 | ||
|  | dc1248dd3a | ||
|  | 9389719c00 | ||
|  | 873a2a0291 | ||
|  | 3ecd8a4b90 | ||
|  | 97cf6e7e48 | ||
|  | 27e1f2047f | ||
|  | 1b75874a85 | ||
|  | 96136659cb | ||
|  | 074bc889f2 | ||
|  | 79037b2b77 | ||
|  | 14758461c0 | ||
|  | 3e9a951b5e | ||
|  | cf4c09beb2 | ||
|  | 7f242a00a3 | ||
|  | 10890ad64e | ||
|  | a11f507248 | ||
|  | 6787bc8875 | ||
|  | 915a5b6d7e | ||
|  | 3daebc279e | ||
|  | 90a06e91b6 | ||
|  | 4f4c080ad9 | ||
|  | cfcf2c12ea | ||
|  | 46e1ac2264 | ||
|  | 710c17567f | ||
|  | 668c51494b | ||
|  | 0df80b87fb | ||
|  | 045ef0fe5b | ||
|  | f02a10b7a9 | ||
|  | 91c4b50066 | ||
|  | cbd1484160 | ||
|  | 991362dfd5 | ||
|  | 5eb023311f | ||
|  | cf613a0c4a | ||
|  | a26ae16bcc | ||
|  | 942a10db23 | ||
|  | 396a7a2f5a | ||
|  | c01098ccad | ||
|  | 4b07e48aac | ||
|  | 51a1b0070c | ||
|  | f593db72f0 | ||
|  | cd154b48cf | ||
|  | 8b1197fe54 | ||
|  | 5053ee1654 | ||
|  | 3392f5d160 | ||
|  | 0c8ab8c1bb | ||
|  | 658b8b1e95 | ||
|  | e08d795e53 | ||
|  | 411db791fe | ||
|  | e30090b6cb | ||
|  | 0a5e3c9b66 | ||
|  | 75d27332dd | ||
|  | 9f9e55fb4e | ||
|  | e8948dc28d | ||
|  | bd94a1372a | ||
|  | 2c0c80c7d3 | ||
|  | 6dd89c48f9 | ||
|  | 336461a14d | ||
|  | 0bf5bbf217 | ||
|  | e29568c97d | ||
|  | 9b92d7ac4c | ||
|  | e1be3f75fb | ||
|  | 3d7494ee3f | ||
|  | 67f534babc | ||
|  | 7ba0db84be | ||
|  | 50a21c9e45 | ||
|  | 77755d0298 | ||
|  | ecd44a3c78 | ||
|  | b9f3cda9b8 | ||
|  | fa36ed8082 | ||
|  | e6b1e2ec10 | ||
|  | 8be0b37093 | ||
|  | bc6f8e9596 | ||
|  | 2ef327622a | ||
|  | 27203bef6b | ||
|  | 6917ee1fce | ||
|  | 1447e03100 | ||
|  | 92bdae2c35 | ||
|  | 9bf7e55528 | ||
|  | ab6db00a54 | ||
|  | 2dd25ad02c | ||
|  | 60fdec8005 | ||
|  | 4cf8f9a4f6 | ||
|  | 7ac0dcbb80 | ||
|  | 0a0dab0ac2 | ||
|  | cbb0edc14a | ||
|  | e259bbc969 | ||
|  | 213cd46a1c | ||
|  | d537294216 | ||
|  | 77111556bd | ||
|  | d8569137e9 | ||
|  | 22ccf1081b | ||
|  | 350e85143a | ||
|  | 1a65407ef7 | ||
|  | 33b9400e4a | ||
|  | 5061c0d950 | ||
|  | 17bbe976b6 | ||
|  | bb923cca81 | ||
|  | 83e06be215 | ||
|  | a1ddb7ab60 | ||
|  | 98277aa8b9 | ||
|  | b2c2f89263 | ||
|  | b2ec1d98fb | ||
|  | 66c0a4d02f | ||
|  | 1ba7c55040 | ||
|  | 1c23fe25c2 | ||
|  | 52e50f6dd8 | ||
|  | 74d26168f9 | ||
|  | e6cf36a1e1 | ||
|  | 03ed448813 | ||
|  | 21d60e230a | ||
|  | 9f6203e762 | ||
|  | e05ce4d719 | ||
|  | 650a6ced04 | ||
|  | a9a54483db | ||
|  | a8f9a582bb | ||
|  | c3723c8cfb | ||
|  | d1e2853b6e | ||
|  | 7f1ab4e039 | ||
|  | 2ddf94eb75 | ||
|  | eeea69196f | ||
|  | 9cc8d610c6 | ||
|  | 46276a83ff | ||
|  | a8436087e6 | ||
|  | 70722ae3bc | ||
|  | 21d1714f7e | ||
|  | 5775c244cb | ||
|  | f8989e4b3c | ||
|  | 808e365dde | ||
|  | d5eadff265 | ||
|  | 280e180ec0 | ||
|  | 88ec60127f | ||
|  | ed2166a8e4 | ||
|  | 6a42912106 | ||
|  | 02ad912923 | ||
|  | 1f0d57c808 | ||
|  | 758899d5d2 | ||
|  | 99145dfe29 | ||
|  | 93fb661712 | ||
|  | 18525d7f45 | ||
|  | 4984f4bbce | ||
|  | 9038f17227 | ||
|  | 87fbb25738 | ||
|  | f6f989b6be | ||
|  | 2faf80cc22 | ||
|  | eef85d2dcb | ||
|  | a703ed79c3 | ||
|  | 0d19d797f2 | ||
|  | cc59548dc7 | ||
|  | 1dcb4f496d | ||
|  | 4c1ae89e11 | ||
|  | 7a2a4d11c4 | ||
|  | a19bbe29d6 | ||
|  | 99a81996a1 | ||
|  | 6b9a3db12a | ||
|  | 7c025411e9 | ||
|  | f302a577fa | ||
|  | 2b233c209c | ||
|  | 27309d242b | ||
|  | 1d7c140180 | ||
|  | e4f37c927f | ||
|  | add921a438 | ||
|  | a56d6e77ba | ||
|  | be95bdfebb | ||
|  | 841034a7ad | ||
|  | d97edae1a5 | ||
|  | 5d9ede9fb0 | ||
|  | 84b74c6f19 | ||
|  | 7167b61241 | ||
|  | 26f3de888d | ||
|  | 110695c03d | ||
|  | 62f201e5e5 | ||
|  | 5c59c6fb1c | ||
|  | ef58ec52d2 | ||
|  | 4e905d03d2 | ||
|  | 15f7b56361 | ||
|  | 39d242d86a | ||
|  | f948203f58 | ||
|  | cdb0945124 | ||
|  | dcebdbe334 | ||
|  | 5213d622a4 | ||
|  | 74507e4663 | ||
|  | e76206dd9b | ||
|  | 147b0a84f3 | ||
|  | cc6d0a987d | ||
|  | c69d040592 | ||
|  | 63a116bc65 | ||
|  | f5c4734430 | ||
|  | d55355267b | ||
|  | e1a1f46ca7 | ||
|  | d9636e8463 | ||
|  | 215dabe5cf | ||
|  | b691377a6c | ||
|  | f0c6bd9964 | ||
|  | 7806ad4981 | ||
|  | b1603f3b29 | ||
|  | a4bd186464 | ||
|  | 3c205667d4 | ||
|  | 7622fd8ca2 | ||
|  | f9d1809e26 | ||
|  | 80f57d2e4d | ||
|  | 48f58d5380 | ||
|  | e4a910e832 | ||
|  | c842a60f45 | ||
|  | 6bc0e587b4 | ||
|  | 761f404ac1 | ||
|  | c1ea828f77 | ||
|  | 3b5aec0bca | ||
|  | 3dde4fa4ce | ||
|  | 24dad80b52 | ||
|  | f3feb75e18 | ||
|  | fa543d0807 | ||
|  | 2583312007 | ||
|  | ecb0d25950 | ||
|  | 02bdd4ab18 | ||
|  | a4d187cdf1 | ||
|  | 8667835d2b | ||
|  | 2b006da12d | ||
|  | aaf2b8b475 | ||
|  | 9894cecb74 | ||
|  | efc9714abb | ||
|  | ab824d2002 | ||
|  | 6fe4959fcc | ||
|  | c917ac5acf | ||
|  | 23302fc5c3 | ||
|  | a049b8d896 | ||
|  | b1988fb42b | ||
|  | 2cc5ddd0de | ||
|  | 083646bb11 | ||
|  | 337bb19746 | ||
|  | addfa5a097 | ||
|  | 15f61074f9 | ||
|  | d09812588d | ||
|  | 068cbb2916 | ||
|  | 70c6d61e23 | ||
|  | ae247c2a9d | ||
|  | fdf5680bde | ||
|  | 9bd1b05763 | ||
|  | f61bbe9c83 | ||
|  | 4696642a66 | ||
|  | d3a253bb64 | ||
|  | d9e5f2bf43 | ||
|  | 729a3eb8ee | ||
|  | ff40f6de8f | ||
|  | b8d9a7fd6e | ||
|  | e17fefbc9d | ||
|  | 6ddbb022f6 | ||
|  | 1d5ed72119 | ||
|  | 9b09468c0f | ||
|  | 2b6f4c3ea4 | ||
|  | dfb0dbc66d | ||
|  | 2ef6de0eb5 | ||
|  | 9368de483b | ||
|  | 860163bb6c | ||
|  | 05c8b55eda | ||
|  | d271a18092 | ||
|  | 1a1f1c59b0 | ||
|  | eb903e592f | ||
|  | 5368c9df66 | ||
|  | 49764c3e3d | ||
|  | 4dccdf87c3 | ||
|  | 6e3baca4d3 | ||
|  | de864a3d91 | ||
|  | 8835447757 | ||
|  | 31a87039ce | ||
|  | ebf6ef2aa6 | ||
|  | 607b897e65 | ||
|  | 8306e1d5fe | ||
|  | 29a2b7adbd | ||
|  | 229b5c66f6 | ||
|  | 018a4329f2 | ||
|  | cdd330a0f2 | ||
|  | 76b673a803 | ||
|  | e141634634 | ||
|  | 3f8e71437d | ||
|  | f9418701b1 | ||
|  | e7bd8103b1 | ||
|  | 280a918d8a | ||
|  | 12124b339d | ||
|  | 56d6d7e4a3 | ||
|  | 48860fd584 | ||
|  | 0d9c250acb | ||
|  | ff63f6f079 | ||
|  | 7fa917b279 | ||
|  | 8d3d16a5f4 | ||
|  | b7915238c3 | ||
|  | 3ae57be0cc | ||
|  | 2bbc303c00 | ||
|  | 3c762e0f69 | ||
|  | 13567fcb3d | ||
|  | e10c69cd2e | ||
|  | 0c889c9076 | ||
|  | 2655a44573 | ||
|  | 4f1592540e | ||
|  | 2ef633a0c8 | ||
|  | 0b83cec78b | ||
|  | 511a98026e | ||
|  | 29dac41f38 | ||
|  | 607496f22e | ||
|  | 0ff81339d7 | ||
|  | 9b62472851 | ||
|  | 56c425d1b3 | ||
|  | 9c90e17192 | ||
|  | d71028399a | ||
|  | 2198e6e6f2 | ||
|  | 4b760830c2 | ||
|  | 99574bc82b | ||
|  | bfb54de844 | ||
|  | ddb9afa4a9 | ||
|  | c575f1c5bd | ||
|  | 341a77efb4 | ||
|  | f114f81888 | ||
|  | b38da8876b | ||
|  | e666bd0772 | ||
|  | 0a76f894f6 | ||
|  | a642a2ef86 | ||
|  | 0a6508a714 | ||
|  | 39fe336980 | ||
|  | c2fcba70f9 | ||
|  | 0a4f500c52 | ||
|  | a139f1a921 | ||
|  | cbd270a47e | ||
|  | 39e54666e1 | ||
|  | 56911c18e6 | ||
|  | 249fdcf4ff | ||
|  | 4870798cda | ||
|  | bed245526f | ||
|  | 942ec62ef3 | ||
|  | 490964507a | ||
|  | 52f80012c2 | ||
|  | 102cab0ad3 | ||
|  | 97d3df74f9 | ||
|  | 6466e22491 | ||
|  | f6f667a0f6 | ||
|  | 94ae33a36a | ||
|  | 41e4a3f3a0 | ||
|  | 8f40ac4dd4 | ||
|  | dd8bba63c0 | ||
|  | d18312c6d1 | ||
|  | 135a662576 | ||
|  | 731444ae9a | ||
|  | 44f9a8a5e8 | ||
|  | f36e184fb7 | ||
|  | b3338b8a27 | ||
|  | 7048bb57bd | ||
|  | 43e2b68093 | ||
|  | e725724e0f | ||
|  | 76252b234e | ||
|  | 1b887350ee | ||
|  | 527a236377 | ||
|  | 36387f09cc | ||
|  | e33464e201 | ||
|  | 980d38f86a | ||
|  | 6c9c660846 | ||
|  | 89777782c6 | ||
|  | b3082e19ca | ||
|  | c00a272e05 | ||
|  | 0338a914cc | ||
|  | 86eacaffca | ||
|  | 1ce02319f9 | ||
|  | e9412b31ed | ||
|  | fd99207ac8 | ||
|  | cd34e7589a | ||
|  | d58102f837 | ||
|  | c67b8ddac5 | ||
|  | ddc6741756 | ||
|  | 83612a66e3 | ||
|  | d57fa9cda4 | ||
|  | 2cc8864afe | ||
|  | a6d6376a81 | ||
|  | ec6c9e5cb9 | ||
|  | 080abff1d6 | ||
|  | 1fd822c3e2 | ||
|  | 0cf5b490ad | ||
|  | 93453ff402 | ||
|  | 0680e835a3 | ||
|  | 423be6e32c | ||
|  | 5757cc76f5 | ||
|  | 2c771a6efb | ||
|  | 3f1d54858c | ||
|  | e8a6fa3ac8 | ||
|  | b8c59a8c50 | ||
|  | 29f68bedf4 | ||
|  | 29897467cb | ||
|  | 7293626b43 | ||
|  | 77c745da22 | ||
|  | 6a26cd0cd7 | ||
|  | 6370d792bb | ||
|  | f19f23ead3 | ||
|  | 75c71cb200 | ||
|  | b916295a8e | ||
|  | 2c73f6616e | ||
|  | 12089dced6 | ||
|  | 12bbe691e8 | ||
|  | 48e694662d | ||
|  | 973b3b71a8 | ||
|  | f0d260d37a | ||
|  | 52ab0ee654 | ||
|  | 7f4bad3131 | ||
|  | beb63fec25 | ||
|  | 60b5f4401c | ||
|  | 551dca7540 | ||
|  | 0faa07e325 | ||
|  | d4423817bb | ||
|  | 6cc4bcf6ed | ||
|  | 09d5995915 | ||
|  | 5d0801ac21 | ||
|  | 6ed5ef69ad | ||
|  | f0babad995 | ||
|  | 5a4c6103e6 | ||
|  | 115ba62141 | ||
|  | 7b967a8540 | ||
|  | fd72e6a23f | ||
|  | 526d7b9209 | ||
|  | 85b606c208 | ||
|  | ebc94282cc | ||
|  | f360453843 | ||
|  | 893044f2e1 | ||
|  | da5e1a9221 | ||
|  | bf207e19ee | ||
|  | 3b794c3229 | ||
| b5983b00ae | |||
| 7af278b0f6 | |||
| e18188becc | |||
| f2aeeed36c | |||
| 4c426bb2ce | |||
|  | a9c7a55ace | ||
|  | ba43a5f135 | ||
|  | b699f6ff4f | ||
|  | 6d2b4888d6 | ||
|  | 432c0fdb90 | ||
|  | cb904385c3 | ||
|  | b45ad4a3c9 | ||
|  | 9b9a5cb1c7 | ||
|  | 8674a0c406 | ||
|  | 7c834349d9 | ||
|  | c2b186c328 | ||
|  | 11f7f6af35 | ||
|  | 9e26794b24 | ||
|  | 81068c24dd | ||
|  | c387fb1ea3 | ||
|  | 724421754a | ||
|  | e863829c5b | ||
|  | d7f6ac5270 | ||
|  | 025455eebd | ||
|  | f151ebbac7 | ||
|  | f42239c1c5 | ||
|  | 2c8a8a2136 | ||
|  | 5f23c94af8 | ||
|  | c04c89507c | ||
|  | c239698292 | ||
|  | c7edfa42e2 | ||
|  | 38361ee0a1 | ||
|  | 8c6a1d2349 | ||
|  | f3ce80b49e | ||
|  | f60dd5e01f | ||
|  | 94f6d25ee9 | ||
|  | 29cb1e4448 | ||
|  | 6fa86ccb8e | ||
|  | 845b19d8a8 | ||
|  | 522991f3d3 | ||
|  | 615ac2faa5 | ||
|  | 8c5ef4cdda | ||
|  | 3b8d858759 | ||
|  | 2e8be19e77 | ||
|  | a9e67623a0 | ||
|  | be25e7cebb | ||
|  | 07a5c3e774 | ||
|  | 8a50b67294 | ||
|  | 1b65ac7286 | ||
|  | c88fa5c6cc | ||
|  | ab510f09d0 | ||
|  | 1f3a5241e8 | ||
|  | 66a93b312d | ||
|  | 484991ceeb | ||
|  | fb8f81951a | ||
|  | 0357fa0940 | ||
|  | 1853839c81 | ||
|  | d87172a6c7 | ||
|  | 3f7875d945 | ||
|  | 11f9119607 | ||
|  | bc7161c806 | ||
|  | a93b30a565 | ||
|  | a9e84c9cf6 | ||
|  | db4fefd098 | ||
|  | 8455e6e24a | ||
|  | 5ef64873ad | ||
|  | 3eda5b324e | ||
|  | d30b483b56 | ||
|  | adadbe6480 | ||
|  | d32f60fd69 | ||
|  | 4af311d1de | ||
|  | 115a321f22 | ||
|  | 8daaf7e55b | ||
|  | 061d7e9b30 | ||
|  | 10d4c88886 | ||
|  | 812f158732 | ||
|  | 60cf307fd2 | ||
|  | e866b41f42 | ||
|  | 27920b8638 | ||
|  | 7a5882c618 | ||
|  | 152bf55233 | ||
|  | fbbd7aadd6 | ||
|  | d2bb350d1f | ||
|  | 803f8a4772 | ||
|  | 91cc8f6797 | ||
|  | 9fcc27a8fc | ||
|  | 89509848cc | ||
|  | a473aa91e0 | ||
|  | 268aa87ae7 | ||
|  | 1f242413f2 | ||
|  | 4d27ebdad0 | ||
|  | eb9b367d57 | ||
|  | 4c9455a85c | ||
|  | 8a539ab7e8 | ||
|  | 73a780c05e | ||
|  | 4fb1600b7a | ||
|  | 38b9f8f3c8 | ||
|  | 36ff4ab3e1 | ||
|  | f602984add | ||
|  | dd51424b45 | ||
|  | 173ab5bca7 | ||
|  | 782d060673 | ||
|  | 119663606c | ||
|  | 9ea36cba79 | ||
|  | b144189e8f | ||
|  | 1749a5bde5 | ||
|  | 0ab14fb757 | ||
|  | 3feb255563 | ||
|  | 223bf47bbf | ||
|  | b239b1ad4a | ||
|  | 6c3aaa7582 | ||
|  | 3bd796f26d | ||
|  | 88368d7000 | ||
|  | 43f81f1f0f | ||
|  | d99ccf44f5 | ||
|  | 91c91d963e | ||
|  | 5857fef0a4 | ||
|  | 901663a004 | ||
|  | 6f788e7ea0 | ||
|  | 3b4888544d | ||
|  | 05bd052689 | ||
|  | 6d7442ec37 | ||
|  | 74dfc82cfd | ||
|  | e8f1fe4da8 | ||
|  | 0b54056026 | ||
|  | b0dcff0ebe | ||
|  | 55bae8d0e4 | ||
|  | bcefa95305 | ||
|  | 27f5becebf | ||
|  | 57bde9ed14 | ||
|  | d01920d015 | ||
|  | 47407454ab | ||
|  | 94049fe776 | ||
|  | 6350b1abb9 | ||
|  | 36d37125dc | ||
|  | 3197b34dcc | ||
|  | b316ea7661 | ||
|  | 65aca68012 | ||
|  | dba4841906 | ||
|  | b76ba3b588 | ||
|  | f01d0f39b2 | ||
|  | ba03829018 | ||
|  | 7f0b19f3f0 | ||
|  | 018fd5c094 | ||
|  | 64750bf632 | ||
|  | 43d01c7e94 | ||
|  | ded932c002 | ||
|  | cf43abb95b | ||
|  | 60cc273b6f | ||
|  | 95bdb2671d | ||
|  | 4e6aa5a17f | ||
|  | 2a2a80f5c9 | ||
|  | 404b26e934 | ||
|  | e13a398e6e | ||
|  | f042951e79 | ||
|  | 09a0135703 | ||
|  | b5fb93adc5 | ||
|  | a0ebce751e | ||
|  | 8e1fedb603 | ||
|  | fc31c74666 | ||
|  | b7646379c4 | ||
|  | 3e61cfb498 | ||
|  | 3259431133 | ||
|  | d59b695ae0 | ||
|  | ba4fa56eda | ||
|  | e983fb9a67 | ||
|  | 12fa343316 | ||
|  | f1e01fd34a | ||
|  | e23d048a5c | ||
|  | a1dc77e206 | ||
|  | 2ed075302c | ||
|  | 1265207f9f | ||
|  | a48e350d2e | ||
|  | 70eeab4bc2 | ||
|  | 265035eb91 | ||
|  | 2a1e2d2a5c | ||
|  | 45ce327bcb | ||
|  | 798b93b3cb | ||
|  | 724118734d | ||
|  | 798b1fad73 | ||
|  | 5de8b3d568 | ||
|  | d6a3d7daf6 | ||
|  | 74fa627d75 | ||
|  | aa2612514e | ||
|  | ada192fa67 | ||
|  | 9acf0777c7 | ||
|  | 15d15ae659 | ||
|  | ad2a47bb56 | ||
|  | e666ee8547 | ||
|  | fdca180787 | ||
|  | 2caf1f7c9a | ||
|  | 99945b2c6d | ||
|  | af7b4c52f9 | ||
|  | adeab55230 | ||
|  | cafe80e2da | ||
|  | 9e091b2fee | ||
|  | d546d47f3d | ||
|  | c521c38af3 | ||
|  | 23db081c99 | ||
|  | 730d625e9c | ||
|  | a13ea7f804 | ||
|  | 2d81ed1b15 | ||
|  | 178879c329 | ||
|  | 8f5a5d1c38 | ||
|  | 06554e4cd6 | ||
|  | 7e48145889 | ||
|  | bbc8e5d95f | ||
|  | ac30d09e12 | ||
|  | 99dd363534 | ||
|  | 73d0c44356 | ||
|  | 15dc8ccc73 | ||
|  | dafa7e7d62 | ||
|  | 41c05f2eb0 | ||
|  | 8b79eb32d6 | ||
|  | 612908bacc | ||
|  | 11c0243521 | ||
|  | 757a4a7182 | ||
|  | c247da0854 | ||
|  | ed04004b30 | ||
|  | 3166fe09a0 | ||
|  | 6e9d3c89dd | ||
|  | 51d4ba7907 | ||
|  | 10d2feb600 | ||
|  | 024bb77f37 | ||
|  | 9d20cd57e2 | ||
|  | 6f8d1de072 | ||
|  | b9152917ce | ||
|  | 7392b320e6 | ||
|  | 2515d1ff07 | ||
|  | 520473c497 | ||
|  | 6f43e40510 | ||
|  | 7f7dbcdc11 | ||
|  | 0d20291973 | ||
|  | a6fc4490c4 | ||
|  | ef54d5e611 | ||
|  | 8465d3689c | ||
|  | c1a3d23d4e | ||
|  | f2391dc9c0 | ||
|  | c857850550 | ||
|  | 1f5c1bb5a5 | ||
|  | b6bb4477c8 | ||
|  | 06ba284f76 | ||
|  | 2e7215e9cc | ||
|  | d9eb5ced2c | ||
|  | 273ff4f90d | ||
|  | 86e378053e | ||
|  | d9788c214d | ||
|  | 7a10b684ee | ||
|  | 1d70b75f14 | ||
|  | 5a63dadc88 | ||
|  | f3f4374159 | ||
|  | 021348293f | ||
|  | 734f8ab79c | ||
|  | f216078eea | ||
|  | d8b13da38a | ||
|  | 4734c76dff | ||
|  | ec37f652c6 | ||
|  | 2d4bcdb918 | ||
|  | 00727a66f2 | ||
|  | 3fb3086be4 | ||
|  | ff5ae8884c | ||
|  | 31367c4f2b | ||
|  | d11123d0ae | ||
|  | 2bff4ceefc | ||
|  | 7a5edf572d | ||
|  | 796179f440 | ||
|  | f5ac457f56 | ||
|  | f8efc03341 | ||
|  | fee55eb9c6 | ||
|  | 6c7c9f5da6 | ||
|  | 78e6ad0292 | ||
|  | 21be21c53a | ||
|  | e3ef0a2cb7 | ||
|  | 11247a161a | ||
|  | 282b41a11f | ||
|  | b5d0a0a02c | ||
|  | a3dfe91a05 | ||
|  | 3d78a4f15c | ||
|  | 7e27d4b467 | ||
|  | 9eea7ba23a | ||
|  | 899430f4cd | ||
|  | 8b0751dd8f | ||
|  | df6ad8016e | ||
|  | 131ac90bdf | ||
|  | 0922aae4f1 | ||
|  | 8e663dc94e | ||
|  | c14d2c7e0f | ||
|  | 715b0e7396 | ||
|  | 226bc12071 | ||
|  | 93fa7005f7 | ||
|  | f85b24310b | ||
|  | 8ab0d46eaf | ||
|  | fc65a3a481 | ||
|  | 6a3f3b10f8 | ||
|  | 92ffbc1231 | ||
|  | 57093b06e4 | ||
|  | c420805ada | ||
|  | f914566c02 | ||
|  | 7ae663db75 | ||
|  | 909d24021a | ||
|  | 29113550bf | ||
|  | 71a711dae7 | ||
|  | 371da2cbc6 | ||
|  | 352adae52d | ||
|  | 69183cc38b | ||
|  | 8a1d74d57b | ||
|  | 9dfcf99125 | ||
|  | 853f5c7a05 | ||
|  | f841f2e462 | ||
|  | 1bc309e60b | ||
|  | 2101c42874 | ||
|  | a59667914b | ||
|  | b8aa27d5ef | ||
|  | 351b0582b2 | ||
|  | eda588e2e3 | ||
|  | cfb00174e3 | ||
|  | 21f5273b84 | ||
|  | 97b79400b6 | ||
|  | b42fa7e9ed | ||
|  | b0c57fbc6e | ||
|  | e0ddc13369 | ||
|  | 9221b97d91 | ||
|  | f189e13195 | ||
|  | c7454c23b4 | ||
|  | f448a9a12a | ||
|  | 047b4d6972 | ||
|  | edfed81029 | ||
|  | 73393e8bff | ||
|  | c7aadf184c | ||
|  | 7f8c3ff490 | ||
|  | 6470a2b52f | ||
|  | 6db67c6fcc | ||
|  | c7ccba8384 | ||
|  | 96db78522c | ||
|  | 9a3043c170 | ||
|  | fdd877f5e5 | ||
|  | 7040288003 | ||
|  | 9c71f94030 | ||
|  | ba01c46f41 | ||
|  | 7af36a0d8b | ||
|  | 93d1761e5d | ||
|  | 5cdd6b74a8 | ||
|  | 66844a46d8 | ||
|  | 6620540f62 | ||
|  | 4e7009f386 | ||
|  | 326262eb57 | ||
|  | 56634faaf9 | ||
|  | 6add4540a5 | ||
|  | 99d9e65dde | ||
|  | 9ec4c3568a | ||
|  | 24dfdac7b9 | ||
|  | a5431c1d77 | ||
|  | 93443d3812 | ||
|  | e329ae9b51 | ||
|  | ef5c05d1d5 | ||
|  | da1d271b72 | ||
|  | f9f75c4e34 | ||
|  | 2457845536 | ||
|  | bc8aae4e28 | ||
|  | 2f371a08bc | ||
|  | 8d2905428e | 
							
								
								
									
										28
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,28 @@ | ||||
| .DS_Store | ||||
| node_modules/ | ||||
| unpackage/ | ||||
| dist/ | ||||
| lib/ | ||||
| # local env files | ||||
| .env.local | ||||
| .env.*.local | ||||
|  | ||||
| # Log files | ||||
| npm-debug.log* | ||||
| yarn-debug.log* | ||||
| yarn-error.log* | ||||
|  | ||||
| # Editor directories and files | ||||
| .project | ||||
| .idea | ||||
| .vscode | ||||
| *.suo | ||||
| *.ntvs* | ||||
| *.njsproj | ||||
| *.sln | ||||
| *.sw* | ||||
| /package-lock.json | ||||
| /.hbuilderx/launch.json | ||||
| /src/pages.json | ||||
|  | ||||
| /src/config.json | ||||
							
								
								
									
										6
									
								
								.npmrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| registry=http://192.168.1.87:4873/ | ||||
| //registry=https://registry.npmjs.org | ||||
| email=aixianling@sinoecare.com | ||||
| always-auth=true | ||||
| //package-lock=false | ||||
| //192.168.1.87:4873/:_auth="YWRtaW46YWRtaW4xMjM=" | ||||
| @@ -1,3 +1,5 @@ | ||||
| # dvcp_v2_wechat_app | ||||
|  | ||||
| 村微2.0 小程序应用库 | ||||
| 村微2.0 小程序应用库 | ||||
|  | ||||
| ``如果出现cache-loader异常,可以考虑升级@vue/cli-service @vue/cli-plugin-babel到5.0`` | ||||
							
								
								
									
										63
									
								
								babel.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,63 @@ | ||||
| const plugins = [] | ||||
|  | ||||
| if (process.env.UNI_OPT_TREESHAKINGNG) { | ||||
|   plugins.push(require('@dcloudio/vue-cli-plugin-uni-optimize/packages/babel-plugin-uni-api/index.js')) | ||||
| } | ||||
|  | ||||
| if ( | ||||
|     ( | ||||
|         process.env.UNI_PLATFORM === 'app-plus' && | ||||
|         process.env.UNI_USING_V8 | ||||
|     ) || | ||||
|     ( | ||||
|         process.env.UNI_PLATFORM === 'h5' && | ||||
|         process.env.UNI_H5_BROWSER === 'builtin' | ||||
|     ) | ||||
| ) { | ||||
|   const path = require('path') | ||||
|  | ||||
|   const isWin = /^win/.test(process.platform) | ||||
|  | ||||
|   const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path) | ||||
|  | ||||
|   const input = normalizePath(process.env.UNI_INPUT_DIR) | ||||
|   try { | ||||
|     plugins.push([ | ||||
|       require('@dcloudio/vue-cli-plugin-hbuilderx/packages/babel-plugin-console'), | ||||
|       { | ||||
|         file (file) { | ||||
|           file = normalizePath(file) | ||||
|           if (file.indexOf(input) === 0) { | ||||
|             return path.relative(input, file) | ||||
|           } | ||||
|           return false | ||||
|         } | ||||
|       } | ||||
|     ]) | ||||
|   } catch (e) {} | ||||
| } | ||||
|  | ||||
| process.UNI_LIBRARIES = process.UNI_LIBRARIES || ['@dcloudio/uni-ui'] | ||||
| process.UNI_LIBRARIES.forEach(libraryName => { | ||||
|   plugins.push([ | ||||
|     'import', | ||||
|     { | ||||
|       'libraryName': libraryName, | ||||
|       'customName': (name) => { | ||||
|         return `${libraryName}/lib/${name}/${name}` | ||||
|       } | ||||
|     } | ||||
|   ]) | ||||
| }) | ||||
| module.exports = { | ||||
|   presets: [ | ||||
|     [ | ||||
|       '@vue/app', | ||||
|       { | ||||
|         modules: 'commonjs', | ||||
|         useBuiltIns: process.env.UNI_PLATFORM === 'h5' ? 'usage' : 'entry' | ||||
|       } | ||||
|     ] | ||||
|   ], | ||||
|   plugins | ||||
| } | ||||
							
								
								
									
										22
									
								
								bin/clean.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | ||||
| const fs = require("fs"); | ||||
| const fse = require("fs-extra") | ||||
| const path = require("path"); | ||||
| const getDirs = (dir, list = [], cb) => { | ||||
|   const dirs = fs.readdirSync(dir, {withFileTypes: true}) | ||||
|   dirs.map(d => { | ||||
|     if (d.isDirectory()) { | ||||
|       let p = path.join(dir, d.name) | ||||
|       list.push(p) | ||||
|       if (cb(d, p)) getDirs(p, list, cb) | ||||
|     } | ||||
|   }) | ||||
|   return list | ||||
| } | ||||
| getDirs(path.join(__dirname, '..', 'src'), [], (dir, path) => { | ||||
|   if (["apps"].includes(dir.name)) { | ||||
|     fse.remove(path) | ||||
|     console.log("已清除%s", path) | ||||
|   } | ||||
|   return !["apps"].includes(dir.name) | ||||
| }) | ||||
| fse.remove(path.join(__dirname, '..', 'lib')) | ||||
							
								
								
									
										16
									
								
								bin/lib.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,16 @@ | ||||
| const {findApp, chalkTag, copyFiles} = require("./tools"); | ||||
| const start = () => { | ||||
|   chalkTag.info("扫描主库目录,并搬运打包应用至lib文件夹下") | ||||
|   let apps = [] | ||||
|   findApp('src/mods', file => apps.push(file)) | ||||
|   .then(() => Promise.all([...new Set(apps)].map(e => { | ||||
|     let name = e.replace(/.+[\\\/]([^\\\/]+)$/, '$1') | ||||
|     if (/^App/.test(name)) { | ||||
|       return copyFiles(`lib/${name}`, e) | ||||
|     } | ||||
|   }))) | ||||
|   .then(() => { | ||||
|     chalkTag.done("打包完成") | ||||
|   }) | ||||
| } | ||||
| start() | ||||
							
								
								
									
										75
									
								
								bin/pages.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,75 @@ | ||||
| const {chalkTag, findPages, fsExtra, fs} = require("./tools"); | ||||
| const PageBase = require("dvcp-wui/utils/PageBase"); | ||||
| let apps = {list: [], desc: "用于产品库主页面获取应用使用", type: "mp"} | ||||
| const getFileInfo = (app, file) => { | ||||
|   if (/^App/.test(app.name)) { | ||||
|     let {name, label} = app, | ||||
|       path = app.path.replace(/.+[\\\/]([^\\\/]+)[\\\/]([^\\\/]+)$/g, `/mods/$1/$2`) | ||||
|     apps.list.push({ | ||||
|       id: file.replace(/\.\/?(vue)?/g, '')?.replace(/[\\\/]/g, '_'), | ||||
|       name, | ||||
|       label, | ||||
|       path, | ||||
|       libPath: file?.replace(/\\/g, '/')?.replace(/^src(\/.+)\.vue/, '$1'), | ||||
|       type: 'mp' | ||||
|     }) | ||||
|   } | ||||
| } | ||||
| const start = () => { | ||||
|   chalkTag.info('开始生成pages.json...') | ||||
|   let json = { | ||||
|     easycom: { | ||||
|       "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue", | ||||
|       "^(Ai|V)(.*)": "@/components/$1$2/$1$2.vue", | ||||
|     }, | ||||
|     pages: [ | ||||
|       {path: 'pages/home', style: {navigationBarTitleText: "小程序应用库"}} | ||||
|     ], | ||||
|     subPackages: [ | ||||
|       {root: "mods/", pages: []}, | ||||
|       {root: "components/pages/", pages: []}, | ||||
|       {root: "project/", pages: []}, | ||||
|     ], | ||||
|     globalStyle: { | ||||
|       pageOrientation: "auto", | ||||
|       navigationBarTextStyle: "white", | ||||
|       navigationBarBackgroundColor: "#4181FF", | ||||
|       "mp-weixin": { | ||||
|         "usingComponents": { | ||||
|           "cell": "plugin://materialPlugin/cell", | ||||
|           "qplayer": "plugin://player/video" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   Promise.all([ | ||||
|     findPages('src/components/pages', file => { | ||||
|       if (/.+\\pages\\[^\\]+\.vue/g.test(file)) { | ||||
|         const app = new PageBase(file.replace(/^src\\components\\pages\\(.*).vue/g, '$1').replace(/\\/g, '/'), fs.readFileSync(file).toString()) | ||||
|         getFileInfo(app, file) | ||||
|         return json.subPackages[1].pages.push(app) | ||||
|       } | ||||
|     }), | ||||
|     findPages('src/mods', file => { | ||||
|       if (/.+\\App[^\\]+\\[^\\]+\.vue/g.test(file)) { | ||||
|         const app = new PageBase(file.replace(/^src\\mods\\(.*).vue/g, '$1').replace(/\\/g, '/'), fs.readFileSync(file).toString()) | ||||
|         getFileInfo(app, file) | ||||
|         return json.subPackages[0].pages.push(app) | ||||
|       } | ||||
|     }), | ||||
|     findPages('src/project', file => { | ||||
|       if (/.+\\App[^\\]+\\[^\\]+\.vue/g.test(file)) { | ||||
|         const app = new PageBase(file.replace(/^src\\project\\(.*).vue/g, '$1').replace(/\\/g, '/'), fs.readFileSync(file).toString()) | ||||
|         getFileInfo(app, file) | ||||
|         return json.subPackages[2].pages.push(app) | ||||
|       } | ||||
|     }) | ||||
|   ]).then(() => { | ||||
|     fsExtra.outputJson('src/config.json', {apps: apps.list}) | ||||
|     fsExtra.outputJson('src/pages.json', json, () => { | ||||
|       chalkTag.done('生成pages.json') | ||||
|     }) | ||||
|   }) | ||||
| } | ||||
|  | ||||
| start(); | ||||
							
								
								
									
										52
									
								
								bin/sync.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,52 @@ | ||||
| const {chalkTag, fs, findPages} = require("./tools"); | ||||
| const axios = require("axios"); | ||||
| const PageBase = require("dvcp-wui/utils/PageBase"); | ||||
|  | ||||
| let apps = {list: [], desc: "用于产品库主页面获取应用使用", type: 'mp'} | ||||
| const saveApps = app => { | ||||
|   if (app.list.length > 0) { | ||||
|     return axios.post("http://192.168.1.87:12525/node/wechatapps/addOrUpdate", app, {timeout: 1000}).then(res => { | ||||
|       if (res.data.code == 0) chalkTag.done("产品库目录已同步至后台数据库...") | ||||
|     }).catch(err => { | ||||
|       console.log(err) | ||||
|     }) | ||||
|   } | ||||
| } | ||||
| const getFileInfo = (app, file) => { | ||||
|   if (/^App/.test(app.name) && app.label) { | ||||
|     let {name, label} = app, | ||||
|         path = app.path.replace(/.+[\\\/]([^\\\/]+)[\\\/]([^\\\/]+)$/g, `/mods/$1/$2`) | ||||
|     apps.list.push({ | ||||
|       id: file.replace(/\.\/?(vue)?/g, '').replace(/[\\\/]/g, '_'), | ||||
|       name, | ||||
|       label, | ||||
|       path, | ||||
|       libPath: file.replace(/[\\\/]/g, '/').replace(/^src(\/.+)\.vue/, '$1'), | ||||
|       type: 'mp' | ||||
|     }) | ||||
|   } | ||||
| } | ||||
| const start = () => { | ||||
|   chalkTag.info('开始同步数据到数据库') | ||||
|   Promise.all([ | ||||
|     findPages('src/components/pages', file => { | ||||
|       if (/.+[\\\/]pages[\\\/][^\\\/]+\.vue/g.test(file)) { | ||||
|         const app = new PageBase(file.replace(/^src[\\\/]components[\\\/]pages[\\\/](.*).vue/g, '$1').replace(/[\\\/]/g, '/'), fs.readFileSync(file).toString()) | ||||
|         return getFileInfo(app, file) | ||||
|       } | ||||
|     }), | ||||
|     findPages('src/mods', file => { | ||||
|       if (/.+[\\\/]App[^\\\/]+[\\\/][^\\\/]+\.vue/g.test(file)) { | ||||
|         const app = new PageBase(file.replace(/^src[\\\/]mods[\\\/](.*).vue/g, '$1').replace(/[\\\/]/g, '/'), fs.readFileSync(file).toString()) | ||||
|         return getFileInfo(app, file) | ||||
|       } | ||||
|     }), | ||||
|     findPages('src/project', file => { | ||||
|       if (/.+[\\\/]App[^\\\/]+[\\\/][^\\\/]+\.vue/g.test(file)) { | ||||
|         const app = new PageBase(file.replace(/^src[\\\/]project[\\\/](.*).vue/g, '$1').replace(/[\\\/]/g, '/'), fs.readFileSync(file).toString()) | ||||
|         return getFileInfo(app, file) | ||||
|       } | ||||
|     }) | ||||
|   ]).then(() => saveApps(apps)).finally(() => chalkTag.done('同步完成')) | ||||
| } | ||||
| start() | ||||
							
								
								
									
										85
									
								
								bin/tools.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,85 @@ | ||||
| const fsExtra = require('fs-extra') | ||||
| const path = require('path') | ||||
| const chalk = require('chalk') | ||||
| const fs = require('fs') | ||||
| /** | ||||
|  * 将函数封装成promise | ||||
|  */ | ||||
| const promisify = fn => { | ||||
|   return function () { | ||||
|     let args = arguments; | ||||
|     return new Promise(function (resolve, reject) { | ||||
|       [].push.call(args, function (err, result) { | ||||
|         if (err) { | ||||
|           console.log(err) | ||||
|           reject(err); | ||||
|         } else { | ||||
|           resolve(result); | ||||
|         } | ||||
|       }); | ||||
|       fn.apply(null, args); | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  | ||||
| const readdir = promisify(fs.readdir) | ||||
| const stat = promisify(fs.stat) | ||||
|  | ||||
| /** | ||||
|  * 封装打印工具 | ||||
|  */ | ||||
| const {log} = console | ||||
| const chalkTag = { | ||||
|   info: msg => log([chalk.bgBlue.black(' INFO '), msg].join(' ')), | ||||
|   done: msg => log([chalk.bgGreen.black(' DONE '), msg].join(' ')), | ||||
|   warn: msg => log([chalk.bgYellow.black(' WARN '), msg].join(' ')), | ||||
|   error: msg => log([chalk.bgRed.black(' ERROR '), msg].join(' ')), | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 遍历应用的方法 | ||||
|  */ | ||||
| const findApp = (dir, cb) => { | ||||
|   fsExtra.ensureDirSync(dir) | ||||
|   return readdir(dir).then(apps => { | ||||
|     return Promise.all(apps.map(e => { | ||||
|       let cPath = path.join(dir, e) | ||||
|       return stat(cPath).then(state => { | ||||
|         if (state.isDirectory()) { | ||||
|           return findApp(cPath, cb) | ||||
|         } else if (state.isFile()) { | ||||
|           cb && cb(dir) | ||||
|         } | ||||
|       }) | ||||
|     }) || []) | ||||
|   }) | ||||
| } | ||||
| const findPages = (dir, cb) => { | ||||
|   fsExtra.ensureDirSync(dir) | ||||
|   return readdir(dir).then(apps => { | ||||
|     return Promise.all(apps.map(e => { | ||||
|       let cPath = path.join(dir, e) | ||||
|       return stat(cPath).then(state => { | ||||
|         if (state.isDirectory()) { | ||||
|           return findPages(cPath, cb) | ||||
|         } else if (state.isFile()) { | ||||
|           cb && cb(cPath) | ||||
|         } | ||||
|       }) | ||||
|     }) || []) | ||||
|   }) | ||||
| } | ||||
| const copyFiles = (dir, source = 'src/mods') => { | ||||
|   chalkTag.info(`开始扫描${source}...`) | ||||
|   return new Promise(resolve => { | ||||
|     fsExtra.emptyDir(dir, err => { | ||||
|       if (!err) { | ||||
|         fsExtra.copy(source, dir).then(() => { | ||||
|           chalkTag.done(source + ' 扫描完毕') | ||||
|           resolve() | ||||
|         }) | ||||
|       } | ||||
|     }) | ||||
|   }) | ||||
| } | ||||
| module.exports = {findApp, chalkTag, fsExtra, copyFiles, fs, path, findPages} | ||||
							
								
								
									
										14
									
								
								jest.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,14 @@ | ||||
| module.exports = { | ||||
|   globalTeardown: '@dcloudio/uni-automator/dist/teardown.js', | ||||
|   testEnvironment: '@dcloudio/uni-automator/dist/environment.js', | ||||
|   testEnvironmentOptions: {}, | ||||
|   testTimeout: 15000, | ||||
|   reporters: [ | ||||
|     'default' | ||||
|   ], | ||||
|   watchPathIgnorePatterns: ['/node_modules/', '/dist/', '/.git/'], | ||||
|   moduleFileExtensions: ['js', 'json'], | ||||
|   rootDir: __dirname, | ||||
|   testMatch: ['<rootDir>/src/__tests__/**/*spec.[jt]s?(x)'], | ||||
|   testPathIgnorePatterns: ['/node_modules/'] | ||||
| } | ||||
							
								
								
									
										88
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,88 @@ | ||||
| { | ||||
|   "name": "dvcp-wechat-apps", | ||||
|   "version": "1.0.0", | ||||
|   "private": false, | ||||
|   "author": "Kubbo", | ||||
|   "scripts": { | ||||
|     "dev": "node bin/pages.js&&cross-env NODE_ENV=development VUE_APP_CW_MODE=dev UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch", | ||||
|     "pages": "node bin/pages.js", | ||||
|     "lib": "npm publish -ws||(npm unpublish -ws -f&&npm publish -ws)", | ||||
|     "clean": "node bin/clean.js", | ||||
|     "sync": "node bin/sync.js", | ||||
|     "info": "node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js" | ||||
|   }, | ||||
|   "files": [ | ||||
|     "lib" | ||||
|   ], | ||||
|   "workspaces": [ | ||||
|     "src/components", | ||||
|     "src" | ||||
|   ], | ||||
|   "dependencies": { | ||||
|     "@dcloudio/uni-app": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-app-plus": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-h5": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-i18n": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-mp-360": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-mp-alipay": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-mp-baidu": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-mp-jd": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-mp-kuaishou": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-mp-lark": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-mp-qq": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-mp-toutiao": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-mp-vue": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-mp-weixin": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-mp-xhs": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-quickapp-native": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-quickapp-webview": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-stacktracey": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-stat": "^2.0.2-4010520240507001", | ||||
|     "@vue/shared": "^3.0.0", | ||||
|     "axios": "^0.19.2", | ||||
|     "axios-miniprogram-adapter": "^0.3.2", | ||||
|     "core-js": "^3.8.3", | ||||
|     "dayjs": "^1.9.5", | ||||
|     "dvcp-wui": "^1.0.1", | ||||
|     "flyio": "^0.6.2", | ||||
|     "query-string": "^7.1.1", | ||||
|     "regenerator-runtime": "^0.12.1", | ||||
|     "swiper": "^11.1.4", | ||||
|     "uview-ui": "^1.8.8", | ||||
|     "vue": ">= 2.6.14 < 2.7", | ||||
|     "vuex": "^3.2.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@dcloudio/types": "^3.3.2", | ||||
|     "@dcloudio/uni-automator": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-cli-i18n": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-cli-shared": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-helper-json": "*", | ||||
|     "@dcloudio/uni-migration": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/uni-template-compiler": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/vue-cli-plugin-uni": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/webpack-uni-mp-loader": "^2.0.2-4010520240507001", | ||||
|     "@dcloudio/webpack-uni-pages-loader": "^2.0.2-4010520240507001", | ||||
|     "@vue/cli-plugin-babel": "~5.0.0", | ||||
|     "@vue/cli-service": "~5.0.0", | ||||
|     "babel-plugin-import": "^1.11.0", | ||||
|     "cross-env": "^7.0.2", | ||||
|     "fs-extra": "^11.1.0", | ||||
|     "jest": "^25.4.0", | ||||
|     "mini-types": "^0.1.4", | ||||
|     "miniprogram-api-typings": "^3.1.6", | ||||
|     "postcss-comment": "^2.0.0", | ||||
|     "sass": "^1.45.1", | ||||
|     "vue-template-compiler": ">= 2.6.14 < 2.7", | ||||
|     "vuex-persistedstate": "^3.1.0" | ||||
|   }, | ||||
|   "browserslist": [ | ||||
|     "Android >= 4.4", | ||||
|     "ios >= 9" | ||||
|   ], | ||||
|   "uni-app": { | ||||
|     "scripts": {} | ||||
|   } | ||||
| } | ||||
							
								
								
									
										22
									
								
								postcss.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | ||||
| const path = require('path') | ||||
| module.exports = { | ||||
|   parser: require('postcss-comment'), | ||||
|   plugins: [ | ||||
|     require('postcss-import')({ | ||||
|       resolve (id, basedir, importOptions) { | ||||
|         if (id.startsWith('~@/')) { | ||||
|           return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3)) | ||||
|         } else if (id.startsWith('@/')) { | ||||
|           return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2)) | ||||
|         } else if (id.startsWith('/') && !id.startsWith('//')) { | ||||
|           return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1)) | ||||
|         } | ||||
|         return id | ||||
|       } | ||||
|     }), | ||||
|     require('autoprefixer')({ | ||||
|       remove: process.env.UNI_PLATFORM !== 'h5' | ||||
|     }), | ||||
|     require('@dcloudio/vue-cli-plugin-uni/packages/postcss') | ||||
|   ] | ||||
| } | ||||
							
								
								
									
										27
									
								
								public/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,27 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="zh-CN"> | ||||
|  | ||||
|     <head> | ||||
|         <meta charset="utf-8"> | ||||
|         <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||||
|         <title> | ||||
|             <%= htmlWebpackPlugin.options.title %> | ||||
|         </title> | ||||
|         <script> | ||||
|             document.addEventListener('DOMContentLoaded', function() { | ||||
|                 document.documentElement.style.fontSize = document.documentElement.clientWidth / 20 + 'px' | ||||
|             }) | ||||
|             var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)')) | ||||
|             document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />') | ||||
|         </script> | ||||
|         <link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" /> | ||||
|     </head> | ||||
|     <body> | ||||
|         <noscript> | ||||
|             <strong>Please enable JavaScript to continue.</strong> | ||||
|         </noscript> | ||||
|         <div id="app"></div> | ||||
|         <!-- built files will be auto injected --> | ||||
|     </body> | ||||
|  | ||||
| </html> | ||||
							
								
								
									
										154
									
								
								src/App.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,154 @@ | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|   onLaunch() { | ||||
|     if (uni.getUpdateManager) { | ||||
|       const updateManager = uni.getUpdateManager() | ||||
|       if (updateManager) { | ||||
|         updateManager.onUpdateReady(() => { | ||||
|           this.$dialog.alert({ | ||||
|             title: '更新提示', | ||||
|             content: '新版本已经准备好,点击确认按钮重启应用!' | ||||
|           }).then(() => { | ||||
|             updateManager.applyUpdate() | ||||
|           }).catch(() => { | ||||
|           }) | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| @import "~dvcp-wui/common"; | ||||
| /* #ifdef MP-BAIDU */ | ||||
| page { | ||||
|   width: 100%; | ||||
|   display: block; | ||||
| } | ||||
|  | ||||
| swan-template { | ||||
|   width: 100%; | ||||
|   min-height: 100%; | ||||
|   display: flex; | ||||
| } | ||||
|  | ||||
| /* 原生组件模式下需要注意组件外部样式 */ | ||||
| custom-component { | ||||
|   width: 100%; | ||||
|   min-height: 100%; | ||||
|   display: flex; | ||||
| } | ||||
|  | ||||
| /* #endif */ | ||||
|  | ||||
| /* #ifdef MP-ALIPAY */ | ||||
| page { | ||||
|   min-height: 100vh; | ||||
| } | ||||
|  | ||||
| /* #endif */ | ||||
|  | ||||
| /* 原生组件模式下需要注意组件外部样式 */ | ||||
| m-input { | ||||
|   width: 100%; | ||||
|   /* min-height: 100%; */ | ||||
|   display: flex; | ||||
|   flex: 1; | ||||
| } | ||||
|  | ||||
| .content { | ||||
|   display: flex; | ||||
|   flex: 1; | ||||
|   flex-direction: column; | ||||
|   background-color: #efeff4; | ||||
|   padding: 10px; | ||||
|   box-sizing: border-box; | ||||
| } | ||||
|  | ||||
| .input-group { | ||||
|   background-color: #ffffff; | ||||
|   margin-top: 20px; | ||||
|   position: relative; | ||||
| } | ||||
|  | ||||
| .input-group::before { | ||||
|   position: absolute; | ||||
|   right: 0; | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   height: 1px; | ||||
|   content: ""; | ||||
|   -webkit-transform: scaleY(0.5); | ||||
|   transform: scaleY(0.5); | ||||
|   background-color: #c8c7cc; | ||||
| } | ||||
|  | ||||
| .input-group::after { | ||||
|   position: absolute; | ||||
|   right: 0; | ||||
|   bottom: 0; | ||||
|   left: 0; | ||||
|   height: 1px; | ||||
|   content: ""; | ||||
|   -webkit-transform: scaleY(0.5); | ||||
|   transform: scaleY(0.5); | ||||
|   background-color: #c8c7cc; | ||||
| } | ||||
|  | ||||
| .input-row { | ||||
|   display: flex; | ||||
|   flex-direction: row; | ||||
|   position: relative; | ||||
|   font-size: 18px; | ||||
|   line-height: 40px; | ||||
| } | ||||
|  | ||||
| .input-row .title { | ||||
|   width: 72px; | ||||
|   padding-left: 15px; | ||||
| } | ||||
|  | ||||
| .input-row.border::after { | ||||
|   position: absolute; | ||||
|   right: 0; | ||||
|   bottom: 0; | ||||
|   left: 8px; | ||||
|   height: 1px; | ||||
|   content: ""; | ||||
|   -webkit-transform: scaleY(0.5); | ||||
|   transform: scaleY(0.5); | ||||
|   background-color: #c8c7cc; | ||||
| } | ||||
|  | ||||
| uni-tabbar .uni-tabbar-border { | ||||
|   position: absolute; | ||||
|   left: 0; | ||||
|   top: 0; | ||||
|   width: 100%; | ||||
|   height: 0; | ||||
|   -webkit-transform: scaleY(0.5); | ||||
|   transform: scaleY(0.5); | ||||
| } | ||||
|  | ||||
| .btn-row { | ||||
|   margin-top: 25px; | ||||
|   padding: 10px; | ||||
| } | ||||
|  | ||||
| button.primary { | ||||
|   background-color: #0faeff; | ||||
| } | ||||
|  | ||||
| .flexRow { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
| } | ||||
|  | ||||
| .u-input__right-icon { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   margin-right: 8px; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										69
									
								
								src/components/AiAdd/AiAdd.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,69 @@ | ||||
| <template> | ||||
|   <movable-area class="movableArea"> | ||||
|     <movable-view direction="all" x="300" y="500"> | ||||
|       <div class="AiAdd" @click.stop="add"></div> | ||||
|     </movable-view> | ||||
|   </movable-area> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiAdd", | ||||
|   props: {}, | ||||
|   data() { | ||||
|     return {} | ||||
|   }, | ||||
|   methods: { | ||||
|     add() { | ||||
|       console.log(789) | ||||
|       this.$emit("add") | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .movableArea { | ||||
|   position: fixed; | ||||
|   left: 0; | ||||
|   top: 0; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   pointer-events: none; | ||||
|   z-index: 999; | ||||
|  | ||||
|   uni-movable-view { | ||||
|     pointer-events: auto; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .AiAdd { | ||||
|   width: 96px; | ||||
|   height: 96px; | ||||
|   background: #1365DD; | ||||
|   box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); | ||||
|   border-radius: 50%; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   flex-direction: column; | ||||
|   justify-content: center; | ||||
|  | ||||
|   &:before, &:after { | ||||
|     content: ""; | ||||
|     background: #FFFFFF; | ||||
|     display: block; | ||||
|     position: absolute; | ||||
|     border-radius: 4px; | ||||
|   } | ||||
|  | ||||
|   &:before { | ||||
|     height: 48px; | ||||
|     width: 4px; | ||||
|   } | ||||
|  | ||||
|   &:after { | ||||
|     height: 4px; | ||||
|     width: 48px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										146
									
								
								src/components/AiAreaPicker/AiAreaPicker.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,146 @@ | ||||
| <template> | ||||
|   <section class="AiAreaPicker"> | ||||
|     <div @tap="handleJump"> | ||||
|       <slot v-if="$slots.default"/> | ||||
|       <div v-else-if="isForm"> | ||||
|         <ai-more v-model="areaName"/> | ||||
|       </div> | ||||
|       <div v-else class="areaBtn"> | ||||
|         <image :src="locationIcon" class="location"/> | ||||
|         <div v-text="areaName"/> | ||||
|       </div> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
| import AiMore from "../AiMore/AiMore"; | ||||
| import qs from "query-string" | ||||
|  | ||||
| export default { | ||||
|   name: 'AiAreaPicker', | ||||
|   components: {AiMore}, | ||||
|   model: { | ||||
|     prop: "value", | ||||
|     event: "input" | ||||
|   }, | ||||
|   props: { | ||||
|     areaId: {default: ''}, | ||||
|     name: {default: ''}, | ||||
|     value: {default: ''}, | ||||
|     all: Boolean, | ||||
|     icon: {default: "location.svg"}, | ||||
|     isForm: Boolean, | ||||
|     valueLevel: {default: 5}, | ||||
|     fullName: {default: ''}, | ||||
|     disabled: Boolean, | ||||
|     selectRoot: {default: true} | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     dataRange() { | ||||
|       let rules = [10, 8, 6, 3, 0], | ||||
|           level = 0 | ||||
|       if (this.all || this.disabled) return (level = 0) | ||||
|       rules.some((e, i) => { | ||||
|         let reg = new RegExp(`0{${e}}`, 'g') | ||||
|         if (reg.test(this.root)) { | ||||
|           return (level = i) | ||||
|         } | ||||
|       }) | ||||
|       return level | ||||
|     }, | ||||
|     root() { | ||||
|       return this.areaId || this.$areaId | ||||
|     }, | ||||
|     locationIcon() { | ||||
|       return this.$cdn + this.icon | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       fullArea: [], | ||||
|       areaName: "" | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     root(v) { | ||||
|       v && (this.getFullArea(v)) | ||||
|     }, | ||||
|     value(v) { | ||||
|       v && !this.areaName && this.getAreaName(this.value) | ||||
|     }, | ||||
|     fullArea(v) { | ||||
|       v && this.$emit('update:fullName', v?.map(e => e.name)?.join("") || "") | ||||
|     }, | ||||
|     areaName(v) { | ||||
|       v && this.$emit('update:name', v) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.value && this.getAreaName(this.value) | ||||
|   }, | ||||
|   methods: { | ||||
|     getInfo(areaId) { | ||||
|       return areaId && this.$instance.post('/admin/area/getAllParentAreaId', null, { | ||||
|         withoutToken: true, | ||||
|         params: {areaId}, | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           return res.data.reverse() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getFullArea(areaId) { | ||||
|       return this.fullArea?.length > 0 ? Promise.resolve(this.fullArea) : this.getInfo(areaId).then(meta => { | ||||
|         if (meta.length > 1) { | ||||
|           this.fullArea = meta.slice(this.dataRange) | ||||
|         } else { | ||||
|           this.fullArea = meta | ||||
|         } | ||||
|         return this.fullArea | ||||
|       }) | ||||
|     }, | ||||
|     handleJump() { | ||||
|       if (!this.disabled) { | ||||
|         uni.$once('selectArea', data => { | ||||
|           if (data?.id) { | ||||
|             this.$emit("input", data.id) | ||||
|             this.areaName = data.name | ||||
|             this.fullArea = data.fullArea | ||||
|             this.$forceUpdate() | ||||
|           } | ||||
|         }) | ||||
|         let {value, all, valueLevel, selectRoot, areaId} = this | ||||
|         let url = qs.stringifyUrl({ | ||||
|           url: "/components/pages/selectArea", query: {...this.$attrs, value, all, valueLevel, selectRoot, areaId} | ||||
|         }) | ||||
|         uni.navigateTo({url}) | ||||
|       } | ||||
|     }, | ||||
|     getAreaName(area, name) { | ||||
|       name ? this.areaName = name : this.getFullArea(area).then(list => { | ||||
|         let arr = JSON.parse(JSON.stringify(list)) | ||||
|         this.areaName = arr?.reverse()?.[0]?.name | ||||
|       }) | ||||
|     }, | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiAreaPicker { | ||||
|  | ||||
|   .areaBtn { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|   } | ||||
|  | ||||
|   .location { | ||||
|     width: 28px; | ||||
|     height: 80px; | ||||
|     margin-right: 12px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										87
									
								
								src/components/AiBack/AiBack.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,87 @@ | ||||
| <template> | ||||
|   <div v-if="btn" class="AiBack" @click.stop="back"> | ||||
|     <img :src="$cdn + 'home/back.png'" alt=""> | ||||
|     <text>返回</text> | ||||
|   </div> | ||||
|   <ai-fixed-btn v-else-if="!isTopPage||custom"> | ||||
|     <div class="AiBack" @click.stop="back"> | ||||
|       <img :src="$cdn + 'home/back.png'" alt=""> | ||||
|       <text>返回</text> | ||||
|     </div> | ||||
|   </ai-fixed-btn> | ||||
| </template> | ||||
| <script> | ||||
| import AiFixedBtn from "./AiFixedBtn"; | ||||
|  | ||||
| export default { | ||||
|   name: "AiBack", | ||||
|   components: {AiFixedBtn}, | ||||
|   inject: {root: {}}, | ||||
|   props: { | ||||
|     delta: { | ||||
|       type: Number, | ||||
|       default: 1 | ||||
|     }, | ||||
|     eventName: { | ||||
|       type: String, | ||||
|       default: '' | ||||
|     }, | ||||
|     data: { | ||||
|       type: Object | Boolean, | ||||
|       default: () => { | ||||
|       } | ||||
|     }, | ||||
|     custom: Boolean, | ||||
|     visible: Boolean, | ||||
|     btn: Boolean | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       isTopPage: false | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     back() { | ||||
|       if (this.visible) { | ||||
|         return this.$parent.$emit(this.eventName, this.data) | ||||
|       } else if (this.custom) { | ||||
|         this.$emit("back") | ||||
|       } else if (this.custom) { | ||||
|       } else uni.navigateBack({ | ||||
|         success: () => { | ||||
|           uni.$emit(this.eventName, this.data) | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.isTopPage = window.history.length <= 1 | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiBack { | ||||
|   width: 108px; | ||||
|   height: 108px; | ||||
|   background: #6BA1F9; | ||||
|   box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.12); | ||||
|   border-radius: 50%; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   flex-direction: column; | ||||
|   justify-content: center; | ||||
|  | ||||
|   img { | ||||
|     width: 40px; | ||||
|     height: 40px; | ||||
|   } | ||||
|  | ||||
|   text { | ||||
|     font-size: 26px; | ||||
|     font-weight: 800; | ||||
|     color: #FFFFFF; | ||||
|     line-height: 40px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										118
									
								
								src/components/AiCard/AiCard.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,118 @@ | ||||
| <template> | ||||
|   <section class="AiCard"> | ||||
|     <div flex v-if="$slots.custom" class="start"> | ||||
|       <div class="fill"> | ||||
|         <slot name="custom"/> | ||||
|       </div> | ||||
|       <div v-if="$slots.menu" class="iconfont iconfont-iconMore" @tap.stop="handleMore"/> | ||||
|     </div> | ||||
|     <template v-else> | ||||
|       <u-row> | ||||
|         <div class="content"> | ||||
|           <slot/> | ||||
|         </div> | ||||
|         <div btn @tap="$emit('send')">发送</div> | ||||
|       </u-row> | ||||
|       <u-row justify="space-between"> | ||||
|         <slot v-if="$slots.title" name="title"/> | ||||
|         <div v-else>{{ cardTitle }}</div> | ||||
|         <div v-if="$slots.menu" class="iconfont iconfont-iconMore" @tap.stop="handleMore"/> | ||||
|       </u-row> | ||||
|     </template> | ||||
|     <div v-if="menu" class="mask" @click.stop="handleClose"> | ||||
|       <div class="moreMenu" :style="menuPos"> | ||||
|         <slot name="menu"/> | ||||
|       </div> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiCard", | ||||
|   props: { | ||||
|     cardTitle: String | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       menuPos: {}, | ||||
|       menu: false | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     handleMore({detail}) { | ||||
|       this.menuPos = { | ||||
|         left: detail.x - 10 + 'px', | ||||
|         top: detail.y + 'px' | ||||
|       } | ||||
|       this.menu = !this.menu | ||||
|     }, | ||||
|     handleClose() { | ||||
|       this.menu = false | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiCard { | ||||
|   width: 100%; | ||||
|   background: #FFFFFF; | ||||
|   box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02); | ||||
|   border-radius: 8px; | ||||
|   padding: 20px; | ||||
|   box-sizing: border-box; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   color: #999; | ||||
|   font-size: 26px; | ||||
|   flex-shrink: 0; | ||||
|  | ||||
|   .content { | ||||
|     background: #F9F9F9; | ||||
|     border-radius: 4px; | ||||
|     min-height: 120px; | ||||
|     flex: 1; | ||||
|     min-width: 0; | ||||
|     margin-bottom: 26px; | ||||
|     padding: 20px; | ||||
|     box-sizing: border-box; | ||||
|     color: #333; | ||||
|   } | ||||
|  | ||||
|   .u-row { | ||||
|     flex-wrap: nowrap; | ||||
|   } | ||||
|  | ||||
|   div[btn] { | ||||
|     color: #1365DD; | ||||
|     padding: 0 0 0 18px; | ||||
|     cursor: pointer; | ||||
|   } | ||||
|  | ||||
|   .iconfont-iconMore { | ||||
|     font-size: 38px; | ||||
|     transform: rotate(90deg); | ||||
|   } | ||||
|  | ||||
|   .moreMenu { | ||||
|     position: fixed; | ||||
|     background: #FFFFFF; | ||||
|     box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.1); | ||||
|     border-radius: 4px; | ||||
|     transform: translate(-100%, -100%); | ||||
|     min-width: 100px; | ||||
|     min-height: 100px; | ||||
|     z-index: 9; | ||||
|   } | ||||
|  | ||||
|   .mask { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     bottom: 0; | ||||
|     left: 0; | ||||
|     right: 0; | ||||
|     z-index: 11; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										76
									
								
								src/components/AiCell/AiCell.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,76 @@ | ||||
| <template> | ||||
|   <section class="AiCell" :class="{bottomBorder,alignCenter,topLabel}"> | ||||
|     <div class="label" :class="{title}"> | ||||
|       <slot v-if="$slots.label" name="label"/> | ||||
|       <span v-else>{{ label }}</span> | ||||
|     </div> | ||||
|     <div class="content" :class="{topLabel}"> | ||||
|       <slot/> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiCell", | ||||
|   props: { | ||||
|     label: {default: ""}, | ||||
|     bottomBorder: Boolean, | ||||
|     topLabel: Boolean, | ||||
|     title: Boolean, | ||||
|     alignCenter: Boolean | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiCell { | ||||
|   display: flex; | ||||
|   min-height: 72px; | ||||
|   font-size: 30px; | ||||
|   color: #333; | ||||
|   padding: 14px 0; | ||||
|   box-sizing: border-box; | ||||
|   justify-content: space-between; | ||||
|  | ||||
|   &.bottomBorder { | ||||
|     border-bottom: 1px solid #eee; | ||||
|   } | ||||
|  | ||||
|   &.alignCenter { | ||||
|     align-items: center; | ||||
|   } | ||||
|  | ||||
|   &.topLabel { | ||||
|     flex-direction: column; | ||||
|   } | ||||
|  | ||||
|   .label { | ||||
|     min-width: 60px; | ||||
|     flex-shrink: 0; | ||||
|     width: auto; | ||||
|     color: #999; | ||||
|  | ||||
|  | ||||
|     &.title { | ||||
|       color: #333; | ||||
|       font-weight: bold; | ||||
|       font-size: 34px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .content { | ||||
|     flex: 1; | ||||
|     min-width: 100px; | ||||
|     min-height: 40px; | ||||
|     max-width: 500px; | ||||
|     text-align: right; | ||||
|  | ||||
|     &.topLabel { | ||||
|       text-align: start; | ||||
|       margin-top: 16px; | ||||
|       max-width: 100%; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										97
									
								
								src/components/AiCheckbox/AiCheckbox.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,97 @@ | ||||
| <template> | ||||
|   <div class="AiCheckbox"> | ||||
|     <div | ||||
|       class="AiCheckbox-item" | ||||
|       v-for="(item, index) in options" | ||||
|       @click="onChange(item.value)" | ||||
|       :class="[choosed.indexOf(item.value) > -1 ? 'active' : '']" | ||||
|       :key="index"> | ||||
|       {{ item.label }} | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'AiCheckbox', | ||||
|  | ||||
|     model: { | ||||
|       event: 'input', | ||||
|       prop: 'value' | ||||
|     }, | ||||
|  | ||||
|     props: { | ||||
|       value: Array, | ||||
|       placeholder: { | ||||
|         default: '请选择' | ||||
|       }, | ||||
|       list: { | ||||
|         default: () => [] | ||||
|       }, | ||||
|       dict: String, | ||||
|       disabled: Boolean | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         dictKey: '', | ||||
|         choosed: [] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       options () { | ||||
|         return this.dictKey ? this.$dict.getDict(this.dict).map(e => ({ | ||||
|           value: e.dictValue, | ||||
|           label: e.dictName | ||||
|         })) : this.list | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     mounted () { | ||||
|       this.$dict.load(this.dict).then(() => { | ||||
|         this.dictKey = this.dict | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onChange (value) { | ||||
|         if (this.choosed.indexOf(value) > -1) { | ||||
|           this.choosed.splice(this.choosed.indexOf(value), 1) | ||||
|         } else { | ||||
|           this.choosed.push(value) | ||||
|         } | ||||
|  | ||||
|         this.$emit('input', this.choosed) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .AiCheckbox { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     flex-wrap: wrap; | ||||
|  | ||||
|     .AiCheckbox-item { | ||||
|       width: 100%; | ||||
|       line-height: 1.3; | ||||
|       padding: 20px 32px; | ||||
|       margin-bottom: 16px; | ||||
|       text-align: center; | ||||
|       background: #FFFFFF; | ||||
|       box-sizing: border-box; | ||||
|       border-radius: 16px; | ||||
|       color: #333333; | ||||
|       font-size: 28px; | ||||
|       border: 1px solid #CCCCCC; | ||||
|  | ||||
|       &.active { | ||||
|         background: #4181FF; | ||||
|         color: #fff; | ||||
|         border-color: #4181FF; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										178
									
								
								src/components/AiComment/AiComment.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,178 @@ | ||||
| <template> | ||||
|   <div class="AiComment"> | ||||
|     <div class="pageTitle flex"> | ||||
|       评论 | ||||
|       <div class="mar-l16" v-text="total"/> | ||||
|     </div> | ||||
|     <div class="flex item" v-for="row in list" :key="row.id"> | ||||
|       <img :src="row.avatar"/> | ||||
|       <div class="fill"> | ||||
|         <div class="flex font-32"> | ||||
|           <div class="fill font600 font-28" v-text="row.name"/> | ||||
|           <AiThumbsUp :bid="row.id" type="comment" :count.sync="row.hotCount"/> | ||||
|         </div> | ||||
|         <div class="font-32 mar-t8 mar-b24" v-text="row.content"/> | ||||
|         <div class="flex mar-b24"> | ||||
|           <div class="color-999" v-text="[row.areaName,row.commentTime].join('    ')"/> | ||||
|           <comment-editor class="mar-l16" :bid="row.id" type="2">回复TA</comment-editor> | ||||
|         </div> | ||||
|         <div v-if="getArrayLength(row.replyList)>0" class="replyList"> | ||||
|           <div v-if="row.showAllReply"> | ||||
|             <div class="flex color-666 mar-t8" v-for="reply in row.replyList" :key="reply.id"> | ||||
|               <div class="font600" v-text="reply.name+':'"/> | ||||
|               <div v-text="reply.content"/> | ||||
|             </div> | ||||
|             <div v-if="getArrayLength(row.replyList)>2" class="color-687DA6 mar-t8" v-text="`收起`" @click="handleExpand(row)"/> | ||||
|           </div> | ||||
|           <div v-else> | ||||
|             <div class="flex color-666 mar-t8" v-for="reply in getReplies(row.replyList)" :key="reply.id"> | ||||
|               <div class="font600" v-text="reply.name+':'"/> | ||||
|               <div v-text="reply.content"/> | ||||
|             </div> | ||||
|             <div v-if="getArrayLength(row.replyList)>2" class="color-687DA6 mar-t8" v-text="`查看全部${getArrayLength(row.replyList)}条回复 >`" | ||||
|                  @click="handleExpand(row)"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <comment-editor class="fixedBottom" :bid="bid" :comment-count="total"/> | ||||
|     <u-gap height="128"/> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| import CommentEditor from "./commentEditor"; | ||||
| import AiThumbsUp from "../AiThumbsUp/AiThumbsUp"; | ||||
|  | ||||
| export default { | ||||
|   name: "AiComment", | ||||
|   components: {AiThumbsUp, CommentEditor}, | ||||
|   props: { | ||||
|     bid: {default: ""} | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       list: [], | ||||
|       current: 1, | ||||
|       total: 0 | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getComments() { | ||||
|       let {current, total, bid: contentId} = this | ||||
|       if (!total || this.list.length < total) { | ||||
|         this.$instance.post("/app/appcontentcomment/list", null, { | ||||
|           params: {current, contentId} | ||||
|         }).then(res => { | ||||
|           if (res?.data) { | ||||
|             res.data.records.map(e => e.showAllReply = false) | ||||
|             this.list = [current == 1 ? [] : this.list, res.data.records].flat() | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|     getReplies(list, showAll) { | ||||
|       return list?.slice(0, showAll ? this.getArrayLength(list) : 2) || [] | ||||
|     }, | ||||
|     getArrayLength(list) { | ||||
|       return list?.length || 0 | ||||
|     }, | ||||
|     handleExpand(row) { | ||||
|       console.log(row) | ||||
|       row.showAllReply = !row.showAllReply | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getComments() | ||||
|     uni.$on("moreComments", flag => { | ||||
|       flag == 1 ? this.current = 1 : this.current++ | ||||
|       this.getComments() | ||||
|     }) | ||||
|   }, | ||||
|   destroyed() { | ||||
|     uni.$off("moreComments") | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiComment { | ||||
|   background: #fff; | ||||
|  | ||||
|   .item { | ||||
|     padding: 24px 32px; | ||||
|     align-items: flex-start; | ||||
|     color: #333; | ||||
|     font-size: 26px; | ||||
|  | ||||
|     & > img { | ||||
|       height: 64px; | ||||
|       width: 64px; | ||||
|       border-radius: 50%; | ||||
|       margin-right: 16px; | ||||
|     } | ||||
|  | ||||
|     .content { | ||||
|       margin: 8px 0 24px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .font600 { | ||||
|     font-weight: 600; | ||||
|   } | ||||
|  | ||||
|   .font-32 { | ||||
|     font-size: 32px; | ||||
|   } | ||||
|  | ||||
|   .font-28 { | ||||
|     font-size: 28px; | ||||
|   } | ||||
|  | ||||
|   .mar-t8 { | ||||
|     margin-top: 8px; | ||||
|   } | ||||
|  | ||||
|   .mar-b24 { | ||||
|     margin-bottom: 24px; | ||||
|   } | ||||
|  | ||||
|   .mar-r16 { | ||||
|     margin-right: 16px; | ||||
|   } | ||||
|  | ||||
|   .mar-l16 { | ||||
|     margin-left: 16px; | ||||
|   } | ||||
|  | ||||
|   .color-999 { | ||||
|     color: #999; | ||||
|   } | ||||
|  | ||||
|   .color-666 { | ||||
|     color: #666; | ||||
|   } | ||||
|  | ||||
|   .color-687DA6 { | ||||
|     color: #687DA6; | ||||
|   } | ||||
|  | ||||
|   .replyList { | ||||
|     padding: 8px 16px 16px; | ||||
|     background: #F4F5FA; | ||||
|     border-radius: 8px; | ||||
|     font-size: 28px; | ||||
|   } | ||||
|  | ||||
|   .pageTitle { | ||||
|     height: 100px; | ||||
|     padding: 0 32px; | ||||
|     font-size: 34px; | ||||
|     font-family: PingFangSC-Semibold, PingFang SC; | ||||
|     font-weight: 600; | ||||
|     color: #333333; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										217
									
								
								src/components/AiComment/commentEditor.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,217 @@ | ||||
| <template> | ||||
|   <section class="commentEditor"> | ||||
|     <div v-if="$slots.default" @click="showCommentBox"> | ||||
|       <slot/> | ||||
|     </div> | ||||
|     <div v-else class="comments flex-row"> | ||||
|       <div class="comments-box" @click="showCommentBox">{{ boxContent }}</div> | ||||
|       <img src="./static/comment.svg" alt=""/> | ||||
|       <text>{{ commentCount || 0 }}</text> | ||||
|     </div> | ||||
|     <div class="modalWrapper" v-if="commentBoxPopup" :class="{clickClose:!modelClickClose}" | ||||
|          @click="commentBoxPopup=false"/> | ||||
|     <div class="commentBox" v-if="commentBoxPopup" :style="{bottom:marginBottom+ 'px'}"> | ||||
|       <textarea v-model="content" placeholder="写下你的想法…" maxlength="300" :focus="focus" @focus="getMarginBottom" | ||||
|                 @blur="marginBottom=0" :adjust-position="false" fixed/> | ||||
|       <view class="flex-row form-submit"> | ||||
|         <div>{{ `字数 ${wordCount || 0} / 300` }}</div> | ||||
|         <button @click="submitComment" :disabled="wordCount == 0">发布</button> | ||||
|       </view> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "commentEditor", | ||||
|   props: { | ||||
|     bid: {default: ""}, | ||||
|     type: {default: 1}, | ||||
|     needLogin: Boolean, | ||||
|     customLogin: Boolean, | ||||
|     commentCount: Number, | ||||
|     modelClickClose: {type: Boolean, default: true} | ||||
|   }, | ||||
|   computed: { | ||||
|     wordCount() { | ||||
|       return this.content.length || 0 | ||||
|     }, | ||||
|     boxContent() { | ||||
|       return this.content || "我也说两句..." | ||||
|     }, | ||||
|     isLogin() { | ||||
|       return Boolean(uni.getStorageSync('token')) | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       content: "", | ||||
|       marginBottom: 0, | ||||
|       commentBoxPopup: false, | ||||
|       focus: false | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     showCommentBox() { | ||||
|       if (this.customLogin) { | ||||
|         this.$emit("login", flag => this.commentBoxPopup = flag) | ||||
|       } else if (this.needLogin) { | ||||
|         if (this.isLogin) { | ||||
|           this.commentBoxPopup = true | ||||
|         } else { | ||||
|           this.$dialog.confirm({ | ||||
|             content: '您还未登陆', | ||||
|             confirmText: '去登录' | ||||
|           }).then(() => { | ||||
|             uni.switchTab({url: '/pages/AppMine/AppMine'}) | ||||
|           }).catch(() => { | ||||
|           }) | ||||
|         } | ||||
|       } else { | ||||
|         this.commentBoxPopup = true | ||||
|       } | ||||
|     }, | ||||
|     submitComment() { | ||||
|       let {content, type, bid: contentId} = this | ||||
|       this.$instance.post("/app/appcontentcomment/addByApplet", {content, type, contentId}).then(res => { | ||||
|         if (res?.code == 0) { | ||||
|           this.$u.toast("提交成功!") | ||||
|           this.commentBoxPopup = false | ||||
|           this.content = "" | ||||
|           uni.$emit("moreComments", 1)//刷新评论列表 | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getMarginBottom({detail}) { | ||||
|       this.marginBottom = detail.height | ||||
|       this.focus = true | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .commentEditor { | ||||
|   font-family: PingFangSC-Regular, PingFang SC; | ||||
|  | ||||
|   .comments { | ||||
|     width: 100%; | ||||
|     height: 128px; | ||||
|     padding: 24px 32px; | ||||
|     box-sizing: border-box; | ||||
|     position: fixed; | ||||
|     bottom: 0; | ||||
|     background: #fff; | ||||
|     border-top: 1px solid #eee; | ||||
|  | ||||
|     .comments-box { | ||||
|       width: 580px; | ||||
|       height: 80px; | ||||
|       line-height: 80px; | ||||
|       background-color: #F4F5FA; | ||||
|       color: #666; | ||||
|       font-size: 32px; | ||||
|       padding-left: 32px; | ||||
|       white-space: nowrap; | ||||
|       text-overflow: ellipsis; | ||||
|       overflow: hidden; | ||||
|       border-radius: 44px; | ||||
|     } | ||||
|  | ||||
|     image { | ||||
|       width: 52px; | ||||
|       height: 52px; | ||||
|       margin-left: 16px; | ||||
|       vertical-align: middle; | ||||
|     } | ||||
|  | ||||
|     text { | ||||
|       color: #666666; | ||||
|       font-size: 28px; | ||||
|       line-height: 60px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .modalWrapper { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     right: 0; | ||||
|     bottom: 0; | ||||
|     background: rgba(0, 0, 0, .6); | ||||
|     z-index: 9; | ||||
|  | ||||
|     &.clickClose { | ||||
|       pointer-events: none; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .commentBox { | ||||
|     width: 100vw; | ||||
|     height: 288px; | ||||
|     background-color: #fff; | ||||
|     padding: 32px 32px 24px 26px; | ||||
|     box-sizing: border-box; | ||||
|     position: fixed; | ||||
|     left: 0; | ||||
|     bottom: 0; | ||||
|     z-index: 99; | ||||
|  | ||||
|     textarea { | ||||
|       width: 100%; | ||||
|       height: 144px; | ||||
|       color: #666; | ||||
|       font-size: 26px; | ||||
|       background: #F7F7F7; | ||||
|       border-radius: 16px; | ||||
|       padding: 16px; | ||||
|       box-sizing: border-box; | ||||
|  | ||||
|       &::placeholder { | ||||
|         font-size: inherit; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .form-submit { | ||||
|       margin-top: 24px; | ||||
|       height: 64px; | ||||
|       justify-content: space-between; | ||||
|       align-items: center; | ||||
|       color: #999; | ||||
|       font-size: 24px; | ||||
|  | ||||
|       button { | ||||
|         width: 144px; | ||||
|         height: 64px; | ||||
|         background-color: #135AB8; | ||||
|         color: #fff; | ||||
|         font-size: 24px; | ||||
|         border-radius: 32px; | ||||
|         line-height: 64px; | ||||
|         text-align: center; | ||||
|         margin: unset; | ||||
|  | ||||
|         &[disabled] { | ||||
|           color: #999; | ||||
|           background-color: #f7f7f7; | ||||
|           font-size: 28px; | ||||
|           border: 0; | ||||
|         } | ||||
|  | ||||
|         &:active { | ||||
|           opacity: .8; | ||||
|         } | ||||
|  | ||||
|         &:after { | ||||
|           border: none; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .flex-row { | ||||
|     display: flex; | ||||
|     flex-direction: row; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										11
									
								
								src/components/AiComment/static/comment.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,11 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <svg width="26px" height="26px" viewBox="0 0 26 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | ||||
|     <!-- Generator: Sketch 55.2 (78181) - https://sketchapp.com --> | ||||
|     <title>icon/tab_bar/Comment</title> | ||||
|     <desc>Created with Sketch.</desc> | ||||
|     <g id="icon/tab_bar/Comment" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> | ||||
|         <path d="M4.75,21.7864745 L9.45344419,19.4347524 C9.6964412,19.3132539 9.96438906,19.25 10.236068,19.25 L20,19.25 C20.6903559,19.25 21.25,18.6903559 21.25,18 L21.25,8 C21.25,7.30964406 20.6903559,6.75 20,6.75 L6,6.75 C5.30964406,6.75 4.75,7.30964406 4.75,8 L4.75,21.7864745 Z" id="矩形" stroke="#333333" stroke-width="1.5"></path> | ||||
|         <rect id="矩形" fill="#999999" x="8" y="10.5" width="10" height="1.5" rx="0.75"></rect> | ||||
|         <rect id="矩形备份" fill="#999999" x="8" y="14" width="10" height="1.5" rx="0.75"></rect> | ||||
|     </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 983 B | 
							
								
								
									
										68
									
								
								src/components/AiDate/AiDate.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,68 @@ | ||||
| <template> | ||||
|   <section class="AiDate"> | ||||
|     <u-calendar v-model="show" :maxDate="maxDate" | ||||
|                 @change="handleSelect" :mode="mode" @close="show=false"/> | ||||
|     <div class="flex" @click="show=true"> | ||||
|       <div class="label" v-if="label" v-html="label"/> | ||||
|       <div class="placeholder" v-else v-html="placeholder"/> | ||||
|       <u-icon name="arrow-right" color="#ddd"/> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import dayjs from 'dayjs' | ||||
|  | ||||
| export default { | ||||
|   name: "AiDate", | ||||
|   computed: { | ||||
|     label() { | ||||
|       let arr = (this.selected || this.value)?.toString()?.split(",") || [] | ||||
|       arr = arr.map(e => dayjs(e).format("YYYY-MM-DD").replace("Invalid Date", '')) | ||||
|       return arr.join('至') | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       show: false, | ||||
|       selected: "" | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     value: {default: ""}, | ||||
|     placeholder: {default: "请选择"}, | ||||
|     mode: {default: "date"},//date 单个日期|range 日期范围 | ||||
|     maxDate: String | ||||
|   }, | ||||
|   methods: { | ||||
|     handleSelect(v) { | ||||
|       if (this.mode == 'date') { | ||||
|         this.selected = v.result | ||||
|         this.$emit('change', v.result) | ||||
|       } else if (this.mode == 'range') { | ||||
|         this.selected = [v.startDate, v.endDate] | ||||
|         this.$emit('change', v) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiDate { | ||||
|   color: #333333; | ||||
|   font-size: 30px; | ||||
|  | ||||
|   .label { | ||||
|     font-size: 30px; | ||||
|   } | ||||
|  | ||||
|   ::v-deep .u-icon { | ||||
|     margin-left: 8px; | ||||
|   } | ||||
|  | ||||
|   .placeholder { | ||||
|     color: $uni-text-color-grey; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										143
									
								
								src/components/AiDetail/AiDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,143 @@ | ||||
| <template> | ||||
|   <section class="AiDetail"> | ||||
|     <div class="content"> | ||||
|       <div class="title">{{ detail.title }}</div> | ||||
|       <div class="info"> | ||||
|         <span>{{ detail.createTime }}</span> | ||||
|         <span class="right"> | ||||
|           <em>{{ detail.viewCount }}</em>人看过 | ||||
|         </span> | ||||
|       </div> | ||||
|       <slot v-if="$slots.content" name="content"/> | ||||
|       <u-parse v-else :html="detail.content"/> | ||||
|     </div> | ||||
|     <!--    <div class="files" v-if="detail.contentType==0 && detail.files && detail.files.length">--> | ||||
|     <!--      <img class="file-img" :src="file.url" @click.native="preview(index)" alt="" v-for="(file,index) in detail.files" :key="index">--> | ||||
|     <!--    </div>--> | ||||
|  | ||||
|     <div class="files" v-if="detail.contentType==1 && detail.files && detail.files.length"> | ||||
|       <video class="file-img" :src="file.url" v-for="(file,index) in detail.files" :key="index"/> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|   name: "AiDetail", | ||||
|   props: { | ||||
|     title: {default: ""}, | ||||
|     detail: {default: () => ({})}, | ||||
|   }, | ||||
|   methods: { | ||||
|     preview(index) { | ||||
|       this.$previewImage(this.detail.files, index, "url"); | ||||
|     } | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiDetail { | ||||
|   padding-bottom: 80px; | ||||
|   background: #fff; | ||||
|  | ||||
|   .header { | ||||
|     .title { | ||||
|       font-weight: bold; | ||||
|       font-size: 48px; | ||||
|     } | ||||
|  | ||||
|     .bottomBar { | ||||
|       justify-content: space-between; | ||||
|       margin-top: 16px; | ||||
|       color: #999; | ||||
|  | ||||
|       .u-icon + .u-icon { | ||||
|         margin-left: 32px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .content { | ||||
|     padding: 32px; | ||||
|     background: #fff; | ||||
|  | ||||
|     &.content { | ||||
|       margin-bottom: 20px; | ||||
|  | ||||
|       .title { | ||||
|         font-size: 38px; | ||||
|         font-weight: 600; | ||||
|         color: #333333; | ||||
|         line-height: 52px; | ||||
|         margin-bottom: 32px; | ||||
|       } | ||||
|  | ||||
|       .info { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         justify-content: space-between; | ||||
|         margin-bottom: 64px; | ||||
|         font-size: 30px; | ||||
|         font-weight: 400; | ||||
|         color: #999999; | ||||
|  | ||||
|         .right { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|  | ||||
|           & > em { | ||||
|             color: #4181FF; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .files { | ||||
|     padding: 0 32px; | ||||
|     background: #fff; | ||||
|  | ||||
|     .file-img { | ||||
|       width: 100%; | ||||
|       height: 486px; | ||||
|       margin-bottom: 32px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .imageList { | ||||
|     justify-content: space-around; | ||||
|  | ||||
|     .AiImage { | ||||
|       margin-right: 8px; | ||||
|       margin-bottom: 8px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .fileList { | ||||
|     & > div { | ||||
|       margin-bottom: 8px; | ||||
|     } | ||||
|  | ||||
|     .info { | ||||
|       flex: 1; | ||||
|       min-width: 0; | ||||
|       display: flex; | ||||
|       margin-left: 16px; | ||||
|       word-break: break-all; | ||||
|       align-items: center; | ||||
|  | ||||
|       & > span { | ||||
|         flex: 1; | ||||
|         min-width: 0; | ||||
|       } | ||||
|  | ||||
|       & > i { | ||||
|         flex-shrink: 0; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										56
									
								
								src/components/AiEmpty/AiEmpty.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,56 @@ | ||||
| <template> | ||||
|   <div class="emptyWrap"> | ||||
|     <img class="emptyImg" :src="emptyImg" :class="noPermit ? 'small-img' : ''"> | ||||
|     <div class="emptyText" v-html="description"></div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiEmpty", | ||||
|   props: { | ||||
|     img: {default: "https://cdn.cunwuyun.cn/dvcp/h5/no-admin.png"}, | ||||
|     noPermit: Boolean, | ||||
|     description: { | ||||
|       default: '暂无相关信息', | ||||
|       type: String | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     emptyImg() { | ||||
|       return this.noPermit ? "https://cdn.cunwuyun.cn/dvcp/h5/no-admin.png" : this.img | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .emptyWrap { | ||||
|   width: 100%; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
|   // margin-top: 100px; | ||||
|   margin-bottom: 20px; | ||||
|  | ||||
|   .emptyImg { | ||||
|     width: 300px; | ||||
|     height: 310px; | ||||
|     margin-top: 52px; | ||||
|   } | ||||
|  | ||||
|   .small-img { | ||||
|     width: 282px; | ||||
|     height: 306px; | ||||
|   } | ||||
|  | ||||
|   .emptyText { | ||||
|     font-size: 29px; | ||||
|     font-family: PingFangSC-Regular, PingFang SC; | ||||
|     font-weight: 400; | ||||
|     color: rgba(183, 183, 183, 1); | ||||
|     text-align: center; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										83
									
								
								src/components/AiEvaluation/AiEvaluation.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,83 @@ | ||||
| <template> | ||||
|   <section class="AiEvaluation"> | ||||
|     <div v-if="type=='submit'"> | ||||
|       <AiPagePicker v-if="!hasEvaluated" type="custom" :ops="ops" nodeKey=""> | ||||
|         <slot v-if="$slots.default"/> | ||||
|         <div v-else v-text="placeholder"/> | ||||
|       </AiPagePicker> | ||||
|       <slot name="finish" v-else-if="$slots.finish"/> | ||||
|     </div> | ||||
|     <div v-else-if="type=='show'"> | ||||
|       <slot v-if="$slots.default" :evaluation="detail"/> | ||||
|       <AiGroup v-if="hasEvaluated" description no-border labelColor="#999" v-else> | ||||
|         <AiItem label="评级分数"> | ||||
|           <u-rate v-model="detail.score" disabled inactive-icon="star-fill" active-color="#F8B425"/> | ||||
|           {{ detail.rateText || "" }} | ||||
|         </AiItem> | ||||
|         <AiItem label="评价详情" top-label> | ||||
|           <div v-html="detail.content"/> | ||||
|         </AiItem> | ||||
|         <AiItem label="附件" top-label> | ||||
|           <AiUploader :def="detail.files" disabled preview/> | ||||
|         </AiItem> | ||||
|       </AiGroup> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import AiPagePicker from "../AiPagePicker/AiPagePicker"; | ||||
| import AiGroup from "../AiGroup/AiGroup"; | ||||
| import AiItem from "../AiItem/AiItem"; | ||||
| import AiUploader from "../AiUploader/AiUploader"; | ||||
|  | ||||
| export default { | ||||
|   name: "AiEvaluation", | ||||
|   model: { | ||||
|     prop: "info", | ||||
|     event: "input" | ||||
|   }, | ||||
|   props: { | ||||
|     info: {default: () => ({})}, | ||||
|     placeholder: {default: "去评价"}, | ||||
|     bid: {default: ""}, | ||||
|     type: {default: "submit"} //可选值: submit:提交评价,show:展示评价 | ||||
|   }, | ||||
|   components: {AiUploader, AiItem, AiGroup, AiPagePicker}, | ||||
|   computed: { | ||||
|     isShow: v => v.type == 'show', | ||||
|     hasEvaluated: v => !!v.detail?.id | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       detail: {}, | ||||
|       ops: { | ||||
|         rateTexts: ['非常不满意', '不满意', '一般', '满意', '非常满意'], | ||||
|         url: "/components/pages/submitEvaluation?bid=" + this.bid | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     bid: { | ||||
|       immediate: true, | ||||
|       handler() { | ||||
|         this.getDetail() | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getDetail() { | ||||
|       const bizId = this.bid | ||||
|       bizId && this.$instance.post("/app/appbusinesscompletionevaluation/queryMyEvaluationByBizId", null, { | ||||
|         params: {bizId} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           const info = res.data?.[0] | ||||
|           this.detail = {...info, rateText: this.rateTexts?.[info.score - 1]} | ||||
|           this.$emit("input", this.detail) | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
							
								
								
									
										35
									
								
								src/components/AiFixedBtn/AiFixedBtn.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,35 @@ | ||||
| <template> | ||||
|   <section class="AiFixedBtn"> | ||||
|     <movable-area class="movableArea"> | ||||
|       <movable-view direction="all" x="300" y="500" @tap.stop> | ||||
|         <slot/> | ||||
|       </movable-view> | ||||
|     </movable-area> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiFixedBtn" | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiFixedBtn { | ||||
|   .movableArea { | ||||
|     position: fixed; | ||||
|     left: 0; | ||||
|     top: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     pointer-events: none; | ||||
|     z-index: 999; | ||||
|  | ||||
|     uni-movable-view { | ||||
|       pointer-events: auto; | ||||
|       width: auto; | ||||
|       height: auto; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										61
									
								
								src/components/AiGroup/AiGroup.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,61 @@ | ||||
| <template> | ||||
|   <section class="AiGroup" :class="{noBorder,description}" :style="{paddingLeft:left+'rpx'}"> | ||||
|     <div class="groupHeader" v-if="title" v-text="title"/> | ||||
|     <slot/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiGroup", | ||||
|   provide() { | ||||
|     return { | ||||
|       labelColor: this.labelColor, | ||||
|       description: this.description, | ||||
|       activeStep: this.activeStep | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     title: String, | ||||
|     noBorder: Boolean, | ||||
|     left: {default: 32}, | ||||
|     labelColor: {default: "#333"}, | ||||
|     description: {default: false}, //用于展示则不会又红星,会把标签的内间距去掉 | ||||
|     activeStep: {default: 1}//用于步骤组件的当前步数 | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       items: [] | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiGroup { | ||||
|   background: #FFFFFF; | ||||
|   box-shadow: inset 0px -1px 0px 0px #DDDDDD; | ||||
|  | ||||
|   &.noBorder { | ||||
|     box-shadow: none; | ||||
|   } | ||||
|  | ||||
|   & + .AiGroup { | ||||
|     margin-top: 16px; | ||||
|   } | ||||
|  | ||||
|   .groupHeader { | ||||
|     font-weight: bold; | ||||
|     font-size: 36px; | ||||
|     padding-left: 20px; | ||||
|     margin-bottom: 16px; | ||||
|   } | ||||
|  | ||||
|   &.description { | ||||
|     .groupHeader { | ||||
|       padding-left: 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										26
									
								
								src/components/AiIcon/AiIcon.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,26 @@ | ||||
| <template> | ||||
|   <section class="AiIcon"> | ||||
|     <view v-if="!singleColor" class="ai-icon" :class="icon" :style="{width:size+'px',height:size+'px'}"/> | ||||
|     <view v-else class="iconfont" :style="{ fontSize: size + 'rpx', color: color }">{{ icon }}</view> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiIcon", | ||||
|   props: { | ||||
|     icon: String, | ||||
|     singleColor: { | ||||
|       type: Boolean, | ||||
|       default: false | ||||
|     }, | ||||
|     color: { | ||||
|       type: String | ||||
|     }, | ||||
|     size: {type: String, default: "32"} | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <style scoped> | ||||
| @import "./iconcss.css"; | ||||
| </style> | ||||
							
								
								
									
										658
									
								
								src/components/AiIcon/iconcss.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										72
									
								
								src/components/AiImage/AiImage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,72 @@ | ||||
| <template> | ||||
|   <section class="AiImage"> | ||||
|     <div v-if="$slots.default" @tap="prev"> | ||||
|       <slot/> | ||||
|     </div> | ||||
|     <u-image v-else :src="image" @tap="prev"> | ||||
|       <image v-if="link" class="errorImage" slot="error" :src="cdn+'link.png'"/> | ||||
|       <image v-else-if="miniapp" class="errorImage" slot="error" :src="cdn+'miniwxmp.jpg'"/> | ||||
|       <image v-else class="errorImage" slot="error" :src="cdn+'file.png'"/> | ||||
|     </u-image> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapActions} from "vuex"; | ||||
|  | ||||
| export default { | ||||
|   name: "AiImage", | ||||
|   data() { | ||||
|     return { | ||||
|       dialog: false, | ||||
|       cdn: "https://cdn.cunwuyun.cn/" | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     image() { | ||||
|       return this.src?.replace(/\\/g, '/') | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     src: String, | ||||
|     preview: Boolean, | ||||
|     link: Boolean, | ||||
|     miniapp: Boolean, | ||||
|     file: {default: () => ({})} | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions(['previewFile', 'injectJWeixin']), | ||||
|     prev() { | ||||
|       if (this.preview) { | ||||
|         if (!!this.image) { | ||||
|           uni.previewImage({ | ||||
|             current: this.image, | ||||
|             urls: [this.image], | ||||
|           }) | ||||
|         } else { | ||||
|           this.previewFile({size: 1, ...this.file}) | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiImage { | ||||
|   ::v-deep image { | ||||
|     width: 160px; | ||||
|     height: 160px; | ||||
|     object-fit: cover; | ||||
|   } | ||||
|  | ||||
|   ::v-deep .u-image__error { | ||||
|     position: relative; | ||||
|   } | ||||
|  | ||||
|   .errorImage { | ||||
|     width: 80px; | ||||
|     height: 80px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										125
									
								
								src/components/AiItem/AiItem.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,125 @@ | ||||
| <template> | ||||
|   <section class="AiItem" :class="{border,readonly}"> | ||||
|     <div v-if="topLabel" class="topLabel"> | ||||
|       <div class="labelPane flex"> | ||||
|         <div class="label" :class="{required,labelBold}" :style="{color}" v-text="label"/> | ||||
|         <slot name="sub" v-if="$slots.sub"/> | ||||
|       </div> | ||||
|       <div class="itemContent"> | ||||
|         <slot v-if="$slots.default"/> | ||||
|         <div v-else v-text="value"/> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div v-else class="normal flex"> | ||||
|       <div class="fill flex"> | ||||
|         <div class="label" :class="{required,labelBold}" :style="{color}" v-text="label"/> | ||||
|         <slot name="sub" v-if="$slots.sub"/> | ||||
|       </div> | ||||
|       <div class="flexContent"> | ||||
|         <slot v-if="$slots.default"/> | ||||
|         <div v-else v-text="value"/> | ||||
|       </div> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiItem", | ||||
|   inject: { | ||||
|     labelColor: {default: "#333"}, | ||||
|     description: {default: false} | ||||
|   }, | ||||
|   props: { | ||||
|     value: {default: ""}, | ||||
|     label: {default: ""}, | ||||
|     required: Boolean, | ||||
|     topLabel: Boolean, | ||||
|     border: {default: true}, | ||||
|     labelBold: Boolean, | ||||
|   }, | ||||
|   computed: { | ||||
|     color: v => v.labelColor, | ||||
|     readonly: v => !!v.description | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiItem { | ||||
|   font-family: PingFangSC-Regular, PingFang SC; | ||||
|  | ||||
|   &.border { | ||||
|     .normal { | ||||
|       border-bottom: 2px solid #ddd; | ||||
|     } | ||||
|  | ||||
|     .topLabel { | ||||
|       border-bottom: 2px solid #ddd; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .normal { | ||||
|     width: 100%; | ||||
|     padding: 32px 32px 32px 0; | ||||
|     line-height: 44px; | ||||
|     box-sizing: border-box; | ||||
|     // height: 112px; | ||||
|  | ||||
|     .flexContent { | ||||
|       max-width: 62vw; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .label { | ||||
|     padding-left: 20px; | ||||
|     font-weight: 400; | ||||
|     margin-right: 20px; | ||||
|     position: relative; | ||||
|  | ||||
|     &.required:before { | ||||
|       position: absolute; | ||||
|       display: block; | ||||
|       left: 0; | ||||
|       top: 50%; | ||||
|       transform: translateY(-50%); | ||||
|       content: "*"; | ||||
|       color: #f46; | ||||
|     } | ||||
|  | ||||
|     &.labelBold { | ||||
|       font-weight: bold; | ||||
|       font-size: 34px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ::v-deep.topLabel { | ||||
|     padding: 32px 32px 32px 0; | ||||
|  | ||||
|     .labelPane { | ||||
|       margin-bottom: 32px; | ||||
|     } | ||||
|  | ||||
|     .itemContent { | ||||
|       padding-left: 20px; | ||||
|  | ||||
|       .AiMore > .u-icon { | ||||
|         width: 100%; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   //展示模式下的特有样式 | ||||
|   &.readonly { | ||||
|     .label, .itemContent { | ||||
|       padding-left: 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .AiStep:last-of-type { | ||||
|     .stepLine { | ||||
|       display: none | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										113
									
								
								src/components/AiListPage/AiListPage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,113 @@ | ||||
| <template> | ||||
|   <section class="AppListPage"> | ||||
|     <div class="header" :style="{backgroundImage: `url(${headerBg})`}"> | ||||
|       <img :src="headerBg" alt=""> | ||||
|       <p>{{label}}</p> | ||||
|     </div> | ||||
|     <div class="content"> | ||||
|       <div class="title">{{label}}</div> | ||||
|       <div class="app-list"> | ||||
|         <div class="item" v-for="(item, index) in appList" :key="index" @click="linkTo(item.url)" > | ||||
|           <!-- <div class="icon" :style="{backgroundImage: url(item.icon)}"></div> --> | ||||
|           <img :src="item.icon" alt="" class="icon"> | ||||
|           <p>{{item.name}}</p> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div>   | ||||
|      | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|   name: "AppListPage", | ||||
|   props: { | ||||
|     label: String, | ||||
|     appList: Array, | ||||
|     headerBg: String | ||||
|   }, | ||||
|   methods: { | ||||
|     linkTo(url) { | ||||
|       uni.navigateTo({url}) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AppListPage { | ||||
|   padding-top: 20px; | ||||
|   .header{ | ||||
|     width: calc(100% - 36px); | ||||
|     height: 240px; | ||||
|     margin: 0 18px 20px 18px; | ||||
|     background-size: 100% 100%; | ||||
|     img { | ||||
|       width: 100%; | ||||
|       height: 100%; | ||||
|     } | ||||
|     p{ | ||||
|       position: absolute; | ||||
|       top: 48px; | ||||
|       left: 50px; | ||||
|       font-size: 46px; | ||||
|       font-family: PingFangSC-Semibold, PingFang SC; | ||||
|       font-weight: 600; | ||||
|       color: #26385C; | ||||
|       line-height: 64px; | ||||
|       // padding: 48px 50px 0 50px; | ||||
|       word-break: break-all; | ||||
|     } | ||||
|   } | ||||
|   .content{ | ||||
|     margin: 0 20px 20px; | ||||
|     width: calc(100% - 40px); | ||||
|     background: #FFF; | ||||
|     border-radius: 16px; | ||||
|     .title{ | ||||
|       line-height: 70px; | ||||
|       border-bottom: 1px solid #eee; | ||||
|       padding-left: 20px; | ||||
|       font-size: 26px; | ||||
|       font-family: PingFangSC-Medium, PingFang SC; | ||||
|       font-weight: 500; | ||||
|       color: #999; | ||||
|     } | ||||
|     .app-list{ | ||||
|       overflow: hidden; | ||||
|       .item{ | ||||
|         text-align: center; | ||||
|         padding-bottom: 38px; | ||||
|         border-right: 1px solid #eee; | ||||
|         border-top: 1px solid #eee; | ||||
|         width: calc(33% - 1px); | ||||
|         float: left; | ||||
|         .icon{ | ||||
|           display: inline-block; | ||||
|           width: 58px; | ||||
|           height: 58px; | ||||
|           margin: 40px 0 18px 0; | ||||
|           background-size: 100% 100%; | ||||
|           text-align: center; | ||||
|         } | ||||
|         p{ | ||||
|           font-size: 28px; | ||||
|           font-family: PingFangSC-Regular, PingFang SC; | ||||
|           font-weight: 400; | ||||
|           color: #3D434A; | ||||
|           line-height: 40px; | ||||
|         } | ||||
|       } | ||||
|       .item:nth-of-type(3n) { | ||||
|         border-right: 0; | ||||
|       } | ||||
|       .item:nth-of-type(1), | ||||
|       .item:nth-of-type(2), | ||||
|       .item:nth-of-type(3) { | ||||
|         border-top: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										28
									
								
								src/components/AiLoading/AiLoading.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,28 @@ | ||||
| <template> | ||||
|   <section class="AiLoading"> | ||||
|     <image :src="image"/> | ||||
|     <span>{{ tips }}</span> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiLoading", | ||||
|   props: { | ||||
|     tips: {default: "应用加载中"}, | ||||
|     image: {default: "https://cdn.cunwuyun.cn/wxAdmin/img/message.png"} | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiLoading { | ||||
|   font-size: 32px; | ||||
|   color: #666; | ||||
|   text-align: center; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										66
									
								
								src/components/AiLogin/AiLogin.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,66 @@ | ||||
| <template> | ||||
|   <div class="ai-login"> | ||||
|     <u-modal v-model="userPhoneShow" showCancelButton :showTitle="true" :title="'手机号码授权'" | ||||
|              :content="'本次操作需要获取您的手机号码,请同意授权'" @cancel="hide"> | ||||
|       <template slot="confirm-button"> | ||||
|         <button open-type="getPhoneNumber" @getphonenumber="getPhoneNumber" class="confirm-button">同意</button> | ||||
|       </template> | ||||
|     </u-modal> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import tools from '../utils/util' | ||||
| import {mapActions} from "vuex" | ||||
|  | ||||
| export default { | ||||
|   name: 'AiLogin', | ||||
|   data() { | ||||
|     return { | ||||
|       userPhoneShow: false, | ||||
|       userData: {}, | ||||
|       code: '' | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions(['autoLogin']), | ||||
|     show() { | ||||
|       tools.$getLoginCode().then(res => { | ||||
|         this.code = res.code; | ||||
|         this.userPhoneShow = true; | ||||
|       }) | ||||
|     }, | ||||
|     hide() { | ||||
|       this.userPhoneShow = false | ||||
|     }, | ||||
|     getPhoneNumber(arg) { | ||||
|       const {encryptedData, errMsg, iv} = arg.detail | ||||
|       if (errMsg == 'getPhoneNumber:ok') { | ||||
|         tools.$getLoginCode().then(() => { | ||||
|           console.log(iv, this.code) | ||||
|           this.$instance.post(`/app/appwechatuser/getWechatUserPhone`, { | ||||
|             encryptedData, iv, | ||||
|             code: this.code | ||||
|           }, {withoutToken: true}).then(d => { | ||||
|             if (d.data) { | ||||
|               let data = {...this.userData, phone: d.data}; | ||||
|               this.autoLogin(data).then(res => { | ||||
|                 this.$emit("success", res); | ||||
|               }); | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .confirm-button { | ||||
|   background-color: #fff !important; | ||||
| } | ||||
|  | ||||
| .confirm-button::after { | ||||
|   border: none !important; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										68
									
								
								src/components/AiMap/AiMap.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,68 @@ | ||||
| <template> | ||||
|   <section class="AiMap"> | ||||
|     <div ref="amap" class="map"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import AMapLoader from "@amap/amap-jsapi-loader"; | ||||
|  | ||||
| export default { | ||||
|   name: "AiMap", | ||||
|   props: { | ||||
|     plugins: {default: () => ['AMap.DistrictSearch']}, | ||||
|     map: Object, | ||||
|     lib: Object | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       amap: null | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     initMap() { | ||||
|       let {plugins} = this | ||||
|       AMapLoader.load({ | ||||
|         key: '54a02a43d9828a8f9cd4f26fe281e74e', | ||||
|         version: '2.0', | ||||
|         plugins | ||||
|       }).then(AMap => { | ||||
|         this.amap = new AMap.Map(this.$refs.amap, { | ||||
|           resizeEnable: true, | ||||
|           zoom: 14, | ||||
|         }) | ||||
|         this.$emit('update:lib', AMap) | ||||
|         this.$emit('update:map', this.amap) | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.initMap() | ||||
|   }, | ||||
|   destroyed() { | ||||
|     this.amap?.destroy() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiMap { | ||||
|   .map { | ||||
|     height: 100%; | ||||
|   } | ||||
|  | ||||
|   ::v-deep .amap-logo, ::v-deep .amap-copyright { | ||||
|     display: none !important; | ||||
|   } | ||||
|  | ||||
|   ::v-deep .amap-icon { | ||||
|     width: 40px !important; | ||||
|     height: 40px !important; | ||||
|  | ||||
|     img { | ||||
|       width: 100%; | ||||
|       height: 100%; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										32
									
								
								src/components/AiMore/AiMore.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,32 @@ | ||||
| <template> | ||||
|   <section class="AiMore"> | ||||
|     <u-icon name="arrow-right" color="#ddd" :label="value||placeholder" label-pos="left" :label-color="labelColor" label-size="32"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiMore", | ||||
|   model: { | ||||
|     prop: "value", | ||||
|     event: "change" | ||||
|   }, | ||||
|   props: { | ||||
|     placeholder: {default: "请选择"}, | ||||
|     value: String | ||||
|   }, | ||||
|   computed: { | ||||
|     isEmpty() { | ||||
|       return !this.value | ||||
|     }, | ||||
|     labelColor() { | ||||
|       return this.isEmpty ? "#999" : "#333" | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiMore { | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										201
									
								
								src/components/AiNewsList/AiNewsList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,201 @@ | ||||
| <template> | ||||
|   <section class="AiNewsList"> | ||||
|     <slot name="header"/> | ||||
|     <slot v-if="$slots.content" name="content"/> | ||||
|     <div class="list-wrap" v-if="list && list.length"> | ||||
|       <div class="list-card" v-for="(category,index) in list" :key="index" | ||||
|            @click="$linkTo(linkUrl+category.id)"> | ||||
|         <div class="header">{{ category.title }}</div> | ||||
|         <div class="content-wrap" v-if="category.contentType==0 && category.files && category.files.length == 1"> | ||||
|           <img class="img" :src="item.url" v-for="(item,index) in category.files" :key="index.id" alt=""> | ||||
|         </div> | ||||
|         <div class="content-wrap" v-if="category.contentType==0 && category.files && category.files.length > 1"> | ||||
|           <img class="min-img" :src="item.url" v-for="(item,index) in category.files && category.files.slice(0,3)" | ||||
|                :key="index.id" alt=""> | ||||
|         </div> | ||||
|         <div class="content-wrap" v-if="category.contentType==1"> | ||||
|           <img class="img" :src="category.pictureUrl" alt=""> | ||||
|           <img class="play-icon" src="https://cdn.cunwuyun.cn/dvcp/pay-btn.png" alt=""> | ||||
|         </div> | ||||
|         <div class="bottom"> | ||||
|           <div class="left"> | ||||
|             <div class="tag">{{ category.categoryName }}</div> | ||||
|             {{ category.createTime }} | ||||
|           </div> | ||||
|           <div class="right"> | ||||
|             <em>{{ category.viewCount }}</em> | ||||
|             人看过 | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <AiEmpty v-else/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|   name: "AiNewsList", | ||||
|   props: { | ||||
|     list: {default: () => []}, | ||||
|     linkUrl: {default: '/mods/AppContent/contentDetail?id='}, | ||||
|     props: { | ||||
|       default: () => ({ | ||||
|         title: 'title', | ||||
|         type: "type", | ||||
|         createTime: "createTime", | ||||
|         count: "count", | ||||
|       }) | ||||
|     }, | ||||
|     loadmore: {default: "loadmore"} | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiNewsList { | ||||
|   height: 100vh; | ||||
|   background: #f3f6f9; | ||||
|  | ||||
|   .listPane { | ||||
|     padding: 24px 32px 36px; | ||||
|  | ||||
|     .card { | ||||
|       background: #FFFFFF; | ||||
|       box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.02); | ||||
|       border-radius: 16px; | ||||
|       padding: 32px; | ||||
|       margin-bottom: 32px; | ||||
|  | ||||
|       .title { | ||||
|         height: 50px; | ||||
|         font-size: 36px; | ||||
|         font-weight: 500; | ||||
|         color: #333333; | ||||
|         line-height: 50px; | ||||
|         margin-bottom: 24px; | ||||
|       } | ||||
|  | ||||
|       .subTitle { | ||||
|         color: #999; | ||||
|         width: 100%; | ||||
|  | ||||
|         .tag { | ||||
|           height: 48px; | ||||
|           background: #EEEEEE; | ||||
|           border-radius: 24px; | ||||
|           text-align: center; | ||||
|           line-height: 48px; | ||||
|           margin-right: 16px; | ||||
|         } | ||||
|  | ||||
|         .count { | ||||
|           color: #4181FF; | ||||
|         } | ||||
|  | ||||
|         .right { | ||||
|           margin-left: auto; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .list-wrap { | ||||
|     box-sizing: border-box; | ||||
|     padding: 32px; | ||||
|  | ||||
|     .list-card { | ||||
|       width: 100%; | ||||
|       min-height: 100px; | ||||
|       background: #FFFFFF; | ||||
|       box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.02); | ||||
|       border-radius: 16px; | ||||
|       box-sizing: border-box; | ||||
|       padding: 32px; | ||||
|       margin-bottom: 24px; | ||||
|  | ||||
|       .header { | ||||
|         font-size: 36px; | ||||
|         font-weight: 600; | ||||
|         color: #333333; | ||||
|         line-height: 50px; | ||||
|         display: -webkit-box; | ||||
|         -webkit-box-orient: vertical; | ||||
|         -webkit-line-clamp: 2; | ||||
|         overflow: hidden; | ||||
|       } | ||||
|  | ||||
|       .content-wrap { | ||||
|         display: flex; | ||||
|         gap: 4px; | ||||
|         flex-wrap: wrap; | ||||
|         margin-top: 24px; | ||||
|         position: relative; | ||||
|  | ||||
|         .img { | ||||
|           width: 100%; | ||||
|           height: 350px; | ||||
|         } | ||||
|  | ||||
|         .min-img { | ||||
|           width: 204px; | ||||
|           height: 204px; | ||||
|         } | ||||
|  | ||||
|         .play-icon { | ||||
|           width: 80px; | ||||
|           height: 80px; | ||||
|           border-radius: 50%; | ||||
|           position: absolute; | ||||
|           left: 50%; | ||||
|           top: 50%; | ||||
|           transform: translate(-50%, -50%); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .bottom { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         justify-content: space-between; | ||||
|         margin-top: 24px; | ||||
|  | ||||
|         .left { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           font-size: 28px; | ||||
|           font-weight: 400; | ||||
|           color: #999999; | ||||
|  | ||||
|           .tag { | ||||
|             width: 144px; | ||||
|             height: 48px; | ||||
|             background: #EEEEEE; | ||||
|             border-radius: 24px; | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             justify-content: center; | ||||
|             font-size: 28px; | ||||
|             font-weight: 400; | ||||
|             color: #999999; | ||||
|             margin-right: 16px; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .right { | ||||
|           font-size: 28px; | ||||
|           font-weight: 400; | ||||
|           color: #999999; | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|  | ||||
|           em { | ||||
|             font-style: normal; | ||||
|             color: #4181FF; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										81
									
								
								src/components/AiPagePicker/AiPagePicker.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,81 @@ | ||||
| <template> | ||||
|   <section class="AiPagePicker"> | ||||
|     <div @click="handleJump"> | ||||
|       <slot v-if="$slots.default"/> | ||||
|       <div v-else v-text="selectedLabel"/> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import qs from 'query-string' | ||||
|  | ||||
| export default { | ||||
|   name: "AiPagePicker", | ||||
|   model: { | ||||
|     prop: "value", | ||||
|     event: "input" | ||||
|   }, | ||||
|   props: { | ||||
|     value: {default: ""}, | ||||
|     type: {default: "resident"}, | ||||
|     nodeKey: {default: "idNumber"}, | ||||
|     selected: {default: () => []}, | ||||
|     placeholder: {default: "选择人员"}, | ||||
|     ops: {default: () => ({})}, | ||||
|     valueObj: Boolean, | ||||
|     params: {default: () => ({})}, | ||||
|     multiple: Boolean, | ||||
|     single: Boolean, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       configList: { | ||||
|         resident: {url: "/components/pages/selectResident", label: "name"}, | ||||
|         residentMultiple: {url: "/components/pages/selectResidentMultiple", label: "name"}, | ||||
|         sysUser: {url: "/components/pages/selectSysUser", label: "name"}, | ||||
|         gird: {url: "/components/pages/selectGird", label: "girdName"}, | ||||
|         party: {url: "/components/pages/selectParty", label: "name"}, | ||||
|         dept: {url: "/components/pages/selectDept", label: "name"}, | ||||
|         deptUser: {url: "/components/pages/selectDeptUser", label: "name"}, | ||||
|         custom: {...this.ops} | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     config() { | ||||
|       return this.configList[this.type] || {} | ||||
|     }, | ||||
|     selectedLabel() { | ||||
|       let {placeholder, config: {label}} = this | ||||
|       return this.selected?.map(e => e[label])?.toString() || placeholder | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     handleJump() { | ||||
|       let {config, nodeKey, valueObj, multiple, single} = this, | ||||
|           selected = (valueObj ? this.value[nodeKey] : this.value) || this.selected?.map(e => e[nodeKey]) | ||||
|       uni.$once('pagePicker:' + this.type, data => { | ||||
|         console.log('发送', data) | ||||
|         this.$emit("update:selected", data) | ||||
|         this.$emit("select", data) | ||||
|         this.$emit("input", valueObj ? data : | ||||
|             data ? (multiple ? [data].flat()?.map(e => e[nodeKey]) : data[nodeKey]) : "") | ||||
|       }) | ||||
|       let url = `${config.url}`, | ||||
|           qsstr = qs.stringify({ | ||||
|             selected, nodeKey, multiple, single, ...this.params | ||||
|           }) | ||||
|       if (!!qsstr) { | ||||
|         url += `?${qsstr}` | ||||
|       } | ||||
|       uni.navigateTo({url}) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiPagePicker { | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										120
									
								
								src/components/AiRadio/AiRadio.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,120 @@ | ||||
| <template> | ||||
|   <div class="AiRadio" :class="[isLine ? 'AiRadio-line' : '']"> | ||||
|     <div | ||||
|       class="AiRadio-item" | ||||
|       v-for="(item, index) in options" | ||||
|       @click="onChange(index)" | ||||
|       :class="[currIndex === index ? 'active' : '']" | ||||
|       :key="index"> | ||||
|       {{ item.label }} | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'AiRadio', | ||||
|  | ||||
|     model: { | ||||
|       event: 'input', | ||||
|       prop: 'value' | ||||
|     }, | ||||
|  | ||||
|     props: { | ||||
|       value: String, | ||||
|       placeholder: { | ||||
|         default: '请选择' | ||||
|       }, | ||||
|       list: { | ||||
|         default: () => [] | ||||
|       }, | ||||
|       isLine: Boolean, | ||||
|       dict: String, | ||||
|       disabled: Boolean | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         currIndex: -1, | ||||
|         dictKey: '' | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       options () { | ||||
|         return this.dictKey ? this.$dict.getDict(this.dict).map(e => ({ | ||||
|           value: e.dictValue, | ||||
|           label: e.dictName | ||||
|         })) : this.list | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     mounted () { | ||||
|       this.$dict.load(this.dict).then(() => { | ||||
|         this.dictKey = this.dict | ||||
|  | ||||
|         if (this.value) { | ||||
|           console.log(this.value) | ||||
|           this.$dict.getDict(this.dict).forEach((e, i) => { | ||||
|             console.log(e) | ||||
|             if (e.dictValue === this.value) { | ||||
|               this.currIndex = i | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onChange (index) { | ||||
|         this.currIndex = index | ||||
|         const choosed = this.options[index] | ||||
|         this.$emit('name', choosed.label) | ||||
|         this.$emit('input', choosed.value) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .AiRadio { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     flex-wrap: wrap; | ||||
|  | ||||
|     .AiRadio-item { | ||||
|       width: 212px; | ||||
|       line-height: 1.3; | ||||
|       padding: 20px 32px; | ||||
|       margin-bottom: 16px; | ||||
|       margin-right: 16px; | ||||
|       padding: 20px 32px; | ||||
|       text-align: center; | ||||
|       background: #FFFFFF; | ||||
|       border-radius: 16px; | ||||
|       color: #333333; | ||||
|       font-size: 28px; | ||||
|       border: 1px solid #CCCCCC; | ||||
|       box-sizing: border-box; | ||||
|  | ||||
|       &:nth-of-type(3n) { | ||||
|         margin-right: 0; | ||||
|       } | ||||
|  | ||||
|       &.active { | ||||
|         background: #4181FF; | ||||
|         color: #fff; | ||||
|         border-color: #4181FF; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     &.AiRadio-line { | ||||
|       width: 100%; | ||||
|  | ||||
|       .AiRadio-item { | ||||
|         width: 100%; | ||||
|         margin-right: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										88
									
								
								src/components/AiResult/AiResult.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,88 @@ | ||||
| <template> | ||||
|   <section class="AiResult"> | ||||
|     <slot v-if="$slots.default"/> | ||||
|     <template v-else> | ||||
|       <image :src="result.image"/> | ||||
|       <span class="tips">{{ result.tips }}</span> | ||||
|       <slot name="extra" class="extra" v-if="$slots.extra"/> | ||||
|       <div v-if="result.btn" class="btn" @tap="handleTap">{{ result.btn }}</div> | ||||
|     </template> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiResult", | ||||
|   props: { | ||||
|     tips: {default: "提交成功!"}, | ||||
|     image: {default: "https://cdn.cunwuyun.cn/dvcp/h5/result/success.png"}, | ||||
|     btn: {default: ""}, | ||||
|     status: {default: "success"}, | ||||
|     btnTap: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     result() { | ||||
|       let obj = { | ||||
|         image: this.image, | ||||
|         tips: this.tips, | ||||
|         btn: this.btn | ||||
|       } | ||||
|       if (this.status == "error") { | ||||
|         obj.image = this.$cdn + "result/fail.png" | ||||
|         obj.tips = this.tips || "提交失败!" | ||||
|       } else if (this.status == "loading") { | ||||
|         obj.image = "https://cdn.cunwuyun.cn/wxAdmin/img/message.png" | ||||
|         obj.tips = this.tips || "数据读取中..." | ||||
|       } | ||||
|       return obj | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     handleTap() { | ||||
|       this.btnTap && this.btnTap() | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiResult { | ||||
|   padding-top: 96px; | ||||
|   width: 100%; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
|   font-size: 36px; | ||||
|   font-weight: bold; | ||||
|  | ||||
|   & > image { | ||||
|     width: 192px; | ||||
|     height: 192px; | ||||
|   } | ||||
|  | ||||
|   .tips { | ||||
|     margin: 16px auto 0; | ||||
|     color: #333; | ||||
|   } | ||||
|  | ||||
|   .extra { | ||||
|     margin-top: 48px; | ||||
|   } | ||||
|  | ||||
|   .btn { | ||||
|     cursor: pointer; | ||||
|     margin-top: 80px; | ||||
|     width: calc(100% - 192px); | ||||
|     height: 88px; | ||||
|     background: #197DF0; | ||||
|     box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02); | ||||
|     border-radius: 8px; | ||||
|     color: #FFF; | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     font-weight: 500; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										105
									
								
								src/components/AiSelect/AiSelect.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,105 @@ | ||||
| <template> | ||||
|   <section class="AiSelect"> | ||||
|     <picker :range="options" :range-key="labelName" @change="handleConfirm" :disabled="disabled" :mode="mode"> | ||||
|       <div class="display" v-if="$slots.default"> | ||||
|         <slot/> | ||||
|       </div> | ||||
|       <div v-else class="display"> | ||||
|         <u-icon v-if="selectedLabel" :label="selectedLabel" label-pos="left" name="arrow-right" color="#ddd"/> | ||||
|         <u-icon v-else :label="placeholder" label-pos="left" name="arrow-right" color="#ddd" label-color="#999"/> | ||||
|       </div> | ||||
|     </picker> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiSelect", | ||||
|   model: { | ||||
|     event: "input", | ||||
|     prop: "value" | ||||
|   }, | ||||
|   props: { | ||||
|     value: String, | ||||
|     placeholder: {default: "请选择"}, | ||||
|     list: {default: () => []}, | ||||
|     mode: {default: "selector"}, | ||||
|     dict: {default: ""}, | ||||
|     disabled: Boolean, | ||||
|     labelName: {default: "label"}, | ||||
|     valueName: {default: "value"}, | ||||
|   }, | ||||
|   computed: { | ||||
|     selectedLabel() { | ||||
|       let str = this.options.find(e => e?.[this.valueName] == this.value)?.[this.labelName] | ||||
|       return this.selected?.[this.labelName] || str | ||||
|     }, | ||||
|     options() { | ||||
|       return this.dictKey ? this.$dict.getDict(this.dict).map(e => ({ | ||||
|         value: e.dictValue, | ||||
|         label: e.dictName | ||||
|       })) : this.list || [] | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     selectedLabel: { | ||||
|       immediate: true, | ||||
|       handler(v) { | ||||
|         this.$emit('name', v) | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       dictKey: '', | ||||
|       selected: {} | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict && this.$dict.load(this.dict).then(() => { | ||||
|       this.dictKey = this.dict | ||||
|     }) | ||||
|   }, | ||||
|   methods: { | ||||
|     handleConfirm(v) { | ||||
|       if (this.mode == "selector") { | ||||
|         this.selected = this.options?.[v.detail?.value] || {} | ||||
|         this.$emit("data", this.selected) | ||||
|         this.$emit("input", this.selected?.[this.valueName]) | ||||
|       } | ||||
|  | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiSelect { | ||||
|   max-width: 100%; | ||||
|  | ||||
|   ::v-deep .u-icon { | ||||
|     margin-left: 8px; | ||||
|   } | ||||
|  | ||||
|   .display { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|  | ||||
|     .selectedLabel { | ||||
|       flex: 1; | ||||
|       min-width: 0; | ||||
|       overflow: hidden; | ||||
|       text-overflow: ellipsis; | ||||
|       font-size: 30px; | ||||
|       color: #333; | ||||
|       white-space: nowrap; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   i { | ||||
|     font-style: normal; | ||||
|     font-size: 30px; | ||||
|     color: $uni-text-color-grey; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										79
									
								
								src/components/AiStep/AiStep.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,79 @@ | ||||
| <template> | ||||
|   <section class="AiStep flex start" :class="{active}"> | ||||
|     <div class="leftPane mar-r32"> | ||||
|       <div class="num" v-text="stepIndex"/> | ||||
|       <div v-if="!isLast" class="stepLine fill"/> | ||||
|     </div> | ||||
|     <div class="fill"> | ||||
|       <slot/> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiStep", | ||||
|   inject: ['activeStep'], | ||||
|   props: { | ||||
|     index: {default: null}, | ||||
|   }, | ||||
|   computed: { | ||||
|     active: v => v.activeStep == v.stepIndex, | ||||
|     stepIndex: v => { | ||||
|       const index = v.$parent.items.findIndex(e => e == v._uid) | ||||
|       return index > -1 ? index + 1 : "" | ||||
|     }, | ||||
|     isLast: v => v.$parent.items.length == v.stepIndex | ||||
|   }, | ||||
|   created() { | ||||
|     this.$parent.items.splice(this.index, 0, this._uid) | ||||
|   }, | ||||
|   destroyed() { | ||||
|     const index = this.$parent.items.findIndex(e => e == this._uid) | ||||
|     this.$parent.items.splice(index, 1) | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiStep { | ||||
|   width: 100%; | ||||
|   font-size: 28px; | ||||
|   position: relative; | ||||
|  | ||||
|   .leftPane { | ||||
|     width: 32px; | ||||
|  | ||||
|     .num { | ||||
|       color: #333; | ||||
|       height: 32px; | ||||
|       width: 32px; | ||||
|       font-size: 28px; | ||||
|       line-height: 32px; | ||||
|       text-align: center; | ||||
|       border: 4px solid #CCCCCC; | ||||
|       border-radius: 50%; | ||||
|     } | ||||
|  | ||||
|     .stepLine { | ||||
|       position: absolute; | ||||
|       top: 40px; | ||||
|       bottom: 0; | ||||
|       width: 4px; | ||||
|       left: 20px; | ||||
|       transform: translateX(-50%); | ||||
|       background: #eee; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   &.active { | ||||
|     .leftPane { | ||||
|       .num { | ||||
|         background: #26f; | ||||
|         border-color: #26f; | ||||
|         color: #fff; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										203
									
								
								src/components/AiTMap/AiTMap.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,203 @@ | ||||
| <template> | ||||
|   <section class="AiTMap"> | ||||
|     <div ref="tmap" class="map"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: "AiTMap", | ||||
|   props: { | ||||
|     /** | ||||
|      * 地区id | ||||
|      */ | ||||
|     areaId: String, | ||||
|     /** | ||||
|      * 地图参数,详情见https://lbs.qq.com/webApi/javascriptGL/glDoc/docIndexMap | ||||
|      */ | ||||
|     ops: {default: () => ({})}, | ||||
|     /** | ||||
|      * 加载三方库,以腾讯地图文档要求进行添加 | ||||
|      */ | ||||
|     libraries: {default: () => ["service"]}, | ||||
|     /** | ||||
|      * 地图实例,支持用.sync绑定获取 | ||||
|      */ | ||||
|     map: Object, | ||||
|     /** | ||||
|      * 地图库,支持用.sync绑定获取 | ||||
|      */ | ||||
|     lib: Object, | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['wxwork']), | ||||
|     key() { | ||||
|       return process.env.NODE_ENV == "production" ? | ||||
|           "RWWBZ-64BEJ-MVLFJ-FTHLQ-JTR6J-SAB2S" : | ||||
|           "3RZBZ-LZUCF-CT6J5-NWKZH-FCWOQ-UUFKY" | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       tmap: null, | ||||
|       mapLib: null | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     injectLib(url, cb) { | ||||
|       const script = document.createElement('script') | ||||
|       script.type = 'text/javascript'; | ||||
|       script.id = "aitmap"; | ||||
|       script.src = url; | ||||
|       script.addEventListener('load', () => { | ||||
|         cb && cb() | ||||
|       }) | ||||
|       document.body.appendChild(script); | ||||
|     }, | ||||
|     initTMap() { | ||||
|       let latLng = {} | ||||
|       if (this.wxwork.config.lat) { //通用版 | ||||
|         latLng = this.wxwork.config | ||||
|         this.mapLib = TMap | ||||
|         this.tmap = new TMap.Map(this.$refs.tmap, { | ||||
|           zoom: 11, | ||||
|           center: new TMap.LatLng(latLng.lat, latLng.lng), | ||||
|           ...this.ops | ||||
|         }) | ||||
|         this.$emit('update:lib', TMap) | ||||
|         this.$emit('update:map', this.tmap) | ||||
|         this.$emit('loaded') | ||||
|         this.areaId && this.getMapArea() | ||||
|       } else {  //上架版 | ||||
|         uni.getLocation({ | ||||
|           type: "gcj02", | ||||
|           success: res => { | ||||
|             latLng = { | ||||
|               lat: res.latitude, | ||||
|               lng: res.longitude | ||||
|             } | ||||
|             if (latLng.lat) { | ||||
|               // this.mapLib = TMap | ||||
|               // this.tmap = new TMap.Map(this.$refs.tmap, { | ||||
|               //   zoom: 11, | ||||
|               //   center: new TMap.LatLng(latLng.lat, latLng.lng), | ||||
|               //   ...this.ops | ||||
|               // }) | ||||
|               // this.$emit('update:lib', TMap) | ||||
|               // this.$emit('update:map', this.tmap) | ||||
|               // this.$emit('loaded') | ||||
|               // this.areaId && this.getMapArea() | ||||
|             } | ||||
|           } | ||||
|         }) | ||||
|         this.mapLib = TMap | ||||
|         this.tmap = new TMap.Map(this.$refs.tmap, { | ||||
|           zoom: 11, | ||||
|           // center: new TMap.LatLng(latLng.lat, latLng.lng), | ||||
|           ...this.ops | ||||
|         }) | ||||
|         this.$emit('update:lib', TMap) | ||||
|         this.$emit('update:map', this.tmap) | ||||
|         this.$emit('loaded') | ||||
|         this.areaId && this.getMapArea() | ||||
|       } | ||||
|     }, | ||||
|     fitBounds(latLngList, count = 0) { | ||||
|       // 由多边形顶点坐标数组计算能完整呈现该多边形的最小矩形范围 | ||||
|       let {mapLib: TMap} = this | ||||
|       if (TMap) { | ||||
|         if (latLngList.length === 0) { | ||||
|           return null; | ||||
|         } | ||||
|         let boundsN = latLngList[0].getLat(); | ||||
|         let boundsS = boundsN; | ||||
|         let boundsW = latLngList[0].getLng(); | ||||
|         let boundsE = boundsW; | ||||
|         latLngList.forEach((point) => { | ||||
|           point.getLat() > boundsN && (boundsN = point.getLat()); | ||||
|           point.getLat() < boundsS && (boundsS = point.getLat()); | ||||
|           point.getLng() > boundsE && (boundsE = point.getLng()); | ||||
|           point.getLng() < boundsW && (boundsW = point.getLng()); | ||||
|         }); | ||||
|         return new TMap.LatLngBounds( | ||||
|             new TMap.LatLng(boundsS, boundsW), | ||||
|             new TMap.LatLng(boundsN, boundsE) | ||||
|         ); | ||||
|       } else { | ||||
|         if (count < 5) { | ||||
|           this.fitBounds(latLngList, ++count) | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     getMapArea() { | ||||
|       let {mapLib, areaId, tmap: map} = this, keyword = areaId.substring(0, 6) | ||||
|       let polygons = new TMap.MultiPolygon({map, geometries: []}); | ||||
|       new mapLib.service.District({ | ||||
|         polygon: 2, | ||||
|         maxOffset: 100 | ||||
|       }).search({keyword}).then(res => { | ||||
|         if (res?.result) { | ||||
|           let center = res.result?.[0]?.[0]?.location | ||||
|           this.tmap.setCenter(center) | ||||
|           res.result.forEach((level) => { | ||||
|             level.forEach((place) => { | ||||
|               let bounds = []; | ||||
|               let newGeometries = place.polygon.map((polygon, index) => { | ||||
|                 bounds.push(this.fitBounds(polygon)); // 计算能完整呈现行政区边界的最小矩形范围 | ||||
|                 return { | ||||
|                   id: `${place.id}_${index}`, | ||||
|                   paths: polygon, // 将得到的行政区划边界用多边形标注在地图上 | ||||
|                 }; | ||||
|               }); | ||||
|               bounds = bounds.reduce((a, b) => { | ||||
|                 return this.fitBounds([ | ||||
|                   a.getNorthEast(), | ||||
|                   a.getSouthWest(), | ||||
|                   b.getNorthEast(), | ||||
|                   b.getSouthWest(), | ||||
|                 ]); | ||||
|               }); // 若一行政区有多个多边形边界,应计算能包含所有多边形边界的范围。 | ||||
|               polygons.updateGeometries(newGeometries); | ||||
|               this.tmap.fitBounds(bounds); | ||||
|             }); | ||||
|           }); | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   mounted() { | ||||
|     if (!window?.TMap) { | ||||
|       window.initTMap = this.initTMap | ||||
|       this.injectLib(`https://map.qq.com/api/gljs?v=1.exp&key=${this.key}&libraries=${this.libraries.toString()}&callback=initTMap`) | ||||
|     } else { | ||||
|       this.initTMap() | ||||
|     } | ||||
|   }, | ||||
|   destroyed() { | ||||
|     this.map.destroy() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiTMap { | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   flex: 1; | ||||
|   min-width: 0; | ||||
|   min-height: 0; | ||||
|  | ||||
|   ::v-deep.map { | ||||
|     height: 100%; | ||||
|  | ||||
|     & > div > div { | ||||
|       &:nth-of-type(2), &:nth-of-type(3) { | ||||
|         display: none; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										48
									
								
								src/components/AiTable/AiTable.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,48 @@ | ||||
| <template> | ||||
|   <section class="AiTable"> | ||||
|     <u-table color="#333"> | ||||
|       <u-tr> | ||||
|         <u-th v-for="(col,i) in colConfigs" :key="i" :width="col.width">{{ col.label }}</u-th> | ||||
|       </u-tr> | ||||
|       <u-tr v-for="(row,j) in data" :key="j"> | ||||
|         <u-td v-for="(col,i) in colConfigs" :key="i" :width="col.width"> | ||||
|           <slot v-if="col.slot" :name="col.slot" :row="row"/> | ||||
|           <p v-else-if="col.dict">{{ $dict.getLabel(col.dict, row[col.prop]) }}</p> | ||||
|           <p v-else>{{ row[col.prop] || "-" }}</p> | ||||
|         </u-td> | ||||
|       </u-tr> | ||||
|     </u-table> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|   name: "AiTable", | ||||
|   props: { | ||||
|     data: {default: () => []}, | ||||
|     colConfigs: {default: () => []}, | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiTable { | ||||
|   border-radius: 8px; | ||||
|   min-height: 100px; | ||||
|   overflow: hidden; | ||||
|  | ||||
|   .u-table, .u-th { | ||||
|     border-color: #D0D4DC !important; | ||||
|   } | ||||
|  | ||||
|   .u-th { | ||||
|     background-color: #DFE6F4; | ||||
|     color: #646D7F; | ||||
|   } | ||||
|  | ||||
|   .u-tr { | ||||
|     height: 80px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										62
									
								
								src/components/AiThumbsUp/AiThumbsUp.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,62 @@ | ||||
| <template> | ||||
|   <section class="AiThumbsUp flex" :class="{checked}" @click.native="handleClick"> | ||||
|     <div class="count" v-text="count||0"/> | ||||
|     <u-icon :name="thumbIcon"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiThumbsUp", | ||||
|   props: { | ||||
|     bid: {default: ""}, | ||||
|     count: {default: 0}, | ||||
|     btn: Boolean, | ||||
|     type: {default: "content"}, | ||||
|     action: {default: ""} | ||||
|   }, | ||||
|   computed: { | ||||
|     thumbIcon() { | ||||
|       return this.checked ? "thumb-up-fill" : "thumb-up" | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       checked: false, | ||||
|       actions: { | ||||
|         content: "/app/appcontentinfo/supportById", | ||||
|         comment: "/app/appcontentcomment/supportById", | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     handleClick() { | ||||
|       if (!this.checked) { | ||||
|         let {action, type, actions, bid: id} = this | ||||
|         this.$instance.post(action || actions[type], null, { | ||||
|           params: {id} | ||||
|         }).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.checked = true | ||||
|             this.$emit("update:count", ++this.count) | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiThumbsUp { | ||||
|   color: #666; | ||||
|  | ||||
|   &.checked { | ||||
|     color: #2D7DFF; | ||||
|   } | ||||
|  | ||||
|   .count { | ||||
|     margin-right: 8px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										65
									
								
								src/components/AiTopFixed/AiTopFixed.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,65 @@ | ||||
| <template> | ||||
|   <section class="AiTopFixed" :style="{background}"> | ||||
|     <!--占位区--> | ||||
|     <div class="placeholder"> | ||||
|       <div v-if="$slots.tabs"> | ||||
|         <slot name="tabs"/> | ||||
|       </div> | ||||
|       <div class="content" v-if="$slots.default"> | ||||
|         <slot/> | ||||
|       </div> | ||||
|     </div> | ||||
|     <!--悬浮区--> | ||||
|     <div class="fixed" :style="{background}"> | ||||
|       <div v-if="$slots.tabs"> | ||||
|         <slot name="tabs"/> | ||||
|       </div> | ||||
|       <div class="content" v-if="$slots.default"> | ||||
|         <slot/> | ||||
|       </div> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiTopFixed", | ||||
|   props: { | ||||
|     background: {default: "#fff"} | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiTopFixed { | ||||
|   width: 100%; | ||||
|  | ||||
|   & > div { | ||||
|     width: 100%; | ||||
|   } | ||||
|  | ||||
|   .fixed { | ||||
|     width: 100%; | ||||
|     min-height: 100px; | ||||
|     top: 0; | ||||
|     position: fixed; | ||||
|     z-index: 9; | ||||
|   } | ||||
|  | ||||
|   .placeholder { | ||||
|     visibility: hidden; | ||||
|     opacity: 0; | ||||
|   } | ||||
|  | ||||
|   .content { | ||||
|     min-height: 100px; | ||||
|     padding: 20px 32px; | ||||
|     box-sizing: border-box; | ||||
|   } | ||||
|  | ||||
|   ::v-deep .u-search { | ||||
|     box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02); | ||||
|     margin-bottom: 32px !important; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										146
									
								
								src/components/AiTransSpeech/AiTransSpeech.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,146 @@ | ||||
| <template> | ||||
|   <div class="AiTransSpeech" v-if="!noSpeech"> | ||||
|     <button title="语音播报" @click="getSpeech"> | ||||
|       <div> | ||||
|         <div class="iconfont" :class="{playing:loading}"></div> | ||||
|       </div> | ||||
|       <div>{{ text }}</div> | ||||
|     </button> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiTransSpeech", | ||||
|   props: { | ||||
|     src: String, | ||||
|     content: String | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       audioContext: null, | ||||
|       speech: "", | ||||
|       loading: false, | ||||
|       text: "开始" | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     speechString() { | ||||
|       return this.content ? this.content.replace(/<\/?.+?\/?>/g, "") : "" | ||||
|     }, | ||||
|     noSpeech() { | ||||
|       return !this.src && !this.content | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getSpeech() { | ||||
|       if (!this.noSpeech) { | ||||
|         if (this.audioContext) { | ||||
|           if (this.loading) { | ||||
|             this.loading = false | ||||
|             this.audioContext.pause() | ||||
|           } else { | ||||
|             this.loading = true | ||||
|             this.audioContext.play() | ||||
|           } | ||||
|         } else if (this.content) { | ||||
|           this.loading = true | ||||
|           if (!this.speech) { | ||||
|             this.$instance.post("/app/msc/transToSpeech" + `?fileName=demo&words=${this.speechString}`).then(res => { | ||||
|               if (res && res.data) { | ||||
|                 let url = res.data.join("") | ||||
|                 this.speech = url.substring(0, url.indexOf(";")) | ||||
|                 this.playAudio() | ||||
|               } | ||||
|             }).catch(() => this.loading = false) | ||||
|           } else { | ||||
|             this.playAudio() | ||||
|           } | ||||
|         } else if (this.src) { | ||||
|           this.loading = true | ||||
|           this.speech = this.src | ||||
|           this.playAudio() | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     playAudio() { | ||||
|       let _ = this | ||||
|       this.audioContext = uni.createInnerAudioContext(); | ||||
|       this.audioContext.src = this.speech; | ||||
|       this.audioContext.play() | ||||
|       this.audioContext.onPlay(() => { | ||||
|         _.text = "暂停" | ||||
|       }); | ||||
|       this.audioContext.onPause(() => { | ||||
|         _.loading = false | ||||
|         _.text = "开始" | ||||
|       }); | ||||
|       this.audioContext.onEnded(() => { | ||||
|         _.loading = false | ||||
|         _.text = "开始" | ||||
|       }); | ||||
|       this.audioContext.onError((res) => { | ||||
|         console.error(res.errMsg); | ||||
|         _.text = "开始" | ||||
|       }); | ||||
|     }, | ||||
|   }, | ||||
|   destroyed() { | ||||
|     if (this.audioContext) { | ||||
|       this.audioContext.pause() | ||||
|       this.audioContext.destroy() | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AiTransSpeech { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
|  | ||||
|   button { | ||||
|     position: fixed; | ||||
|     right: 80px; | ||||
|     bottom: 150px; | ||||
|     width: 104px; | ||||
|     height: 104px; | ||||
|     background: linear-gradient(130deg, rgba(70, 192, 253, 1) 0%, rgba(37, 158, 249, 1) 57%, rgba(39, 148, 248, 1) 100%); | ||||
|     border-radius: 50%; | ||||
|     font-size: 24px; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
|     color: #fff !important; | ||||
|     z-index: 10000; | ||||
|  | ||||
|     & > div { | ||||
|       width: 48px; | ||||
|       white-space: nowrap; | ||||
|       line-height: normal; | ||||
|  | ||||
|       .iconfont { | ||||
|         width: 48px; | ||||
|         font-size: 48px; | ||||
|         line-height: 48px; | ||||
|         overflow: hidden; | ||||
|  | ||||
|         &.playing { | ||||
|           animation: playingSpeech .5s infinite; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @keyframes playingSpeech { | ||||
|     from { | ||||
|       width: 30px | ||||
|     } | ||||
|     to { | ||||
|       width: 100% | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										59
									
								
								src/components/AiTreePath/AiTreePath.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,59 @@ | ||||
| <template> | ||||
|   <section class="AiTreePath"> | ||||
|     <b v-text="`全部`" @click="$emit('click','all')"/> | ||||
|     <div flex v-for="p in parents" :key="p.id"> | ||||
|       <u-icon name="arrow-right" size="32" color="#ccc"/> | ||||
|       <div class="mar-l8" v-text="p[options.label]" @click="$emit('click',p)"/> | ||||
|     </div> | ||||
|     <u-icon v-if="label" name="arrow-right" size="32" color="#ccc"/> | ||||
|     <div class="active" v-text="label" @click="$emit('click',node)"/> | ||||
|   </section> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   name: "AiTreePath", | ||||
|   props: { | ||||
|     prop: {default: () => ({})}, | ||||
|     paths: {default: () => ({})}, | ||||
|     node: {default: null} | ||||
|   }, | ||||
|   computed: { | ||||
|     options: v => ({ | ||||
|       id: 'id', | ||||
|       label: 'name', | ||||
|       parent: 'parentId', | ||||
|       ...v.prop | ||||
|     }), | ||||
|     label: v => v.node?.[v.options.label] || "", | ||||
|     parent: v => v.paths?.[v.node?.[v.options.parent]], | ||||
|     parents() { | ||||
|       const arr = [] | ||||
|       const {id: KEY, parent: PARENT} = this.options | ||||
|       const find = n => { | ||||
|         if (!!n?.[KEY]) { | ||||
|           arr.unshift(n) | ||||
|           find(this.paths[n?.[PARENT]]) | ||||
|         } | ||||
|       } | ||||
|       find(this.parent) | ||||
|       return arr | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <style scoped lang="scss"> | ||||
| .AiTreePath { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   gap: 8px; | ||||
|   font-size: 36px; | ||||
|   line-height: 40px; | ||||
|   font-family: PingFang-SC; | ||||
|   flex-wrap: wrap; | ||||
|  | ||||
|   .active { | ||||
|     font-weight: bold; | ||||
|     color: #26f | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										419
									
								
								src/components/AiUniIcon/AiUniIcon.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										300
									
								
								src/components/AiUploader/AiUploader.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,300 @@ | ||||
| <template> | ||||
|   <div class="ai-uploader"> | ||||
|     <div class="imgList" v-if="type == 'image'"> | ||||
|       <div class="item" v-for="(item, i) in fileList" :key="i"> | ||||
|         <ai-image :src="item.url" :preview="preview"/> | ||||
|         <u-icon v-if="!disabled" class="delBtn" color="#f46" name="close-circle-fill" size="40" @click="remove(i)"/> | ||||
|       </div> | ||||
|       <div v-if="!disabled&&(fileList.length == 0 || (fileList.length < limit))" class="default" @click="upload"> | ||||
|         <u-icon name="photo" size="64" :label="placeholder" label-pos="bottom" label-color="#89b"/> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="imgList" v-else-if="type == 'video'"> | ||||
|       <div class="item" v-for="(item, i) in fileList" :key="i"> | ||||
|         <video :src="item.url" :poster="item.thumb"/> | ||||
|         <u-icon v-if="!disabled" class="delBtn" color="#f46" name="close-circle-fill" size="40" @click="remove(i)"/> | ||||
|       </div> | ||||
|       <div v-if="!disabled&&(fileList.length == 0 || (fileList.length < limit))" class="default" @click="upload"> | ||||
|         <u-icon name="camera" size="64" :label="placeholder" label-pos="bottom" label-color="#89b"/> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="fileList" v-else> | ||||
|       <div class="item" v-for="(item, i) in fileList" :key="i"> | ||||
|         <ai-image :preview="preview" :file="item"/> | ||||
|         <div class="info"> | ||||
|           <span>{{ item.name }} </span> | ||||
|           <i>{{ item.fileSizeStr }}</i> | ||||
|         </div> | ||||
|         <template v-if="!disabled"> | ||||
|           <div class="btn" @tap="handleReUpload(i)"> | ||||
|             重新上传 | ||||
|           </div> | ||||
|           <div class="btn" @tap="remove(i)"> | ||||
|             删除 | ||||
|           </div> | ||||
|         </template> | ||||
|       </div> | ||||
|       <div v-if="!disabled&&(fileList.length == 0 || (multiple && fileList.length < limit))" class="default" | ||||
|            @click="upload"> | ||||
|         <u-icon name="photo" size="64" :label="placeholder" label-pos="bottom" label-color="#89b"/> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
| import AiImage from '../AiImage/AiImage' | ||||
|  | ||||
| export default { | ||||
|   name: 'AiUploader', | ||||
|   components: {AiImage}, | ||||
|   model: { | ||||
|     prop: 'def', // :def.sync才可以回显,v-model不能回显(bug) | ||||
|     event: 'input' | ||||
|   }, | ||||
|   props: { | ||||
|     limit: {default: 1}, //数量 | ||||
|     placeholder: {default: '添加图片'}, // 文字提示 | ||||
|     type: {default: 'image'}, // 文件类型:image,file,video | ||||
|     multiple: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     fileId: String, | ||||
|     mediaId: String, | ||||
|     def: {default: () => []}, | ||||
|     action: String, | ||||
|     preview: Boolean, | ||||
|     size: {default: 10 * 1024 * 1024}, | ||||
|     disabled: Boolean, | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['token']), | ||||
|     errorImage: v => v.$cdn + 'file.png', | ||||
|     api() { | ||||
|       if (this.action) return this.action | ||||
|       else return { | ||||
|         image: '/admin/file/add', | ||||
|         file: '/admin/file/add', | ||||
|         video: '/admin/file/addVideo', | ||||
|       }[this.type] | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     def: { | ||||
|       handler(v) { | ||||
|         if (!!v?.toString()) { | ||||
|           if (this.multiple) { | ||||
|             this.fileList = v | ||||
|           } else if (v?.url) { | ||||
|             this.fileList = [v] | ||||
|           } else if (v?.length > 0) { | ||||
|             this.fileList = v | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       immediate: true, | ||||
|       deep: true | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       fileList: [], | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     remove(index) { | ||||
|       this.fileList.splice(index, 1) | ||||
|       this.$emit('input', this.fileList) | ||||
|     }, | ||||
|     upload(wait) { | ||||
|       let count = this.limit - (this.fileList?.length || 0) | ||||
|       if (count > 0) { | ||||
|         const params = { | ||||
|           count, | ||||
|           sizeType: ['compressed'], | ||||
|           sourceType: ['album', 'camera'], | ||||
|           success: res => { | ||||
|             let count = this.fileList?.length + (res.tempFiles?.length || res.tempFile ? 1 : 0) | ||||
|             if (count > this.limit && this.limit !== 1) { | ||||
|               return this.$u.toast(`不能超过${this.limit}个`) | ||||
|             } | ||||
|             if (res.tempFiles?.length > 0) { | ||||
|               res.tempFiles.map(this.uploadFile) | ||||
|             } else if (res?.tempFile) { | ||||
|               this.uploadFile(res.tempFile) | ||||
|             } | ||||
|           }, | ||||
|         } | ||||
|         typeof wait == 'function' && wait() | ||||
|         if (this.type == 'image') { | ||||
|           uni.chooseMedia({...params, mediaType: ['image']}) | ||||
|         } else if (this.type == 'video') { | ||||
|           uni.chooseMedia({...params, mediaType: ['video']}) | ||||
|         } else { | ||||
|           uni.chooseFile(params) | ||||
|         } | ||||
|       } else { | ||||
|         this.$u.toast(`不能超过${this.limit}个`) | ||||
|       } | ||||
|     }, | ||||
|     uploadFile(img) { | ||||
|       if (this.size > 0 && img.size > this.size) { | ||||
|         return this.$u.toast(`不能超过${Math.ceil(this.size / 1024 / 1024)}MB`) | ||||
|       } | ||||
|       uni.showLoading({title: '上传中'}) | ||||
|       if (this.manual) { | ||||
|         this.$emit('manual', img) | ||||
|         uni.hideLoading() | ||||
|       } else { | ||||
|         const filePath = img.path || img.tempFilePath | ||||
|         uni.uploadFile({ | ||||
|           url: this.$instance.defaults.baseURL + this.api, | ||||
|           filePath, | ||||
|           name: 'file', | ||||
|           header: { | ||||
|             'Content-Type': 'multipart/form-data', | ||||
|             Authorization: this.token, | ||||
|           }, | ||||
|           success: response => { | ||||
|             const res = JSON.parse(response.data) | ||||
|             if (res?.data) { | ||||
|               this.$emit('data', res.data) | ||||
|               this.$u.toast('上传成功!') | ||||
|               if (!this.action) {//默认组件接口 | ||||
|                 if (this.type == 'image') { | ||||
|                   const [image = "",] = res.data | ||||
|                   this.fileList.push({url: image.split(";")[0], id: image.split(";")?.[1]}) | ||||
|                 } else if (this.type == 'video') { | ||||
|                   const [video = "", thumb = ""] = res.data | ||||
|                   this.fileList.push({url: video.split(";")[0], id: video.split(";")?.[1], thumb: thumb.split(";")[0]}) | ||||
|                 } | ||||
|               } else if (this.api == '/admin/file/add2') { | ||||
|                 let info = res.data | ||||
|                 this.$emit('update:fileId', info?.id) | ||||
|                 this.fileList.push(res.data) | ||||
|               } else if (this.api == '/admin/file/add-portrait') { | ||||
|                 this.fileList.push({url: res.data?.split(";")?.[0], id: res.data?.split(";")?.[1]}) | ||||
|               } | ||||
|               this.$emit("input", this.fileList) | ||||
|               this.$emit("update:def", this.fileList) | ||||
|             } else { | ||||
|               this.$u.toast(res.msg) | ||||
|             } | ||||
|           }, | ||||
|           fail: console.error, | ||||
|           complete: uni.hideLoading | ||||
|         }) | ||||
|       } | ||||
|  | ||||
|     }, | ||||
|     handleReUpload(i) { | ||||
|       this.upload(() => this.remove(i)) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .ai-uploader { | ||||
|   width: 100%; | ||||
|   line-height: normal; | ||||
|   margin-bottom: 16px; | ||||
|  | ||||
|   ::v-deep.imgList { | ||||
|     display: flex; | ||||
|     flex-wrap: wrap; | ||||
|  | ||||
|     .item { | ||||
|       width: 27vw; | ||||
|       height: 27vw; | ||||
|       position: relative; | ||||
|       padding: 0 2pt 2pt 0; | ||||
|       box-sizing: border-box; | ||||
|  | ||||
|       .delBtn { | ||||
|         position: absolute; | ||||
|         right: -8px; | ||||
|         top: -8px; | ||||
|         z-index: 2; | ||||
|         border-radius: 50%; | ||||
|         overflow: hidden; | ||||
|         background-color: #fff; | ||||
|         height: 40px; | ||||
|       } | ||||
|  | ||||
|       image,video { | ||||
|         width: 27vw; | ||||
|         height: 27vw; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .fileList { | ||||
|     .item { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       margin-bottom: 10px; | ||||
|  | ||||
|       image { | ||||
|         width: 160px; | ||||
|         height: 160px; | ||||
|       } | ||||
|  | ||||
|       i { | ||||
|         font-style: normal; | ||||
|         color: #9b9b9b; | ||||
|       } | ||||
|  | ||||
|       .info { | ||||
|         flex: 1; | ||||
|         min-width: 0; | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         align-items: flex-start; | ||||
|         overflow: hidden; | ||||
|         text-overflow: ellipsis; | ||||
|  | ||||
|         & > span { | ||||
|           flex: 1; | ||||
|           min-width: 0; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       div.btn { | ||||
|         color: $uni-color-primary; | ||||
|         margin-right: 16px; | ||||
|  | ||||
|       } | ||||
|  | ||||
|       div:nth-child(4) { | ||||
|         color: #f72c27; | ||||
|       } | ||||
|  | ||||
|       & > * + * { | ||||
|         margin-left: 20px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|  | ||||
|   } | ||||
|  | ||||
|   .default { | ||||
|     width: 27vw; | ||||
|     height: 27vw; | ||||
|     box-sizing: border-box; | ||||
|     border-radius: 8px; | ||||
|     background: #f3f4f7; | ||||
|     color: #89b; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|  | ||||
|     .iconfont-iconAdd { | ||||
|       font-size: 64px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										522
									
								
								src/components/ckeditor.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,522 @@ | ||||
| /* | ||||
|  * CKEditor 5 (v34.2.0) content styles. | ||||
|  * Generated on Fri, 29 Jul 2022 13:03:52 GMT. | ||||
|  * For more information, check out https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/content-styles.html | ||||
|  */ | ||||
|  | ||||
| :root { | ||||
|   --ck-color-base-active: hsl(208, 88%, 52%); | ||||
|   --ck-color-image-caption-background: hsl(0, 0%, 97%); | ||||
|   --ck-color-image-caption-text: hsl(0, 0%, 20%); | ||||
|   --ck-color-mention-background: hsla(341, 100%, 30%, 0.1); | ||||
|   --ck-color-mention-text: hsl(341, 100%, 30%); | ||||
|   --ck-color-table-caption-background: hsl(0, 0%, 97%); | ||||
|   --ck-color-table-caption-text: hsl(0, 0%, 20%); | ||||
|   --ck-color-table-column-resizer-hover: var(--ck-color-base-active); | ||||
|   --ck-highlight-marker-blue: hsl(201, 97%, 72%); | ||||
|   --ck-highlight-marker-green: hsl(120, 93%, 68%); | ||||
|   --ck-highlight-marker-pink: hsl(345, 96%, 73%); | ||||
|   --ck-highlight-marker-yellow: hsl(60, 97%, 73%); | ||||
|   --ck-highlight-pen-green: hsl(112, 100%, 27%); | ||||
|   --ck-highlight-pen-red: hsl(0, 85%, 49%); | ||||
|   --ck-image-style-spacing: 1.5em; | ||||
|   --ck-inline-image-style-spacing: calc(var(--ck-image-style-spacing) / 2); | ||||
|   --ck-table-column-resizer-position-offset: calc(var(--ck-table-column-resizer-width) * -0.5 - 0.5px); | ||||
|   --ck-table-column-resizer-width: 7px; | ||||
|   --ck-todo-list-checkmark-size: 16px; | ||||
|   --ck-z-default: 1; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-block-quote/theme/blockquote.css */ | ||||
| .ck-content blockquote { | ||||
|   overflow: hidden; | ||||
|   padding-right: 1.5em; | ||||
|   padding-left: 1.5em; | ||||
|   margin-left: 0; | ||||
|   margin-right: 0; | ||||
|   font-style: italic; | ||||
|   border-left: solid 5px hsl(0, 0%, 80%); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-block-quote/theme/blockquote.css */ | ||||
| .ck-content[dir="rtl"] blockquote { | ||||
|   border-left: 0; | ||||
|   border-right: solid 5px hsl(0, 0%, 80%); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-basic-styles/theme/code.css */ | ||||
| .ck-content code { | ||||
|   background-color: hsla(0, 0%, 78%, 0.3); | ||||
|   padding: .15em; | ||||
|   border-radius: 2px; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-font/theme/fontsize.css */ | ||||
| .ck-content .text-tiny { | ||||
|   font-size: .7em; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-font/theme/fontsize.css */ | ||||
| .ck-content .text-small { | ||||
|   font-size: .85em; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-font/theme/fontsize.css */ | ||||
| .ck-content .text-big { | ||||
|   font-size: 1.4em; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-font/theme/fontsize.css */ | ||||
| .ck-content .text-huge { | ||||
|   font-size: 1.8em; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .marker-yellow { | ||||
|   background-color: var(--ck-highlight-marker-yellow); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .marker-green { | ||||
|   background-color: var(--ck-highlight-marker-green); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .marker-pink { | ||||
|   background-color: var(--ck-highlight-marker-pink); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .marker-blue { | ||||
|   background-color: var(--ck-highlight-marker-blue); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .pen-red { | ||||
|   color: var(--ck-highlight-pen-red); | ||||
|   background-color: transparent; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .pen-green { | ||||
|   color: var(--ck-highlight-pen-green); | ||||
|   background-color: transparent; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/image.css */ | ||||
| .ck-content .image { | ||||
|   display: table; | ||||
|   clear: both; | ||||
|   text-align: center; | ||||
|   margin: 0.9em auto; | ||||
|   min-width: 50px; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/image.css */ | ||||
| .ck-content .image img { | ||||
|   display: block; | ||||
|   margin: 0 auto; | ||||
|   max-width: 100%; | ||||
|   min-width: 100%; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/image.css */ | ||||
| .ck-content .image-inline { | ||||
|   /* | ||||
|    * Normally, the .image-inline would have "display: inline-block" and "img { width: 100% }" (to follow the wrapper while resizing).; | ||||
|    * Unfortunately, together with "srcset", it gets automatically stretched up to the width of the editing root. | ||||
|    * This strange behavior does not happen with inline-flex. | ||||
|    */ | ||||
|   display: inline-flex; | ||||
|   max-width: 100%; | ||||
|   align-items: flex-start; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/image.css */ | ||||
| .ck-content .image-inline picture { | ||||
|   display: flex; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/image.css */ | ||||
| .ck-content .image-inline picture, | ||||
| .ck-content .image-inline img { | ||||
|   flex-grow: 1; | ||||
|   flex-shrink: 1; | ||||
|   max-width: 100%; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-block-align-left, | ||||
| .ck-content .image-style-block-align-right { | ||||
|   max-width: calc(100% - var(--ck-image-style-spacing)); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-align-left, | ||||
| .ck-content .image-style-align-right { | ||||
|   clear: none; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-side { | ||||
|   float: right; | ||||
|   margin-left: var(--ck-image-style-spacing); | ||||
|   max-width: 50%; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-align-left { | ||||
|   float: left; | ||||
|   margin-right: var(--ck-image-style-spacing); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-align-center { | ||||
|   margin-left: auto; | ||||
|   margin-right: auto; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-align-right { | ||||
|   float: right; | ||||
|   margin-left: var(--ck-image-style-spacing); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-block-align-right { | ||||
|   margin-right: 0; | ||||
|   margin-left: auto; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-block-align-left { | ||||
|   margin-left: 0; | ||||
|   margin-right: auto; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content p + .image-style-align-left, | ||||
| .ck-content p + .image-style-align-right, | ||||
| .ck-content p + .image-style-side { | ||||
|   margin-top: 0; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-inline.image-style-align-left, | ||||
| .ck-content .image-inline.image-style-align-right { | ||||
|   margin-top: var(--ck-inline-image-style-spacing); | ||||
|   margin-bottom: var(--ck-inline-image-style-spacing); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-inline.image-style-align-left { | ||||
|   margin-right: var(--ck-inline-image-style-spacing); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-inline.image-style-align-right { | ||||
|   margin-left: var(--ck-inline-image-style-spacing); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imagecaption.css */ | ||||
| .ck-content .image > figcaption { | ||||
|   display: table-caption; | ||||
|   caption-side: bottom; | ||||
|   word-break: break-word; | ||||
|   color: var(--ck-color-image-caption-text); | ||||
|   background-color: var(--ck-color-image-caption-background); | ||||
|   padding: .6em; | ||||
|   font-size: .75em; | ||||
|   outline-offset: -1px; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imageresize.css */ | ||||
| .ck-content .image.image_resized { | ||||
|   max-width: 100%; | ||||
|   display: block; | ||||
|   box-sizing: border-box; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imageresize.css */ | ||||
| .ck-content .image.image_resized img { | ||||
|   width: 100%; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-image/theme/imageresize.css */ | ||||
| .ck-content .image.image_resized > figcaption { | ||||
|   display: block; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-language/theme/language.css */ | ||||
| .ck-content span[lang] { | ||||
|   font-style: italic; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list { | ||||
|   list-style: none; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list li { | ||||
|   margin-bottom: 5px; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list li .todo-list { | ||||
|   margin-top: 5px; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label > input { | ||||
|   -webkit-appearance: none; | ||||
|   display: inline-block; | ||||
|   position: relative; | ||||
|   width: var(--ck-todo-list-checkmark-size); | ||||
|   height: var(--ck-todo-list-checkmark-size); | ||||
|   vertical-align: middle; | ||||
|   border: 0; | ||||
|   left: -25px; | ||||
|   margin-right: -15px; | ||||
|   right: 0; | ||||
|   margin-left: 0; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label > input::before { | ||||
|   display: block; | ||||
|   position: absolute; | ||||
|   box-sizing: border-box; | ||||
|   content: ''; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   border: 1px solid hsl(0, 0%, 20%); | ||||
|   border-radius: 2px; | ||||
|   transition: 250ms ease-in-out box-shadow, 250ms ease-in-out background, 250ms ease-in-out border; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label > input::after { | ||||
|   display: block; | ||||
|   position: absolute; | ||||
|   box-sizing: content-box; | ||||
|   pointer-events: none; | ||||
|   content: ''; | ||||
|   left: calc(var(--ck-todo-list-checkmark-size) / 3); | ||||
|   top: calc(var(--ck-todo-list-checkmark-size) / 5.3); | ||||
|   width: calc(var(--ck-todo-list-checkmark-size) / 5.3); | ||||
|   height: calc(var(--ck-todo-list-checkmark-size) / 2.6); | ||||
|   border-style: solid; | ||||
|   border-color: transparent; | ||||
|   border-width: 0 calc(var(--ck-todo-list-checkmark-size) / 8) calc(var(--ck-todo-list-checkmark-size) / 8) 0; | ||||
|   transform: rotate(45deg); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label > input[checked]::before { | ||||
|   background: hsl(126, 64%, 41%); | ||||
|   border-color: hsl(126, 64%, 41%); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label > input[checked]::after { | ||||
|   border-color: hsl(0, 0%, 100%); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label .todo-list__label__description { | ||||
|   vertical-align: middle; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-media-embed/theme/mediaembed.css */ | ||||
| .ck-content .media { | ||||
|   clear: both; | ||||
|   margin: 0.9em 0; | ||||
|   display: block; | ||||
|   min-width: 15em; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-page-break/theme/pagebreak.css */ | ||||
| .ck-content .page-break { | ||||
|   position: relative; | ||||
|   clear: both; | ||||
|   padding: 5px 0; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-page-break/theme/pagebreak.css */ | ||||
| .ck-content .page-break::after { | ||||
|   content: ''; | ||||
|   position: absolute; | ||||
|   border-bottom: 2px dashed hsl(0, 0%, 77%); | ||||
|   width: 100%; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-page-break/theme/pagebreak.css */ | ||||
| .ck-content .page-break__label { | ||||
|   position: relative; | ||||
|   z-index: 1; | ||||
|   padding: .3em .6em; | ||||
|   display: block; | ||||
|   text-transform: uppercase; | ||||
|   border: 1px solid hsl(0, 0%, 77%); | ||||
|   border-radius: 2px; | ||||
|   font-family: Helvetica, Arial, Tahoma, Verdana, Sans-Serif; | ||||
|   font-size: 0.75em; | ||||
|   font-weight: bold; | ||||
|   color: hsl(0, 0%, 20%); | ||||
|   background: hsl(0, 0%, 100%); | ||||
|   box-shadow: 2px 2px 1px hsla(0, 0%, 0%, 0.15); | ||||
|   -webkit-user-select: none; | ||||
|   -moz-user-select: none; | ||||
|   -ms-user-select: none; | ||||
|   user-select: none; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/tablecaption.css */ | ||||
| .ck-content .table > figcaption { | ||||
|   display: table-caption; | ||||
|   caption-side: top; | ||||
|   word-break: break-word; | ||||
|   text-align: center; | ||||
|   color: var(--ck-color-table-caption-text); | ||||
|   background-color: var(--ck-color-table-caption-background); | ||||
|   padding: .6em; | ||||
|   font-size: .75em; | ||||
|   outline-offset: -1px; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/table.css */ | ||||
| .ck-content .table { | ||||
|   margin: 0.9em auto; | ||||
|   display: table; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/table.css */ | ||||
| .ck-content .table table { | ||||
|   border-collapse: collapse; | ||||
|   border-spacing: 0; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   border: 1px double hsl(0, 0%, 70%); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/table.css */ | ||||
| .ck-content .table table td, | ||||
| .ck-content .table table th { | ||||
|   min-width: 2em; | ||||
|   padding: .4em; | ||||
|   border: 1px solid hsl(0, 0%, 75%); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/table.css */ | ||||
| .ck-content .table table th { | ||||
|   font-weight: bold; | ||||
|   background: hsla(0, 0%, 0%, 5%); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/table.css */ | ||||
| .ck-content[dir="rtl"] .table th { | ||||
|   text-align: right; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/table.css */ | ||||
| .ck-content[dir="ltr"] .table th { | ||||
|   text-align: left; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/tablecolumnresize.css */ | ||||
| .ck-content .table table { | ||||
|   overflow: hidden; | ||||
|   table-layout: fixed; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/tablecolumnresize.css */ | ||||
| .ck-content .table td, | ||||
| .ck-content .table th { | ||||
|   position: relative; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/tablecolumnresize.css */ | ||||
| .ck-content .table .table-column-resizer { | ||||
|   position: absolute; | ||||
|   top: -999999px; | ||||
|   bottom: -999999px; | ||||
|   right: var(--ck-table-column-resizer-position-offset); | ||||
|   width: var(--ck-table-column-resizer-width); | ||||
|   cursor: col-resize; | ||||
|   user-select: none; | ||||
|   z-index: var(--ck-z-default); | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/tablecolumnresize.css */ | ||||
| .ck-content .table[draggable] .table-column-resizer { | ||||
|   display: none; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/tablecolumnresize.css */ | ||||
| .ck-content .table .table-column-resizer:hover, | ||||
| .ck-content .table .table-column-resizer__active { | ||||
|   background-color: var(--ck-color-table-column-resizer-hover); | ||||
|   opacity: 0.25; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/tablecolumnresize.css */ | ||||
| .ck-content[dir=rtl] .table .table-column-resizer { | ||||
|   left: var(--ck-table-column-resizer-position-offset); | ||||
|   right: unset; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-table/theme/tablecolumnresize.css */ | ||||
| .ck-content.ck-read-only .table .table-column-resizer { | ||||
|   display: none; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-code-block/theme/codeblock.css */ | ||||
| .ck-content pre { | ||||
|   padding: 1em; | ||||
|   color: hsl(0, 0%, 20.8%); | ||||
|   background: hsla(0, 0%, 78%, 0.3); | ||||
|   border: 1px solid hsl(0, 0%, 77%); | ||||
|   border-radius: 2px; | ||||
|   text-align: left; | ||||
|   direction: ltr; | ||||
|   tab-size: 4; | ||||
|   white-space: pre-wrap; | ||||
|   font-style: normal; | ||||
|   min-width: 200px; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-code-block/theme/codeblock.css */ | ||||
| .ck-content pre code { | ||||
|   background: unset; | ||||
|   padding: 0; | ||||
|   border-radius: 0; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-horizontal-line/theme/horizontalline.css */ | ||||
| .ck-content hr { | ||||
|   margin: 15px 0; | ||||
|   height: 4px; | ||||
|   background: hsl(0, 0%, 87%); | ||||
|   border: 0; | ||||
| } | ||||
|  | ||||
| /* ckeditor5-mention/theme/mention.css */ | ||||
| .ck-content .mention { | ||||
|   background: var(--ck-color-mention-background); | ||||
|   color: var(--ck-color-mention-text); | ||||
| } | ||||
|  | ||||
| @media print { | ||||
|   /* ckeditor5-page-break/theme/pagebreak.css */ | ||||
|   .ck-content .page-break { | ||||
|     padding: 0; | ||||
|   } | ||||
|   /* ckeditor5-page-break/theme/pagebreak.css */ | ||||
|   .ck-content .page-break::after { | ||||
|     display: none; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										632
									
								
								src/components/common.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,632 @@ | ||||
| @import '~uview-ui/theme.scss'; | ||||
| @import "ckeditor"; | ||||
|  | ||||
| /** | ||||
| 常用内外边距样式 | ||||
|  */ | ||||
| @each $v in (8, 10, 12, 14, 16, 20, 24, 32, 48, 56, 64, 80) { | ||||
|   //gap | ||||
|   .gap-#{$v} { | ||||
|     gap: #{$v}px | ||||
|   } | ||||
|   .font-#{$v} { | ||||
|     font-size: #{$v}px; | ||||
|   } | ||||
|   @each $padMar, $pm in (mar:margin, pad:padding) { | ||||
|     .#{$padMar}-#{$v} { | ||||
|       #{$pm}: #{$v}px | ||||
|     } | ||||
|     //纵向 | ||||
|     .#{$padMar}-v#{$v} { | ||||
|       #{$pm}-top: #{$v}px; | ||||
|       #{$pm}-bottom: #{$v}px; | ||||
|     } | ||||
|     //横向 | ||||
|     .#{$padMar}-h#{$v} { | ||||
|       #{$pm}-left: #{$v}px; | ||||
|       #{$pm}-right: #{$v}px; | ||||
|     } | ||||
|     @each $pos, $p in (l:left, r:right, t:top, b:bottom) { | ||||
|       .#{$padMar}-#{$pos+$v} { | ||||
|         #{$pm}-#{$p}: #{$v}px | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @each $where in (sticky, fixed) { | ||||
|   @each $pos, $p in (l:left, r:right, t:top, b:bottom) { | ||||
|     .#{$where}-#{$pos} { | ||||
|       position: fixed; | ||||
|       #{$p}: 0; | ||||
|       z-index: 202301031019; | ||||
|       width: 100%; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| .bg-fff { | ||||
|   background-color: #fff; | ||||
| } | ||||
|  | ||||
| @font-face { | ||||
|   font-family: 'iconfont'; | ||||
|   /* project id 1862352 */ | ||||
|   src: url('https://at.alicdn.com/t/font_1862352_jpvud12digs.eot'); | ||||
|   src: url('https://at.alicdn.com/t/font_1862352_jpvud12digs.eot?#iefix') format('embedded-opentype'), | ||||
|   url('https://at.alicdn.com/t/font_1862352_jpvud12digs.woff2') format('woff2'), | ||||
|   url('https://at.alicdn.com/t/font_1862352_jpvud12digs.woff') format('woff'), | ||||
|   url('https://at.alicdn.com/t/font_1862352_jpvud12digs.ttf') format('truetype'), | ||||
|   url('https://at.alicdn.com/t/font_1862352_jpvud12digs.svg#iconfont') format('svg'); | ||||
| } | ||||
|  | ||||
| .iconfont { | ||||
|   font-family: "iconfont" !important; | ||||
|   font-size: 32px; | ||||
|   font-style: normal; | ||||
|   -webkit-font-smoothing: antialiased; | ||||
|   -moz-osx-font-smoothing: grayscale; | ||||
| } | ||||
|  | ||||
| page { | ||||
|   width: 100vw; | ||||
|   min-height: 100vh; | ||||
|   overflow-x: hidden; | ||||
|   background-color: #f3f6f9; | ||||
|   overflow-y: auto; | ||||
| } | ||||
|  | ||||
| ::-webkit-scrollbar { | ||||
|   width: 0; | ||||
|   height: 0; | ||||
|   color: transparent; | ||||
| } | ||||
|  | ||||
| .page { | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   background-color: #f3f6f9; | ||||
| } | ||||
|  | ||||
| .text-hover { | ||||
|   background: transparent; | ||||
|   opacity: 0.5; | ||||
| } | ||||
|  | ||||
| .bg-hover { | ||||
|   background: #eee !important; | ||||
| } | ||||
|  | ||||
| .flex { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|  | ||||
|   &.spb { | ||||
|     justify-content: space-between; | ||||
|   } | ||||
|  | ||||
|   &.wrap { | ||||
|     flex-wrap: wrap; | ||||
|   } | ||||
|  | ||||
|   &.column { | ||||
|     flex-direction: column; | ||||
|   } | ||||
|  | ||||
|   &.start { | ||||
|     align-items: flex-start; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .fill { | ||||
|   flex: 1; | ||||
|   min-width: 0; | ||||
|   min-height: 0; | ||||
| } | ||||
|  | ||||
| .flex-align { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
| } | ||||
|  | ||||
| .flex-between { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: space-between; | ||||
| } | ||||
|  | ||||
| .flex1 { | ||||
|   flex: 1; | ||||
| } | ||||
|  | ||||
| .solid { | ||||
|   border-bottom: 2px solid #E8E8E8; | ||||
| } | ||||
|  | ||||
| .flex-row { | ||||
|   display: flex; | ||||
|   flex-direction: row; | ||||
|   align-items: center; | ||||
| } | ||||
|  | ||||
| .flex-column { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
| } | ||||
|  | ||||
| uni-button[disabled] { | ||||
|   background-color: #F7F7F7 !important; | ||||
|   color: #999 !important; | ||||
|   border: 0; | ||||
| } | ||||
|  | ||||
| uni-button:after { | ||||
|   border: none !important; | ||||
| } | ||||
|  | ||||
| .break-word { | ||||
|   word-break: break-all; | ||||
| } | ||||
|  | ||||
| .masking-layer { | ||||
|   position: absolute; | ||||
|   left: 0; | ||||
|   top: 0; | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
|   background-color: rgb(0, 0, 0); | ||||
|   opacity: 0.6; | ||||
| } | ||||
|  | ||||
| /* 入口页列表 */ | ||||
| // .list { | ||||
| //   justify-content: space-between; | ||||
| //   align-items: center; | ||||
| //   height: 112px; | ||||
| //   background-color: #fff; | ||||
| //   padding-left: 32px; | ||||
| //   padding-right: 32px; | ||||
| //   box-sizing: border-box; | ||||
| // } | ||||
|  | ||||
| // .list-cell { | ||||
| //   width: 48px; | ||||
| //   height: 48px; | ||||
| // } | ||||
| .input-placeholder, .textarea-placeholder { | ||||
|   color: #999999; | ||||
|   font-size: 30px; | ||||
| } | ||||
|  | ||||
| .title-sub { | ||||
|   height: 112px; | ||||
|   margin-left: 16px; | ||||
|   width: 654px; | ||||
|   justify-content: space-between; | ||||
|   align-items: center; | ||||
|   background: rgba(255, 255, 255, 1); | ||||
|   font-size: 32px; | ||||
|   color: #333333; | ||||
| } | ||||
|  | ||||
| .more { | ||||
|   width: 32px; | ||||
|   height: 32px; | ||||
| } | ||||
|  | ||||
| .title-line { | ||||
|   border-bottom: 2px solid #DDDDDD; | ||||
| } | ||||
|  | ||||
| .last { | ||||
|   margin-top: 16px; | ||||
| } | ||||
|  | ||||
| .no-content-pds { | ||||
|   margin-top: 360px; | ||||
|   width: 100%; | ||||
|   text-align: center; | ||||
| } | ||||
|  | ||||
| .no-content-pds view { | ||||
|   height: 40px; | ||||
|   font-size: 28px; | ||||
|   line-height: 40px; | ||||
|   font-family: PingFangSC-Regular, PingFangSC; | ||||
| } | ||||
|  | ||||
| .no-content-pds .text { | ||||
|   color: rgba(51, 51, 51, 1); | ||||
| } | ||||
|  | ||||
| .no-content-pds .text-p { | ||||
|   color: rgba(153, 153, 153, 1); | ||||
|   margin-top: 16px; | ||||
| } | ||||
|  | ||||
| /* margin */ | ||||
| .mar-t8 { | ||||
|   margin-top: 16px; | ||||
| } | ||||
|  | ||||
| .mar-b8 { | ||||
|   margin-bottom: 16px; | ||||
| } | ||||
|  | ||||
| .mar-r20 { | ||||
|   margin-right: 40px; | ||||
| } | ||||
|  | ||||
| .mar-l10 { | ||||
|   margin-left: 20px; | ||||
| } | ||||
|  | ||||
| /* color */ | ||||
| .color-333 { | ||||
|   color: #333; | ||||
| } | ||||
|  | ||||
| .color-999 { | ||||
|   color: #999; | ||||
| } | ||||
|  | ||||
| .color-red { | ||||
|   color: #FF4466; | ||||
| } | ||||
|  | ||||
| .color-666 { | ||||
|   color: #666; | ||||
| } | ||||
|  | ||||
| .color-467DFE { | ||||
|   color: #467DFE; | ||||
| } | ||||
|  | ||||
| .color-135AB8 { | ||||
|   color: #197DF0 !important; | ||||
| } | ||||
|  | ||||
| /*  */ | ||||
| .font-12 { | ||||
|   font-size: 24px; | ||||
| } | ||||
|  | ||||
| /*  */ | ||||
| .report { | ||||
|   position: fixed; | ||||
|   bottom: 0; | ||||
|   width: 100%; | ||||
|   height: 112px; | ||||
|   background-color: #197DF0; | ||||
|   color: #fff; | ||||
|   text-align: center; | ||||
|   line-height: 112px; | ||||
|   font-size: 32px; | ||||
| } | ||||
|  | ||||
| .text-right { | ||||
|   text-align: right; | ||||
| } | ||||
|  | ||||
| input::-webkit-input-placeholder { | ||||
|   color: #999; | ||||
| } | ||||
|  | ||||
| .textarea-placeholder { | ||||
|   color: #666; | ||||
|   font-size: 26px; | ||||
| } | ||||
|  | ||||
| /* 多级下拉选择css */ | ||||
| .type-picke-more { | ||||
|   position: fixed; | ||||
|   width: 100%; | ||||
|   height: 330px; | ||||
|   bottom: 0; | ||||
|   left: 0; | ||||
|   background-color: #fff; | ||||
|   z-index: 99; | ||||
| } | ||||
|  | ||||
| .type-picke-more picker-view-column { | ||||
|   text-align: center; | ||||
|   line-height: 110px; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* 固定在顶部 */ | ||||
| .fixed-top { | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   width: 100%; | ||||
| } | ||||
|  | ||||
| /* 固定在底部 */ | ||||
| .fixed-bottom { | ||||
|   position: fixed; | ||||
|   bottom: 0; | ||||
|   left: 0; | ||||
|   width: 100%; | ||||
|   z-index: 99; | ||||
| } | ||||
|  | ||||
| /* 背景颜色为蓝色的按钮 */ | ||||
| .confirm-btn { | ||||
|   background-color: #197DF0; | ||||
|   height: 112px; | ||||
|   line-height: 112px; | ||||
|   color: #fff; | ||||
|   font-size: 32px; | ||||
|   text-align: center; | ||||
| } | ||||
|  | ||||
| /* 顶部搜索栏 */ | ||||
| .header-search { | ||||
|   width: 100%; | ||||
|   height: 112px; | ||||
|   padding: 16px 32px 32px 32px; | ||||
|   box-sizing: border-box; | ||||
|   background: #197DF0; | ||||
| } | ||||
|  | ||||
| .header-search .search-input-content { | ||||
|   width: 686px; | ||||
|   height: 64px; | ||||
|   background: #0D6DDC; | ||||
|   border-radius: 32px; | ||||
|   padding: 14px 24px 0; | ||||
|   box-sizing: border-box; | ||||
|   position: relative; | ||||
| } | ||||
|  | ||||
| .header-search .search-icon { | ||||
|   width: 34px; | ||||
|   height: 34px; | ||||
|   position: absolute; | ||||
|   top: 18px; | ||||
|   left: 24px; | ||||
| } | ||||
|  | ||||
| .header-search .search-input { | ||||
|   display: inline-block; | ||||
|   width: calc(100% - 58px); | ||||
|   height: 36px; | ||||
|   line-height: 36px; | ||||
|   color: #fff; | ||||
|   font-size: 28px; | ||||
|   padding-left: 58px; | ||||
| } | ||||
|  | ||||
| /* 顶部搜索栏 */ | ||||
|  | ||||
| /* 顶部搜索框 (带下拉选择) */ | ||||
| .header-search-select { | ||||
|   width: 100%; | ||||
|   height: 112px; | ||||
|   background: #197DF0; | ||||
|   padding: 24px 32px; | ||||
|   box-sizing: border-box; | ||||
| } | ||||
|  | ||||
| .header-search-select .select-content { | ||||
|   display: inline-block; | ||||
|   width: 206px; | ||||
|   line-height: 64px; | ||||
|   font-weight: 500; | ||||
|   font-size: 28px; | ||||
|   color: #fff; | ||||
|   vertical-align: top; | ||||
| } | ||||
|  | ||||
| .header-search-select .select-content img { | ||||
|   width: 32px; | ||||
|   height: 32px; | ||||
|   vertical-align: middle; | ||||
| } | ||||
|  | ||||
| .header-search-select .input-content { | ||||
|   display: inline-block; | ||||
|   width: calc(100% - 206px); | ||||
|   height: 64px; | ||||
|   background: #0D6DDC; | ||||
|   border-radius: 32px; | ||||
|   padding: 14px 24px 0 58px; | ||||
|   box-sizing: border-box; | ||||
|   position: relative; | ||||
| } | ||||
|  | ||||
| .header-search-select .search-icon { | ||||
|   width: 34px; | ||||
|   height: 34px; | ||||
|   position: absolute; | ||||
|   top: 18px; | ||||
|   left: 24px; | ||||
| } | ||||
|  | ||||
| .header-search-select .search-input { | ||||
|   display: inline-block; | ||||
|   width: calc(100% - 58px); | ||||
|   height: 36px; | ||||
|   line-height: 36px; | ||||
|   color: #fff; | ||||
|   padding-left: 20px; | ||||
|   font-size: 28px; | ||||
| } | ||||
|  | ||||
| /* 顶部搜索框 (带下拉选择) */ | ||||
|  | ||||
| /* 顶部筛选框 */ | ||||
| .header-select { | ||||
|   width: 100%; | ||||
|   height: 96px; | ||||
|   background-color: #fff; | ||||
|   padding: 24px 0; | ||||
|   box-sizing: border-box; | ||||
|   display: flex; | ||||
| } | ||||
|  | ||||
| .header-select .select-item { | ||||
|   flex: 1; | ||||
|   height: 48px; | ||||
|   line-height: 48px; | ||||
|   text-align: center; | ||||
|   color: #666; | ||||
|   font-size: 26px; | ||||
| } | ||||
|  | ||||
| .header-select .down-icon { | ||||
|   width: 32px; | ||||
|   height: 32px; | ||||
|   vertical-align: middle; | ||||
|   margin-left: 8px; | ||||
| } | ||||
|  | ||||
| .header-select .select-item:nth-of-type(2) { | ||||
|   border-left: 2px solid #eee; | ||||
| } | ||||
|  | ||||
| /* 顶部筛选框 */ | ||||
|  | ||||
| /* 顶部tab类型切换栏 */ | ||||
| .header-tab { | ||||
|   height: 96px; | ||||
|   background-color: #4181FF; | ||||
|   padding: 20px 0; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   box-sizing: border-box; | ||||
| } | ||||
|  | ||||
| .header-tab .tab-item { | ||||
|   flex: 1; | ||||
|   text-align: center; | ||||
|   position: relative; | ||||
|   color: #fff; | ||||
|   font-size: 28px; | ||||
| } | ||||
|  | ||||
| .header-tab .tab-active { | ||||
|   font-weight: 500; | ||||
| } | ||||
|  | ||||
| .header-tab .active-line { | ||||
|   position: absolute; | ||||
|   width: 40px; | ||||
|   height: 4px; | ||||
|   background: #FFF; | ||||
|   top: 48px; | ||||
|   left: 50%; | ||||
|   transform: translate(-50%, -50%); | ||||
| } | ||||
|  | ||||
| /* 顶部tab类型切换栏 */ | ||||
|  | ||||
| /* 下划线 */ | ||||
| .underline { | ||||
|   text-decoration: underline; | ||||
| } | ||||
|  | ||||
| /* 字体加粗 500 */ | ||||
| .fw500 { | ||||
|   font-weight: 500; | ||||
| } | ||||
|  | ||||
| /* u-input字体大小重置 */ | ||||
| .fs-32 .u-input__input { | ||||
|   line-height: 42px !important; | ||||
|   font-size: 32px !important; | ||||
|   height: 180px !important; | ||||
|   overflow-y: scroll; | ||||
| } | ||||
|  | ||||
| /* button样式重置 */ | ||||
| button { | ||||
|   margin: 0; | ||||
|   padding: 0; | ||||
|   background-color: #fff; | ||||
|   line-height: inherit; | ||||
|   border-radius: 0; | ||||
|   border: none; | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
| } | ||||
|  | ||||
| button::after { | ||||
|   border: none; | ||||
| } | ||||
|  | ||||
| .button-hover { | ||||
|   background-color: #fff; | ||||
| } | ||||
|  | ||||
| .btn-wrapper { | ||||
|   position: fixed; | ||||
|   left: 50%; | ||||
|   bottom: 0; | ||||
|   z-index: 11; | ||||
|   width: 100%; | ||||
|   padding: 20px 0 20px 0 !important; | ||||
|   transform: translateX(-50%); | ||||
|   background: #f3f6f9; | ||||
| } | ||||
|  | ||||
| .bottomBtn { | ||||
|   color: #fff; | ||||
|   font-size: 34px; | ||||
|   background: #4181FF; | ||||
|   border-radius: 16px; | ||||
|   height: 88px; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
|   margin: 8px 24px; | ||||
| } | ||||
|  | ||||
| .btn-wrapper { | ||||
|   .btn { | ||||
|     width: 686px; | ||||
|     height: 88px; | ||||
|     line-height: 88px; | ||||
|     margin: 0 auto; | ||||
|     padding: 0 !important; | ||||
|     text-align: center; | ||||
|     color: #fff; | ||||
|     font-size: 34px; | ||||
|     background: #4181FF; | ||||
|     border-radius: 16px; | ||||
|   } | ||||
|  | ||||
|   .disabled { | ||||
|     color: #B9E7D0; | ||||
|     background: #50C48A; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .rich-content { | ||||
|   ::v-deep { | ||||
|     p { | ||||
|       margin: 20px 0; | ||||
|       line-height: 1.4; | ||||
|       font-size: 30px; | ||||
|       text-align: justify; | ||||
|       color: #444; | ||||
|     } | ||||
|  | ||||
|     image { | ||||
|       // margin: 20px 0; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| .tabs { | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   z-index: 11; | ||||
|   width: 100%; | ||||
|   padding: 10px 0 10px 16px; | ||||
|   box-sizing: border-box; | ||||
|   background: #4181FF; | ||||
| } | ||||
							
								
								
									
										8
									
								
								src/components/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,8 @@ | ||||
| { | ||||
|   "name": "dvcp-wui", | ||||
|   "description": "小程序UI新库", | ||||
|   "version": "1.0.1", | ||||
|   "dependencies": { | ||||
|     "axios-miniprogram-adapter": "^0.3.2" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								src/components/pages/img/gird--select-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/components/pages/img/right-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 373 B | 
							
								
								
									
										
											BIN
										
									
								
								src/components/pages/img/tx@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/components/pages/img/user-img.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/components/pages/img/xz.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/components/pages/img/xzh.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										337
									
								
								src/components/pages/selectArea.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,337 @@ | ||||
| <template> | ||||
|   <section class="selectArea"> | ||||
|     <div class="areaSelector"> | ||||
|       <div class="fixedTop"> | ||||
|         <em>选择区域</em> | ||||
|         <div class="selectedArea"> | ||||
|           <p v-if="hasSelected" v-text="fullArea.map(e=>e.name).join('')"/> | ||||
|           <p v-else>请选择</p> | ||||
|         </div> | ||||
|         <div/> | ||||
|         <span v-if="urlParams.all" v-text="`省`" @click="selectNode({}, -1)"/> | ||||
|         <span v-for="(area,i) in typeLabels" :key="area.id" | ||||
|               v-text="area.levelLabel" @click="selectNode(area, i)"/> | ||||
|       </div> | ||||
|     </div> | ||||
|     <scroll-view class="fill pendingList" scroll-y> | ||||
|       <div class="pendingItem flexRow" flex v-for="op in pending" :key="op.id" @tap.stop="getChild(op)"> | ||||
|         <div class="fill" :class="{ self: index == op.id }" v-html="op.name"/> | ||||
|         <u-icon v-if="index == op.id" name="checkbox-mark" color="#4181FF"/> | ||||
|       </div> | ||||
|       <AiEmpty v-if="pending.length==0" description="无下级地区数据"/> | ||||
|     </scroll-view> | ||||
|     <div class="bottomBtns"> | ||||
|       <div @click.stop="back">取消</div> | ||||
|       <div class="primary fill" @click.stop="handleSelect">确定</div> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|   name: "selectArea", | ||||
|   appName: "选择地区", | ||||
|   computed: { | ||||
|     dataRange() { | ||||
|       return this.urlParams.all || this.urlParams.disabled ? 0 : this.getAreaType(this.root) | ||||
|     }, | ||||
|     root() { | ||||
|       return this.urlParams.areaId || this.$areaId | ||||
|     }, | ||||
|     pending() { | ||||
|       return this.list?.map(e => ({...e, levelLabel: this.levelLabels[e.type]})) || [] | ||||
|     }, | ||||
|     hasSelected() { | ||||
|       return this.fullArea?.length > 0 | ||||
|     }, | ||||
|     hasLastLevelValue() { | ||||
|       return this.fullArea.some(e => e.type >= this.urlParams.valueLevel) | ||||
|     }, | ||||
|     typeLabels() { | ||||
|       return this.fullArea.filter(e => e.type < this.urlParams.valueLevel) | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       fullArea: [], | ||||
|       index: '', | ||||
|       list: [], | ||||
|       levelLabels: ["省", "市", "县/区", "镇/街道", "村/社区"], | ||||
|       selected: {}, | ||||
|       urlParams: {} | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     root(v) { | ||||
|       v && (this.getFullArea(v)) | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getInfo(areaId) { | ||||
|       return areaId && this.$instance.post('/admin/area/getAllParentAreaId', null, { | ||||
|         withoutToken: true, | ||||
|         params: {areaId}, | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           res.data.forEach((e) => { | ||||
|             e && (e.levelLabel = this.levelLabels[e.type]) | ||||
|           }) | ||||
|           return res.data.reverse() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getFullArea(areaId) { | ||||
|       return this.fullArea?.length > 0 ? Promise.resolve(this.fullArea) : this.getInfo(areaId).then(meta => { | ||||
|         if (meta.length > 1) { | ||||
|           this.fullArea = meta.slice(this.dataRange) | ||||
|         } else { | ||||
|           this.fullArea = meta | ||||
|         } | ||||
|         return this.fullArea | ||||
|       }) | ||||
|     }, | ||||
|     getChildAreas(id) { | ||||
|       id && this.$instance.post('/admin/area/queryAreaByParentId', null, { | ||||
|         withoutToken: true, | ||||
|         params: {id}, | ||||
|       }).then((res) => { | ||||
|         if (res?.data) { | ||||
|           this.list = res.data | ||||
|           if (this.urlParams.selectRoot) { | ||||
|             if (this.hasLastLevelValue) { | ||||
|               let parent = JSON.parse(JSON.stringify(this.fullArea?.slice(-2)?.[0])) | ||||
|               this.list.unshift(parent) | ||||
|             } else { | ||||
|               let parent = JSON.parse(JSON.stringify(this.fullArea?.slice(-1)?.[0])) | ||||
|               this.list.unshift(parent) | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getProvinces() { | ||||
|       this.$instance.post('/admin/area/queryProvinceList', null, {withoutToken: true}).then((res) => { | ||||
|         if (res?.data) { | ||||
|           this.list = res.data | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleSelect() { | ||||
|       let {selected, fullArea} = this | ||||
|       uni.$emit("selectArea", {...selected, fullArea}) | ||||
|       this.back() | ||||
|     }, | ||||
|     getChild(op) { | ||||
|       if (op.id != this.index) { | ||||
|         this.selected = op | ||||
|         this.index = op.id | ||||
|         let {length} = this.fullArea | ||||
|         if (op.type == this.urlParams.valueLevel) { | ||||
|           if (this.hasLastLevelValue) { | ||||
|             this.fullArea.splice(length - 1, 1, op) | ||||
|           } else this.fullArea.push(op) | ||||
|         } else if (op.type < this.urlParams.valueLevel) { | ||||
|           if (this.hasLastLevelValue) { | ||||
|             this.fullArea.splice(length - 1, 1) | ||||
|           } else { | ||||
|             this.fullArea.push(op) | ||||
|             this.getChildAreas(op.id) | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     selectNode(area, i) { | ||||
|       let deleteCount = this.fullArea.length - i | ||||
|       if (deleteCount > 0) { | ||||
|         this.fullArea.splice(i + 1, deleteCount) | ||||
|       } | ||||
|       if (this.urlParams.all && !area.id) { | ||||
|         this.index = '' | ||||
|         this.getProvinces() | ||||
|       } else { | ||||
|         this.index = area.id | ||||
|         this.getChildAreas(area.id) | ||||
|       } | ||||
|     }, | ||||
|     handleInit() { | ||||
|       //初始化 | ||||
|       this.index = this.urlParams.value || this.root | ||||
|       if (!this.urlParams.disabled) { | ||||
|         if (this.urlParams.value) { | ||||
|           this.getFullArea(this.urlParams.value).then(() => { | ||||
|             let area = this.fullArea.find(e => e.id == this.urlParams.value) || {} | ||||
|             //当前选择列表必须是可选范围内的值 | ||||
|             let top = area.type == this.urlParams.valueLevel ? area.parentId : area.id | ||||
|             if (this.getAreaType(top) >= this.dataRange) { | ||||
|               this.getChildAreas(top) | ||||
|             } | ||||
|           }) | ||||
|         } else if (this.urlParams.all) { | ||||
|           this.getProvinces() | ||||
|         } else { | ||||
|           this.getFullArea(this.root).then(() => { | ||||
|             this.getChildAreas(this.root) | ||||
|           }) | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     back() { | ||||
|       uni.navigateBack({}) | ||||
|     }, | ||||
|     getAreaType(area) { | ||||
|       let rules = [10, 8, 6, 3, 0], level = 0 | ||||
|       if (area) { | ||||
|         rules.some((e, i) => { | ||||
|           let reg = new RegExp(`0{${e}}`, 'g') | ||||
|           if (reg.test(area)) { | ||||
|             return (level = i) | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|       return level | ||||
|     } | ||||
|   }, | ||||
|   onLoad(params) { | ||||
|     Object.keys(params).map(k => { | ||||
|       this.$set(this.urlParams, k, | ||||
|           params[k] == "false" ? false : | ||||
|               params[k] == "undefined" ? null : params[k] | ||||
|       ) | ||||
|     }) | ||||
|     this.$nextTick(() => this.handleInit()) | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .selectArea { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   height: 100vh; | ||||
|   background: #fff; | ||||
|  | ||||
|   ::v-deep .areaSelector { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|  | ||||
|     span { | ||||
|       cursor: pointer; | ||||
|       color: #333; | ||||
|       font-weight: bold; | ||||
|       line-height: 112px; | ||||
|       margin-right: 72px; | ||||
|       position: relative; | ||||
|  | ||||
|       &:last-of-type { | ||||
|         margin-right: 0; | ||||
|  | ||||
|         &:after { | ||||
|           content: " "; | ||||
|           display: block; | ||||
|           position: absolute; | ||||
|           bottom: -26px; | ||||
|           left: 50%; | ||||
|           transform: translate(-50%, 100%); | ||||
|           width: 40px; | ||||
|           height: 8px; | ||||
|           background: #4181FF; | ||||
|           border-radius: 4px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     em { | ||||
|       font-style: normal; | ||||
|       font-size: 24px; | ||||
|       font-weight: 400; | ||||
|       color: #999999; | ||||
|       line-height: 34px; | ||||
|     } | ||||
|  | ||||
|     .selectedArea { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       width: fit-content; | ||||
|       max-width: calc(100vw - 128px); | ||||
|       padding: 0 32px; | ||||
|       height: 80px; | ||||
|       background: #ECF2FF; | ||||
|       border-radius: 40px; | ||||
|       font-size: 32px; | ||||
|       font-family: PingFangSC-Medium, PingFang SC; | ||||
|       font-weight: 500; | ||||
|       color: #4181FF !important; | ||||
|       margin: 16px 0 32px; | ||||
|       white-space: nowrap; | ||||
|  | ||||
|       & > p { | ||||
|         overflow: hidden; | ||||
|         text-overflow: ellipsis; | ||||
|         direction: rtl; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .fixedTop { | ||||
|       width: 100vw; | ||||
|       background: #fff; | ||||
|       border-bottom: 4px solid #f5f5f5; | ||||
|       text-align: start; | ||||
|       padding: 32px 32px 0; | ||||
|       box-sizing: border-box; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ::v-deep .pendingList { | ||||
|     padding: 0 32px; | ||||
|     box-sizing: border-box; | ||||
|  | ||||
|     .emptyWrap { | ||||
|       width: 100%; | ||||
|     } | ||||
|  | ||||
|     .pendingItem { | ||||
|       color: #333; | ||||
|       height: 84px; | ||||
|       text-align: start; | ||||
|  | ||||
|       .self { | ||||
|         font-weight: bold; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ::v-deep.bottomBtns { | ||||
|     width: 100vw; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     text-align: center; | ||||
|     height: 120px; | ||||
|     font-size: 34px; | ||||
|     font-family: PingFangSC-Medium, PingFang SC; | ||||
|     font-weight: 500; | ||||
|     color: #3671EE; | ||||
|     background: #fff; | ||||
|     padding: 0 32px; | ||||
|     box-sizing: border-box; | ||||
|  | ||||
|     & > div { | ||||
|       padding: 0 92px; | ||||
|       line-height: 88px; | ||||
|       height: 88px; | ||||
|       border: 1px solid #A0C0FF; | ||||
|       border-radius: 16px; | ||||
|  | ||||
|       &.primary { | ||||
|         color: #fff; | ||||
|         background: #4181FF; | ||||
|         border-color: #4181FF; | ||||
|       } | ||||
|  | ||||
|       & + div { | ||||
|         margin-left: 32px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										182
									
								
								src/components/pages/selectDept.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,182 @@ | ||||
| <template> | ||||
|   <div class="selectDept"> | ||||
|     <AiTopFixed> | ||||
|       <AiTreePath :node="cursor" :paths="depts.map" :prop="{parent:'parentid'}" @click="changeList"/> | ||||
|     </AiTopFixed> | ||||
|     <div class="user-list"> | ||||
|       <template v-if="list.length>0"> | ||||
|         <div class="item" v-for="(item, index) in list" :key="index" flex> | ||||
|           <div class="select-img" @click="checkClick(item)"> | ||||
|             <img :src="item.isCheck ? checkIcon : cirIcon" alt=""> | ||||
|           </div> | ||||
|           <div class="user-info fill" flex @click="getCursor(item)"> | ||||
|             <div class="fill" v-text="item.name"/> | ||||
|             <u-icon v-if="Array.isArray(item.children)" class="mar-r16" name="arrow-right" size="40" color="#999"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </template> | ||||
|       <template v-else> | ||||
|         <AiEmpty/> | ||||
|         <div class="pad-b118"/> | ||||
|       </template> | ||||
|     </div> | ||||
|     <div class="pad-b118"/> | ||||
|     <div class="footer"> | ||||
|       <div class="btn" @click="confirm">确定选择</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: "selectDept", | ||||
|   appName: "选择部门", | ||||
|   data() { | ||||
|     return { | ||||
|       current: 1, | ||||
|       total: 0, | ||||
|       name: '', | ||||
|       list: [], | ||||
|       depts: [], | ||||
|       cirIcon: require('./img/xz.png'), | ||||
|       checkIcon: require('./img/xzh.png'), | ||||
|       selected: [], | ||||
|       cursor: {} | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     isSingle: v => !!v.$route.query.single, | ||||
|     nodeKey: v => v.$route.query.nodeKey || "idNumber", | ||||
|     isRequire: v => v.$route.query.isRequire || 1, | ||||
|     isAuth: v => !!v.$route.query.isAuth, //是否只能选择自己当前部门及以下 | ||||
|   }, | ||||
|   onLoad(query) { | ||||
|     console.log(query) | ||||
|     if (query.selected) { | ||||
|       this.selected = query.selected?.split(",").map(e => Number(e)) || [] | ||||
|     } | ||||
|     this.getList() | ||||
|   }, | ||||
|   methods: { | ||||
|     getList() { | ||||
|       var url = this.isAuth ? `/app/wxcp/wxdepartment/listByUser?name=${this.name}` : `/app/wxcp/wxdepartment/listAll?name=${this.name}` | ||||
|       this.$http.post(url).then(res => { | ||||
|         if (res?.data) { | ||||
|           res.data.forEach(e => e.isCheck = this.selected.includes(e[this.nodeKey])) | ||||
|           this.depts = new this.$tree(res.data, {parent: 'parentid'}) | ||||
|           this.list = this.depts.tree | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     checkClick(item) { | ||||
|       if (this.isSingle && this.isRequire == 1) { | ||||
|         this.depts.every(e => { | ||||
|           e.isCheck = item.id == e.id | ||||
|         }) | ||||
|       } else item.isCheck = !item.isCheck | ||||
|  | ||||
|     }, | ||||
|     confirm() { | ||||
|       let checkList = [] | ||||
|       this.depts.every((item) => { | ||||
|         if (item.isCheck) { | ||||
|           checkList.push(item) | ||||
|         } | ||||
|       }) | ||||
|       if (!checkList.length && this.isRequire == 1) { | ||||
|         return this.$u.toast('请先选择部门') | ||||
|       } else { | ||||
|         uni.navigateBack({ | ||||
|           success: () => { | ||||
|             uni.$emit("pagePicker:dept", checkList) | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|     changeList(item) { | ||||
|       if (item == "all") { | ||||
|         this.cursor = {} | ||||
|         this.list = this.depts.tree | ||||
|       } else { | ||||
|         this.cursor = item | ||||
|         this.list = item.children | ||||
|       } | ||||
|     }, | ||||
|     getCursor(item) { | ||||
|       if (item.children?.length > 0) { | ||||
|         this.cursor = item | ||||
|         this.list = item.children | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .selectDept { | ||||
|   ::v-deep .AiTopFixed .u-search { | ||||
|     margin-bottom: 0 !important; | ||||
|   } | ||||
|  | ||||
|   .pad-b118 { | ||||
|     padding-bottom: 118px; | ||||
|   } | ||||
|  | ||||
|   .user-list { | ||||
|     background-color: #fff; | ||||
|  | ||||
|     .item { | ||||
|       width: 100vw; | ||||
|  | ||||
|       .select-img { | ||||
|         display: inline-block; | ||||
|  | ||||
|         img { | ||||
|           width: 48px; | ||||
|           height: 48px; | ||||
|           margin: 12px 36px 12px 30px; | ||||
|           vertical-align: middle; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .user-info { | ||||
|         padding: 20px 0 20px 0; | ||||
|         height: 100%; | ||||
|         border-bottom: 1px solid #E4E5E6; | ||||
|         font-size: 36px; | ||||
|         font-family: PingFangSC-Medium, PingFang SC; | ||||
|         font-weight: 500; | ||||
|         color: #333; | ||||
|         line-height: 74px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .footer { | ||||
|     width: 100%; | ||||
|     height: 118px; | ||||
|     background: #F4F8FB; | ||||
|     position: fixed; | ||||
|     left: 0; | ||||
|     bottom: 0; | ||||
|     text-align: right; | ||||
|  | ||||
|     .btn { | ||||
|       display: inline-block; | ||||
|       width: 192px; | ||||
|       height: 80px; | ||||
|       line-height: 80px; | ||||
|       background: #1365DD; | ||||
|       border-radius: 4px; | ||||
|       text-align: center; | ||||
|       font-size: 32px; | ||||
|       font-family: PingFangSC-Regular, PingFang SC; | ||||
|       color: #FFF; | ||||
|       margin: 20px 34px 0 0; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										303
									
								
								src/components/pages/selectDeptUser.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,303 @@ | ||||
| <template> | ||||
|   <section class="selectDeptUser"> | ||||
|     <div class="header-middle"> | ||||
|       <div class="hint"> | ||||
|         <span v-for="(item, index) in selectDeptPath" :key="index"> | ||||
|           <span v-if="index>0" class="mar-h4">/</span> | ||||
|           <span class="color-3F8DF5" @click="deptNameClick(item, index)">{{ item.name }}</span> | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="cards" v-for="item in treeList" :key="item.id" @click="itemClick(item)"> | ||||
|         <div class="imges"> | ||||
|           <div class="imgselect" v-if="type == 1" :class="{checked:item.isChecked}" /> | ||||
|           <img src="./img/gird--select-icon.png" alt="" class="avatras"/> | ||||
|         </div> | ||||
|         <div class="rightes"> | ||||
|           <div class="applicationNames">{{ item.name }}</div> | ||||
|           <img src="./img/right-icon.png" alt="" class="imgs"/> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div v-if="type == 0"> | ||||
|         <div class="userCards" v-for="(e, userIndex) in userList" :key="e.id"> | ||||
|           <div class="imges"> | ||||
|             <div class="imgselect" :class="{checked:e.isChecked}" @click.stop="itemCheck(e, 'user', userIndex)"/> | ||||
|             <img src="./img/tx@2x.png" alt="" class="avatras"/> | ||||
|           </div> | ||||
|           <div class="rights fill"> | ||||
|             <div class="applicationNames" v-text="e.name"></div> | ||||
|             <div class="idNumbers">{{ e.phone }}</div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <AiEmpty description="暂无数据" v-if="!hasData"/> | ||||
|     </div> | ||||
|     <div class="subBtn" @click="submit"> | ||||
|       <div>确定选择</div> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapState } from "vuex"; | ||||
| export default { | ||||
|   name: "selectDeptUser", | ||||
|   appName: "选择人员", | ||||
|   data() { | ||||
|     return { | ||||
|       selected: [], | ||||
|       allData: null, | ||||
|       treeList: [], | ||||
|       selectDeptPath: [], | ||||
|       userList: [], | ||||
|       type: 0, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     isSingle: v => !!v.$route.query.single, | ||||
|     nodeKey: v => v.$route.query.nodeKey || "id", | ||||
|     isRequire: v => v.$route.query.isRequire || 1, | ||||
|     hasData() { | ||||
|       return this.treeList?.length > 0 || this.userList?.length > 0 | ||||
|     }, | ||||
|     ...mapState(['user']) | ||||
|   }, | ||||
|   onLoad(query) { | ||||
|     if (query.selected) { | ||||
|       this.selected = query.selected?.split(",") || [] | ||||
|     } | ||||
|     this.getListAll()  | ||||
|   }, | ||||
|   methods: { | ||||
|     isSelected(id) { | ||||
|       return !!this.selected.find(e => e == id) | ||||
|     }, | ||||
|     getListAll() { | ||||
|       this.$instance.post('/app/wxcp/wxdepartment/listAllByCorp').then((res) => { | ||||
|         if (res?.data) { | ||||
|           let parents = res.data.map(e => e.parentid) | ||||
|           this.allData = res.data.map(e => ({...e, hasChildren: parents.includes(e.id), isChecked: this.isSelected(e.id)})) | ||||
|           this.deptInit() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     deptInit() { | ||||
|       this.treeList = this.allData.filter(e => !e.parentid) | ||||
|       this.selectDeptPath = [{name: "可选范围", id: ''}] | ||||
|     }, | ||||
|     itemClick({id, name, corpId}) { | ||||
|       let index = this.selectDeptPath.findIndex(e => e.id == id && e.corpId == corpId) | ||||
|       if (index == -1) { | ||||
|         this.selectDeptPath.push({name, id, corpId}) | ||||
|         this.getDeptsAndUsersByParent(id, corpId) | ||||
|       } | ||||
|     }, | ||||
|     getDeptsAndUsersByParent(departmentId, corpId) { | ||||
|       this.treeList = this.allData.filter(e => e.parentid == departmentId && e.corpId == corpId) | ||||
|       this.userList = [] | ||||
|       this.$instance.post(`/app/wxcp/wxuser/listByDeptId`, null, { | ||||
|         params: {departmentId, status: 1, cid: corpId} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.userList = res.data.map(e => ({...e, isChecked: this.isSelected(e.id, e.corpId)})) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     deptNameClick(row, index) { | ||||
|       this.userList = [] | ||||
|       if (!index) { //第一级别 | ||||
|         this.deptInit() | ||||
|       } else { | ||||
|         let length = this.selectDeptPath.length - index | ||||
|         this.selectDeptPath.splice(index + 1, length) | ||||
|         this.getDeptsAndUsersByParent(row.id, row.corpId) | ||||
|       } | ||||
|     }, | ||||
|     itemCheck(row, kind, index) { | ||||
|       if(this.isSingle) { | ||||
|         this.selected = [] | ||||
|         this.userList.map((item) => { | ||||
|           item.isChecked = false | ||||
|         }) | ||||
|         this.userList[index].isChecked = true | ||||
|         this.selected.push({...row, kind}) | ||||
|       } else { | ||||
|         row.isChecked = !row.isChecked | ||||
|         if (row.isChecked) { | ||||
|           this.selected.push({...row, kind}) | ||||
|         } else { | ||||
|           let index = this.selected.findIndex(e => e.id == row.id) | ||||
|           this.selected.splice(index, 1) | ||||
|         } | ||||
|       } | ||||
|       this.$forceUpdate() | ||||
|     }, | ||||
|     submit() { | ||||
|       if(![this.selected].flat().length) { | ||||
|         return this.$u.toast('请选择人员') | ||||
|       } | ||||
|       uni.navigateBack({ | ||||
|         success: () => { | ||||
|           uni.$emit("pagePicker:deptUser",  this.selected) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .selectDeptUser { | ||||
|   height: 100%; | ||||
|   background: #fff; | ||||
|  | ||||
|   .header-top { | ||||
|     background: #fff; | ||||
|     padding: 20px 32px; | ||||
|   } | ||||
|  | ||||
|   .header-middle { | ||||
|     padding-bottom: 140px; | ||||
|  | ||||
|     .hint { | ||||
|       padding: 28px 20px 28px 32px; | ||||
|       line-height: 56px; | ||||
|       box-shadow: 0 1px 0 0 #e4e5e6; | ||||
|       font-size: 30px; | ||||
|       font-weight: 500; | ||||
|       word-break: break-all; | ||||
|     } | ||||
|  | ||||
|     .empty-div { | ||||
|       height: 16px; | ||||
|       background: #f5f5f5; | ||||
|     } | ||||
|  | ||||
|     .imges { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|  | ||||
|       .imgselect { | ||||
|         width: 48px; | ||||
|         height: 48px; | ||||
|         vertical-align: middle; | ||||
|         background-image: url("./img/xz.png"); | ||||
|         background-position: center; | ||||
|         background-size: 100% 100%; | ||||
|  | ||||
|         &.checked { | ||||
|           background-image: url("./img/xzh.png"); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .avatras { | ||||
|         width: 74px; | ||||
|         height: 74px; | ||||
|         border-radius: 8px; | ||||
|         margin-left: 36px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .cards { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       height: 120px; | ||||
|       line-height: 120px; | ||||
|       padding: 0 0 0 32px; | ||||
|  | ||||
|  | ||||
|       img { | ||||
|         width: 74px; | ||||
|         height: 74px; | ||||
|         border-radius: 8px; | ||||
|       } | ||||
|  | ||||
|       .rightes { | ||||
|         width: calc(100% - 160px); | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         margin-left: 32px; | ||||
|         border-bottom: 1px solid #e4e5e6; | ||||
|  | ||||
|         .applicationNames { | ||||
|           flex: 1; | ||||
|           min-width: 0; | ||||
|           font-size: 36px; | ||||
|           font-weight: 500; | ||||
|           color: #333333; | ||||
|           overflow: hidden; | ||||
|           white-space: nowrap; | ||||
|           text-overflow: ellipsis; | ||||
|         } | ||||
|  | ||||
|         .imgs { | ||||
|           flex-shrink: 0; | ||||
|           width: 40px; | ||||
|           height: 40px; | ||||
|           margin-right: 20px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .userCards { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       height: 120px; | ||||
|       line-height: 120px; | ||||
|       padding: 0 0 0 32px; | ||||
|  | ||||
|       .rights { | ||||
|         display: flex; | ||||
|         justify-content: space-between; | ||||
|         align-items: center; | ||||
|         margin-left: 32px; | ||||
|         border-bottom: 1px solid #e4e5e6; | ||||
|         padding-right: 40px; | ||||
|         height: inherit; | ||||
|  | ||||
|         .applicationNames { | ||||
|           font-size: 36px; | ||||
|           font-weight: 500; | ||||
|           color: #333333; | ||||
|           overflow: hidden; | ||||
|           white-space: nowrap; | ||||
|           text-overflow: ellipsis; | ||||
|         } | ||||
|  | ||||
|         .idNumbers { | ||||
|           color: #666; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .subBtn { | ||||
|     position: fixed; | ||||
|     bottom: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 118px; | ||||
|     background: #f4f8fb; | ||||
|  | ||||
|     div { | ||||
|       width: 192px; | ||||
|       height: 80px; | ||||
|       line-height: 80px; | ||||
|       text-align: center; | ||||
|       background: #1365dd; | ||||
|       border-radius: 4px; | ||||
|       font-size: 32px; | ||||
|       color: #fff; | ||||
|       margin: 20px 34px 0 0; | ||||
|       float: right; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .color-3F8DF5 { | ||||
|     color: #3F8DF5; | ||||
|   } | ||||
|  | ||||
|   .mar-h4 { | ||||
|     margin: 0 4px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										253
									
								
								src/components/pages/selectGird.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,253 @@ | ||||
| <template> | ||||
|   <div class="SelectGird"> | ||||
|     <div class="header-middle"> | ||||
|       <div class="hint"> | ||||
|         <span v-for="(item, index) in selectList" :key="index"> | ||||
|           <span v-if="index" style="margin:0 4px;" v-text="`/`"/> | ||||
|           <span style="color:#3F8DF5" @click="girdNameClick(item, index)" v-text="item.girdName"/> | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="showTypes"> | ||||
|         <div v-if="options.length > 0"> | ||||
|           <div class="cards" v-for="(item, index) in options" :key="index" @click="itemClick(item)"> | ||||
|             <div class="imges"> | ||||
|               <img src="./img/xzh.png" alt="" class="imgselect" v-if="item.isChecked" | ||||
|                    @click.stop="girdClick(item, index)"/> | ||||
|               <img src="./img/xz.png" alt="" class="imgselect" v-else @click.stop="girdClick(item, index)"/> | ||||
|               <img src="./img/gird--select-icon.png" alt="" class="avatras"/> | ||||
|             </div> | ||||
|             <div class="rightes fill"> | ||||
|               <div class="applicationNames fill">{{ item.girdName }}</div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|         <AiEmpty :description="`暂无数据`" class="emptyWrap" v-else/> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="subBtn flex"> | ||||
|       <div v-if="clearable" class="cancel" @click="cancel">清空</div> | ||||
|       <div @click="submit">确定选择</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
|  | ||||
| export default { | ||||
|   name: 'selectGird', | ||||
|   appName: "网格选择", | ||||
|   data() { | ||||
|     return { | ||||
|       SelectGird: {}, | ||||
|       allData: null, | ||||
|       options: [], | ||||
|       selectList: [], | ||||
|       parentGirdId: '', | ||||
|       query: {} | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     //是否展示所有网格(随手拍) | ||||
|     isApply: v => v.query?.formType == 2, | ||||
|     clearable: v => v.query?.clearable, | ||||
|     selected: v => [v.query?.selected].flat(), | ||||
|   }, | ||||
|   onLoad(query) { | ||||
|     this.query = query | ||||
|     this.getAllGrids() | ||||
|   }, | ||||
|   methods: { | ||||
|     getAllGrids() { | ||||
|       this.selectList = [] | ||||
|       let url = this.query.axiosUrl ? this.query.axiosUrl : `/app/appgirdinfo/listByInfo` | ||||
|       this.$instance.post(url).then(res => { | ||||
|         if (res?.data) { | ||||
|           let parents = res.data?.map(e => e.parentGirdId) | ||||
|           this.allData = res.data?.map(e => ({...e, hasChildren: parents.includes(e.id)})) | ||||
|           this.treeInit() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     treeInit(isClick) { | ||||
|       let last = uni.getStorageSync("lastSelectedGrid") | ||||
|       if (!isClick && last && !this.isApply) { | ||||
|         this.$instance.post("/app/appgirdinfo/listFatherGirdInfo", null, { | ||||
|           params: {girdId: last} | ||||
|         }).then(res => { | ||||
|           if (res?.data) { | ||||
|             this.selectList = [{girdName: '可选范围', id: ''}, res.data.filter(e => !!this.allData.find(a => a.id == e.id))].flat() | ||||
|             this.getGridsByGridMemberAndParent({id: last}) | ||||
|           } | ||||
|         }) | ||||
|       } else { | ||||
|         this.options = this.allData.filter((e, i, arr) => !arr?.map(e => e.id).includes(e.parentGirdId)) | ||||
|         this.options?.map((item) => item.isChecked = this.selected.includes(item.id)) | ||||
|         let obj = {girdName: '可选范围', id: ''} | ||||
|         this.selectList.push(obj) | ||||
|       } | ||||
|     }, | ||||
|     itemClick(row) { | ||||
|       if (row.hasChildren) { | ||||
|         let obj = { | ||||
|           girdName: row.girdName, | ||||
|           id: row.id, | ||||
|         } | ||||
|         this.selectList.push(obj) | ||||
|         this.getGridsByGridMemberAndParent(row) | ||||
|       } | ||||
|     }, | ||||
|     getGridsByGridMemberAndParent(row) { | ||||
|       let {id: parentGirdId} = row | ||||
|       this.options = this.allData.filter(e => e.parentGirdId == parentGirdId) | ||||
|       this.options?.map((item) => item.isChecked = this.selected.includes(item.id)) | ||||
|     }, | ||||
|     girdNameClick(row, index) { | ||||
|       if (!index) { //第一级别 | ||||
|         this.selectList = [] | ||||
|         this.treeInit(true) | ||||
|       } else { | ||||
|         this.selectList.splice(index, 8) | ||||
|         this.getGridsByGridMemberAndParent(row) | ||||
|       } | ||||
|     }, | ||||
|     girdClick(row, index) { | ||||
|       if (this.options[index].isChecked) {//取消 | ||||
|         this.options[index].isChecked = false | ||||
|         this.SelectGird = {} | ||||
|       } else { | ||||
|         this.options?.map((item) => { | ||||
|           item.isChecked = false | ||||
|         }) | ||||
|         this.options[index].isChecked = true | ||||
|         this.SelectGird = row | ||||
|       } | ||||
|       this.$forceUpdate() | ||||
|     }, | ||||
|     submit() { | ||||
|       if (this.SelectGird.id != null) { | ||||
|         if (!this.isApply) { | ||||
|           uni.setStorageSync("lastSelectedGrid", this.SelectGird.parentGirdId) | ||||
|         } | ||||
|         uni.navigateBack({ | ||||
|           success: () => { | ||||
|             uni.$emit("pagePicker:gird", this.SelectGird) | ||||
|           } | ||||
|         }) | ||||
|       } else { | ||||
|         return this.$u.toast('请选择网格') | ||||
|       } | ||||
|     }, | ||||
|     cancel() { | ||||
|       this.SelectGird = {} | ||||
|       uni.navigateBack({ | ||||
|         success: () => { | ||||
|           uni.$emit("pagePicker:gird", this.SelectGird) | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .SelectGird { | ||||
|   min-height: 100vh; | ||||
|   background: #fff; | ||||
|   padding-bottom: 140px; | ||||
|   box-sizing: border-box; | ||||
|  | ||||
|   .header-middle { | ||||
|     .hint { | ||||
|       padding: 28px 20px 28px 32px; | ||||
|       line-height: 56px; | ||||
|       box-shadow: 0px 1px 0px 0px #e4e5e6; | ||||
|       font-size: 30px; | ||||
|       font-weight: 500; | ||||
|       word-break: break-all; | ||||
|     } | ||||
|  | ||||
|     .showTypes { | ||||
|       .cards { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         height: 120px; | ||||
|         line-height: 120px; | ||||
|         // background: pink; | ||||
|         padding: 0 0 0 32px; | ||||
|  | ||||
|         .imges { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           // width: 200px; | ||||
|           .imgselect { | ||||
|             width: 48px; | ||||
|             height: 48px; | ||||
|             vertical-align: middle; | ||||
|           } | ||||
|  | ||||
|           .avatras { | ||||
|             width: 74px; | ||||
|             height: 74px; | ||||
|             border-radius: 8px; | ||||
|             margin-left: 36px; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         img { | ||||
|           width: 74px; | ||||
|           height: 74px; | ||||
|           border-radius: 8px; | ||||
|         } | ||||
|  | ||||
|         .rightes { | ||||
|           display: flex; | ||||
|           border-bottom: 1px solid #e4e5e6; | ||||
|           padding: 0 16px; | ||||
|  | ||||
|           .applicationNames { | ||||
|             display: inline-block; | ||||
|             font-size: 36px; | ||||
|             font-weight: 500; | ||||
|             color: #333333; | ||||
|             overflow: hidden; | ||||
|             text-overflow: ellipsis; | ||||
|             white-space: nowrap; | ||||
|             vertical-align: bottom; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .subBtn { | ||||
|     position: fixed; | ||||
|     bottom: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 118px; | ||||
|     background: #f4f8fb; | ||||
|     justify-content: flex-end; | ||||
|  | ||||
|     div { | ||||
|       width: 192px; | ||||
|       height: 80px; | ||||
|       line-height: 80px; | ||||
|       text-align: center; | ||||
|       border: 2px solid #1365dd; | ||||
|       background: #1365dd; | ||||
|       border-radius: 4px; | ||||
|       font-size: 32px; | ||||
|       color: #fff; | ||||
|       margin-right: 32px; | ||||
|  | ||||
|       &.cancel { | ||||
|         color: #333; | ||||
|         background: #fff; | ||||
|         border-color: #ddd; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										202
									
								
								src/components/pages/selectResident.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,202 @@ | ||||
| <template> | ||||
|   <div class="selectResident"> | ||||
|     <!-- <AiTopFixed> --> | ||||
|     <div class="search-top"> | ||||
|       <u-search placeholder="搜索" v-model="name" :show-action="false" bg-color="#fff" search-icon-color="#E2E8F1"  | ||||
|         color="#666" height="72" @search="getSearchList" @clear="handerClear" @change="getList"></u-search> | ||||
|     </div> | ||||
|     <!-- </AiTopFixed> --> | ||||
|     <div class="user-list"> | ||||
|       <template v-if="list.length>0"> | ||||
|         <div class="item" v-for="(item, index) in list" :key="index"> | ||||
|           <div class="select-img" @click="checkClick(index)"> | ||||
|             <img :src="item.isCheck ? checkIcon : cirIcon" alt=""> | ||||
|           </div> | ||||
|           <div class="user-info"> | ||||
|             <img :src="item.photo" alt="" v-if="item.photo"> | ||||
|             <img src="./img/user-img.png" alt="" v-else>{{ item.name }} | ||||
|           </div> | ||||
|         </div> | ||||
|       </template> | ||||
|       <AiEmpty v-else/> | ||||
|     </div> | ||||
|     <div class="pad-b118"></div> | ||||
|     <div class="footer"> | ||||
|       <div class="btn" @click="confirm">确定选择</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: "selectResident", | ||||
|   appName: "人员选择器(居民档案)", | ||||
|   data() { | ||||
|     return { | ||||
|       current: 1, | ||||
|       name: '', | ||||
|       list: [], | ||||
|       cirIcon: require('./img/xz.png'), | ||||
|       checkIcon: require('./img/xzh.png'), | ||||
|       selected: [], | ||||
|       isSingle:  false, //是否单选 | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|   }, | ||||
|   onLoad(query) { | ||||
|     if (query.selected) { | ||||
|       this.selected = query.selected?.split(",") || [] | ||||
|     } | ||||
|     this.isSingle = query.single || false | ||||
|     this.getList() | ||||
|   }, | ||||
|   methods: { | ||||
|     getList() { | ||||
|       this.$instance.post(`/app/appresident/list`, null, { | ||||
|         params: { | ||||
|           current: this.current, | ||||
|           size: 20, | ||||
|           areaId: this.user.areaId, | ||||
|           con: this.name | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           res.data.records.forEach(e => { | ||||
|             e.isCheck = this.selected.includes(e.idNumber) | ||||
|           }) | ||||
|           if (this.current > 1 && this.current > res.data.pages) { | ||||
|             return | ||||
|           } | ||||
|           this.list = this.current > 1 ? [...this.list, ...res.data.records] : res.data.records | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     checkClick(index) { | ||||
|       if(this.isSingle) { | ||||
|         this.list.map((item) => { | ||||
|           item.isCheck = false | ||||
|         }) | ||||
|         this.list[index].isCheck = true | ||||
|       }else { | ||||
|         this.list[index].isCheck = !this.list[index].isCheck | ||||
|       } | ||||
|        | ||||
|     }, | ||||
|     confirm() { | ||||
|       let checkList = [] | ||||
|       this.list.map((item) => { | ||||
|         if (item.isCheck) { | ||||
|           checkList.push(item) | ||||
|         } | ||||
|       }) | ||||
|       if (!checkList.length) { | ||||
|         return this.$u.toast('请先选择人员') | ||||
|       } else { | ||||
|         uni.navigateBack({ | ||||
|           success: () => { | ||||
|             uni.$emit("pagePicker:resident", checkList) | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|     handerClear() { | ||||
|       this.current = 1 | ||||
|       this.name = '' | ||||
|       this.getList() | ||||
|     } | ||||
|   }, | ||||
|   onReachBottom() { | ||||
|     this.current++ | ||||
|     this.getList() | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .selectResident { | ||||
|   ::v-deep .AiTopFixed .u-search { | ||||
|     margin-bottom: 0 !important; | ||||
|   } | ||||
|  | ||||
|   .pad-b118 { | ||||
|     padding-bottom: 118px; | ||||
|   } | ||||
|  | ||||
|   .search-top { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     padding: 16px; | ||||
|     width: 100%; | ||||
|     box-sizing: border-box; | ||||
|     background-color: #E4E5E6; | ||||
|     z-index: 99; | ||||
|   } | ||||
|  | ||||
|   .user-list { | ||||
|     background-color: #fff; | ||||
|     padding-top: 100px; | ||||
|     .item { | ||||
|       .select-img { | ||||
|         display: inline-block; | ||||
|  | ||||
|         img { | ||||
|           width: 48px; | ||||
|           height: 48px; | ||||
|           margin: 12px 36px 12px 30px; | ||||
|           vertical-align: middle; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .user-info { | ||||
|         display: inline-block; | ||||
|         padding: 20px 0 20px 0; | ||||
|         width: calc(100% - 114px); | ||||
|         height: 100%; | ||||
|         border-bottom: 1px solid #E4E5E6; | ||||
|         font-size: 36px; | ||||
|         font-family: PingFangSC-Medium, PingFang SC; | ||||
|         font-weight: 500; | ||||
|         color: #333; | ||||
|         line-height: 74px; | ||||
|  | ||||
|         img { | ||||
|           width: 74px; | ||||
|           height: 74px; | ||||
|           border-radius: 8px; | ||||
|           margin-right: 34px; | ||||
|           vertical-align: bottom; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .footer { | ||||
|     width: 100%; | ||||
|     height: 118px; | ||||
|     background: #F4F8FB; | ||||
|     position: fixed; | ||||
|     left: 0; | ||||
|     bottom: 0; | ||||
|     text-align: right; | ||||
|  | ||||
|     .btn { | ||||
|       display: inline-block; | ||||
|       width: 192px; | ||||
|       height: 80px; | ||||
|       line-height: 80px; | ||||
|       background: #1365DD; | ||||
|       border-radius: 4px; | ||||
|       text-align: center; | ||||
|       font-size: 32px; | ||||
|       font-family: PingFangSC-Regular, PingFang SC; | ||||
|       color: #FFF; | ||||
|       margin: 20px 34px 0 0; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										194
									
								
								src/components/pages/selectResidentMultiple.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,194 @@ | ||||
| <template> | ||||
|   <div class="selectResident"> | ||||
|     <!-- <AiTopFixed> --> | ||||
|     <div class="search-top"> | ||||
|       <u-search placeholder="搜索" v-model="name" :show-action="false" bg-color="#fff" search-icon-color="#E2E8F1"  | ||||
|         color="#666" height="72" @search="getSearchList" @clear="handerClear" @change="getList"></u-search> | ||||
|     </div> | ||||
|     <!-- </AiTopFixed> --> | ||||
|     <div class="user-list"> | ||||
|       <template v-if="list.length>0"> | ||||
|         <div class="item" v-for="(item, index) in list" :key="index"> | ||||
|           <div class="select-img" @click="checkClick(index)"> | ||||
|             <img :src="item.isCheck ? checkIcon : cirIcon" alt=""> | ||||
|           </div> | ||||
|           <div class="user-info"> | ||||
|             <img :src="item.photo" alt="" v-if="item.photo"> | ||||
|             <img src="./img/user-img.png" alt="" v-else>{{ item.name }} | ||||
|           </div> | ||||
|         </div> | ||||
|       </template> | ||||
|       <AiEmpty v-else/> | ||||
|     </div> | ||||
|     <div class="pad-b118"></div> | ||||
|     <div class="footer"> | ||||
|       <div class="btn" @click="confirm">确定选择</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: "selectResident", | ||||
|   appName: "人员选择器(居民档案)", | ||||
|   data() { | ||||
|     return { | ||||
|       current: 1, | ||||
|       name: '', | ||||
|       list: [], | ||||
|       cirIcon: require('./img/xz.png'), | ||||
|       checkIcon: require('./img/xzh.png'), | ||||
|       selected: [], | ||||
|       isSingle:  false, //是否单选 | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|   }, | ||||
|   onLoad(query) { | ||||
|     if (query.selected) { | ||||
|       this.selected = query.selected?.split(",") || [] | ||||
|     } | ||||
|     this.isSingle = query.single || false | ||||
|     this.getList() | ||||
|   }, | ||||
|   methods: { | ||||
|     getList() { | ||||
|       this.$instance.post(`/app/appresident/list`, null, { | ||||
|         params: { | ||||
|           current: this.current, | ||||
|           size: 20, | ||||
|           areaId: this.user.areaId, | ||||
|           con: this.name | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           res.data.records.forEach(e => { | ||||
|             e.isCheck = this.selected.includes(e.idNumber) | ||||
|           }) | ||||
|           if (this.current > 1 && this.current > res.data.pages) { | ||||
|             return | ||||
|           } | ||||
|           this.list = this.current > 1 ? [...this.list, ...res.data.records] : res.data.records | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     checkClick(index) { | ||||
|       this.list[index].isCheck = !this.list[index].isCheck    | ||||
|     }, | ||||
|     confirm() { | ||||
|       let checkList = [] | ||||
|       this.list.map((item) => { | ||||
|         if (item.isCheck) { | ||||
|           checkList.push(item) | ||||
|         } | ||||
|       }) | ||||
|       if (!checkList.length) { | ||||
|         return this.$u.toast('请先选择人员') | ||||
|       } else { | ||||
|         uni.navigateBack({ | ||||
|           success: () => { | ||||
|             uni.$emit("pagePicker:residentMultiple", checkList) | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|     handerClear() { | ||||
|       this.current = 1 | ||||
|       this.name = '' | ||||
|       this.getList() | ||||
|     } | ||||
|   }, | ||||
|   onReachBottom() { | ||||
|     this.current++ | ||||
|     this.getList() | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .selectResident { | ||||
|   ::v-deep .AiTopFixed .u-search { | ||||
|     margin-bottom: 0 !important; | ||||
|   } | ||||
|  | ||||
|   .pad-b118 { | ||||
|     padding-bottom: 118px; | ||||
|   } | ||||
|  | ||||
|   .search-top { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     padding: 16px; | ||||
|     width: 100%; | ||||
|     box-sizing: border-box; | ||||
|     background-color: #E4E5E6; | ||||
|     z-index: 99; | ||||
|   } | ||||
|  | ||||
|   .user-list { | ||||
|     background-color: #fff; | ||||
|     padding-top: 100px; | ||||
|     .item { | ||||
|       .select-img { | ||||
|         display: inline-block; | ||||
|  | ||||
|         img { | ||||
|           width: 48px; | ||||
|           height: 48px; | ||||
|           margin: 12px 36px 12px 30px; | ||||
|           vertical-align: middle; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .user-info { | ||||
|         display: inline-block; | ||||
|         padding: 20px 0 20px 0; | ||||
|         width: calc(100% - 114px); | ||||
|         height: 100%; | ||||
|         border-bottom: 1px solid #E4E5E6; | ||||
|         font-size: 36px; | ||||
|         font-family: PingFangSC-Medium, PingFang SC; | ||||
|         font-weight: 500; | ||||
|         color: #333; | ||||
|         line-height: 74px; | ||||
|  | ||||
|         img { | ||||
|           width: 74px; | ||||
|           height: 74px; | ||||
|           border-radius: 8px; | ||||
|           margin-right: 34px; | ||||
|           vertical-align: bottom; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .footer { | ||||
|     width: 100%; | ||||
|     height: 118px; | ||||
|     background: #F4F8FB; | ||||
|     position: fixed; | ||||
|     left: 0; | ||||
|     bottom: 0; | ||||
|     text-align: right; | ||||
|  | ||||
|     .btn { | ||||
|       display: inline-block; | ||||
|       width: 192px; | ||||
|       height: 80px; | ||||
|       line-height: 80px; | ||||
|       background: #1365DD; | ||||
|       border-radius: 4px; | ||||
|       text-align: center; | ||||
|       font-size: 32px; | ||||
|       font-family: PingFangSC-Regular, PingFang SC; | ||||
|       color: #FFF; | ||||
|       margin: 20px 34px 0 0; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										208
									
								
								src/components/pages/selectSysUser.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,208 @@ | ||||
| <template> | ||||
|   <div class="selectResident"> | ||||
|     <div class="search-top"> | ||||
|       <u-search placeholder="搜索" v-model="name" :show-action="false" bg-color="#fff" search-icon-color="#E2E8F1"  | ||||
|         color="#666" height="72" @search="current=1,getList()" @clear="handerClear" @change="current=1,getList()"></u-search> | ||||
|     </div> | ||||
|     <div class="user-list"> | ||||
|       <template v-if="list.length>0"> | ||||
|         <div class="item" v-for="(item, index) in list" :key="index"> | ||||
|           <div class="select-img" @click="checkClick(index)"> | ||||
|             <img :src="item.isCheck ? checkIcon : cirIcon" alt=""> | ||||
|           </div> | ||||
|           <div class="user-info"> | ||||
|             <img :src="item.photo" alt="" v-if="item.photo"> | ||||
|             <img src="./img/user-img.png" alt="" v-else> | ||||
|             {{ item.name }}  | ||||
|             <span v-if="isShowPhone && item.mobile">({{item.mobile}})</span> | ||||
|             <span v-if="isShowPhone && item.phone && !item.mobile">({{item.phone}})</span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </template> | ||||
|       <template v-else> | ||||
|         <AiEmpty/> | ||||
|         <div class="pad-b118"/> | ||||
|       </template> | ||||
|     </div> | ||||
|     <div class="pad-b118"/> | ||||
|     <div class="footer"> | ||||
|       <div class="btn" @click="confirm">确定选择</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: "selectResident", | ||||
|   appName: "选择人员", | ||||
|   data() { | ||||
|     return { | ||||
|       current: 1, | ||||
|       total: 0, | ||||
|       name: '', | ||||
|       list: [], | ||||
|       cirIcon: require('./img/xz.png'), | ||||
|       checkIcon: require('./img/xzh.png'), | ||||
|       selected: [], | ||||
|       query: null, | ||||
|       isSingle: false, | ||||
|       nodeKey: 'idNumber', | ||||
|       isRequire: 1, | ||||
|       isShowPhone: false | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|   }, | ||||
|   onLoad(query) { | ||||
|     this.query = query | ||||
|     if (query.selected) { | ||||
|       this.selected = query.selected?.split(",") || [] | ||||
|     } | ||||
|     this.isSingle = query.single == 'false' ? false : true | ||||
|     this.nodeKey = query.nodeKey || "idNumber" | ||||
|     this.isRequire = query.isRequire || 1 | ||||
|     this.isShowPhone = query.isShowPhone || false | ||||
|     this.getList() | ||||
|   }, | ||||
|   onShow() { | ||||
|     // document.title = this.nodeKey == 'openId' ? '选择居民' : '选择员工' | ||||
|   }, | ||||
|   methods: { | ||||
|     getList() { | ||||
|       let {current, total, name: con} = this | ||||
|       let url = this.query.axiosUrl ? this.query.axiosUrl : `/admin/user/userIntegralList` | ||||
|       if ((!total && current == 1) || current <= total) { | ||||
|         url = decodeURIComponent(url) | ||||
|         this.$instance.post(url, null, { | ||||
|           params: {current, size: 20, con} | ||||
|         }).then(res => { | ||||
|           if (res?.data) { | ||||
|             this.total = res.data.pages || 0 | ||||
|             res.data.records.forEach(e => { | ||||
|               e.isCheck = this.selected.includes(e[this.nodeKey]) | ||||
|             }) | ||||
|             this.list = [current == 1 ? [] : this.list, res.data.records || []].flat() | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|     checkClick(index) { | ||||
|       if (this.isSingle) { | ||||
|         this.list.map((e, i) => { | ||||
|           e.isCheck = i == index; | ||||
|         }) | ||||
|       } else this.list[index].isCheck = !this.list[index].isCheck | ||||
|  | ||||
|     }, | ||||
|     confirm() { | ||||
|       let checkList = [] | ||||
|       this.list.map((item) => { | ||||
|         if (item.isCheck) { | ||||
|           checkList.push(item) | ||||
|         } | ||||
|       }) | ||||
|       if (!checkList.length && this.isRequire == 1) { | ||||
|         return this.$u.toast('请先选择人员') | ||||
|       } else { | ||||
|         uni.navigateBack({ | ||||
|           success: () => { | ||||
|             uni.$emit("pagePicker:sysUser", checkList) | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   onReachBottom() { | ||||
|     this.current++ | ||||
|     this.getList() | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .selectResident { | ||||
|   ::v-deep .AiTopFixed .u-search { | ||||
|     margin-bottom: 0 !important; | ||||
|   } | ||||
|  | ||||
|   .pad-b118 { | ||||
|     padding-bottom: 118px; | ||||
|   } | ||||
|  | ||||
|   .search-top { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     padding: 16px; | ||||
|     width: 100%; | ||||
|     box-sizing: border-box; | ||||
|     background-color: #E4E5E6; | ||||
|     z-index: 99; | ||||
|   } | ||||
|   .user-list { | ||||
|     padding-top: 100px; | ||||
|     background-color: #fff; | ||||
|  | ||||
|     .item { | ||||
|       .select-img { | ||||
|         display: inline-block; | ||||
|  | ||||
|         img { | ||||
|           width: 48px; | ||||
|           height: 48px; | ||||
|           margin: 12px 36px 12px 30px; | ||||
|           vertical-align: middle; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .user-info { | ||||
|         display: inline-block; | ||||
|         padding: 20px 0 20px 0; | ||||
|         width: calc(100% - 114px); | ||||
|         height: 100%; | ||||
|         border-bottom: 1px solid #E4E5E6; | ||||
|         font-size: 36px; | ||||
|         font-family: PingFangSC-Medium, PingFang SC; | ||||
|         font-weight: 500; | ||||
|         color: #333; | ||||
|         line-height: 74px; | ||||
|  | ||||
|         img { | ||||
|           width: 74px; | ||||
|           height: 74px; | ||||
|           border-radius: 8px; | ||||
|           margin-right: 34px; | ||||
|           vertical-align: bottom; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .footer { | ||||
|     width: 100%; | ||||
|     height: 118px; | ||||
|     background: #F4F8FB; | ||||
|     position: fixed; | ||||
|     left: 0; | ||||
|     bottom: 0; | ||||
|     text-align: right; | ||||
|  | ||||
|     .btn { | ||||
|       display: inline-block; | ||||
|       width: 192px; | ||||
|       height: 80px; | ||||
|       line-height: 80px; | ||||
|       background: #1365DD; | ||||
|       border-radius: 4px; | ||||
|       text-align: center; | ||||
|       font-size: 32px; | ||||
|       font-family: PingFangSC-Regular, PingFang SC; | ||||
|       color: #FFF; | ||||
|       margin: 20px 34px 0 0; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										62
									
								
								src/components/pages/submitEvaluation.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,62 @@ | ||||
| <template> | ||||
|   <section class="submitEvaluation"> | ||||
|     <AiGroup> | ||||
|       <AiItem label="评价分数" top-label required> | ||||
|         <u-rate v-model="form.score" :size="64" active-color="#F8B425" :min-count="1" inactive-icon="star-fill"/> | ||||
|       </AiItem> | ||||
|     </AiGroup> | ||||
|     <u-gap height="24"/> | ||||
|     <AiGroup> | ||||
|       <AiItem label="评价详情" top-label required> | ||||
|         <u-input type="textarea" v-model="form.content" placeholder="请简要描述..."/> | ||||
|       </AiItem> | ||||
|     </AiGroup> | ||||
|     <u-gap height="24"/> | ||||
|     <AiGroup> | ||||
|       <AiItem label="附件" top-label> | ||||
|         <AiUploader v-model="form.files" :limit="9" multiple/> | ||||
|       </AiItem> | ||||
|     </AiGroup> | ||||
|     <div class="fixed-bottom"> | ||||
|       <div class="bottomBtn" @click="submit">提交</div> | ||||
|     </div> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "submitEvaluation", | ||||
|   appName: "提交评价", | ||||
|   data() { | ||||
|     return { | ||||
|       form: { | ||||
|         files: [] | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     submit() { | ||||
|       if (!this.form.score) { | ||||
|         return this.$u.toast("请选择评价分数!") | ||||
|       } | ||||
|       if (!this.form.content) { | ||||
|         return this.$u.toast("请填写评价详情!") | ||||
|       } | ||||
|       this.$instance.post("/app/appbusinesscompletionevaluation/addOrUpdate", this.form).then(res => { | ||||
|         if (res?.code == 0) { | ||||
|           this.$u.toast("提交成功!") | ||||
|           setTimeout(() => uni.navigateBack({}), 1500) | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   onLoad(params) { | ||||
|     this.form.bizId = params.bid | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .submitEvaluation { | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										53
									
								
								src/components/utils/PageBase.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,53 @@ | ||||
| class PageBase { | ||||
|   constructor(path, vue) { | ||||
|     this.path = path | ||||
|     this.name = path.replace(/.*[\\\/]([^\\\/]+)$/g, '$1') | ||||
|     this.init(vue) | ||||
|   } | ||||
|  | ||||
|   init(vue) { | ||||
|     if (/appName/.test(vue)) { | ||||
|       let appName = vue.replace(/[\s\S]*(appName:.+),[\s\S]*/gm, '$1') | ||||
|       this.label = appName.replace(/(appName:|["'])/g, '')?.trim() | ||||
|     } | ||||
|     if (/customNavigation/.test(vue)) { | ||||
|       this.style = { | ||||
|         navigationStyle: "custom", | ||||
|       } | ||||
|       if (/navigationBarTextStyle/.test(vue)) { | ||||
|         this.style.navigationBarTextStyle = vue.replace(/[\s\S]*navigationBarTextStyle:([^,]+),[\s\S]*/gm, '$1').replace(/["']/g, '')?.trim() | ||||
|       } | ||||
|       //导航栏背景颜色(同状态栏背景色) | ||||
|       if (/navigationBarBackgroundColor/.test(vue)) { | ||||
|         this.style.navigationBarBackgroundColor = vue.replace(/[\s\S]*navigationBarBackgroundColor:([^,]+),[\s\S]*/gm, '$1').replace(/["']/g, '')?.trim() | ||||
|       } | ||||
|       if (/enablePullDownRefresh/.test(vue)) { | ||||
|         this.style.enablePullDownRefresh = true | ||||
|       } | ||||
|     } else { | ||||
|       this.style = {navigationBarTitleText: this.label} | ||||
|       //是否开启下拉刷新 | ||||
|       if (/enablePullDownRefresh/.test(vue)) { | ||||
|         this.style.enablePullDownRefresh = true | ||||
|       } | ||||
|       //导航栏标题颜色及状态栏前景颜色,仅支持 black/white | ||||
|       if (/navigationBarTextStyle/.test(vue)) { | ||||
|         this.style.navigationBarTextStyle = vue.replace(/[\s\S]*navigationBarTextStyle:([^,]+),[\s\S]*/gm, '$1').replace(/["']/g, '')?.trim() | ||||
|       } | ||||
|       //导航栏背景颜色(同状态栏背景色) | ||||
|       if (/navigationBarBackgroundColor/.test(vue)) { | ||||
|         this.style.navigationBarBackgroundColor = vue.replace(/[\s\S]*navigationBarBackgroundColor:([^,]+),[\s\S]*/gm, '$1').replace(/["']/g, '')?.trim() | ||||
|       } | ||||
|       // //下拉显示出来的窗口的背景色 | ||||
|       // if (/backgroundColor/.test(vue)) { | ||||
|       //   this.style.backgroundColor = vue.replace(/[\s\S]*(backgroundColor:.+),[\s\S]*/gm, '$1') | ||||
|       // } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   setLabel(name) { | ||||
|     this.label = name | ||||
|   } | ||||
| } | ||||
|  | ||||
| module.exports = PageBase | ||||
							
								
								
									
										19
									
								
								src/components/utils/coin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,19 @@ | ||||
| export default { | ||||
|   cny(money) { | ||||
|     if (money) { | ||||
|       money.toLocaleString('zh-Hans-CN', {style: 'currency', currency: "CNY"}) | ||||
|     } | ||||
|     return money | ||||
|   }, | ||||
|   cn(money) { | ||||
|     let num = parseFloat(money), cnMoney = '', | ||||
|         units = '仟佰拾亿仟佰拾万仟佰拾元角分', | ||||
|         cnNum = '零壹贰叁肆伍陆柒捌玖' | ||||
|     num = num.toFixed(2).replace(/\./g, '') | ||||
|     units = units.substring(units.length - num.length) | ||||
|     Array.from(num).map((e, i) => { | ||||
|       cnMoney += cnNum.charAt(e) + units.charAt(i) | ||||
|     }) | ||||
|     return cnMoney.replace(/零角零分$/, '整').replace(/零[仟佰拾]/g, '零').replace(/零{2,}/g, '零').replace(/零([亿|万])/g, '$1').replace(/零+元/, '元').replace(/亿零{0,3}万/, '亿').replace(/^元/, "零元") | ||||
|   } | ||||
| } | ||||
							
								
								
									
										56
									
								
								src/components/utils/dict.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,56 @@ | ||||
| export default { | ||||
|   instance: null, | ||||
|   init(instance) { | ||||
|     this.instance = instance | ||||
|   }, | ||||
|   dicts() { | ||||
|     return uni.getStorageSync('dicts') || []; | ||||
|   }, | ||||
|   load(...code) { | ||||
|     return !!this.instance && this.instance.post('/admin/dictionary/queryValsByCodeList?codeList=' + code.join(','), null, { | ||||
|       withoutToken: true | ||||
|     }).then((res) => { | ||||
|       if (res && res.data) { | ||||
|         let cacheDicts = {}, | ||||
|             meta = {}; | ||||
|         this.dicts().map((e) => (cacheDicts[e.key] = e)); | ||||
|         res.data.map((e) => (meta[e.key] = e)); | ||||
|         let dicts = {...cacheDicts, ...meta}; | ||||
|         uni.setStorageSync('dicts', Object.values(dicts)); | ||||
|       } | ||||
|     }); | ||||
|   }, | ||||
|   getDict(key) { | ||||
|     if (this.dicts().length) { | ||||
|       let dict = this.dicts().find((e) => e.key == key); | ||||
|       return dict ? dict.values : []; | ||||
|     } else return []; | ||||
|   }, | ||||
|   getValue(key, label) { | ||||
|     if (this.dicts().length) { | ||||
|       let dict = this.dicts().find((e) => e.key == key); | ||||
|       if (dict) { | ||||
|         let item = dict.values.find((v) => v.dictName == label); | ||||
|         return item ? item.dictValue : label; | ||||
|       } else return label; | ||||
|     } else return label; | ||||
|   }, | ||||
|   getLabel(key, value) { | ||||
|     if (this.dicts().length) { | ||||
|       let dict = this.dicts().find((e) => e.key == key); | ||||
|       if (dict) { | ||||
|         let item = dict.values.find((v) => v.dictValue == value); | ||||
|         return item ? item.dictName : value; | ||||
|       } else return value ? value : ''; | ||||
|     } else return value ? value : ''; | ||||
|   }, | ||||
|   getColor(key, value) { | ||||
|     if (this.dicts().length) { | ||||
|       let dict = this.dicts().find((e) => e.key == key); | ||||
|       if (dict) { | ||||
|         let item = dict.values.find((v) => v.dictValue == value); | ||||
|         return item ? item.dictColor : value; | ||||
|       } else return value; | ||||
|     } else return value; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										29
									
								
								src/components/utils/http.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,29 @@ | ||||
| import axios from 'axios' | ||||
| import adapter from 'axios-miniprogram-adapter' | ||||
|  | ||||
| const instance = axios.create({ | ||||
|   timeout: 600000, | ||||
|   withCredentials: true, | ||||
|   adapter | ||||
| }) | ||||
| const getToken = () => { | ||||
|   let vuex = uni.getStorageSync("vuex") | ||||
|   return !!vuex ? JSON.parse(vuex).token : null | ||||
| } | ||||
| const source = axios.CancelToken.source(); | ||||
| instance.interceptors.request.use(config => { | ||||
|   if (config.withoutToken) { | ||||
|     return config | ||||
|   } else if (getToken()) { | ||||
|     config.headers["Authorization"] = getToken() | ||||
|   } else { | ||||
|     config.cancelToken = source.token | ||||
|     source.cancel("用户未验证,取消请求:" + config.url) | ||||
|   } | ||||
|   return config | ||||
| }, err => { | ||||
|   console.error(err) | ||||
|   return Promise.reject(err) | ||||
| }) | ||||
|  | ||||
| export default instance | ||||
							
								
								
									
										36
									
								
								src/components/utils/list.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,36 @@ | ||||
| import http from "./http"; | ||||
|  | ||||
| class List { | ||||
|   constructor(action) { | ||||
|     this.action = action | ||||
|     this.current = 1 | ||||
|     this.total = 0 | ||||
|     this.list = [] | ||||
|   } | ||||
|  | ||||
|   getData(params) { | ||||
|     const {action} = this | ||||
|     return http.post(action, null, {params}) | ||||
|   } | ||||
|  | ||||
|   init(params) { | ||||
|     this.getData({...params, current: 1}).then(res => { | ||||
|       if (res?.data) { | ||||
|         this.list = res.data.records | ||||
|         this.total = res.data.total | ||||
|       } | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   loadMore(params) { | ||||
|     if (this.list.length < this.total) { | ||||
|       this.getData({...params, current: ++this.current}).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.list = [...this.list, ...res.data.records] | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| export default List | ||||
							
								
								
									
										153
									
								
								src/components/utils/modules.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,153 @@ | ||||
| import http from "./http"; | ||||
| import Vue from "vue"; | ||||
|  | ||||
| /** | ||||
|  * 用户登录信息 | ||||
|  */ | ||||
| export const user = { | ||||
|   state: () => ({}), | ||||
|   mutations: { | ||||
|     setUser(state, user) { | ||||
|       for (const key in user) { | ||||
|         Vue.set(state, key, user[key]) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   actions: { | ||||
|     getUserInfo({commit}, way = "std") { | ||||
|       //获取企业微信后台账号信息 | ||||
|       //党员认证状态 partyStatusForWX:0、未认证 1、认证中 2、已认证 | ||||
|       const actions = { | ||||
|         std: "/app/appwechatuser/check", | ||||
|         qujing: "/app/appwechatuserqujing/check", | ||||
|         admin: "/app/appwechatusertog/userinfo" | ||||
|       } | ||||
|       return http.post(actions[way], null, { | ||||
|         params: {corpId: process.env.NODE_ENV == "development" ? "ww596787bb70f08288" : undefined}, | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           commit('setUser', res.data) | ||||
|           return Promise.all([]) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getCode({dispatch}, count = 0) { | ||||
|       if (count > 3) { | ||||
|         return Promise.reject("无法获取code") | ||||
|       } else return new Promise((resolve, reject) => { | ||||
|         uni.login({ | ||||
|           success: res => { | ||||
|             if (res?.code) { | ||||
|               resolve(res.code); | ||||
|             } else { | ||||
|               reject(res); | ||||
|             } | ||||
|           }, | ||||
|           fail: err => { | ||||
|             console.error(err) | ||||
|             resolve(dispatch("getCode", ++count)) | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     getToken({commit}, params) { | ||||
|       if (params?.code) { | ||||
|         return http.post("/auth/wechat-con/token", params, { | ||||
|           headers: {"Authorization": "Basic d2VjaGF0OndlY2hhdA=="}, | ||||
|           withoutToken: true | ||||
|         }).then(res => { | ||||
|           if (res?.access_token) { | ||||
|             const token = [res?.token_type, res?.access_token].join(" ").trim() | ||||
|             commit("setToken", token) | ||||
|             return token | ||||
|           } else { | ||||
|             uni.showToast({title: res?.msg}) | ||||
|             return Promise.reject(res?.msg) | ||||
|           } | ||||
|         }) | ||||
|       } else return Promise.reject("缺少登录code") | ||||
|     }, | ||||
|     getAdminToken({commit}, params) { | ||||
|       const {corpId = process.env.NODE_ENV == "development" ? "ww596787bb70f08288" : undefined} = params | ||||
|       if (params?.code) { | ||||
|         return http.post("/auth/wechat-2g/token", params, { | ||||
|           headers: {"Authorization": "Basic d2VjaGF0OndlY2hhdA=="}, | ||||
|           params: {corpId}, | ||||
|           withoutToken: true | ||||
|         }).then(res => { | ||||
|           if (res?.access_token) { | ||||
|             const token = [res?.token_type, res?.access_token].join(" ").trim() | ||||
|             commit("setToken", token) | ||||
|             return token | ||||
|           } else { | ||||
|             uni.showToast({title: res?.msg}) | ||||
|             return Promise.reject(res?.msg) | ||||
|           } | ||||
|         }) | ||||
|       } else return Promise.reject("缺少登录code") | ||||
|     }, | ||||
|     autoLogin({dispatch, commit, rootState}, params = {nickName: '微信用户'}) { | ||||
|       const {loginWay = rootState.loginWay || "std", phoneCode} = params | ||||
|       commit("setLoginWay", loginWay) | ||||
|       if (loginWay == "admin") { | ||||
|         return phoneCode ? dispatch("getCode", params).then(code => dispatch('getAdminToken', {...params, code})).then(() => dispatch('getUserInfo', loginWay)) : Promise.reject("缺少手机号授权") | ||||
|       } else return dispatch("getCode").then(code => dispatch("getToken", {...params, code})).then(() => dispatch('getUserInfo', loginWay)) | ||||
|     }, | ||||
|     authCheck({state, dispatch, rootState}, {checkType, modulePath}) { | ||||
|       //用于进入应用的权限判断 | ||||
|       //checkType  1、登录认证 2、居民认证 3、党员认证 4、丰都个人认证  5、网格员 | ||||
|       //判断是否需要校验认证信息 | ||||
|       let {user: userInfo, token} = rootState | ||||
|       if (!checkType) { | ||||
|         //如果需要校验认证信息,必定要先验证是否登录 | ||||
|         uni.navigateTo({url: modulePath}); | ||||
|       } else if (checkType == 1) { | ||||
|         if (!token) { | ||||
|           return dispatch('autoLogin').then(() => dispatch('authCheck', {checkType, modulePath})); | ||||
|         } | ||||
|         uni.navigateTo({url: modulePath}); | ||||
|       } else if (checkType == 2) { | ||||
|         if (!token) { | ||||
|           return dispatch('autoLogin').then(() => dispatch('authCheck', {checkType, modulePath})); | ||||
|         } | ||||
|         if (!(userInfo.residentId && userInfo.status == 2)) { | ||||
|           return uni.navigateTo({url: '/mods/AppAuth/AppAuth'}); | ||||
|         } | ||||
|         uni.navigateTo({url: modulePath}); | ||||
|       } else if (checkType == 3) { | ||||
|         if (!token) { | ||||
|           return dispatch('autoLogin').then(() => dispatch('authCheck', {checkType, modulePath})); | ||||
|         } | ||||
|         if (!userInfo?.partyId) { | ||||
|           return uni.showToast({title: "您还不是党员,暂时无法使用该功能", icon: "none"}); | ||||
|         } | ||||
|         uni.navigateTo({url: modulePath}); | ||||
|       } else if (checkType == 4) { | ||||
|         if (!token) { | ||||
|           return dispatch('autoLogin', {loginWay: 'qujing'}).then(() => dispatch('authCheck', {checkType, modulePath})); | ||||
|         } | ||||
|         if (!userInfo.areaId) { | ||||
|           return uni.showModal({ | ||||
|             title: '温馨提示', | ||||
|             content: '您只有完成信息认证后,才可进行相关操作。', | ||||
|             confirmText: '去认证', | ||||
|             success: (res) => { | ||||
|               if (res.confirm) { | ||||
|                 uni.reLaunch({url: `/pages/AppMine/userInfo?isFromTabbar=1&path=/pages/AppHome/AppHome`}) | ||||
|               } else if (res.cancel) { | ||||
|                 // 停留 | ||||
|               } | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|         uni.navigateTo({url: modulePath}); | ||||
|       } else if (checkType == 5) { | ||||
|         if (userInfo.girdInfos2G && userInfo.girdInfos2G.length) { | ||||
|           uni.navigateTo({url: modulePath}); | ||||
|         }else { | ||||
|           return uni.showToast({title: "您还不是网格员,暂时无法使用该功能", icon: "none"}); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										35
									
								
								src/components/utils/moment.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,35 @@ | ||||
| import moment from 'dayjs' | ||||
| import duration from 'dayjs/plugin/duration' | ||||
| import updateLocale from 'dayjs/plugin/updateLocale' | ||||
| import customParseFormat from 'dayjs/plugin/customParseFormat' | ||||
| import 'dayjs/locale/zh-cn' | ||||
|  | ||||
| moment.locale('zh-cn') | ||||
| moment.extend(updateLocale) | ||||
| moment.extend(customParseFormat) | ||||
| moment.extend(duration) | ||||
| moment.updateLocale('zh-cn', { | ||||
|   weekdays: "星期日|星期一|星期二|星期三|星期四|星期五|星期六".split("|"), | ||||
|   meridiem(hour) { | ||||
|     let word = "" | ||||
|     if (hour < 6) { | ||||
|       word = "凌晨" | ||||
|     } else if (hour < 9) { | ||||
|       word = "早上" | ||||
|     } else if (hour < 12) { | ||||
|       word = "上午" | ||||
|     } else if (hour < 14) { | ||||
|       word = "中午" | ||||
|     } else if (hour < 17) { | ||||
|       word = "下午" | ||||
|     } else if (hour < 19) { | ||||
|       word = "傍晚" | ||||
|     } else if (hour < 22) { | ||||
|       word = "晚上" | ||||
|     } else { | ||||
|       word = "夜里" | ||||
|     } | ||||
|     return word; | ||||
|   } | ||||
| }) | ||||
| export default moment | ||||
							
								
								
									
										16
									
								
								src/components/utils/regular.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,16 @@ | ||||
| export default { | ||||
|   phone: /^((0\d{2,3}-\d{7,8})|((13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}))$/, | ||||
|   password: /^(?=.*\d)(?=.*[a-zA-Z])(?=.*[~!@#$%^&*,.?_-])[\da-zA-Z~!@#$%^&*,.?_-]{8,16}$/, | ||||
|   money: /^([1-9]\d*|0)(\.\d{1,2})?$/, | ||||
|   area: { | ||||
|     village: /^\d{9}[^0]0{0,2}$/, | ||||
|     town: /^\d{6}[^0]0{0,2}000$/, | ||||
|     country: /^\d{4}[^0]0?0{6}$/, | ||||
|     city: /^\d{2}[^0]0?0{8}$/, | ||||
|     province: /^[^0]0?0{10}$/, | ||||
|   }, | ||||
|   zh: /^[\u4e00-\u9fa5]+$/, | ||||
|   email: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/, | ||||
|   ip: /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/, | ||||
|   idNumber: /^[1-9]\d{5}(19\d{2}|20[0-2]\d)(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])\d{3}([0-9xX])$/ | ||||
| } | ||||
							
								
								
									
										353
									
								
								src/components/utils/util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,353 @@ | ||||
| import $dayjs from './moment' | ||||
| import $dict from './dict' | ||||
| import $qs from 'query-string' | ||||
| import $coin from './coin' | ||||
| import $reg from "./regular" | ||||
|  | ||||
| const $toast = (obj) => { | ||||
|   let params = {title: '', duration: 2000, icon: 'none'}; | ||||
|   if (typeof obj == 'string') { | ||||
|     params.title = obj; | ||||
|   } else { | ||||
|     Object.assign(params, obj); | ||||
|   } | ||||
|   uni.showToast(params); | ||||
| }; | ||||
|  | ||||
| const $loading = (title) => { | ||||
|   uni.showLoading({ | ||||
|     title: title ? title : '加载中', | ||||
|     mask: true | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| const $hideLoading = () => { | ||||
|   uni.hideLoading(); | ||||
| }; | ||||
|  | ||||
| const $dialog = { | ||||
|   alert: (params) => { | ||||
|     return new Promise((resolve) => { | ||||
|       uni.showModal({ | ||||
|         title: '温馨提示', | ||||
|         showCancel: false, | ||||
|         confirmColor: '#197DF0', | ||||
|         confirmText: params.confirmButtonText ? params.confirmButtonText : '确定', | ||||
|         ...params, | ||||
|         success: (res) => { | ||||
|           if (res.confirm) { | ||||
|             resolve(); | ||||
|           } | ||||
|         } | ||||
|       }); | ||||
|     }); | ||||
|   }, | ||||
|  | ||||
|   confirm: (params) => { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       uni.showModal({ | ||||
|         title: '温馨提示', | ||||
|         showCancel: true, | ||||
|         confirmColor: '#197DF0', | ||||
|         cancelText: params.cancelButtonText ? params.cancelButtonText : '取消', | ||||
|         confirmText: params.confirmButtonText ? params.confirmButtonText : '确定', | ||||
|         ...params, | ||||
|         success: (res) => { | ||||
|           if (res.confirm) { | ||||
|             resolve(); | ||||
|           } else if (res.cancel) { | ||||
|             reject(); | ||||
|           } | ||||
|         } | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const $linkTo = (url) => { | ||||
|   uni.navigateTo({ | ||||
|     url | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| const $formatName = (name) => { | ||||
|   if (name == undefined) { | ||||
|     return; | ||||
|   } | ||||
|   return name.substr(name.length - 2, name.length > 2 ? name.length - 1 : name.length); | ||||
| }; | ||||
|  | ||||
| const $previewImage = (list, index, urlName) => { | ||||
|   uni.previewImage({ | ||||
|     current: list[index][urlName], | ||||
|     urls: list.map((v) => v[urlName]) | ||||
|   }); | ||||
| }; | ||||
|  | ||||
|  | ||||
| const $getUserProfile = () => { | ||||
|   return new Promise(function (resolve) { | ||||
|     wx.getUserProfile({ | ||||
|       desc: '用于完善会员资料', | ||||
|       lang: 'zh_CN', | ||||
|       success: (data) => { | ||||
|         resolve(data); | ||||
|       }, | ||||
|       fail: (err) => { | ||||
|         console.log(err); | ||||
|       } | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| /** | ||||
|  * 身份证工具包 | ||||
|  */ | ||||
| const idCardNoUtil = { | ||||
|   /*省,直辖市代码表*/ | ||||
|   provinceAndCitys: { | ||||
|     11: "北京", | ||||
|     12: "天津", | ||||
|     13: "河北", | ||||
|     14: "山西", | ||||
|     15: "内蒙古", | ||||
|     21: "辽宁", | ||||
|     22: "吉林", | ||||
|     23: "黑龙江", | ||||
|     31: "上海", | ||||
|     32: "江苏", | ||||
|     33: "浙江", | ||||
|     34: "安徽", | ||||
|     35: "福建", | ||||
|     36: "江西", | ||||
|     37: "山东", | ||||
|     41: "河南", | ||||
|     42: "湖北", | ||||
|     43: "湖南", | ||||
|     44: "广东", | ||||
|     45: "广西", | ||||
|     46: "海南", | ||||
|     50: "重庆", | ||||
|     51: "四川", | ||||
|     52: "贵州", | ||||
|     53: "云南", | ||||
|     54: "西藏", | ||||
|     61: "陕西", | ||||
|     62: "甘肃", | ||||
|     63: "青海", | ||||
|     64: "宁夏", | ||||
|     65: "新疆", | ||||
|     71: "台湾", | ||||
|     81: "香港", | ||||
|     82: "澳门", | ||||
|     91: "国外" | ||||
|   }, | ||||
|  | ||||
|   /*每位加权因子*/ | ||||
|   powers: ["7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2"], | ||||
|  | ||||
|   /*第18位校检码*/ | ||||
|   parityBit: ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"], | ||||
|  | ||||
|   /*性别*/ | ||||
|   genders: {male: "男", female: "女"}, | ||||
|  | ||||
|   /*校验地址码*/ | ||||
|   checkAddressCode: function (addressCode) { | ||||
|     const check = /^[1-9]\d{5}$/.test(addressCode); | ||||
|     if (!check) return false; | ||||
|     return !!idCardNoUtil.provinceAndCitys[parseInt(addressCode.substring(0, 2))]; | ||||
|   }, | ||||
|  | ||||
|   /*校验日期码*/ | ||||
|   checkBirthDayCode: function (birDayCode) { | ||||
|     const check = /^[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))$/.test(birDayCode); | ||||
|     if (!check) return false; | ||||
|     const yyyy = parseInt(birDayCode.substring(0, 4), 10); | ||||
|     const mm = parseInt(birDayCode.substring(4, 6), 10); | ||||
|     const dd = parseInt(birDayCode.substring(6), 10); | ||||
|     const xdata = new Date(yyyy, mm - 1, dd); | ||||
|     if (xdata > new Date()) { | ||||
|       return false; //生日不能大于当前日期 | ||||
|     } else return (xdata.getFullYear() == yyyy) && (xdata.getMonth() == mm - 1) && (xdata.getDate() == dd); | ||||
|   }, | ||||
|  | ||||
|   /*计算校检码*/ | ||||
|   getParityBit: function (idCardNo) { | ||||
|     const id17 = idCardNo.substring(0, 17); | ||||
|     /*加权 */ | ||||
|     let power = 0; | ||||
|     for (let i = 0; i < 17; i++) { | ||||
|       power += parseInt(id17.charAt(i), 10) * parseInt(idCardNoUtil.powers[i]); | ||||
|     } | ||||
|     /*取模*/ | ||||
|     const mod = power % 11; | ||||
|     return idCardNoUtil.parityBit[mod]; | ||||
|   }, | ||||
|  | ||||
|   /*验证校检码*/ | ||||
|   checkParityBit: function (idCardNo) { | ||||
|     const parityBit = idCardNo.charAt(17).toUpperCase(); | ||||
|     return idCardNoUtil.getParityBit(idCardNo) == parityBit; | ||||
|   }, | ||||
|  | ||||
|   /*校验15位或18位的身份证号码*/ | ||||
|   checkIdCardNo: function (idCardNo) { | ||||
|     //15位和18位身份证号码的基本校验 | ||||
|     const check = /^\d{15}|(\d{17}(\d|x|X))$/.test(idCardNo); | ||||
|     if (!check) return false; | ||||
|     //判断长度为15位或18位 | ||||
|     if (idCardNo.length == 15) { | ||||
|       return idCardNoUtil.check15IdCardNo(idCardNo); | ||||
|     } else if (idCardNo.length == 18) { | ||||
|       return idCardNoUtil.check18IdCardNo(idCardNo); | ||||
|     } else { | ||||
|       return false; | ||||
|     } | ||||
|   }, | ||||
|  | ||||
| //校验15位的身份证号码 | ||||
|   check15IdCardNo: function (idCardNo) { | ||||
|     //15位身份证号码的基本校验 | ||||
|     let check = /^[1-9]\d{7}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}$/.test(idCardNo); | ||||
|     if (!check) return false; | ||||
|     //校验地址码 | ||||
|     const addressCode = idCardNo.substring(0, 6); | ||||
|     check = idCardNoUtil.checkAddressCode(addressCode); | ||||
|     if (!check) return false; | ||||
|     const birDayCode = '19' + idCardNo.substring(6, 12); | ||||
|     //校验日期码 | ||||
|     return idCardNoUtil.checkBirthDayCode(birDayCode); | ||||
|   }, | ||||
|  | ||||
| //校验18位的身份证号码 | ||||
|   check18IdCardNo: function (idCardNo) { | ||||
|     //18位身份证号码的基本格式校验 | ||||
|     let check = /^[1-9]\d{5}[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}(\d|x|X)$/.test(idCardNo); | ||||
|     if (!check) return false; | ||||
|     //校验地址码 | ||||
|     const addressCode = idCardNo.substring(0, 6); | ||||
|     check = idCardNoUtil.checkAddressCode(addressCode); | ||||
|     if (!check) return false; | ||||
|     //校验日期码 | ||||
|     const birDayCode = idCardNo.substring(6, 14); | ||||
|     check = idCardNoUtil.checkBirthDayCode(birDayCode); | ||||
|     if (!check) return false; | ||||
|     //验证校检码 | ||||
|     return idCardNoUtil.checkParityBit(idCardNo); | ||||
|   }, | ||||
|  | ||||
|   formateDateCN: function (day) { | ||||
|     const yyyy = day.substring(0, 4); | ||||
|     const mm = day.substring(4, 6); | ||||
|     const dd = day.substring(6); | ||||
|     return yyyy + '-' + mm + '-' + dd; | ||||
|   }, | ||||
|  | ||||
| //获取信息 | ||||
|   getIdCardInfo: function (idCardNo) { | ||||
|     let aday; | ||||
|     let idCardInfo = { | ||||
|       gender: "", //性别 | ||||
|       birthday: "", // 出生日期(yyyy-mm-dd) | ||||
|       sex: ""//系统性别码 | ||||
|     }; | ||||
|     if (idCardNo.length == 15) { | ||||
|       aday = '19' + idCardNo.substring(6, 12); | ||||
|       idCardInfo.birthday = idCardNoUtil.formateDateCN(aday); | ||||
|       if (parseInt(idCardNo.charAt(14)) % 2 == 0) { | ||||
|         idCardInfo.gender = idCardNoUtil.genders.female; | ||||
|       } else { | ||||
|         idCardInfo.gender = idCardNoUtil.genders.male; | ||||
|       } | ||||
|     } else if (idCardNo.length == 18) { | ||||
|       aday = idCardNo.substring(6, 14); | ||||
|       idCardInfo.birthday = idCardNoUtil.formateDateCN(aday); | ||||
|       if (parseInt(idCardNo.charAt(16)) % 2 == 0) { | ||||
|         idCardInfo.gender = idCardNoUtil.genders.female; | ||||
|       } else { | ||||
|         idCardInfo.gender = idCardNoUtil.genders.male; | ||||
|       } | ||||
|       idCardInfo.sex = "" + Number(idCardNo.substring(16, 17)) % 2 | ||||
|     } | ||||
|     return idCardInfo; | ||||
|   }, | ||||
|  | ||||
|   /*18位转15位*/ | ||||
|   getId15: function (idCardNo) { | ||||
|     if (idCardNo.length == 15) { | ||||
|       return idCardNo; | ||||
|     } else if (idCardNo.length == 18) { | ||||
|       return idCardNo.substring(0, 6) + idCardNo.substring(8, 17); | ||||
|     } else { | ||||
|       return null; | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   /*15位转18位*/ | ||||
|   getId18: function (idCardNo) { | ||||
|     if (idCardNo.length == 15) { | ||||
|       const id17 = idCardNo.substring(0, 6) + '19' + idCardNo.substring(6); | ||||
|       const parityBit = idCardNoUtil.getParityBit(id17); | ||||
|       return id17 + parityBit; | ||||
|     } else if (idCardNo.length == 18) { | ||||
|       return idCardNo; | ||||
|     } else { | ||||
|       return null; | ||||
|     } | ||||
|   }, | ||||
|   hideId(code) { | ||||
|     return code && code.replace(/^(\d{10})\d{4}(.{4}$)/g, `$1${Array(5).join('*')}$2`) || "-" | ||||
|   } | ||||
| } | ||||
| /** | ||||
|  * 获取年龄 | ||||
|  * @param code | ||||
|  */ | ||||
| const $calcAge = (code) => { | ||||
|   let birthday | ||||
|   if (typeof code == 'string' && code.length == 18) { | ||||
|     birthday = $dayjs(code.substring(6, 14), 'YYYYMMDD') | ||||
|   } else if (typeof code == 'object') { | ||||
|     birthday = code | ||||
|   } | ||||
|   return Math.ceil($dayjs.duration($dayjs().unix() - $dayjs(birthday).unix(), 's').asYears()) | ||||
| } | ||||
| /** | ||||
|  * 获取code | ||||
|  * @returns {Promise<unknown>} | ||||
|  */ | ||||
| const $getLoginCode = () => { | ||||
|   return new Promise(function (resolve, reject) { | ||||
|     uni.login({ | ||||
|       success: function (res) { | ||||
|         if (res.code) { | ||||
|           resolve(res); | ||||
|         } else { | ||||
|           reject(res); | ||||
|         } | ||||
|       }, | ||||
|       fail: function () { | ||||
|         reject(false); | ||||
|       } | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| export default { | ||||
|   $toast, | ||||
|   $loading, | ||||
|   $hideLoading, | ||||
|   $dialog, | ||||
|   $linkTo, | ||||
|   $formatName, | ||||
|   $previewImage, | ||||
|   $getUserProfile, | ||||
|   $idCardNoUtil: idCardNoUtil, | ||||
|   $calcAge, | ||||
|   $dayjs, | ||||
|   $dict, | ||||
|   $getLoginCode, | ||||
|   $qs, | ||||
|   $coin, | ||||
|   $reg | ||||
| }; | ||||
							
								
								
									
										24
									
								
								src/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,24 @@ | ||||
| import Vue from 'vue' | ||||
| import App from './App' | ||||
| import store from './store' | ||||
| import axios from "./utils/axios" | ||||
| import utils from 'dvcp-wui/utils/util' | ||||
| import config from './utils/config' | ||||
| import vui from 'uview-ui' | ||||
| import 'uview-ui/theme.scss' | ||||
|  | ||||
| Vue.use(vui) | ||||
| Vue.config.productionTip = false | ||||
| Vue.prototype.$instance = axios | ||||
| Vue.prototype.$areaId = config.areaId; | ||||
| Vue.prototype.$areaName = config.areaName; | ||||
| Vue.prototype.$cdn = 'https://cdn.cunwuyun.cn/' | ||||
| App.mpType = 'app' | ||||
| Object.keys(utils).map(e => Vue.prototype[e] = utils[e]) | ||||
| utils.$dict.init(axios) | ||||
|  | ||||
| const app = new Vue({ | ||||
|   store, | ||||
|   ...App | ||||
| }) | ||||
| app.$mount() | ||||
							
								
								
									
										42
									
								
								src/manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,42 @@ | ||||
| { | ||||
|   "name": "dvcp-wechatApps", | ||||
|   "description": "数字乡村小程序应用库", | ||||
|   "versionName": "1.0.0", | ||||
|   "versionCode": "100", | ||||
|   "transformPx": true, | ||||
|   "mp-weixin": { | ||||
|     "appid": "wx576d5e829b9e7d49", | ||||
|     "setting": { | ||||
|       "urlCheck": false | ||||
|     }, | ||||
|     "optimization": { | ||||
|       "subPackages": true | ||||
|     }, | ||||
|     "usingComponents": true, | ||||
|     "permission": { | ||||
|       "scope.userLocation": { | ||||
|         "desc": "你的位置信息将用于当前事件发生地点" | ||||
|       }, | ||||
|       "scope.record": { | ||||
|         "desc": "你的录音功能将使用" | ||||
|       }, | ||||
|       "scope.phoneNumber": { | ||||
|         "desc": "你的手机号码将用于当前身份信息验证" | ||||
|       } | ||||
|     }, | ||||
|     "plugins": { | ||||
|       "materialPlugin": { | ||||
|         "version": "1.0.5", | ||||
|         "provider": "wx4d2deeab3aed6e5a" | ||||
|       }, | ||||
|       "player": { | ||||
|         "version": "2.1.15", | ||||
|         "provider": "wxa75efa648b60994b" | ||||
|       } | ||||
|     }, | ||||
|     "requiredPrivateInfos": [ | ||||
|       "getLocation", | ||||
|       "chooseLocation" | ||||
|     ] | ||||
|   } | ||||
| } | ||||
							
								
								
									
										175
									
								
								src/mods/conv/AppAddressBook/AppAddressBook.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,175 @@ | ||||
| <template> | ||||
|   <div class="wrapper"> | ||||
|     <div class="searAreName"> | ||||
|       <AiAreaPicker ref="area" class="ai-area" v-model="areaId" :name.sync="areaName" :areaId="$areaId" @input="areaSelect" > | ||||
|         <div class="ai-area__wrapper"> | ||||
|           <span class="label" v-if="areaName">{{ areaName }}</span> | ||||
|           <span v-else>请选择</span> | ||||
|           <u-icon name="arrow-down" color="#666" size="24" style="margin-left: 4px"></u-icon> | ||||
|         </div> | ||||
|       </AiAreaPicker> | ||||
|       <!-- <span v-else>{{ areaName }}</span> --> | ||||
|  | ||||
|       <u-search v-model="name" ref="searchObj" placeholder="请输入名称/类型/电话" :show-action="false" clearabled bg-color="#F5F5F5" search-icon-color="#ccc" placeholder-color="#666" @search="handerSearch" @clear=";(index = []), (name = ''), getList()" style="width: 70%" /> | ||||
|     </div> | ||||
|  | ||||
|     <!-- <AiTopFixed> | ||||
|       <div class="searchObj"> | ||||
|         <u-search v-model="name" ref="searchObj" placeholder="请输入姓名或电话" :show-action="false" clearabled bg-color="#F5F7F9" search-icon-color="#6AA8F8" placeholder-color="#D0D4D4" @search="handerSearch" @clear=";(index = []), (name = ''), getList()" /> | ||||
|       </div> | ||||
|     </AiTopFixed> --> | ||||
|  | ||||
|     <template v-if="list.length"> | ||||
|       <u-index-list :scrollTop="scrollTop" :index-list="indexList"> | ||||
|         <div v-for="(letter, index) in indexList" :key="index"> | ||||
|           <u-index-anchor :index="letter" /> | ||||
|           <div class="item" hover-class="bg-hover" @click="phone(item)" v-for="(item, index) in list.filter((e) => e.nameInitials == letter)" :key="index"> | ||||
|             <label>{{ item.name }}</label> | ||||
|             <div class="info"> | ||||
|               {{ item.type }}<span>{{ item.phone }}</span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </u-index-list> | ||||
|     </template> | ||||
|  | ||||
|     <AiEmpty v-else></AiEmpty> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapState } from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: 'AppAddressBook', | ||||
|   appName: '便民通讯录', | ||||
|   data() { | ||||
|     return { | ||||
|       scrollTop: 0, | ||||
|       indexList: [], | ||||
|       list: [], | ||||
|       userInfo: {}, | ||||
|       areaId: '', | ||||
|       $areaId: '', | ||||
|       areaName: '', | ||||
|       name: '', | ||||
|     } | ||||
|   }, | ||||
|   onLoad() { | ||||
|     this.userInfo = uni.getStorageSync('userInfo') | ||||
|     this.areaId = this.$areaId | ||||
|     this.areaName = this.$areaName | ||||
|     this.getList() | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|   }, | ||||
|   watch: {}, | ||||
|   methods: { | ||||
|     phone({ phone: phoneNumber }) { | ||||
|       uni.makePhoneCall({ phoneNumber }) | ||||
|     }, | ||||
|     getList() { | ||||
|       this.$instance | ||||
|         .post('/app/appconvenientaddressbook/list', null, { | ||||
|           params: { | ||||
|             isPublic: 1, | ||||
|             resource: 'portal', | ||||
|             areaId: this.areaId, | ||||
|             size: 999, | ||||
|             name: this.name, | ||||
|           }, | ||||
|         }) | ||||
|         .then((res) => { | ||||
|           if (res?.data) { | ||||
|             this.indexList = [...new Set(res.data.records.map((e) => e.nameInitials))] | ||||
|             this.list = res.data.records | ||||
|           } | ||||
|         }) | ||||
|     }, | ||||
|     areaSelect(v) { | ||||
|       if(this.user.status == 2 ) { | ||||
|         this.areaId = v | ||||
|         this.isMore = false | ||||
|         this.current = 0 | ||||
|         this.list = [] | ||||
|       } else { | ||||
|         return false | ||||
|       } | ||||
|       this.$nextTick(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     handerSearch(e) { | ||||
|       this.name = e | ||||
|       this.getList() | ||||
|     }, | ||||
|   }, | ||||
|   onPageScroll(e) { | ||||
|     this.scrollTop = e.scrollTop | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .wrapper { | ||||
|   .searAreName { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
|     padding: 24px 32px; | ||||
|     background: #fff; | ||||
|   } | ||||
|  | ||||
|   ::v-deep .AiTopFixed { | ||||
|     width: 100%; | ||||
|     .placeholder { | ||||
|       opacity: 1; | ||||
|       visibility: inherit; | ||||
|       .content { | ||||
|         padding: 0 !important; | ||||
|       } | ||||
|     } | ||||
|     .fixed { | ||||
|       width: 0; | ||||
|       margin: 0 !important; | ||||
|       .content { | ||||
|         padding: 0 !important; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .searchObj { | ||||
|     padding: 24px 32px; | ||||
|     background: #fff; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .item { | ||||
|   box-sizing: border-box; | ||||
|   padding: 32px 48px; | ||||
|   background: #ffffff; | ||||
|   box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.02); | ||||
|  | ||||
|   & > label { | ||||
|     font-size: 32px; | ||||
|     font-weight: 600; | ||||
|     color: #333333; | ||||
|     line-height: 44px; | ||||
|   } | ||||
|  | ||||
|   .info { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     font-size: 26px; | ||||
|     color: #999999; | ||||
|     margin-top: 8px; | ||||
|  | ||||
|     & > span { | ||||
|       color: #333333; | ||||
|       margin-left: 16px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										664
									
								
								src/mods/conv/AppEnteringVillage/AppEnteringVillage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,664 @@ | ||||
| <template> | ||||
|   <div class="wrapper"> | ||||
|     <div class="header" :class="[isFixed ? 'header-active' : '']"> | ||||
|       <div class="status-bar" :style="{height: statusBarHeight + 'px'}"></div> | ||||
|       <div class="nav-bar"> | ||||
|         <h2>进村</h2> | ||||
|       </div> | ||||
|     </div> | ||||
|     <header> | ||||
|       <image src="https://cdn.sinoecare.com/i/2024/07/23/669f246434b23.png"/> | ||||
|       <div> | ||||
|         <AiAreaPicker :selectRoot="false" ref="area" :value="areaId" :name.sync="areaName" :areaId="$areaId" | ||||
|                       @input="areaSelect"> | ||||
|           <div class="ai-area__wrapper"> | ||||
|             <span class="label" v-if="areaName">{{ areaName }}</span> | ||||
|             <span v-else>请选择</span> | ||||
|             <image src="/static/img/area-bottom.png"/> | ||||
|           </div> | ||||
|         </AiAreaPicker> | ||||
|         <div class="welcome">欢迎进入{{ areaName }}</div> | ||||
|         <div class="tag" v-if="user.homeArea === areaId">我的家乡</div> | ||||
|         <div class="tag1" @click="updateUserInfo" v-if="!user.homeArea && token">设为家乡</div> | ||||
|       </div> | ||||
|     </header> | ||||
|     <div class="card"> | ||||
|       <div class="card-item" hover-class="text-hover" @click="$linkTo('/mods/AppVillagerInfo/AppVillagerInfo?type=0')"> | ||||
|         <image src="/static/img/bcjj.png"/> | ||||
|       </div> | ||||
|       <div class="card-item" hover-class="text-hover" @click="$linkTo('/mods/AppVillagerInfo/AppVillagerInfo?type=4')"> | ||||
|         <image src="/static/img/cgmy.png"/> | ||||
|       </div> | ||||
|       <div class="card-item" hover-class="text-hover" | ||||
|            @click="linkTo('/mods/AppCreditPoints/AppIntegralRanking', 'idNumber')"> | ||||
|         <image src="/static/img/jfph.png"/> | ||||
|       </div> | ||||
|       <div class="card-item" hover-class="text-hover" | ||||
|            @click="linkTo('/mods/AppVillagerDiscussion/AppVillagerDiscussion', 'idNumber')"> | ||||
|         <image src="/static/img/cmys.png"/> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="banner" @click="linkTo('/mods/AppCreditPoints/AppCpSupermarket', 'idNumber')"> | ||||
|       <image src="/static/img/jf-banner.png" class="banner"/> | ||||
|     </div> | ||||
|     <tempalte v-if="publicList.length"> | ||||
|       <div class="title-wrap"> | ||||
|         <span class="title">三务公开</span> | ||||
|         <div class="right" hover-class="text-hover" | ||||
|              @click="$linkTo(`/mods/AppContent/AppContent?names=三务公开&areaId=${areaId}`)"> | ||||
|           <span class="title-more">更多专题</span> | ||||
|           <u-icon name="arrow-right" size="28" color="#999999"></u-icon> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="list-news"> | ||||
|         <div class="news-wrap" v-for="(item,index) in publicList" :key="index" | ||||
|              @click="$linkTo('/mods/AppContent/contentDetail?id='+ item.id)"> | ||||
|           <div class="news-title">{{ item.title }}</div> | ||||
|           <div class="news-bottom"> | ||||
|             <div class="tag">{{ item.categoryName }}</div> | ||||
|             <div class="date">{{ item.createTime ? item.createTime.split(' ')[0] : '' }}</div> | ||||
|             <div class="view"> | ||||
|               <em>{{ item.viewCount }}</em> | ||||
|               人看过 | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </tempalte> | ||||
|     <div class="title-wrap" v-if="activityList.length"> | ||||
|       <span class="title">居民活动</span> | ||||
|       <div class="right"> | ||||
|         <span class="title-more" @click="$linkTo('/mods/AppVillageActivity/AppVillageActivity')">更多活动</span> | ||||
|         <u-icon name="arrow-right" size="28" color="#999999"></u-icon> | ||||
|       </div> | ||||
|     </div> | ||||
|     <scroll-view :scroll-x="true" style="width: 100%" class="scroll-wrap" v-if="activityList.length"> | ||||
|       <div | ||||
|           class="scroll-card" | ||||
|           @click="$linkTo('/mods/AppVillageActivity/ActivityDetail?id=' + item.id)" | ||||
|           hover-class="text-hover" | ||||
|           v-for="(item, index) in activityList" | ||||
|           :key="index"> | ||||
|         <image :src="item.url" mode="aspectFill"/> | ||||
|         <div class="text"> | ||||
|           <span>{{ item.title }}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|       <AiEmpty v-if="!activityList.length"></AiEmpty> | ||||
|     </scroll-view> | ||||
|     <div class="title-wrap"> | ||||
|       <span class="title">乡村相册</span> | ||||
|     </div> | ||||
|     <div class="album-list"> | ||||
|       <div | ||||
|           class="album" | ||||
|           v-for="(item, index) in albumList" | ||||
|           hover-class="text-hover" | ||||
|           :key="index" | ||||
|           @click="$linkTo('/mods/AppPhotoAlbum/AppPhotoAlbum?type=' + item.type + '&name=' + item.name + '&url=' + item.coverImg)"> | ||||
|         <image :src="item.coverImg"/> | ||||
|         <div class="total">共{{ item.total }}张</div> | ||||
|         <div class="desc">{{ item.name }}</div> | ||||
|       </div> | ||||
|       <AiEmpty style="width: 100%" v-if="!albumList.length"></AiEmpty> | ||||
|     </div> | ||||
|     <AiLogin ref="login"/> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| import {mapActions, mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: "AppEnteringVillage", | ||||
|   appName: "进村", | ||||
|   customNavigation: true, | ||||
|   data() { | ||||
|     return { | ||||
|       isFixed: false, | ||||
|       statusBarHeight: 20, | ||||
|       top: 0, | ||||
|       areaName: '', | ||||
|       areaId: '', | ||||
|       $areaId: '', | ||||
|       albumList: [], | ||||
|       activityList: [], | ||||
|       publicList: [], | ||||
|       moduleId: "", | ||||
|       isInit: false | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   onLoad() { | ||||
|     this.areaId = this.$mp.query.areaId || this.$areaId | ||||
|     this.areaName = this.$mp.query.areaName || this.$areaName | ||||
|     this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight | ||||
|     this.autoLogin() | ||||
|  | ||||
|     this.$nextTick(() => { | ||||
|       this.getAlbumList() | ||||
|       this.getActiveList() | ||||
|       this.getName() | ||||
|     }) | ||||
|  | ||||
|     uni.$on('update', () => { | ||||
|       this.getAlbumList() | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapState(['user', 'token']) | ||||
|   }, | ||||
|  | ||||
|   onShow() { | ||||
|     this.$nextTick(() => { | ||||
|       this.token && this.getUserInfo() | ||||
|     }) | ||||
|  | ||||
|     if (this.user.homeArea) { | ||||
|       if (!this.isInit) { | ||||
|         this.areaId = this.user.homeArea | ||||
|         this.areaName = this.user.homeName | ||||
|         uni.setStorageSync('areaId', this.user.homeArea) | ||||
|         uni.setStorageSync('areaName', this.user.homeName) | ||||
|         this.isInit = true | ||||
|       } | ||||
|     } else if (!this.isInit && !this.user.homeArea) { | ||||
|       setTimeout(() => { | ||||
|         this.$dialog.alert({ | ||||
|           content: '请选择您的家乡' | ||||
|         }).then(() => { | ||||
|           this.$refs.area?.handleJump() | ||||
|           this.isInit = true | ||||
|         }) | ||||
|       }, 600) | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions(['autoLogin', 'getUserInfo']), | ||||
|     getName() { | ||||
|       this.$instance.post("/app/appcontentmoduleinfo/listByNames", null, { | ||||
|         params: {names: "三务公开"} | ||||
|       }).then(res => { | ||||
|         if (res.data && res.data.length) { | ||||
|           this.moduleId = res.data[0]["id"]; | ||||
|           this.getPublicList(); | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     updateUserInfo() { | ||||
|       if (this.areaId.endsWith('000')) { | ||||
|         this.$dialog.alert({ | ||||
|           content: '请选择村' | ||||
|         }).then(() => { | ||||
|         }) | ||||
|  | ||||
|         return false | ||||
|       } | ||||
|  | ||||
|       this.$instance.post("/app/appwechatuser/updateById", { | ||||
|         id: this.user.id, | ||||
|         homeArea: this.areaId, | ||||
|         homeName: this.areaName | ||||
|       }).then(res => { | ||||
|         if (res.code === 0) { | ||||
|           this.getUserInfo() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     getPublicList() { | ||||
|       this.$instance.post("/app/appcontentinfo/list", null, { | ||||
|         params: {moduleId: this.moduleId, size: 3, areaId: this.areaId} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.publicList = res.data.records; | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     linkTo(url, type) { | ||||
|       if (type) { | ||||
|         if (this.token) { | ||||
|           if (type === 'idNumber') { | ||||
|             if (!this.user.residentId) { | ||||
|               this.$linkTo('/mods/AppAuth/AppAuth') | ||||
|             } else { | ||||
|               this.$linkTo(url) | ||||
|             } | ||||
|           } | ||||
|         } else { | ||||
|           this.$refs.login.show() | ||||
|         } | ||||
|       } else { | ||||
|         this.$linkTo(url) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     areaSelect(v) { | ||||
|       this.areaId = v | ||||
|       this.isMore = false | ||||
|       this.current = 0 | ||||
|       this.newsList = [] | ||||
|  | ||||
|       this.$nextTick(() => { | ||||
|         this.getActiveList() | ||||
|         this.getAlbumList() | ||||
|         this.getPublicList() | ||||
|         uni.setStorageSync('areaId', this.areaId) | ||||
|         uni.setStorageSync('areaName', this.areaName) | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     getAlbumList() { | ||||
|       this.$instance.post(`/app/appvillagepicturealbum/queryAlbumMenu?areaId=${this.areaId}`).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.albumList = res.data.map(v => { | ||||
|             return { | ||||
|               ...v, | ||||
|               coverImg: `${this.$cdn}/dvcp/album/album${v.type}.png` | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     getActiveList() { | ||||
|       this.$instance.post(`/app/appvillageactivityinfo/listUp`, null, { | ||||
|         params: { | ||||
|           current: 1, | ||||
|           size: 6, | ||||
|           areaId: this.areaId | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.activityList = res.data.records.map(v => { | ||||
|             return { | ||||
|               ...v, | ||||
|               url: v.url ? JSON.parse(v.url)[0].url : '' | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   onShareAppMessage() { | ||||
|     return { | ||||
|       title: '欢迎使用数字乡村治理服务一体化平台~', | ||||
|       path: `/pages/AppEnteringVillage/AppEnteringVillage` | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   onPageScroll(params) { | ||||
|     this.isFixed = params.scrollTop > 60; | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .wrapper { | ||||
|   min-height: 100%; | ||||
|   background: #F3F6F9; | ||||
|  | ||||
|   ::v-deep .emptyImg { | ||||
|     margin-top: 0 !important; | ||||
|   } | ||||
|  | ||||
|   .header { | ||||
|     position: fixed; | ||||
|     left: 0; | ||||
|     top: 0; | ||||
|     z-index: 0; | ||||
|     width: 100%; | ||||
|     opacity: 0; | ||||
|     transition: all 0.2s ease; | ||||
|  | ||||
|     &.header-active { | ||||
|       z-index: 1111; | ||||
|       opacity: 1; | ||||
|       background: #4181FF; | ||||
|     } | ||||
|  | ||||
|     .nav-bar { | ||||
|       position: relative; | ||||
|       height: 88px; | ||||
|       line-height: 88px; | ||||
|       color: #fff; | ||||
|       font-size: 32px; | ||||
|       text-align: center; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   & > header { | ||||
|     position: relative; | ||||
|     height: 656px; | ||||
|     box-sizing: border-box; | ||||
|     padding-left: 32px; | ||||
|  | ||||
|     & > div { | ||||
|       position: relative; | ||||
|       z-index: 11; | ||||
|     } | ||||
|  | ||||
|     .ai-area__wrapper { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       padding-top: 100px; | ||||
|  | ||||
|       span { | ||||
|         margin-right: 16px; | ||||
|         color: #FFFFFF; | ||||
|         font-size: 44px; | ||||
|       } | ||||
|  | ||||
|       image { | ||||
|         width: 16px; | ||||
|         height: 8px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     & > image { | ||||
|       position: absolute; | ||||
|       left: 0; | ||||
|       top: 0; | ||||
|       z-index: 1; | ||||
|       width: 100%; | ||||
|       height: 656px; | ||||
|     } | ||||
|  | ||||
|     .welcome { | ||||
|       font-size: 28px; | ||||
|       font-weight: 400; | ||||
|       color: #FFFFFF; | ||||
|       line-height: 40px; | ||||
|       margin-top: 20px; | ||||
|     } | ||||
|  | ||||
|     .tag { | ||||
|       width: 120px; | ||||
|       height: 44px; | ||||
|       background: rgba(0, 0, 0, 0.3); | ||||
|       border-radius: 8px; | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       font-size: 22px; | ||||
|       font-weight: 400; | ||||
|       color: #c0cae0; | ||||
|       margin-top: 16px; | ||||
|     } | ||||
|  | ||||
|     .tag1 { | ||||
|       width: 120px; | ||||
|       height: 44px; | ||||
|       border: 1px solid #c0cae0; | ||||
|       background: rgba(0, 0, 0, 0.1); | ||||
|       border-radius: 8px; | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       font-size: 22px; | ||||
|       font-weight: 400; | ||||
|       color: #c0cae0; | ||||
|       margin-top: 16px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .card { | ||||
|     position: relative; | ||||
|     z-index: 1; | ||||
|     background: #FFFFFF; | ||||
|     border-radius: 32px 32px 0 0; | ||||
|     margin-top: -336px; | ||||
|     box-sizing: border-box; | ||||
|     padding: 32px 32px 0 32px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     flex-wrap: wrap; | ||||
|  | ||||
|     .card-item { | ||||
|       width: 332px; | ||||
|       height: 160px; | ||||
|       margin-bottom: 32px; | ||||
|       border-radius: 16px; | ||||
|  | ||||
|       image { | ||||
|         width: 332px; | ||||
|         height: 160px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .banner { | ||||
|     position: relative; | ||||
|     z-index: 2; | ||||
|     height: 200px; | ||||
|     background: linear-gradient(180deg, #FFFFFF 0%, #F3F6F9 100%); | ||||
|  | ||||
|     image { | ||||
|       display: block; | ||||
|       width: 692px; | ||||
|       height: 200px; | ||||
|       margin: 0 auto; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .title-wrap { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     box-sizing: border-box; | ||||
|     padding: 48px 32px 32px; | ||||
|  | ||||
|     .title { | ||||
|       font-size: 44px; | ||||
|       font-weight: 600; | ||||
|       color: #333333; | ||||
|     } | ||||
|  | ||||
|     .right { | ||||
|  | ||||
|       .title-more { | ||||
|         font-size: 28px; | ||||
|         font-weight: 400; | ||||
|         line-height: 40px; | ||||
|         color: #999999; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .list-news { | ||||
|     box-sizing: border-box; | ||||
|     padding: 0 32px; | ||||
|  | ||||
|     .news-wrap { | ||||
|       height: 186px; | ||||
|       background: #FFFFFF; | ||||
|       box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.02); | ||||
|       border-radius: 16px; | ||||
|       box-sizing: border-box; | ||||
|       padding: 32px; | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       justify-content: space-between; | ||||
|       margin-bottom: 24px; | ||||
|  | ||||
|       &:last-child { | ||||
|         margin-bottom: 0; | ||||
|       } | ||||
|  | ||||
|       .news-title { | ||||
|         font-size: 36px; | ||||
|         font-weight: 600; | ||||
|         color: #333333; | ||||
|         overflow: hidden; | ||||
|         text-overflow: ellipsis; | ||||
|         white-space: nowrap; | ||||
|       } | ||||
|  | ||||
|       .news-bottom { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|  | ||||
|         .tag { | ||||
|           width: 144px; | ||||
|           height: 48px; | ||||
|           background: #EEEEEE; | ||||
|           border-radius: 24px; | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           justify-content: center; | ||||
|           font-size: 28px; | ||||
|           font-weight: 400; | ||||
|           color: #999999; | ||||
|         } | ||||
|  | ||||
|         .date { | ||||
|           font-size: 28px; | ||||
|           font-weight: 400; | ||||
|           color: #999999; | ||||
|           margin-left: 16px; | ||||
|         } | ||||
|  | ||||
|         .view { | ||||
|           font-size: 28px; | ||||
|           font-weight: 400; | ||||
|           color: #999999; | ||||
|           margin-left: auto; | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|  | ||||
|           & > em { | ||||
|             color: #4181FF; | ||||
|             font-style: normal; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .scroll-wrap { | ||||
|     box-sizing: border-box; | ||||
|     padding: 0 32px; | ||||
|     width: 100%; | ||||
|     white-space: nowrap; | ||||
|  | ||||
|     .scroll-card { | ||||
|       display: inline-block; | ||||
|       width: 400px; | ||||
|       height: 332px; | ||||
|       background: #FFFFFF; | ||||
|       box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.02); | ||||
|       border-radius: 16px; | ||||
|       margin-right: 32px; | ||||
|       font-size: 0; | ||||
|  | ||||
|       & > image { | ||||
|         width: 400px; | ||||
|         height: 240px; | ||||
|         border-radius: 16px 16px 0 0; | ||||
|       } | ||||
|  | ||||
|       .text { | ||||
|         height: calc(100% - 240px); | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         box-sizing: border-box; | ||||
|         padding: 0 32px; | ||||
|  | ||||
|         & > span { | ||||
|           font-size: 32px; | ||||
|           font-weight: 600; | ||||
|           color: #333333; | ||||
|           overflow: hidden; | ||||
|           text-overflow: ellipsis; | ||||
|           white-space: nowrap; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|  | ||||
|       &:last-child { | ||||
|         margin-right: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .album-list { | ||||
|     box-sizing: border-box; | ||||
|     padding: 0 32px 32px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     flex-wrap: wrap; | ||||
|     gap: 16px; | ||||
|  | ||||
|     .album { | ||||
|       position: relative; | ||||
|       width: 218px; | ||||
|       height: 240px; | ||||
|       background: #FFFFFF; | ||||
|       box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.02); | ||||
|       border-radius: 16px; | ||||
|       overflow: hidden; | ||||
|  | ||||
|       image { | ||||
|         position: absolute; | ||||
|         left: 0; | ||||
|         top: 0; | ||||
|         z-index: 1; | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|       } | ||||
|  | ||||
|       .total { | ||||
|         display: flex; | ||||
|         position: absolute; | ||||
|         align-items: center; | ||||
|         justify-content: center; | ||||
|         right: 8px; | ||||
|         top: 8px; | ||||
|         z-index: 2; | ||||
|         width: 74px; | ||||
|         height: 40px; | ||||
|         background: rgba(0, 0, 0, .6); | ||||
|         border-radius: 8px; | ||||
|         font-size: 22px; | ||||
|         font-weight: 400; | ||||
|         color: #FFFFFF; | ||||
|       } | ||||
|  | ||||
|       .desc { | ||||
|         position: absolute; | ||||
|         bottom: 16px; | ||||
|         left: 0; | ||||
|         z-index: 2; | ||||
|         width: 100%; | ||||
|         height: 40px; | ||||
|         line-height: 40px; | ||||
|         padding: 0 12px; | ||||
|         font-size: 32px; | ||||
|         text-align: center; | ||||
|         color: #FFFFFF; | ||||
|         font-weight: 600; | ||||
|         box-sizing: border-box; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ::v-deep .AiArea { | ||||
|     padding-top: 64px; | ||||
|     height: 88px; | ||||
|  | ||||
|     ._img { | ||||
|       display: none; | ||||
|     } | ||||
|  | ||||
|     .area-name { | ||||
|       font-size: 44px; | ||||
|       font-weight: 600; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										
											BIN
										
									
								
								src/mods/conv/AppEnteringVillage/custom.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 970 B | 
							
								
								
									
										
											BIN
										
									
								
								src/mods/conv/AppEnteringVillage/custom_selected.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										431
									
								
								src/mods/conv/AppHealthReport/AddReport.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,431 @@ | ||||
| <template> | ||||
|   <div class="album"> | ||||
|     <div class="tips">请确保以下信息全部由本人填写,本人对所填写内容的真实性和完整性负责</div> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>返乡人员姓名</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" v-model="form.name" disabled :maxlength="20"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>身份证号</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" v-model="form.idNumber" disabled :maxlength="20"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>当前体温</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" v-model="form.temperature" :maxlength="20"/> | ||||
|             <i>℃</i> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__imgs"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>14天内是否接触新冠确诊或疑似患者</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiRadio style="width: 100%;" v-model="form.touchInFourteen" dict="epidemicTouchInFourteen"></AiRadio> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__imgs"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>当前健康状况(可多选)</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiCheckbox style="width: 100%;" v-model="form.health" dict="epidemicRecentHealth"></AiCheckbox> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>核酸检测日期</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <div class="ai-area" @click="isShowDate = true"> | ||||
|               <div class="ai-area__wrapper"> | ||||
|                 <span class="label" v-if="form.checkTime">{{ form.checkTime }}</span> | ||||
|                 <i v-else>请选择</i> | ||||
|                 <u-icon name="arrow-right" color="#ddd"/> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__imgs"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>核酸检测结果</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiRadio style="width: 100%;" v-model="form.checkResult" dict="epidemicRecentTestResult"></AiRadio> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__imgs"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>健康码类型</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiRadio style="width: 100%;" v-model="form.healthCode" dict="epidemicHealthCode"></AiRadio> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__imgs"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>已接种疫苗次数</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiRadio style="width: 100%;" v-model="form.vaccine" dict="epidemicVaccineTime"></AiRadio> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__imgs"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i style="margin-right: 8px"></i> | ||||
|             <h2>本人健康码截图<span style="color: #999; font-size:14px;font-weight:normal;">(最多9张)</span></h2> | ||||
|           </div> | ||||
|           <div class="form-item__right" style="padding-left: 5px"> | ||||
|             <AiUploader v-model="form.checkPhoto" :limit="9" multiple></AiUploader> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <u-picker mode="time" :params="dataParams" v-model="isShowDate" @confirm="onDateChange"></u-picker> | ||||
|     <div class="btn-wrapper"> | ||||
|       <div class="btn" hover-class="text-hover" @click="submit">提交</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   appName:"今日上报", | ||||
|   data() { | ||||
|     return { | ||||
|       isShowDate: false, | ||||
|       dataParams: { | ||||
|         year: true, | ||||
|         month: true, | ||||
|         day: true | ||||
|       }, | ||||
|       form: { | ||||
|         name: '', | ||||
|         idNumber: '', | ||||
|         checkPhoto: [], | ||||
|         checkResult: '', | ||||
|         health: '', | ||||
|         healthCode: '', | ||||
|         temperature: '', | ||||
|         vaccine: '', | ||||
|         checkTime: '', | ||||
|         memberId: '' | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|  | ||||
|   computed: { | ||||
|     ...mapState(['user']) | ||||
|   }, | ||||
|  | ||||
|   onLoad(query) { | ||||
|     this.form.memberId = query.id | ||||
|     this.getInfo(query.id) | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     getInfo(id) { | ||||
|       this.$instance.post(`/app/appepidemicreportmember/queryDetailById?id=${id}`).then(res => { | ||||
|         if (res.code === 0) { | ||||
|           this.form.name = res.data.name | ||||
|           this.form.idNumber = res.data.idNumber | ||||
|  | ||||
|           this.form.checkTime = res.data.checkTime ? res.data.checkTime.split(' ')[0] : '' | ||||
|           this.form.checkResult = res.data.checkResult || '' | ||||
|           this.form.healthCode = res.data.healthCode || '' | ||||
|           this.form.vaccine = res.data.vaccine || '' | ||||
|         } | ||||
|  | ||||
|         this.$hideLoading() | ||||
|       }).catch(() => { | ||||
|         this.$hideLoading() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     onDateChange(e) { | ||||
|       this.form.checkTime = `${e.year}-${e.month}-${e.day}` | ||||
|     }, | ||||
|  | ||||
|     submit() { | ||||
|       if (!this.form.temperature) { | ||||
|         return this.$toast('请输入当前体温') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.touchInFourteen) { | ||||
|         return this.$toast('请选择14天内是否接触新冠确诊或疑似患者') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.health.length) { | ||||
|         return this.$toast('请选择当前健康状况') | ||||
|       } | ||||
|       if (!this.form.checkTime) { | ||||
|         return this.$toast('请选择核酸检测日期') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.checkResult) { | ||||
|         return this.$toast('请选择核酸检测结果') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.healthCode) { | ||||
|         return this.$toast('请选择健康码类型') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.vaccine) { | ||||
|         return this.$toast('请选择已接种疫苗次数') | ||||
|       } | ||||
|  | ||||
|       // if (!this.form.checkPhoto.length) { | ||||
|       //   return this.$toast('请上传健康码截图') | ||||
|       // } | ||||
|       this.$loading() | ||||
|       this.$instance.post(`/app/appepidemichealthreport/addOrUpdate`, { | ||||
|         ...this.form, | ||||
|         openid: this.user.openid, | ||||
|         health: this.form.health.join(','), | ||||
|         checkPhoto: JSON.stringify(this.form.checkPhoto), | ||||
|         checkTime: this.form.checkTime + ' 00:00:00' | ||||
|       }).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           uni.$emit('update') | ||||
|           this.$toast('提交成功') | ||||
|           setTimeout(() => { | ||||
|             uni.navigateBack() | ||||
|           }, 400) | ||||
|         } | ||||
|         this.$hideLoading() | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| .album { | ||||
|   padding-bottom: 140px; | ||||
|  | ||||
|   .tips { | ||||
|     line-height: 1.3; | ||||
|     padding: 32px 32px; | ||||
|     color: #FF883C; | ||||
|     font-size: 30px; | ||||
|     text-align: justify; | ||||
|     background: #FFF8F3; | ||||
|   } | ||||
|  | ||||
|   .form-item__group { | ||||
|     margin-bottom: 24px; | ||||
|     background: #fff; | ||||
|   } | ||||
|  | ||||
|   .form-item { | ||||
|     padding-left: 32px; | ||||
|  | ||||
|     .form-item__checkbox { | ||||
|       width: 100%; | ||||
|  | ||||
|       div { | ||||
|         width: 100%; | ||||
|         height: 80px; | ||||
|         line-height: 80px; | ||||
|         margin-bottom: 24px; | ||||
|         text-align: center; | ||||
|         background: #FFFFFF; | ||||
|         border-radius: 16px; | ||||
|         color: #333333; | ||||
|         font-size: 28px; | ||||
|         border: 1px solid #CCCCCC; | ||||
|  | ||||
|         &.active { | ||||
|           background: #4181FF; | ||||
|           color: #fff; | ||||
|           border-color: #4181FF; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .form-item__radio { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       flex-wrap: wrap; | ||||
|  | ||||
|       div { | ||||
|         width: 212px; | ||||
|         height: 80px; | ||||
|         line-height: 80px; | ||||
|         margin-right: 16px; | ||||
|         margin-bottom: 8px; | ||||
|         text-align: center; | ||||
|         background: #FFFFFF; | ||||
|         border-radius: 16px; | ||||
|         color: #333333; | ||||
|         font-size: 28px; | ||||
|         border: 1px solid #CCCCCC; | ||||
|  | ||||
|         &:nth-of-type(3n) { | ||||
|           margin-right: 0; | ||||
|         } | ||||
|  | ||||
|         &.active { | ||||
|           background: #4181FF; | ||||
|           color: #fff; | ||||
|           border-color: #4181FF; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .ai-area__wrapper { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       padding-left: 100px; | ||||
|  | ||||
|       span { | ||||
|         color: #333; | ||||
|         font-size: 30px; | ||||
|       } | ||||
|  | ||||
|       i { | ||||
|         color: #999; | ||||
|         font-size: 30px; | ||||
|       } | ||||
|  | ||||
|       image { | ||||
|         width: 16px; | ||||
|         height: 8px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .form-item__wrapper { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: space-between; | ||||
|       height: 128px; | ||||
|       padding-right: 28px; | ||||
|       border-bottom: 1px solid #DDDDDD; | ||||
|  | ||||
|       input { | ||||
|         flex: 1; | ||||
|         height: 100%; | ||||
|         text-align: right; | ||||
|         color: #333; | ||||
|         padding-right: 10px; | ||||
|       } | ||||
|  | ||||
|       .form-item__right { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         font-size: 32px; | ||||
|  | ||||
|         span { | ||||
|           max-width: 400px; | ||||
|           margin-right: 8px; | ||||
|           color: #333333; | ||||
|           overflow: hidden; | ||||
|           white-space: nowrap; | ||||
|           text-overflow: ellipsis; | ||||
|         } | ||||
|  | ||||
|         i { | ||||
|           margin-right: 8px; | ||||
|           color: #999999; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     &:last-child { | ||||
|       .form-item__wrapper { | ||||
|         border-bottom: none; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .form-item__title { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|  | ||||
|       i { | ||||
|         font-size: 32px; | ||||
|         color: #FF4466; | ||||
|       } | ||||
|  | ||||
|       span { | ||||
|         font-size: 28px; | ||||
|         color: #999999; | ||||
|       } | ||||
|  | ||||
|       h2 { | ||||
|         padding: 0 4px; | ||||
|         font-weight: 600; | ||||
|         font-size: 32px; | ||||
|         color: #333333; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     &.form-item__imgs, &.form-item__textarea { | ||||
|       .form-item__wrapper { | ||||
|         display: block; | ||||
|         height: auto; | ||||
|         padding-bottom: 32px; | ||||
|       } | ||||
|  | ||||
|       textarea { | ||||
|         width: 100%; | ||||
|         height: 90px; | ||||
|       } | ||||
|  | ||||
|       .form-item__title { | ||||
|         padding: 32px 0; | ||||
|       } | ||||
|  | ||||
|       .form-item__right { | ||||
|         padding-left: 18px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										327
									
								
								src/mods/conv/AppHealthReport/AddUser.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,327 @@ | ||||
| <template> | ||||
|   <div class="album"> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>上报人姓名</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" v-model="form.name" :maxlength="20"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>身份证号</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" type="idcard" v-model="form.idNumber" :maxlength="20"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>手机号码</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" type="number" v-model="form.phone" :maxlength="11"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>上报地区</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiAreaPicker class="ai-area" :areaId="$areaId" v-model="form.areaId" :fullName.sync="form.areaName"> | ||||
|               <div class="ai-area__wrapper"> | ||||
|                 <span class="label" v-if="form.areaName">{{ form.areaName }}</span> | ||||
|                 <i v-else>请选择</i> | ||||
|                 <u-icon name="arrow-right" color="#ddd"/> | ||||
|               </div> | ||||
|             </AiAreaPicker> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__textarea"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>详细地址</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <textarea auto-height v-model="form.address" :maxlength="500" placeholder="请输入详细地址" | ||||
|                       placeholder-style="font-size: 16px;"></textarea> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="btn-wrapper"> | ||||
|       <div class="btn" hover-class="text-hover" @click="submit">提交</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   appName: "添加上报人员", | ||||
|   data() { | ||||
|     return { | ||||
|       form: { | ||||
|         address: '', | ||||
|         areaId: '', | ||||
|         areaName: '', | ||||
|         idNumber: '', | ||||
|         name: '', | ||||
|         phone: '' | ||||
|       }, | ||||
|       $areaId: '', | ||||
|       flag: false | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']) | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     submit() { | ||||
|       if (!this.form.name) { | ||||
|         return this.$toast('请输入上报人姓名') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.idNumber) { | ||||
|         return this.$toast('请输入上报人身份证号') | ||||
|       } | ||||
|  | ||||
|       if (!/^[1-9]\d{5}(19\d{2}|20[0-2]\d)(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])\d{3}([0-9xX])$/.test(this.form.idNumber)) { | ||||
|         return this.$toast('请输入正确的身份证账号') | ||||
|       } | ||||
|       if (!this.form.phone) { | ||||
|         return this.$toast('请选择上报人手机号码') | ||||
|       } | ||||
|  | ||||
|       if (!/^1[0-9]{10,10}$/.test(this.form.phone)) { | ||||
|         return this.$toast('请输入正确的手机号码') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.areaId) { | ||||
|         return this.$toast('请选择上报地区') | ||||
|       } | ||||
|  | ||||
|       if (this.form.areaId.substr(this.form.areaId.length - 3, 3) === '000') { | ||||
|         return this.$toast('上报地区必须选到村或社区') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.address) { | ||||
|         return this.$toast('请输入详细地址') | ||||
|       } | ||||
|       if (this.flag) return | ||||
|       this.flag = true | ||||
|  | ||||
|       this.$loading() | ||||
|       this.$instance.post(`/app/appepidemicreportmember/addOrUpdate`, { | ||||
|         ...this.form, | ||||
|         openid: this.user.openid | ||||
|       }).then(res => { | ||||
|         this.$hideLoading() | ||||
|         this.flag = false | ||||
|         if (res.code == 0) { | ||||
|           this.$toast('提交成功') | ||||
|           uni.$emit('update') | ||||
|           setTimeout(() => { | ||||
|             uni.redirectTo({ | ||||
|               url: `./Result?id=${res.data.id}` | ||||
|             }) | ||||
|           }, 400) | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| .album { | ||||
|   padding-bottom: 140px; | ||||
|  | ||||
|   .form-item__group { | ||||
|     margin-bottom: 24px; | ||||
|     background: #fff; | ||||
|   } | ||||
|  | ||||
|   .form-item { | ||||
|     padding-left: 32px; | ||||
|  | ||||
|     .form-item__checkbox { | ||||
|       width: 100%; | ||||
|  | ||||
|       div { | ||||
|         width: 100%; | ||||
|         height: 80px; | ||||
|         line-height: 80px; | ||||
|         margin-bottom: 24px; | ||||
|         text-align: center; | ||||
|         background: #FFFFFF; | ||||
|         border-radius: 16px; | ||||
|         color: #333333; | ||||
|         font-size: 28px; | ||||
|         border: 1px solid #CCCCCC; | ||||
|  | ||||
|         &.active { | ||||
|           background: #4181FF; | ||||
|           color: #fff; | ||||
|           border-color: #4181FF; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .form-item__radio { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       flex-wrap: wrap; | ||||
|  | ||||
|       div { | ||||
|         width: 212px; | ||||
|         height: 80px; | ||||
|         line-height: 80px; | ||||
|         margin-right: 16px; | ||||
|         margin-bottom: 8px; | ||||
|         text-align: center; | ||||
|         background: #FFFFFF; | ||||
|         border-radius: 16px; | ||||
|         color: #333333; | ||||
|         font-size: 28px; | ||||
|         border: 1px solid #CCCCCC; | ||||
|  | ||||
|         &:nth-of-type(3n) { | ||||
|           margin-right: 0; | ||||
|         } | ||||
|  | ||||
|         &.active { | ||||
|           background: #4181FF; | ||||
|           color: #fff; | ||||
|           border-color: #4181FF; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .ai-area__wrapper { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       padding-left: 100px; | ||||
|  | ||||
|       span { | ||||
|         color: #333; | ||||
|         font-size: 30px; | ||||
|       } | ||||
|  | ||||
|       i { | ||||
|         color: #999; | ||||
|         font-size: 30px; | ||||
|       } | ||||
|  | ||||
|       image { | ||||
|         width: 16px; | ||||
|         height: 8px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .form-item__wrapper { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: space-between; | ||||
|       height: 128px; | ||||
|       padding-right: 28px; | ||||
|       border-bottom: 1px solid #DDDDDD; | ||||
|  | ||||
|       input { | ||||
|         flex: 1; | ||||
|         height: 100%; | ||||
|         text-align: right; | ||||
|         color: #333; | ||||
|         padding-right: 10px; | ||||
|       } | ||||
|  | ||||
|       .form-item__right { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         font-size: 32px; | ||||
|  | ||||
|         span { | ||||
|           max-width: 400px; | ||||
|           margin-right: 8px; | ||||
|           color: #333333; | ||||
|           overflow: hidden; | ||||
|           white-space: nowrap; | ||||
|           text-overflow: ellipsis; | ||||
|         } | ||||
|  | ||||
|         i { | ||||
|           margin-right: 8px; | ||||
|           color: #999999; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     &:last-child { | ||||
|       .form-item__wrapper { | ||||
|         border-bottom: none; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .form-item__title { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|  | ||||
|       i { | ||||
|         font-size: 32px; | ||||
|         color: #FF4466; | ||||
|       } | ||||
|  | ||||
|       span { | ||||
|         font-size: 28px; | ||||
|         color: #999999; | ||||
|       } | ||||
|  | ||||
|       h2 { | ||||
|         padding: 0 4px; | ||||
|         font-weight: 600; | ||||
|         font-size: 32px; | ||||
|         color: #333333; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     &.form-item__imgs, &.form-item__textarea { | ||||
|       .form-item__wrapper { | ||||
|         display: block; | ||||
|         height: auto; | ||||
|         padding-bottom: 32px; | ||||
|       } | ||||
|  | ||||
|       textarea { | ||||
|         width: 100%; | ||||
|         height: 90px; | ||||
|       } | ||||
|  | ||||
|       .form-item__title { | ||||
|         padding: 32px 0; | ||||
|       } | ||||
|  | ||||
|       .form-item__right { | ||||
|         padding-left: 18px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										223
									
								
								src/mods/conv/AppHealthReport/AppHealthReport.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,223 @@ | ||||
| <template> | ||||
|   <div class="returnHomeRegister" v-if="pageShow"> | ||||
|     <div class="title"> | ||||
|       <h2>上报人员</h2> | ||||
|       <div class="right"> | ||||
|         <span>共</span> | ||||
|         <i>{{ total }}</i> | ||||
|         <span>名</span> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="home-list"> | ||||
|       <div class="item" v-for="(item, index) in list" :key="index"> | ||||
|         <div class="item-top"> | ||||
|           <div class="item-top__left"> | ||||
|             <h2>{{ item.name }}</h2> | ||||
|             <p @click.stop="$linkTo('./UserInfo?id=' + item.id)" hover-class="text-hover">查看个人信息></p> | ||||
|           </div> | ||||
|           <span v-if="item.status === '0'">健康数据异常</span> | ||||
|         </div> | ||||
|         <div class="item-bottom"> | ||||
|           <div class="item-bottom__left"> | ||||
|             <span>上报第</span> | ||||
|             <i>{{ item.diffNum || 0 }}</i> | ||||
|             <span>天</span> | ||||
|           </div> | ||||
|           <div class="item-bottom__right" hover-class="text-hover" v-if="item.today === '0'" | ||||
|                @click.stop="$linkTo('./AddReport?id=' + item.id)"> | ||||
|             <span style="color: #FF883C">今日未上报</span> | ||||
|             <u-icon name="arrow-right" color="#ddd"/> | ||||
|           </div> | ||||
|           <div class="item-bottom__right" hover-class="text-hover" v-else | ||||
|                @click.stop="$linkTo('./RecordList?id=' + item.id)"> | ||||
|             <span style="color: #999999">今日已上报</span> | ||||
|             <u-icon name="arrow-right" color="#ddd"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <AiEmpty v-if="list.length==0"/> | ||||
|     </div> | ||||
|     <div class="btn-wrapper"> | ||||
|       <div class="btn" @click="toReport" hover-class="text-hover">添加上报人员</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: "AppHealthReport", | ||||
|   appName: "健康上报", | ||||
|   data() { | ||||
|     return { | ||||
|       list: [], | ||||
|       pageShow: false, | ||||
|       current: 1, | ||||
|       total: 0, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapState(['user']) | ||||
|   }, | ||||
|  | ||||
|   onLoad() { | ||||
|     this.$loading() | ||||
|     this.$dict.load(['villageActivityStatus']).then(() => { | ||||
|       this.getList() | ||||
|     }) | ||||
|  | ||||
|     uni.$on('update', () => { | ||||
|       this.current = 1 | ||||
|       this.$nextTick(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     toReport() { | ||||
|       this.$linkTo('./AddUser') | ||||
|     }, | ||||
|  | ||||
|     getList() { | ||||
|  | ||||
|       this.$instance.post(`/app/appepidemicreportmember/list?openId=${this.user.openId}`, null, { | ||||
|         params: { | ||||
|           current: this.current, | ||||
|           size: 15 | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.total = res.data.total | ||||
|           if (this.current > 1) { | ||||
|             this.list = [...this.list, ...res.data.records] | ||||
|           } else { | ||||
|             this.list = res.data.records | ||||
|           } | ||||
|           uni.hideLoading() | ||||
|           this.pageShow = true | ||||
|           if (res.data.records.length < 15) { | ||||
|  | ||||
|             return false | ||||
|           } | ||||
|  | ||||
|           this.current = this.current + 1 | ||||
|         } else { | ||||
|           uni.hideLoading() | ||||
|         } | ||||
|       }).catch(() => { | ||||
|         uni.hideLoading() | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   onReachBottom() { | ||||
|     this.getList() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .returnHomeRegister { | ||||
|   padding: 0 0 150px 0; | ||||
|  | ||||
|   .title { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     margin-bottom: 32px; | ||||
|     padding: 48px 32px 0 32px; | ||||
|  | ||||
|     & > h2 { | ||||
|       font-size: 38px; | ||||
|       color: #333; | ||||
|       font-weight: 600; | ||||
|     } | ||||
|  | ||||
|     .right { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|  | ||||
|       span { | ||||
|         color: #666666; | ||||
|         font-size: 28px; | ||||
|       } | ||||
|  | ||||
|       i { | ||||
|         color: #4181FF; | ||||
|         font-style: normal; | ||||
|         font-size: 28px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .item { | ||||
|     margin: 0 32px 24px; | ||||
|     border-radius: 16px; | ||||
|     background: #fff; | ||||
|  | ||||
|     .item-top { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: space-between; | ||||
|       height: 152px; | ||||
|       padding: 0 32px; | ||||
|       border-bottom: 1px solid #DDDDDD; | ||||
|  | ||||
|       .item-top__left { | ||||
|         h2 { | ||||
|           line-height: 44px; | ||||
|           margin-bottom: 8px; | ||||
|           color: #333; | ||||
|           font-size: 32px; | ||||
|           font-weight: 600; | ||||
|         } | ||||
|  | ||||
|         p { | ||||
|           color: #999999; | ||||
|           font-size: 26px; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       & > span { | ||||
|         font-size: 26px; | ||||
|         color: #FF4466; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .item-bottom { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: space-between; | ||||
|       height: 104px; | ||||
|       padding: 0 32px; | ||||
|  | ||||
|       .item-bottom__right { | ||||
|         span { | ||||
|           color: #999999; | ||||
|           font-size: 28px; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .item-bottom__left { | ||||
|         span { | ||||
|           color: #999999; | ||||
|           font-size: 28px; | ||||
|         } | ||||
|  | ||||
|         i { | ||||
|           color: #4181FF; | ||||
|           font-size: 28px; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       & > div { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										246
									
								
								src/mods/conv/AppHealthReport/Detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,246 @@ | ||||
| <template> | ||||
|   <div class="detail"> | ||||
|     <div class="detail-info"> | ||||
|       <h2>健康状况</h2> | ||||
|       <div class="detail-info__item"> | ||||
|         <div class="left"> | ||||
|           <label>当前体温</label> | ||||
|         </div> | ||||
|         <div class="right"> | ||||
|           <span :style="{color: info.temperature >= 37.3 ? '#FF4466' : '#42D784'}">{{ info.temperature }}℃</span> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="detail-info__item"> | ||||
|         <div class="left"> | ||||
|           <label>14天内是否接触新冠确诊或疑似患者</label> | ||||
|         </div> | ||||
|         <div class="right"> | ||||
|           <span :style="{color: info.touchInFourteen === '0' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicTouchInFourteen', info.touchInFourteen) }}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="detail-info__item"> | ||||
|         <div class="left"> | ||||
|           <label>当前健康状况</label> | ||||
|         </div> | ||||
|         <div class="right"> | ||||
|           <span :style="{color: !info.isHealth ? '#42D784' : '#FF4466'}">{{ info.healthName }}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="detail-info"> | ||||
|       <h2>核酸检测信息</h2> | ||||
|       <div class="detail-info__item"> | ||||
|         <div class="left"> | ||||
|           <label>核酸检测日期</label> | ||||
|         </div> | ||||
|         <div class="right"> | ||||
|           <span>{{ info.checkTime.split(' ')[0] }}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="detail-info__item"> | ||||
|         <div class="left"> | ||||
|           <label>核酸检测结果</label> | ||||
|         </div> | ||||
|         <div class="right"> | ||||
|           <span :style="{color: info.checkResult === '0' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicRecentTestResult', info.checkResult) }}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="detail-info__item"> | ||||
|         <div class="left"> | ||||
|           <label>健康码状态</label> | ||||
|         </div> | ||||
|         <div class="right"> | ||||
|           <span :style="{color: info.healthCode === '0' || info.healthCode === '1' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicHealthCode', info.healthCode) }}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="detail-info__item"> | ||||
|         <div class="left"> | ||||
|           <label>已接种疫苗次数</label> | ||||
|         </div> | ||||
|         <div class="right"> | ||||
|           <span>{{ $dict.getLabel('epidemicVaccineTime', info.vaccine) }}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="detail-info__item detail-info__item--img"> | ||||
|         <div class="left"> | ||||
|           <label>本人健康码截图</label> | ||||
|         </div> | ||||
|         <div class="right"> | ||||
|           <image :src="item.url" @click="preview(item.url)" v-for="(item, index) in info.checkPhoto" :key="index" /> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     appName:"上报详情", | ||||
|     data () { | ||||
|       return { | ||||
|         info: {}, | ||||
|         pageShow: false | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     onLoad (query) { | ||||
|       this.$loading() | ||||
|       this.$dict.load(['epidemicTouchInFourteen', 'epidemicRecentHealth', 'epidemicRecentTestResult', 'epidemicHealthCode', 'epidemicVaccineTime']).then(() => { | ||||
|         this.getInfo(query.id) | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       preview (url) { | ||||
|         uni.previewImage({ | ||||
|           urls: this.info.checkPhoto.map(v => v.url), | ||||
|           current: url | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getInfo (id) { | ||||
|         this.$instance.post(`/app/appepidemichealthreport/queryDetailById?id=${id}`).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             this.info = res.data | ||||
|             this.info.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.$nextTick(() => { | ||||
|               this.pageShow = true | ||||
|             }) | ||||
|           } | ||||
|  | ||||
|           this.$hideLoading() | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       call (phone) { | ||||
|         uni.makePhoneCall({ | ||||
|           phoneNumber: phone | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   .detail { | ||||
|     padding-bottom: 40px; | ||||
|  | ||||
|     .detail-header { | ||||
|       padding: 32px; | ||||
|       background: #fff; | ||||
|  | ||||
|       h2 { | ||||
|         margin-bottom: 32px; | ||||
|         color: #333333; | ||||
|         font-size: 40px; | ||||
|         font-weight: 600; | ||||
|       } | ||||
|  | ||||
|       .item-info { | ||||
|         .item-info__item { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           margin-bottom: 8px; | ||||
|  | ||||
|           &:last-child { | ||||
|             margin-bottom: 0; | ||||
|           } | ||||
|  | ||||
|           image { | ||||
|             width: 32px; | ||||
|             height: 32px; | ||||
|             margin-right: 16px; | ||||
|           } | ||||
|  | ||||
|           span { | ||||
|             color: #333; | ||||
|             font-size: 28px; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .detail-info { | ||||
|       margin-top: 24px; | ||||
|       padding: 0 32px; | ||||
|       background: #fff; | ||||
|  | ||||
|       & > h2 { | ||||
|         height: 116px; | ||||
|         line-height: 116px; | ||||
|         font-size: 38px; | ||||
|         font-weight: 600; | ||||
|         color: #333; | ||||
|       } | ||||
|  | ||||
|       .detail-info__item { | ||||
|         display: flex; | ||||
|         justify-content: space-between; | ||||
|         padding: 34px 0; | ||||
|         border-bottom: 1px solid #DDDDDD; | ||||
|  | ||||
|         &:last-child { | ||||
|           border: none; | ||||
|         } | ||||
|  | ||||
|         .left { | ||||
|           display: flex; | ||||
|           line-height: 1.3; | ||||
|           max-width: 360px; | ||||
|  | ||||
|           label { | ||||
|             position: relative; | ||||
|             color: #999999; | ||||
|             font-size: 32px; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .right { | ||||
|           display: flex; | ||||
|           max-width: 450px; | ||||
|  | ||||
|           span { | ||||
|             color: #333333; | ||||
|             font-size: 32px; | ||||
|             text-align: right; | ||||
|           } | ||||
|  | ||||
|           image { | ||||
|             width: 40px; | ||||
|             height: 40px; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .detail-info__item--img { | ||||
|         display: block; | ||||
|  | ||||
|         .right { | ||||
|           flex-wrap: wrap; | ||||
|           max-width: 100%; | ||||
|           margin-top: 34px; | ||||
|  | ||||
|           image { | ||||
|             width: 226px; | ||||
|             height: 226px; | ||||
|             margin: 0 9px 9px 0; | ||||
|  | ||||
|             &:nth-of-type(3n) { | ||||
|               margin-right: 0; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										116
									
								
								src/mods/conv/AppHealthReport/RecordList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,116 @@ | ||||
| <template> | ||||
|   <div class="record" v-if="pageShow"> | ||||
|     <div class="record-item" v-for="(item, index) in list" :key="index" @click="$linkTo('./Detail?id=' + item.id)" | ||||
|          hover-class="bg-hover"> | ||||
|       <div class="left">{{ item.createTime.split(' ')[0] }}的健康上报</div> | ||||
|       <div class="right"> | ||||
|         <i v-if="item.status === '0'">健康数据异常</i> | ||||
|         <u-icon name="arrow-right" color="#ddd"/> | ||||
|       </div> | ||||
|     </div> | ||||
|     <AiEmpty v-if="!list.length && isMore"/> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   appName: "上报记录", | ||||
|   data() { | ||||
|     return { | ||||
|       list: [], | ||||
|       pageShow: false, | ||||
|       current: 1, | ||||
|       total: 0, | ||||
|       isMore: false | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   onLoad(query) { | ||||
|     this.$loading() | ||||
|     this.getList(query) | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     getList(query) { | ||||
|       if (this.isMore) return | ||||
|  | ||||
|       this.$instance.post(`/app/appepidemichealthreport/list?memberId=${query.id}`, null, { | ||||
|         params: { | ||||
|           current: this.current, | ||||
|           size: 15 | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.total = res.data.total | ||||
|           if (this.current > 1) { | ||||
|             this.list = [...this.list, ...res.data.records] | ||||
|           } else { | ||||
|             this.list = res.data.records | ||||
|           } | ||||
|           uni.hideLoading() | ||||
|           this.pageShow = true | ||||
|           if (res.data.records.length < 15) { | ||||
|             this.isMore = true | ||||
|  | ||||
|             return false | ||||
|           } | ||||
|  | ||||
|           this.current = this.current + 1 | ||||
|         } else { | ||||
|           uni.hideLoading() | ||||
|         } | ||||
|       }).catch(() => { | ||||
|         uni.hideLoading() | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   onReachBottom() { | ||||
|     this.getList() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| .record { | ||||
|   padding: 32px 0; | ||||
|  | ||||
|   .record-item { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     width: 686px; | ||||
|     height: 112px; | ||||
|     margin: 0 auto 24px; | ||||
|     padding: 0 28px 0 32px; | ||||
|     background: #FFFFFF; | ||||
|     box-sizing: border-box; | ||||
|     box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.02); | ||||
|     border-radius: 16px; | ||||
|  | ||||
|     .left { | ||||
|       color: #333333; | ||||
|       font-size: 32px; | ||||
|       font-weight: 600; | ||||
|     } | ||||
|  | ||||
|     .right { | ||||
|       i { | ||||
|         width: 158px; | ||||
|         height: 36px; | ||||
|         line-height: 36px; | ||||
|         margin-right: 8px; | ||||
|         text-align: center; | ||||
|         font-size: 26px; | ||||
|         color: #FF4466; | ||||
|         background: #FFF5F7; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     & > div { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										83
									
								
								src/mods/conv/AppHealthReport/Result.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,83 @@ | ||||
| <template> | ||||
|   <div class="result"> | ||||
|     <image src="/static/img/result.png" /> | ||||
|     <h2>添加成功!</h2> | ||||
|     <div class="result-btn" hover-class="text-hover" @click="toReport">上报今日状态</div> | ||||
|     <div class="result-backBtn" @click="back">返回</div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     data () { | ||||
|       return { | ||||
|         id: '' | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     onLoad (query) { | ||||
|       this.id = query.id | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       back () { | ||||
|         uni.navigateBack({ | ||||
|           delta: 1 | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       toReport () { | ||||
|         uni.redirectTo({ | ||||
|           url: `./AddReport?id=${this.id}` | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   .result { | ||||
|     min-height: 100vh; | ||||
|     padding-top: 160px; | ||||
|     box-sizing: border-box; | ||||
|     text-align: center; | ||||
|     background: #fff; | ||||
|  | ||||
|     image { | ||||
|       width: 220px; | ||||
|       height: 220px; | ||||
|     } | ||||
|  | ||||
|     .result-backBtn { | ||||
|       width: 320px; | ||||
|       height: 88px; | ||||
|       line-height: 88px; | ||||
|       margin: 32px auto 0; | ||||
|       text-align: center; | ||||
|       border: 1px solid #4181FF; | ||||
|       color: #4181FF; | ||||
|       font-size: 34px; | ||||
|       box-sizing: border-box; | ||||
|       border-radius: 16px; | ||||
|     } | ||||
|  | ||||
|     h2 { | ||||
|       margin: 32px 0 80px; | ||||
|       font-weight: 600; | ||||
|       font-size: 40px; | ||||
|       color: #333; | ||||
|     } | ||||
|  | ||||
|     .result-btn { | ||||
|       width: 320px; | ||||
|       height: 88px; | ||||
|       line-height: 88px; | ||||
|       margin: 0 auto; | ||||
|       text-align: center; | ||||
|       background: #4181FF; | ||||
|       color: #fff; | ||||
|       font-size: 34px; | ||||
|       border-radius: 16px; | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										134
									
								
								src/mods/conv/AppHealthReport/UserInfo.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,134 @@ | ||||
| <template> | ||||
|   <div class="userinfo" v-if="pageShow"> | ||||
|     <div class="cell-group"> | ||||
|       <div class="cell-item"> | ||||
|         <div class="cell-item__wrapper"> | ||||
|           <div class="left"> | ||||
|             <span>上报人姓名</span> | ||||
|           </div> | ||||
|           <div class="right"> | ||||
|             <span>{{ info.name }}</span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="cell-item"> | ||||
|         <div class="cell-item__wrapper"> | ||||
|           <div class="left"> | ||||
|             <span>身份证号</span> | ||||
|           </div> | ||||
|           <div class="right"> | ||||
|             <span>{{ info.idNumber }}</span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="cell-item"> | ||||
|         <div class="cell-item__wrapper"> | ||||
|           <div class="left"> | ||||
|             <span>手机号码</span> | ||||
|           </div> | ||||
|           <div class="right"> | ||||
|             <span>{{ info.phone }}</span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="cell-item"> | ||||
|         <div class="cell-item__wrapper"> | ||||
|           <div class="left"> | ||||
|             <span>上报地区</span> | ||||
|           </div> | ||||
|           <div class="right"> | ||||
|             <span>{{ info.areaName }}</span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="cell-item"> | ||||
|         <div class="cell-item__wrapper"> | ||||
|           <div class="left"> | ||||
|             <span>详细地址</span> | ||||
|           </div> | ||||
|           <div class="right"> | ||||
|             <span>{{ info.address }}</span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     appName:"个人信息", | ||||
|     data () { | ||||
|       return { | ||||
|         info: {}, | ||||
|         pageShow: false | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     onLoad (query) { | ||||
|       this.$loading() | ||||
|       this.getInfo(query.id) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getInfo (id) { | ||||
|         this.$instance.post(`/app/appepidemicreportmember/queryDetailById?id=${id}`).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             this.info = res.data | ||||
|             if (res.data.eventStatus > 1) { | ||||
|               this.result = res.data.processList[0] | ||||
|             } | ||||
|             this.$nextTick(() => { | ||||
|               this.pageShow = true | ||||
|             }) | ||||
|           } | ||||
|  | ||||
|           this.$hideLoading() | ||||
|         }).catch(() => { | ||||
|           this.$hideLoading() | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   .userinfo { | ||||
|     .cell-group { | ||||
|       background: #fff; | ||||
|  | ||||
|       .cell-item { | ||||
|         padding-left: 32px; | ||||
|  | ||||
|         .cell-item__wrapper { | ||||
|           display: flex; | ||||
|           justify-content: space-between; | ||||
|           padding: 34px 32px 34px 0; | ||||
|           border-bottom: 1px solid #DDDDDD; | ||||
|  | ||||
|           .left { | ||||
|             span { | ||||
|               color: #999999; | ||||
|               font-size: 32px; | ||||
|             } | ||||
|           } | ||||
|  | ||||
|           .right { | ||||
|             max-width: 450px; | ||||
|             text-align: right; | ||||
|             span { | ||||
|               color: #333333; | ||||
|               font-size: 32px; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         &:last-child { | ||||
|           .cell-item__wrapper { | ||||
|             border-bottom: none; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										216
									
								
								src/mods/conv/AppMarFuneral/AppMarFuneral.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,216 @@ | ||||
| <template> | ||||
|   <div class="wrapper padding" v-if="pageShow"> | ||||
|     <template v-if="list.length"> | ||||
|       <header> | ||||
|         <span>婚丧嫁娶列表</span> | ||||
|         <div class="total"> | ||||
|           共<em>{{ list.length }}</em>条 | ||||
|         </div> | ||||
|       </header> | ||||
|       <div class="card" v-for="item in list" :key="item.id"> | ||||
|         <div class="item"> | ||||
|           <span class="label">事主姓名</span> | ||||
|           <span class="value">{{ item.name }}</span> | ||||
|         </div> | ||||
|         <div class="item"> | ||||
|           <span class="label">联系方式</span> | ||||
|           <span class="value">{{ item.phone }}</span> | ||||
|         </div> | ||||
|         <div class="item"> | ||||
|           <span class="label">上报时间</span> | ||||
|           <span class="value">{{ item.createTime }}</span> | ||||
|         </div> | ||||
|         <div class="item"> | ||||
|           <span class="label">上报地点</span> | ||||
|           <span class="value">{{ item.address }}</span> | ||||
|         </div> | ||||
|         <div class="item" v-if="item.content.trim().length"> | ||||
|           <span class="label">上报内容</span> | ||||
|           <span class="value">{{ item.content || '' }}</span> | ||||
|         </div> | ||||
|         <div class="tag" :style="{backgroundColor:$dict.getColor('marriageType',item.type)}"> | ||||
|           {{ $dict.getLabel('marriageType', item.type) }} | ||||
|         </div> | ||||
|         <u-icon name="more-dot-fill" size="28" color="#999999" :custom-style="customStyle" @click="handleDel(item)" | ||||
|                 v-if="item.openId == userInfo.openId"></u-icon> | ||||
|       </div> | ||||
|     </template> | ||||
|     <AiEmpty v-else/> | ||||
|     <div class="btn-wrapper"> | ||||
|       <div class="btn" @click="suport" hover-class="text-hover">我要上报</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|   name: "AppMarFuneral", | ||||
|   appName: "婚丧嫁娶", | ||||
|   data() { | ||||
|     return { | ||||
|       current: 1, | ||||
|       pageShow: false, | ||||
|       list: [], | ||||
|       userInfo: {}, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     customStyle() { | ||||
|       return { | ||||
|         position: "absolute", | ||||
|         top: "16px", | ||||
|         right: "24px", | ||||
|         transform: "rotate(90deg)" | ||||
|       }; | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   onLoad() { | ||||
|     this.$loading() | ||||
|     this.userInfo = uni.getStorageSync("userInfo"); | ||||
|  | ||||
|     this.$dict.load("marriageType").then(() => { | ||||
|       this.getList() | ||||
|     }) | ||||
|  | ||||
|     uni.$on('update', () => { | ||||
|       this.current = 1 | ||||
|       this.getList() | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     handleDel({id}) { | ||||
|       uni.showModal({ | ||||
|         title: "提示", | ||||
|         content: "是否确定要删除?", | ||||
|         success: ret => { | ||||
|           if (ret.confirm) { | ||||
|             this.$instance.post("/app/appmarriagefuneralinfo/delete", null, { | ||||
|               params: {ids: id} | ||||
|             }).then(res => { | ||||
|               if (res.code == 0) { | ||||
|                 this.$u.toast("删除成功"); | ||||
|                 this.getList(); | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getList() { | ||||
|       this.$instance.post("/app/appmarriagefuneralinfo/list", null, { | ||||
|         params: { | ||||
|           current: this.current, | ||||
|           size: 10, | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.list = this.current > 1 ? [...this.list, ...res.data.records] : res.data.records; | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             this.pageShow = true | ||||
|           }) | ||||
|         } | ||||
|  | ||||
|         this.$hideLoading() | ||||
|       }).catch(() => { | ||||
|         this.$hideLoading() | ||||
|       }) | ||||
|     }, | ||||
|     suport() { | ||||
|       uni.navigateTo({ | ||||
|         url: "./marAdd" | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   onReachBottom() { | ||||
|     this.current++; | ||||
|     this.getList(); | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|  | ||||
| .padding { | ||||
|   box-sizing: border-box; | ||||
|   padding: 48px 32px 156px; | ||||
|  | ||||
|   header { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     margin-bottom: 44px; | ||||
|  | ||||
|     & > span { | ||||
|       font-size: 38px; | ||||
|       font-weight: 600; | ||||
|       color: #333333; | ||||
|     } | ||||
|  | ||||
|     .total { | ||||
|       margin-left: auto; | ||||
|       font-size: 28px; | ||||
|       font-weight: 400; | ||||
|       color: #666666; | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|  | ||||
|       & > em { | ||||
|         color: #4181FF; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .card { | ||||
|     min-height: 308px; | ||||
|     background: #FFFFFF; | ||||
|     box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.02); | ||||
|     border-radius: 16px; | ||||
|     box-sizing: border-box; | ||||
|     padding: 32px; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     justify-content: space-between; | ||||
|     position: relative; | ||||
|     margin-bottom: 24px; | ||||
|  | ||||
|     .item { | ||||
|       display: flex; | ||||
|       margin-bottom: 8px; | ||||
|  | ||||
|       .label { | ||||
|         font-size: 26px; | ||||
|         font-weight: 400; | ||||
|         color: #999999; | ||||
|         flex-shrink: 0; | ||||
|         line-height: 36px; | ||||
|       } | ||||
|  | ||||
|       .value { | ||||
|         font-size: 26px; | ||||
|         font-weight: 400; | ||||
|         color: #333333; | ||||
|         margin-left: 32px; | ||||
|         line-height: 36px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .tag { | ||||
|       width: 70px; | ||||
|       height: 44px; | ||||
|       background: #FF883C; | ||||
|       border-radius: 8px; | ||||
|       font-size: 26px; | ||||
|       line-height: 40px; | ||||
|       font-weight: 400; | ||||
|       color: #FFFFFF; | ||||
|       text-align: center; | ||||
|       margin-top: 24px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										174
									
								
								src/mods/conv/AppMarFuneral/marAdd.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,174 @@ | ||||
| <template> | ||||
|   <div class="wrapper"> | ||||
|     <div class="card"> | ||||
|       <div class="form"> | ||||
|         <em>*</em> | ||||
|         <label>类型</label> | ||||
|         <div class="right" @click="show=true"> | ||||
|           <u-icon name="arrow-right" color="#999999" size="28"></u-icon> | ||||
|           <span class="value" style="color: #999999;font-weight:normal;" v-if="!form.typeName">请选择</span> | ||||
|           <span class="value" style="color: #333333;font-weight:normal;" v-else>{{ form.typeName }}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="card"> | ||||
|       <div class="form border"> | ||||
|         <em>*</em> | ||||
|         <label>事主姓名</label> | ||||
|         <div class="right"> | ||||
|           <u-input trim placeholder="请输入" input-align="right" v-model="form.name" | ||||
|                    placeholder-style="color:#999;font-size: 16px;"></u-input> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form border"> | ||||
|         <em>*</em> | ||||
|         <label>联系方式</label> | ||||
|         <div class="right"> | ||||
|           <u-input trim placeholder="请输入" input-align="right" v-model="form.phone" | ||||
|                    placeholder-style="color:#999;font-size: 16px;" maxlength="11"></u-input> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form"> | ||||
|         <em>*</em> | ||||
|         <label>活动地点</label> | ||||
|         <div class="right"> | ||||
|           <u-input trim placeholder="请输入" input-align="right" v-model="form.address" | ||||
|                    placeholder-style="color:#999;font-size: 16px;" style="flex: 1;margin-left: 16px;"></u-input> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="card"> | ||||
|       <div class="form"> | ||||
|         <em></em> | ||||
|         <label>详细描述</label> | ||||
|       </div> | ||||
|       <u-input type="textarea" trim v-model="form.content" placeholder="请输入详细描述信息…" maxlength="500" | ||||
|                placeholder-style="color: #999999;font-size: 15px;"/> | ||||
|     </div> | ||||
|     <div class="card" style="padding-bottom: 20px"> | ||||
|       <div class="form"> | ||||
|         <label>图片上传 | ||||
|           <span>(最多9张)</span> | ||||
|         </label> | ||||
|       </div> | ||||
|       <AiUploader :limit="9" v-model="form.files"></AiUploader> | ||||
|     </div> | ||||
|     <div class="btn-wrapper"> | ||||
|       <div class="btn" @click="submit" hover-class="text-hover">提交</div> | ||||
|     </div> | ||||
|     <u-select v-model="show" :list="$dict.getDict('marriageType')" value-name="dictValue" | ||||
|               label-name="dictName" @confirm="confirm"></u-select> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|   name: "marAdd", | ||||
|   appName: "我要上报", | ||||
|   data() { | ||||
|     return { | ||||
|       form: { | ||||
|         type: "", | ||||
|         typeName: "", | ||||
|         name: "", | ||||
|         phone: "", | ||||
|         address: "", | ||||
|         content: "", | ||||
|         personType: 0, | ||||
|         files: [], | ||||
|       }, | ||||
|       show: false, | ||||
|       flag: false | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     submit() { | ||||
|       if (!!!this.form.typeName) return this.$u.toast("请选择类型"); | ||||
|       if (!!!this.form.name) return this.$u.toast("请输入事主姓名"); | ||||
|       if (!!!this.form.phone) return this.$u.toast("请输入联系方式"); | ||||
|       if (!!!this.form.address) return this.$u.toast("请输入活动地点"); | ||||
|       if (this.flag) return | ||||
|       this.flag = true | ||||
|       this.$loading() | ||||
|       this.$instance.post("/app/appmarriagefuneralinfo/addOrUpdate", { | ||||
|         ...this.form | ||||
|       }).then(res => { | ||||
|         this.$hideLoading() | ||||
|         this.flag = false | ||||
|         if (res.code == 0) { | ||||
|           uni.$emit('update') | ||||
|           this.$u.toast("提交成功"); | ||||
|           setTimeout(_ => { | ||||
|             uni.navigateBack(); | ||||
|           }, 500) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     confirm(val) { | ||||
|       this.form.type = val[0].value; | ||||
|       this.form.typeName = val[0].label; | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .wrapper { | ||||
|   padding-bottom: 156px; | ||||
| } | ||||
|  | ||||
| .card { | ||||
|   box-sizing: border-box; | ||||
|   padding-left: 32px; | ||||
|   background-color: #fff; | ||||
|   margin-bottom: 24px; | ||||
|  | ||||
|   .form { | ||||
|     height: 112px; | ||||
|     background: #FFFFFF; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|  | ||||
|     & > em { | ||||
|       width: 16px; | ||||
|       height: 44px; | ||||
|       font-weight: 400; | ||||
|       color: #FF4466; | ||||
|       line-height: 54px; | ||||
|       font-style: normal; | ||||
|       margin-right: 8px; | ||||
|     } | ||||
|  | ||||
|     & > label { | ||||
|       font-size: 32px; | ||||
|       font-weight: 500; | ||||
|       color: #666666; | ||||
|  | ||||
|       & > span { | ||||
|         font-size: 28px; | ||||
|         font-weight: 400; | ||||
|         color: #999999; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .right { | ||||
|       flex: 1; | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       flex-direction: row-reverse; | ||||
|       margin-right: 32px; | ||||
|  | ||||
|       .value { | ||||
|         font-size: 34px; | ||||
|         font-weight: 600; | ||||
|         color: #333333; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .border { | ||||
|     border-bottom: 1px solid #DDDDDD; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										385
									
								
								src/mods/conv/AppPhotoAlbum/AppPhotoAlbum.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,385 @@ | ||||
| <template> | ||||
|   <div class="photo" v-if="pageShow"> | ||||
|     <div class="header" :class="[isFixed ? 'header-active' : '']"> | ||||
|       <div class="status-bar" :style="{height: statusBarHeight + 'px'}"></div> | ||||
|       <div class="nav-bar"> | ||||
|         <image src="/static/img/left.png" @click="back"/> | ||||
|         <h2>乡村相册</h2> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="back-wrapper" @click="back" v-show="!isFixed" :style="{marginTop : statusBarHeight + 'px'}"> | ||||
|       <image src="/static/img/left.png"/> | ||||
|     </div> | ||||
|     <div class="photo-header"> | ||||
|       <image :src="coverImg" mode="aspectFill"/> | ||||
|       <h2>{{ name }}</h2> | ||||
|     </div> | ||||
|     <div class="photo-info"> | ||||
|       <div class="photo-info__item"> | ||||
|         <h2>{{ info.total }}</h2> | ||||
|         <span>照片</span> | ||||
|       </div> | ||||
|       <div class="photo-info__item"> | ||||
|         <h2>{{ info.thisMonth }}</h2> | ||||
|         <span>本月</span> | ||||
|       </div> | ||||
|       <div class="photo-info__item"> | ||||
|         <h2>{{ info.lastMonth }}</h2> | ||||
|         <span>上月</span> | ||||
|       </div> | ||||
|       <div class="photo-info__item"> | ||||
|         <h2>{{ info.thisYear }}</h2> | ||||
|         <span>今年</span> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="photo-list"> | ||||
|       <div class="photo-group" v-for="(group, index) in list" :key="index"> | ||||
|         <h2>{{ group.name }}</h2> | ||||
|         <div class="photo-wrapper"> | ||||
|           <div class="photo-item" v-for="(item, i) in group.list" :key="i"> | ||||
|             <image :src="item.url" @click="preview(item.url)" mode="aspectFill"/> | ||||
|             <div class="photo-item__text"> | ||||
|               <span>{{ item.createUserName }} 上传</span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <AiEmpty v-if="!list.length" description="暂无照片"></AiEmpty> | ||||
|     </div> | ||||
|     <!-- <div class="btn-wrapper"> | ||||
|       <div class="btn" @click="upload" hover-class="text-hover">上传图片</div> | ||||
|     </div> --> | ||||
|     <AiLogin ref="login"/> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: "AppPhotoAlbum", | ||||
|   appName: "乡村相册", | ||||
|   customNavigation: true, | ||||
|   data() { | ||||
|     return { | ||||
|       isFixed: false, | ||||
|       statusBarHeight: 20, | ||||
|       list: [], | ||||
|       type: '', | ||||
|       info: {}, | ||||
|       name: '', | ||||
|       coverImg: '', | ||||
|       imgList: [], | ||||
|       hideStatus: false, | ||||
|       pageShow: false | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapState(['user', 'token']) | ||||
|   }, | ||||
|  | ||||
|   onLoad(query) { | ||||
|     this.type = query.type | ||||
|     this.name = query.name | ||||
|     this.coverImg = query.url | ||||
|     this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight | ||||
|  | ||||
|     this.$loading() | ||||
|     this.getList(query.type) | ||||
|     this.getTotalInfo(query.type) | ||||
|   }, | ||||
|  | ||||
|   onUnload() { | ||||
|     // uni.$off('update') | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     back() { | ||||
|       uni.navigateBack({ | ||||
|         delta: 1 | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     preview(url) { | ||||
|       let imgs = [] | ||||
|       this.list.forEach(item => { | ||||
|         imgs = [...imgs, ...item.list.map(v => v.url)] | ||||
|       }) | ||||
|  | ||||
|       uni.previewImage({ | ||||
|         urls: imgs, | ||||
|         current: url | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     upload() { | ||||
|       if (!this.token) { | ||||
|         this.$refs.login.show() | ||||
|  | ||||
|         return false | ||||
|       } | ||||
|  | ||||
|       this.imgList = [] | ||||
|       this.hideStatus = false | ||||
|       uni.chooseImage({ | ||||
|         count: this.limit, | ||||
|         sizeType: ['compressed'], | ||||
|         sourceType: ['album', 'camera'], | ||||
|         success: (res) => { | ||||
|           if (res.tempFilePaths.length > 9) { | ||||
|             this.$toast(`图片不能超过9张`) | ||||
|  | ||||
|             return false | ||||
|           } | ||||
|  | ||||
|           this.$loading('上传中') | ||||
|           res.tempFilePaths.forEach((item, index) => { | ||||
|             if (index === res.tempFilePaths.length - 1) { | ||||
|               this.hideStatus = true | ||||
|             } | ||||
|  | ||||
|             this.$nextTick(() => { | ||||
|               this.uploadFile(item, res.tempFilePaths.length) | ||||
|             }) | ||||
|           }) | ||||
|         }, | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     uploadFile(img, total) { | ||||
|       uni.uploadFile({ | ||||
|         url: this.$instance.defaults.baseURL + '/admin/file/add', | ||||
|         filePath: img, | ||||
|         name: 'file', | ||||
|         header: { | ||||
|           'Content-Type': 'multipart/form-data', | ||||
|           Authorization: uni.getStorageSync('token'), | ||||
|         }, | ||||
|         success: (res) => { | ||||
|           const data = JSON.parse(res.data) | ||||
|  | ||||
|           if (data.code === 0) { | ||||
|             this.imgList.push(data.data[0].split(';')[0]) | ||||
|           } else { | ||||
|             this.$toast(data.msg) | ||||
|           } | ||||
|         }, | ||||
|         complete: () => { | ||||
|           this.$nextTick(() => { | ||||
|             if (this.imgList.length === total && this.hideStatus) { | ||||
|               this.$instance.post(`/app/appvillagepicturealbum/addPictures`, { | ||||
|                 areaName: uni.getStorageSync('areaName'), | ||||
|                 areaId: uni.getStorageSync('areaId'), | ||||
|                 type: this.type, | ||||
|                 urlList: this.imgList | ||||
|               }).then(res => { | ||||
|                 if (res.code == 0) { | ||||
|                   this.getList(this.type) | ||||
|                   this.getTotalInfo(this.type) | ||||
|                   uni.$emit('update') | ||||
|                 } | ||||
|                 this.$hideLoading() | ||||
|                 this.hideStatus = false | ||||
|               }) | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     getTotalInfo(type) { | ||||
|       this.$instance.post(`/app/appvillagepicturealbum/statistic?areaId=${uni.getStorageSync('areaId')}&type=${type}`).then(res => { | ||||
|         if (res.code === 0) { | ||||
|           this.info = res.data | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     getList(type) { | ||||
|       this.$instance.post(`/app/appvillagepicturealbum/queryAlbum?areaId=${uni.getStorageSync('areaId')}&type=${type}`).then(res => { | ||||
|         if (res.code === 0) { | ||||
|           this.list = Object.keys(res.data).map(v => { | ||||
|             return { | ||||
|               name: v, | ||||
|               list: res.data[v] | ||||
|             } | ||||
|           }) | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             this.pageShow = true | ||||
|           }) | ||||
|         } | ||||
|  | ||||
|         this.$hideLoading() | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   onPageScroll(params) { | ||||
|     this.isFixed = params.scrollTop > 60; | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .photo { | ||||
|   width: 100vw; | ||||
|   overflow-x: hidden; | ||||
|   padding-bottom: 130px; | ||||
|  | ||||
|   * { | ||||
|     box-sizing: border-box; | ||||
|   } | ||||
|  | ||||
|   .back-wrapper { | ||||
|     position: fixed; | ||||
|     z-index: 11; | ||||
|     left: 20px; | ||||
|     top: 24px; | ||||
|     width: 40px; | ||||
|     height: 40px; | ||||
|  | ||||
|     image { | ||||
|       width: 40px; | ||||
|       height: 40px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .header { | ||||
|     position: fixed; | ||||
|     left: 0; | ||||
|     top: 0; | ||||
|     z-index: 0; | ||||
|     width: 100%; | ||||
|     opacity: 0; | ||||
|     transition: all 0.2s ease; | ||||
|  | ||||
|     &.header-active { | ||||
|       z-index: 1111; | ||||
|       opacity: 1; | ||||
|       background: linear-gradient(180deg, #4670F5 0%, #4772F5 100%); | ||||
|     } | ||||
|  | ||||
|     .nav-bar { | ||||
|       position: relative; | ||||
|       height: 88px; | ||||
|       line-height: 88px; | ||||
|       color: #fff; | ||||
|       font-size: 32px; | ||||
|       text-align: center; | ||||
|  | ||||
|       image { | ||||
|         position: absolute; | ||||
|         top: 0; | ||||
|         left: 0; | ||||
|         z-index: 1; | ||||
|         width: 40px; | ||||
|         height: 40px; | ||||
|         padding: 24px 20px 0 20px; | ||||
|         box-sizing: content-box; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .photo-header { | ||||
|     position: relative; | ||||
|     height: 400px; | ||||
|  | ||||
|     image { | ||||
|       width: 100%; | ||||
|       height: 400px; | ||||
|       filter: blur(2px); | ||||
|     } | ||||
|  | ||||
|     h2 { | ||||
|       display: flex; | ||||
|       position: absolute; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       top: 0; | ||||
|       left: 0; | ||||
|       width: 100%; | ||||
|       height: 100%; | ||||
|       z-index: 1; | ||||
|       color: #fff; | ||||
|       background: rgba(0, 0, 0, 0.1); | ||||
|       font-size: 56px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .photo-info { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     height: 168px; | ||||
|     background: #FFFFFF; | ||||
|     box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02); | ||||
|  | ||||
|     & > div { | ||||
|       flex: 1; | ||||
|       text-align: center; | ||||
|  | ||||
|       h2 { | ||||
|         margin-bottom: 10px; | ||||
|         font-weight: 600; | ||||
|         font-size: 38px; | ||||
|         color: #333333; | ||||
|       } | ||||
|  | ||||
|       span { | ||||
|         color: #999999; | ||||
|         font-size: 26px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .photo-list { | ||||
|     margin-top: 32px; | ||||
|     padding: 0 32px; | ||||
|  | ||||
|     h2 { | ||||
|       margin-bottom: 32px; | ||||
|       color: #333333; | ||||
|       font-size: 38px; | ||||
|     } | ||||
|  | ||||
|     .photo-wrapper { | ||||
|       display: flex; | ||||
|       flex-wrap: wrap; | ||||
|  | ||||
|       .photo-item { | ||||
|         position: relative; | ||||
|         width: 328px; | ||||
|         height: 328px; | ||||
|         margin-right: 30px; | ||||
|         margin-bottom: 32px; | ||||
|         border-radius: 12px; | ||||
|         overflow: hidden; | ||||
|  | ||||
|         &:nth-of-type(2n) { | ||||
|           margin-right: 0; | ||||
|         } | ||||
|  | ||||
|         .photo-item__text { | ||||
|           position: absolute; | ||||
|           bottom: 0; | ||||
|           left: 0; | ||||
|           z-index: 1; | ||||
|           width: 100%; | ||||
|           height: 80px; | ||||
|           line-height: 80px; | ||||
|           padding: 0 16px; | ||||
|           color: #FFFFFF; | ||||
|           font-size: 26px; | ||||
|           background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.5) 100%); | ||||
|         } | ||||
|  | ||||
|         image { | ||||
|           width: 328px; | ||||
|           height: 328px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										215
									
								
								src/mods/conv/AppPhotoReport/AppPhotoReport.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,215 @@ | ||||
| <template> | ||||
|   <div class="photo-list"> | ||||
|     <div class="photo-list__wrapper"> | ||||
|  | ||||
|       <div class="photo-item" v-for="(item, index) in list" :key="index"> | ||||
|         <u-swipe-action @content-click="$linkTo('./PhotoDetail?id=' + item.id)" :index="item.id" | ||||
|                         :options="itemOptions" @click="handleDelete"> | ||||
|           <div class="photo-item__top"> | ||||
|             <h2>{{ item.content }}</h2> | ||||
|             <div class="photo-item__top--info"> | ||||
|               <div class="photo-item__top--info-item"> | ||||
|                 <label>事件类型</label> | ||||
|                 <span>{{ item.groupName }}</span> | ||||
|               </div> | ||||
|               <div class="photo-item__top--info-item"> | ||||
|                 <label>所属网格</label> | ||||
|                 <span>{{ item.girdName }}</span> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="photo-item__bottom flex"> | ||||
|             <div class="flex fill"> | ||||
|               <i :class="'status-' + item.eventStatus"></i> | ||||
|               <span :class="'status-' + item.eventStatus">{{ item.statusName }}</span> | ||||
|             </div> | ||||
|             <AiEvaluation :bid="item.id" v-if="item.eventStatus>1"> | ||||
|               <div class="itemBtn">去评价</div> | ||||
|               <div slot="finish" class="finish">已评价</div> | ||||
|             </AiEvaluation> | ||||
|           </div> | ||||
|         </u-swipe-action> | ||||
|       </div> | ||||
|       <AiEmpty v-if="!list.length"/> | ||||
|     </div> | ||||
|     <div class="btn-wrapper"> | ||||
|       <div class="btn" @click="toReport" hover-class="text-hover">我要上报</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: "AppPhotoReport", | ||||
|   appName: "随手拍", | ||||
|   data() { | ||||
|     return { | ||||
|       list: [], | ||||
|       current: 1, | ||||
|       total: 0, | ||||
|       itemOptions: [ | ||||
|         {text: '删除', style: {backgroundColor: '#f46'}} | ||||
|       ] | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapState(['user']) | ||||
|   }, | ||||
|  | ||||
|   onShow() { | ||||
|     this.current = 1 | ||||
|     this.getList() | ||||
|   }, | ||||
|   onLoad() { | ||||
|     this.$dict.load(['clapEventStatus']) | ||||
|   }, | ||||
|   methods: { | ||||
|     toReport() { | ||||
|       this.$linkTo('./PhotoForm') | ||||
|     }, | ||||
|     getList() { | ||||
|       if (this.current == 1) { | ||||
|         //当current=1时,意味着重新刷新数据 | ||||
|       } else if (this.list.length >= this.total && this.total > 0) { | ||||
|         return //当数据总量和列表总量一样时,不用再加载数据 | ||||
|       } | ||||
|       this.$loading() | ||||
|       this.$instance.post(`/app/appclapeventinfo/listByWxApplet`, null, { | ||||
|         params: { | ||||
|           current: this.current, size: 15 | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           const list = res.data.records.map(v => ({...v, statusName: this.$dict.getLabel('clapEventStatus', v.eventStatus)})) | ||||
|           this.list = this.current == 1 ? list : [this.list, list].flat() | ||||
|           this.total = res.data.total | ||||
|           this.current++ | ||||
|         } | ||||
|       }).finally(() => uni.hideLoading()) | ||||
|     }, | ||||
|     handleDelete(ids) { | ||||
|       this.$dialog.confirm({content: "是否要进行删除?"}).then(() => { | ||||
|         this.$instance.post("/app/appclapeventinfo/delete", null, { | ||||
|           params: {ids} | ||||
|         }).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.$u.toast("删除成功!") | ||||
|             this.current = 1 | ||||
|             this.getList() | ||||
|           } | ||||
|         }) | ||||
|       }).catch(() => 0) | ||||
|     } | ||||
|   }, | ||||
|   onReachBottom() { | ||||
|     this.getList() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| .photo-list { | ||||
|   padding: 24px 0 150px 0; | ||||
|  | ||||
|   .photo-item { | ||||
|     width: 686px; | ||||
|     margin: 0 32px 24px; | ||||
|     background: #FFFFFF; | ||||
|     box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.02); | ||||
|     border-radius: 16px; | ||||
|     overflow: hidden; | ||||
|  | ||||
|     .photo-item__top { | ||||
|       padding: 32px; | ||||
|       text-align: justify; | ||||
|  | ||||
|       h2 { | ||||
|         margin-bottom: 32px; | ||||
|         line-height: 1.4; | ||||
|         color: #333333; | ||||
|         font-size: 32px; | ||||
|         font-weight: 600; | ||||
|         overflow: hidden; | ||||
|         text-overflow: ellipsis; | ||||
|         display: -webkit-box; | ||||
|         -webkit-line-clamp: 2; | ||||
|         -webkit-box-orient: vertical; | ||||
|       } | ||||
|  | ||||
|       .photo-item__top--info-item { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|  | ||||
|         &:last-child { | ||||
|           margin-bottom: 8px; | ||||
|         } | ||||
|  | ||||
|         label { | ||||
|           margin-right: 32px; | ||||
|           color: #999999; | ||||
|           font-size: 26px; | ||||
|         } | ||||
|  | ||||
|         span { | ||||
|           color: #333333; | ||||
|           font-size: 26px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .photo-item__bottom { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       height: 104px; | ||||
|       padding: 0 32px; | ||||
|       border-top: 1px solid #DDDDDD; | ||||
|  | ||||
|       i { | ||||
|         width: 8px; | ||||
|         height: 8px; | ||||
|         margin-right: 8px; | ||||
|         border-radius: 50%; | ||||
|         background: #FF883C; | ||||
|       } | ||||
|  | ||||
|       .itemBtn { | ||||
|         border: 1px solid #4181FF; | ||||
|         border-radius: 8px; | ||||
|         color: #4181FF; | ||||
|         padding: 8px 22px; | ||||
|  | ||||
|  | ||||
|       } | ||||
|  | ||||
|       .finish { | ||||
|         color: #42D784; | ||||
|         font-size: 28px; | ||||
|       } | ||||
|  | ||||
|       span { | ||||
|         color: #FF883C; | ||||
|         font-size: 28px; | ||||
|         background: transparent !important; | ||||
|       } | ||||
|  | ||||
|       .status-1 { | ||||
|         color: #1AAAFF; | ||||
|         background: #1AAAFF; | ||||
|       } | ||||
|  | ||||
|       .status-2 { | ||||
|         color: #42D784; | ||||
|         background: #42D784; | ||||
|       } | ||||
|  | ||||
|       .status-3 { | ||||
|         color: #FF4466; | ||||
|         background: #FF4466; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										181
									
								
								src/mods/conv/AppPhotoReport/PhotoDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,181 @@ | ||||
| <template> | ||||
|   <div class="photo-detail"> | ||||
|     <AiGroup noBorder> | ||||
|       <h2>{{ info.content }}</h2> | ||||
|       <div class="status-name" :class="detailStatus.cls" v-text="detailStatus.label"/> | ||||
|     </AiGroup> | ||||
|     <AiGroup description noBorder labelColor="#999"> | ||||
|       <AiItem label="事件类型" :value="info.groupName"/> | ||||
|       <AiItem label="所属网格" :value="info.girdName"/> | ||||
|       <AiItem label="上报时间" :value="info.createTime"/> | ||||
|       <AiItem label="照片" top-label> | ||||
|         <div class="flex wrap"> | ||||
|           <image class="fill imageItem" v-for="(item, index) in info.files" @click="preview(item.url)" :key="index" :src="item.url"/> | ||||
|         </div> | ||||
|         <span v-if="!hasFiles">暂无照片</span> | ||||
|       </AiItem> | ||||
|     </AiGroup> | ||||
|     <u-gap height="24"/> | ||||
|     <AiGroup title="处理详情" v-if="info.eventStatus > 1" description noBorder labelColor="#999"> | ||||
|       <AiItem label="处理结果" top-label :value="result.doExplain"/> | ||||
|       <AiItem label="照片" top-label> | ||||
|         <div class="flex wrap"> | ||||
|           <image class="fill imageItem" v-for="(item, index) in result.files" @click="preview(item.url)" :key="index" :src="item.url"/> | ||||
|         </div> | ||||
|         <span v-if="!hasFiles">暂无照片</span> | ||||
|       </AiItem> | ||||
|     </AiGroup> | ||||
|     <u-gap height="24"/> | ||||
|     <u-tabs :list="evaluation && evaluation.id ? [{name:'办理进度'},{name:'我的评价'}] : [{name:'办理进度'}] " :current="currentTab" @change="v=>currentTab=v"/> | ||||
|     <u-gap height="24"/> | ||||
|     <AiGroup noBorder v-if="currentTab=='0'"> | ||||
|       <AiStep v-for="(item,i) in process" :key="item.id" :index="i"> | ||||
|         <div class="flex start"> | ||||
|           <div class="fill stepTitle" v-text="item.systemExplain"/> | ||||
|           <div class="color-999 mar-r32 stepTime" v-text="item.doTime"/> | ||||
|         </div> | ||||
|         <div v-if="item.doExplain" class="stepContent mar-t8" v-text="item.doExplain"/> | ||||
|         <u-gap height="48"/> | ||||
|       </AiStep> | ||||
|     </AiGroup> | ||||
|     <AiEvaluation v-if="currentTab=='1'" :bid="info.id" type="show"/> | ||||
|     <AiEvaluation v-if="info.eventStatus > 1" v-model="evaluation" class="fixed-bottom bg-fff" :bid="info.id"> | ||||
|       <div class="bottomBtn">去评价</div> | ||||
|     </AiEvaluation> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   appName: "随手拍详情", | ||||
|   data() { | ||||
|     return { | ||||
|       info: {}, | ||||
|       result: {}, | ||||
|       currentTab: 0, | ||||
|       evaluation: {} | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     detailStatus: v => { | ||||
|       const status = !v.evaluation.id ? v.info.eventStatus : 'evaluation' | ||||
|       return { | ||||
|         cls: 'status-' + status, | ||||
|         label: !v.evaluation.id ? v.$dict.getLabel('clapEventStatus', v.info.eventStatus) : "已评价" | ||||
|       } | ||||
|     }, | ||||
|     process() { | ||||
|       const list = this.info.processList | ||||
|       if (this.evaluation.id) { | ||||
|         const {id, createUserName, score, createTime: doTime, rateText: doExplain} = this.evaluation | ||||
|         list.splice(0, 0, { | ||||
|           id, doTime, doExplain, | ||||
|           systemExplain: `${createUserName}完成评价 (${score}星评价)` | ||||
|         }) | ||||
|       } | ||||
|       return list | ||||
|     }, | ||||
|     hasFiles:v=>v.result.files?.length>0 | ||||
|   }, | ||||
|   onShow() { | ||||
|     this.getInfo() | ||||
|   }, | ||||
|   onLoad(query) { | ||||
|     this.getInfo(query.id) | ||||
|     this.$dict.load(['clapEventStatus']) | ||||
|   }, | ||||
|   methods: { | ||||
|     getInfo(id = this.info.id) { | ||||
|       this.$loading() | ||||
|       this.$instance.post(`/app/appclapeventinfo/queryDetailById?id=${id}`).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.info = res.data | ||||
|           if (res.data.eventStatus > 1) { | ||||
|             this.result = res.data.processList[0] | ||||
|           } | ||||
|         } | ||||
|       }).finally(() => this.$hideLoading()) | ||||
|     }, | ||||
|     previewResult(url) { | ||||
|       uni.previewImage({ | ||||
|         urls: this.result.files.map(v => v.url), | ||||
|         current: url | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     preview(url) { | ||||
|       uni.previewImage({ | ||||
|         urls: this.info.files.map(v => v.url), | ||||
|         current: url | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| .photo-detail { | ||||
|   padding: 32px 0 160px; | ||||
|   margin-bottom: 60px; | ||||
|   background: #fff; | ||||
|  | ||||
|   h2 { | ||||
|     line-height: 1.3; | ||||
|     margin-bottom: 26px; | ||||
|     color: #333333; | ||||
|     text-align: justify; | ||||
|     font-size: 40px; | ||||
|   } | ||||
|  | ||||
|   ::v-deep.stepTitle { | ||||
|     min-height: 44px; | ||||
|     font-family: PingFangSC-Regular; | ||||
|     font-weight: 400; | ||||
|     font-size: 32px; | ||||
|   } | ||||
|  | ||||
|   .stepTime { | ||||
|     line-height: 44px; | ||||
|   } | ||||
|  | ||||
|   .stepContent { | ||||
|     color: #343D65; | ||||
|   } | ||||
|  | ||||
|   .status-name { | ||||
|     width: 96px; | ||||
|     height: 44px; | ||||
|     line-height: 44px; | ||||
|     margin-bottom: 20px; | ||||
|     text-align: center; | ||||
|     background: #FF883C; | ||||
|     color: #fff; | ||||
|     font-size: 26px; | ||||
|     border-radius: 8px; | ||||
|  | ||||
|     &.status-1, &.status-evaluation { | ||||
|       background: #1AAAFF; | ||||
|     } | ||||
|  | ||||
|     &.status-2 { | ||||
|       background: #42D784; | ||||
|     } | ||||
|  | ||||
|     &.status-3 { | ||||
|       background: #FF4466; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .imageItem { | ||||
|     min-width: 30%; | ||||
|     height: 30vw; | ||||
|     flex-shrink: 0; | ||||
|     margin-right: 16px; | ||||
|     margin-bottom: 16px; | ||||
|  | ||||
|     &:nth-of-type(3n) { | ||||
|       margin-right: 0; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										347
									
								
								src/mods/conv/AppPhotoReport/PhotoForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,347 @@ | ||||
| <template> | ||||
|   <div class="album"> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>事件类型</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiSelect :list="dictList" v-model="form.groupId" placeholder="请选择"></AiSelect> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__textarea"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>事件描述</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <textarea v-model="form.content" :maxlength="500" placeholder="请简要描述事件…"></textarea> | ||||
|             <!-- <u-input style="width: 100%;" :height="200" v-model="value" type="textarea" :maxlength="500" :border="border" placeholder="请简要描述事件…" /> --> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>上报位置</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right" @click="chooseAddress"> | ||||
|             <span v-if="form.address">{{ form.address }}</span> | ||||
|             <i v-else>请选择</i> | ||||
|             <u-icon name="arrow-right" color="#ddd"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>所属网格</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiPagePicker type="gird" v-model="form.girdId" :params="{formType:2}" @select="handleSelectGrid" nodeKey="id"> | ||||
|               <AiMore v-model="form.girdName"/> | ||||
|             </AiPagePicker> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item form-item__imgs"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i style="opacity: 0;">*</i> | ||||
|             <h2>图片上传</h2> | ||||
|             <span>(最多9张)</span> | ||||
|           </div> | ||||
|           <AiUploader v-model="form.files" :limit="9"></AiUploader> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>姓名</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" v-model="form.name" :maxlength="20"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>联系方式</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" v-model="form.phone" :maxlength="11"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="btn-wrapper"> | ||||
|       <div class="btn" hover-class="text-hover" @click="submit">提交</div> | ||||
|     </div> | ||||
|     <AiLogin ref="login" @success="getAuth()"/> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapActions, mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   appName: "上报随手拍", | ||||
|   data() { | ||||
|     return { | ||||
|       form: { | ||||
|         content: '', | ||||
|         lat: '', | ||||
|         lng: '', | ||||
|         address: '', | ||||
|         name: '', | ||||
|         phone: '', | ||||
|         groupId: '', | ||||
|         groupName: '', | ||||
|         girdName: '', | ||||
|         girdId: '', | ||||
|         files: [] | ||||
|       }, | ||||
|       dictList: [], | ||||
|       flag: false | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapState(['user', 'token']) | ||||
|   }, | ||||
|  | ||||
|   onLoad() { | ||||
|     this.getDict() | ||||
|     this.form.phone = this.user.phone | ||||
|     this.form.name = this.user.realName || '' | ||||
|     if (!this.token) { | ||||
|       this.$refs.login.show(); | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions(['getUserInfo']), | ||||
|     chooseAddress() { | ||||
|       uni.authorize({ | ||||
|         scope: 'scope.userLocation', | ||||
|         success: () => { | ||||
|           uni.chooseLocation({ | ||||
|             success: res => { | ||||
|             console.log(res)   | ||||
|               this.form.address = res.name | ||||
|               this.form.lat = res.latitude | ||||
|               this.form.lng = res.longitude | ||||
|             } | ||||
|           }) | ||||
|         }, | ||||
|         fail: () => { | ||||
|           this.$dialog.confirm({ | ||||
|             content: '您未授权定位权限,无法选择位置' | ||||
|           }).then(() => { | ||||
|             wx.openSetting({ | ||||
|               success: res => { | ||||
|                 if (!res.authSetting['scope.userLocation']) { | ||||
|                   this.$dialog.alert({ | ||||
|                     content: '您未授权定位权限,无法选择位置' | ||||
|                   }).then(() => { | ||||
|                   }) | ||||
|                 } else { | ||||
|                   console.log('设置定位权限') | ||||
|                 } | ||||
|               } | ||||
|             }) | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getDict() { | ||||
|       this.$instance.post(`/app/appclapeventgroup/list?current=1&size=100000`, null, { | ||||
|         withoutToken: true, | ||||
|       }).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.dictList = res.data.records.map(v => { | ||||
|             return { | ||||
|               value: v.id, | ||||
|               label: v.groupName | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     submit() { | ||||
|       if (!this.token) { | ||||
|         return this.$refs.login.show(); | ||||
|       } | ||||
|       if (!this.form.groupId) { | ||||
|         return this.$toast('请选择事件类型') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.content) { | ||||
|         return this.$toast('请输入事件描述') | ||||
|       } | ||||
|       if (!this.form.address) { | ||||
|         return this.$toast('请选择上报位置') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.name) { | ||||
|         return this.$toast('请输入上报人姓名') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.phone) { | ||||
|         return this.$toast('请输入上报人联系方式') | ||||
|       } | ||||
|       if (!this.form.girdId) { | ||||
|         return this.$toast('请选择所属网格') | ||||
|       } | ||||
|       if (this.flag) return | ||||
|       this.flag = true | ||||
|  | ||||
|       this.$loading() | ||||
|       this.$instance.post(`/app/appclapeventinfo/addOrUpdate`, { | ||||
|         ...this.form, | ||||
|         openid: this.user.openid, | ||||
|         portrait: this.user.avatarUrl, | ||||
|         files: this.form.files, | ||||
|         groupName: this.dictList.filter(v => v.value === this.form.groupId)[0].label | ||||
|       }).then(res => { | ||||
|         this.$hideLoading() | ||||
|         this.flag = false | ||||
|         if (res.code == 0) { | ||||
|           uni.$emit('update') | ||||
|           setTimeout(() => { | ||||
|             uni.redirectTo({ | ||||
|               url: './PhotoResult?id=' + res.data.id | ||||
|             }) | ||||
|           }, 400) | ||||
|         } | ||||
|         this.$hideLoading() | ||||
|       }) | ||||
|     }, | ||||
|     handleSelectGrid(v) { | ||||
|       this.form.girdName = v.girdName | ||||
|     }, | ||||
|     getAuth() { | ||||
|       this.$nextTick(() => { | ||||
|         this.token && this.getUserInfo().then(() => { | ||||
|           this.getDict() | ||||
|         }) | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| .album { | ||||
|   padding-bottom: 140px; | ||||
|  | ||||
|   .form-item__group { | ||||
|     margin-bottom: 24px; | ||||
|     background: #fff; | ||||
|   } | ||||
|  | ||||
|   .form-item { | ||||
|     padding-left: 32px; | ||||
|  | ||||
|     .form-item__wrapper { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: space-between; | ||||
|       height: 128px; | ||||
|       padding-right: 28px; | ||||
|       border-bottom: 1px solid #DDDDDD; | ||||
|  | ||||
|       input { | ||||
|         flex: 1; | ||||
|         height: 100%; | ||||
|         text-align: right; | ||||
|         padding-right: 10px; | ||||
|       } | ||||
|  | ||||
|       .form-item__right { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         font-size: 32px; | ||||
|  | ||||
|         span { | ||||
|           max-width: 400px; | ||||
|           margin-right: 8px; | ||||
|           color: #333333; | ||||
|           overflow: hidden; | ||||
|           white-space: nowrap; | ||||
|           text-overflow: ellipsis; | ||||
|         } | ||||
|  | ||||
|         i { | ||||
|           margin-right: 8px; | ||||
|           color: #999999; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     &:last-child { | ||||
|       .form-item__wrapper { | ||||
|         border-bottom: none; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .form-item__title { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|  | ||||
|       i { | ||||
|         font-size: 32px; | ||||
|         color: #FF4466; | ||||
|       } | ||||
|  | ||||
|       span { | ||||
|         font-size: 28px; | ||||
|         color: #999999; | ||||
|       } | ||||
|  | ||||
|       h2 { | ||||
|         padding: 0 4px; | ||||
|         font-weight: 600; | ||||
|         font-size: 32px; | ||||
|         color: #333333; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     &.form-item__imgs, &.form-item__textarea { | ||||
|       .form-item__wrapper { | ||||
|         display: block; | ||||
|         height: auto; | ||||
|         padding-bottom: 32px; | ||||
|       } | ||||
|  | ||||
|       textarea { | ||||
|         width: 100%; | ||||
|         height: 160px; | ||||
|       } | ||||
|  | ||||
|       .form-item__title { | ||||
|         padding: 32px 0; | ||||
|       } | ||||
|  | ||||
|       .form-item__right { | ||||
|         padding-left: 18px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										64
									
								
								src/mods/conv/AppPhotoReport/PhotoResult.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,64 @@ | ||||
| <template> | ||||
|   <div class="result"> | ||||
|     <image src="/static/img/result.png" /> | ||||
|     <h2>上报成功!</h2> | ||||
|     <div class="result-btn" hover-class="text-hover" @click="back">前往查看</div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     appName:"上报随手拍", | ||||
|     data () { | ||||
|       return { | ||||
|         id: '' | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     onLoad (query) { | ||||
|       this.id = query.id | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       back () { | ||||
|         uni.redirectTo({ | ||||
|           url: './PhotoDetail?id=' + this.id | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   .result { | ||||
|     min-height: 100vh; | ||||
|     padding-top: 160px; | ||||
|     box-sizing: border-box; | ||||
|     text-align: center; | ||||
|     background: #fff; | ||||
|  | ||||
|     image { | ||||
|       width: 220px; | ||||
|       height: 220px; | ||||
|     } | ||||
|  | ||||
|     h2 { | ||||
|       margin: 32px 0 80px; | ||||
|       font-weight: 600; | ||||
|       font-size: 40px; | ||||
|       color: #333; | ||||
|     } | ||||
|  | ||||
|     .result-btn { | ||||
|       width: 320px; | ||||
|       height: 88px; | ||||
|       line-height: 88px; | ||||
|       margin: 0 auto; | ||||
|       text-align: center; | ||||
|       background: #4181FF; | ||||
|       color: #fff; | ||||
|       font-size: 34px; | ||||
|       border-radius: 16px; | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										424
									
								
								src/mods/conv/AppResidentAssistant/AppResidentAssistant.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,424 @@ | ||||
| <template> | ||||
|   <div class="AppResidentAssistant"> | ||||
|     <u-navbar title="村长Copilot" title-color="#000" title-width="300" title-size="32" :title-bold="true" :background="backgroundNavbar"></u-navbar> | ||||
|     <div class="service-content"> | ||||
|       <div class="text-content"> | ||||
|         <div class="text-left"> | ||||
|           <div>嘿,你好呀!</div> | ||||
|           <p>我是您的<span>「专属助手」</span>,</p> | ||||
|           <p>有什么问题都可以问我哟~</p> | ||||
|         </div> | ||||
|         <img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/service.png" alt="" class="service-img"> | ||||
|       </div> | ||||
|     </div> | ||||
|     <!-- <scroll-view scroll-y="true" class="scroll-Y" @scroll="scroll"> --> | ||||
|       <div class="list-content"> | ||||
|         <div :class="item.userType == 1 ? 'item-left' : 'item-right'" v-for="(item, index) in messageList" :key="index"> | ||||
|           <div class="item" :class="'item'+index"> | ||||
|             <div class="img-div" v-if="item.sdkFileUrl"> | ||||
|               <u-icon name="play-circle" :color="item.userType == 0 ? '#fff' : '#A8ADAE'" size="52" v-if="!item.isPlay" @click="play(item.sdkFileUrl, index)"></u-icon> | ||||
|               <u-icon name="pause-circle" :color="item.userType == 0 ? '#fff' : '#A8ADAE'" size="52" v-else @click="playStop(index)"></u-icon> | ||||
|               <img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/recording-white.png" alt="" v-if="item.userType == 0"> | ||||
|               <img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/recording-gray.png" alt="" v-else> | ||||
|             </div> | ||||
|             <p>{{item.content || ''}}</p> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     <!-- </scroll-view> --> | ||||
|     <div class="fixed-bottom"> | ||||
|       <div class="type-text" v-if="type == 'text'"> | ||||
|         <u-input type="text" placeholder="输入您的问题…" height="80" input-align="left"  :clearable="false" placeholder-style="color:#666;" v-model="content" @confirm="sendMsg"></u-input> | ||||
|         <img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/send.png" alt="" v-if="content.length" @click="sendMsg"> | ||||
|         <img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/microphone-btn.png" alt="" v-else @click="microPhone"> | ||||
|       </div> | ||||
|       <div class="type-record" v-else> | ||||
|         <img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/keyboard-btn.png" alt="" class="keyboard-btn" @click="keyboardClick"> | ||||
|         <div v-if="!isStart" @click="startRecord"> | ||||
|           <p>点击开始录音</p> | ||||
|           <img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/record-btn.png" alt="" class="record-btn"> | ||||
|         </div> | ||||
|         <div v-else @click="endRecord"> | ||||
|           <p>正在录音中</p> | ||||
|           <div class="tips-text">点击下方,停止录音</div> | ||||
|           <img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/shengbo.gif" alt="" class="recording"> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| import {mapState} from "vuex"; | ||||
| const recorderManager = uni.getRecorderManager(); | ||||
| const innerAudioContext = uni.createInnerAudioContext(); | ||||
| innerAudioContext.autoplay = true; | ||||
| export default { | ||||
|   customNavigation: true, | ||||
|   enablePullDownRefresh: true, | ||||
|   name: 'AppResidentAssistant', | ||||
|   appName: '村长Copilot', | ||||
|   data() { | ||||
|     return { | ||||
|       backgroundNavbar: { | ||||
|         background: 'url(https://cdn.sinoecare.com/i/2024/08/06/66b1c9696650b.png) no-repeat', | ||||
|         backgroundSize: 'cover', | ||||
|       }, | ||||
|       recorderManager: null, | ||||
|       type: 'text', | ||||
|       isStart: false, | ||||
|       content: '', | ||||
|       isFlag: false, | ||||
|       voiceUrl: '', | ||||
|       voiceId: '', | ||||
|       messageList: [ | ||||
|         // { | ||||
|         //   userType: 0, | ||||
|         //   sdkFileUrl: 'http://test87ftp.cunwuyun.cn/20240104/output.mp3', | ||||
|         //   isPlay: false | ||||
|         // } | ||||
|       ], | ||||
|       current: 1, | ||||
|       pages: 2 | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|   }, | ||||
|   onLoad() { | ||||
|     recorderManager.onStop((res)=> { | ||||
|       console.log(res) | ||||
|       this.upLoad(res.tempFilePath) | ||||
| 		}); | ||||
|     this.getHistoryList() | ||||
|   }, | ||||
|   onPullDownRefresh() { | ||||
|     if(this.current > this.pages) { | ||||
|       return this.$u.toast('没有更多记录') | ||||
|     } | ||||
|     this.current = this.current + 1 | ||||
|     this.getHistoryList() | ||||
|   }, | ||||
|   methods: { | ||||
|     startRecord() { | ||||
|       if(this.isFlag) return | ||||
|       this.isStart = true | ||||
|       uni.authorize({ | ||||
|         scope: 'scope.record', | ||||
|         success() { | ||||
|           // const options = { | ||||
|           //   duration: 10000, | ||||
|           //   sampleRate: 44100, | ||||
|           //   numberOfChannels: 1, | ||||
|           //   encodeBitRate: 192000, | ||||
|           //   format: 'aac', | ||||
|           //   frameSize: 50 | ||||
|           // } | ||||
|           const options = { | ||||
|             duration: 60000, | ||||
|             sampleRate: 16000, | ||||
|             format: 'mp3' | ||||
|           } | ||||
|           recorderManager.start(options); | ||||
|            | ||||
|         }, | ||||
|         fail(err) { | ||||
|           this.isStart = false | ||||
|           uni.showModal({ | ||||
|             title: "提示", | ||||
|             content: "您的录音权限未开启", | ||||
|           }) | ||||
|         } | ||||
|       })	 | ||||
| 		}, | ||||
| 		endRecord() { | ||||
|       this.isStart = false | ||||
|       setTimeout(() => { | ||||
|         this.isFlag = false | ||||
|       }, 6000) | ||||
|       recorderManager.stop(); | ||||
| 		}, | ||||
|     microPhone() { | ||||
|       this.type = 'voice' | ||||
|       this.isStart = false | ||||
|     }, | ||||
|     keyboardClick() { | ||||
|       if(this.isStart) return | ||||
|       this.type = 'text' | ||||
|       this.content = '' | ||||
|     }, | ||||
|     upLoad(filePath) { | ||||
|       return new Promise((resolve, reject) => { | ||||
|         uni.uploadFile({ | ||||
|           url: `${this.$instance.defaults.baseURL}/admin/file/add`, | ||||
|           filePath, | ||||
|           fileType: 'audio', | ||||
|           name: 'file', | ||||
|           success: uploadFileRes => { | ||||
|             this.voiceUrl = JSON.parse(uploadFileRes.data).data[0].split(';')[0] | ||||
|             this.voiceId = JSON.parse(uploadFileRes.data).data[0].split(';')[1] | ||||
|             this.sendVoice() | ||||
|             resolve(uploadFileRes) | ||||
|           }, | ||||
|           fail: err => { | ||||
|             reject(err) | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     sendMsg() { | ||||
|       this.$loading() | ||||
|       this.$instance.post("/app/appaigccopilotinfo/add", {content: this.content, appType: 0}).then(res => { | ||||
|         if(res.code == 0) { | ||||
|           this.content = '' | ||||
|           this.messageList.push(res.data[0]) | ||||
|           this.messageList.push(res.data[1]) | ||||
|           this.$nextTick(() => {   | ||||
|             uni.pageScrollTo({ | ||||
|               duration: 300, | ||||
|               selector: `.item${this.messageList.length-1}` | ||||
|             }); | ||||
|           }) | ||||
|           this.$hideLoading() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     sendVoice() { | ||||
|       this.$loading() | ||||
|       this.$instance.post("/app/appaigccopilotinfo/add", {sdkFileUrl: this.voiceUrl, fileId: this.voiceId, appType: 0}).then(res => { | ||||
|         if(res.code == 0) { | ||||
|           this.voiceUrl = '' | ||||
|           this.voiceId = '' | ||||
|           res.data.map((item) => { | ||||
|             if(item.sdkFileUrl) { | ||||
|               item.isPlay = false | ||||
|             } | ||||
|           }) | ||||
|           this.messageList.push(res.data[0]) | ||||
|           this.messageList.push(res.data[1]) | ||||
|           uni.pageScrollTo({ | ||||
|             duration: 300, | ||||
|             selector: `.item${this.messageList.length-1}` | ||||
|           }); | ||||
|           this.$hideLoading() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getHistoryList() { | ||||
|       this.$loading() | ||||
|       this.$instance.post(`/app/appaigccopilotinfo/list?current=${this.current}&size=10`).then(res => { | ||||
|         if(res.code == 0 && res.data.records.length) { | ||||
|           res.data.records.map((item) => { | ||||
|             if(item.sdkFileUrl) { | ||||
|               item.isPlay = false | ||||
|             } | ||||
|           }) | ||||
|           this.messageList = this.current == 1 ? res.data.records : [...res.data.records, ...this.messageList] | ||||
|           var idPage = res.data.records.length-1 | ||||
|           this.$nextTick(() => {   | ||||
|             uni.pageScrollTo({ | ||||
|               duration: 300, | ||||
|               selector: this.current == 1 ? `.item${this.messageList.length-1}` :  `.item${idPage}` | ||||
|             }); | ||||
|           }) | ||||
|           this.pages = res.data.pages | ||||
|           this.$hideLoading() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     play(src, index) { | ||||
|       innerAudioContext.stop(); | ||||
|       this.messageList.map((item) => { | ||||
|         if(item.sdkFileUrl) { | ||||
|           item.isPlay = false | ||||
|         } | ||||
|       }) | ||||
|       this.messageList[index].isPlay = true | ||||
|       innerAudioContext.src = src; | ||||
|  | ||||
|       this.$nextTick(() => { | ||||
|         innerAudioContext.play(); | ||||
|       }) | ||||
|       innerAudioContext.onEnded(() => { | ||||
|         this.messageList[index].isPlay = false | ||||
|       }) | ||||
|     }, | ||||
|     playStop(index) { | ||||
|       innerAudioContext.stop(); | ||||
|       innerAudioContext.onStop(() => { | ||||
|         this.messageList[index].isPlay = false | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @import "~dvcp-wui/common"; | ||||
| page { | ||||
|   height: 100%; | ||||
| } | ||||
| .AppResidentAssistant { | ||||
|   height: 100vh; | ||||
|   background-color: #fff; | ||||
|   .service-content { | ||||
|     width: 100%; | ||||
|     height: 420px; | ||||
|     background-image: url("https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/content-top-bg.png"); | ||||
|     background-size: 100vw; | ||||
|     background-repeat: no-repeat; | ||||
|     padding-top: 20px; | ||||
|     box-sizing: border-box; | ||||
|     .text-content { | ||||
|       margin: 0 0 0 32px; | ||||
|       width: 686px; | ||||
|       height: 260px; | ||||
|       background-image: url("https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/service-content-bg.png"); | ||||
|       background-size: 100vw; | ||||
|       background-repeat: no-repeat; | ||||
|       padding: 32px; | ||||
|       box-sizing: border-box; | ||||
|       border-radius: 32px; | ||||
|       display: flex; | ||||
|       justify-content: space-between; | ||||
|       .text-left { | ||||
|         width: calc(100% - 192px); | ||||
|         div { | ||||
|           line-height: 54px; | ||||
|           font-family: SourceHanSansCN-Bold; | ||||
|           font-weight: 700; | ||||
|           font-size: 36px; | ||||
|           background: linear-gradient(to bottom, #2A6EE9, #58A5F7); | ||||
|           -webkit-background-clip: text; | ||||
|           -webkit-text-fill-color: transparent; | ||||
|           margin-bottom: 16px; | ||||
|         } | ||||
|         p { | ||||
|           color: #222; | ||||
|           font-size: 28px; | ||||
|           font-family: SourceHanSansCN; | ||||
|           line-height: 44px; | ||||
|           span { | ||||
|             display: inline-block; | ||||
|             font-weight: 700; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       .service-img { | ||||
|         display: inline-block; | ||||
|         width: 192px; | ||||
|         height: 170px; | ||||
|       } | ||||
|        | ||||
|     } | ||||
|   } | ||||
|   .list-content { | ||||
|     padding: 0 32px 364px; | ||||
|     overflow: hidden; | ||||
|     margin-top: -112px; | ||||
|     background-color: #fff; | ||||
|     .item { | ||||
|       display: inline-block; | ||||
|       max-width: 600px; | ||||
|       border-radius: 24px 24px 0 24px; | ||||
|       padding: 24px 32px; | ||||
|       box-sizing: border-box; | ||||
|       margin-bottom: 32px; | ||||
|       .img-div { | ||||
|         margin-bottom: 4px; | ||||
|         img { | ||||
|           width: 136px; | ||||
|           height: 28px; | ||||
|           margin-left: 26px; | ||||
|         } | ||||
|       } | ||||
|       p { | ||||
|         word-break: break-all; | ||||
|         line-height: 48px; | ||||
|         font-family: SourceHanSansCN-Regular; | ||||
|         font-size: 32px; | ||||
|       } | ||||
|     } | ||||
|     .item-right { | ||||
|       display: flex; | ||||
|       justify-content: flex-end; | ||||
|       .item { | ||||
|         background-image: linear-gradient(-76deg, #569EF0 0%, #276FEC 100%); | ||||
|       } | ||||
|       p { | ||||
|         color: #fff; | ||||
|       } | ||||
|     } | ||||
|     .item-left { | ||||
|       .item { | ||||
|         background-color: #F1F4F8; | ||||
|       } | ||||
|       p { | ||||
|         color: #222; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .fixed-bottom { | ||||
|     position: fixed; | ||||
|     bottom: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     padding-bottom: 64px; | ||||
|     border-top: 1px solid #eee; | ||||
|     background-color: #fff; | ||||
|     .type-text { | ||||
|       padding: 24px 0 24px 32px; | ||||
|       display: flex; | ||||
|       u-input { | ||||
|         width: calc(100% - 112px); | ||||
|         height: 80px; | ||||
|         background: #F4F6FA; | ||||
|         border-radius: 40px; | ||||
|         padding-left: 32px; | ||||
|       } | ||||
|       img { | ||||
|         width: 80px; | ||||
|         height: 80px; | ||||
|         padding: 0 16px; | ||||
|       } | ||||
|     } | ||||
|     .type-record { | ||||
|       position: relative; | ||||
|       text-align: center; | ||||
|       padding-top: 36px; | ||||
|       .keyboard-btn { | ||||
|         width: 48px; | ||||
|         height: 36px; | ||||
|         position: absolute; | ||||
|         top: 32px; | ||||
|         right: 32px; | ||||
|       } | ||||
|       p { | ||||
|         line-height: 58px; | ||||
|         font-family: SourceHanSansCN-Medium; | ||||
|         font-weight: 500; | ||||
|         font-size: 40px; | ||||
|         color: #222; | ||||
|       } | ||||
|       .record-btn { | ||||
|         width: 156px; | ||||
|         height: 156px; | ||||
|         margin-top: 24px; | ||||
|       } | ||||
|       .tips-text { | ||||
|         line-height: 40px; | ||||
|         font-family: SourceHanSansCN-Regular; | ||||
|         font-size: 28px; | ||||
|         color: #999; | ||||
|         margin-top: 16px; | ||||
|       } | ||||
|       .recording { | ||||
|         padding-top: 48px; | ||||
|         width: 204px; | ||||
|         height: 96px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										635
									
								
								src/mods/conv/AppReturnHomeRegister/Add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,635 @@ | ||||
| <template> | ||||
|   <div class="album"> | ||||
|     <div class="tips">请确保以下信息全部由本人填写,本人对所填写内容的真实性和完整性负责</div> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>返乡人员姓名</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" v-model="form.name" :maxlength="20"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>身份证号</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" type="idcard" v-model="form.idNumber" :maxlength="20"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>手机号码</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" type="number" v-model="form.phone" :maxlength="11"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>人员类别</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiSelect v-model="form.type" dict="epidemicRecentPersonType" class="select"></AiSelect> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>出行方式</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiSelect dict="epidemicRecentTravel" v-model="form.travelType" class="select"></AiSelect> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>出发时间</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <div class="ai-area" @click="isShowStartTime = true"> | ||||
|               <div class="ai-area__wrapper"> | ||||
|                 <span class="label" v-if="form.startTime">{{ form.startTime }}</span> | ||||
|                 <i v-else>请选择</i> | ||||
|                 <u-icon name="arrow-right" color="#ddd"/> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>出发地区</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiAreaPicker class="ai-area" v-model="form.startAreaId" :fullName.sync="form.startAreaName" all> | ||||
|               <div class="ai-area__wrapper"> | ||||
|                 <span class="label" v-if="form.startAreaName">{{ form.startAreaName }}</span> | ||||
|                 <i v-else>请选择</i> | ||||
|                 <u-icon name="arrow-right" color="#ddd"/> | ||||
|               </div> | ||||
|             </AiAreaPicker> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__textarea"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>出发地址</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <textarea auto-height v-model="form.startAddress" :maxlength="500" placeholder="请输入详细的出发地址" | ||||
|                       placeholder-style="font-size: 16px"></textarea> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>到达时间</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <div class="ai-area" @click="isShowEndTime = true"> | ||||
|               <div class="ai-area__wrapper"> | ||||
|                 <span class="label" v-if="form.arriveTime">{{ form.arriveTime }}</span> | ||||
|                 <i v-else>请选择</i> | ||||
|                 <u-icon name="arrow-right" color="#ddd"/> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>到达地区</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiAreaPicker class="ai-area" v-model="form.arriveAreaId" :fullName.sync="form.arriveAreaName" :areaId="$areaId"> | ||||
|               <div class="ai-area__wrapper"> | ||||
|                 <span class="label" v-if="form.arriveAreaName">{{ form.arriveAreaName }}</span> | ||||
|                 <i v-else>请选择</i> | ||||
|                 <u-icon name="arrow-right" color="#ddd"/> | ||||
|               </div> | ||||
|             </AiAreaPicker> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__textarea"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>返乡地址</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <textarea auto-height v-model="form.arriveAddress" :maxlength="500" placeholder="请输入详细的返乡地址" | ||||
|                       placeholder-style="font-size: 16px"></textarea> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__textarea"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>行程描述</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <textarea auto-height style="height: 90px" v-model="form.description" :maxlength="500" placeholder="请输入行程描述" | ||||
|                       placeholder-style="font-size: 16px"></textarea> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>核酸检测日期</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <div class="ai-area" @click="isShowDate = true"> | ||||
|               <div class="ai-area__wrapper"> | ||||
|                 <span class="label" v-if="form.checkTime">{{ form.checkTime }}</span> | ||||
|                 <i v-else>请选择</i> | ||||
|                 <u-icon name="arrow-right" color="#ddd"/> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__imgs"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>本人健康码截图或核酸检测报告<span style="color:#999; fontSize:14px; font-weight: normal;">(最多9张)</span></h2> | ||||
|           </div> | ||||
|           <div class="form-item__right" style="padding-left: 5px;"> | ||||
|             <AiUploader v-model="form.checkPhoto" :limit="9" multiple></AiUploader> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__imgs"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>核酸检测结果</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiRadio style="width: 100%;" v-model="form.checkResult" dict="epidemicRecentTestResult"/> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="form-item__group"> | ||||
|       <div class="form-item"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>当前体温</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <input placeholder="请输入" v-model="form.temperature" :maxlength="20"/> | ||||
|             <i>℃</i> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__imgs"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>14天内是否接触新冠确诊或疑似患者</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiRadio style="width: 100%;" v-model="form.touchInFourteen" dict="epidemicTouchInFourteen"></AiRadio> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="form-item form-item__imgs"> | ||||
|         <div class="form-item__wrapper"> | ||||
|           <div class="form-item__title"> | ||||
|             <i>*</i> | ||||
|             <h2>当前健康状况(可多选)</h2> | ||||
|           </div> | ||||
|           <div class="form-item__right"> | ||||
|             <AiCheckbox style="width: 100%;" v-model="form.health" dict="epidemicRecentHealth"></AiCheckbox> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <u-picker mode="time" :params="dataParams" v-model="isShowDate" @confirm="onDateChange"></u-picker> | ||||
|     <u-picker mode="time" :params="params" v-model="isShowStartTime" @confirm="onStartChange"></u-picker> | ||||
|     <u-picker mode="time" :params="params" v-model="isShowEndTime" @confirm="onEndChange"></u-picker> | ||||
|     <div class="btn-wrapper"> | ||||
|       <div class="btn" hover-class="text-hover" @click="submit">提交</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   appName: "添加返乡记录", | ||||
|   data() { | ||||
|     return { | ||||
|       isShowType: false, | ||||
|       isShowEndTime: false, | ||||
|       isShowStartTime: false, | ||||
|       isShowDate: false, | ||||
|       params: { | ||||
|         year: true, | ||||
|         month: true, | ||||
|         day: true, | ||||
|         hour: true, | ||||
|         minute: true | ||||
|       }, | ||||
|       dataParams: { | ||||
|         year: true, | ||||
|         month: true, | ||||
|         day: true | ||||
|       }, | ||||
|       form: { | ||||
|         arriveAddress: '', | ||||
|         arriveAreaId: '', | ||||
|         arriveAreaName: '', | ||||
|         arriveTime: '', | ||||
|         checkPhoto: [], | ||||
|         checkResult: '', | ||||
|         checkTime: '', | ||||
|         description: '', | ||||
|         health: [], | ||||
|         idNumber: '', | ||||
|         name: '', | ||||
|         phone: '', | ||||
|         startAddress: '', | ||||
|         startAreaId: '', | ||||
|         startAreaName: '', | ||||
|         startTime: '', | ||||
|         temperature: '', | ||||
|         touchInFourteen: '', | ||||
|         travelType: '', | ||||
|         type: '', | ||||
|         unusual: '', | ||||
|       }, | ||||
|       dictList: [], | ||||
|       arr: [], | ||||
|       gridList: [[], [], []], | ||||
|       flag: false, | ||||
|       $areaId: '' | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|  | ||||
|   computed: { | ||||
|     ...mapState(['user']) | ||||
|   }, | ||||
|  | ||||
|   onLoad() { | ||||
|     this.$areaId = this.user.$areaId | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     onDateChange(e) { | ||||
|       this.form.checkTime = `${e.year}-${e.month}-${e.day}` | ||||
|     }, | ||||
|  | ||||
|     onStartChange(e) { | ||||
|       this.form.startTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}` | ||||
|     }, | ||||
|  | ||||
|     onEndChange(e) { | ||||
|       this.form.arriveTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}` | ||||
|     }, | ||||
|  | ||||
|     submit() { | ||||
|       if (!this.form.name) { | ||||
|         return this.$toast('请输入返乡人员姓名') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.idNumber) { | ||||
|         return this.$toast('请输入返乡人员身份证号') | ||||
|       } | ||||
|  | ||||
|       if (!/^[1-9]\d{5}(19\d{2}|20[0-2]\d)(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])\d{3}([0-9xX])$/.test(this.form.idNumber)) { | ||||
|         return this.$toast('请输入正确的身份证账号') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.phone) { | ||||
|         return this.$toast('请输入返乡人员手机号码') | ||||
|       } | ||||
|  | ||||
|       if (!/^1[0-9]{10,10}$/.test(this.form.phone)) { | ||||
|         return this.$toast('请输入正确的手机号码') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.type) { | ||||
|         return this.$toast('请选择人员类别') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.travelType) { | ||||
|         return this.$toast('请选择出行方式') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.startTime) { | ||||
|         return this.$toast('请选择出发时间') | ||||
|       } | ||||
|  | ||||
|       // if (new Date(this.form.startTime.replace(/-/g, '/')).getTime() > new Date().getTime()) { | ||||
|       //   return this.$toast('出发时间不得晚于当前时间') | ||||
|       // } | ||||
|  | ||||
|       if (!this.form.startAreaName) { | ||||
|         return this.$toast('请选择出发地区') | ||||
|       } | ||||
|  | ||||
|       if (this.form.startAreaId.substr(this.form.startAreaId.length - 3, 3) === '000') { | ||||
|         return this.$toast('出发地区必须选到村或社区') | ||||
|       } | ||||
|       if (!this.form.startAddress) { | ||||
|         return this.$toast('请输入出发详细地址') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.arriveTime) { | ||||
|         return this.$toast('请选择到达时间') | ||||
|       } | ||||
|  | ||||
|       if (new Date(this.form.startTime.replace(/-/g, '/')).getTime() >= new Date(this.form.arriveTime.replace(/-/g, '/')).getTime()) { | ||||
|         return this.$toast('到达时间不得早于出发时间') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.arriveAreaName) { | ||||
|         return this.$toast('请选择到达地区') | ||||
|       } | ||||
|       if (this.form.arriveAreaId.substr(this.form.arriveAreaId.length - 3, 3) === '000') { | ||||
|         return this.$toast('到达地区必须选到村或社区') | ||||
|       } | ||||
|       if (!this.form.arriveAddress) { | ||||
|         return this.$toast('请输入返乡地址') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.description) { | ||||
|         return this.$toast('请输入行程描述') | ||||
|       } | ||||
|       if (!this.form.checkTime) { | ||||
|         return this.$toast('请选择核酸检测日期') | ||||
|       } | ||||
|       if (!this.form.checkPhoto.length) { | ||||
|         return this.$toast('请上传本人健康码截图或核酸检测报告') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.checkResult) { | ||||
|         return this.$toast('请选择核酸检测结果') | ||||
|       } | ||||
|       if (!this.form.temperature) { | ||||
|         return this.$toast('请输入当前体温') | ||||
|       } | ||||
|       if (!this.form.touchInFourteen) { | ||||
|         return this.$toast('请选择14天内是否接触新冠确诊或疑似患者') | ||||
|       } | ||||
|  | ||||
|       if (!this.form.health.length) { | ||||
|         return this.$toast('请选择当前健康状况') | ||||
|       } | ||||
|       if (this.flag) return | ||||
|       this.flag = true | ||||
|  | ||||
|       this.$loading() | ||||
|       this.$instance.post(`/app/appepidemicbackhomerecord/addOrUpdate`, { | ||||
|         ...this.form, | ||||
|         openid: this.user.openid, | ||||
|         startTime: this.form.startTime + ':00', | ||||
|         arriveTime: this.form.arriveTime + ':00', | ||||
|         checkTime: this.form.checkTime + ' 00:00:00', | ||||
|         health: this.form.health.join(','), | ||||
|         checkPhoto: JSON.stringify(this.form.checkPhoto) | ||||
|       }).then(res => { | ||||
|         this.$hideLoading() | ||||
|         this.flag = false | ||||
|         if (res.code == 0) { | ||||
|           uni.$emit('update') | ||||
|           this.$toast('提交成功') | ||||
|           setTimeout(() => { | ||||
|             uni.navigateBack() | ||||
|           }, 400) | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| .album { | ||||
|   padding-bottom: 140px; | ||||
|  | ||||
|   .tips { | ||||
|     line-height: 1.3; | ||||
|     padding: 32px 32px; | ||||
|     color: #FF883C; | ||||
|     font-size: 30px; | ||||
|     text-align: justify; | ||||
|     background: #FFF8F3; | ||||
|   } | ||||
|  | ||||
|   .form-item__group { | ||||
|     margin-bottom: 24px; | ||||
|     background: #fff; | ||||
|   } | ||||
|  | ||||
|   .form-item { | ||||
|     padding-left: 32px; | ||||
|  | ||||
|     .form-item__checkbox { | ||||
|       width: 100%; | ||||
|  | ||||
|       div { | ||||
|         width: 100%; | ||||
|         height: 80px; | ||||
|         line-height: 80px; | ||||
|         margin-bottom: 24px; | ||||
|         text-align: center; | ||||
|         background: #FFFFFF; | ||||
|         border-radius: 16px; | ||||
|         color: #333333; | ||||
|         font-size: 28px; | ||||
|         border: 1px solid #CCCCCC; | ||||
|  | ||||
|         &.active { | ||||
|           background: #4181FF; | ||||
|           color: #fff; | ||||
|           border-color: #4181FF; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .form-item__radio { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       flex-wrap: wrap; | ||||
|  | ||||
|       div { | ||||
|         width: 212px; | ||||
|         height: 80px; | ||||
|         line-height: 80px; | ||||
|         margin-right: 16px; | ||||
|         margin-bottom: 8px; | ||||
|         text-align: center; | ||||
|         background: #FFFFFF; | ||||
|         border-radius: 16px; | ||||
|         color: #333333; | ||||
|         font-size: 28px; | ||||
|         border: 1px solid #CCCCCC; | ||||
|  | ||||
|         &:nth-of-type(3n) { | ||||
|           margin-right: 0; | ||||
|         } | ||||
|  | ||||
|         &.active { | ||||
|           background: #4181FF; | ||||
|           color: #fff; | ||||
|           border-color: #4181FF; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .ai-area__wrapper { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       padding-left: 100px; | ||||
|  | ||||
|       span { | ||||
|         color: #333; | ||||
|         font-size: 30px; | ||||
|       } | ||||
|  | ||||
|       i { | ||||
|         color: #999; | ||||
|         font-size: 30px; | ||||
|       } | ||||
|  | ||||
|       image { | ||||
|         width: 16px; | ||||
|         height: 8px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .form-item__wrapper { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: space-between; | ||||
|       height: 128px; | ||||
|       padding-right: 28px; | ||||
|       border-bottom: 1px solid #DDDDDD; | ||||
|  | ||||
|       input { | ||||
|         flex: 1; | ||||
|         height: 100%; | ||||
|         text-align: right; | ||||
|         color: #333; | ||||
|         padding-right: 10px; | ||||
|       } | ||||
|  | ||||
|       .form-item__right { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         font-size: 32px; | ||||
|  | ||||
|         .select { | ||||
|           ._i { | ||||
|             padding-left: 100px; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         span { | ||||
|           max-width: 400px; | ||||
|           margin-right: 8px; | ||||
|           color: #333333; | ||||
|           overflow: hidden; | ||||
|           white-space: nowrap; | ||||
|           text-overflow: ellipsis; | ||||
|         } | ||||
|  | ||||
|         i { | ||||
|           margin-right: 8px; | ||||
|           color: #999999; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     &:last-child { | ||||
|       .form-item__wrapper { | ||||
|         border-bottom: none; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .form-item__title { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|  | ||||
|       i { | ||||
|         font-size: 32px; | ||||
|         color: #FF4466; | ||||
|       } | ||||
|  | ||||
|       span { | ||||
|         font-size: 28px; | ||||
|         color: #999999; | ||||
|       } | ||||
|  | ||||
|       h2 { | ||||
|         padding: 0 4px; | ||||
|         font-weight: 600; | ||||
|         font-size: 32px; | ||||
|         color: #333333; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     &.form-item__imgs, &.form-item__textarea { | ||||
|       .form-item__wrapper { | ||||
|         display: block; | ||||
|         height: auto; | ||||
|         padding-bottom: 32px; | ||||
|       } | ||||
|  | ||||
|       textarea { | ||||
|         width: 100%; | ||||
|         height: 90px; | ||||
|       } | ||||
|  | ||||
|       .form-item__title { | ||||
|         padding: 32px 0; | ||||
|       } | ||||
|  | ||||
|       .form-item__right { | ||||
|         padding-left: 18px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||