/** 人工关系页面使用模拟接口验证交互,不修改业务库。 */ import assert from 'node:assert/strict' import path from 'node:path' import { createRequire } from 'node:module' import { fileURLToPath } from 'node:url' import vue from '@vitejs/plugin-vue' import { createServer } from 'vite' const require = createRequire(import.meta.url) const { chromium } = require(process.env.PLAYWRIGHT_MODULE || 'C:/Users/Administrator/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright') const root = fileURLToPath(new URL('../', import.meta.url)) const id = 'virtual:sales-relations-proof' const harness = `import {createApp,h} from 'vue';import {createPinia,setActivePinia} from 'pinia';import ElementPlus from 'element-plus';import 'element-plus/dist/index.css';import Review from '/src/views/business/businesses/SalesRelationReview.vue';import {useUserStore} from '/src/store/user';const pinia=createPinia();setActivePinia(pinia);useUserStore().userInfo={permissions:location.search?[]:['business:businesses:update','payroll:prepare']};createApp({render:()=>h(Review,{businessId:12})}).use(pinia).use(ElementPlus).mount('#app')` const server = await createServer({ configFile: false, root, resolve: { alias: { '@': path.join(root, 'src') } }, define: { 'import.meta.env.VITE_API_BASE_URL': JSON.stringify('/api') }, plugins: [vue(), { name: 'sales-relations-proof', resolveId: value => value === id ? '\0' + id : undefined, load: value => value === '\0' + id ? harness : undefined, configureServer(instance) { instance.middlewares.use('/__relations-proof', async (_request, response) => { response.setHeader('Content-Type', 'text/html; charset=utf-8') response.end(await instance.transformIndexHtml('/__relations-proof', '
')) }) }, }], server: { host: '127.0.0.1', port: 0 } }) let browser, confirmation = null, version = 0, saved = null, failNext = false try { await server.listen() browser = await chromium.launch({ headless: true, channel: 'msedge' }) const page = await browser.newPage({ viewport: { width: 1024, height: 768 } }) await page.route(url => url.pathname.startsWith('/api/'), async route => { const url = new URL(route.request().url()) if (route.request().method() === 'PUT') { const input = route.request().postDataJSON() saved = input version++ const released = url.pathname.endsWith('/release') confirmation = { disposition: released ? 'RELEASED' : input.disposition, evidence: input.evidence, current: !released, shipment: released ? null : { source_id: 'SHIP1', source_no: '发货1' }, order: released ? null : { source_id: 'ORDER2', source_no: '订单2' } } return route.fulfill({ json: { code: 200, message: 'success', data: { item_id: 1, version } } }) } if (failNext) { failNext = false return route.fulfill({ status: 500, json: { code: 500, message: '加载失败' } }) } const shipPage = Number(url.searchParams.get('shipment_page')) const orderPage = Number(url.searchParams.get('order_page')) const item = { item_id: 1, product_name: '测试产品', spec: '规格', quantity: '2', amount: '200', item_revision: 'a'.repeat(64), version, confirmation, shipments: [{ document_id: shipPage, source_id: `SHIP${shipPage}`, source_no: `发货${shipPage}`, date: '2026-03-10', revision: 'b'.repeat(64) }], shipments_truncated: shipPage === 1, orders: [{ document_id: 100 + orderPage, source_id: `ORDER${orderPage}`, quantity: '2', amount: '200', revision: 'c'.repeat(64) }], orders_truncated: orderPage === 1 } await route.fulfill({ json: { code: 200, message: 'success', data: { list: [item], total: 1 } } }) }) await page.goto(`http://127.0.0.1:${server.httpServer.address().port}/__relations-proof`) await page.getByText('测试产品').waitFor() const row = page.locator('.relation-row') await row.locator('.el-select').nth(0).click() await page.getByRole('option', { name: /发货1/ }).click() await row.locator('.el-select').nth(1).click() await page.getByRole('option', { name: '对应订单发货' }).click() await row.getByRole('button', { name: '下一页' }).nth(1).click() await page.getByText('订单候选第 2 页').waitFor() await row.locator('.el-select').nth(2).click() await page.getByRole('option', { name: /ORDER2/ }).click() await row.locator('input[placeholder="填写依据"]').fill('原单核对') await row.getByRole('button', { name: '保存核对' }).click() await page.getByText(/已确认/).waitFor() assert.match(await row.innerText(), /发货1.*SHIP1.*订单2.*ORDER2/) assert.equal(saved.shipment_document_id, 1) assert.equal(saved.order_document_id, 102) assert.equal(saved.evidence, '原单核对') await row.getByRole('button', { name: '撤销核对' }).click() await page.getByPlaceholder('填写撤销依据').fill('重新核实') await page.getByRole('button', { name: '撤销核对' }).last().click() await page.getByText(/已撤销/).waitFor() assert.equal(saved.expected_version, 1) assert.equal(saved.evidence, '重新核实') await page.setViewportSize({ width: 375, height: 812 }) assert.ok(await page.locator('.relation-row').evaluate(el => el.getBoundingClientRect().right <= innerWidth)) await page.goto(`http://127.0.0.1:${server.httpServer.address().port}/__relations-proof?no-permission=1`) await page.getByText('测试产品').waitFor() assert.equal(await page.getByRole('button', { name: '保存核对' }).isDisabled(), true) failNext = true await page.reload() await page.getByText('列表加载失败,请重试').waitFor() await page.getByRole('button', { name: '重新加载' }).click() await page.getByText('测试产品').waitFor() process.stdout.write('人工关系跨页选择、确认、撤销、权限、失败重试及窄屏的模拟浏览器回归通过。\n') } finally { await browser?.close() await server.close() }