process-list.component.ts 16 KB

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