| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- // 浏览器测试的 API 边界替身;绝不向真实业务接口发请求。
- const pdfObjects = [
- '<< /Type /Catalog /Pages 2 0 R >>',
- '<< /Type /Pages /Kids [3 0 R] /Count 1 >>',
- '<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Resources << >> /Contents 4 0 R >>',
- '<< /Length 0 >>\nstream\n\nendstream'
- ]
- let pdfFixture = '%PDF-1.4\n'
- const offsets = [0]
- pdfObjects.forEach((obj, i) => {
- offsets.push(Buffer.byteLength(pdfFixture))
- pdfFixture += `${i + 1} 0 obj\n${obj}\nendobj\n`
- })
- const xref = Buffer.byteLength(pdfFixture)
- pdfFixture += `xref\n0 5\n0000000000 65535 f \n${offsets
- .slice(1)
- .map((n) => `${String(n).padStart(10, '0')} 00000 n `)
- .join('\n')}\ntrailer\n<< /Size 5 /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF`
- export function makePlan(index, overrides = {}) {
- const id = `plan-${index}`
- const toxic = {
- id: `${id}-toxic`,
- planId: id,
- productId: 'toxic',
- productNo: 'CP001',
- productName: '测试易制毒产品',
- brandName: '测试品牌',
- aliasName: '测试别名',
- model: '99%',
- unit: 'ton',
- quantity: 12,
- actualQty: 11,
- isToxic: 1,
- isExplosive: 0,
- purchaseCertUrl: '',
- transportCertUrl: '',
- legalUseCertUrl: ''
- }
- const explosive = {
- ...toxic,
- id: `${id}-explosive`,
- productId: 'explosive',
- productNo: 'CP002',
- productName: '测试易制爆产品',
- isToxic: 0,
- isExplosive: 1
- }
- const stopProducts = [toxic, explosive].map((p) => ({
- ...p,
- id: `stop-${p.id}`,
- planProductId: p.id,
- planQty: 12,
- inboundQty: 10,
- outboundQty: 9,
- contractId: 'contract-1',
- contractNo: 'HT-001',
- packageSpec: 'bulk',
- remark: '产品备注'
- }))
- return {
- id,
- planNo: `YS${String(index).padStart(3, '0')}`,
- planDate: '2026-10-17',
- createDate: '2026-10-17',
- createTime: '2026-10-17 09:15:00',
- belongsCompany: 'shanxia',
- planType: ['inbound', 'outbound', 'direct'][(index - 1) % 3],
- followStatus: 'pending_arrange',
- transportStatus: 'pending',
- archiveStatus: 'pending',
- completeStatus: 'pending',
- hasFreight: 1,
- freightAmount: 1234,
- freightRemark: '测试运费说明',
- totalAmount: 12345,
- hazardCertReady: 0,
- followUserName: '测试跟进人',
- licensePlate: '鄂E12345',
- trailerNo: '鄂E1234挂',
- driverName: '测试司机',
- escortName: '测试押运员',
- personnelSummary: '司机:测试司机;押运:测试押运员',
- deliveryTimes: ['2026-10-18 10:30:00', '2026-10-19 14:20:00'],
- remark: '证书迁移测试备注',
- products: [toxic, explosive],
- documentAttachments: [{ url: '/fixtures/plan.pdf', label: '计划附件.pdf' }],
- load: {
- id: `${id}-load`,
- customerName: '测试供应商',
- address: '湖北省宜昌市装货地址',
- loadTime: '2026-10-17 09:20:00',
- contact: '张师傅 13800000000',
- notes: '装货注意事项',
- contracts: [{ contractId: 'contract-1', contractNo: 'HT-001' }],
- products: stopProducts
- },
- deliveries: [1, 2].map((seq) => ({
- id: `${id}-delivery-${seq}`,
- seq,
- customerName: `测试需方${seq}`,
- address: `送货地址${seq}`,
- deliveryTime: `2026-10-${17 + seq} 10:30:00`,
- contact: '李师傅 13900000000',
- notes: `送货注意事项${seq}`,
- generateDibang: 0,
- contracts: [{ contractId: 'contract-1', contractNo: 'HT-001' }],
- products: stopProducts.map((p) => ({ ...p, id: `${p.id}-${seq}`, planQty: 6 }))
- })),
- ...overrides
- }
- }
- export async function installCertFixture(context) {
- const state = {
- plans: Array.from({ length: 24 }, (_, i) => makePlan(i + 1)),
- codes: [
- 'mini:pl:plan-cert:list',
- 'pl:plan-cert:list',
- 'pl:plan-cert:upload',
- 'pl:plan-cert:ready'
- ],
- calls: [],
- unknown: [],
- failList: false,
- failSave: false,
- failReadyIds: [],
- uploadGate: null,
- listDelay: null,
- linkedListGate: null,
- failPermissions: false
- }
- state.plans[3].archiveStatus = 'archived'
- state.plans[4].followStatus = 'cancelled'
- state.plans[5].hazardCertReady = 1
- state.plans[6].transportStatus = 'arranged'
- state.plans[6].followStatus = 'arranged'
- state.plans[6].transportId = 'transport-7'
- await context.addInitScript(() => {
- window.__copiedText = ''
- Object.defineProperty(navigator, 'clipboard', {
- configurable: true,
- value: {
- writeText: async (text) => {
- window.__copiedText = text
- }
- }
- })
- window.wx = {
- miniProgram: {
- navigateBack() {},
- reLaunch() {},
- getEnv(cb) {
- cb({ miniprogram: true })
- }
- }
- }
- })
- await context.route('**/fixtures/**', (route) =>
- route.fulfill(
- route.request().url().endsWith('.png')
- ? {
- contentType: 'image/png',
- body: Buffer.from(
- 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+cL1sAAAAASUVORK5CYII=',
- 'base64'
- )
- }
- : { contentType: 'application/pdf', body: pdfFixture }
- )
- )
- await context.route('https://api.qrserver.com/**', (route) =>
- route.fulfill({
- contentType: 'image/svg+xml',
- body: '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"><rect width="200" height="200" fill="white"/><text x="10" y="100">Mock QR preview</text></svg>'
- })
- )
- await context.route('**/api/**', async (route) => {
- const request = route.request()
- const url = new URL(request.url())
- if (!url.pathname.startsWith('/api/')) return route.continue()
- const path = url.pathname.slice(4)
- const method = request.method()
- let body = {}
- try {
- body = request.postDataJSON() || {}
- } catch {
- body = {}
- }
- const params = Object.fromEntries(url.searchParams)
- state.calls.push({ path, method, body, params })
- let data
- let error = ''
- if (path === '/web/auth/mp-webview-exchange') {
- data = {
- token: 'fixture-token',
- refreshToken: 'fixture-refresh',
- userInfo: {
- id: 'user-1',
- userId: 'user-1',
- userName: '测试用户',
- role: 'admin',
- roles: ['admin']
- }
- }
- } else if (path === '/web/auth/menu-codes') {
- data = { all: false, isSuperAdmin: false, menuCodes: state.codes }
- if (state.failPermissions) error = '权限加载失败'
- } else if (path === '/web/admin/dict-data/all') {
- data = {
- crm_product_unit: [{ value: 'ton', label: '吨' }],
- pl_package_spec: [{ value: 'bulk', label: '散装' }]
- }
- } else if (path === '/transport/plan/') {
- if (params.contractId === 'contract-1' && state.linkedListGate) await state.linkedListGate
- if (state.listDelay) await state.listDelay(params)
- if (state.failList) {
- state.failList = false
- error = '列表测试失败'
- }
- let rows = state.plans
- if (params.followStatus)
- rows = rows.filter((p) => params.followStatus.split(',').includes(p.followStatus))
- if (params.planType) rows = rows.filter((p) => p.planType === params.planType)
- if (params.hazardCertReady !== undefined)
- rows = rows.filter((p) => p.hazardCertReady === Number(params.hazardCertReady))
- if (params.q)
- rows = rows.filter(
- (p) =>
- p.planNo.includes(params.q) || p.products.some((x) => x.productName.includes(params.q))
- )
- if (params.certUploadStatus === 'incomplete')
- rows = rows.filter((p) =>
- p.products.some((x) =>
- x.isToxic
- ? !(x.purchaseCertUrl && x.transportCertUrl)
- : x.isExplosive && !x.legalUseCertUrl
- )
- )
- const page = Number(params.page || 1),
- size = Number(params.pageSize || 20)
- data = {
- list: rows.slice((page - 1) * size, page * size),
- total: rows.length,
- page,
- pageSize: size
- }
- } else if (path === '/transport/plan/column-facet-values') {
- const values = {
- planNo: ['YS001'],
- licensePlate: ['鄂E12345'],
- productName: ['测试易制毒产品'],
- productSpec: ['99%'],
- productUnit: ['ton'],
- loadCustomer: ['测试供应商'],
- deliveryCustomer: ['测试需方1'],
- productContract: ['HT-001']
- }
- data = {
- list: (values[body.field] || []).map((value) => ({ value, label: value, count: 1 }))
- }
- } else if (/^\/transport\/plan\/plan-\d+$/.test(path)) {
- data = state.plans.find((p) => p.id === path.split('/').pop())
- } else if (/\/plan-\d+\/product-certs$/.test(path)) {
- const plan = state.plans.find((p) => p.id === path.split('/')[3])
- if (state.failSave) {
- state.failSave = false
- error = '证书保存测试失败'
- } else
- for (const item of body.products)
- Object.assign(
- plan.products.find((p) => p.id === item.id),
- item
- )
- data = plan
- } else if (/\/plan-\d+\/hazard-cert-ready$/.test(path)) {
- const plan = state.plans.find((p) => p.id === path.split('/')[3])
- if (state.failReadyIds.includes(plan.id)) error = '齐备测试失败'
- else plan.hazardCertReady = body.ready ? 1 : 0
- data = plan
- } else if (/\/plan-\d+\/arrange-info$/.test(path)) {
- data = {
- driverUrl: 'https://example.test/driver',
- licensePlate: '鄂E12345',
- siteRecords: [
- {
- siteLinkId: 'site-1',
- siteUrl: 'https://example.test/site',
- planProductId: 'plan-7-toxic',
- productName: '测试易制毒产品',
- customerName: '测试需方1'
- }
- ],
- inventoryRecords: [
- {
- dbInventoryId: 'inventory-7',
- dbPurchasePlanId: 'purchase-7',
- planProductId: 'plan-7-toxic',
- productName: '测试易制毒产品',
- businessType: '入库'
- }
- ]
- }
- } else if (path === '/transport/inbound/by-plan/plan-7') {
- data = {
- id: 'io-7',
- kind: 'inbound',
- orderNo: 'RK-007',
- status: 'in_progress',
- siteFeedbackRemark: '入库现场备注',
- siteFeedbackTime: '2026-10-17 16:20:00',
- siteFeedbackImages: ['/fixtures/inbound.pdf'],
- products: []
- }
- } else if (path === '/transport/order/transport-7') {
- data = {
- id: 'transport-7',
- transportNo: 'TR007',
- licensePlate: '鄂E12345',
- driverName: '测试司机',
- driverPhone: '13800000000',
- escortName: '测试押运员',
- freightAmount: 1234,
- freightPrice: 50,
- freightType: 'by_weight',
- transportQty: 24,
- hasInvoice: 1,
- distanceKm: 100,
- unit: 'ton',
- transportStatus: 'arranged',
- approvalStatus: 'approved',
- createTime: '2026-10-17 11:00:00',
- feedbackTime: '2026-10-17 16:00:00',
- feedbackQty: 23,
- feedbackRemark: '司机回传测试备注',
- feedbackImages: '["/fixtures/driver.pdf"]',
- driverStopFeedbacks: [
- {
- stopType: 'load',
- stopId: 'plan-7-load',
- label: '装货',
- customerName: '测试供应商',
- quantity: 23,
- remark: '司机装货回传',
- feedbackTime: '2026-10-17 16:00:00',
- attachmentUrls: ['/fixtures/driver.png'],
- products: []
- }
- ],
- siteStopFeedbacks: [
- {
- stopType: 'delivery',
- stopId: 'plan-7-delivery-1',
- label: '送货',
- customerName: '测试需方1',
- quantity: 12,
- remark: '现场送货回传',
- feedbackTime: '2026-10-18 10:00:00',
- attachmentUrls: ['/fixtures/site.pdf'],
- products: []
- }
- ]
- }
- } else if (path === '/transport/freight/by-transport/transport-7') {
- data = null
- } else if (path === '/inventory/inventory-7/related') {
- data = {
- plan: null,
- weighing: {
- id: 'weighing-7',
- vehicleNo: '鄂E12345',
- netWeight: 11,
- grossWeight: 30,
- tareWeight: 19,
- grossWeightTime: '2026-10-17 15:30:00',
- tareWeightTime: '2026-10-17 16:30:00',
- supplier: '测试供应商',
- consignee: '测试需方1',
- remarks: '测试过磅备注'
- }
- }
- } else if (path === '/inventory/inventory-7') {
- data = {
- id: 'inventory-7',
- date: '2026-10-17',
- vehicleNo: '鄂E12345',
- partnerCompany: '测试供应商',
- product: '测试易制毒产品',
- quantity: 12,
- businessType: '入库'
- }
- } else if (/^\/web\/crm\/contract\/approval\/flow\/contract-[12]$/.test(path)) {
- data = []
- } else if (/^\/web\/crm\/contract\/contract-[12]$/.test(path)) {
- data = {
- id: path.split('/').pop(),
- contractNo: path.endsWith('contract-1') ? 'HT-001' : 'HT-002',
- contractName: '危化品证书测试合同',
- opportunityId: 'opportunity-1',
- quoteId: 'quote-1',
- contractType: 'sales',
- customerName: '测试需方1',
- supplierName: '测试供应商',
- status: 'approved',
- startDate: '2026-01-01',
- endDate: '2026-12-31',
- remark: '合同说明',
- amount: 2400,
- partyA: '测试甲方',
- partyB: '测试乙方',
- partyAAccount: '测试账号001',
- contractFile: '[{"ossId":"/fixtures/contract.pdf","name":"合同原件.pdf"}]',
- attachmentFiles: '[{"ossId":"/fixtures/extra.pdf","name":"其他附件.pdf"}]',
- products: [
- {
- id: 'contract-product-1',
- productId: 'toxic',
- productName: '测试别名',
- unit: 'ton',
- quantity: 24,
- price: 100,
- subtotal: 2400
- }
- ],
- attachments: '/fixtures/contract.pdf'
- }
- } else if (path === '/web/crm/opportunity/detail') {
- data = { id: 'opportunity-1', opportunityName: '测试关联商机' }
- } else if (path === '/web/crm/quote/detail') {
- data = { id: 'quote-1', quoteNo: 'BJ-001' }
- } else if (path === '/web/crm/products/detail') {
- data = {
- id: body.id,
- productName: body.id === 'toxic' ? '测试易制毒产品' : '测试易制爆产品',
- aliases: [{ aliasName: '测试别名' }],
- isToxic: body.id === 'toxic' ? 1 : 0,
- isExplosive: body.id === 'explosive' ? 1 : 0
- }
- } else if (path === '/web/admin/attachment/preview-url') {
- data = { previewUrl: params.fileUrl || body.fileUrl }
- } else if (path === '/web/admin/attachment/download-url') {
- data = { downloadUrl: params.fileUrl || body.fileUrl }
- } else if (path === '/web/admin/attachment/upload') {
- if (state.uploadGate) await state.uploadGate
- data = {
- id: 'file-1',
- fileName: '测试证书.pdf',
- fileUrl: '/fixtures/cert.pdf',
- fileType: 'application/pdf'
- }
- } else {
- state.unknown.push({ path, method, body, params })
- error = `未定义测试接口:${method} ${path}`
- }
- if (error)
- return route.fulfill({
- status: 400,
- contentType: 'application/json',
- body: JSON.stringify({ code: 400, msg: error, detail: error })
- })
- // 运输 API 是 FastAPI 直出;Web API 使用 code=200 的信封。
- await route.fulfill({
- contentType: 'application/json',
- body: JSON.stringify(
- path.startsWith('/transport/') || path.startsWith('/inventory/')
- ? data
- : { code: 200, msg: 'ok', data }
- )
- })
- })
- return state
- }
|