ABP module-zero +AdminLTE+Bootstrap Table+jQuery權(quán)限管理系統(tǒng)第十二節(jié)--小結(jié),Bootstrap Table之角色管理

ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期
Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS
前往博客園總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期

很多人說(shuō)ABP不適合高并發(fā)大型,有一定的道理,但是我覺(jué)得還是可以的,就看架構(gòu)師的能力了,我之前公司

就是ABP絕對(duì)百萬(wàn)數(shù)據(jù)級(jí)項(xiàng)目,是一個(gè)在線教育網(wǎng)站,涉及到平臺(tái),學(xué)院,院系,班級(jí),課程,學(xué)生等,一個(gè)平臺(tái)多少大學(xué),

一個(gè)大學(xué)多少院系,一個(gè)院系多少班級(jí)多少課程,其負(fù)責(zé)程度一點(diǎn)都不簡(jiǎn)單,不說(shuō)了,那是大神,比我在園子看到絕對(duì)大

多數(shù)架構(gòu)師都強(qiáng)悍.是我等仰望都對(duì)象.但是這不是停下腳步仰望的理由,只會(huì)是我們追求更強(qiáng)的腳步.
隨著軟件工作時(shí)間開(kāi)發(fā)經(jīng)驗(yàn)的不斷增加,我們發(fā)現(xiàn)其實(shí)很多工作都是重復(fù)機(jī)械的,而且隨著軟件復(fù)

雜度的不斷提升,以往依靠經(jīng)驗(yàn)來(lái)完成一些簡(jiǎn)單的增刪改查的做法已經(jīng)行不通了蜡坊。特別是用戶的要求越來(lái)越高典奉,希

望添加的功能越來(lái)多拇惋,目前這種開(kāi)發(fā)模式秒啦,已經(jīng)捉襟見(jiàn)肘。我很難想象如何在現(xiàn)有的模式下進(jìn)行多系統(tǒng)的持續(xù)集成

并添加一些新的特性虱朵。
開(kāi)發(fā)一個(gè)系統(tǒng)時(shí),我們不可避免的會(huì)使用各種框架钓账。數(shù)據(jù)持久層實(shí)現(xiàn)碴犬、日志、ASP[.NET]

(http://lib.csdn.net/base/dotnet)MVC梆暮、IOC以及自動(dòng)映射等服协。一個(gè)高質(zhì)量的軟件系統(tǒng)往往還有全局容錯(cuò),消息隊(duì)

列等組件啦粹。
其實(shí)偿荷,我們無(wú)非是希望在編程的時(shí)候治专,把大部分的注意力全部集中到業(yè)務(wù)實(shí)現(xiàn)上。不要過(guò)多的考

慮基礎(chǔ)的軟件結(jié)構(gòu)上的種種問(wèn)題遭顶。應(yīng)該有一個(gè)框框或者一種范式來(lái)提供基本的服務(wù)张峰,如日志、容錯(cuò)和AOP棒旗,DI等喘批。
稍微正規(guī)一點(diǎn)的公司經(jīng)過(guò)多年沉淀都形成了自己的內(nèi)部軟件框架,他們?cè)陂_(kāi)發(fā)軟件的時(shí)候并不是

從一片空白開(kāi)始的铣揉。而是從一個(gè)非常牢固的基礎(chǔ)平臺(tái)上開(kāi)始構(gòu)建的饶深。這樣大大提高了開(kāi)發(fā)速度,而且一種架構(gòu)往往

也決定了分工協(xié)作的模式逛拱。我們目前之所以無(wú)法分工協(xié)作敌厘,根本原因也是缺少一套成熟穩(wěn)定的基礎(chǔ)開(kāi)發(fā)架構(gòu)和工作

流程。
目前.NET上有不少開(kāi)源框架朽合。比如Apworks和ABP俱两。其中Apworks是中國(guó)人寫(xiě)的一套開(kāi)源框架。它是

一個(gè)全功能的曹步,不僅可以寫(xiě)分布式應(yīng)用宪彩,也可以寫(xiě)桌面應(yīng)用。ABP的全稱是Asp[.net]

(http://lib.csdn.net/base/dotnet)boilerplate project(asp.Net樣板工

程)讲婚。是github上非衬蚩祝活躍的一個(gè)開(kāi)源項(xiàng)目。它并沒(méi)有使用任何新的技術(shù)筹麸,只是由兩名架構(gòu)師將asp.net開(kāi)發(fā)中常用

的一些工具整合到了一起活合,并且部分實(shí)現(xiàn)了DDD的概念。是一個(gè)開(kāi)箱即用的框架物赶,可以作為asp.net分布式應(yīng)用的一

個(gè)良好起點(diǎn)白指。
使用框架當(dāng)然有代價(jià),你必須受到框架強(qiáng)API的侵入块差,抑或要使用他的方言侵续。而且這個(gè)框架想要吃

透,也要付出很大的學(xué)習(xí)成本憨闰。但是好處也是顯而易見(jiàn)的状蜗。業(yè)界頂尖的架構(gòu)師已經(jīng)為你搭建好了一套基礎(chǔ)架構(gòu),很

好的回應(yīng)了關(guān)于一個(gè)軟件系統(tǒng)應(yīng)該如何設(shè)計(jì)鹉动,如何規(guī)劃的問(wèn)題轧坎,并且提供了一套最佳實(shí)踐和范例。
學(xué)習(xí)雖然要付出成本泽示,但是經(jīng)過(guò)漫長(zhǎng)的跋涉缸血,我們從一無(wú)所知已經(jīng)站到了工業(yè)級(jí)開(kāi)發(fā)的門(mén)檻

