From ee340a3da3159fad86bde4437b42dd6600e317bc Mon Sep 17 00:00:00 2001 From: wangziyangyang <707231019@qq.com> Date: Wed, 1 Jul 2020 18:09:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=80=E5=8F=91=E7=94=9F=E4=BA=A7=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../order/controller/SpOrderController.java | 46 +- .../static/lib/gantt/css/img/close.png | Bin 0 -> 1308 bytes .../static/lib/gantt/css/img/grid.png | Bin 0 -> 122 bytes .../static/lib/gantt/css/img/icon_sprite.png | Bin 0 -> 683 bytes .../static/lib/gantt/css/img/loader_bg.png | Bin 0 -> 160 bytes .../lib/gantt/css/img/slider_handle.png | Bin 0 -> 1041 bytes .../resources/static/lib/gantt/css/style.css | 474 +++++ .../resources/static/lib/gantt/index.html | 180 ++ .../static/lib/gantt/js/jquery.fn.gantt.js | 1794 +++++++++++++++++ .../templates/order/production/list.ftl | 73 +- 10 files changed, 2561 insertions(+), 6 deletions(-) create mode 100644 mes/src/main/resources/static/lib/gantt/css/img/close.png create mode 100644 mes/src/main/resources/static/lib/gantt/css/img/grid.png create mode 100644 mes/src/main/resources/static/lib/gantt/css/img/icon_sprite.png create mode 100644 mes/src/main/resources/static/lib/gantt/css/img/loader_bg.png create mode 100644 mes/src/main/resources/static/lib/gantt/css/img/slider_handle.png create mode 100644 mes/src/main/resources/static/lib/gantt/css/style.css create mode 100644 mes/src/main/resources/static/lib/gantt/index.html create mode 100644 mes/src/main/resources/static/lib/gantt/js/jquery.fn.gantt.js diff --git a/mes/src/main/java/com/wangziyang/mes/order/controller/SpOrderController.java b/mes/src/main/java/com/wangziyang/mes/order/controller/SpOrderController.java index aca7b4e..c79e577 100644 --- a/mes/src/main/java/com/wangziyang/mes/order/controller/SpOrderController.java +++ b/mes/src/main/java/com/wangziyang/mes/order/controller/SpOrderController.java @@ -17,10 +17,12 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** *

