添加项目文件。

This commit is contained in:
小肥羊 2025-07-11 18:24:23 +08:00
parent 4ecf930230
commit 494251c76a
27 changed files with 1739 additions and 0 deletions

30
.dockerignore Normal file
View File

@ -0,0 +1,30 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**

31
Learn.Archives.API.sln Normal file
View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35312.102
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Learn.Archives.API", "Learn.Archives.API\Learn.Archives.API.csproj", "{A5B8EE1A-5049-40FE-8498-48DC66D3B549}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Learn.Archives.Core", "Learn.Archives.Core\Learn.Archives.Core.csproj", "{E7F191F2-A871-476F-8E12-CB542DAA2B82}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A5B8EE1A-5049-40FE-8498-48DC66D3B549}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5B8EE1A-5049-40FE-8498-48DC66D3B549}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5B8EE1A-5049-40FE-8498-48DC66D3B549}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5B8EE1A-5049-40FE-8498-48DC66D3B549}.Release|Any CPU.Build.0 = Release|Any CPU
{E7F191F2-A871-476F-8E12-CB542DAA2B82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7F191F2-A871-476F-8E12-CB542DAA2B82}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7F191F2-A871-476F-8E12-CB542DAA2B82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E7F191F2-A871-476F-8E12-CB542DAA2B82}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F40DADFE-A8CA-4AFB-9292-68E85076414B}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,29 @@
# 请参阅 https://aka.ms/customizecontainer 以了解如何自定义调试容器,以及 Visual Studio 如何使用此 Dockerfile 生成映像以更快地进行调试。
# 此阶段用于在快速模式(默认为调试配置)下从 VS 运行时
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080
# 此阶段用于生成服务项目
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Learn.Archives.API/Learn.Archives.API.csproj", "Learn.Archives.API/"]
RUN dotnet restore "./Learn.Archives.API/Learn.Archives.API.csproj"
COPY . .
WORKDIR "/src/Learn.Archives.API"
RUN dotnet build "./Learn.Archives.API.csproj" -c $BUILD_CONFIGURATION -o /app/build
# 此阶段用于发布要复制到最终阶段的服务项目
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Learn.Archives.API.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
# 此阶段在生产中使用,或在常规模式下从 VS 运行时使用(在不使用调试配置时为默认值)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Learn.Archives.API.dll"]

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.2-pre01" />
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Learn.Archives.Core\Learn.Archives.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,6 @@
@Learn.Archives.API_HostAddress = http://localhost:5199
GET {{Learn.Archives.API_HostAddress}}/weatherforecast/
Accept: application/json
###

View File

@ -0,0 +1,69 @@
using Learn.Archives.Core.Common;
using Microsoft.OpenApi.Models;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using Learn.Archives.Core.Common.Expand;
using Mapster;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddLogging(loggingBuilder =>
{
loggingBuilder.ClearProviders(); // 清除默认的日志提供程序
loggingBuilder.AddConsole(); // 添加控制台日志提供程序
loggingBuilder.SetMinimumLevel(LogLevel.Warning); // 设置最小日志级别为 Warning
});
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Description = "学校档案系统v1"
});
var file = Path.Combine(AppContext.BaseDirectory, "Learn.Archives.API.xml"); // xml文档绝对路径
c.IncludeXmlComments(file, true); // true : 显示控制器层注释
c.OrderActionsBy(o => o.RelativePath); // 对action的名称进行排序如果有多个就可以看见效果了。
});
builder.Configuration.AddAppConfig(args);
builder.Services.AddSqlSugarExpand();
builder.Services.AddRedisExpand();
builder.Services.AddCorsExpand();
builder.Services.AddMapster();
builder.Services.AddCorsExpand();
builder.Services.AddHttpClient();
builder.Services.AddHttpContextAccessor();
//异常过滤器
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(typeof(ExceptionFilter));
});
var app = builder.Build();
app.UseMiddleware<BasicAuthMiddleware>("Swagger");
app.UseSwagger();
app.UseSwaggerUI();
//自定义 应用
app.UseCorsExpand();
app.UseSqlSugarExpand();
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@ -0,0 +1,14 @@
{
"profiles": {
"http5199": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5199"
},
},
}

View File

@ -0,0 +1,29 @@
{
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft.AspNetCore": "Error"
}
},
"Redis": {
"ConnectionString": "redis-external.23544.com:16379,password=poiuyt)(*&^%,defaultDatabase=3"
},
"FFmpeg": {
" TimeSlice": 600
},
"AliyunOSS": {
"AccessKeyId": "LTAI5tDC6p9h747B7FHbgwkH",
"AccessKeySecret": "vRKgmbp1LB05LaGOjh3ZrZxbHSLYLF",
"BucketDomain": "https://learn-videoanalysis.oss-cn-chengdu.aliyuncs.com",
"Region": "cn-chengdu",
"BucketName": "learn-videoanalysis",
"EndPoint": "oss-cn-chengdu.aliyuncs.com" //
},
"DB": {
//"ConnectionString": "AllowLoadLocalInfile=true;Server=10.255.255.3;Port=3306;Database=learn.videoanalysis;User ID=marking;Password=qwe123!@#;CharSet=utf8mb4;pooling=true;SslMode=None",
"ConnectionString": "AllowLoadLocalInfile=true;Server=rm-2vc20nd3d11g0oh6g2o.rwlb.cn-chengdu.rds.aliyuncs.com;User ID=marking;Password=poiuytPOIUYT098765)(*&^%;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None",
"SqlType": "MySql",
"UpdateTable": false
}
}
}

