mirror of
https://gitee.com/ShopeX/ECShopX_admin-frontend
synced 2026-08-04 20:16:22 +08:00
Merge branch 'agent/fs/lzm-110-template-i18n-save' into 'main'
LZM-110: stabilize pc decoration i18n save row See merge request ecshopx/ecshopx-admin!5
This commit is contained in:
272
scripts/check-template-i18n-save-payload.mjs
Normal file
272
scripts/check-template-i18n-save-payload.mjs
Normal file
@@ -0,0 +1,272 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import vm from 'node:vm'
|
||||
|
||||
const ROOT = process.cwd()
|
||||
|
||||
function cloneValue(value) {
|
||||
return JSON.parse(JSON.stringify(value))
|
||||
}
|
||||
|
||||
function loadApiPersistence({ getDecorationContent, saveTemplateContent, saveHeaderOrFooter }) {
|
||||
const filename = path.resolve(ROOT, 'src/components/sp-web-decoration/adapters/apiPersistence.js')
|
||||
let source = readFileSync(filename, 'utf8')
|
||||
source = source
|
||||
.replace(/import[\s\S]*?from '\.\.\/definitions\/documents\/global\.js'\n/, '')
|
||||
.replace(/export default[\s\S]*$/, '')
|
||||
.replace(/\bexport\s+(async function|function|const)\s+/g, '$1 ')
|
||||
|
||||
const exports = {}
|
||||
source += `
|
||||
exports.DSL_ROW_TYPE = DSL_ROW_TYPE;
|
||||
exports.DEFAULT_COUNTRY_CODE = typeof DEFAULT_COUNTRY_CODE === 'undefined' ? undefined : DEFAULT_COUNTRY_CODE;
|
||||
exports.buildPageContentPayload = typeof buildPageContentPayload === 'undefined' ? undefined : buildPageContentPayload;
|
||||
exports.parsePageDslRows = typeof parsePageDslRows === 'undefined' ? undefined : parsePageDslRows;
|
||||
exports.getCurrentCountryCode = typeof getCurrentCountryCode === 'undefined' ? undefined : getCurrentCountryCode;
|
||||
exports.savePageDslToApi = savePageDslToApi;
|
||||
exports.saveHeaderDslToApi = saveHeaderDslToApi;
|
||||
exports.saveFooterDslToApi = saveFooterDslToApi;
|
||||
`
|
||||
|
||||
const context = {
|
||||
exports,
|
||||
console,
|
||||
window: {
|
||||
localStorage: {
|
||||
getItem: (key) => (key === 'lang' ? 'en' : null)
|
||||
}
|
||||
},
|
||||
getDecorationContent,
|
||||
saveTemplateContent,
|
||||
saveHeaderOrFooter,
|
||||
createHomeDsl: ({ pageId = '', scene = '1001' } = {}) => ({
|
||||
pageType: 'home',
|
||||
pageId,
|
||||
scene,
|
||||
sections: {},
|
||||
order: []
|
||||
}),
|
||||
createCustomDsl: ({ pageId = '', scene = '1001' } = {}) => ({
|
||||
pageType: 'custom',
|
||||
pageId,
|
||||
scene,
|
||||
sections: {},
|
||||
order: []
|
||||
}),
|
||||
createProductListDsl: ({ pageId = '', scene = '1001' } = {}) => ({
|
||||
pageType: 'product_list',
|
||||
pageId,
|
||||
scene,
|
||||
sections: {},
|
||||
order: []
|
||||
}),
|
||||
createGlobalDsl: () => ({ pageType: 'global', pageId: 'global', sections: {}, order: [] }),
|
||||
createHeaderDsl: () => ({ pageType: 'header', pageId: 'header', sections: {}, order: [] }),
|
||||
createFooterDsl: () => ({ pageType: 'footer', pageId: 'footer', sections: {}, order: [] }),
|
||||
createGlobalSections: () => ({}),
|
||||
ensureGlobalDslDefaults: (dsl) => dsl,
|
||||
splitGlobalDsl: (dsl) => ({ headerDsl: dsl, footerDsl: dsl }),
|
||||
serializeDsl: cloneValue,
|
||||
deserializeDsl: cloneValue
|
||||
}
|
||||
vm.createContext(context)
|
||||
vm.runInContext(source, context, { filename })
|
||||
return exports
|
||||
}
|
||||
|
||||
function loadRequestClient() {
|
||||
const filename = path.resolve(ROOT, 'src/api/request/request.js')
|
||||
let source = readFileSync(filename, 'utf8')
|
||||
source = source
|
||||
.replace(/import axios from 'axios'\n/, '')
|
||||
.replace(/import \{ merge, bindMethods \} from '@\/utils'\n/, '')
|
||||
.replace(/import \{ InterceptorManager \} from '\.\/interceptor'\n/, '')
|
||||
.replace(/export \{ RequestClient \ }/, 'exports.RequestClient = RequestClient')
|
||||
.replace(/export \{ RequestClient \}/, 'exports.RequestClient = RequestClient')
|
||||
|
||||
const exports = {}
|
||||
let lastRequest = null
|
||||
const context = {
|
||||
exports,
|
||||
window: {
|
||||
localStorage: {
|
||||
getItem: (key) => (key === 'lang' ? 'en' : null)
|
||||
}
|
||||
},
|
||||
axios: {
|
||||
create: () => ({
|
||||
request: async (config) => {
|
||||
lastRequest = config
|
||||
return { data: {}, config }
|
||||
}
|
||||
})
|
||||
},
|
||||
InterceptorManager: class {
|
||||
constructor(instance) {
|
||||
this.instance = instance
|
||||
}
|
||||
addRequestInterceptor() {}
|
||||
addResponseInterceptor() {}
|
||||
}
|
||||
}
|
||||
vm.createContext(context)
|
||||
vm.runInContext(source, context, { filename })
|
||||
return {
|
||||
RequestClient: exports.RequestClient,
|
||||
getLastRequest: () => lastRequest
|
||||
}
|
||||
}
|
||||
|
||||
const sampleDsl = {
|
||||
pageType: 'home',
|
||||
pageId: '140',
|
||||
sections: {
|
||||
hero: {
|
||||
id: 'hero',
|
||||
type: 'main-carousel',
|
||||
settings: {},
|
||||
blocks: {},
|
||||
blockOrder: []
|
||||
}
|
||||
},
|
||||
order: ['hero']
|
||||
}
|
||||
|
||||
{
|
||||
const api = loadApiPersistence({
|
||||
getDecorationContent: async () => [],
|
||||
saveTemplateContent: async () => {},
|
||||
saveHeaderOrFooter: async () => {}
|
||||
})
|
||||
|
||||
assert.equal(typeof api.buildPageContentPayload, 'function')
|
||||
const payload = api.buildPageContentPayload({
|
||||
normalizedDsl: sampleDsl,
|
||||
contentRowId: 7084
|
||||
})
|
||||
assert.equal(payload.id, 7084)
|
||||
assert.equal(payload.type, api.DSL_ROW_TYPE)
|
||||
assert.equal(payload.pageType, 'home')
|
||||
assert.equal(payload.pageId, '140')
|
||||
assert.deepEqual(payload.order, ['hero'])
|
||||
assert.ok(payload.sections.hero)
|
||||
assert.equal(Object.hasOwn(payload, 'dsl'), false)
|
||||
}
|
||||
|
||||
{
|
||||
const api = loadApiPersistence({
|
||||
getDecorationContent: async () => [],
|
||||
saveTemplateContent: async () => {},
|
||||
saveHeaderOrFooter: async () => {}
|
||||
})
|
||||
|
||||
assert.equal(typeof api.parsePageDslRows, 'function')
|
||||
const result = api.parsePageDslRows(
|
||||
[
|
||||
{
|
||||
id: 7084,
|
||||
config: JSON.stringify([
|
||||
{
|
||||
type: api.DSL_ROW_TYPE,
|
||||
...sampleDsl
|
||||
}
|
||||
])
|
||||
}
|
||||
],
|
||||
140,
|
||||
'1001',
|
||||
'home'
|
||||
)
|
||||
assert.equal(result.contentRowId, 7084)
|
||||
assert.equal(result.dsl.pageType, 'home')
|
||||
assert.equal(result.dsl.pageId, '140')
|
||||
assert.deepEqual(result.dsl.order, ['hero'])
|
||||
}
|
||||
|
||||
{
|
||||
const saves = []
|
||||
let defaultLoads = 0
|
||||
const api = loadApiPersistence({
|
||||
getDecorationContent: async (params) => {
|
||||
if (params.country_code === 'zh-CN') {
|
||||
defaultLoads += 1
|
||||
return defaultLoads === 1
|
||||
? []
|
||||
: [
|
||||
{
|
||||
id: 9001,
|
||||
config: JSON.stringify([{ type: api.DSL_ROW_TYPE, ...sampleDsl }])
|
||||
}
|
||||
]
|
||||
}
|
||||
return [
|
||||
{
|
||||
id: 9001,
|
||||
config: JSON.stringify([{ type: api.DSL_ROW_TYPE, ...sampleDsl }])
|
||||
}
|
||||
]
|
||||
},
|
||||
saveTemplateContent: async (body) => {
|
||||
saves.push(body)
|
||||
},
|
||||
saveHeaderOrFooter: async () => {}
|
||||
})
|
||||
|
||||
const result = await api.savePageDslToApi({
|
||||
templateId: 140,
|
||||
contentRowId: 0,
|
||||
dsl: sampleDsl,
|
||||
scene: '1001',
|
||||
pageType: 'home'
|
||||
})
|
||||
|
||||
assert.equal(saves.length, 2)
|
||||
assert.equal(saves[0].country_code, 'zh-CN')
|
||||
const defaultConfig = JSON.parse(saves[0].config)
|
||||
assert.equal(defaultConfig[0].pageType, 'home')
|
||||
assert.equal(Object.hasOwn(defaultConfig[0], 'dsl'), false)
|
||||
const currentConfig = JSON.parse(saves[1].config)
|
||||
assert.equal(currentConfig[0].id, 9001)
|
||||
assert.equal(currentConfig[0].pageType, 'home')
|
||||
assert.equal(result.contentRowId, 9001)
|
||||
}
|
||||
|
||||
{
|
||||
const saves = []
|
||||
const api = loadApiPersistence({
|
||||
getDecorationContent: async (params) => {
|
||||
if (params.country_code === 'zh-CN') {
|
||||
return { id: 1, config: JSON.stringify({ pageType: params.page_name }) }
|
||||
}
|
||||
return null
|
||||
},
|
||||
saveTemplateContent: async () => {},
|
||||
saveHeaderOrFooter: async (body) => {
|
||||
saves.push(body)
|
||||
}
|
||||
})
|
||||
|
||||
await api.saveHeaderDslToApi({
|
||||
dsl: { pageType: 'header', pageId: 'header', sections: {}, order: [] }
|
||||
})
|
||||
assert.equal(saves.length, 1)
|
||||
assert.equal(saves[0].page_name, 'header')
|
||||
assert.equal(saves[0].country_code, undefined)
|
||||
assert.equal(Array.isArray(JSON.parse(saves[0].config)), false)
|
||||
}
|
||||
|
||||
{
|
||||
const { RequestClient, getLastRequest } = loadRequestClient()
|
||||
const client = new RequestClient()
|
||||
await client.post('/example', { country_code: 'zh-CN', name: 'x' })
|
||||
assert.equal(getLastRequest().data.country_code, 'zh-CN')
|
||||
|
||||
await client.post('/example', 'name=x&country_code=zh-CN')
|
||||
assert.equal(getLastRequest().data, 'name=x&country_code=zh-CN')
|
||||
|
||||
await client.post('/example', { name: 'x' }, { skipCountryCode: true })
|
||||
assert.equal(getLastRequest().data.country_code, undefined)
|
||||
}
|
||||
|
||||
console.log('Template i18n save payload checks passed')
|
||||
@@ -63,12 +63,15 @@ class RequestClient {
|
||||
const countryCode = langMap[lang]
|
||||
if (config.data) {
|
||||
if (typeof config.data === 'string') {
|
||||
config.data =
|
||||
config.data +
|
||||
(config.data ? '&' : '') +
|
||||
'country_code=' +
|
||||
encodeURIComponent(countryCode)
|
||||
} else {
|
||||
const hasCountryCode = /(?:^|&)country_code=/.test(config.data)
|
||||
if (!hasCountryCode) {
|
||||
config.data =
|
||||
config.data +
|
||||
(config.data ? '&' : '') +
|
||||
'country_code=' +
|
||||
encodeURIComponent(countryCode)
|
||||
}
|
||||
} else if (!config.data.country_code) {
|
||||
config.data.country_code = countryCode
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -19,10 +19,22 @@ import {
|
||||
import { createGlobalSections } from '../definitions/documents/global.js'
|
||||
|
||||
export const DSL_ROW_TYPE = 'ECX_SP_WEB_DECORATION_DSL_V1'
|
||||
export const DEFAULT_COUNTRY_CODE = 'zh-CN'
|
||||
const LEGACY_GLOBAL_DECORATION_PAGE_NAME = 'ecx_sp_web_decoration_global'
|
||||
export const HEADER_DECORATION_PAGE_NAME = 'header'
|
||||
export const FOOTER_DECORATION_PAGE_NAME = 'footer'
|
||||
|
||||
export function getCurrentCountryCode() {
|
||||
const lang = window.localStorage.getItem('lang')
|
||||
const langMap = {
|
||||
zhcn: 'zh-CN',
|
||||
en: 'en-CN',
|
||||
zhtw: 'zh-TW',
|
||||
ar: 'ar-SA'
|
||||
}
|
||||
return langMap[lang] || DEFAULT_COUNTRY_CODE
|
||||
}
|
||||
|
||||
function createPageFallback(templateId, scene, pageType = 'home') {
|
||||
if (pageType === 'custom') {
|
||||
return createCustomDsl({ pageId: String(templateId || ''), scene })
|
||||
@@ -164,12 +176,12 @@ function unwrapPayload(res) {
|
||||
return current == null ? null : current
|
||||
}
|
||||
|
||||
function parsePageDslRows(payload, templateId, scene, pageType = 'home') {
|
||||
export function parsePageDslRows(payload, templateId, scene, pageType = 'home') {
|
||||
const rows = Array.isArray(payload)
|
||||
? payload
|
||||
: payload && typeof payload === 'object'
|
||||
? [payload]
|
||||
: []
|
||||
? [payload]
|
||||
: []
|
||||
if (!rows.length) return null
|
||||
|
||||
for (const row of rows) {
|
||||
@@ -191,23 +203,22 @@ function parsePageDslRows(payload, templateId, scene, pageType = 'home') {
|
||||
continue
|
||||
}
|
||||
const target = Array.isArray(cfg)
|
||||
? cfg.find((item) => item && item.type === DSL_ROW_TYPE)
|
||||
: cfg && cfg.type === DSL_ROW_TYPE && cfg.dsl
|
||||
? cfg
|
||||
: cfg && cfg.pageType && cfg.sections
|
||||
? { dsl: cfg }
|
||||
: null
|
||||
? cfg.find((item) => item && (item.type === DSL_ROW_TYPE || (item.pageType && item.sections)))
|
||||
: cfg && (cfg.type === DSL_ROW_TYPE || (cfg.pageType && cfg.sections))
|
||||
? cfg
|
||||
: null
|
||||
const targetDsl = target?.dsl || target
|
||||
console.log('[sp-web-decoration] page config parsed target', {
|
||||
templateId,
|
||||
rowId: row?.id,
|
||||
isArray: Array.isArray(cfg),
|
||||
hasTarget: Boolean(target),
|
||||
targetDsl: target?.dsl
|
||||
targetDsl
|
||||
})
|
||||
if (!target || !target.dsl) continue
|
||||
if (!targetDsl) continue
|
||||
return {
|
||||
dsl: normalizePageDsl(target.dsl, templateId, scene, pageType),
|
||||
contentRowId: row.id || 0,
|
||||
dsl: normalizePageDsl(targetDsl, templateId, scene, pageType),
|
||||
contentRowId: row.id || target.id || 0,
|
||||
source: 'api'
|
||||
}
|
||||
}
|
||||
@@ -262,6 +273,54 @@ export async function loadPageDslFromApi({ templateId, scene, pageType = 'home'
|
||||
return fallback
|
||||
}
|
||||
|
||||
export function buildPageContentPayload({ normalizedDsl, contentRowId }) {
|
||||
const payload = {
|
||||
type: DSL_ROW_TYPE,
|
||||
...serializeDsl(normalizedDsl)
|
||||
}
|
||||
|
||||
if (contentRowId) {
|
||||
payload.id = contentRowId
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
async function loadDefaultPageRow({ templateId, scene, pageType }) {
|
||||
const raw = await getDecorationContent({
|
||||
page_name: 'page',
|
||||
theme_pc_template_id: templateId,
|
||||
country_code: DEFAULT_COUNTRY_CODE
|
||||
})
|
||||
const list = unwrapPayload(raw)
|
||||
return parsePageDslRows(list, templateId, scene, pageType)
|
||||
}
|
||||
|
||||
async function ensureDefaultPageRow({ templateId, contentRowId, normalizedDsl, scene, pageType }) {
|
||||
if (getCurrentCountryCode() === DEFAULT_COUNTRY_CODE) {
|
||||
return contentRowId || 0
|
||||
}
|
||||
|
||||
const existing = await loadDefaultPageRow({ templateId, scene, pageType })
|
||||
if (existing?.contentRowId) {
|
||||
return existing.contentRowId
|
||||
}
|
||||
|
||||
const payload = buildPageContentPayload({
|
||||
normalizedDsl,
|
||||
contentRowId: 0
|
||||
})
|
||||
|
||||
await saveTemplateContent({
|
||||
theme_pc_template_id: templateId,
|
||||
config: JSON.stringify([payload]),
|
||||
country_code: DEFAULT_COUNTRY_CODE
|
||||
})
|
||||
|
||||
const created = await loadDefaultPageRow({ templateId, scene, pageType })
|
||||
return created?.contentRowId || contentRowId || 0
|
||||
}
|
||||
|
||||
export async function savePageDslToApi({
|
||||
templateId,
|
||||
contentRowId,
|
||||
@@ -270,10 +329,17 @@ export async function savePageDslToApi({
|
||||
pageType = 'home'
|
||||
}) {
|
||||
const normalizedDsl = normalizePageDsl(dsl, templateId, scene, pageType)
|
||||
const payload = {
|
||||
type: DSL_ROW_TYPE,
|
||||
dsl: serializeDsl(normalizedDsl)
|
||||
}
|
||||
const stableContentRowId = await ensureDefaultPageRow({
|
||||
templateId,
|
||||
contentRowId,
|
||||
normalizedDsl,
|
||||
scene,
|
||||
pageType
|
||||
})
|
||||
const payload = buildPageContentPayload({
|
||||
normalizedDsl,
|
||||
contentRowId: stableContentRowId || contentRowId
|
||||
})
|
||||
const config = JSON.stringify([payload])
|
||||
const body = {
|
||||
theme_pc_template_id: templateId,
|
||||
@@ -286,9 +352,15 @@ export async function savePageDslToApi({
|
||||
|
||||
await saveTemplateContent(body)
|
||||
|
||||
const latest = await loadPageDslFromApi({
|
||||
templateId,
|
||||
scene,
|
||||
pageType
|
||||
})
|
||||
|
||||
return {
|
||||
dsl: normalizedDsl,
|
||||
contentRowId: contentRowId || 0
|
||||
contentRowId: latest.contentRowId || stableContentRowId || contentRowId || 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,12 +498,34 @@ export async function loadDecorationContentFromApi({ templateId, scene, pageType
|
||||
}
|
||||
}
|
||||
|
||||
function saveScopedDslToApi({ pageName, dsl }) {
|
||||
const payload = {
|
||||
async function ensureDefaultScopedRow({ pageName, dsl }) {
|
||||
if (getCurrentCountryCode() === DEFAULT_COUNTRY_CODE) {
|
||||
return
|
||||
}
|
||||
|
||||
const raw = await getDecorationContent({
|
||||
page_name: pageName,
|
||||
page_type: pageName,
|
||||
country_code: DEFAULT_COUNTRY_CODE
|
||||
})
|
||||
const payload = unwrapPayload(raw)
|
||||
if (payload?.id || payload?.config) {
|
||||
return
|
||||
}
|
||||
|
||||
await saveHeaderOrFooter({
|
||||
page_name: pageName,
|
||||
config: JSON.stringify(serializeDsl(dsl)),
|
||||
country_code: DEFAULT_COUNTRY_CODE
|
||||
})
|
||||
}
|
||||
|
||||
async function saveScopedDslToApi({ pageName, dsl }) {
|
||||
await ensureDefaultScopedRow({ pageName, dsl })
|
||||
return saveHeaderOrFooter({
|
||||
page_name: pageName,
|
||||
config: JSON.stringify(serializeDsl(dsl))
|
||||
}
|
||||
return saveHeaderOrFooter(payload)
|
||||
})
|
||||
}
|
||||
|
||||
export async function saveHeaderDslToApi({ dsl }) {
|
||||
|
||||
@@ -80,7 +80,7 @@ export default {
|
||||
footerDsl
|
||||
})
|
||||
if (this.templateId) {
|
||||
await Promise.all([
|
||||
const [, pageResult] = await Promise.all([
|
||||
saveHeaderDslToApi({ dsl: headerDsl }),
|
||||
savePageDslToApi({
|
||||
templateId: this.templateId,
|
||||
@@ -90,6 +90,9 @@ export default {
|
||||
}),
|
||||
saveFooterDslToApi({ dsl: footerDsl })
|
||||
])
|
||||
if (pageResult?.contentRowId) {
|
||||
this.contentRowId = pageResult.contentRowId
|
||||
}
|
||||
this.$message.success(this.$t('732e5057.3b1083'))
|
||||
} else {
|
||||
const result = await saveHomeDecoration({
|
||||
|
||||
Reference in New Issue
Block a user