上蜜氨。基于這個(gè)框架捎泻,我們可以很好的來(lái)劃分任務(wù)飒炎,進(jìn)行單元測(cè)試等。

大大降低了軟件出現(xiàn)BUG的幾率笆豁。
這節(jié)我就來(lái)說(shuō)一下在ABP module-zero基礎(chǔ)上做AdminLTE+Bootstrap Table的系統(tǒng),算是前面十一節(jié)的總結(jié)和擴(kuò)展.
首先我們依舊去官網(wǎng)根據(jù)abp模板創(chuàng)建解決方案.勾選上module-zero,然后創(chuàng)建數(shù)據(jù)庫(kù)連接,還原nuget包,然后update-database創(chuàng)建數(shù)據(jù)庫(kù).
接下來(lái)就是創(chuàng)建腳本更新數(shù)據(jù)庫(kù)了,以上這些都在前面的章節(jié)講到了,我就不做累述了,不明白可回去一下第一節(jié).
然后在home控制器下建ActionResult login,添加一個(gè)試圖頁(yè)面.加上自己的登陸頁(yè)面樣式j(luò)s等,這里我們就不用mvc的形式再在去請(qǐng)求控制器 了,我們直接請(qǐng)求webapi的登陸方法了.是的就是已經(jīng)搭好了swagger的然后請(qǐng)求/swagger/ui/index的Account接口.如圖.


既然前面講到ABP 對(duì)javascript ajax的封裝

var newPerson = {
   name: 'Dougles Adams',
   age: 42
};

abp.ajax({
   url: '/People/SavePerson',
   data: JSON.stringify(newPerson)
}).done(function(data) {
   abp.notify.success('created new person with id = ' + data.personId);
});

其實(shí)這里我們還可以做一些再次封裝郎汪,方便在項(xiàng)目中去使用,就以登陸為例效果如下闯狱。

abp.ui.block($('#login'));
              var url = "/api/Account";
              var login = function (para, ajaxtype,posturl) {
                  return abp.ajax({
                      url: posturl,
                      type: ajaxtype,
                      async: false,
                      data: JSON.stringify(para)
                  });
              };

              var loginModel = {
                  "tenancyName": "",
                  "usernameOrEmailAddress": $("#userName").val(),
                  "password": $("#password").val()
              };

             
              abp.ui.setBusy(
                  $('#login'),
                  login(loginModel, "post", url).done(function (data) {
                      abp.auth.setToken("Bearer " + data);
                     window.location.href = "/admin/userinfo/index"
                  }),
                
              );

當(dāng)然這是在ABP原來(lái)封裝的效果上加上的煞赢,細(xì)心的你已經(jīng)發(fā)現(xiàn)這里多了兩個(gè)東西,一個(gè)是abp.ui.block哄孤,另外一個(gè)是abp.ui.setBusy照筑,這其實(shí)是一個(gè)阻止用戶重復(fù)提交,和正在提交繁忙狀態(tài)瘦陈,
其實(shí)就是一個(gè)遮罩層凝危。



這里是ABP集成的jquery.blockUI.js插件,該API使用一個(gè)透明的涂層(transparent overlay)來(lái)阻塞整個(gè)頁(yè)面或者該頁(yè)面上的一個(gè)元素双饥。這樣媒抠,用戶的點(diǎn)擊就無(wú)效了。當(dāng)保存一個(gè)表單或者加載一個(gè)區(qū)域(一個(gè)div或者整個(gè)頁(yè)面)時(shí)這是很有用的咏花。比如
另外abpjs中也對(duì)blockUI做了一些常用方法的封裝,設(shè)置阻塞abp.ui.block阀趴,取消阻塞abp.ui.unblock 昏翰,設(shè)置繁忙狀abp.ui.setBusy 和解除繁忙狀態(tài)abp.ui.clearBusy

abp.ui.block = function (elm) {
       abp.log.warn('abp.ui.block is not implemented!');
   };

   abp.ui.unblock = function (elm) {
       abp.log.warn('abp.ui.unblock is not implemented!');
   };

   /* UI BUSY */
   //Defines UI Busy API, not implements it

   abp.ui.setBusy = function (elm, optionsOrPromise) {
       abp.log.warn('abp.ui.setBusy is not implemented!');
   };

   abp.ui.clearBusy = function (elm) {
       abp.log.warn('abp.ui.clearBusy is not implemented!');
   };
 abp.ui.block(); //阻塞整個(gè)頁(yè)面
  abp.ui.block($('#MyDivElement')); //可以使用jQuery 選擇器..
  abp.ui.block('#MyDivElement'); //..或者直接使用選擇器
  abp.ui.unblock(); //解除阻塞整個(gè)頁(yè)面
  abp.ui.unblock('#MyDivElement'); //解除阻塞特定的元素

UI Block API默認(rèn)使用jQuery的blockUI插件實(shí)現(xiàn)的。要是它生效刘急,你應(yīng)該包含它的javascript文件棚菊,然后在頁(yè)面中包含abp.blockUI.js作為適配器。
另外一個(gè)就是busy 該API用于使得某些頁(yè)面或者元素處于繁忙狀態(tài)叔汁。比如统求,你可能想阻塞一個(gè)表單,然后當(dāng)提交表單至服務(wù)器時(shí)展示一個(gè)繁忙的指示器据块。例子:

   abp.ui.setBusy('#MyLoginForm');
   abp.ui.clearBusy('#MyLoginForm');

