quality_info.js 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987
  1. $(document).ready(() => {
  2. autoFlashHeight();
  3. const xmjSpread = SpreadJsObj.createNewSpread($('#xmj-spread')[0]);
  4. const xmjSheet = xmjSpread.getActiveSheet();
  5. const xmjSpreadSetting = {
  6. cols: [
  7. { title: '工程编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 135, formatter: '@', cellType: 'tree' },
  8. { title: '工程名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 195, formatter: '@' },
  9. ],
  10. emptyRows: 0,
  11. headRows: 1,
  12. headRowHeight: [32],
  13. headColWidth: [32],
  14. defaultRowHeight: 21,
  15. headerFont: '12px 微软雅黑',
  16. font: '12px 微软雅黑',
  17. readOnly: true,
  18. };
  19. SpreadJsObj.initSheet(xmjSheet, xmjSpreadSetting);
  20. const xmjTree = createNewPathTree('gather', { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1 });
  21. postData('load', { filter: 'xmj;pos;quality', spec: { loadStatus: 1 } }, function(result) {
  22. const ledgerTree = createNewPathTree('ledger', { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1 });
  23. const pos = new PosData({id: 'id', ledgerId: 'lid',});
  24. ledgerTree.loadDatas(result.xmj);
  25. pos.loadDatas(result.pos);
  26. const recursiveLoad = function (node, parent, type = 'xmj') {
  27. if (type === 'xmj') {
  28. const cur = !node.b_code ? xmjTree.addNode({ id: node.id, tender_id: node.tender_id, code: node.code, name: node.name, rela_type: type, rela_id: node.id, rela_name: '', }, parent) : parent;
  29. if (node.children && node.children.length > 0) {
  30. for (const child of node.children) {
  31. recursiveLoad(child, cur);
  32. }
  33. } else {
  34. const posRange = pos.getLedgerPos(node.id) || [];
  35. for (const pos of posRange) {
  36. recursiveLoad(pos, cur, 'pos');
  37. }
  38. }
  39. }
  40. if (type === 'pos') {
  41. if (!parent) return;
  42. const cur = parent.children ? parent.children.find(x => { return x.name === node.name }) : null;
  43. if (!cur) {
  44. xmjTree.addNode({ id: node.id, tender_id: node.tid, rela_id: parent.id, code: '', name: node.name, rela_type: 'pos', rela_name: node.name, pid: [node.id]}, parent);
  45. } else {
  46. cur.pid.push(node.id);
  47. }
  48. }
  49. };
  50. for (const node of ledgerTree.children) {
  51. recursiveLoad(node);
  52. }
  53. xmjTree.sortTreeNode(false);
  54. const qualityIndex = [];
  55. for (const q of result.quality) {
  56. const key = q.rela_type + ';' + q.rela_id + ';' + q.rela_name;
  57. qualityIndex[key] = q;
  58. }
  59. for (const x of xmjTree.nodes) {
  60. const qua = qualityIndex[x.rela_type + ';' + x.rela_id + ';' + x.rela_name];
  61. if (qua) {
  62. x.gxby_status = qua.gxby_status;
  63. x.gxby_date = qua.gxby_date;
  64. x.dagl_status = qua.dagl_status;
  65. }
  66. }
  67. SpreadJsObj.loadSheetData(xmjSheet, SpreadJsObj.DataType.Tree, xmjTree);
  68. });
  69. class BaseBlock {
  70. constructor(qualityObj, objKey, blockType) {
  71. this.qualityObj = qualityObj;
  72. this.objKey = objKey;
  73. this.obj = $(`#${objKey}`);
  74. this.blockType = blockType;
  75. this.saveUrl = 'save/' + this.blockType;
  76. }
  77. getFilterData() {
  78. if (!this.node) return null;
  79. const result = { rela_type: this.node.rela_type, rela_id: this.node.rela_id, rela_name: this.node.rela_name };
  80. if (this.node.quality) result.quality_id = this.node.quality.id;
  81. return result;
  82. }
  83. getBwName(){
  84. if (!this.node) return '';
  85. const parents = xmjTree.getAllParents(this.node);
  86. parents.shift();
  87. parents.push(this.node);
  88. return parents.map(x => { return x.name; }).join('/');
  89. }
  90. getFileHtml(file) {
  91. if (!file) return '';
  92. const html = [];
  93. html.push('<tr>');
  94. html.push(`<td class="text-center"><input fid="${file.id}" type="checkbox"></td>`);
  95. const qaMark = file.spec_type === 'qa' ? '<span class="badge badge-pill badge-success p-1 mr-2">质</span>' : '';
  96. html.push(`<td>${file.filename} ${qaMark}</td>`);
  97. html.push(`<td class="text-center">${file.user_name}</td>`);
  98. html.push(`<td class="text-center">${moment(file.create_time).format('YYYY-MM-DD')}</td>`);
  99. // const editHtml = file.canEdit ? `<a href="javascript: void(0);" class="mr-1" name="edit-file" fid="${file.id}"><i class="fa fa-pencil fa-fw"></i></a>` : '';
  100. const editHtml = '';
  101. const viewHtml = file.viewpath ? `<a href="${file.viewpath}" class="mr-1" target="_blank"><i class="fa fa-eye fa-fw"></i></a>` : '';
  102. const downHtml = `<a href="javascript: void(0);" onclick="AliOss.downloadFile('${file.filepath}', '${file.filename + file.fileext}')" class="mr-1"><i class="fa fa-download fa-fw"></i></a>`;
  103. const delHtml = file.canEdit || canDelete
  104. ? `<a href="javascript: void(0);" class="mr-1 text-danger" name="del-file" fid="${file.id}"><i class="fa fa-trash-o fa-fw"></i></a>`
  105. : ''; //'<a href="javascript: void(0);" class="mr-1 text-muted"><i class="fa fa-trash-o fa-fw"></i></a>';
  106. html.push(`<td class="text-center">${editHtml}${viewHtml}${downHtml}${delHtml}</td>`);
  107. html.push('</tr>');
  108. return html.join('');
  109. }
  110. getFilesTableHtml(files, key) {
  111. if (!files) return '';
  112. const html = [];
  113. html.push('<table class="table table-bordered"><thead><tr class="text-center"><th width="60px">选择</th><th width="">名称</th><th width="150px">上传人</th><th width="150px">上传时间</th><th width="100px">操作</th></tr></thead>');
  114. html.push(`<tbody id="${key}">`);
  115. for (const f of files) {
  116. html.push(this.getFileHtml(f));
  117. }
  118. html.push('<tbody>');
  119. html.push('</table>');
  120. return html.join('');
  121. }
  122. async uploadFiles(files, blockId = '', specType = ''){
  123. const formData = new FormData();
  124. formData.append('quality_id', this.node.quality.id);
  125. formData.append('block_type', this.blockType);
  126. formData.append('block_id', blockId);
  127. formData.append('spec_type', specType);
  128. let count = 0;
  129. for (const file of files) {
  130. if (file === undefined) {
  131. toastr.error('未选择上传文件。');
  132. return false;
  133. }
  134. if (file.size > 50 * 1024 * 1024) {
  135. toastr.error('上传文件大小超过50MB。');
  136. return false;
  137. }
  138. const fileext = '.' + file.name.toLowerCase().split('.').splice(-1)[0];
  139. if (whiteList.indexOf(fileext) === -1) {
  140. toastr.error('仅支持office文档、图片、压缩包格式,请勿上传' + fileext + '格式文件。');
  141. return false;
  142. }
  143. formData.append('size', file.size);
  144. formData.append('file[]', file);
  145. count++;
  146. }
  147. if (count === 0) {
  148. toastr.warning('没有可上传的文件');
  149. return false;
  150. }
  151. return await postDataWithFileAsync('file/upload', formData);
  152. }
  153. delFiles(files, callback) {
  154. postData('file/del', { del: files}, function(result) {
  155. callback(result);
  156. });
  157. }
  158. selectUploadFiles(setting){
  159. if (!setting) return;
  160. $('#upload-file').val('');
  161. $('#add-file-ok').off('click');
  162. $('#add-file').modal('show');
  163. $('.spec-type-detail').hide();
  164. if (setting.specType) {
  165. $('.spec-type').show();
  166. for (const st of setting.specType) {
  167. $(`.spec-type-${st}`).show();
  168. }
  169. } else {
  170. $('.spec-type').hide();
  171. }
  172. $('#add-file-ok').on("click", function () {
  173. const specType = setting.specType ? $('[name=specType]:checked').val() : '';
  174. setting.select(document.getElementById('upload-file').files, specType);
  175. $('#add-file').modal('hide');
  176. });
  177. }
  178. getControlHtml() {
  179. throw '请在子类中定义';
  180. }
  181. getContentHtml() {
  182. throw '请在子类中定义';
  183. }
  184. showQuality() {
  185. const html = [];
  186. html.push('<div class="title-main d-flex justify-content-between sjs-bar">', this.getControlHtml(), '</div>');
  187. html.push('<div class="sjs-quality scroll-y">', this.getContentHtml(), '</div>');
  188. html.push('</div>');
  189. this.obj.html(html.join(''));
  190. }
  191. showSum() {
  192. this.obj.html('');
  193. }
  194. show(node) {
  195. this.node = node;
  196. this.refresh();
  197. }
  198. refresh(data){
  199. if (data) this.node.quality[this.blockType] = data;
  200. if (!this.node.children || this.node.children.length === 0) {
  201. this.showQuality();
  202. } else {
  203. this.showSum();
  204. }
  205. }
  206. }
  207. class Kaigong extends BaseBlock {
  208. constructor(objKey, qualityObj) {
  209. super(qualityObj, objKey, 'kaigong');
  210. this.filesTable = objKey + '_files';
  211. this.yyFilesTable = objKey + '_yy_files';
  212. this.fileCountKey = objKey + '_filecount';
  213. const self = this;
  214. $('#add-kaigong-ok').click(function() {
  215. const data = self.getFilterData();
  216. data.add = { name: $('[name=kaigong-name]').val(), date: $('[name=kaigong-date]').val() };
  217. postData(self.saveUrl, data, function(result) {
  218. if (self.node.quality) {
  219. self.node.quality.kaigong = result.kaigong
  220. } else {
  221. self.node.quality = result;
  222. }
  223. self.showQuality();
  224. self.qualityObj.jiaogong.refresh(result.jiaogong);
  225. self.qualityObj.pingding.refresh(result.pingding);
  226. $('#add-kaigong').modal('hide');
  227. autoFlashHeight();
  228. });
  229. });
  230. $('body').on('click', '#del-kaigong', function() {
  231. const data = self.getFilterData();
  232. data.del = data.quality_id;
  233. postData(self.saveUrl, data, function(result) {
  234. delete self.node.quality.kaigong;
  235. self.showQuality();
  236. self.qualityObj.jiaogong.refresh(result.jiaogong);
  237. self.qualityObj.pingding.refresh(result.pingding);
  238. autoFlashHeight();
  239. })
  240. });
  241. $('body').on('click', '[name=upload-kg]', function() {
  242. self.selectUploadFiles({
  243. select: async function(files) {
  244. const result = await self.uploadFiles(files);
  245. self.node.quality.kaigong.files.push(...result);
  246. for (const r of result) {
  247. $(`#${self.filesTable}`).append(self.getFileHtml(r));
  248. }
  249. self.refreshFileCountHtml();
  250. self.qualityObj.refreshFileCountHtml();
  251. autoFlashHeight();
  252. }
  253. });
  254. });
  255. $('body').on('click', `#${this.filesTable} [name=del-file]`, function() {
  256. const del = [this.getAttribute('fid')];
  257. self.delFiles(del, function(result) {
  258. for (const r of result) {
  259. $(`input[fid=${r}]`).parent().parent().remove();
  260. const fi = self.node.quality.kaigong.files.findIndex(x => { return x.id === r; });
  261. if (fi >= 0) self.node.quality.kaigong.files.splice(fi, 1);
  262. }
  263. self.refreshFileCountHtml();
  264. self.qualityObj.refreshFileCountHtml();
  265. autoFlashHeight();
  266. });
  267. });
  268. }
  269. _getAddHtml() {
  270. if (!permission.add) return '';
  271. return !this.node.quality || !this.node.quality.kaigong ? '<a href="#add-kaigong" data-toggle="modal" data-target="#add-kaigong" class="btn btn-primary btn-sm" >新增开工</a>' : '';
  272. }
  273. getControlHtml() {
  274. const html = [];
  275. html.push('<div>', this._getAddHtml(), '</div>');
  276. return html.join('');
  277. }
  278. _getCardHtml() {
  279. if (!this.node.quality.kaigong) return '';
  280. const html = [];
  281. html.push('<div class="card mt-2">');
  282. html.push('<div class="card-header d-flex justify-content-between">', this.getBwName(),
  283. `<a href="javascript: void(0)" class="text-danger" id="del-kaigong"><i class="fa fa-trash-o fa-fw"></i></a>`, '</div>');
  284. html.push(`<div class="card-body pt-2"> <div class="my-2"><table class="col-12"><tbody><tr><td width="33%">计划开工日期:${this.node.quality.kaigong.kaigong_date}</td><td width="33%">资料个数:<span id="${this.fileCountKey}">${this.node.quality.kaigong.files.length}</span></td></tr></tbody></table></div>`);
  285. html.push('<hr/>');
  286. html.push('<nav class="nav nav-tabs"><a class="nav-link nav-item active" data-toggle="tab" href="#kg_files">开工资料</a><a class="nav-link nav-item" data-toggle="tab" href="#yy_files" style="display: none;">引用试验资料</a>',
  287. '<div class="ml-auto"><a href="javascript: void(0);" name="upload-kg" class="btn btn-outline-primary btn-sm">上传开工资料</a><a href="#" data-toggle="modal" data-target="#upload-kg" class="btn btn-outline-primary btn-sm ml-1" style="display: none;">引用试验资料</a></div>', '</nav>');
  288. html.push('<div class="tab-content my-2">');
  289. html.push('<div class="tab-pane fade show active" id="kg_files" role="tabpanel" aria-labelledby="home-tab">', this.getFilesTableHtml(this.node.quality.kaigong.files, this.filesTable), '</div>');
  290. html.push('<div class="tab-pane fade show" id="yy_files" role="tabpanel" aria-labelledby="home-tab">', this.getFilesTableHtml(this.node.quality.kaigong.qa_files, this.yyFilesTable), '</div>');
  291. html.push('</div>');
  292. html.push('</div>');
  293. return html.join('');
  294. }
  295. getContentHtml() {
  296. const html = [];
  297. if (this.node.quality && this.node.quality.kaigong) html.push(this._getCardHtml());
  298. return html.join('');
  299. }
  300. refreshFileCountHtml() {
  301. $(`#${this.fileCountKey}`).html(this.node.quality.kaigong.files.length);
  302. }
  303. }
  304. class Gongxu extends BaseBlock {
  305. constructor (objKey, qualityObj) {
  306. super(qualityObj, objKey, 'gongxu');
  307. this.fileTablesPre = objKey + 'Files';
  308. this.fileCountPre = objKey + 'Filecount';
  309. this.pingding = this.qualityObj.pingding;
  310. const self = this;
  311. $('#add-gongxu-ok').click(function() {
  312. const name = $('[name=gongxu-name]').val();
  313. if (!name) return;
  314. if (name.length > 100) {
  315. $('[name=gongxu-name]').addClass('is-invalid');
  316. $('#gongxu-name-hint').show();
  317. return;
  318. } else {
  319. $('[name=gongxu-name]').removeClass('is-invalid');
  320. $('#gongxu-name-hint').hide();
  321. }
  322. const data = self.getFilterData();
  323. const gxid = $('#gongxu-id').val();
  324. if (gxid) {
  325. data.update = { id: gxid, name };
  326. } else {
  327. data.add = { name };
  328. }
  329. postData(self.saveUrl, data, function(result) {
  330. if (data.add) {
  331. if (self.node.quality) {
  332. self.node.quality.gongxu = result.gongxu
  333. } else {
  334. self.node.quality = result;
  335. }
  336. self.qualityObj.jiaogong.refresh(result.jiaogong);
  337. self.qualityObj.pingding.refresh(result.pingding);
  338. self.showQuality();
  339. } else {
  340. const gx = self.node.quality.gongxu.list.find(x => { return x.id === gxid; });
  341. gx.name = name;
  342. $('[name=gx-name]', `.gongxu-card[gxid=${gxid}]`).html(name);
  343. }
  344. $('#add-gongxu').modal('hide');
  345. autoFlashHeight();
  346. });
  347. });
  348. $('body').on('click', '[name=add-gx]', function() {
  349. $('[name=gongxu-name]').val('');
  350. $('#gongxu-id').val('');
  351. $('#add-gongxu').modal('show');
  352. });
  353. $('body').on('click', '[name=del-gx]', function() {
  354. const gxid = this.getAttribute('gxid');
  355. const data = self.getFilterData();
  356. data.del = gxid;
  357. postData(self.saveUrl, data, function(result) {
  358. const gxIndex = self.node.quality.gongxu.list.findIndex(x => { return x.id === gxid; });
  359. self.node.quality.gongxu.list.splice(gxIndex, 1);
  360. self.qualityObj.jiaogong.refresh(result.jiaogong);
  361. self.qualityObj.pingding.refresh(result.pingding);
  362. $(`.gongxu-card[gxid=${gxid}]`).remove();
  363. autoFlashHeight();
  364. });
  365. });
  366. $('body').on('click', '[name=edit-gx]', function() {
  367. const gxid = this.getAttribute('gxid');
  368. const gx = self.node.quality.gongxu.list.find(x =>{ return x.id === gxid; });
  369. $('[name=gongxu-name]').val(gx.name);
  370. $('#gongxu-id').val(gx.id);
  371. $('#add-gongxu').modal('show');
  372. });
  373. $('body').on('click', '[name=upload-gx]', function() {
  374. const gxid = this.getAttribute('gxid');
  375. self.selectUploadFiles({
  376. specType: ['qa'],
  377. select: async function(files, specType) {
  378. const gx = self.node.quality.gongxu.list.find(x => { return x.id === gxid });
  379. const result = await self.uploadFiles(files, gxid, specType);
  380. gx.files.push(...result);
  381. for (const r of result) {
  382. $(`#${self.fileTablesPre}-${gx.id}`).append(self.getFileHtml(r));
  383. }
  384. self.refreshFileCountHtml(gx);
  385. if (specType === 'qa') {
  386. self.pingding.addQaFiles(result);
  387. }
  388. self.qualityObj.refreshFileCountHtml();
  389. autoFlashHeight();
  390. }
  391. });
  392. });
  393. $('body').on('click', '.gongxu-card [name=del-file]', function(){
  394. const gxid = $(this).closest('.gongxu-card').attr('gxid');
  395. const gx = self.node.quality.gongxu.list.find(x => { return x.id === gxid; });
  396. const del = [this.getAttribute('fid')];
  397. self.delFiles(del, function(result) {
  398. const pdRemoveFiles = [];
  399. for (const r of result) {
  400. $(`input[fid=${r}]`).parent().parent().remove();
  401. const fi = gx.files.findIndex(x => { return x.id === r; });
  402. const file = gx.files[fi];
  403. if (file.spec_type === 'qa') pdRemoveFiles.push(file);
  404. if (fi >= 0) gx.files.splice(fi, 1);
  405. }
  406. if (pdRemoveFiles.length > 0) self.pingding.removeQaFiles(pdRemoveFiles);
  407. self.refreshFileCountHtml(gx);
  408. self.qualityObj.refreshFileCountHtml();
  409. autoFlashHeight();
  410. });
  411. });
  412. }
  413. _getAddHtml() {
  414. return permission.add ? '<a href="javascript: void(0)" name="add-gx" class="btn btn-primary btn-sm" >新增工序</a>' : '';
  415. }
  416. getControlHtml() {
  417. const html = [];
  418. html.push('<div>', this._getAddHtml(), '</div>');
  419. return html.join('');
  420. }
  421. _getCardHtml(gx) {
  422. if (!gx) return '';
  423. const html = [];
  424. html.push(`<div class="card mt-2 gongxu-card" gxid="${gx.id}">`);
  425. html.push('<div class="card-header d-flex justify-content-between">');
  426. const editHtml = gx.canEdit ? `<a href="javascript: void(0);" class="ml-1" name="edit-gx" gxid="${gx.id}"><i class="fa fa-pencil fa-fw"></i></a>` : '';
  427. const delHtml = gx.canEdit ? `<a href="javascript: void(0);" class="ml-1 text-danger" name="del-gx" gxid="${gx.id}"><i class="fa fa-trash-o fa-fw"></i></a>` : '';
  428. html.push(`<span style="width: 40%"><span name="gx-name">${gx.name}</span>${editHtml}${delHtml}<a href="javascript: void(0)" class="btn btn-sm btn-light text-primary" gxid="${gx.id}" name="upload-gx">上传文件</a></span>`);
  429. html.push(`<div class="" style="width:30%">资料个数:<span id="${this.fileCountPre}-${gx.id}">${gx.files.length}</span></div>`);
  430. html.push('<div style="width:30%"></div></div>');
  431. html.push('<div class="card-body pt-2">', this.getFilesTableHtml(gx.files, this.fileTablesPre + '-' + gx.id),'</div>');
  432. html.push('</div>');
  433. return html.join('');
  434. }
  435. getContentHtml() {
  436. const html = [];
  437. if (this.node.quality && this.node.quality.gongxu) {
  438. for (const gx of this.node.quality.gongxu.list) {
  439. html.push(this._getCardHtml(gx));
  440. }
  441. }
  442. return html.join('');
  443. }
  444. refreshFileCountHtml(gx) {
  445. $(`#${this.fileCountPre}-${gx.id}`).html(gx.files.length);
  446. }
  447. }
  448. class Pingding extends BaseBlock {
  449. constructor(objKey, qualityObj) {
  450. super(qualityObj, objKey, 'pingding');
  451. this.filesTable = objKey + '_files';
  452. this.sourceFilesTable = objKey + '_source_files';
  453. const self = this;
  454. $('body').on('click', '[name=upload-pd]', function() {
  455. self.selectUploadFiles({
  456. select: async function(files) {
  457. const result = await self.uploadFiles(files);
  458. self.node.quality.pingding.files.push(...result);
  459. for (const r of result) {
  460. $(`#${self.filesTable}`).append(self.getFileHtml(r));
  461. }
  462. autoFlashHeight();
  463. self.qualityObj.refreshFileCountHtml();
  464. }
  465. });
  466. });
  467. $('body').on('click', `#${this.filesTable} [name=del-file]`, function() {
  468. const del = [this.getAttribute('fid')];
  469. self.delFiles(del, function(result) {
  470. for (const r of result) {
  471. $(`input[fid=${r}]`).parent().parent().remove();
  472. const fi = self.node.quality.pingding.files.findIndex(x => { return x.id === r; });
  473. if (fi >= 0) self.node.quality.pingding.files.splice(fi, 1);
  474. }
  475. self.qualityObj.refreshFileCountHtml();
  476. autoFlashHeight();
  477. });
  478. });
  479. $('body').on('click', '[name=upload-pd-source]', function() {
  480. self.selectUploadFiles({
  481. select: async function(files) {
  482. const result = await self.uploadFiles(files, '', 'add');
  483. self.node.quality.pingding.files.push(...result);
  484. for (const r of result) {
  485. $(`#${self.sourceFilesTable}`).append(self.getFileHtml(r));
  486. }
  487. self.qualityObj.refreshFileCountHtml();
  488. autoFlashHeight();
  489. }
  490. });
  491. });
  492. $('body').on('click', `#${this.sourceFilesTable} [name=del-file]`, function() {
  493. const del = [this.getAttribute('fid')];
  494. self.delFiles(del, function(result) {
  495. for (const r of result) {
  496. $(`input[fid=${r}]`).parent().parent().remove();
  497. const fi = self.node.quality.pingding.source_files.findIndex(x => { return x.id === r; });
  498. if (fi >= 0) self.node.quality.pingding.source_files.splice(fi, 1);
  499. }
  500. self.qualityObj.refreshFileCountHtml();
  501. autoFlashHeight();
  502. });
  503. });
  504. }
  505. getControlHtml() {
  506. const html = [];
  507. return html.join('');
  508. }
  509. _getCardHtml() {
  510. if (!this.node.quality.pingding) return '';
  511. const html = [];
  512. html.push('<div class="card mt-2">');
  513. html.push('<div class="card-header d-flex justify-content-between">', this.getBwName(), '<div><a href="javascript: void(0)" class="btn btn-sm btn-light text-primary" name="upload-pd">上传文件</a></div>', '</div>');
  514. html.push('<div class="card-body pt-2">');
  515. html.push('<div class="mt-2">', this.getFilesTableHtml(this.node.quality.pingding.files, this.filesTable), '</div>');
  516. html.push('<nav class="nav nav-tabs mt-4"><a class="nav-link nav-item active" data-toggle="tab" href="#pd-source">评定资料来源</a>',
  517. '<div class="ml-auto"><a href="javascript: void(0)" name="upload-pd-source" class="btn btn-outline-primary btn-sm">补充资料</a></div></nav>');
  518. html.push('<div class="tab-content my-2">');
  519. html.push('<div class="tab-pane fade show active" id="pd_source" role="tabpanel" aria-labelledby="home-tab">', this.getFilesTableHtml(this.node.quality.pingding.source_files, this.sourceFilesTable), '</div>');
  520. html.push('</div>');
  521. html.push('</div>');
  522. html.push('</div>');
  523. return html.join('');
  524. }
  525. getContentHtml() {
  526. const html = [];
  527. if (this.node.quality && this.node.quality.pingding) html.push(this._getCardHtml());
  528. return html.join('');
  529. }
  530. addQaFiles(files) {
  531. for (const f of files) {
  532. const qaF = JSON.parse(JSON.stringify(f));
  533. qaF.canEdit = false;
  534. this.node.quality.pingding.files.push(qaF);
  535. $(`#${this.sourceFilesTable}`).append(this.getFileHtml(qaF));
  536. }
  537. }
  538. removeQaFiles(files) {
  539. for (const f of files) {
  540. const qaFi = this.node.quality.pingding.source_files.findIndex(x => { return x.id === f.id; });
  541. $(`input[fid=${f.id}]`, this.sourceFilesTable).parent().parent().remove();
  542. this.node.quality.pingding.source_files.splice(qaFi, 1);
  543. }
  544. }
  545. }
  546. class Jiaogong extends BaseBlock {
  547. constructor(objKey, qualityObj) {
  548. super(qualityObj, objKey, 'jiaogong');
  549. this.filesTable = objKey + '_files';
  550. const self = this;
  551. $('body').on('click', '[name=upload-jg]', function() {
  552. self.selectUploadFiles({
  553. select: async function(files) {
  554. const result = await self.uploadFiles(files);
  555. self.node.quality.jiaogong.files.push(...result);
  556. for (const r of result) {
  557. $(`#${self.filesTable}`).append(self.getFileHtml(r));
  558. }
  559. self.qualityObj.refreshFileCountHtml();
  560. autoFlashHeight();
  561. }
  562. });
  563. });
  564. $('body').on('click', `#${this.filesTable} [name=del-file]`, function() {
  565. const del = [this.getAttribute('fid')];
  566. self.delFiles(del, function(result) {
  567. for (const r of result) {
  568. $(`input[fid=${r}]`).parent().parent().remove();
  569. const fi = self.node.quality.jiaogong.files.findIndex(x => { return x.id === r; });
  570. if (fi >= 0) self.node.quality.jiaogong.files.splice(fi, 1);
  571. }
  572. self.qualityObj.refreshFileCountHtml();
  573. autoFlashHeight();
  574. });
  575. });
  576. }
  577. getControlHtml() {
  578. const html = [];
  579. return html.join('');
  580. }
  581. _getCardHtml() {
  582. if (!this.node.quality.jiaogong) return '';
  583. const html = [];
  584. html.push('<div class="card mt-2">');
  585. html.push('<div class="card-header d-flex justify-content-between">', this.getBwName(), '</div>');
  586. html.push('<div class="card-body pt-2">');
  587. html.push('<div class="card">', '<div class="card-header d-flex justify-content-between">', '交工工序', '<div><a href="javascript: void(0)" class="btn btn-sm btn-light text-primary" name="upload-jg">上传文件</a></div>', '</div>');
  588. html.push('<div class="card-body pt-2">', this.getFilesTableHtml(this.node.quality.jiaogong.files, this.filesTable), '</div>');
  589. html.push('</div>');
  590. html.push('</div>');
  591. return html.join('');
  592. }
  593. getContentHtml() {
  594. const html = [];
  595. if (this.node.quality && this.node.quality.jiaogong) html.push(this._getCardHtml());
  596. return html.join('');
  597. }
  598. }
  599. class Yinbi extends BaseBlock {
  600. constructor (objKey, qualityObj) {
  601. super(qualityObj, objKey, 'yinbi');
  602. this.beforeFilesPre = objKey + 'BeforeFiles';
  603. this.afterFilesPre = objKey + 'AfterFiles';
  604. const self = this;
  605. $('#add-yinbi-ok').click(function() {
  606. const name = $('[name=yinbi-name]').val();
  607. if (!name) {
  608. toastr.warning('请输入名称');
  609. return;
  610. }
  611. if (name.length > 100) {
  612. toastr.warning('名称超过100,请缩短');
  613. return;
  614. }
  615. const gongxu_id = $('[name=yinbi-gongxu-id]').val();
  616. const gcbw = $('[name=yinbi-gcbw]').val();
  617. const content = $('[name=yinbi-content]').val();
  618. if (gcbw.length > 1000) {
  619. toastr.warning('工程部位超过1000,请缩短');
  620. return;
  621. }
  622. if (content.length > 1000) {
  623. toastr.warning('隐蔽工程说明超过1000,请缩短');
  624. return;
  625. }
  626. const data = self.getFilterData();
  627. const ybid = $('#yinbi-id').val();
  628. if (ybid) {
  629. data.update = { id: ybid, name, gongxu_id, gcbw, content };
  630. } else {
  631. data.add = { name, gongxu_id, gcbw, content };
  632. }
  633. postData(self.saveUrl, data, function(result) {
  634. if (data.add) {
  635. if (self.node.quality) {
  636. self.node.quality.yinbi = result.yinbi
  637. } else {
  638. self.node.quality = result;
  639. }
  640. self.showQuality();
  641. } else {
  642. const yb = self.node.quality.yinbi.list.find(x => { return x.id === ybid; });
  643. yb.name = name;
  644. yb.gongxu_id = gongxu_id;
  645. yb.gcbw = gcbw;
  646. yb.content = content;
  647. self.afterEdit(yb);
  648. }
  649. $('#add-yinbi').modal('hide');
  650. autoFlashHeight();
  651. });
  652. });
  653. $('body').on('click', '[name=add-yb]', function() {
  654. $('[name=yinbi-name]').val('');
  655. $('[name=yinbi-gongxu-id]').html(self._getSelectGongxuHtml());
  656. $('[name=yinbi-gongxu-id]').val('');
  657. $('[name=yinbi-gcbw]').val('');
  658. $('[name=yinbi-content]').val('');
  659. $('#yinbi-id').val('');
  660. $('#add-yinbi').modal('show');
  661. });
  662. $('body').on('click', '[name=del-yb]', function() {
  663. const ybid = this.getAttribute('ybid');
  664. const data = self.getFilterData();
  665. data.del = ybid;
  666. postData(self.saveUrl, data, function(result) {
  667. const ybIndex = self.node.quality.yinbi.list.findIndex(x => { return x.id === ybid; });
  668. self.node.quality.yinbi.list.splice(ybIndex, 1);
  669. $(`.yinbi-card[ybid=${ybid}]`).remove();
  670. autoFlashHeight();
  671. });
  672. });
  673. $('body').on('click', '[name=edit-yb]', function() {
  674. const ybid = this.getAttribute('ybid');
  675. const yb = self.node.quality.yinbi.list.find(x =>{ return x.id === ybid; });
  676. $('[name=yinbi-name]').val(yb.name);
  677. $('[name=yinbi-gongxu-id]').html(self._getSelectGongxuHtml());
  678. $('[name=yinbi-gongxu-id]').val(yb.gongxu_id);
  679. $('[name=yinbi-gcbw]').val(yb.gcbw);
  680. $('[name=yinbi-content]').val(yb.content);
  681. $('#yinbi-id').val(yb.id);
  682. $('#add-yinbi').modal('show');
  683. });
  684. $('body').on('click', '[name=upload-yb-before]', function() {
  685. const ybid = $(this).closest('.yinbi-card').attr('ybid');
  686. self.selectUploadFiles({
  687. select: async function(files, specType) {
  688. const yb = self.node.quality.yinbi.list.find(x => { return x.id === ybid });
  689. const result = await self.uploadFiles(files, ybid, 'before');
  690. yb.before_files.push(...result);
  691. for (const r of result) {
  692. $(`#${self.beforeFilesPre}-${yb.id}`).append(self.getFileHtml(r));
  693. }
  694. self.qualityObj.refreshFileCountHtml();
  695. autoFlashHeight();
  696. }
  697. });
  698. });
  699. $('body').on('click', '[name=upload-yb-after]', function() {
  700. const ybid = $(this).closest('.yinbi-card').attr('ybid');
  701. self.selectUploadFiles({
  702. select: async function(files, specType) {
  703. const yb = self.node.quality.yinbi.list.find(x => { return x.id === ybid });
  704. const result = await self.uploadFiles(files, ybid, 'after');
  705. yb.after_files.push(...result);
  706. for (const r of result) {
  707. $(`#${self.afterFilesPre}-${yb.id}`).append(self.getFileHtml(r));
  708. }
  709. self.qualityObj.refreshFileCountHtml();
  710. autoFlashHeight();
  711. }
  712. });
  713. });
  714. $('body').on('click', `#${self.objKey} [name=del-file]`, function(){
  715. const tableKey = $(this).closest('tbody').attr('id');
  716. const ybid = $(this).closest('.yinbi-card').attr('ybid');
  717. const yb = self.node.quality.yinbi.list.find(x => { return x.id === ybid; });
  718. const del = [this.getAttribute('fid')];
  719. self.delFiles(del, function(result) {
  720. for (const r of result) {
  721. $(`input[fid=${r}]`).parent().parent().remove();
  722. if (tableKey.indexOf(self.beforeFilesPre) === 0) {
  723. const fi = yb.before_files.findIndex(x => { return x.id === r; });
  724. if (fi >= 0) yb.before_files.splice(fi, 1);
  725. } else if (tableKey.indexOf(self.afterFilesPre) === 0) {
  726. const fi = yb.after_files.findIndex(x => { return x.id === r; });
  727. if (fi >= 0) yb.after_files.splice(fi, 1);
  728. }
  729. }
  730. self.qualityObj.refreshFileCountHtml();
  731. autoFlashHeight();
  732. });
  733. });
  734. }
  735. _getSelectGongxuHtml(){
  736. const html = ['<option value=""></option>'];
  737. this.node.quality.gongxu.list.forEach(x => { html.push(`<option value="${x.id}">${x.name}</option>`)});
  738. return html.join('');
  739. }
  740. _getAddHtml() {
  741. return permission.add ? '<a href="javascript: void(0)" name="add-yb" class="btn btn-primary btn-sm" >新增隐蔽工程</a>' : '';
  742. }
  743. getControlHtml() {
  744. const html = [];
  745. html.push('<div>', this._getAddHtml(), '</div>');
  746. return html.join('');
  747. }
  748. _getCardHeaderHtml(yb){
  749. const html = [];
  750. const editHtml = yb.canEdit ? `<a href="javascript: void(0);" class="ml-1" name="edit-yb" ybid="${yb.id}"><i class="fa fa-pencil fa-fw"></i></a>` : '';
  751. const delHtml = yb.canEdit ? `<a href="javascript: void(0);" class="ml-1 text-danger" name="del-yb" ybid="${yb.id}"><i class="fa fa-trash-o fa-fw"></i></a>` : '';
  752. html.push(`<div class="d-inline-block col-6 pl-0"><span name="yb-name">${yb.name}</span>${editHtml}${delHtml}</div>`);
  753. const gongxu = yb.gongxu_id ? this.node.quality.gongxu.list.find(x => { return x.id === yb.gongxu_id; }) : null;
  754. html.push(`<div class="d-inline-block col-4">${gongxu ? gongxu.name : ''}</div>`);
  755. html.push(`<div class="d-inline-block pull-right"><span class="mr-3">创建日期:${moment(yb.create_time).format('YYYY-MM-DD')}</span></div>`);
  756. return html.join('');
  757. }
  758. _getCardHtml(yb) {
  759. if (!yb) return '';
  760. const html = [];
  761. html.push(`<div class="card mt-2 yinbi-card" ybid="${yb.id}">`);
  762. html.push('<div class="card-header d-flex justify-content-between yinbi-card-header">', this._getCardHeaderHtml(yb), '</div>');
  763. html.push('<div class="card-body pt-2">');
  764. html.push(`<div class="mb-2"><span class="yinbi-gcbw">工程部位及桩号:${yb.gcbw || ''}</span></div>`);
  765. html.push(`<div class="mb-2"><span class="yinbi-content">隐蔽工程说明:${yb.content || ''}</span></div>`);
  766. html.push('<div class="card mt-2">', '<div class="card-header d-flex justify-content-between">', '施工前:', '<div><a href="javascript: void(0)" class="btn btn-sm btn-light text-primary" name="upload-yb-before">上传文件</a></div>', '</div>');
  767. html.push('<div class="card-body pt-2">', this.getFilesTableHtml(yb.before_files, this.beforeFilesPre + '-' + yb.id ), '</div>');
  768. html.push('</div>');
  769. html.push('<div class="card mt-2">', '<div class="card-header d-flex justify-content-between">', '施工后:', '<div><a href="javascript: void(0)" class="btn btn-sm btn-light text-primary" name="upload-yb-after">上传文件</a></div>', '</div>');
  770. html.push('<div class="card-body pt-2">', this.getFilesTableHtml(yb.after_files, this.afterFilesPre + '-' + yb.id ), '</div>');
  771. html.push('</div>');
  772. html.push('</div>');
  773. html.push('</div>');
  774. return html.join('');
  775. }
  776. getContentHtml() {
  777. const html = [];
  778. if (this.node.quality && this.node.quality.yinbi) {
  779. for (const yb of this.node.quality.yinbi.list) {
  780. html.push(this._getCardHtml(yb));
  781. }
  782. }
  783. return html.join('');
  784. }
  785. afterEdit(yb) {
  786. $(`.yinbi-card[ybid=${yb.id}] .yinbi-card-header`).html(this._getCardHeaderHtml(yb));
  787. $(`.yinbi-card[ybid=${yb.id}] .yinbi-gcbw`).html(`工程部位及桩号:${yb.gcbw || ''}`);
  788. $(`.yinbi-card[ybid=${yb.id}] .yinbi-content`).html(`隐蔽工程说明:${yb.content || ''}`);
  789. }
  790. }
  791. class Quality {
  792. constructor () {
  793. this.kaigong = new Kaigong('kaigong', this);
  794. this.pingding = new Pingding('pingding', this);
  795. this.gongxu = new Gongxu('gongxu', this);
  796. this.jiaogong = new Jiaogong('jiaogong', this);
  797. this.yinbi = new Yinbi('yinbi', this);
  798. }
  799. getStatusText(type, status) {
  800. const def = thirdParty[type].find(function (x) {
  801. return x.value === status;
  802. });
  803. return def ? def.name : '';
  804. }
  805. getGxbyText(data) {
  806. return this.getStatusText('gxby', data.gxby_status);
  807. }
  808. getDaglText(data) {
  809. return this.getStatusText('dagl', data.dagl_status);
  810. }
  811. getFileCount() {
  812. if (!this.node || !this.node.quality) return 0;
  813. let result = this.node.quality.kaigong ? this.node.quality.kaigong.files.length : 0;
  814. this.node.quality.gongxu.list.forEach(gx => { result = result + gx.files.length; });
  815. if (this.node.quality.pingding) {
  816. result = result + this.node.quality.pingding.files.length + this.node.quality.pingding.source_files.filter(x => {return x.spec_type !== 'qa'; }).length;
  817. }
  818. if (this.node.quality.jiaogong) result = result + this.node.quality.jiaogong.files.length;
  819. return result;
  820. }
  821. getYinbiFileCount() {
  822. if (!this.node || !this.node.quality) return 0;
  823. let result = 0;
  824. this.node.quality.yinbi.list.forEach(x => {
  825. result = result + x.before_files.length + x.after_files.length;
  826. });
  827. return result;
  828. }
  829. refreshFileCountHtml() {
  830. const fileCount = this.getFileCount();
  831. const yinbiFileCount = this.getYinbiFileCount();
  832. $('#file-count').html('合计:' + (fileCount + yinbiFileCount));
  833. $('#file-count-wo-yinbi').html('不含隐蔽:' + (fileCount));
  834. $('#file-count-yinbi').html('隐蔽工程:' + (yinbiFileCount));
  835. }
  836. refreshGaikuang() {
  837. let gxbyText = this.getGxbyText(this.node);
  838. if (this.node.gxby_date) gxbyText = gxbyText + `(${moment(this.node.gxby_date).format('YYYY-MM-DD')})`;
  839. if (gxbyText) {
  840. $('#gxby-info').html('完工:' + gxbyText).show();
  841. } else {
  842. $('#gxby-info').hide();
  843. }
  844. const daglText = this.getDaglText(this.node);
  845. if (daglText) {
  846. $('#dagl-info').html('资料:' + daglText).show();
  847. } else {
  848. $('#dagl-info').hide();
  849. }
  850. this.refreshFileCountHtml();
  851. }
  852. refreshQuality() {
  853. this.refreshGaikuang();
  854. this.kaigong.show(this.node);
  855. this.gongxu.show(this.node);
  856. this.pingding.show(this.node);
  857. this.jiaogong.show(this.node);
  858. this.yinbi.show(this.node);
  859. autoFlashHeight();
  860. }
  861. async showQuality(node, force = 1) {
  862. this.node = node;
  863. this.isChild = !this.node.children || this.node.children.length === 0;
  864. if (!this.isChild) {
  865. $('#quality-detail').hide();
  866. return;
  867. } else {
  868. $('#quality-detail').show();
  869. }
  870. if (!node.quality || force) {
  871. node.quality = (await postDataAsync('load', { filter: 'detail', rela_type: node.rela_type, rela_id: node.rela_id, rela_name: node.rela_name, })).detail;
  872. if (node.quality) {
  873. node.gxby_status = node.quality.gxby_status;
  874. node.gxby_date = node.quality.gxby_date;
  875. node.dagl_status = node.quality.dagl_status;
  876. }
  877. }
  878. this.refreshQuality();
  879. }
  880. }
  881. const qualityObj = new Quality();
  882. xmjSpread.bind(spreadNS.Events.SelectionChanged, function(e, info) {
  883. if (!info.oldSelections || !info.oldSelections[0] || info.newSelections[0].row !== info.oldSelections[0].row) {
  884. qualityObj.showQuality(SpreadJsObj.getSelectObject(info.sheet));
  885. }
  886. });
  887. $('#reload-quality').click(function() {
  888. qualityObj.showQuality(SpreadJsObj.getSelectObject(xmjSheet), true);
  889. });
  890. $.contextMenu({
  891. selector: '#xmj-spread',
  892. build: function ($trigger, e) {
  893. const target = SpreadJsObj.safeRightClickSelection($trigger, e, xmjSpread);
  894. return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
  895. },
  896. items: {
  897. pushInc: {
  898. name: '推送状态',
  899. callback: function (key, opt, menu, e) {
  900. const select = [];
  901. const node = SpreadJsObj.getSelectObject(xmjSheet);
  902. if (node.children && node.children.length > 0) {
  903. const posterity = xmjTree.getPosterity(node);
  904. for (const p of posterity) {
  905. if (!node.children || node.children.length === 0) select.push({ rela_type: node.rela_type, rela_id: node.rela_id, rela_name: node.rela_name, pid: node.pid });
  906. }
  907. } else {
  908. select.push({ rela_type: node.rela_type, rela_id: node.rela_id, rela_name: node.rela_name, pid: node.pid });
  909. }
  910. postData('push', {push_type: 'inc', select}, function(result) {
  911. if (!result) {
  912. toastr.warning('暂无状态推送');
  913. } else {
  914. toastr.success(`成功推送${result}条状态`);
  915. }
  916. })
  917. },
  918. },
  919. pushAll: {
  920. name: '推送全部状态',
  921. callback: function (key, opt, menu, e) {
  922. postData('push', {push_type: 'all'}, function(result) {
  923. if (!result) {
  924. toastr.warning('暂无状态推送');
  925. } else {
  926. toastr.success('推送成功');
  927. }
  928. });
  929. },
  930. },
  931. }
  932. });
  933. // 显示层次
  934. (function (select, sheet) {
  935. $(select).click(function () {
  936. const tag = $(this).attr('tag');
  937. setTimeout(() => {
  938. showWaitingView();
  939. const tree = sheet.zh_tree;
  940. if (!tree) return;
  941. switch (tag) {
  942. case "1":
  943. case "2":
  944. case "3":
  945. case "4":
  946. case "5":
  947. tree.expandByLevel(parseInt(tag));
  948. SpreadJsObj.refreshTreeRowVisible(sheet);
  949. break;
  950. case "last":
  951. tree.expandByCustom(() => { return true; });
  952. SpreadJsObj.refreshTreeRowVisible(sheet);
  953. break;
  954. }
  955. closeWaitingView();
  956. }, 100);
  957. });
  958. })('a[name=showLevel]', xmjSheet);
  959. const xmjSearch = $.posSearch({selector: '#xmj-search', searchSpread: xmjSpread, hint: '请输入 编号/名称 查询', specClass: 'mt-1'});
  960. });