From 4563f117e1c823fa9832373b46b432fd7a172f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=9C=E6=9C=AA=E5=A4=AE?= <2996985766@qq.com> Date: Mon, 15 Sep 2025 23:36:33 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E9=80=9A=E7=9F=A5=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__pycache__/__init__.cpython-310.pyc | Bin 200 -> 242 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 347 -> 778 bytes .../inherit_res_user.cpython-310.pyc | Bin 999 -> 1007 bytes .../yuthon_hr_department.cpython-310.pyc | Bin 890 -> 6686 bytes .../yuthon_hr_employee.cpython-310.pyc | Bin 5846 -> 27771 bytes .../__pycache__/yuthon_job_lv.cpython-310.pyc | Bin 922 -> 620 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 190 -> 372 bytes .../hr_employee_wizard.cpython-310.pyc | Bin 2268 -> 6999 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 166 -> 208 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 180 -> 272 bytes .../__pycache__/yuthon_notice.cpython-310.pyc | Bin 2582 -> 8091 bytes yuthon_web_notice/__init__.py | 3 ++ yuthon_web_notice/__manifest__.py | 35 ++++++++++++ yuthon_web_notice/controllers/__init__.py | 3 ++ yuthon_web_notice/controllers/controllers.py | 10 ++++ yuthon_web_notice/models/__init__.py | 1 + yuthon_web_notice/models/hr_employee.py | 16 ++++++ yuthon_web_notice/static/src/announcement.js | 32 +++++++++++ yuthon_web_notice/static/src/announcement.xml | 6 +++ yuthon_web_notice/static/src/main.js | 51 ++++++++++++++++++ yuthon_web_notice/views/templates.xml | 14 +++++ 21 files changed, 171 insertions(+) create mode 100644 yuthon_web_notice/__init__.py create mode 100644 yuthon_web_notice/__manifest__.py create mode 100644 yuthon_web_notice/controllers/__init__.py create mode 100644 yuthon_web_notice/controllers/controllers.py create mode 100644 yuthon_web_notice/models/__init__.py create mode 100644 yuthon_web_notice/models/hr_employee.py create mode 100644 yuthon_web_notice/static/src/announcement.js create mode 100644 yuthon_web_notice/static/src/announcement.xml create mode 100644 yuthon_web_notice/static/src/main.js create mode 100644 yuthon_web_notice/views/templates.xml diff --git a/yuthon_hr_employee/__pycache__/__init__.cpython-310.pyc b/yuthon_hr_employee/__pycache__/__init__.cpython-310.pyc index 3fc365c6911d4310f959fef343caf3c09e5e951c..ef3c61379e43ea5607bb46b929825d20ae6aa199 100644 GIT binary patch delta 133 zcmX@X_=%A>pO=@50SMl$EYEPC$ScdJF;QDal_7;Whas0aikXoig(a9lll3JdP>m+z zE$-y}ypp2)oSf96;)#J`#w@oOikN^>Ma&?A1xT!9C}IP#LBucf6sws0l>B^MLvuX? X-OAFEjQqTby~bQ1Ngf6sMgc|uL24dk delta 109 zcmeywc!H5PpO=@50SMAgPf636$ScbzGf`W{jX9V>ljS8NP+XJo7F%w9N@`9qh*h3h zl~|PGr^$Sap@<16Tf__`Rx%W^g4iJ9mwt*>Onyp!zM*-1^2Dvi94tUV9tHtM0K@$m Av;Y7A diff --git a/yuthon_hr_employee/models/__pycache__/__init__.cpython-310.pyc b/yuthon_hr_employee/models/__pycache__/__init__.cpython-310.pyc index 75e986c35d0d43b57dd6e38a83a748b7ce4a198c..daa0f7af6ae4fbab0769eaabe656e6f1e897ce03 100644 GIT binary patch literal 778 zcmZ{i&5qMB6osAsq-mQ!3XH^teHSx=6%s-to`4NIE0UEVR+5nuTXq5}Z!~YfvvfPF z+3*0YIM>tCY;csL&&R&@No<`Y8;17#;YSnB7<;77w83Ma@w#7-idBJPUBH8Ycm|&F znddop&gY&N;00fJUV@i=={W?4JoLN*ulUMy1de#*c@19kwdW0Z!#AF{;4R;Jj=?dH zJtyFVC!SMq%2Ur7IO7>O|H}3+o&v<*2gluE92(t=#tPXPr4LfV%_m)9%9_07H1l5H z3H2Sut4nDmO=*Wt_5&5SeIso<2rHc!owV@MvxkMT098+%(iqi#D}D9Vzm6ENv2b!2 z+P+4`8#CUi)-~cX<1+YilFn#HC60DE*%a?ES!;LRoif%|kA`MvPV2t*nT6GgzWViP zflgLPs6+ft4+oL6d#r3ppj;%F>dI{Ji+A{G|At zGEK%?0#Jd{;?$z}qWqlH$r_A0%zm0|lO33(C08;OaR5yN6Ti$-tYY$0^79SNh3q7H$!B!!VNE22eM%FyYnF%R&HS)PKBi@zWz4N* zO=T8qp0X!Bw<1DiR|DZz!mOd}n&;1YzRFaJjoCt6$?7WYo~TJT486d|pwTCa6;Bi+ z)IKj|AXVz|(3LEfX!_n?5|#V$gzxH_=4yFeXn8~Ec~cm9OPKkDYnPM4!eX)9GiKi5 zdQv!N^n8lt6w7Ir(=2CL&agZLc~}gwJi_uY%cGFT1htGUT(hW&(KAMV4Y!T;wXNm0 zYx>&8xor*4vkr1ntYvvUrZL(`n;asE^ZLJPigsU(YHg~DE2HGA}jV% zZ+@q^N!*OSUFf?`>=P5{yG7i}eb@6`2Ijg=+|DgGxLeA*#r@(garY^j`9_{`A4c3G zKEosS#Pgu#-p(vyzxXV^kQE2SefYmu92B3!|C_`eaG3|xns3#k>A-(P9&&3%8C6|B zx-vX1Cq%cZEWcQF8*5iu3MIJIj$&A<55fA&^RF+z@OtanGnZd``y22+JB*~~Pbnvo z#nMrhq&rjhq$_&HUw-a4AHMZcR+qz=qNn}R#f8h~UhZjVoqN0W(#f8N51;zshx32n zhNTzZYCZev(z*ASetD|C1{1{%t<$f!-Z>esi^sK|{zdD;`%5qUcKL;Ovj%@sC51a# ztXCo)aQV5Hm!5xm>4je{wZGkZ<(>Y9%NKsK^wP`m6g`V+y??fK_IHg80%)QXRBJ_l zwr*n~tGf?ye8LU zy*xg?mDd;SH4tqd>Z`5uUlY{PM43`>Rp-MzvOt z+z!69-{p;=S<*-4W)$@liluXJ#F|oTyDxeni_oOnPzc?kEKL{4H4DLHr=z_hUWx?V zYH&IpsLZ-22s!$UEkCR*Myc%ITPg4H_34Fj#IwK@Yox zV>wMlE9A4WyL3$MAnhA2J$y2kCXNli@4UEy9zL z4PDsJ7cBKT6GacHot^1c2<${_Nrh!iu0yGF2~(8yqu5SlESN%Hgb8L0a;>b9tCNme z7f-fcdnSgLOYfZlz_ng^?b7={>V=)ZUVI7~xdo#oeM-`YB>@Q_jrC+pw-iXRN+W7r zp)~E5juxP9L=o*H@~SS)6B220jE&Hdanky@v1gEW2EE*;gajrbD!@v369OyY>l9H7 z+9DuM=$o_!c%Cq!2KJ{#9dXv_wYZmjO)p#IZHsz2Q8w8(ALx#vIcP*ufIyrgg_?(u zLIo%UYO$O?XD;fxHiH;OERW4uO^a5r;D`*-h|V|be|8%Hq(r9NrTfnhcEN#n=Hj6r#0nO%S~#Cby* z6Spb@=ttERd{OBG6)%h^U=BV&v(eP!TI0b1rWQe=XI)WHz@7^6o{$WJQn3;qgwUDp zQ&%kSrX}3dUB|s$iPy%kcK~euD;g;TN6LWp_M0$zf7fa= zZ21q$y$e%^gj-HxyS@u>HDcfaV5R@%*pv{QtHxF9qsGMlW-~R~V@;xLDup}>g10&) zl1oq!a{wQLzyZ81Mlm4R76co@7^N=PQ;A?k2nl18MhRmBe6j#Mqn=n|WV3QgpIE+% zpCSW4f_Wv`1Kgoj@uCiBS+ug%+S*hI{L*yMp91=Ji74`)aKD5Z+OXy5yY;kT{j+iN z0KI(b1fTG!?#_2$YTkJUai%Y55$zc1a*=jrcJW%$60(-E%7N!gB73pBWa1N5f!K0; zbMgl2?GH$~1#J}9A-(Dt9s z<=zO#OkogI5>U?Tb9U2~8v(+AVS?GYq@SVFSzH$;0WjLlxnu+jHN03T z(`teOoH6O3nfrti35Y^^2cEui(~YaD6?q+8KRd(^sZHlrL`4!GCD0sC=6HZ`})58s7(;ISYWQqiF#&!VMIga9(-Vu5- z$E%Z9w@-q6Bx-$ddU^3e>$$gJ-I%yA7BlejTjaWJ!pzv3A9GJ2v*5glv_mvzHM3JY z+dO6!A{6SrH&cgCgyA&i3@KeYh7Gl)@n?T*Sq`zAzc=n2q_&vdeEO7qx};F+>M}xw zb$M4?m-ir0pvzvaLwp7yM!W}%W<{%DC!4@;%(5--j=-zSHkeG}XhPmivcRe1G{6=7 z1y*TV09dnN&unX3AeobQ;@gtaMr;Nm*vo|C%O3-7;hL;#I`;Q=s9Cc2w&M4PttQ8G!f@zIfWP0c>5Bi`(^T)^9f0T$hwyv4NK5^Lb~1X zBlkqqIZB(-os0>Xjg{kI(mC)YX@!`okHHY{WTaSaxOK>qeKdi0`8|A?K@{g{IORs2 zOlc5^8pc%^bI@65;6#09B?KVkVkhsvBhBG7XNn&HR|HF`rZ5(ZzT3@i>?3{GV ziLR;Fv2!5q>EttK(FsSSnwChj;WJGgh96?X59c@%RJwh|KvxT?uH0kPD%K{+vXWLQ z11iX5vPQ)Wifl5z(6Eol;5ZVL1AfKkQRb8z$vTbWU?HIEV8n51C7K>v;uuM*QrV_r zrBWEE$>%XTr0W`jX5u|`^c-1jm_cmrQ>V;YIr%lrn9F5v#tz~vT2Sc%g?qi?779qM zg_(M>!c?GuF`hr|g4nAR#X7&B>;h+dNx4#44-xC2;Lnfs#7+&jq;9_VXg66rk?*|~ zr4th2R$t>}-DfaU$p>-E;THY;2ri81?!$}fJbE1UsY-C9Sm|+MWgVhhheQ;J;w+!} zRXRSu^KHZ^2#^=wy6~k$d?7%nubf9gSZ>E!8R%nba~(P)HdwwImWrR5%gybNIu=(IEi#7P33x&N!;pKXd8u`#*=bVL!*-B z&SgiGMR%pVVKyn>lqjb*8#8oCLCnM*o5H|}AUqZ`yiu;YCrWOO6A<67@XeG;Jc`3d bg}*RpTeww?9qu6EDj!hBaqBdMXTAAvsP7Sh delta 518 zcmYL`&r2IY6vtwG#b^e`oejBId zcg?!K0RbA4h;kYk+=v)wlzb&%06QkY1nZkej9XxSC%!ey%YCL;Fz6|}(-R>Kl^rD@ z!eRS#Vd-#B`+{%^gd0FP6K3DaTb)pDBb&$tWDD6rwvpdxEy>H%j*)7f}>e|Gh7G4ZLg zhpFtvyV)m}EZf>v1rVKJ6sDMbf0Nx!{@#tRXXDE)e| zAQfpZ5{kvi4^?VQp@kMIj)(#2oXCnU!|?bSKJFxtB=6T+?JPCd>eA9)euh;Y9AZ+} vaOv}|(0Pg(TfUwBTB@yD&HT+#dhPl|Z*{$LHuR^ALa|BnmZlC>T4VnK9N~z) diff --git a/yuthon_hr_employee/models/__pycache__/yuthon_hr_employee.cpython-310.pyc b/yuthon_hr_employee/models/__pycache__/yuthon_hr_employee.cpython-310.pyc index 7e7db81db237257e2d7b9f01140cd64e6376d1de..2a46ff2014b22cae8ea3b5525e34b6c835d253cc 100644 GIT binary patch literal 27771 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 literal 5846 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 bVl;f*$ZX%od>7uvE&(RH1+0N>y{_ti_HFT- diff --git a/yuthon_hr_employee/models/__pycache__/yuthon_job_lv.cpython-310.pyc b/yuthon_hr_employee/models/__pycache__/yuthon_job_lv.cpython-310.pyc index e46a4ef234de835d18aec2342fe0e1c265734dc4..562f22f8004c7160fbaccc524c1a9b20a2645dc0 100644 GIT binary patch delta 413 zcmYjOJxc>Y5Z%4cz2x#?qk#mplOrUUDj-1w5wS3ZqQxS{a5Ip|T~_xJ{Ad+x!*zC+ zY5YO=2T~~h04sOTLI>tCZ+70iUG~-ew92AXDi9T4i`!9)&dUvYJa5)}K){IX*x^p> za+eat&4|T}v%Izx2aE{9-)}jLbVtQ0_}9WL7yFMq?OG z$6}H<0-7;JaXOB%A8PymK^56mnbZ^@;S>lrfN~QIZh^_|+{R9ubaQR_{?rXw*) zKa5VpQzJ~@K?5TewJ4)fcLP5?H0zfYEoMN&J^9M+*U|;|M literal 922 zcmYk5O=}ZD7{_P!Et@pyn=kY$#d�Ke5D zKP!g93}gf*G6M@)5ZnU9Am%C{CN;bEV-q>Vx(BNEv5Wy#OPF4- zBb-);`XmxgzzFpt0dZ5g^W&u0OKGJ5K?0CLATp`dwN;5BM2_SFu{67yZOui^j^>i) zg61jBuI94lqUMU`lICg2Gejw8y0fG_G|-&3RJ3=VOv{g%5mWb*xXr@btZ}EmQW@w) zt;-rUzn_$4!;?oZjt+Ly*TbXTk5wp~DCV7TNxRamgYo8v^y_HyWi_uoHKd<64!;j` zilc9P<2TRJ(c9yvYdYlk;k&~h+mr3lWPd*?%6jRO_v!N;smMwktf#Nm@(I?rWPqHF!ZrhytN4FY)6nV&~I|V6l2exEP0CKrt32jO8IEzTz^*4-(J+=drbfn<|-g zz3p*fDUYyk`pk<_vEfA&FMCTAxpHSRD)v|uXE@iRyv2Cng-wbZEKDL)>B&8%I7%8( zhYZlH7soUtIf3i>zK#~|4KJo~N0u`~wk)QaoJs@M7FPyo+5`No>`qUAE|W`jMi{$r z5jX2gD{;G?9UE?QOoN`!29(yb`}p6Z+V=ak-hewYjV<43K~65PVA&|c{4;ONLakb? t7KEkhaQO=Xy*pgpWv;@7eOFz0Ej(>4qjSpdUdcB5DwL~8#Vx?|=3i^=A1VL< diff --git a/yuthon_hr_employee/wizard/__pycache__/__init__.cpython-310.pyc b/yuthon_hr_employee/wizard/__pycache__/__init__.cpython-310.pyc index 984dc39a1dd9bd61294fe5066e1a927235f88b0c..cf19d77c549494c55e157064e29edcaa6fc11935 100644 GIT binary patch literal 372 zcmYk2%}N6?5XY1KvPcUm6rW)aEqW3}icjFhTL^?`LN~J6EJ;e)zJ$-=!JAiKWUrol z1y9aw5i=qG{N{sUCT_7fC1CHbpUnrnU+AQkfpZTxpeUkfODtuSB4@xE%O=i&bCyqB z02i#7xCAa)30ysr`sABJo0^UnjThSXtsAr!dvlOpLG&_>Mq`uIIiz0PlaNaN*Dt*e zI*ML~uy;O9Sgp*nY=xDb-2SzBsH>59+{ouB1xkrhfxHnvLq_@8s9WxobF1r{_0?+F s#m04fdx#A`vPdT7$N9MsrZZ89bw7-=JL}Z0)f?P5;1|!yoZ>m7zwZ)bl>h($ delta 94 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 f3vs delta 104 zcmcb>xQvlEpO=@50SM-to|0xbkyqA30LV#UNMX!j$YqRTWMoKT3TDt`e#rDNhUW3f6KCnMffNWZ0RXQN7UBQ^ diff --git a/yuthon_notice/models/__pycache__/__init__.cpython-310.pyc b/yuthon_notice/models/__pycache__/__init__.cpython-310.pyc index 8de08b04397dedf0d43c4cd1605271c33e2fc5ab..5d354a6a3f72c1bf30644a12c5c1082d3581a2ac 100644 GIT binary patch delta 185 zcmdnOIDv^bpO=@50SMl&EYE0|$SbR-0pz4Gq%h_%7X=f&scmt-cV#+OtUqyj}nprXn7d1;wNx$&jNsYS(p znk=^%ikN`56fuJc79g>bp@;g2`IIap@;=Yfr(#+DONH0Df#(^=JClBFPgG}6bLW_ E0H5X>F#rGn diff --git a/yuthon_notice/models/__pycache__/yuthon_notice.cpython-310.pyc b/yuthon_notice/models/__pycache__/yuthon_notice.cpython-310.pyc index b54979de302eede0dcb9db089f1f4b27a43fde4c..5e03e4016e96007a6b334529d3b54456709fd452 100644 GIT binary patch literal 8091 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 J_M=tz{V$&v-Ae!f literal 2582 zcmai0-EUMy6rZ_wc6)cb+fV2x6ckW5F&o9G36h2cjJ~ihjRtQ@ZflS1fsIobFlFgXMx90x)X#V+!&i9OBKJl)hiViGKI%}sboGwF4h z9T>fas7}c|qJ-%)MngAKG%RgBm4~rLnfxk)F?J}s+mL@QPRu=O_)j6F=Nmq z?YM}|6!2+k&=gJ6PB1caQ8zmQ%g`+C0twB`s#!PfQL`?Xb<WbUAQ=wA5lr2D{yPl?Q1)u+jCc=-{rwU>Fd5Jwc>ZOpI9aMi<;nP-R(#LNIAu12`O2&? z4!X8CMeXsdJW&H;pxXA09?P#umM!x*F{aEdcgY)3q zyUou&hymrk*5&K1#U%wixU|&z=-fu&?zz^@YcY@`QghV@Zz$)t7Qc-B53u$Si*@8Q zQ-^>l!5F!J`zC-IqjBVZ_-^Irvv4jS03$b=cm7uE^t<4ue!!KlHkcaUI=eV9O$?(s-A~ZuRjsanj^}ic)**r&?VbAiP69hgd*>^4qIQz@P69hg zUFU^5;RR~c^+7~agQ!kmV2hjp-TYXcgva8wHb(eVT@R;dYJ(hDF6AkLDoqyz+H_@^ zi8_o47=OvyD#4|XC+4uc;(~TUn}`#C8FN`pGLHG@ghrVvhnV!jf=C~9oiHi}US)ht z>XM54Q0;|HDIWO6vhA0cRjE!{Tyl{0LD6=@abVW=ugc2gl2oN>f8M+BpCH8k=^ zZP)*}ag&3j=cM~p8q4Mu!Ry$-@8O(QsLK1Td~>~dercugQ|smz&BYtdd#9mFW$|Gy z`vLEgL^)Lv72j;78kQ~SeB646P3;GXxQpT1$R^u1i9KT0de4<*CNq+EuAlX|Q~OFm zyR%w$rNV=gw)^7R(FAXC%cHV|+?X&dOFkTyCDN7!?YZhoK4V!YsN+}!1|&1KYuv6gK7X_)e7B*{tgFrw>WHm3Nk?!760i&Y`XCAA zUm6oF`A3E!3@La}`8kY$ZN&|;*4<69}1=}Um-v9sr diff --git a/yuthon_web_notice/__init__.py b/yuthon_web_notice/__init__.py new file mode 100644 index 000000000..3b3891601 --- /dev/null +++ b/yuthon_web_notice/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +from . import models +from . import controllers diff --git a/yuthon_web_notice/__manifest__.py b/yuthon_web_notice/__manifest__.py new file mode 100644 index 000000000..3707df115 --- /dev/null +++ b/yuthon_web_notice/__manifest__.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +{ + "name": "Yuthon Web Notice", + "summary": "通知公告模块", + "description": "通知公告模块", + "author": "Yuthon", + "website": "#", + "category": "Yuthon/Yuthon Web Notice", + "version": "17.0.0.1", + "depends": ["base", "web","hr"], + "data": [ + "views/templates.xml", + ], + "assets": { + "yuthon_web_notice.assets_announcement": [ + ("include", "web._assets_helpers"), + "web/static/src/scss/pre_variables.scss", + "web/static/lib/bootstrap/scss/_variables.scss", + ("include", "web._assets_bootstrap_backend"), + # 字体图标 + "web/static/src/libs/fontawesome/css/font-awesome.css", + # include base files from framework + ("include", "web._assets_backend"), + ("include", "web._assets_core"), + "web/static/src/core/utils/functions.js", + "web/static/src/core/browser/browser.js", + "web/static/src/core/registry.js", + "web/static/src/core/assets.js", + "yuthon_web_notice/static/src/**/*", + ], + }, + "installable": True, + "application": True, + "license": "AGPL-3", +} diff --git a/yuthon_web_notice/controllers/__init__.py b/yuthon_web_notice/controllers/__init__.py new file mode 100644 index 000000000..457bae27e --- /dev/null +++ b/yuthon_web_notice/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers \ No newline at end of file diff --git a/yuthon_web_notice/controllers/controllers.py b/yuthon_web_notice/controllers/controllers.py new file mode 100644 index 000000000..aa790aff0 --- /dev/null +++ b/yuthon_web_notice/controllers/controllers.py @@ -0,0 +1,10 @@ +from odoo import http +from odoo.http import request, route + +class OwlPlayground(http.Controller): + @http.route(['/web_notice'], type='http', auth='public') + def show_playground(self): + """ + Renders the owl playground page + """ + return request.render('yuthon_web_notice.Announcement') diff --git a/yuthon_web_notice/models/__init__.py b/yuthon_web_notice/models/__init__.py new file mode 100644 index 000000000..d25661f9c --- /dev/null +++ b/yuthon_web_notice/models/__init__.py @@ -0,0 +1 @@ +from . import hr_employee \ No newline at end of file diff --git a/yuthon_web_notice/models/hr_employee.py b/yuthon_web_notice/models/hr_employee.py new file mode 100644 index 000000000..2646f1977 --- /dev/null +++ b/yuthon_web_notice/models/hr_employee.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +from odoo import models, fields + + +class HrEmployee(models.Model): + _inherit = "hr.employee" + + def get_full_employee_info(self, employee_id): + """返回员工完整信息(所有字段)""" + employee = self.browse(employee_id) + if not employee.exists(): + return {} + + # 读取所有字段 + fields = employee.fields_get().keys() # 获取所有字段名 + return employee.sudo().read(fields)[0] # 返回字典 diff --git a/yuthon_web_notice/static/src/announcement.js b/yuthon_web_notice/static/src/announcement.js new file mode 100644 index 000000000..427914cd9 --- /dev/null +++ b/yuthon_web_notice/static/src/announcement.js @@ -0,0 +1,32 @@ +/** @odoo-module **/ + +import { Component, useState, onWillUnmount, } from "@odoo/owl"; +import { useService } from "@web/core/utils/hooks"; + +export class Announcement extends Component { + static template = "yuthon_web_notice.Announcement"; + static props = ["*"]; + setup() { + console.log(useService); + debugger; + this.rpc = useService("rpc"); + this.employee = useState({}); + this.id = this.props.id || ""; + onWillUnmount(async () => { + if (this.id) { + await this.loadEmployee(this.id); + } + }); + } + async loadEmployee(employeeId) { + try { + this.employee = await this.rpc({ + model: "hr.employee", + method: "get_full_employee_info", + args: [parseInt(employeeId)], + }); + } catch (err) { + console.error("获取员工信息失败:", err); + } + } +} diff --git a/yuthon_web_notice/static/src/announcement.xml b/yuthon_web_notice/static/src/announcement.xml new file mode 100644 index 000000000..efda3f4b0 --- /dev/null +++ b/yuthon_web_notice/static/src/announcement.xml @@ -0,0 +1,6 @@ + + + +