效果就是上面的繁忙效果码邻。
該參數(shù)應(yīng)該是一個(gè)選擇器(如‘#MyLoginForm’)或者jQuery選擇器(如$('#MyLoginForm'))。要使得整個(gè)頁(yè)面處于繁忙狀態(tài)另假,你可以傳入null(或者'body')作為選擇器像屋。setBusy函數(shù)第二個(gè)參數(shù)接收一個(gè)promise(約定),當(dāng)該約定完成時(shí)會(huì)自動(dòng)清除繁忙的狀態(tài)边篮。因?yàn)閍bp.ajax返回promise己莺,我們可以直接將它作為promise傳入奏甫。要學(xué)習(xí)慣于promise更多的東西,查看jQuery的Deferred凌受。
UI Busy API是使用spin.js實(shí)現(xiàn)的阵子。要讓它生效,應(yīng)該包含它的javascript文件胜蛉,然后在頁(yè)面中包含abp.spin.js作為適配器款筑。
經(jīng)過(guò)上面的努力,我們得登陸也已經(jīng)做好了腾么。登陸成功之后我們要做事的事情就是一個(gè)保存token另外一個(gè)就是路由的重定向了奈梳。
token在ABP中很重要,我們?cè)谡?qǐng)求 /api/Account會(huì)反饋一個(gè)token解虱,我們?cè)诘顷懙臅r(shí)候就把token存到cookie中攘须,以方便后面的使用。如登陸中的 abp.auth.setToken("Bearer " + data); 那ABP是怎么樣設(shè)置cookie的了殴泰,這里也做了封裝于宙。

abp.auth.tokenCookieName = 'Abp.AuthToken';

   abp.auth.setToken = function (authToken, expireDate) {
       abp.utils.setCookieValue(abp.auth.tokenCookieName, authToken, expireDate, abp.appPath);
   };

   abp.auth.getToken = function () {
       return abp.utils.getCookieValue(abp.auth.tokenCookieName);
   }

   abp.auth.clearToken = function () {
       abp.auth.setToken();
   }

這里面就包含了token常用的存取和清除的方法。頁(yè)面上緩存的cookie名字就是Abp.AuthToken悍汛,獲取的時(shí)候可以直接獲取捞魁。


我們?cè)谝呀?jīng)添加了域,所以這里登陸成功之后直接把url指向/admin/userinfo/index离咐。當(dāng)然在/Areas/Common/Views/Layout里面我們已經(jīng)AdminLTE的布局了谱俭,包括菜單已經(jīng)加載出來(lái)了,其實(shí)現(xiàn)在服務(wù)層的時(shí)候漏了一些東西宵蛀,我們這里補(bǔ)上昆著,ABP既然是一個(gè)框架
那么在創(chuàng)建Service的時(shí)候自然要包含基礎(chǔ)增刪查改的方法,那么這時(shí)候IAsyncCrudAppService就派上用場(chǎng)了术陶。這里我們以模板IModulesService講一下凑懂。首先我們創(chuàng)建好model和DTO

using Abp.Domain.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JCms.Meuns
{
  public class Meun : Entity<int>, IMayHaveTenant
  {
      public int? ParentId { get; set; }
      [Required]
      [StringLength(20)]
      public string Name { get; set; }
      [Required]
      [StringLength(50)]
      public string LinkUrl { get; set; }
      [StringLength(100)]
      public string Description { get; set; }
      public bool IsMenu { get; set; }
      public int Code { get; set; }
      public bool Enabled { get; set; }

      public DateTime UpdateDate { get; set; }
      public int? TenantId { get; set; }

  
  }
}

DTO:

using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Abp.Domain.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JCms.Meuns
{
  /// <summary>
  /// 菜單
  /// </summary>
  [Serializable]
  [AutoMapFrom(typeof(Meun))]
  public class MeunDto : EntityDto<int>
  {  /// <summary>
     /// id
     /// </summary>
      public int Id { get; set; }
      /// <summary>
      /// 父模塊Id
      /// </summary>
      public int? ParentId { get; set; }
      /// <summary>
      /// 名稱
      /// </summary>
      [Required]
      [StringLength(20)]
      public string Name { get; set; }
      /// <summary>
      /// 鏈接地址
      /// </summary>
      [Required]
      [StringLength(50)]
      public string LinkUrl { get; set; }

      /// <summary>
      /// 是否是菜單
      /// </summary>
      public bool IsMenu { get; set; }
      /// <summary>
      /// 模塊編號(hào)
      /// </summary>
      public int Code { get; set; }
      /// <summary>
      /// 描述
      /// </summary>
      [StringLength(100)]
      public string Description { get; set; }
      /// <summary>
      /// 是否激活
      /// </summary>
      public bool Enabled { get; set; }

      public DateTime UpdateDate { get; set; }

      //public virtual MeunDto ParentModule { get; set; }
      //public List<MeunDto> ChildModules { get; private set; }
      public List<MeunDto> children { get; set; }
  }
}

這里要注意的如果model集成了某個(gè)接口,那么DTO也要繼承這個(gè)接口的DTO梧宫,不然再繼承IAsyncCrudAppService就會(huì)報(bào)錯(cuò)接谨。
比如面的model繼承Entity<int> 那么DTO也要繼承EntityDto<int>.
然后我們看一下IAsyncCrudAppService需要哪么參數(shù)。



這里都可以看得很清楚了塘匣,包括增刪查改的DTO這里我比較懶脓豪,都用了一個(gè)。

接口:

public interface IModulesService : IAsyncCrudAppService<MeunDto, int, PagedResultRequestDto, MeunDto, MeunDto> // IApplicationService
  {

  }

實(shí)現(xiàn)

public class ModulesService : AsyncCrudAppService<Meun, MeunDto, int, PagedResultRequestDto, MeunDto, MeunDto>, IModulesService
  {
      public ModulesService(IRepository<Meun, int> repository) : base(repository)
      {
      }
  }

