Просмотр исходного кода

feat(web-admin): add product confirm dialog option builder for scheme A/B.

Co-authored-by: Cursor <cursoragent@cursor.com>
wuzilong 3 недель назад
Родитель
Сommit
6821cd6a03

+ 56 - 0
web-admin/src/utils/mp-crm-product-confirm.test.ts

@@ -0,0 +1,56 @@
+import assert from 'node:assert/strict'
+import { describe, it } from 'node:test'
+import { buildProductConfirmOptions } from './mp-crm-product-confirm'
+
+describe('buildProductConfirmOptions', () => {
+  it('builds scheme A for non-delete confirms', () => {
+    const opts = buildProductConfirmOptions({
+      kind: 'default',
+      title: '下架产品',
+      message: '确认下架该产品?'
+    })
+    assert.equal(opts.title, '下架产品')
+    assert.equal(opts.message, '确认下架该产品?')
+    assert.equal(opts.allowHtml, false)
+    assert.equal(opts.className, 'mp-product-dialog')
+    assert.equal(opts.confirmButtonText, '确认')
+    assert.equal(opts.confirmButtonColor, '#0a9f6d')
+    assert.equal(opts.theme, undefined)
+  })
+
+  it('builds scheme B for delete confirms with warn html', () => {
+    const opts = buildProductConfirmOptions({
+      kind: 'danger',
+      title: '删除产品',
+      message: '确认删除该产品?删除后不可恢复。'
+    })
+    assert.equal(opts.title, '删除产品')
+    assert.equal(opts.allowHtml, true)
+    assert.equal(opts.className, 'mp-product-dialog mp-product-dialog--danger')
+    assert.equal(opts.confirmButtonText, '确认删除')
+    assert.equal(opts.confirmButtonColor, '#dc2626')
+    assert.match(String(opts.message), /mp-product-dialog__warn/)
+    assert.match(String(opts.message), /确认删除该产品?删除后不可恢复。/)
+    assert.doesNotMatch(String(opts.message), /<script/)
+    assert.equal(opts.theme, undefined)
+  })
+
+  it('escapes html in danger message body', () => {
+    const opts = buildProductConfirmOptions({
+      kind: 'danger',
+      title: '删除产品',
+      message: 'a <b>x</b> & "y"'
+    })
+    assert.match(String(opts.message), /a &lt;b&gt;x&lt;\/b&gt; &amp; &quot;y&quot;/)
+  })
+
+  it('allows override confirmButtonText', () => {
+    const opts = buildProductConfirmOptions({
+      kind: 'default',
+      title: '上架产品',
+      message: '确认上架该产品?',
+      confirmButtonText: '立即上架'
+    })
+    assert.equal(opts.confirmButtonText, '立即上架')
+  })
+})

+ 42 - 0
web-admin/src/utils/mp-crm-product-confirm.ts

@@ -0,0 +1,42 @@
+import { showConfirmDialog, type DialogOptions } from 'vant'
+
+export type ProductConfirmKind = 'default' | 'danger'
+
+export type BuildProductConfirmInput = {
+  kind: ProductConfirmKind
+  title: string
+  message: string
+  confirmButtonText?: string
+}
+
+function escapeHtml(text: string): string {
+  return text
+    .replace(/&/g, '&amp;')
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;')
+    .replace(/"/g, '&quot;')
+    .replace(/'/g, '&#39;')
+}
+
+function dangerMessageHtml(message: string): string {
+  return (
+    `<div class="mp-product-dialog__warn"><span class="mp-product-dialog__warn-icon">!</span></div>` +
+    `<div class="mp-product-dialog__msg">${escapeHtml(message)}</div>`
+  )
+}
+
+export function buildProductConfirmOptions(input: BuildProductConfirmInput): DialogOptions {
+  const isDanger = input.kind === 'danger'
+  return {
+    title: input.title,
+    message: isDanger ? dangerMessageHtml(input.message) : input.message,
+    allowHtml: isDanger,
+    className: isDanger ? 'mp-product-dialog mp-product-dialog--danger' : 'mp-product-dialog',
+    confirmButtonText: input.confirmButtonText ?? (isDanger ? '确认删除' : '确认'),
+    confirmButtonColor: isDanger ? '#dc2626' : '#0a9f6d'
+  }
+}
+
+export function showProductConfirmDialog(input: BuildProductConfirmInput) {
+  return showConfirmDialog(buildProductConfirmOptions(input))
+}