Преглед на файлове

Merge remote-tracking branch 'origin/master'

xiaoqiao преди 9 месеца
родител
ревизия
70140340c2
променени са 69 файла, в които са добавени 2549 реда и са изтрити 106 реда
  1. 59 0
      parth5/parth5/src/app/api/partyuser/partydues/index.ts
  2. 53 0
      parth5/parth5/src/app/api/propagandawork/position/index.ts
  3. 44 0
      parth5/parth5/src/app/api/propagandawork/position/panel/index.ts
  4. 15 0
      parth5/parth5/src/app/api/system/dictionary/index.ts
  5. 20 3
      parth5/parth5/src/app/app.scss
  6. 57 0
      parth5/parth5/src/app/comm/modal/alert/index.ts
  7. 1 0
      parth5/parth5/src/app/comm/modal/bimage/bimage.component.html
  8. 7 0
      parth5/parth5/src/app/comm/modal/bimage/bimage.component.scss
  9. 75 0
      parth5/parth5/src/app/comm/modal/bimage/bimage.component.ts
  10. 42 75
      parth5/parth5/src/app/comm/modal/imglist/imglist.component.ts
  11. 12 0
      parth5/parth5/src/app/routes/partyDues.ts
  12. 7 7
      parth5/parth5/src/app/routes/partyUser.ts
  13. 16 0
      parth5/parth5/src/app/routes/propagandawork/position.ts
  14. 17 1
      parth5/parth5/src/app/service/config.service.ts
  15. 41 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/detail/detail.component.html
  16. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/detail/detail.component.scss
  17. 56 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/detail/detail.component.ts
  18. 73 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/edit/edit.component.html
  19. 70 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/edit/edit.component.scss
  20. 153 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/edit/edit.component.ts
  21. 65 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/party-dues.component.html
  22. 47 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/party-dues.component.scss
  23. 139 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/party-dues.component.ts
  24. 51 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/selectuser/selectuser.component.html
  25. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/selectuser/selectuser.component.scss
  26. 103 0
      parth5/parth5/src/app/views/pages/partyuser/party-dues/selectuser/selectuser.component.ts
  27. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/democracy/democracy.component.html
  28. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/democracy/democracy.component.scss
  29. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/democracy/democracy.component.ts
  30. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/detail.component.html
  31. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/detail.component.scss
  32. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/detail.component.ts
  33. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/partyhelp/partyhelp.component.html
  34. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/partyhelp/partyhelp.component.scss
  35. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/partyhelp/partyhelp.component.ts
  36. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/punish/punish.component.html
  37. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/punish/punish.component.scss
  38. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/punish/punish.component.ts
  39. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/reward/reward.component.html
  40. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/reward/reward.component.scss
  41. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/reward/reward.component.ts
  42. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/train/train.component.html
  43. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/train/train.component.scss
  44. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/detail/train/train.component.ts
  45. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/party-user.component.html
  46. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/party-user.component.scss
  47. 0 0
      parth5/parth5/src/app/views/pages/partyuser/party-user/party-user.component.ts
  48. 96 0
      parth5/parth5/src/app/views/pages/propagandawork/position/detail/detail.component.html
  49. 38 0
      parth5/parth5/src/app/views/pages/propagandawork/position/detail/detail.component.scss
  50. 137 0
      parth5/parth5/src/app/views/pages/propagandawork/position/detail/detail.component.ts
  51. 101 0
      parth5/parth5/src/app/views/pages/propagandawork/position/edit/edit.component.html
  52. 31 0
      parth5/parth5/src/app/views/pages/propagandawork/position/edit/edit.component.scss
  53. 208 0
      parth5/parth5/src/app/views/pages/propagandawork/position/edit/edit.component.ts
  54. 55 0
      parth5/parth5/src/app/views/pages/propagandawork/position/panel/detail/detail.component.html
  55. 34 0
      parth5/parth5/src/app/views/pages/propagandawork/position/panel/detail/detail.component.scss
  56. 103 0
      parth5/parth5/src/app/views/pages/propagandawork/position/panel/detail/detail.component.ts
  57. 43 0
      parth5/parth5/src/app/views/pages/propagandawork/position/panel/edit/edit.component.html
  58. 38 0
      parth5/parth5/src/app/views/pages/propagandawork/position/panel/edit/edit.component.scss
  59. 52 0
      parth5/parth5/src/app/views/pages/propagandawork/position/panel/edit/edit.component.ts
  60. 52 0
      parth5/parth5/src/app/views/pages/propagandawork/position/position.component.html
  61. 42 0
      parth5/parth5/src/app/views/pages/propagandawork/position/position.component.scss
  62. 171 0
      parth5/parth5/src/app/views/pages/propagandawork/position/position.component.ts
  63. 5 1
      parth5/parth5/src/app/views/tapp/tab-main/tab-main.module.ts
  64. 5 1
      parth5/parth5/src/app/views/tapp/tab-main/tab-main.route.ts
  65. 9 7
      src/main/java/com/ghsc/partybuild/controller/app/AppPartyController.java
  66. 5 1
      src/main/java/com/ghsc/partybuild/controller/app/AppPublicityController.java
  67. 3 1
      src/main/java/com/ghsc/partybuild/service/PublicityService.java
  68. 87 2
      src/main/java/com/ghsc/partybuild/service/impl/PublicityServiceImpl.java
  69. 11 7
      src/main/resources/mapping/PublicityCQuery.xml

+ 59 - 0
parth5/parth5/src/app/api/partyuser/partydues/index.ts

@@ -0,0 +1,59 @@
+import {Injectable} from "@angular/core";
+import {Observable} from "rxjs";
+import {ConfigService, RequsetData} from "../../../service/config.service";
+import {UserService} from "../../../service/user.service";
+
+export interface reqParams {
+  pageIndex: number;
+  pageSize: number;
+  ssdzzdm: string;
+  xm: string;
+  year: number;
+  month: number;
+}
+
+
+@Injectable({providedIn: 'root'})
+export class PartyDuesApi {
+  public getNotPayUserListUrl = '/appApi/party/getPartyDuesUserListOfAddfee';
+
+  constructor(private configService: ConfigService, private userService: UserService) {
+  }
+
+  getList(params: reqParams): Observable<RequsetData> {
+    return this.configService.HttpGetRomote('/appApi/party/getUserDuesList', params);
+  }
+
+  deleteDetail(detailId: string): Observable<RequsetData> {
+    return this.configService.HttpPostRomote('/appApi/party/deleteDuesById', {
+      id: detailId,
+      userId: this.userService.GetUser().userid
+    });
+  }
+
+  getNotPayUserList(year: number, month: number) {
+    return this.configService.HttpGetRomote(this.getNotPayUserListUrl, {year: year, month: month});
+  }
+
+  saveDuesList(duesList: any) {
+    return this.configService.HttpPostRomote('/appApi/party/savePartyDuesMulti', {
+      userList: JSON.stringify(duesList),
+      userId: this.userService.GetUser().userid,
+      userName: this.userService.GetUser().username
+    });
+  }
+
+  getDataByDetailId(detailId: string) {
+    return this.configService.HttpGetRomote('/appApi/party/getUserduesDetailById', {detailId: detailId});
+  }
+
+  savePartyduesDetail(data: any) {
+    return this.configService.HttpPostRomote('/appApi/party/savePartyduesDetail', {
+      dataModel: data,
+      userId: this.userService.GetUser().userid,
+      userName: this.userService.GetUser().username
+    })
+  }
+
+}
+

+ 53 - 0
parth5/parth5/src/app/api/propagandawork/position/index.ts

@@ -0,0 +1,53 @@
+import {ConfigService, RequsetData} from "../../../service/config.service";
+import {Injectable} from "@angular/core";
+import {Observable} from "rxjs";
+import {UserService} from "../../../service/user.service";
+
+export interface reqParams {
+  pageIndex: number,
+  pageSize: number,
+  dzzdm: string,
+  positionName: string,
+  positionType: number,
+  positionLevel: number,
+  positionState: number,
+  startDate: string,
+  endDate: string
+}
+
+@Injectable({providedIn: 'root'})
+export class PositionApi {
+  constructor(private configService: ConfigService, private userService: UserService) {
+  }
+
+  getList(params: reqParams): Observable<RequsetData> {
+    return this.configService.HttpGetRomote('/appApi/publicity/getPositionList', params);
+  }
+
+  delete(id: string): Observable<RequsetData> {
+    return this.configService.HttpGetRomote('/appApi/publicity/deletePositionById', {
+      id: id,
+    });
+  }
+
+  getData(id: string, dzzdm: string) {
+    return this.configService.HttpGetRomote('/appApi/publicity/getPositionById', {id: id, dzzdm: dzzdm});
+  }
+
+  deletePlan(id: string) {
+    return this.configService.HttpGetRomote('/app/appApi/publicity/deletePanel', {
+      id: id,
+    });
+  }
+
+  save(data: any, panelList: any): Observable<RequsetData> {
+    return this.configService.HttpPostRomote('/appApi/publicity/savePosition', {
+      dataModel: data,
+      userId: this.userService.GetUser().userid,
+      userName: this.userService.GetUser().username,
+      panelList: JSON.stringify(panelList)
+    });
+  }
+
+}
+

+ 44 - 0
parth5/parth5/src/app/api/propagandawork/position/panel/index.ts

@@ -0,0 +1,44 @@
+import {Injectable} from "@angular/core";
+import {Observable} from "rxjs";
+import {UserService} from "../../../../service/user.service";
+import {ConfigService, RequsetData} from "../../../../service/config.service";
+
+export interface reqParams {
+  pageIndex: number,
+  pageSize: number,
+  positionId: string
+
+}
+
+@Injectable({providedIn: 'root'})
+export class PanelApi {
+  constructor(private configService: ConfigService, private userService: UserService) {
+  }
+
+  getList(params: reqParams): Observable<RequsetData> {
+    return this.configService.HttpGetRomote('/appApi/publicity/getPanelRecordList', params);
+  }
+
+  delete(id: string): Observable<RequsetData> {
+    return this.configService.HttpGetRomote('/appApi/publicity/deletePositionById', {
+      id: id,
+    });
+  }
+
+  getData(panelId: string, positionId: string) {
+    return this.configService.HttpGetRomote('/appApi/publicity/getPanelById', {
+      panelId: panelId,
+      positionId: positionId
+    });
+  }
+
+  save(data: any): Observable<RequsetData> {
+    return this.configService.HttpPostRomote('/appApi/publicity/savePanel', {
+      dataModel: data,
+      userId: this.userService.GetUser().userid,
+      userName: this.userService.GetUser().username,
+    });
+  }
+
+}
+

+ 15 - 0
parth5/parth5/src/app/api/system/dictionary/index.ts

@@ -0,0 +1,15 @@
+import {Injectable} from "@angular/core";
+import {Observable} from "rxjs";
+import {ConfigService, RequsetData} from "../../../service/config.service";
+
+@Injectable({providedIn: 'root'})
+export class DictionaryApi {
+  constructor(private configService: ConfigService) {
+  }
+
+  getDictionaryList(dicTypeKey: string): Observable<RequsetData> {
+    return this.configService.HttpGetRomote('/appApi/dic/getDictionaryList', {dicTypeKey: dicTypeKey});
+  }
+
+}
+

+ 20 - 3
parth5/parth5/src/app/app.scss

@@ -1,8 +1,8 @@
 // App Styles
 // ----------------------------------------------------------------------------
-// Put style rules here that you want to apply to the entire application. These 
-// styles are for the entire app and not just one component. Additionally, this 
-// file can hold Sass mixins, functions, and placeholder classes to be imported 
+// Put style rules here that you want to apply to the entire application. These
+// styles are for the entire app and not just one component. Additionally, this
+// file can hold Sass mixins, functions, and placeholder classes to be imported
 // and used throughout the application.
 @import "~photoswipe/dist/photoswipe.css";
 @import "~photoswipe/dist/default-skin/default-skin.css";
@@ -498,3 +498,20 @@ background: white;
 .filter-option{
   min-height: 55px;
 }
+
+.footer-btn{
+  display: flex;
+  text-align: center;
+  margin: 20px;
+  ion-button{
+    width: 100%;
+    height: 35px;
+  }
+}
+
+ion-list {
+  ion-item{
+    --inner-padding-top: 8px;
+    --inner-padding-bottom: 8px;
+  }
+}

+ 57 - 0
parth5/parth5/src/app/comm/modal/alert/index.ts

@@ -0,0 +1,57 @@
+import {Injectable} from "@angular/core";
+import {AlertController, LoadingController} from "@ionic/angular";
+
+@Injectable({
+  providedIn: 'root'
+})
+export class AlertModal {
+  constructor(private alertController: AlertController, private loadingController: LoadingController) {
+
+  }
+
+  async loading(msg: string): Promise<HTMLIonLoadingElement> {
+    const loading = await this.loadingController.create({
+      message: msg,
+      spinner: 'circles'
+    });
+
+    await loading.present();
+
+    return loading;
+  }
+
+  async alert(msg: string) {
+    const alert = await this.alertController.create({
+      header: '提示',
+      subHeader: '',
+      message: msg,
+      buttons: ['确定']
+    });
+
+    await alert.present();
+  }
+
+  async confirm(msg: string, handler) {
+    const alert = await this.alertController.create({
+      header: '提示',
+      message: '<strong>' + msg + '</strong>',
+      buttons: [
+        {
+          text: '关闭',
+          role: 'cancel',
+          cssClass: 'secondary',
+          handler: () => {
+
+          }
+        }, {
+          text: '确定',
+          handler: handler
+        }
+      ]
+    });
+
+    await alert.present();
+  }
+
+
+}

+ 1 - 0
parth5/parth5/src/app/comm/modal/bimage/bimage.component.html

@@ -0,0 +1 @@
+<img [src]="imgModel.trustUrl" (click)="showBigImage()" onerror="this.src='assets/icon/nopic.png';this.classList.remove('item-img')"/>

+ 7 - 0
parth5/parth5/src/app/comm/modal/bimage/bimage.component.scss

@@ -0,0 +1,7 @@
+img{
+  object-fit: cover;
+  margin-right: 10px;
+  border-radius: 8px;
+  height: 100%;
+  width: 100%;
+}

