每日运势小程序
This commit is contained in:
176
DailyFortuneGuide/store/fortuneStore.js
Normal file
176
DailyFortuneGuide/store/fortuneStore.js
Normal file
@@ -0,0 +1,176 @@
|
||||
const config = require("../config/index");
|
||||
const { formatDate } = require("../utils/date");
|
||||
const { safeGetStorage, safeSetStorage } = require("../utils/storage");
|
||||
const { normalizeRegionArray, deriveRegionFromParts, getRegionParts } = require("../utils/region");
|
||||
|
||||
const STORAGE_KEYS = {
|
||||
history: "fortune:history",
|
||||
quotaPrefix: "fortune:quota:",
|
||||
form: "fortune:form"
|
||||
};
|
||||
|
||||
function createDefaultForm() {
|
||||
return {
|
||||
birthDate: formatDate(new Date()),
|
||||
birthTime: "",
|
||||
birthProvince: "",
|
||||
birthCity: "",
|
||||
birthDistrict: "",
|
||||
birthRegion: []
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeForm(payload, fallback) {
|
||||
const base = fallback || createDefaultForm();
|
||||
const toStringValue = (value, fallbackValue = "") => (typeof value === "string" ? value : fallbackValue);
|
||||
const normalized = {
|
||||
birthDate: toStringValue(payload && payload.birthDate, base.birthDate),
|
||||
birthTime: toStringValue(payload && payload.birthTime, base.birthTime || ""),
|
||||
birthProvince: toStringValue(payload && payload.birthProvince, base.birthProvince || ""),
|
||||
birthCity: toStringValue(payload && payload.birthCity, base.birthCity || ""),
|
||||
birthDistrict: toStringValue(payload && payload.birthDistrict, base.birthDistrict || ""),
|
||||
birthRegion: []
|
||||
};
|
||||
const persistedRegion = normalizeRegionArray(payload && payload.birthRegion);
|
||||
const baseRegion = normalizeRegionArray(base.birthRegion);
|
||||
if (persistedRegion.length) {
|
||||
normalized.birthRegion = persistedRegion;
|
||||
} else if (baseRegion.length) {
|
||||
normalized.birthRegion = baseRegion;
|
||||
} else {
|
||||
normalized.birthRegion = deriveRegionFromParts({
|
||||
province: normalized.birthProvince,
|
||||
city: normalized.birthCity,
|
||||
district: normalized.birthDistrict
|
||||
});
|
||||
}
|
||||
const parts = getRegionParts(normalized.birthRegion, {
|
||||
province: normalized.birthProvince,
|
||||
city: normalized.birthCity,
|
||||
district: normalized.birthDistrict
|
||||
});
|
||||
normalized.birthProvince = parts.province;
|
||||
normalized.birthCity = parts.city;
|
||||
normalized.birthDistrict = parts.district;
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function loadPersistedForm() {
|
||||
const stored = safeGetStorage(STORAGE_KEYS.form, null);
|
||||
if (stored && typeof stored === "object") {
|
||||
return normalizeForm(stored);
|
||||
}
|
||||
const defaults = createDefaultForm();
|
||||
safeSetStorage(STORAGE_KEYS.form, defaults);
|
||||
return defaults;
|
||||
}
|
||||
|
||||
function persistForm(form) {
|
||||
const normalized = normalizeForm(form);
|
||||
safeSetStorage(STORAGE_KEYS.form, normalized);
|
||||
}
|
||||
|
||||
const state = {
|
||||
form: loadPersistedForm(),
|
||||
currentFortune: null,
|
||||
history: [],
|
||||
quota: {
|
||||
date: "",
|
||||
count: 0
|
||||
},
|
||||
lastError: ""
|
||||
};
|
||||
|
||||
function getQuotaStorageKey(dateStr) {
|
||||
return `${STORAGE_KEYS.quotaPrefix}${dateStr.replace(/-/g, "")}`;
|
||||
}
|
||||
|
||||
function syncQuota() {
|
||||
const today = formatDate(new Date());
|
||||
const storageKey = getQuotaStorageKey(today);
|
||||
const stored = safeGetStorage(storageKey, 0);
|
||||
const count = typeof stored === "number" ? stored : 0;
|
||||
state.quota = {
|
||||
date: today,
|
||||
count
|
||||
};
|
||||
}
|
||||
|
||||
function incrementQuota() {
|
||||
const today = formatDate(new Date());
|
||||
if (state.quota.date !== today) {
|
||||
syncQuota();
|
||||
}
|
||||
const nextCount = state.quota.count + 1;
|
||||
state.quota = {
|
||||
date: today,
|
||||
count: nextCount
|
||||
};
|
||||
safeSetStorage(getQuotaStorageKey(today), nextCount);
|
||||
}
|
||||
|
||||
function canGenerateToday() {
|
||||
const today = formatDate(new Date());
|
||||
if (state.quota.date !== today) {
|
||||
syncQuota();
|
||||
}
|
||||
return state.quota.count < config.maxDailyQuota;
|
||||
}
|
||||
|
||||
function loadHistory() {
|
||||
const stored = safeGetStorage(STORAGE_KEYS.history, []);
|
||||
state.history = Array.isArray(stored) ? stored : [];
|
||||
}
|
||||
|
||||
function saveHistory() {
|
||||
safeSetStorage(STORAGE_KEYS.history, state.history);
|
||||
}
|
||||
|
||||
function appendHistory(formSnapshot, fortune) {
|
||||
const snapshot = normalizeForm(formSnapshot, state.form);
|
||||
const entry = {
|
||||
id: `${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
|
||||
createdAt: new Date().toISOString(),
|
||||
formSnapshot: snapshot,
|
||||
fortune
|
||||
};
|
||||
const next = [entry, ...state.history];
|
||||
state.history = next.slice(0, config.historyLimit);
|
||||
saveHistory();
|
||||
return entry;
|
||||
}
|
||||
|
||||
function getHistoryById(id) {
|
||||
return state.history.find((item) => item.id === id);
|
||||
}
|
||||
|
||||
function setForm(partial) {
|
||||
const merged = Object.assign({}, state.form, partial);
|
||||
state.form = normalizeForm(merged, state.form);
|
||||
persistForm(state.form);
|
||||
}
|
||||
|
||||
function setCurrentFortune(fortune) {
|
||||
state.currentFortune = fortune;
|
||||
}
|
||||
|
||||
function getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
function initStore() {
|
||||
syncQuota();
|
||||
loadHistory();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
initStore,
|
||||
getState,
|
||||
setForm,
|
||||
setCurrentFortune,
|
||||
appendHistory,
|
||||
loadHistory,
|
||||
getHistoryById,
|
||||
canGenerateToday,
|
||||
incrementQuota
|
||||
};
|
||||
Reference in New Issue
Block a user