commit
a27d8bf05f
|
@ -108,6 +108,12 @@ namespace Bootstrap.Admin.Controllers
|
|||
/// <returns></returns>
|
||||
public ActionResult Mobile() => View(new NavigatorBarModel(this));
|
||||
|
||||
/// <summary>
|
||||
/// 在线用户
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ActionResult Online() => View(new NavigatorBarModel(this));
|
||||
|
||||
/// <summary>
|
||||
/// 用于测试ExceptionFilter
|
||||
/// </summary>
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Bootstrap.Admin.Controllers.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// 在线用户接口
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class OnlineUsersController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取所有在线用户数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost()]
|
||||
public IEnumerable<OnlineUser> Post([FromServices]IOnlineUsers onlineUSers)
|
||||
{
|
||||
return onlineUSers.OnlineUsers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定IP地址的在线用户请求地址明细数据
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="onlineUSers"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{id}")]
|
||||
public IEnumerable<KeyValuePair<DateTime, string>> Get(string id, [FromServices]IOnlineUsers onlineUSers)
|
||||
{
|
||||
var user = onlineUSers.OnlineUsers.FirstOrDefault(u => u.Ip == id);
|
||||
return user?.RequestUrls ?? new KeyValuePair<DateTime, string>[0];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bootstrap.Admin
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal class DefaultOnlineUsers : IOnlineUsers
|
||||
{
|
||||
private ConcurrentDictionary<string, OnlineUser> _onlineUsers = new ConcurrentDictionary<string, OnlineUser>();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<OnlineUser> OnlineUsers
|
||||
{
|
||||
get { return _onlineUsers.Values; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="addValueFactory"></param>
|
||||
/// <param name="updateValueFactory"></param>
|
||||
/// <returns></returns>
|
||||
public OnlineUser AddOrUpdate(string key, Func<string, OnlineUser> addValueFactory, Func<string, OnlineUser, OnlineUser> updateValueFactory) => _onlineUsers.AddOrUpdate(key, addValueFactory, updateValueFactory);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bootstrap.Admin
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public interface IOnlineUsers
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
IEnumerable<OnlineUser> OnlineUsers { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="addValueFactory"></param>
|
||||
/// <param name="updateValueFactory"></param>
|
||||
/// <returns></returns>
|
||||
OnlineUser AddOrUpdate(string key, Func<string, OnlineUser> addValueFactory, Func<string, OnlineUser, OnlineUser> updateValueFactory);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bootstrap.Admin
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class OnlineUser
|
||||
{
|
||||
private ConcurrentQueue<KeyValuePair<DateTime, string>> _requestUrls;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="ip"></param>
|
||||
/// <param name="userName"></param>
|
||||
public OnlineUser(string ip, string userName)
|
||||
{
|
||||
Ip = ip;
|
||||
UserName = userName;
|
||||
FirstAccessTime = DateTime.Now;
|
||||
LastAccessTime = DateTime.Now;
|
||||
_requestUrls = new ConcurrentQueue<KeyValuePair<DateTime, string>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string UserName { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public DateTime FirstAccessTime { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public DateTime LastAccessTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Method { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Ip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string RequestUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IEnumerable<KeyValuePair<DateTime, string>> RequestUrls
|
||||
{
|
||||
get
|
||||
{
|
||||
return _requestUrls.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
public void AddRequestUrl(string url)
|
||||
{
|
||||
_requestUrls.Enqueue(new KeyValuePair<DateTime, string>(DateTime.Now, url));
|
||||
if (_requestUrls.Count > 5)
|
||||
{
|
||||
_requestUrls.TryDequeue(out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using Bootstrap.Admin;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class OnlineUsersMiddlewareExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseOnlineUsers(this IApplicationBuilder builder) => builder.UseWhen(context => context.Filter(), app => app.Use(async (context, next) =>
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var onlineUsers = context.RequestServices.GetService<IOnlineUsers>();
|
||||
var clientIp = context.Connection.RemoteIpAddress.ToString();
|
||||
onlineUsers.AddOrUpdate(clientIp, key =>
|
||||
{
|
||||
var ou = new OnlineUser(key, context.User.Identity.Name);
|
||||
ou.Method = context.Request.Method;
|
||||
ou.RequestUrl = context.Request.Path;
|
||||
ou.AddRequestUrl(context.Request.Path);
|
||||
return ou;
|
||||
}, (key, v) =>
|
||||
{
|
||||
v.LastAccessTime = DateTime.Now;
|
||||
v.Method = context.Request.Method;
|
||||
v.RequestUrl = context.Request.Path;
|
||||
v.AddRequestUrl(context.Request.Path);
|
||||
return v;
|
||||
});
|
||||
});
|
||||
await next();
|
||||
}));
|
||||
|
||||
private static bool Filter(this HttpContext context)
|
||||
{
|
||||
var url = context.Request.Path;
|
||||
return !new string[] { "/api", "/NotiHub", "/swagger" }.Any(r => url.StartsWithSegments(r, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using Bootstrap.Admin;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class OnlineUsersServicesCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddOnlineUsers(this IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<IOnlineUsers, DefaultOnlineUsers>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,6 +60,7 @@ namespace Bootstrap.Admin
|
|||
services.AddConfigurationManager(Configuration);
|
||||
services.AddCacheManager(Configuration);
|
||||
services.AddDbAdapter();
|
||||
services.AddOnlineUsers();
|
||||
var dataProtectionBuilder = services.AddDataProtection(op => op.ApplicationDiscriminator = Configuration["ApplicationDiscriminator"])
|
||||
.SetApplicationName(Configuration["ApplicationName"])
|
||||
.PersistKeysToFileSystem(new DirectoryInfo(Configuration["KeyPath"]));
|
||||
|
@ -125,6 +126,7 @@ namespace Bootstrap.Admin
|
|||
app.UseStaticFiles();
|
||||
app.UseAuthentication();
|
||||
app.UseBootstrapAdminAuthorization(RoleHelper.RetrieveRolesByUserName, RoleHelper.RetrieveRolesByUrl, AppHelper.RetrievesByUserName);
|
||||
app.UseOnlineUsers();
|
||||
app.UseCacheManagerCorsHandler();
|
||||
app.UseSignalR(routes => { routes.MapHub<SignalRHub>("/NotiHub"); });
|
||||
app.UseMvc(routes =>
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
@model NavigatorBarModel
|
||||
@{
|
||||
ViewBag.Title = "在线用户";
|
||||
}
|
||||
@section css {
|
||||
<environment include="Development">
|
||||
<link href="~/lib/bootstrap-table/bootstrap-table.css" rel="stylesheet" />
|
||||
</environment>
|
||||
<environment exclude="Development">
|
||||
<link href="~/lib/bootstrap-table/bootstrap-table.min.css" rel="stylesheet" />
|
||||
</environment>
|
||||
}
|
||||
@section javascript {
|
||||
<environment include="Development">
|
||||
<script src="~/lib/bootstrap-table/bootstrap-table.js"></script>
|
||||
<script src="~/lib/bootstrap-table/locale/bootstrap-table-zh-CN.js"></script>
|
||||
</environment>
|
||||
<environment exclude="Development">
|
||||
<script src="~/lib/bootstrap-table/bootstrap-table.min.js"></script>
|
||||
<script src="~/lib/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
|
||||
</environment>
|
||||
<script src="~/js/online.js" asp-append-version="true"></script>
|
||||
}
|
||||
<div class="card">
|
||||
<div class="card-header">在线用户<span class="pull-right"><a id="refreshUsers" href="javascript:;" class="fa fa-refresh" title="点击刷新" data-toggle="tooltip" data-placement="left"></a></span></div>
|
||||
<div class="card-body" style="padding-top: 25px;">
|
||||
<table></table>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,52 @@
|
|||
$(function () {
|
||||
var apiUrl = "api/OnlineUsers";
|
||||
var $table = $('table').smartTable({
|
||||
url: apiUrl,
|
||||
method: "post",
|
||||
sidePagination: "client",
|
||||
showToggle: false,
|
||||
showRefresh: false,
|
||||
showColumns: false,
|
||||
columns: [
|
||||
{
|
||||
title: "序号", formatter: function (value, row, index) {
|
||||
var options = $table.bootstrapTable('getOptions');
|
||||
return options.pageSize * (options.pageNumber - 1) + index + 1;
|
||||
}
|
||||
},
|
||||
{ title: "登陆名称", field: "UserName" },
|
||||
{ title: "显示名称", field: "DisplayName" },
|
||||
{ title: "登录时间", field: "FirstAccessTime" },
|
||||
{ title: "最近操作时间", field: "LastAccessTime" },
|
||||
{ title: "请求方式", field: "Method" },
|
||||
{ title: "IP地址", field: "Ip" },
|
||||
{ title: "访问地址", field: "RequestUrl" },
|
||||
{
|
||||
title: "历史地址", field: "Ip", formatter: function (value, row, index, field) {
|
||||
return $.format('<button type="button" class="btn btn-info" data-id="{0}" data-toggle="popover" data-trigger="focus" data-html="true" data-title="访问记录">明细</button >', value);
|
||||
}
|
||||
}
|
||||
]
|
||||
}).on('click', 'button[data-id]', function () {
|
||||
var $this = $(this);
|
||||
if (!$this.data($.fn.popover.Constructor.DATA_KEY)) {
|
||||
var id = $this.attr('data-id');
|
||||
$.bc({
|
||||
id: id, url: apiUrl,
|
||||
callback: function (result) {
|
||||
if (!result) return;
|
||||
var content = result.map(function (item) {
|
||||
return $.format("<tr><td>{0}</td><td>{1}</td></tr>", item.Key, item.Value);
|
||||
}).join('');
|
||||
content = $.format('<div class="fixed-table-container"><table class="table table-hover table-sm mb-0"><thead><tr><th class="p-1"><b>访问时间</b></th><th class="p-1">访问地址</th></tr></thead><tbody>{0}</tbody></table></div>', content);
|
||||
$this.lgbPopover({ content: content, placement: $(window).width() < 768 ? 'top' : 'left' });
|
||||
$this.popover('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#refreshUsers').tooltip().on('click', function () {
|
||||
$table.bootstrapTable('refresh');
|
||||
});
|
||||
});
|
|
@ -46,7 +46,8 @@ INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [C
|
|||
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (11, 0, N'任务管理', 110, N'fa fa fa-tasks', N'~/Admin/Tasks', N'0')
|
||||
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (12, 0, N'通知管理', 120, N'fa fa-bell', N'~/Admin/Notifications', N'0')
|
||||
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (13, 0, N'系统日志', 130, N'fa fa-gears', N'~/Admin/Logs', N'0')
|
||||
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, N'程序异常', 140, N'fa fa-cubes', N'~/Admin/Exceptions', N'0')
|
||||
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, N'在线用户', 140, N'fa fa-users', N'~/Admin/Online', N'0')
|
||||
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (15, 0, N'程序异常', 150, N'fa fa-cubes', N'~/Admin/Exceptions', N'0')
|
||||
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (16, 0, N'工具集合', 160, N'fa fa-gavel', N'#', N'0')
|
||||
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (17, 16, N'客户端测试', 10, N'fa fa-wrench', N'~/Admin/Mobile', N'0')
|
||||
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (18, 16, N'API文档', 10, N'fa fa-wrench', N'~/swagger', N'0')
|
||||
|
|
|
@ -155,11 +155,23 @@
|
|||
"IsResource": NumberInt(0),
|
||||
"Application": "0"
|
||||
},
|
||||
{
|
||||
"_id": ObjectId("5bd7b8445fa31256f77e4b89"),
|
||||
"ParentId": "0",
|
||||
"Name": "在线用户",
|
||||
"Order": NumberInt(140),
|
||||
"Icon": "fa fa-users",
|
||||
"Url": "~/Admin/Online",
|
||||
"Category": "0",
|
||||
"Target": "_self",
|
||||
"IsResource": NumberInt(0),
|
||||
"Application": "0"
|
||||
},
|
||||
{
|
||||
"_id": ObjectId("5bd7b8445fa31256f77e4b9d"),
|
||||
"ParentId": "0",
|
||||
"Name": "程序异常",
|
||||
"Order": NumberInt(140),
|
||||
"Order": NumberInt(150),
|
||||
"Icon": "fa fa-cubes",
|
||||
"Url": "~/Admin/Exceptions",
|
||||
"Category": "0",
|
||||
|
|
|
@ -43,7 +43,8 @@ INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUE
|
|||
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (11, 0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0');
|
||||
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (12, 0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0');
|
||||
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (13, 0, '系统日志', 130, 'fa fa-gears', '~/Admin/Logs', '0');
|
||||
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (14, 0, '程序异常', 140, 'fa fa-cubes', '~/Admin/Exceptions', '0');
|
||||
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (14, 0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
|
||||
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (15, 0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');
|
||||
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (16, 0, '工具集合', 160, 'fa fa-gavel', '#', '0');
|
||||
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (17, 16, '客户端测试', 10, 'fa fa-wrench', '~/Admin/Mobile', '0');
|
||||
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (18, 16, 'API文档', 10, 'fa fa-wrench', '~/swagger', '0');
|
||||
|
|
|
@ -43,7 +43,8 @@ INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0
|
|||
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0');
|
||||
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0');
|
||||
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '系统日志', 130, 'fa fa-gears', '~/Admin/Logs', '0');
|
||||
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '程序异常', 140, 'fa fa-cubes', '~/Admin/Exceptions', '0');
|
||||
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
|
||||
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');
|
||||
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '工具集合', 160, 'fa fa-gavel', '#', '0');
|
||||
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (currval('navigations_id_seq') - 1, '客户端测试', 10, 'fa fa-wrench', '~/Admin/Mobile', '0');
|
||||
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (currval('navigations_id_seq') - 2, 'API文档', 10, 'fa fa-wrench', '~/swagger', '0');
|
||||
|
|
|
@ -40,7 +40,8 @@ INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Ca
|
|||
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (11, 0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0');
|
||||
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (12, 0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0');
|
||||
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (13, 0, '系统日志', 130, 'fa fa-gears', '~/Admin/Logs', '0');
|
||||
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, '程序异常', 140, 'fa fa-cubes', '~/Admin/Exceptions', '0');
|
||||
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
|
||||
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (15, 0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');
|
||||
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (16, 0, '工具集合', 160, 'fa fa-gavel', '#', '0');
|
||||
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (17, 16, '客户端测试', 10, 'fa fa-wrench', '~/Admin/Mobile', '0');
|
||||
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (18, 16, 'API文档', 10, 'fa fa-wrench', '~/swagger', '0');
|
||||
|
|
Loading…
Reference in New Issue