@@ -120,4 +122,40 @@ public class SpOrderController extends BaseController { iSpOrderService.removeById(req.getId()); return Result.success(); } + + @ResponseBody + @RequestMapping(value = "/gantt/list", method = RequestMethod.POST, produces = "application/json") + public Result getListGantt(Map params) throws Exception { + List> result = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + Map map = new HashMap<>(8); + map.put("id", "id" + (i + 1)); + if (i % 2 == 0) { + map.put("name", "物料编码" + (i + 1)); + map.put("desc", "计划:"); + } else { + map.put("desc", "实际:"); + } + map.put("cssClass", "redLabel"); + + List> values = new ArrayList<>(); + Map value = new HashMap<>(8); + value.put("from", "/Date(" + System.currentTimeMillis() + ")/"); + value.put("to", "/Date(" + (System.currentTimeMillis() + 1000000000) + ")/"); + value.put("label", "极板"); + value.put("desc", "悬停悬停悬停悬停悬停..."); + value.put("customClass", "ganttGreen"); + if (i == 1) { + value.put("customClass", "ganttOrange"); + } + if (i == 2) { + value.put("customClass", "ganttRed"); + } + value.put("dataObj", "1"); + values.add(value); + map.put("values", values); + result.add(map); + } + return Result.success(result); + } } diff --git a/mes/src/main/resources/static/lib/gantt/css/img/close.png b/mes/src/main/resources/static/lib/gantt/css/img/close.png new file mode 100644 index 0000000000000000000000000000000000000000..b4d1f75cce7da1d787ccd1c718bf5513524af171 GIT binary patch literal 1308 zcmeAS@N?(olHy`uVBq!ia0vp^q9Dw{1|(OCFP#RYBuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFe_$;M3hAM`dB6B=jtVb)aX^@765fKFxc2v6eK2Rr0UTq__OB&@Hb09I0xZL0)vRD^GUf^&XRs)DJWscy1?p^1XIrJkXw zp^1f|j)IYap|QS!vA&_PuAz~Yfu)t9sR9%z0c|TvNwW%aaf8|g1^l#~=$>Fbx5 zm+O@q>*W`v>l<2HTIw4Z=^Gj80#)c1SLT%@R_NvxE5l51Ni9w;$}A|!%+FH*nV6WA zUs__T1av9H3%LbwWAlok!2}F2{ffi_eM3D1ke6TzeSPsO&CP|YE-nd5MYtEM!Nnn! z1*!T$sm1xFMajU3OH&3}Rbb^@l$uzQUlfv`p92fUfQQ@j&W4ue zCN8c(0MqM|pIn-onpXnTn*!HsX@FBNC?(_;0Bv?jEy^rQO>ryA&s6~X*eVmZTU>CO z2i2Q`(=8URIQ8lS9itD5SEP7`2>}xihzU=%Kn^_Jr{)0@dl4{I^C$EEW?*2P=;`7Z zQgLg`)YIB7filP6?|rkTS93k5^n2FGprpniA=guUmJp`ktD_+oTh~U-aXQRQ-i(>c8J!mcGCx0kBPJ^nPK?vfK1cf|V!y`{CTF%4p_HhjzeEGgW#@{G0V!XD!bTyc^9 z4T9z?mzJE8d+|Zwl*Q5?y`?wSEmdKI;Vst0G(me2><{9 literal 0 HcmV?d00001 diff --git a/mes/src/main/resources/static/lib/gantt/css/img/grid.png b/mes/src/main/resources/static/lib/gantt/css/img/grid.png new file mode 100644 index 0000000000000000000000000000000000000000..1de103e5783e5b9b15809503ecda0f2578ade118 GIT binary patch literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaT3?y&uT)!Jgv7|ftIx;Y9?C1WI$O_~$76-XI zF|0c$^AgBm3-AeX{r~^})2B~4n=WJnMT9(E978y+CnqE%q%08q_y4~=1J^-j(e&n@ QUx2azopr0Bm?A2><{9 literal 0 HcmV?d00001 diff --git a/mes/src/main/resources/static/lib/gantt/css/img/icon_sprite.png b/mes/src/main/resources/static/lib/gantt/css/img/icon_sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..242e55200f361ba2632642e5b8f2c184ec0f405f GIT binary patch literal 683 zcmeAS@N?(olHy`uVBq!ia0vp^0zkZhgBeH~8p`bjQY`6?zK#qG8~eHcB(ehejKx9j zP7LeL$-D$|RtNZmxB}^8$BxS>DECp8!hz z{__VY^6uUHM~@x>xj%pY{PE+*m#<%Q^YVe*w)PGcH4TVLh&ezKh<^S01u;ig-w?>% zv2z!Y)X_6|{`|%F@84g&dbMl!ZlFe>8X$N7{sTZ+AbWm$O(xK}79~M`!3@SR&szD_ z(u_skGybXl5S1`rREFc}$xYj}K7M)==2V*A6Tl-UmU?cQnV$0^7lS=h_b$m`p0wF` z%_-kBU@$~^x;Tb-9KSm?J-^vNpiOp~;)K25=iUAN@4x=)UeBccnX45-b)S4Z( z-BWLooxd;ceD!gYJu`C`WfQ<6T@_`R(PuS?<_%J??ydd-JK;hnF(Q_vp5t zl`vu3#PEKRT(cX`tG}(QPArNK&yG_5DzkNx@9MiBwRplG=Y9R4xb<9$)!dS-<@#&4 zEM5_N(xIB=f?QJEnV&@|<{9-`3Dy3N1{EA{+}H zI9Q#23Z8JaO8vC_^%Oy6=jB#AnC2E;(Ol@qS=x0#8N|?Z7ybFIsdKjT{)9(y7xZT^ e|Jcp_On3^f*{2lyX>Wls#o+1c=d#Wzp$PyW4oQ*# literal 0 HcmV?d00001 diff --git a/mes/src/main/resources/static/lib/gantt/css/img/loader_bg.png b/mes/src/main/resources/static/lib/gantt/css/img/loader_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..4841b2cb86f5bf77c40b0cec11b3d46d1f4611ce GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_{3?x-PN__%SEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaOC0(?STXU?2?=FFLQ6*=F4B1|Pge!*T|uXqkw0(n}VE{-7*my;h92xSC5 zDM(Nn{1`8HCb0#Ar1ETEp>(|@1ZG*5qJw3Iww9cMA3*+w%%30d&*o=NJpGsK{xWV+oef=yjFFqNniNrzhL5L(~duvT)TdK zl<=87_onl&A77$>7;b&m)cxva@YC-;7sDILUX|~s`2P&C5n_75Qd5iZ7M-*sqGu&IE`z-in&o}GY7Za;*J2R%M zW~qAgw<~!(_BJUz!Prx}_VSyfdQ+q(Pc6GU$AG~lb|v$co2$Zi&Al~yelbT*eytl* z-lM?v7h{hXd|%1rushzQ@9sVAsZUz{mRhzkB&*lG-0*|rR42Rh{awav4|4J*yq6Nr zE5BLz=GTJ`<{e#2ExVO-uI*c8e<=HRk%+>jHy0Ci{8q2O()sggXx*hIb?KMyU%mL~ z-|K%~PjAVWM8~w{OQLV6%S=9VVuofVOKR$s^zPe7_X;o4DYIe^)>@U>^n|%tH%4VH zkJuEmlr3pypJ#rkcbO4=;?ZWVivJJ#H{Q&#sQt-mJ27UWuh-TFV7xMTy85}Sb4q9e E04k~U_W%F@ literal 0 HcmV?d00001 diff --git a/mes/src/main/resources/static/lib/gantt/css/style.css b/mes/src/main/resources/static/lib/gantt/css/style.css new file mode 100644 index 0000000..2e40730 --- /dev/null +++ b/mes/src/main/resources/static/lib/gantt/css/style.css @@ -0,0 +1,474 @@ +.gantt { + width: 100%; + margin: 0 auto; + /*清除掉上下间距*/ + border: 8px solid #ddd; + position: relative; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +/*设置底部控件位置(前端技术有限,就这样简单的处理了一下)*/ +.nav-slider { + margin-left: 20%; +} + +.gantt:after { + content: "."; + visibility: hidden; + display: block; + height: 0; + clear: both; +} + +.fn-gantt { + width: 100%; +} + +.fn-gantt *, +.fn-gantt *:after, +.fn-gantt *:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.fn-gantt .fn-content { + overflow: hidden; + position: relative; + width: 100%; +} + +.fn-gantt .row { + float: left; + height: 24px; + line-height: 24px; + margin: 0; +} + + +/* === LEFT PANEL === */ + +.fn-gantt .leftPanel { + float: left; + width: 380px; + overflow: hidden; + border-right: 1px solid #DDD; + position: relative; + z-index: 20; +} + +.fn-gantt .leftPanel .fn-label { + display: inline-block; + margin: 0 0 0 5px; + color: #484A4D; + width: 180px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.fn-gantt .leftPanel .row { + border-bottom: 1px solid #DDD; +} + +.fn-gantt .leftPanel .name, .fn-gantt .leftPanel .desc { + float: left; + height: 24px; + width: 50%; + background-color: #f6f6f6; +} + +.fn-gantt .leftPanel .name { + font-weight: bold; +} + +.fn-gantt .leftPanel .fn-wide, .fn-gantt .leftPanel .fn-wide .fn-label { + width: 100%; +} + +.fn-gantt .leftPanel .spacer { + background-color: #f6f6f6; + width: 100%; +} + + +/* === RIGHT PANEL === */ + +.fn-gantt .rightPanel { + overflow: hidden; +} + +.fn-gantt .dataPanel { + margin-left: 0; + outline: 1px solid #DDD; + /* TODO: Replace image with gradient? + background-size: 24px 24px; + background-image: linear-gradient(to left, rgba(221, 221, 221, 0.7) 1px, transparent 1px), linear-gradient(to top, rgba(221, 221, 221, 0.7) 1px, transparent 1px); + */ + background-image: url(img/grid.png); + background-repeat: repeat; + position: relative; +} + +.fn-gantt .row.header { + margin-right: -1px; + width: 100%; +} + +.fn-gantt .day, .fn-gantt .date { + overflow: visible; + width: 24px; + line-height: 24px; + text-align: center; + border-right: 1px solid #DDD; + border-bottom: 1px solid #DDD; + font-size: 11px; + color: #484a4d; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.75); + text-align: center; +} + +.fn-gantt .sa, .fn-gantt .sn, .fn-gantt .wd { + height: 24px; + text-align: center; +} + +.fn-gantt .sa, .fn-gantt .sn { + color: #939496; + background-color: #f5f5f5; + text-align: center; +} + +.fn-gantt .wd { + background-color: #f6f6f6; + text-align: center; +} + +.fn-gantt .holiday { + background-color: #ffd263; + height: 24px; +} + +.fn-gantt .today { + background-color: #fff8da; + height: 24px; + font-weight: bold; + text-align: center; +} + +.fn-gantt .rightPanel .month, .fn-gantt .rightPanel .year { + float: left; + overflow: hidden; + border-right: 1px solid #DDD; + border-bottom: 1px solid #DDD; + height: 24px; + background-color: #f6f6f6; + font-weight: bold; + font-size: 11px; + color: #484a4d; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.75); + text-align: center; +} + +.fn-gantt-hint { + border: 3px solid #eeeeee; + background-color: #F0F0F0; + padding: 10px; + position: absolute; + display: none; + z-index: 11; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.fn-gantt .bar { + background-color: #D0E4FD; + height: 18px; + margin: 0 3px 3px 0; + position: absolute; + z-index: 10; + text-align: center; + -webkit-box-shadow: 0 0 1px rgba(0, 0, 0, 0.25) inset; + -moz-box-shadow: 0 0 1px rgba(0, 0, 0, 0.25) inset; + box-shadow: 0 0 1px rgba(0, 0, 0, 0.25) inset; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + opacity: 0.80; +} + +.fn-gantt .bar .fn-label { + line-height: 18px; + font-weight: bold; + white-space: nowrap; + width: 100%; + text-overflow: ellipsis; + overflow: hidden; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4); + color: #414B57 !important; + text-align: center; + font-size: 11px; +} + +.fn-gantt .ganttRed { + background-color: #FF5722; +} + +.fn-gantt .ganttRed .fn-label { + color: #FFFFFF !important; +} + +.fn-gantt .ganttGreen { + background-color: #009688; +} + +.fn-gantt .ganttGreen .fn-label { + color: #FFFFFF !important; +} + +.fn-gantt .ganttOrange { + background-color: #FFB800; +} + +.fn-gantt .ganttOrange .fn-label { + color: #FFFFFF !important; +} + +.fn-gantt .ganttBlue { + background-color: #1E9FFF; +} + +.fn-gantt .ganttBlue .fn-label { + color: #FFFFFF !important; +} + +.fn-gantt .ganttBlack { + background-color: #393D49; +} + +.fn-gantt .ganttBlack .fn-label { + color: #FFFFFF !important; +} + +.fn-gantt .ganttCyan { + background-color: #2F4056; +} + +.fn-gantt .ganttCyan .fn-label { + color: #FFFFFF !important; +} + +.fn-gantt .ganttGray { + background-color: #666; +} + +.fn-gantt .ganttGray .fn-label { + color: #FFFFFF !important; +} + +/* === BOTTOM NAVIGATION === */ + +.fn-gantt .bottom { + clear: both; + background-color: #f6f6f6; + width: 100%; +} + +.fn-gantt .navigate { + border-top: 1px solid #DDD; + padding: 10px 0 10px 225px; +} + +.fn-gantt .navigate .nav-slider { + height: 20px; + display: inline-block; +} + +.fn-gantt .navigate .nav-slider-left, .fn-gantt .navigate .nav-slider-right { + text-align: center; + height: 20px; + display: inline-block; +} + +.fn-gantt .navigate .nav-slider-left { + float: left; +} + +.fn-gantt .navigate .nav-slider-right { + float: right; +} + +.fn-gantt .navigate .nav-slider-content { + text-align: left; + width: 160px; + height: 20px; + display: inline-block; + margin: 0 10px; +} + +.fn-gantt .navigate .nav-slider-bar, .fn-gantt .navigate .nav-slider-button { + position: absolute; + display: block; +} + +.fn-gantt .navigate .nav-slider-bar { + width: 155px; + height: 6px; + background-color: #838688; + margin: 8px 0 0 0; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6) inset; + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6) inset; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6) inset; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fn-gantt .navigate .nav-slider-button { + width: 17px; + height: 60px; + background: url(img/slider_handle.png) center center no-repeat; + left: 0; + top: 0; + margin: -26px 0 0 0; + cursor: pointer; +} + +.fn-gantt .navigate .page-number { + display: inline-block; + font-size: 10px; + height: 20px; +} + +.fn-gantt .navigate .page-number span { + color: #666666; + margin: 0 6px; + height: 20px; + line-height: 20px; + display: inline-block; +} + +.fn-gantt .navigate a:link, .fn-gantt .navigate a:visited, .fn-gantt .navigate a:active { + text-decoration: none; +} + +.fn-gantt .nav-link { + margin: 0 3px 0 0; + display: inline-block; + width: 20px; + height: 20px; + font-size: 0; + background: #595959 url(img/icon_sprite.png) !important; + border: 1px solid #454546; + cursor: pointer; + vertical-align: top; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.1) inset, 0 1px 1px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.1) inset, 0 1px 1px rgba(0, 0, 0, 0.2); + box-shadow: 0 1px 0 rgba(255, 255, 255, 0.1) inset, 0 1px 1px rgba(0, 0, 0, 0.2); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.fn-gantt .nav-link:active { + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.25) inset, 0 1px 0 #FFF; + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.25) inset, 0 1px 0 #FFF; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.25) inset, 0 1px 0 #FFF; +} + +.fn-gantt .navigate .nav-page-back { + background-position: 1px 0 !important; + margin: 0; +} + +.fn-gantt .navigate .nav-page-next { + background-position: 1px -16px !important; + margin-right: 15px; +} + +.fn-gantt .navigate .nav-slider .nav-page-next { + margin-right: 5px; +} + +.fn-gantt .navigate .nav-begin { + background-position: 1px -112px !important; +} + +.fn-gantt .navigate .nav-prev-week { + background-position: 1px -128px !important; +} + +.fn-gantt .navigate .nav-prev-day { + background-position: 1px -48px !important; +} + +.fn-gantt .navigate .nav-next-day { + background-position: 1px -64px !important; +} + +.fn-gantt .navigate .nav-next-week { + background-position: 1px -160px !important; +} + +.fn-gantt .navigate .nav-end { + background-position: 1px -144px !important; +} + +.fn-gantt .navigate .nav-zoomOut { + background-position: 1px -96px !important; +} + +.fn-gantt .navigate .nav-zoomIn { + background-position: 1px -80px !important; + margin-left: 15px; +} + +.fn-gantt .navigate .nav-now { + background-position: 1px -32px !important; +} + +.fn-gantt .navigate .nav-slider .nav-now { + margin-right: 5px; +} + +.fn-gantt-loader { + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#bf000000', endColorstr='#bf000000', GradientType=0); + background: rgba(0, 0, 0, 0.75); + cursor: wait; + z-index: 30; +} + +.fn-gantt-loader-spinner span { + position: absolute; + margin: auto; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: 100%; + text-align: center; + height: 1em; + line-height: 1em; + color: #fff; + font-size: 1em; + font-weight: bold; +} + +.row:after { + clear: both; +} + diff --git a/mes/src/main/resources/static/lib/gantt/index.html b/mes/src/main/resources/static/lib/gantt/index.html new file mode 100644 index 0000000..4f3d6af --- /dev/null +++ b/mes/src/main/resources/static/lib/gantt/index.html @@ -0,0 +1,180 @@ + + + + jQuery.Gantt + + + + + + + + +

