Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a98cd7d19 | ||
|
|
3a5b48b608 | ||
|
|
d735ad7dd7 | ||
|
|
25dd0f1504 | ||
|
|
8e14c6cef5 | ||
|
|
9f7abe4413 | ||
|
|
de730205af | ||
|
|
a873f0e0dc | ||
|
|
32e3765b52 | ||
|
|
4f62095e8e | ||
|
|
5234448ae5 | ||
|
|
f284c67988 | ||
|
|
2d77813dab | ||
|
|
d22a255143 | ||
|
|
6703bbeeec | ||
|
|
d444c591ec | ||
|
|
f7ddb6cae0 | ||
|
|
7ffc02e887 | ||
|
|
cbacb27bb1 | ||
|
|
03a08a320a | ||
|
|
45223be64a | ||
|
|
b22dfdfa4c | ||
|
|
ce219f0e40 | ||
|
|
a0f26d38b2 | ||
|
|
4efdcfe0fc | ||
|
|
806ccf950f | ||
|
|
b96b78fa0b | ||
|
|
f816bf005e | ||
|
|
791ad6ce37 | ||
|
|
4bc802cee2 | ||
|
|
4662c8c896 | ||
|
|
7058560a03 | ||
|
|
79a5999ad5 | ||
|
|
1aeded5da2 | ||
|
|
e8d1d882c2 | ||
|
|
39dca810a5 | ||
|
|
97f94688f1 | ||
|
|
0b502cbc99 | ||
|
|
a8eb8f9ab1 | ||
|
|
6471f4365a | ||
|
|
48999f5699 | ||
|
|
5ad64a596b | ||
|
|
df60bd0b40 | ||
|
|
41e6f1cf48 | ||
|
|
0802ba191a | ||
|
|
ad57ed241d | ||
|
|
f17cb420e3 | ||
|
|
c2396f093b | ||
|
|
bdf65dcfd1 | ||
|
|
2aefbe17ee | ||
|
|
5e43d69d8e | ||
|
|
4482b92ccd | ||
|
|
d3c39caefb | ||
|
|
24c5dce24d | ||
|
|
9971e512c8 | ||
|
|
0c77ed9bba | ||
|
|
e759c96ade | ||
|
|
f602b75268 | ||
|
|
d4d9eaf773 | ||
|
|
68a800cdfc | ||
|
|
ff45d1a875 | ||
|
|
11d0378060 | ||
|
|
49000c6140 | ||
|
|
24bba484ca | ||
|
|
c8d0d85937 | ||
|
|
c692f7c647 | ||
|
|
080463458b | ||
|
|
08aaf4dd62 | ||
|
|
8ed4f959cb | ||
|
|
e5f7778861 | ||
|
|
ad1e517472 | ||
|
|
17ed5eb46b | ||
|
|
1a2faf02da | ||
|
|
2d086a05b2 | ||
|
|
6ef4603a7c | ||
|
|
d6522338aa | ||
|
|
df154a45b6 | ||
|
|
c5dbea334d | ||
|
|
85f535eb5d | ||
|
|
9334514c71 | ||
|
|
d438755616 | ||
|
|
54595fb7b6 | ||
|
|
4ee8d5a099 | ||
|
|
abe5fae4c4 | ||
|
|
aeb48661b1 | ||
|
|
4bdf68c2b6 | ||
|
|
c5a0e378fd | ||
|
|
538f656640 | ||
|
|
a323c42acf | ||
|
|
095101ad2f | ||
|
|
7ee5ebd506 | ||
|
|
f90ef6297d | ||
|
|
4167107a91 | ||
|
|
90c1cb1f52 | ||
|
|
8c614b84a7 | ||
|
|
7d1a501ad8 | ||
|
|
48589274c8 | ||
|
|
83f7676db4 | ||
|
|
c8b30810f6 | ||
|
|
f71fa7d97a | ||
|
|
4c7c4c00ab | ||
|
|
d2645a9c08 | ||
|
|
ae341d66ba | ||
|
|
fce4def951 | ||
|
|
ba0964f772 | ||
|
|
e346417c29 | ||
|
|
5fcc184a88 | ||
|
|
f6d3f89b5b | ||
|
|
106e09a7a2 | ||
|
|
d1b4600392 | ||
|
|
4204dfa624 | ||
|
|
d7fd5be068 | ||
|
|
735bb397ec | ||
|
|
8b5a2b713c | ||
|
|
f2ec9327fd | ||
|
|
5331e10c96 | ||
|
|
7090f02a52 | ||
|
|
12152a6810 | ||
|
|
c0c2d3d1c9 | ||
|
|
858844e81a | ||
|
|
1ff2731121 | ||
|
|
70db7662bb | ||
|
|
bb57ff72e7 | ||
|
|
8df79fd624 | ||
|
|
7946c08c72 | ||
|
|
6f20ef7273 | ||
|
|
657ae77dde | ||
|
|
4ff80dd257 | ||
|
|
9bb1069d26 | ||
|
|
730be25948 | ||
|
|
78d8fea7f5 | ||
|
|
22ed78c87b | ||
|
|
f5331d4c50 | ||
|
|
f32fe0ec5b | ||
|
|
3b914fbc2e | ||
|
|
533df0eb16 | ||
|
|
9c38165afb | ||
|
|
7b506320b4 | ||
|
|
2b7c497c3e | ||
|
|
4dee1309eb | ||
|
|
f3f8909e45 | ||
|
|
d45cd79422 | ||
|
|
7cbb58ff32 | ||
|
|
9242e1fb47 | ||
|
|
f5ce74d0ee | ||
|
|
3114280e83 | ||
|
|
c7b8b36f4a | ||
|
|
60ee194cc9 | ||
|
|
4f50593eac | ||
|
|
8818dd21c6 | ||
|
|
db8ee298d9 | ||
|
|
9eef99a435 | ||
|
|
3d027ed374 | ||
|
|
271b5d445d | ||
|
|
2457d14ae9 | ||
|
|
d70eb17a72 | ||
|
|
ddd619babc | ||
|
|
5d27ee830e | ||
|
|
b73b83a49f | ||
|
|
549debf8bf | ||
|
|
212b9a43a9 | ||
|
|
f092a23ee4 | ||
|
|
25c357a423 | ||
|
|
a77246a1db | ||
|
|
f00ce31648 | ||
|
|
dc57a491dd | ||
|
|
c9b7266959 | ||
|
|
0dd2111cb9 | ||
|
|
c39b048398 | ||
|
|
87fbf15e2b | ||
|
|
db1cfaa1a6 | ||
|
|
905b750877 | ||
|
|
be14fe2603 | ||
|
|
9739609de4 | ||
|
|
d7f101ee30 | ||
|
|
20f7d595a1 | ||
|
|
e909dc81ad | ||
|
|
a510779ea1 | ||
|
|
c799c199c5 | ||
|
|
0818e9ade2 | ||
|
|
e60a8bed8b | ||
|
|
17fdcd7d1f | ||
|
|
6412e1a997 | ||
|
|
1674598480 | ||
|
|
23ebf36244 | ||
|
|
342db06685 | ||
|
|
35b9f813c4 | ||
|
|
aafb326662 | ||
|
|
aa1b309b26 | ||
|
|
2c355525df | ||
|
|
bd20a499d3 | ||
|
|
5fec5d5239 | ||
|
|
5b3aaa463d | ||
|
|
a14b22b1ef | ||
|
|
50aa549311 | ||
|
|
bf0aef59cd | ||
|
|
b2ddcd0cf3 | ||
|
|
947dba5934 | ||
|
|
572ef04bb4 | ||
|
|
110d6c689c | ||
|
|
f40d6fd5e8 | ||
|
|
49ace44c9b | ||
|
|
cc3bc548c9 | ||
|
|
4816a512bf | ||
|
|
cc3d7ccd7b | ||
|
|
43bc7db7d5 | ||
|
|
b0672aead5 | ||
|
|
086d5a18e8 | ||
|
|
91576f401b | ||
|
|
febcd18eda | ||
|
|
8cc9f0d291 | ||
|
|
41643563f8 | ||
|
|
b6b58eaeba | ||
|
|
e8a5701e73 | ||
|
|
a8f2c8f41a | ||
|
|
241222dcd1 | ||
|
|
380575dae0 | ||
|
|
4d685d5a67 | ||
|
|
96196229f4 | ||
|
|
5e54039028 | ||
|
|
94b2e84c10 | ||
|
|
80d2230c9a | ||
|
|
4fad163b14 | ||
|
|
4d20a68f93 | ||
|
|
90a1d6fdff | ||
|
|
00e1cb707e | ||
|
|
6eeb774a21 | ||
|
|
6c4b8a52dc | ||
|
|
a7e0d8f826 | ||
|
|
d1ccddc1d3 | ||
|
|
d5f0c3bc95 | ||
|
|
da2191f365 | ||
|
|
056643bd96 | ||
|
|
01d5ed297e | ||
|
|
55ab2b8562 | ||
|
|
dae5d0a9f5 | ||
|
|
41ad33310a | ||
|
|
526392c370 | ||
|
|
b38ee9c7c7 | ||
|
|
9f7f1db9b8 | ||
|
|
b7134cb3e4 | ||
|
|
ec78658e46 | ||
|
|
44361af392 | ||
|
|
76130caa6d | ||
|
|
352a78a0c5 | ||
|
|
6020c80a7a | ||
|
|
a2a165a42b | ||
|
|
0f27c1e5ce | ||
|
|
e944ad4369 | ||
|
|
65bee9586d | ||
|
|
31cda8579a | ||
|
|
1dc40b9efc | ||
|
|
6cb3d8ad65 | ||
|
|
225e2732d1 | ||
|
|
768ad001d2 | ||
|
|
866d11988d | ||
|
|
d82ae99b6a | ||
|
|
eb4f6f1b09 | ||
|
|
23341b93c7 | ||
|
|
32b778f961 | ||
|
|
b99f4904b0 | ||
|
|
17b1c12286 | ||
|
|
c79824e358 | ||
|
|
f742feca4b | ||
|
|
de8971bea6 | ||
|
|
569e003827 | ||
|
|
c47c130fc3 | ||
|
|
2db5dd59af | ||
|
|
8a8504dca9 | ||
|
|
7e82c6a802 | ||
|
|
3946fda013 | ||
|
|
db30b45267 | ||
|
|
01377b6013 | ||
|
|
b38be38169 | ||
|
|
b9ac4a1c18 | ||
|
|
bdc6251474 | ||
|
|
479cf5c4a0 | ||
|
|
dbea497cc5 | ||
|
|
94af73a810 | ||
|
|
a7fd6a8e16 | ||
|
|
2b3502161c | ||
|
|
8039ab8281 | ||
|
|
0544a72011 | ||
|
|
34ba09ce1b | ||
|
|
2bfe653ac0 | ||
|
|
aa5a71ae68 | ||
|
|
9067e645b3 | ||
|
|
10d3fc096a | ||
|
|
7fd95ba6f9 | ||
|
|
b4982e07b8 | ||
|
|
6cc2a02df4 | ||
|
|
351e1091ce | ||
|
|
e707637c88 | ||
|
|
5da89e8ee7 | ||
|
|
794691f05e | ||
|
|
e58b84a01b | ||
|
|
3d51f003c0 | ||
|
|
b5a99e5f59 | ||
|
|
afca685fd4 | ||
|
|
f9ff279895 | ||
|
|
4cde9b67c1 | ||
|
|
261941452a | ||
|
|
0f107ff29d | ||
|
|
a860650dfb | ||
|
|
63d2dd1f4f | ||
|
|
8d765c2825 | ||
|
|
80d93c1631 | ||
|
|
872b3d08c0 | ||
|
|
5e69a9b6f0 | ||
|
|
47cb11d07b | ||
|
|
8576ef83b5 | ||
|
|
cb191817a8 | ||
|
|
8198fda45b | ||
|
|
37374cb754 | ||
|
|
e80b8953a0 | ||
|
|
9e36edec7f | ||
|
|
3204bba71b | ||
|
|
3cdcf6a6f7 | ||
|
|
ec9311c76b | ||
|
|
1d1141b59a | ||
|
|
8fd1d59fe2 | ||
|
|
922861c872 | ||
|
|
4a3945f1e4 | ||
|
|
a1caa1b860 | ||
|
|
166dea2b86 | ||
|
|
3f7262e213 | ||
|
|
231ee10ff8 | ||
|
|
5aa9ab4f39 | ||
|
|
8c46f7ca06 | ||
|
|
23e15daa37 | ||
|
|
dd56ed60ad | ||
|
|
18129905d8 | ||
|
|
4c85a7d249 | ||
|
|
f54ce13711 | ||
|
|
fb12eadf65 | ||
|
|
09d4c2d26e | ||
|
|
bb3179f0e4 | ||
|
|
e8b309460e | ||
|
|
b8dac5dc72 | ||
|
|
ed0736dcde | ||
|
|
edc5bb52af | ||
|
|
37ac927c45 | ||
|
|
d03263a3c6 | ||
|
|
be46bcbd17 | ||
|
|
bf9a34cbe8 | ||
|
|
201dbf577f | ||
|
|
fc961e2946 | ||
|
|
73cafc9786 | ||
|
|
e401455f31 | ||
|
|
254986b48b | ||
|
|
4c1615853c | ||
|
|
884dd71ca7 | ||
|
|
70efdc9db5 | ||
|
|
36549e7281 | ||
|
|
c1ffc33834 | ||
|
|
c276ae0c5e | ||
|
|
f67e065c5e | ||
|
|
18a11ab5fa | ||
|
|
6a7eb1f584 | ||
|
|
214ff1a435 | ||
|
|
d7cc579335 | ||
|
|
2c3961644c | ||
|
|
9b53c1ae08 | ||
|
|
b4ed061a53 | ||
|
|
4840a95097 | ||
|
|
08a7a4d6bc | ||
|
|
ddaaa8fc92 | ||
|
|
c02ac6f425 | ||
|
|
2fe3631a0d | ||
|
|
e0cdba00be | ||
|
|
5e206dd210 | ||
|
|
2008a5a9ee | ||
|
|
8bda55c653 | ||
|
|
53aeeccc2a | ||
|
|
c7738a6d6c | ||
|
|
baf29df950 | ||
|
|
0a13f34092 | ||
|
|
0b45361135 | ||
|
|
cff7b7da30 | ||
|
|
83420c76b8 | ||
|
|
42f83bcd24 | ||
|
|
3a253df58a | ||
|
|
197c2583ed | ||
|
|
10f5d42122 | ||
|
|
816b6b2ca8 | ||
|
|
ccfbe6ae32 | ||
|
|
64ed53cf4d | ||
|
|
c8e9fc54ed | ||
|
|
21debe2f77 | ||
|
|
6927f77f86 | ||
|
|
9c86058fe1 | ||
|
|
8126fb844a | ||
|
|
23c9ddf4ce | ||
|
|
c4291ceda5 | ||
|
|
8dfd7cc290 | ||
|
|
0e4f662dfd | ||
|
|
e5498ef04b | ||
|
|
7baebf2cbc | ||
|
|
a4c14433cd | ||
|
|
63388ccc90 | ||
|
|
043fd3d4a8 | ||
|
|
4a797808c1 | ||
|
|
bda3228d0f | ||
|
|
eda0b6b813 | ||
|
|
6dd09971f1 | ||
|
|
95ca40913f | ||
|
|
23424b5eee | ||
|
|
8bfe1c9ab2 | ||
|
|
4bd5276fc5 | ||
|
|
92ed3233af | ||
|
|
3a81b822f2 | ||
|
|
2c1e4d18fc | ||
|
|
3f190dfff6 | ||
|
|
6cc02da7a4 | ||
|
|
0dc981819f | ||
|
|
c87ccf8788 | ||
|
|
dcaa2d5ef3 | ||
|
|
e0715ce177 | ||
|
|
3333f1c8e6 | ||
|
|
4b7ada9362 | ||
|
|
71c5dfb8dd | ||
|
|
7e3911dbd6 | ||
|
|
839d31b9ca | ||
|
|
8e757ab9db | ||
|
|
de7e66afb4 | ||
|
|
63050b0efa | ||
|
|
386fdade59 | ||
|
|
0cbbc3b934 | ||
|
|
f5a7efb324 | ||
|
|
c4592a026a | ||
|
|
c981b83284 | ||
|
|
927bb7cb3a | ||
|
|
725976b5c0 | ||
|
|
cdbe6a855f | ||
|
|
a1c96e9e98 | ||
|
|
1488805242 | ||
|
|
cf681125a6 | ||
|
|
abc3ca184d | ||
|
|
7dcef46829 | ||
|
|
36a7654973 | ||
|
|
5b12f81b8f | ||
|
|
7c88b609f7 | ||
|
|
f5051225ea | ||
|
|
5af4f0f27b | ||
|
|
f7218fc98a | ||
|
|
267c022d58 | ||
|
|
cf115b769f | ||
|
|
774144846d | ||
|
|
0fc2844928 | ||
|
|
3b2f6c386d | ||
|
|
987e5fcbfd | ||
|
|
335872eaec | ||
|
|
df24e7c2a8 | ||
|
|
3b5fee047b | ||
|
|
9bcc8b95e7 | ||
|
|
c9e3ff0d91 | ||
|
|
474ad1ab26 | ||
|
|
9ea3474d43 | ||
|
|
a26bd5ea5b | ||
|
|
7f1fe42ace | ||
|
|
4ee0eab653 | ||
|
|
fe92ba3c27 | ||
|
|
099e000f88 | ||
|
|
7fa4538667 | ||
|
|
91e11a7857 | ||
|
|
e8870d3bcb | ||
|
|
d582293e5f | ||
|
|
9152782a65 | ||
|
|
0dc378285c | ||
|
|
d8c5344451 | ||
|
|
d23a16905d | ||
|
|
2649ce286b | ||
|
|
2f9e97b65b | ||
|
|
c83a13d680 | ||
|
|
403946c50a | ||
|
|
bdc7c64c61 | ||
|
|
181730bcde | ||
|
|
d79e0e585a | ||
|
|
678af2f06e | ||
|
|
dbda77a75b | ||
|
|
0459c0b231 | ||
|
|
e1940043e9 | ||
|
|
7f1c804a0c | ||
|
|
d07bb6074d | ||
|
|
82d67bb4c6 | ||
|
|
3d7dcb6d0e | ||
|
|
ed54fe9646 | ||
|
|
85ef1805e5 | ||
|
|
4109691eea | ||
|
|
4eaac5dbf1 | ||
|
|
07a625e03b | ||
|
|
b99fe8daf1 | ||
|
|
3f4e3581dd | ||
|
|
f00627270f | ||
|
|
a46f24d6d7 | ||
|
|
ee19f9ca59 | ||
|
|
b9e9814664 | ||
|
|
8303fa3860 | ||
|
|
6d9042ac0f | ||
|
|
26f64988ef | ||
|
|
12a0a37d24 | ||
|
|
2e4f2428f0 | ||
|
|
c8c11b19de | ||
|
|
45a500817f | ||
|
|
706cebfeae | ||
|
|
8a352a8e69 | ||
|
|
999fd610af | ||
|
|
dd6aff5ebf | ||
|
|
bc3c841b89 | ||
|
|
99ea453d23 | ||
|
|
71389a104c | ||
|
|
6e2ebe9025 | ||
|
|
29e39f98af | ||
|
|
5192f3e3c0 | ||
|
|
95c8416754 | ||
|
|
b102c4feba | ||
|
|
daff1610e3 | ||
|
|
ee7f5e3a07 | ||
|
|
054dcc4eee | ||
|
|
1f1f72451b | ||
|
|
1858739bb9 | ||
|
|
3d320d0e19 | ||
|
|
9d2c0afb98 | ||
|
|
3d0160f21f | ||
|
|
ae51b8273f | ||
|
|
defe2a8e9b | ||
|
|
28aa932676 | ||
|
|
4aa2d0a62c | ||
|
|
29f2a9169e | ||
|
|
493acc9ebd | ||
|
|
1d8d9c7b3d | ||
|
|
d3bdc58994 | ||
|
|
20efccb4d9 | ||
|
|
f58daf3bac | ||
|
|
83de317308 | ||
|
|
84b1fd07ae | ||
|
|
b42810d29a | ||
|
|
e105f52fea | ||
|
|
2e6a75141b | ||
|
|
0aa0126caf | ||
|
|
f637f096f9 | ||
|
|
5ecdd37187 | ||
|
|
7f497f60af | ||
|
|
7a019b063b | ||
|
|
e5e20a789a | ||
|
|
8883f5ba55 | ||
|
|
d64a694e20 | ||
|
|
a88f8ab33e | ||
|
|
5e3d263750 | ||
|
|
70136aa65d | ||
|
|
b514bdc472 | ||
|
|
20cc2ca248 | ||
|
|
5031f0c582 | ||
|
|
25287dc3d9 | ||
|
|
5527ad8c41 | ||
|
|
75525ec7a8 | ||
|
|
21e967473b | ||
|
|
c67b5844b6 | ||
|
|
ced62ec0c4 | ||
|
|
84bbaa09da | ||
|
|
dfa35542c5 | ||
|
|
a6348050fd | ||
|
|
4d700c3566 | ||
|
|
f2d7e947d7 | ||
|
|
3c65e6f8f5 | ||
|
|
ce60e5f5fb | ||
|
|
c9d85a8ce4 | ||
|
|
5cfd7d65ec | ||
|
|
1efe2dbe89 | ||
|
|
b2260e0b61 | ||
|
|
3c2ca24dea | ||
|
|
2acbeb83d0 | ||
|
|
e0956e05a6 | ||
|
|
e67492853c | ||
|
|
0f8b6cd6d0 | ||
|
|
b11658e1d6 | ||
|
|
bcf5d3caec | ||
|
|
474676af17 | ||
|
|
3b8307b674 | ||
|
|
36e56dcaef | ||
|
|
e42e28d062 | ||
|
|
0786053022 | ||
|
|
e56938f7ff | ||
|
|
791ec1ae2d | ||
|
|
3cc0e9de14 | ||
|
|
b8b0b24b0e | ||
|
|
ff7be74437 | ||
|
|
f52f22e80f | ||
|
|
86e00d48dc | ||
|
|
afbebb9dfc | ||
|
|
bf61f6f76a | ||
|
|
62c41297c4 | ||
|
|
4e4942313a | ||
|
|
09b5cc3798 | ||
|
|
fe76864a05 | ||
|
|
155a727a77 | ||
|
|
a52dacf500 | ||
|
|
e8e38310ee | ||
|
|
2652e2cfe0 | ||
|
|
5a76ae8a88 | ||
|
|
7d9b97aac9 | ||
|
|
69c3183e35 | ||
|
|
2f800c960d | ||
|
|
e6fcbfbde4 | ||
|
|
ed4d1b73cb | ||
|
|
5e6477cddd | ||
|
|
c13cab394a | ||
|
|
73f1940cb0 | ||
|
|
8a35d232ef | ||
|
|
728981cfe6 | ||
|
|
11cb2b9044 | ||
|
|
2728b4058b | ||
|
|
e3dac52d7e | ||
|
|
d1d8a1eff3 | ||
|
|
cae9f94388 | ||
|
|
4502d55ce1 | ||
|
|
cad87496ac | ||
|
|
c1d6cd7b8e | ||
|
|
477426c384 | ||
|
|
3d3b978070 | ||
|
|
117082c862 | ||
|
|
b842905572 | ||
|
|
bfa03aabc0 | ||
|
|
f535cd1010 | ||
|
|
b388edb23c | ||
|
|
85fa9a8658 | ||
|
|
2f6d4ebec1 | ||
|
|
1c3cc5b61b | ||
|
|
db7584cb01 | ||
|
|
ec60a05b01 | ||
|
|
5ae56481c2 | ||
|
|
b842408f41 | ||
|
|
6e33a62ed9 | ||
|
|
36231a5eca | ||
|
|
90f0e4691b | ||
|
|
b41a317788 | ||
|
|
84fb81b245 | ||
|
|
e18f759fab | ||
|
|
ce9c7b17a2 | ||
|
|
c2d6f7fe37 | ||
|
|
9b18aa9cef | ||
|
|
5eccb58aa9 | ||
|
|
acce1364fa | ||
|
|
625c5f5fe2 | ||
|
|
dffa9d74a0 | ||
|
|
668a8ef844 | ||
|
|
df4d708981 | ||
|
|
c48a46c7ab | ||
|
|
8079d7d6af | ||
|
|
da844fb3a7 | ||
|
|
3e1f89d90f | ||
|
|
559e4ee352 | ||
|
|
a1d43dc65c | ||
|
|
d26cd90b02 | ||
|
|
7c8eef1715 | ||
|
|
45f72f7333 | ||
|
|
196d31a084 | ||
|
|
aaf898fb4c | ||
|
|
f10b3179c2 | ||
|
|
533e89c919 | ||
|
|
2f0448a98e | ||
|
|
aab8cf9622 | ||
|
|
5e0693e057 | ||
|
|
1708555133 | ||
|
|
c38d95fd60 | ||
|
|
667f7b2094 | ||
|
|
d17909df41 | ||
|
|
88113fca1c | ||
|
|
2e0bb5aa84 | ||
|
|
81fc947c9d | ||
|
|
c684440e65 | ||
|
|
4c6222acf1 | ||
|
|
2131ecc315 | ||
|
|
f53c72f31f | ||
|
|
1d3910c157 | ||
|
|
3b2f5c2d5d | ||
|
|
903cdaad45 | ||
|
|
386fc61a3f | ||
|
|
6e354690c5 | ||
|
|
adae670318 | ||
|
|
bdbefbf600 | ||
|
|
939089a79c | ||
|
|
f8354344ff | ||
|
|
e596c1f0a6 | ||
|
|
7ae8d42731 | ||
|
|
7f53badcf3 | ||
|
|
1dcf01bb0e | ||
|
|
eec25ab1c4 | ||
|
|
f90f093385 | ||
|
|
befe56fd44 | ||
|
|
47d91424c5 | ||
|
|
ddd72f71d2 | ||
|
|
1a1ff2ec30 | ||
|
|
10d89279bc | ||
|
|
a6f9ba7526 | ||
|
|
19dfe45b0b | ||
|
|
f584e21480 | ||
|
|
6acacbfcf4 | ||
|
|
52a79eca60 | ||
|
|
70faadb27e | ||
|
|
2eb1809f36 | ||
|
|
d9febf8010 | ||
|
|
d4c5787360 | ||
|
|
c8c461e8e8 | ||
|
|
9e2da003f1 | ||
|
|
ae41483bb7 | ||
|
|
d062b8a7d4 | ||
|
|
18825dd0c3 | ||
|
|
6b2ea58b66 | ||
|
|
fdfb37d4d0 | ||
|
|
450de39f8c | ||
|
|
c87ad8ea1b | ||
|
|
b336651503 | ||
|
|
7a1949fc6f | ||
|
|
35a63d7c5c | ||
|
|
031f5e2ed8 | ||
|
|
189b4b7599 | ||
|
|
6ada32cb9f | ||
|
|
5491c524c5 | ||
|
|
8d29f25101 | ||
|
|
28d4b2d831 | ||
|
|
399645a80a | ||
|
|
9d13809d01 | ||
|
|
e8c8db7383 | ||
|
|
b41814ed0c | ||
|
|
d71f2043de | ||
|
|
87ba3e8fa2 | ||
|
|
a9e65af77b | ||
|
|
eabbbf456f | ||
|
|
ebfba7ac8c | ||
|
|
fe4a4a420e | ||
|
|
14ae432833 | ||
|
|
009a38f3ca | ||
|
|
d21ecc975f | ||
|
|
cfc73e4094 | ||
|
|
748be6faa5 | ||
|
|
452509281a | ||
|
|
330e2e5c69 | ||
|
|
343a3f81bf | ||
|
|
13c7d5a0c5 | ||
|
|
a9c38b356a | ||
|
|
4181257afd | ||
|
|
0141ed56c2 | ||
|
|
35dc205810 | ||
|
|
d10a17eaf6 | ||
|
|
a623c53fa5 | ||
|
|
3db8babee7 | ||
|
|
ca7ac992e2 | ||
|
|
a956c9894e | ||
|
|
6c84ba6aeb | ||
|
|
e99b7d8162 | ||
|
|
09bb613929 | ||
|
|
761b0dd502 | ||
|
|
8c72cb3b72 | ||
|
|
35b6f4ae54 | ||
|
|
2e3602eee6 | ||
|
|
cf5ade639a | ||
|
|
0dfd5efa97 | ||
|
|
e6cbb9dfd8 | ||
|
|
52c7215cd8 | ||
|
|
fe88732a80 | ||
|
|
aa5f85a3c1 | ||
|
|
843519c3b5 | ||
|
|
c74917d1d9 | ||
|
|
9dca199d78 | ||
|
|
4fa7542aca | ||
|
|
1cd24b5dd5 | ||
|
|
34f1bf5e6a | ||
|
|
675e5f58d1 | ||
|
|
127fb41145 | ||
|
|
8abf32bb53 | ||
|
|
b567e5df13 | ||
|
|
40acdafed2 | ||
|
|
7f6b05e4e5 | ||
|
|
0d4a698c11 | ||
|
|
5bacfb04b5 | ||
|
|
1e8514a0bc | ||
|
|
b6714dd8a4 | ||
|
|
e05c2a03e0 | ||
|
|
914df505ae | ||
|
|
7e59ae6b66 | ||
|
|
eb84a23d7e | ||
|
|
1076120516 | ||
|
|
54ce26adbc | ||
|
|
28d54b615b | ||
|
|
424fa576fb | ||
|
|
7f8e5fe9f9 | ||
|
|
47f1bd012c | ||
|
|
0c2e762cee | ||
|
|
68124e6abb | ||
|
|
5587e6b6a3 | ||
|
|
ac1e98fbaa | ||
|
|
d25f9f3a01 | ||
|
|
fb638752eb | ||
|
|
8c3dd62f6d | ||
|
|
e79635b81a | ||
|
|
e3a9851de6 | ||
|
|
34811d4571 | ||
|
|
3167a9a6e3 | ||
|
|
a29d1f0cc2 | ||
|
|
7dfd535841 | ||
|
|
e76cddd45b | ||
|
|
39d928b5b1 | ||
|
|
3c214f4725 | ||
|
|
80861938f3 | ||
|
|
401f2dba13 | ||
|
|
525695072a | ||
|
|
c4d7c516ef | ||
|
|
2f11b1185b | ||
|
|
42274a71b7 | ||
|
|
f1fcfa9ee4 | ||
|
|
afcfbbbf61 | ||
|
|
defba2962d | ||
|
|
4c7666169c | ||
|
|
5580b4301f | ||
|
|
972a4ce789 | ||
|
|
421ff8cb40 | ||
|
|
879aadc068 | ||
|
|
96b95e0eb9 | ||
|
|
cea2d39df8 | ||
|
|
f4eae0d33e | ||
|
|
716a20cc22 | ||
|
|
873a74492a | ||
|
|
516d93d6fa | ||
|
|
958a8ffe2c | ||
|
|
0286e2a92e | ||
|
|
01e339cc61 | ||
|
|
0e7c9b4a96 | ||
|
|
d5814043d9 | ||
|
|
e81210ec04 | ||
|
|
8d17623d3a | ||
|
|
ba9d7c8172 | ||
|
|
06f5a3cde0 | ||
|
|
25417dcda1 | ||
|
|
9a3b332130 | ||
|
|
1236a24b61 | ||
|
|
f50de743e3 | ||
|
|
0c2568aad0 | ||
|
|
b15cbeb568 | ||
|
|
afdc06638f | ||
|
|
6fb610d9aa | ||
|
|
c14d536133 | ||
|
|
3008ae2eeb | ||
|
|
3b4d9df0e8 | ||
|
|
48d4a5e135 | ||
|
|
ff33565513 | ||
|
|
b40bae1b50 | ||
|
|
0533d229e6 | ||
|
|
bbb755bf56 | ||
|
|
31caee87db | ||
|
|
87cda451f3 | ||
|
|
e2b8f901a3 | ||
|
|
951e2c1f89 | ||
|
|
20fd291cc3 | ||
|
|
ee3ddce41d | ||
|
|
fb160e712b | ||
|
|
9a6cc1779f | ||
|
|
b459d0fbcb | ||
|
|
9816a9c46a | ||
|
|
f4b8f9d65d | ||
|
|
08e8d7343c | ||
|
|
5505791b6e | ||
|
|
1862477641 | ||
|
|
ff9daa2bfd | ||
|
|
23b13e3fdc | ||
|
|
f93f2674df | ||
|
|
1d7d34b7c1 | ||
|
|
9837a7af71 | ||
|
|
d3ef4094c6 | ||
|
|
bf86291016 | ||
|
|
37ace8b34c | ||
|
|
e170790e4c | ||
|
|
0fe1aa983c | ||
|
|
180eb1f59d | ||
|
|
9ca61dd60d | ||
|
|
52a0635810 | ||
|
|
2337b4cce2 | ||
|
|
6f51b90178 | ||
|
|
162e18142c | ||
|
|
d4797617a6 | ||
|
|
be67395f13 | ||
|
|
20e17861e1 | ||
|
|
deb7375d6b | ||
|
|
2767260505 | ||
|
|
bba4a8eeba | ||
|
|
c9786adc77 | ||
|
|
407051287d | ||
|
|
3d178dd6bc | ||
|
|
8ddedc60ac | ||
|
|
ddb8031e55 | ||
|
|
46cf24c193 | ||
|
|
82ab1376cc | ||
|
|
2c27a67cc3 | ||
|
|
5ea68435ed | ||
|
|
58ca85ce90 | ||
|
|
2ea207a63a | ||
|
|
e47c00f0b6 | ||
|
|
7483d351c3 | ||
|
|
83a3810301 | ||
|
|
c6309bf14d | ||
|
|
c10a2ae1c8 | ||
|
|
3dd09d9fc7 | ||
|
|
46f05dbfa0 | ||
|
|
823d1d7812 | ||
|
|
a274b5a261 | ||
|
|
8737d1eb0a | ||
|
|
a123588e32 | ||
|
|
cc91225b01 | ||
|
|
af8db9457f | ||
|
|
5860cf3a22 | ||
|
|
9d6cc405a9 | ||
|
|
1c37591bab | ||
|
|
c7c69ea5a7 | ||
|
|
cdaaa34569 | ||
|
|
17637146be | ||
|
|
b4033071a1 | ||
|
|
0c66a8f3b7 | ||
|
|
ef7bae98d4 | ||
|
|
d2a1f5e48b | ||
|
|
69b717f517 | ||
|
|
6d0461eaef | ||
|
|
be72a594d7 | ||
|
|
8cc4f58076 | ||
|
|
3f07739756 |
@@ -27,6 +27,8 @@ settings.json
|
||||
.npmrc
|
||||
.cursor
|
||||
.agent
|
||||
CLAUDE.MD
|
||||
|
||||
apps/**/tsconfig.tsbuildinfo
|
||||
packages/**/tsconfig.tsbuildinfo
|
||||
logs/
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Providers } from "@/app/providers";
|
||||
import "@/app/styles/globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "행정지원시스템",
|
||||
title: "유역하수도통합플랫폼 Hasuon",
|
||||
description: "행정지원시스템",
|
||||
};
|
||||
|
||||
|
||||
@@ -19,11 +19,15 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@common/components": ["../../packages/common/components/dist/"],
|
||||
"@common/network": ["../../packages/common/network/"]
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
"../../packages/common/types/**/*.d.ts"
|
||||
],
|
||||
"exclude": ["node_modules", ".next", "dist", "coverage", "storybook-static", "public"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import "@/app/styles/globals.css";
|
||||
|
||||
export const metadata = {
|
||||
title: "유역하수도통합플랫폼 Hasuon",
|
||||
};
|
||||
|
||||
export default function AuthLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="ko">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { CodeManagementPage as default } from "@/pages/code-management";
|
||||
@@ -0,0 +1,3 @@
|
||||
import { DashboardPage } from "@/pages/dashboard/ui/dashboard-page";
|
||||
|
||||
export default DashboardPage;
|
||||
@@ -0,0 +1,10 @@
|
||||
import { DesignEditPage } from "@/pages/design-cnstn";
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export default async function Page({ params }: PageProps) {
|
||||
const { id } = await params;
|
||||
return <DesignEditPage id={id} />;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { DesignDetailGate } from "@/pages/design-cnstn";
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export default async function Page({ params }: PageProps) {
|
||||
const { id } = await params;
|
||||
return <DesignDetailGate id={id} />;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Suspense } from "react";
|
||||
|
||||
import { DesignListPage } from "@/pages/design-cnstn";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Suspense>
|
||||
<DesignListPage />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { DesignRegistPage } from "@/pages/design-cnstn";
|
||||
import { parseTaskSeComCdFromApi } from "@/pages/design-cnstn/lib/design-cnstn-regist-schema";
|
||||
|
||||
interface PageProps {
|
||||
searchParams: Promise<{
|
||||
taskSeComCd?: string;
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export default async function Page({ searchParams }: PageProps) {
|
||||
const params = await searchParams;
|
||||
const taskSeComCd = parseTaskSeComCdFromApi(params.taskSeComCd);
|
||||
|
||||
return (
|
||||
<DesignRegistPage
|
||||
defaults={{
|
||||
taskSeComCd: taskSeComCd.length ? taskSeComCd : undefined,
|
||||
admdstCd: params.admdstCd,
|
||||
sido: params.sido,
|
||||
gugun: params.gugun,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { FnrsEditPage } from "@/pages/fnrs-cnsltn";
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export default async function Page({ params }: PageProps) {
|
||||
const { id } = await params;
|
||||
return <FnrsEditPage id={id} />;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { FnrsDetailGate } from "@/pages/fnrs-cnsltn";
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export default async function Page({ params }: PageProps) {
|
||||
const { id } = await params;
|
||||
return <FnrsDetailGate id={id} />;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Suspense } from "react";
|
||||
|
||||
import { FnrsListPage } from "@/pages/fnrs-cnsltn";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Suspense>
|
||||
<FnrsListPage />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { FnrsRegistPage } from "@/pages/fnrs-cnsltn";
|
||||
import { parseTaskSeComCdFromApi } from "@/pages/fnrs-cnsltn/lib/fnrs-cnsltn-regist-schema";
|
||||
|
||||
interface PageProps {
|
||||
searchParams: Promise<{
|
||||
taskSeComCd?: string;
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export default async function Page({ searchParams }: PageProps) {
|
||||
const params = await searchParams;
|
||||
const taskSeComCd = parseTaskSeComCdFromApi(params.taskSeComCd);
|
||||
|
||||
return (
|
||||
<FnrsRegistPage
|
||||
defaults={{
|
||||
taskSeComCd: taskSeComCd.length ? taskSeComCd : undefined,
|
||||
admdstCd: params.admdstCd,
|
||||
sido: params.sido,
|
||||
gugun: params.gugun,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { InstlEditPage } from "@/pages/instl-sncn";
|
||||
|
||||
interface InstlSncnEditRouteProps {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export default async function Page({ params }: InstlSncnEditRouteProps) {
|
||||
const { id } = await params;
|
||||
return <InstlEditPage id={id} />;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { InstlSncnDetailGate } from "@/pages/instl-sncn";
|
||||
|
||||
export default async function InstlSncnDetailPage({ params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
return <InstlSncnDetailGate id={id} />;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Suspense } from "react";
|
||||
|
||||
import { InstlListPage } from "@/pages/instl-sncn";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Suspense>
|
||||
<InstlListPage />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { InstlRegistPage } from "@/pages/instl-sncn";
|
||||
|
||||
interface InstlSncnRegistRouteProps {
|
||||
searchParams: Promise<{
|
||||
taskSeComCd?: string;
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export default async function Page({ searchParams }: InstlSncnRegistRouteProps) {
|
||||
const params = await searchParams;
|
||||
const taskSeComCd = params.taskSeComCd
|
||||
? params.taskSeComCd.split(",").filter(Boolean)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<InstlRegistPage
|
||||
defaults={{
|
||||
taskSeComCd,
|
||||
admdstCd: params.admdstCd,
|
||||
sido: params.sido,
|
||||
gugun: params.gugun,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { MyPbadmsSprtListPage } from "@/pages/my-pbadms-sprt";
|
||||
|
||||
export default MyPbadmsSprtListPage;
|
||||
@@ -0,0 +1,3 @@
|
||||
import { NtiHstryListPage } from "@/pages/nti-hstry";
|
||||
|
||||
export default NtiHstryListPage;
|
||||
@@ -0,0 +1,3 @@
|
||||
import { NtitlkSndngPage } from "@/pages/ntitlk-sndng";
|
||||
|
||||
export default NtitlkSndngPage;
|
||||
@@ -0,0 +1,13 @@
|
||||
import { SewerBscPlanEditPage } from "@/pages/sewer-bsc-plan";
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
searchParams: Promise<{ chgCycl?: string }>;
|
||||
}
|
||||
|
||||
export default async function Page({ params, searchParams }: PageProps) {
|
||||
const { id } = await params;
|
||||
const { chgCycl } = await searchParams;
|
||||
const propChgCycl = chgCycl ? Number(chgCycl) : undefined;
|
||||
return <SewerBscPlanEditPage id={id} propChgCycl={propChgCycl} />;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { SewerBscPlanDetailGate } from "@/pages/sewer-bsc-plan";
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
searchParams: Promise<{ chgCycl?: string }>;
|
||||
}
|
||||
|
||||
export default async function Page({ params, searchParams }: PageProps) {
|
||||
const { id } = await params;
|
||||
const { chgCycl } = await searchParams;
|
||||
const propChgCycl = chgCycl ? Number(chgCycl) : undefined;
|
||||
return <SewerBscPlanDetailGate id={id} propChgCycl={propChgCycl} />;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Suspense } from "react";
|
||||
|
||||
import { SewerBscPlanListPage } from "@/pages/sewer-bsc-plan";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Suspense>
|
||||
<SewerBscPlanListPage />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { SewerBscPlanRegistPage } from "@/pages/sewer-bsc-plan";
|
||||
|
||||
interface PageProps {
|
||||
searchParams: Promise<{
|
||||
taskSeComCd?: string;
|
||||
taskSeCdNm?: string;
|
||||
sewerBscPlanSeComCd?: string;
|
||||
sewerBscPlanSeCdNm?: string;
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export default async function Page({ searchParams }: PageProps) {
|
||||
const params = await searchParams;
|
||||
|
||||
return <SewerBscPlanRegistPage defaults={params} />;
|
||||
}
|
||||
@@ -6,8 +6,8 @@ import { Providers } from "@/app/providers";
|
||||
import "@/app/styles/globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "행정지원시스템",
|
||||
description: "행정지원시스템",
|
||||
title: "유역하수도통합플랫폼 Hasuon",
|
||||
description: "디지털 행정지원 시스템",
|
||||
};
|
||||
|
||||
interface RootLayoutProps {
|
||||
@@ -1 +0,0 @@
|
||||
export { AcntgCodeManagementPage as default } from "@/pages/acntg-code-management";
|
||||
@@ -1 +0,0 @@
|
||||
export { CnstpCodeManagementPage as default } from "@/pages/cnstp-code-management";
|
||||
@@ -1,10 +0,0 @@
|
||||
import { CnfmModifyPage } from "@/pages/instl-sncn";
|
||||
|
||||
export default async function InstlSncnModifyPage({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ id: string }>;
|
||||
}) {
|
||||
const { id } = await params;
|
||||
return <CnfmModifyPage id={id} />;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import { CnfmViewPage } from "@/pages/instl-sncn";
|
||||
|
||||
export default async function InstlSncnViewPage({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ id: string }>;
|
||||
}) {
|
||||
const { id } = await params;
|
||||
return <CnfmViewPage id={id} />;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import { CnfmListPage } from "@/pages/instl-sncn";
|
||||
|
||||
export default CnfmListPage;
|
||||
@@ -1,5 +0,0 @@
|
||||
import { CnfmRegistPage } from "@/pages/instl-sncn";
|
||||
|
||||
export default function Page(props: any) {
|
||||
return <CnfmRegistPage {...props} />;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { MainPage as default } from "@/pages/home";
|
||||
@@ -0,0 +1,10 @@
|
||||
import { cookies } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { COOKIE_DOMAIN, REFRESH_TOKEN } from "@/shared/config";
|
||||
|
||||
export async function POST() {
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.delete({ name: REFRESH_TOKEN, domain: COOKIE_DOMAIN });
|
||||
return NextResponse.json({ message: "Logged out" }, { status: 200 });
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
ACCESS_TOKEN,
|
||||
AUTH_USER_ID,
|
||||
CLAIM_NAME,
|
||||
COOKIE_DOMAIN,
|
||||
REFRESH_TOKEN,
|
||||
SERVER_API_URL,
|
||||
SITE_ID,
|
||||
@@ -20,6 +21,10 @@ async function handler(
|
||||
"Content-Type": "application/json",
|
||||
"X-Site-Id": SITE_ID,
|
||||
};
|
||||
const deviceId = request.headers.get("X-Device-Id");
|
||||
if (deviceId) {
|
||||
headers["X-Device-Id"] = deviceId;
|
||||
}
|
||||
let body = {};
|
||||
const isRefreshHandler = params.url.includes("refresh");
|
||||
|
||||
@@ -39,27 +44,13 @@ async function handler(
|
||||
}
|
||||
|
||||
const targetUrl = `${SERVER_API_URL}/${params.url.join("/")}`;
|
||||
console.log(`[Proxy API] ${method} ${params.url.join("/")} -> ${targetUrl}`);
|
||||
console.log(`[Proxy API] Headers:`, headers);
|
||||
if (!isRefreshHandler) {
|
||||
console.log(`[Proxy API] Body:`, body);
|
||||
}
|
||||
|
||||
const result = await fetch(targetUrl, {
|
||||
method,
|
||||
headers,
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
console.log(`[Proxy API] Response Status: ${result.status}`);
|
||||
console.log(`[Proxy API] Response Headers:`, {
|
||||
[ACCESS_TOKEN]: result.headers.get(ACCESS_TOKEN),
|
||||
[REFRESH_TOKEN]: result.headers.get(REFRESH_TOKEN) ? '***hidden***' : undefined,
|
||||
[AUTH_USER_ID]: result.headers.get(AUTH_USER_ID),
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
console.error(`[Proxy API] Request failed with status ${result.status}`);
|
||||
return NextResponse.json({ message: "Invalid Credentials" }, { status: 401 });
|
||||
}
|
||||
|
||||
@@ -68,24 +59,16 @@ async function handler(
|
||||
const userId = result.headers.get(AUTH_USER_ID);
|
||||
|
||||
if (accessToken && userId) {
|
||||
console.log(`[Proxy API] Login successful for user: ${userId}`);
|
||||
const response = NextResponse.json({
|
||||
[ACCESS_TOKEN]: accessToken,
|
||||
[AUTH_USER_ID]: userId,
|
||||
});
|
||||
|
||||
const forwardedHost = request.headers.get("x-forwarded-host");
|
||||
const host = request.headers.get("host");
|
||||
const actualHost = forwardedHost || host || new URL(request.url).hostname.toString();
|
||||
|
||||
// 운영 환경에서 domain 설정
|
||||
const domain = actualHost.includes("hasuon.or.kr") ? ".hasuon.or.kr" : actualHost;
|
||||
|
||||
if (refreshToken) {
|
||||
cookieStore.set(REFRESH_TOKEN, refreshToken, {
|
||||
httpOnly: true,
|
||||
sameSite: "strict",
|
||||
domain: domain,
|
||||
domain: COOKIE_DOMAIN,
|
||||
path: "/",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { Metadata } from "next";
|
||||
import Image from "next/image";
|
||||
|
||||
import "@/app/styles/globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "유역하수도통합플랫폼 Hasuon",
|
||||
description: "페이지가 존재하지 않습니다. 관리자에게 문의하여 주십시오.",
|
||||
};
|
||||
|
||||
export default function GlobalNotFound() {
|
||||
return (
|
||||
<html lang="ko">
|
||||
<body>
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-[#f0f4f8] px-4 py-16">
|
||||
<div className="mb-16 text-center">
|
||||
<h1 className="text-[3.2rem] font-bold leading-snug tracking-tight">
|
||||
<span className="text-primary">디지털 행정지원 시스템</span>에 오신 것을 환영합니다.
|
||||
</h1>
|
||||
<p className="mt-6 text-[2rem] text-[#666]">오류가 발생하였습니다.</p>
|
||||
</div>
|
||||
|
||||
<section className="card card-border flex w-full max-w-[72rem] flex-col items-center !rounded-2xl !py-16">
|
||||
<Image
|
||||
src="/images/magnifying-glass-with-warning.png"
|
||||
alt=""
|
||||
width={280}
|
||||
height={280}
|
||||
className="size-[28rem] object-contain"
|
||||
/>
|
||||
<p className="mt-4 text-[2.4rem] font-bold text-[#444]">페이지가 존재하지 않습니다.</p>
|
||||
<p className="mt-2 text-[1.6rem] text-[#666]">관리자에게 문의하여 주십시오</p>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
# 재원협의·실무협의 프론트엔드 개발 가이드
|
||||
|
||||
> **대상 앱**: `frontend/apps/as`
|
||||
> **작성일**: 2026-08-27
|
||||
> **개정일**: 2026-09-07
|
||||
> **버전**: 2.0
|
||||
> **Process**: PR-AS-003 (재원협의 관리 — 실무협의 및 AI 검증 통합)
|
||||
>
|
||||
> **SoT (2026-09-03 완결)**:
|
||||
>
|
||||
> - 프로세스·상태·버튼: `03.재원협의_실무협의_프로세스_통합_v완결.md`
|
||||
> - REST 설계: `05.재원협의_상태별_endpoint_설계.md`
|
||||
> - 공통코드: `FNRSSTTS` (`SV, ST, LE, FV, ER, SL, AC, TE, TP, RM, RB, RC, RA, AV, EV, RK, RR, EP, TA`)
|
||||
>
|
||||
> **백엔드 서비스**:
|
||||
>
|
||||
> - `as-service` — `/api/v1/fnrs-cnsltn-mng`, `/api/v1/pwrk-cnsltn-mng`, `/api/v1/pwrk-cnsltn-doc-crt-rslt`, `/api/v1/dcrag-to`
|
||||
> - `as-elapr-service` — `/api/v1/elapr-dmnd`, `/api/v1/elapr-prgrs-stts`, `/api/v1/elapr-apln`
|
||||
>
|
||||
> **현재 프론트 상태**: 재원협의(`fnrs-cnsltn`)·전자결재(`elapr`)·DC RAG TO(`dcrag-to`)는 존재한다. 실무협의(`pwrk-cnsltn-`\*) 엔티티·화면은 **미구현**. 버튼 매트릭스·상태코드는 **v2.1 잔존**이며 v3.0(`FNRSSTTS`)과 불일치한다. [9절](#9-현재-코드-vs-to-be-갭) 참고.
|
||||
|
||||
---
|
||||
|
||||
## 1. 문서 목적
|
||||
|
||||
재원협의 4대 주체(기초·광역·환경청·공단)의 **상태 전이·버튼·API**를 `apps/as`에 구현할 때 쓰는 프론트엔드 가이드이다.
|
||||
|
||||
v1.0은 공단 접수자의 **자료검증 → 초안생성 → 웹기안기**만 다뤘다. v2.0은 2026-09-03 완결 프로세스 기준으로 **신청부터 최종종결(**`TA`**)까지**, 실무협의·AI 3파이프라인·결재선·보완 루프를 포함한다.
|
||||
|
||||
상세 표·시퀀스·DTO는 본문에 넣지 않고 레퍼런스로 분리한다. 구현 중에는 본문의 규칙만 보고, 표가 필요하면 해당 파일을 연다.
|
||||
|
||||
---
|
||||
|
||||
## 2. 문서 맵
|
||||
|
||||
| 파일 | 내용 | 언제 보는가 |
|
||||
| -------------------------------------------------------- | ------------------------------------------------------------------------- | ----------------------- |
|
||||
| [development-guide.md](./development-guide.md) (본 문서) | 도메인, 핵심 규칙, 화면 흐름, 갭, 구현 순서 | 일상 구현 |
|
||||
| [ref-process-status.md](./ref-process-status.md) | 4-Lane 시퀀스, Activity, `FNRSSTTS`, 보완 3루프, AI 타임아웃, 결재선 복사 | 상태 전이·폴링 UX |
|
||||
| [ref-screen-buttons.md](./ref-screen-buttons.md) | 38행 화면·역할·버튼 매트릭스, 버튼 가시성 | `button-config.ts` 개편 |
|
||||
| [ref-endpoint.md](./ref-endpoint.md) | 버튼→API 총괄, 단계별 입출력, FE 호출 금지 API, Gap Analysis | 엔티티·service 매핑 |
|
||||
| [ref-frontend-entities.md](./ref-frontend-entities.md) | ENDPOINT, 슬라이스, Service 시그니처, 폴링, 웹기안기, DTO | 엔티티 레이어 구현 |
|
||||
| [ref-webhwp-api.md](./ref-webhwp-api.md) | 웹한글기안기 v3 `HwpCtrl` Properties/Methods, Open/SaveAs | 기안기 위젯 연동 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 도메인 개요
|
||||
|
||||
실무협의서(PWRK)는 재원협의서(FNRS)의 **하위 문서**이다. 재원협의 1건당 실무협의서는 **1건만** 생성된다.
|
||||
|
||||
| 문서 | 번호 예시 | 필드 |
|
||||
| -------- | ----------------- | ----------------------------- |
|
||||
| 재원협의 | `F-20260824-0001` | `fnrsCnsltnDocNo` / `upDocNo` |
|
||||
| 실무협의 | `P-20260827-0001` | `pwrkCnsltnDocNo` |
|
||||
|
||||
진행상태는 **재원협의 마스터** `tb_as_fnrs_cnsltn_mng.prgrs_stts_com_cd` (`FNRSSTTS`)가 SSOT이다. 실무협의 문서의 `prgrsSttsComCd`는 연계 표시용이며, 화면 버튼은 재원협의 상태로 분기한다.
|
||||
|
||||
### 3-1. 4대 주체
|
||||
|
||||
| 역할 | 코드 | 화면 소유 | 핵심 구간 |
|
||||
| --------------- | ------------- | -------------- | ------------------------------------ |
|
||||
| 기초자치단체 | `ROLE_USER05` | 작성/수정/상세 | 신청, 3종 보완, 조치결과, 최종확인 |
|
||||
| 광역자치단체 | `ROLE_USER04` | 상세 | 경유 제출, 결과 전달 |
|
||||
| 유역·지방환경청 | `ROLE_USER03` | 상세 | 의뢰/자체종결, 1·2차 회신 |
|
||||
| 한국환경공단 | `ROLE_USER01` | 상세 + 결재선 | 파일검증, 검토자지정, 1·2차 기술검토 |
|
||||
|
||||
### 3-2. 핵심 식별자
|
||||
|
||||
| 필드 | 의미 | 비고 |
|
||||
| ----------------- | ---------------- | ----------------------------------------------------------- |
|
||||
| `fnrsCnsltnDocNo` | 재원협의문서번호 | 상태 전이·목록 PK |
|
||||
| `pwrkCnsltnDocNo` | 실무협의문서번호 | `P-YYYYMMDD-NNNN`. 검토자지정(`ER→AC`) 시 발급 |
|
||||
| `upDocNo` | 상위문서번호 | 재원협의 번호. `upDocSeComCd = "FNRS"` |
|
||||
| `crtDmndUuid` | 생성요청 UUID | 초안 폴링·웹기안기·다운로드 키 |
|
||||
| `verSn` | 버전일련번호 | 복합 PK `(crtDmndUuid, verSn)`. 저장 시 서버가 `+1` |
|
||||
| `orgnlOtptDocCn` | HWP 바이너리 | 목록/상세 응답은 항상 `null`. 다운로드·`webhwp/open`만 사용 |
|
||||
| `elaprCycl` | 결재 차수 | 1차 `TE`, 2차 `RK`. 금액검증 완료 후 1차 결재선 복사 |
|
||||
|
||||
### 3-3. IIPBS 약어
|
||||
|
||||
| 한글 | 약어 | 필드 예 |
|
||||
| ---- | ------------ | --------------------------- |
|
||||
| 재원 | FNRS | `fnrsCnsltnDocNo` |
|
||||
| 실무 | PWRK | `pwrkCnsltnDocNo` |
|
||||
| 협의 | CNSLTN | `fnrs-cnsltn-mng` |
|
||||
| 생성 | CRT | `crtDmndUuid` |
|
||||
| 요청 | DMND | `crtDmndUuid`, `elapr-dmnd` |
|
||||
| 검증 | VRFC | `vrfcSttsComCd` |
|
||||
| 보완 | SPLMNT | `splmntDmndList` |
|
||||
| 결재 | ELAPR / ATRZ | `elaprCycl`, `atrzSeComCd` |
|
||||
|
||||
---
|
||||
|
||||
## 4. 상태코드 한눈에 보기
|
||||
|
||||
상위코드 `FNRSSTTS`. v1.0의 `PWRKSTTS`(`DV`, `AR`, `TR` 등)는 **폐기**한다.
|
||||
|
||||
정방향:
|
||||
|
||||
```
|
||||
SV → ST → LE → FV → ER → AC → TE → TP → RM → RB → RC → RA → AV → EV → RK → RR → EP → TA
|
||||
```
|
||||
|
||||
자체종결: `LE → EP → TA`
|
||||
보완: `ER|TE|RK → SL` 후 직전 상태로 복귀.
|
||||
|
||||
| 코드 | 명칭 | FE에서 할 일 |
|
||||
| ---- | ---------------------- | ------------------------------------------------- |
|
||||
| `SV` | 저장 | 기초 작성화면 저장/신청/삭제 |
|
||||
| `ST` | 신청완료 | 광역 환경청제출 |
|
||||
| `LE` | 환경청 검토 | 자체종결(`EP`) 또는 기술검토 의뢰(`FV`) |
|
||||
| `FV` | 파일검증 | AI 진행 표시. **30분** 후 `ER` Fallback |
|
||||
| `ER` | 기술검토 의뢰 | 공단 접수자: 파일보완 / 수동파일검증 / 검토자지정 |
|
||||
| `SL` | 보완요청 | 기초 수정화면. 복귀 대상은 이력의 직전 상태 |
|
||||
| `AC` | 초안생성 | AI 진행 표시. **30분** 후 `TE` Fallback |
|
||||
| `TE` | 기술검토 | 웹기안기·검토완료·보완. 결재선 1차 |
|
||||
| `TP` | 기술검토 회신 | 환경청 → 광역 `RM` |
|
||||
| `RM` | 재원협의결과회신 | 광역 → 기초 `RB` |
|
||||
| `RB` | 지자체회신 | 기초 실무협의서 관리 / 조치완료 |
|
||||
| `RC` | 조치결과서 제출 | 광역 → 환경청 `RA` |
|
||||
| `RA` | 조치결과서제출(환경청) | 환경청 2차 의뢰 `AV` |
|
||||
| `AV` | 금액검증 | AI 진행 표시. **30분** 후 `EV` Fallback |
|
||||
| `EV` | 조치결과검토의뢰 | 공단 접수자: 2차 결재선 검토자지정 → `RK` |
|
||||
| `RK` | 조치결과서검토 | 웹기안기·금액검증 재실행·보완. 결재선 2차 |
|
||||
| `RR` | 조치결과서검토 회신 | 환경청 → 광역 `EP` |
|
||||
| `EP` | 검토결과 회신 | 광역 → 기초 `TA` |
|
||||
| `TA` | 검토결과 회신(종료) | 기초 조회만. **고시(**`TB`**) 아님** |
|
||||
|
||||
코드 의미·구버전 대조·보완 루프·AI Fallback은 [ref-process-status.md](./ref-process-status.md).
|
||||
|
||||
---
|
||||
|
||||
## 5. 프론트가 지켜야 할 핵심 규칙
|
||||
|
||||
1. **상태 SSOT는** `FNRSSTTS`. 버튼 가시성은 `(dtlInstCd, prgrsSttsComCd, atrzSeComCd)`로만 계산한다. 공단은 결재선 구분(`ATRZ01` 접수자, `ATRZ02` 검토자, `ATRZ03` 승인자, `ATRZ99` 최종승인자)을 추가로 본다.
|
||||
2. **AI 콜백 API는 화면에서 호출하지 않는다.** `POST /dcrag/documents/verify-result`, `POST /dcrag/draft/complete`, `POST /dcrag/cost/verify-result`는 서버 전용이다.
|
||||
3. **초안생성 1차 트리거는 검토자지정이다.** `POST /elapr-dmnd` (`ER → AC`). 예전처럼 `POST /pwrk-cnsltn-mng`로 초안을 시작하지 않는다.
|
||||
4. **기술검토 의뢰는** `LE → FV` **전용 API** `POST /fnrs-cnsltn-mng/{docNo}/request-examine`. 현재 코드의 `updatePrgrsStts(ER)` 직행은 폐기.
|
||||
5. **수동 AI 재실행은 상태를 바꾸지 않는다.**
|
||||
|
||||
- `ER` 파일검증 → `POST /dcrag-to/documents/transfer`
|
||||
- `TE` 초안생성 → `POST /dcrag-to/documents/draft/generate` (타임아웃·실패 시에만)
|
||||
- `RK` 금액검증 → `POST /dcrag-to/documents/cost/verify`
|
||||
|
||||
6. **진행상태만 바꾸는 버튼은** `POST /fnrs-cnsltn-mng/doc/updatePrgrsStts`**를 재사용한다.** (`ST→LE`, `RM→RB`, `RC→RA`, `RR→EP`, `EP→TA`)
|
||||
7. **보완요청/보완완료는 공통 API** `reqsupplement` / `submitsupplement`. 복귀 상태(`ER`/`TE`/`RK`)는 서버가 이력에서 결정한다. 프론트는 직전 상태를 추측해 보내지 않는다.
|
||||
8. **결재 승인/회신은** `PUT /elapr-prgrs-stts/{id}/process` **하나**. 1차 최종승인자 → `TP`, 2차 → `RR`은 서버가 Feign으로 처리한다.
|
||||
9. **2차 결재선은 EV에서 수동 검토자지정**. `POST /elapr-dmnd` (`elaprCycl: 2`, `docPrgrsSttsComCd: RK`). 1차 결재선 자동 copy-line은 사용하지 않는다.
|
||||
10. **웹기안기는 `webhwp/open` 응답을 axios `blob`으로 조회한 뒤 `File`로 감싸 `HwpCtrl.Open`에 전달한다.** `blob:` Object URL과 `orgnlOtptDocCn`은 쓰지 않는다.
|
||||
|
||||
---
|
||||
|
||||
## 6. 화면 데이터 흐름
|
||||
|
||||
재원협의 **목록 → 상세/작성**이 본체다. 실무협의 목록은 공단 검토 보조 화면이다.
|
||||
|
||||
```
|
||||
BEGIN
|
||||
CALL fnrsCnsltnMngService.findPage(...)
|
||||
ON 행 CLICK → /fnrs-cnsltn/{fnrsCnsltnDocNo}
|
||||
|
||||
CALL findById(fnrsCnsltnDocNo)
|
||||
COMPUTE buttons = getButtonConfigs(dtlInstCd, prgrsSttsComCd, atrzSeComCdList)
|
||||
|
||||
// ----- 기초 ROLE_USER05 -----
|
||||
ON [저장] (빈값/SV) → saveApply(prgrsSttsComCd: SV)
|
||||
ON [신청완료] (SV) → saveApply(prgrsSttsComCd: ST)
|
||||
ON [삭제] (SV) → remove
|
||||
ON [파일보완완료] (SL←ER) → submitsupplement
|
||||
ON [보완완료] (SL←TE|RK) → submitsupplement
|
||||
ON [실무협의서 관리] (RB) → GET webhwp/open (blob) → HwpCtrl.Open(File)
|
||||
ON [조치완료] (RB) → submit-actn-result { isSubmit: true }
|
||||
ON [결과회신] (TA) → API 없음 (조회)
|
||||
|
||||
// ----- 광역 ROLE_USER04 -----
|
||||
ON [환경청제출] (ST) → updatePrgrsStts(LE)
|
||||
ON [지자체회신] (RM) → updatePrgrsStts(RB)
|
||||
ON [조치결과서제출] (RC) → updatePrgrsStts(RA)
|
||||
ON [결과회신] (EP) → updatePrgrsStts(TA)
|
||||
|
||||
// ----- 환경청 ROLE_USER03 -----
|
||||
ON [결과회신] (LE 자체종결) → tech-review → EP
|
||||
ON [기술검토 의뢰] (LE) → request-examine → FV → START POLL FV
|
||||
ON [재원협의 결과 회신] (TP) → tech-review → RM
|
||||
ON [실무협의서 관리] (RA) → GET webhwp/open (blob) → HwpCtrl.Open(File) (저장 불가)
|
||||
ON [조치결과 검토의뢰] (RA) → request-actn-review → AV → START POLL AV
|
||||
ON [결과회신] (RR) → updatePrgrsStts(EP)
|
||||
|
||||
// ----- 공단 ROLE_USER01 -----
|
||||
ON [파일보완] (ER, ATRZ01) → GET file-vrfc-results → 팝업 → reqsupplement
|
||||
ON [파일검증] (ER, ATRZ01) → dcrag-to transfer (상태 유지)
|
||||
ON [검토자지정] (ER, ATRZ01) → POST elapr-dmnd (docPrgrsSttsComCd: AC) → START POLL AC
|
||||
ON [검토자지정] (EV, ATRZ01) → POST elapr-dmnd (elaprCycl: 2, docPrgrsSttsComCd: RK)
|
||||
ON [실무협의서관리] (TE|RK) → GET webhwp/open (blob) → HwpCtrl.Open(File)
|
||||
ON [실무협의서생성] (TE, 실패/타임아웃) → dcrag-to draft/generate
|
||||
ON [검토결과조회] (TE) → pwrk-cnsltn-mng findById | findByUpDocNo
|
||||
ON [저장] (TE|RK) → pwrk-cnsltn-mng save-apply
|
||||
ON [검토완료] → elapr-prgrs-stts process (상신)
|
||||
ON [보완요청] (TE|RK) → 보완 팝업 → reqsupplement
|
||||
ON [금액검증] (RK) → dcrag-to cost/verify
|
||||
ON [결재(승인)] → process (중간)
|
||||
ON [결재(회신)] → process (최종 → TP 또는 RR)
|
||||
|
||||
// ----- AI 진행 중 (FV / AC / AV) -----
|
||||
POLL 상태 또는 draft status. 30분 안내. 종료 후 상세 invalidate
|
||||
END
|
||||
```
|
||||
|
||||
38행 버튼 표는 [ref-screen-buttons.md](./ref-screen-buttons.md). API 상세는 [ref-endpoint.md](./ref-endpoint.md).
|
||||
|
||||
---
|
||||
|
||||
## 7. 버튼 → API 축약
|
||||
|
||||
프론트가 치는 것만. 콜백·스케줄러는 제외.
|
||||
|
||||
| 주체 | 버튼 | From → To | Method & URI |
|
||||
| --------- | -------------------------- | ----------------------------- | ---------------------------------------------------------------------------------- |
|
||||
| 기초 | 저장 / 신청완료 | →`SV` / `SV→ST` | `POST /fnrs-cnsltn-mng/save-apply` |
|
||||
| 기초 | 삭제 | `SV` | `DELETE /fnrs-cnsltn-mng/{docNo}` |
|
||||
| 광역 | 환경청제출 | `ST→LE` | `POST /fnrs-cnsltn-mng/doc/updatePrgrsStts` |
|
||||
| 환경청 | 결과회신(자체종결) | `LE→EP` | `POST /fnrs-cnsltn-mng/{docNo}/tech-review` |
|
||||
| 환경청 | 기술검토 의뢰 | `LE→FV` | **신규** `POST /fnrs-cnsltn-mng/{docNo}/request-examine` |
|
||||
| 공단 접수 | 파일보완 팝업 | `ER` | `GET /fnrs-cnsltn-mng/{docNo}/file-vrfc-results` |
|
||||
| 공단 접수 | 파일보완요청 | `ER→SL` | `POST /fnrs-cnsltn-mng/{docNo}/reqsupplement` |
|
||||
| 공단 접수 | 파일검증 재실행 | `ER` 유지 | `POST /dcrag-to/documents/transfer` |
|
||||
| 공단 접수 | 검토자지정 | `ER→AC` | `POST /elapr-dmnd` (`elaprCycl: 1`) |
|
||||
| 공단 접수 | 검토자지정 | `EV→RK` | `POST /elapr-dmnd` (`elaprCycl: 2`) |
|
||||
| 공단 검토 | 실무협의서관리 | `TE`/`RK` | `GET .../pwrk-cnsltn-doc-crt-rslt/{uuid}/webhwp/open` |
|
||||
| 공단 검토 | 실무협의서생성 | `TE` 유지 | `POST /dcrag-to/documents/draft/generate` |
|
||||
| 공단 검토 | 저장 | `TE`/`RK` | `POST /pwrk-cnsltn-mng/save-apply` |
|
||||
| 공단 | 검토완료 / 결재(승인·회신) | `TE` 유지 / `TE→TP` / `RK→RR` | `PUT /elapr-prgrs-stts/{id}/process` |
|
||||
| 공단 검토 | 보완요청 | `TE→SL` / `RK→SL` | `POST /fnrs-cnsltn-mng/{docNo}/reqsupplement` |
|
||||
| 기초 | 파일보완완료 / 보완완료 | `SL→ER` / `TE` / `RK` | `POST /fnrs-cnsltn-mng/{docNo}/submitsupplement` |
|
||||
| 환경청 | 재원협의 결과 회신 | `TP→RM` | `POST /fnrs-cnsltn-mng/{docNo}/tech-review` |
|
||||
| 광역 | 지자체회신 | `RM→RB` | `updatePrgrsStts` |
|
||||
| 기초 | 실무협의서 관리 | `RB` 유지 | `GET .../pwrk-cnsltn-doc-crt-rslt/{uuid}/webhwp/open` |
|
||||
| 기초 | 조치완료 | `RB→RA` | **신규** `POST /pwrk-cnsltn-mng/{pwrkDocNo}/submit-actn-result` (`isSubmit: true`) |
|
||||
| 광역 | 조치결과서제출 | `RC→RA` | `updatePrgrsStts` |
|
||||
| 환경청 | 실무협의서 관리 | `RA` 유지 (조회) | `GET .../pwrk-cnsltn-doc-crt-rslt/{uuid}/webhwp/open` |
|
||||
| 환경청 | 조치결과 검토의뢰 | `RA→AV` | **신규** `POST /fnrs-cnsltn-mng/{docNo}/request-actn-review` |
|
||||
| 공단 검토 | 금액검증 재실행 | `RK` 유지 | `POST /dcrag-to/documents/cost/verify` |
|
||||
| 환경청 | 결과회신 | `RR→EP` | `updatePrgrsStts` |
|
||||
| 광역 | 결과회신 | `EP→TA` | `updatePrgrsStts` |
|
||||
| 웹기안기 | 저장 | 버전 +1 | `POST /pwrk-cnsltn-doc-crt-rslt` multipart |
|
||||
| 공통 | 다운로드 | — | `GET /pwrk-cnsltn-doc-crt-rslt/{uuid}/download` |
|
||||
|
||||
신규 4개: `request-examine`, `submit-actn-result`, `request-actn-review`, EV 2차 `elapr-dmnd`.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,334 @@
|
||||
# 레퍼런스 — 상태별 Endpoint
|
||||
|
||||
> 상위: [개발가이드.md](./개발가이드.md)
|
||||
> SoT: `05.재원협의_상태별_endpoint_설계.md` (v1.0, 2026-09-03)
|
||||
> Gateway: `/as-service`, `/as-elapr-service`
|
||||
> Auth: `Authorization`, `X-Site-Id`, `token-id` (기존 `client` 인터셉터)
|
||||
> 날짜: `yyyy-MM-dd HH:mm:ss`
|
||||
|
||||
프론트가 치는 API만 상세히 적는다. AI 콜백·스케줄러·Feign은 [§6 호출 금지](#6-프론트-호출-금지).
|
||||
|
||||
---
|
||||
|
||||
## 1. 총괄 매트릭스 (38 + WebHWP)
|
||||
|
||||
| 순번 | 버튼 | From → To | 서비스 | Method & URI | 구분 |
|
||||
| :---: | --- | --- | --- | --- | --- |
|
||||
| 1 | 저장 | →`SV` | as | `POST /api/v1/fnrs-cnsltn-mng/save-apply` | 기존 |
|
||||
| 2 | 신청완료 | `SV→ST` | as | 동일 (`prgrsSttsComCd=ST`) | 기존 |
|
||||
| 3 | 삭제 | `SV` | as | `DELETE /api/v1/fnrs-cnsltn-mng/{docNo}` | 기존 |
|
||||
| 4 | 환경청제출 | `ST→LE` | as | `POST /api/v1/fnrs-cnsltn-mng/doc/updatePrgrsStts` | 기존 |
|
||||
| 5 | 결과회신(자체종결) | `LE→EP` | as | `POST /api/v1/fnrs-cnsltn-mng/{docNo}/tech-review` | 기존 |
|
||||
| 6 | 기술검토 의뢰 | `LE→FV` | as | `POST /api/v1/fnrs-cnsltn-mng/{docNo}/request-examine` | **신규** |
|
||||
| 7 | 파일검증 콜백 | `FV→ER` | as | `POST /api/v1/dcrag/documents/verify-result` | 서버 |
|
||||
| 8 | 파일보완 팝업 | `ER` | as | `GET /api/v1/fnrs-cnsltn-mng/{docNo}/file-vrfc-results` | 기존 |
|
||||
| 9 | 파일보완요청 | `ER→SL` | as | `POST /api/v1/fnrs-cnsltn-mng/{docNo}/reqsupplement` | 기존 |
|
||||
| 10 | 파일검증 재실행 | `ER` | as | `POST /api/v1/dcrag-to/documents/transfer` | 기존 |
|
||||
| 11 | 검토자지정 | `ER→AC` | elapr | `POST /api/v1/elapr-dmnd` | 기존 |
|
||||
| 12 | 초안 콜백 | `AC→TE` | as | `POST /api/v1/dcrag/draft/complete` | 서버 |
|
||||
| 13 | 실무협의서관리 | `TE` | as | `GET /api/v1/pwrk-cnsltn-mng/updocno/{upDocNo}` | 기존 |
|
||||
| 14 | 검토결과조회 | `TE` | as | `GET /api/v1/pwrk-cnsltn-mng/{pwrkDocNo}` | 기존 |
|
||||
| 15 | 실무협의서생성 | `TE` | as | `POST /api/v1/dcrag-to/documents/draft/generate` | 기존 |
|
||||
| 16 | 저장(실무) | `TE` | as | `POST /api/v1/pwrk-cnsltn-mng/save-apply` | 기존 |
|
||||
| 17 | 검토완료 | `TE` | elapr | `PUT /api/v1/elapr-prgrs-stts/{id}/process` | 기존 |
|
||||
| 18 | 보완요청 | `TE→SL` | as | `POST .../reqsupplement` | 기존 |
|
||||
| 19 | 결재(승인) | `TE` | elapr | `PUT .../process` | 기존 |
|
||||
| 20 | 결재(회신) | `TE→TP` | elapr | `PUT .../process` | 기존 |
|
||||
| 21 | 파일보완완료 | `SL→ER` | as | `POST .../submitsupplement` | 기존 |
|
||||
| 22 | 보완완료(기술) | `SL→TE` | as | 동일 | 기존 |
|
||||
| 23 | 보완완료(조치) | `SL→RK` | as | 동일 | 기존 |
|
||||
| 24 | 재원협의 결과 회신 | `TP→RM` | as | `POST .../{docNo}/tech-review` | 기존 |
|
||||
| 25 | 지자체회신 | `RM→RB` | as | `POST .../doc/updatePrgrsStts` | 기존 |
|
||||
| 26 | 실무협의서 관리 | `RB` | as | `GET .../pwrk-cnsltn-doc-crt-rslt/{uuid}/webhwp/open` | 기존 |
|
||||
| 27 | 조치완료 | `RB→RA` | as | `POST /api/v1/pwrk-cnsltn-mng/{pwrkDocNo}/submit-actn-result` (`isSubmit=true`) | **신규** |
|
||||
| 28 | 조치결과서제출 | `RC→RA` | as | `updatePrgrsStts` | 기존 |
|
||||
| 29 | 조치결과 검토의뢰 | `RA→AV` | as | `POST /api/v1/fnrs-cnsltn-mng/{docNo}/request-actn-review` | **신규** |
|
||||
| 30 | 금액검증 콜백 | `AV→EV` | as | `POST /api/v1/dcrag/cost/verify-result` | 서버 |
|
||||
| 30a | 검토자지정(2차) | `EV→RK` | elapr | `POST /api/v1/elapr-dmnd` (`elaprCycl=2`) | 기존 |
|
||||
| 31 | 실무협의서관리 | `RK` | as | `GET /pwrk-cnsltn-mng/{pwrkDocNo}` | 기존 |
|
||||
| 32 | 금액검증 재실행 | `RK` | as | `POST /api/v1/dcrag-to/documents/cost/verify` | 기존 |
|
||||
| 33 | 보완요청(금액) | `RK→SL` | as | `reqsupplement` | 기존 |
|
||||
| 34 | 결재(승인) | `RK` | elapr | `process` | 기존 |
|
||||
| 35 | 결재(회신) | `RK→RR` | elapr | `process` | 기존 |
|
||||
| 36 | 결과회신 | `RR→EP` | as | `updatePrgrsStts` | 기존 |
|
||||
| 37 | 결과회신 | `EP→TA` | as | `updatePrgrsStts` | 기존 |
|
||||
| 38 | 결과회신(확인) | `TA` | — | 없음 | — |
|
||||
| W1 | 웹기안기 Open | — | as | `GET /api/v1/pwrk-cnsltn-doc-crt-rslt/{uuid}/webhwp/open` | 기존 |
|
||||
| W2 | HWPX 저장 | — | as | `POST /api/v1/pwrk-cnsltn-doc-crt-rslt` multipart | 기존 |
|
||||
| W3 | 다운로드 | — | as | `GET /api/v1/pwrk-cnsltn-doc-crt-rslt/{uuid}/download` | 기존 |
|
||||
| E-N | 결재선 복사 | `AV→RK` 부수 | elapr | `POST /api/v1/elapr-apln/copy-line` | **신규·서버** |
|
||||
|
||||
조회 공통: `GET /fnrs-cnsltn-mng`, `GET /fnrs-cnsltn-mng/{docNo}`, `GET /pwrk-cnsltn-mng`, `GET /dcrag-to/documents/draft/status/{crtDmndUuid}`.
|
||||
|
||||
---
|
||||
|
||||
## 2. 공통 요청
|
||||
|
||||
### `DocPrgrsUpdateRequestDto`
|
||||
|
||||
`POST /fnrs-cnsltn-mng/doc/updatePrgrsStts` — `ST→LE`, `RM→RB`, `RC→RA`, `RR→EP`, `EP→TA`.
|
||||
|
||||
```json
|
||||
{
|
||||
"docNo": "F-20260824-0001",
|
||||
"docSeComCd": "FNRS",
|
||||
"prgrsSttsComCd": "LE",
|
||||
"rgtrUuid": "optional-uuid",
|
||||
"rmrk": "optional"
|
||||
}
|
||||
```
|
||||
|
||||
응답: `204/200` void. 프론트 엔티티: 기존 `changePrgrsSttsComCd`.
|
||||
|
||||
### `FnrsCnsltnApplySaveRequestDto`
|
||||
|
||||
`save-apply`, `tech-review`, `reqsupplement`, `submitsupplement`가 공유. 핵심은 `fnrsCnsltnMng.prgrsSttsComCd`와 중첩 리스트(`bzScaleList`, `bizCstList`, `cklstResultList`, `esntlAtchFileList`, `splmntDmndList`).
|
||||
|
||||
---
|
||||
|
||||
## 3. 단계별 FE API
|
||||
|
||||
### 3-1. `SV → ST → LE`
|
||||
|
||||
**저장 / 신청완료** — `POST /fnrs-cnsltn-mng/save-apply`
|
||||
권한: `ROLE_USER05`. 임시저장은 `prgrsSttsComCd=SV`, 신청은 `ST`.
|
||||
응답: `string` (문서번호). 기존 `fnrsCnsltnMngService.saveApply`.
|
||||
|
||||
**삭제** — `DELETE /fnrs-cnsltn-mng/{docNo}` (`SV`만).
|
||||
|
||||
**환경청제출** — `updatePrgrsStts` `LE`. 권한: `ROLE_USER04`.
|
||||
|
||||
### 3-2. `LE → FV | EP`
|
||||
|
||||
**자체종결** — `POST /fnrs-cnsltn-mng/{docNo}/tech-review`
|
||||
Body: `FnrsCnsltnApplySaveRequestDto` (환경청 의견·체크리스트). `LE→EP`.
|
||||
기존 `techReview`. 현재 화면은 `TP`에서도 이 API를 쓰며 목표 상태를 `EP`로 넣고 있다 → **`TP`는 `RM`으로 바꿔야 함**.
|
||||
|
||||
**기술검토 의뢰 (신규)** — `POST /fnrs-cnsltn-mng/{docNo}/request-examine`
|
||||
|
||||
```json
|
||||
{ "prgrsSttsComCd": "FV" }
|
||||
```
|
||||
|
||||
응답: `string` (docNo). `LE→FV` + AI 파일검증 + 30분 타이머(서버).
|
||||
프론트: `fnrsCnsltnMngService.requestExamine(docNo, body)` 추가. **`updatePrgrsStts("ER")` 금지.**
|
||||
|
||||
### 3-3. `FV → ER → SL → ER`
|
||||
|
||||
파일검증 콜백은 서버. FE는 `FV`에서 상세 refetch.
|
||||
|
||||
**검증결과 목록** — `GET /fnrs-cnsltn-mng/{fnrsCnsltnDocNo}/file-vrfc-results`
|
||||
응답: `FnrsCnsltnFileVrfcRsltResponseDto[]`
|
||||
|
||||
| 필드 | 설명 |
|
||||
| --- | --- |
|
||||
| `fileSeComCd` | `ESSENTIAL` / `ADDITIONAL` |
|
||||
| `fileSeNm` | 구분명 |
|
||||
| `esntlAtchFileId` | 필수첨부 ID |
|
||||
| `atchFileNm` | 파일명 |
|
||||
| `vrfcRsltComCd` | `PASS` / `FAIL` / `WARN` |
|
||||
| `vrfcOpnn` | 검증의견 |
|
||||
|
||||
엔티티에 `findFileVrfcResults` 추가. 첨부 행 배지는 상세 `esntlFileList`/`etcFileList`의 `vrfcSttsComCd`, `vrfcRsltCn`, `vrfcDt`도 사용 (타입 확장 필요).
|
||||
|
||||
**파일보완요청** — `POST .../{docNo}/reqsupplement` (`ER→SL`).
|
||||
**파일보완완료** — `POST .../{docNo}/submitsupplement` (`SL→ER`). 복귀는 서버.
|
||||
|
||||
**파일검증 재실행** — `POST /dcrag-to/documents/transfer`
|
||||
|
||||
```json
|
||||
{ "fnrsCnsltnDocNo": "F-20260824-0001", "taskSeComCd": "SF", "taskSeCdNm": "하수처리시설" }
|
||||
```
|
||||
|
||||
응답: `{ resultCode, message, requestId }`. 상태 유지. 기존 `dcRagApiToService.requestDocumentTransfer`.
|
||||
|
||||
### 3-4. `ER → AC → TE → TP`
|
||||
|
||||
**검토자지정** — `POST /elapr-dmnd`
|
||||
기존 `elaprDmndService.save`.
|
||||
|
||||
| 필드 | 값 |
|
||||
| --- | --- |
|
||||
| `elaprDocNo` | 재원협의 번호 |
|
||||
| `elaprCycl` | `1` |
|
||||
| `docPrgrsSttsComCd` | **`AC`** (현행은 현재 상태 `ER`를 넣고 있음 → 수정) |
|
||||
| `elaprPrgrsSttsList[].atrzOrdr` | 1 검토자, 2 승인자, 3 최종 |
|
||||
|
||||
서버가 실무협의 문서 생성 + RAG 초안 트리거 + 30분 타이머. 응답의 문서번호/`crtDmndUuid`가 있으면 폴링 키로 쓴다. 없으면 `findByUpDocNo`로 복원.
|
||||
|
||||
**초안 상태 폴링** — `GET /dcrag-to/documents/draft/status/{crtDmndUuid}`
|
||||
기존 `getDraftGenerationStatus`. 주기 5~10초. 종료 `COMPLETED`/`FAILED`.
|
||||
|
||||
**수동 초안생성** — `POST /dcrag-to/documents/draft/generate` (`TE` 유지)
|
||||
|
||||
```json
|
||||
{
|
||||
"fnrsCnsltnDocNo": "F-...",
|
||||
"pwrkCnsltnDocNo": "P-...",
|
||||
"crtDmndUuid": "optional"
|
||||
}
|
||||
```
|
||||
|
||||
202 + `DcRagDraftGenerateResponseDto` (`crtDmndUuid`, `crtSttsComCd`, `estimatedMinutes`).
|
||||
v1.0 가이드의 “이 API를 프론트가 치면 안 된다”는 **폐기**. 1차 트리거는 검토자지정이고, 이 API는 Fallback 전용.
|
||||
|
||||
**실무 저장** — `POST /pwrk-cnsltn-mng/save-apply` → `string`.
|
||||
**보완요청/완료** — fnrs `reqsupplement` / `submitsupplement`.
|
||||
|
||||
**결재** — `PUT /elapr-prgrs-stts/{elaprPrgrsId}/process`
|
||||
|
||||
```json
|
||||
{
|
||||
"atrzPrgrsSttsComCd": "ATRZ_PRGRS_003",
|
||||
"atrzOpnnCn": "의견",
|
||||
"finalApprovalYn": false
|
||||
}
|
||||
```
|
||||
|
||||
반려: `ATRZ_PRGRS_004`. 기존 `elaprPrgrsSttsService.process`. 최종 시 서버가 `TP`/`RR` 전이.
|
||||
|
||||
### 3-5. `TP → RM → RB → RA`
|
||||
|
||||
**환경청 1차 회신** — `tech-review` (`TP→RM`).
|
||||
**광역 지자체회신** — `updatePrgrsStts` `RB`.
|
||||
|
||||
**조치완료 (신규)** — `POST /pwrk-cnsltn-mng/{pwrkDocNo}/submit-actn-result`
|
||||
|
||||
```json
|
||||
{
|
||||
"isSubmit": true,
|
||||
"actnList": [
|
||||
{
|
||||
"rvwOpnnSn": 1,
|
||||
"actnRsltCn": "수용 — 관로 연장 재산정",
|
||||
"atchFileGroupId": "optional"
|
||||
}
|
||||
],
|
||||
"totActnSummary": "제출 시 권장",
|
||||
"muniDocNo": "제출 시 권장"
|
||||
}
|
||||
```
|
||||
|
||||
- `isSubmit: false` → `RB` 유지 (API만 존재, **화면 버튼 없음**. HWP·첨부는 실무협의서 관리 다이얼로그에서 저장)
|
||||
- `isSubmit: true` → `RB→RA` (조치완료)
|
||||
응답: `string` (pwrkDocNo). DTO명 `PwrkActnResultSubmitDto`.
|
||||
|
||||
### 3-6. `RA → AV → EV → RK`
|
||||
**2차 의뢰 (신규)** — `POST /fnrs-cnsltn-mng/{docNo}/request-actn-review`
|
||||
|
||||
```json
|
||||
{
|
||||
"specialRqstCn": "중점 검증 요청 (선택)"
|
||||
}
|
||||
```
|
||||
|
||||
`RA→AV`. 응답: `string` (docNo). DTO명 `EnvoActnReviewReqDto`. `specialRqstCn`만 선택.
|
||||
|
||||
금액검증 콜백은 서버 → `AV→EV`.
|
||||
**2차 검토자지정** — `POST /elapr-dmnd` (`elaprCycl: 2`, `docPrgrsSttsComCd: RK`). 1차 결재선(`findDocPrgrsByDocNo`, cycl=1)을 시드로 편집.
|
||||
|
||||
**금액검증 재실행** — `POST /dcrag-to/documents/cost/verify`
|
||||
|
||||
```json
|
||||
{
|
||||
"fnrsCnsltnDocNo": "F-...",
|
||||
"pwrkCnsltnDocNo": "P-..."
|
||||
}
|
||||
```
|
||||
|
||||
202. 기존 `requestCostVerification`. `RK` 유지.
|
||||
|
||||
### 3-7. `RK → RR | SL`
|
||||
|
||||
보완은 3-4와 동일 API. 팝업만 금액 체크.
|
||||
결재 `process` 2차 최종 → 서버가 `RR`.
|
||||
|
||||
### 3-8. `RR → EP → TA`
|
||||
|
||||
둘 다 `updatePrgrsStts`. `TA` 확인은 API 없음.
|
||||
|
||||
---
|
||||
|
||||
## 4. 웹기안기
|
||||
|
||||
설계서 기준 **기존**. 구현 시 컨트롤러 존재 여부를 확인한다.
|
||||
|
||||
| ID | 용도 | URI | 응답 |
|
||||
| --- | --- | --- | --- |
|
||||
| W1 | 웹기안기 Open | `GET .../pwrk-cnsltn-doc-crt-rslt/{crtDmndUuid}/webhwp/open` | `inline` HWPX blob → `HwpCtrl.Open(File)` |
|
||||
| W2 | 편집 저장 | `POST .../pwrk-cnsltn-doc-crt-rslt` multipart `file` + `crtDmndUuid` | 201, `verSn+1` |
|
||||
| W3 | PC 저장 | `GET .../{crtDmndUuid}/download` | `attachment` blob |
|
||||
|
||||
버전 지정: `GET .../{crtDmndUuid}/{verSn}/webhwp/open`, `.../{verSn}/download`.
|
||||
`/{uuid}/latest`, `/{uuid}/download`가 `/{uuid}/{verSn}`보다 우선. path를 섞지 말 것.
|
||||
|
||||
다운로드:
|
||||
|
||||
- axios `responseType: "blob"`
|
||||
- 파일명: `Content-Disposition` `filename*=UTF-8''...` (`parseFilenameFromResponse`)
|
||||
- 서버 파일명: `재원협의 실무협의서({bizNm})_v{verSn}.hwp`
|
||||
- Content-Type은 `application/x-hwp` 또는 `application/haansofthwpx`일 수 있음. 타입에 의존하지 말 것
|
||||
|
||||
Open은 axios `responseType: "blob"`으로 인증된 API를 호출하고, 응답 Blob을 HWPX `File`로 감싸 `HwpCtrl.Open`에 전달한다. `blob:` Object URL은 사용하지 않는다.
|
||||
|
||||
multipart `Content-Type` 헤더를 수동 지정하지 않는다 (boundary). JSON `saveJson`은 UI에서 쓰지 않는다.
|
||||
|
||||
---
|
||||
|
||||
## 5. 전자결재 (`as-elapr-service`)
|
||||
|
||||
| API | URI | FE |
|
||||
| --- | --- | --- |
|
||||
| 검토자지정·1차 결재요청 | `POST /elapr-dmnd` | O |
|
||||
| 결재 처리 | `PUT /elapr-prgrs-stts/{id}/process` | O |
|
||||
| 결재선 복사 | `POST /elapr-apln/copy-line` | **X (서버)** |
|
||||
|
||||
`copy-line` body (참고만):
|
||||
|
||||
```json
|
||||
{
|
||||
"docNo": "P-20260827-0001",
|
||||
"sourceElaprCycl": 1,
|
||||
"targetElaprCycl": 2,
|
||||
"rgtrUuid": "system-uuid"
|
||||
}
|
||||
```
|
||||
|
||||
`RK`에서 결재현황은 `findDocPrgrsByDocNo`(전체) 조회 후 `elaprCycl`로 1차/2차 탭 표시.
|
||||
|
||||
---
|
||||
|
||||
## 6. 프론트 호출 금지
|
||||
|
||||
| URI | 이유 |
|
||||
| --- | --- |
|
||||
| `POST /dcrag/documents/verify-result` | AI→AS 콜백 |
|
||||
| `POST /dcrag/draft/complete` | AI→AS 콜백 |
|
||||
| `POST /dcrag/cost/verify-result` | AI→AS 콜백. 여기서 copy-line도 호출 |
|
||||
| `POST /elapr-apln/copy-line` | 콜백 Feign |
|
||||
| `POST /pwrk-cnsltn-mng` (`save` 초안 트리거) | v3.0 1차 트리거는 `elapr-dmnd`. 컨트롤러가 남아 있어도 화면에서 쓰지 않음 |
|
||||
|
||||
`POST /dcrag-to/documents/draft/generate`는 **Fallback에서만** 허용.
|
||||
|
||||
---
|
||||
|
||||
## 7. Gap Analysis (프론트 엔티티)
|
||||
|
||||
### 이미 있는 것
|
||||
|
||||
`fnrsCnsltnMngService`: `findPage`, `findById`, `save`, `saveApply`, `update`, `techReview`, `submitSupplement`, `submitReqSupplement`, `remove`, `changePrgrsSttsComCd`
|
||||
`dcRagApiToService`: `requestDocumentTransfer`, `requestDraftGeneration`, `getDraftGenerationStatus`, `requestCostVerification`
|
||||
`elaprDmndService.save`, `elaprPrgrsSttsService.process`
|
||||
|
||||
### 추가할 것
|
||||
|
||||
| 메서드 | URI |
|
||||
| --- | --- |
|
||||
| `requestExamine` | `POST /fnrs-cnsltn-mng/{id}/request-examine` |
|
||||
| `findFileVrfcResults` | `GET /fnrs-cnsltn-mng/{id}/file-vrfc-results` |
|
||||
| `requestActnReview` | `POST /fnrs-cnsltn-mng/{id}/request-actn-review` |
|
||||
| `pwrkCnsltnMngService.*` | 슬라이스 신규 |
|
||||
| `submitActnResult` | `POST /pwrk-cnsltn-mng/{id}/submit-actn-result` |
|
||||
| `pwrkCnsltnDocCrtRsltService.*` | 슬라이스 신규 |
|
||||
|
||||
`copyLine`은 프론트 서비스에 넣지 않는다.
|
||||
@@ -0,0 +1,350 @@
|
||||
# 레퍼런스 — 프론트 엔티티·DTO
|
||||
|
||||
> 상위: [개발가이드.md](./개발가이드.md)
|
||||
> 엔티티 규칙: `frontend/.cursor/skills/backend-controller-to-entity`
|
||||
|
||||
---
|
||||
|
||||
## 1. ENDPOINT
|
||||
|
||||
`apps/as/src/shared/config/api.ts`
|
||||
|
||||
```ts
|
||||
AS_SERVICE: {
|
||||
// 기존
|
||||
FNRS_CNSLTN_MNG: "/as-service/api/v1/fnrs-cnsltn-mng",
|
||||
DCRAG_TO: "/as-service/api/v1/dcrag-to",
|
||||
// 추가
|
||||
PWRK_CNSLTN_MNG: "/as-service/api/v1/pwrk-cnsltn-mng",
|
||||
PWRK_CNSLTN_DOC_CRT_RSLT: "/as-service/api/v1/pwrk-cnsltn-doc-crt-rslt",
|
||||
}
|
||||
|
||||
AS_ELAPR_SERVICE: {
|
||||
ELAPR_TMPLT: "/as-elapr-service/api/v1/elapr-tmplt",
|
||||
ELAPR_APLN: "/as-elapr-service/api/v1/elapr-apln",
|
||||
ELAPR_DMND: "/as-elapr-service/api/v1/elapr-dmnd",
|
||||
ELAPR_PRGRS_STTS: "/as-elapr-service/api/v1/elapr-prgrs-stts",
|
||||
}
|
||||
```
|
||||
|
||||
`copy-line`은 `ELAPR_APLN` 하위이나 FE에서 호출하지 않음.
|
||||
|
||||
---
|
||||
|
||||
## 2. 슬라이스 배치
|
||||
|
||||
```
|
||||
entities/fnrs-cnsltn/ # 확장
|
||||
entities/dcrag-to/ # 구현됨
|
||||
entities/elapr/ # 구현됨
|
||||
entities/pwrk-cnsltn-mng/ # 신규
|
||||
entities/pwrk-cnsltn-doc-crt-rslt/ # 신규
|
||||
```
|
||||
|
||||
```
|
||||
entities/pwrk-cnsltn-mng/
|
||||
├── model/
|
||||
│ ├── pwrk-cnsltn-mng-interface.ts
|
||||
│ └── pwrk-cnsltn-mng-payload-schema.ts
|
||||
├── api/
|
||||
│ ├── pwrk-cnsltn-mng-service.ts
|
||||
│ └── queries.ts
|
||||
└── index.ts
|
||||
```
|
||||
|
||||
`submit-actn-result` Request는 zod SSOT (`PwrkActnResultSubmitDto`).
|
||||
`request-examine` / `request-actn-review`도 fnrs payload-schema에 추가.
|
||||
|
||||
라우트:
|
||||
|
||||
| 화면 | 경로 |
|
||||
| --- | --- |
|
||||
| 재원협의 목록/상세/작성 | 기존 `app/(main)/(with-base-layout)/fnrs-cnsltn/...` |
|
||||
| 실무협의 목록 | `.../pwrk-cnsltn/page.tsx` (선택) |
|
||||
| 실무협의 상세 | `.../pwrk-cnsltn/[id]/page.tsx` (선택) |
|
||||
| 페이지 UI | `pages/fnrs-cnsltn/`, `pages/pwrk-cnsltn/` |
|
||||
|
||||
---
|
||||
|
||||
## 3. Service 시그니처
|
||||
|
||||
`fnrsCnsltnMngService`에 추가:
|
||||
|
||||
```ts
|
||||
requestExamine(docNo: string, body: FnrsExamineRequestDto): Promise<string>;
|
||||
findFileVrfcResults(fnrsCnsltnDocNo: string): Promise<FnrsCnsltnFileVrfcRsltResponseDto[]>;
|
||||
requestActnReview(docNo: string, body: EnvoActnReviewReqDto): Promise<string>;
|
||||
```
|
||||
|
||||
실무협의:
|
||||
|
||||
```ts
|
||||
export interface PwrkCnsltnMngService {
|
||||
findPage(searchDto: PwrkCnsltnMngSearchDto): Promise<PageResponse<PwrkCnsltnMngResponseDto>>;
|
||||
findById(pwrkCnsltnDocNo: string): Promise<PwrkCnsltnMngDetResponseDto>;
|
||||
findByUpDocNo(upDocNo: string): Promise<PwrkCnsltnMngDetResponseDto>;
|
||||
saveApply(body: PwrkCnsltnApplySaveRequestDto): Promise<string>;
|
||||
submitActnResult(
|
||||
pwrkCnsltnDocNo: string,
|
||||
body: PwrkActnResultSubmitDto,
|
||||
): Promise<string>;
|
||||
update(pwrkCnsltnDocNo: string, body: PwrkCnsltnMngUpdateRequestDto): Promise<string>;
|
||||
remove(pwrkCnsltnDocNo: string): Promise<void>;
|
||||
changePrgrsSttsComCd(body: DocPrgrsUpdateRequestDto): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
v1.0의 `save(): PwrkCnsltnMngSaveResponseDto`(초안 트리거)는 화면에서 사용하지 않는다. 컨트롤러가 남아 있으면 엔티티에 넣더라도 UI 연결 금지.
|
||||
|
||||
생성결과:
|
||||
|
||||
```ts
|
||||
export interface PwrkCnsltnDocCrtRsltService {
|
||||
findPage(
|
||||
searchDto: PwrkCnsltnDocCrtRsltSearchDto,
|
||||
): Promise<PageResponse<PwrkCnsltnDocCrtRsltResponseDto>>;
|
||||
findById(crtDmndUuid: string, verSn: number): Promise<PwrkCnsltnDocCrtRsltResponseDto>;
|
||||
findLatestByCrtDmndUuid(crtDmndUuid: string): Promise<PwrkCnsltnDocCrtRsltResponseDto>;
|
||||
openWebHwpLatest(crtDmndUuid: string): Promise<AxiosResponse<Blob>>;
|
||||
download(crtDmndUuid: string, verSn: number): Promise<AxiosResponse<Blob>>;
|
||||
downloadLatest(crtDmndUuid: string): Promise<AxiosResponse<Blob>>;
|
||||
saveMultipart(formData: FormData): Promise<PwrkCnsltnDocCrtRsltResponseDto>;
|
||||
updateMultipart(
|
||||
crtDmndUuid: string,
|
||||
verSn: number,
|
||||
formData: FormData,
|
||||
): Promise<PwrkCnsltnDocCrtRsltResponseDto>;
|
||||
remove(crtDmndUuid: string, verSn: number): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
`webhwp/open`은 인증된 axios 요청으로 Blob을 조회한다:
|
||||
|
||||
```ts
|
||||
async function openWebHwpLatest(crtDmndUuid: string) {
|
||||
return client.get<Blob>(`${BASE}/${crtDmndUuid}/webhwp/open`, {
|
||||
responseType: "blob",
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
응답 Blob은 HWPX `File`로 감싸 `HwpCtrl.Open(file, "HWPX", ...)`에 전달한다. `blob:` Object URL은 사용하지 않는다.
|
||||
|
||||
DC RAG TO (구현됨, 시그니처 유지):
|
||||
|
||||
```ts
|
||||
requestDocumentTransfer(body: DcRagDocumentTransferRequestDto): Promise<DcRagCommonResponseDto>;
|
||||
requestDraftGeneration(body: DcRagDraftGenerateRequestDto): Promise<DcRagDraftGenerateResponseDto>;
|
||||
getDraftGenerationStatus(crtDmndUuid: string): Promise<DcRagDraftStatusResponseDto>;
|
||||
requestCostVerification(body: DcRagCostVerifyRequestDto): Promise<DcRagCommonResponseDto>;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. DTO
|
||||
|
||||
타입명 = 백엔드 클래스명. Save/Apply는 zod.
|
||||
|
||||
### 4-1. 재원협의 추가
|
||||
|
||||
**`FnrsExamineRequestDto`**
|
||||
|
||||
| 필드 | 필수 | 값 |
|
||||
| --- | --- | --- |
|
||||
| `prgrsSttsComCd` | N | 기본 `FV` |
|
||||
|
||||
**`EnvoActnReviewReqDto`**
|
||||
|
||||
| 필드 | 필수 |
|
||||
| --- | --- |
|
||||
| `specialRqstCn` | N |
|
||||
|
||||
**`FnrsCnsltnFileVrfcRsltResponseDto`**: [ref-endpoint.md](./ref-endpoint.md) §3-3.
|
||||
|
||||
첨부 검증 배지용으로 `AtflMngClientResponseDto` / `EsntlAtchFileMngTreeResponseDto`에 `vrfcDt`, `vrfcRsltCn`, `vrfcSttsComCd` 확장.
|
||||
|
||||
### 4-2. `PwrkActnResultSubmitDto` (zod)
|
||||
|
||||
| 필드 | 필수 | 비고 |
|
||||
| --- | --- | --- |
|
||||
| `isSubmit` | Y | `false` API만(화면 버튼 없음), `true` 조치완료(`RB→RA`) |
|
||||
| `actnList` | N | 조치완료 시 선택 |
|
||||
| `actnList[].rvwOpnnSn` | Y (항목 있을 때) | |
|
||||
| `actnList[].actnRsltCn` | N | |
|
||||
| `actnList[].atchFileGroupId` | N | |
|
||||
| `totActnSummary` | N | 제출 시 권장 |
|
||||
| `muniDocNo` | N | 제출 시 권장 |
|
||||
| `pwrkAtchFileGroupId` | N | |
|
||||
|
||||
### 4-3. `PwrkCnsltnMng*`
|
||||
|
||||
**Search**: `pwrkCnsltnDocNo`, `upDocNo`, `upDocSeComCd`, `prgrsSttsComCd`, `admdstCd`, `envoSeComCd`, `taskSeComCd`, `bizNm`
|
||||
|
||||
**DetResponse 중첩**
|
||||
|
||||
- `cnsltnList`: 협의내역 (`rvwOpnnSn`, `rvwOpnnClsfComCd`, `cnsltnCn`, `rfltYn`, …)
|
||||
- `pjtcoAjmtList`: 사업비조정
|
||||
- `crtDmndList[].crtRslt`: 생성요청 + 최신 결과
|
||||
- `splmntDmndList`: 보완요청
|
||||
- `sttsChgHstryList`: 상태변경이력 — `SL` 복귀 라벨에 사용
|
||||
- `trsmFileList`: 전송파일 (Java Det DTO 확인 후 반영)
|
||||
|
||||
마스터 조인: `bizNm`, `admdstCd`, `envoSeComCd`, `taskSeComCd`, `aplcntNm` 등.
|
||||
|
||||
`crtRslt.orgnlOtptDocCn`은 항상 `null`.
|
||||
|
||||
**상세 예**
|
||||
|
||||
```json
|
||||
{
|
||||
"pwrkCnsltnDocNo": "P-20260827-0001",
|
||||
"upDocNo": "F-20260824-0001",
|
||||
"upDocSeComCd": "FNRS",
|
||||
"prgrsSttsComCd": "TE",
|
||||
"cnsltnList": [],
|
||||
"pjtcoAjmtList": [],
|
||||
"crtDmndList": [
|
||||
{
|
||||
"crtDmndUuid": "d0545bef-735f-4d7b-a781-88e96e03577a",
|
||||
"pwrkCnsltnDocNo": "P-20260827-0001",
|
||||
"rqstrUuid": "...",
|
||||
"rqstrNm": "관리자",
|
||||
"crtSttsComCd": "C",
|
||||
"crtRslt": {
|
||||
"crtDmndUuid": "d0545bef-735f-4d7b-a781-88e96e03577a",
|
||||
"verSn": 1,
|
||||
"rgtrNm": "관리자",
|
||||
"orgnlOtptDocCn": null,
|
||||
"crtCmptnDt": "2026-08-27 10:47:01"
|
||||
}
|
||||
}
|
||||
],
|
||||
"splmntDmndList": [],
|
||||
"sttsChgHstryList": []
|
||||
}
|
||||
```
|
||||
|
||||
### 4-4. `PwrkCnsltnDocCrtRslt*`
|
||||
|
||||
복합 PK: `crtDmndUuid` + `verSn`
|
||||
|
||||
**Response**
|
||||
|
||||
| 필드 | 타입 | 비고 |
|
||||
| --- | --- | --- |
|
||||
| `crtDmndUuid` | `string` | |
|
||||
| `verSn` | `number` | |
|
||||
| `rgtrUuid` / `rgtrNm` | `string` | |
|
||||
| `orgnlOtptDocCn` | `null` | 목록/상세 미포함 |
|
||||
| `crtCmptnDt` | `string` | |
|
||||
|
||||
**Search** (`PageableParams`): `crtDmndUuid`(이력 조회 시 필수), `pwrkCnsltnDocNo`, `verSn`, `rgtrUuid`
|
||||
|
||||
```http
|
||||
GET /as-service/api/v1/pwrk-cnsltn-doc-crt-rslt?page=0&size=10&crtDmndUuid={uuid}&sort=verSn,desc
|
||||
```
|
||||
|
||||
**Save (zod)**: `crtDmndUuid` 필수. `rgtrUuid` 생략 시 서버 로그인 사용자. `file`은 multipart part (DTO 필드 아님).
|
||||
|
||||
### 4-5. DC RAG (구현됨)
|
||||
|
||||
```ts
|
||||
interface DcRagDocumentTransferRequestDto {
|
||||
fnrsCnsltnDocNo: string;
|
||||
taskSeComCd?: string;
|
||||
taskSeCdNm?: string;
|
||||
}
|
||||
|
||||
interface DcRagDraftStatusResponseDto {
|
||||
crtDmndUuid: string;
|
||||
status: DraftStatus;
|
||||
statusName?: string;
|
||||
progressPercent?: number;
|
||||
events?: EventInfoDto[];
|
||||
startedDt?: string;
|
||||
estimatedCompletionDt?: string;
|
||||
errorMessage?: string | null;
|
||||
}
|
||||
|
||||
type DraftStatus =
|
||||
| "REQUESTED"
|
||||
| "DOWNLOADING"
|
||||
| "ANALYZING"
|
||||
| "GENERATING"
|
||||
| "COMPLETED"
|
||||
| "FAILED";
|
||||
```
|
||||
|
||||
`estimatedMinutes`는 초안 응답에 있을 수 있으나 UX 안내는 **30분 Fallback**을 따른다.
|
||||
|
||||
---
|
||||
|
||||
## 5. 폴링 훅
|
||||
|
||||
초안 (`AC` 또는 `TE`이면서 생성 중):
|
||||
|
||||
```ts
|
||||
useQuery({
|
||||
queryKey: [...dcragToKeys.draftStatus(crtDmndUuid)],
|
||||
queryFn: () => dcRagApiToService.getDraftGenerationStatus(crtDmndUuid),
|
||||
enabled: Boolean(crtDmndUuid) && isPolling,
|
||||
refetchInterval: (query) => {
|
||||
const status = query.state.data?.status;
|
||||
if (status === "COMPLETED" || status === "FAILED") return false;
|
||||
return 5_000;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
`COMPLETED` 시 `fnrs-cnsltn` 상세·`pwrk-cnsltn-mng` `findByUpDocNo` invalidate.
|
||||
|
||||
`FV`/`AV`는 `findById`를 5~10초 refetch. `prgrsSttsComCd`가 `ER`/`RK`가 되면 중단. 시작 시각 기준 30분 경과 안내 문구.
|
||||
|
||||
`crtDmndUuid` 복원: `findByUpDocNo(fnrsCnsltnDocNo).crtDmndList[0]`.
|
||||
|
||||
---
|
||||
|
||||
## 6. 다운로드
|
||||
|
||||
```ts
|
||||
const response = await client.get<Blob>(url, { responseType: "blob" });
|
||||
const filename = parseFilenameFromResponse(response);
|
||||
const objectUrl = window.URL.createObjectURL(response.data);
|
||||
```
|
||||
|
||||
기존 `attachService`와 동일.
|
||||
|
||||
---
|
||||
|
||||
## 7. 실무협의 목록 컬럼 (선택 화면)
|
||||
|
||||
| 표시명 | Field |
|
||||
| --- | --- |
|
||||
| 실무협의번호 | `pwrkCnsltnDocNo` |
|
||||
| 재원협의번호 | `upDocNo` |
|
||||
| 진행상태 | `prgrsSttsComCdNm` |
|
||||
| 사업명 | `bizNm` |
|
||||
| 시도/구군 | `sido` / `gugun` |
|
||||
| 신청자 | `aplcntNm` |
|
||||
| 등록일 | `regDt` |
|
||||
|
||||
행 클릭 → `/pwrk-cnsltn/{pwrkCnsltnDocNo}` 또는 재원협의 상세로 이동 (화면설계 확정 후).
|
||||
|
||||
---
|
||||
|
||||
## 8. `elapr-dmnd` 저장 시 주의
|
||||
|
||||
현행 `floating-action-buttons.tsx`:
|
||||
|
||||
```ts
|
||||
elaprCycl: data.detDto?.prgrsSttsComCd === "RK" ? 2 : 1,
|
||||
docPrgrsSttsComCd: data.detDto?.prgrsSttsComCd, // ER
|
||||
```
|
||||
|
||||
To-Be:
|
||||
|
||||
- 검토자지정은 **`ER`(1차)** 과 **`EV`(2차)** 에서.
|
||||
- `ER`: `elaprCycl: 1`, `docPrgrsSttsComCd: "AC"`, 서식 선택 다이얼로그
|
||||
- `EV`: `elaprCycl: 2`, `docPrgrsSttsComCd: "RK"`, 1차 결재선 시드 다이얼로그(서식 없음)
|
||||
|
||||
`RK` / ATRZ02 FAB: `findDocPrgrsByDocNo` 전체 조회 후 pending은 `elaprCycl === 2`만 사용. 검토완료 후 `ElaprApprovalDialog`에 `elaprCycl={2}`. 보완요청은 TE와 동일 `SplmntDmndDialog`.
|
||||
@@ -0,0 +1,246 @@
|
||||
# 레퍼런스 — 프로세스·상태 전이
|
||||
|
||||
> 상위: [개발가이드.md](./개발가이드.md)
|
||||
> SoT: `03.재원협의_실무협의_프로세스_통합_v완결.md` (v3.0, 2026-09-03)
|
||||
|
||||
---
|
||||
|
||||
## 1. 프로세스 개요
|
||||
|
||||
| 항목 | 내용 |
|
||||
| --- | --- |
|
||||
| Process No. | PR-AS-003 |
|
||||
| 메뉴 | 행정지원 > 2.2.2 재원협의 > 2.2.2.1 재원협의 관리 |
|
||||
| 목적 | 기초 → 광역(경유) → 환경청(승인) → 공단(기술검토/AI) 4자 협의로 사업규모·국비·분담금을 확정 |
|
||||
|
||||
2-Pass:
|
||||
|
||||
- **Pass 1** 기술 타당성: `SV→ST→LE→FV→ER→AC→TE→TP→RM→RB`
|
||||
- **Pass 2** 조치결과·금액: `RB→RA→AV→EV→RK→RR→EP→TA`
|
||||
|
||||
자체종결(기술검토 생략): `LE→EP→TA`
|
||||
|
||||
---
|
||||
|
||||
## 2. 4-Lane 시퀀스
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor 기초 as 기초 (ROLE_USER05)
|
||||
actor 광역 as 광역 (ROLE_USER04)
|
||||
actor 환경청 as 환경청 (ROLE_USER03)
|
||||
actor 공단 as 공단 (ROLE_USER01)
|
||||
actor AI as AI 엔진
|
||||
|
||||
rect rgb(240, 248, 255)
|
||||
기초->>기초: [저장] SV
|
||||
기초->>광역: [신청완료] ST
|
||||
광역->>환경청: [환경청제출] LE
|
||||
end
|
||||
|
||||
rect rgb(255, 250, 240)
|
||||
alt 자체종결
|
||||
환경청->>광역: [결과회신] LE → EP
|
||||
광역->>기초: [결과회신] EP → TA
|
||||
else 기술검토 의뢰
|
||||
환경청->>AI: [기술검토 의뢰] LE → FV
|
||||
end
|
||||
end
|
||||
|
||||
rect rgb(245, 255, 245)
|
||||
AI-->>공단: 파일검증 콜백 FV → ER
|
||||
Note over 공단: 30분 미응답 시 ER + 수동 [파일검증]
|
||||
alt 파일 미비
|
||||
공단->>기초: [파일보완] ER → SL
|
||||
기초->>공단: [파일보완완료] SL → ER
|
||||
else 적격
|
||||
공단->>AI: [검토자지정] ER → AC
|
||||
end
|
||||
end
|
||||
|
||||
rect rgb(255, 245, 245)
|
||||
AI-->>공단: 초안 콜백 AC → TE
|
||||
Note over 공단: 30분 미응답 시 TE + 수동 [실무협의서생성]
|
||||
alt 설계 미비
|
||||
공단->>기초: [보완요청] TE → SL
|
||||
기초->>공단: [보완완료] SL → TE
|
||||
else 검토 완료
|
||||
공단->>공단: [검토완료] 상신, [결재(승인)] TE 유지
|
||||
공단->>환경청: [결재(회신)] TE → TP
|
||||
end
|
||||
end
|
||||
|
||||
rect rgb(250, 240, 255)
|
||||
환경청->>광역: [재원협의 결과 회신] TP → RM
|
||||
광역->>기초: [지자체회신] RM → RB
|
||||
기초->>환경청: [조치완료] RB → RA
|
||||
end
|
||||
|
||||
rect rgb(240, 255, 255)
|
||||
광역->>환경청: [조치결과서제출] RC → RA
|
||||
환경청->>AI: [조치결과 검토의뢰] RA → AV
|
||||
AI-->>공단: 금액검증 콜백 AV → EV
|
||||
공단->>공단: [검토자지정] EV → RK
|
||||
Note over 공단: EV에서 1차 결재선 시드로 2차 결재선 수동 배정
|
||||
end
|
||||
|
||||
rect rgb(255, 255, 230)
|
||||
alt 소명 미비
|
||||
공단->>기초: [보완요청] RK → SL
|
||||
기초->>공단: [보완완료] SL → RK
|
||||
else 확정
|
||||
공단->>환경청: [결재(회신)] RK → RR
|
||||
end
|
||||
end
|
||||
|
||||
rect rgb(255, 240, 240)
|
||||
환경청->>광역: [결과회신] RR → EP
|
||||
광역->>기초: [결과회신] EP → TA
|
||||
end
|
||||
```
|
||||
|
||||
거버넌스:
|
||||
|
||||
```
|
||||
기초 (USER05) --ST--> 광역 (USER04) --LE--> 환경청 (USER03)
|
||||
기초 <-----TA------ 광역 <-----EP/RM------ 환경청
|
||||
환경청 --FV/ER--> 공단 (USER01) --TP/RR--> 환경청
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Activity 정의 (14)
|
||||
|
||||
| No. | Activity | 주체 | From → To | FE 포인트 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | 재원협의 조회 | 기초 | — | 기본계획·자가점검 대조 |
|
||||
| 2 | 등록 및 제출 | 기초·광역 | `SV→ST`, 광역 `LE` | `save-apply`, `updatePrgrsStts` |
|
||||
| 3 | 접수 및 의뢰 | 환경청 | `LE→FV` / `EP` | 의뢰 vs 자체종결 분기 |
|
||||
| 4 | AI 파일검증 | 공단·AI | `FV→ER` / `SL` | 30분 Fallback, 파일보완 팝업 |
|
||||
| 5 | 자체종결 회신 | 환경청·광역 | `LE→EP→TA` | 공단 레인 없음 |
|
||||
| 6 | 검토자지정·초안 | 공단·AI | `ER→AC→TE` | `elapr-dmnd`, 초안 폴링 |
|
||||
| 7 | 1차 기술검토 | 공단 결재선 | `TE` / `SL` | 웹기안기, HWP 파싱은 서버 |
|
||||
| 8 | 기술검토 회신 | 공단 최종 | `TE→TP` | `process` 최종 |
|
||||
| 9 | 검토결과 회신 | 환경청·광역 | `TP→RM→RB` | 1차 회신. `EP`와 혼동 금지 |
|
||||
| 10 | 조치결과 작성 | 기초 | `RB→RA` | `submit-actn-result` `isSubmit:true` (조치완료) |
|
||||
| 11 | 조치 의뢰 | 환경청 | `RA→AV` | `request-actn-review` |
|
||||
| 12 | AI 금액검증 | AI·공단 | `AV→EV` | 콜백/Fallback 후 접수자 대기 |
|
||||
| 12a | 2차 검토자지정 | 공단 접수 | `EV→RK` | `elapr-dmnd` cycl=2 |
|
||||
| 13 | 2차 검토·결재 | 공단 | `RK→RR` / `SL` | 2차 결재선 |
|
||||
| 14 | 최종 회신 | 환경청·광역·기초 | `RR→EP→TA` | 종결 |
|
||||
|
||||
---
|
||||
|
||||
## 4. `FNRSSTTS` 상세
|
||||
|
||||
관리: `tb_cs_lwpo_cd` / `tb_as_fnrs_cnsltn_mng.prgrs_stts_com_cd`
|
||||
|
||||
| 코드 | 국문 | 영문 | 화면 주체 | 전이 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `SV` | 저장 | Save | 기초 작성 | 신규/`SV` → `SV` |
|
||||
| `ST` | 신청완료 | Submit to Province | 기초→광역 | `SV→ST` |
|
||||
| `LE` | 환경청 검토 | Local Environment Review | 광역→환경청 | `ST→LE` |
|
||||
| `FV` | 파일검증 | File Verification | AI | `LE→FV` |
|
||||
| `ER` | 기술검토 의뢰 | Examine Request | 공단 접수자 | `FV→ER`, `SL→ER` |
|
||||
| `SL` | 보완요청 | Supplement Loop | 공단→기초 | `ER\|TE\|RK → SL` |
|
||||
| `AC` | 초안생성 | AI Auto Creation | AI | `ER→AC` |
|
||||
| `TE` | 기술검토 | Technical Examine | 공단 1차 결재 | `AC→TE`, `SL→TE` |
|
||||
| `TP` | 기술검토 회신 | Technical Pass to Basin | 공단→환경청 | `TE→TP` |
|
||||
| `RM` | 재원협의결과회신 | Result Message to Province | 환경청→광역 | `TP→RM` |
|
||||
| `RB` | 재원협의결과회신(지자체) | Result Back to Municipality | 광역→기초 | `RM→RB` |
|
||||
| `RC` | 조치결과서 제출 | Result Complete | 기초→광역 | `RB→RC` |
|
||||
| `RA` | 조치결과서 제출(환경청) | Result Ask to Basin | 기초→환경청 | `RB→RA` |
|
||||
| `AV` | 금액검증 | Amount Verification | AI | `RA→AV` |
|
||||
| `EV` | 조치결과검토의뢰 | Examine Verify | 공단 접수자 | `AV→EV` |
|
||||
| `RK` | 조치결과서검토 | Result Check | 공단 2차 결재 | `EV→RK`, `SL→RK` |
|
||||
| `RR` | 조치결과서검토 회신 | Result Return to Basin | 공단→환경청 | `RK→RR` |
|
||||
| `EP` | 검토결과 회신 | Examine Pass to Province | 환경청→광역 | `LE→EP`(자체), `RR→EP`(최종) |
|
||||
| `TA` | 검토결과 회신(종료) | Technical Approval | 광역→기초 | `EP→TA` |
|
||||
|
||||
### 4-1. v2.1 → v3.0 대조 (프론트 폐기 대상)
|
||||
|
||||
| 구간 | v2.1 | v3.0 |
|
||||
| --- | --- | --- |
|
||||
| 의뢰 직후 파일검증 | `ER` | **`FV` → `ER`** |
|
||||
| 검토자지정 후 초안 | `EE` → `DV` | **`ER` → `AC` → `TE`** |
|
||||
| 1차 내부 결재 | `TR` → `TP` | **`TE` 유지 → `TP`** |
|
||||
| 환경청→광역 1차 회신 | `EP` | **`RM`** |
|
||||
| 금액검증 | `RA` | **`RA` → `AV` → `RK`** |
|
||||
| 공단 2차 회신 | `TP` | **`RR`** |
|
||||
| 최종 완료 | `TP` / 고시 `TB` | **`TA`** (고시 없음) |
|
||||
|
||||
가이드 v1.0 `PWRKSTTS`(`DV`, `AR`, `TR`, `AA` 등)도 동일하게 폐기.
|
||||
|
||||
---
|
||||
|
||||
## 5. 보완(`SL`) 3루프
|
||||
|
||||
복귀 상태는 `tb_as_doc_stts_chg_hstry` 직전 코드. 프론트는 복귀 코드를 요청에 넣지 않고, 라벨만 이력으로 고른다.
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
ER --> SL: 파일보완 팝업(파일리스트)
|
||||
SL --> ER: 파일보완완료
|
||||
TE --> SL: 보완 검토팝업()
|
||||
SL --> TE: 보완완료
|
||||
RK --> SL: 보완 검토팝업(금액)
|
||||
SL --> RK: 보완완료
|
||||
```
|
||||
|
||||
| 루프 | 팝업 | 요청 | 제출 버튼 |
|
||||
| --- | --- | --- | --- |
|
||||
| 파일 무결성 | 파일리스트 + 검증결과 | 공단 접수자 `ER` | [파일보완완료] |
|
||||
| 1차 기술 | 설계 미달·사유 | 공단 검토자 `TE` | [보완완료] |
|
||||
| 2차 금액 | 공종별 금액 체크 | 공단 검토자 `RK` | [보완완료] |
|
||||
|
||||
---
|
||||
|
||||
## 6. AI 3파이프라인·30분 Fallback
|
||||
|
||||
| ID | 단계 | 진입 → 완료 | 프론트 진입 | Fallback | 수동 재실행 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| AI-1 | 파일 무결성 | `FV→ER` | 환경청 [기술검토 의뢰] | 30분 → `ER` + [파일검증] | `POST /dcrag-to/documents/transfer` |
|
||||
| AI-2 | 초안 생성 | `AC→TE` | 공단 [검토자지정] | 30분 → `TE` + [실무협의서생성] | `POST /dcrag-to/documents/draft/generate` |
|
||||
| AI-3 | 금액 검증 | `AV→EV` | 환경청 [조치결과 검토의뢰] | 30분 → `EV` + 수동 [금액검증] | `POST /dcrag-to/documents/cost/verify` |
|
||||
|
||||
- 예상 소요 안내는 **30분** (v1.0의 10분은 폐기).
|
||||
- 콜백 수신·스케줄러 전이는 서버. FE는 상세 refetch / draft status 폴링만.
|
||||
- `AC→TE` 성공 시에만 [실무협의서관리]·[검토결과조회] 활성. 실패·타임아웃이면 [실무협의서생성].
|
||||
|
||||
초안 폴링 이벤트 예:
|
||||
|
||||
| `eventType` | `eventMessage` |
|
||||
| --- | --- |
|
||||
| `REQUESTED` | 요청을 접수했습니다. |
|
||||
| `DOWNLOADING` | 신청서를 수신하는 중입니다. |
|
||||
| `ANALYZING` | 자료 준비가 완료되었습니다. |
|
||||
| `GENERATING` | 문서 저장이 완료되었습니다. |
|
||||
| `COMPLETED` | 문서 생성이 완료되었습니다. |
|
||||
| `FAILED` | `errorMessage` 표시 |
|
||||
|
||||
종료: `status === "COMPLETED" | "FAILED"` 또는 `events`에 해당 `eventType`.
|
||||
|
||||
---
|
||||
|
||||
## 7. 2차 결재선 (수동 검토자지정)
|
||||
|
||||
1. `TE`에서 1차 결재선(`elaprCycl = 1`) 완료.
|
||||
2. 금액검증 콜백/Fallback → `AV→EV`.
|
||||
3. 공단 접수자가 `EV`에서 [검토자지정]: 1차 결재선을 시드로 편집 후 `POST /elapr-dmnd` (`elaprCycl: 2`) → `RK`.
|
||||
4. `copy-line` 자동 복사는 사용하지 않는다.
|
||||
|
||||
결재 `process`:
|
||||
|
||||
- 상신·중간 승인: 문서 상태 `TE` 또는 `RK` 유지.
|
||||
- 1차 최종: 서버가 `TE→TP`.
|
||||
- 2차 최종: 서버가 `RK→RR`.
|
||||
- 반려: 직전 결재자 복귀. 문서 상태 유지.
|
||||
|
||||
---
|
||||
|
||||
## 8. 웹기안기
|
||||
|
||||
- `TE`/`RK` [실무협의서관리] → `webhwp/open` Blob 조회 후 팝업에서 `HwpCtrl.Open(File)`.
|
||||
- [검토완료] 시 HWP 파싱·DB 등재는 **서버**. FE는 결재 `process`만.
|
||||
- 편집본 저장: `POST /pwrk-cnsltn-doc-crt-rslt` multipart. `verSn`은 클라이언트가 보내지 않음.
|
||||
@@ -0,0 +1,181 @@
|
||||
# 레퍼런스 — 화면·버튼 매트릭스
|
||||
|
||||
> 상위: [개발가이드.md](./개발가이드.md)
|
||||
> SoT: `03` §4 화면 및 버튼별 상세 상태전이 명세서 (Row 4~42, 38행)
|
||||
|
||||
구현 위치: `pages/fnrs-cnsltn/lib/button-config.ts` + `ui/components/floating-action-buttons.tsx`
|
||||
|
||||
---
|
||||
|
||||
## 1. 화면 구분
|
||||
|
||||
| 화면 | 소유 | 라우트 (현행) | 비고 |
|
||||
| --- | --- | --- | --- |
|
||||
| 작성화면 | 기초 `ROLE_USER05` | `/fnrs-cnsltn/new`, `/fnrs-cnsltn/{id}/edit` | `SV` |
|
||||
| 수정화면 | 기초 | `/fnrs-cnsltn/{id}/edit` | `SL` 보완 |
|
||||
| 상세화면 | 광역·환경청·공단·기초(`RB`/`TA`) | `/fnrs-cnsltn/{id}` | 조회 + 액션 버튼 |
|
||||
| 자동화 | AI | 버튼 없음 | `FV`/`AC`/`AV` 진행 패널 |
|
||||
|
||||
공단 상세는 결재선 구분으로 같은 상태라도 버튼이 다르다.
|
||||
|
||||
| `atrzSeComCd` | 역할 |
|
||||
| --- | --- |
|
||||
| `ATRZ01` | 접수자 |
|
||||
| `ATRZ02` | 검토자 |
|
||||
| `ATRZ03` | 승인자 |
|
||||
| `ATRZ99` | 최종승인자 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 38행 매트릭스
|
||||
|
||||
API 컬럼은 [ref-endpoint.md](./ref-endpoint.md)와 동일.
|
||||
|
||||
| 순번 | 화면 | 권한 | 결재선 | 상태 | 버튼 | 전이 | 다음 담당 | FE 동작 |
|
||||
| :---: | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| 1 | 작성 | USER05 | - | 빈값, `SV` | 저장 | `SV` | 본인 | `save-apply` `SV` |
|
||||
| 2 | 작성 | USER05 | - | `SV` | 신청완료 | `ST` | 광역 | `save-apply` `ST` |
|
||||
| 3 | 작성 | USER05 | - | `SV` | 삭제 | 삭제 | — | `DELETE` |
|
||||
| 4 | 상세 | USER04 | - | `ST` | 환경청제출 | `LE` | 환경청 | `updatePrgrsStts` |
|
||||
| 5 | 상세 | USER03 | - | `LE` | 결과회신 | `EP` | 광역 | `tech-review` 자체종결 |
|
||||
| 6 | 상세 | USER03 | - | `LE` | 기술검토 의뢰 | `FV` | 공단 접수 | **`request-examine`** |
|
||||
| 7 | 자동화 | AI | - | `FV` | (파일검증) | `ER` | 공단 접수 | FE 호출 없음. 진행 패널 |
|
||||
| 8 | 상세 | USER01 | 접수자 | `ER` | 파일보완 | `SL` | 기초 | 팝업(파일리스트) → `reqsupplement` |
|
||||
| 9 | 상세 | USER01 | 접수자 | `ER` | 파일검증 | `ER` | 본인 | `dcrag-to/transfer` 재실행 |
|
||||
| 10 | 상세 | USER01 | 접수자 | `ER` | 검토자지정 | `AC` | 다음 결재자 | `POST /elapr-dmnd` |
|
||||
| 11 | 자동화 | AI | - | `AC` | (초안생성) | `TE` | 공단 검토 | FE 호출 없음. 폴링 |
|
||||
| 12 | 상세 | USER01 | 검토자 | `TE` | 실무협의서관리 | 유지 | — | 웹기안기 Open. **초안 성공 시만** |
|
||||
| 13 | 상세 | USER01 | 검토자 | `TE` | 검토결과조회 | 유지 | — | 실무협의 상세 |
|
||||
| 14 | 상세 | USER01 | 검토자 | `TE` | 실무협의서생성 | 유지 | — | **실패/타임아웃/초안 없음** 시 |
|
||||
| 15 | 상세 | USER01 | 검토자 | `TE` | 저장 | `TE` | — | `pwrk save-apply` |
|
||||
| 16 | 상세 | USER01 | 검토자 | `TE` | 검토완료 | `TE` | 다음 결재자 | `elapr process` 상신. 반려 시 직전 결재자 |
|
||||
| 17 | 상세 | USER01 | 검토자 | `TE` | 보완요청 | `SL` | 기초 | 보완 팝업() → `reqsupplement` |
|
||||
| 18 | 상세 | USER01 | 승인자 | `TE` | 결재(승인) | `TE` | 다음 결재자 | `process` |
|
||||
| 19 | 상세 | USER01 | 최종승인자 | `TE` | 결재(회신) | `TP` | 환경청 | `process` 최종 |
|
||||
| 20 | 수정 | USER05 | - | `SL` | 파일보완완료 | `ER` | 공단 접수 | `submitsupplement` (직전=`ER`) |
|
||||
| 21 | 수정 | USER05 | - | `SL` | 보완완료 | `TE` | 공단 검토 | `submitsupplement` (직전=`TE`) |
|
||||
| 22 | 수정 | USER05 | - | `SL` | 보완완료 | `RK` | 공단 검토 | `submitsupplement` (직전=`RK`) |
|
||||
| 23 | 상세 | USER03 | - | `TP` | 재원협의 결과 회신 | `RM` | 광역 | `tech-review` |
|
||||
| 24 | 상세 | USER04 | - | `RM` | 지자체회신 | `RB` | 기초 | `updatePrgrsStts` |
|
||||
| 25 | 상세 | USER05 | - | `RB` | 실무협의서 관리 | 유지 | — | 웹기안기 Open |
|
||||
| 26 | 상세 | USER05 | - | `RB` | 조치완료 | `RA` | 환경청 | **`submit-actn-result` `isSubmit:true`** |
|
||||
| 27 | 상세 | USER04 | - | `RC` | 조치결과서제출 | `RA` | 환경청 | `updatePrgrsStts` |
|
||||
| 28 | 상세 | USER03 | - | `RA` | 실무협의서 관리 | 유지 | — | 웹기안기 Open. **저장 불가** |
|
||||
| 28a | 상세 | USER03 | - | `RA` | 조치결과 검토의뢰 | `AV` | 공단 검토 | **`request-actn-review`** |
|
||||
| 29 | 자동화 | AI | - | `AV` | (금액검증) | `EV` | 공단 접수 | FE 호출 없음. 진행 패널 |
|
||||
| 29a | 상세 | USER01 | 접수자 | `EV` | 검토자지정 | `RK` | 공단 검토 | `POST /elapr-dmnd` cycl=2. 1차 결재선 시드 |
|
||||
| 30 | 상세 | USER01 | 검토자 | `RK` | 실무협의서관리 | 유지 | — | 웹기안기 |
|
||||
| 31 | 상세 | USER01 | 검토자 | `RK` | 금액검증 | `RK` | — | `dcrag-to/cost/verify` |
|
||||
| 32 | 상세 | USER01 | 검토자 | `RK` | 저장 | `RK` | — | `pwrk save-apply` |
|
||||
| 33 | 상세 | USER01 | 검토자 | `RK` | 검토완료 | `RK` | 다음 결재자 | `process` |
|
||||
| 34 | 상세 | USER01 | 승인자 | `RK` | 결재(승인) | `RK` | 다음 결재자 | `process` |
|
||||
| 35 | 상세 | USER01 | 최종승인자 | `RK` | 결재(회신) | `RR` | 환경청 | `process` 최종 |
|
||||
| 36 | 상세 | USER03 | - | `RR` | 실무협의서 관리(조회), 검토결과 회신 | `EP` | 광역 | `tech-review` |
|
||||
| 37 | 작성/상세 | USER04 | - | `EP` | 결과회신, 실무협의서 관리(조회) | `TA` | 기초 | `updatePrgrsStts` |
|
||||
| 38 | 상세 | USER05 | - | `TA` | 결과회신, 실무협의서 관리(조회) | — | — | **API 없음. 조회** |
|
||||
|
||||
`SL` 20~22행: 버튼은 직전 상태에 따라 **하나만** 노출. 파일 루프면 [파일보완완료], 그 외 [보완완료].
|
||||
|
||||
---
|
||||
|
||||
## 3. `button-config` 권장 구조
|
||||
|
||||
액션 키는 현행 `FNRS_CNSLTN_VIEW_BUTTON_ACTION`을 확장한다. 신규·이름 변경:
|
||||
|
||||
| 신규/변경 액션 | 라벨 | 비고 |
|
||||
| --- | --- | --- |
|
||||
| `fileSplmnt` | 파일보완 | `ER` 접수자. 현행에 없음 |
|
||||
| `fileVrfc` | 파일검증 | 유지. `ER` 재실행 |
|
||||
| `dsgntRvwr` | 검토자지정 | `ER→AC`(1차), `EV→RK`(2차) |
|
||||
| `pwrkCnsltnDocMng` | 실무협의서관리 | 유지. `TE`·`RK`·`RB`·`RA`(조회 전용) |
|
||||
| `pwrkCnsltnDocCrt` | 실무협의서생성 | 유지. 실패/타임아웃만 |
|
||||
| `rvwRsltInq` | 검토결과조회 | 신규 |
|
||||
| `actnCmptn` | 조치완료 | `RB→RA`. `isSubmit:true` |
|
||||
| `actnSbmsn` | 조치결과서제출 | 광역 `RC→RA` |
|
||||
| `rqstActnRvw` | 조치결과 검토의뢰 | 환경청 `RA→AV` |
|
||||
| `costVrfc` | 금액검증 | `RK` |
|
||||
| `lclRply` | 지자체회신 | 광역 `RM→RB` |
|
||||
| `fnrsRsltRply` | 재원협의 결과 회신 | 환경청 `TP→RM` |
|
||||
| `rsltRply` | 결과회신 | `LE→EP`, `RR→EP`, `EP→TA`, `TA` 조회 |
|
||||
| `fileSplmntCmptn` | 파일보완완료 | `SL←ER` |
|
||||
| `splmntCmptn` | 보완완료 | `SL←TE\|RK` |
|
||||
|
||||
**삭제**: `fnrsCnsltnAncmnt`(고시→`TB`), `sncnAprv`(인가승인). `EP`/`TA`는 `rsltRply`로 통일.
|
||||
|
||||
### 3-1. 역할 × 상태 (공단 제외)
|
||||
|
||||
```
|
||||
ROLE_USER05
|
||||
"" | SV → 저장, 신청완료, 삭제
|
||||
SL → (직전 ER) 파일보완완료 | (직전 TE|RK) 보완완료
|
||||
RB → 실무협의서 관리, 조치완료
|
||||
TA → 결과회신 (조회), 실무협의서 관리(조회)
|
||||
|
||||
ROLE_USER04
|
||||
ST → 환경청제출 // 현행 반려(rjct→SV)는 SoT 38행에 없음. 유지 시 별도 합의
|
||||
RM → 지자체회신
|
||||
RC → 조치결과서제출
|
||||
EP → 결과회신, 실무협의서 관리(조회)
|
||||
|
||||
ROLE_USER03
|
||||
LE → 결과회신(자체종결), 기술검토 의뢰
|
||||
TP → 재원협의 결과 회신
|
||||
RA → 실무협의서 관리(조회), 조치결과 검토의뢰
|
||||
RR → 실무협의서 관리(조회), 검토결과 회신 (`tech-review` → `EP`)
|
||||
```
|
||||
|
||||
### 3-2. 공단 결재선 × 상태
|
||||
|
||||
```
|
||||
ER / ATRZ01 접수자
|
||||
→ 파일보완, 파일검증, 검토자지정
|
||||
|
||||
EV / ATRZ01 접수자
|
||||
→ 검토자지정 (2차 결재선. 1차 결재선 시드, 서식 선택 없음)
|
||||
|
||||
TE / ATRZ02 검토자
|
||||
→ (초안 성공) 실무협의서관리, 검토결과조회, 저장, 검토완료, 보완요청
|
||||
→ (초안 실패·타임아웃) 실무협의서생성 (+ 위 항목 중 관리/조회는 초안 생긴 뒤)
|
||||
|
||||
TE / ATRZ03 승인자 → 결재(승인)
|
||||
TE / ATRZ99 최종 → 결재(회신)
|
||||
|
||||
RK / ATRZ02 검토자
|
||||
→ (초안 완료) 실무협의서관리
|
||||
→ (초안 완료 + 결재 대기 ATRZ_PRGRS_002, cycl2) 보완요청, 검토완료
|
||||
· 보완요청 UI: TE와 동일 SplmntDmndDialog
|
||||
RK / ATRZ03 → (초안 완료) 실무협의서관리, (cycl2 pending) 결재(승인)
|
||||
RK / ATRZ99 → (초안 완료) 실무협의서관리, (cycl2 pending) 결재(회신)
|
||||
· 결재 UI: ElaprApprovalDialog (elaprCycl=2) 승인/반려 → PUT process
|
||||
```
|
||||
|
||||
`FV`, `AC`, `AV`: 액션 빈 배열 + 진행 패널.
|
||||
|
||||
`PENDING_APPROVAL_ACTIONS`: `dmndSplmnt`, `rvwCmptn`, `atrzAprv`, `atrzRply`만.
|
||||
`pwrkCnsltnDocMng`는 결재 대기와 무관(초안 완료만). ATRZ02·ATRZ03·ATRZ99라도 pending 없으면 관리만 노출.
|
||||
|
||||
---
|
||||
|
||||
## 4. 초안 성공 vs 실패 버튼
|
||||
|
||||
`TE`에서 `crtDmndList[].crtSttsComCd` / 폴링 `status`로 분기.
|
||||
|
||||
| 조건 | 노출 |
|
||||
| --- | --- |
|
||||
| `C` / `COMPLETED` | 실무협의서관리, 검토결과조회, 저장, 검토완료, 보완요청 |
|
||||
| `F` / `FAILED` 또는 30분 Fallback 후 초안 없음 | 실무협의서생성 |
|
||||
| `R`/`I` 생성 중 | 진행 패널. 위 버튼 비활성 (`AC`와 동일 UX, 상태가 이미 `TE`면 패널+생성 버튼) |
|
||||
|
||||
`RK`는 금액검증 성공이 기본. Fallback 후 [금액검증] 재실행만 추가 노출.
|
||||
|
||||
---
|
||||
|
||||
## 5. 현행 `button-config.ts`와의 차이
|
||||
|
||||
| 항목 | 현재 | To-Be |
|
||||
| --- | --- | --- |
|
||||
| USER05 | `""/SV/TA(고시)` | `SL`, `RB` 추가. `TA`는 조회 |
|
||||
| USER04 | `ST`(제출+반려), `EP`(인가승인) | `RM/RC/EP` 추가. 인가승인 삭제 |
|
||||
| USER03 | `LE`, `TP`(→EP로 회신) | `RA`, `RR` 추가. `TP`는 `RM` |
|
||||
| USER01 | `ER`(파일검증, 검토자지정), `TE` | `ER`에 파일보완. `RK` 전면 추가 |
|
||||
| USER01 ATRZ | `ER`, `TE`만 `needsRoleUser01AtrzResolve` | `RK` 포함 |
|
||||
@@ -0,0 +1,674 @@
|
||||
# dmbpRegist.jsp → React 마이그레이션 분석·구현 가이드
|
||||
|
||||
| 항목 | 내용 |
|
||||
| ----------- | ------------------------------------------------------ |
|
||||
| 원본 JSP | `adssNewOld/.../fnrsc/dmbp/dmbpRegist.jsp` |
|
||||
| 대상 앱 | `frontend/apps/as` |
|
||||
| 도메인 | 하수도기본계획 (구: 기본계획검토 / dmbp) |
|
||||
| API 엔티티 | `@/entities/sewer-bsc-plan` (`SewerBscPlanController`) |
|
||||
| 참조 패턴 | `@/pages/fnrs-cnsltn` + `@/widgets/pbadms-sprt` |
|
||||
| 문서 목적 | contents 영역 **섹션별** UI·상태·API 매핑 및 구현 방향 |
|
||||
| 작성 기준일 | 2026-07-27 |
|
||||
|
||||
---
|
||||
|
||||
## 1. 마이그레이션 범위
|
||||
|
||||
### 1-1. 포함 (contents만)
|
||||
|
||||
JSP `568~1274`행: `<div class="contents">` ~ `<!-- //contents -->`
|
||||
|
||||
| 영역 | JSP 식별 | 개요 |
|
||||
| ---- | ---------------------------------- | --------------------------------------------------------------- |
|
||||
| A | `gTitle1` | 페이지 타이틀·브레드크럼 |
|
||||
| B | `slide_10` | 기본계획변경 신청(마스터·연도·개요) |
|
||||
| C | `slide_15` | 신청자·설계자 정보 |
|
||||
| D | `slide_19` | 개인정보 동의 |
|
||||
| E | `slide_11` | 사업개요(단계별 인구·보급률) |
|
||||
| F | `slide_12` | 총사업비 — `BizCstMatrixFormSection` 전용 |
|
||||
| G | `slide_13` | 재원분담 |
|
||||
| H | `slide_14` | 처리시설별 하수도정비기본계획 (Checkbox + Tabs) |
|
||||
| I | `slide_16` | 체크리스트 + 필수첨부 + 기타첨부 |
|
||||
| J | JSP 상단 `saveBtn` / `presentnBtn` | React: 폼 하단 액션바 (`fnrs-form-page` 279~323과 동일 구성, API만 sewer) |
|
||||
|
||||
### 1-2. 제외
|
||||
|
||||
- `<%@ include %>`: top / sideMenu / footer / `bscPlnPopup.jsp` / `sndrdBzAmnt.jsp`
|
||||
- 레이아웃·메뉴·권한 셸 → 기존 `BaseLayout` / `PageLayout` / AUTH 체계
|
||||
- `mStep1` 진행 단계 표시 (미구현 · 마이그레이션 범위 밖)
|
||||
|
||||
팝업(`이전기본계획조회`)은 **별도 Dialog 컴포넌트**로 재구현하며, include JSP 자체는 포팅하지 않는다.
|
||||
|
||||
---
|
||||
|
||||
## 2. 목표 아키텍처
|
||||
|
||||
```
|
||||
app/(with-base-layout)/sewer-bsc-plan/regist/page.tsx
|
||||
└─ pages/sewer-bsc-plan/ui/sewer-bsc-plan-regist-page.tsx
|
||||
└─ sewer-bsc-plan-form-page.tsx # FormProvider + 섹션 조립
|
||||
├─ sections/*-form-section.tsx # 도메인 전용
|
||||
└─ widgets/pbadms-sprt/* # 공통 재사용
|
||||
|
||||
entities/sewer-bsc-plan/ # 이미 구현됨
|
||||
saveApply / findDetails / submitSupplement …
|
||||
```
|
||||
|
||||
**폼 스택 (fnrs-cnsltn과 동일)**
|
||||
|
||||
- `react-hook-form` + `zod` (`zodResolver`, `mode: "onChange"`)
|
||||
- 섹션 래퍼: `SectionCollapsible` (Accordion 아님)
|
||||
- UI: `@common/components` (Input, Select, Textarea, Button, Radio, Tabs, Table 등)
|
||||
- 그리드가 필요한 곳만 `@tanstack/react-table` + `DataTable`
|
||||
- 데이터: React Query (`useSaveApplySewerBscPlan` 등) — 목데이터는 API 미연동 구간만 `@faker-js/faker`
|
||||
|
||||
**Vercel React Best Practices (적용 요약)**
|
||||
|
||||
- `client-swr-dedup`: React Query로 체크리스트/필수첨부/코드 조회 중복 제거
|
||||
- `bundle-dynamic-imports`: 처리시설 Tabs 패널·이전계획 Dialog는 `next/dynamic` 후보
|
||||
- `rerender-derived-state`: 단계 연도·합계·진행률은 render 중 파생, 불필요 effect 금지
|
||||
- `async-parallel`: 등록 진입 시 코드/체크리스트트리/필수첨부트리를 병렬 조회
|
||||
|
||||
---
|
||||
|
||||
## 3. 전체 레이아웃
|
||||
|
||||
`fnrs-form-page.tsx`와 동일한 **FormProvider + 세로 섹션 스택** 구조를 따르고,
|
||||
하단 액션바는 **[`fnrs-form-page.tsx` 279~323](../../src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx)** 과 동일 구성(목록·저장·신청완료·삭제·보완완료)이며 **API/라우트만 sewer** 로 바꾼다.
|
||||
타이틀·브레드크럼은 폼 밖(`PageLayout` / regist·edit·view 셸)에서 처리한다.
|
||||
(상세 View의 sticky FAB·검토/결재 버튼은 본 등록 문서 범위 밖 — `fnrs-view-page` 대응 후속.)
|
||||
|
||||
### 3-1. 컴포넌트 트리 (fnrs 대응)
|
||||
|
||||
```
|
||||
PageLayout (title / breadcrumb)
|
||||
└─ SewerBscPlanRegistPage | SewerBscPlanEditPage | SewerBscPlanViewPage
|
||||
└─ SewerBscPlanFormPage | SewerBscPlanViewPage 본문
|
||||
FormProvider (등록/수정) / 읽기 섹션 (상세)
|
||||
└─ <form|div className="mt-6 space-y-4">
|
||||
├─ BasicInfoFormSection // JSP slide_10
|
||||
├─ ContactInfoFormSection // JSP slide_15 (pbadms-sprt)
|
||||
├─ PrivacyConsentSection // JSP slide_19 (pbadms-sprt, 등록·수정)
|
||||
├─ OutlineFormSection // JSP slide_11 (사업개요, 신규)
|
||||
├─ BizCstMatrixFormSection // JSP slide_12 (총사업비 전용, 신규)
|
||||
├─ FnrsCstFormSection // JSP slide_13 (재원분담, 신규 ※ FnrsShar 아님)
|
||||
├─ TmplntFormSection // JSP slide_14 (처리시설, Tabs로 시설별 패널)
|
||||
├─ ChecklistFormSection // JSP slide_16 (pbadms-sprt)
|
||||
├─ AttachmentsFormSection // JSP 필수·기타첨부 (pbadms-sprt)
|
||||
├─ SplmntDmndFormSection // edit + SL 상태만 (pbadms-sprt)
|
||||
└─ form footer action bar // fnrs-form-page 279~323 동일
|
||||
// [목록] / [저장] / edit시 [신청완료][삭제] / SL시 [보완완료]
|
||||
```
|
||||
|
||||
**폼 하단 액션바 버튼 구성**
|
||||
기준: [`fnrs-form-page.tsx` 279~323](../../src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx). UI·분기만 동일하고 훅/라우트는 sewer.
|
||||
|
||||
| 순서 | 버튼 | 조건 | sewer 비고 |
|
||||
| ---- | -------- | ----------------------------------------- | ---------------------------------------------------- |
|
||||
| 1 | 목록 | 항상 | `router.push("/sewer-bsc-plan")` |
|
||||
| 2 | 저장 | `!isSplmntPrgrsStts` | `type="submit"` → `saveApply` / 임시저장(SV) |
|
||||
| 3 | 신청완료 | `!isSplmntPrgrsStts && isEditMode` | 체크리스트+필수첨부 검증 → `saveApply` / LE |
|
||||
| 4 | 삭제 | `!isSplmntPrgrsStts && isEditMode` | confirm → `delete` → 목록 |
|
||||
| 5 | 보완완료 | `isSplmntPrgrsStts` (`prgrsSttsComCd=SL`) | `submitSupplement` (fnrs `onSplmntCmptn` 대응) |
|
||||
|
||||
**fnrs와의 차이 (섹션 치환만, 골격 동일)**
|
||||
|
||||
| fnrs-form-page | sewer-bsc-plan |
|
||||
| ---------------------------------------------- | ------------------------------------------------------ |
|
||||
| `BasicInfoFormSection` | 동일 역할 (마스터·연도·개요 필드는 sewer DTO) |
|
||||
| `ContactInfoFormSection` | 동일 (`fieldPrefix="sewerBscPlanDtl"`) |
|
||||
| `PrivacyConsentSection` | 동일 |
|
||||
| `BusinessScaleFormSection` | → `OutlineFormSection` (단계별 인구·보급률) |
|
||||
| `BusinessCostFormSection` | → `BizCstMatrixFormSection` (단계×원가 계층 전용) |
|
||||
| `FnrsSharFormSection` | → `FnrsCstFormSection` (국고·지방비·원인자·기타) |
|
||||
| _(없음)_ | `TmplntFormSection` (체크박스 + Tabs 시설별 매트릭스) |
|
||||
| `ChecklistFormSection` `docSeComCd="FNRS"` | `docSeComCd="SEWER"` (TBD) |
|
||||
| `AttachmentsFormSection` | 동일 패턴 |
|
||||
| `SplmntDmndFormSection` | 동일 (`readOnly={!isSplmntPrgrsStts}`) |
|
||||
| 폼 하단 액션바 (목록·저장·신청완료·삭제·보완완료) | **동일 구성, API·라우트만 sewer** |
|
||||
|
||||
### 3-2. 본문 ASCII (폼 페이지)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ PageLayout: 하수도기본계획 신청/수정 breadcrumb │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ FormProvider │
|
||||
│ <form className="mt-6 space-y-4"> │
|
||||
│ │
|
||||
│ ┌─ SectionCollapsible: 기본계획 신청 ─────────────────────┐ │
|
||||
│ │ BasicInfoFormSection │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─ 신청자 정보 ────────────────────────────────────────────┐ │
|
||||
│ │ ContactInfoFormSection │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─ 개인정보 동의 ──────────────────────────────────────────┐ │
|
||||
│ │ PrivacyConsentSection │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─ 사업개요 ────────────── [이전기본계획조회] ─────────────┐ │
|
||||
│ │ OutlineFormSection │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─ 총사업비 (백만원) ──────────────────────────────────────┐ │
|
||||
│ │ BizCstMatrixFormSection │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─ 재원분담 (백만원) ──────────────────────────────────────┐ │
|
||||
│ │ FnrsCstFormSection │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─ 처리시설별 하수도정비기본계획 ──────────────────────────┐ │
|
||||
│ │ TmplntFormSection │ │
|
||||
│ │ ├─ BscFctList Checkbox │ │
|
||||
│ │ └─ Tabs (선택 시설별 TabsTrigger / TabsContent) │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─ 체크리스트 ─────────────────────────────────────────────┐ │
|
||||
│ │ ChecklistFormSection │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─ 첨부파일 ───────────────────────────────────────────────┐ │
|
||||
│ │ AttachmentsFormSection │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ ┌─ 보완요구 (edit + SL) ───────────────────────────────────┐ │
|
||||
│ │ SplmntDmndFormSection │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ form footer (fnrs-form-page 279~323 동일) ──────────────┐ │
|
||||
│ │ [목록] [저장] / edit: [신청완료][삭제] / SL: [보완완료] │ │
|
||||
│ │ ※ API·라우트만 sewer — UI 분기는 fnrs와 동일 │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ </form> │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3-3. 액션바 동작 (`fnrs-form-page` 279~323 동일, API만 sewer)
|
||||
|
||||
구현 위치: `sewer-bsc-plan-form-page.tsx` 하단
|
||||
(`fnrs-form-page.tsx`의 `mx-4 flex flex-wrap justify-center gap-3` 블록을 그대로 옮기고 훅·path만 교체)
|
||||
|
||||
| 버튼 | 조건 | 대표 동작 |
|
||||
| -------- | ---------------------------- | -------------------------------------------------------------------------- |
|
||||
| 목록 | 항상 | `router.push("/sewer-bsc-plan")` |
|
||||
| 저장 | `!isSplmntPrgrsStts` | `type="submit"` → `saveApply` + 임시저장(`SV`) |
|
||||
| 신청완료 | edit && `!isSplmntPrgrsStts` | 체크리스트 완료 + **필수 첨부 완료** 검증 → `saveApply` + `LE` |
|
||||
| 삭제 | edit && `!isSplmntPrgrsStts` | confirm → `delete` → 목록 |
|
||||
| 보완완료 | `isSplmntPrgrsStts` (SL) | `form.handleSubmit` → `useSubmitSupplementSewerBscPlan` |
|
||||
|
||||
**신청완료 사전 검증** (fnrs `handleApplyClick`과 동일 정책)
|
||||
|
||||
1. **체크리스트**: `isFormChecklistComplete(cklstResultList)` — 미완료 시 `"모든 체크리스트 항목을 체크해야 신청이 가능합니다."`
|
||||
2. **필수 첨부**: `esntlAtchYn === "Y"`인 필수첨부 슬롯마다 `esntlAtchFileList`에 `atchFileGroupId`가 있어야 함
|
||||
- Form: `AttachmentsFormSection`의 트리 + 폼 `esntlAtchFileList`
|
||||
- 미충족 시 예: `"필수 첨부파일을 모두 등록해야 신청이 가능합니다."`
|
||||
- 헬퍼 후보: `isFormEsntlAtchComplete(requiredTree, esntlAtchFileList)` (`pbadms-sprt`에 추가)
|
||||
|
||||
저장에는 위 검증을 적용하지 않는다 (임시저장 허용).
|
||||
|
||||
저장/제출 버튼을 섹션 헤더(`gTitle2 gRt`)에 두지 않는다 — **폼 하단 액션바 단일 진입점** (§4-J).
|
||||
|
||||
### 3-4. 라우트
|
||||
|
||||
| 화면 | path | 셸 → FormPage |
|
||||
| ---- | --------------------------- | ------------------------------------------ |
|
||||
| 등록 | `/sewer-bsc-plan/regist` | `mode="create"` |
|
||||
| 수정 | `/sewer-bsc-plan/[id]/edit` | `mode="edit"` + `useSewerBscPlanDetails` |
|
||||
| 상세 | `/sewer-bsc-plan/[id]` | ViewPage (본 문서 범위 밖, fnrs-view 대응) |
|
||||
|
||||
`docSeComCd` 후보: 백엔드 체크리스트·필수첨부 등록값 확인 후 **`SEWER`** (또는 레거시 `DMBP`) — **TBD, CMS 코드와 맞출 것**.
|
||||
|
||||
---
|
||||
|
||||
## 4. 섹션별 상세 구현
|
||||
|
||||
### 4-0. Hidden / 세션 컨텍스트 (폼 루트)
|
||||
|
||||
JSP hidden → React 폼 기본값·세션 스토어로 흡수.
|
||||
|
||||
| JSP | 의미 | React |
|
||||
| ------------------------------- | --------------- | ------------------------------------------------------- |
|
||||
| `chgSe` / `chgSeSp` / `chgSeCd` | 변경구분 | `sewerBscPlan.sewerBscPlanSeComCd` + 표시용 코드명 |
|
||||
| `progrsSttus` | SAVE / PRESENTN | 저장·제출 시 `prgrsSttsComCd`로 매핑 (임시저장 vs 제출) |
|
||||
| `planSeCd` | 고정 `A` | 필요 시 상수 또는 API 필드 확인 |
|
||||
| `adstDstrCd` / `rgnCd` | 행정구역 | `sewerBscPlan.admdstCd` |
|
||||
| `sidoNm` / `gugunNm` | 표시용 | 읽기 전용 표시 (`detDto.sido`/`gugun`) |
|
||||
|
||||
구현: `getCreateDefaultValues(userInfo)`에서 로그인 사용자·소속 지자체 주입.
|
||||
|
||||
---
|
||||
|
||||
### 4-A. 타이틀·브레드크럼
|
||||
|
||||
| JSP | React |
|
||||
| ------------------------ | ------------------------------------------------------ |
|
||||
| `h3` 기본계획검토 | PageLayout title: **하수도기본계획 신청** (IIPBS 명명) |
|
||||
| 설치인가 및 제원협의 > … | 메뉴 메타 기반 breadcrumb |
|
||||
|
||||
별도 섹션 컴포넌트 불필요. 라우트 `page.tsx` / layout metadata로 처리.
|
||||
|
||||
---
|
||||
|
||||
### 4-B. 기본계획변경 신청 (`slide_10`)
|
||||
|
||||
**파일**: `ui/sections/basic-info-form-section.tsx`
|
||||
**래퍼**: `SectionCollapsible` title=`기본계획 신청`
|
||||
**필드 접두사**: `sewerBscPlan.*` + `sewerBscPlanDtl.*`
|
||||
|
||||
| 표시명 | JSP | API 매핑 | UI | 필수 | 비고 |
|
||||
| ---------------- | ----------------- | ------------------------------- | ------------------ | ---- | ---------------------------------- |
|
||||
| 기본계획명 | `drngMtncPlanNm` | `sewerBscPlan.sewerBscPlanNm` | Input | Y | |
|
||||
| 계획년도 | `planYr` | `sewerBscPlanDtl.planYr` | Select (현재~2005) | Y | |
|
||||
| 기준년도 | `crtrYr` | `sewerBscPlanDtl.crtrYr` | Select | Y | |
|
||||
| 1~4단계 목표연도 | `goalYrStep1~4` | `frlvlGoalYr`~`folvlGoalYr` | Select (현재~+30) | Y | 1단계 변경 시 +5/+10/+15 자동 연동 |
|
||||
| 계획개요 | `bzCn` | `sewerBscPlanDtl.bizOtlnCn` | Textarea | Y | |
|
||||
| 구분 | `#chgSeNm` | `sewerBscPlanSeComCd` (+코드명) | 읽기 또는 Select | | 신규/변경 등 |
|
||||
| 신청 지자체 | `${lclgvrnmntNm}` | `admdstCd` | 읽기 전용 | | |
|
||||
|
||||
**동작**
|
||||
|
||||
- `goalYrStep1` onChange → 2·3·4단계 기본값 세팅 + E/F/G 헤더 연도 span 갱신 (`watch` 파생)
|
||||
- JSP 상단 `gRt` 저장/제출은 사용하지 않음 → FormPage 하단 액션바 (§3-3, §4-J)
|
||||
|
||||
---
|
||||
|
||||
### 4-C. 신청자 정보 (`slide_15`)
|
||||
|
||||
**재사용**: `@/widgets/pbadms-sprt`의 `ContactInfoFormSection`
|
||||
**props**: `fieldPrefix="sewerBscPlanDtl"` (또는 dtl 필드 구조에 맞게)
|
||||
|
||||
| 표시 | JSP | API |
|
||||
| ---------------------------- | --------------------------- | --------------------------------------------------------------------------------------- |
|
||||
| 신청자 이름/전화/부서/이메일 | `${UsrNm}` 등 서버렌더 | 로그인 사용자 읽기 전용 → `aplcntNm`, `aplcntMblTelno`, `aplcntOgdpNm`, `aplcntEmlAddr` |
|
||||
| 설계자 | `dsgnrNm/Telno/Psitn/Email` | `dsgnrNm`, `dsgnrTelno`, `dsgnrOgdpNm`, `dsgnrEmlAddr` |
|
||||
|
||||
신청자 4필드는 세션에서 defaultValues에 채우고 Input `disabled`.
|
||||
|
||||
---
|
||||
|
||||
### 4-D. 개인정보 동의 (`slide_19`)
|
||||
|
||||
**재사용**: `PrivacyConsentSection`
|
||||
|
||||
| JSP | React |
|
||||
| ----------------------------- | ------------------------------------------------------------------ |
|
||||
| 고지 textarea + 보유기간 문구 | 동일 문구 상수/마크다운 |
|
||||
| `privacyAgree` Y/N | 폼 필드 `privacyAgree: "Y" \| "N"` (API 미전송, 클라이언트 검증만) |
|
||||
|
||||
**검증**: 제출 시 `Y` 필수 (JSP `presentnBtn`과 동일). 저장(임시)은 동의 없이 허용할지 정책 TBD — 기본은 JSP와 같이 **제출만 강제**.
|
||||
|
||||
---
|
||||
|
||||
### 4-E. 사업개요 (`slide_11`)
|
||||
|
||||
**파일**: `ui/sections/outline-form-section.tsx` (신규, 도메인 전용)
|
||||
**API**: `sewerBscPlanOtlnList: SewerBscPlanOtlnItem[]` (planStpNo 1~4)
|
||||
|
||||
| 행(구분) | JSP name | Item 필드 |
|
||||
| ------------ | --------------- | ------------------- |
|
||||
| 계획인구 | `arrPlanPpltn` | `sewerPlanPpltnCnt` |
|
||||
| 처리인구 | `arrPrcsPpltn` | `sewerPrcsPpltnCnt` |
|
||||
| 하수도보급율 | `arrDrngSplyRt` | `sewerPsplyRt` |
|
||||
|
||||
열: 1~4단계 (헤더에 `frlvlGoalYr` 등 표시).
|
||||
|
||||
**버튼**: `이전기본계획조회` → Dialog (`PreviousPlanLookupDialog`)
|
||||
|
||||
- 레거시: `fnbscPlnPopupToggle` + `bscPlnPopup.jsp`
|
||||
- React: Modal + 조회 API (**TBD**: 이전 계획 조회 엔드포인트; 없으면 1차는 Dialog UI만 + mock)
|
||||
|
||||
숫자 입력: 콤마 제거 후 number 전송 (제출 시 JSP `replaceComma` 대체).
|
||||
|
||||
---
|
||||
|
||||
### 4-F. 총사업비 (`slide_12`)
|
||||
|
||||
**파일**: `ui/sections/biz-cst-matrix-form-section.tsx` (**전용 컴포넌트** — fnrs `BusinessCostFormSection` 재사용 금지)
|
||||
**래퍼**: `SectionCollapsible` title=`총사업비` (단위 `백만원`은 헤더 우측)
|
||||
|
||||
**JSP 현실**: 단계(1~4) × 원가 계층(총사업비, 공사비, 처리시설, 하수관로 신설/보수, 펌프장, 배수설비, 기타, 부대경비, 설계/감리/부대비). 일부 readonly·자동합산 JS.
|
||||
|
||||
**신규 API**: `bizCstList: SewerBscPlanBizCstItem[]` = `{ planStpNo, acntgSeCd, cstrnAmt }`
|
||||
|
||||
**구현 방향 (`BizCstMatrixFormSection` 전용)**
|
||||
|
||||
- 행 = `useAcntgSeMngTree` → `buildAcntgCostItems` (fnrs `BusinessCostFormSection`과 동일 출처)
|
||||
- `costItems` 로드 시 `useEffect`로 `bizCstList`를 `mergeBizCstList(existing, costItems)`로 동기화
|
||||
- 열 = `planStpNo` 1~4 (헤더에 목표연도 표시)
|
||||
- readonly 행(`CostItemDef.readonly=true`)은 children 합산으로 자동계산; Input에 `readOnly` + `bg-muted`
|
||||
- 변경 시 `setAmt` → `recalculateBizCstMatrix(list, costItems)` → `setValue("bizCstList")`
|
||||
- 저장 시 섹션 onChange 합산을 신뢰하여 `bizCstList` 그대로 전송 (`toBizCstSaveList` identity)
|
||||
|
||||
**표준사업비 조회** 버튼은 JSP에서 주석 처리됨 → **미구현**.
|
||||
|
||||
---
|
||||
|
||||
### 4-G. 재원분담 (`slide_13`)
|
||||
|
||||
**주의**: fnrs의 `FnrsSharFormSection`(재원협의 공유구분 트리)과 **다름**.
|
||||
|
||||
| 행 | JSP | `SewerBscPlanFnrsCstItem` |
|
||||
| ------------ | -------------- | ------------------------- |
|
||||
| 총사업비 | `arrTotAmnt` | `sumAmt` (또는 파생) |
|
||||
| 국고 | `arrNlepAmt` | `gvexpAmt` |
|
||||
| 지방비 | `arrLcepAmt` | `lcexpAmt` |
|
||||
| 원인자부담금 | `arrCusrAlotm` | `orgprBdchgAmt` |
|
||||
| 기타 | `arrEtcAmt` | `etcAmt` |
|
||||
|
||||
**파일**: `ui/sections/fnrs-cst-form-section.tsx` (신규)
|
||||
데이터: `fnrsCstList` 길이 4 (`planStpNo` 1~4).
|
||||
|
||||
검증(선택): 단계별 `gvexp+lcexp+orgpr+etc === sumAmt` (JSP `calculateTotalFunding` 참고).
|
||||
|
||||
---
|
||||
|
||||
### 4-H. 처리시설별 하수도정비기본계획 (`slide_14`) — 핵심 복잡도
|
||||
|
||||
**JSP 동작**
|
||||
|
||||
1. `BscFctList` 체크박스로 처리시설 다중 선택 (`arrBscFctCd`)
|
||||
2. 선택 시 `createFormSection(code, name)`로 **당초 4단계 | 현재 | 변경 4단계** 매트릭스 동적 삽입
|
||||
→ **React**: 세로 삽입 대신 `@common/components` `Tabs`로 시설별 패널 관리 (§아래 Tabs 규칙)
|
||||
3. 활성 `formFields`(축소판): 처리구역면적, 하수처리인구, 계획하수량, 시설용량, 분류식 오수/우수, 합류식, 차집, 배수설비, 오수중계/일반/우수 펌프
|
||||
4. 시설별 필수첨부 `createFileAttachmentSection`
|
||||
5. `fetchBasicPlanData`로 당초(이전) 데이터 바인딩
|
||||
|
||||
**API 매핑**
|
||||
|
||||
| UI | DTO |
|
||||
| -------------------- | ------------------------------------------------------------- |
|
||||
| 선택 시설 목록 | `sewerBscPlanTmplntList[].swtrmtFcltCd` (+ `atchFileGroupId`) |
|
||||
| 단계별 수치 (변경측) | `sewerBscPlanTmplntDtlList[]` → `SewerBscPlanTmplntDtlItem` |
|
||||
| 임시저장 | `tmplntTmprStrgList` (편집 중 임시, 필요 시) |
|
||||
|
||||
필드 대응 (변경 단계 기준):
|
||||
|
||||
| UI 라벨 | `SewerBscPlanTmplntDtlItem` |
|
||||
| -------------- | --------------------------- |
|
||||
| 처리구역면적 | `prcsZoneArea` |
|
||||
| 하수처리인구 | `swtrmtPpltnCnt` |
|
||||
| 계획하수량 | `planSwqty` |
|
||||
| 시설용량 | `fcltCpct` |
|
||||
| 분류식 오수 | `sprsysDrtwPplLen` |
|
||||
| 분류식 우수 | `sprsysExlnPplLen` |
|
||||
| 합류식 | `cbsysPplLen` |
|
||||
| 차집관로 | `icptgPplLen` |
|
||||
| 배수설비 | `drgCnt` |
|
||||
| 오수 중계 펌프 | `drtwRlyPumpCnt` |
|
||||
| 오수 일반 펌프 | `drtwPumpCnt` |
|
||||
| 우수 펌프 | `exlnPumpCnt` |
|
||||
|
||||
**구현 구성**
|
||||
|
||||
```
|
||||
ui/sections/tmplnt-form-section.tsx
|
||||
├─ TmplntFacilityPicker # BscFctList Checkbox 목록 (시설 마스터 API TBD)
|
||||
└─ Tabs (@common/components Tabs) # 선택 시설별 동적 패널
|
||||
├─ TabsList / TabsTrigger # value=swtrmtFcltCd, 라벨=시설명
|
||||
└─ TabsContent (시설 1개당)
|
||||
├─ TmplntMatrixTable # 당초|현재|변경 매트릭스 (useFieldArray)
|
||||
└─ TmplntFacilityAttachments # 시설별 필수첨부 (선택)
|
||||
```
|
||||
|
||||
**Tabs 관리 규칙** (`packages/common/components/src/ui/tabs`)
|
||||
|
||||
- `BscFctList` 체크 **선택** → `useFieldArray` append + 해당 시설 `TabsTrigger`/`TabsContent` 추가 → `Tabs` `value`를 신규 시설로 전환
|
||||
- 체크 **해제** → confirm 후 remove + 해당 탭 제거 → 남은 탭 중 하나로 `value` 이동 (없으면 Tabs 영역 비표시)
|
||||
- 선택 시설이 0개면 Tabs UI 숨김; 1개 이상이면 Tabs로 시설별 패널 전환
|
||||
- 매트릭스·첨부는 각 `TabsContent` 안에만 렌더 (JSP의 세로 동적 삽입을 탭 패널로 대체)
|
||||
|
||||
**매트릭스 열**
|
||||
|
||||
- **당초 열**: 이전계획 API 조회 결과 읽기 전용 (없으면 빈 칸)
|
||||
- **현재 열**: 기준년도 시점 값 (API 제공 시)
|
||||
- **변경 열**: 편집 가능 → 저장 payload의 dtl만 전송
|
||||
|
||||
시설 마스터 목록 API: 레거시 `BscFctList` 대체 — **TBD** (`swtrmtFclt` 계열).
|
||||
|
||||
`bundle-dynamic-imports`: `TmplntFormSection`(또는 TabsContent 내부 매트릭스)을 `next/dynamic` 후보.
|
||||
|
||||
---
|
||||
|
||||
### 4-I. 체크리스트 + 첨부 (`slide_16`)
|
||||
|
||||
#### I-1. 체크리스트
|
||||
|
||||
**재사용**: `ChecklistFormSection`
|
||||
`docSeComCd="<SEWER|DMBP TBD>"`
|
||||
`fieldPrefix`: 마스터에서 `taskSeComCd`를 읽는 경로 (예: `sewerBscPlan`)
|
||||
|
||||
| JSP | React |
|
||||
| ----------------------- | ------------------------------------------- |
|
||||
| 업무탭 `ceckEssntlArr` | 코드 `taskSeComCd` 다중 → Tabs |
|
||||
| 진행률 / 전체 예·아니오 | 위젯 내장 로직 |
|
||||
| `exmntResult` Y/N | `cklstResultList[].selected` (+ `picRvwCn`) |
|
||||
|
||||
저장: `cklstResultList: CklstResultItem[]`
|
||||
|
||||
#### I-2. 필수 첨부 (탭별)
|
||||
|
||||
**재사용**: `AttachmentsFormSection`
|
||||
`docSeComCd` 동일, `esntlAtchFileList`
|
||||
|
||||
레거시: 체크리스트 탭마다 `essntlList` + `uploadFile` multipart.
|
||||
신규: TUS/`attach-service` + `esntlAtchFileId` / `atchFileGroupId` (fnrs와 동일).
|
||||
|
||||
#### I-3. 기타 첨부
|
||||
|
||||
`AttachmentsFormSection`의 etc 영역 또는 `atchFileGroupId` on `sewerBscPlanDtl`.
|
||||
JSP `uploadFileETC` multiple → Zip 안내 문구 유지.
|
||||
|
||||
---
|
||||
|
||||
### 4-J. 저장 / 제출
|
||||
|
||||
**UI 구성**: [`fnrs-form-page.tsx` 279~323](../../src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx) 과 **동일**.
|
||||
마크업·분기(`isSplmntPrgrsStts` / `isEditMode`)·버튼 색상·`disabled={isSubmitting}` 패턴을 그대로 두고, **호출 API·목록 path만 sewer** 로 교체한다.
|
||||
|
||||
```tsx
|
||||
<div className="mx-4 flex flex-wrap justify-center gap-3 sm:gap-4">
|
||||
<Button color="white" type="button" onClick={() => router.push("/sewer-bsc-plan")} disabled={isSubmitting}>
|
||||
목록
|
||||
</Button>
|
||||
{!isSplmntPrgrsStts ? (
|
||||
<>
|
||||
<Button type="submit" disabled={isSubmitting}>저장</Button>
|
||||
{isEditMode && (
|
||||
<>
|
||||
<Button color="green" type="button" onClick={handleApplyClick} disabled={isSubmitting}>
|
||||
신청완료
|
||||
</Button>
|
||||
<Button color="red" type="button" onClick={handleDelClick} disabled={isSubmitting}>
|
||||
삭제
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Button type="button" onClick={form.handleSubmit(onSplmntCmptn)} disabled={isSubmitting}>
|
||||
보완완료
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
```
|
||||
|
||||
| 버튼 | fnrs 대응 | sewer API / 동작 |
|
||||
| -------- | ----------------------------- | ------------------------------------------------------------ |
|
||||
| 목록 | `router.push("/fnrs-cnsltn")` | `router.push("/sewer-bsc-plan")` |
|
||||
| 저장 | `saveApply` + 임시저장 | `useSaveApplySewerBscPlan` + `prgrsSttsComCd`=임시저장(`SV`) |
|
||||
| 신청완료 | `handleApplyClick` → 제출 | 체크리스트+필수첨부 검증 → `saveApply` + `LE` (상태코드 TBD) |
|
||||
| 삭제 | `handleDelClick` | `useDeleteSewerBscPlan`(또는 동등) → 목록 |
|
||||
| 보완완료 | `onSplmntCmptn` | `useSubmitSupplementSewerBscPlan` |
|
||||
|
||||
| JSP | 진행값 | URL | React |
|
||||
| ---- | ---------- | ------------------------- | ---------------------------------------------------------- |
|
||||
| 저장 | `SAVE` | `insertFnrscDmbp.do` | `saveApply` + 임시저장 코드 |
|
||||
| 제출 | `PRESENTN` | `insertFnrscDscss.do` (!) | `saveApply` + 제출 상태코드 — **백엔드 상태코드 확인 TBD** |
|
||||
|
||||
페이로드 조립 (`buildApplyPayload`):
|
||||
|
||||
```ts
|
||||
SewerBscPlanApplySaveRequestDto {
|
||||
sewerBscPlan, sewerBscPlanDtl,
|
||||
sewerBscPlanOtlnList, bizCstList, fnrsCstList,
|
||||
sewerBscPlanTmplntList, tmplntTmprStrgList?,
|
||||
cklstResultList, esntlAtchFileList,
|
||||
splmntDmndList?, rvwOpnnList? // 등록 화면에서는 보통 빈 배열
|
||||
}
|
||||
```
|
||||
|
||||
성공 후: `invalidateQueries(sewerBscPlanBaseKey)` → `router.push('/sewer-bsc-plan')` (신청완료는 상세로 보낼 수 있음 — fnrs와 동일 정책).
|
||||
|
||||
권한: JSP `AUTH3` → 기존 AS 권한 훅/역할로 버튼 `disabled`/`hidden`.
|
||||
|
||||
---
|
||||
|
||||
## 5. API / DTO 연결
|
||||
|
||||
Base: `/as-service/api/v1/sewer-bsc-plans`
|
||||
엔티티: `@/entities/sewer-bsc-plan`
|
||||
|
||||
| 화면 동작 | Hook / Service | 비고 |
|
||||
| -------------- | ---------------------------------------- | ---------------- |
|
||||
| 등록 저장·제출 | `useSaveApplySewerBscPlan` → `saveApply` | 본 문서 핵심 |
|
||||
| 수정 로드 | `useSewerBscPlanDetails(docNo, chgCycl)` | 편집 시 |
|
||||
| 마스터만 | `useSewerBscPlan` | 목록 행 클릭 등 |
|
||||
| 보완 제출 | `useSubmitSupplementSewerBscPlan` | edit + `prgrsSttsComCd=SL` 시 폼 하단 [보완완료] |
|
||||
| 기술검토 | `useTechReviewSewerBscPlan` | 등록 JSP 범위 밖 |
|
||||
|
||||
등록 JSP에 없는 섹션(보완요구·검토의견)은 **상세/검토 화면**에서 `SplmntDmndFormSection` / 검토의견 섹션으로 후속 구현.
|
||||
|
||||
---
|
||||
|
||||
## 6. 권장 파일 배치
|
||||
|
||||
```
|
||||
apps/as/
|
||||
├── app/(with-base-layout)/sewer-bsc-plan/
|
||||
│ └── regist/page.tsx
|
||||
├── src/pages/sewer-bsc-plan/
|
||||
│ ├── lib/
|
||||
│ │ ├── sewer-bsc-plan-regist-schema.ts # zod
|
||||
│ │ └── form-data-mapper.ts # Det ↔ Form, Apply payload
|
||||
│ ├── model/
|
||||
│ │ └── (필요 시 table columns)
|
||||
│ └── ui/
|
||||
│ ├── sewer-bsc-plan-regist-page.tsx
|
||||
│ ├── sewer-bsc-plan-form-page.tsx
|
||||
│ ├── components/
|
||||
│ │ └── previous-plan-lookup-dialog.tsx
|
||||
│ └── sections/
|
||||
│ ├── basic-info-form-section.tsx
|
||||
│ ├── outline-form-section.tsx # 사업개요
|
||||
│ ├── biz-cst-matrix-form-section.tsx # 총사업비 (전용)
|
||||
│ ├── fnrs-cst-form-section.tsx # 재원분담
|
||||
│ └── tmplnt-form-section.tsx # 처리시설 (Checkbox + Tabs)
|
||||
└── docs/sewer-bsc-plan/
|
||||
└── dmbp-regist-migration.md # 본 문서
|
||||
```
|
||||
|
||||
공통 재사용 (신규 작성 최소화):
|
||||
|
||||
- `ContactInfoFormSection`, `PrivacyConsentSection`
|
||||
- `ChecklistFormSection`, `AttachmentsFormSection`
|
||||
- `SectionCollapsible`
|
||||
- `Tabs` / `TabsList` / `TabsTrigger` / `TabsContent` (`@common/components` — 처리시설 패널)
|
||||
|
||||
도메인 전용 (재사용 금지):
|
||||
|
||||
- `BizCstMatrixFormSection` — 총사업비 (fnrs `BusinessCostFormSection` 미사용)
|
||||
- 폼 하단 액션바 — `fnrs-form-page` 279~323 복제, API만 sewer
|
||||
|
||||
---
|
||||
|
||||
## 7. 화면 데이터 흐름
|
||||
|
||||
```
|
||||
BEGIN
|
||||
|
||||
// 최초 진입 (등록)
|
||||
CALL 로그인사용자조회
|
||||
CALL 코드조회(SEWERBSCPLANSE, SEWER, …) // 병렬
|
||||
CALL 체크리스트트리(docSeComCd) // 병렬
|
||||
CALL 필수첨부트리(docSeComCd) // 병렬
|
||||
CALL 처리시설마스터목록 // TBD (BscFctList)
|
||||
DISPLAY 폼 defaultValues
|
||||
|
||||
ON 1단계목표연도 CHANGE DO
|
||||
SET 2·3·4단계 연도 (+5/+10/+15)
|
||||
DISPLAY E/F/G/H 헤더 연도
|
||||
END ON
|
||||
|
||||
ON 처리시설 체크 DO
|
||||
ADD tmplntList 항목
|
||||
ADD TabsTrigger / TabsContent (시설 패널)
|
||||
SET Tabs value = 신규 시설
|
||||
CALL 이전기본계획수치(시설코드) // 당초열, TBD
|
||||
END ON
|
||||
|
||||
ON 처리시설 체크해제 DO
|
||||
CONFIRM 제거
|
||||
REMOVE tmplntList + 해당 Tabs 패널
|
||||
SET Tabs value = 남은 시설 (없으면 Tabs 숨김)
|
||||
END ON
|
||||
|
||||
ON [이전기본계획조회] CLICK DO
|
||||
OPEN PreviousPlanLookupDialog
|
||||
END ON
|
||||
|
||||
ON [저장] CLICK DO
|
||||
VALIDATE zod (동의 제외 가능)
|
||||
CALL saveApply(payload, 임시저장 상태)
|
||||
NAVIGATE 목록
|
||||
END ON
|
||||
|
||||
ON [신청완료] CLICK DO
|
||||
VALIDATE zod + privacyAgree=Y + 체크리스트 완료 + 필수첨부(esntlAtchYn=Y) 완료
|
||||
CONFIRM 신청 확인
|
||||
CALL saveApply(payload, 제출 상태 LE)
|
||||
NAVIGATE 상세
|
||||
END ON
|
||||
|
||||
END
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. JSP ↔ 신규 갭·리스크
|
||||
|
||||
| # | 이슈 | 대응 |
|
||||
| --- | ---------------------------------------------------- | ------------------------------------------------- |
|
||||
| 1 | JSP 제출 URL이 `dscss`로 분기 (오타/구프로세스 가능) | 신규는 `saveApply` 단일 진입으로 통일 |
|
||||
| 2 | 총사업비 UI 계층 ≠ `BizCstItem` | `BizCstMatrixFormSection` 전용 + `acntgSeCd` 매핑 테이블 |
|
||||
| 3 | 재원분담 ≠ fnrs shar | 전용 `fnrs-cst-form-section` |
|
||||
| 4 | 처리시설 매트릭스(당초/현재/변경) | Checkbox 선택 → Tabs 패널; 저장은 변경 dtl 중심; 당초는 조회 전용 |
|
||||
| 5 | 시설·이전계획 API | TBD — 미정 시 체크박스 목록 mock(`faker`)만 |
|
||||
| 6 | `docSeComCd` 값 | CMS/체크리스트 마스터와 합의 |
|
||||
| 7 | 레거시 multipart vs TUS | fnrs 첨부 패턴 준수 |
|
||||
| 8 | 주석 처리된 상세 `formFields` (자연발생인구 등) | **축소된 formFields만** 이관; 주석 블록 복원 금지 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 구현 순서 (권장)
|
||||
|
||||
1. 라우트 + `FormPage` 골격 + zod 스키마(마스터·dtl·동의) + 폼 하단 액션바(§4-J)
|
||||
2. B·C·D 섹션 (공통 위젯 최대 활용)
|
||||
3. E 사업개요 + G 재원분담 (4열 매트릭스 패턴 공유)
|
||||
4. F 총사업비 (`BizCstMatrixFormSection` 전용)
|
||||
5. I 체크리스트·첨부
|
||||
6. H 처리시설 (`BscFctList` Checkbox + `@common/components` Tabs — 가장 복잡)
|
||||
7. 저장/신청완료/삭제/보완완료 API 연동 (§4-J)
|
||||
8. 이전계획 Dialog (API 확정 후)
|
||||
|
||||
---
|
||||
|
||||
## 10. 체크리스트 (jsp-migration-as)
|
||||
|
||||
- [ ] contents만 이관 (include 제외)
|
||||
- [ ] vercel-react-best-practices 적용 (Query 병렬·파생상태·dynamic)
|
||||
- [ ] `@common/components` + 필요 시 DataTable
|
||||
- [ ] API·모델은 `@/entities/sewer-bsc-plan` 우선
|
||||
- [ ] 목데이터는 `@faker-js/faker`만 (시설 마스터 등 TBD 구간)
|
||||
- [ ] 로딩·빈·에러 상태
|
||||
- [ ] `router.push`로 목록 복귀
|
||||
|
||||
---
|
||||
|
||||
## 11. 후속 문서
|
||||
|
||||
- 목록(`dmbpList.jsp`) / 상세(`dmbpView.jsp`) / 수정(`dmbpModify.jsp`)은 본 문서와 동일 섹션 체계로 별도 확장
|
||||
- 화면설계서 SPEC 형식이 필요하면 `docs/sewer-bsc-plan/SPEC.md`로 분리 (영역 A~J 표 + API 표)
|
||||
@@ -0,0 +1,498 @@
|
||||
# 화면설계서: 전국 행정지원 지도 (대시보드 메인)
|
||||
|
||||
## 1. 기본 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
| ---------- | -------------------------------------------- |
|
||||
| 버전 | 1.2 |
|
||||
| 프로세스명 | UI설계 |
|
||||
| 화면명 | 전국 행정지원 지도 (대시보드 메인) |
|
||||
| 화면 ID | TBD |
|
||||
| 화면 유형 | [v] 조회 [ ] 입력 [ ] 수정 [ ] 삭제 [ ] 출력 |
|
||||
| 메뉴 경로 | 메인 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 화면 목적
|
||||
|
||||
로그인 사용자의 **기관 권한·당해 연도** 기준으로 문서별 진행상태 통계와 행정지원 알림을 한 화면에서 조회한다. 좌측 지도에서 전국 행정지원 현황을 보고, 우측에서 진행상황 카드·알림이력·공지사항을 확인한 뒤 알림 [처리하기]로 연계 업무 화면으로 이동한다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 화면 구성
|
||||
|
||||
### 3-1. 전체 레이아웃
|
||||
|
||||
브레드크럼·페이지 타이틀은 스크린샷에 없음. 홈(`/`) 메인 콘텐츠로 구성한다.
|
||||
|
||||
```
|
||||
┌────────────────────────────────┬─────────────────────────────────────────────────┐
|
||||
│ [영역 A] 전국 행정지원 지도 │ [영역 B] 문서별 진행상황 카드 (2×2) │
|
||||
│ 타이틀: 전국 행정지원 지도 │ ┌────────────────┐ ┌────────────────┐ │
|
||||
│ │ │ 재원협의 │ │ 설치인가 │ │
|
||||
│ (대한민국 시도·시군구 경계) │ │ 신청/진행/완료 │ │ 신청/진행/완료 │ │
|
||||
│ 마커: 서울 강남구, │ ├────────────────┤ ├────────────────┤ │
|
||||
│ 대전 유성구, │ │ 설계자문 │ │ 기본계획 │ │
|
||||
│ 부산 해운대구 │ │ 신청/진행/완료 │ │ 신청/진행/완료 │ │
|
||||
│ │ └────────────────┘ └────────────────┘ │
|
||||
│ ├─────────────────────────────────────────────────┤
|
||||
│ │ [영역 C] 알림이력 │
|
||||
│ │ 알림이력 업데이트 HH:mm [전체보기] │
|
||||
│ │ [오늘 N건] [지연 N건] [완료대기 N건] │
|
||||
│ │ [뱃지] [일자] 제목 [처리하기] │
|
||||
│ │ … (최대 5건) │
|
||||
│ ├─────────────────────────────────────────────────┤
|
||||
│ │ [영역 D] 공지사항 [더보기] │
|
||||
│ │ ┌────┬────────┬────────┬────────┬──────┐ │
|
||||
│ │ │번호│ 제목 │ 작성자 │ 작성일 │조회수│ │
|
||||
│ │ └────┴────────┴────────┴────────┴──────┘ │
|
||||
└────────────────────────────────┴─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3-2. 화면 데이터 흐름
|
||||
|
||||
```
|
||||
BEGIN
|
||||
|
||||
// 최초 진입
|
||||
// searchYear 미전달 → 서버가 당해 연도로 고정. 알림 목록은 최신 5건
|
||||
CALL getMainDashboard(DashboardMainSearchDto) // Authorization은 client 인터셉터
|
||||
DISPLAY 진행상황 카드 (영역 B) // docPrgrsSttsList, TOTAL 행 제외
|
||||
DISPLAY 알림 통계 칩 · 알림 목록 (영역 C) // notiStats, notiList
|
||||
|
||||
CALL getUserPostList(UserPostSearchParams) // board-service, AS_DASHBOARD_BBS_ID
|
||||
DISPLAY 공지사항 그리드 (영역 D)
|
||||
|
||||
CALL 지도 마커/음영 조회(…) // TBD — 대시보드 API에 없음
|
||||
DISPLAY 전국 지도 (영역 A)
|
||||
|
||||
ON 영역 C [전체보기] 버튼 CLICK DO
|
||||
NAVIGATE /nti-hstry
|
||||
END ON
|
||||
|
||||
ON 영역 C [처리하기] 버튼 CLICK DO
|
||||
CALL readNoti(notiId) // entities/noti
|
||||
NAVIGATE notiUrl // 비어 있으면 이동하지 않음
|
||||
CALL getMainDashboard(…) // → 영역 C 갱신 (invalidate)
|
||||
END ON
|
||||
|
||||
ON 영역 D [더보기] 버튼 CLICK DO
|
||||
NAVIGATE /cms/bbsnotice/{AS_DASHBOARD_BBS_ID} // as 앱 공지 목록 라우트 미구현. st/cm 관례
|
||||
END ON
|
||||
|
||||
ON 영역 D 행 CLICK DO
|
||||
NAVIGATE /cms/bbsnotice/{AS_DASHBOARD_BBS_ID}/{pstNo}
|
||||
END ON
|
||||
|
||||
ON 영역 B 카드 CLICK DO
|
||||
NAVIGATE 해당 문서 목록 // §5-3
|
||||
END ON
|
||||
|
||||
ON 영역 A 마커 CLICK DO
|
||||
// TBD — 팝업/필터/이동 여부 미확정
|
||||
END ON
|
||||
|
||||
END
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 영역 A — 전국 행정지원 지도
|
||||
|
||||
스크린샷 타이틀: **전국 행정지원 지도**.
|
||||
|
||||
`getMainDashboard` 응답에 지도·좌표·행정구역 음영 데이터는 **없다**. 마커·음영 소스 API는 **TBD**.
|
||||
|
||||
### 4-1. 표시 요소
|
||||
|
||||
| 표시명 | 입력 유형 | 필수 | 기본값 | API 파라미터 매핑 | 비고 |
|
||||
| ----------- | --------- | ---- | ------ | ----------------- | ----------------------------------------------------------------- |
|
||||
| 섹션 타이틀 | Text | — | — | — | 고정 문구 `전국 행정지원 지도` |
|
||||
| 전국 지도 | Map | — | — | TBD | 시도·시군구 경계. 북·동부 음영(청) / 남서부 비음영(백) — 의미 TBD |
|
||||
| 마커 라벨 | Marker | — | — | TBD | 스크린샷 샘플: `서울 강남구`, `대전 유성구`, `부산 해운대구` |
|
||||
|
||||
### 4-2. 상호작용
|
||||
|
||||
| 동작 | 설명 |
|
||||
| ---------- | ----------------------------------------- |
|
||||
| 마커 클릭 | TBD (상세 팝업 / 해당 지자체 필터 / 이동) |
|
||||
| 지도 줌·팬 | TBD (스크린샷에 컨트롤 없음) |
|
||||
|
||||
`entities/adstdstr`는 시도·구군 **콤보**만 제공하며 좌표를 주지 않는다. 지도 라이브러리도 as 앱에 없음 — 선정 TBD.
|
||||
|
||||
---
|
||||
|
||||
## 5. 영역 B — 문서별 진행상황 카드
|
||||
|
||||
`DashboardMainResponseDto.docPrgrsSttsList`를 **`docSeComCd`로 매핑**해 4장 카드를 그린다. 배열 순서에 의존하지 않는다.
|
||||
|
||||
스크린샷 배치(좌→우, 상→하):
|
||||
|
||||
| 화면 카드 타이틀 | `docSeComCd` | API `docSeNm` |
|
||||
| ----------------- | ------------ | -------------- |
|
||||
| 재원협의 진행상황 | `FNRS` | 재원협의 |
|
||||
| 설치인가 진행상황 | `INSTL` | 설치인가 |
|
||||
| 설계자문 진행상황 | `CNFM` | 설계자문 |
|
||||
| 기본계획 진행상황 | `SEWER` | 하수도기본계획 |
|
||||
|
||||
서버 SQL `ORDER BY`는 `INSTL → FNRS → SEWER → CNFM` 이며, `GROUP BY ROLLUP`으로 **`docSeComCd = TOTAL`** 합계 행이 추가된다. 카드에는 TOTAL 행을 **표시하지 않는다**.
|
||||
|
||||
카드 타이틀은 스크린샷 문구(`… 진행상황`)를 쓴다. `SEWER`의 API명 `하수도기본계획`은 화면에서 `기본계획`으로 축약한다.
|
||||
|
||||
### 5-1. 카드 내부 필드
|
||||
|
||||
각 카드 공통 구조. `totCnt`는 화면에 없음.
|
||||
|
||||
| 표시명 | Field | 비고 |
|
||||
| ------ | ---------- | ------------------ |
|
||||
| 신청 | `reqCnt` | 파란 아이콘 + 건수 |
|
||||
| 진행 | `prgrsCnt` | 초록 아이콘 + 건수 |
|
||||
| 완료 | `cmptnCnt` | 주황 아이콘 + 건수 |
|
||||
|
||||
상태 그룹(서버): 임시저장(`SV`/`CV`) 제외. 문서별 `prgrs_stts_com_cd` → `REQ`/`PRG`/`CMP`.
|
||||
|
||||
### 5-2. 검색 파라미터 (화면 미표시)
|
||||
|
||||
영역 B에 연도·필터 UI는 없다. 서버 기본값을 따른다.
|
||||
|
||||
| 표시명 | 입력 유형 | 필수 | 기본값 | API 파라미터 매핑 | 비고 |
|
||||
| ------ | --------- | ---- | --------- | ----------------- | --------------------------------------------------------------------- |
|
||||
| (없음) | — | — | 당해 연도 | `searchYear` | 미전달 시 서버 `LocalDate.now().getYear()`. 연도 셀렉터 추가 여부 TBD |
|
||||
|
||||
`docSeComCd` 쿼리는 **알림 목록 필터**에만 쓰이며, 진행상황 SQL에는 전달되지 않는다. 카드 4종은 항상 전원 집계한다.
|
||||
|
||||
### 5-3. 상호작용
|
||||
|
||||
카드 클릭 시 **해당 문서 목록 페이지**로 이동한다. `docSeComCd` → 라우트 고정 매핑.
|
||||
|
||||
| 동작 | `docSeComCd` | 이동 경로 |
|
||||
| --------- | ------------ | ----------------- |
|
||||
| 카드 클릭 | `FNRS` | `/fnrs-cnsltn` |
|
||||
| 카드 클릭 | `INSTL` | `/instl-sncn` |
|
||||
| 카드 클릭 | `CNFM` | `/design-cnstn` |
|
||||
| 카드 클릭 | `SEWER` | `/sewer-bsc-plan` |
|
||||
|
||||
---
|
||||
|
||||
## 6. 영역 C — 알림이력
|
||||
|
||||
서버가 cms-service 알림을 대시보드 응답에 합친다. 목록은 **page=0, size=5** (최신 5건). 페이지네이션 없음.
|
||||
|
||||
### 6-1. 헤더
|
||||
|
||||
| 표시명 | Field / 소스 | 비고 |
|
||||
| ------------- | ------------ | --------------------------------------------------------------------------------------- |
|
||||
| 섹션 타이틀 | — | 고정 문구 `알림이력` |
|
||||
| 업데이트 시각 | (client) | 스크린샷 `업데이트 10:32`. API 필드 없음. `getMainDashboard` 마지막 fetch 시각(`HH:mm`) |
|
||||
| 전체보기 | Button | `/nti-hstry`로 이동 |
|
||||
|
||||
### 6-2. 통계 칩
|
||||
|
||||
`NotiAsStatResponseDto`.
|
||||
|
||||
| 표시명 | Field | 비고 |
|
||||
| ------------ | -------------- | -------------------------------------- |
|
||||
| 오늘 N건 | `todayCount` | 당일 00:00 이후 수신 |
|
||||
| 지연 N건 | `delayCount` | `notReadYn=N` 이고 수신 후 3일 이상 |
|
||||
| 완료대기 N건 | `pendingCount` | `notReadYn=Y` 이고 `notiPrcsCmptnYn=N` |
|
||||
|
||||
### 6-3. 목록 행
|
||||
|
||||
| 표시명 | Field | 비고 |
|
||||
| ------ | --------- | --------------------------------------------- |
|
||||
| 일자 | `regDt` | 표시 `YYYY-MM-DD`. 응답 `yyyy-MM-dd HH:mm:ss` |
|
||||
| 제목 | `notiTtl` | 알림 제목 |
|
||||
| 처리 | (action) | 스크린샷 라벨 `처리하기`. 클릭 §6-4 |
|
||||
|
||||
응답에 있으나 이 목록에 **표시하지 않음**:
|
||||
|
||||
| Field | 비고 |
|
||||
| ----------------- | ----------------------------------------- |
|
||||
| `notiId` | 행 키 · `readNoti` 파라미터 |
|
||||
| `recvUnqId` | 수신 회원 UUID (서버 로그인 사용자 고정) |
|
||||
| `senderUnqId` | 발신 회원 UUID |
|
||||
| `notiType` | `ADSS` |
|
||||
| `notiCn` | 본문 |
|
||||
| `notiUrl` | 처리 후 이동 URL. 컬럼 미표시 |
|
||||
| `notiLnkgUnqNo` | 알림연결고유번호 |
|
||||
| `docSeComCd` | 문서구분 코드 |
|
||||
| `docSeComNm` | 문서구분명 (알림이력 화면에서는 연계업무) |
|
||||
| `notReadYn` | 뱃지 판정 TBD에 사용 가능 |
|
||||
| `notiIdntyYn` | 확인 여부 |
|
||||
| `notiIdntyDt` | 확인 일시 |
|
||||
| `notiPrcsCmptnYn` | 처리 완료 여부 |
|
||||
| `notiPrcsCmptnDt` | 처리 완료 일시 |
|
||||
|
||||
### 6-4. 행 상호작용
|
||||
|
||||
| 동작 | 설명 |
|
||||
| --------------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| [전체보기] 클릭 | `/nti-hstry` (알림이력 목록)로 이동 |
|
||||
| [처리하기] 클릭 | `readNoti(notiId)` 후 `notiUrl`로 이동. URL이 비면 이동하지 않음(읽음 처리는 수행). `dashboardBaseKey` invalidate |
|
||||
|
||||
`DashboardController`에 읽음 API는 없다. **`entities/noti`의 `readNoti`** 를 쓴다. 알림이력 화면과 동일 (`PUT /cms-service/api/v1/noti/{notiId}/read`).
|
||||
|
||||
### 6-5. 검색 파라미터 (화면 미표시)
|
||||
|
||||
서버 `toNotiSearchDto()` 기본: `notiType = ADSS`. 화면 필터 없음.
|
||||
|
||||
| DashboardMainSearchDto | 화면 | 비고 |
|
||||
| ---------------------- | ---- | --------------------------------- |
|
||||
| `notiType` | 없음 | 서버 기본 `ADSS` |
|
||||
| `notReadYn` | 없음 | 통계 칩 클릭 필터 시 후보 (TBD) |
|
||||
| `startDt` / `endDt` | 없음 | 대시보드 기본 미전달 |
|
||||
| `docSeComCd` | 없음 | 알림만 필터. 진행상황 카드와 무관 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 영역 D — 공지사항
|
||||
|
||||
`getMainDashboard`에 공지 필드는 없다. **board-service** `getUserPostList`로 별도 조회한다.
|
||||
|
||||
- Base: `GET /board-service/api/v1/posts/user/{AS_DASHBOARD_BBS_ID}`
|
||||
- `AS_DASHBOARD_BBS_ID` = `NEXT_PUBLIC_AS_DASHBOARD_BBS_ID` (로컬 예: `7`)
|
||||
- 클라이언트: `@/entities/board` — `postApi.getUserPostList` / `useUserPostList`
|
||||
|
||||
페이지네이션 컨트롤은 없다. 요약 목록만 표시한다 (`page=0`, `size=3`).
|
||||
|
||||
### 7-1. 헤더·버튼
|
||||
|
||||
| 버튼명 | 동작 |
|
||||
| ------ | ------------------------------------------------------------------------------------------- |
|
||||
| 더보기 | `/cms/bbsnotice/{AS_DASHBOARD_BBS_ID}` 로 이동. as 앱에 공지 목록 라우트는 없음(st/cm 관례) |
|
||||
|
||||
### 7-2. 그리드 컬럼
|
||||
|
||||
스크린샷 헤더 순서. `UserPost`.
|
||||
|
||||
| 표시명 | Field | 비고 |
|
||||
| ------ | --------- | ---------------------------------------------------- |
|
||||
| 번호 | `rowNo` | `upndFixYn` = `Y` 이면 `[공지]` Badge, 그 외 `rowNo` |
|
||||
| 제목 | `pstTtl` | truncate |
|
||||
| 작성자 | `wrtrNm` | |
|
||||
| 작성일 | `regDt` | 표시 `YYYY-MM-DD` (응답 datetime) |
|
||||
| 조회수 | `inqNocs` | 숫자 |
|
||||
|
||||
조회 파라미터 (`UserPostSearchParams`):
|
||||
|
||||
| 필드 | 값 | 비고 |
|
||||
| ------------- | ----------- | ------------------------------------------ |
|
||||
| `page` | `0` | Spring 0-based |
|
||||
| `size` | `3` | 대시보드 요약. 스크린샷 3행 |
|
||||
| `keywordType` | `bbsTypeCd` | st 대시보드 공지 패널과 동일 |
|
||||
| `keyword` | `BBSNOTICE` | 게시판 유형. path의 bbsId와 함께 공지 한정 |
|
||||
|
||||
응답에 있으나 그리드에 **표시하지 않음**: `bbsId`, `pstNo`(행 키·상세 이동), `pstCn`, `upndFixYn`(번호 열 판정만), `rgtrNm`, `atflCd` 등.
|
||||
|
||||
### 7-3. 행 상호작용
|
||||
|
||||
| 동작 | 설명 |
|
||||
| ------- | ------------------------------------------------------------------------------ |
|
||||
| 행 클릭 | `/cms/bbsnotice/{AS_DASHBOARD_BBS_ID}/{pstNo}` (as 앱 공지 상세 라우트 미구현) |
|
||||
|
||||
---
|
||||
|
||||
## 8. API/DTO 명세
|
||||
|
||||
### 8-1. 공통
|
||||
|
||||
| 항목 | 값 |
|
||||
| --------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| Base prefix | `/as-service/api/v1/dashboard` (`ENDPOINT.AS_SERVICE.DASHBOARD`) |
|
||||
| 인증 | `Authorization` 헤더. 프론트는 `client` 인터셉터. 로그인 기관 권한은 서버가 사용자 캐시로 적용 |
|
||||
| 클라이언트 모듈 | `@/entities/dashboard` — `dashboardService` / `useGetMainDashboard` |
|
||||
| 알림 읽음 | `@/entities/noti` — `notiService.readNoti` / `useReadNoti` |
|
||||
| 공지사항 | `@/entities/board` — `postApi.getUserPostList` / `useUserPostList` |
|
||||
|
||||
영역 A(지도)는 본 컨트롤러·board-service 범위 밖 → **TBD**.
|
||||
|
||||
### 8-2. 대시보드 메인 조회 — `getMainDashboard`
|
||||
|
||||
| 기능 | Method | URL | Request DTO | Response DTO | API |
|
||||
| -------------------------------------------- | ------ | ------------- | ------------------------------- | -------------------------- | ----------------------------------------------------------- |
|
||||
| 대시보드 메인 통합진행상태 및 알림 정보 조회 | GET | `{BASE}/main` | Query: `DashboardMainSearchDto` | `DashboardMainResponseDto` | `dashboardService.getMainDashboard` / `useGetMainDashboard` |
|
||||
|
||||
**Request (`DashboardMainSearchDto`)**
|
||||
|
||||
| 필드 | 필수 | 설명 |
|
||||
| ------------ | ---- | ---------------------------------------------------------------------- |
|
||||
| `searchYear` | N | 검색 연도. 미전달 시 서버 당해 연도. 영역 B 집계 기간 |
|
||||
| `notiType` | N | 알림 종류. 미전달 시 서버 `ADSS` |
|
||||
| `notReadYn` | N | 알림 확인 여부 `Y`/`N`. 본 화면 미사용 |
|
||||
| `startDt` | N | 알림 시작일 `YYYY-MM-DD`. 본 화면 미사용 |
|
||||
| `endDt` | N | 알림 종료일 `YYYY-MM-DD`. 본 화면 미사용 |
|
||||
| `docSeComCd` | N | 알림 문서구분 (`INSTL`/`FNRS`/`SEWER`/`CNFM` 등). 진행상황 집계와 무관 |
|
||||
|
||||
`Authorization`은 service 시그니처에 넣지 않는다.
|
||||
|
||||
**Response (`DashboardMainResponseDto`)**
|
||||
|
||||
| 필드 | 타입 | 설명 |
|
||||
| ------------------ | --------------------------- | --------------------------- |
|
||||
| `docPrgrsSttsList` | `DocPrgrsSttsResponseDto[]` | 문서별 진행상태 + TOTAL 행 |
|
||||
| `notiList` | `NotiAsUserResponseDto[]` | 최신 최대 5건 |
|
||||
| `notiStats` | `NotiAsStatResponseDto` | 오늘 / 지연 / 완료대기 건수 |
|
||||
|
||||
**`DocPrgrsSttsResponseDto`**
|
||||
|
||||
| 필드 | 타입 | 설명 |
|
||||
| ------------ | ------ | --------------------------------------------- |
|
||||
| `docSeNm` | string | 문서 구분 명칭 |
|
||||
| `docSeComCd` | string | `INSTL` / `FNRS` / `SEWER` / `CNFM` / `TOTAL` |
|
||||
| `reqCnt` | number | 신청 건수 |
|
||||
| `prgrsCnt` | number | 진행 건수 |
|
||||
| `cmptnCnt` | number | 완료 건수 |
|
||||
| `totCnt` | number | 총 건수 (화면 미표시) |
|
||||
|
||||
**`NotiAsStatResponseDto`**
|
||||
|
||||
| 필드 | 타입 | 설명 |
|
||||
| -------------- | ------ | --------- |
|
||||
| `todayCount` | number | 오늘 알림 |
|
||||
| `delayCount` | number | 지연 알림 |
|
||||
| `pendingCount` | number | 완료대기 |
|
||||
|
||||
**`NotiAsUserResponseDto`** — 필드 상세는 `docs/spec/nti-hstry` §6-2와 동일 (`notiId`, `notiTtl`, `regDt`, `notiUrl`, `notReadYn`, `notiPrcsCmptnYn` 등).
|
||||
|
||||
### 8-3. 알림 읽음 처리 — `readNoti`
|
||||
|
||||
대시보드 컨트롤러가 아니라 cms-service. 영역 C [처리하기]에서 호출.
|
||||
|
||||
| 기능 | Method | URL | Request DTO | Response DTO | API |
|
||||
| -------------- | ------ | ---------------------------------------- | ----------------------- | ---------------- | -------------------------------------- |
|
||||
| 알림 읽음 처리 | PUT | `/cms-service/api/v1/noti/{notiId}/read` | Path: `notiId` (`Long`) | `Long` (알림 ID) | `notiService.readNoti` / `useReadNoti` |
|
||||
|
||||
Body 없음. 성공 시 `dashboardBaseKey`(및 필요 시 `notiBaseKey`) invalidate.
|
||||
|
||||
### 8-4. 전국 행정지원 지도 — TBD
|
||||
|
||||
| 기능 | Method | URL | Request DTO | Response DTO | API |
|
||||
| ------------------- | ------ | --- | ----------- | ------------ | --- |
|
||||
| 지도 마커·음영 조회 | TBD | TBD | TBD | TBD | TBD |
|
||||
|
||||
### 8-5. 공지사항 — `getUserPostList`
|
||||
|
||||
board-service. bbsId는 환경변수 `AS_DASHBOARD_BBS_ID`로 path에 고정한다.
|
||||
|
||||
| 기능 | Method | URL | Request DTO | Response DTO | API |
|
||||
| ----------------------- | ------ | ------------------------------------------ | ----------------------------- | ------------------------ | --------------------------------------------- |
|
||||
| 대시보드 공지 요약 목록 | GET | `/board-service/api/v1/posts/user/{bbsId}` | Query: `UserPostSearchParams` | `PageResponse<UserPost>` | `postApi.getUserPostList` / `useUserPostList` |
|
||||
|
||||
**Request (`UserPostSearchParams`)** — 본 화면 고정값
|
||||
|
||||
| 필드 | 필수 | 설명 |
|
||||
| ------------- | ---- | -------------- |
|
||||
| `page` | N | `0` |
|
||||
| `size` | N | `3` |
|
||||
| `keywordType` | N | `bbsTypeCd` |
|
||||
| `keyword` | N | `BBSNOTICE` |
|
||||
| `popupYn` 등 | N | 본 화면 미사용 |
|
||||
|
||||
**Response (`UserPost`) — 화면 매핑 필드**
|
||||
|
||||
| 필드 | 타입 | 설명 |
|
||||
| ----------- | ------ | --------------------------- |
|
||||
| `rowNo` | number | 번호. 고정글이 아니면 표시 |
|
||||
| `pstNo` | number | 게시 번호. 상세 이동 키 |
|
||||
| `bbsId` | number | 게시판 ID |
|
||||
| `pstTtl` | string | 제목 |
|
||||
| `wrtrNm` | string | 작성자 |
|
||||
| `regDt` | string | 작성일 |
|
||||
| `inqNocs` | number | 조회수 |
|
||||
| `upndFixYn` | string | 상단고정 `Y`/`N` → `[공지]` |
|
||||
|
||||
---
|
||||
|
||||
## 9. UI 구현 가이드
|
||||
|
||||
### 9-1. 기술 스택·원칙
|
||||
|
||||
- 라우트: 기존 홈 `app/(main)/(with-base-layout)/page.tsx` → `pages/home` (현재 `MainPage` 플레이스홀더)
|
||||
- UI: `@common/components` — Card, Badge, Button, Table(공지). 지도 라이브러리 TBD
|
||||
- 데이터: React Query `useGetMainDashboard()`. 처리하기는 `useReadNoti()`. 공지는 `useUserPostList()`
|
||||
- 진행상황 카드: `docSeComCd`로 4슬롯 매핑. `TOTAL` 제외
|
||||
- 알림 목록: 테이블이 아닌 행 리스트(뱃지 + 일자 + 제목 + 버튼)
|
||||
- 공지: `@tanstack/react-table` + `useDataTable`, 페이지네이션 없음
|
||||
- 검색 조건 URL 동기화: 본 화면 필터 없음. `searchYear` UI가 생기면 그때 검토
|
||||
|
||||
### 9-2. 모듈·파일 배치
|
||||
|
||||
| 구분 | 경로 |
|
||||
| ------------- | ------------------------------------------------------------ |
|
||||
| 라우트 | `app/(main)/(with-base-layout)/page.tsx` |
|
||||
| 페이지 | `pages/dashboard/ui/dashboard-page.tsx` |
|
||||
| 지도 | `pages/dashboard/ui/national-as-map.tsx` (API TBD, Skeleton) |
|
||||
| 진행상황 카드 | `pages/dashboard/ui/doc-prgrs-stts-cards.tsx` |
|
||||
| 알림이력 | `pages/dashboard/ui/dashboard-noti-list.tsx` |
|
||||
| 공지사항 | `pages/dashboard/ui/dashboard-notice-table.tsx` |
|
||||
| 공지 컬럼 | `pages/dashboard/model/dashboard-notice-table-columns.tsx` |
|
||||
| Entity API | `entities/dashboard/api/dashboard-service.ts` |
|
||||
| Entity Hook | `entities/dashboard/api/queries.ts` → `useGetMainDashboard` |
|
||||
| Entity Model | `entities/dashboard/model/dashboard-interface.ts` |
|
||||
| 알림 읽음 | `entities/noti` → `useReadNoti` |
|
||||
| 공지 Entity | `entities/board` → `useUserPostList` |
|
||||
|
||||
Entity(`getMainDashboard`, `getUserPostList`) 구현됨. 영역 B·C·D 화면 구현. 영역 A는 Skeleton.
|
||||
|
||||
### 9-3. 영역별 UI 매핑
|
||||
|
||||
| 영역 | 컴포넌트 | 데이터 |
|
||||
| ---- | ------------------------ | ---------------------------------------------------------------------------- |
|
||||
| A | `national-as-map` | Skeleton (지도 API TBD) |
|
||||
| B | `doc-prgrs-stts-cards` | `useGetMainDashboard` → `docPrgrsSttsList` (`TOTAL` 제외, 코드 매핑) |
|
||||
| C | `dashboard-noti-list` | 동 훅 → `notiStats`, `notiList`. 처리 → `useReadNoti`. 전체보기 `/nti-hstry` |
|
||||
| D | `dashboard-notice-table` | `useUserPostList` → `content[]`. [더보기]·행 클릭 → `/cms/bbsnotice/...` |
|
||||
|
||||
### 9-4. 다이얼로그·라우팅
|
||||
|
||||
| 항목 | 내용 |
|
||||
| -------------- | -------------------------------------------------------------------------------------- |
|
||||
| 다이얼로그 | 없음 |
|
||||
| 본 화면 라우트 | `/` (홈) |
|
||||
| 알림 처리 이동 | [처리하기] → `readNoti` 후 `notiUrl` (알림이력과 동일, SEWER URL은 상세 세그먼트 제거) |
|
||||
| 알림 전체보기 | `/nti-hstry` |
|
||||
| 공지 더보기 | `/cms/bbsnotice/{AS_DASHBOARD_BBS_ID}` (as 앱 공지 라우트 미구현, st/cm 관례) |
|
||||
| 공지 행 클릭 | `/cms/bbsnotice/{AS_DASHBOARD_BBS_ID}/{pstNo}` |
|
||||
| 진행상황 카드 | §5-3 목록 라우트 (`/fnrs-cnsltn`, `/instl-sncn`, `/design-cnstn`, `/sewer-bsc-plan`) |
|
||||
|
||||
### 9-5. 데이터 흐름
|
||||
|
||||
```
|
||||
BEGIN
|
||||
|
||||
// 최초 진입 (홈)
|
||||
CALL getMainDashboard({})
|
||||
DISPLAY 영역 B // docPrgrsSttsList — FNRS/INSTL/CNFM/SEWER 슬롯
|
||||
DISPLAY 영역 C // notiStats + notiList(≤5)
|
||||
|
||||
CALL getUserPostList({ page: 0, size: 3, keywordType: "bbsTypeCd", keyword: "BBSNOTICE" })
|
||||
DISPLAY 영역 D
|
||||
|
||||
CALL 지도 데이터 // TBD → 영역 A
|
||||
|
||||
ON 영역 C [전체보기] CLICK DO
|
||||
NAVIGATE /nti-hstry
|
||||
END ON
|
||||
|
||||
ON 영역 C [처리하기] CLICK DO
|
||||
CALL readNoti(notiId)
|
||||
IF notiUrl THEN
|
||||
NAVIGATE notiUrl
|
||||
END IF
|
||||
CALL getMainDashboard // invalidate dashboardBaseKey
|
||||
END ON
|
||||
|
||||
ON 영역 B 카드 CLICK DO
|
||||
NAVIGATE 문서 목록 // §5-3
|
||||
END ON
|
||||
|
||||
ON 영역 D [더보기] CLICK DO
|
||||
NAVIGATE /cms/bbsnotice/{AS_DASHBOARD_BBS_ID}
|
||||
END ON
|
||||
|
||||
ON 영역 D 행 CLICK DO
|
||||
NAVIGATE /cms/bbsnotice/{AS_DASHBOARD_BBS_ID}/{pstNo}
|
||||
END ON
|
||||
|
||||
END
|
||||
```
|
||||
@@ -0,0 +1,285 @@
|
||||
# 화면설계서: 내 행정지원
|
||||
|
||||
## 1. 기본 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
| ---------- | -------------------------------------------- |
|
||||
| 버전 | 1.0 |
|
||||
| 프로세스명 | UI설계 |
|
||||
| 화면명 | 내 행정지원 |
|
||||
| 화면 ID | AS_SC0204011 |
|
||||
| 화면 유형 | [v] 조회 [ ] 입력 [ ] 수정 [ ] 삭제 [ ] 출력 |
|
||||
| 메뉴 경로 | 메인 > 행정지원서비스 > 내 행정지원 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 화면 목적
|
||||
|
||||
로그인한 사용자가 **본인이 신청한 행정지원 문서**를 기간·구분·진행상태로 조회한다. 목록에서 행을 선택하면 해당 문서 상세 화면으로 이동한다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 화면 구성
|
||||
|
||||
### 3-1. 전체 레이아웃
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 브레드크럼: 메인 > 행정지원서비스 > 내 행정지원 │
|
||||
│ 페이지 타이틀: 내 행정지원 │
|
||||
├─────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ [영역 A] 검색 필터 │
|
||||
│ 기간 [시작일] ~ [종료일] 구분 ▼ 진행상태 ▼ [검색] │
|
||||
├─────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ [영역 B] 내 신청 목록 │
|
||||
│ 타이틀: 내 신청 목록 N개 │
|
||||
│ ┌────┬──────┬────────┬──────────────┬────────────┬────────┬──────────────┐ │
|
||||
│ │ No │ 구분 │ 신청일 │ 진행상태 │ 완료(예정)일│ 담당자 │ 담당자연락처 │ │
|
||||
│ ├────┼──────┼────────┼──────────────┼────────────┼────────┼──────────────┤ │
|
||||
│ │ … │ … │ … │ prgrsSttsComNm│ … │ … │ … │ │
|
||||
│ └────┴──────┴────────┴──────────────┴────────────┴────────┴──────────────┘ │
|
||||
│ [페이지네이션] │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3-2. 화면 데이터 흐름
|
||||
|
||||
```
|
||||
BEGIN
|
||||
|
||||
// 최초 진입
|
||||
// 기간 기본값: 오늘 기준 최근 1개월 (startDate = today-1M, endDate = today)
|
||||
CALL findMyElaperDocList(ElaprMyDocSearchDto + pageable)
|
||||
DISPLAY 내 신청 목록 그리드 (영역 B)
|
||||
|
||||
ON [검색] 버튼 CLICK DO
|
||||
CALL findMyElaperDocList(영역 A 조건 + page=0)
|
||||
DISPLAY 내 신청 목록 그리드 (영역 B)
|
||||
END ON
|
||||
|
||||
ON 페이지네이션 CHANGE DO
|
||||
CALL findMyElaperDocList(영역 A 조건 + page/size)
|
||||
DISPLAY 내 신청 목록 그리드 (영역 B)
|
||||
END ON
|
||||
|
||||
ON 영역 B 행 CLICK DO
|
||||
// docSeComCd·prgrsSttsComCd·rgtr → view/edit
|
||||
NAVIGATE 문서 상세 또는 수정 화면
|
||||
END ON
|
||||
|
||||
END
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 영역 A — 검색 필터
|
||||
|
||||
구성: **기간 · 구분 · 진행상태** (+ 검색).
|
||||
|
||||
> UI설계 상세설명의 `docSecs` / `docStatusCd`는 레거시·설계 문서 명칭이다.
|
||||
> **API SoT**는 `ElaprMyDocSearchDto`의 `docSeComCd` / `prgrsSttsComCd`를 사용한다.
|
||||
|
||||
### 4-1. 필드 정의
|
||||
|
||||
| 표시명 | 입력 유형 | 필수 | 기본값 | API 파라미터 매핑 | 비고 |
|
||||
| ---------- | ---------------- | ---- | --------------------------- | ----------------- | --------------------------------------------------------------------- |
|
||||
| 기간(시작) | DatePicker | N | 오늘 − 1개월 (`YYYY-MM-DD`) | `startDate` | 신청일(`reqDt`) 기준 검색으로 가정 |
|
||||
| 기간(종료) | DatePicker | N | 오늘 (`YYYY-MM-DD`) | `endDate` | |
|
||||
| 구분 | Select(공통코드) | N | 전체(미선택) | `docSeComCd` | 상위코드 `ASDOCSE`. UI설계 `docSecs` → API `docSeComCd` |
|
||||
| 진행상태 | Select(공통코드) | N | 전체(미선택) | `prgrsSttsComCd` | 상위코드 = `{docSeComCd}STTS` (예: `INSTL` → `INSTLSTTS`). UI설계 `docStatusCd` → API 필드명 |
|
||||
|
||||
### 4-2. 버튼
|
||||
|
||||
| 버튼명 | 동작 |
|
||||
| ------ | ----------------------------------------------------------------- |
|
||||
| 검색 | 영역 A 조건으로 `findMyElaperDocList` 호출 → 영역 B 갱신 (page=0) |
|
||||
|
||||
### 4-3. 콤보 의존
|
||||
|
||||
| 트리거 | 동작 |
|
||||
| ----------- | ------------------------------------------------------------------- |
|
||||
| 구분 변경 | 진행상태 옵션을 `upCd = docSeComCd + "STTS"`로 재조회. 진행상태 선택값 RESET |
|
||||
| 구분 미선택 | 진행상태 비활성(옵션 비움). `upCd` 조합 불가이므로 조회하지 않음 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 영역 B — 내 신청 목록
|
||||
|
||||
### 5-1. 그리드 컬럼
|
||||
|
||||
| 표시명 | Field | 비고 |
|
||||
| ------------ | ---------------- | ------------------------------------------------- |
|
||||
| No | (row index) | 페이지 오프셋 반영 |
|
||||
| 구분 | `docSeComNm` | 코드 `docSeComCd` (`ASDOCSE`) |
|
||||
| 신청일 | `reqDt` | 표시 `YYYY-MM-DD` (응답은 `yyyy-MM-dd HH:mm:ss`) |
|
||||
| 진행상태 | `prgrsSttsComNm` | 텍스트 렌더링 (단계형 프로그레스 미사용) |
|
||||
| 완료(예정)일 | `cmptnExpctDt` | 표시 `YYYY-MM-DD` |
|
||||
| 담당자 | `picNm` | |
|
||||
| 담당자연락처 | `picTelno` | |
|
||||
|
||||
응답에 있으나 그리드에 **표시하지 않음**:
|
||||
|
||||
| Field | 비고 |
|
||||
| ---------------- | ----------------------------------------------------------------- |
|
||||
| `docNo` | 문서번호 — 행 클릭 라우팅 키 |
|
||||
| `docTtl` | 문서명/사업명 — 미표시 |
|
||||
| `chgCycl` | 변경차수 — 그리드 미표시. SEWER 이동 시 query 파라미터로 사용 |
|
||||
| `prgrsSttsComCd` | 진행상태 코드 — 컬럼 표시는 `prgrsSttsComNm` |
|
||||
| `rgtr` | 등록자 UUID — edit 판정용 (`rgtr === userUnqId`) |
|
||||
|
||||
### 5-2. 목록 메타·페이지네이션
|
||||
|
||||
| 항목 | 매핑 |
|
||||
| ------------- | ------------------------------------------- |
|
||||
| 건수 `N개` | `PageResponse.totalElements` |
|
||||
| page / size | `ElaprMyDocSearchDto`의 `PageableParams` |
|
||||
| 페이지 컨트롤 | Spring `Page` 표준 (`number`, `totalPages`) |
|
||||
|
||||
### 5-3. 행 상호작용
|
||||
|
||||
| 동작 | 설명 |
|
||||
| ------- | -------------------------------------------------------------------------------------------- |
|
||||
| 행 클릭 | `docSeComCd`·`prgrsSttsComCd`·`rgtr`로 view/edit 분기 후 이동 (`resolveMyPbadmsSprtDetailPath`) |
|
||||
|
||||
**edit 조건** (기존 도메인 목록과 동일):
|
||||
|
||||
| `docSeComCd` | edit 조건 |
|
||||
| ------------------------ | ---------------------------------------------------------------------- |
|
||||
| `INSTL` / `FNRS` / `SEWER` | `(prgrsSttsComCd === "SV" \|\| "SL") && rgtr === loggedInUserUnqId` |
|
||||
| `CNFM` | `prgrsSttsComCd === "CV" && rgtr === loggedInUserUnqId` |
|
||||
|
||||
| `docSeComCd` | edit 경로 | view 경로 |
|
||||
| ------------ | -------------------------------------------- | --------------------------------------- |
|
||||
| `FNRS` | `/fnrs-cnsltn/{docNo}/edit` | `/fnrs-cnsltn/{docNo}` |
|
||||
| `INSTL` | `/instl-sncn/{docNo}/edit` | `/instl-sncn/{docNo}` |
|
||||
| `CNFM` | `/design-cnstn/{docNo}/edit` | `/design-cnstn/{docNo}` |
|
||||
| `SEWER` | `/sewer-bsc-plan/{docNo}/edit?chgCycl={n}` | `/sewer-bsc-plan/{docNo}?chgCycl={n}` |
|
||||
| 그 외 | 이동하지 않음 | |
|
||||
|
||||
- SEWER `chgCycl`: `row.chgCycl ?? 1`
|
||||
- 조건 불충족 시 항상 view
|
||||
|
||||
---
|
||||
|
||||
## 6. API/DTO 명세
|
||||
|
||||
### 6-1. 공통
|
||||
|
||||
| 항목 | 값 |
|
||||
| --------------- | ------------------------------------------------------------------------------------------ |
|
||||
| Base prefix | `/as-elapr-service/api/v1/elapr-prgrs-stts` (`ENDPOINT.AS_ELAPR_SERVICE.ELAPR_PRGRS_STTS`) |
|
||||
| 인증 | 로그인 사용자 UUID — 서버 `SecurityUtils.getLoggedInUserUnqIdUUID()` (클라이언트 미전달) |
|
||||
| 클라이언트 모듈 | `@/entities/elapr` — `elaprPrgrsSttsService` / `useElaprPrgrsSttsMyDocPage` |
|
||||
|
||||
### 6-2. 내 행정지원 목록 — `findMyElaperDocList`
|
||||
|
||||
| 기능 | Method | URL | Request DTO | Response DTO | API |
|
||||
| ----------------- | ------ | --------------- | --------------------------------------- | ------------------------------------ | -------------------------------------------------------------------------- |
|
||||
| 내 신청 목록 조회 | GET | `{BASE}/my/doc` | Query: `ElaprMyDocSearchDto` + Pageable | `PageResponse<MyAdssDocResponseDto>` | `elaprPrgrsSttsService.findMyElaperDocList` / `useElaprPrgrsSttsMyDocPage` |
|
||||
|
||||
**Request (`ElaprMyDocSearchDto` + Pageable)**
|
||||
|
||||
| 필드 | 필수 | 설명 |
|
||||
| ------------------------ | ---- | ------------------------------------------------------------ |
|
||||
| `startDate` | N | 검색 시작일 `YYYY-MM-DD` |
|
||||
| `endDate` | N | 검색 종료일 `YYYY-MM-DD` |
|
||||
| `docSeComCd` | N | 문서구분 (`INSTL` / `FNRS` / `DESIGN` / `SEWER` / `PWRK` 등) |
|
||||
| `prgrsSttsComCd` | N | 문서진행상태공통코드 |
|
||||
| `page` / `size` / `sort` | N | Spring Pageable |
|
||||
|
||||
**Response (`MyAdssDocResponseDto`)**
|
||||
|
||||
| 필드 | 타입 | 설명 |
|
||||
| ---------------- | ------- | ------------------------------------------- |
|
||||
| `docNo` | string | 문서번호 |
|
||||
| `docTtl` | string? | 문서명/사업명 |
|
||||
| `docSeComCd` | string? | 문서구분 코드 |
|
||||
| `docSeComNm` | string? | 문서구분 코드명 (`ASDOCSE`) |
|
||||
| `reqDt` | string? | 신청일시 `yyyy-MM-dd HH:mm:ss` |
|
||||
| `prgrsSttsComCd` | string? | 문서진행상태 코드 |
|
||||
| `prgrsSttsComNm` | string? | 문서진행상태 코드명 |
|
||||
| `cmptnExpctDt` | string? | 완료(예정)일 `yyyy-MM-dd` |
|
||||
| `picNm` | string? | 담당자 성명 |
|
||||
| `picTelno` | string? | 담당자 연락처 |
|
||||
| `chgCycl` | number? | 변경차수 |
|
||||
| `rgtr` | string? | 등록자 UUID |
|
||||
|
||||
### 6-3. 공통코드 (콤보)
|
||||
|
||||
| 용도 | 상위코드 | API | 비고 |
|
||||
| -------- | ------------ | --------------------------- | ----------------------------- |
|
||||
| 구분 | `ASDOCSE` | `useCodeList("ASDOCSE")` 등 | 기존 관리 화면과 동일 |
|
||||
| 진행상태 | `{docSeComCd}STTS` | `useCodeList(docSeComCd + "STTS")` | 예: `INSTLSTTS`, `FNRSSTTS`, `SEWERSTTS`. 구분 미선택 시 미호출 |
|
||||
|
||||
---
|
||||
|
||||
## 7. UI 구현 가이드
|
||||
|
||||
### 7-1. 기술 스택·원칙
|
||||
|
||||
- UI: `@common/components` — DatePicker, Select/`CodeSelect`, Button, DataTable, Pagination
|
||||
- 목록: `@tanstack/react-table` + `useDataTable` (기존 `instl-list` / `fnrs-list` 패턴)
|
||||
- 데이터: React Query `useElaprPrgrsSttsMyDocPage(params)`
|
||||
- 검색 조건·페이지: URL `searchParams` 동기화 권장 (`useSearchParamsState` 스킬)
|
||||
- 진행상태 컬럼: `prgrsSttsComNm` 텍스트 렌더링 (단계형 프로그레스 미사용)
|
||||
- 행 클릭: `docSeComCd` + `prgrsSttsComCd` + `rgtr`로 view/edit 분기 (`SEWER`는 `chgCycl` query 포함)
|
||||
|
||||
### 7-2. 앱·파일 배치
|
||||
|
||||
| 구분 | 경로 |
|
||||
| ------------ | -------------------------------------------------------------- |
|
||||
| 라우트 | `app/(main)/(with-base-layout)/my-pbadms-sprt/page.tsx` |
|
||||
| 페이지 | `pages/my-pbadms-sprt/ui/my-pbadms-sprt-list-page.tsx` |
|
||||
| 목록 그리드 | `pages/my-pbadms-sprt/ui/my-pbadms-sprt-list.tsx` |
|
||||
| 경로 해석 | `pages/my-pbadms-sprt/lib/resolve-detail-path.ts` |
|
||||
| 테이블 컬럼 | `pages/my-pbadms-sprt/model/my-pbadms-sprt-table-columns.tsx` |
|
||||
| Entity API | `entities/elapr/api/elapr-prgrs-stts-service.ts` |
|
||||
| Entity Hook | `entities/elapr/api/queries.ts` → `useElaprPrgrsSttsMyDocPage` |
|
||||
| Entity Model | `entities/elapr/model/elapr-prgrs-stts-interface.ts` |
|
||||
|
||||
### 7-3. 영역별 UI 매핑
|
||||
|
||||
| 영역 | 컴포넌트 | 데이터 |
|
||||
| ---- | -------------------------- | ------------------------------------------ |
|
||||
| A | `my-pbadms-sprt-list-page` | 로컬 state → `ElaprMyDocSearchDto` |
|
||||
| B | DataTable + columns | `useElaprPrgrsSttsMyDocPage` → `content[]` |
|
||||
|
||||
### 7-4. 다이얼로그·라우팅
|
||||
|
||||
| 항목 | 내용 |
|
||||
| ----------- | -------------------------------------------------------------------- |
|
||||
| 다이얼로그 | 없음 (목록 전용) |
|
||||
| 목록 라우트 | `/my-pbadms-sprt` |
|
||||
| 상세 이동 | §5-3 표와 동일 (view/edit + `rgtr` 소유자 검사, SEWER `chgCycl`) |
|
||||
|
||||
### 7-5. 데이터 흐름
|
||||
|
||||
```
|
||||
BEGIN
|
||||
|
||||
// 최초 진입
|
||||
SET 기간 = 최근 1개월
|
||||
CALL findMyElaperDocList
|
||||
DISPLAY 영역 B
|
||||
|
||||
ON [검색] CLICK DO
|
||||
CALL findMyElaperDocList // → 영역 B 갱신
|
||||
END ON
|
||||
|
||||
ON 페이지 CHANGE DO
|
||||
CALL findMyElaperDocList
|
||||
END ON
|
||||
|
||||
ON 영역 B 행 CLICK DO
|
||||
IF NOT docNo OR unsupported docSeComCd THEN
|
||||
// no-op
|
||||
ELSE IF canEdit(prgrsSttsComCd, rgtr === userUnqId) THEN
|
||||
NAVIGATE edit 경로 // SEWER면 ?chgCycl=
|
||||
ELSE
|
||||
NAVIGATE view 경로
|
||||
END IF
|
||||
END ON
|
||||
|
||||
END
|
||||
```
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
# 화면설계서: 알림이력
|
||||
|
||||
## 1. 기본 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
| ----------- | -------------------------------------------- |
|
||||
| 버전 | 1.4 |
|
||||
| 프로세스명 | UI설계 |
|
||||
| 화면명 | 알림이력 |
|
||||
| 화면 ID | AS_SC0205011 |
|
||||
| 요구사항 ID | NSUR-001-001 |
|
||||
| 화면 유형 | [v] 조회 [ ] 입력 [ ] 수정 [ ] 삭제 [ ] 출력 |
|
||||
| 메뉴 경로 | 메인 > 행정지원서비스 > 알림이력 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 화면 목적
|
||||
|
||||
로그인한 사용자가 **본인에게 발송된 행정지원(ADSS) 알림**을 기간·구분으로 조회한다. 목록의 처리 버튼으로 해당 알림을 읽음 처리한 뒤, 연계된 업무 화면으로 이동한다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 화면 구성
|
||||
|
||||
### 3-1. 전체 레이아웃
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 브레드크럼: 메인 > 행정지원서비스 > 알림이력 │
|
||||
│ 페이지 타이틀: 알림이력 │
|
||||
├─────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ [영역 A] 검색 필터 │
|
||||
│ 기간 [시작일] ~ [종료일] 구분 ▼ [검색] │
|
||||
├─────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ [영역 B] 알림 이력 목록 │
|
||||
│ 타이틀: 알림 이력 목록 N개 ▼ │
|
||||
│ ┌────┬──────────────┬────────────────┬──────────┬────────┬────────┐ │
|
||||
│ │ No │ 알림일시 │ 알림내용 │ 연계업무 │ 상태 │ 처리 │ │
|
||||
│ ├────┼──────────────┼────────────────┼──────────┼────────┼────────┤ │
|
||||
│ │ … │ regDt │ notiTtl │ docSeComNm│ Badge │ 버튼 │ │
|
||||
│ └────┴──────────────┴────────────────┴──────────┴────────┴────────┘ │
|
||||
│ [페이지네이션] │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3-2. 화면 데이터 흐름
|
||||
|
||||
```
|
||||
BEGIN
|
||||
|
||||
// 최초 진입
|
||||
// 기간 기본값: 오늘 기준 최근 1개월 (시작일 = today-1M, 종료일 = today)
|
||||
CALL findMyAsNotiList(NotiSearchDto + pageable)
|
||||
DISPLAY 알림 이력 목록 그리드 (영역 B)
|
||||
|
||||
ON [검색] 버튼 CLICK DO
|
||||
CALL findMyAsNotiList(영역 A 조건 + page=0)
|
||||
DISPLAY 알림 이력 목록 그리드 (영역 B)
|
||||
END ON
|
||||
|
||||
ON 페이지네이션 CHANGE DO
|
||||
CALL findMyAsNotiList(영역 A 조건 + page/size)
|
||||
DISPLAY 알림 이력 목록 그리드 (영역 B)
|
||||
END ON
|
||||
|
||||
ON 영역 B [처리] 버튼 CLICK DO
|
||||
CALL readNoti(notiId)
|
||||
// UI설계: 해당 알림에 연계된 URL로 이동
|
||||
NAVIGATE notiUrl
|
||||
END ON
|
||||
|
||||
END
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 영역 A — 검색 필터
|
||||
|
||||
구성: **기간 · 구분** (+ 검색).
|
||||
|
||||
서버 `findMyAsNotiList` 고정 정책 (클라이언트 미전달):
|
||||
|
||||
- `recvUnqId` = 로그인 사용자 UUID
|
||||
- `delYn` = `N`
|
||||
- `notiType` = `ADSS` (행정지원 전용 API)
|
||||
|
||||
### 4-1. 필드 정의
|
||||
|
||||
| 표시명 | 입력 유형 | 필수 | 기본값 | API 파라미터 매핑 | 비고 |
|
||||
| ---------- | ---------- | ---- | --------------------------- | ----------------- | ------------------------------------------------------------------------------------------------ |
|
||||
| 기간(시작) | DatePicker | N | 오늘 − 1개월 (`YYYY-MM-DD`) | `startDt` | `NotiSearchDto.startDt` |
|
||||
| 기간(종료) | DatePicker | N | 오늘 (`YYYY-MM-DD`) | `endDt` | `NotiSearchDto.endDt` |
|
||||
| 구분 | Select | N | 전체(미선택) | `docSeComCd` | `INSTL` / `FNRS` / `SEWER` / `CNFM` / `PWRK` (또는 단축 `I`/`F`/`S`/`C`/`P`). 공통코드 `ASDOCSE` |
|
||||
|
||||
### 4-2. 버튼
|
||||
|
||||
| 버튼명 | 동작 |
|
||||
| ------ | -------------------------------------------------------------- |
|
||||
| 검색 | 영역 A 조건으로 `findMyAsNotiList` 호출 → 영역 B 갱신 (page=0) |
|
||||
|
||||
### 4-3. 콤보·기본값 주의
|
||||
|
||||
| 항목 | 내용 |
|
||||
| -------------- | ---------------------------------------------------------- |
|
||||
| 구분 = 전체 | `docSeComCd` 미전달. `notiType`은 서버가 `ADSS`로 고정 |
|
||||
| 구분 옵션 소스 | 공통코드 `ASDOCSE` (`docSeComCd` ↔ `docSeComNm`) |
|
||||
| 기간 | UI설계 상세설명: 기본 최근 1개월. `startDt`/`endDt`로 전달 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 영역 B — 알림 이력 목록
|
||||
|
||||
### 5-1. 그리드 컬럼
|
||||
|
||||
| 표시명 | Field | 비고 |
|
||||
| -------- | ------------ | --------------------------------------------------------------- |
|
||||
| No | (row index) | 페이지 오프셋 반영 |
|
||||
| 알림일시 | `regDt` | 표시 `YYYY-MM-DD HH:mm` (응답 `yyyy-MM-dd HH:mm:ss`) |
|
||||
| 알림내용 | `notiTtl` | 제목 문자열. UI 샘플은 `[YYYY-MM-DD] …` 접두 |
|
||||
| 연계업무 | `docSeComNm` | 문서구분 공통코드명 (`docSeComCd` + `@CodeName` `ASDOCSE`) |
|
||||
| 상태 | (derived) | `Badge` 렌더링. 판정 규칙은 §5-1-1 |
|
||||
| 처리 | (action) | 상태별 버튼 라벨. 클릭 시 `readNoti` 후 `notiUrl`로 이동 (§5-3) |
|
||||
|
||||
#### 5-1-1. 상태 UI 케이스 (`@common/components` `Badge`)
|
||||
|
||||
판정에 사용: `notiPrcsCmptnYn`, `notReadYn`, `regDt` (오늘 기준 경과일).
|
||||
|
||||
| 조건 | 라벨 | Badge |
|
||||
| ------------------------------------------------------------------------------ | -------- | ----------------------------- |
|
||||
| `notiPrcsCmptnYn` = `Y` | 처리완료 | `variant="default"` (primary) |
|
||||
| `notiPrcsCmptnYn` = `N` 이고 `notReadYn` = `Y` 이고 `regDt`로부터 **7일 초과** | 처리지연 | `color="red"` |
|
||||
| `notiPrcsCmptnYn` = `N` 이고 `notReadYn` = `Y` 이고 `regDt`로부터 **7일 이내** | 처리중 | `color="green"` |
|
||||
| `notiPrcsCmptnYn` = `N` 이고 `notReadYn` = `N` 이고 `regDt`로부터 **3일 초과** | 지연 | `color="orange"` |
|
||||
| `notiPrcsCmptnYn` = `N` 이고 `notReadYn` = `N` 이고 `regDt`로부터 **3일 이내** | 미조회 | `color="yellow"` |
|
||||
|
||||
```
|
||||
IF notiPrcsCmptnYn = Y THEN
|
||||
DISPLAY Badge "처리완료" (primary / variant=default)
|
||||
ELSE IF notReadYn = Y THEN
|
||||
IF daysSince(regDt) > 7 THEN
|
||||
DISPLAY Badge "처리지연" (red)
|
||||
ELSE
|
||||
DISPLAY Badge "처리중" (green)
|
||||
END IF
|
||||
ELSE // notReadYn = N
|
||||
IF daysSince(regDt) > 3 THEN
|
||||
DISPLAY Badge "지연" (orange)
|
||||
ELSE
|
||||
DISPLAY Badge "미조회" (yellow)
|
||||
END IF
|
||||
END IF
|
||||
```
|
||||
|
||||
- `daysSince(regDt)`: 오늘 날짜 − `regDt` 일자 (일 단위)
|
||||
- `regDt`가 없으면 상태 Badge 표시 전략 TBD (미표시 또는 기본값)
|
||||
|
||||
응답에 있으나 그리드에 **표시하지 않음**:
|
||||
|
||||
| Field | 비고 |
|
||||
| ----------------- | ---------------------------------------------------------------------- |
|
||||
| `notiId` | 알림 ID — 행 키 |
|
||||
| `recvUnqId` | 수신 회원 UUID (서버가 로그인 사용자로 고정) |
|
||||
| `senderUnqId` | 발신 회원 UUID |
|
||||
| `notiType` | 알림 종류 (`ADSS`) |
|
||||
| `notiCn` | 알림 내용 (목록에서는 서버가 제외할 수 있음) |
|
||||
| `notReadYn` | 확인 여부 `Y`/`N`. 상태 Badge 판정에 사용 (§5-1-1) |
|
||||
| `notiUrl` | 처리 버튼 이동 URL. 컬럼 미표시 |
|
||||
| `notiLnkgUnqNo` | 알림연결고유번호 |
|
||||
| `docSeComCd` | 문서구분 공통코드. 연계업무 표시는 `docSeComNm` 사용 |
|
||||
| `notiIdntyDt` | 알림 확인 일시 |
|
||||
| `notiIdntyYn` | 알림 확인 여부 (`notReadYn`과 동일 의미). 상태 판정은 `notReadYn` 사용 |
|
||||
| `notiPrcsCmptnYn` | 알림 처리 완료 여부. 상태 Badge 판정에 사용 (§5-1-1) |
|
||||
| `notiPrcsCmptnDt` | 알림 처리 완료 일시 |
|
||||
|
||||
### 5-2. 목록 메타·페이지네이션
|
||||
|
||||
| 항목 | 매핑 |
|
||||
| ------------- | ------------------------------------------- |
|
||||
| 건수 / size ▼ | 상단 우측 `N개` 셀렉트 → `Pageable.size` |
|
||||
| page / size | `NotiSearchDto`의 `PageableParams` |
|
||||
| 페이지 컨트롤 | Spring `Page` 표준 (`number`, `totalPages`) |
|
||||
|
||||
### 5-3. 행 상호작용
|
||||
|
||||
| 동작 | 설명 |
|
||||
| -------------- | --------------------------------------------------------------------------- |
|
||||
| 처리 버튼 클릭 | `readNoti(notiId)`로 읽음 처리 후, 해당 알림에 연계된 URL(`notiUrl`)로 이동 |
|
||||
| 행 클릭 | UI설계에 없음. 처리 버튼만 명시 |
|
||||
|
||||
**처리 버튼 라벨** (상태 Badge §5-1-1 기준):
|
||||
|
||||
| 상태 | 버튼명 |
|
||||
| -------- | -------- |
|
||||
| 미조회 | 처리하기 |
|
||||
| 지연 | 처리하기 |
|
||||
| 처리중 | 처리하기 |
|
||||
| 처리지연 | 처리하기 |
|
||||
| 처리완료 | 상세보기 |
|
||||
|
||||
- `notiUrl`이 비어 있으면 이동하지 않음 (no-op). 읽음 처리는 `notiUrl` 유무와 관계없이 호출
|
||||
- 읽음 처리 성공 후 목록 쿼리(`notiBaseKey`)를 invalidate 하여 영역 B 상태를 갱신
|
||||
|
||||
---
|
||||
|
||||
## 6. API/DTO 명세
|
||||
|
||||
### 6-1. 공통
|
||||
|
||||
| 항목 | 값 |
|
||||
| --------------- | ---------------------------------------------------------------------------------------- |
|
||||
| Base prefix | `/cms-service/api/v1/noti` (`ENDPOINT.CMS_SERVICE.NOTI`) |
|
||||
| 인증 | 로그인 사용자 UUID — 서버 `SecurityUtils.getLoggedInUserUnqIdUUID()` (클라이언트 미전달) |
|
||||
| 클라이언트 모듈 | `@/entities/noti` — `notiService` / `useFindMyAsNotiList` / `useReadNoti` |
|
||||
|
||||
### 6-2. 로그인한 사용자 행정지원 알림 목록 — `findMyAsNotiList`
|
||||
|
||||
| 기능 | Method | URL | Request DTO | Response DTO | API |
|
||||
| ---------------------------------- | ------ | ------------------- | --------------------------------- | ------------------------------------- | ------------------------------------------------------ |
|
||||
| 로그인한 사용자 행정지원 알림 목록 | GET | `{BASE}/as/my/list` | Query: `NotiSearchDto` + Pageable | `PageResponse<NotiAsUserResponseDto>` | `notiService.findMyAsNotiList` / `useFindMyAsNotiList` |
|
||||
|
||||
**Request (`NotiSearchDto` + Pageable)**
|
||||
|
||||
| 필드 | 필수 | 설명 |
|
||||
| ------------------------ | ---- | --------------------------------------------------------------------------- |
|
||||
| `recvUnqId` | N | 수신 회원 UUID. 서버가 로그인 사용자로 덮어씀 |
|
||||
| `senderUnqId` | N | 발신 회원 UUID. 본 화면 필터에 없음 |
|
||||
| `notiType` | N | 알림 종류. 본 API는 서버가 `ADSS`로 고정 |
|
||||
| `notiTtlKeyword` | N | 알림 제목 키워드. 본 화면 필터에 없음 |
|
||||
| `notiCnKeyword` | N | 알림 내용 키워드. 본 화면 필터에 없음 |
|
||||
| `notReadYn` | N | 알림 확인 여부 (`Y`/`N`). 본 화면 검색 필터에 없음 |
|
||||
| `delYn` | N | 삭제 여부. 서버가 `N`으로 고정 |
|
||||
| `startDt` | N | 시작일자 `YYYY-MM-DD` — 영역 A 기간(시작) |
|
||||
| `endDt` | N | 종료일자 `YYYY-MM-DD` — 영역 A 기간(종료) |
|
||||
| `docSeComCd` | N | 문서 구분 공통 코드 (`INSTL`/`FNRS`/`SEWER`/`CNFM`/`PWRK` 등) — 영역 A 구분 |
|
||||
| `page` / `size` / `sort` | N | Spring Pageable |
|
||||
|
||||
**Response (`NotiAsUserResponseDto`)**
|
||||
|
||||
| 필드 | 타입 | 설명 |
|
||||
| ----------------- | ------- | ------------------------------------------------------- |
|
||||
| `notiId` | number | 알림 ID |
|
||||
| `recvUnqId` | string | 수신 회원 UUID |
|
||||
| `senderUnqId` | string | 발신 회원 UUID |
|
||||
| `notiType` | string | 알림 종류 (`ADSS`) |
|
||||
| `notiTtl` | string | 알림 제목 |
|
||||
| `notiCn` | string? | 알림 내용 (목록에서 제외될 수 있음) |
|
||||
| `notReadYn` | string? | 알림 확인 여부 (`Y`/`N`). 상태 Badge 판정 |
|
||||
| `regDt` | string? | 등록 일시 `yyyy-MM-dd HH:mm:ss`. 상태 Badge 경과일 기준 |
|
||||
| `notiUrl` | string? | 알림 URL 주소 |
|
||||
| `notiLnkgUnqNo` | string? | 알림연결고유번호 |
|
||||
| `docSeComCd` | string? | 문서구분 공통코드 |
|
||||
| `docSeComNm` | string? | 문서구분 공통코드명 (`ASDOCSE`) |
|
||||
| `notiIdntyDt` | string? | 알림 확인 일시 `yyyy-MM-dd HH:mm:ss` |
|
||||
| `notiIdntyYn` | string? | 알림 확인 여부 (`Y`/`N`) |
|
||||
| `notiPrcsCmptnYn` | string? | 알림 처리 완료 여부 (`Y`/`N`). 상태 Badge 판정 |
|
||||
| `notiPrcsCmptnDt` | string? | 알림 처리 완료 일시 `yyyy-MM-dd HH:mm:ss` |
|
||||
|
||||
### 6-3. 알림 읽음 처리 — `readNoti`
|
||||
|
||||
| 기능 | Method | URL | Request DTO | Response DTO | API |
|
||||
| -------------- | ------ | ---------------------- | ----------------------- | ---------------- | -------------------------------------- |
|
||||
| 알림 읽음 처리 | PUT | `{BASE}/{notiId}/read` | Path: `notiId` (`Long`) | `Long` (알림 ID) | `notiService.readNoti` / `useReadNoti` |
|
||||
|
||||
**Request**
|
||||
|
||||
| 필드 | 위치 | 필수 | 설명 |
|
||||
| -------- | ---- | ---- | ------- |
|
||||
| `notiId` | Path | Y | 알림 ID |
|
||||
|
||||
Body 없음.
|
||||
|
||||
**Response**
|
||||
|
||||
| 타입 | 설명 |
|
||||
| ------ | ------------------------------ |
|
||||
| number | 읽음 처리된 알림 ID (`notiId`) |
|
||||
|
||||
화면 매핑: 영역 B [처리] 버튼 클릭 시 호출. 성공 시 `notiBaseKey` invalidate → `findMyAsNotiList` 재조회.
|
||||
|
||||
---
|
||||
|
||||
## 7. UI 구현 가이드
|
||||
|
||||
### 7-1. 기술 스택·원칙
|
||||
|
||||
- UI: `@common/components` — DatePicker, Select, Button, DataTable, Pagination, **Badge**
|
||||
- 목록: `@tanstack/react-table` + `useDataTable` (기존 `my-pbadms-sprt-list` 패턴)
|
||||
- 데이터: React Query `useFindMyAsNotiList(params)`, `useReadNoti()`
|
||||
- 검색 조건·페이지: URL `searchParams` 동기화 권장 (`useSearchParamsState` 스킬)
|
||||
- 처리 컬럼: 행 클릭이 아니라 **버튼 클릭**으로 `readNoti` 후 `notiUrl` 이동
|
||||
- 상태 컬럼: §5-1-1 규칙으로 `Badge` 렌더링 (`notiPrcsCmptnYn` / `notReadYn` / `regDt`)
|
||||
- 연계업무: `docSeComNm` 표시
|
||||
|
||||
### 7-2. 앱·파일 배치
|
||||
|
||||
| 구분 | 경로 |
|
||||
| ------------ | --------------------------------------------------------------------- |
|
||||
| 라우트 | `app/(main)/(with-base-layout)/noti/page.tsx` |
|
||||
| 페이지 | `pages/noti/ui/noti-list-page.tsx` |
|
||||
| 목록 그리드 | `pages/noti/ui/noti-list.tsx` |
|
||||
| 테이블 컬럼 | `pages/noti/model/noti-table-columns.tsx` |
|
||||
| 상태 판정 | `pages/noti/lib/resolve-noti-status.ts` |
|
||||
| Entity API | `entities/noti/api/noti-service.ts` |
|
||||
| Entity Hook | `entities/noti/api/queries.ts` → `useFindMyAsNotiList`, `useReadNoti` |
|
||||
| Entity Model | `entities/noti/model/noti-interface.ts` |
|
||||
|
||||
화면 레이어(`pages/noti`)·Entity(`findMyAsNotiList`, `readNoti`) 구현 완료.
|
||||
|
||||
### 7-3. 영역별 UI 매핑
|
||||
|
||||
| 영역 | 컴포넌트 | 데이터 |
|
||||
| ---- | ------------------- | -------------------------------------------------------------- |
|
||||
| A | `noti-list-page` | 로컬 state → `NotiSearchDto` |
|
||||
| B | DataTable + columns | `useFindMyAsNotiList` → `content[]`. 처리 버튼 → `useReadNoti` |
|
||||
|
||||
### 7-4. 다이얼로그·라우팅
|
||||
|
||||
| 항목 | 내용 |
|
||||
| ----------- | --------------------------------------------------------------------- |
|
||||
| 다이얼로그 | 없음 (목록 전용) |
|
||||
| 목록 라우트 | `/noti` |
|
||||
| 상세 이동 | 처리 버튼 → `readNoti(notiId)` 후 `notiUrl` (절대/상대 경로 형식 TBD) |
|
||||
|
||||
### 7-5. 데이터 흐름
|
||||
|
||||
```
|
||||
BEGIN
|
||||
|
||||
// 최초 진입
|
||||
SET 기간 = 최근 1개월 // startDt / endDt 전달
|
||||
CALL findMyAsNotiList
|
||||
DISPLAY 영역 B
|
||||
|
||||
ON [검색] CLICK DO
|
||||
CALL findMyAsNotiList // → 영역 B 갱신
|
||||
END ON
|
||||
|
||||
ON 페이지 CHANGE DO
|
||||
CALL findMyAsNotiList
|
||||
END ON
|
||||
|
||||
ON 영역 B [처리] 버튼 CLICK DO
|
||||
CALL readNoti(notiId) // → 영역 B 상태 갱신 (invalidate)
|
||||
IF NOT notiUrl THEN
|
||||
// no-op (읽음 처리는 수행됨)
|
||||
ELSE
|
||||
NAVIGATE notiUrl
|
||||
END IF
|
||||
END ON
|
||||
|
||||
END
|
||||
```
|
||||
@@ -0,0 +1,441 @@
|
||||
# 화면설계서: 이전기본계획조회 (기본 계획 찾기)
|
||||
|
||||
## 1. 기본 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
| ---------- | --------------------------------------------------------------- |
|
||||
| 버전 | 0.2 |
|
||||
| 프로세스명 | UI설계 |
|
||||
| 화면명 | 이전기본계획조회 (기본 계획 찾기) |
|
||||
| 화면 유형 | [v] 조회 [ ] 입력 [ ] 수정 [ ] 삭제 [ ] 출력 |
|
||||
| 메뉴 경로 | 하수도기본계획 등록·수정 > 사업개요 > [이전기본계획조회] Dialog |
|
||||
|
||||
---
|
||||
|
||||
## 2. 화면 목적
|
||||
|
||||
하수도기본계획 등록·수정 화면에서 **이전(기수립) 기본계획** 수치와 관련 보고서를 **조회·다운로드**한다. 시도·구군·연도·처리시설을 선택한 뒤 총설·처리구역별 현황을 표시하고, 분류 트리에서 기본계획 파일을 내려받는다. **부모 사업개요 폼에는 수치를 반영하지 않는다**(레거시 `bscPlnPopup.jsp`와 동일).
|
||||
|
||||
---
|
||||
|
||||
## 3. 화면 구성
|
||||
|
||||
### 3-1. 전체 레이아웃
|
||||
|
||||
부모: 하수도기본계획 등록/수정 폼 → 사업개요 섹션의 `[이전기본계획조회]` 버튼으로 Dialog 오픈.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Dialog 타이틀: 기본 계획 찾기 [닫기] │
|
||||
├─────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ [영역 A] 검색 필터 │
|
||||
│ 시도 ▼ 구군 ▼ 연도 ▼ 처리시설 ▼ [조회] │
|
||||
├─────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ [영역 B] 기본계획파일 │
|
||||
│ ┌──────────────────────┬────────────────────────────────────────────────────┐ │
|
||||
│ │ [영역 B-1] 분류 트리 │ [영역 B-2] 파일 목록 │ │
|
||||
│ │ (약 40%) │ (약 60%) │ │
|
||||
│ │ └ 노드… │ 파일명 / 다운로드 │ │
|
||||
│ └──────────────────────┴────────────────────────────────────────────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ [영역 C] 총설 │
|
||||
│ ┌────────┬──────────────당초──────────────┬──기준──┬──────────────변경──────────────┐ │
|
||||
│ │ 구분 │ 1단계 │ 2단계 │ 3단계 │ 4단계 │ 기준 │ 1단계 │ 2단계 │ 3단계 │ 4단계 │ │
|
||||
│ ├────────┼───────┼───────┼───────┼───────┼────────┼───────┼───────┼───────┼───────┤ │
|
||||
│ │계획목표│ 년 │ 년 │ 년 │ 년 │ 년 │ 년 │ 년 │ 년 │ 년 │ │
|
||||
│ │년도 │ │ │ │ │ │ │ │ │ │ │
|
||||
│ └────────┴───────┴───────┴───────┴───────┴────────┴───────┴───────┴───────┴───────┘ │
|
||||
├─────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ [영역 D] 처리구역별 현황 │
|
||||
│ ┌────────┬──────────────당초──────────────┬──기준──┬──────────────변경──────────────┐ │
|
||||
│ │ 구분 │ 1~4단계(+연도헤더) │ 기준 │ 1~4단계(+연도헤더) │ │
|
||||
│ ├────────┼────────────────────────────────┼────────┼────────────────────────────────┤ │
|
||||
│ │ 하수처리인구 … 배제방식 (읽기 전용 행) │ │
|
||||
│ └────────┴────────────────────────────────┴────────┴────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3-2. 화면 데이터 흐름
|
||||
|
||||
```
|
||||
BEGIN
|
||||
|
||||
// 부모 폼 — 사업개요
|
||||
ON [이전기본계획조회] 버튼 CLICK DO
|
||||
OPEN PreviousPlanLookupDialog
|
||||
// 프리필: 부모 폼 sewerBscPlan.sido / gugun / admdstCd
|
||||
CALL findSidoCombo()
|
||||
DISPLAY 시도 옵션 (영역 A)
|
||||
IF 시도 프리필 THEN
|
||||
CALL findGugunCombo(sidoCd)
|
||||
DISPLAY 구군 옵션 (영역 A)
|
||||
CALL getLvNowDmgMtncGnsvy({ level: "1", ctpvNm })
|
||||
// TBD: useLvNowDmgMtncGnsvy enabled — level별 필수 파라미터만 검사하도록 조정
|
||||
IF 구군 프리필 THEN
|
||||
CALL getLvNowDmgMtncGnsvy({ level: "2", ctpvNm, sggNm })
|
||||
DISPLAY 연도 옵션 (영역 A) // children 중 level=3 노드의 gnsvyYr
|
||||
CALL getClsfSystm({ clsfSystmNm: gugunNm })
|
||||
DISPLAY 분류 트리 (영역 B-1)
|
||||
END IF
|
||||
END IF
|
||||
END ON
|
||||
|
||||
// 영역 A: 시도 변경
|
||||
ON 영역 A 시도 CHANGE DO
|
||||
RESET 구군 / 연도 / 처리시설
|
||||
CALL findGugunCombo(sidoCd)
|
||||
CALL getLvNowDmgMtncGnsvy({ level: "1", ctpvNm })
|
||||
// 구군 미선택 → 연도·처리시설 옵션 비움, 트리 빈 안내
|
||||
END ON
|
||||
|
||||
// 영역 A: 구군 변경
|
||||
ON 영역 A 구군 CHANGE DO
|
||||
RESET 연도 / 처리시설
|
||||
CALL getLvNowDmgMtncGnsvy({ level: "2", ctpvNm, sggNm })
|
||||
DISPLAY 연도 옵션 (영역 A) // level=3 노드 → gnsvyYr
|
||||
CALL getClsfSystm({ clsfSystmNm: sggNm })
|
||||
DISPLAY 분류 트리 (영역 B-1)
|
||||
END ON
|
||||
|
||||
// 영역 A: 연도 변경
|
||||
ON 영역 A 연도 CHANGE DO
|
||||
RESET 처리시설
|
||||
CALL getLvNowDmgMtncGnsvy({ level: "3", ctpvNm, sggNm, gnsvyYr })
|
||||
DISPLAY 처리시설 옵션 (영역 A) // level=3 노드 children → swtrmtFcltCd / swtrmtFcltNm
|
||||
END ON
|
||||
|
||||
// 영역 A: 조회
|
||||
ON [조회] 버튼 CLICK DO
|
||||
VALIDATE 시도, 구군, 연도(targetYear), 처리시설(swtrmtFcltCd)
|
||||
CALL getNowDmgMtncGnsvy({ swtrmtFcltCd, ctpvNm, sggNm, targetYear })
|
||||
DISPLAY 총설 (영역 C) // 응답[0]의 planYr / planYrDt* / planYrDc*
|
||||
DISPLAY 처리구역별 현황 (영역 D) // 응답[0]의 지표 Dt1~4 / base / Dc1~4
|
||||
END ON
|
||||
|
||||
// 영역 B: 트리 노드 선택
|
||||
ON 영역 B-1 노드 CLICK DO
|
||||
CALL getFile({ clsfSystmSn, sort, vetPrcsYn }) // Response DTO TBD
|
||||
DISPLAY 파일 목록 (영역 B-2)
|
||||
END ON
|
||||
|
||||
// 영역 B: 파일 다운로드
|
||||
ON 영역 B-2 파일 CLICK DO
|
||||
CALL getFilePrcs(fileSn) // 파일 메타(경로·제목) — Response TBD
|
||||
CALL fileDownload({ filePath, fileName })
|
||||
// 브라우저 다운로드 트리거
|
||||
END ON
|
||||
|
||||
ON [닫기] DO
|
||||
CLOSE PreviousPlanLookupDialog
|
||||
// 부모 폼 값 변경 없음
|
||||
END ON
|
||||
|
||||
END
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 영역 A — 검색 필터
|
||||
|
||||
구성: **시도 · 구군 · 연도 · 처리시설** (+ 조회).
|
||||
|
||||
- 시도·구군: `adstdstr` 콤보 (기존 스펙 유지)
|
||||
- 연도·처리시설: 각각 `useLvNowDmgMtncGnsvy`를 **별도 호출**. `level`에 따라 반환 계층이 달라진다.
|
||||
|
||||
### 4-1. 필드 정의
|
||||
|
||||
| 표시명 | 입력 유형 | 필수 | 기본값 | API 파라미터 매핑 | 비고 |
|
||||
| -------- | --------- | ---- | ------------------------- | ------------------------------------------------ | -------------------------------------------------------------- |
|
||||
| 시도 | Select | Y | 부모 `sewerBscPlan.sido` | `ctpvNm`(표시명), 코드는 `adstDstrCd` | `useFindSidoCombo` |
|
||||
| 구군 | Select | Y | 부모 `sewerBscPlan.gugun` | `sggNm`(표시명), 코드는 `adstDstrCd` | `useFindGugunCombo(sidoCd)` |
|
||||
| 연도 | Select | Y | 없음 | `gnsvyYr` / 조회 시 `targetYear` | `useLvNowDmgMtncGnsvy({ level: "2", ctpvNm, sggNm })` |
|
||||
| 처리시설 | Select | Y | 없음 | `swtrmtFcltCd` ← 옵션 value, 라벨 `swtrmtFcltNm` | `useLvNowDmgMtncGnsvy({ level: "3", ctpvNm, sggNm, gnsvyYr })` |
|
||||
|
||||
> 처리시설은 `bns-if` `useFacilityList`를 **사용하지 않는다**.
|
||||
|
||||
### 4-2. 버튼
|
||||
|
||||
| 버튼명 | 동작 |
|
||||
| ------ | -------------------------------------------------------- |
|
||||
| 조회 | 필수값 검증 후 `getNowDmgMtncGnsvy` 호출 → 영역 C·D 갱신 |
|
||||
| 닫기 | Dialog 종료 (부모 미반영) |
|
||||
|
||||
### 4-3. `lvNowDmgMtncGnsvy` level 캐스케이드
|
||||
|
||||
| 트리거 | Request `level` | Request 파라미터 | UI에 쓰는 응답 | 옵션 추출 |
|
||||
| --------- | --------------- | ---------------------------- | --------------- | ------------------------------------------------------------------------------ |
|
||||
| 시도 선택 | `"1"` | `ctpvNm` | (하위 초기화용) | 연도·처리시설 Select 리셋. 구군은 `findGugunCombo` |
|
||||
| 구군 선택 | `"2"` | `ctpvNm`, `sggNm` | 연도 Select | 트리에서 `level === 3` 노드의 `gnsvyYr` |
|
||||
| 연도 선택 | `"3"` | `ctpvNm`, `sggNm`, `gnsvyYr` | 처리시설 Select | 선택 연도(`level === 3`) 노드의 `children[]` → `swtrmtFcltCd` / `swtrmtFcltNm` |
|
||||
|
||||
상위 변경 시 하위 선택값·옵션을 RESET한다 (시도→구군·연도·시설 / 구군→연도·시설 / 연도→시설).
|
||||
|
||||
---
|
||||
|
||||
## 5. 영역 B — 기본계획파일
|
||||
|
||||
### 5-1. 트리 (B-1)
|
||||
|
||||
| 표시명 | Field | 비고 |
|
||||
| ------ | --------------- | ------------------------ |
|
||||
| 분류명 | `clsfSystmNm` | `ClsfSystmResponseDto` |
|
||||
| 노드키 | `clsfSystmSn` | 선택 시 파일 목록 조회 |
|
||||
| 상위키 | `upClsfSystmSn` | 클라이언트에서 트리 조립 |
|
||||
| 정렬 | `sortSeq` | |
|
||||
| 경로 | `path` | |
|
||||
|
||||
- 조회 파라미터: `clsfSystmNm` = 선택 구군명(레거시와 동일). `upClsfSystmSn`은 하위 전개 시 TBD.
|
||||
- 시도·구군 미선택 시: 「시도와 구군을 선택하세요.」 안내.
|
||||
|
||||
### 5-2. 파일 목록 (B-2)
|
||||
|
||||
| 표시명 | Field | 비고 |
|
||||
| ------ | ----- | ------------------------------------------------------------------- |
|
||||
| 파일명 | TBD | `getFile` Response DTO가 `unknown` — 백엔드 스키마 확정 후 매핑 |
|
||||
| (기타) | TBD | 레거시: 트리 선택 후 목록 표시, 클릭 시 `fileprcs` → `fileDownload` |
|
||||
|
||||
### 5-3. 버튼·상호작용
|
||||
|
||||
| 동작 | 설명 |
|
||||
| -------------- | -------------------------------------------------------------- |
|
||||
| 트리 노드 클릭 | `getFile({ clsfSystmSn, … })` → B-2 목록 |
|
||||
| 파일 클릭 | `getFilePrcs(fileSn)` → `fileDownload({ filePath, fileName })` |
|
||||
| 빈 목록 | 「트리에서 항목을 선택하세요.」 / 「파일이 없습니다.」 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 영역 C — 총설
|
||||
|
||||
### 6-1. 테이블 구조
|
||||
|
||||
| 행(구분) | 열 매핑 (당초1~~4 / 기준 / 변경1~~4) |
|
||||
| ------------ | ------------------------------------------------------------------------------ |
|
||||
| 계획목표년도 | `planYrDt1planYrDt4` ~~/~~ `planYr` ~~/~~ `planYrDc1planYrDc4` (+ `년` 접미사) |
|
||||
|
||||
- 헤더: 당초(1~~4단계) · 기준 · 변경(1~~4단계)
|
||||
- 데이터 소스: `getNowDmgMtncGnsvy` 응답 배열의 **첫 번째** 요소
|
||||
- 읽기 전용
|
||||
|
||||
---
|
||||
|
||||
## 7. 영역 D — 처리구역별 현황
|
||||
|
||||
### 7-1. 행 정의 (표시명 → Field 접두사)
|
||||
|
||||
각 행은 `Dt1Dt4` ~~/ (접미사 없음=기준) /~~ `Dc1Dc4` 셀로 표시한다. 숫자는 천단위 콤마, 없으면 `-`.
|
||||
|
||||
| 표시명 | Field 접두사 | 비고 |
|
||||
| ------------------------ | -------------------- | ---------------------------------------------- |
|
||||
| 하수처리인구(인) | `swtrmtPpltnCnt` | |
|
||||
| 자연적하수처리인구수(인) | `natrSwtrmtPpltnCnt` | |
|
||||
| 사회적하수처리인구수(인) | `scilSwtrmtPpltnCnt` | |
|
||||
| 하수처리구역면적 | `swtrmtZoneArea` | |
|
||||
| 물사용량원단위 | `wtrUsqtyOrgnUnit` | |
|
||||
| 오수전환율(%) | `drtwSwtcRt` | |
|
||||
| 변동부하율(%) | `flctnLodRt` | |
|
||||
| 오수원단위 | `drtwOrgnUnit` | |
|
||||
| 계획하수량합계(㎥/일) | `planSwageQntSum` | |
|
||||
| 생활오수(㎥/일) | `lvngDrtwSum` | |
|
||||
| 지하수(㎥/일) | `ugwtSum` | |
|
||||
| 공장폐수(㎥/일) | `fctryWwtSum` | |
|
||||
| 관광오수(㎥/일) | `toursmDrtwSum` | |
|
||||
| 군부대(㎥/일) | `mtbsSum` | |
|
||||
| 연계처리수(㎥/일) | `linkPrcsCntSum` | |
|
||||
| 기타오수(㎥/일) | `etcDrtwSum` | |
|
||||
| 지하수사용량(㎥/일) | `ugwtUseSum` | |
|
||||
| 시설용량(㎥/일) | `fcltCpctSum` | |
|
||||
| 배제방식 | `exclsMethExpln` | 문자열; 단계별 `*Dt*`/`*Dc*` 존재 시 동일 규칙 |
|
||||
|
||||
헤더 3행째 연도: 영역 C와 동일하게 `planYrDt*` / `planYr` / `planYrDc*` 표시.
|
||||
|
||||
---
|
||||
|
||||
## 8. API/DTO 명세
|
||||
|
||||
### 8-1. 공통
|
||||
|
||||
| 항목 | 값 |
|
||||
| --------------- | ---------------------------------------------------- |
|
||||
| DC Base | `/dc-service/api/v1` (`ENDPOINT.DC_SERVICE`) |
|
||||
| AS adstdstr | `/as-service/api/v1/adstdstr` |
|
||||
| 클라이언트 모듈 | `@/entities/dc` (`dcService`), `@/entities/adstdstr` |
|
||||
|
||||
> 영역 A 처리시설은 `bns-if`를 사용하지 않음.
|
||||
|
||||
### 8-2. 시도·구군 콤보 (non-DC)
|
||||
|
||||
| 기능 | Method | URL | Request DTO | Response DTO | API |
|
||||
| -------- | ------ | ----------------------------------- | ------------------------ | -------------------------------- | ---------------------------------------------------------- |
|
||||
| 시도목록 | GET | `/as-service/api/v1/adstdstr/sido` | — | `CmCdAdstDstrComboResponseDto[]` | `cmCdAdstDstrService.findSidoCombo` / `useFindSidoCombo` |
|
||||
| 구군목록 | GET | `/as-service/api/v1/adstdstr/gugun` | Query: `sido` (시도코드) | `CmCdAdstDstrComboResponseDto[]` | `cmCdAdstDstrService.findGugunCombo` / `useFindGugunCombo` |
|
||||
|
||||
### 8-3. 연도·처리시설 계층 조회 — DC
|
||||
|
||||
| 기능 | Method | URL | Request DTO | Response DTO | API |
|
||||
| --------------- | ------ | -------------------------------------- | ---------------------------- | -------------------------------- | --------------------------------------------------------- |
|
||||
| 계층형 계획목록 | GET | `/dc-service/api/v1/lvNowDmgMtncGnsvy` | `LvNowDmgMtncGnsvySearchDto` | `LvNowDmgMtncGnsvyResponseDto[]` | `dcService.getLvNowDmgMtncGnsvy` / `useLvNowDmgMtncGnsvy` |
|
||||
|
||||
연도 Select·처리시설 Select는 **각각** `useLvNowDmgMtncGnsvy`를 호출한다 (`level`만 다르게).
|
||||
|
||||
**Request (**`LvNowDmgMtncGnsvySearchDto`**)**
|
||||
|
||||
| 필드 | 시도(`level=1`) | 구군→연도(`level=2`) | 연도→시설(`level=3`) |
|
||||
| --------- | --------------- | -------------------- | -------------------- |
|
||||
| `level` | `"1"` | `"2"` | `"3"` |
|
||||
| `ctpvNm` | 필수 | 필수 | 필수 |
|
||||
| `sggNm` | — | 필수 | 필수 |
|
||||
| `gnsvyYr` | — | — | 필수 |
|
||||
|
||||
**Response 노드 필드 (**`LvNowDmgMtncGnsvyResponseDto`**, 부분 optional)**
|
||||
|
||||
| 필드 | 등장 level | 설명 |
|
||||
| -------------- | ---------- | ------------------------ |
|
||||
| `level` | 1~3 | 계층 깊이 |
|
||||
| `ctpvNm` | 1 | 시도명 |
|
||||
| `sggNm` | 2 | 구군명 |
|
||||
| `gnsvyYr` | 3 | 연도 → 연도 Select value |
|
||||
| `swtrmtFcltCd` | 시설(리프) | 처리시설 코드 |
|
||||
| `swtrmtFcltNm` | 시설(리프) | 처리시설명 |
|
||||
| `children` | 1~3 | 하위 노드 배열 |
|
||||
|
||||
> **TBD**: 현재 `useLvNowDmgMtncGnsvy` `enabled`가 `level && ctpvNm && sggNm && gnsvyYr`로 고정되어 `level=1`/`2` 호출이 막힘. level별 필수 파라미터만 검사하도록 수정 필요.
|
||||
>
|
||||
> 예: `level=1` → `ctpvNm` / `level=2` → `ctpvNm && sggNm` / `level=3` → `ctpvNm && sggNm && gnsvyYr`
|
||||
|
||||
### 8-4. 기본계획 수치 조회 — DC
|
||||
|
||||
| 기능 | Method | URL | Request DTO | Response DTO | API |
|
||||
| ---------------- | ------ | ------------------------------------ | -------------------------- | ------------------------------ | ----------------------------------------------------- |
|
||||
| 현재·단계별 수치 | GET | `/dc-service/api/v1/nowDmgMtncGnsvy` | `NowDmgMtncGnsvySearchDto` | `NowDmgMtncGnsvyResponseDto[]` | `dcService.getNowDmgMtncGnsvy` / `useNowDmgMtncGnsvy` |
|
||||
|
||||
**Request (**`NowDmgMtncGnsvySearchDto`**)**
|
||||
|
||||
| 필드 | 매핑 |
|
||||
| -------------- | ----------------------- |
|
||||
| `swtrmtFcltCd` | 영역 A 처리시설 |
|
||||
| `ctpvNm` | 영역 A 시도 표시명 |
|
||||
| `sggNm` | 영역 A 구군 표시명 |
|
||||
| `targetYear` | 영역 A 연도 (`gnsvyYr`) |
|
||||
|
||||
**Response**: 지표 필드 + `Dt1Dt4` ~~/~~ `Dc1Dc4` 접미사 스테이지 필드 (`NowDmgMtncGnsvyResponseDto`). UI는 `data[0]` 사용.
|
||||
|
||||
### 8-5. 분류체계 — DC
|
||||
|
||||
| 기능 | Method | URL | Request DTO | Response DTO | API |
|
||||
| ------------ | ------ | ------------------------------ | -------------------- | ------------------------ | ----------------------------------------- |
|
||||
| 분류트리조회 | GET | `/dc-service/api/v1/clsfSystm` | `ClsfSystmParamsDto` | `ClsfSystmResponseDto[]` | `dcService.getClsfSystm` / `useClsfSystm` |
|
||||
|
||||
**Request**: `clsfSystmNm?`, `upClsfSystmSn?`
|
||||
**Response**: `clsfSystmSn`, `upClsfSystmSn`, `clsfSystmNm`, `sortSeq`, `droppAble`, `path`
|
||||
|
||||
> 레거시 경로 `/clsf` → 현재 클라이언트는 `/clsfSystm`.
|
||||
|
||||
### 8-6. 파일 목록·처리·다운로드 — DC
|
||||
|
||||
| 기능 | Method | URL | Request DTO / Params | Response DTO | API |
|
||||
| ------------ | ------ | --------------------------------- | ------------------------------------------------------- | ----------------- | -------------------------------------------- |
|
||||
| 파일목록 | GET | `/dc-service/api/v1/file` | `FileParamsDto` (`sort?`, `clsfSystmSn?`, `vetPrcsYn?`) | `unknown` **TBD** | `dcService.getFile` / `useFile` |
|
||||
| 파일처리정보 | GET | `/dc-service/api/v1/fileprcs` | Query: `fileSn` | `unknown` **TBD** | `dcService.getFilePrcs` / `useFilePrcs` |
|
||||
| 파일다운로드 | POST | `/dc-service/api/v1/fileDownload` | `FileDownloadParamsDto` (`filePath?`, `fileName?`) | `unknown` **TBD** | `dcService.fileDownload` / `useFileDownload` |
|
||||
|
||||
> **TBD**: 파일 관련 Response 스키마·다운로드 blob/헤더 처리·`fileDownload` POST body vs query 전달 방식은 백엔드/게이트웨이 확인 후 확정.
|
||||
|
||||
---
|
||||
|
||||
## 9. UI 구현 가이드
|
||||
|
||||
### 9-1. 기술 스택·원칙
|
||||
|
||||
- UI: `@common/components` — `Dialog`, `Select`, `Button`, `Table`, `Skeleton`
|
||||
- 상태: Dialog 로컬 state + React Query (`entities/dc`, `adstdstr`)
|
||||
- 영역 A 연도·처리시설: `useLvNowDmgMtncGnsvy`를 level별 **두 번**(또는 시도 포함 시 세 번) 호출
|
||||
- 테이블: 읽기 전용 고정 행 → `@tanstack/react-table` / `DataTable` **불필요**
|
||||
- 트리: jsTree 미사용 — 재귀 들여쓰기 트리
|
||||
- 번들: `PreviousPlanLookupDialog`는 outline에서 `next/dynamic` 로드 권장
|
||||
- 부모 폼: **수치 미반영** (조회·다운로드 only)
|
||||
- 1차 구현 시 DC 미연동이면 `@faker-js/faker` mock + TODO → 이후 `dcService` 훅으로 교체
|
||||
|
||||
### 9-2. 앱·파일 배치
|
||||
|
||||
| 구분 | 경로 |
|
||||
| ------------ | ------------------------------------------------------------------------ |
|
||||
| 진입 버튼 | `pages/sewer-bsc-plan/ui/sections/outline-form-section.tsx` |
|
||||
| Dialog | `pages/sewer-bsc-plan/ui/previous-plan-lookup-dialog.tsx` |
|
||||
| 필터 | `pages/sewer-bsc-plan/ui/previous-plan/previous-plan-search-filters.tsx` |
|
||||
| 파일 | `pages/sewer-bsc-plan/ui/previous-plan/previous-plan-file-section.tsx` |
|
||||
| 총설 | `pages/sewer-bsc-plan/ui/previous-plan/previous-plan-summary-table.tsx` |
|
||||
| 처리구역 | `pages/sewer-bsc-plan/ui/previous-plan/previous-plan-area-table.tsx` |
|
||||
| 셀 매핑 유틸 | `pages/sewer-bsc-plan/lib/previous-plan-table-utils.ts` |
|
||||
| mock(선택) | `pages/sewer-bsc-plan/lib/previous-plan-mock.ts` |
|
||||
| DC entity | `entities/dc/api/dc-service.ts`, `queries.ts`, `model/dc-interface.ts` |
|
||||
| 레거시 참조 | `adssNewOld/.../cmmn/bscPlnPopup.jsp` |
|
||||
|
||||
### 9-3. 영역별 UI 매핑
|
||||
|
||||
| 영역 | 컴포넌트 | 데이터 |
|
||||
| ---- | ------------------------------ | -------------------------------------------------------------- |
|
||||
| A | `previous-plan-search-filters` | adstdstr + `useLvNowDmgMtncGnsvy`(level 1·2·3) |
|
||||
| B | `previous-plan-file-section` | `useClsfSystm` + `useFile` + `useFilePrcs` + `useFileDownload` |
|
||||
| C | `previous-plan-summary-table` | `useNowDmgMtncGnsvy` / 조회 결과 state |
|
||||
| D | `previous-plan-area-table` | 동일 |
|
||||
|
||||
### 9-4. 다이얼로그·라우팅
|
||||
|
||||
| 항목 | 내용 |
|
||||
| ------------ | ------------------------------------------------------------------------ |
|
||||
| 다이얼로그명 | `PreviousPlanLookupDialog` / 타이틀 `기본 계획 찾기` |
|
||||
| 오픈 | 사업개요 `[이전기본계획조회]` |
|
||||
| 라우트 | 없음 (모달). 부모: `/sewer-bsc-plan/regist`, `/sewer-bsc-plan/[id]/edit` |
|
||||
| 선택 반영 | 없음 |
|
||||
|
||||
### 9-5. 데이터 흐름 (구현 요약)
|
||||
|
||||
```
|
||||
BEGIN
|
||||
|
||||
ON [이전기본계획조회] CLICK DO
|
||||
OPEN PreviousPlanLookupDialog (sido/gugun 프리필)
|
||||
END ON
|
||||
|
||||
ON 시도 CHANGE DO
|
||||
CALL findGugunCombo
|
||||
CALL getLvNowDmgMtncGnsvy(level=1)
|
||||
RESET 연도·처리시설
|
||||
END ON
|
||||
|
||||
ON 구군 CHANGE DO
|
||||
CALL getLvNowDmgMtncGnsvy(level=2) // → 연도 옵션
|
||||
CALL getClsfSystm
|
||||
RESET 처리시설
|
||||
END ON
|
||||
|
||||
ON 연도 CHANGE DO
|
||||
CALL getLvNowDmgMtncGnsvy(level=3) // → 처리시설 옵션
|
||||
END ON
|
||||
|
||||
ON [조회] CLICK DO
|
||||
VALIDATE
|
||||
CALL getNowDmgMtncGnsvy
|
||||
DISPLAY 영역 C · 영역 D
|
||||
END ON
|
||||
|
||||
ON 트리 노드 / 파일 CLICK DO
|
||||
CALL getFile → getFilePrcs → fileDownload // Response TBD
|
||||
END ON
|
||||
|
||||
END
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 미확정 (TBD) 추적
|
||||
|
||||
| ID | 항목 | 비고 |
|
||||
| --- | -------------------------------------------------------- | -------------------------------------------------------------------- |
|
||||
| T1 | `useLvNowDmgMtncGnsvy` enabled을 level별 필수값으로 분기 | `1`: ctpvNm / `2`: +sggNm / `3`: +gnsvyYr |
|
||||
| T2 | `getFile` / `getFilePrcs` / `fileDownload` Response DTO | 현재 `unknown` |
|
||||
| T3 | 파일 다운로드 UX (blob, Content-Disposition, 게이트웨이) | 레거시 apigateway 직접 호출과 차이 |
|
||||
| T4 | `clsfSystm`의 `upClsfSystmSn` 점진 로드 여부 | flat 목록 vs 계층 API |
|
||||
| T5 | 1차 mock vs 즉시 `dcService` 실연동 | 마이그레이션 플랜은 mock 우선, entity는 준비됨 |
|
||||
| T6 | 부모 폼 수치 반영 | 요구 없음(레거시 동일). 요청 시 별도 스펙 |
|
||||
| T7 | `level=1` 응답 UI 활용 여부 | 시도 선택 시 호출하나 구군은 adstdstr — 응답은 캐시·검증용일 수 있음 |
|
||||
@@ -1,8 +1,16 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
import { AUTH_USER_ID, CLAIM_NAME, PORT, PROXY_HOST, SERVER_API_URL, SITE_ID } from "@/shared/config";
|
||||
import {
|
||||
AUTH_USER_ID,
|
||||
CLAIM_NAME,
|
||||
PORT,
|
||||
PROXY_HOST,
|
||||
SERVER_API_URL,
|
||||
SITE_ID,
|
||||
} from "@/shared/config";
|
||||
|
||||
const serverApiUrl = process.env.SERVER_API_URL;
|
||||
const dcServiceApiUrl = process.env.DC_SERVICE_API_URL;
|
||||
|
||||
// CSP 헤더 설정 함수 (img-src만)
|
||||
function addSecurityHeaders(response: NextResponse): NextResponse {
|
||||
@@ -22,7 +30,15 @@ export function middleware(req: NextRequest) {
|
||||
|
||||
if (pathname.startsWith("/server")) {
|
||||
const queryParams = searchParams.toString();
|
||||
const newUrl = `${serverApiUrl}${pathname.replace("/server", "")}${
|
||||
|
||||
let serverUrl: string | undefined;
|
||||
if (pathname.includes("/dc-service")) {
|
||||
serverUrl = dcServiceApiUrl;
|
||||
} else {
|
||||
serverUrl = serverApiUrl;
|
||||
}
|
||||
|
||||
const newUrl = `${serverUrl}${pathname.replace("/server", "")}${
|
||||
queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
|
||||
@@ -34,7 +50,6 @@ export function middleware(req: NextRequest) {
|
||||
return addSecurityHeaders(response);
|
||||
}
|
||||
|
||||
|
||||
// tus-js-client PATCH 요청: Location 헤더로 /server 없이 반환된 경로 직접 처리
|
||||
// (예: /attach-service/api/v1/tus/upload/{id})
|
||||
if (pathname.startsWith("/attach-service")) {
|
||||
@@ -56,10 +71,10 @@ export function middleware(req: NextRequest) {
|
||||
return addSecurityHeaders(response);
|
||||
}
|
||||
|
||||
// if (pathname === "/") {
|
||||
// const response = NextResponse.redirect(new URL("/dashboard", req.url));
|
||||
// return addSecurityHeaders(response);
|
||||
// }
|
||||
if (pathname === "/") {
|
||||
const response = NextResponse.redirect(new URL("/dashboard", req.url));
|
||||
return response;
|
||||
}
|
||||
|
||||
logMessages.push("\n--------------------------------\n");
|
||||
console.log(logMessages.join("\n"));
|
||||
|
||||
@@ -1,8 +1,53 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const subDomain = process.env.NEXT_PUBLIC_SUB_DOMAIN || "http://localhost:13000";
|
||||
|
||||
const webhwpCtrlBase = (
|
||||
process.env.NEXT_PUBLIC_WEBHYP_CTRL_URL || "https://hwp.onasys.co.kr/webhwpctrl"
|
||||
).replace(/\/$/, "");
|
||||
|
||||
const webhwpAssetPrefixes = ["js", "hwpsdk", "dist", "commonFrame", "wasm"] as const;
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: "standalone",
|
||||
reactStrictMode: true,
|
||||
transpilePackages: ["@common/assets"],
|
||||
experimental: {
|
||||
globalNotFound: true,
|
||||
},
|
||||
|
||||
async rewrites() {
|
||||
return {
|
||||
beforeFiles: [
|
||||
{
|
||||
source: "/_next/static/:path*",
|
||||
destination: `${subDomain}/_next/static/:path*`,
|
||||
has: [
|
||||
{
|
||||
type: "header",
|
||||
key: "referer",
|
||||
value: "(.*)/cms(.*)",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
afterFiles: [
|
||||
{
|
||||
source: "/cms/:path*",
|
||||
destination: `${subDomain}/cms/:path*`,
|
||||
},
|
||||
...webhwpAssetPrefixes.map((prefix) => ({
|
||||
source: `/webhwpctrl/${prefix}/:path*`,
|
||||
destination: `${webhwpCtrlBase}/${prefix}/:path*`,
|
||||
})),
|
||||
{
|
||||
source: "/webhwpctrl/file/:path*",
|
||||
destination: `${webhwpCtrlBase}/file/:path*`,
|
||||
},
|
||||
],
|
||||
fallback: [],
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
@@ -20,10 +20,12 @@
|
||||
"@faker-js/faker": "^9.9.0",
|
||||
"@frontend-opensource/use-react-hooks": "^1.1.4",
|
||||
"@hookform/resolvers": "^4.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@tanstack/react-query": "^5.75.5",
|
||||
"@tanstack/react-query-devtools": "^5.75.5",
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"axios": "^1.8.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"js-cookie": "^3.0.5",
|
||||
"lucide-react": "^0.474.0",
|
||||
@@ -34,6 +36,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3",
|
||||
"@hookform/devtools": "^4.4.0",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"eslint": "^9.0.0",
|
||||
"eslint-config-next": "15.3.8",
|
||||
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 483 KiB |
|
After Width: | Height: | Size: 483 KiB |
@@ -0,0 +1,63 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 538 755">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: #fff;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<!-- Generator: Adobe Illustrator 28.7.9, SVG Export Plug-In . SVG Version: 1.2.0 Build 218) -->
|
||||
<g>
|
||||
<g id="Layer_1">
|
||||
<g id="han" data-label-shift="dx,dy">
|
||||
<path class="cls-1" d="M159.2,197l-5,5.8,5.1,3.7,13.2,9.7-7.3,3.5-8.2-1.2-9.4,1.4,1.4,4.9-3.5,7.3,3.8,2.6-.9,4.7,8.9-2.3,4.2-3.7,5.2,4.2-6.1,2.3.9,12,3,7-.9,3.3-.5,1.6,5.4,6.8,5.2,13.4h-3.6c0-.1,6.4,3.8,6.4,3.8l4.8,6h1.2l3.6-5.4,3.6-.6,13.8,5.9,19.7-1.1,4.6-6.5,3-5.2,8.2-1.7,11.7-17.8,7.1,1.9,4.9,10,13.2,9.6,3.8,13-1.4,12.2-.5,9.5,1.6,1.1-.6,1.3v1.1c.1,0-2.2,2.4-2.2,2.4l-17.5,7.4,7.6,19.2,16.3,1.1,8.4,10.8,12.6.6,4.2-5.2-4.6-7.9-9.2-6.2,12.1-7.1,6.4,5.2,1.3-5.6-6.6-6.5,17.5-5.8,4.8,4.4,4.8-2.1-4.7-6.5,4.5-8.8,6.3-.4,4.7-3,8,3,24.1,4.5,11.5-7.8-2.8-6.4,6.5-11.7,10.5-5.5,7.6-7.9,10.2-2.3,13.4,4.6,4.4-8,12.4,8.2,3.4-3.1.2-15.2.4-11.3,13.4-3.2,4.6-.4-1.9,9.9,9.8,4.6,1.6,12.8,12.2,9.2,9.8-8.4,15-8.9-3.7-19-21.8-40.6-5.7-10.6,1.2-6.8-4.9-6.1-4-4.9,1.2-5.2-26.3-33.1-5.8-12.1-7.1-14.9-11.9-20.9-2.9-9.4-2.1-6.7-1.8-5.2-8.7-25.5-8.6-14.4-.9-11-5.2-11-3-6.3-6,6.5-5.2,22.8-9.8,11-5.5,2.8-7.4,3.7-17.1.5-12.7-1.6-8.2,2.3-5.2-3.4-3.4-2.2-18.8-2.3-21.8,4.5-19-3.7-3.5,4.7-11.2-7.3-5.2,4.2-6.1-.7-11.5,3.5-14.1,10.8-3.7,10.1-12.9,9.8-4,7.3-8.5,6.8-2.3,1.9-9.1,4.5-4,18.3-9.2,11.5-14.3,1.2-2.1,30,5.6,1.4,3.3,9.2-1.4,2.7.9,2.6,2.9-.7,1.8,3.2-4.5,2.2,1.7,8.6,3.8,6.9,8.9,3.4Z"/>
|
||||
</g>
|
||||
<g id="yeongsan" data-label-shift="dx,dy">
|
||||
<path class="cls-1" d="M57.4,578.4s.2,1.4.2,2.3.7,1.6.7,1.9.5,1.4.7,2.3c.2.9,1.2,1.2,1.2,1.2h0s.5,1.4.5,1.4c0,0-.5.7-.9,1.4-.5.7,1.6.9,1.6.9l2.8-.7s1.4-.7,1.4-1.2,0,0-.2-.7c-.2-.7-.5-.7-.9-1.2-.5-.5.5-.2.5-.2l.5.2,2.6-.5s.9-.5,1.4-.7c.5-.2-.2-.5-.2-.9s-.2-1.2-.2-1.2l.2-.9v-1.2c0-.5.7-.7.9-1.2.2-.5.5-.7.9-1.2.5-.5,0-.7,0-1.6s-.5-.5-.5-.9-.5,0-.5,0l-.9.5-.9.7s-.2.9-.5,1.2c-.2.2-1.4.2-1.4.2,0,0-.2-.5-1.2-.9-.9-.5,0,0-.5,0s-1.2-.2-1.2-.2c0,0-1.2-.7-1.6-.9-.5-.2-.5-.9-.5-.9h-1.2s-1.9,1.4-2.8,1.9c-.9.5,0,1.2,0,1.2Z"/>
|
||||
<path class="cls-1" d="M45.2,585.7c.2.2,0,.2.7.9.7.7.5,1.6.9,1.6s.2-.5,1.2,0c.9.5,1.4.5,1.9.7.5.2,1.6.9,1.9.9s1.4.7,1.4.9-.2.2,0,.5c.2.2,0,.5.5,1.4.5.9,1.9,2.6,1.9,2.6,0,0-.7.7.5.5,1.2-.2,1.9-.2,1.9-.9s.2-1.2.2-1.4-.2-.2-.5-1.2c-.2-.9-.7-1.6-.7-1.6,0,0,1.2-.2,0-1.2-1.2-.9-.2-1.2-1.2-.9-.9.2-1.9.2-1.9.2-.2-1.2-.2-1.9-.2-1.9l-.5-.5.7-1.4h0c.5,0,.9-.2,1.2-.2s.9-.7.9-.7c0,0,.2-.2,0-.7-.2-.5-.2-.2-.9-.7s-1.6-.7-1.6-.7l-2.1-1.2-1.4-.9c-.7-.2-2.6.9-2.6.9,0,0,.9-.5,0,.7-.9,1.2-2.3,1.9-2.3,1.9,0,0-.2.5,0,.9.2.5,0,1.2.2,1.4Z"/>
|
||||
<path class="cls-1" d="M28.6,585.5s0,.7,1.2.7h2.1c.5,0,.9.7.9.7v1.9l1.2.7s1.4,0,1.9-.5c.5-.5.5-.7.5-.7l-.5-1.4,2.3-.7s.5-.5.7-1.2c.2-.7-.2-1.2,0-2.3.2-1.2,0-2.8,0-2.8,0,0,.9-1.4.9-2.1s1.9-2.6,1.9-2.8h0v-.7h-1.4c-.2,0-1.7.5-2.1.7-.5.2,0,0-.9,1.2s-.2,1.6-.2,1.6l-1.9.5-1.4.7-.9.2s-1.2-.2-2.1-.2-.5.9-.5.9c0,0-1.2,1.4-1.9,1.6-.7.2-.7.7-.7.7,0,0,.9,2.3.9,2.8v.5Z"/>
|
||||
<path class="cls-1" d="M41.7,591.4c-.5.2-.7-1.2-.5,0,.2,1.2,1.2,2.1,1.2,2.1l1.4.9s.9-.2,1.4,0c.5.2.9,0,.9,0l1.9.7v.2s.7-.2.5-1.6c-.2-1.4,0-1.4,0-1.4l-.7-.9-2.6-1.4h0s-2.8-.7-3-.5c-.2.2-.5-.2-.5.2s.5,1.4,0,1.6Z"/>
|
||||
<path class="cls-1" d="M34.2,597.7s0,0,0,0c0,0,0,0,0,0Z"/>
|
||||
<path class="cls-1" d="M45,598.9l-.7-.7-.5-.9s.2-1.4-.2-1.4-1.9-.5-1.9-.5l-1.4-.7h0s-1.4,0-1.4,0c0,0-.9,0-1.2.7-.2.7-.9.5-.9.9s-2.1,1.2-2.5,1.4c0,0,.2.2.4.5.5.7.5,1.4,1.2,1.4s2.1.2,2.3,0c.2-.2.9-.7,1.2-.5.2.2.5.5.5.9s-.5,1.2-.5,1.6.5,0,0,.5c-.5.5.2,1.4.5,1.6.2.2-.7,2.1-.7,2.1,0,0-.5.5-.5.7s1.4.7,1.6,0c.2-.7.7-1.2.9-1.4.2-.2.9-.5.9-.5,0,0-.5.2.7.2s2.1.2,2.1-.5v-1.9s-.2-1.2,0-1.4c.2-.2,0-2.3,0-2.3Z"/>
|
||||
<path class="cls-1" d="M18.5,619.7c.7,0,1.9-.9,2.3,0,.5.9,1.9,2.6,1.9,2.6,0,0,.2-.2,1.4,0,1.2.2,1.2.5,2.1,0,.9-.5,1.4-1.4,1.4-1.4l1.2-1.2,3.3-1.4s-.2-.7-.7-2.1c-.5-1.4-.7-2.1-.7-2.1,0,0,1.2.2.5-.9-.7-1.2-.9-1.9-.9-1.9l-.5-1.6h0s-.7-.9-.7-.9l-2.1.2s-.2,1.2,0,1.9c.2.7.2.9,0,1.4-.2.5-.7-.5-1.2,0-.5.5-2.3.2-2.3.2h-1.2l-.9,1.4-1.2.9-2.3.9-2.1,1.4s-.5,0,0,.9c.5.9,2.1,1.6,2.8,1.6Z"/>
|
||||
<path class="cls-1" d="M33.1,624h-.9l-1.4-.7-2.1.7s-.9,1.2-.9,1.6.7,1.9,1.4,2.3c.7.5,1.6.7,1.9,1.6.2.9.2,1.9.2,1.9,0,0,1.9.7,2.3-.7.5-1.4.2-2.3.7-2.6.5-.2,1.9-1.6,1.9-1.6,0,0-.5-.5.7-.5s1.6-.5,1.6-.7v-1.9l-.9-.9h.9l.7-.9s.2-.7,0-1.2c-.2-.5-.5-1.9-.5-1.9l-2.6.5h0l-1.4,1.4-.5.9s.2.9,0,1.2c-.2.2-1.2,1.4-1.2,1.4Z"/>
|
||||
<path class="cls-1" d="M65.6,620.2l1.9-.7-2.1-2.6-3.5-1.9h0s-3.3.7-3.3.7l1.6,2.1.9,1.4s-.5.5-.9.9c-.5.5-1.6.7-1.6.7,0,0-.5.5-.5.9s-.9,0-2.1.7c-1.2.7-4.5,1.9-4.5,1.9h-.9c.9,0,1.6,2.6,2.3,2.6h3.1s-.2-.5.9-.7c1.2-.2,2.6-1.2,2.6-1.2,1.4.2,2.3-.7,3,.5.7,1.2,1.4.9,1.6,1.4.2.5,1.2,2.1,1.2,2.1l-.7,2.6s1.2.9,1.6.7c.5-.2,1.9-1.4,1.9-1.4l.9-1.9s-.5-1.4,0-1.9c.5-.5-1.6-1.4-1.6-1.4l-2.8-.7-1.9-2.6v-1.2l2.8-1.2Z"/>
|
||||
<path class="cls-1" d="M64.2,635.5v-1.6s-3.3,1.4-3.3,1.6.9,1.6.9,1.6h1.6l.7-1.6Z"/>
|
||||
<path class="cls-1" d="M59.8,639.2c0,1.2.5,2.8,1.2,3,.7.2,1.6,0,1.6,0v-3l-1.6-.9s-1.2-.2-1.2.9Z"/>
|
||||
<path class="cls-1" d="M38.4,638.3c1.2,0,2.8-4.5,2.8-4.5v-1.4h0s-3.5,0-3.5,0l-2.1,1.4-3.5.7s-.2,1.9,1.4,1.9.7-.1.6-.2c0,0,.3,0,.6.2,1.6.5,3.3.7,3.3,1.2s-.7.7.5.7Z"/>
|
||||
<path class="cls-1" d="M15.4,630.1h0s0,0,0,0h0Z"/>
|
||||
<path class="cls-1" d="M7,642.7c.2-.5,1.2-.7,1.2-1.4s-1.6-2.6-.5-3.1c1.2-.5,2.6-.9,2.8-1.2.2-.2,1.2-.7,1.6-.5s.9.9.9.9l1.4-.5.5-.9s.2-.9.5-1.4c.2-.5.7-1.9.7-1.9v-1.2l-.7-1.6c-.3.2-2.6,2.1-2.8,2.3-.2.2-3,1.2-3.3,1.2s-3.1.2-3.1.2l-3.8.5-2.6,1.9,1.9,2.1s-.2,1.9,0,2.1c.2.2-.5,1.2.5,1.6.9.5,1.6.9,1.6.9,0,0,2.8.2,3-.2Z"/>
|
||||
<path class="cls-1" d="M16.6,649.1c0-.7-1.2-1.6-1.2-1.6l-.7-.7-.9-.9s-.2-1.2-.2-1.4-.7-.9-.7-.9c0,0-2.3.2-2.3.5s-.7.7-.7.7c0,0-.2.7-1.6.7s-2.8-.5-2.6,0c.2.5-.2.9-.2,1.6s-.5,1.9-.5,1.9v1.2s.2,1.2.7,1.4c.5.2,1.2.5,1.4.7.2.2,1.4.9,1.2,1.4-.2.5,2.3.2,2.3.2l.5-.5c.2-.2,1.9-1.2,1.9-1.2,0,0,0-.9.5-.9s3.3-.5,3.3-.5v-1.6Z"/>
|
||||
<polygon class="cls-1" points="12.9 643.4 12.9 643.4 12.9 643.4 12.9 643.4"/>
|
||||
<path class="cls-1" d="M27.7,639.9c.5.5,1.4,1.6,2.1,1.9.7.2,1.2.5,1.4,1.2.2.7.2,1.4.5,2.1.2.7,1.9.7,1.9,1.2s.5-.2,1.4,0c.9.2.2-.2,1.6,1.2,1.4,1.4,2.3,2.1,2.6,2.6.2.5.9,0,.9,0l1.2-.9s-.2-1.6,0-1.6.2-2.1.2-2.3-.5-2.3-.5-2.3c0,0-1.2-1.4-1.4-1.4s-2.1-.7-2.1-.7l-1.2-1.2-.9-1.2-1.4-.5h0l-3.7-.7h-2.1l-1.2,1.6s.2.7.7,1.2Z"/>
|
||||
<path class="cls-1" d="M32.6,663.4c.5.2,2.3.5,2.8.5s1.6-.2,1.9-.5c.2-.2.9-.2,1.6-.2s3.5.2,3.5.2c0,0,.5-.7.2-1.4-.2-.7-.9-1.4-.9-1.4l-.2-.7-.7-.5.7-1.2v-.9s-.7-.5-1.4-.5-1.4.2-1.4-.2-.9-1.9-.9-1.9l-1.4.7h0c-.9.5-1.9.7-2.1.9-.2.2-3.3.2-3.1.7.2.5.7,1.2.9,1.4.2.2.9,1.6.9,1.6,0,0-.5,1.6-.5,1.9s-.5,1.2,0,1.4Z"/>
|
||||
<path class="cls-1" d="M21.3,670.4c0-.2,0-1.4.5-1.6.5-.2.7-.5.7-.7s-.7-1.2-.7-1.4-1.2-1.2-1.2-1.2l-.5-1.2-.2-1.2-.2-1.9h0s-.9-1.9-1.2-1.9-1.4-.2-1.4,0-.5.9-.5.9v.7c0,.2-.2.7,0,1.2.2.5-.2,1.4,0,1.6.2.2.2.7.5,1.4.2.7.7,1.2.7,1.4s-.2,1.2-.2,1.2c0,0-.5-.7-.5.5s-1.9,1.9-.5,2.1c1.4.2,2.8.5,3,.5s1.6-.2,1.6-.5Z"/>
|
||||
<path class="cls-1" d="M27.4,673s-.5-.9,0-1.6c.3-.5.5-.9.7-1.2.2-.5.9-.5.9-.9s.5-2.3,0-2.8c-.5-.5-.9-1.6-1.4-2.3-.5-.7-.2-.9-1.2-1.6-.9-.7-1.9-1.2-1.9-1.2l-1.2.2h0s-.7,2.1-.7,2.3.2,2.3.7,2.6c.5.2,1.6,1.4,1.9,1.9.2.5.2,1.2.2,1.6s-.7,2.1-.9,2.1,0,0-1.2.5c-1.2.5-2.6.2-3,.9-.5.7-1.2,1.4-1.2,1.4v1.4c0,.2-.2.7.5.7s2.3-.2,2.8-.5c.5-.2,1.4-.7,1.4-.7l2.3-2.1,1.2-.7Z"/>
|
||||
<path class="cls-1" d="M63.7,683.1c-.2-.5-1.4-2.1-1.4-2.1l-.5-.9s0-1.6-.9-1.9c-.9-.2-3-.2-3-.2l-1.6-2.3s-1.4-2.6-1.6-2.6-1.4,0-2.1-.2c-.7-.2-2.6-1.2-2.6-1.2l-.9.7c.2.7,1.6,2.8,1.6,2.8l1.2,2.3-.5,1.9s-1.9.5-2.3.5h-3s-.5-.7-.7.7c-.2,1.4-2.6,2.6-2.6,2.6h-3s-.9,1.6-.9,2.1-6.1,3.1-6.1,3.1l-1.9,2.6-1.9.5s-.5.7-.5.9-1.2,1.6-1.2,1.6h-.7s-2.3.5-2.3.9.5,1.6.5,2.1v1.6s0,1.6.2,1.6,1.4.7,1.4.7l.7,1.2s.5.2.5.5.7,1.2.7,1.2l1.2,1.2s-.5,1.6,0,2.1c.5.5.9.5,1.4.7.5.2,4.2.7,4.2.7,0,0,1.9.2,2.1.5.2.2,1.4.5,2.1,0,.7-.5,7-1.6,7-1.6,0,0-.7-.9,0-1.2.7-.2,1.9-.5,3-1.4,1.2-.9,3.7-1.2,3.7-1.2,0,0-.5-1.2.2-1.6.7-.5,2.6-2.1,2.8-2.1s2.1,1.4,2.1,1.4c0,0-.7.7.5.7s1.4-.5,1.9-2.1c.5-1.6,1.9-2.3,1.9-2.3l.5-.7s-.5-.5,0-1.6c.5-1.2.9-2.6.9-2.6v-3.5s-.5,0,.5-.5c.9-.5,2.1-2.3,1.4-3.1-.7-.7-1.6-1.9-1.9-2.3Z"/>
|
||||
<polygon class="cls-1" points="49 672.3 49 672.3 49 672.3 49 672.3"/>
|
||||
<path class="cls-1" d="M93.5,737.5c-2.3-1.2-4.2-2.3-4.2-2.3h-1.9l-1.2,3.5s1.4,0,1.2.9c-.2.9-1.6.5-1.2,1.6.5,1.2-.5.7,1.6,1.6,2.1.9,2.8,1.9,3.7.9.9-.9,1.9-2.6,1.9-2.6h0l.7-1.2s1.6-1.4-.7-2.6Z"/>
|
||||
<path class="cls-1" d="M86.2,745l-2.8-1.9s-2.8,2.6-2.8,3.1-2.1,3.3-1.6,4,1.2,1.6,2.8,1.6,3.3-1.6,5.4-2.6c2.1-.9,2.8-2.3,3.7-1.9.9.5,2.1-.5,2.1-.5h0l-1.9-1.2-4.9-.7Z"/>
|
||||
<path class="cls-1" d="M101.7,742h0l-3.5,1.2s-.9,1.2-.9,1.6.5,2.6.5,2.6c0,0-.5.5-.5,1.6v2.3s1.2,3.1,2.1,3.5c.9.5,2.6-.5,3.1-1.9.5-1.4-.9-5.6-.9-5.6,0,0-2.8-1.2-2.1-1.4.7-.2,2.8-.5,3.1-.5s.9-.7.9-.7l-.7-2.8h-.9Z"/>
|
||||
<path class="cls-1" d="M115.1,720.4l-1.2-1.6-.5-1.6h0v-2.6l-2.1-3.3s-1.6-1.2-1.9-1.6c-.2-.5-3-2.3-3-2.1s-2.3,2.3-2.3,2.6-3.7,2.8-3.7,2.8c0,0,1.2,4,1.2,4.2s-1.9.2-.5,1.9c1.4,1.6,5.9,2.1,5.9,2.1,0,0,.2-1.4.5.5.2,1.9-.5,2.8-.5,3.1s1.2,1.2,2.6,1.2,3.3-.2,3.5,0c.2.2,3.5.5,3.5.5,0,0,.2,0,0-2.1-.2-2.1-1.4-3.8-1.4-3.8Z"/>
|
||||
<path class="cls-1" d="M125.6,711.9c.5,0,1.4-1.9,1.4-1.9,0,0-.5-.7.9-.5,1.4.2.9,0,1.6.5.7.5,1.2.5,1.4.5s1.2-.7.5-1.4c-.7-.7-1.4-.9-1.9-1.6-.5-.7-.5-2.6-.5-2.6,0,0-.5-1.4-.7-1.4h-2.8l-.9.9h0c-.7,0-3.5-.7-3.5-.7l-.5,2.8-2.1,1.4s-.9.5-.5,1.2c.5.7.9,1.2.7,1.6-.2.5-1.6,0-1.4.7.2.7,1.6,1.9,1.6,1.9,0,0-.7,1.2-.7,1.6s.9,1.4,1.4,1.4,1.9-2.1,1.9-2.1c0,0,.5-.9.9-1.2.5-.2,2.1-1.2,2.1-1.2h.9Z"/>
|
||||
<path class="cls-1" d="M141.5,712.4c0-.2-.9-.5-1.2-.7-.2-.2-1.6-.7-1.6-.7l-3-.9h-1.7s-.7,2.1-.7,2.3-.5,1.2,0,1.4c.5.2,2.1.7,2.1.7v1.2c0,.5-.7.7.5,1.2,1.2.5,4.2-.5,4.2-.5h2.6s.9-1.4.5-1.9c-.5-.5-1.6-1.9-1.6-2.1Z"/>
|
||||
<path class="cls-1" d="M128.6,725.1s.2-.2.5,0c.2.2,1.4-.5,1.4-.5,0,0-.2-.5.5-.5s1.9.5,1.9.5c0,0,.7-.2.9-.7.2-.5-.2-.9,0-1.4.2-.5,0-1.6,0-1.6l-.7-1.6s-.9-.2-1.4-.2-1.2-.2-1.2-.2l-.5-.2-.9-.7h0s-2.3-.2-2.6.5c-.2.7-.7,1.6-.9,1.9-.2.2-1.9.9-1.9.9l1.4,1.4s.2.7,1.2,1.2c.9.5,2.3,1.4,2.3,1.4Z"/>
|
||||
<path class="cls-1" d="M121.1,719.9c-.3-.3-.7-.5-1.2-.5h0c-.6,0-1.1.6-1.2,1.2,0,.4.2.8.5,1.2.1.2.3.5.7.7.5.3,1.4.6,1.6.2.2-.2,0-.5-.2-1.6,0-.7,0-.9-.2-1.2Z"/>
|
||||
<path class="cls-1" d="M137.3,747.6c-.9-.5-1.9-.9-1.9-.9l-.5-1.2.9-1.2.2-2.3-4.2-.5-2.1.5h0s-1.2,2.1-1.4,2.6c-.2.5-2.1,1.9-2.1,2.1s0,.7-.2,1.4c-.2.7-.9,1.9,0,2.3.9.5,2.1.7,2.1.7,0,0,2.6-1.4,2.8-.7.2.7.2,1.2,1.2,1.9.9.7,2.1.9,2.3.9s.2-1.2.9-1.4c.7-.2,2.6-1.9,2.6-1.9,0,0,.2-1.9-.7-2.3Z"/>
|
||||
<path class="cls-1" d="M267.1,679.6s.5-.5,0-1.6c-.5-1.2-.7-2.1-.7-2.1l-.7-1.2-.5-1.4s-.5-.5-.2-1.2c.2-.7,0-2.6,0-2.6l-.2-.7.7-.9h0c.2-.2.5-2.1.5-2.1l-3.3-2.3s-1.4.9-1.2,1.9c.2.9.9,2.1.9,2.6s.2,1.6,0,2.1c-.2.5-.9,1.2-.9,1.4s-.7,1.4-.9,1.9c-.2.5-2.8,1.9-2.8,1.9,0,0-1.9,1.9-1.9,2.1s-1.2.2-.7,1.6c.5,1.4.5,3.3.5,3.3,0,0-1.2.9-.5,1.6.7.7,1.4,1.6,2.8,2.1,1.4.5,4.2,1.6,4.2,1.6l3.1.5s2.3-.9,1.9-1.4c-.5-.5-1.6-1.4-1.6-1.4l-.5-1.2s0-1.2.5-1.9,1.6-2.6,1.6-2.6Z"/>
|
||||
<polygon class="cls-1" points="279.4 600.4 279.4 586.1 272 579.9 262.7 571.1 261.3 561.5 254.5 559.9 251.7 557.3 244.7 562.9 243.5 566.9 235.1 563.3 234.4 553 235.1 535.7 240.9 533.6 245.9 532.1 247.1 523.8 256.9 510.3 248.3 507 239.9 515.4 232.7 509.4 238.7 493.8 231.6 486.6 229.2 475.8 217.2 472.2 206.4 484.2 205.2 493.8 195.7 486.6 186.1 495 186.1 502.2 176.5 510.6 159.8 515.4 157.4 523.8 140.6 521.4 127.4 517.8 124.5 512.7 119.4 508.3 115.3 512.5 110.2 512.4 96.4 517.8 89.3 530 84.4 535 85.6 538.3 88.3 540.1 87.2 541.1 82.3 539.9 76.8 551.3 72.3 553.6 67.3 564.8 76.6 566.5 73.6 571.4 75.3 574.4 80.6 583.9 85.4 585.9 85.4 589.7 80 596 78.4 589.4 69.9 588.5 68.8 590 71.3 593.4 75.4 595.9 74.3 598.4 69.7 600 68.7 603.3 63 605.4 61.9 611.5 67.8 615.5 70.4 613.1 73.2 605.9 74.3 613.6 75.3 626.5 69.7 634.5 69.7 639.2 68.1 643.4 67.8 644.3 80.4 650.4 92.7 661.4 89.3 661.9 86.5 659.8 85.6 664 79 654.2 69.4 650 67.8 656.3 70.6 661.9 74.3 663.3 77.1 670.4 72.7 669.9 66.1 661.5 62.9 648.1 58.5 642.1 51.9 654.2 55.1 668.3 59.6 674.6 61.9 673.9 65.8 676.6 67.1 680.5 69.9 680.2 72.7 677.9 79 686.6 77.7 698.2 82.8 699.7 79.7 706.7 76.6 709.9 77.4 712.1 82.5 712.8 82.7 721.2 93.1 719.9 97.3 713.3 97.1 709.8 112.1 701.6 110.7 695.9 117.2 694.3 120.8 688.2 120.2 673.4 122.8 671.1 124.7 675.1 124.5 684.5 122.4 694.3 125.7 699.9 130.4 702.1 134.8 704.2 136.9 700.4 143.5 702.3 145.8 697.6 149.1 698.3 148.3 688.6 152.1 687 152.9 684.2 151.7 682 155 673 162 671.1 167.4 666.2 174.9 662.4 179.6 664 183.8 662.6 187.1 655.8 192.4 654.7 194.6 657.2 202.1 657.2 202.7 663.8 200.6 669.2 196 669.8 194.8 663.8 189.6 664 187.5 671.6 189.1 675.6 185.9 681.9 181.9 681.2 183.1 676 181.4 674.3 176 692.2 189.2 694.5 191.7 701.4 195.5 706.3 203.9 704.4 207.4 697.8 213.3 694.1 214.2 689.9 209.3 687.1 210 684 218 684.7 221 686.6 224.2 683.9 222.7 674.6 209.2 661.4 209.5 657 212.8 653.7 210.5 650.9 215.4 646.2 211.9 643.7 213.5 642.5 216.5 642.5 222 642.5 227.6 640.4 228.1 635.9 230.9 638 231.2 641.7 231.8 647.4 236.2 650.7 238.4 657 234.6 663.8 232.6 672.3 234.9 676.9 238.7 676.9 243.5 679.8 244.5 675.1 243.3 671.1 245.9 662.9 249.9 659.4 255 664.1 261.6 661 262.3 655.8 265.1 651.9 267 645.5 264.6 642 261.1 642.5 257.9 642 248 646 246.3 642 239.9 634.6 244.2 626.8 246.3 631 251.6 632.8 262.5 623.5 278.8 628.6 285.4 617.2 285.4 607.6 279.4 600.4"/>
|
||||
</g>
|
||||
<g id="nakdong" data-label-shift="dx,dy">
|
||||
<path class="cls-1" d="M405.4,649.3l-2.1-.2-1.6,1.2-.9,1.6-1.2.2-.9-.5v-1.2l.2-.9,1.4-.9.9-.7v-.9l.9-.9.7-1.2-.2-1.6-.2-1.4.5-3v-1.9l-1.6-1.6-.9-.9.2-1.9.7-2.8h0c0,0,1.6-.5,1.6-.5,0,0,1.2-.9,1.2-1.2s.2-.7.2-.7l-.2-.9-1.4-.9-1.9-.7-1.6.2-1.2.5-.9,1.2-.7,1.2-.2,1.2.5,1.9v.9l-.5.7-.7.2-1.2.2-.9.5-.5.5-.2,1.2-.2.5h-1.4l-1.4.5s-.9.2-1.2.2-.7.7-.7.7l-1.2.5h-1.4c-.2,0-.7.2-.7.2l-.5.5v.5l.2.7s.7.7.9.7,0,.7,0,.7l.2.9v.7l.2.9.5.5.7.5s.5.5.7.5.2.7.2.7c0,0,.5.7.5.9v2.1h-.2s-.7-.2-.9-.2-.5-.5-.5-.5l-.9-.7h-.9l-.9-.5-.5-.7-.7-1.2-.7-.5-.5-.2-.5.2-.7.7-.7.2h-.9l-1.4-.9-1.4-.9-1.4-.7h-1.2l-.5.2-.7.9-.5.7-1.2.7s-.2,0-.5.2c-.2.2-.7.5-.7.5l-.5.7-.7,1.2-.5,1.2-.9.9v3.3l1.2,1.4s.7,1.4.7,1.6.2,1.4.2,1.4l.7,1.2.7,1.6,1.6.2,1.4-.9.7-1.2.7-.7h2.6l1.4-1.2.9-1.6.7-.9.7-.5.5.5.5.7v2.6s.5.5.7.5,0,.7,0,.7l-.7,1.2-1.2,1.9-.5.7-.2.5-.2.5-.9.5-1.2.2-1.4.2-.7.5-.5.5-.2.7,1.4.5.5.5v.7l.5.5.7.2h1.2l2.1.2.7.5.2.7-.2.5-.7.5s-.9.7-1.2.7-.5.9-.5.9l-.2.7.2.9v.7l.9.2.9.7,1.2.2v.9l-.2.2-.9.5-1.4.5-.7.2-.5.7v.9l.5.7s.5.5.7.5,1.4.2,1.4.2c0,0,1.4.2,1.6.2s.9-.5.9-.5l1.2-.5,1.2-.7.5-.7v-.7l.2-1.2s.5-.9.5-1.2.9-.5.9-.5l1.4-.2.2-.7-.9-.9-.7-1.4.5-1.6v-1.2l.7-.7,1.6-.2,1.6-.2.7-.9.2-1.2v-2.1l.7-.7,1.9.2,1.6-.2.5,2.1,1.2,1.4,2.1.9,1.6-.7.2-1.2-.2-1.2-1.6-1.2-.7-1.4.2-1.2-1.2-.7-.9-.9.5-1.4h1.9c.2,0,.7-.5.7-.5l.7-.9v-1.6h.9c.2,0,.7-.5.7-.5l.2-1.4s.2-.5.7-.7c.5-.2,0-1.4,0-1.4v-1.4Z"/>
|
||||
<path class="cls-1" d="M330.3,650.8v-1.2l-.9-.5h0s-4.2-1.2-4.2-.9-2.8,0-2.8,0l-1.4.9s-.2.7-.2.9.2,1.2.2,1.2l.5.2.9.7,2.8.5h1.9l.9-.7.9-.7.9-.2.5-.2Z"/>
|
||||
<polygon class="cls-1" points="333.8 654.8 332.6 654.1 332.2 652.9 331.7 652.7 331 652.9 329.8 653.9 329.6 654.8 329.1 656 329.1 657.6 329.4 659 329.8 659.7 330.8 659.7 331.9 659.5 332.4 659 333.8 659 335 658.8 335.2 657.8 335.2 656.9 334.7 655.7 333.8 654.8"/>
|
||||
<polygon class="cls-1" points="308 649.2 307.6 648.4 307.6 647.5 308 646.3 308.7 645.2 308.7 644.2 308.3 644 307.3 643.5 306.4 642.8 305.5 641.9 304.7 641.2 303.1 641.4 302.2 642.8 302.2 644.7 301.2 645.2 300.8 644.2 300.5 642.6 301 641.4 301.7 639.8 302.4 638.4 303.6 637.2 303.6 636.5 303.3 635.8 302.6 635.8 301 636 299.8 637 298.4 638.1 298.2 639.5 297.3 640 295.6 640.9 294.7 642.4 293.5 643.5 293.3 644.9 293.3 645.9 293.5 647 294.2 648.2 295.4 648.4 297 649.2 299.4 649.2 301.2 648.7 303.1 649.2 304.1 649.9 306.2 651 307.8 652 308.3 651.7 309.4 651.7 309.7 651 309.2 650.3 308 649.2"/>
|
||||
<path class="cls-1" d="M305.2,653.4l-1.2-.5-.9-.7-.7-.2h-2.1l-1.6-.2-.9-.7h-1.6l-1.2,1.2-1.6,1.2-.9.7v.7l-1.4-.2-.5-1.2-.9-1.4-.2-.7-.5-.9-1.2-.5-1.2-.5-.5-.5s-.2-.5-.2-.7-.2-1.2-.2-1.2v-.5c0-.2-.7-.7-.7-.7l-.2-.7-.5-1.2-.2-1.4.7-.9.2-.9,1.6-.2.7-.5.5-.2.2-.7.2-1.2.5-.5.7-.9v-.7l-.2-1.2-.5-1.4.2-1.4-2.1-1.4h-3.1l-1.9.2-1.4,1.2-.9,1.4-.5,1.2-.5,1.4v.7l-1.6.5-.9.5-.7.9s.2.5,0,.7c-.2.2-1.2.9-1.2.9v1.4l-.5,1.2-.7.5-.9.5-.2.9v1.4l.2,1.2-.2,1.4.5,1.6.5,1.9,1.2,1.9h0v1.6l.2,1.4.7.9.9.7.2.7-.2.7-.9.9-.9.7-.5.7-.2.7,1.2.7.7.5,1.4.7v.7l.2,1.2.5.9.9.5.9-.2h1.9l1.2-.2.9-.5.9-.9v-1.4l-.5-.9-.2-1.4.2-.7.7-.5,1.9-.2,1.2-.9h2.3l.5.9v.7s-.5.7-.5.9-.2,1.2-.2,1.2l-.5,1.4v.5l-.2.9.2.5.2.5.2,1.2v1.2l.5.9,2.1.2,2.3.7,1.6-.2,1.2.2.9-.7s.5.5.7.5.5.9.5.9l1.6.7,1.6.2h.7l.2-1.2-.2-1.4-.7-.7-.2-.9v-1.2l.5-.5.9-.9.7-.2.5-.5v-2.3s-.5-2.1-.5-2.3v-.9l.2-1.2.5-1.4s-.2-.9,0-.9.7-.7.7-.7l.7-.5.2-.9-.2-.9-1.2-.5Z"/>
|
||||
<polygon class="cls-1" points="533.7 451.9 529.9 457.3 516.8 465.7 509.4 457.5 516.6 447.7 513.8 417.3 513.1 408.8 521.3 392.4 522.9 355.1 523.6 353.3 531.1 333.9 526.2 315.4 526.2 282.1 519.8 263.8 504.8 272.7 495 281.2 482.8 272 481.1 259.2 471.4 254.5 473.3 244.6 468.7 245 455.3 248.2 454.9 259.5 454.7 274.8 451.4 277.9 438.9 269.7 434.5 277.6 421.1 273 410.9 275.3 403.3 283.3 392.8 288.8 386.2 300.5 389 306.9 377.6 314.7 353.5 310.3 345.4 307.2 340.7 310.3 334.5 310.7 330 319.5 334.6 326 329.8 328.1 325 323.7 307.5 329.5 314.2 336 312.9 341.5 306.5 336.4 294.4 343.5 303.6 349.6 308.1 357.5 304 362.7 314.1 371.6 316.5 383.6 314.1 388.4 326.1 392 323.3 402.6 325.2 414.4 315.5 413.8 315 423.6 307.5 439.1 298 443 298.5 447.6 301.2 454.4 296.8 462.5 286.2 472.3 276.7 473.4 269.4 480.7 267.1 483.1 264.5 485.8 256.9 505.2 256.9 510.3 247.1 523.8 245.9 532.1 240.9 533.6 235.1 535.7 234.4 553 235.1 563.3 243.5 566.9 244.7 562.9 251.7 557.3 254.5 559.9 261.3 561.5 262.7 571.1 272 579.9 279.4 586.1 279.4 600.4 285.4 607.6 285.4 617.2 278.8 628.6 282.6 628.4 288.8 622.6 289.3 620.3 291.9 621.5 292.3 624.3 296.3 623 298.7 624.3 301.6 622.6 298.9 615.9 301.2 614.9 303.4 615.5 304.7 611.2 309.9 609.7 307.1 614.2 306.9 625.2 305.5 632.3 314.8 637.2 317 641.5 318.3 642.1 322.4 640.3 325.1 641.7 326.8 641.4 329.4 634.9 335.5 635.5 338.5 640.5 342.8 638.4 346.2 633 347.4 636.3 348.6 639.8 343.1 642.3 344.4 645.9 349.4 647.4 351.4 645.9 353.5 647.7 353.3 655.5 347.7 654.1 346.2 655.7 351 659.7 353.7 666.6 356.3 667.8 358.7 665.9 359.9 659.7 358.5 655.6 361.6 654.2 365.6 646.5 363.1 643.5 360.7 647.8 358.5 646.8 361.3 632.3 361.1 630.7 361 629.5 368.3 628 371.4 624.3 365.9 619.1 357.2 620.8 355.4 623.6 351.9 624.1 354.8 618.5 361.5 616.3 367.3 614.4 366.1 610.6 379 609.8 381.7 611.6 383.5 619.4 389.9 616.8 383.5 596.4 387.2 591.5 388.9 592.4 387.7 599.2 390.1 604.4 394.7 605 398 608.8 399.5 604.8 401.5 606.5 400.5 612.2 406.2 614.7 414 613.3 414.9 615.6 420.1 616.2 424.6 617.3 428.8 614.1 432.5 616.6 438.5 610.1 436.6 622.3 438 626.7 441.3 625.8 442.5 620.6 445.7 622.8 453.5 612.9 457 616.4 461.6 616.6 461.7 613.8 459.8 610.5 463.1 606.6 469.9 608.2 480.9 594.4 480.7 591.3 485.5 581.8 491 579.8 494.6 576.1 498.5 573.7 497.1 571.8 499.6 567.6 499.9 561.3 498 558.2 504.1 554 504 546.1 505.5 548.8 506.9 554.5 511.6 551.2 514.6 544.4 514.4 537.4 515.8 532.7 513.9 528 514 525.4 524.7 493.4 527.1 486.2 527.8 477.8 535.1 466.5 538 455.6 533.7 451.9"/>
|
||||
</g>
|
||||
<g id="geum" data-label-shift="dx,dy">
|
||||
<path class="cls-1" d="M298,443l9.5-3.9,7.5-15.6.5-9.8,9.7.6-1.9-11.8,2.8-10.6-12-3.6,2.4-4.8-2.4-12-10.1-8.9-12.6-.6-8.4-10.8-16.3-1.1-7.6-19.2,17.5-7.4,2.3-2.4v-1.1c-.1,0,.4-1.3.4-1.3l-1.6-1.1.5-9.5,1.4-12.2-3.8-13-13.2-9.6-4.9-10-7.1-1.9-11.7,17.8-8.2,1.7-3,5.2-4.6,6.5-19.7,1.1-13.8-5.9-3.6.6-3.6,5.4h-1.2l-4.8-6-6.4-3.9-5-.2-9.1-18.5-5.4,3-2.4-5.7-11.4-2.8-11.7-9.2h-3.9c0,.1-3.4,4.8-3.4,4.8l1,6.2,2.1,5.4-1.2.8-4.4-7.5-6.7-3.2-6.3-.3-5.2,3.3,5.9,3.4-3.6,2.2,5.3,4.4,2.5.8.4,3-6.5,6.1-8.7,11.2-4-1.9,6.4-13.5-1.6-1.9,1.1-7.9-2.1-3-4.7,14.5-3,1.8-3.8-5.7-4.4,2.7.5,8.4-1.5,1.7-3.3-.8-4.2,3.2-5.1,13.8.5,1.5,3.9-.2.2-6.5,5.6,2.5,2.8,5.3-7.4,2.4v3c0,0,5.9,1.2,5.9,1.2l4.3-1.5,2.1-3.3,4-.3-1.4,6,4.1,3.7-2.4,9.4,4.3,6.1,1.1,27,11.6,2.1-6.6-26.7,2.3-4.1-6.3-4.9,1.7-1.9,1-6.9,2-1.5,2.2,9,4.4,3.2,3.1-1.9,3.1-6.1,1.8,1.5-1.9,8.6,2,14.4,1.9,13.7-2.8,6.5,8.2,7.8v2.1l-6.9,2.9,2.9,21.8-1.6,1.9-5.9,6.7,1.3,2.7,3.3-2.7,8.2,2.8,6.2,7.7-1.2,2.8,5.1,13.1,5.6,3.1-19.1.5-1.8,3.3,6.4,3.1-.6,10.7,7.3,2.8,3-3.3,8.9,1.9,9.4-3.4.3,1.4.2.9-3.1,5.4-5.1-.9-9.4,3.5,6.8,6.4,4.3,1.4-.2,5.6-20.6-5.8-6.4,13.7-18.1,10.4-1.9,6.6,5.9,4.7h19.9s3.8,4.2,3.8,4.2l-.5,3.4,3,5.1,13.2,3.6,16.8,2.4,2.4-8.4,16.8-4.8,9.6-8.4v-7.2l9.6-8.4,9.6,7.2,1.2-9.6,10.8-12,12,3.6,2.4,10.8,7.2,7.2-6,15.6,7.2,6,8.4-8.4,8.6,3.3v-5.1s7.6-19.4,7.6-19.4l12.2-12.4,9.6-1.1,10.5-9.8,4.5-8.1-2.7-6.8-.6-4.6Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 219 KiB |
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
||||
* Licensed under the LGPL or a commercial license.
|
||||
* For LGPL see License.txt in the project root for license information.
|
||||
* For commercial licenses see https://www.tiny.cloud/
|
||||
*/
|
||||
/**
|
||||
* Jquery integration plugin.
|
||||
*
|
||||
* @class tinymce.core.JqueryIntegration
|
||||
* @private
|
||||
*/
|
||||
!function(){function f(){
|
||||
// Reference to tinymce needs to be lazily evaluated since tinymce
|
||||
// might be loaded through the compressor or other means
|
||||
return d.tinymce}var p,c,u,s=[],d="undefined"!=typeof global?global:window,m=d.jQuery;m.fn.tinymce=function(o){var e,t,i,n,l=this,r="";
|
||||
// No match then just ignore the call
|
||||
return l.length?
|
||||
// Get editor instance
|
||||
o?(l.css("visibility","hidden"),
|
||||
// Load TinyMCE on demand, if we need to
|
||||
d.tinymce||c||!(e=o.script_url)?
|
||||
// Delay the init call until tinymce is loaded
|
||||
1===c?s.push(a):a():(c=1,t=e.substring(0,e.lastIndexOf("/")),
|
||||
// Check if it's a dev/src version they want to load then
|
||||
// make sure that all plugins, themes etc are loaded in source mode as well
|
||||
-1!=e.indexOf(".min")&&(r=".min"),
|
||||
// Setup tinyMCEPreInit object this will later be used by the TinyMCE
|
||||
// core script to locate other resources like CSS files, dialogs etc
|
||||
// You can also predefined a tinyMCEPreInit object and then it will use that instead
|
||||
d.tinymce=d.tinyMCEPreInit||{base:t,suffix:r},
|
||||
// url contains gzip then we assume it's a compressor
|
||||
-1!=e.indexOf("gzip")&&(i=o.language||"en",e=e+(/\?/.test(e)?"&":"?")+"js=true&core=true&suffix="+escape(r)+"&themes="+escape(o.theme||"modern")+"&plugins="+escape(o.plugins||"")+"&languages="+(i||""),
|
||||
// Check if compressor script is already loaded otherwise setup a basic one
|
||||
d.tinyMCE_GZ||(d.tinyMCE_GZ={start:function(){function n(e){f().ScriptLoader.markDone(f().baseURI.toAbsolute(e))}
|
||||
// Add core languages
|
||||
n("langs/"+i+".js"),
|
||||
// Add themes with languages
|
||||
n("themes/"+o.theme+"/theme"+r+".js"),n("themes/"+o.theme+"/langs/"+i+".js"),
|
||||
// Add plugins with languages
|
||||
m.each(o.plugins.split(","),function(e,t){t&&(n("plugins/"+t+"/plugin"+r+".js"),n("plugins/"+t+"/langs/"+i+".js"))})},end:function(){}})),(n=document.createElement("script")).type="text/javascript",n.onload=n.onreadystatechange=function(e){e=e||window.event,2===c||"load"!=e.type&&!/complete|loaded/.test(n.readyState)||(f().dom.Event.domLoaded=1,c=2,
|
||||
// Execute callback after mainscript has been loaded and before the initialization occurs
|
||||
o.script_loaded&&o.script_loaded(),a(),m.each(s,function(e,t){t()}))},n.src=e,document.body.appendChild(n)),l):f()?f().get(l[0].id):null:l;function a(){var a=[],c=0;
|
||||
// Apply patches to the jQuery object, only once
|
||||
u||(v(),u=!0),
|
||||
// Create an editor instance for each matched node
|
||||
l.each(function(e,t){var n,i=t.id,r=o.oninit;
|
||||
// Generate unique id for target element if needed
|
||||
i||(t.id=i=f().DOM.uniqueId()),
|
||||
// Only init the editor once
|
||||
f().get(i)||(
|
||||
// Create editor instance and render it
|
||||
n=f().createEditor(i,o),a.push(n),n.on("init",function(){var e,t=r;l.css("visibility",""),
|
||||
// Run this if the oninit setting is defined
|
||||
// this logic will fire the oninit callback ones each
|
||||
// matched editor instance is initialized
|
||||
r&&++c==a.length&&("string"==typeof t&&(e=-1===t.indexOf(".")?null:f().resolve(t.replace(/\.\w+$/,"")),t=f().resolve(t)),
|
||||
// Call the oninit function with the object
|
||||
t.apply(e||f(),a))}))}),
|
||||
// Render the editor instances in a separate loop since we
|
||||
// need to have the full editors array used in the onInit calls
|
||||
m.each(a,function(e,t){t.render()})}},
|
||||
// Add :tinymce pseudo selector this will select elements that has been converted into editor instances
|
||||
// it's now possible to use things like $('*:tinymce') to get all TinyMCE bound elements.
|
||||
m.extend(m.expr[":"],{tinymce:function(e){var t;return!!(e.id&&"tinymce"in d&&(t=f().get(e.id))&&t.editorManager===f())}});
|
||||
// This function patches internal jQuery functions so that if
|
||||
// you for example remove an div element containing an editor it's
|
||||
// automatically destroyed by the TinyMCE API
|
||||
var v=function(){function r(e){
|
||||
// If the function is remove
|
||||
"remove"===e&&this.each(function(e,t){var n=u(t);n&&n.remove()}),this.find("span.mceEditor,div.mceEditor").each(function(e,t){var n=f().get(t.id.replace(/_parent$/,""));n&&n.remove()})}function o(i){var e,t=this;
|
||||
// Handle set value
|
||||
/*jshint eqnull:true */if(null!=i)r.call(t),
|
||||
// Saves the contents before get/set value of textarea/div
|
||||
t.each(function(e,t){var n;(n=f().get(t.id))&&n.setContent(i)});else if(0<t.length&&(e=f().get(t[0].id)))return e.getContent()}function l(e){return e&&e.length&&d.tinymce&&e.is(":tinymce")}
|
||||
// Removes any child editor instances by looking for editor wrapper elements
|
||||
var u=function(e){var t=null;return e&&e.id&&d.tinymce?f().get(e.id):t},s={};
|
||||
// Loads or saves contents from/to textarea if the value
|
||||
// argument is defined it will set the TinyMCE internal contents
|
||||
// Patch some setter/getter functions these will
|
||||
// now be able to set/get the contents of editor instances for
|
||||
// example $('#editorid').html('Content'); will update the TinyMCE iframe instance
|
||||
m.each(["text","html","val"],function(e,t){var a=s[t]=m.fn[t],c="text"===t;m.fn[t]=function(e){var t=this;if(!l(t))return a.apply(t,arguments);if(e!==p)return o.call(t.filter(":tinymce"),e),a.apply(t.not(":tinymce"),arguments),t;// return original set for chaining
|
||||
var i="",r=arguments;return(c?t:t.eq(0)).each(function(e,t){var n=u(t);i+=n?c?n.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g,""):n.getContent({save:!0}):a.apply(m(t),r)}),i}}),
|
||||
// Makes it possible to use $('#id').append("content"); to append contents to the TinyMCE editor iframe
|
||||
m.each(["append","prepend"],function(e,t){var n=s[t]=m.fn[t],r="prepend"===t;m.fn[t]=function(i){var e=this;return l(e)?i!==p?("string"==typeof i&&e.filter(":tinymce").each(function(e,t){var n=u(t);n&&n.setContent(r?i+n.getContent():n.getContent()+i)}),n.apply(e.not(":tinymce"),arguments),e):void 0:n.apply(e,arguments)}}),
|
||||
// Makes sure that the editor instance gets properly destroyed when the parent element is removed
|
||||
m.each(["remove","replaceWith","replaceAll","empty"],function(e,t){var n=s[t]=m.fn[t];m.fn[t]=function(){return r.call(this,t),n.apply(this,arguments)}}),s.attr=m.fn.attr,
|
||||
// Makes sure that $('#tinymce_id').attr('value') gets the editors current HTML contents
|
||||
m.fn.attr=function(e,t){var n=this,i=arguments;if(!e||"value"!==e||!l(n))return s.attr.apply(n,i);if(t!==p)return o.call(n.filter(":tinymce"),t),s.attr.apply(n.not(":tinymce"),i),n;// return original set for chaining
|
||||
var r=n[0],a=u(r);return a?a.getContent({save:!0}):s.attr.apply(m(r),i)}}}();
|
||||
@@ -0,0 +1,3 @@
|
||||
This is where language files should be placed.
|
||||
|
||||
Please DO NOT translate these directly use this service: https://www.transifex.com/projects/p/tinymce/
|
||||
@@ -0,0 +1,504 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
||||
* Licensed under the LGPL or a commercial license.
|
||||
* For LGPL see License.txt in the project root for license information.
|
||||
* For commercial licenses see https://www.tiny.cloud/
|
||||
*
|
||||
* Version: 5.10.9 (2023-11-15)
|
||||
*/
|
||||
!function(){"use strict";function f(t,e,n){t.execCommand("UL"===e?"InsertUnorderedList":"InsertOrderedList",!1,!1===n?null:{"list-style-type":n})}function i(t){return function(){return t}}function t(t){return t}function e(){return s}var n=tinymce.util.Tools.resolve("tinymce.PluginManager"),g=tinymce.util.Tools.resolve("tinymce.util.Tools"),u=i(!1),l=i(!0),s={fold:function(t,e){return t()},isSome:u,isNone:l,getOr:t,getOrThunk:r,getOrDie:function(t){throw new Error(t||"error: getOrDie called on none.")},getOrNull:i(null),getOrUndefined:i(void 0),or:t,orThunk:r,map:e,each:function(){},bind:e,exists:u,forall:l,filter:function(){return s},toArray:function(){return[]},toString:i("none()")};function r(t){return t()}function d(t){return t&&/^(TH|TD)$/.test(t.nodeName)}function m(c,a){return function(s){function t(t){var e,n,r,o,i,u,l;s.setActive((e=c,r=a,i=-1!==(o=function(t,e){for(var n=0;n<t.length;n++)if(e(t[n]))return n;return-1}((n=t).parents,d))?n.parents.slice(0,o):n.parents,0<(u=g.grep(i,(l=e,function(t){return t&&/^(OL|UL|DL)$/.test(t.nodeName)&&(e=t,l.$.contains(l.getBody(),e));var e}))).length&&u[0].nodeName===r))}return c.on("NodeChange",t),function(){return c.off("NodeChange",t)}}}function c(t,e,n,r,o,i){var u,l,s,c,a,d;1<i.length?(c=r,a=o,d=i,(s=t).ui.registry.addSplitButton(e,{tooltip:n,icon:"OL"===a?"ordered-list":"unordered-list",presets:"listpreview",columns:3,fetch:function(t){t(g.map(d,function(t){return{type:"choiceitem",value:"default"===t?"":t,icon:"list-"+("OL"===a?"num":"bull")+"-"+("disc"===t||"decimal"===t?"default":t),text:t.replace(/\-/g," ").replace(/\b\w/g,function(t){return t.toUpperCase()})}}))},onAction:function(){return s.execCommand(c)},onItemAction:function(t,e){f(s,a,e)},select:function(e){var t,n=(t=s).dom.getParent(t.selection.getNode(),"ol,ul"),r=t.dom.getStyle(n,"listStyleType");return p(r).map(function(t){return e===t}).getOr(!1)},onSetup:m(s,a)})):(l=r,(u=t).ui.registry.addToggleButton(e,{active:!1,tooltip:n,icon:"OL"===o?"ordered-list":"unordered-list",onSetup:m(u,o),onAction:function(){return u.execCommand(l)}}))}var a=function(n){function t(){return o}function e(t){return t(n)}var r=i(n),o={fold:function(t,e){return e(n)},isSome:l,isNone:u,getOr:r,getOrThunk:r,getOrDie:r,getOrNull:r,getOrUndefined:r,or:t,orThunk:t,map:function(t){return a(t(n))},each:function(t){t(n)},bind:e,exists:e,forall:e,filter:function(t){return t(n)?o:s},toArray:function(){return[n]},toString:function(){return"some("+n+")"}};return o},p=function(t){return null==t?s:a(t)};n.add("advlist",function(t){var n,e,r,o;t.hasPlugin("lists")?(c(e=t,"numlist","Numbered list","InsertOrderedList","OL",(r=e.getParam("advlist_number_styles","default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman"))?r.split(/[ ,]/):[]),c(e,"bullist","Bullet list","InsertUnorderedList","UL",(o=e.getParam("advlist_bullet_styles","default,circle,square"))?o.split(/[ ,]/):[]),(n=t).addCommand("ApplyUnorderedListStyle",function(t,e){f(n,"UL",e["list-style-type"])}),n.addCommand("ApplyOrderedListStyle",function(t,e){f(n,"OL",e["list-style-type"])})):console.error("Please use the Lists plugin together with the Advanced List plugin.")})}();
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
||||
* Licensed under the LGPL or a commercial license.
|
||||
* For LGPL see License.txt in the project root for license information.
|
||||
* For commercial licenses see https://www.tiny.cloud/
|
||||
*
|
||||
* Version: 5.10.9 (2023-11-15)
|
||||
*/
|
||||
!function(){"use strict";function a(e){return e.getAttribute("id")||e.getAttribute("name")||""}function c(e){return e&&"a"===e.nodeName.toLowerCase()&&!e.getAttribute("href")&&""!==a(e)}function d(e){return e.dom.getParent(e.selection.getStart(),l)}function r(e,t){var o,a,n,r,i,l=d(e);l?(n=e,r=t,(i=l).removeAttribute("name"),i.id=r,n.addVisual(),n.undoManager.add()):(a=t,(o=e).undoManager.transact(function(){var e,n;o.getParam("allow_html_in_named_anchor",!1,"boolean")||o.selection.collapse(!0),o.selection.isCollapsed()?o.insertContent(o.dom.createHTML("a",{id:a})):(n=(e=o).dom,u(n).walk(e.selection.getRng(),function(e){s.each(e,function(e){var t;c(t=e)&&!t.firstChild&&n.remove(e,!1)})}),o.formatter.remove("namedAnchor",null,null,!0),o.formatter.apply("namedAnchor",{value:a}),o.addVisual())})),e.focus()}function i(r){return function(e){for(var t,n=0;n<e.length;n++){var o=e[n],a=void 0;!(a=t=o)||a.attr("href")||!a.attr("id")&&!a.attr("name")||t.firstChild||o.attr("contenteditable",r)}}}var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),u=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),s=tinymce.util.Tools.resolve("tinymce.util.Tools"),l="a:not([href])";e.add("anchor",function(e){var t,n,o;(t=e).on("PreInit",function(){t.parser.addNodeFilter("a",i("false")),t.serializer.addNodeFilter("a",i(null))}),(n=e).addCommand("mceAnchor",function(){var o,e,t;t=(e=d(o=n))?a(e):"",o.windowManager.open({title:"Anchor",size:"normal",body:{type:"panel",items:[{name:"id",type:"input",label:"ID",placeholder:"example"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{id:t},onSubmit:function(e){var t=o,n=e.getData().id;(/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(n)?(r(t,n),0):(t.windowManager.alert("Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."),1))||e.close()}})}),(o=e).ui.registry.addToggleButton("anchor",{icon:"bookmark",tooltip:"Anchor",onAction:function(){return o.execCommand("mceAnchor")},onSetup:function(e){return o.selection.selectorChangedWithUnbind("a:not([href])",e.setActive).unbind}}),o.ui.registry.addMenuItem("anchor",{icon:"bookmark",text:"Anchor...",onAction:function(){return o.execCommand("mceAnchor")}}),e.on("PreInit",function(){e.formatter.register("namedAnchor",{inline:"a",selector:l,remove:"all",split:!0,deep:!0,attributes:{id:"%value"},onmatch:c})})})}();
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
||||
* Licensed under the LGPL or a commercial license.
|
||||
* For LGPL see License.txt in the project root for license information.
|
||||
* For commercial licenses see https://www.tiny.cloud/
|
||||
*
|
||||
* Version: 5.10.9 (2023-11-15)
|
||||
*/
|
||||
!function(){"use strict";function k(e){return/^[(\[{ \u00a0]$/.test(e)}function w(e){return 3===e.nodeType}function i(e){return 1===e.nodeType}function o(e,t){var n;return t<0&&(t=0),!w(e)||(n=e.data.length)<t&&(t=n),t}function y(e,t,n){!i(t)||t.hasChildNodes()?e.setStart(t,o(t,n)):e.setStartBefore(t)}function v(e,t,n){!i(t)||t.hasChildNodes()?e.setEnd(t,o(t,n)):e.setEndAfter(t)}function r(e,t){var n,i,o,r,a,f=e.getParam("autolink_pattern",A),s=e.getParam("default_link_target",!1);if(null===e.dom.getParent(e.selection.getNode(),"a[href]")){var d=e.selection.getRng().cloneRange();if(d.startOffset<5){if(!(r=d.endContainer.previousSibling)){if(!d.endContainer.firstChild||!d.endContainer.firstChild.nextSibling)return;r=d.endContainer.firstChild.nextSibling}if(y(d,r,a=r.length),v(d,r,a),d.endOffset<5)return;n=d.endOffset,i=r}else{if(!w(i=d.endContainer)&&i.firstChild){for(;!w(i)&&i.firstChild;)i=i.firstChild;w(i)&&(y(d,i,0),v(d,i,i.nodeValue.length))}n=1===d.endOffset?2:d.endOffset-1-t}for(var l=n;y(d,i,2<=n?n-2:0),v(d,i,1<=n?n-1:0),--n,!k(d.toString())&&0<=n-2;);k(d.toString())?(y(d,i,n),v(d,i,l),n+=1):(0===d.startOffset?y(d,i,0):y(d,i,n),v(d,i,l)),u=d.toString(),/[?!,.;:]/.test(u.charAt(u.length-1))&&v(d,i,l-1);var u,c,g,h,C=(u=d.toString().trim()).match(f),m=e.getParam("link_default_protocol","http","string");C&&((g=c=C[0]).length>=(h="www.").length&&g.substr(0,0+h.length)===h?c=m+"://"+c:-1===c.indexOf("@")||/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(c)||(c="mailto:"+c),o=e.selection.getBookmark(),e.selection.setRng(d),e.execCommand("createlink",!1,c),!1!==s&&e.dom.setAttrib(e.selection.getNode(),"target",s),e.selection.moveToBookmark(o),e.nodeChanged())}}var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.Env"),A=new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i");e.add("autolink",function(e){var t,n;(t=e).on("keydown",function(e){if(13===e.keyCode)return r(t,-1)}),a.browser.isIE()?t.on("focus",function(){if(!n){n=!0;try{t.execCommand("AutoUrlDetect",!1,!0)}catch(e){}}}):(t.on("keypress",function(e){if(41===e.keyCode||93===e.keyCode||125===e.keyCode)return r(t,-1)}),t.on("keyup",function(e){if(32===e.keyCode)return r(t,0)}))})}();
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
||||
* Licensed under the LGPL or a commercial license.
|
||||
* For LGPL see License.txt in the project root for license information.
|
||||
* For commercial licenses see https://www.tiny.cloud/
|
||||
*
|
||||
* Version: 5.10.9 (2023-11-15)
|
||||
*/
|
||||
!function(){"use strict";function y(e){return e.getParam("min_height",e.getElement().offsetHeight,"number")}function p(e,t){var n=e.getBody();n&&(n.style.overflowY=t?"":"hidden",t||(n.scrollTop=0))}function v(e,t,n,i){var o=parseInt(e.getStyle(t,n,i),10);return isNaN(o)?0:o}var l=Object.hasOwnProperty,e=tinymce.util.Tools.resolve("tinymce.PluginManager"),b=tinymce.util.Tools.resolve("tinymce.Env"),r=tinymce.util.Tools.resolve("tinymce.util.Delay"),u=function(e,t,n,i,o){r.setEditorTimeout(e,function(){C(e,t),n--?u(e,t,n,i,o):o&&o()},i)},C=function(e,t,n){var i,o,r,s,a,l,u,g,c,m,f,d=e.dom,h=e.getDoc();h&&(e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen()?p(e,!0):(i=h.documentElement,o=e.getParam("autoresize_bottom_margin",50,"number"),r=y(e),s=v(d,i,"margin-top",!0),a=v(d,i,"margin-bottom",!0),(l=(l=i.offsetHeight+s+a+o)<0?0:l)+(u=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight)>y(e)&&(r=l+u),(g=e.getParam("max_height",0,"number"))&&g<r?(r=g,p(e,!0)):p(e,!1),r!==t.get()&&(c=r-t.get(),d.setStyle(e.getContainer(),"height",r+"px"),t.set(r),e.fire("ResizeEditor"),b.browser.isSafari()&&b.mac&&(m=e.getWin()).scrollTo(m.pageXOffset,m.pageYOffset),!e.hasFocus()||"setcontent"!==(null==(f=n)?void 0:f.type.toLowerCase())||!0!==f.selection&&!0!==f.paste||e.selection.scrollIntoView(),b.webkit&&c<0&&C(e,t,n))))};e.add("autoresize",function(e){var t,n,i,o,r,s,a=e.settings;l.call(a,"resize")||(e.settings.resize=!1),e.inline||(s=0,r=t={get:function(){return s},set:function(e){s=e}},(o=e).addCommand("mceAutoResize",function(){C(o,r)}),i=t,(n=e).on("init",function(){var e=n.getParam("autoresize_overflow_padding",1,"number"),t=n.dom;t.setStyles(n.getDoc().documentElement,{height:"auto"}),t.setStyles(n.getBody(),{paddingLeft:e,paddingRight:e,"min-height":0})}),n.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",function(e){C(n,i,e)}),n.getParam("autoresize_on_init",!0,"boolean")&&n.on("init",function(){u(n,i,20,100,function(){u(n,i,5,1e3)})}))})}();
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
||||
* Licensed under the LGPL or a commercial license.
|
||||
* For LGPL see License.txt in the project root for license information.
|
||||
* For commercial licenses see https://www.tiny.cloud/
|
||||
*
|
||||
* Version: 5.10.9 (2023-11-15)
|
||||
*/
|
||||
!function(){"use strict";function o(t,e){var r=t||e,n=/^(\d+)([ms]?)$/.exec(""+r);return(n[2]?{s:1e3,m:6e4}[n[2]]:1)*parseInt(r,10)}function n(t){var e=document.location;return t.getParam("autosave_prefix","tinymce-autosave-{path}{query}{hash}-{id}-").replace(/{path}/g,e.pathname).replace(/{query}/g,e.search).replace(/{hash}/g,e.hash).replace(/{id}/g,t.id)}function i(t,e){if(a(e))return t.dom.isEmpty(t.getBody());var r=d.trim(e);if(""===r)return!0;var n=(new DOMParser).parseFromString(r,"text/html");return t.dom.isEmpty(n)}function u(t){var e=parseInt(v.getItem(n(t)+"time"),10)||0;return!((new Date).getTime()-e>o(t.getParam("autosave_retention"),"20m")&&(g(t,!1),1))}function s(t){var e=n(t);!i(t)&&t.isDirty()&&(v.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),v.setItem(e+"time",(new Date).getTime().toString()),t.fire("StoreDraft"))}function f(t){var e=n(t);u(t)&&(t.setContent(v.getItem(e+"draft"),{format:"raw"}),t.fire("RestoreDraft"))}function c(t){t.undoManager.transact(function(){f(t),g(t)}),t.focus()}function m(r){return function(t){function e(){return t.setDisabled(!u(r))}return t.setDisabled(!u(r)),r.on("StoreDraft RestoreDraft RemoveDraft",e),function(){return r.off("StoreDraft RestoreDraft RemoveDraft",e)}}}var t=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=function(t){return void 0===t},l=tinymce.util.Tools.resolve("tinymce.util.Delay"),v=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),d=tinymce.util.Tools.resolve("tinymce.util.Tools"),g=function(t,e){var r=n(t);v.removeItem(r+"draft"),v.removeItem(r+"time"),!1!==e&&t.fire("RemoveDraft")},y=tinymce.util.Tools.resolve("tinymce.EditorManager");t.add("autosave",function(t){var e,r,n,a;return t.editorManager.on("BeforeUnload",function(t){var e;d.each(y.get(),function(t){t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&t.getParam("autosave_ask_before_unload",!0)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))}),e&&(t.preventDefault(),t.returnValue=e)}),n=e=t,a=o(n.getParam("autosave_interval"),"30s"),l.setEditorInterval(n,function(){s(n)},a),e.ui.registry.addButton("restoredraft",{tooltip:"Restore last draft",icon:"restore-draft",onAction:function(){c(e)},onSetup:m(e)}),e.ui.registry.addMenuItem("restoredraft",{text:"Restore last draft",icon:"restore-draft",onAction:function(){c(e)},onSetup:m(e)}),t.on("init",function(){t.getParam("autosave_restore_when_empty",!1)&&t.dom.isEmpty(t.getBody())&&f(t)}),r=t,{hasDraft:function(){return u(r)},storeDraft:function(){return s(r)},restoreDraft:function(){return f(r)},removeDraft:function(t){return g(r,t)},isEmpty:function(t){return i(r,t)}}})}();
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
||||
* Licensed under the LGPL or a commercial license.
|
||||
* For LGPL see License.txt in the project root for license information.
|
||||
* For commercial licenses see https://www.tiny.cloud/
|
||||
*
|
||||
* Version: 5.10.9 (2023-11-15)
|
||||
*/
|
||||
!function(){"use strict";function i(t){function o(o,e){t=t.replace(o,e)}return t=n.trim(t),o(/\n/gi,"<br />"),o(/\[b\]/gi,"<strong>"),o(/\[\/b\]/gi,"</strong>"),o(/\[i\]/gi,"<em>"),o(/\[\/i\]/gi,"</em>"),o(/\[u\]/gi,"<u>"),o(/\[\/u\]/gi,"</u>"),o(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,'<a href="$1">$2</a>'),o(/\[url\](.*?)\[\/url\]/gi,'<a href="$1">$1</a>'),o(/\[img\](.*?)\[\/img\]/gi,'<img src="$1" />'),o(/\[color=(.*?)\](.*?)\[\/color\]/gi,'<font color="$1">$2</font>'),o(/\[code\](.*?)\[\/code\]/gi,'<span class="codeStyle">$1</span> '),o(/\[quote.*?\](.*?)\[\/quote\]/gi,'<span class="quoteStyle">$1</span> '),t}var o=tinymce.util.Tools.resolve("tinymce.PluginManager"),n=tinymce.util.Tools.resolve("tinymce.util.Tools");o.add("bbcode",function(o){o.on("BeforeSetContent",function(o){o.content=i(o.content)}),o.on("PostProcess",function(o){function e(o,e){t=t.replace(o,e)}var t;o.set&&(o.content=i(o.content)),o.get&&(o.content=(t=o.content,t=n.trim(t),e(/<a.*?href=\"(.*?)\".*?>(.*?)<\/a>/gi,"[url=$1]$2[/url]"),e(/<font.*?color=\"(.*?)\".*?class=\"codeStyle\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),e(/<font.*?color=\"(.*?)\".*?class=\"quoteStyle\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),e(/<font.*?class=\"codeStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),e(/<font.*?class=\"quoteStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),e(/<span style=\"color: ?(.*?);\">(.*?)<\/span>/gi,"[color=$1]$2[/color]"),e(/<font.*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[color=$1]$2[/color]"),e(/<span style=\"font-size:(.*?);\">(.*?)<\/span>/gi,"[size=$1]$2[/size]"),e(/<font>(.*?)<\/font>/gi,"$1"),e(/<img.*?src=\"(.*?)\".*?\/>/gi,"[img]$1[/img]"),e(/<span class=\"codeStyle\">(.*?)<\/span>/gi,"[code]$1[/code]"),e(/<span class=\"quoteStyle\">(.*?)<\/span>/gi,"[quote]$1[/quote]"),e(/<strong class=\"codeStyle\">(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]"),e(/<strong class=\"quoteStyle\">(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]"),e(/<em class=\"codeStyle\">(.*?)<\/em>/gi,"[code][i]$1[/i][/code]"),e(/<em class=\"quoteStyle\">(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]"),e(/<u class=\"codeStyle\">(.*?)<\/u>/gi,"[code][u]$1[/u][/code]"),e(/<u class=\"quoteStyle\">(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]"),e(/<\/(strong|b)>/gi,"[/b]"),e(/<(strong|b)>/gi,"[b]"),e(/<\/(em|i)>/gi,"[/i]"),e(/<(em|i)>/gi,"[i]"),e(/<\/u>/gi,"[/u]"),e(/<span style=\"text-decoration: ?underline;\">(.*?)<\/span>/gi,"[u]$1[/u]"),e(/<u>/gi,"[u]"),e(/<blockquote[^>]*>/gi,"[quote]"),e(/<\/blockquote>/gi,"[/quote]"),e(/<br \/>/gi,"\n"),e(/<br\/>/gi,"\n"),e(/<br>/gi,"\n"),e(/<p>/gi,""),e(/<\/p>/gi,"\n"),e(/ |\u00a0/gi," "),e(/"/gi,'"'),e(/</gi,"<"),e(/>/gi,">"),e(/&/gi,"&"),t))})})}();
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
||||
* Licensed under the LGPL or a commercial license.
|
||||
* For LGPL see License.txt in the project root for license information.
|
||||
* For commercial licenses see https://www.tiny.cloud/
|
||||
*
|
||||
* Version: 5.10.9 (2023-11-15)
|
||||
*/
|
||||
!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",function(e){var t,o;function n(){return o.execCommand("mceCodeEditor")}return(t=e).addCommand("mceCodeEditor",function(){var n,e;e=(n=t).getContent({source_view:!0}),n.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:e},onSubmit:function(e){var t=n,o=e.getData().code;t.focus(),t.undoManager.transact(function(){t.setContent(o)}),t.selection.setCursorLocation(),t.nodeChanged(),e.close()}})}),(o=e).ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:n}),o.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:n}),{}})}();
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
||||
* Licensed under the LGPL or a commercial license.
|
||||
* For LGPL see License.txt in the project root for license information.
|
||||
* For commercial licenses see https://www.tiny.cloud/
|
||||
*
|
||||
* Version: 5.10.9 (2023-11-15)
|
||||
*/
|
||||
!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("colorpicker",function(){})}();
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
||||
* Licensed under the LGPL or a commercial license.
|
||||
* For LGPL see License.txt in the project root for license information.
|
||||
* For commercial licenses see https://www.tiny.cloud/
|
||||
*
|
||||
* Version: 5.10.9 (2023-11-15)
|
||||
*/
|
||||
!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("contextmenu",function(){})}();
|
||||