更新登录页及优化相关功能
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { test } from 'node:test'
|
||||
import vm from 'node:vm'
|
||||
import * as Vue from 'vue'
|
||||
import { parse } from '@vue/compiler-sfc'
|
||||
import { compile } from '@vue/compiler-dom'
|
||||
import { renderToString } from '@vue/server-renderer'
|
||||
|
||||
const reports = {
|
||||
palletInventory: 'listPalletInventory',
|
||||
consumption: 'listConsumptionReport',
|
||||
return: 'listReturnReport',
|
||||
palletTrace: 'listPalletTrace'
|
||||
}
|
||||
|
||||
async function loadPage(resource, rows = []) {
|
||||
const source = await readFile(new URL(`../src/views/report/${resource}/index.vue`, import.meta.url), 'utf8')
|
||||
const { descriptor } = parse(source)
|
||||
const requests = []
|
||||
const context = vm.createContext({
|
||||
ref: Vue.ref, computed: Vue.computed,
|
||||
getCurrentInstance: () => ({ proxy: { addDateRange: query => query, resetForm() {} } }),
|
||||
onBeforeUnmount() {},
|
||||
[reports[resource]]: async query => {
|
||||
requests.push({ ...query })
|
||||
return { rows, total: rows.length }
|
||||
}
|
||||
})
|
||||
// 执行真实页面脚本,仅替换网络和组件生命周期边界。
|
||||
vm.runInContext(`${descriptor.scriptSetup.content.replace(/^import .*$/gm, '')}
|
||||
globalThis.page = { queryParams, reportList, showSearch, loading, loadError, total, dateRange,
|
||||
handleQuery, resetQuery, getList, handleSizeChange, handleCurrentChange,
|
||||
${resource === 'palletInventory' ? 'flowStateOptions, flowStateLabel, currentLocation, idFallback,' : ''}
|
||||
${resource === 'palletTrace' ? 'eventTypeOptions, eventTypeLabel, sourceLabel, flowStateLabel, formatLocation,' : ''}
|
||||
...(typeof traceSummary === 'undefined' ? {} : { traceSummary })
|
||||
}`, context)
|
||||
await new Promise(resolve => setImmediate(resolve))
|
||||
|
||||
const fields = new Map()
|
||||
const render = new Function('Vue', compile(descriptor.template.content, { mode: 'function', prefixIdentifiers: true }).code)(Vue)
|
||||
async function html() {
|
||||
const app = Vue.createSSRApp({
|
||||
setup: () => ({ ...context.page, parseTime: value => value || '' }),
|
||||
render
|
||||
})
|
||||
app.directive('hasPermi', { getSSRProps: () => ({}) })
|
||||
app.directive('loading', { getSSRProps: () => ({}) })
|
||||
const box = { setup: (_, { slots }) => () => Vue.h('div', slots.default?.()) }
|
||||
for (const name of ['el-form', 'el-row', 'el-select', 'el-option', 'el-button', 'right-toolbar', 'pagination', 'el-date-picker', 'el-empty']) {
|
||||
app.component(name, box)
|
||||
}
|
||||
app.component('el-form-item', {
|
||||
props: ['prop', 'label'],
|
||||
setup(props, { slots }) {
|
||||
Vue.provide('reportField', props.prop)
|
||||
return () => Vue.h('label', { 'data-field': props.prop }, [props.label, slots.default?.()])
|
||||
}
|
||||
})
|
||||
const input = {
|
||||
props: ['modelValue'],
|
||||
setup(props, { attrs }) {
|
||||
fields.set(Vue.inject('reportField'), value => attrs['onUpdate:modelValue'](value))
|
||||
return () => Vue.h('input', { value: props.modelValue })
|
||||
}
|
||||
}
|
||||
app.component('el-input', input)
|
||||
app.component('el-input-number', input)
|
||||
app.component('el-alert', { props: ['title'], setup: props => () => Vue.h('p', props.title) })
|
||||
app.component('el-table', {
|
||||
props: ['data'],
|
||||
setup(props, { slots }) {
|
||||
Vue.provide('reportRows', props.data)
|
||||
return () => Vue.h('div', slots.default?.())
|
||||
}
|
||||
})
|
||||
app.component('el-table-column', {
|
||||
props: ['prop', 'label'],
|
||||
setup(props, { slots }) {
|
||||
const data = Vue.inject('reportRows')
|
||||
return () => Vue.h('section', { 'data-column': props.prop, 'aria-label': props.label },
|
||||
data.map(row => Vue.h('span', slots.default ? slots.default({ row }) : String(row[props.prop] ?? ''))))
|
||||
}
|
||||
})
|
||||
return renderToString(app)
|
||||
}
|
||||
return { page: context.page, requests, fields, html }
|
||||
}
|
||||
|
||||
for (const resource of Object.keys(reports)) {
|
||||
test(`${resource} 页面通过编号、名称和溯源号查询跨托盘明细`, async () => {
|
||||
const report = await loadPage(resource)
|
||||
await report.html()
|
||||
for (const [key, value] of [['tunnelCode', 'T-01'], ['tunnelName', '一号隧道'], ['traceNo', 'TR-MIX']]) {
|
||||
assert.ok(report.fields.has(key), `缺少可操作的 ${key} 输入框`)
|
||||
report.fields.get(key)(value)
|
||||
}
|
||||
if (resource === 'return' || resource === 'palletTrace') {
|
||||
assert.ok(report.fields.has('batchNo'))
|
||||
report.fields.get('batchNo')('B-OLD')
|
||||
}
|
||||
report.page.handleQuery()
|
||||
await new Promise(resolve => setImmediate(resolve))
|
||||
const query = report.requests.at(-1)
|
||||
assert.equal(query.tunnelCode, 'T-01')
|
||||
assert.equal(query.tunnelName, '一号隧道')
|
||||
assert.equal(query.traceNo, 'TR-MIX')
|
||||
assert.equal(query.palletCode, undefined)
|
||||
assert.equal(query.tunnelId, undefined)
|
||||
assert.equal(query.pageNum, 1)
|
||||
})
|
||||
}
|
||||
|
||||
test('消耗页展示隧道且无产线历史记录不显示 #null', async () => {
|
||||
const report = await loadPage('consumption', [{
|
||||
palletCode: 'P-A', tunnelCode: 'T-01', tunnelName: '一号隧道', traceNo: 'TR-MIX',
|
||||
customerId: 1, siteId: 9, strainId: 11,
|
||||
lineId: null, lineName: null, batchNo: 'B-OLD', usedPackages: 30, remainingPackagesAfter: 70
|
||||
}])
|
||||
const html = await report.html()
|
||||
assert.match(html, /T-01/)
|
||||
assert.match(html, /一号隧道/)
|
||||
assert.match(html, /TR-MIX/)
|
||||
assert.doesNotMatch(html, /#null|#undefined/)
|
||||
})
|
||||
|
||||
test('退回页按历史快照展示溯源关系和批次,不需当前库存', async () => {
|
||||
const report = await loadPage('return', [{
|
||||
palletCode: 'P-A', tunnelCode: 'T-OLD', tunnelName: '旧隧道', traceNo: 'TR-OLD',
|
||||
batchNo: 'B-OLD', batchNoSnapshot: 'B-OLD', remainingPackagesSnapshot: 70, status: 'CONFIRMED'
|
||||
}])
|
||||
const html = await report.html()
|
||||
for (const value of ['T-OLD', '旧隧道', 'TR-OLD', 'B-OLD', '70']) assert.ok(html.includes(value), value)
|
||||
})
|
||||
|
||||
test('追溯页跨托盘混批逐笔显示,退回申请和确认不会重复计为使用量', async () => {
|
||||
const common = { tunnelCode: 'T-01', tunnelName: '一号隧道', traceNo: 'TR-MIX', beforeTunnelCode: 'T-01', afterTunnelCode: null }
|
||||
const report = await loadPage('palletTrace', [
|
||||
{ ...common, palletCode: 'P-A', batchNoSnapshot: 'B-A', eventType: 'TUNNEL_ENTERED', usedPackages: 0, returnedPackages: 0 },
|
||||
{ ...common, palletCode: 'P-A', batchNoSnapshot: 'B-A', eventType: 'USAGE_RECORDED', usedPackages: 30, returnedPackages: 0 },
|
||||
{ ...common, palletCode: 'P-B', batchNoSnapshot: 'B-B', eventType: 'USAGE_RECORDED', usedPackages: 20, returnedPackages: 0 },
|
||||
{ ...common, palletCode: 'P-A', batchNoSnapshot: 'B-A', eventType: 'RETURN_REQUESTED', usedPackages: 0, returnedPackages: 0 },
|
||||
{ ...common, palletCode: 'P-A', batchNoSnapshot: 'B-A', eventType: 'RETURN_CONFIRMED', usedPackages: 0, returnedPackages: 70 }
|
||||
])
|
||||
const html = await report.html()
|
||||
assert.match(html, /入隧登记/)
|
||||
assert.doesNotMatch(html, />TUNNEL_ENTERED</)
|
||||
for (const value of ['P-A', 'P-B', 'B-A', 'B-B', 'TR-MIX']) assert.ok(html.includes(value), value)
|
||||
assert.match(html, /本页实际使用 50 包,确认退回 70 包/)
|
||||
})
|
||||
|
||||
test('报表兼容待收货状态与收货确认事件的中文显示', async () => {
|
||||
const inventory = await loadPage('palletInventory', [{ palletCode: 'P-A', flowState: 'IN_TRANSIT' }])
|
||||
const inventoryHtml = await inventory.html()
|
||||
assert.ok(inventoryHtml.includes('待收货'), '库存报表应显示待收货')
|
||||
assert.doesNotMatch(inventoryHtml, />IN_TRANSIT</)
|
||||
|
||||
const trace = await loadPage('palletTrace', [{
|
||||
palletCode: 'P-A', eventType: 'SHIPMENT_RECEIVED', beforeState: 'IN_TRANSIT',
|
||||
afterState: 'AT_SITE_UNUSED', usedPackages: 0, returnedPackages: 0
|
||||
}])
|
||||
const traceHtml = await trace.html()
|
||||
assert.ok(traceHtml.includes('收货确认'), '追溯报表应显示收货确认')
|
||||
assert.ok(traceHtml.includes('待收货'))
|
||||
assert.doesNotMatch(traceHtml, />SHIPMENT_RECEIVED<|>IN_TRANSIT</)
|
||||
assert.match(traceHtml, /本页实际使用 0 包,确认退回 0 包/)
|
||||
})
|
||||
Reference in New Issue
Block a user