+ 75 - 0
parth5/parth5/src/app/comm/modal/bimage/bimage.component.ts

@@ -0,0 +1,75 @@
+import {Component, Input, OnInit, ViewChild} from '@angular/core';
+import {FileApi} from "../../../api/file";
+import {RequsetData} from "../../../service/config.service";
+import {DomSanitizer} from '@angular/platform-browser';
+import {PhotoSwipeComponent} from "../photo-swipe/photo-swipe.component";
+import {AlertModal} from "../alert";
+
+@Component({
+  selector: 'app-bimage',
+  templateUrl: './bimage.component.html',
+  styleUrls: ['./bimage.component.scss'],
+})
+export class BimageComponent implements OnInit {
+  @ViewChild(PhotoSwipeComponent)
+  photoSwipe: PhotoSwipeComponent;
+
+  @Input() fileid: string = '';
+
+  imgModel: any = {
+    fileid: ''
+  };
+
+  constructor(private fileApi: FileApi, private sanitizer: DomSanitizer, private alertModal: AlertModal) {
+  }
+
+  ngOnInit() {
+    this.getImgBase64();
+  }
+
+  getImgBase64() {
+    this.fileApi.getImageBase64(this.fileid).subscribe((data: RequsetData) => {
+      if (data.success && data.item != null) {
+        this.imgModel.base64 = "data:image/png;base64," + data.item.base64;
+        this.imgModel.height = data.item.height;
+        this.imgModel.width = data.item.width;
+        this.imgModel.blobUrl = URL.createObjectURL(this.base64ToBlob(this.imgModel.base64));
+        this.imgModel.trustUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.imgModel.blobUrl);
+      }
+    });
+  }
+
+  base64ToBlob(data) {
+    var arr = data.split(','),
+      mime = arr[0].match(/:(.*?);/)[1],
+      bstr = atob(arr[1]),
+      n = bstr.length,
+      u8arr = new Uint8Array(n);
+
+    while (n--) {
+      u8arr[n] = bstr.charCodeAt(n);
+    }
+    return new Blob([u8arr], {type: mime});
+  }
+
+
+  showBigImage() {
+    try {
+      var items = [];
+
+      items.push({
+        src: this.imgModel.blobUrl,
+        w: this.imgModel.width || 500,
+        h: this.imgModel.height || 300
+      });
+
+      this.photoSwipe.open(items, {
+        index: 0,
+        tapToClose: true
+      }, "pswp" + (Math.random() * 100000).toFixed(0).toString());
+    } catch (e) {
+      this.alertModal.alert("图片查看异常:" + e);
+    }
+  }
+
+}

+ 42 - 75
parth5/parth5/src/app/comm/modal/imglist/imglist.component.ts

