.markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rgba(37, 41, 51, 1) }
.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6 { line-height: 1.5; margin-top: 35px; margin-bottom: 10px; padding-bottom: 5px }
.markdown-body h1 { font-size: 24px; line-height: 38px; margin-bottom: 5px }
.markdown-body h2 { font-size: 22px; line-height: 34px; padding-bottom: 12px; border-bottom: 1px solid rgba(236, 236, 236, 1) }
.markdown-body h3 { font-size: 20px; line-height: 28px }
.markdown-body h4 { font-size: 18px; line-height: 26px }
.markdown-body h5 { font-size: 17px; line-height: 24px }
.markdown-body h6 { font-size: 16px; line-height: 24px }
.markdown-body p { line-height: inherit; margin-top: 22px; margin-bottom: 22px }
.markdown-body img { max-width: 100% }
.markdown-body hr { border-top: 1px solid rgba(221, 221, 221, 1); border-right: none; border-bottom: none; border-left: none; margin-top: 32px; margin-bottom: 32px }
.markdown-body code { border-radius: 2px; overflow-x: auto; background-color: rgba(255, 245, 245, 1); color: rgba(255, 80, 44, 1); font-size: 0.87em; padding: 0.065em 0.4em }
.markdown-body code, .markdown-body pre { font-family: Menlo, Monaco, Consolas, Courier New, monospace }
.markdown-body pre { overflow: auto; position: relative; line-height: 1.75 }
.markdown-body pre>code { font-size: 12px; padding: 15px 12px; margin: 0; word-break: normal; display: block; overflow-x: auto; color: rgba(51, 51, 51, 1); background: rgba(248, 248, 248, 1) }
.markdown-body a { text-decoration: none; color: rgba(2, 105, 200, 1); border-bottom: 1px solid rgba(209, 233, 255, 1) }
.markdown-body a:active, .markdown-body a:hover { color: rgba(39, 91, 140, 1) }
.markdown-body table { display: inline-block !important; font-size: 12px; width: auto; max-width: 100%; overflow: auto; border: 1px solid rgba(246, 246, 246, 1) }
.markdown-body thead { background: rgba(246, 246, 246, 1); color: rgba(0, 0, 0, 1); text-align: left }
.markdown-body tr:nth-child(2n) { background-color: rgba(252, 252, 252, 1) }
.markdown-body td, .markdown-body th { padding: 12px 7px; line-height: 24px }
.markdown-body td { min-width: 120px }
.markdown-body blockquote { color: rgba(102, 102, 102, 1); padding: 1px 23px; margin: 22px 0; border-left: 4px solid rgba(203, 203, 203, 1); background-color: rgba(248, 248, 248, 1) }
.markdown-body blockquote:after { display: block; content: "" }
.markdown-body blockquote>p { margin: 10px 0 }
.markdown-body ol, .markdown-body ul { padding-left: 28px }
.markdown-body ol li, .markdown-body ul li { margin-bottom: 0; list-style: inherit }
.markdown-body ol li .task-list-item, .markdown-body ul li .task-list-item { list-style: none }
.markdown-body ol li .task-list-item ol, .markdown-body ol li .task-list-item ul, .markdown-body ul li .task-list-item ol, .markdown-body ul li .task-list-item ul { margin-top: 0 }
.markdown-body ol ol, .markdown-body ol ul, .markdown-body ul ol, .markdown-body ul ul { margin-top: 3px }
.markdown-body ol li { padding-left: 6px }
.markdown-body .contains-task-list { padding-left: 0 }
.markdown-body .task-list-item { list-style: none }
@media (max-width: 720px) { .markdown-body h1 { font-size: 24px } .markdown-body h2 { font-size: 20px } .markdown-body h3 { font-size: 18px } }.markdown-body pre, .markdown-body pre>code.hljs { color: rgba(51, 51, 51, 1); background: rgba(248, 248, 248, 1) }
.hljs-comment, .hljs-quote { color: rgba(153, 153, 136, 1); font-style: italic }
.hljs-keyword, .hljs-selector-tag, .hljs-subst { color: rgba(51, 51, 51, 1); font-weight: 700 }
.hljs-literal, .hljs-number, .hljs-tag .hljs-attr, .hljs-template-variable, .hljs-variable { color: rgba(0, 128, 128, 1) }
.hljs-doctag, .hljs-string { color: rgba(221, 17, 68, 1) }
.hljs-section, .hljs-selector-id, .hljs-title { color: rgba(153, 0, 0, 1); font-weight: 700 }
.hljs-subst { font-weight: 400 }
.hljs-class .hljs-title, .hljs-type { color: rgba(68, 85, 136, 1); font-weight: 700 }
.hljs-attribute, .hljs-name, .hljs-tag { color: rgba(0, 0, 128, 1); font-weight: 400 }
.hljs-link, .hljs-regexp { color: rgba(0, 153, 38, 1) }
.hljs-bullet, .hljs-symbol { color: rgba(153, 0, 115, 1) }
.hljs-built_in, .hljs-builtin-name { color: rgba(0, 134, 179, 1) }
.hljs-meta { color: rgba(153, 153, 153, 1); font-weight: 700 }
.hljs-deletion { background: rgba(255, 221, 221, 1) }
.hljs-addition { background: rgba(221, 255, 221, 1) }
.hljs-emphasis { font-style: italic }
.hljs-strong { font-weight: 700 }