View File

@ -0,0 +1,32 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"AppConfig": {
"ID": 1, //
"SimpLetex": {
"Host": "https://server.simpletex.cn/api/",
"AppSecret": "05ZbPfCFZgTmfd4uIqHHc9pHgYR2V8bk",
"AppId": "GH2OXwuxSZEH5W28H61bdSzD"
},
"Redis": {
"ConnectionString": "127.0.0.1:6379,password=Woshiren123,defaultDatabase=10"
},
"DB": {
"ConnectionString": "AllowLoadLocalInfile=true;Server=192.168.2.9;User ID=root;Password=qwe123!@#;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None",
"SqlType": "MySql",
"UpdateTable": false
},
"OtherDBArr": [
//{
// "ConfigId": 1001, //ResourceBank
// "ConnectionString": "Server=47.109.35.116;Database=ResourceBank;UID=live;Password=Woshiren^&*();MultipleActiveResultSets=true;Encrypt=True;TrustServerCertificate=True;",
// "SqlType": "SqlServer"
//}
]
}
}

View File

@ -0,0 +1,158 @@
using FreeRedis;
using Learn.Archives.Core.Model;
using Learn.Archives.Core.Model.Interface;
using Microsoft.Extensions.DependencyModel;
using Microsoft.IdentityModel.Tokens;
using SqlSugar;
using SqlSugar.IOC;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.PortableExecutable;
using System.Runtime.Loader;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using UserCenter.Model.Interface;
namespace Learn.Archives.Core.Common
{
/// <summary>
/// 程序 公共变量
/// </summary>
public static class AppCommon
{
/// <summary>
/// 应用有效程序集
/// </summary>
public static readonly IEnumerable<Assembly> Assemblies;
/// <summary>
/// 主库数据库表类型
/// </summary>
public static readonly IEnumerable<Type> DbMatserType;
public static readonly IEnumerable<Type> KnowsType;
static AppCommon()
{
try
{
Assemblies = ExpandFunction.GetAssemblies();
var assembliesType = Assemblies.Where(s => s.FullName.Contains("VideoAnalysis")).SelectMany(s => s.ExportedTypes
.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false)));
DbMatserType = assembliesType
.Where(u => u.GetInterfaces().Contains(typeof(IDB)));
}
catch
{
throw;
}
}
/// <summary>
/// 程序配置
/// </summary>
public static AppConfig Config = new AppConfig();
/// <summary>
/// ServiceProvider
/// </summary>
public static IServiceProvider? Services;
}
/// <summary>
/// 拓展函数
/// </summary>
public static class ExpandFunction
{
static Dictionary<string, string> FormulaData;
static string FormulaDataKey;
/// <summary>
/// 帧文件名称
/// </summary>
public static string FrameName = "frame_";
/// <summary>
/// 对象转化为JSON字符串
/// </summary>
/// <param name="o">拓展对象</param>
/// <param name="WriteIndented">美化输出?</param>
/// <returns></returns>
public static string ToJson(this object o, bool WriteIndented = false)
{
var jsonOptions = new JsonSerializerOptions
{
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
WriteIndented = WriteIndented // 如果需要美化输出
};
return JsonSerializer.Serialize(o, jsonOptions);
}
/// <summary>
/// 获取应用有效程序集
/// </summary>
/// <returns>IEnumerable</returns>
public static List<Assembly> GetAssemblies()
{
// 获取当前解决方案的所有程序集
var assembliesStr = DependencyContext.Default.RuntimeLibraries
.Where(u => !u.Name.StartsWith(nameof(Microsoft))
&& !u.Name.StartsWith(nameof(System))
&& !u.Name.StartsWith("netstandard")
&& u.Type == "project");
var assemblies = assembliesStr.Select(a => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(a.Name))).ToList();
var assemblies1 = Assembly.GetEntryAssembly().GetReferencedAssemblies().Where(x => x.Name.StartsWith("App.") || x.Name.StartsWith("UserCenter."))
.Select(a => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(a.Name))).ToList();
foreach (var item in assemblies1)
{
if (!assemblies.Contains(item))
assemblies.Add(item);
}
return assemblies;
}
/// <summary>
/// 获取下一个枚举值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="current"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static T? NextEnum<T>(this T current) where T : struct, Enum
{
if (!typeof(T).IsEnum)
throw new ArgumentException("传入类型不是枚举");
T[] values = (T[])Enum.GetValues(typeof(T));
int currentIndex = Array.IndexOf(values, current);
if (currentIndex == values.Length - 1)
return null;
int nextIndex = (currentIndex + 1) % values.Length;
return values[nextIndex];
}
/// <summary>
/// 转化枚举
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static T? ToEnum<T>(this object value) where T : struct, Enum
{
try
{
if (value is null || string.IsNullOrEmpty(value.ToString()))
return null;
if (Enum.TryParse<T>(value.ToString(), true, out var result) && Enum.IsDefined(typeof(T), result))
return result;
return null;
}
catch (Exception)
{
return null;
}
}
}
}

View File