然后馆铁,我們?cè)赼piJCMSWebApiModule方法下加上.WithConventionalVerbs() 這樣我們就可以看到特定的HTTP前綴跑揉,不然全是post,HTTP動(dòng)詞是通過(guò)方法名的前綴決定的:
Get:方法名以Get開(kāi)頭。
Put:方法名以Put或Update開(kāi)頭历谍。
Delete:方法名以Delete或Remove開(kāi)頭现拒。
Post:方法名以Post或Create開(kāi)頭。
否則望侈,Post是HTTP動(dòng)詞的默認(rèn)值印蔬。

   我們可以通過(guò)對(duì)特定的方法使用WithVerb方法或者HTTP特性來(lái)覆蓋上述慣例。

就這樣脱衙,我們?cè)跇I(yè)務(wù)層中常用的增刪改查的方法就誕生了侥猬。



驗(yàn)證一下,傳入?yún)?shù)捐韩,結(jié)果沒(méi)毛病退唠,可用。當(dāng)然這里根據(jù)自己的需要可以重寫(xiě)這些方法的荤胁。頁(yè)面和前面的頁(yè)面差不多瞧预,沒(méi)啥講的,這里頁(yè)面增刪改查都已經(jīng)實(shí)現(xiàn)仅政。
首先我們看一下userinfo 頁(yè)面垢油,這里我們也根據(jù)abp ajax的封裝和 swagger的應(yīng)用做了一些改變,首先看頁(yè)面圆丹,我們不通過(guò)控制器去獲取創(chuàng)建和修改刪除的方法了滩愁。控制器只有一個(gè)帶分頁(yè)的獲取的方法 這是因?yàn)锽ootstrap table必須要以這樣的json結(jié)構(gòu)返回

using Abp.Application.Services.Dto;
using Abp.Web.Models;
using Abp.Web.Security.AntiForgery;
using JCMS.Authorization.Users;
using JCMS.Sessions.Dto;
using JCMS.Users;
using JCMS.Users.Dto;
using JCMS.Web.Controllers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace JCMS.Web.Areas.Admin.Controllers
{
  public class UserInfoController : JCMSControllerBase
  {

      private readonly IUserAppService _UserAppService;

      public UserInfoController(

         IUserAppService UserAppService)
      {
          _UserAppService = UserAppService;
      }
      public ActionResult Index()
      {
          return View();
      }

      [DisableAbpAntiForgeryTokenValidation]
      [HttpGet]
      [DontWrapResult] 
      public JsonResult GetUsersList()
      {
          string pageNumber = string.IsNullOrWhiteSpace(Request["pageNumber"]) ? "0" : Request["pageNumber"];
          string pageSize = string.IsNullOrWhiteSpace(Request["pageSize"]) ? "20" : Request["pageSize"];
          List<UserDto> Userlist = new List<UserDto>();
          Userlist = _UserAppService.GetAllList();
          int totaldata = Userlist.Count();
          Userlist = Userlist.Skip(int.Parse(pageNumber) * int.Parse(pageSize)).Take(int.Parse(pageSize)).ToList();
          var result = new { total = totaldata, rows = Userlist };
          return Json(result, JsonRequestBehavior.AllowGet);
      }
  }
}

DontWrapResult標(biāo)簽打上的辫封,不需要abp做的特殊封裝硝枉。js頁(yè)面的一些方法。

