初步可用后台
This commit is contained in:
parent
104cfb2463
commit
c448afdd1d
@ -1,18 +0,0 @@
|
|||||||
using JXCMS.CMS.Attribute;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace JXCMS.CMS.Admin.Controllers
|
|
||||||
{
|
|
||||||
[Area("Admin")]
|
|
||||||
[AdminAuthentication]
|
|
||||||
public class ArticleController : Controller
|
|
||||||
{
|
|
||||||
// GET
|
|
||||||
public IActionResult Index()
|
|
||||||
{
|
|
||||||
ViewBag.title = "所有文章";
|
|
||||||
|
|
||||||
return View();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
73
CMS/JXCMS.CMS.Movie/Admin/Controllers/ClassifyController.cs
Normal file
73
CMS/JXCMS.CMS.Movie/Admin/Controllers/ClassifyController.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using FreeSql;
|
||||||
|
using JXCMS.CMS.Attribute;
|
||||||
|
using JXCMS.CMS.Entity;
|
||||||
|
using JXCMS.CMS.Movie.Entity;
|
||||||
|
using JXCMS.CMS.Movie.Spider;
|
||||||
|
using JXCMS.CMS.Movie.Utils;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Admin.Controllers
|
||||||
|
{
|
||||||
|
[Area("Admin")]
|
||||||
|
[AdminAuthentication]
|
||||||
|
public class ClassifyController : Controller
|
||||||
|
{
|
||||||
|
public IActionResult Index(int pageNumber = 1, int pageSize = 20)
|
||||||
|
{
|
||||||
|
var list = ClassifyEntity.Select.Include(x => x.Parent).Count(out long count).Page(pageNumber, pageSize).ToList(
|
||||||
|
x => new ClassifyEntity{Id = x.Id, Name = x.Name, Alias = x.Alias, ParentId = x.ParentId, Parent = x.Parent, UpdateTime = x.UpdateTime,
|
||||||
|
Count = MovieEntity.Select.Where(y => y.ClassifyId == x.Id).Count()});
|
||||||
|
ViewBag.count = count;
|
||||||
|
ViewBag.pageNumber = pageNumber;
|
||||||
|
ViewBag.totlePage = count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
|
||||||
|
return View(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult ClassifyDialog(int id)
|
||||||
|
{
|
||||||
|
|
||||||
|
ClassifyEntity classifyEntity = null;
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
classifyEntity = new ClassifyEntity();
|
||||||
|
ViewBag.title = "添加新分类";
|
||||||
|
ViewBag.classifyEntities = ClassifyEntity.Select.ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
classifyEntity = ClassifyEntity.Find(id);
|
||||||
|
ViewBag.title = "修改分类" + classifyEntity.Name;
|
||||||
|
ViewBag.classifyEntities = Classify.FindAllNotChildren(ClassifyEntity.Select.ToList(), id);
|
||||||
|
}
|
||||||
|
return View(classifyEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult DeleteClassify(int id)
|
||||||
|
{
|
||||||
|
if (MovieEntity.Select.Any(x => x.ClassifyId == id))
|
||||||
|
{
|
||||||
|
return Redirect(Url.Action("Index"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ClassifyEntity.Select.Any(x => x.ParentId == id))
|
||||||
|
{
|
||||||
|
ClassifyEntity.Where(x => x.ParentId == id).ToUpdate().Set(x => x.ParentId, 0).ExecuteAffrows();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassifyEntity.Find(id).Delete();
|
||||||
|
return Redirect(Url.Action("Index"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult ModifyClassify(ClassifyEntity classifyEntity)
|
||||||
|
{
|
||||||
|
if (classifyEntity.Id != 0 &&
|
||||||
|
Classify.FindAllChildren(ClassifyEntity.Select.ToList(), classifyEntity.Id).Any(x => x.Id == classifyEntity.ParentId))
|
||||||
|
{
|
||||||
|
return Redirect(Url.Action("Index"));
|
||||||
|
}
|
||||||
|
classifyEntity.Save();
|
||||||
|
return Redirect(Url.Action("Index"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,12 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using FreeSql;
|
||||||
using JXCMS.CMS.Attribute;
|
using JXCMS.CMS.Attribute;
|
||||||
using JXCMS.CMS.Movie.Entity;
|
using JXCMS.CMS.Movie.Entity;
|
||||||
using JXCMS.CMS.Movie.Jobs;
|
using JXCMS.CMS.Movie.Jobs;
|
||||||
|
using JXCMS.CMS.Movie.Spider;
|
||||||
|
using JXCMS.CMS.Movie.Utils;
|
||||||
using JXCMS.Core.TimingTask;
|
using JXCMS.Core.TimingTask;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Quartz;
|
using Quartz;
|
||||||
@ -16,7 +20,11 @@ namespace JXCMS.CMS.Movie.Admin.Controllers
|
|||||||
public IActionResult Index(int pageNumber = 1, int pageSize = 20)
|
public IActionResult Index(int pageNumber = 1, int pageSize = 20)
|
||||||
{
|
{
|
||||||
ViewBag.title = "采集地址";
|
ViewBag.title = "采集地址";
|
||||||
var website = WebSiteEntity.Select.Count(out long count).Page(pageNumber, pageSize).ToList();
|
var website = WebSiteEntity.Select.Count(out long count).Page(pageNumber, pageSize).ToList().Select(x =>
|
||||||
|
{
|
||||||
|
x.NextRunTime = x.IsEnable ? QuartzTask.GetCronSchedule(x.Cron, 1, DateTimeOffset.Now) : "已禁用";
|
||||||
|
return x;
|
||||||
|
}).ToList();
|
||||||
ViewBag.website = website;
|
ViewBag.website = website;
|
||||||
ViewBag.count = count;
|
ViewBag.count = count;
|
||||||
ViewBag.pageNumber = pageNumber;
|
ViewBag.pageNumber = pageNumber;
|
||||||
@ -27,6 +35,10 @@ namespace JXCMS.CMS.Movie.Admin.Controllers
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public IActionResult AddWebSite(WebSiteEntity webSiteEntity)
|
public IActionResult AddWebSite(WebSiteEntity webSiteEntity)
|
||||||
{
|
{
|
||||||
|
if (!CronExpression.IsValidExpression(webSiteEntity.Cron))
|
||||||
|
{
|
||||||
|
return Redirect(Url.Action("Index"));
|
||||||
|
}
|
||||||
webSiteEntity.Save();
|
webSiteEntity.Save();
|
||||||
if (webSiteEntity.IsEnable)
|
if (webSiteEntity.IsEnable)
|
||||||
{
|
{
|
||||||
@ -88,6 +100,25 @@ namespace JXCMS.CMS.Movie.Admin.Controllers
|
|||||||
return View(webSiteEntity);
|
return View(webSiteEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IActionResult BindingClassifyDialog(int id)
|
||||||
|
{
|
||||||
|
var classifyEntities = Classify.Structured(ClassifyEntity.Select.ToList());
|
||||||
|
var webSiteClassifyEntities = WebSiteClassifyEntity.Where(x => x.WebSiteId == id).ToList();
|
||||||
|
var webSiteEntity = WebSiteEntity.Find(id);
|
||||||
|
classifyEntities.Insert(0, new ClassifyEntity(){Id = 0, Name = "未绑定"});
|
||||||
|
ViewBag.classifyEntities = classifyEntities;
|
||||||
|
ClassifySpider.GetAllClassifyFromUrl(id, webSiteEntity.ApiUrl, webSiteClassifyEntities);
|
||||||
|
ViewBag.title = "修改" + webSiteEntity.WebSiteName + "的类型绑定";
|
||||||
|
return View(webSiteClassifyEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult UpdateBindingClassify(WebSiteClassifyEntity[] webSiteClassifyEntities)
|
||||||
|
{
|
||||||
|
foreach (var webSiteClassifyEntity in webSiteClassifyEntities)
|
||||||
|
{
|
||||||
|
webSiteClassifyEntity.Save();
|
||||||
|
}
|
||||||
|
return Redirect(Url.Action("Index"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,17 +1,15 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JXCMS.CMS.Attribute;
|
using JXCMS.CMS.Attribute;
|
||||||
using JXCMS.CMS.Entity;
|
|
||||||
using JXCMS.CMS.Movie.Entity;
|
using JXCMS.CMS.Movie.Entity;
|
||||||
using JXCMS.CMS.Utils;
|
using JXCMS.CMS.Utils;
|
||||||
using JXCMS.Core.Auth;
|
using JXCMS.Core.Auth;
|
||||||
using JXCMS.Core.Encrypt;
|
using JXCMS.Core.Encrypt;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace JXCMS.CMS.Admin.Controllers
|
namespace JXCMS.CMS.Movie.Admin.Controllers
|
||||||
{
|
{
|
||||||
[Area("Admin")]
|
[Area("Admin")]
|
||||||
[AdminAuthentication]
|
[AdminAuthentication]
|
||||||
|
@ -73,6 +73,180 @@ namespace JXCMS.CMS.Admin.Controllers
|
|||||||
Type = "Settings"
|
Type = "Settings"
|
||||||
});
|
});
|
||||||
BaseEntity.Orm.Insert(settings).ExecuteInserted();
|
BaseEntity.Orm.Insert(settings).ExecuteInserted();
|
||||||
|
var classify = new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "电影",
|
||||||
|
Alias = "dianying",
|
||||||
|
ParentId = 0
|
||||||
|
};
|
||||||
|
classify.Save();
|
||||||
|
List<ClassifyEntity> classifyEntities = new List<ClassifyEntity>();
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "动作片",
|
||||||
|
Alias = "dongzuo",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "喜剧片",
|
||||||
|
Alias = "xiju",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "爱情片",
|
||||||
|
Alias = "aiqing",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "科幻片",
|
||||||
|
Alias = "kehuan",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "恐怖片",
|
||||||
|
Alias = "kongbu",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "剧情片",
|
||||||
|
Alias = "juqing",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "战争片",
|
||||||
|
Alias = "zhanzheng",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "纪录片",
|
||||||
|
Alias = "jilupian",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "微电影",
|
||||||
|
Alias = "weidianying",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "伦理片",
|
||||||
|
Alias = "lunli",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
BaseEntity.Orm.Insert(classifyEntities).ExecuteAffrows();
|
||||||
|
classify = new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "电视剧",
|
||||||
|
Alias = "tv",
|
||||||
|
ParentId = 0
|
||||||
|
};
|
||||||
|
classify.Save();
|
||||||
|
classifyEntities.Clear();
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "国产剧",
|
||||||
|
Alias = "guochanju",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "香港剧",
|
||||||
|
Alias = "xianggangju",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "韩国剧",
|
||||||
|
Alias = "hanguoju",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "欧美剧",
|
||||||
|
Alias = "oumeiju",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "台湾剧",
|
||||||
|
Alias = "taiwanju",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "日本剧",
|
||||||
|
Alias = "ribenju",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "海外剧",
|
||||||
|
Alias = "haiwaiju",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
BaseEntity.Orm.Insert(classifyEntities).ExecuteAffrows();
|
||||||
|
classify = new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "综艺片",
|
||||||
|
Alias = "zongyi",
|
||||||
|
ParentId = 0
|
||||||
|
};
|
||||||
|
classify.Save();
|
||||||
|
classifyEntities.Clear();
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "内地综艺",
|
||||||
|
Alias = "neidizongyi",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "日韩综艺",
|
||||||
|
Alias = "rihanzongyi",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "欧美综艺",
|
||||||
|
Alias = "oumeizongyi",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
BaseEntity.Orm.Insert(classifyEntities).ExecuteAffrows();
|
||||||
|
classify = new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "动漫片",
|
||||||
|
Alias = "dongman",
|
||||||
|
ParentId = 0
|
||||||
|
};
|
||||||
|
classify.Save();
|
||||||
|
classifyEntities.Clear();
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "国产动漫",
|
||||||
|
Alias = "guochandongman",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "日韩动漫",
|
||||||
|
Alias = "rihandongman",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
classifyEntities.Add(new ClassifyEntity()
|
||||||
|
{
|
||||||
|
Name = "欧美动漫",
|
||||||
|
Alias = "oumeidongman",
|
||||||
|
ParentId = classify.Id
|
||||||
|
});
|
||||||
|
BaseEntity.Orm.Insert(classifyEntities).ExecuteAffrows();
|
||||||
System.IO.File.Create("install.lock");
|
System.IO.File.Create("install.lock");
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
21
CMS/JXCMS.CMS.Movie/Admin/Controllers/MovieController.cs
Normal file
21
CMS/JXCMS.CMS.Movie/Admin/Controllers/MovieController.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using JXCMS.CMS.Attribute;
|
||||||
|
using JXCMS.CMS.Movie.Entity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Admin.Controllers
|
||||||
|
{
|
||||||
|
[Area("Admin")]
|
||||||
|
[AdminAuthentication]
|
||||||
|
public class MovieController : Controller
|
||||||
|
{
|
||||||
|
public IActionResult Index(int pageNumber = 1, int pageSize = 20)
|
||||||
|
{
|
||||||
|
var model = MovieEntity.Select.Count(out long count).Page(pageNumber, pageSize)
|
||||||
|
.Include(x => x.DirectorEntity).Include(x => x.ClassifyEntity).ToList();
|
||||||
|
ViewBag.count = count;
|
||||||
|
ViewBag.pageNumber = pageNumber;
|
||||||
|
ViewBag.totlePage = count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,265 +0,0 @@
|
|||||||
<div class="container-fluid p-t-15">
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-toolbar clearfix">
|
|
||||||
<form class="pull-right search-bar" method="get" action="#!" role="form">
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-btn">
|
|
||||||
<input type="hidden" name="search_field" id="search-field" value="title">
|
|
||||||
<button class="btn btn-default dropdown-toggle" id="search-btn" data-toggle="dropdown" type="button" aria-haspopup="true" aria-expanded="false">
|
|
||||||
标题 <span class="caret"></span>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li> <a tabindex="-1" href="javascript:void(0)" data-field="title">标题</a> </li>
|
|
||||||
<li> <a tabindex="-1" href="javascript:void(0)" data-field="cat_name">栏目</a> </li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<input type="text" class="form-control" value="" name="keyword" placeholder="请输入名称">
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div class="toolbar-btn-action">
|
|
||||||
<a class="btn btn-primary m-r-5" href="#!"><i class="mdi mdi-plus"></i> 新增</a>
|
|
||||||
<a class="btn btn-success m-r-5" href="#!"><i class="mdi mdi-check"></i> 启用</a>
|
|
||||||
<a class="btn btn-warning m-r-5" href="#!"><i class="mdi mdi-block-helper"></i> 禁用</a>
|
|
||||||
<a class="btn btn-danger" href="#!"><i class="mdi mdi-window-close"></i> 删除</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
<label class="lyear-checkbox checkbox-primary">
|
|
||||||
<input type="checkbox" id="check-all"><span></span>
|
|
||||||
</label>
|
|
||||||
</th>
|
|
||||||
<th>编号</th>
|
|
||||||
<th>标题</th>
|
|
||||||
<th>书籍</th>
|
|
||||||
<th>作者</th>
|
|
||||||
<th>阅读量</th>
|
|
||||||
<th>状态</th>
|
|
||||||
<th>操作</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label class="lyear-checkbox checkbox-primary">
|
|
||||||
<input type="checkbox" name="ids[]" value="1"><span></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>1</td>
|
|
||||||
<td>第01章 天涯思君不可忘</td>
|
|
||||||
<td>《倚天屠龙记》</td>
|
|
||||||
<td>金庸</td>
|
|
||||||
<td>36</td>
|
|
||||||
<td><font class="text-success">正常</font></td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label class="lyear-checkbox checkbox-primary">
|
|
||||||
<input type="checkbox" name="ids[]" value="2"><span></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>2</td>
|
|
||||||
<td>第01章 古道腾驹惊白发,危峦快剑识青翎</td>
|
|
||||||
<td>《书剑恩仇录》</td>
|
|
||||||
<td>金庸</td>
|
|
||||||
<td>44</td>
|
|
||||||
<td><font class="text-success">正常</font></td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label class="lyear-checkbox checkbox-primary">
|
|
||||||
<input type="checkbox" name="ids[]" value="3"><span></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>3</td>
|
|
||||||
<td>一个戴水獭皮帽子的朋友</td>
|
|
||||||
<td>《湘行散记》</td>
|
|
||||||
<td>沈从文</td>
|
|
||||||
<td>39</td>
|
|
||||||
<td><font class="text-success">正常</font></td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label class="lyear-checkbox checkbox-primary">
|
|
||||||
<input type="checkbox" name="ids[]" value="4"><span></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>4</td>
|
|
||||||
<td>你是要灼灼容颜,还是要宜其室家</td>
|
|
||||||
<td>《诗三百:思无邪》</td>
|
|
||||||
<td>安意如</td>
|
|
||||||
<td>36</td>
|
|
||||||
<td><font class="text-success">正常</font></td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label class="lyear-checkbox checkbox-primary">
|
|
||||||
<input type="checkbox" name="ids[]" value="5"><span></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>5</td>
|
|
||||||
<td>海上的消息</td>
|
|
||||||
<td>《打开心内的窗》</td>
|
|
||||||
<td>林清玄</td>
|
|
||||||
<td>32</td>
|
|
||||||
<td><font class="text-success">正常</font></td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label class="lyear-checkbox checkbox-primary">
|
|
||||||
<input type="checkbox" name="ids[]" value="6"><span></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>6</td>
|
|
||||||
<td>楔子 一阕词来 南国清秋魂梦绕 十年人散 绣房红烛剑光寒</td>
|
|
||||||
<td>《七剑下天山》</td>
|
|
||||||
<td>梁羽生</td>
|
|
||||||
<td>42</td>
|
|
||||||
<td><font class="text-success">正常</font></td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label class="lyear-checkbox checkbox-primary">
|
|
||||||
<input type="checkbox" name="ids[]" value="7"><span></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>7</td>
|
|
||||||
<td>祝福</td>
|
|
||||||
<td>《彷徨》</td>
|
|
||||||
<td>鲁迅</td>
|
|
||||||
<td>40</td>
|
|
||||||
<td><font class="text-success">正常</font></td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label class="lyear-checkbox checkbox-primary">
|
|
||||||
<input type="checkbox" name="ids[]" value="8"><span></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>8</td>
|
|
||||||
<td>一个女长年的故事</td>
|
|
||||||
<td>《莫泊桑短篇小说集》</td>
|
|
||||||
<td>莫泊桑</td>
|
|
||||||
<td>36</td>
|
|
||||||
<td><font class="text-success">正常</font></td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label class="lyear-checkbox checkbox-primary">
|
|
||||||
<input type="checkbox" name="ids[]" value="9"><span></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>9</td>
|
|
||||||
<td>第一回 赈民饥包公奉旨 图谋害庞相施计</td>
|
|
||||||
<td>《五虎征西》</td>
|
|
||||||
<td>李雨堂</td>
|
|
||||||
<td>35</td>
|
|
||||||
<td><font class="text-success">正常</font></td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label class="lyear-checkbox checkbox-primary">
|
|
||||||
<input type="checkbox" name="ids[]" value="10"><span></span>
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>10</td>
|
|
||||||
<td>第一回 于按察山东赴任 邹其仁赴路登程</td>
|
|
||||||
<td>《于公案》</td>
|
|
||||||
<td>佚名</td>
|
|
||||||
<td>37</td>
|
|
||||||
<td><font class="text-success">正常</font></td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
|
|
||||||
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<ul class="pagination">
|
|
||||||
<li class="disabled"><span>«</span></li>
|
|
||||||
<li class="active"><span>1</span></li>
|
|
||||||
<li><a href="#1">2</a></li>
|
|
||||||
<li><a href="#1">3</a></li>
|
|
||||||
<li><a href="#1">4</a></li>
|
|
||||||
<li><a href="#1">5</a></li>
|
|
||||||
<li><a href="#1">6</a></li>
|
|
||||||
<li><a href="#1">7</a></li>
|
|
||||||
<li><a href="#1">8</a></li>
|
|
||||||
<li class="disabled"><span>...</span></li>
|
|
||||||
<li><a href="#!">14452</a></li>
|
|
||||||
<li><a href="#!">14453</a></li>
|
|
||||||
<li><a href="#!">»</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
@ -0,0 +1,42 @@
|
|||||||
|
@using JXCMS.CMS.Movie.Entity
|
||||||
|
@model JXCMS.CMS.Movie.Entity.ClassifyEntity
|
||||||
|
|
||||||
|
@{
|
||||||
|
Layout = "_DialogLayout";
|
||||||
|
}
|
||||||
|
|
||||||
|
<form id="modify_classify" action="@Url.Action("ModifyClassify")" method="post">
|
||||||
|
<input type="hidden" id="id" name="id" value="@Model.Id"/>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name" class="control-label">分类名称:</label>
|
||||||
|
<input type="text" class="form-control" id="name" name="name" value="@Model.Name">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="alias" class="control-label">别名:</label>
|
||||||
|
<input type="text" class="form-control" id="alias" name="alias" value="@Model.Alias">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="parentId" class="control-label">父级分类:</label>
|
||||||
|
<select class="form-control" id="parentId" name="parentId">
|
||||||
|
<option value="0">无</option>
|
||||||
|
@foreach (ClassifyEntity classify in ViewBag.classifyEntities)
|
||||||
|
{
|
||||||
|
@:<option value="@classify.Id" @(Model.ParentId == classify.Id ? "selected" : "")>@classify.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section dialogScript
|
||||||
|
{
|
||||||
|
<script type="text/javascript">
|
||||||
|
$('#commit').click(function() {
|
||||||
|
var name = $("#name").val();
|
||||||
|
if (name === ""){
|
||||||
|
lightyear.notify('分类名称不能为空', 'danger', 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$('#modify_classify').submit();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
}
|
160
CMS/JXCMS.CMS.Movie/Admin/Views/Classify/Index.cshtml
Normal file
160
CMS/JXCMS.CMS.Movie/Admin/Views/Classify/Index.cshtml
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
@using JXCMS.CMS.Movie.Entity
|
||||||
|
@using JXCMS.Core.Extensions
|
||||||
|
@model List<JXCMS.CMS.Movie.Entity.ClassifyEntity>
|
||||||
|
|
||||||
|
@{
|
||||||
|
ViewBag.Title = "分类目录";
|
||||||
|
Layout = "_Layout";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container-fluid p-t-15">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-toolbar clearfix">
|
||||||
|
<div class="toolbar-btn-action">
|
||||||
|
<a data-src="@Url.Action("ClassifyDialog", "Classify", new {id = 0})" class="btn btn-primary m-r-5" id="new" data-toggle="modal" data-target="#exampleModal"><i class="mdi mdi-plus"></i> 新增</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>名称</th>
|
||||||
|
<th>别名</th>
|
||||||
|
<th>上级分类</th>
|
||||||
|
<th>视频数量</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@if (Model.Count == 0)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" style="text-align: center">无数据</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
@foreach (var classifyEntity in Model)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@classifyEntity.Name</td>
|
||||||
|
<td>@(classifyEntity.Alias.IsNullOrEmpty() ? "-" : classifyEntity.Alias)</td>
|
||||||
|
<td>@(classifyEntity.Parent == null ? "无" : classifyEntity.Parent.Name)</td>
|
||||||
|
<td>@classifyEntity.Count</td>
|
||||||
|
<td>
|
||||||
|
<div class="btn-group">
|
||||||
|
<a class="btn btn-xs btn-default" data-src="@Url.Action("ClassifyDialog", "Classify", new {id = classifyEntity.Id})" title="编辑" data-toggle="modal" data-target="#exampleModal">
|
||||||
|
<i class="mdi mdi-pencil"></i>
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-xs btn-default" title="删除" data-toggle="tooltip" onclick="delClassify(@classifyEntity.Id, '@classifyEntity.Name')"
|
||||||
|
@if (classifyEntity.Count > 0)
|
||||||
|
{
|
||||||
|
@:disabled
|
||||||
|
}>
|
||||||
|
<i class="mdi mdi-window-close"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<ul class="pagination">
|
||||||
|
@if (ViewBag.pageNumber != 1)
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
<a href="@Url.Action("Index", "Classify")"><<</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
@for (int i = ViewBag.pageNumber - 3; i < ViewBag.pageNumber + 3; i++)
|
||||||
|
{
|
||||||
|
if (i < 1 || i > ViewBag.totlePage)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i == ViewBag.pageNumber)
|
||||||
|
{
|
||||||
|
<li class="active">
|
||||||
|
<span>@i</span>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
<a href="@Url.Action("Index", "Classify", new {pageNumber = i})">@i</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if (ViewBag.pageNumber < ViewBag.totlePage)
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
<a href="@Url.Action("Index", "Classify", new {pageNumber = ViewBag.totlePage})">>></a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
正在加载,请稍后...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form id="delForm" action="@Url.Action("DeleteClassify")" method="post">
|
||||||
|
<input type="hidden" name="id" id="delId"/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section style
|
||||||
|
{
|
||||||
|
<link rel="stylesheet" href="@Url.ContentAdmin("js/jconfirm/jquery-confirm.min.css")">
|
||||||
|
}
|
||||||
|
|
||||||
|
@section script
|
||||||
|
{
|
||||||
|
<script src="@Url.ContentAdmin("js/bootstrap-notify.min.js")"></script>
|
||||||
|
<script type="text/javascript" src="@Url.ContentAdmin("js/lightyear.js")"></script>
|
||||||
|
<script src="@Url.ContentAdmin("js/jconfirm/jquery-confirm.min.js")"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$('#exampleModal').on('show.bs.modal', function(event) {
|
||||||
|
var button = $(event.relatedTarget); // Button that triggered the modal
|
||||||
|
var recipient = button.data('src'); // Extract info from data-* attributes
|
||||||
|
var content = $(this).find(".modal-content");
|
||||||
|
content.html("正在加载,请稍后...");
|
||||||
|
$.get(recipient, function(data, status) {
|
||||||
|
if (status === "success") {
|
||||||
|
content.html(data)
|
||||||
|
} else{
|
||||||
|
content.html("发生错误,请重试")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
function delClassify(id, name) {
|
||||||
|
$.alert({
|
||||||
|
title: '删除分类地址' + name,
|
||||||
|
content: '是否删除' + name + ',?(如果该分类下有子分类,子分类将变为顶级分类)<br />该操作不可恢复',
|
||||||
|
buttons: {
|
||||||
|
confirm: {
|
||||||
|
text: '是',
|
||||||
|
btnClass: 'btn-primary',
|
||||||
|
action: function(){
|
||||||
|
$('#delId').val(id);
|
||||||
|
$('#delForm').submit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cancel: {
|
||||||
|
text: '否'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
@{
|
||||||
|
Layout = "_DialogLayout";
|
||||||
|
}
|
||||||
|
@using JXCMS.CMS.Movie.Entity
|
||||||
|
@model List<JXCMS.CMS.Movie.Entity.WebSiteClassifyEntity>
|
||||||
|
@{
|
||||||
|
var classifyEntities = (List<ClassifyEntity>) ViewBag.classifyEntities;
|
||||||
|
}
|
||||||
|
<form id="modify_website" action="@Url.Action("UpdateBindingClassify")" method="post">
|
||||||
|
@for (int i = 0; i < Model.Count; i++)
|
||||||
|
{
|
||||||
|
@Html.HiddenFor(x => x[i].Id)
|
||||||
|
@Html.HiddenFor(x => x[i].WebSiteId)
|
||||||
|
@Html.HiddenFor(x => x[i].TypeName)
|
||||||
|
@Html.HiddenFor(x => x[i].TypeId)
|
||||||
|
<div class="input-daterange input-group" style="margin-bottom: 10px">
|
||||||
|
<span class="form-control">@Model[i].TypeName</span>
|
||||||
|
<span class="input-group-addon">
|
||||||
|
<i class="mdi mdi-link-variant"></i>
|
||||||
|
</span>
|
||||||
|
@Html.DropDownListFor(x => x[i].ClassifyId, new SelectList(classifyEntities, "Id", "Name", Model[i].ClassifyId),
|
||||||
|
new {@class = "form-control"})
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@section dialogScript
|
||||||
|
{
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$('#commit').click(function() {
|
||||||
|
$('#modify_website').submit();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
}
|
@ -47,10 +47,17 @@
|
|||||||
<th>网站url</th>
|
<th>网站url</th>
|
||||||
<th>采集cron</th>
|
<th>采集cron</th>
|
||||||
<th>状态</th>
|
<th>状态</th>
|
||||||
|
<th>下次执行时间</th>
|
||||||
<th>操作</th>
|
<th>操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@if (ViewBag.website.Count == 0)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td colspan="7" style="text-align: center">无数据</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
@foreach (WebSiteEntity webSiteEntity in ViewBag.website)
|
@foreach (WebSiteEntity webSiteEntity in ViewBag.website)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
@ -65,12 +72,13 @@
|
|||||||
<td>
|
<td>
|
||||||
<span class="text-success">@(webSiteEntity.IsEnable ? "正常" : "已禁用")</span>
|
<span class="text-success">@(webSiteEntity.IsEnable ? "正常" : "已禁用")</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>@webSiteEntity.NextRunTime</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a class="btn btn-xs btn-default" data-src="@Url.Action("WebSiteDialog", "Collection", new {id = webSiteEntity.Id})" title="编辑" data-toggle="modal" data-target="#exampleModal">
|
<a class="btn btn-xs btn-default" data-src="@Url.Action("WebSiteDialog", "Collection", new {id = webSiteEntity.Id})" title="编辑" data-toggle="modal" data-target="#exampleModal">
|
||||||
<i class="mdi mdi-pencil"></i>
|
<i class="mdi mdi-pencil"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-xs btn-default" href="#" title="绑定分类" onclick="delWebsite(@webSiteEntity.Id, '@webSiteEntity.WebSiteName')">
|
<a class="btn btn-xs btn-default" data-src="@Url.Action("BindingClassifyDialog", "Collection", new {id = webSiteEntity.Id})" data-toggle="modal" data-target="#exampleModal">
|
||||||
<i class="mdi mdi-link-variant"></i>
|
<i class="mdi mdi-link-variant"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-xs btn-default" href="#" title="删除" onclick="delWebsite(@webSiteEntity.Id, '@webSiteEntity.WebSiteName')">
|
<a class="btn btn-xs btn-default" href="#" title="删除" onclick="delWebsite(@webSiteEntity.Id, '@webSiteEntity.WebSiteName')">
|
||||||
|
@ -34,11 +34,10 @@
|
|||||||
<ul class="nav nav-drawer">
|
<ul class="nav nav-drawer">
|
||||||
<li class="nav-item active"> <a class="multitabs" href="@Url.Action("Home")"><i class="mdi mdi-home"></i> <span>后台首页</span></a> </li>
|
<li class="nav-item active"> <a class="multitabs" href="@Url.Action("Home")"><i class="mdi mdi-home"></i> <span>后台首页</span></a> </li>
|
||||||
<li class="nav-item nav-item-has-subnav">
|
<li class="nav-item nav-item-has-subnav">
|
||||||
<a href="javascript:void(0)"><i class="mdi mdi-format-align-justify"></i> <span>文章</span></a>
|
<a href="javascript:void(0)"><i class="mdi mdi-format-align-justify"></i> <span>影视</span></a>
|
||||||
<ul class="nav nav-subnav">
|
<ul class="nav nav-subnav">
|
||||||
<li> <a class="multitabs" href="@Url.Action("Index", "Article")">所有文章</a> </li>
|
<li> <a class="multitabs" href="@Url.Action("Index", "Movie")">所有影视</a> </li>
|
||||||
<li> <a class="multitabs" href="lyear_forms_radio.html">写文章</a> </li>
|
<li> <a class="multitabs" href="@Url.Action("Index", "Classify")">分类目录</a> </li>
|
||||||
<li> <a class="multitabs" href="lyear_forms_checkbox.html">分类目录</a> </li>
|
|
||||||
<li> <a class="multitabs" href="lyear_forms_switch.html">标签</a> </li>
|
<li> <a class="multitabs" href="lyear_forms_switch.html">标签</a> </li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
131
CMS/JXCMS.CMS.Movie/Admin/Views/Movie/Index.cshtml
Normal file
131
CMS/JXCMS.CMS.Movie/Admin/Views/Movie/Index.cshtml
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
@model List<JXCMS.CMS.Movie.Entity.MovieEntity>
|
||||||
|
|
||||||
|
@{
|
||||||
|
Layout = "_Layout";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container-fluid p-t-15">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-toolbar clearfix">
|
||||||
|
<form class="pull-right search-bar" method="get" action="#!" role="form">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-btn">
|
||||||
|
<input type="hidden" name="search_field" id="search-field" value="title">
|
||||||
|
<button class="btn btn-default dropdown-toggle" id="search-btn" data-toggle="dropdown" type="button" aria-haspopup="true" aria-expanded="false">
|
||||||
|
标题 <span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li>
|
||||||
|
<a tabindex="-1" href="javascript:void(0)" data-field="title">标题</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a tabindex="-1" href="javascript:void(0)" data-field="cat_name">栏目</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-control" value="" name="keyword" placeholder="请输入名称">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="toolbar-btn-action">
|
||||||
|
<a class="btn btn-primary m-r-5" href="#!"><i class="mdi mdi-plus"></i> 新增</a>
|
||||||
|
<a class="btn btn-success m-r-5" href="#!"><i class="mdi mdi-check"></i> 显示</a>
|
||||||
|
<a class="btn btn-warning m-r-5" href="#!"><i class="mdi mdi-block-helper"></i> 隐藏</a>
|
||||||
|
<a class="btn btn-danger" href="#!"><i class="mdi mdi-window-close"></i> 删除</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<label class="lyear-checkbox checkbox-primary">
|
||||||
|
<input type="checkbox" id="check-all"><span></span>
|
||||||
|
</label>
|
||||||
|
</th>
|
||||||
|
<th>名称</th>
|
||||||
|
<th>导演</th>
|
||||||
|
<th>年份</th>
|
||||||
|
<th>语种</th>
|
||||||
|
<th>分类</th>
|
||||||
|
<th>状态</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var movieEntity in Model)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label class="lyear-checkbox checkbox-primary">
|
||||||
|
<input type="checkbox" name="ids[]" value="1"><span></span>
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td>@movieEntity.Name</td>
|
||||||
|
<td>@movieEntity.DirectorEntity.DirectorName</td>
|
||||||
|
<td>@movieEntity.Year</td>
|
||||||
|
<td>@movieEntity.Lang</td>
|
||||||
|
<td>@movieEntity.ClassifyEntity.Name</td>
|
||||||
|
<td>
|
||||||
|
<font class="text-success">@(movieEntity.IsEnable ? "正常" : "已隐藏")</font>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="btn-group">
|
||||||
|
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip">
|
||||||
|
<i class="mdi mdi-pencil"></i>
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip">
|
||||||
|
<i class="mdi mdi-window-close"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<ul class="pagination">
|
||||||
|
@if (ViewBag.pageNumber != 1)
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
<a href="@Url.Action("Index", "Collection")"><<</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
@for (int i = ViewBag.pageNumber - 3; i < ViewBag.pageNumber + 3; i++)
|
||||||
|
{
|
||||||
|
if (i < 1 || i > ViewBag.totlePage)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i == ViewBag.pageNumber)
|
||||||
|
{
|
||||||
|
<li class="active">
|
||||||
|
<span>@i</span>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
<a href="@Url.Action("Index", "Collection", new {pageNumber = i})">@i</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if (ViewBag.pageNumber < ViewBag.totlePage)
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
<a href="@Url.Action("Index", "Collection", new {pageNumber = ViewBag.totlePage})">>></a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
@ -6,6 +6,8 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using JXCMS.CMS.Models;
|
using JXCMS.CMS.Models;
|
||||||
|
using JXCMS.CMS.Movie.Entity;
|
||||||
|
using JXCMS.CMS.Movie.Spider;
|
||||||
using JXCMS.Core.Themes;
|
using JXCMS.Core.Themes;
|
||||||
|
|
||||||
namespace JXCMS.CMS.Controllers
|
namespace JXCMS.CMS.Controllers
|
||||||
@ -35,5 +37,10 @@ namespace JXCMS.CMS.Controllers
|
|||||||
{
|
{
|
||||||
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IActionResult Test()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
CMS/JXCMS.CMS.Movie/Entity/ActorEntity.cs
Normal file
14
CMS/JXCMS.CMS.Movie/Entity/ActorEntity.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using FreeSql;
|
||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Entity
|
||||||
|
{
|
||||||
|
public class ActorEntity : BaseEntity<ActorEntity, int>
|
||||||
|
{
|
||||||
|
public string ActorName { get; set; }
|
||||||
|
|
||||||
|
[Navigate(ManyToMany = typeof(MovieActorEntity))]
|
||||||
|
public List<MovieEntity> MovieEntities { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,7 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using FreeSql;
|
using FreeSql;
|
||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using Renci.SshNet.Messages.Transport;
|
||||||
|
|
||||||
namespace JXCMS.CMS.Movie.Entity
|
namespace JXCMS.CMS.Movie.Entity
|
||||||
{
|
{
|
||||||
@ -6,6 +9,17 @@ namespace JXCMS.CMS.Movie.Entity
|
|||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string Alias { get; set; }
|
||||||
|
|
||||||
public int ParentId { get; set; }
|
public int ParentId { get; set; }
|
||||||
|
|
||||||
|
[Navigate("ParentId")]
|
||||||
|
public ClassifyEntity Parent { get; set; }
|
||||||
|
|
||||||
|
public ICollection<ClassifyEntity> Childs { get; set; }
|
||||||
|
|
||||||
|
[Column(IsIgnore = true)]
|
||||||
|
public long Count { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
9
CMS/JXCMS.CMS.Movie/Entity/DirectorEntity.cs
Normal file
9
CMS/JXCMS.CMS.Movie/Entity/DirectorEntity.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using FreeSql;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Entity
|
||||||
|
{
|
||||||
|
public class DirectorEntity : BaseEntity<DirectorEntity, int>
|
||||||
|
{
|
||||||
|
public string DirectorName { get; set; }
|
||||||
|
}
|
||||||
|
}
|
18
CMS/JXCMS.CMS.Movie/Entity/MovieActorEntity.cs
Normal file
18
CMS/JXCMS.CMS.Movie/Entity/MovieActorEntity.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using FreeSql;
|
||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Entity
|
||||||
|
{
|
||||||
|
public class MovieActorEntity : BaseEntity<MovieActorEntity, int>
|
||||||
|
{
|
||||||
|
public int ActorId { get; set; }
|
||||||
|
|
||||||
|
[Navigate("ActorId")]
|
||||||
|
public ActorEntity ActorEntity { get; set; }
|
||||||
|
|
||||||
|
public int MovieId { get; set; }
|
||||||
|
|
||||||
|
[Navigate("MovieId")]
|
||||||
|
public MovieEntity MovieEntity { get; set; }
|
||||||
|
}
|
||||||
|
}
|
44
CMS/JXCMS.CMS.Movie/Entity/MovieEntity.cs
Normal file
44
CMS/JXCMS.CMS.Movie/Entity/MovieEntity.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using FreeSql;
|
||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Entity
|
||||||
|
{
|
||||||
|
public class MovieEntity : BaseEntity<MovieEntity, int>
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string Pic { get; set; }
|
||||||
|
|
||||||
|
public int ClassifyId { get; set; }
|
||||||
|
|
||||||
|
public string Lang { get; set; }
|
||||||
|
|
||||||
|
public string Area { get; set; }
|
||||||
|
|
||||||
|
public string Year { get; set; }
|
||||||
|
|
||||||
|
public int DirectorId { get; set; }
|
||||||
|
|
||||||
|
public DateTime LastUpdate { get; set; }
|
||||||
|
|
||||||
|
public bool IsEnable { get; set; } = true;
|
||||||
|
|
||||||
|
[StringLength(-1)]
|
||||||
|
public string Des { get; set; }
|
||||||
|
|
||||||
|
[Navigate("DirectorId")]
|
||||||
|
public virtual DirectorEntity DirectorEntity { get; set; }
|
||||||
|
|
||||||
|
[Navigate("ClassifyId")]
|
||||||
|
public virtual ClassifyEntity ClassifyEntity { get; set; }
|
||||||
|
|
||||||
|
[Navigate(ManyToMany = typeof(MovieActorEntity))]
|
||||||
|
public virtual List<ActorEntity> ActorEntities { get; set; }
|
||||||
|
|
||||||
|
[Navigate("Id")]
|
||||||
|
public virtual List<MovieListEntity> MovieListEntities { get; set; }
|
||||||
|
}
|
||||||
|
}
|
22
CMS/JXCMS.CMS.Movie/Entity/MovieListEntity.cs
Normal file
22
CMS/JXCMS.CMS.Movie/Entity/MovieListEntity.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using FreeSql;
|
||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Entity
|
||||||
|
{
|
||||||
|
public class MovieListEntity : BaseEntity<MovieListEntity, int>
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string PlayUrl { get; set; }
|
||||||
|
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
|
public int MovieId { get; set; }
|
||||||
|
|
||||||
|
public int WebSiteId { get; set; }
|
||||||
|
|
||||||
|
[Navigate("MovieId")]
|
||||||
|
public virtual MovieEntity MovieEntity { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
CMS/JXCMS.CMS.Movie/Entity/WebSiteClassifyEntity.cs
Normal file
19
CMS/JXCMS.CMS.Movie/Entity/WebSiteClassifyEntity.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using FreeSql;
|
||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Entity
|
||||||
|
{
|
||||||
|
public class WebSiteClassifyEntity : BaseEntity<WebSiteClassifyEntity, int>
|
||||||
|
{
|
||||||
|
public int WebSiteId { get; set; }
|
||||||
|
|
||||||
|
public int TypeId { get; set; }
|
||||||
|
|
||||||
|
public string TypeName { get; set; }
|
||||||
|
|
||||||
|
public int ClassifyId { get; set; }
|
||||||
|
|
||||||
|
[Navigate("WebSiteId")]
|
||||||
|
public virtual WebSiteEntity WebSiteEntity { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,7 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using FreeSql;
|
using FreeSql;
|
||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
|
||||||
namespace JXCMS.CMS.Movie.Entity
|
namespace JXCMS.CMS.Movie.Entity
|
||||||
{
|
{
|
||||||
@ -11,5 +14,15 @@ namespace JXCMS.CMS.Movie.Entity
|
|||||||
public string Cron { get; set; } = "0 0 * * * ?";
|
public string Cron { get; set; } = "0 0 * * * ?";
|
||||||
|
|
||||||
public bool IsEnable { get; set; } = true;
|
public bool IsEnable { get; set; } = true;
|
||||||
|
|
||||||
|
public string LatestMovieNote { get; set; }
|
||||||
|
|
||||||
|
public DateTime LatestMoveTime { get; set; }
|
||||||
|
|
||||||
|
[Navigate("Id")]
|
||||||
|
public List<ClassifyEntity> WebSiteClassifyEntities { get; set; }
|
||||||
|
|
||||||
|
[Column(IsIgnore = true)]
|
||||||
|
public string NextRunTime { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Admin\Content" />
|
<Folder Include="Admin\Content" />
|
||||||
|
<Folder Include="Logs" />
|
||||||
<Folder Include="Views\Default" />
|
<Folder Include="Views\Default" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
33
CMS/JXCMS.CMS.Movie/Models/MovieListInfoModel.cs
Normal file
33
CMS/JXCMS.CMS.Movie/Models/MovieListInfoModel.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using JXCMS.CMS.Movie.Entity;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Models
|
||||||
|
{
|
||||||
|
public class MovieListInfoModel
|
||||||
|
{
|
||||||
|
public string RecordCount { get; set; }
|
||||||
|
|
||||||
|
public string PageSize { get; set; }
|
||||||
|
|
||||||
|
public string CurrentPage { get; set; }
|
||||||
|
|
||||||
|
public string PageCount { get; set; }
|
||||||
|
|
||||||
|
public List<MovieInfoModel> MovieInfoModels { get; set; } = new List<MovieInfoModel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MovieInfoModel
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
public string TypeId { get; set; }
|
||||||
|
|
||||||
|
public DateTime LastUpdateTime { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string TypeName { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Hosting;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace JXCMS.CMS
|
namespace JXCMS.CMS
|
||||||
{
|
{
|
||||||
@ -22,6 +23,6 @@ namespace JXCMS.CMS
|
|||||||
.ConfigureWebHostDefaults(webBuilder =>
|
.ConfigureWebHostDefaults(webBuilder =>
|
||||||
{
|
{
|
||||||
webBuilder.UseStartup<Startup>();
|
webBuilder.UseStartup<Startup>();
|
||||||
});
|
}).UseSerilog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
CMS/JXCMS.CMS.Movie/Spider/ClassifySpider.cs
Normal file
38
CMS/JXCMS.CMS.Movie/Spider/ClassifySpider.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Xml;
|
||||||
|
using JXCMS.CMS.Movie.Entity;
|
||||||
|
using SufeiUtil;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Spider
|
||||||
|
{
|
||||||
|
public class ClassifySpider
|
||||||
|
{
|
||||||
|
public static void GetAllClassifyFromUrl(int websiteId, string url, List<WebSiteClassifyEntity> webSiteClassifyEntities)
|
||||||
|
{
|
||||||
|
var helper = new HttpHelper();
|
||||||
|
var item = new HttpItem();
|
||||||
|
item.URL = url;
|
||||||
|
var result = helper.GetHtml(item);
|
||||||
|
if (result.StatusCode == HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
XmlDocument doc = new XmlDocument();
|
||||||
|
doc.LoadXml(result.Html);
|
||||||
|
var classNode = doc.SelectSingleNode("/rss/class");
|
||||||
|
|
||||||
|
foreach (XmlNode childNode in classNode.ChildNodes)
|
||||||
|
{
|
||||||
|
if (webSiteClassifyEntities.All(x => x.TypeId.ToString() != childNode.Attributes["id"].Value))
|
||||||
|
{
|
||||||
|
WebSiteClassifyEntity webSiteClassifyEntity = new WebSiteClassifyEntity();
|
||||||
|
webSiteClassifyEntity.TypeId = int.Parse(childNode.Attributes["id"].Value);
|
||||||
|
webSiteClassifyEntity.TypeName = childNode.InnerText;
|
||||||
|
webSiteClassifyEntity.WebSiteId = websiteId;
|
||||||
|
webSiteClassifyEntities.Add(webSiteClassifyEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
265
CMS/JXCMS.CMS.Movie/Spider/MovieSpider.cs
Normal file
265
CMS/JXCMS.CMS.Movie/Spider/MovieSpider.cs
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Xml;
|
||||||
|
using FreeSql;
|
||||||
|
using JXCMS.CMS.Movie.Entity;
|
||||||
|
using JXCMS.CMS.Movie.Models;
|
||||||
|
using JXCMS.Core.Extensions;
|
||||||
|
using JXCMS.Core.Log;
|
||||||
|
using SufeiUtil;
|
||||||
|
using Log = Serilog.Log;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Spider
|
||||||
|
{
|
||||||
|
public class MovieSpider
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly List<WebSiteClassifyEntity> _webSiteClassifyEntities;
|
||||||
|
private readonly List<ActorEntity> _actorEntities;
|
||||||
|
private readonly List<DirectorEntity> _directorEntities;
|
||||||
|
|
||||||
|
private static MovieSpider _instance;
|
||||||
|
|
||||||
|
public static MovieSpider Instance => _instance ??= new MovieSpider();
|
||||||
|
|
||||||
|
private MovieSpider()
|
||||||
|
{
|
||||||
|
_webSiteClassifyEntities = WebSiteClassifyEntity.Select.ToList();
|
||||||
|
_actorEntities = ActorEntity.Select.ToList();
|
||||||
|
_directorEntities = DirectorEntity.Select.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MovieListInfoModel GetMovieList(WebSiteEntity webSiteEntity, int number)
|
||||||
|
{
|
||||||
|
HttpItem item = new HttpItem();
|
||||||
|
item.URL = $"{webSiteEntity.ApiUrl}?pg={number}";
|
||||||
|
HttpHelper helper = new HttpHelper();
|
||||||
|
var result = helper.GetHtml(item);
|
||||||
|
if (result.StatusCode == HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
Log.Logger.Information($"{{@name}} 成功获取地址:{item.URL}", webSiteEntity.WebSiteName);
|
||||||
|
XmlDocument doc = new XmlDocument();
|
||||||
|
doc.LoadXml(result.Html);
|
||||||
|
var listNode = doc.SelectSingleNode("/rss/list");
|
||||||
|
MovieListInfoModel movieListInfoModel = new MovieListInfoModel();;
|
||||||
|
movieListInfoModel.CurrentPage = listNode.Attributes["page"].Value;
|
||||||
|
movieListInfoModel.PageCount = listNode.Attributes["pagecount"].Value;
|
||||||
|
movieListInfoModel.PageSize = listNode.Attributes["pagesize"].Value;
|
||||||
|
movieListInfoModel.RecordCount = listNode.Attributes["recordcount"].Value;
|
||||||
|
var videos = listNode.SelectNodes("//video");
|
||||||
|
foreach (XmlNode video in videos)
|
||||||
|
{
|
||||||
|
MovieInfoModel model = new MovieInfoModel
|
||||||
|
{
|
||||||
|
LastUpdateTime = DateTime.Parse(video.SelectSingleNode("last").InnerText),
|
||||||
|
Name = video.SelectSingleNode("name").InnerText,
|
||||||
|
TypeId = video.SelectSingleNode("tid").InnerText,
|
||||||
|
Id = video.SelectSingleNode("id").InnerText,
|
||||||
|
TypeName = video.SelectSingleNode("type").InnerText
|
||||||
|
};
|
||||||
|
movieListInfoModel.MovieInfoModels.Add(model);
|
||||||
|
}
|
||||||
|
return movieListInfoModel;
|
||||||
|
}
|
||||||
|
Log.Warning($"{{@name}} 获取api失败,错误码{result.StatusCode}", webSiteEntity.WebSiteName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime GetMovieInfos(WebSiteEntity webSiteEntity, List<(string id, string name, string typeId)> idNameTypes)
|
||||||
|
{
|
||||||
|
HttpItem item = new HttpItem();
|
||||||
|
item.URL = $"{webSiteEntity.ApiUrl}?ac=videolist&ids={string.Join(",", idNameTypes.Select(x => x.id))}";
|
||||||
|
HttpHelper helper = new HttpHelper();
|
||||||
|
var result = helper.GetHtml(item);
|
||||||
|
if (result.StatusCode == HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
DateTime dt = DateTime.MinValue;
|
||||||
|
Log.Logger.Information($"{{@name}} 成功获取地址:{item.URL}", webSiteEntity.WebSiteName);
|
||||||
|
XmlDocument doc = new XmlDocument();
|
||||||
|
doc.LoadXml(result.Html);
|
||||||
|
var videoNode = doc.SelectNodes("/rss/list/video");
|
||||||
|
foreach (XmlNode video in videoNode)
|
||||||
|
{
|
||||||
|
var name = video.SelectSingleNode("name").InnerText;
|
||||||
|
var director = video.SelectSingleNode("director").InnerText;
|
||||||
|
if (director.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
director = "未知";
|
||||||
|
}
|
||||||
|
var movieEntity = MovieEntity.Select.Include(x => x.DirectorEntity)
|
||||||
|
.Where(x => x.Name == name && x.DirectorEntity.DirectorName == director).First();
|
||||||
|
if (movieEntity == null)
|
||||||
|
{
|
||||||
|
movieEntity = new MovieEntity();
|
||||||
|
movieEntity.Area = video.SelectSingleNode("area").InnerText == "" ? "未知":video.SelectSingleNode("area").InnerText;
|
||||||
|
movieEntity.Des = video.SelectSingleNode("des").InnerText == "" ? "暂无介绍":video.SelectSingleNode("des").InnerText;
|
||||||
|
movieEntity.Lang = video.SelectSingleNode("lang").InnerText == "" ? "未知":video.SelectSingleNode("lang").InnerText;
|
||||||
|
movieEntity.Name = video.SelectSingleNode("name").InnerText;
|
||||||
|
movieEntity.Pic = video.SelectSingleNode("pic").InnerText == "" ? "/img/cover.jpg":video.SelectSingleNode("lang").InnerText;
|
||||||
|
movieEntity.Year = video.SelectSingleNode("year").InnerText == "" || video.SelectSingleNode("year").InnerText == "0" ? "未知":video.SelectSingleNode("year").InnerText;
|
||||||
|
movieEntity.ClassifyId = int.Parse(idNameTypes.First(x => x.id == video.SelectSingleNode("id").InnerText).typeId);
|
||||||
|
var directorId = _directorEntities.FirstOrDefault(x => x.DirectorName == director)?.Id;
|
||||||
|
if (directorId == null)
|
||||||
|
{
|
||||||
|
DirectorEntity directorEntity = new DirectorEntity();
|
||||||
|
directorEntity.DirectorName = director;
|
||||||
|
directorEntity.Save();
|
||||||
|
directorId = directorEntity.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
movieEntity.DirectorId = directorId.Value;
|
||||||
|
movieEntity.LastUpdate = DateTime.Parse(video.SelectSingleNode("last").InnerText);
|
||||||
|
movieEntity.Save();
|
||||||
|
if (movieEntity.LastUpdate > dt)
|
||||||
|
{
|
||||||
|
dt = movieEntity.LastUpdate;
|
||||||
|
}
|
||||||
|
var actorStr = video.SelectSingleNode("actor").InnerText;
|
||||||
|
if (actorStr.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
actorStr = "未知";
|
||||||
|
}
|
||||||
|
var actorsStr = actorStr.Split(',', ' ');
|
||||||
|
var actors = _actorEntities.Where(x => actorsStr.Contains(x.ActorName)).ToList();
|
||||||
|
foreach (var actor in actorsStr)
|
||||||
|
{
|
||||||
|
var id = actors.FirstOrDefault(x => x.ActorName == actor)?.Id;
|
||||||
|
if (id == null)
|
||||||
|
{
|
||||||
|
ActorEntity actorEntity = new ActorEntity {ActorName = actor};
|
||||||
|
actorEntity.Save();
|
||||||
|
id = actorEntity.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
MovieActorEntity movieActorEntity = new MovieActorEntity
|
||||||
|
{
|
||||||
|
ActorId = id.Value, MovieId = movieEntity.Id
|
||||||
|
};
|
||||||
|
movieActorEntity.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dds = video.SelectNodes("dl/dd");
|
||||||
|
var movieListEntity = MovieListEntity.Where(x => x.MovieId == movieEntity.Id && x.WebSiteId == webSiteEntity.Id)
|
||||||
|
.OrderByDescending(x => x.Id).First();
|
||||||
|
if (movieListEntity == null)
|
||||||
|
{
|
||||||
|
foreach (XmlNode dd in dds)
|
||||||
|
{
|
||||||
|
var number = dd.InnerText.Split('#');
|
||||||
|
if (number.Length <= 0 || !number[0].Split('$')[1].ToLower().EndsWith("m3u8"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Log.Logger.Information("{@name} 获取到m3u8列表!", webSiteEntity.WebSiteName);
|
||||||
|
var movieListEntities = number.Select(x =>
|
||||||
|
{
|
||||||
|
var sp = x.Split('$');
|
||||||
|
return new MovieListEntity
|
||||||
|
{
|
||||||
|
Name = sp[0],
|
||||||
|
Type = sp[2],
|
||||||
|
MovieId = movieEntity.Id,
|
||||||
|
PlayUrl = sp[1],
|
||||||
|
WebSiteId = webSiteEntity.Id
|
||||||
|
};
|
||||||
|
});
|
||||||
|
BaseEntity.Orm.Insert(movieListEntities).ExecuteAffrows();
|
||||||
|
Log.Logger.Information($"{{@name}} 插入剧集{movieEntity.Name}成功!", webSiteEntity.WebSiteName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var node = dds.Cast<XmlNode>().FirstOrDefault(x => x.Attributes["flag"].Value == movieListEntity.Type);
|
||||||
|
if (node == null)
|
||||||
|
{
|
||||||
|
Log.Logger.Error("{@name} 未找到指定的剧集列表!", webSiteEntity.WebSiteName);
|
||||||
|
}
|
||||||
|
bool flag = false;
|
||||||
|
foreach (var number in node.InnerText.Split('#'))
|
||||||
|
{
|
||||||
|
var sp = number.Split('$');
|
||||||
|
if (sp[0] == movieListEntity.Name)
|
||||||
|
{
|
||||||
|
flag = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!flag)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
new MovieListEntity()
|
||||||
|
{
|
||||||
|
Name = sp[0],
|
||||||
|
MovieId = movieEntity.Id,
|
||||||
|
PlayUrl = sp[1],
|
||||||
|
Type = sp[2],
|
||||||
|
WebSiteId = webSiteEntity.Id
|
||||||
|
}.Save();
|
||||||
|
Log.Logger.Information($"{{@name}} 插入剧集{movieEntity.Name}-{sp[0]}成功!", webSiteEntity.WebSiteName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
return DateTime.MinValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartSpider(WebSiteEntity webSiteEntity, bool reGetAll = false)
|
||||||
|
{
|
||||||
|
var model = GetMovieList(webSiteEntity, 1);
|
||||||
|
if (model == null)
|
||||||
|
{
|
||||||
|
Log.Logger.Error("{@name} 获取信息失败,采集结束!", webSiteEntity.WebSiteName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int number = 1;
|
||||||
|
if (!int.TryParse(model.PageCount, out int count))
|
||||||
|
{
|
||||||
|
Log.Logger.Error("{@name} 获取总页数失败,采集结束!", webSiteEntity.WebSiteName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DateTime dt = DateTime.MinValue;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
model = GetMovieList(webSiteEntity, number++);
|
||||||
|
if (model == null)
|
||||||
|
{
|
||||||
|
Log.Logger.Error("{@name} 获取信息失败,采集结束!", webSiteEntity.WebSiteName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<(string id, string name, string typeId)> idNameTypes = new List<(string, string, string)>();
|
||||||
|
foreach (var modelMovieInfoModel in model.MovieInfoModels)
|
||||||
|
{
|
||||||
|
if (webSiteEntity.LatestMoveTime > modelMovieInfoModel.LastUpdateTime)
|
||||||
|
{
|
||||||
|
Log.Logger.Information("{@name} 已检查到最后一条", webSiteEntity.WebSiteName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!_webSiteClassifyEntities.Any(x => x.WebSiteId == webSiteEntity.Id && x.TypeId.ToString() == modelMovieInfoModel.TypeId))
|
||||||
|
{
|
||||||
|
Log.Logger.Warning($"{{@name}} 未找到与{modelMovieInfoModel.TypeName}对应的分类,自动跳过", webSiteEntity.WebSiteName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
idNameTypes.Add((modelMovieInfoModel.Id, modelMovieInfoModel.Name, modelMovieInfoModel.TypeId));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idNameTypes.Count == 0)
|
||||||
|
{
|
||||||
|
if (webSiteEntity.LatestMoveTime < dt)
|
||||||
|
{
|
||||||
|
webSiteEntity.LatestMoveTime = dt;
|
||||||
|
webSiteEntity.Save();
|
||||||
|
}
|
||||||
|
Log.Information("{@name} 采集完成!", webSiteEntity.WebSiteName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dt = GetMovieInfos(webSiteEntity, idNameTypes);
|
||||||
|
} while (number <= count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,12 +8,15 @@ using JXCMS.CMS.Entity;
|
|||||||
using JXCMS.Core;
|
using JXCMS.Core;
|
||||||
using JXCMS.Core.Auth;
|
using JXCMS.Core.Auth;
|
||||||
using JXCMS.Core.Db;
|
using JXCMS.Core.Db;
|
||||||
|
using JXCMS.Core.Log;
|
||||||
using JXCMS.Core.Themes;
|
using JXCMS.Core.Themes;
|
||||||
|
using JXCMS.Core.Utils;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.HttpsPolicy;
|
using Microsoft.AspNetCore.HttpsPolicy;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@ -28,6 +31,8 @@ namespace JXCMS.CMS
|
|||||||
{
|
{
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
Environment = environment;
|
Environment = environment;
|
||||||
|
ConfigHelper.Configs = Configuration;
|
||||||
|
Log.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IHostEnvironment Environment { get; }
|
public IHostEnvironment Environment { get; }
|
||||||
@ -54,6 +59,10 @@ namespace JXCMS.CMS
|
|||||||
|
|
||||||
services.AddCms();
|
services.AddCms();
|
||||||
|
|
||||||
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
|
|
||||||
|
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
46
CMS/JXCMS.CMS.Movie/Utils/Classify.cs
Normal file
46
CMS/JXCMS.CMS.Movie/Utils/Classify.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using JXCMS.CMS.Movie.Entity;
|
||||||
|
using JXCMS.Core.Extensions;
|
||||||
|
|
||||||
|
namespace JXCMS.CMS.Movie.Utils
|
||||||
|
{
|
||||||
|
public static class Classify
|
||||||
|
{
|
||||||
|
public static List<ClassifyEntity> FindAllChildren(List<ClassifyEntity> classifyEntities, int baseId, bool includeSelf = true)
|
||||||
|
{
|
||||||
|
var returnValue = new List<ClassifyEntity>();
|
||||||
|
if (includeSelf)
|
||||||
|
{
|
||||||
|
returnValue.AddRange(classifyEntities.Where(x => x.Id == baseId));
|
||||||
|
}
|
||||||
|
var classifyEntityList = classifyEntities.Where(x => x.ParentId == baseId).ToList();
|
||||||
|
returnValue.AddRange(classifyEntityList);
|
||||||
|
foreach (var classifyEntity in classifyEntityList)
|
||||||
|
{
|
||||||
|
returnValue.AddRange(FindAllChildren(classifyEntities, classifyEntity.Id, false));
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ClassifyEntity> FindAllNotChildren(List<ClassifyEntity> classifyEntities, int baseId)
|
||||||
|
{
|
||||||
|
var children = FindAllChildren(classifyEntities, baseId, true);
|
||||||
|
return classifyEntities.Where(x => !children.Contains(x)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ClassifyEntity> Structured(List<ClassifyEntity> classifyEntities, int baseId = 0, int hierarchy = 0)
|
||||||
|
{
|
||||||
|
var returnValue = new List<ClassifyEntity>();
|
||||||
|
var classifyEntityList = classifyEntities.Where(x => x.ParentId == baseId).ToList();
|
||||||
|
foreach (var classifyEntity in classifyEntityList)
|
||||||
|
{
|
||||||
|
classifyEntity.Name = classifyEntity.Name.InsertMultipleString("-", hierarchy * 2);
|
||||||
|
returnValue.Add(classifyEntity);
|
||||||
|
returnValue.AddRange(Structured(classifyEntities, classifyEntity.Id, hierarchy + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
848
CMS/JXCMS.CMS.Movie/Utils/HttpHelper.cs
Normal file
848
CMS/JXCMS.CMS.Movie/Utils/HttpHelper.cs
Normal file
@ -0,0 +1,848 @@
|
|||||||
|
/// <summary>
|
||||||
|
/// 类说明:HttpHelper类,用来实现Http访问,Post或者Get方式的,直接访问,带Cookie的,带证书的等方式,可以设置代理
|
||||||
|
/// 重要提示:请不要自行修改本类,如果因为你自己修改后将无法升级到新版本。如果确实有什么问题请到官方网站提建议,
|
||||||
|
/// 我们一定会及时修改
|
||||||
|
/// 编码日期:2011-09-20
|
||||||
|
/// 编 码 人:苏飞
|
||||||
|
/// 联系方式:361983679
|
||||||
|
/// 官方网址:http://www.sufeinet.com/thread-3-1-1.html
|
||||||
|
/// 修改日期:2020-02-10
|
||||||
|
/// 版 本 号:2.2.9
|
||||||
|
/// </summary>
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Cache;
|
||||||
|
|
||||||
|
namespace SufeiUtil
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Http连接操作帮助类
|
||||||
|
/// </summary>
|
||||||
|
public class HttpHelper
|
||||||
|
{
|
||||||
|
#region 预定义方变量
|
||||||
|
//默认的编码
|
||||||
|
private Encoding encoding = Encoding.Default;
|
||||||
|
//Post数据编码
|
||||||
|
private Encoding postencoding = Encoding.Default;
|
||||||
|
//HttpWebRequest对象用来发起请求
|
||||||
|
private HttpWebRequest request = null;
|
||||||
|
//获取影响流的数据对象
|
||||||
|
private HttpWebResponse response = null;
|
||||||
|
//设置本地的出口ip和端口
|
||||||
|
private IPEndPoint _IPEndPoint = null;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据相传入的数据,得到相应页面数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">参数类对象</param>
|
||||||
|
/// <returns>返回HttpResult类型</returns>
|
||||||
|
public HttpResult GetHtml(HttpItem item)
|
||||||
|
{
|
||||||
|
//返回参数
|
||||||
|
HttpResult result = new HttpResult();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//准备参数
|
||||||
|
SetRequest(item);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
//配置参数时出错
|
||||||
|
return new HttpResult() { Cookie = string.Empty, Header = null, Html = ex.Message, StatusDescription = "配置参数时出错:" + ex.Message };
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//请求数据
|
||||||
|
using (response = (HttpWebResponse)request.GetResponse())
|
||||||
|
{
|
||||||
|
GetData(item, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (WebException ex)
|
||||||
|
{
|
||||||
|
if (ex.Response != null)
|
||||||
|
{
|
||||||
|
using (response = (HttpWebResponse)ex.Response)
|
||||||
|
{
|
||||||
|
GetData(item, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Html = ex.Message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
result.Html = ex.Message;
|
||||||
|
}
|
||||||
|
if (item.IsToLower) result.Html = result.Html.ToLower();
|
||||||
|
//重置request,response为空
|
||||||
|
if (item.IsReset)
|
||||||
|
{
|
||||||
|
request = null;
|
||||||
|
response = null;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetData
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取数据的并解析的方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item"></param>
|
||||||
|
/// <param name="result"></param>
|
||||||
|
private void GetData(HttpItem item, HttpResult result)
|
||||||
|
{
|
||||||
|
if (response == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#region base
|
||||||
|
//获取StatusCode
|
||||||
|
result.StatusCode = response.StatusCode;
|
||||||
|
//获取StatusDescription
|
||||||
|
result.StatusDescription = response.StatusDescription;
|
||||||
|
//获取Headers
|
||||||
|
result.Header = response.Headers;
|
||||||
|
//获取最后访问的URl
|
||||||
|
result.ResponseUri = response.ResponseUri.ToString();
|
||||||
|
//获取CookieCollection
|
||||||
|
if (response.Cookies != null) result.CookieCollection = response.Cookies;
|
||||||
|
//获取set-cookie
|
||||||
|
if (response.Headers["set-cookie"] != null) result.Cookie = response.Headers["set-cookie"];
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region byte
|
||||||
|
|
||||||
|
//处理网页Byte
|
||||||
|
byte[] ResponseByte = GetByte();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Html
|
||||||
|
if (ResponseByte != null && ResponseByte.Length > 0)
|
||||||
|
{
|
||||||
|
//设置编码
|
||||||
|
SetEncoding(item, result, ResponseByte);
|
||||||
|
//得到返回的HTML
|
||||||
|
result.Html = encoding.GetString(ResponseByte);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//没有返回任何Html代码
|
||||||
|
result.Html = string.Empty;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置编码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">HttpItem</param>
|
||||||
|
/// <param name="result">HttpResult</param>
|
||||||
|
/// <param name="ResponseByte">byte[]</param>
|
||||||
|
private void SetEncoding(HttpItem item, HttpResult result, byte[] ResponseByte)
|
||||||
|
{
|
||||||
|
//是否返回Byte类型数据
|
||||||
|
if (item.ResultType == ResultType.Byte) result.ResultByte = ResponseByte;
|
||||||
|
//从这里开始我们要无视编码了
|
||||||
|
if (encoding == null)
|
||||||
|
{
|
||||||
|
Match meta = Regex.Match(Encoding.Default.GetString(ResponseByte), "<meta[^<]*charset=([^<]*)[\"']", RegexOptions.IgnoreCase);
|
||||||
|
string c = string.Empty;
|
||||||
|
if (meta != null && meta.Groups.Count > 0)
|
||||||
|
{
|
||||||
|
c = meta.Groups[1].Value.ToLower().Trim();
|
||||||
|
}
|
||||||
|
if (c.Length > 2)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
encoding = Encoding.GetEncoding(c.Replace("\"", string.Empty).Replace("'", "").Replace(";", "").Replace("iso-8859-1", "gbk").Trim());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(response.CharacterSet))
|
||||||
|
{
|
||||||
|
encoding = Encoding.UTF8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
encoding = Encoding.GetEncoding(response.CharacterSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(response.CharacterSet))
|
||||||
|
{
|
||||||
|
encoding = Encoding.UTF8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
encoding = Encoding.GetEncoding(response.CharacterSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 提取网页Byte
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private byte[] GetByte()
|
||||||
|
{
|
||||||
|
byte[] ResponseByte = null;
|
||||||
|
using (MemoryStream _stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
//GZIIP处理
|
||||||
|
if (response.ContentEncoding != null && response.ContentEncoding.Equals("gzip", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
//开始读取流并设置编码方式
|
||||||
|
new GZipStream(response.GetResponseStream(), CompressionMode.Decompress).CopyTo(_stream, 1024);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//开始读取流并设置编码方式
|
||||||
|
response.GetResponseStream().CopyTo(_stream, 1024);
|
||||||
|
}
|
||||||
|
//获取Byte
|
||||||
|
ResponseByte = _stream.ToArray();
|
||||||
|
}
|
||||||
|
return ResponseByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region SetRequest
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为请求准备参数
|
||||||
|
/// </summary>
|
||||||
|
///<param name="item">参数列表</param>
|
||||||
|
private void SetRequest(HttpItem item)
|
||||||
|
{
|
||||||
|
|
||||||
|
// 验证证书
|
||||||
|
SetCer(item);
|
||||||
|
if (item.IPEndPoint != null)
|
||||||
|
{
|
||||||
|
_IPEndPoint = item.IPEndPoint;
|
||||||
|
//设置本地的出口ip和端口
|
||||||
|
request.ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint(BindIPEndPointCallback);
|
||||||
|
}
|
||||||
|
//设置Header参数
|
||||||
|
if (item.Header != null && item.Header.Count > 0) foreach (string key in item.Header.AllKeys)
|
||||||
|
{
|
||||||
|
request.Headers.Add(key, item.Header[key]);
|
||||||
|
}
|
||||||
|
// 设置代理
|
||||||
|
SetProxy(item);
|
||||||
|
if (item.ProtocolVersion != null) request.ProtocolVersion = item.ProtocolVersion;
|
||||||
|
request.ServicePoint.Expect100Continue = item.Expect100Continue;
|
||||||
|
//请求方式Get或者Post
|
||||||
|
request.Method = item.Method;
|
||||||
|
request.Timeout = item.Timeout;
|
||||||
|
request.KeepAlive = item.KeepAlive;
|
||||||
|
request.ReadWriteTimeout = item.ReadWriteTimeout;
|
||||||
|
if (!string.IsNullOrWhiteSpace(item.Host))
|
||||||
|
{
|
||||||
|
request.Host = item.Host;
|
||||||
|
}
|
||||||
|
if (item.IfModifiedSince != null) request.IfModifiedSince = Convert.ToDateTime(item.IfModifiedSince);
|
||||||
|
if (item.Date!=null)
|
||||||
|
{
|
||||||
|
request.Date = Convert.ToDateTime(item.Date);
|
||||||
|
}
|
||||||
|
//Accept
|
||||||
|
request.Accept = item.Accept;
|
||||||
|
//ContentType返回类型
|
||||||
|
request.ContentType = item.ContentType;
|
||||||
|
//UserAgent客户端的访问类型,包括浏览器版本和操作系统信息
|
||||||
|
request.UserAgent = item.UserAgent;
|
||||||
|
// 编码
|
||||||
|
encoding = item.Encoding;
|
||||||
|
//设置安全凭证
|
||||||
|
request.Credentials = item.ICredentials;
|
||||||
|
//设置Cookie
|
||||||
|
SetCookie(item);
|
||||||
|
//来源地址
|
||||||
|
request.Referer = item.Referer;
|
||||||
|
//是否执行跳转功能
|
||||||
|
request.AllowAutoRedirect = item.Allowautoredirect;
|
||||||
|
if (item.MaximumAutomaticRedirections > 0)
|
||||||
|
{
|
||||||
|
request.MaximumAutomaticRedirections = item.MaximumAutomaticRedirections;
|
||||||
|
}
|
||||||
|
//设置Post数据
|
||||||
|
SetPostData(item);
|
||||||
|
//设置最大连接
|
||||||
|
if (item.Connectionlimit > 0) request.ServicePoint.ConnectionLimit = item.Connectionlimit;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置证书
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item"></param>
|
||||||
|
private void SetCer(HttpItem item)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(item.CerPath))
|
||||||
|
{
|
||||||
|
//这一句一定要写在创建连接的前面。使用回调的方法进行证书验证。
|
||||||
|
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
|
||||||
|
//初始化对像,并设置请求的URL地址
|
||||||
|
request = (HttpWebRequest)WebRequest.Create(item.URL);
|
||||||
|
SetCerList(item);
|
||||||
|
//将证书添加到请求里
|
||||||
|
request.ClientCertificates.Add(new X509Certificate(item.CerPath));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//初始化对像,并设置请求的URL地址
|
||||||
|
request = (HttpWebRequest)WebRequest.Create(item.URL);
|
||||||
|
SetCerList(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置多个证书
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item"></param>
|
||||||
|
private void SetCerList(HttpItem item)
|
||||||
|
{
|
||||||
|
if (item.ClentCertificates != null && item.ClentCertificates.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (X509Certificate c in item.ClentCertificates)
|
||||||
|
{
|
||||||
|
request.ClientCertificates.Add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置Cookie
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">Http参数</param>
|
||||||
|
private void SetCookie(HttpItem item)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(item.Cookie)) request.Headers[HttpRequestHeader.Cookie] = item.Cookie;
|
||||||
|
//设置CookieCollection
|
||||||
|
if (item.ResultCookieType == ResultCookieType.CookieCollection)
|
||||||
|
{
|
||||||
|
request.CookieContainer = new CookieContainer();
|
||||||
|
if (item.CookieCollection != null && item.CookieCollection.Count > 0)
|
||||||
|
{
|
||||||
|
//默认为20个,如果超出需要增加长度
|
||||||
|
if (item.CookieCollection.Count > 20)
|
||||||
|
{
|
||||||
|
request.CookieContainer.PerDomainCapacity = item.CookieCollection.Count;
|
||||||
|
}
|
||||||
|
request.CookieContainer.Add(item.CookieCollection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置Post数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">Http参数</param>
|
||||||
|
private void SetPostData(HttpItem item)
|
||||||
|
{
|
||||||
|
//验证在得到结果时是否有传入数据
|
||||||
|
if (!request.Method.Trim().ToLower().Contains("get"))
|
||||||
|
{
|
||||||
|
if (item.PostEncoding != null)
|
||||||
|
{
|
||||||
|
postencoding = item.PostEncoding;
|
||||||
|
}
|
||||||
|
byte[] buffer = null;
|
||||||
|
//写入Byte类型
|
||||||
|
if (item.PostDataType == PostDataType.Byte && item.PostdataByte != null && item.PostdataByte.Length > 0)
|
||||||
|
{
|
||||||
|
//验证在得到结果时是否有传入数据
|
||||||
|
buffer = item.PostdataByte;
|
||||||
|
}//写入文件
|
||||||
|
else if (item.PostDataType == PostDataType.FilePath && !string.IsNullOrWhiteSpace(item.Postdata))
|
||||||
|
{
|
||||||
|
StreamReader r = new StreamReader(item.Postdata, postencoding);
|
||||||
|
buffer = postencoding.GetBytes(r.ReadToEnd());
|
||||||
|
r.Close();
|
||||||
|
} //写入字符串
|
||||||
|
else if (!string.IsNullOrWhiteSpace(item.Postdata))
|
||||||
|
{
|
||||||
|
buffer = postencoding.GetBytes(item.Postdata);
|
||||||
|
}
|
||||||
|
if (buffer != null)
|
||||||
|
{
|
||||||
|
request.ContentLength = buffer.Length;
|
||||||
|
request.GetRequestStream().Write(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request.ContentLength = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置代理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">参数对象</param>
|
||||||
|
private void SetProxy(HttpItem item)
|
||||||
|
{
|
||||||
|
bool isIeProxy = false;
|
||||||
|
if (!string.IsNullOrWhiteSpace(item.ProxyIp))
|
||||||
|
{
|
||||||
|
isIeProxy = item.ProxyIp.ToLower().Contains("ieproxy");
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(item.ProxyIp) && !isIeProxy)
|
||||||
|
{
|
||||||
|
//设置代理服务器
|
||||||
|
if (item.ProxyIp.Contains(":"))
|
||||||
|
{
|
||||||
|
string[] plist = item.ProxyIp.Split(':');
|
||||||
|
WebProxy myProxy = new WebProxy(plist[0].Trim(), Convert.ToInt32(plist[1].Trim()));
|
||||||
|
//建议连接
|
||||||
|
myProxy.Credentials = new NetworkCredential(item.ProxyUserName, item.ProxyPwd);
|
||||||
|
//给当前请求对象
|
||||||
|
request.Proxy = myProxy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WebProxy myProxy = new WebProxy(item.ProxyIp, false);
|
||||||
|
//建议连接
|
||||||
|
myProxy.Credentials = new NetworkCredential(item.ProxyUserName, item.ProxyPwd);
|
||||||
|
//给当前请求对象
|
||||||
|
request.Proxy = myProxy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isIeProxy)
|
||||||
|
{
|
||||||
|
//设置为IE代理
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request.Proxy = item.WebProxy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region private main
|
||||||
|
/// <summary>
|
||||||
|
/// 回调验证证书问题
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">流对象</param>
|
||||||
|
/// <param name="certificate">证书</param>
|
||||||
|
/// <param name="chain">X509Chain</param>
|
||||||
|
/// <param name="errors">SslPolicyErrors</param>
|
||||||
|
/// <returns>bool</returns>
|
||||||
|
private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { return true; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 通过设置这个属性,可以在发出连接的时候绑定客户端发出连接所使用的IP地址。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="servicePoint"></param>
|
||||||
|
/// <param name="remoteEndPoint"></param>
|
||||||
|
/// <param name="retryCount"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)
|
||||||
|
{
|
||||||
|
return _IPEndPoint;//端口号
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#region public calss
|
||||||
|
/// <summary>
|
||||||
|
/// Http请求参考类
|
||||||
|
/// </summary>
|
||||||
|
public class HttpItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 请求URL必须填写
|
||||||
|
/// </summary>
|
||||||
|
public string URL { get; set; }
|
||||||
|
string _Method = "GET";
|
||||||
|
/// <summary>
|
||||||
|
/// 请求方式默认为GET方式,当为POST方式时必须设置Postdata的值
|
||||||
|
/// </summary>
|
||||||
|
public string Method
|
||||||
|
{
|
||||||
|
get { return _Method; }
|
||||||
|
set { _Method = value; }
|
||||||
|
}
|
||||||
|
int _Timeout = 100000;
|
||||||
|
/// <summary>
|
||||||
|
/// 默认请求超时时间
|
||||||
|
/// </summary>
|
||||||
|
public int Timeout
|
||||||
|
{
|
||||||
|
get { return _Timeout; }
|
||||||
|
set { _Timeout = value; }
|
||||||
|
}
|
||||||
|
int _ReadWriteTimeout = 30000;
|
||||||
|
/// <summary>
|
||||||
|
/// 默认写入Post数据超时间
|
||||||
|
/// </summary>
|
||||||
|
public int ReadWriteTimeout
|
||||||
|
{
|
||||||
|
get { return _ReadWriteTimeout; }
|
||||||
|
set { _ReadWriteTimeout = value; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置Host的标头信息
|
||||||
|
/// </summary>
|
||||||
|
public string Host { get; set; }
|
||||||
|
Boolean _KeepAlive = true;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置一个值,该值指示是否与 Internet 资源建立持久性连接默认为true。
|
||||||
|
/// </summary>
|
||||||
|
public Boolean KeepAlive
|
||||||
|
{
|
||||||
|
get { return _KeepAlive; }
|
||||||
|
set { _KeepAlive = value; }
|
||||||
|
}
|
||||||
|
string _Accept = "text/html, application/xhtml+xml, */*";
|
||||||
|
/// <summary>
|
||||||
|
/// 请求标头值 默认为text/html, application/xhtml+xml, */*
|
||||||
|
/// </summary>
|
||||||
|
public string Accept
|
||||||
|
{
|
||||||
|
get { return _Accept; }
|
||||||
|
set { _Accept = value; }
|
||||||
|
}
|
||||||
|
string _ContentType = "text/html";
|
||||||
|
/// <summary>
|
||||||
|
/// 请求返回类型默认 text/html
|
||||||
|
/// </summary>
|
||||||
|
public string ContentType
|
||||||
|
{
|
||||||
|
get { return _ContentType; }
|
||||||
|
set { _ContentType = value; }
|
||||||
|
}
|
||||||
|
string _UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)";
|
||||||
|
/// <summary>
|
||||||
|
/// 客户端访问信息默认Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
|
||||||
|
/// </summary>
|
||||||
|
public string UserAgent
|
||||||
|
{
|
||||||
|
get { return _UserAgent; }
|
||||||
|
set { _UserAgent = value; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 返回数据编码默认为NUll,可以自动识别,一般为utf-8,gbk,gb2312
|
||||||
|
/// </summary>
|
||||||
|
public Encoding Encoding { get; set; }
|
||||||
|
private PostDataType _PostDataType = PostDataType.String;
|
||||||
|
/// <summary>
|
||||||
|
/// Post的数据类型
|
||||||
|
/// </summary>
|
||||||
|
public PostDataType PostDataType
|
||||||
|
{
|
||||||
|
get { return _PostDataType; }
|
||||||
|
set { _PostDataType = value; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Post请求时要发送的字符串Post数据
|
||||||
|
/// </summary>
|
||||||
|
public string Postdata { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Post请求时要发送的Byte类型的Post数据
|
||||||
|
/// </summary>
|
||||||
|
public byte[] PostdataByte { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Cookie对象集合
|
||||||
|
/// </summary>
|
||||||
|
public CookieCollection CookieCollection { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 请求时的Cookie
|
||||||
|
/// </summary>
|
||||||
|
public string Cookie { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 来源地址,上次访问地址
|
||||||
|
/// </summary>
|
||||||
|
public string Referer { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 证书绝对路径
|
||||||
|
/// </summary>
|
||||||
|
public string CerPath { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 设置代理对象,不想使用IE默认配置就设置为Null,而且不要设置ProxyIp
|
||||||
|
/// </summary>
|
||||||
|
public WebProxy WebProxy { get; set; }
|
||||||
|
private Boolean isToLower = false;
|
||||||
|
/// <summary>
|
||||||
|
/// 是否设置为全文小写,默认为不转化
|
||||||
|
/// </summary>
|
||||||
|
public Boolean IsToLower
|
||||||
|
{
|
||||||
|
get { return isToLower; }
|
||||||
|
set { isToLower = value; }
|
||||||
|
}
|
||||||
|
private DateTime? _Date = null;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置要在 HTTP 请求中使用的 Date HTTP 标头值。默认不填写
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? Date
|
||||||
|
{
|
||||||
|
get { return _Date; }
|
||||||
|
set { _Date = value; }
|
||||||
|
}
|
||||||
|
private Boolean allowautoredirect = false;
|
||||||
|
/// <summary>
|
||||||
|
/// 支持跳转页面,查询结果将是跳转后的页面,默认是不跳转
|
||||||
|
/// </summary>
|
||||||
|
public Boolean Allowautoredirect
|
||||||
|
{
|
||||||
|
get { return allowautoredirect; }
|
||||||
|
set { allowautoredirect = value; }
|
||||||
|
}
|
||||||
|
private int connectionlimit = 1024;
|
||||||
|
/// <summary>
|
||||||
|
/// 最大连接数
|
||||||
|
/// </summary>
|
||||||
|
public int Connectionlimit
|
||||||
|
{
|
||||||
|
get { return connectionlimit; }
|
||||||
|
set { connectionlimit = value; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 代理Proxy 服务器用户名
|
||||||
|
/// </summary>
|
||||||
|
public string ProxyUserName { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 代理 服务器密码
|
||||||
|
/// </summary>
|
||||||
|
public string ProxyPwd { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 代理 服务IP,如果要使用IE代理就设置为ieproxy
|
||||||
|
/// </summary>
|
||||||
|
public string ProxyIp { get; set; }
|
||||||
|
private ResultType resulttype = ResultType.String;
|
||||||
|
/// <summary>
|
||||||
|
/// 设置返回类型String和Byte
|
||||||
|
/// </summary>
|
||||||
|
public ResultType ResultType
|
||||||
|
{
|
||||||
|
get { return resulttype; }
|
||||||
|
set { resulttype = value; }
|
||||||
|
}
|
||||||
|
private WebHeaderCollection header = new WebHeaderCollection();
|
||||||
|
/// <summary>
|
||||||
|
/// header对象
|
||||||
|
/// </summary>
|
||||||
|
public WebHeaderCollection Header
|
||||||
|
{
|
||||||
|
get { return header; }
|
||||||
|
set { header = value; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
// 获取或设置用于请求的 HTTP 版本。返回结果:用于请求的 HTTP 版本。默认为 System.Net.HttpVersion.Version11。
|
||||||
|
/// </summary>
|
||||||
|
public Version ProtocolVersion { get; set; }
|
||||||
|
private Boolean _expect100continue = false;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置一个 System.Boolean 值,该值确定是否使用 100-Continue 行为。如果 POST 请求需要 100-Continue 响应,则为 true;否则为 false。默认值为 true。
|
||||||
|
/// </summary>
|
||||||
|
public Boolean Expect100Continue
|
||||||
|
{
|
||||||
|
get { return _expect100continue; }
|
||||||
|
set { _expect100continue = value; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置509证书集合
|
||||||
|
/// </summary>
|
||||||
|
public X509CertificateCollection ClentCertificates { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 设置或获取Post参数编码,默认的为Default编码
|
||||||
|
/// </summary>
|
||||||
|
public Encoding PostEncoding { get; set; }
|
||||||
|
private ResultCookieType _ResultCookieType = ResultCookieType.String;
|
||||||
|
/// <summary>
|
||||||
|
/// Cookie返回类型,默认的是只返回字符串类型
|
||||||
|
/// </summary>
|
||||||
|
public ResultCookieType ResultCookieType
|
||||||
|
{
|
||||||
|
get { return _ResultCookieType; }
|
||||||
|
set { _ResultCookieType = value; }
|
||||||
|
}
|
||||||
|
private ICredentials _ICredentials = CredentialCache.DefaultCredentials;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置请求的身份验证信息。
|
||||||
|
/// </summary>
|
||||||
|
public ICredentials ICredentials
|
||||||
|
{
|
||||||
|
get { return _ICredentials; }
|
||||||
|
set { _ICredentials = value; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置请求将跟随的重定向的最大数目
|
||||||
|
/// </summary>
|
||||||
|
public int MaximumAutomaticRedirections { get; set; }
|
||||||
|
private DateTime? _IfModifiedSince = null;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取和设置IfModifiedSince,默认为当前日期和时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? IfModifiedSince
|
||||||
|
{
|
||||||
|
get { return _IfModifiedSince; }
|
||||||
|
set { _IfModifiedSince = value; }
|
||||||
|
}
|
||||||
|
#region ip-port
|
||||||
|
private IPEndPoint _IPEndPoint = null;
|
||||||
|
/// <summary>
|
||||||
|
/// 设置本地的出口ip和端口
|
||||||
|
/// </summary>]
|
||||||
|
/// <example>
|
||||||
|
///item.IPEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.1"),80);
|
||||||
|
/// </example>
|
||||||
|
public IPEndPoint IPEndPoint
|
||||||
|
{
|
||||||
|
get { return _IPEndPoint; }
|
||||||
|
set { _IPEndPoint = value; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private bool _isReset = false;
|
||||||
|
/// <summary>
|
||||||
|
/// 是否重置request,response的值,默认不重置,当设置为True时request,response将被设置为Null
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReset
|
||||||
|
{
|
||||||
|
get { return _isReset; }
|
||||||
|
set { _isReset = value; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Http返回参数类
|
||||||
|
/// </summary>
|
||||||
|
public class HttpResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Http请求返回的Cookie
|
||||||
|
/// </summary>
|
||||||
|
public string Cookie { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Cookie对象集合
|
||||||
|
/// </summary>
|
||||||
|
public CookieCollection CookieCollection { get; set; }
|
||||||
|
private string _html = string.Empty;
|
||||||
|
/// <summary>
|
||||||
|
/// 返回的String类型数据 只有ResultType.String时才返回数据,其它情况为空
|
||||||
|
/// </summary>
|
||||||
|
public string Html
|
||||||
|
{
|
||||||
|
get { return _html; }
|
||||||
|
set { _html = value; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 返回的Byte数组 只有ResultType.Byte时才返回数据,其它情况为空
|
||||||
|
/// </summary>
|
||||||
|
public byte[] ResultByte { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// header对象
|
||||||
|
/// </summary>
|
||||||
|
public WebHeaderCollection Header { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 返回状态说明
|
||||||
|
/// </summary>
|
||||||
|
public string StatusDescription { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 返回状态码,默认为OK
|
||||||
|
/// </summary>
|
||||||
|
public HttpStatusCode StatusCode { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 最后访问的URl
|
||||||
|
/// </summary>
|
||||||
|
public string ResponseUri { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 获取重定向的URl
|
||||||
|
/// </summary>
|
||||||
|
public string RedirectUrl
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Header != null && Header.Count > 0)
|
||||||
|
{
|
||||||
|
if (Header.AllKeys.Any(k => k.ToLower().Contains("location")))
|
||||||
|
{
|
||||||
|
string baseurl = Header["location"].ToString().Trim();
|
||||||
|
string locationurl = baseurl.ToLower();
|
||||||
|
if (!string.IsNullOrWhiteSpace(locationurl))
|
||||||
|
{
|
||||||
|
bool b = locationurl.StartsWith("http://") || locationurl.StartsWith("https://");
|
||||||
|
if (!b)
|
||||||
|
{
|
||||||
|
baseurl = new Uri(new Uri(ResponseUri), baseurl).AbsoluteUri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return baseurl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 返回类型
|
||||||
|
/// </summary>
|
||||||
|
public enum ResultType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 表示只返回字符串 只有Html有数据
|
||||||
|
/// </summary>
|
||||||
|
String,
|
||||||
|
/// <summary>
|
||||||
|
/// 表示返回字符串和字节流 ResultByte和Html都有数据返回
|
||||||
|
/// </summary>
|
||||||
|
Byte
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Post的数据格式默认为string
|
||||||
|
/// </summary>
|
||||||
|
public enum PostDataType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 字符串类型,这时编码Encoding可不设置
|
||||||
|
/// </summary>
|
||||||
|
String,
|
||||||
|
/// <summary>
|
||||||
|
/// Byte类型,需要设置PostdataByte参数的值编码Encoding可设置为空
|
||||||
|
/// </summary>
|
||||||
|
Byte,
|
||||||
|
/// <summary>
|
||||||
|
/// 传文件,Postdata必须设置为文件的绝对路径,必须设置Encoding的值
|
||||||
|
/// </summary>
|
||||||
|
FilePath
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Cookie返回类型
|
||||||
|
/// </summary>
|
||||||
|
public enum ResultCookieType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 只返回字符串类型的Cookie
|
||||||
|
/// </summary>
|
||||||
|
String,
|
||||||
|
/// <summary>
|
||||||
|
/// CookieCollection格式的Cookie集合同时也返回String类型的cookie
|
||||||
|
/// </summary>
|
||||||
|
CookieCollection
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
16
CMS/JXCMS.CMS.Movie/Views/Default/Home/Test.cshtml
Normal file
16
CMS/JXCMS.CMS.Movie/Views/Default/Home/Test.cshtml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
@{
|
||||||
|
Layout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
@Html.Action("Index")
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -110,12 +110,9 @@ namespace JXCMS.Core.Db
|
|||||||
jsonObject.Add("Db", JObject.FromObject(dbConfig));
|
jsonObject.Add("Db", JObject.FromObject(dbConfig));
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var writer = new StreamWriter(filePath))
|
using var writer = new StreamWriter(filePath);
|
||||||
using (JsonTextWriter jsonwriter = new JsonTextWriter(writer))
|
using JsonTextWriter jsonWriter = new JsonTextWriter(writer) {Formatting = Formatting.Indented};
|
||||||
{
|
jsonObject.WriteTo(jsonWriter);
|
||||||
jsonwriter.Formatting = Formatting.Indented;
|
|
||||||
jsonObject.WriteTo(jsonwriter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
99
Core/JXCMS.Core/Extensions/HtmlHelperViewExtensions.cs
Normal file
99
Core/JXCMS.Core/Extensions/HtmlHelperViewExtensions.cs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
using Microsoft.AspNetCore.Html;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Rendering
|
||||||
|
{
|
||||||
|
public static class HtmlHelperViewExtensions
|
||||||
|
{
|
||||||
|
public static IHtmlContent Action(this IHtmlHelper helper, string action, object parameters = null)
|
||||||
|
{
|
||||||
|
var controller = (string)helper.ViewContext.RouteData.Values["controller"];
|
||||||
|
|
||||||
|
return Action(helper, action, controller, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, object parameters = null)
|
||||||
|
{
|
||||||
|
var area = (string)helper.ViewContext.RouteData.Values["area"];
|
||||||
|
|
||||||
|
return Action(helper, action, controller, area, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
|
||||||
|
{
|
||||||
|
if (action == null)
|
||||||
|
throw new ArgumentNullException("action");
|
||||||
|
|
||||||
|
if (controller == null)
|
||||||
|
throw new ArgumentNullException("controller");
|
||||||
|
|
||||||
|
|
||||||
|
var task = RenderActionAsync(helper, action, controller, area, parameters);
|
||||||
|
|
||||||
|
return task.Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<IHtmlContent> RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
|
||||||
|
{
|
||||||
|
// fetching required services for invocation
|
||||||
|
var serviceProvider = helper.ViewContext.HttpContext.RequestServices;
|
||||||
|
var actionContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IActionContextAccessor>();
|
||||||
|
var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IHttpContextAccessor>();
|
||||||
|
var actionSelector = serviceProvider.GetRequiredService<IActionSelector>();
|
||||||
|
|
||||||
|
// creating new action invocation context
|
||||||
|
var routeData = new RouteData();
|
||||||
|
foreach (var router in helper.ViewContext.RouteData.Routers)
|
||||||
|
{
|
||||||
|
routeData.PushState(router, null, null);
|
||||||
|
}
|
||||||
|
routeData.PushState(null, new RouteValueDictionary(new { controller = controller, action = action, area = area }), null);
|
||||||
|
routeData.PushState(null, new RouteValueDictionary(parameters ?? new { }), null);
|
||||||
|
|
||||||
|
//get the actiondescriptor
|
||||||
|
RouteContext routeContext = new RouteContext(helper.ViewContext.HttpContext) { RouteData = routeData };
|
||||||
|
var candidates = actionSelector.SelectCandidates(routeContext);
|
||||||
|
var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates);
|
||||||
|
|
||||||
|
var originalActionContext = actionContextAccessor.ActionContext;
|
||||||
|
var originalhttpContext = httpContextAccessor.HttpContext;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var newHttpContext = serviceProvider.GetRequiredService<IHttpContextFactory>().Create(helper.ViewContext.HttpContext.Features);
|
||||||
|
if (newHttpContext.Items.ContainsKey(typeof(IUrlHelper)))
|
||||||
|
{
|
||||||
|
newHttpContext.Items.Remove(typeof(IUrlHelper));
|
||||||
|
}
|
||||||
|
newHttpContext.Response.Body = new MemoryStream();
|
||||||
|
var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor);
|
||||||
|
actionContextAccessor.ActionContext = actionContext;
|
||||||
|
var invoker = serviceProvider.GetRequiredService<IActionInvokerFactory>().CreateInvoker(actionContext);
|
||||||
|
await invoker.InvokeAsync();
|
||||||
|
newHttpContext.Response.Body.Position = 0;
|
||||||
|
using (var reader = new StreamReader(newHttpContext.Response.Body))
|
||||||
|
{
|
||||||
|
return new HtmlString(reader.ReadToEnd());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return new HtmlString(ex.Message);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
actionContextAccessor.ActionContext = originalActionContext;
|
||||||
|
httpContextAccessor.HttpContext = originalhttpContext;
|
||||||
|
if (helper.ViewContext.HttpContext.Items.ContainsKey(typeof(IUrlHelper)))
|
||||||
|
{
|
||||||
|
helper.ViewContext.HttpContext.Items.Remove(typeof(IUrlHelper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
namespace JXCMS.Core.Extensions
|
using System.Text;
|
||||||
|
|
||||||
|
namespace JXCMS.Core.Extensions
|
||||||
{
|
{
|
||||||
public static class StringExtension
|
public static class StringExtension
|
||||||
{
|
{
|
||||||
@ -6,5 +8,18 @@
|
|||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(str);
|
return string.IsNullOrEmpty(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string InsertMultipleString(this string str, string insertStr, int count)
|
||||||
|
{
|
||||||
|
StringBuilder returnValue = new StringBuilder();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
returnValue.Append(insertStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
returnValue.Append(str);
|
||||||
|
return returnValue.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
@ -11,12 +11,12 @@
|
|||||||
<PackageReference Include="BouncyCastle" Version="1.8.5" />
|
<PackageReference Include="BouncyCastle" Version="1.8.5" />
|
||||||
<PackageReference Include="DeviceDetector.NET" Version="4.1.0" />
|
<PackageReference Include="DeviceDetector.NET" Version="4.1.0" />
|
||||||
<PackageReference Include="DotnetSpider" Version="4.0.7" />
|
<PackageReference Include="DotnetSpider" Version="4.0.7" />
|
||||||
<PackageReference Include="FreeSql.Extensions.BaseEntity" Version="0.11.20" />
|
<PackageReference Include="FreeSql.Extensions.BaseEntity" Version="1.2.0-preview1" />
|
||||||
<PackageReference Include="FreeSql.Provider.MySql" Version="0.11.20" />
|
<PackageReference Include="FreeSql.Provider.MySql" Version="1.2.0-preview1" />
|
||||||
<PackageReference Include="FreeSql.Provider.Oracle" Version="0.11.20" />
|
<PackageReference Include="FreeSql.Provider.Oracle" Version="1.2.0-preview1" />
|
||||||
<PackageReference Include="FreeSql.Provider.PostgreSQL" Version="0.11.20" />
|
<PackageReference Include="FreeSql.Provider.PostgreSQL" Version="1.2.0-preview1" />
|
||||||
<PackageReference Include="FreeSql.Provider.Sqlite" Version="0.11.20" />
|
<PackageReference Include="FreeSql.Provider.Sqlite" Version="1.2.0-preview1" />
|
||||||
<PackageReference Include="FreeSql.Provider.SqlServer" Version="0.11.20" />
|
<PackageReference Include="FreeSql.Provider.SqlServer" Version="1.2.0-preview1" />
|
||||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="0.3.1" />
|
<PackageReference Include="McMaster.NETCore.Plugins" Version="0.3.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="Quartz" Version="3.0.7" />
|
<PackageReference Include="Quartz" Version="3.0.7" />
|
||||||
|
@ -53,5 +53,41 @@ namespace JXCMS.Core.TimingTask
|
|||||||
return await _scheduler.DeleteJobs(jobKeys);
|
return await _scheduler.DeleteJobs(jobKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Corn表达式的运行时间
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cron">表达式</param>
|
||||||
|
/// <param name="times">计算次数</param>
|
||||||
|
/// <param name="startTime">开始时间</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetCronSchedule(String cron, int times, DateTimeOffset startTime)
|
||||||
|
{
|
||||||
|
String timeSchedule = "";
|
||||||
|
if (!CronExpression.IsValidExpression(cron))
|
||||||
|
{
|
||||||
|
return "Cron表达式不合法!";
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ITrigger trigger1 = TriggerBuilder.Create()
|
||||||
|
|
||||||
|
.WithCronSchedule(cron)
|
||||||
|
.StartNow()
|
||||||
|
.Build();
|
||||||
|
for (int i = 0; i < times; i++)
|
||||||
|
{
|
||||||
|
DateTimeOffset? s = trigger1.GetFireTimeAfter(startTime);
|
||||||
|
DateTime? time = s?.LocalDateTime;
|
||||||
|
timeSchedule = time?.ToString("F");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
timeSchedule = "未知时间";
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeSchedule;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
15
Core/JXCMS.Core/Utils/ConfigHelper.cs
Normal file
15
Core/JXCMS.Core/Utils/ConfigHelper.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace JXCMS.Core.Utils
|
||||||
|
{
|
||||||
|
public class ConfigHelper
|
||||||
|
{
|
||||||
|
public static IConfiguration Configs { get; set; }
|
||||||
|
|
||||||
|
public static string GetValue(string key)
|
||||||
|
{
|
||||||
|
var res = Configs.GetSection(key).Value;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user