@ -0,0 +1,214 @@
using Learn.Archives.Core.Common.Expand;
using SqlSugar.IOC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Learn.Archives.Core.Common
{
/// <summary>
/// 应用程序配置
/// </summary>
public class AppConfig
{
/// <summary>
/// 程序ID
/// </summary>
public string ID { get; set; } = string.Empty;
/// <summary>
/// Admin
/// </summary>
public AdminConfig Admin { get; set; } = new AdminConfig();
/// <summary>
/// 子系统
/// </summary>
public SubsystemConfig Subsystem { get; set; } = new SubsystemConfig();
/// <summary>
/// redis
/// </summary>
public RedisConfig Redis { get; set; } = new RedisConfig();
/// <summary>
/// Whisper AI
/// </summary>
public WhisperConfig Whisper { get; set; } = new WhisperConfig();
/// <summary>
/// FFmpeg
/// </summary>
public FFmpegConfig FFmpeg { get; set; } = new FFmpegConfig();
/// <summary>
/// ChatGpt
/// </summary>
public ChatGptConfig ChatGpt { get; set; } = new ChatGptConfig();
/// <summary>
/// 阿里云视频点播配置
/// </summary>
public AlibabaCloudVodConfig AlibabaCloudVod { get; set; } = new AlibabaCloudVodConfig();
public AliyunOSSConfig AliyunOSS { get; set; } = new AliyunOSSConfig();
/// <summary>
/// 数据库配置
/// </summary>
public DBConfig DB { get; set; } = new DBConfig();
/// <summary>
/// 其他数据库配置
/// </summary>
public DBConfig[] OtherDBArr { get; set; } = Array.Empty<DBConfig>();
/// <summary>
/// 系统接收任务设置配置
/// </summary>
public TaskSettingConfig TaskSetting { get; set; } = new TaskSettingConfig();
/// <summary>
/// SimpLetex配置
/// </summary>
public SimpLetexConfig SimpLetex { get; set; } = new SimpLetexConfig();
}
public class SimpLetexConfig
{
/// <summary>
/// 请求 公开的服务地址
/// </summary>
public string Host { get; set; } = string.Empty;
/// <summary>
/// api的密钥
/// </summary>
public string AppSecret { get; set; } = string.Empty;
/// <summary>
/// 应用ID
/// </summary>
public string AppId { get; set; } = string.Empty;
}
public class TaskSettingConfig
{
/// <summary>
/// 下载速度MB/S
/// </summary>
public int DownloadSpeed { get; set; }
/// <summary>
/// 是服务端
/// <para>不执行任务,不回调接口</para>
/// </summary>
public bool IS_Server { get; set; }
}
/// <summary>
/// ffmpeg配置
/// </summary>
public class GptConfig
{
/// <summary>
/// 请求 公开的服务地址
/// </summary>
public string Host { get; set; } = string.Empty;
/// <summary>
/// api的密钥
/// </summary>
public string ApiKey { get; set; } = string.Empty;
}
/// <summary>
/// 文本模型 配置
/// </summary>
public class ChatGptConfig
{
/// <summary>
/// KIMI
/// <para></para>
/// </summary>
public GptConfig ChatGpt { get; set; } = new GptConfig();
public GptConfig DeepSeek { get; set; } = new GptConfig();
public GptConfig KIMI { get; set; } = new GptConfig();
public GptConfig aliyun { get; set; } = new GptConfig();
}
/// <summary>
/// ffmpeg配置
/// </summary>
public class FFmpegConfig
{
/// <summary>
/// 音频切片时间段
/// <para>0不切片</para>
/// </summary>
public int TimeSlice { get; set; } = 0;
}
/// <summary>
/// Whisper配置
/// </summary>
public class WhisperConfig
{
/// <summary>
/// 模型名称
/// </summary>
public string ModelName { get; set; } = string.Empty;
}
/// <summary>
/// 管理界面Admin账号
/// </summary>
public class AdminConfig
{
/// <summary>
/// 账号
/// </summary>
public string Account { get; set; } = string.Empty;
/// <summary>
/// 密码
/// </summary>
public string Password { get; set; } = string.Empty;
}
/// <summary>
/// redis配置
/// </summary>
public class RedisConfig
{
/// <summary>
/// redis连接字符串
/// </summary>
public string ConnectionString { get; set; } = string.Empty;
}
public class DBConfig
{
/// <summary>
/// 主库链接
/// </summary>
public string ConnectionString { get; set; } = string.Empty;
/// <summary>
/// 数据库类型
/// </summary>
public IocDbType SqlType { get; set; }
/// <summary>
/// 启动时更新表结构
/// </summary>
public bool UpdateTable { get; set; }
/// <summary>
/// 配置ID
/// </summary>
public long ConfigId { get; set; }
}
/// <summary>
/// 子系统配置
/// </summary>
public class SubsystemInfo
{
public string APIUrl { get; set; } = string.Empty;
public string Token { get; set; } = string.Empty;
}
/// <summary>
/// 子系统配置
/// </summary>
public class SubsystemConfig
{
public SubsystemInfo { get; set; } = new SubsystemInfo();
}
}

View File

@ -0,0 +1,56 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using OracleInternal.Secure.Network;
using System;
using System.Text;
using System.Threading.Tasks;
namespace Learn.Archives.Core.Common
{
public class BasicAuthMiddleware
{
private readonly RequestDelegate _next;
private readonly string _realm;
public BasicAuthMiddleware(RequestDelegate next, string realm)
{
_next = next;
_realm = realm;
}
public async Task InvokeAsync(HttpContext context)
{
if (context.Request.Path.StartsWithSegments("/swagger"))
{
string authHeader = context.Request.Headers["Authorization"];
if (authHeader != null && authHeader.StartsWith("Basic "))
{
var encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
var decodedUsernamePassword = Encoding.UTF8.GetString(Convert.FromBase64String(encodedUsernamePassword));
var usernamePassword = decodedUsernamePassword.Split(':');
if (await IsAuthorized(usernamePassword[0], usernamePassword[1]))
{
await _next(context);
return;
}
}
context.Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{_realm}\"";
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return;
}
await _next(context);
}
private async Task<bool> IsAuthorized(string username, string password)
{
// 在这里验证用户名和密码
return AppCommon.Config.Admin.Account == username
&& AppCommon.Config.Admin.Password == password;
}
}
}

