openfree commited on
Commit
39c116d
ยท
verified ยท
1 Parent(s): 2d96d6a

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +528 -92
index.html CHANGED
@@ -388,7 +388,7 @@
388
 
389
  .option-card {
390
  background: rgba(255, 255, 255, 0.05);
391
- border: 1px solid rgba(255, 255, 255, 0.2);
392
  border-radius: 10px;
393
  padding: 1rem;
394
  cursor: pointer;
@@ -398,14 +398,32 @@
398
  }
399
 
400
  .option-card.selected {
401
- background: rgba(58, 123, 213, 0.2);
402
  border-color: #3a7bd5;
403
  transform: scale(1.05);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  }
405
 
406
  .option-card:hover {
407
  border-color: #00d2ff;
408
  background: rgba(255, 255, 255, 0.1);
 
409
  }
410
 
411
  .option-name {
@@ -428,6 +446,38 @@
428
  display: none;
429
  }
430
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
431
  .custom-summary {
432
  display: grid;
433
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
@@ -456,10 +506,12 @@
456
  background: rgba(255, 255, 255, 0.05);
457
  border-radius: 10px;
458
  padding: 1.5rem;
 
459
  }
460
 
461
  .selected-components h4 {
462
  margin-bottom: 1rem;
 
463
  }
464
 