说点废话,最近在做一个重构的项目。我感觉学不到东西,业务也就那样。这个简单的我感觉要是之前的我。我就很快做出来了,这次我做了相对久了。很难受。吐槽一下吧,这个项目代码经过很多人说是屎山也不为过。但是搭建确实做的很好,应该仔细研究学习一下。

上成品

数据格式

这次做的久很大一部分原因是我直接就做了,并没有考虑数据,在做着做着就会出现很问题。开发很重要一点先定义数据,再根据数据生成相应的页面。

错误的原因是一开始取巧了打算利用subOrdershoppingList 里面有的数据作为shoppingShow 展示的数据在这里所以在显示开发的时候总有些问题。没有设计数据格式,打算利用subOrdershoppingLis反而浪费了很多时间。


[
{
"interfaceSubOrderId": "1",
"subOrderName": "子订单1",
"subOrdershoppingList": [],
"interfaceOrderId": "1",
"parentOrderName": "父订单1",
"packageList": [
{
"expressName": "",
"expressNo": "",
"expressCode": "",
"shoppingShow": [],
"packageChildren": [
{
"expressName": "",
"expressNo": "",
"expressCode": "",
"shoppingShowChildren": []
},
{
"expressName": "",
"expressNo": "",
"expressCode": "",
"shoppingShowChildren": []
},
{
"expressName": "",
"expressNo": "",
"expressCode": "",
"shoppingShowChildren": []
}
]
},
{
"expressName": "",
"expressNo": "",
"expressCode": "",
"shoppingShow": [],
"packageChildren": [
{
"expressName": "",
"expressNo": "",
"expressCode": "",
"shoppingShowChildren": []
}
]
}, ]
}
]

页面展示

