quality_info.js 46 KB

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