elementui实现复杂表单的实践

news2025/4/21 10:33:49

简介

文章主要讲述在vue3项目中使用elementui框架实现复杂表单的方式。表单中涉及动态组件的生成、文件上传富文本编辑器的使用,只会将在实现过程中较复杂的部分进行分享,然后提供一份完整的前端代码。

表单效果演示

基础信息

spu属性

sku详情

关键点

动态组件的处理

在spu属性步骤中,CPU型号、操作系统和生物解锁三个属性都是动态生成的。

实现原理

组件动态生成和删除的原理是通过操作v-for组件的数据源实现的。向数据源添加数据会动态生成组件,将数据源的数据减少就会删除对应的组件。

所以在点击添加属性时,只要向v-for的数据源中添加属性配置,就能实现动态生成组件的效果。

组件的类型、可选值都是提前定义的。

分析JD、淘宝等各类商城关于spu属性的展示,可以发现基本可以用自定义、单选和多选属性把所有spu属性覆盖。

因此就可以提前将商品可用的属性按类型和可选值完成定义,在页面选择对应属性添加到页面即可。

动态添加spu属性的代码

只需要重点关注 addSpuItemrmAttr 方法和 v-for="(dynamicSpu, dspuK) in state.auxiliaries.optional.attr.spu.dynamicItems"

<el-form-item label="选择属性">
        <el-select filterable v-model="state.auxiliaries.optional.attr.spu.dynamic"
            style="display: inline-block;width: 198px">
            <el-option label="请选择" :value="0"></el-option>
            <el-option v-for="(spuAttr, spuK) in state.auxiliaries.optional.attr.list" :key="spuK" :label="spuAttr.name"
                :value="spuAttr.attrId"></el-option>
        </el-select>
        <el-divider direction="vertical" border-style="none" />
        <el-button type="primary" @click="addSpuItem">添加规格属性</el-button>
    </el-form-item>
    <el-form-item v-for="(dynamicSpu, dspuK) in state.auxiliaries.optional.attr.spu.dynamicItems" :key="dspuK"
        :label="dynamicSpu.name">
        <el-input v-model="dynamicSpu.selectedValue" v-if="dynamicSpu.type === 'CUSTOM'"
            style="max-width: 40%"></el-input>
        <el-radio-group v-model="dynamicSpu.selectedValue" v-else-if="dynamicSpu.type === 'SINGLE'">
            <el-radio v-for="(dspuAttr, dspuaK) in dynamicSpu.value" :key="dspuaK" :label="dspuAttr">{{ dspuAttr
                }}</el-radio>
        </el-radio-group>
        <el-checkbox-group v-model="dynamicSpu.selectedValue" v-else-if="dynamicSpu.type === 'MULTIPLE'">
            <el-checkbox v-for="(dspumAttr, dspumK) in dynamicSpu.value" :key="dspumK" :label="dspumAttr"
                :value="dspumAttr"></el-checkbox>
        </el-checkbox-group>
        <el-divider direction="vertical"></el-divider>
        <el-button type="danger" @click="rmAttr('spu', dspuK)" size="small">删除</el-button>
    </el-form-item>

向spu数据源添加元素

主要是向 state.auxiliaries.optional.attr.spu.dynamicItems 这个数组中追加元素

// 动态生成SPU条目
const addSpuItem = () => {
    if (state.value.auxiliaries.optional.attr.spu.dynamic === 0) {
        ElMessage.error("请选择一个属性")
        return
    }
    // 已选择的SPU属性
    for (let i = 0; i < state.value.auxiliaries.optional.attr.list.length; i++) {
        if (state.value.auxiliaries.optional.attr.list[i].attrId === state.value.auxiliaries.optional.attr.spu.dynamic) {
            // 利用JSON实现简单对象的深拷贝
            let dynamicItem = JSON.parse(JSON.stringify(state.value.auxiliaries.optional.attr.list[i]))
            dynamicItem.selectedValue = []

            state.value.auxiliaries.optional.attr.spu.dynamicItems.push(dynamicItem)
        }
    }
}

删除动态组件

将对应数据源的元素删除,就可以实现动态删除生成的组件

const rmAttr = (type: string, idx: number) => {
    if (type === "spu") {
        // 删除动态添加的SPU属性
        state.value.auxiliaries.optional.attr.spu.dynamicItems.splice(idx, 1)
        return
    }
    if (type === "sku") {
        state.value.auxiliaries.optional.attr.sku.dynamicItems.splice(idx, 1)
    }
}

文件上传组件的使用

在sku部分有上传组件的使用。

