uniapp-商城-54-后台 新增商品(页面布局)

news2025/5/14 18:11:04

        后台页面中还存在商品信息的添加和修改等。接下来我们逐步进行分析和展开。包含页面布局和数据库逻辑等等。

1、整体效果

样式效果如下,依然采用了表单形式来完成和商家信息差不多,但在商品属性上多做了一些弹窗等界面,样式和功能点表多。

2、整体样式和布局

2.1 代码效果:

2.2 表单间隔

从图上看到 每一个标签有一个间隔。

.goodsView{
    padding:30rpx;

3、 这里的布局是使用的uni-froms 以及uni-forms-item

3.1   uni-froms 的使用

<uni-forms ref="goodsForm" :model="goodsFormData" :rules="goodsRules" :label-width="100" label-align="right">

依然是ref 、model、rules 

rules 这里就没有自定义规则(没有uniapp-商城-50-后台 商家信息 第4点的问题)

创作中心-CSDN https://mpbeta.csdn.net/mp_blog/creation/editor/147853834

3.2 商品图片的上传 uni-file-picker

上传图片依然用的是   uni-file-picker  没有对上传张数限制

    <uni-file-picker v-model="goodsFormData.thumb" fileMediatype="image" mode="grid"></uni-file-picker>

uni-app官网uni-app,uniCloud,serverless,介绍,基础用法,选择指定后缀图片,且限制选择个数,手动上传,单选图片且点击再次选择,自定义样式,使用插槽,API,FilePicker Props,value 格式,list-styles 格式,image-styles 格式,FilePickhttps://uniapp.dcloud.net.cn/component/uniui/uni-file-picker.html

3.3 商品名称的页面 uni-easyinput

使用的是 uni-easyinput 进行名称的添加。trim是否自动去掉空格。

uni-easyinput 增强输入框 | uni-app官网uni-app,uniCloud,serverless,uni-easyinput 增强输入框,介绍,基本用法,输入框带左右图标,插槽,输入框禁用,密码框,输入框聚焦,多行文本,多行文本自动高度,取消边框,API,Easyinput Props,Type Options,ConfirmType Ophttps://uniapp.dcloud.net.cn/component/uniui/uni-easyinput.html<uni-data-select collection="kt-mall-category" field="_id as value, name as text"
                    v-model="goodsFormData.category_id"></uni-data-select>

collection 数据库

field 选择数据的范围

3.4 商品分类 uni-data-select

这里的数据来源于前面商品分类添加的数据,需要进行后台数据联动。

使用的是选择组件 uni-data-select,然后根据前面商品属性添加的类别进行选择。

uni-app官网uni-app,uniCloud,serverless,介绍,安装方式,基本用法,云端数据示例,API,DataSelect Props,使用云端数据时的属性(DataCom Props),Localdata Options,DataSelect Events,示例https://uniapp.dcloud.net.cn/component/uniui/uni-data-select.html

安装:

uni-data-select 下拉框选择器 - DCloud 插件市场 通过数据驱动的下拉框选择器https://ext.dcloud.net.cn/plugin?name=uni-data-select

3.5 商品价格 uni-easyinput

使用的 uni-forms-item uni-easyinput, trim是否自动去掉空格。

3.6 商品属性  u-cell 

使用 u-cell  展示。

这个是u-view 提供的组件,需要重新安装和使用

Cell 单元格 | uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架uView UI,是 uni-app 生态最优秀的 UI 框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水https://uviewui.com/components/cell.html<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>

3.7 商品描述 uni-easyinput

使用的 uni-forms-item 、uni-easyinput, trim是否自动去掉空格。

4、页面中使用 弹出层  uni-popup   用于3.6的商品属性

4.1 bug处理

主要是使用的 uni-popup,依然会有前面的bug  但是我们在前面的章节已经处理了。

创作中心-CSDN https://mpbeta.csdn.net/mp_blog/creation/editor/147851881

4. 2 整体页面感知

包含两部分弹窗,上面部分是从底部弹出,下面的是弹出聚焦在中部。

上面分三个盒子  上中下 三个,

复杂的就是中部盒子。

<view class="safe-area-bottom"></view>    兼容ios系统的下边的安全区域遮挡我们也页面显示。

中部:

整体样式结果:(这里没有联动分类数据所以没有分类数据可以选择)

5、整体代码

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

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

			<uni-forms-item label="产品分类" required name="category_id">
				<uni-data-select collection="kt-mall-category" 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">
				<uni-easyinput type="number" v-model="goodsFormData.price" placeholder="请输入商品价格"
					trim="both"></uni-easyinput>
			</uni-forms-item>

			<uni-forms-item label="商品原价">
				<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="商品描述">
				<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">
			<view class="attrWrapper">
				<view class="head">
					<view class="title">商品属性</view>
					<view class="addAttr" @click="clickAddAttr()">+ 添加属性</view>
				</view>

				<view class="body">
					<view class="item" v-for="(item,index) in skuArr">
						<view class="top">
							<checkbox :checked="item.checked" @click="changeCheckbox(index)"></checkbox>
							<view class="font">{{item.skuName}}</view>
						</view>
						<view class="btnGroup" v-if="item.checked">
							<view class="btn" :class="child.checked?'active':''" v-for="(child,cIdx) in item.children"
								@click="clickChlidBtn(index,cIdx)">{{child.name}}</view>
							<view class="btn" @click="clickAddAttr(index)">
								<u-icon name="plus"></u-icon>
							</view>
						</view>
					</view>
				</view>

				<view class="foot">
					<button type="primary" @click="clickConfirmSelect">确认选择</button>
				</view>
			</view>

			<view class="safe-area-bottom"></view>
		</uni-popup>


		<uni-popup ref="addAttrPop">
			<uni-popup-dialog mode="input" title="新增" placeholder="请输入新增的内容"
				@confirm="dialogConfirm"></uni-popup-dialog>
		</uni-popup>
	</view>
</template>

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

	const goodsCloudObj = uniCloud.importObject("kt-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: []
			};
		},

		onLoad() {

		},

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


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


			//点击确认选择
			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
					})
					return {
						...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);
			},


			//点击添加属性
			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();
				if (this.skuArr.length) return;
				this.getSkuData();

			},

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

				}).catch(err => {
					console.log(err);
				})
			},
			//上传到云数据库
			async toDataBase() {
				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/2375564.html

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

相关文章

WebpackVite总结篇与进阶

模块化 Webpack Webpack 入口entry 分离app和第三方库入口 这是什么&#xff1f; 这是告诉 webpack 我们想要配置 2 个单独的入口点&#xff08;例如上面的示例&#xff09;。 为什么&#xff1f; 这样你就可以在 vendor.js 中存入未做修改的必要 library 或文件&#xff0…

【python】基础知识点100问

以下是Python基础语法知识的30条要点整理,涵盖数据类型、函数、控制结构等核心内容,结合最新资料归纳总结: 基础30问 一、函数特性 函数多返回值 支持用逗号分隔返回多个值,自动打包为元组,接收时可解包到多个变量 def func(): return 1, "a" x, y = func()匿…

SpringBoot--springboot简述及快速入门

spring Boot是spring提供的一个子项目&#xff0c;用于快速构建spring应用程序 传统方式&#xff1a; 在众多子项目中&#xff0c;spring framework项目为核心子项目&#xff0c;提供了核心的功能&#xff0c;其他的子项目都需要依赖于spring framework&#xff0c;在我们实际…

vscode_python远程调试_pathMappings配置说明

1.使用说明 vscode python 远程调试pathMappings 配置 launch.json "pathMappings": [{"localRoot": "本地代码目录","remoteRoot": "远程代码目录" # 注意不是运行目录, 是远程代码的目录}],2.测试验证 测试目的: 远程代…

遨游5G-A防爆手机:赋能工业通信更快、更安全

在工业数字化转型与5G-A商用进程加速的双重驱动下&#xff0c;中国防爆手机市场正迎来历史性发展机遇。作为“危、急、特”场景通信解决方案服务商&#xff0c;遨游通讯深刻洞察到&#xff1a;当5G-A网络以超高速率、海量连接和毫秒级时延重塑行业生态时&#xff0c;防爆手机这…

Profibus DP主站与Modbus RTU/TCP网关与海仕达变频器轻松实现数据交互

Profibus DP主站与Modbus RTU/TCP网关与海仕达变频器轻松实现数据交互 Profibus DP主站转Modbus RTU/TCP&#xff08;XD-MDPBm20&#xff09;网关在Profibus总线侧实现主站功能&#xff0c;在Modbus串口侧实现从站功能。可将ProfibusDP协议的设备&#xff08;如&#xff1a;海…

「华为」人形机器人赛道投资首秀!

温馨提示&#xff1a;运营团队2025年最新原创报告&#xff08;共210页&#xff09; —— 正文&#xff1a; 近日&#xff0c;【华为】完成具身智能赛道投资首秀&#xff0c;继续加码人形机器人赛道布局。 2025年3月31日&#xff0c;具身智能机器人头部创企【千寻智能&#x…

格雷希尔G10和G15系列自动化快速密封连接器,适用于哪些管件的密封,以及它们相关的特性有哪些?

格雷希尔G10和G15系列快速密封连接器&#xff0c;用于自动化和半自动化过程中的外部或内部密封&#xff0c;通过使用气压驱动来挤压内部的密封圈&#xff0c;创造一个适用于各种管件的无泄漏密封连接&#xff0c;连接器内部的弹性密封圈可以提供其他产品不能提供的卓越密封性能…

专栏特辑丨悬镜浅谈开源风险治理之SBOM与SCA

随着容器、微服务等新技术日新月异&#xff0c;开源软件成为业界主流形态&#xff0c;软件行业快速发展。但同时&#xff0c;软件供应链也越来越趋于复杂化和多样化&#xff0c;软件供应链安全风险不断加剧。 软件供应链安全主要包括软件开发生命周期和软件生存运营周期&#x…

vue3项目创建-配置-elementPlus导入-路由自动导入

目录 方法一&#xff1a;create-vue 方法二 &#xff1a;Vite Vue Vite.config.ts配置 引入element-plus 安装 如何在项目中使用 Element Plus 完整引入 按需导入 vue3vite中自动配置路由的神器&#xff1a;vite-plugin-pages 1. 安装 2、修改vite.config.js中配置…

MUSE Pi Pro 编译kernel内核及创建自动化脚本进行环境配置

视频讲解&#xff1a; MUSE Pi Pro 编译kernel内核及创建自动化脚本进行环境配置 今天分享的主题为创建自动化脚本编译MUSE Pi Pro的kernel内核&#xff0c;脚本已经上传到中 GitHub - LitchiCheng/MUSE-Pi-Pro-Learning: MUSE-Pi-Pro-Learning &#xff0c;有需要可以自行clon…

Innovus 25.1 版本更新:助力数字后端物理设计新飞跃

在数字后端物理设计领域&#xff0c;每一次工具的更新迭代都可能为项目带来巨大的效率提升与品质优化。今天&#xff0c;就让我们一同聚焦 Innovus 25.1 版本&#xff08;即 25.10 版本&#xff09;的更新要点&#xff0c;探寻其中蕴藏的创新能量。 一、核心功能的强势进 AI…

CodeBuddy 中国版 Cursor 实战:Redis+MySQL双引擎驱动〈王者荣耀〉战区排行榜

文章目录 一、引言二、系统架构设计2.1、整体架构概览2.2、数据库设计2.3、后端服务设计 三、实战&#xff1a;从零构建排行榜3.1、开发环境准备3.2、用户与战区 数据管理3.2.1、MySQL 数据库表创建3.2.2、实现用户和战区数据的 CURD 操作 3.3、实时分数更新3.4、排行榜查询3.5…

在线SQL转ER图工具

在线SQL转ER图网站 在数据库设计、软件开发或学术研究中&#xff0c;ER图&#xff08;实体-关系图&#xff09; 是展示数据库结构的重要工具。然而&#xff0c;手动绘制ER图不仅耗时费力&#xff0c;还容易出错。今天&#xff0c;我将为大家推荐一款非常实用的在线工具——SQL…

python高级特性

json.dumps({a:1,n:2}) #Python 字典类型转换为 JSON 对象。相当于jsonify data2 json.loads(json_str)#将 JSON 对象转换为 Python 字典 异步编程&#xff1a;在异步编程中&#xff0c;程序可以启动一个长时间运行的任务&#xff0c;然后继续执行其他任务&#xff0c;而无需等…

汇编:子程序设计

一、 实验要求 实验目的&#xff1a; 熟练掌握算术运算汇编指令的使用熟练掌握子程序设计的基本方法熟练掌握程序的调试方法 实验内容&#xff1a; 编程实现两个数&#xff1a;#8888H和#79H的乘除运算结合实验1的代码&#xff0c;将加减乘除四则运算写成四个子程序&#xff…

从概念表达到安全验证:智能驾驶功能迎来系统性规范

随着辅助驾驶事故频发&#xff0c;监管机制正在迅速补位。面对能力表达、使用责任、功能部署等方面的新要求&#xff0c;行业开始重估技术边界与验证能力&#xff0c;数字样机正成为企业合规落地的重要抓手。 2025年以来&#xff0c;围绕智能驾驶功能的争议不断升级。多起因辅…

DeepSeek基于注意力模型的可控图像生成

DeepSeek大模型高性能核心技术与多模态融合开发 - 商品搜索 - 京东 图像的加噪与模型训练 在扩散模型的训练过程中&#xff0c;首先需要对输入的信号进行加噪处理&#xff0c;经典的加噪过程是在图像进行向量化处理后在其中添加正态分布&#xff0c;而正态分布的值也是与时间…

“端 - 边 - 云”三级智能协同平台的理论建构与技术实现

摘要 随着低空经济与智能制造的深度融合&#xff0c;传统集中式云计算架构在实时性、隐私保护和资源效率上的瓶颈日益凸显。本文提出“端 - 边 - 云”三级智能协同平台架构&#xff0c;以“时空 - 资源 - 服务”三维协同理论为核心&#xff0c;构建覆盖终端感知、边缘计算、云端…

AI时代,如何实现人机共舞?

在科技飞速发展的当下&#xff0c;人工智能&#xff08;AI&#xff09;已不再是科幻作品中的遥远想象&#xff0c;而是深入渗透到我们生活与工作的方方面面。从智能手机中的语音助手&#xff0c;到金融领域的风险预测模型&#xff1b;从医疗影像的智能诊断&#xff0c;到工业生…