function assertRouter(api) { if (!api || typeof api.get !== 'function' || typeof api.post !== 'function') { throw new Error('attachPortalTemplateCatalogRoutes requires an Express-compatible router'); } } export function attachPortalTemplateCatalogRoutes( api, { getTemplateCatalog = () => null, ensureMindSpaceEnabled = () => false, sendData = (res, _req, data) => res.json({ data }), sendError = (res, _req, status, code, message) => res.status(status).json({ error: { code, message } }), } = {}, ) { assertRouter(api); api.get('/mindspace/v1/template-catalog', async (req, res) => { const catalog = getTemplateCatalog(); if (!catalog || !ensureMindSpaceEnabled(res, req)) return; try { const items = await catalog.listCatalogForUser(req.currentUser.id); return sendData(res, req, { items }); } catch (error) { const message = error instanceof Error ? error.message : '读取模板商城失败'; return sendError(res, req, 500, 'template_catalog_error', message); } }); api.get('/mindspace/v1/template-catalog/mine', async (req, res) => { const catalog = getTemplateCatalog(); if (!catalog || !ensureMindSpaceEnabled(res, req)) return; try { const items = await catalog.listMine(req.currentUser.id); return sendData(res, req, { items }); } catch (error) { const message = error instanceof Error ? error.message : '读取已购模板失败'; return sendError(res, req, 500, 'template_catalog_error', message); } }); api.post('/mindspace/v1/template-catalog/:skillName/purchase', async (req, res) => { const catalog = getTemplateCatalog(); if (!catalog || !ensureMindSpaceEnabled(res, req)) return; try { const result = await catalog.purchaseWithBalance(req.currentUser.id, req.params.skillName); if (!result.ok) { if (result.code === 'INSUFFICIENT_BALANCE') { return res.status(402).json({ error: { code: result.code, message: result.message, }, details: { balanceCents: result.balanceCents, minRechargeCents: result.minRechargeCents, suggestedTiers: result.suggestedTiers, }, }); } return sendError(res, req, 400, 'template_purchase_failed', result.message); } return sendData(res, req, result); } catch (error) { const message = error instanceof Error ? error.message : '购买模板失败'; return sendError(res, req, 500, 'template_purchase_error', message); } }); api.post('/mindspace/v1/template-catalog/:skillName/favorite', async (req, res) => { const catalog = getTemplateCatalog(); if (!catalog || !ensureMindSpaceEnabled(res, req)) return; try { const result = await catalog.toggleTemplateFavorite(req.currentUser.id, req.params.skillName); if (!result.ok) { return sendError(res, req, 400, 'template_favorite_failed', result.message); } return sendData(res, req, result); } catch (error) { const message = error instanceof Error ? error.message : '收藏操作失败'; return sendError(res, req, 500, 'template_favorite_error', message); } }); api.get('/mindspace/v1/template-catalog/:skillName/preview', async (req, res) => { const catalog = getTemplateCatalog(); if (!catalog || !ensureMindSpaceEnabled(res, req)) return; try { const result = await catalog.getTemplatePreviewHtml(req.params.skillName); if (!result.ok) { return sendError(res, req, 404, 'template_preview_not_found', result.message); } res.setHeader('Content-Type', 'text/html; charset=utf-8'); res.setHeader('Cache-Control', 'public, max-age=300'); return res.send(result.html); } catch (error) { const message = error instanceof Error ? error.message : '读取模板预览失败'; return sendError(res, req, 500, 'template_preview_error', message); } }); api.post('/mindspace/v1/template-catalog/:skillName/checkout', async (req, res) => { const catalog = getTemplateCatalog(); if (!catalog || !ensureMindSpaceEnabled(res, req)) return; try { const payScene = ['native', 'h5', 'jsapi'].includes(req.body?.payScene) ? req.body.payScene : 'native'; const result = await catalog.createWechatCheckout({ userId: req.currentUser.id, skillName: req.params.skillName, payScene, clientIp: req.ip, }); if (!result.ok) { return sendError(res, req, 400, 'template_checkout_failed', result.message); } return sendData(res, req, result); } catch (error) { const message = error instanceof Error ? error.message : '创建模板支付订单失败'; return sendError(res, req, 500, 'template_checkout_error', message); } }); }