利用elementUI提供的组件实现,相对来说没有什么难度。由于是动态组件,每个上传文件的组件要设置一个单独的参数接收数据,避免出现数据覆盖的情况

    <!-- 商品轮播图 -->
    <el-form-item label="商品轮播图" label-width="120">
        <el-upload v-model:file-list="state.auxiliaries.configs.upload.coversForm[dDetailItemK].covers"
            action="http://localhost:9900/upload/cover" multiple :headers="state.auxiliaries.configs.upload.headers"
            :on-success="handleUploadCoverSuccess" :on-error="handleUploadCoverFailed" method="post"
            list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove">
            <el-icon>
                <Plus />
            </el-icon>
        </el-upload>
    </el-form-item>

主要用到了组件的action、headers属性。action设置上传文件的接口、headers设置调用接口时必要的请求头

定义headers

一般项目都是前后端分离的,headers通常设置调用接口的token等身份认证信息。

const state = ref({
    auxiliaries: {
        configs: {
            upload: {
                headers: {
                    Authorization: "Bearer " + Session.get('token')
                },
                coversForm: [] as Array<any>
            }
        }
    }
})

动态使用富文本编辑器

富文本编辑器使用的是tinymce,特点就是轻量、简洁。具体使用教程可以看这里。

动态的富文本编辑器实现原理与上传组件一样,区别就是在获取富文本编辑器中的内容的方式有所不同。

在vue3中富文本编辑器的组件需要设置ref属性,在获取编辑器的内容时需要通过ref获取到编辑器的实例,然后再获取内容

<template>
    <!-- 商详 -->
    <el-form-item v-for="(dynamicSku, dskuK) in state.auxiliaries.optional.attr.sku.dynamicItems"
                                :key="dskuK" label="商品详情" label-width="120">
        <!-- 用tinymce富文本编辑器 -->
        <Editor ref="skuDetailRef" :init="state.auxiliaries.configs.editor.configs" initial-value="Welcome to TinyMCE!">
        </Editor>
    </el-form-item>
</template>
<script setup lang="ts">
import Editor from '@tinymce/tinymce-vue'
</script>

在vue3中当页面有多个Editor实例时,对应ref的值会是数组。

获取多富文本编辑器的内容

<script setup lang="ts">

import {ref} from 'vue'
const skuDetailRef = ref()
const submitForm = () => {
    // 将sku的详情追加到form
    for (let skuIdx = 0; skuIdx < skuDetailRef.value.length; skuIdx++) {
        skuDetailRef.value[skuIdx].getEditor().getContent()
    }
}
</script>

相关的完整代码

运行的依赖有Vue3、element-plus和tinymce

