简介
文章主要讲述在vue3项目中使用elementui框架实现复杂表单的方式。表单中涉及动态组件的生成、文件上传和富文本编辑器的使用,只会将在实现过程中较复杂的部分进行分享,然后提供一份完整的前端代码。
表单效果演示
基础信息
spu属性
sku详情
关键点
动态组件的处理
在spu属性步骤中,CPU型号、操作系统和生物解锁三个属性都是动态生成的。
实现原理
组件动态生成和删除的原理是通过操作v-for组件的数据源实现的。向数据源添加数据会动态生成组件,将数据源的数据减少就会删除对应的组件。
所以在点击添加属性时,只要向v-for的数据源中添加属性配置,就能实现动态生成组件的效果。
组件的类型、可选值都是提前定义的。
分析JD、淘宝等各类商城关于spu属性的展示,可以发现基本可以用自定义、单选和多选属性把所有spu属性覆盖。
因此就可以提前将商品可用的属性按类型和可选值完成定义,在页面选择对应属性添加到页面即可。
动态添加spu属性的代码
只需要重点关注 addSpuItem、rmAttr 方法和 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>