465
  .component-list {
@@ -470,8 +522,73 @@
470
  .component-list-item {
471
  display: flex;
472
  justify-content: space-between;
473
- padding: 0.5rem 0;
474
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  }
476
 
477
  @keyframes fadeInDown {
@@ -729,59 +846,59 @@
729
  <div class="component-section">
730
  <div class="component-title">
731
  <div class="component-icon">๐ŸŽฏ</div>
732
- <span>ํƒ€๊นƒ ์„œ๋น„์Šค ์œ ํ˜•</span>
733
  </div>
734
  <div class="component-options">
735
- <div class="option-card" onclick="selectOption('service', 'image-gen', 30, 2)">
736
  <div class="option-name">์ด๋ฏธ์ง€ ์ƒ์„ฑ</div>
737
  <div class="option-details">
738
  <span>โ‚ฉ30M</span>
739
  <span>2๊ฐœ์›”</span>
740
  </div>
741
  </div>
742
- <div class="option-card" onclick="selectOption('service', 'image-edit', 35, 2.5)">
743
  <div class="option-name">์ด๋ฏธ์ง€ ํŽธ์ง‘/ํ•ฉ์„ฑ</div>
744
  <div class="option-details">
745
  <span>โ‚ฉ35M</span>
746
  <span>2.5๊ฐœ์›”</span>
747
  </div>
748
  </div>
749
- <div class="option-card" onclick="selectOption('service', 'video-gen', 50, 3)">
750
  <div class="option-name">๋น„๋””์˜ค ์ƒ์„ฑ</div>
751
  <div class="option-details">
752
  <span>โ‚ฉ50M</span>
753
  <span>3๊ฐœ์›”</span>
754
  </div>
755
  </div>
756
- <div class="option-card" onclick="selectOption('service', 'music-gen', 40, 2.5)">
757
  <div class="option-name">์Œ์•… ๋ฐ ์Œํ–ฅ ์ƒ์„ฑ</div>
758
  <div class="option-details">
759
  <span>โ‚ฉ40M</span>
760
  <span>2.5๊ฐœ์›”</span>
761
  </div>
762
  </div>
763
- <div class="option-card" onclick="selectOption('service', 'text-chat', 20, 1.5)">
764
  <div class="option-name">ํ…์ŠคํŠธ ์ƒ์„ฑ(์ฑ—๋ด‡)</div>
765
  <div class="option-details">
766
  <span>โ‚ฉ20M</span>
767
  <span>1.5๊ฐœ์›”</span>
768
  </div>
769
  </div>
770
- <div class="option-card" onclick="selectOption('service', 'text-expert', 25, 2)">
771
  <div class="option-name">ํ…์ŠคํŠธ ์ƒ์„ฑ(์ „๋ฌธ๊ฐ€)</div>
772
  <div class="option-details">
773
  <span>โ‚ฉ25M</span>
774
  <span>2๊ฐœ์›”</span>
775
  </div>
776
  </div>
777
- <div class="option-card" onclick="selectOption('service', 'voice-clone', 45, 2.5)">
778
  <div class="option-name">์Œ์„ฑ ๋ณต์ œ/์ƒ์„ฑ</div>
779
  <div class="option-details">
780
  <span>โ‚ฉ45M</span>
781
  <span>2.5๊ฐœ์›”</span>
782
  </div>
783
  </div>
784
- <div class="option-card" onclick="selectOption('service', 'vision-ai', 35, 2)">
785
  <div class="option-name">๋น„์ „ ์ธ์‹</div>
786
  <div class="option-details">
787
  <span>โ‚ฉ35M</span>
@@ -798,21 +915,21 @@
798
  <span>DB ๊ด€๋ฆฌ</span>
799
  </div>
800
  <div class="component-options">
801
- <div class="option-card" onclick="selectOption('db', 'basic-db', 5, 0.5)">
802
  <div class="option-name">๊ธฐ๋ณธ DB</div>
803
  <div class="option-details">
804
  <span>โ‚ฉ5M</span>
805
  <span>0.5๊ฐœ์›”</span>
806
  </div>
807
  </div>
808
- <div class="option-card" onclick="selectOption('db', 'advanced-db', 15, 1)">
809
  <div class="option-name">๊ณ ๊ธ‰ DB + ๋ฐฑ์—…</div>
810
  <div class="option-details">
811
  <span>โ‚ฉ15M</span>
812
  <span>1๊ฐœ์›”</span>
813
  </div>
814
  </div>
815
- <div class="option-card" onclick="selectOption('db', 'enterprise-db', 25, 1.5)">
816
  <div class="option-name">์—”ํ„ฐํ”„๋ผ์ด์ฆˆ DB</div>
817
  <div class="option-details">
818
  <span>โ‚ฉ25M</span>
@@ -829,21 +946,21 @@
829
  <span>ํšŒ์›๊ฐ€์ž… ๋ฐ ๋กœ๊ทธ์ธ</span>
830
  </div>
831
  <div class="component-options">
832
- <div class="option-card" onclick="selectOption('auth', 'gmail-only', 3, 0.3)">
833
  <div class="option-name">Gmail ์—ฐ๋™</div>
834
  <div class="option-details">
835
  <span>โ‚ฉ3M</span>
836
  <span>0.3๊ฐœ์›”</span>
837
  </div>
838
  </div>
839
- <div class="option-card" onclick="selectOption('auth', 'multi-auth', 8, 0.5)">
840
  <div class="option-name">๋‹ค์ค‘ ์†Œ์…œ ๋กœ๊ทธ์ธ</div>
841
  <div class="option-details">
842
  <span>โ‚ฉ8M</span>
843
  <span>0.5๊ฐœ์›”</span>
844
  </div>
845
  </div>
846
- <div class="option-card" onclick="selectOption('auth', 'custom-auth', 12, 1)">
847
  <div class="option-name">์ปค์Šคํ…€ ์ธ์ฆ ์‹œ์Šคํ…œ</div>
848
  <div class="option-details">
849
  <span>โ‚ฉ12M</span>
@@ -860,14 +977,14 @@
860
  <span>ํฌ๋ ˆ๋”ง ๊ด€๋ฆฌ</span>
861
  </div>
862
  <div class="component-options">
863
- <div class="option-card" onclick="selectOption('credit', 'basic-credit', 5, 0.5)">
864
  <div class="option-name">๊ธฐ๋ณธ ํฌ๋ ˆ๋”ง ์‹œ์Šคํ…œ</div>
865
  <div class="option-details">
866
  <span>โ‚ฉ5M</span>
867
  <span>0.5๊ฐœ์›”</span>
868
  </div>
869
  </div>
870
- <div class="option-card" onclick="selectOption('credit', 'advanced-credit', 12, 1)">
871
  <div class="option-name">๊ณ ๊ธ‰ ํฌ๋ ˆ๋”ง + ๊ตฌ๋…</div>
872
  <div class="option-details">
873
  <span>โ‚ฉ12M</span>
@@ -884,21 +1001,21 @@
884
  <span>ํŽ˜์ด๋จผํŠธ ์ง€์›</span>
885
  </div>
886
  <div class="component-options">
887
- <div class="option-card" onclick="selectOption('payment', 'basic-payment', 8, 0.5)">
888
  <div class="option-name">๊ธฐ๋ณธ ๊ฒฐ์ œ (์นด๋“œ)</div>
889
  <div class="option-details">
890
  <span>โ‚ฉ8M</span>
891
  <span>0.5๊ฐœ์›”</span>
892
  </div>
893
  </div>
894
- <div class="option-card" onclick="selectOption('payment', 'multi-payment', 15, 1)">
895
  <div class="option-name">๋‹ค์ค‘ ๊ฒฐ์ œ ์ˆ˜๋‹จ</div>
896
  <div class="option-details">
897
  <span>โ‚ฉ15M</span>
898
  <span>1๊ฐœ์›”</span>
899
  </div>
900
  </div>
901
- <div class="option-card" onclick="selectOption('payment', 'global-payment', 20, 1.5)">
902
  <div class="option-name">๊ธ€๋กœ๋ฒŒ ๊ฒฐ์ œ ์‹œ์Šคํ…œ</div>
903
  <div class="option-details">
904
  <span>โ‚ฉ20M</span>
@@ -915,14 +1032,14 @@
915
  <span>๋งˆ์ผ€ํŒ… ์ง€์›</span>
916
  </div>
917
  <div class="component-options">
918
- <div class="option-card" onclick="selectOption('marketing', 'basic-marketing', 10, 1)">
919
  <div class="option-name">๊ธฐ๋ณธ ๋งˆ์ผ€ํŒ… ๋„๊ตฌ</div>
920
  <div class="option-details">
921
  <span>โ‚ฉ10M</span>
922
  <span>1๊ฐœ์›”</span>
923
  </div>
924
  </div>
925
- <div class="option-card" onclick="selectOption('marketing', 'advanced-marketing', 20, 1.5)">
926
  <div class="option-name">๊ณ ๊ธ‰ ๋งˆ์ผ€ํŒ… ์ž๋™ํ™”</div>
927
  <div class="option-details">
928
  <span>โ‚ฉ20M</span>
@@ -939,14 +1056,14 @@
939
  <span>๊ฐœ๋ฐœ ๋ฐ ๊ธฐ์ˆ  ์ธ๋ ฅ ์ง€์›</span>
940
  </div>
941
  <div class="component-options">
942
- <div class="option-card" onclick="selectOption('support', 'basic-support', 5, 0)">
943
  <div class="option-name">๊ธฐ๋ณธ ๊ธฐ์ˆ  ์ง€์›</div>
944
  <div class="option-details">
945
  <span>์›” โ‚ฉ5M</span>
946
  <span>์ฆ‰์‹œ</span>
947
  </div>
948
  </div>
949
- <div class="option-card" onclick="selectOption('support', 'dedicated-support', 15, 0)">
950
  <div class="option-name">์ „๋‹ด ๊ฐœ๋ฐœ์ž ์ง€์›</div>
951
  <div class="option-details">
952
  <span>์›” โ‚ฉ15M</span>
@@ -963,14 +1080,14 @@
963
  <span>์›๊ฒฉ ๋ชจ๋‹ˆํ„ฐ๋ง ์ง€์›</span>
964
  </div>
965
  <div class="component-options">
966
- <div class="option-card" onclick="selectOption('monitoring', 'basic-monitor', 3, 0.3)">
967
  <div class="option-name">๊ธฐ๋ณธ ๋ชจ๋‹ˆํ„ฐ๋ง</div>
968
  <div class="option-details">
969
  <span>โ‚ฉ3M</span>
970
  <span>0.3๊ฐœ์›”</span>
971
  </div>
972
  </div>
973
- <div class="option-card" onclick="selectOption('monitoring', 'advanced-monitor', 8, 0.5)">
974
  <div class="option-name">๊ณ ๊ธ‰ ๋ถ„์„ + ์•Œ๋ฆผ</div>
975
  <div class="option-details">
976
  <span>โ‚ฉ8M</span>
@@ -980,27 +1097,108 @@
980
  </div>
981
  </div>
982
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
983
  <button class="calculate-btn" onclick="calculateCustomCost()">๋งž์ถค ๊ฒฌ์  ๊ณ„์‚ฐํ•˜๊ธฐ</button>
984
 
985
  <div class="custom-result" id="customResult">
 
 
 
 
 
 
 
 
 
 
 
986
  <div class="custom-summary">
987
  <div class="summary-item">
988
- <div class="summary-label">์ด ๊ฐœ๋ฐœ ๋น„์šฉ</div>
989
- <div class="summary-value" id="totalCost">โ‚ฉ0</div>
990
  </div>
991
  <div class="summary-item">
992
  <div class="summary-label">์˜ˆ์ƒ ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„</div>
993
- <div class="summary-value" id="totalTime">0๊ฐœ์›”</div>
994
  </div>
995
  <div class="summary-item">
996
- <div class="summary-label">์›” ์šด์˜ ๋น„์šฉ</div>
997
- <div class="summary-value" id="monthlyCost">โ‚ฉ0</div>
998
  </div>
999
  </div>
 
1000
  <div class="selected-components">
1001
- <h4>์„ ํƒํ•œ ๊ตฌ์„ฑ ์š”์†Œ</h4>
1002
  <div class="component-list" id="componentList"></div>
1003
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1004
  </div>
1005
  </div>
1006
  </div>
@@ -1009,103 +1207,257 @@
1009
  <script>
1010
  let costChart = null;
1011
  let selectedComponents = {};
 
1012
 
 
1013
  function switchTab(tabName) {
1014
- // ๋ชจ๏ฟฝ๏ฟฝ๏ฟฝ ํƒญ ๋‚ด์šฉ ์ˆจ๊ธฐ๊ธฐ
1015
  document.querySelectorAll('.tab-content').forEach(content => {
1016
  content.classList.remove('active');
1017
  });
1018
 
1019
- // ๋ชจ๋“  ํƒญ ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑํ™”
1020
  document.querySelectorAll('.tab').forEach(tab => {
1021
  tab.classList.remove('active');
1022
  });
1023
 
1024
- // ์„ ํƒํ•œ ํƒญ ํ™œ์„ฑํ™”
1025
  document.getElementById(tabName).classList.add('active');
1026
  event.target.classList.add('active');
1027
  }
1028
 
1029
- function selectOption(category, optionId, cost, time) {
1030
- // ์ด์ „ ์„ ํƒ ์ œ๊ฑฐ
1031
- document.querySelectorAll(`.component-section:has(.component-title:has(.component-icon:contains('${getCategoryIcon(category)}'))) .option-card`).forEach(card => {
1032
- card.classList.remove('selected');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1033
  });
1034
-
1035
- // ์ƒˆ ์„ ํƒ ์ถ”๊ฐ€
1036
- event.currentTarget.classList.add('selected');
1037
-
1038
- // ์„ ํƒ ์ •๋ณด ์ €์žฅ
1039
- selectedComponents[category] = {
1040
- id: optionId,
1041
- name: event.currentTarget.querySelector('.option-name').textContent,
1042
- cost: cost,
1043
- time: time
1044
- };
1045
- }
1046
 
1047
- function getCategoryIcon(category) {
1048
- const icons = {
1049
- 'service': '๐ŸŽฏ',
1050
- 'db': '๐Ÿ’พ',
1051
- 'auth': '๐Ÿ”',
1052
- 'credit': '๐Ÿ’ฐ',
1053
- 'payment': '๐Ÿ’ณ',
1054
- 'marketing': '๐Ÿ“ข',
1055
- 'support': '๐Ÿ‘จโ€๐Ÿ’ป',
1056
- 'monitoring': '๐Ÿ“Š'
1057
- };
1058
- return icons[category];
1059
  }
1060
 
 
1061
  function calculateCustomCost() {
1062
- if (Object.keys(selectedComponents).length === 0) {
1063
- alert('๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์„ ํƒํ•ด์ฃผ์„ธ์š”.');
 
1064
  return;
1065
  }
1066
 
1067
- let totalCost = 0;
1068
- let totalTime = 0;
1069
- let monthlyCost = 0;
 
 
 
 
 
 
1070
  let componentListHTML = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1071
 
 
1072
  Object.values(selectedComponents).forEach(component => {
1073
- totalCost += component.cost;
1074
- totalTime = Math.max(totalTime, component.time);
1075
-
1076
- // ์›” ์šด์˜ ๋น„์šฉ ๊ณ„์‚ฐ (support๋Š” ์›” ๋น„์šฉ)
1077
- if (component.id.includes('support')) {
1078
- monthlyCost += component.cost;
1079
  }
 
1080
 
1081
  componentListHTML += `
1082
  <div class="component-list-item">
1083
- <span>${component.name}</span>
1084
- <span>โ‚ฉ${component.cost}M</span>
1085
  </div>
1086
  `;
1087
  });
1088
 
1089
- // ๊ธฐ๋ณธ ์›” ์šด์˜ ๋น„์šฉ ์ถ”๊ฐ€ (์„œ๋ฒ„, API ๋“ฑ)
1090
- monthlyCost += totalCost * 0.05; // ์ดˆ๊ธฐ ๋น„์šฉ์˜ 5%๋ฅผ ์›” ์šด์˜๋น„๋กœ ๊ฐ€์ •
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1091
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1092
  document.getElementById('totalCost').textContent = `โ‚ฉ${totalCost}M`;
1093
- document.getElementById('totalTime').textContent = `${totalTime}๊ฐœ์›”`;
1094
- document.getElementById('monthlyCost').textContent = `โ‚ฉ${monthlyCost.toFixed(1)}M`;
1095
  document.getElementById('componentList').innerHTML = componentListHTML;
1096
- document.getElementById('customResult').style.display = 'block';
1097
 
1098
- // ์Šคํฌ๋กค ๋‹ค์šด
1099
- document.getElementById('customResult').scrollIntoView({ behavior: 'smooth' });
 
 
 
 
 
 
 
 
 
1100
  }
1101
 
 
1102
  function calculateCosts() {
1103
  const scale = document.getElementById('projectScale').value;
1104
  const duration = parseInt(document.getElementById('duration').value);
1105
  const users = parseInt(document.getElementById('users').value);
1106
  const features = document.getElementById('features').value;
1107
 
1108
- // ๊ธฐ๋ณธ ๋น„์šฉ ์„ค์ •
1109
  const baseCosts = {
1110
  outsource: {
1111
  small: { initial: 50, monthly: 5 },
@@ -1124,17 +1476,13 @@
1124
  }
1125
  };
1126
 
1127
- // ๋ณต์žก๋„์— ๋”ฐ๋ฅธ ๊ฐ€์ค‘์น˜
1128
  const complexityMultiplier = {
1129
  basic: 1,
1130
  advanced: 1.5,
1131
  enterprise: 2
1132
  };
1133
 
1134
- // ์‚ฌ์šฉ์ž ์ˆ˜์— ๋”ฐ๋ฅธ ์ถ”๊ฐ€ ๋น„์šฉ
1135
  const userCostFactor = Math.log10(users) / 3;
1136
-
1137
- // ๋น„์šฉ ๊ณ„์‚ฐ
1138
  const multiplier = complexityMultiplier[features] * userCostFactor;
1139
 
1140
  const outsourceCost = baseCosts.outsource[scale].initial +
@@ -1144,7 +1492,95 @@
1144
  const platformCost = baseCosts.platform[scale].initial +
1145
  (baseCosts.platform[scale].monthly * duration * multiplier);
1146
 
1147
- // ๊ฒฐ๊ณผ ํ‘œ์‹œ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1148
  document.getElementById('outsourceCost').textContent = `โ‚ฉ${Math.round(outsourceCost)}M`;
1149
  document.getElementById('inhouseCost').textContent = `โ‚ฉ${Math.round(inhouseCost)}M`;
1150
  document.getElementById('platformCost').textContent = `โ‚ฉ${Math.round(platformCost)}M`;
 
388
 
389
  .option-card {
390
  background: rgba(255, 255, 255, 0.05);
391
+ border: 2px solid rgba(255, 255, 255, 0.2);
392
  border-radius: 10px;
393
  padding: 1rem;
394
  cursor: pointer;
 
398
  }
399
 
400
  .option-card.selected {
401
+ background: rgba(58, 123, 213, 0.3);
402
  border-color: #3a7bd5;
403
  transform: scale(1.05);
404
+ box-shadow: 0 5px 20px rgba(58, 123, 213, 0.3);
405
+ }
406
+
407
+ .option-card.selected::after {
408
+ content: 'โœ“';
409
+ position: absolute;
410
+ top: 0.5rem;
411
+ right: 0.5rem;
412
+ background: #3a7bd5;
413
+ color: white;
414
+ width: 25px;
415
+ height: 25px;
416
+ border-radius: 50%;
417
+ display: flex;
418
+ align-items: center;
419
+ justify-content: center;
420
+ font-weight: bold;
421
  }
422
 
423
  .option-card:hover {
424
  border-color: #00d2ff;
425
  background: rgba(255, 255, 255, 0.1);
426
+ transform: translateY(-2px);
427
  }
428
 
429
  .option-name {
 
446
  display: none;
447
  }
448
 
449
+ .result-header {
450
+ text-align: center;
451
+ margin-bottom: 2rem;
452
+ }
453
+
454
+ .result-header h3 {
455
+ font-size: 1.8rem;
456
+ margin-bottom: 0.5rem;
457
+ color: #00d2ff;
458
+ }
459
+
460
+ .period-tabs {
461
+ display: flex;
462
+ justify-content: center;
463
+ gap: 1rem;
464
+ margin-bottom: 2rem;
465
+ }
466
+
467
+ .period-tab {
468
+ padding: 0.5rem 1.5rem;
469
+ background: rgba(255, 255, 255, 0.1);
470
+ border: 1px solid rgba(255, 255, 255, 0.2);
471
+ border-radius: 20px;
472
+ cursor: pointer;
473
+ transition: all 0.3s ease;
474
+ }
475
+
476
+ .period-tab.active {
477
+ background: linear-gradient(45deg, #00d2ff, #3a7bd5);
478
+ border-color: transparent;
479
+ }
480
+
481
  .custom-summary {
482
  display: grid;
483
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
 
506
  background: rgba(255, 255, 255, 0.05);
507
  border-radius: 10px;
508
  padding: 1.5rem;
509
+ margin-bottom: 1.5rem;
510
  }
511
 
512
  .selected-components h4 {
513
  margin-bottom: 1rem;
514
+ font-size: 1.2rem;
515
  }
516
 
517
  .component-list {
 
522
  .component-list-item {
523
  display: flex;
524
  justify-content: space-between;
525
+ padding: 0.75rem;
526
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
527
+ background: rgba(255, 255, 255, 0.02);
528
+ border-radius: 5px;
529
+ }
530
+
531
+ .component-list-item:last-child {
532
+ border-bottom: none;
533
+ }
534
+
535
+ .timeline-section {
536
+ background: rgba(255, 255, 255, 0.05);
537
+ border-radius: 10px;
538
+ padding: 1.5rem;
539
+ margin-top: 1.5rem;
540
+ }
541
+
542
+ .timeline-section h4 {
543
+ margin-bottom: 1rem;
544
+ font-size: 1.2rem;
545
+ }
546
+
547
+ .timeline-bar {
548
+ position: relative;
549
+ height: 40px;
550
+ background: rgba(255, 255, 255, 0.1);
551
+ border-radius: 20px;
552
+ overflow: hidden;
553
+ margin-bottom: 1rem;
554
+ }
555
+
556
+ .timeline-progress {
557
+ height: 100%;
558
+ background: linear-gradient(90deg, #00d2ff, #3a7bd5);
559
+ border-radius: 20px;
560
+ display: flex;
561
+ align-items: center;
562
+ justify-content: center;
563
+ color: white;
564
+ font-weight: 600;
565
+ transition: width 0.5s ease;
566
+ }
567
+
568
+ .monthly-breakdown {
569
+ display: grid;
570
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
571
+ gap: 1rem;
572
+ margin-top: 1rem;
573
+ }
574
+
575
+ .monthly-item {
576
+ background: rgba(255, 255, 255, 0.05);
577
+ padding: 1rem;
578
+ border-radius: 10px;
579
+ text-align: center;
580
+ }
581
+
582
+ .monthly-label {
583
+ font-size: 0.9rem;
584
+ color: #a8a8b3;
585
+ margin-bottom: 0.5rem;
586
+ }
587
+
588
+ .monthly-value {
589
+ font-size: 1.2rem;
590
+ font-weight: 600;
591
+ color: #00d2ff;
592
  }
593
 
594
  @keyframes fadeInDown {
 
846
  <div class="component-section">
847
  <div class="component-title">
848
  <div class="component-icon">๐ŸŽฏ</div>
849
+ <span>ํƒ€๊นƒ ์„œ๋น„์Šค ์œ ํ˜• (ํ•„์ˆ˜)</span>
850
  </div>
851
  <div class="component-options">
852
+ <div class="option-card" data-category="service" data-id="image-gen" data-cost="30" data-time="2">
853
  <div class="option-name">์ด๋ฏธ์ง€ ์ƒ์„ฑ</div>
854
  <div class="option-details">
855
  <span>โ‚ฉ30M</span>
856
  <span>2๊ฐœ์›”</span>
857
  </div>
858
  </div>
859
+ <div class="option-card" data-category="service" data-id="image-edit" data-cost="35" data-time="2.5">
860
  <div class="option-name">์ด๋ฏธ์ง€ ํŽธ์ง‘/ํ•ฉ์„ฑ</div>
861
  <div class="option-details">
862
  <span>โ‚ฉ35M</span>
863
  <span>2.5๊ฐœ์›”</span>
864
  </div>
865
  </div>
866
+ <div class="option-card" data-category="service" data-id="video-gen" data-cost="50" data-time="3">
867
  <div class="option-name">๋น„๋””์˜ค ์ƒ์„ฑ</div>
868
  <div class="option-details">
869
  <span>โ‚ฉ50M</span>
870
  <span>3๊ฐœ์›”</span>
871
  </div>
872
  </div>
873
+ <div class="option-card" data-category="service" data-id="music-gen" data-cost="40" data-time="2.5">
874
  <div class="option-name">์Œ์•… ๋ฐ ์Œํ–ฅ ์ƒ์„ฑ</div>
875
  <div class="option-details">
876
  <span>โ‚ฉ40M</span>
877
  <span>2.5๊ฐœ์›”</span>
878
  </div>
879
  </div>
880
+ <div class="option-card" data-category="service" data-id="text-chat" data-cost="20" data-time="1.5">
881
  <div class="option-name">ํ…์ŠคํŠธ ์ƒ์„ฑ(์ฑ—๋ด‡)</div>
882
  <div class="option-details">
883
  <span>โ‚ฉ20M</span>
884
  <span>1.5๊ฐœ์›”</span>
885
  </div>
886
  </div>
887
+ <div class="option-card" data-category="service" data-id="text-expert" data-cost="25" data-time="2">
888
  <div class="option-name">ํ…์ŠคํŠธ ์ƒ์„ฑ(์ „๋ฌธ๊ฐ€)</div>
889
  <div class="option-details">
890
  <span>โ‚ฉ25M</span>
891
  <span>2๊ฐœ์›”</span>
892
  </div>
893
  </div>
894
+ <div class="option-card" data-category="service" data-id="voice-clone" data-cost="45" data-time="2.5">
895
  <div class="option-name">์Œ์„ฑ ๋ณต์ œ/์ƒ์„ฑ</div>
896
  <div class="option-details">
897
  <span>โ‚ฉ45M</span>
898
  <span>2.5๊ฐœ์›”</span>
899
  </div>
900
  </div>
901
+ <div class="option-card" data-category="service" data-id="vision-ai" data-cost="35" data-time="2">
902
  <div class="option-name">๋น„์ „ ์ธ์‹</div>
903
  <div class="option-details">
904
  <span>โ‚ฉ35M</span>
 
915
  <span>DB ๊ด€๋ฆฌ</span>
916
  </div>
917
  <div class="component-options">
918
+ <div class="option-card" data-category="db" data-id="basic-db" data-cost="5" data-time="0.5">
919
  <div class="option-name">๊ธฐ๋ณธ DB</div>
920
  <div class="option-details">
921
  <span>โ‚ฉ5M</span>
922
  <span>0.5๊ฐœ์›”</span>
923
  </div>
924
  </div>
925
+ <div class="option-card" data-category="db" data-id="advanced-db" data-cost="15" data-time="1">
926
  <div class="option-name">๊ณ ๊ธ‰ DB + ๋ฐฑ์—…</div>
927
  <div class="option-details">
928
  <span>โ‚ฉ15M</span>
929
  <span>1๊ฐœ์›”</span>
930
  </div>
931
  </div>
932
+ <div class="option-card" data-category="db" data-id="enterprise-db" data-cost="25" data-time="1.5">
933
  <div class="option-name">์—”ํ„ฐํ”„๋ผ์ด์ฆˆ DB</div>
934
  <div class="option-details">
935
  <span>โ‚ฉ25M</span>
 
946
  <span>ํšŒ์›๊ฐ€์ž… ๋ฐ ๋กœ๊ทธ์ธ</span>
947
  </div>
948
  <div class="component-options">
949
+ <div class="option-card" data-category="auth" data-id="gmail-only" data-cost="3" data-time="0.3">
950
  <div class="option-name">Gmail ์—ฐ๋™</div>
951
  <div class="option-details">
952
  <span>โ‚ฉ3M</span>
953
  <span>0.3๊ฐœ์›”</span>
954
  </div>
955
  </div>
956
+ <div class="option-card" data-category="auth" data-id="multi-auth" data-cost="8" data-time="0.5">
957
  <div class="option-name">๋‹ค์ค‘ ์†Œ์…œ ๋กœ๊ทธ์ธ</div>
958
  <div class="option-details">
959
  <span>โ‚ฉ8M</span>
960
  <span>0.5๊ฐœ์›”</span>
961
  </div>
962
  </div>
963
+ <div class="option-card" data-category="auth" data-id="custom-auth" data-cost="12" data-time="1">
964
  <div class="option-name">์ปค์Šคํ…€ ์ธ์ฆ ์‹œ์Šคํ…œ</div>
965
  <div class="option-details">
966
  <span>โ‚ฉ12M</span>
 
977
  <span>ํฌ๋ ˆ๋”ง ๊ด€๋ฆฌ</span>
978
  </div>
979
  <div class="component-options">
980
+ <div class="option-card" data-category="credit" data-id="basic-credit" data-cost="5" data-time="0.5">
981
  <div class="option-name">๊ธฐ๋ณธ ํฌ๋ ˆ๋”ง ์‹œ์Šคํ…œ</div>
982
  <div class="option-details">
983
  <span>โ‚ฉ5M</span>
984
  <span>0.5๊ฐœ์›”</span>
985
  </div>
986
  </div>
987
+ <div class="option-card" data-category="credit" data-id="advanced-credit" data-cost="12" data-time="1">
988
  <div class="option-name">๊ณ ๊ธ‰ ํฌ๋ ˆ๋”ง + ๊ตฌ๋…</div>
989
  <div class="option-details">
990
  <span>โ‚ฉ12M</span>
 
1001
  <span>ํŽ˜์ด๋จผํŠธ ์ง€์›</span>
1002
  </div>
1003
  <div class="component-options">
1004
+ <div class="option-card" data-category="payment" data-id="basic-payment" data-cost="8" data-time="0.5">
1005
  <div class="option-name">๊ธฐ๋ณธ ๊ฒฐ์ œ (์นด๋“œ)</div>
1006
  <div class="option-details">
1007
  <span>โ‚ฉ8M</span>
1008
  <span>0.5๊ฐœ์›”</span>
1009
  </div>
1010
  </div>
1011
+ <div class="option-card" data-category="payment" data-id="multi-payment" data-cost="15" data-time="1">
1012
  <div class="option-name">๋‹ค์ค‘ ๊ฒฐ์ œ ์ˆ˜๋‹จ</div>
1013
  <div class="option-details">
1014
  <span>โ‚ฉ15M</span>
1015
  <span>1๊ฐœ์›”</span>
1016
  </div>
1017
  </div>
1018
+ <div class="option-card" data-category="payment" data-id="global-payment" data-cost="20" data-time="1.5">
1019
  <div class="option-name">๊ธ€๋กœ๋ฒŒ ๊ฒฐ์ œ ์‹œ์Šคํ…œ</div>
1020
  <div class="option-details">
1021
  <span>โ‚ฉ20M</span>
 
1032
  <span>๋งˆ์ผ€ํŒ… ์ง€์›</span>
1033
  </div>
1034
  <div class="component-options">
1035
+ <div class="option-card" data-category="marketing" data-id="basic-marketing" data-cost="10" data-time="1">
1036
  <div class="option-name">๊ธฐ๋ณธ ๋งˆ์ผ€ํŒ… ๋„๊ตฌ</div>
1037
  <div class="option-details">
1038
  <span>โ‚ฉ10M</span>
1039
  <span>1๊ฐœ์›”</span>
1040
  </div>
1041
  </div>
1042
+ <div class="option-card" data-category="marketing" data-id="advanced-marketing" data-cost="20" data-time="1.5">
1043
  <div class="option-name">๊ณ ๊ธ‰ ๋งˆ์ผ€ํŒ… ์ž๋™ํ™”</div>
1044
  <div class="option-details">
1045
  <span>โ‚ฉ20M</span>
 
1056
  <span>๊ฐœ๋ฐœ ๋ฐ ๊ธฐ์ˆ  ์ธ๋ ฅ ์ง€์›</span>
1057
  </div>
1058
  <div class="component-options">
1059
+ <div class="option-card" data-category="support" data-id="basic-support" data-cost="5" data-time="0">
1060
  <div class="option-name">๊ธฐ๋ณธ ๊ธฐ์ˆ  ์ง€์›</div>
1061
  <div class="option-details">
1062
  <span>์›” โ‚ฉ5M</span>
1063
  <span>์ฆ‰์‹œ</span>
1064
  </div>
1065
  </div>
1066
+ <div class="option-card" data-category="support" data-id="dedicated-support" data-cost="15" data-time="0">
1067
  <div class="option-name">์ „๋‹ด ๊ฐœ๋ฐœ์ž ์ง€์›</div>
1068
  <div class="option-details">
1069
  <span>์›” โ‚ฉ15M</span>
 
1080
  <span>์›๊ฒฉ ๋ชจ๋‹ˆํ„ฐ๋ง ์ง€์›</span>
1081
  </div>
1082
  <div class="component-options">
1083
+ <div class="option-card" data-category="monitoring" data-id="basic-monitor" data-cost="3" data-time="0.3">
1084
  <div class="option-name">๊ธฐ๋ณธ ๋ชจ๋‹ˆํ„ฐ๋ง</div>
1085
  <div class="option-details">
1086
  <span>โ‚ฉ3M</span>
1087
  <span>0.3๊ฐœ์›”</span>
1088
  </div>
1089
  </div>
1090
+ <div class="option-card" data-category="monitoring" data-id="advanced-monitor" data-cost="8" data-time="0.5">
1091
  <div class="option-name">๊ณ ๊ธ‰ ๋ถ„์„ + ์•Œ๋ฆผ</div>
1092
  <div class="option-details">
1093
  <span>โ‚ฉ8M</span>
 
1097
  </div>
1098
  </div>
1099
 
1100
+ <!-- ์ถ”๊ฐ€ ๊ตฌ์„ฑ ์š”์†Œ -->
1101
+ <div class="component-section">
1102
+ <div class="component-title">
1103
+ <div class="component-icon">๐Ÿ”ง</div>
1104
+ <span>์ถ”๊ฐ€ ๊ธฐ๋Šฅ</span>
1105
+ </div>
1106
+ <div class="component-options">
1107
+ <div class="option-card" data-category="additional" data-id="admin-panel" data-cost="10" data-time="0.5">
1108
+ <div class="option-name">๊ด€๋ฆฌ์ž ๋Œ€์‹œ๋ณด๋“œ</div>
1109
+ <div class="option-details">
1110
+ <span>โ‚ฉ10M</span>
1111
+ <span>0.5๊ฐœ์›”</span>
1112
+ </div>
1113
+ </div>
1114
+ <div class="option-card" data-category="additional" data-id="api-system" data-cost="15" data-time="1">
1115
+ <div class="option-name">API ์‹œ์Šคํ…œ</div>
1116
+ <div class="option-details">
1117
+ <span>โ‚ฉ15M</span>
1118
+ <span>1๊ฐœ์›”</span>
1119
+ </div>
1120
+ </div>
1121
+ <div class="option-card" data-category="additional" data-id="analytics" data-cost="12" data-time="0.5">
1122
+ <div class="option-name">๋ถ„์„ ๋„๊ตฌ</div>
1123
+ <div class="option-details">
1124
+ <span>โ‚ฉ12M</span>
1125
+ <span>0.5๊ฐœ์›”</span>
1126
+ </div>
1127
+ </div>
1128
+ <div class="option-card" data-category="additional" data-id="multi-language" data-cost="8" data-time="0.5">
1129
+ <div class="option-name">๋‹ค๊ตญ์–ด ์ง€์›</div>
1130
+ <div class="option-details">
1131
+ <span>โ‚ฉ8M</span>
1132
+ <span>0.5๊ฐœ์›”</span>
1133
+ </div>
1134
+ </div>
1135
+ </div>
1136
+ </div>
1137
+
1138
  <button class="calculate-btn" onclick="calculateCustomCost()">๋งž์ถค ๊ฒฌ์  ๊ณ„์‚ฐํ•˜๊ธฐ</button>
1139
 
1140
  <div class="custom-result" id="customResult">
1141
+ <div class="result-header">
1142
+ <h3>๋งž์ถค AI SaaS ๊ฒฌ์ ์„œ</h3>
1143
+ <p>์„ ํƒํ•˜์‹  ๊ตฌ์„ฑ์œผ๋กœ ์‚ฐ์ถœ๋œ ์ƒ์„ธ ๊ฒฌ์ ์ž…๋‹ˆ๋‹ค</p>
1144
+ </div>
1145
+
1146
+ <div class="period-tabs">
1147
+ <div class="period-tab active" onclick="switchPeriod(3)">3๊ฐœ์›”</div>
1148
+ <div class="period-tab" onclick="switchPeriod(6)">6๊ฐœ์›”</div>
1149
+ <div class="period-tab" onclick="switchPeriod(12)">12๊ฐœ์›”</div>
1150
+ </div>
1151
+
1152
  <div class="custom-summary">
1153
  <div class="summary-item">
1154
+ <div class="summary-label">์ดˆ๊ธฐ ๊ฐœ๋ฐœ ๋น„์šฉ</div>
1155
+ <div class="summary-value" id="initialCost">โ‚ฉ0</div>
1156
  </div>
1157
  <div class="summary-item">
1158
  <div class="summary-label">์˜ˆ์ƒ ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„</div>
1159
+ <div class="summary-value" id="devTime">0๊ฐœ์›”</div>
1160
  </div>
1161
  <div class="summary-item">
1162
+ <div class="summary-label">์ด ๋น„์šฉ (<span id="periodText">3</span>๊ฐœ์›”)</div>
1163
+ <div class="summary-value" id="totalCost">โ‚ฉ0</div>
1164
  </div>
1165
  </div>
1166
+
1167
  <div class="selected-components">
1168
+ <h4>์„ ํƒํ•œ ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ธ</h4>
1169
  <div class="component-list" id="componentList"></div>
1170
  </div>
1171
+
1172
+ <div class="timeline-section">
1173
+ <h4>๊ฐœ๋ฐœ ์ผ์ • ๋ฐ ์ง„ํ–‰๋ฅ </h4>
1174
+ <div class="timeline-bar">
1175
+ <div class="timeline-progress" id="timelineProgress" style="width: 0%">
1176
+ <span id="progressText">0%</span>
1177
+ </div>
1178
+ </div>
1179
+ <p style="text-align: center; color: #a8a8b3; margin-top: 0.5rem;">
1180
+ ์˜ˆ์ƒ ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„: <span id="timelineText">0๊ฐœ์›”</span>
1181
+ </p>
1182
+ </div>
1183
+
1184
+ <div class="monthly-breakdown">
1185
+ <div class="monthly-item">
1186
+ <div class="monthly-label">์›” ์„œ๋ฒ„ ๋น„์šฉ</div>
1187
+ <div class="monthly-value" id="serverCost">โ‚ฉ0</div>
1188
+ </div>
1189
+ <div class="monthly-item">
1190
+ <div class="monthly-label">์›” API ๋น„์šฉ</div>
1191
+ <div class="monthly-value" id="apiCost">โ‚ฉ0</div>
1192
+ </div>
1193
+ <div class="monthly-item">
1194
+ <div class="monthly-label">์›” ์œ ์ง€๋ณด์ˆ˜</div>
1195
+ <div class="monthly-value" id="maintenanceCost">โ‚ฉ0</div>
1196
+ </div>
1197
+ <div class="monthly-item">
1198
+ <div class="monthly-label">์›” ์ด ์šด์˜๋น„</div>
1199
+ <div class="monthly-value" id="totalMonthlyCost">โ‚ฉ0</div>
1200
+ </div>
1201
+ </div>
1202
  </div>
1203
  </div>
1204
  </div>
 
1207
  <script>
1208
  let costChart = null;
1209
  let selectedComponents = {};
1210
+ let currentPeriod = 3;
1211
 
1212
+ // ํƒญ ์ „ํ™˜ ํ•จ์ˆ˜
1213
  function switchTab(tabName) {
 
1214
  document.querySelectorAll('.tab-content').forEach(content => {
1215
  content.classList.remove('active');
1216
  });
1217
 
 
1218
  document.querySelectorAll('.tab').forEach(tab => {
1219
  tab.classList.remove('active');
1220
  });
1221
 
 
1222
  document.getElementById(tabName).classList.add('active');
1223
  event.target.classList.add('active');
1224
  }
1225
 
1226
+ // ๋งž์ถค ์„ค๊ณ„ ์˜ต์…˜ ์„ ํƒ ํ•จ์ˆ˜
1227
+ document.addEventListener('DOMContentLoaded', function() {
1228
+ // ๋ชจ๋“  option-card์— ํด๋ฆญ ์ด๋ฒคํŠธ ์ถ”๊ฐ€
1229
+ document.querySelectorAll('.option-card').forEach(card => {
1230
+ card.addEventListener('click', function() {
1231
+ const category = this.dataset.category;
1232
+ const id = this.dataset.id;
1233
+ const cost = parseFloat(this.dataset.cost);
1234
+ const time = parseFloat(this.dataset.time);
1235
+ const name = this.querySelector('.option-name').textContent;
1236
+
1237
+ // ๊ฐ™์€ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ์„ ํƒ ์ œ๊ฑฐ
1238
+ document.querySelectorAll(`.option-card[data-category="${category}"]`).forEach(c => {
1239
+ c.classList.remove('selected');
1240
+ });
1241
+
1242
+ // ํ˜„์žฌ ์นด๋“œ ์„ ํƒ
1243
+ this.classList.add('selected');
1244
+
1245
+ // ์„ ํƒ ์ •๋ณด ์ €์žฅ
1246
+ selectedComponents[category] = {
1247
+ id: id,
1248
+ name: name,
1249
+ cost: cost,
1250
+ time: time,
1251
+ category: category
1252
+ };
1253
+ });
1254
  });
1255
+ });
 
 
 
 
 
 
 
 
 
 
 
1256
 
1257
+ // ๊ธฐ๊ฐ„ ์ „ํ™˜ ํ•จ์ˆ˜
1258
+ function switchPeriod(period) {
1259
+ currentPeriod = period;
1260
+ document.querySelectorAll('.period-tab').forEach(tab => {
1261
+ tab.classList.remove('active');
1262
+ });
1263
+ event.target.classList.add('active');
1264
+
1265
+ if (Object.keys(selectedComponents).length > 0) {
1266
+ displayCustomResults();
1267
+ }
 
1268
  }
1269
 
1270
+ // ๋งž์ถค ๋น„์šฉ ๊ณ„์‚ฐ ํ•จ์ˆ˜
1271
  function calculateCustomCost() {
1272
+ // ํ•„์ˆ˜ ํ•ญ๋ชฉ ์ฒดํฌ
1273
+ if (!selectedComponents.service) {
1274
+ alert('ํƒ€๊นƒ ์„œ๋น„์Šค ์œ ํ˜•์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”.');
1275
  return;
1276
  }
1277
 
1278
+ displayCustomResults();
1279
+ document.getElementById('customResult').style.display = 'block';
1280
+ document.getElementById('customResult').scrollIntoView({ behavior: 'smooth' });
1281
+ }
1282
+
1283
+ // ๊ฒฐ๊ณผ ํ‘œ์‹œ ํ•จ์ˆ˜
1284
+ function displayCustomResults() {
1285
+ let initialCost = 0;
1286
+ let maxTime = 0;
1287
  let componentListHTML = '';
1288
+ let monthlySupport = 0;
1289
+
1290
+ // ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์ด๋ฆ„
1291
+ const categoryNames = {
1292
+ 'service': 'ํƒ€๊นƒ ์„œ๋น„์Šค',
1293
+ 'db': 'DB ๊ด€๋ฆฌ',
1294
+ 'auth': '์ธ์ฆ ์‹œ์Šคํ…œ',
1295
+ 'credit': 'ํฌ๋ ˆ๋”ง ๊ด€๋ฆฌ',
1296
+ 'payment': '๊ฒฐ์ œ ์‹œ์Šคํ…œ',
1297
+ 'marketing': '๋งˆ์ผ€ํŒ… ๋„๊ตฌ',
1298
+ 'support': '๊ธฐ์ˆ  ์ง€์›',
1299
+ 'monitoring': '๋ชจ๋‹ˆํ„ฐ๋ง',
1300
+ 'additional': '์ถ”๊ฐ€ ๊ธฐ๋Šฅ'
1301
+ };
1302
 
1303
+ // ์ดˆ๊ธฐ ๋น„์šฉ ๊ณ„์‚ฐ ๋ฐ ๊ตฌ์„ฑ ์š”์†Œ ๋ชฉ๋ก ์ƒ์„ฑ
1304
  Object.values(selectedComponents).forEach(component => {
1305
+ if (component.category === 'support') {
1306
+ monthlySupport += component.cost;
1307
+ } else {
1308
+ initialCost += component.cost;
 
 
1309
  }
1310
+ maxTime = Math.max(maxTime, component.time);
1311
 
1312
  componentListHTML += `
1313
  <div class="component-list-item">
1314
+ <span><strong>${categoryNames[component.category]}</strong>: ${component.name}</span>
1315
+ <span>${component.category === 'support' ? '์›” ' : ''}โ‚ฉ${component.cost}M</span>
1316
  </div>
1317
  `;
1318
  });
1319
 
1320
+ // ์›”๋ณ„ ์šด์˜ ๋น„์šฉ ๊ณ„์‚ฐ
1321
+ const serverCost = Math.round(initialCost * 0.02); // ์ดˆ๊ธฐ ๋น„์šฉ์˜ 2%
1322
+ const apiCost = Math.round(initialCost * 0.03); // ์ดˆ๊ธฐ ๋น„์šฉ์˜ 3%
1323
+ const maintenanceCost = Math.round(initialCost * 0.01); // ์ดˆ๊ธฐ ๋น„์šฉ์˜ 1%
1324
+ const totalMonthly = serverCost + apiCost + maintenanceCost + monthlySupport;
1325
+
1326
+ // ์ด ๋น„์šฉ ๊ณ„์‚ฐ (๊ธฐ๊ฐ„๋ณ„)
1327
+ const totalCost = initialCost + (totalMonthly * currentPeriod);
1328
+
1329
+ // ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„ ์กฐ์ • (์ตœ์†Œ 3๊ฐœ์›”)
1330
+ const adjustedTime = Math.max(3, Math.ceil(maxTime));
1331
+
1332
+ // ๊ฒฐ๊ณผ ํ‘œ์‹œ
1333
+ document.getElementById('outsourceCost').textContent = `โ‚ฉ${Math.round(outsourceCost)}M`;
1334
+ document.getElementById('inhouseCost').textContent = `โ‚ฉ${Math.round(inhouseCost)}M`;
1335
+ document.getElementById('platformCost').textContent = `โ‚ฉ${Math.round(platformCost)}M`;
1336
+ document.getElementById('results').style.display = 'block';
1337
+
1338
+ // ์ฐจํŠธ ๊ทธ๋ฆฌ๊ธฐ
1339
+ drawChart(duration, baseCosts[scale], multiplier);
1340
+ }
1341
 
1342
+ function drawChart(duration, costs, multiplier) {
1343
+ const ctx = document.getElementById('costChart').getContext('2d');
1344
+
1345
+ if (costChart) {
1346
+ costChart.destroy();
1347
+ }
1348
+
1349
+ const months = Array.from({length: duration}, (_, i) => i + 1);
1350
+
1351
+ costChart = new Chart(ctx, {
1352
+ type: 'line',
1353
+ data: {
1354
+ labels: months.map(m => `${m}๊ฐœ์›”`),
1355
+ datasets: [
1356
+ {
1357
+ label: '์™ธ์ฃผ ์šฉ์—ญ',
1358
+ data: months.map(m => costs.outsource.initial + (costs.outsource.monthly * m * multiplier)),
1359
+ borderColor: '#764ba2',
1360
+ backgroundColor: 'rgba(118, 75, 162, 0.1)',
1361
+ tension: 0.4
1362
+ },
1363
+ {
1364
+ label: '์ž์ฒด ์ธ๋ ฅ',
1365
+ data: months.map(m => costs.inhouse.initial + (costs.inhouse.monthly * m * multiplier)),
1366
+ borderColor: '#f5576c',
1367
+ backgroundColor: 'rgba(245, 87, 108, 0.1)',
1368
+ tension: 0.4
1369
+ },
1370
+ {
1371
+ label: 'ํ”Œ๋žซํผ ๋Œ€์—ฌ',
1372
+ data: months.map(m => costs.platform.initial + (costs.platform.monthly * m * multiplier)),
1373
+ borderColor: '#00f2fe',
1374
+ backgroundColor: 'rgba(0, 242, 254, 0.1)',
1375
+ tension: 0.4
1376
+ }
1377
+ ]
1378
+ },
1379
+ options: {
1380
+ responsive: true,
1381
+ maintainAspectRatio: false,
1382
+ plugins: {
1383
+ title: {
1384
+ display: true,
1385
+ text: '์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ๋ˆ„์  ๋น„์šฉ ์ถ”์ด',
1386
+ color: '#ffffff',
1387
+ font: {
1388
+ size: 16
1389
+ }
1390
+ },
1391
+ legend: {
1392
+ labels: {
1393
+ color: '#ffffff'
1394
+ }
1395
+ }
1396
+ },
1397
+ scales: {
1398
+ x: {
1399
+ grid: {
1400
+ color: 'rgba(255, 255, 255, 0.1)'
1401
+ },
1402
+ ticks: {
1403
+ color: '#ffffff'
1404
+ }
1405
+ },
1406
+ y: {
1407
+ grid: {
1408
+ color: 'rgba(255, 255, 255, 0.1)'
1409
+ },
1410
+ ticks: {
1411
+ color: '#ffffff',
1412
+ callback: function(value) {
1413
+ return 'โ‚ฉ' + value + 'M';
1414
+ }
1415
+ }
1416
+ }
1417
+ }
1418
+ }
1419
+ });
1420
+ }
1421
+
1422
+ // ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ์œ„ํ•œ Intersection Observer
1423
+ const observer = new IntersectionObserver((entries) => {
1424
+ entries.forEach(entry => {
1425
+ if (entry.isIntersecting) {
1426
+ entry.target.style.animation = 'fadeInUp 0.8s ease-out forwards';
1427
+ }
1428
+ });
1429
+ });
1430
+
1431
+ document.querySelectorAll('.method-card').forEach(card => {
1432
+ observer.observe(card);
1433
+ });
1434
+ </script> ํ‘œ์‹œ
1435
+ document.getElementById('initialCost').textContent = `โ‚ฉ${initialCost}M`;
1436
+ document.getElementById('devTime').textContent = `${adjustedTime}๊ฐœ์›”`;
1437
  document.getElementById('totalCost').textContent = `โ‚ฉ${totalCost}M`;
1438
+ document.getElementById('periodText').textContent = currentPeriod;
 
1439
  document.getElementById('componentList').innerHTML = componentListHTML;
 
1440
 
1441
+ // ํƒ€์ž„๋ผ์ธ ์—…๋ฐ์ดํŠธ
1442
+ const progressPercent = Math.min(100, (adjustedTime / 12) * 100);
1443
+ document.getElementById('timelineProgress').style.width = `${progressPercent}%`;
1444
+ document.getElementById('progressText').textContent = `${Math.round(progressPercent)}%`;
1445
+ document.getElementById('timelineText').textContent = `${adjustedTime}๊ฐœ์›”`;
1446
+
1447
+ // ์›”๋ณ„ ๋น„์šฉ ํ‘œ์‹œ
1448
+ document.getElementById('serverCost').textContent = `โ‚ฉ${serverCost}M`;
1449
+ document.getElementById('apiCost').textContent = `โ‚ฉ${apiCost}M`;
1450
+ document.getElementById('maintenanceCost').textContent = `โ‚ฉ${maintenanceCost}M`;
1451
+ document.getElementById('totalMonthlyCost').textContent = `โ‚ฉ${totalMonthly}M`;
1452
  }
1453
 
1454
+ // ๊ธฐ์กด ๋น„์šฉ ๊ณ„์‚ฐ ํ•จ์ˆ˜
1455
  function calculateCosts() {
1456
  const scale = document.getElementById('projectScale').value;
1457
  const duration = parseInt(document.getElementById('duration').value);
1458
  const users = parseInt(document.getElementById('users').value);
1459
  const features = document.getElementById('features').value;
1460
 
 
1461
  const baseCosts = {
1462
  outsource: {
1463
  small: { initial: 50, monthly: 5 },
 
1476
  }
1477
  };
1478
 
 
1479
  const complexityMultiplier = {
1480
  basic: 1,
1481
  advanced: 1.5,
1482
  enterprise: 2
1483
  };
1484
 
 
1485
  const userCostFactor = Math.log10(users) / 3;
 
 
1486
  const multiplier = complexityMultiplier[features] * userCostFactor;
1487
 
1488
  const outsourceCost = baseCosts.outsource[scale].initial +
 
1492
  const platformCost = baseCosts.platform[scale].initial +
1493
  (baseCosts.platform[scale].monthly * duration * multiplier);
1494
 
1495
+ document.getElementById('outsourceCost').textContent = `โ‚ฉ${Math.round(outsourceCost)}M`;
1496
+ document.getElementById('inhouseCost').textContent = `โ‚ฉ${Math.round(inhouseCost)}M`;
1497
+ document.getElementById('platformCost').textContent = `โ‚ฉ${Math.round(platformCost)}M`;
1498
+ document.getElementById('results').style.display = 'block';
1499
+
1500
+ drawChart(duration, baseCosts[scale], multiplier);
1501
+ }
1502
+
1503
+ // ์ฐจํŠธ ๊ทธ๋ฆฌ๊ธฐ ํ•จ์ˆ˜
1504
+ function drawChart(duration, costs, multiplier) {
1505
+ const ctx = document.getElementById('costChart').getContext('2d');
1506
+
1507
+ if (costChart) {
1508
+ costChart.destroy();
1509
+ }
1510
+
1511
+ const months = Array.from({length: duration}, (_, i) => i + 1);
1512
+
1513
+ costChart = new Chart(ctx, {
1514
+ type: 'line',
1515
+ data: {
1516
+ labels: months.map(m => `${m}๊ฐœ์›”`),
1517
+ datasets: [
1518
+ {
1519
+ label: '์™ธ์ฃผ ์šฉ์—ญ',
1520
+ data: months.map(m => costs.outsource.initial + (costs.outsource.monthly * m * multiplier)),
1521
+ borderColor: '#764ba2',
1522
+ backgroundColor: 'rgba(118, 75, 162, 0.1)',
1523
+ tension: 0.4
1524
+ },
1525
+ {
1526
+ label: '์ž์ฒด ์ธ๋ ฅ',
1527
+ data: months.map(m => costs.inhouse.initial + (costs.inhouse.monthly * m * multiplier)),
1528
+ borderColor: '#f5576c',
1529
+ backgroundColor: 'rgba(245, 87, 108, 0.1)',
1530
+ tension: 0.4
1531
+ },
1532
+ {
1533
+ label: 'ํ”Œ๋žซํผ ๋Œ€์—ฌ',
1534
+ data: months.map(m => costs.platform.initial + (costs.platform.monthly * m * multiplier)),
1535
+ borderColor: '#00f2fe',
1536
+ backgroundColor: 'rgba(0, 242, 254, 0.1)',
1537
+ tension: 0.4
1538
+ }
1539
+ ]
1540
+ },
1541
+ options: {
1542
+ responsive: true,
1543
+ maintainAspectRatio: false,
1544
+ plugins: {
1545
+ title: {
1546
+ display: true,
1547
+ text: '์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ๋ˆ„์  ๋น„์šฉ ์ถ”์ด',
1548
+ color: '#ffffff',
1549
+ font: {
1550
+ size: 16
1551
+ }
1552
+ },
1553
+ legend: {
1554
+ labels: {
1555
+ color: '#ffffff'
1556
+ }
1557
+ }
1558
+ },
1559
+ scales: {
1560
+ x: {
1561
+ grid: {
1562
+ color: 'rgba(255, 255, 255, 0.1)'
1563
+ },
1564
+ ticks: {
1565
+ color: '#ffffff'
1566
+ }
1567
+ },
1568
+ y: {
1569
+ grid: {
1570
+ color: 'rgba(255, 255, 255, 0.1)'
1571
+ },
1572
+ ticks: {
1573
+ color: '#ffffff',
1574
+ callback: function(value) {
1575
+ return 'โ‚ฉ' + value + 'M';
1576
+ }
1577
+ }
1578
+ }
1579
+ }
1580
+ }
1581
+ });
1582
+ }
1583
+ </script> ํ‘œ์‹œ
1584
  document.getElementById('outsourceCost').textContent = `โ‚ฉ${Math.round(outsourceCost)}M`;
1585
  document.getElementById('inhouseCost').textContent = `โ‚ฉ${Math.round(inhouseCost)}M`;
1586
  document.getElementById('platformCost').textContent = `โ‚ฉ${Math.round(platformCost)}M`;