<template>
    <el-row style="margin-top: 20px;">
        <el-col :span="22" :offset="1">
            <el-card>
                <el-steps style="width: 100%" :active="state.auxiliaries.configs.step.active" finish-status="success">
                    <el-step title="基础信息" />
                    <el-step title="设置规格" />
                    <el-step title="设置SKU" />
                </el-steps>
                <el-divider border-style="none"></el-divider>
                <el-form v-model="state.form">
                    <el-tabs v-model="state.auxiliaries.configs.step.stepTabActive" class="demo-tabs"
                        @tab-change="handleTabChange">
                        <el-tab-pane label="基础信息" name="product-base">
                            <el-form-item label="商品名称">
                                <el-input v-model="state.form.name"></el-input>
                            </el-form-item>
                            <el-form-item label="选择品牌">
                                <el-select v-model="state.form.brandId">
                                    <el-option :value=0 label="请选择"></el-option>
                                    <el-option v-for="(brand, bk) in state.auxiliaries.optional.brandList" :key="bk"
                                        :label="brand.label" :value="brand.value"></el-option>
                                </el-select>
                            </el-form-item>
                            <el-form-item label="所属分类">
                                <el-cascader v-model="state.form.categoryId" clearable
                                    :props="state.auxiliaries.optional.categories.props"
                                    :options="state.auxiliaries.optional.categories.list"></el-cascader>
                            </el-form-item>
                            <el-form-item>
                                <el-button type="primary" @click="nextStep">下一步</el-button>
                            </el-form-item>
                        </el-tab-pane>
                        <el-tab-pane label="设置规格" name="set-spu">
                            <el-form-item label="选择属性">
                                <el-select filterable v-model="state.auxiliaries.optional.attr.spu.dynamic"
                                    style="display: inline-block;width: 198px">
                                    <el-option label="请选择" :value="0"></el-option>
                                    <el-option v-for="(spuAttr, spuK) in state.auxiliaries.optional.attr.list"
                                        :key="spuK" :label="spuAttr.name" :value="spuAttr.attrId"></el-option>
                                </el-select>
                                <el-divider direction="vertical" border-style="none" />
                                <el-button type="primary" @click="addSpuItem">添加规格属性</el-button>
                            </el-form-item>
                            <el-form-item
                                v-for="(dynamicSpu, dspuK) in state.auxiliaries.optional.attr.spu.dynamicItems"
                                :key="dspuK" :label="dynamicSpu.name">
                                <el-input v-model="dynamicSpu.selectedValue" v-if="dynamicSpu.type === 'CUSTOM'"
                                    style="max-width: 40%"></el-input>
                                <el-radio-group v-model="dynamicSpu.selectedValue" v-else-if="dynamicSpu.type === 'SINGLE'">
                                    <el-radio v-for="(dspuAttr, dspuaK) in dynamicSpu.value" :key="dspuaK"
                                        :label="dspuAttr">{{ dspuAttr }}</el-radio>
                                </el-radio-group>
                                <el-checkbox-group v-model="dynamicSpu.selectedValue" v-else-if="dynamicSpu.type === 'MULTIPLE'">
                                    <el-checkbox v-for="(dspumAttr, dspumK) in dynamicSpu.value" :key="dspumK"
                                        :label="dspumAttr" :value="dspumAttr"></el-checkbox>
                                </el-checkbox-group>
                                <el-divider direction="vertical"></el-divider>
                                <el-button type="danger" @click="rmAttr('spu', dspuK)" size="small">删除</el-button>
                            </el-form-item>
                            <el-form-item>
                                <el-button type="primary" @click="nextStep">下一步</el-button>
                            </el-form-item>
                        </el-tab-pane>
                        <el-tab-pane label="设置SKU" name="set-sku">
                            <el-form-item label="选择属性">
                                <el-select filterable v-model="state.auxiliaries.optional.attr.sku.dynamic"
                                    style="display: inline-block;width: 198px">
                                    <el-option label="请选择" :value="0"></el-option>
                                    <el-option v-for="(skuAttr, skuK) in state.auxiliaries.optional.attr.list"
                                        :key="skuK" :label="skuAttr.name" :value="skuAttr.attrId"></el-option>
                                </el-select>
                                <el-divider direction="vertical" border-style="none" />
                                <el-button type="primary" @click="addSkuItem">添加规格属性</el-button>
                                <el-divider border-style="none" direction="vertical"></el-divider>
                                <el-button type="success" @click="genSkuItems">生成SKU条目</el-button>
                            </el-form-item>
                            <el-form-item
                                v-for="(dynamicSku, dskuK) in state.auxiliaries.optional.attr.sku.dynamicItems"
                                :key="dskuK" :label="dynamicSku.name">
                                <el-checkbox-group v-model="dynamicSku.selectedValue">
                                    <el-checkbox v-for="(dskumAttr, dskumK) in dynamicSku.value" :key="dskumK"
                                        :label="dskumAttr" :value="dskumAttr"></el-checkbox>
                                </el-checkbox-group>
                                <el-divider direction="vertical"></el-divider>
                                <el-button type="danger" @click="rmAttr('sku', dskuK)" size="small">删除</el-button>
                            </el-form-item>
                            <el-form-item v-if="state.auxiliaries.optional.attr.sku.dynamicDetailItems.length > 0">
                                <el-divider content-position="left">设置具体的SKU信息</el-divider>
                                <el-button-group style="margin-bottom: 15px">
                                    <el-button type="primary" @click="initSkuInfo('title')">初始化标题</el-button>
                                    <el-button type="primary" @click="initSkuInfo('summary')">初始化简介</el-button>
                                    <el-button type="primary" @click="initSkuInfo('stock')">初始化库存</el-button>
                                    <el-button type="primary" @click="initSkuInfo('price')">初始化价格</el-button>
                                </el-button-group>
                                <!-- 用折叠面板显示各种SKU的数据 -->
                                <el-collapse style="width: 100%"
                                    v-model="state.auxiliaries.optional.attr.sku.dynamicDetailCollapaseActiveNames">
                                    <el-collapse-item :title="genCollapseTitle(dDetailItemV)"
                                        :name="genCollapseTitle(dDetailItemV)"
                                        v-for="(dDetailItemV, dDetailItemK) in state.auxiliaries.optional.attr.sku.dynamicDetailItems"
                                        :key="dDetailItemK">
                                        <!-- 销售标题 -->
                                        <el-form-item label="销售标题" label-width="120">
                                            <el-input v-model="state.form.skuDetails[dDetailItemK].title"></el-input>
                                        </el-form-item>
                                        <el-divider border-style="none"></el-divider>
                                        <el-form-item label="SKU简介" label-width="120">
                                            <el-input v-model="state.form.skuDetails[dDetailItemK].summary"></el-input>
                                        </el-form-item>
                                        <el-divider border-style="none"></el-divider>
                                        <!-- 商品轮播图 -->
                                        <el-form-item label="商品轮播图" label-width="120">
                                            <el-upload
                                                v-model:file-list="state.auxiliaries.configs.upload.coversForm[dDetailItemK].covers"
                                                action="http://localhost:9900/upload/cover" multiple
                                                :headers="state.auxiliaries.configs.upload.headers"
                                                :on-success="handleUploadCoverSuccess"
                                                :on-error="handleUploadCoverFailed" method="post"
                                                list-type="picture-card" :on-preview="handlePictureCardPreview"
                                                :on-remove="handleRemove">
                                                <el-icon>
                                                    <Plus />
                                                </el-icon>
                                            </el-upload>
                                        </el-form-item>
                                        <el-divider border-style="none"></el-divider>
                                        <!-- 价格 -->
                                        <el-form-item label="价格" label-width="120">
                                            <el-input type="number"
                                                v-model="state.form.skuDetails[dDetailItemK].price"></el-input>
                                        </el-form-item>
                                        <el-divider border-style="none"></el-divider>
                                        <!-- 库存 -->
                                        <el-form-item label="库存" label-width="120">
                                            <el-input type="number"
                                                v-model="state.form.skuDetails[dDetailItemK].stock"></el-input>
                                        </el-form-item>
                                        <el-divider border-style="none"></el-divider>
                                        <!-- 商详 -->
                                        <el-form-item label="商品详情" label-width="120">
                                            <!-- 用tinymce富文本编辑器 -->
                                            <Editor ref="skuDetailRef" :init="state.auxiliaries.configs.editor.configs"
                                                initial-value="Welcome to TinyMCE!">
                                            </Editor>
                                        </el-form-item>
                                        <el-divider border-style="none"></el-divider>
                                    </el-collapse-item>
                                </el-collapse>
                            </el-form-item>
                            <el-form-item>
                                <el-button type="primary" @click="submitForm">提交</el-button>
                                <el-button>重置</el-button>
                            </el-form-item>
                        </el-tab-pane>
                    </el-tabs>

                </el-form>
                <el-dialog v-model="state.auxiliaries.optional.attr.sku.imgDialog.visiable">
                    <img w-full :src="state.auxiliaries.optional.attr.sku.imgDialog.url" alt="Preview Image" />
                </el-dialog>
            </el-card>
        </el-col>
    </el-row>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import type { UploadProps } from 'element-plus'
