数据源修改

This commit is contained in:
cheney 2026-08-06 15:24:55 +08:00
parent b10b1c44db
commit ec15f40323
24 changed files with 2289 additions and 131 deletions

View File

@ -37,6 +37,11 @@ export type Strategy = Prisma.StrategyModel
* *
*/ */
export type Indicator = Prisma.IndicatorModel export type Indicator = Prisma.IndicatorModel
/**
* Model IndicatorPoint
*
*/
export type IndicatorPoint = Prisma.IndicatorPointModel
/** /**
* Model Econ_SowInventory * Model Econ_SowInventory
* *

View File

@ -61,6 +61,11 @@ export type Strategy = Prisma.StrategyModel
* *
*/ */
export type Indicator = Prisma.IndicatorModel export type Indicator = Prisma.IndicatorModel
/**
* Model IndicatorPoint
*
*/
export type IndicatorPoint = Prisma.IndicatorPointModel
/** /**
* Model Econ_SowInventory * Model Econ_SowInventory
* *

View File

@ -150,6 +150,46 @@ export type JsonWithAggregatesFilterBase<$PrismaModel = never> = {
_max?: Prisma.NestedJsonFilter<$PrismaModel> _max?: Prisma.NestedJsonFilter<$PrismaModel>
} }
export type BoolFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
}
export type BoolWithAggregatesFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedBoolFilter<$PrismaModel>
_max?: Prisma.NestedBoolFilter<$PrismaModel>
}
export type FloatFilter<$PrismaModel = never> = {
equals?: number | Prisma.FloatFieldRefInput<$PrismaModel>
in?: number[]
notIn?: number[]
lt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
lte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
gt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
gte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
not?: Prisma.NestedFloatFilter<$PrismaModel> | number
}
export type FloatWithAggregatesFilter<$PrismaModel = never> = {
equals?: number | Prisma.FloatFieldRefInput<$PrismaModel>
in?: number[]
notIn?: number[]
lt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
lte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
gt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
gte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
not?: Prisma.NestedFloatWithAggregatesFilter<$PrismaModel> | number
_count?: Prisma.NestedIntFilter<$PrismaModel>
_avg?: Prisma.NestedFloatFilter<$PrismaModel>
_sum?: Prisma.NestedFloatFilter<$PrismaModel>
_min?: Prisma.NestedFloatFilter<$PrismaModel>
_max?: Prisma.NestedFloatFilter<$PrismaModel>
}
export type StringNullableFilter<$PrismaModel = never> = { export type StringNullableFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | null in?: string[] | null
@ -359,6 +399,35 @@ export type NestedJsonFilterBase<$PrismaModel = never> = {
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
} }
export type NestedBoolFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
}
export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedBoolFilter<$PrismaModel>
_max?: Prisma.NestedBoolFilter<$PrismaModel>
}
export type NestedFloatWithAggregatesFilter<$PrismaModel = never> = {
equals?: number | Prisma.FloatFieldRefInput<$PrismaModel>
in?: number[]
notIn?: number[]
lt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
lte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
gt?: number | Prisma.FloatFieldRefInput<$PrismaModel>
gte?: number | Prisma.FloatFieldRefInput<$PrismaModel>
not?: Prisma.NestedFloatWithAggregatesFilter<$PrismaModel> | number
_count?: Prisma.NestedIntFilter<$PrismaModel>
_avg?: Prisma.NestedFloatFilter<$PrismaModel>
_sum?: Prisma.NestedFloatFilter<$PrismaModel>
_min?: Prisma.NestedFloatFilter<$PrismaModel>
_max?: Prisma.NestedFloatFilter<$PrismaModel>
}
export type NestedStringNullableFilter<$PrismaModel = never> = { export type NestedStringNullableFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | null in?: string[] | null

File diff suppressed because one or more lines are too long

View File

@ -388,6 +388,7 @@ export const ModelName = {
Article: 'Article', Article: 'Article',
Strategy: 'Strategy', Strategy: 'Strategy',
Indicator: 'Indicator', Indicator: 'Indicator',
IndicatorPoint: 'IndicatorPoint',
Econ_SowInventory: 'Econ_SowInventory', Econ_SowInventory: 'Econ_SowInventory',
ScraperCache: 'ScraperCache' ScraperCache: 'ScraperCache'
} as const } as const
@ -405,7 +406,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
omit: GlobalOmitOptions omit: GlobalOmitOptions
} }
meta: { meta: {
modelProps: "user" | "article" | "strategy" | "indicator" | "econ_SowInventory" | "scraperCache" modelProps: "user" | "article" | "strategy" | "indicator" | "indicatorPoint" | "econ_SowInventory" | "scraperCache"
txIsolationLevel: TransactionIsolationLevel txIsolationLevel: TransactionIsolationLevel
} }
model: { model: {
@ -673,6 +674,72 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
} }
} }
} }
IndicatorPoint: {
payload: Prisma.$IndicatorPointPayload<ExtArgs>
fields: Prisma.IndicatorPointFieldRefs
operations: {
findUnique: {
args: Prisma.IndicatorPointFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$IndicatorPointPayload> | null
}
findUniqueOrThrow: {
args: Prisma.IndicatorPointFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$IndicatorPointPayload>
}
findFirst: {
args: Prisma.IndicatorPointFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$IndicatorPointPayload> | null
}
findFirstOrThrow: {
args: Prisma.IndicatorPointFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$IndicatorPointPayload>
}
findMany: {
args: Prisma.IndicatorPointFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$IndicatorPointPayload>[]
}
create: {
args: Prisma.IndicatorPointCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$IndicatorPointPayload>
}
createMany: {
args: Prisma.IndicatorPointCreateManyArgs<ExtArgs>
result: BatchPayload
}
delete: {
args: Prisma.IndicatorPointDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$IndicatorPointPayload>
}
update: {
args: Prisma.IndicatorPointUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$IndicatorPointPayload>
}
deleteMany: {
args: Prisma.IndicatorPointDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.IndicatorPointUpdateManyArgs<ExtArgs>
result: BatchPayload
}
upsert: {
args: Prisma.IndicatorPointUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$IndicatorPointPayload>
}
aggregate: {
args: Prisma.IndicatorPointAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateIndicatorPoint>
}
groupBy: {
args: Prisma.IndicatorPointGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.IndicatorPointGroupByOutputType>[]
}
count: {
args: Prisma.IndicatorPointCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.IndicatorPointCountAggregateOutputType> | number
}
}
}
Econ_SowInventory: { Econ_SowInventory: {
payload: Prisma.$Econ_SowInventoryPayload<ExtArgs> payload: Prisma.$Econ_SowInventoryPayload<ExtArgs>
fields: Prisma.Econ_SowInventoryFieldRefs fields: Prisma.Econ_SowInventoryFieldRefs
@ -885,7 +952,11 @@ export const IndicatorScalarFieldEnum = {
id: 'id', id: 'id',
name: 'name', name: 'name',
groupName: 'groupName', groupName: 'groupName',
data: 'data', title: 'title',
unit: 'unit',
source: 'source',
frequency: 'frequency',
hidden: 'hidden',
createdAt: 'createdAt', createdAt: 'createdAt',
updatedAt: 'updatedAt' updatedAt: 'updatedAt'
} as const } as const
@ -893,6 +964,18 @@ export const IndicatorScalarFieldEnum = {
export type IndicatorScalarFieldEnum = (typeof IndicatorScalarFieldEnum)[keyof typeof IndicatorScalarFieldEnum] export type IndicatorScalarFieldEnum = (typeof IndicatorScalarFieldEnum)[keyof typeof IndicatorScalarFieldEnum]
export const IndicatorPointScalarFieldEnum = {
id: 'id',
indicatorId: 'indicatorId',
period: 'period',
value: 'value',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type IndicatorPointScalarFieldEnum = (typeof IndicatorPointScalarFieldEnum)[keyof typeof IndicatorPointScalarFieldEnum]
export const Econ_SowInventoryScalarFieldEnum = { export const Econ_SowInventoryScalarFieldEnum = {
id: 'id', id: 'id',
month: 'month', month: 'month',
@ -986,12 +1069,23 @@ export type StrategyOrderByRelevanceFieldEnum = (typeof StrategyOrderByRelevance
export const IndicatorOrderByRelevanceFieldEnum = { export const IndicatorOrderByRelevanceFieldEnum = {
name: 'name', name: 'name',
groupName: 'groupName' groupName: 'groupName',
title: 'title',
unit: 'unit',
source: 'source',
frequency: 'frequency'
} as const } as const
export type IndicatorOrderByRelevanceFieldEnum = (typeof IndicatorOrderByRelevanceFieldEnum)[keyof typeof IndicatorOrderByRelevanceFieldEnum] export type IndicatorOrderByRelevanceFieldEnum = (typeof IndicatorOrderByRelevanceFieldEnum)[keyof typeof IndicatorOrderByRelevanceFieldEnum]
export const IndicatorPointOrderByRelevanceFieldEnum = {
period: 'period'
} as const
export type IndicatorPointOrderByRelevanceFieldEnum = (typeof IndicatorPointOrderByRelevanceFieldEnum)[keyof typeof IndicatorPointOrderByRelevanceFieldEnum]
export const Econ_SowInventoryOrderByRelevanceFieldEnum = { export const Econ_SowInventoryOrderByRelevanceFieldEnum = {
month: 'month' month: 'month'
} as const } as const
@ -1056,6 +1150,13 @@ export type EnumQueryModeFieldRefInput<$PrismaModel> = FieldRefInputType<$Prisma
/**
* Reference to a field of type 'Boolean'
*/
export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'>
/** /**
* Reference to a field of type 'Float' * Reference to a field of type 'Float'
*/ */
@ -1161,6 +1262,7 @@ export type GlobalOmitConfig = {
article?: Prisma.ArticleOmit article?: Prisma.ArticleOmit
strategy?: Prisma.StrategyOmit strategy?: Prisma.StrategyOmit
indicator?: Prisma.IndicatorOmit indicator?: Prisma.IndicatorOmit
indicatorPoint?: Prisma.IndicatorPointOmit
econ_SowInventory?: Prisma.Econ_SowInventoryOmit econ_SowInventory?: Prisma.Econ_SowInventoryOmit
scraperCache?: Prisma.ScraperCacheOmit scraperCache?: Prisma.ScraperCacheOmit
} }