View File

@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace Learn.Archives.Core.Common
{
public class ExceptionFilter : IAsyncExceptionFilter
{
public ExceptionFilter()
{
}
public async Task OnExceptionAsync(ExceptionContext context)
{
// 创建一个包含错误信息的对象
var errorObject = new
{
ErrorMessage = context.Exception.Message,
context.Exception.StackTrace,
};
// 将错误对象序列化为JSON格式
var json = errorObject.ToJson();
// 设置响应内容类型为JSON
context.HttpContext.Response.ContentType = "application/json";
// 设置状态码
context.HttpContext.Response.StatusCode = 500;
// 将JSON数据写入响应体
await context.HttpContext.Response.WriteAsync(json);
}
}
}

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Vod20170321;
using AlibabaCloud.SDK.Vod20170321.Models;
using AlibabaCloud.TeaUtil.Models;
using Learn.Archives.Core.Common;
using Microsoft.Extensions.DependencyInjection;
namespace Learn.Archives.Core.Common.Expand
{
public class AlibabaCloudVodConfig
{
/// <summary>
/// id
/// </summary>
public string AccessKeyId { get; set; }
/// <summary>
///密钥
/// </summary>
public string AccessKeySecret { get; set; }
public string Endpoint { get; set; } = "vod.cn-shanghai.aliyuncs.com";
}
/// <summary>
/// 阿里云 视频点播拓展
/// </summary>
public static class AlibabaCloudVodExpand
{
/// <summary>
/// 使用阿里云 vod拓展
/// </summary>
/// <param name="service"></param>
/// <returns></returns>
public static void AddAlibabaCloudVod(this IServiceCollection service)
{
Console.WriteLine($"{DateTime.Now}=>初始化 阿里云VOD");
// 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。
// 建议使用更安全的 STS 方式更多鉴权访问方式请参见https://help.aliyun.com/document_detail/378671.html。
Config config = new()
{
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
AccessKeyId = AppCommon.Config.AlibabaCloudVod.AccessKeyId,
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
AccessKeySecret = AppCommon.Config.AlibabaCloudVod.AccessKeySecret,
Endpoint = AppCommon.Config.AlibabaCloudVod.Endpoint
};
// Endpoint 请参考 https://api.aliyun.com/product/vod
var c = new Client(config);
service.AddSingleton(c);
}
}
}

View File

@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Vod20170321;
using AlibabaCloud.SDK.Vod20170321.Models;
using AlibabaCloud.TeaUtil.Models;
using Aliyun.OSS.Common;
using Aliyun.OSS;
using Microsoft.Extensions.DependencyInjection;
using System.Security.AccessControl;
using Aliyun.Credentials.Models;
using System.IO;
using Learn.Archives.Core.Common;
namespace Learn.Archives.Core.Common.Expand
{
public class AliyunOSSConfig
{
/// <summary>
/// id
/// </summary>
public string AccessKeyId { get; set; }
/// <summary>
///密钥
/// </summary>
public string AccessKeySecret { get; set; }
/// <summary>
/// 区域Url
/// </summary>
public string Region { get; set; }
/// <summary>
/// 筒域名
/// </summary>
public string BucketDomain { get; set; }
/// <summary>
/// 桶名称
/// </summary>
public string BucketName { get; set; }
public string Endpoint { get; set; } = "oss-cn-chengdu.aliyuncs.com";
}
/// <summary>
/// 阿里云 视频点播拓展
/// </summary>
public static class AliyunOSSExpand
{
/// <summary>
/// 使用阿里云 vod拓展
/// </summary>
/// <param name="service"></param>
/// <returns></returns>
public static void AddAliyunOSS(this IServiceCollection service)
{
Console.WriteLine($"{DateTime.Now}=>初始化 阿里云OSS");
AliyunOSSConfig config = new()
{
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
AccessKeyId = AppCommon.Config.AliyunOSS.AccessKeyId,
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
AccessKeySecret = AppCommon.Config.AliyunOSS.AccessKeySecret,
Endpoint = AppCommon.Config.AliyunOSS.Endpoint,
Region = AppCommon.Config.AliyunOSS.Region,
};// 创建ClientConfiguration实例按照您的需要修改默认参数。
var conf = new ClientConfiguration();
// 设置v4签名。
conf.SignatureVersion = SignatureVersion.V4;
// 创建OssClient实例。
var oss = new OssClient(config.Endpoint, config.AccessKeyId, config.AccessKeySecret, conf);
oss.SetRegion(config.Region);
service.AddSingleton(oss);
}
/// <summary>
/// 上传文件
/// </summary>
/// <param name="oss"></param>
/// <param name="fileArr">视频实体片段</param>
// public static void AddVideoQuestionUrl(this OssClient oss, List<VideoQuestionOSSDto> fileArr)
// {
// var cached = new HashSet<string>();
// foreach (var item in fileArr)
// {
// try
// {
// var isDebug = false;
//#if DEBUG
// isDebug = true;
//#endif
// var path = (isDebug ? "debug/" : string.Empty) + item.VideoTaskId.ToString() + "/" + Path.GetFileName(item.FilePath);
// if (cached.Contains(item.FilePath))
// {
// item.PPTImageUrl = AppCommon.Config.AliyunOSS.BucketDomain + "/" + path;
// continue;
// }
// using var file = File.OpenRead(item.FilePath);
// var result = oss
// .PutObject(
// AppCommon.Config.AliyunOSS.BucketName,
// path,
// file);
// item.PPTImageUrl = AppCommon.Config.AliyunOSS.BucketDomain + "/" + path;
// cached.Add(item.FilePath);
// continue;
// }
// catch (Exception)
// {
// }
// }
// }
}
}

