最近公司来了一个陕北的实习妹子,据说家里是开矿的,人长得一般,但很有气质。开矿的,当然钱很多了。以前在大学有个同学,家里是开油田的,有节毛概课,老师说西安的房价都是陕北人轰起来的,西安人都怨陕北人。我这个同学听了不开心了,周末直接在东西南北各买一套。牛逼啊,让你老师多嘴。这几天周围的同事心思都在这个姑娘身上,装作喝咖啡过去瞄一眼,或者站起来瞅瞅背影。IT爷们真的是空虚,IT界无美女啊,还是吉日嘎啦说的好,公司有美女,可以提升爷们的战斗力。
OK,今天我们来看一下新闻审核界面,本来这节是要说ueditor上传图片到mongoDB,但是最近实在精力有限,先放放,稍后再上博客。我们先看一下界面,提提神。
这个界面上面部分是查询,采用响应式布局方式。当在手机或者pad的浏览器上的时候,依然能够正常显示并使用。
OK,我们今天主要看的不是界面,还是看功能的实现。
首先先看一下查询功能,查询有个新闻类别的下拉列表,后台Action代码如下
[HttpGet] public JsonResult GetNewsTypeList() { List<NewsTypesEntity> newsTypeEntityList = NewsMngBiz.GetInstance().GetNewsTypes(); newsTypeEntityList.Insert(0, new NewsTypesEntity() { TransactionNumber = null, NewsTypeName = CommonResouce.DefaultSelectText }); return Json(newsTypeEntityList, JsonRequestBehavior.AllowGet); }
OK,接下来我们就要看界面了
@{ Layout = null; } <div ng-app="newsAuditModule" ng-controller="newsAuditController" id="div_newsAudit" class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title"> <img class="img-panel-title" src="~/Images/Base/audit.png" /> <b>新闻审核</b> </h3> </div> <div class="panel-body"> <div class="row" style="line-height:30px"> <label for="newsTitle" class="col-sm-2 control-label">新闻标题</label> <div class="col-sm-10"> <input type="text" maxlength="100" class="form-control" id="newsTitle" ng-model="newsTitle" placeholder="请输入新闻标题查询"> </div> </div> <div class="row" style="margin-top: 5px; margin-bottom: 5px; line-height: 30px"> <label for="newsTitle" class="col-sm-2 control-label">新闻类别</label> <div class="col-sm-10"> <select id="newsTitle" class="form-control" ng-model="newsType"> @*<option value="">---请选择---</option>*@ <option ng-repeat="type in NewsTypeList" value="{{type.TransactionNumber}}">{{type.NewsTypeName}}</option> </select> </div> </div> <div class="row" style="line-height:30px"> <label for="newsTitle" class="col-sm-2 control-label">审核状态</label> <div class="col-sm-10"> <select id="newsTitle" class="form-control" ng-model="newsState"> <option value="">---请选择---</option> <option value="-1">未审核</option> <option value="0">未通过</option> <option value="1">通过</option> </select> </div> </div> <div class="row" style="margin-top:10px"> <div class="col-sm-3"> <button type="button" class="btn btn-primary btn-form-width" ng-click="getDataList()">查询</button> </div> </div> <div class="pre-scroll" style="margin-top:10px"> <table class="table table-bordered table-striped table-hover" ng-init="load()"> <tr style="background-color: #428bca; color: white"> <th><input type="checkbox" ng-model="isCheckAll" ng-change="setCheckState()"></th> <th>新闻标题</th> <th>新闻类别</th> <th>创建日期</th> <th>审核状态</th> <th>审核人</th> <th>审核日期</th> <th>操作</th> </tr> <tr ng-repeat="newsEntity in NewsList"> <td><input id="chk_{{newsEntity.TransactionNumber}}" type="checkbox" ng-model="newsEntity.IsChecked" /></td> <td title="{{newsEntity.Title}}">{{newsEntity.SubTitle}}</td> <td>{{newsEntity.InforType}}</td> <td>{{newsEntity.InDate.slice(6,-2)|date:‘yyyy-MM-dd‘}}</td> <td style="color:{{ newsEntity.Color }}">{{newsEntity.AuditStatus}}</td> <td>{{newsEntity.AuditUserName}}</td> <td>{{newsEntity.AuditDate.slice(6,-2)|date:‘yyyy-MM-dd‘}}</td> <td> <span style="cursor:pointer;"> <a href="#"><img title="浏览" src="~/Images/Base/preview.png" class="img-table-column" /></a> <a href="#"><img title="审核" ng-click="auditModalShow(newsEntity)" src="~/Images/Base/key.png" class="img-table-column" /></a> </span> </td> </tr> </table> </div> <div class="btn-group dropup"> <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> 批量操作<span class="caret"></span> </button> <ul class="dropdown-menu" role="menu"> <li><a href="#" ng-click="batchOperation(‘A‘)">批量通过</a></li> <li class="divider"></li> <li><a href="#" ng-click="batchOperation(‘D‘)">批量删除</a></li> </ul> </div> </div> <div class="modal fade" id="newAuditModal" tabindex="-1" role="dialog" aria-labelledby="auditModalTitle" aria-hidden="true" data-backdrop="static"> <div class="modal-dialog"> <div class="modal-content" style="width:550px"> <div class="modal-header" style="background-color: #009966;height:45px;line-height:45px"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true"> × </button> <h5 class="modal-title" id="auditModalTitle" style="color:white"> 新闻审核 </h5> </div> <div class="modal-body"> <div class="form-horizontal"> <div class="form-group"> <label class="col-md-3" for="labTitle">新闻标题:</label> <div class="col-md-9"> <label id="labTitle"></label> </div> </div> <div class="form-group"> <label class="col-md-3">审核结果:</label> <div class="col-md-9"> <input type="radio" name="radAuditResult" ng-change="setAuditResaonEditable()" value="1" checked ng-model="AuditResult"> 通过 <input type="radio" name="radAuditResult" ng-change="setAuditResaonEditable()" value="0" ng-model="AuditResult" style="margin-left:10px"> 不通过 </div> </div> <div class="form-group"> <label class="col-md-3" for="div_reason">未通过原因:</label> <div class="col-md-9"> <div id="div_reason" style="border: 1px solid #003366; height: 90px; word-break: break-all;max-height:90px;overflow-y:scroll" contenteditable="true"></div> </div> </div> </div> </div> <div class="modal-footer"> <button type="button" ng-click="auditNews()" class="btn btn-primary btn-form-width"> 提交 </button> <button type="button" class="btn btn-danger btn-form-width" data-dismiss="modal"> 关闭 </button> </div> </div><!-- /.modal-content --> </div><!-- /.modal --> </div> </div>
查询条件下拉列表的初始化很简单。
$scope.getNewsTypeList = function () { $http.get("/NewsManage/GetNewsTypeList").success(function (data) { $scope.NewsTypeList = data; }); };
接下来我们看一下查询功能,点击查询按钮,调用getDataList方法
$scope.getDataList = function () { $scope.isCheckAll = false; var param = { requestJson: JSON.stringify({ Title: $.trim($scope.newsTitle), InforType: $scope.newsType, AuditStatus: $scope.newsState }) }; $http({ method: "post", url: "/NewsManage/GetNewsNativeList", headers: { ‘Content-Type‘: ‘application/x-www-form-urlencoded‘ }, data: $.param(param) }).success(function (data, status, headers, config) { $scope.NewsList = data; angular.forEach($scope.NewsList, function (value, key) { if ($.trim(value.AuditState) == "") { value.Color = "#003366;" } else if (value.AuditState == "0") { value.Color = "#FF0033;" } else { value.Color = "#009966"; } }); }); }
传入查询条件,并且在返回结果后,对颜色进行设置,未审核是蓝色,审核通过是绿色,不通过是红色。<td style="color:{{ newsEntity.Color }}">{{newsEntity.AuditStatus}}</td>这段就是设置审核状态颜色的,颜色是根据Color属性显示的。
OK,查询完了之后,我们看一下最底下的批量操作按钮。
点击批量操作按钮,其实是弹出一个菜单,有批量通过和批量删除两个选项,这正是BootStrap中的按钮菜单。点击批量通过,其实是要将上面选中的新闻全部审核通过,删除也雷同。我们看一下,点击批量通过调用的js方法batchOperation(‘A‘)。
$scope.batchOperation = function (operationType) { var selectedIDs = []; angular.forEach($scope.NewsList, function (value, key) { if (value.IsChecked) { selectedIDs.push(value.TransactionNumber); } }); if (selectedIDs.length == 0) { alert(‘请选择要批量操作的数据!‘); return; } var param = { requestJson: JSON.stringify({ newsIDs: selectedIDs }) }; var postAction = operationType == "A" ? "BatchPassNewsAudit" : "BatchNativeNewsDelete"; $http({ method: "post", url: "/NewsManage/" + postAction, headers: { ‘Content-Type‘: ‘application/x-www-form-urlencoded‘ }, data: $.param(param) }).success(function (data, status, headers, config) { if (data.suc == "1") { $scope.getDataList(); } alert(data.msg); }); }
首先会check有没有选中的数据,然将选中的主键传到后台action进行处理。
[HttpPost] public JsonResult BatchPassNewsAudit() { string requestJson = Request["requestJson"]; string[] userIDArray = JsonBuilder.BuildStringArray(requestJson, "newsIDs"); int suc = NewsMngBiz.GetInstance().BatchAuditPass(string.Join(",", userIDArray), this.UserID); if (suc > 0) { return GetJsonMessage("NM_001", JsonMsgType.SUCCESS); } return GetJsonMessage("NM_002"); }
ok,我们再看一下批量删除,批量删除和批量通过走的是一个js方法并且action也雷同,所以在这里我们只看一下删除的sql脚本。
DECLARE @NewsIDTable TABLE ( ID INT IDENTITY(1,1), TransactionNumber INT NOT NULL ) INSERT INTO @NewsIDTable ( TransactionNumber ) SELECT short_str FROM ChinaInformation.dbo.F_SQLSERVER_SPLIT(@NewsIDs,‘,‘) DELETE FROM ChinaInformation.dbo.InformationNative OUTPUT DELETED.NewsContent, DELETED.InfoTypeID, DELETED.AuditState, DELETED.InDate, DELETED.InUser, DELETED.LastEditDate, DELETED.LastEditUser, DELETED.AuditUser, DELETED.AuditDate, DELETED.Title, GETDATE(), @UserID INTO ChinaInformation.dbo.InformationNativeDeleteLog WHERE TransactionNumber IN( SELECT TransactionNumber FROM @NewsIDTable )
删除的时候要将删除记录插入log表。
接下来我们再看一下单个审核功能
当点击审核图标的时候,弹出modal页面。
<a href="#"><img title="审核" ng-click="auditModalShow(newsEntity)" src="~/Images/Base/key.png" class="img-table-column" /></a>
$scope.auditModalShow = function (newsEntity) { angular.element("#labTitle").text(newsEntity.SubTitle); angular.element("#labTitle").attr("title", newsEntity.Title); $scope.SelectID = newsEntity.TransactionNumber; angular.AuditResult = "1"; if (typeof (Storage) !== "undefined" && sessionStorage.auditReason != undefined && sessionStorage.auditReason != "" && $scope.AuditResult == "0") { document.getElementById("div_reason").innerHTML = sessionStorage.auditReason; } angular.element(‘#newAuditModal‘).modal(‘show‘); }
在这里我们把标题什么的,都附上。标题因为有的可能太长,所以我就设置需要显示的为SubTitle,title为原有没有截断的新闻标题,这样用户鼠标放上去就可以看到完整的标题。
默认值设置完了之后,我们判断如果本地session存储sessionStorage中存储的auditReason有值,我们就把它赋给div。注意这里的div,它的contenteditable为true的话是可以编辑的。另外,想让它换行,又不至于高度一直扩展,我们加了滚动条。
<div id="div_reason" style="border: 1px solid #003366; height: 90px; word-break: break-all;max-height:90px;overflow-y:scroll" contenteditable="true"></div>
OK,最后我们看一下通过和不通过的change事件。
$scope.setAuditResaonEditable = function () { var div_auditReason = document.getElementById("div_reason"); if ($scope.AuditResult == "1") { div_auditReason.contentEditable = "false"; div_auditReason.style.backgroundColor = "#999999"; if (typeof (Storage) !== "undefined") { sessionStorage.auditReason = document.getElementById("div_reason").innerHTML; } div_auditReason.innerHTML = ""; } else { div_auditReason.contentEditable = "true"; div_auditReason.style.backgroundColor = "#FFFFFF"; } }
当radio的值有变化的时候,调用上面js方法。如果审核通过被选中,那么我们需要把不通过原因存储在本地session中,注意本地session的作用域是浏览器,浏览器关了就没有了。另外还要特别注意的是这里的div_auditReason.contentEditable = "true";一定得是"true",双引号括起来的true。contentEditable 这个单词的E一定要大写,不然就不会有任何效果。下面这两张图就是radio change效果。
OK,最后我们再看一下后台的处理
$scope.auditNews = function () { var unPassReason = document.getElementById("div_reason").innerHTML; if ($scope.AuditResult == "0" && (unPassReason == "" || unPassReason.length < 10)) { alert("不通过原因不能少于10个字!"); return; } var param = { requestJson: JSON.stringify({ TransactionNumber: $scope.SelectID, AuditStatus: $scope.AuditResult, UnPassReason: $scope.AuditResult == "1" ? "" : unPassReason }) }; $http({ method: "post", url: "/NewsManage/NewsAuditSingle", headers: { ‘Content-Type‘: ‘application/x-www-form-urlencoded‘ }, data: $.param(param) }).success(function (data, status, headers, config) { if (data.suc == "1") { $scope.getDataList(); } alert(data.msg); }); };
后台代码如下
[HttpPost] public JsonResult NewsAuditSingle(FormCollection fc) { string requestJson = fc["requestJson"]; string auditState = JsonBuilder.BuildValueByType<string>(requestJson, "AuditStatus"); int transactionNumber = JsonBuilder.BuildValueByType<int>(requestJson, "TransactionNumber"); string unPassReason = JsonBuilder.BuildValueByType<string>(requestJson, "UnPassReason"); int suc = NewsMngBiz.GetInstance().NewsNativeAuditSingle(transactionNumber, auditState, unPassReason, this.UserID); if (suc > 0) { return GetJsonMessage("NM_005", JsonMsgType.SUCCESS); } return GetJsonMessage("NM_006"); }
OK,今天就到这里,这个界面还剩余一个新闻预览功能,和审核不通过原因查看。