uniapp-商城-60-后台 新增商品(属性的选中和页面显示,数组join 的使用)

news2025/5/20 20:13:06

        前面添加了属性,添加属性的子级项目。也分析了如何回显,但是在添加新的商品的时,我们也同样需要进行选择,还要能正常的显示在界面上。下面对页面的显示进行分析。

1、界面情况回顾

属性显示其实是个一嵌套的数据显示。

2、选中的界面

3、页面显示

使用了函数方法skuChildName,

还使用了点击就弹窗在两个地方都用了。clickSelect

对于默认显示:还用到了skuTitle 计算接口,

当然这个接口也可以用方法来做,但这里值都可以取得,所以就用这方法。

前一个章节讲了显示,需要添加一个view 进行显示:

4、相应显示的需要的方法 skuChildName

方法很简单,就是将读取的数据,arr数组,找出数组中的name ,然后对name进行/ 拼接

注意使用的方法   map

对数组中的值 使用  / 进行拼接。

注意这里只是计算了 子级 项的name  

            //属性返回子元素的名称
            skuChildName(arr) {
                let nsArr = arr.map(item => {
                    return item.name
                })
                return nsArr.join("/")
            },

5、计算页面的显示,如果没有值,那么就显示点击添加属性

是一个计算值的接口,默认是显示点击添加属性

如果this.goodsFormData.sku_select.length 不为0 ,就显示属性值中的name,用到的用 jion   /  链接

注意不是 children,这里只是计算了父级 属性

在页面上显示 也是直接用了该函数名字

        computed: {
            skuTitle() {
                if (this.goodsFormData.sku_select.length) {
                    let arr = this.goodsFormData.sku_select.map(item => {
                        return item.skuName
                    })
                    return arr.join("/")
                } else {
                    return "点击添加属性"
                }
            }
        },

            <uni-forms-item label="商品属性" >
                <u-cell :title="skuTitle" isLink :border="false" @click="clickSelect"></u-cell>
                <view class="skuList">
                    <view class="item" v-for="item in goodsFormData.sku_select" @click="clickSelect">
                        <view class="left">{{item.skuName}}:</view>
                        <view class="right">{{skuChildName(item.children)}}</view>
                    </view>
                </view>
            </uni-forms-item>

6 整体的代码(除开商品,属性这一栏 界面的  全都有了)

