commit 2183073421ab5e3cde3432dfdac3e65c1e41211b
Author: lq1405 <2769838458@qq.com>
Date: Sun Oct 13 17:04:47 2024 +0800
ceshi
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..1ff0c42
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9491a2f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,363 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Oo]ut/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..018a754
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,31 @@
+#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
+
+FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
+USER app
+WORKDIR /app
+EXPOSE 8080
+EXPOSE 8081
+
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+ARG BUILD_CONFIGURATION=Release
+WORKDIR /src
+# 复制所有的项目文件
+COPY ["LMS.service/LMS.service.csproj", "LMS.service/"]
+COPY ["LMS.Common/LMS.Common.csproj", "LMS.Common/"]
+COPY ["LMS.DAO/LMS.DAO.csproj", "LMS.DAO/"]
+COPY ["LMS.Repository/LMS.Repository.csproj", "LMS.Repository/"]
+COPY ["LMS.Tools/LMS.Tools.csproj", "LMS.Tools/"]
+
+RUN dotnet restore "LMS.service/LMS.service.csproj"
+COPY . .
+WORKDIR "/src/LMS.service"
+RUN dotnet build "LMS.service.csproj" -c $BUILD_CONFIGURATION -o /app/build
+
+FROM build AS publish
+ARG BUILD_CONFIGURATION=Release
+RUN dotnet publish "LMS.service.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "LMS.service.dll"]
\ No newline at end of file
diff --git a/LMS.Common/Attributes/DescriptionAttribute.cs b/LMS.Common/Attributes/DescriptionAttribute.cs
new file mode 100644
index 0000000..f73aebf
--- /dev/null
+++ b/LMS.Common/Attributes/DescriptionAttribute.cs
@@ -0,0 +1,13 @@
+锘縩amespace LMS.Common.Attributes
+{
+ [AttributeUsage(AttributeTargets.Field)]
+ public class DescriptionAttribute : Attribute
+ {
+ public string Description { get; set; }
+
+ public DescriptionAttribute(string description)
+ {
+ Description = description;
+ }
+ }
+}
diff --git a/LMS.Common/Attributes/ResultAttribute.cs b/LMS.Common/Attributes/ResultAttribute.cs
new file mode 100644
index 0000000..6ce017f
--- /dev/null
+++ b/LMS.Common/Attributes/ResultAttribute.cs
@@ -0,0 +1,13 @@
+锘縩amespace LMS.Common.Attributes
+{
+ [AttributeUsage(AttributeTargets.Field)]
+ public class ResultAttribute : Attribute
+ {
+ public string Result { get; set; }
+
+ public ResultAttribute(string result)
+ {
+ Result = result;
+ }
+ }
+}
diff --git a/LMS.Common/Enum/MachineEnum.cs b/LMS.Common/Enum/MachineEnum.cs
new file mode 100644
index 0000000..72b0f17
--- /dev/null
+++ b/LMS.Common/Enum/MachineEnum.cs
@@ -0,0 +1,31 @@
+锘縰sing LMS.Common.Attributes;
+
+namespace LMS.Common.Enums
+{
+ public class MachineEnum
+ {
+ ///
+ /// 鏈哄櫒鐮佷娇鐢ㄧ姸鎬
+ ///
+ public enum MachineUseStatus
+ {
+ [Description("璇曠敤")]
+ Trial = 0,
+
+ [Description("姘镐箙")]
+ Permanent = 1
+ }
+
+ ///
+ /// 鏈哄櫒鐮佺姸鎬
+ ///
+ public enum MachineStatus
+ {
+ [Description("婵娲")]
+ Active = 1,
+
+ [Description("鍐荤粨")]
+ Frozen = 0
+ }
+ }
+}
diff --git a/LMS.Common/Enum/PermissionEnum.cs b/LMS.Common/Enum/PermissionEnum.cs
new file mode 100644
index 0000000..9ab842e
--- /dev/null
+++ b/LMS.Common/Enum/PermissionEnum.cs
@@ -0,0 +1,41 @@
+锘
+
+using LMS.Common.Attributes;
+
+namespace LMS.Common.Enums
+{
+ public class PermissionEnum
+ {
+ public enum PermissionType
+ {
+ [Description("鐢ㄦ埛鏉冮檺")]
+ User = 1,
+
+ [Description("鏈哄櫒鐮佹潈闄")]
+ Machine = 2,
+
+ [Description("瑙掕壊鏉冮檺")]
+ Role = 3,
+
+ [Description("鎻愮ず璇嶇被鍨")]
+ Prompt = 4,
+
+ [Description("鏉冮檺绫诲瀷鏉冮檺")]
+ PermissionType = 5,
+
+ [Description("鏉冮檺鏉冮檺")]
+ Permission = 6,
+
+ [Description("鍏朵粬鏉冮檺")]
+ Custom = 100
+
+ }
+
+ public enum PType
+ {
+ User = 1,
+ Machine = 2,
+ Role = 3,
+ }
+ }
+}
diff --git a/LMS.Common/Enum/PromptEnum.cs b/LMS.Common/Enum/PromptEnum.cs
new file mode 100644
index 0000000..2e66584
--- /dev/null
+++ b/LMS.Common/Enum/PromptEnum.cs
@@ -0,0 +1,49 @@
+锘縩amespace LMS.Common.Enums
+{
+ public class PromptEnum
+ {
+ public enum PromptType
+ {
+ ///
+ /// 寮澶存彁绀鸿瘝
+ ///
+ StartPrompt = 0,
+ }
+
+ public class PromptStatus
+ {
+ ///
+ /// 鎻愮ず璇嶇姸鎬侊細鍚敤
+ ///
+ public const string Enable = "enable";
+ ///
+ ///
+ ///鎻愮ず璇嶇姸鎬侊細绂佺敤
+ ///
+ public const string Disable = "disable";
+ }
+
+ public class PromptTypeStatus
+ {
+ ///
+ /// 鎻愮ず璇嶇被鍨嬬姸鎬侊細鍚敤
+ ///
+ public const string Enable = "enable";
+ ///
+ ///
+ ///鎻愮ず璇嶇被鍨嬬姸鎬侊細绂佺敤
+ ///
+ public const string Disable = "disable";
+
+ ///
+ /// 鎵鏈夋湁鏁堢殑鎻愮ず璇嶇被鍨嬬姸鎬
+ ///
+ public static readonly HashSet ValidStatuses = new HashSet
+ {
+ Enable,
+ Disable
+ };
+ }
+ }
+
+}
diff --git a/LMS.Common/Enum/ResponseCodeEnum.cs b/LMS.Common/Enum/ResponseCodeEnum.cs
new file mode 100644
index 0000000..3c8ac6e
--- /dev/null
+++ b/LMS.Common/Enum/ResponseCodeEnum.cs
@@ -0,0 +1,198 @@
+锘縰sing LMS.Common.Attributes;
+
+namespace LMS.Common.Enums
+{
+ public class ResponseCodeEnum
+ {
+ public enum ResponseCode
+ {
+ #region 鎴愬姛
+
+ [Result("璇锋眰鎴愬姛")]
+ [Description("璇锋眰鎴愬姛")]
+ Success = 1,
+
+ #endregion
+
+ #region User 鎿嶄綔澶辫触
+
+ [Result(ResponseString.UndefinedLoginType)]
+ [Description(ResponseString.UndefinedLoginType)]
+ UndefinedLoginType = 1000,
+
+ [Result(ResponseString.UserNotFound)]
+ [Description("鏈壘鍒板搴旂敤鎴峰悕鐨勮处鍙")]
+ FindUserByNameFail = 1001,
+
+ [Result(ResponseString.UserPasswordError)]
+ [Description("鐢ㄦ埛瀵嗙爜閿欒")]
+ UserPasswordFail = 1002,
+
+ [Result(ResponseString.IdDateNotFound)]
+ [Description("鎸囧畾ID鐨勭敤鎴蜂笉瀛樺湪")]
+ FindUserByIdFail = 1003,
+
+ [Result(ResponseString.UserStatusError)]
+ [Description("鐢ㄦ埛鐨勭姸鎬侀敊璇紝鍙兘鐘舵佷负姝e父鐨勭敤鎴峰彲浠ョ櫥褰")]
+ UserStatusError = 1004,
+
+
+ [Result("鎸囧畾閭鐨勭敤鎴峰凡缁忓瓨鍦")]
+ [Description("鎸囧畾閭鐨勭敤鎴峰凡缁忓瓨鍦")]
+ UserEmailExist = 1005,
+
+ [Result("鎸囧畾鎵嬫満鍙风殑鐢ㄦ埛宸茬粡瀛樺湪")]
+ [Description("鎸囧畾鎵嬫満鍙风殑鐢ㄦ埛宸茬粡瀛樺湪")]
+ UserPhoneExist = 1006,
+
+ [Result("鎸囧畾閭鎴栨墜鏈哄彿鐨勭敤鎴峰凡缁忓瓨鍦")]
+ [Description("鎸囧畾閭鎴栨墜鏈哄彿鐨勭敤鎴峰凡缁忓瓨鍦")]
+ UserEmailOrPhoneExist = 1007,
+
+ [Result("鎸囧畾鐨勭敤鎴峰悕宸插瓨鍦")]
+ [Description("鎸囧畾鐨勭敤鎴峰悕宸插瓨鍦")]
+ UasrNameExist = 1008,
+
+ [Result("鎸囧畾鐨勭敤鎴锋樀绉板凡瀛樺湪")]
+ [Description("鎸囧畾鐨勭敤鎴锋樀绉板凡瀛樺湪")]
+ UserNickNameExist = 1009,
+
+ [Result(ResponseString.UserIsLockedOut)]
+ [Description(ResponseString.UserIsLockedOut)]
+ UserIsLockedOut = 1010,
+
+ [Result(ResponseString.UserLoginOut)]
+ [Description("鐢ㄦ埛鐨勫埛鏂颁护鐗屾棤鏁堬紝鍙兘鏄簩娆$櫥褰曪紝鎴栬呮槸鐧诲綍鍒版湡锛岃閲嶆柊鐧诲綍")]
+ RefreshTokenInvalid = 1011,
+
+ [Result("鐢ㄦ埛娉ㄥ唽澶辫触")]
+ [Description("鐢ㄦ埛娉ㄥ唽澶辫触")]
+ UserRegisterFial = 1012,
+
+ [Result("鐢ㄦ埛涓嶆槸VIP鐢ㄦ埛")]
+ [Description("鐢ㄦ埛涓嶆槸VIP鐢ㄦ埛")]
+ UserNotVip = 1013,
+
+ [Result("鏃犳晥鐨勯個璇风爜")]
+ [Description("鏃犳晥鐨勯個璇风爜")]
+ InvalidAffiliateCode = 1014,
+
+ #endregion
+
+ #region Machine 鎿嶄綔澶辫触
+
+ [Result(ResponseString.MachineStatusNotFoundOrStatusIsNot)]
+ [Description(ResponseString.MachineStatusNotFoundOrStatusIsNot)]
+ MachineNotFound = 2001,
+
+ [Result(ResponseString.IdDateNotFound)]
+ [Description("鎸囧畾ID鐨勬満鍣ㄧ爜涓嶅瓨鍦")]
+ FindMachineByIdFail = 2002,
+
+ [Result(ResponseString.DataExist)]
+ [Description("鎸囧畾鏈哄櫒鐮佸凡缁忓瓨鍦")]
+ MachineAlreadyExist = 2003,
+
+ #endregion
+
+ #region PermissionType 鎿嶄綔澶辫触
+
+ [Result(ResponseString.IdDateNotFound)]
+ [Description("鎸囧畾ID鐨勬潈闄愬垎绫绘病鏈夋壘鍒")]
+ FindPermissionTypeByIdFail = 3001,
+
+ [Result(ResponseString.DataExist)]
+ [Description("鎸囧畾ID鐨勬潈闄愬悕绉板拰缂栫爜宸茬粡瀛樺湪")]
+ PermissionTypeExist = 3002,
+
+
+ #endregion
+
+ #region 鏉冮檺鎿嶄綔澶辫触
+
+ [Result(ResponseString.NotPermissionAction)]
+ [Description(ResponseString.NotPermissionAction)]
+ NotPermissionAction = 4001,
+
+ [Result(ResponseString.DataExist)]
+ [Description("鎸囧畾鐢ㄦ埛ID鍜屾潈闄愬垎绫籌D宸插瓨鍦紝涓嶅彲鏂板")]
+ PermissionExist = 4002,
+
+ [Result(ResponseString.IdDateNotFound)]
+ [Description("鎸囧畾ID鐨勬潈闄愭病鏈夋壘鍒")]
+ FindPermissionByIdFail = 4003,
+
+ [Result("鏉冮檺缂栫爜宸插瓨鍦紝璇锋鏌")]
+ [Description("鏉冮檺缂栫爜宸插瓨鍦紝璇锋鏌")]
+ PermissionCodeExist = 4004,
+
+ #endregion
+
+ #region 绯荤粺鎶ラ敊
+
+ [Result(ResponseString.SystemError)]
+ [Description(ResponseString.SystemError)]
+ SystemError = 5000,
+
+ [Result(ResponseString.ParameterError)]
+ [Description(ResponseString.ParameterError)]
+ ParameterError = 5001,
+
+ [Result(ResponseString.InvalidOptions)]
+ [Description(ResponseString.InvalidOptions)]
+ InvalidOptions = 5002,
+ #endregion
+
+ #region 鎻愮ず璇嶆搷浣滃け璐
+
+ [Result(ResponseString.DataExist)]
+ [Description("鎸囧畾鐨勬彁绀鸿瘝宸茬粡瀛樺湪")]
+ PromptStringExist = 6001,
+
+ [Result(ResponseString.IdDateNotFound)]
+ [Description("鎸囧畾ID鐨勬彁绀鸿瘝娌℃湁鎵惧埌")]
+ FindPromptStringFail = 6002,
+
+ #endregion
+
+ #region 鎻愮ず璇嶇被鍨嬫搷浣滃け璐
+
+ [Result(ResponseString.DataExist)]
+ [Description("鎸囧畾鐨勬彁绀鸿瘝鐨勫悕绉版垨鑰呮槸缂栫爜宸插瓨鍦")]
+ PromptTypeExist = 7001,
+
+ [Result(ResponseString.IdDateNotFound)]
+ [Description("鎸囧畾ID鐨勬彁绀鸿瘝绫诲瀷娌℃湁鎵惧埌")]
+ FindPromptTypeFail = 7002,
+ #endregion
+
+ #region 鏂囨杞彂澶辫触
+
+ [Result(ResponseString.ForwardFail)]
+ [Description("鏂囨杞彂澶辫触")]
+ ForwardWordFail = 8001,
+
+ #endregion
+
+ #region 瑙掕壊鎿嶄綔澶辫触
+
+ [Result(ResponseString.DataExist)]
+ [Description("鎸囧畾鐨勮鑹插悕绉板凡缁忓瓨鍦")]
+ RoleNameExist = 9001,
+
+ [Result(ResponseString.IdDateNotFound)]
+ [Description("鎸囧畾ID鐨勮鑹蹭笉瀛樺湪")]
+ FindRoleByIdFail = 9002,
+
+ [Result(ResponseString.DataNotExist)]
+ [Description("鎸囧畾缂栫爜鐨勮鑹蹭笉瀛樺湪")]
+ FindRoleByCodeFail = 9003,
+
+ [Result(ResponseString.HasRelationship)]
+ [Description("鎸囧畾瑙掕壊宸茬粡缁戝畾浜嗙敤鎴凤紝鏃犳硶鍒犻櫎")]
+ RoleHasUser = 9004,
+
+ #endregion
+ }
+ }
+}
diff --git a/LMS.Common/Enum/ResponseString.cs b/LMS.Common/Enum/ResponseString.cs
new file mode 100644
index 0000000..69e8048
--- /dev/null
+++ b/LMS.Common/Enum/ResponseString.cs
@@ -0,0 +1,42 @@
+锘縩amespace LMS.Common.Enums
+{
+ public static class ResponseString
+ {
+ #region 鐢ㄦ埛鐩稿叧
+ public const string UndefinedLoginType = "鏈煡鐨勭櫥褰曠被鍨";
+
+ public const string UserNotFound = "鐢ㄦ埛鏈壘鍒帮紝璇峰厛娉ㄥ唽";
+
+ public const string UserIsLockedOut = "鐢ㄦ埛宸茶閿佸畾锛岃鑱旂郴绠$悊鍛";
+
+ public const string UserPasswordError = "妫鏌ヨ处鍙峰拰瀵嗙爜鏄惁姝g‘";
+
+ public const string UserLoginOut = "鐢ㄦ埛宸查鍑猴紝璇烽噸鏂扮櫥褰";
+
+ #endregion
+
+ public const string UserLogin = "妫鏌ヨ处鍙峰拰瀵嗙爜鏄惁姝g‘";
+ public const string UserEmailNotFound = "鏈壘鍒板搴旂敤鎴峰悕/閭鐨勮处鍙";
+ public const string UserStatusError = "鐢ㄦ埛鐨勭姸鎬侀敊璇";
+
+ public const string MachineStatusNotFoundOrStatusIsNot = "鏈壘鍒板搴旂殑鏈哄櫒鐮佹垨鑰呮槸鏈哄櫒鐮佸凡杩囨湡锛岃鑱旂郴寮鍙戞垨瀹㈡湇";
+
+ public const string SystemError = "绯荤粺閿欒";
+
+ public const string ParameterError = "鍙傛暟閿欒";
+
+ public const string InvalidOptions = "鏃犳晥鐨勬搷浣";
+
+ public const string IdDateNotFound = "鎸囧畾ID鐨勬暟鎹病鏈夋壘鍒";
+
+ public const string DataExist = "鏁版嵁宸插瓨鍦紝涓嶅彲鏂板";
+
+ public const string HasRelationship = "鏁版嵁瀛樺湪鍏宠仈锛岃鍏堝垹闄ゅ叧鑱";
+
+ public const string DataNotExist = "鏁版嵁涓嶅瓨鍦紝璇锋鏌";
+
+ public const string NotPermissionAction = "娌℃湁鎵ц璇ユ搷浣滅殑鏉冮檺";
+
+ public const string ForwardFail = "杞彂澶辫触";
+ }
+}
diff --git a/LMS.Common/Enum/UserStatus.cs b/LMS.Common/Enum/UserStatus.cs
new file mode 100644
index 0000000..89f10f9
--- /dev/null
+++ b/LMS.Common/Enum/UserStatus.cs
@@ -0,0 +1,31 @@
+锘縰sing LMS.Common.Attributes;
+
+namespace LMS.Common.Enums
+{
+ public class UserStatus
+ {
+ public enum UserStatusEnum
+ {
+ [Description("姝e父")]
+ Normal = 1,
+
+ [Description("绂佺敤")]
+ Disable = 0,
+
+ [Description("鍒犻櫎")]
+ Delete = 2,
+
+ [Description("榛戝悕鍗")]
+ BlackList = 3,
+
+ [Description("鏈縺娲")]
+ NotActive = 4,
+
+ [Description("杩濊")]
+ Violation = 5,
+
+ [Description("鏈煡")]
+ Unknown = 6
+ }
+ }
+}
diff --git a/LMS.Common/LMS.Common.csproj b/LMS.Common/LMS.Common.csproj
new file mode 100644
index 0000000..fa71b7a
--- /dev/null
+++ b/LMS.Common/LMS.Common.csproj
@@ -0,0 +1,9 @@
+锘
+
+
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/LMS.Common/RSAKey/AESGenerate.cs b/LMS.Common/RSAKey/AESGenerate.cs
new file mode 100644
index 0000000..d3d6d35
--- /dev/null
+++ b/LMS.Common/RSAKey/AESGenerate.cs
@@ -0,0 +1,37 @@
+锘縰sing System.Security.Cryptography;
+using System.Text;
+
+namespace LMS.Common.RSAKey
+{
+ public static class AESGenerate
+ {
+
+ public static string Encrypt(string plainText, byte[] key, byte[] iv)
+ {
+ using Aes aesAlg = Aes.Create();
+ aesAlg.Key = key;
+ aesAlg.IV = iv; // 浣跨敤鍏ㄩ浂鐨処V,瀹為檯浣跨敤鏃跺簲璇ヤ娇鐢ㄩ殢鏈篒V
+
+ ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
+
+ byte[] encrypted = encryptor.TransformFinalBlock(Encoding.UTF8.GetBytes(plainText), 0, plainText.Length);
+
+ return Convert.ToBase64String(encrypted);
+ }
+
+ public static string Decrypt(string cipherText, byte[] key, byte[] iv)
+ {
+ using Aes aesAlg = Aes.Create();
+ aesAlg.Key = key;
+ aesAlg.IV = iv; // 浣跨敤鍏ㄩ浂鐨処V,闇瑕佷笌鍔犲瘑鏃朵娇鐢ㄧ殑IV涓鑷
+
+ ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
+
+ byte[] cipher = Convert.FromBase64String(cipherText);
+ byte[] decrypted = decryptor.TransformFinalBlock(cipher, 0, cipher.Length);
+
+ return Encoding.UTF8.GetString(decrypted);
+ }
+
+ }
+}
diff --git a/LMS.Common/RSAKey/ComplexKeyObfuscator.cs b/LMS.Common/RSAKey/ComplexKeyObfuscator.cs
new file mode 100644
index 0000000..7ef4e01
--- /dev/null
+++ b/LMS.Common/RSAKey/ComplexKeyObfuscator.cs
@@ -0,0 +1,99 @@
+锘縰sing System.Security.Cryptography;
+
+namespace LMS.Common.RSAKey
+{
+ ///
+ /// 杩欐槸涓涓贩娣嗗櫒锛岀敤浜庡瀵嗛挜杩涜娣锋穯锛屼互澧炲姞鐮磋В闅惧害
+ ///
+ public static class ComplexKeyObfuscator
+ {
+ private const int SaltSize = 16;
+
+ ///
+ /// 娣锋穯鏂规硶
+ ///
+ ///
+ ///
+ ///
+ public static byte[] Obfuscate(byte[] key)
+ {
+ if (key == null || key.Length == 0)
+ throw new ArgumentException("Key cannot be null or empty");
+
+ byte[] salt = GenerateRandomSalt();
+ byte[] obfuscatedKey = new byte[key.Length];
+ Array.Copy(key, obfuscatedKey, key.Length);
+
+ // 澶氬眰娣锋穯鎿嶄綔
+ for (int i = 0; i < obfuscatedKey.Length; i++)
+ {
+ // 寮傛垨鎿嶄綔
+ obfuscatedKey[i] ^= salt[i % salt.Length];
+ obfuscatedKey[i] ^= (byte)((i * 17) % 256); // 浣跨敤璐ㄦ暟17
+ obfuscatedKey[i] ^= (byte)((obfuscatedKey.Length - i) % 256);
+
+ // 浣嶇Щ鎿嶄綔
+ obfuscatedKey[i] = (byte)(((obfuscatedKey[i] << 3) | (obfuscatedKey[i] >> 5)) & 0xFF);
+
+ // 鍩轰簬浣嶇疆鐨勭疆鎹
+ int newPos = (i * 7 + 5) % obfuscatedKey.Length; // 浣跨敤璐ㄦ暟7
+ byte temp = obfuscatedKey[i];
+ obfuscatedKey[i] = obfuscatedKey[newPos];
+ obfuscatedKey[newPos] = temp;
+ }
+
+ // 灏唖alt鍜屾贩娣嗗悗鐨勫瘑閽ュ悎骞
+ byte[] result = new byte[salt.Length + obfuscatedKey.Length];
+ Array.Copy(salt, 0, result, 0, salt.Length);
+ Array.Copy(obfuscatedKey, 0, result, salt.Length, obfuscatedKey.Length);
+
+ return result;
+ }
+
+ ///
+ /// 瑙e喅娣锋穯鏂规硶
+ ///
+ ///
+ ///
+ ///
+ public static byte[] Deobfuscate(byte[] obfuscatedData)
+ {
+ if (obfuscatedData == null || obfuscatedData.Length <= SaltSize)
+ throw new ArgumentException("Invalid obfuscated data");
+
+ byte[] salt = new byte[SaltSize];
+ byte[] obfuscatedKey = new byte[obfuscatedData.Length - SaltSize];
+
+ Array.Copy(obfuscatedData, 0, salt, 0, SaltSize);
+ Array.Copy(obfuscatedData, SaltSize, obfuscatedKey, 0, obfuscatedKey.Length);
+
+ // 鍙嶅悜澶氬眰娣锋穯鎿嶄綔
+ for (int i = obfuscatedKey.Length - 1; i >= 0; i--)
+ {
+ // 鍙嶅悜缃崲
+ int newPos = (i * 7 + 5) % obfuscatedKey.Length;
+ byte temp = obfuscatedKey[i];
+ obfuscatedKey[i] = obfuscatedKey[newPos];
+ obfuscatedKey[newPos] = temp;
+
+ // 鍙嶅悜浣嶇Щ鎿嶄綔
+ obfuscatedKey[i] = (byte)(((obfuscatedKey[i] >> 3) | (obfuscatedKey[i] << 5)) & 0xFF);
+
+ // 鍙嶅悜寮傛垨鎿嶄綔
+ obfuscatedKey[i] ^= (byte)((obfuscatedKey.Length - i) % 256);
+ obfuscatedKey[i] ^= (byte)((i * 17) % 256);
+ obfuscatedKey[i] ^= salt[i % salt.Length];
+ }
+
+ return obfuscatedKey;
+ }
+
+ private static byte[] GenerateRandomSalt()
+ {
+ using var rng = RandomNumberGenerator.Create();
+ byte[] salt = new byte[SaltSize];
+ rng.GetBytes(salt);
+ return salt;
+ }
+ }
+}
diff --git a/LMS.Common/RSAKey/RSAKeyGenerateModel.cs b/LMS.Common/RSAKey/RSAKeyGenerateModel.cs
new file mode 100644
index 0000000..792a209
--- /dev/null
+++ b/LMS.Common/RSAKey/RSAKeyGenerateModel.cs
@@ -0,0 +1,19 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LMS.Common.RSAKey
+{
+ public class RSAKeyGenerateModel
+ {
+ public string PublicKey { get; set; }
+
+ public string EncryptedPrivateKey { get; set; }
+
+ public string EncryptedKey { get; set; }
+
+ public string EncryptionIV { get; set; }
+ }
+}
diff --git a/LMS.Common/RSAKey/RsaKeyPairGenerator.cs b/LMS.Common/RSAKey/RsaKeyPairGenerator.cs
new file mode 100644
index 0000000..564ddb0
--- /dev/null
+++ b/LMS.Common/RSAKey/RsaKeyPairGenerator.cs
@@ -0,0 +1,131 @@
+锘縰sing LMS.Common.RSAKey;
+using System.Security.Cryptography;
+using System.Text;
+namespace LMS.Common.RSAKey
+{
+ public static class RsaKeyPairGenerator
+ {
+
+ ///
+ /// 鍒濆鍖栦竴涓猂SA瀵嗛挜瀵
+ ///
+ ///
+ public static RSAKeyGenerateModel InitRsaKey()
+ {
+ using RSACryptoServiceProvider rsa = new(2048);
+ string publicKeyPem = ExportPublicKeyToPem(rsa);
+ string privateKeyPem = ExportPrivateKeyToPem(rsa);
+
+ // 闅忔満鐢熸垚涓涓狝ES瀵嗛挜
+ byte[] aesKey = GenerateRandomAesKey(32);
+ byte[] aesIv = GenerateRandomAesKey(16);
+
+ // 閫氳繃闅忔満鐨勫瘑閽ュ紑濮婣ES鍔犲瘑绉侀挜
+ string encryptPrivateKey = AESGenerate.Encrypt(privateKeyPem, aesKey, aesIv);
+
+ return new RSAKeyGenerateModel
+ {
+ PublicKey = publicKeyPem,
+ EncryptedPrivateKey = encryptPrivateKey,
+ EncryptedKey = Convert.ToBase64String(ComplexKeyObfuscator.Obfuscate(aesKey)),
+ EncryptionIV = Convert.ToBase64String(ComplexKeyObfuscator.Obfuscate(aesIv))
+ };
+ }
+
+ private static byte[] GenerateRandomAesKey(int bits)
+ {
+ using var randomNumberGenerator = RandomNumberGenerator.Create();
+ var randomBytes = new byte[bits]; // 256 bits
+ randomNumberGenerator.GetBytes(randomBytes);
+ return randomBytes;
+ }
+
+ public static void GenerateRsaKeyPair()
+ {
+ using RSACryptoServiceProvider rsa = new(2048);
+
+ string publicKeyPem = ExportPublicKeyToPem(rsa);
+ string privateKeyPem = ExportPrivateKeyToPem(rsa);
+
+ Console.WriteLine("鍏挜 (PEM)锛歕n" + publicKeyPem);
+ Console.WriteLine("绉侀挜 (PEM)锛歕n" + privateKeyPem);
+
+ Console.WriteLine();
+ string original = "Hello, RSA!";
+ var encrypted = Encrypt(publicKeyPem, original);
+ Console.WriteLine("Encrypted: " + encrypted);
+
+ Console.WriteLine();
+ var decrypted = Decrypt(privateKeyPem, encrypted);
+ Console.WriteLine("Decrypted: " + decrypted);
+
+ var signData = SignData(privateKeyPem, original);
+ Console.WriteLine("SignData: " + signData);
+
+ var isVerify = VerifySignData(publicKeyPem, original, signData);
+ Console.WriteLine("VerifySign: " + isVerify);
+ }
+
+ private static string ExportPublicKeyToPem(RSA rsa)
+ {
+ var publicKey = rsa.ExportSubjectPublicKeyInfo();
+ var base64 = Convert.ToBase64String(publicKey);
+ return $"-----BEGIN PUBLIC KEY-----\n{InsertNewLines(base64)}\n-----END PUBLIC KEY-----";
+ }
+
+ private static string ExportPrivateKeyToPem(RSA rsa)
+ {
+ var privateKey = rsa.ExportPkcs8PrivateKey();
+ var base64 = Convert.ToBase64String(privateKey);
+ return $"-----BEGIN PRIVATE KEY-----\n{InsertNewLines(base64)}\n-----END PRIVATE KEY-----";
+ }
+
+ private static string InsertNewLines(string input)
+ {
+ return string.Join("\n", Enumerable.Range(0, input.Length / 64 + 1)
+ .Select(i => input.Substring(i * 64, Math.Min(64, input.Length - i * 64))));
+ }
+
+ public static string Encrypt(string publicKeyPem, string data)
+ {
+ using (var rsa = RSA.Create())
+ {
+ rsa.ImportFromPem(publicKeyPem);
+ byte[] encryptedData = rsa.Encrypt(Encoding.UTF8.GetBytes(data), RSAEncryptionPadding.OaepSHA256);
+ return Convert.ToBase64String(encryptedData);
+ }
+ }
+
+ public static string Decrypt(string privateKeyPem, string data)
+ {
+ using (var rsa = RSA.Create())
+ {
+ rsa.ImportFromPem(privateKeyPem);
+ byte[] decryptedData = rsa.Decrypt(Convert.FromBase64String(data), RSAEncryptionPadding.OaepSHA256);
+ return Encoding.UTF8.GetString(decryptedData);
+ }
+ }
+
+ public static string SignData(string privateKeyPem, string data)
+ {
+ using (var rsa = RSA.Create())
+ {
+ rsa.ImportFromPem(privateKeyPem);
+ var inputBytes = Encoding.UTF8.GetBytes(data);
+ var resultBytes = rsa.SignData(inputBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
+ return Convert.ToBase64String(resultBytes);
+ }
+ }
+
+ public static bool VerifySignData(string publicKeyPem, string data, string sign)
+ {
+ using (var rsa = RSA.Create())
+ {
+ rsa.ImportFromPem(publicKeyPem);
+ var dataBytes = Encoding.UTF8.GetBytes(data);
+ var signBytes = Convert.FromBase64String(sign);
+ return rsa.VerifyData(dataBytes, signBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
+ }
+ }
+ }
+}
diff --git a/LMS.DAO/ApplicationDbContext.cs b/LMS.DAO/ApplicationDbContext.cs
new file mode 100644
index 0000000..565791f
--- /dev/null
+++ b/LMS.DAO/ApplicationDbContext.cs
@@ -0,0 +1,46 @@
+锘
+
+using LMS.Repository.DB;
+using LMS.Repository.Models.DB;
+using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore;
+using System.Text.Json;
+
+namespace LMS.DAO
+{
+ public class ApplicationDbContext : IdentityDbContext
+ {
+ public ApplicationDbContext(DbContextOptions options) : base(options) { }
+
+ //public DbSet Prompt { get; set; }
+
+ //public DbSet PromptType { get; set; }
+
+ public DbSet Permission { get; set; }
+
+ public DbSet PermissionType { get; set; }
+
+ public DbSet Machine { get; set; }
+
+ public DbSet RefreshTokens { get; set; }
+
+ public DbSet ApiEndpoints { get; set; }
+
+ public DbSet RsaKeys { get; set; }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+ modelBuilder.Entity()
+ .Property(a => a.RequiredPermissionIds)
+ .HasConversion(
+ v => string.IsNullOrEmpty(JsonSerializer.Serialize(v, (JsonSerializerOptions?)null))
+ ? "[]" // 濡傛灉搴忓垪鍖栫粨鏋滀负绌猴紝鍒欏瓨鍌ㄧ┖鏁扮粍
+ : JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
+ v => string.IsNullOrEmpty(v) || v == "[]"
+ ? new List() // 濡傛灉瀛樺偍鐨勬槸绌哄瓧绗︿覆鎴栫┖鏁扮粍锛屽垯杩斿洖绌哄垪琛
+ : JsonSerializer.Deserialize>(v, (JsonSerializerOptions?)null) ?? new List()
+ );
+ }
+ }
+}
diff --git a/LMS.DAO/LMS.DAO.csproj b/LMS.DAO/LMS.DAO.csproj
new file mode 100644
index 0000000..c3d9456
--- /dev/null
+++ b/LMS.DAO/LMS.DAO.csproj
@@ -0,0 +1,21 @@
+锘
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LMS.DAO/MachineDAO/MachineBasicDao.cs b/LMS.DAO/MachineDAO/MachineBasicDao.cs
new file mode 100644
index 0000000..2f6ff0d
--- /dev/null
+++ b/LMS.DAO/MachineDAO/MachineBasicDao.cs
@@ -0,0 +1,43 @@
+锘縰sing Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LMS.DAO.MachineDAO
+{
+ public class MachineBasicDao(ApplicationDbContext context)
+ {
+ private readonly ApplicationDbContext _context = context;
+
+ ///
+ /// 妫鏌ユ満鍣ㄧ爜鏄惁瀛樺湪锛堟満鍣ㄧ爜锛屼笉鏄搴旂殑ID锛
+ ///
+ ///
+ ///
+ public async Task CheckMachineByMachineId(string? machineId)
+ {
+ if (string.IsNullOrWhiteSpace(machineId))
+ {
+ return false;
+ }
+ return await _context.Machine.AnyAsync(x => x.MachineId == machineId);
+ }
+
+
+ ///
+ /// 妫鏌ユ満鍣ㄧ爜鏄惁瀛樺湪锛堟満鍣ㄧ爜锛屽搴旂殑ID锛
+ ///
+ ///
+ ///
+ public async Task CheckMachineById(string Id)
+ {
+ if (string.IsNullOrWhiteSpace(Id))
+ {
+ return false;
+ }
+ return await _context.Machine.AnyAsync(x => x.Id == Id);
+ }
+ }
+}
diff --git a/LMS.DAO/MyDbcontextDesignFactory.cs b/LMS.DAO/MyDbcontextDesignFactory.cs
new file mode 100644
index 0000000..307d16b
--- /dev/null
+++ b/LMS.DAO/MyDbcontextDesignFactory.cs
@@ -0,0 +1,26 @@
+锘縰sing Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Design;
+
+namespace LMS.DAO
+{
+ public class MyDbcontextDesignFactory : IDesignTimeDbContextFactory
+ {
+ //public MyDbcontextDesignFactory CreateDbContext(string[] args)
+ //{
+ // DbContextOptionsBuilder optionsBuilder = new DbContextOptionsBuilder();
+ // string str = Environment.GetEnvironmentVariable("CONNECTION_STRING");
+ // optionsBuilder.UseMySql(str, ServerVersion.Parse("8.0.18-mysql"));
+ // ApplicationDbContext db = new ApplicationDbContext(optionsBuilder.Options);
+ // return db;
+ //}
+
+ public ApplicationDbContext CreateDbContext(string[] args)
+ {
+ DbContextOptionsBuilder optionsBuilder = new DbContextOptionsBuilder();
+ string str = "server=123.129.219.240;port=14080;user=luo;password=Luoqiang1405;database=LMS_TEST";
+ optionsBuilder.UseMySql(str, ServerVersion.Parse("8.0.18-mysql"));
+ ApplicationDbContext db = new ApplicationDbContext(optionsBuilder.Options);
+ return db;
+ }
+ }
+}
diff --git a/LMS.DAO/PermissionDAO/PermissionBasicDao.cs b/LMS.DAO/PermissionDAO/PermissionBasicDao.cs
new file mode 100644
index 0000000..4493494
--- /dev/null
+++ b/LMS.DAO/PermissionDAO/PermissionBasicDao.cs
@@ -0,0 +1,117 @@
+锘縰sing Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Primitives;
+using OneOf;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using static LMS.Common.Enums.PermissionEnum;
+
+namespace LMS.DAO.PermissionDAO
+{
+ public class PermissionBasicDao(ApplicationDbContext context)
+ {
+ private readonly ApplicationDbContext _context = context;
+
+ ///
+ /// 鍒ゆ柇鎸囧畾鐨処D鐨勬潈闄愭槸涓嶆槸瀛樺湪
+ ///
+ ///
+ ///
+ public async Task CheckPermissionExistById(string id)
+ {
+ if (string.IsNullOrWhiteSpace(id))
+ {
+ return false;
+ }
+ return await _context.Permission.AnyAsync(x => x.Id == id);
+ }
+
+ ///
+ /// 鍒ゆ柇鏉冮檺鐨凱ermissionCode鏄笉鏄瓨鍦
+ /// 閫氳繃鍒ゆ柇鏄笉鏄湁浼犻扞D , 鍒ゆ柇鏄笉鏄渶瑕佹帓闄ゅ綋鍓嶇殑鏁版嵁
+ ///
+ ///
+ ///
+ ///
+ public async Task CheckPermissionCodeExist(string permissionCode, string id = null)
+ {
+ if (string.IsNullOrWhiteSpace(permissionCode))
+ {
+ throw new ArgumentNullException(nameof(permissionCode));
+ }
+
+ if (string.IsNullOrEmpty(id))
+ {
+ return await _context.Permission.AnyAsync(x => x.PermissionCode == permissionCode);
+ }
+ else
+ {
+ return await _context.Permission.AnyAsync(x => x.PermissionCode == permissionCode && x.Id != id);
+ }
+ }
+
+ ///
+ /// 妫鏌ュ搴斿垎绫荤殑鏉冮檺鏄笉鏄瓨鍦
+ ///
+ ///
+ ///
+ /// 鍐嶄慨鏀圭殑鏃跺欏繀浼犺繖涓硷紝鐢ㄤ簬鍒ゆ柇瀵瑰簲鐨勫叧鑱擨D鏄笉鏄湁鍏朵粬鐨勫硷紝鏈夌殑璇濅笉鑳戒慨鏀
+ ///
+ ///
+ public async Task CheckPermissionByTypeAndId(PType type, OneOf id, string pid = null)
+ {
+ if (id.IsT0)
+ {
+ if (type != PType.Machine)
+ {
+ throw new Exception("璇锋鏌ュ弬鏁扮殑瀵瑰簲鍏崇郴");
+ }
+ if (!string.IsNullOrEmpty(pid))
+ {
+ return await _context.Permission.AnyAsync(x => x.MachineId == id.AsT0 && x.Type == type && x.Id != pid);
+ }
+ else
+ {
+ return await _context.Permission.AnyAsync(x => x.MachineId == id.AsT0 && x.Type == type);
+ }
+ }
+ else if (id.IsT1)
+ {
+ if (type == PType.Machine)
+ {
+ throw new Exception("璇锋鏌ュ弬鏁扮殑瀵瑰簲鍏崇郴");
+ }
+ if (id.AsT1 == null)
+ {
+ return false;
+ }
+ if (!string.IsNullOrEmpty(pid))
+ {
+ return type switch
+ {
+ PType.User => await _context.Permission.AnyAsync(x => x.UserId == id.AsT1 && x.Type == type && x.Id != pid),
+ PType.Role => await _context.Permission.AnyAsync(x => x.RoleId == id.AsT1 && x.Type == type && x.Id != pid),
+ PType.Machine => throw new Exception("璇锋鏌ュ弬鏁扮殑瀵瑰簲鍏崇郴"),
+ _ => throw new Exception("鍙傛暟绫诲瀷閿欒"),
+ };
+ }
+ else
+ {
+ return type switch
+ {
+ PType.User => await _context.Permission.AnyAsync(x => x.UserId == id.AsT1 && x.Type == type),
+ PType.Role => await _context.Permission.AnyAsync(x => x.RoleId == id.AsT1 && x.Type == type),
+ PType.Machine => throw new Exception("璇锋鏌ュ弬鏁扮殑瀵瑰簲鍏崇郴"),
+ _ => throw new Exception("鍙傛暟绫诲瀷閿欒"),
+ };
+ }
+ }
+ else
+ {
+ throw new Exception("鍙傛暟绫诲瀷閿欒");
+ }
+ }
+ }
+}
diff --git a/LMS.DAO/PermissionDAO/PermissionTypeDao.cs b/LMS.DAO/PermissionDAO/PermissionTypeDao.cs
new file mode 100644
index 0000000..937a27f
--- /dev/null
+++ b/LMS.DAO/PermissionDAO/PermissionTypeDao.cs
@@ -0,0 +1,55 @@
+锘縰sing Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using static LMS.Common.Enums.ResponseCodeEnum;
+
+namespace LMS.DAO.PermissionDAO
+{
+ public class PermissionTypeDao(ApplicationDbContext context)
+ {
+ private readonly ApplicationDbContext _context = context;
+
+ ///
+ /// 鍒ゆ柇鏉冮檺绫诲瀷ID鏁扮粍涓殑鏁版嵁鏄笉鏄兘瀛樺湪鏁版嵁搴撲腑
+ ///
+ ///
+ ///
+ public async Task CheckPermissionTypeIdsExist(List ids)
+ {
+ foreach (var id in ids)
+ {
+ if (!await _context.PermissionType.AnyAsync(x => x.Id == id))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// 妫鏌ユ潈闄愮被鍨嬬殑Code鏄笉鏄瓨鍦
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task CheckPermissionTypeCodeExist(string Code, string Id = null)
+ {
+ if (string.IsNullOrWhiteSpace(Code))
+ {
+ throw new ArgumentNullException(nameof(Code));
+ }
+ if (string.IsNullOrWhiteSpace(Id))
+ {
+ return await _context.PermissionType.AnyAsync(x => x.Code == Code);
+ }
+ else
+ {
+ return await _context.PermissionType.AnyAsync(x => x.Code == Code && x.Id != Id);
+ }
+ }
+ }
+}
diff --git a/LMS.DAO/RoleDAO/RoleBasicDao.cs b/LMS.DAO/RoleDAO/RoleBasicDao.cs
new file mode 100644
index 0000000..cc69761
--- /dev/null
+++ b/LMS.DAO/RoleDAO/RoleBasicDao.cs
@@ -0,0 +1,28 @@
+锘縰sing LMS.Repository.Models.DB;
+using Microsoft.AspNetCore.Identity;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LMS.DAO.RoleDAO
+{
+ public class RoleBasicDao(ApplicationDbContext context, RoleManager roleManager)
+ {
+ private readonly ApplicationDbContext _context = context;
+ private readonly RoleManager _roleManager = roleManager;
+
+ ///
+ /// 妫鏌ヨ鑹叉槸涓嶆槸瀛樺湪
+ ///
+ ///
+ ///
+ public async Task CheckRoleExistById(long? roleId)
+ {
+ if (roleId == null)
+ return false;
+ return await _roleManager.FindByIdAsync(roleId.ToString()) != null;
+ }
+ }
+}
diff --git a/LMS.DAO/UserDAO/UserBasicDAO.cs b/LMS.DAO/UserDAO/UserBasicDAO.cs
new file mode 100644
index 0000000..f8cdea4
--- /dev/null
+++ b/LMS.DAO/UserDAO/UserBasicDAO.cs
@@ -0,0 +1,29 @@
+锘縰sing LMS.Repository.Models.DB;
+using Microsoft.AspNetCore.Identity;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LMS.DAO.UserDAO
+{
+ public class UserBasicDao(UserManager userManager)
+ {
+ private readonly UserManager _userManager = userManager;
+ ///
+ /// 妫鏌ョ敤鎴锋槸鍚﹀瓨鍦,閫氳繃鐢ㄦ埛ID
+ ///
+ ///
+ ///
+ public async Task CheckUserExistsByID(long? userId)
+ {
+ if (userId == null)
+ {
+ return false;
+ }
+ return await _userManager.FindByIdAsync(userId.ToString()) != null;
+ }
+ }
+
+}
diff --git a/LMS.Repository/DB/ApiEndpoints.cs b/LMS.Repository/DB/ApiEndpoints.cs
new file mode 100644
index 0000000..52212f6
--- /dev/null
+++ b/LMS.Repository/DB/ApiEndpoints.cs
@@ -0,0 +1,22 @@
+锘縰sing LMS.Tools.Extensions;
+
+namespace LMS.Repository.Models.DB
+{
+ public class ApiEndpoints
+ {
+
+ public string Id { get; set; }
+
+ public string HttpMethod { get; set; }
+
+ public string Path { get; set; }
+
+ public DateTime CreateTime { get; set; } = BeijingTimeExtension.GetBeijingTime();
+
+ public List RequiredPermissionIds { get; set; }
+
+ public long CreatedId { get; set; }
+
+ public long UpdatedId { get; set; }
+ }
+}
diff --git a/LMS.Repository/DB/Machine.cs b/LMS.Repository/DB/Machine.cs
new file mode 100644
index 0000000..c010ac1
--- /dev/null
+++ b/LMS.Repository/DB/Machine.cs
@@ -0,0 +1,62 @@
+锘縰sing static LMS.Common.Enums.MachineEnum;
+
+namespace LMS.Repository.Models.DB
+{
+ public class Machine
+ {
+ ///
+ /// ID 涓婚敭
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// 鏈哄櫒ID
+ ///
+ public string MachineId { get; set; }
+
+ ///
+ /// 鍒涘缓鏃堕棿
+ ///
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 鏇存柊鏃堕棿
+ ///
+ public DateTime UpdateTime { get; set; }
+
+ ///
+ /// 鍋滅敤鏃堕棿
+ ///
+ public DateTime? DeactivationTime { get; set; }
+
+ ///
+ /// 鐘舵侊紙鏄惁鍙敤锛
+ ///
+ public MachineStatus Status { get; set; }
+
+ ///
+ /// 鍒涘缓鑰匢D
+ ///
+ public long CreateId { get; set; }
+
+ ///
+ /// 鏇存柊鑰匢D
+ ///
+ public long UpdateId { get; set; }
+
+ ///
+ /// 浣跨敤鐘舵(璇曠敤锛屾案涔)
+ ///
+ public MachineUseStatus UseStatus { get; set; }
+
+ ///
+ /// 澶囨敞
+ ///
+ public string? Remark { get; set; }
+
+ ///
+ /// 鎵灞炵敤鎴稩D
+ ///
+ public required long UserID { get; set; }
+ }
+}
diff --git a/LMS.Repository/DB/Permission.cs b/LMS.Repository/DB/Permission.cs
new file mode 100644
index 0000000..1409a9a
--- /dev/null
+++ b/LMS.Repository/DB/Permission.cs
@@ -0,0 +1,82 @@
+锘縰sing LMS.Common.Enums;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Text.Json;
+using static LMS.Common.Enums.PermissionEnum;
+
+namespace LMS.Repository.Models.DB
+{
+ ///
+ /// 鎵鏈夌殑鏉冮檺闆嗗悎
+ ///
+ public class Permission
+ {
+ ///
+ /// 鏉冮檺鐨処D
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// 鐢ㄦ埛鐨処D
+ ///
+ public long? UserId { get; set; }
+
+ ///
+ /// 鏈哄櫒鐮佺殑ID锛堟槸ID锛屼笉鏄満鍣ㄧ爜锛
+ ///
+ public string? MachineId { get; set; }
+
+ ///
+ /// 瑙掕壊ID
+ ///
+ public long? RoleId { get; set; }
+
+ ///
+ /// 鏉冮檺绫诲瀷鐨処D锛堝瓙鏉冮檺锛
+ ///
+ [Column(TypeName = "json")]
+ public string PermissionTypeIds { get; set; }
+
+ ///
+ /// 鏉冮檺瀵瑰簲鐨凜ode
+ ///
+ public string PermissionCode { get; set; }
+
+ ///
+ /// 鏉冮檺绫诲瀷
+ ///
+ public PType Type { get; set; }
+
+ ///
+ /// 鍒涘缓浜篒D
+ ///
+ public long CreateUserId { get; set; }
+
+ ///
+ /// 鏇存柊浜篒D
+ ///
+ public long UpdateUserId { get; set; }
+
+ ///
+ /// 鍒涘缓鏃堕棿
+ ///
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 鏇存柊鏃堕棿
+ ///
+ public DateTime UpdateTime { get; set; }
+
+
+ ///
+ /// 澶囨敞
+ ///
+ public string Remark { get; set; }
+
+ [NotMapped]
+ public List PermissionTypeIdsJson
+ {
+ get => JsonSerializer.Deserialize>(PermissionTypeIds) ?? [];
+ set => PermissionTypeIds = JsonSerializer.Serialize(value);
+ }
+ }
+}
diff --git a/LMS.Repository/DB/PermissionType.cs b/LMS.Repository/DB/PermissionType.cs
new file mode 100644
index 0000000..f777d9c
--- /dev/null
+++ b/LMS.Repository/DB/PermissionType.cs
@@ -0,0 +1,56 @@
+锘縰sing LMS.Common.Enums;
+using static LMS.Common.Enums.PermissionEnum;
+
+namespace LMS.Repository.Models.DB
+{
+ ///
+ /// 瀛樻斁鏉冮檺鐨勮〃
+ ///
+ public class PermissionType
+ {
+ ///
+ /// 鏉冮檺ID
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// 鏉冮檺鐨勫悕瀛
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// 琛ㄧず鏉冮檺鐨勪唬鐮
+ ///
+ public string Code { get; set; }
+
+ ///
+ /// 鏉冮檺鐨勫垎绫伙紙user鍜宮achine锛
+ ///
+ public PermissionEnum.PermissionType Type { get; set; }
+
+ ///
+ /// 鍒涘缓鑰匢D
+ ///
+ public long CreateUserId { get; set; }
+
+ ///
+ /// 鍒涘缓鏃堕棿
+ ///
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 鏇存柊鑰匢D
+ ///
+ public long UpdateUserId { get; set; }
+
+ ///
+ /// 鏇存柊鏉冮檺鐨勬椂闂
+ ///
+ public DateTime UpdateTime { get; set; }
+
+ ///
+ /// 鏉冮檺鐨勬弿杩
+ ///
+ public string? Remark { get; set; }
+ }
+}
diff --git a/LMS.Repository/DB/Prompt.cs b/LMS.Repository/DB/Prompt.cs
new file mode 100644
index 0000000..afaa291
--- /dev/null
+++ b/LMS.Repository/DB/Prompt.cs
@@ -0,0 +1,71 @@
+锘縩amespace LMS.Repository.Models.DB
+{
+ public class Prompt
+ {
+ ///
+ /// ID
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// 鎻愮ず璇嶉璁剧殑鍚嶇О
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// 鎻愮ず璇嶇殑绫诲瀷ID
+ ///
+ public string PromptTypeId { get; set; }
+
+ ///
+ /// 鎻愮ず璇嶇殑绫诲瀷缂栫爜
+ ///
+ public string PromptTypeCode { get; set; }
+
+ ///
+ /// 鎻愮ず璇嶉璁惧瓧绗︿覆
+ ///
+ public string PromptString { get; set; }
+
+ ///
+ /// 褰撳墠鐗堟湰
+ ///
+ public int Version { get; set; }
+
+ ///
+ /// 鐘舵
+ ///
+ public string Status { get; set; }
+
+ ///
+ /// 鎻愮ず璇嶇殑鎻忚堪
+ ///
+ public string? Description { get; set; }
+
+ ///
+ /// 鍒涘缓鑰
+ ///
+ public string CreateUserId { get; set; }
+
+ ///
+ /// 鍒涘缓鏃堕棿
+ ///
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 鏇存柊鑰
+ ///
+ public string UpdateUserId { get; set; }
+
+ ///
+ /// 鏇存柊鏃堕棿
+ ///
+ public DateTime UpdateTime { get; set; }
+
+ ///
+ /// 澶囨敞
+ ///
+ public string? Remark { get; set; }
+
+ }
+}
diff --git a/LMS.Repository/DB/PromptType.cs b/LMS.Repository/DB/PromptType.cs
new file mode 100644
index 0000000..f204e63
--- /dev/null
+++ b/LMS.Repository/DB/PromptType.cs
@@ -0,0 +1,61 @@
+锘縩amespace LMS.Repository.Models.DB
+{
+ ///
+ /// 鎻愮ず璇嶇被鍨嬬殑搴
+ ///
+ public class PromptType
+ {
+ ///
+ /// ID
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// 鎻愮ず璇嶇被鍨嬬紪鐮
+ ///
+ public string Code { get; set; }
+
+ ///
+ /// 鎻愮ず璇嶇被鍨嬪悕绉
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// 鎻愮ず璇嶇被鍨嬫弿杩
+ ///
+ public string? Remark { get; set; }
+
+ ///
+ /// 鎻愮ず璇嶇被鍨嬬姸鎬
+ ///
+ public string Status { get; set; }
+
+ ///
+ /// 鏄惁鍒犻櫎
+ ///
+ public bool IsDeleted { get; set; }
+
+ ///
+ /// 鍒涘缓鐢ㄦ埛ID
+ ///
+ public string CreateUserId { get; set; }
+
+ ///
+ /// 鍒涘缓鏃堕棿
+ ///
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 鏇存柊鑰匢D
+ ///
+ public string UpdateUserId { get; set; }
+
+ ///
+ /// 鏇存柊鏃堕棿
+ ///
+ public DateTime UpdateTime { get; set; }
+
+
+
+ }
+}
diff --git a/LMS.Repository/DB/RefreshTokens.cs b/LMS.Repository/DB/RefreshTokens.cs
new file mode 100644
index 0000000..bba94e8
--- /dev/null
+++ b/LMS.Repository/DB/RefreshTokens.cs
@@ -0,0 +1,46 @@
+锘縩amespace LMS.Repository.Models.DB
+{
+ public class RefreshTokens
+ {
+ ///
+ /// 涓婚敭 ID
+ ///
+ public required string Id { get; set; }
+
+ ///
+ /// 鐢ㄦ埛ID
+ ///
+ public required long UserId { get; set; }
+
+ ///
+ /// Token
+ ///
+ public required string Token { get; set; }
+
+ ///
+ /// 鍒版湡鏃堕棿
+ ///
+ public DateTime Expiration { get; set; }
+
+ ///
+ /// 鏄笉鏄け鏁
+ ///
+ public Boolean Revoked { get; set; }
+
+ ///
+ /// 鍒涘缓鏃堕棿
+ ///
+ public DateTime CreatedTime { get; set; }
+
+ ///
+ /// 涓婃鏍¢獙IP
+ ///
+ public required string LastCheckIp { get; set; }
+
+ ///
+ /// 璁惧淇℃伅锛屾祻瑙堝櫒淇℃伅绛
+ ///
+ public required string DeviceInfo { get; set; }
+
+ }
+}
diff --git a/LMS.Repository/DB/Role.cs b/LMS.Repository/DB/Role.cs
new file mode 100644
index 0000000..b4b1f52
--- /dev/null
+++ b/LMS.Repository/DB/Role.cs
@@ -0,0 +1,18 @@
+锘縰sing LMS.Tools.Extensions;
+using Microsoft.AspNetCore.Identity;
+
+namespace LMS.Repository.Models.DB
+{
+ public class Role : IdentityRole
+ {
+ public long CreatedUserId { get; set; }
+
+ public long UpdatedUserId { get; set; }
+
+ public DateTime CreatedTime { get; set; }
+
+ public DateTime UpdatedTime { get; set; }
+
+ public string? Remark { get; set; } = string.Empty;
+ }
+}
diff --git a/LMS.Repository/DB/RsaKeys.cs b/LMS.Repository/DB/RsaKeys.cs
new file mode 100644
index 0000000..a57bdd9
--- /dev/null
+++ b/LMS.Repository/DB/RsaKeys.cs
@@ -0,0 +1,57 @@
+锘縰sing LMS.Tools.Extensions;
+
+namespace LMS.Repository.DB
+{
+ public class RsaKeys
+ {
+ ///
+ /// ID 涓婚敭
+ ///
+ public required string Id { get; set; }
+
+ ///
+ /// 浣跨敤娆℃暟
+ ///
+ public int UseCount { get; set; }
+
+ ///
+ /// 鍏挜
+ ///
+ public required string PublicKey { get; set; }
+
+ ///
+ /// 鍔犲瘑鍚庣殑绉侀挜
+ ///
+ public required string EncryptedPrivateKey { get; set; }
+
+ ///
+ /// 鍔犲瘑绉侀挜鐨勯殢鏈哄瓧绗︿覆
+ ///
+ public required string EncryptionKey { get; set; } // 鍔犲瘑绉侀挜鐨勯殢鏈哄瓧绗︿覆
+
+ ///
+ /// 鍔犲瘑绉侀挜鐨勯殢鏈篒V
+ ///
+ public required string EncryptionIV { get; set; } // 鍔犲瘑绉侀挜鐨勯殢鏈哄瓧绗︿覆
+
+ ///
+ /// Key鐨勭増鏈
+ ///
+ public int KeyVersion { get; set; }
+
+ ///
+ /// 鍒涘缓鏃堕棿
+ ///
+ public DateTime CreatedTime { get; set; } = BeijingTimeExtension.GetBeijingTime();
+
+ ///
+ /// 涓婃浣跨敤鐨勬椂闂
+ ///
+ public DateTime? LastUsed { get; set; }
+
+ ///
+ /// 鍒版湡鏃堕棿
+ ///
+ public DateTime ExpirationTime { get; set; }
+ }
+}
diff --git a/LMS.Repository/DB/User.cs b/LMS.Repository/DB/User.cs
new file mode 100644
index 0000000..9ecffd5
--- /dev/null
+++ b/LMS.Repository/DB/User.cs
@@ -0,0 +1,69 @@
+锘縰sing LMS.Repository.User;
+using Microsoft.AspNetCore.Identity;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Text.Json;
+
+namespace LMS.Repository.Models.DB
+{
+ public class User : IdentityUser
+ {
+ [MaxLength(50)]
+ public string NickName { get; set; }
+
+ ///
+ /// 鍏佽浣跨敤鐨勬満鍣ㄧ爜鏁伴噺
+ ///
+ public long AllDeviceCount { get; set; } = 1;
+
+ ///
+ /// 浠g悊鍒嗘垚姣斾緥
+ ///
+ public double AgentPercent { get; set; } = 0.00;
+
+ ///
+ /// 鍏嶈垂淇敼鏈哄櫒鐮佹鏁
+ ///
+ public long FreeCount { get; set; } = 0;
+
+ ///
+ /// 鐢ㄦ埛鐨勪竴浜涚畝鍗曠殑鎿嶄綔
+ ///
+ [Column(TypeName = "json")]
+ public string? Options { get; set; } = "{}";
+
+ [Column(TypeName = "datetime")]
+ public DateTime CreatedDate { get; set; } = DateTime.Now;
+
+ [Column(TypeName = "datetime")]
+ public DateTime UpdatedDate { get; set; } = DateTime.Now;
+
+ [Column(TypeName = "datetime")]
+ public DateTime LastLoginDate { get; set; } = DateTime.Now;
+
+ public string? LastLoginIp { get; set; } = "";
+
+ public string? LastLoginDevice { get; set; } = "";
+
+ ///
+ /// 涓婄骇ID
+ ///
+ public long? ParentId { get; set; }
+
+ ///
+ /// 鎺ㄥ箍鐮
+ ///
+ public string AffiliateCode { get; set; } = string.Empty;
+
+ ///
+ /// 瀹為檯浣跨敤鐨凮ptions
+ ///
+ [NotMapped]
+ public UserPrivateOptions OptionsJson
+ {
+ get => JsonSerializer.Deserialize(Options ?? "{}") ?? new UserPrivateOptions();
+ set => Options = JsonSerializer.Serialize(value);
+ }
+
+ }
+}
diff --git a/LMS.Repository/DB/UserRoles.cs b/LMS.Repository/DB/UserRoles.cs
new file mode 100644
index 0000000..33ee785
--- /dev/null
+++ b/LMS.Repository/DB/UserRoles.cs
@@ -0,0 +1,11 @@
+锘縩amespace LMS.Repository.Models.DB
+{
+ public class UserRoles
+ {
+
+ public required string RoleId { get; set; }
+
+ public required string UserId { get; set; }
+
+ }
+}
diff --git a/LMS.Repository/DTO/CollectionResponse.cs b/LMS.Repository/DTO/CollectionResponse.cs
new file mode 100644
index 0000000..51d76a8
--- /dev/null
+++ b/LMS.Repository/DTO/CollectionResponse.cs
@@ -0,0 +1,19 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LMS.Repository.DTO
+{
+ public class CollectionResponse
+ {
+
+ public int Current { get; set; }
+
+ public int Total { get; set; }
+
+ public List Collection { get; set; } = new List();
+
+ }
+}
diff --git a/LMS.Repository/DTO/MachineDetailDto.cs b/LMS.Repository/DTO/MachineDetailDto.cs
new file mode 100644
index 0000000..5f99351
--- /dev/null
+++ b/LMS.Repository/DTO/MachineDetailDto.cs
@@ -0,0 +1,14 @@
+锘縰sing LMS.Repository.DTO.UserDto;
+using LMS.Repository.Models.DB;
+
+namespace LMS.Repository.DTO
+{
+ public class MachineDetailDto : Machine
+ {
+ public UserBaseDto? CreatedUser { get; set; }
+
+ public UserBaseDto? UpdatedUser { get; set; }
+
+ public UserBaseDto? OwnUser { get; set; }
+ }
+}
diff --git a/LMS.Repository/DTO/MachineDto.cs b/LMS.Repository/DTO/MachineDto.cs
new file mode 100644
index 0000000..a7b7d43
--- /dev/null
+++ b/LMS.Repository/DTO/MachineDto.cs
@@ -0,0 +1,30 @@
+锘縰sing static LMS.Common.Enums.MachineEnum;
+
+namespace LMS.Repository.DTO.MachineResponse
+{
+ public class MachineDto
+ {
+ public class MachineStatusResponse
+ {
+ ///
+ /// 鏈哄櫒鐘舵
+ ///
+ public MachineStatus Status { get; set; }
+
+ ///
+ /// 鍒版湡鏃堕棿
+ ///
+ public DateTime? DeactivationTime { get; set; }
+
+ ///
+ /// 鏈哄櫒鐮両D
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// 鏈哄櫒鐮
+ ///
+ public string MachineId { get; set; }
+ }
+ }
+}
diff --git a/LMS.Repository/DTO/RoleDto.cs b/LMS.Repository/DTO/RoleDto.cs
new file mode 100644
index 0000000..cbb4a04
--- /dev/null
+++ b/LMS.Repository/DTO/RoleDto.cs
@@ -0,0 +1,21 @@
+锘縰sing LMS.Repository.DTO.UserDto;
+
+namespace LMS.Repository.DTO
+{
+ public class RoleDto
+ {
+ public long Id { get; set; }
+
+ public string Name { get; set; } = string.Empty;
+
+ public UserBaseDto? CreatedUser { get; set; }
+
+ public UserBaseDto? UpdeatedUser { get; set; }
+
+ public DateTime CreatedTime { get; set; }
+
+ public DateTime UpdatedTime { get; set; }
+
+ public string Remark { get; set; } = string.Empty;
+ }
+}
diff --git a/LMS.Repository/DTO/SoftwareDao.cs b/LMS.Repository/DTO/SoftwareDao.cs
new file mode 100644
index 0000000..c81e765
--- /dev/null
+++ b/LMS.Repository/DTO/SoftwareDao.cs
@@ -0,0 +1,10 @@
+锘縩amespace LMS.Repository.DTO;
+
+public class SoftwareDao
+{
+ public string Version { get; set; }
+
+ public string Author { get; set; }
+
+ public string Description { get; set; }
+}
diff --git a/LMS.Repository/DTO/UserDto/UserAgentInfoDto.cs b/LMS.Repository/DTO/UserDto/UserAgentInfoDto.cs
new file mode 100644
index 0000000..ebdffbb
--- /dev/null
+++ b/LMS.Repository/DTO/UserDto/UserAgentInfoDto.cs
@@ -0,0 +1,44 @@
+锘縩amespace LMS.Repository.DTO.UserDto;
+
+public class UserAgentInfoDto
+{
+ ///
+ /// 鐢ㄦ埛ID
+ ///
+ public long UserId { get; set; }
+
+ ///
+ /// 鐢ㄦ埛鍚嶇О
+ ///
+ public string UserName { get; set; }
+
+ ///
+ /// 鐢ㄦ埛鏄电О
+ ///
+ public string NickName { get; set; }
+
+ ///
+ /// 鐢ㄦ埛鐨勯個璇风爜
+ ///
+ public string AffiliateCode { get; set; }
+
+ ///
+ /// 鐢ㄦ埛鐨勪唬鐞嗗垎鎴愭瘮渚
+ ///
+ public double AgentPercent { get; set; }
+
+ ///
+ /// 閭璇蜂汉鏁
+ ///
+ public int AffiliateNumber { get; set; }
+
+ ///
+ /// 閭璇风殑VIP浜烘暟
+ ///
+ public int AffiliateVIPNumber { get; set; }
+
+ ///
+ /// 閭璇疯幏鍙栫殑閲戦
+ ///
+ public double AffiliateMoney { get; set; }
+}
diff --git a/LMS.Repository/DTO/UserDto/UserBaseDto.cs b/LMS.Repository/DTO/UserDto/UserBaseDto.cs
new file mode 100644
index 0000000..9bfd3e4
--- /dev/null
+++ b/LMS.Repository/DTO/UserDto/UserBaseDto.cs
@@ -0,0 +1,18 @@
+锘縰sing LMS.Repository.User;
+
+namespace LMS.Repository.DTO.UserDto;
+
+public class UserBaseDto
+{
+ public long Id { get; set; }
+
+ public string NickName { get; set; } = string.Empty;
+
+ public string UserName { get; set; } = string.Empty;
+
+ public string Email { get; set; } = string.Empty;
+
+ public string PhoneNumber { get; set; } = string.Empty;
+
+ public string Avatar { get; set; } = string.Empty;
+}
diff --git a/LMS.Repository/DTO/UserDto/UserCollectionDto.cs b/LMS.Repository/DTO/UserDto/UserCollectionDto.cs
new file mode 100644
index 0000000..e7d0f7a
--- /dev/null
+++ b/LMS.Repository/DTO/UserDto/UserCollectionDto.cs
@@ -0,0 +1,17 @@
+锘縩amespace LMS.Repository.DTO.UserDto
+{
+ public class UserCollectionDto : UserBaseDto
+ {
+ public List RoleNames { get; set; } = [];
+
+ public DateTime CreatedDate { get; set; }
+
+ public DateTime LastLoginDate { get; set; }
+
+ public long ParentId { get; set; }
+
+ public string LastLoginIp { get; set; } = string.Empty;
+
+ public string LastLoginDevice { get; set; } = string.Empty;
+ }
+}
diff --git a/LMS.Repository/DTO/UserDto/UserDto.cs b/LMS.Repository/DTO/UserDto/UserDto.cs
new file mode 100644
index 0000000..9beff27
--- /dev/null
+++ b/LMS.Repository/DTO/UserDto/UserDto.cs
@@ -0,0 +1,40 @@
+锘縰sing LMS.Repository.User;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Text.Json;
+
+namespace LMS.Repository.DTO.UserDto
+{
+ public class UserDto : UserBaseDto
+ {
+ public List RoleNames { get; set; } = [];
+
+ ///
+ /// 鍏佽浣跨敤鐨勬満鍣ㄧ爜鏁伴噺
+ ///
+ public long AllDeviceCount { get; set; } = 1;
+
+ ///
+ /// 浠g悊鍒嗘垚姣斾緥
+ ///
+ public double AgentPercent { get; set; } = 0.00;
+
+ ///
+ /// 鍏嶈垂淇敼鏈哄櫒鐮佹鏁
+ ///
+ public long FreeCount { get; set; } = 0;
+
+ public DateTime CreatedDate { get; set; }
+
+ ///
+ /// 閭璇风爜
+ ///
+ public string AffiliateCode { get; set; } = string.Empty;
+
+ public long ParentId { get; set; }
+
+ ///
+ /// 鏀句竴浜涙搷浣滀俊鎭 涓嶈兘棰戠箒鐨勪慨鏀规暟鎹簱锛屼娇鐢ㄧ殑json鏍煎紡瀛樻斁
+ ///
+ public UserPrivateOptions Options { get; set; } = new UserPrivateOptions();
+ }
+}
diff --git a/LMS.Repository/Forward/OpenAI.cs b/LMS.Repository/Forward/OpenAI.cs
new file mode 100644
index 0000000..92772c4
--- /dev/null
+++ b/LMS.Repository/Forward/OpenAI.cs
@@ -0,0 +1,27 @@
+锘縩amespace LMS.Repository.Model
+{
+ public class OpenAI
+ {
+ public class RequestMessage
+ {
+ ///
+ /// 璇锋眰鐨勮鑹
+ ///
+ public string role { get; set; }
+
+ ///
+ /// 璇锋眰鐨勬秷鎭
+ ///
+ public string content { get; set; }
+ }
+
+ ///
+ /// 璇锋眰澶辫触锛岃繑鍥為敊璇俊鎭
+ ///
+ public class ErrorResponse
+ {
+ public string Error { get; set; }
+ public string Message { get; set; }
+ }
+ }
+}
diff --git a/LMS.Repository/LMS.Repository.csproj b/LMS.Repository/LMS.Repository.csproj
new file mode 100644
index 0000000..7bdbfa6
--- /dev/null
+++ b/LMS.Repository/LMS.Repository.csproj
@@ -0,0 +1,21 @@
+锘
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LMS.Repository/Machine/MachineModel.cs b/LMS.Repository/Machine/MachineModel.cs
new file mode 100644
index 0000000..6f2fe58
--- /dev/null
+++ b/LMS.Repository/Machine/MachineModel.cs
@@ -0,0 +1,42 @@
+锘縰sing System.ComponentModel.DataAnnotations;
+using static LMS.Common.Enums.MachineEnum;
+
+namespace LMS.Repository.Models.Machine
+{
+ public class MachineModel
+ {
+ ///
+ /// 鏈哄櫒ID
+ ///
+ [Required]
+ public string MachineId { get; set; }
+
+ ///
+ /// 鍋滅敤鏃堕棿
+ ///
+ public DateTime? DeactivationTime { get; set; }
+
+
+ ///
+ /// 浣跨敤鐘舵(璇曠敤锛屾案涔)
+ ///
+ [Required]
+ public MachineUseStatus UseStatus { get; set; }
+
+ ///
+ /// 褰撳墠鏈哄櫒鐨勭姸鎬侊紙婵娲伙紝鍐荤粨锛
+ ///
+ [Required]
+ public MachineStatus Status { get; set; }
+
+ ///
+ /// 澶囨敞
+ ///
+ public string? Remark { get; set; }
+
+ ///
+ /// 鎵灞炵敤鎴稩D
+ ///
+ public long? UserId { get; set; }
+ }
+}
diff --git a/LMS.Repository/Promission/PermissionModel.cs b/LMS.Repository/Promission/PermissionModel.cs
new file mode 100644
index 0000000..11d2f42
--- /dev/null
+++ b/LMS.Repository/Promission/PermissionModel.cs
@@ -0,0 +1,47 @@
+锘縰sing System.ComponentModel.DataAnnotations;
+using static LMS.Common.Enums.PermissionEnum;
+
+namespace LMS.Repository.RequestModel.Permission
+{
+ public class PermissionModel
+ {
+
+ ///
+ /// 瑙掕壊ID
+ ///
+ public long? RoleId { get; set; }
+
+ ///
+ /// 鐢ㄦ埛鐨処D
+ ///
+ public long? UserId { get; set; }
+
+ ///
+ /// 鏈哄櫒鐮佺殑ID锛堟槸ID锛屼笉鏄満鍣ㄧ爜锛
+ ///
+ public string? MachineId { get; set; }
+
+ ///
+ /// 鏉冮檺绫诲瀷鐨処D锛堝瓙鏉冮檺锛
+ ///
+ [Required]
+ public List PermissionTypeIds { get; set; }
+
+ ///
+ /// 鏉冮檺瀵瑰簲鐨凜ode
+ ///
+ [Required]
+ public string PermissionCode { get; set; }
+
+ ///
+ /// 鏉冮檺绫诲瀷
+ ///
+ [Required]
+ public PType Type { get; set; }
+
+ ///
+ /// 澶囨敞
+ ///
+ public string? Remark { get; set; }
+ }
+}
diff --git a/LMS.Repository/Promission/PermissionTypeModel.cs b/LMS.Repository/Promission/PermissionTypeModel.cs
new file mode 100644
index 0000000..38744d7
--- /dev/null
+++ b/LMS.Repository/Promission/PermissionTypeModel.cs
@@ -0,0 +1,35 @@
+锘縰sing static LMS.Common.Enums.PermissionEnum;
+using System.ComponentModel.DataAnnotations;
+
+namespace LMS.Repository.Models.Promission
+{
+ public class PermissionTypeModel
+ {
+
+
+ ///
+ /// 鏉冮檺鐨勫悕瀛
+ ///
+ [Required]
+ public string Name { get; set; }
+
+ ///
+ /// 鏉冮檺鐨勫垎绫伙紙user鍜宮achine锛
+ ///
+ [Required]
+ public PermissionType Type { get; set; }
+
+ ///
+ /// 琛ㄧず鏉冮檺鐨勪唬鐮
+ ///
+ [Required]
+ public string Code { get; set; }
+
+
+ ///
+ /// 鏉冮檺鐨勬弿杩
+ ///
+ public string? Remark { get; set; }
+
+ }
+}
diff --git a/LMS.Repository/RSAKey/RSAKeyGenerateModel.cs b/LMS.Repository/RSAKey/RSAKeyGenerateModel.cs
new file mode 100644
index 0000000..4d722b7
--- /dev/null
+++ b/LMS.Repository/RSAKey/RSAKeyGenerateModel.cs
@@ -0,0 +1,19 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LMS.Repository.RSAKey
+{
+ public class RSAKeyGenerateModel
+ {
+ public string PublicKey { get; set; }
+
+ public string EncryptedPrivateKey { get; set; }
+
+ public string EncryptedKey { get; set; }
+
+ public string EncryptionIV { get; set; }
+ }
+}
diff --git a/LMS.Repository/Role/RoleModel.cs b/LMS.Repository/Role/RoleModel.cs
new file mode 100644
index 0000000..1b1ab65
--- /dev/null
+++ b/LMS.Repository/Role/RoleModel.cs
@@ -0,0 +1,17 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LMS.Repository.Role
+{
+ public class RoleModel
+ {
+ [Required]
+ public string Name { get; set; }
+
+ public string Remark { get; set; } = string.Empty;
+ }
+}
diff --git a/LMS.Repository/User/LoginModel.cs b/LMS.Repository/User/LoginModel.cs
new file mode 100644
index 0000000..fbd9cd4
--- /dev/null
+++ b/LMS.Repository/User/LoginModel.cs
@@ -0,0 +1,31 @@
+锘縩amespace LMS.Repository.Models.User
+{
+ ///
+ /// 鐢ㄦ埛鐧诲綍鐨勭被鍨
+ ///
+ public enum LoginType
+ {
+ Username = 1, Email = 0,
+ PhoneNumber = 2,
+ }
+
+ ///
+ /// 鐢ㄦ埛鐧诲綍鐨勫疄浣撶被
+ ///
+ public class LoginModel
+ {
+ public string? UserName { get; set; }
+
+ public string? Email { get; set; }
+
+ public LoginType LoginType { get; set; } = 0;
+
+ public required string Password { get; set; }
+
+ public required string TokenId { get; set; }
+
+ public bool RememberMe { get; set; } = false;
+
+ public required string DeviceInfo { get; set; }
+ }
+}
diff --git a/LMS.Repository/User/PublicKeyModel.cs b/LMS.Repository/User/PublicKeyModel.cs
new file mode 100644
index 0000000..bafb65b
--- /dev/null
+++ b/LMS.Repository/User/PublicKeyModel.cs
@@ -0,0 +1,19 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LMS.Repository.User
+{
+ public class PublicKeyModel
+ {
+ public required string ClientPublicKey { get; set; }
+ }
+
+ public class PublicKeyResponse
+ {
+ public required string Token { get; set; }
+ public required string PublicKey { get; set; }
+ }
+}
diff --git a/LMS.Repository/User/RefreshTokenModel.cs b/LMS.Repository/User/RefreshTokenModel.cs
new file mode 100644
index 0000000..8d0dca0
--- /dev/null
+++ b/LMS.Repository/User/RefreshTokenModel.cs
@@ -0,0 +1,10 @@
+锘縩amespace LMS.Repository.Models.User
+{
+ public class RefreshTokenModel
+ {
+ public string refreshToken { get; set; }
+ public required long UserId { get; set; }
+
+ public required string DeviceInfo { get; set; }
+ }
+}
diff --git a/LMS.Repository/User/RegisterModel.cs b/LMS.Repository/User/RegisterModel.cs
new file mode 100644
index 0000000..281ba9f
--- /dev/null
+++ b/LMS.Repository/User/RegisterModel.cs
@@ -0,0 +1,18 @@
+锘縰sing System.ComponentModel.DataAnnotations;
+
+namespace LMS.Repository.Models.User
+{
+ public class RegisterModel
+ {
+ [Required]
+ public required string UserName { get; set; }
+ public string? Email { get; set; }
+ [Required]
+ public required string Password { get; set; }
+ [Required]
+ public required string TokenId { get; set; }
+
+ [Required]
+ public required string AffiliateCode { get; set; }
+ }
+}
diff --git a/LMS.Repository/User/UpdatedUserModel.cs b/LMS.Repository/User/UpdatedUserModel.cs
new file mode 100644
index 0000000..b5ef95b
--- /dev/null
+++ b/LMS.Repository/User/UpdatedUserModel.cs
@@ -0,0 +1,14 @@
+锘縩amespace LMS.Repository.User
+{
+ public class UpdatedUserModel
+ {
+ public double? AgentPercent { get; set; }
+ public int? AllDeviceCount { get; set; }
+ public string? Email { get; set; }
+ public int? FreeCount { get; set; }
+ public string? NickName { get; set; }
+ public string? UserName { get; set; }
+ public string? PhoneNumber { get; set; }
+ public List? RoleNames { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/LMS.Repository/User/UserPrivateOptions.cs b/LMS.Repository/User/UserPrivateOptions.cs
new file mode 100644
index 0000000..d832439
--- /dev/null
+++ b/LMS.Repository/User/UserPrivateOptions.cs
@@ -0,0 +1,12 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LMS.Repository.User;
+
+public class UserPrivateOptions
+{
+
+}
diff --git a/LMS.Tools/Extensions/BeijingTimeExtension.cs b/LMS.Tools/Extensions/BeijingTimeExtension.cs
new file mode 100644
index 0000000..9622d95
--- /dev/null
+++ b/LMS.Tools/Extensions/BeijingTimeExtension.cs
@@ -0,0 +1,15 @@
+锘縩amespace LMS.Tools.Extensions
+{
+ public class BeijingTimeExtension
+ {
+ ///
+ /// 鑾峰彇鍖椾含鏃堕棿锛屽皢鏃跺尯杞崲涓哄寳浜椂闂
+ ///
+ ///
+ public static DateTime GetBeijingTime()
+ {
+ return TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow,
+ TimeZoneInfo.FindSystemTimeZoneById("China Standard Time"));
+ }
+ }
+}
diff --git a/LMS.Tools/Extensions/ConvertExtension.cs b/LMS.Tools/Extensions/ConvertExtension.cs
new file mode 100644
index 0000000..cce56c3
--- /dev/null
+++ b/LMS.Tools/Extensions/ConvertExtension.cs
@@ -0,0 +1,44 @@
+锘縩amespace LMS.Tools.Extensions
+{
+ public class ConvertExtension
+ {
+ ///
+ /// 灏嗗瓧绗︿覆杞崲涓簂ong锛岄粯璁ゆ垨鑰呮槸杞崲閿欒杩斿洖0
+ ///
+ ///
+ ///
+ public static long ObjectToLong(object obj)
+ {
+ if (obj == null)
+ return 0;
+
+ if (obj is long longValue)
+ return longValue;
+
+ if (obj is int intValue)
+ return intValue;
+
+ if (obj is string strValue)
+ {
+ if (long.TryParse(strValue, out long result))
+ return result;
+ }
+
+ // 澶勭悊鍏朵粬鏁板肩被鍨
+ if (obj is IConvertible convertible)
+ {
+ try
+ {
+ return convertible.ToInt64(System.Globalization.CultureInfo.InvariantCulture);
+ }
+ catch
+ {
+ // 杞崲澶辫触锛岃繑鍥0
+ return 0;
+ }
+ }
+
+ return 0; // 榛樿杩斿洖0
+ }
+ }
+}
diff --git a/LMS.Tools/Extensions/EnumExtensions.cs b/LMS.Tools/Extensions/EnumExtensions.cs
new file mode 100644
index 0000000..03bab85
--- /dev/null
+++ b/LMS.Tools/Extensions/EnumExtensions.cs
@@ -0,0 +1,74 @@
+锘縰sing LMS.Common.Attributes;
+using static LMS.Common.Enums.PermissionEnum;
+
+namespace LMS.Tools
+{
+ public static class EnumExtensions
+ {
+ ///
+ /// 鍒ゆ柇鏄惁涓烘湁鏁堢殑鏉冮檺绫诲瀷
+ ///
+ ///
+ ///
+ public static bool IsValidPermissionType(Type enumType, object value)
+ {
+ if (enumType == null || !enumType.IsEnum)
+ {
+ return false;
+ }
+
+ if (value == null)
+ {
+ return false;
+ }
+
+ // 澶勭悊鏁存暟绫诲瀷
+ if (value is int intValue)
+ {
+ return Enum.IsDefined(enumType, intValue);
+ }
+
+ // 澶勭悊瀛楃涓茬被鍨
+ if (value is string stringValue)
+ {
+ return Enum.TryParse(enumType, stringValue, true, out _);
+ }
+
+ // 濡傛灉涓嶆槸鏁存暟鎴栧瓧绗︿覆锛屽皾璇曡浆鎹负鏋氫妇搴曞眰绫诲瀷
+ try
+ {
+ var underlyingType = Enum.GetUnderlyingType(enumType);
+ var convertedValue = Convert.ChangeType(value, underlyingType);
+ return Enum.IsDefined(enumType, convertedValue);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// 鑾峰彇瀵瑰簲鐨勬灇涓剧殑鎻忚堪
+ ///
+ ///
+ ///
+ public static string GetDescription(this Enum value)
+ {
+ var field = value.GetType().GetField(value.ToString());
+ var attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
+ return attribute == null ? value.ToString() : attribute.Description;
+ }
+
+ ///
+ /// 鑾峰彇瀵瑰簲鐨勬灇涓剧殑缁撴灉
+ ///
+ ///
+ ///
+ public static string GetResult(this Enum value)
+ {
+ var field = value.GetType().GetField(value.ToString());
+ var attribute = Attribute.GetCustomAttribute(field, typeof(ResultAttribute)) as ResultAttribute;
+ return attribute == null ? value.ToString() : attribute.Result;
+ }
+ }
+}
diff --git a/LMS.Tools/LMS.Tools.csproj b/LMS.Tools/LMS.Tools.csproj
new file mode 100644
index 0000000..1808db5
--- /dev/null
+++ b/LMS.Tools/LMS.Tools.csproj
@@ -0,0 +1,13 @@
+锘
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/LMS.service/.dockerignore b/LMS.service/.dockerignore
new file mode 100644
index 0000000..fe1152b
--- /dev/null
+++ b/LMS.service/.dockerignore
@@ -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/**
\ No newline at end of file
diff --git a/LMS.service/.gitattributes b/LMS.service/.gitattributes
new file mode 100644
index 0000000..1ff0c42
--- /dev/null
+++ b/LMS.service/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
diff --git a/LMS.service/.gitignore b/LMS.service/.gitignore
new file mode 100644
index 0000000..7aff47a
--- /dev/null
+++ b/LMS.service/.gitignore
@@ -0,0 +1,364 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Oo]ut/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+/Properties/launchSettings.json
diff --git a/LMS.service/APIResponseModel.cs b/LMS.service/APIResponseModel.cs
new file mode 100644
index 0000000..5819cda
--- /dev/null
+++ b/LMS.service/APIResponseModel.cs
@@ -0,0 +1,174 @@
+锘縰sing LMS.Tools;
+using static LMS.Common.Enums.ResponseCodeEnum;
+
+namespace LMS.service
+{
+ public class APIResponseModel
+ {
+ public APIResponseModel()
+ {
+ Code = (int)ResponseCode.Success;
+ Message = string.Empty;
+ Data = default(T);
+ }
+
+ ///
+ /// 杩斿洖鐨勭爜 0锛1
+ ///
+ public int Code { get; set; }
+
+ ///
+ /// 杩斿洖鐨勪俊鎭紝鎴愬姛鎴栬呭け璐ョ殑淇℃伅
+ ///
+ public string? Message { get; set; }
+
+ ///
+ /// 杩斿洖鐨勬暟鎹紝鍙互鏄换浣曠被鍨
+ ///
+ public object? Data { get; set; }
+
+ ///
+ /// 鍒涘缓杩斿洖娑堟伅
+ ///
+ /// 杩斿洖鐮
+ /// 杩斿洖鏁版嵁
+ /// 杩斿洖娑堟伅
+ ///
+ public static APIResponseModel CreateResponseModel(ResponseCode code, T data)
+ {
+ return new APIResponseModel
+ {
+ Code = (int)code,
+ Message = code.GetResult(),
+ Data = data
+ };
+ }
+
+ ///
+ /// 鍒涘缓姝e父鐨勮繑鍥炴暟鎹
+ ///
+ /// 杩斿洖鐨勬暟鎹
+ /// 杩斿洖鎴愬姛鐨勬秷鎭
+ ///
+ public static APIResponseModel CreateSuccessResponseModel(ResponseCode code, T data)
+ {
+ return new APIResponseModel
+ {
+ Code = (int)code,
+ Message = code.GetResult(),
+ Data = data
+ };
+ }
+
+ ///
+ /// 鍒涘缓涓涓繑鍥炴垚鍔熺殑娑堟伅
+ ///
+ ///
+ ///
+ ///
+ public static APIResponseModel CreateSuccessResponseModel(T data, string message)
+ {
+ return new APIResponseModel
+ {
+ Code = (int)ResponseCode.Success,
+ Message = message,
+ Data = data
+ };
+ }
+
+ ///
+ /// 鍒涘缓涓涓繑鍥炴垚鍔熺殑娑堟伅
+ ///
+ ///
+ ///
+ public static APIResponseModel CreateSuccessResponseModel(T data)
+ {
+ return new APIResponseModel
+ {
+ Code = (int)ResponseCode.Success,
+ Message = "璇锋眰鎴愬姛",
+ Data = data
+ };
+ }
+
+
+ ///
+ /// 鍒涘缓姝e父鐨勮繑鍥炴暟鎹
+ ///
+ /// 杩斿洖鐨勬暟鎹
+ ///
+ public static APIResponseModel CreateSuccessResponseModel(ResponseCode code)
+ {
+ return new APIResponseModel
+ {
+ Code = (int)code,
+ Message = code.GetResult(),
+ Data = null
+ };
+ }
+
+ ///
+ /// 杩斿洖閿欒娑堟伅
+ ///
+ /// 閿欒鐨勭爜
+ /// 杩斿洖鐨勬暟鎹
+ ///
+ public static APIResponseModel CreateErrorResponseModel(ResponseCode code, T data)
+ {
+ return new APIResponseModel
+ {
+ Code = (int)code,
+ Message = code.GetResult(),
+ Data = data
+ };
+ }
+
+ ///
+ /// 杩斿洖閿欒娑堟伅
+ ///
+ /// 閿欒鐨勭爜
+ /// 杩斿洖鐨勬暟鎹
+ /// 杩斿洖鐨勯敊璇秷鎭
+ ///
+ public static APIResponseModel CreateErrorResponseModel(ResponseCode code, T data, string message)
+ {
+ return new APIResponseModel
+ {
+ Code = (int)code,
+ Message = message,
+ Data = data
+ };
+ }
+
+ ///
+ /// 鍒涘缓涓涓敊璇殑杩斿洖鏁版嵁锛屽彧鏈夐敊璇秷鎭
+ ///
+ /// 閿欒鐨勭爜
+ ///
+ public static APIResponseModel CreateErrorResponseModel(ResponseCode code)
+ {
+ return new APIResponseModel
+ {
+ Code = (int)code,
+ Message = code.GetResult(),
+ Data = null
+ };
+ }
+
+ ///
+ /// 鍒涘缓涓涓敊璇殑杩斿洖鏁版嵁锛屽彧鏈夐敊璇秷鎭
+ ///
+ /// 閿欒鐨勭爜
+ /// 閿欒娑堟伅鎻愮ず
+ ///
+ public static APIResponseModel CreateErrorResponseModel(ResponseCode code, string message)
+ {
+ return new APIResponseModel
+ {
+ Code = (int)code,
+ Message = message,
+ Data = null
+ };
+ }
+ }
+}
diff --git a/LMS.service/Configuration/AddCorsConifg.cs b/LMS.service/Configuration/AddCorsConifg.cs
new file mode 100644
index 0000000..b00c20c
--- /dev/null
+++ b/LMS.service/Configuration/AddCorsConifg.cs
@@ -0,0 +1,19 @@
+锘縩amespace LMS.service.Configuration
+{
+ public static class AddCorsConifg
+ {
+ public static void AddCorsServices(this IServiceCollection services)
+ {
+ services.AddCors(options =>
+ {
+ options.AddPolicy("AllowAll",
+ builder =>
+ {
+ builder.AllowAnyOrigin()
+ .AllowAnyMethod()
+ .AllowAnyHeader();
+ });
+ });
+ }
+ }
+}
diff --git a/LMS.service/Configuration/AuthenticationExtensions.cs b/LMS.service/Configuration/AuthenticationExtensions.cs
new file mode 100644
index 0000000..c7ab974
--- /dev/null
+++ b/LMS.service/Configuration/AuthenticationExtensions.cs
@@ -0,0 +1,28 @@
+锘縰sing Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.IdentityModel.Tokens;
+using System.Text;
+
+namespace Lai_server.Configuration
+{
+ public static class AuthenticationExtensions
+ {
+ public static void AddJWTAuthentication(this IServiceCollection services)
+ {
+ services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+ .AddJwtBearer(x =>
+ {
+ string secKeyEnv = Environment.GetEnvironmentVariable("SecKey");
+ byte[] keyBytes = Encoding.UTF8.GetBytes(secKeyEnv);
+ var secKey = new SymmetricSecurityKey(keyBytes);
+ x.TokenValidationParameters = new()
+ {
+ ValidateIssuer = false,
+ ValidateAudience = false,
+ ValidateLifetime = true,
+ ValidateIssuerSigningKey = true,
+ IssuerSigningKey = secKey
+ };
+ });
+ }
+ }
+}
diff --git a/LMS.service/Configuration/AutoMapperConfig.cs b/LMS.service/Configuration/AutoMapperConfig.cs
new file mode 100644
index 0000000..414d8b6
--- /dev/null
+++ b/LMS.service/Configuration/AutoMapperConfig.cs
@@ -0,0 +1,31 @@
+锘縰sing AutoMapper;
+using LMS.Repository.DTO;
+using LMS.Repository.DTO.UserDto;
+using LMS.Repository.Models.DB;
+using LMS.Repository.Models.Machine;
+using LMS.Repository.Models.Promission;
+using LMS.Repository.RequestModel.Permission;
+using static LMS.Repository.DTO.MachineResponse.MachineDto;
+
+namespace Lai_server.Configuration
+{
+ public class AutoMapperConfig : Profile
+ {
+ public AutoMapperConfig()
+ {
+ CreateMap();
+
+ CreateMap();
+
+ CreateMap();
+
+ CreateMap();
+
+ CreateMap();
+
+ CreateMap();
+
+ CreateMap();
+ }
+ }
+}
diff --git a/LMS.service/Configuration/JWTSetting.cs b/LMS.service/Configuration/JWTSetting.cs
new file mode 100644
index 0000000..37942c7
--- /dev/null
+++ b/LMS.service/Configuration/JWTSetting.cs
@@ -0,0 +1,10 @@
+锘縩amespace Lai_server.Configuration
+{
+ public class JWTSetting
+ {
+ public string SecKey { get; set; }
+
+ public int ExpireMinutes { get; set; }
+
+ }
+}
diff --git a/LMS.service/Configuration/RsaConfigurattions.cs b/LMS.service/Configuration/RsaConfigurattions.cs
new file mode 100644
index 0000000..ffcf458
--- /dev/null
+++ b/LMS.service/Configuration/RsaConfigurattions.cs
@@ -0,0 +1,66 @@
+锘
+using LMS.Common.RSAKey;
+using LMS.DAO;
+using LMS.Repository.DB;
+using LMS.Tools.Extensions;
+using Microsoft.EntityFrameworkCore;
+
+namespace LMS.service.Configuration
+{
+ public class RsaConfigurattions(IServiceProvider serviceProvider) : IHostedService
+ {
+ private readonly IServiceProvider _serviceProvider = serviceProvider;
+
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ using var scope = _serviceProvider.CreateScope();
+ var dbContext = scope.ServiceProvider.GetRequiredService();
+ using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken);
+ try
+ {
+ int count = await dbContext.RsaKeys.CountAsync(cancellationToken: cancellationToken);
+
+ // 鍏堝垹闄ゆ棤鏁堢殑RSA鏁版嵁
+ List rsaKeys = await dbContext.RsaKeys.Where(x => x.UseCount > 50 || x.ExpirationTime < BeijingTimeExtension.GetBeijingTime()).ToListAsync(cancellationToken: cancellationToken);
+ if (rsaKeys.Count > 0)
+ {
+ dbContext.RsaKeys.RemoveRange(rsaKeys);
+ }
+
+ // 鏂板 淇濊瘉鏁版嵁搴撲腑鏈夋寚瀹氭暟閲忕殑RSA鏁版嵁
+
+ int AddCount = 20 - (count - rsaKeys.Count);
+ for (int i = 0; i < AddCount; i++)
+ {
+ RSAKeyGenerateModel rSAKeyGenerate = RsaKeyPairGenerator.InitRsaKey();
+
+ await dbContext.RsaKeys.AddAsync(new RsaKeys
+ {
+ PublicKey = rSAKeyGenerate.PublicKey,
+ EncryptedPrivateKey = rSAKeyGenerate.EncryptedPrivateKey,
+ EncryptionKey = rSAKeyGenerate.EncryptedKey,
+ EncryptionIV = rSAKeyGenerate.EncryptionIV,
+ UseCount = 0,
+ ExpirationTime = BeijingTimeExtension.GetBeijingTime().AddDays(10),
+ Id = Guid.NewGuid().ToString(),
+ }, cancellationToken);
+ }
+
+ await dbContext.SaveChangesAsync(cancellationToken);
+ await transaction.CommitAsync(cancellationToken);
+ }
+ catch (Exception ex)
+ {
+ await transaction.RollbackAsync(cancellationToken);
+ // 鏍规嵁闇瑕佸鐞嗗紓甯革紝渚嬪缁堟搴旂敤绋嬪簭
+ Console.WriteLine(ex.Message);
+ Environment.Exit(1);
+ }
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/LMS.service/Configuration/ServiceConfiguration.cs b/LMS.service/Configuration/ServiceConfiguration.cs
new file mode 100644
index 0000000..e60bf00
--- /dev/null
+++ b/LMS.service/Configuration/ServiceConfiguration.cs
@@ -0,0 +1,39 @@
+锘縰sing LMS.DAO.MachineDAO;
+using LMS.DAO.PermissionDAO;
+using LMS.DAO.RoleDAO;
+using LMS.DAO.UserDAO;
+using LMS.service.Configuration;
+using LMS.service.Service;
+using LMS.service.Service.PermissionService;
+using LMS.service.Service.RoleService;
+using LMS.service.Service.UserService;
+
+namespace Lai_server.Configuration
+{
+ public static class ServiceConfiguration
+ {
+ public static void AddServices(this IServiceCollection services)
+ {
+ // 娉ㄥ叆Service
+ services.AddScoped();
+
+ // 娉ㄥ叆DDL
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+
+
+ // 娉ㄥ叆 DAO
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
+
+ }
+ }
+}
diff --git a/LMS.service/Configuration/SwaggerConfiguration.cs b/LMS.service/Configuration/SwaggerConfiguration.cs
new file mode 100644
index 0000000..2493097
--- /dev/null
+++ b/LMS.service/Configuration/SwaggerConfiguration.cs
@@ -0,0 +1,31 @@
+锘縰sing Microsoft.OpenApi.Models;
+
+namespace Lai_server.Configuration
+{
+ public static class SwaggerConfiguration
+ {
+ public static void AddSwaggerService(this IServiceCollection services)
+ {
+ services.AddSwaggerGen(c =>
+ {
+ var scheme = new OpenApiSecurityScheme()
+ {
+ Description = "Authorization header. \r\nExample: 'Bearer 12345abcdef'",
+ Reference = new OpenApiReference
+ {
+ Type = ReferenceType.SecurityScheme,
+ Id = "Authorization"
+ },
+ Scheme = "oauth2",
+ Name = "Authorization",
+ In = ParameterLocation.Header,
+ Type = SecuritySchemeType.ApiKey,
+ };
+ c.AddSecurityDefinition("Authorization", scheme);
+ var requirement = new OpenApiSecurityRequirement();
+ requirement[scheme] = new List();
+ c.AddSecurityRequirement(requirement);
+ });
+ }
+ }
+}
diff --git a/LMS.service/Controllers/MachineController.cs b/LMS.service/Controllers/MachineController.cs
new file mode 100644
index 0000000..07e0d78
--- /dev/null
+++ b/LMS.service/Controllers/MachineController.cs
@@ -0,0 +1,150 @@
+锘縰sing LMS.Repository.DTO;
+using LMS.Repository.Models.DB;
+using LMS.Repository.Models.Machine;
+using LMS.service.Service;
+using LMS.Tools.Extensions;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System.ComponentModel.DataAnnotations;
+using static LMS.Common.Enums.MachineEnum;
+using static LMS.Common.Enums.ResponseCodeEnum;
+using static LMS.Repository.DTO.MachineResponse.MachineDto;
+
+namespace LMS.service.Controllers
+{
+ [Route("lms/[controller]/[action]")]
+ [ApiController]
+ public class MachineController(MachineService machineService) : ControllerBase
+ {
+ private readonly MachineService _machineService = machineService;
+
+ #region 鑾峰彇鎸囧畾鏈哄櫒鐮佺殑鐘舵
+ ///
+ /// 鑾峰彇鎸囧畾鏈哄櫒鐮佺殑鐘舵
+ ///
+ ///
+ ///
+ [HttpGet("{machineId}")]
+ public async Task>> GetMachineStatus(string machineId)
+ {
+ return await _machineService.GetMachineStatus(machineId);
+ }
+
+ #endregion
+
+ #region 淇敼鏈哄櫒鐮佹暟鎹
+ ///
+ /// 淇敼褰撳墠鏈哄櫒鐮
+ ///
+ ///
+ ///
+ [HttpPost("{id}")]
+ [Authorize]
+ public async Task>> ModifyMachine(string id, [FromBody] MachineModel request)
+ {
+ if (!ModelState.IsValid)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError);
+ }
+ long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _machineService.ModifyMachine(id, request, userId);
+ }
+
+ #endregion
+
+ #region 娣诲姞鏈哄櫒鐮
+ ///
+ /// 娣诲姞鏈哄櫒鐮
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Authorize]
+ public async Task>> AddMachine([FromBody] MachineModel request)
+ {
+ if (!ModelState.IsValid)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError);
+ }
+ long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _machineService.AddMachine(request, userId);
+ }
+
+ #endregion
+
+ #region 鑾峰彇鏈哄櫒鐮佸垪琛
+
+ ///
+ /// 閫氳繃鏌ヨ鏉′欢鑾峰彇鏈哄櫒鐮佸垪琛
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpGet]
+ [Authorize]
+ public async Task>>> QueryMachineCollection([Required] int page, [Required] int pageSize, string? machineId, string? createdUserName, MachineStatus? status, MachineUseStatus? useStatus, string? remark, string? ownUserName)
+ {
+ long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _machineService.QueryMachineCollection(page, pageSize, machineId, createdUserName, status, useStatus, remark, ownUserName, requestUserId);
+ }
+
+ #endregion
+
+ #region 鑾峰彇鎸囧畾鐨勬満鍣ㄧ爜璇︽儏
+
+ [HttpGet("{Id}")]
+ [Authorize]
+ public async Task>> GetMachineDetail(string Id)
+ {
+ long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _machineService.GetMachineDetail(Id, userId);
+ }
+
+ #endregion
+
+ #region 灏嗘満鍣ㄧ爜鍋滅敤
+
+ [HttpPost("{Id}")]
+ [Authorize]
+ public async Task>> DeactivateMachine(string Id)
+ {
+ long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _machineService.DeactivateMachine(Id, userId);
+ }
+
+ #endregion
+
+ #region 灏嗘満鍣ㄧ爜鍗囩骇涓烘案涔呬娇鐢
+
+ [HttpPost("{Id}")]
+ [Authorize]
+ public async Task>> UpgradeMachine(string Id)
+ {
+ long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _machineService.UpgradeMachine(Id, userId);
+ }
+
+ #endregion
+
+ #region 鍒犻櫎鏈哄櫒鐮
+ ///
+ /// 鍒犻櫎鏈哄櫒鐮
+ ///
+ ///
+ ///
+ [HttpDelete("{id}")]
+ [Authorize]
+ public async Task>> DeleteMachine(string id)
+ {
+ long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _machineService.DeleteMachine(id, userId);
+ }
+ #endregion
+ }
+}
diff --git a/LMS.service/Controllers/PermissionController.cs b/LMS.service/Controllers/PermissionController.cs
new file mode 100644
index 0000000..c8ad1a1
--- /dev/null
+++ b/LMS.service/Controllers/PermissionController.cs
@@ -0,0 +1,134 @@
+锘縰sing LMS.Repository.Models.Promission;
+using LMS.Repository.RequestModel.Permission;
+using LMS.service;
+using LMS.service.Service.PermissionService;
+using LMS.Tools.Extensions;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using static LMS.Common.Enums.ResponseCodeEnum;
+
+namespace Lai_server.Controllers
+{
+ [Route("lms/[controller]/[action]")]
+ [ApiController]
+ public class PermissionController : ControllerBase
+ {
+ private readonly PermissionService _permissionService;
+ public PermissionController(PermissionService permissionService)
+ {
+ _permissionService = permissionService;
+ }
+
+ #region 鏉冮檺绫诲瀷
+
+ ///
+ /// 鍒涘缓鏉冮檺绫诲瀷
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Authorize]
+ public async Task>> AddPermissionType([FromBody] PermissionTypeModel permissionType)
+ {
+ if (!ModelState.IsValid)
+ {
+ return APIResponseModel