process-list.component.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. import { Component, OnInit, ViewChild } from '@angular/core';
  2. import { ActivatedRoute, RouterOutlet, Router } from '@angular/router';
  3. // import { CompTableListComponent } from '../../../../app/comp-table/comp-table-list/comp-table-list.component';
  4. import _Role from '../../../../schemas/_Role';
  5. // import { TranslateService } from '@ngx-translate/core';
  6. import * as Parse from 'parse';
  7. import { CommonModule } from '@angular/common';
  8. import { Department } from '../../../../schemas/Department';
  9. import { NzSpaceModule } from 'ng-zorro-antd/space';
  10. import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
  11. import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
  12. import { CommonCompModule } from '../../../../services/common.modules';
  13. import { NzModalModule } from 'ng-zorro-antd/modal';
  14. import {
  15. NzFormatEmitEvent,
  16. NzTreeModule,
  17. NzTreeNode,
  18. } from 'ng-zorro-antd/tree';
  19. import {
  20. NzContextMenuService,
  21. NzDropdownMenuComponent,
  22. } from 'ng-zorro-antd/dropdown';
  23. import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
  24. import { NzEmptyModule } from 'ng-zorro-antd/empty';
  25. import { NzRadioModule } from 'ng-zorro-antd/radio';
  26. import { NzMessageService } from 'ng-zorro-antd/message';
  27. import { NzModalService } from 'ng-zorro-antd/modal';
  28. import { NzPopoverModule } from 'ng-zorro-antd/popover';
  29. import { setHours } from 'date-fns';
  30. import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
  31. import { textbookServer } from '../../../../services/textbook';
  32. import { shellServer } from '../../../../services/shell';
  33. interface nodes {
  34. title: string;
  35. key: string;
  36. isLeaf?: boolean;
  37. isParent?: boolean;
  38. children?: Array<any>;
  39. }
  40. interface depart {
  41. name: string;
  42. id?: string;
  43. code?: string;
  44. desc?: string;
  45. parent?: object | any;
  46. branch: string;
  47. }
  48. @Component({
  49. selector: 'app-process-list',
  50. templateUrl: './process-list.component.html',
  51. styleUrls: ['./process-list.component.scss'],
  52. imports: [
  53. CommonModule,
  54. CommonCompModule,
  55. RouterOutlet,
  56. // CompTableListComponent,
  57. NzSpaceModule,
  58. NzPageHeaderModule,
  59. NzBreadCrumbModule,
  60. NzTreeModule,
  61. NzCheckboxModule,
  62. NzEmptyModule,
  63. NzModalModule,
  64. NzRadioModule,
  65. NzPopoverModule,
  66. NzDatePickerModule
  67. ],
  68. standalone: true,
  69. })
  70. export class ProcessListComponent implements OnInit {
  71. // @ViewChild(CompTableListComponent) list: CompTableListComponent | undefined;
  72. timeDefaultValue = setHours(new Date(), 0);
  73. dev = localStorage.getItem('localdev')
  74. // _Role = _Role
  75. Department = Department;
  76. user: Parse.User | undefined;
  77. className: string | undefined;
  78. queryParams: any | undefined;
  79. fieldsArray: Array<any> | undefined;
  80. searchValue: string = ''; //搜索内容
  81. searchValuePro: string = ''; //搜索流程内容
  82. nodes: Array<nodes | any> = [];
  83. currentDepart: nodes | any = null;
  84. eduProcessList: Array<Parse.Object> = [];
  85. statusMap: any = {};
  86. statusFileMap: any = {};
  87. eduProcessLength: number = 0;
  88. pageSize: number = 10;
  89. pageIndex: number = 1;
  90. checkedShowFilter: boolean = false;
  91. checkedAll: boolean = false; //全选
  92. indeterminate = false;
  93. loading = false;
  94. isVisible: boolean = false;
  95. activatedNode: NzTreeNode | any; //当前选择节点
  96. editType: string = 'add'; //弹窗类型
  97. activeDepart?: Parse.Object; //当前编辑部门
  98. editObject: depart = {
  99. name: '',
  100. code: '',
  101. desc: '',
  102. parent: {},
  103. branch: '',
  104. };
  105. parentMap: Array<any> = [];
  106. parentList: Array<any> = [];
  107. setOfCheckedId = new Set<string>();
  108. formatStatus = (e: any) => {
  109. if (e.get('status') == '100') {
  110. return {
  111. title: '已暂停',
  112. color: 'lime',
  113. strat: true,
  114. stop: true,
  115. end: false,
  116. del: false,
  117. };
  118. }
  119. // if(e?.get('collectStartData') && new Date() < new Date(e?.get('collectStartData'))){
  120. // return {
  121. // title: '未开始',
  122. // color: 'default',
  123. // strat: false,
  124. // stop: false,
  125. // end: false,
  126. // del: false,
  127. // collect:true
  128. // };
  129. // }
  130. // if(e?.get('collectStartData') && new Date() > new Date(e?.get('collectStartData'))
  131. // && new Date() < e?.get('collectEndData')){
  132. // return {
  133. // title: '收集中',
  134. // color: 'orange',
  135. // strat: false,
  136. // stop: false,
  137. // end: false,
  138. // del: false,
  139. // collect:true
  140. // };
  141. // }
  142. if (
  143. e?.get('deadline') &&
  144. new Date() > new Date(e?.get('deadline')) &&
  145. e?.get('status') == '400'
  146. ) {
  147. return {
  148. title: '已结束',
  149. color: 'gold',
  150. strat: false,
  151. stop: false,
  152. end: false,
  153. del: true,
  154. collect:true
  155. };
  156. }
  157. if (e?.get('status') == '400') {
  158. return {
  159. title: '已完成',
  160. color: 'green',
  161. strat: false,
  162. stop: false,
  163. end: true,
  164. del: false,
  165. collect:true
  166. };
  167. }
  168. if (!e?.get('startDate') || new Date() < new Date(e.get('startDate'))) {
  169. return {
  170. title: '未开始',
  171. color: 'grey',
  172. strat: true,
  173. stop: false,
  174. end: false,
  175. del: true,
  176. };
  177. }
  178. if (e?.get('deadline') && new Date() > new Date(e?.get('deadline'))) {
  179. return {
  180. title: '已逾期',
  181. color: 'red',
  182. strat: true,
  183. stop: false,
  184. end: false,
  185. del: true,
  186. };
  187. }
  188. if (
  189. e.get('status') == '200' &&
  190. e?.get('startDate') &&
  191. new Date() >= new Date(e?.get('startDate'))
  192. ) {
  193. return {
  194. title: '遴选中',
  195. color: 'blue',
  196. strat: false,
  197. stop: true,
  198. end: true,
  199. del: false,
  200. };
  201. }
  202. if (e.get('status') == '300') {
  203. return {
  204. title: '已公示',
  205. color: 'red',
  206. strat: false,
  207. stop: true,
  208. end: true,
  209. del: false,
  210. };
  211. }
  212. if (e.get('status') == '201') {
  213. return {
  214. title: '评审中',
  215. color: 'cyan',
  216. strat: false,
  217. stop: true,
  218. end: true,
  219. del: false,
  220. };
  221. }
  222. return;
  223. };
  224. formatFileStatus = (e: any) => {
  225. if(!e?.get('collectStartData') || new Date() < new Date(e?.get('collectStartData'))){
  226. return {
  227. title: '未开始',
  228. color: 'default',
  229. strat: false,
  230. stop: false,
  231. end: false,
  232. del: false,
  233. collect:true
  234. };
  235. }
  236. if(e?.get('collectStartData') && new Date() > new Date(e?.get('collectStartData'))
  237. && new Date() < e?.get('collectEndData')){
  238. return {
  239. title: '收集中',
  240. color: 'orange',
  241. strat: false,
  242. stop: false,
  243. end: false,
  244. del: false,
  245. collect:true
  246. };
  247. }
  248. if(e?.get('collectEndData') && new Date() > e?.get('collectEndData')){
  249. return {
  250. title: '已结束',
  251. color: 'orange',
  252. strat: false,
  253. stop: false,
  254. end: false,
  255. del: false,
  256. collect:true
  257. };
  258. }
  259. return;
  260. }
  261. /* 新建组织 */
  262. branchObj: any = {
  263. name: '',
  264. code: '',
  265. desc: '',
  266. };
  267. showModal:boolean = false
  268. eduProcess?:Parse.Object //当前编辑流程
  269. textBookList:Array<Parse.Object> = [] //流程教材列表(推荐)
  270. collectStartData:any
  271. collectEndData:any
  272. constructor(
  273. public tbookSer: textbookServer,
  274. public shellSer:shellServer,
  275. private route: Router,
  276. private activeRoute: ActivatedRoute,
  277. private nzContextMenuService: NzContextMenuService,
  278. private message: NzMessageService,
  279. private modal: NzModalService
  280. ) {
  281. this.user = Parse.User.current();
  282. this.className = this.Department.className;
  283. this.fieldsArray = this.Department.fieldsArray;
  284. this.queryParams = {
  285. where: {
  286. isDeleted: { $ne: true },
  287. },
  288. };
  289. }
  290. ngOnInit(): void {
  291. this.activeRoute.paramMap.subscribe(async (params) => {
  292. this.nodes = await this.getDepart();
  293. });
  294. }
  295. async getDepart(
  296. parent?: string,
  297. searchValue?: string
  298. ): Promise<Array<nodes>> {
  299. let nodes: any = [];
  300. let query = new Parse.Query('Department');
  301. query.equalTo('parent', parent ? parent : undefined);
  302. searchValue && query.contains('name', searchValue);
  303. query.notEqualTo('isDeleted', true);
  304. query.select('code', 'name', 'branch', 'parent', 'type');
  305. query.descending('createdAt');
  306. query.limit(2000);
  307. let res = await query.find();
  308. res.forEach((item) => {
  309. nodes.push({
  310. title: item.get('name'),
  311. key: item.id,
  312. children: [],
  313. // isParent: item.get('type') =='单位' ? true : false, //是否是最下级
  314. isLeaf: true,
  315. });
  316. });
  317. return nodes;
  318. }
  319. async onSearch(e: string) {
  320. this.nodes = await this.getDepart('', e);
  321. }
  322. onSearchPro(e: string) {
  323. this.pageIndex = 1;
  324. this.getEduProcess();
  325. }
  326. changeDepart(e: any) {
  327. this.currentDepart = e;
  328. this.setOfCheckedId = new Set<string>();
  329. this.checkedAll = false;
  330. this.pageIndex = 1;
  331. this.getEduProcess();
  332. }
  333. async getEduProcess() {
  334. this.eduProcessList = [];
  335. this.loading = true;
  336. let query1 = Parse.Query.fromJSON('EduProcess', {
  337. where: {
  338. $or: [
  339. {
  340. name: { $regex: `.*${this.searchValuePro}.*` },
  341. },
  342. ],
  343. },
  344. });
  345. let query2 = Parse.Query.fromJSON('EduProcess', {
  346. where: {
  347. $or: [
  348. {
  349. code: { $regex: `.*${this.searchValuePro}.*` },
  350. },
  351. ],
  352. },
  353. });
  354. let query = Parse.Query.or(query1, query2);
  355. query.include('profileSubmitted', 'profileSubmitted.user');
  356. query.notEqualTo('isDeleted', true);
  357. this.currentDepart?.key && query.equalTo('branch', this.currentDepart.key);
  358. this.eduProcessLength = await query.count();
  359. query.skip(this.pageSize * (this.pageIndex - 1));
  360. query.limit(this.pageSize);
  361. query.descending('createdAt');
  362. let r = await query.find();
  363. // let list: any[] = [];
  364. r.forEach((item) => {
  365. // let _item = item.toJSON();
  366. // _item['checked'] = false;
  367. // _item['state'] = this.formatStatus(_item);
  368. this.statusMap[item.id] = this.formatStatus(item);
  369. this.statusFileMap[item.id] = this.formatFileStatus(item);
  370. });
  371. this.eduProcessList = r;
  372. this.loading = false;
  373. }
  374. //分页切换
  375. pageIndexChange(e: any) {
  376. console.log(e);
  377. this.pageIndex = e;
  378. this.getEduProcess();
  379. }
  380. onAllChecked(checked: boolean): void {
  381. console.log(checked);
  382. this.eduProcessList.forEach((item) => {
  383. if (checked) {
  384. this.setOfCheckedId.add(item.id);
  385. } else {
  386. this.setOfCheckedId.delete(item.id);
  387. }
  388. });
  389. if (!checked) {
  390. this.setOfCheckedId = new Set<string>();
  391. }
  392. this.checkedAll = checked;
  393. }
  394. onItemChecked(id: string, e: boolean) {
  395. if (e) {
  396. this.setOfCheckedId.add(id);
  397. } else {
  398. this.setOfCheckedId.delete(id);
  399. }
  400. this.checkedAll = this.eduProcessList.every((item) =>
  401. this.setOfCheckedId.has(item.id)
  402. );
  403. }
  404. //新建打开弹窗
  405. async showModalDepart(type: string) {
  406. this.parentList = this.nodes;
  407. if (type == 'edit') {
  408. let query = new Parse.Query('Department');
  409. let r = await query.get(this.activatedNode?.key);
  410. this.activeDepart = r;
  411. this.parentMap = this.formatNode(this.activatedNode);
  412. if (this.activatedNode?.parentNode?.origin.key) {
  413. this.parentList = await this.getDepart(
  414. this.activatedNode.parentNode.origin.key
  415. );
  416. }
  417. }
  418. this.editType = type;
  419. this.isVisible = true;
  420. }
  421. //格式化链
  422. formatNode(node: NzTreeNode): Array<any> {
  423. let arr = [];
  424. if (node.parentNode?.origin.title) {
  425. arr.push({
  426. title: node.parentNode?.origin.title,
  427. key: node.parentNode?.origin.key,
  428. });
  429. arr.unshift(...this.formatNode(node.parentNode));
  430. }
  431. return arr;
  432. }
  433. async onPre(data?: any, index?: number) {
  434. if (!data) {
  435. this.parentList = await this.getDepart();
  436. this.parentMap = [];
  437. return;
  438. }
  439. if (index == this.parentMap.length - 1) return;
  440. this.parentMap.splice(index || 0 + 1);
  441. this.parentList = await this.getDepart(data?.key);
  442. }
  443. //选择所属类别下级列表
  444. async onCheckedDepart(e: any, checked?: boolean) {
  445. console.log(e);
  446. if (checked) {
  447. this.editObject = {
  448. name: e.title,
  449. code: '',
  450. desc: '',
  451. parent: e,
  452. branch: '',
  453. };
  454. return;
  455. }
  456. this.parentMap.push({
  457. title: e.title,
  458. key: e.key,
  459. });
  460. this.parentList = await this.getDepart(e?.key);
  461. }
  462. /* 组织 */
  463. showModalOrganize() {
  464. // this.message.warning('权限灰度中');
  465. this.branchObj = {
  466. name: '',
  467. code: '',
  468. desc: '',
  469. };
  470. this.isVisible = true;
  471. }
  472. async handleOk(): Promise<void> {
  473. if (!this.branchObj?.name) {
  474. this.message.warning('组织名称不能为空');
  475. }
  476. let obj = Parse.Object.extend('Department');
  477. let depart = new obj();
  478. depart.set('name', this.branchObj?.name);
  479. depart.set('desc', this.branchObj?.desc);
  480. depart.set('code', this.branchObj?.code);
  481. await depart.save();
  482. this.isVisible = false;
  483. this.message.success('新建成功');
  484. this.nodes = await this.getDepart();
  485. }
  486. handleCancel(): void {
  487. console.log('Button cancel clicked!');
  488. this.isVisible = false;
  489. this.activatedNode = undefined;
  490. this.parentMap = [];
  491. this.showModal = false
  492. this.collectStartData = undefined
  493. this.collectEndData = undefined
  494. this.eduProcess = undefined
  495. this.textBookList = []
  496. }
  497. statusSelected(type: string) {
  498. let map: any = {
  499. strat: '开始',
  500. stop: '暂停',
  501. end: '结束',
  502. del: '删除',
  503. };
  504. this.modal.confirm({
  505. nzTitle: `批量${map[type]}`,
  506. nzContent:
  507. type == 'del'
  508. ? `删除后数据不可恢复,请谨慎操作`
  509. : `确认批量${map[type]}吗`,
  510. nzOkText: '确认',
  511. nzOkType: 'primary',
  512. nzOkDanger: map[type] ? true : false,
  513. nzOnOk: async () => {
  514. let selectedList = this.eduProcessList.filter((item: any) =>
  515. this.setOfCheckedId.has(item?.id)
  516. );
  517. let deletePromiseList = selectedList.map((item: any) => {
  518. return new Promise((resolve) => {
  519. resolve(this.onStatusChange(item, type));
  520. });
  521. });
  522. try {
  523. await Promise.all(deletePromiseList);
  524. this.getEduProcess();
  525. } catch (err) {}
  526. },
  527. nzCancelText: '取消',
  528. nzOnCancel: () => console.log('Cancel'),
  529. });
  530. }
  531. toUrl(url: string, params?: object) {
  532. if (params) {
  533. this.route.navigate([url, params]);
  534. } else {
  535. this.route.navigate([url]);
  536. }
  537. }
  538. //暂停流程
  539. async onStatusChange(
  540. data: Parse.Object,
  541. type: string,
  542. end?: boolean,
  543. ): Promise<void> {
  544. console.log(data, type);
  545. switch (type) {
  546. case 'strat':
  547. if (data?.get('status') == '100') {
  548. data?.set('status', '200');
  549. }
  550. if (!data?.get('startDate') || data?.get('startDate') > new Date()) {
  551. data?.set('startDate', new Date());
  552. }
  553. if (!data?.get('deadline') || data?.get('deadline') < new Date()) {
  554. data?.set(
  555. 'deadline',
  556. new Date(new Date().getTime() + 60 * 1000 * 60 * 24 * 7)
  557. );
  558. console.warn('结束时间延长一周之后');
  559. }
  560. break;
  561. case 'stop':
  562. data?.set('status', '100');
  563. break;
  564. case 'end':
  565. data?.set('status', '400');
  566. data?.set('deadline', new Date());
  567. break;
  568. case 'del':
  569. data?.set('isDeleted', true);
  570. break;
  571. }
  572. await data.save();
  573. if (end) {
  574. this.getEduProcess();
  575. }
  576. }
  577. //打开编辑收集文件弹窗
  578. async openEditCollect(data:Parse.Object){
  579. this.eduProcess = data
  580. this.collectStartData = this.eduProcess?.get('collectStartData')
  581. this.collectEndData = this.eduProcess?.get('collectEndData')
  582. let query = new Parse.Query('EduTextbook')
  583. query.equalTo('eduProcess',this.eduProcess?.id)
  584. query.notEqualTo('isDeleted',true)
  585. query.equalTo('status','400')
  586. query.equalTo('recommend', true);
  587. query.notEqualTo('discard', true);
  588. query.select('title')
  589. let r = await query.find()
  590. this.textBookList = r
  591. this.showModal = true
  592. }
  593. //保存收集文件设置
  594. async editCollect(){
  595. if(!this.collectStartData || !this.collectEndData || this.collectStartData > this.collectEndData){
  596. this.message.warning('请设置正确的开始和截止时间')
  597. return
  598. }
  599. this.eduProcess?.set('collectStartData',this.collectStartData)
  600. this.eduProcess?.set('collectEndData',this.collectEndData)
  601. await this.eduProcess?.save()
  602. this.message.success('设置成功')
  603. this.getEduProcess()
  604. this.showModal = false
  605. }
  606. /* 短信通知 */
  607. sendNoticeMSG(){
  608. this.modal.confirm({
  609. nzTitle: '短信通知',
  610. nzContent: '发送短信提醒所有已提交教材的教师及对应出版单位',
  611. nzOkText: '发送',
  612. nzOkType: 'primary',
  613. nzOkDanger: true,
  614. nzOnOk: () => {
  615. this.shellSer.sendNoticeMSG()
  616. this.message.success('已发送')
  617. },
  618. nzCancelText: '取消',
  619. nzOnCancel: () => console.log('Cancel')
  620. });
  621. }
  622. }