advance_audit.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author lanjianrong
  6. * @date 2020/8/7
  7. * @version
  8. */
  9. $(document).ready(function () {
  10. autoFlashHeight();
  11. $.subMenu({
  12. menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
  13. toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
  14. key: 'menu.1.0.0',
  15. miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
  16. callback: function (info) {
  17. if (info.mini) {
  18. $('.panel-title').addClass('fluid');
  19. $('#sub-menu').removeClass('panel-sidebar');
  20. } else {
  21. $('.panel-title').removeClass('fluid');
  22. $('#sub-menu').addClass('panel-sidebar');
  23. }
  24. autoFlashHeight();
  25. }
  26. });
  27. const decimal = 2
  28. let oldVal = null
  29. let timer = null
  30. let oldSearchVal = null
  31. handleFileList(fileList)
  32. // 控制上报弹窗的文案
  33. function checkModal(isHide) {
  34. $('#start-modal').empty()
  35. if (isHide) {
  36. // 隐藏上传按钮
  37. $('#start-modal').append('<p class="text-danger">无法上报,请设置审批流程。</p>')
  38. $('#tm-submit').hide()
  39. } else {
  40. $('#start-modal').append(`<p>确认上报第${advance.order}期${advance.type === 0 ? '开工' : '材料'}预付款?</p>`)
  41. $('#tm-submit').show()
  42. }
  43. }
  44. $('#gr-search').bind('input propertychange', function(e) {
  45. oldSearchVal = e.target.value
  46. timer && clearTimeout(timer)
  47. timer = setTimeout(() => {
  48. const newVal = $('#gr-search').val()
  49. let html = ''
  50. if (newVal && newVal === oldSearchVal) {
  51. accountList.filter(item => item && cur_uid !== item.id && (item.name.indexOf(newVal) !== -1 || (item.mobile && item.mobile.indexOf(newVal) !== -1))).forEach(item => {
  52. html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
  53. <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
  54. class="ml-auto">${item.mobile || ''}</span></p>
  55. <span class="text-muted">${item.role || ''}</span>
  56. </dd>`
  57. })
  58. $('.book-list').empty()
  59. $('.book-list').append(html)
  60. } else {
  61. if (!$('.acc-btn').length) {
  62. accountGroup.forEach((group, idx) => {
  63. if (!group) return
  64. html += `<dt><a href="javascript: void(0);" class="acc-btn" data-groupid="${idx}" data-type="hide"><i class="fa fa-plus-square"></i>
  65. </a> ${group.groupName}</dt>
  66. <div class="dd-content" data-toggleid="${idx}">`
  67. group.groupList.forEach(item => {
  68. if (item.id !== cur_uid) {
  69. html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
  70. <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
  71. class="ml-auto">${item.mobile || ''}</span></p>
  72. <span class="text-muted">${item.role || ''}</span>
  73. </dd>`
  74. }
  75. });
  76. html += '</div>'
  77. })
  78. $('.book-list').empty()
  79. $('.book-list').append(html)
  80. }
  81. }
  82. }, 400);
  83. })
  84. // 添加审批流程按钮逻辑
  85. $('.book-list').on('click', 'dt', function () {
  86. const idx = $(this).find('.acc-btn').attr('data-groupid')
  87. const type = $(this).find('.acc-btn').attr('data-type')
  88. if (type === 'hide') {
  89. $(this).parent().find(`div[data-toggleid="${idx}"]`).show(() => {
  90. $(this).children().find('i').removeClass('fa-plus-square').addClass('fa-minus-square-o')
  91. $(this).find('.acc-btn').attr('data-type', 'show')
  92. })
  93. } else {
  94. $(this).parent().find(`div[data-toggleid="${idx}"]`).hide(() => {
  95. $(this).children().find('i').removeClass('fa-minus-square-o').addClass('fa-plus-square')
  96. $(this).find('.acc-btn').attr('data-type', 'hide')
  97. })
  98. }
  99. return false
  100. })
  101. // 添加到审批流程中
  102. $('dl').on('click', 'dd', function () {
  103. const id = parseInt($(this).data('id'))
  104. if (id !== 0) {
  105. postData(preUrl + '/audit/add', { auditorId: id }, (datas) => {
  106. // <p class="m-0 ml-2"><small class="text-muted">中交第一公路工程局有限公司国道311线满别公路施工一分部</small></p>
  107. const html = [];
  108. // 如果是重新上报,添加到重新上报列表中
  109. const auditorshtml = [];
  110. for (const [index,data] of datas.entries()) {
  111. if (index !== 0) {
  112. html.push('<li class="list-group-item" auditorId="'+ data.audit_id +'">');
  113. if (shenpi_status === shenpiConst.sp_status.sqspr || (shenpi_status === shenpiConst.sp_status.gdzs && index+1 !== datas.length)) {
  114. html.push('<a href="javascript: void(0)" class="text-danger pull-right">移除</a>');
  115. }
  116. html.push('<span>');
  117. html.push(data.order + ' ');
  118. html.push(data.name + ' ');
  119. html.push('</span>');
  120. html.push('<small class="text-muted">');
  121. html.push(data.role);
  122. html.push('</small>');
  123. html.push(`<p class="m-0 ml-2"><small class="text-muted">${data.company}</small></p></li>`);
  124. }
  125. // 添加新审批人流程修改
  126. auditorshtml.push('<li class="list-group-item" data-auditorid="' + data.audit_id + '">');
  127. auditorshtml.push('<i class="fa ' + (index+1 === datas.length ? 'fa-stop-circle' : 'fa-chevron-circle-down') + '"></i> ');
  128. auditorshtml.push(data.name + ' <small class="text-muted">' + data.role + '</small>');
  129. if (index === 0) {
  130. auditorshtml.push('<span class="pull-right">原报</span>');
  131. } else if (index+1 === datas.length) {
  132. auditorshtml.push('<span class="pull-right">终审</span>');
  133. } else {
  134. auditorshtml.push('<span class="pull-right">'+ transFormToChinese(index) +'审</span>');
  135. }
  136. auditorshtml.push('</li>');
  137. }
  138. $('#auditors').html(html.join(''));
  139. $('#auditors2').html(auditorshtml.join(''));
  140. // if ($('.fa-stop-circle').length) {
  141. // $('.fa-stop-circle').removeClass('fa-stop-circle').addClass('fa-chevron-circle-down')
  142. // }
  143. // const auditorsHTML = `<li class="list-group-item" data-auditorId='${data.audit_id}'><i class="fa fa fa-stop-circle" ></i> ${data.name} <small class="text-muted">${data.role}</small></li>`
  144. // $('#auditors2').append(auditorsHTML)
  145. if ($('#auditors')[0].children.length > 0) {
  146. checkModal(false)
  147. }
  148. });
  149. }
  150. });
  151. // 删除审批人
  152. $('body').on('click', '#auditors li>a', function () {
  153. const li = $(this).parent()
  154. const data = {
  155. auditorId: parseInt(li.attr('auditorId')),
  156. };
  157. postData(preUrl + '/audit/delete', data, (result) => {
  158. li.remove();
  159. for (const rst of result) {
  160. const aLi = $('li[auditorId=' + rst.audit_id + ']');
  161. $('span', aLi).text(rst.order + ' ' + rst.name + ' ')
  162. }
  163. // 删除左边审核人
  164. $(`#auditors2 li[data-auditorid='${data.auditorId}']`).remove();
  165. if ($('#auditors2 li').length !== 0 && !$('#auditors2 li i').hasClass('fa-stop-circle')) {
  166. $('#auditors2 li').eq($('#auditors2 li').length-1).children('i')
  167. .removeClass('fa-chevron-circle-down').addClass('fa-stop-circle');
  168. }
  169. for (let i = 0; i < $('#auditors2 li').length; i++) {
  170. $('#auditors2 li').eq(i).find('.pull-right').text(i === 0 ? '原报' : (i+1 === $('#auditors2 li').length ? '终' : transFormToChinese(i)) + '审');
  171. }
  172. })
  173. });
  174. $('#au-btn').on('click','a', function() {
  175. const content = $(this).data('target')
  176. switch (content) {
  177. case '#sub-sp':
  178. if ($('#auditors')[0].children.length) {
  179. checkModal(false)
  180. } else {
  181. checkModal(true)
  182. }
  183. break;
  184. default:
  185. break;
  186. }
  187. })
  188. // 上报审批
  189. $('#tm-submit').click(function() {
  190. const pay_ratio = parseFloat($(`.pay-input[data-type=0]`).val())
  191. const cur_amount = parseFloat(parseFloat($(`.pay-input[data-type=1]`).val()).toFixed(decimal))
  192. if (!pay_ratio || !cur_amount) {
  193. return toastr.error('请填写本期金额!')
  194. }
  195. const prev_amount = prevAdvance && prevAdvance.prev_total_amount || 0
  196. const prev_total_amount = ZhCalc.add(cur_amount, prev_amount)
  197. const remark = filterText($('#ad-remark').val())
  198. const data = {pay_ratio, cur_amount, prev_amount, prev_total_amount, remark, status: auditConst.status.checking}
  199. postData(preUrl + '/audit/start', data, (data) => {
  200. window.location.reload()
  201. }, () => {
  202. window.location.reload()
  203. })
  204. })
  205. // 重新上报
  206. $('#sp-list2-btn').click(() => {
  207. $('#tm-submit').trigger('click')
  208. })
  209. // 转化成两位小数
  210. function fixedToSub(s, decimal = 2) {
  211. return parseFloat(parseFloat(s).toFixed(decimal))
  212. }
  213. // 自动转换支付比例和本期金额
  214. $('.pay-input').on('change', function(e) {
  215. let val = parseFloat(e.target.value)
  216. const p_amount = prevAdvance && prevAdvance.prev_total_amount || 0 // 截止本期金额
  217. const re_amount = ZhCalc.sub(advancePayTotal, p_amount) // 剩余未付款的总额
  218. const min = parseFloat($(this).attr('min'))
  219. const max = parseFloat($(this).attr('max'))
  220. const type = parseInt($(this).data('type'))
  221. let pay_ratio = null
  222. let cur_amount = null
  223. let isLimitMax = false // 用来判断是否达到最大
  224. if (val < min) {
  225. // 限制最小值为min
  226. $(this).val(min)
  227. val = min
  228. }
  229. if (max && val > max) {
  230. // 限制最大值为max
  231. $(this).val(max)
  232. val = max
  233. }
  234. // 本期金额转化
  235. if (type === 1) {
  236. if (val >= re_amount) {
  237. // 限制不能超过最大值
  238. val = re_amount
  239. isLimitMax = true
  240. }
  241. $(this).val(isLimitMax ? val : fixedToSub(val, decimal)) // 重新赋值限制只有两位小数
  242. const pay_a_input = $(`.pay-input[data-type=${reverse(type)}]`)
  243. pay_ratio = ZhCalc.mul(ZhCalc.div(val, advancePayTotal), 100).toFixed(2)
  244. cur_amount = isLimitMax ? re_amount : ZhCalc.round(val, decimal)
  245. pay_a_input.val(pay_ratio)
  246. const total = ZhCalc.add(cur_amount, p_amount).toString().split('.')[1] || ''
  247. // 截止本期金额文案更新
  248. $('#p_total2').text(formatMoney(ZhCalc.add(cur_amount, p_amount), ',', isLimitMax ? total.length : 2) + '元')
  249. } else {
  250. // 支付比例转化
  251. val = fixedToSub(val)
  252. if (val.toFixed(2) === max.toFixed(2)) {
  253. // 比例达到最大,特殊处理金额的显示小数点
  254. val = fixedToSub(max, 2);
  255. isLimitMax = true
  256. }
  257. $(this).val(val) // 重新赋值限制只有两位小数
  258. const cur_m_input = $(`.pay-input[data-type=${reverse(type)}]`)
  259. cur_amount = isLimitMax ? re_amount : ZhCalc.round(ZhCalc.mul(advancePayTotal, ZhCalc.div(val, 100), 10), decimal)
  260. pay_ratio = val
  261. cur_m_input.val(cur_amount)
  262. const total = ZhCalc.add(cur_amount, p_amount).toString().split('.')[1] || ''
  263. // 截止本期金额文案更新
  264. $('#p_total2').text(formatMoney(ZhCalc.add(cur_amount, p_amount), ',', isLimitMax ? total.length : 2) + '元')
  265. }
  266. const data = {
  267. pay_ratio,
  268. cur_amount,
  269. }
  270. oldVal = {
  271. cur_amount: parseFloat($(`.pay-input[data-type=${1}]`).val()),
  272. remark: filterText($('#ad-remark').val())
  273. }
  274. clearTimeout(timer)
  275. timer = setTimeout(() => {
  276. if (checkInput()) {
  277. update(data)
  278. clearTimeout(timer)
  279. }
  280. }, 500);
  281. })
  282. const payDate = $('.pay-date-input').datepicker().data('datepicker');
  283. payDate.selectDate(new Date(advance.pay_time));
  284. $('.pay-date-input').datepicker({
  285. onShow: function () {
  286. $('.pay-date-input').attr('readOnly', true);
  287. },
  288. onHide: function (dp, animationCompleted) {
  289. if(animationCompleted) {
  290. $('.pay-date-input').attr('readOnly', false);
  291. const val = $('.pay-date-input').val();
  292. // 日期格式判断
  293. if (!(isNaN(val)&&!isNaN(Date.parse(val)))) {
  294. toastr.error('日期格式有误!');
  295. $('.pay-date-input').val(moment(advance.pay_time).format('YYYY-MM-DD'));
  296. payDate.selectDate(new Date(advance.pay_time));
  297. } else if(val !== moment(advance.pay_time).format('YYYY-MM-DD')) {
  298. const data = {
  299. pay_time: val
  300. };
  301. // console.log(data);
  302. update(data);
  303. advance.pay_time = new Date(val);
  304. }
  305. }
  306. }
  307. });
  308. function checkInput() {
  309. const newVal = {
  310. cur_amount: parseFloat($(`.pay-input[data-type=${1}]`).val()),
  311. remark: filterText($('#ad-remark').val())
  312. }
  313. return newVal.cur_amount === oldVal.cur_amount && newVal.remark === oldVal.remark
  314. }
  315. $('#ad-remark').on('change', function(e) {
  316. const remark = filterText(e.target.value);
  317. oldVal = {
  318. pay_ratio: parseFloat($(`.pay-input[data-type=${0}]`).val()),
  319. cur_amount: parseFloat($(`.pay-input[data-type=${1}]`).val()),
  320. remark
  321. }
  322. const data = oldVal
  323. clearTimeout(timer)
  324. timer = setTimeout(() => {
  325. if (checkInput()) {
  326. update(data)
  327. clearTimeout(timer)
  328. }
  329. }, 500);
  330. })
  331. function filterText(text) {
  332. if (!text) return null
  333. return text.replace(/(\r\n)|(\n)/g, '<br/>').replace(/\s/g, ' ')
  334. }
  335. function update(data) {
  336. postData(preUrl + '/update', data)
  337. }
  338. // $('#file-modal-target').click(function () {
  339. // $('#file-modal').trigger('click')
  340. // })
  341. $('#file-ok').click(function () {
  342. const files = Array.from($('#file-modal')[0].files)
  343. const valiData = files.map(v => {
  344. const ext = v.name.substring(v.name.lastIndexOf('.') + 1)
  345. return {
  346. size: v.size,
  347. ext
  348. }
  349. })
  350. if (validateFiles(valiData)) {
  351. if (files.length) {
  352. const formData = new FormData()
  353. files.forEach(file => {
  354. formData.append('name', file.name)
  355. formData.append('size', file.size)
  356. formData.append('file', file)
  357. })
  358. postDataWithFile(preUrl + '/file/upload', formData, function (result) {
  359. handleFileList(result)
  360. $('#file-cancel').click()
  361. });
  362. }
  363. }
  364. })
  365. function handleFileList(files = []) {
  366. $('#file-content').empty()
  367. // const { uncheck, checkNo } = auditConst.status
  368. const newFiles = files.map(file => {
  369. let showDel = false;
  370. if (file.uid === cur_uid) {
  371. // if (!curAuditor) {
  372. // advance.status === uncheck && cur_uid === advance.uid && (showDel = true)
  373. // advance.status === checkNo && cur_uid === advance.uid && (showDel = true)
  374. // } else {
  375. // curAuditor.audit_id === cur_uid && (showDel = true)
  376. // }
  377. if (advance.status === auditConst.status.checked) {
  378. showDel = Boolean(file.extra_upload )
  379. } else {
  380. showDel = true
  381. }
  382. }
  383. return {...file, showDel}
  384. })
  385. let html = advance.filePermission ? `<tr><td colspan="3"><a href="#addfujian" data-toggle="modal" class="btn btn-sm btn-light text-primary" data-placement="bottom" title="" data-original-title="添加清单"><i class="fa fa-cloud-upload" aria-hidden="true"></i> 上传附件</a></td></tr>` : '';
  386. newFiles.forEach((file, idx) => {
  387. if (file.showDel) {
  388. html += `<tr><td width="70">${idx + 1}</td><td><a href="${file.filepath}" target="_blank">${file.filename}</a></td><td width="90"><a href="javascript: void(0);" class="text-danger file-del" data-id="${file.id}">移除</a></td></tr>`
  389. } else {
  390. html += `<tr><td width="70">${idx + 1}</td><td><a href="${file.filepath}" target="_blank">${file.filename}</a></td><td width="90"></td></tr>`
  391. }
  392. })
  393. $('#file-content').append(html)
  394. }
  395. $('#file-content').on('click', 'a', function () {
  396. if ($(this).hasClass('file-del')) {
  397. const id = $(this).data('id')
  398. postData(preUrl + '/file/del', {id}, (result) => {
  399. handleFileList(result)
  400. })
  401. }
  402. })
  403. })
  404. /**
  405. * 校验文件大小、格式
  406. * @param {Array} files 文件数组
  407. */
  408. function validateFiles(files) {
  409. if (files.length > 10) {
  410. toastr.error('至多同时上传10个文件');
  411. return false
  412. }
  413. return files.every(file => {
  414. if (file.size > 1024 * 1024 * 30) {
  415. toastr.error('文件大小限制为30MB');
  416. return false
  417. }
  418. if (whiteList.indexOf('.' + file.ext) === -1) {
  419. toastr.error('请上传正确的格式文件');
  420. return false
  421. }
  422. return true
  423. })
  424. }
  425. function reverse(num){
  426. return 1^num
  427. }
  428. function formatMoney(s, dot = ',', decimal = 2) {
  429. if (!s) {
  430. s = 0;
  431. return s.toFixed(decimal);
  432. }
  433. s = parseFloat((s + '').replace(/[^\d\.-]/g, '')).toFixed(decimal) + '';
  434. if (!decimal) {
  435. s += '.';
  436. }
  437. const l = s.split('.')[0].split('').reverse(),
  438. r = s.split('.')[1];
  439. let t = '';
  440. for (let i = 0; i < l.length; i++) {
  441. t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? dot : '');
  442. }
  443. const num = t.split('').reverse().join('') + (decimal === 0 ? '' : '.' + r);
  444. return num.replace('-,', '-');
  445. }