@@ -1,11 +1,12 @@
 import {Component, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
 import {ConfigService, RequsetData} from "../../../service/config.service";
 import {UserService} from "../../../service/user.service";
-import {ActionSheetController, AlertController, LoadingController} from "@ionic/angular";
+import {ActionSheetController} from "@ionic/angular";
 import {PhotoSwipeComponent} from "../photo-swipe/photo-swipe.component";
 import {base64File, FileApi} from "../../../api/file";
 import {Camera, CameraResultType, CameraSource} from "@capacitor/camera";
 import {DomSanitizer} from '@angular/platform-browser';
+import {AlertModal} from "../alert";
 
 @Component({
   selector: 'app-imglist',
@@ -31,9 +32,8 @@ export class ImglistComponent implements OnInit {
   loading: any = null;
   imgExt = ['.jpg', '.bmp', '.png', '.gif', '.jpe', '.jpeg'];
 
-  constructor(private configService: ConfigService, private userService: UserService, public alertController: AlertController,
-              public loadingController: LoadingController, private actionSheetController: ActionSheetController
-    , private fileApi: FileApi, private sanitizer: DomSanitizer) {
+  constructor(private configService: ConfigService, private userService: UserService, private actionSheetController: ActionSheetController
+    , private fileApi: FileApi, private sanitizer: DomSanitizer, private alertModal: AlertModal) {
   }
 
   ngOnInit() {
@@ -81,7 +81,7 @@ export class ImglistComponent implements OnInit {
 
   //删除图片
   removeImg(id) {
-    this.presentAlertConfirm("确认删除?", () => {
+    this.alertModal.confirm("确认删除?", () => {
       this.fileApi.delete(id).subscribe((fdata: RequsetData) => {
         if (fdata.success) {
           /*this.getImgList();*/
@@ -110,7 +110,7 @@ export class ImglistComponent implements OnInit {
         tapToClose: true
       }, "pswp" + (Math.random() * 100000).toFixed(0).toString());
     } catch (e) {
-      this.presentAlert("图片查看异常:" + e);
+      this.alertModal.alert("图片查看异常:" + e);
     }
   }
 
@@ -202,77 +202,44 @@ export class ImglistComponent implements OnInit {
       isImage: true
     }
 
-    await thisComponent.presentLoading('正在上传,请稍等...', 2000);
-
-    if (!thisComponent.imgOption.isMulti) {
-      thisComponent.fileApi.deleteByRefId(fileModel.fileRefId, fileModel.fileType).subscribe((data: RequsetData) => {
-        if (data.success) {
-          thisComponent.imgList = [];
-
-          thisComponent.fileApi.uploadFileBase64(fileModel).subscribe((data: RequsetData) => {
-            if (data.success) {
-              thisComponent.presentAlert("上传成功");
-              thisComponent.getImgList();
-            } else {
-              thisComponent.presentAlert(data.msg);
-            }
-          });
-        } else {
-          thisComponent.presentAlert("原文件删除失败!" + data.msg);
-        }
-      });
-    } else {
-      thisComponent.fileApi.uploadFileBase64(fileModel).subscribe((data: RequsetData) => {
-        if (data.success) {
-          thisComponent.presentAlert("上传成功");
-          thisComponent.getImgList();
-        } else {
-          thisComponent.presentAlert(data.msg);
-        }
-      });
-    }
-  }
-
-  async presentAlert(msg: string) {
-    const alert = await this.alertController.create({
-      header: '提示',
-      subHeader: '',
-      message: msg,
-      buttons: ['确定']
-    });
-
-    await alert.present();
-  }
-
-  async presentAlertConfirm(msg: string, handler) {
-    const alert = await this.alertController.create({
-      header: '提示',
-      message: '<strong>' + msg + '</strong>',
-      buttons: [
-        {
-          text: '取消',
-          role: 'cancel',
-          cssClass: 'secondary',
-          handler: () => {
-
+    thisComponent.alertModal.loading('正在上传,请稍等...').then((loading) => {
+      if (!thisComponent.imgOption.isMulti) {
+        thisComponent.fileApi.deleteByRefId(fileModel.fileRefId, fileModel.fileType).subscribe((data: RequsetData) => {
+          if (data.success) {
+            thisComponent.imgList = [];
+
+            thisComponent.fileApi.uploadFileBase64(fileModel).subscribe((data: RequsetData) => {
+              loading.dismiss();
+              if (data.success) {
+                thisComponent.alertModal.alert("上传成功");
+                thisComponent.getImgList();
+              } else {
+                thisComponent.alertModal.alert(data.msg);
+              }
+            }, () => {
+              loading.dismiss();
+            });
+          } else {
+            loading.dismiss();
+            thisComponent.alertModal.alert("原文件删除失败!" + data.msg);
           }
-        }, {
-          text: '确定',
-          handler: handler
-        }
-      ]
-    });
-
-    await alert.present();
-  }
-
-  async presentLoading(msg: string, duration: number) {
-    this.loading = await this.loadingController.create({
-      message: msg,
-      spinner: 'circles',
-      duration: duration
+        }, () => {
+          loading.dismiss();
+        });
+      } else {
+        thisComponent.fileApi.uploadFileBase64(fileModel).subscribe((data: RequsetData) => {
+          loading.dismiss();
+          if (data.success) {
+            thisComponent.alertModal.alert("上传成功");
+            thisComponent.getImgList();
+          } else {
+            thisComponent.alertModal.alert(data.msg);
+          }
+        }, () => {
+          loading.dismiss();
+        });
+      }
     });
-    return this.loading.present();
   }
 
 }

+ 12 - 0
parth5/parth5/src/app/routes/partyDues.ts

@@ -0,0 +1,12 @@
+import {Routes} from "@angular/router";
+import {PartyDuesComponent} from "../views/pages/partyuser/party-dues/party-dues.component";
+import {EditComponent} from "../views/pages/partyuser/party-dues/edit/edit.component";
+import {DetailComponent} from "../views/pages/partyuser/party-dues/detail/detail.component";
+
+const routes: Routes = [
+  {path: 'partyDues', component: PartyDuesComponent},
+  {path: 'partyDues/detail', component: DetailComponent},
+  {path: 'partyDues/edit', component: EditComponent},
+];
+
+export default routes;

+ 7 - 7
parth5/parth5/src/app/routes/partyUser.ts

@@ -1,11 +1,11 @@
 import {Routes} from "@angular/router";
-import {PartyUserComponent} from "../views/pages/party/party-user/party-user.component";
-import {DetailComponent} from "../views/pages/party/party-user/detail/detail.component";
-import {DemocracyComponent} from "../views/pages/party/party-user/detail/democracy/democracy.component";
-import {PartyhelpComponent} from "../views/pages/party/party-user/detail/partyhelp/partyhelp.component";
-import {PunishComponent} from "../views/pages/party/party-user/detail/punish/punish.component";
-import {RewardComponent} from "../views/pages/party/party-user/detail/reward/reward.component";
-import {TrainComponent} from "../views/pages/party/party-user/detail/train/train.component";
+import {PartyUserComponent} from "../views/pages/partyuser/party-user/party-user.component";
+import {DetailComponent} from "../views/pages/partyuser/party-user/detail/detail.component";
+import {DemocracyComponent} from "../views/pages/partyuser/party-user/detail/democracy/democracy.component";
+import {PartyhelpComponent} from "../views/pages/partyuser/party-user/detail/partyhelp/partyhelp.component";
+import {PunishComponent} from "../views/pages/partyuser/party-user/detail/punish/punish.component";
+import {RewardComponent} from "../views/pages/partyuser/party-user/detail/reward/reward.component";
+import {TrainComponent} from "../views/pages/partyuser/party-user/detail/train/train.component";
 
 const routes: Routes = [
   {path: 'partyUser', component: PartyUserComponent},

+ 16 - 0
parth5/parth5/src/app/routes/propagandawork/position.ts

@@ -0,0 +1,16 @@
+import {Routes} from "@angular/router";
+import {PositionComponent} from "../../views/pages/propagandawork/position/position.component";
+import {EditComponent} from "../../views/pages/propagandawork/position/edit/edit.component";
+import {DetailComponent} from "../../views/pages/propagandawork/position/detail/detail.component";
+import {EditComponent as PanelEditComponent} from "../../views/pages/propagandawork/position/panel/edit/edit.component";
+import {DetailComponent as PanelDetailComponent} from "../../views/pages/propagandawork/position/panel/detail/detail.component";
+
+const routes: Routes = [
+  {path: 'propagandawork/position', component: PositionComponent},
+  {path: 'propagandawork/position/edit', component: EditComponent},
+  {path: 'propagandawork/position/detail', component: DetailComponent},
+  {path: 'propagandawork/position/panel/edit', component: PanelEditComponent},
+  {path: 'propagandawork/position/panel/detail', component: PanelDetailComponent}
+];
+
+export default routes;

+ 17 - 1
parth5/parth5/src/app/service/config.service.ts

@@ -1,5 +1,5 @@
 import {Injectable, Optional} from '@angular/core';
-import {HttpClient} from '@angular/common/http';
+import {HttpClient, HttpParams} from '@angular/common/http';
 import {HttpErrorResponse, HttpResponse, HttpHeaders} from '@angular/common/http';
 
 import {Observable, throwError} from 'rxjs';
@@ -54,8 +54,24 @@ export class ConfigService {
     return cf;
   };
 
+  //过滤null或undefined的参数
+  cleanedParams(params?: any) {
+    let cleanedParams = {};
+    if (params) {
+      Object.keys(params).forEach(x => {
+        if (params[x] != null && params[x] != undefined) {
+          cleanedParams[x] = params[x];
+        }
+      });
+    }
+
+    return cleanedParams;
+  }
+
   HttpGetRomote(url: string, params?: any): Observable<RequsetData> {
 
+    params = this.cleanedParams(params);
+
     const httpGetSubscriber = new Observable<RequsetData>((observer) => {
       this.GetConfig().subscribe((cfdata: Config) => {
         var remoteUrl = cfdata.webServerHost + url;

+ 41 - 0
parth5/parth5/src/app/views/pages/partyuser/party-dues/detail/detail.component.html

@@ -0,0 +1,41 @@
+<ion-header class="header-theme2">
+  <ion-toolbar>
+    <ion-label class="title-center">党费详情</ion-label>
+    <ion-buttons slot="start">
+      <ion-back-button icon="ios-back2" text="" mode="md"></ion-back-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+<ion-content>
+  <form #dataForm="ngForm" class="form-table">
+    <ion-list>
+      <ion-item mode="md">
+        <ion-label>姓名</ion-label>
+        <ion-input #money="ngModel" name="username" id="username" [(ngModel)]="duesModel.username" readonly></ion-input>
+      </ion-item>
+      <ion-item mode="md">
+        <ion-label>年份</ion-label>
+        <ion-input #money="ngModel" name="year" id="year" [(ngModel)]="duesModel.year" readonly></ion-input>
+      </ion-item>
+      <ion-item mode="md">
+        <ion-label>月份</ion-label>
+        <ion-input #money="ngModel" name="month" id="month" [(ngModel)]="detailModel.month" readonly></ion-input>
+      </ion-item>
+      <ion-item mode="md">
+        <ion-label>交纳金额<span class="danger">*</span></ion-label>
+        <ion-input #money="ngModel" name="money" id="money" [(ngModel)]="detailModel.money" required></ion-input>
+      </ion-item>
+      <!--<ion-item mode="md">
+        <ion-label>特殊党费</ion-label>
+        <ion-input #specialexpenses="ngModel" name="specialexpenses" id="specialexpenses" [(ngModel)]="detailModel.specialexpenses"></ion-input>
+      </ion-item>-->
+    </ion-list>
+    <div class="footer-btn">
+      <ion-button slot="end" color="danger" mode="ios"
+                  (click)="save()" [disabled]="!dataForm.form.valid">
+        提交
+      </ion-button>
+    </div>
+  </form>
+</ion-content>
+

parth5/parth5/src/app/views/pages/party/party-user/party-user.component.scss → parth5/parth5/src/app/views/pages/partyuser/party-dues/detail/detail.component.scss


+ 56 - 0
parth5/parth5/src/app/views/pages/partyuser/party-dues/detail/detail.component.ts

@@ -0,0 +1,56 @@
+import {Component, OnInit} from '@angular/core';
+import {DatePipe} from "@angular/common";
+import {ActivatedRoute, Router} from "@angular/router";
+import {ConfigService, RequsetData} from "../../../../../service/config.service";
+import {UserService} from "../../../../../service/user.service";
+import {AlertModal} from "../../../../../comm/modal/alert";
+import {PartyDuesApi} from "../../../../../api/partyuser/partydues";
+
+@Component({
+  selector: 'app-detail',
+  templateUrl: './detail.component.html',
+  styleUrls: ['./detail.component.scss'],
+})
+export class DetailComponent implements OnInit {
+
+  detailModel: any = {};
+  duesModel: any = {};
+
+  constructor(private datePipe: DatePipe, private router: Router, private routeInfo: ActivatedRoute, private configService: ConfigService, private userService: UserService,
+              public alertModal: AlertModal, private partyDuesApi: PartyDuesApi) {
+  }
+
+  ngOnInit() {
+    this.routeInfo.queryParams.subscribe(params => {
+      this.detailModel.detailid = params['id'];
+      this.getData();
+    });
+  }
+
+  getData() {
+    this.partyDuesApi.getDataByDetailId(this.detailModel.detailid).subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.detailModel = data.item;
+        this.duesModel = data.extdata.duesModel;
+      }
+    });
+  }
+
+  save() {
+    this.alertModal.loading("提交中...").then((loading) => {
+      this.partyDuesApi.savePartyduesDetail(this.detailModel).subscribe((data: RequsetData) => {
+        loading.dismiss();
+
+        if (data.success) {
+          this.back();
+        }
+        this.alertModal.alert(data.msg);
+      });
+    });
+  }
+
+  back() {
+    this.router.navigate(['../../partyDues'], {relativeTo: this.routeInfo, queryParams: {random: Math.random()}});
+  }
+
+}

+ 73 - 0
parth5/parth5/src/app/views/pages/partyuser/party-dues/edit/edit.component.html

@@ -0,0 +1,73 @@
+<ion-header class="header-theme2">
+  <ion-toolbar>
+    <ion-label class="title-center">批量交党费</ion-label>
+    <ion-buttons slot="start">
+      <ion-back-button icon="ios-back2" mode="md"></ion-back-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+<ion-content>
+  <ion-list>
+    <ion-item detail>
+      <ion-label>党支部名称</ion-label>
+      <app-partyselect [(dzzdm)]="dataModel.dzzdm" [(dzzmc)]="dataModel.dzzmc"
+                       (dzzdmChange)="getUserList()"></app-partyselect>
+    </ion-item>
+    <ion-item>
+      <ion-label style="flex:unset;">年份</ion-label>
+      <ion-select okText="确定" cancelText="取消" style="width: 80px;"
+                  interface="action-sheet" [(ngModel)]="dataModel.year"
+                  (ionChange)="yearChange($event)">
+        <ion-select-option [value]="it.dickey" *ngFor="let it of years">{{it.dicvalue}}
+        </ion-select-option>
+      </ion-select>
+      <ion-label style="flex:unset;margin-left: 50px;">月份</ion-label>
+      <ion-select okText="确定" cancelText="取消"
+                  interface="action-sheet" [(ngModel)]="dataModel.month"
+                  (ionChange)="monthChange($event)">
+        <ion-select-option [value]="it" *ngFor="let it of months">{{it}}
+        </ion-select-option>
+      </ion-select>
+    </ion-item>
+  </ion-list>
+  <ion-item class="grid-title">
+    <ion-label>应缴党费明细</ion-label>
+    <ion-button (click)="selectUser()" fill="clear" size="">
+      <ion-icon name="add-circle-outline" size="large" color="danger"></ion-icon>
+    </ion-button>
+  </ion-item>
+  <ion-grid>
+    <ion-row>
+      <ion-col>
+        姓名
+      </ion-col>
+      <ion-col>
+        交纳金额
+        <br>
+        <span> (元/月)</span>
+      </ion-col>
+      <ion-col>
+        操作
+      </ion-col>
+    </ion-row>
+    <ion-row *ngFor="let item of dataList;let idx=index">
+      <ion-col>
+        {{item.USERNAME}}
+      </ion-col>
+      <ion-input type="number" [(ngModel)]="item.MONEY" required></ion-input>
+      <ion-col class="grid-btn">
+        <span (click)="delete(idx)">删除</span>
+      </ion-col>
+    </ion-row>
+  </ion-grid>
+  <ion-item *ngIf="dataList.length==0" style="text-align: center;">
+    <ion-label><p>暂无数据</p></ion-label>
+  </ion-item>
+  <div class="footer-btn">
+    <ion-button slot="end" color="danger" mode="ios"
+                (click)="save()">
+      提交
+    </ion-button>
+  </div>
+</ion-content>
+

+ 70 - 0
parth5/parth5/src/app/views/pages/partyuser/party-dues/edit/edit.component.scss

@@ -0,0 +1,70 @@
+ion-item {
+  --inner-border-width: 0px;
+  --border-width: 0px;
+
+  ion-label {
+    overflow: visible;
+    color: #998989;
+  }
+}
+
+ion-select, ion-input {
+  padding-top: 12px;
+}
+
+.grid-title {
+  --background: #FAFAFA !important;
+
+  ion-label {
+    color: #380F0A;
+  }
+}
+
+ion-grid {
+  padding: 0px;
+  color: #5E4545;
+
+  ion-row {
+    padding: 5px 12px;
+    border-bottom: 1px solid #F4F5F7;
+
+    ion-col {
+      display: -webkit-box;
+      -webkit-box-orient: horizontal;
+      -webkit-box-align: center;
+    }
+
+    ion-col:not(:first-child) {
+      -webkit-box-pack: center;
+      text-align: center;
+    }
+
+    ion-input{
+      background-color: #F5F5F5;
+      border-radius: 20px;
+      margin: 3px;
+      height: 30px;
+      --padding-top: 0;
+      --padding-bottom: 0;
+      --padding-start: 10px;
+    }
+
+    .grid-btn{
+      color: #007EFF;
+      cursor: pointer;
+    }
+  }
+
+  ion-row:first-child {
+    font-size: 14px;
+    color: #998989;
+  }
+
+  ion-row:not(:first-child) {
+    background-color: white;
+  }
+}
+
+app-partyselect{
+  width: 75%;
+}

+ 153 - 0
parth5/parth5/src/app/views/pages/partyuser/party-dues/edit/edit.component.ts

@@ -0,0 +1,153 @@
+import {Component, OnInit} from '@angular/core';
+import {DatePipe} from "@angular/common";
+import {ActivatedRoute, Router} from "@angular/router";
+import {RequsetData} from "../../../../../service/config.service";
+import {UserService} from "../../../../../service/user.service";
+import {ModalController} from "@ionic/angular";
+import {SelectuserComponent} from "../selectuser/selectuser.component";
+import {PartyDuesApi} from "../../../../../api/partyuser/partydues";
+import {DictionaryApi} from "../../../../../api/system/dictionary";
+import {AlertModal} from "../../../../../comm/modal/alert";
+
+@Component({
+  selector: 'app-edit',
+  templateUrl: './edit.component.html',
+  styleUrls: ['./edit.component.scss'],
+})
+export class EditComponent implements OnInit {
+
+  dataModel: any = {
+    'pageIndex': 1,
+    'pageSize': 1000, dzzmc: '', dzzdm: '', year: null, month: ''
+  };
+  years: any = [];
+  months: any = [];
+  dataList: any = [];
+
+  constructor(private datePipe: DatePipe, private router: Router, private routeInfo: ActivatedRoute, private userService: UserService,
+              public modalController: ModalController, private partyDuesApi: PartyDuesApi, private dictionaryApi: DictionaryApi, private alertModal: AlertModal) {
+  }
+
+  ngOnInit() {
+    this.routeInfo.queryParams.subscribe(params => {
+      this.dataModel.dzzdm = this.userService.GetUser().dataDzzdm.length <= 9 ? this.userService.GetUser().DZZDM : this.userService.GetUser().dataDzzdm;
+      this.dataModel.dzzmc = this.userService.GetUser().dataDzzdm.length <= 9 ? this.userService.GetUser().DZZMC : this.userService.GetUser().dataDzzmc;
+      this.getYearList();
+    });
+  }
+
+  getYearList() {
+    this.dictionaryApi.getDictionaryList('years').subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.years = data.item;
+        for (let i = 1; i <= 12; i++) {
+          this.months.push(i);
+        }
+        this.dataModel.month = new Date().getMonth() + 1;
+        this.dataModel.year = new Date().getFullYear();
+        this.getUserList();
+      }
+    });
+  }
+
+  getUserList() {
+    this.dataList = [];
+    this.partyDuesApi.getNotPayUserList(this.dataModel.year, this.dataModel.month).subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.dataList = data.item.list;
+      }
+    });
+  }
+
+  yearChange(e) {
+    this.getUserList();
+  }
+
+  monthChange(e) {
+    this.getUserList();
+  }
+
+  delete(index) {
+    this.dataList.splice(index, 1);
+  }
+
+  selectUser() {
+    this.presentModal();
+  }
+
+  save() {
+    if (this.dataList.length <= 0) {
+      this.alertModal.alert('请选择需要缴费的党员');
+      return false;
+    }
+
+    if (this.dataList.filter(it => it.MONEY == null || it.MONEY === '').length > 0) {
+      this.alertModal.alert('请填写党费');
+      return false;
+    }
+
+    //数据处理
+    var userList = [];
+    this.dataList.forEach((val, key) => {
+      userList.push({
+        partyduesid: val.PARTYDUESID,
+        month: this.dataModel.month,
+        money: val.MONEY,
+        specialexpenses: val.SPECIALEXPENSES,
+        partycode: val.PARTYCODE
+      });
+    });
+
+    this.alertModal.loading("提交中...").then((loading) => {
+      this.partyDuesApi.saveDuesList(userList).subscribe((fdata: RequsetData) => {
+        loading.dismiss();
+        if (fdata.success) {
+          this.back();
+        }
+        this.alertModal.alert(fdata.msg);
+      });
+    });
+  }
+
+  //人员选择控件
+  async presentModal() {
+    const modal = await this.modalController.create({
+      component: SelectuserComponent,
+      componentProps: {
+        'pageIndex': 1,
+        'pageSize': 30,
+        'year': this.dataModel.year,
+        'month': this.dataModel.month,
+        'dzzdm': this.dataModel.dzzdm,
+        'getUserUrl': this.partyDuesApi.getNotPayUserListUrl
+      }
+    });
+
+    await modal.present();
+
+    const {data} = await modal.onWillDismiss();
+    if (data.rtnData != null && data.rtnData.length > 0) {
+      var us = data.rtnData;
+
+      data.rtnData.forEach(item => {
+          this.dataList.push({
+            PARTYDUESID: item.PARTYDUESID,
+            USERNAME: item.USERNAME,
+            USERCODE: item.USERCODE,
+            BASENUMBER: item.BASENUMBER,
+            MONEY: item.MONEY,
+            SPECIALEXPENSES: item.SPECIALEXPENSES,
+            PARTYCODE: item.PARTYCODE
+          });
+        }
+      )
+      ;
+
+    }
+  }
+
+  back() {
+    this.router.navigate(['../../partyDues'], {relativeTo: this.routeInfo});
+  }
+
+}

+ 65 - 0
parth5/parth5/src/app/views/pages/partyuser/party-dues/party-dues.component.html

@@ -0,0 +1,65 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-label>党费管理</ion-label>
+    <ion-buttons slot="start">
+      <ion-back-button icon="ios-back" mode="md"></ion-back-button>
+    </ion-buttons>
+    <ion-searchbar slot="end" mode="ios" enterkeyhint="search" placeholder="搜索党员名称" showCancelButton="never"
+                   (ionChange)="searchChange($event)"></ion-searchbar>
+  </ion-toolbar>
+  <app-partysearch [(dzzdm)]="searchParams.ssdzzdm" (dzzdmChange)="reload()"></app-partysearch>
+  <ion-item class="item-filter">
+    <ion-select okText="确定" cancelText="取消"
+                interface="action-sheet" placeholder="所有年份" [(ngModel)]="searchParams.year"
+                (ionChange)="yearChange($event)" selectedText="{{fetchYearLabel()}}年">
+      <ion-select-option value="">所有年份</ion-select-option>
+      <ion-select-option [value]="it.dickey" *ngFor="let it of yearList">{{it.dicvalue}}年
+      </ion-select-option>
+    </ion-select>
+    <ion-select okText="确定" cancelText="取消"
+                interface="action-sheet" placeholder="所有年份" [(ngModel)]="searchParams.month"
+                (ionChange)="monthChange($event)" style="margin-left: 30px;" selectedText="{{fetchMonthLabel()}}月">
+      <ion-select-option value="">所有月份</ion-select-option>
+      <ion-select-option [value]="it" *ngFor="let it of monthList">{{it}}月
+      </ion-select-option>
+    </ion-select>
+  </ion-item>
+</ion-header>
+<ion-content>
+  <ion-list>
+    <ion-item-sliding *ngFor="let item of dataList">
+      <ion-item detail class="border-item" [routerLink]="['./detail']" [queryParams]="{id: item.detailid}">
+        <ion-label class="item-username">
+          <h2>
+            <div>{{item.userName}}</div>
+            <span class="dues-month">{{item.year}}-{{item.month}}</span></h2>
+          <p>{{item.dzzmc}}</p>
+        </ion-label>
+        <div slot="end" class="dues-money">
+          <span>{{item.money}}元</span>
+        </div>
+      </ion-item>
+
+      <ion-item-options side="end">
+        <ion-item-option (click)="delete(item.detailid)">删除</ion-item-option>
+      </ion-item-options>
+    </ion-item-sliding>
+  </ion-list>
+  <app-empty *ngIf="dataList.length===0"></app-empty>
+  <ion-infinite-scroll threshold="100px" (ionInfinite)="scroll($event)">
+    <ion-infinite-scroll-content
+      loadingSpinner="bubbles"
+      loadingText="{{total>searchParams.pageIndex*searchParams.pageSize?'正在加载...':'暂无更多'}}">
+    </ion-infinite-scroll-content>
+  </ion-infinite-scroll>
+  <ion-fab vertical="bottom" horizontal="center" slot="fixed" class="fab-add">
+    <ion-fab-button>
+      <ion-text class="btn-add" (click)="add()">
+        <img src="assets/icon/btnadd.png" style="width: 30px;height:30px;">
+        <span class="btn-add-text">新增</span>
+      </ion-text>
+    </ion-fab-button>
+  </ion-fab>
+</ion-content>
+
+

+ 47 - 0
parth5/parth5/src/app/views/pages/partyuser/party-dues/party-dues.component.scss

@@ -0,0 +1,47 @@
+ion-label {
+  margin: 3px !important;
+  padding: 0px;
+}
+.dues-month{
+  color: #998989;
+  font-size: 12px;
+  border-radius: 4px;
+  background-color: #F3F3F3;
+  padding: 0px 4px;
+  margin-left: 20px;
+}
+
+.dues-money{
+  color: #DE4F3F;
+}
+
+
+
+ion-select {
+  color: #5E4545;
+
+  --placeholder-color: #5E4545;
+
+  --placeholder-opacity: 1;
+}
+ion-select::part(icon) {
+  color: #5E4545;
+  opacity: 1;
+}
+ion-header {
+  ion-item {
+    --inner-border-width:  0px;
+    --border-width:0px;
+  }
+}
+
+.item-username{
+  h2{
+    display: -webkit-box;
+    div{
+      width: 60px;
+    }
+  }
+}
+
+

+ 139 - 0
parth5/parth5/src/app/views/pages/partyuser/party-dues/party-dues.component.ts

@@ -0,0 +1,139 @@
+import {Component, OnInit, ViewChild} from '@angular/core';
+import {AlertController, IonInfiniteScroll, LoadingController, ModalController, NavController} from "@ionic/angular";
+import {ActivatedRoute, Router} from "@angular/router";
+import {ConfigService, RequsetData} from "../../../../service/config.service";
+import {UserService} from "../../../../service/user.service";
+import {PartyDuesApi, reqParams} from "../../../../api/partyuser/partydues";
+import {DictionaryApi} from "../../../../api/system/dictionary";
+import {AlertModal} from "../../../../comm/modal/alert";
+import {Observable, of} from "rxjs";
+
+@Component({
+  selector: 'app-party-dues',
+  templateUrl: './party-dues.component.html',
+  styleUrls: ['./party-dues.component.scss'],
+})
+export class PartyDuesComponent implements OnInit {
+
+  @ViewChild(IonInfiniteScroll, {static: true}) infiniteScroll: IonInfiniteScroll;
+
+  userInfo: any = {};
+  dataList: any[] = [];
+  searchParams: reqParams = {
+    pageIndex: 1,
+    pageSize: 20,
+    ssdzzdm: '',
+    xm: '',
+    year: null,
+    month: null
+  };
+  total: number = 20;
+  monthList: any[] = [];
+  yearList: any[] = [];
+
+  constructor(private router: Router, private routeInfo: ActivatedRoute, private configService: ConfigService, private userService: UserService, public modalController: ModalController, private navCtrl: NavController,
+              private partyDuesApi: PartyDuesApi, private dictionaryApi: DictionaryApi
+    , private alertModal: AlertModal) {
+  }
+
+  ngOnInit() {
+    this.routeInfo.queryParams.subscribe(params => {
+      this.searchParams.ssdzzdm = this.searchParams.ssdzzdm || this.userService.GetUser().dataDzzdm;
+      this.searchParams.month = new Date().getMonth() + 1;
+      this.searchParams.year = new Date().getFullYear();
+
+      this.getYearList();
+
+      this.getMonthList();
+
+      this.reload();
+    });
+  }
+
+  getList() {
+    this.partyDuesApi.getList(this.searchParams).subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.dataList = this.dataList.concat(data.item.list);
+        this.total = data.item.total;
+      }
+    });
+  }
+
+  getMonthList() {
+    for (let i = 1; i <= 12; i++) {
+      this.monthList.push(i);
+    }
+  }
+
+  getYearList() {
+    this.dictionaryApi.getDictionaryList('years').subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.yearList = data.item;
+      }
+    });
+  }
+
+  fetchYearLabel() {
+    if (this.searchParams.year && this.yearList.length > 0)
+      return this.yearList.filter(e => e.dickey === this.searchParams.year)[0]?.dicvalue;
+  }
+
+  fetchMonthLabel() {
+    if (this.searchParams.month && this.monthList.length > 0)
+      return this.monthList.filter(e => e === this.searchParams.month)[0];
+  }
+
+  reload() {
+    this.dataList = [];
+    this.searchParams.pageIndex = 1;
+    this.total = 20;
+    this.getList();
+  }
+
+  scroll(event) {
+    setTimeout(() => {
+      event.target.complete();
+      if (this.total > this.searchParams.pageIndex * this.searchParams.pageSize) {
+        this.searchParams.pageIndex += 1;
+        this.getList();
+      }
+    }, 500);
+  }
+
+  yearChange(e) {
+    this.reload();
+  }
+
+  monthChange(e) {
+    this.reload();
+  }
+
+  searchChange(event) {
+    this.searchParams.xm = event.detail.value;
+    this.reload();
+  }
+
+  add() {
+    this.router.navigate(['./edit'], {relativeTo: this.routeInfo, queryParams: {random: Math.random()}});
+  }
+
+  delete(id) {
+    const handler = () => {
+      this.alertModal.loading("正在删除...").then((loading) => {
+        this.partyDuesApi.deleteDetail(id).subscribe((fdata: RequsetData) => {
+          loading.dismiss();
+
+          if (fdata.success) {
+            this.reload();
+          }
+          this.alertModal.alert(fdata.msg);
+        }, () => {
+          loading.dismiss();
+        });
+      });
+    };
+
+    this.alertModal.confirm("确认删除?", handler);
+  }
+
+}

+ 51 - 0
parth5/parth5/src/app/views/pages/partyuser/party-dues/selectuser/selectuser.component.html

@@ -0,0 +1,51 @@
+<ion-header>
+  <ion-toolbar color="danger">
+    <ion-title>
+      人员选择
+    </ion-title>
+    <!--<ion-buttons slot="end">
+      <ion-button (click)="dismiss()">
+        取消
+      </ion-button>
+      <ion-button (click)="select()">
+        选择
+      </ion-button>
+    </ion-buttons>-->
+  </ion-toolbar>
+</ion-header>
+<ion-searchbar #searchBox showCancelButton="never" placeholder="输入姓名查询" id="search-box"
+               (input)="search(searchBox.value)"  (ionClear)="search('')" mode="ios"></ion-searchbar>
+<ion-content>
+  <ion-list class="user-list">
+    <ion-radio-group value="biff">
+      <ion-item *ngFor="let us of userList;" (click)="us.checked=!us.checked">
+        <ion-col size="1" *ngIf="!isSingle">
+          <ion-checkbox color="danger" [(ngModel)]="us.checked" (click)="us.checked=!us.checked"></ion-checkbox>
+        </ion-col>
+        <ion-col size="1" *ngIf="isSingle">
+          <ion-radio color="danger" (click)="check(us)"></ion-radio>
+        </ion-col>
+        <ion-col size="3">
+          <ion-text>{{us.USERNAME}}</ion-text>
+        </ion-col>
+        <ion-col>
+          <ion-text>{{us.DZZMC}}</ion-text>
+        </ion-col>
+      </ion-item>
+      <ion-item *ngIf="userList.length==0" style="text-align: center;">
+        <ion-label><p>暂无数据</p></ion-label>
+      </ion-item>
+    </ion-radio-group>
+  </ion-list>
+  <ion-infinite-scroll threshold="100px" (ionInfinite)="scrollData($event)">
+    <ion-infinite-scroll-content
+      loadingSpinner="bubbles"
+      loadingText="{{loadingText}}">
+    </ion-infinite-scroll-content>
+  </ion-infinite-scroll>
+</ion-content>
+<ion-toolbar class="toolbar-center" style="margin-bottom: 40px;">
+  <ion-button color="light" (click)="dismiss()" mode="ios" style="margin-right: 15px;width: 100px;">关闭</ion-button>
+  <ion-button color="danger" (click)="select()" mode="ios" style="margin-left: 15px;width: 100px;">选择</ion-button>
+</ion-toolbar>
+

+ 0 - 0
parth5/parth5/src/app/views/pages/partyuser/party-dues/selectuser/selectuser.component.scss


+ 103 - 0
parth5/parth5/src/app/views/pages/partyuser/party-dues/selectuser/selectuser.component.ts

@@ -0,0 +1,103 @@
+import {Component, Input, OnInit, ViewChild} from '@angular/core';
+import {IonInfiniteScroll, ModalController, NavParams} from "@ionic/angular";
+import {ConfigService, RequsetData} from "../../../../../service/config.service";
+import {Observable, Subject} from "rxjs";
+import {debounceTime, distinctUntilChanged, switchMap} from "rxjs/operators";
+
+@Component({
+  selector: 'app-selectuser',
+  templateUrl: './selectuser.component.html',
+  styleUrls: ['./selectuser.component.scss'],
+})
+export class SelectuserComponent implements OnInit {
+  @ViewChild(IonInfiniteScroll, {static: true}) infiniteScroll: IonInfiniteScroll;
+  private searchTerms = new Subject<string>();
+  getUserUrl: string = '';
+  isSingle: false;
+  selectparam: any = {
+    pageIndex: 1,
+    pageSize: 10,
+    year: '',
+    month: '',
+    dzzdm: '',
+    removeUserIdList: '',
+    xm: ''
+  };
+  userList: any = [];
+  total: 0;
+  selectusers: any = [];
+  loadingText: string = '正在加载...';
+
+  constructor(navParams: NavParams, private configService: ConfigService, public modalController: ModalController) {
+    this.selectparam.pageIndex = navParams.get('pageIndex');
+    this.selectparam.pageSize = navParams.get('pageSize');
+    this.selectparam.year = navParams.get('year');
+    this.selectparam.month = navParams.get('month');
+    this.selectparam.dzzdm = navParams.get('dzzdm');
+    this.selectparam.removeUserIdList = navParams.get('removeUserIdList');
+    this.getUserUrl = navParams.get('getUserUrl') || this.getUserUrl;
+    this.loadUserList();
+  }
+
+  ngOnInit() {
+  }
+
+  loadUserList(): void {
+    this.configService.HttpGetRomote(this.getUserUrl, this.selectparam).subscribe((data: RequsetData) => {
+      if (data.success) {
+        if (data.item != null) {
+          this.userList = this.userList.concat(data.item.list);
+          this.total = data.item.total;
+        }
+      }
+    });
+  }
+
+  //关键字查询
+  search(term: string): void {
+    this.userList = [];
+    this.selectparam.xm = term;
+    this.loadUserList();
+  }
+
+  //下拉刷新
+  scrollData(event) {
+    setTimeout(() => {
+      event.target.complete();
+      if (this.userList.length < this.total) {
+        this.selectparam.pageIndex = this.selectparam.pageIndex + 1;
+        this.loadUserList();
+      } else {
+        this.loadingText = '暂无更多';
+      }
+    }, 200);
+  }
+
+  //关闭modal
+  dismiss() {
+    this.modalController.dismiss({
+      'dismissed': true
+    });
+  }
+
+  //选择(返回值:ryjbxxbs 人员基本信息标识,rybm 人员编码,xm 姓名,szdzbdm 所在党支部代码,szdzzmc 所在党支部名称)
+  select() {
+    this.selectusers = this.userList.filter(it => {
+      return it.checked == true
+    }).map(function (it) {
+      return it
+    });
+    this.modalController.dismiss({
+      'dismissed': true,
+      'rtnData': this.selectusers
+    });
+  }
+
+  check(us) {
+    this.userList.map(x => {
+      x.checked = false;
+    });
+    us.checked = true;
+  }
+}
+

parth5/parth5/src/app/views/pages/party/party-user/detail/democracy/democracy.component.html → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/democracy/democracy.component.html


parth5/parth5/src/app/views/pages/party/party-user/detail/democracy/democracy.component.scss → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/democracy/democracy.component.scss


parth5/parth5/src/app/views/pages/party/party-user/detail/democracy/democracy.component.ts → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/democracy/democracy.component.ts


parth5/parth5/src/app/views/pages/party/party-user/detail/detail.component.html → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/detail.component.html


parth5/parth5/src/app/views/pages/party/party-user/detail/detail.component.scss → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/detail.component.scss


parth5/parth5/src/app/views/pages/party/party-user/detail/detail.component.ts → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/detail.component.ts


parth5/parth5/src/app/views/pages/party/party-user/detail/partyhelp/partyhelp.component.html → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/partyhelp/partyhelp.component.html


parth5/parth5/src/app/views/pages/party/party-user/detail/partyhelp/partyhelp.component.scss → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/partyhelp/partyhelp.component.scss


parth5/parth5/src/app/views/pages/party/party-user/detail/partyhelp/partyhelp.component.ts → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/partyhelp/partyhelp.component.ts


parth5/parth5/src/app/views/pages/party/party-user/detail/punish/punish.component.html → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/punish/punish.component.html


parth5/parth5/src/app/views/pages/party/party-user/detail/punish/punish.component.scss → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/punish/punish.component.scss


parth5/parth5/src/app/views/pages/party/party-user/detail/punish/punish.component.ts → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/punish/punish.component.ts


parth5/parth5/src/app/views/pages/party/party-user/detail/reward/reward.component.html → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/reward/reward.component.html


parth5/parth5/src/app/views/pages/party/party-user/detail/reward/reward.component.scss → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/reward/reward.component.scss


parth5/parth5/src/app/views/pages/party/party-user/detail/reward/reward.component.ts → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/reward/reward.component.ts


parth5/parth5/src/app/views/pages/party/party-user/detail/train/train.component.html → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/train/train.component.html


parth5/parth5/src/app/views/pages/party/party-user/detail/train/train.component.scss → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/train/train.component.scss


parth5/parth5/src/app/views/pages/party/party-user/detail/train/train.component.ts → parth5/parth5/src/app/views/pages/partyuser/party-user/detail/train/train.component.ts


parth5/parth5/src/app/views/pages/party/party-user/party-user.component.html → parth5/parth5/src/app/views/pages/partyuser/party-user/party-user.component.html


+ 0 - 0
parth5/parth5/src/app/views/pages/partyuser/party-user/party-user.component.scss


parth5/parth5/src/app/views/pages/party/party-user/party-user.component.ts → parth5/parth5/src/app/views/pages/partyuser/party-user/party-user.component.ts


+ 96 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/detail/detail.component.html

@@ -0,0 +1,96 @@
+<ion-header class="header-theme2">
+  <ion-toolbar>
+    <ion-label class="title-center">宣传阵地信息详情</ion-label>
+    <ion-buttons slot="start">
+      <ion-back-button icon="ios-back2" mode="md"></ion-back-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+<ion-content>
+  <form class="form-table">
+    <ion-item>
+      <ion-label>阵地名称</ion-label>
+      <ion-text>{{dataModel.positionname}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>所属党组织</ion-label>
+      <ion-text>{{dataModel.partyname}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>阵地类别</ion-label>
+      <ion-text>{{dataModel.positiontypename}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>等级</ion-label>
+      <ion-text>{{dataModel.positionlevelname}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>编号</ion-label>
+      <ion-text>{{dataModel.positioncode}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>位置</ion-label>
+      <ion-text>{{dataModel.address}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>尺寸</ion-label>
+      <ion-text>{{dataModel.sizes}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>建设时间</ion-label>
+      <ion-text>{{dataModel.buildtime | date:'yyyy-MM-dd'}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>责任人</ion-label>
+      <ion-text>{{dataModel.headusername}}</ion-text>
+    </ion-item>
+    <!--<ion-item>
+      <ion-label>状态</ion-label>
+      <ion-text>{{dataModel.positionstatename}}</ion-text>
+    </ion-item>-->
+    <ion-item>
+      <ion-label>宣传标语</ion-label>
+      <ion-text>{{panelModel.TITLE}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>更新时间</ion-label>
+      <ion-text>{{panelModel.PANELTIME | date:'yyyy-MM-dd'}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>宣传备注</ion-label>
+      <ion-text>{{panelModel.REMARK}}</ion-text>
+    </ion-item>
+    <ion-item mode="md" [ngClass]="{'border-none': panelList.length>0}">
+      <ion-label>阵地图片</ion-label>
+      <ion-text style="color: #998989 !important;">{{panelList.length>0?(panelList[0].PANELTIME | date:'yyyy-MM-dd'):'无更新记录'}}</ion-text>
+      <ion-icon *ngIf="userInfo.userid==dataModel.createuserid" slot="end" (click)="addPanel()"  name="add-circle-outline" size="large" color="danger"></ion-icon>
+    </ion-item>
+    <ion-item mode="md" *ngIf="panelList.length>0">
+      <ion-label></ion-label>
+      <div *ngIf="panelList.length>0"  style="width: 70%">
+        <img src="{{webServerHost}}/appApi/home/showImg/{{panelList[0].PANELIMG}}"
+             onerror="this.src='assets/icon/nopic.png';this.classList.remove('item-img')"
+             (click)="showBigImage(panelList[0].PANELIMG)"
+             style="width: 100%;height: 100px;"/>
+      </div>
+    </ion-item>
+    <!--<ion-item style="&#45;&#45;inner-border-width: 0px 0px 0px 0px;">
+      <ion-label>图片</ion-label>
+    </ion-item>
+    <app-imglist [(imgOption)]="imgOption"></app-imglist>-->
+  </form>
+  <!--<ion-item *ngIf="panelList.length>0" (click)="detailOpen=!detailOpen" class="item-detail" [ngClass]="detailOpen?'detail-open':'detail-close'" detail style="&#45;&#45;inner-border-width: 0px 0px 0px 0px;">
+    <div class="line-y"></div>
+    阵地更新记录
+  </ion-item>
+  <ion-list *ngIf="detailOpen">
+    <ion-item *ngFor="let item of panelList" [routerLink]="['../panelDetail']" [queryParams]="{panelId:item.PANELID,positionId:dataModel.publicitypositionid,type:2}" style="&#45;&#45;inner-border-width: 0px 0px 0px 0px;">
+      <img src="{{webServerHost}}/appApi/home/showImg/{{item.PANELIMG}}" class="item-img" onerror="this.src='assets/icon/nopic.png';this.classList.remove('item-img')"/>
+      <ion-label>
+        <h2>{{item.TITLE}}</h2>
+        <p>{{item.PARTYNAME}}</p>
+      </ion-label>
+    </ion-item>
+  </ion-list>-->
+</ion-content>
+<app-photo-swipe></app-photo-swipe>

+ 38 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/detail/detail.component.scss

@@ -0,0 +1,38 @@
+ion-content{
+  z-index: 11;
+}
+
+ion-item {
+  --inner-border-width: 0px 0px 1px 0px;
+  margin-right: 10px;
+}
+
+.detail-open::part(detail-icon){
+  transform: rotate(90deg);
+  transition: transform 0.2s ease-out;
+}
+
+.detail-close::part(detail-icon){
+  transform: rotate(0deg);
+  transition: transform 0.2s ease-out;
+}
+
+ion-item{
+  img{
+    margin-right: 10px;
+    border-radius: 8px;
+    width: 80px;
+    height: 50px;
+  }
+  .item-img{
+    object-fit: cover;
+  }
+}
+
+.item-detail{
+  margin: 0px !important;
+}
+
+.border-none{
+  --inner-border-width: 0px !important;
+}

+ 137 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/detail/detail.component.ts

@@ -0,0 +1,137 @@
+import {Component, OnInit, ViewChild} from '@angular/core';
+import {DatePipe} from "@angular/common";
+import {ActivatedRoute, Router} from "@angular/router";
+import {AlertController, LoadingController, ModalController} from "@ionic/angular";
+import {PhotoSwipeComponent} from "../../../../../comm/modal/photo-swipe/photo-swipe.component";
+import {ConfigService, RequsetData} from "../../../../../service/config.service";
+import {UserService} from "../../../../../service/user.service";
+import {PositionApi} from "../../../../../api/propagandawork/position";
+import {AlertModal} from "../../../../../comm/modal/alert";
+import {PanelApi} from "../../../../../api/propagandawork/position/panel";
+
+@Component({
+  selector: 'app-detail',
+  templateUrl: './detail.component.html',
+  styleUrls: ['./detail.component.scss'],
+})
+export class DetailComponent implements OnInit {
+
+  @ViewChild(PhotoSwipeComponent)
+  photoSwipe: PhotoSwipeComponent;
+
+  userInfo: any = {};
+  loading: any = null;
+  getDataUrl: string = '/appApi/publicity/getPositionInfoById';
+  getPanelListUrl: string = '/appApi/publicity/getPanelRecordList';
+  dataModel: any = {};
+  panelList: any = [];
+  detailOpen: boolean = false;
+  webServerHost: string = '';
+  panelModel: any = {};
+  imgOption: any = {
+    fileRefid: '',
+    fileName: '',
+    fileType: 4,
+    isMulti: true,
+    readonly: true
+  };
+
+  constructor(private datePipe: DatePipe, private router: Router, private routeInfo: ActivatedRoute, private configService: ConfigService, private userService: UserService
+    , public modalController: ModalController, private positionApi: PositionApi, private alertModal: AlertModal, private panelApi: PanelApi) {
+  }
+
+  ngOnInit() {
+    this.userInfo = this.userService.GetUser();
+    this.routeInfo.queryParams.subscribe(params => {
+      this.dataModel.id = params['id'];
+      this.imgOption.fileRefid = params['panelid'];
+      this.getData();
+    });
+
+    this.configService.GetConfig().subscribe((config) => {
+      this.webServerHost = config.webServerHost;
+    });
+  }
+
+  getData() {
+    this.positionApi.getData(
+      this.dataModel.id,
+      this.userService.GetUser().DZZDM
+    ).subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.dataModel = data.item;
+        this.getPanelList();
+      }
+    });
+  }
+
+  getPanelList() {
+    this.panelApi.getList({
+      pageIndex: 1, pageSize: 100, positionId: this.dataModel.publicitypositionid
+    }).subscribe((data: RequsetData) => {
+      if (data.success) {
+        if (data.item.list.length > 0) {
+          this.panelModel = data.item.list[0];
+          this.imgOption.fileRefid = this.panelModel.PANELID;
+          this.panelList = data.item.list;
+        }
+      }
+    });
+  }
+
+
+  back() {
+    this.router.navigate(['../position'], {relativeTo: this.routeInfo, queryParams: {random: Math.random()}});
+  }
+
+  addPanel() {
+    this.router.navigate(['../panelEdit'], {
+      relativeTo: this.routeInfo,
+      queryParams: {random: Math.random(), panelId: '', positionId: this.dataModel.publicitypositionid}
+    });
+  }
+
+  showBigImage(id) {
+    try {
+      var items = [];
+      let url = this.webServerHost + "/appApi/home/showImg/" + id;
+      let img = this.getImageWidth(url) || {width: 500, height: 300};
+      items.push({
+        src: url,
+        w: img.width || 500,
+        h: img.height || 300
+      })
+
+      this.photoSwipe.open(items, {
+        index: 0,
+        tapToClose: true
+      }, "pswp" + (Math.random() * 100000).toFixed(0).toString());
+    } catch (e) {
+      this.alertModal.alert("图片查看异常:" + e);
+    }
+  }
+
+  getImageWidth(url) {
+    let obj = {width: 0, height: 0}
+    try {
+      var img = new Image();
+      img.src = url;
+      // 如果图片被缓存,则直接返回缓存数据
+      if (img.complete) {
+        obj.width = img.width;
+        obj.height = img.height;
+        return obj
+      } else {
+        img.onload = function () {
+          obj.width = img.width;
+          obj.height = img.height;
+          return obj
+        }
+      }
+    } catch (e) {
+      this.alertModal.alert("图片高宽获取异常:" + e);
+      return obj;
+    }
+  }
+
+}

+ 101 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/edit/edit.component.html

@@ -0,0 +1,101 @@
+<ion-header class="header-theme2">
+  <ion-toolbar>
+    <ion-label class="title-center">编辑阵地信息</ion-label>
+    <ion-buttons slot="start">
+      <ion-back-button icon="ios-back2" text="" mode="md"></ion-back-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+<ion-content>
+  <form #dataForm="ngForm" class="form-table">
+    <ion-item detail mode="md">
+      <ion-label>所属党组织<span class="danger">*</span></ion-label>
+      <app-partyselect [(dzzdm)]="dataModel.partycode" [(dzzmc)]="dataModel.partyname"></app-partyselect>
+    </ion-item>
+    <ion-item mode="md">
+      <ion-label>阵地名称<span class="danger">*</span></ion-label>
+      <ion-input #positionname="ngModel" name="positionname" id="positionname" [(ngModel)]="dataModel.positionname"
+                 placeholder="请输入阵地名称" required></ion-input>
+    </ion-item>
+    <ion-item detail mode="md">
+      <ion-label>阵地类别<span class="danger">*</span></ion-label>
+      <ion-select #positiontype="ngModel" name="positiontype"
+                  id="positiontype"
+                  [(ngModel)]="dataModel.positiontype" okText="确定" cancelText="取消" placeholder="请选择"
+                  interface="action-sheet" required>
+        <ion-select-option *ngFor="let item of positionTypeList"
+                           [value]="item.dickey">{{item.dicvalue}}</ion-select-option>
+      </ion-select>
+    </ion-item>
+    <ion-item detail mode="md">
+      <ion-label>等级<span class="danger">*</span></ion-label>
+      <ion-select #positionlevel="ngModel" name="positionlevel"
+                  id="positionlevel"
+                  [(ngModel)]="dataModel.positionlevel" okText="确定" cancelText="取消" placeholder="请选择"
+                  interface="action-sheet" required>
+        <ion-select-option *ngFor="let item of positionLevelList"
+                           [value]="item.dickey">{{item.dicvalue}}</ion-select-option>
+      </ion-select>
+    </ion-item>
+    <ion-item mode="md">
+      <ion-label>建设时间<span class="danger">*</span></ion-label>
+      <ion-datetime #buildtime="ngModel" displayFormat="YYYY-MM-DD" pickerFormat="YYYY MM DD"
+                    name="buildtime"
+                    id="buildtime"
+                    cancelText="取消" doneText="选择" placeholder="请选择时间"
+                    [(ngModel)]="dataModel.buildtime"
+                    max="{{maxDate}}"
+                    required></ion-datetime>
+    </ion-item>
+    <ion-item mode="md">
+      <ion-label>编号</ion-label>
+      <ion-input #positioncode="ngModel" name="positioncode" id="positioncode" [(ngModel)]="dataModel.positioncode"
+                 placeholder="请输入编号"></ion-input>
+    </ion-item>
+    <ion-item mode="md">
+      <ion-label>位置</ion-label>
+      <ion-input #address="ngModel" name="address" id="address"
+                 [(ngModel)]="dataModel.address" placeholder="请输入位置"></ion-input>
+    </ion-item>
+    <ion-item mode="md">
+      <ion-label>尺寸</ion-label>
+      <ion-input #sizes="ngModel" name="sizes" id="sizes"
+                 [(ngModel)]="dataModel.sizes" placeholder="请输入尺寸"></ion-input>
+    </ion-item>
+    <ion-item mode="md">
+      <ion-label>责任人</ion-label>
+      <ion-input #headusername="ngModel" name="headusername" id="headusername" placeholder="请输入责任人"
+                 [(ngModel)]="dataModel.headusername"></ion-input>
+    </ion-item>
+    <ion-item mode="md">
+      <ion-label>阵地更新记录</ion-label>
+      <ion-icon slot="end" (click)="editPanel(null)" name="add-circle-outline" size="large" color="danger"></ion-icon>
+    </ion-item>
+    <ion-list>
+      <ion-item-sliding *ngFor="let item of panelList">
+        <ion-item (click)="editPanel(item)" detail>
+          <div class="item-img">
+            <app-bimage [(fileid)]="item.panelimg"></app-bimage>
+          </div>
+          <ion-label>
+            <h2>{{item.title}}</h2>
+            <p>{{item.paneltime | date:'yyyy-MM-dd'}}</p>
+          </ion-label>
+        </ion-item>
+
+        <ion-item-options side="end">
+          <ion-item-option (click)="delete(item.panelid)">删除</ion-item-option>
+        </ion-item-options>
+      </ion-item-sliding>
+    </ion-list>
+
+    <div class="footer-btn">
+      <ion-button slot="end" color="danger" mode="ios"
+                  (click)="save()" [disabled]="!dataForm.form.valid">
+        提交
+      </ion-button>
+    </div>
+  </form>
+</ion-content>
+<app-photo-swipe></app-photo-swipe>
+

+ 31 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/edit/edit.component.scss

@@ -0,0 +1,31 @@
+ion-content{
+  z-index: 11;
+}
+
+ion-select::part(icon) {
+  display: none;
+}
+
+app-partyselect{
+  width: 75%;
+}
+
+.detail-open::part(detail-icon){
+  transform: rotate(90deg);
+  transition: transform 0.2s ease-out;
+}
+
+.detail-close::part(detail-icon){
+  transform: rotate(0deg);
+  transition: transform 0.2s ease-out;
+}
+
+.item-img{
+  width: 80px;
+  height: 50px;
+  padding-right: 10px;
+}
+
+.item-detail{
+  margin: 0px !important;
+}

+ 208 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/edit/edit.component.ts

@@ -0,0 +1,208 @@
+import {Component, OnInit, ViewChild} from '@angular/core';
+import {DatePipe} from "@angular/common";
+import {ActivatedRoute, Router} from "@angular/router";
+import {ConfigService, RequsetData} from "../../../../../service/config.service";
+import {UserService} from "../../../../../service/user.service";
+import {AlertController, LoadingController, ModalController} from "@ionic/angular";
+import * as moment from 'moment';
+import {PhotoSwipeComponent} from "../../../../../comm/modal/photo-swipe/photo-swipe.component";
+import {PositionApi} from "../../../../../api/propagandawork/position";
+import {AlertModal} from "../../../../../comm/modal/alert";
+import {DictionaryApi} from "../../../../../api/system/dictionary";
+import {PanelApi} from "../../../../../api/propagandawork/position/panel";
+import {EditComponent as PanelEditComponent} from "../panel/edit/edit.component";
+
+@Component({
+  selector: 'app-edit',
+  templateUrl: './edit.component.html',
+  styleUrls: ['./edit.component.scss'],
+})
+export class EditComponent implements OnInit {
+
+  @ViewChild(PhotoSwipeComponent)
+  photoSwipe: PhotoSwipeComponent;
+
+  op: number = 0;
+  dataModel: any = {};
+  positionTypeList: any = [];
+  positionLevelList: any = [];
+  positionStateList: any = [];
+  panelList: any = [];
+  detailOpen: boolean = false;
+  webServerHost: string = '';
+  maxDate: any = moment(new Date()).format("YYYY-MM-DD");
+  panelCycleList: any = [];
+
+  constructor(private datePipe: DatePipe, private router: Router, private routeInfo: ActivatedRoute, private configService: ConfigService, private userService: UserService, public alertController: AlertController,
+              public modalController: ModalController, public loadingController: LoadingController
+    , private positionApi: PositionApi, private alertModal: AlertModal, private dictionaryApi: DictionaryApi, private panelApi: PanelApi) {
+  }
+
+  ngOnInit() {
+    this.routeInfo.queryParams.subscribe(params => {
+      this.dataModel.id = params['id'];
+      this.op = parseInt(params['op']);
+      this.getDictionList();
+      this.getData();
+    });
+
+    this.configService.GetConfig().subscribe((config) => {
+      this.webServerHost = config.webServerHost;
+    });
+  }
+
+  getData() {
+    this.positionApi.getData(this.dataModel.id, this.userService.GetUser().DZZDM).subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.dataModel = data.item;
+        this.getPanelList();
+      }
+    });
+  }
+
+  getDictionList() {
+    this.dictionaryApi.getDictionaryList('positionType').subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.positionTypeList = data.item;
+      }
+    });
+    this.dictionaryApi.getDictionaryList('psiLevel').subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.positionLevelList = data.item;
+      }
+    });
+    this.dictionaryApi.getDictionaryList('positionState').subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.positionStateList = data.item;
+      }
+    });
+    this.dictionaryApi.getDictionaryList('panelCycle').subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.panelCycleList = data.item;
+      }
+    });
+  }
+
+  getPanelList() {
+    this.panelApi.getList({
+      pageIndex: 1, pageSize: 100, positionId: this.dataModel.publicitypositionid
+    }).subscribe((data: RequsetData) => {
+      if (data.success) {
+        data.item.list.forEach(e => {
+          this.panelList.push({
+            panelid: e.PANELID,
+            title: e.TITLE,
+            paneltime: e.PANELTIME,
+            panelimg: e.PANELIMG,
+            remark: e.REMARK
+          });
+        });
+      }
+    });
+  }
+
+  save() {
+    this.alertModal.loading("提交中...").then((loading) => {
+      this.positionApi.save(this.dataModel, this.panelList).subscribe((data: RequsetData) => {
+        loading.dismiss();
+        if (data.success) {
+          this.back();
+        }
+        this.alertModal.alert(data.msg);
+      }, () => {
+        loading.dismiss();
+      });
+    });
+  }
+
+  back() {
+    this.router.navigate(['../../position'], {relativeTo: this.routeInfo, queryParams: {random: Math.random()}});
+  }
+
+  editPanel(panel) {
+    this.panelModal(panel);
+  }
+
+  delete(id) {
+    /*this.alertModal.confirm("确认删除?", () => {
+      this.alertModal.loading("正在删除").then((loading) => {
+        this.positionApi.deletePlan(id).subscribe((fdata: RequsetData) => {
+          loading.dismiss();
+          if (fdata.success) {
+            this.getPanelList();
+          }
+          this.alertModal.alert(fdata.msg);
+        }, () => {
+          loading.dismiss();
+        });
+      });
+    });*/
+
+    this.panelList = this.panelList.filter(e => e.panelid != id);
+  }
+
+  async panelModal(panel) {
+    const modal = await this.modalController.create({
+      component: PanelEditComponent,
+      componentProps: {
+        panel: panel
+      }
+    });
+
+    await modal.present();
+
+    const {data} = await modal.onWillDismiss();
+    if (data.rtnData != null) {
+      let panel = this.panelList.filter(e => e.panelid === data.rtnData.panelid)[0];
+      if (panel == null) {
+        this.panelList.push(data.rtnData);
+      } else {
+        panel = data.rtnData;
+      }
+    }
+  }
+
+  showBigImage(id) {
+    try {
+      var items = [];
+      let url = this.webServerHost + "/appApi/home/showImg/" + id;
+      let img = this.getImageWidth(url) || {width: 500, height: 300};
+      items.push({
+        src: url,
+        w: img.width || 500,
+        h: img.height || 300
+      })
+
+      this.photoSwipe.open(items, {
+        index: 0,
+        tapToClose: true
+      }, "pswp" + (Math.random() * 100000).toFixed(0).toString());
+    } catch (e) {
+      this.alertModal.alert("图片查看异常:" + e);
+    }
+  }
+
+  getImageWidth(url) {
+    let obj = {width: 0, height: 0}
+    try {
+      var img = new Image();
+      img.src = url;
+      // 如果图片被缓存,则直接返回缓存数据
+      if (img.complete) {
+        obj.width = img.width;
+        obj.height = img.height;
+        return obj
+      } else {
+        img.onload = function () {
+          obj.width = img.width;
+          obj.height = img.height;
+          return obj
+        }
+      }
+    } catch (e) {
+      this.alertModal.alert("图片高宽获取异常:" + e);
+      return obj;
+    }
+  }
+
+}

