From 65e988640df6dec2b8cd178846b7204de2b7eee2 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Fri, 19 Jun 2026 15:12:08 +0000 Subject: [PATCH] Autosave: 20260619-151237 --- config/__pycache__/__init__.cpython-311.pyc | Bin 159 -> 159 bytes config/__pycache__/settings.cpython-311.pyc | Bin 5552 -> 5552 bytes config/__pycache__/urls.cpython-311.pyc | Bin 1557 -> 1557 bytes config/__pycache__/wsgi.cpython-311.pyc | Bin 679 -> 679 bytes core/__pycache__/__init__.cpython-311.pyc | Bin 157 -> 157 bytes core/__pycache__/admin.cpython-311.pyc | Bin 212 -> 2779 bytes core/__pycache__/apps.cpython-311.pyc | Bin 524 -> 524 bytes .../context_processors.cpython-311.pyc | Bin 763 -> 763 bytes core/__pycache__/forms.cpython-311.pyc | Bin 0 -> 2272 bytes core/__pycache__/models.cpython-311.pyc | Bin 209 -> 6461 bytes core/__pycache__/urls.cpython-311.pyc | Bin 347 -> 529 bytes core/__pycache__/views.cpython-311.pyc | Bin 1364 -> 21854 bytes core/admin.py | 42 +- core/forms.py | 40 ++ core/migrations/0001_initial.py | 82 ++++ .../__pycache__/0001_initial.cpython-311.pyc | Bin 0 -> 4917 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 168 -> 168 bytes core/models.py | 106 +++- core/templates/base.html | 14 +- core/templates/core/_nav.html | 17 + core/templates/core/case_detail.html | 124 +++++ core/templates/core/case_list.html | 37 ++ core/templates/core/index.html | 330 +++++++------ core/urls.py | 4 +- core/views.py | 456 +++++++++++++++++- static/css/custom.css | 431 ++++++++++++++++- staticfiles/css/custom.css | 442 ++++++++++++++++- 27 files changed, 1944 insertions(+), 181 deletions(-) create mode 100644 core/__pycache__/forms.cpython-311.pyc create mode 100644 core/forms.py create mode 100644 core/migrations/0001_initial.py create mode 100644 core/migrations/__pycache__/0001_initial.cpython-311.pyc create mode 100644 core/templates/core/_nav.html create mode 100644 core/templates/core/case_detail.html create mode 100644 core/templates/core/case_list.html diff --git a/config/__pycache__/__init__.cpython-311.pyc b/config/__pycache__/__init__.cpython-311.pyc index 896bb4f1b8949c96d2f1bf743293342b70a9d0e4..1fe1dcd689fe7ac102a138886cfda17276d14837 100644 GIT binary patch delta 20 acmbQwIG>ScIWI340}wC=n`TYqnG66cNCZ6q delta 20 acmbQwIG>ScIWI340}#~ttjL_mGZ_Fdwgn>q diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index d79d6a79890a58443ee5f65d8d558823a19e9aed..97325ee291f5fac01a65b7eefba5548a4ef733c3 100644 GIT binary patch delta 21 bcmdm>y+NC2IWI340}wC=n`Uj~St1GmIUof2 delta 21 bcmdm>y+NC2IWI340}#~ttjOHRvqTgCKXe7( diff --git a/config/__pycache__/urls.cpython-311.pyc b/config/__pycache__/urls.cpython-311.pyc index 8cf22af743397374cabf5fa358c4f52631471db9..8df0882ff7dedfc49fe2940600b24885114f137f 100644 GIT binary patch delta 21 bcmbQrGnI#DIWI340}wC=n`Uj~;ba2FHvQcz^vRIuA_wm*u^1y(?fEUfTIjiGui0m zlMZ0`FqK6$6h-kJCxOfQRum){dB2V5 zj!cD%?3J8cgqvrC5=-%jrBcl*c#5TaDm-2jjS<_9sSv$s8lq&|q0^$aEh@I% zio7Ji>#A-4nm9o^!!VPC4wEzxI(-r|=LI=|G4l3$b1!PqX0n}xanhtusGGzQYd((H zBi?pg+H@mEn^N;iyTdS@Bw%jy_W`=2vtOO>-tAXw-Me_Qb6Mzgu}d&LO{`^jnpN}) zAX*o5leUd1H%p?xobZv*V?Pe4F#Hy5Hx?DTv*Wuy4c(5=d7DyCl!EB7&3yhy)II9@ z9Q?OA$`VzcxGv?~W=>2^g)PFKHq8>la$r@28bS%7j?e%Q#*R+|kBbJQju(YN$4&>> zEQUzg=kaPT1Ek|00*rgLF!ZWlYjwZwUo^Y-@l2QF$_dx-UE^_rET^tPdT5>sX`)#= zHE3~HwMs+hX2%loHfF3@WSC!~ww-WD9}w-p{zWliyV9(BoB0v*(U*D8^ENNzvk}mA{xQI*&95%}*8QP>{#N(<{@f?s zjecY4X!*0F`fB$co~hZmbi(XWJubk^bhC#hUzkkK)Mq_)px9130hRN@zLc+)_EW{4fV{R97DiV zJEQR{)VPEiZ;flj_~{xayXF_d2$_=lCIO!u_VHPkp1)UgjFaGX#9+x#s%n!Z#pv?#pqF7`kcBLR)+2 zguBtoaC1z9abd`A&l&tFAq=~<{1K47Ow@jMwv)hN!+v^NVb08qRw{bpDyjsyi_jrluHA(pxngOdDu^S?|p=; zZ{q5k#~M*DkK#ux^_R+(o^oZNYRZiPISbFP_7<)kTWLX}?SF^p0v8*9W9!4x{ s$g(!hvNjm8lwT?fJ!N5_s>(W=mxujddh=J&ymd5h9a$F7#>+PG56%64%K!iX delta 148 zcmcaDdWA7%IWI340}#~ttjM$n(vLwL7+``jJ_`XE(-~42QW$d>av7r-85vTTf*CZK zUxE~9GTvfMOv%m6^V4Ly#g~$mn3tZfmzKp_COWFNBt diff --git a/core/__pycache__/apps.cpython-311.pyc b/core/__pycache__/apps.cpython-311.pyc index 2fa4a49f9779402d93d4c58688d65ede2fff84d5..49d5f62c69bce23890a7b6c8bee4c64c21f2c2c1 100644 GIT binary patch delta 20 ZcmeBS>0#kn&dbZi00hjzrdbPlm;fk&1DpT= delta 20 acmeBS>0#kn&dbZi00ebDD>4`IFaZE9?*xJX diff --git a/core/__pycache__/context_processors.cpython-311.pyc b/core/__pycache__/context_processors.cpython-311.pyc index 75bf2234fb21a6b62efc5cec11af9512dd0c9616..e1dde4f30f1b3346a8fd08500d77829537a5e43a 100644 GIT binary patch delta 21 bcmey(`kR$!IWI340}wC=n`Uj~dCvp@Keq*Y delta 21 bcmey(`kR$!IWI340}xbw%g@}%^PUL+NjnD4 diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe54f6151737107332cd87e376bf9e870abcfe25 GIT binary patch literal 2272 zcmZ`)%Wo4$7@vJQiQ^bt>Np8B15`35i3=3kD$q!@g$gR7RzRxy;!Zq6y!Lw6o!KqK z1r=2ste#MXM2d3ADQ!jn7zbIZwGt9iPq`U|6Q_Q&YbPY6Fsy{%~U`j>r@t}1L zp{MXhqhL_;I?Ba1;$L%j(Pp*JiD0FOA;P}2t+OzHj2J2?6cyA^ zqXHV$brrP08;ycSwFju6OKU)*0UFI9`G)Yzpmmpm@bbXCbsu0y0nuo zFVmR+9Jbx^EdI*3EmFqR!q-70sr#Hn8n3cCah9erB@V%7PMyLP-y_o)4p|QV5UeZv z4i?O2f>`;S78oU)2odPqy)A-x-6kbgc5TYI%n;&vTm%LOiL5ae+85HecmEk-TX2-i z9NCnq+L)zo$*(cT%YzdxK|TTb+42>7BHL$ieXs6&*iS7a)5C@7Y_!CMTgW_u^0>$i#3<}wxoxP#UFfPM>||v6Bw|` z?7+NbF`J6Ow8HW-xD6)8N3-L@zgF8)GWa0b0jlw8g}2n!`&Uk-Gc z3S34a2CsMmaDV&PIWW;QI;qLEvDU$B>|3RvJd@7KX)>dow2i>(Tse6XX4v#B9;f92r|GE z%K#5RH!<=Kr~+uld{`5khk&6mdjs-Zg!N@P zR*l$@(zr@Esd|iKvP1wJ0!J)?ZMJBY@gn0jQgui^X9U9~n-Pc6B83_Z4BymjO~;1rhu?xRk6 zyq(VenP{g!`X_ziS^C08daj+GYsR0)N18uv#3$PEiIv4?aomdI=c&=Wb51I>qO+p zUb|=<+27B-ZJFKTV*v1RD&0;UU%S#y<(siiJoWIKU(YwsuVmLQKABpX>U;I(Mrxs* zT4)U~bdu@jNa)o0oXIoN7McBgT!NI#rzPYi9F-83lS~IL(>Vka2vGpo=>lE#T?4A{ zZFniyUhQn;bz=fbzYoK@F)F8fAyO+ff|-FyE6|JGD1XhcyNRgP4PKM2PX4(@=Iu85 z^}vOwPtNf(AWGJ@C<1gfMNv8^)7t&KK$ETAPuD!AfN5{TL-xphDc4`^vl$xyAD6^7 A@Bjb+ literal 0 HcmV?d00001 diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index a251b5fb7c2b603c587f8162d643eb10596d2858..cffc914ff4621a971fa5c7dc87de7ff1dd500bcc 100644 GIT binary patch literal 6461 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 delta 127 zcmdmMbdgbTIWI340}#~ttjM$k(vK$#@`zdq0a?=-QW#Pga~N_NqZk<(Qka4nG?`z5 zlxi~GV$01>NzEzt(`35EnUa;5m!7Yel2pVDl$;#MYA*VV!v?6JG$+-rhyy6b2*ky* SlLIBBxGyls08tSePy_&HAsvGN diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index f705988a223abc7b5af333902925bc196186bbf5..821d1f4664b009f490b3bb8fb2152f9e58b5c05b 100644 GIT binary patch literal 529 zcmZ`!J5R$f5Vo63+BB3RCWMeWS3>o~07RYGkXXu;1%=w`E04-aXknpaM>aYl1|EVR zlS&<`Oh`=Kin?{ePGJDS`E1{P-`)B1W1)~o!tQH(?GJIk%jDa#U%{d;f?Grp#SU_@ zg)yQTsyG=}u@o09a8*miD1#WLz*MTfY7YuRFJiAOWwH!t?oUQ%3eEp!8j7V+qlU_B zGdZM;6X@DubB1N2Bu3p1*coM^-EtB=O`KK`CeZXU3;F+_oo5;E=u&uAeE(Q=o_ zcS&>}d0|9YpVgz#=cMQJPSCaMjMRNDXfe6cyq5gP&&`TW delta 232 zcmbQpa+|4sIWI340}#~ttjNp)(vLwL7+{4mKHC5p(-~42QW$d>av7r-85vTTQkZj? za+#x;85x)uQW;ZNQkhd&*RU;PW?)zi#1N3q7{!vp9?YQ0@e(AU$#{#UAh9IlB_ouR zA)23?dW)e5WD!U*FEKaOPm^^rH>2ESV@6*tKA<>AZL!znE=CzM@e2$n=mQ%AD`$gC ghfqhz47Lj_@)ud;udv8}U}oZHYTyRJA|9Y-0FS#bYXATM diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 2f0989c7137f7930a63ea76fcd63516c4974e834..733da46296207059f6a4d1b6187adb8a2dbd7fd1 100644 GIT binary patch literal 21854 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 Aa{vGU literal 1364 zcmZ`(&1)M+6ra_{dS%J>I!@|TuH%hUh$T{~CE!96oTjQ1+$K)2Q%ZHHP<`ZWm8k%0`!Liw{@%1fY!tdJefM7AQl zBhn19Sa6Ea_&F0f52+#t(zs7E+?3c%aE4Gt31lN`$cK>CaWDY%0l$fN{S4(m*^98b zAQFOZ8L?*M5b8J{)dItqY^-hhUDsF{YgW-QOsAxII>p%0Y9=dd7Ae9|G&s?)vtv@? z*w|s3fmzYCyi6leblsZSXw)-0vAJ^Fb$=8ZkKM6~%pxUIZ^SlnP1|O53-h^$TMxcl z&pj%9yS|;<+IaYARqQc33p$+=>?7eip%aJUUFM01nxMCzWy{3I+3Mq}!>U=li}flaG+QI|spl4T zob~hDF>%eyxOE;8-gFVJ3n+Sj0BfPw>ijEJJ5jZcy4+QlU#Tl6>PkmVchz)jqo<{g zem>D|w6z=i>HYM}h1U1|$#c)H{hoQ2Y2^ko`uNk{{Bl3J(n+Sf$#g%t+)aMbNnYMq_I%*JNq0Rq;#`{q1K zoZG+JUbuEt>cm&O@zr)@^%Rl>0Md)F(RpB8KAS2P06puedS=OZWkMOW!1G(l6GL;A z0R;Uy__hCq=p}LW6JT$Zn>I137G9%QKox%h?+LI$Sdye3inaW&hh|#-_ZofP9$!6l Xr9HlS=yH2}4P;gNa)91vejfh;`i@)& diff --git a/core/admin.py b/core/admin.py index 8c38f3f..0b4c1a6 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,3 +1,43 @@ from django.contrib import admin -# Register your models here. +from .models import ActionPlanStep, ProblemCase, RootCause, SolutionOption + + +class RootCauseInline(admin.TabularInline): + model = RootCause + extra = 0 + + +class SolutionOptionInline(admin.TabularInline): + model = SolutionOption + extra = 0 + fields = ("rank", "title", "impact", "efficiency", "speed", "low_risk", "decision_score", "success_rate") + readonly_fields = ("decision_score",) + + +@admin.register(ProblemCase) +class ProblemCaseAdmin(admin.ModelAdmin): + list_display = ("title", "business_area", "urgency", "priority_score", "financial_impact", "status", "created_at") + list_filter = ("business_area", "status", "urgency") + search_fields = ("title", "description") + inlines = [RootCauseInline, SolutionOptionInline] + + +@admin.register(SolutionOption) +class SolutionOptionAdmin(admin.ModelAdmin): + list_display = ("title", "problem", "rank", "decision_score", "success_rate") + list_filter = ("rank",) + search_fields = ("title", "problem__title") + + +@admin.register(ActionPlanStep) +class ActionPlanStepAdmin(admin.ModelAdmin): + list_display = ("solution", "day_index", "title", "is_done") + list_filter = ("is_done",) + search_fields = ("title", "task", "solution__title") + + +@admin.register(RootCause) +class RootCauseAdmin(admin.ModelAdmin): + list_display = ("factor", "problem", "contribution_score", "parent") + search_fields = ("factor", "why_chain", "problem__title") diff --git a/core/forms.py b/core/forms.py new file mode 100644 index 0000000..ae1e584 --- /dev/null +++ b/core/forms.py @@ -0,0 +1,40 @@ +from django import forms + +from .models import ProblemCase + + +class ProblemCaseForm(forms.ModelForm): + class Meta: + model = ProblemCase + fields = ["description", "urgency"] + labels = { + "description": "Masukkan masalah, target, atau hambatan Anda:", + "urgency": "Tingkat Urgensi", + } + widgets = { + "description": forms.Textarea(attrs={ + "class": "form-control problem-textarea", + "rows": 9, + "placeholder": "Contoh: Kuliah di Singapura atau Jepang, dana 200 juta, ingin 3 tahun selesai.", + }), + "urgency": forms.TextInput(attrs={ + "type": "range", + "class": "form-range urgency-slider", + "min": 1, + "max": 5, + "step": 1, + "oninput": "document.getElementById('urgency-output').value=this.value", + }), + } + + def clean_description(self): + description = self.cleaned_data["description"].strip() + if len(description) < 20: + raise forms.ValidationError("Tuliskan minimal 20 karakter agar analisis lebih bermakna.") + return description + + def clean_urgency(self): + urgency = self.cleaned_data["urgency"] + if urgency < 1 or urgency > 5: + raise forms.ValidationError("Urgensi harus berada pada skala 1 sampai 5.") + return urgency diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..08cde5a --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,82 @@ +# Generated by Django 5.2.7 on 2026-06-19 14:38 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='ProblemCase', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=160, verbose_name='judul kasus')), + ('description', models.TextField(verbose_name='deskripsi masalah')), + ('business_area', models.CharField(choices=[('sales', 'Penjualan'), ('operations', 'Operasional'), ('finance', 'Keuangan'), ('marketing', 'Marketing'), ('product', 'Produk/Layanan'), ('people', 'Tim & SDM'), ('other', 'Lainnya')], default='sales', max_length=32, verbose_name='area bisnis')), + ('urgency', models.PositiveSmallIntegerField(default=3, verbose_name='urgensi')), + ('priority_score', models.PositiveSmallIntegerField(default=0, verbose_name='skor prioritas')), + ('financial_impact', models.CharField(default='Sedang', max_length=32, verbose_name='dampak finansial')), + ('status', models.CharField(choices=[('draft', 'Draft'), ('analyzed', 'Sudah dianalisis')], default='draft', max_length=20)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + options={ + 'verbose_name': 'Problem Case', + 'verbose_name_plural': 'Problem Cases', + 'ordering': ['-created_at'], + }, + ), + migrations.CreateModel( + name='RootCause', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('factor', models.CharField(max_length=120)), + ('contribution_score', models.PositiveSmallIntegerField(default=70)), + ('why_chain', models.TextField()), + ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='core.rootcause')), + ('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='root_causes', to='core.problemcase')), + ], + options={ + 'ordering': ['-contribution_score', 'factor'], + }, + ), + migrations.CreateModel( + name='SolutionOption', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=160)), + ('impact', models.PositiveSmallIntegerField(default=70)), + ('efficiency', models.PositiveSmallIntegerField(default=70)), + ('speed', models.PositiveSmallIntegerField(default=70)), + ('low_risk', models.PositiveSmallIntegerField(default=70)), + ('decision_score', models.DecimalField(decimal_places=2, default=0, max_digits=5)), + ('success_rate', models.PositiveSmallIntegerField(default=70)), + ('rank', models.PositiveSmallIntegerField(default=1)), + ('rationale', models.TextField()), + ('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='solutions', to='core.problemcase')), + ], + options={ + 'ordering': ['rank', '-decision_score'], + }, + ), + migrations.CreateModel( + name='ActionPlanStep', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('day_index', models.PositiveSmallIntegerField()), + ('title', models.CharField(max_length=120)), + ('task', models.TextField()), + ('is_done', models.BooleanField(default=False)), + ('solution', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='action_steps', to='core.solutionoption')), + ], + options={ + 'ordering': ['day_index'], + }, + ), + ] diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..773b1018a0b068c08cf8046b7fcd5693ee2ac520 GIT binary patch literal 4917 zcmbVQO;8(07M>aX^Oq4eCK3V(V@%{9gzcEv#>VEyV2r^S5mHOGG8xp37#PhcGb1oc zZLJS`*kf+tum@@n-r9-|K61!`qYry%Rn0*)r&R5Un^N&9r+wXnWd2;iJ3?=!yI;S4 z?|a|t9`Uc{<^~R~uNQ8wJq&Z)e`%w3`3@d_8;6G&FyI1M=^Ysi+OYo_DR=?JT4=0KO- z+724OJ@wPIFU&?%Pn~Y4*S+%#J!M!JkS$Z3)Xvh#3L{AmHe;0;0Ju&Yehf- zrWvaBpdbpB8eR*a1>d?>BhzBo&_2{uYJSaw4t(7UEVUf9l;zMT|KyQ~!l<=$?!>z1 znRa7sK59c3O6@1s{q&et1VvBL>NvVGiou$lrLLoxgNN~BdI{8>70^Z0Q@V6Qx0mTQ z)&1j3mrq38cS7g0<2u;}ltfq1)hv&${linbesmp}e>iXbACb4zu~-I5H;%83ZZe(s z7~d*=enRIq)2V0nH3a-qEocrf8)W0nwJzWhk6YG0skPSv^(V3Z1eN1n=nHhGboVt> z!B6!{0Gs!Y+WZK6L+F0#!BGrXgsdM8qlYM!6%_st5PtL#2%o5oQxG0G1Hz+c&>1^} z&iEO09y6WRI{p(Vf+kB(jw6Pq&S2~5F`emC*z=6(e3(7|f2L=*ue3jmai<1O-hv!qj-u>omy)OP4YRmMx5&#=N2AWMfNO$6HRw z#D*fPN)bCv8`xOZO)P104m&LoHuk-$XLY|fCUxS zQ_tir8K%RKKacgiii@EIC6~CINRQ7zr%$(5vEc-s$%>|J$p+2!euBkM{Y@+@rlyzx zXCSkxD;aP*fbfc3P%VRQoo!b;RFZ$jbMi6pQL^5=&Czyf>3Q3P^{Jj%?(~>QgDjzcB z70dCB(;LJX1OU{nB1T0qT|n|`0x7gdF%{EDf*Mt8V4Wv2`I{)9VD zbK-V&`|yz5~L zs>i@8gMm3ISUTe$twyJj&X<@0vnVo)KutQ70cZg2N8pDsLd7T*H$fE7T|eo!(~{Oz z7RPfIyW>CLMgv}1Q8Ef89+XrbLzM?r$d93z>rM;88AxzFc*?hZdYl8KY%B*P%d0Xl znx!0GW}&{3l2t6zX)+5L7%(NMNbGnGh<%^FG&&)-M4^0P4>|D4EPitR=weRGNQUA* z2cV@boOeP<-jWmz;g^orlEJ%xVoFHYprmV7fM0BmWWofqc#Z*98+4OCn{0D}65FUG z$!U-zc;zmr7@nIX={wj+XcC|mP&CDY5^|6B=8Ujf2Mp{L*qCBXhb5CO2>zP*bNg3up0xR`WPO1RDx=H5(>?I!acX zhF#W=)}VBCM?lL?kP!wjaROr_>9LXV$4=8YWC-lJ6PreLUB$A-S_b{)@Ne!nklgPN zQ>%IorwYpj%_^kuOPm33jnt-Ytedb$;1q=__5Ped{xO zfdsGWpI=&9UrkoM{CWSYXVoAVivPXA4t7<-UB86eNc)u^HthB*yWY2#$dW`fgS4CF zcGGS*iD*^ApOWa6?aOxb%A3sFW)fX2M;GnrA`!oW=_E0*gt@nt0(Astt@2knll#2%JB(1K0(CELj$`DBtBY>kJ|B3B92wt8qc>>qg;2Y z(l=P?yt4hg8t}HYR5>a-&xIO(^Jso)}GZN=D+e&H1t{F8-|I*Fp(H062s(MzyuO>ohIn|uK(wdedmdN=Y@UePh_p0#T&#sDyo-14sYPp zFy+*6x$BYL^@xZgM|O;(Ie<8mG|pr>a@CGpCE_(kpA@A}YS%|%!{ykp9UCU%!wRKE zKSjBJ_rlK+`|gx|ciz6cM3ha4^Dq27Wl>j}@(Lux36k<^;SjI3zuulXl~Xx>oNx8N zdP+Y=uC{L`{Z7Q)%lpxCzx$7#{@R9atbiJvaBQ!KadytIqs85LRceKq(%|X$;C=Vh z8aBRzCOuS5s!{duJYV&5d^h0|?q7xbjGXpY^-uG>zsj91e`v79OTV(gcOOt;-uw@R CMl>-1 literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/__init__.cpython-311.pyc b/core/migrations/__pycache__/__init__.cpython-311.pyc index 799581567d2858c54584d0675ede42b2d728f5cb..7b257e29d08973e848841d29e98e47c5acceafc3 100644 GIT binary patch delta 20 acmZ3%xPp;qIWI340}wC=n`TYqnF9bUrvz94 delta 20 acmZ3%xPp;qIWI340}#~ttjL_mGY0@N6$L&3 diff --git a/core/models.py b/core/models.py index 71a8362..9fe3bc3 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,107 @@ from django.db import models +from django.urls import reverse -# Create your models here. + +class ProblemCase(models.Model): + AREA_SALES = "sales" + AREA_OPERATIONS = "operations" + AREA_FINANCE = "finance" + AREA_MARKETING = "marketing" + AREA_PRODUCT = "product" + AREA_PEOPLE = "people" + AREA_OTHER = "other" + + BUSINESS_AREA_CHOICES = [ + (AREA_SALES, "Penjualan"), + (AREA_OPERATIONS, "Operasional"), + (AREA_FINANCE, "Keuangan"), + (AREA_MARKETING, "Marketing"), + (AREA_PRODUCT, "Produk/Layanan"), + (AREA_PEOPLE, "Tim & SDM"), + (AREA_OTHER, "Lainnya"), + ] + + STATUS_DRAFT = "draft" + STATUS_ANALYZED = "analyzed" + STATUS_CHOICES = [ + (STATUS_DRAFT, "Draft"), + (STATUS_ANALYZED, "Sudah dianalisis"), + ] + + title = models.CharField("judul kasus", max_length=160) + description = models.TextField("deskripsi masalah") + business_area = models.CharField( + "area bisnis", max_length=32, choices=BUSINESS_AREA_CHOICES, default=AREA_SALES + ) + urgency = models.PositiveSmallIntegerField("urgensi", default=3) + priority_score = models.PositiveSmallIntegerField("skor prioritas", default=0) + financial_impact = models.CharField("dampak finansial", max_length=32, default="Sedang") + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=STATUS_DRAFT) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta: + ordering = ["-created_at"] + verbose_name = "Problem Case" + verbose_name_plural = "Problem Cases" + + def __str__(self): + return self.title + + def get_absolute_url(self): + return reverse("case_detail", kwargs={"pk": self.pk}) + + +class RootCause(models.Model): + problem = models.ForeignKey( + ProblemCase, related_name="root_causes", on_delete=models.CASCADE + ) + parent = models.ForeignKey( + "self", related_name="children", null=True, blank=True, on_delete=models.CASCADE + ) + factor = models.CharField(max_length=120) + contribution_score = models.PositiveSmallIntegerField(default=70) + why_chain = models.TextField() + + class Meta: + ordering = ["-contribution_score", "factor"] + + def __str__(self): + return f"{self.factor} ({self.contribution_score}%)" + + +class SolutionOption(models.Model): + problem = models.ForeignKey( + ProblemCase, related_name="solutions", on_delete=models.CASCADE + ) + title = models.CharField(max_length=160) + impact = models.PositiveSmallIntegerField(default=70) + efficiency = models.PositiveSmallIntegerField(default=70) + speed = models.PositiveSmallIntegerField(default=70) + low_risk = models.PositiveSmallIntegerField(default=70) + decision_score = models.DecimalField(max_digits=5, decimal_places=2, default=0) + success_rate = models.PositiveSmallIntegerField(default=70) + rank = models.PositiveSmallIntegerField(default=1) + rationale = models.TextField() + + class Meta: + ordering = ["rank", "-decision_score"] + + def __str__(self): + return self.title + + +class ActionPlanStep(models.Model): + solution = models.ForeignKey( + SolutionOption, related_name="action_steps", on_delete=models.CASCADE + ) + day_index = models.PositiveSmallIntegerField() + title = models.CharField(max_length=120) + task = models.TextField() + is_done = models.BooleanField(default=False) + + class Meta: + ordering = ["day_index"] + + def __str__(self): + return f"Hari {self.day_index}: {self.title}" diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..734e268 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,11 +1,13 @@ +{% load static %} - + - {% block title %}Knowledge Base{% endblock %} + + {% block title %}{{ page_title|default:"OPTEMA AI" }}{% endblock %} + {% if project_description %} - {% endif %} @@ -13,13 +15,17 @@ {% endif %} - {% load static %} + + + + {% block head %}{% endblock %} {% block content %}{% endblock %} + diff --git a/core/templates/core/_nav.html b/core/templates/core/_nav.html new file mode 100644 index 0000000..c3b431c --- /dev/null +++ b/core/templates/core/_nav.html @@ -0,0 +1,17 @@ + diff --git a/core/templates/core/case_detail.html b/core/templates/core/case_detail.html new file mode 100644 index 0000000..8bb6269 --- /dev/null +++ b/core/templates/core/case_detail.html @@ -0,0 +1,124 @@ +{% extends "base.html" %} +{% block title %}{{ page_title }}{% endblock %} +{% block content %} +{% include "core/_nav.html" %} +
+
+
+ {% if messages %} +
+ {% for message in messages %} + + {% endfor %} +
+ {% endif %} +
+
+

