diff --git a/README.md b/README.md
index 3912ff6f..2537318f 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
Yi框架
+
Yi框架
一套以用户体验出发的.Net8 Web开源框架
支持Abp.vNext 版本原生版本、Furion版本,前端后台接入Ruoyi Vue3.0
集大成者,终究轮子
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs
index 8afd6878..dc7c5b99 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs
@@ -1,7 +1,11 @@
-using System.Diagnostics;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Text;
+using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
+using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Volo.Abp.AspNetCore.Mvc;
@@ -75,12 +79,59 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
{
[scheme] = new string[0]
});
+
+
+ options.SchemaFilter();
}
);
-
+
return services;
}
}
+
+
+ ///
+ /// Swagger文档枚举字段显示枚举属性和枚举值,以及枚举描述
+ ///
+ public class EnumSchemaFilter : ISchemaFilter
+ {
+ ///
+ /// 实现接口
+ ///
+ ///
+ ///
+
+ public void Apply(OpenApiSchema model, SchemaFilterContext context)
+ {
+ if (context.Type.IsEnum)
+ {
+ model.Enum.Clear();
+ model.Type = "string";
+ model.Format = null;
+
+
+ StringBuilder stringBuilder = new StringBuilder();
+ Enum.GetNames(context.Type)
+ .ToList()
+ .ForEach(name =>
+ {
+ Enum e = (Enum)Enum.Parse(context.Type, name);
+ var descrptionOrNull = GetEnumDescription(e);
+ model.Enum.Add(new OpenApiString(name));
+ stringBuilder.Append($"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】
");
+ });
+ model.Description= stringBuilder.ToString();
+ }
+ }
+
+ private static string? GetEnumDescription(Enum value)
+ {
+ var fieldInfo = value.GetType().GetField(value.ToString());
+ var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
+ return attributes.Length > 0 ? attributes[0].Description : null;
+ }
+
+ }
}
diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application.Contracts/Dtos/Article/ArticleImprotDto.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application.Contracts/Dtos/Article/ArticleImprotDto.cs
index cb078ddd..98e8ba3d 100644
--- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application.Contracts/Dtos/Article/ArticleImprotDto.cs
+++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application.Contracts/Dtos/Article/ArticleImprotDto.cs
@@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
using Yi.Framework.Bbs.Domain.Shared.Enums;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Article
@@ -16,6 +17,8 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Article
[Required]
public Guid DiscussId { get; set; }
+ public Guid ArticleParentId { get; set; }= Guid.Empty;
+
public ArticleImportTypeEnum ImportType { get; set; } = ArticleImportTypeEnum.Defalut;
- }
+}
}
diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/ArticleService.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/ArticleService.cs
index 5c9c245b..57de3e2b 100644
--- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/ArticleService.cs
+++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/ArticleService.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Text;
using Mapster;
using Microsoft.AspNetCore.Authorization;
@@ -143,7 +144,7 @@ namespace Yi.Framework.Bbs.Application.Services
/// 导入文章
///
///
- public async Task PostImportAsync(ArticleImprotDto input, [FromForm] IFormFileCollection file)
+ public async Task PostImportAsync([FromQuery] ArticleImprotDto input, [FromForm][Required] IFormFileCollection file)
{
var fileObjs = new List();
if (file.Count > 0)
@@ -161,14 +162,18 @@ namespace Yi.Framework.Bbs.Application.Services
// 将字节转换成字符串
var content = Encoding.UTF8.GetString(bytes);
- fileObjs.Add(new FileObject() { FileName=item.FileName,Content=content});
+ fileObjs.Add(new FileObject() { FileName = item.FileName, Content = content });
}
}
}
}
}
+ else
+ {
+ throw new UserFriendlyException("未选择文件");
+ }
//使用简单工厂根据传入的类型进行判断
- await _forumManager.PostImportAsync(input.DiscussId, fileObjs, input.ImportType);
+ await _forumManager.PostImportAsync(input.DiscussId, input.ArticleParentId, fileObjs, input.ImportType);
}
diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain.Shared/Enums/ArticleImportTypeEnum.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain.Shared/Enums/ArticleImportTypeEnum.cs
index 6c6f2ac3..01686b76 100644
--- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain.Shared/Enums/ArticleImportTypeEnum.cs
+++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain.Shared/Enums/ArticleImportTypeEnum.cs
@@ -1,17 +1,16 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.ComponentModel;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
namespace Yi.Framework.Bbs.Domain.Shared.Enums
{
+ [JsonConverter(typeof(StringEnumConverter))]
public enum ArticleImportTypeEnum
{
- //默认导入方式
+ [Description("默认导入方式")]
Defalut,
- //vuePresss方式
+ [Description("vuePresss方式")]
VuePress
}
}
diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ArticleImport/AbstractArticleImport.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ArticleImport/AbstractArticleImport.cs
new file mode 100644
index 00000000..c39b5dec
--- /dev/null
+++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ArticleImport/AbstractArticleImport.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Yi.Framework.Bbs.Domain.Entities;
+using Yi.Framework.Bbs.Domain.Shared.Model;
+
+namespace Yi.Framework.Bbs.Domain.Managers.ArticleImport
+{
+ public abstract class AbstractArticleImport
+ {
+ public virtual List Import(Guid discussId,Guid articleParentId, List fileObjs)
+ {
+ var articles = Convert(fileObjs);
+ articles.ForEach(article =>
+ {
+ article.DiscussId = discussId;
+ article.ParentId = articleParentId;
+ });
+ return articles;
+ }
+ public abstract List Convert(List fileObjs);
+ }
+}
diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ArticleImport/DefaultArticleImport.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ArticleImport/DefaultArticleImport.cs
new file mode 100644
index 00000000..8ca58332
--- /dev/null
+++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ArticleImport/DefaultArticleImport.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Yi.Framework.Bbs.Domain.Entities;
+using Yi.Framework.Bbs.Domain.Shared.Model;
+
+namespace Yi.Framework.Bbs.Domain.Managers.ArticleImport
+{
+ internal class DefaultArticleImport : AbstractArticleImport
+ {
+ public override List Convert(List fileObjs)
+ {
+ return fileObjs.OrderBy(x => x.FileName).Select(x => new ArticleEntity { Name = x.FileName, Content = x.Content }).ToList();
+ }
+ }
+}
diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ArticleImport/VuePressArticleImport.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ArticleImport/VuePressArticleImport.cs
new file mode 100644
index 00000000..6ebb0626
--- /dev/null
+++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ArticleImport/VuePressArticleImport.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Yi.Framework.Bbs.Domain.Entities;
+using Yi.Framework.Bbs.Domain.Shared.Model;
+
+namespace Yi.Framework.Bbs.Domain.Managers.ArticleImport
+{
+ internal class VuePressArticleImport : AbstractArticleImport
+ {
+ public override List Convert(List fileObjs)
+ {
+ //排序及处理目录名称
+ var fileNameHandler = fileObjs.OrderBy(x => x.FileName).Select(x =>
+ {
+ var f = new FileObject { Content = x.Content };
+
+ //除去数字
+ f.FileName = x.FileName.Split('.')[1];
+ return f;
+ });
+
+
+ //处理内容
+ var fileContentHandler= fileNameHandler.Select(x =>
+ {
+ var f = new FileObject { FileName = x.FileName };
+ var lines = x.Content.SplitToLines();
+
+ var num = 0;
+ var startIndex = 0;
+ for (int i = 0; i < lines.Length; i++)
+ {
+ if (lines[i] == "---")
+ {
+ num++;
+ if (num == 2)
+ {
+ startIndex = i;
+
+ break;
+ }
+
+ }
+
+ }
+ var linesRef = lines.ToList();
+
+ linesRef.RemoveRange(0, startIndex+1);
+ var result = string.Join(Environment.NewLine, linesRef);
+ f.Content = result;
+ return f;
+ });
+
+ var output = fileContentHandler.Select(x => new ArticleEntity() { Content = x.Content, Name = x.FileName }).ToList();
+
+ return output;
+ }
+ }
+}
diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ForumManager.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ForumManager.cs
index 43e82011..7ffd1225 100644
--- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ForumManager.cs
+++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/Managers/ForumManager.cs
@@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Domain.Services;
using Yi.Framework.Bbs.Domain.Entities;
+using Yi.Framework.Bbs.Domain.Managers.ArticleImport;
using Yi.Framework.Bbs.Domain.Shared.Enums;
using Yi.Framework.Bbs.Domain.Shared.Model;
using Yi.Framework.SqlSugarCore.Abstractions;
@@ -16,11 +17,13 @@ namespace Yi.Framework.Bbs.Domain.Managers
public readonly ISqlSugarRepository _discussRepository;
public readonly ISqlSugarRepository _plateEntityRepository;
public readonly ISqlSugarRepository _commentRepository;
- public ForumManager(ISqlSugarRepository discussRepository, ISqlSugarRepository plateEntityRepository, ISqlSugarRepository commentRepository)
+ public readonly ISqlSugarRepository _articleRepository;
+ public ForumManager(ISqlSugarRepository discussRepository, ISqlSugarRepository plateEntityRepository, ISqlSugarRepository commentRepository, ISqlSugarRepository articleRepository)
{
_discussRepository = discussRepository;
_plateEntityRepository = plateEntityRepository;
_commentRepository = commentRepository;
+ _articleRepository = articleRepository;
}
//主题是不能直接创建的,需要由领域服务统一创建
@@ -45,11 +48,30 @@ namespace Yi.Framework.Bbs.Domain.Managers
/// 导入文章
///
///
+ ///
///
///
///
- public async Task PostImportAsync(Guid discussId, List fileObjs, ArticleImportTypeEnum importType)
+ public async Task PostImportAsync(Guid discussId,Guid articleParentId, List fileObjs, ArticleImportTypeEnum importType)
{
+ AbstractArticleImport abstractArticleImport = default;
+ switch (importType)
+ {
+ case ArticleImportTypeEnum.Defalut:
+ abstractArticleImport = new DefaultArticleImport();
+
+ break;
+ case ArticleImportTypeEnum.VuePress:
+ abstractArticleImport = new VuePressArticleImport();
+ break;
+
+ default: abstractArticleImport = new DefaultArticleImport(); break;
+ }
+
+ var articleHandled = abstractArticleImport.Import(discussId, articleParentId, fileObjs);
+
+ //await _articleRepository.InsertManyAsync(articleHandled);
+
}
}
}
diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs
index 83675077..f6c9462c 100644
--- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs
+++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs
@@ -248,6 +248,17 @@ namespace Yi.Framework.Rbac.Application.Services
throw new UserFriendlyException("验证码错误");
}
+ private void ValidateUserName(RegisterDto input)
+ {
+ // 正则表达式,匹配只包含数字和字母的字符串
+ string pattern = @"^[a-zA-Z0-9]+$";
+
+ bool isMatch = Regex.IsMatch(input.UserName, pattern);
+ if (!isMatch)
+ {
+ throw new UserFriendlyException("用户名不能包含除【字母】与【数字】的其他字符");
+ }
+ }
///
/// 注册,需要验证码通过
@@ -276,6 +287,10 @@ namespace Yi.Framework.Rbac.Application.Services
{
throw new UserFriendlyException("密码需大于等于6位!");
}
+
+ //效验用户名
+ ValidateUserName(input);
+
//效验验证码,根据电话号码获取 value,比对验证码已经uuid
await ValidationPhoneCaptchaAsync(input);
@@ -283,7 +298,7 @@ namespace Yi.Framework.Rbac.Application.Services
//输入的用户名与电话号码都不能在数据库中存在
UserEntity user = new();
- var isExist = await _userRepository.IsAnyAsync(x =>x.UserName == input.UserName|| x.Phone == input.Phone);
+ var isExist = await _userRepository.IsAnyAsync(x => x.UserName == input.UserName || x.Phone == input.Phone);
if (isExist)
{
throw new UserFriendlyException("用户已存在,注册失败");
diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
index 83fdecfb..13dc515b 100644
--- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
+++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
@@ -1,9 +1,10 @@
using System.Text;
+using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Authentication.JwtBearer;
-using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
+using Newtonsoft.Json.Converters;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc;
@@ -65,6 +66,7 @@ namespace Yi.Abp.Web
service.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
+ options.SerializerSettings.Converters.Add(new StringEnumConverter());
});
Configure(options =>
diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/wwwroot/logo.png b/Yi.Abp.Net8/src/Yi.Abp.Web/wwwroot/logo.png
new file mode 100644
index 00000000..226b005a
Binary files /dev/null and b/Yi.Abp.Net8/src/Yi.Abp.Web/wwwroot/logo.png differ
diff --git a/readme/1.png b/readme/1.png
index 476268b4..901b0c1d 100644
Binary files a/readme/1.png and b/readme/1.png differ
diff --git a/readme/1696760969217.jpg b/readme/1696760969217.jpg
index fad52ebe..ebef5032 100644
Binary files a/readme/1696760969217.jpg and b/readme/1696760969217.jpg differ
diff --git a/readme/1696761014270.jpg b/readme/1696761014270.jpg
index 29e28e93..21b9db40 100644
Binary files a/readme/1696761014270.jpg and b/readme/1696761014270.jpg differ
diff --git a/readme/2.png b/readme/2.png
index 12a7c7ad..e3885a42 100644
Binary files a/readme/2.png and b/readme/2.png differ
diff --git a/readme/3.png b/readme/3.png
index 85ac88f2..60733fb2 100644
Binary files a/readme/3.png and b/readme/3.png differ
diff --git a/readme/4.png b/readme/4.png
index d7ac081f..1213c1e7 100644
Binary files a/readme/4.png and b/readme/4.png differ
diff --git a/readme/5.png b/readme/5.png
index ea25ace3..bdfea170 100644
Binary files a/readme/5.png and b/readme/5.png differ
diff --git a/readme/6.png b/readme/6.png
index c67669d6..481b493d 100644
Binary files a/readme/6.png and b/readme/6.png differ
diff --git a/readme/7.png b/readme/7.png
index 984c1297..3084d2c6 100644
Binary files a/readme/7.png and b/readme/7.png differ
diff --git a/readme/8.png b/readme/8.png
index 10788d56..3e602e31 100644
Binary files a/readme/8.png and b/readme/8.png differ
diff --git a/readme/9.png b/readme/9.png
index bb6b1df9..37bb1f9d 100644
Binary files a/readme/9.png and b/readme/9.png differ