+ 55 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/panel/detail/detail.component.html

@@ -0,0 +1,55 @@
+<ion-header class="header-theme2">
+  <ion-toolbar>
+    <ion-label class="title-center">阵地信息</ion-label>
+    <ion-buttons slot="start">
+      <ion-back-button icon="ios-back2" mode="md"></ion-back-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+<ion-content>
+  <form class="form-table">
+    <ion-item>
+      <ion-label>阵地名称</ion-label>
+      <ion-text>{{positionModel.positionname}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>所属党组织</ion-label>
+      <ion-text>{{positionModel.partyname}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>宣传标语</ion-label>
+      <ion-text>{{dataModel.title}}</ion-text>
+    </ion-item>
+    <ion-item>
+      <ion-label>更新时间</ion-label>
+      <ion-text>{{dataModel.paneltime | date:'yyyy-MM-dd'}}</ion-text>
+    </ion-item>
+    <!--<ion-item>
+      <ion-label>更新周期</ion-label>
+      <ion-text *ngIf="panelCycleList.length>0">
+        {{(panelCycleList | myfilter:'dickey':dataModel.panelcycle)[0].dicvalue }}
+      </ion-text>
+    </ion-item>-->
+    <ion-item>
+      <ion-label>宣传备注</ion-label>
+      <ion-text>{{dataModel.remark}}</ion-text>
+    </ion-item>
+    <ion-item style="--inner-border-width: 0px 0px 0px 0px;">
+      <ion-label>图片</ion-label>
+    </ion-item>
+    <app-imglist [(imgOption)]="imgOption"></app-imglist>
+  </form>
+  <ion-item *ngIf="panelList.length>0" (click)="detailOpen=!detailOpen" class="item-detail" [ngClass]="detailOpen?'detail-open':'detail-close'" detail>
+    <div class="line-y"></div>
+    阵地更新记录
+  </ion-item>
+  <ion-list *ngIf="detailOpen">
+    <ion-item *ngFor="let item of panelList">
+      <img src="{{webServerHost}}/appApi/home/showImg/{{item.PANELIMG}}" class="item-img" onerror="this.src='assets/icon/nopic.png';this.classList.remove('item-img')"/>
+      <ion-label>
+        <h2>{{item.TITLE}}</h2>
+        <p>{{item.PARTYNAME}}</p>
+      </ion-label>
+    </ion-item>
+  </ion-list>
+</ion-content>

+ 34 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/panel/detail/detail.component.scss

@@ -0,0 +1,34 @@
+ion-content{
+  z-index: 11;
+}
+
+ion-item {
+  --inner-border-width: 0px 0px 1px 0px;
+  margin-right: 10px;
+}
+
+.detail-open::part(detail-icon){
+  transform: rotate(90deg);
+  transition: transform 0.2s ease-out;
+}
+
+.detail-close::part(detail-icon){
+  transform: rotate(0deg);
+  transition: transform 0.2s ease-out;
+}
+
+ion-item{
+  img{
+    margin-right: 10px;
+    border-radius: 8px;
+    width: 80px;
+    height: 50px;
+  }
+  .item-img{
+    object-fit: cover;
+  }
+}
+
+.item-detail{
+  margin: 0px !important;
+}

+ 103 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/panel/detail/detail.component.ts

@@ -0,0 +1,103 @@
+import {Component, OnInit} from '@angular/core';
+import {ActivatedRoute, Router} from "@angular/router";
+import {ModalController, NavController} from "@ionic/angular";
+import {ConfigService, RequsetData} from "../../../../../../service/config.service";
+import {UserService} from "../../../../../../service/user.service";
+import {PanelApi} from "../../../../../../api/propagandawork/position/panel";
+import {AlertModal} from "../../../../../../comm/modal/alert";
+import {DictionaryApi} from "../../../../../../api/system/dictionary";
+import {PositionApi} from "../../../../../../api/propagandawork/position";
+
+@Component({
+  selector: 'app-detail',
+  templateUrl: './detail.component.html',
+  styleUrls: ['./detail.component.scss'],
+})
+export class DetailComponent implements OnInit {
+
+  panelCycleList: any = [];
+  dataModel: any = {};
+  positionModel: any = {};
+  imgOption: any = {
+    fileRefid: '',
+    fileName: '',
+    fileType: 4,
+    isMulti: false,
+    readonly: true
+  };
+  imgList: any = [];
+  panelList: any = [];
+  detailOpen: boolean = false;
+  webServerHost: string = '';
+  type: number = 0;
+
+  constructor(private router: Router, private routeInfo: ActivatedRoute, private configService: ConfigService, private userService: UserService, public modalController: ModalController, private navCtrl: NavController
+    , private panelApi: PanelApi, private alertModal: AlertModal, private dictionaryApi: DictionaryApi, private positionApi: PositionApi) {
+  }
+
+  ngOnInit() {
+    this.routeInfo.queryParams.subscribe(params => {
+      this.dataModel.publicitypositionid = params['positionId'];
+      this.dataModel.panelid = params['panelId'];
+      this.type = params['type'];
+      this.imgOption.fileRefid = this.dataModel.panelid;
+      if (this.dataModel.publicitypositionid) {
+        this.getPosition();
+        if (this.type != 2) {
+          this.getPanelList();
+        }
+      }
+      this.getDictionList();
+
+    });
+
+    this.configService.GetConfig().subscribe((config) => {
+      this.webServerHost = config.webServerHost;
+    });
+  }
+
+  getData() {
+    this.panelApi.getData(this.dataModel.panelid,
+      this.dataModel.publicitypositionid
+    ).subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.dataModel = data.item;
+
+        this.imgOption.fileRefid = this.dataModel.panelid;
+        this.imgOption.fileName = this.dataModel.title;
+      }
+    });
+  }
+
+  getPosition() {
+    this.positionApi.getData(this.dataModel.publicitypositionid, '').subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.positionModel = data.item;
+        this.getData();
+      }
+    });
+  }
+
+  getDictionList() {
+    this.dictionaryApi.getDictionaryList('panelCycle').subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.panelCycleList = data.item;
+      }
+    });
+  }
+
+  getPanelList() {
+    this.panelApi.getList({
+      pageIndex: 1, pageSize: 100, positionId: this.dataModel.publicitypositionid
+    }).subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.panelList = data.item.list.filter(it => it.PANELID != this.dataModel.panelid);
+      }
+    });
+  }
+
+  back() {
+    this.router.navigate(['../panel'], {relativeTo: this.routeInfo});
+  }
+
+}