View File

@ -0,0 +1,28 @@
using Coravel;
using Learn.Archives.Core.Common;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
namespace Learn.Archives.Core.Common.Expand
{
public static class AppConfigExpand
{
public static void AddAppConfig(this IConfigurationManager cm, string[] args)
{
Console.WriteLine($"{DateTime.Now}=>初始化 AppConfig");
cm.GetSection("AppConfig").Bind(AppCommon.Config);
var argList = args.ToList();
var eArgs = Environment.GetEnvironmentVariable("va_args");
if (!string.IsNullOrEmpty(eArgs))
argList.AddRange(eArgs.Split(","));
Console.WriteLine("===========================================");
Console.WriteLine("启动参数如下:");
Console.WriteLine(string.Join(',', args));
Console.WriteLine("===========================================");
if (args.Contains("IS_Server"))
AppCommon.Config.TaskSetting.IS_Server = true;
}
}
}

View File

@ -0,0 +1,41 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace Learn.Archives.Core.Common.Expand
{
/// <summary>
/// 跨域
/// </summary>
public static class CorsExpand
{
/// <summary>
/// 添加跨域拓展
/// </summary>
/// <param name="services"></param>
public static void AddCorsExpand(this IServiceCollection services)
{
services.AddCors(c =>
{
c.AddPolicy("All", policy =>
{
policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
});
});
}
/// <summary>
/// 使用跨域
/// </summary>
/// <param name="app"></param>
public static void UseCorsExpand(this IApplicationBuilder app)
{
app.UseCors("All");
// 获取配置文件中的允许跨域的地址
app.UseCors(options =>
{
options.WithOrigins("*") // 允许跨域请求的地址
.AllowAnyHeader() // 允许的请求标头
.AllowAnyMethod(); // 允许跨域请求的类型 (GET,POST等)
});
}
}
}

View File