<script type="text/javascript">

    $(function () {
        //1.初始化Table
        var oTable = new TableInit();
        oTable.Init();

        //2.初始化Button的點(diǎn)擊事件
        var oButtonInit = new ButtonInit();
        oButtonInit.Init();

    });
   var Url = "@Url.Action("GetUsersList")";
   // var Url = "/api/services/app/user/GetAll()";
    var TableInit = function () {
        var oTableInit = new Object();
        //初始化Table
        oTableInit.Init = function () {
            $('#tb_departments').bootstrapTable({
               // url: '../User/GetUsersList',
                url: Url,         //請(qǐng)求后臺(tái)的URL(*)
                method: 'get',                      //請(qǐng)求方式(*)
                toolbar: '#toolbar',                //工具按鈕用哪個(gè)容器
                striped: true,                      //是否顯示行間隔色
                cache: false,                       //是否使用緩存秸讹,默認(rèn)為true檀咙,所以一般情況下需要設(shè)置一下這個(gè)屬性(*)
                pagination: true,                   //是否顯示分頁(yè)(*)
                sortable: false,                     //是否啟用排序
                sortOrder: "asc",                   //排序方式
                queryParams: oTableInit.queryParams,//傳遞參數(shù)(*)
                sidePagination: "server",           //分頁(yè)方式:client客戶端分頁(yè),server服務(wù)端分頁(yè)(*)
                pageNumber: 1,                       //初始化加載第一頁(yè)璃诀,默認(rèn)第一頁(yè)
                pageSize: 2,                       //每頁(yè)的記錄行數(shù)(*)
                pageList: [10, 25, 50, 100],        //可供選擇的每頁(yè)的行數(shù)(*)
                search: true,                       //是否顯示表格搜索,此搜索是客戶端搜索蔑匣,不會(huì)進(jìn)服務(wù)端劣欢,所以,個(gè)人感覺(jué)意義不大
                strictSearch: true,
                showColumns: true,                  //是否顯示所有的列
                showRefresh: true,                  //是否顯示刷新按鈕
                minimumCountColumns: 2,             //最少允許的列數(shù)
                clickToSelect: true,                //是否啟用點(diǎn)擊選中行
                height: 500,                        //行高裁良,如果沒(méi)有設(shè)置height屬性凿将,表格自動(dòng)根據(jù)記錄條數(shù)覺(jué)得表格高度
                uniqueId: "ID",                     //每一行的唯一標(biāo)識(shí),一般為主鍵列
                showToggle: true,                    //是否顯示詳細(xì)視圖和列表視圖的切換按鈕
                cardView: false,                    //是否顯示詳細(xì)視圖
                detailView: false,                   //是否顯示父子表
                columns: [{
                    checkbox: true
                }, {
                    field: 'UserName',
                    title: '姓名'
                }, {
                    field: 'EmailAddress',
                    title: '郵箱'
                }, {
                    field: 'Surname',
                    title: '真是姓名'
                }, {
                     field: 'Name',
                    title: '角色'
                }, ]
            });
        };

        //得到查詢的參數(shù)
        oTableInit.queryParams = function (params) {
            var temp = {   //這里的鍵的名字和控制器的變量名必須一直价脾,這邊改動(dòng)牧抵,控制器也需要改成一樣的
                limit: params.limit,   //頁(yè)面大小
                offset: params.offset,  //頁(yè)碼
                departmentname: $("#txt_search_departmentname").val(),
                statu: $("#txt_search_statu").val()
            };
            return temp;
        };
        return oTableInit;
    };


    var ButtonInit = function () {
        var oInit = new Object();
        var postdata = {};

        oInit.Init = function () {
            //初始化頁(yè)面上面的按鈕事件
            //查詢角色
            $("#btn_query").click(function () {
                var actionUrl = "@Url.Action("GetUsersList")";
                m_pagerow = 0;
                $("#tb_departments").bootstrapTable('refresh', { url: actionUrl });

            });
            //新增角色
            $("#btn_add").click(function () {
                $("#id").val("");
                $("#txt_Surname").val("");
                $("#txt_Name").val("");
                $("#txt_UserName").val("");
                $("#txt_isDeleted").val("");
                $("#myModalLabel").text("新增");
                $('#myModal').modal();
            });
            //新增角色
            $("#btn_submit").click(function () {

                var Id = $("#id").val() == "" ? 0 : $("#id").val();
                var Url = "/api/services/app/user/Update";
                var ajaxtype = "put";
                if ($("#id").val() == "") {
                    Url = "/api/services/app/user/Create";
                    ajaxtype = "post";
                }
                var careteorUpdatePerson = function (person, ajaxtype) {
                    return abp.ajax({
                        url: Url,
                        type: ajaxtype,
                        async: false,
                        data: JSON.stringify(person)
                    });
                };

                var newPerson = {
                     "id": $("#id").val(),
                     "UserName": $("#txt_Surname").val(),
                     "EmailAddress" : $("#txt_Name").val(),
                     "Name": $("#txt_UserName").val(),
                     "Surname": "test",
                     "Password": "123456"
                };

                careteorUpdatePerson(newPerson, ajaxtype).done(function (data) {
                        toastr.warning('操作成功!');
                        var actionUrl = "@Url.Action("GetUsersList")";
                        $("#tb_departments").bootstrapTable('refresh', { url: actionUrl });
                });
            });

            //編輯角色
            $("#btn_edit").click(function () {
                var arrselections = $("#tb_departments").bootstrapTable('getSelections');
                if (arrselections.length > 1) {
                    toastr.warning('只能選擇一行進(jìn)行編輯');
                    return;
                }
                if (arrselections.length <= 0) {
                    toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
                    return;
                }
                $("#id").val(arrselections[0].id);
                $("#txt_Surname").val(arrselections[0].UserName);
                $("#txt_Name").val(arrselections[0].EmailAddress);
                $("#txt_UserName").val(arrselections[0].Name);
                $("#txt_isDeleted").val(arrselections[0].Id);

                $("#myModalLabel").text("修改");
                $('#myModal').modal();       
            });


            //通常我們使用ajax會(huì)按照如下寫(xiě)法,做一個(gè)簡(jiǎn)單的封裝來(lái)重用ajax,此處框架可以幫你生成簡(jiǎn)單的調(diào)用方法
            var deletePerson = function (person) {
                return abp.ajax({
                  //  url: abp.appPath + '/api/services/app/user/Delete',
                    url:'/api/services/app/user/Delete',
                    type: 'delete',
                    async: false,
                    data: JSON.stringify(person)
                });
            };
            //刪除角色
            $("#btn_delete").click(function () {
                var arrselections = $("#tb_departments").bootstrapTable('getSelections');
                if (arrselections.length > 1) {
                    toastr.warning('只能選擇一行進(jìn)行編輯');
                    return;
                }
                if (arrselections.length <= 0) {
                    toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
                    return;
                }
                var Id = arrselections[0].id;
                var newPerson = {
                    "id": Id
                };
              //直接調(diào)用方法犀变,如何生成上面的調(diào)用方法可以參考源碼中的Abp.Web.Api項(xiàng)目中/ WebApi/ Controllers/ Scripting/ jQuery下的實(shí)現(xiàn)
                deletePerson(newPerson).done(function (data) {
                        toastr.warning('操作成功!');
                        var actionUrl = "@Url.Action("GetUsersList")";
                        $("#tb_departments").bootstrapTable('refresh', { url: actionUrl });
                });

            });


            //權(quán)限授權(quán)
            $("#btn_authorize").click(function () {
                var arrselections = $("#tb_departments").bootstrapTable('getSelections');
                if (arrselections.length > 1) {
                    toastr.warning('只能選擇一個(gè)角色進(jìn)行授權(quán)');
                    return;
                }
                if (arrselections.length <= 0) {
                    toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
                    return;
                }
                var actionUrl = "@Url.Action("AuthorizePermission")";
                var param = { id: arrselections[0].Id };
                ShowModal_Authorize(actionUrl, param, "權(quán)限授權(quán)");
            });
            //模態(tài)框中“權(quán)限授權(quán)”保存
            var $modal = $("#authorizeModal");
            $("#btnSave", $modal).click(function () {
                var actionUrl = "@Url.Action("AuthorizePermission")";
                SaveModal_Authorize(actionUrl);
            });
            //模態(tài)框中“新增編輯角色”保存
            var $formmodal = $("#modal-form");
            $("#btnSave", $formmodal).click(function () {
                var $tb = $("#tb_departments");
                SaveModal($tb);
            });

            /*******彈出表單*********/
            function ShowModal(actionUrl, param, title) {
                debugger;
                var $modal = $("#modal-form");
                //表單初始化
                $(".modal-title", $modal).html(title);
                $("#modal-content", $modal).attr("action", actionUrl);

                $.ajax({
                    type: "GET",
                    url: actionUrl,
                    data: param,
                    beforeSend: function () {
                    },
                    success: function (result) {
                        debugger;
                        $("#modal-content").html(result);
                        $('#modal-form').modal('show');
                    },
                    error: function () {

                    },
                    complete: function () {

                    }
                });
            }


        };

        return oInit;
    };



