2baf29b3ae
Deliver encrypted health zone, observation API, baseline maturity pipeline, page-data bindings, and H5/WeChat channel integration for health P0. Co-authored-by: Cursor <cursoragent@cursor.com>
79 lines
2.7 KiB
JavaScript
79 lines
2.7 KiB
JavaScript
import { createUserDataSpaceService } from './user-data-space-service.mjs';
|
|
import { ensureHealthPageDataForUser } from './health-page-data-bootstrap.mjs';
|
|
import { HEALTH_BASELINES_DATASET } from './health-page-data-schema.mjs';
|
|
import {
|
|
baselineRowKey,
|
|
mapBaselineToPgPayload,
|
|
mapPgBaselineRow,
|
|
serializeBaselineRow,
|
|
} from './health-baseline-serialize.mjs';
|
|
|
|
const DATASET_NAME = HEALTH_BASELINES_DATASET.name;
|
|
|
|
export function createPageDataHealthBaselineStore({
|
|
resolveWorkspaceRoot,
|
|
logger = console,
|
|
} = {}) {
|
|
if (typeof resolveWorkspaceRoot !== 'function') {
|
|
throw new Error('createPageDataHealthBaselineStore requires resolveWorkspaceRoot');
|
|
}
|
|
|
|
async function getUserDataSpace(userId) {
|
|
const workspaceRoot = await resolveWorkspaceRoot(userId);
|
|
if (!workspaceRoot) return null;
|
|
const service = createUserDataSpaceService({ workspaceRoot, userId: String(userId) });
|
|
await ensureHealthPageDataForUser(service, userId);
|
|
return service;
|
|
}
|
|
|
|
async function list(userId) {
|
|
const service = await getUserDataSpace(userId);
|
|
if (!service) return [];
|
|
try {
|
|
const result = await service.readDatasetRows(DATASET_NAME, {
|
|
limit: 200,
|
|
orderBy: 'computed_at',
|
|
orderDir: 'desc',
|
|
});
|
|
return (result.rows ?? []).map((row) => mapPgBaselineRow(row, userId));
|
|
} catch (error) {
|
|
if (error?.code === 'dataset_not_found') return [];
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
return {
|
|
backend: 'page_data',
|
|
list,
|
|
async upsertMany(userId, baselines = [], { computedAt = Date.now() } = {}) {
|
|
const service = await getUserDataSpace(userId);
|
|
if (!service) {
|
|
const error = Object.assign(new Error('用户健康基线空间不可用'), { code: 'health_storage_unavailable' });
|
|
throw error;
|
|
}
|
|
const existing = await list(userId);
|
|
const index = new Map(existing.map((row) => [baselineRowKey(row), row]));
|
|
const merged = [];
|
|
for (const base of baselines) {
|
|
const serialized = serializeBaselineRow(base, computedAt);
|
|
const rowKey = baselineRowKey(serialized);
|
|
const prior = index.get(rowKey);
|
|
const payload = mapBaselineToPgPayload(serialized);
|
|
try {
|
|
if (prior?.id) {
|
|
const { row } = await service.updateDatasetRow(DATASET_NAME, prior.id, payload);
|
|
merged.push(mapPgBaselineRow(row, userId));
|
|
} else {
|
|
const { row } = await service.insertDatasetRow(DATASET_NAME, payload);
|
|
merged.push(mapPgBaselineRow(row, userId));
|
|
}
|
|
} catch (error) {
|
|
logger.warn?.('Page Data health baseline upsert failed:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
return merged;
|
|
},
|
|
};
|
|
}
|