+ 43 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/panel/edit/edit.component.html

@@ -0,0 +1,43 @@
+<ion-header class="header-theme2">
+  <ion-toolbar>
+    <ion-label class="title-center">编辑阵地图片信息</ion-label>
+    <ion-buttons slot="start">
+      <ion-back-button icon="ios-back2" mode="md"></ion-back-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+<ion-content>
+  <form #dataForm="ngForm" class="form-table">
+    <ion-item mode="md">
+      <ion-label>宣传标语</ion-label>
+      <ion-input #title="ngModel" readonly="false" placeholder="请填写主题" name="title"
+                 [(ngModel)]="dataModel.title" required></ion-input>
+    </ion-item>
+    <ion-item detail mode="md">
+      <ion-label>更新时间</ion-label>
+      <ion-datetime #paneltime="ngModel" displayFormat="YYYY-MM-DD" pickerFormat="YYYY MM DD"
+                    name="paneltime"
+                    id="paneltime"
+                    cancelText="取消" doneText="选择" placeholder="请输入时间"
+                    [(ngModel)]="dataModel.paneltime"
+                    max="{{maxDate}}"
+                    required></ion-datetime>
+    </ion-item>
+    <ion-item mode="md">
+      <ion-label>宣传备注</ion-label>
+      <ion-textarea readonly="false" placeholder="请填写宣传备注" name="remark"
+                    [(ngModel)]="dataModel.remark"></ion-textarea>
+    </ion-item>
+    <ion-item mode="md">
+      <ion-label>上传图片</ion-label>
+    </ion-item>
+    <app-imglist [(imgOption)]="imgOption" [(imgList)]="imgList"></app-imglist>
+    <ion-label  style="color: red;">备注:以上可上传照片,此项为选传项,仅作资料留存,不作为必传项点,也不得作为检查、考核项点。</ion-label>
+    <div class="footer-btn">
+      <ion-button color="light" (click)="back()" mode="ios">关闭</ion-button>
+      <ion-button slot="end" color="danger" mode="ios" (click)="save()"
+                  [disabled]="!dataForm.form.valid">保存
+      </ion-button>
+    </div>
+  </form>
+</ion-content>