@ -0,0 +1,230 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Threading.Tasks;
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Vod20170321;
using AlibabaCloud.SDK.Vod20170321.Models;
using AlibabaCloud.TeaUtil.Models;
using Azure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Learn.Archives.Core.Common;
namespace Learn.Archives.Core.Common.Expand
{
public class SimpleTexOcrResponseData
{
public bool status { get; set; }
public SimpleTexOcrResponseDataRes res { get; set; }
public string request_id { get; set; }
}
public class SimpleTexOcrResponseDataRes
{
public string type { get; set; }
[JsonPropertyName("info")] // 替换为实际字段名
public JsonElement DataInfo { get; set; } // 使用JsonElement接收未知类型
public string value { get; set; }
}
public class SimpleTexOcrResponseDataInfo
{
public string markdown { get; set; }
}
/// <summary>
/// 请求参数
/// </summary>
public class SimpleTexOcrRequest
{
public SimpleTexOcrRequest(string filePath)
{
file = File.OpenRead(filePath);
}
/// <summary>
/// 合法的图片二进制文件信息包括png/jpg等格式无法开启批量调用仅支持一次上传一张图片
/// </summary>
public FileStream file { get; set; }
/// <summary>
/// 用以指定识别图片的类型如果使用auto则会自动检测使用document会返回markdown文档结果使用formula会返回LaTeX结果
/// <para>"auto", "document", "formula"</para>
/// </summary>
public string rec_mode { get; set; } = "document";
/// <summary>
/// 开启后模型将基于0°90°, 180°, 270°自动矫正上传图片的方向默认不开启
/// </summary>
public bool enable_img_rot { get; set; } = false;
/// <summary>
/// 用于修改行内公式在markdown中的包裹符号。以Json形式填入如果格式错误将使用默认的包裹符号
/// <para>示例:["$","$"]</para>
/// </summary>
public string inline_formula_wrapper { get; set; }
/// <summary>
/// 用于修改独立行公式在markdown中的包裹符号。以Json形式填入如果格式错误将使用默认的包裹符号
/// <para>示例:["$$","$$"]</para>
/// </summary>
public string isolated_formula_wrapper { get; set; }
}
/// <summary>
/// ocr响应
/// </summary>
public class SimpleTexOcrResponse
{
public bool Success { get; set; }
public SimpleTexOcrResponseData Result { get; set; }
public string ResultStr { get; set; }
public string Error { get; set; }
}
public class SimpLetexClient
{
private readonly IHttpClientFactory _httpClientFactory;
public SimpLetexClient(
IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<SimpleTexOcrResponse> ProcessImageAsync(SimpleTexOcrRequest request)
{
var client = _httpClientFactory.CreateClient();
using var content = new MultipartFormDataContent();
var parameters = new Dictionary<string, string>();
// 添加文件内容
var fileContent = new StreamContent(request.file);
content.Add(fileContent, nameof(request.file), Path.GetFileName(request.file.Name));
// 添加并收集其他参数
if (request.rec_mode != "auto")
{
content.Add(new StringContent(request.rec_mode), nameof(request.rec_mode));
parameters[nameof(request.rec_mode)] = request.rec_mode;
}
var enableImgRotStr = request.enable_img_rot.ToString().ToLower();
content.Add(new StringContent(enableImgRotStr), nameof(request.enable_img_rot));
parameters[nameof(request.enable_img_rot)] = enableImgRotStr;
if (request.inline_formula_wrapper != null)
{
content.Add(new StringContent(request.inline_formula_wrapper), nameof(request.inline_formula_wrapper));
parameters[nameof(request.inline_formula_wrapper)] = request.inline_formula_wrapper;
}
if (request.isolated_formula_wrapper != null)
{
var isolatedWrapper = request.isolated_formula_wrapper.ToJson();
content.Add(new StringContent(isolatedWrapper), nameof(request.isolated_formula_wrapper));
parameters[nameof(request.isolated_formula_wrapper)] = isolatedWrapper;
}
// 生成鉴权参数
var randomStr = Guid.NewGuid().ToString("N").Substring(16);
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
var appId = AppCommon.Config.SimpLetex.AppId;
parameters["timestamp"] = timestamp;
parameters["random-str"] = randomStr;
parameters["app-id"] = appId;
// 生成签名
var signStr = string.Join("&", parameters
.OrderBy(p => p.Key)
.Select(p => $"{p.Key}={Uri.EscapeDataString(p.Value)}"))
+ $"&secret={AppCommon.Config.SimpLetex.AppSecret}";
var sign = ComputeMD5(signStr);
// 创建请求并添加Header
var requestMessage = new HttpRequestMessage(HttpMethod.Post,
AppCommon.Config.SimpLetex.Host + "simpletex_ocr")
{
Content = content
};
requestMessage.Headers.Add("random-str", randomStr);
requestMessage.Headers.Add("timestamp", timestamp);
requestMessage.Headers.Add("app-id", appId);
requestMessage.Headers.Add("sign", sign);
try
{
var response = await client.SendAsync(requestMessage);
var resStr = await response.Content.ReadAsStringAsync();
var responseContent = await response.Content.ReadFromJsonAsync<SimpleTexOcrResponseData>();
if (responseContent.res.DataInfo.ValueKind == JsonValueKind.Object)
{
responseContent.res.value = JsonSerializer.Deserialize<SimpleTexOcrResponseDataInfo>(
responseContent.res.DataInfo.GetRawText(),
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }
)?.markdown ?? string.Empty;
// 处理字符串
}
else if (responseContent.res.DataInfo.ValueKind == JsonValueKind.String)
{
responseContent.res.value = responseContent.res.DataInfo.GetString();
}
request.file.Dispose();
return new SimpleTexOcrResponse
{
Success = response.IsSuccessStatusCode,
Result = responseContent,
ResultStr = resStr,
Error = response.IsSuccessStatusCode ? null : $"HTTP Error: {response.StatusCode}"
};
}
catch (Exception ex)
{
return new SimpleTexOcrResponse
{
Success = false,
Error = $"Request Failed: {ex.Message}"
};
}
}
private string GenerateSignatureString(IDictionary<string, string> parameters, string secret)
{
var sortedParams = parameters
.OrderBy(p => p.Key)
.Select(p => $"{p.Key}={Uri.EscapeDataString(p.Value)}");
return string.Join("&", sortedParams) + $"&secret={secret}";
}
private string ComputeMD5(string input)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.UTF8.GetBytes(input);
var hashBytes = md5.ComputeHash(inputBytes);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
}
/// <summary>
/// 服务注册扩展
/// </summary>
public static class SSimpLetexExtensions
{
public static IServiceCollection AddSimpleTexOcrClient(this IServiceCollection services)
{
services.AddSingleton<SimpLetexClient>();
return services;
}
}
}

View File

