优化
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import ts from 'typescript'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { compileStyle, parse } from 'vue/compiler-sfc'
|
||||
|
||||
@@ -38,11 +39,54 @@ const overseasConsumers = [
|
||||
'overseas-warehouse/components/SmartDispatchDialog.vue',
|
||||
'overseas-warehouse/components/DeliveryDocumentsDialog.vue',
|
||||
]
|
||||
const overseasBusinessConsumers = [
|
||||
'overseas-business/pages/PurchaseOrdersView.vue', 'overseas-business/pages/PurchaseOrderDetailView.vue',
|
||||
'overseas-business/pages/PurchaseOrderEditView.vue', 'overseas-business/pages/TransportOrdersView.vue',
|
||||
'overseas-business/pages/TransportOrderFormView.vue',
|
||||
]
|
||||
const customerServiceConsumers = [
|
||||
'overseas-warehouse/pages/ExceptionOrdersView.vue', 'overseas-warehouse/pages/CustomerVisitsView.vue',
|
||||
]
|
||||
const financeConsumers = [
|
||||
'finance/pages/FinanceCustomerAccountsView.vue', 'finance/pages/FinanceCustomerArapView.vue',
|
||||
'finance/pages/FinanceCustomerStatementsView.vue', 'finance/pages/FinanceFormalSettlementPage.vue',
|
||||
'finance/pages/FinanceReceivableStatisticsView.vue',
|
||||
]
|
||||
const generalCatalogConsumers = [
|
||||
'suppliers/pages/SuppliersView.vue',
|
||||
'suppliers/pages/SupplierDetailView.vue',
|
||||
'suppliers/pages/SupplierFormView.vue',
|
||||
'suppliers/components/SupplierLicenseDialog.vue',
|
||||
'overseas-master-data/pages/ExchangeRatesView.vue',
|
||||
'overseas-master-data/pages/OverseasQuotesView.vue',
|
||||
'overseas-master-data/pages/VehiclesView.vue',
|
||||
'overseas-master-data/pages/VehicleDetailView.vue',
|
||||
'master-data/express-companies/pages/ExpressCompaniesView.vue',
|
||||
'master-data/counterparties/pages/PartnersView.vue',
|
||||
'fee-items/pages/FeeItemsView.vue',
|
||||
'warehouses/pages/WarehousesView.vue',
|
||||
'fba-pricing/carrier-rates/pages/CarrierRatesView.vue',
|
||||
'fba-pricing/carrier-rates/pages/CarrierRateDetailView.vue',
|
||||
'downloads/pages/DownloadCenterView.vue',
|
||||
]
|
||||
const notificationConsumers = [
|
||||
'notifications/pages/PlatformNotificationsView.vue', 'notifications/pages/MessageManagementView.vue',
|
||||
'notifications/pages/MessageTemplatesView.vue', 'notifications/components/MessageComposerDialog.vue',
|
||||
'notifications/components/TemplateEditorDialog.vue',
|
||||
]
|
||||
const systemConsumers = ['iam/pages/InternalUsersView.vue', 'iam/pages/RolesView.vue', 'iam/pages/PermissionsView.vue', 'dashboard/pages/DashboardView.vue']
|
||||
const consumers = [
|
||||
...notificationConsumers,
|
||||
...systemConsumers,
|
||||
...generalCatalogConsumers,
|
||||
...financeConsumers,
|
||||
...customerServiceConsumers,
|
||||
...overseasBusinessConsumers,
|
||||
...overseasConsumers,
|
||||
...cargoConsumers,
|
||||
'customers/pages/CustomersView.vue', 'customers/pages/CustomerDetailView.vue',
|
||||
'customers/pages/OverseasStorageFeesView.vue', 'customers/components/CustomerBillingRulesPanel.vue',
|
||||
'unified-orders/components/InboundFeeDetailManager.vue', 'unified-orders/components/OrderDeclarationEditorDialog.vue',
|
||||
'customers/CustomerOverseasStorageFeePanel.vue', 'unified-orders/pages/UnifiedOrdersView.vue',
|
||||
'inbounds/components/InboundTaskList.vue', 'inbounds/measurement/InboundMeasurementDialog.vue',
|
||||
'inbounds/measurement/InboundMeasurementPanel.vue', 'inbounds/review/MeasurementReviewPanel.vue',
|
||||
@@ -53,7 +97,7 @@ const consumers = [
|
||||
'domestic-containers/pages/DomesticContainerInventoryDetailView.vue',
|
||||
'container-loading/components/ContainerSimulationCreate.vue', 'audit/components/CustomerAuditLogsPanel.vue',
|
||||
]
|
||||
const moduleCss = ['customers/customerDensity.css', 'unified-orders/styles/orderDensity.css', 'inbounds/measurement/measurementDensity.css', 'domestic-containers/pages/domesticContainersSummary.css']
|
||||
const moduleCss = ['iam/iamDensity.css', 'finance/financeDensity.css', 'overseas-business/overseasBusinessDensity.css', 'customers/customerDensity.css', 'unified-orders/styles/orderDensity.css', 'inbounds/measurement/measurementDensity.css', 'domestic-containers/pages/domesticContainersSummary.css']
|
||||
const read = (file: string) => readFileSync(resolve(process.cwd(), 'src', file), 'utf8')
|
||||
const domesticPages = [
|
||||
{ title: '订单列表', path: '/orders', file: 'unified-orders/pages/UnifiedOrdersView.vue' },
|
||||
@@ -69,6 +113,12 @@ const customerPages = [
|
||||
{ title: '海外仓阶梯费用', path: '/customers/overseas-storage-fees', file: 'customers/pages/OverseasStorageFeesView.vue' },
|
||||
]
|
||||
const densityPages = [...new Set([
|
||||
...notificationConsumers.filter(file => file.includes('/pages/')),
|
||||
...systemConsumers,
|
||||
...generalCatalogConsumers.filter(file => file.includes('/pages/')),
|
||||
...financeConsumers,
|
||||
...customerServiceConsumers,
|
||||
...overseasBusinessConsumers,
|
||||
...overseasConsumers.filter(file => !file.endsWith('PalletDetailView.vue')),
|
||||
...cargoConsumers.filter(file => file.includes('/pages/') || ['ContainerOverviewPanel.vue', 'ContainerCustomsPanel.vue', 'ContainerLastLegFeesPanel.vue', 'ContainerFeesPanel.vue', 'OceanBookingDocumentsPanel.vue'].some(name => file.endsWith(name))),
|
||||
...domesticPages.map(page => page.file), 'loading-lists/pages/PreloadPlanDetailView.vue',
|
||||
@@ -86,6 +136,7 @@ const classesOf = (node: ElementNode, preload = true, dense = preload, workbench
|
||||
return flatten(value)
|
||||
})
|
||||
const styles = [
|
||||
...parse(read('shared/components/BatchImportDialog.vue')).descriptor.styles.map(style => ({ file: 'BatchImportDialog.vue', css: style.content })),
|
||||
...consumers.flatMap(file => parse(read(`modules/${file}`)).descriptor.styles.map(style => ({ file, css: style.content }))),
|
||||
...moduleCss.map(file => ({ file, css: read(`modules/${file}`) })),
|
||||
]
|
||||
@@ -98,6 +149,78 @@ const cssRoot = (css: string) => {
|
||||
}
|
||||
|
||||
describe('approved Admin density ownership', () => {
|
||||
it('opts application-shell confirmations in even before a business page loads', () => {
|
||||
const entries = ['app/layouts/AppLayout.vue', 'app/components/WorkspaceTabs.vue', 'app/router/index.ts', 'main.ts']
|
||||
let count = 0
|
||||
for (const file of entries) {
|
||||
const source = read(file)
|
||||
expect(source, file).toContain("@/styles/adminDensity.css")
|
||||
const script = file.endsWith('.vue') ? parse(source).descriptor.scriptSetup!.content : source
|
||||
const tree = ts.createSourceFile(file, script, ts.ScriptTarget.Latest, true)
|
||||
const visit = (node: ts.Node) => {
|
||||
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && node.expression.expression.getText(tree) === 'ElMessageBox') {
|
||||
count += 1
|
||||
const options = node.arguments[2]
|
||||
expect(options && ts.isObjectLiteralExpression(options), file).toBe(true)
|
||||
const customClass = options && ts.isObjectLiteralExpression(options) ? options.properties.find(prop => ts.isPropertyAssignment(prop) && prop.name.getText(tree) === 'customClass') : undefined
|
||||
expect(customClass && ts.isPropertyAssignment(customClass) && ts.isStringLiteral(customClass.initializer) && customClass.initializer.text, file).toBe('admin-density-confirm')
|
||||
}
|
||||
ts.forEachChild(node, visit)
|
||||
}
|
||||
visit(tree)
|
||||
}
|
||||
expect(count).toBe(5)
|
||||
})
|
||||
|
||||
|
||||
it('checks dialog roots along actual static and dynamic Vue imports from approved consumers', () => {
|
||||
const pending = consumers.map(file => resolve(process.cwd(), 'src/modules', file))
|
||||
const seen = new Set<string>()
|
||||
while (pending.length) {
|
||||
const file = pending.shift()!
|
||||
if (seen.has(file)) continue
|
||||
seen.add(file)
|
||||
const descriptor = parse(readFileSync(file, 'utf8')).descriptor
|
||||
const enqueue = (reference: string) => {
|
||||
if (!reference.endsWith('.vue')) return
|
||||
if (reference.startsWith('@/')) pending.push(resolve(process.cwd(), 'src', reference.slice(2)))
|
||||
else if (reference.startsWith('.')) pending.push(resolve(dirname(file), reference))
|
||||
}
|
||||
for (const script of [descriptor.script, descriptor.scriptSetup]) {
|
||||
if (!script) continue
|
||||
const ast = ts.createSourceFile(file, script.content, ts.ScriptTarget.Latest, true)
|
||||
const visitImports = (node: ts.Node) => {
|
||||
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && node.expression.expression.getText(ast) === 'ElMessageBox') {
|
||||
expect(node.arguments[2]?.getText(ast), file + ': reachable confirmation').toContain('admin-density-confirm')
|
||||
}
|
||||
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) enqueue(node.moduleSpecifier.text)
|
||||
if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
|
||||
const reference = node.arguments[0]
|
||||
if (reference && ts.isStringLiteral(reference)) enqueue(reference.text)
|
||||
}
|
||||
ts.forEachChild(node, visitImports)
|
||||
}
|
||||
visitImports(ast)
|
||||
}
|
||||
if (['AppDialog.vue', 'AppDrawer.vue', 'BatchImportDialog.vue'].some(name => file.endsWith(name))) continue
|
||||
const visitTemplate = (nodes: TemplateNode[]) => {
|
||||
for (const node of nodes) {
|
||||
if (node.type !== 1) continue
|
||||
if (['AppDialog', 'el-dialog', 'BatchImportDialog'].includes(node.tag)) expect(classesOf(node), `${file}: reachable modal`).toContain('admin-density-dialog')
|
||||
if (['AppDrawer', 'el-drawer'].includes(node.tag)) expect(classesOf(node), `${file}: reachable drawer`).toContain('admin-density-drawer')
|
||||
visitTemplate(node.children)
|
||||
}
|
||||
}
|
||||
if (descriptor.template?.ast) visitTemplate(descriptor.template.ast.children)
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps the supplier license dialog styled at its own teleported root', () => {
|
||||
const source = read('modules/suppliers/components/SupplierLicenseDialog.vue')
|
||||
expect(source).toContain('<AppDialog class="admin-density-dialog"')
|
||||
expect(source).toContain('width="min(560px, calc(100vw - 24px))"')
|
||||
expect(source).toContain('aria-label="营业执照信息"')
|
||||
})
|
||||
|
||||
it('uses identical authored tab paint for native domestic and Element overseas tabs', () => {
|
||||
const element = '.admin-density .density-element-tabs > .el-tabs__header .el-tabs__nav .el-tabs__item'
|
||||
@@ -321,6 +444,7 @@ describe('approved Admin density ownership', () => {
|
||||
|
||||
it('prevents page copies of action paint, tab primitives and desktop density dimensions', () => {
|
||||
for (const { file, css } of styles) cssRoot(css).walkRules(rule => {
|
||||
expect(rule.selector.trim(), file + ': empty selector').not.toBe('')
|
||||
expect(rule.selector, file).not.toMatch(/customer-action-button|order-action-button|\.density-action|\.density-tab-icon/)
|
||||
let desktop = true
|
||||
for (let parent: typeof rule.parent | ReturnType<typeof cssRoot>['parent'] = rule.parent; parent; parent = parent.parent) {
|
||||
|
||||
Reference in New Issue
Block a user