<template>
	<view class="goodsView">
		<!-- 添加商品 -->
		<uni-forms ref="goodsForm" :model="goodsFormData" :rules="goodsRules" :label-width="100" label-align="right">
			<uni-forms-item label="商品图片" required="true">
				<uni-file-picker v-model="goodsFormData.thumb" fileMediatype="image" mode="grid" ></uni-file-picker>
			</uni-forms-item>

			<uni-forms-item label="商品名称" required name="name" >
				<!-- trim 去空格 -->
				<uni-easyinput v-model="goodsFormData.name" placeholder="请输入商品名称" trim="both"></uni-easyinput>
			</uni-forms-item>

			<uni-forms-item label="产品分类" required name="category_id">
				<!-- 云端数据  下拉框获取  field 就是获取的内容  一定要写成 value text 这是官方定义的  value选中的值,text显示的文本,也就是value后台用,text前台用 -->
				<!-- 利用这个组件就实现了后端数据库的读取 -->
				<uni-data-select collection="green-mall-categories" field="_id as value, name as text"
					v-model="goodsFormData.category_id"></uni-data-select>
			</uni-forms-item>

			<uni-forms-item label="商品价格" required name="price">
				<!-- trim 去空格 -->
				<uni-easyinput type="number" v-model="goodsFormData.price" placeholder="请输入商品价格"
					trim="both"></uni-easyinput>
			</uni-forms-item>

			<uni-forms-item label="商品原价">
				<!-- trim 去空格 -->
				<uni-easyinput type="number" v-model="goodsFormData.before_price" placeholder="请输入原价"
					trim="both"></uni-easyinput>
			</uni-forms-item>

			<uni-forms-item label="商品属性" >
				<u-cell :title="skuTitle" isLink :border="false" @click="clickSelect"></u-cell>
				<view class="skuList">
					<view class="item" v-for="item in goodsFormData.sku_select" @click="clickSelect">
						<view class="left">{{item.skuName}}:</view>
						<view class="right">{{skuChildName(item.children)}}</view>
					</view>
				</view>
			</uni-forms-item>

			<uni-forms-item label="商品描述">
				<!-- type 是类型  textarea 就是大框 -->
				<uni-easyinput type="textarea" placeholder="请输入详细的描述信息"
					v-model="goodsFormData.description"></uni-easyinput>
			</uni-forms-item>

			<view class="btnView">
				<button type="primary" @click="onSubmit">确认提交</button>
			</view>

		</uni-forms>


		<uni-popup ref="attrWrapPop" type="bottom">
			<!-- 底部弹出 type 
			 ref 是一个名字属性,便于被调用 给 clickSelect 
			 在 clickSelect 函数中调用了该接口
			 -->
			<view class="attrWrapper">
				<!-- 分三部分  就是上中下 头身体和尾部 -->
				<view class="head">
					<view class="title">商品属性</view>
					<!-- clickAddAttr函数  添加属性的-->
					<view class="addAttr" @click="clickAddAttr()">+ 添加属性</view>
				</view>

				<view class="body">
					<!-- 读取 skuArr 循环显示 分两部分显示 top 和 btngroup-->
					<view class="item" v-for="(item,index) in skuArr">
						<view class="top">
							<checkbox :checked="item.checked" @click="changeCheckbox(index)"></checkbox>
							<!-- changeCheckbox  选中就做这个操作 -->
							<!-- checked 是否被选中的属性标识 -->
							<view class="font">{{item.skuName}}</view>
						</view>
						<view class="btnGroup" v-if="item.checked">
							<!-- 需要判断checked 是不是true  是不是选中,选中了就展示-->
							<view class="btn" :class="child.checked?'active':''" v-for="(child,cIdx) in item.children"
								@click="clickChlidBtn(index,cIdx)">{{child.name}}</view>
								<!-- btn 读取skuArr ,循环显示
								选中就加class 为active  
								点击 就执行 clickChlidBtn函数
								-->
							<view class="btn" @click="clickAddAttr(index)">
								<!-- btn 该盒子就是一个 + 号,用来添加该属性下的选项 
								 clickAddAttr 点就执行
								 uicon就一个 + 号图标  
								 -->
								<u-icon name="plus"></u-icon>
							</view>
						</view>
					</view>
				</view>

				<view class="foot">
					<button type="primary" @click="clickConfirmSelect">确认选择</button>
					<!-- 按钮 ,蓝色提交按钮
					 type 就是颜色格式
					 点击就是确认该商品的属性
					 clickConfirmSelect
					 -->
				</view>
			</view>

			<view class="safe-area-bottom"></view>
			<!--防止被苹果虚拟home键 挡住 -->
			<!-- 
			这里就是直接调用的app.vue的全局样式。
			什么是全局样式:就是样式那里没有scoped 的,所以在以前老是要写一个表示局部样式,就怕vue 中class名字一样了
			如果你不些scoped ,就要把全局的view 的class 写在最前面。
			不知道懂不懂,慢慢悟吧
			-->
		</uni-popup>

		<!-- 这里是点击的添加属性的弹窗 -->
		<!-- 你可能懵逼了
		那个添加属性的弹窗?
		 两个弹窗都要用
		 一个是第一个弹窗中的右上角的添加属性  class名字 addAttr
		 一个是属性规格下的选项中的 + class的名字就是btn
		-->
		<uni-popup ref="addAttrPop">
			<uni-popup-dialog mode="input" title="新增" placeholder="请输入新增的内容"
				@confirm="dialogConfirm"></uni-popup-dialog>
				<!-- dialogConfirm 是一个确认后处理逻辑 -->
		</uni-popup>
	</view>
</template>