Hello OWL Web

+
+
\ No newline at end of file diff --git a/yuthon_web_notice/static/src/main.js b/yuthon_web_notice/static/src/main.js new file mode 100644 index 000000000..ddfa7991d --- /dev/null +++ b/yuthon_web_notice/static/src/main.js @@ -0,0 +1,51 @@ +/** @odoo-module **/ + +import { browser } from "@web/core/browser/browser"; +import { makeEnv } from "@web/env"; // 引入环境构建工具 +import { mount, whenReady } from "@odoo/owl"; +import { Announcement } from "./announcement"; +import { templates } from "@web/core/assets"; + + +// 当document.body准备好时,挂载 Announcement 组件 +whenReady(() => { + const env = makeEnv(); // 创建标准 Odoo 环境 + mount(Announcement, document.body, { + templates, + dev: true, + name: "Web Notice", + env, + props: { + id: new URLSearchParams(window.location.search).get("id"), + }, + }); +}); + +/** + * 错误日志捕获函数 + * 遍历 error 对象的 cause 属性,输出错误堆栈信息(包含链式错误原因) + * @param {Event} ev 浏览器事件对象 + */ +function logError(ev) { + ev.preventDefault(); + let error = ev?.error || ev.reason; + + if (error.seen) { + // 如果错误已经标记过 seen,就不再重复打印 + // 场景:mount 失败时,Owl 会抛出错误,如果不处理就会打印两次 + return; + } + error.seen = true; + + let errorMessage = error.stack; + while (error.cause) { + errorMessage += "\nCaused by: " + errorMessage += error.cause.stack; + error = error.cause; + } + console.error(errorMessage); +} +// 监听全局错误事件(比如未捕获的异常) +browser.addEventListener("error", (ev) => { logError(ev) }); +// 监听未捕获的 Promise 错误(unhandledrejection) +browser.addEventListener("unhandledrejection", (ev) => { logError(ev) }); diff --git a/yuthon_web_notice/views/templates.xml b/yuthon_web_notice/views/templates.xml new file mode 100644 index 000000000..1dc8800cf --- /dev/null +++ b/yuthon_web_notice/views/templates.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file From c58c987374e41dc6f35c89e66fdd83100f0b7d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= <9664676+pengyuthon@user.noreply.gitee.com> Date: Tue, 16 Sep 2025 11:16:38 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yuthon_hr_attendance/models/hr_attendance.py | 47 +++++++++++-------- .../models/property_meter_archives.py | 1 - .../models/property_meter_water.py | 1 - .../views/property_meter_archives_views.xml | 2 +- .../views/property_meter_water_views.xml | 2 +- .../wizard/property_meter_wizard.py | 2 - .../wizard/property_water_wizard.py | 1 - 7 files changed, 30 insertions(+), 26 deletions(-) diff --git a/yuthon_hr_attendance/models/hr_attendance.py b/yuthon_hr_attendance/models/hr_attendance.py index 5a0eec397..47341ea8a 100644 --- a/yuthon_hr_attendance/models/hr_attendance.py +++ b/yuthon_hr_attendance/models/hr_attendance.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- from datetime import datetime, time +from re import search + from odoo import models, fields, api, exceptions, _ from datetime import timedelta from dateutil.relativedelta import relativedelta @@ -111,27 +113,34 @@ class HrAttendance(models.Model): # 判断是否为上月 record.is_last_month = (first_day_last_month <= record.current_data <= last_day_last_month) - def compute_company_id(self): - employee_date_records = {} - for att in self.env["hr.attendance"].browse(self._context.get('active_ids', self._context.get('active_id'))): - employee_id = att.employee_id.id - # 创建唯一分组键 (员工ID, 日期) - group_key = (employee_id, att.current_data) - # 将记录按员工+日期分组 - if group_key not in employee_date_records: - employee_date_records[group_key] = [] - employee_date_records[group_key].append(att.id) + def update_att(self): + # 定义要更新的员工姓名列表 + target_employees = ["简梓豪", "林紫珊"] + # 定义日期范围:9月1日至9月15日 + start_date = fields.Date.from_string("2025-09-01") + end_date = fields.Date.from_string("2025-09-15") - # 处理重复记录:每个员工每天只保留第一条记录 - for (employee_id, date), record_ids in employee_date_records.items(): - if len(record_ids) > 1: - # 保留第一条记录,其余标记为删除 - ids_to_keep = record_ids[0] - ids_to_delete = record_ids[1:] + # 查找目标员工 + employees = self.env["hr.employee"].search([ + ("name", "in", target_employees) + ]) - # 执行删除操作 - if ids_to_delete: - self.env["hr.attendance"].browse(ids_to_delete).unlink() + if not employees: + raise UserError("未找到指定的员工记录") + + # 生成日期范围内的所有日期 + current_date = start_date + while current_date <= end_date: + for employee in employees: + # 执行考勤详情计算方法 + self.env["hr.attendance.detail"].compute_attendance_detail( + employee, + current_date, + is_manual=True + ) + current_date = current_date + timedelta(days=1) + + return True diff --git a/yuthon_property/models/property_meter_archives.py b/yuthon_property/models/property_meter_archives.py index be7de5f31..06609607a 100644 --- a/yuthon_property/models/property_meter_archives.py +++ b/yuthon_property/models/property_meter_archives.py @@ -17,7 +17,6 @@ class PropertyMeterArchives(models.Model): lessee_id = fields.Many2one('property.tenant.information', string='承租方', store=True, compute='_compute_lessee_id') employee_ids = fields.Many2many('hr.employee', string='抄表人') epitope_values = fields.Char(string='表位置') - meter_type = fields.Selection([('electric', '电表'), ('water', '水表'), ('smart', '智能电表')], string='仪表类型') other = fields.Char(string='其他') meter_date = fields.Date(string='任务日期') last_dosage = fields.Float(string='上次用量') diff --git a/yuthon_property/models/property_meter_water.py b/yuthon_property/models/property_meter_water.py index e03663701..64a756739 100644 --- a/yuthon_property/models/property_meter_water.py +++ b/yuthon_property/models/property_meter_water.py @@ -15,7 +15,6 @@ class PropertyMeterWater(models.Model): maximum_count = fields.Integer(string='最大位数') lessee_id = fields.Many2one('property.tenant.information', store=True, compute='_compute_lessee_id', string="承租方") employee_ids = fields.Many2many('hr.employee', string='抄表人') - meter_type = fields.Selection([('electric', '电表'), ('water', '水表')], string='仪表类型') epitope_values = fields.Char(string='表位置') other = fields.Char(string='其他') meter_date = fields.Date(string='任务日期') diff --git a/yuthon_property/views/property_meter_archives_views.xml b/yuthon_property/views/property_meter_archives_views.xml index 9dae3443a..3aca9d6af 100644 --- a/yuthon_property/views/property_meter_archives_views.xml +++ b/yuthon_property/views/property_meter_archives_views.xml @@ -58,7 +58,6 @@ - @@ -133,6 +132,7 @@ 电表库 property.meter.archives tree,form,search + [('is_push', '=', False)] diff --git a/yuthon_property/views/property_meter_water_views.xml b/yuthon_property/views/property_meter_water_views.xml index 0ecb7e487..01f58d394 100644 --- a/yuthon_property/views/property_meter_water_views.xml +++ b/yuthon_property/views/property_meter_water_views.xml @@ -60,7 +60,6 @@ - @@ -131,6 +130,7 @@ 水表库 property.meter.water tree,form,search + [('is_push', '=', False)] diff --git a/yuthon_property/wizard/property_meter_wizard.py b/yuthon_property/wizard/property_meter_wizard.py index 9f2e39dd1..094c6daa0 100644 --- a/yuthon_property/wizard/property_meter_wizard.py +++ b/yuthon_property/wizard/property_meter_wizard.py @@ -32,7 +32,6 @@ class PropertyMeterWizard(models.Model): epitope_values = row[0].value name = row[3].value type_dict = {'水表': 'water', '电表': 'electric', '电表(电子表)': 'smart', '': ''} - meter_type = type_dict.get(row[4].value) unit_number = row[1].value installation_location = row[2].value if row[5].value: @@ -63,7 +62,6 @@ class PropertyMeterWizard(models.Model): 'unit_number': unit_number, 'installation_location': installation_location, 'type':type, - 'meter_type': meter_type, 'gauge_magnification': gauge_magnification, 'meter_date': meter_date, 'current_read': current_read, diff --git a/yuthon_property/wizard/property_water_wizard.py b/yuthon_property/wizard/property_water_wizard.py index 792dfe6a3..7dc981050 100644 --- a/yuthon_property/wizard/property_water_wizard.py +++ b/yuthon_property/wizard/property_water_wizard.py @@ -65,7 +65,6 @@ class PropertyWaterWizard(models.Model): 'unit_number': unit_number, 'installation_location': installation_location, 'type': type, - 'meter_type': meter_type, 'gauge_magnification': gauge_magnification, 'meter_date': meter_date, 'current_read': current_read, From bfd1b0f4ae379f6779e26c8d562b80bffbc19f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Tue, 16 Sep 2025 11:45:55 +0800 Subject: [PATCH 3/3] 1 --- collapsible_notebook/__init__.py | 2 + collapsible_notebook/__manifest__.py | 35 +++ .../static/src/css/collapsible_notebook.css | 241 ++++++++++++++++++ .../static/src/js/collapsible_notebook.js | 215 ++++++++++++++++ .../views/property_lease_contract.xml | 4 +- 5 files changed, 495 insertions(+), 2 deletions(-) create mode 100644 collapsible_notebook/__init__.py create mode 100644 collapsible_notebook/__manifest__.py create mode 100644 collapsible_notebook/static/src/css/collapsible_notebook.css create mode 100644 collapsible_notebook/static/src/js/collapsible_notebook.js diff --git a/collapsible_notebook/__init__.py b/collapsible_notebook/__init__.py new file mode 100644 index 000000000..633f86615 --- /dev/null +++ b/collapsible_notebook/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- + diff --git a/collapsible_notebook/__manifest__.py b/collapsible_notebook/__manifest__.py new file mode 100644 index 000000000..4d3cf817e --- /dev/null +++ b/collapsible_notebook/__manifest__.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +{ + 'name': 'Collapsible Notebook', + 'version': '17.0.1.0.0', + 'category': 'Productivity', + 'summary': '支持折叠和展开功能的Notebook组件', + 'description': """ + Collapsible Notebook + =================== + + 这个模块提供了一个支持折叠和展开功能的Notebook组件。 + + 主要功能: + * 可折叠的notebook页面 + * 展开/折叠状态记忆 + * 美观的UI设计 + * 响应式布局 + + 使用方法: + 在XML视图中使用 来启用折叠功能。 + """, + 'author': 'TX Team', + 'website': 'https://www.tx.com', + 'depends': ['base', 'web', 'product'], + 'assets': { + 'web.assets_backend': [ + 'collapsible_notebook/static/src/css/collapsible_notebook.css', + 'collapsible_notebook/static/src/js/collapsible_notebook.js', + ], + }, + 'installable': True, + 'auto_install': False, + 'application': False, + 'license': 'LGPL-3', +} diff --git a/collapsible_notebook/static/src/css/collapsible_notebook.css b/collapsible_notebook/static/src/css/collapsible_notebook.css new file mode 100644 index 000000000..162ea0b09 --- /dev/null +++ b/collapsible_notebook/static/src/css/collapsible_notebook.css @@ -0,0 +1,241 @@ +/* 可折叠Notebook样式 */ + +/* 整个Notebook折叠按钮样式 */ +.o_notebook_collapse_btn { + display: inline-block; + /* margin-right: 10px; */ + /* margin-bottom: 5px; */ + /* padding: 6px; */ + background-color: transparent; + color: #000; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 16px; + font-weight: 500; + transition: all 0.2s ease; + user-select: none; + vertical-align: top; + line-height: 1.4; + width: 30px; + height: 30px; + text-align: center; +} + +/* 确保按钮和标签页在同一行 */ +.o_notebook_collapse_btn + .nav-tabs { + display: inline-block; + vertical-align: top; + width: calc(100% - 40px); /* 为按钮留出空间 */ +} + +/* 为包含按钮的容器设置样式 */ +.o_notebook .o_notebook_collapse_btn { + float: left; + margin-top: 5px; + width: 30px; /* 固定按钮宽度 */ +} + +.o_notebook .nav-tabs { + overflow: visible; + white-space: nowrap; + flex-wrap: nowrap; +} + +/* 确保导航标签不换行 */ +.o_notebook .nav-tabs .nav-item { + display: inline-block; + white-space: nowrap; +} + +.o_notebook .nav-tabs .nav-link { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: none; +} + +.o_notebook_collapse_btn:hover { + background-color: #f5f5f5; + color: #000; +} + +.o_notebook_collapse_btn:active { + background-color: #e9e9e9; +} + +.o_notebook_collapse_btn.o_collapsed { + background-color: transparent; + color: #000; +} + +.o_notebook_collapse_btn.o_collapsed:hover { + background-color: #f5f5f5; + color: #000; +} + +/* 折叠状态的整个Notebook */ +.o_collapsible_notebook.o_notebook_collapsed .o_notebook .tab-content { + display: none; + transition: all 0.3s ease; +} + +.o_collapsible_notebook.o_notebook_collapsed .o_notebook .nav-tabs { + opacity: 0.7; + transition: opacity 0.3s ease; +} + +/* 展开状态的整个Notebook */ +.o_collapsible_notebook:not(.o_notebook_collapsed) .o_notebook .tab-content { + display: block; + transition: all 0.3s ease; +} + +.o_collapsible_notebook:not(.o_notebook_collapsed) .o_notebook .nav-tabs { + opacity: 1; + transition: opacity 0.3s ease; +} + +/* 页面内容区域的过渡效果 */ +.o_notebook .tab-pane { + transition: opacity 0.3s ease, height 0.3s ease; +} + +/* 响应式设计 */ +@media (max-width: 768px) { + .o_notebook_collapse_btn { + font-size: 14px; + padding: 4px; + width: 25px; + height: 25px; + } + + .o_notebook_collapse_btn + .nav-tabs { + width: calc(100% - 35px); + } + + .o_notebook .nav-tabs .nav-link { + font-size: 12px; + padding: 8px 6px; + } +} + +/* 深色主题支持 */ +@media (prefers-color-scheme: dark) { + .o_notebook_collapse_btn { + background-color: transparent; + color: #fff; + } + + .o_notebook_collapse_btn:hover { + background-color: #333; + color: #fff; + } + + .o_notebook_collapse_btn.o_collapsed { + background-color: transparent; + color: #fff; + } + + .o_notebook_collapse_btn.o_collapsed:hover { + background-color: #333; + color: #fff; + } +} + +/* 动画效果 */ +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideUp { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-10px); + } +} + +/* 展开动画 */ +.o_notebook .tab-pane.expanding { + animation: slideDown 0.3s ease; +} + +/* 折叠动画 */ +.o_notebook .tab-pane.collapsing { + animation: slideUp 0.3s ease; +} + +/* 工具提示样式 */ +.o_collapse_btn[title]:hover::after { + content: attr(title); + position: absolute; + bottom: 100%; + left: 50%; + transform: translateX(-50%); + background-color: #333; + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 12px; + white-space: nowrap; + z-index: 1000; + margin-bottom: 5px; +} + +.o_collapse_btn[title]:hover::before { + content: ''; + position: absolute; + bottom: 100%; + left: 50%; + transform: translateX(-50%); + border: 5px solid transparent; + border-top-color: #333; + z-index: 1000; +} + +/* 高对比度模式支持 */ +@media (prefers-contrast: high) { + .o_notebook_collapse_btn { + border: 2px solid currentColor; + } +} + +/* 减少动画模式支持 */ +@media (prefers-reduced-motion: reduce) { + .o_notebook .tab-pane, + .o_notebook_collapse_btn, + .o_collapsible_notebook { + transition: none; + } + + .o_notebook .tab-pane.expanding, + .o_notebook .tab-pane.collapsing { + animation: none; + } +} + +/* 打印样式 */ +@media print { + .o_notebook_collapse_btn { + display: none; + } + + .o_collapsible_notebook.o_notebook_collapsed .o_notebook .tab-content { + display: block !important; + } + + .o_collapsible_notebook.o_notebook_collapsed .o_notebook .nav-tabs { + opacity: 1 !important; + } +} diff --git a/collapsible_notebook/static/src/js/collapsible_notebook.js b/collapsible_notebook/static/src/js/collapsible_notebook.js new file mode 100644 index 000000000..7e075c692 --- /dev/null +++ b/collapsible_notebook/static/src/js/collapsible_notebook.js @@ -0,0 +1,215 @@ +// 可折叠Notebook功能 +console.log('Collapsible Notebook JS loaded'); + +/** + * 页面加载完成后自动初始化所有可折叠notebook + */ +function initCollapsibleNotebooks() { + console.log('Initializing collapsible notebooks...'); + + // 初始化现有的notebook + const existingNotebooks = document.querySelectorAll('.o_collapsible_notebook'); + console.log('Found notebooks:', existingNotebooks.length); + + if (existingNotebooks.length === 0) { + console.log('No notebooks found, retrying in 500ms...'); + setTimeout(initCollapsibleNotebooks, 500); + return; + } + + existingNotebooks.forEach((notebook, index) => { + console.log(`Processing notebook ${index}:`, notebook); + if (!notebook.hasAttribute('data-collapsible-initialized')) { + initializeNotebook(notebook); + notebook.setAttribute('data-collapsible-initialized', 'true'); + } + }); +} + +// 页面加载完成后初始化 +document.addEventListener('DOMContentLoaded', function() { + console.log('DOM Content Loaded'); + initCollapsibleNotebooks(); +}); + +// 如果DOM已经加载完成,立即初始化 +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initCollapsibleNotebooks); +} else { + initCollapsibleNotebooks(); +} + +// 使用MutationObserver来监听DOM变化,确保在动态加载的内容中也能工作 +function setupMutationObserver() { + if (!document.body) { + console.log('Document body not ready, retrying...'); + setTimeout(setupMutationObserver, 100); + return; + } + + const observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.type === 'childList') { + mutation.addedNodes.forEach(function(node) { + if (node.nodeType === Node.ELEMENT_NODE) { + const notebooks = node.querySelectorAll ? + node.querySelectorAll('.o_collapsible_notebook') : + (node.classList && node.classList.contains('o_collapsible_notebook') ? [node] : []); + + notebooks.forEach(notebook => { + if (!notebook.hasAttribute('data-collapsible-initialized')) { + console.log('New notebook detected:', notebook); + initializeNotebook(notebook); + notebook.setAttribute('data-collapsible-initialized', 'true'); + } + }); + } + }); + } + }); + }); + + // 开始观察 + observer.observe(document.body, { + childList: true, + subtree: true + }); + + console.log('MutationObserver setup complete'); +} + +// 设置MutationObserver +setupMutationObserver(); + +/** + * 初始化单个notebook + */ +function initializeNotebook(notebook) { + console.log('Initializing notebook:', notebook); + // 为整个notebook添加折叠/展开按钮 + addNotebookCollapseButton(notebook); +} + +/** + * 为整个notebook添加折叠/展开按钮 + */ +function addNotebookCollapseButton(notebook) { + console.log('Adding collapse button to notebook:', notebook); + console.log('Notebook HTML structure:', notebook.outerHTML); + + // 检查是否已经添加了按钮 + if (notebook.querySelector('.o_notebook_collapse_btn')) { + console.log('Collapse button already exists'); + return; + } + + // 创建notebook折叠按钮 + const notebookCollapseBtn = document.createElement('div'); + notebookCollapseBtn.className = 'o_notebook_collapse_btn'; + notebookCollapseBtn.innerHTML = ''; + notebookCollapseBtn.title = '点击折叠/展开整个Notebook'; + + console.log('Created collapse button:', notebookCollapseBtn); + + // 添加点击事件 + notebookCollapseBtn.addEventListener('click', (e) => { + console.log('Collapse button clicked'); + e.preventDefault(); + e.stopPropagation(); + toggleNotebook(notebook, notebookCollapseBtn); + }); + + // 将按钮添加到notebook的nav-tabs前面(与页面标签并排) + try { + const navTabs = notebook.querySelector('.nav-tabs'); + if (navTabs && navTabs.parentNode) { + navTabs.parentNode.insertBefore(notebookCollapseBtn, navTabs); + console.log('Button inserted successfully before nav-tabs'); + } else if (notebook.parentNode) { + notebook.parentNode.insertBefore(notebookCollapseBtn, notebook); + console.log('Button inserted successfully before notebook (fallback)'); + } else { + notebook.insertBefore(notebookCollapseBtn, notebook.firstChild); + console.log('Button inserted successfully inside notebook (fallback)'); + } + } catch (error) { + console.error('Error inserting button:', error); + } + + // 恢复折叠状态 + restoreNotebookState(notebook, notebookCollapseBtn); +} + +/** + * 从localStorage恢复notebook折叠状态 + */ +function restoreNotebookState(notebook, button) { + try { + const notebookId = notebook.getAttribute('id') || 'default_notebook'; + const savedState = localStorage.getItem(`odoo_notebook_collapsed_${notebookId}`); + + if (savedState === 'true') { + console.log('Restoring collapsed state for notebook:', notebookId); + notebook.classList.add('o_notebook_collapsed'); + button.innerHTML = ''; + button.classList.add('o_collapsed'); + + // 直接设置内容隐藏 + const tabContent = notebook.querySelector('.tab-content'); + if (tabContent) { + tabContent.style.display = 'none'; + } + } else { + console.log('Notebook starts in expanded state:', notebookId); + } + } catch (error) { + console.error('Error restoring notebook state:', error); + } +} + +/** + * 切换整个notebook的折叠/展开状态 + */ +function toggleNotebook(notebook, button) { + console.log('Toggling notebook:', notebook); + console.log('Notebook classes before:', notebook.className); + + const isCollapsed = notebook.classList.contains('o_notebook_collapsed'); + console.log('Current state - isCollapsed:', isCollapsed); + + // 查找tab-content元素 + const tabContent = notebook.querySelector('.tab-content'); + console.log('Found tab-content:', tabContent); + + if (isCollapsed) { + // 展开notebook + console.log('Expanding notebook'); + notebook.classList.remove('o_notebook_collapsed'); + button.innerHTML = ''; + button.classList.remove('o_collapsed'); + + if (tabContent) { + tabContent.style.display = 'block'; + console.log('Set tab-content display to block'); + } + } else { + // 折叠notebook + console.log('Collapsing notebook'); + notebook.classList.add('o_notebook_collapsed'); + button.innerHTML = ''; + button.classList.add('o_collapsed'); + + if (tabContent) { + tabContent.style.display = 'none'; + console.log('Set tab-content display to none'); + } + } + + console.log('Notebook classes after:', notebook.className); + + // 保存状态 + const notebookId = notebook.getAttribute('id') || 'default_notebook'; + localStorage.setItem(`odoo_notebook_collapsed_${notebookId}`, isCollapsed ? 'false' : 'true'); + console.log('State saved to localStorage'); +} + diff --git a/yuthon_property_approval/views/property_lease_contract.xml b/yuthon_property_approval/views/property_lease_contract.xml index 61101e55b..0645d0e60 100644 --- a/yuthon_property_approval/views/property_lease_contract.xml +++ b/yuthon_property_approval/views/property_lease_contract.xml @@ -672,7 +672,7 @@ - + @@ -764,7 +764,7 @@ readonly="1"/> - +