list_modal.ejs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <% if (ctx.session.sessionUser.accountId === ctx.tender.data.user_id && ctx.tender.data.ledger_status === auditConst.status.checked &&
  2. (settles.length === 0 || settles[settles.length- 1].audit_status === auditConst.status.checked)) { %>
  3. <!--弹出添加期-->
  4. <div class="modal fade" id="add-qi" data-backdrop="static">
  5. <div class="modal-dialog" role="document">
  6. <form class="modal-content" action="/tender/<%- ctx.tender.id %>/settle/add" method="post" onsubmit="return checkValidSettle(this);">
  7. <div class="modal-header">
  8. <h5 class="modal-title">添加新一期</h5>
  9. </div>
  10. <div class="modal-body">
  11. <div class="form-group">
  12. <label>期</label>
  13. <input class="form-control form-control-sm" value="第 <%- settles.length + 1 %> 期" type="text" readonly="">
  14. </div>
  15. <div class="form-group">
  16. <label>结算年月<b class="text-danger">*</b></label>
  17. <input class="datepicker-here form-control form-control-sm" autocomplete="off" readonly placeholder="点击选择年月" data-view="months" data-min-view="months" data-date-format="yyyy-MM" data-language="zh" type="text" name="date" autocomplete="off">
  18. </div>
  19. <div class="form-group">
  20. <label>结算周期<b class="text-danger">*</b></label>
  21. <input class="datepicker-here form-control form-control-sm" autocomplete="off" readonly placeholder="点击选择时间" data-range="true" data-multiple-dates-separator=" ~ " data-language="zh" type="text" name="period" autocomplete="off">
  22. </div>
  23. </div>
  24. <div class="modal-footer">
  25. <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
  26. <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
  27. <button type="submit" class="btn btn-primary btn-sm" id="add-stage-btn">确定添加</button>
  28. </div>
  29. </form>
  30. </div>
  31. </div>
  32. <% } %>
  33. <!--审批流程/结果-->
  34. <div class="modal fade" id="sp-list" data-backdrop="static">
  35. <div class="modal-dialog modal-lg" role="document">
  36. <div class="modal-content">
  37. <div class="modal-header">
  38. <h5 class="modal-title">审批流程</h5>
  39. </div>
  40. <div class="modal-body">
  41. <div class="row">
  42. <div class="col-4 modal-height-500" style="overflow: auto">
  43. <div class="card mt-3">
  44. <ul class="list-group list-group-flush" id="auditor-list">
  45. </ul>
  46. </div>
  47. </div>
  48. <div class="col-8 modal-height-500" style="overflow: auto" id="audit-list">
  49. </div>
  50. </div>
  51. </div>
  52. <div class="modal-footer">
  53. <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. <% if (settles.length > 0 && settles[0].user_id === ctx.session.sessionUser.accountId) { %>
  59. <!--设置-->
  60. <div class="modal fade" id="edit" data-backdrop="static">
  61. <div class="modal-dialog" role="document">
  62. <form class="modal-content" action="/tender/<%- ctx.tender.id %>/settle/save" method="post" onsubmit="return checkValidSettle(this);">
  63. <div class="modal-header">
  64. <h5 class="modal-title">期编辑</h5>
  65. </div>
  66. <div class="modal-body">
  67. <div class="form-group">
  68. <label>期</label>
  69. <input class="form-control form-control-sm" id="edit-name" value="第 <%- settles[0].order %> 期" type="text" readonly="" name="name">
  70. </div>
  71. <div class="form-group">
  72. <label>结算年月<b class="text-danger">*</b></label>
  73. <input class="datepicker-here form-control form-control-sm" autocomplete="off" readonly name="date" placeholder="点击选择年月" data-view="months" data-min-view="months" data-date-format="yyyy-MM" data-language="zh" type="text">
  74. </div>
  75. <div class="form-group">
  76. <label>结算周期<b class="text-danger">*</b></label>
  77. <input class="datepicker-here form-control form-control-sm" autocomplete="off" readonly name="period" placeholder="点击选择时间" data-range="true" data-multiple-dates-separator=" ~ " data-language="zh" type="text">
  78. </div>
  79. </div>
  80. <div class="modal-footer">
  81. <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
  82. <input type="hidden" name="order" id="edit-order" value="<%- settles[0].order %>">
  83. <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
  84. <button type="submit" class="btn btn-primary btn-sm" id="edit-ok" >确定修改</button>
  85. </div>
  86. </form>
  87. </div>
  88. </div>
  89. <% } %>
  90. <script src="/public/js/datepicker/datepicker.min.js"></script>
  91. <script src="/public/js/datepicker/datepicker.zh.js"></script>
  92. <script src="/public/js/moment/moment.min.js"></script>
  93. <script>
  94. const tenderId = '<%- ctx.tender.id %>';
  95. const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
  96. const auditType = JSON.parse('<%- JSON.stringify(auditType) %>');
  97. $('.datepicker-here').datepicker({
  98. autoClose: true,
  99. });
  100. $('.edit-stage').on('click', function () {
  101. const index = parseInt($(this).data('index'));
  102. const editDate = $('#edit-date').datepicker().data('datepicker');
  103. $('#edit-name').val('第 ' + settles[index].order + ' 期');
  104. $('#edit-order').val(settles[index].order);
  105. if (settles[index].s_time && settles[index].s_time !== '') {
  106. editDate.selectDate(new Date(settles[index].s_time));
  107. }
  108. const period = [];
  109. for (const p of settles[index].period.split('~')) {
  110. if (p && p !== '') {
  111. period.push(new Date(p));
  112. }
  113. }
  114. const editPeriod = $('#edit-period').datepicker().data('datepicker');
  115. if (period.length > 0) {
  116. editPeriod.selectDate(period);
  117. }
  118. });
  119. function checkValidSettle(obj) {
  120. const date = $('input[name=date]', obj).val();
  121. if (date === '') {
  122. toastr.error('请选择结算年月');
  123. return false;
  124. }
  125. const period = $('input[name=period]', obj).val();
  126. if (period === '') {
  127. toastr.error('请选择结算周期');
  128. return false;
  129. }
  130. const startDate = period.split('~')[0];
  131. const endDate = period.split('~')[1] ? period.split('~')[1] : null;
  132. if ((startDate.indexOf(date) === -1 && !endDate) || (startDate.indexOf(date) === -1 && endDate && endDate.indexOf(date) === -1)) {
  133. toastr.error('所选日期与当前月份不匹配,请重新选择');
  134. $('input[name="period"]', obj).parents('.form-group').find('.text-danger').remove();
  135. $('input[name="period"]', obj).parents('.form-group').append('<small class="text-danger">所选日期与当前月份不匹配,请重新选择</small>');
  136. return false;
  137. }
  138. return true;
  139. }
  140. $('#audit-list').on('click', 'a', function() {
  141. const type = $(this).data('target')
  142. const auditCard = $(this).parent().parent()
  143. if (type === 'show') {
  144. $(this).data('target', 'hide')
  145. auditCard.find('.fold-card').slideDown('swing', () => {
  146. auditCard.find('#end-target').text($(this).data('idx') + '#')
  147. auditCard.find('#fold-btn').text('收起历史审核记录')
  148. })
  149. } else {
  150. $(this).data('target', 'show')
  151. auditCard.find('.fold-card').slideUp('swing', () => {
  152. auditCard.find('#end-target').text('1#')
  153. auditCard.find('#fold-btn').text('展开历史审核记录')
  154. })
  155. }
  156. });
  157. const getGroupAuditHtml = function (group) {
  158. return group.map(u => { return `<small class="d-inline-block text-dark mx-1" title="${u.role}" data-auditorId="${u.aid}">${u.name}</small>`; }).join('');
  159. };
  160. const getAuditTypeHtml = function (type) {
  161. if (type === auditType.key.common) return '';
  162. return `<div class="li-subscript"><span class="badge badge-pill badge-${auditType.info[type].class} p-1 badge-bg-small"><small>${auditType.info[type].short}</small></span></div>`;
  163. };
  164. const getAuditTypeText = function (type) {
  165. if (type === auditType.key.common) return '';
  166. return `<span class="text-${auditType.info[type].class}">${auditType.info[type].long}</span>`;
  167. };
  168. const getAuditorsHtml = function (auditors) {
  169. const auditorsHTML = [];
  170. auditors.forEach((group, idx) => {
  171. if (idx === 0) {
  172. auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
  173. <span class="mr-1"><i class="fa fa fa-play-circle fa-rotate-90"></i></span>
  174. <span class="text-muted">${getGroupAuditHtml(group)}</span>
  175. <span class="badge badge-light badge-pill ml-auto"><small>原报</small></span>
  176. </li>`);
  177. } else if(idx === auditors.length -1 && idx !== 0) {
  178. auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
  179. <span class="mr-1"><i class="fa fa fa-stop-circle fa-rotate-90"></i></span>
  180. <span class="text-muted">${getGroupAuditHtml(group)}</span>
  181. <div class="d-flex ml-auto">
  182. ${getAuditTypeHtml(group[0].audit_type)}
  183. <span class="badge badge-light badge-pill ml-auto"><small>终审</small></span>
  184. </div>
  185. </li>`);
  186. } else {
  187. auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
  188. <span class="mr-1"><i class="fa fa fa-chevron-circle-down"></i></span>
  189. <span class="text-muted">${getGroupAuditHtml(group)}</span>
  190. <div class="d-flex ml-auto">
  191. ${getAuditTypeHtml(group[0].audit_type)}
  192. <span class="badge badge-light badge-pill"><small>${transFormToChinese(idx)}审</small></span>
  193. </div>
  194. </li>`);
  195. }
  196. });
  197. return auditorsHTML;
  198. }
  199. const getAuditHistroyHtml = function (auditHistory) {
  200. const historyHTML = [];
  201. auditHistory.forEach((his, idx) => {
  202. if (idx === auditHistory.length - 1 && auditHistory.length !== 1) {
  203. historyHTML.push(`<div class="text-right"><a href="javascript: void(0);" id="fold-btn" data-target="show">展开历史审批流程</a></div>`);
  204. }
  205. historyHTML.push(`<div class="${idx < auditHistory.length - 1 ? 'fold-card' : ''}">`);
  206. historyHTML.push(`<div class="text-center text-muted">${idx+1}#</div>`);
  207. historyHTML.push(`<ul class="timeline-list list-unstyled mt-2 ${ idx === auditHistory.length - 1 && auditHistory.length !== 1 ? 'last-auditor-list' : '' }">`);
  208. his.forEach((group) => {
  209. historyHTML.push(`<li class="timeline-list-item pb-2 ${ group.audit_status === auditConst.status.uncheck && idx === auditHistory.length - 1 && auditHistory.length !== 1 ? 'is_uncheck' : ''}">`);
  210. if (group.auditYear) {
  211. historyHTML.push(`<div class="timeline-item-date">${group.auditYear}<span>${group.auditDate}</span><span>${group.auditTime}</span></div>`);
  212. }
  213. if (group.audit_order < his.length - 1) {
  214. historyHTML.push('<div class="timeline-item-tail"></div>');
  215. }
  216. if (group.audit_status === auditConst.status.checked) {
  217. historyHTML.push('<div class="timeline-item-icon bg-success text-light"><i class="fa fa-check"></i></div>');
  218. } else if (group.audit_status === auditConst.status.checkNo || group.audit_status === auditConst.status.checkNoPre || group.status === auditConst.status.checkCancel) {
  219. historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-level-up"></i></div>');
  220. } else if (group.audit_status === auditConst.status.checking) {
  221. historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-ellipsis-h"></i></div>');
  222. } else {
  223. historyHTML.push('<div class="timeline-item-icon bg-secondary text-light"></div>');
  224. }
  225. historyHTML.push('<div class="timeline-item-content">');
  226. if (group.audit_order > 0) {
  227. const statuStr = group.audit_status !== auditConst.status.uncheck ?
  228. `<span class="pull-right ${auditConst.statusClass[group.audit_status]}">${auditConst.statusString[group.audit_status]}</span>` : '';
  229. historyHTML.push(`<div class="py-1">
  230. <span class="text-black-50">
  231. ${ !group.is_final ? group.audit_order + '' : '终' }审 ${getAuditTypeText(group.audit_type)}
  232. </span>
  233. ${statuStr}
  234. </div>`);
  235. } else {
  236. historyHTML.push(` <div class="py-1">
  237. <span class="text-black-50">原报</span>
  238. <span class="pull-right text-success">${idx !== 0 ? '重新' : '' }上报审批</span>
  239. </div>`);
  240. }
  241. historyHTML.push('<div class="card"><div class="card-body px-3 py-0">');
  242. for (const [i, auditor] of group.auditors.entries()) {
  243. historyHTML.push(`<div class="card-text p-2 py-3 row ${ ( i > 0 ? 'border-top' : '') }">`);
  244. historyHTML.push(`<div class="col"><span class="h6">${auditor.name}</span><span class="text-muted ml-1">${auditor.role}</span></div>`);
  245. historyHTML.push('<div class="col">');
  246. if (auditor.audit_status === auditConst.status.checked) {
  247. historyHTML.push('<span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>');
  248. } if (auditor.audit_status === auditConst.status.checkNo || auditor.audit_status === auditConst.status.checkNoPre || auditor.audit_status === auditConst.status.checkCancel) {
  249. historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>');
  250. }
  251. historyHTML.push('</div>');
  252. if (group.audit_order > 0 && auditor.opinion) {
  253. historyHTML.push(`<div class="col-12 py-1 bg-light"><i class="fa fa-commenting-o mr-1"></i>${auditor.opinion}</div>`);
  254. }
  255. historyHTML.push('</div>');
  256. }
  257. historyHTML.push('</div></div>');
  258. historyHTML.push('</div>');
  259. historyHTML.push('</li>');
  260. });
  261. historyHTML.push('</div>');
  262. historyHTML.push('</ul>');
  263. });
  264. return historyHTML.join('');
  265. }
  266. // 获取审批流程
  267. $('a[data-target="#sp-list" ]').on('click', function () {
  268. postData('/tender/' + tenderId + '/settle/auditors', { order: $(this).attr('s-order') }, function (result) {
  269. $('#auditor-list').html(getAuditorsHtml(result.hisUserGroup));
  270. $('#audit-list').html(getAuditHistroyHtml(result.auditHistory));
  271. });
  272. });
  273. $(window).resize(checkTableWidth);
  274. function checkTableWidth() {
  275. if($('table th[name=contract_tp]').outerWidth() < 107) {
  276. $('table th[name=contract_tp]').html('本期<br>合同计量');
  277. $('table th[name=qc_tp]').html('本期数量<br>变更计量');
  278. $('table th[name=tp]').html('本期<br>完成计量');
  279. $('table th[name=pre_tp]').html('截止上期<br>完成计量');
  280. $('table th[name=end_tp]').html('截止本期<br>完成计量');
  281. } else {
  282. $('table th[name=contract_tp]').html('本期合同计量');
  283. $('table th[name=qc_tp]').html('本期数量变更计量');
  284. $('table th[name=tp]').html('本期完成计量');
  285. $('table th[name=pre_tp]').html('截止上期完成计量');
  286. $('table th[name=end_tp]').html('截止本期完成计量');
  287. }
  288. }
  289. $(function () {
  290. checkTableWidth();
  291. });
  292. </script>