Browse Source

feat: knowledge doc

Signed-off-by: carlos <568187512@qq.com>
carlos 3 months ago
parent
commit
a604ea4223
30 changed files with 644 additions and 131 deletions
  1. 5 5
      src/app/pages/manager/knowledge/bank/bank.component.ts
  2. 12 26
      src/app/pages/manager/knowledge/bank/risk-item-list/risk-item-list.component.html
  3. 0 35
      src/app/pages/manager/knowledge/bank/risk-item-list/risk-item-list.component.less
  4. 8 1
      src/app/pages/manager/knowledge/bank/risk-item-list/risk-item-list.component.ts
  5. 55 0
      src/app/pages/manager/knowledge/doc/doc-import/doc-import.component.html
  6. 0 0
      src/app/pages/manager/knowledge/doc/doc-import/doc-import.component.less
  7. 23 0
      src/app/pages/manager/knowledge/doc/doc-import/doc-import.component.spec.ts
  8. 92 0
      src/app/pages/manager/knowledge/doc/doc-import/doc-import.component.ts
  9. 54 0
      src/app/pages/manager/knowledge/doc/doc-table/doc-table.component.html
  10. 0 0
      src/app/pages/manager/knowledge/doc/doc-table/doc-table.component.less
  11. 23 0
      src/app/pages/manager/knowledge/doc/doc-table/doc-table.component.spec.ts
  12. 83 0
      src/app/pages/manager/knowledge/doc/doc-table/doc-table.component.ts
  13. 33 1
      src/app/pages/manager/knowledge/doc/doc.component.html
  14. 7 0
      src/app/pages/manager/knowledge/doc/doc.component.less
  15. 93 4
      src/app/pages/manager/knowledge/doc/doc.component.ts
  16. 8 8
      src/app/pages/manager/knowledge/list/list.component.ts
  17. 3 1
      src/app/services/api.service.ts
  18. 1 1
      src/app/services/apis/auth.ts
  19. 14 0
      src/app/services/apis/knowledge.ts
  20. 2 2
      src/app/services/auth.service.ts
  21. 2 2
      src/app/services/setting.service.ts
  22. 6 6
      src/app/shared/data-select/user-search.component.ts
  23. 10 0
      src/app/shared/filter-button-group/filter-button-group.component.html
  24. 32 0
      src/app/shared/filter-button-group/filter-button-group.component.less
  25. 23 0
      src/app/shared/filter-button-group/filter-button-group.component.spec.ts
  26. 19 0
      src/app/shared/filter-button-group/filter-button-group.component.ts
  27. 11 0
      src/assets/icons/docx.svg
  28. 8 2
      src/styles/custom.less
  29. 1 37
      src/types/auth.d.ts
  30. 16 0
      src/types/knowledge.d.ts

+ 5 - 5
src/app/pages/manager/knowledge/bank/bank.component.ts

@@ -17,16 +17,16 @@ export class BankComponent {
       label: '风险知识',
       value: 'risk-knowledge',
     },
-    {
-      label: '企业录入情况',
-      value: 'enterprise-input',
-    },
+    // {
+    //   label: '企业录入情况',
+    //   value: 'enterprise-input',
+    // },
     {
       label: '更新纪录',
       value: 'update-record',
     },
   ];
-  activeTab = this.tabs[2].value;
+  activeTab = this.tabs[0].value;
 
   changeTab(tab: string) {
     this.activeTab = tab;

+ 12 - 26
src/app/pages/manager/knowledge/bank/risk-item-list/risk-item-list.component.html

@@ -2,7 +2,6 @@
   <div class="risk-item-header">
     <div class="title">XXXXX公司风险项列表</div>
     <div>
-      <button nz-button nzType="primary" class="precaution-secondary" style="border-radius: 12px">创建风险项</button>
       <button
         nz-button
         nzType="primary"
@@ -15,31 +14,18 @@
     </div>
   </div>
   <div class="risk-item-filter">
-    <div class="filter-item">
-      <label class="label">风险类别: </label>
-      <div class="flex-1">
-        @for (category of categories; track category.value) {
-          <div
-            class="button-item"
-            [class.active]="activeCategory === category.value"
-            (click)="changeCategory(category.value)"
-          >
-            {{ category.label }}
-          </div>
-        }
-      </div>
-    </div>
-
-    <div class="filter-item">
-      <label class="label">风险等级: </label>
-      <div class="flex-1">
-        @for (level of levels; track level.value) {
-          <div class="button-item" [class.active]="activeLevel === level.value" (click)="changeLevel(level.value)">
-            {{ level.label }}
-          </div>
-        }
-      </div>
-    </div>
+    <filter-button-group
+      label="风险类别"
+      [options]="categories"
+      [activeValue]="activeCategory"
+      (change)="changeCategory($event)"
+    ></filter-button-group>
+    <filter-button-group
+      label="风险等级"
+      [options]="levels"
+      [activeValue]="activeLevel"
+      (change)="changeLevel($event)"
+    ></filter-button-group>
   </div>
   <app-risk-item-table></app-risk-item-table>
 </div>

+ 0 - 35
src/app/pages/manager/knowledge/bank/risk-item-list/risk-item-list.component.less

@@ -10,38 +10,3 @@
     padding-bottom: 16px;
   }
 }
