Browse Source

开始流程

main
kely 12 months ago
parent
commit
ae15cefffb
  1. 71
      web-admin-app/src/app/app.routes.ts
  2. 5
      web-admin-app/src/app/components/asset-form/asset-form.component.html
  3. 2
      web-admin-app/src/app/components/asset-form/asset-form.component.ts
  4. 6
      web-admin-app/src/app/components/asset-operation-records/asset-operation-records.component.ts
  5. 52
      web-admin-app/src/app/components/asset-repair-records/asset-repair-records.component.html
  6. 0
      web-admin-app/src/app/components/asset-repair-records/asset-repair-records.component.less
  7. 63
      web-admin-app/src/app/components/asset-repair-records/asset-repair-records.component.ts
  8. 5
      web-admin-app/src/app/components/asset-select/asset-select.component.ts
  9. 2
      web-admin-app/src/app/components/index.ts
  10. 89
      web-admin-app/src/app/components/stocktaking-detail-form/stocktaking-detail-form.component.html
  11. 0
      web-admin-app/src/app/components/stocktaking-detail-form/stocktaking-detail-form.component.less
  12. 125
      web-admin-app/src/app/components/stocktaking-detail-form/stocktaking-detail-form.component.ts
  13. 9
      web-admin-app/src/app/constants/index.ts
  14. 4
      web-admin-app/src/app/pages/fixed-asset/fixed-asset.component.html
  15. 6
      web-admin-app/src/app/pages/fixed-asset/repair/repair-type/repair-type.component.ts
  16. 3
      web-admin-app/src/app/pages/fixed-asset/stocktaking/stockaking-job/stockaking-job.component.html
  17. 25
      web-admin-app/src/app/pages/fixed-asset/stocktaking/stockaking-job/stockaking-job.component.ts
  18. 222
      web-admin-app/src/app/pages/fixed-asset/stocktaking/stockaking-plan/stockaking-plan.component.html
  19. 221
      web-admin-app/src/app/pages/fixed-asset/stocktaking/stockaking-plan/stockaking-plan.component.ts
  20. 97
      web-admin-app/src/app/pages/fixed-asset/stocktaking/stocktaking-detail/stocktaking-detail.component.html
  21. 0
      web-admin-app/src/app/pages/fixed-asset/stocktaking/stocktaking-detail/stocktaking-detail.component.less
  22. 138
      web-admin-app/src/app/pages/fixed-asset/stocktaking/stocktaking-detail/stocktaking-detail.component.ts
  23. 13
      web-admin-app/src/app/pages/flow/flow-layout/flow-layout.component.html
  24. 0
      web-admin-app/src/app/pages/flow/flow-layout/flow-layout.component.less
  25. 24
      web-admin-app/src/app/pages/flow/flow-layout/flow-layout.component.ts
  26. 18
      web-admin-app/src/app/pages/flow/flow-main/flow-main.component.html
  27. 0
      web-admin-app/src/app/pages/flow/flow-main/flow-main.component.less
  28. 40
      web-admin-app/src/app/pages/flow/flow-main/flow-main.component.ts
  29. 1
      web-admin-app/src/app/pages/flow/flow-my-apply/flow-my-apply.component.html
  30. 0
      web-admin-app/src/app/pages/flow/flow-my-apply/flow-my-apply.component.less
  31. 12
      web-admin-app/src/app/pages/flow/flow-my-apply/flow-my-apply.component.ts
  32. 1
      web-admin-app/src/app/pages/flow/flow-my-todo/flow-my-todo.component.html
  33. 0
      web-admin-app/src/app/pages/flow/flow-my-todo/flow-my-todo.component.less
  34. 12
      web-admin-app/src/app/pages/flow/flow-my-todo/flow-my-todo.component.ts
  35. 10
      web-admin-app/src/app/pages/profile-account/profile-account.component.html
  36. 31
      web-admin-app/src/app/pages/profile-account/profile-account.component.ts
  37. 17
      web-admin-app/src/app/pages/profile-basic/profile-basic.component.html
  38. 6
      web-admin-app/src/app/pages/profile-basic/profile-basic.component.ts
  39. 28
      web-admin-app/src/app/pages/system/flow/flow-form/flow-form.component.html
  40. 0
      web-admin-app/src/app/pages/system/flow/flow-form/flow-form.component.less
  41. 95
      web-admin-app/src/app/pages/system/flow/flow-form/flow-form.component.ts
  42. 11
      web-admin-app/src/app/pages/system/index/system.component.html
  43. 8
      web-admin-app/src/app/pages/system/index/system.component.ts
  44. 50
      web-admin-app/src/app/services/api.service.ts
  45. 3
      web-admin-app/src/app/shared/components/header/header.component.html
  46. 1
      web-admin-app/src/app/shared/components/server-paginated-table/server-paginated-table.component.html
  47. 22
      web-admin-app/src/app/shared/components/server-paginated-table/server-paginated-table.component.ts

71
web-admin-app/src/app/app.routes.ts

@ -51,6 +51,12 @@ import { AlertMaintenanceComponent } from './pages/fixed-asset/alert/alert-maint
import { AlertInventorySafetyComponent } from './pages/fixed-asset/alert/alert-inventory-safety/alert-inventory-safety.component'
import { AlertInventoryUpComponent } from './pages/fixed-asset/alert/alert-inventory-up/alert-inventory-up.component'
import { AlertInventoryDownComponent } from './pages/fixed-asset/alert/alert-inventory-down/alert-inventory-down.component'
import { StocktakingDetailComponent } from './pages/fixed-asset/stocktaking/stocktaking-detail/stocktaking-detail.component'
import { FlowFormComponent } from './pages/system/flow/flow-form/flow-form.component'
import { FlowMainComponent } from './pages/flow/flow-main/flow-main.component'
import { FlowMyApplyComponent } from './pages/flow/flow-my-apply/flow-my-apply.component'
import { FlowMyTodoComponent } from './pages/flow/flow-my-todo/flow-my-todo.component'
import { FlowLayoutComponent } from './pages/flow/flow-layout/flow-layout.component'
export const routes: Routes = [
{
@ -122,6 +128,23 @@ export const routes: Routes = [
title: '角色管理',
data: {},
},
{
path: 'flow',
canActivate: [permissionGuard],
title: '流程管理',
children: [
{
path: '',
pathMatch: 'full',
redirectTo: 'form',
},
{
path: 'form',
component: FlowFormComponent,
title: '表单定义',
},
],
},
],
},
// {
@ -340,6 +363,27 @@ export const routes: Routes = [
pathMatch: 'full',
redirectTo: 'job',
},
{
path: 'job',
title: '盘点任务',
children: [
{
path: '',
pathMatch: 'full',
redirectTo: 'list',
},
{
path: 'list',
component: StockakingJobComponent,
},
{
path: 'detail/:id',
title: '盘点明细',
component: StocktakingDetailComponent,
},
],
},
{
path: 'job',
component: StockakingJobComponent,
@ -400,6 +444,33 @@ export const routes: Routes = [
},
],
},
{
path: 'asset-flow',
title: '固资流程',
component: FlowLayoutComponent,
children: [
{
path: '',
pathMatch: 'full',
redirectTo: 'index',
},
{
path: 'index',
title: '流程首页',
component: FlowMainComponent,
},
{
path: 'my-apply',
title: '我的申请',
component: FlowMyApplyComponent,
},
{
path: 'my-todo',
title: '待我处理',
component: FlowMyTodoComponent,
},
],
},
],
},

5
web-admin-app/src/app/components/asset-form/asset-form.component.html

