import Taro from '@tarojs/taro' import type { DesignItem, OrderItem, AddressItem, StickerItem } from '../types' import { PRODUCT_ICON_MAP } from './productConfig' // 重新导出类型,供各页面从 store 直接引用(修正原「声明但不导出」的编译错误) export type { DesignItem, OrderItem, AddressItem, StickerItem } const THEME_KEY = 'smart_theme' const USER_KEY = 'smart_user_info' const ACTIVE_USER_KEY = 'smart_active_openid' /** 判断 openid 是否为历史版 mock 残留(形如 mock_xxx) */ export function isMockOpenid(openid?: string | null): boolean { return !!openid && (openid.startsWith('mock_') || openid.startsWith('mock-')) } // ---------- 当前用户 openid 管理 ---------- function getActiveOpenid(): string { const user = getUserInfoRaw() const openid = user?.openid || Taro.getStorageSync(ACTIVE_USER_KEY) || '_guest_' Taro.setStorageSync(ACTIVE_USER_KEY, openid) return openid } function key(scope: string): string { const prefix = getActiveOpenid() return `${scope}_${prefix}` } // ---------- 用户数据 ---------- const USER_REGISTRY_KEY = 'smart_user_registry' const ADMIN_PASSWORD = 'zhihui2024' // ---------- 用户注册表 ---------- function getUserRegistry(): string[] { try { return Taro.getStorageSync(USER_REGISTRY_KEY) || [] } catch { return [] } } function saveToRegistry(openid: string) { const list = getUserRegistry() if (!list.includes(openid)) { list.push(openid) Taro.setStorageSync(USER_REGISTRY_KEY, list) } } function removeFromRegistry(openid: string) { const list = getUserRegistry().filter(id => id !== openid) Taro.setStorageSync(USER_REGISTRY_KEY, list) } // ---------- 用户数据 ---------- export function getUserInfoRaw(): any { try { return Taro.getStorageSync(USER_KEY) } catch { return null } } export function setUserInfoRaw(info: any) { Taro.setStorageSync(USER_KEY, info) if (info?.openid) { Taro.setStorageSync(ACTIVE_USER_KEY, info.openid) // 为每个用户备份独立副本,方便切换账号时读取 Taro.setStorageSync(`user_info_${info.openid}`, info) saveToRegistry(info.openid) } } export function getUserInfoByOpenid(openid: string): any | null { try { const backup = Taro.getStorageSync(`user_info_${openid}`) if (backup) return backup } catch {} const current = getUserInfoRaw() if (current?.openid === openid) return current return null } export function clearUserInfo() { // 仅退出登录,不删除用户数据 Taro.removeStorageSync(USER_KEY) Taro.removeStorageSync(ACTIVE_USER_KEY) } export function setUserInfo(info: any) { setUserInfoRaw(info) } export function getUserInfo() { return getUserInfoRaw() } // ---------- 用户数据库管理 ---------- export function listAllUsers() { const registry = getUserRegistry() return registry.map(openid => { const info = getUserInfoByOpenid(openid) const dList = getDesignListFor(openid) const oList = getOrderListFor(openid) return { openid, nickName: info?.nickName || '未知用户', avatarUrl: info?.avatarUrl || '', loginAt: info?.loginAt || 0, designCount: dList.length, orderCount: oList.length } }) } export function createUser(nickName: string, avatarUrl?: string) { const openid = 'mock_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 6) const info = { openid, nickName: nickName || '微信用户', avatarUrl: avatarUrl || '', loginAt: Date.now() } setUserInfoRaw(info) return info } export function switchUser(openid: string) { const info = getUserInfoByOpenid(openid) if (!info) return false Taro.setStorageSync(USER_KEY, info) Taro.setStorageSync(ACTIVE_USER_KEY, openid) return true } export function deleteUser(openid: string) { // 删除该用户的所有数据 Taro.removeStorageSync(`user_info_${openid}`) Taro.removeStorageSync(`design_list_${openid}`) Taro.removeStorageSync(`order_list_${openid}`) Taro.removeStorageSync(`address_list_${openid}`) removeFromRegistry(openid) // 如果删的是当前登录用户,清掉登录态 const current = getUserInfoRaw() if (current?.openid === openid) { clearUserInfo() } } export function verifyAdminPassword(password: string): boolean { return password === ADMIN_PASSWORD } // ---------- 跨用户读取辅助函数 ---------- function keyFor(scope: string, openid: string) { return `${scope}_${openid}` } function getDesignListFor(openid: string): DesignItem[] { try { return Taro.getStorageSync(keyFor('design_list', openid)) || [] } catch { return [] } } function getOrderListFor(openid: string): OrderItem[] { try { return Taro.getStorageSync(keyFor('order_list', openid)) || [] } catch { return [] } } // ---------- 设计清单 ---------- export function getDesignList(): DesignItem[] { try { return Taro.getStorageSync(key('design_list')) || [] } catch { return [] } } export function setDesignList(list: DesignItem[]) { Taro.setStorageSync(key('design_list'), list) } export function addDesign(product: any, count: number): DesignItem { const list = getDesignList() const iconImg = product?.iconImg || PRODUCT_ICON_MAP[product?.id] || '/icon/四角星.png' const item: DesignItem = { id: 'DSG' + Date.now(), productId: product.id, productName: product.name, productIcon: iconImg, unitPrice: product.price, count, status: 'undesigned', createdAt: new Date().toISOString().slice(0, 10) } setDesignList([...list, item]) return item } export function updateDesign(id: string, patch: Partial) { const list = getDesignList() const idx = list.findIndex(d => d.id === id) if (idx === -1) return list[idx] = { ...list[idx], ...patch } setDesignList(list) } /** 批量删除设计条目 */ export function removeDesigns(ids: string[]) { const list = getDesignList().filter(d => !ids.includes(d.id)) setDesignList(list) } /** 根据ID删除单条设计 */ export function removeDesign(id: string) { const list = getDesignList().filter(d => d.id !== id) setDesignList(list) } // ---------- 订单 ---------- export function getOrderList(): OrderItem[] { try { return Taro.getStorageSync(key('order_list')) || [] } catch { return [] } } export function setOrderList(list: OrderItem[]) { Taro.setStorageSync(key('order_list'), list) } export function designToOrder(designId: string): OrderItem | null { const dList = getDesignList() const oList = getOrderList() const design = dList.find(d => d.id === designId) if (!design) return null const iconImg = design.productIcon?.startsWith('/icon/') ? design.productIcon : PRODUCT_ICON_MAP[design.productId] || '/icon/四角星.png' const order: OrderItem = { id: 'ORD' + Date.now().toString().slice(-9), productName: design.productName, productIcon: iconImg, statusCode: 'pending', date: new Date().toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }).replace(/\//g, '-'), price: '¥' + (design.unitPrice * design.count).toFixed(2), count: design.count, sku: `${design.productName} × ${design.count}` } const dIdx = dList.findIndex(d => d.id === designId) if (dIdx !== -1) { dList[dIdx].status = 'ordered' dList[dIdx].orderId = order.id } setDesignList(dList) setOrderList([order, ...oList]) return order } // ---------- 主题 ---------- export type ThemeMode = 'light' | 'dark' | 'auto' export function getTheme(): ThemeMode { try { return Taro.getStorageSync(THEME_KEY) || 'auto' } catch { return 'auto' } } export function setTheme(theme: ThemeMode) { Taro.setStorageSync(THEME_KEY, theme) } /** 根据自动模式解析实际生效主题 */ export function resolveTheme(mode: ThemeMode): 'light' | 'dark' { if (mode === 'auto') { // 需 app.json 开启 darkmode 后 theme 字段才有效;getSystemInfoSync 已废弃,改用 getAppBaseInfo try { const info = Taro.getAppBaseInfo() return info.theme === 'dark' ? 'dark' : 'light' } catch { const info = Taro.getSystemInfoSync() return info.theme === 'dark' ? 'dark' : 'light' } } return mode } // ---------- 收货地址 ---------- export function getAddressList(): AddressItem[] { try { return Taro.getStorageSync(key('address_list')) || [] } catch { return [] } } export function setAddressList(list: AddressItem[]) { Taro.setStorageSync(key('address_list'), list) } export function addAddress(addr: Omit): AddressItem { const list = getAddressList() const item: AddressItem = { ...addr, id: 'ADR' + Date.now() } // 若设为默认,取消其他默认 if (item.isDefault) { list.forEach(a => { a.isDefault = false }) } setAddressList([item, ...list]) return item } export function updateAddress(id: string, patch: Partial) { const list = getAddressList() const idx = list.findIndex(a => a.id === id) if (idx === -1) return if (patch.isDefault) list.forEach(a => { a.isDefault = false }) list[idx] = { ...list[idx], ...patch } setAddressList(list) } export function deleteAddress(id: string) { const list = getAddressList().filter(a => a.id !== id) setAddressList(list) } export function getDefaultAddress(): AddressItem | undefined { return getAddressList().find(a => a.isDefault) }