极简实用的Asp.NetCore框架再新增商城模块
概述
关于这个框架的背景,在前面我已经交代过了。不清楚的可以查看这个链接
1、极简实用的Asp.NetCore模块化框架决定免费开源了
2、极简实用的Asp.NetCore模块化框架新增CMS模块
算下来确实好长时间没更新博客了,在这段时间内一直在出差,闲暇时间一直在想dotnetcore框架本身就是模块化的,为什么还要在这个上层应用上面继续进行模块化封装,意义何在?是为了更好地划分业务还是轮子重复利用?
细细想来,这个框架不应该再继续模块化下去,主要有以下几点理由支持:
1、本身于我现有地业务而言,没必要模块化,我只是做个大而全地系统(权限管理,内容管理,商城,微信管理等)。
2、如果要做模块化,本身就要牺牲掉一些性能,这是我反反复复斟酌以后不能接受的,主要是牺牲性能有点多!
3、dotnetcore本身就更友好模块化,没必要在这个上层应用上面再包裹一层,没有任何意义,我下载了dotnetcore源码后,觉得它的设计理念特别棒,于是“dotnetcore”本身就是最好的模块化(组件化)框架,可以把很多时间和精力投身于源码上面研究,没有必要在纠结于模块化这个概念,在上层应用折腾来折腾去,对于技术的成长微乎其微。
4、以前划分为模块化,是想朝微服务的方向发展,到时尽量改动小一点。现在想想我就一个后台管理,没必要想那么多。
基于以上几点,我于是把框架进行了更改,对于原来的模块化框架也进行了分支保留(一定意义上来说也不全是模块化)。
新增业务功能
新增加一个商城模块,主要包含商品管理(支持多个sku),商品分类,小程序用户,用户收获地址、订单各种状态的列表。
关于添加和修改商品的部分后端代码:
- public async Task<ApiResult> AddAsync(GoodsInput input)
- {
- try
- {
- Db.BeginTran();
- // 保存商品
- var goods = _mapper.Map<Goods>(input);
- var goodsId = await Db.Insertable<Goods>(goods).ExecuteReturnIdentityAsync();
- // 保存规格
- await DealwithGoodsSpec(goodsId, input);
- Db.CommitTran();
- }
- catch (Exception e)
- {
- Db.RollbackTran();
- return new ApiResult(e.Message);
- }
- return new ApiResult();
- }
- /// <summary>
- /// 公共的商品规格信息处理
- /// </summary>
- /// <param name="goodsId"></param>
- /// <param name="input"></param>
- /// <returns></returns>
- private async Task DealwithGoodsSpec(int goodsId, GoodsInput input)
- {
- // 保存规格
- if (input.SpecType == SpecTypeEnum.Single.GetValue<int>())
- {
- var specSingle = JsonConvert.DeserializeObject<GoodsSpecInput>(input.SpecSingle);
- input.GoodsSpecInput = specSingle;
- var goodsSpec = input.BuildGoodsSpec(goodsId);
- if (null == goodsSpec)
- {
- throw new FriendlyException("商品规格实体数据不能为空!");
- }
- await Db.Insertable(goodsSpec).ExecuteReturnIdentityAsync();
- }
- else
- {
- var goodsSpecs = input.BuildGoodsSpecs(goodsId);
- if (null == goodsSpecs || goodsSpecs.Count == 0)
- {
- throw new FriendlyException("商品规格实体数据集合不能为空!");
- }
- await Db.Insertable(goodsSpecs).ExecuteReturnIdentityAsync();
- var goodsSpecRels = input.BuildGoodsSpecRels(goodsId);
- if (goodsSpecRels.Count == 0 || goodsSpecRels == null)
- {
- throw new FriendlyException("商品规格实体关系集合数据不能为空!");
- }
- //根据规格值反推规格组id
- var specValues = await Db.Queryable<SpecValue>().Where(d => d.Status).ToListAsync();
- foreach (var item in goodsSpecRels)
- {
- var specId = specValues.Where(d => d.Status && d.Id == item.SpecValueId).Select(d => d.SpecId);
- item.SpecId = specId.FirstOrDefault();
- }
- await Db.Insertable(goodsSpecRels).ExecuteReturnIdentityAsync();
- }
- }
- public async Task<ApiResult> ModifyAsync(GoodsModifyInput input)
- {
- var goods = await GetModelAsync(d => d.Id == input.Id);
- if (goods == null) throw new FriendlyException($"此商品{input.Id}没有查找对应的商品信息");
- try
- {
- Db.BeginTran();
- // 更新商品
- var model = _mapper.Map<Goods>(input);
- var goodsId = await Db.Updateable(model).IgnoreColumns(d => new { d.CreateTime }).ExecuteCommandAsync();
- // 更新规格
- await Db.Deleteable<GoodsSpec>().Where(d => d.GoodsId == input.Id).ExecuteCommandAsync();
- await Db.Deleteable<GoodsSpecRel>().Where(d => d.GoodsId == input.Id).ExecuteCommandAsync();
- // 保存规格
- await DealwithGoodsSpec(input.Id, input);
- Db.CommitTran();
- }
- catch (Exception e)
- {
- Db.RollbackTran();
- return new ApiResult(e.Message);
- }
- return new ApiResult();
- }
前端添加商品部分代码:
- @{
- ViewData["Title"] = "Modify";
- Layout = "~/Views/Shared/_Layout.cshtml";
- }
- @section css{
- <link href="~/css/site.min.css" rel="stylesheet" asp-append-version="true" />
- <link href="~/css/goods.css" rel="stylesheet" asp-append-version="true" />
- }
- <div id="container">
- <form class="layui-form form-cus form-back" action="" id="app" lay-filter="column-edit">
- <div class="panel-body">
- <div class="panel-addpic">
- <div class="text">基本属性</div>
- <div class="form-cur-wall">
- <label>所属分类</label>
- <div class="layui-input-block">
- <select name="categoryId" id="categoryId" lay-search="">
- <option value="0">父级</option>
- </select>
- </div>
- </div>
- <div class="form-cur-wall">
- <label>初始销量</label>
- <div class="layui-input-block">
- <input type="text" name="salesInitial" maxlength="100" autocomplete="off" class="layui-input">
- </div>
- </div>
- <div class="form-cur-wall">
- <label>商品状态</label>
- <div class="layui-input-block">
- <input type="radio" name="goodsStatus" lay-skin="primary" value="10" title="上架" />
- <input type="radio" name="goodsStatus" lay-skin="primary" value="20" title="下架" />
- </div>
- </div>
- <div class="form-cur-wall">
- <label>运费模板</label>
- @*目前现调用字典表的模板*@
- <div class="layui-input-block">
- <select name="deliveryId" id="deliveryId" lay-verify="required" lay-search="" maxlength="100">
- @if (ViewBag.Freights != null)
- {
- foreach (var item in (List<Config>)ViewBag.Freights)
- {
- <option value="@item.Id">@item.Name</option>
- }
- }
- </select>
- </div>
- </div>
- </div>
- <div class="layui-row">
- <div class="layui-form-item">
- <label class="layui-form-label" required>商品名称</label>
- <div class="layui-input-block">
- <input type="text" name="name" maxlength="100" lay-verify="required" lay-verType="tips" autocomplete="off" class="layui-input">
- </div>
- </div>
- <div class="layui-form-item">
- <label class="layui-form-label required">商品图片</label>
- <div class="layui-upload">
- <button type="button" class="layui-btn" id="btnUploadShowImg">上传图片</button>
- <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;margin-left:110px;">
- 预览图:
- <div class="layui-upload-list" id="demo2"></div>
- </blockquote>
- </div>
- </div>
- <hr />
- <div class="layui-form-item">
- <label class="layui-form-label" required>商品规格</label>
- <div class="layui-input-block">
- <input type="radio" name="specType" lay-skin="primary" value="10" lay-filter="specType" title="单规格" class="layui-input" checked/>
- <input type="radio" name="specType" lay-skin="primary" value="20" lay-filter="specType" title="多规格" class="layui-input" />
- </div>
- </div>
- <div class="goods-spec-many am-form-group">
- <div class="goods-spec-box am-u-sm-9 am-u-sm-push-2 am-u-end">
- <!-- 规格属性 -->
- <div class="spec-attr"></div>
- <!-- 添加规格:按钮 -->
- <div class="spec-group-button">
- <button type="button" class="btn-addSpecGroup am-btn">添加规格</button>
- </div>
- <!-- 添加规格:表单 -->
- <div class="spec-group-add">
- <div class="spec-group-add-item am-form-group">
- <label class="am-form-label form-require">规格名 </label>
- <input type="text" class="input-specName tpl-form-input" placeholder="请输入规格名称">
- </div>
- <div class="spec-group-add-item am-form-group">
- <label class="am-form-label form-require">规格值 </label>
- <input type="text" class="input-specValue tpl-form-input" placeholder="请输入规格值">
- </div>
- <div class="spec-group-add-item am-margin-top">
- <button type="button" class="btn-addSpecName am-btn am-btn-xs
- am-btn-secondary">
- 确定
- </button>
- <button type="button" class="btn-cancleAddSpecName am-btn am-btn-xs
- am-btn-default">
- 取消
- </button>
- </div>
- </div>
- <!-- 商品多规格sku信息 -->
- <div class="goods-sku am-scrollable-horizontal">
- <!-- 分割线 -->
- <div class="goods-spec-line am-margin-top-lg am-margin-bottom-lg"></div>
- <!-- sku 批量设置 -->
- <div class="spec-batch am-form-inline">
- <div class="am-form-group">
- <label class="am-form-label">批量设置</label>
- </div>
- <div class="am-form-group">
- <input type="text" data-type="goods_no" placeholder="商家编码">
- </div>
- <div class="am-form-group">
- <input type="number" data-type="goods_price" placeholder="销售价">
- </div>
- <div class="am-form-group">
- <input type="number" data-type="line_price" placeholder="划线价">
- </div>
- <div class="am-form-group">
- <input type="number" data-type="stock_num" placeholder="库存数量">
- </div>
- <div class="am-form-group">
- <input type="number" data-type="goods_weight" placeholder="重量">
- </div>
- <div class="am-form-group">
- <button type="button" class="btn-specBatchBtn am-btn am-btn-sm am-btn-secondary
- am-radius">
- 确定
- </button>
- </div>
- </div>
- <!-- sku table -->
- <table class="spec-sku-tabel am-table am-table-bordered am-table-centered am-margin-bottom-xs am-text-nowrap"></table>
- </div>
- </div>
- </div>
- <div id="sigleSpec">
- <div class="layui-form-item">
- <label class="layui-form-label" required>商品价格</label>
- <div class="layui-input-block">
- <input type="text" name="goodsPrice" maxlength="30" autocomplete="off" class="layui-input">
- </div>
- </div>
- <div class="layui-form-item">
- <label class="layui-form-label" required>商品划线价</label>
- <div class="layui-input-block">
- <input type="text" name="linePrice" maxlength="40" autocomplete="off" class="layui-input">
- </div>
- </div>
- <div class="layui-form-item">
- <label class="layui-form-label">商品编码</label>
- <div class="layui-input-block">
- <input type="text" name="goodsNo" maxlength="40" autocomplete="off" class="layui-input">
- </div>
- </div>
- <div class="layui-form-item">
- <label class="layui-form-label" required>库存数量</label>
- <div class="layui-input-block">
- <input type="number" name="stockNum" maxlength="40" class="layui-input">
- </div>
- </div>
- <div class="layui-form-item">
- <label class="layui-form-label" required>商品重量(Kg)</label>
- <div class="layui-input-block">
- <input type="number" name="goodsWeight" maxlength="40" class="layui-input">
- </div>
- </div>
- </div>
- <div class="layui-form-item">
- <label class="layui-form-label" required>库存计算</label>
- <div class="layui-input-block">
- <input type="radio" name="deductStockType" value="10" lay-skin="primary" title="下单减库存" />
- <input type="radio" name="deductStockType" value="20" lay-skin="primary" title="付款减库存" />
- </div>
- </div>
- </div>
- <div class="layui-row">
- <div class="layui-form-item layui-form-text">
- <label class="layui-form-label">商品详情</label>
- <div class="layui-input-block">
- <textarea id="content" name="content" placeholder="请输入内容" class="layui-textarea"></textarea>
- </div>
- </div>
- </div>
- <div class="layui-form-item">
- <div class="layui-input-block">
- <button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">确认保存</button>
- </div>
- </div>
- </div>
- </form>
- </div>
- @section js{
- <script src="/lib/tinymce/tinymce.min.js"></script>
- <script src="/lib/tinymce/langs/zh_CN.js"></script>
- <script src="~/lib/jquery-3.4.1/jquery-3.4.1.min.js"></script>
- <script src="~/js/goodsSpec.js" asp-append-version="true"></script>
- <script src="~/js/art-template.js" asp-append-version="true"></script>
- <script src="~/js/imgUpload.js" asp-append-version="true"></script>
- <!-- 商品多规格模板 -->
- @await Html.PartialAsync("~/Views/Shared/Templates/tpl_spec_many.cshtml")
- <script>
- tinymce.init({
- selector: '#content',
- auto_focus: true,
- height: 500,
- content_style: "img {max-width:100%;}",
- image_advtab: true,//开启图片上传的高级选项功能
- images_upload_url: '/api/goods/UploadImg',//图片上传
- plugins: 'print preview code searchreplace autolink directionality visualblocks visualchars fullscreen image link media codesample table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists textcolor wordcount imagetools contextmenu colorpicker textpattern help ',
- toolbar: 'formatselect styleselect | bold italic forecolor backcolor | link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat'
- });
- layui.use(['form', 'common'], function () {
- var form = layui.form,
- $ = layui.$,
- apiUtil = layui.common;
- // 当前弹出层,防止ID被覆盖
- var parentIndex = parent.layer.getFrameIndex(window.name);
- apiUtil.BindParentCategory();
- form.render();
- // 注册商品多规格组件
- var specMany = new GoodsSpec({
- container: '.goods-spec-many'
- });
- //处理单/多规格的显示问题
- form.on('radio(specType)', function (data) {
- //但规格
- if (data.value == 10) {
- $("#sigleSpec").show() && $(".goods-spec-many").hide();
- }
- //多规格
- if (data.value == 20) {
- $("#sigleSpec").hide() && $(".goods-spec-many").show();
- }
- //console.log(data.elem); //得到radio原始DOM对象
- });
- //监听提交
- form.on('submit(saveBtn)', function (data) {
- data.field.content = tinyMCE.editors[0].getContent();
- var specType = $('input[name=specType]:checked').val();
- if (specType == 20) {
- var specMany2 = JSON.stringify(specMany.getData());
- console.log("specMany:" + specMany2);
- var isEmpty = specMany.isEmptySkuList();
- if (isEmpty == true) {
- layer.msg('商品规格不能为空');
- return false;
- }
- data.field.specMany = specMany2;
- } else {
- var specSingle = {
- goods_no: data.field.goodsNo,
- line_price: data.field.linePrice,
- goods_price: data.field.goodsPrice,
- goods_weight: data.field.goodsWeight,
- stock_num: data.field.stockNum,
- };
- data.field.specSingle=JSON.stringify(specSingle);
- }
- data.field.specType = specType;
- data.field.goodsStatus = $('input[name=goodsStatus]:checked').val();
- data.field.deductStockType = $('input[name=deductStockType]:checked').val();
- data.field.imgUrl = $(".div_img input").map(function () { return $(this).attr("value"); }).get().join(',');
- if (data.field.imgUrl == "" || data.field.imgUrl == null) {
- apiUtil.error("商品图片至少需要上传一张!");
- return false;
- }
- apiUtil.ajax('goods/add', data.field, "application/json", "post", function (res) {
- apiUtil.success(res.msg);
- parent.layer.close(parentIndex);
- });
- return false;
- });
- });
- </script>
- }
这里只贴部分代码吧,更多的细节可以直接去看源码。另外关于商城的设计其实写个系列也不过分,下次抽时间具体写篇文章介绍下商品的多规格怎么设计好一点。
源码地址:https://gitee.com/shenniu_code_group/shen-nius.-modularity
喜欢交流的人进微信群
极简实用的Asp.NetCore框架再新增商城模块的更多相关文章
- 极简实用的Asp.NetCore模块化框架新增CMS模块
简介 关于这个框架的背景,在前面我已经交代过了.不清楚的可以查看这个链接 极简实用的Asp.NetCore模块化框架决定免费开源了 在最近一段时间内,对这个框架新增了以下功能: 1.新增了CMS模块, ...
- 极简实用的Asp.NetCore模块化框架决定免费开源了
背景 在开发这个框架之前,前前后后看过好几款模块化的框架,最后在一段时间内对ABP VNext痛下狠心,研究一段时间后,不得不说 ABP VNext的代码层面很规范,也都是一些最佳实践,开发出一个模块 ...
- 在windows上极简安装GPU版AI框架(Tensorflow、Pytorch)
在windows上极简安装GPU版AI框架 如果我们想在windows系统上安装GPU版本的AI框架,比如GPU版本的tesnorflow,通常我们会看到类似下面的安装教程 官方版本 安装CUDA 安 ...
- Spring Boot(5)一个极简且完整的后台框架
https://blog.csdn.net/daleiwang/article/details/75007588 Spring Boot(5)一个极简且完整的后台框架 2017年07月12日 11:3 ...
- Spring Boot (七): Mybatis极简配置
Spring Boot (七): Mybatis极简配置 1. 前言 ORM 框架的目的是简化编程中的数据库操作,经过这么多年的发展,基本上活到现在的就剩下两家了,一个是宣称可以不用写 SQL 的 H ...
- Asp.NetCore Web开发之RazorPage
这节讲一下Razor页面. 首先要明确,Razor 不是一种编程语言.它是服务器端的标记语言,配合C#语言,就可以像PHP语言语言一样(但它们并不相同),处理HTML页面逻辑.它是Asp.NetCor ...
- 通过极简模拟框架让你了解ASP.NET Core MVC框架的设计与实现[上篇]
<200行代码,7个对象--让你了解ASP.NET Core框架的本质>让很多读者对ASP.NET Core管道有了真实的了解.在过去很长一段时间中,有很多人私信给我:能否按照相同的方式分 ...
- CentOS安装使用.netcore极简教程(免费提供学习服务器)
本文目标是指引从未使用过Linux的.Neter,如何在CentOS7上安装.Net Core环境,以及部署.Net Core应用. 仅针对CentOS,其它Linux系统类似,命令环节稍加调整: 需 ...
- Resty 一款极简的restful轻量级的web框架
https://github.com/Dreampie/Resty Resty 一款极简的restful轻量级的web框架 开发文档 如果你还不是很了解restful,或者认为restful只是一种规 ...
随机推荐
- python基础--网站推荐
Python教程 - 廖雪峰的官方网站 Python 基础教程 | 菜鸟教程 随笔分类 - 机器学习
- 本地Markdown文件上传到博客
本地Markdown文件上传到博客 参考:https://www.cnblogs.com/ccylhw/p/13954153.html 1.Typora 最漂亮的写作APPhttps://www.ty ...
- 新环境c7、php7.4、openssl1.1.1g,再discuz里发送邮件总是报ssl连接不上
Warning: fsockopen(): SSL operation failed with code 1. OpenSSL Error messages: error:1416F086:SSL r ...
- Docker系列(26)- 发布镜像到阿里云容器服务
1.登录阿里云 2.找到容器镜像服务 3.创建命名空间 4.创建镜像仓库 5.上传镜像
- 剑指offer计划25(模拟中等)---java
1.1.题目1 剑指 Offer 29. 顺时针打印矩阵 1.2.解法 常规开头,先判断特殊情况,然后创建四个变量存放矩阵四边的长度限制. 创建res数组存放结果. 循坏开始,遍历完一行或者一列,就将 ...
- YbtOJ#912-神秘语言【结论,欧拉定理】
正题 题目链接:http://www.ybtoj.com.cn/problem/912 题目大意 给出\(L,R\),求有多少长度在\([L,R]\)之间的字符串满足依次取出所有偶数位置的放在最前面后 ...
- 一篇文章告诉你Python接口自动化测试中读取Text,Excel,Yaml文件的方法
前言 不管是做Ui自动化和接口自动,代码和数据要分离,会用到Text,Excel,Yaml.今天讲讲如何读取文件数据 Python也可以读取ini文件,传送门 记住一点:测试的数据是不能写死在代码里面 ...
- 深入浅出WPF-03.XAML语法
2 XAML语法 树形结构,我们将整个XAML的结构想象成一棵树,我们从树的顶部向下看,形成俯视图.最上面的叶子节点会覆盖父节点,同级的子节点,后面的(也就是树的最上面)会覆盖前面的.覆盖包含了形状( ...
- 解决报错:Unable to process Jar entry [org/springframework/jmx/export/annotation/*****]
情况说明:从gitub上clone的maven项目,pox.xml配置中的依赖,自己的repository都有,所以正常update project ,正常clean,install,整个过程无报错 ...
- Unity3D组成
从宏观的角度来看,分为七个模块: 1.图形模块(Graphics). 2.物理模块(Physics) 3. 音效模块(Audio) 4.动作模块(Animation) 5.导航模块(Navigatio ...