@things-factory/kpi 9.0.23 → 9.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/client/pages/kpi/kpi-viz-editor.ts +1 -1
  2. package/client/pages/kpi-category-value/kpi-category-value-list-page.ts +404 -0
  3. package/client/pages/kpi-metric-value/kpi-metric-value-editor-page.ts +763 -0
  4. package/client/pages/kpi-metric-value/kpi-metric-value-list-page.ts +12 -0
  5. package/client/pages/kpi-value/kpi-value-editor-page.ts +774 -0
  6. package/client/pages/kpi-value/kpi-value-list-page.ts +13 -0
  7. package/client/route.ts +16 -0
  8. package/dist-client/pages/kpi/kpi-viz-editor.d.ts +0 -1
  9. package/dist-client/pages/kpi/kpi-viz-editor.js +1 -1
  10. package/dist-client/pages/kpi/kpi-viz-editor.js.map +1 -1
  11. package/dist-client/pages/kpi-category-value/kpi-category-value-list-page.d.ts +63 -0
  12. package/dist-client/pages/kpi-category-value/kpi-category-value-list-page.js +393 -0
  13. package/dist-client/pages/kpi-category-value/kpi-category-value-list-page.js.map +1 -0
  14. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +58 -0
  15. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +736 -0
  16. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -0
  17. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +1 -0
  18. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +11 -0
  19. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -1
  20. package/dist-client/pages/kpi-value/kpi-value-editor-page.d.ts +55 -0
  21. package/dist-client/pages/kpi-value/kpi-value-editor-page.js +748 -0
  22. package/dist-client/pages/kpi-value/kpi-value-editor-page.js.map +1 -0
  23. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +9 -2
  24. package/dist-client/pages/kpi-value/kpi-value-list-page.js +12 -0
  25. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
  26. package/dist-client/route.d.ts +1 -1
  27. package/dist-client/route.js +12 -0
  28. package/dist-client/route.js.map +1 -1
  29. package/dist-client/tsconfig.tsbuildinfo +1 -1
  30. package/dist-server/service/index.d.ts +4 -2
  31. package/dist-server/service/index.js +5 -0
  32. package/dist-server/service/index.js.map +1 -1
  33. package/dist-server/service/kpi-category/kpi-category-mutation.d.ts +2 -3
  34. package/dist-server/service/kpi-category/kpi-category-mutation.js +149 -78
  35. package/dist-server/service/kpi-category/kpi-category-mutation.js.map +1 -1
  36. package/dist-server/service/kpi-category/kpi-category-query.d.ts +1 -9
  37. package/dist-server/service/kpi-category/kpi-category-query.js +3 -165
  38. package/dist-server/service/kpi-category/kpi-category-query.js.map +1 -1
  39. package/dist-server/service/kpi-category-value/index.d.ts +6 -0
  40. package/dist-server/service/kpi-category-value/index.js +10 -0
  41. package/dist-server/service/kpi-category-value/index.js.map +1 -0
  42. package/dist-server/service/kpi-category-value/kpi-category-value-mutation.d.ts +8 -0
  43. package/dist-server/service/kpi-category-value/kpi-category-value-mutation.js +102 -0
  44. package/dist-server/service/kpi-category-value/kpi-category-value-mutation.js.map +1 -0
  45. package/dist-server/service/kpi-category-value/kpi-category-value-query.d.ts +13 -0
  46. package/dist-server/service/kpi-category-value/kpi-category-value-query.js +91 -0
  47. package/dist-server/service/kpi-category-value/kpi-category-value-query.js.map +1 -0
  48. package/dist-server/service/kpi-category-value/kpi-category-value-type.d.ts +19 -0
  49. package/dist-server/service/kpi-category-value/kpi-category-value-type.js +73 -0
  50. package/dist-server/service/kpi-category-value/kpi-category-value-type.js.map +1 -0
  51. package/dist-server/service/kpi-category-value/kpi-category-value.d.ts +19 -0
  52. package/dist-server/service/kpi-category-value/kpi-category-value.js +91 -0
  53. package/dist-server/service/kpi-category-value/kpi-category-value.js.map +1 -0
  54. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +20 -0
  55. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -1
  56. package/dist-server/service/kpi-value/kpi-value-mutation.d.ts +1 -0
  57. package/dist-server/service/kpi-value/kpi-value-mutation.js +60 -0
  58. package/dist-server/service/kpi-value/kpi-value-mutation.js.map +1 -1
  59. package/dist-server/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +5 -5
  61. package/server/service/index.ts +5 -0
  62. package/server/service/kpi-category/kpi-category-mutation.ts +154 -81
  63. package/server/service/kpi-category/kpi-category-query.ts +1 -155
  64. package/server/service/kpi-category-value/index.ts +7 -0
  65. package/server/service/kpi-category-value/kpi-category-value-mutation.ts +88 -0
  66. package/server/service/kpi-category-value/kpi-category-value-query.ts +62 -0
  67. package/server/service/kpi-category-value/kpi-category-value-type.ts +48 -0
  68. package/server/service/kpi-category-value/kpi-category-value.ts +79 -0
  69. package/server/service/kpi-metric-value/kpi-metric-value-mutation.ts +28 -0
  70. package/server/service/kpi-value/kpi-value-mutation.ts +66 -0
  71. package/things-factory.config.js +3 -0
  72. package/translations/en.json +3 -0
  73. package/translations/ja.json +3 -0
  74. package/translations/ko.json +3 -0
  75. package/translations/ms.json +3 -0
  76. package/translations/zh.json +3 -0