@ -0,0 +1,169 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using MySqlConnector;
using SqlSugar;
using SqlSugar.IOC;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Yitter.IdGenerator;
namespace Learn.Archives.Core.Common.Expand
{
public static class SqlSugarExpand
{
public static bool ShowSQL = false;
public static void AddSqlSugarExpand(this IServiceCollection services)
{
services.AddHttpContextAccessor();
Console.WriteLine($"{DateTime.Now}=>初始化 YitId雪花ID");
var options = new IdGeneratorOptions(ushort.Parse(AppCommon.Config.ID));
YitIdHelper.SetIdGenerator(options);
#region SqlSugar注入
var dbList = new List<IocConfig>() {
new IocConfig()
{
ConfigId =1,
ConnectionString = AppCommon.Config.DB.ConnectionString,
DbType =AppCommon.Config.DB.SqlType,
IsAutoCloseConnection = true//自动释放
},
};
dbList.AddRange(AppCommon.Config.OtherDBArr.Select(s => new IocConfig()
{
ConfigId = s.ConfigId,
ConnectionString = s.ConnectionString,
DbType = s.SqlType,
IsAutoCloseConnection = true
}));
services.AddTransient(typeof(Repository<>));
//注入SqlSugar 主库
services.AddSqlSugar(dbList);
services.ConfigurationSugar(db =>
{
var config = db.CurrentConnectionConfig;
// 设置超时时间
db.Ado.CommandTimeOut = 61;
#if DEBUG
// 打印SQL语句
db.Aop.OnLogExecuting = (sql, pars) =>
{
if (!ShowSQL) return;
//var originColor = Console.ForegroundColor;
//if (sql.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
// Console.ForegroundColor = ConsoleColor.Green;
//if (sql.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase) || sql.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase))
// Console.ForegroundColor = ConsoleColor.Yellow;
//if (sql.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase))
// Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"【{DateTime.Now}——执行SQL - [{config.ConfigId}]】\r\n" + UtilMethods.GetSqlString(config.DbType, sql, pars) + "\r\n");
//Console.ForegroundColor = originColor;
};
#endif
db.Aop.OnError = (ex) =>
{
if (ex.Parametres == null) return;
//var originColor = Console.ForegroundColor;
//Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine($"【{DateTime.Now}——错误SQL - [{config.ConfigId}]】\r\n" + ex.Message + "\r\n" + UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres) + "\r\n");
Console.WriteLine();
//Console.ForegroundColor = originColor;
};
db.Aop.DataExecuting = (oldValue, entityInfo) =>
{
if (entityInfo.OperationType == DataFilterType.InsertByObject)
{
// 主键(long类型)且没有值的---赋值雪花Id
if (entityInfo.EntityColumnInfo.IsPrimarykey && !entityInfo.EntityColumnInfo.IsIdentity && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long))
{
var id = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue);
if (id == null || (long)id == 0)
entityInfo.SetValue(YitIdHelper.NextId());
}
if (entityInfo.PropertyName == "CreateTime" && entityInfo.EntityValue is null)
entityInfo.SetValue(DateTime.Now);
}
if (entityInfo.OperationType == DataFilterType.UpdateByObject)
{
}
};
});
#endregion
}
public static void UseSqlSugarExpand(this IApplicationBuilder app)
{
ShowSQL = false;
var builder = new MySqlConnectionStringBuilder(AppCommon.Config.DB.ConnectionString);
var dbName = builder.Database;
builder.Database = "mysql";
using SqlSugarClient dbMysql = new SqlSugarClient(new ConnectionConfig
{
ConnectionString = builder.ConnectionString,
DbType = DbType.MySql,
IsAutoCloseConnection = true,
});
var dataBaseList = dbMysql.DbMaintenance.GetDataBaseList();
if (dataBaseList.Contains(dbName))
{
Console.WriteLine($"【0】数据库 {dbName} 已存在 【√】");
}
else
{
Console.WriteLine($"【0】创建数据库{dbName} ... ");
var res = dbMysql.Ado.ExecuteCommand($"CREATE DATABASE `{dbName}` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci");
try
{
dbMysql.Ado.ExecuteCommand($"alter database `{dbName}` character set utf8mb4;" +
$"alter database `{dbName}` character set utf8mb4 collate utf8mb4_general_ci;");
//res 没有权限
dbMysql.Ado.ExecuteCommand($"SET GLOBAL local_infile=1;");
Console.WriteLine($"【0】数据库 {dbName} 创建完成 【√】");
}
catch (Exception ex)
{
Console.WriteLine("【0】主库初始化配置 出现异常 " + ex.Message);
}
}
InitDbTable();
}
public static void InitDbTable()
{
if (!AppCommon.Config.DB.UpdateTable)
{
Console.WriteLine($"【1】初始化主库表 跳过....");
//ShowSQL = true;
return;
}
Console.WriteLine($"【1】初始化主库表 执行中....");
var entityTypes = AppCommon.DbMatserType;
Console.WriteLine($"【1】数量{entityTypes.Count()} ....");
if (!entityTypes.Any()) return;
var i = 0;
var totalCount = entityTypes.Count().ToString().Length;
foreach (var t in entityTypes)
{
Console.Write($"【1】{entityTypes.Count()}/{(++i).ToString().PadLeft(totalCount, '0')} 执行 {t.FullName}".PadRight(60, ' '));
DbScoped.Sugar.CodeFirst.InitTables(t);
Console.WriteLine($"【√】");
}
Console.WriteLine($"【1】数量{entityTypes.Count()} 执行完毕");
ShowSQL = true;
}
}
}

View File

@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
namespace Learn.Archives.Core.Common
{
public static class JsonExtractor
{
/// <summary>
/// 提取json字符串
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static List<string> ExtractJsonStrings(this string input)
{
List<string> jsonList = new List<string>();
int index = 0;
while (index < input.Length)
{
if (input[index] == '{' || input[index] == '[')
{
int? endIndex = FindMatchingBracket(input, index);
if (endIndex.HasValue)
{
string candidate = input.Substring(index, endIndex.Value - index + 1);
if (IsValidJson(candidate))
{
jsonList.Add(candidate);
index = endIndex.Value + 1;
continue;
}
}
}
index++;
}
return jsonList;
}
private static int? FindMatchingBracket(string str, int start)
{
Stack<char> stack = new Stack<char>();
bool inString = false;
bool inEscape = false;
for (int i = start; i < str.Length; i++)
{
char c = str[i];
if (inEscape)
{
inEscape = false;
}
else if (inString)
{
if (c == '\\')
inEscape = true;
else if (c == '"')
inString = false;
}
else
{
switch (c)
{
case '{':
case '[':
stack.Push(c);
break;
case '}':
if (stack.Count == 0 || stack.Peek() != '{')
return null;
stack.Pop();
break;
case ']':
if (stack.Count == 0 || stack.Peek() != '[')
return null;
stack.Pop();
break;
case '"':
inString = true;
break;
}
}
if (stack.Count == 0)
return i;
}
return null; // 括号未完全匹配
}
public static bool IsValidJson(string candidate)
{
if (string.IsNullOrEmpty(candidate))
return false;
try
{
JsonDocument.Parse(candidate);
return true;
}
catch (Exception)
{
return false;
}
}
}
}