Analisis Tersimpan · {{ problem.get_business_area_display }}

+

{{ problem.title }}

+

{{ problem.description }}

+
+
+
+
✅ Analisis Berhasil Disimulasikan!
+

Case ini tersimpan di database lokal dan bisa dibuka ulang dari Riwayat Case.

+
+
+
+
+
+ +
+
+
Problem Detection
+

1. Problem Detection

+
+
Prioritas Skor{{ problem.priority_score }}/100
+
Dampak Finansial{{ problem.financial_impact }}
+
+
+ +
+
+
+
Root Cause Analysis
+

2. Root Cause (Akar Masalah)

+
+ {% for cause in problem.root_causes.all %} +
+
{{ cause.factor }}{{ cause.contribution_score }}%
+
+
+
+

{{ cause.why_chain }}

+
+ {% endfor %} +
+
+
+
+
+
Solution & Decision Scoring
+

3. Rekomendasi Solusi & Prediksi Sukses

+

Rumus: Decision Score = Impact×0.4 + Efficiency×0.3 + Speed×0.2 + LowRisk×0.1

+
+ + + + + + + + + + + + + + + {% for solution in problem.solutions.all %} + + + + + + + + + + + {% endfor %} + +
RankSolusiImpactEfficiencySpeedLow RiskSukses RateDecision Score
#{{ solution.rank }} + {{ solution.title }} +