@@ -0,0 +1,48 @@
1
+ import { InputType, Field, Float, ObjectType } from 'type-graphql'
2
+ import { KpiPeriodType } from '../kpi/kpi'
3
+ import { KpiCategoryValue } from './kpi-category-value'
4
+
5
+ @InputType()
6
+ export class NewKpiCategoryValue {
7
+ @Field()
8
+ domainId: string
9
+
10
+ @Field()
11
+ categoryId: string
12
+
13
+ @Field({ nullable: true })
14
+ group?: string
15
+
16
+ @Field(type => Float, { nullable: true, description: 'Performance score for this category (0-1 range)' })
17
+ score?: number
18
+
19
+ @Field()
20
+ valueDate: string
21
+ }
22
+
23
+ @InputType()
24
+ export class KpiCategoryValuePatch {
25
+ @Field({ nullable: true })
26
+ domainId?: string
27
+
28
+ @Field({ nullable: true })
29
+ categoryId?: string
30
+
31
+ @Field({ nullable: true })
32
+ group?: string
33
+
34
+ @Field(type => Float, { nullable: true, description: 'Performance score for this category (0-1 range)' })
35
+ score?: number
36
+
37
+ @Field({ nullable: true })
38
+ valueDate?: string
39
+ }
40
+
41
+ @ObjectType()
42
+ export class KpiCategoryValueList {
43
+ @Field(type => [KpiCategoryValue])
44
+ items: KpiCategoryValue[]
45
+
46
+ @Field()
47
+ total: number
48
+ }
@@ -0,0 +1,79 @@
1
+ import {
2
+ Entity,
3
+ PrimaryGeneratedColumn,
4
+ Column,
5
+ Index,
6
+ ManyToOne,
7
+ CreateDateColumn,
8
+ UpdateDateColumn,
9
+ RelationId
10
+ } from 'typeorm'
11
+ import { Field, ObjectType, ID, Float } from 'type-graphql'
12
+ import { Domain } from '@things-factory/shell'
13
+ import { KpiCategory } from '../kpi-category/kpi-category'
14
+ import { User } from '@things-factory/auth-base'
15
+
16
+ @Entity()
17
+ @Index('ix_kpi_category_value_latest', ['domain', 'group', 'category', 'valueDate'], { unique: true })
18
+ @ObjectType({ description: 'Entity for KpiCategoryValue' })
19
+ export class KpiCategoryValue {
20
+ @PrimaryGeneratedColumn('uuid')
21
+ @Field(type => ID, { description: 'Unique identifier for this KPI category value record.' })
22
+ readonly id: string
23
+
24
+ @ManyToOne(() => Domain, { onDelete: 'CASCADE' })
25
+ @Field(type => Domain, { nullable: true, description: 'Domain (tenant) to which this KPI category value belongs.' })
26
+ domain: Domain
27
+
28
+ @RelationId((kpiCategoryValue: KpiCategoryValue) => kpiCategoryValue.domain)
29
+ @Field({ nullable: true, description: 'Domain (tenant) to which this KPI category value belongs.' })
30
+ domainId: string
31
+
32
+ @Column({ default: '' })
33
+ @Field({ nullable: true, description: 'Group key for this value (organization, line, user, etc.)' })
34
+ group?: string
35
+
36
+ @Field(type => Float, { nullable: true, description: 'Performance score for this category (0-1 range).' })
37
+ @Column('float', { nullable: true })
38
+ score?: number
39
+
40
+ @Field({
41
+ nullable: true,
42
+ description:
43
+ 'Date or period for which this KPI category value is recorded (e.g., day: YYYY-MM-DD, month: YYYY-MM, quarter: YYYY-Qn, range: YYYY-MM-DD~YYYY-MM-DD).'
44
+ })
45
+ @Column()
46
+ valueDate: string
47
+
48
+ @ManyToOne(() => KpiCategory, { onDelete: 'CASCADE' })
49
+ @Field(type => KpiCategory, { nullable: true, description: 'KPI category to which this value belongs.' })
50
+ category: KpiCategory
51
+
52
+ @RelationId((kpiCategoryValue: KpiCategoryValue) => kpiCategoryValue.category)
53
+ @Field({ nullable: true, description: 'ID of the domain (tenant) for this KPI category value.' })
54
+ categoryId: string
55
+
56
+ @Field({ nullable: true, description: 'Timestamp when this KPI category value record was created.' })
57
+ @CreateDateColumn()
58
+ createdAt: Date
59
+
60
+ @Field({ nullable: true, description: 'Timestamp when this KPI category value record was last updated.' })
61
+ @UpdateDateColumn()
62
+ updatedAt: Date
63
+
64
+ @ManyToOne(() => User, { nullable: true, onDelete: 'SET NULL' })
65
+ @Field(type => User, { nullable: true, description: 'User who created this KPI category value record.' })
66
+ creator?: User
67
+
68
+ @RelationId((kpiCategoryValue: KpiCategoryValue) => kpiCategoryValue.creator)
69
+ @Field({ nullable: true, description: 'ID of the user who created this KPI category value record.' })
70
+ creatorId?: string
71
+
72
+ @ManyToOne(() => User, { nullable: true, onDelete: 'SET NULL' })
73
+ @Field(type => User, { nullable: true, description: 'User who last updated this KPI category value record.' })
74
+ updater?: User
75
+
76
+ @RelationId((kpiCategoryValue: KpiCategoryValue) => kpiCategoryValue.updater)
77
+ @Field({ nullable: true, description: 'ID of the user who last updated this KPI category value record.' })
78
+ updaterId?: string
79
+ }
@@ -151,8 +151,22 @@ export class KpiMetricValueMutation {
151
151
  if (_createRecords.length > 0) {
152
152
  for (let i = 0; i < _createRecords.length; i++) {
153
153
  const newRecord = _createRecords[i]
154
+
155
+ if (!newRecord.metricId) {
156
+ throw new Error('metricId is required for creating new metric value')
157
+ }
158
+
159
+ const metric = await getRepository(KpiMetric).findOne({
160
+ where: { domain: { id: domain.id }, id: newRecord.metricId }
161
+ })
162
+
163
+ if (!metric) {
164
+ throw new Error(`Metric not found: ${newRecord.metricId}`)
165
+ }
166
+
154
167
  const result = await metricValueRepo.save({
155
168
  ...newRecord,
169
+ metric,
156
170
  domain,
157
171
  creator: user,
158
172
  updater: user
@@ -165,9 +179,23 @@ export class KpiMetricValueMutation {
165
179
  for (let i = 0; i < _updateRecords.length; i++) {
166
180
  const updateRecord = _updateRecords[i]
167
181
  const metricValue = await metricValueRepo.findOneBy({ id: updateRecord.id })
182
+
183
+ if (!updateRecord.metricId) {
184
+ throw new Error('metricId is required for updating value')
185
+ }
186
+
187
+ const metric = await getRepository(KpiMetric).findOne({
188
+ where: { domain: { id: domain.id }, id: updateRecord.metricId }
189
+ })
190
+
191
+ if (!metric) {
192
+ throw new Error(`Metric not found: ${updateRecord.metricId}`)
193
+ }
194
+
168
195
  const result = await metricValueRepo.save({
169
196
  ...metricValue,
170
197
  ...updateRecord,
198
+ metric,
171
199
  updater: user
172
200
  } as any)
173
201
  results.push({ ...result, cuFlag: 'M' })
@@ -54,6 +54,60 @@ export class KpiValueMutation {
54
54
  return await getRepository(KpiValue, tx).save(entity)
55
55
  }
56
56
 
57
+ @Directive('@transaction')
58
+ @Mutation(returns => [KpiValue], { description: 'Create multiple KPI values with the provided details.' })
59
+ async createMultipleKpiValue(
60
+ @Arg('values', type => [NewKpiValue], {
61
+ description: 'Array of input objects containing details for the new KPI values.'
62
+ })
63
+ values: NewKpiValue[],
64
+ @Ctx() context: ResolverContext
65
+ ): Promise<KpiValue[]> {
66
+ const { domain, user, tx } = context.state
67
+ const repository = getRepository(KpiValue, tx)
68
+ const scoreService = new KpiValueScoreService()
69
+
70
+ const entities: KpiValue[] = []
71
+
72
+ for (const kpiValue of values) {
73
+ let kpi = kpiValue.kpiId ? await getRepository(Kpi).findOne({ where: { id: kpiValue.kpiId } }) : undefined
74
+
75
+ let inputType: KpiValueInputType | undefined = undefined
76
+ if (kpiValue.inputType) {
77
+ if (typeof kpiValue.inputType === 'string') {
78
+ inputType = KpiValueInputType[kpiValue.inputType as keyof typeof KpiValueInputType]
79
+ } else {
80
+ inputType = kpiValue.inputType
81
+ }
82
+ }
83
+
84
+ const entity: Partial<KpiValue> = {
85
+ kpi,
86
+ kpiId: kpiValue.kpiId,
87
+ version: kpiValue.version || 1,
88
+ valueDate: kpiValue.valueDate,
89
+ value: kpiValue.value,
90
+ group: kpiValue.group || '',
91
+ source: kpiValue.source || 'MANUAL',
92
+ domain: domain,
93
+ creator: user,
94
+ updater: user
95
+ }
96
+ if (inputType) entity.inputType = inputType
97
+
98
+ const savedEntity = await repository.save(entity)
99
+
100
+ // 성과 점수 자동 계산 및 저장
101
+ if (kpi) {
102
+ await scoreService.calculateAndSaveScore(savedEntity, kpi)
103
+ }
104
+
105
+ entities.push(savedEntity)
106
+ }
107
+
108
+ return entities
109
+ }
110
+
57
111
  @Directive('@transaction')
58
112
  @Mutation(returns => KpiValue, { description: 'To modify KpiValue information' })
59
113
  async updateKpiValue(
@@ -109,8 +163,14 @@ export class KpiValueMutation {
109
163
  for (let i = 0; i < _createRecords.length; i++) {
110
164
  const newRecord = _createRecords[i]
111
165
 
166
+ const kpi = await getRepository(Kpi, tx).findOne({
167
+ where: { domain: { id: domain.id }, id: newRecord.kpiId }
168
+ })
169
+
112
170
  const result = await kpiValueRepo.save({
113
171
  ...newRecord,
172
+ kpi,
173
+ version: newRecord.version || kpi.version,
114
174
  domain,
115
175
  creator: user,
116
176
  updater: user
@@ -125,9 +185,15 @@ export class KpiValueMutation {
125
185
  const updateRecord = _updateRecords[i]
126
186
  const kpiValue = await kpiValueRepo.findOneBy({ id: updateRecord.id })
127
187
 
188
+ const kpi = await getRepository(Kpi, tx).findOne({
189
+ where: { domain: { id: domain.id }, id: updateRecord.kpiId }
190
+ })
191
+
128
192
  const result = await kpiValueRepo.save({
129
193
  ...kpiValue,
130
194
  ...updateRecord,
195
+ kpi,
196
+ version: updateRecord.version || kpi.version,
131
197
  updater: user
132
198
  } as any)
133
199
 
@@ -8,9 +8,12 @@ export default {
8
8
  { tagname: 'kpi-dashboard', page: 'kpi-dashboard' },
9
9
  { tagname: 'kpi-list-page', page: 'kpi-list' },
10
10
  { tagname: 'kpi-category-list-page', page: 'kpi-category-list' },
11
+ { tagname: 'kpi-category-value-list-page', page: 'kpi-category-value-list' },
11
12
  { tagname: 'kpi-metric-list-page', page: 'kpi-metric-list' },
12
13
  { tagname: 'kpi-value-list-page', page: 'kpi-value-list' },
14
+ { tagname: 'kpi-value-editor-page', page: 'kpi-value-editor' },
13
15
  { tagname: 'kpi-metric-value-list-page', page: 'kpi-metric-value-list' },
16
+ { tagname: 'kpi-metric-value-editor-page', page: 'kpi-metric-value-editor' },
14
17
  { tagname: 'kpi-value-manual-entry-page', page: 'kpi-value-manual-entry' },
15
18
  { tagname: 'kpi-metric-value-manual-entry-page', page: 'kpi-metric-value-manual-entry' },
16
19
  { tagname: 'kpi-history-list-page', page: 'kpi-history-list' }
@@ -5,10 +5,13 @@
5
5
  "label.functions": "functions",
6
6
  "title.kpi list": "KPI List",
7
7
  "title.kpi category list": "KPI Catogory List",
8
+ "title.kpi category value list": "KPI Category Value List",
9
+ "title.kpi value editor": "KPI Value Editor",
8
10
  "title.kpi grade list": "KPI Grade List",
9
11
  "title.kpi metric list": "KPI Metric List",
10
12
  "title.kpi value list": "KPI Value List",
11
13
  "title.kpi metric value list": "KPI Metric Value List",
14
+ "title.kpi metric value editor": "KPI Metric Value Editor",
12
15
  "title.kpi performance board": "KPI Performance Board",
13
16
  "title.kpi management center": "KPI Management Center",
14
17
  "title.kpi overview": "KPI Overview",
@@ -5,10 +5,13 @@
5
5
  "label.functions": "함수",
6
6
  "title.kpi list": "KPI リスト",
7
7
  "title.kpi category list": "KPI カテゴリ リスト",
8
+ "title.kpi category value list": "KPI カテゴリ 値 リスト",
9
+ "title.kpi value editor": "KPI 値 エディター",
8
10
  "title.kpi grade list": "KPI グレード リスト",
9
11
  "title.kpi metric list": "KPI メトリック リスト",
10
12
  "title.kpi value list": "KPI 値 リスト",
11
13
  "title.kpi metric value list": "KPI メトリック 値 リスト",
14
+ "title.kpi metric value editor": "KPI メトリック 値 エディター",
12
15
  "title.kpi performance board": "KPI パフォーマンス ボード",
13
16
  "title.kpi management center": "KPI 管理 センター",
14
17
  "title.kpi overview": "KPI 概要",
@@ -5,10 +5,13 @@
5
5
  "label.functions": "함수",
6
6
  "title.kpi list": "KPI 목록",
7
7
  "title.kpi category list": "KPI 카테고리 목록",
8
+ "title.kpi category value list": "KPI 카테고리 값 목록",
9
+ "title.kpi value editor": "KPI 값 편집기",
8
10
  "title.kpi grade list": "KPI 등급 목록",
9
11
  "title.kpi metric list": "KPI 메트릭 목록",
10
12
  "title.kpi value list": "KPI 값 목록",
11
13
  "title.kpi metric value list": "KPI 메트릭 값 목록",
14
+ "title.kpi metric value editor": "KPI 메트릭 값 편집기",
12
15
  "title.kpi performance board": "KPI 성과 보드",
13
16
  "title.kpi management center": "KPI 관리 센터",
14
17
  "title.kpi overview": "KPI 개요",
@@ -5,10 +5,13 @@
5
5
  "label.functions": "functions",
6
6
  "title.kpi list": "Senarai KPI",
7
7
  "title.kpi category list": "Senarai Kategori KPI",
8
+ "title.kpi category value list": "Senarai Nilai Kategori KPI",
9
+ "title.kpi value editor": "KPI Nilai Editor",
8
10
  "title.kpi grade list": "Senarai Gred KPI",
9
11
  "title.kpi metric list": "Senarai Metrik KPI",
10
12
  "title.kpi value list": "Senarai Nilai KPI",
11
13
  "title.kpi metric value list": "Senarai Metrik KPI",
14
+ "title.kpi metric value editor": "KPI Metrik Editor",
12
15
  "title.kpi performance board": "Papan KPI",
13
16
  "title.kpi management center": "Pusat Pengurusan KPI",
14
17
  "title.kpi overview": "Pengenalan KPI",
@@ -5,10 +5,13 @@
5
5
  "label.functions": "函数",
6
6
  "title.kpi list": "KPI 列表",
7
7
  "title.kpi category list": "KPI 分类列表",
8
+ "title.kpi category value list": "KPI 分类值列表",
9
+ "title.kpi value editor": "KPI 值编辑器",
8
10
  "title.kpi grade list": "KPI 等级列表",
9
11
  "title.kpi metric list": "KPI 指标列表",
10
12
  "title.kpi value list": "KPI 值列表",
11
13
  "title.kpi metric value list": "KPI 指标值列表",
14
+ "title.kpi metric value editor": "KPI 指标值编辑器",
12
15
  "title.kpi performance board": "KPI 绩效看板",
13
16
  "title.kpi management center": "KPI 管理中心",
14
17
  "title.kpi overview": "KPI 概述",