+ 38 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/panel/edit/edit.component.scss

@@ -0,0 +1,38 @@
+ion-content{
+  z-index: 11;
+}
+
+ion-select::part(icon) {
+  display: none;
+}
+
+app-partyselect{
+  width: 75%;
+}
+
+.detail-open::part(detail-icon){
+  transform: rotate(90deg);
+  transition: transform 0.2s ease-out;
+}
+
+.detail-close::part(detail-icon){
+  transform: rotate(0deg);
+  transition: transform 0.2s ease-out;
+}
+
+ion-item{
+  img{
+    margin-right: 10px;
+    border-radius: 8px;
+    width: 80px;
+    height: 50px;
+  }
+  .item-img{
+    object-fit: cover;
+  }
+}
+
+.item-detail{
+  margin: 0px !important;
+}
+

+ 52 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/panel/edit/edit.component.ts

@@ -0,0 +1,52 @@
+import {Component, OnInit} from '@angular/core';
+import {ActivatedRoute, Router} from "@angular/router";
+import {ModalController, NavParams} from "@ionic/angular";
+import * as moment from 'moment';
+import * as uuid from 'uuid';
+
+@Component({
+  selector: 'app-edit',
+  templateUrl: './edit.component.html',
+  styleUrls: ['./edit.component.scss'],
+})
+export class EditComponent implements OnInit {
+
+  dataModel: any = {};
+  imgOption: any = {
+    fileRefid: '',
+    fileName: '',
+    fileType: 4,
+    isMulti: true,
+    readonly: false
+  };
+  imgList = [];
+  panelList: any = [];
+  webServerHost: string = '';
+  maxDate: any = moment(new Date()).format("YYYY-MM-DD");
+
+  constructor(private router: Router, private routeInfo: ActivatedRoute,  public modalController: ModalController,navParams: NavParams) {
+    this.dataModel = navParams.get('panel') || {panelid:uuid.v4()};
+    this.imgOption.fileRefid = this.dataModel.panelid;
+  }
+
+  ngOnInit() {
+
+  }
+
+  save() {
+    if (this.imgList.length > 0) {
+      this.dataModel.panelimg = this.imgList[0].fileid;
+    }
+
+    this.modalController.dismiss({
+      'dismissed': true,
+      'rtnData': this.dataModel
+    });
+  }
+
+  back() {
+    this.modalController.dismiss({
+      'dismissed': true
+    });
+  }
+}