<el-dilog :title="title" v-model="modelValue" @close="closeGroup">
<div
class="select-table-main"
v-for="v in deliverGoodsData.newGoodList"
:key="v.interfaceSubOrderId"
>
<div class="select-table-title">
<h3>子订单号:{{ v.interfaceSubOrderId }}</h3>
<el-button type="text" @click="addGroup(v.interfaceSubOrderId)"
>添加包裹</el-button
>
</div>
<el-form label-width="80px" class="form-detail">
<el-form-item
:label="'包裹' + (index + 1) + ':'"
v-for="(item, index) in v.packageList"
:key="index"
>
<el-select
style="display: inline-block; width: 150px; margin-left: 10px"
v-model="item.expressName"
placeholder="请选择物流"
filterable
>
<el-option
v-for="it in deliverGoodsData.expressCompanyList"
:label="it.dictValue"
:value="it.dictValue"
:key="it.dictValue"
></el-option>
</el-select>
<el-input
style="display: inline-block; width: 260px"
v-model="item.expressNo"
placeholder="请输入快递单号"
></el-input>
<el-button v-if="index != 0" type="text" @click="ycFun(index)"
>移除</el-button
>
<el-button
type="text"
@click="
handleSelectGood({
pitchShopIndex: index,
type: null,
data: v.subOrdershoppingList,
})
"
>选择商品</el-button
>
<el-button
type="text"
@click="addDeliver(index, v.interfaceSubOrderId)"
>添加子包裹</el-button
>
<div>
<div
v-for="sle in item.shoppingShow"
:key="sle.id"
style="margin-left: 10px; font-size: 12px; color: gray"
>
<div v-if="sle.number">
{{ sle.showTitle }}&nbsp;&nbsp; {{ sle.specsName }}*{{
sle.number
}}
</div>
</div>
</div> <el-form-item
:label="'子包裹' + (subindex + 1) + ':'"
v-for="(pac, subindex) in item.packageChildren"
:key="subindex"
>
<el-select
style="display: inline-block; width: 150px; margin-left: 10px"
v-model="pac.expressName"
placeholder="请选择物流"
filterable
>
<el-option
v-for="exp in deliverGoodsData.expressCompanyList"
:label="exp.dictValue"
:value="exp.dictValue"
:key="exp.dictValue"
></el-option>
</el-select>
<el-input
style="display: inline-block; width: 180px"
v-model="pac.expressNo"
placeholder="请输入快递单号"
></el-input>
<el-button
v-if="subindex != 0"
type="text"
@click="subYcFun(index, subindex)"
>移除</el-button
>
<el-button
type="text"
@click="
handleSelectGood({
pitchShopIndex: index,
subPitchShopIndex: subindex,
type: 'sub',
data: v.subOrdershoppingList,
})
"
>选择子商品</el-button
>
<div
v-for="subSle in pac.shoppingShowChildren"
:key="subSle.id"
style="margin-left: 10px; font-size: 12px; color: gray"
>
<div v-if="subSle.number">
{{ subSle.showTitle }}&nbsp;&nbsp; {{ subSle.specsName }}*{{
subSle.number
}}
</div>
</div>
</el-form-item>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="default" @click="closeGroup">取消</el-button>
<el-button type="primary" @click="submit">确认</el-button>
</div>
</template>
</el-dilog>

其实这个现在想想很简单只要维护packageList就可以了。期间遇到一个问题在改变数据的时候不回显,这个项目用的是vue3 确是vue2和vue3混合写很恶心。我又全删了重新写的vue3.
在vue2 使用$set 解决 在vue3直接使用 reactive就可以了 computed 并不会随着数组更新而影响视图变化


