| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- import assert from 'node:assert/strict'
- import { readFile } from 'node:fs/promises'
- const root = new URL('../src/views/m/crm/customer/', import.meta.url)
- const [list, detail, filters, attachments, fields, styles] = await Promise.all([
- readFile(new URL('index.vue', root), 'utf8'),
- readFile(new URL('detail.vue', root), 'utf8'),
- readFile(new URL('CustomerFilters.vue', root), 'utf8'),
- readFile(new URL('CustomerAttachments.vue', root), 'utf8'),
- readFile(new URL('CustomerFields.vue', root), 'utf8'),
- readFile(new URL('customer.scss', root), 'utf8')
- ])
- for (const component of [
- 'MpBusinessHeader',
- 'MpStatusTabs',
- 'MpThreeColumnFilters',
- 'MpExpenseCard'
- ]) {
- assert.match(list, new RegExp(`<${component}\\b`), `客户列表应使用 ${component}`)
- }
- const headerAt = list.indexOf('<MpBusinessHeader')
- const tabsAt = list.indexOf('<MpStatusTabs')
- const filtersAt = list.indexOf('<MpThreeColumnFilters')
- const cardAt = list.indexOf('<MpExpenseCard')
- assert.ok(headerAt >= 0 && headerAt < tabsAt && tabsAt < filtersAt && filtersAt < cardAt)
- assert.doesNotMatch(
- list,
- /class="mp-customer-actions"[\s\S]*+ 新增[\s\S]*筛选[\s\S]*显示[\s\S]*刷新/
- )
- assert.match(list, /class="mp-wv-speed-dial"/)
- assert.match(list, /class="mp-customer-batch-bar"/)
- assert.match(list, /requestSnapshot/)
- assert.match(list, /onKeywordUpdate/)
- assert.match(list, /customerTypeIn/)
- assert.match(list, /levelIn/)
- assert.match(list, /:show-actions="!selectMode"/, '选择模式必须隐藏卡片动作栏')
- assert.match(list, /rows\.value = \[\]/, 'reset 请求必须先清空旧列表')
- assert.match(list, /total\.value = 0/, 'reset 请求必须先清空旧总数')
- assert.match(list, /selected\.value = \[\]/, 'reset 请求必须先清空旧选择')
- assert.match(list, /customerCardTime\(row\)/, '客户卡时间必须支持 lastTime/createTime 回退')
- assert.match(detail, /<MpBusinessHeader\s+title="客户详情"/)
- assert.doesNotMatch(detail, /mp-wv-header__sub/)
- for (const label of ['资料', '跟进记录', '联系人', '商机', '合同', '开票信息', '操作日志']) {
- assert.ok(detail.includes(label), `详情应保留 ${label} Tab`)
- }
- assert.match(detail, /mp-customer-detail-tabs/)
- assert.match(detail, /watch\(/, '详情必须监听复用路由变化')
- assert.match(detail, /route\.params\.id/, '详情必须监听客户 ID')
- assert.match(detail, /route\.query\.tab/, '详情必须监听 query tab')
- assert.match(detail, /requestSeq/, '详情必须隔离过期请求')
- assert.match(detail, /requestedId/, '详情应用响应前必须核对请求客户 ID')
- assert.match(filters, />关键词</, 'More 面板必须展示并回写顶部关键词')
- assert.match(filters, />业务视图</, 'More 面板必须展示四个业务视图')
- assert.match(filters, /keyword:\s*keyword\.trim\(\)/, 'facet 请求必须传递服务端关键词')
- assert.match(filters, /facets\.value = \{\}/, '筛选上下文变化必须清空 facet')
- assert.match(filters, /facetContextVersion/, '筛选上下文变化必须隔离旧 facet 响应')
- assert.match(attachments, /<MpAttachmentGrid\b/)
- assert.match(attachments, /type="file"/)
- assert.match(attachments, /:disabled="uploading > 0"/, '上传期间必须禁止再次选择文件')
- assert.match(attachments, /if \(uploading\.value > 0\)/, '上传处理器必须拒绝并发选择')
- assert.match(
- attachments,
- /existing\.push\(url\)[\s\S]*emit\('update:modelValue', existing\.join\(','\)\)/,
- '每个文件成功后必须立即保留并提交引用'
- )
- assert.match(attachments, /ElMessage\.error\(/, '后续文件上传失败必须给出反馈')
- assert.doesNotMatch(fields, /<el-tag\b/, 'WebView 详情字典与状态不得使用桌面深色标签')
- assert.match(fields, /mp-customer-webview-tag/, 'WebView 详情字典与状态必须使用浅底标签')
- assert.match(styles, /\.mp-customer-batch-bar/)
- assert.match(styles, /min-height:\s*44px/)
- assert.match(styles, /\.mp-customer-webview-tag/)
- console.log('customer DOM contract: PASS')
|