{{ solution.rationale }}

+
{{ solution.impact }}{{ solution.efficiency }}{{ solution.speed }}{{ solution.low_risk }}{{ solution.success_rate }}%{{ solution.decision_score|floatformat:1 }}
+
+
+ + {% if top_solution %} +
+
Action Plan
+

4. Action Plan 5 Hari: {{ top_solution.title }}

+
+ {% for step in top_solution.action_steps.all %} +
+ Hari {{ step.day_index }} +
+

{{ step.title }}

+

{{ step.task }}

+
+
+ {% endfor %} +
+
+ {% endif %} +
+
+ +
+
+{% endblock %} diff --git a/core/templates/core/case_list.html b/core/templates/core/case_list.html new file mode 100644 index 0000000..e1f9949 --- /dev/null +++ b/core/templates/core/case_list.html @@ -0,0 +1,37 @@ +{% extends "base.html" %} +{% block title %}{{ page_title }}{% endblock %} +{% block content %} +{% include "core/_nav.html" %} +
+
+
+
+

Case Library

+

Daftar Kasus OPTEMA

+

Histori masalah yang sudah diproses menjadi keputusan dan action plan.

+
+ Tambah Kasus Baru +
+
+ {% for case in cases %} + + {% empty %} +
+
+

Case library masih kosong.