</script>

以careteorUpdatePerson方法為例妹孙,我都是封裝好的。 調(diào)用的時(shí)候直接請(qǐng)求 "/api/services/app/user/Create"地址就可以了获枝,其實(shí)這些代碼都是可以復(fù)用的蠢正,我們也可以封裝到一個(gè)共同的js頁(yè)面。我這里就沒(méi)有做這么詳細(xì)省店。

var careteorUpdatePerson = function (person, ajaxtype) {
                    return abp.ajax({
                        url: Url,
                        type: ajaxtype,
                        async: false,
                        data: JSON.stringify(person)
                    });
                };

                var newPerson = {
                     "id": $("#id").val(),
                     "UserName": $("#txt_Surname").val(),
                     "EmailAddress" : $("#txt_Name").val(),
                     "Name": $("#txt_UserName").val(),
                     "Surname": "test",
                     "Password": "123456"
                };

                careteorUpdatePerson(newPerson, ajaxtype).done(function (data) {
                        toastr.warning('操作成功!');
                        var actionUrl = "@Url.Action("GetUsersList")";
                        $("#tb_departments").bootstrapTable('refresh', { url: actionUrl });
                });
            });

首先我們傳入的參數(shù)newPerson 必須與接口里面的需要的參數(shù)一致嚣崭。而且接口里面自帶驗(yàn)證。數(shù)據(jù)格式也必須一致懦傍。



比如這里郵箱地址我們隨便傳一個(gè)參數(shù)進(jìn)去雹舀,他就會(huì)報(bào)錯(cuò)。頁(yè)面上也是這樣的粗俱。



當(dāng)然這里的提示我們是可以修改的说榆。角色管理頁(yè)面的代碼也是一樣的。
@{
    ViewBag.Title = "Index";
    Layout = "~/Areas/Common/Views/Layout/_Layout.cshtml";
}