import Editor from '@tinymce/tinymce-vue'
import { Session } from '/@/utils/storage';
import { UploadAjaxError } from 'element-plus/es/components/upload/src/ajax'
import { useFiletApi } from '/@/api/file'


const skuDetailRef = ref()
const fileApi = useFiletApi()

const state = ref({
    form: {
        id: null,
        name: "",
        brandId: 0,
        categoryId: [],
        spu: [] as ProductAttrType[],
        sku: [] as ProductAttrType[],
        skuDetails: [] as ProductSkuFormType[],
    } as ProductFormType,
    rawForm: {
        id: null,
        name: "",
        brandId: 0,
        categoryId: [],
        spu: [] as ProductAttrType[],
        sku: [] as ProductAttrType[],
        skuDetails: [] as ProductSkuFormType[]
    } as ProductFormType,
    auxiliaries: {
        configs: {
            step: {
                active: 1, // 步骤条
                stepTab: [
                    { name: "product-base", step: 1 },
                    { name: "set-spu", step: 2 },
                    { name: "set-sku", step: 3 },
                ],
                stepTabActive: "product-base",
            },
            editor: {
                configs: {
                    width: '100%',
                    resize: 'both',
                    min_height: 300,
                    plugins: "image fullscreen",
                    // 实现上传逻辑
                    images_upload_handler: async (blobInfo: any, success: any) => {
                        console.log("upload image ", blobInfo, success)
                        const formData = new FormData();
                        formData.append('file', blobInfo.blob());
                        // 上传
                        const uploadRs = await uploadImg(formData)
                        // success("https://cdn3-banquan.ituchong.com/weili/image/l/1517224685217251339.jpeg")
                        success(uploadRs.data)
                    }
                }
            },
            upload: {
                headers: {
                    Authorization: "Bearer " + Session.get('token')
                },
                coversForm: [] as Array<any>
            }
        },
        optional: {
            brandList: [
                { label: "华为", value: 1 }, { label: "苹果", value: 2 },
            ],
            categories: {
                list: [
                    {
                        label: "手机品类", value: 1, children: [
                            { label: "手机", value: 3 },
                            { label: "手机配件", value: 4 }
                        ]
                    },
                    {
                        label: "电脑", value: 2, children: [
                            { label: "电脑配件", value: 5 },
                            {
                                label: "外设产品", value: 6, children: [
                                    { label: "鼠标", value: 7 },
                                    { label: "键盘", value: 8 }
                                ]
                            }
                        ]
                    }
                ],
                props: {
                    expandTrigger: 'hover' as const
                }
            },
            attr: {
                list: [
                    { attrId: 1, name: "颜色", value: ["雅川青", "雅丹黑", "南糯紫", "白沙银", "red"], type: "SINGLE" },
                    { attrId: 2, name: "版本", value: ["12GB+512GB", "12GB+1TB", "16GB+1TB"], type: "SINGLE" },
                    { attrId: 3, name: "CPU型号", value: [], type: "CUSTOM" },
                    { attrId: 4, name: "操作系统", value: ["HarmonyOS", "IOS", "Android"], type: "SINGLE" },
                    { attrId: 5, name: "生物解锁", value: ["指纹", "面部", "视网膜"], type: "MULTIPLE" },
                ],
                spu: {
                    dynamic: 0, // 动态选择的SPU属性组
                    dynamicItems: [] as any[], // 动态选择并生成的SPU属性表单项
                },
                sku: {
                    dynamic: 0, // 动态选择的SPU属性组
                    dynamicItems: [] as any[], // 动态选择并生成的SPU属性表单项
                    dynamicDetailItems: [] as any[], // 根据选择的SKU属性排列组合生成的SKU具体条目
                    dynamicDetailCollapaseActiveNames: [], // 激活状态的折叠面板
                    imgDialog: {
                        visiable: false,
                        url: ""
                    }
                }
            }
        }
    }
})