View File

@ -0,0 +1,54 @@
using FreeRedis;
using FreeRedis.Internal;
using Microsoft.Extensions.DependencyInjection;
using NetTaste;
using Newtonsoft.Json.Schema;
using SqlSugar.IOC;
using System;
using System.Security.Cryptography;
using System.Text.Json;
using System.Threading.Channels;
using System.Threading.Tasks;
using System.Xml.Linq;
using UserCenter.Model.Enum;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Learn.Archives.Core.Common
{
/// <summary>
/// redis key
/// </summary>
public static class RedisExpandKey
{
}
/// <summary>
/// redis拓展
/// </summary>
public static class RedisExpand
{
/// <summary>
/// redis 连接
/// </summary>
/// <summary>
/// 队列池
/// </summary>
static SubscribeListObject? Subscribe;
/// <summary>
/// 初始化 redis
/// <para>需要在初始化配置文件时候调用</para>
/// </summary>
public static void AddRedisExpand(this IServiceCollection service)
{
Console.WriteLine($"{DateTime.Now}=>初始化 Redis");
RedisClient Redis = new RedisClient(AppCommon.Config.Redis.ConnectionString);
Redis.Serialize = obj => JsonSerializer.Serialize(obj);
Redis.Deserialize = (json, type) => JsonSerializer.Deserialize(json, type);
service.AddSingleton(Redis);
}
}
}

View File

@ -0,0 +1,37 @@
using SqlSugar;
using SqlSugar.IOC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Learn.Archives.Core.Common
{
public class Repository<T> : SimpleClient<T> where T : class, new()
{
readonly Dictionary<Type, object?> CID = new Dictionary<Type, object?>();
public Repository()
{
SwitchConnection();
}
public void SwitchConnection()
{
var t = typeof(T);
if (CID.ContainsKey(t))
{
base.Context = CID[t] != null
? DbScoped.Sugar.GetConnectionScope(CID[t])
: DbScoped.Sugar;
return;
}
var c = t.GetCustomAttribute<TenantAttribute>();
if (!CID.ContainsKey(t))
CID.Add(t, c?.configId);
base.Context = c != null
? DbScoped.Sugar.GetConnectionScope(c.configId)
: DbScoped.Sugar;
}
}
}

View File

@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AlibabaCloud.SDK.Vod20170321" Version="3.6.1" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageReference Include="Coravel" Version="6.0.2" />
<PackageReference Include="FreeRedis" Version="1.3.2" />
<PackageReference Include="Downloader" Version="3.2.1" />
<PackageReference Include="Mapster" Version="7.4.1-pre01" />
<PackageReference Include="Microsoft.AspNetCore.Cors" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.3.0" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
<PackageReference Include="SqlSugar.IOC" Version="2.0.0" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.170" />
<PackageReference Include="UserCenter.Model" Version="1.3.9" />
</ItemGroup>
<ItemGroup>
<Folder Include="Model\Dto\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,43 @@
using Learn.Archives.Core.Model.Interface;
using SqlSugar;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Text.Json;
using UserCenter.Model.Enum;
namespace Learn.Archives.Core.Model
{
/// <summary>
/// 管理员
/// </summary>
[SugarTable("admin")]
public class Admin : IDB
{
/// <summary>
/// id
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
public long Id { get; set; }
/// <summary>
/// 账号
/// </summary>
[SugarColumn(Length = 12)]
public string Name { get; set; }
[SugarColumn(Length = 12)]
public string Account { get; set; }
/// <summary>
/// 密码
/// </summary>
[SugarColumn(Length = 12)]
public string Password { get; set; }
/// <summary>
/// 启用
/// </summary>
public bool Enable { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; } = DateTime.Now;
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Learn.Archives.Core.Model.Enum
{
public enum UserStatusEnum
{
=1,
退=10,
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Learn.Archives.Core.Model.Interface
{
/// <summary>
/// 表属于IDB
/// </summary>
interface IDB
{
}
}

View File

@ -0,0 +1,65 @@
using Learn.Archives.Core.Model.Interface;
using SqlSugar;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Text.Json;
using UserCenter.Model;
using UserCenter.Model.Enum;
namespace Learn.Archives.Core.Model
{
/// <summary>
/// 用户
/// <para>数据中心拓展用户</para>
/// </summary>
[SugarTable("user")]
public class User : IDB
{
/// <summary>
/// id
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
public long Id { get; set; }
/// <summary>
/// 用户中心的id
/// <see cref="UserCenter.Model.User.Id"/>
/// </summary>
public long UserCenterId { get; set; }
/// <summary>
/// 减免金额
/// </summary>
[SugarColumn(DecimalDigits =2)]
public decimal AmountRelief { get; set; }
/// <summary>
/// 学生状态
/// </summary>
public UserSourceEnum Status { get; set; }
/// <summary>
/// 备注
/// <para></para>
/// </summary>
[SugarColumn(IsNullable = true)]
public string? Remark { get; set; }
/// <summary>
/// 退出时间
/// </summary>
[SugarColumn(IsNullable = true)]
public DateTime ExitTime { get; set; } = DateTime.Now;
/// <summary>
/// 退出时间
/// </summary>
[SugarColumn(IsNullable = true)]
public DateTime JoinTime { get; set; } = DateTime.Now;
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; } = DateTime.Now;
}
}