process-list.component.ts 16 KB

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