const nextStep = () => {
    state.value.auxiliaries.configs.step.stepTabActive = state.value.auxiliaries.configs.step.stepTab[state.value.auxiliaries.configs.step.active].name
    state.value.auxiliaries.configs.step.active += 1
}

const handleTabChange = (currentTabName: string) => {
    for (let i = 0; i < state.value.auxiliaries.configs.step.stepTab.length; i++) {
        if (state.value.auxiliaries.configs.step.stepTab[i].name === currentTabName) {
            state.value.auxiliaries.configs.step.active = state.value.auxiliaries.configs.step.stepTab[i].step
        }
    }
}
// 动态生成SPU条目
const addSpuItem = () => {
    if (state.value.auxiliaries.optional.attr.spu.dynamic === 0) {
        ElMessage.error("请选择一个属性")
        return
    }
    // 已选择的SPU属性
    for (let i = 0; i < state.value.auxiliaries.optional.attr.list.length; i++) {
        if (state.value.auxiliaries.optional.attr.list[i].attrId === state.value.auxiliaries.optional.attr.spu.dynamic) {
            let dynamicItem = JSON.parse(JSON.stringify(state.value.auxiliaries.optional.attr.list[i]))
            dynamicItem.selectedValue = []

            state.value.auxiliaries.optional.attr.spu.dynamicItems.push(dynamicItem)
        }
    }
}

const rmAttr = (type: string, idx: number) => {
    if (type === "spu") {
        // 删除动态添加的SPU属性
        state.value.auxiliaries.optional.attr.spu.dynamicItems.splice(idx, 1)
        return
    }
    if (type === "sku") {
        state.value.auxiliaries.optional.attr.sku.dynamicItems.splice(idx, 1)
    }
}

// 动态生成SKU条目
const addSkuItem = () => {
    if (state.value.auxiliaries.optional.attr.sku.dynamic === 0) {
        ElMessage.error("请选择一个属性")
        return
    }
    // 已选择的sku属性
    for (let i = 0; i < state.value.auxiliaries.optional.attr.list.length; i++) {
        if (state.value.auxiliaries.optional.attr.list[i].attrId === state.value.auxiliaries.optional.attr.sku.dynamic) {
            let dynamicItem = JSON.parse(JSON.stringify(state.value.auxiliaries.optional.attr.list[i]))
            // SKU的值全部多选,然后做排列组合
            dynamicItem.selectedValue = []

            state.value.auxiliaries.optional.attr.sku.dynamicItems.push(dynamicItem)
        }
    }
}

// 根据选择的SKU属性值,按排列组合生成SKU条目
// 递归比较适合处理这种问题
const genSkuItems = () => {
    // 清空已有的SKU信息
    state.value.form.skuDetails = [] as ProductSkuFormType[]
    state.value.auxiliaries.configs.upload.coversForm = [] as any[]
    // 获取所有SKU属性和选择的值
    const skus = state.value.auxiliaries.optional.attr.sku.dynamicItems
    // 遍历属性数
    let tempSkuItems = [] // 排列组合临时状态
    for (let i = 0; i < skus.length; i++) {
        // 遍历属性选择的值
        if (tempSkuItems.length <= 0) {
            for (let j = 0; j < skus[i].selectedValue.length; j++) {
                tempSkuItems.push([{
                    attrId: skus[i].attrId,
                    name: skus[i].name,
                    selectedValue: [skus[i].selectedValue[j]]
                }])
            }
        } else {
            let iterTempSkuItems = []
            for (let j = 0; j < skus[i].selectedValue.length; j++) {
                // 判断临时组合是否存在
                for (let k = 0; k < tempSkuItems.length; k++) {
                    let iterTempSkuItem = JSON.parse(JSON.stringify(tempSkuItems[k]))
                    iterTempSkuItem.push({
                        attrId: skus[i].attrId,
                        name: skus[i].name,
                        selectedValue: [skus[i].selectedValue[j]]
                    })
                    iterTempSkuItems.push(iterTempSkuItem)
                }
            }
            // 让最终的排列组合临时变量接管,遍历中的临时变量
            tempSkuItems = JSON.parse(JSON.stringify(iterTempSkuItems))
        }
    }
    // 为表单的SKU生成对应数量的SKU表单字段
    console.log("covers form ", state.value.auxiliaries.configs.upload.coversForm)
    for (let k = 0; k < tempSkuItems.length; k++) {
        state.value.form.skuDetails.push({
            id: null,
            sku: JSON.parse(JSON.stringify(tempSkuItems[k])),
            title: "",
            summary: "",
            price: 0,
            stock: 0,
            covers: [],
            detail: ""
        })
        state.value.auxiliaries.configs.upload.coversForm.push({
            covers: []
        })
    }

    state.value.auxiliaries.optional.attr.sku.dynamicDetailItems = JSON.parse(JSON.stringify(tempSkuItems))
    console.log("covers form ", state.value.auxiliaries.configs.upload.coversForm)
    console.log("sku detail form ", state.value.form.skuDetails)
}