<meta name="viewport" content="width=device-width" />
<script type="text/javascript">

    $(function () {



        //1.初始化Table
        var oTable = new TableInit();
        oTable.Init();

        //2.初始化Button的點(diǎn)擊事件
        var oButtonInit = new ButtonInit();
        oButtonInit.Init();

    });
   var Url = "@Url.Action("GetUsersList")";
   // var Url = "/api/services/app/user/GetAll()";
    var TableInit = function () {
        var oTableInit = new Object();
        //初始化Table
        oTableInit.Init = function () {
            $('#tb_departments').bootstrapTable({
               // url: '../User/GetUsersList',
                url: Url,         //請(qǐng)求后臺(tái)的URL(*)
                method: 'get',                      //請(qǐng)求方式(*)
                toolbar: '#toolbar',                //工具按鈕用哪個(gè)容器
                striped: true,                      //是否顯示行間隔色
                cache: false,                       //是否使用緩存源梭,默認(rèn)為true娱俺,所以一般情況下需要設(shè)置一下這個(gè)屬性(*)
                pagination: true,                   //是否顯示分頁(yè)(*)
                sortable: false,                     //是否啟用排序
                sortOrder: "asc",                   //排序方式
                queryParams: oTableInit.queryParams,//傳遞參數(shù)(*)
                sidePagination: "server",           //分頁(yè)方式:client客戶端分頁(yè),server服務(wù)端分頁(yè)(*)
                pageNumber: 1,                       //初始化加載第一頁(yè)废麻,默認(rèn)第一頁(yè)
                pageSize: 2,                       //每頁(yè)的記錄行數(shù)(*)
                pageList: [10, 25, 50, 100],        //可供選擇的每頁(yè)的行數(shù)(*)
                search: true,                       //是否顯示表格搜索荠卷,此搜索是客戶端搜索,不會(huì)進(jìn)服務(wù)端烛愧,所以油宜,個(gè)人感覺(jué)意義不大
                strictSearch: true,
                showColumns: true,                  //是否顯示所有的列
                showRefresh: true,                  //是否顯示刷新按鈕
                minimumCountColumns: 2,             //最少允許的列數(shù)
                clickToSelect: true,                //是否啟用點(diǎn)擊選中行
                height: 500,                        //行高,如果沒(méi)有設(shè)置height屬性怜姿,表格自動(dòng)根據(jù)記錄條數(shù)覺(jué)得表格高度
                uniqueId: "ID",                     //每一行的唯一標(biāo)識(shí)慎冤,一般為主鍵列
                showToggle: true,                    //是否顯示詳細(xì)視圖和列表視圖的切換按鈕
                cardView: false,                    //是否顯示詳細(xì)視圖
                detailView: false,                   //是否顯示父子表
                columns: [{
                    checkbox: true
                }, {
                     field: 'Name',
                    title: '角色名稱'
                }, {
                    field: 'DisplayName',
                    title: '描述'
                }, {
                     field: 'CreationTime',
                    title: '創(chuàng)建時(shí)間'
                }, {
                     field: 'IsStatic',
                    title: '是否啟用'
                }, ]
            });
        };

        //得到查詢的參數(shù)
        oTableInit.queryParams = function (params) {
            var temp = {   //這里的鍵的名字和控制器的變量名必須一直,這邊改動(dòng)沧卢,控制器也需要改成一樣的
                limit: params.limit,   //頁(yè)面大小
                offset: params.offset,  //頁(yè)碼
                departmentname: $("#txt_search_departmentname").val(),
                statu: $("#txt_search_statu").val()
            };
            return temp;
        };
        return oTableInit;
    };


    var ButtonInit = function () {
        var oInit = new Object();
        var postdata = {};

        oInit.Init = function () {
            //初始化頁(yè)面上面的按鈕事件
            //查詢角色
            $("#btn_query").click(function () {
                var actionUrl = "@Url.Action("GetUsersList")";
                m_pagerow = 0;
                $("#tb_departments").bootstrapTable('refresh', { url: actionUrl });

            });
            //新增角色
            $("#btn_add").click(function () {
                $("#id").val("");
                $("#txt_Name").val("");
                $("#txt_DisplayName").val("");
                $("#myModalLabel").text("新增");
                $('#myModal').modal();
            });
            //新增角色
            $("#btn_submit").click(function () {

                var Id = $("#id").val() == "" ? 0 : $("#id").val();
                var Url = "/api/services/app/role/Update";
                var ajaxtype = "put";
                if ($("#id").val() == "") {
                    Url = "/api/services/app/role/Create";
                    ajaxtype = "post";
                }
                debugger;
                var careteorUpdatePerson = function (person, ajaxtype) {
                    return abp.ajax({
                        url: Url,
                        type: ajaxtype,
                        async: false,
                        data: JSON.stringify(person)
                    });
                };

                var newPerson = {
                     "id": $("#id").val(),
                     "Name": $("#txt_Name").val(),
                     "DisplayName": $("#txt_DisplayName").val(),
                     "IsStatic": $("input[type='chekIsStatic']").is(':checked') ? true : false
                };

                careteorUpdatePerson(newPerson, ajaxtype).done(function (data) {
                        toastr.warning('操作成功!');
                        var actionUrl = "@Url.Action("GetUsersList")";
                        $("#tb_departments").bootstrapTable('refresh', { url: actionUrl });
                });
            });

            //編輯角色
            $("#btn_edit").click(function () {
                var arrselections = $("#tb_departments").bootstrapTable('getSelections');
                if (arrselections.length > 1) {
                    toastr.warning('只能選擇一行進(jìn)行編輯');
                    return;
                }
                if (arrselections.length <= 0) {
                    toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
                    return;
                }
                debugger;
                $("#id").val(arrselections[0].id);
                $("#txt_Name").val(arrselections[0].Name);
                $("#txt_DisplayName").val(arrselections[0].DisplayName);
                if (!arrselections[0].IsStatic) {
                    $("#chekIsStatic").attr("checked", false);
                }
                $("#myModalLabel").text("修改");
                $('#myModal').modal();
            });

            var deletePerson = function (person) {
                return abp.ajax({
                    url:'/api/services/app/role/Delete',
                    type: 'delete',
                    async: false,
                    data: JSON.stringify(person)
                });
            };
            //刪除角色
            $("#btn_delete").click(function () {
                var arrselections = $("#tb_departments").bootstrapTable('getSelections');
                if (arrselections.length > 1) {
                    toastr.warning('只能選擇一行進(jìn)行編輯');
                    return;
                }
                if (arrselections.length <= 0) {
                    toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
                    return;
                }
                var Id = arrselections[0].id;
                var newPerson = {
                    "id": Id
                };
                deletePerson(newPerson).done(function (data) {
                        toastr.warning('操作成功!');
                        var actionUrl = "@Url.Action("GetUsersList")";
                        $("#tb_departments").bootstrapTable('refresh', { url: actionUrl });
                });

            });


            //權(quán)限授權(quán)
            $("#btn_authorize").click(function () {
                var arrselections = $("#tb_departments").bootstrapTable('getSelections');
                if (arrselections.length > 1) {
                    toastr.warning('只能選擇一個(gè)角色進(jìn)行授權(quán)');
                    return;
                }
                if (arrselections.length <= 0) {
                    toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
                    return;
                }
                var actionUrl = "@Url.Action("AuthorizePermission")";
                var param = { id: arrselections[0].Id };
                ShowModal_Authorize(actionUrl, param, "權(quán)限授權(quán)");
            });
            //模態(tài)框中“權(quán)限授權(quán)”保存
            var $modal = $("#authorizeModal");
            $("#btnSave", $modal).click(function () {
                var actionUrl = "@Url.Action("AuthorizePermission")";
                SaveModal_Authorize(actionUrl);
            });
            //模態(tài)框中“新增編輯角色”保存
            var $formmodal = $("#modal-form");
            $("#btnSave", $formmodal).click(function () {
                var $tb = $("#tb_departments");
                SaveModal($tb);
            });

            /*******彈出表單*********/
            function ShowModal(actionUrl, param, title) {
                debugger;
                var $modal = $("#modal-form");
                //表單初始化
                $(".modal-title", $modal).html(title);
                $("#modal-content", $modal).attr("action", actionUrl);

                $.ajax({
                    type: "GET",
                    url: actionUrl,
                    data: param,
                    beforeSend: function () {
                    },
                    success: function (result) {
                        debugger;
                        $("#modal-content").html(result);
                        $('#modal-form').modal('show');
                    },
                    error: function () {

                    },
                    complete: function () {

                    }
                });
            }


        };

        return oInit;
    };