+ 52 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/position.component.html

@@ -0,0 +1,52 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-label>阵地管理</ion-label>
+    <ion-buttons slot="start">
+      <ion-back-button icon="ios-back" mode="md"></ion-back-button>
+    </ion-buttons>
+    <ion-searchbar slot="end" mode="ios" enterkeyhint="search" placeholder="搜索阵地名称" showCancelButton="never"
+                   (ionChange)="searchChange($event)"></ion-searchbar>
+  </ion-toolbar>
+  <app-partysearch [(dzzdm)]="searchParams.dzzdm" (dzzdmChange)="reload()"></app-partysearch>
+  <ion-item class="item-filter">
+    <div slot="end" (click)="search()">
+      <span>条件筛选</span>
+      <ion-icon name="dj-search"></ion-icon>
+    </div>
+  </ion-item>
+</ion-header>
+<ion-content>
+  <ion-list>
+    <ion-item-sliding *ngFor="let item of dataList">
+      <ion-item detail [routerLink]="['./edit']" [queryParams]="{id: item.PUBLICITYPOSITIONID,op:1,panelid:item.PANELID}">
+        <div class="item-img">
+          <app-bimage [(fileid)]="item.PANELIMG"></app-bimage>
+        </div>
+        <ion-label>
+          <h2>{{item.POSITIONNAME}}<span class="dues-month">{{item.PANELTIME!=null?(item.PANELTIME | date:'yyyy-MM-dd'):'无更新记录'}}</span></h2>
+          <p>{{item.PARTYNAME}}</p>
+        </ion-label>
+      </ion-item>
+
+      <ion-item-options side="end">
+        <ion-item-option (click)="delete(item.PUBLICITYPOSITIONID)">删除</ion-item-option>
+      </ion-item-options>
+    </ion-item-sliding>
+  </ion-list>
+  <ion-infinite-scroll threshold="100px" (ionInfinite)="scroll($event)">
+    <ion-infinite-scroll-content
+      loadingSpinner="bubbles"
+      loadingText="{{total>searchParams.pageIndex*searchParams.pageSize?'正在加载...':'暂无更多'}}">
+    </ion-infinite-scroll-content>
+  </ion-infinite-scroll>
+  <ion-fab vertical="bottom" horizontal="center" slot="fixed" class="fab-add">
+    <ion-fab-button>
+      <ion-text class="btn-add" (click)="add()">
+        <img src="assets/icon/btnadd.png" style="width: 30px;height:30px;">
+        <span class="btn-add-text">新增</span>
+      </ion-text>
+    </ion-fab-button>
+  </ion-fab>
+</ion-content>
+
+

+ 42 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/position.component.scss

@@ -0,0 +1,42 @@
+ion-label {
+  margin: 3px !important;
+  padding: 0px;
+  white-space: normal !important;
+}
+.dues-month{
+  color: #998989;
+  font-size: 12px;
+  border-radius: 4px;
+  background-color: #F3F3F3;
+  padding: 0px 4px;
+  margin-left: 20px;
+}
+
+.dues-money{
+  color: #DE4F3F;
+}
+
+ion-select {
+  color: #5E4545;
+
+  --placeholder-color: #5E4545;
+
+  --placeholder-opacity: 1;
+}
+ion-select::part(icon) {
+  color: #5E4545;
+  opacity: 1;
+}
+ion-header {
+  ion-item {
+    --inner-border-width:  0px;
+    --border-width:0px;
+  }
+}
+
+.item-img{
+  width: 80px;
+  height: 50px;
+  padding-right: 10px;
+}
+

+ 171 - 0
parth5/parth5/src/app/views/pages/propagandawork/position/position.component.ts

@@ -0,0 +1,171 @@
+import {Component, OnInit, ViewChild} from '@angular/core';
+import {AlertController, IonInfiniteScroll, LoadingController, ModalController, NavController} from "@ionic/angular";
+import {ActivatedRoute, Router} from "@angular/router";
+import {ConfigService, RequsetData} from "../../../../service/config.service";
+import {UserService} from "../../../../service/user.service";
+import {SearchComponent} from "../../../../comm/modal/search/search.component";
+import {PositionApi, reqParams} from "../../../../api/propagandawork/position";
+import {AlertModal} from "../../../../comm/modal/alert";
+
+@Component({
+  selector: 'app-position',
+  templateUrl: './position.component.html',
+  styleUrls: ['./position.component.scss'],
+})
+export class PositionComponent implements OnInit {
+
+  @ViewChild(IonInfiniteScroll, {static: true}) infiniteScroll: IonInfiniteScroll;
+
+  webServerHost: string = '';
+  userInfo: any = {};
+  dataList: any[] = [];
+  searchParams: reqParams = {
+    pageIndex: 1,
+    pageSize: 15,
+    dzzdm: '',
+    positionName: '',
+    positionType: null,
+    positionLevel: null,
+    positionState: null,
+    startDate: '',
+    endDate: ''
+  };
+  total: number = 15;
+  fieldList: any[] = [{label: '阵地名称', name: 'positionName', type: 'text', value: '', placeholder: '输入阵地名称'},
+    {
+      label: '建设日期',
+      name: '',
+      type: 'group-datetime',
+      inputs: [{name: 'startDate', type: 'datetime', value: '', placeholder: '开始日期'}, {
+        name: 'endDate',
+        type: 'datetime',
+        value: '',
+        placeholder: '结束日期'
+      }]
+    },
+    {
+      label: '阵地类别',
+      name: 'positionType',
+      type: 'select',
+      value: '',
+      dicParams: {
+        getUrl: 'getDictionaryListByDicTypeKey',
+        dicTypeKey: 'positionType',
+        textField: 'dicvalue',
+        valueField: 'dickey',
+        ismulti: true
+      }
+    },
+    {
+      label: '等级',
+      name: 'positionLevel',
+      type: 'select',
+      value: '',
+      dicParams: {
+        getUrl: 'getDictionaryListByDicTypeKey',
+        dicTypeKey: 'psiLevel',
+        textField: 'dicvalue',
+        valueField: 'dickey',
+        ismulti: true
+      }
+    }
+  ];
+
+  constructor(private router: Router, private routeInfo: ActivatedRoute, private configService: ConfigService, private userService: UserService, public modalController: ModalController, private navCtrl: NavController
+    , private positionApi: PositionApi, private alertModal: AlertModal) {
+  }
+
+  ngOnInit() {
+    this.userInfo = this.userService.GetUser();
+    this.routeInfo.queryParams.subscribe(params => {
+      this.searchParams.dzzdm = this.searchParams.dzzdm || this.userService.GetUser().dataDzzdm;
+      this.reload();
+    });
+    this.configService.GetConfig().subscribe((config) => {
+      this.webServerHost = config.webServerHost;
+    });
+  }
+
+  getList() {
+    this.positionApi.getList(this.searchParams).subscribe((data: RequsetData) => {
+      if (data.success) {
+        this.dataList = this.dataList.concat(data.item.list);
+        this.total = data.item.total;
+      }
+    });
+  }
+
+  reload() {
+    this.dataList = [];
+    this.searchParams.pageIndex = 1;
+    this.total = 15;
+    this.getList();
+  }
+
+  scroll(event) {
+    setTimeout(() => {
+      event.target.complete();
+      if (this.total > this.searchParams.pageIndex * this.searchParams.pageSize) {
+        this.searchParams.pageIndex += 1;
+        this.getList();
+      }
+    }, 500);
+  }
+
+  yearChange(e) {
+    this.reload();
+  }
+
+  searchChange(event) {
+    this.fieldList[0].value = event.detail.value;
+    this.searchParams.positionName = event.detail.value;
+    this.reload();
+  }
+
+  async search() {
+    const modal = await this.modalController.create({
+      component: SearchComponent,
+      componentProps: {
+        'fieldList': this.fieldList
+      },
+      cssClass: 'search-modal'
+    });
+
+    await modal.present();
+
+    const {data} = await modal.onWillDismiss();
+    if (data && data.success) {
+      this.searchParams.positionName = data.params.positionName;
+      this.searchParams.startDate = data.params.startDate;
+      this.searchParams.endDate = data.params.endDate;
+      this.searchParams.positionType = data.params.positionType;
+      this.searchParams.positionLevel = data.params.positionLevel;
+      this.reload();
+    }
+  }
+
+  add() {
+    this.router.navigate(['./edit'], {
+      relativeTo: this.routeInfo,
+      queryParams: {random: Math.random(), op: 0}
+    });
+  }
+
+
+  delete(id) {
+    this.alertModal.confirm("确认删除?", () => {
+      this.alertModal.loading("正在删除").then((loading) => {
+        this.positionApi.delete(id).subscribe((fdata: RequsetData) => {
+          loading.dismiss();
+          if (fdata.success) {
+            this.reload();
+          }
+          this.alertModal.alert(fdata.msg);
+        }, () => {
+          loading.dismiss();
+        });
+      });
+    });
+  }
+
+}

+ 5 - 1
parth5/parth5/src/app/views/tapp/tab-main/tab-main.module.ts