const initSkuInfo = (type: string) => {
    // 用确认框的方式进行交互
    let msgBoxTitle = ""
    switch (type) {
        case "title":
            msgBoxTitle = "初始化销售标题"
            break
        case "summary":
            msgBoxTitle = "初始化SKU简介"
            break
        case "stock":
            msgBoxTitle = "初始化库存"
            break
        case "price":
            msgBoxTitle = "初始化价格"
            break
        default:
            msgBoxTitle = "-"
    }
    ElMessageBox.prompt(msgBoxTitle, '初始化sku数据', {
        confirmButtonText: '提交',
        cancelButtonText: '取消',
    })
        .then(({ value }) => {
            // 将sku的对应信息初始化
            if (type === 'title') {
                initTitle(value)
                return
            }
            if (type === 'summary') {
                initSummary(value)
                return
            }
            if (type === 'stock') {
                initStock(parseInt(value))
                return
            }
            if (type === 'price') {
                initPrice(parseFloat(value))
                return
            }
        })
}
// 初始化sku的销售标题
const initTitle = (titlePrefix: string) => {
    // 自定义的标题加设置的sku属性名
    for (let i = 0; i < state.value.form.skuDetails.length; i++) {
        let skuTitle = ""
        for (let j = 0; j < state.value.form.skuDetails[i].sku.length; j++) {
            skuTitle += " " + state.value.form.skuDetails[i].sku[j].selectedValue.join("")
        }
        state.value.form.skuDetails[i].title = titlePrefix + skuTitle
    }
}

const initSummary = (summary: string) => {
    for (let i = 0; i < state.value.form.skuDetails.length; i++) {
        state.value.form.skuDetails[i].summary = summary
    }
}

const initStock = (stock: number) => {
    for (let i = 0; i < state.value.form.skuDetails.length; i++) {
        state.value.form.skuDetails[i].stock = stock
    }
}

const initPrice = (price: number) => {
    for (let i = 0; i < state.value.form.skuDetails.length; i++) {
        state.value.form.skuDetails[i].price = price
    }
}

const uploadImg = (uploadForm: FormData) => {
    console.log("调用上传文件的接口", uploadForm.get('rawFilename'))
    return fileApi.uploadCover(uploadForm)
}

const handleUploadCoverSuccess = (response: any) => {
    console.log("upload success ", response)
}

const handleUploadCoverFailed = (error: UploadAjaxError) => {
    let rs = JSON.parse(error.message)
    ElMessage.error(rs.msg)
}

const genCollapseTitle = (tempSkuItems: Array<any>): string => {
    let tempTitle = ""
    for (let n = 0; n < tempSkuItems.length; n++) {
        tempTitle += " " + tempSkuItems[n].selectedValue[0]
    }
    return tempTitle
}

const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
    console.log(uploadFile, uploadFiles)
}

const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
    state.value.auxiliaries.optional.attr.sku.imgDialog.url = uploadFile.url!
    state.value.auxiliaries.optional.attr.sku.imgDialog.visiable = true
}