@ -11,6 +11,7 @@
<nz-tab nzTitle="保养记录"></nz-tab>
<nz-tab nzTitle="巡检记录"></nz-tab> -->
<nz-tab nzTitle="历史记录"></nz-tab>
<nz-tab nzTitle="维修记录"></nz-tab>
}
</nz-tabset>
</nz-card-tab>
@ -375,10 +376,10 @@
} @else {
@switch (groupIndex) {
@case (3) {
<app-asset-operation-records />
<app-asset-operation-records [assetId]="data?.value?.assetId" />
}
@case (4) {
4
<app-asset-repair-records [assetId]="data?.value?.assetId" />
}
@case (5) {
5

2
web-admin-app/src/app/components/asset-form/asset-form.component.ts

@ -14,6 +14,7 @@ import { MaintenanceSelectComponent } from '../maintenance-select/maintenance-se
import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NZ_MODAL_DATA } from 'ng-zorro-antd/modal'
import { AssetOperationRecordsComponent } from '../asset-operation-records/asset-operation-records.component'
import { AssetRepairRecordsComponent } from '../asset-repair-records/asset-repair-records.component'
@Component({
selector: 'app-asset-form',
@ -27,6 +28,7 @@ import { AssetOperationRecordsComponent } from '../asset-operation-records/asset
PositionSelectComponent,
MaintenanceSelectComponent,
AssetOperationRecordsComponent,
AssetRepairRecordsComponent,
],
templateUrl: './asset-form.component.html',
styleUrl: './asset-form.component.less',

6
web-admin-app/src/app/components/asset-operation-records/asset-operation-records.component.ts

@ -1,4 +1,4 @@
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'
import { Component, Input, OnInit, TemplateRef, ViewChild } from '@angular/core'
import { SharedModule } from 'app/shared/shared.module'
import { ApiService } from 'app/services'
@ -27,6 +27,8 @@ export class AssetOperationRecordsComponent {
private fb: FormBuilder,
) {}
@Input() assetId!: number
table = new TableOption(this.fetchData.bind(this))
queryForm!: FormGroup
@ -56,6 +58,6 @@ export class AssetOperationRecordsComponent {
}
fetchData(p: {}, q: AnyObject) {
return this.api.getAssetLog({ ...p, ...q })
return this.api.getAssetLog({ ...p, ...q, assetId: this.assetId })
}
}

52
web-admin-app/src/app/components/asset-repair-records/asset-repair-records.component.html

@ -0,0 +1,52 @@
<div class="overflow-hidden flex-1">
<app-server-paginated-table [options]="table" [renderColumn]="renderColumnTpl" [formGroup]="queryForm">
<ng-template #renderColumnTpl let-data let-key="key" let-row="row">
@switch (key) {
@case ('status') {
<!-- <nz-badge
[nzText]="data === 0 ? '在职' : '离职'"
[nzStatus]="data === 0 ? 'processing' : 'error'"
/> -->
}
@case ('_repairType') {
{{ data.name }}
}
@default {
{{ data }}
}
}
</ng-template>
<!-- <ng-container *appTableForm>
<div class="mr-3">
<div nz-row nzGutter="24">
<div nz-col nzSpan="8">
<nz-form-item>
<nz-form-label>业务编号</nz-form-label>
<nz-form-control>
<input nz-input placeholder="请输入" formControlName="businessId" />
</nz-form-control>
</nz-form-item>
</div>
<div nz-col nzSpan="8">
<nz-form-item>
<nz-form-label>操作内容</nz-form-label>
<nz-form-control>
<input nz-input placeholder="请输入" formControlName="operationNotes" />
</nz-form-control>
</nz-form-item>
</div>
<div nz-col nzSpan="8">
<nz-form-item>
<nz-form-label>操作类型</nz-form-label>
<nz-form-control>
<input nz-input placeholder="请输入" formControlName="operationType" />
</nz-form-control>
</nz-form-item>
</div>
</div>
</div>
</ng-container> -->
</app-server-paginated-table>
</div>

0
web-admin-app/src/app/components/asset-repair-records/asset-repair-records.component.less

63
web-admin-app/src/app/components/asset-repair-records/asset-repair-records.component.ts

@ -0,0 +1,63 @@
import { Component, Input, OnInit, TemplateRef, ViewChild } from '@angular/core'
import { SharedModule } from 'app/shared/shared.module'
import { ApiService } from 'app/services'
import { FormBuilder, FormGroup } from '@angular/forms'
import { AnyObject, TableOption } from 'app/shared/components/server-paginated-table'
import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message'
import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer'
import { lastValueFrom } from 'rxjs'
import { FormValidators } from 'app/utils'
@Component({
selector: 'app-asset-repair-records',
standalone: true,
imports: [SharedModule],
templateUrl: './asset-repair-records.component.html',
styleUrl: './asset-repair-records.component.less',
})
export class AssetRepairRecordsComponent {
constructor(
private modal: NzModalService,
private msg: NzMessageService,
private drawer: NzDrawerService,
private api: ApiService,
private fb: FormBuilder,
) {}
@Input() assetId!: number
table = new TableOption(this.fetchData.bind(this))
queryForm!: FormGroup
initQueryForm() {
this.queryForm = this.fb.group({
businessId: [],
operationNotes: [],
operationType: [],
})
}
ngOnInit(): void {
this.table
.setConfig({
cacheKey: 'asset-repair-records.component',
})
.setColumn([
{ key: 'id', title: '主键', width: '100px' },
{ key: 'businessId', title: '业务编号', width: '170px' },
{ key: 'name', title: '名称' },
{ key: '_repairType', title: '维修类型' },
{ key: 'plannedDate', title: '计划完成时间' },
// { key: 'createTime', title: '创建时间' },
])
this.initQueryForm()
}
fetchData(p: {}, q: AnyObject) {
return this.api.getAssetRepairLog({ ...p, ...q }, this.assetId)
}
}

5
web-admin-app/src/app/components/asset-select/asset-select.component.ts

@ -96,6 +96,8 @@ export class AssetSelectComponent {
.setConfig({
selectable: true,
rowKey: 'assetId',
radio: true,
noneCache: true,
})
.setColumn([
{ key: 'assetCode', title: '资产编号', visible: true },
@ -125,6 +127,9 @@ export class AssetSelectComponent {
nzWidth: '80vw',
nzWrapClassName: 'modal-lg',
nzOnOk: () => {
if (this.radio) {
this.selectedDataList = []
}
this.allGetedDataMap.forEach((i: NzSafeAny) => {
if (this.table.ref.selected.has(String(i.assetId))) {
if (!this.selectedDataList.some((s) => s.assetId === i.assetId)) {

2
web-admin-app/src/app/components/index.ts

@ -8,6 +8,7 @@ export * from './manufacturer-select/manufacturer-select.component'
export * from './position-select/position-select.component'
export * from './maintenance-select/maintenance-select.component'
export * from './asset-operation-records/asset-operation-records.component'
export * from './asset-repair-records/asset-repair-records.component'
export * from './asset-business-storage-form/asset-business-storage-form.component'
export * from './supplier-select/supplier-select.component'
export * from './asset-select/asset-select.component'
@ -24,3 +25,4 @@ export * from './repair-form/repair-form.component'
export * from './repair-fault-form/repair-fault-form.component'
export * from './position-tree/position-tree.component'
export * from './stocktaking-detail-form/stocktaking-detail-form.component'

89
web-admin-app/src/app/components/stocktaking-detail-form/stocktaking-detail-form.component.html

@ -0,0 +1,89 @@
<div class="modal">
<form nz-form [formGroup]="formGroup" nzLayout="vertical">
<div class="overflow-hidden">
<div nz-row [nzGutter]="24">
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label [nzRequired]="true">盘点状态</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-select [nzPlaceHolder]="'请选择状态'" formControlName="status">
@for (item of STOCKTAKING_JOB_STATUS_MAP | keyvalue; track $index) {
<nz-option [nzLabel]="item.value" [nzValue]="item.key"></nz-option>
}
</nz-select>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>盘点任务</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<input
nz-input
[ngModel]="jobName"
[disabled]="true"
[ngModelOptions]="{ standalone: true }"
/>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>图片</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<input type="hidden" nz-input formControlName="img" />
<div class="mb-2" *ngIf="iconPreview">
<img [src]="iconPreview" class="h-20 w-20" />
</div>
<button class="upload-btn" nz-button [nzLoading]="uploadImgLoading">
<i nz-icon nzType="upload"></i>
上传图片
<input type="file" (change)="onImgChange($event)" accept=".jpg,.jpeg,.png" />
</button>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>附件</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<input type="hidden" formControlName="attachment" />
<button class="upload-btn" nz-button [nzLoading]="uploadLoading">
<i nz-icon nzType="upload"></i>
选择文件
<input type="file" (change)="onFileChange($event)" />
</button>
@if (formGroup.get('attachment')?.value) {
<div class="mt-1">
<nz-tag class="break-words w-full !whitespace-pre-wrap">
{{ formGroup.get('attachment')?.value }}
</nz-tag>
</div>
}
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="24">
<nz-form-item>
<nz-form-label>盘点说明</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<textarea nz-input placeholder="请输入盘点说明" formControlName="notes"></textarea>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="24">
<nz-form-item>
<nz-form-label>资产列表</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<app-asset-select [radio]="true" formControlName="assetId" />
</nz-form-control>
</nz-form-item>
</div>
</div>
</div>
</form>
<ng-template #errorTpl let-control>
<form-error-tips [control]="control"></form-error-tips>
</ng-template>
</div>

0
web-admin-app/src/app/components/stocktaking-detail-form/stocktaking-detail-form.component.less

125
web-admin-app/src/app/components/stocktaking-detail-form/stocktaking-detail-form.component.ts

@ -0,0 +1,125 @@
import { Component, Input, OnInit, inject } from '@angular/core'
import { FormBuilder, FormGroup } from '@angular/forms'
import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module'
import { FormValidators, Utils } from 'app/utils'
import { NzMessageService } from 'ng-zorro-antd/message'
import { OrgSelectComponent } from '../org-select/org-select.component'
import { SelectUserByOrgComponent } from '../select-user-by-org/select-user-by-org.component'
import { PositionSelectComponent } from '../position-select/position-select.component'
import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NZ_MODAL_DATA } from 'ng-zorro-antd/modal'
import { SupplierSelectComponent } from '../supplier-select/supplier-select.component'
import { AssetSelectComponent } from '../asset-select/asset-select.component'
import { ActivatedRoute } from '@angular/router'
import { STOCKTAKING_JOB_STATUS_MAP } from 'app/constants'
@Component({
selector: 'app-stocktaking-detail-form',
standalone: true,
imports: [
SharedModule,
SelectUserByOrgComponent,
SupplierSelectComponent,
AssetSelectComponent,
OrgSelectComponent,
PositionSelectComponent,
],
templateUrl: './stocktaking-detail-form.component.html',
styleUrl: './stocktaking-detail-form.component.less',
})
export class StocktakingDetailFormComponent {
constructor(
private fb: FormBuilder,
private api: ApiService,
private msg: NzMessageService,
private route: ActivatedRoute,
) {}
readonly data: NzSafeAny = inject(NZ_MODAL_DATA)
STOCKTAKING_JOB_STATUS_MAP = STOCKTAKING_JOB_STATUS_MAP
jobName = ''
formGroup!: FormGroup
groupIndex = 0
uploadLoading = false
uploadImgLoading = false
iconPreview = ''
ngOnInit(): void {
this.jobName = this.route.snapshot.queryParamMap.get('name') || ''
this.formGroup = this.fb.group({
id: this.fb.control(null, []),
status: this.fb.control(null, [FormValidators.required('请选择')]),
assetId: this.fb.control([], [FormValidators.required('请选择')]),
notes: this.fb.control(null, []),
img: this.fb.control('', []),
attachment: this.fb.control('', []),
})
this.patchValues()
}
patchValues() {
const { value: data, preview } = this.data
if (data) {
this.formGroup.patchValue({
...data,
})
}
if (preview) {
this.formGroup.disable()
}
}
public getValues() {
let values = null
if (FormValidators.validateFormGroup(this.formGroup)) {
const v = this.formGroup.value
values = {
...v,
assetId: v.assetId[0],
}
}
return values
}
onFileChange(e: Event) {
const target = e.target as HTMLInputElement
const file = target.files![0]
target.value = ''
const formdata = new FormData()
formdata.append('file', file)
this.api.upload(formdata).subscribe((res) => {
this.formGroup.get('attachment')?.setValue(res.body.fileName)
})
}
onImgChange(e: Event) {
const target = e.target as HTMLInputElement
const file = target.files![0]
target.value = ''
if (file.size / 1024 / 1024 >= 2) {
this.msg.error('图片大小不能超过2M')
return
}
const fileReader = new FileReader()
fileReader.onload = () => {
const base64 = fileReader.result as string
this.iconPreview = base64
}
fileReader.readAsDataURL(file)
const formdata = new FormData()
formdata.append('file', file)
this.api.upload(formdata).subscribe((res) => {
this.formGroup.get('img')?.setValue(res.body.fileName)
})
}
}

9
web-admin-app/src/app/constants/index.ts

@ -50,3 +50,12 @@ export const BUSINESS_STATUS_MAP = new Map([
[3, '审批中'],
[4, '取消'],
])
export const STOCKTAKING_JOB_STATUS_MAP = new Map([
// 0-盘盈,1-盘亏,2-已盘点,3-带盘点,4-异常
[0, '盘盈'],
[1, '盘亏'],
[2, '已盘点'],
[3, '待盘点'],
[4, '异常'],
])

4
web-admin-app/src/app/pages/fixed-asset/fixed-asset.component.html

@ -34,9 +34,9 @@
<li nz-menu-item [nzPaddingLeft]="24" [routerLink]="['/fixed-asset/manage/transfer']" nzMatchRouter>
资产转移
</li>
<li nz-menu-item [nzPaddingLeft]="24" [routerLink]="['/fixed-asset/manage/scrap']" nzMatchRouter>
<!-- <li nz-menu-item [nzPaddingLeft]="24" [routerLink]="['/fixed-asset/manage/scrap']" nzMatchRouter>
资产报废
</li>
</li> -->
<!-- <li nzMatchRouter [nzPaddingLeft]="24" nz-submenu nzTitle="资产变更">
<ul>

6
web-admin-app/src/app/pages/fixed-asset/repair/repair-type/repair-type.component.ts

@ -72,7 +72,7 @@ export class RepairTypeComponent {
this.createForm.patchValue(data)
}
this.modal.create({
nzTitle: data ? '编辑资产入库' : '添加资产入库',
nzTitle: data ? '编辑' : '添加',
nzContent: this.createFormTpl,
nzOnOk: async () => {
if (FormValidators.validateFormGroup(this.createForm)) {
@ -80,10 +80,14 @@ export class RepairTypeComponent {
const res = await lastValueFrom(this.api.saveRepairType(vals))
this.msg.success(res.desc)
this.table.ref.reload()
this.createForm.reset()
return true
}
return false
},
nzOnCancel: () => {
this.createForm.reset()
},
})
}

3
web-admin-app/src/app/pages/fixed-asset/stocktaking/stockaking-job/stockaking-job.component.html

@ -92,7 +92,8 @@
<app-query-item label="盘点状态">
<nz-select
nzPlacement="bottomRight"
class="!w-auto"
class="!w-40"
[nzPlaceHolder]="'请选择'"
[nzDropdownMatchSelectWidth]="false"
formControlName="status"
nzAllowClear

25
web-admin-app/src/app/pages/fixed-asset/stocktaking/stockaking-job/stockaking-job.component.ts

@ -9,8 +9,9 @@ import { NzMessageService } from 'ng-zorro-antd/message'
import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer'
import { lastValueFrom } from 'rxjs'
import { FormValidators, Utils } from 'app/utils'
import { SelectUserByOrgComponent, buildCateTree } from 'app/components'
import { SelectUserByOrgComponent } from 'app/components'
import { ASSET_STATUS, MAX_PAGE_SIZE } from 'app/constants'
import { Router } from '@angular/router'
@Component({
selector: 'app-stockaking-job',
@ -26,6 +27,7 @@ export class StockakingJobComponent {
private drawer: NzDrawerService,
private api: ApiService,
private fb: FormBuilder,
private router: Router,
) {}
table = new TableOption(this.fetchData.bind(this))
@ -40,6 +42,8 @@ export class StockakingJobComponent {
@ViewChild('formContentTpl') formContentTpl!: TemplateRef<NzSafeAny>
@ViewChild('detailTpl') detailTpl!: TemplateRef<NzSafeAny>
ASSET_STATUS = ASSET_STATUS
assetCategoryTree: NzSafeAny[] = []
@ -109,7 +113,7 @@ export class StockakingJobComponent {
{ key: 'notes', title: '备注' },
])
.setRowOperate([
{ title: '明细', onClick: this.onCreate.bind(this) },
{ title: '明细', onClick: this.onDetail.bind(this) },
// { title: '详情', onClick: this.onDetail.bind(this) },
{ title: '编辑', onClick: this.onCreate.bind(this) },
{ title: '删除', onClick: this.deleteItem.bind(this) },
@ -172,14 +176,17 @@ export class StockakingJobComponent {
nzOnCancel: this.onCancel.bind(this),
})
}
detailItem: NzSafeAny = null
onDetail(data: NzSafeAny) {
this.drawerRef = this.drawer.create({
nzTitle: data ? '编辑盘点任务' : '新增盘点任务',
nzContent: this.formContentTpl,
nzFooter: this.drawerFooterTpl,
nzWidth: 600,
nzOnCancel: this.onCancel.bind(this),
})
window.open(`/fixed-asset/stocktaking/job/detail/${data.stocktakingJobId}?name=${data.name}`)
// this.router.navigate(['/fixed-asset/stocktaking/job/detail', data.stocktakingJobId], {
// queryParams: {
// name: data.name,
// },
// })
}
onConfirm() {

222
web-admin-app/src/app/pages/fixed-asset/stocktaking/stockaking-plan/stockaking-plan.component.html

@ -1 +1,221 @@
<p>stockaking-plan works!</p>
<app-page class="p-3">
<div class="flex-1 overflow-hidden">
<app-server-paginated-table
[options]="table"
[tableAction]="tableActionTpl"
[renderColumn]="renderColumnTpl"
[formGroup]="queryForm"
>
<ng-template #renderColumnTpl let-data let-key="key" let-row="row">
@switch (key) {
@case ('fullStocktaking') {
@switch (data) {
@case (0) {
<nz-badge [nzText]="'禁用'" [nzStatus]="'error'" />
}
@case (1) {
<nz-badge [nzText]="'启用'" [nzStatus]="'processing'" />
}
@default {
-
}
}
}
@case ('status') {
@switch (data) {
@case (0) {
<nz-badge [nzText]="'未开始'" [nzStatus]="'default'" />
}
@case (1) {
<nz-badge [nzText]="'进行中'" [nzStatus]="'processing'" />
}
@case (2) {
<nz-badge [nzText]="'取消'" [nzStatus]="'error'" />
}
@case (3) {
<nz-badge [nzText]="'已完成'" [nzStatus]="'success'" />
}
@default {
-
}
}
}
@case ('_stocktakingUser') {
{{ data?.userName ?? '-' }}
}
@case ('_useUser') {
{{ data?.userName ?? '-' }}
}
@case ('_warehouse') {
{{ data?.name ?? '-' }}
}
@case ('_position') {
{{ data?.name ?? '-' }}
}
@case ('_head') {
{{ data?.userName ?? '-' }}
}
@case ('_ownCompany') {
{{ data?.organizationName ?? '-' }}
}
@case ('_useOrganization') {
{{ data?.organizationName ?? '-' }}
}
@case ('_category') {
{{ data?.categoryName ?? '-' }}
}
@default {
{{ data }}
}
}
</ng-template>
<ng-template #tableActionTpl>
<nz-space>
<button *nzSpaceItem nz-button nzType="primary" (click)="onCreate()">新建</button>
</nz-space>
</ng-template>
<ng-container *appTableForm>
<app-query-item label="名称" class="w-60">
<input nz-input placeholder="请输入" formControlName="name" />
</app-query-item>
<app-query-item label="备注" class="w-60">
<input nz-input placeholder="请输入" formControlName="notes" />
</app-query-item>
<app-query-item label="盘点状态">
<nz-select
nzPlacement="bottomRight"
class="!w-40"
[nzPlaceHolder]="'请选择'"
[nzDropdownMatchSelectWidth]="false"
formControlName="status"
nzAllowClear
>
<nz-option [nzValue]="0" nzLabel="未开始"></nz-option>
<nz-option [nzValue]="1" nzLabel="进行中"></nz-option>
<nz-option [nzValue]="2" nzLabel="取消"></nz-option>
<nz-option [nzValue]="3" nzLabel="已完成"></nz-option>
</nz-select>
</app-query-item>
</ng-container>
</app-server-paginated-table>
</div>
</app-page>
<ng-template #drawerFooterTpl>
<nz-space>
<button *nzSpaceItem nz-button nzType="primary" (click)="onConfirm()">确定</button>
<button *nzSpaceItem nz-button nzType="default" (click)="onCancel()">取消</button>
</nz-space>
</ng-template>
<ng-template #formContentTpl>
<form nz-form nzLayout="vertical" [formGroup]="createForm">
<nz-form-item>
<nz-form-label nzRequired> 名称 </nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<input type="text" nz-input formControlName="name" placeholder="请输入名称" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 全员盘点 </nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-radio-group formControlName="fullStocktaking">
<label nz-radio [nzValue]="1">启用</label>
<label nz-radio [nzValue]="0">禁用</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 负责人 </nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<app-select-user-by-org [radio]="true" formControlName="head" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 盘点人 </nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<app-select-user-by-org [radio]="true" formControlName="stocktakingUserId" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 备注 </nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<textarea nz-input formControlName="notes" placeholder="请输入备注"></textarea>
</nz-form-control>
</nz-form-item>
<h2>盘点范围</h2>
<nz-form-item>
<nz-form-label> 购置开始日期 </nz-form-label>
<nz-form-control>
<nz-date-picker nzShowTime class="w-full" formControlName="stocktakingStartDate" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 购置结束日期 </nz-form-label>
<nz-form-control>
<nz-date-picker nzShowTime class="w-full" formControlName="stocktakingEndDate" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 资产分类 </nz-form-label>
<nz-form-control>
<nz-tree-select [nzNodes]="assetCategoryTree" formControlName="categoryId"></nz-tree-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 资产状态 </nz-form-label>
<nz-form-control>
<nz-select nzPlaceHolder="请选择" formControlName="assetStatus">
@for (item of ASSET_STATUS; track $index) {
<nz-option [nzLabel]="item.label" [nzValue]="item.value"></nz-option>
}
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 位置 </nz-form-label>
<nz-form-control>
<nz-tree-select nzPlaceHolder="请选择" [nzNodes]="positionTree" formControlName="positionId">
</nz-tree-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 仓库 </nz-form-label>
<nz-form-control>
<nz-select nzPlaceHolder="请选择" formControlName="warehouseId">
@for (item of warehouse; track $index) {
<nz-option [nzLabel]="item.label" [nzValue]="item.value"></nz-option>
}
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 所属公司 </nz-form-label>
<nz-form-control>
<nz-tree-select nzPlaceHolder="请选择" [nzNodes]="companyTree" formControlName="ownCompanyId">
</nz-tree-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 使用公司/部门 </nz-form-label>
<nz-form-control>
<nz-tree-select nzPlaceHolder="请选择" [nzNodes]="orgTree" formControlName="useOrganizationId">
</nz-tree-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 保管人 </nz-form-label>
<nz-form-control>
<app-select-user-by-org [radio]="true" formControlName="useUserId" />
</nz-form-control>
</nz-form-item>
</form>
</ng-template>
<ng-template #errorTpl let-control>
<form-error-tips [control]="control"></form-error-tips>
</ng-template>

221
web-admin-app/src/app/pages/fixed-asset/stocktaking/stockaking-plan/stockaking-plan.component.ts

@ -8,14 +8,227 @@ import { NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message'
import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer'
import { lastValueFrom } from 'rxjs'
import { FormValidators } from 'app/utils'
import { SelectUserByOrgComponent } from 'app/components'
import { FormValidators, Utils } from 'app/utils'
import { SelectUserByOrgComponent, buildCateTree } from 'app/components'
import { ASSET_STATUS, MAX_PAGE_SIZE } from 'app/constants'
@Component({
selector: 'app-stockaking-plan',
standalone: true,
imports: [],
imports: [SharedModule, SelectUserByOrgComponent],
templateUrl: './stockaking-plan.component.html',
styleUrl: './stockaking-plan.component.less',
})
export class StockakingPlanComponent {}
export class StockakingPlanComponent {
constructor(
private modal: NzModalService,
private msg: NzMessageService,
private drawer: NzDrawerService,
private api: ApiService,
private fb: FormBuilder,
) {}
table = new TableOption(this.fetchData.bind(this))
queryForm!: FormGroup
createForm!: FormGroup
drawerRef?: NzDrawerRef
@ViewChild('drawerFooterTpl') drawerFooterTpl!: TemplateRef<NzSafeAny>
@ViewChild('formContentTpl') formContentTpl!: TemplateRef<NzSafeAny>
ASSET_STATUS = ASSET_STATUS
assetCategoryTree: NzSafeAny[] = []
positionTree: NzSafeAny[] = []
warehouse: NzSafeAny[] = []
companyTree: NzSafeAny[] = []
orgTree: NzSafeAny[] = []
initCreateForm() {
this.createForm = this.fb.group({
stocktakingJobId: [],
name: ['', [FormValidators.required('请输入')]],
notes: ['', []],
stocktakingUserId: [[], []],
head: [[], []],
fullStocktaking: [1, []],
stocktakingStartDate: [null, []],
stocktakingEndDate: [null, []],
categoryId: [null, []],
warehouseId: [null, []],
positionId: [null, []],
ownCompanyId: [null, []],
useOrganizationId: [null, []],
useUserId: [null, []],
assetStatus: [0, []],
})
}
initQueryForm() {
this.queryForm = this.fb.group({
name: [],
status: [],
notes: [],
})
}
ngOnInit(): void {
this.table
.setConfig({
selectable: true,
rowKey: 'stocktakingJobId',
})
.setColumn([
{ key: 'name', title: '名称' },
{ key: 'fullStocktaking', title: '全员盘点' },
{ key: 'status', title: '盘点状态' },
{ key: '_head', title: '负责人', width: '150px' },
{ key: '_stocktakingUser', title: '盘点人', width: '150px' },
// { key: 'countPending', title: '待盘点', width: '100px' },
// { key: 'countCompleted', title: '已盘点', width: '100px' },
// { key: 'countLoss', title: '盘亏', width: '100px' },
// { key: 'countSurplus', title: '盘盈', width: '100px' },
// { key: 'countException', title: '异常数据', width: '100px' },
{ key: '_category', title: '资产分类' },
{ key: '_ownCompany', title: '所属公司' },
{ key: '_useOrganization', title: '使用公司/部门' },
{ key: '_useUser', title: '保管人', width: '150px' },
{ key: '_warehouse', title: '仓库' },
{ key: '_position', title: '存放位置' },
{ key: 'stocktakingStartDate', title: '购置开始日期', width: '180px' },
{ key: 'stocktakingEndDate', title: '购置结束日期', width: '180px' },
{ key: 'createTime', title: '创建时间', width: '180px' },
{ key: 'createUser', title: '创建人', width: '150px' },
{ key: 'notes', title: '备注' },
])
.setRowOperate([
// { title: '明细', onClick: this.onCreate.bind(this) },
// { title: '详情', onClick: this.onDetail.bind(this) },
{ title: '创建任务', onClick: this.onCreateTask.bind(this) },
{ title: '编辑', onClick: this.onCreate.bind(this) },
{ title: '删除', onClick: this.deleteItem.bind(this) },
])
this.initQueryForm()
this.initCreateForm()
this.api.getBasicCategoryTree().subscribe((res) => {
this.assetCategoryTree = Utils.buildTree(res.body, 'categoryId', 'categoryName')
})
this.api.getBasicPositionTree().subscribe((res) => {
this.positionTree = Utils.buildTree(res.body, 'positionId', 'name')
})
this.api.getBasicWarehousePage({ pageSize: MAX_PAGE_SIZE, pageNum: 1 }).subscribe((r) => {
this.warehouse = r.body.rows.map((i: NzSafeAny) => {
return {
label: i.name,
value: i.warehouseId,
}
})
})
this.api.getOrgTree().subscribe((res) => {
const c: NzSafeAny[] = []
const o: NzSafeAny[] = []
res.body.forEach((i: NzSafeAny) => {
if (i.organizationType === '0') {
c.push(i)
}
if (['1', '0'].includes(i.organizationType)) {
o.push(i)
}
})
this.orgTree = Utils.buildTree(o, 'organizationId', 'organizationName')
this.companyTree = Utils.buildTree(c, 'organizationId', 'organizationName')
})
}
fetchData(p: {}, q: AnyObject) {
return this.api.getStocktakingPlanPage({ ...p, ...q })
}
onCreate(data?: NzSafeAny) {
if (data) {
this.createForm.patchValue({
...data,
stocktakingUserId: data._stocktakingUser?.userId ? [data._stocktakingUser?.userId] : [],
head: data._head?.userId ? [data._head?.userId] : [],
useUserId: data._useUser?.userId ? [data._useUser?.userId] : [],
categoryId: data._category?.categoryId + '',
positionId: data._position?.positionId + '',
ownCompanyId: data._ownCompany?.organizationId + '',
useOrganizationId: data._useOrganization?.organizationId + '',
warehouseId: data._warehouse?.warehouseId,
})
}
this.drawerRef = this.drawer.create({
nzTitle: data ? '编辑盘点任务' : '新增盘点任务',
nzContent: this.formContentTpl,
nzFooter: this.drawerFooterTpl,
nzWidth: 600,
nzOnCancel: this.onCancel.bind(this),
})
}
onDetail(data: NzSafeAny) {
this.drawerRef = this.drawer.create({
nzTitle: data ? '编辑盘点任务' : '新增盘点任务',
nzContent: this.formContentTpl,
nzFooter: this.drawerFooterTpl,
nzWidth: 600,
nzOnCancel: this.onCancel.bind(this),
})
}
onConfirm() {
if (FormValidators.validateFormGroup(this.createForm)) {
const { value } = this.createForm
this.api
.saveStocktakingPlan({
...value,
stocktakingUserId: value.stocktakingUserId?.[0],
head: value.head?.[0],
useUserId: value.useUserId?.[0],
})
.subscribe((res) => {
this.msg.success(res.desc)
this.onCancel()
this.table.ref.reload()
})
}
}
async onCancel() {
this.drawerRef?.close()
this.createForm.reset({
fullStocktaking: 1,
})
}
deleteItem(item: NzSafeAny) {
this.modal.confirm({
nzTitle: '警告',
nzContent: '是否要删除该盘点任务?',
nzOnOk: async () => {
const res = await lastValueFrom(this.api.deleteStocktakingPlan([item.stocktakingJobId]))
this.msg.success(res.desc)
this.table.ref.reload()
},
})
}
onCreateTask(i: NzSafeAny) {
this.modal.confirm({
nzTitle: '警告',
nzContent: '是否要创建盘点任务?',
nzOnOk: async () => {
const res = await lastValueFrom(this.api.createStocktakingJobByPlan([i.stocktakingPlanId]))
this.msg.success(res.desc)
this.table.ref.reload()
},
})
}
}

97
web-admin-app/src/app/pages/fixed-asset/stocktaking/stocktaking-detail/stocktaking-detail.component.html

@ -0,0 +1,97 @@
<app-page>
<div class="flex-1 overflow-hidden">
<app-server-paginated-table
[options]="table"
[formGroup]="queryForm"
[renderColumn]="renderColumnTpl"
[tableAction]="tableActionTpl"
>
<ng-template #tableActionTpl>
<nz-space>
<button *nzSpaceItem nz-button nzType="primary" (click)="add()">新增盘点</button>
<button
*nzSpaceItem
nz-button
nzDanger
[disabled]="table.ref.selected.size === 0"
(click)="deleteItem()"
>
删除
</button>
</nz-space>
</ng-template>
<ng-template #renderColumnTpl let-data let-key="key" let-row="row">
@switch (key) {
@case ('status') {
<nz-tag>
{{ STOCKTAKING_JOB_STATUS_MAP.get(data) }}
</nz-tag>
}
@case ('code') {
{{ row?._asset.assetCode ?? '-' }}
}
@case ('name') {
{{ row?._asset.name ?? '-' }}
}
@case ('category') {
{{ row?._asset._category?.categoryName ?? '-' }}
}
@case ('_warehouse') {
{{ data?.name ?? '-' }}
}
@case ('_position') {
{{ data?.name ?? '-' }}
}
@case ('_head') {
{{ data?.userName ?? '-' }}
}
@case ('_ownCompany') {
{{ data?.organizationName ?? '-' }}
}
@case ('_useOrganization') {
{{ data?.organizationName ?? '-' }}
}
@case ('_category') {
{{ data?.categoryName ?? '-' }}
}
@default {
{{ data }}
}
}
</ng-template>
<!-- <ng-container *appTableAction>
<nz-space>
<button *nzSpaceItem nz-button nzType="link">资产确认</button>
<button *nzSpaceItem nz-button nzType="link" nzDanger="">删除</button>
</nz-space>
</ng-container> -->
<ng-container *appTableForm>
<app-query-item label="资产名称">
<input nz-input placeholder="请输入" formControlName="name" />
</app-query-item>
<app-query-item label="资产编号">
<input nz-input placeholder="请输入" formControlName="assetCode" />
</app-query-item>
<app-query-item label="规格型号">
<input nz-input placeholder="请输入" formControlName="model" />
</app-query-item>
<app-query-item label="序列号">
<input nz-input placeholder="请输入" formControlName="serialNumber" />
</app-query-item>
<app-query-item label="资产状态">
<nz-select
nzPlacement="bottomRight"
class="!w-24"
[nzDropdownMatchSelectWidth]="false"
formControlName="status"
>
@for (item of ASSET_STATUS_MAP | keyvalue; track $index) {
<nz-option [nzLabel]="item.value" [nzValue]="item.key"></nz-option>
}
</nz-select>
</app-query-item>
</ng-container>
</app-server-paginated-table>
</div>
</app-page>

0
web-admin-app/src/app/pages/fixed-asset/stocktaking/stocktaking-detail/stocktaking-detail.component.less

138
web-admin-app/src/app/pages/fixed-asset/stocktaking/stocktaking-detail/stocktaking-detail.component.ts

@ -0,0 +1,138 @@
import { STOCKTAKING_JOB_STATUS_MAP } from './../../../../constants/index'
import {
ChangeDetectorRef,
Component,
EventEmitter,
Input,
OnInit,
Output,
TemplateRef,
ViewChild,
forwardRef,
} from '@angular/core'
import { ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'
import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzModalService } from 'ng-zorro-antd/modal'
import { ApiService } from 'app/services'
import { NzMessageService } from 'ng-zorro-antd/message'
import { SharedModule } from 'app/shared/shared.module'
import { Utils } from 'app/utils'
import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd/tree'
import { NzTreeSelectComponent } from 'ng-zorro-antd/tree-select'
import { ASSET_SOURCE_MAP, ASSET_STATUS_MAP, MAX_PAGE_SIZE } from 'app/constants'
import { AnyObject, TableOption } from 'app/shared/components/server-paginated-table'
import { AssetSelectComponent, StocktakingDetailFormComponent } from 'app/components'
import { lastValueFrom } from 'rxjs'
import { ActivatedRoute } from '@angular/router'
@Component({
selector: 'app-stocktaking-detail',
standalone: true,
imports: [SharedModule],
templateUrl: './stocktaking-detail.component.html',
styleUrl: './stocktaking-detail.component.less',
})
export class StocktakingDetailComponent {
constructor(
private api: ApiService,
private modal: NzModalService,
private msg: NzMessageService,
private route: ActivatedRoute,
) {}
originData: NzSafeAny[] = []
loading = false
ASSET_SOURCE_MAP = ASSET_SOURCE_MAP
ASSET_STATUS_MAP = ASSET_STATUS_MAP()
STOCKTAKING_JOB_STATUS_MAP = STOCKTAKING_JOB_STATUS_MAP
table = new TableOption(this.fetchData.bind(this))
queryForm = new FormGroup({
name: new FormControl(),
model: new FormControl(),
status: new FormControl(),
assetCode: new FormControl(),
serialNumber: new FormControl(),
sourceId: new FormControl(),
positionId: new FormControl(),
manufacturersVendorId: new FormControl(),
})
ngOnInit(): void {
this.api.getBasicSupplierVendorPage({ pageSize: MAX_PAGE_SIZE, pageNum: 1 }).subscribe((res) => {
this.originData = res.body.rows
})
this.table
.setConfig({
selectable: true,
})
.setColumn([
{ key: 'id', title: '主键', visible: true },
{ key: 'code', title: '资产编号', visible: true },
{ key: 'name', title: '资产名称', visible: true },
{ key: 'category', title: '资产分类', visible: true },
{ key: 'status', title: '盘点状态', visible: true },
{ key: 'createTime', title: '操作时间', visible: true },
// { key: '_ownCompany', title: '所属公司', visible: true },
// { key: '_useOrganization', title: '使用组织', visible: true },
// { key: '_position', title: '存放位置', visible: true },
])
}
fetchData(p: {}, q: AnyObject) {
return this.api.getStocktakingJobDetailPage({ ...p, ...q }).pipe()
}
add(data?: NzSafeAny) {
let nzTitle = data ? '编辑资产盘点' : '添加资产盘点'
this.modal.create({
nzTitle,
nzContent: StocktakingDetailFormComponent,
nzWidth: '80vw',
nzWrapClassName: 'modal-lg',
nzData: {
value: data,
},
nzOnOk: async (e) => {
const vals = e.getValues()
if (vals) {
const res = await lastValueFrom(
this.api.saveStocktakingJobDetail({
...vals,
stocktakingJobId: Number(this.route.snapshot.paramMap.get('id')),
}),
)
this.msg.success(res.desc)
this.table.ref.reload()
return true
}
return false
},
})
}
deleteItem() {
this.modal.confirm({
nzTitle: '警告',
nzContent: '是否要删除该盘点?',
nzOnOk: async () => {
const res = await lastValueFrom(
this.api.deleteStocktakingDetail(Array.from(this.table.ref.selected).map((i) => Number(i))),
)
this.msg.success(res.desc)
this.table.ref.reload()
},
})
}
}

13
web-admin-app/src/app/pages/flow/flow-layout/flow-layout.component.html

@ -0,0 +1,13 @@
<div
class="menu bg-white shadow fixed left-0 top-12 bottom-0 z-20 w-48 flex-shrink-0 py-3 overflow-y-auto overflow-x-hidden"
>
<ul nz-menu nzMode="inline">
<li nz-menu-item [nzPaddingLeft]="12" [routerLink]="['/asset-flow/index']" nzMatchRouter>流程首页</li>
<li nz-menu-item [nzPaddingLeft]="12" [routerLink]="['/asset-flow/my-apply']" nzMatchRouter>我的申请</li>
<li nz-menu-item [nzPaddingLeft]="12" [routerLink]="['/asset-flow/my-todo']" nzMatchRouter>待我处理</li>
</ul>
</div>
<div class="pl-48 overflow-hidden">
<router-outlet></router-outlet>
</div>

0
web-admin-app/src/app/pages/flow/flow-layout/flow-layout.component.less

24
web-admin-app/src/app/pages/flow/flow-layout/flow-layout.component.ts

@ -0,0 +1,24 @@
import { Component } from '@angular/core'
import { Router } from '@angular/router'
import { SharedModule } from 'app/shared/shared.module'
@Component({
selector: 'app-flow-layout',
standalone: true,
imports: [SharedModule],
templateUrl: './flow-layout.component.html',
styleUrl: './flow-layout.component.less',
})
export class FlowLayoutComponent {
constructor(private router: Router) {
this.openedSubmenu = this.router.url
}
openedSubmenu = ''
ngOnInit(): void {}
onMenuOpenChange(open: boolean) {
this.openedSubmenu = open ? this.router.url : ''
}
}

18
web-admin-app/src/app/pages/flow/flow-main/flow-main.component.html

@ -0,0 +1,18 @@
<app-page>
<nz-spin [nzSpinning]="loading">
<div nz-row [nzGutter]="[24, 24]">
@for (item of assetFlows; track $index) {
<div nz-col nzSpan="6">
<nz-card [nzBordered]="false" [nzActions]="[actionSetting]">
<div class="h-28">
<div>
{{ item.name }}
</div>
</div>
<ng-template #actionSetting> 发起流程 </ng-template>
</nz-card>
</div>
}
</div>
</nz-spin>
</app-page>

0
web-admin-app/src/app/pages/flow/flow-main/flow-main.component.less

40
web-admin-app/src/app/pages/flow/flow-main/flow-main.component.ts

@ -0,0 +1,40 @@
import { Component, OnInit } from '@angular/core'
import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module'
import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzMessageService } from 'ng-zorro-antd/message'
import { NzModalService } from 'ng-zorro-antd/modal'
import { finalize } from 'rxjs'
@Component({
selector: 'app-flow-main',
standalone: true,
imports: [SharedModule],
templateUrl: './flow-main.component.html',
styleUrl: './flow-main.component.less',
})
export class FlowMainComponent implements OnInit {
constructor(
private api: ApiService,
private msg: NzMessageService,
private modal: NzModalService,
) {}
assetFlows: NzSafeAny[] = []
loading = false
ngOnInit(): void {
this.loading = true
this.api
.getFlowForms({})
.pipe(
finalize(() => {
this.loading = false
}),
)
.subscribe((res) => {
this.assetFlows = res.body
})
}
}

1
web-admin-app/src/app/pages/flow/flow-my-apply/flow-my-apply.component.html

@ -0,0 +1 @@
<p>flow-my-apply works!</p>

0
web-admin-app/src/app/pages/flow/flow-my-apply/flow-my-apply.component.less

12
web-admin-app/src/app/pages/flow/flow-my-apply/flow-my-apply.component.ts

@ -0,0 +1,12 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-flow-my-apply',
standalone: true,
imports: [],
templateUrl: './flow-my-apply.component.html',
styleUrl: './flow-my-apply.component.less'
})
export class FlowMyApplyComponent {
}

1
web-admin-app/src/app/pages/flow/flow-my-todo/flow-my-todo.component.html

@ -0,0 +1 @@
<p>flow-my-todo works!</p>

0
web-admin-app/src/app/pages/flow/flow-my-todo/flow-my-todo.component.less

12
web-admin-app/src/app/pages/flow/flow-my-todo/flow-my-todo.component.ts

@ -0,0 +1,12 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-flow-my-todo',
standalone: true,
imports: [],
templateUrl: './flow-my-todo.component.html',
styleUrl: './flow-my-todo.component.less'
})
export class FlowMyTodoComponent {
}

10
web-admin-app/src/app/pages/profile-account/profile-account.component.html

@ -6,16 +6,22 @@
<input nz-input placeholder="请输入用户名" formControlName="username" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="4" nzRequired> 旧密码 </nz-form-label>
<nz-form-control nzSpan="16">
<input nz-input type="password" placeholder="请输入新密码" formControlName="oldPassword" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="4" nzRequired> 新密码 </nz-form-label>
<nz-form-control nzSpan="16">
<input nz-input type="password" placeholder="请输入新密码" formControlName="password" />
<input nz-input type="password" placeholder="请输入新密码" formControlName="newPassword" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="4" nzRequired> 确认密码 </nz-form-label>
<nz-form-control nzSpan="16">
<input nz-input type="password" placeholder="请再次输入密码" formControlName="confirmPassword" />
<input nz-input type="password" placeholder="请再次输入密码" formControlName="checkPassword" />
</nz-form-control>
</nz-form-item>

31
web-admin-app/src/app/pages/profile-account/profile-account.component.ts

@ -21,24 +21,27 @@ export class ProfileAccountComponent {
formGroup = new FormGroup({
id: new FormControl(),
username: new FormControl({ value: '', disabled: true }, [FormValidators.required('请输入用户名')]),
password: new FormControl('', [FormValidators.required('请输入密码')]),
confirmPassword: new FormControl('', [FormValidators.required('请再次输入密码')]),
username: new FormControl({ value: this.api.authInfo?.loginName, disabled: true }, [
FormValidators.required('请输入用户名'),
]),
oldPassword: new FormControl('', [FormValidators.required('请输入旧密码')]),
newPassword: new FormControl('', [FormValidators.required('请输入新密码')]),
checkPassword: new FormControl('', [FormValidators.required('请再次输入新密码')]),
})
onSubmit() {
if (FormValidators.validateFormGroup(this.formGroup)) {
// if (this.formGroup.value.confirmPassword !== this.formGroup.value.password) {
// this.msg.error('两次输入密码不一致')
// return
// }
// const v = this.formGroup.getRawValue()
// this.api.changePassword(v).subscribe(() => {
// this.msg.success('修改成功,请重新登录').onClose.subscribe(() => {
// this.local.removeAccess()
// window.location.href = '/login'
// })
// })
if (this.formGroup.value.checkPassword !== this.formGroup.value.newPassword) {
this.msg.error('两次输入密码不一致')
return
}
const v = this.formGroup.getRawValue()
this.api.savePassword(v).subscribe(() => {
this.msg.success('修改成功,请重新登录').onClose.subscribe(() => {
this.api.removeAuthData()
window.location.href = '/login'
})
})
}
}
}

17
web-admin-app/src/app/pages/profile-basic/profile-basic.component.html

@ -3,16 +3,27 @@
<nz-form-item>
<nz-form-label nzSpan="4" nzRequired>姓名</nz-form-label>
<nz-form-control nzSpan="16" [nzErrorTip]="formErrorTipsTpl">
<input nz-input placeholder="请输入姓名" formControlName="name" />
<input nz-input placeholder="请输入姓名" formControlName="userName" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="4">手机号</nz-form-label>
<nz-form-control nzSpan="16" [nzErrorTip]="formErrorTipsTpl">
<input nz-input placeholder="请输入姓名" formControlName="phone" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="4">邮箱</nz-form-label>
<nz-form-control nzSpan="16" [nzErrorTip]="formErrorTipsTpl">
<input nz-input placeholder="请输入邮箱" formControlName="email" />
</nz-form-control>
</nz-form-item>
<!-- <nz-form-item>
<nz-form-label nzSpan="4">备注</nz-form-label>
<nz-form-control nzSpan="16">
<textarea nz-input placeholder="请输入备注" formControlName="remark"></textarea>
</nz-form-control>
</nz-form-item>
</nz-form-item> -->
<!-- <nz-form-item>
<nz-form-label nzSpan="4">登录限制</nz-form-label>
<nz-form-control nzSpan="16">

6
web-admin-app/src/app/pages/profile-basic/profile-basic.component.ts

@ -24,7 +24,9 @@ export class ProfileBasicComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.formGroup = this.fb.group({
name: new FormControl('', [FormValidators.required('请输入姓名')]),
userName: new FormControl(this.api.authInfo?.userName, [FormValidators.required('请输入姓名')]),
phone: new FormControl(this.api.authInfo?.['phone']),
email: new FormControl(this.api.authInfo?.['email']),
remark: new FormControl(''),
})
}
@ -42,7 +44,7 @@ export class ProfileBasicComponent implements OnInit, OnDestroy {
onSubmit() {
const vals = this.getValues()
if (vals) {
this.api.saveUser({ ...this.api.authInfo, ...vals }).subscribe(() => {
this.api.saveSelfAccount(vals).subscribe(() => {
this.msg.success('保存成功')
// this.api.getAuthInfo(true).subscribe(() => {})
})

28
web-admin-app/src/app/pages/system/flow/flow-form/flow-form.component.html

@ -0,0 +1,28 @@
<app-page>
<div class="flex-1 overflow-hidden">
<app-server-paginated-table [options]="table" [renderColumn]="renderColumnTpl">
<ng-template #renderColumnTpl let-data let-key="key" let-row="row">
@switch (key) {
@default {
{{ data }}
}
}
</ng-template>
</app-server-paginated-table>
</div>
</app-page>
<ng-template #createFormTpl>
<form nz-form [formGroup]="createForm">
<nz-form-item>
<nz-form-label [nzSpan]="6" [nzRequired]="true">审批人</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="errorTpl">
<app-select-user-by-org formControlName="userId" />
</nz-form-control>
</nz-form-item>
</form>
</ng-template>
<ng-template #errorTpl let-control>
<form-error-tips [control]="control"></form-error-tips>
</ng-template>

0
web-admin-app/src/app/pages/system/flow/flow-form/flow-form.component.less

95
web-admin-app/src/app/pages/system/flow/flow-form/flow-form.component.ts

@ -0,0 +1,95 @@
import { Component, TemplateRef, ViewChild } from '@angular/core'
import { FormControl, FormGroup } from '@angular/forms'
import { AnyObject, TableOption } from 'app/shared/components/server-paginated-table'
import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module'
import { lastValueFrom, map, of } from 'rxjs'
import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message'
import { FormValidators } from 'app/utils'
import { SelectUserByOrgComponent } from 'app/components'
@Component({
selector: 'app-flow-form',
standalone: true,
imports: [SharedModule, SelectUserByOrgComponent],
templateUrl: './flow-form.component.html',
styleUrl: './flow-form.component.less',
})
export class FlowFormComponent {
constructor(
private api: ApiService,
private modal: NzModalService,
private msg: NzMessageService,
) {}
@ViewChild('createFormTpl') createFormTpl!: TemplateRef<{}>
createForm = new FormGroup({
formId: new FormControl(''),
userId: new FormControl('', [FormValidators.required('请选择')]),
})
table = new TableOption(this.fetchData.bind(this))
ngOnInit(): void {
this.table
// .setConfig({
// selectable: true,
// rowKey: 'id',
// })
.setColumn([
{ key: 'formId', title: '主键', visible: true },
{ key: 'formKey', title: '标识', visible: true },
{ key: 'name', title: '名称', visible: true },
{ key: 'deployId', title: '流程ID', visible: true },
// { key: 'createTime', title: '创建时间', visible: true },
])
.setRowOperate([{ title: '设置审批人', onClick: this.onSetApprover.bind(this) }])
}
fetchData(p: {}, q: AnyObject) {
return this.api.getFlowForms({ ...p, ...q }).pipe(
map((r) => {
return {
body: {
rows: r.body,
total: r.body.length,
},
}
}),
)
}
onSetApprover(data?: NzSafeAny) {
if (data) {
this.createForm.patchValue(data)
}
this.modal.create({
nzTitle: '设置审批人',
nzContent: this.createFormTpl,
nzOnOk: async () => {
if (FormValidators.validateFormGroup(this.createForm)) {
const vals = this.createForm.value
const res = await lastValueFrom(
this.api.setFlowFormsAssignee({
...vals,
userId: vals.userId?.[0],
}),
)
this.msg.success(res.desc)
this.table.ref.reload()
this.createForm.reset()
return true
}
return false
},
nzOnCancel: () => {
this.createForm.reset()
},
})
}
}

11
web-admin-app/src/app/pages/system/index/system.component.html

@ -4,6 +4,17 @@
<ul nz-menu nzMode="inline">
<li nz-menu-item [nzPaddingLeft]="12" [routerLink]="['/system/user']" nzMatchRouter>组织架构</li>
<li nz-menu-item [nzPaddingLeft]="12" [routerLink]="['/system/role']" nzMatchRouter>角色管理</li>
<li
nzMatchRouter
[nzPaddingLeft]="12"
nz-submenu
nzTitle="流程管理"
[nzOpen]="openedSubmenu.startsWith('/system/flow/')"
>
<ul>
<li nz-menu-item [nzPaddingLeft]="24" [routerLink]="['/system/flow/form']" nzMatchRouter>表单定义</li>
</ul>
</li>
</ul>
</div>

8
web-admin-app/src/app/pages/system/index/system.component.ts

@ -2,8 +2,6 @@ import { Component } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { SharedModule } from 'app/shared/shared.module'
const pathTabs = ['/system/global-config', '/system/log', '/system/bill']
@Component({
selector: 'app-system',
standalone: true,
@ -13,14 +11,14 @@ const pathTabs = ['/system/global-config', '/system/log', '/system/bill']
})
export class SystemComponent {
constructor(private router: Router) {
this.openedSubmenu = this.router.url.split('/')[2] ?? ''
this.openedSubmenu = this.router.url
}
openedSubmenu = ''
ngOnInit(): void {}
onMenuOpenChange(open: boolean, v: string) {
this.openedSubmenu = open ? v : ''
onMenuOpenChange(open: boolean) {
this.openedSubmenu = open ? this.router.url : ''
}
}

50
web-admin-app/src/app/services/api.service.ts

@ -83,6 +83,12 @@ export class ApiService {
return this.http.post<JwResponse>(`/api/umsUser/delete`, ids)
}
saveSelfAccount(data: NzSafeAny) {
return this.http.post<JwResponse>('/api/umsUser/update/selfInfo', data)
}
savePassword(data: NzSafeAny) {
return this.http.post<JwResponse>('/api/umsUser/update/selfPassword', data)
}
saveUser(data: NzSafeAny) {
if (Utils.isEmpty(data.userId)) {
return this.http.post<JwResponse>('/api/umsUser/add', data)
@ -115,6 +121,9 @@ export class ApiService {
getAssetLog(data: {}) {
return this.http.post<JwResponse>('/api/eamAssetLog/list', data)
}
getAssetRepairLog(data: {}, id: number) {
return this.http.post<JwResponse>(`/api/eamAsset/repair/list?id=${id}`, data)
}
copyAsset(num: number, id: number) {
return this.http.post<JwResponse>(`/api/eamAsset/copyByNum?num=${num}&id=${id}`, null)
}
@ -260,6 +269,37 @@ export class ApiService {
return this.http.post<JwResponse>('/api/eamBasicCategory/delete', ids)
}
getStocktakingPlanPage(data: {}) {
return this.http.post<JwResponse>('/api/eamStocktakingPlan/list', data)
}
saveStocktakingPlan(data: NzSafeAny) {
if (Utils.isEmpty(data.stocktakingJobId)) {
return this.http.post<JwResponse>('/api/eamStocktakingPlan/add', data)
}
return this.http.post<JwResponse>('/api/eamStocktakingPlan/update', data)
}
deleteStocktakingPlan(ids: number[]) {
return this.http.post<JwResponse>(`/api/eamStocktakingPlan/delete`, ids)
}
createStocktakingJobByPlan(ids: number[]) {
return this.http.post<JwResponse>(`/api/eamStocktakingPlan/job`, ids)
}
getStocktakingJobDetailPage(data: {}) {
return this.http.post<JwResponse>('/api/eamStocktakingDetails/list', data)
}
saveStocktakingJobDetail(data: NzSafeAny) {
if (Utils.isEmpty(data.id)) {
return this.http.post<JwResponse>('/api/eamStocktakingDetails/add', data)
}
return this.http.post<JwResponse>('/api/eamStocktakingDetails/update', data)
}
deleteStocktakingDetail(ids: number[]) {
return this.http.post<JwResponse>(`/api/eamStocktakingDetails/delete`, ids)
}
getStocktakingJobPage(data: {}) {
return this.http.post<JwResponse>('/api/eamStocktakingJob/list', data)
}
@ -430,4 +470,14 @@ export class ApiService {
deleteRepairFault(ids: number[]) {
return this.http.post<JwResponse>(`/api/eamRepairFault/delete`, ids)
}
// flow
getFlowForms(data: {}) {
return this.http.post<JwResponse>(`/api/flForm/all`, data)
}
setFlowFormsAssignee(data: {}) {
return this.http.post<JwResponse>(`/api/flForm/assignee`, null, {
params: data,
})
}
}

3
web-admin-app/src/app/shared/components/header/header.component.html

@ -12,6 +12,9 @@
<li class="nav-item">
<a routerLink="/fixed-asset" routerLinkActive="active">固资管理</a>
</li>
<li class="nav-item">
<a routerLink="/asset-flow" routerLinkActive="active">固资流程</a>
</li>
<!-- <li class="nav-item">
<a routerLink="/org" routerLinkActive="active">人事管理</a>
</li> -->

1
web-admin-app/src/app/shared/components/server-paginated-table/server-paginated-table.component.html

@ -78,6 +78,7 @@
<th
nzWidth="60px"
nzLabel="Select all"
[nzDisabled]="!!options.config.radio"
[nzChecked]="selected.size > 0 && tableRef.data.length > 0"
[nzIndeterminate]="indeterminate"
(nzCheckedChange)="onAllChecked($event)"

22
web-admin-app/src/app/shared/components/server-paginated-table/server-paginated-table.component.ts

@ -41,6 +41,8 @@ export interface TableOptionConfigInterface {
manual?: boolean
frontPagination?: boolean
selectable?: boolean
noneCache?: boolean
radio?: boolean
}
export class TableOption {
@ -105,7 +107,7 @@ export class TableOption {
const cachedColumns = this.getCachedColumns()
const cacheKey = this.config.cacheKey!
const currentTableColumns = cachedColumns[cacheKey] ?? []
console.log('currentTableColumns', cachedColumns, cacheKey, currentTableColumns)
// console.log('currentTableColumns', cachedColumns, cacheKey, currentTableColumns)
this.columns = columns.map((i) => {
const cachedItem = currentTableColumns.find((c) => c.key === i.key)
const visible = cachedItem?.visible ?? i.visible
@ -219,6 +221,9 @@ export class ServerPaginatedTableComponent implements OnInit, OnChanges {
}
private setCachedDataToState() {
if (this.options.config.noneCache) {
return
}
const cachedState = this.pageTable.getCachedState()
if (cachedState) {
const cacheKey = this.options.config.cacheKey!
@ -238,6 +243,9 @@ export class ServerPaginatedTableComponent implements OnInit, OnChanges {
}
private saveCacheState() {
if (this.options.config.noneCache) {
return
}
const cachedState = this.pageTable.getCachedState()
const { pageIndex, pageSize } = this.pagination
@ -288,6 +296,9 @@ export class ServerPaginatedTableComponent implements OnInit, OnChanges {
...this.pagination,
...res,
}
// 不允许跨页选择
this.selected.clear()
this.onSelectChange()
})
}
@ -352,16 +363,23 @@ export class ServerPaginatedTableComponent implements OnInit, OnChanges {
onRowSelected(selected: boolean, row: any) {
const id = String(row[this.options.config.rowKey!])
if (this.options.config.radio) {
this.selected.clear()
if (selected) {
this.selected.add(id)
}
} else {
if (selected) {
this.selected.add(id)
} else {
this.selected.delete(id)
}
}
this.onSelectChange()
}
onSelectChange() {
console.log('this.pagination.data', this.pagination.data)
this.indeterminate = this.selected.size > 0 && this.selected.size < this.pagination.data.length
}
}

Loading…
Cancel
Save