+

Buat analisis pertama untuk mulai membangun histori keputusan.

+ Mulai Analisis +
+
+ {% endfor %} +
+
+
+{% endblock %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..b4b9bdd 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,201 @@ {% extends "base.html" %} +{% load static %} -{% block title %}{{ project_name }}{% endblock %} - -{% block head %} - - - - -{% endblock %} +{% block title %}{{ page_title }}{% endblock %} {% block content %} +{% include "core/_nav.html" %} +
-
-

Analyzing your requirements and generating your app…

-
- Loading… +
+ + +
+
+
+

Mesin Pemecah Masalah Universal & Decision Intelligence Platform

+

💡 OPTEMA AI

+

Optimal, Effective, Efficient Management Assistant

+

MVP single-user tanpa login: masukkan masalah bisnis, keuangan, karier, logistik, teknologi, atau pendidikan; atur urgensi, lalu dapatkan simulasi Problem Detection, Root Cause, Decision Scoring, dan Action Plan yang tersimpan otomatis.

+ +
+ Problem Detection + Root Cause + Decision Score +
+
+
+
+
+ Simulasi MVP + Prioritas 95/100 +
+
+
Keterbatasan Dana96%
+
Target 3 Tahun92%
+
Biaya Hidup88%
+
Bahasa & Admission76%
+
+
+

Solusi Teratas

+

Prioritaskan Jepang + Beasiswa

+

Decision Score 83.8 · Sukses Rate 84%

+
+
+
+
-

AppWizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} - — UTC {{ current_time|date:"Y-m-d H:i:s" }} -