const submitForm = () => {
    console.log("upload covers: ", state.value.auxiliaries.configs.upload.coversForm)
    // 从临时保存轮播图数据的变量中提取轮播图的url
    // 遍历sku
    for (let i = 0; i < state.value.auxiliaries.configs.upload.coversForm.length; i++) {
        // 遍历sku的轮播图
        let skuCovers = []
        for (let j = 0; j < state.value.auxiliaries.configs.upload.coversForm[i].covers.length; j++) {
            // 提取轮播图url
            let coverRs = JSON.parse(JSON.stringify(state.value.auxiliaries.configs.upload.coversForm[i].covers[j].response))
            skuCovers.push(coverRs.data)
        }
        // 赋值到对应的sku的covers
        state.value.form.skuDetails[i].covers = JSON.parse(JSON.stringify(skuCovers))
    }
    // 将sku的详情追加到form
    for (let skuIdx = 0; skuIdx < skuDetailRef.value.length; skuIdx++) {
        state.value.form.skuDetails[skuIdx].detail = skuDetailRef.value[skuIdx].getEditor().getContent()
    }
    // 将sku选择的值追加到form
    state.value.form.sku = JSON.parse(JSON.stringify(state.value.auxiliaries.optional.attr.sku.dynamicItems))
    // 将SPU选择的值追加到form
    state.value.form.spu = JSON.parse(JSON.stringify(state.value.auxiliaries.optional.attr.spu.dynamicItems))
    // 特殊处理spu的值,值都认为是多选的
    for (let b = 0; b < state.value.form.spu.length; b++) {
        if (!(state.value.form.spu[b].selectedValue instanceof Object)) {
            state.value.form.spu[b].selectedValue = [state.value.form.spu[b].selectedValue]
        }
    }

    console.log("submit form: ", state.value.form)
    afterSubmit()
}

const afterSubmit = () => {
    // 重置表单
    state.value.form = JSON.parse(JSON.stringify(state.value.rawForm))
    // 重置sku、spu的动态数据
    state.value.auxiliaries.optional.attr.sku.dynamicItems = []
    state.value.auxiliaries.optional.attr.sku.dynamicDetailItems = []
    state.value.auxiliaries.optional.attr.spu.dynamicItems = []
}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1917472.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《梦醒蝶飞:释放Excel函数与公式的力量》 11.1 ISBLANK函数

第11章&#xff1a;信息函数 第一节 11.1 ISBLANK函数 11.1.1 简介 ISBLANK函数是Excel中的一个信息函数&#xff0c;用于检查指定单元格是否为空。该函数返回布尔值&#xff1a;如果单元格为空&#xff0c;返回TRUE&#xff1b;否则返回FALSE。ISBLANK函数在数据清理、条件…

楼道灯微波雷达模块模组,智能感应uA级超低功耗替换红外传感器,飞睿助力绿色照明

随着科技的飞速发展&#xff0c;LED楼道灯早已不仅仅是照亮我们回家路的工具&#xff0c;它们正变得越来越智能、高效和环保。今天&#xff0c;就让我们一起探索LED楼道灯背后的科技——飞睿智能微波雷达模块模组&#xff0c;以及它如何以超低功耗&#xff08;uA级别&#xff0…

thinkphp8框架源码精讲

前言 很开心你能看到这个笔记&#xff0c;相信你对thinkphp是有一定兴趣的&#xff0c;正好大家都是志同道合的人。 thinkphp是我入门学习的第一个框架&#xff0c;经过这么多年了&#xff0c;还没好好的研究它&#xff0c;今年利用了空闲的时间狠狠的深入源码学习了一把&…

将 Vision Transformer 用于医学图像的语义分割

关于ViT的关键点如下&#xff1a; ViT架构基于将图像表示为一组补丁。图像补丁是图像的非重叠块。每个块最初都有一个由该块中的图像像素形成的嵌入向量。Transformer编码器是ViT的主要部分&#xff0c;它根据它们的类别归属来训练补丁之间的相似度。它包含一系列线性、归一化…

什么是RLHF(基于人类反馈的强化学习)?

什么是RLHF&#xff08;基于人类反馈的强化学习&#xff09;&#xff1f; 基于人类反馈的强化学习&#xff08;Reinforcement Learning from Human Feedback, RLHF&#xff09;是一种结合强化学习和人类反馈的技术&#xff0c;用于训练智能体&#xff0c;使其行为更符合人类期…

叉车司机疲劳检测系统解决方案

在日益繁忙的物流仓储和工业制造领域&#xff0c;叉车司机的工作强度逐渐增大&#xff0c;疲劳驾驶的风险也随之提升。因此&#xff0c;我们提出了一套能够准确检测叉车司机疲劳状态的系统&#xff0c;以确保驾驶安全&#xff0c;提高工作效率。 安全监控功能主要透过三颗独立摄…

科普丨企业防泄密有哪些方法?10个防泄密技巧推荐

在信息化高速发展的今天&#xff0c;企业数据安全已成为企业运营的核心议题。随着信息技术的发展和市场竞争的加剧&#xff0c;企业面临的泄密风险越来越大&#xff0c;尤其是商业机密和敏感数据的泄露&#xff0c;会对企业的经济效益、品牌信誉乃至法律地位构成严重威胁。因此…

学习测试8-数据库mysql操作

下载配置mysql 网络博客 使用 在Linux里 1 service mysql start 启动服务 2 在Navicatt 中连接Linux服务器 3 第一步 将所有文件上传到/opt目录下 第二步 chmod 777 deploy-mysql.sh 第三步 ./deploy-mysql.sh4 service mysql status 查看状态是否安装成功 5 重启mys…

