feat: 重构首页回执营业统计并增加企业返还金额
CSS quality / css-quality (push) Has been cancelled

This commit is contained in:
hectorzhao
2026-09-17 13:11:35 +08:00
parent 627fa7ec97
commit 5e4d644788
29 changed files with 1684 additions and 231 deletions
@@ -0,0 +1,24 @@
CREATE TABLE "HomeProjectionState" (id TEXT PRIMARY KEY, version INTEGER NOT NULL DEFAULT 0, "seededDay" TEXT, initialized BOOLEAN NOT NULL DEFAULT false, "lastError" TEXT, "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP);
CREATE TABLE "HomeProjectionDirty" ("messageRecordId" TEXT PRIMARY KEY,"enqueuedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP);
CREATE TABLE "HomeMessageFact" ("messageRecordId" TEXT NOT NULL,"fromVersion" INTEGER NOT NULL,"toVersion" INTEGER,"queuedDay" TEXT NOT NULL,payload JSONB NOT NULL,PRIMARY KEY("messageRecordId","fromVersion"));
CREATE INDEX "HomeMessageFact_queuedDay_toVersion_idx" ON "HomeMessageFact"("queuedDay","toVersion");
CREATE TABLE "HomeSnapshot" (id TEXT PRIMARY KEY,"userId" TEXT NOT NULL,"businessDate" TEXT NOT NULL,version INTEGER NOT NULL,"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,"expiresAt" TIMESTAMP(3) NOT NULL,summary JSONB NOT NULL);
CREATE INDEX "HomeSnapshot_expiresAt_idx" ON "HomeSnapshot"("expiresAt");
INSERT INTO "HomeProjectionState"(id) VALUES ('home');
-- A durable, transactional invalidation only: no business state or external effects.
CREATE FUNCTION home_mark_dirty() RETURNS trigger LANGUAGE plpgsql AS $$
DECLARE mid TEXT;
BEGIN
IF TG_TABLE_NAME = 'SmsMessageRecord' THEN mid := COALESCE(NEW.id,OLD.id);
ELSIF TG_TABLE_NAME = 'UpstreamReceiptInbox' THEN mid := COALESCE(NEW."matchedMessageRecordId",OLD."matchedMessageRecordId");
ELSE mid := COALESCE(NEW."messageRecordId",OLD."messageRecordId"); END IF;
IF mid IS NOT NULL THEN
INSERT INTO "HomeProjectionDirty"("messageRecordId") VALUES(mid) ON CONFLICT ("messageRecordId") DO UPDATE SET "enqueuedAt"=CURRENT_TIMESTAMP;
END IF;
RETURN NULL;
END $$;
CREATE TRIGGER home_message_dirty AFTER INSERT OR UPDATE OR DELETE ON "SmsMessageRecord" FOR EACH ROW EXECUTE FUNCTION home_mark_dirty();
CREATE TRIGGER home_submit_dirty AFTER INSERT OR UPDATE OR DELETE ON "SmsSubmitRecord" FOR EACH ROW EXECUTE FUNCTION home_mark_dirty();
CREATE TRIGGER home_segment_dirty AFTER INSERT OR UPDATE OR DELETE ON "SmsMessageSegmentAudit" FOR EACH ROW EXECUTE FUNCTION home_mark_dirty();
CREATE TRIGGER home_inbox_dirty AFTER INSERT OR UPDATE OR DELETE ON "UpstreamReceiptInbox" FOR EACH ROW EXECUTE FUNCTION home_mark_dirty();
CREATE TRIGGER home_receipt_dirty AFTER INSERT OR UPDATE OR DELETE ON "SmsReceiptRecord" FOR EACH ROW EXECUTE FUNCTION home_mark_dirty();
@@ -0,0 +1,24 @@
-- Re-association invalidates both owners; source writes and the durable invalidation are atomic.
CREATE OR REPLACE FUNCTION home_mark_dirty() RETURNS trigger LANGUAGE plpgsql AS $$
DECLARE mid TEXT; previous_mid TEXT;
BEGIN
IF TG_TABLE_NAME = 'SmsMessageRecord' THEN
mid := COALESCE(NEW.id,OLD.id); previous_mid := OLD.id;
ELSIF TG_TABLE_NAME = 'UpstreamReceiptInbox' THEN
mid := COALESCE(NEW."matchedMessageRecordId",OLD."matchedMessageRecordId"); previous_mid := OLD."matchedMessageRecordId";
ELSE
mid := COALESCE(NEW."messageRecordId",OLD."messageRecordId"); previous_mid := OLD."messageRecordId";
END IF;
IF mid IS NOT NULL THEN
INSERT INTO "HomeProjectionDirty"("messageRecordId") VALUES(mid)
ON CONFLICT ("messageRecordId") DO UPDATE SET "enqueuedAt"=CURRENT_TIMESTAMP;
END IF;
IF previous_mid IS NOT NULL AND previous_mid IS DISTINCT FROM mid THEN
INSERT INTO "HomeProjectionDirty"("messageRecordId") VALUES(previous_mid)
ON CONFLICT ("messageRecordId") DO UPDATE SET "enqueuedAt"=CURRENT_TIMESTAMP;
END IF;
RETURN NULL;
END $$;
CREATE INDEX "HomeProjectionDirty_enqueuedAt_idx" ON "HomeProjectionDirty"("enqueuedAt");
CREATE INDEX "HomeMessageFact_toVersion_idx" ON "HomeMessageFact"("toVersion");
CREATE UNIQUE INDEX "HomeMessageFact_current_key" ON "HomeMessageFact"("messageRecordId") WHERE "toVersion" IS NULL;
+35
View File
@@ -2996,3 +2996,38 @@ model UnreportedSignatureDaily {
@@id([generationId, dimensionKey])
@@index([businessDate, generationId, messageCount])
}
model HomeProjectionState {
id String @id
version Int @default(0)
seededDay String?
initialized Boolean @default(false)
lastError String?
updatedAt DateTime @default(now())
}
model HomeProjectionDirty {
messageRecordId String @id
enqueuedAt DateTime @default(now())
@@index([enqueuedAt])
}
model HomeMessageFact {
messageRecordId String
fromVersion Int
toVersion Int?
queuedDay String
payload Json
@@id([messageRecordId, fromVersion])
@@index([queuedDay, toVersion])
@@index([toVersion])
}
model HomeSnapshot {
id String @id
userId String
businessDate String
version Int
createdAt DateTime @default(now())
expiresAt DateTime
summary Json
@@index([expiresAt])
}