.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. Jax框架的Traced object特性与TensorFlow的placeholder的一致性

    前文: Jax框架的static与Traced Operations -- Static vs Traced Operations 前文讨论分析了Jax的static特性和Traced特性,这些谈下个 ...

  2. mendeley存储是有限的吗

    用了mendeley好多年,总是有一个疑问,那就是这东西的云存储空间是不是有限的,如果是有限的话那么上限是多少?这东西不论是app还是桌面端都没有这个空间信息的大小,但是这东西必然是有上限的,那么这个 ...

  3. 拈花云科基于 Apache DolphinScheduler 在文旅业态下的实践

    作者|云科NearFar X Lab团队 左益.周志银.洪守伟.陈超.武超 一.导读 无锡拈花云科技服务有限公司(以下简称:拈花云科)是由拈花湾文旅和北京滴普科技共同孵化的文旅目的地数智化服务商.20 ...

  4. 零基础学习人工智能—Python—Pytorch学习(三)

    前言 这篇文章主要两个内容. 一,把上一篇关于requires_grad的内容补充一下. 二,介绍一下线性回归. 关闭张量计算 关闭张量计算.这个相对简单,阅读下面代码即可. print(" ...

  5. MPTCP(六):MPTCP测试

    MPTCP测试 1.注意事项 测试主机已替换支持MPTCPv1的内核,并且已使能MPTCP,本次测试中使用的内核版本均为5.18.19 测试主机中确保已经正确配置了iproute2 和 mptcpd, ...

  6. Linux驱动小技巧 | 利用DRIVER_ATTR实现调用内核函数

    1. 前言 很多朋友在调试驱动的时候,都会遇到这样一个场景: 修改一个参数,然后调用某个内核中的函数. 比如将某个gpio的值拉高/拉低,修改某个寄存器的值等等. 如果每一个参数都通过字符设备的ioc ...

  7. containerd在线部署

    containerd的作用以及跟docker的区别 Containerd是一个用于管理容器生命周期的开源项目.它最初是从Docker项目中分离出来的,现在已经成为了一个独立的项目.它可以用作容器镜像管 ...

  8. Microsoft Ignite 2022 After Party (Placeholder)

    通过Microsoft Ignite 2022了解最新的创新成果,向产品专家和合作伙伴学习,优化自身技能组合,并与来自世界各地的人士建立联系.请于 PDT 时间 10 月 12 日至 14 日早上 9 ...

  9. [Linux]yum下载慢!!

    有全局代理,但是yum下载特别慢,怎么办? 确保/etc/yum.conf文件中代理配置的语法正确,包括代理服务器的地址和端口号,如下所示: proxy=http://your_proxy_serve ...

  10. JMESPath 使用

    最近在学习使用 AWS CLI,经常要用到 query 功能.AWS CLI 使用的查询语法是 JMESPath,因此特地在这里记录常用的 JMESPath 语法. JMESPath 是一种查询语言, ...