import { createServer } from '../../admin/node_modules/vite/dist/node/index.js' import vue from '../../admin/node_modules/@vitejs/plugin-vue/dist/index.mjs' import fs from 'node:fs' const root = 'D:/web/zyt/admin' const apiNames = [...fs.readFileSync(`${root}/src/api/first_visit.ts`, 'utf8').matchAll(/export (?:async )?function (wecomPromotion\w+)\s*\(/g)].map(match => match[1]) const members = [ { id: 1, admin_id: 1, name: '测试许可', userid: 'test_xuke', enabled: 1, reception_available: true }, { id: 2, admin_id: 2, name: '测试旧医助', userid: 'test_old', enabled: 0, reception_available: false } ].map(member => ({ ...member, dept_ids: [1], dept_names: ['测试部门'], display_dept_id: 1, status: member.enabled, today_count: 0, total_count: 0, daily_limit: 0, is_in_remote_range: true, sync_status: 1 })) const overview = { automation_installed: false, meta: { scope_label: '隔离验证', generated_at: '' }, config: { configured: true, ready: true, missing: [], callback_ready: true }, summary: { configured_apps: 1, pool_count: 1, online_links: 1, today_clicks: 0 }, member_options: members, operator_options: [], department_options: [{ id: 1, name: '测试部门' }], links: [], pools: [{ id: 99, name: '仅许可接待测试方案', public_key: 'test-only', status: 1, member_admin_ids: [1, 2], main_url: 'https://work.weixin.qq.com/ca/test-only', can_operate: true, can_manage_access: true, can_delete: true, operator_admin_ids: [], member_rules: members, automation_config: { backup_member_admin_ids: [] }, official_link: { id: 199, remote_link_id: 'test-link', range_userids: ['test_xuke', 'test_old'], range_department_ids: [], last_sync_time: 1788920000 }, dispatch_sync: { status: 1, desired_version: 2, applied_version: 1, last_error: '' } }] } const fixture = `const overview = ${JSON.stringify(overview)}; async function invoke(name, params) { if (name === 'wecomPromotionOverview') return structuredClone(overview); if (name === 'wecomPromotionSyncMemberRange') { const pool = overview.pools[0]; if (new URLSearchParams(location.search).get('mode') === 'failure') { pool.dispatch_sync.status = 3; pool.dispatch_sync.last_error = '模拟企微网络错误'; pool.member_rules.forEach(row => {row.sync_status = 3; row.sync_error = '模拟企微网络错误';}); return {pool_id:99,sync_status:'failed',sync_error:'模拟企微网络错误',sync_queued:true}; } pool.official_link.range_userids = ['test_xuke']; pool.official_link.last_sync_time = Math.floor(Date.now()/1000); pool.dispatch_sync = {status:0,desired_version:2,applied_version:2,last_error:''}; pool.member_rules.forEach(row => {row.is_in_remote_range = row.enabled === 1; row.sync_status = 0;}); return {pool_id:99,sync_status:'synced',sync_error:'',sync_queued:false,range_userids:['test_xuke'],range_department_ids:[]}; } throw new Error('隔离页面未实现该操作:' + name); } ${apiNames.map(name => `export function ${name}(params) {return invoke('${name}',params);}`).join('\n')}` const server = await createServer({ configFile: false, root, base: '/', cacheDir: 'D:/web/zyt/artifacts/wecom-member-sync/vite-cache', optimizeDeps: { entries: [], include: ['vue', 'element-plus', '@element-plus/icons-vue'] }, resolve: { alias: { '@': `${root}/src` } }, plugins: [{ name: 'member-sync-isolated-fixture', enforce: 'pre', resolveId(id) { if (id === '@/api/first_visit' || id.endsWith('/src/api/first_visit')) return '\0member-sync-api' if (id === '/__member-sync-entry.js') return '\0member-sync-entry' }, load(id) { if (id === '\0member-sync-api') return fixture if (id === '\0member-sync-entry') return `import {createApp} from 'vue';import ElementPlus from 'element-plus';import 'element-plus/dist/index.css';import View from '/src/views/first_visit/wecom_promotion/index.vue';createApp(View).use(ElementPlus).mount('#app');` }, configureServer(dev) { dev.middlewares.use((req, res, next) => { if (!req.url?.startsWith('/__member-sync-check')) return next() res.setHeader('Content-Type', 'text/html;charset=utf-8') res.end('企微成员同步隔离验证

隔离验证:虚构数据,不连接企业微信

') }) } }, vue()], server: { host: '127.0.0.1', port: 5587, strictPort: true, open: false } }) await server.listen() console.log('Isolated UI: http://127.0.0.1:5587/__member-sync-check') for (const event of ['SIGINT', 'SIGTERM']) process.on(event, async () => { await server.close(); process.exit(0) })