分布式训练

一、分布式计算 跟多GPU不同是&#xff1a;数据不是从主存拿的&#xff0c;是在分布式文件系统拿的&#xff0c;有多个工作站&#xff0c;工作站中有多个GPU&#xff0c;通过网络读取数据到GPU中&#xff0c;GPU通过网络接收到来自参数服务器的参数进行运算计算梯度&#xff0c…

【C++深度探索】全面解析多态性机制(一)

hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;大耳朵土土垚的博客 &#x1…

与沃尔玛进行EDI对接,需要了解什么?如何实现EDI对接呢?

与沃尔玛进行EDI对接前&#xff0c;需要了解什么呢&#xff1f; 首先&#xff0c;需要了解什么是EDI&#xff1f; EDI&#xff08;Electronic Data Interchange&#xff09;即电子数据交换&#xff0c;借助EDI使得企业&#xff08;计算机/应用系统&#xff09;与企业&#xff…

腰肌筋膜炎最好的治疗方法

腰部疼痛是腰肌筋膜炎的主要症状&#xff0c;这种疼痛可能是隐痛、酸痛或肿胀痛&#xff0c;且疼痛可能呈持续性或间歇性。在长时间站立、坐姿、弯腰或腰部受寒着凉后&#xff0c;疼痛通常会加重。疼痛可能会扩散到腰部的其他区域&#xff0c;甚至可能影响到臀部或大腿后侧。疼…

基于springboot+mybatis学生管理系统

基于springbootmybatis学生管理系统 简介&#xff1a; 题目虽然是学生管理系统&#xff0c;但功能包含(学生&#xff0c;教师&#xff0c;管理员),项目基于springboot2.1.x实现的管理系统。 编译环境 &#xff1a; jdk 1.8 mysql 5.5 tomcat 7 框架 &#xff1a; springboot…

W外链短网址平台怎么样?抖音/小红书/快手/微信卡片生成

在当今数字化时代&#xff0c;网址的便捷性和易记性对于用户体验和网站推广至关重要。短网址技术应运而生&#xff0c;以其简洁、易记、方便分享的特性&#xff0c;逐渐成为网站优化和推广的重要手段之一。其中&#xff0c;W外链作为一个功能全面的短网址服务平台&#xff0c;以…

mavlink协议解析

1. mavlink数据包格式 字节索引C 版本内容值说明0uint8_t magic数据包启动标记0xFE特定于协议的文本启动 (stx) 标记, 用于指示新数据包的开始。 任何不识别协议版本的系统都将跳过数据包。1uint8_t len载荷长度0 - 255指示以下 payload 部分的长度 (为特定消息固定)。2uint8_t…

一款永久免费的内网穿透工具——巴比达

近期&#xff0c;一款名为巴比达的内网穿透工具凭借其永久免费的特性&#xff0c;以及卓越的性能与安全性&#xff0c;引起了我的关注。本文将深入探讨巴比达如何通过其独创的技术方案&#xff0c;达到企业级数据通信要求。 WanGooe Tunnel协议 首先&#xff0c;巴比达的核心竞…

矩阵管理系统实现后台统一管理的解决方案

在当今数字化浪潮中&#xff0c;企业面临着前所未有的挑战与机遇。如何快速响应市场变化、提升运营效率、降低管理成本&#xff0c;成为众多企业关注的焦点。而矩阵管理系统作为一种新兴的管理工具&#xff0c;凭借其强大的后台统一管理能力&#xff0c;正成为越来越多企业的首…

适合学生写作业的台灯怎么选?一文读懂护眼台灯怎么选!

不知大家发现没有&#xff0c;近些年&#xff0c;戴眼镜的小孩儿是越来越多了&#xff0c;甚至有的地方好多刚上小学一年级的孩子&#xff0c;就已经戴着200度的近视镜了。据统计&#xff0c;如今&#xff0c;中国小学生近视比例为42%&#xff0c;初中生近视比例为80.7%&#x…

技校专业群的生成机制研究

一、引言 随着我国经济的快速发展和产业结构的不断优化&#xff0c;技术型人才的需求日益旺盛。技工学校&#xff08;简称技校&#xff09;作为培养技术型人才的摇篮&#xff0c;其专业群的构建与发展显得尤为重要。专业群作为技校战略发展的核心&#xff0c;不仅能够优化教学…

项目三层架构详情

三层架构 三层架构就是为了符合“高内聚&#xff0c;低耦合”思想&#xff0c;把各个功能模块划分为表示层&#xff08;UI&#xff09;、业务逻辑层&#xff08;BLL&#xff09;和数据访问层&#xff08;DAL&#xff09;三层架构&#xff0c;各层之间采用接口相互访问&#xf…