Files
medical-mall/pages/mall/admin/design/design.uts
2026-02-02 20:07:37 +08:00

550 lines
13 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 页面装修业务逻辑模块
* 参考CRMEB项目提供完整的装修管理功能
*/
/**
* 装修页面数据接口
*/
export interface DesignItem {
id: string | number
name: string
type: 'homepage' | 'category' | 'product' | 'custom'
status: 0 | 1 // 0: 草稿, 1: 已发布
categoryId?: string | number
categoryName?: string
path?: string
preview_url?: string
content: DesignComponent[]
version?: string
created_at?: string
updated_at?: string
}
/**
* 装修组件接口
*/
export interface DesignComponent {
id: string
type: 'image' | 'text' | 'product' | 'carousel' | 'divider' | 'spacer' | 'button' | 'form'
name: string
icon: string
description?: string
componentName?: string
config?: Record<string, any>
children?: DesignComponent[]
}
/**
* 装修模板接口
*/
export interface DesignTemplate {
id: string | number
name: string
description: string
type: string
preview: string
content: DesignComponent[]
created_at?: string
}
/**
* 获取装修页面列表
* @param params 查询参数
* @returns 装修页面列表
*/
export function getDesignList(params?: Record<string, any>): Promise<DesignItem[]> {
return new Promise((resolve, reject) => {
// TODO: 实际应调用后端API
const designList: DesignItem[] = [
{
id: 1,
name: '首页装修',
type: 'homepage',
status: 1,
content: [],
updated_at: '2026-01-30 14:30:00'
},
{
id: 2,
name: '年货节活动页',
type: 'custom',
status: 1,
content: [],
updated_at: '2026-01-28 10:15:00'
}
]
setTimeout(() => resolve(designList), 300)
})
}
/**
* 获取首页装修详情
* @returns 首页装修数据
*/
export function getHomePageDesign(): Promise<DesignItem> {
return new Promise((resolve, reject) => {
const homepage: DesignItem = {
id: 'homepage',
name: '首页装修',
type: 'homepage',
status: 1,
content: [
{
id: 'carousel-1',
type: 'carousel',
name: '轮播图',
icon: 'C',
description: '首页顶部轮播图展示',
config: {
autoplay: true,
duration: 5000,
height: 300
}
},
{
id: 'product-1',
type: 'product',
name: '商品展示',
icon: 'P',
description: '热销商品列表',
config: {
count: 8,
columns: 2,
layout: 'grid'
}
}
],
version: '1.0.0',
updated_at: '2026-01-30 14:30:00'
}
setTimeout(() => resolve(homepage), 300)
})
}
/**
* 获取商品页装修详情
* @returns 商品页装修数据
*/
export function getProductPageDesign(): Promise<DesignItem> {
return new Promise((resolve, reject) => {
const productPage: DesignItem = {
id: 'product',
name: '商品页装修',
type: 'product',
status: 1,
content: [
{
id: 'image-1',
type: 'image',
name: '商品图',
icon: 'I',
description: '商品主图展示'
},
{
id: 'product-info',
type: 'text',
name: '商品信息',
icon: 'T',
description: '商品名称和价格'
}
],
version: '1.0.0',
updated_at: '2026-01-30 14:30:00'
}
setTimeout(() => resolve(productPage), 300)
})
}
/**
* 获取分类装修列表
* @returns 分类装修列表
*/
export function getCategoryDesigns(): Promise<DesignItem[]> {
return new Promise((resolve, reject) => {
const categories: DesignItem[] = [
{
id: 1,
name: '默认分类装修',
type: 'category',
status: 1,
categoryId: 0,
categoryName: '全部分类',
content: [],
updated_at: '2026-01-30 14:30:00'
},
{
id: 2,
name: '热销商品分类',
type: 'category',
status: 0,
categoryId: 1,
categoryName: '推荐分类',
content: [],
updated_at: '2026-01-29 10:15:00'
}
]
setTimeout(() => resolve(categories), 300)
})
}
/**
* 获取自定义页面列表
* @returns 自定义页面列表
*/
export function getCustomPages(): Promise<DesignItem[]> {
return new Promise((resolve, reject) => {
const customPages: DesignItem[] = [
{
id: 1,
name: '新年促销页',
type: 'custom',
status: 1,
path: '/pages/promotion/newyear',
content: [],
updated_at: '2026-01-28 09:00:00'
}
]
setTimeout(() => resolve(customPages), 300)
})
}
/**
* 获取页面模板库
* @returns 模板列表
*/
export function getTemplateLibrary(): Promise<DesignTemplate[]> {
return new Promise((resolve, reject) => {
const templates: DesignTemplate[] = [
{
id: 1,
name: '电商风格A',
description: '简洁现代的电商布局',
type: 'homepage',
preview: '@/static/images/template-a.png',
content: []
},
{
id: 2,
name: '电商风格B',
description: '豪华展示的电商布局',
type: 'homepage',
preview: '@/static/images/template-b.png',
content: []
},
{
id: 3,
name: '精品风格',
description: '精品商品展示布局',
type: 'homepage',
preview: '@/static/images/template-c.png',
content: []
},
{
id: 4,
name: '商城风格',
description: '完整商城功能布局',
type: 'homepage',
preview: '@/static/images/template-d.png',
content: []
}
]
setTimeout(() => resolve(templates), 300)
})
}
/**
* 获取可用组件库
* @returns 组件列表
*/
export function getAvailableComponents(): Promise<DesignComponent[]> {
return new Promise((resolve, reject) => {
const components: DesignComponent[] = [
{
id: 'image',
type: 'image',
name: '图片组件',
icon: 'I',
description: '展示图片和图片轮播',
componentName: 'ImageComponent',
config: {
defaultWidth: '100%',
defaultHeight: 'auto'
}
},
{
id: 'text',
type: 'text',
name: '文本组件',
icon: 'T',
description: '展示文本内容和段落',
componentName: 'TextComponent'
},
{
id: 'product',
type: 'product',
name: '商品组件',
icon: 'P',
description: '展示商品列表和推荐',
componentName: 'ProductComponent',
config: {
defaultCount: 6,
defaultColumns: 2
}
},
{
id: 'carousel',
type: 'carousel',
name: '轮播组件',
icon: 'C',
description: '图片和内容轮播',
componentName: 'CarouselComponent',
config: {
autoplay: true,
duration: 5000
}
},
{
id: 'divider',
type: 'divider',
name: '分割线',
icon: 'D',
description: '分割不同内容区域',
componentName: 'DividerComponent'
},
{
id: 'spacer',
type: 'spacer',
name: '间距组件',
icon: 'S',
description: '调整元素间距',
componentName: 'SpacerComponent',
config: {
defaultHeight: 16
}
},
{
id: 'button',
type: 'button',
name: '按钮组件',
icon: 'B',
description: '创建点击按钮',
componentName: 'ButtonComponent'
},
{
id: 'form',
type: 'form',
name: '表单组件',
icon: 'F',
description: '收集用户输入数据',
componentName: 'FormComponent'
}
]
setTimeout(() => resolve(components), 300)
})
}
/**
* 保存装修页面
* @param design 装修数据
* @returns 保存结果
*/
export function saveDesign(design: DesignItem): Promise<{ id: string | number; message: string }> {
return new Promise((resolve, reject) => {
if (!design.name || design.name.trim() === '') {
reject(new Error('装修名称不能为空'))
return
}
if (!design.type) {
reject(new Error('装修类型不能为空'))
return
}
// TODO: 实际应调用后端API保存
const result = {
id: design.id || Math.random().toString(36).substr(2, 9),
message: '保存成功'
}
setTimeout(() => resolve(result), 500)
})
}
/**
* 发布装修页面
* @param designId 装修页面ID
* @returns 发布结果
*/
export function publishDesign(designId: string | number): Promise<{ message: string }> {
return new Promise((resolve, reject) => {
if (!designId) {
reject(new Error('装修ID不能为空'))
return
}
// TODO: 实际应调用后端API发布
setTimeout(() => {
resolve({ message: '发布成功' })
}, 500)
})
}
/**
* 删除装修页面
* @param designId 装修页面ID
* @returns 删除结果
*/
export function deleteDesign(designId: string | number): Promise<{ message: string }> {
return new Promise((resolve, reject) => {
if (!designId) {
reject(new Error('装修ID不能为空'))
return
}
// TODO: 实际应调用后端API删除
setTimeout(() => {
resolve({ message: '删除成功' })
}, 500)
})
}
/**
* 获取装修预览URL
* @param designId 装修ID
* @returns 预览URL
*/
export function getDesignPreviewUrl(designId: string | number): string {
return `/pages/mall/design/preview/${designId}`
}
/**
* 获取装修编辑URL
* @param designId 装修ID
* @returns 编辑URL
*/
export function getDesignEditorUrl(designId: string | number): string {
return `/pages/mall/admin/design/editor?id=${designId}`
}
/**
* 格式化日期时间
* @param dateStr 日期字符串
* @returns 格式化后的日期
*/
export function formatDateTime(dateStr?: string): string {
if (!dateStr) return '--'
try {
const date = new Date(dateStr)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
} catch {
return dateStr
}
}
/**
* 验证组件配置
* @param component 组件配置
* @returns 验证结果
*/
export function validateComponent(component: DesignComponent): { valid: boolean; errors: string[] } {
const errors: string[] = []
if (!component.id) {
errors.push('组件ID不能为空')
}
if (!component.type) {
errors.push('组件类型不能为空')
}
if (!component.name) {
errors.push('组件名称不能为空')
}
return {
valid: errors.length === 0,
errors
}
}
/**
* 生成组件ID
* @param type 组件类型
* @returns 生成的组件ID
*/
export function generateComponentId(type: string): string {
const timestamp = Date.now().toString(36)
const random = Math.random().toString(36).substr(2, 5)
return `${type}-${timestamp}-${random}`
}
/**
* 获取装修约束条件
* @returns 约束条件对象
*/
export function getDesignConstraints(): DesignConstraints {
return {
maxComponents: 50,
allowedComponentTypes: ['image', 'text', 'product', 'carousel', 'divider', 'spacer', 'button', 'form'],
maxImageSize: 5242880, // 5MB
supportedImageFormats: ['jpg', 'jpeg', 'png', 'gif', 'webp']
}
}
/**
* 深度克隆装修数据
* @param design 装修数据
* @returns 克隆后的数据
*/
export function cloneDesign(design: DesignItem): DesignItem {
return JSON.parse(JSON.stringify(design))
}
/**
* 验证装修数据完整性
* @param design 装修数据
* @returns 验证结果
*/
export function validateDesign(design: DesignItem): { valid: boolean; message: string } {
if (!design.name || design.name.trim() === '') {
return { valid: false, message: '装修名称不能为空' }
}
if (!design.type) {
return { valid: false, message: '装修类型不能为空' }
}
if (!Array.isArray(design.content)) {
return { valid: false, message: '装修内容格式错误' }
}
if (design.content.length > getDesignConstraints().maxComponents) {
return { valid: false, message: `组件数量超过限制(最多${getDesignConstraints().maxComponents}个)` }
}
return { valid: true, message: '验证通过' }
}
/**
* 导出装修为JSON
* @param design 装修数据
* @returns JSON字符串
*/
export function exportDesignJSON(design: DesignItem): string {
return JSON.stringify(design, null, 2)
}
/**
* 从JSON导入装修
* @param jsonStr JSON字符串
* @returns 装修数据
*/
export function importDesignJSON(jsonStr: string): DesignItem {
try {
return JSON.parse(jsonStr) as DesignItem
} catch (error) {
throw new Error('JSON格式错误无法导入')
}
}