+
+
+ + + + + + + + + + diff --git a/mes/src/main/resources/static/lib/gantt/js/jquery.fn.gantt.js b/mes/src/main/resources/static/lib/gantt/js/jquery.fn.gantt.js new file mode 100644 index 0000000..ac4bb8a --- /dev/null +++ b/mes/src/main/resources/static/lib/gantt/js/jquery.fn.gantt.js @@ -0,0 +1,1794 @@ +/** + * jQuery Gantt Chart + * + * @see http://taitems.github.io/jQuery.Gantt/ + * @license MIT + */ +/*jshint camelcase:true, freeze:true, jquery:true */ +(function ($, undefined) { + "use strict"; + + var UTC_DAY_IN_MS = 24 * 60 * 60 * 1000; + + // custom selector `:findday` used to match on specified day in ms. + // + // The selector is passed a date in ms and elements are added to the + // selection filter if the element date matches, as determined by the + // id attribute containing a parsable date in ms. + function findDay(elt, text) { + var cd = new Date(parseInt(text, 10)); + cd.setHours(0, 0, 0, 0); + var id = $(elt).attr("id") || ""; + var si = id.indexOf("-") + 1; + var ed = new Date(parseInt(id.substring(si, id.length), 10)); + ed.setHours(0, 0, 0, 0); + return cd.getTime() === ed.getTime(); + } + + $.expr.pseudos.findday = $.expr.createPseudo ? + $.expr.createPseudo(function (text) { + return function (elt) { + return findDay(elt, text); + }; + }) : + function (elt, i, match) { + return findDay(elt, match[3]); + }; + + // custom selector `:findweek` used to match on specified week in ms. + function findWeek(elt, text) { + var cd = new Date(parseInt(text, 10)); + var y = cd.getFullYear(); + var w = cd.getWeekOfYear(); + var m = cd.getMonth(); + if (m === 11 && w === 1) { + y++; + } else if (!m && w > 51) { + y--; + } + cd = y + "-" + w; + var id = $(elt).attr("id") || ""; + var si = id.indexOf("-") + 1; + var ed = id.substring(si, id.length); + return cd === ed; + } + + $.expr.pseudos.findweek = $.expr.createPseudo ? + $.expr.createPseudo(function (text) { + return function (elt) { + return findWeek(elt, text); + }; + }) : + function (elt, i, match) { + return findWeek(elt, match[3]); + }; + + // custom selector `:findmonth` used to match on specified month in ms. + function findMonth(elt, text) { + var cd = new Date(parseInt(text, 10)); + cd = cd.getFullYear() + "-" + cd.getMonth(); + var id = $(elt).attr("id") || ""; + var si = id.indexOf("-") + 1; + var ed = id.substring(si, id.length); + return cd === ed; + } + + $.expr[':'].findmonth = $.expr.createPseudo ? + $.expr.createPseudo(function (text) { + return function (elt) { + return findMonth(elt, text); + }; + }) : + function (elt, i, match) { + return findMonth(elt, match[3]); + }; + + // Date prototype helpers + // ====================== + + // `getWeekId` returns a string in the form of 'dh-YYYY-WW', where WW is + // the week # for the year. + // It is used to add an id to the week divs + Date.prototype.getWeekId = function () { + var y = this.getFullYear(); + var w = this.getWeekOfYear(); + var m = this.getMonth(); + if (m === 11 && w === 1) { + y++; + } else if (!m && w > 51) { + y--; + } + return 'dh-' + y + "-" + w; + }; + + // `getRepDate` returns the milliseconds since the epoch for a given date + // depending on the active scale + Date.prototype.getRepDate = function (scale) { + switch (scale) { + case "hours": + return this.getTime(); + case "weeks": + return this.getDayForWeek().getTime(); + case "months": + return new Date(this.getFullYear(), this.getMonth(), 1).getTime(); + case "days": + /* falls through */ + default: + return this.getTime(); + } + }; + + // `getDayOfYear` returns the day number for the year + Date.prototype.getDayOfYear = function () { + var year = this.getFullYear(); + return (Date.UTC(year, this.getMonth(), this.getDate()) - + Date.UTC(year, 0, 0)) / UTC_DAY_IN_MS; + }; + + // Use ISO week by default + //TODO: make these options. + var firstDay = 1; // ISO week starts with Monday (1); use Sunday (0) for, e.g., North America + var weekOneDate = 4; // ISO week one always contains 4 Jan; use 1 Jan for, e.g., North America + + // `getWeekOfYear` returns the week number for the year + //TODO: fix bug when firstDay=6/weekOneDate=1 : https://github.com/moment/moment/issues/2115 + Date.prototype.getWeekOfYear = function () { + var year = this.getFullYear(), + month = this.getMonth(), + date = this.getDate(), + day = this.getDay(); + //var diff = weekOneDate - day + 7 * (day < firstDay ? -1 : 1); + var diff = weekOneDate - day; + if (day < firstDay) { + diff -= 7; + } + if (diff + 7 < weekOneDate - firstDay) { + diff += 7; + } + return Math.ceil(new Date(year, month, date + diff).getDayOfYear() / 7); + }; + + // `getDayForWeek` returns the first day of this Date's week + Date.prototype.getDayForWeek = function () { + var day = this.getDay(); + var diff = (day < firstDay ? -7 : 0) + firstDay - day; + return new Date(this.getFullYear(), this.getMonth(), this.getDate() + diff); + }; + + // fixes https://github.com/taitems/jQuery.Gantt/issues/62 + function ktkGetNextDate(currentDate, scaleStep) { + for (var minIncrements = 1; ; minIncrements++) { + var nextDate = new Date(currentDate); + nextDate.setHours(currentDate.getHours() + scaleStep * minIncrements); + + if (nextDate.getTime() !== currentDate.getTime()) { + return nextDate; + } + + // If code reaches here, it's because current didn't really increment (invalid local time) because of daylight-saving adjustments + // => retry adding 2, 3, 4 hours, and so on (until nextDate > current) + } + } + + $.fn.gantt = function (options) { + + var scales = ["hours", "days", "weeks", "months"]; + //Default settings + var settings = { + source: [], + holidays: [], + // 默认的页数 + itemsPerPage: 7, + // localisation + // dow: ["S", "M", "T", "W", "T", "F", "S"], + //面板上的星期,只能为一个字,两个字会被挤出来 + dow: ["日", "一", "二", "三", "四", "五", "六"], + //面板上的月份 + months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + //甘特图在渲染的时候显示的提示文字 + waitText: "加载中,请稍候...", + // 底部使用拖拽的刻度尺还是按钮:scroll和buttons + navigate: "buttons", + //网格加载完毕后是否自动滚动到今天,true为是 false为不需要 + scrollToToday: false, + // cookie options + useCookie: false, + cookieKey: "jquery.fn.gantt", + // scale parameters + scale: "days", + maxScale: "months", + minScale: "hours", + // callbacks + onItemClick: function (data) { + return; + }, + onAddClick: function (dt, rowId) { + return; + }, + onRender: $.noop + }; + + // read options + $.extend(settings, options); + + // can't use cookie if don't have `$.cookie` + settings.useCookie = settings.useCookie && $.isFunction($.cookie); + + // Grid management + // =============== + + // Core object is responsible for navigation and rendering + var core = { + // Return the element whose topmost point lies under the given point + // Normalizes for old browsers (NOTE: doesn't work when element is outside viewport) + //TODO: https://github.com/taitems/jQuery.Gantt/issues/137 + elementFromPoint: (function () { // IIFE + // version for normal browsers + if (document.compatMode === "CSS1Compat") { + return function (x, y) { + x -= window.pageXOffset; + y -= window.pageYOffset; + return document.elementFromPoint(x, y); + }; + } + // version for older browsers + return function (x, y) { + x -= $(document).scrollLeft(); + y -= $(document).scrollTop(); + return document.elementFromPoint(x, y); + }; + })(), + + // **Create the chart** + create: function (element) { + + // Initialize data with a json object or fetch via an xhr + // request depending on `settings.source` + if (typeof settings.source !== "string") { + element.data = settings.source; + core.init(element); + } else { + $.getJSON(settings.source, function (jsData) { + element.data = jsData; + core.init(element); + }); + } + }, + + // **Setup the initial view** + // Here we calculate the number of rows, pages and visible start + // and end dates once the data are ready + init: function (element) { + element.rowsNum = element.data.length; + element.pageCount = Math.ceil(element.rowsNum / settings.itemsPerPage); + element.rowsOnLastPage = element.rowsNum - (Math.floor(element.rowsNum / settings.itemsPerPage) * settings.itemsPerPage); + + element.dateStart = tools.getMinDate(element); + element.dateEnd = tools.getMaxDate(element); + + + /* core.render(element); */ + core.waitToggle(element, function () { + core.render(element); + }); + }, + + // **Render the grid** + render: function (element) { + var content = $('
'); + var $leftPanel = core.leftPanel(element); + content.append($leftPanel); + var $rightPanel = core.rightPanel(element, $leftPanel); + var pLeft, hPos; + + content.append($rightPanel); + content.append(core.navigation(element)); + + var $dataPanel = $rightPanel.find(".dataPanel"); + + element.gantt = $('
').append(content); + + $(element).empty().append(element.gantt); + + element.scrollNavigation.panelMargin = parseInt($dataPanel.css("left").replace("px", ""), 10); + element.scrollNavigation.panelMaxPos = ($dataPanel.width() - $rightPanel.width()); + + element.scrollNavigation.canScroll = ($dataPanel.width() > $rightPanel.width()); + + core.markNow(element); + core.fillData(element, $dataPanel, $leftPanel); + + // Set a cookie to record current position in the view + if (settings.useCookie) { + var sc = $.cookie(settings.cookieKey + "ScrollPos"); + if (sc) { + element.hPosition = sc; + } + } + + // Scroll the grid to today's date + if (settings.scrollToToday) { + core.navigateTo(element, 'now'); + core.scrollPanel(element, 0); + // or, scroll the grid to the left most date in the panel + } else { + if (element.hPosition !== 0) { + if (element.scaleOldWidth) { + pLeft = ($dataPanel.width() - $rightPanel.width()); + hPos = pLeft * element.hPosition / element.scaleOldWidth; + element.hPosition = hPos > 0 ? 0 : hPos; + element.scaleOldWidth = null; + } + $dataPanel.css({"left": element.hPosition}); + element.scrollNavigation.panelMargin = element.hPosition; + } + core.repositionLabel(element); + } + + $dataPanel.css({height: $leftPanel.height()}); + core.waitToggle(element); + settings.onRender(); + }, + + // Create and return the left panel with labels + leftPanel: function (element) { + /* Left panel */ + var ganttLeftPanel = $('
') + .append($('
' + + '
' + (settings.spTitle1 || '') + '
' + + '
' + (settings.spTitle2 || '') + '
' + + '
') + .css("height", tools.getCellSize() * element.headerRows)); + + var entries = []; + $.each(element.data, function (i, entry) { + if (i >= element.pageNum * settings.itemsPerPage && + i < (element.pageNum * settings.itemsPerPage + settings.itemsPerPage)) { + var dataId = ('id' in entry) ? '" data-id="' + entry.id : ''; + entries.push( + '
' + + '' + + (entry.name || '') + + '' + + '
'); + + if (entry.desc) { + entries.push( + '
' + + '' + + entry.desc + + '' + + '
'); + } + + } + }); + return ganttLeftPanel.append(entries.join("")); + }, + + // Create and return the data panel element + dataPanel: function (element, width) { + var dataPanel = $('
'); + + // Handle mousewheel events for scrolling the data panel + var wheel = 'onwheel' in element ? + 'wheel' : document.onmousewheel !== undefined ? + 'mousewheel' : 'DOMMouseScroll'; + $(element).on(wheel, function (e) { + core.wheelScroll(element, e); + }); + + // Handle click events and dispatch to registered `onAddClick` function + dataPanel.click(function (e) { + + e.stopPropagation(); + var corrX/* <- never used? */, corrY; + var leftpanel = $(element).find(".fn-gantt .leftPanel"); + var datapanel = $(element).find(".fn-gantt .dataPanel"); + switch (settings.scale) { + case "months": + corrY = tools.getCellSize(); + break; + case "hours": + corrY = tools.getCellSize() * 4; + break; + case "days": + corrY = tools.getCellSize() * 3; + break; + case "weeks": + /* falls through */ + default: + corrY = tools.getCellSize() * 2; + } + + /* Adjust, so get middle of elm + corrY -= Math.floor(tools.getCellSize() / 2); + */ + + // Find column where click occurred + var col = core.elementFromPoint(e.pageX, datapanel.offset().top + corrY); + // Was the label clicked directly? + if (col.className === "fn-label") { + col = $(col.parentNode); + } else { + col = $(col); + } + + var dt = col.data("repdate"); + // Find row where click occurred + var row = core.elementFromPoint(leftpanel.offset().left + leftpanel.width() - 10, e.pageY); + // Was the label clicked directly? + if (row.className.indexOf("fn-label") === 0) { + row = $(row.parentNode); + } else { + row = $(row); + } + var rowId = row.data('id'); + + // Dispatch user registered function with the DateTime in ms + // and the id if the clicked object is a row + settings.onAddClick(dt, rowId); + }); + return dataPanel; + }, + + // Creates and return the right panel containing the year/week/day header + rightPanel: function (element, leftPanel /* <- never used? */) { + var range = null; + // Days of the week have a class of one of + // `sn` (Sunday), `sa` (Saturday), or `wd` (Weekday) + var dowClass = ["sn", "wd", "wd", "wd", "wd", "wd", "sa"]; + //unused: was someone planning to allow styles to stretch to the bottom of the chart? + //var gridDowClass = [" sn", "", "", "", "", "", " sa"]; + + var yearArr = []; + var scaleUnitsThisYear = 0; + + var monthArr = []; + var scaleUnitsThisMonth = 0; + + var dayArr = []; + var hoursInDay = 0; + + var dowArr = []; + var horArr = []; + + var today = new Date(); + today.setHours(0, 0, 0, 0); + + // reused variables + var $row = $('
'); + var i, len; + var year, month, week, day; + var rday, dayClass; + var dataPanel, dataPanelWidth; + + // Setup the headings based on the chosen `settings.scale` + switch (settings.scale) { + // **Hours** + case "hours": + range = tools.parseTimeRange(element.dateStart, element.dateEnd, element.scaleStep); + dataPanelWidth = range.length * tools.getCellSize(); + + year = range[0].getFullYear(); + month = range[0].getMonth(); + day = range[0]; + + for (i = 0, len = range.length; i < len; i++) { + rday = range[i]; + + // Fill years + var rfy = rday.getFullYear(); + if (rfy !== year) { + yearArr.push( + '
' + + year + + '
'); + + year = rfy; + scaleUnitsThisYear = 0; + } + scaleUnitsThisYear++; + + + // Fill months + var rm = rday.getMonth(); + if (rm !== month) { + monthArr.push( + '
' + + settings.months[month] + + '
'); + + month = rm; + scaleUnitsThisMonth = 0; + } + scaleUnitsThisMonth++; + + // Fill days & hours + var rgetDay = rday.getDay(); + var getDay = day.getDay(); + if (rgetDay !== getDay) { + dayClass = (today - day === 0) ? + "today" : tools.isHoliday(day.getTime()) ? + "holiday" : dowClass[getDay]; + + dayArr.push( + '
' + + '
' + day.getDate() + '
'); + dowArr.push( + '
' + + '
' + settings.dow[getDay] + '
'); + + day = rday; + hoursInDay = 0; + } + hoursInDay++; + + dayClass = dowClass[rgetDay]; + if (tools.isHoliday(rday)) { + dayClass = "holiday"; + } + horArr.push( + '
' + + rday.getHours() + + '
'); + } + + // Last year + yearArr.push( + '
' + + year + + '
'); + + // Last month + monthArr.push( + '
' + + settings.months[month] + + '
'); + + dayClass = dowClass[day.getDay()]; + + if (tools.isHoliday(day)) { + dayClass = "holiday"; + } + + dayArr.push( + '
' + + '
' + day.getDate() + '
'); + + dowArr.push( + '
' + + '
' + settings.dow[day.getDay()] + '
'); + + dataPanel = core.dataPanel(element, dataPanelWidth); + + // Append panel elements + dataPanel.append( + $row.clone().html(yearArr.join("")), + $row.clone().html(monthArr.join("")), + $row.clone().html(dayArr.join("")), + $row.clone().html(dowArr.join("")), + $row.clone().html(horArr.join("")) + ); + break; + + // **Weeks** + case "weeks": + range = tools.parseWeeksRange(element.dateStart, element.dateEnd); + dataPanelWidth = range.length * tools.getCellSize(); + + year = range[0].getFullYear(); + month = range[0].getMonth(); + week = range[0].getWeekOfYear(); + var diff; + + for (i = 0, len = range.length; i < len; i++) { + rday = range[i]; + + // Fill years + if (week > (week = rday.getWeekOfYear())) { + // partial weeks to subtract from year header + diff = rday.getDate() - 1; + // offset one month (December) if week starts in last year + diff -= !rday.getMonth() ? 0 : 31; + diff /= 7; + yearArr.push( + '
' + + year + + '
'); + year++; + scaleUnitsThisYear = diff; + } + scaleUnitsThisYear++; + + // Fill months + if (rday.getMonth() !== month) { + // partial weeks to subtract from month header + diff = rday.getDate() - 1; + // offset one week if week starts in last month + //diff -= (diff <= 6) ? 0 : 7; + diff /= 7; + monthArr.push( + '
' + + settings.months[month] + + '
'); + month = rday.getMonth(); + scaleUnitsThisMonth = diff; + } + scaleUnitsThisMonth++; + + // Fill weeks + dayArr.push( + '
' + + '
' + week + '
'); + } + + // Last year + yearArr.push( + '
' + + year + + '
'); + + // Last month + monthArr.push( + '
' + + settings.months[month] + + '
'); + + dataPanel = core.dataPanel(element, dataPanelWidth); + + // Append panel elements + dataPanel.append( + $row.clone().html(yearArr.join("")), + $row.clone().html(monthArr.join("")), + $row.clone().html(dayArr.join("")) + ); + break; + + // **Months** + case 'months': + range = tools.parseMonthsRange(element.dateStart, element.dateEnd); + dataPanelWidth = range.length * tools.getCellSize(); + + year = range[0].getFullYear(); + month = range[0].getMonth(); + + for (i = 0, len = range.length; i < len; i++) { + rday = range[i]; + + // Fill years + if (rday.getFullYear() !== year) { + yearArr.push( + '
' + + year + + '
'); + year = rday.getFullYear(); + scaleUnitsThisYear = 0; + } + scaleUnitsThisYear++; + monthArr.push( + '
' + + (1 + rday.getMonth()) + '
'); + } + + // Last year + yearArr.push( + '
' + + year + + '
'); + + dataPanel = core.dataPanel(element, dataPanelWidth); + + // Append panel elements + dataPanel.append( + $row.clone().html(yearArr.join("")), + $row.clone().html(monthArr.join("")) + ); + break; + + // **Days (default)** + default: + range = tools.parseDateRange(element.dateStart, element.dateEnd); + dataPanelWidth = range.length * tools.getCellSize(); + + var dateBefore = ktkGetNextDate(range[0], -1); + year = dateBefore.getFullYear(); + month = dateBefore.getMonth(); + //day = dateBefore; // <- never used? + + for (i = 0, len = range.length; i < len; i++) { + rday = range[i]; + + // Fill years + if (rday.getFullYear() !== year) { + yearArr.push( + '
' + + year + + '
'); + year = rday.getFullYear(); + scaleUnitsThisYear = 0; + } + scaleUnitsThisYear++; + + // Fill months + if (rday.getMonth() !== month) { + monthArr.push( + '
' + + settings.months[month] + + '
'); + month = rday.getMonth(); + scaleUnitsThisMonth = 0; + } + scaleUnitsThisMonth++; + + day = rday.getDay(); + dayClass = dowClass[day]; + if (tools.isHoliday(rday)) { + dayClass = "holiday"; + } + + dayArr.push( + '
' + + '
' + rday.getDate() + '
'); + dowArr.push( + '
' + + '
' + settings.dow[day] + '
'); + } //for + + // Last year + yearArr.push( + '
' + + year + + '
'); + + // Last month + monthArr.push( + '
' + + settings.months[month] + + '
'); + + dataPanel = core.dataPanel(element, dataPanelWidth); + + // Append panel elements + dataPanel.append( + $row.clone().html(yearArr.join("")), + $row.clone().html(monthArr.join("")), + $row.clone().html(dayArr.join("")), + $row.clone().html(dowArr.join("")) + ); + } + + return $('
').append(dataPanel); + }, + + // **Navigation** + navigation: function (element) { + var ganttNavigate = null; + // Scrolling navigation is provided by setting + // `settings.navigate='scroll'` + if (settings.navigate === "scroll") { + ganttNavigate = $('