概述
關于這個框架的背景,在前面我已經交代過了,不清楚的可以查看這個鏈接
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="https://www.cnblogs.com/mhg215/p/~/css/site.min.css" rel="stylesheet" asp-append-version="true" /> <link href="https://www.cnblogs.com/mhg215/p/~/css/goods.css" rel="stylesheet" asp-append-version="true" /> } <div id="container"> <form action="" id="app" lay-filter="column-edit"> <div > <div > <div >基本屬性</div> <div > <label>所屬分類</label> <div > <select name="categoryId" id="categoryId" lay-search=""> <option value="https://www.cnblogs.com/mhg215/p/0">父級</option> </select> </div> </div> <div > <label>初始銷量</label> <div > <input type="text" name="salesInitial" maxlength="100" autocomplete="off" > </div> </div> <div > <label>商品狀態</label> <div > <input type="radio" name="goodsStatus" lay-skin="primary" value="https://www.cnblogs.com/mhg215/p/10" title="上架" /> <input type="radio" name="goodsStatus" lay-skin="primary" value="https://www.cnblogs.com/mhg215/p/20" title="下架" /> </div> </div> <div > <label>運費模板</label> @*目前現呼叫字典表的模板*@ <div > <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="https://www.cnblogs.com/mhg215/p/@item.Id">@item.Name</option> } } </select> </div> </div> </div> <div > <div > <label required>商品名稱</label> <div > <input type="text" name="name" maxlength="100" lay-verify="required" lay-verType="tips" autocomplete="off" > </div> </div> <div > <label >商品圖片</label> <div > <button type="button" id="btnUploadShowImg">上傳圖片</button> <blockquote style="margin-top: 10px;margin-left:110px;"> 預覽圖: <div id="demo2"></div> </blockquote> </div> </div> <hr /> <div > <label required>商品規格</label> <div > <input type="radio" name="specType" lay-skin="primary" value="https://www.cnblogs.com/mhg215/p/10" lay-filter="specType" title="單規格" checked/> <input type="radio" name="specType" lay-skin="primary" value="https://www.cnblogs.com/mhg215/p/20" lay-filter="specType" title="多規格" /> </div> </div> <div > <div > <!-- 規格屬性 --> <div ></div> <!-- 添加規格:按鈕 --> <div > <button type="button" >添加規格</button> </div> <!-- 添加規格:表單 --> <div > <div > <label >規格名 </label> <input type="text" placeholder="請輸入規格名稱"> </div> <div > <label >規格值 </label> <input type="text" placeholder="請輸入規格值"> </div> <div > <button type="button" color: rgba(0, 0, 0, 1)">btn-addSpecName am-btn am-btn-xs am-btn-secondary"> 確定 </button> <button type="button" color: rgba(0, 0, 0, 1)">btn-cancleAddSpecName am-btn am-btn-xs am-btn-default"> 取消 </button> </div> </div> <!-- 商品多規格sku資訊 --> <div > <!-- 分割線 --> <div ></div> <!-- sku 批量設定 --> <div > <div > <label >批量設定</label> </div> <div > <input type="text" data-type="goods_no" placeholder="商家編碼"> </div> <div > <input type="number" data-type="goods_price" placeholder="銷售價"> </div> <div > <input type="number" data-type="line_price" placeholder="劃線價"> </div> <div > <input type="number" data-type="stock_num" placeholder="庫存數量"> </div> <div > <input type="number" data-type="goods_weight" placeholder="重量"> </div> <div > <button type="button" color: rgba(0, 0, 0, 1)">btn-specBatchBtn am-btn am-btn-sm am-btn-secondary am-radius"> 確定 </button> </div> </div> <!-- sku table --> <table ></table> </div> </div> </div> <div id="sigleSpec"> <div > <label required>商品價格</label> <div > <input type="text" name="goodsPrice" maxlength="30" autocomplete="off" > </div> </div> <div > <label required>商品劃線價</label> <div > <input type="text" name="linePrice" maxlength="40" autocomplete="off" > </div> </div> <div > <label >商品編碼</label> <div > <input type="text" name="goodsNo" maxlength="40" autocomplete="off" > </div> </div> <div > <label required>庫存數量</label> <div > <input type="number" name="stockNum" maxlength="40" > </div> </div> <div > <label required>商品重量(Kg)</label> <div > <input type="number" name="goodsWeight" maxlength="40" > </div> </div> </div> <div > <label required>庫存計算</label> <div > <input type="radio" name="deductStockType" value="https://www.cnblogs.com/mhg215/p/10" lay-skin="primary" title="下單減庫存" /> <input type="radio" name="deductStockType" value="https://www.cnblogs.com/mhg215/p/20" lay-skin="primary" title="付款減庫存" /> </div> </div> </div> <div > <div > <label >商品詳情</label> <div > <textarea id="content" name="content" placeholder="請輸入內容" ></textarea> </div> </div> </div> <div > <div > <button lay-submit lay-filter="saveBtn">確認保存</button> </div> </div> </div> </form> </div> @section js{ <script src="https://www.cnblogs.com/lib/tinymce/tinymce.min.js"></script> <script src="https://www.cnblogs.com/lib/tinymce/langs/zh_CN.js"></script> <script src="https://www.cnblogs.com/mhg215/p/~/lib/jquery-3.4.1/jquery-3.4.1.min.js"></script> <script src="https://www.cnblogs.com/mhg215/p/~/js/goodsSpec.js" asp-append-version="true"></script> <script src="https://www.cnblogs.com/mhg215/p/~/js/art-template.js" asp-append-version="true"></script> <script src="https://www.cnblogs.com/mhg215/p/~/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 =https://www.cnblogs.com/mhg215/p/= 10) { $("#sigleSpec").show() && $(".goods-spec-many").hide(); } //多規格 if (data.value =https://www.cnblogs.com/mhg215/p/= 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
喜歡交流的人進微信群

作者:realyrare
出處:https://www.cnblogs.com/mhg215/
聲援博主:如果您覺得文章對您有幫助,請點擊文章末尾的【關注我】吧!
別忘記點擊文章右下角的【推薦】支持一波,~~~///(^v^)\\\~~~ .
如果您有其他問題,也歡迎關注我的公眾號,可以聯系我一起交流切磋!
本文著作權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/340289.html
標籤:.NET Core
上一篇:IOC和DI之刨根問底之第一節