</script>



<section class="content-header">
    <h1>
        用戶明細(xì)
        <small>advanced cxdmles</small>
    </h1>
    <ol class="breadcrumb">
        <li><a href="#"><i class="fa fa-dashboard"></i> 主頁(yè)</a></li>
        <li><a href="#">用戶管理</a></li>
        <li class="active">用戶列表</li>
    </ol>

</section>
<section class="content">
    <div class="panel-body" style="padding-bottom:0px;">
        <div class="panel panel-default">
            <div class="panel-heading">查詢條件</div>
            <div class="panel-body">
                <form id="formSearch" class="form-horizontal">
                    <div class="form-group" style="margin-top:15px">
                        <label class="control-label col-sm-1" for="txt_search_departmentname">姓名</label>
                        <div class="col-sm-3">
                            <input type="text" class="form-control" id="txt_search_departmentname">
                        </div>
                        <label class="control-label col-sm-1" for="txt_search_statu">昵稱</label>
                        <div class="col-sm-3">
                            <input type="text" class="form-control" id="txt_search_statu">
                        </div>
                        <div class="col-sm-4" style="text-align:left;">
                            <button type="button" style="margin-left:50px" id="btn_query" class="btn btn-primary">查詢</button>
                        </div>
                    </div>
                </form>
            </div>
        </div>

        <div id="toolbar" class="btn-group">
            <button id="btn_add" type="button" class="btn btn-success">
                <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增
            </button>
            <button id="btn_edit" type="button" class="btn btn-warning">
                <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>修改
            </button>
            <button id="btn_delete" type="button" class="btn btn-danger">
                <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>刪除
            </button>
            <button id="btn_authorize" type="button" class="btn btn-info ">
                <span class="glyphicon glyphicon-lock" aria-hidden="true"></span>授權(quán)
            </button>

        </div>
        <table id="tb_departments"></table>
    </div>


    <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                    <h4 class="modal-title" id="myModalLabel"></h4>
                </div>
                <div class="modal-body">

                    <div class="form-group">
                        <label for="txt_departmentname">角色名稱</label>
                        <input type="text" name="id" class="form-control" id="id" placeholder="id" style="display:none">
                        <input type="text" name="txt_departmentname" class="form-control" id="txt_Name" placeholder="角色名稱">
                    </div>
                    <div class="form-group">
                        <label for="txt_parentdepartment">角色描述</label>
                        <input type="text" name="txt_parentdepartment" class="form-control" id="txt_DisplayName" placeholder="角色描述">
                    </div>
                    @*<div class="form-group">
                        <label for="txt_departmentlevel">創(chuàng)建時(shí)間</label>
                        <input type="text" name="txt_departmentlevel" class="form-control" id="txt_CreationTime" placeholder="創(chuàng)建時(shí)間">
                    </div>*@
                    <div class="form-group">
                        <label for="txt_departmentlevel">是否啟用</label>
                        <div class="checkbox">
                            <label>
                                <input type="checkbox" id="chekIsStatic" checked="checked">
                            </label>
                        </div>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span>關(guān)閉</button>
                    <button type="button" id="btn_submit" class="btn btn-primary" data-dismiss="modal"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>保存</button>
                </div>
            </div>
        </div>
    </div>

</section>

這里有共同的js我們已經(jīng)放到 布局頁(yè)面蚁堤。



現(xiàn)在用戶管理和角色管理功能已經(jīng)實(shí)現(xiàn),后面我會(huì)再做菜單管理但狭,授權(quán)管理披诗,做完基本上就完了,當(dāng)然后面的也是重點(diǎn)立磁。共同努力呈队!
github 地址:https://github.com/Jimmey-Jiang/JCMS

返回簡(jiǎn)書(shū)總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期
前往博客園總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市唱歧,隨后出現(xiàn)的幾起案子宪摧,更是在濱河造成了極大的恐慌粒竖,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件几于,死亡現(xiàn)場(chǎng)離奇詭異蕊苗,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)孩革,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)岁歉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人膝蜈,你說(shuō)我怎么就攤上這事锅移。” “怎么了饱搏?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵非剃,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我推沸,道長(zhǎng)备绽,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任鬓催,我火速辦了婚禮肺素,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宇驾。我一直安慰自己倍靡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布课舍。 她就那樣靜靜地躺著塌西,像睡著了一般。 火紅的嫁衣襯著肌膚如雪筝尾。 梳的紋絲不亂的頭發(fā)上捡需,一...
    開(kāi)封第一講書(shū)人閱讀 49,837評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音筹淫,去河邊找鬼站辉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛损姜,可吹牛的內(nèi)容都是我干的庵寞。 我是一名探鬼主播,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼薛匪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了脓鹃?” 一聲冷哼從身側(cè)響起逸尖,我...
    開(kāi)封第一講書(shū)人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后娇跟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體岩齿,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年苞俘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盹沈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吃谣,死狀恐怖乞封,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情岗憋,我是刑警寧澤肃晚,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站仔戈,受9級(jí)特大地震影響关串,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜监徘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一晋修、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凰盔,春花似錦墓卦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至山叮,卻和暖如春著榴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背屁倔。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工脑又, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人锐借。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓问麸,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親钞翔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子严卖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容