-
-.risk-item-filter {
-  .filter-item {
-    display: flex;
-    gap: 10px;
-    align-items: flex-start;
-    justify-content: flex-start;
-    margin-bottom: 16px;
-  }
-  .label {
-    line-height: 32px;
-  }
-  .button-item {
-    display: inline-block;
-    border-radius: 10px;
-    padding: 0 18px;
-    height: 32px;
-    line-height: 32px;
-    color: rgba(102, 102, 102, 0.667);
-    margin-right: 8px;
-    cursor: pointer;
-    transition: all 0.3s;
-    &:hover {
-      background-color: var(--ant-primary-1);
-    }
-
-    &:last-child {
-      margin-right: 0;
-    }
-    &.active {
-      background-color: var(--deep-blue);
-      color: #ffffff;
-    }
-  }
-}

+ 8 - 1
src/app/pages/manager/knowledge/bank/risk-item-list/risk-item-list.component.ts

@@ -1,6 +1,7 @@
 import { Component } from '@angular/core';
 import { CommonNzModule } from '../../../../../common.nz.module';
 import { CustomDrawerComponent } from '../../../../../shared/custom-drawer/custom-drawer.component';
+import { FilterButtonGroupComponent } from '../../../../../shared/filter-button-group/filter-button-group.component';
 import { RiskItemFormComponent } from '../risk-item-form/risk-item-form.component';
 import { RiskItemTableComponent } from '../risk-item-table/risk-item-table.component';
 
@@ -26,7 +27,13 @@ const levels = ['R1', 'R2', 'R2*', 'R3', 'R4'];
 @Component({
   selector: 'risk-item-list',
   standalone: true,
-  imports: [CommonNzModule, RiskItemTableComponent, CustomDrawerComponent, RiskItemFormComponent],
+  imports: [
+    CommonNzModule,
+    RiskItemTableComponent,
+    CustomDrawerComponent,
+    RiskItemFormComponent,
+    FilterButtonGroupComponent,
+  ],
   templateUrl: './risk-item-list.component.html',
   styleUrl: './risk-item-list.component.less',
 })

+ 55 - 0
src/app/pages/manager/knowledge/doc/doc-import/doc-import.component.html

@@ -0,0 +1,55 @@
+<nz-spin [nzSpinning]="importing" nzSize="large">
+  @if (!this.validateForm.valid) {
+    <nz-alert class="rounded-alert" nzType="warning" nzMessage="导入注意事项:  风险类别,风险等级是必选项!"></nz-alert>
+  }
+
+  <form class="py-2" nz-form nzLayout="horizontal" [formGroup]="validateForm">
+    <nz-form-item style="margin: 4px 0 4px 0">
+      <nz-form-label nzSpan="5">风险类别</nz-form-label>
+      <nz-form-control nzSpan="16">
+        <nz-select
+          class="precaution-select"
+          nzDropdownClassName="precaution-select-dropdown"
+          [style.minWidth]="'150px'"
+          formControlName="category"
+          nzPlaceHolder="请选择"
+        >
+          @for (item of categories; track item.value) {
+            <nz-option [nzValue]="item.value" [nzLabel]="item.label"></nz-option>
+          }
+        </nz-select>
+      </nz-form-control>
+    </nz-form-item>
+    <nz-form-item style="margin: 4px 0 4px 0">
+      <nz-form-label nzSpan="5">风险等级</nz-form-label>
+      <nz-form-control nzSpan="16">
+        <nz-select
+          class="precaution-select"
+          nzDropdownClassName="precaution-select-dropdown"
+          [style.minWidth]="'150px'"
+          formControlName="level"
+          nzPlaceHolder="请选择"
+        >
+          @for (item of levels; track item.value) {
+            <nz-option [nzValue]="item.value" [nzLabel]="item.label"></nz-option>
+          }
+        </nz-select>
+      </nz-form-control>
+    </nz-form-item>
+  </form>
+
+  <div class="pt-4 pb-6 text-right flex justify-end">
+    <nz-upload
+      [nzAction]="'/doc/import?category=' + validateForm.value.category + '&level=' + validateForm.value.level"
+      nzAccept=".docx,.pdf"
+      [nzShowUploadList]="false"
+      (nzChange)="handleImportStatusChange($event)"
+    >
+      <button class="precaution-button ml-4 mr-2" nzType="primary" nz-button [disabled]="!validateForm.valid">
+        <span nz-icon nzType="upload"></span>
+        导入文档
+      </button>
+    </nz-upload>
+    <button class="precaution-secondary" nz-button (click)="handleReset()">重置</button>
+  </div>
+</nz-spin>