<script>
	const skuCloudObj = uniCloud.importObject("green-mall-sku", {
		"customUI": true
	});

	const goodsCloudObj = uniCloud.importObject("green-mall-goods", {
		"customUI": true
	})

	export default {
		data() {
			return {
				goodsFormData: {
					thumb: [],
					name: "",
					category_id: null,
					price: null,
					before_price: null,
					description: "",
					sku_select: []
				},
				addAttrType: "parent", //parent代表父,child代表子

				goodsRules: {
					name: {
						rules: [{
							required: true,
							errorMessage: "请输入产品名称"
						}]
					},
					price: {
						rules: [{
							required: true,
							errorMessage: "请输入产品价格"
						}]
					},
					category_id: {
						rules: [{
							required: true,
							errorMessage: "请输入产品分类"
						}]
					}
				},
				/*
				skuArr: [{
					_id:1,
					skuName:"颜色",
					checked:false,
					children:[{
						name:"红",
						checked:false
					},{
						name:"蓝",
						checked:false
					}]
				},{
					_id:2,
					skuName:"规格",
					checked:false,
					children:[{
						name:"M",
						checked:false
					},{
						name:"S",
						checked:false
					}]
				}],
				*/
				// 上面是一个数据结构例子,后台数据就应该着这样存
				// 实际是下面的[]
				skuArr: [],
			};
		},

		onLoad() {

		},

		computed: {
			skuTitle() {
				if (this.goodsFormData.sku_select.length) {
					let arr = this.goodsFormData.sku_select.map(item => {
						return item.skuName
					})
					console.log(arr);
					return arr.join("/")
				} else {
					return "点击添加属性"
				}
			}
		},


		methods: {
			//属性返回子元素的名称
			skuChildName(arr) {
				let nsArr = arr.map(item => {
					return item.name
				})
				return nsArr.join("/")
			},


			//点击确认选择 是在弹出框上选
			//some 数组至少有一个满足 没有就是false   every就是每一个都要满足,不满足就是false
			// 这里filter 选出父级属性 checked =true 被选中的 且子级属性有一个被选中的数组对象;
			// 然后再对选中的对象,逐一进行map运算
			//运算就是filter 过滤出来选中的子级元素
			//返回一个 数组 arr 且元素为一个对象,对象展开了item ,然后将children的值放到里面,覆盖item中的children
			clickConfirmSelect() {
				let arr = this.skuArr.filter(item => {
					let state = item.children.some(child => child.checked)  
					return item.checked && state
				}).map(item => {
					let children = item.children.filter(child => {
						return child.checked
					})
					// console.log(item,11111111);
					// console.log(children,2222222);
					return {
						...item,
						// children   //覆盖了item中children
					}
				})
				this.goodsFormData.sku_select = arr   //赋值后,页面在使用这个数组来显示  立即回显
				this.$refs.attrWrapPop.close();   //关闭掉弹窗
			},
			//获取sku列表
			async getSkuData() {
				let res = await skuCloudObj.get();
				this.skuArr = res.data
				// console.log(res);
			},


			//点击添加属性 index 存在就是嵌套下 父类属性的子类选项 ,不存在就是添加父类属性
			clickAddAttr(index = null) {
				if (index == null) {
					this.addAttrType = "parent"
					this.attrIndex = null
				} else {
					this.addAttrType = "child"
					this.attrIndex = index
				}
				this.$refs.addAttrPop.open();
			},
			//添加属性弹窗的确认按钮
			async dialogConfirm(e) {
				if (!e) return;
				if (this.addAttrType == "parent") {
					let obj = {
						skuName: e,
						checked: true,
						children: []
					}
					let res = await skuCloudObj.add(obj)
					obj._id = res.id;
					this.skuArr.push(obj)
					//向数组中添加一个元素,就弹窗的确认按钮

				} else if (this.addAttrType == "child") {
					let obj = {
						name: e,
						checked: true
					}
					let id = this.skuArr[this.attrIndex]._id;
					let res = await skuCloudObj.updateChild(id, obj)
					this.skuArr[this.attrIndex].children.push(obj)
				}
			},

			//点击属性的复选框	改变了值,也相应改变了显示 后面也把值存到了数据库
			changeCheckbox(index) {
				this.skuArr[index].checked = !this.skuArr[index].checked
			},

			//点击属性值的子元素  改变了值,也相应改变了显示 后面也把值存到了数据库
			clickChlidBtn(index, cIdx) {
				this.skuArr[index].children[cIdx].checked = !this.skuArr[index].children[cIdx].checked
			},


			//点击选择属性
			clickSelect() {
				this.$refs.attrWrapPop.open(); //使用open方法弹出来
				if (this.skuArr.length) return;
				this.getSkuData();

			},

			//点击提交表单
			onSubmit() {
				this.$refs.goodsForm.validate().then(res => {
					this.toDataBase();

				}).catch(err => {
					console.log(err);
				})
			},
			//上传到云数据库
			async toDataBase() {
				//这里缺少一个更新的按钮,需要在list中去实现
				this.goodsFormData.thumb = this.goodsFormData.thumb.map(item => {
					return {
						url: item.url,
						name: item.name,
						extname: item.extname
					}
				})

				let res = await goodsCloudObj.add(this.goodsFormData)
				uni.showToast({
					title: "新增商品成功"
				})
				setTimeout(() => {
					uni.navigateBack()
				}, 1500)

			}


		}
	}
</script>