View File

@ -55,6 +55,7 @@ export const ModelName = {
Article: 'Article', Article: 'Article',
Strategy: 'Strategy', Strategy: 'Strategy',
Indicator: 'Indicator', Indicator: 'Indicator',
IndicatorPoint: 'IndicatorPoint',
Econ_SowInventory: 'Econ_SowInventory', Econ_SowInventory: 'Econ_SowInventory',
ScraperCache: 'ScraperCache' ScraperCache: 'ScraperCache'
} as const } as const
@ -116,7 +117,11 @@ export const IndicatorScalarFieldEnum = {
id: 'id', id: 'id',
name: 'name', name: 'name',
groupName: 'groupName', groupName: 'groupName',
data: 'data', title: 'title',
unit: 'unit',
source: 'source',
frequency: 'frequency',
hidden: 'hidden',
createdAt: 'createdAt', createdAt: 'createdAt',
updatedAt: 'updatedAt' updatedAt: 'updatedAt'
} as const } as const
@ -124,6 +129,18 @@ export const IndicatorScalarFieldEnum = {
export type IndicatorScalarFieldEnum = (typeof IndicatorScalarFieldEnum)[keyof typeof IndicatorScalarFieldEnum] export type IndicatorScalarFieldEnum = (typeof IndicatorScalarFieldEnum)[keyof typeof IndicatorScalarFieldEnum]
export const IndicatorPointScalarFieldEnum = {
id: 'id',
indicatorId: 'indicatorId',
period: 'period',
value: 'value',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type IndicatorPointScalarFieldEnum = (typeof IndicatorPointScalarFieldEnum)[keyof typeof IndicatorPointScalarFieldEnum]
export const Econ_SowInventoryScalarFieldEnum = { export const Econ_SowInventoryScalarFieldEnum = {
id: 'id', id: 'id',
month: 'month', month: 'month',
@ -217,12 +234,23 @@ export type StrategyOrderByRelevanceFieldEnum = (typeof StrategyOrderByRelevance
export const IndicatorOrderByRelevanceFieldEnum = { export const IndicatorOrderByRelevanceFieldEnum = {
name: 'name', name: 'name',
groupName: 'groupName' groupName: 'groupName',
title: 'title',
unit: 'unit',
source: 'source',
frequency: 'frequency'
} as const } as const
export type IndicatorOrderByRelevanceFieldEnum = (typeof IndicatorOrderByRelevanceFieldEnum)[keyof typeof IndicatorOrderByRelevanceFieldEnum] export type IndicatorOrderByRelevanceFieldEnum = (typeof IndicatorOrderByRelevanceFieldEnum)[keyof typeof IndicatorOrderByRelevanceFieldEnum]
export const IndicatorPointOrderByRelevanceFieldEnum = {
period: 'period'
} as const
export type IndicatorPointOrderByRelevanceFieldEnum = (typeof IndicatorPointOrderByRelevanceFieldEnum)[keyof typeof IndicatorPointOrderByRelevanceFieldEnum]
export const Econ_SowInventoryOrderByRelevanceFieldEnum = { export const Econ_SowInventoryOrderByRelevanceFieldEnum = {
month: 'month' month: 'month'
} as const } as const

View File

@ -12,6 +12,7 @@ export type * from './models/User.ts'
export type * from './models/Article.ts' export type * from './models/Article.ts'
export type * from './models/Strategy.ts' export type * from './models/Strategy.ts'
export type * from './models/Indicator.ts' export type * from './models/Indicator.ts'
export type * from './models/IndicatorPoint.ts'
export type * from './models/Econ_SowInventory.ts' export type * from './models/Econ_SowInventory.ts'
export type * from './models/ScraperCache.ts' export type * from './models/ScraperCache.ts'
export type * from './commonInputTypes.ts' export type * from './commonInputTypes.ts'

View File

@ -38,6 +38,11 @@ export type IndicatorMinAggregateOutputType = {
id: number | null id: number | null
name: string | null name: string | null
groupName: string | null groupName: string | null
title: string | null
unit: string | null
source: string | null
frequency: string | null
hidden: boolean | null
createdAt: Date | null createdAt: Date | null
updatedAt: Date | null updatedAt: Date | null
} }
@ -46,6 +51,11 @@ export type IndicatorMaxAggregateOutputType = {
id: number | null id: number | null
name: string | null name: string | null
groupName: string | null groupName: string | null
title: string | null
unit: string | null
source: string | null
frequency: string | null
hidden: boolean | null
createdAt: Date | null createdAt: Date | null
updatedAt: Date | null updatedAt: Date | null
} }
@ -54,7 +64,11 @@ export type IndicatorCountAggregateOutputType = {
id: number id: number
name: number name: number
groupName: number groupName: number
data: number title: number
unit: number
source: number
frequency: number
hidden: number
createdAt: number createdAt: number
updatedAt: number updatedAt: number
_all: number _all: number
@ -73,6 +87,11 @@ export type IndicatorMinAggregateInputType = {
id?: true id?: true
name?: true name?: true
groupName?: true groupName?: true
title?: true
unit?: true
source?: true
frequency?: true
hidden?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
} }
@ -81,6 +100,11 @@ export type IndicatorMaxAggregateInputType = {
id?: true id?: true
name?: true name?: true
groupName?: true groupName?: true
title?: true
unit?: true
source?: true
frequency?: true
hidden?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
} }
@ -89,7 +113,11 @@ export type IndicatorCountAggregateInputType = {
id?: true id?: true
name?: true name?: true
groupName?: true groupName?: true
data?: true title?: true
unit?: true
source?: true
frequency?: true
hidden?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
_all?: true _all?: true
@ -185,7 +213,11 @@ export type IndicatorGroupByOutputType = {
id: number id: number
name: string name: string
groupName: string groupName: string
data: runtime.JsonValue title: string
unit: string
source: string
frequency: string
hidden: boolean
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date
_count: IndicatorCountAggregateOutputType | null _count: IndicatorCountAggregateOutputType | null
@ -217,18 +249,28 @@ export type IndicatorWhereInput = {
id?: Prisma.IntFilter<"Indicator"> | number id?: Prisma.IntFilter<"Indicator"> | number
name?: Prisma.StringFilter<"Indicator"> | string name?: Prisma.StringFilter<"Indicator"> | string
groupName?: Prisma.StringFilter<"Indicator"> | string groupName?: Prisma.StringFilter<"Indicator"> | string
data?: Prisma.JsonFilter<"Indicator"> title?: Prisma.StringFilter<"Indicator"> | string
unit?: Prisma.StringFilter<"Indicator"> | string
source?: Prisma.StringFilter<"Indicator"> | string
frequency?: Prisma.StringFilter<"Indicator"> | string
hidden?: Prisma.BoolFilter<"Indicator"> | boolean
createdAt?: Prisma.DateTimeFilter<"Indicator"> | Date | string createdAt?: Prisma.DateTimeFilter<"Indicator"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"Indicator"> | Date | string updatedAt?: Prisma.DateTimeFilter<"Indicator"> | Date | string
points?: Prisma.IndicatorPointListRelationFilter
} }
export type IndicatorOrderByWithRelationInput = { export type IndicatorOrderByWithRelationInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
name?: Prisma.SortOrder name?: Prisma.SortOrder
groupName?: Prisma.SortOrder groupName?: Prisma.SortOrder
data?: Prisma.SortOrder title?: Prisma.SortOrder
unit?: Prisma.SortOrder
source?: Prisma.SortOrder
frequency?: Prisma.SortOrder
hidden?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
points?: Prisma.IndicatorPointOrderByRelationAggregateInput
_relevance?: Prisma.IndicatorOrderByRelevanceInput _relevance?: Prisma.IndicatorOrderByRelevanceInput
} }
@ -239,16 +281,25 @@ export type IndicatorWhereUniqueInput = Prisma.AtLeast<{
OR?: Prisma.IndicatorWhereInput[] OR?: Prisma.IndicatorWhereInput[]
NOT?: Prisma.IndicatorWhereInput | Prisma.IndicatorWhereInput[] NOT?: Prisma.IndicatorWhereInput | Prisma.IndicatorWhereInput[]
groupName?: Prisma.StringFilter<"Indicator"> | string groupName?: Prisma.StringFilter<"Indicator"> | string
data?: Prisma.JsonFilter<"Indicator"> title?: Prisma.StringFilter<"Indicator"> | string
unit?: Prisma.StringFilter<"Indicator"> | string
source?: Prisma.StringFilter<"Indicator"> | string
frequency?: Prisma.StringFilter<"Indicator"> | string
hidden?: Prisma.BoolFilter<"Indicator"> | boolean
createdAt?: Prisma.DateTimeFilter<"Indicator"> | Date | string createdAt?: Prisma.DateTimeFilter<"Indicator"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"Indicator"> | Date | string updatedAt?: Prisma.DateTimeFilter<"Indicator"> | Date | string
points?: Prisma.IndicatorPointListRelationFilter
}, "id" | "name"> }, "id" | "name">
export type IndicatorOrderByWithAggregationInput = { export type IndicatorOrderByWithAggregationInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
name?: Prisma.SortOrder name?: Prisma.SortOrder
groupName?: Prisma.SortOrder groupName?: Prisma.SortOrder
data?: Prisma.SortOrder title?: Prisma.SortOrder
unit?: Prisma.SortOrder
source?: Prisma.SortOrder
frequency?: Prisma.SortOrder
hidden?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
_count?: Prisma.IndicatorCountOrderByAggregateInput _count?: Prisma.IndicatorCountOrderByAggregateInput
@ -265,7 +316,11 @@ export type IndicatorScalarWhereWithAggregatesInput = {
id?: Prisma.IntWithAggregatesFilter<"Indicator"> | number id?: Prisma.IntWithAggregatesFilter<"Indicator"> | number
name?: Prisma.StringWithAggregatesFilter<"Indicator"> | string name?: Prisma.StringWithAggregatesFilter<"Indicator"> | string
groupName?: Prisma.StringWithAggregatesFilter<"Indicator"> | string groupName?: Prisma.StringWithAggregatesFilter<"Indicator"> | string
data?: Prisma.JsonWithAggregatesFilter<"Indicator"> title?: Prisma.StringWithAggregatesFilter<"Indicator"> | string
unit?: Prisma.StringWithAggregatesFilter<"Indicator"> | string
source?: Prisma.StringWithAggregatesFilter<"Indicator"> | string
frequency?: Prisma.StringWithAggregatesFilter<"Indicator"> | string
hidden?: Prisma.BoolWithAggregatesFilter<"Indicator"> | boolean
createdAt?: Prisma.DateTimeWithAggregatesFilter<"Indicator"> | Date | string createdAt?: Prisma.DateTimeWithAggregatesFilter<"Indicator"> | Date | string
updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Indicator"> | Date | string updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Indicator"> | Date | string
} }
@ -273,42 +328,66 @@ export type IndicatorScalarWhereWithAggregatesInput = {
export type IndicatorCreateInput = { export type IndicatorCreateInput = {
name: string name: string
groupName: string groupName: string
data: Prisma.JsonNullValueInput | runtime.InputJsonValue title?: string
unit?: string
source?: string
frequency?: string
hidden?: boolean
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
points?: Prisma.IndicatorPointCreateNestedManyWithoutIndicatorInput
} }
export type IndicatorUncheckedCreateInput = { export type IndicatorUncheckedCreateInput = {
id?: number id?: number
name: string name: string
groupName: string groupName: string
data: Prisma.JsonNullValueInput | runtime.InputJsonValue title?: string
unit?: string
source?: string
frequency?: string
hidden?: boolean
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
points?: Prisma.IndicatorPointUncheckedCreateNestedManyWithoutIndicatorInput
} }
export type IndicatorUpdateInput = { export type IndicatorUpdateInput = {
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
groupName?: Prisma.StringFieldUpdateOperationsInput | string groupName?: Prisma.StringFieldUpdateOperationsInput | string
data?: Prisma.JsonNullValueInput | runtime.InputJsonValue title?: Prisma.StringFieldUpdateOperationsInput | string
unit?: Prisma.StringFieldUpdateOperationsInput | string
source?: Prisma.StringFieldUpdateOperationsInput | string
frequency?: Prisma.StringFieldUpdateOperationsInput | string
hidden?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
points?: Prisma.IndicatorPointUpdateManyWithoutIndicatorNestedInput
} }
export type IndicatorUncheckedUpdateInput = { export type IndicatorUncheckedUpdateInput = {
id?: Prisma.IntFieldUpdateOperationsInput | number id?: Prisma.IntFieldUpdateOperationsInput | number
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
groupName?: Prisma.StringFieldUpdateOperationsInput | string groupName?: Prisma.StringFieldUpdateOperationsInput | string
data?: Prisma.JsonNullValueInput | runtime.InputJsonValue title?: Prisma.StringFieldUpdateOperationsInput | string
unit?: Prisma.StringFieldUpdateOperationsInput | string
source?: Prisma.StringFieldUpdateOperationsInput | string
frequency?: Prisma.StringFieldUpdateOperationsInput | string
hidden?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
points?: Prisma.IndicatorPointUncheckedUpdateManyWithoutIndicatorNestedInput
} }
export type IndicatorCreateManyInput = { export type IndicatorCreateManyInput = {
id?: number id?: number
name: string name: string
groupName: string groupName: string
data: Prisma.JsonNullValueInput | runtime.InputJsonValue title?: string
unit?: string
source?: string
frequency?: string
hidden?: boolean
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
} }
@ -316,7 +395,11 @@ export type IndicatorCreateManyInput = {
export type IndicatorUpdateManyMutationInput = { export type IndicatorUpdateManyMutationInput = {
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
groupName?: Prisma.StringFieldUpdateOperationsInput | string groupName?: Prisma.StringFieldUpdateOperationsInput | string
data?: Prisma.JsonNullValueInput | runtime.InputJsonValue title?: Prisma.StringFieldUpdateOperationsInput | string
unit?: Prisma.StringFieldUpdateOperationsInput | string
source?: Prisma.StringFieldUpdateOperationsInput | string
frequency?: Prisma.StringFieldUpdateOperationsInput | string
hidden?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
} }
@ -325,7 +408,11 @@ export type IndicatorUncheckedUpdateManyInput = {
id?: Prisma.IntFieldUpdateOperationsInput | number id?: Prisma.IntFieldUpdateOperationsInput | number
name?: Prisma.StringFieldUpdateOperationsInput | string name?: Prisma.StringFieldUpdateOperationsInput | string
groupName?: Prisma.StringFieldUpdateOperationsInput | string groupName?: Prisma.StringFieldUpdateOperationsInput | string
data?: Prisma.JsonNullValueInput | runtime.InputJsonValue title?: Prisma.StringFieldUpdateOperationsInput | string
unit?: Prisma.StringFieldUpdateOperationsInput | string
source?: Prisma.StringFieldUpdateOperationsInput | string
frequency?: Prisma.StringFieldUpdateOperationsInput | string
hidden?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
} }
@ -340,7 +427,11 @@ export type IndicatorCountOrderByAggregateInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
name?: Prisma.SortOrder name?: Prisma.SortOrder
groupName?: Prisma.SortOrder groupName?: Prisma.SortOrder
data?: Prisma.SortOrder title?: Prisma.SortOrder
unit?: Prisma.SortOrder
source?: Prisma.SortOrder
frequency?: Prisma.SortOrder
hidden?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
} }
@ -353,6 +444,11 @@ export type IndicatorMaxOrderByAggregateInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
name?: Prisma.SortOrder name?: Prisma.SortOrder
groupName?: Prisma.SortOrder groupName?: Prisma.SortOrder
title?: Prisma.SortOrder
unit?: Prisma.SortOrder
source?: Prisma.SortOrder
frequency?: Prisma.SortOrder
hidden?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
} }
@ -361,6 +457,11 @@ export type IndicatorMinOrderByAggregateInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
name?: Prisma.SortOrder name?: Prisma.SortOrder
groupName?: Prisma.SortOrder groupName?: Prisma.SortOrder
title?: Prisma.SortOrder
unit?: Prisma.SortOrder
source?: Prisma.SortOrder
frequency?: Prisma.SortOrder
hidden?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
} }
@ -369,15 +470,139 @@ export type IndicatorSumOrderByAggregateInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
} }
export type IndicatorScalarRelationFilter = {
is?: Prisma.IndicatorWhereInput
isNot?: Prisma.IndicatorWhereInput
}
export type BoolFieldUpdateOperationsInput = {
set?: boolean
}
export type IndicatorCreateNestedOneWithoutPointsInput = {
create?: Prisma.XOR<Prisma.IndicatorCreateWithoutPointsInput, Prisma.IndicatorUncheckedCreateWithoutPointsInput>
connectOrCreate?: Prisma.IndicatorCreateOrConnectWithoutPointsInput
connect?: Prisma.IndicatorWhereUniqueInput
}
export type IndicatorUpdateOneRequiredWithoutPointsNestedInput = {
create?: Prisma.XOR<Prisma.IndicatorCreateWithoutPointsInput, Prisma.IndicatorUncheckedCreateWithoutPointsInput>
connectOrCreate?: Prisma.IndicatorCreateOrConnectWithoutPointsInput
upsert?: Prisma.IndicatorUpsertWithoutPointsInput
connect?: Prisma.IndicatorWhereUniqueInput
update?: Prisma.XOR<Prisma.XOR<Prisma.IndicatorUpdateToOneWithWhereWithoutPointsInput, Prisma.IndicatorUpdateWithoutPointsInput>, Prisma.IndicatorUncheckedUpdateWithoutPointsInput>
}
export type IndicatorCreateWithoutPointsInput = {
name: string
groupName: string
title?: string
unit?: string
source?: string
frequency?: string
hidden?: boolean
createdAt?: Date | string
updatedAt?: Date | string
}
export type IndicatorUncheckedCreateWithoutPointsInput = {
id?: number
name: string
groupName: string
title?: string
unit?: string
source?: string
frequency?: string
hidden?: boolean
createdAt?: Date | string
updatedAt?: Date | string
}
export type IndicatorCreateOrConnectWithoutPointsInput = {
where: Prisma.IndicatorWhereUniqueInput
create: Prisma.XOR<Prisma.IndicatorCreateWithoutPointsInput, Prisma.IndicatorUncheckedCreateWithoutPointsInput>
}
export type IndicatorUpsertWithoutPointsInput = {
update: Prisma.XOR<Prisma.IndicatorUpdateWithoutPointsInput, Prisma.IndicatorUncheckedUpdateWithoutPointsInput>
create: Prisma.XOR<Prisma.IndicatorCreateWithoutPointsInput, Prisma.IndicatorUncheckedCreateWithoutPointsInput>
where?: Prisma.IndicatorWhereInput
}
export type IndicatorUpdateToOneWithWhereWithoutPointsInput = {
where?: Prisma.IndicatorWhereInput
data: Prisma.XOR<Prisma.IndicatorUpdateWithoutPointsInput, Prisma.IndicatorUncheckedUpdateWithoutPointsInput>
}
export type IndicatorUpdateWithoutPointsInput = {
name?: Prisma.StringFieldUpdateOperationsInput | string
groupName?: Prisma.StringFieldUpdateOperationsInput | string
title?: Prisma.StringFieldUpdateOperationsInput | string
unit?: Prisma.StringFieldUpdateOperationsInput | string
source?: Prisma.StringFieldUpdateOperationsInput | string
frequency?: Prisma.StringFieldUpdateOperationsInput | string
hidden?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
}
export type IndicatorUncheckedUpdateWithoutPointsInput = {
id?: Prisma.IntFieldUpdateOperationsInput | number
name?: Prisma.StringFieldUpdateOperationsInput | string
groupName?: Prisma.StringFieldUpdateOperationsInput | string
title?: Prisma.StringFieldUpdateOperationsInput | string
unit?: Prisma.StringFieldUpdateOperationsInput | string
source?: Prisma.StringFieldUpdateOperationsInput | string
frequency?: Prisma.StringFieldUpdateOperationsInput | string
hidden?: Prisma.BoolFieldUpdateOperationsInput | boolean
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
}
/**
* Count Type IndicatorCountOutputType
*/
export type IndicatorCountOutputType = {
points: number
}
export type IndicatorCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
points?: boolean | IndicatorCountOutputTypeCountPointsArgs
}
/**
* IndicatorCountOutputType without action
*/
export type IndicatorCountOutputTypeDefaultArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
/**
* Select specific fields to fetch from the IndicatorCountOutputType
*/
select?: Prisma.IndicatorCountOutputTypeSelect<ExtArgs> | null
}
/**
* IndicatorCountOutputType without action
*/
export type IndicatorCountOutputTypeCountPointsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
where?: Prisma.IndicatorPointWhereInput
}
export type IndicatorSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{ export type IndicatorSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
id?: boolean id?: boolean
name?: boolean name?: boolean
groupName?: boolean groupName?: boolean
data?: boolean title?: boolean
unit?: boolean
source?: boolean
frequency?: boolean
hidden?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
points?: boolean | Prisma.Indicator$pointsArgs<ExtArgs>
_count?: boolean | Prisma.IndicatorCountOutputTypeDefaultArgs<ExtArgs>
}, ExtArgs["result"]["indicator"]> }, ExtArgs["result"]["indicator"]>
@ -386,21 +611,35 @@ export type IndicatorSelectScalar = {
id?: boolean id?: boolean
name?: boolean name?: boolean
groupName?: boolean groupName?: boolean
data?: boolean title?: boolean
unit?: boolean
source?: boolean
frequency?: boolean
hidden?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
} }
export type IndicatorOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "groupName" | "data" | "createdAt" | "updatedAt", ExtArgs["result"]["indicator"]> export type IndicatorOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "groupName" | "title" | "unit" | "source" | "frequency" | "hidden" | "createdAt" | "updatedAt", ExtArgs["result"]["indicator"]>
export type IndicatorInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
points?: boolean | Prisma.Indicator$pointsArgs<ExtArgs>
_count?: boolean | Prisma.IndicatorCountOutputTypeDefaultArgs<ExtArgs>
}
export type $IndicatorPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = { export type $IndicatorPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
name: "Indicator" name: "Indicator"
objects: {} objects: {
points: Prisma.$IndicatorPointPayload<ExtArgs>[]
}
scalars: runtime.Types.Extensions.GetPayloadResult<{ scalars: runtime.Types.Extensions.GetPayloadResult<{
id: number id: number
name: string name: string
groupName: string groupName: string
data: runtime.JsonValue title: string
unit: string
source: string
frequency: string
hidden: boolean
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date
}, ExtArgs["result"]["indicator"]> }, ExtArgs["result"]["indicator"]>
@ -743,6 +982,7 @@ readonly fields: IndicatorFieldRefs;
*/ */
export interface Prisma__IndicatorClient<T, Null = never, ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs, GlobalOmitOptions = {}> extends Prisma.PrismaPromise<T> { export interface Prisma__IndicatorClient<T, Null = never, ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs, GlobalOmitOptions = {}> extends Prisma.PrismaPromise<T> {
readonly [Symbol.toStringTag]: "PrismaPromise" readonly [Symbol.toStringTag]: "PrismaPromise"
points<T extends Prisma.Indicator$pointsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Indicator$pointsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$IndicatorPointPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
/** /**
* Attaches callbacks for the resolution and/or rejection of the Promise. * Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved. * @param onfulfilled The callback to execute when the Promise is resolved.
@ -775,7 +1015,11 @@ export interface IndicatorFieldRefs {
readonly id: Prisma.FieldRef<"Indicator", 'Int'> readonly id: Prisma.FieldRef<"Indicator", 'Int'>
readonly name: Prisma.FieldRef<"Indicator", 'String'> readonly name: Prisma.FieldRef<"Indicator", 'String'>
readonly groupName: Prisma.FieldRef<"Indicator", 'String'> readonly groupName: Prisma.FieldRef<"Indicator", 'String'>
readonly data: Prisma.FieldRef<"Indicator", 'Json'> readonly title: Prisma.FieldRef<"Indicator", 'String'>
readonly unit: Prisma.FieldRef<"Indicator", 'String'>
readonly source: Prisma.FieldRef<"Indicator", 'String'>
readonly frequency: Prisma.FieldRef<"Indicator", 'String'>
readonly hidden: Prisma.FieldRef<"Indicator", 'Boolean'>
readonly createdAt: Prisma.FieldRef<"Indicator", 'DateTime'> readonly createdAt: Prisma.FieldRef<"Indicator", 'DateTime'>
readonly updatedAt: Prisma.FieldRef<"Indicator", 'DateTime'> readonly updatedAt: Prisma.FieldRef<"Indicator", 'DateTime'>
} }
@ -794,6 +1038,10 @@ export type IndicatorFindUniqueArgs<ExtArgs extends runtime.Types.Extensions.Int
* Omit specific fields from the Indicator * Omit specific fields from the Indicator
*/ */
omit?: Prisma.IndicatorOmit<ExtArgs> | null omit?: Prisma.IndicatorOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.IndicatorInclude<ExtArgs> | null
/** /**
* Filter, which Indicator to fetch. * Filter, which Indicator to fetch.
*/ */
@ -812,6 +1060,10 @@ export type IndicatorFindUniqueOrThrowArgs<ExtArgs extends runtime.Types.Extensi
* Omit specific fields from the Indicator * Omit specific fields from the Indicator
*/ */
omit?: Prisma.IndicatorOmit<ExtArgs> | null omit?: Prisma.IndicatorOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.IndicatorInclude<ExtArgs> | null
/** /**
* Filter, which Indicator to fetch. * Filter, which Indicator to fetch.
*/ */
@ -830,6 +1082,10 @@ export type IndicatorFindFirstArgs<ExtArgs extends runtime.Types.Extensions.Inte
* Omit specific fields from the Indicator * Omit specific fields from the Indicator
*/ */
omit?: Prisma.IndicatorOmit<ExtArgs> | null omit?: Prisma.IndicatorOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.IndicatorInclude<ExtArgs> | null
/** /**
* Filter, which Indicator to fetch. * Filter, which Indicator to fetch.
*/ */
@ -878,6 +1134,10 @@ export type IndicatorFindFirstOrThrowArgs<ExtArgs extends runtime.Types.Extensio
* Omit specific fields from the Indicator * Omit specific fields from the Indicator
*/ */
omit?: Prisma.IndicatorOmit<ExtArgs> | null omit?: Prisma.IndicatorOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.IndicatorInclude<ExtArgs> | null
/** /**
* Filter, which Indicator to fetch. * Filter, which Indicator to fetch.
*/ */
@ -926,6 +1186,10 @@ export type IndicatorFindManyArgs<ExtArgs extends runtime.Types.Extensions.Inter
* Omit specific fields from the Indicator * Omit specific fields from the Indicator
*/ */
omit?: Prisma.IndicatorOmit<ExtArgs> | null omit?: Prisma.IndicatorOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.IndicatorInclude<ExtArgs> | null
/** /**
* Filter, which Indicators to fetch. * Filter, which Indicators to fetch.
*/ */
@ -974,6 +1238,10 @@ export type IndicatorCreateArgs<ExtArgs extends runtime.Types.Extensions.Interna
* Omit specific fields from the Indicator * Omit specific fields from the Indicator
*/ */
omit?: Prisma.IndicatorOmit<ExtArgs> | null omit?: Prisma.IndicatorOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.IndicatorInclude<ExtArgs> | null
/** /**
* The data needed to create a Indicator. * The data needed to create a Indicator.
*/ */
@ -1003,6 +1271,10 @@ export type IndicatorUpdateArgs<ExtArgs extends runtime.Types.Extensions.Interna
* Omit specific fields from the Indicator * Omit specific fields from the Indicator
*/ */
omit?: Prisma.IndicatorOmit<ExtArgs> | null omit?: Prisma.IndicatorOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.IndicatorInclude<ExtArgs> | null
/** /**
* The data needed to update a Indicator. * The data needed to update a Indicator.
*/ */
@ -1043,6 +1315,10 @@ export type IndicatorUpsertArgs<ExtArgs extends runtime.Types.Extensions.Interna
* Omit specific fields from the Indicator * Omit specific fields from the Indicator
*/ */
omit?: Prisma.IndicatorOmit<ExtArgs> | null omit?: Prisma.IndicatorOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.IndicatorInclude<ExtArgs> | null
/** /**
* The filter to search for the Indicator to update in case it exists. * The filter to search for the Indicator to update in case it exists.
*/ */
@ -1069,6 +1345,10 @@ export type IndicatorDeleteArgs<ExtArgs extends runtime.Types.Extensions.Interna
* Omit specific fields from the Indicator * Omit specific fields from the Indicator
*/ */
omit?: Prisma.IndicatorOmit<ExtArgs> | null omit?: Prisma.IndicatorOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.IndicatorInclude<ExtArgs> | null
/** /**
* Filter which Indicator to delete. * Filter which Indicator to delete.
*/ */
@ -1089,6 +1369,30 @@ export type IndicatorDeleteManyArgs<ExtArgs extends runtime.Types.Extensions.Int
limit?: number limit?: number
} }
/**
* Indicator.points
*/
export type Indicator$pointsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
/**
* Select specific fields to fetch from the IndicatorPoint
*/
select?: Prisma.IndicatorPointSelect<ExtArgs> | null
/**
* Omit specific fields from the IndicatorPoint
*/
omit?: Prisma.IndicatorPointOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.IndicatorPointInclude<ExtArgs> | null
where?: Prisma.IndicatorPointWhereInput
orderBy?: Prisma.IndicatorPointOrderByWithRelationInput | Prisma.IndicatorPointOrderByWithRelationInput[]
cursor?: Prisma.IndicatorPointWhereUniqueInput
take?: number
skip?: number
distinct?: Prisma.IndicatorPointScalarFieldEnum | Prisma.IndicatorPointScalarFieldEnum[]
}
/** /**
* Indicator without action * Indicator without action
*/ */
@ -1101,4 +1405,8 @@ export type IndicatorDefaultArgs<ExtArgs extends runtime.Types.Extensions.Intern
* Omit specific fields from the Indicator * Omit specific fields from the Indicator
*/ */
omit?: Prisma.IndicatorOmit<ExtArgs> | null omit?: Prisma.IndicatorOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.IndicatorInclude<ExtArgs> | null
} }

