更新首页
This commit is contained in:
@@ -34,3 +34,4 @@ dist/*
|
|||||||
|
|
||||||
# local env (contains API keys)
|
# local env (contains API keys)
|
||||||
/.env
|
/.env
|
||||||
|
.reasonix/*
|
||||||
@@ -52,6 +52,21 @@ export type News = Prisma.NewsModel
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export type Alert = Prisma.AlertModel
|
export type Alert = Prisma.AlertModel
|
||||||
|
/**
|
||||||
|
* Model ServerNode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type ServerNode = Prisma.ServerNodeModel
|
||||||
|
/**
|
||||||
|
* Model ServerNodeHistory
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type ServerNodeHistory = Prisma.ServerNodeHistoryModel
|
||||||
|
/**
|
||||||
|
* Model ServiceCheck
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type ServiceCheck = Prisma.ServiceCheckModel
|
||||||
/**
|
/**
|
||||||
* Model Econ_SowInventory
|
* Model Econ_SowInventory
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -76,6 +76,21 @@ export type News = Prisma.NewsModel
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export type Alert = Prisma.AlertModel
|
export type Alert = Prisma.AlertModel
|
||||||
|
/**
|
||||||
|
* Model ServerNode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type ServerNode = Prisma.ServerNodeModel
|
||||||
|
/**
|
||||||
|
* Model ServerNodeHistory
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type ServerNodeHistory = Prisma.ServerNodeHistoryModel
|
||||||
|
/**
|
||||||
|
* Model ServiceCheck
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type ServiceCheck = Prisma.ServiceCheckModel
|
||||||
/**
|
/**
|
||||||
* Model Econ_SowInventory
|
* Model Econ_SowInventory
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -205,6 +205,56 @@ export type StringNullableFilter<$PrismaModel = never> = {
|
|||||||
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type SortOrderInput = {
|
||||||
|
sort: Prisma.SortOrder
|
||||||
|
nulls?: Prisma.NullsOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StringNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||||
|
in?: string[] | null
|
||||||
|
notIn?: string[] | null
|
||||||
|
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||||
|
search?: string
|
||||||
|
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
|
||||||
|
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BigIntFilter<$PrismaModel = never> = {
|
||||||
|
equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
in?: bigint[] | number[]
|
||||||
|
notIn?: bigint[] | number[]
|
||||||
|
lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedBigIntFilter<$PrismaModel> | bigint | number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BigIntWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
in?: bigint[] | number[]
|
||||||
|
notIn?: bigint[] | number[]
|
||||||
|
lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedBigIntWithAggregatesFilter<$PrismaModel> | bigint | number
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_avg?: Prisma.NestedFloatFilter<$PrismaModel>
|
||||||
|
_sum?: Prisma.NestedBigIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedBigIntFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedBigIntFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
export type JsonNullableFilter<$PrismaModel = never> =
|
export type JsonNullableFilter<$PrismaModel = never> =
|
||||||
| Prisma.PatchUndefined<
|
| Prisma.PatchUndefined<
|
||||||
Prisma.Either<Required<JsonNullableFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonNullableFilterBase<$PrismaModel>>, 'path'>>,
|
Prisma.Either<Required<JsonNullableFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonNullableFilterBase<$PrismaModel>>, 'path'>>,
|
||||||
@@ -229,29 +279,6 @@ export type JsonNullableFilterBase<$PrismaModel = never> = {
|
|||||||
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SortOrderInput = {
|
|
||||||
sort: Prisma.SortOrder
|
|
||||||
nulls?: Prisma.NullsOrder
|
|
||||||
}
|
|
||||||
|
|
||||||
export type StringNullableWithAggregatesFilter<$PrismaModel = never> = {
|
|
||||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
|
||||||
in?: string[] | null
|
|
||||||
notIn?: string[] | null
|
|
||||||
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
|
||||||
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
|
||||||
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
|
||||||
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
|
||||||
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
|
||||||
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
|
||||||
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
|
||||||
search?: string
|
|
||||||
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
|
|
||||||
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
|
|
||||||
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
|
||||||
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type JsonNullableWithAggregatesFilter<$PrismaModel = never> =
|
export type JsonNullableWithAggregatesFilter<$PrismaModel = never> =
|
||||||
| Prisma.PatchUndefined<
|
| Prisma.PatchUndefined<
|
||||||
Prisma.Either<Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>, 'path'>>,
|
Prisma.Either<Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonNullableWithAggregatesFilterBase<$PrismaModel>>, 'path'>>,
|
||||||
@@ -472,6 +499,33 @@ export type NestedIntNullableFilter<$PrismaModel = never> = {
|
|||||||
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
|
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NestedBigIntFilter<$PrismaModel = never> = {
|
||||||
|
equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
in?: bigint[] | number[]
|
||||||
|
notIn?: bigint[] | number[]
|
||||||
|
lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedBigIntFilter<$PrismaModel> | bigint | number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NestedBigIntWithAggregatesFilter<$PrismaModel = never> = {
|
||||||
|
equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
in?: bigint[] | number[]
|
||||||
|
notIn?: bigint[] | number[]
|
||||||
|
lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel>
|
||||||
|
not?: Prisma.NestedBigIntWithAggregatesFilter<$PrismaModel> | bigint | number
|
||||||
|
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||||
|
_avg?: Prisma.NestedFloatFilter<$PrismaModel>
|
||||||
|
_sum?: Prisma.NestedBigIntFilter<$PrismaModel>
|
||||||
|
_min?: Prisma.NestedBigIntFilter<$PrismaModel>
|
||||||
|
_max?: Prisma.NestedBigIntFilter<$PrismaModel>
|
||||||
|
}
|
||||||
|
|
||||||
export type NestedJsonNullableFilter<$PrismaModel = never> =
|
export type NestedJsonNullableFilter<$PrismaModel = never> =
|
||||||
| Prisma.PatchUndefined<
|
| Prisma.PatchUndefined<
|
||||||
Prisma.Either<Required<NestedJsonNullableFilterBase<$PrismaModel>>, Exclude<keyof Required<NestedJsonNullableFilterBase<$PrismaModel>>, 'path'>>,
|
Prisma.Either<Required<NestedJsonNullableFilterBase<$PrismaModel>>, Exclude<keyof Required<NestedJsonNullableFilterBase<$PrismaModel>>, 'path'>>,
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -391,6 +391,9 @@ export const ModelName = {
|
|||||||
IndicatorPoint: 'IndicatorPoint',
|
IndicatorPoint: 'IndicatorPoint',
|
||||||
News: 'News',
|
News: 'News',
|
||||||
Alert: 'Alert',
|
Alert: 'Alert',
|
||||||
|
ServerNode: 'ServerNode',
|
||||||
|
ServerNodeHistory: 'ServerNodeHistory',
|
||||||
|
ServiceCheck: 'ServiceCheck',
|
||||||
Econ_SowInventory: 'Econ_SowInventory',
|
Econ_SowInventory: 'Econ_SowInventory',
|
||||||
ScraperCache: 'ScraperCache'
|
ScraperCache: 'ScraperCache'
|
||||||
} as const
|
} as const
|
||||||
@@ -408,7 +411,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
|
|||||||
omit: GlobalOmitOptions
|
omit: GlobalOmitOptions
|
||||||
}
|
}
|
||||||
meta: {
|
meta: {
|
||||||
modelProps: "user" | "article" | "strategy" | "indicator" | "indicatorPoint" | "news" | "alert" | "econ_SowInventory" | "scraperCache"
|
modelProps: "user" | "article" | "strategy" | "indicator" | "indicatorPoint" | "news" | "alert" | "serverNode" | "serverNodeHistory" | "serviceCheck" | "econ_SowInventory" | "scraperCache"
|
||||||
txIsolationLevel: TransactionIsolationLevel
|
txIsolationLevel: TransactionIsolationLevel
|
||||||
}
|
}
|
||||||
model: {
|
model: {
|
||||||
@@ -874,6 +877,204 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ServerNode: {
|
||||||
|
payload: Prisma.$ServerNodePayload<ExtArgs>
|
||||||
|
fields: Prisma.ServerNodeFieldRefs
|
||||||
|
operations: {
|
||||||
|
findUnique: {
|
||||||
|
args: Prisma.ServerNodeFindUniqueArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodePayload> | null
|
||||||
|
}
|
||||||
|
findUniqueOrThrow: {
|
||||||
|
args: Prisma.ServerNodeFindUniqueOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodePayload>
|
||||||
|
}
|
||||||
|
findFirst: {
|
||||||
|
args: Prisma.ServerNodeFindFirstArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodePayload> | null
|
||||||
|
}
|
||||||
|
findFirstOrThrow: {
|
||||||
|
args: Prisma.ServerNodeFindFirstOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodePayload>
|
||||||
|
}
|
||||||
|
findMany: {
|
||||||
|
args: Prisma.ServerNodeFindManyArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodePayload>[]
|
||||||
|
}
|
||||||
|
create: {
|
||||||
|
args: Prisma.ServerNodeCreateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodePayload>
|
||||||
|
}
|
||||||
|
createMany: {
|
||||||
|
args: Prisma.ServerNodeCreateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
delete: {
|
||||||
|
args: Prisma.ServerNodeDeleteArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodePayload>
|
||||||
|
}
|
||||||
|
update: {
|
||||||
|
args: Prisma.ServerNodeUpdateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodePayload>
|
||||||
|
}
|
||||||
|
deleteMany: {
|
||||||
|
args: Prisma.ServerNodeDeleteManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateMany: {
|
||||||
|
args: Prisma.ServerNodeUpdateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
upsert: {
|
||||||
|
args: Prisma.ServerNodeUpsertArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodePayload>
|
||||||
|
}
|
||||||
|
aggregate: {
|
||||||
|
args: Prisma.ServerNodeAggregateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.AggregateServerNode>
|
||||||
|
}
|
||||||
|
groupBy: {
|
||||||
|
args: Prisma.ServerNodeGroupByArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.ServerNodeGroupByOutputType>[]
|
||||||
|
}
|
||||||
|
count: {
|
||||||
|
args: Prisma.ServerNodeCountArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.ServerNodeCountAggregateOutputType> | number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ServerNodeHistory: {
|
||||||
|
payload: Prisma.$ServerNodeHistoryPayload<ExtArgs>
|
||||||
|
fields: Prisma.ServerNodeHistoryFieldRefs
|
||||||
|
operations: {
|
||||||
|
findUnique: {
|
||||||
|
args: Prisma.ServerNodeHistoryFindUniqueArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodeHistoryPayload> | null
|
||||||
|
}
|
||||||
|
findUniqueOrThrow: {
|
||||||
|
args: Prisma.ServerNodeHistoryFindUniqueOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodeHistoryPayload>
|
||||||
|
}
|
||||||
|
findFirst: {
|
||||||
|
args: Prisma.ServerNodeHistoryFindFirstArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodeHistoryPayload> | null
|
||||||
|
}
|
||||||
|
findFirstOrThrow: {
|
||||||
|
args: Prisma.ServerNodeHistoryFindFirstOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodeHistoryPayload>
|
||||||
|
}
|
||||||
|
findMany: {
|
||||||
|
args: Prisma.ServerNodeHistoryFindManyArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodeHistoryPayload>[]
|
||||||
|
}
|
||||||
|
create: {
|
||||||
|
args: Prisma.ServerNodeHistoryCreateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodeHistoryPayload>
|
||||||
|
}
|
||||||
|
createMany: {
|
||||||
|
args: Prisma.ServerNodeHistoryCreateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
delete: {
|
||||||
|
args: Prisma.ServerNodeHistoryDeleteArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodeHistoryPayload>
|
||||||
|
}
|
||||||
|
update: {
|
||||||
|
args: Prisma.ServerNodeHistoryUpdateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodeHistoryPayload>
|
||||||
|
}
|
||||||
|
deleteMany: {
|
||||||
|
args: Prisma.ServerNodeHistoryDeleteManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateMany: {
|
||||||
|
args: Prisma.ServerNodeHistoryUpdateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
upsert: {
|
||||||
|
args: Prisma.ServerNodeHistoryUpsertArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServerNodeHistoryPayload>
|
||||||
|
}
|
||||||
|
aggregate: {
|
||||||
|
args: Prisma.ServerNodeHistoryAggregateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.AggregateServerNodeHistory>
|
||||||
|
}
|
||||||
|
groupBy: {
|
||||||
|
args: Prisma.ServerNodeHistoryGroupByArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.ServerNodeHistoryGroupByOutputType>[]
|
||||||
|
}
|
||||||
|
count: {
|
||||||
|
args: Prisma.ServerNodeHistoryCountArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.ServerNodeHistoryCountAggregateOutputType> | number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ServiceCheck: {
|
||||||
|
payload: Prisma.$ServiceCheckPayload<ExtArgs>
|
||||||
|
fields: Prisma.ServiceCheckFieldRefs
|
||||||
|
operations: {
|
||||||
|
findUnique: {
|
||||||
|
args: Prisma.ServiceCheckFindUniqueArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServiceCheckPayload> | null
|
||||||
|
}
|
||||||
|
findUniqueOrThrow: {
|
||||||
|
args: Prisma.ServiceCheckFindUniqueOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServiceCheckPayload>
|
||||||
|
}
|
||||||
|
findFirst: {
|
||||||
|
args: Prisma.ServiceCheckFindFirstArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServiceCheckPayload> | null
|
||||||
|
}
|
||||||
|
findFirstOrThrow: {
|
||||||
|
args: Prisma.ServiceCheckFindFirstOrThrowArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServiceCheckPayload>
|
||||||
|
}
|
||||||
|
findMany: {
|
||||||
|
args: Prisma.ServiceCheckFindManyArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServiceCheckPayload>[]
|
||||||
|
}
|
||||||
|
create: {
|
||||||
|
args: Prisma.ServiceCheckCreateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServiceCheckPayload>
|
||||||
|
}
|
||||||
|
createMany: {
|
||||||
|
args: Prisma.ServiceCheckCreateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
delete: {
|
||||||
|
args: Prisma.ServiceCheckDeleteArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServiceCheckPayload>
|
||||||
|
}
|
||||||
|
update: {
|
||||||
|
args: Prisma.ServiceCheckUpdateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServiceCheckPayload>
|
||||||
|
}
|
||||||
|
deleteMany: {
|
||||||
|
args: Prisma.ServiceCheckDeleteManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
updateMany: {
|
||||||
|
args: Prisma.ServiceCheckUpdateManyArgs<ExtArgs>
|
||||||
|
result: BatchPayload
|
||||||
|
}
|
||||||
|
upsert: {
|
||||||
|
args: Prisma.ServiceCheckUpsertArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.PayloadToResult<Prisma.$ServiceCheckPayload>
|
||||||
|
}
|
||||||
|
aggregate: {
|
||||||
|
args: Prisma.ServiceCheckAggregateArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.AggregateServiceCheck>
|
||||||
|
}
|
||||||
|
groupBy: {
|
||||||
|
args: Prisma.ServiceCheckGroupByArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.ServiceCheckGroupByOutputType>[]
|
||||||
|
}
|
||||||
|
count: {
|
||||||
|
args: Prisma.ServiceCheckCountArgs<ExtArgs>
|
||||||
|
result: runtime.Types.Utils.Optional<Prisma.ServiceCheckCountAggregateOutputType> | number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Econ_SowInventory: {
|
Econ_SowInventory: {
|
||||||
payload: Prisma.$Econ_SowInventoryPayload<ExtArgs>
|
payload: Prisma.$Econ_SowInventoryPayload<ExtArgs>
|
||||||
fields: Prisma.Econ_SowInventoryFieldRefs
|
fields: Prisma.Econ_SowInventoryFieldRefs
|
||||||
@@ -1114,6 +1315,7 @@ export const NewsScalarFieldEnum = {
|
|||||||
id: 'id',
|
id: 'id',
|
||||||
title: 'title',
|
title: 'title',
|
||||||
summary: 'summary',
|
summary: 'summary',
|
||||||
|
content: 'content',
|
||||||
source: 'source',
|
source: 'source',
|
||||||
url: 'url',
|
url: 'url',
|
||||||
publishedAt: 'publishedAt',
|
publishedAt: 'publishedAt',
|
||||||
@@ -1140,6 +1342,70 @@ export const AlertScalarFieldEnum = {
|
|||||||
export type AlertScalarFieldEnum = (typeof AlertScalarFieldEnum)[keyof typeof AlertScalarFieldEnum]
|
export type AlertScalarFieldEnum = (typeof AlertScalarFieldEnum)[keyof typeof AlertScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServerNodeScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
uuid: 'uuid',
|
||||||
|
name: 'name',
|
||||||
|
cpuName: 'cpuName',
|
||||||
|
os: 'os',
|
||||||
|
region: 'region',
|
||||||
|
memTotal: 'memTotal',
|
||||||
|
diskTotal: 'diskTotal',
|
||||||
|
cpuCores: 'cpuCores',
|
||||||
|
cpuUsage: 'cpuUsage',
|
||||||
|
ramUsed: 'ramUsed',
|
||||||
|
swapUsed: 'swapUsed',
|
||||||
|
load1: 'load1',
|
||||||
|
load5: 'load5',
|
||||||
|
load15: 'load15',
|
||||||
|
diskUsed: 'diskUsed',
|
||||||
|
netIn: 'netIn',
|
||||||
|
netOut: 'netOut',
|
||||||
|
uptime: 'uptime',
|
||||||
|
process: 'process',
|
||||||
|
connections: 'connections',
|
||||||
|
status: 'status',
|
||||||
|
recordedAt: 'recordedAt',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServerNodeScalarFieldEnum = (typeof ServerNodeScalarFieldEnum)[keyof typeof ServerNodeScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServerNodeHistoryScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
uuid: 'uuid',
|
||||||
|
period: 'period',
|
||||||
|
cpu: 'cpu',
|
||||||
|
ram: 'ram',
|
||||||
|
load: 'load',
|
||||||
|
disk: 'disk',
|
||||||
|
netIn: 'netIn',
|
||||||
|
netOut: 'netOut',
|
||||||
|
process: 'process',
|
||||||
|
connections: 'connections',
|
||||||
|
createdAt: 'createdAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServerNodeHistoryScalarFieldEnum = (typeof ServerNodeHistoryScalarFieldEnum)[keyof typeof ServerNodeHistoryScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServiceCheckScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
name: 'name',
|
||||||
|
url: 'url',
|
||||||
|
status: 'status',
|
||||||
|
latencyMs: 'latencyMs',
|
||||||
|
message: 'message',
|
||||||
|
lastCheckAt: 'lastCheckAt',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServiceCheckScalarFieldEnum = (typeof ServiceCheckScalarFieldEnum)[keyof typeof ServiceCheckScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const Econ_SowInventoryScalarFieldEnum = {
|
export const Econ_SowInventoryScalarFieldEnum = {
|
||||||
id: 'id',
|
id: 'id',
|
||||||
month: 'month',
|
month: 'month',
|
||||||
@@ -1250,9 +1516,18 @@ export const IndicatorPointOrderByRelevanceFieldEnum = {
|
|||||||
export type IndicatorPointOrderByRelevanceFieldEnum = (typeof IndicatorPointOrderByRelevanceFieldEnum)[keyof typeof IndicatorPointOrderByRelevanceFieldEnum]
|
export type IndicatorPointOrderByRelevanceFieldEnum = (typeof IndicatorPointOrderByRelevanceFieldEnum)[keyof typeof IndicatorPointOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const NullsOrder = {
|
||||||
|
first: 'first',
|
||||||
|
last: 'last'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
|
||||||
|
|
||||||
|
|
||||||
export const NewsOrderByRelevanceFieldEnum = {
|
export const NewsOrderByRelevanceFieldEnum = {
|
||||||
title: 'title',
|
title: 'title',
|
||||||
summary: 'summary',
|
summary: 'summary',
|
||||||
|
content: 'content',
|
||||||
source: 'source',
|
source: 'source',
|
||||||
url: 'url'
|
url: 'url'
|
||||||
} as const
|
} as const
|
||||||
@@ -1270,6 +1545,35 @@ export const AlertOrderByRelevanceFieldEnum = {
|
|||||||
export type AlertOrderByRelevanceFieldEnum = (typeof AlertOrderByRelevanceFieldEnum)[keyof typeof AlertOrderByRelevanceFieldEnum]
|
export type AlertOrderByRelevanceFieldEnum = (typeof AlertOrderByRelevanceFieldEnum)[keyof typeof AlertOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServerNodeOrderByRelevanceFieldEnum = {
|
||||||
|
uuid: 'uuid',
|
||||||
|
name: 'name',
|
||||||
|
cpuName: 'cpuName',
|
||||||
|
os: 'os',
|
||||||
|
region: 'region',
|
||||||
|
status: 'status'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServerNodeOrderByRelevanceFieldEnum = (typeof ServerNodeOrderByRelevanceFieldEnum)[keyof typeof ServerNodeOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServerNodeHistoryOrderByRelevanceFieldEnum = {
|
||||||
|
uuid: 'uuid'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServerNodeHistoryOrderByRelevanceFieldEnum = (typeof ServerNodeHistoryOrderByRelevanceFieldEnum)[keyof typeof ServerNodeHistoryOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServiceCheckOrderByRelevanceFieldEnum = {
|
||||||
|
name: 'name',
|
||||||
|
url: 'url',
|
||||||
|
status: 'status',
|
||||||
|
message: 'message'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServiceCheckOrderByRelevanceFieldEnum = (typeof ServiceCheckOrderByRelevanceFieldEnum)[keyof typeof ServiceCheckOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const Econ_SowInventoryOrderByRelevanceFieldEnum = {
|
export const Econ_SowInventoryOrderByRelevanceFieldEnum = {
|
||||||
month: 'month'
|
month: 'month'
|
||||||
} as const
|
} as const
|
||||||
@@ -1277,14 +1581,6 @@ export const Econ_SowInventoryOrderByRelevanceFieldEnum = {
|
|||||||
export type Econ_SowInventoryOrderByRelevanceFieldEnum = (typeof Econ_SowInventoryOrderByRelevanceFieldEnum)[keyof typeof Econ_SowInventoryOrderByRelevanceFieldEnum]
|
export type Econ_SowInventoryOrderByRelevanceFieldEnum = (typeof Econ_SowInventoryOrderByRelevanceFieldEnum)[keyof typeof Econ_SowInventoryOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const NullsOrder = {
|
|
||||||
first: 'first',
|
|
||||||
last: 'last'
|
|
||||||
} as const
|
|
||||||
|
|
||||||
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
|
|
||||||
|
|
||||||
|
|
||||||
export const ScraperCacheOrderByRelevanceFieldEnum = {
|
export const ScraperCacheOrderByRelevanceFieldEnum = {
|
||||||
scraperName: 'scraperName',
|
scraperName: 'scraperName',
|
||||||
lastDataHash: 'lastDataHash'
|
lastDataHash: 'lastDataHash'
|
||||||
@@ -1347,6 +1643,13 @@ export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel,
|
|||||||
export type FloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float'>
|
export type FloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float'>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a field of type 'BigInt'
|
||||||
|
*/
|
||||||
|
export type BigIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'BigInt'>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Batch Payload for updateMany & deleteMany & createMany
|
* Batch Payload for updateMany & deleteMany & createMany
|
||||||
*/
|
*/
|
||||||
@@ -1449,6 +1752,9 @@ export type GlobalOmitConfig = {
|
|||||||
indicatorPoint?: Prisma.IndicatorPointOmit
|
indicatorPoint?: Prisma.IndicatorPointOmit
|
||||||
news?: Prisma.NewsOmit
|
news?: Prisma.NewsOmit
|
||||||
alert?: Prisma.AlertOmit
|
alert?: Prisma.AlertOmit
|
||||||
|
serverNode?: Prisma.ServerNodeOmit
|
||||||
|
serverNodeHistory?: Prisma.ServerNodeHistoryOmit
|
||||||
|
serviceCheck?: Prisma.ServiceCheckOmit
|
||||||
econ_SowInventory?: Prisma.Econ_SowInventoryOmit
|
econ_SowInventory?: Prisma.Econ_SowInventoryOmit
|
||||||
scraperCache?: Prisma.ScraperCacheOmit
|
scraperCache?: Prisma.ScraperCacheOmit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ export const ModelName = {
|
|||||||
IndicatorPoint: 'IndicatorPoint',
|
IndicatorPoint: 'IndicatorPoint',
|
||||||
News: 'News',
|
News: 'News',
|
||||||
Alert: 'Alert',
|
Alert: 'Alert',
|
||||||
|
ServerNode: 'ServerNode',
|
||||||
|
ServerNodeHistory: 'ServerNodeHistory',
|
||||||
|
ServiceCheck: 'ServiceCheck',
|
||||||
Econ_SowInventory: 'Econ_SowInventory',
|
Econ_SowInventory: 'Econ_SowInventory',
|
||||||
ScraperCache: 'ScraperCache'
|
ScraperCache: 'ScraperCache'
|
||||||
} as const
|
} as const
|
||||||
@@ -147,6 +150,7 @@ export const NewsScalarFieldEnum = {
|
|||||||
id: 'id',
|
id: 'id',
|
||||||
title: 'title',
|
title: 'title',
|
||||||
summary: 'summary',
|
summary: 'summary',
|
||||||
|
content: 'content',
|
||||||
source: 'source',
|
source: 'source',
|
||||||
url: 'url',
|
url: 'url',
|
||||||
publishedAt: 'publishedAt',
|
publishedAt: 'publishedAt',
|
||||||
@@ -173,6 +177,70 @@ export const AlertScalarFieldEnum = {
|
|||||||
export type AlertScalarFieldEnum = (typeof AlertScalarFieldEnum)[keyof typeof AlertScalarFieldEnum]
|
export type AlertScalarFieldEnum = (typeof AlertScalarFieldEnum)[keyof typeof AlertScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServerNodeScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
uuid: 'uuid',
|
||||||
|
name: 'name',
|
||||||
|
cpuName: 'cpuName',
|
||||||
|
os: 'os',
|
||||||
|
region: 'region',
|
||||||
|
memTotal: 'memTotal',
|
||||||
|
diskTotal: 'diskTotal',
|
||||||
|
cpuCores: 'cpuCores',
|
||||||
|
cpuUsage: 'cpuUsage',
|
||||||
|
ramUsed: 'ramUsed',
|
||||||
|
swapUsed: 'swapUsed',
|
||||||
|
load1: 'load1',
|
||||||
|
load5: 'load5',
|
||||||
|
load15: 'load15',
|
||||||
|
diskUsed: 'diskUsed',
|
||||||
|
netIn: 'netIn',
|
||||||
|
netOut: 'netOut',
|
||||||
|
uptime: 'uptime',
|
||||||
|
process: 'process',
|
||||||
|
connections: 'connections',
|
||||||
|
status: 'status',
|
||||||
|
recordedAt: 'recordedAt',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServerNodeScalarFieldEnum = (typeof ServerNodeScalarFieldEnum)[keyof typeof ServerNodeScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServerNodeHistoryScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
uuid: 'uuid',
|
||||||
|
period: 'period',
|
||||||
|
cpu: 'cpu',
|
||||||
|
ram: 'ram',
|
||||||
|
load: 'load',
|
||||||
|
disk: 'disk',
|
||||||
|
netIn: 'netIn',
|
||||||
|
netOut: 'netOut',
|
||||||
|
process: 'process',
|
||||||
|
connections: 'connections',
|
||||||
|
createdAt: 'createdAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServerNodeHistoryScalarFieldEnum = (typeof ServerNodeHistoryScalarFieldEnum)[keyof typeof ServerNodeHistoryScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServiceCheckScalarFieldEnum = {
|
||||||
|
id: 'id',
|
||||||
|
name: 'name',
|
||||||
|
url: 'url',
|
||||||
|
status: 'status',
|
||||||
|
latencyMs: 'latencyMs',
|
||||||
|
message: 'message',
|
||||||
|
lastCheckAt: 'lastCheckAt',
|
||||||
|
createdAt: 'createdAt',
|
||||||
|
updatedAt: 'updatedAt'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServiceCheckScalarFieldEnum = (typeof ServiceCheckScalarFieldEnum)[keyof typeof ServiceCheckScalarFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const Econ_SowInventoryScalarFieldEnum = {
|
export const Econ_SowInventoryScalarFieldEnum = {
|
||||||
id: 'id',
|
id: 'id',
|
||||||
month: 'month',
|
month: 'month',
|
||||||
@@ -283,9 +351,18 @@ export const IndicatorPointOrderByRelevanceFieldEnum = {
|
|||||||
export type IndicatorPointOrderByRelevanceFieldEnum = (typeof IndicatorPointOrderByRelevanceFieldEnum)[keyof typeof IndicatorPointOrderByRelevanceFieldEnum]
|
export type IndicatorPointOrderByRelevanceFieldEnum = (typeof IndicatorPointOrderByRelevanceFieldEnum)[keyof typeof IndicatorPointOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const NullsOrder = {
|
||||||
|
first: 'first',
|
||||||
|
last: 'last'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
|
||||||
|
|
||||||
|
|
||||||
export const NewsOrderByRelevanceFieldEnum = {
|
export const NewsOrderByRelevanceFieldEnum = {
|
||||||
title: 'title',
|
title: 'title',
|
||||||
summary: 'summary',
|
summary: 'summary',
|
||||||
|
content: 'content',
|
||||||
source: 'source',
|
source: 'source',
|
||||||
url: 'url'
|
url: 'url'
|
||||||
} as const
|
} as const
|
||||||
@@ -303,6 +380,35 @@ export const AlertOrderByRelevanceFieldEnum = {
|
|||||||
export type AlertOrderByRelevanceFieldEnum = (typeof AlertOrderByRelevanceFieldEnum)[keyof typeof AlertOrderByRelevanceFieldEnum]
|
export type AlertOrderByRelevanceFieldEnum = (typeof AlertOrderByRelevanceFieldEnum)[keyof typeof AlertOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServerNodeOrderByRelevanceFieldEnum = {
|
||||||
|
uuid: 'uuid',
|
||||||
|
name: 'name',
|
||||||
|
cpuName: 'cpuName',
|
||||||
|
os: 'os',
|
||||||
|
region: 'region',
|
||||||
|
status: 'status'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServerNodeOrderByRelevanceFieldEnum = (typeof ServerNodeOrderByRelevanceFieldEnum)[keyof typeof ServerNodeOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServerNodeHistoryOrderByRelevanceFieldEnum = {
|
||||||
|
uuid: 'uuid'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServerNodeHistoryOrderByRelevanceFieldEnum = (typeof ServerNodeHistoryOrderByRelevanceFieldEnum)[keyof typeof ServerNodeHistoryOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
|
export const ServiceCheckOrderByRelevanceFieldEnum = {
|
||||||
|
name: 'name',
|
||||||
|
url: 'url',
|
||||||
|
status: 'status',
|
||||||
|
message: 'message'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ServiceCheckOrderByRelevanceFieldEnum = (typeof ServiceCheckOrderByRelevanceFieldEnum)[keyof typeof ServiceCheckOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const Econ_SowInventoryOrderByRelevanceFieldEnum = {
|
export const Econ_SowInventoryOrderByRelevanceFieldEnum = {
|
||||||
month: 'month'
|
month: 'month'
|
||||||
} as const
|
} as const
|
||||||
@@ -310,14 +416,6 @@ export const Econ_SowInventoryOrderByRelevanceFieldEnum = {
|
|||||||
export type Econ_SowInventoryOrderByRelevanceFieldEnum = (typeof Econ_SowInventoryOrderByRelevanceFieldEnum)[keyof typeof Econ_SowInventoryOrderByRelevanceFieldEnum]
|
export type Econ_SowInventoryOrderByRelevanceFieldEnum = (typeof Econ_SowInventoryOrderByRelevanceFieldEnum)[keyof typeof Econ_SowInventoryOrderByRelevanceFieldEnum]
|
||||||
|
|
||||||
|
|
||||||
export const NullsOrder = {
|
|
||||||
first: 'first',
|
|
||||||
last: 'last'
|
|
||||||
} as const
|
|
||||||
|
|
||||||
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
|
|
||||||
|
|
||||||
|
|
||||||
export const ScraperCacheOrderByRelevanceFieldEnum = {
|
export const ScraperCacheOrderByRelevanceFieldEnum = {
|
||||||
scraperName: 'scraperName',
|
scraperName: 'scraperName',
|
||||||
lastDataHash: 'lastDataHash'
|
lastDataHash: 'lastDataHash'
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ export type * from './models/Indicator.ts'
|
|||||||
export type * from './models/IndicatorPoint.ts'
|
export type * from './models/IndicatorPoint.ts'
|
||||||
export type * from './models/News.ts'
|
export type * from './models/News.ts'
|
||||||
export type * from './models/Alert.ts'
|
export type * from './models/Alert.ts'
|
||||||
|
export type * from './models/ServerNode.ts'
|
||||||
|
export type * from './models/ServerNodeHistory.ts'
|
||||||
|
export type * from './models/ServiceCheck.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'
|
||||||
@@ -40,6 +40,7 @@ export type NewsMinAggregateOutputType = {
|
|||||||
id: number | null
|
id: number | null
|
||||||
title: string | null
|
title: string | null
|
||||||
summary: string | null
|
summary: string | null
|
||||||
|
content: string | null
|
||||||
source: string | null
|
source: string | null
|
||||||
url: string | null
|
url: string | null
|
||||||
publishedAt: Date | null
|
publishedAt: Date | null
|
||||||
@@ -51,6 +52,7 @@ export type NewsMaxAggregateOutputType = {
|
|||||||
id: number | null
|
id: number | null
|
||||||
title: string | null
|
title: string | null
|
||||||
summary: string | null
|
summary: string | null
|
||||||
|
content: string | null
|
||||||
source: string | null
|
source: string | null
|
||||||
url: string | null
|
url: string | null
|
||||||
publishedAt: Date | null
|
publishedAt: Date | null
|
||||||
@@ -62,6 +64,7 @@ export type NewsCountAggregateOutputType = {
|
|||||||
id: number
|
id: number
|
||||||
title: number
|
title: number
|
||||||
summary: number
|
summary: number
|
||||||
|
content: number
|
||||||
source: number
|
source: number
|
||||||
url: number
|
url: number
|
||||||
publishedAt: number
|
publishedAt: number
|
||||||
@@ -85,6 +88,7 @@ export type NewsMinAggregateInputType = {
|
|||||||
id?: true
|
id?: true
|
||||||
title?: true
|
title?: true
|
||||||
summary?: true
|
summary?: true
|
||||||
|
content?: true
|
||||||
source?: true
|
source?: true
|
||||||
url?: true
|
url?: true
|
||||||
publishedAt?: true
|
publishedAt?: true
|
||||||
@@ -96,6 +100,7 @@ export type NewsMaxAggregateInputType = {
|
|||||||
id?: true
|
id?: true
|
||||||
title?: true
|
title?: true
|
||||||
summary?: true
|
summary?: true
|
||||||
|
content?: true
|
||||||
source?: true
|
source?: true
|
||||||
url?: true
|
url?: true
|
||||||
publishedAt?: true
|
publishedAt?: true
|
||||||
@@ -107,6 +112,7 @@ export type NewsCountAggregateInputType = {
|
|||||||
id?: true
|
id?: true
|
||||||
title?: true
|
title?: true
|
||||||
summary?: true
|
summary?: true
|
||||||
|
content?: true
|
||||||
source?: true
|
source?: true
|
||||||
url?: true
|
url?: true
|
||||||
publishedAt?: true
|
publishedAt?: true
|
||||||
@@ -205,6 +211,7 @@ export type NewsGroupByOutputType = {
|
|||||||
id: number
|
id: number
|
||||||
title: string
|
title: string
|
||||||
summary: string
|
summary: string
|
||||||
|
content: string | null
|
||||||
source: string
|
source: string
|
||||||
url: string
|
url: string
|
||||||
publishedAt: Date
|
publishedAt: Date
|
||||||
@@ -239,6 +246,7 @@ export type NewsWhereInput = {
|
|||||||
id?: Prisma.IntFilter<"News"> | number
|
id?: Prisma.IntFilter<"News"> | number
|
||||||
title?: Prisma.StringFilter<"News"> | string
|
title?: Prisma.StringFilter<"News"> | string
|
||||||
summary?: Prisma.StringFilter<"News"> | string
|
summary?: Prisma.StringFilter<"News"> | string
|
||||||
|
content?: Prisma.StringNullableFilter<"News"> | string | null
|
||||||
source?: Prisma.StringFilter<"News"> | string
|
source?: Prisma.StringFilter<"News"> | string
|
||||||
url?: Prisma.StringFilter<"News"> | string
|
url?: Prisma.StringFilter<"News"> | string
|
||||||
publishedAt?: Prisma.DateTimeFilter<"News"> | Date | string
|
publishedAt?: Prisma.DateTimeFilter<"News"> | Date | string
|
||||||
@@ -250,6 +258,7 @@ export type NewsOrderByWithRelationInput = {
|
|||||||
id?: Prisma.SortOrder
|
id?: Prisma.SortOrder
|
||||||
title?: Prisma.SortOrder
|
title?: Prisma.SortOrder
|
||||||
summary?: Prisma.SortOrder
|
summary?: Prisma.SortOrder
|
||||||
|
content?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
source?: Prisma.SortOrder
|
source?: Prisma.SortOrder
|
||||||
url?: Prisma.SortOrder
|
url?: Prisma.SortOrder
|
||||||
publishedAt?: Prisma.SortOrder
|
publishedAt?: Prisma.SortOrder
|
||||||
@@ -266,6 +275,7 @@ export type NewsWhereUniqueInput = Prisma.AtLeast<{
|
|||||||
NOT?: Prisma.NewsWhereInput | Prisma.NewsWhereInput[]
|
NOT?: Prisma.NewsWhereInput | Prisma.NewsWhereInput[]
|
||||||
title?: Prisma.StringFilter<"News"> | string
|
title?: Prisma.StringFilter<"News"> | string
|
||||||
summary?: Prisma.StringFilter<"News"> | string
|
summary?: Prisma.StringFilter<"News"> | string
|
||||||
|
content?: Prisma.StringNullableFilter<"News"> | string | null
|
||||||
source?: Prisma.StringFilter<"News"> | string
|
source?: Prisma.StringFilter<"News"> | string
|
||||||
url?: Prisma.StringFilter<"News"> | string
|
url?: Prisma.StringFilter<"News"> | string
|
||||||
publishedAt?: Prisma.DateTimeFilter<"News"> | Date | string
|
publishedAt?: Prisma.DateTimeFilter<"News"> | Date | string
|
||||||
@@ -277,6 +287,7 @@ export type NewsOrderByWithAggregationInput = {
|
|||||||
id?: Prisma.SortOrder
|
id?: Prisma.SortOrder
|
||||||
title?: Prisma.SortOrder
|
title?: Prisma.SortOrder
|
||||||
summary?: Prisma.SortOrder
|
summary?: Prisma.SortOrder
|
||||||
|
content?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
source?: Prisma.SortOrder
|
source?: Prisma.SortOrder
|
||||||
url?: Prisma.SortOrder
|
url?: Prisma.SortOrder
|
||||||
publishedAt?: Prisma.SortOrder
|
publishedAt?: Prisma.SortOrder
|
||||||
@@ -296,6 +307,7 @@ export type NewsScalarWhereWithAggregatesInput = {
|
|||||||
id?: Prisma.IntWithAggregatesFilter<"News"> | number
|
id?: Prisma.IntWithAggregatesFilter<"News"> | number
|
||||||
title?: Prisma.StringWithAggregatesFilter<"News"> | string
|
title?: Prisma.StringWithAggregatesFilter<"News"> | string
|
||||||
summary?: Prisma.StringWithAggregatesFilter<"News"> | string
|
summary?: Prisma.StringWithAggregatesFilter<"News"> | string
|
||||||
|
content?: Prisma.StringNullableWithAggregatesFilter<"News"> | string | null
|
||||||
source?: Prisma.StringWithAggregatesFilter<"News"> | string
|
source?: Prisma.StringWithAggregatesFilter<"News"> | string
|
||||||
url?: Prisma.StringWithAggregatesFilter<"News"> | string
|
url?: Prisma.StringWithAggregatesFilter<"News"> | string
|
||||||
publishedAt?: Prisma.DateTimeWithAggregatesFilter<"News"> | Date | string
|
publishedAt?: Prisma.DateTimeWithAggregatesFilter<"News"> | Date | string
|
||||||
@@ -306,6 +318,7 @@ export type NewsScalarWhereWithAggregatesInput = {
|
|||||||
export type NewsCreateInput = {
|
export type NewsCreateInput = {
|
||||||
title: string
|
title: string
|
||||||
summary?: string
|
summary?: string
|
||||||
|
content?: string | null
|
||||||
source?: string
|
source?: string
|
||||||
url?: string
|
url?: string
|
||||||
publishedAt: Date | string
|
publishedAt: Date | string
|
||||||
@@ -317,6 +330,7 @@ export type NewsUncheckedCreateInput = {
|
|||||||
id?: number
|
id?: number
|
||||||
title: string
|
title: string
|
||||||
summary?: string
|
summary?: string
|
||||||
|
content?: string | null
|
||||||
source?: string
|
source?: string
|
||||||
url?: string
|
url?: string
|
||||||
publishedAt: Date | string
|
publishedAt: Date | string
|
||||||
@@ -327,6 +341,7 @@ export type NewsUncheckedCreateInput = {
|
|||||||
export type NewsUpdateInput = {
|
export type NewsUpdateInput = {
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
summary?: Prisma.StringFieldUpdateOperationsInput | string
|
summary?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
content?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
source?: Prisma.StringFieldUpdateOperationsInput | string
|
source?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
url?: Prisma.StringFieldUpdateOperationsInput | string
|
url?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
@@ -338,6 +353,7 @@ export type NewsUncheckedUpdateInput = {
|
|||||||
id?: Prisma.IntFieldUpdateOperationsInput | number
|
id?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
summary?: Prisma.StringFieldUpdateOperationsInput | string
|
summary?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
content?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
source?: Prisma.StringFieldUpdateOperationsInput | string
|
source?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
url?: Prisma.StringFieldUpdateOperationsInput | string
|
url?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
@@ -349,6 +365,7 @@ export type NewsCreateManyInput = {
|
|||||||
id?: number
|
id?: number
|
||||||
title: string
|
title: string
|
||||||
summary?: string
|
summary?: string
|
||||||
|
content?: string | null
|
||||||
source?: string
|
source?: string
|
||||||
url?: string
|
url?: string
|
||||||
publishedAt: Date | string
|
publishedAt: Date | string
|
||||||
@@ -359,6 +376,7 @@ export type NewsCreateManyInput = {
|
|||||||
export type NewsUpdateManyMutationInput = {
|
export type NewsUpdateManyMutationInput = {
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
summary?: Prisma.StringFieldUpdateOperationsInput | string
|
summary?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
content?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
source?: Prisma.StringFieldUpdateOperationsInput | string
|
source?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
url?: Prisma.StringFieldUpdateOperationsInput | string
|
url?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
@@ -370,6 +388,7 @@ export type NewsUncheckedUpdateManyInput = {
|
|||||||
id?: Prisma.IntFieldUpdateOperationsInput | number
|
id?: Prisma.IntFieldUpdateOperationsInput | number
|
||||||
title?: Prisma.StringFieldUpdateOperationsInput | string
|
title?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
summary?: Prisma.StringFieldUpdateOperationsInput | string
|
summary?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
|
content?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
|
||||||
source?: Prisma.StringFieldUpdateOperationsInput | string
|
source?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
url?: Prisma.StringFieldUpdateOperationsInput | string
|
url?: Prisma.StringFieldUpdateOperationsInput | string
|
||||||
publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||||
@@ -392,6 +411,7 @@ export type NewsCountOrderByAggregateInput = {
|
|||||||
id?: Prisma.SortOrder
|
id?: Prisma.SortOrder
|
||||||
title?: Prisma.SortOrder
|
title?: Prisma.SortOrder
|
||||||
summary?: Prisma.SortOrder
|
summary?: Prisma.SortOrder
|
||||||
|
content?: Prisma.SortOrder
|
||||||
source?: Prisma.SortOrder
|
source?: Prisma.SortOrder
|
||||||
url?: Prisma.SortOrder
|
url?: Prisma.SortOrder
|
||||||
publishedAt?: Prisma.SortOrder
|
publishedAt?: Prisma.SortOrder
|
||||||
@@ -408,6 +428,7 @@ export type NewsMaxOrderByAggregateInput = {
|
|||||||
id?: Prisma.SortOrder
|
id?: Prisma.SortOrder
|
||||||
title?: Prisma.SortOrder
|
title?: Prisma.SortOrder
|
||||||
summary?: Prisma.SortOrder
|
summary?: Prisma.SortOrder
|
||||||
|
content?: Prisma.SortOrder
|
||||||
source?: Prisma.SortOrder
|
source?: Prisma.SortOrder
|
||||||
url?: Prisma.SortOrder
|
url?: Prisma.SortOrder
|
||||||
publishedAt?: Prisma.SortOrder
|
publishedAt?: Prisma.SortOrder
|
||||||
@@ -419,6 +440,7 @@ export type NewsMinOrderByAggregateInput = {
|
|||||||
id?: Prisma.SortOrder
|
id?: Prisma.SortOrder
|
||||||
title?: Prisma.SortOrder
|
title?: Prisma.SortOrder
|
||||||
summary?: Prisma.SortOrder
|
summary?: Prisma.SortOrder
|
||||||
|
content?: Prisma.SortOrder
|
||||||
source?: Prisma.SortOrder
|
source?: Prisma.SortOrder
|
||||||
url?: Prisma.SortOrder
|
url?: Prisma.SortOrder
|
||||||
publishedAt?: Prisma.SortOrder
|
publishedAt?: Prisma.SortOrder
|
||||||
@@ -431,12 +453,17 @@ export type NewsSumOrderByAggregateInput = {
|
|||||||
impactRank?: Prisma.SortOrder
|
impactRank?: Prisma.SortOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NullableStringFieldUpdateOperationsInput = {
|
||||||
|
set?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export type NewsSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
export type NewsSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
||||||
id?: boolean
|
id?: boolean
|
||||||
title?: boolean
|
title?: boolean
|
||||||
summary?: boolean
|
summary?: boolean
|
||||||
|
content?: boolean
|
||||||
source?: boolean
|
source?: boolean
|
||||||
url?: boolean
|
url?: boolean
|
||||||
publishedAt?: boolean
|
publishedAt?: boolean
|
||||||
@@ -450,6 +477,7 @@ export type NewsSelectScalar = {
|
|||||||
id?: boolean
|
id?: boolean
|
||||||
title?: boolean
|
title?: boolean
|
||||||
summary?: boolean
|
summary?: boolean
|
||||||
|
content?: boolean
|
||||||
source?: boolean
|
source?: boolean
|
||||||
url?: boolean
|
url?: boolean
|
||||||
publishedAt?: boolean
|
publishedAt?: boolean
|
||||||
@@ -457,7 +485,7 @@ export type NewsSelectScalar = {
|
|||||||
createdAt?: boolean
|
createdAt?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NewsOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "title" | "summary" | "source" | "url" | "publishedAt" | "impactRank" | "createdAt", ExtArgs["result"]["news"]>
|
export type NewsOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "title" | "summary" | "content" | "source" | "url" | "publishedAt" | "impactRank" | "createdAt", ExtArgs["result"]["news"]>
|
||||||
|
|
||||||
export type $NewsPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
export type $NewsPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||||
name: "News"
|
name: "News"
|
||||||
@@ -466,6 +494,7 @@ export type $NewsPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
|
|||||||
id: number
|
id: number
|
||||||
title: string
|
title: string
|
||||||
summary: string
|
summary: string
|
||||||
|
content: string | null
|
||||||
source: string
|
source: string
|
||||||
url: string
|
url: string
|
||||||
publishedAt: Date
|
publishedAt: Date
|
||||||
@@ -843,6 +872,7 @@ export interface NewsFieldRefs {
|
|||||||
readonly id: Prisma.FieldRef<"News", 'Int'>
|
readonly id: Prisma.FieldRef<"News", 'Int'>
|
||||||
readonly title: Prisma.FieldRef<"News", 'String'>
|
readonly title: Prisma.FieldRef<"News", 'String'>
|
||||||
readonly summary: Prisma.FieldRef<"News", 'String'>
|
readonly summary: Prisma.FieldRef<"News", 'String'>
|
||||||
|
readonly content: Prisma.FieldRef<"News", 'String'>
|
||||||
readonly source: Prisma.FieldRef<"News", 'String'>
|
readonly source: Prisma.FieldRef<"News", 'String'>
|
||||||
readonly url: Prisma.FieldRef<"News", 'String'>
|
readonly url: Prisma.FieldRef<"News", 'String'>
|
||||||
readonly publishedAt: Prisma.FieldRef<"News", 'DateTime'>
|
readonly publishedAt: Prisma.FieldRef<"News", 'DateTime'>
|
||||||
|
|||||||
@@ -391,10 +391,6 @@ export type ScraperCacheSumOrderByAggregateInput = {
|
|||||||
id?: Prisma.SortOrder
|
id?: Prisma.SortOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NullableStringFieldUpdateOperationsInput = {
|
|
||||||
set?: string | null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export type ScraperCacheSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
export type ScraperCacheSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Generated
+23
-1
@@ -24,7 +24,8 @@
|
|||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router-dom": "^6.26.0",
|
"react-router-dom": "^6.26.0",
|
||||||
"recharts": "^3.8.1"
|
"recharts": "^3.8.1",
|
||||||
|
"ws": "^8.21.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/api": "^2.0.0",
|
"@tauri-apps/api": "^2.0.0",
|
||||||
@@ -6360,6 +6361,27 @@
|
|||||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.21.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.21.2.tgz",
|
||||||
|
"integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/y18n": {
|
"node_modules/y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
|||||||
+2
-1
@@ -41,7 +41,8 @@
|
|||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router-dom": "^6.26.0",
|
"react-router-dom": "^6.26.0",
|
||||||
"recharts": "^3.8.1"
|
"recharts": "^3.8.1",
|
||||||
|
"ws": "^8.21.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/api": "^2.0.0",
|
"@tauri-apps/api": "^2.0.0",
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
-- 服务器监控 + 服务健康检查
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE `ServerNode` (
|
||||||
|
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||||
|
`uuid` VARCHAR(191) NOT NULL,
|
||||||
|
`name` VARCHAR(191) NOT NULL,
|
||||||
|
`cpuName` VARCHAR(191) NOT NULL DEFAULT '',
|
||||||
|
`os` VARCHAR(191) NOT NULL DEFAULT '',
|
||||||
|
`region` VARCHAR(191) NOT NULL DEFAULT '',
|
||||||
|
`memTotal` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`diskTotal` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`cpuCores` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
`cpuUsage` DOUBLE NOT NULL DEFAULT 0,
|
||||||
|
`ramUsed` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`swapUsed` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`load1` DOUBLE NOT NULL DEFAULT 0,
|
||||||
|
`load5` DOUBLE NOT NULL DEFAULT 0,
|
||||||
|
`load15` DOUBLE NOT NULL DEFAULT 0,
|
||||||
|
`diskUsed` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`netIn` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`netOut` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`uptime` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`process` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
`connections` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
`status` VARCHAR(191) NOT NULL DEFAULT 'unknown',
|
||||||
|
`recordedAt` DATETIME(3) NOT NULL,
|
||||||
|
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`updatedAt` DATETIME(3) NOT NULL,
|
||||||
|
|
||||||
|
UNIQUE INDEX `ServerNode_uuid_key`(`uuid`),
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE `ServerNodeHistory` (
|
||||||
|
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||||
|
`uuid` VARCHAR(191) NOT NULL,
|
||||||
|
`period` DATETIME(3) NOT NULL,
|
||||||
|
`cpu` DOUBLE NOT NULL DEFAULT 0,
|
||||||
|
`ram` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`load` DOUBLE NOT NULL DEFAULT 0,
|
||||||
|
`disk` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`netIn` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`netOut` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`process` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
`connections` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
|
||||||
|
UNIQUE INDEX `ServerNodeHistory_uuid_period_key`(`uuid`, `period`),
|
||||||
|
INDEX `ServerNodeHistory_uuid_period_idx`(`uuid`, `period`),
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE `ServiceCheck` (
|
||||||
|
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` VARCHAR(191) NOT NULL,
|
||||||
|
`url` VARCHAR(191) NOT NULL,
|
||||||
|
`status` VARCHAR(191) NOT NULL DEFAULT 'unknown',
|
||||||
|
`latencyMs` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
`message` VARCHAR(191) NOT NULL DEFAULT '',
|
||||||
|
`lastCheckAt` DATETIME(3) NOT NULL,
|
||||||
|
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||||
|
`updatedAt` DATETIME(3) NOT NULL,
|
||||||
|
|
||||||
|
UNIQUE INDEX `ServiceCheck_name_key`(`name`),
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable (news.content 全文, 须在 news_and_alerts 建表之后执行)
|
||||||
|
ALTER TABLE `News` ADD COLUMN `content` TEXT NULL;
|
||||||
@@ -72,6 +72,7 @@ model News {
|
|||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
title String
|
title String
|
||||||
summary String @default("")
|
summary String @default("")
|
||||||
|
content String? @db.Text
|
||||||
source String @default("")
|
source String @default("")
|
||||||
url String @default("")
|
url String @default("")
|
||||||
publishedAt DateTime
|
publishedAt DateTime
|
||||||
@@ -98,6 +99,69 @@ model Alert {
|
|||||||
@@index([createdAt])
|
@@index([createdAt])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 服务器监控: 对接 komari 公开 API
|
||||||
|
model ServerNode {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
uuid String @unique
|
||||||
|
name String
|
||||||
|
cpuName String @default("")
|
||||||
|
os String @default("")
|
||||||
|
region String @default("")
|
||||||
|
memTotal BigInt @default(0)
|
||||||
|
diskTotal BigInt @default(0)
|
||||||
|
cpuCores Int @default(0)
|
||||||
|
// 最新实时快照
|
||||||
|
cpuUsage Float @default(0)
|
||||||
|
ramUsed BigInt @default(0)
|
||||||
|
swapUsed BigInt @default(0)
|
||||||
|
load1 Float @default(0)
|
||||||
|
load5 Float @default(0)
|
||||||
|
load15 Float @default(0)
|
||||||
|
diskUsed BigInt @default(0)
|
||||||
|
netIn BigInt @default(0)
|
||||||
|
netOut BigInt @default(0)
|
||||||
|
uptime BigInt @default(0)
|
||||||
|
process Int @default(0)
|
||||||
|
connections Int @default(0)
|
||||||
|
status String @default("unknown") // online | offline | unknown
|
||||||
|
recordedAt DateTime
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时序历史: 每节点每分钟一条 (komari records 1 分钟粒度)
|
||||||
|
model ServerNodeHistory {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
uuid String
|
||||||
|
period DateTime
|
||||||
|
cpu Float @default(0)
|
||||||
|
ram BigInt @default(0)
|
||||||
|
load Float @default(0)
|
||||||
|
disk BigInt @default(0)
|
||||||
|
netIn BigInt @default(0)
|
||||||
|
netOut BigInt @default(0)
|
||||||
|
process Int @default(0)
|
||||||
|
connections Int @default(0)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
|
@@unique([uuid, period])
|
||||||
|
@@index([uuid, period])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 服务健康检查: 本应用自检 (健康端点 / DB / 第三方)
|
||||||
|
model ServiceCheck {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
name String @unique
|
||||||
|
url String
|
||||||
|
status String @default("unknown") // up | down | unknown
|
||||||
|
latencyMs Int @default(0)
|
||||||
|
message String @default("")
|
||||||
|
lastCheckAt DateTime
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
}
|
||||||
|
|
||||||
model Econ_SowInventory {
|
model Econ_SowInventory {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
month String @unique
|
month String @unique
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const content = `import cron from 'node-cron'
|
||||||
|
import { prisma } from './db.js'
|
||||||
|
import mysql from 'mysql2/promise'
|
||||||
|
import { fetchNewsList, persistNews } from '../scripts/fetchers/news.fetcher.js'
|
||||||
|
import { checkAfterRefresh } from './alert-engine.js'
|
||||||
|
|
||||||
|
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(/^\\//, '') }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openConn() {
|
||||||
|
return mysql.createConnection(parseUrl(process.env.DATABASE_URL))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每天凌晨 3:00 (本地时间) 拉取新闻 + 跑跨源对比
|
||||||
|
function scheduleNews() {
|
||||||
|
cron.schedule('0 3 * * *', async () => {
|
||||||
|
console.log('[cron] 3:00 触发')
|
||||||
|
try {
|
||||||
|
const list = await fetchNewsList()
|
||||||
|
const r = await persistNews(list)
|
||||||
|
console.log('[cron] 新闻入库: 新增 ' + r.inserted + ' / 跳过 ' + r.skipped)
|
||||||
|
const conn = await openConn()
|
||||||
|
try {
|
||||||
|
const a = await checkAfterRefresh(conn)
|
||||||
|
console.log('[cron] 报警检测: 新增 ' + a.inserted + ' 条 (扫描 ' + a.scanned + ')')
|
||||||
|
} finally { await conn.end() }
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[cron] 任务失败:', e.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
console.log('[cron] 已注册: 每天 03:00 拉取新闻 + 跨源报警检测')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每 2 分钟: 拉取 komari 节点 + 服务自检
|
||||||
|
function scheduleMonitors() {
|
||||||
|
cron.schedule('*/2 * * * *', async () => {
|
||||||
|
try {
|
||||||
|
const k = require('./komari-monitor.cjs')
|
||||||
|
const r = await k.runOnce()
|
||||||
|
console.log('[cron] komari: nodes=' + r.nodes + ' snapshots=' + r.snapshots + ' history=' + r.history + ' failed=' + r.failed)
|
||||||
|
} catch (e) { console.error('[cron] komari 任务失败:', e.message) }
|
||||||
|
try {
|
||||||
|
const h = require('./health-check.cjs')
|
||||||
|
const arr = await h.runOnce()
|
||||||
|
const down = arr.filter(x => x.status !== 'up').map(x => x.name)
|
||||||
|
console.log('[cron] health: ' + arr.length + ' 项, down=' + (down.length ? down.join(',') : '无'))
|
||||||
|
} catch (e) { console.error('[cron] health 任务失败:', e.message) }
|
||||||
|
})
|
||||||
|
console.log('[cron] 已注册: 每 2 分钟 komari + 服务自检')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每小时: 清理 24h 前的 komari 历史
|
||||||
|
function scheduleMonitorCleanup() {
|
||||||
|
cron.schedule('0 * * * *', async () => {
|
||||||
|
try {
|
||||||
|
const k = require('./komari-monitor.cjs')
|
||||||
|
const n = await k.cleanupOld()
|
||||||
|
console.log('[cron] 监控历史清理: 删除 ' + n + ' 条')
|
||||||
|
} catch (e) { console.error('[cron] 监控清理失败:', e.message) }
|
||||||
|
})
|
||||||
|
console.log('[cron] 已注册: 每小时清理 24h 前监控历史')
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleNews()
|
||||||
|
scheduleMonitors()
|
||||||
|
scheduleMonitorCleanup()
|
||||||
|
`
|
||||||
|
fs.writeFileSync('server/cron.js', content, 'utf8')
|
||||||
|
console.log('OK len=' + content.length)
|
||||||
@@ -50,15 +50,17 @@ function parseNewsSheet(sheet, impactBase = 0) {
|
|||||||
const out = []
|
const out = []
|
||||||
for (let i = 0; i < sheet.items.length; i++) {
|
for (let i = 0; i < sheet.items.length; i++) {
|
||||||
const r = sheet.items[i]
|
const r = sheet.items[i]
|
||||||
const title = String(r[0] || '').trim()
|
const title = String(r[0] || '').trim().slice(0, 190)
|
||||||
if (!title) continue
|
if (!title) continue
|
||||||
const publishedAt = parsePublishedAt(r[2])
|
const publishedAt = parsePublishedAt(r[2])
|
||||||
if (!publishedAt) continue
|
if (!publishedAt) continue
|
||||||
|
const body = String(r[1] || '').trim()
|
||||||
out.push({
|
out.push({
|
||||||
title,
|
title,
|
||||||
summary: String(r[1] || '').trim().slice(0, 180),
|
summary: body.slice(0, 180),
|
||||||
|
content: body.slice(0, 8000), // 正文全文 (MCP "摘要"列实际是正文), 上限防异常超长
|
||||||
source: String(r[3] || '').trim().slice(0, 80),
|
source: String(r[3] || '').trim().slice(0, 80),
|
||||||
url: String(r[4] || '').trim().slice(0, 400),
|
url: String(r[4] || '').trim().slice(0, 190), // 列宽 varchar(191), 超长会被 MySQL 拒绝
|
||||||
publishedAt,
|
publishedAt,
|
||||||
impactRank: impactBase + i + 1,
|
impactRank: impactBase + i + 1,
|
||||||
})
|
})
|
||||||
@@ -103,20 +105,27 @@ export async function persistNews(newsList) {
|
|||||||
if (!process.env.DATABASE_URL) throw new Error('缺少 DATABASE_URL')
|
if (!process.env.DATABASE_URL) throw new Error('缺少 DATABASE_URL')
|
||||||
if (!newsList || newsList.length === 0) return { inserted: 0, skipped: 0 }
|
if (!newsList || newsList.length === 0) return { inserted: 0, skipped: 0 }
|
||||||
const conn = await mysql.createConnection(parseUrl(process.env.DATABASE_URL))
|
const conn = await mysql.createConnection(parseUrl(process.env.DATABASE_URL))
|
||||||
let inserted = 0, skipped = 0
|
let inserted = 0, skipped = 0, failed = 0
|
||||||
try {
|
try {
|
||||||
for (const n of newsList) {
|
for (const n of newsList) {
|
||||||
const [r] = await conn.execute(
|
try {
|
||||||
'INSERT INTO `News` (`title`, `summary`, `source`, `url`, `publishedAt`, `impactRank`, `createdAt`) ' +
|
// 注意: content 列依赖迁移 add_news_content 已应用, 发布顺序须先迁移后跑本脚本
|
||||||
'VALUES (?, ?, ?, ?, ?, ?, NOW(3)) ' +
|
// 重复命中 (title, publishedAt) 时只回填仍为 NULL 的 content, 避免覆盖已有全文
|
||||||
'ON DUPLICATE KEY UPDATE `impactRank` = VALUES(`impactRank`)',
|
const [r] = await conn.execute(
|
||||||
[n.title, n.summary, n.source, n.url, n.publishedAt, n.impactRank],
|
'INSERT INTO `News` (`title`, `summary`, `content`, `source`, `url`, `publishedAt`, `impactRank`, `createdAt`) ' +
|
||||||
)
|
'VALUES (?, ?, ?, ?, ?, ?, ?, NOW(3)) ' +
|
||||||
if (r.affectedRows === 1) inserted++
|
'AS new ON DUPLICATE KEY UPDATE `impactRank` = new.`impactRank`, `content` = IFNULL(News.`content`, new.`content`)',
|
||||||
else skipped++
|
[n.title, n.summary, n.content || null, n.source, n.url, n.publishedAt, n.impactRank],
|
||||||
|
)
|
||||||
|
if (r.affectedRows === 1) inserted++
|
||||||
|
else skipped++
|
||||||
|
} catch (e) {
|
||||||
|
failed++
|
||||||
|
console.error('[News] 单条入库失败:', n.title, e.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
await conn.end()
|
await conn.end()
|
||||||
}
|
}
|
||||||
return { inserted, skipped }
|
return { inserted, skipped, failed }
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,6 @@ async function main() {
|
|||||||
console.log('[News] 拉取 ' + list.length + ' 条, 耗时 ' + ((Date.now() - t0) / 1000).toFixed(1) + 's')
|
console.log('[News] 拉取 ' + list.length + ' 条, 耗时 ' + ((Date.now() - t0) / 1000).toFixed(1) + 's')
|
||||||
if (list.length === 0) { console.log('[News] 无数据, 跳过'); return }
|
if (list.length === 0) { console.log('[News] 无数据, 跳过'); return }
|
||||||
const r = await mod.persistNews(list)
|
const r = await mod.persistNews(list)
|
||||||
console.log('[News] 入库: 新增 ' + r.inserted + ' 条, 重复跳过 ' + r.skipped + ' 条')
|
console.log('[News] 入库: 新增 ' + r.inserted + ' 条, 重复跳过 ' + r.skipped + ' 条' + (r.failed ? ', 失败 ' + r.failed + ' 条' : ''))
|
||||||
}
|
}
|
||||||
main().catch((e) => { console.error('[News] 失败:', e); process.exit(1) })
|
main().catch((e) => { console.error('[News] 失败:', e); process.exit(1) })
|
||||||
|
|||||||
@@ -33,4 +33,36 @@ function scheduleNews() {
|
|||||||
console.log('[cron] 已注册: 每天 03:00 拉取新闻 + 跨源报警检测')
|
console.log('[cron] 已注册: 每天 03:00 拉取新闻 + 跨源报警检测')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 每 2 分钟: 拉取 komari 节点 + 服务自检
|
||||||
|
function scheduleMonitors() {
|
||||||
|
cron.schedule('*/2 * * * *', async () => {
|
||||||
|
try {
|
||||||
|
const k = require('./komari-monitor.cjs')
|
||||||
|
const r = await k.runOnce()
|
||||||
|
console.log('[cron] komari: nodes=' + r.nodes + ' snapshots=' + r.snapshots + ' history=' + r.history + ' failed=' + r.failed)
|
||||||
|
} catch (e) { console.error('[cron] komari 任务失败:', e.message) }
|
||||||
|
try {
|
||||||
|
const h = require('./health-check.cjs')
|
||||||
|
const arr = await h.runOnce()
|
||||||
|
const down = arr.filter(x => x.status !== 'up').map(x => x.name)
|
||||||
|
console.log('[cron] health: ' + arr.length + ' 项, down=' + (down.length ? down.join(',') : '无'))
|
||||||
|
} catch (e) { console.error('[cron] health 任务失败:', e.message) }
|
||||||
|
})
|
||||||
|
console.log('[cron] 已注册: 每 2 分钟 komari + 服务自检')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每小时: 清理 24h 前的 komari 历史
|
||||||
|
function scheduleMonitorCleanup() {
|
||||||
|
cron.schedule('0 * * * *', async () => {
|
||||||
|
try {
|
||||||
|
const k = require('./komari-monitor.cjs')
|
||||||
|
const n = await k.cleanupOld()
|
||||||
|
console.log('[cron] 监控历史清理: 删除 ' + n + ' 条')
|
||||||
|
} catch (e) { console.error('[cron] 监控清理失败:', e.message) }
|
||||||
|
})
|
||||||
|
console.log('[cron] 已注册: 每小时清理 24h 前监控历史')
|
||||||
|
}
|
||||||
|
|
||||||
scheduleNews()
|
scheduleNews()
|
||||||
|
scheduleMonitors()
|
||||||
|
scheduleMonitorCleanup()
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// 服务健康检查: 探测本应用各关键端点, 写入 ServiceCheck 表
|
||||||
|
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(/^\//, '') } }
|
||||||
|
|
||||||
|
const TARGETS = [
|
||||||
|
{ name: 'api-health', url: 'http://127.0.0.1:' + (process.env.PORT || 3001) + '/api/health' },
|
||||||
|
{ name: 'auth-login', url: 'http://127.0.0.1:' + (process.env.PORT || 3001) + '/api/auth/login' },
|
||||||
|
]
|
||||||
|
|
||||||
|
async function probeOne(target) {
|
||||||
|
const t0 = Date.now()
|
||||||
|
try {
|
||||||
|
const ctrl = new AbortController()
|
||||||
|
setTimeout(() => ctrl.abort(), 8000)
|
||||||
|
const r = await fetch(target.url, { method: 'GET', signal: ctrl.signal })
|
||||||
|
const latency = Date.now() - t0
|
||||||
|
const status = (r.ok || r.status === 400 || r.status === 401) ? 'up' : 'down'
|
||||||
|
const msg = 'HTTP ' + r.status
|
||||||
|
return { name: target.name, url: target.url, status, latencyMs: latency, message: msg }
|
||||||
|
} catch (e) {
|
||||||
|
return { name: target.name, url: target.url, status: 'down', latencyMs: Date.now() - t0, message: e.message || String(e) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkDb() {
|
||||||
|
const t0 = Date.now()
|
||||||
|
try {
|
||||||
|
const conn = await mysql.createConnection(parseUrl(process.env.DATABASE_URL))
|
||||||
|
await conn.execute('SELECT 1')
|
||||||
|
await conn.end()
|
||||||
|
return { name: 'database', url: 'mysql://' + (new URL(process.env.DATABASE_URL)).host, status: 'up', latencyMs: Date.now() - t0, message: 'ok' }
|
||||||
|
} catch (e) {
|
||||||
|
return { name: 'database', url: 'mysql', status: 'down', latencyMs: Date.now() - t0, message: e.message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runOnce() {
|
||||||
|
const results = await Promise.all([...TARGETS.map(probeOne), checkDb()])
|
||||||
|
const conn = await mysql.createConnection(parseUrl(process.env.DATABASE_URL))
|
||||||
|
try {
|
||||||
|
for (const r of results) {
|
||||||
|
await conn.execute(
|
||||||
|
'INSERT INTO `ServiceCheck` (`name`,`url`,`status`,`latencyMs`,`message`,`lastCheckAt`,`createdAt`,`updatedAt`) VALUES (?,?,?,?,?,NOW(3),NOW(3),NOW(3)) ' +
|
||||||
|
'ON DUPLICATE KEY UPDATE `url`=VALUES(`url`),`status`=VALUES(`status`),`latencyMs`=VALUES(`latencyMs`),`message`=VALUES(`message`),`lastCheckAt`=NOW(3),`updatedAt`=NOW(3)',
|
||||||
|
[r.name, r.url, r.status, r.latencyMs, r.message.slice(0, 180)],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
await conn.end()
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { runOnce, TARGETS }
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
// komari 服务器监控拉取: 公开 API (无需 key)
|
||||||
|
// GET /api/nodes 节点列表
|
||||||
|
// GET /api/recent/{uuid} 最近实时状态 (数组, 多个时间点)
|
||||||
|
// GET /api/records/load?uuid=... 1 分钟粒度历史 (保留 24h)
|
||||||
|
const mysql = require('mysql2/promise')
|
||||||
|
|
||||||
|
const BASE = process.env.KOMARI_BASE || 'https://komari.honor3.com'
|
||||||
|
const TIMEOUT = 20000
|
||||||
|
|
||||||
|
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(/^\//, '') }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function jget(path) {
|
||||||
|
const ctrl = new AbortController()
|
||||||
|
setTimeout(() => ctrl.abort(), TIMEOUT)
|
||||||
|
const r = await fetch(BASE + path, { headers: { 'User-Agent': 'iboard-monitor/1.0' }, signal: ctrl.signal })
|
||||||
|
if (!r.ok) throw new Error('komari ' + path + ' HTTP ' + r.status)
|
||||||
|
const j = await r.json()
|
||||||
|
if (j.status && j.status !== 'success') throw new Error('komari ' + path + ' status: ' + j.status + ' ' + (j.message || ''))
|
||||||
|
return j.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拉一次所有节点 + 最近状态 + 1 分钟历史, 入库
|
||||||
|
async function runOnce() {
|
||||||
|
const conn = await mysql.createConnection(parseUrl(process.env.DATABASE_URL))
|
||||||
|
const stats = { nodes: 0, snapshots: 0, history: 0, failed: 0 }
|
||||||
|
try {
|
||||||
|
const nodes = await jget('/api/nodes')
|
||||||
|
if (!Array.isArray(nodes)) throw new Error('nodes 格式异常')
|
||||||
|
stats.nodes = nodes.length
|
||||||
|
for (const n of nodes) {
|
||||||
|
const uuid = n.uuid
|
||||||
|
if (!uuid) continue
|
||||||
|
try {
|
||||||
|
const recent = await jget('/api/recent/' + uuid)
|
||||||
|
let snap = null
|
||||||
|
if (Array.isArray(recent) && recent.length) snap = recent[recent.length - 1]
|
||||||
|
const recordedAt = snap ? new Date(snap.updated_at) : new Date()
|
||||||
|
const ramTotal = snap && snap.ram ? Number(snap.ram.total) : Number(n.mem_total || 0)
|
||||||
|
const diskTotal = snap && snap.disk ? Number(snap.disk.total) : Number(n.disk_total || 0)
|
||||||
|
await conn.execute(
|
||||||
|
'INSERT INTO `ServerNode` (`uuid`,`name`,`cpuName`,`os`,`region`,`memTotal`,`diskTotal`,`cpuCores`,' +
|
||||||
|
'`cpuUsage`,`ramUsed`,`swapUsed`,`load1`,`load5`,`load15`,`diskUsed`,`netIn`,`netOut`,`uptime`,`process`,`connections`,`status`,`recordedAt`,`createdAt`,`updatedAt`) ' +
|
||||||
|
'VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(3),NOW(3)) ' +
|
||||||
|
'ON DUPLICATE KEY UPDATE `name`=VALUES(`name`),`cpuName`=VALUES(`cpuName`),`os`=VALUES(`os`),`region`=VALUES(`region`),' +
|
||||||
|
'`memTotal`=VALUES(`memTotal`),`diskTotal`=VALUES(`diskTotal`),`cpuCores`=VALUES(`cpuCores`),' +
|
||||||
|
'`cpuUsage`=VALUES(`cpuUsage`),`ramUsed`=VALUES(`ramUsed`),`swapUsed`=VALUES(`swapUsed`),' +
|
||||||
|
'`load1`=VALUES(`load1`),`load5`=VALUES(`load5`),`load15`=VALUES(`load15`),`diskUsed`=VALUES(`diskUsed`),' +
|
||||||
|
'`netIn`=VALUES(`netIn`),`netOut`=VALUES(`netOut`),`uptime`=VALUES(`uptime`),' +
|
||||||
|
'`process`=VALUES(`process`),`connections`=VALUES(`connections`),`status`=VALUES(`status`),' +
|
||||||
|
'`recordedAt`=VALUES(`recordedAt`),`updatedAt`=NOW(3)',
|
||||||
|
[
|
||||||
|
uuid, n.name || '', n.cpu_name || '', n.os || '', n.region || '',
|
||||||
|
ramTotal, diskTotal, Number(n.cpu_cores || 0),
|
||||||
|
snap ? Number(snap.cpu?.usage || 0) : 0,
|
||||||
|
snap ? Number(snap.ram?.used || 0) : 0,
|
||||||
|
snap ? Number(snap.swap?.used || 0) : 0,
|
||||||
|
snap ? Number(snap.load?.load1 || 0) : 0,
|
||||||
|
snap ? Number(snap.load?.load5 || 0) : 0,
|
||||||
|
snap ? Number(snap.load?.load15 || 0) : 0,
|
||||||
|
snap ? Number(snap.disk?.used || 0) : 0,
|
||||||
|
snap ? Number(snap.network?.down || 0) : 0,
|
||||||
|
snap ? Number(snap.network?.up || 0) : 0,
|
||||||
|
snap ? Number(snap.uptime || 0) : 0,
|
||||||
|
snap ? Number(snap.process || 0) : 0,
|
||||||
|
snap ? Number(snap.connections?.tcp || 0) : 0,
|
||||||
|
snap ? 'online' : 'unknown',
|
||||||
|
recordedAt,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
stats.snapshots++
|
||||||
|
|
||||||
|
let rec = null
|
||||||
|
try { rec = await jget('/api/records/load?uuid=' + uuid) } catch (e) { /* 节点未开启 record */ }
|
||||||
|
if (rec && Array.isArray(rec.records)) {
|
||||||
|
for (const r of rec.records) {
|
||||||
|
const period = new Date(r.time)
|
||||||
|
if (isNaN(period.getTime())) continue
|
||||||
|
const [res] = await conn.execute(
|
||||||
|
'INSERT INTO `ServerNodeHistory` (`uuid`,`period`,`cpu`,`ram`,`load`,`disk`,`netIn`,`netOut`,`process`,`connections`,`createdAt`) ' +
|
||||||
|
'VALUES (?,?,?,?,?,?,?,?,?,?,NOW(3)) ' +
|
||||||
|
'ON DUPLICATE KEY UPDATE `cpu`=VALUES(`cpu`),`ram`=VALUES(`ram`),`load`=VALUES(`load`),`disk`=VALUES(`disk`),' +
|
||||||
|
'`netIn`=VALUES(`netIn`),`netOut`=VALUES(`netOut`),`process`=VALUES(`process`),`connections`=VALUES(`connections`)',
|
||||||
|
[
|
||||||
|
uuid, period,
|
||||||
|
Number(r.cpu || 0), Number(r.ram || 0), Number(r.load || 0),
|
||||||
|
Number(r.disk || 0), Number(r.net_in || 0), Number(r.net_out || 0),
|
||||||
|
Number(r.process || 0), Number(r.connections || 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if (res.affectedRows === 1) stats.history++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
stats.failed++
|
||||||
|
console.error('[komari] 节点 ' + uuid + ' 失败:', e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
await conn.end()
|
||||||
|
}
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理 24h 之前的历史
|
||||||
|
async function cleanupOld() {
|
||||||
|
const conn = await mysql.createConnection(parseUrl(process.env.DATABASE_URL))
|
||||||
|
try {
|
||||||
|
const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000)
|
||||||
|
const [r] = await conn.execute('DELETE FROM `ServerNodeHistory` WHERE `period` < ?', [cutoff])
|
||||||
|
return r.affectedRows
|
||||||
|
} finally {
|
||||||
|
await conn.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { runOnce, cleanupOld, BASE }
|
||||||
|
|
||||||
+13
-8
@@ -8,16 +8,21 @@ router.use(authRequired)
|
|||||||
// 报警列表: 按时间最新优先, cursor 分页 (cursor = id)
|
// 报警列表: 按时间最新优先, cursor 分页 (cursor = id)
|
||||||
router.get('/alerts', async (req, res, next) => {
|
router.get('/alerts', async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const limit = Math.min(Number(req.query.limit) || 10, 50)
|
const rawLimit = Number(req.query.limit)
|
||||||
const cursor = req.query.cursor ? Number(req.query.cursor) : null
|
const limit = Number.isFinite(rawLimit) && rawLimit >= 1 ? Math.min(Math.floor(rawLimit), 50) : 10
|
||||||
|
const rawCursor = Number(req.query.cursor)
|
||||||
|
const cursor = Number.isInteger(rawCursor) && rawCursor > 0 ? rawCursor : null
|
||||||
const where = cursor ? { id: { lt: cursor } } : {}
|
const where = cursor ? { id: { lt: cursor } } : {}
|
||||||
const items = await prisma.alert.findMany({
|
const [items, total] = await Promise.all([
|
||||||
where,
|
prisma.alert.findMany({
|
||||||
orderBy: { id: 'desc' },
|
where,
|
||||||
take: limit,
|
orderBy: { id: 'desc' },
|
||||||
})
|
take: limit,
|
||||||
|
}),
|
||||||
|
prisma.alert.count(),
|
||||||
|
])
|
||||||
const nextCursor = items.length === limit ? String(items[items.length - 1].id) : null
|
const nextCursor = items.length === limit ? String(items[items.length - 1].id) : null
|
||||||
res.json({ items, nextCursor })
|
res.json({ items, nextCursor, total })
|
||||||
} catch (e) { next(e) }
|
} catch (e) { next(e) }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { Router } from 'express'
|
||||||
|
import { prisma } from '../db.js'
|
||||||
|
import { authRequired } from '../middleware.js'
|
||||||
|
|
||||||
|
const router = Router()
|
||||||
|
router.use(authRequired)
|
||||||
|
|
||||||
|
// 服务器节点列表: 元数据 + 最新快照
|
||||||
|
router.get('/servers', async (_req, res, next) => {
|
||||||
|
try {
|
||||||
|
const rows = await prisma.serverNode.findMany({
|
||||||
|
orderBy: { name: 'asc' },
|
||||||
|
})
|
||||||
|
res.json({ items: rows })
|
||||||
|
} catch (e) { next(e) }
|
||||||
|
})
|
||||||
|
|
||||||
|
// 节点时序: ?uuid=...&hours=24
|
||||||
|
router.get('/servers/:uuid/history', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const hours = Math.min(Math.max(Number(req.query.hours) || 24, 1), 168)
|
||||||
|
const since = new Date(Date.now() - hours * 3600 * 1000)
|
||||||
|
const rows = await prisma.serverNodeHistory.findMany({
|
||||||
|
where: { uuid: req.params.uuid, period: { gte: since } },
|
||||||
|
orderBy: { period: 'asc' },
|
||||||
|
take: 2000,
|
||||||
|
})
|
||||||
|
res.json({ items: rows })
|
||||||
|
} catch (e) { next(e) }
|
||||||
|
})
|
||||||
|
|
||||||
|
// 服务健康列表
|
||||||
|
router.get('/services', async (_req, res, next) => {
|
||||||
|
try {
|
||||||
|
const rows = await prisma.serviceCheck.findMany({
|
||||||
|
orderBy: { name: 'asc' },
|
||||||
|
})
|
||||||
|
res.json({ items: rows })
|
||||||
|
} catch (e) { next(e) }
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
+32
-6
@@ -5,21 +5,47 @@ import { authRequired } from '../middleware.js'
|
|||||||
const router = Router()
|
const router = Router()
|
||||||
router.use(authRequired)
|
router.use(authRequired)
|
||||||
|
|
||||||
// 新闻列表: 按时间最新优先, cursor 分页 (cursor = publishedAt ISO 字符串)
|
// 新闻列表: 按时间最新优先, cursor 分页
|
||||||
// 用 prisma cursor 配合 id 兜底 (同一秒发布的新闻)
|
// cursor 格式: "<publishedAt ISO>|<lastId>", 兼容旧版纯时间戳 (不带 |)
|
||||||
|
// 同秒多条时用 id 兜底, 避免翻页时整批漏掉
|
||||||
router.get('/news', async (req, res, next) => {
|
router.get('/news', async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const limit = Math.min(Number(req.query.limit) || 10, 50)
|
const rawLimit = Number(req.query.limit)
|
||||||
const cursor = req.query.cursor || null
|
const limit = Number.isFinite(rawLimit) && rawLimit >= 1 ? Math.min(Math.floor(rawLimit), 50) : 10
|
||||||
const where = cursor ? { publishedAt: { lt: new Date(cursor) } } : {}
|
let where = {}
|
||||||
|
const cursor = req.query.cursor || ''
|
||||||
|
if (cursor) {
|
||||||
|
const [ts, idRaw] = cursor.split('|')
|
||||||
|
const c = new Date(ts)
|
||||||
|
if (!isNaN(c.getTime())) {
|
||||||
|
const id = Number(idRaw)
|
||||||
|
where = id > 0
|
||||||
|
? { OR: [{ publishedAt: { lt: c } }, { publishedAt: c, id: { lt: id } }] }
|
||||||
|
: { publishedAt: { lt: c } }
|
||||||
|
}
|
||||||
|
}
|
||||||
const items = await prisma.news.findMany({
|
const items = await prisma.news.findMany({
|
||||||
|
select: { id: true, title: true, summary: true, source: true, url: true, publishedAt: true, impactRank: true },
|
||||||
where,
|
where,
|
||||||
orderBy: [{ publishedAt: 'desc' }, { id: 'desc' }],
|
orderBy: [{ publishedAt: 'desc' }, { id: 'desc' }],
|
||||||
take: limit,
|
take: limit,
|
||||||
})
|
})
|
||||||
const nextCursor = items.length === limit ? items[items.length - 1].publishedAt.toISOString() : null
|
const nextCursor = items.length === limit && items.length > 0
|
||||||
|
? items[items.length - 1].publishedAt.toISOString() + '|' + items[items.length - 1].id
|
||||||
|
: null
|
||||||
res.json({ items, nextCursor })
|
res.json({ items, nextCursor })
|
||||||
} catch (e) { next(e) }
|
} catch (e) { next(e) }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 新闻详情: 含正文 content
|
||||||
|
router.get('/news/:id', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const id = Number(req.params.id)
|
||||||
|
if (!Number.isInteger(id) || id <= 0) return res.status(400).json({ error: '无效的新闻 id' })
|
||||||
|
const item = await prisma.news.findUnique({ where: { id } })
|
||||||
|
if (!item) return res.status(404).json({ error: '新闻不存在' })
|
||||||
|
res.json({ item })
|
||||||
|
} catch (e) { next(e) }
|
||||||
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Routes, Route, Navigate, useLocation } from 'react-router-dom'
|
|||||||
import MobileShell from './layouts/MobileShell.jsx'
|
import MobileShell from './layouts/MobileShell.jsx'
|
||||||
import LoginPage from './pages/LoginPage.jsx'
|
import LoginPage from './pages/LoginPage.jsx'
|
||||||
import HomePage from './pages/HomePage.jsx'
|
import HomePage from './pages/HomePage.jsx'
|
||||||
|
import NewsDetail from './pages/news/NewsDetail.jsx'
|
||||||
import MacroPage from './pages/MacroPage.jsx'
|
import MacroPage from './pages/MacroPage.jsx'
|
||||||
import MonitorPage from './pages/MonitorPage.jsx'
|
import MonitorPage from './pages/MonitorPage.jsx'
|
||||||
import MePage from './pages/MePage.jsx'
|
import MePage from './pages/MePage.jsx'
|
||||||
@@ -30,6 +31,7 @@ export default function App() {
|
|||||||
<Route path="/login" element={<RedirectIfAuthed><LoginPage /></RedirectIfAuthed>} />
|
<Route path="/login" element={<RedirectIfAuthed><LoginPage /></RedirectIfAuthed>} />
|
||||||
<Route element={<RequireAuth><MobileShell /></RequireAuth>}>
|
<Route element={<RequireAuth><MobileShell /></RequireAuth>}>
|
||||||
<Route path="/" element={<HomePage />} />
|
<Route path="/" element={<HomePage />} />
|
||||||
|
<Route path="/news/:id" element={<NewsDetail />} />
|
||||||
<Route path="/macro/*" element={<MacroPage />} />
|
<Route path="/macro/*" element={<MacroPage />} />
|
||||||
<Route path="/monitor" element={<MonitorPage />} />
|
<Route path="/monitor" element={<MonitorPage />} />
|
||||||
<Route path="/me" element={<MePage />} />
|
<Route path="/me" element={<MePage />} />
|
||||||
|
|||||||
+36
-9
@@ -1,6 +1,8 @@
|
|||||||
import { useEffect, useState, useRef, useCallback } from 'react'
|
import { useEffect, useState, useRef, useCallback } from 'react'
|
||||||
import { NavBar, List, Card, Empty, DotLoading } from 'antd-mobile'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { NavBar, Card, Empty, DotLoading, Badge } from 'antd-mobile'
|
||||||
import { api } from '../api/client.js'
|
import { api } from '../api/client.js'
|
||||||
|
import SwipeTabs from '../components/SwipeTabs.jsx'
|
||||||
|
|
||||||
// 首页: 报警模块 + 新闻模块
|
// 首页: 报警模块 + 新闻模块
|
||||||
// - 报警: World Bank 与妙想 MCP 跨源同 (指标, 周期) 数据差异超阈值 (按时间倒序)
|
// - 报警: World Bank 与妙想 MCP 跨源同 (指标, 周期) 数据差异超阈值 (按时间倒序)
|
||||||
@@ -22,41 +24,62 @@ function fmtDate(s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
|
const [active, setActive] = useState('news') // 默认选中新闻
|
||||||
|
const [alertCount, setAlertCount] = useState(0)
|
||||||
|
const handleAlertCount = useCallback((n) => setAlertCount(n), [])
|
||||||
|
|
||||||
|
const tabs = [
|
||||||
|
{
|
||||||
|
key: 'alerts',
|
||||||
|
label: (
|
||||||
|
<span className="tab-label">
|
||||||
|
报警
|
||||||
|
{alertCount > 0 && <Badge content={alertCount} />}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
render: () => <AlertSection onCount={handleAlertCount} />,
|
||||||
|
},
|
||||||
|
{ key: 'news', label: '新闻', render: () => <NewsSection /> },
|
||||||
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page-with-navbar">
|
<div className="page-with-navbar">
|
||||||
<NavBar back={null}>首页</NavBar>
|
<NavBar back={null}>首页</NavBar>
|
||||||
<div className="home-content">
|
<div className="home-content">
|
||||||
<AlertSection />
|
<SwipeTabs tabs={tabs} active={active} onChange={setActive} />
|
||||||
<NewsSection />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 报警模块
|
// 报警模块
|
||||||
function AlertSection() {
|
function AlertSection({ onCount }) {
|
||||||
const [items, setItems] = useState([])
|
const [items, setItems] = useState([])
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [done, setDone] = useState(false)
|
const [done, setDone] = useState(false)
|
||||||
const cursorRef = useRef(null)
|
const cursorRef = useRef(null)
|
||||||
const sentinelRef = useRef(null)
|
const sentinelRef = useRef(null)
|
||||||
|
const inFlightRef = useRef(false)
|
||||||
|
|
||||||
const fetchPage = useCallback(async () => {
|
const fetchPage = useCallback(async () => {
|
||||||
if (loading || done) return
|
if (inFlightRef.current || done) return
|
||||||
|
inFlightRef.current = true
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
try {
|
try {
|
||||||
const url = '/alerts?limit=10' + (cursorRef.current ? '&cursor=' + cursorRef.current : '')
|
const url = '/alerts?limit=10' + (cursorRef.current ? '&cursor=' + cursorRef.current : '')
|
||||||
const data = await api(url)
|
const data = await api(url)
|
||||||
setItems((prev) => prev.concat(data.items || []))
|
setItems((prev) => prev.concat(data.items || []))
|
||||||
|
onCount?.(data.total ?? (data.items?.length || 0))
|
||||||
cursorRef.current = data.nextCursor
|
cursorRef.current = data.nextCursor
|
||||||
if (!data.nextCursor) setDone(true)
|
if (!data.nextCursor) setDone(true)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('alerts load error', e)
|
console.error('alerts load error', e)
|
||||||
setDone(true)
|
setDone(true)
|
||||||
} finally {
|
} finally {
|
||||||
|
inFlightRef.current = false
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}, [loading, done])
|
}, [done, onCount])
|
||||||
|
|
||||||
useEffect(() => { fetchPage() }, [])
|
useEffect(() => { fetchPage() }, [])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -106,9 +129,12 @@ function NewsSection() {
|
|||||||
const [done, setDone] = useState(false)
|
const [done, setDone] = useState(false)
|
||||||
const cursorRef = useRef(null)
|
const cursorRef = useRef(null)
|
||||||
const sentinelRef = useRef(null)
|
const sentinelRef = useRef(null)
|
||||||
|
const inFlightRef = useRef(false)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
const fetchPage = useCallback(async () => {
|
const fetchPage = useCallback(async () => {
|
||||||
if (loading || done) return
|
if (inFlightRef.current || done) return
|
||||||
|
inFlightRef.current = true
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
try {
|
try {
|
||||||
const url = '/news?limit=10' + (cursorRef.current ? '&cursor=' + encodeURIComponent(cursorRef.current) : '')
|
const url = '/news?limit=10' + (cursorRef.current ? '&cursor=' + encodeURIComponent(cursorRef.current) : '')
|
||||||
@@ -120,9 +146,10 @@ function NewsSection() {
|
|||||||
console.error('news load error', e)
|
console.error('news load error', e)
|
||||||
setDone(true)
|
setDone(true)
|
||||||
} finally {
|
} finally {
|
||||||
|
inFlightRef.current = false
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}, [loading, done])
|
}, [done])
|
||||||
|
|
||||||
useEffect(() => { fetchPage() }, [])
|
useEffect(() => { fetchPage() }, [])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -144,7 +171,7 @@ function NewsSection() {
|
|||||||
) : (
|
) : (
|
||||||
<div className="section-list">
|
<div className="section-list">
|
||||||
{items.map((n) => (
|
{items.map((n) => (
|
||||||
<Card key={n.id} className="news-card">
|
<Card key={n.id} className="news-card" onClick={() => navigate('/news/' + n.id)}>
|
||||||
<div className="news-title">{n.title}</div>
|
<div className="news-title">{n.title}</div>
|
||||||
{n.summary && <div className="news-summary">{n.summary}</div>}
|
{n.summary && <div className="news-summary">{n.summary}</div>}
|
||||||
<div className="news-meta">
|
<div className="news-meta">
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useParams, useNavigate } from 'react-router-dom'
|
||||||
|
import { NavBar } from 'antd-mobile'
|
||||||
|
import { api } from '../../api/client.js'
|
||||||
|
|
||||||
|
// 新闻详情: /news/:id
|
||||||
|
// 正文来自 News.content (MCP 返回的完整正文), 旧数据可能无 content, 兜底显示摘要
|
||||||
|
function fmtDate(s) {
|
||||||
|
if (!s) return ''
|
||||||
|
const d = new Date(s)
|
||||||
|
if (isNaN(d.getTime())) return s
|
||||||
|
const pad = (n) => String(n).padStart(2, '0')
|
||||||
|
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate())
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function NewsDetail() {
|
||||||
|
const { id } = useParams()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const [item, setItem] = useState(null)
|
||||||
|
const [err, setErr] = useState('')
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let cancelled = false
|
||||||
|
setLoading(true)
|
||||||
|
api('/news/' + encodeURIComponent(id))
|
||||||
|
.then((data) => { if (!cancelled) setItem(data.item) })
|
||||||
|
.catch((e) => !cancelled && setErr(e.message))
|
||||||
|
.finally(() => !cancelled && setLoading(false))
|
||||||
|
return () => { cancelled = true }
|
||||||
|
}, [id])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="article-page">
|
||||||
|
<NavBar onBack={() => navigate(-1)}>新闻详情</NavBar>
|
||||||
|
{loading && <div className="loading">加载中...</div>}
|
||||||
|
{err && <div className="error-banner">{err}</div>}
|
||||||
|
{!loading && !err && !item && <div className="empty">新闻不存在</div>}
|
||||||
|
{!loading && !err && item && (
|
||||||
|
<div className="news-detail">
|
||||||
|
<h1>{item.title}</h1>
|
||||||
|
<div className="meta">
|
||||||
|
{item.source || '未知来源'} · {fmtDate(item.publishedAt)} · #{item.impactRank}
|
||||||
|
{/^https?:\/\//i.test(item.url || '') && (
|
||||||
|
<a className="news-origin" href={item.url} target="_blank" rel="noreferrer">原文链接</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="news-content">
|
||||||
|
{item.content ? item.content : item.summary}
|
||||||
|
{!item.content && <div className="news-content-empty">(本条暂无全文,仅摘要)</div>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -197,6 +197,8 @@ input, textarea, select { font: inherit; }
|
|||||||
.me-logout { color: var(--color-danger); }
|
.me-logout { color: var(--color-danger); }
|
||||||
/* 首页模块: 报警 + 新闻 */
|
/* 首页模块: 报警 + 新闻 */
|
||||||
.home-content { padding: 0 0 16px; }
|
.home-content { padding: 0 0 16px; }
|
||||||
|
.home-content .adm-tabs-content { --content-padding: 0; }
|
||||||
|
.home-content .tab-label { display: inline-flex; align-items: center; gap: 4px; }
|
||||||
.home-section { padding: 0 12px 16px; }
|
.home-section { padding: 0 12px 16px; }
|
||||||
.section-title { font-size: 16px; font-weight: 700; padding: 14px 4px 8px; color: var(--color-text); }
|
.section-title { font-size: 16px; font-weight: 700; padding: 14px 4px 8px; color: var(--color-text); }
|
||||||
.section-list { display: flex; flex-direction: column; gap: 8px; }
|
.section-list { display: flex; flex-direction: column; gap: 8px; }
|
||||||
@@ -214,4 +216,12 @@ input, textarea, select { font: inherit; }
|
|||||||
.news-summary { font-size: 12px; color: var(--color-muted); margin-top: 4px; line-height: 1.5; max-height: 3.6em; overflow: hidden; }
|
.news-summary { font-size: 12px; color: var(--color-muted); margin-top: 4px; line-height: 1.5; max-height: 3.6em; overflow: hidden; }
|
||||||
.news-meta { display: flex; gap: 10px; font-size: 11px; color: var(--color-muted); margin-top: 6px; }
|
.news-meta { display: flex; gap: 10px; font-size: 11px; color: var(--color-muted); margin-top: 6px; }
|
||||||
.news-rank { color: var(--color-primary); font-weight: 600; }
|
.news-rank { color: var(--color-primary); font-weight: 600; }
|
||||||
|
.news-card:active .adm-card-body { background: #f5f5f5; }
|
||||||
|
/* 新闻详情页 */
|
||||||
|
.news-detail { background: #fff; padding: 18px 16px 24px; }
|
||||||
|
.news-detail h1 { font-size: 20px; line-height: 1.35; margin-bottom: 8px; }
|
||||||
|
.news-detail .meta { font-size: 12px; color: var(--color-muted); margin-bottom: 14px; padding-bottom: 10px; border-bottom: 1px solid var(--color-border); display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
||||||
|
.news-origin { color: var(--color-primary); margin-left: auto; }
|
||||||
|
.news-content { font-size: 15px; line-height: 1.75; color: #333; white-space: pre-wrap; word-break: break-word; }
|
||||||
|
.news-content-empty { margin-top: 12px; font-size: 12px; color: var(--color-muted); }
|
||||||
.scroll-sentinel { text-align: center; padding: 14px 0 4px; color: var(--color-muted); font-size: 12px; }
|
.scroll-sentinel { text-align: center; padding: 14px 0 4px; color: var(--color-muted); font-size: 12px; }
|
||||||
|
|||||||
Reference in New Issue
Block a user