// 全 API 本地拦截;沉默期响应依据 docs/api/package-silence.openapi.json。 import { mockApiPlugin as fallback } from './pollingSchedulerBrowserFixtures.mjs' const time = '2026-10-28T10:00:00+08:00' const log = [] let localPaymentStatus = 'pending_payment' const silence = { silence_status: 'expired', silence_status_name: '沉默期已过期', silence_deadline_at: '2026-10-27T23:59:59+08:00', silence_period_days: 30, silence_extended_days: 0, silence_paid_extended_days: 0, silence_extension_count: 0, silence_free_extension_used: 0, silence_adjust_pending: false, extendable: true } const silenceOrder = () => ({ id: 7, order_no: 'LOCAL-SILENCE-7', status: localPaymentStatus, status_name: localPaymentStatus === 'completed' ? '已完成' : '待支付', package_usage_id: 4, package_id: 8, package_name: '本地实名套餐', asset_identifier: '89860426012345678901', asset_type: 'iot_card', asset_id: 2, source: 'admin', source_name: '后台', amount: 100, paid_amount: null, payment_method: 'wechat', input_days: 31, extension_days: 60, qr_content: localPaymentStatus === 'pending_payment' ? 'https://local.invalid/payment/7' : '', expire_at: '2026-10-28T23:59:59+08:00', before_deadline_at: '2026-10-27T23:59:59+08:00', expected_deadline_at: '2026-12-26T23:59:59+08:00', created_at: time, approval_required: false }) const silencePolicy = { id: 1, name: '本地全部套餐政策', scope_type: 'all', scope_type_name: '全部套餐', scope_ids: [], unit_price: 100, free_extension_limit: 1, paid_max_months: 12, single_max_months: null, effective_from: time, effective_to: null, approval_exempt_types: [], status: 1, created_at: time, updated_at: time } const silenceBatch = { id: 3, batch_no: 'LOCAL-BATCH-3', path: 'special', extension_type: 'free', status: 'pending_approval', approval_required: true, approval_status: 'pending', requested_count: 1, succeeded_count: 0, failed_count: 0, reason: '本地原因', basis: '本地依据', amount: 0, requested_at: time, evidence_refs: [], items: [ { id: 9, row_no: 1, package_usage_id: 4, asset_identifier: '89860426012345678901', package_name: '本地实名套餐', extension_days: 30, status: 'exception', failure_code: 'local_exception', failure_summary: '仅本地模拟执行异常', amount: 0, before_deadline_at: time } ] } const pkg = { id: 8, package_name: '本地实名套餐', package_code: 'LOCAL', package_type: 'formal', series_id: 1, series_name: '本地系列', expiry_base: 'from_activation', silence_period_days: 30, silence_extension_enabled: true, silence_config_required: true, duration_months: 1, calendar_type: 'natural_month', status: 1, shelf_status: 1, cost_price: 100, suggested_retail_price: 200, real_data_mb: 1024, is_gift: false, created_at: time, updated_at: time } const entries = [ ['平台订单', '/order-management/platform-orders', 'orders:platform_page'], ['代理商订单', '/order-management/agent-orders', 'orders:agent_page'], ['在线支付订单', '/order-management/online-orders', 'orders:online_page'], ['订单列表', '/order-management/order-list', ''], ['订单详情', '/order-management/order-list/detail/:id', ''] ] const page = (items, url) => ({ items, total: items.length, page: Number(url.searchParams.get('page') || 1), page_size: Number(url.searchParams.get('page_size') || 20), size: Number(url.searchParams.get('page_size') || 20), total_pages: 1 }) const ok = (res, data, code = 0, msg = 'local mock only') => { res.setHeader('Content-Type', 'application/json; charset=utf-8') res.end(JSON.stringify({ code, msg, data })) } export const mockApiPlugin = { name: 'order-silence-known-contract-mock', configureServer(server) { server.middlewares.use(async (req, res, next) => { const url = new URL(req.url, 'http://127.0.0.1'), path = url.pathname if (path === '/__order-silence-log') return ok(res, log) const handled = ['/api/auth/me', '/api/auth/login', '/api/auth/logout'].includes(path) || /^\/api\/admin\/(orders|packages|package-series|package-silence|employee-collection-payment-methods|assets|system-configs|iot-cards|devices|shops|accounts)(\/|$)/.test( path ) if (!handled) return next() let raw = '' for await (const part of req) raw += part const input = raw ? JSON.parse(raw) : {}, token = String(req.headers.authorization || ''), type = token.includes('enterprise') ? 4 : token.includes('agent') ? 3 : token.includes('super') ? 1 : 2 log.push({ path, method: req.method, body: input, query: Object.fromEntries(url.searchParams) }) const matches = (items, field, keyword) => items.filter((item) => !keyword || String(item[field]).includes(keyword)) if (path === '/api/admin/iot-cards/standalone') return ok( res, page( matches( [ { id: 2, iccid: '89860426012345678901', virtual_no: 'LOCAL-CARD', shop_name: '本地店铺' } ], 'iccid', url.searchParams.get('keyword') ), url ) ) if (path === '/api/admin/devices') return ok( res, page( matches( [ { id: 3, virtual_no: 'LOCAL-DEVICE', device_name: '本地设备', imei: '860000000000001', shop_name: '本地店铺' } ], 'virtual_no', url.searchParams.get('keyword') ), url ) ) if (path === '/api/admin/shops') return ok( res, page( matches( [{ id: 6, shop_name: '本地店铺' }], 'shop_name', url.searchParams.get('shop_name') ), url ) ) if (path === '/api/admin/accounts') return ok( res, page( matches( [{ id: 2, username: '本地操作员', shop_name: '本地店铺' }], 'username', url.searchParams.get('username') ), url ) ) if (path.startsWith('/api/auth/')) return ok(res, { access_token: `local-silence-${type === 1 ? 'super' : type === 3 ? 'agent' : type === 4 ? 'enterprise' : 'platform'}`, refresh_token: '', expires_in: 3600, user: { id: type, user_type: type, username: '本地订单沉默期验收', roles: [type === 1 ? 'R_SUPER' : 'R_ADMIN'] }, permissions: [ 'orders:platform_page', 'orders:agent_page', 'orders:online_page', 'package_silence:orders_page', 'package_silence:order_detail_page', 'package_silence:batches_page', 'package_silence:batch_detail_page', 'package_silence:usages_page', 'package_silence:policies_page' ], buttons: [ 'orders:add', 'orders:export', 'orders:view_detail', 'package:add', 'package:edit', 'package:detail', 'package_silence:override', 'package_silence:extend', 'package_silence:extend_batch', 'package_silence:offline', 'package_silence:exception', 'package_silence:policy', 'package_silence:order_detail', 'package_silence:batch_detail', 'package_silence:order_export', 'package_silence:usage_export' ], menus: [ { name: '订单管理', url: '/order-management', children: entries.map(([name, url, perm_code]) => ({ name, url, perm_code })) }, { name: '套餐管理', url: '/package-management', children: [ { name: '套餐列表', url: '/package-management/package-list' }, { name: '套餐详情', url: '/package-management/package-list/detail/:id' }, ...['orders', 'batches', 'usages', 'policies'].map((kind, index) => ({ name: ['延期订单', '延期批次与异常', '临期/过期套餐', '延期政策'][index], url: `/package-management/silence-${kind}`, perm_code: `package_silence:${kind}_page` })), { name: '延期订单详情', url: '/package-management/silence-orders/detail/:id', perm_code: 'package_silence:order_detail_page', is_hidden: true }, { name: '延期批次详情', url: '/package-management/silence-batches/detail/:id', perm_code: 'package_silence:batch_detail_page', is_hidden: true } ] }, { name: '设置', url: '/settings', children: [{ name: '沉默期总开关', url: '/settings/package-silence-switch' }] } ] }) if (path.startsWith('/api/admin/orders')) { if (type === 4) return ok(res, null, 403, '企业账号无权访问订单') if (path.endsWith('/online') && type === 3) return ok(res, page([], url)) const order = { id: 1, order_no: `LOCAL-${path.split('/').at(-1)}`, order_type: 'single_card', buyer_type: 'personal', buyer_id: 1, payment_status: 2, payment_status_text: '已支付', payment_method: 'offline', total_amount: 200, actual_paid_amount: 200, paid_at: time, items: [ { id: 1, package_id: 8, package_name: pkg.package_name, quantity: 1, unit_price: 200, amount: 200 } ], asset_identifier: '89860426012345678901', asset_type: 'card', created_at: time, updated_at: time, commission_status: 2, commission_config_version: 1, payments: [] } return ok( res, /\/orders\/\d+$/.test(path) || req.method === 'POST' ? order : page([order], url) ) } if (path === '/api/admin/package-silence/switch') { if (type !== 1) return ok(res, null, 403, '仅超级管理员可操作') const precheck = [ { code: 'package', name: '套餐沉默期配置', passed: false, count: 2 }, { code: 'policy', name: '延期政策', passed: true, count: 1 }, { code: 'template', name: '企微审批模板', passed: true, count: 1 }, { code: 'member', name: '默认审批人', passed: true, count: 1 } ] return req.method === 'PUT' ? ok(res, { failed_items: [precheck[0]] }, 1275, '检查未通过,存在未配置沉默期套餐') : ok(res, { enabled: false, precheck }) } if (path === '/api/admin/employee-collection-payment-methods') return ok(res, page([{ id: 2, name: '本地银行收款', enabled: true }], url)) if (path.startsWith('/api/admin/assets/') && path.endsWith('/first-purchase-records')) return ok(res, [ { id: 1, generation: 1, asset_identifier: 'LOCAL-ASSET', first_purchase_at: time, source: 'order', source_name: '首次购买套餐', order_no: 'LOCAL-ORDER', end_reason: 'exchange_return', ended_at: time, created_at: time } ]) if (path.startsWith('/api/admin/package-silence/')) { if (path.endsWith('/eligibility')) return ok(res, { package_usage_id: 4, can_extend: true, special_extension_available: true, free_extension_available: true, min_days: 1, max_days: 360, min_months: 1, max_months: 12, unit_price: 100, options: [{ amount: 100, billed_days: 30, months: 1, new_deadline: '2026-11-26' }], original_deadline: '2026-10-27', reason: '', policy_id: 1, policy_name: '本地全部套餐政策' }) if (path.endsWith('/quote')) return ok(res, { amount: 200, billed_days: 60, input_days: Number(url.searchParams.get('days')), months: 2, new_deadline: '2026-12-26', valid: true }) if (path.endsWith('/orders/qrcode')) { localPaymentStatus = 'pending_payment' return ok(res, silenceOrder()) } if (path.endsWith('/orders/offline')) return ok(res, { ...silenceOrder(), status: 'pending_approval', status_name: '待审批', approval_required: true, qr_content: '', payment_method: 'offline' }) if (path.endsWith('/orders')) return ok(res, page([silenceOrder()], url)) if (/\/orders\/\d+$/.test(path)) { const order = silenceOrder() localPaymentStatus = 'completed' return ok(res, order) } if (path.endsWith('/special')) return ok(res, silenceBatch) if (path.endsWith('/batches')) return ok(res, page([silenceBatch], url)) if (/\/batches\/\d+$/.test(path)) return ok(res, silenceBatch) if (path.endsWith('/handle')) return ok(res, { ...silenceBatch.items[0], status: input.action === 'close' ? 'closed' : 'completed', failure_summary: '' }) if (path.endsWith('/usages')) return ok( res, page( [ { package_usage_id: 4, package_id: 8, package_name: pkg.package_name, asset_id: 2, asset_identifier: '89860426012345678901', asset_type: 'iot_card', shop_id: 1, shop_name: '本地店铺', created_at: time, order_no: 'LOCAL-ORDER', silence } ], url ) ) if (path.endsWith('/records')) return ok(res, [ { id: 1, event_type: 'set', event_name: '设置沉默期', before_status: null, after_status: 'waiting', after_deadline_at: time, change_days: 30, operator_id: 1, operator_type: 'admin', reason: '本地记录', created_at: time } ]) if (path.endsWith('/policies/match')) return ok(res, { matched: true, package_id: 8, policy: silencePolicy }) if (path.endsWith('/policies')) return ok(res, req.method === 'GET' ? [silencePolicy] : { ...silencePolicy, ...input }) if (/\/policies\/\d+(\/status)?$/.test(path)) return ok(res, { ...silencePolicy, ...input }) return ok(res, null, 400, '本地未定义的沉默期接口已阻止') } if (path.startsWith('/api/admin/packages')) return ok( res, path === '/api/admin/packages' && req.method === 'GET' ? page([pkg], url) : { ...pkg, ...input } ) if (path.startsWith('/api/admin/package-series')) return ok( res, page([{ id: 1, series_name: '本地系列', series_code: 'LOCAL', status: 1 }], url) ) if (path.startsWith('/api/admin/system-configs')) return ok(res, { list: [], total: 0, page: 1, page_size: 20 }) return ok(res, null, 400, '本地未定义,已阻止请求') }) fallback.configureServer(server) } }