import assert from 'node:assert/strict' import test from 'node:test' import { readFileSync } from 'node:fs' import { parse } from '@vue/compiler-sfc' import ts from 'typescript' import { computed, ref } from 'vue' import { mapLoadFromApi, mapDeliveriesFromApi, resolveLoadViewAddress, resolveDeliveryViewAddress, resolveStopProductsForView } from '../src/utils/pl-plan-stop-form' import { resolvePlanStopsForList } from '../src/utils/pl-plan-list-display-rows' import { stopProductMeta } from '../src/views/m/pl/plan-cert/model' function declaration(source: string, name: string) { const ast = ts.createSourceFile('test.ts', source, ts.ScriptTarget.Latest, true) return ast.statements .find((node) => ts.isFunctionDeclaration(node) ? node.name?.text === name : ts.isVariableStatement(node) && node.declarationList.declarations.some((d) => d.name.getText(ast) === name) )! .getText(ast) .replace(/^export /, '') } test('actual detail stop mapping retains per-line mobile metadata and explicit empty values', () => { const loadMeta = { aliasName: '装货别名', brandMode: 'required', brandName: '装货品牌', brandId: 'b' } const deliveryMeta = { aliasName: null, brandMode: 'any', brandName: '', brandId: '' } const line = { id: 's', planProductId: 'p', productId: 'crm', productName: '产品', planQty: 0, inboundQty: 0, outboundQty: 0 } const plan = ref({ id: 'A', load: { products: [{ ...line, mobileProductMeta: loadMeta }] }, deliveries: [{ products: [{ ...line, mobileProductMeta: deliveryMeta }] }] }) const products = ref([ { id: 'p', productId: 'crm', productName: '根别名', standardProductName: '标准产品', aliasName: '根别名', brandName: '根品牌', brandMode: 'required', quantity: 5 } ]) const source = parse( readFileSync(new URL('../src/views/m/pl/plan-cert/CertDetail.vue', import.meta.url), 'utf8') ).descriptor.scriptSetup!.content const shared = readFileSync( new URL('../src/composables/usePlPlanViewDetail.ts', import.meta.url), 'utf8' ) const code = declaration(shared, 'mapPlanProductToFormRow') + '\n' + declaration(source, 'stops') const bindings = { computed, plan, products, resolvePlanStopsForList, mapLoadFromApi, mapDeliveriesFromApi, resolveLoadViewAddress, resolveDeliveryViewAddress, resolveStopProductsForView } const stops = new Function( ...Object.keys(bindings), `${ts.transpile(code, { target: ts.ScriptTarget.ESNext })}; return stops` )(...Object.values(bindings)).value assert.deepEqual(stops.load.products[0].mobileProductMeta, loadMeta) assert.deepEqual(stops.deliveries[0].products[0].mobileProductMeta, deliveryMeta) assert.equal(stopProductMeta(stops.deliveries[0].products[0], products.value).aliasName, null) assert.equal(stops.load.products[0].standardProductName, '标准产品') assert.equal(stops.load.products[0].planQty, 0) assert.equal(stops.deliveries[0].products[0].outboundQty, 0) }) test('certificate detail action and teleported preview controls retain 44px targets', () => { const style = readFileSync( new URL('../src/views/m/pl/plan-cert/cert.scss', import.meta.url), 'utf8' ) const actions = style.slice( style.indexOf('.cert-detail-actions {'), style.indexOf('.cert-sheet-content {') ) assert.match(actions, /min-height:\s*44px/) const preview = style.slice(style.indexOf('.el-dialog .preview-toolbar .el-button {')) assert.match(preview, /min-height:\s*44px !important/) assert.match(preview, /min-width:\s*44px !important/) })