@@ -14,6 +14,8 @@ import {ImglistComponent} from "../../../comm/modal/imglist/imglist.component";
 import {PhotoshowComponent} from "../../../comm/modal/photoshow/photoshow.component";
 import {PhotoSwipeComponent} from "../../../comm/modal/photo-swipe/photo-swipe.component";
 import {MyfilterPipe} from "../../../comm/pipes/myfilter.pipe";
+import {SelectuserComponent} from "../../pages/partyuser/party-dues/selectuser/selectuser.component";
+import {BimageComponent} from "../../../comm/modal/bimage/bimage.component";
 
 const pubComponents = [
   PartysearchComponent,
@@ -24,7 +26,9 @@ const pubComponents = [
   ImglistComponent,
   PhotoshowComponent,
   PhotoSwipeComponent,
-  MyfilterPipe
+  MyfilterPipe,
+  SelectuserComponent,
+  BimageComponent
 ];
 
 /*function getRoutesComponent(routes: Routes) {

+ 5 - 1
parth5/parth5/src/app/views/tapp/tab-main/tab-main.route.ts

@@ -3,6 +3,8 @@ import {TabMainPage} from "./tab-main.page";
 import partyInfoRoutes from "../../../routes/partyInfo";
 import partyUserRoutes from "../../../routes/partyUser";
 import shykRoutes from "../../../routes/shyk";
+import partyDuesRoutes from "../../../routes/partyDues";
+import positionRoutes from "../../../routes/propagandawork/position";
 
 export const routes: Routes = [
   {
@@ -11,5 +13,7 @@ export const routes: Routes = [
   },
   ...partyInfoRoutes,
   ...partyUserRoutes,
-  ...shykRoutes
+  ...shykRoutes,
+  ...partyDuesRoutes,
+  ...positionRoutes
 ];

+ 9 - 7
src/main/java/com/ghsc/partybuild/controller/app/AppPartyController.java

@@ -77,14 +77,14 @@ public class AppPartyController {
                                                                            @RequestParam(required = false) List<String> removeRybmList, @RequestParam(required = false) List<String> ryztList,
                                                                            @RequestParam(required = false) Integer age_begin, @RequestParam(required = false) Integer age_end, @RequestParam(required = false) Integer sfsldry,
                                                                            @RequestParam(required = false) String xb, @RequestParam(required = false) String xl, @RequestParam(required = false) String partyGroupId,
-                                                                           @RequestParam(required = false) String sqrdrq_begin, @RequestParam(required = false) String sqrdrq_end,@RequestParam(required = false) Integer isStudent) {
+                                                                           @RequestParam(required = false) String sqrdrq_begin, @RequestParam(required = false) String sqrdrq_end, @RequestParam(required = false) Integer isStudent) {
 
         sqrdrq_begin = dateUtils.strFormat_short(sqrdrq_begin);
         sqrdrq_end = dateUtils.strFormat_short(sqrdrq_end);
 
         RequsetData<PageInfo<HashMap<String, Object>>> res = new RequsetData<>();
         res.setItem(partyUserService.getPartyUserList(pageIndex, pageSize, xb, dzzdm, null, xm, null, null, sqrdrq_begin, sqrdrq_end, null, null,
-                null, ryztList, null, szdzbdm, removeRybmList, rybmList, null, null, null, xl, age_begin, age_end, sfsldry, null, null, null, userId, partyGroupId, null,isStudent,null));
+                null, ryztList, null, szdzbdm, removeRybmList, rybmList, null, null, null, xl, age_begin, age_end, sfsldry, null, null, null, userId, partyGroupId, null, isStudent, null));
 
         return res;
     }
@@ -264,6 +264,7 @@ public class AppPartyController {
 
     /**
      * 获取并初始化党员缴费基数(学生党员默认为0.2,一般不会去设置,需系统自动初始化,逻辑为:用户登录时进行检测,若未配置,则由系统初始化)
+     *
      * @param usercode
      * @param year
      * @return
@@ -429,13 +430,14 @@ public class AppPartyController {
         return res;
     }
 
-    @ResponseBody
-    @GetMapping("/deleteDuesById")
-    public RequsetData<Integer> deleteDuesById(@RequestParam("id") String id) {
-
+    @PostMapping("/deleteDuesById")
+    public RequsetData<Integer> deleteDuesById(@RequestBody Map<String, Object> reqMap) {
         RequsetData<Integer> result = new RequsetData<>();
 
-        int row = publicityService.deleteDuesById(id);
+        String id = reqMap.get("id").toString();
+        String userId = reqMap.get("userId").toString();
+
+        int row = publicityService.deleteDuesById(id, userId);
         result.setItem(row);
         if (row == 0) {
             result.setSuccess(false);

+ 5 - 1
src/main/java/com/ghsc/partybuild/controller/app/AppPublicityController.java

@@ -3,6 +3,7 @@ package com.ghsc.partybuild.controller.app;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ghsc.partybuild.vo.shyk.MeetingTopicJsonData;
 import com.github.pagehelper.PageInfo;
 import com.ghsc.partybuild.controller.jsonmodel.RequsetData;
 import com.ghsc.partybuild.model.*;
@@ -247,7 +248,10 @@ public class AppPublicityController {
             String userId = reqMap.get("userId").toString();
             String userName = reqMap.get("userName").toString();
 
-            count = publicityService.savePublicityPosition(dataModel, userId, userName);
+            List<PubPublicitypositionPanel> panelList = JsonMapper.jsonToObject(reqMap.get("panelList").toString(), new TypeReference<List<PubPublicitypositionPanel>>() {
+            });
+
+            count = publicityService.savePublicityPositionAndPanel(dataModel,panelList, userId, userName);
 
         } catch (Exception e) {
 

+ 3 - 1
src/main/java/com/ghsc/partybuild/service/PublicityService.java

@@ -53,6 +53,8 @@ public interface PublicityService {
      */
     int savePublicityPosition(PubPublicityposition model, String userId, String userName);
 
+    int savePublicityPositionAndPanel(PubPublicityposition model,List<PubPublicitypositionPanel> panelList, String userId, String userName);
+
     /**
      * 删除宣传阵地信息
      * @param id
@@ -410,7 +412,7 @@ public interface PublicityService {
 
     int savePartyduesDetail(UsPartyduesDetail model,String userId,String userName);
 
-    int deleteDuesById(String id);
+    int deleteDuesById(String id,String userId);
 
     PageInfo<HashMap<String, Object>> getSettingDuesUserList(int page, int rows,Integer year, String dzzdm
             ,String rybm,String xm,String szdzb,Integer isStudent);

+ 87 - 2
src/main/java/com/ghsc/partybuild/service/impl/PublicityServiceImpl.java

@@ -175,6 +175,85 @@ public class PublicityServiceImpl implements PublicityService {
         return result;
     }
 
+    /**
+     * @param model
+     * @param userId
+     * @param userName
+     * @return
+     */
+    @Override
+    public int savePublicityPositionAndPanel(PubPublicityposition model, List<PubPublicitypositionPanel> panelList, String userId, String userName) {
+        int result = 0;
+        PubPublicityposition dbModel = getPublicityPositionById(model.getPublicitypositionid());
+        if (dbModel == null || (model != null && stringUtils.IsNullOrEmpty(model.getPublicitypositionid()))) {
+            model.setCreatetime(new Date());
+            model.setCreateuserid(userId);
+            model.setCreateusername(userName);
+            model.setOperatestate("A");
+            model.setOperatetime(new Date());
+            model.setSyncstate("N");
+
+            result = pubPublicitypositionMapper.insert(model);
+        } else {
+
+            model.setUpdatetime(new Date());
+            model.setUpdateuserid(userId);
+            model.setUpdateusername(userName);
+            model.setOperatestate("M");
+            model.setOperatetime(new Date());
+            model.setSyncstate("N");
+
+            result = pubPublicitypositionMapper.updateByPrimaryKey(model);
+        }
+
+        PubPublicitypositionPanelExample exp = new PubPublicitypositionPanelExample();
+        PubPublicitypositionPanelExample.Criteria cri = exp.or();
+        cri.andPublicitypositionidEqualTo(model.getPublicitypositionid());
+        List<PubPublicitypositionPanel> dbPanelList = pubPublicitypositionPanelMapper.selectByExample(exp);
+        List<String> dbPanelIdList = dbPanelList.stream().map(PubPublicitypositionPanel::getPanelid).collect(Collectors.toList());
+        List<String> newPanelIdList = panelList.stream().map(PubPublicitypositionPanel::getPanelid).collect(Collectors.toList());
+        List<String> removePanelIdList = dbPanelIdList.stream().filter(e -> !newPanelIdList.contains(e)).collect(Collectors.toList());
+
+        if (removePanelIdList.size() > 0) {
+            cri.andPanelidIn(removePanelIdList);
+
+            pubPublicitypositionPanelMapper.deleteByExample(exp);
+        }
+
+
+        panelList.forEach(panel -> {
+            PubPublicitypositionPanel dbPanel = dbPanelList.stream().filter(it -> it.getPanelid().equals(panel.getPanelid())).findFirst().orElse(null);
+            if (dbPanel == null) {
+                panel.setPublicitypositionid(model.getPublicitypositionid());
+                panel.setCreatetime(new Date());
+                panel.setCreateuserid(userId);
+                panel.setCreateusername(userName);
+                panel.setOperatestate("A");
+                panel.setOperatetime(new Date());
+                panel.setSyncstate("N");
+                panel.setPanelstate(0);
+
+                pubPublicitypositionPanelMapper.insert(panel);
+            } else {
+                dbPanel.setTitle(panel.getTitle());
+                dbPanel.setRemark(panel.getRemark());
+                dbPanel.setPaneltime(panel.getPaneltime());
+                dbPanel.setPanelcycle(panel.getPanelcycle());
+                dbPanel.setPanelimg(panel.getPanelimg());
+                dbPanel.setUpdatetime(new Date());
+                dbPanel.setUpdateuserid(userId);
+                dbPanel.setUpdateusername(userName);
+                dbPanel.setOperatestate("M");
+                dbPanel.setOperatetime(new Date());
+                dbPanel.setSyncstate("N");
+
+                pubPublicitypositionPanelMapper.updateByPrimaryKey(dbPanel);
+            }
+        });
+
+        return result;
+    }
+
     /**
      * @param id
      * @return
@@ -1258,8 +1337,14 @@ public class PublicityServiceImpl implements PublicityService {
     }
 
     @Override
-    public int deleteDuesById(String id) {
-        return 0;/*usPartyduesDetailMapper.deleteByPrimaryKey(id);*/
+    public int deleteDuesById(String id, String userId) {
+        UsPartyduesDetail detail = usPartyduesDetailMapper.selectByPrimaryKey(id);
+        detail.setMoney(null);
+        detail.setPaystate(0);
+        detail.setUpdatetime(new Date());
+        detail.setUpdateuserid(userId);
+
+        return usPartyduesDetailMapper.updateByPrimaryKey(detail);
     }
 
     /**

+ 11 - 7
src/main/resources/mapping/PublicityCQuery.xml

@@ -60,7 +60,7 @@
         <if test="zzfbType != null">
             and SUBSTR(p.partyCode,1,12) in(select dzzdm from ZZ_DZZFBQK where zzfb= #{zzfbType})
         </if>
-        order by IF(ISNULL(panel.PANELTIME),1,0) desc,p.PARTYCODE,p.CREATETIME desc
+        order by panel.PANELTIME desc,p.PARTYCODE,p.CREATETIME desc
     </select>
 
     <select id="selectPublicityPanelList" resultType="java.util.HashMap">
@@ -140,6 +140,7 @@
     <select id="selectPublicityPanelRecordList" resultType="java.util.HashMap">
         select p.PUBLICITYPOSITIONID,p.POSITIONNAME,panel.TITLE,panel.PANELIMG,panel.CREATEUSERNAME,panel.PANELTIME,
         panel.PANELCYCLE,panel.PANELSTATE,panel.PANELID,z.DZZMC as PARTYNAME
+        ,panel.REMARK
         from PUB_PUBLICITYPOSITION p
         inner join PUB_PUBLICITYPOSITION_PANEL panel on p.PUBLICITYPOSITIONID=panel.PUBLICITYPOSITIONID
         inner join ZZ_ZZQKXX z on p.partycode=z.dzzdm
@@ -626,15 +627,18 @@
     </select>
 
     <select id="selectUserDuesList" resultType="java.util.HashMap">
-        select us.partyduesId,u.xm,u.rybm,z.dzzdm,z.dzzmc,us.year,d.month,us.MONEY as baseMoney,(ifnull(d.MONEY,0)+ifnull(d.SPECIALEXPENSES,0)) as money,
+        select us.partyduesId,u.xm as userName,u.rybm as userCode
+        ,z.dzzdm as partyCode,z.dzzmc as partyName
+        ,us.year,d.month,us.MONEY as baseMoney,(ifnull(d.MONEY,0)+ifnull(d.SPECIALEXPENSES,0)) as money,
         d.detailid
         from US_PARTYDUES us
         inner join US_PARTYDUES_DETAIL d on us.PARTYDUESID = d.PARTYDUESID
-        inner join VM_RYJBXX u on us.USERCODE = u.RYBM
-        inner join ZZ_ZZQKXX z on u.SZDZBDM = z.DZZDM
-        where 1=1 and d.OPERATESTATE <![CDATA[ <> ]]> 'D'
+        inner join VM_RYJBXX_ALL u on us.USERCODE = u.RYBM
+        inner join us_party_month upm on us.userCode= upm.userCode and upm.yearMonth = (us.YEAR*100+d.month)
+        inner join ZZ_ZZQKXX z on upm.partycode = z.DZZDM
+        where 1=1 and d.payState=1
         <if test="ssdzzdm!=null and ssdzzdm !=''">
-            and u.SZDZBDM like concat( '%',#{ssdzzdm},'%')
+            and z.DZZDM like concat( '',#{ssdzzdm},'%')
         </if>
         <if test="xm!=null and xm !=''">
             and u.XM like concat('%',#{xm},'%')
@@ -645,7 +649,7 @@
         <if test="month!=null">
             and d.MONTH = #{month}
         </if>
-        order by us.YEAR desc,d.MONTH desc,u.XMPY,u.RYJBXXBS
+        order by us.YEAR desc,d.MONTH desc,CONVERT(u.XM USING gbk)
     </select>
 
     <!--党员基本信息-->