+ 0 - 0
src/app/pages/manager/knowledge/doc/doc-import/doc-import.component.less


+ 23 - 0
src/app/pages/manager/knowledge/doc/doc-import/doc-import.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DocImportComponent } from './doc-import.component';
+
+describe('DocImportComponent', () => {
+  let component: DocImportComponent;
+  let fixture: ComponentFixture<DocImportComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [DocImportComponent]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(DocImportComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 92 - 0
src/app/pages/manager/knowledge/doc/doc-import/doc-import.component.ts

@@ -0,0 +1,92 @@
+import { Component, inject } from '@angular/core';
+import { NonNullableFormBuilder, Validators } from '@angular/forms';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { NZ_MODAL_DATA } from 'ng-zorro-antd/modal';
+import { NzUploadChangeParam } from 'ng-zorro-antd/upload';
+import { CommonNzModule } from '../../../../../common.nz.module';
+
+export interface DocImportModalData {
+  onImportSuccess: () => void; // Add this callback
+  categories: Option[];
+  levels: Option[];
+  category: number | string;
+  level: number | string;
+}
+
+@Component({
+  selector: 'doc-import',
+  standalone: true,
+  imports: [CommonNzModule],
+  templateUrl: './doc-import.component.html',
+  styleUrl: './doc-import.component.less',
+})
+export class DocImportComponent {
+  readonly nzModalData: DocImportModalData = inject(NZ_MODAL_DATA);
+  importing: boolean = false;
+
+  // repeatWords: string[] = [];
+  constructor(
+    private message: NzMessageService,
+    private fb: NonNullableFormBuilder
+  ) {}
+  validateForm = this.fb.group({
+    category: this.fb.control<number | string | undefined>(undefined, {
+      validators: [Validators.required],
+    }),
+    level: this.fb.control<number | string | undefined>(undefined, {
+      validators: [Validators.required],
+    }),
+  });
+  selectFields: {
+    label: string;
+    key: string;
+    minWidth?: string;
+    options: Option[];
+  }[] = [
+    // { label: '风险类别', key: 'category', options: [], minWidth: '150px' },
+    // { label: '风险等级', key: 'level', options: [], minWidth: '150px' },
+  ];
+
+  ngOnInit() {
+    console.log(this.nzModalData.category, this.nzModalData.level);
+    this.validateForm.patchValue({
+      category: this.nzModalData.category,
+      level: this.nzModalData.level,
+    });
+  }
+  handleImportStatusChange(event: NzUploadChangeParam) {
+    if (event.type === 'start') {
+      this.importing = true;
+    }
+    if (event.type === 'success') {
+      if (event.file.response?.code !== 0) {
+        this.message.error('导入失败: ' + event.file.response?.message);
+        this.importing = false;
+        return;
+      }
+      this.message.success('导入成功');
+      this.importing = false;
+
+      // Call the callback function to refresh the list in the parent component
+      if (this.nzModalData.onImportSuccess) {
+        this.nzModalData.onImportSuccess();
+      }
+    } else if (event.type === 'error') {
+      if (event.file.error.error?.message) {
+        this.message.error('导入失败: ' + event.file.error.error.message);
+      } else {
+        this.message.error('导入失败');
+      }
+      this.importing = false;
+    }
+  }
+  handleReset() {
+    this.validateForm.reset();
+  }
+  get categories() {
+    return this.nzModalData.categories;
+  }
+  get levels() {
+    return this.nzModalData.levels;
+  }
+}

+ 54 - 0
src/app/pages/manager/knowledge/doc/doc-table/doc-table.component.html

@@ -0,0 +1,54 @@
+<nz-table
+  class="precaution-table"
+  #table
+  [nzData]="list"
+  nzShowPagination
+  nzPaginationType="small"
+  [nzFrontPagination]="false"
+  [nzTotal]="pageConfig.total"
+  [nzPageIndex]="pageConfig.page + 1"
+  (nzPageIndexChange)="onCurrentPageChange($event - 1)"
+  [nzLoading]="loading"
+>
+  <thead>
+    <tr>
+      <th>文档名称</th>
+      <th>更新日期</th>
+      <th>发布部门</th>
+      <th [nzRight]="'0px'">操作</th>
+    </tr>
+  </thead>
+  <tbody>
+    @for (data of table.data; track $index) {
+      <tr>
+        <td>
+          <span nz-icon nzType="icons:docx" class="mr-2"></span>
+          <span>{{ data.name }}</span>
+        </td>
+        <td>{{ data.updateDate }}</td>
+        <td>{{ data.department }}</td>
+
+        <td [nzRight]="'0px'">
+          <nz-upload
+            [nzAction]="'/doc/update?id=' + data.id"
+            nzAccept=".docx,.pdf"
+            [nzShowUploadList]="false"
+            (nzChange)="handleImportStatusChange($event)"
+          >
+            <button class="precaution-button ml-4 mr-2" nzType="primary" nzSize="small" nz-button>更新文档</button>
+          </nz-upload>
+          <button
+            class="precaution-secondary px-2 ml-4"
+            nz-button
+            nzSize="small"
+            nzType="primary"
+            nzDanger
+            (click)="onRemove(data)"
+          >
+            删除
+          </button>
+        </td>
+      </tr>
+    }
+  </tbody>
+</nz-table>

+ 0 - 0
src/app/pages/manager/knowledge/doc/doc-table/doc-table.component.less


+ 23 - 0
src/app/pages/manager/knowledge/doc/doc-table/doc-table.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DocTableComponent } from './doc-table.component';
+
+describe('DocTableComponent', () => {
+  let component: DocTableComponent;
+  let fixture: ComponentFixture<DocTableComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [DocTableComponent]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(DocTableComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 83 - 0
src/app/pages/manager/knowledge/doc/doc-table/doc-table.component.ts

@@ -0,0 +1,83 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { NzModalService } from 'ng-zorro-antd/modal';
+import { NzUploadChangeParam } from 'ng-zorro-antd/upload';
+import { CommonNzModule } from '../../../../../common.nz.module';
+import { ApiService } from '../../../../../services/api.service';
+
+@Component({
+  selector: 'doc-table',
+  standalone: true,
+  imports: [CommonNzModule],
+  templateUrl: './doc-table.component.html',
+  styleUrl: './doc-table.component.less',
+})
+export class DocTableComponent {
+  importing = false;
+  loading = false;
+  @Input() pageConfig: IPageConfig = {
+    page: 0,
+    total: 0,
+    size: 10,
+  };
+  @Input() list: Knowledge.Doc[] = [];
+  @Output() pageChange = new EventEmitter<number>();
+
+  constructor(
+    private message: NzMessageService,
+    private modal: NzModalService,
+    private api: ApiService
+  ) {}
+
+  onCurrentPageChange(page: number) {
+    this.pageConfig.page = page;
+    this.pageChange.emit(page);
+  }
+
+  onRemove(data: Knowledge.Doc) {
+    this.list = this.list.filter(item => item.id !== data.id);
+    this.modal.confirm({
+      nzClassName: 'precaution-modal',
+      nzTitle: '删除文档',
+      nzContent: `确定要删除【${data.name}】吗?`,
+      nzOkText: '确定',
+      nzOkDanger: true,
+      nzOnOk: async () => {
+        await this.api.knowledge
+          .deleteDoc(data.id)
+          .then(() => {
+            this.message.success('删除成功');
+            this.pageChange.emit(this.pageConfig.page);
+          })
+          .catch(err => {
+            this.message.error(err.message);
+            throw err;
+          });
+      },
+    });
+  }
+
+  handleImportStatusChange(event: NzUploadChangeParam) {
+    if (event.type === 'start') {
+      this.importing = true;
+    }
+    if (event.type === 'success') {
+      if (event.file.response?.code !== 0) {
+        this.message.error('更新失败: ' + event.file.response?.message);
+        this.importing = false;
+        return;
+      }
+      this.message.success('更新成功');
+      this.importing = false;
+
+      this.pageChange.emit(this.pageConfig.page);
+    } else if (event.type === 'error') {
+      if (event.file.error.error?.message) {
+        this.message.error('更新失败: ' + event.file.error.error.message);
+      } else {
+        this.message.error('更新失败');
+      }
+      this.importing = false;
+    }
+  }
+}

+ 33 - 1
src/app/pages/manager/knowledge/doc/doc.component.html

@@ -1 +1,33 @@
-<p>doc works!</p>
+<div class="knowledge-panel">
+  <div class="knowledge-header">
+    <div class="title">风险文档</div>
+  </div>
+  <div class="knowledge-content">
+    <div class="risk-item-filter">
+      <filter-button-group
+        label="风险类别"
+        [options]="docCategories"
+        [activeValue]="category"
+        (change)="changeCategory($event)"
+      ></filter-button-group>
+      <filter-button-group
+        label="风险等级"
+        [options]="levelOptions"
+        [activeValue]="level"
+        (change)="changeLevel($event)"
+      ></filter-button-group>
+    </div>
+
+    <div class="flex justify-between pb-4">
+      <div>
+        <span class="title-text">文档库</span>
+      </div>
+      <div>
+        <button nz-button nzType="primary" class="precaution-button" style="border-radius: 12px" (click)="onImport()">
+          上传文档
+        </button>
+      </div>
+    </div>
+    <doc-table [list]="list" [pageConfig]="pageConfig" (pageChange)="onPageChange($event)"></doc-table>
+  </div>
+</div>

+ 7 - 0
src/app/pages/manager/knowledge/doc/doc.component.less

@@ -0,0 +1,7 @@
+.title-text {
+  font-weight: 500;
+  font-size: 20px;
+  color: #333333;
+  line-height: 28px;
+  text-shadow: 0px 0px 8px rgba(223, 223, 223, 0.5);
+}

+ 93 - 4
src/app/pages/manager/knowledge/doc/doc.component.ts

@@ -1,12 +1,101 @@
-import { Component } from '@angular/core';
+import { Component, ViewContainerRef } from '@angular/core';
+import { NzModalService } from 'ng-zorro-antd/modal';
+import { CommonNzModule } from '../../../../common.nz.module';
+import { ApiService } from '../../../../services/api.service';
+import { FilterButtonGroupComponent } from '../../../../shared/filter-button-group/filter-button-group.component';
+import { DocImportComponent, DocImportModalData } from './doc-import/doc-import.component';
+import { DocTableComponent } from './doc-table/doc-table.component';
+
+const getMockItem = (id: number): Knowledge.Doc => ({
+  id,
+  name: `文档${id}`,
+  department: `部门${id}`,
+  updateDate: '2024/9/9',
+});
 
 @Component({
-  selector: 'app-doc',
+  selector: 'knowledge-doc',
   standalone: true,
-  imports: [],
+  imports: [CommonNzModule, FilterButtonGroupComponent, DocTableComponent],
   templateUrl: './doc.component.html',
-  styleUrl: './doc.component.less'
+  styleUrl: './doc.component.less',
 })
 export class DocComponent {
+  docCategories = [
+    { label: '管理规定', value: 1 },
+    { label: '规程', value: 2 },
+    { label: '作业指导', value: 3 },
+    { label: '应急预案', value: 4 },
+    { label: '教育培训', value: 5 },
+  ];
+  levelOptions = [
+    { label: '集团级', value: 1 },
+    { label: '公司级', value: 2 },
+  ];
+  category = this.docCategories[0].value;
+  level = this.levelOptions[0].value;
+
+  pageConfig: IPageConfig = {
+    page: 0,
+    total: 0,
+    size: 10,
+  };
+  list: Knowledge.Doc[] = Array.from({ length: 10 }, (_, index) => getMockItem(index + 1));
+
+  constructor(
+    private modal: NzModalService,
+    private viewContainerRef: ViewContainerRef,
+    private api: ApiService
+  ) {}
+
+  ngOnInit() {
+    this.fetchList();
+  }
+
+  changeCategory(value: number | string) {
+    this.category = value as number;
+    this.fetchList();
+  }
+  changeLevel(value: number | string) {
+    this.level = value as number;
+    this.fetchList();
+  }
+
+  onPageChange(page: number) {
+    this.pageConfig.page = page;
+    this.fetchList();
+  }
+
+  onImport() {
+    this.modal.create<DocImportComponent, DocImportModalData>({
+      nzClassName: 'precaution-modal',
+      nzTitle: '文档 - 导入',
+      nzContent: DocImportComponent,
+      nzWidth: 500,
+      nzBodyStyle: { paddingBottom: '0px' },
+      nzViewContainerRef: this.viewContainerRef,
+      nzData: {
+        categories: this.docCategories,
+        levels: this.levelOptions,
+        category: this.category,
+        level: this.level,
+        onImportSuccess: () => {
+          this.onSearch();
+        },
+      },
+      nzFooter: null,
+    });
+  }
 
+  onSearch() {
+    console.log('search');
+    this.fetchList();
+  }
+  async fetchList() {
+    const result = await this.api.knowledge.getDocList({
+      category: this.category,
+      level: this.level,
+    });
+    console.log(result);
+  }
 }

+ 8 - 8
src/app/pages/manager/knowledge/list/list.component.ts

@@ -15,14 +15,14 @@ export class ListComponent {
       label: '风险知识',
       value: 'risk-knowledge',
     },
-    {
-      label: '企业录入情况',
-      value: 'enterprise-input',
-    },
-    {
-      label: '更新纪录',
-      value: 'update-record',
-    },
+    // {
+    //   label: '企业录入情况',
+    //   value: 'enterprise-input',
+    // },
+    // {
+    //   label: '更新纪录',
+    //   value: 'update-record',
+    // },
   ];
   activeTab = this.tabs[0].value;
 

+ 3 - 1
src/app/services/api.service.ts

@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
 
 import { AuthApi } from './apis/auth';
 import { BasicApi } from './apis/basic';
+import { KnowledgeApi } from './apis/knowledge';
 import { HttpService } from './http.service';
 
 @Injectable({ providedIn: 'root' })
@@ -9,7 +10,8 @@ export class ApiService {
   constructor(
     public readonly http: HttpService,
     public readonly basic: BasicApi,
-    public readonly auth: AuthApi
+    public readonly auth: AuthApi,
+    public readonly knowledge: KnowledgeApi
   ) {}
 
   getAllUrls(): string[] {

+ 1 - 1
src/app/services/apis/auth.ts

@@ -5,7 +5,7 @@ import { _BaseApi } from './_base';
 @Injectable({ providedIn: 'root' })
 export class AuthApi extends _BaseApi {
   @Post('/user/login')
-  async login(data: UserApi.LoginParams): Promise<UserApi.LoginResponse> {
+  async login(data: Auth.LoginParams): Promise<Auth.LoginResponse> {
     requestDone(data);
   }
 

+ 14 - 0
src/app/services/apis/knowledge.ts

@@ -0,0 +1,14 @@
+import { Injectable } from '@angular/core';
+import { Post, requestDone } from '../http.decorators';
+import { _BaseApi } from './_base';
+
+@Injectable({ providedIn: 'root' })
+export class KnowledgeApi extends _BaseApi {
+  @Post('/knowledge/doc/list')
+  async getDocList(data: Knowledge.GetDocListParams): Promise<Knowledge.GetDocListResponse> {
+    requestDone(data);
+  }
+  async deleteDoc(id: number) {
+    return this.http.post('/knowledge/doc/delete', { id });
+  }
+}

+ 2 - 2
src/app/services/auth.service.ts

@@ -18,7 +18,7 @@ export class AuthService {
     return this.token != undefined;
   }
 
-  async login(params: UserApi.LoginParams): Promise<UserApi.LoginResponse> {
+  async login(params: Auth.LoginParams): Promise<Auth.LoginResponse> {
     const result = await this.api.auth.login(params).catch(err => {
       throw err;
     });
@@ -37,7 +37,7 @@ export class AuthService {
     return true;
   }
 
-  private async afterLogin(result: UserApi.LoginResponse) {
+  private async afterLogin(result: Auth.LoginResponse) {
     this.storage.token = result.token;
     const autoLogin = await this.autoLogin();
     if (!autoLogin) {

+ 2 - 2
src/app/services/setting.service.ts

@@ -7,7 +7,7 @@ import { StorageService } from './storage.service';
   providedIn: 'root',
 })
 export class SettingService {
-  user?: UserApi.User;
+  user?: Auth.User;
 
   get userCompany() {
     return this.user?.company || '';
@@ -52,7 +52,7 @@ export class SettingService {
     // this.user = info;
   }
 
-  updateUser(data: UserApi.ModifyUserInfo) {
+  updateUser(data: Auth.ModifyUserInfo) {
     // return this.api.user.modifyMyInfo(data);
   }
 }

+ 6 - 6
src/app/shared/data-select/user-search.component.ts

@@ -12,20 +12,20 @@ import { CommonNzModule } from '../../common.nz.module';
 })
 export class UserSearchComponent {
   @Input() hiddenContent = false;
-  @Input() userList: UserApi.User[] = [];
+  @Input() userList: Auth.User[] = [];
   loading = false;
-  sources: UserApi.User[] = [];
-  dataMap: Map<string, UserApi.User[]> = new Map();
+  sources: Auth.User[] = [];
+  dataMap: Map<string, Auth.User[]> = new Map();
   checkedDto: Record<string, boolean> = {};
 
   search = {
     text: '',
   };
-  filteredList: UserApi.User[] = [];
+  filteredList: Auth.User[] = [];
   capitals: string[] = [];
   list: {
     w: string;
-    items: UserApi.User[];
+    items: Auth.User[];
   }[] = [];
 
   private subject$ = new Subject<void>();
@@ -178,7 +178,7 @@ export class UserSearchComponent {
     this.onItemCheckedChange();
   }
 
-  additionalLabel(user: UserApi.User) {
+  additionalLabel(user: Auth.User) {
     const { job } = user;
     return job ? `(${job})` : '';
   }

+ 10 - 0
src/app/shared/filter-button-group/filter-button-group.component.html

@@ -0,0 +1,10 @@
+<div class="filter-item">
+  <label class="label">{{ label }}: </label>
+  <div class="flex-1">
+    @for (o of options; track o.value) {
+      <div class="button-item" [class.active]="activeValue === o.value" (click)="handleChange(o.value)">
+        {{ o.label }}
+      </div>
+    }
+  </div>
+</div>

+ 32 - 0
src/app/shared/filter-button-group/filter-button-group.component.less

@@ -0,0 +1,32 @@
+.filter-item {
+  display: flex;
+  gap: 10px;
+  align-items: flex-start;
+  justify-content: flex-start;
+  margin-bottom: 16px;
+}
+.label {
+  line-height: 32px;
+}
+.button-item {
+  display: inline-block;
+  border-radius: 10px;
+  padding: 0 18px;
+  height: 32px;
+  line-height: 32px;
+  color: rgba(102, 102, 102, 0.667);
+  margin-right: 8px;
+  cursor: pointer;
+  transition: all 0.3s;
+  &:hover {
+    background-color: var(--ant-primary-1);
+  }
+
+  &:last-child {
+    margin-right: 0;
+  }
+  &.active {
+    background-color: var(--deep-blue);
+    color: #ffffff;
+  }
+}

+ 23 - 0
src/app/shared/filter-button-group/filter-button-group.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FilterButtonGroupComponent } from './filter-button-group.component';
+
+describe('FilterButtonGroupComponent', () => {
+  let component: FilterButtonGroupComponent;
+  let fixture: ComponentFixture<FilterButtonGroupComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [FilterButtonGroupComponent]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(FilterButtonGroupComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 19 - 0
src/app/shared/filter-button-group/filter-button-group.component.ts

@@ -0,0 +1,19 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+  selector: 'filter-button-group',
+  standalone: true,
+  imports: [],
+  templateUrl: './filter-button-group.component.html',
+  styleUrl: './filter-button-group.component.less',
+})
+export class FilterButtonGroupComponent<T = any> {
+  @Input() label = '';
+  @Input() options: Option<T>[] = [];
+  @Input() activeValue: T | null = null;
+  @Output() change = new EventEmitter<T>();
+
+  handleChange(value: T) {
+    this.change.emit(value);
+  }
+}

+ 11 - 0
src/assets/icons/docx.svg

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>编组备份 7</title>
+    <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="风险知识-风险文档" transform="translate(-357.000000, -499.000000)" fill="#009994" fill-rule="nonzero">
+            <g id="编组备份-2" transform="translate(357.000000, 499.000000)">
+                <path d="M10.5,1.40929557 L13.5,1.40929557 C13.7761406,1.40929557 14,1.63096523 14,1.90440474 L14,11.8039888 C14,12.0774283 13.7761406,12.2990979 13.5,12.2990979 L10.5,12.2990979 L10.5,13.2133479 C10.5,13.4867256 10.2761406,13.7083333 10,13.7083333 C9.97634375,13.7083333 9.95271875,13.7066778 9.92929688,13.7033513 L0.429296875,12.3598107 C0.18296875,12.3249674 0,12.1161241 0,11.8698073 L0,1.83858617 C0,1.59226935 0.18296875,1.38342612 0.429296875,1.34858281 L9.92929688,0.00504219827 C10.2026563,-0.0336382054 10.4559219,0.154425917 10.4949687,0.425049493 C10.4983281,0.448242263 10.5,0.471620699 10.5,0.495045552 L10.5,1.40929557 Z M10.5,2.39928182 L10.5,11.3091117 L13,11.3091117 L13,2.39928182 L10.5,2.39928182 Z M1.125,2.37522261 L1.125,11.3331709 L9.375,12.4999266 L9.375,1.20846692 L1.125,2.37522261 Z M4.75,4.25549251 L5.75,4.25549251 L6.75,7.71970946 L7.75,4.25549251 L8.75,4.25549251 L7.25,9.45181794 L6.25,9.45181794 L5.25,5.98760098 L4.25,9.45181794 L4.2496875,9.45181794 L4.25,9.45290099 L3.25,9.45290099 L1.75,4.25549251 L2.75,4.25549251 L3.74989062,7.72006532 L4.75,4.25549251 Z" id="形状"></path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 8 - 2
src/styles/custom.less

@@ -112,7 +112,7 @@ textarea {
   border-radius: 4px;
   display: inline-flex;
   align-items: center;
-  --ant-error-color: #fa6400;
+  --ant-error-color: #f43f5e;
 }
 .precaution-secondary {
   border-radius: 4px;
@@ -121,7 +121,7 @@ textarea {
   --ant-primary-color-active: #839dfd;
   --ant-error-color: #ffd9d9;
   &.ant-btn-dangerous {
-    color: #ff0000;
+    color: #f43f5e;
   }
   &:hover,
   &:active {
@@ -188,6 +188,11 @@ textarea {
         border-bottom: 1px solid rgba(151, 151, 151, 0.3);
         padding: 16px;
       }
+      &:last-child {
+        td {
+          border-bottom: none;
+        }
+      }
     }
   }
   nz-pagination {
@@ -296,6 +301,7 @@ textarea {
   }
 }
 .precaution-modal {
+  --ant-error-color: #ff0000;
   .ant-modal-header {
     border-radius: 8px 8px 0 0;
   }

+ 1 - 37
src/types/user.d.ts → src/types/auth.d.ts

@@ -1,4 +1,4 @@
-declare namespace UserApi {
+declare namespace Auth {
   interface LoginParams {
     username: string;
     password: string;
@@ -44,40 +44,4 @@ declare namespace UserApi {
     startingDate: string;
     loginDate: string;
   }
-
-  // interface User {
-  //   count: number;
-  //   department: number;
-  //   id: number;
-  //   job: number;
-  //   username: string;
-  //   email: string; // 邮箱
-  //   last_login_time?: string;
-  //   name: string;
-  //   path: string;
-  //   phone: string;
-  //   roles: string;
-  //   roleName: string;
-  //   status: number;
-  //   update_time: string;
-  //   create_time: string;
-  //   delete_time: string;
-  //   avatar: string; // 头像
-  // }
-
-  interface UserRequestParams extends User {
-    roles: number[];
-  }
-
-  interface SimpleUser {
-    id: number;
-    name: string;
-    status: number; // 1表示角色启用,-1表示删除
-  }
-
-  interface SimpleRole {
-    id: number;
-    name: string;
-    status: number; // 1表示角色启用,0表示禁用
-  }
 }

+ 16 - 0
src/types/knowledge.d.ts

@@ -0,0 +1,16 @@
+declare namespace Knowledge {
+  interface Doc {
+    id: number;
+    name: string;
+    department: string;
+    updateDate: string;
+  }
+  interface GetDocListParams {
+    category: number;
+    level: number;
+  }
+  interface GetDocListResponse {
+    items: Doc[];
+    total: number;
+  }
+}