feat(order-service): 增加提交资料确认与核对摘要
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
-- 134_order_service_material_confirmation.sql
|
||||
-- 客户提交资料前的确认弹窗配置;同时移除已废弃的页面公告字段。
|
||||
|
||||
ALTER TABLE order_service_profiles
|
||||
ADD COLUMN IF NOT EXISTS material_confirmation_json JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
DROP COLUMN IF EXISTS announcement_json;
|
||||
|
||||
COMMENT ON COLUMN order_service_profiles.material_confirmation_json IS
|
||||
'提交资料确认:enabled/title/content/confirmText/cancelText';
|
||||
@@ -12,7 +12,7 @@ export type OrderServiceProfileRow = {
|
||||
fields_json: Array<Record<string, unknown>>
|
||||
screenshots_json: Record<string, unknown>
|
||||
auto_publish_json: Record<string, unknown>
|
||||
announcement_json: Record<string, unknown>
|
||||
material_confirmation_json: Record<string, unknown>
|
||||
submit_text: string
|
||||
success_text: string
|
||||
status: string
|
||||
@@ -99,7 +99,7 @@ export async function upsertOrderServiceProfile(input: {
|
||||
fields: Array<Record<string, unknown>>
|
||||
screenshots: Record<string, unknown>
|
||||
autoPublish: Record<string, unknown>
|
||||
announcement: Record<string, unknown>
|
||||
materialConfirmation: Record<string, unknown>
|
||||
submitText: string
|
||||
successText: string
|
||||
adminUserId: number | null
|
||||
@@ -108,7 +108,8 @@ export async function upsertOrderServiceProfile(input: {
|
||||
`
|
||||
INSERT INTO order_service_profiles (
|
||||
category_id, name, title, description,
|
||||
guide_image_json, fields_json, screenshots_json, auto_publish_json, announcement_json,
|
||||
guide_image_json, fields_json, screenshots_json, auto_publish_json,
|
||||
material_confirmation_json,
|
||||
submit_text, success_text, status, created_by_admin_user_id
|
||||
) VALUES (
|
||||
$1, $2, $3, $4,
|
||||
@@ -123,7 +124,7 @@ export async function upsertOrderServiceProfile(input: {
|
||||
fields_json = EXCLUDED.fields_json,
|
||||
screenshots_json = EXCLUDED.screenshots_json,
|
||||
auto_publish_json = EXCLUDED.auto_publish_json,
|
||||
announcement_json = EXCLUDED.announcement_json,
|
||||
material_confirmation_json = EXCLUDED.material_confirmation_json,
|
||||
submit_text = EXCLUDED.submit_text,
|
||||
success_text = EXCLUDED.success_text,
|
||||
current_version_id = CASE
|
||||
@@ -143,7 +144,7 @@ export async function upsertOrderServiceProfile(input: {
|
||||
JSON.stringify(input.fields),
|
||||
JSON.stringify(input.screenshots),
|
||||
JSON.stringify(input.autoPublish),
|
||||
JSON.stringify(input.announcement),
|
||||
JSON.stringify(input.materialConfirmation),
|
||||
input.submitText,
|
||||
input.successText,
|
||||
input.adminUserId,
|
||||
|
||||
@@ -78,41 +78,33 @@ test('订单服务配置规范化:未知字段类型降级为文本,空下
|
||||
assert.equal(normalized.fields[0]?.type, 'text')
|
||||
})
|
||||
|
||||
test('订单服务页面公告:旧配置默认展示资料填写错误免责声明', () => {
|
||||
test('订单服务提交确认:旧配置默认展示不可修改与资料错误免责声明', () => {
|
||||
const normalized = config()
|
||||
assert.deepEqual(normalized.announcement, {
|
||||
assert.deepEqual(normalized.materialConfirmation, {
|
||||
enabled: true,
|
||||
title: '公告',
|
||||
content: '由于个人资料填写错误,导致的赠送错误,店铺概不负责!',
|
||||
fontSize: 14,
|
||||
color: '#8a4b00',
|
||||
backgroundColor: '#fff7e6',
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'left',
|
||||
title: '提交资料确认',
|
||||
content:
|
||||
'请确认资料填写准确无误。资料提交后不能修改,因个人资料填写错误导致的赠送错误,店铺概不负责!',
|
||||
confirmText: '确认提交',
|
||||
cancelText: '返回检查',
|
||||
})
|
||||
})
|
||||
|
||||
test('订单服务页面公告:支持自定义样式并拦截非法颜色与越界字号', () => {
|
||||
test('订单服务提交确认:支持自定义标题、正文和按钮文字', () => {
|
||||
const normalized = config({
|
||||
announcement: {
|
||||
materialConfirmation: {
|
||||
enabled: false,
|
||||
title: '填写前必看',
|
||||
content: '请确认资料无误后再提交。',
|
||||
fontSize: 99,
|
||||
color: 'red;position:fixed',
|
||||
backgroundColor: '#123456',
|
||||
fontWeight: 'normal',
|
||||
textAlign: 'center',
|
||||
title: '请再次核对',
|
||||
content: '提交后无法修改,请返回检查。',
|
||||
confirmText: '确认无误',
|
||||
cancelText: '再检查一下',
|
||||
},
|
||||
})
|
||||
assert.deepEqual(normalized.announcement, {
|
||||
assert.deepEqual(normalized.materialConfirmation, {
|
||||
enabled: false,
|
||||
title: '填写前必看',
|
||||
content: '请确认资料无误后再提交。',
|
||||
fontSize: 24,
|
||||
color: '#8a4b00',
|
||||
backgroundColor: '#123456',
|
||||
fontWeight: 'normal',
|
||||
textAlign: 'center',
|
||||
title: '请再次核对',
|
||||
content: '提交后无法修改,请返回检查。',
|
||||
confirmText: '确认无误',
|
||||
cancelText: '再检查一下',
|
||||
})
|
||||
})
|
||||
|
||||
@@ -47,15 +47,12 @@ export type OrderServiceAutoPublish = {
|
||||
retryMax: number
|
||||
}
|
||||
|
||||
export type OrderServiceAnnouncement = {
|
||||
export type OrderServiceMaterialConfirmation = {
|
||||
enabled: boolean
|
||||
title: string
|
||||
content: string
|
||||
fontSize: number
|
||||
color: string
|
||||
backgroundColor: string
|
||||
fontWeight: 'normal' | 'bold'
|
||||
textAlign: 'left' | 'center'
|
||||
confirmText: string
|
||||
cancelText: string
|
||||
}
|
||||
|
||||
export type OrderServiceProfileConfig = {
|
||||
@@ -66,7 +63,7 @@ export type OrderServiceProfileConfig = {
|
||||
fields: OrderServiceField[]
|
||||
screenshots: OrderServiceScreenshots
|
||||
autoPublish: OrderServiceAutoPublish
|
||||
announcement: OrderServiceAnnouncement
|
||||
materialConfirmation: OrderServiceMaterialConfirmation
|
||||
submitText: string
|
||||
successText: string
|
||||
}
|
||||
@@ -88,15 +85,13 @@ const FIELD_TYPES = new Set<OrderServiceFieldType>([
|
||||
'date',
|
||||
])
|
||||
|
||||
export const DEFAULT_ORDER_SERVICE_ANNOUNCEMENT: OrderServiceAnnouncement = {
|
||||
export const DEFAULT_ORDER_SERVICE_MATERIAL_CONFIRMATION: OrderServiceMaterialConfirmation = {
|
||||
enabled: true,
|
||||
title: '公告',
|
||||
content: '由于个人资料填写错误,导致的赠送错误,店铺概不负责!',
|
||||
fontSize: 14,
|
||||
color: '#8a4b00',
|
||||
backgroundColor: '#fff7e6',
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'left',
|
||||
title: '提交资料确认',
|
||||
content:
|
||||
'请确认资料填写准确无误。资料提交后不能修改,因个人资料填写错误导致的赠送错误,店铺概不负责!',
|
||||
confirmText: '确认提交',
|
||||
cancelText: '返回检查',
|
||||
}
|
||||
|
||||
export async function listAdminOrderServiceProfiles() {
|
||||
@@ -138,7 +133,9 @@ export async function saveAdminOrderServiceProfile(payload: JsonObject = {}) {
|
||||
const fields = normalizeFields(payload.fields ?? payload.fields_json)
|
||||
const screenshots = normalizeScreenshots(payload.screenshots ?? payload.screenshots_json)
|
||||
const autoPublish = normalizeAutoPublish(payload.autoPublish ?? payload.auto_publish_json)
|
||||
const announcement = normalizeAnnouncement(payload.announcement ?? payload.announcement_json)
|
||||
const materialConfirmation = normalizeMaterialConfirmation(
|
||||
payload.materialConfirmation ?? payload.material_confirmation_json,
|
||||
)
|
||||
const guideImage = normalizeGuideImage(payload.guideImage ?? payload.guide_image_json)
|
||||
const adminUserId = Number(payload.adminUserId ?? payload.admin_user_id ?? 0) || null
|
||||
|
||||
@@ -151,7 +148,7 @@ export async function saveAdminOrderServiceProfile(payload: JsonObject = {}) {
|
||||
fields,
|
||||
screenshots,
|
||||
autoPublish,
|
||||
announcement,
|
||||
materialConfirmation,
|
||||
submitText: text(payload.submitText, 30) || '提交资料',
|
||||
successText: text(payload.successText, 80) || '资料已提交,请等待处理',
|
||||
adminUserId,
|
||||
@@ -229,7 +226,7 @@ function mapAdminProfile(row: OrderServiceProfileRow) {
|
||||
fields: row.fields_json,
|
||||
screenshots: row.screenshots_json,
|
||||
autoPublish: row.auto_publish_json,
|
||||
announcement: normalizeAnnouncement(row.announcement_json),
|
||||
materialConfirmation: normalizeMaterialConfirmation(row.material_confirmation_json),
|
||||
submitText: row.submit_text,
|
||||
successText: row.success_text,
|
||||
status: row.status,
|
||||
@@ -248,7 +245,7 @@ export function buildProfileConfig(row: {
|
||||
fields_json: unknown
|
||||
screenshots_json: unknown
|
||||
auto_publish_json: unknown
|
||||
announcement_json: unknown
|
||||
material_confirmation_json: unknown
|
||||
submit_text: string
|
||||
success_text: string
|
||||
}): OrderServiceProfileConfig & { guideImage: Record<string, unknown> } {
|
||||
@@ -260,7 +257,7 @@ export function buildProfileConfig(row: {
|
||||
fields: normalizeFields(row.fields_json),
|
||||
screenshots: normalizeScreenshots(row.screenshots_json),
|
||||
autoPublish: normalizeAutoPublish(row.auto_publish_json),
|
||||
announcement: normalizeAnnouncement(row.announcement_json),
|
||||
materialConfirmation: normalizeMaterialConfirmation(row.material_confirmation_json),
|
||||
submitText: row.submit_text || '提交资料',
|
||||
successText: row.success_text || '资料已提交,请等待处理',
|
||||
}
|
||||
@@ -312,7 +309,7 @@ export function normalizeProfileConfig(value: JsonObject): OrderServiceProfileCo
|
||||
fields: normalizeFields(value.fields),
|
||||
screenshots: normalizeScreenshots(value.screenshots),
|
||||
autoPublish: normalizeAutoPublish(value.autoPublish),
|
||||
announcement: normalizeAnnouncement(value.announcement),
|
||||
materialConfirmation: normalizeMaterialConfirmation(value.materialConfirmation),
|
||||
submitText: text(value.submitText, 30) || '提交资料',
|
||||
successText: text(value.successText, 80) || '资料已提交,请等待处理',
|
||||
}
|
||||
@@ -391,25 +388,18 @@ function normalizeAutoPublish(value: unknown): OrderServiceAutoPublish {
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeAnnouncement(value: unknown): OrderServiceAnnouncement {
|
||||
function normalizeMaterialConfirmation(value: unknown): OrderServiceMaterialConfirmation {
|
||||
const source = value && typeof value === 'object' ? (value as JsonObject) : {}
|
||||
return {
|
||||
enabled: source.enabled !== false,
|
||||
title: text(source.title, 30) || DEFAULT_ORDER_SERVICE_ANNOUNCEMENT.title,
|
||||
content: text(source.content, 500) || DEFAULT_ORDER_SERVICE_ANNOUNCEMENT.content,
|
||||
fontSize: clampInteger(source.fontSize ?? source.font_size, 14, 12, 24),
|
||||
color: normalizeHexColor(source.color, DEFAULT_ORDER_SERVICE_ANNOUNCEMENT.color),
|
||||
backgroundColor: normalizeHexColor(
|
||||
source.backgroundColor ?? source.background_color,
|
||||
DEFAULT_ORDER_SERVICE_ANNOUNCEMENT.backgroundColor,
|
||||
),
|
||||
fontWeight:
|
||||
source.fontWeight === 'normal' || source.font_weight === 'normal'
|
||||
? 'normal'
|
||||
: source.fontWeight === 'bold' || source.font_weight === 'bold'
|
||||
? 'bold'
|
||||
: DEFAULT_ORDER_SERVICE_ANNOUNCEMENT.fontWeight,
|
||||
textAlign: source.textAlign === 'center' || source.text_align === 'center' ? 'center' : 'left',
|
||||
title: text(source.title, 40) || DEFAULT_ORDER_SERVICE_MATERIAL_CONFIRMATION.title,
|
||||
content: text(source.content, 500) || DEFAULT_ORDER_SERVICE_MATERIAL_CONFIRMATION.content,
|
||||
confirmText:
|
||||
text(source.confirmText ?? source.confirm_text, 12) ||
|
||||
DEFAULT_ORDER_SERVICE_MATERIAL_CONFIRMATION.confirmText,
|
||||
cancelText:
|
||||
text(source.cancelText ?? source.cancel_text, 12) ||
|
||||
DEFAULT_ORDER_SERVICE_MATERIAL_CONFIRMATION.cancelText,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,11 +408,6 @@ function normalizeGuideImage(value: unknown): Record<string, unknown> {
|
||||
return normalized ? { ...normalized } : {}
|
||||
}
|
||||
|
||||
function normalizeHexColor(value: unknown, fallback: string) {
|
||||
const normalized = text(value, 7)
|
||||
return /^#[0-9a-fA-F]{6}$/.test(normalized) ? normalized.toLowerCase() : fallback
|
||||
}
|
||||
|
||||
function clampInteger(value: unknown, fallback: number, min: number, max: number) {
|
||||
const parsed = Number(value)
|
||||
if (!Number.isFinite(parsed)) return fallback
|
||||
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
throwPublicMaterialBlocked,
|
||||
} from './work-order-material-link-service.js'
|
||||
import {
|
||||
DEFAULT_ORDER_SERVICE_ANNOUNCEMENT,
|
||||
DEFAULT_ORDER_SERVICE_MATERIAL_CONFIRMATION,
|
||||
getOrderServiceProfileSnapshotByVersion,
|
||||
normalizeProfileConfig,
|
||||
type OrderServiceField,
|
||||
@@ -78,7 +78,7 @@ export type OrderServicePublicItem = {
|
||||
message: string
|
||||
canSubmit: boolean
|
||||
blockedReason: string
|
||||
announcement?: OrderServiceProfileConfig['announcement']
|
||||
materialConfirmation?: OrderServiceProfileConfig['materialConfirmation']
|
||||
fields?: OrderServiceField[]
|
||||
values?: Record<string, string>
|
||||
screenshots?: Array<Record<string, unknown>>
|
||||
@@ -371,7 +371,9 @@ async function mapPublicOrderItem(order: WorkOrderRow): Promise<OrderServicePubl
|
||||
}),
|
||||
canSubmit: state.canSubmit,
|
||||
blockedReason: state.blockedReason,
|
||||
...(profile?.announcement ? { announcement: profile.announcement } : {}),
|
||||
...(profile?.materialConfirmation
|
||||
? { materialConfirmation: profile.materialConfirmation }
|
||||
: {}),
|
||||
}
|
||||
|
||||
if (!state.canSubmit) return base
|
||||
@@ -429,7 +431,7 @@ async function resolveProfileConfig(
|
||||
helpText: '',
|
||||
},
|
||||
autoPublish: { enabled: false, requireVoucherConsume: true, retryMax: 3 },
|
||||
announcement: DEFAULT_ORDER_SERVICE_ANNOUNCEMENT,
|
||||
materialConfirmation: DEFAULT_ORDER_SERVICE_MATERIAL_CONFIRMATION,
|
||||
submitText: '提交资料',
|
||||
successText: '资料已提交,请等待处理',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user