<style lang="scss" scoped>
	.goodsView {
		padding: 30rpx;

		.skuList {
			.item {
				padding: 30rpx;
				background: $page-bg-color;
				margin: 15rpx 0;
				@include flex-box-set(start);
			}
		}
	}


	.attrWrapper {
		padding: 30rpx;
		background: #fff;
		border-radius: 20rpx 20rpx 0 0;

		.head {
			@include flex-box();
			font-size: 34rpx;
			margin-bottom: 30rpx;

			.title {
				font-weight: bold;
			}

			.addAttr {
				color: $brand-theme-color-aux;
			}
		}

		.body {
			.item {
				border-top: 1px solid $border-color-light;

				&:last-child {
					border-bottom: 1px solid $border-color-light;
				}

				.top {
					padding: 30rpx 0;
					@include flex-box-set(start);

					.font {
						padding-left: 10rpx;
						font-weight: bold;
					}
				}

				.btnGroup {
					padding: 10rpx 0 30rpx;
					@include flex-box-set(start);
					flex-wrap: wrap;

					.btn {
						padding: 0rpx 25rpx;
						height: 60rpx;
						border: 1rpx solid $border-color-light;
						margin-right: 20rpx;
						border-radius: 10rpx;
						color: $text-font-color-2;
						margin-bottom: 20rpx;
						@include flex-box-set();

						&.active {
							border-color: $brand-theme-color;
							color: $brand-theme-color;
							background: rgba(236, 87, 79, 0.1);
						}
					}
				}
			}
		}

		.foot {
			padding: 50rpx 200rpx;
		}
	}
</style>

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

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

相关文章

[c语言日寄]数据结构:栈

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋&#xff1a;这是一个专注于C语言刷题的专栏&#xff0c;精选题目&#xff0c;搭配详细题解、拓展算法。从基础语法到复杂算法&#xff0c;题目涉及的知识点全面覆盖&#xff0c;助力你系统提升。无论你是初学者&#xff0c;还是…

WEB安全--Java安全--LazyMap_CC1利用链

一、前言 该篇是基于WEB安全--Java安全--CC1利用链-CSDN博客的补充&#xff0c;上篇文章利用的是TransformedMap类&#xff0c;而CC链的原作者是利用的LazyMap类作为介质进行的触发。 所以本文将分析国外原作者在ysoserial commonscollections1中给出的CC1利用链。 二、回顾梳…

黑马k8s(六)

1.Deployment&#xff08;Pod控制器&#xff09; Selector runnginx 标签选择&#xff1a;会找pod打的标签 执行删除之后&#xff0c;pod也会删除&#xff0c;Terminating正在删除 如果想要访问其中的一个pod借助&#xff1a;IP地址端口号访问 假设在某一个瞬间&#xff0c;…

【OpenGL学习】(一)创建窗口

文章目录 【OpenGL学习】&#xff08;一&#xff09;创建窗口 【OpenGL学习】&#xff08;一&#xff09;创建窗口 GLFW OpenGL 本身只是一套图形渲染 API&#xff0c;不提供窗口创建、上下文管理或输入处理的功能。 GLFW 是一个支持创建窗口、处理键盘鼠标输入和管理 OpenGL…

AI大语言模型评测体系演进与未来展望

随着人工智能技术的飞速发展,大语言模型(LLMs)已成为自然语言处理领域的核心研究方向。2025年最新行业报告显示,当前主流模型的评测体系已从单一任务评估转向多维度、全链路的能力剖析。例如,《全球首个大语言模型意识水平”识商”白盒DIKWP测评报告》通过数据、信息、知识…

微服务项目->在线oj系统(Java版 - 5)

相信自己,终会成功 微服务代码: lyyy-oj: 微服务 目录 C端代码 用户题目接口 修改后用户提交代码(应用版) 用户提交题目判题结果 代码沙箱 1. 代码沙箱的核心功能 2. 常见的代码沙箱实现方式 3. 代码沙箱的关键问题与解决方案 4. 你的代码如何与沙箱交互&#xff1f; …

get请求使用数组进行传参

get请求使用数组进行传参,无需添加中括号 mvc接口要添加参数名&#xff0c;使用array承接。不能用list, 否则会报错 这里是用apifox模拟前端调用。 前端调用代码 // 根据项目ID和角色ID查询相关审批人 export function findRelativeApproverByProjectIdAndRoleId(roleIds, p…

【MySQL成神之路】MySQL常用语法总结

目录 MySQL 语法总结 数据库操作 表操作 数据操作 查询语句 索引操作 约束 事务控制 视图操作 存储过程和函数 触发器 用户和权限管理 数据库操作 创建数据库&#xff1a; CREATE DATABASE database_name; 选择数据库&#xff1a; USE database_name; 删除数…

Linux动静态库制作与原理

什么是库 库是写好的现有的&#xff0c;成熟的&#xff0c;可以复用的代码。现实中每个程序都要依赖很多基础的底层库&#xff0c;不可能每个人的代码都从零开始&#xff0c;因此库的存在意义非同寻常。 本质上来说库是一种可执行代码的二进制形式&#xff0c;可以被操作系统…

