Files
shoot-miniprograms/src/utils/storeVip.js
T
2026-10-21 15:49:43 +08:00

71 lines
2.9 KiB
JavaScript

import { getStoreBenefitAPI, getStoreVipListAPI } from "@/apis";
import useStore from "@/store";
// 按账号隔离最近选择,刷新登录令牌后仍可恢复同一门店。
const selectionKey = () => {
const version = uni.getAccountInfoSync().miniProgram.envVersion;
return `${version}_experience_store_${useStore().user.id || "guest"}`;
};
export const getSelectedExperienceStore = () => {
const value = uni.getStorageSync(selectionKey());
return value && /^\d+$/.test(String(value.id)) && Number(value.id) > 0
? { id: String(value.id), name: String(value.name || "") }
: null;
};
export const rememberExperienceStore = (id, name) => {
uni.setStorageSync(selectionKey(), { id: String(id), name });
};
// 入口汇总所有门店;找到有效会员即可结束,未开通须查询完整列表。
export const hasAnyStoreVip = async () => {
const pageSize = 20;
let received = 0;
for (let page = 1; ; page += 1) {
const result = await getStoreVipListAPI({ page, pageSize });
const list = result?.list;
if (!Array.isArray(list) || !Number.isSafeInteger(result.total) || result.total < 0) {
throw new Error("门店会员列表响应格式异常");
}
if (list.some((item) => item?.isVip === true)) return true;
if (list.some((item) => typeof item?.isVip !== "boolean")) {
throw new Error("门店会员状态缺失");
}
received += list.length;
if (received >= result.total) return false;
// 列表尚未读完却返回空页时,不把不完整结果判为未开通。
if (!list.length) throw new Error("门店会员列表分页异常");
}
};
// 只接受非负整数,缺失或异常值不能转换成“已用完”的 0 次。
const normalizeRemaining = (benefit) => {
const remain = benefit?.remain;
return Number.isSafeInteger(remain) && remain >= 0 ? remain : "--";
};
export const normalizeStoreMembership = (store) => {
if (typeof store?.isVip !== "boolean") throw new Error("门店会员状态缺失");
const active = store.isVip === true;
return {
active,
cardImage: `https://static.shelingxingqiu.com/shootmini/static/coin/store-vip-card-${active ? "active" : "inactive"}.png`,
expiresAt: active ? String(store.vipExpireAt || "").slice(0, 10).replace(/-/g, "/") || "--" : "",
// 未开通或已过期统一为 0;有效会员逐项读取后端剩余次数。
remaining: {
trial: active ? normalizeRemaining(store.freeTrial) : 0,
discount: active ? normalizeRemaining(store.discountPurchase) : 0,
drink: active ? normalizeRemaining(store.drink) : 0,
},
};
};
export const loadStoreMembership = async (storeId) => {
const result = await getStoreBenefitAPI(storeId);
if (String(result?.storeId) !== String(storeId)) {
throw new Error("门店权益响应与当前门店不匹配");
}
return { name: result.storeName || "", ...normalizeStoreMembership(result) };
};