-
+ + +
+
+
MVP Workspace
+

Input kiri, output analisis kanan — seperti prototype Streamlit.

+ + {% if messages %} +
+ {% for message in messages %} + + {% endfor %} +
+ {% endif %} + +
+
+
+
+ 📥 +
+

Input Masalah

+

Masukkan masalah, target, atau hambatan Anda. Contoh: kuliah Singapura/Jepang dengan budget terbatas.

+
+
+
+ {% csrf_token %} + {{ form.non_field_errors }} +
+ + {{ form.description }} + {% for error in form.description.errors %}
{{ error }}
{% endfor %} +
+
+
+ + {{ form.urgency.value|default:3 }} +
+ {{ form.urgency }} +
135
+ {% for error in form.urgency.errors %}
{{ error }}
{% endfor %} +
+ +

Hasil akan disimpan otomatis ke Riwayat Case.

+
+
+
+ +
+
+
✅ Analisis Berhasil Disimulasikan!
+ +
+

1. Problem Detection

+
+
Prioritas Skor95/100
+
Dampak / ConstraintBudget ketat
+
+
+ +
+

2. Root Cause (Akar Masalah)

+
+
+
Keterbatasan Dana96%
+
+
+
+
Target Lulus 3 Tahun92%
+
+
+
+
Biaya Hidup Negara88%
+
+
+
+
Bahasa & Admission76%
+
+
+
+
+ +
+

3. Rekomendasi Solusi & Prediksi Sukses

+

Decision Score = Impact×0.4 + Efficiency×0.3 + Speed×0.2 + LowRisk×0.1

+
+ + + + + + + + + + + + + + + + + +
SolusiImpactEfficiencySpeedLow RiskSukses RateDecision Score
Prioritaskan Jepang + Beasiswa/Part-time Legal8886727884%83.8
Pathway Hemat: Lokal lalu Transfer7688688680%78.4
Singapura Jika Scholarship Besar8258865566%72.9
+
+
+
+
+
+
+
+ +
+
+
+
+
Histori Keputusan
+

Kasus terbaru

+
+ Lihat semua kasus → +
+
+ {% for case in recent_cases %} + + {% empty %} +
+
+

Belum ada kasus tersimpan.

+

Gunakan form di atas untuk membuat analisis OPTEMA AI pertama Anda.

+
+
+ {% endfor %} +
+
+
-