File diff suppressed because it is too large Load Diff

View File

@ -234,15 +234,15 @@ export type StrategyOrderByWithRelationInput = {
export type StrategyWhereUniqueInput = Prisma.AtLeast<{ export type StrategyWhereUniqueInput = Prisma.AtLeast<{
id?: number id?: number
name?: string
AND?: Prisma.StrategyWhereInput | Prisma.StrategyWhereInput[] AND?: Prisma.StrategyWhereInput | Prisma.StrategyWhereInput[]
OR?: Prisma.StrategyWhereInput[] OR?: Prisma.StrategyWhereInput[]
NOT?: Prisma.StrategyWhereInput | Prisma.StrategyWhereInput[] NOT?: Prisma.StrategyWhereInput | Prisma.StrategyWhereInput[]
name?: Prisma.StringFilter<"Strategy"> | string
description?: Prisma.StringFilter<"Strategy"> | string description?: Prisma.StringFilter<"Strategy"> | string
data?: Prisma.JsonFilter<"Strategy"> data?: Prisma.JsonFilter<"Strategy">
createdAt?: Prisma.DateTimeFilter<"Strategy"> | Date | string createdAt?: Prisma.DateTimeFilter<"Strategy"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"Strategy"> | Date | string updatedAt?: Prisma.DateTimeFilter<"Strategy"> | Date | string
}, "id" | "name"> }, "id">
export type StrategyOrderByWithAggregationInput = { export type StrategyOrderByWithAggregationInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder

View File

@ -0,0 +1,24 @@
-- 经济指标: 明细数据拆到独立表, 兼容年/季/月/日频率
-- 第一步: 建 IndicatorPoint 表 + Indicator 加元数据列 (data 列暂保留, 由迁移脚本搬运后删除)
-- CreateTable
CREATE TABLE `IndicatorPoint` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`indicatorId` INTEGER NOT NULL,
`period` VARCHAR(191) NOT NULL,
`value` DOUBLE NOT NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `IndicatorPoint_indicatorId_period_key`(`indicatorId`, `period`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AlterTable: 元数据列 (data JSON 拆出)
ALTER TABLE `Indicator` ADD COLUMN `title` VARCHAR(191) NOT NULL DEFAULT '',
ADD COLUMN `unit` VARCHAR(191) NOT NULL DEFAULT '',
ADD COLUMN `source` VARCHAR(191) NOT NULL DEFAULT '',
ADD COLUMN `frequency` VARCHAR(191) NOT NULL DEFAULT 'month';
-- AddForeignKey
ALTER TABLE `IndicatorPoint` ADD CONSTRAINT `IndicatorPoint_indicatorId_fkey` FOREIGN KEY (`indicatorId`) REFERENCES `Indicator`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -0,0 +1,3 @@
-- 第二步: 明细数据已迁移到 IndicatorPoint, 删除 Indicator.data JSON 列
-- AlterTable
ALTER TABLE `Indicator` DROP COLUMN `data`;

View File

@ -0,0 +1,2 @@
-- 指标隐藏标记: 数据与获取脚本保留, 前端展示过滤 hidden=true
ALTER TABLE `Indicator` ADD COLUMN `hidden` BOOLEAN NOT NULL DEFAULT false;

View File

@ -41,12 +41,29 @@ model Strategy {
} }
model Indicator { model Indicator {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
name String name String @unique
groupName String groupName String
data Json title String @default("")
createdAt DateTime @default(now()) unit String @default("")
updatedAt DateTime @updatedAt source String @default("")
frequency String @default("month") // year | quarter | month | day
hidden Boolean @default(false) // true = 数据/脚本保留, 但不在前端展示
points IndicatorPoint[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model IndicatorPoint {
id Int @id @default(autoincrement())
indicatorId Int
indicator Indicator @relation(fields: [indicatorId], references: [id], onDelete: Cascade)
period String // "2024" | "2024-Q1" | "2024-01" | "2024-01-15"
value Float
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([indicatorId, period])
} }
model Econ_SowInventory { model Econ_SowInventory {
@ -66,3 +83,5 @@ model ScraperCache {
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
} }

20
readme
View File

@ -6,18 +6,18 @@
## 新闻模块
增加一个新闻模块,数据来源是每日夜间 3点通过妙想 MCP 获取国内外最新经济政治新闻按影响大小排序10条。
存入数据库。
## 报警模块
World Bank 中的数据只用来对比妙想 MCP 拉取的数据正确性。当同一时间的同一项数据不同时,记录一个报警。
## 首页 ## 首页
首页显示新闻模块和报警模块的数据,按照时间最新优先,无限滚动,直到数据库中没有数据为止。 首页显示新闻模块和报警模块的数据,按照时间最新优先,无限滚动,直到数据库中没有数据为止。
### 新闻模块
增加一个新闻模块,数据来源是每日夜间 3点通过妙想 MCP 获取国内外最新经济政治新闻按影响大小排序10条。
存入数据库。
### 报警模块
World Bank 中的数据只用来对比妙想 MCP 拉取的数据正确性。当同一时间的同一项数据不同时,记录一个报警。

View File

@ -50,6 +50,59 @@ const INDICATORS = [
sheets.find((s) => s.items?.[0]?.[0]?.includes('GDP') && s.items[0][0].includes('同比')) sheets.find((s) => s.items?.[0]?.[0]?.includes('GDP') && s.items[0][0].includes('同比'))
|| sheets[0], || sheets[0],
}, },
{
// 国债收益率: MCP 返回日频, 用月末降采样成月频点
name: 'china-bond-10y',
groupName: 'china-macro',
title: '中国国债 10 年期收益率',
unit: '%',
frequency: 'month',
tool: 'mx_macro_data',
query: '查询中国10年期国债到期收益率 2024年至今 每日数据',
pickSheet: (sheets) =>
sheets.find((s) => s.items?.some?.((row) => String(row[0] || '').includes('国债到期收益率:10年')))
|| sheets[0],
parseSheet: (sheet) => monthEndSample(sheet, '国债到期收益率:10年'),
},
{
name: 'china-bond-1y',
groupName: 'china-macro',
title: '中国国债 1 年期收益率',
unit: '%',
frequency: 'month',
tool: 'mx_macro_data',
query: '查询中国1年期国债到期收益率 2024年至今 每日数据',
pickSheet: (sheets) =>
sheets.find((s) => s.items?.some?.((row) => String(row[0] || '').includes('国债到期收益率:1年')))
|| sheets[0],
parseSheet: (sheet) => monthEndSample(sheet, '国债到期收益率:1年'),
},
{
name: 'china-lpr-1y',
groupName: 'china-macro',
title: '中国 LPR 1 年期',
unit: '%',
frequency: 'month',
tool: 'mx_macro_data',
query: '查询中国LPR 1年期贷款市场报价利率 2024年至今 月度数据,每一个月的数值',
pickSheet: (sheets) =>
sheets.find((s) => s.sheetName?.includes('宏观数据(月)'))
|| sheets[0],
parseSheet: (sheet) => pickRowByKeyword(sheet, '(LPR):1年'),
},
{
name: 'china-lpr-5y',
groupName: 'china-macro',
title: '中国 LPR 5 年期',
unit: '%',
frequency: 'month',
tool: 'mx_macro_data',
query: '查询中国LPR 5年期以上贷款市场报价利率 2024年至今 月度数据,每一个月的数值',
pickSheet: (sheets) =>
sheets.find((s) => s.sheetName?.includes('宏观数据(月)'))
|| sheets[0],
parseSheet: (sheet) => pickRowByKeyword(sheet, '(LPR):5年'),
},
] ]
export const META = { export const META = {
@ -139,6 +192,44 @@ function defaultParseSheet(sheet) {
return out.reverse() // 从老到新 return out.reverse() // 从老到新
} }
// 宽表 → 长表, 指定 item 行 (按指标全名前缀匹配), 日频列降采样为月末值
// 例: columns=["指标","来源","2026-08-05","2026-08-04",...] → [{period:"2024-01",value},...]
function monthEndSample(sheet, keyword) {
if (!sheet || !sheet.columns || !sheet.items) return []
const row = sheet.items.find((r) => String(r[0] || '').includes(keyword))
if (!row) return []
const cols = sheet.columns
const dates = cols.slice(2) // 新 → 老
const values = row.slice(2)
const out = []
const seen = new Set()
for (let i = 0; i < dates.length; i++) {
const v = parseFloat(values[i])
const m = String(dates[i] || '').slice(0, 7) // "2024-01-02" → "2024-01"
if (!/^\d{4}-\d{2}$/.test(m) || Number.isNaN(v)) continue
if (seen.has(m)) continue // 列是降序, 第一次遇到的即当月最后一个交易日
seen.add(m)
out.push({ period: m, value: v })
}
return out.reverse() // 从老到新
}
// 宽表 → 长表, 指定 item 行 (按指标全名前缀匹配), 保留原频率 (月/季/年)
function pickRowByKeyword(sheet, keyword) {
if (!sheet || !sheet.columns || !sheet.items) return []
const row = sheet.items.find((r) => String(r[0] || '').includes(keyword))
if (!row) return []
const cols = sheet.columns
const dates = cols.slice(2)
const values = row.slice(2)
const out = []
for (let i = 0; i < dates.length; i++) {
const v = parseFloat(values[i])
if (!Number.isNaN(v)) out.push({ period: String(dates[i]), value: v })
}
return out.reverse() // 从老到新
}
// ====== fetcher 入口 ====== // ====== fetcher 入口 ======
export async function listAvailableTools() { export async function listAvailableTools() {
@ -156,6 +247,7 @@ export async function fetchAll(opts = {}) {
throw new Error('eastmoney-mcp: INDICATORS 数组为空, 加新指标见文件顶部注释') throw new Error('eastmoney-mcp: INDICATORS 数组为空, 加新指标见文件顶部注释')
} }
const skip = opts.skipNames || new Set() const skip = opts.skipNames || new Set()
const force = opts.forceNames || new Set()
const only = opts.onlyNames || null const only = opts.onlyNames || null
const key = process.env.EM_API_KEY const key = process.env.EM_API_KEY
@ -165,7 +257,7 @@ export async function fetchAll(opts = {}) {
const results = [] const results = []
for (const cfg of INDICATORS) { for (const cfg of INDICATORS) {
if (skip.has(cfg.name)) { if (skip.has(cfg.name) && !force.has(cfg.name)) {
console.log(`[MCP] ${cfg.name} 跳过 (DB 已存在)`) console.log(`[MCP] ${cfg.name} 跳过 (DB 已存在)`)
continue continue
} }
@ -199,7 +291,7 @@ export async function fetchAll(opts = {}) {
} }
} }
// 全部被 DB 优先跳过时, 返回显式标记而不是空数组 (避免被误判为失败) // 全部被 DB 优先跳过时, 返回显式标记而不是空数组 (避免被误判为失败)
if (results.length === 0 && INDICATORS.every((cfg) => skip.has(cfg.name))) { if (results.length === 0 && INDICATORS.every((cfg) => skip.has(cfg.name) && !force.has(cfg.name))) {
return { skipped: true, reason: 'DB 已存在全部指标' } return { skipped: true, reason: 'DB 已存在全部指标' }
} }
return results return results
@ -208,3 +300,4 @@ export async function fetchAll(opts = {}) {

View File

@ -36,7 +36,8 @@ export function checkEnv(required) {
// 加载并运行所有启用的 fetcher, 返回 [{ name, ok, items, error, skipped }] // 加载并运行所有启用的 fetcher, 返回 [{ name, ok, items, error, skipped }]
// 错误隔离: 一个 fetcher 挂了不影响其他 // 错误隔离: 一个 fetcher 挂了不影响其他
// opts.skipNames: Set<string> — DB 优先, 已存在的指标名, 透传给 fetcher // opts.skipNames: Set<string> — DB 优先, 已存在的指标名, 透传给 fetcher
// opts.forceNames: Set<string> — 强制刷新名单, 即使 skipNames 里有也照拉
export async function runFetchers(opts = {}) { export async function runFetchers(opts = {}) {
const results = [] const results = []
for (const meta of FETCHERS) { for (const meta of FETCHERS) {
@ -57,7 +58,7 @@ export async function runFetchers(opts = {}) {
throw new Error('fetcher 必须导出 META 和 fetchAll') throw new Error('fetcher 必须导出 META 和 fetchAll')
} }
console.log(`[Fetcher] ${meta.name} 开始...`) console.log(`[Fetcher] ${meta.name} 开始...`)
const out = await mod.fetchAll({ skipNames: opts.skipNames, onlyNames: opts.onlyNames }) const out = await mod.fetchAll({ skipNames: opts.skipNames, onlyNames: opts.onlyNames, forceNames: opts.forceNames })
// fetcher 可返回 { skipped: true, reason } 表示"全部被 DB 优先跳过", 不算失败 // fetcher 可返回 { skipped: true, reason } 表示"全部被 DB 优先跳过", 不算失败
if (out && out.skipped) { if (out && out.skipped) {
results.push({ name: meta.name, skipped: true, reason: out.reason }) results.push({ name: meta.name, skipped: true, reason: out.reason })

View File

@ -0,0 +1,84 @@
/**
* 一次性数据迁移: Indicator.data (JSON) 拆分到 IndicatorPoint 明细表
* 用法: 在迁移 A (建表+加列) 之后迁移 B ( data ) 之前运行
* 幂等: (indicatorId, period) 重复插入会更新 value, 可安全重跑
*/
require('dotenv').config()
const mysql = require('mysql2/promise')
function parseUrl(url) {
const u = new URL(url)
return {
host: u.hostname,
port: Number(u.port) || 3306,
user: decodeURIComponent(u.username),
password: decodeURIComponent(u.password),
database: u.pathname.replace(/^\//, ''),
}
}
// 根据 row 的时间字段推断频率: year | quarter | month | day
function inferFrequency(row) {
if (row && row.month !== undefined) return 'month'
if (row && row.year !== undefined) return 'year'
const p = String((row && row.period) || '')
if (/^\d{4}$/.test(p)) return 'year'
if (/^\d{4}-Q[1-4]$/.test(p)) return 'quarter'
if (/^\d{4}-\d{2}$/.test(p)) return 'month'
if (/^\d{4}-\d{2}-\d{2}$/.test(p)) return 'day'
return 'month'
}
// 统一 row 的时间字段为 period
function periodOf(row) {
if (!row) return ''
return String(row.period !== undefined ? row.period : (row.month !== undefined ? row.month : row.year))
}
async function main() {
const conn = await mysql.createConnection(parseUrl(process.env.DATABASE_URL))
try {
const [rows] = await conn.execute('SELECT id, name, groupName, data FROM Indicator')
console.log('[Migrate] 读取', rows.length, '个 Indicator')
let points = 0, updated = 0
for (const ind of rows) {
// mysql2 对 JSON 列已自动解析为对象, 兼容字符串兜底
let data = ind.data
if (typeof data === 'string') {
try { data = JSON.parse(data) } catch { data = null }
}
const title = (data && data.title) || ind.name
const unit = (data && data.unit) || ''
const source = (data && data.source) || ''
const rowsArr = (data && Array.isArray(data.rows)) ? data.rows : []
const freq = rowsArr.length ? inferFrequency(rowsArr[0]) : 'month'
// 更新 Indicator 元数据列
await conn.execute(
'UPDATE Indicator SET title=?, unit=?, source=?, frequency=?, updatedAt=NOW(3) WHERE id=?',
[title, unit, source, freq, ind.id],
)
updated++
// 写入明细
for (const r of rowsArr) {
const period = periodOf(r)
const value = Number(r.value)
if (!period || Number.isNaN(value)) continue
const [res] = await conn.execute(
'INSERT INTO IndicatorPoint (indicatorId, period, value, createdAt, updatedAt) VALUES (?, ?, ?, NOW(3), NOW(3)) ' +
'ON DUPLICATE KEY UPDATE value=VALUES(value), updatedAt=NOW(3)',
[ind.id, period, value],
)
points += (res.affectedRows > 0 ? 1 : 0)
}
console.log('[Migrate]', ind.name, '->', rowsArr.length, '个点, 频率', freq)
}
console.log('[Migrate] 完成: 更新', updated, '个 Indicator, 写入/更新', points, '个明细点')
} finally {
await conn.end()
}
}
main().catch((e) => { console.error('[Migrate] 失败:', e); process.exit(1) })

View File

@ -1,7 +1,12 @@
/** /**
* 拉所有启用的数据源, upsert Indicator * 拉所有启用的数据源, upsert Indicator + IndicatorPoint 明细表
* 用法: npm run data:refresh * 用法:
* 幂等: name 覆盖 data, 跨源独立, 错误隔离 * npm run data:refresh # 只拉 DB 里没有的指标
* npm run data:refresh -- --force a,b,c # 强制刷新指定指标 (忽略 DB 已有)
*
* 数据结构 (2026-08 重构):
* Indicator 元数据: name/groupName/title/unit/source/frequency/hidden
* IndicatorPoint 明细: (indicatorId, period, value), period 兼容年///
* *
* DB 优先策略: * DB 优先策略:
* 1. 先从 DB 查已存在的 name 集合 * 1. 先从 DB 查已存在的 name 集合
@ -14,6 +19,15 @@
require('dotenv').config() require('dotenv').config()
const mysql = require('mysql2/promise') const mysql = require('mysql2/promise')
// 隐藏指标: 数据与获取脚本保留, 但不参与前端展示 (API 过滤)
const HIDDEN_INDICATORS = new Set([
'china-gdp-usd', // 中国 GDP (现价美元)
'china-gdp-growth', // 中国 GDP 同比 (World Bank)
'china-gdp-yoy', // 中国 GDP 同比 (妙想季度)
'china-unemploy', // 中国失业率
'usa-gdp-usd', // 美国 GDP
])
function parseUrl(url) { function parseUrl(url) {
const u = new URL(url) const u = new URL(url)
return { return {
@ -25,13 +39,63 @@ function parseUrl(url) {
} }
} }
async function upsertIndicator(conn, payload) { function parseForceArg(argv) {
const sql = const i = argv.indexOf('--force')
'INSERT INTO `Indicator` (`name`, `groupName`, `data`, `createdAt`, `updatedAt`) ' + if (i === -1) return new Set()
'VALUES (?, ?, ?, NOW(3), NOW(3)) ' + return new Set(String(argv[i + 1] || '').split(',').map((s) => s.trim()).filter(Boolean))
'ON DUPLICATE KEY UPDATE `groupName` = VALUES(`groupName`), `data` = VALUES(`data`), `updatedAt` = NOW(3)' }
const [r] = await conn.execute(sql, [payload.name, payload.groupName, JSON.stringify(payload.data)])
return r.affectedRows // 推断频率: year | quarter | month | day (优先用 fetcher 显式声明)
function inferFrequency(data) {
if (data && data.frequency) return data.frequency
const p = String(((data && data.rows) || [])[0]?.period || '')
if (/^\d{4}$/.test(p)) return 'year'
if (/^\d{4}-Q[1-4]$/.test(p)) return 'quarter'
if (/^\d{4}-\d{2}$/.test(p)) return 'month'
if (/^\d{4}-\d{2}-\d{2}$/.test(p)) return 'day'
return 'month'
}
// 写 Indicator 元数据 + 全量替换明细点 (每指标一个事务)
async function upsertIndicatorWithPoints(conn, payload) {
const { name, groupName, data, hidden } = payload
const title = data.title || name
const unit = data.unit || ''
const source = data.source || ''
const frequency = inferFrequency(data)
const rows = Array.isArray(data.rows) ? data.rows : []
await conn.beginTransaction()
try {
const [res] = await conn.execute(
'INSERT INTO `Indicator` (`name`, `groupName`, `title`, `unit`, `source`, `frequency`, `hidden`, `createdAt`, `updatedAt`) ' +
'VALUES (?, ?, ?, ?, ?, ?, ?, NOW(3), NOW(3)) ' +
'ON DUPLICATE KEY UPDATE `groupName` = VALUES(`groupName`), `title` = VALUES(`title`), ' +
'`unit` = VALUES(`unit`), `source` = VALUES(`source`), `frequency` = VALUES(`frequency`), ' +
'`hidden` = VALUES(`hidden`), `updatedAt` = NOW(3)',
[name, groupName, title, unit, source, frequency, hidden ? 1 : 0],
)
const indicatorId = res.insertId
// 明细: 先删旧点再插入新点 (全量替换, 保证与数据源一致)
await conn.execute('DELETE FROM `IndicatorPoint` WHERE `indicatorId` = ?', [indicatorId])
let points = 0
for (const r of rows) {
const period = String(r.period !== undefined ? r.period : (r.month !== undefined ? r.month : r.year))
const value = Number(r.value)
if (!period || Number.isNaN(value)) continue
await conn.execute(
'INSERT INTO `IndicatorPoint` (`indicatorId`, `period`, `value`, `createdAt`, `updatedAt`) VALUES (?, ?, ?, NOW(3), NOW(3))',
[indicatorId, period, value],
)
points++
}
await conn.commit()
return { indicatorId, points }
} catch (e) {
await conn.rollback()
throw e
}
} }
async function fetchExistingNames(conn) { async function fetchExistingNames(conn) {
@ -44,48 +108,63 @@ async function main() {
console.error('缺少 DATABASE_URL 环境变量') console.error('缺少 DATABASE_URL 环境变量')
process.exit(1) process.exit(1)
} }
const force = parseForceArg(process.argv.slice(2))
if (force.size) console.log('[Refresh] 强制刷新: ' + [...force].join(', '))
const conn = await mysql.createConnection(parseUrl(process.env.DATABASE_URL)) const conn = await mysql.createConnection(parseUrl(process.env.DATABASE_URL))
try { try {
// 1) 查 DB 已存在的指标名 // 1) 查 DB 已存在的指标名
const existing = await fetchExistingNames(conn) const existing = await fetchExistingNames(conn)
console.log(`[Refresh] DB 已有 ${existing.size} 个指标: ${[...existing].join(', ') || '(空)'}`) console.log('[Refresh] DB 已有 ' + existing.size + ' 个指标: ' + ([...existing].join(', ') || '(空)'))
// 2) 跑所有 fetcher, 传入 existing (DB 优先) // 2) 跑所有 fetcher, 传入 existing + force (DB 优先, force 覆盖)
const { runFetchers } = await import('./fetchers/index.js') const { runFetchers } = await import('./fetchers/index.js')
const fetcherResults = await runFetchers({ skipNames: existing }) const fetcherResults = await runFetchers({ skipNames: existing, forceNames: force })
// 3) 汇总 // 3) 汇总: force 名单里的指标即使 DB 已有也写入
const allItems = [] const allItems = []
let skipped = 0, failed = 0 let skipped = 0, failed = 0
for (const r of fetcherResults) { for (const r of fetcherResults) {
if (r.skipped) { skipped++; continue } if (r.skipped) { skipped++; continue }
if (!r.ok) { failed++; continue } if (!r.ok) { failed++; continue }
// fetcher 内部已经按 skipNames 过滤过, 这里再做一次防御性去重
for (const it of r.items) { for (const it of r.items) {
if (existing.has(it.name)) continue if (existing.has(it.name) && !force.has(it.name)) continue
allItems.push(it) allItems.push(it)
} }
} }
console.log(`\n[Refresh] 汇总: ${allItems.length} 个新指标 (跳过 ${skipped} 个数据源, 失败 ${failed} 个, DB 已存在 ${existing.size} 个)`) console.log('\n[Refresh] 汇总: ' + allItems.length + ' 个指标待写 (跳过 ' + skipped + ' 个数据源, 失败 ' + failed + ' 个, DB 已存在 ' + existing.size + ' 个)')
if (failed > 0) { if (failed > 0) {
console.error('[Refresh] 警告: 有数据源失败, 仅写入成功的指标') console.error('[Refresh] 警告: 有数据源失败, 仅写入成功的指标')
} }
// 5) 同步隐藏标记: 即使指标被 DB 优先跳过, 名单内的也确保 hidden=true
if (HIDDEN_INDICATORS.size > 0) {
const names = [...HIDDEN_INDICATORS]
const ph = names.map(() => '?').join(',')
const sql = "UPDATE `Indicator` SET `hidden` = 1, `updatedAt` = NOW(3) WHERE `name` IN (" + ph + ")"
await conn.execute(sql, names)
console.log('[Refresh] 同步隐藏标记: ' + names.length + ' 个指标 hidden=true (数据保留, 不展示)')
}
if (allItems.length === 0) { if (allItems.length === 0) {
console.log('[Refresh] 无新指标, 不写库 (DB 优先策略生效)') console.log('[Refresh] 无指标待写, 不写库 (DB 优先策略生效)')
return return
} }
// 4) 写库 // 4) 写库
console.log('[Refresh] 写入数据库...') console.log('[Refresh] 写入数据库...')
let ins = 0, upd = 0 let ins = 0, upd = 0, totalPoints = 0
for (const it of allItems) { for (const it of allItems) {
const n = await upsertIndicator(conn, { name: it.name, groupName: it.groupName, data: it.data }) const hidden = HIDDEN_INDICATORS.has(it.name)
if (n === 1) ins++ const { points } = await upsertIndicatorWithPoints(conn, { name: it.name, groupName: it.groupName, data: it.data, hidden })
else if (n === 2) upd++ if (points > 0) ins++
else upd++
totalPoints += points
console.log('[Refresh] ' + it.name + (hidden ? ' (hidden)' : '') + ': ' + points + ' 个明细点')
} }
console.log(`[Refresh] 写入完成: ${ins} 新增, ${upd} 更新\n`) console.log('[Refresh] 写入完成: ' + ins + ' 个指标有数据, ' + upd + ' 个无数据, 共 ' + totalPoints + ' 个明细点\n')
} finally { } finally {
await conn.end() await conn.end()
} }
@ -95,3 +174,4 @@ main().catch((e) => {
console.error('[Refresh] 异常:', e) console.error('[Refresh] 异常:', e)
process.exit(1) process.exit(1)
}) })

View File

@ -92,16 +92,8 @@ async function main() {
} }
console.log('[Strategy] upsert 策略: ' + n2 + ' 行 (1=新增, 2=更新)'); console.log('[Strategy] upsert 策略: ' + n2 + ' 行 (1=新增, 2=更新)');
// Indicator 表: 改由 scripts/refresh-indicators.cjs 从 World Bank API 拉取最新数据 // Indicator 表: 改由 scripts/refresh-indicators.cjs 管理 (2026-08 重构后数据存 IndicatorPoint 明细表)
// 旧 4 个金融指标 (国债/LPR) 无稳定 JSON 数据源, 暂不维护 // 本脚本不再写入 Indicator, 如需初始化指标请运行 npm run data:refresh
const indicators = [];
let n3 = 0;
for (const i of indicators) {
n3 += await upsertByName(conn, 'Indicator',
{ name: i.name, groupName: i.groupName, data: JSON.stringify(i.data), updatedAt: new Date() },
'name');
}
console.log('[Indicator] upsert 指标: ' + n3 + ' 行 (1=新增, 2=更新)');
const article = { const article = {
title: '欢迎使用 iBoard', title: '欢迎使用 iBoard',

View File

@ -6,10 +6,26 @@ const router = Router()
router.use(authRequired) router.use(authRequired)
// 指标列表: 元数据 + 明细点, 过滤 hidden (数据与脚本保留, 仅不展示)
router.get('/indicators', async (_req, res, next) => { router.get('/indicators', async (_req, res, next) => {
try { try {
const rows = await prisma.indicator.findMany({ orderBy: [{ groupName: 'asc' }, { name: 'asc' }] }) const rows = await prisma.indicator.findMany({
res.json({ indicators: rows }) where: { hidden: false },
include: { points: { orderBy: { period: 'asc' } } },
orderBy: [{ groupName: 'asc' }, { name: 'asc' }],
})
// 组装前端友好结构: points 保持从老到新
const indicators = rows.map((r) => ({
id: r.id,
name: r.name,
groupName: r.groupName,
title: r.title,
unit: r.unit,
source: r.source,
frequency: r.frequency,
points: r.points.map((p) => ({ period: p.period, value: p.value })),
}))
res.json({ indicators })
} catch (e) { next(e) } } catch (e) { next(e) }
}) })

View File

@ -45,10 +45,13 @@ export default function MacroPage() {
if (next) navigate(next.path) if (next) navigate(next.path)
} }
// /macro/articles/:slug React Router , // /macro/articles/:slug /macro/data/:name React Router ,
if (location.pathname.match(/^\/macro\/articles\/[^/]+$/)) { // /
if (location.pathname.match(/^\/macro\/(articles|data|strategy)\/[^/]+$/)) {
return ( return (
<Routes> <Routes>
<Route path="data/:name" element={<DataView />} />
<Route path="strategy/:name" element={<StrategyView />} />
<Route path="articles/:slug" element={<ArticleDetail />} /> <Route path="articles/:slug" element={<ArticleDetail />} />
</Routes> </Routes>
) )

View File

@ -1,4 +1,5 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts' import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'
import { Card, List, NavBar } from 'antd-mobile' import { Card, List, NavBar } from 'antd-mobile'
import { api } from '../../api/client.js' import { api } from '../../api/client.js'
@ -7,6 +8,9 @@ import TrendBadge, { calcTrend, lastPoint } from '../../components/TrendBadge.js
// //
// (): , + , // (): , + ,
// : NavBar () + 线 + // : NavBar () + 线 +
// ( Indicator.frequency)
const FREQ_LABEL = { year: '年', quarter: '季', month: '月', day: '日' }
// : {month}/{year}/{period} // : {month}/{year}/{period}
function periodOf(r) { function periodOf(r) {
return (r && (r.period || r.month || r.year)) || '' return (r && (r.period || r.month || r.year)) || ''
@ -16,7 +20,9 @@ export default function DataView() {
const [indicators, setIndicators] = useState([]) const [indicators, setIndicators] = useState([])
const [err, setErr] = useState('') const [err, setErr] = useState('')
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [selected, setSelected] = useState(null) // null = , = // : /macro/data , /macro/data/:name , /
const { name } = useParams()
const navigate = useNavigate()
useEffect(() => { useEffect(() => {
let cancelled = false let cancelled = false
@ -35,41 +41,33 @@ export default function DataView() {
if (err) return <div className="error-banner">{err}</div> if (err) return <div className="error-banner">{err}</div>
if (!indicators.length) return <div className="empty">暂无指标数据, 请先执行 npm run db:seed</div> if (!indicators.length) return <div className="empty">暂无指标数据, 请先执行 npm run db:seed</div>
// // ( /macro/data/:name)
if (selected) { if (name) {
const cur = indicators.find((i) => i.name === selected) const cur = indicators.find((i) => i.name === name)
if (cur) return <DataDetail indicator={cur} onBack={() => setSelected(null)} /> if (cur) return <DataDetail indicator={cur} onBack={() => navigate('/macro/data')} />
} }
// //
const labelOf = (i) => (i.data && i.data.title) || i.name const labelOf = (i) => i.title || i.name
return ( return (
<div className="list-page"> <div className="list-page">
<div className="page-title">经济数据</div> <div className="page-title">经济数据</div>
<List> <List>
{indicators.map((i) => { {indicators.map((i) => {
const lp = lastPoint(i.data) const lp = lastPoint({ rows: i.points || [] })
const { trend, change } = calcTrend(i.data && i.data.rows) const { trend, change } = calcTrend(i.points || [])
const unit = (i.data && i.data.unit) || '' const unit = i.unit || ''
return ( return (
<List.Item <List.Item
key={i.name} key={i.name}
title={labelOf(i)} title={labelOf(i)}
description={lp ? <><b>{lp.value}{unit}</b> · {periodOf(lp)}</> : '暂无数据'} description={lp ? <><b>{lp.value}{unit}</b> · {periodOf(lp)}</> : '暂无数据'}
extra={ extra={<TrendBadge trend={trend} />}
<div className="row-meta">
{lp && Math.abs(change) >= 1 && (
<span className="row-change">
{change > 0 ? '+' : ''}{change.toFixed(1)}%
</span>
)}
<TrendBadge trend={trend} />
</div>
}
arrowIcon arrowIcon
clickable clickable
onClick={() => setSelected(i.name)} onClick={() => navigate('/macro/data/' + i.name)}
/> />
) )
})} })}
@ -81,19 +79,19 @@ export default function DataView() {
// : 线 + // : 线 +
function DataDetail({ indicator, onBack }) { function DataDetail({ indicator, onBack }) {
const i = indicator const i = indicator
const rows = (i.data && i.data.rows) || [] const rows = (i.points || [])
// X period // X period
const chartRows = rows.map((r) => ({ ...r, period: periodOf(r) })) const chartRows = rows.map((r) => ({ ...r, period: periodOf(r) }))
const lp = lastPoint(i.data) const lp = lastPoint({ rows })
const { trend } = calcTrend(rows) const { trend } = calcTrend(rows)
const title = (i.data && i.data.title) || i.name const title = i.title || i.name
return ( return (
<div className="detail-page"> <div className="detail-page">
<NavBar onBack={onBack}>{title}</NavBar> <NavBar onBack={onBack}>{title}</NavBar>
<Card className="detail-card"> <Card className="detail-card">
<div className="detail-meta"> <div className="detail-meta">
单位 {i.data.unit || '-'} · 来源 {i.data.source || 'seed'} · 单位 {i.unit || '-'} · 频率 {FREQ_LABEL[i.frequency] || i.frequency || '-'} · 来源 {i.source || 'seed'} ·
{lp && <> 最新 <b style={{ color: 'var(--color-text)' }}>{lp.value}{i.data.unit || ''}</b> ({periodOf(lp)}) </>} {lp && <> 最新 <b style={{ color: 'var(--color-text)' }}>{lp.value}{i.unit || ''}</b> ({periodOf(lp)}) </>}
<TrendBadge trend={trend} /> <TrendBadge trend={trend} />
</div> </div>
<div className="chart-wrap"> <div className="chart-wrap">
@ -104,7 +102,7 @@ function DataDetail({ indicator, onBack }) {
<YAxis tick={{ fontSize: 11 }} /> <YAxis tick={{ fontSize: 11 }} />
<Tooltip /> <Tooltip />
<Legend /> <Legend />
<Line type="monotone" dataKey="value" name={i.data.unit || '值'} stroke="#1677ff" strokeWidth={2} dot={{ r: 3 }} /> <Line type="monotone" dataKey="value" name={i.unit || '值'} stroke="#1677ff" strokeWidth={2} dot={{ r: 3 }} />
</LineChart> </LineChart>
</ResponsiveContainer> </ResponsiveContainer>
</div> </div>

View File

@ -1,4 +1,5 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts' import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'
import { Card, List, NavBar } from 'antd-mobile' import { Card, List, NavBar } from 'antd-mobile'
import { api } from '../../api/client.js' import { api } from '../../api/client.js'
@ -26,7 +27,9 @@ export default function StrategyView() {
const [strategies, setStrategies] = useState([]) const [strategies, setStrategies] = useState([])
const [err, setErr] = useState('') const [err, setErr] = useState('')
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [selected, setSelected] = useState(null) // : /macro/strategy , /macro/strategy/:name , /
const { name } = useParams()
const navigate = useNavigate()
useEffect(() => { useEffect(() => {
let cancelled = false let cancelled = false
@ -42,10 +45,10 @@ export default function StrategyView() {
if (err) return <div className="error-banner">{err}</div> if (err) return <div className="error-banner">{err}</div>
if (!strategies.length) return <div className="empty">暂无策略数据</div> if (!strategies.length) return <div className="empty">暂无策略数据</div>
// // ( /macro/strategy/:name)
if (selected) { if (name) {
const cur = strategies.find((s) => s.name === selected) const cur = strategies.find((s) => s.name === name)
if (cur) return <StrategyDetail strategy={cur} onBack={() => setSelected(null)} /> if (cur) return <StrategyDetail strategy={cur} onBack={() => navigate('/macro/strategy')} />
} }
// : = /GDP, // : = /GDP,
@ -64,19 +67,10 @@ export default function StrategyView() {
description={last description={last
? <><b>{last.debtToGdp}%</b> · 债务利息/GDP {last.interestToGdp}% · {last.year}</> ? <><b>{last.debtToGdp}%</b> · 债务利息/GDP {last.interestToGdp}% · {last.year}</>
: '暂无数据'} : '暂无数据'}
extra={ extra={<TrendBadge trend={trend} />}
<div className="row-meta">
{last && Math.abs(change) >= 1 && (
<span className="row-change">
{change > 0 ? '+' : ''}{change.toFixed(1)}%
</span>
)}
<TrendBadge trend={trend} />
</div>
}
arrowIcon arrowIcon
clickable clickable
onClick={() => setSelected(s.name)} onClick={() => navigate('/macro/strategy/' + s.name)}
/> />
) )
})} })}