const deliverGoodsData = reactive({
expressCompanyList: [], // 快递公司列表
subDeliver: false,
tableGoods: [],
newGoodList: [],
pitchShopIndex: null,
subPitchShopIndex: null,
}) const selectGoodsRef = ref() const props = defineProps({
modelValue: Boolean,
rowData: {
type: Object,
default: function () {
return {}
},
},
title: {
type: String,
default: function () {
return '订单发货'
},
},
opeType: {
//操作类型 delivery发货,changeEms变更物流
type: String,
default: function () {
return 'delivery'
},
},
sendType: {
//发货 send 与 变更发货状态 change(无移除,无添加包裹)
type: String,
default: function () {
return 'send'
},
},
}) const emit = defineEmits(['updateTable', 'modelValue']) watch(
() => props.rowData,
(newData, oldData) => {
if (newData) {
let newSubOrderList = newData.map((v) => v.interfaceSubOrderId)
let arr = []
newSubOrderList.map((v) => {
newTableData.forEach((i) => {
i.subOrderList.filter((sub, index) => {
sub.packageList = [
{
expressName: '', //快递名称
expressNo: '', //快递单号
expressCode: '',
shoppingShow: [],
packageChildren: [
{
expressName: '', //快递名称
expressNo: '', //快递单号
expressCode: '',
shoppingShowChildren: [],
},
],
},
]
if (sub.interfaceSubOrderId === v) {
arr.push(sub)
}
})
})
}) console.log('arr: ', arr)
deliverGoodsData.newGoodList = arr
}
},
{ deep: true, immediate: true },
) onMounted(() => {
globalApi.queryDictsByAlias('ExpressCompany').then((res) => {
deliverGoodsData.expressCompanyList = res.data
})
}) const subPitchData = (data) => {
deliverGoodsData.newGoodList = deliverGoodsData.newGoodList.map((item) => {
item.packageList[deliverGoodsData.pitchShopIndex].packageChildren[
deliverGoodsData.subPitchShopIndex
].shoppingShowChildren = item.subOrdershoppingList.filter((v) => {
if (data.includes(v.id)) {
// v.subShowGoods = true
return v
}
})
return item
})
} const pitchData = (data) => {
deliverGoodsData.newGoodList = deliverGoodsData.newGoodList.map((item) => {
item.packageList[deliverGoodsData.pitchShopIndex].shoppingShow =
item.subOrdershoppingList.filter((v) => {
if (data.includes(v.id)) {
// v.showGoods = true
return v
}
})
return item
})
} const closeGroup = () => {
emit('update:modelValue', false)
} const addGroup = (id) => {
deliverGoodsData.newGoodList.forEach((item) => {
if (item.interfaceSubOrderId === id) {
item.packageList.push({
expressName: '', //快递名称
expressNo: '', //快递单号
expressCode: '',
shoppingShow: [],
packageChildren: [
{
expressName: '', //快递名称
expressNo: '', //快递单号
expressCode: '',
shoppingShowChildren: [],
},
],
})
}
})
} const addDeliver = (index, id) => {
deliverGoodsData.newGoodList.forEach((item) => {
if (item.interfaceSubOrderId === id) {
item.packageList[index].packageChildren.push({
expressName: '', //快递名称
expressNo: '', //快递单号
expressCode: '',
shoppingShowChildren: [],
})
}
})
} const subYcFun = (index, subIndex) => {
deliverGoodsData.newGoodList.forEach((item) => {
item.packageList[index].packageChildren.splice(subIndex, 1)
})
} const ycFun = (index) => {
deliverGoodsData.newGoodList.forEach((item) => {
item.packageList.splice(index, 1)
})
} const handleSelectGood = (selData) => {
let { pitchShopIndex, subPitchShopIndex, type, data } = selData
deliverGoodsData.tableGoods = data
deliverGoodsData.subPitchShopIndex = subPitchShopIndex
deliverGoodsData.pitchShopIndex = pitchShopIndex
if (type === 'sub') {
deliverGoodsData.subDeliver = true
} else {
deliverGoodsData.subDeliver = false
}
selectGoodsRef.value.goodsModel = true
} const submit = () => {}
const getQueryOrderPackageList = () => {}
</script> <style scoped lang="stylus">
.icon-style {
font-size: 20px;
color: #ff9900;
position: reactive;
top: 3px;
margin-right: 5px;
}
.select-table-main{
background-color rgba(242, 242, 242, 1)
padding 10px
}
.select-table-title{
display: flex;
justify-content: space-between; }
</style>