ffmpeg 把一个视频复制3次

1. 起因&#xff0c; 目的: 前面我写过&#xff0c;使用 python 把一个视频复制3次但是速度太慢了&#xff0c;我想试试看能否改进。而且我想换一种新的视频处理思路&#xff0c;并试试看速度如何。 2. 先看效果 效果就是能行&#xff0c;而且速度也快。 3. 过程: 代码 1…

GPT/Claude3国内免费镜像站更新 亲测可用

无限次使用&#xff1a;无限制的提问次数&#xff0c;不设上限&#xff0c;随心所欲。 无需魔法、稳定流畅&#xff1a;操作简便&#xff0c;无需复杂设置&#xff0c;即可享受稳定流畅的服务。 手机和电脑均能用&#xff1a;轻松适配手机和电脑&#xff0c;使用体验更佳。 …

Python:操作Excel按行写入

Python按行写入Excel数据,5种实用方法大揭秘! 在日常的数据处理和分析工作中,我们经常需要将数据写入到Excel文件中。Python作为一门强大的编程语言,提供了多种库和方法来实现将数据按行写入Excel文件的功能。本文将详细介绍5种常见的Python按行写入Excel数据的方法,并附上…

Redis进阶知识

Redis 1.事务2. 主从复制2.1 如何启动多个Redis服务器2.2 监控主从节点的状态2.3 断开主从复制关系2.4 额外注意2.5拓扑结构2.6 复制过程2.6.1 数据同步 3.哨兵选举原理注意事项 4.集群4.1 数据分片算法4.2 故障检测 5. 缓存5.1 缓存问题 6. 分布式锁 1.事务 Redis的事务只能保…

12.vue整合springboot首页显示数据库表-实现按钮:【添加修改删除查询】

vue整合springboot首页显示数据库表&#xff1a;【添加修改删除查询】 提示&#xff1a;帮帮志会陆续更新非常多的IT技术知识&#xff0c;希望分享的内容对您有用。本章分享的是node.js和vue的使用。前后每一小节的内容是存在的有&#xff1a;学习and理解的关联性。【帮帮志系…

bisheng系列(一)- 本地部署(Docker)

目录 一、导读 二、说明 1、镜像说明 2、本节内容 三、docker部署 1、克隆代码 2、运行镜像 3、可能的错误信息 四、页面测试 1、注册用户 2、登陆成功 3、添加模型 一、导读 环境&#xff1a;Ubuntu 24.04、Windows 11、WSL 2、Python 3.10 、bisheng 1.1.1 背景…

如何用Python批量解压ZIP文件?快速解决方案

如何用Python批量解压ZIP文件&#xff1f;快速解决方案 文章目录 **如何用Python批量解压ZIP文件&#xff1f;快速解决方案**代码结果详细解释 话不多说&#xff0c;先上干货&#xff01;&#xff01;&#xff01; 代码 import os import zipfiledef unzip_file(dir_path: str…

DriveGenVLM:基于视觉-语言模型的自动驾驶真实世界视频生成

《DriveGenVLM: Real-world Video Generation for Vision Language Model based Autonomous Driving》2024年8月发表&#xff0c;来自哥伦比亚大学的论文。 自动驾驶技术的进步需要越来越复杂的方法来理解和预测现实世界的场景。视觉语言模型&#xff08;VLM&#xff09;正在成…

企业标准信息公共服务平台已开放标准通编辑器访问入口

标准通 数字化标准编辑器 专业、高效、便捷 企业标准信息公共服务平台 近日&#xff0c;企业标准信息公共服务平台已开放标准通编辑器访问入口&#xff0c;可进入官网指定版块使用&#xff01; 核心功能亮点 解决企业痛点 传统标准编制&#xff0c;需反复核对格式、逐条…

进阶-数据结构部分:1、数据结构入门

飞书文档https://x509p6c8to.feishu.cn/wiki/HRLkwznHiiOgZqkqhLrcZNqVnLd 一、存储结构 顺序存储 链式存储 二、常用数据结构 2.1、栈 先进后出 场景&#xff1a; 后退/前进功能&#xff1a;网页浏览器中的后退和前进按钮可以使用栈来实现。在浏览网页时&#xff0c;每次…

React 19中useContext不需要Provider了。

文章目录 前言一、React 19中useContext移除了Provider&#xff1f;二、使用步骤总结 前言 在 React 19 中&#xff0c;useContext 的使用方式有所更新。开发者现在可以直接使用 作为提供者&#xff0c;而不再需要使用 <Context.Provider>。这一变化简化了代码结构&…