import { computed, reactive, watch } from 'vue'; import { Bell, LogOut, Store, Smartphone, ShieldCheck, LayoutDashboard, Package, ShoppingBag, Users, Megaphone, Headset, BookOpen, SlidersHorizontal, Rocket, Wallet, KeyRound, Radio, ClipboardCheck, History, ChartNoAxesCombined, MessageSquare, FileText, Settings, Activity, Layers, Cpu, Send, Gauge } from '@lucide/vue'; import { useRoute } from 'vue-router'; import { allowedPage } from './access.js'; import CustomerPage, { customerPages } from './pages/customer.js'; import MerchantPage, { merchantPages, merchantMenus } from './pages/merchant.js'; import PlatformPage, { platformPages, platformMenus } from './pages/platform.js'; export default { props: ['context'], components: { CustomerPage, MerchantPage, PlatformPage, Bell, LogOut, Store, Smartphone, ShieldCheck }, setup(props) { const ctx = props.context; const route = useRoute(); const login = reactive({ tenant: ctx.tenantId, account: '', password: '', pending: false, error: '' }); const navigationIcons = { overview: LayoutDashboard, dashboard: LayoutDashboard, products: Package, orders: ShoppingBag, 'after-sales': ClipboardCheck, customers: Users, marketing: Megaphone, service: Headset, queue: Headset, knowledge: BookOpen, rules: SlidersHorizontal, release: Rocket, billing: Wallet, access: KeyRound, channels: Radio, notifications: Bell, approvals: ClipboardCheck, history: History, team: Users, statistics: ChartNoAxesCombined, reference: BookOpen, 'quick-replies': MessageSquare, tenants: Store, applications: Layers, capacity: Gauge, models: Cpu, deliveries: Send, health: Activity, audit: FileText, permissions: KeyRound, settings: Settings }; function navigationIcon(name) { return navigationIcons[name] || FileText; } const product = computed(() => route.path.split('/')[1] || 'customer'); const role = computed(() => product.value === 'merchant' ? ctx.session.merchant?.role || 'merchant' : product.value); const page = computed(() => route.path.split('/').filter(Boolean).at(-1) || 'home'); const account = computed(() => ctx.session[product.value]); const productTitle = computed(() => ({ customer: '购物商城 H5', merchant: '商家后台', platform: '平台后台' })[product.value]); function allowed(name) { return allowedPage(product.value, account.value, name); } const menus = computed(() => (product.value === 'platform' ? platformMenus : merchantMenus[role.value] || []).map(([group, items]) => [group, items.filter(([name]) => allowed(name))]).filter(([, items]) => items.length)); const current = computed(() => { if (product.value === 'customer') return customerPages.find(item => (typeof item === 'string' ? item : item.page) === page.value); if (product.value === 'platform') return platformPages.find(item => item.page === page.value); return merchantPages.find(item => item.role === role.value && item.page === page.value && allowed(item.page)); }); const title = computed(() => current.value?.title || (page.value === 'login' ? '员工登录' : '页面不可访问')); const blocked = computed(() => { const section = route.path.split('/')[2]; const wrongSection = product.value === 'merchant' && account.value && (section === 'service' && route.path.split('/').length > 3 && role.value !== 'staff' || section === 'approval' && role.value !== 'supervisor'); return !['customer', 'merchant', 'platform'].includes(product.value) || wrongSection || page.value !== 'login' && !current.value; }); watch(() => route.path, () => { login.password = ''; login.error = ''; if (route.path === '/') { ctx.navigate('customer', 'home'); return; } if (['merchant', 'platform'].includes(product.value) && page.value !== 'login' && !account.value) ctx.requireLogin(product.value, route.path); // 子路径仅描述业务栏目,员工身份始终来自已验证账户。 if (product.value === 'merchant' && account.value && page.value !== 'login') { const segment = route.path.split('/')[2]; if (segment === 'service' && route.path.split('/').length > 3 && role.value !== 'staff' || segment === 'approval' && role.value !== 'supervisor') ctx.notify('当前账户无权访问此功能。'); } document.title = `${title.value} · 智服`; }, { immediate: true }); async function submitLogin() { if (login.pending) return; login.pending = true; login.error = ''; try { await ctx.login(product.value, login); } catch (error) { login.error = error.message; } finally { login.password = ''; login.pending = false; } } async function accept() { const state = ctx.confirmation; if (state.busy) return; state.busy = true; try { await state.callback(); state.open = false; } catch (error) { ctx.notify(error.message); state.open = false; } finally { state.busy = false; } } function logout() { ctx.confirm('退出登录', '确认退出当前后台?未提交内容将被清理。', () => ctx.logout(product.value)); } async function beforeCustomerClose(action) { // 异步业务结束前保持窗口,组件库负责确认按钮的处理中状态。 if (ctx.confirmation.busy) return false; if (action === 'confirm') await accept(); return true; } function home(target) { const r = ctx.session[target]?.role || target; ctx.navigate(r, { customer: 'home', merchant: 'overview', staff: 'queue', supervisor: 'approvals', platform: 'dashboard' }[r]); } return { ctx, product, role, page, account, productTitle, menus, title, blocked, login, submitLogin, accept, logout, home, navigationIcon, beforeCustomerClose }; }, template: `
智服商城与管理中心

页面不可访问

返回首页

{{ctx.confirmation.text}}

`, };