vue3实现多层级的动态表单增减的更多相关文章

  1. antd+vue3实现动态表单的自动校验

    由于vue3用的人还不多,所以有些问题博主踩了坑只能自己爬出来了,特此做个记录.如有错误,请大家指正. 回归正题,我所做的业务是,动态添加表单项,对每一项单独做校验,效果如下: 主要代码如下: 1 & ...

  2. K3CLOUD开发-动态表单树形单据体实现银行交易对账

    背景:系统手机开单生成销售单据,通过银行pos机收款,系统收款流水与银行流水可能存在差异,所以通过获取银行接口,获取消费信息自动插入到生产系统数据库,开发对账报表,实现差异汇总! 展示效果如下: 开发 ...

  3. [K/3Cloud] 如何从被调用的动态表单界面返回数据

    在需要返回数据的地方调用表单返回方法完成数据返回 this.View.ReturnToParentWindow(retData); 在调用界面的回调函数中取出返回结果的ReturnData即可使用. ...

  4. Vue+Element的动态表单,动态表格(后端发送配置,前端动态生成)

    Vue+Element的动态表单,动态表格(后端发送配置,前端动态生成) 动态表单生成 ElementUI官网引导 Element表单生成 Element动态增减表单,在线代码 关键配置 templa ...

  5. 简易OA漫谈之工作流设计(六,快捷表单和动态表单)

    如果没有表单设计功能,我们一般建物理表,再把表单挂接到流程, 我们可以把外接表单的地址填到表单地址中,地址中会传递一个id. 如果使用外接表单,在审批的时候可能会“不太友好”,因为在审批单上看不到任何 ...

  6. angularjs 动态表单, 原生事件中调用angular方法

    1. 原生事件中调用angular方法, 比如 input的onChange事件想调用angular里面定义的方法 - onChange="angular.element(this).sco ...

  7. vue 开发系列(八) 动态表单开发

    概要 动态表单指的是我们的表单不是通过vue 组件一个个编写的,我们的表单是根据后端生成的vue模板,在前端通过vue构建出来的.主要的思路是,在后端生成vue的模板,前端通过ajax的方式加载后端的 ...

  8. Struts动态表单(DynamicForm)

    动态表单的含义是不要手动定义,直接在配置文件中进行定义. 1.手动进行定义 <form-beans > <form-bean name="userForm" ty ...

  9. 如何在.Net Core MVC中为动态表单开启客户端验证

    非Core中的请参照: MVC的验证 jquery.validate.unobtrusive mvc验证jquery.unobtrusive-ajax 参照向动态表单增加验证 页面引入相关JS: &l ...

  10. Angular动态表单生成(八)

    动态表单生成之拖拽生成表单(下) 我们的动态表单,最终要实现的效果与Form.io的在线生成表单的效果类似,可以参考它的demo地址:https://codepen.io/travist/full/x ...

随机推荐

  1. 【Uni-APP】02 FLEX 弹性布局

    新建一个项目: 注释所有内容: <template> <!-- <view class="content"> <image class=&quo ...

  2. NVIDIA显卡的利用率“Volatile GPU Util"是什么???

    相关: CPU端多进程/多线程调用CUDA是否可以加速??? 如何实现nvidia显卡的cuda的多kernel并发执行??? ==================================== ...

  3. Functional PHP (通义千问)

    Functional PHP 是一个专为 PHP 开发者设计的库,旨在引入函数式编程的概念和工具,帮助开发者编写更高效.可读性强的代码.以下是几个使用 Functional PHP 库进行函数式编程的 ...

  4. 记一次 .NET某智慧出行系统 CPU爆高分析

    一:背景 1. 讲故事 前些天有位朋友找到我,说他们的系统出现了CPU 100%的情况,让你帮忙看一下怎么回事?dump也拿到了,本想着这种情况让他多抓几个,既然有了就拿现有的分析吧. 二:WinDb ...

  5. 一种PyInstaller中优雅的控制包大小的方法

    PyInstaller会在打包时自动为我们收集一些依赖项,特别是我们在打包PyQt/PySide相关的应用时,PyInstaller会自动包含我们程序通常不需要的文件,如'tanslations'文件 ...

  6. 电商API接口应该如何使用?

    从定义上看,API接口是指预先定义的一组规则和协议,允许不同的软件应用之间相互通信和交换数据. 目前,市场中电商行业用到API接口的场景较多,电商API接口则是专门针对电子商务应用场景所提供的API, ...

  7. PHP 程序员学会了 Go 语言就能唬住面试官吗?

    大家好,我是码农先森. 唬住了 50k ,唬不住就 5k .这句话一直是 PHP 程序员之间相互吹捧.吹牛逼的笑点,每次面试过后都会挠挠头上仅剩的几根头发,回想自己是否吹牛逼会过了头.我经常在微信程序 ...

  8. 闲的蛋疼整理了一下Dockerfile的命令和参数备查

    Dockerfile 主要指令及参数: 指令 主要参数 作用 用法示例 FROM <image>[:<tag>] [AS <name>] 指定基础镜像 FROM u ...

  9. ASP.NET Core – Razor Pages 冷知识

    Multiple Form Binding 问题 在一个 page 里面有 2 张 form, 那么就会有 2 个 model binding. 当任何一个 submit 的时候. 由于 2 个 mo ...

  10. ASP.NET Core – 读写 Request / Response

    需求 常见的需求就是从 request 里面读取一些 information. 比如 request URL, header, cookie, 写入 response header, cookie 实 ...