diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..8f642dac --- /dev/null +++ b/.editorconfig @@ -0,0 +1,79 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +ij_xml_attribute_wrap = off +ij_xml_text_wrap = off +indent_size = 4 +indent_style = space +insert_final_newline = false +trim_trailing_whitespace = true + +[{*.json,*.yml}] +indent_size = 2 + +[*.cs] +dotnet_analyzer_diagnostic.severity = warning +dotnet_diagnostic.CA1200.severity = none +dotnet_diagnostic.CA1707.severity = none +dotnet_diagnostic.CA1716.severity = none +dotnet_diagnostic.IDE0005.severity = none +dotnet_diagnostic.IDE0008.severity = none +dotnet_diagnostic.IDE0010.severity = none +dotnet_diagnostic.IDE0055.severity = none +dotnet_diagnostic.IDE0160.severity = none +dotnet_diagnostic.IDE0270.severity = none +dotnet_diagnostic.RCS1141.severity = none +dotnet_diagnostic.RCS1142.severity = none +dotnet_diagnostic.RCS1181.severity = none +dotnet_diagnostic.RCS1186.severity = none +dotnet_diagnostic.S101.severity = none +dotnet_diagnostic.S1121.severity = none +dotnet_diagnostic.S1199.severity = none +dotnet_diagnostic.S125.severity = none +dotnet_diagnostic.S2094.severity = none +dotnet_diagnostic.S3925.severity = none +dotnet_diagnostic.S4663.severity = none +dotnet_diagnostic.SYSLIB1045.severity = none + + +# ReSharper properties +resharper_align_linq_query = true +resharper_align_multiline_argument = true +resharper_align_multiline_array_and_object_initializer = true +resharper_align_multiline_binary_patterns = true +resharper_align_multiline_calls_chain = true +resharper_align_multiline_extends_list = true +resharper_align_multiline_parameter = true +resharper_align_multiline_property_pattern = true +resharper_align_multiline_switch_expression = true +resharper_align_multiple_declaration = true +resharper_align_multline_type_parameter_constrains = true +resharper_align_multline_type_parameter_list = true +resharper_align_tuple_components = true +resharper_allow_comment_after_lbrace = true +resharper_blank_lines_before_single_line_comment = 1 +resharper_csharp_empty_block_style = together_same_line +resharper_csharp_outdent_commas = true +resharper_csharp_place_type_constraints_on_same_line = false +resharper_csharp_stick_comment = false +resharper_csharp_wrap_before_comma = true +resharper_indent_nested_for_stmt = true +resharper_indent_nested_foreach_stmt = true +resharper_indent_nested_while_stmt = true +resharper_indent_preprocessor_if = usual_indent +resharper_indent_preprocessor_other = usual_indent +resharper_int_align = true +resharper_keep_existing_arrangement = false +resharper_place_linq_into_on_new_line = false +resharper_place_simple_embedded_statement_on_same_line = false +resharper_place_simple_switch_expression_on_single_line = true +resharper_wrap_before_eq = true +resharper_wrap_chained_method_calls = chop_if_long +resharper_wrap_switch_expression = chop_if_long + + +# Microsoft .NET properties +csharp_indent_braces = false +csharp_new_line_before_open_brace = local_functions, methods, types \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..a1e1e97a --- /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 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..acde096a --- /dev/null +++ b/.gitignore @@ -0,0 +1,405 @@ +## 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/main/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/ +# [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 +*.tlog +*.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 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# 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/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# 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 + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea/ + +# User Define +dist/ +refs/ +*.[Dd]esigner.cs +*.db diff --git a/.template.config/template.json b/.template.config/template.json new file mode 100644 index 00000000..987ece6f --- /dev/null +++ b/.template.config/template.json @@ -0,0 +1,30 @@ +{ + "author": "nsnail", //必须 + "classifications": [ + "Web/WebAPI" + ], //必须,这个对应模板的Tags + "name": "NetAdmin", //必须,这个对应模板的Templates + "identity": "NetAdmin", //可选,模板的唯一名称 + "shortName": "lop", //必须,这个对应模板的Short Name + "tags": { + "language": "C#", + "type": "project" + }, + "sourceName": "NetAdmin", // 可选,要替换的名字 + "preferNameDirectory": true, // 可选,添加目录 + "sources": [ + { + "modifiers": [ + { + "exclude": [ + "**/.vs/**", + "**/.idea/**", + "**/.git/**", + "**/dist/**", + "**/node_modules/**" + ] + } + ] + } + ], +} \ No newline at end of file diff --git a/Build.cake b/Build.cake new file mode 100644 index 00000000..c2878115 --- /dev/null +++ b/Build.cake @@ -0,0 +1,198 @@ +var target = Argument("target", "Default"); +var configuration = Argument("configuration", "Release"); +var outputDirectory = Argument("output-directory", "./dist/Server/publish"); + +//////////////////////////////////////////////////////////////// +// Tasks + +Task("Clean") + .Does(context => +{ + context.CleanDirectory("./dist"); +}); + +Task("Build") + .IsDependentOn("Clean") + .Does(context => +{ + DotNetBuild("./NetAdmin.sln", new DotNetBuildSettings { + Configuration = configuration + }); +}); + +Task("Publish-BizServer") + .Does(context => +{ + DotNetPublish("./src/Server/NetAdmin.BizServer.Host/NetAdmin.BizServer.Host.csproj", new DotNetPublishSettings { + NoBuild = true, + Configuration = configuration, + OutputDirectory = new DirectoryPath(outputDirectory) + }); +}); + +Task("Publish-SdkServer") + .Does(context => +{ + DotNetPublish("./src/Server/NetAdmin.SdkServer.Host/NetAdmin.SdkServer.Host.csproj", new DotNetPublishSettings { + NoBuild = true, + Configuration = configuration, + OutputDirectory = new DirectoryPath(outputDirectory) + }); +}); + +Task("Publish-ManServer") + .Does(context => +{ + DotNetPublish("./src/Server/NetAdmin.ManServer.Host/NetAdmin.ManServer.Host.csproj", new DotNetPublishSettings { + NoBuild = true, + Configuration = configuration, + OutputDirectory = new DirectoryPath(outputDirectory) + }); +}); + +Task("Publish-SdkService") + .Does(context => +{ + DotNetPublish("./src/Server/NetAdmin.SdkService/NetAdmin.SdkService.csproj", new DotNetPublishSettings { + NoBuild = true, + Configuration = configuration, + OutputDirectory = new DirectoryPath(outputDirectory) + }); +}); + +Task("Publish-ManService") + .Does(context => +{ + DotNetPublish("./src/Server/NetAdmin.ManService/NetAdmin.ManService.csproj", new DotNetPublishSettings { + NoBuild = true, + Configuration = configuration, + OutputDirectory = new DirectoryPath(outputDirectory) + }); +}); + +Task("Publish-CallbackService") + .Does(context => +{ + DotNetPublish("./src/Server/NetAdmin.CallbackService/NetAdmin.CallbackService.csproj", new DotNetPublishSettings { + NoBuild = true, + Configuration = configuration, + OutputDirectory = new DirectoryPath(outputDirectory) + }); +}); + + +Task("Publish-ScheduledService") + .Does(context => +{ + DotNetPublish("./src/Server/NetAdmin.ScheduledService/NetAdmin.ScheduledService.csproj", new DotNetPublishSettings { + NoBuild = true, + Configuration = configuration, + OutputDirectory = new DirectoryPath(outputDirectory) + }); +}); + + +Task("Publish-PushService") + .Does(context => +{ + DotNetPublish("./src/Server/NetAdmin.PushService/NetAdmin.PushService.csproj", new DotNetPublishSettings { + NoBuild = true, + Configuration = configuration, + OutputDirectory = new DirectoryPath(outputDirectory) + }); +}); + + +// Task("Test") +// .IsDependentOn("Build") +// .Does(context => +// { +// DotNetTest("./test/Spectre.Console.Tests/Spectre.Console.Tests.csproj", new DotNetTestSettings { +// Configuration = configuration, +// NoRestore = true, +// NoBuild = true, +// }); +// +// DotNetTest("./test/Spectre.Console.Cli.Tests/Spectre.Console.Cli.Tests.csproj", new DotNetTestSettings { +// Configuration = configuration, +// NoRestore = true, +// NoBuild = true, +// }); +// +// DotNetTest("./test/Spectre.Console.Analyzer.Tests/Spectre.Console.Analyzer.Tests.csproj", new DotNetTestSettings { +// Configuration = configuration, +// NoRestore = true, +// NoBuild = true, +// }); +// }); + + +// Task("Publish-GitHub") +// .WithCriteria(ctx => BuildSystem.IsRunningOnGitHubActions, "Not running on GitHub Actions") +// //.IsDependentOn("Package") +// .Does(context => +// { +// var apiKey = Argument("github-key", null); +// if(string.IsNullOrWhiteSpace(apiKey)) { +// throw new CakeException("No GitHub API key was provided."); +// } +// +// // Publish to GitHub Packages +// var exitCode = 0; +// foreach(var file in context.GetFiles("./.artifacts/*.nupkg")) +// { +// context.Information("Publishing {0}...", file.GetFilename().FullPath); +// exitCode += StartProcess("dotnet", +// new ProcessSettings { +// Arguments = new ProcessArgumentBuilder() +// .Append("gpr") +// .Append("push") +// .AppendQuoted(file.FullPath) +// .AppendSwitchSecret("-k", " ", apiKey) +// } +// ); +// } +// +// if(exitCode != 0) +// { +// throw new CakeException("Could not push GitHub packages."); +// } +// }); + +// Task("Publish-NuGet") +// //.WithCriteria(ctx => BuildSystem.IsRunningOnGitHubActions, "Not running on GitHub Actions") +// //.IsDependentOn("Package") +// .Does(context => +// { +// var apiKey = Argument("nuget-key", null); +// if(string.IsNullOrWhiteSpace(apiKey)) { +// throw new CakeException("No NuGet API key was provided."); +// } +// +// // Publish to GitHub Packages +// foreach(var file in context.GetFiles("./.artifacts/*.nupkg")) +// { +// context.Information("Publishing {0}...", file.GetFilename().FullPath); +// DotNetNuGetPush(file.FullPath, new DotNetNuGetPushSettings +// { +// Source = "https://api.nuget.org/v3/index.json", +// ApiKey = apiKey, +// SkipDuplicate = true +// }); +// } +// }); + +//////////////////////////////////////////////////////////////// +// Targets + +// Task("Publish") +// .IsDependentOn("Publish-GitHub") +// .IsDependentOn("Publish-NuGet"); + +Task("Default") + .IsDependentOn("Build"); + +//////////////////////////////////////////////////////////////// +// Execution + +RunTarget(target) \ No newline at end of file diff --git a/CodeQuality.props b/CodeQuality.props new file mode 100644 index 00000000..45b284f6 --- /dev/null +++ b/CodeQuality.props @@ -0,0 +1,41 @@ + + + $(SolutionDir)/StyleCopAnalyzers.ruleset + true + true + true + true + true + true + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + \ No newline at end of file diff --git a/CopyPackageXmlCommentFiles.targets b/CopyPackageXmlCommentFiles.targets new file mode 100644 index 00000000..5f7a4f5d --- /dev/null +++ b/CopyPackageXmlCommentFiles.targets @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 00000000..47281162 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,26 @@ + + + + $(MSBuildThisFileDirectory) + $(SolutionDir)/dist/Server/$(MSBuildProjectName)/obj + $(SolutionDir)/dist/Server/$(MSBuildProjectName)/bin + false + true + enable + beta + NetAdmin + git + http://git.shequnpay.com/lingyun/NetAdmin.git + net7.0 + $(AssemblyName) + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE index d289d820..25c689db 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. \ No newline at end of file diff --git a/NetAdmin.sln b/NetAdmin.sln new file mode 100644 index 00000000..4bb45988 --- /dev/null +++ b/NetAdmin.sln @@ -0,0 +1,176 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C84EB5A0-37AD-4B17-A51E-E36888C4441E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "backend", "backend", "{4DAF9366-855F-46BB-AE4C-660C92FA0697}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{5198A03D-0CAC-4828-A807-34A693F73859}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitattributes = .gitattributes + .gitignore = .gitignore + Build.cake = Build.cake + CodeQuality.props = CodeQuality.props + CopyPackageXmlCommentFiles.targets = CopyPackageXmlCommentFiles.targets + Directory.Build.props = Directory.Build.props + dotnet-tools.json = dotnet-tools.json + global.json = global.json + LICENSE = LICENSE + NetAdmin.sln.DotSettings = NetAdmin.sln.DotSettings + NuGet.Config = NuGet.Config + package.json = package.json + PreBuild.targets = PreBuild.targets + README.md = README.md + StyleCop.json = StyleCop.json + StyleCopAnalyzers.ruleset = StyleCopAnalyzers.ruleset + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Infrastructure", "src\backend\NetAdmin.Infrastructure\NetAdmin.Infrastructure.csproj", "{1E62C322-EE42-4699-A6F1-791C53EFA62D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.BizServer.Application", "src\backend\NetAdmin.BizServer.Application\NetAdmin.BizServer.Application.csproj", "{E38B2EB4-D7A5-4777-9236-3B348919DF23}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.BizServer.Host", "src\backend\NetAdmin.BizServer.Host\NetAdmin.BizServer.Host.csproj", "{CE895E44-EEC3-4ECE-A56A-8A82E7D863E3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "03.HostedServers", "03.HostedServers", "{12AE5B4B-CB1A-498E-83B8-04E201E31D86}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Domain", "src\backend\NetAdmin.Domain\NetAdmin.Domain.csproj", "{58509C57-09FA-4E3C-BC07-78E786A2A326}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Application", "src\backend\NetAdmin.Application\NetAdmin.Application.csproj", "{70C54E1B-2083-4196-AB68-34CAF0075D82}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Host", "src\backend\NetAdmin.Host\NetAdmin.Host.csproj", "{91839A15-D08F-4848-A301-F793412BC688}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Cache", "src\backend\NetAdmin.Cache\NetAdmin.Cache.csproj", "{91452C22-4B57-4F16-9AF6-42C7BF830504}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.BizServer.Cache", "src\backend\NetAdmin.BizServer.Cache\NetAdmin.BizServer.Cache.csproj", "{7CB632D3-3635-4F8D-AFE7-F496D37D422B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Host", "src\backend\NetAdmin.SysComponent.Host\NetAdmin.SysComponent.Host.csproj", "{C2CC1596-3BEE-43EA-A9BE-4EDE5716296C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Cache", "src\backend\NetAdmin.SysComponent.Cache\NetAdmin.SysComponent.Cache.csproj", "{19872A4C-3C9A-4C62-A33B-74F5B8D6F77C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Application", "src\backend\NetAdmin.SysComponent.Application\NetAdmin.SysComponent.Application.csproj", "{34650E82-D257-46DA-BD6B-DE307113347B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "02.Components", "02.Components", "{3F23258D-8299-4992-9F51-2EE9B52CF9D2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "21.System", "21.System", "{E146D707-4D44-47B3-A8F9-D51EC5E1D047}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "04.BackgroundServices", "04.BackgroundServices", "{CBFBF29B-27E8-4DB1-ADD6-4B750897ACD3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "01.Frameworks", "01.Frameworks", "{D9C3EF66-2757-473D-A26B-54FD08DA203F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.ScheduledService", "src\backend\NetAdmin.ScheduledService\NetAdmin.ScheduledService.csproj", "{96668960-310F-4682-B3F9-1E8F1EED8C90}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "06.Tests", "06.Tests", "{89260294-80FC-49F1-8D73-AECD39AFF2B7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.BizServer.Tests", "src\backend\NetAdmin.BizServer.Tests\NetAdmin.BizServer.Tests.csproj", "{C7F27698-DA05-4ACD-B0D7-4791B3972002}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{2D81D62C-1B2E-4758-84C6-728343CB734F}" + ProjectSection(SolutionItems) = preProject + CloneProjectRefs.ps1 = tools/CloneProjectRefs.ps1 + CodeCleanup.csx = tools/CodeCleanup.csx + CodeCleanup.ps1 = tools/CodeCleanup.ps1 + CodeCleanupFull.ps1 = tools/CodeCleanupFull.ps1 + DotClean.cmd = tools/DotClean.cmd + GenerateLn.cmd = tools/GenerateLn.cmd + GenerateLnCs.tt = tools/GenerateLnCs.tt + GenerateLnResx.tt = tools/GenerateLnResx.tt + GitPR.ps1 = tools/GitPR.ps1 + GitRecreate.ps1 = tools/GitRecreate.ps1 + IdGenerator.linq = tools/IdGenerator.linq + ImageOptimize.csx = tools/ImageOptimize.csx + InstallAsTpl.ps1 = tools/InstallAsTpl.ps1 + Switcher.FreeSql.json = tools/Switcher.FreeSql.json + Switcher.Furion.json = tools/Switcher.Furion.json + Switcher.NSExt.json = tools/Switcher.NSExt.json + Switcher.ps1 = tools/Switcher.ps1 + SyncMetaFiles.csx = tools/SyncMetaFiles.csx + EndProjectSection +EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1E62C322-EE42-4699-A6F1-791C53EFA62D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E62C322-EE42-4699-A6F1-791C53EFA62D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E62C322-EE42-4699-A6F1-791C53EFA62D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E62C322-EE42-4699-A6F1-791C53EFA62D}.Release|Any CPU.Build.0 = Release|Any CPU + {E38B2EB4-D7A5-4777-9236-3B348919DF23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E38B2EB4-D7A5-4777-9236-3B348919DF23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E38B2EB4-D7A5-4777-9236-3B348919DF23}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E38B2EB4-D7A5-4777-9236-3B348919DF23}.Release|Any CPU.Build.0 = Release|Any CPU + {CE895E44-EEC3-4ECE-A56A-8A82E7D863E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE895E44-EEC3-4ECE-A56A-8A82E7D863E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE895E44-EEC3-4ECE-A56A-8A82E7D863E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE895E44-EEC3-4ECE-A56A-8A82E7D863E3}.Release|Any CPU.Build.0 = Release|Any CPU + {58509C57-09FA-4E3C-BC07-78E786A2A326}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {58509C57-09FA-4E3C-BC07-78E786A2A326}.Debug|Any CPU.Build.0 = Debug|Any CPU + {58509C57-09FA-4E3C-BC07-78E786A2A326}.Release|Any CPU.ActiveCfg = Release|Any CPU + {58509C57-09FA-4E3C-BC07-78E786A2A326}.Release|Any CPU.Build.0 = Release|Any CPU + {70C54E1B-2083-4196-AB68-34CAF0075D82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {70C54E1B-2083-4196-AB68-34CAF0075D82}.Debug|Any CPU.Build.0 = Debug|Any CPU + {70C54E1B-2083-4196-AB68-34CAF0075D82}.Release|Any CPU.ActiveCfg = Release|Any CPU + {70C54E1B-2083-4196-AB68-34CAF0075D82}.Release|Any CPU.Build.0 = Release|Any CPU + {91839A15-D08F-4848-A301-F793412BC688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {91839A15-D08F-4848-A301-F793412BC688}.Debug|Any CPU.Build.0 = Debug|Any CPU + {91839A15-D08F-4848-A301-F793412BC688}.Release|Any CPU.ActiveCfg = Release|Any CPU + {91839A15-D08F-4848-A301-F793412BC688}.Release|Any CPU.Build.0 = Release|Any CPU + {91452C22-4B57-4F16-9AF6-42C7BF830504}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {91452C22-4B57-4F16-9AF6-42C7BF830504}.Debug|Any CPU.Build.0 = Debug|Any CPU + {91452C22-4B57-4F16-9AF6-42C7BF830504}.Release|Any CPU.ActiveCfg = Release|Any CPU + {91452C22-4B57-4F16-9AF6-42C7BF830504}.Release|Any CPU.Build.0 = Release|Any CPU + {7CB632D3-3635-4F8D-AFE7-F496D37D422B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7CB632D3-3635-4F8D-AFE7-F496D37D422B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7CB632D3-3635-4F8D-AFE7-F496D37D422B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7CB632D3-3635-4F8D-AFE7-F496D37D422B}.Release|Any CPU.Build.0 = Release|Any CPU + {C2CC1596-3BEE-43EA-A9BE-4EDE5716296C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2CC1596-3BEE-43EA-A9BE-4EDE5716296C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2CC1596-3BEE-43EA-A9BE-4EDE5716296C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2CC1596-3BEE-43EA-A9BE-4EDE5716296C}.Release|Any CPU.Build.0 = Release|Any CPU + {19872A4C-3C9A-4C62-A33B-74F5B8D6F77C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {19872A4C-3C9A-4C62-A33B-74F5B8D6F77C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {19872A4C-3C9A-4C62-A33B-74F5B8D6F77C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {19872A4C-3C9A-4C62-A33B-74F5B8D6F77C}.Release|Any CPU.Build.0 = Release|Any CPU + {34650E82-D257-46DA-BD6B-DE307113347B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34650E82-D257-46DA-BD6B-DE307113347B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34650E82-D257-46DA-BD6B-DE307113347B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34650E82-D257-46DA-BD6B-DE307113347B}.Release|Any CPU.Build.0 = Release|Any CPU + {96668960-310F-4682-B3F9-1E8F1EED8C90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96668960-310F-4682-B3F9-1E8F1EED8C90}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96668960-310F-4682-B3F9-1E8F1EED8C90}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96668960-310F-4682-B3F9-1E8F1EED8C90}.Release|Any CPU.Build.0 = Release|Any CPU + {C7F27698-DA05-4ACD-B0D7-4791B3972002}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7F27698-DA05-4ACD-B0D7-4791B3972002}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7F27698-DA05-4ACD-B0D7-4791B3972002}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7F27698-DA05-4ACD-B0D7-4791B3972002}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {4DAF9366-855F-46BB-AE4C-660C92FA0697} = {C84EB5A0-37AD-4B17-A51E-E36888C4441E} + {12AE5B4B-CB1A-498E-83B8-04E201E31D86} = {4DAF9366-855F-46BB-AE4C-660C92FA0697} + {3F23258D-8299-4992-9F51-2EE9B52CF9D2} = {4DAF9366-855F-46BB-AE4C-660C92FA0697} + {E146D707-4D44-47B3-A8F9-D51EC5E1D047} = {3F23258D-8299-4992-9F51-2EE9B52CF9D2} + {34650E82-D257-46DA-BD6B-DE307113347B} = {E146D707-4D44-47B3-A8F9-D51EC5E1D047} + {19872A4C-3C9A-4C62-A33B-74F5B8D6F77C} = {E146D707-4D44-47B3-A8F9-D51EC5E1D047} + {C2CC1596-3BEE-43EA-A9BE-4EDE5716296C} = {E146D707-4D44-47B3-A8F9-D51EC5E1D047} + {CBFBF29B-27E8-4DB1-ADD6-4B750897ACD3} = {4DAF9366-855F-46BB-AE4C-660C92FA0697} + {D9C3EF66-2757-473D-A26B-54FD08DA203F} = {4DAF9366-855F-46BB-AE4C-660C92FA0697} + {70C54E1B-2083-4196-AB68-34CAF0075D82} = {D9C3EF66-2757-473D-A26B-54FD08DA203F} + {91452C22-4B57-4F16-9AF6-42C7BF830504} = {D9C3EF66-2757-473D-A26B-54FD08DA203F} + {58509C57-09FA-4E3C-BC07-78E786A2A326} = {D9C3EF66-2757-473D-A26B-54FD08DA203F} + {91839A15-D08F-4848-A301-F793412BC688} = {D9C3EF66-2757-473D-A26B-54FD08DA203F} + {1E62C322-EE42-4699-A6F1-791C53EFA62D} = {D9C3EF66-2757-473D-A26B-54FD08DA203F} + {96668960-310F-4682-B3F9-1E8F1EED8C90} = {CBFBF29B-27E8-4DB1-ADD6-4B750897ACD3} + {E38B2EB4-D7A5-4777-9236-3B348919DF23} = {12AE5B4B-CB1A-498E-83B8-04E201E31D86} + {7CB632D3-3635-4F8D-AFE7-F496D37D422B} = {12AE5B4B-CB1A-498E-83B8-04E201E31D86} + {CE895E44-EEC3-4ECE-A56A-8A82E7D863E3} = {12AE5B4B-CB1A-498E-83B8-04E201E31D86} + {89260294-80FC-49F1-8D73-AECD39AFF2B7} = {4DAF9366-855F-46BB-AE4C-660C92FA0697} + {C7F27698-DA05-4ACD-B0D7-4791B3972002} = {89260294-80FC-49F1-8D73-AECD39AFF2B7} + EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/NetAdmin.sln.DotSettings b/NetAdmin.sln.DotSettings new file mode 100644 index 00000000..a09783ab --- /dev/null +++ b/NetAdmin.sln.DotSettings @@ -0,0 +1,105 @@ + + Inherit + True + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + NEVER + NEVER + NEVER + NEVER + ID + IOS + IP + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + + True + True + True + True + True + 1 + 1 + OFF + HINT + Required + Required + Required + Required + <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> + <Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /> + <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <?xml version="1.0" encoding="utf-16"?> +<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> + <TypePattern> + <Entry> + <Entry.SortBy> + <Kind> + <Kind.Order> + <DeclarationKind>Constant</DeclarationKind> + <DeclarationKind>Field</DeclarationKind> + <DeclarationKind>Constructor</DeclarationKind> + <DeclarationKind>Destructor</DeclarationKind> + <DeclarationKind>Delegate</DeclarationKind> + <DeclarationKind>Event</DeclarationKind> + <DeclarationKind>Enum</DeclarationKind> + <DeclarationKind>Interface</DeclarationKind> + <DeclarationKind>Property</DeclarationKind> + <DeclarationKind>Indexer</DeclarationKind> + <DeclarationKind>Method</DeclarationKind> + <DeclarationKind>Struct</DeclarationKind> + <DeclarationKind>Record</DeclarationKind> + <DeclarationKind>Class</DeclarationKind> + </Kind.Order> + </Kind> + <Access> + <Access.Order> + <AccessModifier>Public</AccessModifier> + <AccessModifier>Internal</AccessModifier> + <AccessModifier>ProtectedInternal</AccessModifier> + <AccessModifier>Protected</AccessModifier> + <AccessModifier>PrivateProtected</AccessModifier> + <AccessModifier>Private</AccessModifier> + </Access.Order> + </Access> + <Static /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> +</Patterns> + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + + \ No newline at end of file diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 00000000..eb8bbcaf --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/PreBuild.targets b/PreBuild.targets new file mode 100644 index 00000000..fb39f8ba --- /dev/null +++ b/PreBuild.targets @@ -0,0 +1,24 @@ + + + + + + + + + Languages/Ln.txt + + + Languages/Ln.resx + PublicResXFileCodeGenerator + + + Languages/Ln.Designer.cs + + + \ No newline at end of file diff --git a/README.md b/README.md index 27ebd0e5..6aff29a0 100644 --- a/README.md +++ b/README.md @@ -1 +1,86 @@ -# NetAdmin \ No newline at end of file +# NetAdmin + +## Git Commits 语义 + +- `FEA` 新增特性 +- `REF` 项目重构 +- `FIX` 缺陷修复 +- `PER` 性能优化 +- `RVT` 还原变更 +- `FMT` 格式整理 +- `DOC` 文档变更 +- `TST` 单元测试 +- `BLD` 工程构建 + + +## 构建指南 +1. 后端 + 1. 检查dotnet-sdk版本>=7.0.0 + ``` + dotnet --list-sdks + ``` + 2. 克隆代码仓库 + ``` + git clone https://github.com/nsnail/NetAdmin.git + cd ./NetAdmin + ``` + 3. 确保本机redis处于运行状态 + ``` + redis-cli + ``` + 4. 运行后端WebApi + ``` + dotnet run --project ./src/backend/NetAdmin.BizServer.Host/NetAdmin.BizServer.Host.csproj --urls http://[::]:65010 + ``` + 5. 体验WebApi程序 + ``` + 浏览器打开 http://localhost:65010 ,将看到Swagger(Knife4jUI)界面 + ``` +2. 前端 + 1. 检查nodejs版本>=20 + ``` + node -v + ``` + 2. 安装npm依赖包 + ``` + cd ./src/frontend/admin + npm install + ``` + 3. 运行前端项目 + ``` + npm run dev + ``` + 4. 体验前端程序 + ``` + 浏览器打开 http://localhost:65020 ,将看到管理界面(默认用户名:root,密码:1234qwer) + ``` + +## 项目文件目录树描述 +``` ++---.template.config dotnet 项目模板配置目录 ++---assets 程序运行需要的资源文件目录 ++---dist 项目编译与分发的二进制文件目录 ++---refs 引用的第三方项目源文件目录 ++---src 项目源文件目录 +| +---backend 后端程序源文件目录 +| \---frontend 前端程序源文件目录 +\---tools 构建相关的工具目录 +``` + +## 后端项目架构 +```mermaid +flowchart TD +H["NetAdmin.Host\n公共主机层\n(.Net自托管主机程序)\n(输入输出格式化)\n(数据校验、鉴权)\n(...所有HTTP管道过滤器中间件)"] --> C["NetAdmin.Cache\n公共缓存层\n(基于Redis或MemoryCache的缓存策略实现)"] +C --> A["NetAdmin.Application\n公共业务逻辑层\n(内部服务增删改查)\n(外部服务增删改查)\n(...所有业务用例的计算与组合逻辑的模块化)"] +A --> D["NetAdmin.Domain\n数据实体层\n(数据库关系实体映射)\n(DTO数据传输对象)\n(...所有数据模型的抽象与封装)"] +D --> I["NetAdmin.Infrastructure\n基础设施层\n(第三方组件和Nuget包引用)\n(公共构建和程序运行配置)\n(公共常量枚举异常定义)\n(全球化化和多语言)\n(...所有公共Utility工具)"] + +XH["NetAdmin.XXX.Host\n(WebApi)"]-->H +XS["NetAdmin.XXXService\n(常驻内存服务)"]-->H +XS["NetAdmin.XXXService\n(常驻内存服务)"]-->XC +XC["NetAdmin.XXX.Cache\n(缓存层实例)"]-->C +XA["NetAdmin.XXX.Application\n(业务逻辑层实例)"]-->A + +XH-->XC +XC-->XA +``` \ No newline at end of file diff --git a/StyleCop.json b/StyleCop.json new file mode 100644 index 00000000..9251b508 --- /dev/null +++ b/StyleCop.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "indentation": { + "useTabs": false, + "indentationSize": 4 + } + } +} \ No newline at end of file diff --git a/StyleCopAnalyzers.ruleset b/StyleCopAnalyzers.ruleset new file mode 100644 index 00000000..b8faaff9 --- /dev/null +++ b/StyleCopAnalyzers.ruleset @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/README.md b/assets/README.md new file mode 100644 index 00000000..c613f732 --- /dev/null +++ b/assets/README.md @@ -0,0 +1 @@ +# 资源文件目录 \ No newline at end of file diff --git a/assets/captcha/background/1.jpg b/assets/captcha/background/1.jpg new file mode 100644 index 00000000..067358ea Binary files /dev/null and b/assets/captcha/background/1.jpg differ diff --git a/assets/captcha/background/10.jpg b/assets/captcha/background/10.jpg new file mode 100644 index 00000000..ebbb328e Binary files /dev/null and b/assets/captcha/background/10.jpg differ diff --git a/assets/captcha/background/100.jpg b/assets/captcha/background/100.jpg new file mode 100644 index 00000000..c11a1630 Binary files /dev/null and b/assets/captcha/background/100.jpg differ diff --git a/assets/captcha/background/11.jpg b/assets/captcha/background/11.jpg new file mode 100644 index 00000000..bf37f0cc Binary files /dev/null and b/assets/captcha/background/11.jpg differ diff --git a/assets/captcha/background/12.jpg b/assets/captcha/background/12.jpg new file mode 100644 index 00000000..bf222152 Binary files /dev/null and b/assets/captcha/background/12.jpg differ diff --git a/assets/captcha/background/13.jpg b/assets/captcha/background/13.jpg new file mode 100644 index 00000000..6a8e095b Binary files /dev/null and b/assets/captcha/background/13.jpg differ diff --git a/assets/captcha/background/14.jpg b/assets/captcha/background/14.jpg new file mode 100644 index 00000000..d7832b98 Binary files /dev/null and b/assets/captcha/background/14.jpg differ diff --git a/assets/captcha/background/15.jpg b/assets/captcha/background/15.jpg new file mode 100644 index 00000000..3b794e76 Binary files /dev/null and b/assets/captcha/background/15.jpg differ diff --git a/assets/captcha/background/16.jpg b/assets/captcha/background/16.jpg new file mode 100644 index 00000000..9052c7f5 Binary files /dev/null and b/assets/captcha/background/16.jpg differ diff --git a/assets/captcha/background/17.jpg b/assets/captcha/background/17.jpg new file mode 100644 index 00000000..3037e829 Binary files /dev/null and b/assets/captcha/background/17.jpg differ diff --git a/assets/captcha/background/18.jpg b/assets/captcha/background/18.jpg new file mode 100644 index 00000000..94d41633 Binary files /dev/null and b/assets/captcha/background/18.jpg differ diff --git a/assets/captcha/background/19.jpg b/assets/captcha/background/19.jpg new file mode 100644 index 00000000..a0bc6fc1 Binary files /dev/null and b/assets/captcha/background/19.jpg differ diff --git a/assets/captcha/background/2.jpg b/assets/captcha/background/2.jpg new file mode 100644 index 00000000..5f2f2f16 Binary files /dev/null and b/assets/captcha/background/2.jpg differ diff --git a/assets/captcha/background/20.jpg b/assets/captcha/background/20.jpg new file mode 100644 index 00000000..c0ca5e4a Binary files /dev/null and b/assets/captcha/background/20.jpg differ diff --git a/assets/captcha/background/21.jpg b/assets/captcha/background/21.jpg new file mode 100644 index 00000000..b45f3591 Binary files /dev/null and b/assets/captcha/background/21.jpg differ diff --git a/assets/captcha/background/22.jpg b/assets/captcha/background/22.jpg new file mode 100644 index 00000000..bd4415c7 Binary files /dev/null and b/assets/captcha/background/22.jpg differ diff --git a/assets/captcha/background/23.jpg b/assets/captcha/background/23.jpg new file mode 100644 index 00000000..659f0ccf Binary files /dev/null and b/assets/captcha/background/23.jpg differ diff --git a/assets/captcha/background/24.jpg b/assets/captcha/background/24.jpg new file mode 100644 index 00000000..eac721bd Binary files /dev/null and b/assets/captcha/background/24.jpg differ diff --git a/assets/captcha/background/25.jpg b/assets/captcha/background/25.jpg new file mode 100644 index 00000000..c11a1630 Binary files /dev/null and b/assets/captcha/background/25.jpg differ diff --git a/assets/captcha/background/26.jpg b/assets/captcha/background/26.jpg new file mode 100644 index 00000000..d98e9378 Binary files /dev/null and b/assets/captcha/background/26.jpg differ diff --git a/assets/captcha/background/27.jpg b/assets/captcha/background/27.jpg new file mode 100644 index 00000000..bf222152 Binary files /dev/null and b/assets/captcha/background/27.jpg differ diff --git a/assets/captcha/background/28.jpg b/assets/captcha/background/28.jpg new file mode 100644 index 00000000..03e95213 Binary files /dev/null and b/assets/captcha/background/28.jpg differ diff --git a/assets/captcha/background/29.jpg b/assets/captcha/background/29.jpg new file mode 100644 index 00000000..c377a178 Binary files /dev/null and b/assets/captcha/background/29.jpg differ diff --git a/assets/captcha/background/3.jpg b/assets/captcha/background/3.jpg new file mode 100644 index 00000000..837b2585 Binary files /dev/null and b/assets/captcha/background/3.jpg differ diff --git a/assets/captcha/background/30.jpg b/assets/captcha/background/30.jpg new file mode 100644 index 00000000..98fa60bc Binary files /dev/null and b/assets/captcha/background/30.jpg differ diff --git a/assets/captcha/background/31.jpg b/assets/captcha/background/31.jpg new file mode 100644 index 00000000..f165abf5 Binary files /dev/null and b/assets/captcha/background/31.jpg differ diff --git a/assets/captcha/background/32.jpg b/assets/captcha/background/32.jpg new file mode 100644 index 00000000..1d9cbd60 Binary files /dev/null and b/assets/captcha/background/32.jpg differ diff --git a/assets/captcha/background/33.jpg b/assets/captcha/background/33.jpg new file mode 100644 index 00000000..d2f8faa1 Binary files /dev/null and b/assets/captcha/background/33.jpg differ diff --git a/assets/captcha/background/34.jpg b/assets/captcha/background/34.jpg new file mode 100644 index 00000000..13d4adb1 Binary files /dev/null and b/assets/captcha/background/34.jpg differ diff --git a/assets/captcha/background/35.jpg b/assets/captcha/background/35.jpg new file mode 100644 index 00000000..769a403e Binary files /dev/null and b/assets/captcha/background/35.jpg differ diff --git a/assets/captcha/background/36.jpg b/assets/captcha/background/36.jpg new file mode 100644 index 00000000..3c8f6cc4 Binary files /dev/null and b/assets/captcha/background/36.jpg differ diff --git a/assets/captcha/background/37.jpg b/assets/captcha/background/37.jpg new file mode 100644 index 00000000..5d05d76d Binary files /dev/null and b/assets/captcha/background/37.jpg differ diff --git a/assets/captcha/background/38.jpg b/assets/captcha/background/38.jpg new file mode 100644 index 00000000..12dc40c1 Binary files /dev/null and b/assets/captcha/background/38.jpg differ diff --git a/assets/captcha/background/39.jpg b/assets/captcha/background/39.jpg new file mode 100644 index 00000000..2cf13f71 Binary files /dev/null and b/assets/captcha/background/39.jpg differ diff --git a/assets/captcha/background/4.jpg b/assets/captcha/background/4.jpg new file mode 100644 index 00000000..9db2cfe8 Binary files /dev/null and b/assets/captcha/background/4.jpg differ diff --git a/assets/captcha/background/40.jpg b/assets/captcha/background/40.jpg new file mode 100644 index 00000000..d79f8940 Binary files /dev/null and b/assets/captcha/background/40.jpg differ diff --git a/assets/captcha/background/41.jpg b/assets/captcha/background/41.jpg new file mode 100644 index 00000000..1c451c18 Binary files /dev/null and b/assets/captcha/background/41.jpg differ diff --git a/assets/captcha/background/42.jpg b/assets/captcha/background/42.jpg new file mode 100644 index 00000000..4b3295ac Binary files /dev/null and b/assets/captcha/background/42.jpg differ diff --git a/assets/captcha/background/43.jpg b/assets/captcha/background/43.jpg new file mode 100644 index 00000000..70620bfc Binary files /dev/null and b/assets/captcha/background/43.jpg differ diff --git a/assets/captcha/background/44.jpg b/assets/captcha/background/44.jpg new file mode 100644 index 00000000..85958ccd Binary files /dev/null and b/assets/captcha/background/44.jpg differ diff --git a/assets/captcha/background/45.jpg b/assets/captcha/background/45.jpg new file mode 100644 index 00000000..d0284fcd Binary files /dev/null and b/assets/captcha/background/45.jpg differ diff --git a/assets/captcha/background/46.jpg b/assets/captcha/background/46.jpg new file mode 100644 index 00000000..739073be Binary files /dev/null and b/assets/captcha/background/46.jpg differ diff --git a/assets/captcha/background/47.jpg b/assets/captcha/background/47.jpg new file mode 100644 index 00000000..3176a9f4 Binary files /dev/null and b/assets/captcha/background/47.jpg differ diff --git a/assets/captcha/background/48.jpg b/assets/captcha/background/48.jpg new file mode 100644 index 00000000..f4f381d7 Binary files /dev/null and b/assets/captcha/background/48.jpg differ diff --git a/assets/captcha/background/49.jpg b/assets/captcha/background/49.jpg new file mode 100644 index 00000000..0ea8d1c1 Binary files /dev/null and b/assets/captcha/background/49.jpg differ diff --git a/assets/captcha/background/5.jpg b/assets/captcha/background/5.jpg new file mode 100644 index 00000000..4fec1bd1 Binary files /dev/null and b/assets/captcha/background/5.jpg differ diff --git a/assets/captcha/background/50.jpg b/assets/captcha/background/50.jpg new file mode 100644 index 00000000..837b2585 Binary files /dev/null and b/assets/captcha/background/50.jpg differ diff --git a/assets/captcha/background/51.jpg b/assets/captcha/background/51.jpg new file mode 100644 index 00000000..f669339b Binary files /dev/null and b/assets/captcha/background/51.jpg differ diff --git a/assets/captcha/background/52.jpg b/assets/captcha/background/52.jpg new file mode 100644 index 00000000..f119fc64 Binary files /dev/null and b/assets/captcha/background/52.jpg differ diff --git a/assets/captcha/background/53.jpg b/assets/captcha/background/53.jpg new file mode 100644 index 00000000..bcdd8348 Binary files /dev/null and b/assets/captcha/background/53.jpg differ diff --git a/assets/captcha/background/54.jpg b/assets/captcha/background/54.jpg new file mode 100644 index 00000000..0b922eaf Binary files /dev/null and b/assets/captcha/background/54.jpg differ diff --git a/assets/captcha/background/55.jpg b/assets/captcha/background/55.jpg new file mode 100644 index 00000000..fd9405c1 Binary files /dev/null and b/assets/captcha/background/55.jpg differ diff --git a/assets/captcha/background/56.jpg b/assets/captcha/background/56.jpg new file mode 100644 index 00000000..aa512dbb Binary files /dev/null and b/assets/captcha/background/56.jpg differ diff --git a/assets/captcha/background/57.jpg b/assets/captcha/background/57.jpg new file mode 100644 index 00000000..13d7a21c Binary files /dev/null and b/assets/captcha/background/57.jpg differ diff --git a/assets/captcha/background/58.jpg b/assets/captcha/background/58.jpg new file mode 100644 index 00000000..e9549352 Binary files /dev/null and b/assets/captcha/background/58.jpg differ diff --git a/assets/captcha/background/59.jpg b/assets/captcha/background/59.jpg new file mode 100644 index 00000000..0c55f67e Binary files /dev/null and b/assets/captcha/background/59.jpg differ diff --git a/assets/captcha/background/6.jpg b/assets/captcha/background/6.jpg new file mode 100644 index 00000000..5d8febd9 Binary files /dev/null and b/assets/captcha/background/6.jpg differ diff --git a/assets/captcha/background/60.jpg b/assets/captcha/background/60.jpg new file mode 100644 index 00000000..525a981d Binary files /dev/null and b/assets/captcha/background/60.jpg differ diff --git a/assets/captcha/background/61.jpg b/assets/captcha/background/61.jpg new file mode 100644 index 00000000..6b5ebdd0 Binary files /dev/null and b/assets/captcha/background/61.jpg differ diff --git a/assets/captcha/background/62.jpg b/assets/captcha/background/62.jpg new file mode 100644 index 00000000..0667299c Binary files /dev/null and b/assets/captcha/background/62.jpg differ diff --git a/assets/captcha/background/63.jpg b/assets/captcha/background/63.jpg new file mode 100644 index 00000000..8e7192ed Binary files /dev/null and b/assets/captcha/background/63.jpg differ diff --git a/assets/captcha/background/64.jpg b/assets/captcha/background/64.jpg new file mode 100644 index 00000000..8b388371 Binary files /dev/null and b/assets/captcha/background/64.jpg differ diff --git a/assets/captcha/background/65.jpg b/assets/captcha/background/65.jpg new file mode 100644 index 00000000..5f2f2f16 Binary files /dev/null and b/assets/captcha/background/65.jpg differ diff --git a/assets/captcha/background/66.jpg b/assets/captcha/background/66.jpg new file mode 100644 index 00000000..c01e84df Binary files /dev/null and b/assets/captcha/background/66.jpg differ diff --git a/assets/captcha/background/67.jpg b/assets/captcha/background/67.jpg new file mode 100644 index 00000000..4eee5202 Binary files /dev/null and b/assets/captcha/background/67.jpg differ diff --git a/assets/captcha/background/68.jpg b/assets/captcha/background/68.jpg new file mode 100644 index 00000000..b92b9b42 Binary files /dev/null and b/assets/captcha/background/68.jpg differ diff --git a/assets/captcha/background/69.jpg b/assets/captcha/background/69.jpg new file mode 100644 index 00000000..98fa60bc Binary files /dev/null and b/assets/captcha/background/69.jpg differ diff --git a/assets/captcha/background/7.jpg b/assets/captcha/background/7.jpg new file mode 100644 index 00000000..fc0e2f14 Binary files /dev/null and b/assets/captcha/background/7.jpg differ diff --git a/assets/captcha/background/70.jpg b/assets/captcha/background/70.jpg new file mode 100644 index 00000000..1d3086f8 Binary files /dev/null and b/assets/captcha/background/70.jpg differ diff --git a/assets/captcha/background/71.jpg b/assets/captcha/background/71.jpg new file mode 100644 index 00000000..78626e7c Binary files /dev/null and b/assets/captcha/background/71.jpg differ diff --git a/assets/captcha/background/72.jpg b/assets/captcha/background/72.jpg new file mode 100644 index 00000000..dbabade3 Binary files /dev/null and b/assets/captcha/background/72.jpg differ diff --git a/assets/captcha/background/73.jpg b/assets/captcha/background/73.jpg new file mode 100644 index 00000000..8fb5916a Binary files /dev/null and b/assets/captcha/background/73.jpg differ diff --git a/assets/captcha/background/74.jpg b/assets/captcha/background/74.jpg new file mode 100644 index 00000000..68475ca2 Binary files /dev/null and b/assets/captcha/background/74.jpg differ diff --git a/assets/captcha/background/75.jpg b/assets/captcha/background/75.jpg new file mode 100644 index 00000000..0db705d8 Binary files /dev/null and b/assets/captcha/background/75.jpg differ diff --git a/assets/captcha/background/76.jpg b/assets/captcha/background/76.jpg new file mode 100644 index 00000000..822ab361 Binary files /dev/null and b/assets/captcha/background/76.jpg differ diff --git a/assets/captcha/background/77.jpg b/assets/captcha/background/77.jpg new file mode 100644 index 00000000..cdf53128 Binary files /dev/null and b/assets/captcha/background/77.jpg differ diff --git a/assets/captcha/background/78.jpg b/assets/captcha/background/78.jpg new file mode 100644 index 00000000..d355de59 Binary files /dev/null and b/assets/captcha/background/78.jpg differ diff --git a/assets/captcha/background/79.jpg b/assets/captcha/background/79.jpg new file mode 100644 index 00000000..4aa78d62 Binary files /dev/null and b/assets/captcha/background/79.jpg differ diff --git a/assets/captcha/background/8.jpg b/assets/captcha/background/8.jpg new file mode 100644 index 00000000..b5b1c386 Binary files /dev/null and b/assets/captcha/background/8.jpg differ diff --git a/assets/captcha/background/80.jpg b/assets/captcha/background/80.jpg new file mode 100644 index 00000000..1d3086f8 Binary files /dev/null and b/assets/captcha/background/80.jpg differ diff --git a/assets/captcha/background/81.jpg b/assets/captcha/background/81.jpg new file mode 100644 index 00000000..6977db67 Binary files /dev/null and b/assets/captcha/background/81.jpg differ diff --git a/assets/captcha/background/82.jpg b/assets/captcha/background/82.jpg new file mode 100644 index 00000000..aa0f3cd0 Binary files /dev/null and b/assets/captcha/background/82.jpg differ diff --git a/assets/captcha/background/83.jpg b/assets/captcha/background/83.jpg new file mode 100644 index 00000000..de28472a Binary files /dev/null and b/assets/captcha/background/83.jpg differ diff --git a/assets/captcha/background/84.jpg b/assets/captcha/background/84.jpg new file mode 100644 index 00000000..5bc6ae84 Binary files /dev/null and b/assets/captcha/background/84.jpg differ diff --git a/assets/captcha/background/85.jpg b/assets/captcha/background/85.jpg new file mode 100644 index 00000000..dbcfc208 Binary files /dev/null and b/assets/captcha/background/85.jpg differ diff --git a/assets/captcha/background/86.jpg b/assets/captcha/background/86.jpg new file mode 100644 index 00000000..26edc97f Binary files /dev/null and b/assets/captcha/background/86.jpg differ diff --git a/assets/captcha/background/87.jpg b/assets/captcha/background/87.jpg new file mode 100644 index 00000000..e86db4ed Binary files /dev/null and b/assets/captcha/background/87.jpg differ diff --git a/assets/captcha/background/88.jpg b/assets/captcha/background/88.jpg new file mode 100644 index 00000000..5d05d76d Binary files /dev/null and b/assets/captcha/background/88.jpg differ diff --git a/assets/captcha/background/89.jpg b/assets/captcha/background/89.jpg new file mode 100644 index 00000000..e53820f4 Binary files /dev/null and b/assets/captcha/background/89.jpg differ diff --git a/assets/captcha/background/9.jpg b/assets/captcha/background/9.jpg new file mode 100644 index 00000000..16c0569a Binary files /dev/null and b/assets/captcha/background/9.jpg differ diff --git a/assets/captcha/background/90.jpg b/assets/captcha/background/90.jpg new file mode 100644 index 00000000..03e95213 Binary files /dev/null and b/assets/captcha/background/90.jpg differ diff --git a/assets/captcha/background/91.jpg b/assets/captcha/background/91.jpg new file mode 100644 index 00000000..fc0e2f14 Binary files /dev/null and b/assets/captcha/background/91.jpg differ diff --git a/assets/captcha/background/92.jpg b/assets/captcha/background/92.jpg new file mode 100644 index 00000000..58e49d93 Binary files /dev/null and b/assets/captcha/background/92.jpg differ diff --git a/assets/captcha/background/93.jpg b/assets/captcha/background/93.jpg new file mode 100644 index 00000000..d3453998 Binary files /dev/null and b/assets/captcha/background/93.jpg differ diff --git a/assets/captcha/background/94.jpg b/assets/captcha/background/94.jpg new file mode 100644 index 00000000..c9f4b08e Binary files /dev/null and b/assets/captcha/background/94.jpg differ diff --git a/assets/captcha/background/95.jpg b/assets/captcha/background/95.jpg new file mode 100644 index 00000000..7c095065 Binary files /dev/null and b/assets/captcha/background/95.jpg differ diff --git a/assets/captcha/background/96.jpg b/assets/captcha/background/96.jpg new file mode 100644 index 00000000..ee96fb8b Binary files /dev/null and b/assets/captcha/background/96.jpg differ diff --git a/assets/captcha/background/97.jpg b/assets/captcha/background/97.jpg new file mode 100644 index 00000000..ba84d3a5 Binary files /dev/null and b/assets/captcha/background/97.jpg differ diff --git a/assets/captcha/background/98.jpg b/assets/captcha/background/98.jpg new file mode 100644 index 00000000..5b9b39bc Binary files /dev/null and b/assets/captcha/background/98.jpg differ diff --git a/assets/captcha/background/99.jpg b/assets/captcha/background/99.jpg new file mode 100644 index 00000000..582bc75f Binary files /dev/null and b/assets/captcha/background/99.jpg differ diff --git a/assets/captcha/template/1/dark.png b/assets/captcha/template/1/dark.png new file mode 100644 index 00000000..8684a67e Binary files /dev/null and b/assets/captcha/template/1/dark.png differ diff --git a/assets/captcha/template/1/transparent.png b/assets/captcha/template/1/transparent.png new file mode 100644 index 00000000..9e568ed6 Binary files /dev/null and b/assets/captcha/template/1/transparent.png differ diff --git a/assets/captcha/template/2/dark.png b/assets/captcha/template/2/dark.png new file mode 100644 index 00000000..bcc08bdd Binary files /dev/null and b/assets/captcha/template/2/dark.png differ diff --git a/assets/captcha/template/2/transparent.png b/assets/captcha/template/2/transparent.png new file mode 100644 index 00000000..e2fa6257 Binary files /dev/null and b/assets/captcha/template/2/transparent.png differ diff --git a/assets/captcha/template/3/dark.png b/assets/captcha/template/3/dark.png new file mode 100644 index 00000000..cb4ee592 Binary files /dev/null and b/assets/captcha/template/3/dark.png differ diff --git a/assets/captcha/template/3/transparent.png b/assets/captcha/template/3/transparent.png new file mode 100644 index 00000000..aa14e19b Binary files /dev/null and b/assets/captcha/template/3/transparent.png differ diff --git a/assets/captcha/template/4/dark.png b/assets/captcha/template/4/dark.png new file mode 100644 index 00000000..b9399273 Binary files /dev/null and b/assets/captcha/template/4/dark.png differ diff --git a/assets/captcha/template/4/transparent.png b/assets/captcha/template/4/transparent.png new file mode 100644 index 00000000..41192d5c Binary files /dev/null and b/assets/captcha/template/4/transparent.png differ diff --git a/assets/captcha/template/5/dark.png b/assets/captcha/template/5/dark.png new file mode 100644 index 00000000..24df9307 Binary files /dev/null and b/assets/captcha/template/5/dark.png differ diff --git a/assets/captcha/template/5/transparent.png b/assets/captcha/template/5/transparent.png new file mode 100644 index 00000000..6edc2b94 Binary files /dev/null and b/assets/captcha/template/5/transparent.png differ diff --git a/assets/captcha/template/6/dark.png b/assets/captcha/template/6/dark.png new file mode 100644 index 00000000..2b128349 Binary files /dev/null and b/assets/captcha/template/6/dark.png differ diff --git a/assets/captcha/template/6/transparent.png b/assets/captcha/template/6/transparent.png new file mode 100644 index 00000000..700424ad Binary files /dev/null and b/assets/captcha/template/6/transparent.png differ diff --git a/assets/logo/drone.png b/assets/logo/drone.png new file mode 100644 index 00000000..fa16e5ce Binary files /dev/null and b/assets/logo/drone.png differ diff --git a/assets/logo/drone_red.png b/assets/logo/drone_red.png new file mode 100644 index 00000000..67023597 Binary files /dev/null and b/assets/logo/drone_red.png differ diff --git a/assets/logo/gitea.png b/assets/logo/gitea.png new file mode 100644 index 00000000..fac41d96 Binary files /dev/null and b/assets/logo/gitea.png differ diff --git a/assets/logo/grafana.png b/assets/logo/grafana.png new file mode 100644 index 00000000..553821a0 Binary files /dev/null and b/assets/logo/grafana.png differ diff --git a/assets/logo/line.png b/assets/logo/line.png new file mode 100644 index 00000000..c2ce860c Binary files /dev/null and b/assets/logo/line.png differ diff --git a/assets/minio/docker-compose-minio.yml b/assets/minio/docker-compose-minio.yml new file mode 100644 index 00000000..9ed7b5db --- /dev/null +++ b/assets/minio/docker-compose-minio.yml @@ -0,0 +1,15 @@ +version: "3" +services: + net-admin-minio: + image: minio/minio:latest + command: server /data --console-address ":9001" + ports: + - "9000:9000" + - "9001:9001" + restart: always + container_name: net-admin-minio + environment: + TZ: Asia/Shanghai + volumes: + - /etc/localtime:/etc/localtime + - /etc/timezone:/etc/timezone \ No newline at end of file diff --git a/assets/resx/Ln.resx b/assets/resx/Ln.resx new file mode 100644 index 00000000..8883d0db --- /dev/null +++ b/assets/resx/Ln.resx @@ -0,0 +1,216 @@ + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + 1分钟内只能发送1次 + 6位数字 + 8位以上数字字母组合 + Xml注释文件不存在 + 不正确 + 不能为空 + 业务模块 + 东乡族 + 丧偶 + 中专 + 中共党员 + 中文姓名 + 乌孜别克族 + 事务已回滚 + 事务已提交 + 京族 + 人机校验请求 + 人机验证未通过 + 仡佬族 + 仫佬族 + 佤族 + 侗族 + 俄罗斯族 + 保安族 + 保密 + 倒序排序 + 傈僳族 + 傣族 + 允许的文件大小 + 允许的文件格式 + 全部数据 + 共青团员 + 出生证 + 初中 + 初始化完毕 + 区号电话号码分机号 + 博士 + 博士后 + 参数格式不正确 + 发送失败 + 哈尼族 + 哈萨克族 + 唯一编码 + 回族 + 图标代码 + 图标名称 + 土家族 + 土族 + 基诺族 + 塔吉克族 + 塔塔尔族 + 壮族 + 外国人居留证 + 大专 + + 字典名称 + 字典目录不存在 + 字典目录编号 + 字典编码 + 密码 + 小学 + 已发送 + 已婚 + 已完成 + 已校验 + 布依族 + 布朗族 + 开始事务 + 彝族 + 德昂族 + 必须介于 + 怒族 + 意外错误 + 成功 + 手机 + 手机号码 + 手机号码或座机号码 + 护照 + 拉祜族族 + 指定部门数据 + 按钮 + 撒拉族 + 支付宝账号 + 数据库同步开始 + 数据库服务器时钟偏移 + 数据库结构同步完成 + 数据版本 + 文件不能为空 + 新密码 + 新手机号码 + 无效操作 + 无效网络地址 + 无效证件号码 + 无效输入 + 日志长度超过限制 + 旧密码 + 旧手机号码 + 时间戳缺失或误差过大 + 普米族 + 景颇族 + 朝鲜族 + 未婚 + 未指定部门 + 本人数据 + 本科 + 本部门和下级部门数据 + 本部门数据 + 柯尔克孜族 + 框架 + 毛南族 + 水族 + 汉族 + 注册 + 港澳台通行证 + 满族 + 父节点不存在 + 独龙族 + 珞巴族 + 瑶族 + 用户不存在 + 用户名 + 用户名不能是手机号 + 用户名或密码错误 + 用户名长度4位以上 + 用户头像 + 用户档案 + 电子邮箱 + + 畲族 + 登录 + 白族 + 目标手机 + 目标设备 + 短信验证请求 + 硕士 + 离异 + 等待发送 + 签名缺失 + 系统模块 + 纳西族 + 绑定手机号 + 结果非预期 + 维吾尔族 + 羌族 + 群众 + 苗族 + 菜单 + 菜单名称 + 菜单标题 + 菜单编号 + 蒙古族 + 藏族 + 裕固族 + 角色不存在 + 角色名称 + 角色编号 + 角色编号列表 + 解绑手机号 + 设备类型 + 该角色下存在用户 + 该部门下存在子部门 + 该部门下存在用户 + 请求 + 请求对象 + 请联系管理员激活账号 + 读取用户令牌出错 + 账号 + 赫哲族 + 身份证 + 达斡尔族 + 邀请码不正确 + 邮箱验证码不正确 + 部门不存在 + 部门名称 + 鄂伦春族 + 鄂温克族 + 重设密码 + 链接 + 锡伯族 + 键值 + 键名称 + 门巴族 + 阿昌族 + 顺序排序 + 验证数据 + 验证码 + 验证码不正确 + 验证码类型 + 高中 + 高山族 + 黎族 + \ No newline at end of file diff --git a/assets/resx/Ln.txt b/assets/resx/Ln.txt new file mode 100644 index 00000000..31457baf --- /dev/null +++ b/assets/resx/Ln.txt @@ -0,0 +1,191 @@ +1分钟内只能发送1次 +6位数字 +8位以上数字字母组合 +Xml注释文件不存在 +不正确 +不能为空 +业务模块 +东乡族 +丧偶 +中专 +中共党员 +中文姓名 +乌孜别克族 +事务已回滚 +事务已提交 +京族 +人机校验请求 +人机验证未通过 +仡佬族 +仫佬族 +佤族 +侗族 +俄罗斯族 +保安族 +保密 +倒序排序 +傈僳族 +傣族 +允许的文件大小 +允许的文件格式 +全部数据 +共青团员 +出生证 +初中 +初始化完毕 +区号电话号码分机号 +博士 +博士后 +参数格式不正确 +发送失败 +哈尼族 +哈萨克族 +唯一编码 +回族 +图标代码 +图标名称 +土家族 +土族 +基诺族 +塔吉克族 +塔塔尔族 +壮族 +外国人居留证 +大专 +女 +字典名称 +字典目录不存在 +字典目录编号 +字典编码 +密码 +小学 +已发送 +已婚 +已完成 +已校验 +布依族 +布朗族 +开始事务 +彝族 +德昂族 +必须介于 +怒族 +意外错误 +成功 +手机 +手机号码 +手机号码或座机号码 +护照 +拉祜族族 +指定部门数据 +按钮 +撒拉族 +支付宝账号 +数据库同步开始 +数据库服务器时钟偏移 +数据库结构同步完成 +数据版本 +文件不能为空 +新密码 +新手机号码 +无效操作 +无效网络地址 +无效证件号码 +无效输入 +日志长度超过限制 +旧密码 +旧手机号码 +时间戳缺失或误差过大 +普米族 +景颇族 +朝鲜族 +未婚 +未指定部门 +本人数据 +本科 +本部门和下级部门数据 +本部门数据 +柯尔克孜族 +框架 +毛南族 +水族 +汉族 +注册 +港澳台通行证 +满族 +父节点不存在 +独龙族 +珞巴族 +瑶族 +用户不存在 +用户名 +用户名不能是手机号 +用户名或密码错误 +用户名长度4位以上 +用户头像 +用户档案 +电子邮箱 +男 +畲族 +登录 +白族 +目标手机 +目标设备 +短信验证请求 +硕士 +离异 +等待发送 +签名缺失 +系统模块 +纳西族 +绑定手机号 +结果非预期 +维吾尔族 +羌族 +群众 +苗族 +菜单 +菜单名称 +菜单标题 +菜单编号 +蒙古族 +藏族 +裕固族 +角色不存在 +角色名称 +角色编号 +角色编号列表 +解绑手机号 +设备类型 +该角色下存在用户 +该部门下存在子部门 +该部门下存在用户 +请求 +请求对象 +请联系管理员激活账号 +读取用户令牌出错 +账号 +赫哲族 +身份证 +达斡尔族 +邀请码不正确 +邮箱验证码不正确 +部门不存在 +部门名称 +鄂伦春族 +鄂温克族 +重设密码 +链接 +锡伯族 +键值 +键名称 +门巴族 +阿昌族 +顺序排序 +验证数据 +验证码 +验证码不正确 +验证码类型 +高中 +高山族 +黎族 \ No newline at end of file diff --git a/assets/seed-data/Sys_Config.json b/assets/seed-data/Sys_Config.json new file mode 100644 index 00000000..68a2abd8 --- /dev/null +++ b/assets/seed-data/Sys_Config.json @@ -0,0 +1,8 @@ +[ + { + "Enabled": true, + "UserRegisterConfirm": false, + "UserRegisterDeptId": 372119301627909, + "UserRegisterRoleId": 371729946431493 + } +] \ No newline at end of file diff --git a/assets/seed-data/Sys_Dept.json b/assets/seed-data/Sys_Dept.json new file mode 100644 index 00000000..37ba0225 --- /dev/null +++ b/assets/seed-data/Sys_Dept.json @@ -0,0 +1,8 @@ +[ + { + "Id": 372119301627909, + "Name": "默认部门", + "Enabled": true, + "Sort": 100 + } +] \ No newline at end of file diff --git a/assets/seed-data/Sys_DicCatalog.json b/assets/seed-data/Sys_DicCatalog.json new file mode 100644 index 00000000..1c47893f --- /dev/null +++ b/assets/seed-data/Sys_DicCatalog.json @@ -0,0 +1,13 @@ +[ + { + "Code": "generic", + "Id": 375317236772869, + "Name": "通用字典" + }, + { + "Code": "geo-area", + "Id": 379794295185413, + "Name": "行政区划代码", + "ParentId": 375317236772869 + } +] \ No newline at end of file diff --git a/assets/seed-data/Sys_DicContent.json b/assets/seed-data/Sys_DicContent.json new file mode 100644 index 00000000..48ef2913 --- /dev/null +++ b/assets/seed-data/Sys_DicContent.json @@ -0,0 +1,19250 @@ +[ + { + "CatalogId": 379794295185413, + "Id": 396423788572677, + "Key": "北京市", + "Value": "110000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788580869, + "Key": "北京市东城区", + "Value": "110101" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584965, + "Key": "北京市西城区", + "Value": "110102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584966, + "Key": "北京市朝阳区", + "Value": "110105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584967, + "Key": "北京市丰台区", + "Value": "110106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584968, + "Key": "北京市石景山区", + "Value": "110107" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584969, + "Key": "北京市海淀区", + "Value": "110108" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584970, + "Key": "北京市门头沟区", + "Value": "110109" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584971, + "Key": "北京市房山区", + "Value": "110111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584972, + "Key": "北京市通州区", + "Value": "110112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584973, + "Key": "北京市顺义区", + "Value": "110113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584974, + "Key": "北京市昌平区", + "Value": "110114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584975, + "Key": "北京市大兴区", + "Value": "110115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788584976, + "Key": "北京市怀柔区", + "Value": "110116" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589061, + "Key": "北京市平谷区", + "Value": "110117" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589062, + "Key": "北京市密云区", + "Value": "110118" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589063, + "Key": "北京市延庆区", + "Value": "110119" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589064, + "Key": "天津市", + "Value": "120000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589065, + "Key": "天津市和平区", + "Value": "120101" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589066, + "Key": "天津市河东区", + "Value": "120102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589067, + "Key": "天津市河西区", + "Value": "120103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589068, + "Key": "天津市南开区", + "Value": "120104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589069, + "Key": "天津市河北区", + "Value": "120105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589070, + "Key": "天津市红桥区", + "Value": "120106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589071, + "Key": "天津市东丽区", + "Value": "120110" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788589072, + "Key": "天津市西青区", + "Value": "120111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788593157, + "Key": "天津市津南区", + "Value": "120112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788593158, + "Key": "天津市北辰区", + "Value": "120113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788593159, + "Key": "天津市武清区", + "Value": "120114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788593160, + "Key": "天津市宝坻区", + "Value": "120115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788593161, + "Key": "天津市滨海新区", + "Value": "120116" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788593162, + "Key": "天津市宁河区", + "Value": "120117" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788593163, + "Key": "天津市静海区", + "Value": "120118" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788593164, + "Key": "天津市蓟州区", + "Value": "120119" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788593165, + "Key": "河北省", + "Value": "130000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788593166, + "Key": "河北省石家庄市", + "Value": "130100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788593167, + "Key": "河北省石家庄市长安区", + "Value": "130102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597253, + "Key": "河北省石家庄市桥西区", + "Value": "130104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597254, + "Key": "河北省石家庄市新华区", + "Value": "130105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597255, + "Key": "河北省石家庄市井陉矿区", + "Value": "130107" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597256, + "Key": "河北省石家庄市裕华区", + "Value": "130108" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597257, + "Key": "河北省石家庄市藁城区", + "Value": "130109" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597258, + "Key": "河北省石家庄市鹿泉区", + "Value": "130110" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597259, + "Key": "河北省石家庄市栾城区", + "Value": "130111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597260, + "Key": "河北省石家庄市井陉县", + "Value": "130121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597261, + "Key": "河北省石家庄市正定县", + "Value": "130123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597262, + "Key": "河北省石家庄市行唐县", + "Value": "130125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597263, + "Key": "河北省石家庄市灵寿县", + "Value": "130126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788597264, + "Key": "河北省石家庄市高邑县", + "Value": "130127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601349, + "Key": "河北省石家庄市深泽县", + "Value": "130128" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601350, + "Key": "河北省石家庄市赞皇县", + "Value": "130129" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601351, + "Key": "河北省石家庄市无极县", + "Value": "130130" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601352, + "Key": "河北省石家庄市平山县", + "Value": "130131" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601353, + "Key": "河北省石家庄市元氏县", + "Value": "130132" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601354, + "Key": "河北省石家庄市赵县", + "Value": "130133" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601355, + "Key": "河北省石家庄市辛集市", + "Value": "130181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601356, + "Key": "河北省石家庄市晋州市", + "Value": "130183" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601357, + "Key": "河北省石家庄市新乐市", + "Value": "130184" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601358, + "Key": "河北省唐山市", + "Value": "130200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601359, + "Key": "河北省唐山市路南区", + "Value": "130202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788601360, + "Key": "河北省唐山市路北区", + "Value": "130203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605445, + "Key": "河北省唐山市古冶区", + "Value": "130204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605446, + "Key": "河北省唐山市开平区", + "Value": "130205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605447, + "Key": "河北省唐山市丰南区", + "Value": "130207" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605448, + "Key": "河北省唐山市丰润区", + "Value": "130208" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605449, + "Key": "河北省唐山市曹妃甸区", + "Value": "130209" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605450, + "Key": "河北省唐山市滦南县", + "Value": "130224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605451, + "Key": "河北省唐山市乐亭县", + "Value": "130225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605452, + "Key": "河北省唐山市迁西县", + "Value": "130227" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605453, + "Key": "河北省唐山市玉田县", + "Value": "130229" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605454, + "Key": "河北省唐山市遵化市", + "Value": "130281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605455, + "Key": "河北省唐山市迁安市", + "Value": "130283" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788605456, + "Key": "河北省唐山市滦州市", + "Value": "130284" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609541, + "Key": "河北省秦皇岛市", + "Value": "130300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609542, + "Key": "河北省秦皇岛市海港区", + "Value": "130302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609543, + "Key": "河北省秦皇岛市山海关区", + "Value": "130303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609544, + "Key": "河北省秦皇岛市北戴河区", + "Value": "130304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609545, + "Key": "河北省秦皇岛市抚宁区", + "Value": "130306" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609546, + "Key": "河北省秦皇岛市青龙满族自治县", + "Value": "130321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609547, + "Key": "河北省秦皇岛市昌黎县", + "Value": "130322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609548, + "Key": "河北省秦皇岛市卢龙县", + "Value": "130324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609549, + "Key": "河北省邯郸市", + "Value": "130400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609550, + "Key": "河北省邯郸市邯山区", + "Value": "130402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609551, + "Key": "河北省邯郸市丛台区", + "Value": "130403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788609552, + "Key": "河北省邯郸市复兴区", + "Value": "130404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613637, + "Key": "河北省邯郸市峰峰矿区", + "Value": "130406" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613638, + "Key": "河北省邯郸市肥乡区", + "Value": "130407" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613639, + "Key": "河北省邯郸市永年区", + "Value": "130408" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613640, + "Key": "河北省邯郸市临漳县", + "Value": "130423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613641, + "Key": "河北省邯郸市成安县", + "Value": "130424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613642, + "Key": "河北省邯郸市大名县", + "Value": "130425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613643, + "Key": "河北省邯郸市涉县", + "Value": "130426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613644, + "Key": "河北省邯郸市磁县", + "Value": "130427" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613645, + "Key": "河北省邯郸市邱县", + "Value": "130430" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613646, + "Key": "河北省邯郸市鸡泽县", + "Value": "130431" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613647, + "Key": "河北省邯郸市广平县", + "Value": "130432" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788613648, + "Key": "河北省邯郸市馆陶县", + "Value": "130433" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617733, + "Key": "河北省邯郸市魏县", + "Value": "130434" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617734, + "Key": "河北省邯郸市曲周县", + "Value": "130435" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617735, + "Key": "河北省邯郸市武安市", + "Value": "130481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617736, + "Key": "河北省邢台市", + "Value": "130500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617737, + "Key": "河北省邢台市襄都区", + "Value": "130502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617738, + "Key": "河北省邢台市信都区", + "Value": "130503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617739, + "Key": "河北省邢台市任泽区", + "Value": "130505" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617740, + "Key": "河北省邢台市南和区", + "Value": "130506" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617741, + "Key": "河北省邢台市临城县", + "Value": "130522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617742, + "Key": "河北省邢台市内丘县", + "Value": "130523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617743, + "Key": "河北省邢台市柏乡县", + "Value": "130524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788617744, + "Key": "河北省邢台市隆尧县", + "Value": "130525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621829, + "Key": "河北省邢台市宁晋县", + "Value": "130528" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621830, + "Key": "河北省邢台市巨鹿县", + "Value": "130529" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621831, + "Key": "河北省邢台市新河县", + "Value": "130530" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621832, + "Key": "河北省邢台市广宗县", + "Value": "130531" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621833, + "Key": "河北省邢台市平乡县", + "Value": "130532" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621834, + "Key": "河北省邢台市威县", + "Value": "130533" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621835, + "Key": "河北省邢台市清河县", + "Value": "130534" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621836, + "Key": "河北省邢台市临西县", + "Value": "130535" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621837, + "Key": "河北省邢台市南宫市", + "Value": "130581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621838, + "Key": "河北省邢台市沙河市", + "Value": "130582" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621839, + "Key": "河北省保定市", + "Value": "130600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788621840, + "Key": "河北省保定市竞秀区", + "Value": "130602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625925, + "Key": "河北省保定市莲池区", + "Value": "130606" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625926, + "Key": "河北省保定市满城区", + "Value": "130607" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625927, + "Key": "河北省保定市清苑区", + "Value": "130608" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625928, + "Key": "河北省保定市徐水区", + "Value": "130609" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625929, + "Key": "河北省保定市涞水县", + "Value": "130623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625930, + "Key": "河北省保定市阜平县", + "Value": "130624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625931, + "Key": "河北省保定市定兴县", + "Value": "130626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625932, + "Key": "河北省保定市唐县", + "Value": "130627" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625933, + "Key": "河北省保定市高阳县", + "Value": "130628" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625934, + "Key": "河北省保定市容城县", + "Value": "130629" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625935, + "Key": "河北省保定市涞源县", + "Value": "130630" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788625936, + "Key": "河北省保定市望都县", + "Value": "130631" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630021, + "Key": "河北省保定市安新县", + "Value": "130632" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630022, + "Key": "河北省保定市易县", + "Value": "130633" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630023, + "Key": "河北省保定市曲阳县", + "Value": "130634" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630024, + "Key": "河北省保定市蠡县", + "Value": "130635" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630025, + "Key": "河北省保定市顺平县", + "Value": "130636" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630026, + "Key": "河北省保定市博野县", + "Value": "130637" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630027, + "Key": "河北省保定市雄县", + "Value": "130638" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630028, + "Key": "河北省保定市涿州市", + "Value": "130681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630029, + "Key": "河北省保定市定州市", + "Value": "130682" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630030, + "Key": "河北省保定市安国市", + "Value": "130683" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630031, + "Key": "河北省保定市高碑店市", + "Value": "130684" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630032, + "Key": "河北省张家口市", + "Value": "130700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788630033, + "Key": "河北省张家口市桥东区", + "Value": "130702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634117, + "Key": "河北省张家口市桥西区", + "Value": "130703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634118, + "Key": "河北省张家口市宣化区", + "Value": "130705" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634119, + "Key": "河北省张家口市下花园区", + "Value": "130706" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634120, + "Key": "河北省张家口市万全区", + "Value": "130708" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634121, + "Key": "河北省张家口市崇礼区", + "Value": "130709" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634122, + "Key": "河北省张家口市张北县", + "Value": "130722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634123, + "Key": "河北省张家口市康保县", + "Value": "130723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634124, + "Key": "河北省张家口市沽源县", + "Value": "130724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634125, + "Key": "河北省张家口市尚义县", + "Value": "130725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634126, + "Key": "河北省张家口市蔚县", + "Value": "130726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634127, + "Key": "河北省张家口市阳原县", + "Value": "130727" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788634128, + "Key": "河北省张家口市怀安县", + "Value": "130728" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788638213, + "Key": "河北省张家口市怀来县", + "Value": "130730" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788638214, + "Key": "河北省张家口市涿鹿县", + "Value": "130731" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788638215, + "Key": "河北省张家口市赤城县", + "Value": "130732" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788638216, + "Key": "河北省承德市", + "Value": "130800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788638217, + "Key": "河北省承德市双桥区", + "Value": "130802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788638218, + "Key": "河北省承德市双滦区", + "Value": "130803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788638219, + "Key": "河北省承德市鹰手营子矿区", + "Value": "130804" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788638220, + "Key": "河北省承德市承德县", + "Value": "130821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788638221, + "Key": "河北省承德市兴隆县", + "Value": "130822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788638222, + "Key": "河北省承德市滦平县", + "Value": "130824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788638223, + "Key": "河北省承德市隆化县", + "Value": "130825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642309, + "Key": "河北省承德市丰宁满族自治县", + "Value": "130826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642310, + "Key": "河北省承德市宽城满族自治县", + "Value": "130827" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642311, + "Key": "河北省承德市围场满族蒙古族自治县", + "Value": "130828" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642312, + "Key": "河北省承德市平泉市", + "Value": "130881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642313, + "Key": "河北省沧州市", + "Value": "130900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642314, + "Key": "河北省沧州市新华区", + "Value": "130902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642315, + "Key": "河北省沧州市运河区", + "Value": "130903" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642316, + "Key": "河北省沧州市沧县", + "Value": "130921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642317, + "Key": "河北省沧州市青县", + "Value": "130922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642318, + "Key": "河北省沧州市东光县", + "Value": "130923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642319, + "Key": "河北省沧州市海兴县", + "Value": "130924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788642320, + "Key": "河北省沧州市盐山县", + "Value": "130925" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788646405, + "Key": "河北省沧州市肃宁县", + "Value": "130926" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788646406, + "Key": "河北省沧州市南皮县", + "Value": "130927" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788646407, + "Key": "河北省沧州市吴桥县", + "Value": "130928" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788646408, + "Key": "河北省沧州市献县", + "Value": "130929" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788646409, + "Key": "河北省沧州市孟村回族自治县", + "Value": "130930" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788646410, + "Key": "河北省沧州市泊头市", + "Value": "130981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788646411, + "Key": "河北省沧州市任丘市", + "Value": "130982" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788646412, + "Key": "河北省沧州市黄骅市", + "Value": "130983" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788646413, + "Key": "河北省沧州市河间市", + "Value": "130984" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788646414, + "Key": "河北省廊坊市", + "Value": "131000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788646415, + "Key": "河北省廊坊市安次区", + "Value": "131002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650501, + "Key": "河北省廊坊市广阳区", + "Value": "131003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650502, + "Key": "河北省廊坊市固安县", + "Value": "131022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650503, + "Key": "河北省廊坊市永清县", + "Value": "131023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650504, + "Key": "河北省廊坊市香河县", + "Value": "131024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650505, + "Key": "河北省廊坊市大城县", + "Value": "131025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650506, + "Key": "河北省廊坊市文安县", + "Value": "131026" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650507, + "Key": "河北省廊坊市大厂回族自治县", + "Value": "131028" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650508, + "Key": "河北省廊坊市霸州市", + "Value": "131081" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650509, + "Key": "河北省廊坊市三河市", + "Value": "131082" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650510, + "Key": "河北省衡水市", + "Value": "131100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650511, + "Key": "河北省衡水市桃城区", + "Value": "131102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788650512, + "Key": "河北省衡水市冀州区", + "Value": "131103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788654597, + "Key": "河北省衡水市枣强县", + "Value": "131121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788654598, + "Key": "河北省衡水市武邑县", + "Value": "131122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788654599, + "Key": "河北省衡水市武强县", + "Value": "131123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788654600, + "Key": "河北省衡水市饶阳县", + "Value": "131124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788654601, + "Key": "河北省衡水市安平县", + "Value": "131125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788654602, + "Key": "河北省衡水市故城县", + "Value": "131126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788654603, + "Key": "河北省衡水市景县", + "Value": "131127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788654604, + "Key": "河北省衡水市阜城县", + "Value": "131128" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788654605, + "Key": "河北省衡水市深州市", + "Value": "131182" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788654606, + "Key": "山西省", + "Value": "140000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788654607, + "Key": "山西省太原市", + "Value": "140100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788658693, + "Key": "山西省太原市小店区", + "Value": "140105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788658694, + "Key": "山西省太原市迎泽区", + "Value": "140106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788658695, + "Key": "山西省太原市杏花岭区", + "Value": "140107" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788658696, + "Key": "山西省太原市尖草坪区", + "Value": "140108" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788658697, + "Key": "山西省太原市万柏林区", + "Value": "140109" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788658698, + "Key": "山西省太原市晋源区", + "Value": "140110" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788658699, + "Key": "山西省太原市清徐县", + "Value": "140121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788658700, + "Key": "山西省太原市阳曲县", + "Value": "140122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788658701, + "Key": "山西省太原市娄烦县", + "Value": "140123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788658702, + "Key": "山西省太原市古交市", + "Value": "140181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788658703, + "Key": "山西省大同市", + "Value": "140200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662789, + "Key": "山西省大同市新荣区", + "Value": "140212" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662790, + "Key": "山西省大同市平城区", + "Value": "140213" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662791, + "Key": "山西省大同市云冈区", + "Value": "140214" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662792, + "Key": "山西省大同市云州区", + "Value": "140215" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662793, + "Key": "山西省大同市阳高县", + "Value": "140221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662794, + "Key": "山西省大同市天镇县", + "Value": "140222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662795, + "Key": "山西省大同市广灵县", + "Value": "140223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662796, + "Key": "山西省大同市灵丘县", + "Value": "140224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662797, + "Key": "山西省大同市浑源县", + "Value": "140225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662798, + "Key": "山西省大同市左云县", + "Value": "140226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662799, + "Key": "山西省阳泉市", + "Value": "140300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788662800, + "Key": "山西省阳泉市城区", + "Value": "140302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666885, + "Key": "山西省阳泉市矿区", + "Value": "140303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666886, + "Key": "山西省阳泉市郊区", + "Value": "140311" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666887, + "Key": "山西省阳泉市平定县", + "Value": "140321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666888, + "Key": "山西省阳泉市盂县", + "Value": "140322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666889, + "Key": "山西省长治市", + "Value": "140400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666890, + "Key": "山西省长治市潞州区", + "Value": "140403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666891, + "Key": "山西省长治市上党区", + "Value": "140404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666892, + "Key": "山西省长治市屯留区", + "Value": "140405" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666893, + "Key": "山西省长治市潞城区", + "Value": "140406" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666894, + "Key": "山西省长治市襄垣县", + "Value": "140423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666895, + "Key": "山西省长治市平顺县", + "Value": "140425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788666896, + "Key": "山西省长治市黎城县", + "Value": "140426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670981, + "Key": "山西省长治市壶关县", + "Value": "140427" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670982, + "Key": "山西省长治市长子县", + "Value": "140428" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670983, + "Key": "山西省长治市武乡县", + "Value": "140429" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670984, + "Key": "山西省长治市沁县", + "Value": "140430" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670985, + "Key": "山西省长治市沁源县", + "Value": "140431" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670986, + "Key": "山西省晋城市", + "Value": "140500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670987, + "Key": "山西省晋城市城区", + "Value": "140502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670988, + "Key": "山西省晋城市沁水县", + "Value": "140521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670989, + "Key": "山西省晋城市阳城县", + "Value": "140522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670990, + "Key": "山西省晋城市陵川县", + "Value": "140524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670991, + "Key": "山西省晋城市泽州县", + "Value": "140525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788670992, + "Key": "山西省晋城市高平市", + "Value": "140581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675077, + "Key": "山西省朔州市", + "Value": "140600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675078, + "Key": "山西省朔州市朔城区", + "Value": "140602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675079, + "Key": "山西省朔州市平鲁区", + "Value": "140603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675080, + "Key": "山西省朔州市山阴县", + "Value": "140621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675081, + "Key": "山西省朔州市应县", + "Value": "140622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675082, + "Key": "山西省朔州市右玉县", + "Value": "140623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675083, + "Key": "山西省朔州市怀仁市", + "Value": "140681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675084, + "Key": "山西省晋中市", + "Value": "140700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675085, + "Key": "山西省晋中市榆次区", + "Value": "140702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675086, + "Key": "山西省晋中市太谷区", + "Value": "140703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675087, + "Key": "山西省晋中市榆社县", + "Value": "140721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788675088, + "Key": "山西省晋中市左权县", + "Value": "140722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679173, + "Key": "山西省晋中市和顺县", + "Value": "140723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679174, + "Key": "山西省晋中市昔阳县", + "Value": "140724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679175, + "Key": "山西省晋中市寿阳县", + "Value": "140725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679176, + "Key": "山西省晋中市祁县", + "Value": "140727" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679177, + "Key": "山西省晋中市平遥县", + "Value": "140728" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679178, + "Key": "山西省晋中市灵石县", + "Value": "140729" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679179, + "Key": "山西省晋中市介休市", + "Value": "140781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679180, + "Key": "山西省运城市", + "Value": "140800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679181, + "Key": "山西省运城市盐湖区", + "Value": "140802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679182, + "Key": "山西省运城市临猗县", + "Value": "140821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679183, + "Key": "山西省运城市万荣县", + "Value": "140822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788679184, + "Key": "山西省运城市闻喜县", + "Value": "140823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683269, + "Key": "山西省运城市稷山县", + "Value": "140824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683270, + "Key": "山西省运城市新绛县", + "Value": "140825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683271, + "Key": "山西省运城市绛县", + "Value": "140826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683272, + "Key": "山西省运城市垣曲县", + "Value": "140827" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683273, + "Key": "山西省运城市夏县", + "Value": "140828" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683274, + "Key": "山西省运城市平陆县", + "Value": "140829" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683275, + "Key": "山西省运城市芮城县", + "Value": "140830" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683276, + "Key": "山西省运城市永济市", + "Value": "140881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683277, + "Key": "山西省运城市河津市", + "Value": "140882" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683278, + "Key": "山西省忻州市", + "Value": "140900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683279, + "Key": "山西省忻州市忻府区", + "Value": "140902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683280, + "Key": "山西省忻州市定襄县", + "Value": "140921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788683281, + "Key": "山西省忻州市五台县", + "Value": "140922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687365, + "Key": "山西省忻州市代县", + "Value": "140923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687366, + "Key": "山西省忻州市繁峙县", + "Value": "140924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687367, + "Key": "山西省忻州市宁武县", + "Value": "140925" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687368, + "Key": "山西省忻州市静乐县", + "Value": "140926" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687369, + "Key": "山西省忻州市神池县", + "Value": "140927" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687370, + "Key": "山西省忻州市五寨县", + "Value": "140928" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687371, + "Key": "山西省忻州市岢岚县", + "Value": "140929" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687372, + "Key": "山西省忻州市河曲县", + "Value": "140930" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687373, + "Key": "山西省忻州市保德县", + "Value": "140931" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687374, + "Key": "山西省忻州市偏关县", + "Value": "140932" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687375, + "Key": "山西省忻州市原平市", + "Value": "140981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788687376, + "Key": "山西省临汾市", + "Value": "141000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691461, + "Key": "山西省临汾市尧都区", + "Value": "141002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691462, + "Key": "山西省临汾市曲沃县", + "Value": "141021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691463, + "Key": "山西省临汾市翼城县", + "Value": "141022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691464, + "Key": "山西省临汾市襄汾县", + "Value": "141023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691465, + "Key": "山西省临汾市洪洞县", + "Value": "141024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691466, + "Key": "山西省临汾市古县", + "Value": "141025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691467, + "Key": "山西省临汾市安泽县", + "Value": "141026" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691468, + "Key": "山西省临汾市浮山县", + "Value": "141027" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691469, + "Key": "山西省临汾市吉县", + "Value": "141028" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691470, + "Key": "山西省临汾市乡宁县", + "Value": "141029" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691471, + "Key": "山西省临汾市大宁县", + "Value": "141030" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691472, + "Key": "山西省临汾市隰县", + "Value": "141031" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788691473, + "Key": "山西省临汾市永和县", + "Value": "141032" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695557, + "Key": "山西省临汾市蒲县", + "Value": "141033" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695558, + "Key": "山西省临汾市汾西县", + "Value": "141034" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695559, + "Key": "山西省临汾市侯马市", + "Value": "141081" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695560, + "Key": "山西省临汾市霍州市", + "Value": "141082" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695561, + "Key": "山西省吕梁市", + "Value": "141100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695562, + "Key": "山西省吕梁市离石区", + "Value": "141102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695563, + "Key": "山西省吕梁市文水县", + "Value": "141121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695564, + "Key": "山西省吕梁市交城县", + "Value": "141122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695565, + "Key": "山西省吕梁市兴县", + "Value": "141123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695566, + "Key": "山西省吕梁市临县", + "Value": "141124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695567, + "Key": "山西省吕梁市柳林县", + "Value": "141125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695568, + "Key": "山西省吕梁市石楼县", + "Value": "141126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788695569, + "Key": "山西省吕梁市岚县", + "Value": "141127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699653, + "Key": "山西省吕梁市方山县", + "Value": "141128" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699654, + "Key": "山西省吕梁市中阳县", + "Value": "141129" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699655, + "Key": "山西省吕梁市交口县", + "Value": "141130" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699656, + "Key": "山西省吕梁市孝义市", + "Value": "141181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699657, + "Key": "山西省吕梁市汾阳市", + "Value": "141182" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699658, + "Key": "内蒙古自治区", + "Value": "150000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699659, + "Key": "内蒙古自治区呼和浩特市呼和浩特市", + "Value": "150100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699660, + "Key": "内蒙古自治区呼和浩特市新城区", + "Value": "150102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699661, + "Key": "内蒙古自治区呼和浩特市回民区", + "Value": "150103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699662, + "Key": "内蒙古自治区呼和浩特市玉泉区", + "Value": "150104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699663, + "Key": "内蒙古自治区呼和浩特市赛罕区", + "Value": "150105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788699664, + "Key": "内蒙古自治区呼和浩特市土默特左旗", + "Value": "150121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703749, + "Key": "内蒙古自治区呼和浩特市托克托县", + "Value": "150122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703750, + "Key": "内蒙古自治区呼和浩特市和林格尔县", + "Value": "150123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703751, + "Key": "内蒙古自治区呼和浩特市清水河县", + "Value": "150124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703752, + "Key": "内蒙古自治区呼和浩特市武川县", + "Value": "150125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703753, + "Key": "内蒙古自治区包头市", + "Value": "150200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703754, + "Key": "内蒙古自治区包头市东河区", + "Value": "150202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703755, + "Key": "内蒙古自治区包头市昆都仑区", + "Value": "150203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703756, + "Key": "内蒙古自治区包头市青山区", + "Value": "150204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703757, + "Key": "内蒙古自治区包头市石拐区", + "Value": "150205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703758, + "Key": "内蒙古自治区包头市白云鄂博矿区", + "Value": "150206" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703759, + "Key": "内蒙古自治区包头市九原区", + "Value": "150207" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703760, + "Key": "内蒙古自治区包头市土默特右旗", + "Value": "150221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788703761, + "Key": "内蒙古自治区包头市固阳县", + "Value": "150222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707845, + "Key": "内蒙古自治区包头市达尔罕茂明安联合旗", + "Value": "150223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707846, + "Key": "内蒙古自治区乌海市", + "Value": "150300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707847, + "Key": "内蒙古自治区乌海市海勃湾区", + "Value": "150302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707848, + "Key": "内蒙古自治区乌海市海南区", + "Value": "150303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707849, + "Key": "内蒙古自治区乌海市乌达区", + "Value": "150304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707850, + "Key": "内蒙古自治区赤峰市", + "Value": "150400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707851, + "Key": "内蒙古自治区赤峰市红山区", + "Value": "150402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707852, + "Key": "内蒙古自治区赤峰市元宝山区", + "Value": "150403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707853, + "Key": "内蒙古自治区赤峰市松山区", + "Value": "150404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707854, + "Key": "内蒙古自治区赤峰市阿鲁科尔沁旗", + "Value": "150421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707855, + "Key": "内蒙古自治区赤峰市巴林左旗", + "Value": "150422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788707856, + "Key": "内蒙古自治区赤峰市巴林右旗", + "Value": "150423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711941, + "Key": "内蒙古自治区赤峰市林西县", + "Value": "150424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711942, + "Key": "内蒙古自治区赤峰市克什克腾旗", + "Value": "150425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711943, + "Key": "内蒙古自治区赤峰市翁牛特旗", + "Value": "150426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711944, + "Key": "内蒙古自治区赤峰市喀喇沁旗", + "Value": "150428" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711945, + "Key": "内蒙古自治区赤峰市宁城县", + "Value": "150429" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711946, + "Key": "内蒙古自治区赤峰市敖汉旗", + "Value": "150430" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711947, + "Key": "内蒙古自治区通辽市", + "Value": "150500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711948, + "Key": "内蒙古自治区通辽市科尔沁区", + "Value": "150502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711949, + "Key": "内蒙古自治区通辽市科尔沁左翼中旗", + "Value": "150521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711950, + "Key": "内蒙古自治区通辽市科尔沁左翼后旗", + "Value": "150522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711951, + "Key": "内蒙古自治区通辽市开鲁县", + "Value": "150523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788711952, + "Key": "内蒙古自治区通辽市库伦旗", + "Value": "150524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716037, + "Key": "内蒙古自治区通辽市奈曼旗", + "Value": "150525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716038, + "Key": "内蒙古自治区通辽市扎鲁特旗", + "Value": "150526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716039, + "Key": "内蒙古自治区通辽市霍林郭勒市", + "Value": "150581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716040, + "Key": "内蒙古自治区鄂尔多斯市", + "Value": "150600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716041, + "Key": "内蒙古自治区鄂尔多斯市东胜区", + "Value": "150602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716042, + "Key": "内蒙古自治区鄂尔多斯市康巴什区", + "Value": "150603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716043, + "Key": "内蒙古自治区鄂尔多斯市达拉特旗", + "Value": "150621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716044, + "Key": "内蒙古自治区鄂尔多斯市准格尔旗", + "Value": "150622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716045, + "Key": "内蒙古自治区鄂尔多斯市鄂托克前旗", + "Value": "150623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716046, + "Key": "内蒙古自治区鄂尔多斯市鄂托克旗", + "Value": "150624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716047, + "Key": "内蒙古自治区鄂尔多斯市杭锦旗", + "Value": "150625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716048, + "Key": "内蒙古自治区鄂尔多斯市乌审旗", + "Value": "150626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788716049, + "Key": "内蒙古自治区鄂尔多斯市伊金霍洛旗", + "Value": "150627" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720133, + "Key": "内蒙古自治区呼伦贝尔市", + "Value": "150700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720134, + "Key": "内蒙古自治区呼伦贝尔市海拉尔区", + "Value": "150702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720135, + "Key": "内蒙古自治区呼伦贝尔市扎赉诺尔区", + "Value": "150703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720136, + "Key": "内蒙古自治区呼伦贝尔市阿荣旗", + "Value": "150721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720137, + "Key": "内蒙古自治区呼伦贝尔市莫力达瓦达斡尔族自治旗", + "Value": "150722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720138, + "Key": "内蒙古自治区呼伦贝尔市鄂伦春自治旗", + "Value": "150723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720139, + "Key": "内蒙古自治区呼伦贝尔市鄂温克族自治旗", + "Value": "150724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720140, + "Key": "内蒙古自治区呼伦贝尔市陈巴尔虎旗", + "Value": "150725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720141, + "Key": "内蒙古自治区呼伦贝尔市新巴尔虎左旗", + "Value": "150726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720142, + "Key": "内蒙古自治区呼伦贝尔市新巴尔虎右旗", + "Value": "150727" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720143, + "Key": "内蒙古自治区呼伦贝尔市满洲里市", + "Value": "150781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788720144, + "Key": "内蒙古自治区呼伦贝尔市牙克石市", + "Value": "150782" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724229, + "Key": "内蒙古自治区呼伦贝尔市扎兰屯市", + "Value": "150783" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724230, + "Key": "内蒙古自治区呼伦贝尔市额尔古纳市", + "Value": "150784" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724231, + "Key": "内蒙古自治区呼伦贝尔市根河市", + "Value": "150785" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724232, + "Key": "内蒙古自治区巴彦淖尔市", + "Value": "150800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724233, + "Key": "内蒙古自治区巴彦淖尔市临河区", + "Value": "150802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724234, + "Key": "内蒙古自治区巴彦淖尔市五原县", + "Value": "150821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724235, + "Key": "内蒙古自治区巴彦淖尔市磴口县", + "Value": "150822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724236, + "Key": "内蒙古自治区巴彦淖尔市乌拉特前旗", + "Value": "150823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724237, + "Key": "内蒙古自治区巴彦淖尔市乌拉特中旗", + "Value": "150824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724238, + "Key": "内蒙古自治区巴彦淖尔市乌拉特后旗", + "Value": "150825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724239, + "Key": "内蒙古自治区巴彦淖尔市杭锦后旗", + "Value": "150826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724240, + "Key": "内蒙古自治区乌兰察布市", + "Value": "150900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788724241, + "Key": "内蒙古自治区乌兰察布市集宁区", + "Value": "150902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728325, + "Key": "内蒙古自治区乌兰察布市卓资县", + "Value": "150921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728326, + "Key": "内蒙古自治区乌兰察布市化德县", + "Value": "150922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728327, + "Key": "内蒙古自治区乌兰察布市商都县", + "Value": "150923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728328, + "Key": "内蒙古自治区乌兰察布市兴和县", + "Value": "150924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728329, + "Key": "内蒙古自治区乌兰察布市凉城县", + "Value": "150925" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728330, + "Key": "内蒙古自治区乌兰察布市察哈尔右翼前旗", + "Value": "150926" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728331, + "Key": "内蒙古自治区乌兰察布市察哈尔右翼中旗", + "Value": "150927" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728332, + "Key": "内蒙古自治区乌兰察布市察哈尔右翼后旗", + "Value": "150928" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728333, + "Key": "内蒙古自治区乌兰察布市四子王旗", + "Value": "150929" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728334, + "Key": "内蒙古自治区乌兰察布市丰镇市", + "Value": "150981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728335, + "Key": "内蒙古自治区兴安盟", + "Value": "152200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788728336, + "Key": "内蒙古自治区兴安盟乌兰浩特市", + "Value": "152201" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732421, + "Key": "内蒙古自治区兴安盟阿尔山市", + "Value": "152202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732422, + "Key": "内蒙古自治区兴安盟科尔沁右翼前旗", + "Value": "152221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732423, + "Key": "内蒙古自治区兴安盟科尔沁右翼中旗", + "Value": "152222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732424, + "Key": "内蒙古自治区兴安盟扎赉特旗", + "Value": "152223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732425, + "Key": "内蒙古自治区兴安盟突泉县", + "Value": "152224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732426, + "Key": "内蒙古自治区锡林郭勒盟", + "Value": "152500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732427, + "Key": "内蒙古自治区锡林郭勒盟二连浩特市", + "Value": "152501" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732428, + "Key": "内蒙古自治区锡林郭勒盟锡林浩特市", + "Value": "152502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732429, + "Key": "内蒙古自治区锡林郭勒盟阿巴嘎旗", + "Value": "152522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732430, + "Key": "内蒙古自治区锡林郭勒盟苏尼特左旗", + "Value": "152523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732431, + "Key": "内蒙古自治区锡林郭勒盟苏尼特右旗", + "Value": "152524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732432, + "Key": "内蒙古自治区锡林郭勒盟东乌珠穆沁旗", + "Value": "152525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788732433, + "Key": "内蒙古自治区锡林郭勒盟西乌珠穆沁旗", + "Value": "152526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788736517, + "Key": "内蒙古自治区锡林郭勒盟太仆寺旗", + "Value": "152527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788736518, + "Key": "内蒙古自治区锡林郭勒盟镶黄旗", + "Value": "152528" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788736519, + "Key": "内蒙古自治区锡林郭勒盟正镶白旗", + "Value": "152529" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788736520, + "Key": "内蒙古自治区锡林郭勒盟正蓝旗", + "Value": "152530" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788736521, + "Key": "内蒙古自治区锡林郭勒盟多伦县", + "Value": "152531" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788736522, + "Key": "内蒙古自治区阿拉善盟", + "Value": "152900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788736523, + "Key": "内蒙古自治区阿拉善盟阿拉善左旗", + "Value": "152921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788740613, + "Key": "内蒙古自治区阿拉善盟阿拉善右旗", + "Value": "152922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788744709, + "Key": "内蒙古自治区阿拉善盟额济纳旗", + "Value": "152923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788744710, + "Key": "辽宁省", + "Value": "210000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788748805, + "Key": "辽宁省沈阳市", + "Value": "210100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788748806, + "Key": "辽宁省沈阳市和平区", + "Value": "210102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788748807, + "Key": "辽宁省沈阳市沈河区", + "Value": "210103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788752901, + "Key": "辽宁省沈阳市大东区", + "Value": "210104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788752902, + "Key": "辽宁省沈阳市皇姑区", + "Value": "210105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788756997, + "Key": "辽宁省沈阳市铁西区", + "Value": "210106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788756998, + "Key": "辽宁省沈阳市苏家屯区", + "Value": "210111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788761093, + "Key": "辽宁省沈阳市浑南区", + "Value": "210112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788765189, + "Key": "辽宁省沈阳市沈北新区", + "Value": "210113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788765190, + "Key": "辽宁省沈阳市于洪区", + "Value": "210114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788765191, + "Key": "辽宁省沈阳市辽中区", + "Value": "210115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788765192, + "Key": "辽宁省沈阳市康平县", + "Value": "210123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788769285, + "Key": "辽宁省沈阳市法库县", + "Value": "210124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788769286, + "Key": "辽宁省沈阳市新民市", + "Value": "210181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788769287, + "Key": "辽宁省大连市", + "Value": "210200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788769288, + "Key": "辽宁省大连市中山区", + "Value": "210202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788769289, + "Key": "辽宁省大连市西岗区", + "Value": "210203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788773381, + "Key": "辽宁省大连市沙河口区", + "Value": "210204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788773382, + "Key": "辽宁省大连市甘井子区", + "Value": "210211" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788773383, + "Key": "辽宁省大连市旅顺口区", + "Value": "210212" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788773384, + "Key": "辽宁省大连市金州区", + "Value": "210213" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788777477, + "Key": "辽宁省大连市普兰店区", + "Value": "210214" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788777478, + "Key": "辽宁省大连市长海县", + "Value": "210224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788777479, + "Key": "辽宁省大连市瓦房店市", + "Value": "210281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788777480, + "Key": "辽宁省大连市庄河市", + "Value": "210283" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788777481, + "Key": "辽宁省鞍山市", + "Value": "210300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788777482, + "Key": "辽宁省鞍山市铁东区", + "Value": "210302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788777483, + "Key": "辽宁省鞍山市铁西区", + "Value": "210303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788777484, + "Key": "辽宁省鞍山市立山区", + "Value": "210304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788777485, + "Key": "辽宁省鞍山市千山区", + "Value": "210311" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788777486, + "Key": "辽宁省鞍山市台安县", + "Value": "210321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788781573, + "Key": "辽宁省鞍山市岫岩满族自治县", + "Value": "210323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788781574, + "Key": "辽宁省鞍山市海城市", + "Value": "210381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788781575, + "Key": "辽宁省抚顺市", + "Value": "210400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788781576, + "Key": "辽宁省抚顺市新抚区", + "Value": "210402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788781577, + "Key": "辽宁省抚顺市东洲区", + "Value": "210403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788781578, + "Key": "辽宁省抚顺市望花区", + "Value": "210404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788781579, + "Key": "辽宁省抚顺市顺城区", + "Value": "210411" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788781580, + "Key": "辽宁省抚顺市抚顺县", + "Value": "210421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788781581, + "Key": "辽宁省抚顺市新宾满族自治县", + "Value": "210422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788785669, + "Key": "辽宁省抚顺市清原满族自治县", + "Value": "210423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788785670, + "Key": "辽宁省本溪市", + "Value": "210500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788785671, + "Key": "辽宁省本溪市平山区", + "Value": "210502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788785672, + "Key": "辽宁省本溪市溪湖区", + "Value": "210503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788785673, + "Key": "辽宁省本溪市明山区", + "Value": "210504" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788785674, + "Key": "辽宁省本溪市南芬区", + "Value": "210505" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788785675, + "Key": "辽宁省本溪市本溪满族自治县", + "Value": "210521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788785676, + "Key": "辽宁省本溪市桓仁满族自治县", + "Value": "210522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788789765, + "Key": "辽宁省丹东市", + "Value": "210600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788789766, + "Key": "辽宁省丹东市元宝区", + "Value": "210602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788789767, + "Key": "辽宁省丹东市振兴区", + "Value": "210603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788789768, + "Key": "辽宁省丹东市振安区", + "Value": "210604" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788789769, + "Key": "辽宁省丹东市宽甸满族自治县", + "Value": "210624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788789770, + "Key": "辽宁省丹东市东港市", + "Value": "210681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788789771, + "Key": "辽宁省丹东市凤城市", + "Value": "210682" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788789772, + "Key": "辽宁省锦州市", + "Value": "210700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788789773, + "Key": "辽宁省锦州市古塔区", + "Value": "210702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788789774, + "Key": "辽宁省锦州市凌河区", + "Value": "210703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793861, + "Key": "辽宁省锦州市太和区", + "Value": "210711" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793862, + "Key": "辽宁省锦州市黑山县", + "Value": "210726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793863, + "Key": "辽宁省锦州市义县", + "Value": "210727" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793864, + "Key": "辽宁省锦州市凌海市", + "Value": "210781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793865, + "Key": "辽宁省锦州市北镇市", + "Value": "210782" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793866, + "Key": "辽宁省营口市", + "Value": "210800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793867, + "Key": "辽宁省营口市站前区", + "Value": "210802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793868, + "Key": "辽宁省营口市西市区", + "Value": "210803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793869, + "Key": "辽宁省营口市鲅鱼圈区", + "Value": "210804" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793870, + "Key": "辽宁省营口市老边区", + "Value": "210811" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793871, + "Key": "辽宁省营口市盖州市", + "Value": "210881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788793872, + "Key": "辽宁省营口市大石桥市", + "Value": "210882" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797957, + "Key": "辽宁省阜新市", + "Value": "210900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797958, + "Key": "辽宁省阜新市海州区", + "Value": "210902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797959, + "Key": "辽宁省阜新市新邱区", + "Value": "210903" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797960, + "Key": "辽宁省阜新市太平区", + "Value": "210904" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797961, + "Key": "辽宁省阜新市清河门区", + "Value": "210905" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797962, + "Key": "辽宁省阜新市细河区", + "Value": "210911" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797963, + "Key": "辽宁省阜新市阜新蒙古族自治县", + "Value": "210921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797964, + "Key": "辽宁省阜新市彰武县", + "Value": "210922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797965, + "Key": "辽宁省辽阳市", + "Value": "211000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797966, + "Key": "辽宁省辽阳市白塔区", + "Value": "211002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797967, + "Key": "辽宁省辽阳市文圣区", + "Value": "211003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797968, + "Key": "辽宁省辽阳市宏伟区", + "Value": "211004" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788797969, + "Key": "辽宁省辽阳市弓长岭区", + "Value": "211005" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802053, + "Key": "辽宁省辽阳市太子河区", + "Value": "211011" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802054, + "Key": "辽宁省辽阳市辽阳县", + "Value": "211021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802055, + "Key": "辽宁省辽阳市灯塔市", + "Value": "211081" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802056, + "Key": "辽宁省盘锦市", + "Value": "211100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802057, + "Key": "辽宁省盘锦市双台子区", + "Value": "211102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802058, + "Key": "辽宁省盘锦市兴隆台区", + "Value": "211103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802059, + "Key": "辽宁省盘锦市大洼区", + "Value": "211104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802060, + "Key": "辽宁省盘锦市盘山县", + "Value": "211122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802061, + "Key": "辽宁省铁岭市", + "Value": "211200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802062, + "Key": "辽宁省铁岭市银州区", + "Value": "211202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802063, + "Key": "辽宁省铁岭市清河区", + "Value": "211204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788802064, + "Key": "辽宁省铁岭市铁岭县", + "Value": "211221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806149, + "Key": "辽宁省铁岭市西丰县", + "Value": "211223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806150, + "Key": "辽宁省铁岭市昌图县", + "Value": "211224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806151, + "Key": "辽宁省铁岭市调兵山市", + "Value": "211281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806152, + "Key": "辽宁省铁岭市开原市", + "Value": "211282" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806153, + "Key": "辽宁省朝阳市", + "Value": "211300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806154, + "Key": "辽宁省朝阳市双塔区", + "Value": "211302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806155, + "Key": "辽宁省朝阳市龙城区", + "Value": "211303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806156, + "Key": "辽宁省朝阳市朝阳县", + "Value": "211321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806157, + "Key": "辽宁省朝阳市建平县", + "Value": "211322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806158, + "Key": "辽宁省朝阳市喀喇沁左翼蒙古族自治县", + "Value": "211324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806159, + "Key": "辽宁省朝阳市北票市", + "Value": "211381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788806160, + "Key": "辽宁省朝阳市凌源市", + "Value": "211382" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810245, + "Key": "辽宁省葫芦岛市", + "Value": "211400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810246, + "Key": "辽宁省葫芦岛市连山区", + "Value": "211402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810247, + "Key": "辽宁省葫芦岛市龙港区", + "Value": "211403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810248, + "Key": "辽宁省葫芦岛市南票区", + "Value": "211404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810249, + "Key": "辽宁省葫芦岛市绥中县", + "Value": "211421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810250, + "Key": "辽宁省葫芦岛市建昌县", + "Value": "211422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810251, + "Key": "辽宁省葫芦岛市兴城市", + "Value": "211481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810252, + "Key": "吉林省", + "Value": "220000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810253, + "Key": "吉林省长春市", + "Value": "220100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810254, + "Key": "吉林省长春市南关区", + "Value": "220102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810255, + "Key": "吉林省长春市宽城区", + "Value": "220103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810256, + "Key": "吉林省长春市朝阳区", + "Value": "220104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788810257, + "Key": "吉林省长春市二道区", + "Value": "220105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814341, + "Key": "吉林省长春市绿园区", + "Value": "220106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814342, + "Key": "吉林省长春市双阳区", + "Value": "220112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814343, + "Key": "吉林省长春市九台区", + "Value": "220113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814344, + "Key": "吉林省长春市农安县", + "Value": "220122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814345, + "Key": "吉林省长春市榆树市", + "Value": "220182" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814346, + "Key": "吉林省长春市德惠市", + "Value": "220183" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814347, + "Key": "吉林省长春市公主岭市", + "Value": "220184" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814348, + "Key": "吉林省吉林市", + "Value": "220200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814349, + "Key": "吉林省吉林市昌邑区", + "Value": "220202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814350, + "Key": "吉林省吉林市龙潭区", + "Value": "220203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814351, + "Key": "吉林省吉林市船营区", + "Value": "220204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788814352, + "Key": "吉林省吉林市丰满区", + "Value": "220211" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818437, + "Key": "吉林省吉林市永吉县", + "Value": "220221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818438, + "Key": "吉林省吉林市蛟河市", + "Value": "220281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818439, + "Key": "吉林省吉林市桦甸市", + "Value": "220282" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818440, + "Key": "吉林省吉林市舒兰市", + "Value": "220283" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818441, + "Key": "吉林省吉林市磐石市", + "Value": "220284" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818442, + "Key": "吉林省四平市", + "Value": "220300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818443, + "Key": "吉林省四平市铁西区", + "Value": "220302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818444, + "Key": "吉林省四平市铁东区", + "Value": "220303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818445, + "Key": "吉林省四平市梨树县", + "Value": "220322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818446, + "Key": "吉林省四平市伊通满族自治县", + "Value": "220323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818447, + "Key": "吉林省四平市双辽市", + "Value": "220382" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818448, + "Key": "吉林省辽源市", + "Value": "220400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788818449, + "Key": "吉林省辽源市龙山区", + "Value": "220402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822533, + "Key": "吉林省辽源市西安区", + "Value": "220403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822534, + "Key": "吉林省辽源市东丰县", + "Value": "220421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822535, + "Key": "吉林省辽源市东辽县", + "Value": "220422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822536, + "Key": "吉林省通化市", + "Value": "220500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822537, + "Key": "吉林省通化市东昌区", + "Value": "220502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822538, + "Key": "吉林省通化市二道江区", + "Value": "220503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822539, + "Key": "吉林省通化市通化县", + "Value": "220521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822540, + "Key": "吉林省通化市辉南县", + "Value": "220523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822541, + "Key": "吉林省通化市柳河县", + "Value": "220524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822542, + "Key": "吉林省通化市梅河口市", + "Value": "220581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822543, + "Key": "吉林省通化市集安市", + "Value": "220582" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788822544, + "Key": "吉林省白山市", + "Value": "220600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826629, + "Key": "吉林省白山市浑江区", + "Value": "220602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826630, + "Key": "吉林省白山市江源区", + "Value": "220605" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826631, + "Key": "吉林省白山市抚松县", + "Value": "220621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826632, + "Key": "吉林省白山市靖宇县", + "Value": "220622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826633, + "Key": "吉林省白山市长白朝鲜族自治县", + "Value": "220623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826634, + "Key": "吉林省白山市临江市", + "Value": "220681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826635, + "Key": "吉林省松原市", + "Value": "220700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826636, + "Key": "吉林省松原市宁江区", + "Value": "220702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826637, + "Key": "吉林省松原市前郭尔罗斯蒙古族自治县", + "Value": "220721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826638, + "Key": "吉林省松原市长岭县", + "Value": "220722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826639, + "Key": "吉林省松原市乾安县", + "Value": "220723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826640, + "Key": "吉林省松原市扶余市", + "Value": "220781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788826641, + "Key": "吉林省白城市", + "Value": "220800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830725, + "Key": "吉林省白城市洮北区", + "Value": "220802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830726, + "Key": "吉林省白城市镇赉县", + "Value": "220821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830727, + "Key": "吉林省白城市通榆县", + "Value": "220822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830728, + "Key": "吉林省白城市洮南市", + "Value": "220881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830729, + "Key": "吉林省白城市大安市", + "Value": "220882" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830730, + "Key": "吉林省延边朝鲜族自治州", + "Value": "222400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830731, + "Key": "吉林省延边朝鲜族自治州延吉市", + "Value": "222401" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830732, + "Key": "吉林省延边朝鲜族自治州图们市", + "Value": "222402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830733, + "Key": "吉林省延边朝鲜族自治州敦化市", + "Value": "222403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830734, + "Key": "吉林省延边朝鲜族自治州珲春市", + "Value": "222404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830735, + "Key": "吉林省延边朝鲜族自治州龙井市", + "Value": "222405" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830736, + "Key": "吉林省延边朝鲜族自治州和龙市", + "Value": "222406" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788830737, + "Key": "吉林省延边朝鲜族自治州汪清县", + "Value": "222424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834821, + "Key": "吉林省延边朝鲜族自治州安图县", + "Value": "222426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834822, + "Key": "黑龙江省", + "Value": "230000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834823, + "Key": "黑龙江省哈尔滨市", + "Value": "230100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834824, + "Key": "黑龙江省哈尔滨市道里区", + "Value": "230102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834825, + "Key": "黑龙江省哈尔滨市南岗区", + "Value": "230103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834826, + "Key": "黑龙江省哈尔滨市道外区", + "Value": "230104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834827, + "Key": "黑龙江省哈尔滨市平房区", + "Value": "230108" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834828, + "Key": "黑龙江省哈尔滨市松北区", + "Value": "230109" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834829, + "Key": "黑龙江省哈尔滨市香坊区", + "Value": "230110" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834830, + "Key": "黑龙江省哈尔滨市呼兰区", + "Value": "230111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834831, + "Key": "黑龙江省哈尔滨市阿城区", + "Value": "230112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788834832, + "Key": "黑龙江省哈尔滨市双城区", + "Value": "230113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838917, + "Key": "黑龙江省哈尔滨市依兰县", + "Value": "230123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838918, + "Key": "黑龙江省哈尔滨市方正县", + "Value": "230124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838919, + "Key": "黑龙江省哈尔滨市宾县", + "Value": "230125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838920, + "Key": "黑龙江省哈尔滨市巴彦县", + "Value": "230126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838921, + "Key": "黑龙江省哈尔滨市木兰县", + "Value": "230127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838922, + "Key": "黑龙江省哈尔滨市通河县", + "Value": "230128" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838923, + "Key": "黑龙江省哈尔滨市延寿县", + "Value": "230129" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838924, + "Key": "黑龙江省哈尔滨市尚志市", + "Value": "230183" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838925, + "Key": "黑龙江省哈尔滨市五常市", + "Value": "230184" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838926, + "Key": "黑龙江省齐齐哈尔市", + "Value": "230200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838927, + "Key": "黑龙江省齐齐哈尔市龙沙区", + "Value": "230202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788838928, + "Key": "黑龙江省齐齐哈尔市建华区", + "Value": "230203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843013, + "Key": "黑龙江省齐齐哈尔市铁锋区", + "Value": "230204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843014, + "Key": "黑龙江省齐齐哈尔市昂昂溪区", + "Value": "230205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843015, + "Key": "黑龙江省齐齐哈尔市富拉尔基区", + "Value": "230206" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843016, + "Key": "黑龙江省齐齐哈尔市碾子山区", + "Value": "230207" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843017, + "Key": "黑龙江省齐齐哈尔市梅里斯达斡尔族区", + "Value": "230208" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843018, + "Key": "黑龙江省齐齐哈尔市龙江县", + "Value": "230221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843019, + "Key": "黑龙江省齐齐哈尔市依安县", + "Value": "230223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843020, + "Key": "黑龙江省齐齐哈尔市泰来县", + "Value": "230224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843021, + "Key": "黑龙江省齐齐哈尔市甘南县", + "Value": "230225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843022, + "Key": "黑龙江省齐齐哈尔市富裕县", + "Value": "230227" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843023, + "Key": "黑龙江省齐齐哈尔市克山县", + "Value": "230229" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843024, + "Key": "黑龙江省齐齐哈尔市克东县", + "Value": "230230" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788843025, + "Key": "黑龙江省齐齐哈尔市拜泉县", + "Value": "230231" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847109, + "Key": "黑龙江省齐齐哈尔市讷河市", + "Value": "230281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847110, + "Key": "黑龙江省鸡西市", + "Value": "230300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847111, + "Key": "黑龙江省鸡西市鸡冠区", + "Value": "230302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847112, + "Key": "黑龙江省鸡西市恒山区", + "Value": "230303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847113, + "Key": "黑龙江省鸡西市滴道区", + "Value": "230304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847114, + "Key": "黑龙江省鸡西市梨树区", + "Value": "230305" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847115, + "Key": "黑龙江省鸡西市城子河区", + "Value": "230306" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847116, + "Key": "黑龙江省鸡西市麻山区", + "Value": "230307" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847117, + "Key": "黑龙江省鸡西市鸡东县", + "Value": "230321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847118, + "Key": "黑龙江省鸡西市虎林市", + "Value": "230381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847119, + "Key": "黑龙江省鸡西市密山市", + "Value": "230382" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847120, + "Key": "黑龙江省鹤岗市", + "Value": "230400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788847121, + "Key": "黑龙江省鹤岗市向阳区", + "Value": "230402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851205, + "Key": "黑龙江省鹤岗市工农区", + "Value": "230403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851206, + "Key": "黑龙江省鹤岗市南山区", + "Value": "230404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851207, + "Key": "黑龙江省鹤岗市兴安区", + "Value": "230405" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851208, + "Key": "黑龙江省鹤岗市东山区", + "Value": "230406" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851209, + "Key": "黑龙江省鹤岗市兴山区", + "Value": "230407" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851210, + "Key": "黑龙江省鹤岗市萝北县", + "Value": "230421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851211, + "Key": "黑龙江省鹤岗市绥滨县", + "Value": "230422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851212, + "Key": "黑龙江省双鸭山市", + "Value": "230500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851213, + "Key": "黑龙江省双鸭山市尖山区", + "Value": "230502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851214, + "Key": "黑龙江省双鸭山市岭东区", + "Value": "230503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851215, + "Key": "黑龙江省双鸭山市四方台区", + "Value": "230505" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788851216, + "Key": "黑龙江省双鸭山市宝山区", + "Value": "230506" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855301, + "Key": "黑龙江省双鸭山市集贤县", + "Value": "230521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855302, + "Key": "黑龙江省双鸭山市友谊县", + "Value": "230522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855303, + "Key": "黑龙江省双鸭山市宝清县", + "Value": "230523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855304, + "Key": "黑龙江省双鸭山市饶河县", + "Value": "230524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855305, + "Key": "黑龙江省大庆市", + "Value": "230600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855306, + "Key": "黑龙江省大庆市萨尔图区", + "Value": "230602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855307, + "Key": "黑龙江省大庆市龙凤区", + "Value": "230603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855308, + "Key": "黑龙江省大庆市让胡路区", + "Value": "230604" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855309, + "Key": "黑龙江省大庆市红岗区", + "Value": "230605" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855310, + "Key": "黑龙江省大庆市大同区", + "Value": "230606" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855311, + "Key": "黑龙江省大庆市肇州县", + "Value": "230621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855312, + "Key": "黑龙江省大庆市肇源县", + "Value": "230622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788855313, + "Key": "黑龙江省大庆市林甸县", + "Value": "230623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859397, + "Key": "黑龙江省大庆市杜尔伯特蒙古族自治县", + "Value": "230624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859398, + "Key": "黑龙江省伊春市", + "Value": "230700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859399, + "Key": "黑龙江省伊春市伊美区", + "Value": "230717" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859400, + "Key": "黑龙江省伊春市乌翠区", + "Value": "230718" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859401, + "Key": "黑龙江省伊春市友好区", + "Value": "230719" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859402, + "Key": "黑龙江省伊春市嘉荫县", + "Value": "230722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859403, + "Key": "黑龙江省伊春市汤旺县", + "Value": "230723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859404, + "Key": "黑龙江省伊春市丰林县", + "Value": "230724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859405, + "Key": "黑龙江省伊春市大箐山县", + "Value": "230725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859406, + "Key": "黑龙江省伊春市南岔县", + "Value": "230726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859407, + "Key": "黑龙江省伊春市金林区", + "Value": "230751" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859408, + "Key": "黑龙江省伊春市铁力市", + "Value": "230781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788859409, + "Key": "黑龙江省佳木斯市", + "Value": "230800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863493, + "Key": "黑龙江省佳木斯市向阳区", + "Value": "230803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863494, + "Key": "黑龙江省佳木斯市前进区", + "Value": "230804" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863495, + "Key": "黑龙江省佳木斯市东风区", + "Value": "230805" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863496, + "Key": "黑龙江省佳木斯市郊区", + "Value": "230811" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863497, + "Key": "黑龙江省佳木斯市桦南县", + "Value": "230822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863498, + "Key": "黑龙江省佳木斯市桦川县", + "Value": "230826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863499, + "Key": "黑龙江省佳木斯市汤原县", + "Value": "230828" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863500, + "Key": "黑龙江省佳木斯市同江市", + "Value": "230881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863501, + "Key": "黑龙江省佳木斯市富锦市", + "Value": "230882" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863502, + "Key": "黑龙江省佳木斯市抚远市", + "Value": "230883" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863503, + "Key": "黑龙江省七台河市", + "Value": "230900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788863504, + "Key": "黑龙江省七台河市新兴区", + "Value": "230902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867589, + "Key": "黑龙江省七台河市桃山区", + "Value": "230903" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867590, + "Key": "黑龙江省七台河市茄子河区", + "Value": "230904" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867591, + "Key": "黑龙江省七台河市勃利县", + "Value": "230921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867592, + "Key": "黑龙江省牡丹江市", + "Value": "231000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867593, + "Key": "黑龙江省牡丹江市东安区", + "Value": "231002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867594, + "Key": "黑龙江省牡丹江市阳明区", + "Value": "231003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867595, + "Key": "黑龙江省牡丹江市爱民区", + "Value": "231004" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867596, + "Key": "黑龙江省牡丹江市西安区", + "Value": "231005" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867597, + "Key": "黑龙江省牡丹江市林口县", + "Value": "231025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867598, + "Key": "黑龙江省牡丹江市绥芬河市", + "Value": "231081" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867599, + "Key": "黑龙江省牡丹江市海林市", + "Value": "231083" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788867600, + "Key": "黑龙江省牡丹江市宁安市", + "Value": "231084" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871685, + "Key": "黑龙江省牡丹江市穆棱市", + "Value": "231085" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871686, + "Key": "黑龙江省牡丹江市东宁市", + "Value": "231086" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871687, + "Key": "黑龙江省黑河市", + "Value": "231100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871688, + "Key": "黑龙江省黑河市爱辉区", + "Value": "231102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871689, + "Key": "黑龙江省黑河市逊克县", + "Value": "231123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871690, + "Key": "黑龙江省黑河市孙吴县", + "Value": "231124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871691, + "Key": "黑龙江省黑河市北安市", + "Value": "231181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871692, + "Key": "黑龙江省黑河市五大连池市", + "Value": "231182" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871693, + "Key": "黑龙江省黑河市嫩江市", + "Value": "231183" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871694, + "Key": "黑龙江省绥化市", + "Value": "231200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871695, + "Key": "黑龙江省绥化市北林区", + "Value": "231202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871696, + "Key": "黑龙江省绥化市望奎县", + "Value": "231221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788871697, + "Key": "黑龙江省绥化市兰西县", + "Value": "231222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875781, + "Key": "黑龙江省绥化市青冈县", + "Value": "231223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875782, + "Key": "黑龙江省绥化市庆安县", + "Value": "231224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875783, + "Key": "黑龙江省绥化市明水县", + "Value": "231225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875784, + "Key": "黑龙江省绥化市绥棱县", + "Value": "231226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875785, + "Key": "黑龙江省绥化市安达市", + "Value": "231281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875786, + "Key": "黑龙江省绥化市肇东市", + "Value": "231282" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875787, + "Key": "黑龙江省绥化市海伦市", + "Value": "231283" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875788, + "Key": "黑龙江省大兴安岭地区", + "Value": "232700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875789, + "Key": "黑龙江省大兴安岭地区漠河市", + "Value": "232701" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875790, + "Key": "黑龙江省大兴安岭地区呼玛县", + "Value": "232721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875791, + "Key": "黑龙江省大兴安岭地区塔河县", + "Value": "232722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788875792, + "Key": "上海市", + "Value": "310000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879877, + "Key": "上海市黄浦区", + "Value": "310101" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879878, + "Key": "上海市徐汇区", + "Value": "310104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879879, + "Key": "上海市长宁区", + "Value": "310105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879880, + "Key": "上海市静安区", + "Value": "310106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879881, + "Key": "上海市普陀区", + "Value": "310107" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879882, + "Key": "上海市虹口区", + "Value": "310109" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879883, + "Key": "上海市杨浦区", + "Value": "310110" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879884, + "Key": "上海市闵行区", + "Value": "310112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879885, + "Key": "上海市宝山区", + "Value": "310113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879886, + "Key": "上海市嘉定区", + "Value": "310114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879887, + "Key": "上海市浦东新区", + "Value": "310115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879888, + "Key": "上海市金山区", + "Value": "310116" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788879889, + "Key": "上海市松江区", + "Value": "310117" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883973, + "Key": "上海市青浦区", + "Value": "310118" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883974, + "Key": "上海市奉贤区", + "Value": "310120" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883975, + "Key": "上海市崇明区", + "Value": "310151" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883976, + "Key": "江苏省", + "Value": "320000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883977, + "Key": "江苏省南京市", + "Value": "320100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883978, + "Key": "江苏省南京市玄武区", + "Value": "320102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883979, + "Key": "江苏省南京市秦淮区", + "Value": "320104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883980, + "Key": "江苏省南京市建邺区", + "Value": "320105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883981, + "Key": "江苏省南京市鼓楼区", + "Value": "320106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883982, + "Key": "江苏省南京市浦口区", + "Value": "320111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883983, + "Key": "江苏省南京市栖霞区", + "Value": "320113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788883984, + "Key": "江苏省南京市雨花台区", + "Value": "320114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888069, + "Key": "江苏省南京市江宁区", + "Value": "320115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888070, + "Key": "江苏省南京市六合区", + "Value": "320116" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888071, + "Key": "江苏省南京市溧水区", + "Value": "320117" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888072, + "Key": "江苏省南京市高淳区", + "Value": "320118" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888073, + "Key": "江苏省无锡市", + "Value": "320200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888074, + "Key": "江苏省无锡市锡山区", + "Value": "320205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888075, + "Key": "江苏省无锡市惠山区", + "Value": "320206" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888076, + "Key": "江苏省无锡市滨湖区", + "Value": "320211" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888077, + "Key": "江苏省无锡市梁溪区", + "Value": "320213" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888078, + "Key": "江苏省无锡市新吴区", + "Value": "320214" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888079, + "Key": "江苏省无锡市江阴市", + "Value": "320281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788888080, + "Key": "江苏省无锡市宜兴市", + "Value": "320282" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892165, + "Key": "江苏省徐州市", + "Value": "320300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892166, + "Key": "江苏省徐州市鼓楼区", + "Value": "320302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892167, + "Key": "江苏省徐州市云龙区", + "Value": "320303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892168, + "Key": "江苏省徐州市贾汪区", + "Value": "320305" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892169, + "Key": "江苏省徐州市泉山区", + "Value": "320311" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892170, + "Key": "江苏省徐州市铜山区", + "Value": "320312" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892171, + "Key": "江苏省徐州市丰县", + "Value": "320321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892172, + "Key": "江苏省徐州市沛县", + "Value": "320322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892173, + "Key": "江苏省徐州市睢宁县", + "Value": "320324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892174, + "Key": "江苏省徐州市新沂市", + "Value": "320381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892175, + "Key": "江苏省徐州市邳州市", + "Value": "320382" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788892176, + "Key": "江苏省常州市", + "Value": "320400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896261, + "Key": "江苏省常州市天宁区", + "Value": "320402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896262, + "Key": "江苏省常州市钟楼区", + "Value": "320404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896263, + "Key": "江苏省常州市新北区", + "Value": "320411" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896264, + "Key": "江苏省常州市武进区", + "Value": "320412" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896265, + "Key": "江苏省常州市金坛区", + "Value": "320413" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896266, + "Key": "江苏省常州市溧阳市", + "Value": "320481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896267, + "Key": "江苏省苏州市", + "Value": "320500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896268, + "Key": "江苏省苏州市虎丘区", + "Value": "320505" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896269, + "Key": "江苏省苏州市吴中区", + "Value": "320506" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896270, + "Key": "江苏省苏州市相城区", + "Value": "320507" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896271, + "Key": "江苏省苏州市姑苏区", + "Value": "320508" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896272, + "Key": "江苏省苏州市吴江区", + "Value": "320509" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788896273, + "Key": "江苏省苏州市常熟市", + "Value": "320581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900357, + "Key": "江苏省苏州市张家港市", + "Value": "320582" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900358, + "Key": "江苏省苏州市昆山市", + "Value": "320583" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900359, + "Key": "江苏省苏州市太仓市", + "Value": "320585" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900360, + "Key": "江苏省南通市", + "Value": "320600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900361, + "Key": "江苏省南通市通州区", + "Value": "320612" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900362, + "Key": "江苏省南通市崇川区", + "Value": "320613" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900363, + "Key": "江苏省南通市海门区", + "Value": "320614" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900364, + "Key": "江苏省南通市如东县", + "Value": "320623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900365, + "Key": "江苏省南通市启东市", + "Value": "320681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900366, + "Key": "江苏省南通市如皋市", + "Value": "320682" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900367, + "Key": "江苏省南通市海安市", + "Value": "320685" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788900368, + "Key": "江苏省连云港市", + "Value": "320700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904453, + "Key": "江苏省连云港市连云区", + "Value": "320703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904454, + "Key": "江苏省连云港市海州区", + "Value": "320706" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904455, + "Key": "江苏省连云港市赣榆区", + "Value": "320707" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904456, + "Key": "江苏省连云港市东海县", + "Value": "320722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904457, + "Key": "江苏省连云港市灌云县", + "Value": "320723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904458, + "Key": "江苏省连云港市灌南县", + "Value": "320724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904459, + "Key": "江苏省淮安市", + "Value": "320800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904460, + "Key": "江苏省淮安市淮安区", + "Value": "320803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904461, + "Key": "江苏省淮安市淮阴区", + "Value": "320804" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904462, + "Key": "江苏省淮安市清江浦区", + "Value": "320812" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904463, + "Key": "江苏省淮安市洪泽区", + "Value": "320813" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788904464, + "Key": "江苏省淮安市涟水县", + "Value": "320826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908549, + "Key": "江苏省淮安市盱眙县", + "Value": "320830" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908550, + "Key": "江苏省淮安市金湖县", + "Value": "320831" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908551, + "Key": "江苏省盐城市", + "Value": "320900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908552, + "Key": "江苏省盐城市亭湖区", + "Value": "320902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908553, + "Key": "江苏省盐城市盐都区", + "Value": "320903" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908554, + "Key": "江苏省盐城市大丰区", + "Value": "320904" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908555, + "Key": "江苏省盐城市响水县", + "Value": "320921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908556, + "Key": "江苏省盐城市滨海县", + "Value": "320922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908557, + "Key": "江苏省盐城市阜宁县", + "Value": "320923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908558, + "Key": "江苏省盐城市射阳县", + "Value": "320924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908559, + "Key": "江苏省盐城市建湖县", + "Value": "320925" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788908560, + "Key": "江苏省盐城市东台市", + "Value": "320981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912645, + "Key": "江苏省扬州市", + "Value": "321000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912646, + "Key": "江苏省扬州市广陵区", + "Value": "321002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912647, + "Key": "江苏省扬州市邗江区", + "Value": "321003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912648, + "Key": "江苏省扬州市江都区", + "Value": "321012" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912649, + "Key": "江苏省扬州市宝应县", + "Value": "321023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912650, + "Key": "江苏省扬州市仪征市", + "Value": "321081" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912651, + "Key": "江苏省扬州市高邮市", + "Value": "321084" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912652, + "Key": "江苏省镇江市", + "Value": "321100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912653, + "Key": "江苏省镇江市京口区", + "Value": "321102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912654, + "Key": "江苏省镇江市润州区", + "Value": "321111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912655, + "Key": "江苏省镇江市丹徒区", + "Value": "321112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788912656, + "Key": "江苏省镇江市丹阳市", + "Value": "321181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916741, + "Key": "江苏省镇江市扬中市", + "Value": "321182" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916742, + "Key": "江苏省镇江市句容市", + "Value": "321183" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916743, + "Key": "江苏省泰州市", + "Value": "321200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916744, + "Key": "江苏省泰州市海陵区", + "Value": "321202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916745, + "Key": "江苏省泰州市高港区", + "Value": "321203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916746, + "Key": "江苏省泰州市姜堰区", + "Value": "321204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916747, + "Key": "江苏省泰州市兴化市", + "Value": "321281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916748, + "Key": "江苏省泰州市靖江市", + "Value": "321282" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916749, + "Key": "江苏省泰州市泰兴市", + "Value": "321283" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916750, + "Key": "江苏省宿迁市", + "Value": "321300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916751, + "Key": "江苏省宿迁市宿城区", + "Value": "321302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916752, + "Key": "江苏省宿迁市宿豫区", + "Value": "321311" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788916753, + "Key": "江苏省宿迁市沭阳县", + "Value": "321322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920837, + "Key": "江苏省宿迁市泗阳县", + "Value": "321323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920838, + "Key": "江苏省宿迁市泗洪县", + "Value": "321324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920839, + "Key": "浙江省", + "Value": "330000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920840, + "Key": "浙江省杭州市", + "Value": "330100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920841, + "Key": "浙江省杭州市上城区", + "Value": "330102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920842, + "Key": "浙江省杭州市拱墅区", + "Value": "330105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920843, + "Key": "浙江省杭州市西湖区", + "Value": "330106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920844, + "Key": "浙江省杭州市滨江区", + "Value": "330108" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920845, + "Key": "浙江省杭州市萧山区", + "Value": "330109" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920846, + "Key": "浙江省杭州市余杭区", + "Value": "330110" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920847, + "Key": "浙江省杭州市富阳区", + "Value": "330111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788920848, + "Key": "浙江省杭州市临安区", + "Value": "330112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924933, + "Key": "浙江省杭州市临平区", + "Value": "330113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924934, + "Key": "浙江省杭州市钱塘区", + "Value": "330114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924935, + "Key": "浙江省杭州市桐庐县", + "Value": "330122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924936, + "Key": "浙江省杭州市淳安县", + "Value": "330127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924937, + "Key": "浙江省杭州市建德市", + "Value": "330182" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924938, + "Key": "浙江省宁波市", + "Value": "330200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924939, + "Key": "浙江省宁波市海曙区", + "Value": "330203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924940, + "Key": "浙江省宁波市江北区", + "Value": "330205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924941, + "Key": "浙江省宁波市北仑区", + "Value": "330206" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924942, + "Key": "浙江省宁波市镇海区", + "Value": "330211" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924943, + "Key": "浙江省宁波市鄞州区", + "Value": "330212" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788924944, + "Key": "浙江省宁波市奉化区", + "Value": "330213" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929029, + "Key": "浙江省宁波市象山县", + "Value": "330225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929030, + "Key": "浙江省宁波市宁海县", + "Value": "330226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929031, + "Key": "浙江省宁波市余姚市", + "Value": "330281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929032, + "Key": "浙江省宁波市慈溪市", + "Value": "330282" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929033, + "Key": "浙江省温州市", + "Value": "330300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929034, + "Key": "浙江省温州市鹿城区", + "Value": "330302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929035, + "Key": "浙江省温州市龙湾区", + "Value": "330303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929036, + "Key": "浙江省温州市瓯海区", + "Value": "330304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929037, + "Key": "浙江省温州市洞头区", + "Value": "330305" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929038, + "Key": "浙江省温州市永嘉县", + "Value": "330324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929039, + "Key": "浙江省温州市平阳县", + "Value": "330326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788929040, + "Key": "浙江省温州市苍南县", + "Value": "330327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933125, + "Key": "浙江省温州市文成县", + "Value": "330328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933126, + "Key": "浙江省温州市泰顺县", + "Value": "330329" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933127, + "Key": "浙江省温州市瑞安市", + "Value": "330381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933128, + "Key": "浙江省温州市乐清市", + "Value": "330382" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933129, + "Key": "浙江省温州市龙港市", + "Value": "330383" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933130, + "Key": "浙江省嘉兴市", + "Value": "330400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933131, + "Key": "浙江省嘉兴市南湖区", + "Value": "330402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933132, + "Key": "浙江省嘉兴市秀洲区", + "Value": "330411" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933133, + "Key": "浙江省嘉兴市嘉善县", + "Value": "330421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933134, + "Key": "浙江省嘉兴市海盐县", + "Value": "330424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933135, + "Key": "浙江省嘉兴市海宁市", + "Value": "330481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933136, + "Key": "浙江省嘉兴市平湖市", + "Value": "330482" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788933137, + "Key": "浙江省嘉兴市桐乡市", + "Value": "330483" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937221, + "Key": "浙江省湖州市", + "Value": "330500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937222, + "Key": "浙江省湖州市吴兴区", + "Value": "330502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937223, + "Key": "浙江省湖州市南浔区", + "Value": "330503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937224, + "Key": "浙江省湖州市德清县", + "Value": "330521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937225, + "Key": "浙江省湖州市长兴县", + "Value": "330522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937226, + "Key": "浙江省湖州市安吉县", + "Value": "330523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937227, + "Key": "浙江省绍兴市", + "Value": "330600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937228, + "Key": "浙江省绍兴市越城区", + "Value": "330602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937229, + "Key": "浙江省绍兴市柯桥区", + "Value": "330603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937230, + "Key": "浙江省绍兴市上虞区", + "Value": "330604" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937231, + "Key": "浙江省绍兴市新昌县", + "Value": "330624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788937232, + "Key": "浙江省绍兴市诸暨市", + "Value": "330681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941317, + "Key": "浙江省绍兴市嵊州市", + "Value": "330683" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941318, + "Key": "浙江省金华市", + "Value": "330700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941319, + "Key": "浙江省金华市婺城区", + "Value": "330702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941320, + "Key": "浙江省金华市金东区", + "Value": "330703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941321, + "Key": "浙江省金华市武义县", + "Value": "330723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941322, + "Key": "浙江省金华市浦江县", + "Value": "330726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941323, + "Key": "浙江省金华市磐安县", + "Value": "330727" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941324, + "Key": "浙江省金华市兰溪市", + "Value": "330781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941325, + "Key": "浙江省金华市义乌市", + "Value": "330782" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941326, + "Key": "浙江省金华市东阳市", + "Value": "330783" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941327, + "Key": "浙江省金华市永康市", + "Value": "330784" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941328, + "Key": "浙江省衢州市", + "Value": "330800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788941329, + "Key": "浙江省衢州市柯城区", + "Value": "330802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788945413, + "Key": "浙江省衢州市衢江区", + "Value": "330803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788945414, + "Key": "浙江省衢州市常山县", + "Value": "330822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788945415, + "Key": "浙江省衢州市开化县", + "Value": "330824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788945416, + "Key": "浙江省衢州市龙游县", + "Value": "330825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788945417, + "Key": "浙江省衢州市江山市", + "Value": "330881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788945418, + "Key": "浙江省舟山市", + "Value": "330900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788945419, + "Key": "浙江省舟山市定海区", + "Value": "330902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788945420, + "Key": "浙江省舟山市普陀区", + "Value": "330903" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788945421, + "Key": "浙江省舟山市岱山县", + "Value": "330921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788945422, + "Key": "浙江省舟山市嵊泗县", + "Value": "330922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788945423, + "Key": "浙江省台州市", + "Value": "331000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788949509, + "Key": "浙江省台州市椒江区", + "Value": "331002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788949510, + "Key": "浙江省台州市黄岩区", + "Value": "331003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788949511, + "Key": "浙江省台州市路桥区", + "Value": "331004" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788949512, + "Key": "浙江省台州市三门县", + "Value": "331022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788949513, + "Key": "浙江省台州市天台县", + "Value": "331023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788949514, + "Key": "浙江省台州市仙居县", + "Value": "331024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788949515, + "Key": "浙江省台州市温岭市", + "Value": "331081" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788949516, + "Key": "浙江省台州市临海市", + "Value": "331082" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788949517, + "Key": "浙江省台州市玉环市", + "Value": "331083" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788949518, + "Key": "浙江省丽水市", + "Value": "331100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788969989, + "Key": "浙江省丽水市莲都区", + "Value": "331102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788978181, + "Key": "浙江省丽水市青田县", + "Value": "331121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788978182, + "Key": "浙江省丽水市缙云县", + "Value": "331122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788978183, + "Key": "浙江省丽水市遂昌县", + "Value": "331123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788978184, + "Key": "浙江省丽水市松阳县", + "Value": "331124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788978185, + "Key": "浙江省丽水市云和县", + "Value": "331125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788978186, + "Key": "浙江省丽水市庆元县", + "Value": "331126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788978187, + "Key": "浙江省丽水市景宁畲族自治县", + "Value": "331127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788978188, + "Key": "浙江省丽水市龙泉市", + "Value": "331181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788982277, + "Key": "安徽省", + "Value": "340000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788982278, + "Key": "安徽省合肥市", + "Value": "340100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788982279, + "Key": "安徽省合肥市瑶海区", + "Value": "340102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788982280, + "Key": "安徽省合肥市庐阳区", + "Value": "340103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788982281, + "Key": "安徽省合肥市蜀山区", + "Value": "340104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788982282, + "Key": "安徽省合肥市包河区", + "Value": "340111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788982283, + "Key": "安徽省合肥市长丰县", + "Value": "340121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788982284, + "Key": "安徽省合肥市肥东县", + "Value": "340122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788982285, + "Key": "安徽省合肥市肥西县", + "Value": "340123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788982286, + "Key": "安徽省合肥市庐江县", + "Value": "340124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788982287, + "Key": "安徽省合肥市巢湖市", + "Value": "340181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788986373, + "Key": "安徽省芜湖市", + "Value": "340200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788986374, + "Key": "安徽省芜湖市镜湖区", + "Value": "340202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788986375, + "Key": "安徽省芜湖市鸠江区", + "Value": "340207" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788986376, + "Key": "安徽省芜湖市弋江区", + "Value": "340209" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788986377, + "Key": "安徽省芜湖市湾沚区", + "Value": "340210" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788986378, + "Key": "安徽省芜湖市繁昌区", + "Value": "340212" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788986379, + "Key": "安徽省芜湖市南陵县", + "Value": "340223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788986380, + "Key": "安徽省芜湖市无为市", + "Value": "340281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788986381, + "Key": "安徽省蚌埠市", + "Value": "340300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788986382, + "Key": "安徽省蚌埠市龙子湖区", + "Value": "340302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788986383, + "Key": "安徽省蚌埠市蚌山区", + "Value": "340303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990469, + "Key": "安徽省蚌埠市禹会区", + "Value": "340304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990470, + "Key": "安徽省蚌埠市淮上区", + "Value": "340311" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990471, + "Key": "安徽省蚌埠市怀远县", + "Value": "340321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990472, + "Key": "安徽省蚌埠市五河县", + "Value": "340322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990473, + "Key": "安徽省蚌埠市固镇县", + "Value": "340323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990474, + "Key": "安徽省淮南市", + "Value": "340400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990475, + "Key": "安徽省淮南市大通区", + "Value": "340402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990476, + "Key": "安徽省淮南市田家庵区", + "Value": "340403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990477, + "Key": "安徽省淮南市谢家集区", + "Value": "340404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990478, + "Key": "安徽省淮南市八公山区", + "Value": "340405" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990479, + "Key": "安徽省淮南市潘集区", + "Value": "340406" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788990480, + "Key": "安徽省淮南市凤台县", + "Value": "340421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994565, + "Key": "安徽省淮南市寿县", + "Value": "340422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994566, + "Key": "安徽省马鞍山市", + "Value": "340500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994567, + "Key": "安徽省马鞍山市花山区", + "Value": "340503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994568, + "Key": "安徽省马鞍山市雨山区", + "Value": "340504" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994569, + "Key": "安徽省马鞍山市博望区", + "Value": "340506" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994570, + "Key": "安徽省马鞍山市当涂县", + "Value": "340521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994571, + "Key": "安徽省马鞍山市含山县", + "Value": "340522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994572, + "Key": "安徽省马鞍山市和县", + "Value": "340523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994573, + "Key": "安徽省淮北市", + "Value": "340600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994574, + "Key": "安徽省淮北市杜集区", + "Value": "340602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994575, + "Key": "安徽省淮北市相山区", + "Value": "340603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994576, + "Key": "安徽省淮北市烈山区", + "Value": "340604" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788994577, + "Key": "安徽省淮北市濉溪县", + "Value": "340621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998661, + "Key": "安徽省铜陵市", + "Value": "340700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998662, + "Key": "安徽省铜陵市铜官区", + "Value": "340705" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998663, + "Key": "安徽省铜陵市义安区", + "Value": "340706" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998664, + "Key": "安徽省铜陵市郊区", + "Value": "340711" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998665, + "Key": "安徽省铜陵市枞阳县", + "Value": "340722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998666, + "Key": "安徽省安庆市", + "Value": "340800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998667, + "Key": "安徽省安庆市迎江区", + "Value": "340802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998668, + "Key": "安徽省安庆市大观区", + "Value": "340803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998669, + "Key": "安徽省安庆市宜秀区", + "Value": "340811" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998670, + "Key": "安徽省安庆市怀宁县", + "Value": "340822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998671, + "Key": "安徽省安庆市太湖县", + "Value": "340825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998672, + "Key": "安徽省安庆市宿松县", + "Value": "340826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423788998673, + "Key": "安徽省安庆市望江县", + "Value": "340827" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002757, + "Key": "安徽省安庆市岳西县", + "Value": "340828" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002758, + "Key": "安徽省安庆市桐城市", + "Value": "340881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002759, + "Key": "安徽省安庆市潜山市", + "Value": "340882" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002760, + "Key": "安徽省黄山市", + "Value": "341000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002761, + "Key": "安徽省黄山市屯溪区", + "Value": "341002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002762, + "Key": "安徽省黄山市黄山区", + "Value": "341003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002763, + "Key": "安徽省黄山市徽州区", + "Value": "341004" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002764, + "Key": "安徽省黄山市歙县", + "Value": "341021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002765, + "Key": "安徽省黄山市休宁县", + "Value": "341022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002766, + "Key": "安徽省黄山市黟县", + "Value": "341023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002767, + "Key": "安徽省黄山市祁门县", + "Value": "341024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002768, + "Key": "安徽省滁州市", + "Value": "341100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789002769, + "Key": "安徽省滁州市琅琊区", + "Value": "341102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006853, + "Key": "安徽省滁州市南谯区", + "Value": "341103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006854, + "Key": "安徽省滁州市来安县", + "Value": "341122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006855, + "Key": "安徽省滁州市全椒县", + "Value": "341124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006856, + "Key": "安徽省滁州市定远县", + "Value": "341125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006857, + "Key": "安徽省滁州市凤阳县", + "Value": "341126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006858, + "Key": "安徽省滁州市天长市", + "Value": "341181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006859, + "Key": "安徽省滁州市明光市", + "Value": "341182" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006860, + "Key": "安徽省阜阳市", + "Value": "341200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006861, + "Key": "安徽省阜阳市颍州区", + "Value": "341202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006862, + "Key": "安徽省阜阳市颍东区", + "Value": "341203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006863, + "Key": "安徽省阜阳市颍泉区", + "Value": "341204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006864, + "Key": "安徽省阜阳市临泉县", + "Value": "341221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789006865, + "Key": "安徽省阜阳市太和县", + "Value": "341222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010949, + "Key": "安徽省阜阳市阜南县", + "Value": "341225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010950, + "Key": "安徽省阜阳市颍上县", + "Value": "341226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010951, + "Key": "安徽省阜阳市界首市", + "Value": "341282" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010952, + "Key": "安徽省宿州市", + "Value": "341300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010953, + "Key": "安徽省宿州市埇桥区", + "Value": "341302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010954, + "Key": "安徽省宿州市砀山县", + "Value": "341321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010955, + "Key": "安徽省宿州市萧县", + "Value": "341322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010956, + "Key": "安徽省宿州市灵璧县", + "Value": "341323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010957, + "Key": "安徽省宿州市泗县", + "Value": "341324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010958, + "Key": "安徽省六安市", + "Value": "341500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010959, + "Key": "安徽省六安市金安区", + "Value": "341502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789010960, + "Key": "安徽省六安市裕安区", + "Value": "341503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015045, + "Key": "安徽省六安市叶集区", + "Value": "341504" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015046, + "Key": "安徽省六安市霍邱县", + "Value": "341522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015047, + "Key": "安徽省六安市舒城县", + "Value": "341523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015048, + "Key": "安徽省六安市金寨县", + "Value": "341524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015049, + "Key": "安徽省六安市霍山县", + "Value": "341525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015050, + "Key": "安徽省亳州市", + "Value": "341600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015051, + "Key": "安徽省亳州市谯城区", + "Value": "341602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015052, + "Key": "安徽省亳州市涡阳县", + "Value": "341621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015053, + "Key": "安徽省亳州市蒙城县", + "Value": "341622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015054, + "Key": "安徽省亳州市利辛县", + "Value": "341623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015055, + "Key": "安徽省池州市", + "Value": "341700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015056, + "Key": "安徽省池州市贵池区", + "Value": "341702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789015057, + "Key": "安徽省池州市东至县", + "Value": "341721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019141, + "Key": "安徽省池州市石台县", + "Value": "341722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019142, + "Key": "安徽省池州市青阳县", + "Value": "341723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019143, + "Key": "安徽省宣城市", + "Value": "341800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019144, + "Key": "安徽省宣城市宣州区", + "Value": "341802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019145, + "Key": "安徽省宣城市郎溪县", + "Value": "341821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019146, + "Key": "安徽省宣城市泾县", + "Value": "341823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019147, + "Key": "安徽省宣城市绩溪县", + "Value": "341824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019148, + "Key": "安徽省宣城市旌德县", + "Value": "341825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019149, + "Key": "安徽省宣城市宁国市", + "Value": "341881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019150, + "Key": "安徽省宣城市广德市", + "Value": "341882" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019151, + "Key": "福建省", + "Value": "350000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019152, + "Key": "福建省福州市", + "Value": "350100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789019153, + "Key": "福建省福州市鼓楼区", + "Value": "350102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023237, + "Key": "福建省福州市台江区", + "Value": "350103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023238, + "Key": "福建省福州市仓山区", + "Value": "350104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023239, + "Key": "福建省福州市马尾区", + "Value": "350105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023240, + "Key": "福建省福州市晋安区", + "Value": "350111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023241, + "Key": "福建省福州市长乐区", + "Value": "350112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023242, + "Key": "福建省福州市闽侯县", + "Value": "350121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023243, + "Key": "福建省福州市连江县", + "Value": "350122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023244, + "Key": "福建省福州市罗源县", + "Value": "350123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023245, + "Key": "福建省福州市闽清县", + "Value": "350124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023246, + "Key": "福建省福州市永泰县", + "Value": "350125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023247, + "Key": "福建省福州市平潭县", + "Value": "350128" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023248, + "Key": "福建省福州市福清市", + "Value": "350181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789023249, + "Key": "福建省厦门市", + "Value": "350200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027333, + "Key": "福建省厦门市思明区", + "Value": "350203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027334, + "Key": "福建省厦门市海沧区", + "Value": "350205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027335, + "Key": "福建省厦门市湖里区", + "Value": "350206" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027336, + "Key": "福建省厦门市集美区", + "Value": "350211" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027337, + "Key": "福建省厦门市同安区", + "Value": "350212" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027338, + "Key": "福建省厦门市翔安区", + "Value": "350213" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027339, + "Key": "福建省莆田市", + "Value": "350300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027340, + "Key": "福建省莆田市城厢区", + "Value": "350302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027341, + "Key": "福建省莆田市涵江区", + "Value": "350303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027342, + "Key": "福建省莆田市荔城区", + "Value": "350304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027343, + "Key": "福建省莆田市秀屿区", + "Value": "350305" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027344, + "Key": "福建省莆田市仙游县", + "Value": "350322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789027345, + "Key": "福建省三明市", + "Value": "350400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031429, + "Key": "福建省三明市三元区", + "Value": "350404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031430, + "Key": "福建省三明市沙县区", + "Value": "350405" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031431, + "Key": "福建省三明市明溪县", + "Value": "350421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031432, + "Key": "福建省三明市清流县", + "Value": "350423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031433, + "Key": "福建省三明市宁化县", + "Value": "350424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031434, + "Key": "福建省三明市大田县", + "Value": "350425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031435, + "Key": "福建省三明市尤溪县", + "Value": "350426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031436, + "Key": "福建省三明市将乐县", + "Value": "350428" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031437, + "Key": "福建省三明市泰宁县", + "Value": "350429" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031438, + "Key": "福建省三明市建宁县", + "Value": "350430" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031439, + "Key": "福建省三明市永安市", + "Value": "350481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789031440, + "Key": "福建省泉州市", + "Value": "350500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035525, + "Key": "福建省泉州市鲤城区", + "Value": "350502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035526, + "Key": "福建省泉州市丰泽区", + "Value": "350503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035527, + "Key": "福建省泉州市洛江区", + "Value": "350504" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035528, + "Key": "福建省泉州市泉港区", + "Value": "350505" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035529, + "Key": "福建省泉州市惠安县", + "Value": "350521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035530, + "Key": "福建省泉州市安溪县", + "Value": "350524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035531, + "Key": "福建省泉州市永春县", + "Value": "350525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035532, + "Key": "福建省泉州市德化县", + "Value": "350526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035533, + "Key": "福建省泉州市金门县", + "Value": "350527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035534, + "Key": "福建省泉州市石狮市", + "Value": "350581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035535, + "Key": "福建省泉州市晋江市", + "Value": "350582" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035536, + "Key": "福建省泉州市南安市", + "Value": "350583" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789035537, + "Key": "福建省漳州市", + "Value": "350600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039621, + "Key": "福建省漳州市芗城区", + "Value": "350602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039622, + "Key": "福建省漳州市龙文区", + "Value": "350603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039623, + "Key": "福建省漳州市龙海区", + "Value": "350604" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039624, + "Key": "福建省漳州市长泰市", + "Value": "350605" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039625, + "Key": "福建省漳州市云霄县", + "Value": "350622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039626, + "Key": "福建省漳州市漳浦县", + "Value": "350623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039627, + "Key": "福建省漳州市诏安县", + "Value": "350624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039628, + "Key": "福建省漳州市东山县", + "Value": "350626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039629, + "Key": "福建省漳州市南靖县", + "Value": "350627" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039630, + "Key": "福建省漳州市平和县", + "Value": "350628" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039631, + "Key": "福建省漳州市华安县", + "Value": "350629" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039632, + "Key": "福建省南平市", + "Value": "350700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789039633, + "Key": "福建省南平市延平区", + "Value": "350702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043717, + "Key": "福建省南平市建阳区", + "Value": "350703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043718, + "Key": "福建省南平市顺昌县", + "Value": "350721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043719, + "Key": "福建省南平市浦城县", + "Value": "350722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043720, + "Key": "福建省南平市光泽县", + "Value": "350723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043721, + "Key": "福建省南平市松溪县", + "Value": "350724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043722, + "Key": "福建省南平市政和县", + "Value": "350725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043723, + "Key": "福建省南平市邵武市", + "Value": "350781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043724, + "Key": "福建省南平市武夷山市", + "Value": "350782" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043725, + "Key": "福建省南平市建瓯市", + "Value": "350783" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043726, + "Key": "福建省龙岩市", + "Value": "350800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043727, + "Key": "福建省龙岩市新罗区", + "Value": "350802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789043728, + "Key": "福建省龙岩市永定区", + "Value": "350803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047813, + "Key": "福建省龙岩市长汀县", + "Value": "350821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047814, + "Key": "福建省龙岩市上杭县", + "Value": "350823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047815, + "Key": "福建省龙岩市武平县", + "Value": "350824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047816, + "Key": "福建省龙岩市连城县", + "Value": "350825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047817, + "Key": "福建省龙岩市漳平市", + "Value": "350881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047818, + "Key": "福建省宁德市", + "Value": "350900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047819, + "Key": "福建省宁德市蕉城区", + "Value": "350902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047820, + "Key": "福建省宁德市霞浦县", + "Value": "350921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047821, + "Key": "福建省宁德市古田县", + "Value": "350922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047822, + "Key": "福建省宁德市屏南县", + "Value": "350923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047823, + "Key": "福建省宁德市寿宁县", + "Value": "350924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047824, + "Key": "福建省宁德市周宁县", + "Value": "350925" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789047825, + "Key": "福建省宁德市柘荣县", + "Value": "350926" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051909, + "Key": "福建省宁德市福安市", + "Value": "350981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051910, + "Key": "福建省宁德市福鼎市", + "Value": "350982" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051911, + "Key": "江西省", + "Value": "360000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051912, + "Key": "江西省南昌市", + "Value": "360100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051913, + "Key": "江西省南昌市东湖区", + "Value": "360102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051914, + "Key": "江西省南昌市西湖区", + "Value": "360103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051915, + "Key": "江西省南昌市青云谱区", + "Value": "360104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051916, + "Key": "江西省南昌市青山湖区", + "Value": "360111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051917, + "Key": "江西省南昌市新建区", + "Value": "360112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051918, + "Key": "江西省南昌市红谷滩区", + "Value": "360113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051919, + "Key": "江西省南昌市南昌县", + "Value": "360121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051920, + "Key": "江西省南昌市安义县", + "Value": "360123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789051921, + "Key": "江西省南昌市进贤县", + "Value": "360124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056005, + "Key": "江西省景德镇市", + "Value": "360200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056006, + "Key": "江西省景德镇市昌江区", + "Value": "360202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056007, + "Key": "江西省景德镇市珠山区", + "Value": "360203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056008, + "Key": "江西省景德镇市浮梁县", + "Value": "360222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056009, + "Key": "江西省景德镇市乐平市", + "Value": "360281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056010, + "Key": "江西省萍乡市", + "Value": "360300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056011, + "Key": "江西省萍乡市安源区", + "Value": "360302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056012, + "Key": "江西省萍乡市湘东区", + "Value": "360313" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056013, + "Key": "江西省萍乡市莲花县", + "Value": "360321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056014, + "Key": "江西省萍乡市上栗县", + "Value": "360322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056015, + "Key": "江西省萍乡市芦溪县", + "Value": "360323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056016, + "Key": "江西省九江市", + "Value": "360400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789056017, + "Key": "江西省九江市濂溪区", + "Value": "360402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060101, + "Key": "江西省九江市浔阳区", + "Value": "360403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060102, + "Key": "江西省九江市柴桑区", + "Value": "360404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060103, + "Key": "江西省九江市武宁县", + "Value": "360423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060104, + "Key": "江西省九江市修水县", + "Value": "360424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060105, + "Key": "江西省九江市永修县", + "Value": "360425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060106, + "Key": "江西省九江市德安县", + "Value": "360426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060107, + "Key": "江西省九江市都昌县", + "Value": "360428" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060108, + "Key": "江西省九江市湖口县", + "Value": "360429" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060109, + "Key": "江西省九江市彭泽县", + "Value": "360430" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060110, + "Key": "江西省九江市瑞昌市", + "Value": "360481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060111, + "Key": "江西省九江市共青城市", + "Value": "360482" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060112, + "Key": "江西省九江市庐山市", + "Value": "360483" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789060113, + "Key": "江西省新余市", + "Value": "360500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064197, + "Key": "江西省新余市渝水区", + "Value": "360502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064198, + "Key": "江西省新余市分宜县", + "Value": "360521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064199, + "Key": "江西省鹰潭市", + "Value": "360600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064200, + "Key": "江西省鹰潭市月湖区", + "Value": "360602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064201, + "Key": "江西省鹰潭市余江区", + "Value": "360603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064202, + "Key": "江西省鹰潭市贵溪市", + "Value": "360681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064203, + "Key": "江西省赣州市", + "Value": "360700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064204, + "Key": "江西省赣州市章贡区", + "Value": "360702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064205, + "Key": "江西省赣州市南康区", + "Value": "360703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064206, + "Key": "江西省赣州市赣县区", + "Value": "360704" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064207, + "Key": "江西省赣州市信丰县", + "Value": "360722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064208, + "Key": "江西省赣州市大余县", + "Value": "360723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789064209, + "Key": "江西省赣州市上犹县", + "Value": "360724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068293, + "Key": "江西省赣州市崇义县", + "Value": "360725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068294, + "Key": "江西省赣州市安远县", + "Value": "360726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068295, + "Key": "江西省赣州市定南县", + "Value": "360728" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068296, + "Key": "江西省赣州市全南县", + "Value": "360729" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068297, + "Key": "江西省赣州市宁都县", + "Value": "360730" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068298, + "Key": "江西省赣州市于都县", + "Value": "360731" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068299, + "Key": "江西省赣州市兴国县", + "Value": "360732" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068300, + "Key": "江西省赣州市会昌县", + "Value": "360733" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068301, + "Key": "江西省赣州市寻乌县", + "Value": "360734" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068302, + "Key": "江西省赣州市石城县", + "Value": "360735" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068303, + "Key": "江西省赣州市瑞金市", + "Value": "360781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789068304, + "Key": "江西省赣州市龙南市", + "Value": "360783" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072389, + "Key": "江西省吉安市", + "Value": "360800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072390, + "Key": "江西省吉安市吉州区", + "Value": "360802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072391, + "Key": "江西省吉安市青原区", + "Value": "360803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072392, + "Key": "江西省吉安市吉安县", + "Value": "360821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072393, + "Key": "江西省吉安市吉水县", + "Value": "360822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072394, + "Key": "江西省吉安市峡江县", + "Value": "360823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072395, + "Key": "江西省吉安市新干县", + "Value": "360824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072396, + "Key": "江西省吉安市永丰县", + "Value": "360825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072397, + "Key": "江西省吉安市泰和县", + "Value": "360826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072398, + "Key": "江西省吉安市遂川县", + "Value": "360827" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072399, + "Key": "江西省吉安市万安县", + "Value": "360828" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072400, + "Key": "江西省吉安市安福县", + "Value": "360829" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789072401, + "Key": "江西省吉安市永新县", + "Value": "360830" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076485, + "Key": "江西省吉安市井冈山市", + "Value": "360881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076486, + "Key": "江西省宜春市", + "Value": "360900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076487, + "Key": "江西省宜春市袁州区", + "Value": "360902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076488, + "Key": "江西省宜春市奉新县", + "Value": "360921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076489, + "Key": "江西省宜春市万载县", + "Value": "360922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076490, + "Key": "江西省宜春市上高县", + "Value": "360923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076491, + "Key": "江西省宜春市宜丰县", + "Value": "360924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076492, + "Key": "江西省宜春市靖安县", + "Value": "360925" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076493, + "Key": "江西省宜春市铜鼓县", + "Value": "360926" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076494, + "Key": "江西省宜春市丰城市", + "Value": "360981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076495, + "Key": "江西省宜春市樟树市", + "Value": "360982" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076496, + "Key": "江西省宜春市高安市", + "Value": "360983" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789076497, + "Key": "江西省抚州市", + "Value": "361000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080581, + "Key": "江西省抚州市临川区", + "Value": "361002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080582, + "Key": "江西省抚州市东乡区", + "Value": "361003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080583, + "Key": "江西省抚州市南城县", + "Value": "361021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080584, + "Key": "江西省抚州市黎川县", + "Value": "361022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080585, + "Key": "江西省抚州市南丰县", + "Value": "361023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080586, + "Key": "江西省抚州市崇仁县", + "Value": "361024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080587, + "Key": "江西省抚州市乐安县", + "Value": "361025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080588, + "Key": "江西省抚州市宜黄县", + "Value": "361026" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080589, + "Key": "江西省抚州市金溪县", + "Value": "361027" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080590, + "Key": "江西省抚州市资溪县", + "Value": "361028" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080591, + "Key": "江西省抚州市广昌县", + "Value": "361030" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080592, + "Key": "江西省上饶市", + "Value": "361100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789080593, + "Key": "江西省上饶市信州区", + "Value": "361102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084677, + "Key": "江西省上饶市广丰区", + "Value": "361103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084678, + "Key": "江西省上饶市广信区", + "Value": "361104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084679, + "Key": "江西省上饶市玉山县", + "Value": "361123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084680, + "Key": "江西省上饶市铅山县", + "Value": "361124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084681, + "Key": "江西省上饶市横峰县", + "Value": "361125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084682, + "Key": "江西省上饶市弋阳县", + "Value": "361126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084683, + "Key": "江西省上饶市余干县", + "Value": "361127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084684, + "Key": "江西省上饶市鄱阳县", + "Value": "361128" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084685, + "Key": "江西省上饶市万年县", + "Value": "361129" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084686, + "Key": "江西省上饶市婺源县", + "Value": "361130" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084687, + "Key": "江西省上饶市德兴市", + "Value": "361181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084688, + "Key": "山东省", + "Value": "370000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789084689, + "Key": "山东省济南市", + "Value": "370100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088773, + "Key": "山东省济南市历下区", + "Value": "370102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088774, + "Key": "山东省济南市市中区", + "Value": "370103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088775, + "Key": "山东省济南市槐荫区", + "Value": "370104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088776, + "Key": "山东省济南市天桥区", + "Value": "370105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088777, + "Key": "山东省济南市历城区", + "Value": "370112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088778, + "Key": "山东省济南市长清区", + "Value": "370113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088779, + "Key": "山东省济南市章丘区", + "Value": "370114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088780, + "Key": "山东省济南市济阳区", + "Value": "370115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088781, + "Key": "山东省济南市莱芜区", + "Value": "370116" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088782, + "Key": "山东省济南市钢城区", + "Value": "370117" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088783, + "Key": "山东省济南市平阴县", + "Value": "370124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088784, + "Key": "山东省济南市商河县", + "Value": "370126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789088785, + "Key": "山东省青岛市", + "Value": "370200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092869, + "Key": "山东省青岛市市南区", + "Value": "370202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092870, + "Key": "山东省青岛市市北区", + "Value": "370203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092871, + "Key": "山东省青岛市黄岛区", + "Value": "370211" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092872, + "Key": "山东省青岛市崂山区", + "Value": "370212" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092873, + "Key": "山东省青岛市李沧区", + "Value": "370213" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092874, + "Key": "山东省青岛市城阳区", + "Value": "370214" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092875, + "Key": "山东省青岛市即墨区", + "Value": "370215" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092876, + "Key": "山东省青岛市胶州市", + "Value": "370281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092877, + "Key": "山东省青岛市平度市", + "Value": "370283" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092878, + "Key": "山东省青岛市莱西市", + "Value": "370285" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092879, + "Key": "山东省淄博市", + "Value": "370300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092880, + "Key": "山东省淄博市淄川区", + "Value": "370302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789092881, + "Key": "山东省淄博市张店区", + "Value": "370303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096965, + "Key": "山东省淄博市博山区", + "Value": "370304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096966, + "Key": "山东省淄博市临淄区", + "Value": "370305" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096967, + "Key": "山东省淄博市周村区", + "Value": "370306" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096968, + "Key": "山东省淄博市桓台县", + "Value": "370321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096969, + "Key": "山东省淄博市高青县", + "Value": "370322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096970, + "Key": "山东省淄博市沂源县", + "Value": "370323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096971, + "Key": "山东省枣庄市", + "Value": "370400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096972, + "Key": "山东省枣庄市市中区", + "Value": "370402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096973, + "Key": "山东省枣庄市薛城区", + "Value": "370403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096974, + "Key": "山东省枣庄市峄城区", + "Value": "370404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096975, + "Key": "山东省枣庄市台儿庄区", + "Value": "370405" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096976, + "Key": "山东省枣庄市山亭区", + "Value": "370406" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789096977, + "Key": "山东省枣庄市滕州市", + "Value": "370481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101061, + "Key": "山东省东营市", + "Value": "370500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101062, + "Key": "山东省东营市东营区", + "Value": "370502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101063, + "Key": "山东省东营市河口区", + "Value": "370503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101064, + "Key": "山东省东营市垦利区", + "Value": "370505" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101065, + "Key": "山东省东营市利津县", + "Value": "370522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101066, + "Key": "山东省东营市广饶县", + "Value": "370523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101067, + "Key": "山东省烟台市", + "Value": "370600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101068, + "Key": "山东省烟台市芝罘区", + "Value": "370602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101069, + "Key": "山东省烟台市福山区", + "Value": "370611" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101070, + "Key": "山东省烟台市牟平区", + "Value": "370612" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101071, + "Key": "山东省烟台市莱山区", + "Value": "370613" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101072, + "Key": "山东省烟台市蓬莱区", + "Value": "370614" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789101073, + "Key": "山东省烟台市龙口市", + "Value": "370681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105157, + "Key": "山东省烟台市莱阳市", + "Value": "370682" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105158, + "Key": "山东省烟台市莱州市", + "Value": "370683" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105159, + "Key": "山东省烟台市招远市", + "Value": "370685" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105160, + "Key": "山东省烟台市栖霞市", + "Value": "370686" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105161, + "Key": "山东省烟台市海阳市", + "Value": "370687" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105162, + "Key": "山东省潍坊市", + "Value": "370700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105163, + "Key": "山东省潍坊市潍城区", + "Value": "370702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105164, + "Key": "山东省潍坊市寒亭区", + "Value": "370703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105165, + "Key": "山东省潍坊市坊子区", + "Value": "370704" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105166, + "Key": "山东省潍坊市奎文区", + "Value": "370705" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105167, + "Key": "山东省潍坊市临朐县", + "Value": "370724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105168, + "Key": "山东省潍坊市昌乐县", + "Value": "370725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789105169, + "Key": "山东省潍坊市青州市", + "Value": "370781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109253, + "Key": "山东省潍坊市诸城市", + "Value": "370782" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109254, + "Key": "山东省潍坊市寿光市", + "Value": "370783" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109255, + "Key": "山东省潍坊市安丘市", + "Value": "370784" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109256, + "Key": "山东省潍坊市高密市", + "Value": "370785" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109257, + "Key": "山东省潍坊市昌邑市", + "Value": "370786" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109258, + "Key": "山东省济宁市", + "Value": "370800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109259, + "Key": "山东省济宁市任城区", + "Value": "370811" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109260, + "Key": "山东省济宁市兖州区", + "Value": "370812" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109261, + "Key": "山东省济宁市微山县", + "Value": "370826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109262, + "Key": "山东省济宁市鱼台县", + "Value": "370827" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109263, + "Key": "山东省济宁市金乡县", + "Value": "370828" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789109264, + "Key": "山东省济宁市嘉祥县", + "Value": "370829" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789113349, + "Key": "山东省济宁市汶上县", + "Value": "370830" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789113350, + "Key": "山东省济宁市泗水县", + "Value": "370831" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789113351, + "Key": "山东省济宁市梁山县", + "Value": "370832" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789113352, + "Key": "山东省济宁市曲阜市", + "Value": "370881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789113353, + "Key": "山东省济宁市邹城市", + "Value": "370883" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789113354, + "Key": "山东省泰安市", + "Value": "370900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789113355, + "Key": "山东省泰安市泰山区", + "Value": "370902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789113356, + "Key": "山东省泰安市岱岳区", + "Value": "370911" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789113357, + "Key": "山东省泰安市宁阳县", + "Value": "370921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117445, + "Key": "山东省泰安市东平县", + "Value": "370923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117446, + "Key": "山东省泰安市新泰市", + "Value": "370982" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117447, + "Key": "山东省泰安市肥城市", + "Value": "370983" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117448, + "Key": "山东省威海市", + "Value": "371000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117449, + "Key": "山东省威海市环翠区", + "Value": "371002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117450, + "Key": "山东省威海市文登区", + "Value": "371003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117451, + "Key": "山东省威海市荣成市", + "Value": "371082" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117452, + "Key": "山东省威海市乳山市", + "Value": "371083" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117453, + "Key": "山东省日照市", + "Value": "371100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117454, + "Key": "山东省日照市东港区", + "Value": "371102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117455, + "Key": "山东省日照市岚山区", + "Value": "371103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789117456, + "Key": "山东省日照市五莲县", + "Value": "371121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789121541, + "Key": "山东省日照市莒县", + "Value": "371122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789121542, + "Key": "山东省临沂市", + "Value": "371300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789121543, + "Key": "山东省临沂市兰山区", + "Value": "371302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789121544, + "Key": "山东省临沂市罗庄区", + "Value": "371311" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789121545, + "Key": "山东省临沂市河东区", + "Value": "371312" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789121546, + "Key": "山东省临沂市沂南县", + "Value": "371321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789121547, + "Key": "山东省临沂市郯城县", + "Value": "371322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789121548, + "Key": "山东省临沂市沂水县", + "Value": "371323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789121549, + "Key": "山东省临沂市兰陵县", + "Value": "371324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789125637, + "Key": "山东省临沂市费县", + "Value": "371325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789125638, + "Key": "山东省临沂市平邑县", + "Value": "371326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789125639, + "Key": "山东省临沂市莒南县", + "Value": "371327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789125640, + "Key": "山东省临沂市蒙阴县", + "Value": "371328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789125641, + "Key": "山东省临沂市临沭县", + "Value": "371329" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789125642, + "Key": "山东省德州市", + "Value": "371400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789125643, + "Key": "山东省德州市德城区", + "Value": "371402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789125644, + "Key": "山东省德州市陵城区", + "Value": "371403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789125645, + "Key": "山东省德州市宁津县", + "Value": "371422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789125646, + "Key": "山东省德州市庆云县", + "Value": "371423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129733, + "Key": "山东省德州市临邑县", + "Value": "371424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129734, + "Key": "山东省德州市齐河县", + "Value": "371425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129735, + "Key": "山东省德州市平原县", + "Value": "371426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129736, + "Key": "山东省德州市夏津县", + "Value": "371427" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129737, + "Key": "山东省德州市武城县", + "Value": "371428" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129738, + "Key": "山东省德州市乐陵市", + "Value": "371481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129739, + "Key": "山东省德州市禹城市", + "Value": "371482" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129740, + "Key": "山东省聊城市", + "Value": "371500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129741, + "Key": "山东省聊城市东昌府区", + "Value": "371502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129742, + "Key": "山东省聊城市茌平区", + "Value": "371503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129743, + "Key": "山东省聊城市阳谷县", + "Value": "371521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789129744, + "Key": "山东省聊城市莘县", + "Value": "371522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789133829, + "Key": "山东省聊城市东阿县", + "Value": "371524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789133830, + "Key": "山东省聊城市冠县", + "Value": "371525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789133831, + "Key": "山东省聊城市高唐县", + "Value": "371526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789133832, + "Key": "山东省聊城市临清市", + "Value": "371581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789133833, + "Key": "山东省滨州市", + "Value": "371600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789133834, + "Key": "山东省滨州市滨城区", + "Value": "371602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789133835, + "Key": "山东省滨州市沾化区", + "Value": "371603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789133836, + "Key": "山东省滨州市惠民县", + "Value": "371621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789133837, + "Key": "山东省滨州市阳信县", + "Value": "371622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789133838, + "Key": "山东省滨州市无棣县", + "Value": "371623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789133839, + "Key": "山东省滨州市博兴县", + "Value": "371625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137925, + "Key": "山东省滨州市邹平市", + "Value": "371681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137926, + "Key": "山东省菏泽市", + "Value": "371700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137927, + "Key": "山东省菏泽市牡丹区", + "Value": "371702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137928, + "Key": "山东省菏泽市定陶区", + "Value": "371703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137929, + "Key": "山东省菏泽市曹县", + "Value": "371721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137930, + "Key": "山东省菏泽市单县", + "Value": "371722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137931, + "Key": "山东省菏泽市成武县", + "Value": "371723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137932, + "Key": "山东省菏泽市巨野县", + "Value": "371724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137933, + "Key": "山东省菏泽市郓城县", + "Value": "371725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137934, + "Key": "山东省菏泽市鄄城县", + "Value": "371726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137935, + "Key": "山东省菏泽市东明县", + "Value": "371728" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789137936, + "Key": "河南省", + "Value": "410000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142021, + "Key": "河南省郑州市", + "Value": "410100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142022, + "Key": "河南省郑州市中原区", + "Value": "410102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142023, + "Key": "河南省郑州市二七区", + "Value": "410103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142024, + "Key": "河南省郑州市管城回族区", + "Value": "410104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142025, + "Key": "河南省郑州市金水区", + "Value": "410105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142026, + "Key": "河南省郑州市上街区", + "Value": "410106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142027, + "Key": "河南省郑州市惠济区", + "Value": "410108" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142028, + "Key": "河南省郑州市中牟县", + "Value": "410122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142029, + "Key": "河南省郑州市巩义市", + "Value": "410181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142030, + "Key": "河南省郑州市荥阳市", + "Value": "410182" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142031, + "Key": "河南省郑州市新密市", + "Value": "410183" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142032, + "Key": "河南省郑州市新郑市", + "Value": "410184" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789142033, + "Key": "河南省郑州市登封市", + "Value": "410185" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146117, + "Key": "河南省开封市", + "Value": "410200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146118, + "Key": "河南省开封市龙亭区", + "Value": "410202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146119, + "Key": "河南省开封市顺河回族区", + "Value": "410203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146120, + "Key": "河南省开封市鼓楼区", + "Value": "410204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146121, + "Key": "河南省开封市禹王台区", + "Value": "410205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146122, + "Key": "河南省开封市祥符区", + "Value": "410212" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146123, + "Key": "河南省开封市杞县", + "Value": "410221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146124, + "Key": "河南省开封市通许县", + "Value": "410222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146125, + "Key": "河南省开封市尉氏县", + "Value": "410223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146126, + "Key": "河南省开封市兰考县", + "Value": "410225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146127, + "Key": "河南省洛阳市", + "Value": "410300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789146128, + "Key": "河南省洛阳市老城区", + "Value": "410302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150213, + "Key": "河南省洛阳市西工区", + "Value": "410303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150214, + "Key": "河南省洛阳市瀍河回族区", + "Value": "410304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150215, + "Key": "河南省洛阳市涧西区", + "Value": "410305" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150216, + "Key": "河南省洛阳市偃师区", + "Value": "410307" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150217, + "Key": "河南省洛阳市孟津区", + "Value": "410308" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150218, + "Key": "河南省洛阳市洛龙区", + "Value": "410311" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150219, + "Key": "河南省洛阳市新安县", + "Value": "410323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150220, + "Key": "河南省洛阳市栾川县", + "Value": "410324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150221, + "Key": "河南省洛阳市嵩县", + "Value": "410325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150222, + "Key": "河南省洛阳市汝阳县", + "Value": "410326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150223, + "Key": "河南省洛阳市宜阳县", + "Value": "410327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789150224, + "Key": "河南省洛阳市洛宁县", + "Value": "410328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154309, + "Key": "河南省洛阳市伊川县", + "Value": "410329" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154310, + "Key": "河南省平顶山市", + "Value": "410400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154311, + "Key": "河南省平顶山市新华区", + "Value": "410402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154312, + "Key": "河南省平顶山市卫东区", + "Value": "410403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154313, + "Key": "河南省平顶山市石龙区", + "Value": "410404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154314, + "Key": "河南省平顶山市湛河区", + "Value": "410411" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154315, + "Key": "河南省平顶山市宝丰县", + "Value": "410421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154316, + "Key": "河南省平顶山市叶县", + "Value": "410422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154317, + "Key": "河南省平顶山市鲁山县", + "Value": "410423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154318, + "Key": "河南省平顶山市郏县", + "Value": "410425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154319, + "Key": "河南省平顶山市舞钢市", + "Value": "410481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154320, + "Key": "河南省平顶山市汝州市", + "Value": "410482" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789154321, + "Key": "河南省安阳市", + "Value": "410500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158405, + "Key": "河南省安阳市文峰区", + "Value": "410502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158406, + "Key": "河南省安阳市北关区", + "Value": "410503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158407, + "Key": "河南省安阳市殷都区", + "Value": "410505" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158408, + "Key": "河南省安阳市龙安区", + "Value": "410506" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158409, + "Key": "河南省安阳市安阳县", + "Value": "410522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158410, + "Key": "河南省安阳市汤阴县", + "Value": "410523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158411, + "Key": "河南省安阳市滑县", + "Value": "410526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158412, + "Key": "河南省安阳市内黄县", + "Value": "410527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158413, + "Key": "河南省安阳市林州市", + "Value": "410581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158414, + "Key": "河南省鹤壁市", + "Value": "410600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158415, + "Key": "河南省鹤壁市鹤山区", + "Value": "410602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158416, + "Key": "河南省鹤壁市山城区", + "Value": "410603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789158417, + "Key": "河南省鹤壁市淇滨区", + "Value": "410611" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162501, + "Key": "河南省鹤壁市浚县", + "Value": "410621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162502, + "Key": "河南省鹤壁市淇县", + "Value": "410622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162503, + "Key": "河南省新乡市", + "Value": "410700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162504, + "Key": "河南省新乡市红旗区", + "Value": "410702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162505, + "Key": "河南省新乡市卫滨区", + "Value": "410703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162506, + "Key": "河南省新乡市凤泉区", + "Value": "410704" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162507, + "Key": "河南省新乡市牧野区", + "Value": "410711" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162508, + "Key": "河南省新乡市新乡县", + "Value": "410721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162509, + "Key": "河南省新乡市获嘉县", + "Value": "410724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162510, + "Key": "河南省新乡市原阳县", + "Value": "410725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162511, + "Key": "河南省新乡市延津县", + "Value": "410726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162512, + "Key": "河南省新乡市封丘县", + "Value": "410727" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789162513, + "Key": "河南省新乡市卫辉市", + "Value": "410781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166597, + "Key": "河南省新乡市辉县市", + "Value": "410782" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166598, + "Key": "河南省新乡市长垣市", + "Value": "410783" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166599, + "Key": "河南省焦作市", + "Value": "410800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166600, + "Key": "河南省焦作市解放区", + "Value": "410802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166601, + "Key": "河南省焦作市中站区", + "Value": "410803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166602, + "Key": "河南省焦作市马村区", + "Value": "410804" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166603, + "Key": "河南省焦作市山阳区", + "Value": "410811" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166604, + "Key": "河南省焦作市修武县", + "Value": "410821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166605, + "Key": "河南省焦作市博爱县", + "Value": "410822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166606, + "Key": "河南省焦作市武陟县", + "Value": "410823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166607, + "Key": "河南省焦作市温县", + "Value": "410825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166608, + "Key": "河南省焦作市沁阳市", + "Value": "410882" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789166609, + "Key": "河南省焦作市孟州市", + "Value": "410883" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170693, + "Key": "河南省濮阳市", + "Value": "410900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170694, + "Key": "河南省濮阳市华龙区", + "Value": "410902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170695, + "Key": "河南省濮阳市清丰县", + "Value": "410922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170696, + "Key": "河南省濮阳市南乐县", + "Value": "410923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170697, + "Key": "河南省濮阳市范县", + "Value": "410926" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170698, + "Key": "河南省濮阳市台前县", + "Value": "410927" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170699, + "Key": "河南省濮阳市濮阳县", + "Value": "410928" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170700, + "Key": "河南省许昌市", + "Value": "411000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170701, + "Key": "河南省许昌市魏都区", + "Value": "411002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170702, + "Key": "河南省许昌市建安区", + "Value": "411003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170703, + "Key": "河南省许昌市鄢陵县", + "Value": "411024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170704, + "Key": "河南省许昌市襄城县", + "Value": "411025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789170705, + "Key": "河南省许昌市禹州市", + "Value": "411081" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174789, + "Key": "河南省许昌市长葛市", + "Value": "411082" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174790, + "Key": "河南省漯河市", + "Value": "411100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174791, + "Key": "河南省漯河市源汇区", + "Value": "411102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174792, + "Key": "河南省漯河市郾城区", + "Value": "411103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174793, + "Key": "河南省漯河市召陵区", + "Value": "411104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174794, + "Key": "河南省漯河市舞阳县", + "Value": "411121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174795, + "Key": "河南省漯河市临颍县", + "Value": "411122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174796, + "Key": "河南省三门峡市", + "Value": "411200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174797, + "Key": "河南省三门峡市湖滨区", + "Value": "411202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174798, + "Key": "河南省三门峡市陕州区", + "Value": "411203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174799, + "Key": "河南省三门峡市渑池县", + "Value": "411221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174800, + "Key": "河南省三门峡市卢氏县", + "Value": "411224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789174801, + "Key": "河南省三门峡市义马市", + "Value": "411281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178885, + "Key": "河南省三门峡市灵宝市", + "Value": "411282" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178886, + "Key": "河南省南阳市", + "Value": "411300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178887, + "Key": "河南省南阳市宛城区", + "Value": "411302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178888, + "Key": "河南省南阳市卧龙区", + "Value": "411303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178889, + "Key": "河南省南阳市南召县", + "Value": "411321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178890, + "Key": "河南省南阳市方城县", + "Value": "411322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178891, + "Key": "河南省南阳市西峡县", + "Value": "411323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178892, + "Key": "河南省南阳市镇平县", + "Value": "411324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178893, + "Key": "河南省南阳市内乡县", + "Value": "411325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178894, + "Key": "河南省南阳市淅川县", + "Value": "411326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178895, + "Key": "河南省南阳市社旗县", + "Value": "411327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178896, + "Key": "河南省南阳市唐河县", + "Value": "411328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789178897, + "Key": "河南省南阳市新野县", + "Value": "411329" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182981, + "Key": "河南省南阳市桐柏县", + "Value": "411330" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182982, + "Key": "河南省南阳市邓州市", + "Value": "411381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182983, + "Key": "河南省商丘市", + "Value": "411400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182984, + "Key": "河南省商丘市梁园区", + "Value": "411402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182985, + "Key": "河南省商丘市睢阳区", + "Value": "411403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182986, + "Key": "河南省商丘市民权县", + "Value": "411421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182987, + "Key": "河南省商丘市睢县", + "Value": "411422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182988, + "Key": "河南省商丘市宁陵县", + "Value": "411423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182989, + "Key": "河南省商丘市柘城县", + "Value": "411424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182990, + "Key": "河南省商丘市虞城县", + "Value": "411425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182991, + "Key": "河南省商丘市夏邑县", + "Value": "411426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789182992, + "Key": "河南省商丘市永城市", + "Value": "411481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187077, + "Key": "河南省信阳市", + "Value": "411500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187078, + "Key": "河南省信阳市浉河区", + "Value": "411502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187079, + "Key": "河南省信阳市平桥区", + "Value": "411503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187080, + "Key": "河南省信阳市罗山县", + "Value": "411521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187081, + "Key": "河南省信阳市光山县", + "Value": "411522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187082, + "Key": "河南省信阳市新县", + "Value": "411523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187083, + "Key": "河南省信阳市商城县", + "Value": "411524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187084, + "Key": "河南省信阳市固始县", + "Value": "411525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187085, + "Key": "河南省信阳市潢川县", + "Value": "411526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187086, + "Key": "河南省信阳市淮滨县", + "Value": "411527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187087, + "Key": "河南省信阳市息县", + "Value": "411528" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187088, + "Key": "河南省周口市", + "Value": "411600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789187089, + "Key": "河南省周口市川汇区", + "Value": "411602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191173, + "Key": "河南省周口市淮阳区", + "Value": "411603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191174, + "Key": "河南省周口市扶沟县", + "Value": "411621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191175, + "Key": "河南省周口市西华县", + "Value": "411622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191176, + "Key": "河南省周口市商水县", + "Value": "411623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191177, + "Key": "河南省周口市沈丘县", + "Value": "411624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191178, + "Key": "河南省周口市郸城县", + "Value": "411625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191179, + "Key": "河南省周口市太康县", + "Value": "411627" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191180, + "Key": "河南省周口市鹿邑县", + "Value": "411628" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191181, + "Key": "河南省周口市项城市", + "Value": "411681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191182, + "Key": "河南省驻马店市", + "Value": "411700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191183, + "Key": "河南省驻马店市驿城区", + "Value": "411702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191184, + "Key": "河南省驻马店市西平县", + "Value": "411721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789191185, + "Key": "河南省驻马店市上蔡县", + "Value": "411722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195269, + "Key": "河南省驻马店市平舆县", + "Value": "411723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195270, + "Key": "河南省驻马店市正阳县", + "Value": "411724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195271, + "Key": "河南省驻马店市确山县", + "Value": "411725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195272, + "Key": "河南省驻马店市泌阳县", + "Value": "411726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195273, + "Key": "河南省驻马店市汝南县", + "Value": "411727" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195274, + "Key": "河南省驻马店市遂平县", + "Value": "411728" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195275, + "Key": "河南省驻马店市新蔡县", + "Value": "411729" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195276, + "Key": "河南省济源市", + "Value": "419001" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195277, + "Key": "湖北省", + "Value": "420000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195278, + "Key": "湖北省武汉市", + "Value": "420100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195279, + "Key": "湖北省武汉市江岸区", + "Value": "420102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789195280, + "Key": "湖北省武汉市江汉区", + "Value": "420103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199365, + "Key": "湖北省武汉市硚口区", + "Value": "420104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199366, + "Key": "湖北省武汉市汉阳区", + "Value": "420105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199367, + "Key": "湖北省武汉市武昌区", + "Value": "420106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199368, + "Key": "湖北省武汉市青山区", + "Value": "420107" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199369, + "Key": "湖北省武汉市洪山区", + "Value": "420111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199370, + "Key": "湖北省武汉市东西湖区", + "Value": "420112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199371, + "Key": "湖北省武汉市汉南区", + "Value": "420113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199372, + "Key": "湖北省武汉市蔡甸区", + "Value": "420114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199373, + "Key": "湖北省武汉市江夏区", + "Value": "420115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199374, + "Key": "湖北省武汉市黄陂区", + "Value": "420116" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199375, + "Key": "湖北省武汉市新洲区", + "Value": "420117" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199376, + "Key": "湖北省黄石市", + "Value": "420200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789199377, + "Key": "湖北省黄石市黄石港区", + "Value": "420202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203461, + "Key": "湖北省黄石市西塞山区", + "Value": "420203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203462, + "Key": "湖北省黄石市下陆区", + "Value": "420204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203463, + "Key": "湖北省黄石市铁山区", + "Value": "420205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203464, + "Key": "湖北省黄石市阳新县", + "Value": "420222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203465, + "Key": "湖北省黄石市大冶市", + "Value": "420281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203466, + "Key": "湖北省十堰市", + "Value": "420300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203467, + "Key": "湖北省十堰市茅箭区", + "Value": "420302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203468, + "Key": "湖北省十堰市张湾区", + "Value": "420303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203469, + "Key": "湖北省十堰市郧阳区", + "Value": "420304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203470, + "Key": "湖北省十堰市郧西县", + "Value": "420322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203471, + "Key": "湖北省十堰市竹山县", + "Value": "420323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203472, + "Key": "湖北省十堰市竹溪县", + "Value": "420324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789203473, + "Key": "湖北省十堰市房县", + "Value": "420325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207557, + "Key": "湖北省十堰市丹江口市", + "Value": "420381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207558, + "Key": "湖北省宜昌市", + "Value": "420500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207559, + "Key": "湖北省宜昌市西陵区", + "Value": "420502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207560, + "Key": "湖北省宜昌市伍家岗区", + "Value": "420503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207561, + "Key": "湖北省宜昌市点军区", + "Value": "420504" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207562, + "Key": "湖北省宜昌市猇亭区", + "Value": "420505" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207563, + "Key": "湖北省宜昌市夷陵区", + "Value": "420506" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207564, + "Key": "湖北省宜昌市远安县", + "Value": "420525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207565, + "Key": "湖北省宜昌市兴山县", + "Value": "420526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207566, + "Key": "湖北省宜昌市秭归县", + "Value": "420527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207567, + "Key": "湖北省宜昌市长阳土家族自治县", + "Value": "420528" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207568, + "Key": "湖北省宜昌市五峰土家族自治县", + "Value": "420529" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789207569, + "Key": "湖北省宜昌市宜都市", + "Value": "420581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211653, + "Key": "湖北省宜昌市当阳市", + "Value": "420582" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211654, + "Key": "湖北省宜昌市枝江市", + "Value": "420583" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211655, + "Key": "湖北省襄阳市", + "Value": "420600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211656, + "Key": "湖北省襄阳市襄城区", + "Value": "420602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211657, + "Key": "湖北省襄阳市樊城区", + "Value": "420606" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211658, + "Key": "湖北省襄阳市襄州区", + "Value": "420607" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211659, + "Key": "湖北省襄阳市南漳县", + "Value": "420624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211660, + "Key": "湖北省襄阳市谷城县", + "Value": "420625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211661, + "Key": "湖北省襄阳市保康县", + "Value": "420626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211662, + "Key": "湖北省襄阳市老河口市", + "Value": "420682" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211663, + "Key": "湖北省襄阳市枣阳市", + "Value": "420683" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211664, + "Key": "湖北省襄阳市宜城市", + "Value": "420684" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789211665, + "Key": "湖北省鄂州市", + "Value": "420700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215749, + "Key": "湖北省鄂州市梁子湖区", + "Value": "420702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215750, + "Key": "湖北省鄂州市华容区", + "Value": "420703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215751, + "Key": "湖北省鄂州市鄂城区", + "Value": "420704" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215752, + "Key": "湖北省荆门市", + "Value": "420800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215753, + "Key": "湖北省荆门市东宝区", + "Value": "420802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215754, + "Key": "湖北省荆门市掇刀区", + "Value": "420804" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215755, + "Key": "湖北省荆门市沙洋县", + "Value": "420822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215756, + "Key": "湖北省荆门市钟祥市", + "Value": "420881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215757, + "Key": "湖北省荆门市京山市", + "Value": "420882" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215758, + "Key": "湖北省孝感市", + "Value": "420900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215759, + "Key": "湖北省孝感市孝南区", + "Value": "420902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215760, + "Key": "湖北省孝感市孝昌县", + "Value": "420921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789215761, + "Key": "湖北省孝感市大悟县", + "Value": "420922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219845, + "Key": "湖北省孝感市云梦县", + "Value": "420923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219846, + "Key": "湖北省孝感市应城市", + "Value": "420981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219847, + "Key": "湖北省孝感市安陆市", + "Value": "420982" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219848, + "Key": "湖北省孝感市汉川市", + "Value": "420984" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219849, + "Key": "湖北省荆州市", + "Value": "421000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219850, + "Key": "湖北省荆州市沙市区", + "Value": "421002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219851, + "Key": "湖北省荆州市荆州区", + "Value": "421003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219852, + "Key": "湖北省荆州市公安县", + "Value": "421022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219853, + "Key": "湖北省荆州市江陵县", + "Value": "421024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219854, + "Key": "湖北省荆州市石首市", + "Value": "421081" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219855, + "Key": "湖北省荆州市洪湖市", + "Value": "421083" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219856, + "Key": "湖北省荆州市松滋市", + "Value": "421087" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789219857, + "Key": "湖北省荆州市监利市", + "Value": "421088" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223941, + "Key": "湖北省黄冈市", + "Value": "421100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223942, + "Key": "湖北省黄冈市黄州区", + "Value": "421102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223943, + "Key": "湖北省黄冈市团风县", + "Value": "421121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223944, + "Key": "湖北省黄冈市红安县", + "Value": "421122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223945, + "Key": "湖北省黄冈市罗田县", + "Value": "421123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223946, + "Key": "湖北省黄冈市英山县", + "Value": "421124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223947, + "Key": "湖北省黄冈市浠水县", + "Value": "421125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223948, + "Key": "湖北省黄冈市蕲春县", + "Value": "421126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223949, + "Key": "湖北省黄冈市黄梅县", + "Value": "421127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223950, + "Key": "湖北省黄冈市麻城市", + "Value": "421181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223951, + "Key": "湖北省黄冈市武穴市", + "Value": "421182" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223952, + "Key": "湖北省咸宁市", + "Value": "421200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789223953, + "Key": "湖北省咸宁市咸安区", + "Value": "421202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228037, + "Key": "湖北省咸宁市嘉鱼县", + "Value": "421221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228038, + "Key": "湖北省咸宁市通城县", + "Value": "421222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228039, + "Key": "湖北省咸宁市崇阳县", + "Value": "421223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228040, + "Key": "湖北省咸宁市通山县", + "Value": "421224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228041, + "Key": "湖北省咸宁市赤壁市", + "Value": "421281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228042, + "Key": "湖北省随州市", + "Value": "421300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228043, + "Key": "湖北省随州市曾都区", + "Value": "421303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228044, + "Key": "湖北省随州市随县", + "Value": "421321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228045, + "Key": "湖北省随州市广水市", + "Value": "421381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228046, + "Key": "湖北省恩施土家族苗族自治州", + "Value": "422800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228047, + "Key": "湖北省恩施土家族苗族自治州恩施市", + "Value": "422801" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228048, + "Key": "湖北省恩施土家族苗族自治州利川市", + "Value": "422802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789228049, + "Key": "湖北省恩施土家族苗族自治州建始县", + "Value": "422822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232133, + "Key": "湖北省恩施土家族苗族自治州巴东县", + "Value": "422823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232134, + "Key": "湖北省恩施土家族苗族自治州宣恩县", + "Value": "422825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232135, + "Key": "湖北省恩施土家族苗族自治州咸丰县", + "Value": "422826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232136, + "Key": "湖北省恩施土家族苗族自治州来凤县", + "Value": "422827" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232137, + "Key": "湖北省恩施土家族苗族自治州鹤峰县", + "Value": "422828" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232138, + "Key": "湖北省仙桃市", + "Value": "429004" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232139, + "Key": "湖北省潜江市", + "Value": "429005" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232140, + "Key": "湖北省天门市", + "Value": "429006" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232141, + "Key": "湖北省神农架林区", + "Value": "429021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232142, + "Key": "湖南省", + "Value": "430000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232143, + "Key": "湖南省长沙市", + "Value": "430100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232144, + "Key": "湖南省长沙市芙蓉区", + "Value": "430102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789232145, + "Key": "湖南省长沙市天心区", + "Value": "430103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236229, + "Key": "湖南省长沙市岳麓区", + "Value": "430104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236230, + "Key": "湖南省长沙市开福区", + "Value": "430105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236231, + "Key": "湖南省长沙市雨花区", + "Value": "430111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236232, + "Key": "湖南省长沙市望城区", + "Value": "430112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236233, + "Key": "湖南省长沙市长沙县", + "Value": "430121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236234, + "Key": "湖南省长沙市浏阳市", + "Value": "430181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236235, + "Key": "湖南省长沙市宁乡市", + "Value": "430182" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236236, + "Key": "湖南省株洲市", + "Value": "430200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236237, + "Key": "湖南省株洲市荷塘区", + "Value": "430202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236238, + "Key": "湖南省株洲市芦淞区", + "Value": "430203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236239, + "Key": "湖南省株洲市石峰区", + "Value": "430204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236240, + "Key": "湖南省株洲市天元区", + "Value": "430211" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789236241, + "Key": "湖南省株洲市渌口区", + "Value": "430212" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240325, + "Key": "湖南省株洲市攸县", + "Value": "430223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240326, + "Key": "湖南省株洲市茶陵县", + "Value": "430224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240327, + "Key": "湖南省株洲市炎陵县", + "Value": "430225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240328, + "Key": "湖南省株洲市醴陵市", + "Value": "430281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240329, + "Key": "湖南省湘潭市", + "Value": "430300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240330, + "Key": "湖南省湘潭市雨湖区", + "Value": "430302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240331, + "Key": "湖南省湘潭市岳塘区", + "Value": "430304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240332, + "Key": "湖南省湘潭市湘潭县", + "Value": "430321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240333, + "Key": "湖南省湘潭市湘乡市", + "Value": "430381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240334, + "Key": "湖南省湘潭市韶山市", + "Value": "430382" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240335, + "Key": "湖南省衡阳市", + "Value": "430400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240336, + "Key": "湖南省衡阳市珠晖区", + "Value": "430405" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789240337, + "Key": "湖南省衡阳市雁峰区", + "Value": "430406" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244421, + "Key": "湖南省衡阳市石鼓区", + "Value": "430407" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244422, + "Key": "湖南省衡阳市蒸湘区", + "Value": "430408" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244423, + "Key": "湖南省衡阳市南岳区", + "Value": "430412" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244424, + "Key": "湖南省衡阳市衡阳县", + "Value": "430421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244425, + "Key": "湖南省衡阳市衡南县", + "Value": "430422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244426, + "Key": "湖南省衡阳市衡山县", + "Value": "430423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244427, + "Key": "湖南省衡阳市衡东县", + "Value": "430424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244428, + "Key": "湖南省衡阳市祁东县", + "Value": "430426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244429, + "Key": "湖南省衡阳市耒阳市", + "Value": "430481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244430, + "Key": "湖南省衡阳市常宁市", + "Value": "430482" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244431, + "Key": "湖南省邵阳市", + "Value": "430500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244432, + "Key": "湖南省邵阳市双清区", + "Value": "430502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789244433, + "Key": "湖南省邵阳市大祥区", + "Value": "430503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248517, + "Key": "湖南省邵阳市北塔区", + "Value": "430511" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248518, + "Key": "湖南省邵阳市新邵县", + "Value": "430522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248519, + "Key": "湖南省邵阳市邵阳县", + "Value": "430523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248520, + "Key": "湖南省邵阳市隆回县", + "Value": "430524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248521, + "Key": "湖南省邵阳市洞口县", + "Value": "430525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248522, + "Key": "湖南省邵阳市绥宁县", + "Value": "430527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248523, + "Key": "湖南省邵阳市新宁县", + "Value": "430528" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248524, + "Key": "湖南省邵阳市城步苗族自治县", + "Value": "430529" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248525, + "Key": "湖南省邵阳市武冈市", + "Value": "430581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248526, + "Key": "湖南省邵阳市邵东市", + "Value": "430582" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248527, + "Key": "湖南省岳阳市", + "Value": "430600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248528, + "Key": "湖南省岳阳市岳阳楼区", + "Value": "430602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789248529, + "Key": "湖南省岳阳市云溪区", + "Value": "430603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252613, + "Key": "湖南省岳阳市君山区", + "Value": "430611" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252614, + "Key": "湖南省岳阳市岳阳县", + "Value": "430621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252615, + "Key": "湖南省岳阳市华容县", + "Value": "430623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252616, + "Key": "湖南省岳阳市湘阴县", + "Value": "430624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252617, + "Key": "湖南省岳阳市平江县", + "Value": "430626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252618, + "Key": "湖南省岳阳市汨罗市", + "Value": "430681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252619, + "Key": "湖南省岳阳市临湘市", + "Value": "430682" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252620, + "Key": "湖南省常德市", + "Value": "430700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252621, + "Key": "湖南省常德市武陵区", + "Value": "430702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252622, + "Key": "湖南省常德市鼎城区", + "Value": "430703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252623, + "Key": "湖南省常德市安乡县", + "Value": "430721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252624, + "Key": "湖南省常德市汉寿县", + "Value": "430722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789252625, + "Key": "湖南省常德市澧县", + "Value": "430723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256709, + "Key": "湖南省常德市临澧县", + "Value": "430724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256710, + "Key": "湖南省常德市桃源县", + "Value": "430725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256711, + "Key": "湖南省常德市石门县", + "Value": "430726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256712, + "Key": "湖南省常德市津市市", + "Value": "430781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256713, + "Key": "湖南省张家界市", + "Value": "430800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256714, + "Key": "湖南省张家界市永定区", + "Value": "430802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256715, + "Key": "湖南省张家界市武陵源区", + "Value": "430811" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256716, + "Key": "湖南省张家界市慈利县", + "Value": "430821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256717, + "Key": "湖南省张家界市桑植县", + "Value": "430822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256718, + "Key": "湖南省益阳市", + "Value": "430900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256719, + "Key": "湖南省益阳市资阳区", + "Value": "430902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256720, + "Key": "湖南省益阳市赫山区", + "Value": "430903" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789256721, + "Key": "湖南省益阳市南县", + "Value": "430921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260805, + "Key": "湖南省益阳市桃江县", + "Value": "430922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260806, + "Key": "湖南省益阳市安化县", + "Value": "430923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260807, + "Key": "湖南省益阳市沅江市", + "Value": "430981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260808, + "Key": "湖南省郴州市", + "Value": "431000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260809, + "Key": "湖南省郴州市北湖区", + "Value": "431002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260810, + "Key": "湖南省郴州市苏仙区", + "Value": "431003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260811, + "Key": "湖南省郴州市桂阳县", + "Value": "431021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260812, + "Key": "湖南省郴州市宜章县", + "Value": "431022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260813, + "Key": "湖南省郴州市永兴县", + "Value": "431023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260814, + "Key": "湖南省郴州市嘉禾县", + "Value": "431024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260815, + "Key": "湖南省郴州市临武县", + "Value": "431025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260816, + "Key": "湖南省郴州市汝城县", + "Value": "431026" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260817, + "Key": "湖南省郴州市桂东县", + "Value": "431027" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260818, + "Key": "湖南省郴州市安仁县", + "Value": "431028" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789260819, + "Key": "湖南省郴州市资兴市", + "Value": "431081" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264901, + "Key": "湖南省永州市", + "Value": "431100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264902, + "Key": "湖南省永州市零陵区", + "Value": "431102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264903, + "Key": "湖南省永州市冷水滩区", + "Value": "431103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264904, + "Key": "湖南省永州市东安县", + "Value": "431122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264905, + "Key": "湖南省永州市双牌县", + "Value": "431123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264906, + "Key": "湖南省永州市道县", + "Value": "431124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264907, + "Key": "湖南省永州市江永县", + "Value": "431125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264908, + "Key": "湖南省永州市宁远县", + "Value": "431126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264909, + "Key": "湖南省永州市蓝山县", + "Value": "431127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264910, + "Key": "湖南省永州市新田县", + "Value": "431128" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264911, + "Key": "湖南省永州市江华瑶族自治县", + "Value": "431129" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264912, + "Key": "湖南省永州市祁阳市", + "Value": "431181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264913, + "Key": "湖南省怀化市", + "Value": "431200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789264914, + "Key": "湖南省怀化市鹤城区", + "Value": "431202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789268997, + "Key": "湖南省怀化市中方县", + "Value": "431221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789268998, + "Key": "湖南省怀化市沅陵县", + "Value": "431222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789268999, + "Key": "湖南省怀化市辰溪县", + "Value": "431223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789269000, + "Key": "湖南省怀化市溆浦县", + "Value": "431224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789269001, + "Key": "湖南省怀化市会同县", + "Value": "431225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789269002, + "Key": "湖南省怀化市麻阳苗族自治县", + "Value": "431226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789269003, + "Key": "湖南省怀化市新晃侗族自治县", + "Value": "431227" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789269004, + "Key": "湖南省怀化市芷江侗族自治县", + "Value": "431228" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789269005, + "Key": "湖南省怀化市靖州苗族侗族自治县", + "Value": "431229" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789269006, + "Key": "湖南省怀化市通道侗族自治县", + "Value": "431230" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789269007, + "Key": "湖南省怀化市洪江市", + "Value": "431281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789269008, + "Key": "湖南省娄底市", + "Value": "431300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789269009, + "Key": "湖南省娄底市娄星区", + "Value": "431302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789269010, + "Key": "湖南省娄底市双峰县", + "Value": "431321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273093, + "Key": "湖南省娄底市新化县", + "Value": "431322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273094, + "Key": "湖南省娄底市冷水江市", + "Value": "431381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273095, + "Key": "湖南省娄底市涟源市", + "Value": "431382" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273096, + "Key": "湖南省湘西土家族苗族自治州", + "Value": "433100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273097, + "Key": "湖南省湘西土家族苗族自治州吉首市", + "Value": "433101" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273098, + "Key": "湖南省湘西土家族苗族自治州泸溪县", + "Value": "433122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273099, + "Key": "湖南省湘西土家族苗族自治州凤凰县", + "Value": "433123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273100, + "Key": "湖南省湘西土家族苗族自治州花垣县", + "Value": "433124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273101, + "Key": "湖南省湘西土家族苗族自治州保靖县", + "Value": "433125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273102, + "Key": "湖南省湘西土家族苗族自治州古丈县", + "Value": "433126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273103, + "Key": "湖南省湘西土家族苗族自治州永顺县", + "Value": "433127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273104, + "Key": "湖南省湘西土家族苗族自治州龙山县", + "Value": "433130" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273105, + "Key": "广东省", + "Value": "440000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789273106, + "Key": "广东省广州市", + "Value": "440100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277189, + "Key": "广东省广州市荔湾区", + "Value": "440103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277190, + "Key": "广东省广州市越秀区", + "Value": "440104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277191, + "Key": "广东省广州市海珠区", + "Value": "440105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277192, + "Key": "广东省广州市天河区", + "Value": "440106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277193, + "Key": "广东省广州市白云区", + "Value": "440111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277194, + "Key": "广东省广州市黄埔区", + "Value": "440112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277195, + "Key": "广东省广州市番禺区", + "Value": "440113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277196, + "Key": "广东省广州市花都区", + "Value": "440114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277197, + "Key": "广东省广州市南沙区", + "Value": "440115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277198, + "Key": "广东省广州市从化区", + "Value": "440117" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277199, + "Key": "广东省广州市增城区", + "Value": "440118" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277200, + "Key": "广东省韶关市", + "Value": "440200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789277201, + "Key": "广东省韶关市武江区", + "Value": "440203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281285, + "Key": "广东省韶关市浈江区", + "Value": "440204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281286, + "Key": "广东省韶关市曲江区", + "Value": "440205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281287, + "Key": "广东省韶关市始兴县", + "Value": "440222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281288, + "Key": "广东省韶关市仁化县", + "Value": "440224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281289, + "Key": "广东省韶关市翁源县", + "Value": "440229" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281290, + "Key": "广东省韶关市乳源瑶族自治县", + "Value": "440232" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281291, + "Key": "广东省韶关市新丰县", + "Value": "440233" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281292, + "Key": "广东省韶关市乐昌市", + "Value": "440281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281293, + "Key": "广东省韶关市南雄市", + "Value": "440282" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281294, + "Key": "广东省深圳市", + "Value": "440300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281295, + "Key": "广东省深圳市罗湖区", + "Value": "440303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281296, + "Key": "广东省深圳市福田区", + "Value": "440304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789281297, + "Key": "广东省深圳市南山区", + "Value": "440305" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285381, + "Key": "广东省深圳市宝安区", + "Value": "440306" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285382, + "Key": "广东省深圳市龙岗区", + "Value": "440307" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285383, + "Key": "广东省深圳市盐田区", + "Value": "440308" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285384, + "Key": "广东省深圳市龙华区", + "Value": "440309" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285385, + "Key": "广东省深圳市坪山区", + "Value": "440310" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285386, + "Key": "广东省深圳市光明区", + "Value": "440311" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285387, + "Key": "广东省珠海市", + "Value": "440400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285388, + "Key": "广东省珠海市香洲区", + "Value": "440402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285389, + "Key": "广东省珠海市斗门区", + "Value": "440403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285390, + "Key": "广东省珠海市金湾区", + "Value": "440404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285391, + "Key": "广东省汕头市", + "Value": "440500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789285392, + "Key": "广东省汕头市龙湖区", + "Value": "440507" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289477, + "Key": "广东省汕头市金平区", + "Value": "440511" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289478, + "Key": "广东省汕头市濠江区", + "Value": "440512" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289479, + "Key": "广东省汕头市潮阳区", + "Value": "440513" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289480, + "Key": "广东省汕头市潮南区", + "Value": "440514" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289481, + "Key": "广东省汕头市澄海区", + "Value": "440515" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289482, + "Key": "广东省汕头市南澳县", + "Value": "440523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289483, + "Key": "广东省佛山市", + "Value": "440600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289484, + "Key": "广东省佛山市禅城区", + "Value": "440604" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289485, + "Key": "广东省佛山市南海区", + "Value": "440605" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289486, + "Key": "广东省佛山市顺德区", + "Value": "440606" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289487, + "Key": "广东省佛山市三水区", + "Value": "440607" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289488, + "Key": "广东省佛山市高明区", + "Value": "440608" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289489, + "Key": "广东省江门市", + "Value": "440700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789289490, + "Key": "广东省江门市蓬江区", + "Value": "440703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293573, + "Key": "广东省江门市江海区", + "Value": "440704" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293574, + "Key": "广东省江门市新会区", + "Value": "440705" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293575, + "Key": "广东省江门市台山市", + "Value": "440781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293576, + "Key": "广东省江门市开平市", + "Value": "440783" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293577, + "Key": "广东省江门市鹤山市", + "Value": "440784" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293578, + "Key": "广东省江门市恩平市", + "Value": "440785" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293579, + "Key": "广东省湛江市", + "Value": "440800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293580, + "Key": "广东省湛江市赤坎区", + "Value": "440802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293581, + "Key": "广东省湛江市霞山区", + "Value": "440803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293582, + "Key": "广东省湛江市坡头区", + "Value": "440804" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293583, + "Key": "广东省湛江市麻章区", + "Value": "440811" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293584, + "Key": "广东省湛江市遂溪县", + "Value": "440823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293585, + "Key": "广东省湛江市徐闻县", + "Value": "440825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789293586, + "Key": "广东省湛江市廉江市", + "Value": "440881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297669, + "Key": "广东省湛江市雷州市", + "Value": "440882" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297670, + "Key": "广东省湛江市吴川市", + "Value": "440883" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297671, + "Key": "广东省茂名市", + "Value": "440900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297672, + "Key": "广东省茂名市茂南区", + "Value": "440902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297673, + "Key": "广东省茂名市电白区", + "Value": "440904" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297674, + "Key": "广东省茂名市高州市", + "Value": "440981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297675, + "Key": "广东省茂名市化州市", + "Value": "440982" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297676, + "Key": "广东省茂名市信宜市", + "Value": "440983" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297677, + "Key": "广东省肇庆市", + "Value": "441200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297678, + "Key": "广东省肇庆市端州区", + "Value": "441202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297679, + "Key": "广东省肇庆市鼎湖区", + "Value": "441203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297680, + "Key": "广东省肇庆市高要区", + "Value": "441204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297681, + "Key": "广东省肇庆市广宁县", + "Value": "441223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297682, + "Key": "广东省肇庆市怀集县", + "Value": "441224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789297683, + "Key": "广东省肇庆市封开县", + "Value": "441225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301765, + "Key": "广东省肇庆市德庆县", + "Value": "441226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301766, + "Key": "广东省肇庆市四会市", + "Value": "441284" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301767, + "Key": "广东省惠州市", + "Value": "441300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301768, + "Key": "广东省惠州市惠城区", + "Value": "441302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301769, + "Key": "广东省惠州市惠阳区", + "Value": "441303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301770, + "Key": "广东省惠州市博罗县", + "Value": "441322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301771, + "Key": "广东省惠州市惠东县", + "Value": "441323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301772, + "Key": "广东省惠州市龙门县", + "Value": "441324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301773, + "Key": "广东省梅州市", + "Value": "441400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301774, + "Key": "广东省梅州市梅江区", + "Value": "441402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301775, + "Key": "广东省梅州市梅县区", + "Value": "441403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301776, + "Key": "广东省梅州市大埔县", + "Value": "441422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301777, + "Key": "广东省梅州市丰顺县", + "Value": "441423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789301778, + "Key": "广东省梅州市五华县", + "Value": "441424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305861, + "Key": "广东省梅州市平远县", + "Value": "441426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305862, + "Key": "广东省梅州市蕉岭县", + "Value": "441427" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305863, + "Key": "广东省梅州市兴宁市", + "Value": "441481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305864, + "Key": "广东省汕尾市", + "Value": "441500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305865, + "Key": "广东省汕尾市城区", + "Value": "441502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305866, + "Key": "广东省汕尾市海丰县", + "Value": "441521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305867, + "Key": "广东省汕尾市陆河县", + "Value": "441523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305868, + "Key": "广东省汕尾市陆丰市", + "Value": "441581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305869, + "Key": "广东省汕尾市河源市", + "Value": "441600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305870, + "Key": "广东省汕尾市源城区", + "Value": "441602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305871, + "Key": "广东省汕尾市紫金县", + "Value": "441621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305872, + "Key": "广东省汕尾市龙川县", + "Value": "441622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789305873, + "Key": "广东省汕尾市连平县", + "Value": "441623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309957, + "Key": "广东省汕尾市和平县", + "Value": "441624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309958, + "Key": "广东省汕尾市东源县", + "Value": "441625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309959, + "Key": "广东省阳江市", + "Value": "441700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309960, + "Key": "广东省阳江市江城区", + "Value": "441702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309961, + "Key": "广东省阳江市阳东区", + "Value": "441704" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309962, + "Key": "广东省阳江市阳西县", + "Value": "441721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309963, + "Key": "广东省阳江市阳春市", + "Value": "441781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309964, + "Key": "广东省清远市", + "Value": "441800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309965, + "Key": "广东省清远市清城区", + "Value": "441802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309966, + "Key": "广东省清远市清新区", + "Value": "441803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309967, + "Key": "广东省清远市佛冈县", + "Value": "441821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309968, + "Key": "广东省清远市阳山县", + "Value": "441823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309969, + "Key": "广东省清远市连山壮族瑶族自治县", + "Value": "441825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789309970, + "Key": "广东省清远市连南瑶族自治县", + "Value": "441826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314053, + "Key": "广东省清远市英德市", + "Value": "441881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314054, + "Key": "广东省清远市连州市", + "Value": "441882" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314055, + "Key": "广东省清远市东莞市", + "Value": "441900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314056, + "Key": "广东省清远市中山市", + "Value": "442000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314057, + "Key": "广东省潮州市", + "Value": "445100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314058, + "Key": "广东省潮州市湘桥区", + "Value": "445102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314059, + "Key": "广东省潮州市潮安区", + "Value": "445103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314060, + "Key": "广东省潮州市饶平县", + "Value": "445122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314061, + "Key": "广东省揭阳市", + "Value": "445200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314062, + "Key": "广东省揭阳市榕城区", + "Value": "445202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314063, + "Key": "广东省揭阳市揭东区", + "Value": "445203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314064, + "Key": "广东省揭阳市揭西县", + "Value": "445222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789314065, + "Key": "广东省揭阳市惠来县", + "Value": "445224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318149, + "Key": "广东省揭阳市普宁市", + "Value": "445281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318150, + "Key": "广东省云浮市", + "Value": "445300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318151, + "Key": "广东省云浮市云城区", + "Value": "445302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318152, + "Key": "广东省云浮市云安区", + "Value": "445303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318153, + "Key": "广东省云浮市新兴县", + "Value": "445321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318154, + "Key": "广东省云浮市郁南县", + "Value": "445322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318155, + "Key": "广东省云浮市罗定市", + "Value": "445381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318156, + "Key": "广西壮族自治区", + "Value": "450000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318157, + "Key": "广西壮族自治区南宁市", + "Value": "450100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318158, + "Key": "广西壮族自治区南宁市兴宁区", + "Value": "450102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318159, + "Key": "广西壮族自治区南宁市青秀区", + "Value": "450103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318160, + "Key": "广西壮族自治区南宁市江南区", + "Value": "450105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318161, + "Key": "广西壮族自治区南宁市西乡塘区", + "Value": "450107" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789318162, + "Key": "广西壮族自治区南宁市良庆区", + "Value": "450108" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322245, + "Key": "广西壮族自治区南宁市邕宁区", + "Value": "450109" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322246, + "Key": "广西壮族自治区南宁市武鸣区", + "Value": "450110" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322247, + "Key": "广西壮族自治区南宁市隆安县", + "Value": "450123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322248, + "Key": "广西壮族自治区南宁市马山县", + "Value": "450124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322249, + "Key": "广西壮族自治区南宁市上林县", + "Value": "450125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322250, + "Key": "广西壮族自治区南宁市宾阳县", + "Value": "450126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322251, + "Key": "广西壮族自治区南宁市横州市", + "Value": "450181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322252, + "Key": "广西壮族自治区柳州市", + "Value": "450200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322253, + "Key": "广西壮族自治区柳州市城中区", + "Value": "450202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322254, + "Key": "广西壮族自治区柳州市鱼峰区", + "Value": "450203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322255, + "Key": "广西壮族自治区柳州市柳南区", + "Value": "450204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322256, + "Key": "广西壮族自治区柳州市柳北区", + "Value": "450205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789322257, + "Key": "广西壮族自治区柳州市柳江区", + "Value": "450206" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326341, + "Key": "广西壮族自治区柳州市柳城县", + "Value": "450222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326342, + "Key": "广西壮族自治区柳州市鹿寨县", + "Value": "450223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326343, + "Key": "广西壮族自治区柳州市融安县", + "Value": "450224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326344, + "Key": "广西壮族自治区柳州市融水苗族自治县", + "Value": "450225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326345, + "Key": "广西壮族自治区柳州市三江侗族自治县", + "Value": "450226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326346, + "Key": "广西壮族自治区桂林市", + "Value": "450300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326347, + "Key": "广西壮族自治区桂林市秀峰区", + "Value": "450302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326348, + "Key": "广西壮族自治区桂林市叠彩区", + "Value": "450303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326349, + "Key": "广西壮族自治区桂林市象山区", + "Value": "450304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326350, + "Key": "广西壮族自治区桂林市七星区", + "Value": "450305" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326351, + "Key": "广西壮族自治区桂林市雁山区", + "Value": "450311" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326352, + "Key": "广西壮族自治区桂林市临桂区", + "Value": "450312" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326353, + "Key": "广西壮族自治区桂林市阳朔县", + "Value": "450321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789326354, + "Key": "广西壮族自治区桂林市灵川县", + "Value": "450323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330437, + "Key": "广西壮族自治区桂林市全州县", + "Value": "450324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330438, + "Key": "广西壮族自治区桂林市兴安县", + "Value": "450325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330439, + "Key": "广西壮族自治区桂林市永福县", + "Value": "450326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330440, + "Key": "广西壮族自治区桂林市灌阳县", + "Value": "450327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330441, + "Key": "广西壮族自治区桂林市龙胜各族自治县", + "Value": "450328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330442, + "Key": "广西壮族自治区桂林市资源县", + "Value": "450329" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330443, + "Key": "广西壮族自治区桂林市平乐县", + "Value": "450330" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330444, + "Key": "广西壮族自治区桂林市恭城瑶族自治县", + "Value": "450332" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330445, + "Key": "广西壮族自治区桂林市荔浦市", + "Value": "450381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330446, + "Key": "广西壮族自治区梧州市", + "Value": "450400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330447, + "Key": "广西壮族自治区梧州市万秀区", + "Value": "450403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330448, + "Key": "广西壮族自治区梧州市长洲区", + "Value": "450405" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330449, + "Key": "广西壮族自治区梧州市龙圩区", + "Value": "450406" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789330450, + "Key": "广西壮族自治区梧州市苍梧县", + "Value": "450421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334533, + "Key": "广西壮族自治区梧州市藤县", + "Value": "450422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334534, + "Key": "广西壮族自治区梧州市蒙山县", + "Value": "450423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334535, + "Key": "广西壮族自治区梧州市岑溪市", + "Value": "450481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334536, + "Key": "广西壮族自治区北海市", + "Value": "450500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334537, + "Key": "广西壮族自治区北海市海城区", + "Value": "450502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334538, + "Key": "广西壮族自治区北海市银海区", + "Value": "450503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334539, + "Key": "广西壮族自治区北海市铁山港区", + "Value": "450512" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334540, + "Key": "广西壮族自治区北海市合浦县", + "Value": "450521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334541, + "Key": "广西壮族自治区防城港市", + "Value": "450600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334542, + "Key": "广西壮族自治区防城港市港口区", + "Value": "450602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334543, + "Key": "广西壮族自治区防城港市防城区", + "Value": "450603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334544, + "Key": "广西壮族自治区防城港市上思县", + "Value": "450621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334545, + "Key": "广西壮族自治区防城港市东兴市", + "Value": "450681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789334546, + "Key": "广西壮族自治区钦州市", + "Value": "450700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338629, + "Key": "广西壮族自治区钦州市钦南区", + "Value": "450702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338630, + "Key": "广西壮族自治区钦州市钦北区", + "Value": "450703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338631, + "Key": "广西壮族自治区钦州市灵山县", + "Value": "450721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338632, + "Key": "广西壮族自治区钦州市浦北县", + "Value": "450722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338633, + "Key": "广西壮族自治区贵港市", + "Value": "450800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338634, + "Key": "广西壮族自治区贵港市港北区", + "Value": "450802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338635, + "Key": "广西壮族自治区贵港市港南区", + "Value": "450803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338636, + "Key": "广西壮族自治区贵港市覃塘区", + "Value": "450804" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338637, + "Key": "广西壮族自治区贵港市平南县", + "Value": "450821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338638, + "Key": "广西壮族自治区贵港市桂平市", + "Value": "450881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338639, + "Key": "广西壮族自治区玉林市", + "Value": "450900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338640, + "Key": "广西壮族自治区玉林市玉州区", + "Value": "450902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338641, + "Key": "广西壮族自治区玉林市福绵区", + "Value": "450903" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789338642, + "Key": "广西壮族自治区玉林市容县", + "Value": "450921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342725, + "Key": "广西壮族自治区玉林市陆川县", + "Value": "450922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342726, + "Key": "广西壮族自治区玉林市博白县", + "Value": "450923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342727, + "Key": "广西壮族自治区玉林市兴业县", + "Value": "450924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342728, + "Key": "广西壮族自治区玉林市北流市", + "Value": "450981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342729, + "Key": "广西壮族自治区百色市", + "Value": "451000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342730, + "Key": "广西壮族自治区百色市右江区", + "Value": "451002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342731, + "Key": "广西壮族自治区百色市田阳区", + "Value": "451003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342732, + "Key": "广西壮族自治区百色市田东县", + "Value": "451022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342733, + "Key": "广西壮族自治区百色市德保县", + "Value": "451024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342734, + "Key": "广西壮族自治区百色市那坡县", + "Value": "451026" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342735, + "Key": "广西壮族自治区百色市凌云县", + "Value": "451027" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342736, + "Key": "广西壮族自治区百色市乐业县", + "Value": "451028" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342737, + "Key": "广西壮族自治区百色市田林县", + "Value": "451029" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342738, + "Key": "广西壮族自治区百色市西林县", + "Value": "451030" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789342739, + "Key": "广西壮族自治区百色市隆林各族自治县", + "Value": "451031" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346821, + "Key": "广西壮族自治区百色市靖西市", + "Value": "451081" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346822, + "Key": "广西壮族自治区百色市平果市", + "Value": "451082" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346823, + "Key": "广西壮族自治区贺州市", + "Value": "451100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346824, + "Key": "广西壮族自治区贺州市八步区", + "Value": "451102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346825, + "Key": "广西壮族自治区贺州市平桂区", + "Value": "451103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346826, + "Key": "广西壮族自治区贺州市昭平县", + "Value": "451121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346827, + "Key": "广西壮族自治区贺州市钟山县", + "Value": "451122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346828, + "Key": "广西壮族自治区贺州市富川瑶族自治县", + "Value": "451123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346829, + "Key": "广西壮族自治区河池市", + "Value": "451200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346830, + "Key": "广西壮族自治区河池市金城江区", + "Value": "451202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346831, + "Key": "广西壮族自治区河池市宜州区", + "Value": "451203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346832, + "Key": "广西壮族自治区河池市南丹县", + "Value": "451221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346833, + "Key": "广西壮族自治区河池市天峨县", + "Value": "451222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789346834, + "Key": "广西壮族自治区河池市凤山县", + "Value": "451223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350917, + "Key": "广西壮族自治区河池市东兰县", + "Value": "451224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350918, + "Key": "广西壮族自治区河池市罗城仫佬族自治县", + "Value": "451225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350919, + "Key": "广西壮族自治区河池市环江毛南族自治县", + "Value": "451226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350920, + "Key": "广西壮族自治区河池市巴马瑶族自治县", + "Value": "451227" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350921, + "Key": "广西壮族自治区河池市都安瑶族自治县", + "Value": "451228" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350922, + "Key": "广西壮族自治区河池市大化瑶族自治县", + "Value": "451229" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350923, + "Key": "广西壮族自治区来宾市", + "Value": "451300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350924, + "Key": "广西壮族自治区来宾市兴宾区", + "Value": "451302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350925, + "Key": "广西壮族自治区来宾市忻城县", + "Value": "451321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350926, + "Key": "广西壮族自治区来宾市象州县", + "Value": "451322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350927, + "Key": "广西壮族自治区来宾市武宣县", + "Value": "451323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350928, + "Key": "广西壮族自治区来宾市金秀瑶族自治县", + "Value": "451324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350929, + "Key": "广西壮族自治区来宾市合山市", + "Value": "451381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789350930, + "Key": "广西壮族自治区崇左市", + "Value": "451400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355013, + "Key": "广西壮族自治区崇左市江州区", + "Value": "451402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355014, + "Key": "广西壮族自治区崇左市扶绥县", + "Value": "451421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355015, + "Key": "广西壮族自治区崇左市宁明县", + "Value": "451422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355016, + "Key": "广西壮族自治区崇左市龙州县", + "Value": "451423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355017, + "Key": "广西壮族自治区崇左市大新县", + "Value": "451424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355018, + "Key": "广西壮族自治区崇左市天等县", + "Value": "451425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355019, + "Key": "广西壮族自治区崇左市凭祥市", + "Value": "451481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355020, + "Key": "海南省", + "Value": "460000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355021, + "Key": "海南省海口市", + "Value": "460100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355022, + "Key": "海南省海口市秀英区", + "Value": "460105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355023, + "Key": "海南省海口市龙华区", + "Value": "460106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355024, + "Key": "海南省海口市琼山区", + "Value": "460107" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355025, + "Key": "海南省海口市美兰区", + "Value": "460108" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355026, + "Key": "海南省三亚市", + "Value": "460200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789355027, + "Key": "海南省三亚市海棠区", + "Value": "460202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359109, + "Key": "海南省三亚市吉阳区", + "Value": "460203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359110, + "Key": "海南省三亚市天涯区", + "Value": "460204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359111, + "Key": "海南省三亚市崖州区", + "Value": "460205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359112, + "Key": "海南省三亚市三沙市", + "Value": "460300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359113, + "Key": "海南省三亚市儋州市", + "Value": "460400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359114, + "Key": "海南省五指山市", + "Value": "469001" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359115, + "Key": "海南省琼海市", + "Value": "469002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359116, + "Key": "海南省文昌市", + "Value": "469005" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359117, + "Key": "海南省万宁市", + "Value": "469006" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359118, + "Key": "海南省东方市", + "Value": "469007" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359119, + "Key": "海南省定安县", + "Value": "469021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359120, + "Key": "海南省屯昌县", + "Value": "469022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359121, + "Key": "海南省澄迈县", + "Value": "469023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789359122, + "Key": "海南省临高县", + "Value": "469024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363205, + "Key": "海南省白沙黎族自治县", + "Value": "469025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363206, + "Key": "海南省昌江黎族自治县", + "Value": "469026" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363207, + "Key": "海南省乐东黎族自治县", + "Value": "469027" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363208, + "Key": "海南省陵水黎族自治县", + "Value": "469028" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363209, + "Key": "海南省保亭黎族苗族自治县", + "Value": "469029" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363210, + "Key": "海南省琼中黎族苗族自治县", + "Value": "469030" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363211, + "Key": "重庆市", + "Value": "500000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363212, + "Key": "重庆市万州区", + "Value": "500101" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363213, + "Key": "重庆市涪陵区", + "Value": "500102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363214, + "Key": "重庆市渝中区", + "Value": "500103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363215, + "Key": "重庆市大渡口区", + "Value": "500104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363216, + "Key": "重庆市江北区", + "Value": "500105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363217, + "Key": "重庆市沙坪坝区", + "Value": "500106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789363218, + "Key": "重庆市九龙坡区", + "Value": "500107" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367301, + "Key": "重庆市南岸区", + "Value": "500108" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367302, + "Key": "重庆市北碚区", + "Value": "500109" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367303, + "Key": "重庆市綦江区", + "Value": "500110" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367304, + "Key": "重庆市大足区", + "Value": "500111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367305, + "Key": "重庆市渝北区", + "Value": "500112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367306, + "Key": "重庆市巴南区", + "Value": "500113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367307, + "Key": "重庆市黔江区", + "Value": "500114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367308, + "Key": "重庆市长寿区", + "Value": "500115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367309, + "Key": "重庆市江津区", + "Value": "500116" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367310, + "Key": "重庆市合川区", + "Value": "500117" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367311, + "Key": "重庆市永川区", + "Value": "500118" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367312, + "Key": "重庆市南川区", + "Value": "500119" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367313, + "Key": "重庆市璧山区", + "Value": "500120" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367314, + "Key": "重庆市铜梁区", + "Value": "500151" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789367315, + "Key": "重庆市潼南区", + "Value": "500152" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371397, + "Key": "重庆市荣昌区", + "Value": "500153" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371398, + "Key": "重庆市开州区", + "Value": "500154" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371399, + "Key": "重庆市梁平区", + "Value": "500155" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371400, + "Key": "重庆市武隆区", + "Value": "500156" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371401, + "Key": "重庆市城口县", + "Value": "500229" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371402, + "Key": "重庆市丰都县", + "Value": "500230" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371403, + "Key": "重庆市垫江县", + "Value": "500231" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371404, + "Key": "重庆市忠县", + "Value": "500233" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371405, + "Key": "重庆市云阳县", + "Value": "500235" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371406, + "Key": "重庆市奉节县", + "Value": "500236" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371407, + "Key": "重庆市巫山县", + "Value": "500237" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371408, + "Key": "重庆市巫溪县", + "Value": "500238" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371409, + "Key": "重庆市石柱土家族自治县", + "Value": "500240" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789371410, + "Key": "重庆市秀山土家族苗族自治县", + "Value": "500241" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375493, + "Key": "重庆市酉阳土家族苗族自治县", + "Value": "500242" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375494, + "Key": "重庆市彭水苗族土家族自治县", + "Value": "500243" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375495, + "Key": "四川省", + "Value": "510000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375496, + "Key": "四川省成都市", + "Value": "510100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375497, + "Key": "四川省成都市锦江区", + "Value": "510104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375498, + "Key": "四川省成都市青羊区", + "Value": "510105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375499, + "Key": "四川省成都市金牛区", + "Value": "510106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375500, + "Key": "四川省成都市武侯区", + "Value": "510107" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375501, + "Key": "四川省成都市成华区", + "Value": "510108" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375502, + "Key": "四川省成都市龙泉驿区", + "Value": "510112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375503, + "Key": "四川省成都市青白江区", + "Value": "510113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375504, + "Key": "四川省成都市新都区", + "Value": "510114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375505, + "Key": "四川省成都市温江区", + "Value": "510115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789375506, + "Key": "四川省成都市双流区", + "Value": "510116" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379589, + "Key": "四川省成都市郫都区", + "Value": "510117" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379590, + "Key": "四川省成都市新津区", + "Value": "510118" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379591, + "Key": "四川省成都市金堂县", + "Value": "510121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379592, + "Key": "四川省成都市大邑县", + "Value": "510129" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379593, + "Key": "四川省成都市蒲江县", + "Value": "510131" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379594, + "Key": "四川省成都市都江堰市", + "Value": "510181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379595, + "Key": "四川省成都市彭州市", + "Value": "510182" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379596, + "Key": "四川省成都市邛崃市", + "Value": "510183" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379597, + "Key": "四川省成都市崇州市", + "Value": "510184" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379598, + "Key": "四川省成都市简阳市", + "Value": "510185" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379599, + "Key": "四川省自贡市", + "Value": "510300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379600, + "Key": "四川省自贡市自流井区", + "Value": "510302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789379601, + "Key": "四川省自贡市贡井区", + "Value": "510303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383685, + "Key": "四川省自贡市大安区", + "Value": "510304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383686, + "Key": "四川省自贡市沿滩区", + "Value": "510311" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383687, + "Key": "四川省自贡市荣县", + "Value": "510321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383688, + "Key": "四川省自贡市富顺县", + "Value": "510322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383689, + "Key": "四川省攀枝花市", + "Value": "510400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383690, + "Key": "四川省攀枝花市东区", + "Value": "510402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383691, + "Key": "四川省攀枝花市西区", + "Value": "510403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383692, + "Key": "四川省攀枝花市仁和区", + "Value": "510411" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383693, + "Key": "四川省攀枝花市米易县", + "Value": "510421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383694, + "Key": "四川省攀枝花市盐边县", + "Value": "510422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383695, + "Key": "四川省泸州市", + "Value": "510500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383696, + "Key": "四川省泸州市江阳区", + "Value": "510502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789383697, + "Key": "四川省泸州市纳溪区", + "Value": "510503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387781, + "Key": "四川省泸州市龙马潭区", + "Value": "510504" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387782, + "Key": "四川省泸州市泸县", + "Value": "510521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387783, + "Key": "四川省泸州市合江县", + "Value": "510522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387784, + "Key": "四川省泸州市叙永县", + "Value": "510524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387785, + "Key": "四川省泸州市古蔺县", + "Value": "510525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387786, + "Key": "四川省德阳市", + "Value": "510600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387787, + "Key": "四川省德阳市旌阳区", + "Value": "510603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387788, + "Key": "四川省德阳市罗江区", + "Value": "510604" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387789, + "Key": "四川省德阳市中江县", + "Value": "510623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387790, + "Key": "四川省德阳市广汉市", + "Value": "510681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387791, + "Key": "四川省德阳市什邡市", + "Value": "510682" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387792, + "Key": "四川省德阳市绵竹市", + "Value": "510683" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387793, + "Key": "四川省绵阳市", + "Value": "510700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789387794, + "Key": "四川省绵阳市涪城区", + "Value": "510703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391877, + "Key": "四川省绵阳市游仙区", + "Value": "510704" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391878, + "Key": "四川省绵阳市安州区", + "Value": "510705" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391879, + "Key": "四川省绵阳市三台县", + "Value": "510722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391880, + "Key": "四川省绵阳市盐亭县", + "Value": "510723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391881, + "Key": "四川省绵阳市梓潼县", + "Value": "510725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391882, + "Key": "四川省绵阳市北川羌族自治县", + "Value": "510726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391883, + "Key": "四川省绵阳市平武县", + "Value": "510727" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391884, + "Key": "四川省绵阳市江油市", + "Value": "510781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391885, + "Key": "四川省广元市", + "Value": "510800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391886, + "Key": "四川省广元市利州区", + "Value": "510802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391887, + "Key": "四川省广元市昭化区", + "Value": "510811" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391888, + "Key": "四川省广元市朝天区", + "Value": "510812" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391889, + "Key": "四川省广元市旺苍县", + "Value": "510821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789391890, + "Key": "四川省广元市青川县", + "Value": "510822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395973, + "Key": "四川省广元市剑阁县", + "Value": "510823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395974, + "Key": "四川省广元市苍溪县", + "Value": "510824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395975, + "Key": "四川省遂宁市", + "Value": "510900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395976, + "Key": "四川省遂宁市船山区", + "Value": "510903" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395977, + "Key": "四川省遂宁市安居区", + "Value": "510904" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395978, + "Key": "四川省遂宁市蓬溪县", + "Value": "510921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395979, + "Key": "四川省遂宁市大英县", + "Value": "510923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395980, + "Key": "四川省遂宁市射洪市", + "Value": "510981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395981, + "Key": "四川省内江市", + "Value": "511000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395982, + "Key": "四川省内江市市中区", + "Value": "511002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395983, + "Key": "四川省内江市东兴区", + "Value": "511011" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395984, + "Key": "四川省内江市威远县", + "Value": "511024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395985, + "Key": "四川省内江市资中县", + "Value": "511025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789395986, + "Key": "四川省内江市隆昌市", + "Value": "511083" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400069, + "Key": "四川省乐山市", + "Value": "511100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400070, + "Key": "四川省乐山市市中区", + "Value": "511102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400071, + "Key": "四川省乐山市沙湾区", + "Value": "511111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400072, + "Key": "四川省乐山市五通桥区", + "Value": "511112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400073, + "Key": "四川省乐山市金口河区", + "Value": "511113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400074, + "Key": "四川省乐山市犍为县", + "Value": "511123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400075, + "Key": "四川省乐山市井研县", + "Value": "511124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400076, + "Key": "四川省乐山市夹江县", + "Value": "511126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400077, + "Key": "四川省乐山市沐川县", + "Value": "511129" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400078, + "Key": "四川省乐山市峨边彝族自治县", + "Value": "511132" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400079, + "Key": "四川省乐山市马边彝族自治县", + "Value": "511133" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400080, + "Key": "四川省乐山市峨眉山市", + "Value": "511181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400081, + "Key": "四川省南充市", + "Value": "511300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789400082, + "Key": "四川省南充市顺庆区", + "Value": "511302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404165, + "Key": "四川省南充市高坪区", + "Value": "511303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404166, + "Key": "四川省南充市嘉陵区", + "Value": "511304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404167, + "Key": "四川省南充市南部县", + "Value": "511321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404168, + "Key": "四川省南充市营山县", + "Value": "511322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404169, + "Key": "四川省南充市蓬安县", + "Value": "511323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404170, + "Key": "四川省南充市仪陇县", + "Value": "511324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404171, + "Key": "四川省南充市西充县", + "Value": "511325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404172, + "Key": "四川省南充市阆中市", + "Value": "511381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404173, + "Key": "四川省眉山市", + "Value": "511400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404174, + "Key": "四川省眉山市东坡区", + "Value": "511402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404175, + "Key": "四川省眉山市彭山区", + "Value": "511403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404176, + "Key": "四川省眉山市仁寿县", + "Value": "511421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404177, + "Key": "四川省眉山市洪雅县", + "Value": "511423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789404178, + "Key": "四川省眉山市丹棱县", + "Value": "511424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408261, + "Key": "四川省眉山市青神县", + "Value": "511425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408262, + "Key": "四川省宜宾市", + "Value": "511500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408263, + "Key": "四川省宜宾市翠屏区", + "Value": "511502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408264, + "Key": "四川省宜宾市南溪区", + "Value": "511503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408265, + "Key": "四川省宜宾市叙州区", + "Value": "511504" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408266, + "Key": "四川省宜宾市江安县", + "Value": "511523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408267, + "Key": "四川省宜宾市长宁县", + "Value": "511524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408268, + "Key": "四川省宜宾市高县", + "Value": "511525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408269, + "Key": "四川省宜宾市珙县", + "Value": "511526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408270, + "Key": "四川省宜宾市筠连县", + "Value": "511527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408271, + "Key": "四川省宜宾市兴文县", + "Value": "511528" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408272, + "Key": "四川省宜宾市屏山县", + "Value": "511529" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408273, + "Key": "四川省广安市", + "Value": "511600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789408274, + "Key": "四川省广安市广安区", + "Value": "511602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412357, + "Key": "四川省广安市前锋区", + "Value": "511603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412358, + "Key": "四川省广安市岳池县", + "Value": "511621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412359, + "Key": "四川省广安市武胜县", + "Value": "511622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412360, + "Key": "四川省广安市邻水县", + "Value": "511623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412361, + "Key": "四川省广安市华蓥市", + "Value": "511681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412362, + "Key": "四川省达州市", + "Value": "511700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412363, + "Key": "四川省达州市通川区", + "Value": "511702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412364, + "Key": "四川省达州市达川区", + "Value": "511703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412365, + "Key": "四川省达州市宣汉县", + "Value": "511722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412366, + "Key": "四川省达州市开江县", + "Value": "511723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412367, + "Key": "四川省达州市大竹县", + "Value": "511724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412368, + "Key": "四川省达州市渠县", + "Value": "511725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412369, + "Key": "四川省达州市万源市", + "Value": "511781" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789412370, + "Key": "四川省雅安市", + "Value": "511800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416453, + "Key": "四川省雅安市雨城区", + "Value": "511802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416454, + "Key": "四川省雅安市名山区", + "Value": "511803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416455, + "Key": "四川省雅安市荥经县", + "Value": "511822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416456, + "Key": "四川省雅安市汉源县", + "Value": "511823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416457, + "Key": "四川省雅安市石棉县", + "Value": "511824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416458, + "Key": "四川省雅安市天全县", + "Value": "511825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416459, + "Key": "四川省雅安市芦山县", + "Value": "511826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416460, + "Key": "四川省雅安市宝兴县", + "Value": "511827" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416461, + "Key": "四川省巴中市", + "Value": "511900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416462, + "Key": "四川省巴中市巴州区", + "Value": "511902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416463, + "Key": "四川省巴中市恩阳区", + "Value": "511903" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416464, + "Key": "四川省巴中市通江县", + "Value": "511921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416465, + "Key": "四川省巴中市南江县", + "Value": "511922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789416466, + "Key": "四川省巴中市平昌县", + "Value": "511923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420549, + "Key": "四川省资阳市", + "Value": "512000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420550, + "Key": "四川省资阳市雁江区", + "Value": "512002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420551, + "Key": "四川省资阳市安岳县", + "Value": "512021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420552, + "Key": "四川省资阳市乐至县", + "Value": "512022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420553, + "Key": "四川省阿坝藏族羌族自治州", + "Value": "513200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420554, + "Key": "四川省阿坝藏族羌族自治州马尔康市", + "Value": "513201" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420555, + "Key": "四川省阿坝藏族羌族自治州汶川县", + "Value": "513221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420556, + "Key": "四川省阿坝藏族羌族自治州理县", + "Value": "513222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420557, + "Key": "四川省阿坝藏族羌族自治州茂县", + "Value": "513223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420558, + "Key": "四川省阿坝藏族羌族自治州松潘县", + "Value": "513224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420559, + "Key": "四川省阿坝藏族羌族自治州九寨沟县", + "Value": "513225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420560, + "Key": "四川省阿坝藏族羌族自治州金川县", + "Value": "513226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420561, + "Key": "四川省阿坝藏族羌族自治州小金县", + "Value": "513227" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420562, + "Key": "四川省阿坝藏族羌族自治州黑水县", + "Value": "513228" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789420563, + "Key": "四川省阿坝藏族羌族自治州壤塘县", + "Value": "513230" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424645, + "Key": "四川省阿坝藏族羌族自治州阿坝县", + "Value": "513231" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424646, + "Key": "四川省阿坝藏族羌族自治州若尔盖县", + "Value": "513232" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424647, + "Key": "四川省阿坝藏族羌族自治州红原县", + "Value": "513233" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424648, + "Key": "四川省甘孜藏族自治州", + "Value": "513300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424649, + "Key": "四川省甘孜藏族自治州康定市", + "Value": "513301" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424650, + "Key": "四川省甘孜藏族自治州泸定县", + "Value": "513322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424651, + "Key": "四川省甘孜藏族自治州丹巴县", + "Value": "513323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424652, + "Key": "四川省甘孜藏族自治州九龙县", + "Value": "513324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424653, + "Key": "四川省甘孜藏族自治州雅江县", + "Value": "513325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424654, + "Key": "四川省甘孜藏族自治州道孚县", + "Value": "513326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424655, + "Key": "四川省甘孜藏族自治州炉霍县", + "Value": "513327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424656, + "Key": "四川省甘孜藏族自治州甘孜县", + "Value": "513328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789424657, + "Key": "四川省甘孜藏族自治州新龙县", + "Value": "513329" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428741, + "Key": "四川省甘孜藏族自治州德格县", + "Value": "513330" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428742, + "Key": "四川省甘孜藏族自治州白玉县", + "Value": "513331" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428743, + "Key": "四川省甘孜藏族自治州石渠县", + "Value": "513332" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428744, + "Key": "四川省甘孜藏族自治州色达县", + "Value": "513333" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428745, + "Key": "四川省甘孜藏族自治州理塘县", + "Value": "513334" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428746, + "Key": "四川省甘孜藏族自治州巴塘县", + "Value": "513335" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428747, + "Key": "四川省甘孜藏族自治州乡城县", + "Value": "513336" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428748, + "Key": "四川省甘孜藏族自治州稻城县", + "Value": "513337" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428749, + "Key": "四川省甘孜藏族自治州得荣县", + "Value": "513338" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428750, + "Key": "四川省凉山彝族自治州", + "Value": "513400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428751, + "Key": "四川省凉山彝族自治州西昌市", + "Value": "513401" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428752, + "Key": "四川省凉山彝族自治州会理市", + "Value": "513402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428753, + "Key": "四川省凉山彝族自治州木里藏族自治县", + "Value": "513422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428754, + "Key": "四川省凉山彝族自治州盐源县", + "Value": "513423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789428755, + "Key": "四川省凉山彝族自治州德昌县", + "Value": "513424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432837, + "Key": "四川省凉山彝族自治州会东县", + "Value": "513426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432838, + "Key": "四川省凉山彝族自治州宁南县", + "Value": "513427" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432839, + "Key": "四川省凉山彝族自治州普格县", + "Value": "513428" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432840, + "Key": "四川省凉山彝族自治州布拖县", + "Value": "513429" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432841, + "Key": "四川省凉山彝族自治州金阳县", + "Value": "513430" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432842, + "Key": "四川省凉山彝族自治州昭觉县", + "Value": "513431" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432843, + "Key": "四川省凉山彝族自治州喜德县", + "Value": "513432" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432844, + "Key": "四川省凉山彝族自治州冕宁县", + "Value": "513433" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432845, + "Key": "四川省凉山彝族自治州越西县", + "Value": "513434" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432846, + "Key": "四川省凉山彝族自治州甘洛县", + "Value": "513435" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432847, + "Key": "四川省凉山彝族自治州美姑县", + "Value": "513436" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432848, + "Key": "四川省凉山彝族自治州雷波县", + "Value": "513437" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432849, + "Key": "贵州省", + "Value": "520000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789432850, + "Key": "贵州省贵阳市", + "Value": "520100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436933, + "Key": "贵州省贵阳市南明区", + "Value": "520102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436934, + "Key": "贵州省贵阳市云岩区", + "Value": "520103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436935, + "Key": "贵州省贵阳市花溪区", + "Value": "520111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436936, + "Key": "贵州省贵阳市乌当区", + "Value": "520112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436937, + "Key": "贵州省贵阳市白云区", + "Value": "520113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436938, + "Key": "贵州省贵阳市观山湖区", + "Value": "520115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436939, + "Key": "贵州省贵阳市开阳县", + "Value": "520121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436940, + "Key": "贵州省贵阳市息烽县", + "Value": "520122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436941, + "Key": "贵州省贵阳市修文县", + "Value": "520123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436942, + "Key": "贵州省贵阳市清镇市", + "Value": "520181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436943, + "Key": "贵州省六盘水市", + "Value": "520200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789436944, + "Key": "贵州省六盘水市钟山区", + "Value": "520201" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789441029, + "Key": "贵州省六盘水市六枝特区", + "Value": "520203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789441030, + "Key": "贵州省六盘水市水城区", + "Value": "520204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789441031, + "Key": "贵州省六盘水市盘州市", + "Value": "520281" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789441032, + "Key": "贵州省遵义市", + "Value": "520300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789441033, + "Key": "贵州省遵义市红花岗区", + "Value": "520302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789441034, + "Key": "贵州省遵义市汇川区", + "Value": "520303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789441035, + "Key": "贵州省遵义市播州区", + "Value": "520304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789441036, + "Key": "贵州省遵义市桐梓县", + "Value": "520322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789441037, + "Key": "贵州省遵义市绥阳县", + "Value": "520323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445125, + "Key": "贵州省遵义市正安县", + "Value": "520324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445126, + "Key": "贵州省遵义市道真仡佬族苗族自治县", + "Value": "520325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445127, + "Key": "贵州省遵义市务川仡佬族苗族自治县", + "Value": "520326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445128, + "Key": "贵州省遵义市凤冈县", + "Value": "520327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445129, + "Key": "贵州省遵义市湄潭县", + "Value": "520328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445130, + "Key": "贵州省遵义市余庆县", + "Value": "520329" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445131, + "Key": "贵州省遵义市习水县", + "Value": "520330" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445132, + "Key": "贵州省遵义市赤水市", + "Value": "520381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445133, + "Key": "贵州省遵义市仁怀市", + "Value": "520382" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445134, + "Key": "贵州省安顺市", + "Value": "520400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445135, + "Key": "贵州省安顺市西秀区", + "Value": "520402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445136, + "Key": "贵州省安顺市平坝区", + "Value": "520403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789445137, + "Key": "贵州省安顺市普定县", + "Value": "520422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449221, + "Key": "贵州省安顺市镇宁布依族苗族自治县", + "Value": "520423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449222, + "Key": "贵州省安顺市关岭布依族苗族自治县", + "Value": "520424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449223, + "Key": "贵州省安顺市紫云苗族布依族自治县", + "Value": "520425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449224, + "Key": "贵州省毕节市", + "Value": "520500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449225, + "Key": "贵州省毕节市七星关区", + "Value": "520502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449226, + "Key": "贵州省毕节市大方县", + "Value": "520521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449227, + "Key": "贵州省毕节市金沙县", + "Value": "520523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449228, + "Key": "贵州省毕节市织金县", + "Value": "520524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449229, + "Key": "贵州省毕节市纳雍县", + "Value": "520525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449230, + "Key": "贵州省毕节市威宁彝族回族苗族自治县", + "Value": "520526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449231, + "Key": "贵州省毕节市赫章县", + "Value": "520527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449232, + "Key": "贵州省毕节市黔西市", + "Value": "520581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449233, + "Key": "贵州省铜仁市", + "Value": "520600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789449234, + "Key": "贵州省铜仁市碧江区", + "Value": "520602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453317, + "Key": "贵州省铜仁市万山区", + "Value": "520603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453318, + "Key": "贵州省铜仁市江口县", + "Value": "520621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453319, + "Key": "贵州省铜仁市玉屏侗族自治县", + "Value": "520622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453320, + "Key": "贵州省铜仁市石阡县", + "Value": "520623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453321, + "Key": "贵州省铜仁市思南县", + "Value": "520624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453322, + "Key": "贵州省铜仁市印江土家族苗族自治县", + "Value": "520625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453323, + "Key": "贵州省铜仁市德江县", + "Value": "520626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453324, + "Key": "贵州省铜仁市沿河土家族自治县", + "Value": "520627" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453325, + "Key": "贵州省铜仁市松桃苗族自治县", + "Value": "520628" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453326, + "Key": "贵州省黔西南布依族苗族自治州", + "Value": "522300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453327, + "Key": "贵州省黔西南布依族苗族自治州兴义市", + "Value": "522301" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453328, + "Key": "贵州省黔西南布依族苗族自治州兴仁市", + "Value": "522302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789453329, + "Key": "贵州省黔西南布依族苗族自治州普安县", + "Value": "522323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457413, + "Key": "贵州省黔西南布依族苗族自治州晴隆县", + "Value": "522324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457414, + "Key": "贵州省黔西南布依族苗族自治州贞丰县", + "Value": "522325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457415, + "Key": "贵州省黔西南布依族苗族自治州望谟县", + "Value": "522326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457416, + "Key": "贵州省黔西南布依族苗族自治州册亨县", + "Value": "522327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457417, + "Key": "贵州省黔西南布依族苗族自治州安龙县", + "Value": "522328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457418, + "Key": "贵州省黔东南苗族侗族自治州", + "Value": "522600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457419, + "Key": "贵州省黔东南苗族侗族自治州凯里市", + "Value": "522601" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457420, + "Key": "贵州省黔东南苗族侗族自治州黄平县", + "Value": "522622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457421, + "Key": "贵州省黔东南苗族侗族自治州施秉县", + "Value": "522623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457422, + "Key": "贵州省黔东南苗族侗族自治州三穗县", + "Value": "522624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457423, + "Key": "贵州省黔东南苗族侗族自治州镇远县", + "Value": "522625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457424, + "Key": "贵州省黔东南苗族侗族自治州岑巩县", + "Value": "522626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457425, + "Key": "贵州省黔东南苗族侗族自治州天柱县", + "Value": "522627" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789457426, + "Key": "贵州省黔东南苗族侗族自治州锦屏县", + "Value": "522628" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461509, + "Key": "贵州省黔东南苗族侗族自治州剑河县", + "Value": "522629" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461510, + "Key": "贵州省黔东南苗族侗族自治州台江县", + "Value": "522630" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461511, + "Key": "贵州省黔东南苗族侗族自治州黎平县", + "Value": "522631" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461512, + "Key": "贵州省黔东南苗族侗族自治州榕江县", + "Value": "522632" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461513, + "Key": "贵州省黔东南苗族侗族自治州从江县", + "Value": "522633" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461514, + "Key": "贵州省黔东南苗族侗族自治州雷山县", + "Value": "522634" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461515, + "Key": "贵州省黔东南苗族侗族自治州麻江县", + "Value": "522635" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461516, + "Key": "贵州省黔东南苗族侗族自治州丹寨县", + "Value": "522636" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461517, + "Key": "贵州省黔南布依族苗族自治州", + "Value": "522700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461518, + "Key": "贵州省黔南布依族苗族自治州都匀市", + "Value": "522701" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461519, + "Key": "贵州省黔南布依族苗族自治州福泉市", + "Value": "522702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461520, + "Key": "贵州省黔南布依族苗族自治州荔波县", + "Value": "522722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789461521, + "Key": "贵州省黔南布依族苗族自治州贵定县", + "Value": "522723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465605, + "Key": "贵州省黔南布依族苗族自治州瓮安县", + "Value": "522725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465606, + "Key": "贵州省黔南布依族苗族自治州独山县", + "Value": "522726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465607, + "Key": "贵州省黔南布依族苗族自治州平塘县", + "Value": "522727" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465608, + "Key": "贵州省黔南布依族苗族自治州罗甸县", + "Value": "522728" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465609, + "Key": "贵州省黔南布依族苗族自治州长顺县", + "Value": "522729" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465610, + "Key": "贵州省黔南布依族苗族自治州龙里县", + "Value": "522730" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465611, + "Key": "贵州省黔南布依族苗族自治州惠水县", + "Value": "522731" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465612, + "Key": "贵州省黔南布依族苗族自治州三都水族自治县", + "Value": "522732" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465613, + "Key": "云南省", + "Value": "530000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465614, + "Key": "云南省昆明市", + "Value": "530100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465615, + "Key": "云南省昆明市五华区", + "Value": "530102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465616, + "Key": "云南省昆明市盘龙区", + "Value": "530103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465617, + "Key": "云南省昆明市官渡区", + "Value": "530111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789465618, + "Key": "云南省昆明市西山区", + "Value": "530112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469701, + "Key": "云南省昆明市东川区", + "Value": "530113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469702, + "Key": "云南省昆明市呈贡区", + "Value": "530114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469703, + "Key": "云南省昆明市晋宁区", + "Value": "530115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469704, + "Key": "云南省昆明市富民县", + "Value": "530124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469705, + "Key": "云南省昆明市宜良县", + "Value": "530125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469706, + "Key": "云南省昆明市石林彝族自治县", + "Value": "530126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469707, + "Key": "云南省昆明市嵩明县", + "Value": "530127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469708, + "Key": "云南省昆明市禄劝彝族苗族自治县", + "Value": "530128" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469709, + "Key": "云南省昆明市寻甸回族彝族自治县", + "Value": "530129" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469710, + "Key": "云南省昆明市安宁市", + "Value": "530181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469711, + "Key": "云南省曲靖市", + "Value": "530300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469712, + "Key": "云南省曲靖市麒麟区", + "Value": "530302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789469713, + "Key": "云南省曲靖市沾益区", + "Value": "530303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789473797, + "Key": "云南省曲靖市马龙区", + "Value": "530304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789473798, + "Key": "云南省曲靖市陆良县", + "Value": "530322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789473799, + "Key": "云南省曲靖市师宗县", + "Value": "530323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789473800, + "Key": "云南省曲靖市罗平县", + "Value": "530324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789473801, + "Key": "云南省曲靖市富源县", + "Value": "530325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789473802, + "Key": "云南省曲靖市会泽县", + "Value": "530326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789473803, + "Key": "云南省曲靖市宣威市", + "Value": "530381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789473804, + "Key": "云南省玉溪市", + "Value": "530400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789473805, + "Key": "云南省玉溪市红塔区", + "Value": "530402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789473806, + "Key": "云南省玉溪市江川区", + "Value": "530403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789473807, + "Key": "云南省玉溪市通海县", + "Value": "530423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477893, + "Key": "云南省玉溪市华宁县", + "Value": "530424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477894, + "Key": "云南省玉溪市易门县", + "Value": "530425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477895, + "Key": "云南省玉溪市峨山彝族自治县", + "Value": "530426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477896, + "Key": "云南省玉溪市新平彝族傣族自治县", + "Value": "530427" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477897, + "Key": "云南省玉溪市元江哈尼族彝族傣族自治县", + "Value": "530428" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477898, + "Key": "云南省玉溪市澄江市", + "Value": "530481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477899, + "Key": "云南省保山市", + "Value": "530500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477900, + "Key": "云南省保山市隆阳区", + "Value": "530502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477901, + "Key": "云南省保山市施甸县", + "Value": "530521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477902, + "Key": "云南省保山市龙陵县", + "Value": "530523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477903, + "Key": "云南省保山市昌宁县", + "Value": "530524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477904, + "Key": "云南省保山市腾冲市", + "Value": "530581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477905, + "Key": "云南省昭通市", + "Value": "530600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789477906, + "Key": "云南省昭通市昭阳区", + "Value": "530602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789481989, + "Key": "云南省昭通市鲁甸县", + "Value": "530621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789481990, + "Key": "云南省昭通市巧家县", + "Value": "530622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789481991, + "Key": "云南省昭通市盐津县", + "Value": "530623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789481992, + "Key": "云南省昭通市大关县", + "Value": "530624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789481993, + "Key": "云南省昭通市永善县", + "Value": "530625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789481994, + "Key": "云南省昭通市绥江县", + "Value": "530626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789481995, + "Key": "云南省昭通市镇雄县", + "Value": "530627" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789481996, + "Key": "云南省昭通市彝良县", + "Value": "530628" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789481997, + "Key": "云南省昭通市威信县", + "Value": "530629" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789481998, + "Key": "云南省昭通市水富市", + "Value": "530681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789481999, + "Key": "云南省丽江市", + "Value": "530700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789482000, + "Key": "云南省丽江市古城区", + "Value": "530702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789482001, + "Key": "云南省丽江市玉龙纳西族自治县", + "Value": "530721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789482002, + "Key": "云南省丽江市永胜县", + "Value": "530722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486085, + "Key": "云南省丽江市华坪县", + "Value": "530723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486086, + "Key": "云南省丽江市宁蒗彝族自治县", + "Value": "530724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486087, + "Key": "云南省普洱市", + "Value": "530800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486088, + "Key": "云南省普洱市思茅区", + "Value": "530802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486089, + "Key": "云南省普洱市宁洱哈尼族彝族自治县", + "Value": "530821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486090, + "Key": "云南省普洱市墨江哈尼族自治县", + "Value": "530822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486091, + "Key": "云南省普洱市景东彝族自治县", + "Value": "530823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486092, + "Key": "云南省普洱市景谷傣族彝族自治县", + "Value": "530824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486093, + "Key": "云南省普洱市镇沅彝族哈尼族拉祜族自治县", + "Value": "530825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486094, + "Key": "云南省普洱市江城哈尼族彝族自治县", + "Value": "530826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486095, + "Key": "云南省普洱市孟连傣族拉祜族佤族自治县", + "Value": "530827" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486096, + "Key": "云南省普洱市澜沧拉祜族自治县", + "Value": "530828" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486097, + "Key": "云南省普洱市西盟佤族自治县", + "Value": "530829" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789486098, + "Key": "云南省临沧市", + "Value": "530900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490181, + "Key": "云南省临沧市临翔区", + "Value": "530902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490182, + "Key": "云南省临沧市凤庆县", + "Value": "530921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490183, + "Key": "云南省临沧市云县", + "Value": "530922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490184, + "Key": "云南省临沧市永德县", + "Value": "530923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490185, + "Key": "云南省临沧市镇康县", + "Value": "530924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490186, + "Key": "云南省临沧市双江拉祜族佤族布朗族傣族自治县", + "Value": "530925" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490187, + "Key": "云南省临沧市耿马傣族佤族自治县", + "Value": "530926" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490188, + "Key": "云南省临沧市沧源佤族自治县", + "Value": "530927" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490189, + "Key": "云南省楚雄彝族自治州", + "Value": "532300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490190, + "Key": "云南省楚雄彝族自治州楚雄市", + "Value": "532301" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490191, + "Key": "云南省楚雄彝族自治州禄丰市", + "Value": "532302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490192, + "Key": "云南省楚雄彝族自治州双柏县", + "Value": "532322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490193, + "Key": "云南省楚雄彝族自治州牟定县", + "Value": "532323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789490194, + "Key": "云南省楚雄彝族自治州南华县", + "Value": "532324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494277, + "Key": "云南省楚雄彝族自治州姚安县", + "Value": "532325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494278, + "Key": "云南省楚雄彝族自治州大姚县", + "Value": "532326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494279, + "Key": "云南省楚雄彝族自治州永仁县", + "Value": "532327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494280, + "Key": "云南省楚雄彝族自治州元谋县", + "Value": "532328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494281, + "Key": "云南省楚雄彝族自治州武定县", + "Value": "532329" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494282, + "Key": "云南省红河哈尼族彝族自治州", + "Value": "532500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494283, + "Key": "云南省红河哈尼族彝族自治州个旧市", + "Value": "532501" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494284, + "Key": "云南省红河哈尼族彝族自治州开远市", + "Value": "532502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494285, + "Key": "云南省红河哈尼族彝族自治州蒙自市", + "Value": "532503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494286, + "Key": "云南省红河哈尼族彝族自治州弥勒市", + "Value": "532504" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494287, + "Key": "云南省红河哈尼族彝族自治州屏边苗族自治县", + "Value": "532523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494288, + "Key": "云南省红河哈尼族彝族自治州建水县", + "Value": "532524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494289, + "Key": "云南省红河哈尼族彝族自治州石屏县", + "Value": "532525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494290, + "Key": "云南省红河哈尼族彝族自治州泸西县", + "Value": "532527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789494291, + "Key": "云南省红河哈尼族彝族自治州元阳县", + "Value": "532528" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498373, + "Key": "云南省红河哈尼族彝族自治州红河县", + "Value": "532529" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498374, + "Key": "云南省红河哈尼族彝族自治州金平苗族瑶族傣族自治县", + "Value": "532530" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498375, + "Key": "云南省红河哈尼族彝族自治州绿春县", + "Value": "532531" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498376, + "Key": "云南省红河哈尼族彝族自治州河口瑶族自治县", + "Value": "532532" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498377, + "Key": "云南省文山壮族苗族自治州", + "Value": "532600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498378, + "Key": "云南省文山壮族苗族自治州文山市", + "Value": "532601" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498379, + "Key": "云南省文山壮族苗族自治州砚山县", + "Value": "532622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498380, + "Key": "云南省文山壮族苗族自治州西畴县", + "Value": "532623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498381, + "Key": "云南省文山壮族苗族自治州麻栗坡县", + "Value": "532624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498382, + "Key": "云南省文山壮族苗族自治州马关县", + "Value": "532625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498383, + "Key": "云南省文山壮族苗族自治州丘北县", + "Value": "532626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498384, + "Key": "云南省文山壮族苗族自治州广南县", + "Value": "532627" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498385, + "Key": "云南省文山壮族苗族自治州富宁县", + "Value": "532628" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789498386, + "Key": "云南省西双版纳傣族自治州", + "Value": "532800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502469, + "Key": "云南省西双版纳傣族自治州景洪市", + "Value": "532801" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502470, + "Key": "云南省西双版纳傣族自治州勐海县", + "Value": "532822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502471, + "Key": "云南省西双版纳傣族自治州勐腊县", + "Value": "532823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502472, + "Key": "云南省大理白族自治州", + "Value": "532900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502473, + "Key": "云南省大理白族自治州大理市", + "Value": "532901" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502474, + "Key": "云南省大理白族自治州漾濞彝族自治县", + "Value": "532922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502475, + "Key": "云南省大理白族自治州祥云县", + "Value": "532923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502476, + "Key": "云南省大理白族自治州宾川县", + "Value": "532924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502477, + "Key": "云南省大理白族自治州弥渡县", + "Value": "532925" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502478, + "Key": "云南省大理白族自治州南涧彝族自治县", + "Value": "532926" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502479, + "Key": "云南省大理白族自治州巍山彝族回族自治县", + "Value": "532927" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502480, + "Key": "云南省大理白族自治州永平县", + "Value": "532928" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502481, + "Key": "云南省大理白族自治州云龙县", + "Value": "532929" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789502482, + "Key": "云南省大理白族自治州洱源县", + "Value": "532930" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506565, + "Key": "云南省大理白族自治州剑川县", + "Value": "532931" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506566, + "Key": "云南省大理白族自治州鹤庆县", + "Value": "532932" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506567, + "Key": "云南省德宏傣族景颇族自治州", + "Value": "533100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506568, + "Key": "云南省德宏傣族景颇族自治州瑞丽市", + "Value": "533102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506569, + "Key": "云南省德宏傣族景颇族自治州芒市", + "Value": "533103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506570, + "Key": "云南省德宏傣族景颇族自治州梁河县", + "Value": "533122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506571, + "Key": "云南省德宏傣族景颇族自治州盈江县", + "Value": "533123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506572, + "Key": "云南省德宏傣族景颇族自治州陇川县", + "Value": "533124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506573, + "Key": "云南省怒江傈僳族自治州", + "Value": "533300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506574, + "Key": "云南省怒江傈僳族自治州泸水市", + "Value": "533301" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506575, + "Key": "云南省怒江傈僳族自治州福贡县", + "Value": "533323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506576, + "Key": "云南省怒江傈僳族自治州贡山独龙族怒族自治县", + "Value": "533324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506577, + "Key": "云南省怒江傈僳族自治州兰坪白族普米族自治县", + "Value": "533325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789506578, + "Key": "云南省迪庆藏族自治州", + "Value": "533400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510661, + "Key": "云南省迪庆藏族自治州香格里拉市", + "Value": "533401" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510662, + "Key": "云南省迪庆藏族自治州德钦县", + "Value": "533422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510663, + "Key": "云南省迪庆藏族自治州维西傈僳族自治县", + "Value": "533423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510664, + "Key": "西藏自治区", + "Value": "540000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510665, + "Key": "西藏自治区拉萨市", + "Value": "540100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510666, + "Key": "西藏自治区拉萨市城关区", + "Value": "540102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510667, + "Key": "西藏自治区拉萨市堆龙德庆区", + "Value": "540103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510668, + "Key": "西藏自治区拉萨市达孜区", + "Value": "540104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510669, + "Key": "西藏自治区拉萨市林周县", + "Value": "540121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510670, + "Key": "西藏自治区拉萨市当雄县", + "Value": "540122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510671, + "Key": "西藏自治区拉萨市尼木县", + "Value": "540123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510672, + "Key": "西藏自治区拉萨市曲水县", + "Value": "540124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510673, + "Key": "西藏自治区拉萨市墨竹工卡县", + "Value": "540127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789510674, + "Key": "西藏自治区日喀则市", + "Value": "540200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514757, + "Key": "西藏自治区日喀则市桑珠孜区", + "Value": "540202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514758, + "Key": "西藏自治区日喀则市南木林县", + "Value": "540221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514759, + "Key": "西藏自治区日喀则市江孜县", + "Value": "540222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514760, + "Key": "西藏自治区日喀则市定日县", + "Value": "540223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514761, + "Key": "西藏自治区日喀则市萨迦县", + "Value": "540224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514762, + "Key": "西藏自治区日喀则市拉孜县", + "Value": "540225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514763, + "Key": "西藏自治区日喀则市昂仁县", + "Value": "540226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514764, + "Key": "西藏自治区日喀则市谢通门县", + "Value": "540227" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514765, + "Key": "西藏自治区日喀则市白朗县", + "Value": "540228" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514766, + "Key": "西藏自治区日喀则市仁布县", + "Value": "540229" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514767, + "Key": "西藏自治区日喀则市康马县", + "Value": "540230" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514768, + "Key": "西藏自治区日喀则市定结县", + "Value": "540231" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514769, + "Key": "西藏自治区日喀则市仲巴县", + "Value": "540232" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514770, + "Key": "西藏自治区日喀则市亚东县", + "Value": "540233" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789514771, + "Key": "西藏自治区日喀则市吉隆县", + "Value": "540234" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789518853, + "Key": "西藏自治区日喀则市聂拉木县", + "Value": "540235" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789518854, + "Key": "西藏自治区日喀则市萨嘎县", + "Value": "540236" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789518855, + "Key": "西藏自治区日喀则市岗巴县", + "Value": "540237" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789518856, + "Key": "西藏自治区昌都市", + "Value": "540300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789518857, + "Key": "西藏自治区昌都市卡若区", + "Value": "540302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789518858, + "Key": "西藏自治区昌都市江达县", + "Value": "540321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789518859, + "Key": "西藏自治区昌都市贡觉县", + "Value": "540322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789518860, + "Key": "西藏自治区昌都市类乌齐县", + "Value": "540323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789518861, + "Key": "西藏自治区昌都市丁青县", + "Value": "540324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789518862, + "Key": "西藏自治区昌都市察雅县", + "Value": "540325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789518863, + "Key": "西藏自治区昌都市八宿县", + "Value": "540326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789522949, + "Key": "西藏自治区昌都市左贡县", + "Value": "540327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789522950, + "Key": "西藏自治区昌都市芒康县", + "Value": "540328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789522951, + "Key": "西藏自治区昌都市洛隆县", + "Value": "540329" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789522952, + "Key": "西藏自治区昌都市边坝县", + "Value": "540330" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789522953, + "Key": "西藏自治区林芝市", + "Value": "540400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789522954, + "Key": "西藏自治区林芝市巴宜区", + "Value": "540402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789522955, + "Key": "西藏自治区林芝市工布江达县", + "Value": "540421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789522956, + "Key": "西藏自治区林芝市米林县", + "Value": "540422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789522957, + "Key": "西藏自治区林芝市墨脱县", + "Value": "540423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789522958, + "Key": "西藏自治区林芝市波密县", + "Value": "540424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789522959, + "Key": "西藏自治区林芝市察隅县", + "Value": "540425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527045, + "Key": "西藏自治区林芝市朗县", + "Value": "540426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527046, + "Key": "西藏自治区山南市", + "Value": "540500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527047, + "Key": "西藏自治区山南市乃东区", + "Value": "540502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527048, + "Key": "西藏自治区山南市扎囊县", + "Value": "540521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527049, + "Key": "西藏自治区山南市贡嘎县", + "Value": "540522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527050, + "Key": "西藏自治区山南市桑日县", + "Value": "540523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527051, + "Key": "西藏自治区山南市琼结县", + "Value": "540524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527052, + "Key": "西藏自治区山南市曲松县", + "Value": "540525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527053, + "Key": "西藏自治区山南市措美县", + "Value": "540526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527054, + "Key": "西藏自治区山南市洛扎县", + "Value": "540527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527055, + "Key": "西藏自治区山南市加查县", + "Value": "540528" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527056, + "Key": "西藏自治区山南市隆子县", + "Value": "540529" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527057, + "Key": "西藏自治区山南市错那县", + "Value": "540530" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527058, + "Key": "西藏自治区山南市浪卡子县", + "Value": "540531" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789527059, + "Key": "西藏自治区那曲市", + "Value": "540600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531141, + "Key": "西藏自治区那曲市色尼区", + "Value": "540602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531142, + "Key": "西藏自治区那曲市嘉黎县", + "Value": "540621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531143, + "Key": "西藏自治区那曲市比如县", + "Value": "540622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531144, + "Key": "西藏自治区那曲市聂荣县", + "Value": "540623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531145, + "Key": "西藏自治区那曲市安多县", + "Value": "540624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531146, + "Key": "西藏自治区那曲市申扎县", + "Value": "540625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531147, + "Key": "西藏自治区那曲市索县", + "Value": "540626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531148, + "Key": "西藏自治区那曲市班戈县", + "Value": "540627" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531149, + "Key": "西藏自治区那曲市巴青县", + "Value": "540628" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531150, + "Key": "西藏自治区那曲市尼玛县", + "Value": "540629" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531151, + "Key": "西藏自治区那曲市双湖县", + "Value": "540630" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531152, + "Key": "西藏自治区阿里地区", + "Value": "542500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531153, + "Key": "西藏自治区阿里地区普兰县", + "Value": "542521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789531154, + "Key": "西藏自治区阿里地区札达县", + "Value": "542522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535237, + "Key": "西藏自治区阿里地区噶尔县", + "Value": "542523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535238, + "Key": "西藏自治区阿里地区日土县", + "Value": "542524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535239, + "Key": "西藏自治区阿里地区革吉县", + "Value": "542525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535240, + "Key": "西藏自治区阿里地区改则县", + "Value": "542526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535241, + "Key": "西藏自治区阿里地区措勤县", + "Value": "542527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535242, + "Key": "陕西省", + "Value": "610000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535243, + "Key": "陕西省西安市", + "Value": "610100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535244, + "Key": "陕西省西安市新城区", + "Value": "610102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535245, + "Key": "陕西省西安市碑林区", + "Value": "610103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535246, + "Key": "陕西省西安市莲湖区", + "Value": "610104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535247, + "Key": "陕西省西安市灞桥区", + "Value": "610111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789535248, + "Key": "陕西省西安市未央区", + "Value": "610112" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539333, + "Key": "陕西省西安市雁塔区", + "Value": "610113" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539334, + "Key": "陕西省西安市阎良区", + "Value": "610114" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539335, + "Key": "陕西省西安市临潼区", + "Value": "610115" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539336, + "Key": "陕西省西安市长安区", + "Value": "610116" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539337, + "Key": "陕西省西安市高陵区", + "Value": "610117" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539338, + "Key": "陕西省西安市鄠邑区", + "Value": "610118" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539339, + "Key": "陕西省西安市蓝田县", + "Value": "610122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539340, + "Key": "陕西省西安市周至县", + "Value": "610124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539341, + "Key": "陕西省铜川市", + "Value": "610200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539342, + "Key": "陕西省铜川市王益区", + "Value": "610202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539343, + "Key": "陕西省铜川市印台区", + "Value": "610203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539344, + "Key": "陕西省铜川市耀州区", + "Value": "610204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539345, + "Key": "陕西省铜川市宜君县", + "Value": "610222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789539346, + "Key": "陕西省宝鸡市", + "Value": "610300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543429, + "Key": "陕西省宝鸡市渭滨区", + "Value": "610302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543430, + "Key": "陕西省宝鸡市金台区", + "Value": "610303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543431, + "Key": "陕西省宝鸡市陈仓区", + "Value": "610304" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543432, + "Key": "陕西省宝鸡市凤翔区", + "Value": "610305" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543433, + "Key": "陕西省宝鸡市岐山县", + "Value": "610323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543434, + "Key": "陕西省宝鸡市扶风县", + "Value": "610324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543435, + "Key": "陕西省宝鸡市眉县", + "Value": "610326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543436, + "Key": "陕西省宝鸡市陇县", + "Value": "610327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543437, + "Key": "陕西省宝鸡市千阳县", + "Value": "610328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543438, + "Key": "陕西省宝鸡市麟游县", + "Value": "610329" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543439, + "Key": "陕西省宝鸡市凤县", + "Value": "610330" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543440, + "Key": "陕西省宝鸡市太白县", + "Value": "610331" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543441, + "Key": "陕西省咸阳市", + "Value": "610400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543442, + "Key": "陕西省咸阳市秦都区", + "Value": "610402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789543443, + "Key": "陕西省咸阳市杨陵区", + "Value": "610403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547525, + "Key": "陕西省咸阳市渭城区", + "Value": "610404" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547526, + "Key": "陕西省咸阳市三原县", + "Value": "610422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547527, + "Key": "陕西省咸阳市泾阳县", + "Value": "610423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547528, + "Key": "陕西省咸阳市乾县", + "Value": "610424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547529, + "Key": "陕西省咸阳市礼泉县", + "Value": "610425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547530, + "Key": "陕西省咸阳市永寿县", + "Value": "610426" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547531, + "Key": "陕西省咸阳市长武县", + "Value": "610428" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547532, + "Key": "陕西省咸阳市旬邑县", + "Value": "610429" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547533, + "Key": "陕西省咸阳市淳化县", + "Value": "610430" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547534, + "Key": "陕西省咸阳市武功县", + "Value": "610431" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547535, + "Key": "陕西省咸阳市兴平市", + "Value": "610481" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547536, + "Key": "陕西省咸阳市彬州市", + "Value": "610482" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547537, + "Key": "陕西省渭南市", + "Value": "610500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789547538, + "Key": "陕西省渭南市临渭区", + "Value": "610502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551621, + "Key": "陕西省渭南市华州区", + "Value": "610503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551622, + "Key": "陕西省渭南市潼关县", + "Value": "610522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551623, + "Key": "陕西省渭南市大荔县", + "Value": "610523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551624, + "Key": "陕西省渭南市合阳县", + "Value": "610524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551625, + "Key": "陕西省渭南市澄城县", + "Value": "610525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551626, + "Key": "陕西省渭南市蒲城县", + "Value": "610526" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551627, + "Key": "陕西省渭南市白水县", + "Value": "610527" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551628, + "Key": "陕西省渭南市富平县", + "Value": "610528" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551629, + "Key": "陕西省渭南市韩城市", + "Value": "610581" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551630, + "Key": "陕西省渭南市华阴市", + "Value": "610582" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551631, + "Key": "陕西省延安市", + "Value": "610600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551632, + "Key": "陕西省延安市宝塔区", + "Value": "610602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551633, + "Key": "陕西省延安市安塞区", + "Value": "610603" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789551634, + "Key": "陕西省延安市延长县", + "Value": "610621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555717, + "Key": "陕西省延安市延川县", + "Value": "610622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555718, + "Key": "陕西省延安市志丹县", + "Value": "610625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555719, + "Key": "陕西省延安市吴起县", + "Value": "610626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555720, + "Key": "陕西省延安市甘泉县", + "Value": "610627" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555721, + "Key": "陕西省延安市富县", + "Value": "610628" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555722, + "Key": "陕西省延安市洛川县", + "Value": "610629" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555723, + "Key": "陕西省延安市宜川县", + "Value": "610630" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555724, + "Key": "陕西省延安市黄龙县", + "Value": "610631" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555725, + "Key": "陕西省延安市黄陵县", + "Value": "610632" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555726, + "Key": "陕西省延安市子长市", + "Value": "610681" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555727, + "Key": "陕西省汉中市", + "Value": "610700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555728, + "Key": "陕西省汉中市汉台区", + "Value": "610702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555729, + "Key": "陕西省汉中市南郑区", + "Value": "610703" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789555730, + "Key": "陕西省汉中市城固县", + "Value": "610722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559813, + "Key": "陕西省汉中市洋县", + "Value": "610723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559814, + "Key": "陕西省汉中市西乡县", + "Value": "610724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559815, + "Key": "陕西省汉中市勉县", + "Value": "610725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559816, + "Key": "陕西省汉中市宁强县", + "Value": "610726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559817, + "Key": "陕西省汉中市略阳县", + "Value": "610727" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559818, + "Key": "陕西省汉中市镇巴县", + "Value": "610728" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559819, + "Key": "陕西省汉中市留坝县", + "Value": "610729" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559820, + "Key": "陕西省汉中市佛坪县", + "Value": "610730" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559821, + "Key": "陕西省榆林市", + "Value": "610800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559822, + "Key": "陕西省榆林市榆阳区", + "Value": "610802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559823, + "Key": "陕西省榆林市横山区", + "Value": "610803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559824, + "Key": "陕西省榆林市府谷县", + "Value": "610822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559825, + "Key": "陕西省榆林市靖边县", + "Value": "610824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789559826, + "Key": "陕西省榆林市定边县", + "Value": "610825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563909, + "Key": "陕西省榆林市绥德县", + "Value": "610826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563910, + "Key": "陕西省榆林市米脂县", + "Value": "610827" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563911, + "Key": "陕西省榆林市佳县", + "Value": "610828" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563912, + "Key": "陕西省榆林市吴堡县", + "Value": "610829" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563913, + "Key": "陕西省榆林市清涧县", + "Value": "610830" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563914, + "Key": "陕西省榆林市子洲县", + "Value": "610831" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563915, + "Key": "陕西省榆林市神木市", + "Value": "610881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563916, + "Key": "陕西省安康市", + "Value": "610900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563917, + "Key": "陕西省安康市汉滨区", + "Value": "610902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563918, + "Key": "陕西省安康市汉阴县", + "Value": "610921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563919, + "Key": "陕西省安康市石泉县", + "Value": "610922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563920, + "Key": "陕西省安康市宁陕县", + "Value": "610923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563921, + "Key": "陕西省安康市紫阳县", + "Value": "610924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563922, + "Key": "陕西省安康市岚皋县", + "Value": "610925" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789563923, + "Key": "陕西省安康市平利县", + "Value": "610926" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568005, + "Key": "陕西省安康市镇坪县", + "Value": "610927" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568006, + "Key": "陕西省安康市白河县", + "Value": "610929" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568007, + "Key": "陕西省安康市旬阳市", + "Value": "610981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568008, + "Key": "陕西省商洛市", + "Value": "611000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568009, + "Key": "陕西省商洛市商州区", + "Value": "611002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568010, + "Key": "陕西省商洛市洛南县", + "Value": "611021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568011, + "Key": "陕西省商洛市丹凤县", + "Value": "611022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568012, + "Key": "陕西省商洛市商南县", + "Value": "611023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568013, + "Key": "陕西省商洛市山阳县", + "Value": "611024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568014, + "Key": "陕西省商洛市镇安县", + "Value": "611025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568015, + "Key": "陕西省商洛市柞水县", + "Value": "611026" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568016, + "Key": "甘肃省", + "Value": "620000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568017, + "Key": "甘肃省兰州市", + "Value": "620100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789568018, + "Key": "甘肃省兰州市城关区", + "Value": "620102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572101, + "Key": "甘肃省兰州市七里河区", + "Value": "620103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572102, + "Key": "甘肃省兰州市西固区", + "Value": "620104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572103, + "Key": "甘肃省兰州市安宁区", + "Value": "620105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572104, + "Key": "甘肃省兰州市红古区", + "Value": "620111" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572105, + "Key": "甘肃省兰州市永登县", + "Value": "620121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572106, + "Key": "甘肃省兰州市皋兰县", + "Value": "620122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572107, + "Key": "甘肃省兰州市榆中县", + "Value": "620123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572108, + "Key": "甘肃省兰州市嘉峪关市", + "Value": "620200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572109, + "Key": "甘肃省金昌市", + "Value": "620300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572110, + "Key": "甘肃省金昌市金川区", + "Value": "620302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572111, + "Key": "甘肃省金昌市永昌县", + "Value": "620321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572112, + "Key": "甘肃省白银市", + "Value": "620400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572113, + "Key": "甘肃省白银市白银区", + "Value": "620402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789572114, + "Key": "甘肃省白银市平川区", + "Value": "620403" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576197, + "Key": "甘肃省白银市靖远县", + "Value": "620421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576198, + "Key": "甘肃省白银市会宁县", + "Value": "620422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576199, + "Key": "甘肃省白银市景泰县", + "Value": "620423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576200, + "Key": "甘肃省天水市", + "Value": "620500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576201, + "Key": "甘肃省天水市秦州区", + "Value": "620502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576202, + "Key": "甘肃省天水市麦积区", + "Value": "620503" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576203, + "Key": "甘肃省天水市清水县", + "Value": "620521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576204, + "Key": "甘肃省天水市秦安县", + "Value": "620522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576205, + "Key": "甘肃省天水市甘谷县", + "Value": "620523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576206, + "Key": "甘肃省天水市武山县", + "Value": "620524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576207, + "Key": "甘肃省天水市张家川回族自治县", + "Value": "620525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576208, + "Key": "甘肃省武威市", + "Value": "620600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576209, + "Key": "甘肃省武威市凉州区", + "Value": "620602" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576210, + "Key": "甘肃省武威市民勤县", + "Value": "620621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789576211, + "Key": "甘肃省武威市古浪县", + "Value": "620622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580293, + "Key": "甘肃省武威市天祝藏族自治县", + "Value": "620623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580294, + "Key": "甘肃省张掖市", + "Value": "620700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580295, + "Key": "甘肃省张掖市甘州区", + "Value": "620702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580296, + "Key": "甘肃省张掖市肃南裕固族自治县", + "Value": "620721" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580297, + "Key": "甘肃省张掖市民乐县", + "Value": "620722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580298, + "Key": "甘肃省张掖市临泽县", + "Value": "620723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580299, + "Key": "甘肃省张掖市高台县", + "Value": "620724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580300, + "Key": "甘肃省张掖市山丹县", + "Value": "620725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580301, + "Key": "甘肃省平凉市", + "Value": "620800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580302, + "Key": "甘肃省平凉市崆峒区", + "Value": "620802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580303, + "Key": "甘肃省平凉市泾川县", + "Value": "620821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580304, + "Key": "甘肃省平凉市灵台县", + "Value": "620822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580305, + "Key": "甘肃省平凉市崇信县", + "Value": "620823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789580306, + "Key": "甘肃省平凉市庄浪县", + "Value": "620825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584389, + "Key": "甘肃省平凉市静宁县", + "Value": "620826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584390, + "Key": "甘肃省平凉市华亭市", + "Value": "620881" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584391, + "Key": "甘肃省酒泉市", + "Value": "620900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584392, + "Key": "甘肃省酒泉市肃州区", + "Value": "620902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584393, + "Key": "甘肃省酒泉市金塔县", + "Value": "620921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584394, + "Key": "甘肃省酒泉市瓜州县", + "Value": "620922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584395, + "Key": "甘肃省酒泉市肃北蒙古族自治县", + "Value": "620923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584396, + "Key": "甘肃省酒泉市阿克塞哈萨克族自治县", + "Value": "620924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584397, + "Key": "甘肃省酒泉市玉门市", + "Value": "620981" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584398, + "Key": "甘肃省酒泉市敦煌市", + "Value": "620982" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584399, + "Key": "甘肃省庆阳市", + "Value": "621000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584400, + "Key": "甘肃省庆阳市西峰区", + "Value": "621002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584401, + "Key": "甘肃省庆阳市庆城县", + "Value": "621021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789584402, + "Key": "甘肃省庆阳市环县", + "Value": "621022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588485, + "Key": "甘肃省庆阳市华池县", + "Value": "621023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588486, + "Key": "甘肃省庆阳市合水县", + "Value": "621024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588487, + "Key": "甘肃省庆阳市正宁县", + "Value": "621025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588488, + "Key": "甘肃省庆阳市宁县", + "Value": "621026" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588489, + "Key": "甘肃省庆阳市镇原县", + "Value": "621027" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588490, + "Key": "甘肃省定西市", + "Value": "621100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588491, + "Key": "甘肃省定西市安定区", + "Value": "621102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588492, + "Key": "甘肃省定西市通渭县", + "Value": "621121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588493, + "Key": "甘肃省定西市陇西县", + "Value": "621122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588494, + "Key": "甘肃省定西市渭源县", + "Value": "621123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588495, + "Key": "甘肃省定西市临洮县", + "Value": "621124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588496, + "Key": "甘肃省定西市漳县", + "Value": "621125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588497, + "Key": "甘肃省定西市岷县", + "Value": "621126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789588498, + "Key": "甘肃省陇南市", + "Value": "621200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592581, + "Key": "甘肃省陇南市武都区", + "Value": "621202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592582, + "Key": "甘肃省陇南市成县", + "Value": "621221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592583, + "Key": "甘肃省陇南市文县", + "Value": "621222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592584, + "Key": "甘肃省陇南市宕昌县", + "Value": "621223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592585, + "Key": "甘肃省陇南市康县", + "Value": "621224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592586, + "Key": "甘肃省陇南市西和县", + "Value": "621225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592587, + "Key": "甘肃省陇南市礼县", + "Value": "621226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592588, + "Key": "甘肃省陇南市徽县", + "Value": "621227" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592589, + "Key": "甘肃省陇南市两当县", + "Value": "621228" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592590, + "Key": "甘肃省临夏回族自治州", + "Value": "622900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592591, + "Key": "甘肃省临夏回族自治州临夏市", + "Value": "622901" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592592, + "Key": "甘肃省临夏回族自治州临夏县", + "Value": "622921" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592593, + "Key": "甘肃省临夏回族自治州康乐县", + "Value": "622922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592594, + "Key": "甘肃省临夏回族自治州永靖县", + "Value": "622923" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789592595, + "Key": "甘肃省临夏回族自治州广河县", + "Value": "622924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596677, + "Key": "甘肃省临夏回族自治州和政县", + "Value": "622925" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596678, + "Key": "甘肃省临夏回族自治州东乡族自治县", + "Value": "622926" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596679, + "Key": "甘肃省临夏回族自治州积石山保安族东乡族撒拉族自治县", + "Value": "622927" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596680, + "Key": "甘肃省甘南藏族自治州", + "Value": "623000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596681, + "Key": "甘肃省甘南藏族自治州合作市", + "Value": "623001" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596682, + "Key": "甘肃省甘南藏族自治州临潭县", + "Value": "623021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596683, + "Key": "甘肃省甘南藏族自治州卓尼县", + "Value": "623022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596684, + "Key": "甘肃省甘南藏族自治州舟曲县", + "Value": "623023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596685, + "Key": "甘肃省甘南藏族自治州迭部县", + "Value": "623024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596686, + "Key": "甘肃省甘南藏族自治州玛曲县", + "Value": "623025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596687, + "Key": "甘肃省甘南藏族自治州碌曲县", + "Value": "623026" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596688, + "Key": "甘肃省甘南藏族自治州夏河县", + "Value": "623027" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596689, + "Key": "青海省", + "Value": "630000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789596690, + "Key": "青海省西宁市", + "Value": "630100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600773, + "Key": "青海省西宁市城东区", + "Value": "630102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600774, + "Key": "青海省西宁市城中区", + "Value": "630103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600775, + "Key": "青海省西宁市城西区", + "Value": "630104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600776, + "Key": "青海省西宁市城北区", + "Value": "630105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600777, + "Key": "青海省西宁市湟中区", + "Value": "630106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600778, + "Key": "青海省西宁市大通回族土族自治县", + "Value": "630121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600779, + "Key": "青海省西宁市湟源县", + "Value": "630123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600780, + "Key": "青海省海东市", + "Value": "630200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600781, + "Key": "青海省海东市乐都区", + "Value": "630202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600782, + "Key": "青海省海东市平安区", + "Value": "630203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600783, + "Key": "青海省海东市民和回族土族自治县", + "Value": "630222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600784, + "Key": "青海省海东市互助土族自治县", + "Value": "630223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789600785, + "Key": "青海省海东市化隆回族自治县", + "Value": "630224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604869, + "Key": "青海省海东市循化撒拉族自治县", + "Value": "630225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604870, + "Key": "青海省海北藏族自治州", + "Value": "632200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604871, + "Key": "青海省海北藏族自治州门源回族自治县", + "Value": "632221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604872, + "Key": "青海省海北藏族自治州祁连县", + "Value": "632222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604873, + "Key": "青海省海北藏族自治州海晏县", + "Value": "632223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604874, + "Key": "青海省海北藏族自治州刚察县", + "Value": "632224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604875, + "Key": "青海省黄南藏族自治州", + "Value": "632300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604876, + "Key": "青海省黄南藏族自治州同仁市", + "Value": "632301" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604877, + "Key": "青海省黄南藏族自治州尖扎县", + "Value": "632322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604878, + "Key": "青海省黄南藏族自治州泽库县", + "Value": "632323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604879, + "Key": "青海省黄南藏族自治州河南蒙古族自治县", + "Value": "632324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604880, + "Key": "青海省海南藏族自治州", + "Value": "632500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789604881, + "Key": "青海省海南藏族自治州共和县", + "Value": "632521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608965, + "Key": "青海省海南藏族自治州同德县", + "Value": "632522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608966, + "Key": "青海省海南藏族自治州贵德县", + "Value": "632523" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608967, + "Key": "青海省海南藏族自治州兴海县", + "Value": "632524" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608968, + "Key": "青海省海南藏族自治州贵南县", + "Value": "632525" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608969, + "Key": "青海省果洛藏族自治州", + "Value": "632600" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608970, + "Key": "青海省果洛藏族自治州玛沁县", + "Value": "632621" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608971, + "Key": "青海省果洛藏族自治州班玛县", + "Value": "632622" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608972, + "Key": "青海省果洛藏族自治州甘德县", + "Value": "632623" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608973, + "Key": "青海省果洛藏族自治州达日县", + "Value": "632624" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608974, + "Key": "青海省果洛藏族自治州久治县", + "Value": "632625" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608975, + "Key": "青海省果洛藏族自治州玛多县", + "Value": "632626" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608976, + "Key": "青海省玉树藏族自治州", + "Value": "632700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608977, + "Key": "青海省玉树藏族自治州玉树市", + "Value": "632701" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789608978, + "Key": "青海省玉树藏族自治州杂多县", + "Value": "632722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613061, + "Key": "青海省玉树藏族自治州称多县", + "Value": "632723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613062, + "Key": "青海省玉树藏族自治州治多县", + "Value": "632724" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613063, + "Key": "青海省玉树藏族自治州囊谦县", + "Value": "632725" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613064, + "Key": "青海省玉树藏族自治州曲麻莱县", + "Value": "632726" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613065, + "Key": "青海省海西蒙古族藏族自治州", + "Value": "632800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613066, + "Key": "青海省海西蒙古族藏族自治州格尔木市", + "Value": "632801" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613067, + "Key": "青海省海西蒙古族藏族自治州德令哈市", + "Value": "632802" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613068, + "Key": "青海省海西蒙古族藏族自治州茫崖市", + "Value": "632803" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613069, + "Key": "青海省海西蒙古族藏族自治州乌兰县", + "Value": "632821" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613070, + "Key": "青海省海西蒙古族藏族自治州都兰县", + "Value": "632822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613071, + "Key": "青海省海西蒙古族藏族自治州天峻县", + "Value": "632823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613072, + "Key": "宁夏回族自治区", + "Value": "640000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789613073, + "Key": "宁夏回族自治区银川市", + "Value": "640100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617157, + "Key": "宁夏回族自治区银川市兴庆区", + "Value": "640104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617158, + "Key": "宁夏回族自治区银川市西夏区", + "Value": "640105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617159, + "Key": "宁夏回族自治区银川市金凤区", + "Value": "640106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617160, + "Key": "宁夏回族自治区银川市永宁县", + "Value": "640121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617161, + "Key": "宁夏回族自治区银川市贺兰县", + "Value": "640122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617162, + "Key": "宁夏回族自治区银川市灵武市", + "Value": "640181" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617163, + "Key": "宁夏回族自治区石嘴山市", + "Value": "640200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617164, + "Key": "宁夏回族自治区石嘴山市大武口区", + "Value": "640202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617165, + "Key": "宁夏回族自治区石嘴山市惠农区", + "Value": "640205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617166, + "Key": "宁夏回族自治区石嘴山市平罗县", + "Value": "640221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617167, + "Key": "宁夏回族自治区吴忠市", + "Value": "640300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617168, + "Key": "宁夏回族自治区吴忠市利通区", + "Value": "640302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617169, + "Key": "宁夏回族自治区吴忠市红寺堡区", + "Value": "640303" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789617170, + "Key": "宁夏回族自治区吴忠市盐池县", + "Value": "640323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621253, + "Key": "宁夏回族自治区吴忠市同心县", + "Value": "640324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621254, + "Key": "宁夏回族自治区吴忠市青铜峡市", + "Value": "640381" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621255, + "Key": "宁夏回族自治区固原市", + "Value": "640400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621256, + "Key": "宁夏回族自治区固原市原州区", + "Value": "640402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621257, + "Key": "宁夏回族自治区固原市西吉县", + "Value": "640422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621258, + "Key": "宁夏回族自治区固原市隆德县", + "Value": "640423" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621259, + "Key": "宁夏回族自治区固原市泾源县", + "Value": "640424" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621260, + "Key": "宁夏回族自治区固原市彭阳县", + "Value": "640425" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621261, + "Key": "宁夏回族自治区中卫市", + "Value": "640500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621262, + "Key": "宁夏回族自治区中卫市沙坡头区", + "Value": "640502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621263, + "Key": "宁夏回族自治区中卫市中宁县", + "Value": "640521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621264, + "Key": "宁夏回族自治区中卫市海原县", + "Value": "640522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621265, + "Key": "新疆维吾尔自治区", + "Value": "650000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789621266, + "Key": "新疆维吾尔自治区乌鲁木齐市", + "Value": "650100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625349, + "Key": "新疆维吾尔自治区乌鲁木齐市天山区", + "Value": "650102" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625350, + "Key": "新疆维吾尔自治区乌鲁木齐市沙依巴克区", + "Value": "650103" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625351, + "Key": "新疆维吾尔自治区乌鲁木齐市新市区", + "Value": "650104" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625352, + "Key": "新疆维吾尔自治区乌鲁木齐市水磨沟区", + "Value": "650105" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625353, + "Key": "新疆维吾尔自治区乌鲁木齐市头屯河区", + "Value": "650106" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625354, + "Key": "新疆维吾尔自治区乌鲁木齐市达坂城区", + "Value": "650107" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625355, + "Key": "新疆维吾尔自治区乌鲁木齐市米东区", + "Value": "650109" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625356, + "Key": "新疆维吾尔自治区乌鲁木齐市乌鲁木齐县", + "Value": "650121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625357, + "Key": "新疆维吾尔自治区克拉玛依市", + "Value": "650200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625358, + "Key": "新疆维吾尔自治区克拉玛依市独山子区", + "Value": "650202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625359, + "Key": "新疆维吾尔自治区克拉玛依市克拉玛依区", + "Value": "650203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625360, + "Key": "新疆维吾尔自治区克拉玛依市白碱滩区", + "Value": "650204" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625361, + "Key": "新疆维吾尔自治区克拉玛依市乌尔禾区", + "Value": "650205" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789625362, + "Key": "新疆维吾尔自治区吐鲁番市", + "Value": "650400" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629445, + "Key": "新疆维吾尔自治区吐鲁番市高昌区", + "Value": "650402" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629446, + "Key": "新疆维吾尔自治区吐鲁番市鄯善县", + "Value": "650421" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629447, + "Key": "新疆维吾尔自治区吐鲁番市托克逊县", + "Value": "650422" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629448, + "Key": "新疆维吾尔自治区哈密市", + "Value": "650500" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629449, + "Key": "新疆维吾尔自治区哈密市伊州区", + "Value": "650502" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629450, + "Key": "新疆维吾尔自治区哈密市巴里坤哈萨克自治县", + "Value": "650521" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629451, + "Key": "新疆维吾尔自治区哈密市伊吾县", + "Value": "650522" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629452, + "Key": "新疆维吾尔自治区昌吉回族自治州", + "Value": "652300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629453, + "Key": "新疆维吾尔自治区昌吉回族自治州昌吉市", + "Value": "652301" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629454, + "Key": "新疆维吾尔自治区昌吉回族自治州阜康市", + "Value": "652302" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629455, + "Key": "新疆维吾尔自治区昌吉回族自治州呼图壁县", + "Value": "652323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629456, + "Key": "新疆维吾尔自治区昌吉回族自治州玛纳斯县", + "Value": "652324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629457, + "Key": "新疆维吾尔自治区昌吉回族自治州奇台县", + "Value": "652325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629458, + "Key": "新疆维吾尔自治区昌吉回族自治州吉木萨尔县", + "Value": "652327" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789629459, + "Key": "新疆维吾尔自治区昌吉回族自治州木垒哈萨克自治县", + "Value": "652328" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633541, + "Key": "新疆维吾尔自治区博尔塔拉蒙古自治州", + "Value": "652700" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633542, + "Key": "新疆维吾尔自治区博尔塔拉蒙古自治州博乐市", + "Value": "652701" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633543, + "Key": "新疆维吾尔自治区博尔塔拉蒙古自治州阿拉山口市", + "Value": "652702" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633544, + "Key": "新疆维吾尔自治区博尔塔拉蒙古自治州精河县", + "Value": "652722" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633545, + "Key": "新疆维吾尔自治区博尔塔拉蒙古自治州温泉县", + "Value": "652723" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633546, + "Key": "新疆维吾尔自治区巴音郭楞蒙古自治州", + "Value": "652800" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633547, + "Key": "新疆维吾尔自治区巴音郭楞蒙古自治州库尔勒市", + "Value": "652801" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633548, + "Key": "新疆维吾尔自治区巴音郭楞蒙古自治州轮台县", + "Value": "652822" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633549, + "Key": "新疆维吾尔自治区巴音郭楞蒙古自治州尉犁县", + "Value": "652823" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633550, + "Key": "新疆维吾尔自治区巴音郭楞蒙古自治州若羌县", + "Value": "652824" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633551, + "Key": "新疆维吾尔自治区巴音郭楞蒙古自治州且末县", + "Value": "652825" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633552, + "Key": "新疆维吾尔自治区巴音郭楞蒙古自治州焉耆回族自治县", + "Value": "652826" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633553, + "Key": "新疆维吾尔自治区巴音郭楞蒙古自治州和静县", + "Value": "652827" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789633554, + "Key": "新疆维吾尔自治区巴音郭楞蒙古自治州和硕县", + "Value": "652828" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637637, + "Key": "新疆维吾尔自治区巴音郭楞蒙古自治州博湖县", + "Value": "652829" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637638, + "Key": "新疆维吾尔自治区阿克苏地区", + "Value": "652900" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637639, + "Key": "新疆维吾尔自治区阿克苏地区阿克苏市", + "Value": "652901" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637640, + "Key": "新疆维吾尔自治区阿克苏地区库车市", + "Value": "652902" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637641, + "Key": "新疆维吾尔自治区阿克苏地区温宿县", + "Value": "652922" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637642, + "Key": "新疆维吾尔自治区阿克苏地区沙雅县", + "Value": "652924" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637643, + "Key": "新疆维吾尔自治区阿克苏地区新和县", + "Value": "652925" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637644, + "Key": "新疆维吾尔自治区阿克苏地区拜城县", + "Value": "652926" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637645, + "Key": "新疆维吾尔自治区阿克苏地区乌什县", + "Value": "652927" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637646, + "Key": "新疆维吾尔自治区阿克苏地区阿瓦提县", + "Value": "652928" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637647, + "Key": "新疆维吾尔自治区阿克苏地区柯坪县", + "Value": "652929" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637648, + "Key": "新疆维吾尔自治区克孜勒苏柯尔克孜自治州", + "Value": "653000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637649, + "Key": "新疆维吾尔自治区克孜勒苏柯尔克孜自治州阿图什市", + "Value": "653001" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789637650, + "Key": "新疆维吾尔自治区克孜勒苏柯尔克孜自治州阿克陶县", + "Value": "653022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641733, + "Key": "新疆维吾尔自治区克孜勒苏柯尔克孜自治州阿合奇县", + "Value": "653023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641734, + "Key": "新疆维吾尔自治区克孜勒苏柯尔克孜自治州乌恰县", + "Value": "653024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641735, + "Key": "新疆维吾尔自治区喀什地区", + "Value": "653100" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641736, + "Key": "新疆维吾尔自治区喀什地区喀什市", + "Value": "653101" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641737, + "Key": "新疆维吾尔自治区喀什地区疏附县", + "Value": "653121" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641738, + "Key": "新疆维吾尔自治区喀什地区疏勒县", + "Value": "653122" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641739, + "Key": "新疆维吾尔自治区喀什地区英吉沙县", + "Value": "653123" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641740, + "Key": "新疆维吾尔自治区喀什地区泽普县", + "Value": "653124" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641741, + "Key": "新疆维吾尔自治区喀什地区莎车县", + "Value": "653125" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641742, + "Key": "新疆维吾尔自治区喀什地区叶城县", + "Value": "653126" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641743, + "Key": "新疆维吾尔自治区喀什地区麦盖提县", + "Value": "653127" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641744, + "Key": "新疆维吾尔自治区喀什地区岳普湖县", + "Value": "653128" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641745, + "Key": "新疆维吾尔自治区喀什地区伽师县", + "Value": "653129" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789641746, + "Key": "新疆维吾尔自治区喀什地区巴楚县", + "Value": "653130" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645829, + "Key": "新疆维吾尔自治区喀什地区塔什库尔干塔吉克自治县", + "Value": "653131" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645830, + "Key": "新疆维吾尔自治区和田地区", + "Value": "653200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645831, + "Key": "新疆维吾尔自治区和田地区和田市", + "Value": "653201" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645832, + "Key": "新疆维吾尔自治区和田地区和田县", + "Value": "653221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645833, + "Key": "新疆维吾尔自治区和田地区墨玉县", + "Value": "653222" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645834, + "Key": "新疆维吾尔自治区和田地区皮山县", + "Value": "653223" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645835, + "Key": "新疆维吾尔自治区和田地区洛浦县", + "Value": "653224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645836, + "Key": "新疆维吾尔自治区和田地区策勒县", + "Value": "653225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645837, + "Key": "新疆维吾尔自治区和田地区于田县", + "Value": "653226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645838, + "Key": "新疆维吾尔自治区和田地区民丰县", + "Value": "653227" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645839, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州", + "Value": "654000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645840, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州伊宁市", + "Value": "654002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645841, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州奎屯市", + "Value": "654003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645842, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州霍尔果斯市", + "Value": "654004" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789645843, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州伊宁县", + "Value": "654021" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649925, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州察布查尔锡伯自治县", + "Value": "654022" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649926, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州霍城县", + "Value": "654023" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649927, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州巩留县", + "Value": "654024" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649928, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州新源县", + "Value": "654025" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649929, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州昭苏县", + "Value": "654026" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649930, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州特克斯县", + "Value": "654027" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649931, + "Key": "新疆维吾尔自治区伊犁哈萨克自治州尼勒克县", + "Value": "654028" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649932, + "Key": "新疆维吾尔自治区塔城地区", + "Value": "654200" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649933, + "Key": "新疆维吾尔自治区塔城地区塔城市", + "Value": "654201" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649934, + "Key": "新疆维吾尔自治区塔城地区乌苏市", + "Value": "654202" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649935, + "Key": "新疆维吾尔自治区塔城地区沙湾市", + "Value": "654203" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649936, + "Key": "新疆维吾尔自治区塔城地区额敏县", + "Value": "654221" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649937, + "Key": "新疆维吾尔自治区塔城地区托里县", + "Value": "654224" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789649938, + "Key": "新疆维吾尔自治区塔城地区裕民县", + "Value": "654225" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654021, + "Key": "新疆维吾尔自治区塔城地区和布克赛尔蒙古自治县", + "Value": "654226" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654022, + "Key": "新疆维吾尔自治区阿勒泰地区", + "Value": "654300" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654023, + "Key": "新疆维吾尔自治区阿勒泰地区阿勒泰市", + "Value": "654301" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654024, + "Key": "新疆维吾尔自治区阿勒泰地区布尔津县", + "Value": "654321" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654025, + "Key": "新疆维吾尔自治区阿勒泰地区富蕴县", + "Value": "654322" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654026, + "Key": "新疆维吾尔自治区阿勒泰地区福海县", + "Value": "654323" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654027, + "Key": "新疆维吾尔自治区阿勒泰地区哈巴河县", + "Value": "654324" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654028, + "Key": "新疆维吾尔自治区阿勒泰地区青河县", + "Value": "654325" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654029, + "Key": "新疆维吾尔自治区阿勒泰地区吉木乃县", + "Value": "654326" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654030, + "Key": "新疆维吾尔自治区石河子市", + "Value": "659001" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654031, + "Key": "新疆维吾尔自治区阿拉尔市", + "Value": "659002" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654032, + "Key": "新疆维吾尔自治区图木舒克市", + "Value": "659003" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654033, + "Key": "新疆维吾尔自治区五家渠市", + "Value": "659004" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654034, + "Key": "新疆维吾尔自治区北屯市", + "Value": "659005" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789654035, + "Key": "新疆维吾尔自治区铁门关市", + "Value": "659006" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789658117, + "Key": "新疆维吾尔自治区双河市", + "Value": "659007" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789658118, + "Key": "新疆维吾尔自治区可克达拉市", + "Value": "659008" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789658119, + "Key": "新疆维吾尔自治区昆玉市", + "Value": "659009" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789658120, + "Key": "新疆维吾尔自治区胡杨河市", + "Value": "659010" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789658121, + "Key": "新疆维吾尔自治区新星市", + "Value": "659011" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789658122, + "Key": "台湾省", + "Value": "710000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789658123, + "Key": "香港特别行政区", + "Value": "810000" + }, + { + "CatalogId": 379794295185413, + "Id": 396423789658124, + "Key": "澳门特别行政区", + "Value": "820000" + } +] \ No newline at end of file diff --git a/assets/seed-data/Sys_Menu.json b/assets/seed-data/Sys_Menu.json new file mode 100644 index 00000000..5aa362e2 --- /dev/null +++ b/assets/seed-data/Sys_Menu.json @@ -0,0 +1,192 @@ +[ + { + "Component": "home", + "Icon": "el-icon-house", + "Id": 373837717815301, + "Name": "home", + "Path": "/home", + "Sort": 100, + "Title": "控制面板", + "Type": 1 + }, + { + "Component": "profile", + "Id": 374967228141573, + "Name": "profile", + "Path": "/profile", + "Sort": 100, + "Title": "账号信息", + "Hidden": true, + "Type": 1 + }, + { + "Icon": "el-icon-setting", + "Id": 373837917724677, + "Name": "sys", + "Path": "/sys", + "Sort": 99, + "Title": "系统管理", + "Type": 1 + }, + { + "Component": "sys/user", + "Icon": "el-icon-user", + "Id": 373837957840901, + "Name": "sys-user", + "ParentId": 373837917724677, + "Path": "/sys/user", + "Sort": 100, + "Title": "用户管理", + "Type": 1 + }, + { + "Component": "sys/role", + "Icon": "sc-icon-role", + "Id": 373838018527237, + "Name": "sys-role", + "ParentId": 373837917724677, + "Path": "/sys/role", + "Sort": 99, + "Title": "角色管理", + "Type": 1 + }, + { + "Component": "sys/dept", + "Icon": "sc-icon-dept", + "Id": 373838045605893, + "Name": "sys-dept", + "ParentId": 373837917724677, + "Path": "/sys/dept", + "Sort": 98, + "Title": "部门管理", + "Type": 1 + }, + { + "Component": "sys/menu", + "Icon": "el-icon-fold", + "Id": 373838070898693, + "Name": "sys-menu", + "ParentId": 373837917724677, + "Path": "/sys/menu", + "Sort": 96, + "Title": "菜单管理", + "Type": 1 + }, + { + "Component": "sys/log", + "Icon": "el-icon-tickets", + "Id": 374792687640581, + "Name": "sys-log", + "ParentId": 373837917724677, + "Path": "/sys/log", + "Sort": 93, + "Title": "请求日志", + "Type": 1 + }, + { + "Component": "sys/cache", + "Icon": "sc-icon-memory", + "Id": 374911555702789, + "Name": "sys-cache", + "ParentId": 373837917724677, + "Path": "/sys/cache", + "Sort": 94, + "Title": "缓存管理", + "Type": 1 + }, + { + "Component": "sys/dic", + "Icon": "sc-icon-dic", + "Id": 375315654221829, + "Name": "sys-dic", + "ParentId": 373837917724677, + "Path": "/sys/dic", + "Sort": 95, + "Title": "字典管理", + "Type": 1 + }, + { + "Component": "sys/config", + "Icon": "el-icon-set-up", + "Id": 380415005847557, + "Name": "sys-config", + "ParentId": 373837917724677, + "Path": "/sys/config", + "Sort": 92, + "Title": "系统设置", + "Type": 1 + }, + { + "Component": "sys/api", + "Icon": "sc-icon-api", + "Id": 397880678895621, + "Name": "sys-api", + "ParentId": 373837917724677, + "Path": "/sys/api", + "Sort": 96, + "Title": "接口管理", + "Type": 1 + }, + { + "Icon": "sc-icon-business", + "Id": 420881941635077, + "Name": "biz", + "Path": "/biz", + "Sort": 99, + "Title": "业务管理", + "Type": 1 + }, + { + "Component": "biz/product-category", + "Icon": "sc-icon-product-category", + "Id": 420881941635087, + "Name": "biz-product-category", + "ParentId": 420881941635077, + "Path": "/biz/product-category", + "Sort": 100, + "Title": "商品分类", + "Type": 1 + }, + { + "Component": "biz/member", + "Icon": "el-icon-user", + "Id": 422658027704337, + "Name": "biz-member", + "ParentId": 420881941635077, + "Path": "/biz/member", + "Sort": 100, + "Title": "会员管理", + "Type": 1 + }, + { + "Component": "biz/product", + "Icon": "sc-icon-product", + "Id": 421506245349391, + "Name": "biz-product", + "ParentId": 420881941635077, + "Path": "/biz/product", + "Sort": 100, + "Title": "商品管理", + "Type": 1 + }, + { + "Icon": "sc-icon-code", + "Id": 373838105399301, + "Name": "dev", + "Path": "/dev", + "Sort": 97, + "Title": "开发管理", + "Type": 1 + }, + { + "Component": "dev/code", + "Icon": "sc-icon-code2", + "Id": 373838147022853, + "Name": "dev-code", + "ParentId": 373838105399301, + "Path": "/dev/code", + "Sort": 100, + "Title": "代码生成", + "Type": 1 + }, +] \ No newline at end of file diff --git a/assets/seed-data/Sys_Role.json b/assets/seed-data/Sys_Role.json new file mode 100644 index 00000000..3fa98853 --- /dev/null +++ b/assets/seed-data/Sys_Role.json @@ -0,0 +1,18 @@ +[ + { + "DataScope": 1, + "Enabled": true, + "Id": 370943613149253, + "IgnorePermissionControl": true, + "DisplayDashboard": true, + "Name": "超级管理员", + "Sort": 100 + }, + { + "DataScope": 1, + "Enabled": true, + "Id": 371729946431493, + "Name": "普通用户", + "Sort": 100 + } +] \ No newline at end of file diff --git a/assets/seed-data/Sys_RoleApi.json b/assets/seed-data/Sys_RoleApi.json new file mode 100644 index 00000000..d141e48c --- /dev/null +++ b/assets/seed-data/Sys_RoleApi.json @@ -0,0 +1,22 @@ +[ + { + "ApiId": "api/sys/menu/user.menus", + "RoleId": 371729946431493 + }, + { + "ApiId": "api/sys/user/user.info", + "RoleId": 371729946431493 + }, + { + "ApiId": "api/sys/menu", + "RoleId": 371729946431493 + }, + { + "ApiId": "api/sys/user", + "RoleId": 371729946431493 + }, + { + "ApiId": "api/biz/member/member.info", + "RoleId": 371729946431493 + } +] \ No newline at end of file diff --git a/assets/seed-data/Sys_RoleMenu.json b/assets/seed-data/Sys_RoleMenu.json new file mode 100644 index 00000000..1d33ef9e --- /dev/null +++ b/assets/seed-data/Sys_RoleMenu.json @@ -0,0 +1,12 @@ +[ + { + "Id": 396423792566281, + "MenuId": 373837717815301, + "RoleId": 371729946431493 + }, + { + "Id": 396423792566282, + "MenuId": 374967228141573, + "RoleId": 371729946431493 + } +] \ No newline at end of file diff --git a/assets/seed-data/Sys_User.json b/assets/seed-data/Sys_User.json new file mode 100644 index 00000000..a86d7889 --- /dev/null +++ b/assets/seed-data/Sys_User.json @@ -0,0 +1,10 @@ +[ + { + "DeptId": 372119301627909, + "Enabled": true, + "Id": 370942943322181, + "Password": "A8E87D23-49BC-25A1-1C7C-59186BEF5D15", + "Token": "A9AFD92E-A33D-4152-9A6C-A9C141D24887", + "UserName": "root" + } +] \ No newline at end of file diff --git a/assets/seed-data/Sys_UserProfile.json b/assets/seed-data/Sys_UserProfile.json new file mode 100644 index 00000000..fa8bc31b --- /dev/null +++ b/assets/seed-data/Sys_UserProfile.json @@ -0,0 +1,5 @@ +[ + { + "Id": 370942943322181 + } +] \ No newline at end of file diff --git a/assets/seed-data/Sys_UserRole.json b/assets/seed-data/Sys_UserRole.json new file mode 100644 index 00000000..5069b6c8 --- /dev/null +++ b/assets/seed-data/Sys_UserRole.json @@ -0,0 +1,6 @@ +[ + { + "RoleId": 370943613149253, + "UserId": 370942943322181 + } +] \ No newline at end of file diff --git a/dotnet-tools.json b/dotnet-tools.json new file mode 100644 index 00000000..e476009c --- /dev/null +++ b/dotnet-tools.json @@ -0,0 +1,36 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-t4": { + "version": "2.3.1", + "commands": [ + "t4" + ] + }, + "cake.tool": { + "version": "3.1.0", + "commands": [ + "dotnet-cake" + ] + }, + "dotnet-script": { + "version": "1.4.0", + "commands": [ + "dotnet-script" + ] + }, + "jetbrains.resharper.globaltools": { + "version": "2023.2.0", + "commands": [ + "jb" + ] + }, + "dnt": { + "version": "1.8.3", + "commands": [ + "dnt" + ] + } + } +} \ No newline at end of file diff --git a/global.json b/global.json new file mode 100644 index 00000000..89476433 --- /dev/null +++ b/global.json @@ -0,0 +1,10 @@ +{ + "sdk": { + "version": "7.0.0", + "rollForward": "latestMajor", + "allowPrerelease": true + }, + "tools": { + "dotnet": "7.0.0" + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..414cf903 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "devDependencies": { + "cz-conventional-changelog": "^3.3.0", + "prettier": "3.0.2", + "prettier-plugin-csharp": "0.6.0-development" + }, + "config": { + "commitizen": { + "path": "./node_modules/cz-conventional-changelog" + } + } +} \ No newline at end of file diff --git a/src/backend/GlobalUsings.cs b/src/backend/GlobalUsings.cs new file mode 100644 index 00000000..237e18fb --- /dev/null +++ b/src/backend/GlobalUsings.cs @@ -0,0 +1,69 @@ +// ReSharper disable RedundantUsingDirective.Global + +global using System; +global using System.Collections; +global using System.Collections.Generic; +global using System.Collections.Immutable; +global using System.ComponentModel; +global using System.ComponentModel.DataAnnotations; +global using System.Data; +global using System.Diagnostics; +global using System.Globalization; +global using System.IO; +global using System.Linq; +global using System.Linq.Expressions; +global using System.Net; +global using System.Reflection; +global using System.Text; +global using System.Text.Encodings.Web; +global using System.Text.Json; +global using System.Text.Json.Serialization; +global using System.Text.Json.Serialization.Metadata; +global using System.Text.RegularExpressions; +global using System.Threading.Tasks; +global using FreeSql; +global using FreeSql.Aop; +global using FreeSql.DataAnnotations; +global using FreeSql.Internal.Model; +global using Furion; +global using Furion.Authorization; +global using Furion.ConfigurableOptions; +global using Furion.DataEncryption; +global using Furion.DataValidation; +global using Furion.DependencyInjection; +global using Furion.DynamicApiController; +global using Furion.EventBus; +global using Furion.SpecificationDocument; +global using Furion.UnifyResult; +global using Mapster; +global using Microsoft.AspNetCore.Authorization; +global using Microsoft.AspNetCore.Builder; +global using Microsoft.AspNetCore.Diagnostics; +global using Microsoft.AspNetCore.Http; +global using Microsoft.AspNetCore.Mvc; +global using Microsoft.AspNetCore.Mvc.ActionConstraints; +global using Microsoft.AspNetCore.Mvc.Controllers; +global using Microsoft.AspNetCore.Mvc.Filters; +global using Microsoft.AspNetCore.Mvc.Infrastructure; +global using Microsoft.Extensions.Caching.Distributed; +global using Microsoft.Extensions.Caching.Memory; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.Hosting; +global using Microsoft.Extensions.Logging; +global using Microsoft.Extensions.Options; +global using NetAdmin.Infrastructure; +global using NetAdmin.Infrastructure.Attributes; +global using NetAdmin.Infrastructure.Configuration.Options; +global using NetAdmin.Infrastructure.Configuration.Options.SubNodes.Redis; +global using NetAdmin.Infrastructure.Configuration.Options.SubNodes.Upload; +global using NetAdmin.Infrastructure.Constant; +global using NetAdmin.Infrastructure.Enums; +global using NetAdmin.Infrastructure.Exceptions; +global using NetAdmin.Infrastructure.Exceptions.InvalidInput; +global using NetAdmin.Infrastructure.Exceptions.InvalidOperation; +global using NetAdmin.Infrastructure.Exceptions.Unexpected; +global using NetAdmin.Infrastructure.Extensions; +global using NetAdmin.Infrastructure.Languages; +global using NetAdmin.Infrastructure.Utils; +global using NSExt.Attributes; +global using NSExt.Extensions; \ No newline at end of file diff --git a/src/backend/NetAdmin.Application/Modules/ICrudModule.cs b/src/backend/NetAdmin.Application/Modules/ICrudModule.cs new file mode 100644 index 00000000..f093de83 --- /dev/null +++ b/src/backend/NetAdmin.Application/Modules/ICrudModule.cs @@ -0,0 +1,64 @@ +using NetAdmin.Domain; +using NetAdmin.Domain.Dto.Dependency; + +namespace NetAdmin.Application.Modules; + +/// +/// 增删改查模块接口 +/// +/// 创建请求类型 +/// 创建响应类型 +/// 查询请求类型 +/// 查询响应类型 +/// 修改请求类型 +/// 修改响应类型 +/// 删除请求类型 +public interface ICrudModule + where TCreateReq : DataAbstraction, new() + where TCreateRsp : DataAbstraction + where TQueryReq : DataAbstraction, new() + where TQueryRsp : DataAbstraction + where TUpdateReq : DataAbstraction, new() + where TUpdateRsp : DataAbstraction + where TDelReq : DataAbstraction, new() +{ + /// + /// 批量删除实体 + /// + Task BulkDeleteAsync(BulkReq req); + + /// + /// 创建实体 + /// + Task CreateAsync(TCreateReq req); + + /// + /// 删除实体 + /// + Task DeleteAsync(TDelReq req); + + /// + /// 判断实体是否存在 + /// + Task ExistAsync(QueryReq req); + + /// + /// 获取单个实体 + /// + Task GetAsync(TQueryReq req); + + /// + /// 分页查询实体 + /// + Task> PagedQueryAsync(PagedQueryReq req); + + /// + /// 查询实体 + /// + Task> QueryAsync(QueryReq req); + + /// + /// 更新实体 + /// + Task UpdateAsync(TUpdateReq req); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Application/NetAdmin.Application.csproj b/src/backend/NetAdmin.Application/NetAdmin.Application.csproj new file mode 100644 index 00000000..9f0908f5 --- /dev/null +++ b/src/backend/NetAdmin.Application/NetAdmin.Application.csproj @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.Application/Repositories/IRepository.cs b/src/backend/NetAdmin.Application/Repositories/IRepository.cs new file mode 100644 index 00000000..e0da9fd2 --- /dev/null +++ b/src/backend/NetAdmin.Application/Repositories/IRepository.cs @@ -0,0 +1,39 @@ +using NetAdmin.Domain.Contexts; +using NetAdmin.Domain.DbMaps.Dependency; + +namespace NetAdmin.Application.Repositories; + +/// +/// 基础仓储接口 +/// +public interface IRepository : IBaseRepository + where TEntity : EntityBase +{ + /// + /// 当前上下文关联的用户 + /// + ContextUserToken UserToken { get; } + + /// + /// 递归删除 + /// + /// exp + /// 禁用全局过滤器名 + Task DeleteRecursiveAsync(Expression> exp, params string[] disableGlobalFilterNames); + + /// + /// 获得Dto + /// + /// 主键 + Task GetAsync(long id); + + /// + /// 根据条件获取Dto + /// + Task GetAsync(Expression> exp); + + /// + /// 根据条件获取实体 + /// + Task GetAsync(Expression> exp); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Application/Repositories/Repository.cs b/src/backend/NetAdmin.Application/Repositories/Repository.cs new file mode 100644 index 00000000..85b3d444 --- /dev/null +++ b/src/backend/NetAdmin.Application/Repositories/Repository.cs @@ -0,0 +1,82 @@ +using NetAdmin.Domain.Contexts; +using NetAdmin.Domain.DbMaps.Dependency; + +namespace NetAdmin.Application.Repositories; + +/// +public sealed class Repository : DefaultRepository, IRepository + where TEntity : EntityBase +{ + /// + /// Initializes a new instance of the class. + /// + public Repository(IFreeSql fSql, UnitOfWorkManager uowManger, ContextUserToken userToken) // + : base(fSql, uowManger) + { + UserToken = userToken; + } + + /// + /// 当前上下文关联的用户 + /// + public ContextUserToken UserToken { get; } + + /// + /// 递归删除 + /// + /// exp + /// 禁用全局过滤器名 + public async Task DeleteRecursiveAsync( // + Expression> exp, params string[] disableGlobalFilterNames) + { + _ = await Select.Where(exp) + .DisableGlobalFilter(disableGlobalFilterNames) + .AsTreeCte() + .ToDelete() + .ExecuteAffrowsAsync(); + + return true; + } + + /// + /// 获得Dto + /// + /// 主键 + public Task GetAsync(long id) + { + return Select.WhereDynamic(id).ToOneAsync(); + } + + /// + /// 根据条件获取Dto + /// + public Task GetAsync(Expression> exp) + { + return Select.Where(exp).ToOneAsync(); + } + + /// + /// 根据条件获取实体 + /// + public Task GetAsync(Expression> exp) + { + return Select.Where(exp).ToOneAsync(); + } + + /// + /// 获取分页列表 + /// + /// 动态过滤器 + /// 页码 + /// 页容量 + /// 分页列表和总条数 + public async Task<(IEnumerable List, long Total)> GetPagedListAsync( + DynamicFilterInfo dynamicFilterInfo, int page, int pageSize) + { + var list = await Select.WhereDynamicFilter(dynamicFilterInfo) + .Count(out var total) + .Page(page, pageSize) + .ToListAsync(); + return (list, total); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Application/Services/IService.cs b/src/backend/NetAdmin.Application/Services/IService.cs new file mode 100644 index 00000000..7453be44 --- /dev/null +++ b/src/backend/NetAdmin.Application/Services/IService.cs @@ -0,0 +1,19 @@ +using NetAdmin.Domain.Contexts; + +namespace NetAdmin.Application.Services; + +/// +/// 服务接口 +/// +public interface IService +{ + /// + /// 服务编号 + /// + Guid ServiceId { get; set; } + + /// + /// 上下文用户 + /// + ContextUserToken UserToken { get; set; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Application/Services/RepositoryService.cs b/src/backend/NetAdmin.Application/Services/RepositoryService.cs new file mode 100644 index 00000000..11c313d3 --- /dev/null +++ b/src/backend/NetAdmin.Application/Services/RepositoryService.cs @@ -0,0 +1,34 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Domain.DbMaps.Dependency; + +namespace NetAdmin.Application.Services; + +/// +/// 仓储服务基类 +/// +/// 实体类型 +/// 日志类型 +public abstract class RepositoryService : ServiceBase + where TEntity : EntityBase +{ + /// + /// Initializes a new instance of the class. + /// + protected RepositoryService(Repository rpo) // + { + Rpo = rpo; + } + + /// + /// 默认仓储 + /// + protected Repository Rpo { get; } + + /// + /// 启用级联保存 + /// + protected bool EnableCascadeSave { + get => Rpo.DbContextOptions.EnableCascadeSave; + set => Rpo.DbContextOptions.EnableCascadeSave = value; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Application/Services/ServiceBase.cs b/src/backend/NetAdmin.Application/Services/ServiceBase.cs new file mode 100644 index 00000000..476adfd9 --- /dev/null +++ b/src/backend/NetAdmin.Application/Services/ServiceBase.cs @@ -0,0 +1,45 @@ +using NetAdmin.Domain.Contexts; + +namespace NetAdmin.Application.Services; + +/// +public abstract class ServiceBase : ServiceBase +{ + /// + /// Initializes a new instance of the class. + /// + protected ServiceBase() // + { + Logger = App.GetService>(); + } + + /// + /// 日志记录器 + /// + protected ILogger Logger { get; } +} + +/// +/// 服务基类 +/// +public abstract class ServiceBase : IScoped, IService +{ + /// + /// Initializes a new instance of the class. + /// + protected ServiceBase() + { + UserToken = App.GetService(); + ServiceId = Guid.NewGuid(); + } + + /// + /// 服务编号 + /// + public Guid ServiceId { get; set; } + + /// + /// 上下文用户 + /// + public ContextUserToken UserToken { get; set; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Application/NetAdmin.BizServer.Application.csproj b/src/backend/NetAdmin.BizServer.Application/NetAdmin.BizServer.Application.csproj new file mode 100644 index 00000000..d66eacec --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Application/NetAdmin.BizServer.Application.csproj @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Cache/NetAdmin.BizServer.Cache.csproj b/src/backend/NetAdmin.BizServer.Cache/NetAdmin.BizServer.Cache.csproj new file mode 100644 index 00000000..1c307fc1 --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Cache/NetAdmin.BizServer.Cache.csproj @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Host/Extensions/ServiceCollectionExtensions.cs b/src/backend/NetAdmin.BizServer.Host/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..979b7096 --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Host/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,39 @@ +using NetAdmin.BizServer.Host.Filters; +using NetAdmin.Domain.Contexts; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.Enums.Sys; +using NetAdmin.Host.Extensions; + +namespace NetAdmin.BizServer.Host.Extensions; + +/// +/// ServiceCollection 扩展方法 +/// +[SuppressSniffer] +public static class ServiceCollectionExtensions +{ + /// + /// 注册FreeSql + /// + public static IServiceCollection AddFreeSql(this IServiceCollection me) + { + _ = me.AddFreeSql( // + FreeSqlInitOptions.SyncStructure | FreeSqlInitOptions.InsertSeedData, freeSql => { + // 数据权限过滤器 + _ = freeSql.GlobalFilter.ApplyOnlyIf( // + Chars.FLG_GLOBAL_FILTER_DATA + , () => ContextUserInfo.Create()?.Roles.All(x => x.DataScope == DataScopes.Self) ?? false + , a => a.OwnerId == ContextUserInfo.Create().Id); + }); + return me; + } + + /// + /// jwt授权处理器 + /// + public static IServiceCollection AddJwt(this IServiceCollection me) + { + _ = me.AddJwt(enableGlobalAuthorize: true); + return me; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Host/Filters/JwtHandler.cs b/src/backend/NetAdmin.BizServer.Host/Filters/JwtHandler.cs new file mode 100644 index 00000000..6b74d59f --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Host/Filters/JwtHandler.cs @@ -0,0 +1,48 @@ +using NetAdmin.Domain.Contexts; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.BizServer.Host.Filters; + +/// +[SuppressSniffer] +public sealed class JwtHandler : AppAuthorizeHandler +{ + /// + /// Initializes a new instance of the class. + /// + public JwtHandler() { } + + /// + /// 验证管道 + /// + public override async Task PipelineAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext) + { + // 无法从token中获取context user,拒绝访问 + if (App.GetService() == null) { + return false; + } + + // 数据库不存在context user,或用户已被禁用,拒绝访问 + var userInfo = await App.GetService().UserInfoAsync(); + if (userInfo?.Roles == null) { + return false; + } + + httpContext.Items.Add(Chars.FLG_CONTEXT_USER_INFO, userInfo); + + var path = httpContext.Request.Path.Value!.TrimStart('/'); + foreach (var role in userInfo.Roles) { + // 忽略权限控制,直接通过 + if (role.IgnorePermissionControl) { + return true; + } + + // 获取所属角色接口权限 进行核对 + if (role.ApiIds?.Contains(path) ?? false) { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Host/NetAdmin.BizServer.Host.csproj b/src/backend/NetAdmin.BizServer.Host/NetAdmin.BizServer.Host.csproj new file mode 100644 index 00000000..cff7f53a --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Host/NetAdmin.BizServer.Host.csproj @@ -0,0 +1,15 @@ + + + + + + + + + + + + PreserveNewest + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Host/Properties/launchSettings.json b/src/backend/NetAdmin.BizServer.Host/Properties/launchSettings.json new file mode 100644 index 00000000..6794562a --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Host/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "NetAdmin.BizServer.Host": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "http://localhost:65010", + "applicationUrl": "http://[::]:65010", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Host/Startup.cs b/src/backend/NetAdmin.BizServer.Host/Startup.cs new file mode 100644 index 00000000..cb304232 --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Host/Startup.cs @@ -0,0 +1,67 @@ +using NetAdmin.BizServer.Host.Extensions; +using NetAdmin.Host.Extensions; +using NetAdmin.Host.Middlewares; +using Prometheus; + +namespace NetAdmin.BizServer.Host; + +/// +/// 启动类 +/// +public sealed class Startup : NetAdmin.Host.Startup +{ + /// + /// 程序入口 + /// + public static void Main(string[] args) + { + ShowBanner(); + _ = Serve.Run(RunOptions.Default.WithArgs(args)); + } + + /// + /// 配置应用程序中间件 + /// + public void Configure(IApplicationBuilder app) + { + _ = app // + .UseRealIp() // 获取真实IP + .EnableBuffering() // 启用 Body 重读 + .UseMiddleware() // 请求审计 + #if DEBUG + .UseOpenApiSkin() // Swagger皮肤 + #endif + .UseInject(string.Empty) // / Furion脚手架 + .UseUnifyResultStatusCodes() // 状态码拦截 + .UseCorsAccessor() // 跨域访问 + .UseRouting() // 路由映射 + .UseHttpMetrics() // 性能监控 + .UseAuthentication() // / 认证 + .UseAuthorization() // 授权 + .UseMiddleware() // 删除json空节点 + .UseEndpoints(); // 执行匹配的端点 + } + + /// + /// 配置服务容器 + /// + public void ConfigureServices(IServiceCollection services) + { + _ = services.AddConsoleFormatter() // 控制台日志模板 + .AddAllOptions() // 注册配置项 + .AddJwt() // Jwt 授权处理器 + .AddSnowflake() // 雪花编号生成器 + .AddEventBus() // 事件总线 + .AddFreeSql() // freeSql + .AddRemoteRequest() // 注册远程请求 + .AddCorsAccessor() // 支持跨域访问 + .AddContextUser() // 上下文用户 + .AddRedisCache() // Redis缓存 + + // IMvcBuilder + .AddControllers() // 注册控制器 + .AddJsonSerializer(true) // json序列化配置 + .AddDefaultApiResultHandler() // Api结果处理器 + ; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Host/settings.Development.json b/src/backend/NetAdmin.BizServer.Host/settings.Development.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Host/settings.Development.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Host/settings.Test.json b/src/backend/NetAdmin.BizServer.Host/settings.Test.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Host/settings.Test.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Host/settings.json b/src/backend/NetAdmin.BizServer.Host/settings.json new file mode 100644 index 00000000..1da5c252 --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Host/settings.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", + "SpecificationDocumentSettings": { + "GroupOpenApiInfos": [ + { + "Group": "Sys", + "Title": "系统组件", + "Description": "NetAdmin - 系统组件", + }, + { + "Group": "Biz", + "Title": "业务服务", + "Description": "NetAdmin - 业务服务", + }, + { + "Group": "Tpl", + "Title": "示例服务", + "Description": "NetAdmin - 示例服务", + "Visible": false + }, + { + "Group": "Health", + "Visible": false + } + ], + "SecurityDefinitions": [ + { + "Id": "Bearer", + "Type": "ApiKey", + "Name": "Authorization", + "Description": "JWT Authorization header using the Bearer scheme.", + "BearerFormat": "JWT", + "Scheme": "bearer", + "In": "Header", + "Requirement": { + "Scheme": { + "Reference": { + "Id": "Bearer", + "Type": "SecurityScheme" + }, + "Accesses": [] + } + } + } + ] + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Tests/NetAdmin.BizServer.Tests.csproj b/src/backend/NetAdmin.BizServer.Tests/NetAdmin.BizServer.Tests.csproj new file mode 100644 index 00000000..974ab32d --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Tests/NetAdmin.BizServer.Tests.csproj @@ -0,0 +1,21 @@ + + + true + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.BizServer.Tests/UsedNumberTests.cs b/src/backend/NetAdmin.BizServer.Tests/UsedNumberTests.cs new file mode 100644 index 00000000..88b63515 --- /dev/null +++ b/src/backend/NetAdmin.BizServer.Tests/UsedNumberTests.cs @@ -0,0 +1,18 @@ +using Xunit; + +namespace NetAdmin.BizServer.Tests; + +/// +/// UsedNumberTests +/// +public class UsedNumberTests +{ + /// + /// Test1 + /// + [Fact] + public void Test1() + { + // Assert.True("1".Int32() == 2); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Cache/CacheBase.cs b/src/backend/NetAdmin.Cache/CacheBase.cs new file mode 100644 index 00000000..67b87c14 --- /dev/null +++ b/src/backend/NetAdmin.Cache/CacheBase.cs @@ -0,0 +1,29 @@ +using NetAdmin.Application.Services; + +namespace NetAdmin.Cache; + +/// +/// 缓存基类 +/// +public abstract class CacheBase : ICache + where TService : IService +{ + /// + /// Initializes a new instance of the class. + /// + protected CacheBase(TCacheContainer cache, TService service) + { + Cache = cache; + Service = service; + } + + /// + /// 缓存对象 + /// + public TCacheContainer Cache { get; } + + /// + /// 关联的服务 + /// + public TService Service { get; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Cache/DistributedCache.cs b/src/backend/NetAdmin.Cache/DistributedCache.cs new file mode 100644 index 00000000..f8d20b93 --- /dev/null +++ b/src/backend/NetAdmin.Cache/DistributedCache.cs @@ -0,0 +1,95 @@ +using System.Runtime.CompilerServices; +using NetAdmin.Application.Services; + +namespace NetAdmin.Cache; + +/// +/// 分布式缓存 +/// +public abstract class DistributedCache : CacheBase + where TService : IService +{ + /// + /// Initializes a new instance of the class. + /// + protected DistributedCache(IDistributedCache cache, TService service) // + : base(cache, service) { } + + /// + /// 创建缓存 + /// + /// 缓存键 + /// 创建对象 + /// 绝对过期时间 + /// 滑动过期时间 + /// 缓存对象类型 + /// 缓存对象 + protected Task CreateAsync(string key, T createObj, TimeSpan? absLifeTime = null, TimeSpan? slideLifeTime = null) + { + var cacheWrite = createObj.ToJson(); + + var options = new DistributedCacheEntryOptions(); + if (absLifeTime != null) { + _ = options.SetAbsoluteExpiration(absLifeTime.Value); + } + + if (slideLifeTime != null) { + _ = options.SetSlidingExpiration(slideLifeTime.Value); + } + + return Cache.SetAsync(key, cacheWrite.Hex(), options); + } + + /// + /// 获取缓存 + /// + protected async Task GetAsync(string key) + { + var cacheRead = await Cache.GetStringAsync(key); + return cacheRead != null ? cacheRead.ToObject() : default; + } + + /// + /// 获取缓存键 + /// + protected virtual string GetCacheKey(string id = "0", [CallerMemberName] string memberName = null) + { + return $"{GetType().FullName}.{memberName}.{id}"; + } + + /// + /// 获取或创建缓存 + /// + /// 缓存键 + /// 创建函数 + /// 绝对过期时间 + /// 滑动过期时间 + /// 缓存对象类型 + /// 缓存对象 + protected async Task GetOrCreateAsync(string key, Func> createProc, TimeSpan? absLifeTime = null + , TimeSpan? slideLifeTime = null) + { + var cacheRead = await GetAsync(key); + if (cacheRead is not null) { + return cacheRead; + } + + var obj = await createProc.Invoke(); + + var cacheWrite = obj?.ToJson(); + if (cacheWrite == null) { + return obj; + } + + await CreateAsync(key, obj, absLifeTime, slideLifeTime); + return obj; + } + + /// + /// 删除缓存 + /// + protected Task RemoveAsync(string key) + { + return Cache.RemoveAsync(key); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Cache/ICache.cs b/src/backend/NetAdmin.Cache/ICache.cs new file mode 100644 index 00000000..092f8efd --- /dev/null +++ b/src/backend/NetAdmin.Cache/ICache.cs @@ -0,0 +1,20 @@ +using NetAdmin.Application.Services; + +namespace NetAdmin.Cache; + +/// +/// 缓存接口 +/// +public interface ICache + where TService : IService +{ + /// + /// 缓存对象 + /// + TCacheLoad Cache { get; } + + /// + /// 关联的服务 + /// + public TService Service { get; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Cache/MemoryCache.cs b/src/backend/NetAdmin.Cache/MemoryCache.cs new file mode 100644 index 00000000..a2c3cf95 --- /dev/null +++ b/src/backend/NetAdmin.Cache/MemoryCache.cs @@ -0,0 +1,16 @@ +using NetAdmin.Application.Services; + +namespace NetAdmin.Cache; + +/// +/// 内存缓存 +/// +public abstract class MemoryCache : CacheBase + where TService : IService +{ + /// + /// Initializes a new instance of the class. + /// + protected MemoryCache(IMemoryCache cache, TService service) // + : base(cache, service) { } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Cache/NetAdmin.Cache.csproj b/src/backend/NetAdmin.Cache/NetAdmin.Cache.csproj new file mode 100644 index 00000000..1124ffb6 --- /dev/null +++ b/src/backend/NetAdmin.Cache/NetAdmin.Cache.csproj @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/AlipayAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/AlipayAttribute.cs new file mode 100644 index 00000000..47b7dfef --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/AlipayAttribute.cs @@ -0,0 +1,23 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 支付宝验证器(手机或邮箱) +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class AlipayAttribute : ValidationAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public AlipayAttribute() + { + ErrorMessageResourceName = nameof(Ln.支付宝账号); + ErrorMessageResourceType = typeof(Ln); + } + + /// + public override bool IsValid(object value) + { + return new MobileAttribute().IsValid(value) || new EmailAddressAttribute().IsValid(value); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/CertificateAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/CertificateAttribute.cs new file mode 100644 index 00000000..95eec345 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/CertificateAttribute.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 证件号码 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class CertificateAttribute : RegexAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public CertificateAttribute() // + : base(Chars.RGX_CERTIFICATE) + { + ErrorMessageResourceName = nameof(Ln.无效证件号码); + ErrorMessageResourceType = typeof(Ln); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/ChineseNameAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/ChineseNameAttribute.cs new file mode 100644 index 00000000..8e5e9652 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/ChineseNameAttribute.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 中文姓名 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class ChineseNameAttribute : RegexAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public ChineseNameAttribute() // + : base(Chars.RGX_CHINESE_NAME) + { + ErrorMessageResourceName = nameof(Ln.中文姓名); + ErrorMessageResourceType = typeof(Ln); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/CulturePhoneAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/CulturePhoneAttribute.cs new file mode 100644 index 00000000..c866505e --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/CulturePhoneAttribute.cs @@ -0,0 +1,23 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 电话验证器(手机或固话) +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class CulturePhoneAttribute : ValidationAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public CulturePhoneAttribute() + { + ErrorMessageResourceName = nameof(Ln.手机号码或座机号码); + ErrorMessageResourceType = typeof(Ln); + } + + /// + public override bool IsValid(object value) + { + return new MobileAttribute().IsValid(value) || new TelephoneAttribute().IsValid(value); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/CultureRangeAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/CultureRangeAttribute.cs new file mode 100644 index 00000000..0069dcd3 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/CultureRangeAttribute.cs @@ -0,0 +1,26 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 区间验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class CultureRangeAttribute : RangeAttribute +{ + /// + public CultureRangeAttribute(double minimum, double maximum) // + : base(minimum, maximum) { } + + /// + public CultureRangeAttribute(int minimum, int maximum) // + : base(minimum, maximum) { } + + /// + public CultureRangeAttribute(Type type, string minimum, string maximum) // + : base(type, minimum, maximum) { } + + /// + public override string FormatErrorMessage(string name) + { + return $"{ErrorMessageString} {Ln.必须介于} {Minimum} - {Maximum}"; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/CultureRequiredAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/CultureRequiredAttribute.cs new file mode 100644 index 00000000..44fd7c6f --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/CultureRequiredAttribute.cs @@ -0,0 +1,17 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 非空验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class CultureRequiredAttribute : RequiredAttribute +{ + /// Applies formatting to an error message, based on the data field where the error occurred. + /// The name to include in the formatted message. + /// The current attribute is malformed. + /// An instance of the formatted error message. + public override string FormatErrorMessage(string name) + { + return $"{ErrorMessageString.NullOrEmpty(name)} {Ln.不能为空}"; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/CultureUrlAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/CultureUrlAttribute.cs new file mode 100644 index 00000000..8658c418 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/CultureUrlAttribute.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// Url验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class CultureUrlAttribute : RegexAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public CultureUrlAttribute() // + : base(Chars.RGX_URL) + { + ErrorMessageResourceName = nameof(Ln.无效网络地址); + ErrorMessageResourceType = typeof(Ln); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/EmailAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/EmailAttribute.cs new file mode 100644 index 00000000..6717b8f6 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/EmailAttribute.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 邮箱验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class EmailAttribute : RegexAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public EmailAttribute() // + : base(Chars.RGX_EMAIL) + { + ErrorMessageResourceName = nameof(Ln.电子邮箱); + ErrorMessageResourceType = typeof(Ln); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/InviteCodeAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/InviteCodeAttribute.cs new file mode 100644 index 00000000..a55a02ec --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/InviteCodeAttribute.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 邀请码验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class InviteCodeAttribute : RegexAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public InviteCodeAttribute() // + : base(Chars.RGX_INVITE_CODE) + { + ErrorMessageResourceName = nameof(Ln.邀请码不正确); + ErrorMessageResourceType = typeof(Ln); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/MobileAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/MobileAttribute.cs new file mode 100644 index 00000000..f37e34bf --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/MobileAttribute.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 手机号验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class MobileAttribute : RegexAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public MobileAttribute() // + : base(Chars.RGX_MOBILE) + { + ErrorMessageResourceName = nameof(Ln.手机号码); + ErrorMessageResourceType = typeof(Ln); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/PasswordAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/PasswordAttribute.cs new file mode 100644 index 00000000..0ff71759 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/PasswordAttribute.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 密码验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class PasswordAttribute : RegexAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public PasswordAttribute() // + : base(Chars.RGX_PASSWORD) + { + ErrorMessageResourceName = nameof(Ln._8位以上数字字母组合); + ErrorMessageResourceType = typeof(Ln); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/PayPasswordAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/PayPasswordAttribute.cs new file mode 100644 index 00000000..f97f1c5c --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/PayPasswordAttribute.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 交易密码验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class PayPasswordAttribute : RegexAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public PayPasswordAttribute() // + : base(Chars.RGX_PAY_PASSWORD) + { + ErrorMessageResourceName = nameof(Ln._6位数字); + ErrorMessageResourceType = typeof(Ln); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/RegexAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/RegexAttribute.cs new file mode 100644 index 00000000..f4eeb44d --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/RegexAttribute.cs @@ -0,0 +1,16 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 正则表达式验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +#pragma warning disable DesignedForInheritance +public class RegexAttribute : RegularExpressionAttribute + #pragma warning restore DesignedForInheritance +{ + /// + /// Initializes a new instance of the class. + /// + protected RegexAttribute(string pattern) // + : base(pattern) { } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/SpecificDeptAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/SpecificDeptAttribute.cs new file mode 100644 index 00000000..b3bd1cbd --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/SpecificDeptAttribute.cs @@ -0,0 +1,27 @@ +using NetAdmin.Domain.Dto.Sys.Role; +using NetAdmin.Domain.Enums.Sys; + +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 数据范围为特定部门的验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class SpecificDeptAttribute : ValidationAttribute +{ + /// + protected override ValidationResult IsValid(object value, ValidationContext validationContext) + { + if (validationContext.ObjectInstance is not CreateRoleReq { DataScope: DataScopes.SpecificDept }) { + return ValidationResult.Success; + } + #pragma warning disable IDE0046 + + if ((value as IEnumerable)?.Any() ?? false) { + #pragma warning restore IDE0046 + return ValidationResult.Success; + } + + return new ValidationResult(Ln.未指定部门); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/TelephoneAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/TelephoneAttribute.cs new file mode 100644 index 00000000..c521e97a --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/TelephoneAttribute.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 固定电话验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class TelephoneAttribute : RegexAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public TelephoneAttribute() // + : base(Chars.RGX_TELEPHONE) + { + ErrorMessageResourceName = nameof(Ln.区号电话号码分机号); + ErrorMessageResourceType = typeof(Ln); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/UserNameAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/UserNameAttribute.cs new file mode 100644 index 00000000..a97ed3da --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/UserNameAttribute.cs @@ -0,0 +1,34 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 用户名验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class UserNameAttribute : RegexAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public UserNameAttribute() // + : base(Chars.RGX_USERNAME) + { + ErrorMessageResourceType = typeof(Ln); + } + + /// + public override bool IsValid(object value) + { + if (!base.IsValid(value)) { + ErrorMessageResourceName = nameof(Ln.用户名长度4位以上); + return false; + } + + if (!new MobileAttribute().IsValid(value)) { + return true; + } + + // 不能是手机号 + ErrorMessageResourceName = nameof(Ln.用户名不能是手机号); + return false; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/DataValidation/VerifyCodeAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/DataValidation/VerifyCodeAttribute.cs new file mode 100644 index 00000000..07cdf1c1 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/DataValidation/VerifyCodeAttribute.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Domain.Attributes.DataValidation; + +/// +/// 验证码验证器 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] +public sealed class VerifyCodeAttribute : RegexAttribute +{ + /// + /// Initializes a new instance of the class. + /// + public VerifyCodeAttribute() // + : base(Chars.RGX_VERIFY_CODE) + { + ErrorMessageResourceName = nameof(Ln.验证码不正确); + ErrorMessageResourceType = typeof(Ln); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/ServerTimeAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/ServerTimeAttribute.cs new file mode 100644 index 00000000..47d195bf --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/ServerTimeAttribute.cs @@ -0,0 +1,7 @@ +namespace NetAdmin.Domain.Attributes; + +/// +/// 标记一个字段启用服务器时间 +/// +[AttributeUsage(AttributeTargets.Property)] +public sealed class ServerTimeAttribute : Attribute { } \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Attributes/SnowflakeAttribute.cs b/src/backend/NetAdmin.Domain/Attributes/SnowflakeAttribute.cs new file mode 100644 index 00000000..3c652389 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Attributes/SnowflakeAttribute.cs @@ -0,0 +1,12 @@ +// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global + +namespace NetAdmin.Domain.Attributes; + +/// +/// 标记一个字段启用雪花编号生成 +/// +[AttributeUsage(AttributeTargets.Property)] +public sealed class SnowflakeAttribute : Attribute +{ + // +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Contexts/ContextApp.cs b/src/backend/NetAdmin.Domain/Contexts/ContextApp.cs new file mode 100644 index 00000000..836fa40b --- /dev/null +++ b/src/backend/NetAdmin.Domain/Contexts/ContextApp.cs @@ -0,0 +1,113 @@ +namespace NetAdmin.Domain.Contexts; + +/// +/// 上下文应用信息 +/// +/// +/// 签名算法: $"${appId}{appSecret.ToLowerInvariant()}{timestamp}{reqBody}".Md5(Encoding.UTF8); +/// reqBody 需去除\r、\n、whitespace +/// +public sealed record ContextApp : DataAbstraction, IValidatableObject +{ + private const int _TS_OFFSET_SCOPE_SEC = 30; + + /// + /// Initializes a new instance of the class. + /// + public ContextApp(long appId, string appSecret, long timestamp) + { + AppId = appId; + AppSecret = appSecret; + Timestamp = timestamp; + } + + /// + /// Initializes a new instance of the class. + /// + private ContextApp() + { + AppId = App.HttpContext.Request.Headers[nameof(AppId)].FirstOrDefault().Int64Try(0); + AppSecret = App.HttpContext.Request.Headers[nameof(AppSecret)].FirstOrDefault(); + Sign = App.HttpContext.Request.Headers[nameof(Sign)].FirstOrDefault(); + Timestamp = App.HttpContext.Request.Headers[nameof(Timestamp)].FirstOrDefault().Int64Try(0); + } + + /// + /// AppId + /// + [Range(1, long.MaxValue)] + public long AppId { get; init; } + + /// + /// AppSecret + /// + public string AppSecret { get; init; } + + /// + /// 签名 + /// + public string Sign { get; set; } + + /// + /// 时间戳 + /// + public long Timestamp { get; set; } + + /// + /// 从HttpContext 创建上下文应用 + /// + public static async Task CreateAsync() + { + var ret = new ContextApp(); + if (!ret.TryValidate().IsValid) { + return null; + } + + // 具有secret的情况下,自动生成时间戳+sign,方便调试 + if (!ret.AppSecret.NullOrEmpty()) { + ret.Timestamp = DateTime.Now.TimeUnixUtc(); + ret.Sign = await ret.BuildSignFromHttpContextAsync(); + } + + return ret; + } + + /// + /// 构建签名 + /// + public string BuildSign(string reqBody) + { + // 去除\r\n和空格再计算签名,规避风格样式问题 + reqBody = reqBody.Replace("\r", string.Empty).Replace("\n", string.Empty).Replace(" ", string.Empty); + return $"{AppId}{AppSecret.ToLowerInvariant()}{Timestamp}{reqBody}".Md5(Encoding.UTF8); + } + + /// + /// 构建签名(从http上下文) + /// + public async Task BuildSignFromHttpContextAsync() + { + var sr = new StreamReader(App.HttpContext.Request.Body); + var reqBody = await sr.ReadToEndAsync(); + + _ = App.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin); + return BuildSign(reqBody); + } + + /// + public IEnumerable Validate(ValidationContext validationContext) + { + if (!AppSecret.NullOrEmpty()) { + yield break; + } + + // 没有密码, 就要签名+时间戳 + if (Sign.NullOrEmpty()) { + yield return new ValidationResult(Ln.签名缺失, new[] { nameof(Sign) }); + } + + if (Math.Abs(DateTime.Now.TimeUnixUtc() - Timestamp) > _TS_OFFSET_SCOPE_SEC) { + yield return new ValidationResult(Ln.时间戳缺失或误差过大, new[] { nameof(Timestamp) }); + } + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Contexts/ContextUserInfo.cs b/src/backend/NetAdmin.Domain/Contexts/ContextUserInfo.cs new file mode 100644 index 00000000..481e2133 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Contexts/ContextUserInfo.cs @@ -0,0 +1,26 @@ +using NetAdmin.Domain.Dto.Sys.User; + +namespace NetAdmin.Domain.Contexts; + +/// +/// 上下文用户信息 +/// +public sealed record ContextUserInfo : QueryUserRsp +{ + /// + /// 从HttpContext 创建上下文用户信息 + /// + public static ContextUserInfo Create() + { + var ret = App.HttpContext?.Items[nameof(Chars.FLG_CONTEXT_USER_INFO)] as QueryUserRsp; + return ret?.Adapt(); + } + + /// + /// 是否存在于 HttpContext + /// + public static bool HasInContext() + { + return App.HttpContext?.Items.ContainsKey(Chars.FLG_CONTEXT_USER_INFO) ?? false; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Contexts/ContextUserToken.cs b/src/backend/NetAdmin.Domain/Contexts/ContextUserToken.cs new file mode 100644 index 00000000..b768f7c7 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Contexts/ContextUserToken.cs @@ -0,0 +1,41 @@ +using NetAdmin.Domain.Dto.Sys.User; + +namespace NetAdmin.Domain.Contexts; + +/// +/// 上下文用户凭据 +/// +public sealed record ContextUserToken : DataAbstraction +{ + /// + /// 用户编号 + /// + public long Id { get; set; } + + /// + /// 做授权验证的Token,全局唯一,可以随时重置(强制下线) + /// + public Guid Token { get; init; } + + /// + /// 用户名 + /// + public string UserName { get; init; } + + /// + /// 从HttpContext 创建上下文用户 + /// + public static ContextUserToken Create() + { + var claim = App.User?.FindFirst(nameof(ContextUserToken)); + return claim?.Value.ToObject(); + } + + /// + /// 从 QueryUserRsp 创建上下文用户 + /// + public static ContextUserToken Create(QueryUserRsp user) + { + return new ContextUserToken { Id = user.Id, Token = user.Token, UserName = user.UserName }; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DataAbstraction.cs b/src/backend/NetAdmin.Domain/DataAbstraction.cs new file mode 100644 index 00000000..498be2a0 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DataAbstraction.cs @@ -0,0 +1,36 @@ +namespace NetAdmin.Domain; + +/// +/// 数据基类 +/// +public abstract record DataAbstraction +{ + /// + public override string ToString() + { + return this.ToJson(); + } + + /// + /// 截断所有字符串属性 以符合[MaxLength(x)]特性 + /// + public void TruncateStrings() + { + foreach (var property in GetType() + .GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(x => x.PropertyType == typeof(string))) { + var maxLen = property.GetCustomAttribute(true)?.Length; + if (maxLen is null or 0) { + continue; + } + + var value = property.GetValue(this); + if (value is not string s || s.Length < maxLen) { + continue; + } + + s = s.Sub(0, maxLen.Value); + property.SetValue(this, s); + } + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/EntityBase.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/EntityBase.cs new file mode 100644 index 00000000..db6af365 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/EntityBase.cs @@ -0,0 +1,6 @@ +namespace NetAdmin.Domain.DbMaps.Dependency; + +/// +/// 数据库实体基类 +/// +public abstract record EntityBase : DataAbstraction; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClient.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClient.cs new file mode 100644 index 00000000..3f3687e4 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedClient.cs @@ -0,0 +1,22 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 创建者客户端字段接口 +/// +public interface IFieldCreatedClient +{ + /// + /// 创建者客户端IP + /// + int? CreatedClientIp { get; init; } + + /// + /// 创建者来源地址 + /// + string CreatedReferer { get; init; } + + /// + /// 创建者客户端用户代理 + /// + string CreatedUserAgent { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedTime.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedTime.cs new file mode 100644 index 00000000..e2e2336c --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedTime.cs @@ -0,0 +1,12 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 创建时间字段接口 +/// +public interface IFieldCreatedTime +{ + /// + /// 创建时间 + /// + DateTime CreatedTime { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedUser.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedUser.cs new file mode 100644 index 00000000..4591804c --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldCreatedUser.cs @@ -0,0 +1,17 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 创建用户字段接口 +/// +public interface IFieldCreatedUser +{ + /// + /// 创建者编号 + /// + long? CreatedUserId { get; init; } + + /// + /// 创建者用户名 + /// + string CreatedUserName { get; set; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldEnabled.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldEnabled.cs new file mode 100644 index 00000000..a537d5cb --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldEnabled.cs @@ -0,0 +1,12 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 启用字段接口 +/// +public interface IFieldEnabled +{ + /// + /// 是否启用 + /// + bool Enabled { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClient.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClient.cs new file mode 100644 index 00000000..f95d2c25 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedClient.cs @@ -0,0 +1,17 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 修改客户端字段接口 +/// +public interface IFieldModifiedClient +{ + /// + /// 客户端IP + /// + int ModifiedClientIp { get; init; } + + /// + /// 客户端用户代理 + /// + string ModifiedUserAgent { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedTime.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedTime.cs new file mode 100644 index 00000000..50f55804 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedTime.cs @@ -0,0 +1,12 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 修改时间字段接口 +/// +public interface IFieldModifiedTime +{ + /// + /// 修改时间 + /// + DateTime? ModifiedTime { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedUser.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedUser.cs new file mode 100644 index 00000000..b5fce03d --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldModifiedUser.cs @@ -0,0 +1,17 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 更新用户字段接口 +/// +public interface IFieldModifiedUser +{ + /// + /// 修改者编号 + /// + long? ModifiedUserId { get; init; } + + /// + /// 修改者用户名 + /// + string ModifiedUserName { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldOwner.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldOwner.cs new file mode 100644 index 00000000..91b45072 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldOwner.cs @@ -0,0 +1,17 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 拥有者字段接口 +/// +public interface IFieldOwner +{ + /// + /// 拥有者部门编号 + /// + long? OwnerDeptId { get; init; } + + /// + /// 拥有者用户编号 + /// + long? OwnerId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldPrimary.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldPrimary.cs new file mode 100644 index 00000000..20172a99 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldPrimary.cs @@ -0,0 +1,12 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 主键字段接口 +/// +public interface IFieldPrimary +{ + /// + /// 唯一编码 + /// + T Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldSort.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldSort.cs new file mode 100644 index 00000000..620cc0fa --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldSort.cs @@ -0,0 +1,12 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 排序字段接口 +/// +public interface IFieldSort +{ + /// + /// 排序值,越大越前 + /// + long Sort { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldSummary.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldSummary.cs new file mode 100644 index 00000000..bd93c673 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldSummary.cs @@ -0,0 +1,12 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 描述字段接口 +/// +public interface IFieldSummary +{ + /// + /// 描述 + /// + string Summary { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldVersion.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldVersion.cs new file mode 100644 index 00000000..56d7d54b --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/Fields/IFieldVersion.cs @@ -0,0 +1,12 @@ +namespace NetAdmin.Domain.DbMaps.Dependency.Fields; + +/// +/// 版本字段接口 +/// +public interface IFieldVersion +{ + /// + /// 数据版本 + /// + long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/ImmutableEntity.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/ImmutableEntity.cs new file mode 100644 index 00000000..c18883b8 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/ImmutableEntity.cs @@ -0,0 +1,44 @@ +using NetAdmin.Domain.Attributes; +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.DbMaps.Dependency; + +/// +/// 不可变实体 +/// +public abstract record ImmutableEntity : ImmutableEntity +{ + /// + /// 唯一编码 + /// + [Snowflake] + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public override long Id { get; init; } +} + +/// +/// 不可变实体 +/// +/// +public abstract record ImmutableEntity : LiteImmutableEntity, IFieldCreatedUser +{ + /// + /// 创建者编号 + /// + [JsonIgnore] + [Column(CanUpdate = false, Position = -1)] + public long? CreatedUserId { get; init; } + + /// + /// 创建者用户名 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31, CanUpdate = false, Position = -1)] + public virtual string CreatedUserName { get; set; } + + /// + /// 唯一编码 + /// + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public override T Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/LiteImmutableEntity.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/LiteImmutableEntity.cs new file mode 100644 index 00000000..af30950f --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/LiteImmutableEntity.cs @@ -0,0 +1,38 @@ +using NetAdmin.Domain.Attributes; +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.DbMaps.Dependency; + +/// +/// 轻型不可变实体 +/// +public abstract record LiteImmutableEntity : LiteImmutableEntity +{ + /// + /// 唯一编码 + /// + [Snowflake] + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public override long Id { get; init; } +} + +/// +/// 轻型不可变实体 +/// +/// +public abstract record LiteImmutableEntity : EntityBase, IFieldPrimary, IFieldCreatedTime +{ + /// + /// 创建时间 + /// + [JsonIgnore] + [Column(ServerTime = DateTimeKind.Utc, CanUpdate = false, Position = -1)] + public virtual DateTime CreatedTime { get; init; } + + /// + /// 唯一编码 + /// + [JsonIgnore] + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public virtual T Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/LiteMutableEntity.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/LiteMutableEntity.cs new file mode 100644 index 00000000..7b7e7e93 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/LiteMutableEntity.cs @@ -0,0 +1,36 @@ +using NetAdmin.Domain.Attributes; +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.DbMaps.Dependency; + +/// +/// 轻型可变实体 +/// +public abstract record LiteMutableEntity : LiteMutableEntity +{ + /// + /// 唯一编码 + /// + [Snowflake] + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public override long Id { get; init; } +} + +/// +/// 轻型可变实体 +/// +public abstract record LiteMutableEntity : LiteImmutableEntity, IFieldModifiedTime +{ + /// + /// 唯一编码 + /// + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public override T Id { get; init; } + + /// + /// 修改时间 + /// + [JsonIgnore] + [Column(ServerTime = DateTimeKind.Utc, CanInsert = false, Position = -1)] + public virtual DateTime? ModifiedTime { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/LiteVersionEntity.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/LiteVersionEntity.cs new file mode 100644 index 00000000..10495ca0 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/LiteVersionEntity.cs @@ -0,0 +1,36 @@ +using NetAdmin.Domain.Attributes; +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.DbMaps.Dependency; + +/// +/// 乐观锁轻型可变实体 +/// +public abstract record LiteVersionEntity : LiteVersionEntity +{ + /// + /// 唯一编码 + /// + [Snowflake] + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public override long Id { get; init; } +} + +/// +/// 乐观锁轻型可变实体 +/// +public abstract record LiteVersionEntity : LiteMutableEntity, IFieldVersion +{ + /// + /// 唯一编码 + /// + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public override T Id { get; init; } + + /// + /// 数据版本 + /// + [JsonIgnore] + [Column(IsVersion = true, Position = -1)] + public virtual long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/MutableEntity.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/MutableEntity.cs new file mode 100644 index 00000000..16ce7f87 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/MutableEntity.cs @@ -0,0 +1,43 @@ +using NetAdmin.Domain.Attributes; +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.DbMaps.Dependency; + +/// +/// 可变实体 +/// +public abstract record MutableEntity : MutableEntity +{ + /// + /// 唯一编码 + /// + [Snowflake] + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public override long Id { get; init; } +} + +/// +/// 可变实体 +/// +public abstract record MutableEntity : LiteMutableEntity, IFieldModifiedUser +{ + /// + /// 唯一编码 + /// + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public override T Id { get; init; } + + /// + /// 修改者编号 + /// + [JsonIgnore] + [Column(CanInsert = false, Position = -1)] + public long? ModifiedUserId { get; init; } + + /// + /// 修改者用户名 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31, CanInsert = false, Position = -1)] + public string ModifiedUserName { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/SimpleEntity.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/SimpleEntity.cs new file mode 100644 index 00000000..71bf2c1e --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/SimpleEntity.cs @@ -0,0 +1,6 @@ +namespace NetAdmin.Domain.DbMaps.Dependency; + +/// +/// 简单实体 +/// +public abstract record SimpleEntity : EntityBase; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Dependency/VersionEntity.cs b/src/backend/NetAdmin.Domain/DbMaps/Dependency/VersionEntity.cs new file mode 100644 index 00000000..5d658533 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Dependency/VersionEntity.cs @@ -0,0 +1,43 @@ +using NetAdmin.Domain.Attributes; +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.DbMaps.Dependency; + +/// +/// 乐观锁可变实体 +/// +public abstract record VersionEntity : VersionEntity +{ + /// + /// 唯一编码 + /// + [Snowflake] + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public override long Id { get; init; } +} + +/// +/// 乐观锁可变实体 +/// +public abstract record VersionEntity : LiteVersionEntity, IFieldModifiedUser +{ + /// + /// 唯一编码 + /// + [Column(IsIdentity = false, IsPrimary = true, Position = 1)] + public override T Id { get; init; } + + /// + /// 修改者编号 + /// + [JsonIgnore] + [Column(CanInsert = false, Position = -1)] + public long? ModifiedUserId { get; init; } + + /// + /// 修改者用户名 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31, CanInsert = false, Position = -1)] + public string ModifiedUserName { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Api.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Api.cs new file mode 100644 index 00000000..7b66da95 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Api.cs @@ -0,0 +1,67 @@ +using NetAdmin.Domain.DbMaps.Dependency; +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// Api接口表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_Api))] +public record Sys_Api : ImmutableEntity, IFieldSummary +{ + /// + /// 子节点 + /// + [JsonIgnore] + [Navigate(nameof(ParentId))] + public IEnumerable Children { get; init; } + + /// + /// 唯一编码 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127, IsIdentity = false, IsPrimary = true, Position = 1)] + public override string Id { get; init; } + + /// + /// 请求方式 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_15)] + public virtual string Method { get; init; } + + /// + /// 服务名称 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] + public virtual string Name { get; init; } + + /// + /// 命名空间 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string Namespace { get; init; } + + /// + /// 父编号 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)] + public virtual string ParentId { get; init; } + + /// + /// 角色集合 + /// + [JsonIgnore] + [Navigate(ManyToMany = typeof(Sys_RoleApi))] + public ICollection Roles { get; init; } + + /// + /// 服务描述 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] + public virtual string Summary { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Config.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Config.cs new file mode 100644 index 00000000..73a89a8c --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Config.cs @@ -0,0 +1,53 @@ +using NetAdmin.Domain.DbMaps.Dependency; +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 配置表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_Config))] +public record Sys_Config : VersionEntity, IFieldEnabled +{ + /// + /// 是否启用 + /// + [JsonIgnore] + [Column] + public virtual bool Enabled { get; init; } + + /// + /// 用户注册是否需要人工确认 + /// + [JsonIgnore] + [Column] + public virtual bool UserRegisterConfirm { get; set; } + + /// + /// 用户注册默认部门 + /// + [JsonIgnore] + [Navigate(nameof(UserRegisterDeptId))] + public Sys_Dept UserRegisterDept { get; init; } + + /// + /// 用户注册默认部门编号 + /// + [JsonIgnore] + [Column] + public virtual long UserRegisterDeptId { get; init; } + + /// + /// 用户注册默认角色 + /// + [JsonIgnore] + [Navigate(nameof(UserRegisterRoleId))] + public Sys_Role UserRegisterRole { get; init; } + + /// + /// 用户注册默认角色编号 + /// + [JsonIgnore] + [Column] + public virtual long UserRegisterRoleId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Dept.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Dept.cs new file mode 100644 index 00000000..634c888a --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Dept.cs @@ -0,0 +1,60 @@ +using NetAdmin.Domain.DbMaps.Dependency; +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 部门表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_Dept))] +public record Sys_Dept : VersionEntity, IFieldEnabled, IFieldSummary, IFieldSort +{ + /// + /// 子节点 + /// + [JsonIgnore] + [Navigate(nameof(ParentId))] + public IEnumerable Children { get; init; } + + /// + /// 是否启用 + /// + [JsonIgnore] + [Column] + public virtual bool Enabled { get; init; } + + /// + /// 部门名称 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string Name { get; init; } + + /// + /// 父编号 + /// + [JsonIgnore] + [Column] + public virtual long ParentId { get; init; } + + /// + /// 角色集合 + /// + [JsonIgnore] + [Navigate(ManyToMany = typeof(Sys_RoleDept))] + public ICollection Roles { get; init; } + + /// + /// 排序值,越大越前 + /// + [JsonIgnore] + [Column] + public virtual long Sort { get; init; } + + /// + /// 部门描述 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + public virtual string Summary { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicCatalog.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicCatalog.cs new file mode 100644 index 00000000..ee326b1d --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicCatalog.cs @@ -0,0 +1,46 @@ +using NetAdmin.Domain.DbMaps.Dependency; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 字典目录表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_DicCatalog))] +[Index($"idx_{{tablename}}_{nameof(Code)}", nameof(Code), true)] +public record Sys_DicCatalog : VersionEntity +{ + /// + /// 子节点 + /// + [JsonIgnore] + [Navigate(nameof(ParentId))] + public IEnumerable Children { get; init; } + + /// + /// 字典编码 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string Code { get; init; } + + /// + /// 字典内容集合 + /// + [JsonIgnore] + [Navigate(nameof(Sys_DicContent.CatalogId))] + public ICollection Contents { get; init; } + + /// + /// 字典名称 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string Name { get; init; } + + /// + /// 父编号 + /// + [JsonIgnore] + [Column] + public virtual long ParentId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicContent.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicContent.cs new file mode 100644 index 00000000..bfc0a2aa --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_DicContent.cs @@ -0,0 +1,40 @@ +using NetAdmin.Domain.DbMaps.Dependency; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 字典内容表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_DicContent))] +[Index($"idx_{{tablename}}_{nameof(CatalogId)}_{nameof(Key)}", $"{nameof(CatalogId)},{nameof(Key)}", true)] +[Index($"idx_{{tablename}}_{nameof(CatalogId)}_{nameof(Value)}", $"{nameof(CatalogId)},{nameof(Value)}", true)] +public record Sys_DicContent : VersionEntity +{ + /// + /// 字典目录 + /// + [JsonIgnore] + [Navigate(nameof(CatalogId))] + public Sys_DicCatalog Catalog { get; init; } + + /// + /// 字典目录编号 + /// + [JsonIgnore] + [Column] + public virtual long CatalogId { get; init; } + + /// + /// 键名称 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] + public virtual string Key { get; init; } + + /// + /// 键值 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + public virtual string Value { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Menu.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Menu.cs new file mode 100644 index 00000000..a85073b7 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Menu.cs @@ -0,0 +1,132 @@ +using NetAdmin.Domain.DbMaps.Dependency; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.Enums.Sys; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 菜单表 +/// +[Table(Name = "Sys_Menu")] +[Index($"idx_{{tablename}}_{nameof(Name)}", nameof(Name), true)] +public record Sys_Menu : VersionEntity, IFieldSort +{ + /// + /// 子节点或详情页需要高亮的上级菜单路由地址 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)] + public virtual string Active { get; init; } + + /// + /// 子节点 + /// + [JsonIgnore] + [Navigate(nameof(ParentId))] + public IEnumerable Children { get; init; } + + /// + /// 背景颜色 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_7)] + public virtual string Color { get; init; } + + /// + /// 组件 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] + public virtual string Component { get; init; } + + /// + /// 是否整页路由 + /// + [JsonIgnore] + [Column] + public virtual bool FullPageRouting { get; init; } + + /// + /// 是否隐藏菜单 + /// + [JsonIgnore] + [Column] + public virtual bool Hidden { get; init; } + + /// + /// 是否隐藏面包屑 + /// + [JsonIgnore] + [Column] + public virtual bool HiddenBreadCrumb { get; init; } + + /// + /// 图标 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string Icon { get; init; } + + /// + /// 菜单名称 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] + public virtual string Name { get; init; } + + /// + /// 父编号 + /// + [JsonIgnore] + [Column] + public virtual long ParentId { get; init; } + + /// + /// 菜单路径 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)] + public virtual string Path { get; init; } + + /// + /// 重定向地址 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)] + public virtual string Redirect { get; init; } + + /// + /// 拥有此菜单的角色集合 + /// + [JsonIgnore] + [Navigate(ManyToMany = typeof(Sys_RoleMenu))] + public ICollection Roles { get; init; } + + /// + /// 排序值,越大越前 + /// + [JsonIgnore] + [Column] + public virtual long Sort { get; init; } + + /// + /// 标签 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string Tag { get; init; } + + /// + /// 菜单标题 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] + public virtual string Title { get; init; } + + /// + /// 菜单类型 + /// + [JsonIgnore] + [Column] + public virtual MenuTypes Type { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLog.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLog.cs new file mode 100644 index 00000000..52dca8ac --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLog.cs @@ -0,0 +1,151 @@ +using NetAdmin.Domain.DbMaps.Dependency; +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 请求日志表 +/// +[Table(Name = "Sys_RequestLog")] +public record Sys_RequestLog : ImmutableEntity, IFieldCreatedClient +{ + /// + /// 接口 + /// + [JsonIgnore] + [Navigate(nameof(ApiId))] + public Sys_Api Api { get; init; } + + /// + /// 接口编号 + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)] + [JsonIgnore] + public virtual string ApiId { get; init; } + + /// + /// 创建者客户端IP + /// + [Column(Position = -1)] + [JsonIgnore] + public virtual int? CreatedClientIp { get; init; } + + /// + /// 创建者来源地址 + /// + [Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [JsonIgnore] + public string CreatedReferer { get; init; } + + /// + /// 创建者客户端用户代理 + /// + [Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [JsonIgnore] + public virtual string CreatedUserAgent { get; init; } + + /// + /// 执行耗时(微秒) + /// + [Column] + [JsonIgnore] + public virtual long Duration { get; init; } + + /// + /// 程序响应码 + /// + [Column] + [JsonIgnore] + public virtual ErrorCodes ErrorCode { get; init; } + + /// + /// 异常信息 + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [JsonIgnore] + public virtual string Exception { get; init; } + + /// + /// 附加数据 + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [JsonIgnore] + public virtual string ExtraData { get; init; } + + /// + /// HTTP状态码 + /// + [Column] + [JsonIgnore] + public virtual int HttpStatusCode { get; init; } + + /// + /// 请求方法 + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_15)] + [JsonIgnore] + public virtual string Method { get; init; } + + /// + /// 来源地址 + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [JsonIgnore] + public virtual string ReferUrl { get; init; } + + /// + /// 请求内容 + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [JsonIgnore] + public virtual string RequestBody { get; init; } + + /// + /// 请求content-type + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] + [JsonIgnore] + public virtual string RequestContentType { get; init; } + + /// + /// 请求头信息 + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [JsonIgnore] + public virtual string RequestHeaders { get; init; } + + /// + /// 请求地址 + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)] + [JsonIgnore] + public virtual string RequestUrl { get; init; } + + /// + /// 响应内容 + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [JsonIgnore] + public virtual string ResponseBody { get; init; } + + /// + /// 响应content-type + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] + [JsonIgnore] + public virtual string ResponseContentType { get; init; } + + /// + /// 响应头 + /// + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + [JsonIgnore] + public virtual string ResponseHeaders { get; init; } + + /// + /// 服务器IP + /// + [Column] + [JsonIgnore] + public virtual int? ServerIp { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Role.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Role.cs new file mode 100644 index 00000000..e2f700e4 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_Role.cs @@ -0,0 +1,115 @@ +using NetAdmin.Domain.DbMaps.Dependency; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.Dto.Sys.Role; +using NetAdmin.Domain.Enums.Sys; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 角色表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_Role))] +[Index("idx_{tablename}_01", nameof(Name), true)] +public record Sys_Role : VersionEntity, IFieldSort, IFieldEnabled, IFieldSummary, IRegister +{ + /// + /// 角色-接口映射 + /// + [JsonIgnore] + [Navigate(ManyToMany = typeof(Sys_RoleApi))] + public ICollection Apis { get; init; } + + /// + /// 数据范围 + /// + [JsonIgnore] + [Column] + public virtual DataScopes DataScope { get; init; } + + /// + /// 角色-部门映射 + /// + [JsonIgnore] + [Navigate(ManyToMany = typeof(Sys_RoleDept))] + public ICollection Depts { get; init; } + + /// + /// 是否显示仪表板 + /// + [JsonIgnore] + [Column] + public virtual bool DisplayDashboard { get; init; } + + /// + /// 是否启用 + /// + [JsonIgnore] + [Column] + public virtual bool Enabled { get; init; } + + /// + /// 是否忽略权限控制 + /// + [JsonIgnore] + [Column] + public virtual bool IgnorePermissionControl { get; init; } + + /// + /// 角色-菜单映射 + /// + [JsonIgnore] + [Navigate(ManyToMany = typeof(Sys_RoleMenu))] + public ICollection Menus { get; init; } + + /// + /// 角色名称 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string Name { get; init; } + + /// + /// 排序值,越大越前 + /// + [JsonIgnore] + [Column] + public virtual long Sort { get; init; } + + /// + /// 备注 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + public virtual string Summary { get; init; } + + /// + /// 此角色下的用户集合 + /// + [JsonIgnore] + [Navigate(ManyToMany = typeof(Sys_UserRole))] + public ICollection Users { get; init; } + + /// + public void Register(TypeAdapterConfig config) + { + _ = config.ForType() + .Map( // + d => d.Depts + , s => s.DeptIds.NullOrEmpty() + ? Array.Empty() + : s.DeptIds.Select(x => new Sys_Dept { Id = x })) + .Map( // + d => d.Menus + , s => s.MenuIds.NullOrEmpty() + ? Array.Empty() + : s.MenuIds.Select(x => new Sys_Menu { Id = x })) + .Map( // + d => d.Apis + , s => s.ApiIds.NullOrEmpty() + ? Array.Empty() + : s.ApiIds.Select(x => new Sys_Api { Id = x })) + + // + ; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RoleApi.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RoleApi.cs new file mode 100644 index 00000000..5582acdc --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RoleApi.cs @@ -0,0 +1,36 @@ +using NetAdmin.Domain.DbMaps.Dependency; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 角色-接口映射表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_RoleApi))] +public sealed record Sys_RoleApi : ImmutableEntity +{ + /// + /// 关联的接口 + /// + [JsonIgnore] + public Sys_Api Api { get; init; } + + /// + /// 接口编号 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)] + public string ApiId { get; init; } + + /// + /// 关联的角色 + /// + [JsonIgnore] + public Sys_Role Role { get; init; } + + /// + /// 角色编号 + /// + [JsonIgnore] + [Column] + public long RoleId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RoleDept.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RoleDept.cs new file mode 100644 index 00000000..2bfa7681 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RoleDept.cs @@ -0,0 +1,37 @@ +using NetAdmin.Domain.DbMaps.Dependency; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 角色-部门映射表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_RoleDept))] +[Index($"idx_{{tablename}}_{nameof(RoleId)}_{nameof(DeptId)}", $"{nameof(RoleId)},{nameof(DeptId)}", true)] +public sealed record Sys_RoleDept : ImmutableEntity +{ + /// + /// 关联的部门 + /// + [JsonIgnore] + public Sys_Dept Dept { get; init; } + + /// + /// 可访问的部门编号 + /// + [JsonIgnore] + [Column] + public long DeptId { get; init; } + + /// + /// 关联的角色 + /// + [JsonIgnore] + public Sys_Role Role { get; init; } + + /// + /// 角色编号 + /// + [JsonIgnore] + [Column] + public long RoleId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RoleMenu.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RoleMenu.cs new file mode 100644 index 00000000..8e90d6ad --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RoleMenu.cs @@ -0,0 +1,37 @@ +using NetAdmin.Domain.DbMaps.Dependency; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 角色-菜单映射表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_RoleMenu))] +[Index($"idx_{{tablename}}_{nameof(RoleId)}_{nameof(MenuId)}", $"{nameof(RoleId)},{nameof(MenuId)}", true)] +public record Sys_RoleMenu : ImmutableEntity +{ + /// + /// 关联的菜单 + /// + [JsonIgnore] + public Sys_Menu Menu { get; init; } + + /// + /// 菜单编号 + /// + [JsonIgnore] + [Column] + public virtual long MenuId { get; init; } + + /// + /// 关联的角色 + /// + [JsonIgnore] + public Sys_Role Role { get; init; } + + /// + /// 角色编号 + /// + [JsonIgnore] + [Column] + public virtual long RoleId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_User.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_User.cs new file mode 100644 index 00000000..ab0af16e --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_User.cs @@ -0,0 +1,120 @@ +using NetAdmin.Domain.DbMaps.Dependency; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.Dto.Sys.User; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 用户基本信息表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_User))] +[Index($"idx_{{tablename}}_{nameof(UserName)}", nameof(UserName), true)] +[Index($"idx_{{tablename}}_{nameof(Mobile)}", nameof(Mobile), true)] +[Index($"idx_{{tablename}}_{nameof(Email)}", nameof(Email), true)] +public record Sys_User : VersionEntity, IFieldSummary, IFieldEnabled, IRegister +{ + /// + /// 头像链接 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)] + public virtual string Avatar { get; init; } + + /// + /// 所属部门 + /// + [JsonIgnore] + [Navigate(nameof(DeptId))] + public Sys_Dept Dept { get; init; } + + /// + /// 部门编号 + /// + [JsonIgnore] + [Column] + public virtual long DeptId { get; init; } + + /// + /// 邮箱 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] + public virtual string Email { get; init; } + + /// + /// 是否启用 + /// + [JsonIgnore] + [Column] + public virtual bool Enabled { get; init; } + + /// + /// 手机号 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_15)] + public virtual string Mobile { get; init; } + + /// + /// 密码 + /// + [JsonIgnore] + [Column] + public Guid Password { get; set; } + + /// + /// 用户档案 + /// + [JsonIgnore] + public Sys_UserProfile Profile { get; init; } + + /// + /// 所属角色 + /// + [JsonIgnore] + [Navigate(ManyToMany = typeof(Sys_UserRole))] + public ICollection Roles { get; init; } + + /// + /// 描述 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + public virtual string Summary { get; init; } + + /// + /// 授权验证Token,全局唯一,可以随时重置(强制下线) + /// + [JsonIgnore] + [Column] + public Guid Token { get; init; } + + /// + /// 用户名 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string UserName { get; init; } + + /// + public void Register(TypeAdapterConfig config) + { + _ = config.ForType() + .Map(d => d.Password, s => s.PasswordText.Pwd().Guid()) + .Map(d => d.Token, _ => Guid.NewGuid()) + .Map( // + d => d.Roles + , s => s.RoleIds.NullOrEmpty() + ? Array.Empty() + : s.RoleIds.Select(x => new Sys_Role { Id = x })); + + _ = config.ForType() + .Map( // + d => d.Password, s => s.PasswordText.NullOrEmpty() ? Guid.Empty : s.PasswordText.Pwd().Guid()) + .Map( // + d => d.Roles + , s => s.RoleIds.NullOrEmpty() + ? Array.Empty() + : s.RoleIds.Select(x => new Sys_Role { Id = x })); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_UserProfile.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_UserProfile.cs new file mode 100644 index 00000000..35e67df8 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_UserProfile.cs @@ -0,0 +1,198 @@ +using NetAdmin.Domain.DbMaps.Dependency; +using NetAdmin.Domain.Dto.Sys.UserProfile; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 用户档案表 +/// +[Table(Name = "Sys_UserProfile")] +public record Sys_UserProfile : VersionEntity, IRegister +{ + /// + /// 出生日期 + /// + [JsonIgnore] + [Column] + public virtual DateTime? BornDate { get; init; } + + /// + /// 证件号码 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] + public virtual string CertificateNumber { get; init; } + + /// + /// 证件类型 + /// + [JsonIgnore] + [Column] + public virtual CertificateTypes? CertificateType { get; init; } + + /// + /// 工作地址 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)] + public virtual string CompanyAddress { get; init; } + + /// + /// 工作地区 + /// + [JsonIgnore] + [Column] + public int? CompanyArea { get; init; } + + /// + /// 工作单位 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string CompanyName { get; init; } + + /// + /// 工作电话 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string CompanyTelephone { get; init; } + + /// + /// 文化程度 + /// + [JsonIgnore] + [Column] + public virtual Educations? Education { get; init; } + + /// + /// 紧急联系地址 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)] + public virtual string EmergencyContactAddress { get; init; } + + /// + /// 紧急联系地区 + /// + [JsonIgnore] + [Column] + public int? EmergencyContactArea { get; init; } + + /// + /// 紧急联系人手机号 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_15)] + public virtual string EmergencyContactMobile { get; init; } + + /// + /// 紧急联系人 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string EmergencyContactName { get; init; } + + /// + /// 毕业学校 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string GraduateSchool { get; init; } + + /// + /// 身高 + /// + [JsonIgnore] + [Column] + public virtual int? Height { get; init; } + + /// + /// 住宅地址 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)] + public virtual string HomeAddress { get; init; } + + /// + /// 住宅地区 + /// + [JsonIgnore] + [Column] + public int? HomeArea { get; init; } + + /// + /// 住宅电话 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string HomeTelephone { get; init; } + + /// + /// 婚姻状况 + /// + [JsonIgnore] + [Column] + public virtual MarriageStatues? MarriageStatus { get; init; } + + /// + /// 民族 + /// + /// 7 + [JsonIgnore] + [Column] + public virtual Nations? Nation { get; init; } + + /// + /// 籍贯 + /// + [JsonIgnore] + [Column] + public int? NationArea { get; init; } + + /// + /// 政治面貌 + /// + [JsonIgnore] + [Column] + public virtual PoliticalStatues? PoliticalStatus { get; init; } + + /// + /// 职业 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string Profession { get; init; } + + /// + /// 真实姓名 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)] + public virtual string RealName { get; init; } + + /// + /// 性别 + /// + [JsonIgnore] + [Column] + public virtual Sexes? Sex { get; init; } + + /// + /// 用户基本信息 + /// + [JsonIgnore] + public Sys_User User { get; init; } + + /// + public void Register(TypeAdapterConfig config) + { + _ = config.ForType() + .Map(d => d.NationArea, s => s.NationArea == null ? null : s.NationArea.Value) + .Map(d => d.CompanyArea, s => s.CompanyArea == null ? null : s.CompanyArea.Value) + .Map(d => d.HomeArea, s => s.HomeArea == null ? null : s.HomeArea.Value) + .Map( // + d => d.EmergencyContactArea + , s => s.EmergencyContactArea == null ? null : s.EmergencyContactArea.Value); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_UserRole.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_UserRole.cs new file mode 100644 index 00000000..05f99f72 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_UserRole.cs @@ -0,0 +1,36 @@ +using NetAdmin.Domain.DbMaps.Dependency; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 用户-角色映射表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_UserRole))] +public sealed record Sys_UserRole : VersionEntity +{ + /// + /// 关联的角色 + /// + [JsonIgnore] + public Sys_Role Role { get; init; } + + /// + /// 角色编号 + /// + [JsonIgnore] + [Column] + public long RoleId { get; init; } + + /// + /// 关联的用户 + /// + [JsonIgnore] + public Sys_User User { get; init; } + + /// + /// 用户编号 + /// + [JsonIgnore] + [Column] + public long UserId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_VerifyCode.cs b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_VerifyCode.cs new file mode 100644 index 00000000..bd4a864e --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_VerifyCode.cs @@ -0,0 +1,53 @@ +using NetAdmin.Domain.DbMaps.Dependency; +using NetAdmin.Domain.Enums.Sys; + +namespace NetAdmin.Domain.DbMaps.Sys; + +/// +/// 验证码表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Sys_VerifyCode))] +public record Sys_VerifyCode : VersionEntity +{ + /// + /// 验证码 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_7)] + public virtual string Code { get; init; } + + /// + /// 目标设备 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] + public virtual string DestDevice { get; init; } + + /// + /// 设备类型 + /// + [JsonIgnore] + [Column] + public virtual VerifyCodeDeviceTypes DeviceType { get; init; } + + /// + /// 发送报告 + /// + [JsonIgnore] + [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)] + public string Report { get; init; } + + /// + /// 验证码状态 + /// + [JsonIgnore] + [Column] + public virtual VerifyCodeStatues Status { get; init; } + + /// + /// 验证码类型 + /// + [JsonIgnore] + [Column] + public virtual VerifyCodeTypes Type { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/DbMaps/Tpl/Tpl_Example.cs b/src/backend/NetAdmin.Domain/DbMaps/Tpl/Tpl_Example.cs new file mode 100644 index 00000000..421c1f79 --- /dev/null +++ b/src/backend/NetAdmin.Domain/DbMaps/Tpl/Tpl_Example.cs @@ -0,0 +1,9 @@ +using NetAdmin.Domain.DbMaps.Dependency; + +namespace NetAdmin.Domain.DbMaps.Tpl; + +/// +/// 示例表 +/// +[Table(Name = Chars.FLG_TABLE_NAME_PREFIX + nameof(Tpl_Example))] +public record Tpl_Example : VersionEntity; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Dependency/BulkReq.cs b/src/backend/NetAdmin.Domain/Dto/Dependency/BulkReq.cs new file mode 100644 index 00000000..20a7a1f4 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Dependency/BulkReq.cs @@ -0,0 +1,18 @@ +using NetAdmin.Domain.Attributes.DataValidation; + +namespace NetAdmin.Domain.Dto.Dependency; + +/// +/// 批量请求 +/// +public sealed record BulkReq : DataAbstraction + where T : DataAbstraction, new() +{ + /// + /// 请求对象 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.请求对象))] + [MinLength(1)] + [MaxLength(Numbers.BULK_REQ_LIMIT)] + public IEnumerable Items { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Dependency/DelReq.cs b/src/backend/NetAdmin.Domain/Dto/Dependency/DelReq.cs new file mode 100644 index 00000000..d33eaec2 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Dependency/DelReq.cs @@ -0,0 +1,16 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.Dto.Dependency; + +/// +public sealed record DelReq : DelReq; + +/// +/// 请求:通过编号删除 +/// +/// +public record DelReq : DataAbstraction, IFieldPrimary +{ + /// + public T Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Dependency/IPagedInfo.cs b/src/backend/NetAdmin.Domain/Dto/Dependency/IPagedInfo.cs new file mode 100644 index 00000000..c02bb3fe --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Dependency/IPagedInfo.cs @@ -0,0 +1,17 @@ +namespace NetAdmin.Domain.Dto.Dependency; + +/// +/// 信息:分页 +/// +public interface IPagedInfo +{ + /// + /// 当前页码 + /// + int Page { get; init; } + + /// + /// 页容量 + /// + int PageSize { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Dependency/NopReq.cs b/src/backend/NetAdmin.Domain/Dto/Dependency/NopReq.cs new file mode 100644 index 00000000..667c3045 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Dependency/NopReq.cs @@ -0,0 +1,6 @@ +namespace NetAdmin.Domain.Dto.Dependency; + +/// +/// 空请求 +/// +public sealed record NopReq : DataAbstraction; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Dependency/PagedQueryReq.cs b/src/backend/NetAdmin.Domain/Dto/Dependency/PagedQueryReq.cs new file mode 100644 index 00000000..0f4a3a4a --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Dependency/PagedQueryReq.cs @@ -0,0 +1,16 @@ +namespace NetAdmin.Domain.Dto.Dependency; + +/// +/// 请求:分页查询 +/// +public sealed record PagedQueryReq : QueryReq, IPagedInfo + where T : DataAbstraction, new() +{ + /// + [Range(1, Numbers.QUERY_MAX_PAGE_NO)] + public int Page { get; init; } = 1; + + /// + [Range(1, Numbers.QUERY_MAX_PAGE_SIZE)] + public int PageSize { get; init; } = Numbers.QUERY_DEF_PAGE_SIZE; +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Dependency/PagedQueryRsp.cs b/src/backend/NetAdmin.Domain/Dto/Dependency/PagedQueryRsp.cs new file mode 100644 index 00000000..b341b454 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Dependency/PagedQueryRsp.cs @@ -0,0 +1,24 @@ +namespace NetAdmin.Domain.Dto.Dependency; + +/// +/// 响应:分页查询 +/// +public sealed record PagedQueryRsp(int Page, int PageSize, long Total, IEnumerable Rows) : IPagedInfo + where T : DataAbstraction +{ + /// + public int Page { get; init; } = Page; + + /// + public int PageSize { get; init; } = PageSize; + + /// + /// 数据行 + /// + public IEnumerable Rows { get; init; } = Rows; + + /// + /// 数据总条 + /// + public long Total { get; init; } = Total; +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Dependency/QueryReq.cs b/src/backend/NetAdmin.Domain/Dto/Dependency/QueryReq.cs new file mode 100644 index 00000000..b69b191c --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Dependency/QueryReq.cs @@ -0,0 +1,39 @@ +namespace NetAdmin.Domain.Dto.Dependency; + +/// +/// 请求:查询 +/// +public record QueryReq : DataAbstraction + where T : DataAbstraction, new() +{ + /// + /// 取前n条 + /// + [Range(1, Numbers.QUERY_LIMIT)] + public int Count { get; init; } = Numbers.QUERY_LIMIT; + + /// + /// 动态查询条件 + /// + public DynamicFilterInfo DynamicFilter { get; init; } + + /// + /// 查询条件 + /// + public T Filter { get; init; } + + /// + /// 查询关键字 + /// + public string Keywords { get; set; } + + /// + /// 排序方式 + /// + public Orders? Order { get; init; } + + /// + /// 排序字段 + /// + public string Prop { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/RestfulInfo.cs b/src/backend/NetAdmin.Domain/Dto/RestfulInfo.cs new file mode 100644 index 00000000..08856711 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/RestfulInfo.cs @@ -0,0 +1,23 @@ +namespace NetAdmin.Domain.Dto; + +/// +/// 信息:RESTful 风格结果集 +/// +public record RestfulInfo : DataAbstraction +{ + /// + /// 代码 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public ErrorCodes Code { get; init; } + + /// + /// 数据 + /// + public T Data { get; init; } + + /// + /// 消息 + /// + public object Msg { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Api/CreateApiReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Api/CreateApiReq.cs new file mode 100644 index 00000000..7c600097 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Api/CreateApiReq.cs @@ -0,0 +1,8 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Api; + +/// +/// 请求:创建接口 +/// +public sealed record CreateApiReq : Sys_Api; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Api/QueryApiReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Api/QueryApiReq.cs new file mode 100644 index 00000000..fb0e1310 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Api/QueryApiReq.cs @@ -0,0 +1,8 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Api; + +/// +/// 请求:查询接口 +/// +public sealed record QueryApiReq : Sys_Api; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Api/QueryApiRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Api/QueryApiRsp.cs new file mode 100644 index 00000000..05558293 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Api/QueryApiRsp.cs @@ -0,0 +1,38 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Api; + +/// +/// 响应:查询接口 +/// +public sealed record QueryApiRsp : Sys_Api +{ + /// + /// 子节点 + /// + public new IEnumerable Children { get; init; } + + /// + public override string Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Method { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Name { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Namespace { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string ParentId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Summary { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Cache/CacheStatisticsRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Cache/CacheStatisticsRsp.cs new file mode 100644 index 00000000..c1396d69 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Cache/CacheStatisticsRsp.cs @@ -0,0 +1,71 @@ +namespace NetAdmin.Domain.Dto.Sys.Cache; + +/// +/// 响应:缓存统计 +/// +public sealed record CacheStatisticsRsp : DataAbstraction +{ + private static readonly Regex[] _regexes = { + new(@"keyspace_hits:(\d+)", RegexOptions.Compiled) + , new(@"keyspace_misses:(\d+)", RegexOptions.Compiled) + , new(@"uptime_in_seconds:(\d+)", RegexOptions.Compiled) + , new(@"used_cpu_sys:([\d\\.]+)", RegexOptions.Compiled) + , new(@"used_cpu_user:([\d\\.]+)", RegexOptions.Compiled) + , new(@"used_memory:(\d+)", RegexOptions.Compiled) + , new("redis_version:(.+)", RegexOptions.Compiled) + }; + + /// + /// Initializes a new instance of the class. + /// + public CacheStatisticsRsp() { } + + /// + /// Initializes a new instance of the class. + /// + public CacheStatisticsRsp(string redisResult) + { + KeyspaceHits = _regexes[0].Match(redisResult).Groups[1].Value.Trim().Int64Try(0); + KeyspaceMisses = _regexes[1].Match(redisResult).Groups[1].Value.Trim().Int64Try(0); + UpTime = _regexes[2].Match(redisResult).Groups[1].Value.Trim().Int64Try(0); + UsedCpu = _regexes[3].Match(redisResult).Groups[1].Value.Trim().DecTry(0) + + _regexes[4].Match(redisResult).Groups[1].Value.Trim().DecTry(0); + UsedMemory = _regexes[5].Match(redisResult).Groups[1].Value.Trim().Int64Try(0); + Version = _regexes[6].Match(redisResult).Groups[1].Value.Trim(); + } + + /// + /// 键总数 + /// + public long DbSize { get; init; } + + /// + /// 命中键的数量 + /// + public long KeyspaceHits { get; init; } + + /// + /// 未命中键的数量 + /// + public long KeyspaceMisses { get; init; } + + /// + /// Redis运行时间(秒) + /// + public long UpTime { get; init; } + + /// + /// 使用的CPU时间(秒) + /// + public decimal UsedCpu { get; init; } + + /// + /// 使用的内存量(字节) + /// + public long UsedMemory { get; init; } + + /// + /// Redis版本号 + /// + public string Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Cache/GetAllEntriesReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Cache/GetAllEntriesReq.cs new file mode 100644 index 00000000..e44860f8 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Cache/GetAllEntriesReq.cs @@ -0,0 +1,12 @@ +namespace NetAdmin.Domain.Dto.Sys.Cache; + +/// +/// 请求:获取所有缓存项 +/// +public sealed record GetAllEntriesReq : DataAbstraction +{ + /// + /// 数据库索引号 + /// + public uint DbIndex { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Cache/GetAllEntriesRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Cache/GetAllEntriesRsp.cs new file mode 100644 index 00000000..fd386241 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Cache/GetAllEntriesRsp.cs @@ -0,0 +1,43 @@ +namespace NetAdmin.Domain.Dto.Sys.Cache; + +/// +/// 响应:获取所有缓存项 +/// +public sealed record GetAllEntriesRsp : DataAbstraction +{ + /// + /// Initializes a new instance of the class. + /// + public GetAllEntriesRsp() { } + + /// + /// Initializes a new instance of the class. + /// + public GetAllEntriesRsp(long absExp, string key, long sldExp, string data) + { + AbsExp = absExp; + Key = key; + SldExp = sldExp; + Data = data; + } + + /// + /// 绝对过期时间 + /// + public long AbsExp { get; init; } + + /// + /// 缓存值 + /// + public string Data { get; init; } + + /// + /// 缓存键 + /// + public string Key { get; init; } + + /// + /// 滑动过期时间 + /// + public long SldExp { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Captcha/GetCaptchaRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Captcha/GetCaptchaRsp.cs new file mode 100644 index 00000000..2472c75e --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Captcha/GetCaptchaRsp.cs @@ -0,0 +1,28 @@ +namespace NetAdmin.Domain.Dto.Sys.Captcha; + +/// +/// 响应:获取人机校验图 +/// +public sealed record GetCaptchaRsp : DataAbstraction +{ + /// + /// 背景图(base64) + /// + public string BackgroundImage { get; init; } + + /// + /// 唯一编码 + /// + public string Id { get; init; } + + /// + /// 缺口x坐标 + /// + [JsonIgnore] + public int SawOffsetX { get; init; } + + /// + /// 滑块图(base64) + /// + public string SliderImage { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Captcha/VerifyCaptchaReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Captcha/VerifyCaptchaReq.cs new file mode 100644 index 00000000..c8ac2893 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Captcha/VerifyCaptchaReq.cs @@ -0,0 +1,27 @@ +using NetAdmin.Domain.Attributes.DataValidation; + +namespace NetAdmin.Domain.Dto.Sys.Captcha; + +/// +/// 请求:完成人机验证 +/// +public sealed record VerifyCaptchaReq : DataAbstraction +{ + /// + /// 唯一编码 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.唯一编码))] + public string Id { get; init; } + + /// + /// 缺口x坐标 + /// + [JsonIgnore] + public int? SawOffsetX { get; init; } + + /// + /// 验证数据 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.验证数据))] + public string VerifyData { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Config/CreateConfigReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Config/CreateConfigReq.cs new file mode 100644 index 00000000..5db55870 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Config/CreateConfigReq.cs @@ -0,0 +1,26 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Config; + +/// +/// 请求:创建配置 +/// +public record CreateConfigReq : Sys_Config +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool Enabled { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool UserRegisterConfirm { get; set; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long UserRegisterDeptId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long UserRegisterRoleId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Config/QueryConfigReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Config/QueryConfigReq.cs new file mode 100644 index 00000000..3e753085 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Config/QueryConfigReq.cs @@ -0,0 +1,20 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Config; + +/// +/// 请求:查询配置 +/// +public sealed record QueryConfigReq : Sys_Config +{ + /// + /// 是否启用 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public new bool? Enabled { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Config/QueryConfigRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Config/QueryConfigRsp.cs new file mode 100644 index 00000000..281583b5 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Config/QueryConfigRsp.cs @@ -0,0 +1,44 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.Dept; +using NetAdmin.Domain.Dto.Sys.Role; + +namespace NetAdmin.Domain.Dto.Sys.Config; + +/// +/// 响应:查询配置 +/// +public sealed record QueryConfigRsp : Sys_Config +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool Enabled { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool UserRegisterConfirm { get; set; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public new QueryDeptRsp UserRegisterDept { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long UserRegisterDeptId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public new QueryRoleRsp UserRegisterRole { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long UserRegisterRoleId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Config/UpdateConfigReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Config/UpdateConfigReq.cs new file mode 100644 index 00000000..11cd77ba --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Config/UpdateConfigReq.cs @@ -0,0 +1,13 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.Dto.Sys.Config; + +/// +/// 请求:更新配置 +/// +public sealed record UpdateConfigReq : CreateConfigReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dept/CreateDeptReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dept/CreateDeptReq.cs new file mode 100644 index 00000000..0f8620c5 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dept/CreateDeptReq.cs @@ -0,0 +1,32 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Dept; + +/// +/// 请求:创建部门 +/// +public record CreateDeptReq : Sys_Dept +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool Enabled { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.部门名称))] + public override string Name { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long ParentId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Sort { get; init; } = Numbers.DEF_SORT_VAL; + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Summary { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dept/QueryDeptReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dept/QueryDeptReq.cs new file mode 100644 index 00000000..891961cb --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dept/QueryDeptReq.cs @@ -0,0 +1,14 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Dept; + +/// +/// 请求:查询部门 +/// +public sealed record QueryDeptReq : Sys_Dept +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dept/QueryDeptRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dept/QueryDeptRsp.cs new file mode 100644 index 00000000..fb594b17 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dept/QueryDeptRsp.cs @@ -0,0 +1,47 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Dept; + +/// +/// 响应:查询部门 +/// +public record QueryDeptRsp : Sys_Dept +{ + /// + /// 子节点 + /// + public new virtual IEnumerable Children { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override DateTime CreatedTime { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool Enabled { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Name { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long ParentId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Sort { get; init; } = Numbers.DEF_SORT_VAL; + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Summary { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dept/UpdateDeptReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dept/UpdateDeptReq.cs new file mode 100644 index 00000000..eba8983e --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dept/UpdateDeptReq.cs @@ -0,0 +1,17 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.Dto.Sys.Dept; + +/// +/// 请求:更新部门 +/// +public sealed record UpdateDeptReq : CreateDeptReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dev/GenerateCsCodeReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dev/GenerateCsCodeReq.cs new file mode 100644 index 00000000..c6fc980c --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dev/GenerateCsCodeReq.cs @@ -0,0 +1,22 @@ +namespace NetAdmin.Domain.Dto.Sys.Dev; + +/// +/// 请求:生成后端代码 +/// +public sealed record GenerateCsCodeReq : DataAbstraction +{ + /// + /// 模块名称 + /// + public string ModuleName { get; init; } + + /// + /// 模块说明 + /// + public string ModuleRemark { get; init; } + + /// + /// 模块类型 + /// + public ModuleTypes Type { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dev/GenerateIconCodeReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dev/GenerateIconCodeReq.cs new file mode 100644 index 00000000..f6503ef1 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dev/GenerateIconCodeReq.cs @@ -0,0 +1,21 @@ +using NetAdmin.Domain.Attributes.DataValidation; + +namespace NetAdmin.Domain.Dto.Sys.Dev; + +/// +/// 请求:生成图标代码 +/// +public sealed record GenerateIconCodeReq : DataAbstraction +{ + /// + /// 图标名称 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.图标名称))] + public string IconName { get; init; } + + /// + /// 图标代码 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.图标代码))] + public string SvgCode { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dev/IconExportJsInfo.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dev/IconExportJsInfo.cs new file mode 100644 index 00000000..820fb60e --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dev/IconExportJsInfo.cs @@ -0,0 +1,39 @@ +namespace NetAdmin.Domain.Dto.Sys.Dev; + +/// +/// IconExportJsInfo +/// +public sealed record IconExportJsInfo : DataAbstraction +{ + /// + /// ExportDefault + /// + public ExportDefaultRecord ExportDefault { get; init; } + + /// + /// ExportDefaultRecord + /// + public sealed record ExportDefaultRecord + { + /// + /// Icons + /// + public IEnumerable Icons { get; init; } + } + + /// + /// IconsItem + /// + public sealed record IconsItem + { + /// + /// Icons + /// + public ICollection Icons { get; init; } + + /// + /// Name + /// + public string Name { get; init; } + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/CreateDicCatalogReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/CreateDicCatalogReq.cs new file mode 100644 index 00000000..bab0c3ed --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/CreateDicCatalogReq.cs @@ -0,0 +1,24 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Dic.Catalog; + +/// +/// 请求:创建字典目录 +/// +public record CreateDicCatalogReq : Sys_DicCatalog +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.字典编码))] + public override string Code { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.字典名称))] + public override string Name { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long ParentId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/QueryDicCatalogReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/QueryDicCatalogReq.cs new file mode 100644 index 00000000..7109e016 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/QueryDicCatalogReq.cs @@ -0,0 +1,8 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Dic.Catalog; + +/// +/// 请求:查询字典目录 +/// +public sealed record QueryDicCatalogReq : Sys_DicCatalog; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/QueryDicCatalogRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/QueryDicCatalogRsp.cs new file mode 100644 index 00000000..d85e86d7 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/QueryDicCatalogRsp.cs @@ -0,0 +1,35 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Dic.Catalog; + +/// +/// 响应:查询字典目录 +/// +public sealed record QueryDicCatalogRsp : Sys_DicCatalog +{ + /// + /// 子节点 + /// + public new IEnumerable Children { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Code { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Name { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long ParentId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/UpdateDicCatalogReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/UpdateDicCatalogReq.cs new file mode 100644 index 00000000..cb71d31f --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Catalog/UpdateDicCatalogReq.cs @@ -0,0 +1,13 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.Dto.Sys.Dic.Catalog; + +/// +/// 请求:更新字典目录 +/// +public sealed record UpdateDicCatalogReq : CreateDicCatalogReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/CreateDicContentReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/CreateDicContentReq.cs new file mode 100644 index 00000000..49e1affc --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/CreateDicContentReq.cs @@ -0,0 +1,25 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Dic.Content; + +/// +/// 请求:创建字典内容 +/// +public record CreateDicContentReq : Sys_DicContent +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.字典目录编号))] + public override long CatalogId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.键名称))] + public override string Key { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.键值))] + public override string Value { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/QueryDicContentReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/QueryDicContentReq.cs new file mode 100644 index 00000000..542721db --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/QueryDicContentReq.cs @@ -0,0 +1,8 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Dic.Content; + +/// +/// 请求:查询字典内容 +/// +public sealed record QueryDicContentReq : Sys_DicContent; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/QueryDicContentRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/QueryDicContentRsp.cs new file mode 100644 index 00000000..f1fcdecd --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/QueryDicContentRsp.cs @@ -0,0 +1,30 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Dic.Content; + +/// +/// 响应:查询字典内容 +/// +public sealed record QueryDicContentRsp : Sys_DicContent +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long CatalogId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override DateTime CreatedTime { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Key { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Value { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/UpdateDicContentReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/UpdateDicContentReq.cs new file mode 100644 index 00000000..c2a1ba76 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Dic/Content/UpdateDicContentReq.cs @@ -0,0 +1,13 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.Dto.Sys.Dic.Content; + +/// +/// 请求:更新字典内容 +/// +public sealed record UpdateDicContentReq : CreateDicContentReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Menu/CreateMenuReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Menu/CreateMenuReq.cs new file mode 100644 index 00000000..9230f278 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Menu/CreateMenuReq.cs @@ -0,0 +1,72 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Enums.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Menu; + +/// +/// 请求:创建菜单 +/// +public record CreateMenuReq : Sys_Menu +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Active { get; init; } + + /// + public override string Color => Meta.Color; + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Component { get; init; } + + /// + public override bool FullPageRouting => Meta.FullPage; + + /// + public override bool Hidden => Meta.Hidden; + + /// + public override bool HiddenBreadCrumb => Meta.HiddenBreadCrumb; + + /// + public override string Icon => Meta.Icon; + + /// + /// 元数据 + /// + public MetaInfo Meta { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.菜单名称))] + public override string Name { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long ParentId { get; init; } = 0; + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Path { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Redirect { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Sort { get; init; } = Numbers.DEF_SORT_VAL; + + /// + public override string Tag => Meta.Tag; + + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.菜单标题))] + public override string Title => Meta.Title; + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override MenuTypes Type => Meta.Type; +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Menu/MetaInfo.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Menu/MetaInfo.cs new file mode 100644 index 00000000..04879e31 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Menu/MetaInfo.cs @@ -0,0 +1,71 @@ +using NetAdmin.Domain.Enums.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Menu; + +/// +/// 信息:元数据 +/// +public sealed record MetaInfo : DataAbstraction +{ + /// + /// Initializes a new instance of the class. + /// + public MetaInfo() { } + + /// + /// Initializes a new instance of the class. + /// + public MetaInfo(string color, bool fullPage, bool hidden, bool hiddenBreadCrumb, string icon, string tag + , string title, MenuTypes type) + { + Color = color; + FullPage = fullPage; + Hidden = hidden; + HiddenBreadCrumb = hiddenBreadCrumb; + Icon = icon; + Tag = tag; + Title = title; + Type = type; + } + + /// + /// 背景颜色 + /// + public string Color { get; init; } + + /// + /// 是否整页路由 + /// + public bool FullPage { get; init; } + + /// + /// 是否隐藏 + /// + public bool Hidden { get; init; } + + /// + /// 是否隐藏面包屑 + /// + public bool HiddenBreadCrumb { get; init; } + + /// + /// 图标 + /// + public string Icon { get; init; } + + /// + /// 标签 + /// + public string Tag { get; init; } + + /// + /// 标题 + /// + public string Title { get; init; } + + /// + /// 类型 + /// + [EnumDataType(typeof(MenuTypes))] + public MenuTypes Type { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Menu/QueryMenuReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Menu/QueryMenuReq.cs new file mode 100644 index 00000000..bf2af730 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Menu/QueryMenuReq.cs @@ -0,0 +1,14 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Menu; + +/// +/// 请求:查询菜单 +/// +public sealed record QueryMenuReq : Sys_Menu +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Menu/QueryMenuRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Menu/QueryMenuRsp.cs new file mode 100644 index 00000000..054a19a9 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Menu/QueryMenuRsp.cs @@ -0,0 +1,78 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Menu; + +/// +/// 信息:菜单 +/// +public sealed record QueryMenuRsp : Sys_Menu, IRegister +{ + /// + /// 元数据 + /// + public MetaInfo Meta => new(Color, FullPageRouting, Hidden, HiddenBreadCrumb, Icon, Tag, Title, Type); + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Active { get; init; } + + /// + /// 子节点 + /// + public new IEnumerable Children { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Component { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool FullPageRouting { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool Hidden { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool HiddenBreadCrumb { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Name { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long ParentId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Path { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Redirect { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Sort { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } + + /// + public void Register(TypeAdapterConfig config) + { + _ = config.ForType() // + .Map(d => d.Path, s => s.Path ?? string.Empty) + + // + ; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Menu/UpdateMenuReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Menu/UpdateMenuReq.cs new file mode 100644 index 00000000..d0275beb --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Menu/UpdateMenuReq.cs @@ -0,0 +1,17 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.Dto.Sys.Menu; + +/// +/// 请求:更新菜单 +/// +public sealed record UpdateMenuReq : CreateMenuReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/CreateRequestLogReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/CreateRequestLogReq.cs new file mode 100644 index 00000000..bbf1681a --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/CreateRequestLogReq.cs @@ -0,0 +1,8 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.RequestLog; + +/// +/// 请求:创建请求日志 +/// +public sealed record CreateRequestLogReq : Sys_RequestLog; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/QueryRequestLogReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/QueryRequestLogReq.cs new file mode 100644 index 00000000..9d175f7b --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/QueryRequestLogReq.cs @@ -0,0 +1,8 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.RequestLog; + +/// +/// 请求:查询请求日志 +/// +public sealed record QueryRequestLogReq : Sys_RequestLog; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/QueryRequestLogRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/QueryRequestLogRsp.cs new file mode 100644 index 00000000..dd979b8d --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/RequestLog/QueryRequestLogRsp.cs @@ -0,0 +1,106 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.RequestLog; + +/// +/// 响应:查询请求日志 +/// +public sealed record QueryRequestLogRsp : Sys_RequestLog, IRegister +{ + /// + /// 操作系统 + /// + public string Os => UserAgentParser.Create(CreatedUserAgent).Platform; + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string ApiId { get; init; } + + /// + /// 接口描述 + /// + public string ApiSummary { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override int? CreatedClientIp { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override DateTime CreatedTime { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string CreatedUserAgent { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string CreatedUserName { get; set; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Duration { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override ErrorCodes ErrorCode { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Exception { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string ExtraData { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override int HttpStatusCode { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Method { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string ReferUrl { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string RequestBody { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string RequestContentType { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string RequestHeaders { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string RequestUrl { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string ResponseBody { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string ResponseContentType { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string ResponseHeaders { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override int? ServerIp { get; init; } + + /// + public void Register(TypeAdapterConfig config) + { + _ = config.ForType().Map(dest => dest.ApiSummary, src => src.Api.Summary); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Role/CreateRoleReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Role/CreateRoleReq.cs new file mode 100644 index 00000000..c762b7b0 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Role/CreateRoleReq.cs @@ -0,0 +1,57 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Enums.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Role; + +/// +/// 请求:创建角色 +/// +public record CreateRoleReq : Sys_Role +{ + /// + /// 角色-接口映射 + /// + public IReadOnlyCollection ApiIds { get; init; } + + /// + [EnumDataType(typeof(DataScopes))] + public override DataScopes DataScope { get; init; } = DataScopes.All; + + /// + /// 当 DataScope = SpecificDept ,此参数指定部门编号 + /// + [SpecificDept] + public IReadOnlyCollection DeptIds { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool DisplayDashboard { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool Enabled { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool IgnorePermissionControl { get; init; } + + /// + /// 角色-菜单映射 + /// + public IReadOnlyCollection MenuIds { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.角色名称))] + public override string Name { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Sort { get; init; } = Numbers.DEF_SORT_VAL; + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Summary { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Role/GetMenusRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Role/GetMenusRsp.cs new file mode 100644 index 00000000..64c8153f --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Role/GetMenusRsp.cs @@ -0,0 +1,17 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Role; + +/// +/// 响应: 获取角色菜单 +/// +public sealed record GetMenusRsp : Sys_RoleMenu +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long MenuId { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long RoleId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Role/MapMenusReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Role/MapMenusReq.cs new file mode 100644 index 00000000..1edfd0cf --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Role/MapMenusReq.cs @@ -0,0 +1,21 @@ +using NetAdmin.Domain.Attributes.DataValidation; + +namespace NetAdmin.Domain.Dto.Sys.Role; + +/// +/// 请求:角色-菜单映射 +/// +public sealed record MapMenusReq : DataAbstraction +{ + /// + /// 菜单编号 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.菜单编号))] + public IReadOnlyCollection MenuIds { get; init; } + + /// + /// 角色编号 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.角色编号))] + public long RoleId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Role/QueryRoleReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Role/QueryRoleReq.cs new file mode 100644 index 00000000..db256ba9 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Role/QueryRoleReq.cs @@ -0,0 +1,14 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Role; + +/// +/// 请求:查询角色 +/// +public sealed record QueryRoleReq : Sys_Role +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Role/QueryRoleRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Role/QueryRoleRsp.cs new file mode 100644 index 00000000..221817f5 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Role/QueryRoleRsp.cs @@ -0,0 +1,84 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Enums.Sys; + +namespace NetAdmin.Domain.Dto.Sys.Role; + +/// +/// 响应:查询角色 +/// +public sealed record QueryRoleRsp : Sys_Role, IRegister +{ + /// + /// 角色-接口映射 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IReadOnlyCollection ApiIds { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override DateTime CreatedTime { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override DataScopes DataScope { get; init; } + + /// + /// 角色-部门映射 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IEnumerable DeptIds { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool DisplayDashboard { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool Enabled { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool IgnorePermissionControl { get; init; } + + /// + /// 角色-菜单映射 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IReadOnlyCollection MenuIds { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Name { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Sort { get; init; } = Numbers.DEF_SORT_VAL; + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Summary { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } + + /// + public new void Register(TypeAdapterConfig config) + { + _ = config.ForType() // + .IgnoreIf((s, _) => s.Depts == null, d => d.DeptIds) + .IgnoreIf((s, _) => s.Menus == null, d => d.MenuIds) + .IgnoreIf((s, _) => s.Apis == null, d => d.ApiIds) + .Map(d => d.DeptIds, s => s.Depts.Select(x => x.Id)) + .Map(d => d.ApiIds, s => s.Apis.Select(x => x.Id)) + .Map(d => d.MenuIds, s => s.Menus.Select(x => x.Id)) + + // + ; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/Role/UpdateRoleReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/Role/UpdateRoleReq.cs new file mode 100644 index 00000000..304d0b04 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/Role/UpdateRoleReq.cs @@ -0,0 +1,20 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.Dto.Sys.Role; + +/// +/// 请求:修改角色 +/// +public sealed record UpdateRoleReq : CreateRoleReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.唯一编码))] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.数据版本))] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/CheckMobileAvailableReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/CheckMobileAvailableReq.cs new file mode 100644 index 00000000..4dadc4a6 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/CheckMobileAvailableReq.cs @@ -0,0 +1,20 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:检查手机号是否可用 +/// +public sealed record CheckMobileAvailableReq : Sys_User +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [Mobile] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Mobile { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/CheckUserNameAvailableReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/CheckUserNameAvailableReq.cs new file mode 100644 index 00000000..dd3b234a --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/CheckUserNameAvailableReq.cs @@ -0,0 +1,21 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:检查用户名是否可用 +/// +public sealed record CheckUserNameAvailableReq : Sys_User +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.用户名))] + [UserName] + public override string UserName { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/CreateUpdateUserReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/CreateUpdateUserReq.cs new file mode 100644 index 00000000..b656c305 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/CreateUpdateUserReq.cs @@ -0,0 +1,58 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:创建更新用户 +/// +public abstract record CreateUpdateUserReq : Sys_User +{ + /// + [CultureUrl] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Avatar { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long DeptId { get; init; } + + /// + [EmailAddress] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Email { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool Enabled { get; init; } + + /// + [Mobile] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Mobile { get; init; } + + /// + /// 登录密码 + /// + [Password] + public virtual string PasswordText { get; init; } + + /// + /// 角色编号列表 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.角色编号列表))] + [MinLength(1)] + [MaxLength(Numbers.BULK_REQ_LIMIT)] + public IReadOnlyCollection RoleIds { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Summary { get; init; } + + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.用户名))] + [UserName] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string UserName { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/CreateUserReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/CreateUserReq.cs new file mode 100644 index 00000000..b7167f45 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/CreateUserReq.cs @@ -0,0 +1,29 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.UserProfile; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:创建用户 +/// +public record CreateUserReq : CreateUpdateUserReq, IRegister +{ + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.密码))] + public override string PasswordText { get; init; } + + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.用户档案))] + public new CreateUserProfileReq Profile { get; init; } + + /// + public new void Register(TypeAdapterConfig config) + { + _ = config.ForType() // + .Map(d => d.Mobile, s => s.VerifySmsCodeReq.DestDevice) + + // + ; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/LoginByPwdReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/LoginByPwdReq.cs new file mode 100644 index 00000000..00071fd9 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/LoginByPwdReq.cs @@ -0,0 +1,20 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:密码登录 +/// +public record LoginByPwdReq : DataAbstraction +{ + /// + /// 用户名、手机号、邮箱 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.账号))] + public string Account { get; init; } + + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.密码))] + public string Password { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/LoginBySmsReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/LoginBySmsReq.cs new file mode 100644 index 00000000..f2b5e07e --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/LoginBySmsReq.cs @@ -0,0 +1,8 @@ +using NetAdmin.Domain.Dto.Sys.VerifyCode; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:短信登录 +/// +public record LoginBySmsReq : VerifySmsCodeReq; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/LoginRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/LoginRsp.cs new file mode 100644 index 00000000..a74c40dc --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/LoginRsp.cs @@ -0,0 +1,27 @@ +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 响应:密码登录 +/// +public record LoginRsp : DataAbstraction +{ + /// + /// 访问令牌 + /// + public string AccessToken { get; init; } + + /// + /// 刷新令牌 + /// + public string RefreshToken { get; init; } + + /// + /// 设置到响应头 + /// + public void SetToRspHeader() + { + // 设置响应报文头 + App.HttpContext.Response.Headers[Chars.FLG_ACCESS_TOKEN] = AccessToken; + App.HttpContext.Response.Headers[Chars.FLG_X_ACCESS_TOKEN] = RefreshToken; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserReq.cs new file mode 100644 index 00000000..ad3d07ec --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserReq.cs @@ -0,0 +1,26 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:查询用户 +/// +public sealed record QueryUserReq : Sys_User +{ + /// + /// 部门编号 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long DeptId { get; init; } + + /// + /// id + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + /// 角色编号 + /// + public long RoleId { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserRsp.cs new file mode 100644 index 00000000..1e7203ef --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserRsp.cs @@ -0,0 +1,58 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.Dept; +using NetAdmin.Domain.Dto.Sys.Role; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 响应:查询用户 +/// +public record QueryUserRsp : Sys_User +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Avatar { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override DateTime CreatedTime { get; init; } + + /// + /// 部门 + /// + public new virtual QueryDeptRsp Dept { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Email { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override bool Enabled { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Mobile { get; init; } + + /// + /// 角色列表 + /// + public new virtual IEnumerable Roles { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Summary { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string UserName { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/RegisterUserReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/RegisterUserReq.cs new file mode 100644 index 00000000..1ca7bb4a --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/RegisterUserReq.cs @@ -0,0 +1,39 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.VerifyCode; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:注册用户 +/// +public record RegisterUserReq : Sys_User +{ + /// + /// 密码 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.密码))] + [Password] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public virtual string PasswordText { get; init; } + + /// + /// 角色编号列表 + /// + [JsonIgnore] + public IReadOnlyCollection RoleIds { get; init; } + + /// + /// 用户名 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.用户名))] + [UserName] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string UserName { get; init; } + + /// + /// 短信验证请求 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.短信验证请求))] + public VerifySmsCodeReq VerifySmsCodeReq { get; set; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/ResetPasswordReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/ResetPasswordReq.cs new file mode 100644 index 00000000..06ad2631 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/ResetPasswordReq.cs @@ -0,0 +1,23 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.Dto.Sys.VerifyCode; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:重置密码 +/// +public sealed record ResetPasswordReq : DataAbstraction +{ + /// + /// 密码 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.密码))] + [Password] + public string PasswordText { get; init; } + + /// + /// 短信验证请求 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.短信验证请求))] + public VerifySmsCodeReq VerifySmsCodeReq { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/SetAvatarReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/SetAvatarReq.cs new file mode 100644 index 00000000..7ebd7e7d --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/SetAvatarReq.cs @@ -0,0 +1,16 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:更新用户头像 +/// +public sealed record SetAvatarReq : Sys_User +{ + /// + [CultureUrl] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.用户头像))] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Avatar { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/SetEmailReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/SetEmailReq.cs new file mode 100644 index 00000000..c63c8125 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/SetEmailReq.cs @@ -0,0 +1,14 @@ +using NetAdmin.Domain.Dto.Sys.VerifyCode; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:设置邮箱 +/// +public sealed record SetEmailReq : VerifyEmailCodeReq +{ + /// + /// 短信验证请求 + /// + public VerifySmsCodeReq VerifySmsCodeReq { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/SetMobileReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/SetMobileReq.cs new file mode 100644 index 00000000..93688358 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/SetMobileReq.cs @@ -0,0 +1,21 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.Dto.Sys.VerifyCode; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:设置手机号 +/// +public sealed record SetMobileReq : DataAbstraction +{ + /// + /// 新手机短信验证请求 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.短信验证请求))] + public VerifySmsCodeReq NewVerifySmsCodeReq { get; init; } + + /// + /// 原手机短信验证请求 + /// + public VerifySmsCodeReq OriginVerifySmsCodeReq { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/SetPasswordReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/SetPasswordReq.cs new file mode 100644 index 00000000..579aa226 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/SetPasswordReq.cs @@ -0,0 +1,23 @@ +using NetAdmin.Domain.Attributes.DataValidation; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:设置密码 +/// +public sealed record SetPasswordReq : DataAbstraction +{ + /// + /// 新密码 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.新密码))] + [Password] + public string NewPassword { get; init; } + + /// + /// 旧密码 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.旧密码))] + [Password] + public string OldPassword { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/UpdateUserReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/UpdateUserReq.cs new file mode 100644 index 00000000..17101947 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/UpdateUserReq.cs @@ -0,0 +1,24 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.UserProfile; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 请求:更新用户 +/// +public sealed record UpdateUserReq : CreateUpdateUserReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.用户档案))] + public new UpdateUserProfileReq Profile { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/User/UserInfoRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/User/UserInfoRsp.cs new file mode 100644 index 00000000..42844656 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/User/UserInfoRsp.cs @@ -0,0 +1,28 @@ +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.Dept; +using NetAdmin.Domain.Dto.Sys.Role; + +namespace NetAdmin.Domain.Dto.Sys.User; + +/// +/// 响应:当前用户信息 +/// +public record UserInfoRsp : QueryUserRsp, IRegister +{ + /// + public override QueryDeptRsp Dept { get; init; } + + /// + public override IEnumerable Roles { get; init; } + + /// + public new void Register(TypeAdapterConfig config) + { + _ = config.ForType() // + .IgnoreIf((s, _) => s.Mobile == null, d => d.Mobile) + .Map(d => d.Mobile, s => s.Mobile.MaskMobile()) + + // + ; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/CreateUserProfileReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/CreateUserProfileReq.cs new file mode 100644 index 00000000..f7a1e9c7 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/CreateUserProfileReq.cs @@ -0,0 +1,122 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.Dic.Content; + +namespace NetAdmin.Domain.Dto.Sys.UserProfile; + +/// +/// 请求:创建用户档案 +/// +public record CreateUserProfileReq : Sys_UserProfile +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override DateTime? BornDate { get; init; } + + /// + [Certificate] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string CertificateNumber { get; init; } + + /// + [EnumDataType(typeof(CertificateTypes))] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override CertificateTypes? CertificateType { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string CompanyAddress { get; init; } + + /// + /// 工作地区 + /// + public new QueryDicContentRsp CompanyArea { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string CompanyName { get; init; } + + /// + [Telephone] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string CompanyTelephone { get; init; } + + /// + [EnumDataType(typeof(Educations))] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override Educations? Education { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string EmergencyContactAddress { get; init; } + + /// + /// 紧急联系地区 + /// + public new QueryDicContentRsp EmergencyContactArea { get; init; } + + /// + [Mobile] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string EmergencyContactMobile { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string EmergencyContactName { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string GraduateSchool { get; init; } + + /// + [Range(100, 250)] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override int? Height { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string HomeAddress { get; init; } + + /// + /// 住宅地区 + /// + public new QueryDicContentRsp HomeArea { get; init; } + + /// + [Telephone] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string HomeTelephone { get; init; } + + /// + [EnumDataType(typeof(MarriageStatues))] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override MarriageStatues? MarriageStatus { get; init; } + + /// + [EnumDataType(typeof(Nations))] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override Nations? Nation { get; init; } + + /// + /// 籍贯 + /// + public new CreateDicContentReq NationArea { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [EnumDataType(typeof(PoliticalStatues))] + public override PoliticalStatues? PoliticalStatus { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Profession { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string RealName { get; init; } + + /// + [EnumDataType(typeof(Sexes))] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override Sexes? Sex { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/QueryUserProfileReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/QueryUserProfileReq.cs new file mode 100644 index 00000000..38d2ac12 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/QueryUserProfileReq.cs @@ -0,0 +1,14 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.UserProfile; + +/// +/// 请求:查询用户档案 +/// +public sealed record QueryUserProfileReq : Sys_UserProfile +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/QueryUserProfileRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/QueryUserProfileRsp.cs new file mode 100644 index 00000000..56540ddf --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/QueryUserProfileRsp.cs @@ -0,0 +1,119 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.Dic.Content; + +namespace NetAdmin.Domain.Dto.Sys.UserProfile; + +/// +/// 响应:查询用户档案 +/// +public sealed record QueryUserProfileRsp : Sys_UserProfile +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override DateTime? BornDate { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string CertificateNumber { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override CertificateTypes? CertificateType { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string CompanyAddress { get; init; } + + /// + /// 工作地区 + /// + public new QueryDicContentRsp CompanyArea { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string CompanyName { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string CompanyTelephone { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override Educations? Education { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string EmergencyContactAddress { get; init; } + + /// + /// 紧急联系地区 + /// + public new QueryDicContentRsp EmergencyContactArea { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string EmergencyContactMobile { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string EmergencyContactName { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string GraduateSchool { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override int? Height { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string HomeAddress { get; init; } + + /// + /// 住宅地区 + /// + public new QueryDicContentRsp HomeArea { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string HomeTelephone { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override MarriageStatues? MarriageStatus { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override Nations? Nation { get; init; } + + /// + /// 籍贯 + /// + public new QueryDicContentRsp NationArea { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override PoliticalStatues? PoliticalStatus { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string Profession { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string RealName { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override Sexes? Sex { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/UpdateUserProfileReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/UpdateUserProfileReq.cs new file mode 100644 index 00000000..ee467ee9 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/UserProfile/UpdateUserProfileReq.cs @@ -0,0 +1,13 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.Dto.Sys.UserProfile; + +/// +/// 请求:更新用户档案 +/// +public sealed record UpdateUserProfileReq : CreateUserProfileReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/CreateVerifyCodeReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/CreateVerifyCodeReq.cs new file mode 100644 index 00000000..edad0698 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/CreateVerifyCodeReq.cs @@ -0,0 +1,8 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.VerifyCode; + +/// +/// 请求:创建验证码 +/// +public record CreateVerifyCodeReq : Sys_VerifyCode; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/QueryVerifyCodeReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/QueryVerifyCodeReq.cs new file mode 100644 index 00000000..502325c5 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/QueryVerifyCodeReq.cs @@ -0,0 +1,14 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.VerifyCode; + +/// +/// 请求:查询验证码 +/// +public sealed record QueryVerifyCodeReq : Sys_VerifyCode +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/QueryVerifyCodeRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/QueryVerifyCodeRsp.cs new file mode 100644 index 00000000..82084c48 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/QueryVerifyCodeRsp.cs @@ -0,0 +1,18 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.VerifyCode; + +/// +/// 响应:查询验证码 +/// +public sealed record QueryVerifyCodeRsp : Sys_VerifyCode +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/SendVerifyCodeReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/SendVerifyCodeReq.cs new file mode 100644 index 00000000..abfef460 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/SendVerifyCodeReq.cs @@ -0,0 +1,64 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Sys.Captcha; +using NetAdmin.Domain.Enums.Sys; + +namespace NetAdmin.Domain.Dto.Sys.VerifyCode; + +/// +/// 请求:发送验证码 +/// +public sealed record SendVerifyCodeReq : Sys_VerifyCode, IValidatableObject +{ + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.目标设备))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public override string DestDevice { get; init; } + + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.设备类型))] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [EnumDataType(typeof(VerifyCodeDeviceTypes))] + public override VerifyCodeDeviceTypes DeviceType { get; init; } + + /// + public override VerifyCodeStatues Status => VerifyCodeStatues.Waiting; + + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.验证码类型))] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [EnumDataType(typeof(VerifyCodeTypes))] + public override VerifyCodeTypes Type { get; init; } + + /// + /// 人机校验请求 + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.人机校验请求))] + public VerifyCaptchaReq VerifyCaptchaReq { get; init; } + + /// + public IEnumerable Validate(ValidationContext validationContext) + { + ValidationResult validationResult; + switch (DeviceType) { + case VerifyCodeDeviceTypes.Email: + validationResult = new EmailAttribute().GetValidationResult(DestDevice, validationContext); + if (validationResult == null) { + yield break; + } + + yield return new ValidationResult(validationResult.ErrorMessage, new[] { nameof(DestDevice) }); + break; + case VerifyCodeDeviceTypes.Mobile: + validationResult = new MobileAttribute().GetValidationResult(DestDevice, validationContext); + if (validationResult == null) { + yield break; + } + + yield return new ValidationResult(validationResult.ErrorMessage, new[] { nameof(DestDevice) }); + break; + default: + yield break; + } + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/SendVerifyCodeRsp.cs b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/SendVerifyCodeRsp.cs new file mode 100644 index 00000000..9bfc1aa2 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/SendVerifyCodeRsp.cs @@ -0,0 +1,15 @@ +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.VerifyCode; + +/// +/// 响应:发送验证码 +/// +public sealed record SendVerifyCodeRsp : Sys_VerifyCode +{ + #if DEBUG + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override string Code { get; init; } + #endif +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/UpdateVerifyCodeReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/UpdateVerifyCodeReq.cs new file mode 100644 index 00000000..f6186caa --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/UpdateVerifyCodeReq.cs @@ -0,0 +1,13 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.Dto.Sys.VerifyCode; + +/// +/// 请求:更新验证码 +/// +public sealed record UpdateVerifyCodeReq : CreateVerifyCodeReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/VerifyCodeReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/VerifyCodeReq.cs new file mode 100644 index 00000000..2a41d82a --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/VerifyCodeReq.cs @@ -0,0 +1,21 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.DbMaps.Sys; + +namespace NetAdmin.Domain.Dto.Sys.VerifyCode; + +/// +/// 请求:核实验证码 +/// +public abstract record VerifyCodeReq : Sys_VerifyCode +{ + /// + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.验证码))] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [VerifyCode] + public override string Code { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + [CultureRequired(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.目标设备))] + public override string DestDevice { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/VerifyEmailCodeReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/VerifyEmailCodeReq.cs new file mode 100644 index 00000000..caeb9d38 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/VerifyEmailCodeReq.cs @@ -0,0 +1,18 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.Enums.Sys; + +namespace NetAdmin.Domain.Dto.Sys.VerifyCode; + +/// +/// 请求:核实邮箱验证码 +/// +public record VerifyEmailCodeReq : VerifyCodeReq +{ + /// + [Email] + public override string DestDevice { get; init; } + + /// + [JsonIgnore] + public override VerifyCodeDeviceTypes DeviceType { get; init; } = VerifyCodeDeviceTypes.Email; +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/VerifySmsCodeReq.cs b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/VerifySmsCodeReq.cs new file mode 100644 index 00000000..93f1a36f --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Sys/VerifyCode/VerifySmsCodeReq.cs @@ -0,0 +1,18 @@ +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.Enums.Sys; + +namespace NetAdmin.Domain.Dto.Sys.VerifyCode; + +/// +/// 请求:核实短信验证码 +/// +public record VerifySmsCodeReq : VerifyCodeReq +{ + /// + [Mobile] + public override string DestDevice { get; init; } + + /// + [JsonIgnore] + public override VerifyCodeDeviceTypes DeviceType { get; init; } = VerifyCodeDeviceTypes.Mobile; +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Tpl/Example/CreateExampleReq.cs b/src/backend/NetAdmin.Domain/Dto/Tpl/Example/CreateExampleReq.cs new file mode 100644 index 00000000..bf6eeb95 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Tpl/Example/CreateExampleReq.cs @@ -0,0 +1,8 @@ +using NetAdmin.Domain.DbMaps.Tpl; + +namespace NetAdmin.Domain.Dto.Tpl.Example; + +/// +/// 请求:创建示例 +/// +public record CreateExampleReq : Tpl_Example; \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Tpl/Example/QueryExampleReq.cs b/src/backend/NetAdmin.Domain/Dto/Tpl/Example/QueryExampleReq.cs new file mode 100644 index 00000000..2db659c8 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Tpl/Example/QueryExampleReq.cs @@ -0,0 +1,14 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Tpl; + +namespace NetAdmin.Domain.Dto.Tpl.Example; + +/// +/// 请求:查询示例 +/// +public sealed record QueryExampleReq : Tpl_Example +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Tpl/Example/QueryExampleRsp.cs b/src/backend/NetAdmin.Domain/Dto/Tpl/Example/QueryExampleRsp.cs new file mode 100644 index 00000000..b07f12fa --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Tpl/Example/QueryExampleRsp.cs @@ -0,0 +1,18 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Tpl; + +namespace NetAdmin.Domain.Dto.Tpl.Example; + +/// +/// 响应:查询示例 +/// +public sealed record QueryExampleRsp : Tpl_Example +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Id { get; init; } + + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Dto/Tpl/Example/UpdateExampleReq.cs b/src/backend/NetAdmin.Domain/Dto/Tpl/Example/UpdateExampleReq.cs new file mode 100644 index 00000000..a8ffd174 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Dto/Tpl/Example/UpdateExampleReq.cs @@ -0,0 +1,13 @@ +using NetAdmin.Domain.DbMaps.Dependency.Fields; + +namespace NetAdmin.Domain.Dto.Tpl.Example; + +/// +/// 请求:更新示例 +/// +public sealed record UpdateExampleReq : CreateExampleReq +{ + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public override long Version { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Enums/Sys/DataScopes.cs b/src/backend/NetAdmin.Domain/Enums/Sys/DataScopes.cs new file mode 100644 index 00000000..4f5c9d98 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Enums/Sys/DataScopes.cs @@ -0,0 +1,46 @@ +namespace NetAdmin.Domain.Enums.Sys; + +/// +/// 角色数据范围 +/// +[Export] +public enum DataScopes +{ + /// + /// 全部数据 + /// + [ResourceDescription(nameof(Ln.全部数据))] + All = 1 + + , + + /// + /// 本部门和下级部门数据 + /// + [ResourceDescription(nameof(Ln.本部门和下级部门数据))] + DeptWithChild = 2 + + , + + /// + /// 本部门数据 + /// + [ResourceDescription(nameof(Ln.本部门数据))] + Dept = 3 + + , + + /// + /// 本人数据 + /// + [ResourceDescription(nameof(Ln.本人数据))] + Self = 4 + + , + + /// + /// 指定部门数据 + /// + [ResourceDescription(nameof(Ln.指定部门数据))] + SpecificDept = 5 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Enums/Sys/MenuTypes.cs b/src/backend/NetAdmin.Domain/Enums/Sys/MenuTypes.cs new file mode 100644 index 00000000..70f22274 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Enums/Sys/MenuTypes.cs @@ -0,0 +1,38 @@ +namespace NetAdmin.Domain.Enums.Sys; + +/// +/// 菜单类型 +/// +[Export] +public enum MenuTypes +{ + /// + /// 菜单 + /// + [ResourceDescription(nameof(Ln.菜单))] + Menu = 1 + + , + + /// + /// 链接 + /// + [ResourceDescription(nameof(Ln.链接))] + Link = 2 + + , + + /// + /// 框架 + /// + [ResourceDescription(nameof(Ln.框架))] + Iframe = 3 + + , + + /// + /// 按钮 + /// + [ResourceDescription(nameof(Ln.按钮))] + Button = 4 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Enums/Sys/VerifyCodeDeviceTypes.cs b/src/backend/NetAdmin.Domain/Enums/Sys/VerifyCodeDeviceTypes.cs new file mode 100644 index 00000000..18563bc0 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Enums/Sys/VerifyCodeDeviceTypes.cs @@ -0,0 +1,21 @@ +namespace NetAdmin.Domain.Enums.Sys; + +/// +/// 验证码目标设备类型 +/// +public enum VerifyCodeDeviceTypes +{ + /// + /// 手机 + /// + [ResourceDescription(nameof(Ln.手机))] + Mobile = 1 + + , + + /// + /// 电子邮箱 + /// + [ResourceDescription(nameof(Ln.电子邮箱))] + Email = 2 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Enums/Sys/VerifyCodeStatues.cs b/src/backend/NetAdmin.Domain/Enums/Sys/VerifyCodeStatues.cs new file mode 100644 index 00000000..ef7a0941 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Enums/Sys/VerifyCodeStatues.cs @@ -0,0 +1,37 @@ +namespace NetAdmin.Domain.Enums.Sys; + +/// +/// 验证码状态 +/// +public enum VerifyCodeStatues +{ + /// + /// 等待发送 + /// + [ResourceDescription(nameof(Ln.等待发送))] + Waiting = 1 + + , + + /// + /// 已发送 + /// + [ResourceDescription(nameof(Ln.已发送))] + Sent = 2 + + , + + /// + /// 发送失败 + /// + [ResourceDescription(nameof(Ln.发送失败))] + Failed = 3 + + , + + /// + /// 已校验 + /// + [ResourceDescription(nameof(Ln.已校验))] + Verified = 4 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Enums/Sys/VerifyCodeTypes.cs b/src/backend/NetAdmin.Domain/Enums/Sys/VerifyCodeTypes.cs new file mode 100644 index 00000000..a30fa9c2 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Enums/Sys/VerifyCodeTypes.cs @@ -0,0 +1,46 @@ +namespace NetAdmin.Domain.Enums.Sys; + +/// +/// 验证码类型 +/// +[Export] +public enum VerifyCodeTypes +{ + /// + /// 绑定手机号 + /// + [ResourceDescription(nameof(Ln.绑定手机号))] + LinkMobile = 1 + + , + + /// + /// 登录 + /// + [ResourceDescription(nameof(Ln.登录))] + Login = 2 + + , + + /// + /// 解绑手机号 + /// + [ResourceDescription(nameof(Ln.解绑手机号))] + UnlinkMobile = 3 + + , + + /// + /// 注册 + /// + [ResourceDescription(nameof(Ln.注册))] + Register = 4 + + , + + /// + /// 重设密码 + /// + [ResourceDescription(nameof(Ln.重设密码))] + ResetPassword = 5 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Events/IEventSourceGeneric.cs b/src/backend/NetAdmin.Domain/Events/IEventSourceGeneric.cs new file mode 100644 index 00000000..b784b80b --- /dev/null +++ b/src/backend/NetAdmin.Domain/Events/IEventSourceGeneric.cs @@ -0,0 +1,12 @@ +namespace NetAdmin.Domain.Events; + +/// +/// 泛型事件源接口 +/// +public interface IEventSourceGeneric : IEventSource +{ + /// + /// 事件承载(携带)数据 + /// + T Data { get; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Events/SqlCommandAfterEvent.cs b/src/backend/NetAdmin.Domain/Events/SqlCommandAfterEvent.cs new file mode 100644 index 00000000..aeaa9dc3 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Events/SqlCommandAfterEvent.cs @@ -0,0 +1,28 @@ +namespace NetAdmin.Domain.Events; + +/// +/// Sql命令执行后事件 +/// +public sealed record SqlCommandAfterEvent : SqlCommandBeforeEvent +{ + /// + /// Initializes a new instance of the class. + /// + public SqlCommandAfterEvent(CommandAfterEventArgs e) // + : base(e) + { + ElapsedMicroseconds = (long)((double)e.ElapsedTicks / Stopwatch.Frequency * 1_000_000); + EventId = nameof(SqlCommandAfterEvent); + } + + /// + /// 耗时(单位:微秒) + /// + public long ElapsedMicroseconds { get; set; } + + /// + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "SQL-{0}: {2} us {1}", Id, Sql, ElapsedMicroseconds); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Events/SqlCommandBeforeEvent.cs b/src/backend/NetAdmin.Domain/Events/SqlCommandBeforeEvent.cs new file mode 100644 index 00000000..5a96632a --- /dev/null +++ b/src/backend/NetAdmin.Domain/Events/SqlCommandBeforeEvent.cs @@ -0,0 +1,24 @@ +namespace NetAdmin.Domain.Events; + +/// +/// Sql命令执行前事件 +/// +public record SqlCommandBeforeEvent : SqlCommandEvent +{ + /// + /// Initializes a new instance of the class. + /// + public SqlCommandBeforeEvent(CommandBeforeEventArgs e) + { + Identifier = e.Identifier; + Sql = e.Command.ParameterFormat().RemoveWrapped(); + EventId = nameof(SqlCommandBeforeEvent); + CreatedTime = DateTime.Now; + } + + /// + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "SQL-{0}: Executing...", Id); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Events/SqlCommandEvent.cs b/src/backend/NetAdmin.Domain/Events/SqlCommandEvent.cs new file mode 100644 index 00000000..2e2aa63a --- /dev/null +++ b/src/backend/NetAdmin.Domain/Events/SqlCommandEvent.cs @@ -0,0 +1,45 @@ +namespace NetAdmin.Domain.Events; + +/// +/// Sql命令事件 +/// +public record SqlCommandEvent : DataAbstraction, IEventSource +{ + /// + /// 标识符缩写 + /// + public string Id => Identifier.ToString()[..8].ToUpperInvariant(); + + /// + /// 取消任务 Token + /// + /// + /// 用于取消本次消息处理 + /// + public CancellationToken CancellationToken { get; init; } + + /// + /// 事件创建时间 + /// + public DateTime CreatedTime { get; protected init; } + + /// + /// 事件 Id + /// + public string EventId { get; protected init; } + + /// + /// 标识符,可将 CommandBefore 与 CommandAfter 进行匹配 + /// + public Guid Identifier { get; protected init; } + + /// + /// 事件承载(携带)数据 + /// + public object Payload { get; init; } + + /// + /// 关联的Sql语句 + /// + public string Sql { get; protected init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Events/SyncStructureAfterEvent.cs b/src/backend/NetAdmin.Domain/Events/SyncStructureAfterEvent.cs new file mode 100644 index 00000000..383c03d8 --- /dev/null +++ b/src/backend/NetAdmin.Domain/Events/SyncStructureAfterEvent.cs @@ -0,0 +1,23 @@ +namespace NetAdmin.Domain.Events; + +/// +/// 同步数据库结构之后事件 +/// +public sealed record SyncStructureAfterEvent : SyncStructureBeforeEvent +{ + /// + /// Initializes a new instance of the class. + /// + public SyncStructureAfterEvent(SyncStructureBeforeEventArgs e) // + : base(e) + { + EventId = nameof(SyncStructureAfterEvent); + } + + /// + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "{0}: {1}: {2}", Id, Ln.数据库结构同步完成 + , string.Join(',', EntityTypes.Select(x => x.Name))); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Events/SyncStructureBeforeEvent.cs b/src/backend/NetAdmin.Domain/Events/SyncStructureBeforeEvent.cs new file mode 100644 index 00000000..8a1012af --- /dev/null +++ b/src/backend/NetAdmin.Domain/Events/SyncStructureBeforeEvent.cs @@ -0,0 +1,29 @@ +namespace NetAdmin.Domain.Events; + +/// +/// 同步数据库结构之前事件 +/// +public record SyncStructureBeforeEvent : SqlCommandEvent +{ + /// + /// Initializes a new instance of the class. + /// + public SyncStructureBeforeEvent(SyncStructureBeforeEventArgs e) + { + Identifier = e.Identifier; + EventId = nameof(SyncStructureBeforeEvent); + CreatedTime = DateTime.Now; + EntityTypes = e.EntityTypes; + } + + /// + /// 实体类型 + /// + public Type[] EntityTypes { get; } + + /// + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "{0}: {1}", Id, Ln.数据库同步开始); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Events/Sys/RequestLogEvent.cs b/src/backend/NetAdmin.Domain/Events/Sys/RequestLogEvent.cs new file mode 100644 index 00000000..f4ccb49d --- /dev/null +++ b/src/backend/NetAdmin.Domain/Events/Sys/RequestLogEvent.cs @@ -0,0 +1,45 @@ +using NetAdmin.Domain.Dto.Sys.RequestLog; + +namespace NetAdmin.Domain.Events.Sys; + +/// +/// 请求日志事件 +/// +public sealed record RequestLogEvent : DataAbstraction, IEventSourceGeneric +{ + /// + /// Initializes a new instance of the class. + /// + public RequestLogEvent(CreateRequestLogReq data) + { + Data = data; + } + + /// + /// 取消任务 Token + /// + /// + /// 用于取消本次消息处理 + /// + public CancellationToken CancellationToken { get; } + + /// + /// 事件创建时间 + /// + public DateTime CreatedTime { get; } + + /// + /// 事件承载(携带)数据 + /// + public CreateRequestLogReq Data { get; } + + /// + /// 事件 Id + /// + public string EventId => nameof(RequestLogEvent); + + /// + /// 事件承载(携带)数据 + /// + public object Payload { get; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Events/Sys/UserUpdatedEvent.cs b/src/backend/NetAdmin.Domain/Events/Sys/UserUpdatedEvent.cs new file mode 100644 index 00000000..12ffe2dc --- /dev/null +++ b/src/backend/NetAdmin.Domain/Events/Sys/UserUpdatedEvent.cs @@ -0,0 +1,45 @@ +using NetAdmin.Domain.Dto.Sys.User; + +namespace NetAdmin.Domain.Events.Sys; + +/// +/// 用户被更新事件 +/// +public sealed record UserUpdatedEvent : DataAbstraction, IEventSourceGeneric +{ + /// + /// Initializes a new instance of the class. + /// + public UserUpdatedEvent(UserInfoRsp data) + { + Data = data; + } + + /// + /// 取消任务 Token + /// + /// + /// 用于取消本次消息处理 + /// + public CancellationToken CancellationToken { get; } + + /// + /// 事件创建时间 + /// + public DateTime CreatedTime { get; } + + /// + /// 事件承载(携带)数据 + /// + public UserInfoRsp Data { get; } + + /// + /// 事件 Id + /// + public string EventId => nameof(UserUpdatedEvent); + + /// + /// 事件承载(携带)数据 + /// + public object Payload { get; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/Events/Sys/VerifyCodeCreatedEvent.cs b/src/backend/NetAdmin.Domain/Events/Sys/VerifyCodeCreatedEvent.cs new file mode 100644 index 00000000..42c8e26b --- /dev/null +++ b/src/backend/NetAdmin.Domain/Events/Sys/VerifyCodeCreatedEvent.cs @@ -0,0 +1,45 @@ +using NetAdmin.Domain.Dto.Sys.VerifyCode; + +namespace NetAdmin.Domain.Events.Sys; + +/// +/// 验证码创建事件 +/// +public sealed record VerifyCodeCreatedEvent : DataAbstraction, IEventSourceGeneric +{ + /// + /// Initializes a new instance of the class. + /// + public VerifyCodeCreatedEvent(QueryVerifyCodeRsp data) + { + Data = data; + } + + /// + /// 取消任务 Token + /// + /// + /// 用于取消本次消息处理 + /// + public CancellationToken CancellationToken { get; } + + /// + /// 事件创建时间 + /// + public DateTime CreatedTime { get; } + + /// + /// 事件承载(携带)数据 + /// + public QueryVerifyCodeRsp Data { get; } + + /// + /// 事件 Id + /// + public string EventId => nameof(VerifyCodeCreatedEvent); + + /// + /// 事件承载(携带)数据 + /// + public object Payload { get; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Domain/NetAdmin.Domain.csproj b/src/backend/NetAdmin.Domain/NetAdmin.Domain.csproj new file mode 100644 index 00000000..2a10724d --- /dev/null +++ b/src/backend/NetAdmin.Domain/NetAdmin.Domain.csproj @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Attributes/RemoveNullNodeAttribute.cs b/src/backend/NetAdmin.Host/Attributes/RemoveNullNodeAttribute.cs new file mode 100644 index 00000000..6953cb25 --- /dev/null +++ b/src/backend/NetAdmin.Host/Attributes/RemoveNullNodeAttribute.cs @@ -0,0 +1,7 @@ +namespace NetAdmin.Host.Attributes; + +/// +/// 标记一个Action,其响应的json结果会被删除值为null的节点 +/// +[AttributeUsage(AttributeTargets.Method)] +public sealed class RemoveNullNodeAttribute : Attribute { } \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Attributes/TransactionAttribute.cs b/src/backend/NetAdmin.Host/Attributes/TransactionAttribute.cs new file mode 100644 index 00000000..2c74403d --- /dev/null +++ b/src/backend/NetAdmin.Host/Attributes/TransactionAttribute.cs @@ -0,0 +1,41 @@ +namespace NetAdmin.Host.Attributes; + +/// +/// 标记一个Action启用事务 +/// +[AttributeUsage(AttributeTargets.Method)] +public sealed class TransactionAttribute : Attribute +{ + /// + /// Initializes a new instance of the class. + /// + public TransactionAttribute() { } + + /// + /// Initializes a new instance of the class. + /// + public TransactionAttribute(Propagation propagation) // + : this(null, propagation) { } + + /// + /// Initializes a new instance of the class. + /// + public TransactionAttribute(IsolationLevel isolationLevel, Propagation propagation) // + : this(new IsolationLevel?(isolationLevel), propagation) { } + + private TransactionAttribute(IsolationLevel? isolationLevel, Propagation propagation) + { + IsolationLevel = isolationLevel; + Propagation = propagation; + } + + /// + /// 事务隔离级别 + /// + public IsolationLevel? IsolationLevel { get; } + + /// + /// 事务传播方式 + /// + public Propagation Propagation { get; } = Propagation.Required; +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/BackgroundRunning/WorkBase.cs b/src/backend/NetAdmin.Host/BackgroundRunning/WorkBase.cs new file mode 100644 index 00000000..9ffc9343 --- /dev/null +++ b/src/backend/NetAdmin.Host/BackgroundRunning/WorkBase.cs @@ -0,0 +1,72 @@ +using RedLockNet; + +namespace NetAdmin.Host.BackgroundRunning; + +/// +/// 工作基类 +/// +public abstract class WorkBase +{ + private readonly RedLocker _redLocker; + + /// + /// Initializes a new instance of the class. + /// + protected WorkBase() + { + ServiceProvider = App.GetService().CreateScope().ServiceProvider; + _redLocker = ServiceProvider.GetService(); + UowManager = ServiceProvider.GetService(); + Logger = ServiceProvider.GetService>(); + } + + /// + /// 日志记录器 + /// + protected ILogger Logger { get; } + + /// + /// 服务提供器 + /// + protected IServiceProvider ServiceProvider { get; } + + /// + /// 事务单元管理器 + /// + protected UnitOfWorkManager UowManager { get; } + + /// + /// 获取锁 + /// + protected Task GetLockerAsync(string lockId) + { + return _redLocker.RedlockFactory.CreateLockAsync(lockId, TimeSpan.FromSeconds(Numbers.RED_LOCK_EXPIRY_TIME_SECS) + , TimeSpan.FromSeconds(Numbers.RED_LOCK_WAIT_TIME_SECS) + , TimeSpan.FromSeconds(Numbers.RED_LOCK_RETRY_TIME_SECS)); + } + + /// + /// 通用工作流 + /// + protected abstract ValueTask WorkflowAsync(CancellationToken cancelToken); + + /// + /// 通用工作流 + /// + /// 加锁失败异常 + protected virtual async ValueTask WorkflowAsync(bool singleInstance, CancellationToken cancelToken) + { + if (singleInstance) { + // 加锁 + await using var redLock = await GetLockerAsync(GetType().FullName); + if (!redLock.IsAcquired) { + throw new NetAdminGetLockerException(); + } + + await WorkflowAsync(cancelToken); + return; + } + + await WorkflowAsync(cancelToken); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Controllers/ControllerBase.cs b/src/backend/NetAdmin.Host/Controllers/ControllerBase.cs new file mode 100644 index 00000000..a5f3dac8 --- /dev/null +++ b/src/backend/NetAdmin.Host/Controllers/ControllerBase.cs @@ -0,0 +1,25 @@ +using NetAdmin.Application.Services; +using NetAdmin.Cache; + +namespace NetAdmin.Host.Controllers; + +/// +/// 控制器基类 +/// +public abstract class ControllerBase : IDynamicApiController + where TCache : ICache // + where TService : IService +{ + /// + /// Initializes a new instance of the class. + /// + protected ControllerBase(TCache cache) + { + Cache = cache; + } + + /// + /// 关联的缓存 + /// + protected TCache Cache { get; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Controllers/HealthController.cs b/src/backend/NetAdmin.Host/Controllers/HealthController.cs new file mode 100644 index 00000000..688c2db9 --- /dev/null +++ b/src/backend/NetAdmin.Host/Controllers/HealthController.cs @@ -0,0 +1,29 @@ +using NetAdmin.Application.Services; +using NetAdmin.Cache; + +namespace NetAdmin.Host.Controllers; + +/// +/// 健康控制器 +/// +[ApiDescriptionSettings("Health")] +public sealed class HealthController : ControllerBase, IService> +{ + /// + /// Initializes a new instance of the class. + /// + public HealthController(ICache cache) // + : base(cache) { } + + /// + /// 健康检查 + /// + [AllowAnonymous] + [HttpGet] + #pragma warning disable CA1822, S3400 + public string Check() + #pragma warning restore S3400, CA1822 + { + return Global.ProductVersion; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Extensions/HttpContextExtensions.cs b/src/backend/NetAdmin.Host/Extensions/HttpContextExtensions.cs new file mode 100644 index 00000000..53aeb343 --- /dev/null +++ b/src/backend/NetAdmin.Host/Extensions/HttpContextExtensions.cs @@ -0,0 +1,34 @@ +namespace NetAdmin.Host.Extensions; + +/// +/// HttpContext 扩展方法 +/// +public static class HttpContextExtensions +{ + private static readonly Regex _nullRegex = new("\"[^\"]+?\":null,?", RegexOptions.Compiled); + + /// + /// 删除 response json body 中value 为null的节点 + /// + public static async Task RemoveJsonNodeWithNullValueAsync(this HttpContext me) + { + // 非json格式,退出 + if (!(me.Response.ContentType?.Contains(Chars.FLG_APPLICATION_JSON) ?? false)) { + return; + } + + // 流不可读,退出 + if (!me.Response.Body.CanSeek || !me.Response.Body.CanRead || !me.Response.Body.CanWrite) { + return; + } + + _ = me.Response.Body.Seek(0, SeekOrigin.Begin); + var sr = new StreamReader(me.Response.Body); + var bodyString = await sr.ReadToEndAsync(); + bodyString = _nullRegex.Replace(bodyString, string.Empty).Replace(",}", "}"); + _ = me.Response.Body.Seek(0, SeekOrigin.Begin); + var bytes = Encoding.UTF8.GetBytes(bodyString); + me.Response.Body.SetLength(bytes.Length); + await me.Response.Body.WriteAsync(bytes); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Extensions/IApplicationBuilderExtensions.cs b/src/backend/NetAdmin.Host/Extensions/IApplicationBuilderExtensions.cs new file mode 100644 index 00000000..094c5437 --- /dev/null +++ b/src/backend/NetAdmin.Host/Extensions/IApplicationBuilderExtensions.cs @@ -0,0 +1,54 @@ +using IGeekFan.AspNetCore.Knife4jUI; +using Microsoft.AspNetCore.HttpOverrides; +using Prometheus; + +namespace NetAdmin.Host.Extensions; + +/// +/// ApplicationBuilder对象 扩展方法 +/// +[SuppressSniffer] + +// ReSharper disable once InconsistentNaming +public static class IApplicationBuilderExtensions +{ + /// + /// 执行匹配的端点 + /// + public static IApplicationBuilder UseEndpoints(this IApplicationBuilder me) + { + _ = me.UseEndpoints(endpoints => { + _ = endpoints.MapControllers(); + _ = endpoints.MapMetrics(); + }); + return me; + } + + /// + /// 使用 api skin (knife4j-vue) + /// + public static IApplicationBuilder UseOpenApiSkin(this IApplicationBuilder me) + { + _ = me.UseKnife4UI(options => { + options.RoutePrefix = string.Empty; // 配置 Knife4UI 路由地址 + foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups()) { + options.SwaggerEndpoint($"/{groupInfo.RouteTemplate}", groupInfo.Title); + } + }); + + return me; + } + + /// + /// 获取客户端真实Ip + /// + public static IApplicationBuilder UseRealIp(this IApplicationBuilder me) + { + _ = me.UseForwardedHeaders(new ForwardedHeadersOptions // + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor | + ForwardedHeaders.XForwardedProto + }); + return me; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Extensions/IMvcBuilderExtensions.cs b/src/backend/NetAdmin.Host/Extensions/IMvcBuilderExtensions.cs new file mode 100644 index 00000000..442ec8cf --- /dev/null +++ b/src/backend/NetAdmin.Host/Extensions/IMvcBuilderExtensions.cs @@ -0,0 +1,115 @@ +using NetAdmin.Host.Filters; +using NetAdmin.Host.Utils; + +namespace NetAdmin.Host.Extensions; + +/// +/// IMvcBuilder 扩展方法 +/// +[SuppressSniffer] + +// ReSharper disable once InconsistentNaming +public static class IMvcBuilderExtensions +{ + /// + /// api结果处理器 + /// + public static IMvcBuilder AddDefaultApiResultHandler(this IMvcBuilder me) + { + return me.AddInjectWithUnifyResult(injectOptions => { + injectOptions.ConfigureSwaggerGen( + genOptions => { + // 替换自定义的EnumSchemaFilter,支持多语言Resx资源 (需将SpecificationDocumentSettings.EnableEnumSchemaFilter配置为false) + genOptions + .SchemaFilter< + SwaggerEnumSchemaFixer>(); + + // 将程序集版本号与OpenApi版本号同步 + foreach (var doc in genOptions + .SwaggerGeneratorOptions + .SwaggerDocs) { + doc.Value.Version + = FileVersionInfo + .GetVersionInfo( + Assembly + .GetEntryAssembly()! + .Location) + .ProductVersion; + } + }); + }); + } + + /// + /// Json序列化配置 + /// + /// + /// 正反序列化规则: + /// object->json: + /// 1、值为 null 或 default 的节点将被忽略 + /// 2、值为 "" 的节点将被忽略。 + /// 3、值为 [] 的节点将被忽略。 + /// 4、节点名:大驼峰转小驼峰 + /// 5、不转义除对json结构具有破坏性(如")以外的任何字符 + /// 6、大数字原样输出(不加引号),由前端处理js大数兼容问题 + /// json->object: + /// 1、允许带注释的json(自动忽略) + /// 2、允许尾随逗号 + /// 3、节点名大小写不敏感 + /// 4、允许带双引号的数字 + /// 5、值为"" 转 null + /// 6、值为[] 转 null + /// + public static IMvcBuilder AddJsonSerializer(this IMvcBuilder me, bool enumToString = false) + { + return me.AddJsonOptions(options => { + ////////////////////////////// json -> object + + // 允许带注释 + options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip; + + // 允许尾随逗号 + options.JsonSerializerOptions.AllowTrailingCommas = true; + + // 允许数字带双引号 + options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString; + + // 大小写不敏感 + options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; + + // 允许读取引号包围的数字 + options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString; + + ///////////////////////////// object -> json + + // 转小驼峰 + options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase; + options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + + // 不严格转义 + options.JsonSerializerOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; + + // 写入时,忽略null、default + options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + + ////////////////////////////// object <-> json + + // "" 转 null 双向 + options.JsonSerializerOptions.Converters.Add(new ToNullIfEmptyStringConverter()); + + // [] 转 null 双向 + options.JsonSerializerOptions.TypeInfoResolver = new CollectionJsonTypeInfoResolver(); + + // 日期格式 2023-01-18 20:02:12 + _ = options.JsonSerializerOptions.Converters.AddDateTimeTypeConverters(Chars.TPL_DATE_YYYY_MM_DD_HH_MM_SS); + + // object->json 枚举显名 而非数字 ,json->object 可以枚举名 也可以数值 + if (enumToString) { + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); + } + + // 快捷访问方式 + Global.JsonSerializerOptions = options.JsonSerializerOptions; + }); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Extensions/ResourceExecutingContextExtensions.cs b/src/backend/NetAdmin.Host/Extensions/ResourceExecutingContextExtensions.cs new file mode 100644 index 00000000..3d5c1a79 --- /dev/null +++ b/src/backend/NetAdmin.Host/Extensions/ResourceExecutingContextExtensions.cs @@ -0,0 +1,19 @@ +using NetAdmin.Domain.Dto; + +namespace NetAdmin.Host.Extensions; + +/// +/// ResourceExecutingContextExtensions +/// +public static class ResourceExecutingContextExtensions +{ + /// + /// 设置失败结果 + /// + public static void SetFailResult(this ResourceExecutingContext me, ErrorCodes errorCode, string errorMsg = null) + where T : RestfulInfo, new() + { + me.Result = new JsonResult(new T { Code = errorCode, Msg = errorMsg }); + me.HttpContext.Response.StatusCode = Numbers.HTTP_STATUS_BIZ_FAIL; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Extensions/ServiceCollectionExtensions.cs b/src/backend/NetAdmin.Host/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..7d8c9fa7 --- /dev/null +++ b/src/backend/NetAdmin.Host/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,269 @@ +using Furion.Logging; +using NetAdmin.Domain.Contexts; +using NetAdmin.Domain.Events; +using NetAdmin.Host.Filters; +using NetAdmin.Host.Utils; +using Spectre.Console; +using StackExchange.Redis; +using Yitter.IdGenerator; +using FreeSqlBuilder = NetAdmin.Infrastructure.Utils.FreeSqlBuilder; + +namespace NetAdmin.Host.Extensions; + +/// +/// ServiceCollection 扩展方法 +/// +[SuppressSniffer] +public static class ServiceCollectionExtensions +{ + private const int _CONSOLE_LINE_LEN_LIMIT = 4096; + + private static readonly Dictionary _consoleColors // + = new() { + { + new Regex( // + @"(\d{2,}\.\d+ ?ms)", RegexOptions.Compiled) + , $"[{nameof(ConsoleColor.Magenta)}]$1[/]" + } + , { + new Regex( // + "(Tb[a-zA-Z0-9]+)", RegexOptions.Compiled) + , $"[{nameof(ConsoleColor.Cyan)}]$1[/]" + } + , { + new Regex( // + "(INSERT) ", RegexOptions.Compiled) + , $"[{nameof(ConsoleColor.Blue)}]$1[/] " + } + , { + new Regex( // + "(SELECT) ", RegexOptions.Compiled) + , $"[{nameof(ConsoleColor.Green)}]$1[/] " + } + , { + new Regex( // + "(UPDATE) ", RegexOptions.Compiled) + , $"[{nameof(ConsoleColor.Yellow)}]$1[/] " + } + , { + new Regex( // + "(DELETE) ", RegexOptions.Compiled) + , $"[{nameof(ConsoleColor.Red)}]$1[/] " + } + , { + new Regex( // + "()", RegexOptions.Compiled) + , $"[underline {nameof(ConsoleColor.Gray)}]$1[/] " + } + , { + new Regex( // + "(ResponseBody)", RegexOptions.Compiled) + , $"[underline {nameof(ConsoleColor.Cyan)}]$1[/] " + } + , { + new Regex( // + "(RequestBody)", RegexOptions.Compiled) + , $"[underline {nameof(ConsoleColor.Magenta)}]$1[/] " + } + , { + new Regex( // + @"(\[\[dbo\]\]\.)(\[\[.+?\]\]) ", RegexOptions.Compiled) + , $"$1[{nameof(ConsoleColor.Magenta)}]$2[/] " + } + }; + + /// + /// 扫描程序集中继承自IConfigurableOptions的选项,注册 + /// + public static IServiceCollection AddAllOptions( // + this IServiceCollection me) + { + var optionsTypes + = from type in App.EffectiveTypes.Where(x => !x.IsAbstract && !x.FullName!.Contains(nameof(Furion)) && + x.GetInterfaces().Contains(typeof(IConfigurableOptions))) + select type; + + var sbLog = new StringBuilder(); + foreach (var type in optionsTypes) { + var configureMethod = typeof(ConfigurableOptionsServiceCollectionExtensions).GetMethod( + nameof(ConfigurableOptionsServiceCollectionExtensions.AddConfigurableOptions) + , BindingFlags.Public | BindingFlags.Static, new[] { typeof(IServiceCollection) }); + _ = configureMethod!.MakeGenericMethod(type).Invoke(me, new object[] { me }); + _ = sbLog.Append(CultureInfo.InvariantCulture, $", {type.Name}"); + } + + LogHelper.Get()?.Info($"{nameof(IConfigurableOptions)} {Ln.初始化完毕} {sbLog}"); + return me; + } + + /// + /// 注册控制台日志模板 + /// + public static IServiceCollection AddConsoleFormatter(this IServiceCollection me) + { + static (string Date, string LogName, string LogFormat) ParseMessage(LogMessage message, bool showColor) + { + var date = message.LogDateTime.ToString(Chars.TPL_DATE_HH_MM_SS_FFFFFF, CultureInfo.InvariantCulture); + var logName = message.LogName.PadRight(64, ' ')[^64..]; + var format = showColor + ? $"[{nameof(ConsoleColor.Gray)}][[{{0}} {{1}} {{2,-{64}}} #{{3,4}}]][/] {{4}}" + : $"[{{0}} {{1}} {{2,-{64}}} #{{3,4}}] {{4}}"; + + return (date, logName, format); + } + + return me.AddConsoleFormatter(options => { + var logLevels = Enum.GetValues(typeof(LogLevels)) + .Cast() + .ToDictionary(x => x, x => x.GetDisplay()); + + if (App.WebHostEnvironment.IsDevelopment()) { + static void MarkupLine(string msg, LogMessage message + , IReadOnlyDictionary logLevels) + { + // 日志过长 + if (msg.Length > _CONSOLE_LINE_LEN_LIMIT) { + msg = $"{Ln.日志长度超过限制} {_CONSOLE_LINE_LEN_LIMIT}"; + } + + msg = _consoleColors.Aggregate( // + msg, (current, regex) => regex.Key.Replace(current, regex.Value)); + msg = msg.ReplaceLineEndings(string.Empty); + var colorName = logLevels[(LogLevels)message.LogLevel].Name!; + var (date, logName, logFormat) = ParseMessage(message, true); + AnsiConsole.MarkupLine( // + CultureInfo.InvariantCulture, logFormat, date, colorName, logName, message.ThreadId, msg); + } + + options.WriteHandler = (message, _, _, _, _) => { + MarkupLine(message.Message.EscapeMarkup(), message, logLevels); + if (message.Exception != null) { + MarkupLine(message.Exception.ToString().EscapeMarkup(), message, logLevels); + } + }; + } + else { + options.WriteHandler = (message, _, _, _, _) => { + var msg = message.Message.ReplaceLineEndings(string.Empty); + var (date, logName, logFormat) = ParseMessage(message, false); + Console.WriteLine( // + logFormat, date, logLevels[(LogLevels)message.LogLevel].ShortName, logName, message.ThreadId + , msg); + }; + } + }); + } + + /// + /// 注册上下文用户 + /// + public static IServiceCollection AddContextUser(this IServiceCollection me) + { + _ = me.AddScoped(typeof(ContextUserToken), _ => ContextUserToken.Create()); + _ = me.AddScoped(typeof(ContextUserInfo), _ => ContextUserInfo.Create()); + + return me; + } + + /// + /// 注册事件总线 + /// + public static IServiceCollection AddEventBus(this IServiceCollection me) + { + _ = me.AddEventBus(builder => builder.AddSubscribers(App.Assemblies.ToArray())); + return me; + } + + /// + /// 注册freeSql orm工具 + /// + public static IServiceCollection AddFreeSql( // + this IServiceCollection me, FreeSqlInitOptions initOptions = FreeSqlInitOptions.None + , Action freeSqlConfig = null) + { + // 非调试模式下禁止同步数据库 + #if !DEBUG + initOptions = FreeSqlInitOptions.None; + #endif + var freeSql = new FreeSqlBuilder(App.GetOptions()).Build(initOptions); + _ = me.AddSingleton(freeSql); + + var sqlAuditor = App.GetService(); + + freeSql.Aop.AuditValue += sqlAuditor.DataAuditHandler; // Insert/Update自动值处理 + + // AOP事件发布(异步) + freeSql.Aop.CommandBefore + += (_, e) => App.GetService().PublishAsync(new SqlCommandBeforeEvent(e)); // 增删查改,执行命令之前触发 + freeSql.Aop.CommandAfter + += (_, e) => App.GetService().PublishAsync(new SqlCommandAfterEvent(e)); // 增删查改,执行命令完成后触发 + + freeSql.Aop.SyncStructureBefore += (_, e) => + App.GetService().PublishAsync(new SyncStructureBeforeEvent(e)); // CodeFirst迁移,执行之前触发 + + freeSql.Aop.SyncStructureAfter += (_, e) => + App.GetService().PublishAsync(new SyncStructureAfterEvent(e)); // CodeFirst迁移,执行完成触发 + + // 全局过滤器设置 + freeSqlConfig?.Invoke(freeSql); + + _ = me.AddScoped(); // 注入工作单元管理器 + _ = me.AddFreeRepository(null, App.Assemblies.ToArray()); // 批量注入 Repository + _ = me.AddMvcFilter(); // 注入事务拦截器 + + return me; + } + + /// + /// 注册内存缓存 + /// + public static IServiceCollection AddMemCache(this IServiceCollection me) + { + _ = me.AddMemoryCache(options => options.TrackStatistics = true); + return me; + } + + /// + /// OpenTelemetry数据监控 + /// + public static IServiceCollection AddOpenTelemetryNet(this IServiceCollection me) + { + // _ = me.AddOpenTelemetry() + // .WithMetrics(builder => builder.AddAspNetCoreInstrumentation() + // .AddHttpClientInstrumentation() + // .AddRuntimeInstrumentation() + // .AddProcessInstrumentation() + // .AddPrometheusExporter()); + return me; + } + + /// + /// 注册Redis缓存 + /// + public static IServiceCollection AddRedisCache(this IServiceCollection me) + { + var redisOptions = App.GetOptions() + .Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE); + + // IDistributedCache 分布式缓存通用接口 + _ = me.AddStackExchangeRedisCache(options => { + // 连接字符串 + options.Configuration = redisOptions.ConnStr; + }); + + // Redis原生接口 + _ = me.AddSingleton(ConnectionMultiplexer.Connect(redisOptions.ConnStr)); + return me; + } + + /// + /// 注册雪花编号生成器 + /// + public static IServiceCollection AddSnowflake(this IServiceCollection me) + { + // 雪花漂移算法 + var idGeneratorOptions = new IdGeneratorOptions(); + YitIdHelper.SetIdGenerator(idGeneratorOptions); + return me; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Extensions/UnitOfWorkManagerExtensions.cs b/src/backend/NetAdmin.Host/Extensions/UnitOfWorkManagerExtensions.cs new file mode 100644 index 00000000..ebe32d28 --- /dev/null +++ b/src/backend/NetAdmin.Host/Extensions/UnitOfWorkManagerExtensions.cs @@ -0,0 +1,30 @@ +namespace NetAdmin.Host.Extensions; + +/// +/// 工作单元管理器扩展类 +/// +public static class UnitOfWorkManagerExtensions +{ + /// + /// 事务操作 + /// + public static async Task AtomicOperateAsync(this UnitOfWorkManager me, Func handle) + { + var logger = LogHelper.Get(); + using var unitOfWork = me.Begin(); + var hashCode = unitOfWork.GetHashCode(); + try { + #if DEBUG + logger?.Debug($"{Ln.开始事务}: {hashCode}"); + #endif + await handle(); + unitOfWork.Commit(); + logger?.Info($"{Ln.事务已提交}: {hashCode}"); + } + catch { + unitOfWork.Rollback(); + logger?.Error($"{Ln.事务已回滚}: {hashCode}"); + throw; + } + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Filters/ApiResultHandler.cs b/src/backend/NetAdmin.Host/Filters/ApiResultHandler.cs new file mode 100644 index 00000000..84876d49 --- /dev/null +++ b/src/backend/NetAdmin.Host/Filters/ApiResultHandler.cs @@ -0,0 +1,99 @@ +using Furion.FriendlyException; +using NetAdmin.Domain.Dto; + +namespace NetAdmin.Host.Filters; + +/// +/// Api结果格式化处理器 +/// +/// +/// 约定: +/// 1、业务异常需要设置HttpStatusCode与成功请求区分,不要统一返回200( 为了方便前端调试:在浏览器F12中快速观察失败请求【红色高亮】) +/// 2、不得占用常见HttpStatusCode,例如4xx、5xx,以免与传输层错误混淆,干扰运维。 +/// 实现: +/// 1、本系统代码覆盖范围内占用4个HttpStatusCode:200(表示业务成功)、401(身份未确认)、403(权限不足)、900(其他所有业务异常) +/// 2、当HttpStatusCode为900时,通过子码(JsonBody里面的Code区分具体异常),同时将子码写入RspHeader中,方便日志系统快速筛选归类。 +/// 3、子码定义,见枚举 +/// +public abstract class ApiResultHandler + where T : RestfulInfo, new() +{ + /// + /// 发生异常 + /// + public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata) + { + var lineException = context.Exception switch { NetAdminException ex => ex, _ => null }; + var errorCode = lineException?.Code ?? ErrorCodes.Unhandled; + var result = RestfulResult(errorCode, metadata.Data, lineException?.Message ?? errorCode.ResDesc()); + + SetErrorCodeToHeader(context.HttpContext, errorCode); + + return new JsonResult(result) { StatusCode = Numbers.HTTP_STATUS_BIZ_FAIL }; + } + + /// + /// HTTP状态码处理 + /// + #pragma warning disable ASA001 + public Task OnResponseStatusCodes( // + HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings = null) + { + // 设置响应状态码 + UnifyContext.SetResponseStatusCodes(context, statusCode, unifyResultSettings); + return Task.CompletedTask; + } + + /// + /// 请求成功 + /// + public IActionResult OnSucceeded(ActionExecutedContext _, object data) + { + return new JsonResult(RestfulResult(0, data)); + } + + /// + /// 校验失败 + /// + public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata) + { + SetErrorCodeToHeader(context.HttpContext, ErrorCodes.InvalidInput); + + return new JsonResult(RestfulResult(ErrorCodes.InvalidInput, metadata.Data + , GetValidationResult(metadata.ValidationResult))) { + StatusCode = Numbers.HTTP_STATUS_BIZ_FAIL + }; + } + + private static object GetValidationResult(object validationResult) + { + var startWithDollar = false; + try { + return validationResult is Dictionary dic + ? dic.ToDictionary( // + x => (startWithDollar = x.Key.StartsWith("$", StringComparison.InvariantCulture)) + ? x.Key[1..].TrimStart('.').NullOrEmpty(null) ?? throw new NetAdminInvalidInputException() + : x.Key, x => startWithDollar ? new[] { Ln.参数格式不正确 } : x.Value) + : validationResult; + } + catch (NetAdminInvalidInputException) { + return Ln.参数格式不正确; + } + } + + /// + /// 返回 RESTful 风格结果集 + /// + private static T RestfulResult(ErrorCodes errorCode, object data = default, object message = default) + { + return new T { Code = errorCode, Data = data, Msg = message }; + } + + /// + /// 写入错误码到HttpHeader + /// + private static void SetErrorCodeToHeader(HttpContext context, ErrorCodes errorCode) + { + context.Response.Headers[nameof(ErrorCodes)] = Enum.GetName(errorCode); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Filters/DefaultApiResultHandler.cs b/src/backend/NetAdmin.Host/Filters/DefaultApiResultHandler.cs new file mode 100644 index 00000000..77c31aa7 --- /dev/null +++ b/src/backend/NetAdmin.Host/Filters/DefaultApiResultHandler.cs @@ -0,0 +1,19 @@ +using NetAdmin.Domain.Dto; + +namespace NetAdmin.Host.Filters; + +/// +/// Api结果格式化处理器 +/// +/// +/// 约定: +/// 1、业务异常需要设置HttpStatusCode与成功请求区分,不要统一返回200( 为了方便前端调试:在浏览器F12中快速观察失败请求【红色高亮】) +/// 2、不得占用常见HttpStatusCode,例如4xx、5xx,以免与传输层错误混淆,干扰运维。 +/// 实现: +/// 1、本系统代码覆盖范围内占用4个HttpStatusCode:200(表示业务成功)、401(身份未确认)、403(权限不足)、900(其他所有业务异常) +/// 2、当HttpStatusCode为900时,通过子码(JsonBody里面的Code区分具体异常),同时将子码写入RspHeader中,方便日志系统快速筛选归类。 +/// 3、子码定义,见枚举 +/// +[SuppressSniffer] +[UnifyModel(typeof(RestfulInfo<>))] +public sealed class DefaultApiResultHandler : ApiResultHandler>, IUnifyResultProvider { } \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Filters/GlobalExceptionHandler.cs b/src/backend/NetAdmin.Host/Filters/GlobalExceptionHandler.cs new file mode 100644 index 00000000..70fa549f --- /dev/null +++ b/src/backend/NetAdmin.Host/Filters/GlobalExceptionHandler.cs @@ -0,0 +1,33 @@ +using Furion.FriendlyException; + +namespace NetAdmin.Host.Filters; + +/// +/// 全局捕异常 +/// +public sealed class GlobalExceptionHandler : IGlobalExceptionHandler, ISingleton +{ + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + public GlobalExceptionHandler(ILogger logger) + { + _logger = logger; + } + + /// + /// 异常拦截 + /// + public Task OnExceptionAsync(ExceptionContext context) + { + _logger.Error(context.Exception); + + // 将异常设置到HttpContext.Features中 以便中间件能获取到他 + context.HttpContext.Features.Set( + new ExceptionHandlerFeature { Error = context.Exception }); + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Filters/TransactionInterceptor.cs b/src/backend/NetAdmin.Host/Filters/TransactionInterceptor.cs new file mode 100644 index 00000000..4865f325 --- /dev/null +++ b/src/backend/NetAdmin.Host/Filters/TransactionInterceptor.cs @@ -0,0 +1,41 @@ +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Extensions; + +namespace NetAdmin.Host.Filters; + +/// +/// 事务拦截器 +/// +[SuppressSniffer] +public sealed class TransactionInterceptor : IAsyncActionFilter +{ + private readonly UnitOfWorkManager _uowManager; + + /// + /// Initializes a new instance of the class. + /// 事务拦截器 + /// + public TransactionInterceptor(UnitOfWorkManager uowManager) + { + _uowManager = uowManager; + } + + /// + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + // 跳过没有事务特性标记的方法 + if (context.HttpContext.GetControllerActionDescriptor().MethodInfo.GetCustomAttribute() == + null) { + _ = await next(); + return; + } + + // 事务操作 + await _uowManager.AtomicOperateAsync(async () => { + var result = await next(); + if (result.Exception != null) { + throw result.Exception; + } + }); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Middlewares/RemoveNullNodeMiddleware.cs b/src/backend/NetAdmin.Host/Middlewares/RemoveNullNodeMiddleware.cs new file mode 100644 index 00000000..301335b8 --- /dev/null +++ b/src/backend/NetAdmin.Host/Middlewares/RemoveNullNodeMiddleware.cs @@ -0,0 +1,34 @@ +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Extensions; + +namespace NetAdmin.Host.Middlewares; + +/// +/// 删除 response json body 中value 为null的节点 +/// +public sealed class RemoveNullNodeMiddleware +{ + private readonly RequestDelegate _next; + + /// + /// Initializes a new instance of the class. + /// + public RemoveNullNodeMiddleware(RequestDelegate next) + { + _next = next; + } + + /// + /// InvokeAsync + /// + public async Task InvokeAsync(HttpContext context) + { + await _next(context); + + if (context.GetMetadata() is null) { + return; + } + + await context.RemoveJsonNodeWithNullValueAsync(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Middlewares/RequestAuditMiddleware.cs b/src/backend/NetAdmin.Host/Middlewares/RequestAuditMiddleware.cs new file mode 100644 index 00000000..b5552e6d --- /dev/null +++ b/src/backend/NetAdmin.Host/Middlewares/RequestAuditMiddleware.cs @@ -0,0 +1,72 @@ +using NetAdmin.Host.Utils; + +namespace NetAdmin.Host.Middlewares; + +/// +/// 请求审计中间件 +/// +/// +/// 放在所有中间件最前面 +/// +public sealed class RequestAuditMiddleware +{ + private readonly PathString _defaultRoutePrefix; + private readonly PathString _healthCheckRoutePrefix; + private readonly RequestDelegate _next; + private readonly RequestLogger _requestLogger; + + /// + /// Initializes a new instance of the class. + /// + public RequestAuditMiddleware( // + RequestDelegate next, IOptions dynamicApiControllerSettingsOptions + , RequestLogger requestLogger) + { + _next = next; + _requestLogger = requestLogger; + _defaultRoutePrefix = new PathString($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}"); + _healthCheckRoutePrefix + = new PathString($"/{dynamicApiControllerSettingsOptions.Value.DefaultRoutePrefix}/health/check"); + } + + /// + /// InvokeAsync + /// + public async Task InvokeAsync(HttpContext context) + { + // 跳过处理的情况: + if (!context.Request.Path.StartsWithSegments(_defaultRoutePrefix) // 非api请求 + || context.Request.Path.StartsWithSegments(_healthCheckRoutePrefix) // 健康检查 + || context.Request.Method == Chars.FLG_HTTP_METHOD_OPTIONS) { // is options 请求 + await _next(context); + return; + } + + // Response.Body流默认是不可读的,将Response.Body流替换成MemoryStream 使其可读 + using var ms = new MemoryStream(); + var stream = context.Response.Body; + context.Response.Body = ms; + + // 在控制台上输出分割线,区分不同请求 + + // 调用下一个中间件 + var sw = Stopwatch.StartNew(); + await _next(context); + sw.Stop(); + + _ = ms.Seek(0, SeekOrigin.Begin); + using var sr = new StreamReader(ms); + var responseBody = await sr.ReadToEndAsync(); + _ = ms.Seek(0, SeekOrigin.Begin); + await ms.CopyToAsync(stream); + context.Response.Body = stream; + + var exception = context.Features.Get(); + var errorCode = context.Response.Headers[nameof(ErrorCodes)] // + .FirstOrDefault() + ?.Enum() ?? 0; + + _ = await _requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMicroseconds, responseBody, errorCode + , exception); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/NetAdmin.Host.csproj b/src/backend/NetAdmin.Host/NetAdmin.Host.csproj new file mode 100644 index 00000000..706d4416 --- /dev/null +++ b/src/backend/NetAdmin.Host/NetAdmin.Host.csproj @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Startup.cs b/src/backend/NetAdmin.Host/Startup.cs new file mode 100644 index 00000000..b581124f --- /dev/null +++ b/src/backend/NetAdmin.Host/Startup.cs @@ -0,0 +1,34 @@ +using Spectre.Console; + +namespace NetAdmin.Host; + +/// +/// 启动类 +/// +public abstract class Startup : AppStartup +{ + /// + /// 打印Banner + /// + protected static void ShowBanner() + { + AnsiConsole.WriteLine(); + var gridInfo = new Grid().AddColumn(new GridColumn().NoWrap().PadRight(10)) + .AddColumn(new GridColumn().NoWrap()) + .Expand(); + foreach (var kv in ApplicationHelper.GetEnvironmentInfo()) { + _ = gridInfo.AddRow(kv.Key, kv.Value.ToString()!.EscapeMarkup()); + } + + var gridWrap = new Grid().AddColumn(); + var entryAssembly = Assembly.GetEntryAssembly(); + var assemblyName = entryAssembly!.GetName(); + foreach (var str in assemblyName.Name!.Split('.')) { + _ = gridWrap.AddRow(new FigletText(str).Color(Color.Green)); + } + + _ = gridWrap.AddRow(gridInfo); + AnsiConsole.Write(new Panel(gridWrap).Header(Global.ProductVersion).Expand()); + AnsiConsole.WriteLine(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Subscribers/SqlProfiler.cs b/src/backend/NetAdmin.Host/Subscribers/SqlProfiler.cs new file mode 100644 index 00000000..d2b73956 --- /dev/null +++ b/src/backend/NetAdmin.Host/Subscribers/SqlProfiler.cs @@ -0,0 +1,63 @@ +using NetAdmin.Domain.Events; + +namespace NetAdmin.Host.Subscribers; + +/// +/// Sql性能分析 +/// +public sealed class SqlProfiler : IEventSubscriber +{ + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + public SqlProfiler(ILogger logger) + { + _logger = logger; + } + + /// + /// Sql命令执行后 + /// + [EventSubscribe(nameof(SqlCommandAfterEvent))] + public Task CommandAfterAsync(EventHandlerExecutingContext context) + { + var source = context.Source as SqlCommandAfterEvent; + _logger.Info(source); + return Task.CompletedTask; + } + + /// + /// Sql命令执行前 + /// + [EventSubscribe(nameof(SqlCommandBeforeEvent))] + public Task CommandBeforeAsync(EventHandlerExecutingContext context) + { + var source = context.Source as SqlCommandBeforeEvent; + _logger.Debug(source); + return Task.CompletedTask; + } + + /// + /// 同步数据库结构之后 + /// + [EventSubscribe(nameof(SyncStructureAfterEvent))] + public Task SyncStructureAfterAsync(EventHandlerExecutingContext context) + { + var source = context.Source as SyncStructureAfterEvent; + _logger.Info(source); + return Task.CompletedTask; + } + + /// + /// 同步数据库结构之前 + /// + [EventSubscribe(nameof(SyncStructureBeforeEvent))] + public Task SyncStructureBeforeAsync(EventHandlerExecutingContext context) + { + var source = context.Source as SyncStructureBeforeEvent; + _logger.Info(source); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Utils/CollectionJsonTypeInfoResolver.cs b/src/backend/NetAdmin.Host/Utils/CollectionJsonTypeInfoResolver.cs new file mode 100644 index 00000000..dfd3e462 --- /dev/null +++ b/src/backend/NetAdmin.Host/Utils/CollectionJsonTypeInfoResolver.cs @@ -0,0 +1,92 @@ +namespace NetAdmin.Host.Utils; + +/// +/// 处理集合类型的Json解析器 +/// +public sealed class CollectionJsonTypeInfoResolver : DefaultJsonTypeInfoResolver +{ + /// + /// Initializes a new instance of the class. + /// + public CollectionJsonTypeInfoResolver() + { + Modifiers.Add(CollectionValueModifier); + } + + private static void CollectionValueModifier(JsonTypeInfo typeInfo) + { + foreach (var property in typeInfo.Properties) { + // 跳过非集合属性 + if (!property.PropertyType.GetInterfaces().Contains(typeof(IEnumerable))) { + continue; + } + + // 跳过字符串 + if (property.PropertyType == typeof(string)) { + continue; + } + + var memberName = GetMemberName(property); + + // object->json 只在count>0时返回其值,否则返回null + property.Get = PropertyGet(memberName); + + // json->object 时 为对象分配属性, 改为只在count>0分配 ,否则分配null,而不是分配[] + property.Set = PropertySet(memberName); + } + } + + private static string GetMemberName(JsonPropertyInfo property) + { + return property.GetType() + .GetRuntimeProperties() + .First(x => x.Name == "MemberName") + .GetValue(property) as string; + } + + /// + /// 这里处理子类new隐藏父类同名属性, 取得多个同名属性的问题 + /// + private static PropertyInfo GetNewProperty(string memberName, object obj) + { + return obj.GetType() + .GetProperties() + .Where(x => x.Name == memberName) + .First(x => x.DeclaringType == x.ReflectedType); + } + + /// + /// object->json 只在count>0时返回其值,否则返回null + /// + private static Func PropertyGet(string memberName) + { + return obj => { + object prop; + try { + prop = obj.GetType().GetProperty(memberName!)?.GetValue(obj); + } + catch (AmbiguousMatchException) { + // 这里处理子类new隐藏父类同名属性, 取得多个同名属性的问题 + prop = GetNewProperty(memberName, obj).GetValue(obj); + } + + return prop switch { string => prop, ICollection { Count: > 0 } => prop, _ => null }; + }; + } + + /// + /// json->object 时 为对象分配属性, 改为只在count>0分配 ,否则分配null,而不是分配[] + /// + private static Action PropertySet(string memberName) + { + return (obj, val) => { + val = val switch { string => val, ICollection { Count: > 0 } => val, _ => null }; + try { + obj.GetType().GetProperty(memberName!)?.SetValue(obj, val); + } + catch (AmbiguousMatchException) { + GetNewProperty(memberName, obj).SetValue(obj, val); + } + }; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Utils/RequestLogger.cs b/src/backend/NetAdmin.Host/Utils/RequestLogger.cs new file mode 100644 index 00000000..8c9a1913 --- /dev/null +++ b/src/backend/NetAdmin.Host/Utils/RequestLogger.cs @@ -0,0 +1,95 @@ +using NetAdmin.Domain.Contexts; +using NetAdmin.Domain.Dto.Sys.RequestLog; +using NetAdmin.Domain.Events.Sys; + +namespace NetAdmin.Host.Utils; + +/// +/// 请求日志记录器 +/// +public sealed class RequestLogger : ISingleton +{ + private static readonly string[] _textContentTypes = { "text", "json", "xml", "urlencoded" }; + private readonly IEventPublisher _eventPublisher; + private readonly ILogger _logger; + private readonly int _tokenPrefixLength; + + /// + /// Initializes a new instance of the class. + /// + public RequestLogger( // + ILogger logger + , IOptions specificationDocumentSettingsOptions + , IEventPublisher eventPublisher) + { + _logger = logger; + _eventPublisher = eventPublisher; + _tokenPrefixLength = specificationDocumentSettingsOptions?.Value.SecurityDefinitions?[0]?.Scheme?.Length + 1 ?? + 0; // eg. "Bearer " + } + + /// + /// 生成审计数据 + /// + public async Task LogAsync(HttpContext context, long duration, string responseBody + , ErrorCodes errorCode, IExceptionHandlerFeature exception) + { + // 从请求头中读取用户信息 + var associatedUser = GetAssociatedUser(context); + + var auditData = new CreateRequestLogReq { + Duration = duration + , Method = context.Request.Method + , ReferUrl = context.Request.GetRefererUrlAddress() + , RequestContentType = context.Request.ContentType + , RequestBody = Array.Exists( // + _textContentTypes + , x => context.Request.ContentType?.Contains( + x, StringComparison.OrdinalIgnoreCase) ?? false) + ? await context.ReadBodyContentAsync() + : string.Empty + , RequestUrl = context.Request.GetRequestUrlAddress() + , ResponseBody = responseBody + , ServerIp = context.GetLocalIpAddressToIPv4()?.IpV4ToInt32() + , ApiId = context.Request.Path.Value?.TrimStart('/') + , RequestHeaders = context.Request.Headers.ToJson() + , ResponseContentType = context.Response.ContentType + , ResponseHeaders = context.Response.Headers.ToJson() + , HttpStatusCode = context.Response.StatusCode + , ErrorCode = errorCode + , Exception = exception?.Error.ToString() + , CreatedUserId = associatedUser?.UserId + , CreatedUserName = associatedUser?.UserName + , CreatedUserAgent = context.Request.Headers.UserAgent.ToString() + , CreatedClientIp = context.GetRemoteIpAddressToIPv4()?.IpV4ToInt32() + }; + + // 打印日志 + _logger.Info(auditData); + + // 发布请求日志事件 + await _eventPublisher.PublishAsync(new RequestLogEvent(auditData)); + + return auditData; + } + + private (long UserId, string UserName)? GetAssociatedUser(HttpContext context) + { + var token = context.Request.Headers.Authorization.FirstOrDefault(); + if (token == null) { + return null; + } + + ContextUserToken userToken = null; + try { + var jsonWebToken = JWTEncryption.ReadJwtToken(token[_tokenPrefixLength..]); + var claim = jsonWebToken?.Claims.FirstOrDefault(y => y.Type == nameof(ContextUserToken)); + userToken = claim?.Value.ToObject(); + } + catch (Exception ex) { + _logger.Warn($"{Ln.读取用户令牌出错}: {ex}"); + } + + return userToken == null ? null : (userToken.Id, userToken.UserName); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Utils/SqlAuditor.cs b/src/backend/NetAdmin.Host/Utils/SqlAuditor.cs new file mode 100644 index 00000000..b25a3574 --- /dev/null +++ b/src/backend/NetAdmin.Host/Utils/SqlAuditor.cs @@ -0,0 +1,181 @@ +using NetAdmin.Domain.Attributes; +using NetAdmin.Domain.Contexts; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using Yitter.IdGenerator; + +namespace NetAdmin.Host.Utils; + +/// +/// Sql审核器 +/// +public sealed class SqlAuditor : ISingleton +{ + /// + /// 数据库服务器时钟偏移 + /// + #pragma warning disable S1450 + + // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable + private readonly TimeSpan _timeOffset; + #pragma warning restore S1450 + + /// + /// Initializes a new instance of the class. + /// + public SqlAuditor(ILogger logger) + { + // 设置服务器时间偏差 + _timeOffset = DateTime.UtcNow.Subtract(App.GetService().Ado.QuerySingle(() => DateTime.UtcNow)); + + logger.Info($"{Ln.数据库服务器时钟偏移} {_timeOffset}"); + } + + /// + /// 对Insert/Update的数据加工 + /// + /// e + public void DataAuditHandler(object sender, AuditValueEventArgs e) + { + // SetServerTime(e); + SetSnowflake(e); + + // 设置创建者、修改者信息 + var user = App.GetService(); + switch (e.AuditValueType) { + case AuditValueType.Insert: + SetCreator(e, user); + SetOwner(e, user); + break; + case AuditValueType.Update: + SetUpdater(e, user); + break; + case AuditValueType.InsertOrUpdate: + break; + default: + throw new ArgumentOutOfRangeException(nameof(e)); + } + } + + /// + /// 设置创建者 + /// + private static void SetCreator(AuditValueEventArgs e, ContextUserInfo userInfo) + { + switch (e.Property.Name) { + case nameof(IFieldCreatedTime.CreatedTime): + if (e.Value == null || (e.Value is DateTime val && val == default)) { + e.Value = DateTime.Now; + } + + break; + case nameof(IFieldCreatedUser.CreatedUserId): + if (userInfo != null && e.Value is null or (long and 0)) { + e.Value = userInfo.Id; + } + + break; + + case nameof(IFieldCreatedUser.CreatedUserName): + if (userInfo != null && e.Value is null or "") { + e.Value = userInfo.UserName; + } + + break; + case nameof(IFieldCreatedClient.CreatedClientIp): + if (e.Value is null or 0) { + e.Value = App.HttpContext?.GetRemoteIpAddressToIPv4().IpV4ToInt32(); + } + + break; + case nameof(IFieldCreatedClient.CreatedUserAgent): + if (e.Value is null or "") { + e.Value = App.HttpContext?.Request.Headers[Chars.FLG_HTTP_HEADER_USER_AGENT].ToString(); + } + + break; + case nameof(IFieldCreatedClient.CreatedReferer): + if (e.Value is null or "") { + e.Value = App.HttpContext?.Request.GetRefererUrlAddress(); + } + + break; + default: + return; + } + } + + /// + /// 设置拥有者 + /// + private static void SetOwner(AuditValueEventArgs e, ContextUserInfo userInfo) + { + switch (e.Property.Name) { + case nameof(IFieldOwner.OwnerId): + if (userInfo != null && e.Value is null or (long and 0)) { + e.Value = userInfo.Id; + } + + break; + case nameof(IFieldOwner.OwnerDeptId): + if (userInfo != null && e.Value is null or "") { + e.Value = userInfo.Dept.Id; + } + + break; + default: + return; + } + } + + /// + /// 设置雪花编号字段 + /// + private static void SetSnowflake(AuditValueEventArgs e) + { + var isSnowflake = e.Property.GetCustomAttribute(false) != null; + var isLongType = e.Column.CsType == typeof(long); + var isNoValue = e.Value is null or (long and 0); + if (isSnowflake && isLongType && isNoValue) { + e.Value = YitIdHelper.NextId(); + } + } + + /// + /// 设置更新人 + /// + private static void SetUpdater(AuditValueEventArgs e, ContextUserInfo userInfo) + { + switch (e.Property.Name) { + // case nameof(IFieldModifiedTime.ModifiedTime): + // e.Value = DateTime.Now; + // break; + case nameof(IFieldModifiedUser.ModifiedUserId): + if (userInfo != null && e.Value is null or (long and 0)) { + e.Value = userInfo.Id; + } + + break; + + case nameof(IFieldModifiedUser.ModifiedUserName): + if (userInfo != null && e.Value is null or "") { + e.Value = userInfo.UserName; + } + + break; + } + } + + // /// + // /// 设置服务器时间字段 + // /// + // private void SetServerTime(AuditValueEventArgs e) + // #pragma warning restore RCS1213, IDE0051 + // { + // var isServerTime = e.Property.GetCustomAttribute(false) is { Enable: true }; + // var isDateType = e.Column.CsType == typeof(DateTime) || e.Column.CsType == typeof(DateTime?); + // var hasValue = e.Value is DateTime val && val != default; + // if (isServerTime && isDateType && hasValue) { + // e.Value = ((DateTime)e.Value).Subtract(_timeOffset); + // } + // } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Utils/SwaggerEnumSchemaFixer.cs b/src/backend/NetAdmin.Host/Utils/SwaggerEnumSchemaFixer.cs new file mode 100644 index 00000000..b2f9e105 --- /dev/null +++ b/src/backend/NetAdmin.Host/Utils/SwaggerEnumSchemaFixer.cs @@ -0,0 +1,40 @@ +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace NetAdmin.Host.Utils; + +/// +/// 修正 规范化文档 Enum 提示 +/// +[SuppressSniffer] +public sealed class SwaggerEnumSchemaFixer : ISchemaFilter +{ + /// + /// 实现过滤器方法 + /// + public void Apply(OpenApiSchema schema, SchemaFilterContext context) + { + // 非枚举退出 + if (!context.Type.IsEnum) { + return; + } + + const string wrap = "
"; + schema.Enum.Clear(); + schema.Type = context.Type.Name; + var sb = new StringBuilder(); + _ = sb.Append(schema.Description); + + foreach (var e in Enum.GetValues(context.Type).Cast()) { + var value = Convert.ToInt64(e, CultureInfo.InvariantCulture); + schema.Enum.Add(new OpenApiLong(value)); + _ = sb.Append(wrap) + .Append( // + CultureInfo.InvariantCulture + , $"{Enum.GetName(context.Type, e).ToLowerCamelCase()} = {value} ({e.ResDesc()})"); + } + + schema.Description = sb.ToString(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Host/Utils/ToNullIfEmptyStringConverter.cs b/src/backend/NetAdmin.Host/Utils/ToNullIfEmptyStringConverter.cs new file mode 100644 index 00000000..ccb819aa --- /dev/null +++ b/src/backend/NetAdmin.Host/Utils/ToNullIfEmptyStringConverter.cs @@ -0,0 +1,25 @@ +namespace NetAdmin.Host.Utils; + +/// +/// "" -> null 转换器 +/// +public sealed class ToNullIfEmptyStringConverter : JsonConverter +{ + /// + public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Number) { + var success = reader.TryGetDecimal(out var dec); + return success ? dec.ToString(CultureInfo.InvariantCulture) : "0"; + } + + var ret = reader.GetString(); + return ret?.Length == 0 ? null : ret; + } + + /// + public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.Length == 0 ? null : value); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Attributes/ExportAttribute.cs b/src/backend/NetAdmin.Infrastructure/Attributes/ExportAttribute.cs new file mode 100644 index 00000000..8114df34 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Attributes/ExportAttribute.cs @@ -0,0 +1,7 @@ +namespace NetAdmin.Infrastructure.Attributes; + +/// +/// 标记一个此字段(枚举)将通过接口暴露到前端 +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Enum)] +public sealed class ExportAttribute : Attribute { } \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Configuration/Options/CaptchaOptions.cs b/src/backend/NetAdmin.Infrastructure/Configuration/Options/CaptchaOptions.cs new file mode 100644 index 00000000..b3fe85f3 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Configuration/Options/CaptchaOptions.cs @@ -0,0 +1,28 @@ +namespace NetAdmin.Infrastructure.Configuration.Options; + +/// +/// 人机验证配置 +/// +public sealed record CaptchaOptions : OptionAbstraction +{ + private static readonly double _seed + = BitConverter.ToInt32(Chars.TPL_DATE_YYYYMMDD[..4].Select(x => (byte)x).ToArray()); + + #pragma warning disable S3963 + static CaptchaOptions() + #pragma warning restore S3963 + { + var rtn = new char[32]; + for (var i = 0; i != 32; i++) { + rtn[i] = Chars.FLG_VISIBLE_ASCIIS[ + (int)(Math.Abs(Math.Sin(_seed * (i + 1))) * Chars.FLG_VISIBLE_ASCIIS.Length)]; + } + + SecretKey = new string(rtn); + } + + /// + /// 密钥 + /// + public static string SecretKey { get; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Configuration/Options/DatabaseOptions.cs b/src/backend/NetAdmin.Infrastructure/Configuration/Options/DatabaseOptions.cs new file mode 100644 index 00000000..469449f6 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Configuration/Options/DatabaseOptions.cs @@ -0,0 +1,24 @@ +using DataType = FreeSql.DataType; + +namespace NetAdmin.Infrastructure.Configuration.Options; + +/// +/// 数据库连接字符串配置 +/// +public sealed record DatabaseOptions : OptionAbstraction +{ + /// + /// 链接字符串 + /// + public string ConnStr { get; init; } + + /// + /// 数据库类型 + /// + public DataType DbType { get; init; } + + /// + /// 种子数据路径(相对) + /// + public string SeedDataRelativePath { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Configuration/Options/OptionAbstraction.cs b/src/backend/NetAdmin.Infrastructure/Configuration/Options/OptionAbstraction.cs new file mode 100644 index 00000000..bf9cca15 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Configuration/Options/OptionAbstraction.cs @@ -0,0 +1,6 @@ +namespace NetAdmin.Infrastructure.Configuration.Options; + +/// +/// 选项抽象基类 +/// +public abstract record OptionAbstraction : IConfigurableOptions; \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Configuration/Options/RedisOptions.cs b/src/backend/NetAdmin.Infrastructure/Configuration/Options/RedisOptions.cs new file mode 100644 index 00000000..e7ce70e6 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Configuration/Options/RedisOptions.cs @@ -0,0 +1,12 @@ +namespace NetAdmin.Infrastructure.Configuration.Options; + +/// +/// Redis配置 +/// +public sealed record RedisOptions : OptionAbstraction +{ + /// + /// 实例列表 + /// + public InstanceNode[] Instances { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Configuration/Options/SubNodes/Redis/InstanceNode.cs b/src/backend/NetAdmin.Infrastructure/Configuration/Options/SubNodes/Redis/InstanceNode.cs new file mode 100644 index 00000000..d6196da8 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Configuration/Options/SubNodes/Redis/InstanceNode.cs @@ -0,0 +1,22 @@ +namespace NetAdmin.Infrastructure.Configuration.Options.SubNodes.Redis; + +/// +/// Redis实例 +/// +public sealed record InstanceNode +{ + /// + /// 链接字符串 + /// + public string ConnStr { get; init; } + + /// + /// 数据库 + /// + public int Database { get; set; } + + /// + /// 实例名称 + /// + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Configuration/Options/SubNodes/Upload/MinioNode.cs b/src/backend/NetAdmin.Infrastructure/Configuration/Options/SubNodes/Upload/MinioNode.cs new file mode 100644 index 00000000..f1f8b61a --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Configuration/Options/SubNodes/Upload/MinioNode.cs @@ -0,0 +1,37 @@ +namespace NetAdmin.Infrastructure.Configuration.Options.SubNodes.Upload; + +/// +/// Minio 节点 +/// +public sealed record MinioNode +{ + /// + /// 访问令牌 + /// + public string AccessKey { get; init; } + + /// + /// 文件访问Url地址 + /// + public string AccessUrl { get; init; } + + /// + /// 使用的存储桶名称 + /// + public string BucketName { get; init; } + + /// + /// 安全码 + /// + public string SecretKey { get; init; } + + /// + /// 是否启用ssl + /// + public bool Secure { get; init; } + + /// + /// 服务器地址 + /// + public string ServerAddress { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Configuration/Options/UploadOptions.cs b/src/backend/NetAdmin.Infrastructure/Configuration/Options/UploadOptions.cs new file mode 100644 index 00000000..2d4256b0 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Configuration/Options/UploadOptions.cs @@ -0,0 +1,22 @@ +namespace NetAdmin.Infrastructure.Configuration.Options; + +/// +/// 上传配置 +/// +public sealed record UploadOptions : OptionAbstraction +{ + /// + /// 允许的文件类型 + /// + public IReadOnlyCollection ContentTypes { get; init; } + + /// + /// 允许的文件大小(字节) + /// + public long MaxSize { get; init; } + + /// + /// Minio 配置 + /// + public MinioNode Minio { get; init; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs b/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs new file mode 100644 index 00000000..fa2c0561 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs @@ -0,0 +1,91 @@ +#pragma warning disable CS1591 + +namespace NetAdmin.Infrastructure.Constant; + +/// +/// 字符串常量表 +/// +/// +/// public类型会通过接口暴露给前端 +/// +public static class Chars +{ + public const string FLG_ACCESS_TOKEN = "ACCESS-TOKEN"; + public const string FLG_APPLICATION_JSON = "application/json"; + public const string FLG_CONSUL_REG_HOSTNAME = "CONSUL_REG_HOSTNAME"; + public const string FLG_CONSUL_REG_PORT = "CONSUL_REG_PORT"; + public const string FLG_CONTEXT_MEMBER_INFO = nameof(FLG_CONTEXT_MEMBER_INFO); + public const string FLG_CONTEXT_OWNER_DEPT_ID = nameof(FLG_CONTEXT_OWNER_DEPT_ID); + public const string FLG_CONTEXT_USER_ID = nameof(FLG_CONTEXT_USER_ID); + public const string FLG_CONTEXT_USER_INFO = nameof(FLG_CONTEXT_USER_INFO); + public const string FLG_DB_FIELD_TYPE_NVARCHAR = "nvarchar"; + public const string FLG_DB_FIELD_TYPE_NVARCHAR_255 = "nvarchar(255)"; + public const string FLG_DB_FIELD_TYPE_NVARCHAR_MAX = "nvarchar(max)"; + public const string FLG_DB_FIELD_TYPE_VARCHAR = "varchar"; + public const string FLG_DB_FIELD_TYPE_VARCHAR_1022 = "varchar(1022)"; + public const string FLG_DB_FIELD_TYPE_VARCHAR_127 = "varchar(127)"; + public const string FLG_DB_FIELD_TYPE_VARCHAR_15 = "varchar(15)"; + public const string FLG_DB_FIELD_TYPE_VARCHAR_255 = "varchar(255)"; + public const string FLG_DB_FIELD_TYPE_VARCHAR_31 = "varchar(31)"; + public const string FLG_DB_FIELD_TYPE_VARCHAR_4094 = "varchar(4094)"; + public const string FLG_DB_FIELD_TYPE_VARCHAR_510 = "varchar(510)"; + public const string FLG_DB_FIELD_TYPE_VARCHAR_63 = "varchar(63)"; + public const string FLG_DB_FIELD_TYPE_VARCHAR_7 = "varchar(7)"; + public const string FLG_DB_FIELD_TYPE_VARCHAR_MAX = "varchar(max)"; + public const string FLG_GLOBAL_FILTER_DATA = nameof(FLG_GLOBAL_FILTER_DATA); + public const string FLG_GLOBAL_FILTER_DELETE = nameof(FLG_GLOBAL_FILTER_DELETE); + public const string FLG_GLOBAL_FILTER_MEMBER = nameof(FLG_GLOBAL_FILTER_MEMBER); + public const string FLG_GLOBAL_FILTER_SELF = nameof(FLG_GLOBAL_FILTER_SELF); + public const string FLG_GLOBAL_FILTER_TENANT = nameof(FLG_GLOBAL_FILTER_TENANT); + public const string FLG_HEALTH_CHECK_PATH_PREFIX = "health/check"; + public const string FLG_HTTP_HEADER_REFERER = "Referer"; + public const string FLG_HTTP_HEADER_USER_AGENT = "User-Agent"; + public const string FLG_HTTP_METHOD_CONNECT = "CONNECT"; + public const string FLG_HTTP_METHOD_DELETE = "DELETE"; + public const string FLG_HTTP_METHOD_GET = "GET"; + public const string FLG_HTTP_METHOD_HEAD = "HEAD"; + public const string FLG_HTTP_METHOD_OPTIONS = "OPTIONS"; + public const string FLG_HTTP_METHOD_PATCH = "PATCH"; + public const string FLG_HTTP_METHOD_POST = "POST"; + public const string FLG_HTTP_METHOD_PUT = "PUT"; + public const string FLG_HTTP_METHOD_TRACE = "TRACE"; + public const string FLG_RANDOM_UNAME_PWD = "VcXlp7WY"; + public const string FLG_REDIS_INSTANCE_DATA_CACHE = "DataCache"; + public const string FLG_SYSTEM_PREFIX = "sc_"; + public const string FLG_TABLE_NAME_PREFIX = ""; + + public const string FLG_UA_MOBILE + = "Mozilla/5.0 (Linux; Android 9; Redmi Note 8 Pro Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.96 Mobile Safari/537.36"; + + public const string FLG_UA_PC + = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"; + + public const string FLG_VISIBLE_ASCIIS + = """!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"""; + + public const string FLG_X_ACCESS_TOKEN = "X-ACCESS-TOKEN"; + + public const string RGX_CERTIFICATE = """^[a-zA-Z0-9-_]+$"""; + + public const string RGX_CHINESE_NAME + = """^(?:赵|钱|孙|李|周|吴|郑|王|冯|陈|褚|卫|蒋|沈|韩|杨|朱|秦|尤|许|何|吕|施|张|孔|曹|严|华|金|魏|陶|姜|戚|谢|邹|喻|柏|水|窦|章|云|苏|潘|葛|奚|范|彭|郎|鲁|韦|昌|马|苗|凤|花|方|俞|任|袁|柳|酆|鲍|史|唐|费|廉|岑|薛|雷|贺|倪|汤|滕|殷|罗|毕|郝|邬|安|常|乐|于|时|傅|皮|卞|齐|康|伍|余|元|卜|顾|孟|平|黄|和|穆|萧|尹|姚|邵|湛|汪|祁|毛|禹|狄|米|贝|明|臧|计|伏|成|戴|谈|宋|茅|庞|熊|纪|舒|屈|项|祝|董|梁|杜|阮|蓝|闵|席|季|麻|强|贾|路|娄|危|江|童|颜|郭|梅|盛|林|刁|钟|徐|邱|骆|高|夏|蔡|田|樊|胡|凌|霍|虞|万|支|柯|昝|管|卢|莫|经|房|裘|缪|干|解|应|宗|丁|宣|贲|邓|郁|单|杭|洪|包|诸|左|石|崔|吉|钮|龚|程|嵇|邢|滑|裴|陆|荣|翁|荀|羊|於|惠|甄|曲|家|封|芮|羿|储|靳|汲|邴|糜|松|井|段|富|巫|乌|焦|巴|弓|牧|隗|山|谷|车|侯|宓|蓬|全|郗|班|仰|秋|仲|伊|宫|宁|仇|栾|暴|甘|钭|厉|戎|祖|武|符|刘|景|詹|束|龙|叶|幸|司|韶|郜|黎|蓟|薄|印|宿|白|怀|蒲|邰|从|鄂|索|咸|籍|赖|卓|蔺|屠|蒙|池|乔|阴|胥|能|苍|双|闻|莘|党|翟|谭|贡|劳|逄|姬|申|扶|堵|冉|宰|郦|雍|郤|璩|桑|桂|濮|牛|寿|通|边|扈|燕|冀|郏|浦|尚|农|温|别|庄|晏|柴|瞿|阎|充|慕|连|茹|习|宦|艾|鱼|容|向|古|易|慎|戈|廖|庾|终|暨|居|衡|步|都|耿|满|弘|匡|国|文|寇|广|禄|阙|东|欧|殳|沃|利|蔚|越|夔|隆|师|巩|厍|聂|晁|勾|敖|融|冷|訾|辛|阚|那|简|饶|空|曾|毋|沙|乜|养|鞠|须|丰|巢|关|蒯|相|查|後|荆|红|游|竺|权|逯|盖|益|桓|公|万俟|司马|上官|欧阳|夏侯|诸葛|闻人|东方|赫连|皇甫|尉迟|公羊|澹台|公冶|宗政|濮阳|淳于|单于|太叔|申屠|公孙|仲孙|轩辕|令狐|钟离|宇文|长孙|慕容|鲜于|闾丘|司徒|司空|亓官|司寇|仉|督|子车|颛孙|端木|巫马|公西|漆雕|乐正|壤驷|公良|拓跋|夹谷|宰父|谷梁|晋|楚|闫|法|汝|鄢|涂|钦|段干|百里|东郭|南门|呼延|归|海|羊舌|微生|岳|帅|缑|亢|况|后|有|琴|梁丘|左丘|东门|西门|商|牟|佘|佴|伯|赏|南宫|墨|哈|谯|笪|年|爱|阳|佟|第五|言|福)[\u4e00-\u9fa5]{1,3}$"""; + + public const string RGX_EMAIL + = """^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$"""; + + public const string RGX_INVITE_CODE = """^\d{8}$"""; + + public const string RGX_MOBILE = """^1(3\d|4[5-9]|5[0-35-9]|6[6]|7[2-8]|8\d|9[0-35-9])\d{8}$"""; + public const string RGX_PASSWORD = """^(?![0-9]+$)(?![a-zA-Z]+$).{8,16}$"""; + public const string RGX_PAY_PASSWORD = """^\d{6}$"""; + public const string RGX_TELEPHONE = """^((\d{3,4}\-)|)\d{7,8}(|([-\u8f6c]{1}\d{1,5}))$"""; + public const string RGX_URL = """^(https?|ftp):\/\/[^\s/$.?#].[^\s]*\.[^\s]{2,}$"""; + public const string RGX_USERNAME = """^[a-zA-Z0-9_]{4,16}$"""; + public const string RGX_VERIFY_CODE = """^\d{4}$"""; + + public const string TPL_DATE_HH_MM_SS_FFFFFF = "HH:mm:ss.ffffff"; + public const string TPL_DATE_YYYY_MM_DD = "yyyy-MM-dd"; + public const string TPL_DATE_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; + public const string TPL_DATE_YYYYMMDD = "yyyyMMdd"; + public const string TPL_DATE_YYYYMMDDHHMMSSFFFZZZZ = "yyyyMMddHHmmssfffzzz"; +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Constant/Numbers.cs b/src/backend/NetAdmin.Infrastructure/Constant/Numbers.cs new file mode 100644 index 00000000..c7db970d --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Constant/Numbers.cs @@ -0,0 +1,25 @@ +#pragma warning disable CS1591 + +namespace NetAdmin.Infrastructure.Constant; + +/// +/// 数字常量表 +/// +/// +/// public类型会通过接口暴露给前端 +/// +public static class Numbers +{ + public const int BULK_REQ_LIMIT = 100; // 批量请求允许的最大数量 + public const long DEF_SORT_VAL = 100; // 排序默认值 + public const long DIC_CATALOG_ID_GEO_AREA = 379794295185413; // 字典目录编号-行政区划字典 + public const int HEART_TIMEOUT_SECS = 600; // 心跳超时时间 + public const int HTTP_STATUS_BIZ_FAIL = 900; // Http状态码-业务异常 + public const int QUERY_DEF_PAGE_SIZE = 20; // 分页查询默认的页容量 + public const int QUERY_LIMIT = 100; // 非分页查询允许返回的最大条数 + public const int QUERY_MAX_PAGE_NO = 1000; // 分页查询允许最大的页码 + public const int QUERY_MAX_PAGE_SIZE = 100; // 分页查询允许最大的页容量 + public const int RED_LOCK_EXPIRY_TIME_SECS = 30; // red lock 锁锁定过期时间,锁区域内的逻辑执行如果超过过期时间,锁将被释放 + public const int RED_LOCK_RETRY_TIME_SECS = 1; // red lock 锁等待时间内,多久尝试获取一次 + public const int RED_LOCK_WAIT_TIME_SECS = 10; // red lock 锁等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Enums/CertificateTypes.cs b/src/backend/NetAdmin.Infrastructure/Enums/CertificateTypes.cs new file mode 100644 index 00000000..659b4a25 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Enums/CertificateTypes.cs @@ -0,0 +1,46 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 证件类型 +/// +[Export] +public enum CertificateTypes +{ + /// + /// 身份证 + /// + [ResourceDescription(nameof(Ln.身份证))] + IdentityCard = 1 + + , + + /// + /// 护照 + /// + [ResourceDescription(nameof(Ln.护照))] + Passport = 2 + + , + + /// + /// 外国人居留证 + /// + [ResourceDescription(nameof(Ln.外国人居留证))] + ForeignerResidencePermit = 3 + + , + + /// + /// 港澳台通行证 + /// + [ResourceDescription(nameof(Ln.港澳台通行证))] + HKorMacauPermit = 4 + + , + + /// + /// 出生证 + /// + [ResourceDescription(nameof(Ln.出生证))] + BirthCertificate = 5 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Enums/Educations.cs b/src/backend/NetAdmin.Infrastructure/Enums/Educations.cs new file mode 100644 index 00000000..cf88e935 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Enums/Educations.cs @@ -0,0 +1,78 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 学历 +/// +[Export] +public enum Educations +{ + /// + /// 小学 + /// + [ResourceDescription(nameof(Ln.小学))] + Primary = 1 + + , + + /// + /// 初中 + /// + [ResourceDescription(nameof(Ln.初中))] + Junior = 2 + + , + + /// + /// 高中 + /// + [ResourceDescription(nameof(Ln.高中))] + Higher = 3 + + , + + /// + /// 中专 + /// + [ResourceDescription(nameof(Ln.中专))] + Technical = 4 + + , + + /// + /// 大专 + /// + [ResourceDescription(nameof(Ln.大专))] + College = 5 + + , + + /// + /// 本科 + /// + [ResourceDescription(nameof(Ln.本科))] + Bachelor = 6 + + , + + /// + /// 硕士 + /// + [ResourceDescription(nameof(Ln.硕士))] + Master = 7 + + , + + /// + /// 博士 + /// + [ResourceDescription(nameof(Ln.博士))] + Doctor = 8 + + , + + /// + /// 博士后 + /// + [ResourceDescription(nameof(Ln.博士后))] + Post = 9 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Enums/ErrorCodes.cs b/src/backend/NetAdmin.Infrastructure/Enums/ErrorCodes.cs new file mode 100644 index 00000000..12749243 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Enums/ErrorCodes.cs @@ -0,0 +1,46 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 错误码 +/// +[Export] +public enum ErrorCodes +{ + /// + /// 成功 + /// + [ResourceDescription(nameof(Ln.成功))] + Succeed = 0 + + , + + /// + /// 意外错误 + /// + [ResourceDescription(nameof(Ln.意外错误))] + Unhandled = 9000 + + , + + /// + /// 结果非预期 + /// + [ResourceDescription(nameof(Ln.结果非预期))] + Unexpected = 9100 + + , + + /// + /// 无效输入 + /// + [ResourceDescription(nameof(Ln.无效输入))] + InvalidInput = 9200 + + , + + /// + /// 无效操作 + /// + [ResourceDescription(nameof(Ln.无效操作))] + InvalidOperation = 9300 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Enums/FreeSqlInitOptions.cs b/src/backend/NetAdmin.Infrastructure/Enums/FreeSqlInitOptions.cs new file mode 100644 index 00000000..3243ca6a --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Enums/FreeSqlInitOptions.cs @@ -0,0 +1,34 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 初始化选项 +/// +[Flags] +public enum FreeSqlInitOptions +{ + /// + /// 无 + /// + None = 0 + + , + + /// + /// 同步数据库结构 + /// + SyncStructure = 1 + + , + + /// + /// 插入种子数据 + /// + InsertSeedData = 1 << 1 + + , + + /// + /// 比较数据库结构 + /// + CompareStructure = 1 << 2 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Enums/LogLevels.cs b/src/backend/NetAdmin.Infrastructure/Enums/LogLevels.cs new file mode 100644 index 00000000..449053bb --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Enums/LogLevels.cs @@ -0,0 +1,53 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 日志等级 +/// +public enum LogLevels +{ + /// + /// Trace + /// + [Display(Name = "[gray]TCE[/]", ShortName = "TCE")] + Trace = 0 + + , + + /// + /// Debug + /// + [Display(Name = "[gray]DBG[/]", ShortName = "DBG")] + Debug = 1 + + , + + /// + /// Information + /// + [Display(Name = "[green]INF[/]", ShortName = "INF")] + Information = 2 + + , + + /// + /// Warning + /// + [Display(Name = "[yellow]WRN[/]", ShortName = "WRN")] + Warning = 3 + + , + + /// + /// Error + /// + [Display(Name = "[red]ERR[/]", ShortName = "ERR")] + Error = 4 + + , + + /// + /// Critical + /// + [Display(Name = "[red]CTL[/]", ShortName = "CTL")] + Critical = 5 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Enums/MarriageStatues.cs b/src/backend/NetAdmin.Infrastructure/Enums/MarriageStatues.cs new file mode 100644 index 00000000..0153174b --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Enums/MarriageStatues.cs @@ -0,0 +1,38 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 婚姻状况 +/// +[Export] +public enum MarriageStatues +{ + /// + /// 未婚 + /// + [ResourceDescription(nameof(Ln.未婚))] + Unmarried = 1 + + , + + /// + /// 已婚 + /// + [ResourceDescription(nameof(Ln.已婚))] + Married = 2 + + , + + /// + /// 离异 + /// + [ResourceDescription(nameof(Ln.离异))] + Divorced = 3 + + , + + /// + /// 丧偶 + /// + [ResourceDescription(nameof(Ln.丧偶))] + Bereft = 4 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Enums/ModuleTypes.cs b/src/backend/NetAdmin.Infrastructure/Enums/ModuleTypes.cs new file mode 100644 index 00000000..903b7b1b --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Enums/ModuleTypes.cs @@ -0,0 +1,22 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 模块类型 +/// +[Export] +public enum ModuleTypes +{ + /// + /// 系统模块 + /// + [ResourceDescription(nameof(Ln.系统模块))] + SysComponent = 1 + + , + + /// + /// 业务模块 + /// + [ResourceDescription(nameof(Ln.业务模块))] + BizServer = 2 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Enums/Nations.cs b/src/backend/NetAdmin.Infrastructure/Enums/Nations.cs new file mode 100644 index 00000000..d1e5feda --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Enums/Nations.cs @@ -0,0 +1,456 @@ +// ReSharper disable IdentifierTypo + +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 民族 +/// +[Export] +public enum Nations +{ + /// + /// 汉族 + /// + [ResourceDescription(nameof(Ln.汉族))] + Han = 1 + + , + + /// + /// 壮族 + /// + [ResourceDescription(nameof(Ln.壮族))] + Zhuang = 2 + + , + + /// + /// 满族 + /// + [ResourceDescription(nameof(Ln.满族))] + Manchu = 3 + + , + + /// + /// 回族 + /// + [ResourceDescription(nameof(Ln.回族))] + Hui = 4 + + , + + /// + /// 苗族 + /// + [ResourceDescription(nameof(Ln.苗族))] + Miao = 5 + + , + + /// + /// 维吾尔族 + /// + [ResourceDescription(nameof(Ln.维吾尔族))] + Uyghur = 6 + + , + + /// + /// 土家族 + /// + [ResourceDescription(nameof(Ln.土家族))] + Tujia = 7 + + , + + /// + /// 彝族 + /// + [ResourceDescription(nameof(Ln.彝族))] + Yi = 8 + + , + + /// + /// 蒙古族 + /// + [ResourceDescription(nameof(Ln.蒙古族))] + Mongolian = 9 + + , + + /// + /// 藏族 + /// + [ResourceDescription(nameof(Ln.藏族))] + Tibetan = 10 + + , + + /// + /// 布依族 + /// + [ResourceDescription(nameof(Ln.布依族))] + Buyei = 11 + + , + + /// + /// 侗族 + /// + [ResourceDescription(nameof(Ln.侗族))] + Dong = 12 + + , + + /// + /// 瑶族 + /// + [ResourceDescription(nameof(Ln.瑶族))] + Yao = 13 + + , + + /// + /// 朝鲜族 + /// + [ResourceDescription(nameof(Ln.朝鲜族))] + Korean = 14 + + , + + /// + /// 白族 + /// + [ResourceDescription(nameof(Ln.白族))] + Bai = 15 + + , + + /// + /// 哈尼族 + /// + [ResourceDescription(nameof(Ln.哈尼族))] + Hani = 16 + + , + + /// + /// 哈萨克族 + /// + [ResourceDescription(nameof(Ln.哈萨克族))] + Kazakh = 17 + + , + + /// + /// 黎族 + /// + [ResourceDescription(nameof(Ln.黎族))] + Li = 18 + + , + + /// + /// 傣族 + /// + [ResourceDescription(nameof(Ln.傣族))] + Dai = 19 + + , + + /// + /// 畲族 + /// + [ResourceDescription(nameof(Ln.畲族))] + She = 20 + + , + + /// + /// 傈僳族 + /// + [ResourceDescription(nameof(Ln.傈僳族))] + Lisu = 21 + + , + + /// + /// 仡佬族 + /// + [ResourceDescription(nameof(Ln.仡佬族))] + Gelao = 22 + + , + + /// + /// 东乡族 + /// + [ResourceDescription(nameof(Ln.东乡族))] + Dongxiang = 23 + + , + + /// + /// 高山族 + /// + [ResourceDescription(nameof(Ln.高山族))] + Gaoshan = 24 + + , + + /// + /// 拉祜族族 + /// + [ResourceDescription(nameof(Ln.拉祜族族))] + Lahu = 25 + + , + + /// + /// 水族 + /// + [ResourceDescription(nameof(Ln.水族))] + Shui = 26 + + , + + /// + /// 佤族 + /// + [ResourceDescription(nameof(Ln.佤族))] + Va = 27 + + , + + /// + /// 纳西族 + /// + [ResourceDescription(nameof(Ln.纳西族))] + Nakhi = 28 + + , + + /// + /// 羌族 + /// + [ResourceDescription(nameof(Ln.羌族))] + Qiang = 29 + + , + + /// + /// 土族 + /// + [ResourceDescription(nameof(Ln.土族))] + Monguor = 30 + + , + + /// + /// 仫佬族 + /// + [ResourceDescription(nameof(Ln.仫佬族))] + Mulao = 31 + + , + + /// + /// 锡伯族 + /// + [ResourceDescription(nameof(Ln.锡伯族))] + Xibe = 32 + + , + + /// + /// 柯尔克孜族 + /// + [ResourceDescription(nameof(Ln.柯尔克孜族))] + Kyrgyz = 33 + + , + + /// + /// 达斡尔族 + /// + [ResourceDescription(nameof(Ln.达斡尔族))] + Daur = 34 + + , + + /// + /// 景颇族 + /// + [ResourceDescription(nameof(Ln.景颇族))] + Jingpo = 35 + + , + + /// + /// 毛南族 + /// + [ResourceDescription(nameof(Ln.毛南族))] + Maonan = 36 + + , + + /// + /// 撒拉族 + /// + [ResourceDescription(nameof(Ln.撒拉族))] + Salar = 37 + + , + + /// + /// 布朗族 + /// + [ResourceDescription(nameof(Ln.布朗族))] + Blang = 38 + + , + + /// + /// 塔吉克族 + /// + [ResourceDescription(nameof(Ln.塔吉克族))] + Tajik = 39 + + , + + /// + /// 阿昌族 + /// + [ResourceDescription(nameof(Ln.阿昌族))] + Achang = 40 + + , + + /// + /// 普米族 + /// + [ResourceDescription(nameof(Ln.普米族))] + Pumi = 41 + + , + + /// + /// 鄂温克族 + /// + [ResourceDescription(nameof(Ln.鄂温克族))] + Evenk = 42 + + , + + /// + /// 怒族 + /// + [ResourceDescription(nameof(Ln.怒族))] + Nu = 43 + + , + + /// + /// 京族 + /// + [ResourceDescription(nameof(Ln.京族))] + Kinh = 44 + + , + + /// + /// 基诺族 + /// + [ResourceDescription(nameof(Ln.基诺族))] + Jino = 45 + + , + + /// + /// 德昂族 + /// + [ResourceDescription(nameof(Ln.德昂族))] + Deang = 46 + + , + + /// + /// 保安族 + /// + [ResourceDescription(nameof(Ln.保安族))] + Bonan = 47 + + , + + /// + /// 俄罗斯族 + /// + [ResourceDescription(nameof(Ln.俄罗斯族))] + Russian = 48 + + , + + /// + /// 裕固族 + /// + [ResourceDescription(nameof(Ln.裕固族))] + Yughur = 49 + + , + + /// + /// 乌孜别克族 + /// + [ResourceDescription(nameof(Ln.乌孜别克族))] + Uzbek = 50 + + , + + /// + /// 门巴族 + /// + [ResourceDescription(nameof(Ln.门巴族))] + Monpa = 51 + + , + + /// + /// 鄂伦春族 + /// + [ResourceDescription(nameof(Ln.鄂伦春族))] + Oroqen = 52 + + , + + /// + /// 独龙族 + /// + [ResourceDescription(nameof(Ln.独龙族))] + Derung = 53 + + , + + /// + /// 塔塔尔族 + /// + [ResourceDescription(nameof(Ln.塔塔尔族))] + Tatar = 54 + + , + + /// + /// 赫哲族 + /// + [ResourceDescription(nameof(Ln.赫哲族))] + Nanai = 55 + + , + + /// + /// 珞巴族 + /// + [ResourceDescription(nameof(Ln.珞巴族))] + Lhoba = 56 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Enums/Orders.cs b/src/backend/NetAdmin.Infrastructure/Enums/Orders.cs new file mode 100644 index 00000000..b14dee5f --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Enums/Orders.cs @@ -0,0 +1,22 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 排序方式 +/// +[Export] +public enum Orders +{ + /// + /// 顺序 + /// + [ResourceDescription(nameof(Ln.顺序排序))] + Ascending = 1 + + , + + /// + /// 倒序 + /// + [ResourceDescription(nameof(Ln.倒序排序))] + Descending = 2 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Enums/PoliticalStatues.cs b/src/backend/NetAdmin.Infrastructure/Enums/PoliticalStatues.cs new file mode 100644 index 00000000..62b1be2e --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Enums/PoliticalStatues.cs @@ -0,0 +1,30 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 政治面貌 +/// +[Export] +public enum PoliticalStatues +{ + /// + /// 中共党员 + /// + [ResourceDescription(nameof(Ln.中共党员))] + MemberOfCommunistParty = 1 + + , + + /// + /// 共青团员 + /// + [ResourceDescription(nameof(Ln.共青团员))] + MemberOfCommunistYouthLeague = 2 + + , + + /// + /// 群众 + /// + [ResourceDescription(nameof(Ln.群众))] + CommonPeople = 3 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Enums/Sexes.cs b/src/backend/NetAdmin.Infrastructure/Enums/Sexes.cs new file mode 100644 index 00000000..9abb48a6 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Enums/Sexes.cs @@ -0,0 +1,30 @@ +namespace NetAdmin.Infrastructure.Enums; + +/// +/// 性别 +/// +[Export] +public enum Sexes +{ + /// + /// 男 + /// + [ResourceDescription(nameof(Ln.男))] + Male = 1 + + , + + /// + /// 女 + /// + [ResourceDescription(nameof(Ln.女))] + Female = 2 + + , + + /// + /// 保密 + /// + [ResourceDescription(nameof(Ln.保密))] + Secrecy = 3 +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Exceptions/InvalidInput/NetAdminInvalidInputException.cs b/src/backend/NetAdmin.Infrastructure/Exceptions/InvalidInput/NetAdminInvalidInputException.cs new file mode 100644 index 00000000..c4e11bda --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Exceptions/InvalidInput/NetAdminInvalidInputException.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Infrastructure.Exceptions.InvalidInput; + +/// +/// 无效输入异常 +/// +/// +/// 参数格式错误、内容校验错误等 +/// +#pragma warning disable RCS1194 +public sealed class NetAdminInvalidInputException : NetAdminException + #pragma warning restore RCS1194 +{ + /// + /// Initializes a new instance of the class. + /// + public NetAdminInvalidInputException(string message = null, Exception innerException = null) // + : base(ErrorCodes.InvalidInput, message, innerException) { } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Exceptions/InvalidOperation/NetAdminInvalidOperationException.cs b/src/backend/NetAdmin.Infrastructure/Exceptions/InvalidOperation/NetAdminInvalidOperationException.cs new file mode 100644 index 00000000..fb8f47e8 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Exceptions/InvalidOperation/NetAdminInvalidOperationException.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Infrastructure.Exceptions.InvalidOperation; + +/// +/// 无效操作异常 +/// +/// +/// 非正常的业务流程或逻辑 +/// +#pragma warning disable RCS1194, DesignedForInheritance +public class NetAdminInvalidOperationException : NetAdminException + #pragma warning restore DesignedForInheritance, RCS1194 +{ + /// + /// Initializes a new instance of the class. + /// + public NetAdminInvalidOperationException(string message = null, Exception innerException = null) // + : base(ErrorCodes.InvalidOperation, message, innerException) { } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Exceptions/NetAdminException.cs b/src/backend/NetAdmin.Infrastructure/Exceptions/NetAdminException.cs new file mode 100644 index 00000000..6d436145 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Exceptions/NetAdminException.cs @@ -0,0 +1,23 @@ +namespace NetAdmin.Infrastructure.Exceptions; + +/// +/// Line异常基类 +/// +#pragma warning disable RCS1194 +public abstract class NetAdminException : Exception + #pragma warning restore RCS1194 +{ + /// + /// Initializes a new instance of the class. + /// + protected NetAdminException(ErrorCodes code, string message = null, Exception innerException = null) // + : base(message, innerException) + { + Code = code; + } + + /// + /// 错误码 + /// + public ErrorCodes Code { get; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Exceptions/Unexpected/NetAdminGetLockerException.cs b/src/backend/NetAdmin.Infrastructure/Exceptions/Unexpected/NetAdminGetLockerException.cs new file mode 100644 index 00000000..b391aa01 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Exceptions/Unexpected/NetAdminGetLockerException.cs @@ -0,0 +1,9 @@ +namespace NetAdmin.Infrastructure.Exceptions.Unexpected; + +/// +/// 加锁失败异常 +/// +#pragma warning disable RCS1194 +public sealed class NetAdminGetLockerException : NetAdminUnexpectedException + #pragma warning restore RCS1194 +{ } \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Exceptions/Unexpected/NetAdminUnexpectedException.cs b/src/backend/NetAdmin.Infrastructure/Exceptions/Unexpected/NetAdminUnexpectedException.cs new file mode 100644 index 00000000..f22f21d6 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Exceptions/Unexpected/NetAdminUnexpectedException.cs @@ -0,0 +1,18 @@ +namespace NetAdmin.Infrastructure.Exceptions.Unexpected; + +/// +/// 非预期结果异常 +/// +/// +/// 运行结果是非预期的,例如事务失败回滚 +/// +#pragma warning disable RCS1194, DesignedForInheritance +public class NetAdminUnexpectedException : NetAdminException + #pragma warning restore DesignedForInheritance, RCS1194 +{ + /// + /// Initializes a new instance of the class. + /// + public NetAdminUnexpectedException(string message = null, Exception innerException = null) // + : base(ErrorCodes.Unexpected, message, innerException) { } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Extensions/HttpRequestMessageExtensions.cs b/src/backend/NetAdmin.Infrastructure/Extensions/HttpRequestMessageExtensions.cs new file mode 100644 index 00000000..eec19fb7 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Extensions/HttpRequestMessageExtensions.cs @@ -0,0 +1,25 @@ +namespace NetAdmin.Infrastructure.Extensions; + +/// +/// HttpRequestMessage 扩展方法 +/// +public static class HttpRequestMessageExtensions +{ + /// + /// 将Http请求的Uri、Header、Body打包成Json字符串 + /// + public static async Task BuildJsonAsync(this HttpRequestMessage me) + { + var body = me?.Content == null ? null : await me.Content!.ReadAsStringAsync(); + return new { Uri = me?.RequestUri, Header = me?.ToString(), Body = body }.ToJson(); + } + + /// + /// 记录日志 + /// + public static async Task LogAsync(this HttpRequestMessage me, ILogger logger) + { + logger.Info($"{Ln.请求}: {await me.BuildJsonAsync()}"); + return me; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Extensions/HttpRequestPartExtensions.cs b/src/backend/NetAdmin.Infrastructure/Extensions/HttpRequestPartExtensions.cs new file mode 100644 index 00000000..1b577a1a --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Extensions/HttpRequestPartExtensions.cs @@ -0,0 +1,35 @@ +using Furion.RemoteRequest; + +namespace NetAdmin.Infrastructure.Extensions; + +/// +/// HttpRequestPart 扩展方法 +/// +public static class HttpRequestPartExtensions +{ + /// + /// 设置日志 + /// + public static HttpRequestPart SetLog(this HttpRequestPart me, ILogger logger + , Func bodyHandle = null) + { + async void RequestHandle(HttpClient _, HttpRequestMessage req) + { + #pragma warning disable IDE0058 + await req.LogAsync(logger); + #pragma warning restore IDE0058 + } + + async void ResponseHandle(HttpClient _, HttpResponseMessage rsp) + { + await rsp.LogAsync(logger, bodyHandle); + } + + async void ExceptionHandle(HttpClient _, HttpResponseMessage rsp, string errors) + { + await rsp.LogExceptionAsync(errors, logger, bodyHandle); + } + + return me.OnRequesting(RequestHandle).OnResponsing(ResponseHandle).OnException(ExceptionHandle); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Extensions/HttpResponseMessageExtensions.cs b/src/backend/NetAdmin.Infrastructure/Extensions/HttpResponseMessageExtensions.cs new file mode 100644 index 00000000..3297ce62 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Extensions/HttpResponseMessageExtensions.cs @@ -0,0 +1,35 @@ +namespace NetAdmin.Infrastructure.Extensions; + +/// +/// HttpResponseMessage 扩展方法 +/// +public static class HttpResponseMessageExtensions +{ + /// + /// 记录日志 + /// + public static async Task LogAsync(this HttpResponseMessage me, ILogger logger + , Func bodyPreHandle = null) + { + logger.Info(await me.BuildJsonAsync(bodyPreHandle)); + } + + /// + /// 记录异常日志 + /// + public static async Task LogExceptionAsync(this HttpResponseMessage me, string errors, ILogger logger + , Func bodyHandle = null) + { + logger.Warn($"{errors}: {await me.BuildJsonAsync(bodyHandle)}"); + } + + /// + /// 将Http请求的Uri、Header、Body打包成Json字符串 + /// + private static async Task BuildJsonAsync( // + this HttpResponseMessage me, Func bodyHandle = null) + { + var body = me?.Content is null ? null : await me.Content!.ReadAsStringAsync(); + return new { Header = me?.ToString(), Body = bodyHandle is null ? body : bodyHandle(body) }.ToJson(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Extensions/ObjectExtensions.cs b/src/backend/NetAdmin.Infrastructure/Extensions/ObjectExtensions.cs new file mode 100644 index 00000000..b7545d96 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Extensions/ObjectExtensions.cs @@ -0,0 +1,15 @@ +namespace NetAdmin.Infrastructure.Extensions; + +/// +/// Object 扩展类 +/// +public static class ObjectExtensions +{ + /// + /// object -> json + /// + public static string ToJson(this object me) + { + return me.Json(Global.JsonSerializerOptions); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Extensions/StringExtensions.cs b/src/backend/NetAdmin.Infrastructure/Extensions/StringExtensions.cs new file mode 100644 index 00000000..033a7a0a --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Extensions/StringExtensions.cs @@ -0,0 +1,31 @@ +namespace NetAdmin.Infrastructure.Extensions; + +/// +/// String 扩展类 +/// +public static class StringExtensions +{ + /// + /// object -> json + /// + public static T ToObject(this string me) + { + return me.Object(Global.JsonSerializerOptions); + } + + /// + /// object -> json + /// + public static object ToObject(this string me, Type toType) + { + return me.Object(toType, Global.JsonSerializerOptions); + } + + /// + /// 去掉尾部字符串“Options” + /// + public static string TrimEndOptions(this string me) + { + return Regex.Replace(me, "Options$", string.Empty); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Global.cs b/src/backend/NetAdmin.Infrastructure/Global.cs new file mode 100644 index 00000000..5492a96f --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Global.cs @@ -0,0 +1,23 @@ +namespace NetAdmin.Infrastructure; + +/// +/// 全局静态类 +/// +public static class Global +{ + /// + /// 产品版本 + /// + public static readonly string ProductVersion + = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly()!.Location).ProductVersion; + + /// + /// 系统内部密钥 + /// + public static string SecretKey => "{6C4922D3-499A-46db-BFC4-0B51A9C4395F}"; + + /// + /// Json序列化选项 + /// + public static JsonSerializerOptions JsonSerializerOptions { get; set; } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj b/src/backend/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj new file mode 100644 index 00000000..d39dcd14 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Utils/ApplicationHelper.cs b/src/backend/NetAdmin.Infrastructure/Utils/ApplicationHelper.cs new file mode 100644 index 00000000..b30f415a --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Utils/ApplicationHelper.cs @@ -0,0 +1,20 @@ +namespace NetAdmin.Infrastructure.Utils; + +/// +/// 应用程序帮助类 +/// +public static class ApplicationHelper +{ + /// + /// 获取系统环境 + /// + public static Dictionary GetEnvironmentInfo() + { + var ret = typeof(Environment).GetProperties(BindingFlags.Public | BindingFlags.Static) + .Where(x => x.Name != nameof(Environment.StackTrace)) + .ToDictionary(x => x.Name, x => x.GetValue(null)); + _ = ret.TryAdd( // + "Environment", Environment.GetEnvironmentVariables().ToJson()); + return ret; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Utils/CaptchaImageHelper.cs b/src/backend/NetAdmin.Infrastructure/Utils/CaptchaImageHelper.cs new file mode 100644 index 00000000..637d3437 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Utils/CaptchaImageHelper.cs @@ -0,0 +1,176 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; + +namespace NetAdmin.Infrastructure.Utils; + +/// +/// 验证码图片工具类 +/// +public static class CaptchaImageHelper +{ + /// + /// 创建一个缺口滑块验证码图片 + /// + /// 包含资源的程序集 + /// 背景图路径 + /// 滑块模板小图路径 + /// 背景图随机序号范围(1-x) + /// 模板图随机序号范围(1-x) + /// 滑块尺寸 + /// 背景图(base64),滑块图(base64),缺口坐标 + #pragma warning disable SA1414 + public static async Task<(string BackgroundImage, string SliderImage, Point OffsetSaw)> CreateSawSliderImageAsync( + Assembly resAsm, string bgPath, string tempPath, (int, int) bgIndexScope, (int, int) tempIndexScope + , Size sliderSize) + #pragma warning restore SA1414 + { + // 深色模板图 + var templateIndex = new[] { tempIndexScope.Item1, tempIndexScope.Item2 }.Rand(); + + await using var bgStream = resAsm.GetManifestResourceStream( + $"{bgPath}.{new[] { bgIndexScope.Item1, bgIndexScope.Item2 }.Rand()}.jpg"); + await using var darkStream = resAsm.GetManifestResourceStream($"{tempPath}._{templateIndex}.dark.png"); + await using var tranStream = resAsm.GetManifestResourceStream($"{tempPath}._{templateIndex}.transparent.png"); + + // 底图 + using var backgroundImage = await Image.LoadAsync(bgStream); + + using var darkTemplateImage = await Image.LoadAsync(darkStream); + + // 透明模板图 + using var transparentTemplateImage = await Image.LoadAsync(tranStream); + + // 调整模板图大小 + darkTemplateImage.Mutate(x => x.Resize(sliderSize)); + transparentTemplateImage.Mutate(x => x.Resize(sliderSize)); + + // 新建拼图 + using var blockImage = new Image(sliderSize.Width, sliderSize.Height); + + // 新建滑块拼图 + using var sliderBlockImage = new Image(sliderSize.Width, backgroundImage.Height); + + // 随机生成拼图坐标 + var offsetRand = GeneratePoint(backgroundImage.Width, backgroundImage.Height, sliderSize.Width + , sliderSize.Height); + + // 根据深色模板图计算轮廓形状 + var blockShape = CalcBlockShape(darkTemplateImage); + + // 生成拼图 + blockImage.Mutate(x => { + // ReSharper disable once AccessToDisposedClosure + _ = x.Clip(blockShape, p => p.DrawImage(backgroundImage, new Point(-offsetRand.X, -offsetRand.Y), 1)); + }); + + // 拼图叠加透明模板图层 + // ReSharper disable once AccessToDisposedClosure + blockImage.Mutate(x => x.DrawImage(transparentTemplateImage, new Point(0, 0), 1)); + + // 生成滑块拼图 + // ReSharper disable once AccessToDisposedClosure + sliderBlockImage.Mutate(x => x.DrawImage(blockImage, new Point(0, offsetRand.Y), 1)); + + var opacity = (float)(new[] { 70, 100 }.Rand() * 0.01); + + // 底图叠加深色模板图 + // ReSharper disable once AccessToDisposedClosure + backgroundImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(offsetRand.X, offsetRand.Y), opacity)); + + // 生成干扰图坐标 + var interferencePoint = GenerateInterferencePoint(backgroundImage.Width, backgroundImage.Height + , sliderSize.Width, sliderSize.Height, offsetRand.X + , offsetRand.Y); + + // 底图叠加深色干扰模板图 + // ReSharper disable once AccessToDisposedClosure + backgroundImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(interferencePoint.X, interferencePoint.Y) + , opacity)); + return (backgroundImage.ToBase64String(PngFormat.Instance), sliderBlockImage.ToBase64String(PngFormat.Instance) + , offsetRand); + } + + private static ComplexPolygon CalcBlockShape(Image templateDarkImage) + { + var temp = 0; + var pathList = new List(); + templateDarkImage.ProcessPixelRows(accessor => { + for (var y = 0; y < templateDarkImage.Height; y++) { + var rowSpan = accessor.GetRowSpan(y); + for (var x = 0; x < rowSpan.Length; x++) { + ref var pixel = ref rowSpan[x]; + if (pixel.A != 0) { + temp = temp switch { 0 => x, _ => temp }; + } + else { + if (temp == 0) { + continue; + } + + pathList.Add(new RectangularPolygon(temp, y, x - temp, 1)); + temp = 0; + } + } + } + }); + + return new ComplexPolygon(new PathCollection(pathList)); + } + + /// + /// 随机生成干扰图坐标 + /// + private static Point GenerateInterferencePoint(int originalWidth, int originalHeight, int templateWidth + , int templateHeight, int blockX, int blockY) + { + var x = + + // 在原扣图右边插入干扰图 + originalWidth - blockX - 5 > templateWidth * 2 + ? GetRandomInt(blockX + templateWidth + 5, originalWidth - templateWidth) + : + + // 在原扣图左边插入干扰图 + GetRandomInt(100, blockX - templateWidth - 5); + + var y = + + // 在原扣图下边插入干扰图 + originalHeight - blockY - 5 > templateHeight * 2 + ? GetRandomInt(blockY + templateHeight + 5, originalHeight - templateHeight) + : + + // 在原扣图上边插入干扰图 + GetRandomInt(5, blockY - templateHeight - 5); + + return new Point(x, y); + } + + /// + /// 随机生成拼图坐标 + /// + private static Point GeneratePoint(int originalWidth, int originalHeight, int templateWidth, int templateHeight) + { + var widthDifference = originalWidth - templateWidth; + var heightDifference = originalHeight - templateHeight; + var x = widthDifference switch { + <= 0 => 5, _ => new[] { 0, originalWidth - templateWidth - 100 }.Rand() + 100 + }; + + var y = heightDifference switch { <= 0 => 5, _ => new[] { 0, originalHeight - templateHeight - 5 }.Rand() + 5 }; + + return new Point(x, y); + } + + /// + /// 随机范围内数字 + /// + private static int GetRandomInt(int startNum, int endNum) + { + return (endNum > startNum ? new[] { 0, endNum - startNum }.Rand() : 0) + startNum; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Utils/FreeSqlBuilder.cs b/src/backend/NetAdmin.Infrastructure/Utils/FreeSqlBuilder.cs new file mode 100644 index 00000000..3d7c6e40 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Utils/FreeSqlBuilder.cs @@ -0,0 +1,145 @@ +using Newtonsoft.Json; +using DataType = FreeSql.DataType; + +namespace NetAdmin.Infrastructure.Utils; + +/// +/// FreeSqlBuilder +/// +public sealed class FreeSqlBuilder +{ + private readonly DatabaseOptions _databaseOptions; + + /// + /// Initializes a new instance of the class. + /// + public FreeSqlBuilder(DatabaseOptions databaseOptions) + { + _databaseOptions = databaseOptions; + } + + /// + /// 构建freeSql对象 + /// + public IFreeSql Build(FreeSqlInitOptions initOptions) + { + var freeSql = new FreeSql.FreeSqlBuilder() + .UseConnectionString(_databaseOptions.DbType, _databaseOptions.ConnStr) + .UseAutoSyncStructure(false) + .Build(); + + _ = InitDbAsync(freeSql, initOptions); // 初始化数据库 ,异步 + return freeSql; + } + + private static void CompareStructure(IFreeSql freeSql, Type[] entityTypes) + { + File.WriteAllText( // + $"{nameof(CompareStructure)}.sql", freeSql.CodeFirst.GetComparisonDDLStatements(entityTypes)); + } + + /// + /// 获取所有实体类型定义 + /// + private static Type[] GetEntityTypes() + { + return (from type in App.EffectiveTypes + from attr in type.GetCustomAttributes() + where attr is TableAttribute { DisableSyncStructure: false } + select type).ToArray(); + } + + private static MethodInfo MakeGetRepositoryMethod(Type entityType) + { + return typeof(FreeSqlDbContextExtensions).GetMethods() + .Where(x => x.Name == nameof(FreeSqlDbContextExtensions.GetRepository)) + .FirstOrDefault(x => x.GetGenericArguments().Length == 1) + ?.MakeGenericMethod(entityType); + } + + private static MethodInfo MakeInsertMethod(Type entityType) + { + return typeof(IBaseRepository<>).MakeGenericType(entityType) + .GetMethod( // + nameof(IBaseRepository.Insert) + , BindingFlags.Public | BindingFlags.Instance, null + , CallingConventions.Any + , new[] { typeof(IEnumerable<>).MakeGenericType(entityType) }, null); + } + + /// + /// 初始化数据库 + /// + private Task InitDbAsync(IFreeSql freeSql, FreeSqlInitOptions initOptions) + { + return Task.Run(() => { + if (initOptions == FreeSqlInitOptions.None) { + return; + } + + var entityTypes = GetEntityTypes(); + if (initOptions.HasFlag(FreeSqlInitOptions.SyncStructure)) { + SyncStructure(freeSql, entityTypes); + } + + if (initOptions.HasFlag(FreeSqlInitOptions.InsertSeedData)) { + InsertSeedData(freeSql, entityTypes); + } + + if (initOptions.HasFlag(FreeSqlInitOptions.CompareStructure)) { + CompareStructure(freeSql, entityTypes); + } + }); + } + + /// + /// 插入种子数据 + /// + private void InsertSeedData(IFreeSql freeSql, IEnumerable entityTypes) + { + foreach (var entityType in entityTypes) { + var file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _databaseOptions.SeedDataRelativePath + , $"{entityType.Name}.json"); + if (!File.Exists(file)) { + continue; + } + + var fileContent = File.ReadAllText(file); + + dynamic entities = JsonConvert.DeserializeObject( // + fileContent, typeof(IEnumerable<>).MakeGenericType(entityType)); + + // 如果表存在数据,跳过 + var select = typeof(IFreeSql).GetMethod(nameof(freeSql.Select), 1, Type.EmptyTypes) + ?.MakeGenericMethod(entityType) + .Invoke(freeSql, null); + if (select?.GetType() + .GetMethod(nameof(ISelect.Any), 0, Type.EmptyTypes) + ?.Invoke(select, null) as bool? ?? true) { + continue; + } + + var rep = MakeGetRepositoryMethod(entityType)?.Invoke(null, new object[] { freeSql, null }); + if (rep?.GetType().GetProperty(nameof(DbContextOptions))?.GetValue(rep) is DbContextOptions options) { + options.EnableCascadeSave = true; + options.NoneParameter = true; + } + + var insert = MakeInsertMethod(entityType); + + _ = insert?.Invoke(rep, new[] { entities }); + } + } + + /// + /// 同步数据库结构 + /// + private void SyncStructure(IFreeSql freeSql, Type[] entityTypes) + { + if (_databaseOptions.DbType == DataType.Oracle) { + freeSql.CodeFirst.IsSyncStructureToUpper = true; + } + + freeSql.CodeFirst.SyncStructure(entityTypes); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Utils/LogHelper.cs b/src/backend/NetAdmin.Infrastructure/Utils/LogHelper.cs new file mode 100644 index 00000000..5ac74075 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Utils/LogHelper.cs @@ -0,0 +1,15 @@ +namespace NetAdmin.Infrastructure.Utils; + +/// +/// 日志帮助类 +/// +public static class LogHelper +{ + /// + /// 获取ILogger + /// + public static ILogger Get() + { + return App.GetService>(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Utils/MinioHelper.cs b/src/backend/NetAdmin.Infrastructure/Utils/MinioHelper.cs new file mode 100644 index 00000000..f90fd219 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Utils/MinioHelper.cs @@ -0,0 +1,52 @@ +using Minio; + +namespace NetAdmin.Infrastructure.Utils; + +/// +/// MinioHelper +/// +public sealed class MinioHelper : IScoped +{ + private readonly UploadOptions _uploadOptions; + + /// + /// Initializes a new instance of the class. + /// + public MinioHelper(IOptions uploadOptions) + { + _uploadOptions = uploadOptions.Value; + } + + /// + /// 上传文件 + /// + /// 对象名称 + /// 文件流 + /// 文件类型 + /// 文件大小 + /// 可访问的url地址 + public async Task UploadAsync(string objectName, Stream fileStream, string contentType, long fileSize) + { + using var minio = new MinioClient().WithEndpoint(_uploadOptions.Minio.ServerAddress) + .WithCredentials( // + _uploadOptions.Minio.AccessKey, _uploadOptions.Minio.SecretKey) + .WithSSL(_uploadOptions.Minio.Secure) + .Build(); + + var beArgs = new BucketExistsArgs().WithBucket(_uploadOptions.Minio.BucketName); + + if (!await minio.BucketExistsAsync(beArgs)) { + var mbArgs = new MakeBucketArgs().WithBucket(_uploadOptions.Minio.BucketName); + await minio.MakeBucketAsync(mbArgs); + } + + var putArgs = new PutObjectArgs().WithBucket(_uploadOptions.Minio.BucketName) + .WithObject(objectName) + .WithStreamData(fileStream) + .WithObjectSize(fileSize) + .WithContentType(contentType); + _ = await minio.PutObjectAsync(putArgs); + + return $"{_uploadOptions.Minio.AccessUrl}/{_uploadOptions.Minio.BucketName}/{objectName}"; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Utils/RedLocker.cs b/src/backend/NetAdmin.Infrastructure/Utils/RedLocker.cs new file mode 100644 index 00000000..26dbbb64 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Utils/RedLocker.cs @@ -0,0 +1,98 @@ +using RedLockNet.SERedis; +using RedLockNet.SERedis.Configuration; +using StackExchange.Redis; + +namespace NetAdmin.Infrastructure.Utils; + +/// +/// Redis锁 +/// +#pragma warning disable DesignedForInheritance +public class RedLocker : IDisposable, ISingleton + #pragma warning restore DesignedForInheritance +{ + // Track whether Dispose has been called. + private bool _disposed; + + /// + /// Initializes a new instance of the class. + /// + public RedLocker(IOptions redisOptions) + { + RedlockFactory = RedLockFactory.Create( // + new List // + { + ConnectionMultiplexer.Connect( // + redisOptions.Value.Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE).ConnStr) + }); + } + + /// + /// Finalizes an instance of the class. + /// Use C# finalizer syntax for finalization code. + /// This finalizer will run only if the Dispose method + /// does not get called. + /// It gives your base class the opportunity to finalize. + /// Do not provide finalizer in types derived from this class. + /// + ~RedLocker() + { + // Do not re-create Dispose clean-up code here. + // Calling Dispose(disposing: false) is optimal in terms of + // readability and maintainability. + Dispose(false); + } + + /// + /// RedlockFactory + /// + public RedLockFactory RedlockFactory { get; } + + /// + /// Implement IDisposable. + /// Do not make this method virtual. + /// A derived class should not be able to override this method. + /// + public void Dispose() + { + Dispose(true); + + // This object will be cleaned up by the Dispose method. + // Therefore, you should call GC.SuppressFinalize to + // take this object off the finalization queue + // and prevent finalization code for this object + // from executing a second time. + GC.SuppressFinalize(this); + } + + /// + /// Dispose(bool disposing) executes in two distinct scenarios. + /// If disposing equals true, the method has been called directly + /// or indirectly by a user's code. Managed and unmanaged resources + /// can be disposed. + /// If disposing equals false, the method has been called by the + /// runtime from inside the finalizer and you should not reference + /// other objects. Only unmanaged resources can be disposed. + /// + protected virtual void Dispose(bool disposing) + { + // Check to see if Dispose has already been called. + if (_disposed) { + return; + } + + // If disposing equals true, dispose all managed + // and unmanaged resources. + if (disposing) { + RedlockFactory.Dispose(); + } + + // Call the appropriate methods to clean up + // unmanaged resources here. + // If disposing is false, + // only the following code is executed. + + // Note disposing has been done. + _disposed = true; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Utils/UserAgentParser.cs b/src/backend/NetAdmin.Infrastructure/Utils/UserAgentParser.cs new file mode 100644 index 00000000..52d9695e --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Utils/UserAgentParser.cs @@ -0,0 +1,347 @@ +// ReSharper disable StringLiteralTypo + +namespace NetAdmin.Infrastructure.Utils; + +/// +/// 解析用户代理字符串 +/// +public sealed class UserAgentParser +{ + private static readonly Dictionary _browsers = new() { + { "OPR", "Opera" } + , { "Flock", "Flock" } + , { "Edge", "Spartan" } + , { "Chrome", "Chrome" } + , { "Opera.*?Version", "Opera" } + , { "Opera", "Opera" } + , { "MSIE", "Internet Explorer" } + , { + "Internet Explorer" + , "Internet Explorer" + } + , { "Trident.* rv", "Internet Explorer" } + , { "Shiira", "Shiira" } + , { "Firefox", "Firefox" } + , { "Chimera", "Chimera" } + , { "Phoenix", "Phoenix" } + , { "Firebird", "Firebird" } + , { "Camino", "Camino" } + , { "Netscape", "Netscape" } + , { "OmniWeb", "OmniWeb" } + , { "Safari", "Safari" } + , { "Mozilla", "Mozilla" } + , { "Konqueror", "Konqueror" } + , { "icab", "iCab" } + , { "Lynx", "Lynx" } + , { "Links", "Links" } + , { "hotjava", "HotJava" } + , { "amaya", "Amaya" } + , { "IBrowse", "IBrowse" } + , { "Maxthon", "Maxthon" } + , { "Ubuntu", "Ubuntu Web Browser" } + }; + + private static readonly Dictionary _mobiles = new() { + // Legacy + { "mobileexplorer", "Mobile Explorer" } + , { "palmsource", "Palm" } + , { "palmscape", "Palmscape" } + , + + // Phones and Manufacturers + { "motorola", "Motorola" } + , { "nokia", "Nokia" } + , { "palm", "Palm" } + , { "iphone", "Apple iPhone" } + , { "ipad", "iPad" } + , { "ipod", "Apple iPod Touch" } + , { "sony", "Sony Ericsson" } + , { "ericsson", "Sony Ericsson" } + , { "blackberry", "BlackBerry" } + , { "cocoon", "O2 Cocoon" } + , { "blazer", "Treo" } + , { "lg", "LG" } + , { "amoi", "Amoi" } + , { "xda", "XDA" } + , { "mda", "MDA" } + , { "vario", "Vario" } + , { "htc", "HTC" } + , { "samsung", "Samsung" } + , { "sharp", "Sharp" } + , { "sie-", "Siemens" } + , { "alcatel", "Alcatel" } + , { "benq", "BenQ" } + , { "ipaq", "HP iPaq" } + , { "mot-", "Motorola" } + , { + "playstation portable" + , "PlayStation Portable" + } + , { "playstation 3", "PlayStation 3" } + , { "playstation vita", "PlayStation Vita" } + , { "hiptop", "Danger Hiptop" } + , { "nec-", "NEC" } + , { "panasonic", "Panasonic" } + , { "philips", "Philips" } + , { "sagem", "Sagem" } + , { "sanyo", "Sanyo" } + , { "spv", "SPV" } + , { "zte", "ZTE" } + , { "sendo", "Sendo" } + , { "nintendo dsi", "Nintendo DSi" } + , { "nintendo ds", "Nintendo DS" } + , { "nintendo 3ds", "Nintendo 3DS" } + , { "wii", "Nintendo Wii" } + , { "open web", "Open Web" } + , { "openweb", "OpenWeb" } + , + + // Operating Systems + { "android", "Android" } + , { "symbian", "Symbian" } + , { "SymbianOS", "SymbianOS" } + , { "elaine", "Palm" } + , { "series60", "Symbian S60" } + , { "windows ce", "Windows CE" } + , + + // Browsers + { "obigo", "Obigo" } + , { "netfront", "Netfront Browser" } + , { "openwave", "Openwave Browser" } + , { "mobilexplorer", "Mobile Explorer" } + , { "operamini", "Opera Mini" } + , { "opera mini", "Opera Mini" } + , { "opera mobi", "Opera Mobile" } + , { "fennec", "Firefox Mobile" } + , + + // Other + { "digital paths", "Digital Paths" } + , { "avantgo", "AvantGo" } + , { "xiino", "Xiino" } + , { "novarra", "Novarra Transcoder" } + , { "vodafone", "Vodafone" } + , { "docomo", "NTT DoCoMo" } + , { "o2", "O2" } + , + + // Fallback + { "mobile", "Generic Mobile" } + , { "wireless", "Generic Mobile" } + , { "j2me", "Generic Mobile" } + , { "midp", "Generic Mobile" } + , { "cldc", "Generic Mobile" } + , { "up.link", "Generic Mobile" } + , { "up.browser", "Generic Mobile" } + , { "smartphone", "Generic Mobile" } + , { "cellphone", "Generic Mobile" } + }; + + private static readonly Dictionary _platforms = new() { + { "windows nt 10.0", "Windows 10" } + , { "windows nt 6.3", "Windows 8.1" } + , { "windows nt 6.2", "Windows 8" } + , { "windows nt 6.1", "Windows 7" } + , { "windows nt 6.0", "Windows Vista" } + , { "windows nt 5.2", "Windows 2003" } + , { "windows nt 5.1", "Windows XP" } + , { "windows nt 5.0", "Windows 2000" } + , { "windows nt 4.0", "Windows NT 4.0" } + , { "winnt4.0", "Windows NT 4.0" } + , { "winnt 4.0", "Windows NT" } + , { "winnt", "Windows NT" } + , { "windows 98", "Windows 98" } + , { "win98", "Windows 98" } + , { "windows 95", "Windows 95" } + , { "win95", "Windows 95" } + , { "windows phone", "Windows Phone" } + , { "windows", "Unknown Windows OS" } + , { "android", "Android" } + , { "blackberry", "BlackBerry" } + , { "iphone", "iOS" } + , { "ipad", "iOS" } + , { "ipod", "iOS" } + , { "os x", "Mac OS X" } + , { "ppc mac", "Power PC Mac" } + , { "freebsd", "FreeBSD" } + , { "ppc", "Macintosh" } + , { "linux", "Linux" } + , { "debian", "Debian" } + , { "sunos", "Sun Solaris" } + , { "beos", "BeOS" } + , { "apachebench", "ApacheBench" } + , { "aix", "AIX" } + , { "irix", "Irix" } + , { "osf", "DEC OSF" } + , { "hp-ux", "HP-UX" } + , { "netbsd", "NetBSD" } + , { "bsdi", "BSDi" } + , { "openbsd", "OpenBSD" } + , { "gnu", "GNU/Linux" } + , { "unix", "Unknown Unix OS" } + , { "symbian", "Symbian OS" } + }; + + private static readonly Dictionary _robots = new() { + { "googlebot", "Googlebot" } + , { "msnbot", "MSNBot" } + , { "baiduspider", "Baiduspider" } + , { "bingbot", "Bing" } + , { "slurp", "Inktomi Slurp" } + , { "yahoo", "Yahoo" } + , { "ask jeeves", "Ask Jeeves" } + , { "fastcrawler", "FastCrawler" } + , { "infoseek", "InfoSeek Robot 1.0" } + , { "lycos", "Lycos" } + , { "yandex", "YandexBot" } + , { + "mediapartners-google" + , "MediaPartners Google" + } + , { "CRAZYWEBCRAWLER", "Crazy Webcrawler" } + , { "adsbot-google", "AdsBot Google" } + , { + "feedfetcher-google" + , "Feedfetcher Google" + } + , { "curious george", "Curious George" } + , { "ia_archiver", "Alexa Crawler" } + , { "MJ12bot", "Majestic-12" } + , { "Uptimebot", "Uptimebot" } + }; + + private readonly string _agent; + + /// + /// Initializes a new instance of the class. + /// + private UserAgentParser(string userAgentString) + { + _agent = userAgentString.Trim(); + _ = SetPlatform(); + if (SetRobot()) { + return; + } + + if (SetBrowser()) { + return; + } + + if (SetMobile()) { + // + } + } + + /// + /// 浏览器 + /// + public string Browser { get; set; } = string.Empty; + + /// + /// 浏览器版本 + /// + public string BrowserVersion { get; set; } = string.Empty; + + /// + /// 是浏览器 + /// + public bool IsBrowser { get; set; } + + /// + /// 是手机 + /// + public bool IsMobile { get; set; } + + /// + /// 是机器人 + /// + public bool IsRobot { get; set; } + + /// + /// 手机 + /// + public string Mobile { get; set; } = string.Empty; + + /// + /// 平台 + /// + public string Platform { get; set; } = string.Empty; + + /// + /// 机器人 + /// + public string Robot { get; set; } = string.Empty; + + /// + /// 创建 UserAgentParser + /// + public static UserAgentParser Create(string userAgentString) + { + return new UserAgentParser(userAgentString); + } + + private bool SetBrowser() + { + foreach (var item in _browsers) { + var match = Regex.Match(_agent, $@"{item.Key}.*?([0-9\.]+)", RegexOptions.IgnoreCase); + if (!match.Success) { + continue; + } + + IsBrowser = true; + BrowserVersion = match.Groups[1].Value; + Browser = item.Value; + _ = SetMobile(); + return true; + } + + return false; + } + + private bool SetMobile() + { + foreach (var item in _mobiles) { + if (_agent.IndexOf(item.Key, StringComparison.OrdinalIgnoreCase) != -1) { + IsMobile = true; + Mobile = item.Value; + return true; + } + } + + return false; + } + + private bool SetPlatform() + { + #pragma warning disable S3267 + foreach (var item in _platforms) { + #pragma warning restore S3267 + if (!Regex.IsMatch(_agent, $"{Regex.Escape(item.Key)}", RegexOptions.IgnoreCase)) { + continue; + } + + Platform = item.Value; + return true; + } + + Platform = "Unknown Platform"; + return false; + } + + private bool SetRobot() + { + #pragma warning disable S3267 + foreach (var item in _robots) { + #pragma warning restore S3267 + if (Regex.IsMatch(_agent, $"{Regex.Escape(item.Key)}", RegexOptions.IgnoreCase)) { + IsRobot = true; + Robot = item.Value; + _ = SetMobile(); + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/Utils/XmlCommentReader.cs b/src/backend/NetAdmin.Infrastructure/Utils/XmlCommentReader.cs new file mode 100644 index 00000000..42873e02 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/Utils/XmlCommentReader.cs @@ -0,0 +1,95 @@ +using System.Xml; + +namespace NetAdmin.Infrastructure.Utils; + +/// +/// 程序集注释文档读取工具 +/// +public sealed class XmlCommentReader : ISingleton +{ + private const string _XPATH = "//doc/members/member[@name=\"{0}\"]"; + private readonly List _xmlDocuments = new(); + + /// + /// Initializes a new instance of the class. + /// + public XmlCommentReader(IOptions specificationDocumentSettings) + { + var xmlComments = specificationDocumentSettings.Value.XmlComments // + ?? App.GetConfig( + nameof(SpecificationDocumentSettingsOptions).TrimEndOptions()) + .XmlComments; + foreach (var commentFile in xmlComments.Where(x => x.Contains(nameof(NetAdmin)))) { + var xmlDoc = new XmlDocument(); + try { + xmlDoc.Load(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, commentFile)); + _xmlDocuments.Add(xmlDoc); + } + catch (FileNotFoundException) { + LogHelper.Get().Warn(Ln.Xml注释文件不存在); + } + } + } + + /// + /// 获取指定类型的注释 + /// + /// InvalidCastException + public string GetComments(MemberInfo memberInfo) + { + var node = memberInfo switch { + MethodInfo method => GetNodeByMethod(method) + , Type type => GetNodeByType(type) + , _ => throw new InvalidCastException() + }; + + if (node?.FirstChild?.Name != "inheritdoc") { + return node?.FirstChild?.InnerText.Trim(); + } + + var cref = node.FirstChild.Attributes?["cref"]?.Value; + if (cref != null) { + return GetComments(App.EffectiveTypes.Single(x => x.FullName == cref[2..])); + } + + var methodFromBaseType = memberInfo.DeclaringType?.BaseType?.GetMethod(memberInfo.Name); + + if (methodFromBaseType != null) { + return GetComments(methodFromBaseType); + } + + var methodFromInterface = memberInfo.DeclaringType?.GetInterfaces() + .Select(x => x.GetMethod(memberInfo.Name)) + .FirstOrDefault(x => x != null); + return methodFromInterface == null ? null : GetComments(methodFromInterface); + } + + private XmlNode GetNodeByMethod(MethodInfo method) + { + static string Replace(ParameterInfo parameterInfo) + { + return Regex.Replace(parameterInfo.ParameterType.ToString(), @"`\d+", string.Empty) + .Replace("[", "{") + .Replace("]", "}"); + } + + var nodeName = $"M:{method.DeclaringType}.{method.Name}"; + var parameters = method.GetParameters(); + if (parameters.Length != 0) { + nodeName += $"({string.Join(',', parameters.Select(Replace))})"; + } + + return _xmlDocuments + .Select(xmlDoc => xmlDoc.SelectSingleNode( + string.Format(NumberFormatInfo.InvariantInfo, _XPATH, nodeName))) + .FirstOrDefault(ret => ret != null); + } + + private XmlNode GetNodeByType(Type type) + { + return _xmlDocuments + .Select(xmlDoc => xmlDoc.SelectSingleNode( + string.Format(NumberFormatInfo.InvariantInfo, _XPATH, $"T:{type.FullName}"))) + .FirstOrDefault(ret => ret != null); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/commonSettings.Development.json b/src/backend/NetAdmin.Infrastructure/commonSettings.Development.json new file mode 100644 index 00000000..4874d4e4 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/commonSettings.Development.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", + "AppSettings": { + "InjectSpecificationDocument": true, + "InjectMiniProfiler": true + }, + "Redis": { + "Instances": [ + // 数据缓存 + { + "Name": "DataCache", + "ConnStr": "localhost:6379", + "Database": 0 + } + ] + }, + "JWTSettings": { + "ExpiredTime": 20000 + }, + "Logging": { + "LogLevel": { + "Default": "Debug", + }, + }, +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/commonSettings.Test.json b/src/backend/NetAdmin.Infrastructure/commonSettings.Test.json new file mode 100644 index 00000000..cbd707f3 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/commonSettings.Test.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", + "AppSettings": { + "InjectSpecificationDocument": true, + "InjectMiniProfiler": true + }, + "Redis": { + "Instances": [ + // 数据缓存 + { + "Name": "DataCache", + "ConnStr": "localhost:6379", + "Database": 0 + } + ] + }, + "JWTSettings": { + "ExpiredTime": 20000 + }, + "Logging": { + "LogLevel": { + "Default": "Debug", + }, + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.Infrastructure/commonSettings.json b/src/backend/NetAdmin.Infrastructure/commonSettings.json new file mode 100644 index 00000000..bc205704 --- /dev/null +++ b/src/backend/NetAdmin.Infrastructure/commonSettings.json @@ -0,0 +1,332 @@ +{ + "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", + // App基本配置 + "AppSettings": { + // AppSettings:配置根节点 + // InjectMiniProfiler:是否注入 MiniProfiler,bool 类型,默认 true,关闭 Swagger 左上角监听 + // InjectSpecificationDocument:是否启用 Swagger 文档,bool 类型,默认 true,生产环境可关闭 + // EnabledReferenceAssemblyScan:是否启用通过 dll 方式添加的引用程序集扫描,bool 类型,默认 false + // ExternalAssemblies:配置外部程序集完整路径,支持动态加载,string[] 类型,默认 [] + // PrintDbConnectionInfo:是否打印数据库连接信息到 MiniProfiler 中,bool 类型,默认 true + // SupportPackageNamePrefixs:配置支持的包前缀名,string[] 类型,默认 [] + // OutputOriginalSqlExecuteLog:是否输出原始 Sql 执行日志(ADO.NET),默认 true + // VirtualPath:配置虚拟目录,必须以 / 开头 + "InjectSpecificationDocument": false, + "InjectMiniProfiler": false + }, + // Swagger文档配置 ------------------------------------------------------------------------------ + "SpecificationDocumentSettings": { + // DocumentTitle:文档标题,string,默认 Specification Api Document + // DefaultGroupName:默认分组名,string,默认 Default + // EnableAuthorized:是否启用权限控制,bool,默认 true + // FormatAsV2:采用 Swagger 2.0 版本,bool,默认 false 已弃用 + // RoutePrefix:规范化文档地址,string,默认 api,如果希望在首页,改为空字符串即可。 + // DocExpansionState:文档显示方式,DocExpansion,默认 List,取值: + // List:列表式(展开子类),默认值 + // Full:完全展开 + // None:列表式(不展开子类) + // XmlComments:程序集注释描述文件名(可带 .xml,string,默认 Furion.Application, Furion.Web.Entry, Furion.Web.Core + // GroupOpenApiInfos:分组信息配置,SpecificationOpenApiInfo[],默认 { 'Group': 'Default'} + // SecurityDefinitions:安全策略定义配置,SpecificationOpenApiSecurityScheme[],默认 [] + // Servers:配置 Server 下拉列表,OpenApiServer[] 类型,默认 [],如:{Servers:[ { Url:"地址", Description:"描述"} ]} + // HideServers:是否隐藏 Server 下拉列表,bool 类型,默认 true + // RouteTemplate:配置文档 swagger.json 路由模板,默认模板:swagger/{documentName}/swagger.json, {documentName} 代表分组名,必须保留原样 + // PackagesGroups:配置模块化内置分组名称,string[] 类型,默认 [] + // EnableEnumSchemaFilter:启用枚举 Schema 筛选器,bool 类型,默认 true + // EnableTagsOrderDocumentFilter:启用标签排序筛选器,bool 类型,默认 true + // ServerDir:配置 IIS 添加 Application 部署名,string 类型,默认空,仅在 Furion v3.2.0+` 有效 + // LoginInfo:配置 Swagger 是否需要登录才能访问,SpecificationLoginInfo 类型,默认 null,仅在 Furion v3.3.3+` 有效 + // Enabled:是否启用登录授权,默认 false + // CheckUrl:检查登录状态的 Url 地址,该地址必须是 POST 请求,已授权返回 200,否则返回 401 + // SubmitUrl:提交登录的 Url 地址,该地址必须是 POST 请求且只有一个 SpecificationAuth 类型参数,成功登录返回 200,否则返回 401,支持相对地址,以 / 开头 + // EnableAllGroups:启用 Swagger 总分组功能,自动将所有分组的接口合并到 All Groups 中,bool 类型,默认 false,仅在 Furion v3.3.4+` 有效 + // 另外 SpecificationOpenApiInfo 内置配置如下: + // + // Group:分组唯一标识,string 类型,必填 + // Order:分组排序,int 类型,数字越大排前面,默认 0 + // Visible:配置分组是否可见,bool 类型,默认 true + // Title:配置分组标题,string 类型 + // Description:配置分组描述,string 类型 + // Version:配置分组版本,默认 1.0 + // TermsOfService:配置相关链接地址,Uri 类型 + // Contact:配置联系方式,OpenApiContact 类型 + // License:配置协议,OpenApiLicense 类型 + "EnableEnumSchemaFilter": false, + "EnableAuthorized": false, + "RoutePrefix": "swagger", + "XmlComments": [ + "FreeSql.xml", + "NetAdmin.Application.xml", + "NetAdmin.BizServer.Application.xml", + "NetAdmin.BizServer.Cache.xml", + "NetAdmin.BizServer.Host.xml", + "NetAdmin.Cache.xml", + "NetAdmin.Domain.xml", + "NetAdmin.Host.xml", + "NetAdmin.Infrastructure.xml", + "NetAdmin.ScheduledService.xml", + "NetAdmin.SysComponent.Application.xml", + "NetAdmin.SysComponent.Cache.xml", + "NetAdmin.SysComponent.Host.xml", + ] + }, + // 验证码配置 -------------------------------------------------------------------------------------------------------- + "Captcha": { + "ImageRelativePath": ".data/captcha", + "SecretKey": "1Z?f(2)%v?:X5NYRl+]PSi.rDf7Ip#lB" + }, + // 跨域配置 ---------------------------------------------------------------------------------------------------------- + "CorsAccessorSettings": { + // CorsAccessorSettings + // PolicyName:跨域策略名,string 类型,必填,默认 App.Cors.Policy + // WithOrigins:允许跨域的域名列表,string[] 类型,默认 * + // WithHeaders:请求表头,没有配置则允许所有表头,string[] 类型 + // WithExposedHeaders:设置客户端可获取的响应标头,string[] 类型,默认 ["access-token", "x-access-token"] + // WithMethods:设置跨域允许请求谓词,没有配置则允许所有,string[] 类型 + // AllowCredentials:是否允许跨域请求中的凭据,bool 类型,默认值 true + // SetPreflightMaxAge:设置预检过期时间,int 类型,默认值 24小时 + // FixedClientToken:是否默认配置 WithExposedHeaders,bool 类型,默认 true + // SignalRSupport:是否启用 SignalR 跨域支持,bool 类型,默认 false + "WithExposedHeaders": [ + "access-token", + "x-access-token", + "content-disposition" + ] + }, + // 数据库配置 -------------------------------------------------------------------------------------------------------- + "Database": { + "DbType": "Sqlite", + "ConnStr": "data source=../../../assets/NetAdmin.db", + "SeedDataRelativePath": "SeedData" + }, + // 动态webapi配置 ---------------------------------------------------------------------------------------------------- + "DynamicApiControllerSettings": { + // 5.1.10 DynamicApiControllerSettings 配置 + // Furion 还提供动态 WebAPI 接口一些全局配置选项,如: + // + // DefaultRoutePrefix:默认路由前缀,string,默认 api + // DefaultHttpMethod:默认请求谓词,string,默认:POST + // DefaultModule:默认模块名称(区域),可用作接口版本,string,默认:v1 + // LowercaseRoute:小写路由格式,bool,默认:true + // AsLowerCamelCase:启用小驼峰命名(首字母小写),默认 false + // KeepVerb:是否保留动作谓词,bool,默认:false + // KeepName:是否保留默认名称,bool,默认:fasle + // CamelCaseSeparator:骆驼(驼峰)/帕斯卡命名分隔符,string,默认:- + // VersionSeparator:版本分隔符,string,默认:@ + // ModelToQuery:GET/HEAD 请求将 类类型参数转查询参数,bool,默认 false + // SupportedMvcController:是否支持 Mvc Controller 动态配置,bool,默认 false + // UrlParameterization:路由参数采用 [FromQuery] 化,默认 false([FromRoute] 方式) + // DefaultArea:配置默认区域,默认 null + // ForceWithRoutePrefix:配置是否强制添加 DefaultRoutePrefix,当控制器自定义了 [Route] 有效,仅限 v3.4.1+版本有效 + // AbandonControllerAffixes:默认去除控制器名称前后缀列表名,string[],默认: + // AppServices + // AppService + // ApiController + // Controller + // Services + // Service + // AbandonActionAffixes:默认去除动作方法名称前后缀列表名,string[],默认: + // Async + // VerbToHttpMethods:复写默认方法名转 [HttpMethod] 规则,string[][] 二维数组类型,内置匹配规则为: + // ["post"] = "POST", + // ["add"] = "POST", + // ["create"] = "POST", + // ["insert"] = "POST", + // ["submit"] = "POST", + // ["get"] = "GET", + // ["find"] = "GET", + // ["fetch"] = "GET", + // ["query"] = "GET", + // ["getlist"] = "GET", + // ["getall"] = "GET", + // ["put"] = "PUT", + // ["update"] = "PUT", + // ["delete"] = "DELETE", + // ["remove"] = "DELETE", + // ["clear"] = "DELETE", + // ["patch"] = "PATCH" + // + // 复写示例 + // "DynamicApiControllerSettings": { + // "VerbToHttpMethods": [ + // [ "getall", "HEAD" ], // => getall 会被复写为 `[HttpHead]` + // [ "other", "PUT" ] // => 新增一条新规则,比如,一 `[other]` 开头会转换为 `[HttpPut]` 请求 + // ] + // } + // "DefaultRoutePrefix": "rest", + "VerbToHttpMethods": [ + [ + "post", + "POST" + ], + [ + "add", + "POST" + ], + [ + "create", + "POST" + ], + [ + "insert", + "POST" + ], + [ + "submit", + "POST" + ], + [ + "get", + "POST" + ], + [ + "find", + "POST" + ], + [ + "fetch", + "POST" + ], + [ + "query", + "POST" + ], + [ + "getlist", + "POST" + ], + [ + "getall", + "POST" + ], + [ + "put", + "POST" + ], + [ + "update", + "POST" + ], + [ + "delete", + "POST" + ], + [ + "remove", + "POST" + ], + [ + "clear", + "POST" + ], + [ + "patch", + "POST" + ] + ], + "CamelCaseSeparator": ".", + "UrlParameterization": true, + "KeepVerb": true, + "AbandonControllerAffixes": [ + "Controller" + ], + }, + // 友好异常配置 ------------------------------------------------------------------------------------------------------- + "FriendlyExceptionSettings": { + // 7.15 FriendlyExceptionSettings 配置 + // HideErrorCode:隐藏错误码,bool 类型,默认 false + // DefaultErrorCode:默认错误码,string 类型 + // DefaultErrorMessage:默认错误消息,string 类型 + // ThrowBah:是否将 Oops.Oh 默认抛出为业务异常,bool 类型,默认 false,设置 true 之后 Oops.Oh 默认进入 OnValidateFailed 处理,而不是 OnException + // LogError:是否输出异常日志,bool 类型,默认 true + "LogError": false + }, + // JWT鉴权配置 ------------------------------------------------------------------------------------------------------- + "JWTSettings": { + "ValidateIssuerSigningKey": true, + // 是否验证密钥,bool 类型,默认true + "IssuerSigningKey": "bO0BCAGxpxYnm6AE4XpgO25T27NayFzjGgfDqBuzUzD6ROpFiZUi3KjVg93bdGek", + // 密钥,string 类型,必须是复杂密钥,长度大于16 + "ValidateIssuer": true, + // 是否验证签发方,bool 类型,默认true + "ValidIssuer": "签发方", + // 签发方,string 类型 + "ValidateAudience": true, + // 是否验证签收方,bool 类型,默认true + "ValidAudience": "签收方", + // 签收方,string 类型 + "ValidateLifetime": true, + // 是否验证过期时间,bool 类型,默认true,建议true + "ExpiredTime": 20, + // 过期时间,long 类型,单位分钟,默认20分钟 + "ClockSkew": 5, + // 过期时间容错值,long 类型,单位秒,默认 5秒 + "Algorithm": "HS256" + // 加密算法,string 类型,默认 HS256 + }, + // 日志配置 ---------------------------------------------------------------------------------------------------------- + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "System.Logging.EventBusService": "Error" + }, + "Monitor": { + "GlobalEnabled": true, + // 是否启用全局拦截,默认 `false` + // "IncludeOfMethods": [], // 是否指定拦截特定方法,当 GlobalEnabled: false 有效 + // "ExcludeOfMethods": [], // 是否指定排除特定方法,当 GlobalEnabled: true 有效 + // "BahLogLevel": "Information", // 配置 Oops.Oh 和 Oops.Bah 业务日志输出级别,默认 Information + // "WithReturnValue": true, // 配置是否包含返回值,默认 `true`,Furion 4.3.9+ 有效 + "ReturnValueThreshold": 1000 + // 配置返回值字符串阈值,默认 0,全量输出,Furion 4.3.9+ 有效 + // "JsonBehavior": "None", // 配置 LoggingMonitor Json 输出行为,默认 None,Furion 4.5.2+ 有效 + // "MethodsSettings": [ + // // 配置被监视方法更多信息,Furion 4.3.9+ 有效 + // { + // "FullName": "Furion.Application.TestLoggerServices.MethodName", // 方法完全限定名 + // "WithReturnValue": true, // 配置是否包含返回值,默认 `true`,Furion 4.3.9+ 有效 + // "ReturnValueThreshold": 0 // 配置返回值字符串阈值,默认 0,全量输出,Furion 4.3.9+ 有效 + // } + // ] + } + }, + // Redis配置 -------------------------------------------------------------------------------------------------------- + "Redis": { + "Instances": [ + // 数据缓存 + { + "Name": "DataCache", + "ConnStr": "localhost:6379", + "Database": 0 + } + ] + }, + // UnifyResultSettings 规范化配置 ------------------------------------------------------------------------------------ + "UnifyResultSettings": { + // Return200StatusCodes:配置返回 200 状态码的请求,int[] 类型,只支持 400+(404除外) 状态码篡改 + // AdaptStatusCodes:配置篡改状态码规则,int[][] 类型,只支持 400+(404除外) 状态码篡改 + // SupportMvcController:是否支持 MVC 控制台规范化处理,bool 类型,默认 false + "Return200StatusCodes": [ + 999 + ], + }, + // 文件上传配置 ------------------------------------------------------------------------------------------------------- + "Upload": { + "ContentTypes": [ + "image/jpg", + "image/png", + "image/jpeg", + "image/gif" + ], + "MaxSize": 1073741824, + "Minio": { + "ServerAddress": "vm-ubt-1:9000", + "AccessKey": "nVMM0gSqwyIjM8iZ", + "SecretKey": "F8OZngGrNsZSYn4MP9swwMSf5rfm61EC", + "BucketName": "net-admin", + "AccessUrl": "http://vm-ubt-1:9000", + "Secure": false, + } + }, +} \ No newline at end of file diff --git a/src/backend/NetAdmin.ScheduledService/Extensions/ServiceCollectionExtensions.cs b/src/backend/NetAdmin.ScheduledService/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..d8825491 --- /dev/null +++ b/src/backend/NetAdmin.ScheduledService/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,50 @@ +using Furion.Schedule; +using NetAdmin.Domain.Contexts; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.Enums.Sys; +using NetAdmin.Host.Extensions; +using NetAdmin.ScheduledService.Jobs; + +namespace NetAdmin.ScheduledService.Extensions; + +/// +/// ServiceCollection 扩展方法 +/// +[SuppressSniffer] +public static class ServiceCollectionExtensions +{ + /// + /// 注册FreeSql + /// + public static IServiceCollection AddFreeSql(this IServiceCollection me) + { + _ = me.AddFreeSql( // + FreeSqlInitOptions.SyncStructure | FreeSqlInitOptions.InsertSeedData, freeSql => { + // 数据权限过滤器 + _ = freeSql.GlobalFilter.ApplyOnlyIf( // + Chars.FLG_GLOBAL_FILTER_DATA + , () => ContextUserInfo.Create()?.Roles.All(x => x.DataScope == DataScopes.Self) ?? false + , a => a.OwnerId == ContextUserInfo.Create().Id); + }); + return me; + } + + /// + /// 注册定时任务 + /// + public static IServiceCollection AddSchedules(this IServiceCollection me) + { + _ = me.AddSchedule( // + builder => builder // + .AddJob(false, Triggers.Minutely().SetRunOnStart(true)) + + // .AddJob(false, Triggers.PeriodSeconds(10).SetRunOnStart(true)) + // .AddJob(false, Triggers.PeriodSeconds(10).SetRunOnStart(true)) + + // + #pragma warning disable SA1009, SA1111 + ); + #pragma warning restore SA1111, SA1009 + return me; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.ScheduledService/Jobs/ExampleJob.cs b/src/backend/NetAdmin.ScheduledService/Jobs/ExampleJob.cs new file mode 100644 index 00000000..50044e5c --- /dev/null +++ b/src/backend/NetAdmin.ScheduledService/Jobs/ExampleJob.cs @@ -0,0 +1,34 @@ +using Furion.Schedule; +using NetAdmin.Host.BackgroundRunning; + +namespace NetAdmin.ScheduledService.Jobs; + +/// +/// 示例Job +/// +public sealed class ExampleJob : WorkBase, IJob +{ + /// + /// Initializes a new instance of the class. + /// + public ExampleJob() { } + + /// + /// 具体处理逻辑 + /// + /// 作业执行前上下文 + /// 取消任务 Token + /// 加锁失败异常 + public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken) + { + await WorkflowAsync(stoppingToken); + } + + /// + /// 通用工作流 + /// + protected override ValueTask WorkflowAsync(CancellationToken cancelToken) + { + return ValueTask.CompletedTask; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.ScheduledService/NetAdmin.ScheduledService.csproj b/src/backend/NetAdmin.ScheduledService/NetAdmin.ScheduledService.csproj new file mode 100644 index 00000000..cb796d2f --- /dev/null +++ b/src/backend/NetAdmin.ScheduledService/NetAdmin.ScheduledService.csproj @@ -0,0 +1,15 @@ + + + + + + + + + + + + PreserveNewest + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.ScheduledService/Properties/launchSettings.json b/src/backend/NetAdmin.ScheduledService/Properties/launchSettings.json new file mode 100644 index 00000000..be13b02f --- /dev/null +++ b/src/backend/NetAdmin.ScheduledService/Properties/launchSettings.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "NetAdmin.ScheduledService": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchUrl": "http://localhost:65080", + "applicationUrl": "http://[::]:65080", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.ScheduledService/Startup.cs b/src/backend/NetAdmin.ScheduledService/Startup.cs new file mode 100644 index 00000000..f7428792 --- /dev/null +++ b/src/backend/NetAdmin.ScheduledService/Startup.cs @@ -0,0 +1,68 @@ +using NetAdmin.Host.Extensions; +using NetAdmin.Host.Middlewares; +using NetAdmin.ScheduledService.Extensions; +using Prometheus; + +namespace NetAdmin.ScheduledService; + +/// +/// 启动类 +/// +public sealed class Startup : Host.Startup +{ + /// + /// 程序入口 + /// + public static void Main(string[] args) + { + ShowBanner(); + _ = Serve.Run(RunOptions.Default.WithArgs(args)); + } + + /// + /// 配置应用程序中间件 + /// + public void Configure(IApplicationBuilder app) + { + _ = app // + .UseRealIp() // 获取真实IP + .EnableBuffering() // / 启用 Body 重读 + .UseMiddleware() // 请求审计 + #if DEBUG + .UseOpenApiSkin() // / Swagger皮肤 + #endif + .UseInject(string.Empty) // / Furion脚手架 + .UseUnifyResultStatusCodes() // 状态码拦截 + .UseCorsAccessor() // 跨域访问 + .UseRouting() // 路由映射 + .UseHttpMetrics() // 性能监控 + .UseMiddleware() // 删除json空节点 + .UseEndpoints() // / 执行匹配的端点 + + // + ; + } + + /// + /// 配置服务容器 + /// + public void ConfigureServices(IServiceCollection services) + { + _ = services.AddConsoleFormatter() // / 控制台日志模板 + .AddAllOptions() // / 注册配置项 + .AddSnowflake() // / 雪花编号生成器 + .AddEventBus() // 事件总线 + .AddFreeSql() // freeSql + .AddRemoteRequest() // 注册远程请求 + .AddCorsAccessor() // 支持跨域访问 + .AddRedisCache() // Redis缓存 + .AddContextUser() // 上下文用户 + .AddSchedules() // 计划任务 + + // IMvcBuilder + .AddControllers() // 注册控制器 + .AddJsonSerializer() // json序列化配置 + .AddDefaultApiResultHandler() // Api结果处理器 + ; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.ScheduledService/settings.Development.json b/src/backend/NetAdmin.ScheduledService/settings.Development.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/src/backend/NetAdmin.ScheduledService/settings.Development.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/backend/NetAdmin.ScheduledService/settings.Test.json b/src/backend/NetAdmin.ScheduledService/settings.Test.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/src/backend/NetAdmin.ScheduledService/settings.Test.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/backend/NetAdmin.ScheduledService/settings.json b/src/backend/NetAdmin.ScheduledService/settings.json new file mode 100644 index 00000000..496930a9 --- /dev/null +++ b/src/backend/NetAdmin.ScheduledService/settings.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", + "SpecificationDocumentSettings": { + "GroupOpenApiInfos": [ + { + "Group": "Default", + "Title": "计划任务服务", + "Description": "NetAdmin - 计划任务服务", + }, + { + "Group": "Health", + "Visible": false + } + ] + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IApiModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IApiModule.cs new file mode 100644 index 00000000..d31a9946 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IApiModule.cs @@ -0,0 +1,20 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Api; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 接口模块 +/// +public interface IApiModule : ICrudModule +{ + /// + /// 同步接口 + /// + Task SyncAsync(); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/ICacheModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/ICacheModule.cs new file mode 100644 index 00000000..4d164684 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/ICacheModule.cs @@ -0,0 +1,20 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Cache; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 缓存模块 +/// +public interface ICacheModule +{ + /// + /// 缓存统计 + /// + Task CacheStatisticsAsync(); + + /// + /// 获取所有缓存项 + /// + PagedQueryRsp GetAllEntries(PagedQueryReq req); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/ICaptchaModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/ICaptchaModule.cs new file mode 100644 index 00000000..a37af239 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/ICaptchaModule.cs @@ -0,0 +1,19 @@ +using NetAdmin.Domain.Dto.Sys.Captcha; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 人机验证模块 +/// +public interface ICaptchaModule +{ + /// + /// 获取人机校验图 + /// + Task GetCaptchaImageAsync(); + + /// + /// 完成人机校验 + /// + Task VerifyCaptchaAsync(VerifyCaptchaReq req); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IConfigModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IConfigModule.cs new file mode 100644 index 00000000..37871bcd --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IConfigModule.cs @@ -0,0 +1,20 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Config; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 配置模块 +/// +public interface IConfigModule : ICrudModule +{ + /// + /// 获取最新有效配置 + /// + Task GetLatestConfigAsync(); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IConstantModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IConstantModule.cs new file mode 100644 index 00000000..57057bff --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IConstantModule.cs @@ -0,0 +1,27 @@ +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 常量模块 +/// +public interface IConstantModule +{ + /// + /// 获得常量字符串 + /// + IDictionary GetCharsDic(); + + /// + /// 获得公共枚举值 + /// + IDictionary> GetEnums(); + + /// + /// 获得本地化字符串 + /// + IDictionary GetLocalizedStrings(); + + /// + /// 获得数字常量表 + /// + IDictionary GetNumbersDic(); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDeptModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDeptModule.cs new file mode 100644 index 00000000..91290f93 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDeptModule.cs @@ -0,0 +1,14 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dept; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 部门模块 +/// +public interface IDeptModule : ICrudModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDevModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDevModule.cs new file mode 100644 index 00000000..cb3c2092 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDevModule.cs @@ -0,0 +1,24 @@ +using NetAdmin.Domain.Dto.Sys.Dev; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 开发模块 +/// +public interface IDevModule +{ + /// + /// 生成后端代码 + /// + Task GenerateCsCodeAsync(GenerateCsCodeReq req); + + /// + /// 生成图标代码 + /// + Task GenerateIconCodeAsync(GenerateIconCodeReq req); + + /// + /// 生成接口代码 + /// + Task GenerateJsCodeAsync(); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDicCatalogModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDicCatalogModule.cs new file mode 100644 index 00000000..167dcc21 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDicCatalogModule.cs @@ -0,0 +1,14 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Catalog; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 字典目录模块 +/// +public interface IDicCatalogModule : ICrudModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDicContentModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDicContentModule.cs new file mode 100644 index 00000000..acda7e03 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDicContentModule.cs @@ -0,0 +1,14 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Content; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 字典内容模块 +/// +public interface IDicContentModule : ICrudModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDicModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDicModule.cs new file mode 100644 index 00000000..82e8b029 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IDicModule.cs @@ -0,0 +1,71 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Catalog; +using NetAdmin.Domain.Dto.Sys.Dic.Content; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 字典模块 +/// +public interface IDicModule +{ + /// + /// 批量删除字典目录 + /// + Task BulkDeleteCatalogAsync(BulkReq req); + + /// + /// 批量删除字典内容 + /// + Task BulkDeleteContentAsync(BulkReq req); + + /// + /// 创建字典目录 + /// + Task CreateCatalogAsync(CreateDicCatalogReq req); + + /// + /// 创建字典内容 + /// + Task CreateContentAsync(CreateDicContentReq req); + + /// + /// 删除字典目录 + /// + Task DeleteCatalogAsync(DelReq req); + + /// + /// 删除字典内容 + /// + Task DeleteContentAsync(DelReq req); + + /// + /// 分页查询字典目录 + /// + Task> PagedQueryCatalogAsync(PagedQueryReq req); + + /// + /// 分页查询字典内容 + /// + Task> PagedQueryContentAsync(PagedQueryReq req); + + /// + /// 查询字典目录 + /// + Task> QueryCatalogAsync(QueryReq req); + + /// + /// 查询字典内容 + /// + Task> QueryContentAsync(QueryReq req); + + /// + /// 更新字典目录 + /// + Task UpdateCatalogAsync(UpdateDicCatalogReq req); + + /// + /// 更新字典内容 + /// + Task UpdateContentAsync(UpdateDicContentReq req); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IFileModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IFileModule.cs new file mode 100644 index 00000000..c6c54631 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IFileModule.cs @@ -0,0 +1,12 @@ +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 文件模块 +/// +public interface IFileModule +{ + /// + /// 文件上传 + /// + Task UploadAsync(IFormFile file); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IMenuModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IMenuModule.cs new file mode 100644 index 00000000..a48668da --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IMenuModule.cs @@ -0,0 +1,20 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Menu; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 菜单模块 +/// +public interface IMenuModule : ICrudModule +{ + /// + /// 当前用户菜单 + /// + Task> UserMenusAsync(); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRequestLogModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRequestLogModule.cs new file mode 100644 index 00000000..5b5e32c8 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRequestLogModule.cs @@ -0,0 +1,14 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.RequestLog; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 请求日志模块 +/// +public interface IRequestLogModule : ICrudModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRoleModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRoleModule.cs new file mode 100644 index 00000000..ff9fe37c --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IRoleModule.cs @@ -0,0 +1,14 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Role; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 角色模块 +/// +public interface IRoleModule : ICrudModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IToolsModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IToolsModule.cs new file mode 100644 index 00000000..56d88f39 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IToolsModule.cs @@ -0,0 +1,17 @@ +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 工具模块 +/// +public interface IToolsModule +{ + /// + /// 服务器时间 + /// + DateTime GetServerUtcTime(); + + /// + /// 版本信息 + /// + string Version(); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IUserModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IUserModule.cs new file mode 100644 index 00000000..c848034a --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IUserModule.cs @@ -0,0 +1,76 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.User; +using NetAdmin.Domain.Dto.Sys.UserProfile; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 用户模块 +/// +public interface IUserModule : ICrudModule +{ + /// + /// 检查手机号是否可用 + /// + Task CheckMobileAvailableAsync(CheckMobileAvailableReq req); + + /// + /// 检查用户名是否可用 + /// + Task CheckUserNameAvailableAsync(CheckUserNameAvailableReq req); + + /// + /// 密码登录 + /// + Task LoginByPwdAsync(LoginByPwdReq req); + + /// + /// 短信登录 + /// + Task LoginBySmsAsync(LoginBySmsReq req); + + /// + /// 查询用户档案 + /// + Task> QueryProfileAsync(QueryReq req); + + /// + /// 注册用户 + /// + Task RegisterAsync(RegisterUserReq req); + + /// + /// 重设密码 + /// + Task ResetPasswordAsync(ResetPasswordReq req); + + /// + /// 设置用户头像 + /// + Task SetAvatarAsync(SetAvatarReq req); + + /// + /// 设置邮箱 + /// + Task SetEmailAsync(SetEmailReq req); + + /// + /// 设置手机号 + /// + Task SetMobileAsync(SetMobileReq req); + + /// + /// 设置密码 + /// + Task SetPasswordAsync(SetPasswordReq req); + + /// + /// 当前用户信息 + /// + Task UserInfoAsync(); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IUserProfileModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IUserProfileModule.cs new file mode 100644 index 00000000..8f85c38f --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IUserProfileModule.cs @@ -0,0 +1,14 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.UserProfile; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 用户档案模块 +/// +public interface IUserProfileModule : ICrudModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IVerifyCodeModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IVerifyCodeModule.cs new file mode 100644 index 00000000..aa6bf83a --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IVerifyCodeModule.cs @@ -0,0 +1,28 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.VerifyCode; + +namespace NetAdmin.SysComponent.Application.Modules.Sys; + +/// +/// 验证码模块 +/// +public interface IVerifyCodeModule : ICrudModule +{ + /// + /// 发送验证码 + /// + Task SendVerifyCodeAsync(SendVerifyCodeReq req); + + /// + /// 完成验证 + /// + /// + /// 对于验证失败的,不主动删除缓存,通过防火墙来应对暴力破解 + /// + Task VerifyAsync(VerifyCodeReq req); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Tpl/IExampleModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Tpl/IExampleModule.cs new file mode 100644 index 00000000..7d71660a --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Tpl/IExampleModule.cs @@ -0,0 +1,14 @@ +using NetAdmin.Application.Modules; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Tpl.Example; + +namespace NetAdmin.SysComponent.Application.Modules.Tpl; + +/// +/// 示例模块 +/// +public interface IExampleModule : ICrudModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/NetAdmin.SysComponent.Application.csproj b/src/backend/NetAdmin.SysComponent.Application/NetAdmin.SysComponent.Application.csproj new file mode 100644 index 00000000..1124ffb6 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/NetAdmin.SysComponent.Application.csproj @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ApiService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ApiService.cs new file mode 100644 index 00000000..03378b3f --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ApiService.cs @@ -0,0 +1,160 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Api; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class ApiService : RepositoryService, IApiService +{ + private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider; + private readonly XmlCommentReader _xmlCommentReader; + + /// + /// Initializes a new instance of the class. + /// + public ApiService(Repository rpo, XmlCommentReader xmlCommentReader + , IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) // + : base(rpo) + { + _xmlCommentReader = xmlCommentReader; + _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider; + } + + /// + /// 批量删除接口 + /// + /// NotImplementedException + public Task BulkDeleteAsync(BulkReq req) + { + throw new NotImplementedException(); + } + + /// + /// 创建接口 + /// + /// NotImplementedException + public Task CreateAsync(CreateApiReq req) + { + throw new NotImplementedException(); + } + + /// + /// 删除接口 + /// + /// NotImplementedException + public Task DeleteAsync(DelReq req) + { + throw new NotImplementedException(); + } + + /// + /// 判断接口是否存在 + /// + /// NotImplementedException + public Task ExistAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 获取单个接口 + /// + /// NotImplementedException + public Task GetAsync(QueryApiReq req) + { + throw new NotImplementedException(); + } + + /// + /// 分页查询接口 + /// + /// NotImplementedException + public Task> PagedQueryAsync(PagedQueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 查询接口 + /// + public async Task> QueryAsync(QueryReq req) + { + var ret = await Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter).ToTreeListAsync(); + return ret.Adapt>(); + } + + /// + /// 反射接口列表 + /// + public IEnumerable ReflectionList(bool excludeAnonymous = true) + { + var regex = new Regex(@"\.(\w+)$", RegexOptions.Compiled); + + QueryApiRsp SelectQueryApiRsp(IGrouping group) + { + var first = group.First()!; + return new QueryApiRsp { + Summary = _xmlCommentReader.GetComments(group.Key) + , Name = first.ControllerName + , Id = Regex.Replace( // + first.AttributeRouteInfo!.Template!, $"/{first.ActionName}$", string.Empty) + , Children = GetChildren(group) + , Namespace = regex.Match(group.Key.Namespace!).Groups[1].Value.ToLowerInvariant() + }; + } + + var actionDescriptors // + = _actionDescriptorCollectionProvider.ActionDescriptors.Items.Cast(); + + if (excludeAnonymous) { + actionDescriptors = actionDescriptors.Where(x => x.EndpointMetadata.All(y => y is AllowAnonymousAttribute)); + } + + var actionGroup // + = actionDescriptors.GroupBy(x => x.ControllerTypeInfo); + + return actionGroup.Select(SelectQueryApiRsp); + } + + /// + /// 同步接口 + /// + public async Task SyncAsync() + { + _ = await Rpo.DeleteAsync(_ => true); + + var list = ReflectionList(false); + + EnableCascadeSave = true; + foreach (var item in list) { + var entity = item.Adapt(); + _ = await Rpo.InsertAsync(entity); + } + } + + /// + /// 更新接口 + /// + /// NotImplementedException + public Task UpdateAsync(NopReq req) + { + throw new NotImplementedException(); + } + + private IEnumerable GetChildren(IEnumerable actionDescriptors) + { + return actionDescriptors // + .Select(x => new QueryApiRsp { + Summary = _xmlCommentReader.GetComments(x.MethodInfo) + , Name = x.ActionName + , Id = x.AttributeRouteInfo!.Template + , Method = x.ActionConstraints?.OfType() + .FirstOrDefault() + ?.HttpMethods.First() + }); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/CacheService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/CacheService.cs new file mode 100644 index 00000000..b76bbbf0 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/CacheService.cs @@ -0,0 +1,49 @@ +using NetAdmin.Application.Services; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Cache; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using StackExchange.Redis; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class CacheService : ServiceBase, ICacheService +{ + private readonly IConnectionMultiplexer _connectionMultiplexer; + + /// + /// Initializes a new instance of the class. + /// + public CacheService(IConnectionMultiplexer connectionMultiplexer) + { + _connectionMultiplexer = connectionMultiplexer; + } + + /// + /// 缓存统计 + /// + public Task CacheStatisticsAsync() + { + var database = _connectionMultiplexer.GetDatabase(); + return Task.FromResult( + new CacheStatisticsRsp((string)database.Execute("info")) { DbSize = (long)database.Execute("dbSize") }); + } + + /// + public PagedQueryRsp GetAllEntries(PagedQueryReq req) + { + var database = _connectionMultiplexer.GetDatabase((int?)req.Filter?.DbIndex ?? 0); + var redisResults + = (RedisResult[])database.Execute("scan", (req.Page - 1) * req.PageSize, "count", req.PageSize); + + var list = ((string[])redisResults![1])!.Where(x => database.KeyType(x) == RedisType.Hash) + .Select(x => database.HashGetAll(x) + .Append(new HashEntry("key", x)) + .ToArray() + .ToStringDictionary()) + .ToList() + .ConvertAll(x => x.Adapt()); + + return new PagedQueryRsp(req.Page, req.PageSize, 10000, list); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/CaptchaService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/CaptchaService.cs new file mode 100644 index 00000000..7db65f72 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/CaptchaService.cs @@ -0,0 +1,58 @@ +using NetAdmin.Application.Services; +using NetAdmin.Domain.Dto.Sys.Captcha; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using SixLabors.ImageSharp; +using Yitter.IdGenerator; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class CaptchaService : ServiceBase, ICaptchaService +{ + private static readonly Assembly _entryAsm = Assembly.GetEntryAssembly(); + private static readonly string _entryAsmName = _entryAsm.FullName![.._entryAsm.FullName.IndexOf(',')]; + + /// + /// Initializes a new instance of the class. + /// + public CaptchaService() { } + + /// + /// 获取人机校验图 + /// + public async Task GetCaptchaImageAsync() + { + var (backgroundImage, sliderImage, offsetSaw) = await CaptchaImageHelper.CreateSawSliderImageAsync( + _entryAsm, $"{_entryAsmName}.Assets.Captcha.background", $"{_entryAsmName}.Assets.Captcha.template" + , (1, 101), (1, 7), new Size(50, 50)); + + var id = $"{nameof(GetCaptchaImageAsync)}_{YitIdHelper.NextId()}"; + return new GetCaptchaRsp { + Id = id + , BackgroundImage = backgroundImage + , SliderImage = sliderImage + , SawOffsetX = offsetSaw.X + }; + } + + /// + /// 完成人机校验 + /// + public Task VerifyCaptchaAsync(VerifyCaptchaReq req) + { + if (req.SawOffsetX == null) { + return Task.FromResult(false); + } + + bool ret; + try { + var aesKey = req.Id.Aes(CaptchaOptions.SecretKey)[..32]; + ret = Math.Abs(req.SawOffsetX.Value - req.VerifyData.AesDe(aesKey).Float()) < 5f; + } + catch { + ret = false; + } + + return Task.FromResult(ret); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConfigService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConfigService.cs new file mode 100644 index 00000000..6d8d7b6c --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConfigService.cs @@ -0,0 +1,132 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Config; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using DataType = FreeSql.DataType; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class ConfigService : RepositoryService, IConfigService +{ + /// + /// Initializes a new instance of the class. + /// + public ConfigService(Repository rpo) // + : base(rpo) { } + + /// + /// 批量删除配置 + /// + public async Task BulkDeleteAsync(BulkReq req) + { + var sum = 0; + foreach (var item in req.Items) { + sum += await DeleteAsync(item); + } + + return sum; + } + + /// + /// 创建配置 + /// + public async Task CreateAsync(CreateConfigReq req) + { + var ret = await Rpo.InsertAsync(req); + return ret.Adapt(); + } + + /// + /// 删除配置 + /// + public Task DeleteAsync(DelReq req) + { + return Rpo.DeleteAsync(a => a.Id == req.Id); + } + + /// + /// 判断配置是否存在 + /// + /// NotImplementedException + public Task ExistAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 获取单个配置 + /// + /// NotImplementedException + public async Task GetAsync(QueryConfigReq req) + { + var ret = await QueryInternal(new QueryReq { Filter = req }).ToOneAsync(); + return ret.Adapt(); + } + + /// + /// 获取最新有效配置 + /// + public async Task GetLatestConfigAsync() + { + var ret = await QueryAsync( + new QueryReq { Count = 1, Filter = new QueryConfigReq { Enabled = true } }); + return ret.FirstOrDefault(); + } + + /// + /// 分页查询配置 + /// + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var list = await QueryInternal(req).Page(req.Page, req.PageSize).Count(out var total).ToListAsync(); + + return new PagedQueryRsp(req.Page, req.PageSize, total + , list.Adapt>()); + } + + /// + /// 查询配置 + /// + public async Task> QueryAsync(QueryReq req) + { + var ret = await QueryInternal(req).Take(req.Count).ToListAsync(); + return ret.Adapt>(); + } + + /// + /// 更新配置 + /// + public async Task UpdateAsync(UpdateConfigReq req) + { + if (Rpo.Orm.Ado.DataType == DataType.Sqlite) { + return await UpdateForSqliteAsync(req); + } + + var ret = await Rpo.UpdateDiy.SetSource(req).ExecuteUpdatedAsync(); + return ret.FirstOrDefault()?.Adapt(); + } + + private ISelect QueryInternal(QueryReq req) + { + return Rpo.Select.Include(a => a.UserRegisterDept) + .Include(a => a.UserRegisterRole) + .WhereDynamicFilter(req.DynamicFilter) + .WhereIf( // + req.Filter?.Enabled.HasValue ?? false, a => a.Enabled == req.Filter.Enabled.Value) + .OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending) + .OrderByDescending(a => a.Id); + } + + /// + /// 非sqlite数据库请删掉 + /// + private async Task UpdateForSqliteAsync(Sys_Config req) + { + return await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync() <= 0 + ? null + : await GetAsync(new QueryConfigReq { Id = req.Id }); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConstantService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConstantService.cs new file mode 100644 index 00000000..3c53ec5e --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ConstantService.cs @@ -0,0 +1,58 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class ConstantService : ServiceBase, IConstantService +{ + /// + /// 获得常量字符串 + /// + public IDictionary GetCharsDic() + { + return typeof(Chars).GetFields(BindingFlags.Public | BindingFlags.Static) + .Where(x => x.FieldType == typeof(string)) + .ToImmutableSortedDictionary( // + x => x.Name, x => x.GetValue(null)?.ToString()); + } + + /// + /// 获得公共枚举值 + /// + public IDictionary> GetEnums() + { + return App.EffectiveTypes.Where(x => x.IsEnum && x.GetCustomAttribute(false) != null) + .ToDictionary(x => x.Name, x => // + x.GetEnumValues() + .Cast() + .ToDictionary( // + y => y.ToString() + , y => new[] { + Convert.ToInt64(y, CultureInfo.InvariantCulture) + .ToString(CultureInfo.InvariantCulture) + , y.ResDesc() + })); + } + + /// + /// 获得本地化字符串 + /// + public IDictionary GetLocalizedStrings() + { + return typeof(Ln).GetProperties(BindingFlags.Public | BindingFlags.Static) + .Where(x => x.PropertyType == typeof(string)) + .ToImmutableSortedDictionary(x => x.Name, x => x.GetValue(null)?.ToString()); + } + + /// + /// 获得数字常量表 + /// + public IDictionary GetNumbersDic() + { + return typeof(Numbers).GetFields(BindingFlags.Public | BindingFlags.Static) + .Where(x => x.FieldType == typeof(int) || x.FieldType == typeof(long)) + .ToImmutableSortedDictionary( // + x => x.Name, x => Convert.ToInt64(x.GetValue(null), CultureInfo.InvariantCulture)); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IApiService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IApiService.cs new file mode 100644 index 00000000..3d4a8234 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IApiService.cs @@ -0,0 +1,16 @@ +using NetAdmin.Application.Services; +using NetAdmin.Domain.Dto.Sys.Api; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 接口服务 +/// +public interface IApiService : IService, IApiModule +{ + /// + /// 反射接口列表 + /// + IEnumerable ReflectionList(bool excludeAnonymous = true); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/ICacheService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/ICacheService.cs new file mode 100644 index 00000000..78d6b48f --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/ICacheService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 缓存服务 +/// +public interface ICacheService : IService, ICacheModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/ICaptchaService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/ICaptchaService.cs new file mode 100644 index 00000000..46fd43d6 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/ICaptchaService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 人机验证服务 +/// +public interface ICaptchaService : IService, ICaptchaModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IConfigService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IConfigService.cs new file mode 100644 index 00000000..f26c43e2 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IConfigService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 配置服务 +/// +public interface IConfigService : IService, IConfigModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IConstantService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IConstantService.cs new file mode 100644 index 00000000..fe260225 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IConstantService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 常量服务 +/// +public interface IConstantService : IService, IConstantModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDeptService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDeptService.cs new file mode 100644 index 00000000..6b391409 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDeptService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 部门服务 +/// +public interface IDeptService : IService, IDeptModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDevService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDevService.cs new file mode 100644 index 00000000..0da0592a --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDevService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 开发服务 +/// +public interface IDevService : IService, IDevModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDicCatalogService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDicCatalogService.cs new file mode 100644 index 00000000..c8dca8fe --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDicCatalogService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 字典目录服务 +/// +public interface IDicCatalogService : IService, IDicCatalogModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDicContentService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDicContentService.cs new file mode 100644 index 00000000..dca7b15b --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDicContentService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 字典内容服务 +/// +public interface IDicContentService : IService, IDicContentModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDicService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDicService.cs new file mode 100644 index 00000000..578b0f39 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IDicService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 字典服务 +/// +public interface IDicService : IService, IDicModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IFileService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IFileService.cs new file mode 100644 index 00000000..1c5dd427 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IFileService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 文件服务 +/// +public interface IFileService : IService, IFileModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IMenuService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IMenuService.cs new file mode 100644 index 00000000..ad1f11bb --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IMenuService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 菜单服务 +/// +public interface IMenuService : IService, IMenuModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IRequestLogService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IRequestLogService.cs new file mode 100644 index 00000000..d5f2d5ec --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IRequestLogService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 请求日志服务 +/// +public interface IRequestLogService : IService, IRequestLogModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IRoleService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IRoleService.cs new file mode 100644 index 00000000..61fcbca5 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IRoleService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 角色服务 +/// +public interface IRoleService : IService, IRoleModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IToolsService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IToolsService.cs new file mode 100644 index 00000000..6adf6859 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IToolsService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 工具服务 +/// +public interface IToolsService : IService, IToolsModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IUserProfileService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IUserProfileService.cs new file mode 100644 index 00000000..4af0aae9 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IUserProfileService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 用户档案服务 +/// +public interface IUserProfileService : IService, IUserProfileModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IUserService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IUserService.cs new file mode 100644 index 00000000..23cf0b5a --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IUserService.cs @@ -0,0 +1,21 @@ +using NetAdmin.Application.Services; +using NetAdmin.Domain.Dto.Sys.User; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 用户服务 +/// +public interface IUserService : IService, IUserModule +{ + /// + /// 获取单个用户(带更新锁) + /// + Task GetForUpdateAsync(QueryUserReq req); + + /// + /// 单体更新 + /// + Task UpdateSingleAsync(UpdateUserReq req); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IVerifyCodeService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IVerifyCodeService.cs new file mode 100644 index 00000000..347f49f1 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/Dependency/IVerifyCodeService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Sys; + +namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +/// +/// 验证码服务 +/// +public interface IVerifyCodeService : IService, IVerifyCodeModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DeptService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DeptService.cs new file mode 100644 index 00000000..768da1f3 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DeptService.cs @@ -0,0 +1,139 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dept; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class DeptService : RepositoryService, IDeptService +{ + /// + /// Initializes a new instance of the class. + /// + public DeptService(Repository rpo) // + : base(rpo) { } + + /// + /// 批量删除部门 + /// + public async Task BulkDeleteAsync(BulkReq req) + { + var sum = 0; + foreach (var item in req.Items) { + sum += await DeleteAsync(item); + } + + return sum; + } + + /// + /// 创建部门 + /// + /// Parent_department_does_not_exist + public async Task CreateAsync(CreateDeptReq req) + { + if (req.ParentId != 0 && !await Rpo.Select.AnyAsync(a => a.Id == req.ParentId)) { + throw new NetAdminInvalidOperationException(Ln.父节点不存在); + } + + var ret = await Rpo.InsertAsync(req); + + return ret.Adapt(); + } + + /// + /// 删除部门 + /// + /// 该部门下存在用户 + /// 该部门下存在子部门 + public async Task DeleteAsync(DelReq req) + { + if (await Rpo.Orm.Select().AnyAsync(a => a.DeptId == req.Id)) { + throw new NetAdminInvalidOperationException(Ln.该部门下存在用户); + } + + #pragma warning disable IDE0046 + if (await Rpo.Select.AnyAsync(a => a.ParentId == req.Id)) { + #pragma warning restore IDE0046 + throw new NetAdminInvalidOperationException(Ln.该部门下存在子部门); + } + + return await Rpo.DeleteAsync(x => x.Id == req.Id); + } + + /// + /// 判断部门是否存在 + /// + /// NotImplementedException + public Task ExistAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 获取单个部门 + /// + /// NotImplementedException + public Task GetAsync(QueryDeptReq req) + { + throw new NotImplementedException(); + } + + /// + /// 分页查询部门 + /// + /// NotImplementedException + public Task> PagedQueryAsync(PagedQueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 查询部门 + /// + public async Task> QueryAsync(QueryReq req) + { + return (await QueryInternal(req).ToTreeListAsync()).Adapt>(); + } + + /// + /// 更新部门 + /// + /// NetAdminUnexpectedException + public async Task UpdateAsync(UpdateDeptReq req) + { + return await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync() <= 0 + ? throw new NetAdminUnexpectedException() + : (await QueryInternal(new QueryReq { Filter = new QueryDeptReq { Id = req.Id } }, true) + .ToTreeListAsync())[0] + .Adapt(); + } + + private ISelect QueryInternal(QueryReq req, bool asTreeCte = false) + { + var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) + .WhereDynamic(req.Filter) + .WhereIf( // + req.Keywords?.Length > 0 + , a => a.Name.Contains(req.Keywords) || a.Summary.Contains(req.Keywords) || + a.Id == req.Keywords.Int64Try(0)); + if (asTreeCte) { + ret = ret.AsTreeCte(); + } + + ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); + + if (!req.Prop?.Equals(nameof(req.Filter.Sort), StringComparison.OrdinalIgnoreCase) ?? true) { + ret = ret.OrderByDescending(a => a.Sort); + } + + if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) { + ret = ret.OrderByDescending(a => a.CreatedTime); + } + + return ret; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DevService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DevService.cs new file mode 100644 index 00000000..aa8635bd --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DevService.cs @@ -0,0 +1,215 @@ +using NetAdmin.Application.Services; +using NetAdmin.Domain.Dto.Sys.Api; +using NetAdmin.Domain.Dto.Sys.Dev; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class DevService : ServiceBase, IDevService +{ + private const string _REPLACE_TO_EMPTY = "//~"; + + private static readonly string _clientProjectPath = Path.Combine( // + Environment.CurrentDirectory, "../../frontend/admin"); + + private static readonly string[] _projectDirs + = Directory.GetDirectories(Path.Combine(Environment.CurrentDirectory, "../")); + + private readonly IApiService _apiService; + + /// + /// Initializes a new instance of the class. + /// + public DevService(IApiService apiService) + { + _apiService = apiService; + } + + /// + /// 生成后端代码 + /// + public async Task GenerateCsCodeAsync(GenerateCsCodeReq req) + { + // 模块类型(Sys、Biz、等) + var moduleType = Enum.GetName(req.Type)!; + + // 模板层目录 + var tplHostDir = GetDir("SysComponent.Host"); + var tplCacheDir = GetDir("SysComponent.Cache"); + var tplAppDir = GetDir("SysComponent.Application"); + + // 主机层目录 + var hostControllerDir = Path.Combine(GetDir($"{moduleType}.Host"), "Controllers", moduleType[..3]); + + // 缓存层目录 + var cacheDir = Path.Combine(GetDir($"{moduleType}.Cache"), moduleType[..3]); + var cacheDependencyDir = Path.Combine(cacheDir, "Dependency"); + + // 业务逻辑层目录 + var appDir = GetDir($"{moduleType}.Application"); + var appModulesDir = Path.Combine(appDir, "Modules", moduleType[..3]); + var appServicesDir = Path.Combine(appDir, "Services", moduleType[..3]); + var appServicesDependencyDir = Path.Combine(appServicesDir, "Dependency"); + + // 数据契约层目录 + var dataDir = GetDir("NetAdmin.Domain"); + var dtoDir = Path.Combine(dataDir, "Dto", moduleType[..3], req.ModuleName); + var entityDir = Path.Combine(dataDir, "DbMaps", moduleType[..3]); + + // 创建缺少的目录 + CreateDir(hostControllerDir, cacheDir, cacheDependencyDir, appDir, appModulesDir, appServicesDir +, appServicesDependencyDir, dataDir, dtoDir, entityDir); + + // Controller + await WriteCodeFileAsync(req, Path.Combine(tplHostDir, "Controllers", "Tpl", "ExampleController.cs") + , Path.Combine(hostControllerDir, $"{req.ModuleName}Controller.cs")); + + // CreateReq + await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "CreateExampleReq.cs") + , Path.Combine(dtoDir, $"Create{req.ModuleName}Req.cs")); + + // UpdateReq + await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "UpdateExampleReq.cs") + , Path.Combine(dtoDir, $"Update{req.ModuleName}Req.cs")); + + // QueryReq + await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "QueryExampleReq.cs") + , Path.Combine(dtoDir, $"Query{req.ModuleName}Req.cs")); + + // QueryRsp + await WriteCodeFileAsync(req, Path.Combine(dataDir, "Dto", "Tpl", "Example", "QueryExampleRsp.cs") + , Path.Combine(dtoDir, $"Query{req.ModuleName}Rsp.cs")); + + // ICache + await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "Dependency", "IExampleCache.cs") + , Path.Combine(cacheDependencyDir, $"I{req.ModuleName}Cache.cs")); + + // Cache + await WriteCodeFileAsync(req, Path.Combine(tplCacheDir, "Tpl", "ExampleCache.cs") + , Path.Combine(cacheDir, $"{req.ModuleName}Cache.cs")); + + // IModule + await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Modules", "Tpl", "IExampleModule.cs") + , Path.Combine(appModulesDir, $"I{req.ModuleName}Module.cs")); + + // IService + await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "Dependency", "IExampleService.cs") + , Path.Combine(appServicesDependencyDir, $"I{req.ModuleName}Service.cs")); + + // Service + await WriteCodeFileAsync(req, Path.Combine(tplAppDir, "Services", "Tpl", "ExampleService.cs") + , Path.Combine(appServicesDir, $"{req.ModuleName}Service.cs")); + + // Entity + await WriteCodeFileAsync(req, Path.Combine(dataDir, "DbMaps", "Tpl", "Tpl_Example.cs") + , Path.Combine(entityDir, $"{moduleType[..3]}_{req.ModuleName}.cs")); + } + + /// + /// 生成图标代码 + /// + public async Task GenerateIconCodeAsync(GenerateIconCodeReq req) + { + var tplSvg = await File.ReadAllTextAsync( + Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl", "Svg.vue")); + var tplExport + = await File.ReadAllTextAsync( + Path.Combine(_clientProjectPath, "src", "assets", "icons", "tpl", "export.js")); + + var vueContent = tplSvg.Replace("$svgCode$", req.SvgCode).Replace(_REPLACE_TO_EMPTY, string.Empty); + + var dir = Path.Combine(_clientProjectPath, "src", "assets", "icons"); + if (!Directory.Exists(dir)) { + _ = Directory.CreateDirectory(dir); + } + + var vueFile = Path.Combine(dir, $"{req.IconName}.vue"); + await File.WriteAllTextAsync(vueFile, vueContent); + + var indexJsFile = Path.Combine(dir, "index.js"); + + await File.AppendAllTextAsync( + indexJsFile + , Environment.NewLine + + tplExport.Replace("$iconName$", req.IconName).Replace(_REPLACE_TO_EMPTY, string.Empty)); + + // 修改iconSelect.js + var iconSelectFile = Path.Combine(_clientProjectPath, "src", "config", "iconSelect.js"); + var iconSelectContent = await File.ReadAllTextAsync(iconSelectFile); + iconSelectContent = iconSelectContent.Replace("export default", "exportDefault:").Replace("'", "\""); + iconSelectContent = Regex.Replace(iconSelectContent, "([a-zA-Z]+):", "\"$1\":"); + iconSelectContent = "{" + iconSelectContent + "}"; + var iconExportJsInfo = iconSelectContent.ToObject(); + iconExportJsInfo.ExportDefault.Icons.Last().Icons.Add($"sc-icon-{req.IconName.ToLowerInvariant()}"); + var newContent = iconExportJsInfo.ToJson().TrimStart('{')[..^1].Replace("\"exportDefault\":", "export default"); + + await File.WriteAllTextAsync(iconSelectFile, newContent); + } + + /// + /// 生成接口代码 + /// + public async Task GenerateJsCodeAsync() + { + // 模板文件 + var tplOuter = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "api", "tpl", "outer.js")); + var tplInner = await File.ReadAllTextAsync(Path.Combine(_clientProjectPath, "src", "api", "tpl", "inner.js")); + + IEnumerable Select(QueryApiRsp item) + { + return item.Children.Select(x => tplInner.Replace("$actionDesc$", x.Summary) + .Replace( // + "$actionName$" + , Regex.Replace(x.Name, @"\.(\w)" + , y => y.Groups[1].Value.ToUpperInvariant())) + .Replace("$actionPath$", x.Id) + .Replace( // + "$actionMethod$", x.Method?.ToLowerInvariant()) + .Replace(_REPLACE_TO_EMPTY, string.Empty)); // + } + + foreach (var item in _apiService.ReflectionList(false)) { + var dir = Path.Combine(_clientProjectPath, "src", "api", item.Namespace); + if (!Directory.Exists(dir)) { + _ = Directory.CreateDirectory(dir); + } + + var file = Path.Combine(dir, $"{item.Name.Replace(".", string.Empty)}.js"); + + var content = tplOuter.Replace("$controllerDesc$", item.Summary) + .Replace("$controllerPath$", item.Id) + .Replace( // + "$inner$" + , string.Join(Environment.NewLine + Environment.NewLine, Select(item))) + .Replace(_REPLACE_TO_EMPTY, string.Empty); + + await File.WriteAllTextAsync(file, content); + } + } + + private static void CreateDir(params string[] dirs) + { + foreach (var dir in dirs) { + if (!Directory.Exists(dir)) { + _ = Directory.CreateDirectory(dir); + } + } + } + + private static string GetDir(string key) + { + return _projectDirs.First(x => x.EndsWith(key, true, CultureInfo.InvariantCulture)); + } + + private static async Task WriteCodeFileAsync(GenerateCsCodeReq req, string tplFile, string writeFile) + { + var tplContent = await File.ReadAllTextAsync(tplFile); + tplContent = tplContent.Replace("Tpl", Enum.GetName(req.Type)![..3]) + .Replace("示例", req.ModuleRemark) + .Replace("Example", req.ModuleName) + .Replace("NetAdmin.SysComponent", "SysComponent"); + + await File.WriteAllTextAsync(writeFile, tplContent); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicCatalogService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicCatalogService.cs new file mode 100644 index 00000000..8f17d9ec --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicCatalogService.cs @@ -0,0 +1,119 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Catalog; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class DicCatalogService : RepositoryService, IDicCatalogService +{ + /// + /// Initializes a new instance of the class. + /// + public DicCatalogService(Repository rpo) // + : base(rpo) { } + + /// + /// 批量删除字典目录 + /// + public async Task BulkDeleteAsync(BulkReq req) + { + var sum = 0; + foreach (var item in req.Items) { + sum += await DeleteAsync(item); + } + + return sum; + } + + /// + /// 创建字典目录 + /// + /// The_parent_node_does_not_exist + public async Task CreateAsync(CreateDicCatalogReq req) + { + if (req.ParentId != 0 && !await Rpo.Select.Where(a => a.Id == req.ParentId).ForUpdate().AnyAsync()) { + throw new NetAdminInvalidOperationException(Ln.父节点不存在); + } + + var ret = await Rpo.InsertAsync(req); + return ret.Adapt(); + } + + /// + /// 删除字典目录 + /// + public async Task DeleteAsync(DelReq req) + { + var ret = await Rpo.DeleteCascadeByDatabaseAsync(a => a.Id == req.Id); + return ret.Count; + } + + /// + /// 判断字典目录是否存在 + /// + /// NotImplementedException + public Task ExistAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 获取单个字典目录 + /// + /// NotImplementedException + public Task GetAsync(QueryDicCatalogReq req) + { + throw new NotImplementedException(); + } + + /// + /// 分页查询字典目录 + /// + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var list = await QueryInternal(req).Page(req.Page, req.PageSize).Count(out var total).ToListAsync(); + + return new PagedQueryRsp(req.Page, req.PageSize, total + , list.Adapt>()); + } + + /// + /// 查询字典目录 + /// + public async Task> QueryAsync(QueryReq req) + { + var ret = await QueryInternal(req).ToTreeListAsync(); + return ret.Adapt>(); + } + + /// + /// 更新字典目录 + /// + /// The_parent_node_does_not_exist + /// NetAdminUnexpectedException + public async Task UpdateAsync(UpdateDicCatalogReq req) + { + if (req.ParentId != 0 && !await Rpo.Select.Where(a => a.Id == req.ParentId).ForUpdate().AnyAsync()) { + throw new NetAdminInvalidOperationException(Ln.父节点不存在); + } + + if (await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync() <= 0) { + throw new NetAdminUnexpectedException(); + } + + var ret = await Rpo.Select.Where(a => a.Id == req.Id).ToOneAsync(); + return ret.Adapt(); + } + + private ISelect QueryInternal(QueryReq req) + { + return Rpo.Select.WhereDynamicFilter(req.DynamicFilter) + .WhereDynamic(req.Filter) + .OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending) + .OrderByDescending(a => a.Id); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicContentService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicContentService.cs new file mode 100644 index 00000000..05a7c70f --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicContentService.cs @@ -0,0 +1,122 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Content; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class DicContentService : RepositoryService, IDicContentService +{ + /// + /// Initializes a new instance of the class. + /// + public DicContentService(Repository rpo) // + : base(rpo) { } + + /// + /// 批量删除字典内容 + /// + public async Task BulkDeleteAsync(BulkReq req) + { + var sum = 0; + foreach (var item in req.Items) { + sum += await DeleteAsync(item); + } + + return sum; + } + + /// + /// 创建字典内容 + /// + /// Dictionary_directory_does_not_exist + public async Task CreateAsync(CreateDicContentReq req) + { + if (!await Rpo.Orm.Select().Where(a => a.Id == req.CatalogId).ForUpdate().AnyAsync()) { + throw new NetAdminInvalidOperationException(Ln.字典目录不存在); + } + + var ret = await Rpo.InsertAsync(req); + return ret.Adapt(); + } + + /// + /// 删除字典内容 + /// + public Task DeleteAsync(DelReq req) + { + return Rpo.DeleteAsync(a => a.Id == req.Id); + } + + /// + /// 判断字典是否存在 + /// + /// NotImplementedException + public Task ExistAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 获取单个字典 + /// + /// NotImplementedException + public Task GetAsync(QueryDicContentReq req) + { + throw new NotImplementedException(); + } + + /// + /// 分页查询字典内容 + /// + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var list = await QueryInternal(req).Page(req.Page, req.PageSize).Count(out var total).ToListAsync(); + + return new PagedQueryRsp(req.Page, req.PageSize, total + , list.Adapt>()); + } + + /// + /// 查询字典内容 + /// + public async Task> QueryAsync(QueryReq req) + { + var ret = await QueryInternal(req).Take(req.Count).ToListAsync(); + return ret.Adapt>(); + } + + /// + /// 更新字典内容 + /// + /// Dictionary_directory_does_not_exist + /// NetAdminUnexpectedException + public async Task UpdateAsync(UpdateDicContentReq req) + { + if (!await Rpo.Orm.Select().Where(a => a.Id == req.CatalogId).ForUpdate().AnyAsync()) { + throw new NetAdminInvalidOperationException(Ln.字典目录不存在); + } + + if (await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync() <= 0) { + throw new NetAdminUnexpectedException(); + } + + var ret = await Rpo.Select.Where(a => a.Id == req.Id).ToOneAsync(); + return ret.Adapt(); + } + + private ISelect QueryInternal(QueryReq req) + { + var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter) + .WhereDynamic(req.Filter) + .OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); + if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { + ret = ret.OrderByDescending(a => a.Id); + } + + return ret; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicService.cs new file mode 100644 index 00000000..a941f06e --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/DicService.cs @@ -0,0 +1,119 @@ +using NetAdmin.Application.Services; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Catalog; +using NetAdmin.Domain.Dto.Sys.Dic.Content; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class DicService : ServiceBase, IDicService +{ + private readonly IDicCatalogService _catalogService; + private readonly IDicContentService _contentService; + + /// + /// Initializes a new instance of the class. + /// + public DicService(IDicCatalogService catalogService, IDicContentService contentService) + { + _catalogService = catalogService; + _contentService = contentService; + } + + /// + /// 批量删除字典目录 + /// + public Task BulkDeleteCatalogAsync(BulkReq req) + { + return _catalogService.BulkDeleteAsync(req); + } + + /// + /// 批量删除字典内容 + /// + public Task BulkDeleteContentAsync(BulkReq req) + { + return _contentService.BulkDeleteAsync(req); + } + + /// + /// 创建字典目录 + /// + public Task CreateCatalogAsync(CreateDicCatalogReq req) + { + return _catalogService.CreateAsync(req); + } + + /// + /// 创建字典内容 + /// + public Task CreateContentAsync(CreateDicContentReq req) + { + return _contentService.CreateAsync(req); + } + + /// + /// 删除字典目录 + /// + public Task DeleteCatalogAsync(DelReq req) + { + return _catalogService.DeleteAsync(req); + } + + /// + /// 删除字典内容 + /// + public Task DeleteContentAsync(DelReq req) + { + return _contentService.DeleteAsync(req); + } + + /// + /// 分页查询字典目录 + /// + public Task> PagedQueryCatalogAsync(PagedQueryReq req) + { + return _catalogService.PagedQueryAsync(req); + } + + /// + /// 分页查询字典内容 + /// + public Task> PagedQueryContentAsync(PagedQueryReq req) + { + return _contentService.PagedQueryAsync(req); + } + + /// + /// 查询字典目录 + /// + public Task> QueryCatalogAsync(QueryReq req) + { + return _catalogService.QueryAsync(req); + } + + /// + /// 查询字典内容 + /// + public Task> QueryContentAsync(QueryReq req) + { + return _contentService.QueryAsync(req); + } + + /// + /// 更新字典目录 + /// + public Task UpdateCatalogAsync(UpdateDicCatalogReq req) + { + return _catalogService.UpdateAsync(req); + } + + /// + /// 更新字典内容 + /// + public Task UpdateContentAsync(UpdateDicContentReq req) + { + return _contentService.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/FileService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/FileService.cs new file mode 100644 index 00000000..872bf1cf --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/FileService.cs @@ -0,0 +1,47 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class FileService : ServiceBase, IFileService +{ + private readonly MinioHelper _minioHelper; + private readonly UploadOptions _uploadOptions; + + /// + /// Initializes a new instance of the class. + /// + public FileService(IOptions uploadOptions, MinioHelper minioHelper) // + { + _minioHelper = minioHelper; + _uploadOptions = uploadOptions.Value; + } + + /// + /// 文件上传 + /// + /// 文件不能为空 + /// 允许上传的文件格式 + /// 允许的文件大小 + public async Task UploadAsync(IFormFile file) + { + if (file == null || file.Length < 1) { + throw new NetAdminInvalidOperationException(Ln.文件不能为空); + } + + if (!_uploadOptions.ContentTypes.Contains(file.ContentType)) { + throw new NetAdminInvalidOperationException( + $"{Ln.允许的文件格式} {string.Join(",", _uploadOptions.ContentTypes)}"); + } + + if (file.Length > _uploadOptions.MaxSize) { + throw new NetAdminInvalidOperationException($"{Ln.允许的文件大小} {_uploadOptions.MaxSize}"); + } + + var fileName = $"{Guid.NewGuid()}{Path.GetExtension(file.FileName)}"; + var objectName = $"{UserToken.Id}/{fileName}"; + await using var fs = file.OpenReadStream(); + return await _minioHelper.UploadAsync(objectName, fs, file.ContentType, file.Length); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/MenuService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/MenuService.cs new file mode 100644 index 00000000..a7c942c8 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/MenuService.cs @@ -0,0 +1,144 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Menu; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class MenuService : RepositoryService, IMenuService +{ + private readonly IUserService _userService; + + /// + /// Initializes a new instance of the class. + /// + public MenuService(Repository rpo, IUserService userService) // + : base(rpo) + { + _userService = userService; + } + + /// + /// 批量删除菜单 + /// + public async Task BulkDeleteAsync(BulkReq req) + { + var sum = 0; + foreach (var item in req.Items) { + sum += await DeleteAsync(item); + } + + return sum; + } + + /// + /// 创建菜单 + /// + public async Task CreateAsync(CreateMenuReq req) + { + var ret = await Rpo.InsertAsync(req); + return ret.Adapt(); + } + + /// + /// 删除菜单 + /// + public Task DeleteAsync(DelReq req) + { + return Rpo.DeleteAsync(a => a.Id == req.Id); + } + + /// + /// 判断菜单是否存在 + /// + /// NotImplementedException + public Task ExistAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 获取单个菜单 + /// + /// NotImplementedException + public Task GetAsync(QueryMenuReq req) + { + throw new NotImplementedException(); + } + + /// + /// 分页查询菜单 + /// + /// NotImplementedException + public Task> PagedQueryAsync(PagedQueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 查询菜单 + /// + public async Task> QueryAsync(QueryReq req) + { + var ret = await QueryInternal(req).ToTreeListAsync(); + return ret.Adapt>(); + } + + /// + /// 更新菜单 + /// + /// NetAdminUnexpectedException + public async Task UpdateAsync(UpdateMenuReq req) + { + if (await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync() <= 0) { + throw new NetAdminUnexpectedException(); + } + + var ret = await Rpo.Select.Where(a => a.Id == req.Id).ToOneAsync(); + return ret.Adapt(); + } + + /// + /// 当前用户菜单 + /// + public async Task> UserMenusAsync() + { + var userInfo = await _userService.UserInfoAsync(); + Task> ret; + var req = new QueryReq(); + + if (userInfo.Roles.Any(x => x.IgnorePermissionControl)) { + // 忽略权限控制 + ret = QueryAsync(req); + } + else { + var ownedMenuIds = userInfo.Roles.SelectMany(x => x.MenuIds); + if (ownedMenuIds.NullOrEmpty()) { + ownedMenuIds = new[] { 0L }; + } + + ret = QueryAsync(req with { + DynamicFilter = new DynamicFilterInfo { + Field = nameof(QueryMenuReq.Id) + , Operator = DynamicFilterOperator.Any + , Value = ownedMenuIds + } + }); + } + + return await ret; + } + + private ISelect QueryInternal(QueryReq req) + { + return Rpo.Select.WhereDynamicFilter(req.DynamicFilter) + .WhereDynamic(req.Filter) + .OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending) + .OrderByDescending(a => a.Sort) + .OrderBy(a => a.Name) + .OrderBy(a => a.Id); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogService.cs new file mode 100644 index 00000000..6b51c822 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RequestLogService.cs @@ -0,0 +1,125 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.RequestLog; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class RequestLogService : RepositoryService, IRequestLogService +{ + /// + /// Initializes a new instance of the class. + /// + public RequestLogService(Repository rpo) // + : base(rpo) { } + + /// + /// 批量删除请求日志 + /// + public async Task BulkDeleteAsync(BulkReq req) + { + var sum = 0; + foreach (var item in req.Items) { + sum += await DeleteAsync(item); + } + + return sum; + } + + /// + /// 创建请求日志 + /// + public async Task CreateAsync(CreateRequestLogReq req) + { + var ret = await Rpo.InsertAsync(req); + return ret.Adapt(); + } + + /// + /// 删除请求日志 + /// + /// NotImplementedException + public Task DeleteAsync(DelReq req) + { + throw new NotImplementedException(); + } + + /// + /// 判断请求日志是否存在 + /// + /// NotImplementedException + public Task ExistAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 获取单个请求日志 + /// + /// NotImplementedException + public Task GetAsync(QueryRequestLogReq req) + { + throw new NotImplementedException(); + } + + /// + /// 分页查询请求日志 + /// + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var list = await QueryInternal(req) + .Page(req.Page, req.PageSize) + .Count(out var total) + .ToListAsync(a => new { + a.ApiId + , ApiSummary = a.Api.Summary + , a.ExtraData + , a.CreatedClientIp + , a.CreatedTime + , a.CreatedUserName + , a.Duration + , a.Method + , a.CreatedUserAgent + , a.HttpStatusCode + , a.Id + }); + + return new PagedQueryRsp(req.Page, req.PageSize, total + , list.Adapt>()); + } + + /// + /// 查询请求日志 + /// + public async Task> QueryAsync(QueryReq req) + { + var ret = await QueryInternal(req).Take(req.Count).ToListAsync(); + return ret.Adapt>(); + } + + /// + /// 更新请求日志 + /// + /// NotImplementedException + public Task UpdateAsync(NopReq req) + { + throw new NotImplementedException(); + } + + private ISelect QueryInternal(QueryReq req) + { + var ret = Rpo.Select.Include(a => a.Api) + .WhereDynamicFilter(req.DynamicFilter) + .WhereDynamic(req.Filter) + .OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); + + if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) { + ret = ret.OrderByDescending(a => a.CreatedTime); + } + + return ret; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RoleService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RoleService.cs new file mode 100644 index 00000000..3bd1db68 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/RoleService.cs @@ -0,0 +1,133 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Role; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class RoleService : RepositoryService, IRoleService +{ + /// + /// Initializes a new instance of the class. + /// + public RoleService(Repository rpo) // + : base(rpo) { } + + /// + /// 批量删除角色 + /// + public async Task BulkDeleteAsync(BulkReq req) + { + var sum = 0; + foreach (var item in req.Items) { + sum += await DeleteAsync(item); + } + + return sum; + } + + /// + /// 创建角色 + /// + public async Task CreateAsync(CreateRoleReq req) + { + var entity = req.Adapt(); + var ret = await Rpo.InsertAsync(entity); + + await Rpo.SaveManyAsync(entity, nameof(entity.Depts)); + await Rpo.SaveManyAsync(entity, nameof(entity.Menus)); + await Rpo.SaveManyAsync(entity, nameof(entity.Apis)); + + entity = entity with { Id = ret.Id }; + return entity.Adapt(); + } + + /// + /// 删除角色 + /// + /// Users_exist_under_this_role_and_deletion_is_not_allowed + public async Task DeleteAsync(DelReq req) + { + return await Rpo.Orm.Select().ForUpdate().AnyAsync(a => a.RoleId == req.Id) + ? throw new NetAdminInvalidOperationException(Ln.该角色下存在用户) + : await Rpo.DeleteAsync(a => a.Id == req.Id); + } + + /// + /// 判断角色是否存在 + /// + /// NotImplementedException + public Task ExistAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 获取单个角色 + /// + /// NotImplementedException + public Task GetAsync(QueryRoleReq req) + { + throw new NotImplementedException(); + } + + /// + /// 分页查询角色 + /// + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var list = await QueryInternal(req).Page(req.Page, req.PageSize).Count(out var total).ToListAsync(); + + return new PagedQueryRsp(req.Page, req.PageSize, total, list.Adapt>()); + } + + /// + /// 查询角色 + /// + public async Task> QueryAsync(QueryReq req) + { + var ret = await QueryInternal(req).ToListAsync(); + return ret.Adapt>(); + } + + /// + /// 更新角色 + /// + public async Task UpdateAsync(UpdateRoleReq req) + { + var entity = req.Adapt(); + _ = await Rpo.UpdateAsync(entity); + await Rpo.SaveManyAsync(entity, nameof(entity.Depts)); + await Rpo.SaveManyAsync(entity, nameof(entity.Menus)); + await Rpo.SaveManyAsync(entity, nameof(entity.Apis)); + + return (await QueryAsync(new QueryReq { Filter = new QueryRoleReq { Id = req.Id } })).First(); + } + + private ISelect QueryInternal(QueryReq req) + { + var ret = Rpo.Select.IncludeMany(a => a.Depts.Select(b => new Sys_Dept { Id = b.Id })) + .IncludeMany(a => a.Menus.Select(b => new Sys_Menu { Id = b.Id })) + .IncludeMany(a => a.Apis.Select(b => new Sys_Api { Id = b.Id })) + .WhereDynamicFilter(req.DynamicFilter) + .WhereDynamic(req.Filter) + .WhereIf( // + req.Keywords?.Length > 0 + , a => a.Name.Contains(req.Keywords) || a.Summary.Contains(req.Keywords) || + a.Id == req.Keywords.Int64Try(0)) + .OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); + + if (!req.Prop?.Equals(nameof(req.Filter.Sort), StringComparison.OrdinalIgnoreCase) ?? true) { + ret = ret.OrderByDescending(a => a.Sort); + } + + if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) { + ret = ret.OrderByDescending(a => a.CreatedTime); + } + + return ret; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ToolsService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ToolsService.cs new file mode 100644 index 00000000..00d27f5a --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/ToolsService.cs @@ -0,0 +1,24 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class ToolsService : ServiceBase, IToolsService +{ + /// + /// 服务器时间 + /// + public DateTime GetServerUtcTime() + { + return DateTime.UtcNow; + } + + /// + /// 版本信息 + /// + public string Version() + { + return Global.ProductVersion; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserProfileService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserProfileService.cs new file mode 100644 index 00000000..8ca8926c --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserProfileService.cs @@ -0,0 +1,171 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Content; +using NetAdmin.Domain.Dto.Sys.UserProfile; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using DataType = FreeSql.DataType; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class UserProfileService : RepositoryService, IUserProfileService +{ + /// + /// Initializes a new instance of the class. + /// + public UserProfileService(Repository rpo) // + : base(rpo) { } + + /// + /// 批量删除用户档案 + /// + public async Task BulkDeleteAsync(BulkReq req) + { + var sum = 0; + foreach (var item in req.Items) { + sum += await DeleteAsync(item); + } + + return sum; + } + + /// + /// 创建用户档案 + /// + public async Task CreateAsync(CreateUserProfileReq req) + { + var entity = req.Adapt(); + var ret = await Rpo.InsertAsync(entity); + return ret.Adapt(); + } + + /// + /// 删除用户档案 + /// + public Task DeleteAsync(DelReq req) + { + return Rpo.DeleteAsync(a => a.Id == req.Id); + } + + /// + /// 判断用户档案是否存在 + /// + /// NotImplementedException + public Task ExistAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 获取单个用户档案 + /// + /// NotImplementedException + public async Task GetAsync(QueryUserProfileReq req) + { + var ret = await QueryInternal(new QueryReq { Filter = req }).ToOneAsync(); + return ret.Adapt(); + } + + /// + /// 分页查询用户档案 + /// + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var list = await QueryInternal(req) + .Page(req.Page, req.PageSize) + .Count(out var total) + .ToListAsync((a, b, c, d, e) => new { + a + , b = new { b.Key, b.Value } + , c = new { c.Key, c.Value } + , d = new { d.Key, d.Value } + , e = new { e.Key, e.Value } + }); + + return new PagedQueryRsp(req.Page, req.PageSize, total + , list.ConvertAll( + x => x.a.Adapt() with { + NationArea = x.b.Adapt() + , CompanyArea = x.c.Adapt() + , HomeArea = x.d.Adapt() + , EmergencyContactArea + = x.e.Adapt() + })); + } + + /// + /// 查询用户档案 + /// + public async Task> QueryAsync(QueryReq req) + { + var ret = await QueryInternal(req) + .Take(req.Count) + .ToListAsync((a, b, c, d, e) => new { + a + , b = new { b.Key, b.Value } + , c = new { c.Key, c.Value } + , d = new { d.Key, d.Value } + , e = new { e.Key, e.Value } + }); + return ret.ConvertAll(x => x.a.Adapt() with { + NationArea + = x.b.Key == null + ? null + : x.b.Adapt() + , CompanyArea + = x.c.Key == null + ? null + : x.c.Adapt() + , HomeArea + = x.d.Key == null + ? null + : x.d.Adapt() + , EmergencyContactArea = x.e.Key == null + ? null + : x.e.Adapt() + }); + } + + /// + /// 更新用户档案 + /// + public async Task UpdateAsync(UpdateUserProfileReq req) + { + var entity = req.Adapt(); + if (Rpo.Orm.Ado.DataType == DataType.Sqlite) { + return await UpdateForSqliteAsync(entity); + } + + var ret = await Rpo.UpdateDiy.SetSource(entity).ExecuteUpdatedAsync(); + return ret.FirstOrDefault()?.Adapt(); + } + + private ISelect QueryInternal( + QueryReq req) + { + return Rpo.Orm.Select() + .LeftJoin((a, b, _, __, ___) => + a.NationArea.ToString() == b.Value && b.CatalogId == Numbers.DIC_CATALOG_ID_GEO_AREA) + .LeftJoin((a, _, c, __, ___) => + a.CompanyArea.ToString() == c.Value && c.CatalogId == Numbers.DIC_CATALOG_ID_GEO_AREA) + .LeftJoin((a, _, __, d, ___) => + a.HomeArea.ToString() == d.Value && d.CatalogId == Numbers.DIC_CATALOG_ID_GEO_AREA) + .LeftJoin((a, _, __, ___, e) => a.EmergencyContactArea.ToString() == e.Value && + e.CatalogId == Numbers.DIC_CATALOG_ID_GEO_AREA) + .WhereDynamicFilter(req.DynamicFilter) + .OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending) + .OrderByDescending((a, _, __, ___, ____) => a.Id); + } + + /// + /// 非sqlite数据库请删掉 + /// + private async Task UpdateForSqliteAsync(Sys_UserProfile req) + { + return await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync() <= 0 + ? null + : await GetAsync(new QueryUserProfileReq { Id = req.Id }); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs new file mode 100644 index 00000000..20a1066f --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/UserService.cs @@ -0,0 +1,487 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.Attributes.DataValidation; +using NetAdmin.Domain.Contexts; +using NetAdmin.Domain.DbMaps.Dependency.Fields; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.User; +using NetAdmin.Domain.Dto.Sys.UserProfile; +using NetAdmin.Domain.Dto.Sys.VerifyCode; +using NetAdmin.Domain.Events.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class UserService : RepositoryService, IUserService +{ + private readonly IEventPublisher _eventPublisher; + + private readonly Expression> _selectUserFields = a => new Sys_User { + Id = a.Id + , Avatar = a.Avatar + , Email = a.Email + , Mobile = a.Mobile + , Enabled = a.Enabled + , UserName = a.UserName + , Summary = a.Summary + , Version = a.Version + , CreatedTime = a.CreatedTime + , Dept = new Sys_Dept { Id = a.Dept.Id, Name = a.Dept.Name } + , Roles = a.Roles + }; + + private readonly IUserProfileService _userProfileService; + + private readonly IVerifyCodeService _verifyCodeService; + + /// + /// Initializes a new instance of the class. + /// + public UserService(Repository rpo, IUserProfileService userProfileService + , IVerifyCodeService verifyCodeService, IEventPublisher eventPublisher) // + : base(rpo) + { + _userProfileService = userProfileService; + _verifyCodeService = verifyCodeService; + _eventPublisher = eventPublisher; + } + + /// + /// 批量删除用户 + /// + public async Task BulkDeleteAsync(BulkReq req) + { + var sum = 0; + foreach (var item in req.Items) { + sum += await DeleteAsync(item); + } + + return sum; + } + + /// + /// 检查手机号是否可用 + /// + public async Task CheckMobileAvailableAsync(CheckMobileAvailableReq req) + { + return !await Rpo.Select.Where(a => a.Mobile == req.Mobile && a.Id != req.Id).AnyAsync(); + } + + /// + /// 检查用户名是否可用 + /// + public async Task CheckUserNameAvailableAsync(CheckUserNameAvailableReq req) + { + return !await Rpo.Select.Where(a => a.UserName == req.UserName && a.Id != req.Id).AnyAsync(); + } + + /// + /// 创建用户 + /// + public async Task CreateAsync(CreateUserReq req) + { + await CreateUpdateCheckAsync(req); + + // 主表 + var entity = req.Adapt(); + var dbUser = await Rpo.InsertAsync(entity); + + // 分表 + await Rpo.SaveManyAsync(entity, nameof(entity.Roles)); + + // 档案表 + _ = await _userProfileService.CreateAsync(req.Profile with { Id = dbUser.Id }); + var ret = await QueryAsync(new QueryReq { Filter = new QueryUserReq { Id = dbUser.Id } }); + return ret.First(); + } + + /// + /// 删除用户 + /// + public async Task DeleteAsync(DelReq req) + { + var effect = 0; + + // 删除主表 + effect += await Rpo.DeleteAsync(req.Id); + + // 删除分表 + effect += await Rpo.Orm.Delete(new { UserId = req.Id }).ExecuteAffrowsAsync(); + + // 删除档案表 + effect += await _userProfileService.DeleteAsync(req); + + return effect; + } + + /// + /// 判断用户是否存在 + /// + public async Task ExistAsync(QueryReq req) + { + return await (await QueryInternalAsync(req)).AnyAsync(); + } + + /// + /// 获取单个用户 + /// + /// NotImplementedException + public Task GetAsync(QueryUserReq req) + { + throw new NotImplementedException(); + } + + /// + /// 获取单个用户(带更新锁) + /// + public async Task GetForUpdateAsync(QueryUserReq req) + { + // ReSharper disable once MethodHasAsyncOverload + return (await QueryInternal(new QueryReq { Filter = req }).ForUpdate().ToOneAsync()) + .Adapt(); + } + + /// + /// 密码登录 + /// + /// 用户名或密码错误 + public async Task LoginByPwdAsync(LoginByPwdReq req) + { + var pwd = req.Password.Pwd().Guid(); + + Sys_User dbUser; + #pragma warning disable IDE0045 + if (new MobileAttribute().IsValid(req.Account)) { + #pragma warning restore IDE0045 + dbUser = await Rpo.GetAsync(a => a.Mobile == req.Account && a.Password == pwd); + } + else { + dbUser = new EmailAddressAttribute().IsValid(req.Account) + ? await Rpo.GetAsync(a => a.Email == req.Account && a.Password == pwd) + : await Rpo.GetAsync(a => a.UserName == req.Account && a.Password == pwd); + } + + return dbUser == null ? throw new NetAdminInvalidOperationException(Ln.用户名或密码错误) : LoginInternal(dbUser); + } + + /// + /// 短信登录 + /// + /// 验证码不正确 + /// 用户不存在 + public async Task LoginBySmsAsync(LoginBySmsReq req) + { + if (!await _verifyCodeService.VerifyAsync(req.Adapt())) { + throw new NetAdminInvalidOperationException(Ln.验证码不正确); + } + + var dbUser = await Rpo.GetAsync(a => a.Mobile == req.DestDevice); + return dbUser == null ? throw new NetAdminInvalidOperationException(Ln.用户不存在) : LoginInternal(dbUser); + } + + /// + /// 分页查询用户 + /// + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var list = await (await QueryInternalAsync(req)).Page(req.Page, req.PageSize) + .Count(out var total) + .ToListAsync(_selectUserFields); + return new PagedQueryRsp(req.Page, req.PageSize, total, list.Adapt>()); + } + + /// + /// 查询用户 + /// + public async Task> QueryAsync(QueryReq req) + { + var list = await (await QueryInternalAsync(req)).Take(req.Count).ToListAsync(_selectUserFields); + return list.Adapt>(); + } + + /// + /// 查询用户档案 + /// + public Task> QueryProfileAsync(QueryReq req) + { + return _userProfileService.QueryAsync(req); + } + + /// + /// 注册用户 + /// + /// 验证码不正确 + public async Task RegisterAsync(RegisterUserReq req) + { + if (!await _verifyCodeService.VerifyAsync(req.VerifySmsCodeReq)) { + throw new NetAdminInvalidOperationException(Ln.验证码不正确); + } + + var createReq = req.Adapt() with { Profile = new CreateUserProfileReq() }; + return (await CreateAsync(createReq)).Adapt(); + } + + /// + /// 重设密码 + /// + /// 验证码不正确 + /// 用户不存在 + public async Task ResetPasswordAsync(ResetPasswordReq req) + { + return !await _verifyCodeService.VerifyAsync(req.VerifySmsCodeReq) + ? throw new NetAdminInvalidOperationException(Ln.验证码不正确) + : (uint)await Rpo.UpdateDiy + .SetSource((await Rpo.Where(a => a.Mobile == req.VerifySmsCodeReq.DestDevice) + .ToOneAsync(a => new { a.Version, a.Id })).Adapt() with { + Password = req.PasswordText.Pwd().Guid() + }) + .UpdateColumns(a => a.Password) + .ExecuteAffrowsAsync(); + } + + /// + public async Task SetAvatarAsync(SetAvatarReq req) + { + if (await Rpo.UpdateDiy + .SetSource(req with { + Id = UserToken.Id + , Version = Rpo.Where(a => a.Id == UserToken.Id).ToOne(a => a.Version) + }) + .UpdateColumns(a => a.Avatar) + .ExecuteAffrowsAsync() <= 0) { + throw new NetAdminUnexpectedException(); + } + + var ret = (await QueryAsync(new QueryReq { Filter = new QueryUserReq { Id = UserToken.Id } })) + .First() + .Adapt(); + + // 发布用户更新事件 + await _eventPublisher.PublishAsync(new UserUpdatedEvent(ret)); + return ret; + } + + /// + public async Task SetEmailAsync(SetEmailReq req) + { + var user = Rpo.Where(a => a.Id == UserToken.Id).ToOne(a => new { a.Mobile, a.Version, a.Email }); + + // 如果已绑定手机号、需要手机安全验证 + if (!user.Mobile.NullOrEmpty()) { + if (!await _verifyCodeService.VerifyAsync(req.VerifySmsCodeReq)) { + throw new NetAdminInvalidOperationException(Ln.验证码不正确); + } + + if (user.Mobile != req.VerifySmsCodeReq.DestDevice) { + throw new NetAdminInvalidOperationException($"{Ln.手机号码} {Ln.不正确}"); + } + } + + if (await Rpo.UpdateDiy + .SetSource(new Sys_User { Email = req.DestDevice, Id = UserToken.Id, Version = user.Version }) + .UpdateColumns(a => a.Email) + .ExecuteAffrowsAsync() <= 0) { + throw new NetAdminUnexpectedException(); + } + + var ret = (await QueryAsync(new QueryReq { Filter = new QueryUserReq { Id = UserToken.Id } })) + .First() + .Adapt(); + + // 发布用户更新事件 + await _eventPublisher.PublishAsync(new UserUpdatedEvent(ret)); + return ret; + } + + /// + public async Task SetMobileAsync(SetMobileReq req) + { + var user = await Rpo.Where(a => a.Id == UserToken.Id).ToOneAsync(a => new { a.Version, a.Mobile }); + + if (!user.Mobile.NullOrEmpty()) { + // 已有手机号,需验证旧手机 + if (!await _verifyCodeService.VerifyAsync(req.OriginVerifySmsCodeReq)) { + throw new NetAdminInvalidOperationException($"{Ln.旧手机号码} {Ln.验证码不正确}"); + } + + if (user.Mobile != req.OriginVerifySmsCodeReq.DestDevice) { + throw new NetAdminInvalidOperationException($"{Ln.旧手机号码} {Ln.不正确}"); + } + } + + // 验证新手机号 + if (!await _verifyCodeService.VerifyAsync(req.NewVerifySmsCodeReq)) { + throw new NetAdminInvalidOperationException($"{Ln.新手机号码} {Ln.验证码不正确}"); + } + + if (await Rpo.UpdateDiy + .SetSource(new Sys_User { + Version = user.Version + , Id = UserToken.Id + , Mobile = req.NewVerifySmsCodeReq.DestDevice + }) + .UpdateColumns(a => a.Mobile) + .ExecuteAffrowsAsync() <= 0) { + throw new NetAdminUnexpectedException(); + } + + var ret = (await QueryAsync(new QueryReq { Filter = new QueryUserReq { Id = UserToken.Id } })) + .First() + .Adapt(); + + // 发布用户更新事件 + await _eventPublisher.PublishAsync(new UserUpdatedEvent(ret)); + return ret; + } + + /// + public async Task SetPasswordAsync(SetPasswordReq req) + { + var version = await Rpo.Where(a => a.Id == UserToken.Id && a.Password == req.OldPassword.Pwd().Guid()) + .ToOneAsync(a => new long?(a.Version)); + if (version == null) { + throw new NetAdminInvalidInputException($"{Ln.旧密码} {Ln.不正确}"); + } + + var ret = await Rpo.UpdateDiy + .SetSource(new Sys_User { + Id = UserToken.Id + , Password = req.NewPassword.Pwd().Guid() + , Version = version.Value + }) + .UpdateColumns(a => a.Password) + .ExecuteAffrowsAsync(); + return ret <= 0 ? throw new NetAdminUnexpectedException() : (uint)ret; + } + + /// + /// 更新用户 + /// + public async Task UpdateAsync(UpdateUserReq req) + { + await CreateUpdateCheckAsync(req); + + // 主表 + var entity = req.Adapt(); + var ignoreCols = new List { nameof(Sys_User.Token) }; + if (entity.Password == Guid.Empty) { + ignoreCols.Add(nameof(Sys_User.Password)); + } + + _ = await Rpo.UpdateDiy.SetSource(entity).IgnoreColumns(ignoreCols.ToArray()).ExecuteAffrowsAsync(); + + // 档案表 + _ = await _userProfileService.UpdateAsync(req.Profile); + + // 分表 + await Rpo.SaveManyAsync(entity, nameof(entity.Roles)); + + var ret = (await QueryAsync(new QueryReq { Filter = new QueryUserReq { Id = req.Id } })).First(); + + // 发布用户更新事件 + await _eventPublisher.PublishAsync(new UserUpdatedEvent(ret.Adapt())); + return ret; + } + + /// + /// 单体更新 + /// + public Task UpdateSingleAsync(UpdateUserReq req) + { + return Rpo.UpdateAsync(req); + } + + /// + /// 当前用户信息 + /// + public async Task UserInfoAsync() + { + var dbUser = await Rpo.Where(a => a.Token == UserToken.Token && a.Enabled) + .Include(a => a.Dept) + .IncludeMany( // + a => a.Roles + , then => then.Where(a => a.Enabled) + .IncludeMany(a => a.Menus) + .IncludeMany(a => a.Depts) + .IncludeMany(a => a.Apis)) + .ToOneAsync(); + return dbUser.Adapt(); + } + + private static LoginRsp LoginInternal(IFieldEnabled dbUser) + { + if (!dbUser.Enabled) { + throw new NetAdminInvalidOperationException(Ln.请联系管理员激活账号); + } + + var tokenPayload + = new Dictionary { { nameof(ContextUserToken), dbUser.Adapt() } }; + + var accessToken = JWTEncryption.Encrypt(tokenPayload); + return new LoginRsp { + AccessToken = accessToken + , RefreshToken = JWTEncryption.GenerateRefreshToken(accessToken) + }; + } + + private async Task CreateUpdateCheckAsync(CreateUpdateUserReq req) + { + // 检查角色是否存在 + var roles = await Rpo.Orm.Select() + .ForUpdate() + .Where(a => req.RoleIds.Contains(a.Id)) + .ToListAsync(a => a.Id); + if (roles.Count != req.RoleIds.Count) { + throw new NetAdminInvalidOperationException(Ln.角色不存在); + } + + // 检查部门是否存在 + var dept = await Rpo.Orm.Select().ForUpdate().Where(a => req.DeptId == a.Id).ToListAsync(a => a.Id); + + if (dept.Count != 1) { + throw new NetAdminInvalidOperationException(Ln.部门不存在); + } + } + + private ISelect QueryInternal(QueryReq req) + { + return Rpo.Select.WhereDynamicFilter(req.DynamicFilter) + .WhereDynamic(req.Filter) + .OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending) + .OrderByDescending(a => a.Id); + } + + private async Task> QueryInternalAsync(QueryReq req) + { + IEnumerable deptIds = null; + if (req.Filter?.DeptId > 0) { + deptIds = await Rpo.Orm.Select() + .Where(a => a.Id == req.Filter.DeptId) + .AsTreeCte() + .ToListAsync(a => a.Id); + } + + var ret = Rpo.Select.Include(a => a.Dept) + .IncludeMany(a => a.Roles.Select(b => new Sys_Role { Id = b.Id, Name = b.Name })) + .WhereDynamicFilter(req.DynamicFilter) + .WhereIf(deptIds != null, a => deptIds.Contains(a.DeptId)) + .WhereIf( // + req.Filter?.Id > 0, a => a.Id == req.Filter.Id) + .WhereIf( // + req.Filter?.RoleId > 0, a => a.Roles.Any(b => b.Id == req.Filter.RoleId)) + .WhereIf( // + req.Keywords?.Length > 0 + , a => a.UserName.Contains(req.Keywords) || a.Id == req.Keywords.Int64Try(0) || + a.Mobile.Contains(req.Keywords) || a.Email.Contains(req.Keywords) || + a.Summary.Contains(req.Keywords)) + .OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); + + if (!req.Prop?.Equals(nameof(req.Filter.CreatedTime), StringComparison.OrdinalIgnoreCase) ?? true) { + ret = ret.OrderByDescending(a => a.CreatedTime); + } + + return ret; + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/VerifyCodeService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/VerifyCodeService.cs new file mode 100644 index 00000000..c8c9c00d --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/VerifyCodeService.cs @@ -0,0 +1,194 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.DbMaps.Sys; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.VerifyCode; +using NetAdmin.Domain.Enums.Sys; +using NetAdmin.Domain.Events.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using DataType = FreeSql.DataType; + +namespace NetAdmin.SysComponent.Application.Services.Sys; + +/// +public sealed class VerifyCodeService : RepositoryService, IVerifyCodeService +{ + private readonly IEventPublisher _eventPublisher; + + /// + /// Initializes a new instance of the class. + /// + public VerifyCodeService(Repository rpo, IEventPublisher eventPublisher) // + : base(rpo) + { + _eventPublisher = eventPublisher; + } + + /// + /// 批量删除验证码 + /// + public async Task BulkDeleteAsync(BulkReq req) + { + var sum = 0; + foreach (var item in req.Items) { + sum += await DeleteAsync(item); + } + + return sum; + } + + /// + /// 创建验证码 + /// + public async Task CreateAsync(CreateVerifyCodeReq req) + { + var entity = await Rpo.InsertAsync(req); + + var ret = entity.Adapt(); + + // 发布验证码创建事件 + await _eventPublisher.PublishAsync(new VerifyCodeCreatedEvent(ret)); + + return ret; + } + + /// + /// 删除验证码 + /// + public Task DeleteAsync(DelReq req) + { + return Rpo.DeleteAsync(a => a.Id == req.Id); + } + + /// + /// 判断验证码是否存在 + /// + public Task ExistAsync(QueryReq req) + { + return QueryInternal(req).AnyAsync(); + } + + /// + /// 获取单个验证码 + /// + public async Task GetAsync(QueryVerifyCodeReq req) + { + var ret = await QueryInternal(new QueryReq { Filter = req }).ToOneAsync(); + return ret.Adapt(); + } + + /// + /// 分页查询验证码 + /// + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var list = await QueryInternal(req).Page(req.Page, req.PageSize).Count(out var total).ToListAsync(); + + return new PagedQueryRsp(req.Page, req.PageSize, total + , list.Adapt>()); + } + + /// + /// 查询验证码 + /// + public async Task> QueryAsync(QueryReq req) + { + var ret = await QueryInternal(req).Take(req.Count).ToListAsync(); + return ret.Adapt>(); + } + + /// + public async Task SendVerifyCodeAsync(SendVerifyCodeReq req) + { + var lastSent = await GetLastSentAsync(req.DestDevice); + + QueryVerifyCodeRsp ret; + + #if !DEBUG + // 有发送记录,且小于1分钟,不允许 + if (lastSent != null && (DateTime.UtcNow - lastSent.CreatedTime).TotalMinutes < 1) { + throw new NetAdminInvalidOperationException(Ln._1分钟内只能发送1次); + } + #endif + + if (lastSent != null && lastSent.Status != VerifyCodeStatues.Verified) { // 上次发送未验证,生成相同code + ret = await CreateAsync(req.Adapt() with { Code = lastSent.Code }); + } + else { // 生成新的code + var code = new[] { 0, 10000 }.Rand().ToString(CultureInfo.InvariantCulture).PadLeft(4, '0'); + ret = await CreateAsync(req.Adapt() with { Code = code }); + } + + return ret.Adapt(); + } + + /// + /// 更新验证码 + /// + public async Task UpdateAsync(UpdateVerifyCodeReq req) + { + if (Rpo.Orm.Ado.DataType == DataType.Sqlite) { + return await UpdateForSqliteAsync(req); + } + + var ret = await Rpo.UpdateDiy.SetSource(req).ExecuteUpdatedAsync(); + return ret.FirstOrDefault()?.Adapt(); + } + + /// + public async Task VerifyAsync(VerifyCodeReq req) + { + #if DEBUG + if (req.Code == "8888") { + return true; + } + #endif + if (req.Code == Global.SecretKey) { + return true; + } + + var lastSent = await GetLastSentAsync(req.DestDevice); + + if (lastSent is not { Status: VerifyCodeStatues.Sent } || req.Code != lastSent.Code || + (DateTime.UtcNow - lastSent.CreatedTime).TotalMinutes > 10) { + return false; + } + + _ = await UpdateAsync((lastSent with { Status = VerifyCodeStatues.Verified }).Adapt()); + + return true; + } + + private Task GetLastSentAsync(string destDevice) + { + return QueryInternal(new QueryReq { + Count = 1 + , DynamicFilter + = new DynamicFilterInfo { + Field = nameof( + Sys_VerifyCode.DestDevice) + , Operator = DynamicFilterOperator.Eq + , Value = destDevice + } + }) + .ToOneAsync(); + } + + private ISelect QueryInternal(QueryReq req) + { + return Rpo.Select.WhereDynamicFilter(req.DynamicFilter) + .WhereDynamic(req.Filter) + .OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending) + .OrderByDescending(a => a.Id); + } + + /// + /// 非sqlite数据库请删掉 + /// + private async Task UpdateForSqliteAsync(Sys_VerifyCode req) + { + return await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync() <= 0 + ? null + : await GetAsync(new QueryVerifyCodeReq { Id = req.Id }); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/Dependency/IExampleService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/Dependency/IExampleService.cs new file mode 100644 index 00000000..6a74fa86 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/Dependency/IExampleService.cs @@ -0,0 +1,9 @@ +using NetAdmin.Application.Services; +using NetAdmin.SysComponent.Application.Modules.Tpl; + +namespace NetAdmin.SysComponent.Application.Services.Tpl.Dependency; + +/// +/// 示例服务 +/// +public interface IExampleService : IService, IExampleModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/ExampleService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/ExampleService.cs new file mode 100644 index 00000000..07956af2 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Tpl/ExampleService.cs @@ -0,0 +1,117 @@ +using NetAdmin.Application.Repositories; +using NetAdmin.Application.Services; +using NetAdmin.Domain.DbMaps.Tpl; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Tpl.Example; +using NetAdmin.SysComponent.Application.Services.Tpl.Dependency; +using DataType = FreeSql.DataType; + +namespace NetAdmin.SysComponent.Application.Services.Tpl; + +/// +public sealed class ExampleService : RepositoryService, IExampleService +{ + /// + /// Initializes a new instance of the class. + /// + public ExampleService(Repository rpo) // + : base(rpo) { } + + /// + /// 批量删除示例 + /// + public async Task BulkDeleteAsync(BulkReq req) + { + var sum = 0; + foreach (var item in req.Items) { + sum += await DeleteAsync(item); + } + + return sum; + } + + /// + /// 创建示例 + /// + public async Task CreateAsync(CreateExampleReq req) + { + var ret = await Rpo.InsertAsync(req); + return ret.Adapt(); + } + + /// + /// 删除示例 + /// + public Task DeleteAsync(DelReq req) + { + return Rpo.DeleteAsync(a => a.Id == req.Id); + } + + /// + /// 判断示例是否存在 + /// + public Task ExistAsync(QueryReq req) + { + return QueryInternal(req).AnyAsync(); + } + + /// + /// 获取单个示例 + /// + public async Task GetAsync(QueryExampleReq req) + { + var ret = await QueryInternal(new QueryReq { Filter = req }).ToOneAsync(); + return ret.Adapt(); + } + + /// + /// 分页查询示例 + /// + public async Task> PagedQueryAsync(PagedQueryReq req) + { + var list = await QueryInternal(req).Page(req.Page, req.PageSize).Count(out var total).ToListAsync(); + + return new PagedQueryRsp(req.Page, req.PageSize, total + , list.Adapt>()); + } + + /// + /// 查询示例 + /// + public async Task> QueryAsync(QueryReq req) + { + var ret = await QueryInternal(req).Take(req.Count).ToListAsync(); + return ret.Adapt>(); + } + + /// + /// 更新示例 + /// + public async Task UpdateAsync(UpdateExampleReq req) + { + if (Rpo.Orm.Ado.DataType == DataType.Sqlite) { + return await UpdateForSqliteAsync(req); + } + + var ret = await Rpo.UpdateDiy.SetSource(req).ExecuteUpdatedAsync(); + return ret.FirstOrDefault()?.Adapt(); + } + + private ISelect QueryInternal(QueryReq req) + { + return Rpo.Select.WhereDynamicFilter(req.DynamicFilter) + .WhereDynamic(req.Filter) + .OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending) + .OrderByDescending(a => a.Id); + } + + /// + /// 非sqlite数据库请删掉 + /// + private async Task UpdateForSqliteAsync(Tpl_Example req) + { + return await Rpo.UpdateDiy.SetSource(req).ExecuteAffrowsAsync() <= 0 + ? null + : await GetAsync(new QueryExampleReq { Id = req.Id }); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/NetAdmin.SysComponent.Cache.csproj b/src/backend/NetAdmin.SysComponent.Cache/NetAdmin.SysComponent.Cache.csproj new file mode 100644 index 00000000..fe98ed52 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/NetAdmin.SysComponent.Cache.csproj @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/ApiCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/ApiCache.cs new file mode 100644 index 00000000..0fece7e5 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/ApiCache.cs @@ -0,0 +1,73 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Api; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 接口缓存 +/// +public sealed class ApiCache : DistributedCache, IScoped, IApiCache +{ + /// + /// Initializes a new instance of the class. + /// + public ApiCache(IDistributedCache cache, IApiService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CreateAsync(CreateApiReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryApiReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task SyncAsync() + { + return Service.SyncAsync(); + } + + /// + public Task UpdateAsync(NopReq req) + { + return Service.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/CacheCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/CacheCache.cs new file mode 100644 index 00000000..532aefde --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/CacheCache.cs @@ -0,0 +1,32 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Cache; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 缓存缓存 +/// +public sealed class CacheCache : DistributedCache, IScoped, ICacheCache +{ + /// + /// Initializes a new instance of the class. + /// + public CacheCache(IDistributedCache cache, ICacheService service) // + : base(cache, service) { } + + /// + public Task CacheStatisticsAsync() + { + return GetOrCreateAsync( // + GetCacheKey(string.Empty), Service.CacheStatisticsAsync, TimeSpan.FromMinutes(1)); + } + + /// + public PagedQueryRsp GetAllEntries(PagedQueryReq req) + { + return Service.GetAllEntries(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/CaptchaCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/CaptchaCache.cs new file mode 100644 index 00000000..2167e619 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/CaptchaCache.cs @@ -0,0 +1,52 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Sys.Captcha; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +public sealed class CaptchaCache : DistributedCache, IScoped, ICaptchaCache +{ + /// + /// Initializes a new instance of the class. + /// + public CaptchaCache(IDistributedCache cache, ICaptchaService service) // + : base(cache, service) { } + + /// + /// 获取人机校验图 + /// + public async Task GetCaptchaImageAsync() + { + var captchaRsp = await Service.GetCaptchaImageAsync(); + await CreateAsync(GetCacheKey(captchaRsp.Id, nameof(CaptchaCache)), captchaRsp.SawOffsetX +, TimeSpan.FromMinutes(1)); + return captchaRsp; + } + + /// + /// 完成人机校验 ,并删除缓存项 + /// + /// 人机验证未通过 + public async Task VerifyCaptchaAndRemoveAsync(VerifyCaptchaReq req) + { + var ret = await VerifyCaptchaAsync(req); + if (ret) { + // 人机验证通过,删除人机验证缓存 + await RemoveAsync(GetCacheKey(req.Id, nameof(CaptchaCache))); + } + else { + throw new NetAdminInvalidOperationException(Ln.人机验证未通过); + } + } + + /// + /// 完成人机校验 + /// + public async Task VerifyCaptchaAsync(VerifyCaptchaReq req) + { + var val = await GetAsync(GetCacheKey(req.Id, nameof(CaptchaCache))); + return await Service.VerifyCaptchaAsync(req with { SawOffsetX = val }); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/ConfigCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/ConfigCache.cs new file mode 100644 index 00000000..8e95172a --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/ConfigCache.cs @@ -0,0 +1,73 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Config; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 配置缓存 +/// +public sealed class ConfigCache : DistributedCache, IScoped, IConfigCache +{ + /// + /// Initializes a new instance of the class. + /// + public ConfigCache(IDistributedCache cache, IConfigService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CreateAsync(CreateConfigReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryConfigReq req) + { + return Service.GetAsync(req); + } + + /// + public Task GetLatestConfigAsync() + { + return Service.GetLatestConfigAsync(); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task UpdateAsync(UpdateConfigReq req) + { + return Service.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/ConstantCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/ConstantCache.cs new file mode 100644 index 00000000..20396bc7 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/ConstantCache.cs @@ -0,0 +1,41 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 常量缓存 +/// +public sealed class ConstantCache : DistributedCache, IScoped, IConstantCache +{ + /// + /// Initializes a new instance of the class. + /// + public ConstantCache(IDistributedCache cache, IConstantService service) // + : base(cache, service) { } + + /// + public IDictionary GetCharsDic() + { + return Service.GetCharsDic(); + } + + /// + public IDictionary> GetEnums() + { + return Service.GetEnums(); + } + + /// + public IDictionary GetLocalizedStrings() + { + return Service.GetLocalizedStrings(); + } + + /// + public IDictionary GetNumbersDic() + { + return Service.GetNumbersDic(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IApiCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IApiCache.cs new file mode 100644 index 00000000..d4b25cd3 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IApiCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 接口缓存 +/// +public interface IApiCache : ICache, IApiModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/ICacheCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/ICacheCache.cs new file mode 100644 index 00000000..fc5e43ca --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/ICacheCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 缓存缓存 +/// +public interface ICacheCache : ICache, ICacheModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/ICaptchaCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/ICaptchaCache.cs new file mode 100644 index 00000000..36d29411 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/ICaptchaCache.cs @@ -0,0 +1,17 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Sys.Captcha; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 人机验证缓存 +/// +public interface ICaptchaCache : ICache, ICaptchaModule +{ + /// + /// 完成人机校验 ,并删除缓存项 + /// + Task VerifyCaptchaAndRemoveAsync(VerifyCaptchaReq req); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IConfigCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IConfigCache.cs new file mode 100644 index 00000000..3ca9fad0 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IConfigCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 配置缓存 +/// +public interface IConfigCache : ICache, IConfigModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IConstantCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IConstantCache.cs new file mode 100644 index 00000000..5054a9ef --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IConstantCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 常量缓存 +/// +public interface IConstantCache : ICache, IConstantModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDeptCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDeptCache.cs new file mode 100644 index 00000000..f8d8359a --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDeptCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 部门缓存 +/// +public interface IDeptCache : ICache, IDeptModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDevCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDevCache.cs new file mode 100644 index 00000000..14bf26db --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDevCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 开发缓存 +/// +public interface IDevCache : ICache, IDevModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDicCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDicCache.cs new file mode 100644 index 00000000..8914955b --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDicCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 字典缓存 +/// +public interface IDicCache : ICache, IDicModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDicCatalogCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDicCatalogCache.cs new file mode 100644 index 00000000..c395f3ab --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDicCatalogCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 字典目录缓存 +/// +public interface IDicCatalogCache : ICache, IDicCatalogModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDicContentCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDicContentCache.cs new file mode 100644 index 00000000..3a847448 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IDicContentCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 字典内容缓存 +/// +public interface IDicContentCache : ICache, IDicContentModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IFileCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IFileCache.cs new file mode 100644 index 00000000..2fd9acc2 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IFileCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 文件缓存 +/// +public interface IFileCache : ICache, IFileModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IMenuCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IMenuCache.cs new file mode 100644 index 00000000..191bd4ed --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IMenuCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 菜单缓存 +/// +public interface IMenuCache : ICache, IMenuModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IRequestLogCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IRequestLogCache.cs new file mode 100644 index 00000000..024eb64b --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IRequestLogCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 请求日志缓存 +/// +public interface IRequestLogCache : ICache, IRequestLogModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IRoleCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IRoleCache.cs new file mode 100644 index 00000000..3ff1ba85 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IRoleCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 角色缓存 +/// +public interface IRoleCache : ICache, IRoleModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IToolsCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IToolsCache.cs new file mode 100644 index 00000000..0efcf351 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IToolsCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 工具缓存 +/// +public interface IToolsCache : ICache, IToolsModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IUserCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IUserCache.cs new file mode 100644 index 00000000..fd41193e --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IUserCache.cs @@ -0,0 +1,54 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.User; +using NetAdmin.Domain.Dto.Sys.UserProfile; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 用户缓存 +/// +public interface IUserCache : ICache, IUserModule +{ + /// + /// 删除缓存 CheckMobileAvailableAsync + /// + Task RemoveCheckMobileAvailableAsync(CheckMobileAvailableReq req); + + /// + /// 删除缓存 CheckUserNameAvailableAsync + /// + Task RemoveCheckUserNameAvailableAsync(CheckUserNameAvailableReq req); + + /// + /// 删除缓存 LoginByPwdAsync + /// + Task RemoveLoginByPwdAsync(LoginByPwdReq req); + + /// + /// 删除缓存 LoginBySmsAsync + /// + Task RemoveLoginBySmsAsync(LoginBySmsReq req); + + /// + /// 删除缓存 QueryProfileAsync + /// + Task RemoveQueryProfileAsync(QueryReq req); + + /// + /// 删除缓存 RegisterAsync + /// + Task RemoveRegisterAsync(RegisterUserReq userReq); + + /// + /// 删除缓存 ResetPasswordAsync + /// + Task RemoveResetPasswordAsync(ResetPasswordReq req); + + /// + /// 删除缓存 UserInfoAsync + /// + Task RemoveUserInfoAsync(); +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IUserProfileCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IUserProfileCache.cs new file mode 100644 index 00000000..e59b7558 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IUserProfileCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 用户档案缓存 +/// +public interface IUserProfileCache : ICache, IUserProfileModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IVerifyCodeCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IVerifyCodeCache.cs new file mode 100644 index 00000000..acac07ff --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/Dependency/IVerifyCodeCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys.Dependency; + +/// +/// 验证码缓存 +/// +public interface IVerifyCodeCache : ICache, IVerifyCodeModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/DeptCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/DeptCache.cs new file mode 100644 index 00000000..89b9d6f1 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/DeptCache.cs @@ -0,0 +1,67 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dept; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 部门缓存 +/// +public sealed class DeptCache : DistributedCache, IScoped, IDeptCache +{ + /// + /// Initializes a new instance of the class. + /// + public DeptCache(IDistributedCache cache, IDeptService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CreateAsync(CreateDeptReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryDeptReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task UpdateAsync(UpdateDeptReq req) + { + return Service.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/DevCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/DevCache.cs new file mode 100644 index 00000000..9dfac095 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/DevCache.cs @@ -0,0 +1,36 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Sys.Dev; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 开发缓存 +/// +public sealed class DevCache : DistributedCache, IScoped, IDevCache +{ + /// + /// Initializes a new instance of the class. + /// + public DevCache(IDistributedCache cache, IDevService service) // + : base(cache, service) { } + + /// + public Task GenerateCsCodeAsync(GenerateCsCodeReq req) + { + return Service.GenerateCsCodeAsync(req); + } + + /// + public Task GenerateIconCodeAsync(GenerateIconCodeReq req) + { + return Service.GenerateIconCodeAsync(req); + } + + /// + public Task GenerateJsCodeAsync() + { + return Service.GenerateJsCodeAsync(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/DicCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/DicCache.cs new file mode 100644 index 00000000..a61194b0 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/DicCache.cs @@ -0,0 +1,92 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Catalog; +using NetAdmin.Domain.Dto.Sys.Dic.Content; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 字典缓存 +/// +public sealed class DicCache : DistributedCache, IScoped, IDicCache +{ + /// + /// Initializes a new instance of the class. + /// + public DicCache(IDistributedCache cache, IDicService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteCatalogAsync(BulkReq req) + { + return Service.BulkDeleteCatalogAsync(req); + } + + /// + public Task BulkDeleteContentAsync(BulkReq req) + { + return Service.BulkDeleteContentAsync(req); + } + + /// + public Task CreateCatalogAsync(CreateDicCatalogReq req) + { + return Service.CreateCatalogAsync(req); + } + + /// + public Task CreateContentAsync(CreateDicContentReq req) + { + return Service.CreateContentAsync(req); + } + + /// + public Task DeleteCatalogAsync(DelReq req) + { + return Service.DeleteCatalogAsync(req); + } + + /// + public Task DeleteContentAsync(DelReq req) + { + return Service.DeleteContentAsync(req); + } + + /// + public Task> PagedQueryCatalogAsync(PagedQueryReq req) + { + return Service.PagedQueryCatalogAsync(req); + } + + /// + public Task> PagedQueryContentAsync(PagedQueryReq req) + { + return Service.PagedQueryContentAsync(req); + } + + /// + public Task> QueryCatalogAsync(QueryReq req) + { + return Service.QueryCatalogAsync(req); + } + + /// + public Task> QueryContentAsync(QueryReq req) + { + return Service.QueryContentAsync(req); + } + + /// + public Task UpdateCatalogAsync(UpdateDicCatalogReq req) + { + return Service.UpdateCatalogAsync(req); + } + + /// + public Task UpdateContentAsync(UpdateDicContentReq req) + { + return Service.UpdateContentAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/DicCatalogCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/DicCatalogCache.cs new file mode 100644 index 00000000..40514917 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/DicCatalogCache.cs @@ -0,0 +1,67 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Catalog; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 字典目录缓存 +/// +public sealed class DicCatalogCache : DistributedCache, IScoped, IDicCatalogCache +{ + /// + /// Initializes a new instance of the class. + /// + public DicCatalogCache(IDistributedCache cache, IDicCatalogService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CreateAsync(CreateDicCatalogReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryDicCatalogReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task UpdateAsync(UpdateDicCatalogReq req) + { + return Service.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/DicContentCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/DicContentCache.cs new file mode 100644 index 00000000..0ca5a242 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/DicContentCache.cs @@ -0,0 +1,67 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Content; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 字典内容缓存 +/// +public sealed class DicContentCache : DistributedCache, IScoped, IDicContentCache +{ + /// + /// Initializes a new instance of the class. + /// + public DicContentCache(IDistributedCache cache, IDicContentService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CreateAsync(CreateDicContentReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryDicContentReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task UpdateAsync(UpdateDicContentReq req) + { + return Service.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/FileCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/FileCache.cs new file mode 100644 index 00000000..cebde69b --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/FileCache.cs @@ -0,0 +1,23 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 文件缓存 +/// +public sealed class FileCache : DistributedCache, IScoped, IFileCache +{ + /// + /// Initializes a new instance of the class. + /// + public FileCache(IDistributedCache cache, IFileService service) // + : base(cache, service) { } + + /// + public Task UploadAsync(IFormFile file) + { + return Service.UploadAsync(file); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/MenuCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/MenuCache.cs new file mode 100644 index 00000000..b960eba1 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/MenuCache.cs @@ -0,0 +1,73 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Menu; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 菜单缓存 +/// +public sealed class MenuCache : DistributedCache, IScoped, IMenuCache +{ + /// + /// Initializes a new instance of the class. + /// + public MenuCache(IDistributedCache cache, IMenuService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CreateAsync(CreateMenuReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryMenuReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task UpdateAsync(UpdateMenuReq req) + { + return Service.UpdateAsync(req); + } + + /// + public Task> UserMenusAsync() + { + return Service.UserMenusAsync(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/RequestLogCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/RequestLogCache.cs new file mode 100644 index 00000000..cd9add4c --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/RequestLogCache.cs @@ -0,0 +1,67 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.RequestLog; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 请求日志缓存 +/// +public sealed class RequestLogCache : DistributedCache, IScoped, IRequestLogCache +{ + /// + /// Initializes a new instance of the class. + /// + public RequestLogCache(IDistributedCache cache, IRequestLogService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CreateAsync(CreateRequestLogReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryRequestLogReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task UpdateAsync(NopReq req) + { + return Service.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/RoleCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/RoleCache.cs new file mode 100644 index 00000000..800d68fd --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/RoleCache.cs @@ -0,0 +1,67 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Role; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 角色缓存 +/// +public sealed class RoleCache : DistributedCache, IScoped, IRoleCache +{ + /// + /// Initializes a new instance of the class. + /// + public RoleCache(IDistributedCache cache, IRoleService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CreateAsync(CreateRoleReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryRoleReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task UpdateAsync(UpdateRoleReq req) + { + return Service.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/ToolsCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/ToolsCache.cs new file mode 100644 index 00000000..6d17aeb8 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/ToolsCache.cs @@ -0,0 +1,29 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 工具缓存 +/// +public sealed class ToolsCache : DistributedCache, IScoped, IToolsCache +{ + /// + /// Initializes a new instance of the class. + /// + public ToolsCache(IDistributedCache cache, IToolsService service) // + : base(cache, service) { } + + /// + public DateTime GetServerUtcTime() + { + return Service.GetServerUtcTime(); + } + + /// + public string Version() + { + return Service.Version(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/UserCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/UserCache.cs new file mode 100644 index 00000000..21f24a50 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/UserCache.cs @@ -0,0 +1,196 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.User; +using NetAdmin.Domain.Dto.Sys.UserProfile; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +public sealed class UserCache : DistributedCache, IScoped, IUserCache +{ + private readonly IVerifyCodeCache _verifyCodeCache; + + /// + /// Initializes a new instance of the class. + /// + public UserCache(IDistributedCache cache, IUserService service, IVerifyCodeCache verifyCodeCache) // + : base(cache, service) + { + _verifyCodeCache = verifyCodeCache; + } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CheckMobileAvailableAsync(CheckMobileAvailableReq req) + { + return Service.CheckMobileAvailableAsync(req); + } + + /// + public Task CheckUserNameAvailableAsync(CheckUserNameAvailableReq req) + { + return Service.CheckUserNameAvailableAsync(req); + } + + /// + public Task CreateAsync(CreateUserReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryUserReq req) + { + return Service.GetAsync(req); + } + + /// + public Task LoginByPwdAsync(LoginByPwdReq req) + { + return Service.LoginByPwdAsync(req); + } + + /// + public Task LoginBySmsAsync(LoginBySmsReq req) + { + return Service.LoginBySmsAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task> QueryProfileAsync(QueryReq req) + { + return Service.QueryProfileAsync(req); + } + + /// + public Task RegisterAsync(RegisterUserReq req) + { + return Service.RegisterAsync(req); + } + + /// + public Task RemoveCheckMobileAvailableAsync(CheckMobileAvailableReq req) + { + throw new NotImplementedException(); + } + + /// + public Task RemoveCheckUserNameAvailableAsync(CheckUserNameAvailableReq req) + { + throw new NotImplementedException(); + } + + /// + public Task RemoveLoginByPwdAsync(LoginByPwdReq req) + { + throw new NotImplementedException(); + } + + /// + public Task RemoveLoginBySmsAsync(LoginBySmsReq req) + { + throw new NotImplementedException(); + } + + /// + public Task RemoveQueryProfileAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + public Task RemoveRegisterAsync(RegisterUserReq userReq) + { + throw new NotImplementedException(); + } + + /// + public Task RemoveResetPasswordAsync(ResetPasswordReq req) + { + throw new NotImplementedException(); + } + + /// + public Task RemoveUserInfoAsync() + { + return RemoveAsync(GetCacheKey( // + Service.UserToken.Id.ToString(CultureInfo.InvariantCulture), nameof(UserInfoAsync))); + } + + /// + public Task ResetPasswordAsync(ResetPasswordReq req) + { + return Service.ResetPasswordAsync(req); + } + + /// + public Task SetAvatarAsync(SetAvatarReq req) + { + return Service.SetAvatarAsync(req); + } + + /// + public async Task SetEmailAsync(SetEmailReq req) + { + return !await _verifyCodeCache.VerifyAsync(req) + ? throw new NetAdminInvalidOperationException(Ln.邮箱验证码不正确) + : await Service.SetEmailAsync(req); + } + + /// + public Task SetMobileAsync(SetMobileReq req) + { + return Service.SetMobileAsync(req); + } + + /// + public Task SetPasswordAsync(SetPasswordReq req) + { + return Service.SetPasswordAsync(req); + } + + /// + public Task UpdateAsync(UpdateUserReq req) + { + return Service.UpdateAsync(req); + } + + /// + public Task UserInfoAsync() + { + return GetOrCreateAsync( // + GetCacheKey(Service.UserToken.Id.ToString(CultureInfo.InvariantCulture)), Service.UserInfoAsync +, TimeSpan.FromMinutes(1)); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/UserProfileCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/UserProfileCache.cs new file mode 100644 index 00000000..015a3b0a --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/UserProfileCache.cs @@ -0,0 +1,67 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.UserProfile; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +/// 用户档案缓存 +/// +public sealed class UserProfileCache : DistributedCache, IScoped, IUserProfileCache +{ + /// + /// Initializes a new instance of the class. + /// + public UserProfileCache(IDistributedCache cache, IUserProfileService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CreateAsync(CreateUserProfileReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryUserProfileReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task UpdateAsync(UpdateUserProfileReq req) + { + return Service.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/VerifyCodeCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/VerifyCodeCache.cs new file mode 100644 index 00000000..7865cce6 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/VerifyCodeCache.cs @@ -0,0 +1,78 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.VerifyCode; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Cache.Sys; + +/// +public sealed class VerifyCodeCache : DistributedCache, IScoped, IVerifyCodeCache +{ + /// + /// Initializes a new instance of the class. + /// + public VerifyCodeCache(IDistributedCache cache, IVerifyCodeService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CreateAsync(CreateVerifyCodeReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryVerifyCodeReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task SendVerifyCodeAsync(SendVerifyCodeReq req) + { + return Service.SendVerifyCodeAsync(req); + } + + /// + public Task UpdateAsync(UpdateVerifyCodeReq req) + { + return Service.UpdateAsync(req); + } + + /// + public Task VerifyAsync(VerifyCodeReq req) + { + return Service.VerifyAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Tpl/Dependency/IExampleCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Tpl/Dependency/IExampleCache.cs new file mode 100644 index 00000000..a371b185 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Tpl/Dependency/IExampleCache.cs @@ -0,0 +1,10 @@ +using NetAdmin.Cache; +using NetAdmin.SysComponent.Application.Modules.Tpl; +using NetAdmin.SysComponent.Application.Services.Tpl.Dependency; + +namespace NetAdmin.SysComponent.Cache.Tpl.Dependency; + +/// +/// 示例缓存 +/// +public interface IExampleCache : ICache, IExampleModule { } \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Cache/Tpl/ExampleCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Tpl/ExampleCache.cs new file mode 100644 index 00000000..1c20eaa5 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Cache/Tpl/ExampleCache.cs @@ -0,0 +1,65 @@ +using NetAdmin.Cache; +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Tpl.Example; +using NetAdmin.SysComponent.Application.Services.Tpl.Dependency; +using NetAdmin.SysComponent.Cache.Tpl.Dependency; + +namespace NetAdmin.SysComponent.Cache.Tpl; + +/// +public sealed class ExampleCache : DistributedCache, IScoped, IExampleCache +{ + /// + /// Initializes a new instance of the class. + /// + public ExampleCache(IDistributedCache cache, IExampleService service) // + : base(cache, service) { } + + /// + public Task BulkDeleteAsync(BulkReq req) + { + return Service.BulkDeleteAsync(req); + } + + /// + public Task CreateAsync(CreateExampleReq req) + { + return Service.CreateAsync(req); + } + + /// + public Task DeleteAsync(DelReq req) + { + return Service.DeleteAsync(req); + } + + /// + public Task ExistAsync(QueryReq req) + { + return Service.ExistAsync(req); + } + + /// + public Task GetAsync(QueryExampleReq req) + { + return Service.GetAsync(req); + } + + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Service.PagedQueryAsync(req); + } + + /// + public Task> QueryAsync(QueryReq req) + { + return Service.QueryAsync(req); + } + + /// + public Task UpdateAsync(UpdateExampleReq req) + { + return Service.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ApiController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ApiController.cs new file mode 100644 index 00000000..8e7cc8ef --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ApiController.cs @@ -0,0 +1,105 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Api; +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 接口服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class ApiController : ControllerBase, IApiModule +{ + /// + /// Initializes a new instance of the class. + /// + public ApiController(IApiCache cache) // + : base(cache) { } + + /// + /// 批量删除接口 + /// + [NonAction] + [Transaction] + public Task BulkDeleteAsync(BulkReq req) + { + return Cache.BulkDeleteAsync(req); + } + + /// + /// 创建接口 + /// + [NonAction] + [Transaction] + public Task CreateAsync(CreateApiReq req) + { + return Cache.CreateAsync(req); + } + + /// + /// 删除接口 + /// + [NonAction] + [Transaction] + public Task DeleteAsync(DelReq req) + { + return Cache.DeleteAsync(req); + } + + /// + /// 接口是否存在 + /// + [NonAction] + public Task ExistAsync(QueryReq req) + { + return Cache.ExistAsync(req); + } + + /// + /// 获取单个接口 + /// + [NonAction] + public Task GetAsync(QueryApiReq req) + { + return Cache.GetAsync(req); + } + + /// + /// 分页查询接口 + /// + [NonAction] + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Cache.PagedQueryAsync(req); + } + + /// + /// 查询接口 + /// + public Task> QueryAsync(QueryReq req) + { + return Cache.QueryAsync(req); + } + + /// + /// 同步接口 + /// + [Transaction] + public Task SyncAsync() + { + return Cache.SyncAsync(); + } + + /// + /// 更新接口 + /// + [NonAction] + public Task UpdateAsync(NopReq req) + { + return Cache.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/CacheController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/CacheController.cs new file mode 100644 index 00000000..dc9e8491 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/CacheController.cs @@ -0,0 +1,37 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Cache; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 缓存服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class CacheController : ControllerBase, ICacheModule +{ + /// + /// Initializes a new instance of the class. + /// + public CacheController(ICacheCache cache) // + : base(cache) { } + + /// + /// 缓存统计 + /// + public Task CacheStatisticsAsync() + { + return Cache.CacheStatisticsAsync(); + } + + /// + /// 获取所有缓存项 + /// + public PagedQueryRsp GetAllEntries(PagedQueryReq req) + { + return Cache.GetAllEntries(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/CaptchaController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/CaptchaController.cs new file mode 100644 index 00000000..e2c2994d --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/CaptchaController.cs @@ -0,0 +1,38 @@ +using NetAdmin.Domain.Dto.Sys.Captcha; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 人机验证服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class CaptchaController : ControllerBase, ICaptchaModule +{ + /// + /// Initializes a new instance of the class. + /// + public CaptchaController(ICaptchaCache cache) // + : base(cache) { } + + /// + /// 获取人机校验图 + /// + [AllowAnonymous] + public Task GetCaptchaImageAsync() + { + return Cache.GetCaptchaImageAsync(); + } + + /// + /// 完成人机校验 + /// + [AllowAnonymous] + public Task VerifyCaptchaAsync(VerifyCaptchaReq req) + { + return Cache.VerifyCaptchaAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ConfigController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ConfigController.cs new file mode 100644 index 00000000..eb4f6668 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ConfigController.cs @@ -0,0 +1,100 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Config; +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 配置服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class ConfigController : ControllerBase, IConfigModule +{ + /// + /// Initializes a new instance of the class. + /// + public ConfigController(IConfigCache cache) // + : base(cache) { } + + /// + /// 批量删除配置 + /// + [Transaction] + public Task BulkDeleteAsync(BulkReq req) + { + return Cache.BulkDeleteAsync(req); + } + + /// + /// 创建配置 + /// + [Transaction] + public Task CreateAsync(CreateConfigReq req) + { + return Cache.CreateAsync(req); + } + + /// + /// 删除配置 + /// + [Transaction] + public Task DeleteAsync(DelReq req) + { + return Cache.DeleteAsync(req); + } + + /// + /// 配置是否存在 + /// + [NonAction] + public Task ExistAsync(QueryReq req) + { + return Cache.ExistAsync(req); + } + + /// + /// 获取单个配置 + /// + [NonAction] + public Task GetAsync(QueryConfigReq req) + { + return Cache.GetAsync(req); + } + + /// + /// 获取最新有效配置 + /// + public Task GetLatestConfigAsync() + { + return Cache.GetLatestConfigAsync(); + } + + /// + /// 分页查询配置 + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Cache.PagedQueryAsync(req); + } + + /// + /// 查询配置 + /// + public Task> QueryAsync(QueryReq req) + { + return Cache.QueryAsync(req); + } + + /// + /// 更新配置 + /// + [Transaction] + public Task UpdateAsync(UpdateConfigReq req) + { + return Cache.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ConstantController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ConstantController.cs new file mode 100644 index 00000000..ba54dde2 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ConstantController.cs @@ -0,0 +1,87 @@ +using NetAdmin.Domain.Dto; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 常量服务 +/// +[AllowAnonymous] +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class ConstantController : ControllerBase, IConstantModule +{ + private readonly JsonOptions _jsonOptions; + + /// + /// Initializes a new instance of the class. + /// + public ConstantController(IConstantCache cache, IOptions jsonOptions) // + : base(cache) + { + _jsonOptions = jsonOptions.Value; + } + + /// + /// 获得常量字符串 + /// + [NonUnify] + public IActionResult GetChars() + { + var ret = GetCharsDic(); + return OriginNamingResult(ret); + } + + /// + /// 获得常量字符串 + /// + [NonAction] + public IDictionary GetCharsDic() + { + return Cache.GetCharsDic(); + } + + /// + /// 获得公共枚举值 + /// + public IDictionary> GetEnums() + { + return Cache.GetEnums(); + } + + /// + /// 获得本地化字符串 + /// + public IDictionary GetLocalizedStrings() + { + return Cache.GetLocalizedStrings(); + } + + /// + /// 获得数字常量表 + /// + [NonUnify] + public IActionResult GetNumbers() + { + var ret = GetNumbersDic(); + return OriginNamingResult(ret); + } + + /// + /// 获得数字常量表 + /// + [NonAction] + public IDictionary GetNumbersDic() + { + return Cache.GetNumbersDic(); + } + + private IActionResult OriginNamingResult(T data) + { + return new JsonResult( // + new RestfulInfo { Code = 0, Data = data } + , new JsonSerializerOptions(_jsonOptions.JsonSerializerOptions) { DictionaryKeyPolicy = null }); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/DeptController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/DeptController.cs new file mode 100644 index 00000000..fe383861 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/DeptController.cs @@ -0,0 +1,93 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dept; +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 部门服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class DeptController : ControllerBase, IDeptModule +{ + /// + /// Initializes a new instance of the class. + /// + public DeptController(IDeptCache cache) // + : base(cache) { } + + /// + /// 批量删除部门 + /// + [Transaction] + public Task BulkDeleteAsync(BulkReq req) + { + return Cache.BulkDeleteAsync(req); + } + + /// + /// 创建部门 + /// + [Transaction] + public Task CreateAsync(CreateDeptReq req) + { + return Cache.CreateAsync(req); + } + + /// + /// 删除部门 + /// + [Transaction] + public Task DeleteAsync(DelReq req) + { + return Cache.DeleteAsync(req); + } + + /// + /// 部门是否存在 + /// + [NonAction] + public Task ExistAsync(QueryReq req) + { + return Cache.ExistAsync(req); + } + + /// + /// 获取单个部门 + /// + [NonAction] + public Task GetAsync(QueryDeptReq req) + { + return Cache.GetAsync(req); + } + + /// + /// 分页查询部门 + /// + [NonAction] + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Cache.PagedQueryAsync(req); + } + + /// + /// 查询部门 + /// + public Task> QueryAsync(QueryReq req) + { + return Cache.QueryAsync(req); + } + + /// + /// 更新部门 + /// + [Transaction] + public Task UpdateAsync(UpdateDeptReq req) + { + return Cache.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/DevController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/DevController.cs new file mode 100644 index 00000000..4f2d38dc --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/DevController.cs @@ -0,0 +1,44 @@ +using NetAdmin.Domain.Dto.Sys.Dev; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 开发服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class DevController : ControllerBase, IDevModule +{ + /// + /// Initializes a new instance of the class. + /// + public DevController(IDevCache cache) // + : base(cache) { } + + /// + /// 生成后端代码 + /// + public Task GenerateCsCodeAsync(GenerateCsCodeReq req) + { + return Cache.GenerateCsCodeAsync(req); + } + + /// + /// 生成图标代码 + /// + public Task GenerateIconCodeAsync(GenerateIconCodeReq req) + { + return Cache.GenerateIconCodeAsync(req); + } + + /// + /// 生成接口代码 + /// + public Task GenerateJsCodeAsync() + { + return Cache.GenerateJsCodeAsync(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/DicController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/DicController.cs new file mode 100644 index 00000000..aca077b6 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/DicController.cs @@ -0,0 +1,127 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Dic.Catalog; +using NetAdmin.Domain.Dto.Sys.Dic.Content; +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 字典服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class DicController : ControllerBase, IDicModule +{ + /// + /// Initializes a new instance of the class. + /// + public DicController(IDicCache cache) // + : base(cache) { } + + /// + /// 批量删除字典目录 + /// + [Transaction] + public Task BulkDeleteCatalogAsync(BulkReq req) + { + return Cache.BulkDeleteCatalogAsync(req); + } + + /// + /// 批量删除字典内容 + /// + [Transaction] + public Task BulkDeleteContentAsync(BulkReq req) + { + return Cache.BulkDeleteContentAsync(req); + } + + /// + /// 创建字典目录 + /// + [Transaction] + public Task CreateCatalogAsync(CreateDicCatalogReq req) + { + return Cache.CreateCatalogAsync(req); + } + + /// + /// 创建字典内容 + /// + [Transaction] + public Task CreateContentAsync(CreateDicContentReq req) + { + return Cache.CreateContentAsync(req); + } + + /// + /// 删除字典目录 + /// + [Transaction] + public Task DeleteCatalogAsync(DelReq req) + { + return Cache.DeleteCatalogAsync(req); + } + + /// + /// 删除字典内容 + /// + [Transaction] + public Task DeleteContentAsync(DelReq req) + { + return Cache.DeleteContentAsync(req); + } + + /// + /// 分页查询字典目录 + /// + public Task> PagedQueryCatalogAsync(PagedQueryReq req) + { + return Cache.PagedQueryCatalogAsync(req); + } + + /// + /// 分页查询字典内容 + /// + public Task> PagedQueryContentAsync(PagedQueryReq req) + { + return Cache.PagedQueryContentAsync(req); + } + + /// + /// 查询字典目录 + /// + public Task> QueryCatalogAsync(QueryReq req) + { + return Cache.QueryCatalogAsync(req); + } + + /// + /// 查询字典内容 + /// + public Task> QueryContentAsync(QueryReq req) + { + return Cache.QueryContentAsync(req); + } + + /// + /// 更新字典目录 + /// + [Transaction] + public Task UpdateCatalogAsync(UpdateDicCatalogReq req) + { + return Cache.UpdateCatalogAsync(req); + } + + /// + /// 更新字典内容 + /// + [Transaction] + public Task UpdateContentAsync(UpdateDicContentReq req) + { + return Cache.UpdateContentAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/FileController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/FileController.cs new file mode 100644 index 00000000..e910d652 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/FileController.cs @@ -0,0 +1,27 @@ +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 文件服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class FileController : ControllerBase, IFileModule +{ + /// + /// Initializes a new instance of the class. + /// + public FileController(IFileCache cache) // + : base(cache) { } + + /// + /// 文件上传 + /// + public Task UploadAsync(IFormFile file) + { + return Cache.UploadAsync(file); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/LogController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/LogController.cs new file mode 100644 index 00000000..f6e4474d --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/LogController.cs @@ -0,0 +1,96 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.RequestLog; +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 请求日志服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class LogController : ControllerBase, IRequestLogModule +{ + /// + /// Initializes a new instance of the class. + /// + public LogController(IRequestLogCache cache) // + : base(cache) { } + + /// + /// 批量删除请求日志 + /// + [NonAction] + [Transaction] + public Task BulkDeleteAsync(BulkReq req) + { + return Cache.BulkDeleteAsync(req); + } + + /// + /// 创建请求日志 + /// + [NonAction] + [Transaction] + public Task CreateAsync(CreateRequestLogReq req) + { + return Cache.CreateAsync(req); + } + + /// + /// 删除请求日志 + /// + [NonAction] + [Transaction] + public Task DeleteAsync(DelReq req) + { + return Cache.DeleteAsync(req); + } + + /// + /// 请求日志是否存在 + /// + [NonAction] + public Task ExistAsync(QueryReq req) + { + return Cache.ExistAsync(req); + } + + /// + /// 获取单个请求日志 + /// + [NonAction] + public Task GetAsync(QueryRequestLogReq req) + { + return Cache.GetAsync(req); + } + + /// + /// 分页查询请求日志 + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Cache.PagedQueryAsync(req); + } + + /// + /// 查询请求日志 + /// + public Task> QueryAsync(QueryReq req) + { + return Cache.QueryAsync(req); + } + + /// + /// 更新请求日志 + /// + [NonAction] + [Transaction] + public Task UpdateAsync(NopReq req) + { + return Cache.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/MenuController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/MenuController.cs new file mode 100644 index 00000000..df200d8d --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/MenuController.cs @@ -0,0 +1,101 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Menu; +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 菜单服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class MenuController : ControllerBase, IMenuModule +{ + /// + /// Initializes a new instance of the class. + /// + public MenuController(IMenuCache cache) // + : base(cache) { } + + /// + /// 批量删除菜单 + /// + [Transaction] + public Task BulkDeleteAsync(BulkReq req) + { + return Cache.BulkDeleteAsync(req); + } + + /// + /// 创建菜单 + /// + [Transaction] + public Task CreateAsync(CreateMenuReq req) + { + return Cache.CreateAsync(req); + } + + /// + /// 删除菜单 + /// + [Transaction] + public Task DeleteAsync(DelReq req) + { + return Cache.DeleteAsync(req); + } + + /// + /// 菜单是否存在 + /// + [NonAction] + public Task ExistAsync(QueryReq req) + { + return Cache.ExistAsync(req); + } + + /// + /// 获取单个菜单 + /// + [NonAction] + public Task GetAsync(QueryMenuReq req) + { + return Cache.GetAsync(req); + } + + /// + /// 分页查询菜单 + /// + [NonAction] + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Cache.PagedQueryAsync(req); + } + + /// + /// 查询菜单 + /// + public Task> QueryAsync(QueryReq req) + { + return Cache.QueryAsync(req); + } + + /// + /// 更新菜单 + /// + [Transaction] + public Task UpdateAsync(UpdateMenuReq req) + { + return Cache.UpdateAsync(req); + } + + /// + /// 当前用户菜单 + /// + public Task> UserMenusAsync() + { + return Cache.UserMenusAsync(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/RoleController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/RoleController.cs new file mode 100644 index 00000000..daadf439 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/RoleController.cs @@ -0,0 +1,92 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.Role; +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 角色服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class RoleController : ControllerBase, IRoleModule +{ + /// + /// Initializes a new instance of the class. + /// + public RoleController(IRoleCache cache) // + : base(cache) { } + + /// + /// 批量删除角色 + /// + [Transaction] + public Task BulkDeleteAsync(BulkReq req) + { + return Cache.BulkDeleteAsync(req); + } + + /// + /// 创建角色 + /// + [Transaction] + public Task CreateAsync(CreateRoleReq req) + { + return Cache.CreateAsync(req); + } + + /// + /// 删除角色 + /// + [Transaction] + public Task DeleteAsync(DelReq req) + { + return Cache.DeleteAsync(req); + } + + /// + /// 角色是否存在 + /// + [NonAction] + public Task ExistAsync(QueryReq req) + { + return Cache.ExistAsync(req); + } + + /// + /// 获取单个角色 + /// + [NonAction] + public Task GetAsync(QueryRoleReq req) + { + return Cache.GetAsync(req); + } + + /// + /// 分页查询角色 + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Cache.PagedQueryAsync(req); + } + + /// + /// 查询角色 + /// + public Task> QueryAsync(QueryReq req) + { + return Cache.QueryAsync(req); + } + + /// + /// 更新角色 + /// + [Transaction] + public Task UpdateAsync(UpdateRoleReq req) + { + return Cache.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ToolsController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ToolsController.cs new file mode 100644 index 00000000..e7649b7d --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/ToolsController.cs @@ -0,0 +1,37 @@ +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 工具服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class ToolsController : ControllerBase, IToolsModule +{ + /// + /// Initializes a new instance of the class. + /// + public ToolsController(IToolsCache cache) // + : base(cache) { } + + /// + /// 服务器时间 + /// + [AllowAnonymous] + public DateTime GetServerUtcTime() + { + return Cache.GetServerUtcTime(); + } + + /// + /// 版本信息 + /// + [AllowAnonymous] + public string Version() + { + return Cache.Version(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/UserController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/UserController.cs new file mode 100644 index 00000000..e7519410 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/UserController.cs @@ -0,0 +1,221 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.User; +using NetAdmin.Domain.Dto.Sys.UserProfile; +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 用户服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class UserController : ControllerBase, IUserModule +{ + private readonly IConfigCache _configCache; + + /// + /// Initializes a new instance of the class. + /// + public UserController(IUserCache cache, IConfigCache configCache) // + : base(cache) + { + _configCache = configCache; + } + + /// + /// 批量删除用户 + /// + [NonAction] + [Transaction] + public Task BulkDeleteAsync(BulkReq req) + { + return Cache.BulkDeleteAsync(req); + } + + /// + /// 检查手机号是否可用 + /// + [AllowAnonymous] + public Task CheckMobileAvailableAsync(CheckMobileAvailableReq req) + { + return Cache.CheckMobileAvailableAsync(req); + } + + /// + /// 检查用户名是否可用 + /// + [AllowAnonymous] + public Task CheckUserNameAvailableAsync(CheckUserNameAvailableReq req) + { + return Cache.CheckUserNameAvailableAsync(req); + } + + /// + /// 创建用户 + /// + [Transaction] + public Task CreateAsync(CreateUserReq req) + { + return Cache.CreateAsync(req); + } + + /// + /// 删除用户 + /// + [Transaction] + public Task DeleteAsync(DelReq req) + { + return Cache.DeleteAsync(req); + } + + /// + /// 用户是否存在 + /// + [NonAction] + public Task ExistAsync(QueryReq req) + { + return Cache.ExistAsync(req); + } + + /// + /// 获取单个用户 + /// + [NonAction] + public Task GetAsync(QueryUserReq req) + { + return Cache.GetAsync(req); + } + + /// + /// 密码登录 + /// + [AllowAnonymous] + [Transaction] + public async Task LoginByPwdAsync(LoginByPwdReq req) + { + var ret = await Cache.LoginByPwdAsync(req); + ret.SetToRspHeader(); + return ret; + } + + /// + /// 短信登录 + /// + [AllowAnonymous] + [Transaction] + public async Task LoginBySmsAsync(LoginBySmsReq req) + { + var ret = await Cache.LoginBySmsAsync(req); + ret.SetToRspHeader(); + return ret; + } + + /// + /// 分页查询用户 + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Cache.PagedQueryAsync(req); + } + + /// + /// 查询用户 + /// + public Task> QueryAsync(QueryReq req) + { + return Cache.QueryAsync(req); + } + + /// + /// 查询用户档案 + /// + public Task> QueryProfileAsync(QueryReq req) + { + return Cache.QueryProfileAsync(req); + } + + /// + /// 注册用户 + /// + [Transaction] + [AllowAnonymous] + public async Task RegisterAsync(RegisterUserReq req) + { + var config = await _configCache.GetLatestConfigAsync(); + + return await Cache.RegisterAsync(req with { + DeptId = config.UserRegisterDeptId + , RoleIds = new[] { config.UserRegisterRoleId } + , Profile = new CreateUserProfileReq() + , Enabled = !config.UserRegisterConfirm + , Mobile = req.VerifySmsCodeReq.DestDevice + }); + } + + /// + /// 重设密码 + /// + [AllowAnonymous] + [Transaction] + public Task ResetPasswordAsync(ResetPasswordReq req) + { + return Cache.ResetPasswordAsync(req); + } + + /// + /// 更新用户头像 + /// + [Transaction] + public Task SetAvatarAsync(SetAvatarReq req) + { + return Cache.SetAvatarAsync(req); + } + + /// + /// 设置邮箱 + /// + [Transaction] + public Task SetEmailAsync(SetEmailReq req) + { + return Cache.SetEmailAsync(req); + } + + /// + /// 设置手机号 + /// + [Transaction] + public Task SetMobileAsync(SetMobileReq req) + { + return Cache.SetMobileAsync(req); + } + + /// + /// 设置密码 + /// + [Transaction] + public Task SetPasswordAsync(SetPasswordReq req) + { + return Cache.SetPasswordAsync(req); + } + + /// + /// 更新用户 + /// + [Transaction] + public Task UpdateAsync(UpdateUserReq req) + { + return Cache.UpdateAsync(req); + } + + /// + /// 当前用户信息 + /// + public Task UserInfoAsync() + { + return Cache.UserInfoAsync(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/VerifyCodeController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/VerifyCodeController.cs new file mode 100644 index 00000000..066e1a78 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/VerifyCodeController.cs @@ -0,0 +1,104 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Sys.VerifyCode; +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Sys; + +/// +/// 验证码服务 +/// +[ApiDescriptionSettings(nameof(Sys), Module = nameof(Sys))] +public sealed class VerifyCodeController : ControllerBase, IVerifyCodeModule +{ + private readonly ICaptchaCache _captchaCache; + + /// + /// Initializes a new instance of the class. + /// + public VerifyCodeController(IVerifyCodeCache cache, ICaptchaCache captchaCache) // + : base(cache) + { + _captchaCache = captchaCache; + } + + /// + [NonAction] + public Task BulkDeleteAsync(BulkReq req) + { + throw new NotImplementedException(); + } + + /// + [NonAction] + public Task CreateAsync(CreateVerifyCodeReq req) + { + throw new NotImplementedException(); + } + + /// + [NonAction] + public Task DeleteAsync(DelReq req) + { + throw new NotImplementedException(); + } + + /// + [NonAction] + public Task ExistAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + [NonAction] + public Task GetAsync(QueryVerifyCodeReq req) + { + throw new NotImplementedException(); + } + + /// + [NonAction] + public Task> PagedQueryAsync(PagedQueryReq req) + { + throw new NotImplementedException(); + } + + /// + [NonAction] + public Task> QueryAsync(QueryReq req) + { + throw new NotImplementedException(); + } + + /// + /// 发送验证码 + /// + [Transaction] + [AllowAnonymous] + public async Task SendVerifyCodeAsync(SendVerifyCodeReq req) + { + await _captchaCache.VerifyCaptchaAndRemoveAsync(req.VerifyCaptchaReq); + return await Cache.SendVerifyCodeAsync(req); + } + + /// + [NonAction] + public Task UpdateAsync(UpdateVerifyCodeReq req) + { + throw new NotImplementedException(); + } + + /// + /// 完成验证 + /// + [Transaction] + [AllowAnonymous] + public Task VerifyAsync(VerifyCodeReq req) + { + return Cache.VerifyAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Tpl/ExampleController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Tpl/ExampleController.cs new file mode 100644 index 00000000..7610c70b --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Tpl/ExampleController.cs @@ -0,0 +1,92 @@ +using NetAdmin.Domain.Dto.Dependency; +using NetAdmin.Domain.Dto.Tpl.Example; +using NetAdmin.Host.Attributes; +using NetAdmin.Host.Controllers; +using NetAdmin.SysComponent.Application.Modules.Tpl; +using NetAdmin.SysComponent.Application.Services.Tpl.Dependency; +using NetAdmin.SysComponent.Cache.Tpl.Dependency; + +namespace NetAdmin.SysComponent.Host.Controllers.Tpl; + +/// +/// 示例服务 +/// +[ApiDescriptionSettings(nameof(Tpl), Module = nameof(Tpl))] +public sealed class ExampleController : ControllerBase, IExampleModule +{ + /// + /// Initializes a new instance of the class. + /// + public ExampleController(IExampleCache cache) // + : base(cache) { } + + /// + /// 批量删除示例 + /// + [Transaction] + public Task BulkDeleteAsync(BulkReq req) + { + return Cache.BulkDeleteAsync(req); + } + + /// + /// 创建示例 + /// + [Transaction] + public Task CreateAsync(CreateExampleReq req) + { + return Cache.CreateAsync(req); + } + + /// + /// 删除示例 + /// + [Transaction] + public Task DeleteAsync(DelReq req) + { + return Cache.DeleteAsync(req); + } + + /// + /// 示例是否存在 + /// + [NonAction] + public Task ExistAsync(QueryReq req) + { + return Cache.ExistAsync(req); + } + + /// + /// 获取单个示例 + /// + [NonAction] + public Task GetAsync(QueryExampleReq req) + { + return Cache.GetAsync(req); + } + + /// + /// 分页查询示例 + /// + public Task> PagedQueryAsync(PagedQueryReq req) + { + return Cache.PagedQueryAsync(req); + } + + /// + /// 查询示例 + /// + public Task> QueryAsync(QueryReq req) + { + return Cache.QueryAsync(req); + } + + /// + /// 更新示例 + /// + [Transaction] + public Task UpdateAsync(UpdateExampleReq req) + { + return Cache.UpdateAsync(req); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/NetAdmin.SysComponent.Host.csproj b/src/backend/NetAdmin.SysComponent.Host/NetAdmin.SysComponent.Host.csproj new file mode 100644 index 00000000..e89eea5c --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/NetAdmin.SysComponent.Host.csproj @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Subscribers/ApiSynchronizer.cs b/src/backend/NetAdmin.SysComponent.Host/Subscribers/ApiSynchronizer.cs new file mode 100644 index 00000000..0c50c043 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Subscribers/ApiSynchronizer.cs @@ -0,0 +1,31 @@ +using NetAdmin.Domain.Events; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Subscribers; + +/// +/// Api接口同步器 +/// +public sealed class ApiSynchronizer : IEventSubscriber +{ + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + public ApiSynchronizer(ILogger logger) + { + _logger = logger; + } + + /// + /// 同步Api接口 + /// + [EventSubscribe(nameof(SyncStructureAfterEvent))] + public async Task SyncApiAsync(EventHandlerExecutingContext _) + { + var logService = App.GetService(); + await logService.SyncAsync(); + _logger.Info($"{nameof(IApiService)}.{nameof(IApiService.SyncAsync)} {Ln.已完成}"); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Subscribers/CacheCleaner.cs b/src/backend/NetAdmin.SysComponent.Host/Subscribers/CacheCleaner.cs new file mode 100644 index 00000000..94c50866 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Subscribers/CacheCleaner.cs @@ -0,0 +1,31 @@ +using NetAdmin.Domain.Contexts; +using NetAdmin.Domain.Events.Sys; +using NetAdmin.SysComponent.Cache.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Subscribers; + +/// +/// 缓存清理器 +/// +public sealed class CacheCleaner : IEventSubscriber +{ + /// + /// Initializes a new instance of the class. + /// + public CacheCleaner() { } + + /// + /// 用户缓存清理 + /// + [EventSubscribe(nameof(UserUpdatedEvent))] + public async Task RemoveUserInfoAsync(EventHandlerExecutingContext context) + { + if (context.Source is not UserUpdatedEvent userUpdatedEvent) { + return; + } + + var cache = App.GetService(); + cache.Service.UserToken = ContextUserToken.Create(userUpdatedEvent.Data); + await cache.RemoveUserInfoAsync(); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Subscribers/EmailCodeSender.cs b/src/backend/NetAdmin.SysComponent.Host/Subscribers/EmailCodeSender.cs new file mode 100644 index 00000000..f8560124 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Subscribers/EmailCodeSender.cs @@ -0,0 +1,40 @@ +using NetAdmin.Domain.Dto.Sys.VerifyCode; +using NetAdmin.Domain.Enums.Sys; +using NetAdmin.Domain.Events.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Subscribers; + +/// +/// 邮件验证码发送器 +/// +public sealed class EmailCodeSender : IEventSubscriber +{ + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + public EmailCodeSender(ILogger logger) + { + _logger = logger; + } + + /// + /// 发送邮件 + /// + [EventSubscribe(nameof(VerifyCodeCreatedEvent))] + public async Task SendEmailAsync(EventHandlerExecutingContext context) + { + if (context.Source is not VerifyCodeCreatedEvent verifyCodeCreatedEvent || + verifyCodeCreatedEvent.Data.DeviceType != VerifyCodeDeviceTypes.Email) { + return; + } + + // 发送... + var verifyCodeService = App.GetService(); + _ = await verifyCodeService.UpdateAsync( + verifyCodeCreatedEvent.Data.Adapt() with { Status = VerifyCodeStatues.Sent }); + _logger.Info($"{nameof(IVerifyCodeService)}.{nameof(IVerifyCodeService.UpdateAsync)} {Ln.已完成}"); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Subscribers/OperationLogger.cs b/src/backend/NetAdmin.SysComponent.Host/Subscribers/OperationLogger.cs new file mode 100644 index 00000000..b9473359 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Subscribers/OperationLogger.cs @@ -0,0 +1,46 @@ +using NetAdmin.Domain.Dto.Sys.RequestLog; +using NetAdmin.Domain.Dto.Sys.User; +using NetAdmin.Domain.Events.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Subscribers; + +/// +/// 操作日志记录 +/// +public sealed class OperationLogger : IEventSubscriber +{ + /// + /// 保存请求日志到数据库 + /// + [EventSubscribe(nameof(RequestLogEvent))] + public async Task OperationEventDbRecordAsync(EventHandlerExecutingContext context) + { + if (context.Source is not RequestLogEvent operationEvent) { + return; + } + + // 跳过心跳请求 + if (operationEvent.Data.ApiId.Equals("api/health/check", StringComparison.OrdinalIgnoreCase)) { + return; + } + + CreateRequestLogReq logReq = null; + + // 登录日志特殊处理 + if (operationEvent.Data.ApiId.Equals("api/user/login", StringComparison.OrdinalIgnoreCase)) { + try { + var loginReq = operationEvent.Data.RequestBody.ToObject(); + logReq = operationEvent.Data with { ExtraData = loginReq.Account }; + } + catch { + // ignored + } + } + + logReq ??= operationEvent.Data; + var logService = App.GetService(); + logReq.TruncateStrings(); + _ = await logService.CreateAsync(logReq); + } +} \ No newline at end of file diff --git a/src/backend/NetAdmin.SysComponent.Host/Subscribers/SmsCodeSender.cs b/src/backend/NetAdmin.SysComponent.Host/Subscribers/SmsCodeSender.cs new file mode 100644 index 00000000..3309a729 --- /dev/null +++ b/src/backend/NetAdmin.SysComponent.Host/Subscribers/SmsCodeSender.cs @@ -0,0 +1,40 @@ +using NetAdmin.Domain.Dto.Sys.VerifyCode; +using NetAdmin.Domain.Enums.Sys; +using NetAdmin.Domain.Events.Sys; +using NetAdmin.SysComponent.Application.Services.Sys.Dependency; + +namespace NetAdmin.SysComponent.Host.Subscribers; + +/// +/// 短信验证码发送器 +/// +public sealed class SmsCodeSender : IEventSubscriber +{ + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + public SmsCodeSender(ILogger logger) + { + _logger = logger; + } + + /// + /// 发送短信 + /// + [EventSubscribe(nameof(VerifyCodeCreatedEvent))] + public async Task SendSmsAsync(EventHandlerExecutingContext context) + { + if (context.Source is not VerifyCodeCreatedEvent verifyCodeCreatedEvent || + verifyCodeCreatedEvent.Data.DeviceType != VerifyCodeDeviceTypes.Mobile) { + return; + } + + // 发送... + var verifyCodeService = App.GetService(); + _ = await verifyCodeService.UpdateAsync( + verifyCodeCreatedEvent.Data.Adapt() with { Status = VerifyCodeStatues.Sent }); + _logger.Info($"{nameof(IVerifyCodeService)}.{nameof(IVerifyCodeService.UpdateAsync)} {Ln.已完成}"); + } +} \ No newline at end of file diff --git a/src/frontend/admin/.editorconfig b/src/frontend/admin/.editorconfig new file mode 100644 index 00000000..b79317dd --- /dev/null +++ b/src/frontend/admin/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +ij_xml_attribute_wrap = off +ij_xml_text_wrap = off +indent_size = 4 +indent_style = space +insert_final_newline = false +trim_trailing_whitespace = true \ No newline at end of file diff --git a/src/frontend/admin/.eslintrc.js b/src/frontend/admin/.eslintrc.js new file mode 100644 index 00000000..20c5028f --- /dev/null +++ b/src/frontend/admin/.eslintrc.js @@ -0,0 +1,47 @@ +module.exports = { + root: true, + extends: ['plugin:vue/vue3-essential', 'eslint:recommended', '@vue/eslint-config-prettier'], + rules: { + 'vue/multi-word-component-names': [ + 'off', + { + ignores: [], + }, + ], + 'vue/attributes-order': [ + 'error', + { + order: [ + 'DEFINITION', + 'LIST_RENDERING', + 'CONDITIONALS', + 'RENDER_MODIFIERS', + 'GLOBAL', + ['UNIQUE', 'SLOT'], + 'TWO_WAY_BINDING', + 'OTHER_DIRECTIVES', + 'OTHER_ATTR', + 'EVENTS', + 'CONTENT', + ], + alphabetical: false, + }, + ], + 'vue/no-unused-vars': ['warn'], + 'no-return-await': ['warn'], + 'no-multiple-empty-lines': ['warn'], + 'no-inner-declarations': ['off'], + eqeqeq: 'error', + }, + env: { + browser: true, + es2021: true, + node: true, + 'vue/setup-compiler-macros': true, + }, + globals: { + defineOptions: 'writable', + defineProps: 'readonly', + NodeJS: true, + }, +} \ No newline at end of file diff --git a/src/frontend/admin/.gitignore b/src/frontend/admin/.gitignore new file mode 100644 index 00000000..403adbc1 --- /dev/null +++ b/src/frontend/admin/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules +/dist + + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/src/frontend/admin/.prettierignore b/src/frontend/admin/.prettierignore new file mode 100644 index 00000000..7bf12a5a --- /dev/null +++ b/src/frontend/admin/.prettierignore @@ -0,0 +1,3 @@ +# 忽略格式化文件 (根据项目需要自行添加) +node_modules +dist \ No newline at end of file diff --git a/src/frontend/admin/.prettierrc b/src/frontend/admin/.prettierrc new file mode 100644 index 00000000..2df9eb10 --- /dev/null +++ b/src/frontend/admin/.prettierrc @@ -0,0 +1,10 @@ +{ + "tabWidth": 4, + "useTabs": false, + "semi": false, + "singleQuote": true, + "trailingComma": "all", + "bracketSameLine": true, + "printWidth": 150, + "endOfLine": "auto" +} \ No newline at end of file diff --git a/src/frontend/admin/LICENSE b/src/frontend/admin/LICENSE new file mode 100644 index 00000000..596e09bb --- /dev/null +++ b/src/frontend/admin/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 sakuya + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/frontend/admin/README.md b/src/frontend/admin/README.md new file mode 100644 index 00000000..ec4a0b4f --- /dev/null +++ b/src/frontend/admin/README.md @@ -0,0 +1,30 @@ +原版仓库 [SCUI](https://gitee.com/lolicode/scui) + +1. 本仓库只是将 vue-cli 替换为 vite(vite版本与官网),只做了为适配 vite 的必要修改,其它仍与原版一致(除部分静态资源)。 +2. 和原SCUI不同的一点就是加入了eslint和prettier,stylelint没必要 + +### 使用 yarn + +``` +# 进入项目目录 +cd ./scui_vite + +# 安装依赖 +yarn + +# 启动项目(开发模式) +yarn dev +``` + +### 使用 npm + +``` +# 进入项目目录 +cd ./scui_vite + +# 安装依赖 +npm i + +# 启动项目(开发模式) +npm run dev +``` \ No newline at end of file diff --git a/src/frontend/admin/babel.config.js b/src/frontend/admin/babel.config.js new file mode 100644 index 00000000..e813dbcb --- /dev/null +++ b/src/frontend/admin/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ['@vue/cli-plugin-babel/preset'], +} \ No newline at end of file diff --git a/src/frontend/admin/index.html b/src/frontend/admin/index.html new file mode 100644 index 00000000..e8e3f08d --- /dev/null +++ b/src/frontend/admin/index.html @@ -0,0 +1,191 @@ + + + + + + + + SCUI + + + + + +
+
+ +
+
SCUI
+
+ +
+ + +
+

当前使用的浏览器内核版本过低 :(

+

+ 当前版本:-- -- +

+

+ 最低版本要求:Chrome 71+、Firefox 65+、Safari 12+、Edge 97+。 +

+

+ 请升级浏览器版本,或更换现代浏览器,如果你使用的是双核浏览器,请切换到极速/高速模式。 +

+
+ + + \ No newline at end of file diff --git a/src/frontend/admin/jsconfig.json b/src/frontend/admin/jsconfig.json new file mode 100644 index 00000000..8f62680f --- /dev/null +++ b/src/frontend/admin/jsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "esnext", + "baseUrl": "./", + "moduleResolution": "node", + "paths": { + "@/*": [ + "src/*" + ] + }, + "lib": [ + "esnext", + "dom", + "dom.iterable", + "scripthost" + ] + } +} \ No newline at end of file diff --git a/src/frontend/admin/package.json b/src/frontend/admin/package.json new file mode 100644 index 00000000..bbdf2775 --- /dev/null +++ b/src/frontend/admin/package.json @@ -0,0 +1,53 @@ +{ + "name": "scui", + "version": "1.6.6", + "private": true, + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "prettier": "prettier --write ." + }, + "dependencies": { + "@element-plus/icons-vue": "^2.1.0", + "@tinymce/tinymce-vue": "^5.1.0", + "axios": "^1.4.0", + "codemirror": "^5.65.5", + "core-js": "^3.32.0", + "cropperjs": "^1.5.13", + "crypto-js": "^4.1.1", + "echarts": "^5.4.3", + "element-plus": "^2.3.8", + "json-bigint": "^1.0.0", + "json5-to-table": "^0.1.8", + "nprogress": "^0.2.0", + "pinyin-match": "^1.2.4", + "qrcodejs2": "^0.0.2", + "sortablejs": "^1.15.0", + "tinymce": "^6.6.0", + "vue": "^3.3.4", + "vue-i18n": "^9.2.2", + "vue-json-viewer": "^3.0.4", + "vue-router": "^4.2.4", + "vuedraggable": "^4.0.3", + "vuex": "^4.1.0", + "xgplayer": "^3.0.7", + "xgplayer-hls": "^3.0.7" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^4.2.3", + "@vue/eslint-config-prettier": "^8.0.0", + "eslint": "^8.46.0", + "eslint-plugin-vue": "^9.16.1", + "prettier": "^3.0.0", + "sass": "^1.64.2", + "terser": "^5.19.2", + "vite": "^4.4.7" + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not dead", + "not ie 11" + ] +} \ No newline at end of file diff --git a/src/frontend/admin/public/code/list/index.vue b/src/frontend/admin/public/code/list/index.vue new file mode 100644 index 00000000..842c1b0c --- /dev/null +++ b/src/frontend/admin/public/code/list/index.vue @@ -0,0 +1,185 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/public/code/list/save.vue b/src/frontend/admin/public/code/list/save.vue new file mode 100644 index 00000000..733122b5 --- /dev/null +++ b/src/frontend/admin/public/code/list/save.vue @@ -0,0 +1,87 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/public/config.js b/src/frontend/admin/public/config.js new file mode 100644 index 00000000..c7956d6c --- /dev/null +++ b/src/frontend/admin/public/config.js @@ -0,0 +1,9 @@ +// 此文件非必要,在生产环境下此文件配置可覆盖运行配置,开发环境下不起效 +// 详情见 src/config/index.js + +const APP_CONFIG = { + //标题 + //APP_NAME: "SCUI", + //接口地址,如遇跨域需使用nginx代理 + //API_URL: "https://www.fastmock.site/mock/5039c4361c39a7e3252c5b55971f1bd3/api" +} \ No newline at end of file diff --git a/src/frontend/admin/public/favicon.ico b/src/frontend/admin/public/favicon.ico new file mode 100644 index 00000000..23156d86 Binary files /dev/null and b/src/frontend/admin/public/favicon.ico differ diff --git a/src/frontend/admin/public/tinymce/langs/zh_CN.js b/src/frontend/admin/public/tinymce/langs/zh_CN.js new file mode 100644 index 00000000..0eee2a79 --- /dev/null +++ b/src/frontend/admin/public/tinymce/langs/zh_CN.js @@ -0,0 +1,426 @@ +tinymce.addI18n('zh_CN', { + Redo: '\u91cd\u505a', + Undo: '\u64a4\u9500', + Cut: '\u526a\u5207', + Copy: '\u590d\u5236', + Paste: '\u7c98\u8d34', + 'Select all': '\u5168\u9009', + 'New document': '\u65b0\u6587\u4ef6', + Ok: '\u786e\u5b9a', + Cancel: '\u53d6\u6d88', + 'Visual aids': '\u7f51\u683c\u7ebf', + Bold: '\u7c97\u4f53', + Italic: '\u659c\u4f53', + Underline: '\u4e0b\u5212\u7ebf', + Strikethrough: '\u5220\u9664\u7ebf', + Superscript: '\u4e0a\u6807', + Subscript: '\u4e0b\u6807', + 'Clear formatting': '\u6e05\u9664\u683c\u5f0f', + 'Align left': '\u5de6\u8fb9\u5bf9\u9f50', + 'Align center': '\u4e2d\u95f4\u5bf9\u9f50', + 'Align right': '\u53f3\u8fb9\u5bf9\u9f50', + Justify: '\u4e24\u7aef\u5bf9\u9f50', + 'Bullet list': '\u9879\u76ee\u7b26\u53f7', + 'Numbered list': '\u7f16\u53f7\u5217\u8868', + 'Decrease indent': '\u51cf\u5c11\u7f29\u8fdb', + 'Increase indent': '\u589e\u52a0\u7f29\u8fdb', + Close: '\u5173\u95ed', + Formats: '\u683c\u5f0f', + "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.": + '\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u6253\u5f00\u526a\u8d34\u677f\uff0c\u8bf7\u4f7f\u7528Ctrl+X/C/V\u7b49\u5feb\u6377\u952e\u3002', + Headers: '\u6807\u9898', + 'Header 1': '\u6807\u98981', + 'Header 2': '\u6807\u98982', + 'Header 3': '\u6807\u98983', + 'Header 4': '\u6807\u98984', + 'Header 5': '\u6807\u98985', + 'Header 6': '\u6807\u98986', + Headings: '\u6807\u9898', + 'Heading 1': '\u6807\u98981', + 'Heading 2': '\u6807\u98982', + 'Heading 3': '\u6807\u98983', + 'Heading 4': '\u6807\u98984', + 'Heading 5': '\u6807\u98985', + 'Heading 6': '\u6807\u98986', + Preformatted: '\u9884\u5148\u683c\u5f0f\u5316\u7684', + Div: 'Div', + Pre: 'Pre', + Code: '\u4ee3\u7801', + Paragraph: '\u6bb5\u843d', + Blockquote: '\u5f15\u6587\u533a\u5757', + Inline: '\u6587\u672c', + Blocks: '\u57fa\u5757', + 'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.': + '\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002', + Fonts: '\u5b57\u4f53', + 'Font Sizes': '\u5b57\u53f7', + Class: '\u7c7b\u578b', + 'Browse for an image': '\u6d4f\u89c8\u56fe\u50cf', + OR: '\u6216', + 'Drop an image here': '\u62d6\u653e\u4e00\u5f20\u56fe\u50cf\u81f3\u6b64', + Upload: '\u4e0a\u4f20', + Block: '\u5757', + Align: '\u5bf9\u9f50', + Default: '\u9ed8\u8ba4', + Circle: '\u7a7a\u5fc3\u5706', + Disc: '\u5b9e\u5fc3\u5706', + Square: '\u65b9\u5757', + 'Lower Alpha': '\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd', + 'Lower Greek': '\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd', + 'Lower Roman': '\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd', + 'Upper Alpha': '\u5927\u5199\u82f1\u6587\u5b57\u6bcd', + 'Upper Roman': '\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd', + 'Anchor...': '\u951a\u70b9...', + Name: '\u540d\u79f0', + Id: '\u6807\u8bc6\u7b26', + 'Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.': + '\u6807\u8bc6\u7b26\u5e94\u8be5\u4ee5\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u8ddf\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002', + 'You have unsaved changes are you sure you want to navigate away?': + '\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f', + 'Restore last draft': '\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f', + 'Special character...': '\u7279\u6b8a\u5b57\u7b26...', + 'Source code': '\u6e90\u4ee3\u7801', + 'Insert/Edit code sample': '\u63d2\u5165/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b', + Language: '\u8bed\u8a00', + 'Code sample...': '\u793a\u4f8b\u4ee3\u7801...', + 'Color Picker': '\u9009\u8272\u5668', + R: 'R', + G: 'G', + B: 'B', + 'Left to right': '\u4ece\u5de6\u5230\u53f3', + 'Right to left': '\u4ece\u53f3\u5230\u5de6', + 'Emoticons...': '\u8868\u60c5\u7b26\u53f7...', + 'Metadata and Document Properties': '\u5143\u6570\u636e\u548c\u6587\u6863\u5c5e\u6027', + Title: '\u6807\u9898', + Keywords: '\u5173\u952e\u8bcd', + Description: '\u63cf\u8ff0', + Robots: '\u673a\u5668\u4eba', + Author: '\u4f5c\u8005', + Encoding: '\u7f16\u7801', + Fullscreen: '\u5168\u5c4f', + Action: '\u64cd\u4f5c', + Shortcut: '\u5feb\u6377\u952e', + Help: '\u5e2e\u52a9', + Address: '\u5730\u5740', + 'Focus to menubar': '\u79fb\u52a8\u7126\u70b9\u5230\u83dc\u5355\u680f', + 'Focus to toolbar': '\u79fb\u52a8\u7126\u70b9\u5230\u5de5\u5177\u680f', + 'Focus to element path': '\u79fb\u52a8\u7126\u70b9\u5230\u5143\u7d20\u8def\u5f84', + 'Focus to contextual toolbar': '\u79fb\u52a8\u7126\u70b9\u5230\u4e0a\u4e0b\u6587\u83dc\u5355', + 'Insert link (if link plugin activated)': '\u63d2\u5165\u94fe\u63a5 (\u5982\u679c\u94fe\u63a5\u63d2\u4ef6\u5df2\u6fc0\u6d3b)', + 'Save (if save plugin activated)': '\u4fdd\u5b58(\u5982\u679c\u4fdd\u5b58\u63d2\u4ef6\u5df2\u6fc0\u6d3b)', + 'Find (if searchreplace plugin activated)': '\u67e5\u627e(\u5982\u679c\u67e5\u627e\u66ff\u6362\u63d2\u4ef6\u5df2\u6fc0\u6d3b)', + 'Plugins installed ({0}):': '\u5df2\u5b89\u88c5\u63d2\u4ef6 ({0}):', + 'Premium plugins:': '\u4f18\u79c0\u63d2\u4ef6\uff1a', + 'Learn more...': '\u4e86\u89e3\u66f4\u591a...', + 'You are using {0}': '\u4f60\u6b63\u5728\u4f7f\u7528 {0}', + Plugins: '\u63d2\u4ef6', + 'Handy Shortcuts': '\u5feb\u6377\u952e', + 'Horizontal line': '\u6c34\u5e73\u5206\u5272\u7ebf', + 'Insert/edit image': '\u63d2\u5165/\u7f16\u8f91\u56fe\u7247', + 'Image description': '\u56fe\u7247\u63cf\u8ff0', + Source: '\u5730\u5740', + Dimensions: '\u5927\u5c0f', + 'Constrain proportions': '\u4fdd\u6301\u7eb5\u6a2a\u6bd4', + General: '\u666e\u901a', + Advanced: '\u9ad8\u7ea7', + Style: '\u6837\u5f0f', + 'Vertical space': '\u5782\u76f4\u8fb9\u8ddd', + 'Horizontal space': '\u6c34\u5e73\u8fb9\u8ddd', + Border: '\u8fb9\u6846', + 'Insert image': '\u63d2\u5165\u56fe\u7247', + 'Image...': '\u56fe\u7247...', + 'Image list': '\u56fe\u7247\u5217\u8868', + 'Rotate counterclockwise': '\u9006\u65f6\u9488\u65cb\u8f6c', + 'Rotate clockwise': '\u987a\u65f6\u9488\u65cb\u8f6c', + 'Flip vertically': '\u5782\u76f4\u7ffb\u8f6c', + 'Flip horizontally': '\u6c34\u5e73\u7ffb\u8f6c', + 'Edit image': '\u7f16\u8f91\u56fe\u7247', + 'Image options': '\u56fe\u7247\u9009\u9879', + 'Zoom in': '\u653e\u5927', + 'Zoom out': '\u7f29\u5c0f', + Crop: '\u88c1\u526a', + Resize: '\u8c03\u6574\u5927\u5c0f', + Orientation: '\u65b9\u5411', + Brightness: '\u4eae\u5ea6', + Sharpen: '\u9510\u5316', + Contrast: '\u5bf9\u6bd4\u5ea6', + 'Color levels': '\u989c\u8272\u5c42\u6b21', + Gamma: '\u4f3d\u9a6c\u503c', + Invert: '\u53cd\u8f6c', + Apply: '\u5e94\u7528', + Back: '\u540e\u9000', + 'Insert date/time': '\u63d2\u5165\u65e5\u671f/\u65f6\u95f4', + 'Date/time': '\u65e5\u671f/\u65f6\u95f4', + 'Insert/Edit Link': '\u63d2\u5165/\u7f16\u8f91\u94fe\u63a5', + 'Insert/edit link': '\u63d2\u5165/\u7f16\u8f91\u94fe\u63a5', + 'Text to display': '\u663e\u793a\u6587\u5b57', + Url: '\u5730\u5740', + 'Open link in...': '\u94fe\u63a5\u6253\u5f00\u4f4d\u7f6e...', + 'Current window': '\u5f53\u524d\u7a97\u53e3', + None: '\u65e0', + 'New window': '\u5728\u65b0\u7a97\u53e3\u6253\u5f00', + 'Remove link': '\u5220\u9664\u94fe\u63a5', + Anchors: '\u951a\u70b9', + 'Link...': '\u94fe\u63a5...', + 'Paste or type a link': '\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5', + 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?': + '\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7f00\u5417\uff1f', + 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?': + '\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp://:\u524d\u7f00\u5417\uff1f', + 'Link list': '\u94fe\u63a5\u5217\u8868', + 'Insert video': '\u63d2\u5165\u89c6\u9891', + 'Insert/edit video': '\u63d2\u5165/\u7f16\u8f91\u89c6\u9891', + 'Insert/edit media': '\u63d2\u5165/\u7f16\u8f91\u5a92\u4f53', + 'Alternative source': '\u955c\u50cf', + 'Alternative source URL': '\u66ff\u4ee3\u6765\u6e90\u7f51\u5740', + 'Media poster (Image URL)': '\u5c01\u9762(\u56fe\u7247\u5730\u5740)', + 'Paste your embed code below:': '\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:', + Embed: '\u5185\u5d4c', + 'Media...': '\u591a\u5a92\u4f53...', + 'Nonbreaking space': '\u4e0d\u95f4\u65ad\u7a7a\u683c', + 'Page break': '\u5206\u9875\u7b26', + 'Paste as text': '\u7c98\u8d34\u4e3a\u6587\u672c', + Preview: '\u9884\u89c8', + 'Print...': '\u6253\u5370...', + Save: '\u4fdd\u5b58', + Find: '\u67e5\u627e', + 'Replace with': '\u66ff\u6362\u4e3a', + Replace: '\u66ff\u6362', + 'Replace all': '\u5168\u90e8\u66ff\u6362', + Previous: '\u4e0a\u4e00\u4e2a', + Next: '\u4e0b\u4e00\u4e2a', + 'Find and replace...': '\u67e5\u627e\u5e76\u66ff\u6362...', + 'Could not find the specified string.': '\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9.', + 'Match case': '\u533a\u5206\u5927\u5c0f\u5199', + 'Find whole words only': '\u5168\u5b57\u5339\u914d', + 'Spell check': '\u62fc\u5199\u68c0\u67e5', + Ignore: '\u5ffd\u7565', + 'Ignore all': '\u5168\u90e8\u5ffd\u7565', + Finish: '\u5b8c\u6210', + 'Add to Dictionary': '\u6dfb\u52a0\u5230\u5b57\u5178', + 'Insert table': '\u63d2\u5165\u8868\u683c', + 'Table properties': '\u8868\u683c\u5c5e\u6027', + 'Delete table': '\u5220\u9664\u8868\u683c', + Cell: '\u5355\u5143\u683c', + Row: '\u884c', + Column: '\u5217', + 'Cell properties': '\u5355\u5143\u683c\u5c5e\u6027', + 'Merge cells': '\u5408\u5e76\u5355\u5143\u683c', + 'Split cell': '\u62c6\u5206\u5355\u5143\u683c', + 'Insert row before': '\u5728\u4e0a\u65b9\u63d2\u5165', + 'Insert row after': '\u5728\u4e0b\u65b9\u63d2\u5165', + 'Delete row': '\u5220\u9664\u884c', + 'Row properties': '\u884c\u5c5e\u6027', + 'Cut row': '\u526a\u5207\u884c', + 'Copy row': '\u590d\u5236\u884c', + 'Paste row before': '\u7c98\u8d34\u5230\u4e0a\u65b9', + 'Paste row after': '\u7c98\u8d34\u5230\u4e0b\u65b9', + 'Insert column before': '\u5728\u5de6\u4fa7\u63d2\u5165', + 'Insert column after': '\u5728\u53f3\u4fa7\u63d2\u5165', + 'Delete column': '\u5220\u9664\u5217', + Cols: '\u5217', + Rows: '\u884c', + Width: '\u5bbd', + Height: '\u9ad8', + 'Cell spacing': '\u5355\u5143\u683c\u5916\u95f4\u8ddd', + 'Cell padding': '\u5355\u5143\u683c\u5185\u8fb9\u8ddd', + 'Show caption': '\u663e\u793a\u6807\u9898', + Left: '\u5de6\u5bf9\u9f50', + Center: '\u5c45\u4e2d', + Right: '\u53f3\u5bf9\u9f50', + 'Cell type': '\u5355\u5143\u683c\u7c7b\u578b', + Scope: '\u8303\u56f4', + Alignment: '\u5bf9\u9f50\u65b9\u5f0f', + 'H Align': '\u6c34\u5e73\u5bf9\u9f50', + 'V Align': '\u5782\u76f4\u5bf9\u9f50', + Top: '\u9876\u90e8\u5bf9\u9f50', + Middle: '\u5782\u76f4\u5c45\u4e2d', + Bottom: '\u5e95\u90e8\u5bf9\u9f50', + 'Header cell': '\u8868\u5934\u5355\u5143\u683c', + 'Row group': '\u884c\u7ec4', + 'Column group': '\u5217\u7ec4', + 'Row type': '\u884c\u7c7b\u578b', + Header: '\u8868\u5934', + Body: '\u8868\u4f53', + Footer: '\u8868\u5c3e', + 'Border color': '\u8fb9\u6846\u989c\u8272', + 'Insert template...': '\u63d2\u5165\u6a21\u677f...', + Templates: '\u6a21\u677f', + Template: '\u6a21\u677f', + 'Text color': '\u6587\u5b57\u989c\u8272', + 'Background color': '\u80cc\u666f\u8272', + 'Custom...': '\u81ea\u5b9a\u4e49...', + 'Custom color': '\u81ea\u5b9a\u4e49\u989c\u8272', + 'No color': '\u65e0', + 'Remove color': '\u79fb\u9664\u989c\u8272', + 'Table of Contents': '\u5185\u5bb9\u5217\u8868', + 'Show blocks': '\u663e\u793a\u533a\u5757\u8fb9\u6846', + 'Show invisible characters': '\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26', + 'Word count': '\u5b57\u6570', + Count: '\u8ba1\u6570', + Document: '\u6587\u6863', + Selection: '\u9009\u62e9', + Words: '\u5355\u8bcd', + 'Words: {0}': '\u5b57\u6570\uff1a{0}', + '{0} words': '{0} \u5b57', + File: '\u6587\u4ef6', + Edit: '\u7f16\u8f91', + Insert: '\u63d2\u5165', + View: '\u89c6\u56fe', + Format: '\u683c\u5f0f', + Table: '\u8868\u683c', + Tools: '\u5de5\u5177', + 'Powered by {0}': '\u7531{0}\u9a71\u52a8', + 'Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help': + '\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9', + 'Image title': '\u56fe\u7247\u6807\u9898', + 'Border width': '\u8fb9\u6846\u5bbd\u5ea6', + 'Border style': '\u8fb9\u6846\u6837\u5f0f', + Error: '\u9519\u8bef', + Warn: '\u8b66\u544a', + Valid: '\u6709\u6548', + 'To open the popup, press Shift+Enter': '\u6309Shitf+Enter\u952e\u6253\u5f00\u5bf9\u8bdd\u6846', + 'Rich Text Area. Press ALT-0 for help.': '\u7f16\u8f91\u533a\u3002\u6309Alt+0\u952e\u6253\u5f00\u5e2e\u52a9\u3002', + 'System Font': '\u7cfb\u7edf\u5b57\u4f53', + 'Failed to upload image: {0}': '\u56fe\u7247\u4e0a\u4f20\u5931\u8d25: {0}', + 'Failed to load plugin: {0} from url {1}': '\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25: {0} \u6765\u81ea\u94fe\u63a5 {1}', + 'Failed to load plugin url: {0}': '\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25 \u94fe\u63a5: {0}', + 'Failed to initialize plugin: {0}': '\u63d2\u4ef6\u521d\u59cb\u5316\u5931\u8d25: {0}', + example: '\u793a\u4f8b', + Search: '\u641c\u7d22', + All: '\u5168\u90e8', + Currency: '\u8d27\u5e01', + Text: '\u6587\u5b57', + Quotations: '\u5f15\u7528', + Mathematical: '\u6570\u5b66', + 'Extended Latin': '\u62c9\u4e01\u8bed\u6269\u5145', + Symbols: '\u7b26\u53f7', + Arrows: '\u7bad\u5934', + 'User Defined': '\u81ea\u5b9a\u4e49', + 'dollar sign': '\u7f8e\u5143\u7b26\u53f7', + 'currency sign': '\u8d27\u5e01\u7b26\u53f7', + 'euro-currency sign': '\u6b27\u5143\u7b26\u53f7', + 'colon sign': '\u5192\u53f7', + 'cruzeiro sign': '\u514b\u9c81\u8d5b\u7f57\u5e01\u7b26\u53f7', + 'french franc sign': '\u6cd5\u90ce\u7b26\u53f7', + 'lira sign': '\u91cc\u62c9\u7b26\u53f7', + 'mill sign': '\u5bc6\u5c14\u7b26\u53f7', + 'naira sign': '\u5948\u62c9\u7b26\u53f7', + 'peseta sign': '\u6bd4\u585e\u5854\u7b26\u53f7', + 'rupee sign': '\u5362\u6bd4\u7b26\u53f7', + 'won sign': '\u97e9\u5143\u7b26\u53f7', + 'new sheqel sign': '\u65b0\u8c22\u514b\u5c14\u7b26\u53f7', + 'dong sign': '\u8d8a\u5357\u76fe\u7b26\u53f7', + 'kip sign': '\u8001\u631d\u57fa\u666e\u7b26\u53f7', + 'tugrik sign': '\u56fe\u683c\u91cc\u514b\u7b26\u53f7', + 'drachma sign': '\u5fb7\u62c9\u514b\u9a6c\u7b26\u53f7', + 'german penny symbol': '\u5fb7\u56fd\u4fbf\u58eb\u7b26\u53f7', + 'peso sign': '\u6bd4\u7d22\u7b26\u53f7', + 'guarani sign': '\u74dc\u62c9\u5c3c\u7b26\u53f7', + 'austral sign': '\u6fb3\u5143\u7b26\u53f7', + 'hryvnia sign': '\u683c\u91cc\u592b\u5c3c\u4e9a\u7b26\u53f7', + 'cedi sign': '\u585e\u5730\u7b26\u53f7', + 'livre tournois sign': '\u91cc\u5f17\u5f17\u5c14\u7b26\u53f7', + 'spesmilo sign': 'spesmilo\u7b26\u53f7', + 'tenge sign': '\u575a\u6208\u7b26\u53f7', + 'indian rupee sign': '\u5370\u5ea6\u5362\u6bd4', + 'turkish lira sign': '\u571f\u8033\u5176\u91cc\u62c9', + 'nordic mark sign': '\u5317\u6b27\u9a6c\u514b', + 'manat sign': '\u9a6c\u7eb3\u7279\u7b26\u53f7', + 'ruble sign': '\u5362\u5e03\u7b26\u53f7', + 'yen character': '\u65e5\u5143\u5b57\u6837', + 'yuan character': '\u4eba\u6c11\u5e01\u5143\u5b57\u6837', + 'yuan character, in hong kong and taiwan': '\u5143\u5b57\u6837\uff08\u6e2f\u53f0\u5730\u533a\uff09', + 'yen/yuan character variant one': '\u5143\u5b57\u6837\uff08\u5927\u5199\uff09', + 'Loading emoticons...': '\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7...', + 'Could not load emoticons': '\u4e0d\u80fd\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7', + People: '\u4eba\u7c7b', + 'Animals and Nature': '\u52a8\u7269\u548c\u81ea\u7136', + 'Food and Drink': '\u98df\u7269\u548c\u996e\u54c1', + Activity: '\u6d3b\u52a8', + 'Travel and Places': '\u65c5\u6e38\u548c\u5730\u70b9', + Objects: '\u7269\u4ef6', + Flags: '\u65d7\u5e1c', + Characters: '\u5b57\u7b26', + 'Characters (no spaces)': '\u5b57\u7b26(\u65e0\u7a7a\u683c)', + '{0} characters': '{0} \u4e2a\u5b57\u7b26', + 'Error: Form submit field collision.': '\u9519\u8bef: \u8868\u5355\u63d0\u4ea4\u5b57\u6bb5\u51b2\u7a81\u3002', + 'Error: No form element found.': '\u9519\u8bef: \u6ca1\u6709\u8868\u5355\u63a7\u4ef6\u3002', + Update: '\u66f4\u65b0', + 'Color swatch': '\u989c\u8272\u6837\u672c', + Turquoise: '\u9752\u7eff\u8272', + Green: '\u7eff\u8272', + Blue: '\u84dd\u8272', + Purple: '\u7d2b\u8272', + 'Navy Blue': '\u6d77\u519b\u84dd', + 'Dark Turquoise': '\u6df1\u84dd\u7eff\u8272', + 'Dark Green': '\u6df1\u7eff\u8272', + 'Medium Blue': '\u4e2d\u84dd\u8272', + 'Medium Purple': '\u4e2d\u7d2b\u8272', + 'Midnight Blue': '\u6df1\u84dd\u8272', + Yellow: '\u9ec4\u8272', + Orange: '\u6a59\u8272', + Red: '\u7ea2\u8272', + 'Light Gray': '\u6d45\u7070\u8272', + Gray: '\u7070\u8272', + 'Dark Yellow': '\u6697\u9ec4\u8272', + 'Dark Orange': '\u6df1\u6a59\u8272', + 'Dark Red': '\u6df1\u7ea2\u8272', + 'Medium Gray': '\u4e2d\u7070\u8272', + 'Dark Gray': '\u6df1\u7070\u8272', + 'Light Green': '\u6d45\u7eff\u8272', + 'Light Yellow': '\u6d45\u9ec4\u8272', + 'Light Red': '\u6d45\u7ea2\u8272', + 'Light Purple': '\u6d45\u7d2b\u8272', + 'Light Blue': '\u6d45\u84dd\u8272', + 'Dark Purple': '\u6df1\u7d2b\u8272', + 'Dark Blue': '\u6df1\u84dd\u8272', + Black: '\u9ed1\u8272', + White: '\u767d\u8272', + 'Switch to or from fullscreen mode': '\u5207\u6362\u5168\u5c4f\u6a21\u5f0f', + 'Open help dialog': '\u6253\u5f00\u5e2e\u52a9\u5bf9\u8bdd\u6846', + history: '\u5386\u53f2', + styles: '\u6837\u5f0f', + formatting: '\u683c\u5f0f\u5316', + alignment: '\u5bf9\u9f50', + indentation: '\u7f29\u8fdb', + 'permanent pen': '\u8bb0\u53f7\u7b14', + comments: '\u5907\u6ce8', + 'Format Painter': '\u683c\u5f0f\u5237', + 'Insert/edit iframe': '\u63d2\u5165/\u7f16\u8f91\u6846\u67b6', + Capitalization: '\u5927\u5199', + lowercase: '\u5c0f\u5199', + UPPERCASE: '\u5927\u5199', + 'Title Case': '\u9996\u5b57\u6bcd\u5927\u5199', + 'Permanent Pen Properties': '\u6c38\u4e45\u7b14\u5c5e\u6027', + 'Permanent pen properties...': '\u6c38\u4e45\u7b14\u5c5e\u6027...', + Font: '\u5b57\u4f53', + Size: '\u5b57\u53f7', + 'More...': '\u66f4\u591a...', + 'Spellcheck Language': '\u62fc\u5199\u68c0\u67e5\u8bed\u8a00', + 'Select...': '\u9009\u62e9...', + Preferences: '\u9996\u9009\u9879', + Yes: '\u662f', + No: '\u5426', + 'Keyboard Navigation': '\u952e\u76d8\u6307\u5f15', + Version: '\u7248\u672c', + Anchor: '\u951a\u70b9', + 'Special character': '\u7279\u6b8a\u7b26\u53f7', + 'Code sample': '\u4ee3\u7801\u793a\u4f8b', + Color: '\u989c\u8272', + Emoticons: '\u8868\u60c5', + 'Document properties': '\u6587\u6863\u5c5e\u6027', + Image: '\u56fe\u7247', + 'Insert link': '\u63d2\u5165\u94fe\u63a5', + Target: '\u6253\u5f00\u65b9\u5f0f', + Link: '\u94fe\u63a5', + Poster: '\u5c01\u9762', + Media: '\u5a92\u4f53', + Print: '\u6253\u5370', + Prev: '\u4e0a\u4e00\u4e2a', + 'Find and replace': '\u67e5\u627e\u548c\u66ff\u6362', + 'Whole words': '\u5168\u5b57\u5339\u914d', + Spellcheck: '\u62fc\u5199\u68c0\u67e5', + Caption: '\u6807\u9898', + 'Insert template': '\u63d2\u5165\u6a21\u677f', +}) \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/dark/content.css b/src/frontend/admin/public/tinymce/skins/content/dark/content.css new file mode 100644 index 00000000..507ae6f4 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/dark/content.css @@ -0,0 +1,79 @@ +body { + background-color: #222f3e; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem; +} + +a { + color: #4099ff; +} + +table { + border-collapse: collapse; +} + +/* Apply a default padding if legacy cellpadding attribute is missing */ +table:not([cellpadding]) th, +table:not([cellpadding]) td { + padding: 0.4rem; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-width']) th, +table[border]:not([border='0']):not([style*='border-width']) td { + border-width: 1px; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-style']) th, +table[border]:not([border='0']):not([style*='border-style']) td { + border-style: solid; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-color']) th, +table[border]:not([border='0']):not([style*='border-color']) td { + border-color: #6d737b; +} + +figure { + display: table; + margin: 1rem auto; +} + +figure figcaption { + color: #8a8f97; + display: block; + margin-top: 0.25rem; + text-align: center; +} + +hr { + border-color: #6d737b; + border-style: solid; + border-width: 1px 0 0 0; +} + +code { + background-color: #6d737b; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} + +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #6d737b; + margin-left: 1.5rem; + padding-left: 1rem; +} + +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #6d737b; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/dark/content.min.css b/src/frontend/admin/public/tinymce/skins/content/dark/content.min.css new file mode 100644 index 00000000..89239689 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/dark/content.min.css @@ -0,0 +1,60 @@ +body { + background-color: #222f3e; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem; +} +a { + color: #4099ff; +} +table { + border-collapse: collapse; +} +table:not([cellpadding]) td, +table:not([cellpadding]) th { + padding: 0.4rem; +} +table[border]:not([border='0']):not([style*='border-width']) td, +table[border]:not([border='0']):not([style*='border-width']) th { + border-width: 1px; +} +table[border]:not([border='0']):not([style*='border-style']) td, +table[border]:not([border='0']):not([style*='border-style']) th { + border-style: solid; +} +table[border]:not([border='0']):not([style*='border-color']) td, +table[border]:not([border='0']):not([style*='border-color']) th { + border-color: #6d737b; +} +figure { + display: table; + margin: 1rem auto; +} +figure figcaption { + color: #8a8f97; + display: block; + margin-top: 0.25rem; + text-align: center; +} +hr { + border-color: #6d737b; + border-style: solid; + border-width: 1px 0 0 0; +} +code { + background-color: #6d737b; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #6d737b; + margin-left: 1.5rem; + padding-left: 1rem; +} +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #6d737b; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/default/content.css b/src/frontend/admin/public/tinymce/skins/content/default/content.css new file mode 100644 index 00000000..7fe5ff9b --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/default/content.css @@ -0,0 +1,73 @@ +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem; +} + +table { + border-collapse: collapse; +} + +/* Apply a default padding if legacy cellpadding attribute is missing */ +table:not([cellpadding]) th, +table:not([cellpadding]) td { + padding: 0.4rem; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-width']) th, +table[border]:not([border='0']):not([style*='border-width']) td { + border-width: 1px; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-style']) th, +table[border]:not([border='0']):not([style*='border-style']) td { + border-style: solid; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-color']) th, +table[border]:not([border='0']):not([style*='border-color']) td { + border-color: #ccc; +} + +figure { + display: table; + margin: 1rem auto; +} + +figure figcaption { + color: #999; + display: block; + margin-top: 0.25rem; + text-align: center; +} + +hr { + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0 0; +} + +code { + background-color: #e8e8e8; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} + +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #ccc; + margin-left: 1.5rem; + padding-left: 1rem; +} + +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #ccc; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/default/content.min.css b/src/frontend/admin/public/tinymce/skins/content/default/content.min.css new file mode 100644 index 00000000..cca44e14 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/default/content.min.css @@ -0,0 +1,55 @@ +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem; +} +table { + border-collapse: collapse; +} +table:not([cellpadding]) td, +table:not([cellpadding]) th { + padding: 0.4rem; +} +table[border]:not([border='0']):not([style*='border-width']) td, +table[border]:not([border='0']):not([style*='border-width']) th { + border-width: 1px; +} +table[border]:not([border='0']):not([style*='border-style']) td, +table[border]:not([border='0']):not([style*='border-style']) th { + border-style: solid; +} +table[border]:not([border='0']):not([style*='border-color']) td, +table[border]:not([border='0']):not([style*='border-color']) th { + border-color: #ccc; +} +figure { + display: table; + margin: 1rem auto; +} +figure figcaption { + color: #999; + display: block; + margin-top: 0.25rem; + text-align: center; +} +hr { + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0 0; +} +code { + background-color: #e8e8e8; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #ccc; + margin-left: 1.5rem; + padding-left: 1rem; +} +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #ccc; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/document/content.css b/src/frontend/admin/public/tinymce/skins/content/document/content.css new file mode 100644 index 00000000..3d08c023 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/document/content.css @@ -0,0 +1,78 @@ +@media screen { + html { + background: #f4f4f4; + min-height: 100%; + } +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; +} + +@media screen { + body { + background-color: #fff; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.15); + box-sizing: border-box; + margin: 1rem auto 0; + max-width: 820px; + min-height: calc(100vh - 1rem); + padding: 4rem 6rem 6rem 6rem; + } +} + +table { + border-collapse: collapse; +} + +/* Apply a default padding if legacy cellpadding attribute is missing */ +table:not([cellpadding]) th, +table:not([cellpadding]) td { + padding: 0.4rem; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-width']) th, +table[border]:not([border='0']):not([style*='border-width']) td { + border-width: 1px; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-style']) th, +table[border]:not([border='0']):not([style*='border-style']) td { + border-style: solid; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-color']) th, +table[border]:not([border='0']):not([style*='border-color']) td { + border-color: #ccc; +} + +figure figcaption { + color: #999; + margin-top: 0.25rem; + text-align: center; +} + +hr { + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0 0; +} + +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #ccc; + margin-left: 1.5rem; + padding-left: 1rem; +} + +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #ccc; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/document/content.min.css b/src/frontend/admin/public/tinymce/skins/content/document/content.min.css new file mode 100644 index 00000000..834df86c --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/document/content.min.css @@ -0,0 +1,60 @@ +@media screen { + html { + background: #f4f4f4; + min-height: 100%; + } +} +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; +} +@media screen { + body { + background-color: #fff; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.15); + box-sizing: border-box; + margin: 1rem auto 0; + max-width: 820px; + min-height: calc(100vh - 1rem); + padding: 4rem 6rem 6rem 6rem; + } +} +table { + border-collapse: collapse; +} +table:not([cellpadding]) td, +table:not([cellpadding]) th { + padding: 0.4rem; +} +table[border]:not([border='0']):not([style*='border-width']) td, +table[border]:not([border='0']):not([style*='border-width']) th { + border-width: 1px; +} +table[border]:not([border='0']):not([style*='border-style']) td, +table[border]:not([border='0']):not([style*='border-style']) th { + border-style: solid; +} +table[border]:not([border='0']):not([style*='border-color']) td, +table[border]:not([border='0']):not([style*='border-color']) th { + border-color: #ccc; +} +figure figcaption { + color: #999; + margin-top: 0.25rem; + text-align: center; +} +hr { + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0 0; +} +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #ccc; + margin-left: 1.5rem; + padding-left: 1rem; +} +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #ccc; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/tinymce-5-dark/content.css b/src/frontend/admin/public/tinymce/skins/content/tinymce-5-dark/content.css new file mode 100644 index 00000000..2dd6d917 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/tinymce-5-dark/content.css @@ -0,0 +1,79 @@ +body { + background-color: #2f3742; + color: #dfe0e4; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem; +} + +a { + color: #4099ff; +} + +table { + border-collapse: collapse; +} + +/* Apply a default padding if legacy cellpadding attribute is missing */ +table:not([cellpadding]) th, +table:not([cellpadding]) td { + padding: 0.4rem; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-width']) th, +table[border]:not([border='0']):not([style*='border-width']) td { + border-width: 1px; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-style']) th, +table[border]:not([border='0']):not([style*='border-style']) td { + border-style: solid; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-color']) th, +table[border]:not([border='0']):not([style*='border-color']) td { + border-color: #6d737b; +} + +figure { + display: table; + margin: 1rem auto; +} + +figure figcaption { + color: #8a8f97; + display: block; + margin-top: 0.25rem; + text-align: center; +} + +hr { + border-color: #6d737b; + border-style: solid; + border-width: 1px 0 0 0; +} + +code { + background-color: #6d737b; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} + +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #6d737b; + margin-left: 1.5rem; + padding-left: 1rem; +} + +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #6d737b; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/tinymce-5-dark/content.min.css b/src/frontend/admin/public/tinymce/skins/content/tinymce-5-dark/content.min.css new file mode 100644 index 00000000..3c689eb7 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/tinymce-5-dark/content.min.css @@ -0,0 +1,60 @@ +body { + background-color: #2f3742; + color: #dfe0e4; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem; +} +a { + color: #4099ff; +} +table { + border-collapse: collapse; +} +table:not([cellpadding]) td, +table:not([cellpadding]) th { + padding: 0.4rem; +} +table[border]:not([border='0']):not([style*='border-width']) td, +table[border]:not([border='0']):not([style*='border-width']) th { + border-width: 1px; +} +table[border]:not([border='0']):not([style*='border-style']) td, +table[border]:not([border='0']):not([style*='border-style']) th { + border-style: solid; +} +table[border]:not([border='0']):not([style*='border-color']) td, +table[border]:not([border='0']):not([style*='border-color']) th { + border-color: #6d737b; +} +figure { + display: table; + margin: 1rem auto; +} +figure figcaption { + color: #8a8f97; + display: block; + margin-top: 0.25rem; + text-align: center; +} +hr { + border-color: #6d737b; + border-style: solid; + border-width: 1px 0 0 0; +} +code { + background-color: #6d737b; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #6d737b; + margin-left: 1.5rem; + padding-left: 1rem; +} +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #6d737b; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/tinymce-5/content.css b/src/frontend/admin/public/tinymce/skins/content/tinymce-5/content.css new file mode 100644 index 00000000..5176f8b2 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/tinymce-5/content.css @@ -0,0 +1,73 @@ +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem; +} + +table { + border-collapse: collapse; +} + +/* Apply a default padding if legacy cellpadding attribute is missing */ +table:not([cellpadding]) th, +table:not([cellpadding]) td { + padding: 0.4rem; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-width']) th, +table[border]:not([border='0']):not([style*='border-width']) td { + border-width: 1px; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-style']) th, +table[border]:not([border='0']):not([style*='border-style']) td { + border-style: solid; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-color']) th, +table[border]:not([border='0']):not([style*='border-color']) td { + border-color: #ccc; +} + +figure { + display: table; + margin: 1rem auto; +} + +figure figcaption { + color: #999; + display: block; + margin-top: 0.25rem; + text-align: center; +} + +hr { + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0 0; +} + +code { + background-color: #e8e8e8; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} + +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #ccc; + margin-left: 1.5rem; + padding-left: 1rem; +} + +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #ccc; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/tinymce-5/content.min.css b/src/frontend/admin/public/tinymce/skins/content/tinymce-5/content.min.css new file mode 100644 index 00000000..cca44e14 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/tinymce-5/content.min.css @@ -0,0 +1,55 @@ +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem; +} +table { + border-collapse: collapse; +} +table:not([cellpadding]) td, +table:not([cellpadding]) th { + padding: 0.4rem; +} +table[border]:not([border='0']):not([style*='border-width']) td, +table[border]:not([border='0']):not([style*='border-width']) th { + border-width: 1px; +} +table[border]:not([border='0']):not([style*='border-style']) td, +table[border]:not([border='0']):not([style*='border-style']) th { + border-style: solid; +} +table[border]:not([border='0']):not([style*='border-color']) td, +table[border]:not([border='0']):not([style*='border-color']) th { + border-color: #ccc; +} +figure { + display: table; + margin: 1rem auto; +} +figure figcaption { + color: #999; + display: block; + margin-top: 0.25rem; + text-align: center; +} +hr { + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0 0; +} +code { + background-color: #e8e8e8; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #ccc; + margin-left: 1.5rem; + padding-left: 1rem; +} +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #ccc; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/writer/content.css b/src/frontend/admin/public/tinymce/skins/content/writer/content.css new file mode 100644 index 00000000..59ca49f6 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/writer/content.css @@ -0,0 +1,74 @@ +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem auto; + max-width: 900px; +} + +table { + border-collapse: collapse; +} + +/* Apply a default padding if legacy cellpadding attribute is missing */ +table:not([cellpadding]) th, +table:not([cellpadding]) td { + padding: 0.4rem; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-width']) th, +table[border]:not([border='0']):not([style*='border-width']) td { + border-width: 1px; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-style']) th, +table[border]:not([border='0']):not([style*='border-style']) td { + border-style: solid; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border='0']):not([style*='border-color']) th, +table[border]:not([border='0']):not([style*='border-color']) td { + border-color: #ccc; +} + +figure { + display: table; + margin: 1rem auto; +} + +figure figcaption { + color: #999; + display: block; + margin-top: 0.25rem; + text-align: center; +} + +hr { + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0 0; +} + +code { + background-color: #e8e8e8; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} + +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #ccc; + margin-left: 1.5rem; + padding-left: 1rem; +} + +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #ccc; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/content/writer/content.min.css b/src/frontend/admin/public/tinymce/skins/content/writer/content.min.css new file mode 100644 index 00000000..7dfe636b --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/content/writer/content.min.css @@ -0,0 +1,56 @@ +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', + 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem auto; + max-width: 900px; +} +table { + border-collapse: collapse; +} +table:not([cellpadding]) td, +table:not([cellpadding]) th { + padding: 0.4rem; +} +table[border]:not([border='0']):not([style*='border-width']) td, +table[border]:not([border='0']):not([style*='border-width']) th { + border-width: 1px; +} +table[border]:not([border='0']):not([style*='border-style']) td, +table[border]:not([border='0']):not([style*='border-style']) th { + border-style: solid; +} +table[border]:not([border='0']):not([style*='border-color']) td, +table[border]:not([border='0']):not([style*='border-color']) th { + border-color: #ccc; +} +figure { + display: table; + margin: 1rem auto; +} +figure figcaption { + color: #999; + display: block; + margin-top: 0.25rem; + text-align: center; +} +hr { + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0 0; +} +code { + background-color: #e8e8e8; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} +.mce-content-body:not([dir='rtl']) blockquote { + border-left: 2px solid #ccc; + margin-left: 1.5rem; + padding-left: 1rem; +} +.mce-content-body[dir='rtl'] blockquote { + border-right: 2px solid #ccc; + margin-right: 1.5rem; + padding-right: 1rem; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.css b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.css new file mode 100644 index 00000000..ca33c5dc --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.css @@ -0,0 +1,848 @@ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; +} + +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} + +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * Dracula Theme originally by Zeno Rocha [@zenorocha] + * https://draculatheme.com/ + * + * Ported for PrismJS by Albert Vallverdu [@byverdu] + */ +code[class*='language-'], +pre[class*='language-'] { + color: #f8f8f2; + background: none; + text-shadow: 0 1px rgba(0, 0, 0, 0.3); + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; + border-radius: 0.3em; +} + +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #282a36; +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #6272a4; +} + +.token.punctuation { + color: #f8f8f2; +} + +.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.constant, +.token.symbol, +.token.deleted { + color: #ff79c6; +} + +.token.boolean, +.token.number { + color: #bd93f9; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #50fa7b; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string, +.token.variable { + color: #f8f8f2; +} + +.token.atrule, +.token.attr-value, +.token.function, +.token.class-name { + color: #f1fa8c; +} + +.token.keyword { + color: #8be9fd; +} + +.token.regex, +.token.important { + color: #ffb86c; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable='false'] { + cursor: default; +} + +.mce-content-body *[contentEditable='true'] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A') no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} + +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #4099ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #4099ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:focus { + outline: 3px solid #4099ff; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:hover { + outline: 3px solid #4099ff; +} + +.mce-content-body *[contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #4099ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable='true']:focus, +.mce-content-body.mce-content-readonly *[contentEditable='true']:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected='inline-boundary'] { + background-color: #4099ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #4099ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid transparent; + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: lighten; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #4099ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*='border-width: 0px'], +.mce-item-table:not([border]), +.mce-item-table[border='0'], +table[style*='border-width: 0px'] td, +.mce-item-table:not([border]) td, +.mce-item-table[border='0'] td, +table[style*='border-width: 0px'] th, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border='0'] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) ul, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] ul, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} + +body { + font-family: sans-serif; +} + +table { + border-collapse: collapse; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.inline.css b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.inline.css new file mode 100644 index 00000000..e7acef31 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.inline.css @@ -0,0 +1,861 @@ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; +} + +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} + +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*='language-'], +pre[class*='language-'] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} + +pre[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +code[class*='language-'] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*='language-']::selection, +pre[class*='language-'] ::selection, +code[class*='language-']::selection, +code[class*='language-'] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.token.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + /* This background color was intended by the author of this theme. */ + background: hsla(0, 0%, 100%, 0.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #dd4a68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable='false'] { + cursor: default; +} + +.mce-content-body *[contentEditable='true'] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} + +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #b4d7ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable='true']:focus, +.mce-content-body.mce-content-readonly *[contentEditable='true']:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*='border-width: 0px'], +.mce-item-table:not([border]), +.mce-item-table[border='0'], +table[style*='border-width: 0px'] td, +.mce-item-table:not([border]) td, +.mce-item-table[border='0'] td, +table[style*='border-width: 0px'] th, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border='0'] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) ul, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] ul, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.inline.min.css b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.inline.min.css new file mode 100644 index 00000000..882dfd5b --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.inline.min.css @@ -0,0 +1,720 @@ +.mce-content-body .mce-item-anchor { + background: transparent + url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") + no-repeat center; +} +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} +code[class*='language-'], +pre[class*='language-'] { + color: #000; + background: 0 0; + text-shadow: 0 1px #fff; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} +code[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +pre[class*='language-']::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} +code[class*='language-'] ::selection, +code[class*='language-']::selection, +pre[class*='language-'] ::selection, +pre[class*='language-']::selection { + text-shadow: none; + background: #b3d4fc; +} +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} +.token.cdata, +.token.comment, +.token.doctype, +.token.prolog { + color: #708090; +} +.token.punctuation { + color: #999; +} +.token.namespace { + opacity: 0.7; +} +.token.boolean, +.token.constant, +.token.deleted, +.token.number, +.token.property, +.token.symbol, +.token.tag { + color: #905; +} +.token.attr-name, +.token.builtin, +.token.char, +.token.inserted, +.token.selector, +.token.string { + color: #690; +} +.language-css .token.string, +.style .token.string, +.token.entity, +.token.operator, +.token.url { + color: #9a6e3a; + background: hsla(0, 0%, 100%, 0.5); +} +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} +.token.class-name, +.token.function { + color: #dd4a68; +} +.token.important, +.token.regex, +.token.variable { + color: #e90; +} +.token.bold, +.token.important { + font-weight: 700; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} +.mce-content-body .mce-visual-caret { + background-color: #000; + background-color: currentColor; + position: absolute; +} +.mce-content-body .mce-visual-caret-hidden { + display: none; +} +.mce-content-body [data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} +.mce-content-body [contentEditable='false'] { + cursor: default; +} +.mce-content-body [contentEditable='true'] { + cursor: text; +} +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} +.mce-content-body figure.align-left { + float: left; +} +.mce-content-body figure.align-right { + float: right; +} +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} +.mce-object { + background: transparent + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') + no-repeat center; + border: 1px dashed #aaa; +} +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} +@media print { + .mce-pagebreak { + border: 0; + } +} +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} +.tiny-pageembed { + display: inline-block; + position: relative; +} +.tiny-pageembed--16by9, +.tiny-pageembed--1by1, +.tiny-pageembed--21by9, +.tiny-pageembed--4by3 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} +.tiny-pageembed--4by3 { + padding-top: 75%; +} +.tiny-pageembed--1by1 { + padding-top: 100%; +} +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--1by1 iframe, +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--4by3 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-content-body[data-mce-placeholder] { + position: relative; +} +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed #000; + position: absolute; + z-index: 10001; +} +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th { + border: 0; +} +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: #fff; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} +.tox-rtc-user-selection { + position: relative; +} +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: 700; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} +.tox-rtc-remote-image { + background: #eaeaea + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') + no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} +.mce-match-marker { + background: #aaa; + color: #fff; +} +.mce-match-marker-selected { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} +.mce-content-body audio[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body img[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body table[data-mce-selected], +.mce-content-body video[data-mce-selected] { + outline: 3px solid #b4d7ff; +} +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} +.mce-content-body.mce-content-readonly [contentEditable='true']:focus, +.mce-content-body.mce-content-readonly [contentEditable='true']:hover { + outline: 0; +} +.mce-content-body [data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} +.mce-content-body img::-moz-selection { + background: 0 0; +} +.mce-content-body img::selection { + background: 0 0; +} +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ephox-snooker-resizer-cols { + cursor: col-resize; +} +.ephox-snooker-resizer-rows { + cursor: row-resize; +} +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} +.mce-toc { + border: 1px solid gray; +} +.mce-toc h2 { + margin: 4px; +} +.mce-toc li { + list-style-type: none; +} +.mce-item-table:not([border]), +.mce-item-table:not([border]) caption, +.mce-item-table:not([border]) td, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'], +.mce-item-table[border='0'] caption, +.mce-item-table[border='0'] td, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'], +table[style*='border-width: 0px'] caption, +table[style*='border-width: 0px'] td, +table[style*='border-width: 0px'] th { + border: 1px dashed #bbb; +} +.mce-visualblocks address, +.mce-visualblocks article, +.mce-visualblocks aside, +.mce-visualblocks blockquote, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks dl, +.mce-visualblocks figcaption, +.mce-visualblocks figure, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks hgroup, +.mce-visualblocks ol, +.mce-visualblocks p, +.mce-visualblocks pre, +.mce-visualblocks section, +.mce-visualblocks ul { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) dl, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) ul { + margin-left: 3px; +} +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] dl, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] ul { + background-position-x: right; + margin-right: 3px; +} +.mce-nbsp, +.mce-shy { + background: #aaa; +} +.mce-shy::after { + content: '-'; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.min.css b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.min.css new file mode 100644 index 00000000..04195ea7 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/content.min.css @@ -0,0 +1,707 @@ +.mce-content-body .mce-item-anchor { + background: transparent + url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") + no-repeat center; +} +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} +code[class*='language-'], +pre[class*='language-'] { + color: #f8f8f2; + background: 0 0; + text-shadow: 0 1px rgba(0, 0, 0, 0.3); + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; + border-radius: 0.3em; +} +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #282a36; +} +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} +.token.cdata, +.token.comment, +.token.doctype, +.token.prolog { + color: #6272a4; +} +.token.punctuation { + color: #f8f8f2; +} +.namespace { + opacity: 0.7; +} +.token.constant, +.token.deleted, +.token.property, +.token.symbol, +.token.tag { + color: #ff79c6; +} +.token.boolean, +.token.number { + color: #bd93f9; +} +.token.attr-name, +.token.builtin, +.token.char, +.token.inserted, +.token.selector, +.token.string { + color: #50fa7b; +} +.language-css .token.string, +.style .token.string, +.token.entity, +.token.operator, +.token.url, +.token.variable { + color: #f8f8f2; +} +.token.atrule, +.token.attr-value, +.token.class-name, +.token.function { + color: #f1fa8c; +} +.token.keyword { + color: #8be9fd; +} +.token.important, +.token.regex { + color: #ffb86c; +} +.token.bold, +.token.important { + font-weight: 700; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} +.mce-content-body .mce-visual-caret { + background-color: #000; + background-color: currentColor; + position: absolute; +} +.mce-content-body .mce-visual-caret-hidden { + display: none; +} +.mce-content-body [data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} +.mce-content-body [contentEditable='false'] { + cursor: default; +} +.mce-content-body [contentEditable='true'] { + cursor: text; +} +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} +.mce-content-body figure.align-left { + float: left; +} +.mce-content-body figure.align-right { + float: right; +} +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} +.mce-object { + background: transparent + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A') + no-repeat center; + border: 1px dashed #aaa; +} +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} +@media print { + .mce-pagebreak { + border: 0; + } +} +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} +.tiny-pageembed { + display: inline-block; + position: relative; +} +.tiny-pageembed--16by9, +.tiny-pageembed--1by1, +.tiny-pageembed--21by9, +.tiny-pageembed--4by3 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} +.tiny-pageembed--4by3 { + padding-top: 75%; +} +.tiny-pageembed--1by1 { + padding-top: 100%; +} +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--1by1 iframe, +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--4by3 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-content-body[data-mce-placeholder] { + position: relative; +} +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed #000; + position: absolute; + z-index: 10001; +} +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th { + border: 0; +} +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: #fff; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} +.tox-rtc-user-selection { + position: relative; +} +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: 700; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} +.tox-rtc-remote-image { + background: #eaeaea + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') + no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} +.mce-match-marker { + background: #aaa; + color: #fff; +} +.mce-match-marker-selected { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} +.mce-content-body audio[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body img[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body table[data-mce-selected], +.mce-content-body video[data-mce-selected] { + outline: 3px solid #4099ff; +} +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #4099ff; + outline-offset: 1px; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:focus { + outline: 3px solid #4099ff; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:hover { + outline: 3px solid #4099ff; +} +.mce-content-body [contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #4099ff; +} +.mce-content-body.mce-content-readonly [contentEditable='true']:focus, +.mce-content-body.mce-content-readonly [contentEditable='true']:hover { + outline: 0; +} +.mce-content-body [data-mce-selected='inline-boundary'] { + background-color: #4099ff; +} +.mce-content-body .mce-edit-focus { + outline: 3px solid #4099ff; +} +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid transparent; + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: lighten; + position: absolute; + right: -1px; + top: -1px; +} +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} +.mce-content-body img::-moz-selection { + background: 0 0; +} +.mce-content-body img::selection { + background: 0 0; +} +.ephox-snooker-resizer-bar { + background-color: #4099ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ephox-snooker-resizer-cols { + cursor: col-resize; +} +.ephox-snooker-resizer-rows { + cursor: row-resize; +} +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} +.mce-toc { + border: 1px solid gray; +} +.mce-toc h2 { + margin: 4px; +} +.mce-toc li { + list-style-type: none; +} +.mce-item-table:not([border]), +.mce-item-table:not([border]) caption, +.mce-item-table:not([border]) td, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'], +.mce-item-table[border='0'] caption, +.mce-item-table[border='0'] td, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'], +table[style*='border-width: 0px'] caption, +table[style*='border-width: 0px'] td, +table[style*='border-width: 0px'] th { + border: 1px dashed #bbb; +} +.mce-visualblocks address, +.mce-visualblocks article, +.mce-visualblocks aside, +.mce-visualblocks blockquote, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks dl, +.mce-visualblocks figcaption, +.mce-visualblocks figure, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks hgroup, +.mce-visualblocks ol, +.mce-visualblocks p, +.mce-visualblocks pre, +.mce-visualblocks section, +.mce-visualblocks ul { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) dl, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) ul { + margin-left: 3px; +} +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] dl, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] ul { + background-position-x: right; + margin-right: 3px; +} +.mce-nbsp, +.mce-shy { + background: #aaa; +} +.mce-shy::after { + content: '-'; +} +body { + font-family: sans-serif; +} +table { + border-collapse: collapse; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.css b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.css new file mode 100644 index 00000000..2726e0fc --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.css @@ -0,0 +1,3664 @@ +.tox { + box-shadow: none; + box-sizing: content-box; + color: #222f3e; + cursor: auto; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-style: normal; + font-weight: normal; + line-height: normal; + -webkit-tap-highlight-color: transparent; + text-decoration: none; + text-shadow: none; + text-transform: none; + vertical-align: initial; + white-space: normal; +} + +.tox *:not(svg):not(rect) { + box-sizing: inherit; + color: inherit; + cursor: inherit; + direction: inherit; + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; + line-height: inherit; + -webkit-tap-highlight-color: inherit; + text-align: inherit; + text-decoration: inherit; + text-shadow: inherit; + text-transform: inherit; + vertical-align: inherit; + white-space: inherit; +} + +.tox *:not(svg):not(rect) { + /* stylelint-disable-line no-duplicate-selectors */ + background: transparent; + border: 0; + box-shadow: none; + float: none; + height: auto; + margin: 0; + max-width: none; + outline: 0; + padding: 0; + position: static; + width: auto; +} + +.tox:not([dir='rtl']) { + direction: ltr; + text-align: left; +} + +.tox[dir='rtl'] { + direction: rtl; + text-align: right; +} + +.tox-tinymce { + border: 2px solid #161f29; + border-radius: 10px; + box-shadow: none; + box-sizing: border-box; + display: flex; + flex-direction: column; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + overflow: hidden; + position: relative; + visibility: inherit !important; +} + +.tox.tox-tinymce-inline { + border: none; + box-shadow: none; + overflow: initial; +} + +.tox.tox-tinymce-inline .tox-editor-container { + overflow: initial; +} + +.tox.tox-tinymce-inline .tox-editor-header { + background-color: #222f3e; + border: 2px solid #161f29; + border-radius: 10px; + box-shadow: none; + overflow: hidden; +} + +.tox-tinymce-aux { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + z-index: 1300; +} + +.tox-tinymce *:focus, +.tox-tinymce-aux *:focus { + outline: none; +} + +button::-moz-focus-inner { + border: 0; +} + +.tox[dir='rtl'] .tox-icon--flip svg { + transform: rotateY(180deg); +} + +.tox .accessibility-issue__header { + align-items: center; + display: flex; + margin-bottom: 4px; +} + +.tox .accessibility-issue__description { + align-items: stretch; + border: 1px solid #161f29; + border-radius: 6px; + display: flex; + justify-content: space-between; +} + +.tox .accessibility-issue__description > div { + padding-bottom: 4px; +} + +.tox .accessibility-issue__description > div > div { + align-items: center; + display: flex; + margin-bottom: 4px; +} + +.tox .accessibility-issue__description > *:last-child:not(:only-child) { + border-color: #161f29; + border-style: solid; +} + +.tox .accessibility-issue__repair { + margin-top: 16px; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { + background-color: rgba(0, 108, 231, 0.5); + border-color: rgba(0, 108, 231, 0.4); + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description > *:last-child { + border-color: rgba(0, 108, 231, 0.4); +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { + background-color: rgba(255, 165, 0, 0.5); + border-color: rgba(255, 165, 0, 0.8); + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description > *:last-child { + border-color: rgba(255, 165, 0, 0.8); +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { + background-color: rgba(204, 0, 0, 0.5); + border-color: rgba(204, 0, 0, 0.8); + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description > *:last-child { + border-color: rgba(204, 0, 0, 0.8); +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { + background-color: rgba(120, 171, 70, 0.5); + border-color: rgba(120, 171, 70, 0.8); + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > *:last-child { + border-color: rgba(120, 171, 70, 0.8); +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue__header h1, +.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { + margin-top: 0; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-left: auto; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 4px 4px 8px; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-left-width: 1px; + padding-left: 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-right: auto; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 8px 4px 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-right-width: 1px; + padding-right: 4px; +} + +.tox .tox-anchorbar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-bar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-button { + background-color: #006ce7; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #006ce7; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + line-height: 24px; + margin: 0; + outline: none; + padding: 4px 16px; + text-align: center; + text-decoration: none; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-button[disabled] { + background-color: #006ce7; + background-image: none; + border-color: #006ce7; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-button:focus:not(:disabled) { + background-color: #0060ce; + background-image: none; + border-color: #0060ce; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:hover:not(:disabled) { + background-color: #0060ce; + background-image: none; + border-color: #0060ce; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:active:not(:disabled) { + background-color: #0054b4; + background-image: none; + border-color: #0054b4; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary { + background-color: #3d546f; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #3d546f; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + color: #fff; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + outline: none; + padding: 4px 16px; + text-decoration: none; + text-transform: none; +} + +.tox .tox-button--secondary[disabled] { + background-color: #3d546f; + background-image: none; + border-color: #3d546f; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} + +.tox .tox-button--secondary:focus:not(:disabled) { + background-color: #34485f; + background-image: none; + border-color: #34485f; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary:hover:not(:disabled) { + background-color: #34485f; + background-image: none; + border-color: #34485f; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary:active:not(:disabled) { + background-color: #2b3b4e; + background-image: none; + border-color: #2b3b4e; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--icon, +.tox .tox-button.tox-button--icon, +.tox .tox-button.tox-button--secondary.tox-button--icon { + padding: 4px; +} + +.tox .tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { + display: block; + fill: currentColor; +} + +.tox .tox-button-link { + background: 0; + border: none; + box-sizing: border-box; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-weight: normal; + line-height: 1.3; + margin: 0; + padding: 0; + white-space: nowrap; +} + +.tox .tox-button-link--sm { + font-size: 14px; +} + +.tox .tox-button--naked { + background-color: transparent; + border-color: transparent; + box-shadow: unset; + color: #fff; +} + +.tox .tox-button--naked[disabled] { + background-color: rgba(255, 255, 255, 0.2); + border-color: transparent; + box-shadow: unset; + color: rgba(255, 255, 255, 0.5); +} + +.tox .tox-button--naked:hover:not(:disabled) { + background-color: rgba(255, 255, 255, 0.2); + border-color: transparent; + box-shadow: unset; + color: #fff; +} + +.tox .tox-button--naked:focus:not(:disabled) { + background-color: rgba(255, 255, 255, 0.2); + border-color: transparent; + box-shadow: unset; + color: #fff; +} + +.tox .tox-button--naked:active:not(:disabled) { + background-color: rgba(255, 255, 255, 0.3); + border-color: transparent; + box-shadow: unset; + color: #fff; +} + +.tox .tox-button--naked .tox-icon svg { + fill: currentColor; +} + +.tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { + color: #fff; +} + +.tox .tox-checkbox { + align-items: center; + border-radius: 6px; + cursor: pointer; + display: flex; + height: 36px; + min-width: 36px; +} + +.tox .tox-checkbox__input { + /* Hide from view but visible to screen readers */ + height: 1px; + overflow: hidden; + position: absolute; + top: auto; + width: 1px; +} + +.tox .tox-checkbox__icons { + align-items: center; + border-radius: 6px; + box-shadow: 0 0 0 2px transparent; + box-sizing: content-box; + display: flex; + height: 24px; + justify-content: center; + padding: calc(4px - 1px); + width: 24px; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: block; + fill: rgba(255, 255, 255, 0.2); +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: none; + fill: #006ce7; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: none; + fill: #006ce7; +} + +.tox .tox-checkbox--disabled { + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: block; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: block; +} + +.tox input.tox-checkbox__input:focus + .tox-checkbox__icons { + border-radius: 6px; + box-shadow: inset 0 0 0 1px #006ce7; + padding: calc(4px - 1px); +} + +.tox:not([dir='rtl']) .tox-checkbox__label { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-checkbox__input { + left: -10000px; +} + +.tox:not([dir='rtl']) .tox-bar .tox-checkbox { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-checkbox__label { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-checkbox__input { + right: -10000px; +} + +.tox[dir='rtl'] .tox-bar .tox-checkbox { + margin-right: 4px; +} + +.tox { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox .tox-collection--toolbar .tox-collection__group { + display: flex; + padding: 0; +} + +.tox .tox-collection--grid .tox-collection__group { + display: flex; + flex-wrap: wrap; + max-height: 208px; + overflow-x: hidden; + overflow-y: auto; + padding: 0; +} + +.tox .tox-collection--list .tox-collection__group { + border-bottom-width: 0; + border-color: rgba(255, 255, 255, 0.15); + border-left-width: 0; + border-right-width: 0; + border-style: solid; + border-top-width: 1px; + padding: 4px 0; +} + +.tox .tox-collection--list .tox-collection__group:first-child { + border-top-width: 0; +} + +.tox .tox-collection__group-heading { + background-color: rgba(255, 255, 255, 0.15); + color: rgba(255, 255, 255, 0.5); + cursor: default; + font-size: 12px; + font-style: normal; + font-weight: normal; + margin-bottom: 4px; + margin-top: -4px; + padding: 4px 8px; + text-transform: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.tox .tox-collection__item { + align-items: center; + border-radius: 3px; + color: #fff; + display: flex; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.tox .tox-collection--list .tox-collection__item { + padding: 4px 8px; +} + +.tox .tox-collection--toolbar .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--grid .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--list .tox-collection__item--enabled { + background-color: #2b3b4e; + color: #fff; +} + +.tox .tox-collection--list .tox-collection__item--active { + background-color: #3389ec; +} + +.tox .tox-collection--toolbar .tox-collection__item--enabled { + background-color: #599fef; + color: #fff; +} + +.tox .tox-collection--toolbar .tox-collection__item--active { + background-color: #3389ec; +} + +.tox .tox-collection--grid .tox-collection__item--enabled { + background-color: #599fef; + color: #fff; +} + +.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + background-color: #3389ec; + color: #fff; +} + +.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #fff; +} + +.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #fff; +} + +.tox .tox-collection__item-icon, +.tox .tox-collection__item-checkmark { + align-items: center; + display: flex; + height: 24px; + justify-content: center; + width: 24px; +} + +.tox .tox-collection__item-icon svg, +.tox .tox-collection__item-checkmark svg { + fill: currentColor; +} + +.tox .tox-collection--toolbar-lg .tox-collection__item-icon { + height: 48px; + width: 48px; +} + +.tox .tox-collection__item-label { + color: currentColor; + display: inline-block; + flex: 1; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 24px; + text-transform: none; + word-break: break-all; +} + +.tox .tox-collection__item-accessory { + color: rgba(255, 255, 255, 0.5); + display: inline-block; + font-size: 14px; + height: 24px; + line-height: 24px; + text-transform: none; +} + +.tox .tox-collection__item-caret { + align-items: center; + display: flex; + min-height: 24px; +} + +.tox .tox-collection__item-caret::after { + content: ''; + font-size: 0; + min-height: inherit; +} + +.tox .tox-collection__item-caret svg { + fill: #fff; +} + +.tox .tox-collection__item--state-disabled { + background-color: transparent; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox +.tox-collection--list +.tox-collection__item:not(.tox-collection__item--enabled) +.tox-collection__item-checkmark +svg { + display: none; +} + +.tox +.tox-collection--list +.tox-collection__item:not(.tox-collection__item--enabled) +.tox-collection__item-accessory ++ .tox-collection__item-checkmark { + display: none; +} + +.tox .tox-collection--horizontal { + background-color: #2b3b4e; + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: nowrap; + margin-bottom: 0; + overflow-x: auto; + padding: 0; +} + +.tox .tox-collection--horizontal .tox-collection__group { + align-items: center; + display: flex; + flex-wrap: nowrap; + margin: 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item { + height: 28px; + margin: 6px 1px 5px 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item-label { + white-space: nowrap; +} + +.tox .tox-collection--horizontal .tox-collection__item-caret { + margin-left: 4px; +} + +.tox .tox-collection__item-container { + display: flex; +} + +.tox .tox-collection__item-container--row { + align-items: center; + flex: 1 1 auto; + flex-direction: row; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-left { + margin-right: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-right { + justify-content: flex-end; + margin-left: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { + align-items: flex-start; + margin-bottom: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { + align-items: center; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { + align-items: flex-end; + margin-top: auto; +} + +.tox .tox-collection__item-container--column { + align-self: center; + flex: 1 1 auto; + flex-direction: column; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-left { + align-items: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-right { + align-items: flex-end; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { + align-self: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { + align-self: center; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { + align-self: flex-end; +} + +.tox:not([dir='rtl']) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-right: 1px solid transparent; +} + +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-left: 8px; +} + +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-collection__item-accessory { + margin-left: 16px; + text-align: right; +} + +.tox:not([dir='rtl']) .tox-collection .tox-collection__item-caret { + margin-left: 16px; +} + +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-left: 1px solid transparent; +} + +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-right: 8px; +} + +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-collection__item-accessory { + margin-right: 16px; + text-align: left; +} + +.tox[dir='rtl'] .tox-collection .tox-collection__item-caret { + margin-right: 16px; + transform: rotateY(180deg); +} + +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__item-caret { + margin-right: 4px; +} + +.tox .tox-color-picker-container { + display: flex; + flex-direction: row; + height: 225px; + margin: 0; +} + +.tox .tox-sv-palette { + box-sizing: border-box; + display: flex; + height: 100%; +} + +.tox .tox-sv-palette-spectrum { + height: 100%; +} + +.tox .tox-sv-palette, +.tox .tox-sv-palette-spectrum { + width: 225px; +} + +.tox .tox-sv-palette-thumb { + background: none; + border: 1px solid black; + border-radius: 50%; + box-sizing: content-box; + height: 12px; + position: absolute; + width: 12px; +} + +.tox .tox-sv-palette-inner-thumb { + border: 1px solid white; + border-radius: 50%; + height: 10px; + position: absolute; + width: 10px; +} + +.tox .tox-hue-slider { + box-sizing: border-box; + height: 100%; + width: 25px; +} + +.tox .tox-hue-slider-spectrum { + background: linear-gradient( + to bottom, + #f00, + #ff0080, + #f0f, + #8000ff, + #00f, + #0080ff, + #0ff, + #00ff80, + #0f0, + #80ff00, + #ff0, + #ff8000, + #f00 + ); + height: 100%; + width: 100%; +} + +.tox .tox-hue-slider, +.tox .tox-hue-slider-spectrum { + width: 20px; +} + +.tox .tox-hue-slider-thumb { + background: white; + border: 1px solid black; + box-sizing: content-box; + height: 4px; + width: 100%; +} + +.tox .tox-rgb-form { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.tox .tox-rgb-form div { + align-items: center; + display: flex; + justify-content: space-between; + margin-bottom: 5px; + width: inherit; +} + +.tox .tox-rgb-form input { + width: 6em; +} + +.tox .tox-rgb-form input.tox-invalid { + /* Need !important to override Chrome's focus styling unfortunately */ + border: 1px solid red !important; +} + +.tox .tox-rgb-form .tox-rgba-preview { + border: 1px solid black; + flex-grow: 2; + margin-bottom: 0; +} + +.tox:not([dir='rtl']) .tox-sv-palette { + margin-right: 15px; +} + +.tox:not([dir='rtl']) .tox-hue-slider { + margin-right: 15px; +} + +.tox:not([dir='rtl']) .tox-hue-slider-thumb { + margin-left: -1px; +} + +.tox:not([dir='rtl']) .tox-rgb-form label { + margin-right: 0.5em; +} + +.tox[dir='rtl'] .tox-sv-palette { + margin-left: 15px; +} + +.tox[dir='rtl'] .tox-hue-slider { + margin-left: 15px; +} + +.tox[dir='rtl'] .tox-hue-slider-thumb { + margin-right: -1px; +} + +.tox[dir='rtl'] .tox-rgb-form label { + margin-left: 0.5em; +} + +.tox .tox-toolbar .tox-swatches, +.tox .tox-toolbar__primary .tox-swatches, +.tox .tox-toolbar__overflow .tox-swatches { + margin: 5px 0 6px 11px; +} + +.tox .tox-collection--list .tox-collection__group .tox-swatches-menu { + border: 0; + margin: -4px -4px; +} + +.tox .tox-swatches__row { + display: flex; +} + +.tox .tox-swatch { + height: 30px; + transition: transform 0.15s, box-shadow 0.15s; + width: 30px; +} + +.tox .tox-swatch:hover, +.tox .tox-swatch:focus { + box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; + transform: scale(0.8); +} + +.tox .tox-swatch--remove { + align-items: center; + display: flex; + justify-content: center; +} + +.tox .tox-swatch--remove svg path { + stroke: #e74c3c; +} + +.tox .tox-swatches__picker-btn { + align-items: center; + background-color: transparent; + border: 0; + cursor: pointer; + display: flex; + height: 30px; + justify-content: center; + outline: none; + padding: 0; + width: 30px; +} + +.tox .tox-swatches__picker-btn svg { + fill: #fff; + height: 24px; + width: 24px; +} + +.tox .tox-swatches__picker-btn:hover { + background: #3389ec; +} + +.tox:not([dir='rtl']) .tox-swatches__picker-btn { + margin-left: auto; +} + +.tox[dir='rtl'] .tox-swatches__picker-btn { + margin-right: auto; +} + +.tox .tox-comment-thread { + background: #2b3b4e; + position: relative; +} + +.tox .tox-comment-thread > *:not(:first-child) { + margin-top: 8px; +} + +.tox .tox-comment { + background: #2b3b4e; + border: 1px solid #161f29; + border-radius: 6px; + box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); + padding: 8px 8px 16px 8px; + position: relative; +} + +.tox .tox-comment__header { + align-items: center; + color: #fff; + display: flex; + justify-content: space-between; +} + +.tox .tox-comment__date { + color: rgba(255, 255, 255, 0.5); + font-size: 12px; +} + +.tox .tox-comment__body { + color: #fff; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin-top: 8px; + position: relative; + text-transform: initial; +} + +.tox .tox-comment__body textarea { + resize: none; + white-space: normal; + width: 100%; +} + +.tox .tox-comment__expander { + padding-top: 8px; +} + +.tox .tox-comment__expander p { + color: rgba(255, 255, 255, 0.5); + font-size: 14px; + font-style: normal; +} + +.tox .tox-comment__body p { + margin: 0; +} + +.tox .tox-comment__buttonspacing { + padding-top: 16px; + text-align: center; +} + +.tox .tox-comment-thread__overlay::after { + background: #2b3b4e; + bottom: 0; + content: ''; + display: flex; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + top: 0; + z-index: 5; +} + +.tox .tox-comment__reply { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 8px; +} + +.tox .tox-comment__reply > *:first-child { + margin-bottom: 8px; + width: 100%; +} + +.tox .tox-comment__edit { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 16px; +} + +.tox .tox-comment__gradient::after { + background: linear-gradient(rgba(43, 59, 78, 0), #2b3b4e); + bottom: 0; + content: ''; + display: block; + height: 5em; + margin-top: -40px; + position: absolute; + width: 100%; +} + +.tox .tox-comment__overlay { + background: #2b3b4e; + bottom: 0; + display: flex; + flex-direction: column; + flex-grow: 1; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + text-align: center; + top: 0; + z-index: 5; +} + +.tox .tox-comment__loading-text { + align-items: center; + color: #fff; + display: flex; + flex-direction: column; + position: relative; +} + +.tox .tox-comment__loading-text > div { + padding-bottom: 16px; +} + +.tox .tox-comment__overlaytext { + bottom: 0; + flex-direction: column; + font-size: 14px; + left: 0; + padding: 1em; + position: absolute; + right: 0; + top: 0; + z-index: 10; +} + +.tox .tox-comment__overlaytext p { + background-color: #2b3b4e; + box-shadow: 0 0 8px 8px #2b3b4e; + color: #fff; + text-align: center; +} + +.tox .tox-comment__overlaytext div:nth-of-type(2) { + font-size: 0.8em; +} + +.tox .tox-comment__busy-spinner { + align-items: center; + background-color: #2b3b4e; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 20; +} + +.tox .tox-comment__scroll { + display: flex; + flex-direction: column; + flex-shrink: 1; + overflow: auto; +} + +.tox .tox-conversations { + margin: 8px; +} + +.tox:not([dir='rtl']) .tox-comment__edit { + margin-left: 8px; +} + +.tox:not([dir='rtl']) .tox-comment__buttonspacing > *:last-child, +.tox:not([dir='rtl']) .tox-comment__edit > *:last-child, +.tox:not([dir='rtl']) .tox-comment__reply > *:last-child { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-comment__edit { + margin-right: 8px; +} + +.tox[dir='rtl'] .tox-comment__buttonspacing > *:last-child, +.tox[dir='rtl'] .tox-comment__edit > *:last-child, +.tox[dir='rtl'] .tox-comment__reply > *:last-child { + margin-right: 8px; +} + +.tox .tox-user { + align-items: center; + display: flex; +} + +.tox .tox-user__avatar svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-user__name { + color: rgba(255, 255, 255, 0.5); + font-size: 12px; + font-style: normal; + font-weight: bold; + text-transform: uppercase; +} + +.tox:not([dir='rtl']) .tox-user__avatar svg { + margin-right: 8px; +} + +.tox:not([dir='rtl']) .tox-user__avatar + .tox-user__name { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-user__avatar svg { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-user__avatar + .tox-user__name { + margin-right: 8px; +} + +.tox .tox-dialog-wrap { + align-items: center; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 1100; +} + +.tox .tox-dialog-wrap__backdrop { + background-color: rgba(34, 47, 62, 0.75); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} + +.tox .tox-dialog-wrap__backdrop--opaque { + background-color: #222f3e; +} + +.tox .tox-dialog { + background-color: #2b3b4e; + border-color: #161f29; + border-radius: 10px; + border-style: solid; + border-width: 0px; + box-shadow: 0 16px 16px -10px rgba(34, 47, 62, 0.15), 0 0 40px 1px rgba(34, 47, 62, 0.15); + display: flex; + flex-direction: column; + max-height: 100%; + max-width: 480px; + overflow: hidden; + position: relative; + width: 95vw; + z-index: 2; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog { + align-self: flex-start; + margin: 8px auto; + width: calc(100vw - 16px); + } +} + +.tox .tox-dialog-inline { + z-index: 1100; +} + +.tox .tox-dialog__header { + align-items: center; + background-color: #2b3b4e; + border-bottom: none; + color: #fff; + display: flex; + font-size: 16px; + justify-content: space-between; + padding: 8px 16px 0 16px; + position: relative; +} + +.tox .tox-dialog__header .tox-button { + z-index: 1; +} + +.tox .tox-dialog__draghandle { + cursor: grab; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tox .tox-dialog__draghandle:active { + cursor: grabbing; +} + +.tox .tox-dialog__dismiss { + margin-left: auto; +} + +.tox .tox-dialog__title { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 20px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin: 0; + text-transform: none; +} + +.tox .tox-dialog__body { + color: #fff; + display: flex; + flex: 1; + font-size: 16px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + min-width: 0; + text-align: left; + text-transform: none; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body { + flex-direction: column; + } +} + +.tox .tox-dialog__body-nav { + align-items: flex-start; + display: flex; + flex-direction: column; + padding: 16px 16px; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { + flex-direction: row; + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding-bottom: 0; + } +} + +.tox .tox-dialog__body-nav-item { + border-bottom: 2px solid transparent; + color: rgba(255, 255, 255, 0.5); + display: inline-block; + font-size: 14px; + line-height: 1.3; + margin-bottom: 8px; + text-decoration: none; + white-space: nowrap; +} + +.tox .tox-dialog__body-nav-item:focus { + background-color: rgba(0, 108, 231, 0.1); +} + +.tox .tox-dialog__body-nav-item--active { + border-bottom: 2px solid #006ce7; + color: #006ce7; +} + +.tox .tox-dialog__body-content { + box-sizing: border-box; + display: flex; + flex: 1; + flex-direction: column; + max-height: 650px; + overflow: auto; + -webkit-overflow-scrolling: touch; + padding: 16px 16px; +} + +.tox .tox-dialog__body-content > * { + margin-bottom: 0; + margin-top: 16px; +} + +.tox .tox-dialog__body-content > *:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content > *:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content > *:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog__body-content a { + color: #006ce7; + cursor: pointer; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:hover, +.tox .tox-dialog__body-content a:focus { + color: #0054b4; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:active { + color: #0054b4; + text-decoration: none; +} + +.tox .tox-dialog__body-content svg { + fill: #fff; +} + +.tox .tox-dialog__body-content ul { + display: block; + list-style-type: disc; + margin-bottom: 16px; + margin-inline-end: 0; + margin-inline-start: 0; + padding-inline-start: 2.5rem; +} + +.tox .tox-dialog__body-content .tox-form__group h1 { + color: #fff; + font-size: 20px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group h2 { + color: #fff; + font-size: 16px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group p { + margin-bottom: 16px; +} + +.tox .tox-dialog__body-content .tox-form__group h1:first-child, +.tox .tox-dialog__body-content .tox-form__group h2:first-child, +.tox .tox-dialog__body-content .tox-form__group p:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:last-child, +.tox .tox-dialog__body-content .tox-form__group h2:last-child, +.tox .tox-dialog__body-content .tox-form__group p:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:only-child, +.tox .tox-dialog__body-content .tox-form__group h2:only-child, +.tox .tox-dialog__body-content .tox-form__group p:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog--width-lg { + height: 650px; + max-width: 1200px; +} + +.tox .tox-dialog--width-md { + max-width: 800px; +} + +.tox .tox-dialog--width-md .tox-dialog__body-content { + overflow: auto; +} + +.tox .tox-dialog__body-content--centered { + text-align: center; +} + +.tox .tox-dialog__footer { + align-items: center; + background-color: #2b3b4e; + border-top: none; + display: flex; + justify-content: space-between; + padding: 8px 16px; +} + +.tox .tox-dialog__footer-start, +.tox .tox-dialog__footer-end { + display: flex; +} + +.tox .tox-dialog__busy-spinner { + align-items: center; + background-color: rgba(34, 47, 62, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 3; +} + +.tox .tox-dialog__table { + border-collapse: collapse; + width: 100%; +} + +.tox .tox-dialog__table thead th { + font-weight: bold; + padding-bottom: 8px; +} + +.tox .tox-dialog__table tbody tr { + border-bottom: 1px solid #161f29; +} + +.tox .tox-dialog__table tbody tr:last-child { + border-bottom: none; +} + +.tox .tox-dialog__table td { + padding-bottom: 8px; + padding-top: 8px; +} + +.tox .tox-dialog__popups { + position: absolute; + width: 100%; + z-index: 1100; +} + +.tox .tox-dialog__body-iframe { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-dialog__body-iframe .tox-navobj { + display: flex; + flex: 1; +} + +.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} + +.tox .tox-dialog-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox .tox-dialog-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox .tox-dialog-dock-transition { + transition: visibility 0s linear 0.3s, opacity 0.3s ease; +} + +.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { + transition-delay: 0s; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav { + margin-right: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav-item:not(:first-child) { + margin-left: 8px; + } +} + +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-start > *, +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-end > * { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-dialog__body { + text-align: right; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav { + margin-left: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav-item:not(:first-child) { + margin-right: 8px; + } +} + +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-start > *, +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-end > * { + margin-right: 8px; +} + +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox .tox-dropzone-container { + display: flex; + flex: 1; +} + +.tox .tox-dropzone { + align-items: center; + background: #fff; + border: 2px dashed #161f29; + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-grow: 1; + justify-content: center; + min-height: 100px; + padding: 10px; +} + +.tox .tox-dropzone p { + color: rgba(255, 255, 255, 0.5); + margin: 0 0 16px 0; +} + +.tox .tox-edit-area { + display: flex; + flex: 1; + overflow: hidden; + position: relative; +} + +.tox .tox-edit-area__iframe { + background-color: #fff; + border: 0; + box-sizing: border-box; + flex: 1; + height: 100%; + position: absolute; + width: 100%; +} + +.tox.tox-inline-edit-area { + border: 1px dotted #161f29; +} + +.tox .tox-editor-container { + display: flex; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} + +.tox .tox-editor-header { + z-index: 1; +} + +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: #222f3e; + border-bottom: 1px solid rgba(255, 255, 255, 0.15); + box-shadow: none; + padding: 4px 0; + transition: box-shadow 0.5s; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: 1px solid rgba(255, 255, 255, 0.15); + box-shadow: none; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: #222f3e; + box-shadow: none; + padding: 4px 0; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: none; +} + +.tox-editor-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox-editor-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox-editor-dock-transition { + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} + +.tox-editor-dock-transition.tox-editor-dock-fadein { + transition-delay: 0s; +} + +.tox .tox-control-wrap { + flex: 1; + position: relative; +} + +.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, +.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, +.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { + display: none; +} + +.tox .tox-control-wrap svg { + display: block; +} + +.tox .tox-control-wrap__status-icon-wrap { + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-control-wrap__status-icon-invalid svg { + fill: #c00; +} + +.tox .tox-control-wrap__status-icon-unknown svg { + fill: orange; +} + +.tox .tox-control-wrap__status-icon-valid svg { + fill: green; +} + +.tox:not([dir='rtl']) .tox-control-wrap--status-invalid .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-unknown .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-valid .tox-textfield { + padding-right: 32px; +} + +.tox:not([dir='rtl']) .tox-control-wrap__status-icon-wrap { + right: 4px; +} + +.tox[dir='rtl'] .tox-control-wrap--status-invalid .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-unknown .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-valid .tox-textfield { + padding-left: 32px; +} + +.tox[dir='rtl'] .tox-control-wrap__status-icon-wrap { + left: 4px; +} + +.tox .tox-autocompleter { + max-width: 25em; +} + +.tox .tox-autocompleter .tox-menu { + border-color: #161f29; + box-shadow: none; + max-width: 25em; +} + +.tox .tox-autocompleter .tox-autocompleter-highlight { + font-weight: bold; +} + +.tox .tox-color-input { + display: flex; + position: relative; + z-index: 1; +} + +.tox .tox-color-input .tox-textfield { + z-index: -1; +} + +.tox .tox-color-input span { + border-color: rgba(34, 47, 62, 0.2); + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + height: 24px; + position: absolute; + top: 6px; + width: 24px; +} + +.tox .tox-color-input span:hover:not([aria-disabled='true']), +.tox .tox-color-input span:focus:not([aria-disabled='true']) { + border-color: #006ce7; + cursor: pointer; +} + +.tox .tox-color-input span::before { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), + linear-gradient(-45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%), + linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%); + background-position: 0 0, 0 6px, 6px -6px, -6px 0; + background-size: 12px 12px; + border: 1px solid #2b3b4e; + border-radius: 6px; + box-sizing: border-box; + content: ''; + height: 24px; + left: -1px; + position: absolute; + top: -1px; + width: 24px; + z-index: -1; +} + +.tox .tox-color-input span[aria-disabled='true'] { + cursor: not-allowed; +} + +.tox:not([dir='rtl']) .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir='rtl']) .tox-color-input .tox-textfield { + padding-left: 36px; +} + +.tox:not([dir='rtl']) .tox-color-input span { + left: 6px; +} + +.tox[dir='rtl'] .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir='rtl'] .tox-color-input .tox-textfield { + padding-right: 36px; +} + +.tox[dir='rtl'] .tox-color-input span { + right: 6px; +} + +.tox .tox-label, +.tox .tox-toolbar-label { + color: rgba(255, 255, 255, 0.5); + display: block; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + padding: 0 8px 0 0; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-toolbar-label { + padding: 0 8px; +} + +.tox[dir='rtl'] .tox-label { + padding: 0 0 0 8px; +} + +.tox .tox-form { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-form__group { + box-sizing: border-box; + margin-bottom: 4px; +} + +.tox .tox-form-group--maximize { + flex: 1; +} + +.tox .tox-form__group--error { + color: #c00; +} + +.tox .tox-form__group--collection { + display: flex; +} + +.tox .tox-form__grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} + +.tox .tox-form__grid--2col > .tox-form__group { + width: calc(50% - (8px / 2)); +} + +.tox .tox-form__grid--3col > .tox-form__group { + width: calc(100% / 3 - (8px / 2)); +} + +.tox .tox-form__grid--4col > .tox-form__group { + width: calc(25% - (8px / 2)); +} + +.tox .tox-form__controls-h-stack { + align-items: center; + display: flex; +} + +.tox .tox-form__group--inline { + align-items: center; + display: flex; +} + +.tox .tox-form__group--stretched { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-form__group--stretched .tox-textarea { + flex: 1; +} + +.tox .tox-form__group--stretched .tox-navobj { + display: flex; + flex: 1; +} + +.tox .tox-form__group--stretched .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} + +.tox:not([dir='rtl']) .tox-form__controls-h-stack > *:not(:first-child) { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-form__controls-h-stack > *:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-lock.tox-locked .tox-lock-icon__unlock, +.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { + display: none; +} + +.tox .tox-textfield, +.tox .tox-toolbar-textfield, +.tox .tox-listboxfield .tox-listbox--select, +.tox .tox-textarea { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #2b3b4e; + border-color: #161f29; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 5.5px; + resize: none; + width: 100%; +} + +.tox .tox-textfield[disabled], +.tox .tox-textarea[disabled] { + background-color: #222f3e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} + +.tox .tox-textfield:focus, +.tox .tox-listboxfield .tox-listbox--select:focus, +.tox .tox-textarea:focus { + background-color: #2b3b4e; + border-color: #006ce7; + box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); + outline: none; +} + +.tox .tox-toolbar-textfield { + border-width: 0; + margin-bottom: 3px; + margin-top: 2px; + max-width: 250px; +} + +.tox .tox-naked-btn { + background-color: transparent; + border: 0; + border-color: transparent; + box-shadow: unset; + color: #006ce7; + cursor: pointer; + display: block; + margin: 0; + padding: 0; +} + +.tox .tox-naked-btn svg { + display: block; + fill: #fff; +} + +.tox:not([dir='rtl']) .tox-toolbar-textfield + * { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-toolbar-textfield + * { + margin-right: 4px; +} + +.tox .tox-listboxfield { + cursor: pointer; + position: relative; +} + +.tox .tox-listboxfield .tox-listbox--select[disabled] { + background-color: #19232e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} + +.tox .tox-listbox__select-label { + cursor: default; + flex: 1; + margin: 0 4px; +} + +.tox .tox-listbox__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-listbox__select-chevron svg { + fill: #fff; +} + +.tox .tox-listboxfield .tox-listbox--select { + align-items: center; + display: flex; +} + +.tox:not([dir='rtl']) .tox-listboxfield svg { + right: 8px; +} + +.tox[dir='rtl'] .tox-listboxfield svg { + left: 8px; +} + +.tox .tox-selectfield { + cursor: pointer; + position: relative; +} + +.tox .tox-selectfield select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #2b3b4e; + border-color: #161f29; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 5.5px; + resize: none; + width: 100%; +} + +.tox .tox-selectfield select[disabled] { + background-color: #19232e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} + +.tox .tox-selectfield select::-ms-expand { + display: none; +} + +.tox .tox-selectfield select:focus { + background-color: #2b3b4e; + border-color: #006ce7; + box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); + outline: none; +} + +.tox .tox-selectfield svg { + pointer-events: none; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox:not([dir='rtl']) .tox-selectfield select[size='0'], +.tox:not([dir='rtl']) .tox-selectfield select[size='1'] { + padding-right: 24px; +} + +.tox:not([dir='rtl']) .tox-selectfield svg { + right: 8px; +} + +.tox[dir='rtl'] .tox-selectfield select[size='0'], +.tox[dir='rtl'] .tox-selectfield select[size='1'] { + padding-left: 24px; +} + +.tox[dir='rtl'] .tox-selectfield svg { + left: 8px; +} + +.tox .tox-textarea { + -webkit-appearance: textarea; + -moz-appearance: textarea; + appearance: textarea; + white-space: pre-wrap; +} + +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen, +.tox-shadowhost.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} + +.tox .tox-help__more-link { + list-style: none; + margin-top: 1em; +} + +.tox .tox-imagepreview { + background-color: #666; + height: 380px; + overflow: hidden; + position: relative; + width: 100%; +} + +.tox .tox-imagepreview.tox-imagepreview__loaded { + overflow: auto; +} + +.tox .tox-imagepreview__container { + display: flex; + left: 100vw; + position: absolute; + top: 100vw; +} + +.tox .tox-imagepreview__image { + background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); +} + +.tox .tox-image-tools .tox-spacer { + flex: 1; +} + +.tox .tox-image-tools .tox-bar { + align-items: center; + display: flex; + height: 60px; + justify-content: center; +} + +.tox .tox-image-tools .tox-imagepreview, +.tox .tox-image-tools .tox-imagepreview + .tox-bar { + margin-top: 8px; +} + +.tox .tox-image-tools .tox-croprect-block { + background: black; + filter: alpha(opacity=50); + opacity: 0.5; + position: absolute; + zoom: 1; +} + +.tox .tox-image-tools .tox-croprect-handle { + border: 2px solid white; + height: 20px; + left: 0; + position: absolute; + top: 0; + width: 20px; +} + +.tox .tox-image-tools .tox-croprect-handle-move { + border: 0; + cursor: move; + position: absolute; +} + +.tox .tox-image-tools .tox-croprect-handle-nw { + border-width: 2px 0 0 2px; + cursor: nw-resize; + left: 100px; + margin: -2px 0 0 -2px; + top: 100px; +} + +.tox .tox-image-tools .tox-croprect-handle-ne { + border-width: 2px 2px 0 0; + cursor: ne-resize; + left: 200px; + margin: -2px 0 0 -20px; + top: 100px; +} + +.tox .tox-image-tools .tox-croprect-handle-sw { + border-width: 0 0 2px 2px; + cursor: sw-resize; + left: 100px; + margin: -20px 2px 0 -2px; + top: 200px; +} + +.tox .tox-image-tools .tox-croprect-handle-se { + border-width: 0 2px 2px 0; + cursor: se-resize; + left: 200px; + margin: -20px 0 0 -20px; + top: 200px; +} + +.tox .tox-insert-table-picker { + display: flex; + flex-wrap: wrap; + width: 170px; +} + +.tox .tox-insert-table-picker > div { + border-color: rgba(255, 255, 255, 0.15); + border-style: solid; + border-width: 0 1px 1px 0; + box-sizing: border-box; + height: 17px; + width: 17px; +} + +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: -4px -4px; +} + +.tox .tox-insert-table-picker .tox-insert-table-picker__selected { + background-color: rgba(0, 108, 231, 0.5); + border-color: rgba(0, 108, 231, 0.5); +} + +.tox .tox-insert-table-picker__label { + color: #fff; + display: block; + font-size: 14px; + padding: 4px; + text-align: center; + width: 100%; +} + +.tox:not([dir='rtl']) { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir='rtl']) .tox-insert-table-picker > div:nth-child(10n) { + border-right: 0; +} + +.tox[dir='rtl'] { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir='rtl'] .tox-insert-table-picker > div:nth-child(10n + 1) { + border-right: 0; +} + +.tox { + /* stylelint-disable */ + /* stylelint-enable */ +} + +.tox .tox-menu { + background-color: #2b3b4e; + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 6px; + box-shadow: none; + display: inline-block; + overflow: hidden; + vertical-align: top; + z-index: 1150; +} + +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0 4px; +} + +.tox .tox-menu.tox-collection.tox-collection--toolbar { + padding: 8px; +} + +.tox .tox-menu.tox-collection.tox-collection--grid { + padding: 8px; +} + +.tox .tox-menu__label h1, +.tox .tox-menu__label h2, +.tox .tox-menu__label h3, +.tox .tox-menu__label h4, +.tox .tox-menu__label h5, +.tox .tox-menu__label h6, +.tox .tox-menu__label p, +.tox .tox-menu__label blockquote, +.tox .tox-menu__label code { + margin: 0; +} + +.tox .tox-menubar { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='transparent'/%3E%3C/svg%3E") left 0 top 0 #222f3e; + background-color: #222f3e; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 11px 0 12px; +} + +.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { + border-top: 1px solid transparent; +} + +/* Deprecated. Remove in next major release */ +.tox .tox-mbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 28px; + justify-content: center; + margin: 5px 1px 6px 0; + outline: none; + overflow: hidden; + padding: 0 4px; + text-transform: none; + width: auto; +} + +.tox .tox-mbtn[disabled] { + background-color: transparent; + border: 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-mbtn:focus:not(:disabled) { + background: #3389ec; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-mbtn--active { + background: #599fef; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { + background: #3389ec; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-mbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-mbtn[disabled] .tox-mbtn__select-label { + cursor: not-allowed; +} + +.tox .tox-mbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; + display: none; +} + +.tox .tox-notification { + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + display: grid; + font-size: 14px; + font-weight: normal; + grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + margin-top: 4px; + opacity: 0; + padding: 4px; + transition: transform 100ms ease-in, opacity 150ms ease-in; +} + +.tox .tox-notification p { + font-size: 14px; + font-weight: normal; +} + +.tox .tox-notification a { + cursor: pointer; + text-decoration: underline; +} + +.tox .tox-notification--in { + opacity: 1; +} + +.tox .tox-notification--success { + background-color: #334840; + border-color: #3c5440; + color: #fff; +} + +.tox .tox-notification--success p { + color: #fff; +} + +.tox .tox-notification--success a { + color: #b5d199; +} + +.tox .tox-notification--success svg { + fill: #fff; +} + +.tox .tox-notification--error { + background-color: #442632; + border-color: #55212b; + color: #fff; +} + +.tox .tox-notification--error p { + color: #fff; +} + +.tox .tox-notification--error a { + color: #e68080; +} + +.tox .tox-notification--error svg { + fill: #fff; +} + +.tox .tox-notification--warn, +.tox .tox-notification--warning { + background-color: #222f3e; + border-color: rgba(255, 255, 255, 0.15); + color: #fff0b3; +} + +.tox .tox-notification--warn p, +.tox .tox-notification--warning p { + color: #fff0b3; +} + +.tox .tox-notification--warn a, +.tox .tox-notification--warning a { + color: #ffcc00; +} + +.tox .tox-notification--warn svg, +.tox .tox-notification--warning svg { + fill: #fff0b3; +} + +.tox .tox-notification--info { + background-color: #254161; + border-color: #264972; + color: #fff; +} + +.tox .tox-notification--info p { + color: #fff; +} + +.tox .tox-notification--info a { + color: #83b7f3; +} + +.tox .tox-notification--info svg { + fill: #fff; +} + +.tox .tox-notification__body { + align-self: center; + color: #fff; + font-size: 14px; + grid-column-end: 3; + grid-column-start: 2; + grid-row-end: 2; + grid-row-start: 1; + text-align: center; + white-space: normal; + word-break: break-all; + word-break: break-word; +} + +.tox .tox-notification__body > * { + margin: 0; +} + +.tox .tox-notification__body > * + * { + margin-top: 1rem; +} + +.tox .tox-notification__icon { + align-self: center; + grid-column-end: 2; + grid-column-start: 1; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} + +.tox .tox-notification__icon svg { + display: block; +} + +.tox .tox-notification__dismiss { + align-self: start; + grid-column-end: 4; + grid-column-start: 3; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} + +.tox .tox-notification .tox-progress-bar { + grid-column-end: 4; + grid-column-start: 1; + grid-row-end: 3; + grid-row-start: 2; + justify-self: center; +} + +.tox .tox-pop { + display: inline-block; + position: relative; +} + +.tox .tox-pop--resizing { + transition: width 0.1s ease; +} + +.tox .tox-pop--resizing .tox-toolbar, +.tox .tox-pop--resizing .tox-toolbar__group { + flex-wrap: nowrap; +} + +.tox .tox-pop--transition { + transition: 0.15s ease; + transition-property: left, right, top, bottom; +} + +.tox .tox-pop--transition::before, +.tox .tox-pop--transition::after { + transition: all 0.15s, visibility 0s, opacity 0.075s ease 0.075s; +} + +.tox .tox-pop__dialog { + background-color: #222f3e; + border: 1px solid #161f29; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + min-width: 0; + overflow: hidden; +} + +.tox .tox-pop__dialog > *:not(.tox-toolbar) { + margin: 4px 4px 4px 8px; +} + +.tox .tox-pop__dialog .tox-toolbar { + background-color: transparent; + margin-bottom: -1px; +} + +.tox .tox-pop::before, +.tox .tox-pop::after { + border-style: solid; + content: ''; + display: block; + height: 0; + opacity: 1; + position: absolute; + width: 0; +} + +.tox .tox-pop.tox-pop--inset::before, +.tox .tox-pop.tox-pop--inset::after { + opacity: 0; + transition: all 0s 0.15s, visibility 0s, opacity 0.075s ease; +} + +.tox .tox-pop.tox-pop--bottom::before, +.tox .tox-pop.tox-pop--bottom::after { + left: 50%; + top: 100%; +} + +.tox .tox-pop.tox-pop--bottom::after { + border-color: #222f3e transparent transparent transparent; + border-width: 8px; + margin-left: -8px; + margin-top: -1px; +} + +.tox .tox-pop.tox-pop--bottom::before { + border-color: #161f29 transparent transparent transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--top::before, +.tox .tox-pop.tox-pop--top::after { + left: 50%; + top: 0; + transform: translateY(-100%); +} + +.tox .tox-pop.tox-pop--top::after { + border-color: transparent transparent #222f3e transparent; + border-width: 8px; + margin-left: -8px; + margin-top: 1px; +} + +.tox .tox-pop.tox-pop--top::before { + border-color: transparent transparent #161f29 transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--left::before, +.tox .tox-pop.tox-pop--left::after { + left: 0; + top: calc(50% - 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--left::after { + border-color: transparent #222f3e transparent transparent; + border-width: 8px; + margin-left: -15px; +} + +.tox .tox-pop.tox-pop--left::before { + border-color: transparent #161f29 transparent transparent; + border-width: 10px; + margin-left: -19px; +} + +.tox .tox-pop.tox-pop--right::before, +.tox .tox-pop.tox-pop--right::after { + left: 100%; + top: calc(50% + 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--right::after { + border-color: transparent transparent transparent #222f3e; + border-width: 8px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--right::before { + border-color: transparent transparent transparent #161f29; + border-width: 10px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--align-left::before, +.tox .tox-pop.tox-pop--align-left::after { + left: 20px; +} + +.tox .tox-pop.tox-pop--align-right::before, +.tox .tox-pop.tox-pop--align-right::after { + left: calc(100% - 20px); +} + +.tox .tox-sidebar-wrap { + display: flex; + flex-direction: row; + flex-grow: 1; + min-height: 0; +} + +.tox .tox-sidebar { + background-color: #222f3e; + display: flex; + flex-direction: row; + justify-content: flex-end; +} + +.tox .tox-sidebar__slider { + display: flex; + overflow: hidden; +} + +.tox .tox-sidebar__pane-container { + display: flex; +} + +.tox .tox-sidebar__pane { + display: flex; +} + +.tox .tox-sidebar--sliding-closed { + opacity: 0; +} + +.tox .tox-sidebar--sliding-open { + opacity: 1; +} + +.tox .tox-sidebar--sliding-growing, +.tox .tox-sidebar--sliding-shrinking { + transition: width 0.5s ease, opacity 0.5s ease; +} + +.tox .tox-selector { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + display: inline-block; + height: 10px; + position: absolute; + width: 10px; +} + +.tox.tox-platform-touch .tox-selector { + height: 12px; + width: 12px; +} + +.tox .tox-slider { + align-items: center; + display: flex; + flex: 1; + height: 24px; + justify-content: center; + position: relative; +} + +.tox .tox-slider__rail { + background-color: transparent; + border: 1px solid #161f29; + border-radius: 6px; + height: 10px; + min-width: 120px; + width: 100%; +} + +.tox .tox-slider__handle { + background-color: #006ce7; + border: 2px solid #0054b4; + border-radius: 6px; + box-shadow: none; + height: 24px; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: 14px; +} + +.tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { + margin-inline-start: 8px; +} + +.tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { + margin-inline-start: 32px; +} + +.tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { + margin-inline-start: 32px; +} + +.tox .tox-source-code { + overflow: auto; +} + +.tox .tox-spinner { + display: flex; +} + +.tox .tox-spinner > div { + animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; + background-color: rgba(255, 255, 255, 0.5); + border-radius: 100%; + height: 8px; + width: 8px; +} + +.tox .tox-spinner > div:nth-child(1) { + animation-delay: -0.32s; +} + +.tox .tox-spinner > div:nth-child(2) { + animation-delay: -0.16s; +} + +@keyframes tam-bouncing-dots { + 0%, + 80%, + 100% { + transform: scale(0); + } + 40% { + transform: scale(1); + } +} + +.tox:not([dir='rtl']) .tox-spinner > div:not(:first-child) { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-spinner > div:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-statusbar { + align-items: center; + background-color: #222f3e; + border-top: 1px solid rgba(255, 255, 255, 0.15); + color: rgba(255, 255, 255, 0.75); + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-weight: normal; + height: 25px; + overflow: hidden; + padding: 0 8px; + position: relative; + text-transform: none; +} + +.tox .tox-statusbar__text-container { + display: flex; + flex: 1 1 auto; + justify-content: flex-end; + overflow: hidden; +} + +.tox .tox-statusbar__path { + display: flex; + flex: 1 1 auto; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tox .tox-statusbar__path > * { + display: inline; + white-space: nowrap; +} + +.tox .tox-statusbar__wordcount { + flex: 0 0 auto; + margin-left: 1ch; +} + +.tox .tox-statusbar a, +.tox .tox-statusbar__path-item, +.tox .tox-statusbar__wordcount { + color: rgba(255, 255, 255, 0.75); + text-decoration: none; +} + +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']) { + color: #fff; + cursor: pointer; +} + +.tox .tox-statusbar__branding svg { + fill: rgba(255, 255, 255, 0.8); + height: 1.14em; + vertical-align: -0.28em; + width: 3.6em; +} + +.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled='true']) svg, +.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled='true']) svg { + fill: #fff; +} + +.tox .tox-statusbar__resize-handle { + align-items: flex-end; + align-self: stretch; + cursor: nwse-resize; + display: flex; + flex: 0 0 auto; + justify-content: flex-end; + margin-left: auto; + margin-right: -8px; + padding-bottom: 3px; + padding-left: 1ch; + padding-right: 3px; +} + +.tox .tox-statusbar__resize-handle svg { + display: block; + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-statusbar__resize-handle:focus svg { + background-color: #434e5b; + border-radius: 1px 1px 5px 1px; + box-shadow: 0 0 0 2px #434e5b; +} + +.tox:not([dir='rtl']) .tox-statusbar__path > * { + margin-right: 4px; +} + +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 2ch; +} + +.tox[dir='rtl'] .tox-statusbar { + flex-direction: row-reverse; +} + +.tox[dir='rtl'] .tox-statusbar__path > * { + margin-left: 4px; +} + +.tox .tox-throbber { + z-index: 1299; +} + +.tox .tox-throbber__busy-spinner { + align-items: center; + background-color: rgba(34, 47, 62, 0.6); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.tox .tox-tbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 28px; + justify-content: center; + margin: 6px 1px 5px 0; + outline: none; + overflow: hidden; + padding: 0; + text-transform: none; + width: 34px; +} + +.tox .tox-tbtn svg { + display: block; + fill: #fff; +} + +.tox .tox-tbtn.tox-tbtn-more { + padding-left: 5px; + padding-right: 5px; + width: inherit; +} + +.tox .tox-tbtn:focus { + background: #3389ec; + border: 0; + box-shadow: none; +} + +.tox .tox-tbtn:hover { + background: #3389ec; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-tbtn:hover svg { + fill: #fff; +} + +.tox .tox-tbtn:active { + background: #599fef; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-tbtn:active svg { + fill: #fff; +} + +.tox .tox-tbtn--disabled, +.tox .tox-tbtn--disabled:hover, +.tox .tox-tbtn:disabled, +.tox .tox-tbtn:disabled:hover { + background: transparent; + border: 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-tbtn--disabled svg, +.tox .tox-tbtn--disabled:hover svg, +.tox .tox-tbtn:disabled svg, +.tox .tox-tbtn:disabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-tbtn--enabled, +.tox .tox-tbtn--enabled:hover { + background: #599fef; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-tbtn--enabled > *, +.tox .tox-tbtn--enabled:hover > * { + transform: none; +} + +.tox .tox-tbtn--enabled svg, +.tox .tox-tbtn--enabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: #fff; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { + color: #fff; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { + fill: #fff; +} + +.tox .tox-tbtn:active > * { + transform: none; +} + +.tox .tox-tbtn--md { + height: 42px; + width: 51px; +} + +.tox .tox-tbtn--lg { + flex-direction: column; + height: 56px; + width: 68px; +} + +.tox .tox-tbtn--return { + align-self: stretch; + height: unset; + width: 16px; +} + +.tox .tox-tbtn--labeled { + padding: 0 4px; + width: unset; +} + +.tox .tox-tbtn__vlabel { + display: block; + font-size: 10px; + font-weight: normal; + letter-spacing: -0.025em; + margin-bottom: 4px; + white-space: nowrap; +} + +.tox .tox-tbtn--select { + margin: 6px 1px 5px 0; + padding: 0 4px; + width: auto; +} + +.tox .tox-tbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-tbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-tbtn__select-chevron svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-tbtn--bespoke { + background: #2f4055; +} + +.tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { + margin-inline-start: 4px; +} + +.tox .tox-tbtn--bespoke .tox-tbtn__select-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 7em; +} + +.tox .tox-split-button { + border: 0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + margin: 6px 1px 5px 0; + overflow: hidden; +} + +.tox .tox-split-button:hover { + box-shadow: 0 0 0 1px #3389ec inset; +} + +.tox .tox-split-button:focus { + background: #3389ec; + box-shadow: none; + color: #fff; +} + +.tox .tox-split-button > * { + border-radius: 0; +} + +.tox .tox-split-button__chevron { + width: 16px; +} + +.tox .tox-split-button__chevron svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-split-button .tox-tbtn { + margin: 0; +} + +.tox .tox-split-button.tox-tbtn--disabled:hover, +.tox .tox-split-button.tox-tbtn--disabled:focus, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus { + background: transparent; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} + +.tox.tox-platform-touch .tox-split-button .tox-tbtn--select { + padding: 0 0px; +} + +.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { + width: 30px; +} + +.tox.tox-platform-touch .tox-split-button__chevron { + width: 20px; +} + +.tox .tox-toolbar-overlord { + background-color: #222f3e; +} + +.tox .tox-toolbar, +.tox .tox-toolbar__primary, +.tox .tox-toolbar__overflow { + background-color: #222f3e; + background-image: repeating-linear-gradient(rgba(255, 255, 255, 0.15) 0px 1px, transparent 1px 39px); + background-position: center top 40px; + background-repeat: no-repeat; + background-size: calc(100% - 11px * 2) calc(100% - 41px); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 0px; + transform: perspective(1px); +} + +.tox .tox-toolbar-overlord > .tox-toolbar, +.tox .tox-toolbar-overlord > .tox-toolbar__primary, +.tox .tox-toolbar-overlord > .tox-toolbar__overflow { + background-position: center top 0px; + background-size: calc(100% - 11px * 2) calc(100% - 0px); +} + +.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { + height: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; + visibility: hidden; +} + +.tox .tox-toolbar__overflow--growing { + transition: height 0.3s ease, opacity 0.2s linear 0.1s; +} + +.tox .tox-toolbar__overflow--shrinking { + transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; +} + +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: 1px solid transparent; + margin-top: 0px; + padding-bottom: 1px; + padding-top: 1px; +} + +.tox .tox-toolbar--scrolling { + flex-wrap: nowrap; + overflow-x: auto; +} + +.tox .tox-pop .tox-toolbar { + border-width: 0; +} + +.tox .tox-toolbar--no-divider { + background-image: none; +} + +.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, +.tox .tox-toolbar-overlord .tox-toolbar__primary { + background-position: center top 39px; +} + +.tox .tox-editor-header > .tox-toolbar--scrolling, +.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { + background-image: none; +} + +.tox.tox-tinymce-aux .tox-toolbar__overflow { + background-color: #222f3e; + background-position: center top 43px; + background-size: calc(100% - 8px * 2) calc(100% - 51px); + border: none; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + padding: 4px 0; +} + +.tox-pop .tox-pop__dialog { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox-pop .tox-pop__dialog .tox-toolbar { + background-position: center top 43px; + background-size: calc(100% - 11px * 2) calc(100% - 51px); + padding: 4px 0; +} + +.tox .tox-toolbar__group { + align-items: center; + display: flex; + flex-wrap: wrap; + margin: 0 0; + padding: 0 11px 0 12px; +} + +.tox .tox-toolbar__group--pull-right { + margin-left: auto; +} + +.tox .tox-toolbar--scrolling .tox-toolbar__group { + flex-shrink: 0; + flex-wrap: nowrap; +} + +.tox:not([dir='rtl']) .tox-toolbar__group:not(:last-of-type) { + border-right: 1px solid transparent; +} + +.tox[dir='rtl'] .tox-toolbar__group:not(:last-of-type) { + border-left: 1px solid transparent; +} + +.tox .tox-tooltip { + display: inline-block; + padding: 8px; + position: relative; +} + +.tox .tox-tooltip__body { + background-color: #3d546f; + border-radius: 6px; + box-shadow: 0 2px 4px rgba(34, 47, 62, 0.3); + color: rgba(255, 255, 255, 0.75); + font-size: 14px; + font-style: normal; + font-weight: normal; + padding: 4px 8px; + text-transform: none; +} + +.tox .tox-tooltip__arrow { + position: absolute; +} + +.tox .tox-tooltip--down .tox-tooltip__arrow { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #3d546f; + bottom: 0; + left: 50%; + position: absolute; + transform: translateX(-50%); +} + +.tox .tox-tooltip--up .tox-tooltip__arrow { + border-bottom: 8px solid #3d546f; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + left: 50%; + position: absolute; + top: 0; + transform: translateX(-50%); +} + +.tox .tox-tooltip--right .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-left: 8px solid #3d546f; + border-top: 8px solid transparent; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-tooltip--left .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-right: 8px solid #3d546f; + border-top: 8px solid transparent; + left: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-well { + border: 1px solid #161f29; + border-radius: 6px; + padding: 8px; + width: 100%; +} + +.tox .tox-well > *:first-child { + margin-top: 0; +} + +.tox .tox-well > *:last-child { + margin-bottom: 0; +} + +.tox .tox-well > *:only-child { + margin: 0; +} + +.tox .tox-custom-editor { + border: 1px solid #161f29; + border-radius: 6px; + display: flex; + flex: 1; + position: relative; +} + +/* stylelint-disable */ +.tox { + /* stylelint-enable */ +} + +.tox .tox-dialog-loading::before { + background-color: rgba(0, 0, 0, 0.5); + content: ''; + height: 100%; + position: absolute; + width: 100%; + z-index: 1000; +} + +.tox .tox-tab { + cursor: pointer; +} + +.tox .tox-dialog__content-js { + display: flex; + flex: 1; +} + +.tox .tox-dialog__body-content .tox-collection { + display: flex; + flex: 1; +} + +.tox.tox-tinymce-aux .tox-toolbar__overflow { + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.15); +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.min.css b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.min.css new file mode 100644 index 00000000..842afba1 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.min.css @@ -0,0 +1,3043 @@ +.tox { + box-shadow: none; + box-sizing: content-box; + color: #222f3e; + cursor: auto; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + -webkit-tap-highlight-color: transparent; + text-decoration: none; + text-shadow: none; + text-transform: none; + vertical-align: initial; + white-space: normal; +} +.tox :not(svg):not(rect) { + box-sizing: inherit; + color: inherit; + cursor: inherit; + direction: inherit; + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; + line-height: inherit; + -webkit-tap-highlight-color: inherit; + text-align: inherit; + text-decoration: inherit; + text-shadow: inherit; + text-transform: inherit; + vertical-align: inherit; + white-space: inherit; +} +.tox :not(svg):not(rect) { + background: 0 0; + border: 0; + box-shadow: none; + float: none; + height: auto; + margin: 0; + max-width: none; + outline: 0; + padding: 0; + position: static; + width: auto; +} +.tox:not([dir='rtl']) { + direction: ltr; + text-align: left; +} +.tox[dir='rtl'] { + direction: rtl; + text-align: right; +} +.tox-tinymce { + border: 2px solid #161f29; + border-radius: 10px; + box-shadow: none; + box-sizing: border-box; + display: flex; + flex-direction: column; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + overflow: hidden; + position: relative; + visibility: inherit !important; +} +.tox.tox-tinymce-inline { + border: none; + box-shadow: none; + overflow: initial; +} +.tox.tox-tinymce-inline .tox-editor-container { + overflow: initial; +} +.tox.tox-tinymce-inline .tox-editor-header { + background-color: #222f3e; + border: 2px solid #161f29; + border-radius: 10px; + box-shadow: none; + overflow: hidden; +} +.tox-tinymce-aux { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + z-index: 1300; +} +.tox-tinymce :focus, +.tox-tinymce-aux :focus { + outline: 0; +} +button::-moz-focus-inner { + border: 0; +} +.tox[dir='rtl'] .tox-icon--flip svg { + transform: rotateY(180deg); +} +.tox .accessibility-issue__header { + align-items: center; + display: flex; + margin-bottom: 4px; +} +.tox .accessibility-issue__description { + align-items: stretch; + border: 1px solid #161f29; + border-radius: 6px; + display: flex; + justify-content: space-between; +} +.tox .accessibility-issue__description > div { + padding-bottom: 4px; +} +.tox .accessibility-issue__description > div > div { + align-items: center; + display: flex; + margin-bottom: 4px; +} +.tox .accessibility-issue__description > :last-child:not(:only-child) { + border-color: #161f29; + border-style: solid; +} +.tox .accessibility-issue__repair { + margin-top: 16px; +} +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { + background-color: rgba(0, 108, 231, 0.5); + border-color: rgba(0, 108, 231, 0.4); + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description > :last-child { + border-color: rgba(0, 108, 231, 0.4); +} +.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { + fill: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { + background-color: rgba(255, 165, 0, 0.5); + border-color: rgba(255, 165, 0, 0.8); + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description > :last-child { + border-color: rgba(255, 165, 0, 0.8); +} +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { + fill: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { + background-color: rgba(204, 0, 0, 0.5); + border-color: rgba(204, 0, 0, 0.8); + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description > :last-child { + border-color: rgba(204, 0, 0, 0.8); +} +.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { + fill: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { + background-color: rgba(120, 171, 70, 0.5); + border-color: rgba(120, 171, 70, 0.8); + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > :last-child { + border-color: rgba(120, 171, 70, 0.8); +} +.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { + fill: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue__header h1, +.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { + margin-top: 0; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header > :nth-last-child(2) { + margin-left: auto; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 4px 4px 8px; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description > :last-child { + border-left-width: 1px; + padding-left: 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header > :nth-last-child(2) { + margin-right: auto; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 8px 4px 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description > :last-child { + border-right-width: 1px; + padding-right: 4px; +} +.tox .tox-anchorbar { + display: flex; + flex: 0 0 auto; +} +.tox .tox-bar { + display: flex; + flex: 0 0 auto; +} +.tox .tox-button { + background-color: #006ce7; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #006ce7; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 14px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + line-height: 24px; + margin: 0; + outline: 0; + padding: 4px 16px; + text-align: center; + text-decoration: none; + text-transform: none; + white-space: nowrap; +} +.tox .tox-button[disabled] { + background-color: #006ce7; + background-image: none; + border-color: #006ce7; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-button:focus:not(:disabled) { + background-color: #0060ce; + background-image: none; + border-color: #0060ce; + box-shadow: none; + color: #fff; +} +.tox .tox-button:hover:not(:disabled) { + background-color: #0060ce; + background-image: none; + border-color: #0060ce; + box-shadow: none; + color: #fff; +} +.tox .tox-button:active:not(:disabled) { + background-color: #0054b4; + background-image: none; + border-color: #0054b4; + box-shadow: none; + color: #fff; +} +.tox .tox-button--secondary { + background-color: #3d546f; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #3d546f; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + color: #fff; + font-size: 14px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + outline: 0; + padding: 4px 16px; + text-decoration: none; + text-transform: none; +} +.tox .tox-button--secondary[disabled] { + background-color: #3d546f; + background-image: none; + border-color: #3d546f; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} +.tox .tox-button--secondary:focus:not(:disabled) { + background-color: #34485f; + background-image: none; + border-color: #34485f; + box-shadow: none; + color: #fff; +} +.tox .tox-button--secondary:hover:not(:disabled) { + background-color: #34485f; + background-image: none; + border-color: #34485f; + box-shadow: none; + color: #fff; +} +.tox .tox-button--secondary:active:not(:disabled) { + background-color: #2b3b4e; + background-image: none; + border-color: #2b3b4e; + box-shadow: none; + color: #fff; +} +.tox .tox-button--icon, +.tox .tox-button.tox-button--icon, +.tox .tox-button.tox-button--secondary.tox-button--icon { + padding: 4px; +} +.tox .tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { + display: block; + fill: currentColor; +} +.tox .tox-button-link { + background: 0; + border: none; + box-sizing: border-box; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-weight: 400; + line-height: 1.3; + margin: 0; + padding: 0; + white-space: nowrap; +} +.tox .tox-button-link--sm { + font-size: 14px; +} +.tox .tox-button--naked { + background-color: transparent; + border-color: transparent; + box-shadow: unset; + color: #fff; +} +.tox .tox-button--naked[disabled] { + background-color: rgba(255, 255, 255, 0.2); + border-color: transparent; + box-shadow: unset; + color: rgba(255, 255, 255, 0.5); +} +.tox .tox-button--naked:hover:not(:disabled) { + background-color: rgba(255, 255, 255, 0.2); + border-color: transparent; + box-shadow: unset; + color: #fff; +} +.tox .tox-button--naked:focus:not(:disabled) { + background-color: rgba(255, 255, 255, 0.2); + border-color: transparent; + box-shadow: unset; + color: #fff; +} +.tox .tox-button--naked:active:not(:disabled) { + background-color: rgba(255, 255, 255, 0.3); + border-color: transparent; + box-shadow: unset; + color: #fff; +} +.tox .tox-button--naked .tox-icon svg { + fill: currentColor; +} +.tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { + color: #fff; +} +.tox .tox-checkbox { + align-items: center; + border-radius: 6px; + cursor: pointer; + display: flex; + height: 36px; + min-width: 36px; +} +.tox .tox-checkbox__input { + height: 1px; + overflow: hidden; + position: absolute; + top: auto; + width: 1px; +} +.tox .tox-checkbox__icons { + align-items: center; + border-radius: 6px; + box-shadow: 0 0 0 2px transparent; + box-sizing: content-box; + display: flex; + height: 24px; + justify-content: center; + padding: calc(4px - 1px); + width: 24px; +} +.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: block; + fill: rgba(255, 255, 255, 0.2); +} +.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: none; + fill: #006ce7; +} +.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: none; + fill: #006ce7; +} +.tox .tox-checkbox--disabled { + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: block; +} +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: block; +} +.tox input.tox-checkbox__input:focus + .tox-checkbox__icons { + border-radius: 6px; + box-shadow: inset 0 0 0 1px #006ce7; + padding: calc(4px - 1px); +} +.tox:not([dir='rtl']) .tox-checkbox__label { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-checkbox__input { + left: -10000px; +} +.tox:not([dir='rtl']) .tox-bar .tox-checkbox { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-checkbox__label { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-checkbox__input { + right: -10000px; +} +.tox[dir='rtl'] .tox-bar .tox-checkbox { + margin-right: 4px; +} +.tox .tox-collection--toolbar .tox-collection__group { + display: flex; + padding: 0; +} +.tox .tox-collection--grid .tox-collection__group { + display: flex; + flex-wrap: wrap; + max-height: 208px; + overflow-x: hidden; + overflow-y: auto; + padding: 0; +} +.tox .tox-collection--list .tox-collection__group { + border-bottom-width: 0; + border-color: rgba(255, 255, 255, 0.15); + border-left-width: 0; + border-right-width: 0; + border-style: solid; + border-top-width: 1px; + padding: 4px 0; +} +.tox .tox-collection--list .tox-collection__group:first-child { + border-top-width: 0; +} +.tox .tox-collection__group-heading { + background-color: rgba(255, 255, 255, 0.15); + color: rgba(255, 255, 255, 0.5); + cursor: default; + font-size: 12px; + font-style: normal; + font-weight: 400; + margin-bottom: 4px; + margin-top: -4px; + padding: 4px 8px; + text-transform: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.tox .tox-collection__item { + align-items: center; + border-radius: 3px; + color: #fff; + display: flex; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.tox .tox-collection--list .tox-collection__item { + padding: 4px 8px; +} +.tox .tox-collection--toolbar .tox-collection__item { + border-radius: 3px; + padding: 4px; +} +.tox .tox-collection--grid .tox-collection__item { + border-radius: 3px; + padding: 4px; +} +.tox .tox-collection--list .tox-collection__item--enabled { + background-color: #2b3b4e; + color: #fff; +} +.tox .tox-collection--list .tox-collection__item--active { + background-color: #3389ec; +} +.tox .tox-collection--toolbar .tox-collection__item--enabled { + background-color: #599fef; + color: #fff; +} +.tox .tox-collection--toolbar .tox-collection__item--active { + background-color: #3389ec; +} +.tox .tox-collection--grid .tox-collection__item--enabled { + background-color: #599fef; + color: #fff; +} +.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + background-color: #3389ec; + color: #fff; +} +.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #fff; +} +.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #fff; +} +.tox .tox-collection__item-checkmark, +.tox .tox-collection__item-icon { + align-items: center; + display: flex; + height: 24px; + justify-content: center; + width: 24px; +} +.tox .tox-collection__item-checkmark svg, +.tox .tox-collection__item-icon svg { + fill: currentColor; +} +.tox .tox-collection--toolbar-lg .tox-collection__item-icon { + height: 48px; + width: 48px; +} +.tox .tox-collection__item-label { + color: currentColor; + display: inline-block; + flex: 1; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 24px; + text-transform: none; + word-break: break-all; +} +.tox .tox-collection__item-accessory { + color: rgba(255, 255, 255, 0.5); + display: inline-block; + font-size: 14px; + height: 24px; + line-height: 24px; + text-transform: none; +} +.tox .tox-collection__item-caret { + align-items: center; + display: flex; + min-height: 24px; +} +.tox .tox-collection__item-caret::after { + content: ''; + font-size: 0; + min-height: inherit; +} +.tox .tox-collection__item-caret svg { + fill: #fff; +} +.tox .tox-collection__item--state-disabled { + background-color: transparent; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox + .tox-collection--list + .tox-collection__item:not(.tox-collection__item--enabled) + .tox-collection__item-checkmark + svg { + display: none; +} +.tox + .tox-collection--list + .tox-collection__item:not(.tox-collection__item--enabled) + .tox-collection__item-accessory + + .tox-collection__item-checkmark { + display: none; +} +.tox .tox-collection--horizontal { + background-color: #2b3b4e; + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: nowrap; + margin-bottom: 0; + overflow-x: auto; + padding: 0; +} +.tox .tox-collection--horizontal .tox-collection__group { + align-items: center; + display: flex; + flex-wrap: nowrap; + margin: 0; + padding: 0 4px; +} +.tox .tox-collection--horizontal .tox-collection__item { + height: 28px; + margin: 6px 1px 5px 0; + padding: 0 4px; +} +.tox .tox-collection--horizontal .tox-collection__item-label { + white-space: nowrap; +} +.tox .tox-collection--horizontal .tox-collection__item-caret { + margin-left: 4px; +} +.tox .tox-collection__item-container { + display: flex; +} +.tox .tox-collection__item-container--row { + align-items: center; + flex: 1 1 auto; + flex-direction: row; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--align-left { + margin-right: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--align-right { + justify-content: flex-end; + margin-left: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { + align-items: flex-start; + margin-bottom: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { + align-items: center; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { + align-items: flex-end; + margin-top: auto; +} +.tox .tox-collection__item-container--column { + align-self: center; + flex: 1 1 auto; + flex-direction: column; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--align-left { + align-items: flex-start; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--align-right { + align-items: flex-end; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { + align-self: flex-start; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { + align-self: center; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { + align-self: flex-end; +} +.tox:not([dir='rtl']) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-right: 1px solid transparent; +} +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > :not(:first-child) { + margin-left: 8px; +} +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-collection__item-accessory { + margin-left: 16px; + text-align: right; +} +.tox:not([dir='rtl']) .tox-collection .tox-collection__item-caret { + margin-left: 16px; +} +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-left: 1px solid transparent; +} +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > :not(:first-child) { + margin-right: 8px; +} +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-collection__item-accessory { + margin-right: 16px; + text-align: left; +} +.tox[dir='rtl'] .tox-collection .tox-collection__item-caret { + margin-right: 16px; + transform: rotateY(180deg); +} +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__item-caret { + margin-right: 4px; +} +.tox .tox-color-picker-container { + display: flex; + flex-direction: row; + height: 225px; + margin: 0; +} +.tox .tox-sv-palette { + box-sizing: border-box; + display: flex; + height: 100%; +} +.tox .tox-sv-palette-spectrum { + height: 100%; +} +.tox .tox-sv-palette, +.tox .tox-sv-palette-spectrum { + width: 225px; +} +.tox .tox-sv-palette-thumb { + background: 0 0; + border: 1px solid #000; + border-radius: 50%; + box-sizing: content-box; + height: 12px; + position: absolute; + width: 12px; +} +.tox .tox-sv-palette-inner-thumb { + border: 1px solid #fff; + border-radius: 50%; + height: 10px; + position: absolute; + width: 10px; +} +.tox .tox-hue-slider { + box-sizing: border-box; + height: 100%; + width: 25px; +} +.tox .tox-hue-slider-spectrum { + background: linear-gradient( + to bottom, + red, + #ff0080, + #f0f, + #8000ff, + #00f, + #0080ff, + #0ff, + #00ff80, + #0f0, + #80ff00, + #ff0, + #ff8000, + red + ); + height: 100%; + width: 100%; +} +.tox .tox-hue-slider, +.tox .tox-hue-slider-spectrum { + width: 20px; +} +.tox .tox-hue-slider-thumb { + background: #fff; + border: 1px solid #000; + box-sizing: content-box; + height: 4px; + width: 100%; +} +.tox .tox-rgb-form { + display: flex; + flex-direction: column; + justify-content: space-between; +} +.tox .tox-rgb-form div { + align-items: center; + display: flex; + justify-content: space-between; + margin-bottom: 5px; + width: inherit; +} +.tox .tox-rgb-form input { + width: 6em; +} +.tox .tox-rgb-form input.tox-invalid { + border: 1px solid red !important; +} +.tox .tox-rgb-form .tox-rgba-preview { + border: 1px solid #000; + flex-grow: 2; + margin-bottom: 0; +} +.tox:not([dir='rtl']) .tox-sv-palette { + margin-right: 15px; +} +.tox:not([dir='rtl']) .tox-hue-slider { + margin-right: 15px; +} +.tox:not([dir='rtl']) .tox-hue-slider-thumb { + margin-left: -1px; +} +.tox:not([dir='rtl']) .tox-rgb-form label { + margin-right: 0.5em; +} +.tox[dir='rtl'] .tox-sv-palette { + margin-left: 15px; +} +.tox[dir='rtl'] .tox-hue-slider { + margin-left: 15px; +} +.tox[dir='rtl'] .tox-hue-slider-thumb { + margin-right: -1px; +} +.tox[dir='rtl'] .tox-rgb-form label { + margin-left: 0.5em; +} +.tox .tox-toolbar .tox-swatches, +.tox .tox-toolbar__overflow .tox-swatches, +.tox .tox-toolbar__primary .tox-swatches { + margin: 5px 0 6px 11px; +} +.tox .tox-collection--list .tox-collection__group .tox-swatches-menu { + border: 0; + margin: -4px -4px; +} +.tox .tox-swatches__row { + display: flex; +} +.tox .tox-swatch { + height: 30px; + transition: transform 0.15s, box-shadow 0.15s; + width: 30px; +} +.tox .tox-swatch:focus, +.tox .tox-swatch:hover { + box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; + transform: scale(0.8); +} +.tox .tox-swatch--remove { + align-items: center; + display: flex; + justify-content: center; +} +.tox .tox-swatch--remove svg path { + stroke: #e74c3c; +} +.tox .tox-swatches__picker-btn { + align-items: center; + background-color: transparent; + border: 0; + cursor: pointer; + display: flex; + height: 30px; + justify-content: center; + outline: 0; + padding: 0; + width: 30px; +} +.tox .tox-swatches__picker-btn svg { + fill: #fff; + height: 24px; + width: 24px; +} +.tox .tox-swatches__picker-btn:hover { + background: #3389ec; +} +.tox:not([dir='rtl']) .tox-swatches__picker-btn { + margin-left: auto; +} +.tox[dir='rtl'] .tox-swatches__picker-btn { + margin-right: auto; +} +.tox .tox-comment-thread { + background: #2b3b4e; + position: relative; +} +.tox .tox-comment-thread > :not(:first-child) { + margin-top: 8px; +} +.tox .tox-comment { + background: #2b3b4e; + border: 1px solid #161f29; + border-radius: 6px; + box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); + padding: 8px 8px 16px 8px; + position: relative; +} +.tox .tox-comment__header { + align-items: center; + color: #fff; + display: flex; + justify-content: space-between; +} +.tox .tox-comment__date { + color: rgba(255, 255, 255, 0.5); + font-size: 12px; +} +.tox .tox-comment__body { + color: #fff; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + margin-top: 8px; + position: relative; + text-transform: initial; +} +.tox .tox-comment__body textarea { + resize: none; + white-space: normal; + width: 100%; +} +.tox .tox-comment__expander { + padding-top: 8px; +} +.tox .tox-comment__expander p { + color: rgba(255, 255, 255, 0.5); + font-size: 14px; + font-style: normal; +} +.tox .tox-comment__body p { + margin: 0; +} +.tox .tox-comment__buttonspacing { + padding-top: 16px; + text-align: center; +} +.tox .tox-comment-thread__overlay::after { + background: #2b3b4e; + bottom: 0; + content: ''; + display: flex; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + top: 0; + z-index: 5; +} +.tox .tox-comment__reply { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 8px; +} +.tox .tox-comment__reply > :first-child { + margin-bottom: 8px; + width: 100%; +} +.tox .tox-comment__edit { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 16px; +} +.tox .tox-comment__gradient::after { + background: linear-gradient(rgba(43, 59, 78, 0), #2b3b4e); + bottom: 0; + content: ''; + display: block; + height: 5em; + margin-top: -40px; + position: absolute; + width: 100%; +} +.tox .tox-comment__overlay { + background: #2b3b4e; + bottom: 0; + display: flex; + flex-direction: column; + flex-grow: 1; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + text-align: center; + top: 0; + z-index: 5; +} +.tox .tox-comment__loading-text { + align-items: center; + color: #fff; + display: flex; + flex-direction: column; + position: relative; +} +.tox .tox-comment__loading-text > div { + padding-bottom: 16px; +} +.tox .tox-comment__overlaytext { + bottom: 0; + flex-direction: column; + font-size: 14px; + left: 0; + padding: 1em; + position: absolute; + right: 0; + top: 0; + z-index: 10; +} +.tox .tox-comment__overlaytext p { + background-color: #2b3b4e; + box-shadow: 0 0 8px 8px #2b3b4e; + color: #fff; + text-align: center; +} +.tox .tox-comment__overlaytext div:nth-of-type(2) { + font-size: 0.8em; +} +.tox .tox-comment__busy-spinner { + align-items: center; + background-color: #2b3b4e; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 20; +} +.tox .tox-comment__scroll { + display: flex; + flex-direction: column; + flex-shrink: 1; + overflow: auto; +} +.tox .tox-conversations { + margin: 8px; +} +.tox:not([dir='rtl']) .tox-comment__edit { + margin-left: 8px; +} +.tox:not([dir='rtl']) .tox-comment__buttonspacing > :last-child, +.tox:not([dir='rtl']) .tox-comment__edit > :last-child, +.tox:not([dir='rtl']) .tox-comment__reply > :last-child { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-comment__edit { + margin-right: 8px; +} +.tox[dir='rtl'] .tox-comment__buttonspacing > :last-child, +.tox[dir='rtl'] .tox-comment__edit > :last-child, +.tox[dir='rtl'] .tox-comment__reply > :last-child { + margin-right: 8px; +} +.tox .tox-user { + align-items: center; + display: flex; +} +.tox .tox-user__avatar svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-user__name { + color: rgba(255, 255, 255, 0.5); + font-size: 12px; + font-style: normal; + font-weight: 700; + text-transform: uppercase; +} +.tox:not([dir='rtl']) .tox-user__avatar svg { + margin-right: 8px; +} +.tox:not([dir='rtl']) .tox-user__avatar + .tox-user__name { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-user__avatar svg { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-user__avatar + .tox-user__name { + margin-right: 8px; +} +.tox .tox-dialog-wrap { + align-items: center; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 1100; +} +.tox .tox-dialog-wrap__backdrop { + background-color: rgba(34, 47, 62, 0.75); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} +.tox .tox-dialog-wrap__backdrop--opaque { + background-color: #222f3e; +} +.tox .tox-dialog { + background-color: #2b3b4e; + border-color: #161f29; + border-radius: 10px; + border-style: solid; + border-width: 0; + box-shadow: 0 16px 16px -10px rgba(34, 47, 62, 0.15), 0 0 40px 1px rgba(34, 47, 62, 0.15); + display: flex; + flex-direction: column; + max-height: 100%; + max-width: 480px; + overflow: hidden; + position: relative; + width: 95vw; + z-index: 2; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog { + align-self: flex-start; + margin: 8px auto; + width: calc(100vw - 16px); + } +} +.tox .tox-dialog-inline { + z-index: 1100; +} +.tox .tox-dialog__header { + align-items: center; + background-color: #2b3b4e; + border-bottom: none; + color: #fff; + display: flex; + font-size: 16px; + justify-content: space-between; + padding: 8px 16px 0 16px; + position: relative; +} +.tox .tox-dialog__header .tox-button { + z-index: 1; +} +.tox .tox-dialog__draghandle { + cursor: grab; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tox .tox-dialog__draghandle:active { + cursor: grabbing; +} +.tox .tox-dialog__dismiss { + margin-left: auto; +} +.tox .tox-dialog__title { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 20px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + margin: 0; + text-transform: none; +} +.tox .tox-dialog__body { + color: #fff; + display: flex; + flex: 1; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + min-width: 0; + text-align: left; + text-transform: none; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body { + flex-direction: column; + } +} +.tox .tox-dialog__body-nav { + align-items: flex-start; + display: flex; + flex-direction: column; + padding: 16px 16px; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { + flex-direction: row; + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding-bottom: 0; + } +} +.tox .tox-dialog__body-nav-item { + border-bottom: 2px solid transparent; + color: rgba(255, 255, 255, 0.5); + display: inline-block; + font-size: 14px; + line-height: 1.3; + margin-bottom: 8px; + text-decoration: none; + white-space: nowrap; +} +.tox .tox-dialog__body-nav-item:focus { + background-color: rgba(0, 108, 231, 0.1); +} +.tox .tox-dialog__body-nav-item--active { + border-bottom: 2px solid #006ce7; + color: #006ce7; +} +.tox .tox-dialog__body-content { + box-sizing: border-box; + display: flex; + flex: 1; + flex-direction: column; + max-height: 650px; + overflow: auto; + -webkit-overflow-scrolling: touch; + padding: 16px 16px; +} +.tox .tox-dialog__body-content > * { + margin-bottom: 0; + margin-top: 16px; +} +.tox .tox-dialog__body-content > :first-child { + margin-top: 0; +} +.tox .tox-dialog__body-content > :last-child { + margin-bottom: 0; +} +.tox .tox-dialog__body-content > :only-child { + margin-bottom: 0; + margin-top: 0; +} +.tox .tox-dialog__body-content a { + color: #006ce7; + cursor: pointer; + text-decoration: none; +} +.tox .tox-dialog__body-content a:focus, +.tox .tox-dialog__body-content a:hover { + color: #0054b4; + text-decoration: none; +} +.tox .tox-dialog__body-content a:active { + color: #0054b4; + text-decoration: none; +} +.tox .tox-dialog__body-content svg { + fill: #fff; +} +.tox .tox-dialog__body-content ul { + display: block; + list-style-type: disc; + margin-bottom: 16px; + margin-inline-end: 0; + margin-inline-start: 0; + padding-inline-start: 2.5rem; +} +.tox .tox-dialog__body-content .tox-form__group h1 { + color: #fff; + font-size: 20px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} +.tox .tox-dialog__body-content .tox-form__group h2 { + color: #fff; + font-size: 16px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} +.tox .tox-dialog__body-content .tox-form__group p { + margin-bottom: 16px; +} +.tox .tox-dialog__body-content .tox-form__group h1:first-child, +.tox .tox-dialog__body-content .tox-form__group h2:first-child, +.tox .tox-dialog__body-content .tox-form__group p:first-child { + margin-top: 0; +} +.tox .tox-dialog__body-content .tox-form__group h1:last-child, +.tox .tox-dialog__body-content .tox-form__group h2:last-child, +.tox .tox-dialog__body-content .tox-form__group p:last-child { + margin-bottom: 0; +} +.tox .tox-dialog__body-content .tox-form__group h1:only-child, +.tox .tox-dialog__body-content .tox-form__group h2:only-child, +.tox .tox-dialog__body-content .tox-form__group p:only-child { + margin-bottom: 0; + margin-top: 0; +} +.tox .tox-dialog--width-lg { + height: 650px; + max-width: 1200px; +} +.tox .tox-dialog--width-md { + max-width: 800px; +} +.tox .tox-dialog--width-md .tox-dialog__body-content { + overflow: auto; +} +.tox .tox-dialog__body-content--centered { + text-align: center; +} +.tox .tox-dialog__footer { + align-items: center; + background-color: #2b3b4e; + border-top: none; + display: flex; + justify-content: space-between; + padding: 8px 16px; +} +.tox .tox-dialog__footer-end, +.tox .tox-dialog__footer-start { + display: flex; +} +.tox .tox-dialog__busy-spinner { + align-items: center; + background-color: rgba(34, 47, 62, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 3; +} +.tox .tox-dialog__table { + border-collapse: collapse; + width: 100%; +} +.tox .tox-dialog__table thead th { + font-weight: 700; + padding-bottom: 8px; +} +.tox .tox-dialog__table tbody tr { + border-bottom: 1px solid #161f29; +} +.tox .tox-dialog__table tbody tr:last-child { + border-bottom: none; +} +.tox .tox-dialog__table td { + padding-bottom: 8px; + padding-top: 8px; +} +.tox .tox-dialog__popups { + position: absolute; + width: 100%; + z-index: 1100; +} +.tox .tox-dialog__body-iframe { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-dialog__body-iframe .tox-navobj { + display: flex; + flex: 1; +} +.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} +.tox .tox-dialog-dock-fadeout { + opacity: 0; + visibility: hidden; +} +.tox .tox-dialog-dock-fadein { + opacity: 1; + visibility: visible; +} +.tox .tox-dialog-dock-transition { + transition: visibility 0s linear 0.3s, opacity 0.3s ease; +} +.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { + transition-delay: 0s; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav { + margin-right: 0; + } +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav-item:not(:first-child) { + margin-left: 8px; + } +} +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-end > *, +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-start > * { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-dialog__body { + text-align: right; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav { + margin-left: 0; + } +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav-item:not(:first-child) { + margin-right: 8px; + } +} +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-end > *, +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-start > * { + margin-right: 8px; +} +body.tox-dialog__disable-scroll { + overflow: hidden; +} +.tox .tox-dropzone-container { + display: flex; + flex: 1; +} +.tox .tox-dropzone { + align-items: center; + background: #fff; + border: 2px dashed #161f29; + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-grow: 1; + justify-content: center; + min-height: 100px; + padding: 10px; +} +.tox .tox-dropzone p { + color: rgba(255, 255, 255, 0.5); + margin: 0 0 16px 0; +} +.tox .tox-edit-area { + display: flex; + flex: 1; + overflow: hidden; + position: relative; +} +.tox .tox-edit-area__iframe { + background-color: #fff; + border: 0; + box-sizing: border-box; + flex: 1; + height: 100%; + position: absolute; + width: 100%; +} +.tox.tox-inline-edit-area { + border: 1px dotted #161f29; +} +.tox .tox-editor-container { + display: flex; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} +.tox .tox-editor-header { + z-index: 1; +} +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: #222f3e; + border-bottom: 1px solid rgba(255, 255, 255, 0.15); + box-shadow: none; + padding: 4px 0; + transition: box-shadow 0.5s; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: 1px solid rgba(255, 255, 255, 0.15); + box-shadow: none; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: #222f3e; + box-shadow: none; + padding: 4px 0; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: none; +} +.tox-editor-dock-fadeout { + opacity: 0; + visibility: hidden; +} +.tox-editor-dock-fadein { + opacity: 1; + visibility: visible; +} +.tox-editor-dock-transition { + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} +.tox-editor-dock-transition.tox-editor-dock-fadein { + transition-delay: 0s; +} +.tox .tox-control-wrap { + flex: 1; + position: relative; +} +.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, +.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, +.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { + display: none; +} +.tox .tox-control-wrap svg { + display: block; +} +.tox .tox-control-wrap__status-icon-wrap { + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-control-wrap__status-icon-invalid svg { + fill: #c00; +} +.tox .tox-control-wrap__status-icon-unknown svg { + fill: orange; +} +.tox .tox-control-wrap__status-icon-valid svg { + fill: green; +} +.tox:not([dir='rtl']) .tox-control-wrap--status-invalid .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-unknown .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-valid .tox-textfield { + padding-right: 32px; +} +.tox:not([dir='rtl']) .tox-control-wrap__status-icon-wrap { + right: 4px; +} +.tox[dir='rtl'] .tox-control-wrap--status-invalid .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-unknown .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-valid .tox-textfield { + padding-left: 32px; +} +.tox[dir='rtl'] .tox-control-wrap__status-icon-wrap { + left: 4px; +} +.tox .tox-autocompleter { + max-width: 25em; +} +.tox .tox-autocompleter .tox-menu { + border-color: #161f29; + box-shadow: none; + max-width: 25em; +} +.tox .tox-autocompleter .tox-autocompleter-highlight { + font-weight: 700; +} +.tox .tox-color-input { + display: flex; + position: relative; + z-index: 1; +} +.tox .tox-color-input .tox-textfield { + z-index: -1; +} +.tox .tox-color-input span { + border-color: rgba(34, 47, 62, 0.2); + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + height: 24px; + position: absolute; + top: 6px; + width: 24px; +} +.tox .tox-color-input span:focus:not([aria-disabled='true']), +.tox .tox-color-input span:hover:not([aria-disabled='true']) { + border-color: #006ce7; + cursor: pointer; +} +.tox .tox-color-input span::before { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), + linear-gradient(-45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%), + linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%); + background-position: 0 0, 0 6px, 6px -6px, -6px 0; + background-size: 12px 12px; + border: 1px solid #2b3b4e; + border-radius: 6px; + box-sizing: border-box; + content: ''; + height: 24px; + left: -1px; + position: absolute; + top: -1px; + width: 24px; + z-index: -1; +} +.tox .tox-color-input span[aria-disabled='true'] { + cursor: not-allowed; +} +.tox:not([dir='rtl']) .tox-color-input .tox-textfield { + padding-left: 36px; +} +.tox:not([dir='rtl']) .tox-color-input span { + left: 6px; +} +.tox[dir='rtl'] .tox-color-input .tox-textfield { + padding-right: 36px; +} +.tox[dir='rtl'] .tox-color-input span { + right: 6px; +} +.tox .tox-label, +.tox .tox-toolbar-label { + color: rgba(255, 255, 255, 0.5); + display: block; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + padding: 0 8px 0 0; + text-transform: none; + white-space: nowrap; +} +.tox .tox-toolbar-label { + padding: 0 8px; +} +.tox[dir='rtl'] .tox-label { + padding: 0 0 0 8px; +} +.tox .tox-form { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-form__group { + box-sizing: border-box; + margin-bottom: 4px; +} +.tox .tox-form-group--maximize { + flex: 1; +} +.tox .tox-form__group--error { + color: #c00; +} +.tox .tox-form__group--collection { + display: flex; +} +.tox .tox-form__grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} +.tox .tox-form__grid--2col > .tox-form__group { + width: calc(50% - (8px / 2)); +} +.tox .tox-form__grid--3col > .tox-form__group { + width: calc(100% / 3 - (8px / 2)); +} +.tox .tox-form__grid--4col > .tox-form__group { + width: calc(25% - (8px / 2)); +} +.tox .tox-form__controls-h-stack { + align-items: center; + display: flex; +} +.tox .tox-form__group--inline { + align-items: center; + display: flex; +} +.tox .tox-form__group--stretched { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-form__group--stretched .tox-textarea { + flex: 1; +} +.tox .tox-form__group--stretched .tox-navobj { + display: flex; + flex: 1; +} +.tox .tox-form__group--stretched .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} +.tox:not([dir='rtl']) .tox-form__controls-h-stack > :not(:first-child) { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-form__controls-h-stack > :not(:first-child) { + margin-right: 4px; +} +.tox .tox-lock.tox-locked .tox-lock-icon__unlock, +.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { + display: none; +} +.tox .tox-listboxfield .tox-listbox--select, +.tox .tox-textarea, +.tox .tox-textfield, +.tox .tox-toolbar-textfield { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #2b3b4e; + border-color: #161f29; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: 0; + padding: 5px 5.5px; + resize: none; + width: 100%; +} +.tox .tox-textarea[disabled], +.tox .tox-textfield[disabled] { + background-color: #222f3e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} +.tox .tox-listboxfield .tox-listbox--select:focus, +.tox .tox-textarea:focus, +.tox .tox-textfield:focus { + background-color: #2b3b4e; + border-color: #006ce7; + box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); + outline: 0; +} +.tox .tox-toolbar-textfield { + border-width: 0; + margin-bottom: 3px; + margin-top: 2px; + max-width: 250px; +} +.tox .tox-naked-btn { + background-color: transparent; + border: 0; + border-color: transparent; + box-shadow: unset; + color: #006ce7; + cursor: pointer; + display: block; + margin: 0; + padding: 0; +} +.tox .tox-naked-btn svg { + display: block; + fill: #fff; +} +.tox:not([dir='rtl']) .tox-toolbar-textfield + * { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-toolbar-textfield + * { + margin-right: 4px; +} +.tox .tox-listboxfield { + cursor: pointer; + position: relative; +} +.tox .tox-listboxfield .tox-listbox--select[disabled] { + background-color: #19232e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} +.tox .tox-listbox__select-label { + cursor: default; + flex: 1; + margin: 0 4px; +} +.tox .tox-listbox__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} +.tox .tox-listbox__select-chevron svg { + fill: #fff; +} +.tox .tox-listboxfield .tox-listbox--select { + align-items: center; + display: flex; +} +.tox:not([dir='rtl']) .tox-listboxfield svg { + right: 8px; +} +.tox[dir='rtl'] .tox-listboxfield svg { + left: 8px; +} +.tox .tox-selectfield { + cursor: pointer; + position: relative; +} +.tox .tox-selectfield select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #2b3b4e; + border-color: #161f29; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: 0; + padding: 5px 5.5px; + resize: none; + width: 100%; +} +.tox .tox-selectfield select[disabled] { + background-color: #19232e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} +.tox .tox-selectfield select::-ms-expand { + display: none; +} +.tox .tox-selectfield select:focus { + background-color: #2b3b4e; + border-color: #006ce7; + box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); + outline: 0; +} +.tox .tox-selectfield svg { + pointer-events: none; + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox:not([dir='rtl']) .tox-selectfield select[size='0'], +.tox:not([dir='rtl']) .tox-selectfield select[size='1'] { + padding-right: 24px; +} +.tox:not([dir='rtl']) .tox-selectfield svg { + right: 8px; +} +.tox[dir='rtl'] .tox-selectfield select[size='0'], +.tox[dir='rtl'] .tox-selectfield select[size='1'] { + padding-left: 24px; +} +.tox[dir='rtl'] .tox-selectfield svg { + left: 8px; +} +.tox .tox-textarea { + -webkit-appearance: textarea; + -moz-appearance: textarea; + appearance: textarea; + white-space: pre-wrap; +} +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} +.tox-shadowhost.tox-fullscreen, +.tox.tox-tinymce.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} +.tox .tox-help__more-link { + list-style: none; + margin-top: 1em; +} +.tox .tox-imagepreview { + background-color: #666; + height: 380px; + overflow: hidden; + position: relative; + width: 100%; +} +.tox .tox-imagepreview.tox-imagepreview__loaded { + overflow: auto; +} +.tox .tox-imagepreview__container { + display: flex; + left: 100vw; + position: absolute; + top: 100vw; +} +.tox .tox-imagepreview__image { + background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); +} +.tox .tox-image-tools .tox-spacer { + flex: 1; +} +.tox .tox-image-tools .tox-bar { + align-items: center; + display: flex; + height: 60px; + justify-content: center; +} +.tox .tox-image-tools .tox-imagepreview, +.tox .tox-image-tools .tox-imagepreview + .tox-bar { + margin-top: 8px; +} +.tox .tox-image-tools .tox-croprect-block { + background: #000; + opacity: 0.5; + position: absolute; + zoom: 1; +} +.tox .tox-image-tools .tox-croprect-handle { + border: 2px solid #fff; + height: 20px; + left: 0; + position: absolute; + top: 0; + width: 20px; +} +.tox .tox-image-tools .tox-croprect-handle-move { + border: 0; + cursor: move; + position: absolute; +} +.tox .tox-image-tools .tox-croprect-handle-nw { + border-width: 2px 0 0 2px; + cursor: nw-resize; + left: 100px; + margin: -2px 0 0 -2px; + top: 100px; +} +.tox .tox-image-tools .tox-croprect-handle-ne { + border-width: 2px 2px 0 0; + cursor: ne-resize; + left: 200px; + margin: -2px 0 0 -20px; + top: 100px; +} +.tox .tox-image-tools .tox-croprect-handle-sw { + border-width: 0 0 2px 2px; + cursor: sw-resize; + left: 100px; + margin: -20px 2px 0 -2px; + top: 200px; +} +.tox .tox-image-tools .tox-croprect-handle-se { + border-width: 0 2px 2px 0; + cursor: se-resize; + left: 200px; + margin: -20px 0 0 -20px; + top: 200px; +} +.tox .tox-insert-table-picker { + display: flex; + flex-wrap: wrap; + width: 170px; +} +.tox .tox-insert-table-picker > div { + border-color: rgba(255, 255, 255, 0.15); + border-style: solid; + border-width: 0 1px 1px 0; + box-sizing: border-box; + height: 17px; + width: 17px; +} +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: -4px -4px; +} +.tox .tox-insert-table-picker .tox-insert-table-picker__selected { + background-color: rgba(0, 108, 231, 0.5); + border-color: rgba(0, 108, 231, 0.5); +} +.tox .tox-insert-table-picker__label { + color: #fff; + display: block; + font-size: 14px; + padding: 4px; + text-align: center; + width: 100%; +} +.tox:not([dir='rtl']) .tox-insert-table-picker > div:nth-child(10n) { + border-right: 0; +} +.tox[dir='rtl'] .tox-insert-table-picker > div:nth-child(10n + 1) { + border-right: 0; +} +.tox .tox-menu { + background-color: #2b3b4e; + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 6px; + box-shadow: none; + display: inline-block; + overflow: hidden; + vertical-align: top; + z-index: 1150; +} +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0 4px; +} +.tox .tox-menu.tox-collection.tox-collection--toolbar { + padding: 8px; +} +.tox .tox-menu.tox-collection.tox-collection--grid { + padding: 8px; +} +.tox .tox-menu__label blockquote, +.tox .tox-menu__label code, +.tox .tox-menu__label h1, +.tox .tox-menu__label h2, +.tox .tox-menu__label h3, +.tox .tox-menu__label h4, +.tox .tox-menu__label h5, +.tox .tox-menu__label h6, +.tox .tox-menu__label p { + margin: 0; +} +.tox .tox-menubar { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='transparent'/%3E%3C/svg%3E") + left 0 top 0 #222f3e; + background-color: #222f3e; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 11px 0 12px; +} +.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { + border-top: 1px solid transparent; +} +.tox .tox-mbtn { + align-items: center; + background: 0 0; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: 400; + height: 28px; + justify-content: center; + margin: 5px 1px 6px 0; + outline: 0; + overflow: hidden; + padding: 0 4px; + text-transform: none; + width: auto; +} +.tox .tox-mbtn[disabled] { + background-color: transparent; + border: 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-mbtn:focus:not(:disabled) { + background: #3389ec; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-mbtn--active { + background: #599fef; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { + background: #3389ec; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-mbtn__select-label { + cursor: default; + font-weight: 400; + margin: 0 4px; +} +.tox .tox-mbtn[disabled] .tox-mbtn__select-label { + cursor: not-allowed; +} +.tox .tox-mbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; + display: none; +} +.tox .tox-notification { + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + display: grid; + font-size: 14px; + font-weight: 400; + grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + margin-top: 4px; + opacity: 0; + padding: 4px; + transition: transform 0.1s ease-in, opacity 150ms ease-in; +} +.tox .tox-notification p { + font-size: 14px; + font-weight: 400; +} +.tox .tox-notification a { + cursor: pointer; + text-decoration: underline; +} +.tox .tox-notification--in { + opacity: 1; +} +.tox .tox-notification--success { + background-color: #334840; + border-color: #3c5440; + color: #fff; +} +.tox .tox-notification--success p { + color: #fff; +} +.tox .tox-notification--success a { + color: #b5d199; +} +.tox .tox-notification--success svg { + fill: #fff; +} +.tox .tox-notification--error { + background-color: #442632; + border-color: #55212b; + color: #fff; +} +.tox .tox-notification--error p { + color: #fff; +} +.tox .tox-notification--error a { + color: #e68080; +} +.tox .tox-notification--error svg { + fill: #fff; +} +.tox .tox-notification--warn, +.tox .tox-notification--warning { + background-color: #222f3e; + border-color: rgba(255, 255, 255, 0.15); + color: #fff0b3; +} +.tox .tox-notification--warn p, +.tox .tox-notification--warning p { + color: #fff0b3; +} +.tox .tox-notification--warn a, +.tox .tox-notification--warning a { + color: #fc0; +} +.tox .tox-notification--warn svg, +.tox .tox-notification--warning svg { + fill: #fff0b3; +} +.tox .tox-notification--info { + background-color: #254161; + border-color: #264972; + color: #fff; +} +.tox .tox-notification--info p { + color: #fff; +} +.tox .tox-notification--info a { + color: #83b7f3; +} +.tox .tox-notification--info svg { + fill: #fff; +} +.tox .tox-notification__body { + align-self: center; + color: #fff; + font-size: 14px; + grid-column-end: 3; + grid-column-start: 2; + grid-row-end: 2; + grid-row-start: 1; + text-align: center; + white-space: normal; + word-break: break-all; + word-break: break-word; +} +.tox .tox-notification__body > * { + margin: 0; +} +.tox .tox-notification__body > * + * { + margin-top: 1rem; +} +.tox .tox-notification__icon { + align-self: center; + grid-column-end: 2; + grid-column-start: 1; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} +.tox .tox-notification__icon svg { + display: block; +} +.tox .tox-notification__dismiss { + align-self: start; + grid-column-end: 4; + grid-column-start: 3; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} +.tox .tox-notification .tox-progress-bar { + grid-column-end: 4; + grid-column-start: 1; + grid-row-end: 3; + grid-row-start: 2; + justify-self: center; +} +.tox .tox-pop { + display: inline-block; + position: relative; +} +.tox .tox-pop--resizing { + transition: width 0.1s ease; +} +.tox .tox-pop--resizing .tox-toolbar, +.tox .tox-pop--resizing .tox-toolbar__group { + flex-wrap: nowrap; +} +.tox .tox-pop--transition { + transition: 0.15s ease; + transition-property: left, right, top, bottom; +} +.tox .tox-pop--transition::after, +.tox .tox-pop--transition::before { + transition: all 0.15s, visibility 0s, opacity 75ms ease 75ms; +} +.tox .tox-pop__dialog { + background-color: #222f3e; + border: 1px solid #161f29; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + min-width: 0; + overflow: hidden; +} +.tox .tox-pop__dialog > :not(.tox-toolbar) { + margin: 4px 4px 4px 8px; +} +.tox .tox-pop__dialog .tox-toolbar { + background-color: transparent; + margin-bottom: -1px; +} +.tox .tox-pop::after, +.tox .tox-pop::before { + border-style: solid; + content: ''; + display: block; + height: 0; + opacity: 1; + position: absolute; + width: 0; +} +.tox .tox-pop.tox-pop--inset::after, +.tox .tox-pop.tox-pop--inset::before { + opacity: 0; + transition: all 0s 0.15s, visibility 0s, opacity 75ms ease; +} +.tox .tox-pop.tox-pop--bottom::after, +.tox .tox-pop.tox-pop--bottom::before { + left: 50%; + top: 100%; +} +.tox .tox-pop.tox-pop--bottom::after { + border-color: #222f3e transparent transparent transparent; + border-width: 8px; + margin-left: -8px; + margin-top: -1px; +} +.tox .tox-pop.tox-pop--bottom::before { + border-color: #161f29 transparent transparent transparent; + border-width: 9px; + margin-left: -9px; +} +.tox .tox-pop.tox-pop--top::after, +.tox .tox-pop.tox-pop--top::before { + left: 50%; + top: 0; + transform: translateY(-100%); +} +.tox .tox-pop.tox-pop--top::after { + border-color: transparent transparent #222f3e transparent; + border-width: 8px; + margin-left: -8px; + margin-top: 1px; +} +.tox .tox-pop.tox-pop--top::before { + border-color: transparent transparent #161f29 transparent; + border-width: 9px; + margin-left: -9px; +} +.tox .tox-pop.tox-pop--left::after, +.tox .tox-pop.tox-pop--left::before { + left: 0; + top: calc(50% - 1px); + transform: translateY(-50%); +} +.tox .tox-pop.tox-pop--left::after { + border-color: transparent #222f3e transparent transparent; + border-width: 8px; + margin-left: -15px; +} +.tox .tox-pop.tox-pop--left::before { + border-color: transparent #161f29 transparent transparent; + border-width: 10px; + margin-left: -19px; +} +.tox .tox-pop.tox-pop--right::after, +.tox .tox-pop.tox-pop--right::before { + left: 100%; + top: calc(50% + 1px); + transform: translateY(-50%); +} +.tox .tox-pop.tox-pop--right::after { + border-color: transparent transparent transparent #222f3e; + border-width: 8px; + margin-left: -1px; +} +.tox .tox-pop.tox-pop--right::before { + border-color: transparent transparent transparent #161f29; + border-width: 10px; + margin-left: -1px; +} +.tox .tox-pop.tox-pop--align-left::after, +.tox .tox-pop.tox-pop--align-left::before { + left: 20px; +} +.tox .tox-pop.tox-pop--align-right::after, +.tox .tox-pop.tox-pop--align-right::before { + left: calc(100% - 20px); +} +.tox .tox-sidebar-wrap { + display: flex; + flex-direction: row; + flex-grow: 1; + min-height: 0; +} +.tox .tox-sidebar { + background-color: #222f3e; + display: flex; + flex-direction: row; + justify-content: flex-end; +} +.tox .tox-sidebar__slider { + display: flex; + overflow: hidden; +} +.tox .tox-sidebar__pane-container { + display: flex; +} +.tox .tox-sidebar__pane { + display: flex; +} +.tox .tox-sidebar--sliding-closed { + opacity: 0; +} +.tox .tox-sidebar--sliding-open { + opacity: 1; +} +.tox .tox-sidebar--sliding-growing, +.tox .tox-sidebar--sliding-shrinking { + transition: width 0.5s ease, opacity 0.5s ease; +} +.tox .tox-selector { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + display: inline-block; + height: 10px; + position: absolute; + width: 10px; +} +.tox.tox-platform-touch .tox-selector { + height: 12px; + width: 12px; +} +.tox .tox-slider { + align-items: center; + display: flex; + flex: 1; + height: 24px; + justify-content: center; + position: relative; +} +.tox .tox-slider__rail { + background-color: transparent; + border: 1px solid #161f29; + border-radius: 6px; + height: 10px; + min-width: 120px; + width: 100%; +} +.tox .tox-slider__handle { + background-color: #006ce7; + border: 2px solid #0054b4; + border-radius: 6px; + box-shadow: none; + height: 24px; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: 14px; +} +.tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { + margin-inline-start: 8px; +} +.tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { + margin-inline-start: 32px; +} +.tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { + margin-inline-start: 32px; +} +.tox .tox-source-code { + overflow: auto; +} +.tox .tox-spinner { + display: flex; +} +.tox .tox-spinner > div { + animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; + background-color: rgba(255, 255, 255, 0.5); + border-radius: 100%; + height: 8px; + width: 8px; +} +.tox .tox-spinner > div:nth-child(1) { + animation-delay: -0.32s; +} +.tox .tox-spinner > div:nth-child(2) { + animation-delay: -0.16s; +} +@keyframes tam-bouncing-dots { + 0%, + 100%, + 80% { + transform: scale(0); + } + 40% { + transform: scale(1); + } +} +.tox:not([dir='rtl']) .tox-spinner > div:not(:first-child) { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-spinner > div:not(:first-child) { + margin-right: 4px; +} +.tox .tox-statusbar { + align-items: center; + background-color: #222f3e; + border-top: 1px solid rgba(255, 255, 255, 0.15); + color: rgba(255, 255, 255, 0.75); + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-weight: 400; + height: 25px; + overflow: hidden; + padding: 0 8px; + position: relative; + text-transform: none; +} +.tox .tox-statusbar__text-container { + display: flex; + flex: 1 1 auto; + justify-content: flex-end; + overflow: hidden; +} +.tox .tox-statusbar__path { + display: flex; + flex: 1 1 auto; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.tox .tox-statusbar__path > * { + display: inline; + white-space: nowrap; +} +.tox .tox-statusbar__wordcount { + flex: 0 0 auto; + margin-left: 1ch; +} +.tox .tox-statusbar a, +.tox .tox-statusbar__path-item, +.tox .tox-statusbar__wordcount { + color: rgba(255, 255, 255, 0.75); + text-decoration: none; +} +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']) { + color: #fff; + cursor: pointer; +} +.tox .tox-statusbar__branding svg { + fill: rgba(255, 255, 255, 0.8); + height: 1.14em; + vertical-align: -0.28em; + width: 3.6em; +} +.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled='true']) svg, +.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled='true']) svg { + fill: #fff; +} +.tox .tox-statusbar__resize-handle { + align-items: flex-end; + align-self: stretch; + cursor: nwse-resize; + display: flex; + flex: 0 0 auto; + justify-content: flex-end; + margin-left: auto; + margin-right: -8px; + padding-bottom: 3px; + padding-left: 1ch; + padding-right: 3px; +} +.tox .tox-statusbar__resize-handle svg { + display: block; + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-statusbar__resize-handle:focus svg { + background-color: #434e5b; + border-radius: 1px 1px 5px 1px; + box-shadow: 0 0 0 2px #434e5b; +} +.tox:not([dir='rtl']) .tox-statusbar__path > * { + margin-right: 4px; +} +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 2ch; +} +.tox[dir='rtl'] .tox-statusbar { + flex-direction: row-reverse; +} +.tox[dir='rtl'] .tox-statusbar__path > * { + margin-left: 4px; +} +.tox .tox-throbber { + z-index: 1299; +} +.tox .tox-throbber__busy-spinner { + align-items: center; + background-color: rgba(34, 47, 62, 0.6); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} +.tox .tox-tbtn { + align-items: center; + background: 0 0; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: 400; + height: 28px; + justify-content: center; + margin: 6px 1px 5px 0; + outline: 0; + overflow: hidden; + padding: 0; + text-transform: none; + width: 34px; +} +.tox .tox-tbtn svg { + display: block; + fill: #fff; +} +.tox .tox-tbtn.tox-tbtn-more { + padding-left: 5px; + padding-right: 5px; + width: inherit; +} +.tox .tox-tbtn:focus { + background: #3389ec; + border: 0; + box-shadow: none; +} +.tox .tox-tbtn:hover { + background: #3389ec; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-tbtn:hover svg { + fill: #fff; +} +.tox .tox-tbtn:active { + background: #599fef; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-tbtn:active svg { + fill: #fff; +} +.tox .tox-tbtn--disabled, +.tox .tox-tbtn--disabled:hover, +.tox .tox-tbtn:disabled, +.tox .tox-tbtn:disabled:hover { + background: 0 0; + border: 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-tbtn--disabled svg, +.tox .tox-tbtn--disabled:hover svg, +.tox .tox-tbtn:disabled svg, +.tox .tox-tbtn:disabled:hover svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-tbtn--enabled, +.tox .tox-tbtn--enabled:hover { + background: #599fef; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-tbtn--enabled:hover > *, +.tox .tox-tbtn--enabled > * { + transform: none; +} +.tox .tox-tbtn--enabled svg, +.tox .tox-tbtn--enabled:hover svg { + fill: #fff; +} +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { + color: #fff; +} +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { + fill: #fff; +} +.tox .tox-tbtn:active > * { + transform: none; +} +.tox .tox-tbtn--md { + height: 42px; + width: 51px; +} +.tox .tox-tbtn--lg { + flex-direction: column; + height: 56px; + width: 68px; +} +.tox .tox-tbtn--return { + align-self: stretch; + height: unset; + width: 16px; +} +.tox .tox-tbtn--labeled { + padding: 0 4px; + width: unset; +} +.tox .tox-tbtn__vlabel { + display: block; + font-size: 10px; + font-weight: 400; + letter-spacing: -0.025em; + margin-bottom: 4px; + white-space: nowrap; +} +.tox .tox-tbtn--select { + margin: 6px 1px 5px 0; + padding: 0 4px; + width: auto; +} +.tox .tox-tbtn__select-label { + cursor: default; + font-weight: 400; + margin: 0 4px; +} +.tox .tox-tbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} +.tox .tox-tbtn__select-chevron svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-tbtn--bespoke { + background: #2f4055; +} +.tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { + margin-inline-start: 4px; +} +.tox .tox-tbtn--bespoke .tox-tbtn__select-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 7em; +} +.tox .tox-split-button { + border: 0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + margin: 6px 1px 5px 0; + overflow: hidden; +} +.tox .tox-split-button:hover { + box-shadow: 0 0 0 1px #3389ec inset; +} +.tox .tox-split-button:focus { + background: #3389ec; + box-shadow: none; + color: #fff; +} +.tox .tox-split-button > * { + border-radius: 0; +} +.tox .tox-split-button__chevron { + width: 16px; +} +.tox .tox-split-button__chevron svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-split-button .tox-tbtn { + margin: 0; +} +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, +.tox .tox-split-button.tox-tbtn--disabled:focus, +.tox .tox-split-button.tox-tbtn--disabled:hover { + background: 0 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} +.tox.tox-platform-touch .tox-split-button .tox-tbtn--select { + padding: 0 0; +} +.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { + width: 30px; +} +.tox.tox-platform-touch .tox-split-button__chevron { + width: 20px; +} +.tox .tox-toolbar-overlord { + background-color: #222f3e; +} +.tox .tox-toolbar, +.tox .tox-toolbar__overflow, +.tox .tox-toolbar__primary { + background-color: #222f3e; + background-image: repeating-linear-gradient(rgba(255, 255, 255, 0.15) 0 1px, transparent 1px 39px); + background-position: center top 40px; + background-repeat: no-repeat; + background-size: calc(100% - 11px * 2) calc(100% - 41px); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 0; + transform: perspective(1px); +} +.tox .tox-toolbar-overlord > .tox-toolbar, +.tox .tox-toolbar-overlord > .tox-toolbar__overflow, +.tox .tox-toolbar-overlord > .tox-toolbar__primary { + background-position: center top 0; + background-size: calc(100% - 11px * 2) calc(100% - 0px); +} +.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { + height: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; + visibility: hidden; +} +.tox .tox-toolbar__overflow--growing { + transition: height 0.3s ease, opacity 0.2s linear 0.1s; +} +.tox .tox-toolbar__overflow--shrinking { + transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; +} +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: 1px solid transparent; + margin-top: 0; + padding-bottom: 1px; + padding-top: 1px; +} +.tox .tox-toolbar--scrolling { + flex-wrap: nowrap; + overflow-x: auto; +} +.tox .tox-pop .tox-toolbar { + border-width: 0; +} +.tox .tox-toolbar--no-divider { + background-image: none; +} +.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, +.tox .tox-toolbar-overlord .tox-toolbar__primary { + background-position: center top 39px; +} +.tox .tox-editor-header > .tox-toolbar--scrolling, +.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { + background-image: none; +} +.tox.tox-tinymce-aux .tox-toolbar__overflow { + background-color: #222f3e; + background-position: center top 43px; + background-size: calc(100% - 8px * 2) calc(100% - 51px); + border: none; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + padding: 4px 0; +} +.tox-pop .tox-pop__dialog .tox-toolbar { + background-position: center top 43px; + background-size: calc(100% - 11px * 2) calc(100% - 51px); + padding: 4px 0; +} +.tox .tox-toolbar__group { + align-items: center; + display: flex; + flex-wrap: wrap; + margin: 0 0; + padding: 0 11px 0 12px; +} +.tox .tox-toolbar__group--pull-right { + margin-left: auto; +} +.tox .tox-toolbar--scrolling .tox-toolbar__group { + flex-shrink: 0; + flex-wrap: nowrap; +} +.tox:not([dir='rtl']) .tox-toolbar__group:not(:last-of-type) { + border-right: 1px solid transparent; +} +.tox[dir='rtl'] .tox-toolbar__group:not(:last-of-type) { + border-left: 1px solid transparent; +} +.tox .tox-tooltip { + display: inline-block; + padding: 8px; + position: relative; +} +.tox .tox-tooltip__body { + background-color: #3d546f; + border-radius: 6px; + box-shadow: 0 2px 4px rgba(34, 47, 62, 0.3); + color: rgba(255, 255, 255, 0.75); + font-size: 14px; + font-style: normal; + font-weight: 400; + padding: 4px 8px; + text-transform: none; +} +.tox .tox-tooltip__arrow { + position: absolute; +} +.tox .tox-tooltip--down .tox-tooltip__arrow { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #3d546f; + bottom: 0; + left: 50%; + position: absolute; + transform: translateX(-50%); +} +.tox .tox-tooltip--up .tox-tooltip__arrow { + border-bottom: 8px solid #3d546f; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + left: 50%; + position: absolute; + top: 0; + transform: translateX(-50%); +} +.tox .tox-tooltip--right .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-left: 8px solid #3d546f; + border-top: 8px solid transparent; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-tooltip--left .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-right: 8px solid #3d546f; + border-top: 8px solid transparent; + left: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-well { + border: 1px solid #161f29; + border-radius: 6px; + padding: 8px; + width: 100%; +} +.tox .tox-well > :first-child { + margin-top: 0; +} +.tox .tox-well > :last-child { + margin-bottom: 0; +} +.tox .tox-well > :only-child { + margin: 0; +} +.tox .tox-custom-editor { + border: 1px solid #161f29; + border-radius: 6px; + display: flex; + flex: 1; + position: relative; +} +.tox .tox-dialog-loading::before { + background-color: rgba(0, 0, 0, 0.5); + content: ''; + height: 100%; + position: absolute; + width: 100%; + z-index: 1000; +} +.tox .tox-tab { + cursor: pointer; +} +.tox .tox-dialog__content-js { + display: flex; + flex: 1; +} +.tox .tox-dialog__body-content .tox-collection { + display: flex; + flex: 1; +} +.tox.tox-tinymce-aux .tox-toolbar__overflow { + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.15); +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.css b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.css new file mode 100644 index 00000000..d9ea82a3 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.css @@ -0,0 +1,35 @@ +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen, +.tox-shadowhost.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css new file mode 100644 index 00000000..c1141c55 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css @@ -0,0 +1,30 @@ +body.tox-dialog__disable-scroll { + overflow: hidden; +} +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} +.tox-shadowhost.tox-fullscreen, +.tox.tox-tinymce.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide/content.css b/src/frontend/admin/public/tinymce/skins/ui/oxide/content.css new file mode 100644 index 00000000..b81f358d --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide/content.css @@ -0,0 +1,869 @@ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; +} + +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} + +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*='language-'], +pre[class*='language-'] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} + +pre[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +code[class*='language-'] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*='language-']::selection, +pre[class*='language-'] ::selection, +code[class*='language-']::selection, +code[class*='language-'] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.token.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + /* This background color was intended by the author of this theme. */ + background: hsla(0, 0%, 100%, 0.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #dd4a68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable='false'] { + cursor: default; +} + +.mce-content-body *[contentEditable='true'] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} + +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #b4d7ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable='true']:focus, +.mce-content-body.mce-content-readonly *[contentEditable='true']:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*='border-width: 0px'], +.mce-item-table:not([border]), +.mce-item-table[border='0'], +table[style*='border-width: 0px'] td, +.mce-item-table:not([border]) td, +.mce-item-table[border='0'] td, +table[style*='border-width: 0px'] th, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border='0'] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) ul, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] ul, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} + +body { + font-family: sans-serif; +} + +table { + border-collapse: collapse; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide/content.inline.css b/src/frontend/admin/public/tinymce/skins/ui/oxide/content.inline.css new file mode 100644 index 00000000..e7acef31 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide/content.inline.css @@ -0,0 +1,861 @@ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; +} + +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} + +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*='language-'], +pre[class*='language-'] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} + +pre[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +code[class*='language-'] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*='language-']::selection, +pre[class*='language-'] ::selection, +code[class*='language-']::selection, +code[class*='language-'] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.token.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + /* This background color was intended by the author of this theme. */ + background: hsla(0, 0%, 100%, 0.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #dd4a68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable='false'] { + cursor: default; +} + +.mce-content-body *[contentEditable='true'] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} + +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #b4d7ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable='true']:focus, +.mce-content-body.mce-content-readonly *[contentEditable='true']:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*='border-width: 0px'], +.mce-item-table:not([border]), +.mce-item-table[border='0'], +table[style*='border-width: 0px'] td, +.mce-item-table:not([border]) td, +.mce-item-table[border='0'] td, +table[style*='border-width: 0px'] th, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border='0'] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) ul, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] ul, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide/content.inline.min.css b/src/frontend/admin/public/tinymce/skins/ui/oxide/content.inline.min.css new file mode 100644 index 00000000..882dfd5b --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide/content.inline.min.css @@ -0,0 +1,720 @@ +.mce-content-body .mce-item-anchor { + background: transparent + url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") + no-repeat center; +} +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} +code[class*='language-'], +pre[class*='language-'] { + color: #000; + background: 0 0; + text-shadow: 0 1px #fff; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} +code[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +pre[class*='language-']::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} +code[class*='language-'] ::selection, +code[class*='language-']::selection, +pre[class*='language-'] ::selection, +pre[class*='language-']::selection { + text-shadow: none; + background: #b3d4fc; +} +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} +.token.cdata, +.token.comment, +.token.doctype, +.token.prolog { + color: #708090; +} +.token.punctuation { + color: #999; +} +.token.namespace { + opacity: 0.7; +} +.token.boolean, +.token.constant, +.token.deleted, +.token.number, +.token.property, +.token.symbol, +.token.tag { + color: #905; +} +.token.attr-name, +.token.builtin, +.token.char, +.token.inserted, +.token.selector, +.token.string { + color: #690; +} +.language-css .token.string, +.style .token.string, +.token.entity, +.token.operator, +.token.url { + color: #9a6e3a; + background: hsla(0, 0%, 100%, 0.5); +} +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} +.token.class-name, +.token.function { + color: #dd4a68; +} +.token.important, +.token.regex, +.token.variable { + color: #e90; +} +.token.bold, +.token.important { + font-weight: 700; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} +.mce-content-body .mce-visual-caret { + background-color: #000; + background-color: currentColor; + position: absolute; +} +.mce-content-body .mce-visual-caret-hidden { + display: none; +} +.mce-content-body [data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} +.mce-content-body [contentEditable='false'] { + cursor: default; +} +.mce-content-body [contentEditable='true'] { + cursor: text; +} +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} +.mce-content-body figure.align-left { + float: left; +} +.mce-content-body figure.align-right { + float: right; +} +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} +.mce-object { + background: transparent + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') + no-repeat center; + border: 1px dashed #aaa; +} +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} +@media print { + .mce-pagebreak { + border: 0; + } +} +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} +.tiny-pageembed { + display: inline-block; + position: relative; +} +.tiny-pageembed--16by9, +.tiny-pageembed--1by1, +.tiny-pageembed--21by9, +.tiny-pageembed--4by3 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} +.tiny-pageembed--4by3 { + padding-top: 75%; +} +.tiny-pageembed--1by1 { + padding-top: 100%; +} +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--1by1 iframe, +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--4by3 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-content-body[data-mce-placeholder] { + position: relative; +} +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed #000; + position: absolute; + z-index: 10001; +} +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th { + border: 0; +} +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: #fff; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} +.tox-rtc-user-selection { + position: relative; +} +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: 700; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} +.tox-rtc-remote-image { + background: #eaeaea + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') + no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} +.mce-match-marker { + background: #aaa; + color: #fff; +} +.mce-match-marker-selected { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} +.mce-content-body audio[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body img[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body table[data-mce-selected], +.mce-content-body video[data-mce-selected] { + outline: 3px solid #b4d7ff; +} +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} +.mce-content-body.mce-content-readonly [contentEditable='true']:focus, +.mce-content-body.mce-content-readonly [contentEditable='true']:hover { + outline: 0; +} +.mce-content-body [data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} +.mce-content-body img::-moz-selection { + background: 0 0; +} +.mce-content-body img::selection { + background: 0 0; +} +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ephox-snooker-resizer-cols { + cursor: col-resize; +} +.ephox-snooker-resizer-rows { + cursor: row-resize; +} +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} +.mce-toc { + border: 1px solid gray; +} +.mce-toc h2 { + margin: 4px; +} +.mce-toc li { + list-style-type: none; +} +.mce-item-table:not([border]), +.mce-item-table:not([border]) caption, +.mce-item-table:not([border]) td, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'], +.mce-item-table[border='0'] caption, +.mce-item-table[border='0'] td, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'], +table[style*='border-width: 0px'] caption, +table[style*='border-width: 0px'] td, +table[style*='border-width: 0px'] th { + border: 1px dashed #bbb; +} +.mce-visualblocks address, +.mce-visualblocks article, +.mce-visualblocks aside, +.mce-visualblocks blockquote, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks dl, +.mce-visualblocks figcaption, +.mce-visualblocks figure, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks hgroup, +.mce-visualblocks ol, +.mce-visualblocks p, +.mce-visualblocks pre, +.mce-visualblocks section, +.mce-visualblocks ul { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) dl, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) ul { + margin-left: 3px; +} +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] dl, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] ul { + background-position-x: right; + margin-right: 3px; +} +.mce-nbsp, +.mce-shy { + background: #aaa; +} +.mce-shy::after { + content: '-'; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide/content.min.css b/src/frontend/admin/public/tinymce/skins/ui/oxide/content.min.css new file mode 100644 index 00000000..6e0034ba --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide/content.min.css @@ -0,0 +1,726 @@ +.mce-content-body .mce-item-anchor { + background: transparent + url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") + no-repeat center; +} +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} +code[class*='language-'], +pre[class*='language-'] { + color: #000; + background: 0 0; + text-shadow: 0 1px #fff; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} +code[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +pre[class*='language-']::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} +code[class*='language-'] ::selection, +code[class*='language-']::selection, +pre[class*='language-'] ::selection, +pre[class*='language-']::selection { + text-shadow: none; + background: #b3d4fc; +} +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} +.token.cdata, +.token.comment, +.token.doctype, +.token.prolog { + color: #708090; +} +.token.punctuation { + color: #999; +} +.token.namespace { + opacity: 0.7; +} +.token.boolean, +.token.constant, +.token.deleted, +.token.number, +.token.property, +.token.symbol, +.token.tag { + color: #905; +} +.token.attr-name, +.token.builtin, +.token.char, +.token.inserted, +.token.selector, +.token.string { + color: #690; +} +.language-css .token.string, +.style .token.string, +.token.entity, +.token.operator, +.token.url { + color: #9a6e3a; + background: hsla(0, 0%, 100%, 0.5); +} +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} +.token.class-name, +.token.function { + color: #dd4a68; +} +.token.important, +.token.regex, +.token.variable { + color: #e90; +} +.token.bold, +.token.important { + font-weight: 700; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} +.mce-content-body .mce-visual-caret { + background-color: #000; + background-color: currentColor; + position: absolute; +} +.mce-content-body .mce-visual-caret-hidden { + display: none; +} +.mce-content-body [data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} +.mce-content-body [contentEditable='false'] { + cursor: default; +} +.mce-content-body [contentEditable='true'] { + cursor: text; +} +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} +.mce-content-body figure.align-left { + float: left; +} +.mce-content-body figure.align-right { + float: right; +} +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} +.mce-object { + background: transparent + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') + no-repeat center; + border: 1px dashed #aaa; +} +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} +@media print { + .mce-pagebreak { + border: 0; + } +} +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} +.tiny-pageembed { + display: inline-block; + position: relative; +} +.tiny-pageembed--16by9, +.tiny-pageembed--1by1, +.tiny-pageembed--21by9, +.tiny-pageembed--4by3 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} +.tiny-pageembed--4by3 { + padding-top: 75%; +} +.tiny-pageembed--1by1 { + padding-top: 100%; +} +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--1by1 iframe, +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--4by3 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-content-body[data-mce-placeholder] { + position: relative; +} +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed #000; + position: absolute; + z-index: 10001; +} +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th { + border: 0; +} +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: #fff; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} +.tox-rtc-user-selection { + position: relative; +} +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: 700; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} +.tox-rtc-remote-image { + background: #eaeaea + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') + no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} +.mce-match-marker { + background: #aaa; + color: #fff; +} +.mce-match-marker-selected { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} +.mce-content-body audio[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body img[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body table[data-mce-selected], +.mce-content-body video[data-mce-selected] { + outline: 3px solid #b4d7ff; +} +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} +.mce-content-body.mce-content-readonly [contentEditable='true']:focus, +.mce-content-body.mce-content-readonly [contentEditable='true']:hover { + outline: 0; +} +.mce-content-body [data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} +.mce-content-body img::-moz-selection { + background: 0 0; +} +.mce-content-body img::selection { + background: 0 0; +} +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ephox-snooker-resizer-cols { + cursor: col-resize; +} +.ephox-snooker-resizer-rows { + cursor: row-resize; +} +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} +.mce-toc { + border: 1px solid gray; +} +.mce-toc h2 { + margin: 4px; +} +.mce-toc li { + list-style-type: none; +} +.mce-item-table:not([border]), +.mce-item-table:not([border]) caption, +.mce-item-table:not([border]) td, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'], +.mce-item-table[border='0'] caption, +.mce-item-table[border='0'] td, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'], +table[style*='border-width: 0px'] caption, +table[style*='border-width: 0px'] td, +table[style*='border-width: 0px'] th { + border: 1px dashed #bbb; +} +.mce-visualblocks address, +.mce-visualblocks article, +.mce-visualblocks aside, +.mce-visualblocks blockquote, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks dl, +.mce-visualblocks figcaption, +.mce-visualblocks figure, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks hgroup, +.mce-visualblocks ol, +.mce-visualblocks p, +.mce-visualblocks pre, +.mce-visualblocks section, +.mce-visualblocks ul { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) dl, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) ul { + margin-left: 3px; +} +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] dl, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] ul { + background-position-x: right; + margin-right: 3px; +} +.mce-nbsp, +.mce-shy { + background: #aaa; +} +.mce-shy::after { + content: '-'; +} +body { + font-family: sans-serif; +} +table { + border-collapse: collapse; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.css b/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.css new file mode 100644 index 00000000..b5a17d78 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.css @@ -0,0 +1,3660 @@ +.tox { + box-shadow: none; + box-sizing: content-box; + color: #222f3e; + cursor: auto; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-style: normal; + font-weight: normal; + line-height: normal; + -webkit-tap-highlight-color: transparent; + text-decoration: none; + text-shadow: none; + text-transform: none; + vertical-align: initial; + white-space: normal; +} + +.tox *:not(svg):not(rect) { + box-sizing: inherit; + color: inherit; + cursor: inherit; + direction: inherit; + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; + line-height: inherit; + -webkit-tap-highlight-color: inherit; + text-align: inherit; + text-decoration: inherit; + text-shadow: inherit; + text-transform: inherit; + vertical-align: inherit; + white-space: inherit; +} + +.tox *:not(svg):not(rect) { + /* stylelint-disable-line no-duplicate-selectors */ + background: transparent; + border: 0; + box-shadow: none; + float: none; + height: auto; + margin: 0; + max-width: none; + outline: 0; + padding: 0; + position: static; + width: auto; +} + +.tox:not([dir='rtl']) { + direction: ltr; + text-align: left; +} + +.tox[dir='rtl'] { + direction: rtl; + text-align: right; +} + +.tox-tinymce { + border: 2px solid #eeeeee; + border-radius: 10px; + box-shadow: none; + box-sizing: border-box; + display: flex; + flex-direction: column; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + overflow: hidden; + position: relative; + visibility: inherit !important; +} + +.tox.tox-tinymce-inline { + border: none; + box-shadow: none; + overflow: initial; +} + +.tox.tox-tinymce-inline .tox-editor-container { + overflow: initial; +} + +.tox.tox-tinymce-inline .tox-editor-header { + background-color: #fff; + border: 2px solid #eeeeee; + border-radius: 10px; + box-shadow: none; + overflow: hidden; +} + +.tox-tinymce-aux { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + z-index: 1300; +} + +.tox-tinymce *:focus, +.tox-tinymce-aux *:focus { + outline: none; +} + +button::-moz-focus-inner { + border: 0; +} + +.tox[dir='rtl'] .tox-icon--flip svg { + transform: rotateY(180deg); +} + +.tox .accessibility-issue__header { + align-items: center; + display: flex; + margin-bottom: 4px; +} + +.tox .accessibility-issue__description { + align-items: stretch; + border: 1px solid #eeeeee; + border-radius: 6px; + display: flex; + justify-content: space-between; +} + +.tox .accessibility-issue__description > div { + padding-bottom: 4px; +} + +.tox .accessibility-issue__description > div > div { + align-items: center; + display: flex; + margin-bottom: 4px; +} + +.tox .accessibility-issue__description > *:last-child:not(:only-child) { + border-color: #eeeeee; + border-style: solid; +} + +.tox .accessibility-issue__repair { + margin-top: 16px; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { + background-color: rgba(0, 108, 231, 0.1); + border-color: #006ce7; + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description > *:last-child { + border-color: #006ce7; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { + color: #006ce7; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { + fill: #006ce7; +} + +.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon { + color: #006ce7; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { + background-color: rgba(255, 165, 0, 0.1); + border-color: rgba(255, 165, 0, 0.5); + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description > *:last-child { + border-color: rgba(255, 165, 0, 0.5); +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { + color: #cc8500; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { + fill: #cc8500; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon { + color: #cc8500; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { + background-color: rgba(204, 0, 0, 0.1); + border-color: rgba(204, 0, 0, 0.4); + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description > *:last-child { + border-color: rgba(204, 0, 0, 0.4); +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { + color: #c00; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { + fill: #c00; +} + +.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon { + color: #c00; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { + background-color: rgba(120, 171, 70, 0.1); + border-color: rgba(120, 171, 70, 0.4); + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > *:last-child { + border-color: rgba(120, 171, 70, 0.4); +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { + color: #78ab46; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { + fill: #78ab46; +} + +.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon { + color: #78ab46; +} + +.tox .tox-dialog__body-content .accessibility-issue__header h1, +.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { + margin-top: 0; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-left: auto; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 4px 4px 8px; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-left-width: 1px; + padding-left: 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-right: auto; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 8px 4px 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-right-width: 1px; + padding-right: 4px; +} + +.tox .tox-anchorbar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-bar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-button { + background-color: #006ce7; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #006ce7; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + line-height: 24px; + margin: 0; + outline: none; + padding: 4px 16px; + text-align: center; + text-decoration: none; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-button[disabled] { + background-color: #006ce7; + background-image: none; + border-color: #006ce7; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-button:focus:not(:disabled) { + background-color: #0060ce; + background-image: none; + border-color: #0060ce; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:hover:not(:disabled) { + background-color: #0060ce; + background-image: none; + border-color: #0060ce; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:active:not(:disabled) { + background-color: #0054b4; + background-image: none; + border-color: #0054b4; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary { + background-color: #f0f0f0; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #f0f0f0; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + color: #222f3e; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + outline: none; + padding: 4px 16px; + text-decoration: none; + text-transform: none; +} + +.tox .tox-button--secondary[disabled] { + background-color: #f0f0f0; + background-image: none; + border-color: #f0f0f0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} + +.tox .tox-button--secondary:focus:not(:disabled) { + background-color: #e3e3e3; + background-image: none; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--secondary:hover:not(:disabled) { + background-color: #e3e3e3; + background-image: none; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--secondary:active:not(:disabled) { + background-color: #d6d6d6; + background-image: none; + border-color: #d6d6d6; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--icon, +.tox .tox-button.tox-button--icon, +.tox .tox-button.tox-button--secondary.tox-button--icon { + padding: 4px; +} + +.tox .tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { + display: block; + fill: currentColor; +} + +.tox .tox-button-link { + background: 0; + border: none; + box-sizing: border-box; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-weight: normal; + line-height: 1.3; + margin: 0; + padding: 0; + white-space: nowrap; +} + +.tox .tox-button-link--sm { + font-size: 14px; +} + +.tox .tox-button--naked { + background-color: transparent; + border-color: transparent; + box-shadow: unset; + color: #222f3e; +} + +.tox .tox-button--naked[disabled] { + background-color: rgba(34, 47, 62, 0.12); + border-color: transparent; + box-shadow: unset; + color: rgba(34, 47, 62, 0.5); +} + +.tox .tox-button--naked:hover:not(:disabled) { + background-color: rgba(34, 47, 62, 0.12); + border-color: transparent; + box-shadow: unset; + color: #222f3e; +} + +.tox .tox-button--naked:focus:not(:disabled) { + background-color: rgba(34, 47, 62, 0.12); + border-color: transparent; + box-shadow: unset; + color: #222f3e; +} + +.tox .tox-button--naked:active:not(:disabled) { + background-color: rgba(34, 47, 62, 0.18); + border-color: transparent; + box-shadow: unset; + color: #222f3e; +} + +.tox .tox-button--naked .tox-icon svg { + fill: currentColor; +} + +.tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { + color: #222f3e; +} + +.tox .tox-checkbox { + align-items: center; + border-radius: 6px; + cursor: pointer; + display: flex; + height: 36px; + min-width: 36px; +} + +.tox .tox-checkbox__input { + /* Hide from view but visible to screen readers */ + height: 1px; + overflow: hidden; + position: absolute; + top: auto; + width: 1px; +} + +.tox .tox-checkbox__icons { + align-items: center; + border-radius: 6px; + box-shadow: 0 0 0 2px transparent; + box-sizing: content-box; + display: flex; + height: 24px; + justify-content: center; + padding: calc(4px - 1px); + width: 24px; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: block; + fill: rgba(34, 47, 62, 0.3); +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: none; + fill: #006ce7; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: none; + fill: #006ce7; +} + +.tox .tox-checkbox--disabled { + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: block; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: block; +} + +.tox input.tox-checkbox__input:focus + .tox-checkbox__icons { + border-radius: 6px; + box-shadow: inset 0 0 0 1px #006ce7; + padding: calc(4px - 1px); +} + +.tox:not([dir='rtl']) .tox-checkbox__label { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-checkbox__input { + left: -10000px; +} + +.tox:not([dir='rtl']) .tox-bar .tox-checkbox { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-checkbox__label { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-checkbox__input { + right: -10000px; +} + +.tox[dir='rtl'] .tox-bar .tox-checkbox { + margin-right: 4px; +} + +.tox { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox .tox-collection--toolbar .tox-collection__group { + display: flex; + padding: 0; +} + +.tox .tox-collection--grid .tox-collection__group { + display: flex; + flex-wrap: wrap; + max-height: 208px; + overflow-x: hidden; + overflow-y: auto; + padding: 0; +} + +.tox .tox-collection--list .tox-collection__group { + border-bottom-width: 0; + border-color: #e3e3e3; + border-left-width: 0; + border-right-width: 0; + border-style: solid; + border-top-width: 1px; + padding: 4px 0; +} + +.tox .tox-collection--list .tox-collection__group:first-child { + border-top-width: 0; +} + +.tox .tox-collection__group-heading { + background-color: #fcfcfc; + color: rgba(34, 47, 62, 0.7); + cursor: default; + font-size: 12px; + font-style: normal; + font-weight: normal; + margin-bottom: 4px; + margin-top: -4px; + padding: 4px 8px; + text-transform: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.tox .tox-collection__item { + align-items: center; + border-radius: 3px; + color: #222f3e; + display: flex; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.tox .tox-collection--list .tox-collection__item { + padding: 4px 8px; +} + +.tox .tox-collection--toolbar .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--grid .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--list .tox-collection__item--enabled { + background-color: #fff; + color: #222f3e; +} + +.tox .tox-collection--list .tox-collection__item--active { + background-color: #cce2fa; +} + +.tox .tox-collection--toolbar .tox-collection__item--enabled { + background-color: #a6ccf7; + color: #222f3e; +} + +.tox .tox-collection--toolbar .tox-collection__item--active { + background-color: #cce2fa; +} + +.tox .tox-collection--grid .tox-collection__item--enabled { + background-color: #a6ccf7; + color: #222f3e; +} + +.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + background-color: #cce2fa; + color: #222f3e; +} + +.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #222f3e; +} + +.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #222f3e; +} + +.tox .tox-collection__item-icon, +.tox .tox-collection__item-checkmark { + align-items: center; + display: flex; + height: 24px; + justify-content: center; + width: 24px; +} + +.tox .tox-collection__item-icon svg, +.tox .tox-collection__item-checkmark svg { + fill: currentColor; +} + +.tox .tox-collection--toolbar-lg .tox-collection__item-icon { + height: 48px; + width: 48px; +} + +.tox .tox-collection__item-label { + color: currentColor; + display: inline-block; + flex: 1; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 24px; + text-transform: none; + word-break: break-all; +} + +.tox .tox-collection__item-accessory { + color: rgba(34, 47, 62, 0.7); + display: inline-block; + font-size: 14px; + height: 24px; + line-height: 24px; + text-transform: none; +} + +.tox .tox-collection__item-caret { + align-items: center; + display: flex; + min-height: 24px; +} + +.tox .tox-collection__item-caret::after { + content: ''; + font-size: 0; + min-height: inherit; +} + +.tox .tox-collection__item-caret svg { + fill: #222f3e; +} + +.tox .tox-collection__item--state-disabled { + background-color: transparent; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox +.tox-collection--list +.tox-collection__item:not(.tox-collection__item--enabled) +.tox-collection__item-checkmark +svg { + display: none; +} + +.tox +.tox-collection--list +.tox-collection__item:not(.tox-collection__item--enabled) +.tox-collection__item-accessory ++ .tox-collection__item-checkmark { + display: none; +} + +.tox .tox-collection--horizontal { + background-color: #fff; + border: 1px solid #e3e3e3; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: nowrap; + margin-bottom: 0; + overflow-x: auto; + padding: 0; +} + +.tox .tox-collection--horizontal .tox-collection__group { + align-items: center; + display: flex; + flex-wrap: nowrap; + margin: 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item { + height: 28px; + margin: 6px 1px 5px 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item-label { + white-space: nowrap; +} + +.tox .tox-collection--horizontal .tox-collection__item-caret { + margin-left: 4px; +} + +.tox .tox-collection__item-container { + display: flex; +} + +.tox .tox-collection__item-container--row { + align-items: center; + flex: 1 1 auto; + flex-direction: row; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-left { + margin-right: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-right { + justify-content: flex-end; + margin-left: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { + align-items: flex-start; + margin-bottom: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { + align-items: center; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { + align-items: flex-end; + margin-top: auto; +} + +.tox .tox-collection__item-container--column { + align-self: center; + flex: 1 1 auto; + flex-direction: column; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-left { + align-items: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-right { + align-items: flex-end; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { + align-self: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { + align-self: center; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { + align-self: flex-end; +} + +.tox:not([dir='rtl']) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-right: 1px solid transparent; +} + +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-left: 8px; +} + +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-collection__item-accessory { + margin-left: 16px; + text-align: right; +} + +.tox:not([dir='rtl']) .tox-collection .tox-collection__item-caret { + margin-left: 16px; +} + +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-left: 1px solid transparent; +} + +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-right: 8px; +} + +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-collection__item-accessory { + margin-right: 16px; + text-align: left; +} + +.tox[dir='rtl'] .tox-collection .tox-collection__item-caret { + margin-right: 16px; + transform: rotateY(180deg); +} + +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__item-caret { + margin-right: 4px; +} + +.tox .tox-color-picker-container { + display: flex; + flex-direction: row; + height: 225px; + margin: 0; +} + +.tox .tox-sv-palette { + box-sizing: border-box; + display: flex; + height: 100%; +} + +.tox .tox-sv-palette-spectrum { + height: 100%; +} + +.tox .tox-sv-palette, +.tox .tox-sv-palette-spectrum { + width: 225px; +} + +.tox .tox-sv-palette-thumb { + background: none; + border: 1px solid black; + border-radius: 50%; + box-sizing: content-box; + height: 12px; + position: absolute; + width: 12px; +} + +.tox .tox-sv-palette-inner-thumb { + border: 1px solid white; + border-radius: 50%; + height: 10px; + position: absolute; + width: 10px; +} + +.tox .tox-hue-slider { + box-sizing: border-box; + height: 100%; + width: 25px; +} + +.tox .tox-hue-slider-spectrum { + background: linear-gradient( + to bottom, + #f00, + #ff0080, + #f0f, + #8000ff, + #00f, + #0080ff, + #0ff, + #00ff80, + #0f0, + #80ff00, + #ff0, + #ff8000, + #f00 + ); + height: 100%; + width: 100%; +} + +.tox .tox-hue-slider, +.tox .tox-hue-slider-spectrum { + width: 20px; +} + +.tox .tox-hue-slider-thumb { + background: white; + border: 1px solid black; + box-sizing: content-box; + height: 4px; + width: 100%; +} + +.tox .tox-rgb-form { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.tox .tox-rgb-form div { + align-items: center; + display: flex; + justify-content: space-between; + margin-bottom: 5px; + width: inherit; +} + +.tox .tox-rgb-form input { + width: 6em; +} + +.tox .tox-rgb-form input.tox-invalid { + /* Need !important to override Chrome's focus styling unfortunately */ + border: 1px solid red !important; +} + +.tox .tox-rgb-form .tox-rgba-preview { + border: 1px solid black; + flex-grow: 2; + margin-bottom: 0; +} + +.tox:not([dir='rtl']) .tox-sv-palette { + margin-right: 15px; +} + +.tox:not([dir='rtl']) .tox-hue-slider { + margin-right: 15px; +} + +.tox:not([dir='rtl']) .tox-hue-slider-thumb { + margin-left: -1px; +} + +.tox:not([dir='rtl']) .tox-rgb-form label { + margin-right: 0.5em; +} + +.tox[dir='rtl'] .tox-sv-palette { + margin-left: 15px; +} + +.tox[dir='rtl'] .tox-hue-slider { + margin-left: 15px; +} + +.tox[dir='rtl'] .tox-hue-slider-thumb { + margin-right: -1px; +} + +.tox[dir='rtl'] .tox-rgb-form label { + margin-left: 0.5em; +} + +.tox .tox-toolbar .tox-swatches, +.tox .tox-toolbar__primary .tox-swatches, +.tox .tox-toolbar__overflow .tox-swatches { + margin: 5px 0 6px 11px; +} + +.tox .tox-collection--list .tox-collection__group .tox-swatches-menu { + border: 0; + margin: -4px -4px; +} + +.tox .tox-swatches__row { + display: flex; +} + +.tox .tox-swatch { + height: 30px; + transition: transform 0.15s, box-shadow 0.15s; + width: 30px; +} + +.tox .tox-swatch:hover, +.tox .tox-swatch:focus { + box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; + transform: scale(0.8); +} + +.tox .tox-swatch--remove { + align-items: center; + display: flex; + justify-content: center; +} + +.tox .tox-swatch--remove svg path { + stroke: #e74c3c; +} + +.tox .tox-swatches__picker-btn { + align-items: center; + background-color: transparent; + border: 0; + cursor: pointer; + display: flex; + height: 30px; + justify-content: center; + outline: none; + padding: 0; + width: 30px; +} + +.tox .tox-swatches__picker-btn svg { + fill: #222f3e; + height: 24px; + width: 24px; +} + +.tox .tox-swatches__picker-btn:hover { + background: #cce2fa; +} + +.tox:not([dir='rtl']) .tox-swatches__picker-btn { + margin-left: auto; +} + +.tox[dir='rtl'] .tox-swatches__picker-btn { + margin-right: auto; +} + +.tox .tox-comment-thread { + background: #fff; + position: relative; +} + +.tox .tox-comment-thread > *:not(:first-child) { + margin-top: 8px; +} + +.tox .tox-comment { + background: #fff; + border: 1px solid #eeeeee; + border-radius: 6px; + box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); + padding: 8px 8px 16px 8px; + position: relative; +} + +.tox .tox-comment__header { + align-items: center; + color: #222f3e; + display: flex; + justify-content: space-between; +} + +.tox .tox-comment__date { + color: rgba(34, 47, 62, 0.7); + font-size: 12px; +} + +.tox .tox-comment__body { + color: #222f3e; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin-top: 8px; + position: relative; + text-transform: initial; +} + +.tox .tox-comment__body textarea { + resize: none; + white-space: normal; + width: 100%; +} + +.tox .tox-comment__expander { + padding-top: 8px; +} + +.tox .tox-comment__expander p { + color: rgba(34, 47, 62, 0.7); + font-size: 14px; + font-style: normal; +} + +.tox .tox-comment__body p { + margin: 0; +} + +.tox .tox-comment__buttonspacing { + padding-top: 16px; + text-align: center; +} + +.tox .tox-comment-thread__overlay::after { + background: #fff; + bottom: 0; + content: ''; + display: flex; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + top: 0; + z-index: 5; +} + +.tox .tox-comment__reply { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 8px; +} + +.tox .tox-comment__reply > *:first-child { + margin-bottom: 8px; + width: 100%; +} + +.tox .tox-comment__edit { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 16px; +} + +.tox .tox-comment__gradient::after { + background: linear-gradient(rgba(255, 255, 255, 0), #fff); + bottom: 0; + content: ''; + display: block; + height: 5em; + margin-top: -40px; + position: absolute; + width: 100%; +} + +.tox .tox-comment__overlay { + background: #fff; + bottom: 0; + display: flex; + flex-direction: column; + flex-grow: 1; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + text-align: center; + top: 0; + z-index: 5; +} + +.tox .tox-comment__loading-text { + align-items: center; + color: #222f3e; + display: flex; + flex-direction: column; + position: relative; +} + +.tox .tox-comment__loading-text > div { + padding-bottom: 16px; +} + +.tox .tox-comment__overlaytext { + bottom: 0; + flex-direction: column; + font-size: 14px; + left: 0; + padding: 1em; + position: absolute; + right: 0; + top: 0; + z-index: 10; +} + +.tox .tox-comment__overlaytext p { + background-color: #fff; + box-shadow: 0 0 8px 8px #fff; + color: #222f3e; + text-align: center; +} + +.tox .tox-comment__overlaytext div:nth-of-type(2) { + font-size: 0.8em; +} + +.tox .tox-comment__busy-spinner { + align-items: center; + background-color: #fff; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 20; +} + +.tox .tox-comment__scroll { + display: flex; + flex-direction: column; + flex-shrink: 1; + overflow: auto; +} + +.tox .tox-conversations { + margin: 8px; +} + +.tox:not([dir='rtl']) .tox-comment__edit { + margin-left: 8px; +} + +.tox:not([dir='rtl']) .tox-comment__buttonspacing > *:last-child, +.tox:not([dir='rtl']) .tox-comment__edit > *:last-child, +.tox:not([dir='rtl']) .tox-comment__reply > *:last-child { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-comment__edit { + margin-right: 8px; +} + +.tox[dir='rtl'] .tox-comment__buttonspacing > *:last-child, +.tox[dir='rtl'] .tox-comment__edit > *:last-child, +.tox[dir='rtl'] .tox-comment__reply > *:last-child { + margin-right: 8px; +} + +.tox .tox-user { + align-items: center; + display: flex; +} + +.tox .tox-user__avatar svg { + fill: rgba(34, 47, 62, 0.7); +} + +.tox .tox-user__name { + color: rgba(34, 47, 62, 0.7); + font-size: 12px; + font-style: normal; + font-weight: bold; + text-transform: uppercase; +} + +.tox:not([dir='rtl']) .tox-user__avatar svg { + margin-right: 8px; +} + +.tox:not([dir='rtl']) .tox-user__avatar + .tox-user__name { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-user__avatar svg { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-user__avatar + .tox-user__name { + margin-right: 8px; +} + +.tox .tox-dialog-wrap { + align-items: center; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 1100; +} + +.tox .tox-dialog-wrap__backdrop { + background-color: rgba(255, 255, 255, 0.75); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} + +.tox .tox-dialog-wrap__backdrop--opaque { + background-color: #fff; +} + +.tox .tox-dialog { + background-color: #fff; + border-color: #eeeeee; + border-radius: 10px; + border-style: solid; + border-width: 0px; + box-shadow: 0 16px 16px -10px rgba(34, 47, 62, 0.15), 0 0 40px 1px rgba(34, 47, 62, 0.15); + display: flex; + flex-direction: column; + max-height: 100%; + max-width: 480px; + overflow: hidden; + position: relative; + width: 95vw; + z-index: 2; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog { + align-self: flex-start; + margin: 8px auto; + width: calc(100vw - 16px); + } +} + +.tox .tox-dialog-inline { + z-index: 1100; +} + +.tox .tox-dialog__header { + align-items: center; + background-color: #fff; + border-bottom: none; + color: #222f3e; + display: flex; + font-size: 16px; + justify-content: space-between; + padding: 8px 16px 0 16px; + position: relative; +} + +.tox .tox-dialog__header .tox-button { + z-index: 1; +} + +.tox .tox-dialog__draghandle { + cursor: grab; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tox .tox-dialog__draghandle:active { + cursor: grabbing; +} + +.tox .tox-dialog__dismiss { + margin-left: auto; +} + +.tox .tox-dialog__title { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 20px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin: 0; + text-transform: none; +} + +.tox .tox-dialog__body { + color: #222f3e; + display: flex; + flex: 1; + font-size: 16px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + min-width: 0; + text-align: left; + text-transform: none; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body { + flex-direction: column; + } +} + +.tox .tox-dialog__body-nav { + align-items: flex-start; + display: flex; + flex-direction: column; + padding: 16px 16px; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { + flex-direction: row; + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding-bottom: 0; + } +} + +.tox .tox-dialog__body-nav-item { + border-bottom: 2px solid transparent; + color: rgba(34, 47, 62, 0.7); + display: inline-block; + font-size: 14px; + line-height: 1.3; + margin-bottom: 8px; + text-decoration: none; + white-space: nowrap; +} + +.tox .tox-dialog__body-nav-item:focus { + background-color: rgba(0, 108, 231, 0.1); +} + +.tox .tox-dialog__body-nav-item--active { + border-bottom: 2px solid #006ce7; + color: #006ce7; +} + +.tox .tox-dialog__body-content { + box-sizing: border-box; + display: flex; + flex: 1; + flex-direction: column; + max-height: 650px; + overflow: auto; + -webkit-overflow-scrolling: touch; + padding: 16px 16px; +} + +.tox .tox-dialog__body-content > * { + margin-bottom: 0; + margin-top: 16px; +} + +.tox .tox-dialog__body-content > *:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content > *:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content > *:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog__body-content a { + color: #006ce7; + cursor: pointer; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:hover, +.tox .tox-dialog__body-content a:focus { + color: #0054b4; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:active { + color: #0054b4; + text-decoration: none; +} + +.tox .tox-dialog__body-content svg { + fill: #222f3e; +} + +.tox .tox-dialog__body-content ul { + display: block; + list-style-type: disc; + margin-bottom: 16px; + margin-inline-end: 0; + margin-inline-start: 0; + padding-inline-start: 2.5rem; +} + +.tox .tox-dialog__body-content .tox-form__group h1 { + color: #222f3e; + font-size: 20px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group h2 { + color: #222f3e; + font-size: 16px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group p { + margin-bottom: 16px; +} + +.tox .tox-dialog__body-content .tox-form__group h1:first-child, +.tox .tox-dialog__body-content .tox-form__group h2:first-child, +.tox .tox-dialog__body-content .tox-form__group p:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:last-child, +.tox .tox-dialog__body-content .tox-form__group h2:last-child, +.tox .tox-dialog__body-content .tox-form__group p:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:only-child, +.tox .tox-dialog__body-content .tox-form__group h2:only-child, +.tox .tox-dialog__body-content .tox-form__group p:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog--width-lg { + height: 650px; + max-width: 1200px; +} + +.tox .tox-dialog--width-md { + max-width: 800px; +} + +.tox .tox-dialog--width-md .tox-dialog__body-content { + overflow: auto; +} + +.tox .tox-dialog__body-content--centered { + text-align: center; +} + +.tox .tox-dialog__footer { + align-items: center; + background-color: #fff; + border-top: none; + display: flex; + justify-content: space-between; + padding: 8px 16px; +} + +.tox .tox-dialog__footer-start, +.tox .tox-dialog__footer-end { + display: flex; +} + +.tox .tox-dialog__busy-spinner { + align-items: center; + background-color: rgba(255, 255, 255, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 3; +} + +.tox .tox-dialog__table { + border-collapse: collapse; + width: 100%; +} + +.tox .tox-dialog__table thead th { + font-weight: bold; + padding-bottom: 8px; +} + +.tox .tox-dialog__table tbody tr { + border-bottom: 1px solid #eeeeee; +} + +.tox .tox-dialog__table tbody tr:last-child { + border-bottom: none; +} + +.tox .tox-dialog__table td { + padding-bottom: 8px; + padding-top: 8px; +} + +.tox .tox-dialog__popups { + position: absolute; + width: 100%; + z-index: 1100; +} + +.tox .tox-dialog__body-iframe { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-dialog__body-iframe .tox-navobj { + display: flex; + flex: 1; +} + +.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} + +.tox .tox-dialog-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox .tox-dialog-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox .tox-dialog-dock-transition { + transition: visibility 0s linear 0.3s, opacity 0.3s ease; +} + +.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { + transition-delay: 0s; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav { + margin-right: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav-item:not(:first-child) { + margin-left: 8px; + } +} + +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-start > *, +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-end > * { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-dialog__body { + text-align: right; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav { + margin-left: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav-item:not(:first-child) { + margin-right: 8px; + } +} + +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-start > *, +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-end > * { + margin-right: 8px; +} + +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox .tox-dropzone-container { + display: flex; + flex: 1; +} + +.tox .tox-dropzone { + align-items: center; + background: #fff; + border: 2px dashed #eeeeee; + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-grow: 1; + justify-content: center; + min-height: 100px; + padding: 10px; +} + +.tox .tox-dropzone p { + color: rgba(34, 47, 62, 0.7); + margin: 0 0 16px 0; +} + +.tox .tox-edit-area { + display: flex; + flex: 1; + overflow: hidden; + position: relative; +} + +.tox .tox-edit-area__iframe { + background-color: #fff; + border: 0; + box-sizing: border-box; + flex: 1; + height: 100%; + position: absolute; + width: 100%; +} + +.tox.tox-inline-edit-area { + border: 1px dotted #eeeeee; +} + +.tox .tox-editor-container { + display: flex; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} + +.tox .tox-editor-header { + z-index: 1; +} + +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: #fff; + border-bottom: none; + box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.1), 0 8px 8px -4px rgba(34, 47, 62, 0.07); + padding: 4px 0; + transition: box-shadow 0.5s; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: 1px solid #e3e3e3; + box-shadow: none; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: #fff; + box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.2), 0 8px 8px -4px rgba(34, 47, 62, 0.15); + padding: 4px 0; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.2), 0 8px 8px -4px rgba(34, 47, 62, 0.15); +} + +.tox-editor-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox-editor-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox-editor-dock-transition { + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} + +.tox-editor-dock-transition.tox-editor-dock-fadein { + transition-delay: 0s; +} + +.tox .tox-control-wrap { + flex: 1; + position: relative; +} + +.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, +.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, +.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { + display: none; +} + +.tox .tox-control-wrap svg { + display: block; +} + +.tox .tox-control-wrap__status-icon-wrap { + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-control-wrap__status-icon-invalid svg { + fill: #c00; +} + +.tox .tox-control-wrap__status-icon-unknown svg { + fill: orange; +} + +.tox .tox-control-wrap__status-icon-valid svg { + fill: green; +} + +.tox:not([dir='rtl']) .tox-control-wrap--status-invalid .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-unknown .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-valid .tox-textfield { + padding-right: 32px; +} + +.tox:not([dir='rtl']) .tox-control-wrap__status-icon-wrap { + right: 4px; +} + +.tox[dir='rtl'] .tox-control-wrap--status-invalid .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-unknown .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-valid .tox-textfield { + padding-left: 32px; +} + +.tox[dir='rtl'] .tox-control-wrap__status-icon-wrap { + left: 4px; +} + +.tox .tox-autocompleter { + max-width: 25em; +} + +.tox .tox-autocompleter .tox-menu { + border-color: #eeeeee; + box-shadow: none; + max-width: 25em; +} + +.tox .tox-autocompleter .tox-autocompleter-highlight { + font-weight: bold; +} + +.tox .tox-color-input { + display: flex; + position: relative; + z-index: 1; +} + +.tox .tox-color-input .tox-textfield { + z-index: -1; +} + +.tox .tox-color-input span { + border-color: rgba(34, 47, 62, 0.2); + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + height: 24px; + position: absolute; + top: 6px; + width: 24px; +} + +.tox .tox-color-input span:hover:not([aria-disabled='true']), +.tox .tox-color-input span:focus:not([aria-disabled='true']) { + border-color: #006ce7; + cursor: pointer; +} + +.tox .tox-color-input span::before { + background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), + linear-gradient(-45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%), + linear-gradient(-45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%); + background-position: 0 0, 0 6px, 6px -6px, -6px 0; + background-size: 12px 12px; + border: 1px solid #fff; + border-radius: 6px; + box-sizing: border-box; + content: ''; + height: 24px; + left: -1px; + position: absolute; + top: -1px; + width: 24px; + z-index: -1; +} + +.tox .tox-color-input span[aria-disabled='true'] { + cursor: not-allowed; +} + +.tox:not([dir='rtl']) .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir='rtl']) .tox-color-input .tox-textfield { + padding-left: 36px; +} + +.tox:not([dir='rtl']) .tox-color-input span { + left: 6px; +} + +.tox[dir='rtl'] .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir='rtl'] .tox-color-input .tox-textfield { + padding-right: 36px; +} + +.tox[dir='rtl'] .tox-color-input span { + right: 6px; +} + +.tox .tox-label, +.tox .tox-toolbar-label { + color: rgba(34, 47, 62, 0.7); + display: block; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + padding: 0 8px 0 0; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-toolbar-label { + padding: 0 8px; +} + +.tox[dir='rtl'] .tox-label { + padding: 0 0 0 8px; +} + +.tox .tox-form { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-form__group { + box-sizing: border-box; + margin-bottom: 4px; +} + +.tox .tox-form-group--maximize { + flex: 1; +} + +.tox .tox-form__group--error { + color: #c00; +} + +.tox .tox-form__group--collection { + display: flex; +} + +.tox .tox-form__grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} + +.tox .tox-form__grid--2col > .tox-form__group { + width: calc(50% - (8px / 2)); +} + +.tox .tox-form__grid--3col > .tox-form__group { + width: calc(100% / 3 - (8px / 2)); +} + +.tox .tox-form__grid--4col > .tox-form__group { + width: calc(25% - (8px / 2)); +} + +.tox .tox-form__controls-h-stack { + align-items: center; + display: flex; +} + +.tox .tox-form__group--inline { + align-items: center; + display: flex; +} + +.tox .tox-form__group--stretched { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-form__group--stretched .tox-textarea { + flex: 1; +} + +.tox .tox-form__group--stretched .tox-navobj { + display: flex; + flex: 1; +} + +.tox .tox-form__group--stretched .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} + +.tox:not([dir='rtl']) .tox-form__controls-h-stack > *:not(:first-child) { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-form__controls-h-stack > *:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-lock.tox-locked .tox-lock-icon__unlock, +.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { + display: none; +} + +.tox .tox-textfield, +.tox .tox-toolbar-textfield, +.tox .tox-listboxfield .tox-listbox--select, +.tox .tox-textarea { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #eeeeee; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #222f3e; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 5.5px; + resize: none; + width: 100%; +} + +.tox .tox-textfield[disabled], +.tox .tox-textarea[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} + +.tox .tox-textfield:focus, +.tox .tox-listboxfield .tox-listbox--select:focus, +.tox .tox-textarea:focus { + background-color: #fff; + border-color: #006ce7; + box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); + outline: none; +} + +.tox .tox-toolbar-textfield { + border-width: 0; + margin-bottom: 3px; + margin-top: 2px; + max-width: 250px; +} + +.tox .tox-naked-btn { + background-color: transparent; + border: 0; + border-color: transparent; + box-shadow: unset; + color: #006ce7; + cursor: pointer; + display: block; + margin: 0; + padding: 0; +} + +.tox .tox-naked-btn svg { + display: block; + fill: #222f3e; +} + +.tox:not([dir='rtl']) .tox-toolbar-textfield + * { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-toolbar-textfield + * { + margin-right: 4px; +} + +.tox .tox-listboxfield { + cursor: pointer; + position: relative; +} + +.tox .tox-listboxfield .tox-listbox--select[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} + +.tox .tox-listbox__select-label { + cursor: default; + flex: 1; + margin: 0 4px; +} + +.tox .tox-listbox__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-listbox__select-chevron svg { + fill: #222f3e; +} + +.tox .tox-listboxfield .tox-listbox--select { + align-items: center; + display: flex; +} + +.tox:not([dir='rtl']) .tox-listboxfield svg { + right: 8px; +} + +.tox[dir='rtl'] .tox-listboxfield svg { + left: 8px; +} + +.tox .tox-selectfield { + cursor: pointer; + position: relative; +} + +.tox .tox-selectfield select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #eeeeee; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #222f3e; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 5.5px; + resize: none; + width: 100%; +} + +.tox .tox-selectfield select[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} + +.tox .tox-selectfield select::-ms-expand { + display: none; +} + +.tox .tox-selectfield select:focus { + background-color: #fff; + border-color: #006ce7; + box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); + outline: none; +} + +.tox .tox-selectfield svg { + pointer-events: none; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox:not([dir='rtl']) .tox-selectfield select[size='0'], +.tox:not([dir='rtl']) .tox-selectfield select[size='1'] { + padding-right: 24px; +} + +.tox:not([dir='rtl']) .tox-selectfield svg { + right: 8px; +} + +.tox[dir='rtl'] .tox-selectfield select[size='0'], +.tox[dir='rtl'] .tox-selectfield select[size='1'] { + padding-left: 24px; +} + +.tox[dir='rtl'] .tox-selectfield svg { + left: 8px; +} + +.tox .tox-textarea { + -webkit-appearance: textarea; + -moz-appearance: textarea; + appearance: textarea; + white-space: pre-wrap; +} + +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen, +.tox-shadowhost.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} + +.tox .tox-help__more-link { + list-style: none; + margin-top: 1em; +} + +.tox .tox-imagepreview { + background-color: #666; + height: 380px; + overflow: hidden; + position: relative; + width: 100%; +} + +.tox .tox-imagepreview.tox-imagepreview__loaded { + overflow: auto; +} + +.tox .tox-imagepreview__container { + display: flex; + left: 100vw; + position: absolute; + top: 100vw; +} + +.tox .tox-imagepreview__image { + background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); +} + +.tox .tox-image-tools .tox-spacer { + flex: 1; +} + +.tox .tox-image-tools .tox-bar { + align-items: center; + display: flex; + height: 60px; + justify-content: center; +} + +.tox .tox-image-tools .tox-imagepreview, +.tox .tox-image-tools .tox-imagepreview + .tox-bar { + margin-top: 8px; +} + +.tox .tox-image-tools .tox-croprect-block { + background: black; + filter: alpha(opacity=50); + opacity: 0.5; + position: absolute; + zoom: 1; +} + +.tox .tox-image-tools .tox-croprect-handle { + border: 2px solid white; + height: 20px; + left: 0; + position: absolute; + top: 0; + width: 20px; +} + +.tox .tox-image-tools .tox-croprect-handle-move { + border: 0; + cursor: move; + position: absolute; +} + +.tox .tox-image-tools .tox-croprect-handle-nw { + border-width: 2px 0 0 2px; + cursor: nw-resize; + left: 100px; + margin: -2px 0 0 -2px; + top: 100px; +} + +.tox .tox-image-tools .tox-croprect-handle-ne { + border-width: 2px 2px 0 0; + cursor: ne-resize; + left: 200px; + margin: -2px 0 0 -20px; + top: 100px; +} + +.tox .tox-image-tools .tox-croprect-handle-sw { + border-width: 0 0 2px 2px; + cursor: sw-resize; + left: 100px; + margin: -20px 2px 0 -2px; + top: 200px; +} + +.tox .tox-image-tools .tox-croprect-handle-se { + border-width: 0 2px 2px 0; + cursor: se-resize; + left: 200px; + margin: -20px 0 0 -20px; + top: 200px; +} + +.tox .tox-insert-table-picker { + display: flex; + flex-wrap: wrap; + width: 170px; +} + +.tox .tox-insert-table-picker > div { + border-color: #eeeeee; + border-style: solid; + border-width: 0 1px 1px 0; + box-sizing: border-box; + height: 17px; + width: 17px; +} + +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: -4px -4px; +} + +.tox .tox-insert-table-picker .tox-insert-table-picker__selected { + background-color: rgba(0, 108, 231, 0.5); + border-color: rgba(0, 108, 231, 0.5); +} + +.tox .tox-insert-table-picker__label { + color: rgba(34, 47, 62, 0.7); + display: block; + font-size: 14px; + padding: 4px; + text-align: center; + width: 100%; +} + +.tox:not([dir='rtl']) { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir='rtl']) .tox-insert-table-picker > div:nth-child(10n) { + border-right: 0; +} + +.tox[dir='rtl'] { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir='rtl'] .tox-insert-table-picker > div:nth-child(10n + 1) { + border-right: 0; +} + +.tox { + /* stylelint-disable */ + /* stylelint-enable */ +} + +.tox .tox-menu { + background-color: #fff; + border: 1px solid transparent; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + display: inline-block; + overflow: hidden; + vertical-align: top; + z-index: 1150; +} + +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0 4px; +} + +.tox .tox-menu.tox-collection.tox-collection--toolbar { + padding: 8px; +} + +.tox .tox-menu.tox-collection.tox-collection--grid { + padding: 8px; +} + +.tox .tox-menu__label h1, +.tox .tox-menu__label h2, +.tox .tox-menu__label h3, +.tox .tox-menu__label h4, +.tox .tox-menu__label h5, +.tox .tox-menu__label h6, +.tox .tox-menu__label p, +.tox .tox-menu__label blockquote, +.tox .tox-menu__label code { + margin: 0; +} + +.tox .tox-menubar { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='transparent'/%3E%3C/svg%3E") left 0 top 0 #fff; + background-color: #fff; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 11px 0 12px; +} + +.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { + border-top: 1px solid transparent; +} + +/* Deprecated. Remove in next major release */ +.tox .tox-mbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #222f3e; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 28px; + justify-content: center; + margin: 5px 1px 6px 0; + outline: none; + overflow: hidden; + padding: 0 4px; + text-transform: none; + width: auto; +} + +.tox .tox-mbtn[disabled] { + background-color: transparent; + border: 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-mbtn:focus:not(:disabled) { + background: #cce2fa; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-mbtn--active { + background: #a6ccf7; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { + background: #cce2fa; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-mbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-mbtn[disabled] .tox-mbtn__select-label { + cursor: not-allowed; +} + +.tox .tox-mbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; + display: none; +} + +.tox .tox-notification { + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + display: grid; + font-size: 14px; + font-weight: normal; + grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + margin-top: 4px; + opacity: 0; + padding: 4px; + transition: transform 100ms ease-in, opacity 150ms ease-in; +} + +.tox .tox-notification p { + font-size: 14px; + font-weight: normal; +} + +.tox .tox-notification a { + cursor: pointer; + text-decoration: underline; +} + +.tox .tox-notification--in { + opacity: 1; +} + +.tox .tox-notification--success { + background-color: #e4eeda; + border-color: #d7e6c8; + color: #222f3e; +} + +.tox .tox-notification--success p { + color: #222f3e; +} + +.tox .tox-notification--success a { + color: #517342; +} + +.tox .tox-notification--success svg { + fill: #222f3e; +} + +.tox .tox-notification--error { + background-color: #f5cccc; + border-color: #f0b3b3; + color: #222f3e; +} + +.tox .tox-notification--error p { + color: #222f3e; +} + +.tox .tox-notification--error a { + color: #77181f; +} + +.tox .tox-notification--error svg { + fill: #222f3e; +} + +.tox .tox-notification--warn, +.tox .tox-notification--warning { + background-color: #fff5cc; + border-color: #fff0b3; + color: #222f3e; +} + +.tox .tox-notification--warn p, +.tox .tox-notification--warning p { + color: #222f3e; +} + +.tox .tox-notification--warn a, +.tox .tox-notification--warning a { + color: #7a6e25; +} + +.tox .tox-notification--warn svg, +.tox .tox-notification--warning svg { + fill: #222f3e; +} + +.tox .tox-notification--info { + background-color: #d6e7fb; + border-color: #c1dbf9; + color: #222f3e; +} + +.tox .tox-notification--info p { + color: #222f3e; +} + +.tox .tox-notification--info a { + color: #2a64a6; +} + +.tox .tox-notification--info svg { + fill: #222f3e; +} + +.tox .tox-notification__body { + align-self: center; + color: #222f3e; + font-size: 14px; + grid-column-end: 3; + grid-column-start: 2; + grid-row-end: 2; + grid-row-start: 1; + text-align: center; + white-space: normal; + word-break: break-all; + word-break: break-word; +} + +.tox .tox-notification__body > * { + margin: 0; +} + +.tox .tox-notification__body > * + * { + margin-top: 1rem; +} + +.tox .tox-notification__icon { + align-self: center; + grid-column-end: 2; + grid-column-start: 1; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} + +.tox .tox-notification__icon svg { + display: block; +} + +.tox .tox-notification__dismiss { + align-self: start; + grid-column-end: 4; + grid-column-start: 3; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} + +.tox .tox-notification .tox-progress-bar { + grid-column-end: 4; + grid-column-start: 1; + grid-row-end: 3; + grid-row-start: 2; + justify-self: center; +} + +.tox .tox-pop { + display: inline-block; + position: relative; +} + +.tox .tox-pop--resizing { + transition: width 0.1s ease; +} + +.tox .tox-pop--resizing .tox-toolbar, +.tox .tox-pop--resizing .tox-toolbar__group { + flex-wrap: nowrap; +} + +.tox .tox-pop--transition { + transition: 0.15s ease; + transition-property: left, right, top, bottom; +} + +.tox .tox-pop--transition::before, +.tox .tox-pop--transition::after { + transition: all 0.15s, visibility 0s, opacity 0.075s ease 0.075s; +} + +.tox .tox-pop__dialog { + background-color: #fff; + border: 1px solid #eeeeee; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + min-width: 0; + overflow: hidden; +} + +.tox .tox-pop__dialog > *:not(.tox-toolbar) { + margin: 4px 4px 4px 8px; +} + +.tox .tox-pop__dialog .tox-toolbar { + background-color: transparent; + margin-bottom: -1px; +} + +.tox .tox-pop::before, +.tox .tox-pop::after { + border-style: solid; + content: ''; + display: block; + height: 0; + opacity: 1; + position: absolute; + width: 0; +} + +.tox .tox-pop.tox-pop--inset::before, +.tox .tox-pop.tox-pop--inset::after { + opacity: 0; + transition: all 0s 0.15s, visibility 0s, opacity 0.075s ease; +} + +.tox .tox-pop.tox-pop--bottom::before, +.tox .tox-pop.tox-pop--bottom::after { + left: 50%; + top: 100%; +} + +.tox .tox-pop.tox-pop--bottom::after { + border-color: #fff transparent transparent transparent; + border-width: 8px; + margin-left: -8px; + margin-top: -1px; +} + +.tox .tox-pop.tox-pop--bottom::before { + border-color: #eeeeee transparent transparent transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--top::before, +.tox .tox-pop.tox-pop--top::after { + left: 50%; + top: 0; + transform: translateY(-100%); +} + +.tox .tox-pop.tox-pop--top::after { + border-color: transparent transparent #fff transparent; + border-width: 8px; + margin-left: -8px; + margin-top: 1px; +} + +.tox .tox-pop.tox-pop--top::before { + border-color: transparent transparent #eeeeee transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--left::before, +.tox .tox-pop.tox-pop--left::after { + left: 0; + top: calc(50% - 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--left::after { + border-color: transparent #fff transparent transparent; + border-width: 8px; + margin-left: -15px; +} + +.tox .tox-pop.tox-pop--left::before { + border-color: transparent #eeeeee transparent transparent; + border-width: 10px; + margin-left: -19px; +} + +.tox .tox-pop.tox-pop--right::before, +.tox .tox-pop.tox-pop--right::after { + left: 100%; + top: calc(50% + 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--right::after { + border-color: transparent transparent transparent #fff; + border-width: 8px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--right::before { + border-color: transparent transparent transparent #eeeeee; + border-width: 10px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--align-left::before, +.tox .tox-pop.tox-pop--align-left::after { + left: 20px; +} + +.tox .tox-pop.tox-pop--align-right::before, +.tox .tox-pop.tox-pop--align-right::after { + left: calc(100% - 20px); +} + +.tox .tox-sidebar-wrap { + display: flex; + flex-direction: row; + flex-grow: 1; + min-height: 0; +} + +.tox .tox-sidebar { + background-color: #fff; + display: flex; + flex-direction: row; + justify-content: flex-end; +} + +.tox .tox-sidebar__slider { + display: flex; + overflow: hidden; +} + +.tox .tox-sidebar__pane-container { + display: flex; +} + +.tox .tox-sidebar__pane { + display: flex; +} + +.tox .tox-sidebar--sliding-closed { + opacity: 0; +} + +.tox .tox-sidebar--sliding-open { + opacity: 1; +} + +.tox .tox-sidebar--sliding-growing, +.tox .tox-sidebar--sliding-shrinking { + transition: width 0.5s ease, opacity 0.5s ease; +} + +.tox .tox-selector { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + display: inline-block; + height: 10px; + position: absolute; + width: 10px; +} + +.tox.tox-platform-touch .tox-selector { + height: 12px; + width: 12px; +} + +.tox .tox-slider { + align-items: center; + display: flex; + flex: 1; + height: 24px; + justify-content: center; + position: relative; +} + +.tox .tox-slider__rail { + background-color: transparent; + border: 1px solid #eeeeee; + border-radius: 6px; + height: 10px; + min-width: 120px; + width: 100%; +} + +.tox .tox-slider__handle { + background-color: #006ce7; + border: 2px solid #0054b4; + border-radius: 6px; + box-shadow: none; + height: 24px; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: 14px; +} + +.tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { + margin-inline-start: 8px; +} + +.tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { + margin-inline-start: 32px; +} + +.tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { + margin-inline-start: 32px; +} + +.tox .tox-source-code { + overflow: auto; +} + +.tox .tox-spinner { + display: flex; +} + +.tox .tox-spinner > div { + animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; + background-color: rgba(34, 47, 62, 0.7); + border-radius: 100%; + height: 8px; + width: 8px; +} + +.tox .tox-spinner > div:nth-child(1) { + animation-delay: -0.32s; +} + +.tox .tox-spinner > div:nth-child(2) { + animation-delay: -0.16s; +} + +@keyframes tam-bouncing-dots { + 0%, + 80%, + 100% { + transform: scale(0); + } + 40% { + transform: scale(1); + } +} + +.tox:not([dir='rtl']) .tox-spinner > div:not(:first-child) { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-spinner > div:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-statusbar { + align-items: center; + background-color: #fff; + border-top: 1px solid #e3e3e3; + color: rgba(34, 47, 62, 0.7); + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-weight: normal; + height: 25px; + overflow: hidden; + padding: 0 8px; + position: relative; + text-transform: none; +} + +.tox .tox-statusbar__text-container { + display: flex; + flex: 1 1 auto; + justify-content: flex-end; + overflow: hidden; +} + +.tox .tox-statusbar__path { + display: flex; + flex: 1 1 auto; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tox .tox-statusbar__path > * { + display: inline; + white-space: nowrap; +} + +.tox .tox-statusbar__wordcount { + flex: 0 0 auto; + margin-left: 1ch; +} + +.tox .tox-statusbar a, +.tox .tox-statusbar__path-item, +.tox .tox-statusbar__wordcount { + color: rgba(34, 47, 62, 0.7); + text-decoration: none; +} + +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']) { + color: #222f3e; + cursor: pointer; +} + +.tox .tox-statusbar__branding svg { + fill: rgba(34, 47, 62, 0.8); + height: 1.14em; + vertical-align: -0.28em; + width: 3.6em; +} + +.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled='true']) svg, +.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled='true']) svg { + fill: #222f3e; +} + +.tox .tox-statusbar__resize-handle { + align-items: flex-end; + align-self: stretch; + cursor: nwse-resize; + display: flex; + flex: 0 0 auto; + justify-content: flex-end; + margin-left: auto; + margin-right: -8px; + padding-bottom: 3px; + padding-left: 1ch; + padding-right: 3px; +} + +.tox .tox-statusbar__resize-handle svg { + display: block; + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-statusbar__resize-handle:focus svg { + background-color: #dee0e2; + border-radius: 1px 1px 5px 1px; + box-shadow: 0 0 0 2px #dee0e2; +} + +.tox:not([dir='rtl']) .tox-statusbar__path > * { + margin-right: 4px; +} + +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 2ch; +} + +.tox[dir='rtl'] .tox-statusbar { + flex-direction: row-reverse; +} + +.tox[dir='rtl'] .tox-statusbar__path > * { + margin-left: 4px; +} + +.tox .tox-throbber { + z-index: 1299; +} + +.tox .tox-throbber__busy-spinner { + align-items: center; + background-color: rgba(255, 255, 255, 0.6); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.tox .tox-tbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #222f3e; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 28px; + justify-content: center; + margin: 6px 1px 5px 0; + outline: none; + overflow: hidden; + padding: 0; + text-transform: none; + width: 34px; +} + +.tox .tox-tbtn svg { + display: block; + fill: #222f3e; +} + +.tox .tox-tbtn.tox-tbtn-more { + padding-left: 5px; + padding-right: 5px; + width: inherit; +} + +.tox .tox-tbtn:focus { + background: #cce2fa; + border: 0; + box-shadow: none; +} + +.tox .tox-tbtn:hover { + background: #cce2fa; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-tbtn:hover svg { + fill: #222f3e; +} + +.tox .tox-tbtn:active { + background: #a6ccf7; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-tbtn:active svg { + fill: #222f3e; +} + +.tox .tox-tbtn--disabled, +.tox .tox-tbtn--disabled:hover, +.tox .tox-tbtn:disabled, +.tox .tox-tbtn:disabled:hover { + background: transparent; + border: 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-tbtn--disabled svg, +.tox .tox-tbtn--disabled:hover svg, +.tox .tox-tbtn:disabled svg, +.tox .tox-tbtn:disabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-tbtn--enabled, +.tox .tox-tbtn--enabled:hover { + background: #a6ccf7; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-tbtn--enabled > *, +.tox .tox-tbtn--enabled:hover > * { + transform: none; +} + +.tox .tox-tbtn--enabled svg, +.tox .tox-tbtn--enabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: #222f3e; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { + color: #222f3e; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { + fill: #222f3e; +} + +.tox .tox-tbtn:active > * { + transform: none; +} + +.tox .tox-tbtn--md { + height: 42px; + width: 51px; +} + +.tox .tox-tbtn--lg { + flex-direction: column; + height: 56px; + width: 68px; +} + +.tox .tox-tbtn--return { + align-self: stretch; + height: unset; + width: 16px; +} + +.tox .tox-tbtn--labeled { + padding: 0 4px; + width: unset; +} + +.tox .tox-tbtn__vlabel { + display: block; + font-size: 10px; + font-weight: normal; + letter-spacing: -0.025em; + margin-bottom: 4px; + white-space: nowrap; +} + +.tox .tox-tbtn--select { + margin: 6px 1px 5px 0; + padding: 0 4px; + width: auto; +} + +.tox .tox-tbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-tbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-tbtn__select-chevron svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-tbtn--bespoke { + background: #f7f7f7; +} + +.tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { + margin-inline-start: 4px; +} + +.tox .tox-tbtn--bespoke .tox-tbtn__select-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 7em; +} + +.tox .tox-split-button { + border: 0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + margin: 6px 1px 5px 0; + overflow: hidden; +} + +.tox .tox-split-button:hover { + box-shadow: 0 0 0 1px #cce2fa inset; +} + +.tox .tox-split-button:focus { + background: #cce2fa; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-split-button > * { + border-radius: 0; +} + +.tox .tox-split-button__chevron { + width: 16px; +} + +.tox .tox-split-button__chevron svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-split-button .tox-tbtn { + margin: 0; +} + +.tox .tox-split-button.tox-tbtn--disabled:hover, +.tox .tox-split-button.tox-tbtn--disabled:focus, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus { + background: transparent; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} + +.tox.tox-platform-touch .tox-split-button .tox-tbtn--select { + padding: 0 0px; +} + +.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { + width: 30px; +} + +.tox.tox-platform-touch .tox-split-button__chevron { + width: 20px; +} + +.tox .tox-toolbar-overlord { + background-color: #fff; +} + +.tox .tox-toolbar, +.tox .tox-toolbar__primary, +.tox .tox-toolbar__overflow { + background-color: #fff; + background-image: repeating-linear-gradient(#e3e3e3 0px 1px, transparent 1px 39px); + background-position: center top 40px; + background-repeat: no-repeat; + background-size: calc(100% - 11px * 2) calc(100% - 41px); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 0px; + transform: perspective(1px); +} + +.tox .tox-toolbar-overlord > .tox-toolbar, +.tox .tox-toolbar-overlord > .tox-toolbar__primary, +.tox .tox-toolbar-overlord > .tox-toolbar__overflow { + background-position: center top 0px; + background-size: calc(100% - 11px * 2) calc(100% - 0px); +} + +.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { + height: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; + visibility: hidden; +} + +.tox .tox-toolbar__overflow--growing { + transition: height 0.3s ease, opacity 0.2s linear 0.1s; +} + +.tox .tox-toolbar__overflow--shrinking { + transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; +} + +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: 1px solid transparent; + margin-top: 0px; + padding-bottom: 1px; + padding-top: 1px; +} + +.tox .tox-toolbar--scrolling { + flex-wrap: nowrap; + overflow-x: auto; +} + +.tox .tox-pop .tox-toolbar { + border-width: 0; +} + +.tox .tox-toolbar--no-divider { + background-image: none; +} + +.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, +.tox .tox-toolbar-overlord .tox-toolbar__primary { + background-position: center top 39px; +} + +.tox .tox-editor-header > .tox-toolbar--scrolling, +.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { + background-image: none; +} + +.tox.tox-tinymce-aux .tox-toolbar__overflow { + background-color: #fff; + background-position: center top 43px; + background-size: calc(100% - 8px * 2) calc(100% - 51px); + border: none; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + padding: 4px 0; +} + +.tox-pop .tox-pop__dialog { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox-pop .tox-pop__dialog .tox-toolbar { + background-position: center top 43px; + background-size: calc(100% - 11px * 2) calc(100% - 51px); + padding: 4px 0; +} + +.tox .tox-toolbar__group { + align-items: center; + display: flex; + flex-wrap: wrap; + margin: 0 0; + padding: 0 11px 0 12px; +} + +.tox .tox-toolbar__group--pull-right { + margin-left: auto; +} + +.tox .tox-toolbar--scrolling .tox-toolbar__group { + flex-shrink: 0; + flex-wrap: nowrap; +} + +.tox:not([dir='rtl']) .tox-toolbar__group:not(:last-of-type) { + border-right: 1px solid transparent; +} + +.tox[dir='rtl'] .tox-toolbar__group:not(:last-of-type) { + border-left: 1px solid transparent; +} + +.tox .tox-tooltip { + display: inline-block; + padding: 8px; + position: relative; +} + +.tox .tox-tooltip__body { + background-color: #222f3e; + border-radius: 6px; + box-shadow: 0 2px 4px rgba(34, 47, 62, 0.3); + color: rgba(255, 255, 255, 0.75); + font-size: 14px; + font-style: normal; + font-weight: normal; + padding: 4px 8px; + text-transform: none; +} + +.tox .tox-tooltip__arrow { + position: absolute; +} + +.tox .tox-tooltip--down .tox-tooltip__arrow { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #222f3e; + bottom: 0; + left: 50%; + position: absolute; + transform: translateX(-50%); +} + +.tox .tox-tooltip--up .tox-tooltip__arrow { + border-bottom: 8px solid #222f3e; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + left: 50%; + position: absolute; + top: 0; + transform: translateX(-50%); +} + +.tox .tox-tooltip--right .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-left: 8px solid #222f3e; + border-top: 8px solid transparent; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-tooltip--left .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-right: 8px solid #222f3e; + border-top: 8px solid transparent; + left: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-well { + border: 1px solid #eeeeee; + border-radius: 6px; + padding: 8px; + width: 100%; +} + +.tox .tox-well > *:first-child { + margin-top: 0; +} + +.tox .tox-well > *:last-child { + margin-bottom: 0; +} + +.tox .tox-well > *:only-child { + margin: 0; +} + +.tox .tox-custom-editor { + border: 1px solid #eeeeee; + border-radius: 6px; + display: flex; + flex: 1; + position: relative; +} + +/* stylelint-disable */ +.tox { + /* stylelint-enable */ +} + +.tox .tox-dialog-loading::before { + background-color: rgba(0, 0, 0, 0.5); + content: ''; + height: 100%; + position: absolute; + width: 100%; + z-index: 1000; +} + +.tox .tox-tab { + cursor: pointer; +} + +.tox .tox-dialog__content-js { + display: flex; + flex: 1; +} + +.tox .tox-dialog__body-content .tox-collection { + display: flex; + flex: 1; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.min.css b/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.min.css new file mode 100644 index 00000000..3f1bf7ec --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.min.css @@ -0,0 +1,3040 @@ +.tox { + box-shadow: none; + box-sizing: content-box; + color: #222f3e; + cursor: auto; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + -webkit-tap-highlight-color: transparent; + text-decoration: none; + text-shadow: none; + text-transform: none; + vertical-align: initial; + white-space: normal; +} +.tox :not(svg):not(rect) { + box-sizing: inherit; + color: inherit; + cursor: inherit; + direction: inherit; + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; + line-height: inherit; + -webkit-tap-highlight-color: inherit; + text-align: inherit; + text-decoration: inherit; + text-shadow: inherit; + text-transform: inherit; + vertical-align: inherit; + white-space: inherit; +} +.tox :not(svg):not(rect) { + background: 0 0; + border: 0; + box-shadow: none; + float: none; + height: auto; + margin: 0; + max-width: none; + outline: 0; + padding: 0; + position: static; + width: auto; +} +.tox:not([dir='rtl']) { + direction: ltr; + text-align: left; +} +.tox[dir='rtl'] { + direction: rtl; + text-align: right; +} +.tox-tinymce { + border: 2px solid #eee; + border-radius: 10px; + box-shadow: none; + box-sizing: border-box; + display: flex; + flex-direction: column; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + overflow: hidden; + position: relative; + visibility: inherit !important; +} +.tox.tox-tinymce-inline { + border: none; + box-shadow: none; + overflow: initial; +} +.tox.tox-tinymce-inline .tox-editor-container { + overflow: initial; +} +.tox.tox-tinymce-inline .tox-editor-header { + background-color: #fff; + border: 2px solid #eee; + border-radius: 10px; + box-shadow: none; + overflow: hidden; +} +.tox-tinymce-aux { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + z-index: 1300; +} +.tox-tinymce :focus, +.tox-tinymce-aux :focus { + outline: 0; +} +button::-moz-focus-inner { + border: 0; +} +.tox[dir='rtl'] .tox-icon--flip svg { + transform: rotateY(180deg); +} +.tox .accessibility-issue__header { + align-items: center; + display: flex; + margin-bottom: 4px; +} +.tox .accessibility-issue__description { + align-items: stretch; + border: 1px solid #eee; + border-radius: 6px; + display: flex; + justify-content: space-between; +} +.tox .accessibility-issue__description > div { + padding-bottom: 4px; +} +.tox .accessibility-issue__description > div > div { + align-items: center; + display: flex; + margin-bottom: 4px; +} +.tox .accessibility-issue__description > :last-child:not(:only-child) { + border-color: #eee; + border-style: solid; +} +.tox .accessibility-issue__repair { + margin-top: 16px; +} +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { + background-color: rgba(0, 108, 231, 0.1); + border-color: #006ce7; + color: #222f3e; +} +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description > :last-child { + border-color: #006ce7; +} +.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { + color: #006ce7; +} +.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { + fill: #006ce7; +} +.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon { + color: #006ce7; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { + background-color: rgba(255, 165, 0, 0.1); + border-color: rgba(255, 165, 0, 0.5); + color: #222f3e; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description > :last-child { + border-color: rgba(255, 165, 0, 0.5); +} +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { + color: #cc8500; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { + fill: #cc8500; +} +.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon { + color: #cc8500; +} +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { + background-color: rgba(204, 0, 0, 0.1); + border-color: rgba(204, 0, 0, 0.4); + color: #222f3e; +} +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description > :last-child { + border-color: rgba(204, 0, 0, 0.4); +} +.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { + color: #c00; +} +.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { + fill: #c00; +} +.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon { + color: #c00; +} +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { + background-color: rgba(120, 171, 70, 0.1); + border-color: rgba(120, 171, 70, 0.4); + color: #222f3e; +} +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > :last-child { + border-color: rgba(120, 171, 70, 0.4); +} +.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { + color: #78ab46; +} +.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { + fill: #78ab46; +} +.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon { + color: #78ab46; +} +.tox .tox-dialog__body-content .accessibility-issue__header h1, +.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { + margin-top: 0; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header > :nth-last-child(2) { + margin-left: auto; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 4px 4px 8px; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description > :last-child { + border-left-width: 1px; + padding-left: 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header > :nth-last-child(2) { + margin-right: auto; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 8px 4px 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description > :last-child { + border-right-width: 1px; + padding-right: 4px; +} +.tox .tox-anchorbar { + display: flex; + flex: 0 0 auto; +} +.tox .tox-bar { + display: flex; + flex: 0 0 auto; +} +.tox .tox-button { + background-color: #006ce7; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #006ce7; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 14px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + line-height: 24px; + margin: 0; + outline: 0; + padding: 4px 16px; + text-align: center; + text-decoration: none; + text-transform: none; + white-space: nowrap; +} +.tox .tox-button[disabled] { + background-color: #006ce7; + background-image: none; + border-color: #006ce7; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-button:focus:not(:disabled) { + background-color: #0060ce; + background-image: none; + border-color: #0060ce; + box-shadow: none; + color: #fff; +} +.tox .tox-button:hover:not(:disabled) { + background-color: #0060ce; + background-image: none; + border-color: #0060ce; + box-shadow: none; + color: #fff; +} +.tox .tox-button:active:not(:disabled) { + background-color: #0054b4; + background-image: none; + border-color: #0054b4; + box-shadow: none; + color: #fff; +} +.tox .tox-button--secondary { + background-color: #f0f0f0; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #f0f0f0; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + color: #222f3e; + font-size: 14px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + outline: 0; + padding: 4px 16px; + text-decoration: none; + text-transform: none; +} +.tox .tox-button--secondary[disabled] { + background-color: #f0f0f0; + background-image: none; + border-color: #f0f0f0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} +.tox .tox-button--secondary:focus:not(:disabled) { + background-color: #e3e3e3; + background-image: none; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} +.tox .tox-button--secondary:hover:not(:disabled) { + background-color: #e3e3e3; + background-image: none; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} +.tox .tox-button--secondary:active:not(:disabled) { + background-color: #d6d6d6; + background-image: none; + border-color: #d6d6d6; + box-shadow: none; + color: #222f3e; +} +.tox .tox-button--icon, +.tox .tox-button.tox-button--icon, +.tox .tox-button.tox-button--secondary.tox-button--icon { + padding: 4px; +} +.tox .tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { + display: block; + fill: currentColor; +} +.tox .tox-button-link { + background: 0; + border: none; + box-sizing: border-box; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-weight: 400; + line-height: 1.3; + margin: 0; + padding: 0; + white-space: nowrap; +} +.tox .tox-button-link--sm { + font-size: 14px; +} +.tox .tox-button--naked { + background-color: transparent; + border-color: transparent; + box-shadow: unset; + color: #222f3e; +} +.tox .tox-button--naked[disabled] { + background-color: rgba(34, 47, 62, 0.12); + border-color: transparent; + box-shadow: unset; + color: rgba(34, 47, 62, 0.5); +} +.tox .tox-button--naked:hover:not(:disabled) { + background-color: rgba(34, 47, 62, 0.12); + border-color: transparent; + box-shadow: unset; + color: #222f3e; +} +.tox .tox-button--naked:focus:not(:disabled) { + background-color: rgba(34, 47, 62, 0.12); + border-color: transparent; + box-shadow: unset; + color: #222f3e; +} +.tox .tox-button--naked:active:not(:disabled) { + background-color: rgba(34, 47, 62, 0.18); + border-color: transparent; + box-shadow: unset; + color: #222f3e; +} +.tox .tox-button--naked .tox-icon svg { + fill: currentColor; +} +.tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { + color: #222f3e; +} +.tox .tox-checkbox { + align-items: center; + border-radius: 6px; + cursor: pointer; + display: flex; + height: 36px; + min-width: 36px; +} +.tox .tox-checkbox__input { + height: 1px; + overflow: hidden; + position: absolute; + top: auto; + width: 1px; +} +.tox .tox-checkbox__icons { + align-items: center; + border-radius: 6px; + box-shadow: 0 0 0 2px transparent; + box-sizing: content-box; + display: flex; + height: 24px; + justify-content: center; + padding: calc(4px - 1px); + width: 24px; +} +.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: block; + fill: rgba(34, 47, 62, 0.3); +} +.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: none; + fill: #006ce7; +} +.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: none; + fill: #006ce7; +} +.tox .tox-checkbox--disabled { + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: block; +} +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: block; +} +.tox input.tox-checkbox__input:focus + .tox-checkbox__icons { + border-radius: 6px; + box-shadow: inset 0 0 0 1px #006ce7; + padding: calc(4px - 1px); +} +.tox:not([dir='rtl']) .tox-checkbox__label { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-checkbox__input { + left: -10000px; +} +.tox:not([dir='rtl']) .tox-bar .tox-checkbox { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-checkbox__label { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-checkbox__input { + right: -10000px; +} +.tox[dir='rtl'] .tox-bar .tox-checkbox { + margin-right: 4px; +} +.tox .tox-collection--toolbar .tox-collection__group { + display: flex; + padding: 0; +} +.tox .tox-collection--grid .tox-collection__group { + display: flex; + flex-wrap: wrap; + max-height: 208px; + overflow-x: hidden; + overflow-y: auto; + padding: 0; +} +.tox .tox-collection--list .tox-collection__group { + border-bottom-width: 0; + border-color: #e3e3e3; + border-left-width: 0; + border-right-width: 0; + border-style: solid; + border-top-width: 1px; + padding: 4px 0; +} +.tox .tox-collection--list .tox-collection__group:first-child { + border-top-width: 0; +} +.tox .tox-collection__group-heading { + background-color: #fcfcfc; + color: rgba(34, 47, 62, 0.7); + cursor: default; + font-size: 12px; + font-style: normal; + font-weight: 400; + margin-bottom: 4px; + margin-top: -4px; + padding: 4px 8px; + text-transform: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.tox .tox-collection__item { + align-items: center; + border-radius: 3px; + color: #222f3e; + display: flex; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.tox .tox-collection--list .tox-collection__item { + padding: 4px 8px; +} +.tox .tox-collection--toolbar .tox-collection__item { + border-radius: 3px; + padding: 4px; +} +.tox .tox-collection--grid .tox-collection__item { + border-radius: 3px; + padding: 4px; +} +.tox .tox-collection--list .tox-collection__item--enabled { + background-color: #fff; + color: #222f3e; +} +.tox .tox-collection--list .tox-collection__item--active { + background-color: #cce2fa; +} +.tox .tox-collection--toolbar .tox-collection__item--enabled { + background-color: #a6ccf7; + color: #222f3e; +} +.tox .tox-collection--toolbar .tox-collection__item--active { + background-color: #cce2fa; +} +.tox .tox-collection--grid .tox-collection__item--enabled { + background-color: #a6ccf7; + color: #222f3e; +} +.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + background-color: #cce2fa; + color: #222f3e; +} +.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #222f3e; +} +.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #222f3e; +} +.tox .tox-collection__item-checkmark, +.tox .tox-collection__item-icon { + align-items: center; + display: flex; + height: 24px; + justify-content: center; + width: 24px; +} +.tox .tox-collection__item-checkmark svg, +.tox .tox-collection__item-icon svg { + fill: currentColor; +} +.tox .tox-collection--toolbar-lg .tox-collection__item-icon { + height: 48px; + width: 48px; +} +.tox .tox-collection__item-label { + color: currentColor; + display: inline-block; + flex: 1; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 24px; + text-transform: none; + word-break: break-all; +} +.tox .tox-collection__item-accessory { + color: rgba(34, 47, 62, 0.7); + display: inline-block; + font-size: 14px; + height: 24px; + line-height: 24px; + text-transform: none; +} +.tox .tox-collection__item-caret { + align-items: center; + display: flex; + min-height: 24px; +} +.tox .tox-collection__item-caret::after { + content: ''; + font-size: 0; + min-height: inherit; +} +.tox .tox-collection__item-caret svg { + fill: #222f3e; +} +.tox .tox-collection__item--state-disabled { + background-color: transparent; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} +.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox + .tox-collection--list + .tox-collection__item:not(.tox-collection__item--enabled) + .tox-collection__item-checkmark + svg { + display: none; +} +.tox + .tox-collection--list + .tox-collection__item:not(.tox-collection__item--enabled) + .tox-collection__item-accessory + + .tox-collection__item-checkmark { + display: none; +} +.tox .tox-collection--horizontal { + background-color: #fff; + border: 1px solid #e3e3e3; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: nowrap; + margin-bottom: 0; + overflow-x: auto; + padding: 0; +} +.tox .tox-collection--horizontal .tox-collection__group { + align-items: center; + display: flex; + flex-wrap: nowrap; + margin: 0; + padding: 0 4px; +} +.tox .tox-collection--horizontal .tox-collection__item { + height: 28px; + margin: 6px 1px 5px 0; + padding: 0 4px; +} +.tox .tox-collection--horizontal .tox-collection__item-label { + white-space: nowrap; +} +.tox .tox-collection--horizontal .tox-collection__item-caret { + margin-left: 4px; +} +.tox .tox-collection__item-container { + display: flex; +} +.tox .tox-collection__item-container--row { + align-items: center; + flex: 1 1 auto; + flex-direction: row; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--align-left { + margin-right: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--align-right { + justify-content: flex-end; + margin-left: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { + align-items: flex-start; + margin-bottom: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { + align-items: center; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { + align-items: flex-end; + margin-top: auto; +} +.tox .tox-collection__item-container--column { + align-self: center; + flex: 1 1 auto; + flex-direction: column; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--align-left { + align-items: flex-start; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--align-right { + align-items: flex-end; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { + align-self: flex-start; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { + align-self: center; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { + align-self: flex-end; +} +.tox:not([dir='rtl']) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-right: 1px solid transparent; +} +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > :not(:first-child) { + margin-left: 8px; +} +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-collection__item-accessory { + margin-left: 16px; + text-align: right; +} +.tox:not([dir='rtl']) .tox-collection .tox-collection__item-caret { + margin-left: 16px; +} +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-left: 1px solid transparent; +} +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > :not(:first-child) { + margin-right: 8px; +} +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-collection__item-accessory { + margin-right: 16px; + text-align: left; +} +.tox[dir='rtl'] .tox-collection .tox-collection__item-caret { + margin-right: 16px; + transform: rotateY(180deg); +} +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__item-caret { + margin-right: 4px; +} +.tox .tox-color-picker-container { + display: flex; + flex-direction: row; + height: 225px; + margin: 0; +} +.tox .tox-sv-palette { + box-sizing: border-box; + display: flex; + height: 100%; +} +.tox .tox-sv-palette-spectrum { + height: 100%; +} +.tox .tox-sv-palette, +.tox .tox-sv-palette-spectrum { + width: 225px; +} +.tox .tox-sv-palette-thumb { + background: 0 0; + border: 1px solid #000; + border-radius: 50%; + box-sizing: content-box; + height: 12px; + position: absolute; + width: 12px; +} +.tox .tox-sv-palette-inner-thumb { + border: 1px solid #fff; + border-radius: 50%; + height: 10px; + position: absolute; + width: 10px; +} +.tox .tox-hue-slider { + box-sizing: border-box; + height: 100%; + width: 25px; +} +.tox .tox-hue-slider-spectrum { + background: linear-gradient( + to bottom, + red, + #ff0080, + #f0f, + #8000ff, + #00f, + #0080ff, + #0ff, + #00ff80, + #0f0, + #80ff00, + #ff0, + #ff8000, + red + ); + height: 100%; + width: 100%; +} +.tox .tox-hue-slider, +.tox .tox-hue-slider-spectrum { + width: 20px; +} +.tox .tox-hue-slider-thumb { + background: #fff; + border: 1px solid #000; + box-sizing: content-box; + height: 4px; + width: 100%; +} +.tox .tox-rgb-form { + display: flex; + flex-direction: column; + justify-content: space-between; +} +.tox .tox-rgb-form div { + align-items: center; + display: flex; + justify-content: space-between; + margin-bottom: 5px; + width: inherit; +} +.tox .tox-rgb-form input { + width: 6em; +} +.tox .tox-rgb-form input.tox-invalid { + border: 1px solid red !important; +} +.tox .tox-rgb-form .tox-rgba-preview { + border: 1px solid #000; + flex-grow: 2; + margin-bottom: 0; +} +.tox:not([dir='rtl']) .tox-sv-palette { + margin-right: 15px; +} +.tox:not([dir='rtl']) .tox-hue-slider { + margin-right: 15px; +} +.tox:not([dir='rtl']) .tox-hue-slider-thumb { + margin-left: -1px; +} +.tox:not([dir='rtl']) .tox-rgb-form label { + margin-right: 0.5em; +} +.tox[dir='rtl'] .tox-sv-palette { + margin-left: 15px; +} +.tox[dir='rtl'] .tox-hue-slider { + margin-left: 15px; +} +.tox[dir='rtl'] .tox-hue-slider-thumb { + margin-right: -1px; +} +.tox[dir='rtl'] .tox-rgb-form label { + margin-left: 0.5em; +} +.tox .tox-toolbar .tox-swatches, +.tox .tox-toolbar__overflow .tox-swatches, +.tox .tox-toolbar__primary .tox-swatches { + margin: 5px 0 6px 11px; +} +.tox .tox-collection--list .tox-collection__group .tox-swatches-menu { + border: 0; + margin: -4px -4px; +} +.tox .tox-swatches__row { + display: flex; +} +.tox .tox-swatch { + height: 30px; + transition: transform 0.15s, box-shadow 0.15s; + width: 30px; +} +.tox .tox-swatch:focus, +.tox .tox-swatch:hover { + box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; + transform: scale(0.8); +} +.tox .tox-swatch--remove { + align-items: center; + display: flex; + justify-content: center; +} +.tox .tox-swatch--remove svg path { + stroke: #e74c3c; +} +.tox .tox-swatches__picker-btn { + align-items: center; + background-color: transparent; + border: 0; + cursor: pointer; + display: flex; + height: 30px; + justify-content: center; + outline: 0; + padding: 0; + width: 30px; +} +.tox .tox-swatches__picker-btn svg { + fill: #222f3e; + height: 24px; + width: 24px; +} +.tox .tox-swatches__picker-btn:hover { + background: #cce2fa; +} +.tox:not([dir='rtl']) .tox-swatches__picker-btn { + margin-left: auto; +} +.tox[dir='rtl'] .tox-swatches__picker-btn { + margin-right: auto; +} +.tox .tox-comment-thread { + background: #fff; + position: relative; +} +.tox .tox-comment-thread > :not(:first-child) { + margin-top: 8px; +} +.tox .tox-comment { + background: #fff; + border: 1px solid #eee; + border-radius: 6px; + box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); + padding: 8px 8px 16px 8px; + position: relative; +} +.tox .tox-comment__header { + align-items: center; + color: #222f3e; + display: flex; + justify-content: space-between; +} +.tox .tox-comment__date { + color: rgba(34, 47, 62, 0.7); + font-size: 12px; +} +.tox .tox-comment__body { + color: #222f3e; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + margin-top: 8px; + position: relative; + text-transform: initial; +} +.tox .tox-comment__body textarea { + resize: none; + white-space: normal; + width: 100%; +} +.tox .tox-comment__expander { + padding-top: 8px; +} +.tox .tox-comment__expander p { + color: rgba(34, 47, 62, 0.7); + font-size: 14px; + font-style: normal; +} +.tox .tox-comment__body p { + margin: 0; +} +.tox .tox-comment__buttonspacing { + padding-top: 16px; + text-align: center; +} +.tox .tox-comment-thread__overlay::after { + background: #fff; + bottom: 0; + content: ''; + display: flex; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + top: 0; + z-index: 5; +} +.tox .tox-comment__reply { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 8px; +} +.tox .tox-comment__reply > :first-child { + margin-bottom: 8px; + width: 100%; +} +.tox .tox-comment__edit { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 16px; +} +.tox .tox-comment__gradient::after { + background: linear-gradient(rgba(255, 255, 255, 0), #fff); + bottom: 0; + content: ''; + display: block; + height: 5em; + margin-top: -40px; + position: absolute; + width: 100%; +} +.tox .tox-comment__overlay { + background: #fff; + bottom: 0; + display: flex; + flex-direction: column; + flex-grow: 1; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + text-align: center; + top: 0; + z-index: 5; +} +.tox .tox-comment__loading-text { + align-items: center; + color: #222f3e; + display: flex; + flex-direction: column; + position: relative; +} +.tox .tox-comment__loading-text > div { + padding-bottom: 16px; +} +.tox .tox-comment__overlaytext { + bottom: 0; + flex-direction: column; + font-size: 14px; + left: 0; + padding: 1em; + position: absolute; + right: 0; + top: 0; + z-index: 10; +} +.tox .tox-comment__overlaytext p { + background-color: #fff; + box-shadow: 0 0 8px 8px #fff; + color: #222f3e; + text-align: center; +} +.tox .tox-comment__overlaytext div:nth-of-type(2) { + font-size: 0.8em; +} +.tox .tox-comment__busy-spinner { + align-items: center; + background-color: #fff; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 20; +} +.tox .tox-comment__scroll { + display: flex; + flex-direction: column; + flex-shrink: 1; + overflow: auto; +} +.tox .tox-conversations { + margin: 8px; +} +.tox:not([dir='rtl']) .tox-comment__edit { + margin-left: 8px; +} +.tox:not([dir='rtl']) .tox-comment__buttonspacing > :last-child, +.tox:not([dir='rtl']) .tox-comment__edit > :last-child, +.tox:not([dir='rtl']) .tox-comment__reply > :last-child { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-comment__edit { + margin-right: 8px; +} +.tox[dir='rtl'] .tox-comment__buttonspacing > :last-child, +.tox[dir='rtl'] .tox-comment__edit > :last-child, +.tox[dir='rtl'] .tox-comment__reply > :last-child { + margin-right: 8px; +} +.tox .tox-user { + align-items: center; + display: flex; +} +.tox .tox-user__avatar svg { + fill: rgba(34, 47, 62, 0.7); +} +.tox .tox-user__name { + color: rgba(34, 47, 62, 0.7); + font-size: 12px; + font-style: normal; + font-weight: 700; + text-transform: uppercase; +} +.tox:not([dir='rtl']) .tox-user__avatar svg { + margin-right: 8px; +} +.tox:not([dir='rtl']) .tox-user__avatar + .tox-user__name { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-user__avatar svg { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-user__avatar + .tox-user__name { + margin-right: 8px; +} +.tox .tox-dialog-wrap { + align-items: center; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 1100; +} +.tox .tox-dialog-wrap__backdrop { + background-color: rgba(255, 255, 255, 0.75); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} +.tox .tox-dialog-wrap__backdrop--opaque { + background-color: #fff; +} +.tox .tox-dialog { + background-color: #fff; + border-color: #eee; + border-radius: 10px; + border-style: solid; + border-width: 0; + box-shadow: 0 16px 16px -10px rgba(34, 47, 62, 0.15), 0 0 40px 1px rgba(34, 47, 62, 0.15); + display: flex; + flex-direction: column; + max-height: 100%; + max-width: 480px; + overflow: hidden; + position: relative; + width: 95vw; + z-index: 2; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog { + align-self: flex-start; + margin: 8px auto; + width: calc(100vw - 16px); + } +} +.tox .tox-dialog-inline { + z-index: 1100; +} +.tox .tox-dialog__header { + align-items: center; + background-color: #fff; + border-bottom: none; + color: #222f3e; + display: flex; + font-size: 16px; + justify-content: space-between; + padding: 8px 16px 0 16px; + position: relative; +} +.tox .tox-dialog__header .tox-button { + z-index: 1; +} +.tox .tox-dialog__draghandle { + cursor: grab; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tox .tox-dialog__draghandle:active { + cursor: grabbing; +} +.tox .tox-dialog__dismiss { + margin-left: auto; +} +.tox .tox-dialog__title { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 20px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + margin: 0; + text-transform: none; +} +.tox .tox-dialog__body { + color: #222f3e; + display: flex; + flex: 1; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + min-width: 0; + text-align: left; + text-transform: none; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body { + flex-direction: column; + } +} +.tox .tox-dialog__body-nav { + align-items: flex-start; + display: flex; + flex-direction: column; + padding: 16px 16px; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { + flex-direction: row; + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding-bottom: 0; + } +} +.tox .tox-dialog__body-nav-item { + border-bottom: 2px solid transparent; + color: rgba(34, 47, 62, 0.7); + display: inline-block; + font-size: 14px; + line-height: 1.3; + margin-bottom: 8px; + text-decoration: none; + white-space: nowrap; +} +.tox .tox-dialog__body-nav-item:focus { + background-color: rgba(0, 108, 231, 0.1); +} +.tox .tox-dialog__body-nav-item--active { + border-bottom: 2px solid #006ce7; + color: #006ce7; +} +.tox .tox-dialog__body-content { + box-sizing: border-box; + display: flex; + flex: 1; + flex-direction: column; + max-height: 650px; + overflow: auto; + -webkit-overflow-scrolling: touch; + padding: 16px 16px; +} +.tox .tox-dialog__body-content > * { + margin-bottom: 0; + margin-top: 16px; +} +.tox .tox-dialog__body-content > :first-child { + margin-top: 0; +} +.tox .tox-dialog__body-content > :last-child { + margin-bottom: 0; +} +.tox .tox-dialog__body-content > :only-child { + margin-bottom: 0; + margin-top: 0; +} +.tox .tox-dialog__body-content a { + color: #006ce7; + cursor: pointer; + text-decoration: none; +} +.tox .tox-dialog__body-content a:focus, +.tox .tox-dialog__body-content a:hover { + color: #0054b4; + text-decoration: none; +} +.tox .tox-dialog__body-content a:active { + color: #0054b4; + text-decoration: none; +} +.tox .tox-dialog__body-content svg { + fill: #222f3e; +} +.tox .tox-dialog__body-content ul { + display: block; + list-style-type: disc; + margin-bottom: 16px; + margin-inline-end: 0; + margin-inline-start: 0; + padding-inline-start: 2.5rem; +} +.tox .tox-dialog__body-content .tox-form__group h1 { + color: #222f3e; + font-size: 20px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} +.tox .tox-dialog__body-content .tox-form__group h2 { + color: #222f3e; + font-size: 16px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} +.tox .tox-dialog__body-content .tox-form__group p { + margin-bottom: 16px; +} +.tox .tox-dialog__body-content .tox-form__group h1:first-child, +.tox .tox-dialog__body-content .tox-form__group h2:first-child, +.tox .tox-dialog__body-content .tox-form__group p:first-child { + margin-top: 0; +} +.tox .tox-dialog__body-content .tox-form__group h1:last-child, +.tox .tox-dialog__body-content .tox-form__group h2:last-child, +.tox .tox-dialog__body-content .tox-form__group p:last-child { + margin-bottom: 0; +} +.tox .tox-dialog__body-content .tox-form__group h1:only-child, +.tox .tox-dialog__body-content .tox-form__group h2:only-child, +.tox .tox-dialog__body-content .tox-form__group p:only-child { + margin-bottom: 0; + margin-top: 0; +} +.tox .tox-dialog--width-lg { + height: 650px; + max-width: 1200px; +} +.tox .tox-dialog--width-md { + max-width: 800px; +} +.tox .tox-dialog--width-md .tox-dialog__body-content { + overflow: auto; +} +.tox .tox-dialog__body-content--centered { + text-align: center; +} +.tox .tox-dialog__footer { + align-items: center; + background-color: #fff; + border-top: none; + display: flex; + justify-content: space-between; + padding: 8px 16px; +} +.tox .tox-dialog__footer-end, +.tox .tox-dialog__footer-start { + display: flex; +} +.tox .tox-dialog__busy-spinner { + align-items: center; + background-color: rgba(255, 255, 255, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 3; +} +.tox .tox-dialog__table { + border-collapse: collapse; + width: 100%; +} +.tox .tox-dialog__table thead th { + font-weight: 700; + padding-bottom: 8px; +} +.tox .tox-dialog__table tbody tr { + border-bottom: 1px solid #eee; +} +.tox .tox-dialog__table tbody tr:last-child { + border-bottom: none; +} +.tox .tox-dialog__table td { + padding-bottom: 8px; + padding-top: 8px; +} +.tox .tox-dialog__popups { + position: absolute; + width: 100%; + z-index: 1100; +} +.tox .tox-dialog__body-iframe { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-dialog__body-iframe .tox-navobj { + display: flex; + flex: 1; +} +.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} +.tox .tox-dialog-dock-fadeout { + opacity: 0; + visibility: hidden; +} +.tox .tox-dialog-dock-fadein { + opacity: 1; + visibility: visible; +} +.tox .tox-dialog-dock-transition { + transition: visibility 0s linear 0.3s, opacity 0.3s ease; +} +.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { + transition-delay: 0s; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav { + margin-right: 0; + } +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav-item:not(:first-child) { + margin-left: 8px; + } +} +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-end > *, +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-start > * { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-dialog__body { + text-align: right; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav { + margin-left: 0; + } +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav-item:not(:first-child) { + margin-right: 8px; + } +} +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-end > *, +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-start > * { + margin-right: 8px; +} +body.tox-dialog__disable-scroll { + overflow: hidden; +} +.tox .tox-dropzone-container { + display: flex; + flex: 1; +} +.tox .tox-dropzone { + align-items: center; + background: #fff; + border: 2px dashed #eee; + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-grow: 1; + justify-content: center; + min-height: 100px; + padding: 10px; +} +.tox .tox-dropzone p { + color: rgba(34, 47, 62, 0.7); + margin: 0 0 16px 0; +} +.tox .tox-edit-area { + display: flex; + flex: 1; + overflow: hidden; + position: relative; +} +.tox .tox-edit-area__iframe { + background-color: #fff; + border: 0; + box-sizing: border-box; + flex: 1; + height: 100%; + position: absolute; + width: 100%; +} +.tox.tox-inline-edit-area { + border: 1px dotted #eee; +} +.tox .tox-editor-container { + display: flex; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} +.tox .tox-editor-header { + z-index: 1; +} +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: #fff; + border-bottom: none; + box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.1), 0 8px 8px -4px rgba(34, 47, 62, 0.07); + padding: 4px 0; + transition: box-shadow 0.5s; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: 1px solid #e3e3e3; + box-shadow: none; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: #fff; + box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.2), 0 8px 8px -4px rgba(34, 47, 62, 0.15); + padding: 4px 0; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: 0 2px 2px -2px rgba(34, 47, 62, 0.2), 0 8px 8px -4px rgba(34, 47, 62, 0.15); +} +.tox-editor-dock-fadeout { + opacity: 0; + visibility: hidden; +} +.tox-editor-dock-fadein { + opacity: 1; + visibility: visible; +} +.tox-editor-dock-transition { + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} +.tox-editor-dock-transition.tox-editor-dock-fadein { + transition-delay: 0s; +} +.tox .tox-control-wrap { + flex: 1; + position: relative; +} +.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, +.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, +.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { + display: none; +} +.tox .tox-control-wrap svg { + display: block; +} +.tox .tox-control-wrap__status-icon-wrap { + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-control-wrap__status-icon-invalid svg { + fill: #c00; +} +.tox .tox-control-wrap__status-icon-unknown svg { + fill: orange; +} +.tox .tox-control-wrap__status-icon-valid svg { + fill: green; +} +.tox:not([dir='rtl']) .tox-control-wrap--status-invalid .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-unknown .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-valid .tox-textfield { + padding-right: 32px; +} +.tox:not([dir='rtl']) .tox-control-wrap__status-icon-wrap { + right: 4px; +} +.tox[dir='rtl'] .tox-control-wrap--status-invalid .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-unknown .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-valid .tox-textfield { + padding-left: 32px; +} +.tox[dir='rtl'] .tox-control-wrap__status-icon-wrap { + left: 4px; +} +.tox .tox-autocompleter { + max-width: 25em; +} +.tox .tox-autocompleter .tox-menu { + border-color: #eee; + box-shadow: none; + max-width: 25em; +} +.tox .tox-autocompleter .tox-autocompleter-highlight { + font-weight: 700; +} +.tox .tox-color-input { + display: flex; + position: relative; + z-index: 1; +} +.tox .tox-color-input .tox-textfield { + z-index: -1; +} +.tox .tox-color-input span { + border-color: rgba(34, 47, 62, 0.2); + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + height: 24px; + position: absolute; + top: 6px; + width: 24px; +} +.tox .tox-color-input span:focus:not([aria-disabled='true']), +.tox .tox-color-input span:hover:not([aria-disabled='true']) { + border-color: #006ce7; + cursor: pointer; +} +.tox .tox-color-input span::before { + background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), + linear-gradient(-45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%), + linear-gradient(-45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%); + background-position: 0 0, 0 6px, 6px -6px, -6px 0; + background-size: 12px 12px; + border: 1px solid #fff; + border-radius: 6px; + box-sizing: border-box; + content: ''; + height: 24px; + left: -1px; + position: absolute; + top: -1px; + width: 24px; + z-index: -1; +} +.tox .tox-color-input span[aria-disabled='true'] { + cursor: not-allowed; +} +.tox:not([dir='rtl']) .tox-color-input .tox-textfield { + padding-left: 36px; +} +.tox:not([dir='rtl']) .tox-color-input span { + left: 6px; +} +.tox[dir='rtl'] .tox-color-input .tox-textfield { + padding-right: 36px; +} +.tox[dir='rtl'] .tox-color-input span { + right: 6px; +} +.tox .tox-label, +.tox .tox-toolbar-label { + color: rgba(34, 47, 62, 0.7); + display: block; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + padding: 0 8px 0 0; + text-transform: none; + white-space: nowrap; +} +.tox .tox-toolbar-label { + padding: 0 8px; +} +.tox[dir='rtl'] .tox-label { + padding: 0 0 0 8px; +} +.tox .tox-form { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-form__group { + box-sizing: border-box; + margin-bottom: 4px; +} +.tox .tox-form-group--maximize { + flex: 1; +} +.tox .tox-form__group--error { + color: #c00; +} +.tox .tox-form__group--collection { + display: flex; +} +.tox .tox-form__grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} +.tox .tox-form__grid--2col > .tox-form__group { + width: calc(50% - (8px / 2)); +} +.tox .tox-form__grid--3col > .tox-form__group { + width: calc(100% / 3 - (8px / 2)); +} +.tox .tox-form__grid--4col > .tox-form__group { + width: calc(25% - (8px / 2)); +} +.tox .tox-form__controls-h-stack { + align-items: center; + display: flex; +} +.tox .tox-form__group--inline { + align-items: center; + display: flex; +} +.tox .tox-form__group--stretched { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-form__group--stretched .tox-textarea { + flex: 1; +} +.tox .tox-form__group--stretched .tox-navobj { + display: flex; + flex: 1; +} +.tox .tox-form__group--stretched .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} +.tox:not([dir='rtl']) .tox-form__controls-h-stack > :not(:first-child) { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-form__controls-h-stack > :not(:first-child) { + margin-right: 4px; +} +.tox .tox-lock.tox-locked .tox-lock-icon__unlock, +.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { + display: none; +} +.tox .tox-listboxfield .tox-listbox--select, +.tox .tox-textarea, +.tox .tox-textfield, +.tox .tox-toolbar-textfield { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #eee; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #222f3e; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: 0; + padding: 5px 5.5px; + resize: none; + width: 100%; +} +.tox .tox-textarea[disabled], +.tox .tox-textfield[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} +.tox .tox-listboxfield .tox-listbox--select:focus, +.tox .tox-textarea:focus, +.tox .tox-textfield:focus { + background-color: #fff; + border-color: #006ce7; + box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); + outline: 0; +} +.tox .tox-toolbar-textfield { + border-width: 0; + margin-bottom: 3px; + margin-top: 2px; + max-width: 250px; +} +.tox .tox-naked-btn { + background-color: transparent; + border: 0; + border-color: transparent; + box-shadow: unset; + color: #006ce7; + cursor: pointer; + display: block; + margin: 0; + padding: 0; +} +.tox .tox-naked-btn svg { + display: block; + fill: #222f3e; +} +.tox:not([dir='rtl']) .tox-toolbar-textfield + * { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-toolbar-textfield + * { + margin-right: 4px; +} +.tox .tox-listboxfield { + cursor: pointer; + position: relative; +} +.tox .tox-listboxfield .tox-listbox--select[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} +.tox .tox-listbox__select-label { + cursor: default; + flex: 1; + margin: 0 4px; +} +.tox .tox-listbox__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} +.tox .tox-listbox__select-chevron svg { + fill: #222f3e; +} +.tox .tox-listboxfield .tox-listbox--select { + align-items: center; + display: flex; +} +.tox:not([dir='rtl']) .tox-listboxfield svg { + right: 8px; +} +.tox[dir='rtl'] .tox-listboxfield svg { + left: 8px; +} +.tox .tox-selectfield { + cursor: pointer; + position: relative; +} +.tox .tox-selectfield select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #eee; + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #222f3e; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: 0; + padding: 5px 5.5px; + resize: none; + width: 100%; +} +.tox .tox-selectfield select[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} +.tox .tox-selectfield select::-ms-expand { + display: none; +} +.tox .tox-selectfield select:focus { + background-color: #fff; + border-color: #006ce7; + box-shadow: 0 0 0 2px rgba(0, 108, 231, 0.25); + outline: 0; +} +.tox .tox-selectfield svg { + pointer-events: none; + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox:not([dir='rtl']) .tox-selectfield select[size='0'], +.tox:not([dir='rtl']) .tox-selectfield select[size='1'] { + padding-right: 24px; +} +.tox:not([dir='rtl']) .tox-selectfield svg { + right: 8px; +} +.tox[dir='rtl'] .tox-selectfield select[size='0'], +.tox[dir='rtl'] .tox-selectfield select[size='1'] { + padding-left: 24px; +} +.tox[dir='rtl'] .tox-selectfield svg { + left: 8px; +} +.tox .tox-textarea { + -webkit-appearance: textarea; + -moz-appearance: textarea; + appearance: textarea; + white-space: pre-wrap; +} +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} +.tox-shadowhost.tox-fullscreen, +.tox.tox-tinymce.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} +.tox .tox-help__more-link { + list-style: none; + margin-top: 1em; +} +.tox .tox-imagepreview { + background-color: #666; + height: 380px; + overflow: hidden; + position: relative; + width: 100%; +} +.tox .tox-imagepreview.tox-imagepreview__loaded { + overflow: auto; +} +.tox .tox-imagepreview__container { + display: flex; + left: 100vw; + position: absolute; + top: 100vw; +} +.tox .tox-imagepreview__image { + background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); +} +.tox .tox-image-tools .tox-spacer { + flex: 1; +} +.tox .tox-image-tools .tox-bar { + align-items: center; + display: flex; + height: 60px; + justify-content: center; +} +.tox .tox-image-tools .tox-imagepreview, +.tox .tox-image-tools .tox-imagepreview + .tox-bar { + margin-top: 8px; +} +.tox .tox-image-tools .tox-croprect-block { + background: #000; + opacity: 0.5; + position: absolute; + zoom: 1; +} +.tox .tox-image-tools .tox-croprect-handle { + border: 2px solid #fff; + height: 20px; + left: 0; + position: absolute; + top: 0; + width: 20px; +} +.tox .tox-image-tools .tox-croprect-handle-move { + border: 0; + cursor: move; + position: absolute; +} +.tox .tox-image-tools .tox-croprect-handle-nw { + border-width: 2px 0 0 2px; + cursor: nw-resize; + left: 100px; + margin: -2px 0 0 -2px; + top: 100px; +} +.tox .tox-image-tools .tox-croprect-handle-ne { + border-width: 2px 2px 0 0; + cursor: ne-resize; + left: 200px; + margin: -2px 0 0 -20px; + top: 100px; +} +.tox .tox-image-tools .tox-croprect-handle-sw { + border-width: 0 0 2px 2px; + cursor: sw-resize; + left: 100px; + margin: -20px 2px 0 -2px; + top: 200px; +} +.tox .tox-image-tools .tox-croprect-handle-se { + border-width: 0 2px 2px 0; + cursor: se-resize; + left: 200px; + margin: -20px 0 0 -20px; + top: 200px; +} +.tox .tox-insert-table-picker { + display: flex; + flex-wrap: wrap; + width: 170px; +} +.tox .tox-insert-table-picker > div { + border-color: #eee; + border-style: solid; + border-width: 0 1px 1px 0; + box-sizing: border-box; + height: 17px; + width: 17px; +} +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: -4px -4px; +} +.tox .tox-insert-table-picker .tox-insert-table-picker__selected { + background-color: rgba(0, 108, 231, 0.5); + border-color: rgba(0, 108, 231, 0.5); +} +.tox .tox-insert-table-picker__label { + color: rgba(34, 47, 62, 0.7); + display: block; + font-size: 14px; + padding: 4px; + text-align: center; + width: 100%; +} +.tox:not([dir='rtl']) .tox-insert-table-picker > div:nth-child(10n) { + border-right: 0; +} +.tox[dir='rtl'] .tox-insert-table-picker > div:nth-child(10n + 1) { + border-right: 0; +} +.tox .tox-menu { + background-color: #fff; + border: 1px solid transparent; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + display: inline-block; + overflow: hidden; + vertical-align: top; + z-index: 1150; +} +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0 4px; +} +.tox .tox-menu.tox-collection.tox-collection--toolbar { + padding: 8px; +} +.tox .tox-menu.tox-collection.tox-collection--grid { + padding: 8px; +} +.tox .tox-menu__label blockquote, +.tox .tox-menu__label code, +.tox .tox-menu__label h1, +.tox .tox-menu__label h2, +.tox .tox-menu__label h3, +.tox .tox-menu__label h4, +.tox .tox-menu__label h5, +.tox .tox-menu__label h6, +.tox .tox-menu__label p { + margin: 0; +} +.tox .tox-menubar { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='transparent'/%3E%3C/svg%3E") + left 0 top 0 #fff; + background-color: #fff; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 11px 0 12px; +} +.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { + border-top: 1px solid transparent; +} +.tox .tox-mbtn { + align-items: center; + background: 0 0; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #222f3e; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: 400; + height: 28px; + justify-content: center; + margin: 5px 1px 6px 0; + outline: 0; + overflow: hidden; + padding: 0 4px; + text-transform: none; + width: auto; +} +.tox .tox-mbtn[disabled] { + background-color: transparent; + border: 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} +.tox .tox-mbtn:focus:not(:disabled) { + background: #cce2fa; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-mbtn--active { + background: #a6ccf7; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { + background: #cce2fa; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-mbtn__select-label { + cursor: default; + font-weight: 400; + margin: 0 4px; +} +.tox .tox-mbtn[disabled] .tox-mbtn__select-label { + cursor: not-allowed; +} +.tox .tox-mbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; + display: none; +} +.tox .tox-notification { + border-radius: 6px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + display: grid; + font-size: 14px; + font-weight: 400; + grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + margin-top: 4px; + opacity: 0; + padding: 4px; + transition: transform 0.1s ease-in, opacity 150ms ease-in; +} +.tox .tox-notification p { + font-size: 14px; + font-weight: 400; +} +.tox .tox-notification a { + cursor: pointer; + text-decoration: underline; +} +.tox .tox-notification--in { + opacity: 1; +} +.tox .tox-notification--success { + background-color: #e4eeda; + border-color: #d7e6c8; + color: #222f3e; +} +.tox .tox-notification--success p { + color: #222f3e; +} +.tox .tox-notification--success a { + color: #517342; +} +.tox .tox-notification--success svg { + fill: #222f3e; +} +.tox .tox-notification--error { + background-color: #f5cccc; + border-color: #f0b3b3; + color: #222f3e; +} +.tox .tox-notification--error p { + color: #222f3e; +} +.tox .tox-notification--error a { + color: #77181f; +} +.tox .tox-notification--error svg { + fill: #222f3e; +} +.tox .tox-notification--warn, +.tox .tox-notification--warning { + background-color: #fff5cc; + border-color: #fff0b3; + color: #222f3e; +} +.tox .tox-notification--warn p, +.tox .tox-notification--warning p { + color: #222f3e; +} +.tox .tox-notification--warn a, +.tox .tox-notification--warning a { + color: #7a6e25; +} +.tox .tox-notification--warn svg, +.tox .tox-notification--warning svg { + fill: #222f3e; +} +.tox .tox-notification--info { + background-color: #d6e7fb; + border-color: #c1dbf9; + color: #222f3e; +} +.tox .tox-notification--info p { + color: #222f3e; +} +.tox .tox-notification--info a { + color: #2a64a6; +} +.tox .tox-notification--info svg { + fill: #222f3e; +} +.tox .tox-notification__body { + align-self: center; + color: #222f3e; + font-size: 14px; + grid-column-end: 3; + grid-column-start: 2; + grid-row-end: 2; + grid-row-start: 1; + text-align: center; + white-space: normal; + word-break: break-all; + word-break: break-word; +} +.tox .tox-notification__body > * { + margin: 0; +} +.tox .tox-notification__body > * + * { + margin-top: 1rem; +} +.tox .tox-notification__icon { + align-self: center; + grid-column-end: 2; + grid-column-start: 1; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} +.tox .tox-notification__icon svg { + display: block; +} +.tox .tox-notification__dismiss { + align-self: start; + grid-column-end: 4; + grid-column-start: 3; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} +.tox .tox-notification .tox-progress-bar { + grid-column-end: 4; + grid-column-start: 1; + grid-row-end: 3; + grid-row-start: 2; + justify-self: center; +} +.tox .tox-pop { + display: inline-block; + position: relative; +} +.tox .tox-pop--resizing { + transition: width 0.1s ease; +} +.tox .tox-pop--resizing .tox-toolbar, +.tox .tox-pop--resizing .tox-toolbar__group { + flex-wrap: nowrap; +} +.tox .tox-pop--transition { + transition: 0.15s ease; + transition-property: left, right, top, bottom; +} +.tox .tox-pop--transition::after, +.tox .tox-pop--transition::before { + transition: all 0.15s, visibility 0s, opacity 75ms ease 75ms; +} +.tox .tox-pop__dialog { + background-color: #fff; + border: 1px solid #eee; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + min-width: 0; + overflow: hidden; +} +.tox .tox-pop__dialog > :not(.tox-toolbar) { + margin: 4px 4px 4px 8px; +} +.tox .tox-pop__dialog .tox-toolbar { + background-color: transparent; + margin-bottom: -1px; +} +.tox .tox-pop::after, +.tox .tox-pop::before { + border-style: solid; + content: ''; + display: block; + height: 0; + opacity: 1; + position: absolute; + width: 0; +} +.tox .tox-pop.tox-pop--inset::after, +.tox .tox-pop.tox-pop--inset::before { + opacity: 0; + transition: all 0s 0.15s, visibility 0s, opacity 75ms ease; +} +.tox .tox-pop.tox-pop--bottom::after, +.tox .tox-pop.tox-pop--bottom::before { + left: 50%; + top: 100%; +} +.tox .tox-pop.tox-pop--bottom::after { + border-color: #fff transparent transparent transparent; + border-width: 8px; + margin-left: -8px; + margin-top: -1px; +} +.tox .tox-pop.tox-pop--bottom::before { + border-color: #eee transparent transparent transparent; + border-width: 9px; + margin-left: -9px; +} +.tox .tox-pop.tox-pop--top::after, +.tox .tox-pop.tox-pop--top::before { + left: 50%; + top: 0; + transform: translateY(-100%); +} +.tox .tox-pop.tox-pop--top::after { + border-color: transparent transparent #fff transparent; + border-width: 8px; + margin-left: -8px; + margin-top: 1px; +} +.tox .tox-pop.tox-pop--top::before { + border-color: transparent transparent #eee transparent; + border-width: 9px; + margin-left: -9px; +} +.tox .tox-pop.tox-pop--left::after, +.tox .tox-pop.tox-pop--left::before { + left: 0; + top: calc(50% - 1px); + transform: translateY(-50%); +} +.tox .tox-pop.tox-pop--left::after { + border-color: transparent #fff transparent transparent; + border-width: 8px; + margin-left: -15px; +} +.tox .tox-pop.tox-pop--left::before { + border-color: transparent #eee transparent transparent; + border-width: 10px; + margin-left: -19px; +} +.tox .tox-pop.tox-pop--right::after, +.tox .tox-pop.tox-pop--right::before { + left: 100%; + top: calc(50% + 1px); + transform: translateY(-50%); +} +.tox .tox-pop.tox-pop--right::after { + border-color: transparent transparent transparent #fff; + border-width: 8px; + margin-left: -1px; +} +.tox .tox-pop.tox-pop--right::before { + border-color: transparent transparent transparent #eee; + border-width: 10px; + margin-left: -1px; +} +.tox .tox-pop.tox-pop--align-left::after, +.tox .tox-pop.tox-pop--align-left::before { + left: 20px; +} +.tox .tox-pop.tox-pop--align-right::after, +.tox .tox-pop.tox-pop--align-right::before { + left: calc(100% - 20px); +} +.tox .tox-sidebar-wrap { + display: flex; + flex-direction: row; + flex-grow: 1; + min-height: 0; +} +.tox .tox-sidebar { + background-color: #fff; + display: flex; + flex-direction: row; + justify-content: flex-end; +} +.tox .tox-sidebar__slider { + display: flex; + overflow: hidden; +} +.tox .tox-sidebar__pane-container { + display: flex; +} +.tox .tox-sidebar__pane { + display: flex; +} +.tox .tox-sidebar--sliding-closed { + opacity: 0; +} +.tox .tox-sidebar--sliding-open { + opacity: 1; +} +.tox .tox-sidebar--sliding-growing, +.tox .tox-sidebar--sliding-shrinking { + transition: width 0.5s ease, opacity 0.5s ease; +} +.tox .tox-selector { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + display: inline-block; + height: 10px; + position: absolute; + width: 10px; +} +.tox.tox-platform-touch .tox-selector { + height: 12px; + width: 12px; +} +.tox .tox-slider { + align-items: center; + display: flex; + flex: 1; + height: 24px; + justify-content: center; + position: relative; +} +.tox .tox-slider__rail { + background-color: transparent; + border: 1px solid #eee; + border-radius: 6px; + height: 10px; + min-width: 120px; + width: 100%; +} +.tox .tox-slider__handle { + background-color: #006ce7; + border: 2px solid #0054b4; + border-radius: 6px; + box-shadow: none; + height: 24px; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: 14px; +} +.tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { + margin-inline-start: 8px; +} +.tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { + margin-inline-start: 32px; +} +.tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { + margin-inline-start: 32px; +} +.tox .tox-source-code { + overflow: auto; +} +.tox .tox-spinner { + display: flex; +} +.tox .tox-spinner > div { + animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; + background-color: rgba(34, 47, 62, 0.7); + border-radius: 100%; + height: 8px; + width: 8px; +} +.tox .tox-spinner > div:nth-child(1) { + animation-delay: -0.32s; +} +.tox .tox-spinner > div:nth-child(2) { + animation-delay: -0.16s; +} +@keyframes tam-bouncing-dots { + 0%, + 100%, + 80% { + transform: scale(0); + } + 40% { + transform: scale(1); + } +} +.tox:not([dir='rtl']) .tox-spinner > div:not(:first-child) { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-spinner > div:not(:first-child) { + margin-right: 4px; +} +.tox .tox-statusbar { + align-items: center; + background-color: #fff; + border-top: 1px solid #e3e3e3; + color: rgba(34, 47, 62, 0.7); + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-weight: 400; + height: 25px; + overflow: hidden; + padding: 0 8px; + position: relative; + text-transform: none; +} +.tox .tox-statusbar__text-container { + display: flex; + flex: 1 1 auto; + justify-content: flex-end; + overflow: hidden; +} +.tox .tox-statusbar__path { + display: flex; + flex: 1 1 auto; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.tox .tox-statusbar__path > * { + display: inline; + white-space: nowrap; +} +.tox .tox-statusbar__wordcount { + flex: 0 0 auto; + margin-left: 1ch; +} +.tox .tox-statusbar a, +.tox .tox-statusbar__path-item, +.tox .tox-statusbar__wordcount { + color: rgba(34, 47, 62, 0.7); + text-decoration: none; +} +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']) { + color: #222f3e; + cursor: pointer; +} +.tox .tox-statusbar__branding svg { + fill: rgba(34, 47, 62, 0.8); + height: 1.14em; + vertical-align: -0.28em; + width: 3.6em; +} +.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled='true']) svg, +.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled='true']) svg { + fill: #222f3e; +} +.tox .tox-statusbar__resize-handle { + align-items: flex-end; + align-self: stretch; + cursor: nwse-resize; + display: flex; + flex: 0 0 auto; + justify-content: flex-end; + margin-left: auto; + margin-right: -8px; + padding-bottom: 3px; + padding-left: 1ch; + padding-right: 3px; +} +.tox .tox-statusbar__resize-handle svg { + display: block; + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-statusbar__resize-handle:focus svg { + background-color: #dee0e2; + border-radius: 1px 1px 5px 1px; + box-shadow: 0 0 0 2px #dee0e2; +} +.tox:not([dir='rtl']) .tox-statusbar__path > * { + margin-right: 4px; +} +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 2ch; +} +.tox[dir='rtl'] .tox-statusbar { + flex-direction: row-reverse; +} +.tox[dir='rtl'] .tox-statusbar__path > * { + margin-left: 4px; +} +.tox .tox-throbber { + z-index: 1299; +} +.tox .tox-throbber__busy-spinner { + align-items: center; + background-color: rgba(255, 255, 255, 0.6); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} +.tox .tox-tbtn { + align-items: center; + background: 0 0; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #222f3e; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: 400; + height: 28px; + justify-content: center; + margin: 6px 1px 5px 0; + outline: 0; + overflow: hidden; + padding: 0; + text-transform: none; + width: 34px; +} +.tox .tox-tbtn svg { + display: block; + fill: #222f3e; +} +.tox .tox-tbtn.tox-tbtn-more { + padding-left: 5px; + padding-right: 5px; + width: inherit; +} +.tox .tox-tbtn:focus { + background: #cce2fa; + border: 0; + box-shadow: none; +} +.tox .tox-tbtn:hover { + background: #cce2fa; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-tbtn:hover svg { + fill: #222f3e; +} +.tox .tox-tbtn:active { + background: #a6ccf7; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-tbtn:active svg { + fill: #222f3e; +} +.tox .tox-tbtn--disabled, +.tox .tox-tbtn--disabled:hover, +.tox .tox-tbtn:disabled, +.tox .tox-tbtn:disabled:hover { + background: 0 0; + border: 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} +.tox .tox-tbtn--disabled svg, +.tox .tox-tbtn--disabled:hover svg, +.tox .tox-tbtn:disabled svg, +.tox .tox-tbtn:disabled:hover svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-tbtn--enabled, +.tox .tox-tbtn--enabled:hover { + background: #a6ccf7; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-tbtn--enabled:hover > *, +.tox .tox-tbtn--enabled > * { + transform: none; +} +.tox .tox-tbtn--enabled svg, +.tox .tox-tbtn--enabled:hover svg { + fill: #222f3e; +} +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { + color: #222f3e; +} +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { + fill: #222f3e; +} +.tox .tox-tbtn:active > * { + transform: none; +} +.tox .tox-tbtn--md { + height: 42px; + width: 51px; +} +.tox .tox-tbtn--lg { + flex-direction: column; + height: 56px; + width: 68px; +} +.tox .tox-tbtn--return { + align-self: stretch; + height: unset; + width: 16px; +} +.tox .tox-tbtn--labeled { + padding: 0 4px; + width: unset; +} +.tox .tox-tbtn__vlabel { + display: block; + font-size: 10px; + font-weight: 400; + letter-spacing: -0.025em; + margin-bottom: 4px; + white-space: nowrap; +} +.tox .tox-tbtn--select { + margin: 6px 1px 5px 0; + padding: 0 4px; + width: auto; +} +.tox .tox-tbtn__select-label { + cursor: default; + font-weight: 400; + margin: 0 4px; +} +.tox .tox-tbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} +.tox .tox-tbtn__select-chevron svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-tbtn--bespoke { + background: #f7f7f7; +} +.tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { + margin-inline-start: 4px; +} +.tox .tox-tbtn--bespoke .tox-tbtn__select-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 7em; +} +.tox .tox-split-button { + border: 0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + margin: 6px 1px 5px 0; + overflow: hidden; +} +.tox .tox-split-button:hover { + box-shadow: 0 0 0 1px #cce2fa inset; +} +.tox .tox-split-button:focus { + background: #cce2fa; + box-shadow: none; + color: #222f3e; +} +.tox .tox-split-button > * { + border-radius: 0; +} +.tox .tox-split-button__chevron { + width: 16px; +} +.tox .tox-split-button__chevron svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-split-button .tox-tbtn { + margin: 0; +} +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, +.tox .tox-split-button.tox-tbtn--disabled:focus, +.tox .tox-split-button.tox-tbtn--disabled:hover { + background: 0 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} +.tox.tox-platform-touch .tox-split-button .tox-tbtn--select { + padding: 0 0; +} +.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { + width: 30px; +} +.tox.tox-platform-touch .tox-split-button__chevron { + width: 20px; +} +.tox .tox-toolbar-overlord { + background-color: #fff; +} +.tox .tox-toolbar, +.tox .tox-toolbar__overflow, +.tox .tox-toolbar__primary { + background-color: #fff; + background-image: repeating-linear-gradient(#e3e3e3 0 1px, transparent 1px 39px); + background-position: center top 40px; + background-repeat: no-repeat; + background-size: calc(100% - 11px * 2) calc(100% - 41px); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 0; + transform: perspective(1px); +} +.tox .tox-toolbar-overlord > .tox-toolbar, +.tox .tox-toolbar-overlord > .tox-toolbar__overflow, +.tox .tox-toolbar-overlord > .tox-toolbar__primary { + background-position: center top 0; + background-size: calc(100% - 11px * 2) calc(100% - 0px); +} +.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { + height: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; + visibility: hidden; +} +.tox .tox-toolbar__overflow--growing { + transition: height 0.3s ease, opacity 0.2s linear 0.1s; +} +.tox .tox-toolbar__overflow--shrinking { + transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; +} +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: 1px solid transparent; + margin-top: 0; + padding-bottom: 1px; + padding-top: 1px; +} +.tox .tox-toolbar--scrolling { + flex-wrap: nowrap; + overflow-x: auto; +} +.tox .tox-pop .tox-toolbar { + border-width: 0; +} +.tox .tox-toolbar--no-divider { + background-image: none; +} +.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, +.tox .tox-toolbar-overlord .tox-toolbar__primary { + background-position: center top 39px; +} +.tox .tox-editor-header > .tox-toolbar--scrolling, +.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { + background-image: none; +} +.tox.tox-tinymce-aux .tox-toolbar__overflow { + background-color: #fff; + background-position: center top 43px; + background-size: calc(100% - 8px * 2) calc(100% - 51px); + border: none; + border-radius: 6px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + padding: 4px 0; +} +.tox-pop .tox-pop__dialog .tox-toolbar { + background-position: center top 43px; + background-size: calc(100% - 11px * 2) calc(100% - 51px); + padding: 4px 0; +} +.tox .tox-toolbar__group { + align-items: center; + display: flex; + flex-wrap: wrap; + margin: 0 0; + padding: 0 11px 0 12px; +} +.tox .tox-toolbar__group--pull-right { + margin-left: auto; +} +.tox .tox-toolbar--scrolling .tox-toolbar__group { + flex-shrink: 0; + flex-wrap: nowrap; +} +.tox:not([dir='rtl']) .tox-toolbar__group:not(:last-of-type) { + border-right: 1px solid transparent; +} +.tox[dir='rtl'] .tox-toolbar__group:not(:last-of-type) { + border-left: 1px solid transparent; +} +.tox .tox-tooltip { + display: inline-block; + padding: 8px; + position: relative; +} +.tox .tox-tooltip__body { + background-color: #222f3e; + border-radius: 6px; + box-shadow: 0 2px 4px rgba(34, 47, 62, 0.3); + color: rgba(255, 255, 255, 0.75); + font-size: 14px; + font-style: normal; + font-weight: 400; + padding: 4px 8px; + text-transform: none; +} +.tox .tox-tooltip__arrow { + position: absolute; +} +.tox .tox-tooltip--down .tox-tooltip__arrow { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #222f3e; + bottom: 0; + left: 50%; + position: absolute; + transform: translateX(-50%); +} +.tox .tox-tooltip--up .tox-tooltip__arrow { + border-bottom: 8px solid #222f3e; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + left: 50%; + position: absolute; + top: 0; + transform: translateX(-50%); +} +.tox .tox-tooltip--right .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-left: 8px solid #222f3e; + border-top: 8px solid transparent; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-tooltip--left .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-right: 8px solid #222f3e; + border-top: 8px solid transparent; + left: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-well { + border: 1px solid #eee; + border-radius: 6px; + padding: 8px; + width: 100%; +} +.tox .tox-well > :first-child { + margin-top: 0; +} +.tox .tox-well > :last-child { + margin-bottom: 0; +} +.tox .tox-well > :only-child { + margin: 0; +} +.tox .tox-custom-editor { + border: 1px solid #eee; + border-radius: 6px; + display: flex; + flex: 1; + position: relative; +} +.tox .tox-dialog-loading::before { + background-color: rgba(0, 0, 0, 0.5); + content: ''; + height: 100%; + position: absolute; + width: 100%; + z-index: 1000; +} +.tox .tox-tab { + cursor: pointer; +} +.tox .tox-dialog__content-js { + display: flex; + flex: 1; +} +.tox .tox-dialog__body-content .tox-collection { + display: flex; + flex: 1; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.shadowdom.css b/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.shadowdom.css new file mode 100644 index 00000000..8bf192d2 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.shadowdom.css @@ -0,0 +1,35 @@ +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen, +.tox-shadowhost.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.shadowdom.min.css b/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.shadowdom.min.css new file mode 100644 index 00000000..c1141c55 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/oxide/skin.shadowdom.min.css @@ -0,0 +1,30 @@ +body.tox-dialog__disable-scroll { + overflow: hidden; +} +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} +.tox-shadowhost.tox-fullscreen, +.tox.tox-tinymce.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.css new file mode 100644 index 00000000..ca33c5dc --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.css @@ -0,0 +1,848 @@ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; +} + +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} + +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * Dracula Theme originally by Zeno Rocha [@zenorocha] + * https://draculatheme.com/ + * + * Ported for PrismJS by Albert Vallverdu [@byverdu] + */ +code[class*='language-'], +pre[class*='language-'] { + color: #f8f8f2; + background: none; + text-shadow: 0 1px rgba(0, 0, 0, 0.3); + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; + border-radius: 0.3em; +} + +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #282a36; +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #6272a4; +} + +.token.punctuation { + color: #f8f8f2; +} + +.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.constant, +.token.symbol, +.token.deleted { + color: #ff79c6; +} + +.token.boolean, +.token.number { + color: #bd93f9; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #50fa7b; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string, +.token.variable { + color: #f8f8f2; +} + +.token.atrule, +.token.attr-value, +.token.function, +.token.class-name { + color: #f1fa8c; +} + +.token.keyword { + color: #8be9fd; +} + +.token.regex, +.token.important { + color: #ffb86c; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable='false'] { + cursor: default; +} + +.mce-content-body *[contentEditable='true'] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A') no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} + +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #4099ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #4099ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:focus { + outline: 3px solid #4099ff; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:hover { + outline: 3px solid #4099ff; +} + +.mce-content-body *[contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #4099ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable='true']:focus, +.mce-content-body.mce-content-readonly *[contentEditable='true']:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected='inline-boundary'] { + background-color: #4099ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #4099ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid transparent; + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: lighten; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #4099ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*='border-width: 0px'], +.mce-item-table:not([border]), +.mce-item-table[border='0'], +table[style*='border-width: 0px'] td, +.mce-item-table:not([border]) td, +.mce-item-table[border='0'] td, +table[style*='border-width: 0px'] th, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border='0'] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) ul, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] ul, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} + +body { + font-family: sans-serif; +} + +table { + border-collapse: collapse; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.inline.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.inline.css new file mode 100644 index 00000000..761b0a30 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.inline.css @@ -0,0 +1,861 @@ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; +} + +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} + +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*='language-'], +pre[class*='language-'] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} + +pre[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +code[class*='language-'] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*='language-']::selection, +pre[class*='language-'] ::selection, +code[class*='language-']::selection, +code[class*='language-'] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.token.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + /* This background color was intended by the author of this theme. */ + background: hsla(0, 0%, 100%, 0.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #dd4a68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable='false'] { + cursor: default; +} + +.mce-content-body *[contentEditable='true'] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} + +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #b4d7ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable='true']:focus, +.mce-content-body.mce-content-readonly *[contentEditable='true']:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*='border-width: 0px'], +.mce-item-table:not([border]), +.mce-item-table[border='0'], +table[style*='border-width: 0px'] td, +.mce-item-table:not([border]) td, +.mce-item-table[border='0'] td, +table[style*='border-width: 0px'] th, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border='0'] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) ul, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] ul, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css new file mode 100644 index 00000000..882dfd5b --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css @@ -0,0 +1,720 @@ +.mce-content-body .mce-item-anchor { + background: transparent + url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") + no-repeat center; +} +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} +code[class*='language-'], +pre[class*='language-'] { + color: #000; + background: 0 0; + text-shadow: 0 1px #fff; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} +code[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +pre[class*='language-']::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} +code[class*='language-'] ::selection, +code[class*='language-']::selection, +pre[class*='language-'] ::selection, +pre[class*='language-']::selection { + text-shadow: none; + background: #b3d4fc; +} +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} +.token.cdata, +.token.comment, +.token.doctype, +.token.prolog { + color: #708090; +} +.token.punctuation { + color: #999; +} +.token.namespace { + opacity: 0.7; +} +.token.boolean, +.token.constant, +.token.deleted, +.token.number, +.token.property, +.token.symbol, +.token.tag { + color: #905; +} +.token.attr-name, +.token.builtin, +.token.char, +.token.inserted, +.token.selector, +.token.string { + color: #690; +} +.language-css .token.string, +.style .token.string, +.token.entity, +.token.operator, +.token.url { + color: #9a6e3a; + background: hsla(0, 0%, 100%, 0.5); +} +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} +.token.class-name, +.token.function { + color: #dd4a68; +} +.token.important, +.token.regex, +.token.variable { + color: #e90; +} +.token.bold, +.token.important { + font-weight: 700; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} +.mce-content-body .mce-visual-caret { + background-color: #000; + background-color: currentColor; + position: absolute; +} +.mce-content-body .mce-visual-caret-hidden { + display: none; +} +.mce-content-body [data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} +.mce-content-body [contentEditable='false'] { + cursor: default; +} +.mce-content-body [contentEditable='true'] { + cursor: text; +} +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} +.mce-content-body figure.align-left { + float: left; +} +.mce-content-body figure.align-right { + float: right; +} +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} +.mce-object { + background: transparent + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') + no-repeat center; + border: 1px dashed #aaa; +} +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} +@media print { + .mce-pagebreak { + border: 0; + } +} +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} +.tiny-pageembed { + display: inline-block; + position: relative; +} +.tiny-pageembed--16by9, +.tiny-pageembed--1by1, +.tiny-pageembed--21by9, +.tiny-pageembed--4by3 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} +.tiny-pageembed--4by3 { + padding-top: 75%; +} +.tiny-pageembed--1by1 { + padding-top: 100%; +} +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--1by1 iframe, +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--4by3 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-content-body[data-mce-placeholder] { + position: relative; +} +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed #000; + position: absolute; + z-index: 10001; +} +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th { + border: 0; +} +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: #fff; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} +.tox-rtc-user-selection { + position: relative; +} +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: 700; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} +.tox-rtc-remote-image { + background: #eaeaea + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') + no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} +.mce-match-marker { + background: #aaa; + color: #fff; +} +.mce-match-marker-selected { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} +.mce-content-body audio[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body img[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body table[data-mce-selected], +.mce-content-body video[data-mce-selected] { + outline: 3px solid #b4d7ff; +} +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} +.mce-content-body.mce-content-readonly [contentEditable='true']:focus, +.mce-content-body.mce-content-readonly [contentEditable='true']:hover { + outline: 0; +} +.mce-content-body [data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} +.mce-content-body img::-moz-selection { + background: 0 0; +} +.mce-content-body img::selection { + background: 0 0; +} +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ephox-snooker-resizer-cols { + cursor: col-resize; +} +.ephox-snooker-resizer-rows { + cursor: row-resize; +} +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} +.mce-toc { + border: 1px solid gray; +} +.mce-toc h2 { + margin: 4px; +} +.mce-toc li { + list-style-type: none; +} +.mce-item-table:not([border]), +.mce-item-table:not([border]) caption, +.mce-item-table:not([border]) td, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'], +.mce-item-table[border='0'] caption, +.mce-item-table[border='0'] td, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'], +table[style*='border-width: 0px'] caption, +table[style*='border-width: 0px'] td, +table[style*='border-width: 0px'] th { + border: 1px dashed #bbb; +} +.mce-visualblocks address, +.mce-visualblocks article, +.mce-visualblocks aside, +.mce-visualblocks blockquote, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks dl, +.mce-visualblocks figcaption, +.mce-visualblocks figure, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks hgroup, +.mce-visualblocks ol, +.mce-visualblocks p, +.mce-visualblocks pre, +.mce-visualblocks section, +.mce-visualblocks ul { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) dl, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) ul { + margin-left: 3px; +} +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] dl, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] ul { + background-position-x: right; + margin-right: 3px; +} +.mce-nbsp, +.mce-shy { + background: #aaa; +} +.mce-shy::after { + content: '-'; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.min.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.min.css new file mode 100644 index 00000000..04195ea7 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/content.min.css @@ -0,0 +1,707 @@ +.mce-content-body .mce-item-anchor { + background: transparent + url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") + no-repeat center; +} +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} +code[class*='language-'], +pre[class*='language-'] { + color: #f8f8f2; + background: 0 0; + text-shadow: 0 1px rgba(0, 0, 0, 0.3); + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; + border-radius: 0.3em; +} +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #282a36; +} +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} +.token.cdata, +.token.comment, +.token.doctype, +.token.prolog { + color: #6272a4; +} +.token.punctuation { + color: #f8f8f2; +} +.namespace { + opacity: 0.7; +} +.token.constant, +.token.deleted, +.token.property, +.token.symbol, +.token.tag { + color: #ff79c6; +} +.token.boolean, +.token.number { + color: #bd93f9; +} +.token.attr-name, +.token.builtin, +.token.char, +.token.inserted, +.token.selector, +.token.string { + color: #50fa7b; +} +.language-css .token.string, +.style .token.string, +.token.entity, +.token.operator, +.token.url, +.token.variable { + color: #f8f8f2; +} +.token.atrule, +.token.attr-value, +.token.class-name, +.token.function { + color: #f1fa8c; +} +.token.keyword { + color: #8be9fd; +} +.token.important, +.token.regex { + color: #ffb86c; +} +.token.bold, +.token.important { + font-weight: 700; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} +.mce-content-body .mce-visual-caret { + background-color: #000; + background-color: currentColor; + position: absolute; +} +.mce-content-body .mce-visual-caret-hidden { + display: none; +} +.mce-content-body [data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} +.mce-content-body [contentEditable='false'] { + cursor: default; +} +.mce-content-body [contentEditable='true'] { + cursor: text; +} +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} +.mce-content-body figure.align-left { + float: left; +} +.mce-content-body figure.align-right { + float: right; +} +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} +.mce-object { + background: transparent + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A') + no-repeat center; + border: 1px dashed #aaa; +} +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} +@media print { + .mce-pagebreak { + border: 0; + } +} +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} +.tiny-pageembed { + display: inline-block; + position: relative; +} +.tiny-pageembed--16by9, +.tiny-pageembed--1by1, +.tiny-pageembed--21by9, +.tiny-pageembed--4by3 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} +.tiny-pageembed--4by3 { + padding-top: 75%; +} +.tiny-pageembed--1by1 { + padding-top: 100%; +} +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--1by1 iframe, +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--4by3 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-content-body[data-mce-placeholder] { + position: relative; +} +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed #000; + position: absolute; + z-index: 10001; +} +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th { + border: 0; +} +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: #fff; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} +.tox-rtc-user-selection { + position: relative; +} +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: 700; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} +.tox-rtc-remote-image { + background: #eaeaea + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') + no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} +.mce-match-marker { + background: #aaa; + color: #fff; +} +.mce-match-marker-selected { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} +.mce-content-body audio[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body img[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body table[data-mce-selected], +.mce-content-body video[data-mce-selected] { + outline: 3px solid #4099ff; +} +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #4099ff; + outline-offset: 1px; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:focus { + outline: 3px solid #4099ff; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:hover { + outline: 3px solid #4099ff; +} +.mce-content-body [contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #4099ff; +} +.mce-content-body.mce-content-readonly [contentEditable='true']:focus, +.mce-content-body.mce-content-readonly [contentEditable='true']:hover { + outline: 0; +} +.mce-content-body [data-mce-selected='inline-boundary'] { + background-color: #4099ff; +} +.mce-content-body .mce-edit-focus { + outline: 3px solid #4099ff; +} +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid transparent; + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: lighten; + position: absolute; + right: -1px; + top: -1px; +} +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} +.mce-content-body img::-moz-selection { + background: 0 0; +} +.mce-content-body img::selection { + background: 0 0; +} +.ephox-snooker-resizer-bar { + background-color: #4099ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ephox-snooker-resizer-cols { + cursor: col-resize; +} +.ephox-snooker-resizer-rows { + cursor: row-resize; +} +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} +.mce-toc { + border: 1px solid gray; +} +.mce-toc h2 { + margin: 4px; +} +.mce-toc li { + list-style-type: none; +} +.mce-item-table:not([border]), +.mce-item-table:not([border]) caption, +.mce-item-table:not([border]) td, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'], +.mce-item-table[border='0'] caption, +.mce-item-table[border='0'] td, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'], +table[style*='border-width: 0px'] caption, +table[style*='border-width: 0px'] td, +table[style*='border-width: 0px'] th { + border: 1px dashed #bbb; +} +.mce-visualblocks address, +.mce-visualblocks article, +.mce-visualblocks aside, +.mce-visualblocks blockquote, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks dl, +.mce-visualblocks figcaption, +.mce-visualblocks figure, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks hgroup, +.mce-visualblocks ol, +.mce-visualblocks p, +.mce-visualblocks pre, +.mce-visualblocks section, +.mce-visualblocks ul { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) dl, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) ul { + margin-left: 3px; +} +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] dl, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] ul { + background-position-x: right; + margin-right: 3px; +} +.mce-nbsp, +.mce-shy { + background: #aaa; +} +.mce-shy::after { + content: '-'; +} +body { + font-family: sans-serif; +} +table { + border-collapse: collapse; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.css new file mode 100644 index 00000000..67f5befd --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.css @@ -0,0 +1,3764 @@ +.tox { + box-shadow: none; + box-sizing: content-box; + color: #2a3746; + cursor: auto; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-style: normal; + font-weight: normal; + line-height: normal; + -webkit-tap-highlight-color: transparent; + text-decoration: none; + text-shadow: none; + text-transform: none; + vertical-align: initial; + white-space: normal; +} + +.tox *:not(svg):not(rect) { + box-sizing: inherit; + color: inherit; + cursor: inherit; + direction: inherit; + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; + line-height: inherit; + -webkit-tap-highlight-color: inherit; + text-align: inherit; + text-decoration: inherit; + text-shadow: inherit; + text-transform: inherit; + vertical-align: inherit; + white-space: inherit; +} + +.tox *:not(svg):not(rect) { + /* stylelint-disable-line no-duplicate-selectors */ + background: transparent; + border: 0; + box-shadow: none; + float: none; + height: auto; + margin: 0; + max-width: none; + outline: 0; + padding: 0; + position: static; + width: auto; +} + +.tox:not([dir='rtl']) { + direction: ltr; + text-align: left; +} + +.tox[dir='rtl'] { + direction: rtl; + text-align: right; +} + +.tox-tinymce { + border: 1px solid #000000; + border-radius: 0; + box-shadow: none; + box-sizing: border-box; + display: flex; + flex-direction: column; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + overflow: hidden; + position: relative; + visibility: inherit !important; +} + +.tox.tox-tinymce-inline { + border: none; + box-shadow: none; + overflow: initial; +} + +.tox.tox-tinymce-inline .tox-editor-container { + overflow: initial; +} + +.tox.tox-tinymce-inline .tox-editor-header { + background-color: #222f3e; + border: 1px solid #000000; + border-radius: 0; + box-shadow: none; + overflow: hidden; +} + +.tox-tinymce-aux { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + z-index: 1300; +} + +.tox-tinymce *:focus, +.tox-tinymce-aux *:focus { + outline: none; +} + +button::-moz-focus-inner { + border: 0; +} + +.tox[dir='rtl'] .tox-icon--flip svg { + transform: rotateY(180deg); +} + +.tox .accessibility-issue__header { + align-items: center; + display: flex; + margin-bottom: 4px; +} + +.tox .accessibility-issue__description { + align-items: stretch; + border: 1px solid #000000; + border-radius: 3px; + display: flex; + justify-content: space-between; +} + +.tox .accessibility-issue__description > div { + padding-bottom: 4px; +} + +.tox .accessibility-issue__description > div > div { + align-items: center; + display: flex; + margin-bottom: 4px; +} + +.tox .accessibility-issue__description > *:last-child:not(:only-child) { + border-color: #000000; + border-style: solid; +} + +.tox .accessibility-issue__repair { + margin-top: 16px; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { + background-color: rgba(32, 122, 183, 0.5); + border-color: #207ab7; + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description > *:last-child { + border-color: #207ab7; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { + background-color: rgba(255, 165, 0, 0.5); + border-color: rgba(255, 165, 0, 0.8); + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description > *:last-child { + border-color: rgba(255, 165, 0, 0.8); +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { + background-color: rgba(204, 0, 0, 0.5); + border-color: rgba(204, 0, 0, 0.8); + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description > *:last-child { + border-color: rgba(204, 0, 0, 0.8); +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { + background-color: rgba(120, 171, 70, 0.5); + border-color: rgba(120, 171, 70, 0.8); + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > *:last-child { + border-color: rgba(120, 171, 70, 0.8); +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue__header h1, +.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { + margin-top: 0; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-left: auto; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 4px 4px 8px; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-left-width: 1px; + padding-left: 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-right: auto; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 8px 4px 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-right-width: 1px; + padding-right: 4px; +} + +.tox .tox-anchorbar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-bar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-button { + background-color: #207ab7; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #207ab7; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + line-height: 24px; + margin: 0; + outline: none; + padding: 4px 16px; + text-align: center; + text-decoration: none; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-button[disabled] { + background-color: #207ab7; + background-image: none; + border-color: #207ab7; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-button:focus:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:hover:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:active:not(:disabled) { + background-color: #185d8c; + background-image: none; + border-color: #185d8c; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary { + background-color: #3d546f; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #3d546f; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + color: #fff; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + outline: none; + padding: 4px 16px; + text-decoration: none; + text-transform: none; +} + +.tox .tox-button--secondary[disabled] { + background-color: #3d546f; + background-image: none; + border-color: #3d546f; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} + +.tox .tox-button--secondary:focus:not(:disabled) { + background-color: #34485f; + background-image: none; + border-color: #34485f; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary:hover:not(:disabled) { + background-color: #34485f; + background-image: none; + border-color: #34485f; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary:active:not(:disabled) { + background-color: #2b3b4e; + background-image: none; + border-color: #2b3b4e; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--icon, +.tox .tox-button.tox-button--icon, +.tox .tox-button.tox-button--secondary.tox-button--icon { + padding: 4px; +} + +.tox .tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { + display: block; + fill: currentColor; +} + +.tox .tox-button-link { + background: 0; + border: none; + box-sizing: border-box; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-weight: normal; + line-height: 1.3; + margin: 0; + padding: 0; + white-space: nowrap; +} + +.tox .tox-button-link--sm { + font-size: 14px; +} + +.tox .tox-button--naked { + background-color: transparent; + border-color: transparent; + box-shadow: unset; + color: #fff; +} + +.tox .tox-button--naked[disabled] { + background-color: #3d546f; + border-color: #3d546f; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} + +.tox .tox-button--naked:hover:not(:disabled) { + background-color: #34485f; + border-color: #34485f; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--naked:focus:not(:disabled) { + background-color: #34485f; + border-color: #34485f; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--naked:active:not(:disabled) { + background-color: #2b3b4e; + border-color: #2b3b4e; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--naked .tox-icon svg { + fill: currentColor; +} + +.tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { + color: #fff; +} + +.tox .tox-checkbox { + align-items: center; + border-radius: 3px; + cursor: pointer; + display: flex; + height: 36px; + min-width: 36px; +} + +.tox .tox-checkbox__input { + /* Hide from view but visible to screen readers */ + height: 1px; + overflow: hidden; + position: absolute; + top: auto; + width: 1px; +} + +.tox .tox-checkbox__icons { + align-items: center; + border-radius: 3px; + box-shadow: 0 0 0 2px transparent; + box-sizing: content-box; + display: flex; + height: 24px; + justify-content: center; + padding: calc(4px - 1px); + width: 24px; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: block; + fill: rgba(255, 255, 255, 0.2); +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: none; + fill: #207ab7; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: none; + fill: #207ab7; +} + +.tox .tox-checkbox--disabled { + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: block; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: block; +} + +.tox input.tox-checkbox__input:focus + .tox-checkbox__icons { + border-radius: 3px; + box-shadow: inset 0 0 0 1px #207ab7; + padding: calc(4px - 1px); +} + +.tox:not([dir='rtl']) .tox-checkbox__label { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-checkbox__input { + left: -10000px; +} + +.tox:not([dir='rtl']) .tox-bar .tox-checkbox { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-checkbox__label { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-checkbox__input { + right: -10000px; +} + +.tox[dir='rtl'] .tox-bar .tox-checkbox { + margin-right: 4px; +} + +.tox { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox .tox-collection--toolbar .tox-collection__group { + display: flex; + padding: 0; +} + +.tox .tox-collection--grid .tox-collection__group { + display: flex; + flex-wrap: wrap; + max-height: 208px; + overflow-x: hidden; + overflow-y: auto; + padding: 0; +} + +.tox .tox-collection--list .tox-collection__group { + border-bottom-width: 0; + border-color: #1a1a1a; + border-left-width: 0; + border-right-width: 0; + border-style: solid; + border-top-width: 1px; + padding: 4px 0; +} + +.tox .tox-collection--list .tox-collection__group:first-child { + border-top-width: 0; +} + +.tox .tox-collection__group-heading { + background-color: #333333; + color: #fff; + cursor: default; + font-size: 12px; + font-style: normal; + font-weight: normal; + margin-bottom: 4px; + margin-top: -4px; + padding: 4px 8px; + text-transform: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.tox .tox-collection__item { + align-items: center; + border-radius: 3px; + color: #fff; + display: flex; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.tox .tox-collection--list .tox-collection__item { + padding: 4px 8px; +} + +.tox .tox-collection--toolbar .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--grid .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--list .tox-collection__item--enabled { + background-color: #2b3b4e; + color: #fff; +} + +.tox .tox-collection--list .tox-collection__item--active { + background-color: #4a5562; +} + +.tox .tox-collection--toolbar .tox-collection__item--enabled { + background-color: #757d87; + color: #fff; +} + +.tox .tox-collection--toolbar .tox-collection__item--active { + background-color: #4a5562; +} + +.tox .tox-collection--grid .tox-collection__item--enabled { + background-color: #757d87; + color: #fff; +} + +.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + background-color: #4a5562; + color: #fff; +} + +.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #fff; +} + +.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #fff; +} + +.tox .tox-collection__item-icon, +.tox .tox-collection__item-checkmark { + align-items: center; + display: flex; + height: 24px; + justify-content: center; + width: 24px; +} + +.tox .tox-collection__item-icon svg, +.tox .tox-collection__item-checkmark svg { + fill: currentColor; +} + +.tox .tox-collection--toolbar-lg .tox-collection__item-icon { + height: 48px; + width: 48px; +} + +.tox .tox-collection__item-label { + color: currentColor; + display: inline-block; + flex: 1; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 24px; + text-transform: none; + word-break: break-all; +} + +.tox .tox-collection__item-accessory { + color: rgba(255, 255, 255, 0.5); + display: inline-block; + font-size: 14px; + height: 24px; + line-height: 24px; + text-transform: none; +} + +.tox .tox-collection__item-caret { + align-items: center; + display: flex; + min-height: 24px; +} + +.tox .tox-collection__item-caret::after { + content: ''; + font-size: 0; + min-height: inherit; +} + +.tox .tox-collection__item-caret svg { + fill: #fff; +} + +.tox .tox-collection__item--state-disabled { + background-color: transparent; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox +.tox-collection--list +.tox-collection__item:not(.tox-collection__item--enabled) +.tox-collection__item-checkmark +svg { + display: none; +} + +.tox +.tox-collection--list +.tox-collection__item:not(.tox-collection__item--enabled) +.tox-collection__item-accessory ++ .tox-collection__item-checkmark { + display: none; +} + +.tox .tox-collection--horizontal { + background-color: #2b3b4e; + border: 1px solid #1a1a1a; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(42, 55, 70, 0.2), 0 4px 8px 0 rgba(42, 55, 70, 0.15); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: nowrap; + margin-bottom: 0; + overflow-x: auto; + padding: 0; +} + +.tox .tox-collection--horizontal .tox-collection__group { + align-items: center; + display: flex; + flex-wrap: nowrap; + margin: 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item { + height: 34px; + margin: 3px 0 2px 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item-label { + white-space: nowrap; +} + +.tox .tox-collection--horizontal .tox-collection__item-caret { + margin-left: 4px; +} + +.tox .tox-collection__item-container { + display: flex; +} + +.tox .tox-collection__item-container--row { + align-items: center; + flex: 1 1 auto; + flex-direction: row; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-left { + margin-right: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-right { + justify-content: flex-end; + margin-left: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { + align-items: flex-start; + margin-bottom: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { + align-items: center; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { + align-items: flex-end; + margin-top: auto; +} + +.tox .tox-collection__item-container--column { + align-self: center; + flex: 1 1 auto; + flex-direction: column; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-left { + align-items: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-right { + align-items: flex-end; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { + align-self: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { + align-self: center; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { + align-self: flex-end; +} + +.tox:not([dir='rtl']) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-right: 1px solid #000000; +} + +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-left: 8px; +} + +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-collection__item-accessory { + margin-left: 16px; + text-align: right; +} + +.tox:not([dir='rtl']) .tox-collection .tox-collection__item-caret { + margin-left: 16px; +} + +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-left: 1px solid #000000; +} + +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-right: 8px; +} + +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-collection__item-accessory { + margin-right: 16px; + text-align: left; +} + +.tox[dir='rtl'] .tox-collection .tox-collection__item-caret { + margin-right: 16px; + transform: rotateY(180deg); +} + +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__item-caret { + margin-right: 4px; +} + +.tox .tox-color-picker-container { + display: flex; + flex-direction: row; + height: 225px; + margin: 0; +} + +.tox .tox-sv-palette { + box-sizing: border-box; + display: flex; + height: 100%; +} + +.tox .tox-sv-palette-spectrum { + height: 100%; +} + +.tox .tox-sv-palette, +.tox .tox-sv-palette-spectrum { + width: 225px; +} + +.tox .tox-sv-palette-thumb { + background: none; + border: 1px solid black; + border-radius: 50%; + box-sizing: content-box; + height: 12px; + position: absolute; + width: 12px; +} + +.tox .tox-sv-palette-inner-thumb { + border: 1px solid white; + border-radius: 50%; + height: 10px; + position: absolute; + width: 10px; +} + +.tox .tox-hue-slider { + box-sizing: border-box; + height: 100%; + width: 25px; +} + +.tox .tox-hue-slider-spectrum { + background: linear-gradient( + to bottom, + #f00, + #ff0080, + #f0f, + #8000ff, + #00f, + #0080ff, + #0ff, + #00ff80, + #0f0, + #80ff00, + #ff0, + #ff8000, + #f00 + ); + height: 100%; + width: 100%; +} + +.tox .tox-hue-slider, +.tox .tox-hue-slider-spectrum { + width: 20px; +} + +.tox .tox-hue-slider-thumb { + background: white; + border: 1px solid black; + box-sizing: content-box; + height: 4px; + width: 100%; +} + +.tox .tox-rgb-form { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.tox .tox-rgb-form div { + align-items: center; + display: flex; + justify-content: space-between; + margin-bottom: 5px; + width: inherit; +} + +.tox .tox-rgb-form input { + width: 6em; +} + +.tox .tox-rgb-form input.tox-invalid { + /* Need !important to override Chrome's focus styling unfortunately */ + border: 1px solid red !important; +} + +.tox .tox-rgb-form .tox-rgba-preview { + border: 1px solid black; + flex-grow: 2; + margin-bottom: 0; +} + +.tox:not([dir='rtl']) .tox-sv-palette { + margin-right: 15px; +} + +.tox:not([dir='rtl']) .tox-hue-slider { + margin-right: 15px; +} + +.tox:not([dir='rtl']) .tox-hue-slider-thumb { + margin-left: -1px; +} + +.tox:not([dir='rtl']) .tox-rgb-form label { + margin-right: 0.5em; +} + +.tox[dir='rtl'] .tox-sv-palette { + margin-left: 15px; +} + +.tox[dir='rtl'] .tox-hue-slider { + margin-left: 15px; +} + +.tox[dir='rtl'] .tox-hue-slider-thumb { + margin-right: -1px; +} + +.tox[dir='rtl'] .tox-rgb-form label { + margin-left: 0.5em; +} + +.tox .tox-toolbar .tox-swatches, +.tox .tox-toolbar__primary .tox-swatches, +.tox .tox-toolbar__overflow .tox-swatches { + margin: 2px 0 3px 4px; +} + +.tox .tox-collection--list .tox-collection__group .tox-swatches-menu { + border: 0; + margin: -4px 0; +} + +.tox .tox-swatches__row { + display: flex; +} + +.tox .tox-swatch { + height: 30px; + transition: transform 0.15s, box-shadow 0.15s; + width: 30px; +} + +.tox .tox-swatch:hover, +.tox .tox-swatch:focus { + box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; + transform: scale(0.8); +} + +.tox .tox-swatch--remove { + align-items: center; + display: flex; + justify-content: center; +} + +.tox .tox-swatch--remove svg path { + stroke: #e74c3c; +} + +.tox .tox-swatches__picker-btn { + align-items: center; + background-color: transparent; + border: 0; + cursor: pointer; + display: flex; + height: 30px; + justify-content: center; + outline: none; + padding: 0; + width: 30px; +} + +.tox .tox-swatches__picker-btn svg { + fill: #fff; + height: 24px; + width: 24px; +} + +.tox .tox-swatches__picker-btn:hover { + background: #4a5562; +} + +.tox:not([dir='rtl']) .tox-swatches__picker-btn { + margin-left: auto; +} + +.tox[dir='rtl'] .tox-swatches__picker-btn { + margin-right: auto; +} + +.tox .tox-comment-thread { + background: #2b3b4e; + position: relative; +} + +.tox .tox-comment-thread > *:not(:first-child) { + margin-top: 8px; +} + +.tox .tox-comment { + background: #2b3b4e; + border: 1px solid #000000; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(42, 55, 70, 0.1); + padding: 8px 8px 16px 8px; + position: relative; +} + +.tox .tox-comment__header { + align-items: center; + color: #fff; + display: flex; + justify-content: space-between; +} + +.tox .tox-comment__date { + color: rgba(255, 255, 255, 0.5); + font-size: 12px; +} + +.tox .tox-comment__body { + color: #fff; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin-top: 8px; + position: relative; + text-transform: initial; +} + +.tox .tox-comment__body textarea { + resize: none; + white-space: normal; + width: 100%; +} + +.tox .tox-comment__expander { + padding-top: 8px; +} + +.tox .tox-comment__expander p { + color: rgba(255, 255, 255, 0.5); + font-size: 14px; + font-style: normal; +} + +.tox .tox-comment__body p { + margin: 0; +} + +.tox .tox-comment__buttonspacing { + padding-top: 16px; + text-align: center; +} + +.tox .tox-comment-thread__overlay::after { + background: #2b3b4e; + bottom: 0; + content: ''; + display: flex; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + top: 0; + z-index: 5; +} + +.tox .tox-comment__reply { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 8px; +} + +.tox .tox-comment__reply > *:first-child { + margin-bottom: 8px; + width: 100%; +} + +.tox .tox-comment__edit { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 16px; +} + +.tox .tox-comment__gradient::after { + background: linear-gradient(rgba(43, 59, 78, 0), #2b3b4e); + bottom: 0; + content: ''; + display: block; + height: 5em; + margin-top: -40px; + position: absolute; + width: 100%; +} + +.tox .tox-comment__overlay { + background: #2b3b4e; + bottom: 0; + display: flex; + flex-direction: column; + flex-grow: 1; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + text-align: center; + top: 0; + z-index: 5; +} + +.tox .tox-comment__loading-text { + align-items: center; + color: #fff; + display: flex; + flex-direction: column; + position: relative; +} + +.tox .tox-comment__loading-text > div { + padding-bottom: 16px; +} + +.tox .tox-comment__overlaytext { + bottom: 0; + flex-direction: column; + font-size: 14px; + left: 0; + padding: 1em; + position: absolute; + right: 0; + top: 0; + z-index: 10; +} + +.tox .tox-comment__overlaytext p { + background-color: #2b3b4e; + box-shadow: 0 0 8px 8px #2b3b4e; + color: #fff; + text-align: center; +} + +.tox .tox-comment__overlaytext div:nth-of-type(2) { + font-size: 0.8em; +} + +.tox .tox-comment__busy-spinner { + align-items: center; + background-color: #2b3b4e; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 20; +} + +.tox .tox-comment__scroll { + display: flex; + flex-direction: column; + flex-shrink: 1; + overflow: auto; +} + +.tox .tox-conversations { + margin: 8px; +} + +.tox:not([dir='rtl']) .tox-comment__edit { + margin-left: 8px; +} + +.tox:not([dir='rtl']) .tox-comment__buttonspacing > *:last-child, +.tox:not([dir='rtl']) .tox-comment__edit > *:last-child, +.tox:not([dir='rtl']) .tox-comment__reply > *:last-child { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-comment__edit { + margin-right: 8px; +} + +.tox[dir='rtl'] .tox-comment__buttonspacing > *:last-child, +.tox[dir='rtl'] .tox-comment__edit > *:last-child, +.tox[dir='rtl'] .tox-comment__reply > *:last-child { + margin-right: 8px; +} + +.tox .tox-user { + align-items: center; + display: flex; +} + +.tox .tox-user__avatar svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-user__name { + color: rgba(255, 255, 255, 0.5); + font-size: 12px; + font-style: normal; + font-weight: bold; + text-transform: uppercase; +} + +.tox:not([dir='rtl']) .tox-user__avatar svg { + margin-right: 8px; +} + +.tox:not([dir='rtl']) .tox-user__avatar + .tox-user__name { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-user__avatar svg { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-user__avatar + .tox-user__name { + margin-right: 8px; +} + +.tox .tox-dialog-wrap { + align-items: center; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 1100; +} + +.tox .tox-dialog-wrap__backdrop { + background-color: rgba(34, 47, 62, 0.75); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} + +.tox .tox-dialog-wrap__backdrop--opaque { + background-color: #222f3e; +} + +.tox .tox-dialog { + background-color: #2b3b4e; + border-color: #000000; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: 0 16px 16px -10px rgba(42, 55, 70, 0.15), 0 0 40px 1px rgba(42, 55, 70, 0.15); + display: flex; + flex-direction: column; + max-height: 100%; + max-width: 480px; + overflow: hidden; + position: relative; + width: 95vw; + z-index: 2; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog { + align-self: flex-start; + margin: 8px auto; + width: calc(100vw - 16px); + } +} + +.tox .tox-dialog-inline { + z-index: 1100; +} + +.tox .tox-dialog__header { + align-items: center; + background-color: #2b3b4e; + border-bottom: none; + color: #fff; + display: flex; + font-size: 16px; + justify-content: space-between; + padding: 8px 16px 0 16px; + position: relative; +} + +.tox .tox-dialog__header .tox-button { + z-index: 1; +} + +.tox .tox-dialog__draghandle { + cursor: grab; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tox .tox-dialog__draghandle:active { + cursor: grabbing; +} + +.tox .tox-dialog__dismiss { + margin-left: auto; +} + +.tox .tox-dialog__title { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 20px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin: 0; + text-transform: none; +} + +.tox .tox-dialog__body { + color: #fff; + display: flex; + flex: 1; + font-size: 16px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + min-width: 0; + text-align: left; + text-transform: none; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body { + flex-direction: column; + } +} + +.tox .tox-dialog__body-nav { + align-items: flex-start; + display: flex; + flex-direction: column; + padding: 16px 16px; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { + flex-direction: row; + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding-bottom: 0; + } +} + +.tox .tox-dialog__body-nav-item { + border-bottom: 2px solid transparent; + color: rgba(255, 255, 255, 0.5); + display: inline-block; + font-size: 14px; + line-height: 1.3; + margin-bottom: 8px; + text-decoration: none; + white-space: nowrap; +} + +.tox .tox-dialog__body-nav-item:focus { + background-color: rgba(32, 122, 183, 0.1); +} + +.tox .tox-dialog__body-nav-item--active { + border-bottom: 2px solid #207ab7; + color: #207ab7; +} + +.tox .tox-dialog__body-content { + box-sizing: border-box; + display: flex; + flex: 1; + flex-direction: column; + max-height: 650px; + overflow: auto; + -webkit-overflow-scrolling: touch; + padding: 16px 16px; +} + +.tox .tox-dialog__body-content > * { + margin-bottom: 0; + margin-top: 16px; +} + +.tox .tox-dialog__body-content > *:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content > *:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content > *:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog__body-content a { + color: #207ab7; + cursor: pointer; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:hover, +.tox .tox-dialog__body-content a:focus { + color: #185d8c; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:active { + color: #185d8c; + text-decoration: none; +} + +.tox .tox-dialog__body-content svg { + fill: #fff; +} + +.tox .tox-dialog__body-content ul { + display: block; + list-style-type: disc; + margin-bottom: 16px; + margin-inline-end: 0; + margin-inline-start: 0; + padding-inline-start: 2.5rem; +} + +.tox .tox-dialog__body-content .tox-form__group h1 { + color: #fff; + font-size: 20px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group h2 { + color: #fff; + font-size: 16px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group p { + margin-bottom: 16px; +} + +.tox .tox-dialog__body-content .tox-form__group h1:first-child, +.tox .tox-dialog__body-content .tox-form__group h2:first-child, +.tox .tox-dialog__body-content .tox-form__group p:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:last-child, +.tox .tox-dialog__body-content .tox-form__group h2:last-child, +.tox .tox-dialog__body-content .tox-form__group p:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:only-child, +.tox .tox-dialog__body-content .tox-form__group h2:only-child, +.tox .tox-dialog__body-content .tox-form__group p:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog--width-lg { + height: 650px; + max-width: 1200px; +} + +.tox .tox-dialog--width-md { + max-width: 800px; +} + +.tox .tox-dialog--width-md .tox-dialog__body-content { + overflow: auto; +} + +.tox .tox-dialog__body-content--centered { + text-align: center; +} + +.tox .tox-dialog__footer { + align-items: center; + background-color: #2b3b4e; + border-top: 1px solid #000000; + display: flex; + justify-content: space-between; + padding: 8px 16px; +} + +.tox .tox-dialog__footer-start, +.tox .tox-dialog__footer-end { + display: flex; +} + +.tox .tox-dialog__busy-spinner { + align-items: center; + background-color: rgba(34, 47, 62, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 3; +} + +.tox .tox-dialog__table { + border-collapse: collapse; + width: 100%; +} + +.tox .tox-dialog__table thead th { + font-weight: bold; + padding-bottom: 8px; +} + +.tox .tox-dialog__table tbody tr { + border-bottom: 1px solid #000000; +} + +.tox .tox-dialog__table tbody tr:last-child { + border-bottom: none; +} + +.tox .tox-dialog__table td { + padding-bottom: 8px; + padding-top: 8px; +} + +.tox .tox-dialog__popups { + position: absolute; + width: 100%; + z-index: 1100; +} + +.tox .tox-dialog__body-iframe { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-dialog__body-iframe .tox-navobj { + display: flex; + flex: 1; +} + +.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} + +.tox .tox-dialog-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox .tox-dialog-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox .tox-dialog-dock-transition { + transition: visibility 0s linear 0.3s, opacity 0.3s ease; +} + +.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { + transition-delay: 0s; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav { + margin-right: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav-item:not(:first-child) { + margin-left: 8px; + } +} + +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-start > *, +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-end > * { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-dialog__body { + text-align: right; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav { + margin-left: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav-item:not(:first-child) { + margin-right: 8px; + } +} + +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-start > *, +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-end > * { + margin-right: 8px; +} + +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox .tox-dropzone-container { + display: flex; + flex: 1; +} + +.tox .tox-dropzone { + align-items: center; + background: #fff; + border: 2px dashed #000000; + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-grow: 1; + justify-content: center; + min-height: 100px; + padding: 10px; +} + +.tox .tox-dropzone p { + color: rgba(255, 255, 255, 0.5); + margin: 0 0 16px 0; +} + +.tox .tox-edit-area { + display: flex; + flex: 1; + overflow: hidden; + position: relative; +} + +.tox .tox-edit-area__iframe { + background-color: #fff; + border: 0; + box-sizing: border-box; + flex: 1; + height: 100%; + position: absolute; + width: 100%; +} + +.tox.tox-inline-edit-area { + border: 1px dotted #000000; +} + +.tox .tox-editor-container { + display: flex; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} + +.tox .tox-editor-header { + z-index: 1; +} + +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: #222f3e; + border-bottom: none; + box-shadow: none; + padding: 4px 0; + transition: box-shadow 0.5s; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: 1px solid #000000; + box-shadow: none; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: #222f3e; + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); + padding: 4px 0; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); +} + +.tox-editor-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox-editor-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox-editor-dock-transition { + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} + +.tox-editor-dock-transition.tox-editor-dock-fadein { + transition-delay: 0s; +} + +.tox .tox-control-wrap { + flex: 1; + position: relative; +} + +.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, +.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, +.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { + display: none; +} + +.tox .tox-control-wrap svg { + display: block; +} + +.tox .tox-control-wrap__status-icon-wrap { + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-control-wrap__status-icon-invalid svg { + fill: #c00; +} + +.tox .tox-control-wrap__status-icon-unknown svg { + fill: orange; +} + +.tox .tox-control-wrap__status-icon-valid svg { + fill: green; +} + +.tox:not([dir='rtl']) .tox-control-wrap--status-invalid .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-unknown .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-valid .tox-textfield { + padding-right: 32px; +} + +.tox:not([dir='rtl']) .tox-control-wrap__status-icon-wrap { + right: 4px; +} + +.tox[dir='rtl'] .tox-control-wrap--status-invalid .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-unknown .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-valid .tox-textfield { + padding-left: 32px; +} + +.tox[dir='rtl'] .tox-control-wrap__status-icon-wrap { + left: 4px; +} + +.tox .tox-autocompleter { + max-width: 25em; +} + +.tox .tox-autocompleter .tox-menu { + border-color: #000000; + box-shadow: none; + max-width: 25em; +} + +.tox .tox-autocompleter .tox-autocompleter-highlight { + font-weight: bold; +} + +.tox .tox-color-input { + display: flex; + position: relative; + z-index: 1; +} + +.tox .tox-color-input .tox-textfield { + z-index: -1; +} + +.tox .tox-color-input span { + border-color: rgba(42, 55, 70, 0.2); + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + height: 24px; + position: absolute; + top: 6px; + width: 24px; +} + +.tox .tox-color-input span:hover:not([aria-disabled='true']), +.tox .tox-color-input span:focus:not([aria-disabled='true']) { + border-color: #207ab7; + cursor: pointer; +} + +.tox .tox-color-input span::before { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), + linear-gradient(-45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%), + linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%); + background-position: 0 0, 0 6px, 6px -6px, -6px 0; + background-size: 12px 12px; + border: 1px solid #2b3b4e; + border-radius: 3px; + box-sizing: border-box; + content: ''; + height: 24px; + left: -1px; + position: absolute; + top: -1px; + width: 24px; + z-index: -1; +} + +.tox .tox-color-input span[aria-disabled='true'] { + cursor: not-allowed; +} + +.tox:not([dir='rtl']) .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir='rtl']) .tox-color-input .tox-textfield { + padding-left: 36px; +} + +.tox:not([dir='rtl']) .tox-color-input span { + left: 6px; +} + +.tox[dir='rtl'] .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir='rtl'] .tox-color-input .tox-textfield { + padding-right: 36px; +} + +.tox[dir='rtl'] .tox-color-input span { + right: 6px; +} + +.tox .tox-label, +.tox .tox-toolbar-label { + color: rgba(255, 255, 255, 0.5); + display: block; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + padding: 0 8px 0 0; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-toolbar-label { + padding: 0 8px; +} + +.tox[dir='rtl'] .tox-label { + padding: 0 0 0 8px; +} + +.tox .tox-form { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-form__group { + box-sizing: border-box; + margin-bottom: 4px; +} + +.tox .tox-form-group--maximize { + flex: 1; +} + +.tox .tox-form__group--error { + color: #c00; +} + +.tox .tox-form__group--collection { + display: flex; +} + +.tox .tox-form__grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} + +.tox .tox-form__grid--2col > .tox-form__group { + width: calc(50% - (8px / 2)); +} + +.tox .tox-form__grid--3col > .tox-form__group { + width: calc(100% / 3 - (8px / 2)); +} + +.tox .tox-form__grid--4col > .tox-form__group { + width: calc(25% - (8px / 2)); +} + +.tox .tox-form__controls-h-stack { + align-items: center; + display: flex; +} + +.tox .tox-form__group--inline { + align-items: center; + display: flex; +} + +.tox .tox-form__group--stretched { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-form__group--stretched .tox-textarea { + flex: 1; +} + +.tox .tox-form__group--stretched .tox-navobj { + display: flex; + flex: 1; +} + +.tox .tox-form__group--stretched .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} + +.tox:not([dir='rtl']) .tox-form__controls-h-stack > *:not(:first-child) { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-form__controls-h-stack > *:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-lock.tox-locked .tox-lock-icon__unlock, +.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { + display: none; +} + +.tox .tox-textfield, +.tox .tox-toolbar-textfield, +.tox .tox-listboxfield .tox-listbox--select, +.tox .tox-textarea { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #2b3b4e; + border-color: #000000; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 4.75px; + resize: none; + width: 100%; +} + +.tox .tox-textfield[disabled], +.tox .tox-textarea[disabled] { + background-color: #222f3e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} + +.tox .tox-textfield:focus, +.tox .tox-listboxfield .tox-listbox--select:focus, +.tox .tox-textarea:focus { + background-color: #2b3b4e; + border-color: #207ab7; + box-shadow: none; + outline: 2px solid rgba(32, 122, 183, 0.25); +} + +.tox .tox-toolbar-textfield { + border-width: 0; + margin-bottom: 3px; + margin-top: 2px; + max-width: 250px; +} + +.tox .tox-naked-btn { + background-color: transparent; + border: 0; + border-color: transparent; + box-shadow: unset; + color: #207ab7; + cursor: pointer; + display: block; + margin: 0; + padding: 0; +} + +.tox .tox-naked-btn svg { + display: block; + fill: #fff; +} + +.tox:not([dir='rtl']) .tox-toolbar-textfield + * { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-toolbar-textfield + * { + margin-right: 4px; +} + +.tox .tox-listboxfield { + cursor: pointer; + position: relative; +} + +.tox .tox-listboxfield .tox-listbox--select[disabled] { + background-color: #19232e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} + +.tox .tox-listbox__select-label { + cursor: default; + flex: 1; + margin: 0 4px; +} + +.tox .tox-listbox__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-listbox__select-chevron svg { + fill: #fff; +} + +.tox .tox-listboxfield .tox-listbox--select { + align-items: center; + display: flex; +} + +.tox:not([dir='rtl']) .tox-listboxfield svg { + right: 8px; +} + +.tox[dir='rtl'] .tox-listboxfield svg { + left: 8px; +} + +.tox .tox-selectfield { + cursor: pointer; + position: relative; +} + +.tox .tox-selectfield select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #2b3b4e; + border-color: #000000; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 4.75px; + resize: none; + width: 100%; +} + +.tox .tox-selectfield select[disabled] { + background-color: #19232e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} + +.tox .tox-selectfield select::-ms-expand { + display: none; +} + +.tox .tox-selectfield select:focus { + background-color: #2b3b4e; + border-color: #207ab7; + box-shadow: none; + outline: 2px solid rgba(32, 122, 183, 0.25); +} + +.tox .tox-selectfield svg { + pointer-events: none; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox:not([dir='rtl']) .tox-selectfield select[size='0'], +.tox:not([dir='rtl']) .tox-selectfield select[size='1'] { + padding-right: 24px; +} + +.tox:not([dir='rtl']) .tox-selectfield svg { + right: 8px; +} + +.tox[dir='rtl'] .tox-selectfield select[size='0'], +.tox[dir='rtl'] .tox-selectfield select[size='1'] { + padding-left: 24px; +} + +.tox[dir='rtl'] .tox-selectfield svg { + left: 8px; +} + +.tox .tox-textarea { + -webkit-appearance: textarea; + -moz-appearance: textarea; + appearance: textarea; + white-space: pre-wrap; +} + +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen, +.tox-shadowhost.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} + +.tox .tox-help__more-link { + list-style: none; + margin-top: 1em; +} + +.tox .tox-imagepreview { + background-color: #666; + height: 380px; + overflow: hidden; + position: relative; + width: 100%; +} + +.tox .tox-imagepreview.tox-imagepreview__loaded { + overflow: auto; +} + +.tox .tox-imagepreview__container { + display: flex; + left: 100vw; + position: absolute; + top: 100vw; +} + +.tox .tox-imagepreview__image { + background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); +} + +.tox .tox-image-tools .tox-spacer { + flex: 1; +} + +.tox .tox-image-tools .tox-bar { + align-items: center; + display: flex; + height: 60px; + justify-content: center; +} + +.tox .tox-image-tools .tox-imagepreview, +.tox .tox-image-tools .tox-imagepreview + .tox-bar { + margin-top: 8px; +} + +.tox .tox-image-tools .tox-croprect-block { + background: black; + filter: alpha(opacity=50); + opacity: 0.5; + position: absolute; + zoom: 1; +} + +.tox .tox-image-tools .tox-croprect-handle { + border: 2px solid white; + height: 20px; + left: 0; + position: absolute; + top: 0; + width: 20px; +} + +.tox .tox-image-tools .tox-croprect-handle-move { + border: 0; + cursor: move; + position: absolute; +} + +.tox .tox-image-tools .tox-croprect-handle-nw { + border-width: 2px 0 0 2px; + cursor: nw-resize; + left: 100px; + margin: -2px 0 0 -2px; + top: 100px; +} + +.tox .tox-image-tools .tox-croprect-handle-ne { + border-width: 2px 2px 0 0; + cursor: ne-resize; + left: 200px; + margin: -2px 0 0 -20px; + top: 100px; +} + +.tox .tox-image-tools .tox-croprect-handle-sw { + border-width: 0 0 2px 2px; + cursor: sw-resize; + left: 100px; + margin: -20px 2px 0 -2px; + top: 200px; +} + +.tox .tox-image-tools .tox-croprect-handle-se { + border-width: 0 2px 2px 0; + cursor: se-resize; + left: 200px; + margin: -20px 0 0 -20px; + top: 200px; +} + +.tox .tox-insert-table-picker { + display: flex; + flex-wrap: wrap; + width: 170px; +} + +.tox .tox-insert-table-picker > div { + border-color: #000000; + border-style: solid; + border-width: 0 1px 1px 0; + box-sizing: border-box; + height: 17px; + width: 17px; +} + +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: 0 -4px; +} + +.tox .tox-insert-table-picker .tox-insert-table-picker__selected { + background-color: rgba(32, 122, 183, 0.5); + border-color: rgba(32, 122, 183, 0.5); +} + +.tox .tox-insert-table-picker__label { + color: #fff; + display: block; + font-size: 14px; + padding: 4px; + text-align: center; + width: 100%; +} + +.tox:not([dir='rtl']) { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir='rtl']) .tox-insert-table-picker > div:nth-child(10n) { + border-right: 0; +} + +.tox[dir='rtl'] { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir='rtl'] .tox-insert-table-picker > div:nth-child(10n + 1) { + border-right: 0; +} + +.tox { + /* stylelint-disable */ + /* stylelint-enable */ +} + +.tox .tox-menu { + background-color: #2b3b4e; + border: 1px solid #000000; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(42, 55, 70, 0.1); + display: inline-block; + overflow: hidden; + vertical-align: top; + z-index: 1150; +} + +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0 0; +} + +.tox .tox-menu.tox-collection.tox-collection--toolbar { + padding: 4px; +} + +.tox .tox-menu.tox-collection.tox-collection--grid { + padding: 4px; +} + +.tox .tox-menu__label h1, +.tox .tox-menu__label h2, +.tox .tox-menu__label h3, +.tox .tox-menu__label h4, +.tox .tox-menu__label h5, +.tox .tox-menu__label h6, +.tox .tox-menu__label p, +.tox .tox-menu__label blockquote, +.tox .tox-menu__label code { + margin: 0; +} + +.tox .tox-menubar { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0 #222f3e; + background-color: #222f3e; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 4px 0 4px; +} + +.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { + border-top: 1px solid #000000; +} + +/* Deprecated. Remove in next major release */ +.tox .tox-mbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 34px; + justify-content: center; + margin: 2px 0 3px 0; + outline: none; + overflow: hidden; + padding: 0 4px; + text-transform: none; + width: auto; +} + +.tox .tox-mbtn[disabled] { + background-color: transparent; + border: 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-mbtn:focus:not(:disabled) { + background: #4a5562; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-mbtn--active { + background: #757d87; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { + background: #4a5562; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-mbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-mbtn[disabled] .tox-mbtn__select-label { + cursor: not-allowed; +} + +.tox .tox-mbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; + display: none; +} + +.tox .tox-notification { + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + display: grid; + font-size: 14px; + font-weight: normal; + grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + margin-top: 4px; + opacity: 0; + padding: 4px; + transition: transform 100ms ease-in, opacity 150ms ease-in; +} + +.tox .tox-notification p { + font-size: 14px; + font-weight: normal; +} + +.tox .tox-notification a { + cursor: pointer; + text-decoration: underline; +} + +.tox .tox-notification--in { + opacity: 1; +} + +.tox .tox-notification--success { + background-color: #334840; + border-color: #3c5440; + color: #fff; +} + +.tox .tox-notification--success p { + color: #fff; +} + +.tox .tox-notification--success a { + color: #b5d199; +} + +.tox .tox-notification--success svg { + fill: #fff; +} + +.tox .tox-notification--error { + background-color: #442632; + border-color: #55212b; + color: #fff; +} + +.tox .tox-notification--error p { + color: #fff; +} + +.tox .tox-notification--error a { + color: #e68080; +} + +.tox .tox-notification--error svg { + fill: #fff; +} + +.tox .tox-notification--warn, +.tox .tox-notification--warning { + background-color: #222f3e; + border-color: #000000; + color: #fff0b3; +} + +.tox .tox-notification--warn p, +.tox .tox-notification--warning p { + color: #fff0b3; +} + +.tox .tox-notification--warn a, +.tox .tox-notification--warning a { + color: #ffcc00; +} + +.tox .tox-notification--warn svg, +.tox .tox-notification--warning svg { + fill: #fff0b3; +} + +.tox .tox-notification--info { + background-color: #254161; + border-color: #264972; + color: #fff; +} + +.tox .tox-notification--info p { + color: #fff; +} + +.tox .tox-notification--info a { + color: #83b7f3; +} + +.tox .tox-notification--info svg { + fill: #fff; +} + +.tox .tox-notification__body { + align-self: center; + color: #fff; + font-size: 14px; + grid-column-end: 3; + grid-column-start: 2; + grid-row-end: 2; + grid-row-start: 1; + text-align: center; + white-space: normal; + word-break: break-all; + word-break: break-word; +} + +.tox .tox-notification__body > * { + margin: 0; +} + +.tox .tox-notification__body > * + * { + margin-top: 1rem; +} + +.tox .tox-notification__icon { + align-self: center; + grid-column-end: 2; + grid-column-start: 1; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} + +.tox .tox-notification__icon svg { + display: block; +} + +.tox .tox-notification__dismiss { + align-self: start; + grid-column-end: 4; + grid-column-start: 3; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} + +.tox .tox-notification .tox-progress-bar { + grid-column-end: 4; + grid-column-start: 1; + grid-row-end: 3; + grid-row-start: 2; + justify-self: center; +} + +.tox .tox-pop { + display: inline-block; + position: relative; +} + +.tox .tox-pop--resizing { + transition: width 0.1s ease; +} + +.tox .tox-pop--resizing .tox-toolbar, +.tox .tox-pop--resizing .tox-toolbar__group { + flex-wrap: nowrap; +} + +.tox .tox-pop--transition { + transition: 0.15s ease; + transition-property: left, right, top, bottom; +} + +.tox .tox-pop--transition::before, +.tox .tox-pop--transition::after { + transition: all 0.15s, visibility 0s, opacity 0.075s ease 0.075s; +} + +.tox .tox-pop__dialog { + background-color: #222f3e; + border: 1px solid #000000; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(42, 55, 70, 0.2), 0 4px 8px 0 rgba(42, 55, 70, 0.15); + min-width: 0; + overflow: hidden; +} + +.tox .tox-pop__dialog > *:not(.tox-toolbar) { + margin: 4px 4px 4px 8px; +} + +.tox .tox-pop__dialog .tox-toolbar { + background-color: transparent; + margin-bottom: -1px; +} + +.tox .tox-pop::before, +.tox .tox-pop::after { + border-style: solid; + content: ''; + display: block; + height: 0; + opacity: 1; + position: absolute; + width: 0; +} + +.tox .tox-pop.tox-pop--inset::before, +.tox .tox-pop.tox-pop--inset::after { + opacity: 0; + transition: all 0s 0.15s, visibility 0s, opacity 0.075s ease; +} + +.tox .tox-pop.tox-pop--bottom::before, +.tox .tox-pop.tox-pop--bottom::after { + left: 50%; + top: 100%; +} + +.tox .tox-pop.tox-pop--bottom::after { + border-color: #222f3e transparent transparent transparent; + border-width: 8px; + margin-left: -8px; + margin-top: -1px; +} + +.tox .tox-pop.tox-pop--bottom::before { + border-color: #000000 transparent transparent transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--top::before, +.tox .tox-pop.tox-pop--top::after { + left: 50%; + top: 0; + transform: translateY(-100%); +} + +.tox .tox-pop.tox-pop--top::after { + border-color: transparent transparent #222f3e transparent; + border-width: 8px; + margin-left: -8px; + margin-top: 1px; +} + +.tox .tox-pop.tox-pop--top::before { + border-color: transparent transparent #000000 transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--left::before, +.tox .tox-pop.tox-pop--left::after { + left: 0; + top: calc(50% - 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--left::after { + border-color: transparent #222f3e transparent transparent; + border-width: 8px; + margin-left: -15px; +} + +.tox .tox-pop.tox-pop--left::before { + border-color: transparent #000000 transparent transparent; + border-width: 10px; + margin-left: -19px; +} + +.tox .tox-pop.tox-pop--right::before, +.tox .tox-pop.tox-pop--right::after { + left: 100%; + top: calc(50% + 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--right::after { + border-color: transparent transparent transparent #222f3e; + border-width: 8px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--right::before { + border-color: transparent transparent transparent #000000; + border-width: 10px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--align-left::before, +.tox .tox-pop.tox-pop--align-left::after { + left: 20px; +} + +.tox .tox-pop.tox-pop--align-right::before, +.tox .tox-pop.tox-pop--align-right::after { + left: calc(100% - 20px); +} + +.tox .tox-sidebar-wrap { + display: flex; + flex-direction: row; + flex-grow: 1; + min-height: 0; +} + +.tox .tox-sidebar { + background-color: #222f3e; + display: flex; + flex-direction: row; + justify-content: flex-end; +} + +.tox .tox-sidebar__slider { + display: flex; + overflow: hidden; +} + +.tox .tox-sidebar__pane-container { + display: flex; +} + +.tox .tox-sidebar__pane { + display: flex; +} + +.tox .tox-sidebar--sliding-closed { + opacity: 0; +} + +.tox .tox-sidebar--sliding-open { + opacity: 1; +} + +.tox .tox-sidebar--sliding-growing, +.tox .tox-sidebar--sliding-shrinking { + transition: width 0.5s ease, opacity 0.5s ease; +} + +.tox .tox-selector { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + display: inline-block; + height: 10px; + position: absolute; + width: 10px; +} + +.tox.tox-platform-touch .tox-selector { + height: 12px; + width: 12px; +} + +.tox .tox-slider { + align-items: center; + display: flex; + flex: 1; + height: 24px; + justify-content: center; + position: relative; +} + +.tox .tox-slider__rail { + background-color: transparent; + border: 1px solid #000000; + border-radius: 3px; + height: 10px; + min-width: 120px; + width: 100%; +} + +.tox .tox-slider__handle { + background-color: #207ab7; + border: 2px solid #185d8c; + border-radius: 3px; + box-shadow: none; + height: 24px; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: 14px; +} + +.tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { + margin-inline-start: 8px; +} + +.tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { + margin-inline-start: 32px; +} + +.tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { + margin-inline-start: 32px; +} + +.tox .tox-source-code { + overflow: auto; +} + +.tox .tox-spinner { + display: flex; +} + +.tox .tox-spinner > div { + animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; + background-color: rgba(255, 255, 255, 0.5); + border-radius: 100%; + height: 8px; + width: 8px; +} + +.tox .tox-spinner > div:nth-child(1) { + animation-delay: -0.32s; +} + +.tox .tox-spinner > div:nth-child(2) { + animation-delay: -0.16s; +} + +@keyframes tam-bouncing-dots { + 0%, + 80%, + 100% { + transform: scale(0); + } + 40% { + transform: scale(1); + } +} + +.tox:not([dir='rtl']) .tox-spinner > div:not(:first-child) { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-spinner > div:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-statusbar { + align-items: center; + background-color: #222f3e; + border-top: 1px solid #000000; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 12px; + font-weight: normal; + height: 18px; + overflow: hidden; + padding: 0 8px; + position: relative; + text-transform: uppercase; +} + +.tox .tox-statusbar__text-container { + display: flex; + flex: 1 1 auto; + justify-content: flex-end; + overflow: hidden; +} + +.tox .tox-statusbar__path { + display: flex; + flex: 1 1 auto; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tox .tox-statusbar__path > * { + display: inline; + white-space: nowrap; +} + +.tox .tox-statusbar__wordcount { + flex: 0 0 auto; + margin-left: 1ch; +} + +.tox .tox-statusbar a, +.tox .tox-statusbar__path-item, +.tox .tox-statusbar__wordcount { + color: #fff; + text-decoration: none; +} + +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']) { + color: #fff; + cursor: pointer; +} + +.tox .tox-statusbar__branding svg { + fill: rgba(255, 255, 255, 0.8); + height: 1.14em; + vertical-align: -0.28em; + width: 3.6em; +} + +.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled='true']) svg, +.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled='true']) svg { + fill: #fff; +} + +.tox .tox-statusbar__resize-handle { + align-items: flex-end; + align-self: stretch; + cursor: nwse-resize; + display: flex; + flex: 0 0 auto; + justify-content: flex-end; + margin-left: auto; + margin-right: -8px; + padding-bottom: 3px; + padding-left: 1ch; + padding-right: 3px; +} + +.tox .tox-statusbar__resize-handle svg { + display: block; + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-statusbar__resize-handle:focus svg { + background-color: #4a5562; + border-radius: 1px 1px -4px 1px; + box-shadow: 0 0 0 2px #4a5562; +} + +.tox:not([dir='rtl']) .tox-statusbar__path > * { + margin-right: 4px; +} + +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 2ch; +} + +.tox[dir='rtl'] .tox-statusbar { + flex-direction: row-reverse; +} + +.tox[dir='rtl'] .tox-statusbar__path > * { + margin-left: 4px; +} + +.tox .tox-throbber { + z-index: 1299; +} + +.tox .tox-throbber__busy-spinner { + align-items: center; + background-color: rgba(34, 47, 62, 0.6); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.tox .tox-tbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 34px; + justify-content: center; + margin: 3px 0 2px 0; + outline: none; + overflow: hidden; + padding: 0; + text-transform: none; + width: 34px; +} + +.tox .tox-tbtn svg { + display: block; + fill: #fff; +} + +.tox .tox-tbtn.tox-tbtn-more { + padding-left: 5px; + padding-right: 5px; + width: inherit; +} + +.tox .tox-tbtn:focus { + background: #4a5562; + border: 0; + box-shadow: none; +} + +.tox .tox-tbtn:hover { + background: #4a5562; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-tbtn:hover svg { + fill: #fff; +} + +.tox .tox-tbtn:active { + background: #757d87; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-tbtn:active svg { + fill: #fff; +} + +.tox .tox-tbtn--disabled, +.tox .tox-tbtn--disabled:hover, +.tox .tox-tbtn:disabled, +.tox .tox-tbtn:disabled:hover { + background: transparent; + border: 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-tbtn--disabled svg, +.tox .tox-tbtn--disabled:hover svg, +.tox .tox-tbtn:disabled svg, +.tox .tox-tbtn:disabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-tbtn--enabled, +.tox .tox-tbtn--enabled:hover { + background: #757d87; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-tbtn--enabled > *, +.tox .tox-tbtn--enabled:hover > * { + transform: none; +} + +.tox .tox-tbtn--enabled svg, +.tox .tox-tbtn--enabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: #fff; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { + color: #fff; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { + fill: #fff; +} + +.tox .tox-tbtn:active > * { + transform: none; +} + +.tox .tox-tbtn--md { + height: 51px; + width: 51px; +} + +.tox .tox-tbtn--lg { + flex-direction: column; + height: 68px; + width: 68px; +} + +.tox .tox-tbtn--return { + align-self: stretch; + height: unset; + width: 16px; +} + +.tox .tox-tbtn--labeled { + padding: 0 4px; + width: unset; +} + +.tox .tox-tbtn__vlabel { + display: block; + font-size: 10px; + font-weight: normal; + letter-spacing: -0.025em; + margin-bottom: 4px; + white-space: nowrap; +} + +.tox .tox-tbtn--select { + margin: 3px 0 2px 0; + padding: 0 4px; + width: auto; +} + +.tox .tox-tbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-tbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-tbtn__select-chevron svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-tbtn--bespoke { + background: transparent; +} + +.tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { + margin-inline-start: 0; +} + +.tox .tox-tbtn--bespoke .tox-tbtn__select-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 7em; +} + +.tox .tox-split-button { + border: 0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + margin: 3px 0 2px 0; + overflow: hidden; +} + +.tox .tox-split-button:hover { + box-shadow: 0 0 0 1px #4a5562 inset; +} + +.tox .tox-split-button:focus { + background: #4a5562; + box-shadow: none; + color: #fff; +} + +.tox .tox-split-button > * { + border-radius: 0; +} + +.tox .tox-split-button__chevron { + width: 16px; +} + +.tox .tox-split-button__chevron svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-split-button .tox-tbtn { + margin: 0; +} + +.tox .tox-split-button.tox-tbtn--disabled:hover, +.tox .tox-split-button.tox-tbtn--disabled:focus, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus { + background: transparent; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} + +.tox.tox-platform-touch .tox-split-button .tox-tbtn--select { + padding: 0 0px; +} + +.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { + width: 30px; +} + +.tox.tox-platform-touch .tox-split-button__chevron { + width: 20px; +} + +.tox .tox-toolbar-overlord { + background-color: #222f3e; +} + +.tox .tox-toolbar, +.tox .tox-toolbar__primary, +.tox .tox-toolbar__overflow { + background-color: #222f3e; + background-image: repeating-linear-gradient(#000000 0px 1px, transparent 1px 39px); + background-position: center top 39px; + background-repeat: no-repeat; + background-size: calc(100% - 4px * 2) calc(100% - 39px); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 0px; + transform: perspective(1px); +} + +.tox .tox-toolbar-overlord > .tox-toolbar, +.tox .tox-toolbar-overlord > .tox-toolbar__primary, +.tox .tox-toolbar-overlord > .tox-toolbar__overflow { + background-position: center top 0px; + background-size: calc(100% - 4px * 2) calc(100% - 0px); +} + +.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { + height: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; + visibility: hidden; +} + +.tox .tox-toolbar__overflow--growing { + transition: height 0.3s ease, opacity 0.2s linear 0.1s; +} + +.tox .tox-toolbar__overflow--shrinking { + transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; +} + +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: 1px solid #000000; + margin-top: 0; + padding-bottom: 0px; + padding-top: 0px; +} + +.tox .tox-toolbar--scrolling { + flex-wrap: nowrap; + overflow-x: auto; +} + +.tox .tox-pop .tox-toolbar { + border-width: 0; +} + +.tox .tox-toolbar--no-divider { + background-image: none; +} + +.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, +.tox .tox-toolbar-overlord .tox-toolbar__primary { + background-position: center top 39px; +} + +.tox .tox-editor-header > .tox-toolbar--scrolling, +.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { + background-image: none; +} + +.tox.tox-tinymce-aux .tox-toolbar__overflow { + background-color: #222f3e; + background-position: center top 43px; + background-size: calc(100% - 8px * 2) calc(100% - 51px); + border: none; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(42, 55, 70, 0.2), 0 4px 8px 0 rgba(42, 55, 70, 0.15); + padding: 4px 0; +} + +.tox-pop .tox-pop__dialog { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox-pop .tox-pop__dialog .tox-toolbar { + background-position: center top 43px; + background-size: calc(100% - 4px * 2) calc(100% - 51px); + padding: 4px 0; +} + +.tox .tox-toolbar__group { + align-items: center; + display: flex; + flex-wrap: wrap; + margin: 0 0; + padding: 0 4px 0 4px; +} + +.tox .tox-toolbar__group--pull-right { + margin-left: auto; +} + +.tox .tox-toolbar--scrolling .tox-toolbar__group { + flex-shrink: 0; + flex-wrap: nowrap; +} + +.tox:not([dir='rtl']) .tox-toolbar__group:not(:last-of-type) { + border-right: 1px solid #000000; +} + +.tox[dir='rtl'] .tox-toolbar__group:not(:last-of-type) { + border-left: 1px solid #000000; +} + +.tox .tox-tooltip { + display: inline-block; + padding: 8px; + position: relative; +} + +.tox .tox-tooltip__body { + background-color: #3d546f; + border-radius: 3px; + box-shadow: 0 2px 4px rgba(42, 55, 70, 0.3); + color: rgba(255, 255, 255, 0.75); + font-size: 14px; + font-style: normal; + font-weight: normal; + padding: 4px 8px; + text-transform: none; +} + +.tox .tox-tooltip__arrow { + position: absolute; +} + +.tox .tox-tooltip--down .tox-tooltip__arrow { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #3d546f; + bottom: 0; + left: 50%; + position: absolute; + transform: translateX(-50%); +} + +.tox .tox-tooltip--up .tox-tooltip__arrow { + border-bottom: 8px solid #3d546f; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + left: 50%; + position: absolute; + top: 0; + transform: translateX(-50%); +} + +.tox .tox-tooltip--right .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-left: 8px solid #3d546f; + border-top: 8px solid transparent; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-tooltip--left .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-right: 8px solid #3d546f; + border-top: 8px solid transparent; + left: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-well { + border: 1px solid #000000; + border-radius: 3px; + padding: 8px; + width: 100%; +} + +.tox .tox-well > *:first-child { + margin-top: 0; +} + +.tox .tox-well > *:last-child { + margin-bottom: 0; +} + +.tox .tox-well > *:only-child { + margin: 0; +} + +.tox .tox-custom-editor { + border: 1px solid #000000; + border-radius: 3px; + display: flex; + flex: 1; + position: relative; +} + +/* stylelint-disable */ +.tox { + /* stylelint-enable */ +} + +.tox .tox-dialog-loading::before { + background-color: rgba(0, 0, 0, 0.5); + content: ''; + height: 100%; + position: absolute; + width: 100%; + z-index: 1000; +} + +.tox .tox-tab { + cursor: pointer; +} + +.tox .tox-dialog__content-js { + display: flex; + flex: 1; +} + +.tox .tox-dialog__body-content .tox-collection { + display: flex; + flex: 1; +} + +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: none; + padding: 0; +} + +.tox.tox-tinymce--toolbar-bottom .tox-editor-header, +.tox.tox-tinymce-inline .tox-editor-header { + margin-bottom: -1px; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: none; + box-shadow: none; +} + +.tox.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: transparent; + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); + padding: 0; +} + +.tox.tox.tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); +} + +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: -4px 0; +} + +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0; +} + +.tox .tox-pop { + box-shadow: none; +} + +.tox .tox-tbtn, +.tox .tox-tbtn--select, +.tox .tox-split-button { + margin: 2px 0 3px 0; +} + +.tox .tox-toolbar, +.tox .tox-toolbar__primary, +.tox .tox-toolbar__overflow { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0px #222f3e !important; +} + +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: none; +} + +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord .tox-toolbar__primary { + border-top: 1px solid #000000; + margin-top: -1px; +} + +.tox.tox-tinymce-aux .tox-toolbar__overflow { + border: 1px solid #000000; + padding: 0; +} + +.tox:not(.tox-tinymce-inline) +.tox-editor-header:not(:first-child) +.tox-toolbar-overlord:first-child +.tox-toolbar__primary, +.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child { + border-top: 1px solid #000000; +} + +.tox .tox-toolbar__group { + padding: 0 4px 0 4px; +} + +.tox .tox-collection__item { + border-radius: 0; + cursor: pointer; +} + +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']) { + color: #fff; + text-decoration: underline; +} + +.tox .tox-statusbar__branding svg { + vertical-align: -0.25em; +} + +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 1ch; +} + +.tox .tox-statusbar__resize-handle { + padding-bottom: 0; + padding-right: 0; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.min.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.min.css new file mode 100644 index 00000000..e38e829e --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.min.css @@ -0,0 +1,3125 @@ +.tox { + box-shadow: none; + box-sizing: content-box; + color: #2a3746; + cursor: auto; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + -webkit-tap-highlight-color: transparent; + text-decoration: none; + text-shadow: none; + text-transform: none; + vertical-align: initial; + white-space: normal; +} +.tox :not(svg):not(rect) { + box-sizing: inherit; + color: inherit; + cursor: inherit; + direction: inherit; + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; + line-height: inherit; + -webkit-tap-highlight-color: inherit; + text-align: inherit; + text-decoration: inherit; + text-shadow: inherit; + text-transform: inherit; + vertical-align: inherit; + white-space: inherit; +} +.tox :not(svg):not(rect) { + background: 0 0; + border: 0; + box-shadow: none; + float: none; + height: auto; + margin: 0; + max-width: none; + outline: 0; + padding: 0; + position: static; + width: auto; +} +.tox:not([dir='rtl']) { + direction: ltr; + text-align: left; +} +.tox[dir='rtl'] { + direction: rtl; + text-align: right; +} +.tox-tinymce { + border: 1px solid #000; + border-radius: 0; + box-shadow: none; + box-sizing: border-box; + display: flex; + flex-direction: column; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + overflow: hidden; + position: relative; + visibility: inherit !important; +} +.tox.tox-tinymce-inline { + border: none; + box-shadow: none; + overflow: initial; +} +.tox.tox-tinymce-inline .tox-editor-container { + overflow: initial; +} +.tox.tox-tinymce-inline .tox-editor-header { + background-color: #222f3e; + border: 1px solid #000; + border-radius: 0; + box-shadow: none; + overflow: hidden; +} +.tox-tinymce-aux { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + z-index: 1300; +} +.tox-tinymce :focus, +.tox-tinymce-aux :focus { + outline: 0; +} +button::-moz-focus-inner { + border: 0; +} +.tox[dir='rtl'] .tox-icon--flip svg { + transform: rotateY(180deg); +} +.tox .accessibility-issue__header { + align-items: center; + display: flex; + margin-bottom: 4px; +} +.tox .accessibility-issue__description { + align-items: stretch; + border: 1px solid #000; + border-radius: 3px; + display: flex; + justify-content: space-between; +} +.tox .accessibility-issue__description > div { + padding-bottom: 4px; +} +.tox .accessibility-issue__description > div > div { + align-items: center; + display: flex; + margin-bottom: 4px; +} +.tox .accessibility-issue__description > :last-child:not(:only-child) { + border-color: #000; + border-style: solid; +} +.tox .accessibility-issue__repair { + margin-top: 16px; +} +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { + background-color: rgba(32, 122, 183, 0.5); + border-color: #207ab7; + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description > :last-child { + border-color: #207ab7; +} +.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { + fill: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { + background-color: rgba(255, 165, 0, 0.5); + border-color: rgba(255, 165, 0, 0.8); + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description > :last-child { + border-color: rgba(255, 165, 0, 0.8); +} +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { + fill: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { + background-color: rgba(204, 0, 0, 0.5); + border-color: rgba(204, 0, 0, 0.8); + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description > :last-child { + border-color: rgba(204, 0, 0, 0.8); +} +.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { + fill: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { + background-color: rgba(120, 171, 70, 0.5); + border-color: rgba(120, 171, 70, 0.8); + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > :last-child { + border-color: rgba(120, 171, 70, 0.8); +} +.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { + fill: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon { + color: #fff; +} +.tox .tox-dialog__body-content .accessibility-issue__header h1, +.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { + margin-top: 0; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header > :nth-last-child(2) { + margin-left: auto; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 4px 4px 8px; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description > :last-child { + border-left-width: 1px; + padding-left: 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header > :nth-last-child(2) { + margin-right: auto; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 8px 4px 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description > :last-child { + border-right-width: 1px; + padding-right: 4px; +} +.tox .tox-anchorbar { + display: flex; + flex: 0 0 auto; +} +.tox .tox-bar { + display: flex; + flex: 0 0 auto; +} +.tox .tox-button { + background-color: #207ab7; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #207ab7; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 14px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + line-height: 24px; + margin: 0; + outline: 0; + padding: 4px 16px; + text-align: center; + text-decoration: none; + text-transform: none; + white-space: nowrap; +} +.tox .tox-button[disabled] { + background-color: #207ab7; + background-image: none; + border-color: #207ab7; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-button:focus:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} +.tox .tox-button:hover:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} +.tox .tox-button:active:not(:disabled) { + background-color: #185d8c; + background-image: none; + border-color: #185d8c; + box-shadow: none; + color: #fff; +} +.tox .tox-button--secondary { + background-color: #3d546f; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #3d546f; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + color: #fff; + font-size: 14px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + outline: 0; + padding: 4px 16px; + text-decoration: none; + text-transform: none; +} +.tox .tox-button--secondary[disabled] { + background-color: #3d546f; + background-image: none; + border-color: #3d546f; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} +.tox .tox-button--secondary:focus:not(:disabled) { + background-color: #34485f; + background-image: none; + border-color: #34485f; + box-shadow: none; + color: #fff; +} +.tox .tox-button--secondary:hover:not(:disabled) { + background-color: #34485f; + background-image: none; + border-color: #34485f; + box-shadow: none; + color: #fff; +} +.tox .tox-button--secondary:active:not(:disabled) { + background-color: #2b3b4e; + background-image: none; + border-color: #2b3b4e; + box-shadow: none; + color: #fff; +} +.tox .tox-button--icon, +.tox .tox-button.tox-button--icon, +.tox .tox-button.tox-button--secondary.tox-button--icon { + padding: 4px; +} +.tox .tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { + display: block; + fill: currentColor; +} +.tox .tox-button-link { + background: 0; + border: none; + box-sizing: border-box; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-weight: 400; + line-height: 1.3; + margin: 0; + padding: 0; + white-space: nowrap; +} +.tox .tox-button-link--sm { + font-size: 14px; +} +.tox .tox-button--naked { + background-color: transparent; + border-color: transparent; + box-shadow: unset; + color: #fff; +} +.tox .tox-button--naked[disabled] { + background-color: #3d546f; + border-color: #3d546f; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} +.tox .tox-button--naked:hover:not(:disabled) { + background-color: #34485f; + border-color: #34485f; + box-shadow: none; + color: #fff; +} +.tox .tox-button--naked:focus:not(:disabled) { + background-color: #34485f; + border-color: #34485f; + box-shadow: none; + color: #fff; +} +.tox .tox-button--naked:active:not(:disabled) { + background-color: #2b3b4e; + border-color: #2b3b4e; + box-shadow: none; + color: #fff; +} +.tox .tox-button--naked .tox-icon svg { + fill: currentColor; +} +.tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { + color: #fff; +} +.tox .tox-checkbox { + align-items: center; + border-radius: 3px; + cursor: pointer; + display: flex; + height: 36px; + min-width: 36px; +} +.tox .tox-checkbox__input { + height: 1px; + overflow: hidden; + position: absolute; + top: auto; + width: 1px; +} +.tox .tox-checkbox__icons { + align-items: center; + border-radius: 3px; + box-shadow: 0 0 0 2px transparent; + box-sizing: content-box; + display: flex; + height: 24px; + justify-content: center; + padding: calc(4px - 1px); + width: 24px; +} +.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: block; + fill: rgba(255, 255, 255, 0.2); +} +.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: none; + fill: #207ab7; +} +.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: none; + fill: #207ab7; +} +.tox .tox-checkbox--disabled { + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: block; +} +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: block; +} +.tox input.tox-checkbox__input:focus + .tox-checkbox__icons { + border-radius: 3px; + box-shadow: inset 0 0 0 1px #207ab7; + padding: calc(4px - 1px); +} +.tox:not([dir='rtl']) .tox-checkbox__label { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-checkbox__input { + left: -10000px; +} +.tox:not([dir='rtl']) .tox-bar .tox-checkbox { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-checkbox__label { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-checkbox__input { + right: -10000px; +} +.tox[dir='rtl'] .tox-bar .tox-checkbox { + margin-right: 4px; +} +.tox .tox-collection--toolbar .tox-collection__group { + display: flex; + padding: 0; +} +.tox .tox-collection--grid .tox-collection__group { + display: flex; + flex-wrap: wrap; + max-height: 208px; + overflow-x: hidden; + overflow-y: auto; + padding: 0; +} +.tox .tox-collection--list .tox-collection__group { + border-bottom-width: 0; + border-color: #1a1a1a; + border-left-width: 0; + border-right-width: 0; + border-style: solid; + border-top-width: 1px; + padding: 4px 0; +} +.tox .tox-collection--list .tox-collection__group:first-child { + border-top-width: 0; +} +.tox .tox-collection__group-heading { + background-color: #333; + color: #fff; + cursor: default; + font-size: 12px; + font-style: normal; + font-weight: 400; + margin-bottom: 4px; + margin-top: -4px; + padding: 4px 8px; + text-transform: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.tox .tox-collection__item { + align-items: center; + border-radius: 3px; + color: #fff; + display: flex; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.tox .tox-collection--list .tox-collection__item { + padding: 4px 8px; +} +.tox .tox-collection--toolbar .tox-collection__item { + border-radius: 3px; + padding: 4px; +} +.tox .tox-collection--grid .tox-collection__item { + border-radius: 3px; + padding: 4px; +} +.tox .tox-collection--list .tox-collection__item--enabled { + background-color: #2b3b4e; + color: #fff; +} +.tox .tox-collection--list .tox-collection__item--active { + background-color: #4a5562; +} +.tox .tox-collection--toolbar .tox-collection__item--enabled { + background-color: #757d87; + color: #fff; +} +.tox .tox-collection--toolbar .tox-collection__item--active { + background-color: #4a5562; +} +.tox .tox-collection--grid .tox-collection__item--enabled { + background-color: #757d87; + color: #fff; +} +.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + background-color: #4a5562; + color: #fff; +} +.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #fff; +} +.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #fff; +} +.tox .tox-collection__item-checkmark, +.tox .tox-collection__item-icon { + align-items: center; + display: flex; + height: 24px; + justify-content: center; + width: 24px; +} +.tox .tox-collection__item-checkmark svg, +.tox .tox-collection__item-icon svg { + fill: currentColor; +} +.tox .tox-collection--toolbar-lg .tox-collection__item-icon { + height: 48px; + width: 48px; +} +.tox .tox-collection__item-label { + color: currentColor; + display: inline-block; + flex: 1; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 24px; + text-transform: none; + word-break: break-all; +} +.tox .tox-collection__item-accessory { + color: rgba(255, 255, 255, 0.5); + display: inline-block; + font-size: 14px; + height: 24px; + line-height: 24px; + text-transform: none; +} +.tox .tox-collection__item-caret { + align-items: center; + display: flex; + min-height: 24px; +} +.tox .tox-collection__item-caret::after { + content: ''; + font-size: 0; + min-height: inherit; +} +.tox .tox-collection__item-caret svg { + fill: #fff; +} +.tox .tox-collection__item--state-disabled { + background-color: transparent; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox + .tox-collection--list + .tox-collection__item:not(.tox-collection__item--enabled) + .tox-collection__item-checkmark + svg { + display: none; +} +.tox + .tox-collection--list + .tox-collection__item:not(.tox-collection__item--enabled) + .tox-collection__item-accessory + + .tox-collection__item-checkmark { + display: none; +} +.tox .tox-collection--horizontal { + background-color: #2b3b4e; + border: 1px solid #1a1a1a; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(42, 55, 70, 0.2), 0 4px 8px 0 rgba(42, 55, 70, 0.15); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: nowrap; + margin-bottom: 0; + overflow-x: auto; + padding: 0; +} +.tox .tox-collection--horizontal .tox-collection__group { + align-items: center; + display: flex; + flex-wrap: nowrap; + margin: 0; + padding: 0 4px; +} +.tox .tox-collection--horizontal .tox-collection__item { + height: 34px; + margin: 3px 0 2px 0; + padding: 0 4px; +} +.tox .tox-collection--horizontal .tox-collection__item-label { + white-space: nowrap; +} +.tox .tox-collection--horizontal .tox-collection__item-caret { + margin-left: 4px; +} +.tox .tox-collection__item-container { + display: flex; +} +.tox .tox-collection__item-container--row { + align-items: center; + flex: 1 1 auto; + flex-direction: row; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--align-left { + margin-right: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--align-right { + justify-content: flex-end; + margin-left: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { + align-items: flex-start; + margin-bottom: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { + align-items: center; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { + align-items: flex-end; + margin-top: auto; +} +.tox .tox-collection__item-container--column { + align-self: center; + flex: 1 1 auto; + flex-direction: column; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--align-left { + align-items: flex-start; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--align-right { + align-items: flex-end; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { + align-self: flex-start; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { + align-self: center; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { + align-self: flex-end; +} +.tox:not([dir='rtl']) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-right: 1px solid #000; +} +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > :not(:first-child) { + margin-left: 8px; +} +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-collection__item-accessory { + margin-left: 16px; + text-align: right; +} +.tox:not([dir='rtl']) .tox-collection .tox-collection__item-caret { + margin-left: 16px; +} +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-left: 1px solid #000; +} +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > :not(:first-child) { + margin-right: 8px; +} +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-collection__item-accessory { + margin-right: 16px; + text-align: left; +} +.tox[dir='rtl'] .tox-collection .tox-collection__item-caret { + margin-right: 16px; + transform: rotateY(180deg); +} +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__item-caret { + margin-right: 4px; +} +.tox .tox-color-picker-container { + display: flex; + flex-direction: row; + height: 225px; + margin: 0; +} +.tox .tox-sv-palette { + box-sizing: border-box; + display: flex; + height: 100%; +} +.tox .tox-sv-palette-spectrum { + height: 100%; +} +.tox .tox-sv-palette, +.tox .tox-sv-palette-spectrum { + width: 225px; +} +.tox .tox-sv-palette-thumb { + background: 0 0; + border: 1px solid #000; + border-radius: 50%; + box-sizing: content-box; + height: 12px; + position: absolute; + width: 12px; +} +.tox .tox-sv-palette-inner-thumb { + border: 1px solid #fff; + border-radius: 50%; + height: 10px; + position: absolute; + width: 10px; +} +.tox .tox-hue-slider { + box-sizing: border-box; + height: 100%; + width: 25px; +} +.tox .tox-hue-slider-spectrum { + background: linear-gradient( + to bottom, + red, + #ff0080, + #f0f, + #8000ff, + #00f, + #0080ff, + #0ff, + #00ff80, + #0f0, + #80ff00, + #ff0, + #ff8000, + red + ); + height: 100%; + width: 100%; +} +.tox .tox-hue-slider, +.tox .tox-hue-slider-spectrum { + width: 20px; +} +.tox .tox-hue-slider-thumb { + background: #fff; + border: 1px solid #000; + box-sizing: content-box; + height: 4px; + width: 100%; +} +.tox .tox-rgb-form { + display: flex; + flex-direction: column; + justify-content: space-between; +} +.tox .tox-rgb-form div { + align-items: center; + display: flex; + justify-content: space-between; + margin-bottom: 5px; + width: inherit; +} +.tox .tox-rgb-form input { + width: 6em; +} +.tox .tox-rgb-form input.tox-invalid { + border: 1px solid red !important; +} +.tox .tox-rgb-form .tox-rgba-preview { + border: 1px solid #000; + flex-grow: 2; + margin-bottom: 0; +} +.tox:not([dir='rtl']) .tox-sv-palette { + margin-right: 15px; +} +.tox:not([dir='rtl']) .tox-hue-slider { + margin-right: 15px; +} +.tox:not([dir='rtl']) .tox-hue-slider-thumb { + margin-left: -1px; +} +.tox:not([dir='rtl']) .tox-rgb-form label { + margin-right: 0.5em; +} +.tox[dir='rtl'] .tox-sv-palette { + margin-left: 15px; +} +.tox[dir='rtl'] .tox-hue-slider { + margin-left: 15px; +} +.tox[dir='rtl'] .tox-hue-slider-thumb { + margin-right: -1px; +} +.tox[dir='rtl'] .tox-rgb-form label { + margin-left: 0.5em; +} +.tox .tox-toolbar .tox-swatches, +.tox .tox-toolbar__overflow .tox-swatches, +.tox .tox-toolbar__primary .tox-swatches { + margin: 2px 0 3px 4px; +} +.tox .tox-collection--list .tox-collection__group .tox-swatches-menu { + border: 0; + margin: -4px 0; +} +.tox .tox-swatches__row { + display: flex; +} +.tox .tox-swatch { + height: 30px; + transition: transform 0.15s, box-shadow 0.15s; + width: 30px; +} +.tox .tox-swatch:focus, +.tox .tox-swatch:hover { + box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; + transform: scale(0.8); +} +.tox .tox-swatch--remove { + align-items: center; + display: flex; + justify-content: center; +} +.tox .tox-swatch--remove svg path { + stroke: #e74c3c; +} +.tox .tox-swatches__picker-btn { + align-items: center; + background-color: transparent; + border: 0; + cursor: pointer; + display: flex; + height: 30px; + justify-content: center; + outline: 0; + padding: 0; + width: 30px; +} +.tox .tox-swatches__picker-btn svg { + fill: #fff; + height: 24px; + width: 24px; +} +.tox .tox-swatches__picker-btn:hover { + background: #4a5562; +} +.tox:not([dir='rtl']) .tox-swatches__picker-btn { + margin-left: auto; +} +.tox[dir='rtl'] .tox-swatches__picker-btn { + margin-right: auto; +} +.tox .tox-comment-thread { + background: #2b3b4e; + position: relative; +} +.tox .tox-comment-thread > :not(:first-child) { + margin-top: 8px; +} +.tox .tox-comment { + background: #2b3b4e; + border: 1px solid #000; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(42, 55, 70, 0.1); + padding: 8px 8px 16px 8px; + position: relative; +} +.tox .tox-comment__header { + align-items: center; + color: #fff; + display: flex; + justify-content: space-between; +} +.tox .tox-comment__date { + color: rgba(255, 255, 255, 0.5); + font-size: 12px; +} +.tox .tox-comment__body { + color: #fff; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + margin-top: 8px; + position: relative; + text-transform: initial; +} +.tox .tox-comment__body textarea { + resize: none; + white-space: normal; + width: 100%; +} +.tox .tox-comment__expander { + padding-top: 8px; +} +.tox .tox-comment__expander p { + color: rgba(255, 255, 255, 0.5); + font-size: 14px; + font-style: normal; +} +.tox .tox-comment__body p { + margin: 0; +} +.tox .tox-comment__buttonspacing { + padding-top: 16px; + text-align: center; +} +.tox .tox-comment-thread__overlay::after { + background: #2b3b4e; + bottom: 0; + content: ''; + display: flex; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + top: 0; + z-index: 5; +} +.tox .tox-comment__reply { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 8px; +} +.tox .tox-comment__reply > :first-child { + margin-bottom: 8px; + width: 100%; +} +.tox .tox-comment__edit { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 16px; +} +.tox .tox-comment__gradient::after { + background: linear-gradient(rgba(43, 59, 78, 0), #2b3b4e); + bottom: 0; + content: ''; + display: block; + height: 5em; + margin-top: -40px; + position: absolute; + width: 100%; +} +.tox .tox-comment__overlay { + background: #2b3b4e; + bottom: 0; + display: flex; + flex-direction: column; + flex-grow: 1; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + text-align: center; + top: 0; + z-index: 5; +} +.tox .tox-comment__loading-text { + align-items: center; + color: #fff; + display: flex; + flex-direction: column; + position: relative; +} +.tox .tox-comment__loading-text > div { + padding-bottom: 16px; +} +.tox .tox-comment__overlaytext { + bottom: 0; + flex-direction: column; + font-size: 14px; + left: 0; + padding: 1em; + position: absolute; + right: 0; + top: 0; + z-index: 10; +} +.tox .tox-comment__overlaytext p { + background-color: #2b3b4e; + box-shadow: 0 0 8px 8px #2b3b4e; + color: #fff; + text-align: center; +} +.tox .tox-comment__overlaytext div:nth-of-type(2) { + font-size: 0.8em; +} +.tox .tox-comment__busy-spinner { + align-items: center; + background-color: #2b3b4e; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 20; +} +.tox .tox-comment__scroll { + display: flex; + flex-direction: column; + flex-shrink: 1; + overflow: auto; +} +.tox .tox-conversations { + margin: 8px; +} +.tox:not([dir='rtl']) .tox-comment__edit { + margin-left: 8px; +} +.tox:not([dir='rtl']) .tox-comment__buttonspacing > :last-child, +.tox:not([dir='rtl']) .tox-comment__edit > :last-child, +.tox:not([dir='rtl']) .tox-comment__reply > :last-child { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-comment__edit { + margin-right: 8px; +} +.tox[dir='rtl'] .tox-comment__buttonspacing > :last-child, +.tox[dir='rtl'] .tox-comment__edit > :last-child, +.tox[dir='rtl'] .tox-comment__reply > :last-child { + margin-right: 8px; +} +.tox .tox-user { + align-items: center; + display: flex; +} +.tox .tox-user__avatar svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-user__name { + color: rgba(255, 255, 255, 0.5); + font-size: 12px; + font-style: normal; + font-weight: 700; + text-transform: uppercase; +} +.tox:not([dir='rtl']) .tox-user__avatar svg { + margin-right: 8px; +} +.tox:not([dir='rtl']) .tox-user__avatar + .tox-user__name { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-user__avatar svg { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-user__avatar + .tox-user__name { + margin-right: 8px; +} +.tox .tox-dialog-wrap { + align-items: center; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 1100; +} +.tox .tox-dialog-wrap__backdrop { + background-color: rgba(34, 47, 62, 0.75); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} +.tox .tox-dialog-wrap__backdrop--opaque { + background-color: #222f3e; +} +.tox .tox-dialog { + background-color: #2b3b4e; + border-color: #000; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: 0 16px 16px -10px rgba(42, 55, 70, 0.15), 0 0 40px 1px rgba(42, 55, 70, 0.15); + display: flex; + flex-direction: column; + max-height: 100%; + max-width: 480px; + overflow: hidden; + position: relative; + width: 95vw; + z-index: 2; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog { + align-self: flex-start; + margin: 8px auto; + width: calc(100vw - 16px); + } +} +.tox .tox-dialog-inline { + z-index: 1100; +} +.tox .tox-dialog__header { + align-items: center; + background-color: #2b3b4e; + border-bottom: none; + color: #fff; + display: flex; + font-size: 16px; + justify-content: space-between; + padding: 8px 16px 0 16px; + position: relative; +} +.tox .tox-dialog__header .tox-button { + z-index: 1; +} +.tox .tox-dialog__draghandle { + cursor: grab; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tox .tox-dialog__draghandle:active { + cursor: grabbing; +} +.tox .tox-dialog__dismiss { + margin-left: auto; +} +.tox .tox-dialog__title { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 20px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + margin: 0; + text-transform: none; +} +.tox .tox-dialog__body { + color: #fff; + display: flex; + flex: 1; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + min-width: 0; + text-align: left; + text-transform: none; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body { + flex-direction: column; + } +} +.tox .tox-dialog__body-nav { + align-items: flex-start; + display: flex; + flex-direction: column; + padding: 16px 16px; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { + flex-direction: row; + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding-bottom: 0; + } +} +.tox .tox-dialog__body-nav-item { + border-bottom: 2px solid transparent; + color: rgba(255, 255, 255, 0.5); + display: inline-block; + font-size: 14px; + line-height: 1.3; + margin-bottom: 8px; + text-decoration: none; + white-space: nowrap; +} +.tox .tox-dialog__body-nav-item:focus { + background-color: rgba(32, 122, 183, 0.1); +} +.tox .tox-dialog__body-nav-item--active { + border-bottom: 2px solid #207ab7; + color: #207ab7; +} +.tox .tox-dialog__body-content { + box-sizing: border-box; + display: flex; + flex: 1; + flex-direction: column; + max-height: 650px; + overflow: auto; + -webkit-overflow-scrolling: touch; + padding: 16px 16px; +} +.tox .tox-dialog__body-content > * { + margin-bottom: 0; + margin-top: 16px; +} +.tox .tox-dialog__body-content > :first-child { + margin-top: 0; +} +.tox .tox-dialog__body-content > :last-child { + margin-bottom: 0; +} +.tox .tox-dialog__body-content > :only-child { + margin-bottom: 0; + margin-top: 0; +} +.tox .tox-dialog__body-content a { + color: #207ab7; + cursor: pointer; + text-decoration: none; +} +.tox .tox-dialog__body-content a:focus, +.tox .tox-dialog__body-content a:hover { + color: #185d8c; + text-decoration: none; +} +.tox .tox-dialog__body-content a:active { + color: #185d8c; + text-decoration: none; +} +.tox .tox-dialog__body-content svg { + fill: #fff; +} +.tox .tox-dialog__body-content ul { + display: block; + list-style-type: disc; + margin-bottom: 16px; + margin-inline-end: 0; + margin-inline-start: 0; + padding-inline-start: 2.5rem; +} +.tox .tox-dialog__body-content .tox-form__group h1 { + color: #fff; + font-size: 20px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} +.tox .tox-dialog__body-content .tox-form__group h2 { + color: #fff; + font-size: 16px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} +.tox .tox-dialog__body-content .tox-form__group p { + margin-bottom: 16px; +} +.tox .tox-dialog__body-content .tox-form__group h1:first-child, +.tox .tox-dialog__body-content .tox-form__group h2:first-child, +.tox .tox-dialog__body-content .tox-form__group p:first-child { + margin-top: 0; +} +.tox .tox-dialog__body-content .tox-form__group h1:last-child, +.tox .tox-dialog__body-content .tox-form__group h2:last-child, +.tox .tox-dialog__body-content .tox-form__group p:last-child { + margin-bottom: 0; +} +.tox .tox-dialog__body-content .tox-form__group h1:only-child, +.tox .tox-dialog__body-content .tox-form__group h2:only-child, +.tox .tox-dialog__body-content .tox-form__group p:only-child { + margin-bottom: 0; + margin-top: 0; +} +.tox .tox-dialog--width-lg { + height: 650px; + max-width: 1200px; +} +.tox .tox-dialog--width-md { + max-width: 800px; +} +.tox .tox-dialog--width-md .tox-dialog__body-content { + overflow: auto; +} +.tox .tox-dialog__body-content--centered { + text-align: center; +} +.tox .tox-dialog__footer { + align-items: center; + background-color: #2b3b4e; + border-top: 1px solid #000; + display: flex; + justify-content: space-between; + padding: 8px 16px; +} +.tox .tox-dialog__footer-end, +.tox .tox-dialog__footer-start { + display: flex; +} +.tox .tox-dialog__busy-spinner { + align-items: center; + background-color: rgba(34, 47, 62, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 3; +} +.tox .tox-dialog__table { + border-collapse: collapse; + width: 100%; +} +.tox .tox-dialog__table thead th { + font-weight: 700; + padding-bottom: 8px; +} +.tox .tox-dialog__table tbody tr { + border-bottom: 1px solid #000; +} +.tox .tox-dialog__table tbody tr:last-child { + border-bottom: none; +} +.tox .tox-dialog__table td { + padding-bottom: 8px; + padding-top: 8px; +} +.tox .tox-dialog__popups { + position: absolute; + width: 100%; + z-index: 1100; +} +.tox .tox-dialog__body-iframe { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-dialog__body-iframe .tox-navobj { + display: flex; + flex: 1; +} +.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} +.tox .tox-dialog-dock-fadeout { + opacity: 0; + visibility: hidden; +} +.tox .tox-dialog-dock-fadein { + opacity: 1; + visibility: visible; +} +.tox .tox-dialog-dock-transition { + transition: visibility 0s linear 0.3s, opacity 0.3s ease; +} +.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { + transition-delay: 0s; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav { + margin-right: 0; + } +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav-item:not(:first-child) { + margin-left: 8px; + } +} +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-end > *, +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-start > * { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-dialog__body { + text-align: right; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav { + margin-left: 0; + } +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav-item:not(:first-child) { + margin-right: 8px; + } +} +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-end > *, +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-start > * { + margin-right: 8px; +} +body.tox-dialog__disable-scroll { + overflow: hidden; +} +.tox .tox-dropzone-container { + display: flex; + flex: 1; +} +.tox .tox-dropzone { + align-items: center; + background: #fff; + border: 2px dashed #000; + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-grow: 1; + justify-content: center; + min-height: 100px; + padding: 10px; +} +.tox .tox-dropzone p { + color: rgba(255, 255, 255, 0.5); + margin: 0 0 16px 0; +} +.tox .tox-edit-area { + display: flex; + flex: 1; + overflow: hidden; + position: relative; +} +.tox .tox-edit-area__iframe { + background-color: #fff; + border: 0; + box-sizing: border-box; + flex: 1; + height: 100%; + position: absolute; + width: 100%; +} +.tox.tox-inline-edit-area { + border: 1px dotted #000; +} +.tox .tox-editor-container { + display: flex; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} +.tox .tox-editor-header { + z-index: 1; +} +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: #222f3e; + border-bottom: none; + box-shadow: none; + padding: 4px 0; + transition: box-shadow 0.5s; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: 1px solid #000; + box-shadow: none; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: #222f3e; + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); + padding: 4px 0; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); +} +.tox-editor-dock-fadeout { + opacity: 0; + visibility: hidden; +} +.tox-editor-dock-fadein { + opacity: 1; + visibility: visible; +} +.tox-editor-dock-transition { + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} +.tox-editor-dock-transition.tox-editor-dock-fadein { + transition-delay: 0s; +} +.tox .tox-control-wrap { + flex: 1; + position: relative; +} +.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, +.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, +.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { + display: none; +} +.tox .tox-control-wrap svg { + display: block; +} +.tox .tox-control-wrap__status-icon-wrap { + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-control-wrap__status-icon-invalid svg { + fill: #c00; +} +.tox .tox-control-wrap__status-icon-unknown svg { + fill: orange; +} +.tox .tox-control-wrap__status-icon-valid svg { + fill: green; +} +.tox:not([dir='rtl']) .tox-control-wrap--status-invalid .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-unknown .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-valid .tox-textfield { + padding-right: 32px; +} +.tox:not([dir='rtl']) .tox-control-wrap__status-icon-wrap { + right: 4px; +} +.tox[dir='rtl'] .tox-control-wrap--status-invalid .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-unknown .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-valid .tox-textfield { + padding-left: 32px; +} +.tox[dir='rtl'] .tox-control-wrap__status-icon-wrap { + left: 4px; +} +.tox .tox-autocompleter { + max-width: 25em; +} +.tox .tox-autocompleter .tox-menu { + border-color: #000; + box-shadow: none; + max-width: 25em; +} +.tox .tox-autocompleter .tox-autocompleter-highlight { + font-weight: 700; +} +.tox .tox-color-input { + display: flex; + position: relative; + z-index: 1; +} +.tox .tox-color-input .tox-textfield { + z-index: -1; +} +.tox .tox-color-input span { + border-color: rgba(42, 55, 70, 0.2); + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + height: 24px; + position: absolute; + top: 6px; + width: 24px; +} +.tox .tox-color-input span:focus:not([aria-disabled='true']), +.tox .tox-color-input span:hover:not([aria-disabled='true']) { + border-color: #207ab7; + cursor: pointer; +} +.tox .tox-color-input span::before { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), + linear-gradient(-45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%), + linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%); + background-position: 0 0, 0 6px, 6px -6px, -6px 0; + background-size: 12px 12px; + border: 1px solid #2b3b4e; + border-radius: 3px; + box-sizing: border-box; + content: ''; + height: 24px; + left: -1px; + position: absolute; + top: -1px; + width: 24px; + z-index: -1; +} +.tox .tox-color-input span[aria-disabled='true'] { + cursor: not-allowed; +} +.tox:not([dir='rtl']) .tox-color-input .tox-textfield { + padding-left: 36px; +} +.tox:not([dir='rtl']) .tox-color-input span { + left: 6px; +} +.tox[dir='rtl'] .tox-color-input .tox-textfield { + padding-right: 36px; +} +.tox[dir='rtl'] .tox-color-input span { + right: 6px; +} +.tox .tox-label, +.tox .tox-toolbar-label { + color: rgba(255, 255, 255, 0.5); + display: block; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + padding: 0 8px 0 0; + text-transform: none; + white-space: nowrap; +} +.tox .tox-toolbar-label { + padding: 0 8px; +} +.tox[dir='rtl'] .tox-label { + padding: 0 0 0 8px; +} +.tox .tox-form { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-form__group { + box-sizing: border-box; + margin-bottom: 4px; +} +.tox .tox-form-group--maximize { + flex: 1; +} +.tox .tox-form__group--error { + color: #c00; +} +.tox .tox-form__group--collection { + display: flex; +} +.tox .tox-form__grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} +.tox .tox-form__grid--2col > .tox-form__group { + width: calc(50% - (8px / 2)); +} +.tox .tox-form__grid--3col > .tox-form__group { + width: calc(100% / 3 - (8px / 2)); +} +.tox .tox-form__grid--4col > .tox-form__group { + width: calc(25% - (8px / 2)); +} +.tox .tox-form__controls-h-stack { + align-items: center; + display: flex; +} +.tox .tox-form__group--inline { + align-items: center; + display: flex; +} +.tox .tox-form__group--stretched { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-form__group--stretched .tox-textarea { + flex: 1; +} +.tox .tox-form__group--stretched .tox-navobj { + display: flex; + flex: 1; +} +.tox .tox-form__group--stretched .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} +.tox:not([dir='rtl']) .tox-form__controls-h-stack > :not(:first-child) { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-form__controls-h-stack > :not(:first-child) { + margin-right: 4px; +} +.tox .tox-lock.tox-locked .tox-lock-icon__unlock, +.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { + display: none; +} +.tox .tox-listboxfield .tox-listbox--select, +.tox .tox-textarea, +.tox .tox-textfield, +.tox .tox-toolbar-textfield { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #2b3b4e; + border-color: #000; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: 0; + padding: 5px 4.75px; + resize: none; + width: 100%; +} +.tox .tox-textarea[disabled], +.tox .tox-textfield[disabled] { + background-color: #222f3e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} +.tox .tox-listboxfield .tox-listbox--select:focus, +.tox .tox-textarea:focus, +.tox .tox-textfield:focus { + background-color: #2b3b4e; + border-color: #207ab7; + box-shadow: none; + outline: 2px solid rgba(32, 122, 183, 0.25); +} +.tox .tox-toolbar-textfield { + border-width: 0; + margin-bottom: 3px; + margin-top: 2px; + max-width: 250px; +} +.tox .tox-naked-btn { + background-color: transparent; + border: 0; + border-color: transparent; + box-shadow: unset; + color: #207ab7; + cursor: pointer; + display: block; + margin: 0; + padding: 0; +} +.tox .tox-naked-btn svg { + display: block; + fill: #fff; +} +.tox:not([dir='rtl']) .tox-toolbar-textfield + * { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-toolbar-textfield + * { + margin-right: 4px; +} +.tox .tox-listboxfield { + cursor: pointer; + position: relative; +} +.tox .tox-listboxfield .tox-listbox--select[disabled] { + background-color: #19232e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} +.tox .tox-listbox__select-label { + cursor: default; + flex: 1; + margin: 0 4px; +} +.tox .tox-listbox__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} +.tox .tox-listbox__select-chevron svg { + fill: #fff; +} +.tox .tox-listboxfield .tox-listbox--select { + align-items: center; + display: flex; +} +.tox:not([dir='rtl']) .tox-listboxfield svg { + right: 8px; +} +.tox[dir='rtl'] .tox-listboxfield svg { + left: 8px; +} +.tox .tox-selectfield { + cursor: pointer; + position: relative; +} +.tox .tox-selectfield select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #2b3b4e; + border-color: #000; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: 0; + padding: 5px 4.75px; + resize: none; + width: 100%; +} +.tox .tox-selectfield select[disabled] { + background-color: #19232e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} +.tox .tox-selectfield select::-ms-expand { + display: none; +} +.tox .tox-selectfield select:focus { + background-color: #2b3b4e; + border-color: #207ab7; + box-shadow: none; + outline: 2px solid rgba(32, 122, 183, 0.25); +} +.tox .tox-selectfield svg { + pointer-events: none; + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox:not([dir='rtl']) .tox-selectfield select[size='0'], +.tox:not([dir='rtl']) .tox-selectfield select[size='1'] { + padding-right: 24px; +} +.tox:not([dir='rtl']) .tox-selectfield svg { + right: 8px; +} +.tox[dir='rtl'] .tox-selectfield select[size='0'], +.tox[dir='rtl'] .tox-selectfield select[size='1'] { + padding-left: 24px; +} +.tox[dir='rtl'] .tox-selectfield svg { + left: 8px; +} +.tox .tox-textarea { + -webkit-appearance: textarea; + -moz-appearance: textarea; + appearance: textarea; + white-space: pre-wrap; +} +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} +.tox-shadowhost.tox-fullscreen, +.tox.tox-tinymce.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} +.tox .tox-help__more-link { + list-style: none; + margin-top: 1em; +} +.tox .tox-imagepreview { + background-color: #666; + height: 380px; + overflow: hidden; + position: relative; + width: 100%; +} +.tox .tox-imagepreview.tox-imagepreview__loaded { + overflow: auto; +} +.tox .tox-imagepreview__container { + display: flex; + left: 100vw; + position: absolute; + top: 100vw; +} +.tox .tox-imagepreview__image { + background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); +} +.tox .tox-image-tools .tox-spacer { + flex: 1; +} +.tox .tox-image-tools .tox-bar { + align-items: center; + display: flex; + height: 60px; + justify-content: center; +} +.tox .tox-image-tools .tox-imagepreview, +.tox .tox-image-tools .tox-imagepreview + .tox-bar { + margin-top: 8px; +} +.tox .tox-image-tools .tox-croprect-block { + background: #000; + opacity: 0.5; + position: absolute; + zoom: 1; +} +.tox .tox-image-tools .tox-croprect-handle { + border: 2px solid #fff; + height: 20px; + left: 0; + position: absolute; + top: 0; + width: 20px; +} +.tox .tox-image-tools .tox-croprect-handle-move { + border: 0; + cursor: move; + position: absolute; +} +.tox .tox-image-tools .tox-croprect-handle-nw { + border-width: 2px 0 0 2px; + cursor: nw-resize; + left: 100px; + margin: -2px 0 0 -2px; + top: 100px; +} +.tox .tox-image-tools .tox-croprect-handle-ne { + border-width: 2px 2px 0 0; + cursor: ne-resize; + left: 200px; + margin: -2px 0 0 -20px; + top: 100px; +} +.tox .tox-image-tools .tox-croprect-handle-sw { + border-width: 0 0 2px 2px; + cursor: sw-resize; + left: 100px; + margin: -20px 2px 0 -2px; + top: 200px; +} +.tox .tox-image-tools .tox-croprect-handle-se { + border-width: 0 2px 2px 0; + cursor: se-resize; + left: 200px; + margin: -20px 0 0 -20px; + top: 200px; +} +.tox .tox-insert-table-picker { + display: flex; + flex-wrap: wrap; + width: 170px; +} +.tox .tox-insert-table-picker > div { + border-color: #000; + border-style: solid; + border-width: 0 1px 1px 0; + box-sizing: border-box; + height: 17px; + width: 17px; +} +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: 0 -4px; +} +.tox .tox-insert-table-picker .tox-insert-table-picker__selected { + background-color: rgba(32, 122, 183, 0.5); + border-color: rgba(32, 122, 183, 0.5); +} +.tox .tox-insert-table-picker__label { + color: #fff; + display: block; + font-size: 14px; + padding: 4px; + text-align: center; + width: 100%; +} +.tox:not([dir='rtl']) .tox-insert-table-picker > div:nth-child(10n) { + border-right: 0; +} +.tox[dir='rtl'] .tox-insert-table-picker > div:nth-child(10n + 1) { + border-right: 0; +} +.tox .tox-menu { + background-color: #2b3b4e; + border: 1px solid #000; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(42, 55, 70, 0.1); + display: inline-block; + overflow: hidden; + vertical-align: top; + z-index: 1150; +} +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0 0; +} +.tox .tox-menu.tox-collection.tox-collection--toolbar { + padding: 4px; +} +.tox .tox-menu.tox-collection.tox-collection--grid { + padding: 4px; +} +.tox .tox-menu__label blockquote, +.tox .tox-menu__label code, +.tox .tox-menu__label h1, +.tox .tox-menu__label h2, +.tox .tox-menu__label h3, +.tox .tox-menu__label h4, +.tox .tox-menu__label h5, +.tox .tox-menu__label h6, +.tox .tox-menu__label p { + margin: 0; +} +.tox .tox-menubar { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") + left 0 top 0 #222f3e; + background-color: #222f3e; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 4px 0 4px; +} +.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { + border-top: 1px solid #000; +} +.tox .tox-mbtn { + align-items: center; + background: 0 0; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: 400; + height: 34px; + justify-content: center; + margin: 2px 0 3px 0; + outline: 0; + overflow: hidden; + padding: 0 4px; + text-transform: none; + width: auto; +} +.tox .tox-mbtn[disabled] { + background-color: transparent; + border: 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-mbtn:focus:not(:disabled) { + background: #4a5562; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-mbtn--active { + background: #757d87; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { + background: #4a5562; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-mbtn__select-label { + cursor: default; + font-weight: 400; + margin: 0 4px; +} +.tox .tox-mbtn[disabled] .tox-mbtn__select-label { + cursor: not-allowed; +} +.tox .tox-mbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; + display: none; +} +.tox .tox-notification { + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + display: grid; + font-size: 14px; + font-weight: 400; + grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + margin-top: 4px; + opacity: 0; + padding: 4px; + transition: transform 0.1s ease-in, opacity 150ms ease-in; +} +.tox .tox-notification p { + font-size: 14px; + font-weight: 400; +} +.tox .tox-notification a { + cursor: pointer; + text-decoration: underline; +} +.tox .tox-notification--in { + opacity: 1; +} +.tox .tox-notification--success { + background-color: #334840; + border-color: #3c5440; + color: #fff; +} +.tox .tox-notification--success p { + color: #fff; +} +.tox .tox-notification--success a { + color: #b5d199; +} +.tox .tox-notification--success svg { + fill: #fff; +} +.tox .tox-notification--error { + background-color: #442632; + border-color: #55212b; + color: #fff; +} +.tox .tox-notification--error p { + color: #fff; +} +.tox .tox-notification--error a { + color: #e68080; +} +.tox .tox-notification--error svg { + fill: #fff; +} +.tox .tox-notification--warn, +.tox .tox-notification--warning { + background-color: #222f3e; + border-color: #000; + color: #fff0b3; +} +.tox .tox-notification--warn p, +.tox .tox-notification--warning p { + color: #fff0b3; +} +.tox .tox-notification--warn a, +.tox .tox-notification--warning a { + color: #fc0; +} +.tox .tox-notification--warn svg, +.tox .tox-notification--warning svg { + fill: #fff0b3; +} +.tox .tox-notification--info { + background-color: #254161; + border-color: #264972; + color: #fff; +} +.tox .tox-notification--info p { + color: #fff; +} +.tox .tox-notification--info a { + color: #83b7f3; +} +.tox .tox-notification--info svg { + fill: #fff; +} +.tox .tox-notification__body { + align-self: center; + color: #fff; + font-size: 14px; + grid-column-end: 3; + grid-column-start: 2; + grid-row-end: 2; + grid-row-start: 1; + text-align: center; + white-space: normal; + word-break: break-all; + word-break: break-word; +} +.tox .tox-notification__body > * { + margin: 0; +} +.tox .tox-notification__body > * + * { + margin-top: 1rem; +} +.tox .tox-notification__icon { + align-self: center; + grid-column-end: 2; + grid-column-start: 1; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} +.tox .tox-notification__icon svg { + display: block; +} +.tox .tox-notification__dismiss { + align-self: start; + grid-column-end: 4; + grid-column-start: 3; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} +.tox .tox-notification .tox-progress-bar { + grid-column-end: 4; + grid-column-start: 1; + grid-row-end: 3; + grid-row-start: 2; + justify-self: center; +} +.tox .tox-pop { + display: inline-block; + position: relative; +} +.tox .tox-pop--resizing { + transition: width 0.1s ease; +} +.tox .tox-pop--resizing .tox-toolbar, +.tox .tox-pop--resizing .tox-toolbar__group { + flex-wrap: nowrap; +} +.tox .tox-pop--transition { + transition: 0.15s ease; + transition-property: left, right, top, bottom; +} +.tox .tox-pop--transition::after, +.tox .tox-pop--transition::before { + transition: all 0.15s, visibility 0s, opacity 75ms ease 75ms; +} +.tox .tox-pop__dialog { + background-color: #222f3e; + border: 1px solid #000; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(42, 55, 70, 0.2), 0 4px 8px 0 rgba(42, 55, 70, 0.15); + min-width: 0; + overflow: hidden; +} +.tox .tox-pop__dialog > :not(.tox-toolbar) { + margin: 4px 4px 4px 8px; +} +.tox .tox-pop__dialog .tox-toolbar { + background-color: transparent; + margin-bottom: -1px; +} +.tox .tox-pop::after, +.tox .tox-pop::before { + border-style: solid; + content: ''; + display: block; + height: 0; + opacity: 1; + position: absolute; + width: 0; +} +.tox .tox-pop.tox-pop--inset::after, +.tox .tox-pop.tox-pop--inset::before { + opacity: 0; + transition: all 0s 0.15s, visibility 0s, opacity 75ms ease; +} +.tox .tox-pop.tox-pop--bottom::after, +.tox .tox-pop.tox-pop--bottom::before { + left: 50%; + top: 100%; +} +.tox .tox-pop.tox-pop--bottom::after { + border-color: #222f3e transparent transparent transparent; + border-width: 8px; + margin-left: -8px; + margin-top: -1px; +} +.tox .tox-pop.tox-pop--bottom::before { + border-color: #000 transparent transparent transparent; + border-width: 9px; + margin-left: -9px; +} +.tox .tox-pop.tox-pop--top::after, +.tox .tox-pop.tox-pop--top::before { + left: 50%; + top: 0; + transform: translateY(-100%); +} +.tox .tox-pop.tox-pop--top::after { + border-color: transparent transparent #222f3e transparent; + border-width: 8px; + margin-left: -8px; + margin-top: 1px; +} +.tox .tox-pop.tox-pop--top::before { + border-color: transparent transparent #000 transparent; + border-width: 9px; + margin-left: -9px; +} +.tox .tox-pop.tox-pop--left::after, +.tox .tox-pop.tox-pop--left::before { + left: 0; + top: calc(50% - 1px); + transform: translateY(-50%); +} +.tox .tox-pop.tox-pop--left::after { + border-color: transparent #222f3e transparent transparent; + border-width: 8px; + margin-left: -15px; +} +.tox .tox-pop.tox-pop--left::before { + border-color: transparent #000 transparent transparent; + border-width: 10px; + margin-left: -19px; +} +.tox .tox-pop.tox-pop--right::after, +.tox .tox-pop.tox-pop--right::before { + left: 100%; + top: calc(50% + 1px); + transform: translateY(-50%); +} +.tox .tox-pop.tox-pop--right::after { + border-color: transparent transparent transparent #222f3e; + border-width: 8px; + margin-left: -1px; +} +.tox .tox-pop.tox-pop--right::before { + border-color: transparent transparent transparent #000; + border-width: 10px; + margin-left: -1px; +} +.tox .tox-pop.tox-pop--align-left::after, +.tox .tox-pop.tox-pop--align-left::before { + left: 20px; +} +.tox .tox-pop.tox-pop--align-right::after, +.tox .tox-pop.tox-pop--align-right::before { + left: calc(100% - 20px); +} +.tox .tox-sidebar-wrap { + display: flex; + flex-direction: row; + flex-grow: 1; + min-height: 0; +} +.tox .tox-sidebar { + background-color: #222f3e; + display: flex; + flex-direction: row; + justify-content: flex-end; +} +.tox .tox-sidebar__slider { + display: flex; + overflow: hidden; +} +.tox .tox-sidebar__pane-container { + display: flex; +} +.tox .tox-sidebar__pane { + display: flex; +} +.tox .tox-sidebar--sliding-closed { + opacity: 0; +} +.tox .tox-sidebar--sliding-open { + opacity: 1; +} +.tox .tox-sidebar--sliding-growing, +.tox .tox-sidebar--sliding-shrinking { + transition: width 0.5s ease, opacity 0.5s ease; +} +.tox .tox-selector { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + display: inline-block; + height: 10px; + position: absolute; + width: 10px; +} +.tox.tox-platform-touch .tox-selector { + height: 12px; + width: 12px; +} +.tox .tox-slider { + align-items: center; + display: flex; + flex: 1; + height: 24px; + justify-content: center; + position: relative; +} +.tox .tox-slider__rail { + background-color: transparent; + border: 1px solid #000; + border-radius: 3px; + height: 10px; + min-width: 120px; + width: 100%; +} +.tox .tox-slider__handle { + background-color: #207ab7; + border: 2px solid #185d8c; + border-radius: 3px; + box-shadow: none; + height: 24px; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: 14px; +} +.tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { + margin-inline-start: 8px; +} +.tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { + margin-inline-start: 32px; +} +.tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { + margin-inline-start: 32px; +} +.tox .tox-source-code { + overflow: auto; +} +.tox .tox-spinner { + display: flex; +} +.tox .tox-spinner > div { + animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; + background-color: rgba(255, 255, 255, 0.5); + border-radius: 100%; + height: 8px; + width: 8px; +} +.tox .tox-spinner > div:nth-child(1) { + animation-delay: -0.32s; +} +.tox .tox-spinner > div:nth-child(2) { + animation-delay: -0.16s; +} +@keyframes tam-bouncing-dots { + 0%, + 100%, + 80% { + transform: scale(0); + } + 40% { + transform: scale(1); + } +} +.tox:not([dir='rtl']) .tox-spinner > div:not(:first-child) { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-spinner > div:not(:first-child) { + margin-right: 4px; +} +.tox .tox-statusbar { + align-items: center; + background-color: #222f3e; + border-top: 1px solid #000; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 12px; + font-weight: 400; + height: 18px; + overflow: hidden; + padding: 0 8px; + position: relative; + text-transform: uppercase; +} +.tox .tox-statusbar__text-container { + display: flex; + flex: 1 1 auto; + justify-content: flex-end; + overflow: hidden; +} +.tox .tox-statusbar__path { + display: flex; + flex: 1 1 auto; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.tox .tox-statusbar__path > * { + display: inline; + white-space: nowrap; +} +.tox .tox-statusbar__wordcount { + flex: 0 0 auto; + margin-left: 1ch; +} +.tox .tox-statusbar a, +.tox .tox-statusbar__path-item, +.tox .tox-statusbar__wordcount { + color: #fff; + text-decoration: none; +} +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']) { + color: #fff; + cursor: pointer; +} +.tox .tox-statusbar__branding svg { + fill: rgba(255, 255, 255, 0.8); + height: 1.14em; + vertical-align: -0.28em; + width: 3.6em; +} +.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled='true']) svg, +.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled='true']) svg { + fill: #fff; +} +.tox .tox-statusbar__resize-handle { + align-items: flex-end; + align-self: stretch; + cursor: nwse-resize; + display: flex; + flex: 0 0 auto; + justify-content: flex-end; + margin-left: auto; + margin-right: -8px; + padding-bottom: 3px; + padding-left: 1ch; + padding-right: 3px; +} +.tox .tox-statusbar__resize-handle svg { + display: block; + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-statusbar__resize-handle:focus svg { + background-color: #4a5562; + border-radius: 1px 1px -4px 1px; + box-shadow: 0 0 0 2px #4a5562; +} +.tox:not([dir='rtl']) .tox-statusbar__path > * { + margin-right: 4px; +} +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 2ch; +} +.tox[dir='rtl'] .tox-statusbar { + flex-direction: row-reverse; +} +.tox[dir='rtl'] .tox-statusbar__path > * { + margin-left: 4px; +} +.tox .tox-throbber { + z-index: 1299; +} +.tox .tox-throbber__busy-spinner { + align-items: center; + background-color: rgba(34, 47, 62, 0.6); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} +.tox .tox-tbtn { + align-items: center; + background: 0 0; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: 400; + height: 34px; + justify-content: center; + margin: 3px 0 2px 0; + outline: 0; + overflow: hidden; + padding: 0; + text-transform: none; + width: 34px; +} +.tox .tox-tbtn svg { + display: block; + fill: #fff; +} +.tox .tox-tbtn.tox-tbtn-more { + padding-left: 5px; + padding-right: 5px; + width: inherit; +} +.tox .tox-tbtn:focus { + background: #4a5562; + border: 0; + box-shadow: none; +} +.tox .tox-tbtn:hover { + background: #4a5562; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-tbtn:hover svg { + fill: #fff; +} +.tox .tox-tbtn:active { + background: #757d87; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-tbtn:active svg { + fill: #fff; +} +.tox .tox-tbtn--disabled, +.tox .tox-tbtn--disabled:hover, +.tox .tox-tbtn:disabled, +.tox .tox-tbtn:disabled:hover { + background: 0 0; + border: 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-tbtn--disabled svg, +.tox .tox-tbtn--disabled:hover svg, +.tox .tox-tbtn:disabled svg, +.tox .tox-tbtn:disabled:hover svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-tbtn--enabled, +.tox .tox-tbtn--enabled:hover { + background: #757d87; + border: 0; + box-shadow: none; + color: #fff; +} +.tox .tox-tbtn--enabled:hover > *, +.tox .tox-tbtn--enabled > * { + transform: none; +} +.tox .tox-tbtn--enabled svg, +.tox .tox-tbtn--enabled:hover svg { + fill: #fff; +} +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { + color: #fff; +} +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { + fill: #fff; +} +.tox .tox-tbtn:active > * { + transform: none; +} +.tox .tox-tbtn--md { + height: 51px; + width: 51px; +} +.tox .tox-tbtn--lg { + flex-direction: column; + height: 68px; + width: 68px; +} +.tox .tox-tbtn--return { + align-self: stretch; + height: unset; + width: 16px; +} +.tox .tox-tbtn--labeled { + padding: 0 4px; + width: unset; +} +.tox .tox-tbtn__vlabel { + display: block; + font-size: 10px; + font-weight: 400; + letter-spacing: -0.025em; + margin-bottom: 4px; + white-space: nowrap; +} +.tox .tox-tbtn--select { + margin: 3px 0 2px 0; + padding: 0 4px; + width: auto; +} +.tox .tox-tbtn__select-label { + cursor: default; + font-weight: 400; + margin: 0 4px; +} +.tox .tox-tbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} +.tox .tox-tbtn__select-chevron svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-tbtn--bespoke { + background: 0 0; +} +.tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { + margin-inline-start: 0; +} +.tox .tox-tbtn--bespoke .tox-tbtn__select-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 7em; +} +.tox .tox-split-button { + border: 0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + margin: 3px 0 2px 0; + overflow: hidden; +} +.tox .tox-split-button:hover { + box-shadow: 0 0 0 1px #4a5562 inset; +} +.tox .tox-split-button:focus { + background: #4a5562; + box-shadow: none; + color: #fff; +} +.tox .tox-split-button > * { + border-radius: 0; +} +.tox .tox-split-button__chevron { + width: 16px; +} +.tox .tox-split-button__chevron svg { + fill: rgba(255, 255, 255, 0.5); +} +.tox .tox-split-button .tox-tbtn { + margin: 0; +} +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, +.tox .tox-split-button.tox-tbtn--disabled:focus, +.tox .tox-split-button.tox-tbtn--disabled:hover { + background: 0 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} +.tox.tox-platform-touch .tox-split-button .tox-tbtn--select { + padding: 0 0; +} +.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { + width: 30px; +} +.tox.tox-platform-touch .tox-split-button__chevron { + width: 20px; +} +.tox .tox-toolbar-overlord { + background-color: #222f3e; +} +.tox .tox-toolbar, +.tox .tox-toolbar__overflow, +.tox .tox-toolbar__primary { + background-color: #222f3e; + background-image: repeating-linear-gradient(#000 0 1px, transparent 1px 39px); + background-position: center top 39px; + background-repeat: no-repeat; + background-size: calc(100% - 4px * 2) calc(100% - 39px); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 0; + transform: perspective(1px); +} +.tox .tox-toolbar-overlord > .tox-toolbar, +.tox .tox-toolbar-overlord > .tox-toolbar__overflow, +.tox .tox-toolbar-overlord > .tox-toolbar__primary { + background-position: center top 0; + background-size: calc(100% - 4px * 2) calc(100% - 0px); +} +.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { + height: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; + visibility: hidden; +} +.tox .tox-toolbar__overflow--growing { + transition: height 0.3s ease, opacity 0.2s linear 0.1s; +} +.tox .tox-toolbar__overflow--shrinking { + transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; +} +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: 1px solid #000; + margin-top: 0; + padding-bottom: 0; + padding-top: 0; +} +.tox .tox-toolbar--scrolling { + flex-wrap: nowrap; + overflow-x: auto; +} +.tox .tox-pop .tox-toolbar { + border-width: 0; +} +.tox .tox-toolbar--no-divider { + background-image: none; +} +.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, +.tox .tox-toolbar-overlord .tox-toolbar__primary { + background-position: center top 39px; +} +.tox .tox-editor-header > .tox-toolbar--scrolling, +.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { + background-image: none; +} +.tox.tox-tinymce-aux .tox-toolbar__overflow { + background-color: #222f3e; + background-position: center top 43px; + background-size: calc(100% - 8px * 2) calc(100% - 51px); + border: none; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(42, 55, 70, 0.2), 0 4px 8px 0 rgba(42, 55, 70, 0.15); + padding: 4px 0; +} +.tox-pop .tox-pop__dialog .tox-toolbar { + background-position: center top 43px; + background-size: calc(100% - 4px * 2) calc(100% - 51px); + padding: 4px 0; +} +.tox .tox-toolbar__group { + align-items: center; + display: flex; + flex-wrap: wrap; + margin: 0 0; + padding: 0 4px 0 4px; +} +.tox .tox-toolbar__group--pull-right { + margin-left: auto; +} +.tox .tox-toolbar--scrolling .tox-toolbar__group { + flex-shrink: 0; + flex-wrap: nowrap; +} +.tox:not([dir='rtl']) .tox-toolbar__group:not(:last-of-type) { + border-right: 1px solid #000; +} +.tox[dir='rtl'] .tox-toolbar__group:not(:last-of-type) { + border-left: 1px solid #000; +} +.tox .tox-tooltip { + display: inline-block; + padding: 8px; + position: relative; +} +.tox .tox-tooltip__body { + background-color: #3d546f; + border-radius: 3px; + box-shadow: 0 2px 4px rgba(42, 55, 70, 0.3); + color: rgba(255, 255, 255, 0.75); + font-size: 14px; + font-style: normal; + font-weight: 400; + padding: 4px 8px; + text-transform: none; +} +.tox .tox-tooltip__arrow { + position: absolute; +} +.tox .tox-tooltip--down .tox-tooltip__arrow { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #3d546f; + bottom: 0; + left: 50%; + position: absolute; + transform: translateX(-50%); +} +.tox .tox-tooltip--up .tox-tooltip__arrow { + border-bottom: 8px solid #3d546f; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + left: 50%; + position: absolute; + top: 0; + transform: translateX(-50%); +} +.tox .tox-tooltip--right .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-left: 8px solid #3d546f; + border-top: 8px solid transparent; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-tooltip--left .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-right: 8px solid #3d546f; + border-top: 8px solid transparent; + left: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-well { + border: 1px solid #000; + border-radius: 3px; + padding: 8px; + width: 100%; +} +.tox .tox-well > :first-child { + margin-top: 0; +} +.tox .tox-well > :last-child { + margin-bottom: 0; +} +.tox .tox-well > :only-child { + margin: 0; +} +.tox .tox-custom-editor { + border: 1px solid #000; + border-radius: 3px; + display: flex; + flex: 1; + position: relative; +} +.tox .tox-dialog-loading::before { + background-color: rgba(0, 0, 0, 0.5); + content: ''; + height: 100%; + position: absolute; + width: 100%; + z-index: 1000; +} +.tox .tox-tab { + cursor: pointer; +} +.tox .tox-dialog__content-js { + display: flex; + flex: 1; +} +.tox .tox-dialog__body-content .tox-collection { + display: flex; + flex: 1; +} +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: none; + padding: 0; +} +.tox.tox-tinymce--toolbar-bottom .tox-editor-header, +.tox.tox-tinymce-inline .tox-editor-header { + margin-bottom: -1px; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: none; + box-shadow: none; +} +.tox.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: transparent; + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); + padding: 0; +} +.tox.tox.tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); +} +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: -4px 0; +} +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0; +} +.tox .tox-pop { + box-shadow: none; +} +.tox .tox-split-button, +.tox .tox-tbtn, +.tox .tox-tbtn--select { + margin: 2px 0 3px 0; +} +.tox .tox-toolbar, +.tox .tox-toolbar__overflow, +.tox .tox-toolbar__primary { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") + left 0 top 0 #222f3e !important; +} +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: none; +} +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord .tox-toolbar__primary { + border-top: 1px solid #000; + margin-top: -1px; +} +.tox.tox-tinymce-aux .tox-toolbar__overflow { + border: 1px solid #000; + padding: 0; +} +.tox:not(.tox-tinymce-inline) + .tox-editor-header:not(:first-child) + .tox-toolbar-overlord:first-child + .tox-toolbar__primary, +.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child { + border-top: 1px solid #000; +} +.tox .tox-toolbar__group { + padding: 0 4px 0 4px; +} +.tox .tox-collection__item { + border-radius: 0; + cursor: pointer; +} +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']) { + color: #fff; + text-decoration: underline; +} +.tox .tox-statusbar__branding svg { + vertical-align: -0.25em; +} +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 1ch; +} +.tox .tox-statusbar__resize-handle { + padding-bottom: 0; + padding-right: 0; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.css new file mode 100644 index 00000000..8bf192d2 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.css @@ -0,0 +1,35 @@ +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen, +.tox-shadowhost.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css new file mode 100644 index 00000000..c1141c55 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css @@ -0,0 +1,30 @@ +body.tox-dialog__disable-scroll { + overflow: hidden; +} +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} +.tox-shadowhost.tox-fullscreen, +.tox.tox-tinymce.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.css new file mode 100644 index 00000000..b81f358d --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.css @@ -0,0 +1,869 @@ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; +} + +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} + +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*='language-'], +pre[class*='language-'] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} + +pre[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +code[class*='language-'] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*='language-']::selection, +pre[class*='language-'] ::selection, +code[class*='language-']::selection, +code[class*='language-'] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.token.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + /* This background color was intended by the author of this theme. */ + background: hsla(0, 0%, 100%, 0.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #dd4a68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable='false'] { + cursor: default; +} + +.mce-content-body *[contentEditable='true'] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} + +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #b4d7ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable='true']:focus, +.mce-content-body.mce-content-readonly *[contentEditable='true']:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*='border-width: 0px'], +.mce-item-table:not([border]), +.mce-item-table[border='0'], +table[style*='border-width: 0px'] td, +.mce-item-table:not([border]) td, +.mce-item-table[border='0'] td, +table[style*='border-width: 0px'] th, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border='0'] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) ul, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] ul, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} + +body { + font-family: sans-serif; +} + +table { + border-collapse: collapse; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.inline.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.inline.css new file mode 100644 index 00000000..e7acef31 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.inline.css @@ -0,0 +1,861 @@ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; +} + +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} + +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*='language-'], +pre[class*='language-'] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} + +pre[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +code[class*='language-'] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*='language-']::selection, +pre[class*='language-'] ::selection, +code[class*='language-']::selection, +code[class*='language-'] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.token.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + /* This background color was intended by the author of this theme. */ + background: hsla(0, 0%, 100%, 0.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #dd4a68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable='false'] { + cursor: default; +} + +.mce-content-body *[contentEditable='true'] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} + +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #b4d7ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'] *[contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable='true']:focus, +.mce-content-body.mce-content-readonly *[contentEditable='true']:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*='border-width: 0px'], +.mce-item-table:not([border]), +.mce-item-table[border='0'], +table[style*='border-width: 0px'] td, +.mce-item-table:not([border]) td, +.mce-item-table[border='0'] td, +table[style*='border-width: 0px'] th, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border='0'] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) ul, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] ul, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.inline.min.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.inline.min.css new file mode 100644 index 00000000..882dfd5b --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.inline.min.css @@ -0,0 +1,720 @@ +.mce-content-body .mce-item-anchor { + background: transparent + url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") + no-repeat center; +} +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} +code[class*='language-'], +pre[class*='language-'] { + color: #000; + background: 0 0; + text-shadow: 0 1px #fff; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} +code[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +pre[class*='language-']::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} +code[class*='language-'] ::selection, +code[class*='language-']::selection, +pre[class*='language-'] ::selection, +pre[class*='language-']::selection { + text-shadow: none; + background: #b3d4fc; +} +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} +.token.cdata, +.token.comment, +.token.doctype, +.token.prolog { + color: #708090; +} +.token.punctuation { + color: #999; +} +.token.namespace { + opacity: 0.7; +} +.token.boolean, +.token.constant, +.token.deleted, +.token.number, +.token.property, +.token.symbol, +.token.tag { + color: #905; +} +.token.attr-name, +.token.builtin, +.token.char, +.token.inserted, +.token.selector, +.token.string { + color: #690; +} +.language-css .token.string, +.style .token.string, +.token.entity, +.token.operator, +.token.url { + color: #9a6e3a; + background: hsla(0, 0%, 100%, 0.5); +} +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} +.token.class-name, +.token.function { + color: #dd4a68; +} +.token.important, +.token.regex, +.token.variable { + color: #e90; +} +.token.bold, +.token.important { + font-weight: 700; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} +.mce-content-body .mce-visual-caret { + background-color: #000; + background-color: currentColor; + position: absolute; +} +.mce-content-body .mce-visual-caret-hidden { + display: none; +} +.mce-content-body [data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} +.mce-content-body [contentEditable='false'] { + cursor: default; +} +.mce-content-body [contentEditable='true'] { + cursor: text; +} +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} +.mce-content-body figure.align-left { + float: left; +} +.mce-content-body figure.align-right { + float: right; +} +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} +.mce-object { + background: transparent + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') + no-repeat center; + border: 1px dashed #aaa; +} +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} +@media print { + .mce-pagebreak { + border: 0; + } +} +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} +.tiny-pageembed { + display: inline-block; + position: relative; +} +.tiny-pageembed--16by9, +.tiny-pageembed--1by1, +.tiny-pageembed--21by9, +.tiny-pageembed--4by3 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} +.tiny-pageembed--4by3 { + padding-top: 75%; +} +.tiny-pageembed--1by1 { + padding-top: 100%; +} +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--1by1 iframe, +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--4by3 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-content-body[data-mce-placeholder] { + position: relative; +} +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed #000; + position: absolute; + z-index: 10001; +} +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th { + border: 0; +} +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: #fff; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} +.tox-rtc-user-selection { + position: relative; +} +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: 700; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} +.tox-rtc-remote-image { + background: #eaeaea + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') + no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} +.mce-match-marker { + background: #aaa; + color: #fff; +} +.mce-match-marker-selected { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} +.mce-content-body audio[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body img[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body table[data-mce-selected], +.mce-content-body video[data-mce-selected] { + outline: 3px solid #b4d7ff; +} +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} +.mce-content-body.mce-content-readonly [contentEditable='true']:focus, +.mce-content-body.mce-content-readonly [contentEditable='true']:hover { + outline: 0; +} +.mce-content-body [data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} +.mce-content-body img::-moz-selection { + background: 0 0; +} +.mce-content-body img::selection { + background: 0 0; +} +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ephox-snooker-resizer-cols { + cursor: col-resize; +} +.ephox-snooker-resizer-rows { + cursor: row-resize; +} +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} +.mce-toc { + border: 1px solid gray; +} +.mce-toc h2 { + margin: 4px; +} +.mce-toc li { + list-style-type: none; +} +.mce-item-table:not([border]), +.mce-item-table:not([border]) caption, +.mce-item-table:not([border]) td, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'], +.mce-item-table[border='0'] caption, +.mce-item-table[border='0'] td, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'], +table[style*='border-width: 0px'] caption, +table[style*='border-width: 0px'] td, +table[style*='border-width: 0px'] th { + border: 1px dashed #bbb; +} +.mce-visualblocks address, +.mce-visualblocks article, +.mce-visualblocks aside, +.mce-visualblocks blockquote, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks dl, +.mce-visualblocks figcaption, +.mce-visualblocks figure, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks hgroup, +.mce-visualblocks ol, +.mce-visualblocks p, +.mce-visualblocks pre, +.mce-visualblocks section, +.mce-visualblocks ul { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) dl, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) ul { + margin-left: 3px; +} +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] dl, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] ul { + background-position-x: right; + margin-right: 3px; +} +.mce-nbsp, +.mce-shy { + background: #aaa; +} +.mce-shy::after { + content: '-'; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.min.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.min.css new file mode 100644 index 00000000..6e0034ba --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/content.min.css @@ -0,0 +1,726 @@ +.mce-content-body .mce-item-anchor { + background: transparent + url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") + no-repeat center; +} +.mce-content-body .mce-item-anchor:empty { + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + user-select: all; + width: 8px !important; +} +.mce-content-body .mce-item-anchor:not(:empty) { + background-position-x: 2px; + display: inline-block; + padding-left: 12px; +} +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} +.tox-comments-visible .tox-comment[data-mce-annotation-active='true']:not([data-mce-selected='inline-boundary']) { + background-color: #ffe168; +} +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A'); +} +[dir='rtl'] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} +code[class*='language-'], +pre[class*='language-'] { + color: #000; + background: 0 0; + text-shadow: 0 1px #fff; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} +code[class*='language-'] ::-moz-selection, +code[class*='language-']::-moz-selection, +pre[class*='language-'] ::-moz-selection, +pre[class*='language-']::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} +code[class*='language-'] ::selection, +code[class*='language-']::selection, +pre[class*='language-'] ::selection, +pre[class*='language-']::selection { + text-shadow: none; + background: #b3d4fc; +} +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #f5f2f0; +} +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} +.token.cdata, +.token.comment, +.token.doctype, +.token.prolog { + color: #708090; +} +.token.punctuation { + color: #999; +} +.token.namespace { + opacity: 0.7; +} +.token.boolean, +.token.constant, +.token.deleted, +.token.number, +.token.property, +.token.symbol, +.token.tag { + color: #905; +} +.token.attr-name, +.token.builtin, +.token.char, +.token.inserted, +.token.selector, +.token.string { + color: #690; +} +.language-css .token.string, +.style .token.string, +.token.entity, +.token.operator, +.token.url { + color: #9a6e3a; + background: hsla(0, 0%, 100%, 0.5); +} +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} +.token.class-name, +.token.function { + color: #dd4a68; +} +.token.important, +.token.regex, +.token.variable { + color: #e90; +} +.token.bold, +.token.important { + font-weight: 700; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} +.mce-content-body .mce-visual-caret { + background-color: #000; + background-color: currentColor; + position: absolute; +} +.mce-content-body .mce-visual-caret-hidden { + display: none; +} +.mce-content-body [data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} +.mce-content-body [contentEditable='false'] { + cursor: default; +} +.mce-content-body [contentEditable='true'] { + cursor: text; +} +.tox-cursor-format-painter { + cursor: url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'), + default; +} +.mce-content-body figure.align-left { + float: left; +} +.mce-content-body figure.align-right { + float: right; +} +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-preview-object[data-mce-selected='2'] .mce-shim { + display: none; +} +.mce-object { + background: transparent + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A') + no-repeat center; + border: 1px dashed #aaa; +} +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} +@media print { + .mce-pagebreak { + border: 0; + } +} +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tiny-pageembed[data-mce-selected='2'] .mce-shim { + display: none; +} +.tiny-pageembed { + display: inline-block; + position: relative; +} +.tiny-pageembed--16by9, +.tiny-pageembed--1by1, +.tiny-pageembed--21by9, +.tiny-pageembed--4by3 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} +.tiny-pageembed--4by3 { + padding-top: 75%; +} +.tiny-pageembed--1by1 { + padding-top: 100%; +} +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--1by1 iframe, +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--4by3 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.mce-content-body[data-mce-placeholder] { + position: relative; +} +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} +.mce-content-body:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; +} +.mce-content-body[dir='rtl'][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 1298; +} +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed #000; + position: absolute; + z-index: 10001; +} +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th { + border: 0; +} +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: #fff; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} +.tox-rtc-user-selection { + position: relative; +} +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: 700; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} +.tox-rtc-remote-image { + background: #eaeaea + url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A') + no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} +.mce-match-marker { + background: #aaa; + color: #fff; +} +.mce-match-marker-selected { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} +.mce-content-body audio[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body img[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body table[data-mce-selected], +.mce-content-body video[data-mce-selected] { + outline: 3px solid #b4d7ff; +} +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'] [contentEditable='true']:hover { + outline: 3px solid #b4d7ff; +} +.mce-content-body [contentEditable='false'][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} +.mce-content-body.mce-content-readonly [contentEditable='true']:focus, +.mce-content-body.mce-content-readonly [contentEditable='true']:hover { + outline: 0; +} +.mce-content-body [data-mce-selected='inline-boundary'] { + background-color: #b4d7ff; +} +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: 0 0; +} +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} +.mce-content-body img::-moz-selection { + background: 0 0; +} +.mce-content-body img::selection { + background: 0 0; +} +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ephox-snooker-resizer-cols { + cursor: col-resize; +} +.ephox-snooker-resizer-rows { + cursor: row-resize; +} +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} +.mce-toc { + border: 1px solid gray; +} +.mce-toc h2 { + margin: 4px; +} +.mce-toc li { + list-style-type: none; +} +.mce-item-table:not([border]), +.mce-item-table:not([border]) caption, +.mce-item-table:not([border]) td, +.mce-item-table:not([border]) th, +.mce-item-table[border='0'], +.mce-item-table[border='0'] caption, +.mce-item-table[border='0'] td, +.mce-item-table[border='0'] th, +table[style*='border-width: 0px'], +table[style*='border-width: 0px'] caption, +table[style*='border-width: 0px'] td, +table[style*='border-width: 0px'] th { + border: 1px dashed #bbb; +} +.mce-visualblocks address, +.mce-visualblocks article, +.mce-visualblocks aside, +.mce-visualblocks blockquote, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks dl, +.mce-visualblocks figcaption, +.mce-visualblocks figure, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks hgroup, +.mce-visualblocks ol, +.mce-visualblocks p, +.mce-visualblocks pre, +.mce-visualblocks section, +.mce-visualblocks ul { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} +.mce-visualblocks:not([dir='rtl']) address, +.mce-visualblocks:not([dir='rtl']) article, +.mce-visualblocks:not([dir='rtl']) aside, +.mce-visualblocks:not([dir='rtl']) blockquote, +.mce-visualblocks:not([dir='rtl']) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir='rtl']) dl, +.mce-visualblocks:not([dir='rtl']) figcaption, +.mce-visualblocks:not([dir='rtl']) figure, +.mce-visualblocks:not([dir='rtl']) h1, +.mce-visualblocks:not([dir='rtl']) h2, +.mce-visualblocks:not([dir='rtl']) h3, +.mce-visualblocks:not([dir='rtl']) h4, +.mce-visualblocks:not([dir='rtl']) h5, +.mce-visualblocks:not([dir='rtl']) h6, +.mce-visualblocks:not([dir='rtl']) hgroup, +.mce-visualblocks:not([dir='rtl']) ol, +.mce-visualblocks:not([dir='rtl']) p, +.mce-visualblocks:not([dir='rtl']) pre, +.mce-visualblocks:not([dir='rtl']) section, +.mce-visualblocks:not([dir='rtl']) ul { + margin-left: 3px; +} +.mce-visualblocks[dir='rtl'] address, +.mce-visualblocks[dir='rtl'] article, +.mce-visualblocks[dir='rtl'] aside, +.mce-visualblocks[dir='rtl'] blockquote, +.mce-visualblocks[dir='rtl'] div:not([data-mce-bogus]), +.mce-visualblocks[dir='rtl'] dl, +.mce-visualblocks[dir='rtl'] figcaption, +.mce-visualblocks[dir='rtl'] figure, +.mce-visualblocks[dir='rtl'] h1, +.mce-visualblocks[dir='rtl'] h2, +.mce-visualblocks[dir='rtl'] h3, +.mce-visualblocks[dir='rtl'] h4, +.mce-visualblocks[dir='rtl'] h5, +.mce-visualblocks[dir='rtl'] h6, +.mce-visualblocks[dir='rtl'] hgroup, +.mce-visualblocks[dir='rtl'] ol, +.mce-visualblocks[dir='rtl'] p, +.mce-visualblocks[dir='rtl'] pre, +.mce-visualblocks[dir='rtl'] section, +.mce-visualblocks[dir='rtl'] ul { + background-position-x: right; + margin-right: 3px; +} +.mce-nbsp, +.mce-shy { + background: #aaa; +} +.mce-shy::after { + content: '-'; +} +body { + font-family: sans-serif; +} +table { + border-collapse: collapse; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.css new file mode 100644 index 00000000..290ce87d --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.css @@ -0,0 +1,3764 @@ +.tox { + box-shadow: none; + box-sizing: content-box; + color: #222f3e; + cursor: auto; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-style: normal; + font-weight: normal; + line-height: normal; + -webkit-tap-highlight-color: transparent; + text-decoration: none; + text-shadow: none; + text-transform: none; + vertical-align: initial; + white-space: normal; +} + +.tox *:not(svg):not(rect) { + box-sizing: inherit; + color: inherit; + cursor: inherit; + direction: inherit; + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; + line-height: inherit; + -webkit-tap-highlight-color: inherit; + text-align: inherit; + text-decoration: inherit; + text-shadow: inherit; + text-transform: inherit; + vertical-align: inherit; + white-space: inherit; +} + +.tox *:not(svg):not(rect) { + /* stylelint-disable-line no-duplicate-selectors */ + background: transparent; + border: 0; + box-shadow: none; + float: none; + height: auto; + margin: 0; + max-width: none; + outline: 0; + padding: 0; + position: static; + width: auto; +} + +.tox:not([dir='rtl']) { + direction: ltr; + text-align: left; +} + +.tox[dir='rtl'] { + direction: rtl; + text-align: right; +} + +.tox-tinymce { + border: 1px solid #cccccc; + border-radius: 0; + box-shadow: none; + box-sizing: border-box; + display: flex; + flex-direction: column; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + overflow: hidden; + position: relative; + visibility: inherit !important; +} + +.tox.tox-tinymce-inline { + border: none; + box-shadow: none; + overflow: initial; +} + +.tox.tox-tinymce-inline .tox-editor-container { + overflow: initial; +} + +.tox.tox-tinymce-inline .tox-editor-header { + background-color: #fff; + border: 1px solid #cccccc; + border-radius: 0; + box-shadow: none; + overflow: hidden; +} + +.tox-tinymce-aux { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + z-index: 1300; +} + +.tox-tinymce *:focus, +.tox-tinymce-aux *:focus { + outline: none; +} + +button::-moz-focus-inner { + border: 0; +} + +.tox[dir='rtl'] .tox-icon--flip svg { + transform: rotateY(180deg); +} + +.tox .accessibility-issue__header { + align-items: center; + display: flex; + margin-bottom: 4px; +} + +.tox .accessibility-issue__description { + align-items: stretch; + border: 1px solid #cccccc; + border-radius: 3px; + display: flex; + justify-content: space-between; +} + +.tox .accessibility-issue__description > div { + padding-bottom: 4px; +} + +.tox .accessibility-issue__description > div > div { + align-items: center; + display: flex; + margin-bottom: 4px; +} + +.tox .accessibility-issue__description > *:last-child:not(:only-child) { + border-color: #cccccc; + border-style: solid; +} + +.tox .accessibility-issue__repair { + margin-top: 16px; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { + background-color: rgba(32, 122, 183, 0.1); + border-color: rgba(32, 122, 183, 0.4); + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description > *:last-child { + border-color: rgba(32, 122, 183, 0.4); +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { + color: #207ab7; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { + fill: #207ab7; +} + +.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon { + color: #207ab7; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { + background-color: rgba(255, 165, 0, 0.1); + border-color: rgba(255, 165, 0, 0.5); + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description > *:last-child { + border-color: rgba(255, 165, 0, 0.5); +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { + color: #cc8500; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { + fill: #cc8500; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon { + color: #cc8500; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { + background-color: rgba(204, 0, 0, 0.1); + border-color: rgba(204, 0, 0, 0.4); + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description > *:last-child { + border-color: rgba(204, 0, 0, 0.4); +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { + color: #c00; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { + fill: #c00; +} + +.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon { + color: #c00; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { + background-color: rgba(120, 171, 70, 0.1); + border-color: rgba(120, 171, 70, 0.4); + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > *:last-child { + border-color: rgba(120, 171, 70, 0.4); +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { + color: #78ab46; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { + fill: #78ab46; +} + +.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon { + color: #78ab46; +} + +.tox .tox-dialog__body-content .accessibility-issue__header h1, +.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { + margin-top: 0; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-left: auto; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 4px 4px 8px; +} + +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-left-width: 1px; + padding-left: 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-right: auto; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 8px 4px 4px; +} + +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-right-width: 1px; + padding-right: 4px; +} + +.tox .tox-anchorbar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-bar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-button { + background-color: #207ab7; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #207ab7; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + line-height: 24px; + margin: 0; + outline: none; + padding: 4px 16px; + text-align: center; + text-decoration: none; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-button[disabled] { + background-color: #207ab7; + background-image: none; + border-color: #207ab7; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-button:focus:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:hover:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:active:not(:disabled) { + background-color: #185d8c; + background-image: none; + border-color: #185d8c; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary { + background-color: #f0f0f0; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #f0f0f0; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + color: #222f3e; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + outline: none; + padding: 4px 16px; + text-decoration: none; + text-transform: none; +} + +.tox .tox-button--secondary[disabled] { + background-color: #f0f0f0; + background-image: none; + border-color: #f0f0f0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} + +.tox .tox-button--secondary:focus:not(:disabled) { + background-color: #e3e3e3; + background-image: none; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--secondary:hover:not(:disabled) { + background-color: #e3e3e3; + background-image: none; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--secondary:active:not(:disabled) { + background-color: #d6d6d6; + background-image: none; + border-color: #d6d6d6; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--icon, +.tox .tox-button.tox-button--icon, +.tox .tox-button.tox-button--secondary.tox-button--icon { + padding: 4px; +} + +.tox .tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { + display: block; + fill: currentColor; +} + +.tox .tox-button-link { + background: 0; + border: none; + box-sizing: border-box; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-weight: normal; + line-height: 1.3; + margin: 0; + padding: 0; + white-space: nowrap; +} + +.tox .tox-button-link--sm { + font-size: 14px; +} + +.tox .tox-button--naked { + background-color: transparent; + border-color: transparent; + box-shadow: unset; + color: #222f3e; +} + +.tox .tox-button--naked[disabled] { + background-color: #f0f0f0; + border-color: #f0f0f0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} + +.tox .tox-button--naked:hover:not(:disabled) { + background-color: #e3e3e3; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--naked:focus:not(:disabled) { + background-color: #e3e3e3; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--naked:active:not(:disabled) { + background-color: #d6d6d6; + border-color: #d6d6d6; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--naked .tox-icon svg { + fill: currentColor; +} + +.tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { + color: #222f3e; +} + +.tox .tox-checkbox { + align-items: center; + border-radius: 3px; + cursor: pointer; + display: flex; + height: 36px; + min-width: 36px; +} + +.tox .tox-checkbox__input { + /* Hide from view but visible to screen readers */ + height: 1px; + overflow: hidden; + position: absolute; + top: auto; + width: 1px; +} + +.tox .tox-checkbox__icons { + align-items: center; + border-radius: 3px; + box-shadow: 0 0 0 2px transparent; + box-sizing: content-box; + display: flex; + height: 24px; + justify-content: center; + padding: calc(4px - 1px); + width: 24px; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: block; + fill: rgba(34, 47, 62, 0.3); +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: none; + fill: #207ab7; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: none; + fill: #207ab7; +} + +.tox .tox-checkbox--disabled { + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: block; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: block; +} + +.tox input.tox-checkbox__input:focus + .tox-checkbox__icons { + border-radius: 3px; + box-shadow: inset 0 0 0 1px #207ab7; + padding: calc(4px - 1px); +} + +.tox:not([dir='rtl']) .tox-checkbox__label { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-checkbox__input { + left: -10000px; +} + +.tox:not([dir='rtl']) .tox-bar .tox-checkbox { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-checkbox__label { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-checkbox__input { + right: -10000px; +} + +.tox[dir='rtl'] .tox-bar .tox-checkbox { + margin-right: 4px; +} + +.tox { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox .tox-collection--toolbar .tox-collection__group { + display: flex; + padding: 0; +} + +.tox .tox-collection--grid .tox-collection__group { + display: flex; + flex-wrap: wrap; + max-height: 208px; + overflow-x: hidden; + overflow-y: auto; + padding: 0; +} + +.tox .tox-collection--list .tox-collection__group { + border-bottom-width: 0; + border-color: #cccccc; + border-left-width: 0; + border-right-width: 0; + border-style: solid; + border-top-width: 1px; + padding: 4px 0; +} + +.tox .tox-collection--list .tox-collection__group:first-child { + border-top-width: 0; +} + +.tox .tox-collection__group-heading { + background-color: #e6e6e6; + color: rgba(34, 47, 62, 0.7); + cursor: default; + font-size: 12px; + font-style: normal; + font-weight: normal; + margin-bottom: 4px; + margin-top: -4px; + padding: 4px 8px; + text-transform: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.tox .tox-collection__item { + align-items: center; + border-radius: 3px; + color: #222f3e; + display: flex; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.tox .tox-collection--list .tox-collection__item { + padding: 4px 8px; +} + +.tox .tox-collection--toolbar .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--grid .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--list .tox-collection__item--enabled { + background-color: #fff; + color: #222f3e; +} + +.tox .tox-collection--list .tox-collection__item--active { + background-color: #dee0e2; +} + +.tox .tox-collection--toolbar .tox-collection__item--enabled { + background-color: #c8cbcf; + color: #222f3e; +} + +.tox .tox-collection--toolbar .tox-collection__item--active { + background-color: #dee0e2; +} + +.tox .tox-collection--grid .tox-collection__item--enabled { + background-color: #c8cbcf; + color: #222f3e; +} + +.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + background-color: #dee0e2; + color: #222f3e; +} + +.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #222f3e; +} + +.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #222f3e; +} + +.tox .tox-collection__item-icon, +.tox .tox-collection__item-checkmark { + align-items: center; + display: flex; + height: 24px; + justify-content: center; + width: 24px; +} + +.tox .tox-collection__item-icon svg, +.tox .tox-collection__item-checkmark svg { + fill: currentColor; +} + +.tox .tox-collection--toolbar-lg .tox-collection__item-icon { + height: 48px; + width: 48px; +} + +.tox .tox-collection__item-label { + color: currentColor; + display: inline-block; + flex: 1; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 24px; + text-transform: none; + word-break: break-all; +} + +.tox .tox-collection__item-accessory { + color: rgba(34, 47, 62, 0.7); + display: inline-block; + font-size: 14px; + height: 24px; + line-height: 24px; + text-transform: none; +} + +.tox .tox-collection__item-caret { + align-items: center; + display: flex; + min-height: 24px; +} + +.tox .tox-collection__item-caret::after { + content: ''; + font-size: 0; + min-height: inherit; +} + +.tox .tox-collection__item-caret svg { + fill: #222f3e; +} + +.tox .tox-collection__item--state-disabled { + background-color: transparent; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox +.tox-collection--list +.tox-collection__item:not(.tox-collection__item--enabled) +.tox-collection__item-checkmark +svg { + display: none; +} + +.tox +.tox-collection--list +.tox-collection__item:not(.tox-collection__item--enabled) +.tox-collection__item-accessory ++ .tox-collection__item-checkmark { + display: none; +} + +.tox .tox-collection--horizontal { + background-color: #fff; + border: 1px solid #cccccc; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: nowrap; + margin-bottom: 0; + overflow-x: auto; + padding: 0; +} + +.tox .tox-collection--horizontal .tox-collection__group { + align-items: center; + display: flex; + flex-wrap: nowrap; + margin: 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item { + height: 34px; + margin: 3px 0 2px 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item-label { + white-space: nowrap; +} + +.tox .tox-collection--horizontal .tox-collection__item-caret { + margin-left: 4px; +} + +.tox .tox-collection__item-container { + display: flex; +} + +.tox .tox-collection__item-container--row { + align-items: center; + flex: 1 1 auto; + flex-direction: row; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-left { + margin-right: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-right { + justify-content: flex-end; + margin-left: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { + align-items: flex-start; + margin-bottom: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { + align-items: center; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { + align-items: flex-end; + margin-top: auto; +} + +.tox .tox-collection__item-container--column { + align-self: center; + flex: 1 1 auto; + flex-direction: column; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-left { + align-items: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-right { + align-items: flex-end; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { + align-self: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { + align-self: center; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { + align-self: flex-end; +} + +.tox:not([dir='rtl']) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-right: 1px solid #cccccc; +} + +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-left: 8px; +} + +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-left: 4px; +} + +.tox:not([dir='rtl']) .tox-collection__item-accessory { + margin-left: 16px; + text-align: right; +} + +.tox:not([dir='rtl']) .tox-collection .tox-collection__item-caret { + margin-left: 16px; +} + +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-left: 1px solid #cccccc; +} + +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-right: 8px; +} + +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-right: 4px; +} + +.tox[dir='rtl'] .tox-collection__item-accessory { + margin-right: 16px; + text-align: left; +} + +.tox[dir='rtl'] .tox-collection .tox-collection__item-caret { + margin-right: 16px; + transform: rotateY(180deg); +} + +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__item-caret { + margin-right: 4px; +} + +.tox .tox-color-picker-container { + display: flex; + flex-direction: row; + height: 225px; + margin: 0; +} + +.tox .tox-sv-palette { + box-sizing: border-box; + display: flex; + height: 100%; +} + +.tox .tox-sv-palette-spectrum { + height: 100%; +} + +.tox .tox-sv-palette, +.tox .tox-sv-palette-spectrum { + width: 225px; +} + +.tox .tox-sv-palette-thumb { + background: none; + border: 1px solid black; + border-radius: 50%; + box-sizing: content-box; + height: 12px; + position: absolute; + width: 12px; +} + +.tox .tox-sv-palette-inner-thumb { + border: 1px solid white; + border-radius: 50%; + height: 10px; + position: absolute; + width: 10px; +} + +.tox .tox-hue-slider { + box-sizing: border-box; + height: 100%; + width: 25px; +} + +.tox .tox-hue-slider-spectrum { + background: linear-gradient( + to bottom, + #f00, + #ff0080, + #f0f, + #8000ff, + #00f, + #0080ff, + #0ff, + #00ff80, + #0f0, + #80ff00, + #ff0, + #ff8000, + #f00 + ); + height: 100%; + width: 100%; +} + +.tox .tox-hue-slider, +.tox .tox-hue-slider-spectrum { + width: 20px; +} + +.tox .tox-hue-slider-thumb { + background: white; + border: 1px solid black; + box-sizing: content-box; + height: 4px; + width: 100%; +} + +.tox .tox-rgb-form { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.tox .tox-rgb-form div { + align-items: center; + display: flex; + justify-content: space-between; + margin-bottom: 5px; + width: inherit; +} + +.tox .tox-rgb-form input { + width: 6em; +} + +.tox .tox-rgb-form input.tox-invalid { + /* Need !important to override Chrome's focus styling unfortunately */ + border: 1px solid red !important; +} + +.tox .tox-rgb-form .tox-rgba-preview { + border: 1px solid black; + flex-grow: 2; + margin-bottom: 0; +} + +.tox:not([dir='rtl']) .tox-sv-palette { + margin-right: 15px; +} + +.tox:not([dir='rtl']) .tox-hue-slider { + margin-right: 15px; +} + +.tox:not([dir='rtl']) .tox-hue-slider-thumb { + margin-left: -1px; +} + +.tox:not([dir='rtl']) .tox-rgb-form label { + margin-right: 0.5em; +} + +.tox[dir='rtl'] .tox-sv-palette { + margin-left: 15px; +} + +.tox[dir='rtl'] .tox-hue-slider { + margin-left: 15px; +} + +.tox[dir='rtl'] .tox-hue-slider-thumb { + margin-right: -1px; +} + +.tox[dir='rtl'] .tox-rgb-form label { + margin-left: 0.5em; +} + +.tox .tox-toolbar .tox-swatches, +.tox .tox-toolbar__primary .tox-swatches, +.tox .tox-toolbar__overflow .tox-swatches { + margin: 2px 0 3px 4px; +} + +.tox .tox-collection--list .tox-collection__group .tox-swatches-menu { + border: 0; + margin: -4px 0; +} + +.tox .tox-swatches__row { + display: flex; +} + +.tox .tox-swatch { + height: 30px; + transition: transform 0.15s, box-shadow 0.15s; + width: 30px; +} + +.tox .tox-swatch:hover, +.tox .tox-swatch:focus { + box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; + transform: scale(0.8); +} + +.tox .tox-swatch--remove { + align-items: center; + display: flex; + justify-content: center; +} + +.tox .tox-swatch--remove svg path { + stroke: #e74c3c; +} + +.tox .tox-swatches__picker-btn { + align-items: center; + background-color: transparent; + border: 0; + cursor: pointer; + display: flex; + height: 30px; + justify-content: center; + outline: none; + padding: 0; + width: 30px; +} + +.tox .tox-swatches__picker-btn svg { + fill: #222f3e; + height: 24px; + width: 24px; +} + +.tox .tox-swatches__picker-btn:hover { + background: #dee0e2; +} + +.tox:not([dir='rtl']) .tox-swatches__picker-btn { + margin-left: auto; +} + +.tox[dir='rtl'] .tox-swatches__picker-btn { + margin-right: auto; +} + +.tox .tox-comment-thread { + background: #fff; + position: relative; +} + +.tox .tox-comment-thread > *:not(:first-child) { + margin-top: 8px; +} + +.tox .tox-comment { + background: #fff; + border: 1px solid #cccccc; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); + padding: 8px 8px 16px 8px; + position: relative; +} + +.tox .tox-comment__header { + align-items: center; + color: #222f3e; + display: flex; + justify-content: space-between; +} + +.tox .tox-comment__date { + color: rgba(34, 47, 62, 0.7); + font-size: 12px; +} + +.tox .tox-comment__body { + color: #222f3e; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin-top: 8px; + position: relative; + text-transform: initial; +} + +.tox .tox-comment__body textarea { + resize: none; + white-space: normal; + width: 100%; +} + +.tox .tox-comment__expander { + padding-top: 8px; +} + +.tox .tox-comment__expander p { + color: rgba(34, 47, 62, 0.7); + font-size: 14px; + font-style: normal; +} + +.tox .tox-comment__body p { + margin: 0; +} + +.tox .tox-comment__buttonspacing { + padding-top: 16px; + text-align: center; +} + +.tox .tox-comment-thread__overlay::after { + background: #fff; + bottom: 0; + content: ''; + display: flex; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + top: 0; + z-index: 5; +} + +.tox .tox-comment__reply { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 8px; +} + +.tox .tox-comment__reply > *:first-child { + margin-bottom: 8px; + width: 100%; +} + +.tox .tox-comment__edit { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 16px; +} + +.tox .tox-comment__gradient::after { + background: linear-gradient(rgba(255, 255, 255, 0), #fff); + bottom: 0; + content: ''; + display: block; + height: 5em; + margin-top: -40px; + position: absolute; + width: 100%; +} + +.tox .tox-comment__overlay { + background: #fff; + bottom: 0; + display: flex; + flex-direction: column; + flex-grow: 1; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + text-align: center; + top: 0; + z-index: 5; +} + +.tox .tox-comment__loading-text { + align-items: center; + color: #222f3e; + display: flex; + flex-direction: column; + position: relative; +} + +.tox .tox-comment__loading-text > div { + padding-bottom: 16px; +} + +.tox .tox-comment__overlaytext { + bottom: 0; + flex-direction: column; + font-size: 14px; + left: 0; + padding: 1em; + position: absolute; + right: 0; + top: 0; + z-index: 10; +} + +.tox .tox-comment__overlaytext p { + background-color: #fff; + box-shadow: 0 0 8px 8px #fff; + color: #222f3e; + text-align: center; +} + +.tox .tox-comment__overlaytext div:nth-of-type(2) { + font-size: 0.8em; +} + +.tox .tox-comment__busy-spinner { + align-items: center; + background-color: #fff; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 20; +} + +.tox .tox-comment__scroll { + display: flex; + flex-direction: column; + flex-shrink: 1; + overflow: auto; +} + +.tox .tox-conversations { + margin: 8px; +} + +.tox:not([dir='rtl']) .tox-comment__edit { + margin-left: 8px; +} + +.tox:not([dir='rtl']) .tox-comment__buttonspacing > *:last-child, +.tox:not([dir='rtl']) .tox-comment__edit > *:last-child, +.tox:not([dir='rtl']) .tox-comment__reply > *:last-child { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-comment__edit { + margin-right: 8px; +} + +.tox[dir='rtl'] .tox-comment__buttonspacing > *:last-child, +.tox[dir='rtl'] .tox-comment__edit > *:last-child, +.tox[dir='rtl'] .tox-comment__reply > *:last-child { + margin-right: 8px; +} + +.tox .tox-user { + align-items: center; + display: flex; +} + +.tox .tox-user__avatar svg { + fill: rgba(34, 47, 62, 0.7); +} + +.tox .tox-user__name { + color: rgba(34, 47, 62, 0.7); + font-size: 12px; + font-style: normal; + font-weight: bold; + text-transform: uppercase; +} + +.tox:not([dir='rtl']) .tox-user__avatar svg { + margin-right: 8px; +} + +.tox:not([dir='rtl']) .tox-user__avatar + .tox-user__name { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-user__avatar svg { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-user__avatar + .tox-user__name { + margin-right: 8px; +} + +.tox .tox-dialog-wrap { + align-items: center; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 1100; +} + +.tox .tox-dialog-wrap__backdrop { + background-color: rgba(255, 255, 255, 0.75); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} + +.tox .tox-dialog-wrap__backdrop--opaque { + background-color: #fff; +} + +.tox .tox-dialog { + background-color: #fff; + border-color: #cccccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: 0 16px 16px -10px rgba(34, 47, 62, 0.15), 0 0 40px 1px rgba(34, 47, 62, 0.15); + display: flex; + flex-direction: column; + max-height: 100%; + max-width: 480px; + overflow: hidden; + position: relative; + width: 95vw; + z-index: 2; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog { + align-self: flex-start; + margin: 8px auto; + width: calc(100vw - 16px); + } +} + +.tox .tox-dialog-inline { + z-index: 1100; +} + +.tox .tox-dialog__header { + align-items: center; + background-color: #fff; + border-bottom: none; + color: #222f3e; + display: flex; + font-size: 16px; + justify-content: space-between; + padding: 8px 16px 0 16px; + position: relative; +} + +.tox .tox-dialog__header .tox-button { + z-index: 1; +} + +.tox .tox-dialog__draghandle { + cursor: grab; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tox .tox-dialog__draghandle:active { + cursor: grabbing; +} + +.tox .tox-dialog__dismiss { + margin-left: auto; +} + +.tox .tox-dialog__title { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 20px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin: 0; + text-transform: none; +} + +.tox .tox-dialog__body { + color: #222f3e; + display: flex; + flex: 1; + font-size: 16px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + min-width: 0; + text-align: left; + text-transform: none; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body { + flex-direction: column; + } +} + +.tox .tox-dialog__body-nav { + align-items: flex-start; + display: flex; + flex-direction: column; + padding: 16px 16px; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { + flex-direction: row; + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding-bottom: 0; + } +} + +.tox .tox-dialog__body-nav-item { + border-bottom: 2px solid transparent; + color: rgba(34, 47, 62, 0.7); + display: inline-block; + font-size: 14px; + line-height: 1.3; + margin-bottom: 8px; + text-decoration: none; + white-space: nowrap; +} + +.tox .tox-dialog__body-nav-item:focus { + background-color: rgba(32, 122, 183, 0.1); +} + +.tox .tox-dialog__body-nav-item--active { + border-bottom: 2px solid #207ab7; + color: #207ab7; +} + +.tox .tox-dialog__body-content { + box-sizing: border-box; + display: flex; + flex: 1; + flex-direction: column; + max-height: 650px; + overflow: auto; + -webkit-overflow-scrolling: touch; + padding: 16px 16px; +} + +.tox .tox-dialog__body-content > * { + margin-bottom: 0; + margin-top: 16px; +} + +.tox .tox-dialog__body-content > *:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content > *:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content > *:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog__body-content a { + color: #207ab7; + cursor: pointer; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:hover, +.tox .tox-dialog__body-content a:focus { + color: #185d8c; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:active { + color: #185d8c; + text-decoration: none; +} + +.tox .tox-dialog__body-content svg { + fill: #222f3e; +} + +.tox .tox-dialog__body-content ul { + display: block; + list-style-type: disc; + margin-bottom: 16px; + margin-inline-end: 0; + margin-inline-start: 0; + padding-inline-start: 2.5rem; +} + +.tox .tox-dialog__body-content .tox-form__group h1 { + color: #222f3e; + font-size: 20px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group h2 { + color: #222f3e; + font-size: 16px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group p { + margin-bottom: 16px; +} + +.tox .tox-dialog__body-content .tox-form__group h1:first-child, +.tox .tox-dialog__body-content .tox-form__group h2:first-child, +.tox .tox-dialog__body-content .tox-form__group p:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:last-child, +.tox .tox-dialog__body-content .tox-form__group h2:last-child, +.tox .tox-dialog__body-content .tox-form__group p:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:only-child, +.tox .tox-dialog__body-content .tox-form__group h2:only-child, +.tox .tox-dialog__body-content .tox-form__group p:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog--width-lg { + height: 650px; + max-width: 1200px; +} + +.tox .tox-dialog--width-md { + max-width: 800px; +} + +.tox .tox-dialog--width-md .tox-dialog__body-content { + overflow: auto; +} + +.tox .tox-dialog__body-content--centered { + text-align: center; +} + +.tox .tox-dialog__footer { + align-items: center; + background-color: #fff; + border-top: 1px solid #cccccc; + display: flex; + justify-content: space-between; + padding: 8px 16px; +} + +.tox .tox-dialog__footer-start, +.tox .tox-dialog__footer-end { + display: flex; +} + +.tox .tox-dialog__busy-spinner { + align-items: center; + background-color: rgba(255, 255, 255, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 3; +} + +.tox .tox-dialog__table { + border-collapse: collapse; + width: 100%; +} + +.tox .tox-dialog__table thead th { + font-weight: bold; + padding-bottom: 8px; +} + +.tox .tox-dialog__table tbody tr { + border-bottom: 1px solid #cccccc; +} + +.tox .tox-dialog__table tbody tr:last-child { + border-bottom: none; +} + +.tox .tox-dialog__table td { + padding-bottom: 8px; + padding-top: 8px; +} + +.tox .tox-dialog__popups { + position: absolute; + width: 100%; + z-index: 1100; +} + +.tox .tox-dialog__body-iframe { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-dialog__body-iframe .tox-navobj { + display: flex; + flex: 1; +} + +.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} + +.tox .tox-dialog-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox .tox-dialog-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox .tox-dialog-dock-transition { + transition: visibility 0s linear 0.3s, opacity 0.3s ease; +} + +.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { + transition-delay: 0s; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav { + margin-right: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav-item:not(:first-child) { + margin-left: 8px; + } +} + +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-start > *, +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-end > * { + margin-left: 8px; +} + +.tox[dir='rtl'] .tox-dialog__body { + text-align: right; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav { + margin-left: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav-item:not(:first-child) { + margin-right: 8px; + } +} + +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-start > *, +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-end > * { + margin-right: 8px; +} + +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox .tox-dropzone-container { + display: flex; + flex: 1; +} + +.tox .tox-dropzone { + align-items: center; + background: #fff; + border: 2px dashed #cccccc; + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-grow: 1; + justify-content: center; + min-height: 100px; + padding: 10px; +} + +.tox .tox-dropzone p { + color: rgba(34, 47, 62, 0.7); + margin: 0 0 16px 0; +} + +.tox .tox-edit-area { + display: flex; + flex: 1; + overflow: hidden; + position: relative; +} + +.tox .tox-edit-area__iframe { + background-color: #fff; + border: 0; + box-sizing: border-box; + flex: 1; + height: 100%; + position: absolute; + width: 100%; +} + +.tox.tox-inline-edit-area { + border: 1px dotted #cccccc; +} + +.tox .tox-editor-container { + display: flex; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} + +.tox .tox-editor-header { + z-index: 1; +} + +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: #fff; + border-bottom: none; + box-shadow: none; + padding: 4px 0; + transition: box-shadow 0.5s; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: 1px solid #c1c1c1; + box-shadow: none; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: #fff; + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); + padding: 4px 0; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); +} + +.tox-editor-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox-editor-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox-editor-dock-transition { + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} + +.tox-editor-dock-transition.tox-editor-dock-fadein { + transition-delay: 0s; +} + +.tox .tox-control-wrap { + flex: 1; + position: relative; +} + +.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, +.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, +.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { + display: none; +} + +.tox .tox-control-wrap svg { + display: block; +} + +.tox .tox-control-wrap__status-icon-wrap { + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-control-wrap__status-icon-invalid svg { + fill: #c00; +} + +.tox .tox-control-wrap__status-icon-unknown svg { + fill: orange; +} + +.tox .tox-control-wrap__status-icon-valid svg { + fill: green; +} + +.tox:not([dir='rtl']) .tox-control-wrap--status-invalid .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-unknown .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-valid .tox-textfield { + padding-right: 32px; +} + +.tox:not([dir='rtl']) .tox-control-wrap__status-icon-wrap { + right: 4px; +} + +.tox[dir='rtl'] .tox-control-wrap--status-invalid .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-unknown .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-valid .tox-textfield { + padding-left: 32px; +} + +.tox[dir='rtl'] .tox-control-wrap__status-icon-wrap { + left: 4px; +} + +.tox .tox-autocompleter { + max-width: 25em; +} + +.tox .tox-autocompleter .tox-menu { + border-color: #cccccc; + box-shadow: none; + max-width: 25em; +} + +.tox .tox-autocompleter .tox-autocompleter-highlight { + font-weight: bold; +} + +.tox .tox-color-input { + display: flex; + position: relative; + z-index: 1; +} + +.tox .tox-color-input .tox-textfield { + z-index: -1; +} + +.tox .tox-color-input span { + border-color: rgba(34, 47, 62, 0.2); + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + height: 24px; + position: absolute; + top: 6px; + width: 24px; +} + +.tox .tox-color-input span:hover:not([aria-disabled='true']), +.tox .tox-color-input span:focus:not([aria-disabled='true']) { + border-color: #207ab7; + cursor: pointer; +} + +.tox .tox-color-input span::before { + background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), + linear-gradient(-45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%), + linear-gradient(-45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%); + background-position: 0 0, 0 6px, 6px -6px, -6px 0; + background-size: 12px 12px; + border: 1px solid #fff; + border-radius: 3px; + box-sizing: border-box; + content: ''; + height: 24px; + left: -1px; + position: absolute; + top: -1px; + width: 24px; + z-index: -1; +} + +.tox .tox-color-input span[aria-disabled='true'] { + cursor: not-allowed; +} + +.tox:not([dir='rtl']) .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir='rtl']) .tox-color-input .tox-textfield { + padding-left: 36px; +} + +.tox:not([dir='rtl']) .tox-color-input span { + left: 6px; +} + +.tox[dir='rtl'] .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir='rtl'] .tox-color-input .tox-textfield { + padding-right: 36px; +} + +.tox[dir='rtl'] .tox-color-input span { + right: 6px; +} + +.tox .tox-label, +.tox .tox-toolbar-label { + color: rgba(34, 47, 62, 0.7); + display: block; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + padding: 0 8px 0 0; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-toolbar-label { + padding: 0 8px; +} + +.tox[dir='rtl'] .tox-label { + padding: 0 0 0 8px; +} + +.tox .tox-form { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-form__group { + box-sizing: border-box; + margin-bottom: 4px; +} + +.tox .tox-form-group--maximize { + flex: 1; +} + +.tox .tox-form__group--error { + color: #c00; +} + +.tox .tox-form__group--collection { + display: flex; +} + +.tox .tox-form__grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} + +.tox .tox-form__grid--2col > .tox-form__group { + width: calc(50% - (8px / 2)); +} + +.tox .tox-form__grid--3col > .tox-form__group { + width: calc(100% / 3 - (8px / 2)); +} + +.tox .tox-form__grid--4col > .tox-form__group { + width: calc(25% - (8px / 2)); +} + +.tox .tox-form__controls-h-stack { + align-items: center; + display: flex; +} + +.tox .tox-form__group--inline { + align-items: center; + display: flex; +} + +.tox .tox-form__group--stretched { + display: flex; + flex: 1; + flex-direction: column; +} + +.tox .tox-form__group--stretched .tox-textarea { + flex: 1; +} + +.tox .tox-form__group--stretched .tox-navobj { + display: flex; + flex: 1; +} + +.tox .tox-form__group--stretched .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} + +.tox:not([dir='rtl']) .tox-form__controls-h-stack > *:not(:first-child) { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-form__controls-h-stack > *:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-lock.tox-locked .tox-lock-icon__unlock, +.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { + display: none; +} + +.tox .tox-textfield, +.tox .tox-toolbar-textfield, +.tox .tox-listboxfield .tox-listbox--select, +.tox .tox-textarea { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #cccccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #222f3e; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 4.75px; + resize: none; + width: 100%; +} + +.tox .tox-textfield[disabled], +.tox .tox-textarea[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} + +.tox .tox-textfield:focus, +.tox .tox-listboxfield .tox-listbox--select:focus, +.tox .tox-textarea:focus { + background-color: #fff; + border-color: #207ab7; + box-shadow: none; + outline: 2px solid rgba(32, 122, 183, 0.25); +} + +.tox .tox-toolbar-textfield { + border-width: 0; + margin-bottom: 3px; + margin-top: 2px; + max-width: 250px; +} + +.tox .tox-naked-btn { + background-color: transparent; + border: 0; + border-color: transparent; + box-shadow: unset; + color: #207ab7; + cursor: pointer; + display: block; + margin: 0; + padding: 0; +} + +.tox .tox-naked-btn svg { + display: block; + fill: #222f3e; +} + +.tox:not([dir='rtl']) .tox-toolbar-textfield + * { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-toolbar-textfield + * { + margin-right: 4px; +} + +.tox .tox-listboxfield { + cursor: pointer; + position: relative; +} + +.tox .tox-listboxfield .tox-listbox--select[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} + +.tox .tox-listbox__select-label { + cursor: default; + flex: 1; + margin: 0 4px; +} + +.tox .tox-listbox__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-listbox__select-chevron svg { + fill: #222f3e; +} + +.tox .tox-listboxfield .tox-listbox--select { + align-items: center; + display: flex; +} + +.tox:not([dir='rtl']) .tox-listboxfield svg { + right: 8px; +} + +.tox[dir='rtl'] .tox-listboxfield svg { + left: 8px; +} + +.tox .tox-selectfield { + cursor: pointer; + position: relative; +} + +.tox .tox-selectfield select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #cccccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #222f3e; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 4.75px; + resize: none; + width: 100%; +} + +.tox .tox-selectfield select[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} + +.tox .tox-selectfield select::-ms-expand { + display: none; +} + +.tox .tox-selectfield select:focus { + background-color: #fff; + border-color: #207ab7; + box-shadow: none; + outline: 2px solid rgba(32, 122, 183, 0.25); +} + +.tox .tox-selectfield svg { + pointer-events: none; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox:not([dir='rtl']) .tox-selectfield select[size='0'], +.tox:not([dir='rtl']) .tox-selectfield select[size='1'] { + padding-right: 24px; +} + +.tox:not([dir='rtl']) .tox-selectfield svg { + right: 8px; +} + +.tox[dir='rtl'] .tox-selectfield select[size='0'], +.tox[dir='rtl'] .tox-selectfield select[size='1'] { + padding-left: 24px; +} + +.tox[dir='rtl'] .tox-selectfield svg { + left: 8px; +} + +.tox .tox-textarea { + -webkit-appearance: textarea; + -moz-appearance: textarea; + appearance: textarea; + white-space: pre-wrap; +} + +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen, +.tox-shadowhost.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} + +.tox .tox-help__more-link { + list-style: none; + margin-top: 1em; +} + +.tox .tox-imagepreview { + background-color: #666; + height: 380px; + overflow: hidden; + position: relative; + width: 100%; +} + +.tox .tox-imagepreview.tox-imagepreview__loaded { + overflow: auto; +} + +.tox .tox-imagepreview__container { + display: flex; + left: 100vw; + position: absolute; + top: 100vw; +} + +.tox .tox-imagepreview__image { + background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); +} + +.tox .tox-image-tools .tox-spacer { + flex: 1; +} + +.tox .tox-image-tools .tox-bar { + align-items: center; + display: flex; + height: 60px; + justify-content: center; +} + +.tox .tox-image-tools .tox-imagepreview, +.tox .tox-image-tools .tox-imagepreview + .tox-bar { + margin-top: 8px; +} + +.tox .tox-image-tools .tox-croprect-block { + background: black; + filter: alpha(opacity=50); + opacity: 0.5; + position: absolute; + zoom: 1; +} + +.tox .tox-image-tools .tox-croprect-handle { + border: 2px solid white; + height: 20px; + left: 0; + position: absolute; + top: 0; + width: 20px; +} + +.tox .tox-image-tools .tox-croprect-handle-move { + border: 0; + cursor: move; + position: absolute; +} + +.tox .tox-image-tools .tox-croprect-handle-nw { + border-width: 2px 0 0 2px; + cursor: nw-resize; + left: 100px; + margin: -2px 0 0 -2px; + top: 100px; +} + +.tox .tox-image-tools .tox-croprect-handle-ne { + border-width: 2px 2px 0 0; + cursor: ne-resize; + left: 200px; + margin: -2px 0 0 -20px; + top: 100px; +} + +.tox .tox-image-tools .tox-croprect-handle-sw { + border-width: 0 0 2px 2px; + cursor: sw-resize; + left: 100px; + margin: -20px 2px 0 -2px; + top: 200px; +} + +.tox .tox-image-tools .tox-croprect-handle-se { + border-width: 0 2px 2px 0; + cursor: se-resize; + left: 200px; + margin: -20px 0 0 -20px; + top: 200px; +} + +.tox .tox-insert-table-picker { + display: flex; + flex-wrap: wrap; + width: 170px; +} + +.tox .tox-insert-table-picker > div { + border-color: #cccccc; + border-style: solid; + border-width: 0 1px 1px 0; + box-sizing: border-box; + height: 17px; + width: 17px; +} + +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: 0 -4px; +} + +.tox .tox-insert-table-picker .tox-insert-table-picker__selected { + background-color: rgba(32, 122, 183, 0.5); + border-color: rgba(32, 122, 183, 0.5); +} + +.tox .tox-insert-table-picker__label { + color: rgba(34, 47, 62, 0.7); + display: block; + font-size: 14px; + padding: 4px; + text-align: center; + width: 100%; +} + +.tox:not([dir='rtl']) { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir='rtl']) .tox-insert-table-picker > div:nth-child(10n) { + border-right: 0; +} + +.tox[dir='rtl'] { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir='rtl'] .tox-insert-table-picker > div:nth-child(10n + 1) { + border-right: 0; +} + +.tox { + /* stylelint-disable */ + /* stylelint-enable */ +} + +.tox .tox-menu { + background-color: #fff; + border: 1px solid #cccccc; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); + display: inline-block; + overflow: hidden; + vertical-align: top; + z-index: 1150; +} + +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0 0; +} + +.tox .tox-menu.tox-collection.tox-collection--toolbar { + padding: 4px; +} + +.tox .tox-menu.tox-collection.tox-collection--grid { + padding: 4px; +} + +.tox .tox-menu__label h1, +.tox .tox-menu__label h2, +.tox .tox-menu__label h3, +.tox .tox-menu__label h4, +.tox .tox-menu__label h5, +.tox .tox-menu__label h6, +.tox .tox-menu__label p, +.tox .tox-menu__label blockquote, +.tox .tox-menu__label code { + margin: 0; +} + +.tox .tox-menubar { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0 #fff; + background-color: #fff; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 4px 0 4px; +} + +.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { + border-top: 1px solid #cccccc; +} + +/* Deprecated. Remove in next major release */ +.tox .tox-mbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #222f3e; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 34px; + justify-content: center; + margin: 2px 0 3px 0; + outline: none; + overflow: hidden; + padding: 0 4px; + text-transform: none; + width: auto; +} + +.tox .tox-mbtn[disabled] { + background-color: transparent; + border: 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-mbtn:focus:not(:disabled) { + background: #dee0e2; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-mbtn--active { + background: #c8cbcf; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { + background: #dee0e2; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-mbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-mbtn[disabled] .tox-mbtn__select-label { + cursor: not-allowed; +} + +.tox .tox-mbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; + display: none; +} + +.tox .tox-notification { + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + display: grid; + font-size: 14px; + font-weight: normal; + grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + margin-top: 4px; + opacity: 0; + padding: 4px; + transition: transform 100ms ease-in, opacity 150ms ease-in; +} + +.tox .tox-notification p { + font-size: 14px; + font-weight: normal; +} + +.tox .tox-notification a { + cursor: pointer; + text-decoration: underline; +} + +.tox .tox-notification--in { + opacity: 1; +} + +.tox .tox-notification--success { + background-color: #e4eeda; + border-color: #d7e6c8; + color: #222f3e; +} + +.tox .tox-notification--success p { + color: #222f3e; +} + +.tox .tox-notification--success a { + color: #517342; +} + +.tox .tox-notification--success svg { + fill: #222f3e; +} + +.tox .tox-notification--error { + background-color: #f5cccc; + border-color: #f0b3b3; + color: #222f3e; +} + +.tox .tox-notification--error p { + color: #222f3e; +} + +.tox .tox-notification--error a { + color: #77181f; +} + +.tox .tox-notification--error svg { + fill: #222f3e; +} + +.tox .tox-notification--warn, +.tox .tox-notification--warning { + background-color: #fff5cc; + border-color: #fff0b3; + color: #222f3e; +} + +.tox .tox-notification--warn p, +.tox .tox-notification--warning p { + color: #222f3e; +} + +.tox .tox-notification--warn a, +.tox .tox-notification--warning a { + color: #7a6e25; +} + +.tox .tox-notification--warn svg, +.tox .tox-notification--warning svg { + fill: #222f3e; +} + +.tox .tox-notification--info { + background-color: #d6e7fb; + border-color: #c1dbf9; + color: #222f3e; +} + +.tox .tox-notification--info p { + color: #222f3e; +} + +.tox .tox-notification--info a { + color: #2a64a6; +} + +.tox .tox-notification--info svg { + fill: #222f3e; +} + +.tox .tox-notification__body { + align-self: center; + color: #222f3e; + font-size: 14px; + grid-column-end: 3; + grid-column-start: 2; + grid-row-end: 2; + grid-row-start: 1; + text-align: center; + white-space: normal; + word-break: break-all; + word-break: break-word; +} + +.tox .tox-notification__body > * { + margin: 0; +} + +.tox .tox-notification__body > * + * { + margin-top: 1rem; +} + +.tox .tox-notification__icon { + align-self: center; + grid-column-end: 2; + grid-column-start: 1; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} + +.tox .tox-notification__icon svg { + display: block; +} + +.tox .tox-notification__dismiss { + align-self: start; + grid-column-end: 4; + grid-column-start: 3; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} + +.tox .tox-notification .tox-progress-bar { + grid-column-end: 4; + grid-column-start: 1; + grid-row-end: 3; + grid-row-start: 2; + justify-self: center; +} + +.tox .tox-pop { + display: inline-block; + position: relative; +} + +.tox .tox-pop--resizing { + transition: width 0.1s ease; +} + +.tox .tox-pop--resizing .tox-toolbar, +.tox .tox-pop--resizing .tox-toolbar__group { + flex-wrap: nowrap; +} + +.tox .tox-pop--transition { + transition: 0.15s ease; + transition-property: left, right, top, bottom; +} + +.tox .tox-pop--transition::before, +.tox .tox-pop--transition::after { + transition: all 0.15s, visibility 0s, opacity 0.075s ease 0.075s; +} + +.tox .tox-pop__dialog { + background-color: #fff; + border: 1px solid #cccccc; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + min-width: 0; + overflow: hidden; +} + +.tox .tox-pop__dialog > *:not(.tox-toolbar) { + margin: 4px 4px 4px 8px; +} + +.tox .tox-pop__dialog .tox-toolbar { + background-color: transparent; + margin-bottom: -1px; +} + +.tox .tox-pop::before, +.tox .tox-pop::after { + border-style: solid; + content: ''; + display: block; + height: 0; + opacity: 1; + position: absolute; + width: 0; +} + +.tox .tox-pop.tox-pop--inset::before, +.tox .tox-pop.tox-pop--inset::after { + opacity: 0; + transition: all 0s 0.15s, visibility 0s, opacity 0.075s ease; +} + +.tox .tox-pop.tox-pop--bottom::before, +.tox .tox-pop.tox-pop--bottom::after { + left: 50%; + top: 100%; +} + +.tox .tox-pop.tox-pop--bottom::after { + border-color: #fff transparent transparent transparent; + border-width: 8px; + margin-left: -8px; + margin-top: -1px; +} + +.tox .tox-pop.tox-pop--bottom::before { + border-color: #cccccc transparent transparent transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--top::before, +.tox .tox-pop.tox-pop--top::after { + left: 50%; + top: 0; + transform: translateY(-100%); +} + +.tox .tox-pop.tox-pop--top::after { + border-color: transparent transparent #fff transparent; + border-width: 8px; + margin-left: -8px; + margin-top: 1px; +} + +.tox .tox-pop.tox-pop--top::before { + border-color: transparent transparent #cccccc transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--left::before, +.tox .tox-pop.tox-pop--left::after { + left: 0; + top: calc(50% - 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--left::after { + border-color: transparent #fff transparent transparent; + border-width: 8px; + margin-left: -15px; +} + +.tox .tox-pop.tox-pop--left::before { + border-color: transparent #cccccc transparent transparent; + border-width: 10px; + margin-left: -19px; +} + +.tox .tox-pop.tox-pop--right::before, +.tox .tox-pop.tox-pop--right::after { + left: 100%; + top: calc(50% + 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--right::after { + border-color: transparent transparent transparent #fff; + border-width: 8px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--right::before { + border-color: transparent transparent transparent #cccccc; + border-width: 10px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--align-left::before, +.tox .tox-pop.tox-pop--align-left::after { + left: 20px; +} + +.tox .tox-pop.tox-pop--align-right::before, +.tox .tox-pop.tox-pop--align-right::after { + left: calc(100% - 20px); +} + +.tox .tox-sidebar-wrap { + display: flex; + flex-direction: row; + flex-grow: 1; + min-height: 0; +} + +.tox .tox-sidebar { + background-color: #fff; + display: flex; + flex-direction: row; + justify-content: flex-end; +} + +.tox .tox-sidebar__slider { + display: flex; + overflow: hidden; +} + +.tox .tox-sidebar__pane-container { + display: flex; +} + +.tox .tox-sidebar__pane { + display: flex; +} + +.tox .tox-sidebar--sliding-closed { + opacity: 0; +} + +.tox .tox-sidebar--sliding-open { + opacity: 1; +} + +.tox .tox-sidebar--sliding-growing, +.tox .tox-sidebar--sliding-shrinking { + transition: width 0.5s ease, opacity 0.5s ease; +} + +.tox .tox-selector { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + display: inline-block; + height: 10px; + position: absolute; + width: 10px; +} + +.tox.tox-platform-touch .tox-selector { + height: 12px; + width: 12px; +} + +.tox .tox-slider { + align-items: center; + display: flex; + flex: 1; + height: 24px; + justify-content: center; + position: relative; +} + +.tox .tox-slider__rail { + background-color: transparent; + border: 1px solid #cccccc; + border-radius: 3px; + height: 10px; + min-width: 120px; + width: 100%; +} + +.tox .tox-slider__handle { + background-color: #207ab7; + border: 2px solid #185d8c; + border-radius: 3px; + box-shadow: none; + height: 24px; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: 14px; +} + +.tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { + margin-inline-start: 8px; +} + +.tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { + margin-inline-start: 32px; +} + +.tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { + margin-inline-start: 32px; +} + +.tox .tox-source-code { + overflow: auto; +} + +.tox .tox-spinner { + display: flex; +} + +.tox .tox-spinner > div { + animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; + background-color: rgba(34, 47, 62, 0.7); + border-radius: 100%; + height: 8px; + width: 8px; +} + +.tox .tox-spinner > div:nth-child(1) { + animation-delay: -0.32s; +} + +.tox .tox-spinner > div:nth-child(2) { + animation-delay: -0.16s; +} + +@keyframes tam-bouncing-dots { + 0%, + 80%, + 100% { + transform: scale(0); + } + 40% { + transform: scale(1); + } +} + +.tox:not([dir='rtl']) .tox-spinner > div:not(:first-child) { + margin-left: 4px; +} + +.tox[dir='rtl'] .tox-spinner > div:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-statusbar { + align-items: center; + background-color: #fff; + border-top: 1px solid #cccccc; + color: rgba(34, 47, 62, 0.7); + display: flex; + flex: 0 0 auto; + font-size: 12px; + font-weight: normal; + height: 18px; + overflow: hidden; + padding: 0 8px; + position: relative; + text-transform: uppercase; +} + +.tox .tox-statusbar__text-container { + display: flex; + flex: 1 1 auto; + justify-content: flex-end; + overflow: hidden; +} + +.tox .tox-statusbar__path { + display: flex; + flex: 1 1 auto; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tox .tox-statusbar__path > * { + display: inline; + white-space: nowrap; +} + +.tox .tox-statusbar__wordcount { + flex: 0 0 auto; + margin-left: 1ch; +} + +.tox .tox-statusbar a, +.tox .tox-statusbar__path-item, +.tox .tox-statusbar__wordcount { + color: rgba(34, 47, 62, 0.7); + text-decoration: none; +} + +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']) { + color: #222f3e; + cursor: pointer; +} + +.tox .tox-statusbar__branding svg { + fill: rgba(34, 47, 62, 0.8); + height: 1.14em; + vertical-align: -0.28em; + width: 3.6em; +} + +.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled='true']) svg, +.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled='true']) svg { + fill: #222f3e; +} + +.tox .tox-statusbar__resize-handle { + align-items: flex-end; + align-self: stretch; + cursor: nwse-resize; + display: flex; + flex: 0 0 auto; + justify-content: flex-end; + margin-left: auto; + margin-right: -8px; + padding-bottom: 3px; + padding-left: 1ch; + padding-right: 3px; +} + +.tox .tox-statusbar__resize-handle svg { + display: block; + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-statusbar__resize-handle:focus svg { + background-color: #dee0e2; + border-radius: 1px 1px -4px 1px; + box-shadow: 0 0 0 2px #dee0e2; +} + +.tox:not([dir='rtl']) .tox-statusbar__path > * { + margin-right: 4px; +} + +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 2ch; +} + +.tox[dir='rtl'] .tox-statusbar { + flex-direction: row-reverse; +} + +.tox[dir='rtl'] .tox-statusbar__path > * { + margin-left: 4px; +} + +.tox .tox-throbber { + z-index: 1299; +} + +.tox .tox-throbber__busy-spinner { + align-items: center; + background-color: rgba(255, 255, 255, 0.6); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.tox .tox-tbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #222f3e; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 34px; + justify-content: center; + margin: 3px 0 2px 0; + outline: none; + overflow: hidden; + padding: 0; + text-transform: none; + width: 34px; +} + +.tox .tox-tbtn svg { + display: block; + fill: #222f3e; +} + +.tox .tox-tbtn.tox-tbtn-more { + padding-left: 5px; + padding-right: 5px; + width: inherit; +} + +.tox .tox-tbtn:focus { + background: #dee0e2; + border: 0; + box-shadow: none; +} + +.tox .tox-tbtn:hover { + background: #dee0e2; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-tbtn:hover svg { + fill: #222f3e; +} + +.tox .tox-tbtn:active { + background: #c8cbcf; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-tbtn:active svg { + fill: #222f3e; +} + +.tox .tox-tbtn--disabled, +.tox .tox-tbtn--disabled:hover, +.tox .tox-tbtn:disabled, +.tox .tox-tbtn:disabled:hover { + background: transparent; + border: 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-tbtn--disabled svg, +.tox .tox-tbtn--disabled:hover svg, +.tox .tox-tbtn:disabled svg, +.tox .tox-tbtn:disabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-tbtn--enabled, +.tox .tox-tbtn--enabled:hover { + background: #c8cbcf; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-tbtn--enabled > *, +.tox .tox-tbtn--enabled:hover > * { + transform: none; +} + +.tox .tox-tbtn--enabled svg, +.tox .tox-tbtn--enabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: #222f3e; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { + color: #222f3e; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { + fill: #222f3e; +} + +.tox .tox-tbtn:active > * { + transform: none; +} + +.tox .tox-tbtn--md { + height: 51px; + width: 51px; +} + +.tox .tox-tbtn--lg { + flex-direction: column; + height: 68px; + width: 68px; +} + +.tox .tox-tbtn--return { + align-self: stretch; + height: unset; + width: 16px; +} + +.tox .tox-tbtn--labeled { + padding: 0 4px; + width: unset; +} + +.tox .tox-tbtn__vlabel { + display: block; + font-size: 10px; + font-weight: normal; + letter-spacing: -0.025em; + margin-bottom: 4px; + white-space: nowrap; +} + +.tox .tox-tbtn--select { + margin: 3px 0 2px 0; + padding: 0 4px; + width: auto; +} + +.tox .tox-tbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-tbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-tbtn__select-chevron svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-tbtn--bespoke { + background: transparent; +} + +.tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { + margin-inline-start: 0; +} + +.tox .tox-tbtn--bespoke .tox-tbtn__select-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 7em; +} + +.tox .tox-split-button { + border: 0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + margin: 3px 0 2px 0; + overflow: hidden; +} + +.tox .tox-split-button:hover { + box-shadow: 0 0 0 1px #dee0e2 inset; +} + +.tox .tox-split-button:focus { + background: #dee0e2; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-split-button > * { + border-radius: 0; +} + +.tox .tox-split-button__chevron { + width: 16px; +} + +.tox .tox-split-button__chevron svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-split-button .tox-tbtn { + margin: 0; +} + +.tox .tox-split-button.tox-tbtn--disabled:hover, +.tox .tox-split-button.tox-tbtn--disabled:focus, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus { + background: transparent; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} + +.tox.tox-platform-touch .tox-split-button .tox-tbtn--select { + padding: 0 0px; +} + +.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { + width: 30px; +} + +.tox.tox-platform-touch .tox-split-button__chevron { + width: 20px; +} + +.tox .tox-toolbar-overlord { + background-color: #fff; +} + +.tox .tox-toolbar, +.tox .tox-toolbar__primary, +.tox .tox-toolbar__overflow { + background-color: #fff; + background-image: repeating-linear-gradient(#cccccc 0px 1px, transparent 1px 39px); + background-position: center top 39px; + background-repeat: no-repeat; + background-size: calc(100% - 4px * 2) calc(100% - 39px); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 0px; + transform: perspective(1px); +} + +.tox .tox-toolbar-overlord > .tox-toolbar, +.tox .tox-toolbar-overlord > .tox-toolbar__primary, +.tox .tox-toolbar-overlord > .tox-toolbar__overflow { + background-position: center top 0px; + background-size: calc(100% - 4px * 2) calc(100% - 0px); +} + +.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { + height: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; + visibility: hidden; +} + +.tox .tox-toolbar__overflow--growing { + transition: height 0.3s ease, opacity 0.2s linear 0.1s; +} + +.tox .tox-toolbar__overflow--shrinking { + transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; +} + +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: 1px solid #cccccc; + margin-top: 0; + padding-bottom: 0px; + padding-top: 0px; +} + +.tox .tox-toolbar--scrolling { + flex-wrap: nowrap; + overflow-x: auto; +} + +.tox .tox-pop .tox-toolbar { + border-width: 0; +} + +.tox .tox-toolbar--no-divider { + background-image: none; +} + +.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, +.tox .tox-toolbar-overlord .tox-toolbar__primary { + background-position: center top 39px; +} + +.tox .tox-editor-header > .tox-toolbar--scrolling, +.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { + background-image: none; +} + +.tox.tox-tinymce-aux .tox-toolbar__overflow { + background-color: #fff; + background-position: center top 43px; + background-size: calc(100% - 8px * 2) calc(100% - 51px); + border: none; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + padding: 4px 0; +} + +.tox-pop .tox-pop__dialog { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox-pop .tox-pop__dialog .tox-toolbar { + background-position: center top 43px; + background-size: calc(100% - 4px * 2) calc(100% - 51px); + padding: 4px 0; +} + +.tox .tox-toolbar__group { + align-items: center; + display: flex; + flex-wrap: wrap; + margin: 0 0; + padding: 0 4px 0 4px; +} + +.tox .tox-toolbar__group--pull-right { + margin-left: auto; +} + +.tox .tox-toolbar--scrolling .tox-toolbar__group { + flex-shrink: 0; + flex-wrap: nowrap; +} + +.tox:not([dir='rtl']) .tox-toolbar__group:not(:last-of-type) { + border-right: 1px solid #cccccc; +} + +.tox[dir='rtl'] .tox-toolbar__group:not(:last-of-type) { + border-left: 1px solid #cccccc; +} + +.tox .tox-tooltip { + display: inline-block; + padding: 8px; + position: relative; +} + +.tox .tox-tooltip__body { + background-color: #222f3e; + border-radius: 3px; + box-shadow: 0 2px 4px rgba(34, 47, 62, 0.3); + color: rgba(255, 255, 255, 0.75); + font-size: 14px; + font-style: normal; + font-weight: normal; + padding: 4px 8px; + text-transform: none; +} + +.tox .tox-tooltip__arrow { + position: absolute; +} + +.tox .tox-tooltip--down .tox-tooltip__arrow { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #222f3e; + bottom: 0; + left: 50%; + position: absolute; + transform: translateX(-50%); +} + +.tox .tox-tooltip--up .tox-tooltip__arrow { + border-bottom: 8px solid #222f3e; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + left: 50%; + position: absolute; + top: 0; + transform: translateX(-50%); +} + +.tox .tox-tooltip--right .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-left: 8px solid #222f3e; + border-top: 8px solid transparent; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-tooltip--left .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-right: 8px solid #222f3e; + border-top: 8px solid transparent; + left: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-well { + border: 1px solid #cccccc; + border-radius: 3px; + padding: 8px; + width: 100%; +} + +.tox .tox-well > *:first-child { + margin-top: 0; +} + +.tox .tox-well > *:last-child { + margin-bottom: 0; +} + +.tox .tox-well > *:only-child { + margin: 0; +} + +.tox .tox-custom-editor { + border: 1px solid #cccccc; + border-radius: 3px; + display: flex; + flex: 1; + position: relative; +} + +/* stylelint-disable */ +.tox { + /* stylelint-enable */ +} + +.tox .tox-dialog-loading::before { + background-color: rgba(0, 0, 0, 0.5); + content: ''; + height: 100%; + position: absolute; + width: 100%; + z-index: 1000; +} + +.tox .tox-tab { + cursor: pointer; +} + +.tox .tox-dialog__content-js { + display: flex; + flex: 1; +} + +.tox .tox-dialog__body-content .tox-collection { + display: flex; + flex: 1; +} + +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: none; + padding: 0; +} + +.tox.tox-tinymce--toolbar-bottom .tox-editor-header, +.tox.tox-tinymce-inline .tox-editor-header { + margin-bottom: -1px; +} + +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: none; + box-shadow: none; +} + +.tox.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: transparent; + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); + padding: 0; +} + +.tox.tox.tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); +} + +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: -4px 0; +} + +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0; +} + +.tox .tox-pop { + box-shadow: none; +} + +.tox .tox-tbtn, +.tox .tox-tbtn--select, +.tox .tox-split-button { + margin: 2px 0 3px 0; +} + +.tox .tox-toolbar, +.tox .tox-toolbar__primary, +.tox .tox-toolbar__overflow { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0px #fff !important; +} + +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: none; +} + +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord .tox-toolbar__primary { + border-top: 1px solid #cccccc; + margin-top: -1px; +} + +.tox.tox-tinymce-aux .tox-toolbar__overflow { + border: 1px solid #cccccc; + padding: 0; +} + +.tox:not(.tox-tinymce-inline) +.tox-editor-header:not(:first-child) +.tox-toolbar-overlord:first-child +.tox-toolbar__primary, +.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child { + border-top: 1px solid #cccccc; +} + +.tox .tox-toolbar__group { + padding: 0 4px 0 4px; +} + +.tox .tox-collection__item { + border-radius: 0; + cursor: pointer; +} + +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']) { + color: rgba(34, 47, 62, 0.7); + text-decoration: underline; +} + +.tox .tox-statusbar__branding svg { + vertical-align: -0.25em; +} + +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 1ch; +} + +.tox .tox-statusbar__resize-handle { + padding-bottom: 0; + padding-right: 0; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.min.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.min.css new file mode 100644 index 00000000..62db7f27 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.min.css @@ -0,0 +1,3125 @@ +.tox { + box-shadow: none; + box-sizing: content-box; + color: #222f3e; + cursor: auto; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; + -webkit-tap-highlight-color: transparent; + text-decoration: none; + text-shadow: none; + text-transform: none; + vertical-align: initial; + white-space: normal; +} +.tox :not(svg):not(rect) { + box-sizing: inherit; + color: inherit; + cursor: inherit; + direction: inherit; + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; + line-height: inherit; + -webkit-tap-highlight-color: inherit; + text-align: inherit; + text-decoration: inherit; + text-shadow: inherit; + text-transform: inherit; + vertical-align: inherit; + white-space: inherit; +} +.tox :not(svg):not(rect) { + background: 0 0; + border: 0; + box-shadow: none; + float: none; + height: auto; + margin: 0; + max-width: none; + outline: 0; + padding: 0; + position: static; + width: auto; +} +.tox:not([dir='rtl']) { + direction: ltr; + text-align: left; +} +.tox[dir='rtl'] { + direction: rtl; + text-align: right; +} +.tox-tinymce { + border: 1px solid #ccc; + border-radius: 0; + box-shadow: none; + box-sizing: border-box; + display: flex; + flex-direction: column; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + overflow: hidden; + position: relative; + visibility: inherit !important; +} +.tox.tox-tinymce-inline { + border: none; + box-shadow: none; + overflow: initial; +} +.tox.tox-tinymce-inline .tox-editor-container { + overflow: initial; +} +.tox.tox-tinymce-inline .tox-editor-header { + background-color: #fff; + border: 1px solid #ccc; + border-radius: 0; + box-shadow: none; + overflow: hidden; +} +.tox-tinymce-aux { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + z-index: 1300; +} +.tox-tinymce :focus, +.tox-tinymce-aux :focus { + outline: 0; +} +button::-moz-focus-inner { + border: 0; +} +.tox[dir='rtl'] .tox-icon--flip svg { + transform: rotateY(180deg); +} +.tox .accessibility-issue__header { + align-items: center; + display: flex; + margin-bottom: 4px; +} +.tox .accessibility-issue__description { + align-items: stretch; + border: 1px solid #ccc; + border-radius: 3px; + display: flex; + justify-content: space-between; +} +.tox .accessibility-issue__description > div { + padding-bottom: 4px; +} +.tox .accessibility-issue__description > div > div { + align-items: center; + display: flex; + margin-bottom: 4px; +} +.tox .accessibility-issue__description > :last-child:not(:only-child) { + border-color: #ccc; + border-style: solid; +} +.tox .accessibility-issue__repair { + margin-top: 16px; +} +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { + background-color: rgba(32, 122, 183, 0.1); + border-color: rgba(32, 122, 183, 0.4); + color: #222f3e; +} +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description > :last-child { + border-color: rgba(32, 122, 183, 0.4); +} +.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { + color: #207ab7; +} +.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { + fill: #207ab7; +} +.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon { + color: #207ab7; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { + background-color: rgba(255, 165, 0, 0.1); + border-color: rgba(255, 165, 0, 0.5); + color: #222f3e; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description > :last-child { + border-color: rgba(255, 165, 0, 0.5); +} +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { + color: #cc8500; +} +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { + fill: #cc8500; +} +.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon { + color: #cc8500; +} +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { + background-color: rgba(204, 0, 0, 0.1); + border-color: rgba(204, 0, 0, 0.4); + color: #222f3e; +} +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description > :last-child { + border-color: rgba(204, 0, 0, 0.4); +} +.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { + color: #c00; +} +.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { + fill: #c00; +} +.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon { + color: #c00; +} +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { + background-color: rgba(120, 171, 70, 0.1); + border-color: rgba(120, 171, 70, 0.4); + color: #222f3e; +} +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > :last-child { + border-color: rgba(120, 171, 70, 0.4); +} +.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { + color: #78ab46; +} +.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { + fill: #78ab46; +} +.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon { + color: #78ab46; +} +.tox .tox-dialog__body-content .accessibility-issue__header h1, +.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { + margin-top: 0; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__header > :nth-last-child(2) { + margin-left: auto; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 4px 4px 8px; +} +.tox:not([dir='rtl']) .tox-dialog__body-content .accessibility-issue__description > :last-child { + border-left-width: 1px; + padding-left: 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__header > :nth-last-child(2) { + margin-right: auto; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 8px 4px 4px; +} +.tox[dir='rtl'] .tox-dialog__body-content .accessibility-issue__description > :last-child { + border-right-width: 1px; + padding-right: 4px; +} +.tox .tox-anchorbar { + display: flex; + flex: 0 0 auto; +} +.tox .tox-bar { + display: flex; + flex: 0 0 auto; +} +.tox .tox-button { + background-color: #207ab7; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #207ab7; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 14px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + line-height: 24px; + margin: 0; + outline: 0; + padding: 4px 16px; + text-align: center; + text-decoration: none; + text-transform: none; + white-space: nowrap; +} +.tox .tox-button[disabled] { + background-color: #207ab7; + background-image: none; + border-color: #207ab7; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} +.tox .tox-button:focus:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} +.tox .tox-button:hover:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} +.tox .tox-button:active:not(:disabled) { + background-color: #185d8c; + background-image: none; + border-color: #185d8c; + box-shadow: none; + color: #fff; +} +.tox .tox-button--secondary { + background-color: #f0f0f0; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #f0f0f0; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + color: #222f3e; + font-size: 14px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + outline: 0; + padding: 4px 16px; + text-decoration: none; + text-transform: none; +} +.tox .tox-button--secondary[disabled] { + background-color: #f0f0f0; + background-image: none; + border-color: #f0f0f0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} +.tox .tox-button--secondary:focus:not(:disabled) { + background-color: #e3e3e3; + background-image: none; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} +.tox .tox-button--secondary:hover:not(:disabled) { + background-color: #e3e3e3; + background-image: none; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} +.tox .tox-button--secondary:active:not(:disabled) { + background-color: #d6d6d6; + background-image: none; + border-color: #d6d6d6; + box-shadow: none; + color: #222f3e; +} +.tox .tox-button--icon, +.tox .tox-button.tox-button--icon, +.tox .tox-button.tox-button--secondary.tox-button--icon { + padding: 4px; +} +.tox .tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { + display: block; + fill: currentColor; +} +.tox .tox-button-link { + background: 0; + border: none; + box-sizing: border-box; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + font-weight: 400; + line-height: 1.3; + margin: 0; + padding: 0; + white-space: nowrap; +} +.tox .tox-button-link--sm { + font-size: 14px; +} +.tox .tox-button--naked { + background-color: transparent; + border-color: transparent; + box-shadow: unset; + color: #222f3e; +} +.tox .tox-button--naked[disabled] { + background-color: #f0f0f0; + border-color: #f0f0f0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} +.tox .tox-button--naked:hover:not(:disabled) { + background-color: #e3e3e3; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} +.tox .tox-button--naked:focus:not(:disabled) { + background-color: #e3e3e3; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} +.tox .tox-button--naked:active:not(:disabled) { + background-color: #d6d6d6; + border-color: #d6d6d6; + box-shadow: none; + color: #222f3e; +} +.tox .tox-button--naked .tox-icon svg { + fill: currentColor; +} +.tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { + color: #222f3e; +} +.tox .tox-checkbox { + align-items: center; + border-radius: 3px; + cursor: pointer; + display: flex; + height: 36px; + min-width: 36px; +} +.tox .tox-checkbox__input { + height: 1px; + overflow: hidden; + position: absolute; + top: auto; + width: 1px; +} +.tox .tox-checkbox__icons { + align-items: center; + border-radius: 3px; + box-shadow: 0 0 0 2px transparent; + box-sizing: content-box; + display: flex; + height: 24px; + justify-content: center; + padding: calc(4px - 1px); + width: 24px; +} +.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: block; + fill: rgba(34, 47, 62, 0.3); +} +.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: none; + fill: #207ab7; +} +.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: none; + fill: #207ab7; +} +.tox .tox-checkbox--disabled { + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: block; +} +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: block; +} +.tox input.tox-checkbox__input:focus + .tox-checkbox__icons { + border-radius: 3px; + box-shadow: inset 0 0 0 1px #207ab7; + padding: calc(4px - 1px); +} +.tox:not([dir='rtl']) .tox-checkbox__label { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-checkbox__input { + left: -10000px; +} +.tox:not([dir='rtl']) .tox-bar .tox-checkbox { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-checkbox__label { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-checkbox__input { + right: -10000px; +} +.tox[dir='rtl'] .tox-bar .tox-checkbox { + margin-right: 4px; +} +.tox .tox-collection--toolbar .tox-collection__group { + display: flex; + padding: 0; +} +.tox .tox-collection--grid .tox-collection__group { + display: flex; + flex-wrap: wrap; + max-height: 208px; + overflow-x: hidden; + overflow-y: auto; + padding: 0; +} +.tox .tox-collection--list .tox-collection__group { + border-bottom-width: 0; + border-color: #ccc; + border-left-width: 0; + border-right-width: 0; + border-style: solid; + border-top-width: 1px; + padding: 4px 0; +} +.tox .tox-collection--list .tox-collection__group:first-child { + border-top-width: 0; +} +.tox .tox-collection__group-heading { + background-color: #e6e6e6; + color: rgba(34, 47, 62, 0.7); + cursor: default; + font-size: 12px; + font-style: normal; + font-weight: 400; + margin-bottom: 4px; + margin-top: -4px; + padding: 4px 8px; + text-transform: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.tox .tox-collection__item { + align-items: center; + border-radius: 3px; + color: #222f3e; + display: flex; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.tox .tox-collection--list .tox-collection__item { + padding: 4px 8px; +} +.tox .tox-collection--toolbar .tox-collection__item { + border-radius: 3px; + padding: 4px; +} +.tox .tox-collection--grid .tox-collection__item { + border-radius: 3px; + padding: 4px; +} +.tox .tox-collection--list .tox-collection__item--enabled { + background-color: #fff; + color: #222f3e; +} +.tox .tox-collection--list .tox-collection__item--active { + background-color: #dee0e2; +} +.tox .tox-collection--toolbar .tox-collection__item--enabled { + background-color: #c8cbcf; + color: #222f3e; +} +.tox .tox-collection--toolbar .tox-collection__item--active { + background-color: #dee0e2; +} +.tox .tox-collection--grid .tox-collection__item--enabled { + background-color: #c8cbcf; + color: #222f3e; +} +.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + background-color: #dee0e2; + color: #222f3e; +} +.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #222f3e; +} +.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #222f3e; +} +.tox .tox-collection__item-checkmark, +.tox .tox-collection__item-icon { + align-items: center; + display: flex; + height: 24px; + justify-content: center; + width: 24px; +} +.tox .tox-collection__item-checkmark svg, +.tox .tox-collection__item-icon svg { + fill: currentColor; +} +.tox .tox-collection--toolbar-lg .tox-collection__item-icon { + height: 48px; + width: 48px; +} +.tox .tox-collection__item-label { + color: currentColor; + display: inline-block; + flex: 1; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 24px; + text-transform: none; + word-break: break-all; +} +.tox .tox-collection__item-accessory { + color: rgba(34, 47, 62, 0.7); + display: inline-block; + font-size: 14px; + height: 24px; + line-height: 24px; + text-transform: none; +} +.tox .tox-collection__item-caret { + align-items: center; + display: flex; + min-height: 24px; +} +.tox .tox-collection__item-caret::after { + content: ''; + font-size: 0; + min-height: inherit; +} +.tox .tox-collection__item-caret svg { + fill: #222f3e; +} +.tox .tox-collection__item--state-disabled { + background-color: transparent; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} +.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox + .tox-collection--list + .tox-collection__item:not(.tox-collection__item--enabled) + .tox-collection__item-checkmark + svg { + display: none; +} +.tox + .tox-collection--list + .tox-collection__item:not(.tox-collection__item--enabled) + .tox-collection__item-accessory + + .tox-collection__item-checkmark { + display: none; +} +.tox .tox-collection--horizontal { + background-color: #fff; + border: 1px solid #ccc; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: nowrap; + margin-bottom: 0; + overflow-x: auto; + padding: 0; +} +.tox .tox-collection--horizontal .tox-collection__group { + align-items: center; + display: flex; + flex-wrap: nowrap; + margin: 0; + padding: 0 4px; +} +.tox .tox-collection--horizontal .tox-collection__item { + height: 34px; + margin: 3px 0 2px 0; + padding: 0 4px; +} +.tox .tox-collection--horizontal .tox-collection__item-label { + white-space: nowrap; +} +.tox .tox-collection--horizontal .tox-collection__item-caret { + margin-left: 4px; +} +.tox .tox-collection__item-container { + display: flex; +} +.tox .tox-collection__item-container--row { + align-items: center; + flex: 1 1 auto; + flex-direction: row; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--align-left { + margin-right: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--align-right { + justify-content: flex-end; + margin-left: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { + align-items: flex-start; + margin-bottom: auto; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { + align-items: center; +} +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { + align-items: flex-end; + margin-top: auto; +} +.tox .tox-collection__item-container--column { + align-self: center; + flex: 1 1 auto; + flex-direction: column; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--align-left { + align-items: flex-start; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--align-right { + align-items: flex-end; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { + align-self: flex-start; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { + align-self: center; +} +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { + align-self: flex-end; +} +.tox:not([dir='rtl']) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-right: 1px solid #ccc; +} +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > :not(:first-child) { + margin-left: 8px; +} +.tox:not([dir='rtl']) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-left: 4px; +} +.tox:not([dir='rtl']) .tox-collection__item-accessory { + margin-left: 16px; + text-align: right; +} +.tox:not([dir='rtl']) .tox-collection .tox-collection__item-caret { + margin-left: 16px; +} +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-left: 1px solid #ccc; +} +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > :not(:first-child) { + margin-right: 8px; +} +.tox[dir='rtl'] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-right: 4px; +} +.tox[dir='rtl'] .tox-collection__item-accessory { + margin-right: 16px; + text-align: left; +} +.tox[dir='rtl'] .tox-collection .tox-collection__item-caret { + margin-right: 16px; + transform: rotateY(180deg); +} +.tox[dir='rtl'] .tox-collection--horizontal .tox-collection__item-caret { + margin-right: 4px; +} +.tox .tox-color-picker-container { + display: flex; + flex-direction: row; + height: 225px; + margin: 0; +} +.tox .tox-sv-palette { + box-sizing: border-box; + display: flex; + height: 100%; +} +.tox .tox-sv-palette-spectrum { + height: 100%; +} +.tox .tox-sv-palette, +.tox .tox-sv-palette-spectrum { + width: 225px; +} +.tox .tox-sv-palette-thumb { + background: 0 0; + border: 1px solid #000; + border-radius: 50%; + box-sizing: content-box; + height: 12px; + position: absolute; + width: 12px; +} +.tox .tox-sv-palette-inner-thumb { + border: 1px solid #fff; + border-radius: 50%; + height: 10px; + position: absolute; + width: 10px; +} +.tox .tox-hue-slider { + box-sizing: border-box; + height: 100%; + width: 25px; +} +.tox .tox-hue-slider-spectrum { + background: linear-gradient( + to bottom, + red, + #ff0080, + #f0f, + #8000ff, + #00f, + #0080ff, + #0ff, + #00ff80, + #0f0, + #80ff00, + #ff0, + #ff8000, + red + ); + height: 100%; + width: 100%; +} +.tox .tox-hue-slider, +.tox .tox-hue-slider-spectrum { + width: 20px; +} +.tox .tox-hue-slider-thumb { + background: #fff; + border: 1px solid #000; + box-sizing: content-box; + height: 4px; + width: 100%; +} +.tox .tox-rgb-form { + display: flex; + flex-direction: column; + justify-content: space-between; +} +.tox .tox-rgb-form div { + align-items: center; + display: flex; + justify-content: space-between; + margin-bottom: 5px; + width: inherit; +} +.tox .tox-rgb-form input { + width: 6em; +} +.tox .tox-rgb-form input.tox-invalid { + border: 1px solid red !important; +} +.tox .tox-rgb-form .tox-rgba-preview { + border: 1px solid #000; + flex-grow: 2; + margin-bottom: 0; +} +.tox:not([dir='rtl']) .tox-sv-palette { + margin-right: 15px; +} +.tox:not([dir='rtl']) .tox-hue-slider { + margin-right: 15px; +} +.tox:not([dir='rtl']) .tox-hue-slider-thumb { + margin-left: -1px; +} +.tox:not([dir='rtl']) .tox-rgb-form label { + margin-right: 0.5em; +} +.tox[dir='rtl'] .tox-sv-palette { + margin-left: 15px; +} +.tox[dir='rtl'] .tox-hue-slider { + margin-left: 15px; +} +.tox[dir='rtl'] .tox-hue-slider-thumb { + margin-right: -1px; +} +.tox[dir='rtl'] .tox-rgb-form label { + margin-left: 0.5em; +} +.tox .tox-toolbar .tox-swatches, +.tox .tox-toolbar__overflow .tox-swatches, +.tox .tox-toolbar__primary .tox-swatches { + margin: 2px 0 3px 4px; +} +.tox .tox-collection--list .tox-collection__group .tox-swatches-menu { + border: 0; + margin: -4px 0; +} +.tox .tox-swatches__row { + display: flex; +} +.tox .tox-swatch { + height: 30px; + transition: transform 0.15s, box-shadow 0.15s; + width: 30px; +} +.tox .tox-swatch:focus, +.tox .tox-swatch:hover { + box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; + transform: scale(0.8); +} +.tox .tox-swatch--remove { + align-items: center; + display: flex; + justify-content: center; +} +.tox .tox-swatch--remove svg path { + stroke: #e74c3c; +} +.tox .tox-swatches__picker-btn { + align-items: center; + background-color: transparent; + border: 0; + cursor: pointer; + display: flex; + height: 30px; + justify-content: center; + outline: 0; + padding: 0; + width: 30px; +} +.tox .tox-swatches__picker-btn svg { + fill: #222f3e; + height: 24px; + width: 24px; +} +.tox .tox-swatches__picker-btn:hover { + background: #dee0e2; +} +.tox:not([dir='rtl']) .tox-swatches__picker-btn { + margin-left: auto; +} +.tox[dir='rtl'] .tox-swatches__picker-btn { + margin-right: auto; +} +.tox .tox-comment-thread { + background: #fff; + position: relative; +} +.tox .tox-comment-thread > :not(:first-child) { + margin-top: 8px; +} +.tox .tox-comment { + background: #fff; + border: 1px solid #ccc; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); + padding: 8px 8px 16px 8px; + position: relative; +} +.tox .tox-comment__header { + align-items: center; + color: #222f3e; + display: flex; + justify-content: space-between; +} +.tox .tox-comment__date { + color: rgba(34, 47, 62, 0.7); + font-size: 12px; +} +.tox .tox-comment__body { + color: #222f3e; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + margin-top: 8px; + position: relative; + text-transform: initial; +} +.tox .tox-comment__body textarea { + resize: none; + white-space: normal; + width: 100%; +} +.tox .tox-comment__expander { + padding-top: 8px; +} +.tox .tox-comment__expander p { + color: rgba(34, 47, 62, 0.7); + font-size: 14px; + font-style: normal; +} +.tox .tox-comment__body p { + margin: 0; +} +.tox .tox-comment__buttonspacing { + padding-top: 16px; + text-align: center; +} +.tox .tox-comment-thread__overlay::after { + background: #fff; + bottom: 0; + content: ''; + display: flex; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + top: 0; + z-index: 5; +} +.tox .tox-comment__reply { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 8px; +} +.tox .tox-comment__reply > :first-child { + margin-bottom: 8px; + width: 100%; +} +.tox .tox-comment__edit { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 16px; +} +.tox .tox-comment__gradient::after { + background: linear-gradient(rgba(255, 255, 255, 0), #fff); + bottom: 0; + content: ''; + display: block; + height: 5em; + margin-top: -40px; + position: absolute; + width: 100%; +} +.tox .tox-comment__overlay { + background: #fff; + bottom: 0; + display: flex; + flex-direction: column; + flex-grow: 1; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + text-align: center; + top: 0; + z-index: 5; +} +.tox .tox-comment__loading-text { + align-items: center; + color: #222f3e; + display: flex; + flex-direction: column; + position: relative; +} +.tox .tox-comment__loading-text > div { + padding-bottom: 16px; +} +.tox .tox-comment__overlaytext { + bottom: 0; + flex-direction: column; + font-size: 14px; + left: 0; + padding: 1em; + position: absolute; + right: 0; + top: 0; + z-index: 10; +} +.tox .tox-comment__overlaytext p { + background-color: #fff; + box-shadow: 0 0 8px 8px #fff; + color: #222f3e; + text-align: center; +} +.tox .tox-comment__overlaytext div:nth-of-type(2) { + font-size: 0.8em; +} +.tox .tox-comment__busy-spinner { + align-items: center; + background-color: #fff; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 20; +} +.tox .tox-comment__scroll { + display: flex; + flex-direction: column; + flex-shrink: 1; + overflow: auto; +} +.tox .tox-conversations { + margin: 8px; +} +.tox:not([dir='rtl']) .tox-comment__edit { + margin-left: 8px; +} +.tox:not([dir='rtl']) .tox-comment__buttonspacing > :last-child, +.tox:not([dir='rtl']) .tox-comment__edit > :last-child, +.tox:not([dir='rtl']) .tox-comment__reply > :last-child { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-comment__edit { + margin-right: 8px; +} +.tox[dir='rtl'] .tox-comment__buttonspacing > :last-child, +.tox[dir='rtl'] .tox-comment__edit > :last-child, +.tox[dir='rtl'] .tox-comment__reply > :last-child { + margin-right: 8px; +} +.tox .tox-user { + align-items: center; + display: flex; +} +.tox .tox-user__avatar svg { + fill: rgba(34, 47, 62, 0.7); +} +.tox .tox-user__name { + color: rgba(34, 47, 62, 0.7); + font-size: 12px; + font-style: normal; + font-weight: 700; + text-transform: uppercase; +} +.tox:not([dir='rtl']) .tox-user__avatar svg { + margin-right: 8px; +} +.tox:not([dir='rtl']) .tox-user__avatar + .tox-user__name { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-user__avatar svg { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-user__avatar + .tox-user__name { + margin-right: 8px; +} +.tox .tox-dialog-wrap { + align-items: center; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 1100; +} +.tox .tox-dialog-wrap__backdrop { + background-color: rgba(255, 255, 255, 0.75); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} +.tox .tox-dialog-wrap__backdrop--opaque { + background-color: #fff; +} +.tox .tox-dialog { + background-color: #fff; + border-color: #ccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: 0 16px 16px -10px rgba(34, 47, 62, 0.15), 0 0 40px 1px rgba(34, 47, 62, 0.15); + display: flex; + flex-direction: column; + max-height: 100%; + max-width: 480px; + overflow: hidden; + position: relative; + width: 95vw; + z-index: 2; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog { + align-self: flex-start; + margin: 8px auto; + width: calc(100vw - 16px); + } +} +.tox .tox-dialog-inline { + z-index: 1100; +} +.tox .tox-dialog__header { + align-items: center; + background-color: #fff; + border-bottom: none; + color: #222f3e; + display: flex; + font-size: 16px; + justify-content: space-between; + padding: 8px 16px 0 16px; + position: relative; +} +.tox .tox-dialog__header .tox-button { + z-index: 1; +} +.tox .tox-dialog__draghandle { + cursor: grab; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.tox .tox-dialog__draghandle:active { + cursor: grabbing; +} +.tox .tox-dialog__dismiss { + margin-left: auto; +} +.tox .tox-dialog__title { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 20px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + margin: 0; + text-transform: none; +} +.tox .tox-dialog__body { + color: #222f3e; + display: flex; + flex: 1; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + min-width: 0; + text-align: left; + text-transform: none; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body { + flex-direction: column; + } +} +.tox .tox-dialog__body-nav { + align-items: flex-start; + display: flex; + flex-direction: column; + padding: 16px 16px; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { + flex-direction: row; + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding-bottom: 0; + } +} +.tox .tox-dialog__body-nav-item { + border-bottom: 2px solid transparent; + color: rgba(34, 47, 62, 0.7); + display: inline-block; + font-size: 14px; + line-height: 1.3; + margin-bottom: 8px; + text-decoration: none; + white-space: nowrap; +} +.tox .tox-dialog__body-nav-item:focus { + background-color: rgba(32, 122, 183, 0.1); +} +.tox .tox-dialog__body-nav-item--active { + border-bottom: 2px solid #207ab7; + color: #207ab7; +} +.tox .tox-dialog__body-content { + box-sizing: border-box; + display: flex; + flex: 1; + flex-direction: column; + max-height: 650px; + overflow: auto; + -webkit-overflow-scrolling: touch; + padding: 16px 16px; +} +.tox .tox-dialog__body-content > * { + margin-bottom: 0; + margin-top: 16px; +} +.tox .tox-dialog__body-content > :first-child { + margin-top: 0; +} +.tox .tox-dialog__body-content > :last-child { + margin-bottom: 0; +} +.tox .tox-dialog__body-content > :only-child { + margin-bottom: 0; + margin-top: 0; +} +.tox .tox-dialog__body-content a { + color: #207ab7; + cursor: pointer; + text-decoration: none; +} +.tox .tox-dialog__body-content a:focus, +.tox .tox-dialog__body-content a:hover { + color: #185d8c; + text-decoration: none; +} +.tox .tox-dialog__body-content a:active { + color: #185d8c; + text-decoration: none; +} +.tox .tox-dialog__body-content svg { + fill: #222f3e; +} +.tox .tox-dialog__body-content ul { + display: block; + list-style-type: disc; + margin-bottom: 16px; + margin-inline-end: 0; + margin-inline-start: 0; + padding-inline-start: 2.5rem; +} +.tox .tox-dialog__body-content .tox-form__group h1 { + color: #222f3e; + font-size: 20px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} +.tox .tox-dialog__body-content .tox-form__group h2 { + color: #222f3e; + font-size: 16px; + font-style: normal; + font-weight: 700; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} +.tox .tox-dialog__body-content .tox-form__group p { + margin-bottom: 16px; +} +.tox .tox-dialog__body-content .tox-form__group h1:first-child, +.tox .tox-dialog__body-content .tox-form__group h2:first-child, +.tox .tox-dialog__body-content .tox-form__group p:first-child { + margin-top: 0; +} +.tox .tox-dialog__body-content .tox-form__group h1:last-child, +.tox .tox-dialog__body-content .tox-form__group h2:last-child, +.tox .tox-dialog__body-content .tox-form__group p:last-child { + margin-bottom: 0; +} +.tox .tox-dialog__body-content .tox-form__group h1:only-child, +.tox .tox-dialog__body-content .tox-form__group h2:only-child, +.tox .tox-dialog__body-content .tox-form__group p:only-child { + margin-bottom: 0; + margin-top: 0; +} +.tox .tox-dialog--width-lg { + height: 650px; + max-width: 1200px; +} +.tox .tox-dialog--width-md { + max-width: 800px; +} +.tox .tox-dialog--width-md .tox-dialog__body-content { + overflow: auto; +} +.tox .tox-dialog__body-content--centered { + text-align: center; +} +.tox .tox-dialog__footer { + align-items: center; + background-color: #fff; + border-top: 1px solid #ccc; + display: flex; + justify-content: space-between; + padding: 8px 16px; +} +.tox .tox-dialog__footer-end, +.tox .tox-dialog__footer-start { + display: flex; +} +.tox .tox-dialog__busy-spinner { + align-items: center; + background-color: rgba(255, 255, 255, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 3; +} +.tox .tox-dialog__table { + border-collapse: collapse; + width: 100%; +} +.tox .tox-dialog__table thead th { + font-weight: 700; + padding-bottom: 8px; +} +.tox .tox-dialog__table tbody tr { + border-bottom: 1px solid #ccc; +} +.tox .tox-dialog__table tbody tr:last-child { + border-bottom: none; +} +.tox .tox-dialog__table td { + padding-bottom: 8px; + padding-top: 8px; +} +.tox .tox-dialog__popups { + position: absolute; + width: 100%; + z-index: 1100; +} +.tox .tox-dialog__body-iframe { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-dialog__body-iframe .tox-navobj { + display: flex; + flex: 1; +} +.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} +.tox .tox-dialog-dock-fadeout { + opacity: 0; + visibility: hidden; +} +.tox .tox-dialog-dock-fadein { + opacity: 1; + visibility: visible; +} +.tox .tox-dialog-dock-transition { + transition: visibility 0s linear 0.3s, opacity 0.3s ease; +} +.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { + transition-delay: 0s; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav { + margin-right: 0; + } +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir='rtl']) .tox-dialog__body-nav-item:not(:first-child) { + margin-left: 8px; + } +} +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-end > *, +.tox:not([dir='rtl']) .tox-dialog__footer .tox-dialog__footer-start > * { + margin-left: 8px; +} +.tox[dir='rtl'] .tox-dialog__body { + text-align: right; +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav { + margin-left: 0; + } +} +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir='rtl'] .tox-dialog__body-nav-item:not(:first-child) { + margin-right: 8px; + } +} +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-end > *, +.tox[dir='rtl'] .tox-dialog__footer .tox-dialog__footer-start > * { + margin-right: 8px; +} +body.tox-dialog__disable-scroll { + overflow: hidden; +} +.tox .tox-dropzone-container { + display: flex; + flex: 1; +} +.tox .tox-dropzone { + align-items: center; + background: #fff; + border: 2px dashed #ccc; + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-grow: 1; + justify-content: center; + min-height: 100px; + padding: 10px; +} +.tox .tox-dropzone p { + color: rgba(34, 47, 62, 0.7); + margin: 0 0 16px 0; +} +.tox .tox-edit-area { + display: flex; + flex: 1; + overflow: hidden; + position: relative; +} +.tox .tox-edit-area__iframe { + background-color: #fff; + border: 0; + box-sizing: border-box; + flex: 1; + height: 100%; + position: absolute; + width: 100%; +} +.tox.tox-inline-edit-area { + border: 1px dotted #ccc; +} +.tox .tox-editor-container { + display: flex; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} +.tox .tox-editor-header { + z-index: 1; +} +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: #fff; + border-bottom: none; + box-shadow: none; + padding: 4px 0; + transition: box-shadow 0.5s; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: 1px solid #c1c1c1; + box-shadow: none; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: #fff; + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); + padding: 4px 0; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); +} +.tox-editor-dock-fadeout { + opacity: 0; + visibility: hidden; +} +.tox-editor-dock-fadein { + opacity: 1; + visibility: visible; +} +.tox-editor-dock-transition { + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} +.tox-editor-dock-transition.tox-editor-dock-fadein { + transition-delay: 0s; +} +.tox .tox-control-wrap { + flex: 1; + position: relative; +} +.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, +.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, +.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { + display: none; +} +.tox .tox-control-wrap svg { + display: block; +} +.tox .tox-control-wrap__status-icon-wrap { + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-control-wrap__status-icon-invalid svg { + fill: #c00; +} +.tox .tox-control-wrap__status-icon-unknown svg { + fill: orange; +} +.tox .tox-control-wrap__status-icon-valid svg { + fill: green; +} +.tox:not([dir='rtl']) .tox-control-wrap--status-invalid .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-unknown .tox-textfield, +.tox:not([dir='rtl']) .tox-control-wrap--status-valid .tox-textfield { + padding-right: 32px; +} +.tox:not([dir='rtl']) .tox-control-wrap__status-icon-wrap { + right: 4px; +} +.tox[dir='rtl'] .tox-control-wrap--status-invalid .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-unknown .tox-textfield, +.tox[dir='rtl'] .tox-control-wrap--status-valid .tox-textfield { + padding-left: 32px; +} +.tox[dir='rtl'] .tox-control-wrap__status-icon-wrap { + left: 4px; +} +.tox .tox-autocompleter { + max-width: 25em; +} +.tox .tox-autocompleter .tox-menu { + border-color: #ccc; + box-shadow: none; + max-width: 25em; +} +.tox .tox-autocompleter .tox-autocompleter-highlight { + font-weight: 700; +} +.tox .tox-color-input { + display: flex; + position: relative; + z-index: 1; +} +.tox .tox-color-input .tox-textfield { + z-index: -1; +} +.tox .tox-color-input span { + border-color: rgba(34, 47, 62, 0.2); + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + height: 24px; + position: absolute; + top: 6px; + width: 24px; +} +.tox .tox-color-input span:focus:not([aria-disabled='true']), +.tox .tox-color-input span:hover:not([aria-disabled='true']) { + border-color: #207ab7; + cursor: pointer; +} +.tox .tox-color-input span::before { + background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), + linear-gradient(-45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%), + linear-gradient(-45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%); + background-position: 0 0, 0 6px, 6px -6px, -6px 0; + background-size: 12px 12px; + border: 1px solid #fff; + border-radius: 3px; + box-sizing: border-box; + content: ''; + height: 24px; + left: -1px; + position: absolute; + top: -1px; + width: 24px; + z-index: -1; +} +.tox .tox-color-input span[aria-disabled='true'] { + cursor: not-allowed; +} +.tox:not([dir='rtl']) .tox-color-input .tox-textfield { + padding-left: 36px; +} +.tox:not([dir='rtl']) .tox-color-input span { + left: 6px; +} +.tox[dir='rtl'] .tox-color-input .tox-textfield { + padding-right: 36px; +} +.tox[dir='rtl'] .tox-color-input span { + right: 6px; +} +.tox .tox-label, +.tox .tox-toolbar-label { + color: rgba(34, 47, 62, 0.7); + display: block; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 1.3; + padding: 0 8px 0 0; + text-transform: none; + white-space: nowrap; +} +.tox .tox-toolbar-label { + padding: 0 8px; +} +.tox[dir='rtl'] .tox-label { + padding: 0 0 0 8px; +} +.tox .tox-form { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-form__group { + box-sizing: border-box; + margin-bottom: 4px; +} +.tox .tox-form-group--maximize { + flex: 1; +} +.tox .tox-form__group--error { + color: #c00; +} +.tox .tox-form__group--collection { + display: flex; +} +.tox .tox-form__grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} +.tox .tox-form__grid--2col > .tox-form__group { + width: calc(50% - (8px / 2)); +} +.tox .tox-form__grid--3col > .tox-form__group { + width: calc(100% / 3 - (8px / 2)); +} +.tox .tox-form__grid--4col > .tox-form__group { + width: calc(25% - (8px / 2)); +} +.tox .tox-form__controls-h-stack { + align-items: center; + display: flex; +} +.tox .tox-form__group--inline { + align-items: center; + display: flex; +} +.tox .tox-form__group--stretched { + display: flex; + flex: 1; + flex-direction: column; +} +.tox .tox-form__group--stretched .tox-textarea { + flex: 1; +} +.tox .tox-form__group--stretched .tox-navobj { + display: flex; + flex: 1; +} +.tox .tox-form__group--stretched .tox-navobj :nth-child(2) { + flex: 1; + height: 100%; +} +.tox:not([dir='rtl']) .tox-form__controls-h-stack > :not(:first-child) { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-form__controls-h-stack > :not(:first-child) { + margin-right: 4px; +} +.tox .tox-lock.tox-locked .tox-lock-icon__unlock, +.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { + display: none; +} +.tox .tox-listboxfield .tox-listbox--select, +.tox .tox-textarea, +.tox .tox-textfield, +.tox .tox-toolbar-textfield { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #ccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #222f3e; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: 0; + padding: 5px 4.75px; + resize: none; + width: 100%; +} +.tox .tox-textarea[disabled], +.tox .tox-textfield[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} +.tox .tox-listboxfield .tox-listbox--select:focus, +.tox .tox-textarea:focus, +.tox .tox-textfield:focus { + background-color: #fff; + border-color: #207ab7; + box-shadow: none; + outline: 2px solid rgba(32, 122, 183, 0.25); +} +.tox .tox-toolbar-textfield { + border-width: 0; + margin-bottom: 3px; + margin-top: 2px; + max-width: 250px; +} +.tox .tox-naked-btn { + background-color: transparent; + border: 0; + border-color: transparent; + box-shadow: unset; + color: #207ab7; + cursor: pointer; + display: block; + margin: 0; + padding: 0; +} +.tox .tox-naked-btn svg { + display: block; + fill: #222f3e; +} +.tox:not([dir='rtl']) .tox-toolbar-textfield + * { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-toolbar-textfield + * { + margin-right: 4px; +} +.tox .tox-listboxfield { + cursor: pointer; + position: relative; +} +.tox .tox-listboxfield .tox-listbox--select[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} +.tox .tox-listbox__select-label { + cursor: default; + flex: 1; + margin: 0 4px; +} +.tox .tox-listbox__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} +.tox .tox-listbox__select-chevron svg { + fill: #222f3e; +} +.tox .tox-listboxfield .tox-listbox--select { + align-items: center; + display: flex; +} +.tox:not([dir='rtl']) .tox-listboxfield svg { + right: 8px; +} +.tox[dir='rtl'] .tox-listboxfield svg { + left: 8px; +} +.tox .tox-selectfield { + cursor: pointer; + position: relative; +} +.tox .tox-selectfield select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #ccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #222f3e; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', + sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: 0; + padding: 5px 4.75px; + resize: none; + width: 100%; +} +.tox .tox-selectfield select[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} +.tox .tox-selectfield select::-ms-expand { + display: none; +} +.tox .tox-selectfield select:focus { + background-color: #fff; + border-color: #207ab7; + box-shadow: none; + outline: 2px solid rgba(32, 122, 183, 0.25); +} +.tox .tox-selectfield svg { + pointer-events: none; + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox:not([dir='rtl']) .tox-selectfield select[size='0'], +.tox:not([dir='rtl']) .tox-selectfield select[size='1'] { + padding-right: 24px; +} +.tox:not([dir='rtl']) .tox-selectfield svg { + right: 8px; +} +.tox[dir='rtl'] .tox-selectfield select[size='0'], +.tox[dir='rtl'] .tox-selectfield select[size='1'] { + padding-left: 24px; +} +.tox[dir='rtl'] .tox-selectfield svg { + left: 8px; +} +.tox .tox-textarea { + -webkit-appearance: textarea; + -moz-appearance: textarea; + appearance: textarea; + white-space: pre-wrap; +} +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} +.tox-shadowhost.tox-fullscreen, +.tox.tox-tinymce.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} +.tox .tox-help__more-link { + list-style: none; + margin-top: 1em; +} +.tox .tox-imagepreview { + background-color: #666; + height: 380px; + overflow: hidden; + position: relative; + width: 100%; +} +.tox .tox-imagepreview.tox-imagepreview__loaded { + overflow: auto; +} +.tox .tox-imagepreview__container { + display: flex; + left: 100vw; + position: absolute; + top: 100vw; +} +.tox .tox-imagepreview__image { + background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); +} +.tox .tox-image-tools .tox-spacer { + flex: 1; +} +.tox .tox-image-tools .tox-bar { + align-items: center; + display: flex; + height: 60px; + justify-content: center; +} +.tox .tox-image-tools .tox-imagepreview, +.tox .tox-image-tools .tox-imagepreview + .tox-bar { + margin-top: 8px; +} +.tox .tox-image-tools .tox-croprect-block { + background: #000; + opacity: 0.5; + position: absolute; + zoom: 1; +} +.tox .tox-image-tools .tox-croprect-handle { + border: 2px solid #fff; + height: 20px; + left: 0; + position: absolute; + top: 0; + width: 20px; +} +.tox .tox-image-tools .tox-croprect-handle-move { + border: 0; + cursor: move; + position: absolute; +} +.tox .tox-image-tools .tox-croprect-handle-nw { + border-width: 2px 0 0 2px; + cursor: nw-resize; + left: 100px; + margin: -2px 0 0 -2px; + top: 100px; +} +.tox .tox-image-tools .tox-croprect-handle-ne { + border-width: 2px 2px 0 0; + cursor: ne-resize; + left: 200px; + margin: -2px 0 0 -20px; + top: 100px; +} +.tox .tox-image-tools .tox-croprect-handle-sw { + border-width: 0 0 2px 2px; + cursor: sw-resize; + left: 100px; + margin: -20px 2px 0 -2px; + top: 200px; +} +.tox .tox-image-tools .tox-croprect-handle-se { + border-width: 0 2px 2px 0; + cursor: se-resize; + left: 200px; + margin: -20px 0 0 -20px; + top: 200px; +} +.tox .tox-insert-table-picker { + display: flex; + flex-wrap: wrap; + width: 170px; +} +.tox .tox-insert-table-picker > div { + border-color: #ccc; + border-style: solid; + border-width: 0 1px 1px 0; + box-sizing: border-box; + height: 17px; + width: 17px; +} +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: 0 -4px; +} +.tox .tox-insert-table-picker .tox-insert-table-picker__selected { + background-color: rgba(32, 122, 183, 0.5); + border-color: rgba(32, 122, 183, 0.5); +} +.tox .tox-insert-table-picker__label { + color: rgba(34, 47, 62, 0.7); + display: block; + font-size: 14px; + padding: 4px; + text-align: center; + width: 100%; +} +.tox:not([dir='rtl']) .tox-insert-table-picker > div:nth-child(10n) { + border-right: 0; +} +.tox[dir='rtl'] .tox-insert-table-picker > div:nth-child(10n + 1) { + border-right: 0; +} +.tox .tox-menu { + background-color: #fff; + border: 1px solid #ccc; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); + display: inline-block; + overflow: hidden; + vertical-align: top; + z-index: 1150; +} +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0 0; +} +.tox .tox-menu.tox-collection.tox-collection--toolbar { + padding: 4px; +} +.tox .tox-menu.tox-collection.tox-collection--grid { + padding: 4px; +} +.tox .tox-menu__label blockquote, +.tox .tox-menu__label code, +.tox .tox-menu__label h1, +.tox .tox-menu__label h2, +.tox .tox-menu__label h3, +.tox .tox-menu__label h4, +.tox .tox-menu__label h5, +.tox .tox-menu__label h6, +.tox .tox-menu__label p { + margin: 0; +} +.tox .tox-menubar { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") + left 0 top 0 #fff; + background-color: #fff; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 4px 0 4px; +} +.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { + border-top: 1px solid #ccc; +} +.tox .tox-mbtn { + align-items: center; + background: 0 0; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #222f3e; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: 400; + height: 34px; + justify-content: center; + margin: 2px 0 3px 0; + outline: 0; + overflow: hidden; + padding: 0 4px; + text-transform: none; + width: auto; +} +.tox .tox-mbtn[disabled] { + background-color: transparent; + border: 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} +.tox .tox-mbtn:focus:not(:disabled) { + background: #dee0e2; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-mbtn--active { + background: #c8cbcf; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { + background: #dee0e2; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-mbtn__select-label { + cursor: default; + font-weight: 400; + margin: 0 4px; +} +.tox .tox-mbtn[disabled] .tox-mbtn__select-label { + cursor: not-allowed; +} +.tox .tox-mbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; + display: none; +} +.tox .tox-notification { + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + display: grid; + font-size: 14px; + font-weight: 400; + grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + margin-top: 4px; + opacity: 0; + padding: 4px; + transition: transform 0.1s ease-in, opacity 150ms ease-in; +} +.tox .tox-notification p { + font-size: 14px; + font-weight: 400; +} +.tox .tox-notification a { + cursor: pointer; + text-decoration: underline; +} +.tox .tox-notification--in { + opacity: 1; +} +.tox .tox-notification--success { + background-color: #e4eeda; + border-color: #d7e6c8; + color: #222f3e; +} +.tox .tox-notification--success p { + color: #222f3e; +} +.tox .tox-notification--success a { + color: #517342; +} +.tox .tox-notification--success svg { + fill: #222f3e; +} +.tox .tox-notification--error { + background-color: #f5cccc; + border-color: #f0b3b3; + color: #222f3e; +} +.tox .tox-notification--error p { + color: #222f3e; +} +.tox .tox-notification--error a { + color: #77181f; +} +.tox .tox-notification--error svg { + fill: #222f3e; +} +.tox .tox-notification--warn, +.tox .tox-notification--warning { + background-color: #fff5cc; + border-color: #fff0b3; + color: #222f3e; +} +.tox .tox-notification--warn p, +.tox .tox-notification--warning p { + color: #222f3e; +} +.tox .tox-notification--warn a, +.tox .tox-notification--warning a { + color: #7a6e25; +} +.tox .tox-notification--warn svg, +.tox .tox-notification--warning svg { + fill: #222f3e; +} +.tox .tox-notification--info { + background-color: #d6e7fb; + border-color: #c1dbf9; + color: #222f3e; +} +.tox .tox-notification--info p { + color: #222f3e; +} +.tox .tox-notification--info a { + color: #2a64a6; +} +.tox .tox-notification--info svg { + fill: #222f3e; +} +.tox .tox-notification__body { + align-self: center; + color: #222f3e; + font-size: 14px; + grid-column-end: 3; + grid-column-start: 2; + grid-row-end: 2; + grid-row-start: 1; + text-align: center; + white-space: normal; + word-break: break-all; + word-break: break-word; +} +.tox .tox-notification__body > * { + margin: 0; +} +.tox .tox-notification__body > * + * { + margin-top: 1rem; +} +.tox .tox-notification__icon { + align-self: center; + grid-column-end: 2; + grid-column-start: 1; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} +.tox .tox-notification__icon svg { + display: block; +} +.tox .tox-notification__dismiss { + align-self: start; + grid-column-end: 4; + grid-column-start: 3; + grid-row-end: 2; + grid-row-start: 1; + justify-self: end; +} +.tox .tox-notification .tox-progress-bar { + grid-column-end: 4; + grid-column-start: 1; + grid-row-end: 3; + grid-row-start: 2; + justify-self: center; +} +.tox .tox-pop { + display: inline-block; + position: relative; +} +.tox .tox-pop--resizing { + transition: width 0.1s ease; +} +.tox .tox-pop--resizing .tox-toolbar, +.tox .tox-pop--resizing .tox-toolbar__group { + flex-wrap: nowrap; +} +.tox .tox-pop--transition { + transition: 0.15s ease; + transition-property: left, right, top, bottom; +} +.tox .tox-pop--transition::after, +.tox .tox-pop--transition::before { + transition: all 0.15s, visibility 0s, opacity 75ms ease 75ms; +} +.tox .tox-pop__dialog { + background-color: #fff; + border: 1px solid #ccc; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + min-width: 0; + overflow: hidden; +} +.tox .tox-pop__dialog > :not(.tox-toolbar) { + margin: 4px 4px 4px 8px; +} +.tox .tox-pop__dialog .tox-toolbar { + background-color: transparent; + margin-bottom: -1px; +} +.tox .tox-pop::after, +.tox .tox-pop::before { + border-style: solid; + content: ''; + display: block; + height: 0; + opacity: 1; + position: absolute; + width: 0; +} +.tox .tox-pop.tox-pop--inset::after, +.tox .tox-pop.tox-pop--inset::before { + opacity: 0; + transition: all 0s 0.15s, visibility 0s, opacity 75ms ease; +} +.tox .tox-pop.tox-pop--bottom::after, +.tox .tox-pop.tox-pop--bottom::before { + left: 50%; + top: 100%; +} +.tox .tox-pop.tox-pop--bottom::after { + border-color: #fff transparent transparent transparent; + border-width: 8px; + margin-left: -8px; + margin-top: -1px; +} +.tox .tox-pop.tox-pop--bottom::before { + border-color: #ccc transparent transparent transparent; + border-width: 9px; + margin-left: -9px; +} +.tox .tox-pop.tox-pop--top::after, +.tox .tox-pop.tox-pop--top::before { + left: 50%; + top: 0; + transform: translateY(-100%); +} +.tox .tox-pop.tox-pop--top::after { + border-color: transparent transparent #fff transparent; + border-width: 8px; + margin-left: -8px; + margin-top: 1px; +} +.tox .tox-pop.tox-pop--top::before { + border-color: transparent transparent #ccc transparent; + border-width: 9px; + margin-left: -9px; +} +.tox .tox-pop.tox-pop--left::after, +.tox .tox-pop.tox-pop--left::before { + left: 0; + top: calc(50% - 1px); + transform: translateY(-50%); +} +.tox .tox-pop.tox-pop--left::after { + border-color: transparent #fff transparent transparent; + border-width: 8px; + margin-left: -15px; +} +.tox .tox-pop.tox-pop--left::before { + border-color: transparent #ccc transparent transparent; + border-width: 10px; + margin-left: -19px; +} +.tox .tox-pop.tox-pop--right::after, +.tox .tox-pop.tox-pop--right::before { + left: 100%; + top: calc(50% + 1px); + transform: translateY(-50%); +} +.tox .tox-pop.tox-pop--right::after { + border-color: transparent transparent transparent #fff; + border-width: 8px; + margin-left: -1px; +} +.tox .tox-pop.tox-pop--right::before { + border-color: transparent transparent transparent #ccc; + border-width: 10px; + margin-left: -1px; +} +.tox .tox-pop.tox-pop--align-left::after, +.tox .tox-pop.tox-pop--align-left::before { + left: 20px; +} +.tox .tox-pop.tox-pop--align-right::after, +.tox .tox-pop.tox-pop--align-right::before { + left: calc(100% - 20px); +} +.tox .tox-sidebar-wrap { + display: flex; + flex-direction: row; + flex-grow: 1; + min-height: 0; +} +.tox .tox-sidebar { + background-color: #fff; + display: flex; + flex-direction: row; + justify-content: flex-end; +} +.tox .tox-sidebar__slider { + display: flex; + overflow: hidden; +} +.tox .tox-sidebar__pane-container { + display: flex; +} +.tox .tox-sidebar__pane { + display: flex; +} +.tox .tox-sidebar--sliding-closed { + opacity: 0; +} +.tox .tox-sidebar--sliding-open { + opacity: 1; +} +.tox .tox-sidebar--sliding-growing, +.tox .tox-sidebar--sliding-shrinking { + transition: width 0.5s ease, opacity 0.5s ease; +} +.tox .tox-selector { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + display: inline-block; + height: 10px; + position: absolute; + width: 10px; +} +.tox.tox-platform-touch .tox-selector { + height: 12px; + width: 12px; +} +.tox .tox-slider { + align-items: center; + display: flex; + flex: 1; + height: 24px; + justify-content: center; + position: relative; +} +.tox .tox-slider__rail { + background-color: transparent; + border: 1px solid #ccc; + border-radius: 3px; + height: 10px; + min-width: 120px; + width: 100%; +} +.tox .tox-slider__handle { + background-color: #207ab7; + border: 2px solid #185d8c; + border-radius: 3px; + box-shadow: none; + height: 24px; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: 14px; +} +.tox .tox-form__controls-h-stack > .tox-slider:not(:first-of-type) { + margin-inline-start: 8px; +} +.tox .tox-form__controls-h-stack > .tox-form__group + .tox-slider { + margin-inline-start: 32px; +} +.tox .tox-form__controls-h-stack > .tox-slider + .tox-form__group { + margin-inline-start: 32px; +} +.tox .tox-source-code { + overflow: auto; +} +.tox .tox-spinner { + display: flex; +} +.tox .tox-spinner > div { + animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; + background-color: rgba(34, 47, 62, 0.7); + border-radius: 100%; + height: 8px; + width: 8px; +} +.tox .tox-spinner > div:nth-child(1) { + animation-delay: -0.32s; +} +.tox .tox-spinner > div:nth-child(2) { + animation-delay: -0.16s; +} +@keyframes tam-bouncing-dots { + 0%, + 100%, + 80% { + transform: scale(0); + } + 40% { + transform: scale(1); + } +} +.tox:not([dir='rtl']) .tox-spinner > div:not(:first-child) { + margin-left: 4px; +} +.tox[dir='rtl'] .tox-spinner > div:not(:first-child) { + margin-right: 4px; +} +.tox .tox-statusbar { + align-items: center; + background-color: #fff; + border-top: 1px solid #ccc; + color: rgba(34, 47, 62, 0.7); + display: flex; + flex: 0 0 auto; + font-size: 12px; + font-weight: 400; + height: 18px; + overflow: hidden; + padding: 0 8px; + position: relative; + text-transform: uppercase; +} +.tox .tox-statusbar__text-container { + display: flex; + flex: 1 1 auto; + justify-content: flex-end; + overflow: hidden; +} +.tox .tox-statusbar__path { + display: flex; + flex: 1 1 auto; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.tox .tox-statusbar__path > * { + display: inline; + white-space: nowrap; +} +.tox .tox-statusbar__wordcount { + flex: 0 0 auto; + margin-left: 1ch; +} +.tox .tox-statusbar a, +.tox .tox-statusbar__path-item, +.tox .tox-statusbar__wordcount { + color: rgba(34, 47, 62, 0.7); + text-decoration: none; +} +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']) { + color: #222f3e; + cursor: pointer; +} +.tox .tox-statusbar__branding svg { + fill: rgba(34, 47, 62, 0.8); + height: 1.14em; + vertical-align: -0.28em; + width: 3.6em; +} +.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled='true']) svg, +.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled='true']) svg { + fill: #222f3e; +} +.tox .tox-statusbar__resize-handle { + align-items: flex-end; + align-self: stretch; + cursor: nwse-resize; + display: flex; + flex: 0 0 auto; + justify-content: flex-end; + margin-left: auto; + margin-right: -8px; + padding-bottom: 3px; + padding-left: 1ch; + padding-right: 3px; +} +.tox .tox-statusbar__resize-handle svg { + display: block; + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-statusbar__resize-handle:focus svg { + background-color: #dee0e2; + border-radius: 1px 1px -4px 1px; + box-shadow: 0 0 0 2px #dee0e2; +} +.tox:not([dir='rtl']) .tox-statusbar__path > * { + margin-right: 4px; +} +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 2ch; +} +.tox[dir='rtl'] .tox-statusbar { + flex-direction: row-reverse; +} +.tox[dir='rtl'] .tox-statusbar__path > * { + margin-left: 4px; +} +.tox .tox-throbber { + z-index: 1299; +} +.tox .tox-throbber__busy-spinner { + align-items: center; + background-color: rgba(255, 255, 255, 0.6); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} +.tox .tox-tbtn { + align-items: center; + background: 0 0; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #222f3e; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: 400; + height: 34px; + justify-content: center; + margin: 3px 0 2px 0; + outline: 0; + overflow: hidden; + padding: 0; + text-transform: none; + width: 34px; +} +.tox .tox-tbtn svg { + display: block; + fill: #222f3e; +} +.tox .tox-tbtn.tox-tbtn-more { + padding-left: 5px; + padding-right: 5px; + width: inherit; +} +.tox .tox-tbtn:focus { + background: #dee0e2; + border: 0; + box-shadow: none; +} +.tox .tox-tbtn:hover { + background: #dee0e2; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-tbtn:hover svg { + fill: #222f3e; +} +.tox .tox-tbtn:active { + background: #c8cbcf; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-tbtn:active svg { + fill: #222f3e; +} +.tox .tox-tbtn--disabled, +.tox .tox-tbtn--disabled:hover, +.tox .tox-tbtn:disabled, +.tox .tox-tbtn:disabled:hover { + background: 0 0; + border: 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} +.tox .tox-tbtn--disabled svg, +.tox .tox-tbtn--disabled:hover svg, +.tox .tox-tbtn:disabled svg, +.tox .tox-tbtn:disabled:hover svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-tbtn--enabled, +.tox .tox-tbtn--enabled:hover { + background: #c8cbcf; + border: 0; + box-shadow: none; + color: #222f3e; +} +.tox .tox-tbtn--enabled:hover > *, +.tox .tox-tbtn--enabled > * { + transform: none; +} +.tox .tox-tbtn--enabled svg, +.tox .tox-tbtn--enabled:hover svg { + fill: #222f3e; +} +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { + color: #222f3e; +} +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { + fill: #222f3e; +} +.tox .tox-tbtn:active > * { + transform: none; +} +.tox .tox-tbtn--md { + height: 51px; + width: 51px; +} +.tox .tox-tbtn--lg { + flex-direction: column; + height: 68px; + width: 68px; +} +.tox .tox-tbtn--return { + align-self: stretch; + height: unset; + width: 16px; +} +.tox .tox-tbtn--labeled { + padding: 0 4px; + width: unset; +} +.tox .tox-tbtn__vlabel { + display: block; + font-size: 10px; + font-weight: 400; + letter-spacing: -0.025em; + margin-bottom: 4px; + white-space: nowrap; +} +.tox .tox-tbtn--select { + margin: 3px 0 2px 0; + padding: 0 4px; + width: auto; +} +.tox .tox-tbtn__select-label { + cursor: default; + font-weight: 400; + margin: 0 4px; +} +.tox .tox-tbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} +.tox .tox-tbtn__select-chevron svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-tbtn--bespoke { + background: 0 0; +} +.tox .tox-tbtn--bespoke + .tox-tbtn--bespoke { + margin-inline-start: 0; +} +.tox .tox-tbtn--bespoke .tox-tbtn__select-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 7em; +} +.tox .tox-split-button { + border: 0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + margin: 3px 0 2px 0; + overflow: hidden; +} +.tox .tox-split-button:hover { + box-shadow: 0 0 0 1px #dee0e2 inset; +} +.tox .tox-split-button:focus { + background: #dee0e2; + box-shadow: none; + color: #222f3e; +} +.tox .tox-split-button > * { + border-radius: 0; +} +.tox .tox-split-button__chevron { + width: 16px; +} +.tox .tox-split-button__chevron svg { + fill: rgba(34, 47, 62, 0.5); +} +.tox .tox-split-button .tox-tbtn { + margin: 0; +} +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, +.tox .tox-split-button.tox-tbtn--disabled:focus, +.tox .tox-split-button.tox-tbtn--disabled:hover { + background: 0 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} +.tox.tox-platform-touch .tox-split-button .tox-tbtn--select { + padding: 0 0; +} +.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child { + width: 30px; +} +.tox.tox-platform-touch .tox-split-button__chevron { + width: 20px; +} +.tox .tox-toolbar-overlord { + background-color: #fff; +} +.tox .tox-toolbar, +.tox .tox-toolbar__overflow, +.tox .tox-toolbar__primary { + background-color: #fff; + background-image: repeating-linear-gradient(#ccc 0 1px, transparent 1px 39px); + background-position: center top 39px; + background-repeat: no-repeat; + background-size: calc(100% - 4px * 2) calc(100% - 39px); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 0; + transform: perspective(1px); +} +.tox .tox-toolbar-overlord > .tox-toolbar, +.tox .tox-toolbar-overlord > .tox-toolbar__overflow, +.tox .tox-toolbar-overlord > .tox-toolbar__primary { + background-position: center top 0; + background-size: calc(100% - 4px * 2) calc(100% - 0px); +} +.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { + height: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; + visibility: hidden; +} +.tox .tox-toolbar__overflow--growing { + transition: height 0.3s ease, opacity 0.2s linear 0.1s; +} +.tox .tox-toolbar__overflow--shrinking { + transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; +} +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: 1px solid #ccc; + margin-top: 0; + padding-bottom: 0; + padding-top: 0; +} +.tox .tox-toolbar--scrolling { + flex-wrap: nowrap; + overflow-x: auto; +} +.tox .tox-pop .tox-toolbar { + border-width: 0; +} +.tox .tox-toolbar--no-divider { + background-image: none; +} +.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child, +.tox .tox-toolbar-overlord .tox-toolbar__primary { + background-position: center top 39px; +} +.tox .tox-editor-header > .tox-toolbar--scrolling, +.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child { + background-image: none; +} +.tox.tox-tinymce-aux .tox-toolbar__overflow { + background-color: #fff; + background-position: center top 43px; + background-size: calc(100% - 8px * 2) calc(100% - 51px); + border: none; + border-radius: 3px; + box-shadow: 0 0 2px 0 rgba(34, 47, 62, 0.2), 0 4px 8px 0 rgba(34, 47, 62, 0.15); + padding: 4px 0; +} +.tox-pop .tox-pop__dialog .tox-toolbar { + background-position: center top 43px; + background-size: calc(100% - 4px * 2) calc(100% - 51px); + padding: 4px 0; +} +.tox .tox-toolbar__group { + align-items: center; + display: flex; + flex-wrap: wrap; + margin: 0 0; + padding: 0 4px 0 4px; +} +.tox .tox-toolbar__group--pull-right { + margin-left: auto; +} +.tox .tox-toolbar--scrolling .tox-toolbar__group { + flex-shrink: 0; + flex-wrap: nowrap; +} +.tox:not([dir='rtl']) .tox-toolbar__group:not(:last-of-type) { + border-right: 1px solid #ccc; +} +.tox[dir='rtl'] .tox-toolbar__group:not(:last-of-type) { + border-left: 1px solid #ccc; +} +.tox .tox-tooltip { + display: inline-block; + padding: 8px; + position: relative; +} +.tox .tox-tooltip__body { + background-color: #222f3e; + border-radius: 3px; + box-shadow: 0 2px 4px rgba(34, 47, 62, 0.3); + color: rgba(255, 255, 255, 0.75); + font-size: 14px; + font-style: normal; + font-weight: 400; + padding: 4px 8px; + text-transform: none; +} +.tox .tox-tooltip__arrow { + position: absolute; +} +.tox .tox-tooltip--down .tox-tooltip__arrow { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #222f3e; + bottom: 0; + left: 50%; + position: absolute; + transform: translateX(-50%); +} +.tox .tox-tooltip--up .tox-tooltip__arrow { + border-bottom: 8px solid #222f3e; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + left: 50%; + position: absolute; + top: 0; + transform: translateX(-50%); +} +.tox .tox-tooltip--right .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-left: 8px solid #222f3e; + border-top: 8px solid transparent; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-tooltip--left .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-right: 8px solid #222f3e; + border-top: 8px solid transparent; + left: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); +} +.tox .tox-well { + border: 1px solid #ccc; + border-radius: 3px; + padding: 8px; + width: 100%; +} +.tox .tox-well > :first-child { + margin-top: 0; +} +.tox .tox-well > :last-child { + margin-bottom: 0; +} +.tox .tox-well > :only-child { + margin: 0; +} +.tox .tox-custom-editor { + border: 1px solid #ccc; + border-radius: 3px; + display: flex; + flex: 1; + position: relative; +} +.tox .tox-dialog-loading::before { + background-color: rgba(0, 0, 0, 0.5); + content: ''; + height: 100%; + position: absolute; + width: 100%; + z-index: 1000; +} +.tox .tox-tab { + cursor: pointer; +} +.tox .tox-dialog__content-js { + display: flex; + flex: 1; +} +.tox .tox-dialog__body-content .tox-collection { + display: flex; + flex: 1; +} +.tox:not(.tox-tinymce-inline) .tox-editor-header { + background-color: none; + padding: 0; +} +.tox.tox-tinymce--toolbar-bottom .tox-editor-header, +.tox.tox-tinymce-inline .tox-editor-header { + margin-bottom: -1px; +} +.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header { + border-top: none; + box-shadow: none; +} +.tox.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: transparent; + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); + padding: 0; +} +.tox.tox.tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header { + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); +} +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: -4px 0; +} +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0; +} +.tox .tox-pop { + box-shadow: none; +} +.tox .tox-split-button, +.tox .tox-tbtn, +.tox .tox-tbtn--select { + margin: 2px 0 3px 0; +} +.tox .tox-toolbar, +.tox .tox-toolbar__overflow, +.tox .tox-toolbar__primary { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") + left 0 top 0 #fff !important; +} +.tox .tox-menubar + .tox-toolbar-overlord { + border-top: none; +} +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord .tox-toolbar__primary { + border-top: 1px solid #ccc; + margin-top: -1px; +} +.tox.tox-tinymce-aux .tox-toolbar__overflow { + border: 1px solid #ccc; + padding: 0; +} +.tox:not(.tox-tinymce-inline) + .tox-editor-header:not(:first-child) + .tox-toolbar-overlord:first-child + .tox-toolbar__primary, +.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child { + border-top: 1px solid #ccc; +} +.tox .tox-toolbar__group { + padding: 0 4px 0 4px; +} +.tox .tox-collection__item { + border-radius: 0; + cursor: pointer; +} +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled='true']), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled='true']) { + color: rgba(34, 47, 62, 0.7); + text-decoration: underline; +} +.tox .tox-statusbar__branding svg { + vertical-align: -0.25em; +} +.tox:not([dir='rtl']) .tox-statusbar__branding { + margin-left: 1ch; +} +.tox .tox-statusbar__resize-handle { + padding-bottom: 0; + padding-right: 0; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.css new file mode 100644 index 00000000..d9ea82a3 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.css @@ -0,0 +1,35 @@ +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen, +.tox-shadowhost.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} \ No newline at end of file diff --git a/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css new file mode 100644 index 00000000..c1141c55 --- /dev/null +++ b/src/frontend/admin/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css @@ -0,0 +1,30 @@ +body.tox-dialog__disable-scroll { + overflow: hidden; +} +.tox-fullscreen { + border: 0; + height: 100%; + margin: 0; + overflow: hidden; + overscroll-behavior: none; + padding: 0; + touch-action: pinch-zoom; + width: 100%; +} +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} +.tox-shadowhost.tox-fullscreen, +.tox.tox-tinymce.tox-fullscreen { + left: 0; + position: fixed; + top: 0; + z-index: 1200; +} +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; +} +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} \ No newline at end of file diff --git a/src/frontend/admin/src/App.vue b/src/frontend/admin/src/App.vue new file mode 100644 index 00000000..805ab9b2 --- /dev/null +++ b/src/frontend/admin/src/App.vue @@ -0,0 +1,46 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/api/index.js b/src/frontend/admin/src/api/index.js new file mode 100644 index 00000000..1397ad01 --- /dev/null +++ b/src/frontend/admin/src/api/index.js @@ -0,0 +1,11 @@ +/** + * @description 自动import导入所有 api 模块 + */ + +const files = import.meta.globEager('./*/*.js') +const modules = {} +Object.keys(files).forEach((key) => { + modules[key.replace(/^\.\/(.*?)\/(.*)\.js$/g, '$1_$2')] = files[key].default +}) + +export default modules \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/api.js b/src/frontend/admin/src/api/sys/api.js new file mode 100644 index 00000000..0ba9a3a2 --- /dev/null +++ b/src/frontend/admin/src/api/sys/api.js @@ -0,0 +1,33 @@ +/** + * 接口服务 + * @module @/api/sys/api + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 查询接口 + */ +query :{ + url: `${config.API_URL}/api/sys/api/query`, + name: `查询接口`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 同步接口 + */ +sync :{ + url: `${config.API_URL}/api/sys/api/sync`, + name: `同步接口`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/cache.js b/src/frontend/admin/src/api/sys/cache.js new file mode 100644 index 00000000..c0af0208 --- /dev/null +++ b/src/frontend/admin/src/api/sys/cache.js @@ -0,0 +1,33 @@ +/** + * 缓存服务 + * @module @/api/sys/cache + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 缓存统计 + */ +cacheStatistics :{ + url: `${config.API_URL}/api/sys/cache/cache.statistics`, + name: `缓存统计`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 获取所有缓存项 + */ +getAllEntries :{ + url: `${config.API_URL}/api/sys/cache/get.all.entries`, + name: `获取所有缓存项`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/captcha.js b/src/frontend/admin/src/api/sys/captcha.js new file mode 100644 index 00000000..7136d98b --- /dev/null +++ b/src/frontend/admin/src/api/sys/captcha.js @@ -0,0 +1,33 @@ +/** + * 人机验证服务 + * @module @/api/sys/captcha + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 获取人机校验图 + */ +getCaptchaImage :{ + url: `${config.API_URL}/api/sys/captcha/get.captcha.image`, + name: `获取人机校验图`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 完成人机校验 + */ +verifyCaptcha :{ + url: `${config.API_URL}/api/sys/captcha/verify.captcha`, + name: `完成人机校验`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/config.js b/src/frontend/admin/src/api/sys/config.js new file mode 100644 index 00000000..cb4d0981 --- /dev/null +++ b/src/frontend/admin/src/api/sys/config.js @@ -0,0 +1,88 @@ +/** + * 配置服务 + * @module @/api/sys/config + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除配置 + */ +bulkDelete :{ + url: `${config.API_URL}/api/sys/config/bulk.delete`, + name: `批量删除配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建配置 + */ +create :{ + url: `${config.API_URL}/api/sys/config/create`, + name: `创建配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除配置 + */ +delete :{ + url: `${config.API_URL}/api/sys/config/delete`, + name: `删除配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 获取最新有效配置 + */ +getLatestConfig :{ + url: `${config.API_URL}/api/sys/config/get.latest.config`, + name: `获取最新有效配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询配置 + */ +pagedQuery :{ + url: `${config.API_URL}/api/sys/config/paged.query`, + name: `分页查询配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询配置 + */ +query :{ + url: `${config.API_URL}/api/sys/config/query`, + name: `查询配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新配置 + */ +update :{ + url: `${config.API_URL}/api/sys/config/update`, + name: `更新配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/constant.js b/src/frontend/admin/src/api/sys/constant.js new file mode 100644 index 00000000..42c8aae4 --- /dev/null +++ b/src/frontend/admin/src/api/sys/constant.js @@ -0,0 +1,55 @@ +/** + * 常量服务 + * @module @/api/sys/constant + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 获得常量字符串 + */ +getChars :{ + url: `${config.API_URL}/api/sys/constant/get.chars`, + name: `获得常量字符串`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 获得公共枚举值 + */ +getEnums :{ + url: `${config.API_URL}/api/sys/constant/get.enums`, + name: `获得公共枚举值`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 获得本地化字符串 + */ +getLocalizedStrings :{ + url: `${config.API_URL}/api/sys/constant/get.localized.strings`, + name: `获得本地化字符串`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 获得数字常量表 + */ +getNumbers :{ + url: `${config.API_URL}/api/sys/constant/get.numbers`, + name: `获得数字常量表`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/dept.js b/src/frontend/admin/src/api/sys/dept.js new file mode 100644 index 00000000..963b6e06 --- /dev/null +++ b/src/frontend/admin/src/api/sys/dept.js @@ -0,0 +1,66 @@ +/** + * 部门服务 + * @module @/api/sys/dept + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除部门 + */ +bulkDelete :{ + url: `${config.API_URL}/api/sys/dept/bulk.delete`, + name: `批量删除部门`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建部门 + */ +create :{ + url: `${config.API_URL}/api/sys/dept/create`, + name: `创建部门`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除部门 + */ +delete :{ + url: `${config.API_URL}/api/sys/dept/delete`, + name: `删除部门`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询部门 + */ +query :{ + url: `${config.API_URL}/api/sys/dept/query`, + name: `查询部门`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新部门 + */ +update :{ + url: `${config.API_URL}/api/sys/dept/update`, + name: `更新部门`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/dev.js b/src/frontend/admin/src/api/sys/dev.js new file mode 100644 index 00000000..fddc09c5 --- /dev/null +++ b/src/frontend/admin/src/api/sys/dev.js @@ -0,0 +1,44 @@ +/** + * 开发服务 + * @module @/api/sys/dev + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 生成后端代码 + */ +generateCsCode :{ + url: `${config.API_URL}/api/sys/dev/generate.cs.code`, + name: `生成后端代码`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 生成图标代码 + */ +generateIconCode :{ + url: `${config.API_URL}/api/sys/dev/generate.icon.code`, + name: `生成图标代码`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 生成接口代码 + */ +generateJsCode :{ + url: `${config.API_URL}/api/sys/dev/generate.js.code`, + name: `生成接口代码`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/dic.js b/src/frontend/admin/src/api/sys/dic.js new file mode 100644 index 00000000..9ccefda6 --- /dev/null +++ b/src/frontend/admin/src/api/sys/dic.js @@ -0,0 +1,143 @@ +/** + * 字典服务 + * @module @/api/sys/dic + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除字典目录 + */ +bulkDeleteCatalog :{ + url: `${config.API_URL}/api/sys/dic/bulk.delete.catalog`, + name: `批量删除字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 批量删除字典内容 + */ +bulkDeleteContent :{ + url: `${config.API_URL}/api/sys/dic/bulk.delete.content`, + name: `批量删除字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建字典目录 + */ +createCatalog :{ + url: `${config.API_URL}/api/sys/dic/create.catalog`, + name: `创建字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建字典内容 + */ +createContent :{ + url: `${config.API_URL}/api/sys/dic/create.content`, + name: `创建字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除字典目录 + */ +deleteCatalog :{ + url: `${config.API_URL}/api/sys/dic/delete.catalog`, + name: `删除字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除字典内容 + */ +deleteContent :{ + url: `${config.API_URL}/api/sys/dic/delete.content`, + name: `删除字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询字典目录 + */ +pagedQueryCatalog :{ + url: `${config.API_URL}/api/sys/dic/paged.query.catalog`, + name: `分页查询字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询字典内容 + */ +pagedQueryContent :{ + url: `${config.API_URL}/api/sys/dic/paged.query.content`, + name: `分页查询字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询字典目录 + */ +queryCatalog :{ + url: `${config.API_URL}/api/sys/dic/query.catalog`, + name: `查询字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询字典内容 + */ +queryContent :{ + url: `${config.API_URL}/api/sys/dic/query.content`, + name: `查询字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新字典目录 + */ +updateCatalog :{ + url: `${config.API_URL}/api/sys/dic/update.catalog`, + name: `更新字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新字典内容 + */ +updateContent :{ + url: `${config.API_URL}/api/sys/dic/update.content`, + name: `更新字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/file.js b/src/frontend/admin/src/api/sys/file.js new file mode 100644 index 00000000..5b50ba66 --- /dev/null +++ b/src/frontend/admin/src/api/sys/file.js @@ -0,0 +1,22 @@ +/** + * 文件服务 + * @module @/api/sys/file + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 文件上传 + */ +upload :{ + url: `${config.API_URL}/api/sys/file/upload`, + name: `文件上传`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/log.js b/src/frontend/admin/src/api/sys/log.js new file mode 100644 index 00000000..054de945 --- /dev/null +++ b/src/frontend/admin/src/api/sys/log.js @@ -0,0 +1,33 @@ +/** + * 请求日志服务 + * @module @/api/sys/log + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 分页查询请求日志 + */ +pagedQuery :{ + url: `${config.API_URL}/api/sys/log/paged.query`, + name: `分页查询请求日志`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询请求日志 + */ +query :{ + url: `${config.API_URL}/api/sys/log/query`, + name: `查询请求日志`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/menu.js b/src/frontend/admin/src/api/sys/menu.js new file mode 100644 index 00000000..ea55a58f --- /dev/null +++ b/src/frontend/admin/src/api/sys/menu.js @@ -0,0 +1,77 @@ +/** + * 菜单服务 + * @module @/api/sys/menu + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除菜单 + */ +bulkDelete :{ + url: `${config.API_URL}/api/sys/menu/bulk.delete`, + name: `批量删除菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建菜单 + */ +create :{ + url: `${config.API_URL}/api/sys/menu/create`, + name: `创建菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除菜单 + */ +delete :{ + url: `${config.API_URL}/api/sys/menu/delete`, + name: `删除菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询菜单 + */ +query :{ + url: `${config.API_URL}/api/sys/menu/query`, + name: `查询菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新菜单 + */ +update :{ + url: `${config.API_URL}/api/sys/menu/update`, + name: `更新菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 当前用户菜单 + */ +userMenus :{ + url: `${config.API_URL}/api/sys/menu/user.menus`, + name: `当前用户菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/position.js b/src/frontend/admin/src/api/sys/position.js new file mode 100644 index 00000000..43e5093b --- /dev/null +++ b/src/frontend/admin/src/api/sys/position.js @@ -0,0 +1,77 @@ +/** + * 岗位服务 + * @module @/api/sys/position + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除岗位 + */ +bulkDelete :{ + url: `${config.API_URL}/api/sys/position/bulk.delete`, + name: `批量删除岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建岗位 + */ +create :{ + url: `${config.API_URL}/api/sys/position/create`, + name: `创建岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除岗位 + */ +delete :{ + url: `${config.API_URL}/api/sys/position/delete`, + name: `删除岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询岗位 + */ +pagedQuery :{ + url: `${config.API_URL}/api/sys/position/paged.query`, + name: `分页查询岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询岗位 + */ +query :{ + url: `${config.API_URL}/api/sys/position/query`, + name: `查询岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新岗位 + */ +update :{ + url: `${config.API_URL}/api/sys/position/update`, + name: `更新岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/role.js b/src/frontend/admin/src/api/sys/role.js new file mode 100644 index 00000000..1772d99f --- /dev/null +++ b/src/frontend/admin/src/api/sys/role.js @@ -0,0 +1,77 @@ +/** + * 角色服务 + * @module @/api/sys/role + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除角色 + */ +bulkDelete :{ + url: `${config.API_URL}/api/sys/role/bulk.delete`, + name: `批量删除角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建角色 + */ +create :{ + url: `${config.API_URL}/api/sys/role/create`, + name: `创建角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除角色 + */ +delete :{ + url: `${config.API_URL}/api/sys/role/delete`, + name: `删除角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询角色 + */ +pagedQuery :{ + url: `${config.API_URL}/api/sys/role/paged.query`, + name: `分页查询角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询角色 + */ +query :{ + url: `${config.API_URL}/api/sys/role/query`, + name: `查询角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新角色 + */ +update :{ + url: `${config.API_URL}/api/sys/role/update`, + name: `更新角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/tools.js b/src/frontend/admin/src/api/sys/tools.js new file mode 100644 index 00000000..f42c06fa --- /dev/null +++ b/src/frontend/admin/src/api/sys/tools.js @@ -0,0 +1,33 @@ +/** + * 工具服务 + * @module @/api/sys/tools + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 服务器时间 + */ +getServerUtcTime :{ + url: `${config.API_URL}/api/sys/tools/get.server.utc.time`, + name: `服务器时间`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 版本信息 + */ +version :{ + url: `${config.API_URL}/api/sys/tools/version`, + name: `版本信息`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/user.js b/src/frontend/admin/src/api/sys/user.js new file mode 100644 index 00000000..5a4d30c6 --- /dev/null +++ b/src/frontend/admin/src/api/sys/user.js @@ -0,0 +1,198 @@ +/** + * 用户服务 + * @module @/api/sys/user + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 检查手机号是否可用 + */ +checkMobileAvailable :{ + url: `${config.API_URL}/api/sys/user/check.mobile.available`, + name: `检查手机号是否可用`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 检查用户名是否可用 + */ +checkUserNameAvailable :{ + url: `${config.API_URL}/api/sys/user/check.user.name.available`, + name: `检查用户名是否可用`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建用户 + */ +create :{ + url: `${config.API_URL}/api/sys/user/create`, + name: `创建用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除用户 + */ +delete :{ + url: `${config.API_URL}/api/sys/user/delete`, + name: `删除用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 密码登录 + */ +loginByPwd :{ + url: `${config.API_URL}/api/sys/user/login.by.pwd`, + name: `密码登录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 短信登录 + */ +loginBySms :{ + url: `${config.API_URL}/api/sys/user/login.by.sms`, + name: `短信登录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询用户 + */ +pagedQuery :{ + url: `${config.API_URL}/api/sys/user/paged.query`, + name: `分页查询用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询用户 + */ +query :{ + url: `${config.API_URL}/api/sys/user/query`, + name: `查询用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询用户档案 + */ +queryProfile :{ + url: `${config.API_URL}/api/sys/user/query.profile`, + name: `查询用户档案`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 注册用户 + */ +register :{ + url: `${config.API_URL}/api/sys/user/register`, + name: `注册用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 重设密码 + */ +resetPassword :{ + url: `${config.API_URL}/api/sys/user/reset.password`, + name: `重设密码`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新用户头像 + */ +setAvatar :{ + url: `${config.API_URL}/api/sys/user/set.avatar`, + name: `更新用户头像`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 设置邮箱 + */ +setEmail :{ + url: `${config.API_URL}/api/sys/user/set.email`, + name: `设置邮箱`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 设置手机号 + */ +setMobile :{ + url: `${config.API_URL}/api/sys/user/set.mobile`, + name: `设置手机号`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 设置密码 + */ +setPassword :{ + url: `${config.API_URL}/api/sys/user/set.password`, + name: `设置密码`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新用户 + */ +update :{ + url: `${config.API_URL}/api/sys/user/update`, + name: `更新用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 当前用户信息 + */ +userInfo :{ + url: `${config.API_URL}/api/sys/user/user.info`, + name: `当前用户信息`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/sys/verifycode.js b/src/frontend/admin/src/api/sys/verifycode.js new file mode 100644 index 00000000..f0ea1264 --- /dev/null +++ b/src/frontend/admin/src/api/sys/verifycode.js @@ -0,0 +1,33 @@ +/** + * 验证码服务 + * @module @/api/sys/verify.code + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 发送验证码 + */ +sendVerifyCode :{ + url: `${config.API_URL}/api/sys/verify.code/send.verify.code`, + name: `发送验证码`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 完成验证 + */ +verify :{ + url: `${config.API_URL}/api/sys/verify.code/verify`, + name: `完成验证`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/tpl/example.js b/src/frontend/admin/src/api/tpl/example.js new file mode 100644 index 00000000..4b672530 --- /dev/null +++ b/src/frontend/admin/src/api/tpl/example.js @@ -0,0 +1,77 @@ +/** + * 示例服务 + * @module @/api/tpl/example + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除示例 + */ +bulkDelete :{ + url: `${config.API_URL}/api/tpl/example/bulk.delete`, + name: `批量删除示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建示例 + */ +create :{ + url: `${config.API_URL}/api/tpl/example/create`, + name: `创建示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除示例 + */ +delete :{ + url: `${config.API_URL}/api/tpl/example/delete`, + name: `删除示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询示例 + */ +pagedQuery :{ + url: `${config.API_URL}/api/tpl/example/paged.query`, + name: `分页查询示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询示例 + */ +query :{ + url: `${config.API_URL}/api/tpl/example/query`, + name: `查询示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新示例 + */ +update :{ + url: `${config.API_URL}/api/tpl/example/update`, + name: `更新示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/admin/src/api/tpl/inner.js b/src/frontend/admin/src/api/tpl/inner.js new file mode 100644 index 00000000..d4dfd800 --- /dev/null +++ b/src/frontend/admin/src/api/tpl/inner.js @@ -0,0 +1,10 @@ +//~/** +//~ * $actionDesc$ +//~ */ +//~$actionName$ :{ +//~ url: `${config.API_URL}/$actionPath$`, +//~ name: `$actionDesc$`, +//~ $actionMethod$:async function(data={}, config={}) { +//~ return await http.$actionMethod$(this.url,data, config) +//~ } +//~}, \ No newline at end of file diff --git a/src/frontend/admin/src/api/tpl/outer.js b/src/frontend/admin/src/api/tpl/outer.js new file mode 100644 index 00000000..15b6479b --- /dev/null +++ b/src/frontend/admin/src/api/tpl/outer.js @@ -0,0 +1,13 @@ +/** + * $controllerDesc$ + * @module @/$controllerPath$ + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + //~$inner$ + +} \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Api.vue b/src/frontend/admin/src/assets/icons/Api.vue new file mode 100644 index 00000000..bf12ac5a --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Api.vue @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/App.vue b/src/frontend/admin/src/assets/icons/App.vue new file mode 100644 index 00000000..969371f1 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/App.vue @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/App2.vue b/src/frontend/admin/src/assets/icons/App2.vue new file mode 100644 index 00000000..84c82568 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/App2.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/BugFill.vue b/src/frontend/admin/src/assets/icons/BugFill.vue new file mode 100644 index 00000000..82131e69 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/BugFill.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/BugLine.vue b/src/frontend/admin/src/assets/icons/BugLine.vue new file mode 100644 index 00000000..06a8f25c --- /dev/null +++ b/src/frontend/admin/src/assets/icons/BugLine.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Business.vue b/src/frontend/admin/src/assets/icons/Business.vue new file mode 100644 index 00000000..462eaf0c --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Business.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Code.vue b/src/frontend/admin/src/assets/icons/Code.vue new file mode 100644 index 00000000..766183de --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Code.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Code2.vue b/src/frontend/admin/src/assets/icons/Code2.vue new file mode 100644 index 00000000..9e49fcc7 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Code2.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Csharp.vue b/src/frontend/admin/src/assets/icons/Csharp.vue new file mode 100644 index 00000000..f68bbb99 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Csharp.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Dashboard.vue b/src/frontend/admin/src/assets/icons/Dashboard.vue new file mode 100644 index 00000000..fa38220b --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Dashboard.vue @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Demo.vue b/src/frontend/admin/src/assets/icons/Demo.vue new file mode 100644 index 00000000..43036476 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Demo.vue @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Dept.vue b/src/frontend/admin/src/assets/icons/Dept.vue new file mode 100644 index 00000000..41f810aa --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Dept.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Device.vue b/src/frontend/admin/src/assets/icons/Device.vue new file mode 100644 index 00000000..fa32daf0 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Device.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Dic.vue b/src/frontend/admin/src/assets/icons/Dic.vue new file mode 100644 index 00000000..ebaabec9 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Dic.vue @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Docker.vue b/src/frontend/admin/src/assets/icons/Docker.vue new file mode 100644 index 00000000..7a7628fd --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Docker.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Download.vue b/src/frontend/admin/src/assets/icons/Download.vue new file mode 100644 index 00000000..4ebd9cba --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Download.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Drone.vue b/src/frontend/admin/src/assets/icons/Drone.vue new file mode 100644 index 00000000..4b16be7b --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Drone.vue @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Elastic.vue b/src/frontend/admin/src/assets/icons/Elastic.vue new file mode 100644 index 00000000..2a604114 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Elastic.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/FileExcel.vue b/src/frontend/admin/src/assets/icons/FileExcel.vue new file mode 100644 index 00000000..bc94f8ec --- /dev/null +++ b/src/frontend/admin/src/assets/icons/FileExcel.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/FilePpt.vue b/src/frontend/admin/src/assets/icons/FilePpt.vue new file mode 100644 index 00000000..dc86cb42 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/FilePpt.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/FileWord.vue b/src/frontend/admin/src/assets/icons/FileWord.vue new file mode 100644 index 00000000..938125d3 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/FileWord.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Gitea.vue b/src/frontend/admin/src/assets/icons/Gitea.vue new file mode 100644 index 00000000..988fb8a4 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Gitea.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Grafana.vue b/src/frontend/admin/src/assets/icons/Grafana.vue new file mode 100644 index 00000000..48a0a3c8 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Grafana.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Js.vue b/src/frontend/admin/src/assets/icons/Js.vue new file mode 100644 index 00000000..37044e49 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Js.vue @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Kafka.vue b/src/frontend/admin/src/assets/icons/Kafka.vue new file mode 100644 index 00000000..d114aa9b --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Kafka.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Kibana.vue b/src/frontend/admin/src/assets/icons/Kibana.vue new file mode 100644 index 00000000..d5c06819 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Kibana.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Link.vue b/src/frontend/admin/src/assets/icons/Link.vue new file mode 100644 index 00000000..9a7e5eca --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Link.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Memory.vue b/src/frontend/admin/src/assets/icons/Memory.vue new file mode 100644 index 00000000..005e4cbb --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Memory.vue @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Meter.vue b/src/frontend/admin/src/assets/icons/Meter.vue new file mode 100644 index 00000000..89eb0a24 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Meter.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Organization.vue b/src/frontend/admin/src/assets/icons/Organization.vue new file mode 100644 index 00000000..6010b5c2 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Organization.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Position.vue b/src/frontend/admin/src/assets/icons/Position.vue new file mode 100644 index 00000000..3ee928a3 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Position.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Product.vue b/src/frontend/admin/src/assets/icons/Product.vue new file mode 100644 index 00000000..bc776705 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Product.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/ProductCategory.vue b/src/frontend/admin/src/assets/icons/ProductCategory.vue new file mode 100644 index 00000000..bbc45dbb --- /dev/null +++ b/src/frontend/admin/src/assets/icons/ProductCategory.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Resource.vue b/src/frontend/admin/src/assets/icons/Resource.vue new file mode 100644 index 00000000..51abc643 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Resource.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Robot.vue b/src/frontend/admin/src/assets/icons/Robot.vue new file mode 100644 index 00000000..581c85ba --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Robot.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Role.vue b/src/frontend/admin/src/assets/icons/Role.vue new file mode 100644 index 00000000..214bcadd --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Role.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Send.vue b/src/frontend/admin/src/assets/icons/Send.vue new file mode 100644 index 00000000..2b084c0b --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Send.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/SmsCode.vue b/src/frontend/admin/src/assets/icons/SmsCode.vue new file mode 100644 index 00000000..4f0aa13e --- /dev/null +++ b/src/frontend/admin/src/assets/icons/SmsCode.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Sync.vue b/src/frontend/admin/src/assets/icons/Sync.vue new file mode 100644 index 00000000..c672d426 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Sync.vue @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Task.vue b/src/frontend/admin/src/assets/icons/Task.vue new file mode 100644 index 00000000..48598cce --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Task.vue @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Tpl.vue b/src/frontend/admin/src/assets/icons/Tpl.vue new file mode 100644 index 00000000..8ef06b19 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Tpl.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Unlink.vue b/src/frontend/admin/src/assets/icons/Unlink.vue new file mode 100644 index 00000000..85880af9 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Unlink.vue @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Upload.vue b/src/frontend/admin/src/assets/icons/Upload.vue new file mode 100644 index 00000000..12a73ed8 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Upload.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Vue.vue b/src/frontend/admin/src/assets/icons/Vue.vue new file mode 100644 index 00000000..134feed2 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Vue.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/Wechat.vue b/src/frontend/admin/src/assets/icons/Wechat.vue new file mode 100644 index 00000000..8393938b --- /dev/null +++ b/src/frontend/admin/src/assets/icons/Wechat.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/index.js b/src/frontend/admin/src/assets/icons/index.js new file mode 100644 index 00000000..c1d46af6 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/index.js @@ -0,0 +1,45 @@ +export {default as Vue} from './Vue.vue' +export {default as Code} from './Code.vue' +export {default as Wechat} from './Wechat.vue' +export {default as BugFill} from './BugFill.vue' +export {default as BugLine} from './BugLine.vue' +export {default as FileWord} from './FileWord.vue' +export {default as FileExcel} from './FileExcel.vue' +export {default as FilePpt} from './FilePpt.vue' +export {default as Organization} from './Organization.vue' +export {default as Upload} from './Upload.vue' +export {default as Download} from './Download.vue' +export {default as Role} from './Role.vue' +export {default as Dept} from './Dept.vue' +export {default as Js} from './Js.vue' +export {default as Memory} from './Memory.vue' +export {default as Dashboard} from './Dashboard.vue' +export {default as Api} from './Api.vue' +export {default as Code2} from './Code2.vue' +export {default as Csharp} from './Csharp.vue' +export {default as Dic} from './Dic.vue' +export {default as Position} from './Position.vue' +export {default as Tpl} from './Tpl.vue' +export {default as Demo} from './Demo.vue' +export {default as Link} from './Link.vue' +export {default as Unlink} from './Unlink.vue' +export {default as Send} from './Send.vue' +export {default as SmsCode} from './SmsCode.vue' +export {default as Meter} from './Meter.vue' +export {default as Grafana} from './Grafana.vue' +export {default as Elastic} from './Elastic.vue' +export {default as Kibana} from './Kibana.vue' +export {default as Kafka} from './Kafka.vue' +export {default as Resource} from './Resource.vue' +export {default as Robot} from './Robot.vue' +export {default as Device} from './Device.vue' +export {default as Business} from './Business.vue' +export {default as App} from './App.vue' +export {default as App2} from './App2.vue' +export {default as Sync} from './Sync.vue' +export {default as Drone} from './Drone.vue' +export {default as Gitea} from './Gitea.vue' +export {default as Docker} from './Docker.vue' +export {default as Task} from './Task.vue' +export {default as ProductCategory} from './ProductCategory.vue' +export {default as Product} from './Product.vue' \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/tpl/Svg.vue b/src/frontend/admin/src/assets/icons/tpl/Svg.vue new file mode 100644 index 00000000..ccf33639 --- /dev/null +++ b/src/frontend/admin/src/assets/icons/tpl/Svg.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/icons/tpl/export.js b/src/frontend/admin/src/assets/icons/tpl/export.js new file mode 100644 index 00000000..85fb64cd --- /dev/null +++ b/src/frontend/admin/src/assets/icons/tpl/export.js @@ -0,0 +1 @@ +//~export {default as $iconName$} from './$iconName$.vue' \ No newline at end of file diff --git a/src/frontend/admin/src/assets/img/404.png b/src/frontend/admin/src/assets/img/404.png new file mode 100644 index 00000000..47197ec7 Binary files /dev/null and b/src/frontend/admin/src/assets/img/404.png differ diff --git a/src/frontend/admin/src/assets/img/auth_banner.jpg b/src/frontend/admin/src/assets/img/auth_banner.jpg new file mode 100644 index 00000000..449b0ad5 Binary files /dev/null and b/src/frontend/admin/src/assets/img/auth_banner.jpg differ diff --git a/src/frontend/admin/src/assets/img/avatar.jpg b/src/frontend/admin/src/assets/img/avatar.jpg new file mode 100644 index 00000000..b8a3cf3c Binary files /dev/null and b/src/frontend/admin/src/assets/img/avatar.jpg differ diff --git a/src/frontend/admin/src/assets/img/avatar2.gif b/src/frontend/admin/src/assets/img/avatar2.gif new file mode 100644 index 00000000..6fade970 Binary files /dev/null and b/src/frontend/admin/src/assets/img/avatar2.gif differ diff --git a/src/frontend/admin/src/assets/img/avatar3.gif b/src/frontend/admin/src/assets/img/avatar3.gif new file mode 100644 index 00000000..495fe433 Binary files /dev/null and b/src/frontend/admin/src/assets/img/avatar3.gif differ diff --git a/src/frontend/admin/src/assets/img/loginbg.svg b/src/frontend/admin/src/assets/img/loginbg.svg new file mode 100644 index 00000000..39f62148 --- /dev/null +++ b/src/frontend/admin/src/assets/img/loginbg.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/img/logo-r.png b/src/frontend/admin/src/assets/img/logo-r.png new file mode 100644 index 00000000..9f8fba91 Binary files /dev/null and b/src/frontend/admin/src/assets/img/logo-r.png differ diff --git a/src/frontend/admin/src/assets/img/logo.png b/src/frontend/admin/src/assets/img/logo.png new file mode 100644 index 00000000..7a2fb283 Binary files /dev/null and b/src/frontend/admin/src/assets/img/logo.png differ diff --git a/src/frontend/admin/src/assets/img/no-widgets.svg b/src/frontend/admin/src/assets/img/no-widgets.svg new file mode 100644 index 00000000..52b529e1 --- /dev/null +++ b/src/frontend/admin/src/assets/img/no-widgets.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/assets/img/tasks-example.png b/src/frontend/admin/src/assets/img/tasks-example.png new file mode 100644 index 00000000..0f135913 Binary files /dev/null and b/src/frontend/admin/src/assets/img/tasks-example.png differ diff --git a/src/frontend/admin/src/assets/img/ver.svg b/src/frontend/admin/src/assets/img/ver.svg new file mode 100644 index 00000000..7122258a --- /dev/null +++ b/src/frontend/admin/src/assets/img/ver.svg @@ -0,0 +1,238 @@ + + + + + 升级中 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naArea/index.vue b/src/frontend/admin/src/components/naArea/index.vue new file mode 100644 index 00000000..6387fbd7 --- /dev/null +++ b/src/frontend/admin/src/components/naArea/index.vue @@ -0,0 +1,75 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naButtonAdd/index.vue b/src/frontend/admin/src/components/naButtonAdd/index.vue new file mode 100644 index 00000000..b943e8d3 --- /dev/null +++ b/src/frontend/admin/src/components/naButtonAdd/index.vue @@ -0,0 +1,25 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naButtonBatchDel/index.vue b/src/frontend/admin/src/components/naButtonBatchDel/index.vue new file mode 100644 index 00000000..790dcb5e --- /dev/null +++ b/src/frontend/admin/src/components/naButtonBatchDel/index.vue @@ -0,0 +1,38 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naColAvatar/index.vue b/src/frontend/admin/src/components/naColAvatar/index.vue new file mode 100644 index 00000000..4c9d91fc --- /dev/null +++ b/src/frontend/admin/src/components/naColAvatar/index.vue @@ -0,0 +1,38 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naColIndicator/index.vue b/src/frontend/admin/src/components/naColIndicator/index.vue new file mode 100644 index 00000000..7f8733f3 --- /dev/null +++ b/src/frontend/admin/src/components/naColIndicator/index.vue @@ -0,0 +1,39 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naColOperation/index.vue b/src/frontend/admin/src/components/naColOperation/index.vue new file mode 100644 index 00000000..30960048 --- /dev/null +++ b/src/frontend/admin/src/components/naColOperation/index.vue @@ -0,0 +1,47 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naColTags/index.vue b/src/frontend/admin/src/components/naColTags/index.vue new file mode 100644 index 00000000..eaca1e53 --- /dev/null +++ b/src/frontend/admin/src/components/naColTags/index.vue @@ -0,0 +1,30 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naDept/index.vue b/src/frontend/admin/src/components/naDept/index.vue new file mode 100644 index 00000000..c6481a0c --- /dev/null +++ b/src/frontend/admin/src/components/naDept/index.vue @@ -0,0 +1,44 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naDicCatalog/index.vue b/src/frontend/admin/src/components/naDicCatalog/index.vue new file mode 100644 index 00000000..9b63722a --- /dev/null +++ b/src/frontend/admin/src/components/naDicCatalog/index.vue @@ -0,0 +1,50 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naFormEmail/index.vue b/src/frontend/admin/src/components/naFormEmail/index.vue new file mode 100644 index 00000000..95a5f1d7 --- /dev/null +++ b/src/frontend/admin/src/components/naFormEmail/index.vue @@ -0,0 +1,117 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naFormPhone/index.vue b/src/frontend/admin/src/components/naFormPhone/index.vue new file mode 100644 index 00000000..e3f9716e --- /dev/null +++ b/src/frontend/admin/src/components/naFormPhone/index.vue @@ -0,0 +1,118 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naInfo/index.vue b/src/frontend/admin/src/components/naInfo/index.vue new file mode 100644 index 00000000..fba958f4 --- /dev/null +++ b/src/frontend/admin/src/components/naInfo/index.vue @@ -0,0 +1,36 @@ + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naSearch/index.vue b/src/frontend/admin/src/components/naSearch/index.vue new file mode 100644 index 00000000..a52a7480 --- /dev/null +++ b/src/frontend/admin/src/components/naSearch/index.vue @@ -0,0 +1,189 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naVerifition/index.vue b/src/frontend/admin/src/components/naVerifition/index.vue new file mode 100644 index 00000000..ab7bc9b8 --- /dev/null +++ b/src/frontend/admin/src/components/naVerifition/index.vue @@ -0,0 +1,452 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/naVerifition/slide.vue b/src/frontend/admin/src/components/naVerifition/slide.vue new file mode 100644 index 00000000..b64b3ea1 --- /dev/null +++ b/src/frontend/admin/src/components/naVerifition/slide.vue @@ -0,0 +1,422 @@ + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scCodeEditor/index.vue b/src/frontend/admin/src/components/scCodeEditor/index.vue new file mode 100644 index 00000000..40efce2f --- /dev/null +++ b/src/frontend/admin/src/components/scCodeEditor/index.vue @@ -0,0 +1,122 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scContextmenu/index.vue b/src/frontend/admin/src/components/scContextmenu/index.vue new file mode 100644 index 00000000..65558c99 --- /dev/null +++ b/src/frontend/admin/src/components/scContextmenu/index.vue @@ -0,0 +1,157 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scContextmenu/item.vue b/src/frontend/admin/src/components/scContextmenu/item.vue new file mode 100644 index 00000000..6d527b1a --- /dev/null +++ b/src/frontend/admin/src/components/scContextmenu/item.vue @@ -0,0 +1,85 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scCron/index.vue b/src/frontend/admin/src/components/scCron/index.vue new file mode 100644 index 00000000..1db9135c --- /dev/null +++ b/src/frontend/admin/src/components/scCron/index.vue @@ -0,0 +1,835 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scCropper/index.vue b/src/frontend/admin/src/components/scCropper/index.vue new file mode 100644 index 00000000..b7727a89 --- /dev/null +++ b/src/frontend/admin/src/components/scCropper/index.vue @@ -0,0 +1,120 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scDialog/index.vue b/src/frontend/admin/src/components/scDialog/index.vue new file mode 100644 index 00000000..3dccb6a5 --- /dev/null +++ b/src/frontend/admin/src/components/scDialog/index.vue @@ -0,0 +1,120 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scEcharts/echarts-theme-T.js b/src/frontend/admin/src/components/scEcharts/echarts-theme-T.js new file mode 100644 index 00000000..a0ebbf98 --- /dev/null +++ b/src/frontend/admin/src/components/scEcharts/echarts-theme-T.js @@ -0,0 +1,62 @@ +const T = { + color: ['#409EFF', '#36CE9E', '#f56e6a', '#626c91', '#edb00d', '#909399'], + grid: { + left: '3%', + right: '3%', + bottom: '10', + top: '40', + containLabel: true, + }, + legend: { + textStyle: { + color: '#999', + }, + inactiveColor: 'rgba(128,128,128,0.4)', + }, + categoryAxis: { + axisLine: { + show: true, + lineStyle: { + color: 'rgba(128,128,128,0.2)', + width: 1, + }, + }, + axisTick: { + show: false, + lineStyle: { + color: '#333', + }, + }, + axisLabel: { + color: '#999', + }, + splitLine: { + show: false, + lineStyle: { + color: ['#eee'], + }, + }, + splitArea: { + show: false, + areaStyle: { + color: ['rgba(255,255,255,0.01)', 'rgba(0,0,0,0.01)'], + }, + }, + }, + valueAxis: { + axisLine: { + show: false, + lineStyle: { + color: '#999', + }, + }, + splitLine: { + show: true, + lineStyle: { + color: 'rgba(128,128,128,0.2)', + }, + }, + }, +} + +export default T \ No newline at end of file diff --git a/src/frontend/admin/src/components/scEcharts/index.vue b/src/frontend/admin/src/components/scEcharts/index.vue new file mode 100644 index 00000000..8909938f --- /dev/null +++ b/src/frontend/admin/src/components/scEcharts/index.vue @@ -0,0 +1,68 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scEditor/index.vue b/src/frontend/admin/src/components/scEditor/index.vue new file mode 100644 index 00000000..88fd8de4 --- /dev/null +++ b/src/frontend/admin/src/components/scEditor/index.vue @@ -0,0 +1,150 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scFileExport/column.vue b/src/frontend/admin/src/components/scFileExport/column.vue new file mode 100644 index 00000000..1b47b9a6 --- /dev/null +++ b/src/frontend/admin/src/components/scFileExport/column.vue @@ -0,0 +1,58 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scFileExport/index.vue b/src/frontend/admin/src/components/scFileExport/index.vue new file mode 100644 index 00000000..4818e2c9 --- /dev/null +++ b/src/frontend/admin/src/components/scFileExport/index.vue @@ -0,0 +1,219 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scFileImport/index.vue b/src/frontend/admin/src/components/scFileImport/index.vue new file mode 100644 index 00000000..bf5514e6 --- /dev/null +++ b/src/frontend/admin/src/components/scFileImport/index.vue @@ -0,0 +1,138 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scFileSelect/index.vue b/src/frontend/admin/src/components/scFileSelect/index.vue new file mode 100644 index 00000000..df577433 --- /dev/null +++ b/src/frontend/admin/src/components/scFileSelect/index.vue @@ -0,0 +1,507 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scFilterBar/index.vue b/src/frontend/admin/src/components/scFilterBar/index.vue new file mode 100644 index 00000000..fccbb773 --- /dev/null +++ b/src/frontend/admin/src/components/scFilterBar/index.vue @@ -0,0 +1,481 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scFilterBar/my.vue b/src/frontend/admin/src/components/scFilterBar/my.vue new file mode 100644 index 00000000..30008b6d --- /dev/null +++ b/src/frontend/admin/src/components/scFilterBar/my.vue @@ -0,0 +1,176 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scFilterBar/pySelect.vue b/src/frontend/admin/src/components/scFilterBar/pySelect.vue new file mode 100644 index 00000000..5faf6b79 --- /dev/null +++ b/src/frontend/admin/src/components/scFilterBar/pySelect.vue @@ -0,0 +1,62 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scForm/index.vue b/src/frontend/admin/src/components/scForm/index.vue new file mode 100644 index 00000000..6097c5b1 --- /dev/null +++ b/src/frontend/admin/src/components/scForm/index.vue @@ -0,0 +1,319 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scForm/items/tableselect.vue b/src/frontend/admin/src/components/scForm/items/tableselect.vue new file mode 100644 index 00000000..9533daf4 --- /dev/null +++ b/src/frontend/admin/src/components/scForm/items/tableselect.vue @@ -0,0 +1,48 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scFormTable/index.vue b/src/frontend/admin/src/components/scFormTable/index.vue new file mode 100644 index 00000000..838a401e --- /dev/null +++ b/src/frontend/admin/src/components/scFormTable/index.vue @@ -0,0 +1,156 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scIconSelect/index.vue b/src/frontend/admin/src/components/scIconSelect/index.vue new file mode 100644 index 00000000..7242f59f --- /dev/null +++ b/src/frontend/admin/src/components/scIconSelect/index.vue @@ -0,0 +1,196 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scMini/scStatusIndicator.vue b/src/frontend/admin/src/components/scMini/scStatusIndicator.vue new file mode 100644 index 00000000..dba54fb2 --- /dev/null +++ b/src/frontend/admin/src/components/scMini/scStatusIndicator.vue @@ -0,0 +1,82 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scMini/scTrend.vue b/src/frontend/admin/src/components/scMini/scTrend.vue new file mode 100644 index 00000000..56ed87a0 --- /dev/null +++ b/src/frontend/admin/src/components/scMini/scTrend.vue @@ -0,0 +1,90 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scPageHeader/index.vue b/src/frontend/admin/src/components/scPageHeader/index.vue new file mode 100644 index 00000000..f20dde8d --- /dev/null +++ b/src/frontend/admin/src/components/scPageHeader/index.vue @@ -0,0 +1,94 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scPasswordStrength/index.vue b/src/frontend/admin/src/components/scPasswordStrength/index.vue new file mode 100644 index 00000000..f5e98da7 --- /dev/null +++ b/src/frontend/admin/src/components/scPasswordStrength/index.vue @@ -0,0 +1,149 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scQrCode/index.vue b/src/frontend/admin/src/components/scQrCode/index.vue new file mode 100644 index 00000000..bed48d40 --- /dev/null +++ b/src/frontend/admin/src/components/scQrCode/index.vue @@ -0,0 +1,87 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scQrCode/qrcode.js b/src/frontend/admin/src/components/scQrCode/qrcode.js new file mode 100644 index 00000000..bd7ae78a --- /dev/null +++ b/src/frontend/admin/src/components/scQrCode/qrcode.js @@ -0,0 +1,1426 @@ +/** + * @fileoverview + * - Using the 'QRCode for Javascript library' + * - Fixed dataset of 'QRCode for Javascript library' for support full-spec. + * - this library has no dependencies. + * - source page: https://github.com/makevoid/qrcodejs + * + * + * @author davidshimjs + * @see http://www.d-project.com/ + * @see http://jeromeetienne.github.com/jquery-qrcode/ + */ +var QRCode +;(function () { + //--------------------------------------------------------------------- + // QRCode for JavaScript + // + // Copyright (c) 2009 Kazuhiko Arase + // + // URL: http://www.d-project.com/ + // + // Licensed under the MIT license: + // http://www.opensource.org/licenses/mit-license.php + // + // The word "QR Code" is registered trademark of + // DENSO WAVE INCORPORATED + // http://www.denso-wave.com/qrcode/faqpatent-e.html + // + //--------------------------------------------------------------------- + function QR8bitByte(data) { + this.mode = QRMode.MODE_8BIT_BYTE + this.data = data + this.parsedData = [] + + // Added to support UTF-8 Characters + for (var i = 0, l = this.data.length; i < l; i++) { + var byteArray = [] + var code = this.data.charCodeAt(i) + + if (code > 0x10000) { + byteArray[0] = 0xf0 | ((code & 0x1c0000) >>> 18) + byteArray[1] = 0x80 | ((code & 0x3f000) >>> 12) + byteArray[2] = 0x80 | ((code & 0xfc0) >>> 6) + byteArray[3] = 0x80 | (code & 0x3f) + } else if (code > 0x800) { + byteArray[0] = 0xe0 | ((code & 0xf000) >>> 12) + byteArray[1] = 0x80 | ((code & 0xfc0) >>> 6) + byteArray[2] = 0x80 | (code & 0x3f) + } else if (code > 0x80) { + byteArray[0] = 0xc0 | ((code & 0x7c0) >>> 6) + byteArray[1] = 0x80 | (code & 0x3f) + } else { + byteArray[0] = code + } + + this.parsedData.push(byteArray) + } + + this.parsedData = Array.prototype.concat.apply([], this.parsedData) + + if (this.parsedData.length != this.data.length) { + this.parsedData.unshift(191) + this.parsedData.unshift(187) + this.parsedData.unshift(239) + } + } + + QR8bitByte.prototype = { + getLength: function (buffer) { + return this.parsedData.length + }, + write: function (buffer) { + for (var i = 0, l = this.parsedData.length; i < l; i++) { + buffer.put(this.parsedData[i], 8) + } + }, + } + + function QRCodeModel(typeNumber, errorCorrectLevel) { + this.typeNumber = typeNumber + this.errorCorrectLevel = errorCorrectLevel + this.modules = null + this.moduleCount = 0 + this.dataCache = null + this.dataList = [] + } + + QRCodeModel.prototype = { + addData: function (data) { + var newData = new QR8bitByte(data) + this.dataList.push(newData) + this.dataCache = null + }, + isDark: function (row, col) { + if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) { + throw new Error(row + ',' + col) + } + return this.modules[row][col] + }, + getModuleCount: function () { + return this.moduleCount + }, + make: function () { + this.makeImpl(false, this.getBestMaskPattern()) + }, + makeImpl: function (test, maskPattern) { + this.moduleCount = this.typeNumber * 4 + 17 + this.modules = new Array(this.moduleCount) + for (var row = 0; row < this.moduleCount; row++) { + this.modules[row] = new Array(this.moduleCount) + for (var col = 0; col < this.moduleCount; col++) { + this.modules[row][col] = null + } + } + this.setupPositionProbePattern(0, 0) + this.setupPositionProbePattern(this.moduleCount - 7, 0) + this.setupPositionProbePattern(0, this.moduleCount - 7) + this.setupPositionAdjustPattern() + this.setupTimingPattern() + this.setupTypeInfo(test, maskPattern) + if (this.typeNumber >= 7) { + this.setupTypeNumber(test) + } + if (this.dataCache == null) { + this.dataCache = QRCodeModel.createData(this.typeNumber, this.errorCorrectLevel, this.dataList) + } + this.mapData(this.dataCache, maskPattern) + }, + setupPositionProbePattern: function (row, col) { + for (var r = -1; r <= 7; r++) { + if (row + r <= -1 || this.moduleCount <= row + r) continue + for (var c = -1; c <= 7; c++) { + if (col + c <= -1 || this.moduleCount <= col + c) continue + if ( + (0 <= r && r <= 6 && (c == 0 || c == 6)) || + (0 <= c && c <= 6 && (r == 0 || r == 6)) || + (2 <= r && r <= 4 && 2 <= c && c <= 4) + ) { + this.modules[row + r][col + c] = true + } else { + this.modules[row + r][col + c] = false + } + } + } + }, + getBestMaskPattern: function () { + var minLostPoint = 0 + var pattern = 0 + for (var i = 0; i < 8; i++) { + this.makeImpl(true, i) + var lostPoint = QRUtil.getLostPoint(this) + if (i == 0 || minLostPoint > lostPoint) { + minLostPoint = lostPoint + pattern = i + } + } + return pattern + }, + createMovieClip: function (target_mc, instance_name, depth) { + var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth) + var cs = 1 + this.make() + for (var row = 0; row < this.modules.length; row++) { + var y = row * cs + for (var col = 0; col < this.modules[row].length; col++) { + var x = col * cs + var dark = this.modules[row][col] + if (dark) { + qr_mc.beginFill(0, 100) + qr_mc.moveTo(x, y) + qr_mc.lineTo(x + cs, y) + qr_mc.lineTo(x + cs, y + cs) + qr_mc.lineTo(x, y + cs) + qr_mc.endFill() + } + } + } + return qr_mc + }, + setupTimingPattern: function () { + for (var r = 8; r < this.moduleCount - 8; r++) { + if (this.modules[r][6] != null) { + continue + } + this.modules[r][6] = r % 2 == 0 + } + for (var c = 8; c < this.moduleCount - 8; c++) { + if (this.modules[6][c] != null) { + continue + } + this.modules[6][c] = c % 2 == 0 + } + }, + setupPositionAdjustPattern: function () { + var pos = QRUtil.getPatternPosition(this.typeNumber) + for (var i = 0; i < pos.length; i++) { + for (var j = 0; j < pos.length; j++) { + var row = pos[i] + var col = pos[j] + if (this.modules[row][col] != null) { + continue + } + for (var r = -2; r <= 2; r++) { + for (var c = -2; c <= 2; c++) { + if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) { + this.modules[row + r][col + c] = true + } else { + this.modules[row + r][col + c] = false + } + } + } + } + } + }, + setupTypeNumber: function (test) { + var bits = QRUtil.getBCHTypeNumber(this.typeNumber) + for (var i = 0; i < 18; i++) { + var mod = !test && ((bits >> i) & 1) == 1 + this.modules[Math.floor(i / 3)][(i % 3) + this.moduleCount - 8 - 3] = mod + } + for (var i = 0; i < 18; i++) { + var mod = !test && ((bits >> i) & 1) == 1 + this.modules[(i % 3) + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod + } + }, + setupTypeInfo: function (test, maskPattern) { + var data = (this.errorCorrectLevel << 3) | maskPattern + var bits = QRUtil.getBCHTypeInfo(data) + for (var i = 0; i < 15; i++) { + var mod = !test && ((bits >> i) & 1) == 1 + if (i < 6) { + this.modules[i][8] = mod + } else if (i < 8) { + this.modules[i + 1][8] = mod + } else { + this.modules[this.moduleCount - 15 + i][8] = mod + } + } + for (var i = 0; i < 15; i++) { + var mod = !test && ((bits >> i) & 1) == 1 + if (i < 8) { + this.modules[8][this.moduleCount - i - 1] = mod + } else if (i < 9) { + this.modules[8][15 - i - 1 + 1] = mod + } else { + this.modules[8][15 - i - 1] = mod + } + } + this.modules[this.moduleCount - 8][8] = !test + }, + mapData: function (data, maskPattern) { + var inc = -1 + var row = this.moduleCount - 1 + var bitIndex = 7 + var byteIndex = 0 + for (var col = this.moduleCount - 1; col > 0; col -= 2) { + if (col == 6) col-- + while (true) { + for (var c = 0; c < 2; c++) { + if (this.modules[row][col - c] == null) { + var dark = false + if (byteIndex < data.length) { + dark = ((data[byteIndex] >>> bitIndex) & 1) == 1 + } + var mask = QRUtil.getMask(maskPattern, row, col - c) + if (mask) { + dark = !dark + } + this.modules[row][col - c] = dark + bitIndex-- + if (bitIndex == -1) { + byteIndex++ + bitIndex = 7 + } + } + } + row += inc + if (row < 0 || this.moduleCount <= row) { + row -= inc + inc = -inc + break + } + } + } + }, + } + QRCodeModel.PAD0 = 0xec + QRCodeModel.PAD1 = 0x11 + QRCodeModel.createData = function (typeNumber, errorCorrectLevel, dataList) { + var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel) + var buffer = new QRBitBuffer() + for (var i = 0; i < dataList.length; i++) { + var data = dataList[i] + buffer.put(data.mode, 4) + buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber)) + data.write(buffer) + } + var totalDataCount = 0 + for (var i = 0; i < rsBlocks.length; i++) { + totalDataCount += rsBlocks[i].dataCount + } + if (buffer.getLengthInBits() > totalDataCount * 8) { + throw new Error('code length overflow. (' + buffer.getLengthInBits() + '>' + totalDataCount * 8 + ')') + } + if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { + buffer.put(0, 4) + } + while (buffer.getLengthInBits() % 8 != 0) { + buffer.putBit(false) + } + while (true) { + if (buffer.getLengthInBits() >= totalDataCount * 8) { + break + } + buffer.put(QRCodeModel.PAD0, 8) + if (buffer.getLengthInBits() >= totalDataCount * 8) { + break + } + buffer.put(QRCodeModel.PAD1, 8) + } + return QRCodeModel.createBytes(buffer, rsBlocks) + } + QRCodeModel.createBytes = function (buffer, rsBlocks) { + var offset = 0 + var maxDcCount = 0 + var maxEcCount = 0 + var dcdata = new Array(rsBlocks.length) + var ecdata = new Array(rsBlocks.length) + for (var r = 0; r < rsBlocks.length; r++) { + var dcCount = rsBlocks[r].dataCount + var ecCount = rsBlocks[r].totalCount - dcCount + maxDcCount = Math.max(maxDcCount, dcCount) + maxEcCount = Math.max(maxEcCount, ecCount) + dcdata[r] = new Array(dcCount) + for (var i = 0; i < dcdata[r].length; i++) { + dcdata[r][i] = 0xff & buffer.buffer[i + offset] + } + offset += dcCount + var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount) + var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1) + var modPoly = rawPoly.mod(rsPoly) + ecdata[r] = new Array(rsPoly.getLength() - 1) + for (var i = 0; i < ecdata[r].length; i++) { + var modIndex = i + modPoly.getLength() - ecdata[r].length + ecdata[r][i] = modIndex >= 0 ? modPoly.get(modIndex) : 0 + } + } + var totalCodeCount = 0 + for (var i = 0; i < rsBlocks.length; i++) { + totalCodeCount += rsBlocks[i].totalCount + } + var data = new Array(totalCodeCount) + var index = 0 + for (var i = 0; i < maxDcCount; i++) { + for (var r = 0; r < rsBlocks.length; r++) { + if (i < dcdata[r].length) { + data[index++] = dcdata[r][i] + } + } + } + for (var i = 0; i < maxEcCount; i++) { + for (var r = 0; r < rsBlocks.length; r++) { + if (i < ecdata[r].length) { + data[index++] = ecdata[r][i] + } + } + } + return data + } + var QRMode = { MODE_NUMBER: 1 << 0, MODE_ALPHA_NUM: 1 << 1, MODE_8BIT_BYTE: 1 << 2, MODE_KANJI: 1 << 3 } + var QRErrorCorrectLevel = { L: 1, M: 0, Q: 3, H: 2 } + var QRMaskPattern = { + PATTERN000: 0, + PATTERN001: 1, + PATTERN010: 2, + PATTERN011: 3, + PATTERN100: 4, + PATTERN101: 5, + PATTERN110: 6, + PATTERN111: 7, + } + var QRUtil = { + PATTERN_POSITION_TABLE: [ + [], + [6, 18], + [6, 22], + [6, 26], + [6, 30], + [6, 34], + [6, 22, 38], + [6, 24, 42], + [6, 26, 46], + [6, 28, 50], + [6, 30, 54], + [6, 32, 58], + [6, 34, 62], + [6, 26, 46, 66], + [6, 26, 48, 70], + [6, 26, 50, 74], + [6, 30, 54, 78], + [6, 30, 56, 82], + [6, 30, 58, 86], + [6, 34, 62, 90], + [6, 28, 50, 72, 94], + [6, 26, 50, 74, 98], + [6, 30, 54, 78, 102], + [6, 28, 54, 80, 106], + [6, 32, 58, 84, 110], + [6, 30, 58, 86, 114], + [6, 34, 62, 90, 118], + [6, 26, 50, 74, 98, 122], + [6, 30, 54, 78, 102, 126], + [6, 26, 52, 78, 104, 130], + [6, 30, 56, 82, 108, 134], + [6, 34, 60, 86, 112, 138], + [6, 30, 58, 86, 114, 142], + [6, 34, 62, 90, 118, 146], + [6, 30, 54, 78, 102, 126, 150], + [6, 24, 50, 76, 102, 128, 154], + [6, 28, 54, 80, 106, 132, 158], + [6, 32, 58, 84, 110, 136, 162], + [6, 26, 54, 82, 110, 138, 166], + [6, 30, 58, 86, 114, 142, 170], + ], + G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0), + G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0), + G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1), + getBCHTypeInfo: function (data) { + var d = data << 10 + while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) { + d ^= QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)) + } + return ((data << 10) | d) ^ QRUtil.G15_MASK + }, + getBCHTypeNumber: function (data) { + var d = data << 12 + while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) { + d ^= QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)) + } + return (data << 12) | d + }, + getBCHDigit: function (data) { + var digit = 0 + while (data != 0) { + digit++ + data >>>= 1 + } + return digit + }, + getPatternPosition: function (typeNumber) { + return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1] + }, + getMask: function (maskPattern, i, j) { + switch (maskPattern) { + case QRMaskPattern.PATTERN000: + return (i + j) % 2 == 0 + case QRMaskPattern.PATTERN001: + return i % 2 == 0 + case QRMaskPattern.PATTERN010: + return j % 3 == 0 + case QRMaskPattern.PATTERN011: + return (i + j) % 3 == 0 + case QRMaskPattern.PATTERN100: + return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0 + case QRMaskPattern.PATTERN101: + return ((i * j) % 2) + ((i * j) % 3) == 0 + case QRMaskPattern.PATTERN110: + return (((i * j) % 2) + ((i * j) % 3)) % 2 == 0 + case QRMaskPattern.PATTERN111: + return (((i * j) % 3) + ((i + j) % 2)) % 2 == 0 + default: + throw new Error('bad maskPattern:' + maskPattern) + } + }, + getErrorCorrectPolynomial: function (errorCorrectLength) { + var a = new QRPolynomial([1], 0) + for (var i = 0; i < errorCorrectLength; i++) { + a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0)) + } + return a + }, + getLengthInBits: function (mode, type) { + if (1 <= type && type < 10) { + switch (mode) { + case QRMode.MODE_NUMBER: + return 10 + case QRMode.MODE_ALPHA_NUM: + return 9 + case QRMode.MODE_8BIT_BYTE: + return 8 + case QRMode.MODE_KANJI: + return 8 + default: + throw new Error('mode:' + mode) + } + } else if (type < 27) { + switch (mode) { + case QRMode.MODE_NUMBER: + return 12 + case QRMode.MODE_ALPHA_NUM: + return 11 + case QRMode.MODE_8BIT_BYTE: + return 16 + case QRMode.MODE_KANJI: + return 10 + default: + throw new Error('mode:' + mode) + } + } else if (type < 41) { + switch (mode) { + case QRMode.MODE_NUMBER: + return 14 + case QRMode.MODE_ALPHA_NUM: + return 13 + case QRMode.MODE_8BIT_BYTE: + return 16 + case QRMode.MODE_KANJI: + return 12 + default: + throw new Error('mode:' + mode) + } + } else { + throw new Error('type:' + type) + } + }, + getLostPoint: function (qrCode) { + var moduleCount = qrCode.getModuleCount() + var lostPoint = 0 + for (var row = 0; row < moduleCount; row++) { + for (var col = 0; col < moduleCount; col++) { + var sameCount = 0 + var dark = qrCode.isDark(row, col) + for (var r = -1; r <= 1; r++) { + if (row + r < 0 || moduleCount <= row + r) { + continue + } + for (var c = -1; c <= 1; c++) { + if (col + c < 0 || moduleCount <= col + c) { + continue + } + if (r == 0 && c == 0) { + continue + } + if (dark == qrCode.isDark(row + r, col + c)) { + sameCount++ + } + } + } + if (sameCount > 5) { + lostPoint += 3 + sameCount - 5 + } + } + } + for (var row = 0; row < moduleCount - 1; row++) { + for (var col = 0; col < moduleCount - 1; col++) { + var count = 0 + if (qrCode.isDark(row, col)) count++ + if (qrCode.isDark(row + 1, col)) count++ + if (qrCode.isDark(row, col + 1)) count++ + if (qrCode.isDark(row + 1, col + 1)) count++ + if (count == 0 || count == 4) { + lostPoint += 3 + } + } + } + for (var row = 0; row < moduleCount; row++) { + for (var col = 0; col < moduleCount - 6; col++) { + if ( + qrCode.isDark(row, col) && + !qrCode.isDark(row, col + 1) && + qrCode.isDark(row, col + 2) && + qrCode.isDark(row, col + 3) && + qrCode.isDark(row, col + 4) && + !qrCode.isDark(row, col + 5) && + qrCode.isDark(row, col + 6) + ) { + lostPoint += 40 + } + } + } + for (var col = 0; col < moduleCount; col++) { + for (var row = 0; row < moduleCount - 6; row++) { + if ( + qrCode.isDark(row, col) && + !qrCode.isDark(row + 1, col) && + qrCode.isDark(row + 2, col) && + qrCode.isDark(row + 3, col) && + qrCode.isDark(row + 4, col) && + !qrCode.isDark(row + 5, col) && + qrCode.isDark(row + 6, col) + ) { + lostPoint += 40 + } + } + } + var darkCount = 0 + for (var col = 0; col < moduleCount; col++) { + for (var row = 0; row < moduleCount; row++) { + if (qrCode.isDark(row, col)) { + darkCount++ + } + } + } + var ratio = Math.abs((100 * darkCount) / moduleCount / moduleCount - 50) / 5 + lostPoint += ratio * 10 + return lostPoint + }, + } + var QRMath = { + glog: function (n) { + if (n < 1) { + throw new Error('glog(' + n + ')') + } + return QRMath.LOG_TABLE[n] + }, + gexp: function (n) { + while (n < 0) { + n += 255 + } + while (n >= 256) { + n -= 255 + } + return QRMath.EXP_TABLE[n] + }, + EXP_TABLE: new Array(256), + LOG_TABLE: new Array(256), + } + for (var i = 0; i < 8; i++) { + QRMath.EXP_TABLE[i] = 1 << i + } + for (var i = 8; i < 256; i++) { + QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8] + } + for (var i = 0; i < 255; i++) { + QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i + } + + function QRPolynomial(num, shift) { + if (num.length == undefined) { + throw new Error(num.length + '/' + shift) + } + var offset = 0 + while (offset < num.length && num[offset] == 0) { + offset++ + } + this.num = new Array(num.length - offset + shift) + for (var i = 0; i < num.length - offset; i++) { + this.num[i] = num[i + offset] + } + } + + QRPolynomial.prototype = { + get: function (index) { + return this.num[index] + }, + getLength: function () { + return this.num.length + }, + multiply: function (e) { + var num = new Array(this.getLength() + e.getLength() - 1) + for (var i = 0; i < this.getLength(); i++) { + for (var j = 0; j < e.getLength(); j++) { + num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j))) + } + } + return new QRPolynomial(num, 0) + }, + mod: function (e) { + if (this.getLength() - e.getLength() < 0) { + return this + } + var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0)) + var num = new Array(this.getLength()) + for (var i = 0; i < this.getLength(); i++) { + num[i] = this.get(i) + } + for (var i = 0; i < e.getLength(); i++) { + num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio) + } + return new QRPolynomial(num, 0).mod(e) + }, + } + + function QRRSBlock(totalCount, dataCount) { + this.totalCount = totalCount + this.dataCount = dataCount + } + + QRRSBlock.RS_BLOCK_TABLE = [ + [1, 26, 19], + [1, 26, 16], + [1, 26, 13], + [1, 26, 9], + [1, 44, 34], + [1, 44, 28], + [1, 44, 22], + [1, 44, 16], + [1, 70, 55], + [1, 70, 44], + [2, 35, 17], + [2, 35, 13], + [1, 100, 80], + [2, 50, 32], + [2, 50, 24], + [4, 25, 9], + [1, 134, 108], + [2, 67, 43], + [2, 33, 15, 2, 34, 16], + [2, 33, 11, 2, 34, 12], + [2, 86, 68], + [4, 43, 27], + [4, 43, 19], + [4, 43, 15], + [2, 98, 78], + [4, 49, 31], + [2, 32, 14, 4, 33, 15], + [4, 39, 13, 1, 40, 14], + [2, 121, 97], + [2, 60, 38, 2, 61, 39], + [4, 40, 18, 2, 41, 19], + [4, 40, 14, 2, 41, 15], + [2, 146, 116], + [3, 58, 36, 2, 59, 37], + [4, 36, 16, 4, 37, 17], + [4, 36, 12, 4, 37, 13], + [2, 86, 68, 2, 87, 69], + [4, 69, 43, 1, 70, 44], + [6, 43, 19, 2, 44, 20], + [6, 43, 15, 2, 44, 16], + [4, 101, 81], + [1, 80, 50, 4, 81, 51], + [4, 50, 22, 4, 51, 23], + [3, 36, 12, 8, 37, 13], + [2, 116, 92, 2, 117, 93], + [6, 58, 36, 2, 59, 37], + [4, 46, 20, 6, 47, 21], + [7, 42, 14, 4, 43, 15], + [4, 133, 107], + [8, 59, 37, 1, 60, 38], + [8, 44, 20, 4, 45, 21], + [12, 33, 11, 4, 34, 12], + [3, 145, 115, 1, 146, 116], + [4, 64, 40, 5, 65, 41], + [11, 36, 16, 5, 37, 17], + [11, 36, 12, 5, 37, 13], + [5, 109, 87, 1, 110, 88], + [5, 65, 41, 5, 66, 42], + [5, 54, 24, 7, 55, 25], + [11, 36, 12], + [5, 122, 98, 1, 123, 99], + [7, 73, 45, 3, 74, 46], + [15, 43, 19, 2, 44, 20], + [3, 45, 15, 13, 46, 16], + [1, 135, 107, 5, 136, 108], + [10, 74, 46, 1, 75, 47], + [1, 50, 22, 15, 51, 23], + [2, 42, 14, 17, 43, 15], + [5, 150, 120, 1, 151, 121], + [9, 69, 43, 4, 70, 44], + [17, 50, 22, 1, 51, 23], + [2, 42, 14, 19, 43, 15], + [3, 141, 113, 4, 142, 114], + [3, 70, 44, 11, 71, 45], + [17, 47, 21, 4, 48, 22], + [9, 39, 13, 16, 40, 14], + [3, 135, 107, 5, 136, 108], + [3, 67, 41, 13, 68, 42], + [15, 54, 24, 5, 55, 25], + [15, 43, 15, 10, 44, 16], + [4, 144, 116, 4, 145, 117], + [17, 68, 42], + [17, 50, 22, 6, 51, 23], + [19, 46, 16, 6, 47, 17], + [2, 139, 111, 7, 140, 112], + [17, 74, 46], + [7, 54, 24, 16, 55, 25], + [34, 37, 13], + [4, 151, 121, 5, 152, 122], + [4, 75, 47, 14, 76, 48], + [11, 54, 24, 14, 55, 25], + [16, 45, 15, 14, 46, 16], + [6, 147, 117, 4, 148, 118], + [6, 73, 45, 14, 74, 46], + [11, 54, 24, 16, 55, 25], + [30, 46, 16, 2, 47, 17], + [8, 132, 106, 4, 133, 107], + [8, 75, 47, 13, 76, 48], + [7, 54, 24, 22, 55, 25], + [22, 45, 15, 13, 46, 16], + [10, 142, 114, 2, 143, 115], + [19, 74, 46, 4, 75, 47], + [28, 50, 22, 6, 51, 23], + [33, 46, 16, 4, 47, 17], + [8, 152, 122, 4, 153, 123], + [22, 73, 45, 3, 74, 46], + [8, 53, 23, 26, 54, 24], + [12, 45, 15, 28, 46, 16], + [3, 147, 117, 10, 148, 118], + [3, 73, 45, 23, 74, 46], + [4, 54, 24, 31, 55, 25], + [11, 45, 15, 31, 46, 16], + [7, 146, 116, 7, 147, 117], + [21, 73, 45, 7, 74, 46], + [1, 53, 23, 37, 54, 24], + [19, 45, 15, 26, 46, 16], + [5, 145, 115, 10, 146, 116], + [19, 75, 47, 10, 76, 48], + [15, 54, 24, 25, 55, 25], + [23, 45, 15, 25, 46, 16], + [13, 145, 115, 3, 146, 116], + [2, 74, 46, 29, 75, 47], + [42, 54, 24, 1, 55, 25], + [23, 45, 15, 28, 46, 16], + [17, 145, 115], + [10, 74, 46, 23, 75, 47], + [10, 54, 24, 35, 55, 25], + [19, 45, 15, 35, 46, 16], + [17, 145, 115, 1, 146, 116], + [14, 74, 46, 21, 75, 47], + [29, 54, 24, 19, 55, 25], + [11, 45, 15, 46, 46, 16], + [13, 145, 115, 6, 146, 116], + [14, 74, 46, 23, 75, 47], + [44, 54, 24, 7, 55, 25], + [59, 46, 16, 1, 47, 17], + [12, 151, 121, 7, 152, 122], + [12, 75, 47, 26, 76, 48], + [39, 54, 24, 14, 55, 25], + [22, 45, 15, 41, 46, 16], + [6, 151, 121, 14, 152, 122], + [6, 75, 47, 34, 76, 48], + [46, 54, 24, 10, 55, 25], + [2, 45, 15, 64, 46, 16], + [17, 152, 122, 4, 153, 123], + [29, 74, 46, 14, 75, 47], + [49, 54, 24, 10, 55, 25], + [24, 45, 15, 46, 46, 16], + [4, 152, 122, 18, 153, 123], + [13, 74, 46, 32, 75, 47], + [48, 54, 24, 14, 55, 25], + [42, 45, 15, 32, 46, 16], + [20, 147, 117, 4, 148, 118], + [40, 75, 47, 7, 76, 48], + [43, 54, 24, 22, 55, 25], + [10, 45, 15, 67, 46, 16], + [19, 148, 118, 6, 149, 119], + [18, 75, 47, 31, 76, 48], + [34, 54, 24, 34, 55, 25], + [20, 45, 15, 61, 46, 16], + ] + QRRSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) { + var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel) + if (rsBlock == undefined) { + throw new Error('bad rs block @ typeNumber:' + typeNumber + '/errorCorrectLevel:' + errorCorrectLevel) + } + var length = rsBlock.length / 3 + var list = [] + for (var i = 0; i < length; i++) { + var count = rsBlock[i * 3 + 0] + var totalCount = rsBlock[i * 3 + 1] + var dataCount = rsBlock[i * 3 + 2] + for (var j = 0; j < count; j++) { + list.push(new QRRSBlock(totalCount, dataCount)) + } + } + return list + } + QRRSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) { + switch (errorCorrectLevel) { + case QRErrorCorrectLevel.L: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0] + case QRErrorCorrectLevel.M: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1] + case QRErrorCorrectLevel.Q: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2] + case QRErrorCorrectLevel.H: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3] + default: + return undefined + } + } + + function QRBitBuffer() { + this.buffer = [] + this.length = 0 + } + + QRBitBuffer.prototype = { + get: function (index) { + var bufIndex = Math.floor(index / 8) + return ((this.buffer[bufIndex] >>> (7 - (index % 8))) & 1) == 1 + }, + put: function (num, length) { + for (var i = 0; i < length; i++) { + this.putBit(((num >>> (length - i - 1)) & 1) == 1) + } + }, + getLengthInBits: function () { + return this.length + }, + putBit: function (bit) { + var bufIndex = Math.floor(this.length / 8) + if (this.buffer.length <= bufIndex) { + this.buffer.push(0) + } + if (bit) { + this.buffer[bufIndex] |= 0x80 >>> this.length % 8 + } + this.length++ + }, + } + var QRCodeLimitLength = [ + [17, 14, 11, 7], + [32, 26, 20, 14], + [53, 42, 32, 24], + [78, 62, 46, 34], + [106, 84, 60, 44], + [134, 106, 74, 58], + [154, 122, 86, 64], + [192, 152, 108, 84], + [230, 180, 130, 98], + [271, 213, 151, 119], + [321, 251, 177, 137], + [367, 287, 203, 155], + [425, 331, 241, 177], + [458, 362, 258, 194], + [520, 412, 292, 220], + [586, 450, 322, 250], + [644, 504, 364, 280], + [718, 560, 394, 310], + [792, 624, 442, 338], + [858, 666, 482, 382], + [929, 711, 509, 403], + [1003, 779, 565, 439], + [1091, 857, 611, 461], + [1171, 911, 661, 511], + [1273, 997, 715, 535], + [1367, 1059, 751, 593], + [1465, 1125, 805, 625], + [1528, 1190, 868, 658], + [1628, 1264, 908, 698], + [1732, 1370, 982, 742], + [1840, 1452, 1030, 790], + [1952, 1538, 1112, 842], + [2068, 1628, 1168, 898], + [2188, 1722, 1228, 958], + [2303, 1809, 1283, 983], + [2431, 1911, 1351, 1051], + [2563, 1989, 1423, 1093], + [2699, 2099, 1499, 1139], + [2809, 2213, 1579, 1219], + [2953, 2331, 1663, 1273], + ] + + function _isSupportCanvas() { + return typeof CanvasRenderingContext2D != 'undefined' + } + + // android 2.x doesn't support Data-URI spec + function _getAndroid() { + var android = false + var sAgent = navigator.userAgent + + if (/android/i.test(sAgent)) { + // android + android = true + var aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i) + + if (aMat && aMat[1]) { + android = parseFloat(aMat[1]) + } + } + + return android + } + + var svgDrawer = (function () { + var Drawing = function (el, htOption) { + this._el = el + this._htOption = htOption + } + + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption + var _el = this._el + var nCount = oQRCode.getModuleCount() + var nWidth = Math.floor(_htOption.width / nCount) + var nHeight = Math.floor(_htOption.height / nCount) + + this.clear() + + function makeSVG(tag, attrs) { + var el = document.createElementNS('http://www.w3.org/2000/svg', tag) + for (var k in attrs) if (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]) + return el + } + + var svg = makeSVG('svg', { + viewBox: '0 0 ' + String(nCount) + ' ' + String(nCount), + width: '100%', + height: '100%', + fill: _htOption.colorLight, + }) + svg.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink') + _el.appendChild(svg) + + svg.appendChild(makeSVG('rect', { fill: _htOption.colorLight, width: '100%', height: '100%' })) + svg.appendChild(makeSVG('rect', { fill: _htOption.colorDark, width: '1', height: '1', id: 'template' })) + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + if (oQRCode.isDark(row, col)) { + var child = makeSVG('use', { x: String(col), y: String(row) }) + child.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#template') + svg.appendChild(child) + } + } + } + } + Drawing.prototype.clear = function () { + while (this._el.hasChildNodes()) this._el.removeChild(this._el.lastChild) + } + return Drawing + })() + + var useSVG = document.documentElement.tagName.toLowerCase() === 'svg' + + // Drawing in DOM by using Table tag + var Drawing = useSVG + ? svgDrawer + : !_isSupportCanvas() + ? (function () { + var Drawing = function (el, htOption) { + this._el = el + this._htOption = htOption + } + + /** + * Draw the QRCode + * + * @param {QRCode} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption + var _el = this._el + var nCount = oQRCode.getModuleCount() + var nWidth = Math.floor(_htOption.width / nCount) + var nHeight = Math.floor(_htOption.height / nCount) + var aHTML = [''] + + for (var row = 0; row < nCount; row++) { + aHTML.push('') + + for (var col = 0; col < nCount; col++) { + aHTML.push( + '', + ) + } + + aHTML.push('') + } + + aHTML.push('
') + _el.innerHTML = aHTML.join('') + + // Fix the margin values as real size. + var elTable = _el.childNodes[0] + var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2 + var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2 + + if (nLeftMarginTable > 0 && nTopMarginTable > 0) { + elTable.style.margin = nTopMarginTable + 'px ' + nLeftMarginTable + 'px' + } + } + + /** + * Clear the QRCode + */ + Drawing.prototype.clear = function () { + this._el.innerHTML = '' + } + + return Drawing + })() + : (function () { + // Drawing in Canvas + function _onMakeImage() { + this._elImage.src = this._elCanvas.toDataURL('image/png') + this._elImage.style.display = 'block' + this._elCanvas.style.display = 'none' + } + + // Android 2.1 bug workaround + // http://code.google.com/p/android/issues/detail?id=5141 + if (this && this._android && this._android <= 2.1) { + var factor = 1 / window.devicePixelRatio + var drawImage = CanvasRenderingContext2D.prototype.drawImage + CanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) { + if ('nodeName' in image && /img/i.test(image.nodeName)) { + for (var i = arguments.length - 1; i >= 1; i--) { + arguments[i] = arguments[i] * factor + } + } else if (typeof dw == 'undefined') { + arguments[1] *= factor + arguments[2] *= factor + arguments[3] *= factor + arguments[4] *= factor + } + + drawImage.apply(this, arguments) + } + } + + /** + * Check whether the user's browser supports Data URI or not + * + * @private + * @param {Function} fSuccess Occurs if it supports Data URI + * @param {Function} fFail Occurs if it doesn't support Data URI + */ + function _safeSetDataURI(fSuccess, fFail) { + var self = this + self._fFail = fFail + self._fSuccess = fSuccess + + // Check it just once + if (self._bSupportDataURI === null) { + var el = document.createElement('img') + var fOnError = function () { + self._bSupportDataURI = false + + if (self._fFail) { + self._fFail.call(self) + } + } + var fOnSuccess = function () { + self._bSupportDataURI = true + + if (self._fSuccess) { + self._fSuccess.call(self) + } + } + + el.onabort = fOnError + el.onerror = fOnError + el.onload = fOnSuccess + el.src = + 'data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==' // the Image contains 1px data. + return + } else if (self._bSupportDataURI === true && self._fSuccess) { + self._fSuccess.call(self) + } else if (self._bSupportDataURI === false && self._fFail) { + self._fFail.call(self) + } + } + + /** + * Drawing QRCode by using canvas + * + * @constructor + * @param {HTMLElement} el + * @param {Object} htOption QRCode Options + */ + var Drawing = function (el, htOption) { + this._bIsPainted = false + this._android = _getAndroid() + + this._htOption = htOption + this._elCanvas = document.createElement('canvas') + this._elCanvas.width = htOption.width + this._elCanvas.height = htOption.height + el.appendChild(this._elCanvas) + this._el = el + this._oContext = this._elCanvas.getContext('2d') + this._bIsPainted = false + this._elImage = document.createElement('img') + this._elImage.alt = 'Scan me!' + this._elImage.style.display = 'none' + this._el.appendChild(this._elImage) + this._bSupportDataURI = null + } + + /** + * Draw the QRCode + * + * @param {QRCode} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _elImage = this._elImage + var _oContext = this._oContext + var _htOption = this._htOption + + var nCount = oQRCode.getModuleCount() + var nWidth = _htOption.width / nCount + var nHeight = _htOption.height / nCount + var nRoundedWidth = Math.round(nWidth) + var nRoundedHeight = Math.round(nHeight) + + _elImage.style.display = 'none' + this.clear() + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + var bIsDark = oQRCode.isDark(row, col) + var nLeft = col * nWidth + var nTop = row * nHeight + _oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight + _oContext.lineWidth = 1 + _oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight + _oContext.fillRect(nLeft, nTop, nWidth, nHeight) + + // 안티 앨리어싱 방지 처리 + _oContext.strokeRect(Math.floor(nLeft) + 0.5, Math.floor(nTop) + 0.5, nRoundedWidth, nRoundedHeight) + + _oContext.strokeRect(Math.ceil(nLeft) - 0.5, Math.ceil(nTop) - 0.5, nRoundedWidth, nRoundedHeight) + } + } + + this._bIsPainted = true + } + + /** + * Make the image from Canvas if the browser supports Data URI. + */ + Drawing.prototype.makeImage = function () { + if (this._bIsPainted) { + _safeSetDataURI.call(this, _onMakeImage) + } + } + + /** + * Return whether the QRCode is painted or not + * + * @return {Boolean} + */ + Drawing.prototype.isPainted = function () { + return this._bIsPainted + } + + /** + * Clear the QRCode + */ + Drawing.prototype.clear = function () { + this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height) + this._bIsPainted = false + } + + /** + * @private + * @param {Number} nNumber + */ + Drawing.prototype.round = function (nNumber) { + if (!nNumber) { + return nNumber + } + + return Math.floor(nNumber * 1000) / 1000 + } + + return Drawing + })() + + /** + * Get the type by string length + * + * @private + * @param {String} sText + * @param {Number} nCorrectLevel + * @return {Number} type + */ + function _getTypeNumber(sText, nCorrectLevel) { + var nType = 1 + var length = _getUTF8Length(sText) + + for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) { + var nLimit = 0 + + switch (nCorrectLevel) { + case QRErrorCorrectLevel.L: + nLimit = QRCodeLimitLength[i][0] + break + case QRErrorCorrectLevel.M: + nLimit = QRCodeLimitLength[i][1] + break + case QRErrorCorrectLevel.Q: + nLimit = QRCodeLimitLength[i][2] + break + case QRErrorCorrectLevel.H: + nLimit = QRCodeLimitLength[i][3] + break + } + + if (length <= nLimit) { + break + } else { + nType++ + } + } + + if (nType > QRCodeLimitLength.length) { + throw new Error('Too long data') + } + + return nType + } + + function _getUTF8Length(sText) { + var replacedText = encodeURI(sText) + .toString() + .replace(/\%[0-9a-fA-F]{2}/g, 'a') + return replacedText.length + (replacedText.length != sText ? 3 : 0) + } + + /** + * @class QRCode + * @constructor + * @example + * new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie"); + * + * @example + * var oQRCode = new QRCode("test", { + * text : "http://naver.com", + * width : 128, + * height : 128 + * }); + * + * oQRCode.clear(); // Clear the QRCode. + * oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode. + * + * @param {HTMLElement|String} el target element or 'id' attribute of element. + * @param {Object|String} vOption + * @param {String} vOption.text QRCode link data + * @param {Number} [vOption.width=256] + * @param {Number} [vOption.height=256] + * @param {String} [vOption.colorDark="#000000"] + * @param {String} [vOption.colorLight="#ffffff"] + * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H] + */ + QRCode = function (el, vOption) { + this._htOption = { + width: 256, + height: 256, + typeNumber: 4, + colorDark: '#000000', + colorLight: '#ffffff', + correctLevel: QRErrorCorrectLevel.H, + } + + if (typeof vOption === 'string') { + vOption = { + text: vOption, + } + } + + // Overwrites options + if (vOption) { + for (var i in vOption) { + this._htOption[i] = vOption[i] + } + } + + if (typeof el == 'string') { + el = document.getElementById(el) + } + + if (this._htOption.useSVG) { + Drawing = svgDrawer + } + + this._android = _getAndroid() + this._el = el + this._oQRCode = null + this._oDrawing = new Drawing(this._el, this._htOption) + + if (this._htOption.text) { + this.makeCode(this._htOption.text) + } + } + + /** + * Make the QRCode + * + * @param {String} sText link data + */ + QRCode.prototype.makeCode = function (sText) { + this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel) + this._oQRCode.addData(sText) + this._oQRCode.make() + this._el.title = sText + this._oDrawing.draw(this._oQRCode) + this.makeImage() + } + + /** + * Make the Image from Canvas element + * - It occurs automatically + * - Android below 3 doesn't support Data-URI spec. + * + * @private + */ + QRCode.prototype.makeImage = function () { + if (typeof this._oDrawing.makeImage == 'function' && (!this._android || this._android >= 3)) { + this._oDrawing.makeImage() + } + } + + /** + * Clear the QRCode + */ + QRCode.prototype.clear = function () { + this._oDrawing.clear() + } + + /** + * @name QRCode.CorrectLevel + */ + QRCode.CorrectLevel = QRErrorCorrectLevel +})() + +export default QRCode \ No newline at end of file diff --git a/src/frontend/admin/src/components/scSelect/index.vue b/src/frontend/admin/src/components/scSelect/index.vue new file mode 100644 index 00000000..6de25f77 --- /dev/null +++ b/src/frontend/admin/src/components/scSelect/index.vue @@ -0,0 +1,116 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scSelectFilter/index.vue b/src/frontend/admin/src/components/scSelectFilter/index.vue new file mode 100644 index 00000000..ee022e79 --- /dev/null +++ b/src/frontend/admin/src/components/scSelectFilter/index.vue @@ -0,0 +1,195 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scStatistic/index.vue b/src/frontend/admin/src/components/scStatistic/index.vue new file mode 100644 index 00000000..7a4f305a --- /dev/null +++ b/src/frontend/admin/src/components/scStatistic/index.vue @@ -0,0 +1,99 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scTable/column.js b/src/frontend/admin/src/components/scTable/column.js new file mode 100644 index 00000000..a6e52d12 --- /dev/null +++ b/src/frontend/admin/src/components/scTable/column.js @@ -0,0 +1,23 @@ +import { h, resolveComponent } from 'vue' + +export default { + render() { + return h( + resolveComponent('el-table-column'), + { + index: this.index, + ...this.$attrs, + }, + this.$slots, + ) + }, + methods: { + index(index) { + if (this.$attrs.type === 'index') { + let page = this.$parent.$parent.currentPage + let pageSize = this.$parent.$parent.pageSize + return (page - 1) * pageSize + index + 1 + } + }, + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/components/scTable/columnSetting.vue b/src/frontend/admin/src/components/scTable/columnSetting.vue new file mode 100644 index 00000000..79de9dce --- /dev/null +++ b/src/frontend/admin/src/components/scTable/columnSetting.vue @@ -0,0 +1,200 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scTable/index.vue b/src/frontend/admin/src/components/scTable/index.vue new file mode 100644 index 00000000..f00ef42a --- /dev/null +++ b/src/frontend/admin/src/components/scTable/index.vue @@ -0,0 +1,514 @@ + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scTableSelect/index.vue b/src/frontend/admin/src/components/scTableSelect/index.vue new file mode 100644 index 00000000..8b642687 --- /dev/null +++ b/src/frontend/admin/src/components/scTableSelect/index.vue @@ -0,0 +1,282 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scTitle/index.vue b/src/frontend/admin/src/components/scTitle/index.vue new file mode 100644 index 00000000..0f4b9a2c --- /dev/null +++ b/src/frontend/admin/src/components/scTitle/index.vue @@ -0,0 +1,28 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scUpload/file.vue b/src/frontend/admin/src/components/scUpload/file.vue new file mode 100644 index 00000000..dfefaf0c --- /dev/null +++ b/src/frontend/admin/src/components/scUpload/file.vue @@ -0,0 +1,214 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scUpload/index.vue b/src/frontend/admin/src/components/scUpload/index.vue new file mode 100644 index 00000000..7264fd76 --- /dev/null +++ b/src/frontend/admin/src/components/scUpload/index.vue @@ -0,0 +1,406 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scUpload/multiple.vue b/src/frontend/admin/src/components/scUpload/multiple.vue new file mode 100644 index 00000000..dab2f7a6 --- /dev/null +++ b/src/frontend/admin/src/components/scUpload/multiple.vue @@ -0,0 +1,340 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scVideo/index.vue b/src/frontend/admin/src/components/scVideo/index.vue new file mode 100644 index 00000000..ddea4d24 --- /dev/null +++ b/src/frontend/admin/src/components/scVideo/index.vue @@ -0,0 +1,111 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scWaterMark/index.vue b/src/frontend/admin/src/components/scWaterMark/index.vue new file mode 100644 index 00000000..8ecb1002 --- /dev/null +++ b/src/frontend/admin/src/components/scWaterMark/index.vue @@ -0,0 +1,71 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scWorkflow/index.vue b/src/frontend/admin/src/components/scWorkflow/index.vue new file mode 100644 index 00000000..70a9b70d --- /dev/null +++ b/src/frontend/admin/src/components/scWorkflow/index.vue @@ -0,0 +1,572 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scWorkflow/nodeWrap.vue b/src/frontend/admin/src/components/scWorkflow/nodeWrap.vue new file mode 100644 index 00000000..e5baa349 --- /dev/null +++ b/src/frontend/admin/src/components/scWorkflow/nodeWrap.vue @@ -0,0 +1,56 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scWorkflow/nodes/addNode.vue b/src/frontend/admin/src/components/scWorkflow/nodes/addNode.vue new file mode 100644 index 00000000..bedf3865 --- /dev/null +++ b/src/frontend/admin/src/components/scWorkflow/nodes/addNode.vue @@ -0,0 +1,104 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scWorkflow/nodes/approver.vue b/src/frontend/admin/src/components/scWorkflow/nodes/approver.vue new file mode 100644 index 00000000..707d7d4b --- /dev/null +++ b/src/frontend/admin/src/components/scWorkflow/nodes/approver.vue @@ -0,0 +1,225 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scWorkflow/nodes/branch.vue b/src/frontend/admin/src/components/scWorkflow/nodes/branch.vue new file mode 100644 index 00000000..8e9854a5 --- /dev/null +++ b/src/frontend/admin/src/components/scWorkflow/nodes/branch.vue @@ -0,0 +1,243 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scWorkflow/nodes/promoter.vue b/src/frontend/admin/src/components/scWorkflow/nodes/promoter.vue new file mode 100644 index 00000000..a6b5fdae --- /dev/null +++ b/src/frontend/admin/src/components/scWorkflow/nodes/promoter.vue @@ -0,0 +1,123 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scWorkflow/nodes/send.vue b/src/frontend/admin/src/components/scWorkflow/nodes/send.vue new file mode 100644 index 00000000..f9964408 --- /dev/null +++ b/src/frontend/admin/src/components/scWorkflow/nodes/send.vue @@ -0,0 +1,136 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/components/scWorkflow/select.vue b/src/frontend/admin/src/components/scWorkflow/select.vue new file mode 100644 index 00000000..fc3d482d --- /dev/null +++ b/src/frontend/admin/src/components/scWorkflow/select.vue @@ -0,0 +1,414 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/config/fileSelect.js b/src/frontend/admin/src/config/fileSelect.js new file mode 100644 index 00000000..9c99c17b --- /dev/null +++ b/src/frontend/admin/src/config/fileSelect.js @@ -0,0 +1,69 @@ +import API from '@/api' + +//文件选择器配置 + +export default { + apiObj: API.common.upload, + menuApiObj: API.common.file.menu, + listApiObj: API.common.file.list, + successCode: 200, + maxSize: 30, + max: 99, + uploadParseData: function (res) { + return { + id: res.data.id, + fileName: res.data.fileName, + url: res.data.src, + } + }, + listParseData: function (res) { + return { + rows: res.data.rows, + total: res.data.total, + msg: res.message, + code: res.code, + } + }, + request: { + page: 'page', + pageSize: 'pageSize', + keyword: 'keyword', + menuKey: 'groupId', + }, + menuProps: { + key: 'id', + label: 'label', + children: 'children', + }, + fileProps: { + key: 'id', + fileName: 'fileName', + url: 'url', + }, + files: { + doc: { + icon: 'sc-icon-file-word-2-fill', + color: '#409eff', + }, + docx: { + icon: 'sc-icon-file-word-2-fill', + color: '#409eff', + }, + xls: { + icon: 'sc-icon-file-excel-2-fill', + color: '#67C23A', + }, + xlsx: { + icon: 'sc-icon-file-excel-2-fill', + color: '#67C23A', + }, + ppt: { + icon: 'sc-icon-file-ppt-2-fill', + color: '#F56C6C', + }, + pptx: { + icon: 'sc-icon-file-ppt-2-fill', + color: '#F56C6C', + }, + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/filterBar.js b/src/frontend/admin/src/config/filterBar.js new file mode 100644 index 00000000..1f6a31e9 --- /dev/null +++ b/src/frontend/admin/src/config/filterBar.js @@ -0,0 +1,74 @@ +export default { + //运算符 + operator: [ + { + label: '等于', + value: '=', + }, + { + label: '不等于', + value: '!=', + }, + { + label: '大于', + value: '>', + }, + { + label: '大于等于', + value: '>=', + }, + { + label: '小于', + value: '<', + }, + { + label: '小于等于', + value: '<=', + }, + { + label: '包含', + value: 'include', + }, + { + label: '不包含', + value: 'notinclude', + }, + ], + //过滤结果运算符的分隔符 + separator: '|', + //获取我的常用 + getMy: function (name) { + return new Promise((resolve) => { + console.log(`这里可以根据${name}参数请求接口`) + var list = [] + setTimeout(() => { + resolve(list) + }, 500) + }) + }, + /** + * 常用保存处理 返回resolve后继续操作 + * @name scFilterBar组件的props->filterName + * @obj 过滤项整理好的对象 + */ + saveMy: function (name, obj) { + return new Promise((resolve) => { + console.log(name, obj) + setTimeout(() => { + resolve(true) + }, 500) + }) + }, + /** + * 常用删除处理 返回resolve后继续操作 + * @name scFilterBar组件的props->filterName + */ + delMy: function (name) { + return new Promise((resolve) => { + console.log(name) + setTimeout(() => { + resolve(true) + }, 500) + }) + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/iconSelect.js b/src/frontend/admin/src/config/iconSelect.js new file mode 100644 index 00000000..e59209b3 --- /dev/null +++ b/src/frontend/admin/src/config/iconSelect.js @@ -0,0 +1,309 @@ +//图标选择器配置 +export default { + icons: [ + { + name: '默认', + icons: [ + 'el-icon-add-location', + 'el-icon-aim', + 'el-icon-alarm-clock', + 'el-icon-apple', + 'el-icon-arrow-down', + 'el-icon-arrow-down-bold', + 'el-icon-arrow-left', + 'el-icon-arrow-left-bold', + 'el-icon-arrow-right', + 'el-icon-arrow-right-bold', + 'el-icon-arrow-up', + 'el-icon-arrow-up-bold', + 'el-icon-avatar', + 'el-icon-back', + 'el-icon-baseball', + 'el-icon-basketball', + 'el-icon-bell', + 'el-icon-bell-filled', + 'el-icon-bicycle', + 'el-icon-bottom', + 'el-icon-bottom-left', + 'el-icon-bottom-right', + 'el-icon-bowl', + 'el-icon-box', + 'el-icon-briefcase', + 'el-icon-brush', + 'el-icon-brush-filled', + 'el-icon-burger', + 'el-icon-calendar', + 'el-icon-camera', + 'el-icon-camera-filled', + 'el-icon-caret-bottom', + 'el-icon-caret-left', + 'el-icon-caret-right', + 'el-icon-caret-top', + 'el-icon-cellphone', + 'el-icon-chat-dot-round', + 'el-icon-chat-dot-square', + 'el-icon-chat-line-round', + 'el-icon-chat-line-square', + 'el-icon-chat-round', + 'el-icon-chat-square', + 'el-icon-check', + 'el-icon-checked', + 'el-icon-cherry', + 'el-icon-chicken', + 'el-icon-circle-check', + 'el-icon-circle-check-filled', + 'el-icon-circle-close', + 'el-icon-circle-close-filled', + 'el-icon-circle-plus', + 'el-icon-circle-plus-filled', + 'el-icon-clock', + 'el-icon-close', + 'el-icon-close-bold', + 'el-icon-cloudy', + 'el-icon-coffee', + 'el-icon-coffee-cup', + 'el-icon-coin', + 'el-icon-cold-drink', + 'el-icon-collection', + 'el-icon-collection-tag', + 'el-icon-comment', + 'el-icon-compass', + 'el-icon-connection', + 'el-icon-coordinate', + 'el-icon-copy-document', + 'el-icon-cpu', + 'el-icon-credit-card', + 'el-icon-crop', + 'el-icon-d-arrow-left', + 'el-icon-d-arrow-right', + 'el-icon-d-caret', + 'el-icon-data-analysis', + 'el-icon-data-board', + 'el-icon-data-line', + 'el-icon-delete', + 'el-icon-delete-filled', + 'el-icon-delete-location', + 'el-icon-dessert', + 'el-icon-discount', + 'el-icon-dish', + 'el-icon-dish-dot', + 'el-icon-document', + 'el-icon-document-add', + 'el-icon-document-checked', + 'el-icon-document-copy', + 'el-icon-document-delete', + 'el-icon-document-remove', + 'el-icon-download', + 'el-icon-drizzling', + 'el-icon-edit', + 'el-icon-edit-pen', + 'el-icon-eleme', + 'el-icon-eleme-filled', + 'el-icon-element-plus', + 'el-icon-expand', + 'el-icon-failed', + 'el-icon-female', + 'el-icon-files', + 'el-icon-film', + 'el-icon-filter', + 'el-icon-finished', + 'el-icon-first-aid-kit', + 'el-icon-flag', + 'el-icon-fold', + 'el-icon-folder', + 'el-icon-folder-add', + 'el-icon-folder-checked', + 'el-icon-folder-delete', + 'el-icon-folder-opened', + 'el-icon-folder-remove', + 'el-icon-food', + 'el-icon-football', + 'el-icon-fork-spoon', + 'el-icon-fries', + 'el-icon-full-screen', + 'el-icon-goblet', + 'el-icon-goblet-full', + 'el-icon-goblet-square', + 'el-icon-goblet-square-full', + 'el-icon-goods', + 'el-icon-goods-filled', + 'el-icon-grape', + 'el-icon-grid', + 'el-icon-guide', + 'el-icon-headset', + 'el-icon-help', + 'el-icon-help-filled', + 'el-icon-hide', + 'el-icon-histogram', + 'el-icon-home-filled', + 'el-icon-hot-water', + 'el-icon-house', + 'el-icon-ice-cream', + 'el-icon-ice-cream-round', + 'el-icon-ice-cream-square', + 'el-icon-ice-drink', + 'el-icon-ice-tea', + 'el-icon-info-filled', + 'el-icon-iphone', + 'el-icon-key', + 'el-icon-knife-fork', + 'el-icon-lightning', + 'el-icon-link', + 'el-icon-list', + 'el-icon-loading', + 'el-icon-location', + 'el-icon-location-filled', + 'el-icon-location-information', + 'el-icon-lock', + 'el-icon-lollipop', + 'el-icon-magic-stick', + 'el-icon-magnet', + 'el-icon-male', + 'el-icon-management', + 'el-icon-map-location', + 'el-icon-medal', + 'el-icon-menu', + 'el-icon-message', + 'el-icon-message-box', + 'el-icon-mic', + 'el-icon-microphone', + 'el-icon-milk-tea', + 'el-icon-minus', + 'el-icon-money', + 'el-icon-monitor', + 'el-icon-moon', + 'el-icon-moon-night', + 'el-icon-more', + 'el-icon-more-filled', + 'el-icon-mostly-cloudy', + 'el-icon-mouse', + 'el-icon-mug', + 'el-icon-mute', + 'el-icon-mute-notification', + 'el-icon-no-smoking', + 'el-icon-notebook', + 'el-icon-notification', + 'el-icon-odometer', + 'el-icon-office-building', + 'el-icon-open', + 'el-icon-operation', + 'el-icon-opportunity', + 'el-icon-orange', + 'el-icon-paperclip', + 'el-icon-partly-cloudy', + 'el-icon-pear', + 'el-icon-phone', + 'el-icon-phone-filled', + 'el-icon-picture', + 'el-icon-picture-filled', + 'el-icon-picture-rounded', + 'el-icon-pie-chart', + 'el-icon-place', + 'el-icon-platform', + 'el-icon-plus', + 'el-icon-pointer', + 'el-icon-position', + 'el-icon-postcard', + 'el-icon-pouring', + 'el-icon-present', + 'el-icon-price-tag', + 'el-icon-printer', + 'el-icon-promotion', + 'el-icon-question-filled', + 'el-icon-rank', + 'el-icon-reading', + 'el-icon-reading-lamp', + 'el-icon-refresh', + 'el-icon-refresh-left', + 'el-icon-refresh-right', + 'el-icon-refrigerator', + 'el-icon-remove', + 'el-icon-remove-filled', + 'el-icon-right', + 'el-icon-scale-to-original', + 'el-icon-school', + 'el-icon-scissor', + 'el-icon-search', + 'el-icon-select', + 'el-icon-sell', + 'el-icon-semi-select', + 'el-icon-service', + 'el-icon-set-up', + 'el-icon-setting', + 'el-icon-share', + 'el-icon-ship', + 'el-icon-shop', + 'el-icon-shopping-bag', + 'el-icon-shopping-cart', + 'el-icon-shopping-cart-full', + 'el-icon-smoking', + 'el-icon-soccer', + 'el-icon-sold-out', + 'el-icon-sort', + 'el-icon-sort-down', + 'el-icon-sort-up', + 'el-icon-stamp', + 'el-icon-star', + 'el-icon-star-filled', + 'el-icon-stopwatch', + 'el-icon-success-filled', + 'el-icon-sugar', + 'el-icon-suitcase', + 'el-icon-sunny', + 'el-icon-sunrise', + 'el-icon-sunset', + 'el-icon-switch', + 'el-icon-switch-button', + 'el-icon-takeaway-box', + 'el-icon-ticket', + 'el-icon-tickets', + 'el-icon-timer', + 'el-icon-toilet-paper', + 'el-icon-tools', + 'el-icon-top', + 'el-icon-top-left', + 'el-icon-top-right', + 'el-icon-trend-charts', + 'el-icon-trophy', + 'el-icon-turn-off', + 'el-icon-umbrella', + 'el-icon-unlock', + 'el-icon-upload', + 'el-icon-upload-filled', + 'el-icon-user', + 'el-icon-user-filled', + 'el-icon-van', + 'el-icon-video-camera', + 'el-icon-video-camera-filled', + 'el-icon-video-pause', + 'el-icon-video-play', + 'el-icon-view', + 'el-icon-wallet', + 'el-icon-wallet-filled', + 'el-icon-warning', + 'el-icon-warning-filled', + 'el-icon-watch', + 'el-icon-watermelon', + 'el-icon-wind-power', + 'el-icon-zoom-in', + 'el-icon-zoom-out', + ], + }, + { + name: '扩展', + icons: [ + 'sc-icon-vue', + 'sc-icon-code', + 'sc-icon-wechat', + 'sc-icon-bug-fill', + 'sc-icon-bug-line', + 'sc-icon-file-word', + 'sc-icon-file-excel', + 'sc-icon-file-ppt', + 'sc-icon-organization', + 'sc-icon-upload', + 'sc-icon-download', + ], + }, + ], +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/index.js b/src/frontend/admin/src/config/index.js new file mode 100644 index 00000000..b1870e35 --- /dev/null +++ b/src/frontend/admin/src/config/index.js @@ -0,0 +1,81 @@ +import MY_CONFIG from './myConfig' + +const DEFAULT_CONFIG = { + //标题 + APP_NAME: 'SCUI', + + //首页地址 + DASHBOARD_URL: '/home', + + //版本号 + APP_VER: '1.6.9', + + //内核版本号 + CORE_VER: '1.6.9', + + //接口地址 + API_URL: 'http://localhost:65010', + + //请求超时 + TIMEOUT: 10000, + + //TokenName + TOKEN_NAME: 'Authorization', + + //Token前缀,注意最后有个空格,如不需要需设置空字符串 + TOKEN_PREFIX: 'Bearer ', + + //追加其他头 + HEADERS: {}, + + //请求是否开启缓存 + REQUEST_CACHE: false, + + //布局 默认:default | 通栏:header | 经典:menu | 功能坞:dock + //dock将关闭标签和面包屑栏 + LAYOUT: 'menu', + + //菜单是否折叠 + MENU_IS_COLLAPSE: false, + + //菜单是否启用手风琴效果 + MENU_UNIQUE_OPENED: false, + + //是否开启多标签 + LAYOUT_TAGS: true, + + //语言 + LANG: 'zh-cn', + + //主题颜色 + COLOR: '', + + //是否加密localStorage, 为空不加密,可填写AES(模式ECB,移位Pkcs7)加密 + LS_ENCRYPTION: '', + + //localStorageAES加密秘钥,位数建议填写8的倍数 + LS_ENCRYPTION_key: '2XNN4K8LC0ELVWN4', + + //控制台首页默认布局 + DEFAULT_GRID: { + //默认分栏数量和宽度 例如 [24] [18,6] [8,8,8] [6,12,6] + layout: [12, 6, 6], + //小组件分布,com取值:views/home/components 文件名 + copmsList: [['welcome'], ['about', 'ver'], ['time', 'progress']], + }, + + //默认头像 + DEFAULT_AVATAR: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAflJREFUeNqs1u1P2kAYAHB6B+21UmZbatEAki2+MKIR42TGaHRLjBr/Yj/7wWRb3If5gjHbfIlBjIqCUCq0PmaJLqG9IwdP+qV3vV+v1/Z5Ttg/Ke39tm+q7VD/wlBx/j0J7xzWbccL9TVgosCivrv/Atgw8yI9JuZGVXNQjCkROL2tOpc39q8/D7bj0gcy6NSQvDoTR4LwdidVhOPDyMD29/Jd9YkyFlH6pAhanjb+d19DFvHSlOHX0x09kYpGcOAFMPf0kMxJJ02ZvlyWRjhpWcJ0moiIk240Gf9Rw2lz0o92i04/Nnhpl/Hhhtqux0mnLcZrzCQUTrrV9lh/M++CFM9rtOXyvL+lOif98+T++r4Z1Ht0Vju9anDSEKXbQBqSFH0sgz6+qMGDd7Y/1J96pav1FuTPzvZvxYrrej3REOWK09l4XWkyB7Jp30RBRNwH2jf/MZMimzZi/kk5l1HFMOKnFYK/zMaDqsxqPo6QwENDtd2YtwakwOI5rJO1OZOS0/3p8VR0s2CpMqMoJzSytWAldKmrig7cQk4fMUiX+w14rPVPVvGi9qNYcVpuIP1xVM2PvaOU2sACnYwmTbJ7cHdefssqSJFeXkUYCysz8flJjcN9nf7XvFnIahi/gMCiwphMROFzVstYSu/7sWxaXczpAAL7LMAA6FWV/DBrhrIAAAAASUVORK5CYII=', +} + +//合并业务配置 +Object.assign(DEFAULT_CONFIG, MY_CONFIG) + +// 如果生产模式,就合并动态的APP_CONFIG +// public/config.js +if (process.env.NODE_ENV === 'production') { + Object.assign(DEFAULT_CONFIG, APP_CONFIG) +} + +export default DEFAULT_CONFIG \ No newline at end of file diff --git a/src/frontend/admin/src/config/myConfig.js b/src/frontend/admin/src/config/myConfig.js new file mode 100644 index 00000000..26304a0e --- /dev/null +++ b/src/frontend/admin/src/config/myConfig.js @@ -0,0 +1,10 @@ +//业务配置 +//会合并至this.$CONFIG +//生产模式 public/config.js 同名key会覆盖这里的配置从而实现打包后的热更新 +//为避免和SCUI框架配置混淆建议添加前缀 MY_ +//全局可使用 this.$CONFIG.MY_KEY 访问 + +export default { + //是否显示第三方授权登录 + MY_SHOW_LOGIN_OAUTH: true, +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/naColOperation.js b/src/frontend/admin/src/config/naColOperation.js new file mode 100644 index 00000000..9ed8f9d2 --- /dev/null +++ b/src/frontend/admin/src/config/naColOperation.js @@ -0,0 +1,24 @@ +export default { + buttons: [ + { + icon: 'el-icon-view', + click: async (row, vue) => { + vue.loading = true + vue.dialog.save = true + await vue.$nextTick() + vue.$refs.saveDialog.open('view', row) + vue.loading = false + }, + }, + { + icon: 'el-icon-edit', + click: async (row, vue) => { + vue.loading = true + vue.dialog.save = true + await vue.$nextTick() + vue.$refs.saveDialog.open('edit', row) + vue.loading = false + }, + }, + ], +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/naFormEmail.js b/src/frontend/admin/src/config/naFormEmail.js new file mode 100644 index 00000000..ae65df19 --- /dev/null +++ b/src/frontend/admin/src/config/naFormEmail.js @@ -0,0 +1,35 @@ +export default { + email: (_this) => { + return { + required: true, + message: '您的邮箱地址', + pattern: _this.$GLOBAL.chars.RGX_EMAIL, + } + }, + emailNoUsed: (_this, id) => { + return { + validator: async (rule, valueEquals, callback) => { + try { + const res = await _this.$API.sys_user.checkEmailAvailable.post({ + email: valueEquals, + id: id(), + }) + if (res.data) { + return callback() + } + } catch { + // + } + callback(new Error('邮箱已被使用')) + }, + trigger: 'blur', + } + }, + + code: () => { + return { + required: true, + message: '请输入4位数字验证码', + } + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/naFormPassword.js b/src/frontend/admin/src/config/naFormPassword.js new file mode 100644 index 00000000..ee4a9dfd --- /dev/null +++ b/src/frontend/admin/src/config/naFormPassword.js @@ -0,0 +1,22 @@ +export default { + passwordText: (_this) => { + return { + required: true, + message: '8位以上数字字母组合', + pattern: _this.$GLOBAL.chars.RGX_PASSWORD, + } + }, + + passwordText2: (passwordText) => [ + { required: true, message: '请再次输入密码' }, + { + validator: (rule, value, callback) => { + if (value !== passwordText()) { + callback(new Error('两次输入密码不一致')) + } else { + callback() + } + }, + }, + ], +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/naFormPhone.js b/src/frontend/admin/src/config/naFormPhone.js new file mode 100644 index 00000000..317f6409 --- /dev/null +++ b/src/frontend/admin/src/config/naFormPhone.js @@ -0,0 +1,35 @@ +export default { + mobile: (_this) => { + return { + required: true, + message: '您的手机号码', + pattern: _this.$GLOBAL.chars.RGX_MOBILE, + } + }, + mobileNoUsed: (_this, id) => { + return { + validator: async (rule, valueEquals, callback) => { + try { + const res = await _this.$API.sys_user.checkMobileAvailable.post({ + mobile: valueEquals, + id: id(), + }) + if (res.data) { + return callback() + } + } catch { + // + } + callback(new Error('手机号已被使用')) + }, + trigger: 'blur', + } + }, + + code: () => { + return { + required: true, + message: '请输入4位数字验证码', + } + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/route.js b/src/frontend/admin/src/config/route.js new file mode 100644 index 00000000..a5d5a201 --- /dev/null +++ b/src/frontend/admin/src/config/route.js @@ -0,0 +1,31 @@ +// 静态路由配置 +// 书写格式与动态路由格式一致,全部经由框架统一转换 +// 比较动态路由在meta中多加入了role角色权限,为数组类型。一个菜单是否有权限显示,取决于它以及后代菜单是否有权限。 +// routes 显示在左侧菜单中的路由(显示顺序在动态路由之前) +// 示例如下 + +// const routes = [ +// { +// name: "demo", +// path: "/demo", +// meta: { +// icon: "el-icon-eleme-filled", +// title: "演示", +// role: ["SA"] +// }, +// children: [{ +// name: "demopage", +// path: "/demopage", +// component: "test/autocode/index", +// meta: { +// icon: "el-icon-menu", +// title: "演示页面", +// role: ["SA"] +// } +// }] +// } +// ] + +const routes = [] + +export default routes \ No newline at end of file diff --git a/src/frontend/admin/src/config/select.js b/src/frontend/admin/src/config/select.js new file mode 100644 index 00000000..7e6f880b --- /dev/null +++ b/src/frontend/admin/src/config/select.js @@ -0,0 +1,19 @@ +//字典选择器配置 + +export default { + dicApiObj: null, //获取字典接口对象 + parseData: function (res) { + return { + data: res.data, //分析行数据字段结构 + msg: res.msg, //分析描述字段结构 + code: res.code, //分析状态字段结构 + } + }, + request: { + name: 'name', //规定搜索字段 + }, + props: { + label: 'label', //映射label显示字段 + value: 'value', //映射value值字段 + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/table.js b/src/frontend/admin/src/config/table.js new file mode 100644 index 00000000..9d241118 --- /dev/null +++ b/src/frontend/admin/src/config/table.js @@ -0,0 +1,95 @@ +//数据表格配置 + +import tool from '@/utils/tool' + +export default { + successCode: 'succeed', //请求完成代码 + pageSize: 20, //表格每一页条数 + pageSizes: [10, 20, 30, 40, 50], //表格可设置的一页条数 + paginationLayout: 'total, sizes, prev, pager, next, jumper', //表格分页布局,可设置"total, sizes, prev, pager, next, jumper" + parseData: function (res) { + //数据分析 + return { + data: res.data, //分析无分页的数据字段结构 + rows: res.data.rows, //分析行数据字段结构 + total: res.data.total, //分析总数字段结构 + summary: res.data.summary, //分析合计行字段结构 + msg: res.msg, //分析描述字段结构 + code: res.code, //分析状态字段结构 + } + }, + request: { + //请求规定字段 + page: 'page', //规定当前分页字段 + pageSize: 'pageSize', //规定一页条数字段 + prop: 'prop', //规定排序字段名字段 + order: 'order', //规定排序规格字段 + }, + /** + * 自定义列保存处理 + * @tableName scTable组件的props->tableName + * @column 用户配置好的列 + */ + columnSettingSave: function (tableName, column) { + return new Promise((resolve) => { + setTimeout(() => { + //这里为了演示使用了session和setTimeout演示,开发时应用数据请求 + tool.session.set(tableName, column) + resolve(true) + }, 1000) + }) + }, + /** + * 获取自定义列 + * @tableName scTable组件的props->tableName + * @column 组件接受到的props->column + */ + columnSettingGet: function (tableName, column) { + return new Promise((resolve) => { + //这里为了演示使用了session和setTimeout演示,开发时应用数据请求 + const userColumn = tool.session.get(tableName) + if (userColumn) { + resolve(userColumn) + } else { + resolve(column) + } + }) + }, + /** + * 重置自定义列 + * @tableName scTable组件的props->tableName + * @column 组件接受到的props->column + */ + columnSettingReset: function (tableName, column) { + return new Promise((resolve) => { + //这里为了演示使用了session和setTimeout演示,开发时应用数据请求 + setTimeout(() => { + tool.session.remove(tableName) + resolve(column) + }, 1000) + }) + }, + handleUpdate: function (table, data, mode) { + if (mode === 'add') { + table.upData() + } else if (mode === 'edit') { + function func(items) { + items.forEach((item) => { + if (item.id === data.id) { + Object.keys(item).forEach((x) => delete item[x]) + Object.assign(item, data) + } else if (item.children) return func(item.children) + }) + } + + func(table.tableData) + + // table.tableData + // .filter((item) => item.id === data.id) + // .forEach((item) => { + // Object.keys(item).forEach((x) => delete item[x]) + // Object.assign(item, data) + // }) + } + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/tableSelect.js b/src/frontend/admin/src/config/tableSelect.js new file mode 100644 index 00000000..149cd20c --- /dev/null +++ b/src/frontend/admin/src/config/tableSelect.js @@ -0,0 +1,23 @@ +//表格选择器配置 + +export default { + pageSize: 20, //表格每一页条数 + parseData: function (res) { + return { + data: res.data, + rows: res.data.rows, //分析行数据字段结构 + total: res.data.total, //分析总数字段结构 + msg: res.message, //分析描述字段结构 + code: res.code, //分析状态字段结构 + } + }, + request: { + page: 'page', //规定当前分页字段 + pageSize: 'pageSize', //规定一页条数字段 + keyword: 'keyword', //规定搜索字段 + }, + props: { + label: 'label', //映射label显示字段 + value: 'value', //映射value值字段 + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/upload.js b/src/frontend/admin/src/config/upload.js new file mode 100644 index 00000000..60cb3857 --- /dev/null +++ b/src/frontend/admin/src/config/upload.js @@ -0,0 +1,20 @@ +import API from '@/api' + +//上传配置 + +export default { + apiObj: API.sys_file.upload, //上传请求API对象 + filename: 'file', //form请求时文件的key + successCode: 'succeed', //请求完成代码 + maxSize: 10, //最大文件大小 默认10MB + parseData: function (res) { + return { + code: res.code, //分析状态字段结构 + // fileName: null, //分析文件名称 + src: res.data, //分析图片远程地址结构 + msg: res.msg, //分析描述字段结构 + } + }, + apiObjFile: API.sys_file.upload, //附件上传请求API对象 + maxSizeFile: 10, //最大文件大小 默认10MB +} \ No newline at end of file diff --git a/src/frontend/admin/src/config/workflow.js b/src/frontend/admin/src/config/workflow.js new file mode 100644 index 00000000..aad283c3 --- /dev/null +++ b/src/frontend/admin/src/config/workflow.js @@ -0,0 +1,69 @@ +import API from '@/api' + +//审批工作流人员/组织选择器配置 + +export default { + //配置接口正常返回代码 + successCode: 200, + //配置组织 + group: { + //请求接口对象 + apiObj: API.system.dept.list, + //接受数据字段映射 + parseData: function (res) { + return { + rows: res.data, + msg: res.message, + code: res.code, + } + }, + //显示数据字段映射 + props: { + key: 'id', + label: 'label', + children: 'children', + }, + }, + //配置用户 + user: { + apiObj: API.demo.page, + pageSize: 20, + parseData: function (res) { + return { + rows: res.data.rows, + total: res.data.total, + msg: res.message, + code: res.code, + } + }, + props: { + key: 'id', + label: 'user', + }, + request: { + page: 'page', + pageSize: 'pageSize', + groupId: 'groupId', + keyword: 'keyword', + }, + }, + //配置角色 + role: { + //请求接口对象 + apiObj: API.system.dept.list, + //接受数据字段映射 + parseData: function (res) { + return { + rows: res.data, + msg: res.message, + code: res.code, + } + }, + //显示数据字段映射 + props: { + key: 'id', + label: 'label', + children: 'children', + }, + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/directives/auth.js b/src/frontend/admin/src/directives/auth.js new file mode 100644 index 00000000..7b415ac2 --- /dev/null +++ b/src/frontend/admin/src/directives/auth.js @@ -0,0 +1,18 @@ +import { permissionAll } from '@/utils/permission' +import tool from '@/utils/tool' + +/** + * 用户权限指令 + * @directive 单个权限验证(v-auth="'xxx'") + * @directive 多个权限验证,满足一个则显示(v-auths="['xxx','xxx']") + * @directive 多个权限验证,全部满足则显示(v-auths-all="['xxx','xxx']") + */ +export default { + mounted(el, binding) { + if (permissionAll()) { + return + } + let permissions = tool.data.get('PERMISSIONS') + if (!permissions.some((v) => v === binding.value)) el.parentNode.removeChild(el) + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/directives/auths.js b/src/frontend/admin/src/directives/auths.js new file mode 100644 index 00000000..6f70e5ca --- /dev/null +++ b/src/frontend/admin/src/directives/auths.js @@ -0,0 +1,24 @@ +import { permissionAll } from '@/utils/permission' +import tool from '@/utils/tool' + +/** + * 用户权限指令 + * @directive 单个权限验证(v-auth="'xxx'") + * @directive 多个权限验证,满足一个则显示(v-auths="['xxx','xxx']") + * @directive 多个权限验证,全部满足则显示(v-auths-all="['xxx','xxx']") + */ +export default { + mounted(el, binding) { + if (permissionAll()) { + return + } + let permissions = tool.data.get('PERMISSIONS') + let flag = false + permissions.map((val) => { + binding.value.map((v) => { + if (val === v) flag = true + }) + }) + if (!flag) el.parentNode.removeChild(el) + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/directives/authsAll.js b/src/frontend/admin/src/directives/authsAll.js new file mode 100644 index 00000000..cd641cb4 --- /dev/null +++ b/src/frontend/admin/src/directives/authsAll.js @@ -0,0 +1,19 @@ +import { judementSameArr, permissionAll } from '@/utils/permission' +import tool from '@/utils/tool' + +/** + * 用户权限指令 + * @directive 单个权限验证(v-auth="'xxx'") + * @directive 多个权限验证,满足一个则显示(v-auths="['xxx','xxx']") + * @directive 多个权限验证,全部满足则显示(v-auths-all="['xxx','xxx']") + */ +export default { + mounted(el, binding) { + if (permissionAll()) { + return + } + let permissions = tool.data.get('PERMISSIONS') + const flag = judementSameArr(binding.value, permissions) + if (!flag) el.parentNode.removeChild(el) + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/directives/copy.js b/src/frontend/admin/src/directives/copy.js new file mode 100644 index 00000000..a43ba017 --- /dev/null +++ b/src/frontend/admin/src/directives/copy.js @@ -0,0 +1,29 @@ +import { ElMessage } from 'element-plus' + +export default { + mounted(el, binding) { + el.$value = binding.value + el.handler = () => { + const textarea = document.createElement('textarea') + textarea.readOnly = 'readonly' + textarea.style.position = 'absolute' + textarea.style.left = '-9999px' + textarea.value = el.$value + document.body.appendChild(textarea) + textarea.select() + textarea.setSelectionRange(0, textarea.value.length) + const result = document.execCommand('Copy') + if (result) { + ElMessage.success('复制成功') + } + document.body.removeChild(textarea) + } + el.addEventListener('click', el.handler) + }, + updated(el, binding) { + el.$value = binding.value + }, + unmounted(el) { + el.removeEventListener('click', el.handler) + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/directives/role.js b/src/frontend/admin/src/directives/role.js new file mode 100644 index 00000000..80b3c8a3 --- /dev/null +++ b/src/frontend/admin/src/directives/role.js @@ -0,0 +1,22 @@ +import { rolePermission } from '@/utils/permission' + +export default { + mounted(el, binding) { + const { value } = binding + if (Array.isArray(value)) { + let ishas = false + value.forEach((item) => { + if (rolePermission(item)) { + ishas = true + } + }) + if (!ishas) { + el.parentNode.removeChild(el) + } + } else { + if (!rolePermission(value)) { + el.parentNode.removeChild(el) + } + } + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/directives/time.js b/src/frontend/admin/src/directives/time.js new file mode 100644 index 00000000..a91d8f3d --- /dev/null +++ b/src/frontend/admin/src/directives/time.js @@ -0,0 +1,79 @@ +import tool from '@/utils/tool' + +var Time = { + //获取当前时间戳 + getUnix: function () { + var date = new Date() + return date.getTime() + }, + //获取今天0点0分0秒的时间戳 + getTodayUnix: function () { + var date = new Date() + date.setHours(0) + date.setMinutes(0) + date.setSeconds(0) + date.setMilliseconds(0) + return date.getTime() + }, + //获取今年1月1日0点0秒的时间戳 + getYearUnix: function () { + var date = new Date() + date.setMonth(0) + date.setDate(1) + date.setHours(0) + date.setMinutes(0) + date.setSeconds(0) + date.setMilliseconds(0) + return date.getTime() + }, + //获取标准年月日 + getLastDate: function (time) { + var date = new Date(time) + var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 + var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() + return date.getFullYear() + '-' + month + '-' + day + }, + //转换时间 + getFormateTime: function (timestamp) { + timestamp = new Date(timestamp) + var now = this.getUnix() + var today = this.getTodayUnix() + //var year = this.getYearUnix(); + var timer = (now - timestamp) / 1000 + var tip = '' + + if (timer <= 0) { + tip = '刚刚' + } else if (Math.floor(timer / 60) <= 0) { + tip = '刚刚' + } else if (timer < 3600) { + tip = Math.floor(timer / 60) + '分钟前' + } else if (timer >= 3600 && timestamp - today >= 0) { + tip = Math.floor(timer / 3600) + '小时前' + } else if (timer / 86400 <= 31) { + tip = Math.ceil(timer / 86400) + '天前' + } else { + tip = this.getLastDate(timestamp) + } + return tip + }, +} + +export default (el, binding) => { + let { value, modifiers } = binding + if (!value) { + return false + } + if (value.toString().length === 10) { + value = value * 1000 + } + if (modifiers.tip) { + el.innerHTML = Time.getFormateTime(value) + el.__timeout__ = setInterval(() => { + el.innerHTML = Time.getFormateTime(value) + }, 60000) + } else { + const format = el.getAttribute('format') || undefined + el.innerHTML = tool.dateFormat(value, format) + } +} \ No newline at end of file diff --git a/src/frontend/admin/src/layout/components/NavMenu.vue b/src/frontend/admin/src/layout/components/NavMenu.vue new file mode 100644 index 00000000..3315b1ff --- /dev/null +++ b/src/frontend/admin/src/layout/components/NavMenu.vue @@ -0,0 +1,42 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/layout/components/iframeView.vue b/src/frontend/admin/src/layout/components/iframeView.vue new file mode 100644 index 00000000..f986a45c --- /dev/null +++ b/src/frontend/admin/src/layout/components/iframeView.vue @@ -0,0 +1,77 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/layout/components/search.vue b/src/frontend/admin/src/layout/components/search.vue new file mode 100644 index 00000000..2a069011 --- /dev/null +++ b/src/frontend/admin/src/layout/components/search.vue @@ -0,0 +1,192 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/layout/components/setting.vue b/src/frontend/admin/src/layout/components/setting.vue new file mode 100644 index 00000000..ce4aff03 --- /dev/null +++ b/src/frontend/admin/src/layout/components/setting.vue @@ -0,0 +1,96 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/layout/components/sideM.vue b/src/frontend/admin/src/layout/components/sideM.vue new file mode 100644 index 00000000..9048980c --- /dev/null +++ b/src/frontend/admin/src/layout/components/sideM.vue @@ -0,0 +1,182 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/layout/components/tags.vue b/src/frontend/admin/src/layout/components/tags.vue new file mode 100644 index 00000000..69cdf6cb --- /dev/null +++ b/src/frontend/admin/src/layout/components/tags.vue @@ -0,0 +1,346 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/layout/components/tasks.vue b/src/frontend/admin/src/layout/components/tasks.vue new file mode 100644 index 00000000..2419b8f4 --- /dev/null +++ b/src/frontend/admin/src/layout/components/tasks.vue @@ -0,0 +1,130 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/layout/components/topbar.vue b/src/frontend/admin/src/layout/components/topbar.vue new file mode 100644 index 00000000..2895f013 --- /dev/null +++ b/src/frontend/admin/src/layout/components/topbar.vue @@ -0,0 +1,73 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/layout/components/userbar.vue b/src/frontend/admin/src/layout/components/userbar.vue new file mode 100644 index 00000000..59c06d9d --- /dev/null +++ b/src/frontend/admin/src/layout/components/userbar.vue @@ -0,0 +1,296 @@ + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/layout/index.vue b/src/frontend/admin/src/layout/index.vue new file mode 100644 index 00000000..04c41fac --- /dev/null +++ b/src/frontend/admin/src/layout/index.vue @@ -0,0 +1,334 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/layout/other/404.vue b/src/frontend/admin/src/layout/other/404.vue new file mode 100644 index 00000000..4ca4e464 --- /dev/null +++ b/src/frontend/admin/src/layout/other/404.vue @@ -0,0 +1,77 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/layout/other/autoExit.js b/src/frontend/admin/src/layout/other/autoExit.js new file mode 100644 index 00000000..e31cef55 --- /dev/null +++ b/src/frontend/admin/src/layout/other/autoExit.js @@ -0,0 +1,49 @@ +export default { + render() {}, + data() { + return { + logoutCount: this.$TOOL.data.get('AUTO_EXIT'), + } + }, + mounted() { + if (this.logoutCount) { + this.setNewAutoExitTime() + document.onclick = () => { + this.setNewAutoExitTime() + } + document.onmousemove = () => { + this.setNewAutoExitTime() + } + document.onkeydown = () => { + this.setNewAutoExitTime() + } + document.onscroll = () => { + this.setNewAutoExitTime() + } + window.autoExitTimer = window.setInterval(this.autoExitfun, 1000) + } + }, + unmounted() { + if (this.logoutCount) { + clearInterval(window.autoExitTimer) + window.autoExitTimer = null + } + }, + methods: { + setNewAutoExitTime() { + window.autoExitTime = new Date().getTime() + }, + autoExitfun() { + if (new Date().getTime() - window.autoExitTime > this.logoutCount * 60 * 1000) { + clearInterval(window.autoExitTimer) + window.autoExitTimer = null + this.$router.replace({ path: '/anonymous/login' }) + this.$alert('用户长时间无操作,为保证账户安全,系统已自动登出。', '提示', { + type: 'warning', + center: true, + roundButton: true, + }) + } + }, + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/layout/other/empty.vue b/src/frontend/admin/src/layout/other/empty.vue new file mode 100644 index 00000000..e3bc8ac8 --- /dev/null +++ b/src/frontend/admin/src/layout/other/empty.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/frontend/admin/src/locales/index.js b/src/frontend/admin/src/locales/index.js new file mode 100644 index 00000000..a8654de2 --- /dev/null +++ b/src/frontend/admin/src/locales/index.js @@ -0,0 +1,28 @@ +import sysConfig from '@/config' +import tool from '@/utils/tool' +import { createI18n } from 'vue-i18n' +import el_zh_cn from 'element-plus/es/locale/lang/zh-cn' +import el_en from 'element-plus/es/locale/lang/en' + +import zh_cn from './lang/zh-cn.js' +import en from './lang/en.js' + +const messages = { + 'zh-cn': { + el: el_zh_cn, + ...zh_cn, + }, + en: { + el: el_en, + ...en, + }, +} + +const i18n = createI18n({ + locale: tool.data.get('APP_LANG') || sysConfig.LANG, + fallbackLocale: 'zh-cn', + globalInjection: true, + messages, +}) + +export default i18n \ No newline at end of file diff --git a/src/frontend/admin/src/locales/lang/en.js b/src/frontend/admin/src/locales/lang/en.js new file mode 100644 index 00000000..63b277be --- /dev/null +++ b/src/frontend/admin/src/locales/lang/en.js @@ -0,0 +1,39 @@ +export default { + login: { + slogan: 'High performance / delicate / grace', + describe: 'Vue3 + element plus based front-end solutions in the background.', + signInTitle: 'Sign in', + accountLogin: 'Account sign in', + mobileLogin: 'Mobile sign in', + rememberMe: 'Remember me', + forgetPassword: 'Forget password', + signIn: 'Sign in', + signInOther: 'Sign in with', + userPlaceholder: 'user / phone / email', + userError: 'Please input a user name', + PWPlaceholder: 'Please input a password', + PWError: 'Please input a password', + admin: 'Administrator', + user: 'User', + mobilePlaceholder: 'Mobile', + mobileError: 'Please input mobile', + smsPlaceholder: 'SMS Code', + smsError: 'Please input sms code', + smsGet: 'Get SMS Code', + smsSent: 'SMS sent to mobile number', + noAccount: 'No account?', + createAccount: 'Create a new account', + wechatLoginTitle: 'QR code sign in', + wechatLoginMsg: 'Please use wechat to scan and log in | Auto scan after 3 seconds of simulation', + wechatLoginResult: 'Scanned | Please click authorize login in the device', + }, + user: { + dynamic: 'Dynamic', + info: 'User Info', + settings: 'Settings', + nightmode: 'night mode', + nightmode_msg: 'Suitable for low light environment,The current night mode is beta', + language: 'language', + language_msg: 'Translation in progress,Temporarily translated the text of this view', + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/locales/lang/zh-cn.js b/src/frontend/admin/src/locales/lang/zh-cn.js new file mode 100644 index 00000000..9023963f --- /dev/null +++ b/src/frontend/admin/src/locales/lang/zh-cn.js @@ -0,0 +1,39 @@ +export default { + login: { + slogan: '高性能 / 精致 / 优雅', + describe: '基于Vue3 + Element-Plus 的中后台前端解决方案。', + signInTitle: '用户登录', + accountLogin: '账号登录', + mobileLogin: '手机号登录', + rememberMe: '24小时免登录', + forgetPassword: '忘记密码', + signIn: '登录', + signInOther: '其他登录方式', + userPlaceholder: '用户名 / 手机 / 邮箱', + userError: '请输入用户名', + PWPlaceholder: '请输入密码', + PWError: '请输入密码', + admin: '管理员', + user: '用户', + mobilePlaceholder: '手机号码', + mobileError: '请输入手机号码', + smsPlaceholder: '短信验证码', + smsError: '请输入短信验证码', + smsGet: '获取验证码', + smsSent: '已发送短信至手机号码', + noAccount: '还没有账号?', + createAccount: '创建新账号', + wechatLoginTitle: '二维码登录', + wechatLoginMsg: '请使用微信扫一扫登录 | 模拟3秒后自动扫描', + wechatLoginResult: '已扫描 | 请在设备中点击授权登录', + }, + user: { + dynamic: '近期动态', + info: '个人信息', + settings: '设置', + nightmode: '黑夜模式', + nightmode_msg: '适合光线较弱的环境,当前黑暗模式为beta版本', + language: '语言', + language_msg: '翻译进行中,暂翻译了本视图的文本', + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/main.js b/src/frontend/admin/src/main.js new file mode 100644 index 00000000..c5e91fbb --- /dev/null +++ b/src/frontend/admin/src/main.js @@ -0,0 +1,22 @@ +import { createApp } from 'vue' +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' +import 'element-plus/theme-chalk/display.css' +import scui from './scui' +import i18n from './locales' +import router from './router' +import store from './store' +import App from './App.vue' +import preload from '@/utils/preload' + +const app = createApp(App) +app.use(ElementPlus) +app.use(store) +app.use(i18n) +app.use(scui) + +preload.install(app).then(() => { + app.use(router) + //挂载app + app.mount('#app') +}) \ No newline at end of file diff --git a/src/frontend/admin/src/router/index.js b/src/frontend/admin/src/router/index.js new file mode 100644 index 00000000..75bbb0f3 --- /dev/null +++ b/src/frontend/admin/src/router/index.js @@ -0,0 +1,192 @@ +import { createRouter, createWebHashHistory } from 'vue-router' +import { ElNotification } from 'element-plus' +import config from '@/config' +import NProgress from 'nprogress' +import 'nprogress/nprogress.css' +import tool from '@/utils/tool' +import systemRouter from './systemRouter' +import userRoutes from '@/config/route' +import { afterEach, beforeEach } from './scrollBehavior' + +// 匹配views里面所有的.vue文件 +const modules = import.meta.glob('./../views/**/*.vue') +const otherModules = { + 404: () => import('../layout/other/404.vue'), + empty: () => import('../layout/other/empty.vue'), +} + +//系统路由 +const routes = systemRouter + +//系统特殊路由 +const routes_404 = { + path: '/:pathMatch(.*)*', + hidden: true, + component: otherModules['404'], +} +let routes_404_r = () => {} + +const router = createRouter({ + history: createWebHashHistory(), + routes: routes, +}) + +//设置标题 +document.title = config.APP_NAME + +//判断是否已加载过动态/静态路由 +let isGetRouter = false + +router.beforeEach(async (to, from, next) => { + NProgress.start() + //动态标题 + document.title = to.meta.title ? `${to.meta.title} - ${config.APP_NAME}` : `${config.APP_NAME}` + + let token = tool.cookie.get('ACCESS-TOKEN') || tool.cookie.get('X-ACCESS-TOKEN') + + if (to.path === '/anonymous/login') { + //删除路由(替换当前layout路由) + router.addRoute(routes[0]) + //删除路由(404) + routes_404_r() + isGetRouter = false + next() + return false + } + + if (routes.findIndex((r) => r.path === to.path) >= 0) { + next() + return false + } + + //整页路由处理 + if (to.meta.fullpage) { + to.matched = [to.matched[to.matched.length - 1]] + } + //加载动态/静态路由 + + if (!isGetRouter) { + let userMenu = treeFilter(userRoutes, (node) => { + return node.meta.role + ? node.meta.role.filter((item) => router.app.config.globalProperties.$GLOBAL.user.role.indexOf(item) > -1).length > 0 + : true + }) + let menu = [...userMenu, ...(router.app.config.globalProperties.$GLOBAL.menu || [])] + let menuRouter = filterAsyncRouter(menu) + menuRouter = flatAsyncRoutes(menuRouter) + menuRouter.forEach((item) => { + router.addRoute('layout', item) + }) + routes_404_r = router.addRoute(routes_404) + + if (to.matched.length === 0) { + await router.push(to.fullPath) + } + isGetRouter = true + } + beforeEach(to, from) + next() +}) + +router.afterEach((to, from) => { + afterEach(to, from) + NProgress.done() +}) + +router.onError((error) => { + NProgress.done() + ElNotification.error({ + title: '路由错误', + message: error.message, + }) +}) + +//入侵追加自定义方法、对象 +router.sc_getMenu = () => { + const apiMenu = router.app.config.globalProperties.$GLOBAL.menu || [] + const userInfo = router.app.config.globalProperties.$GLOBAL.user + const userMenu = treeFilter(userRoutes, (node) => { + return node.meta.role ? node.meta.role.filter((item) => userInfo.role.indexOf(item) > -1).length > 0 : true + }) + return [...userMenu, ...apiMenu] +} + +//转换 +function filterAsyncRouter(routerMap) { + const accessedRouters = [] + routerMap.forEach((item) => { + item.meta = item.meta ? item.meta : {} + //处理外部链接特殊路由 + if (item.meta.type === 'iframe') { + item.meta.url = item.path + item.path = `/i/${item.name}` + } + //MAP转路由对象 + const route = { + path: item.path, + name: item.name, + meta: item.meta, + redirect: item.redirect, + children: item.children ? filterAsyncRouter(item.children) : null, + component: loadComponent(item.component), + } + accessedRouters.push(route) + }) + return accessedRouters +} + +function loadComponent(component) { + if (component) { + for (const path in modules) { + const dir = path.split('views/')[1].split('.vue')[0] + if (dir === component || dir === component + '/index') { + return () => modules[path]() + } + } + } + return otherModules['empty'] +} + +//路由扁平化 +function flatAsyncRoutes(routes, breadcrumb = []) { + let res = [] + routes.forEach((route) => { + const tmp = { ...route } + if (tmp.children) { + let childrenBreadcrumb = [...breadcrumb] + childrenBreadcrumb.push(route) + let tmpRoute = { ...route } + tmpRoute.meta.breadcrumb = childrenBreadcrumb + delete tmpRoute.children + res.push(tmpRoute) + let childrenRoutes = flatAsyncRoutes(tmp.children, childrenBreadcrumb) + childrenRoutes.map((item) => { + res.push(item) + }) + } else { + let tmpBreadcrumb = [...breadcrumb] + tmpBreadcrumb.push(tmp) + tmp.meta.breadcrumb = tmpBreadcrumb + res.push(tmp) + } + }) + return res +} + +//过滤树 +function treeFilter(tree, func) { + return tree + .map((node) => ({ ...node })) + .filter((node) => { + node.children = node.children && treeFilter(node.children, func) + return func(node) || (node.children && node.children.length) + }) +} + +export default { + ...router, + install(app) { + router.install(app) + router.app = app + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/router/scrollBehavior.js b/src/frontend/admin/src/router/scrollBehavior.js new file mode 100644 index 00000000..f3a522dc --- /dev/null +++ b/src/frontend/admin/src/router/scrollBehavior.js @@ -0,0 +1,26 @@ +import store from '@/store' +import { nextTick } from 'vue' + +export function beforeEach(to, from) { + var adminMain = document.querySelector('#adminui-main') + if (!adminMain) { + return false + } + store.commit('updateViewTags', { + fullPath: from.fullPath, + scrollTop: adminMain.scrollTop, + }) +} + +export function afterEach(to) { + var adminMain = document.querySelector('#adminui-main') + if (!adminMain) { + return false + } + nextTick(() => { + var beforeRoute = store.state.viewTags.viewTags.filter((v) => v.fullPath === to.fullPath)[0] + if (beforeRoute) { + adminMain.scrollTop = beforeRoute.scrollTop || 0 + } + }) +} \ No newline at end of file diff --git a/src/frontend/admin/src/router/systemRouter.js b/src/frontend/admin/src/router/systemRouter.js new file mode 100644 index 00000000..5784033d --- /dev/null +++ b/src/frontend/admin/src/router/systemRouter.js @@ -0,0 +1,35 @@ +import config from '@/config' + +//系统路由 +const routes = [ + { + name: 'layout', + path: '/', + component: () => import(/* webpackChunkName: "layout" */ '@/layout'), + redirect: config.DASHBOARD_URL || '/home', + children: [], + }, + { + path: '/anonymous/login', + component: () => import(/* webpackChunkName: "login" */ '@/views/anonymous/login'), + meta: { + title: '登录', + }, + }, + { + path: '/anonymous/register', + component: () => import(/* webpackChunkName: "userRegister" */ '@/views/anonymous/register.vue'), + meta: { + title: '注册', + }, + }, + { + path: '/anonymous/reset-password', + component: () => import(/* webpackChunkName: "resetPassword" */ '@/views/anonymous/resetPassword'), + meta: { + title: '重置密码', + }, + }, +] + +export default routes \ No newline at end of file diff --git a/src/frontend/admin/src/scui.js b/src/frontend/admin/src/scui.js new file mode 100644 index 00000000..19edd692 --- /dev/null +++ b/src/frontend/admin/src/scui.js @@ -0,0 +1,116 @@ +import config from '@/config' +import api from '@/api' +import tool from '@/utils/tool' +import http from '@/utils/request' +import { permission, rolePermission } from '@/utils/permission' + +import scTable from '@/components/scTable' +import scTableColumn from '@/components/scTable/column.js' +import scFilterBar from '@/components/scFilterBar' +import scUpload from '@/components/scUpload' +import scUploadMultiple from '@/components/scUpload/multiple' +import scUploadFile from '@/components/scUpload/file' +import scFormTable from '@/components/scFormTable' +import scTableSelect from '@/components/scTableSelect' +import scPageHeader from '@/components/scPageHeader' +import scSelect from '@/components/scSelect' +import scDialog from '@/components/scDialog' +import scForm from '@/components/scForm' +import scTitle from '@/components/scTitle' +import scWaterMark from '@/components/scWaterMark' +import scQrCode from '@/components/scQrCode' +import scStatusIndicator from '@/components/scMini/scStatusIndicator' +import scTrend from '@/components/scMini/scTrend' +import naSearch from '@/components/naSearch' +import naColAvatar from '@/components/naColAvatar' +import naColOperation from '@/components/naColOperation' +import naButtonAdd from '@/components/naButtonAdd/index.vue' +import naColIndicator from '@/components/naColIndicator/index.vue' + +import auth from '@/directives/auth' +import role from '@/directives/role' +import time from '@/directives/time' +import copy from '@/directives/copy' +import errorHandler from '@/utils/errorHandler' +import * as elIcons from '@element-plus/icons-vue' +import * as scIcons from '@/assets/icons' +import naColTags from '@/components/naColTags/index.vue' +import naArea from '@/components/naArea/index.vue' +import naDept from '@/components/naDept/index.vue' +import naDicCatalog from '@/components/naDicCatalog/index.vue' +import naButtonBatchDel from '@/components/naButtonBatchDel/index.vue' +import naFormEmail from '@/components/naFormEmail/index.vue' + +export default { + install(app) { + //挂载全局对象 + app.config.globalProperties.$CONFIG = config + app.config.globalProperties.$TOOL = tool + + // http + http.axios.app = () => app + app.config.globalProperties.$HTTP = http + + app.config.globalProperties.$API = api + app.config.globalProperties.$AUTH = permission + app.config.globalProperties.$ROLE = rolePermission + app.config.globalProperties.$GLOBAL = { + enums: null, + menu: null, + user: null, + numbers: null, + chars: null, + } + + //注册全局组件 + app.component('scTable', scTable) + app.component('scTableColumn', scTableColumn) + app.component('scFilterBar', scFilterBar) + app.component('scUpload', scUpload) + app.component('scUploadMultiple', scUploadMultiple) + app.component('scUploadFile', scUploadFile) + app.component('scFormTable', scFormTable) + app.component('scTableSelect', scTableSelect) + app.component('scPageHeader', scPageHeader) + app.component('scSelect', scSelect) + app.component('scDialog', scDialog) + app.component('scForm', scForm) + app.component('scTitle', scTitle) + app.component('scWaterMark', scWaterMark) + app.component('scQrCode', scQrCode) + app.component('scStatusIndicator', scStatusIndicator) + app.component('scTrend', scTrend) + app.component('naSearch', naSearch) + app.component('naColAvatar', naColAvatar) + app.component('naColOperation', naColOperation) + app.component('naButtonAdd', naButtonAdd) + app.component('naColIndicator', naColIndicator) + app.component('naColTags', naColTags) + app.component('naArea', naArea) + app.component('naDept', naDept) + app.component('naDicCatalog', naDicCatalog) + app.component('naButtonBatchDel', naButtonBatchDel) + app.component('naFormEmail', naFormEmail) + + //注册全局指令 + app.directive('auth', auth) + app.directive('role', role) + app.directive('time', time) + app.directive('copy', copy) + + //统一注册el-icon图标 + for (let icon in elIcons) { + app.component(`ElIcon${icon}`, elIcons[icon]) + } + //统一注册sc-icon图标 + for (let icon in scIcons) { + app.component(`ScIcon${icon}`, scIcons[icon]) + } + + //关闭async-validator全局控制台警告 + window.ASYNC_VALIDATOR_NO_WARNING = 1 + + //全局代码错误捕捉 + app.config.errorHandler = errorHandler + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/store/index.js b/src/frontend/admin/src/store/index.js new file mode 100644 index 00000000..ba78b185 --- /dev/null +++ b/src/frontend/admin/src/store/index.js @@ -0,0 +1,15 @@ +/** + * @description 自动import导入所有 vuex 模块 + */ + +import { createStore } from 'vuex' + +const files = import.meta.globEager('./modules/*.js') +const modules = {} +Object.keys(files).forEach((key) => { + modules[key.replace(/^\.\/modules\/(.*)\.js$/g, '$1')] = files[key].default +}) + +export default createStore({ + modules, +}) \ No newline at end of file diff --git a/src/frontend/admin/src/store/modules/global.js b/src/frontend/admin/src/store/modules/global.js new file mode 100644 index 00000000..51660580 --- /dev/null +++ b/src/frontend/admin/src/store/modules/global.js @@ -0,0 +1,33 @@ +import config from '@/config' + +export default { + state: { + //移动端布局 + ismobile: false, + //布局 + layout: config.LAYOUT, + //菜单是否折叠 toggle + menuIsCollapse: config.MENU_IS_COLLAPSE, + //多标签栏 + layoutTags: config.LAYOUT_TAGS, + //主题 + theme: config.THEME, + }, + mutations: { + SET_ismobile(state, key) { + state.ismobile = key + }, + SET_layout(state, key) { + state.layout = key + }, + SET_theme(state, key) { + state.theme = key + }, + TOGGLE_menuIsCollapse(state) { + state.menuIsCollapse = !state.menuIsCollapse + }, + TOGGLE_layoutTags(state) { + state.layoutTags = !state.layoutTags + }, + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/store/modules/iframe.js b/src/frontend/admin/src/store/modules/iframe.js new file mode 100644 index 00000000..2bea1ec5 --- /dev/null +++ b/src/frontend/admin/src/store/modules/iframe.js @@ -0,0 +1,38 @@ +export default { + state: { + iframeList: [], + }, + mutations: { + setIframeList(state, route) { + state.iframeList = [] + state.iframeList.push(route) + }, + pushIframeList(state, route) { + let target = state.iframeList.find((item) => item.path === route.path) + if (!target) { + state.iframeList.push(route) + } + }, + removeIframeList(state, route) { + state.iframeList.forEach((item, index) => { + if (item.path === route.path) { + state.iframeList.splice(index, 1) + } + }) + }, + refreshIframe(state, route) { + state.iframeList.forEach((item) => { + if (item.path === route.path) { + var url = route.meta.url + item.meta.url = '' + setTimeout(function () { + item.meta.url = url + }, 200) + } + }) + }, + clearIframeList(state) { + state.iframeList = [] + }, + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/store/modules/keepAlive.js b/src/frontend/admin/src/store/modules/keepAlive.js new file mode 100644 index 00000000..f1014890 --- /dev/null +++ b/src/frontend/admin/src/store/modules/keepAlive.js @@ -0,0 +1,34 @@ +export default { + state: { + keepLiveRoute: [], + routeKey: null, + routeShow: true, + }, + mutations: { + pushKeepLive(state, component) { + if (!state.keepLiveRoute.includes(component)) { + state.keepLiveRoute.push(component) + } + }, + removeKeepLive(state, component) { + var index = state.keepLiveRoute.indexOf(component) + if (index !== -1) { + state.keepLiveRoute.splice(index, 1) + } + }, + clearKeepLive(state) { + state.keepLiveRoute = [] + }, + setRouteKey(state, key) { + state.routeKey = key + }, + setRouteShow(state, key) { + state.routeShow = key + }, + }, + actions: { + setRouteKey({ commit }, key) { + commit('setRouteKey', key) + }, + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/store/modules/viewTags.js b/src/frontend/admin/src/store/modules/viewTags.js new file mode 100644 index 00000000..66acd967 --- /dev/null +++ b/src/frontend/admin/src/store/modules/viewTags.js @@ -0,0 +1,46 @@ +import router from '@/router' + +export default { + state: { + viewTags: [], + }, + mutations: { + pushViewTags(state, route) { + let backPathIndex = state.viewTags.findIndex((item) => item.fullPath === router.options.history.state.back) + let target = state.viewTags.find((item) => item.fullPath === route.fullPath) + let isName = route.name + if (!target && isName) { + if (backPathIndex === -1) { + state.viewTags.push(route) + } else { + state.viewTags.splice(backPathIndex + 1, 0, route) + } + } + }, + removeViewTags(state, route) { + state.viewTags.forEach((item, index) => { + if (item.fullPath === route.fullPath) { + state.viewTags.splice(index, 1) + } + }) + }, + updateViewTags(state, route) { + state.viewTags.forEach((item) => { + if (item.fullPath === route.fullPath) { + item = Object.assign(item, route) + } + }) + }, + updateViewTagsTitle(state, title = '') { + const nowFullPath = location.hash.substring(1) + state.viewTags.forEach((item) => { + if (item.fullPath === nowFullPath) { + item.meta.title = title + } + }) + }, + clearViewTags(state) { + state.viewTags = [] + }, + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/style/app.scss b/src/frontend/admin/src/style/app.scss new file mode 100644 index 00000000..c277992d --- /dev/null +++ b/src/frontend/admin/src/style/app.scss @@ -0,0 +1,515 @@ +/* 全局 */ +#app, +body, +html { + width: 100%; + height: 100%; + background-color: #f6f8f9; + font-size: 13px; +} + +a { + color: #333; + text-decoration: none; +} + +a:hover, +a:focus { + color: #000; + text-decoration: none; +} + +a:link { + text-decoration: none; +} + +a:-webkit-any-link { + text-decoration: none; +} + +a, +button, +input, +textarea { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + box-sizing: border-box; + outline: none !important; + -webkit-appearance: none; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + outline: none; +} + +/* 大布局样式 */ +.aminui { + display: flex; + flex-flow: column; +} + +.aminui-wrapper { + display: flex; + flex: 1; + overflow: auto; +} + +/* 全局滚动条样式 */ +.scrollable { + -webkit-overflow-scrolling: touch; +} + +::-webkit-scrollbar { + width: 5px; + height: 5px; +} + +::-webkit-scrollbar-thumb { + background-color: rgba(50, 50, 50, 0.3); +} + +::-webkit-scrollbar-thumb:hover { + background-color: rgba(50, 50, 50, 0.6); +} + +::-webkit-scrollbar-track { + background-color: rgba(50, 50, 50, 0.1); +} + +::-webkit-scrollbar-track:hover { + background-color: rgba(50, 50, 50, 0.2); +} + +/*布局设置*/ +.layout-setting { + position: fixed; + width: 40px; + height: 40px; + border-radius: 3px 0 0 3px; + bottom: 100px; + right: 0px; + z-index: 100; + background: #409eff; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; +} + +.layout-setting i { + font-size: 18px; + color: #fff; +} + +/* 头部 */ +.adminui-header { + height: 58px; + background: #222b45; + color: #fff; + display: flex; + justify-content: space-between; +} + +.adminui-header-left { + display: flex; + align-items: center; + padding-left: 20px; +} + +.adminui-header-right { + display: flex; + align-items: center; +} + +.adminui-header .logo-bar { + font-size: 20px; + font-weight: bold; + display: flex; + align-items: center; +} + +.adminui-header .logo-bar .logo { + margin-right: 10px; + width: 35px; + height: 35px; +} + +.adminui-header .nav { + display: flex; + height: 100%; + margin-left: 40px; +} + +.adminui-header .nav li { + padding: 0 10px; + margin: 0 10px 0 0; + font-size: 14px; + color: rgba(255, 255, 255, 0.6); + list-style: none; + height: 100%; + display: flex; + align-items: center; + cursor: pointer; +} + +.adminui-header .nav li i { + margin-right: 5px; +} + +.adminui-header .nav li:hover { + color: #fff; +} + +.adminui-header .nav li.active { + background: rgba(255, 255, 255, 0.1); + color: #fff; +} + +.adminui-header .user-bar .panel-item:hover { + background: rgba(255, 255, 255, 0.1) !important; +} + +.adminui-header .user-bar .user label { + color: #fff; +} + +/* 左侧菜单 */ +.aminui-side-split { + width: 65px; + flex-shrink: 0; + background: #222b45; + display: flex; + flex-flow: column; +} + +.aminui-side-split-top { + height: 49px; +} + +.aminui-side-split-top a { + display: inline-block; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} + +.aminui-side-split-top .logo { + height: 30px; + vertical-align: bottom; +} + +.adminui-side-split-scroll { + overflow: auto; + overflow-x: hidden; + height: 100%; + flex: 1; +} + +.aminui-side-split li { + cursor: pointer; + width: 65px; + height: 65px; + color: #fff; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.aminui-side-split li i { + font-size: 18px; +} + +.aminui-side-split li p { + margin-top: 5px; +} + +.aminui-side-split li:hover { + background: rgba(255, 255, 255, 0.1); +} + +.aminui-side-split li.active { + background: #409eff; +} + +.adminui-side-split-scroll::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.4); + border-radius: 5px; +} + +.adminui-side-split-scroll::-webkit-scrollbar-thumb:hover { + background-color: rgba(255, 255, 255, 0.5); +} + +.adminui-side-split-scroll::-webkit-scrollbar-track { + background-color: rgba(255, 255, 255, 0); +} + +.adminui-side-split-scroll::-webkit-scrollbar-track:hover { + background-color: rgba(255, 255, 255, 0); +} + +.aminui-side { + display: flex; + flex-flow: column; + flex-shrink: 0; + width: 210px; + background: #fff; + box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05); + border-right: 1px solid #e6e6e6; + transition: width 0.3s; +} + +.adminui-side-top { + border-bottom: 1px solid #ebeef5; + height: 50px; + line-height: 50px; +} + +.adminui-side-top h2 { + padding: 0 20px; + font-size: 17px; + color: #3c4a54; +} + +.adminui-side-scroll { + overflow: auto; + overflow-x: hidden; + flex: 1; +} + +.adminui-side-bottom { + border-top: 1px solid #ebeef5; + height: 51px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; +} + +.adminui-side-bottom i { + font-size: 16px; +} + +.adminui-side-bottom:hover { + color: var(--el-color-primary); +} + +.aminui-side.isCollapse { + width: 65px; +} + +.el-menu .menu-tag { + position: absolute; + height: 18px; + line-height: 18px; + background: var(--el-color-danger); + font-size: 12px; + color: #fff; + right: 20px; + border-radius: 18px; + padding: 0 6px; +} + +.el-menu .el-sub-menu__title .menu-tag { + right: 40px; +} + +.el-menu--horizontal > li .menu-tag { + display: none; +} + +/* 右侧内容 */ +.aminui-body { + flex: 1; + display: flex; + flex-flow: column; +} + +.adminui-topbar { + height: 50px; + border-bottom: 1px solid #ebeef5; + background: #fff; + box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); + display: flex; + justify-content: space-between; +} + +.adminui-topbar .left-panel { + display: flex; + align-items: center; +} + +.adminui-topbar .right-panel { + display: flex; + align-items: center; +} + +.right-panel-search { + display: flex; + align-items: center; + gap: .5rem; +} + + +.adminui-tags { + height: 35px; + background: #fff; + border-bottom: 1px solid #e6e6e6; +} + +.adminui-tags ul { + display: flex; + overflow: hidden; +} + +.adminui-tags li { + cursor: pointer; + display: inline-block; + height: 34px; + line-height: 34px; + position: relative; + flex-shrink: 0; +} + +.adminui-tags li::after { + content: ' '; + width: 1px; + height: 100%; + position: absolute; + right: 0px; + background-image: linear-gradient(#fff, #e6e6e6); +} + +.adminui-tags li a { + display: inline-block; + padding: 0 10px; + width: 100%; + height: 100%; + color: #999; + text-decoration: none; + display: flex; + align-items: center; +} + +.adminui-tags li i { + margin-left: 10px; + border-radius: 3px; + width: 18px; + height: 18px; + display: flex; + align-items: center; + justify-content: center; +} + +.adminui-tags li i:hover { + background: rgba(0, 0, 0, 0.2); + color: #fff; +} + +.adminui-tags li:hover { + background: #ecf5ff; +} + +.adminui-tags li.active { + background: #409eff; +} + +.adminui-tags li.active a { + color: #fff; +} + +.adminui-tags li.sortable-ghost { + opacity: 0; +} + +.adminui-main { + overflow: auto; + background-color: #f6f8f9; + flex: 1; +} + +/*页面最大化*/ +.aminui.main-maximize { + .main-maximize-exit { + display: block; + } + + .aminui-side-split, + .aminui-side, + .adminui-header, + .adminui-topbar, + .adminui-tags { + display: none; + } +} + +.main-maximize-exit { + display: none; + position: fixed; + z-index: 3000; + top: -20px; + left: 50%; + margin-left: -20px; + border-radius: 50%; + width: 40px; + height: 40px; + cursor: pointer; + background: rgba(0, 0, 0, 0.2); + text-align: center; +} + +.main-maximize-exit i { + font-size: 14px; + margin-top: 22px; + color: #fff; +} + +.main-maximize-exit:hover { + background: rgba(0, 0, 0, 0.4); +} + +/*定宽页面*/ +.sc-page { + width: 1230px; + margin: 0 auto; +} + + +.no-zIndex .el-table__cell { + z-index: unset; +} + +.w15 { + width: 15rem; +} + +.w100p { + width: 100%; +} + +.text-center { + text-align: center; +} + +.flex { + display: flex; +} + +.gap05 { + gap: .5rem; +} + +.items-center { + align-items: center; +} + +.justify-content-center { + justify-content: center; +} \ No newline at end of file diff --git a/src/frontend/admin/src/style/dark.scss b/src/frontend/admin/src/style/dark.scss new file mode 100644 index 00000000..56795385 --- /dev/null +++ b/src/frontend/admin/src/style/dark.scss @@ -0,0 +1,95 @@ +@import 'element-plus/theme-chalk/src/dark/css-vars.scss'; + +html.dark { + //变量 + --el-text-color-primary: #d0d0d0; + --el-color-primary-dark-2: var(--el-color-primary-light-2) !important; + --el-color-primary-light-9: var(--el-color-primary-dark-8) !important; + --el-color-primary-light-8: var(--el-color-primary-dark-7) !important; + --el-color-primary-light-7: var(--el-color-primary-dark-6) !important; + --el-color-primary-light-5: var(--el-color-primary-dark-4) !important; + --el-color-primary-light-3: var(--el-color-primary-dark-3) !important; + + //背景 + #app { + background: var(--el-bg-color); + } + + //登录背景 + .login_bg { + background: var(--el-bg-color); + } + + //框架 + .adminui-header { + background: var(--el-bg-color-overlay); + border-bottom: 1px solid var(--el-border-color-light); + height: 59px; + } + + .aminui-side-split { + background: var(--el-bg-color); + } + + .aminui-side-split li { + color: var(--el-text-color-primary); + } + + .aminui-side { + background: var(--el-bg-color-overlay); + border-color: var(--el-border-color-light); + } + + .adminui-side-top, + .adminui-side-bottom { + border-color: var(--el-border-color-light); + } + + .adminui-side-top h2 { + color: var(--el-text-color-primary); + } + + .adminui-topbar, + .adminui-tags { + background: var(--el-bg-color-overlay); + border-color: var(--el-border-color-light); + } + + .adminui-main { + background: var(--el-bg-color); + } + + .drawerBG { + background: var(--el-bg-color); + } + + .adminui-header-menu .el-menu { + --el-menu-bg-color: var(--el-bg-color-overlay) !important; + --el-menu-hover-bg-color: #171819 !important; + } + + //组件 + .el-header, + .el-main.nopadding, + .el-footer { + background: var(--el-bg-color-overlay); + border-color: var(--el-border-color-light); + } + + .el-main { + background: var(--el-bg-color); + } + + .el-aside { + background: var(--el-bg-color-overlay); + border-color: var(--el-border-color-light); + } + + .el-table .el-table__body-wrapper { + background: var(--el-bg-color); + } + + .el-table th.is-sortable:hover { + background: #111; + } +} \ No newline at end of file diff --git a/src/frontend/admin/src/style/fix.scss b/src/frontend/admin/src/style/fix.scss new file mode 100644 index 00000000..a207af25 --- /dev/null +++ b/src/frontend/admin/src/style/fix.scss @@ -0,0 +1,293 @@ +/* 覆盖element-plus样式 */ + +:root { + --el-color-primary: #409eff; + --el-color-primary-light-1: #53a7ff; + --el-color-primary-light-2: #66b1ff; + --el-color-primary-light-3: #79bbff; + --el-color-primary-light-4: #8cc4ff; + --el-color-primary-light-5: #9fceff; + --el-color-primary-light-6: #b2d8ff; + --el-color-primary-light-7: #c5e1ff; + --el-color-primary-light-8: #d8ebff; + --el-color-primary-light-9: #ebf5ff; + --el-color-primary-dark-1: #398ee5; + --el-color-primary-dark-2: #337ecc; + --el-color-primary-dark-3: #2c6eb2; + --el-color-primary-dark-4: #265e99; + --el-color-primary-dark-5: #204f7f; + --el-color-primary-dark-6: #193f66; + --el-color-primary-dark-7: #132f4c; + --el-color-primary-dark-8: #0c1f32; + --el-color-primary-dark-9: #060f19; + --el-font-size-base: 13px; +} + +.right-panel-search .el-input { + --el-input-width: 15rem; +} + +.el-date-editor { + --el-date-editor-daterange-width: 20rem; +} + +.el-menu { + border: none !important; +} + +.el-menu .el-menu-item a { + color: inherit; + text-decoration: none; + display: block; + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; +} + +.el-form-item-msg { + font-size: 12px; + color: #999; + flex-grow: 1; + line-height: 2rem +} + +.el-container { + height: 100%; +} + +.el-aside { + border-right: 1px solid var(--el-border-color-light); +} + +.el-container + .el-aside { + border-right: 0; + border-left: 1px solid var(--el-border-color-light); +} + +.el-header { + background: #fff; + border-bottom: 1px solid var(--el-border-color-light); + padding: 13px 15px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.el-header .left-panel { + display: flex; + align-items: center; +} + +.el-header .right-panel { + display: flex; + align-items: center; +} + +.el-header .right-panel > * + * { + margin-left: 10px; +} + +.el-footer { + background: #fff; + border-top: 1px solid var(--el-border-color-light); + padding: 13px 15px; + height: 51px; +} + +.el-main { + padding: 1rem; +} + +.el-main.nopadding { + padding: 0; + background: #fff; +} + +.el-drawer__body { + overflow: auto; + padding: 0; +} + +.el-popconfirm__main { + margin: 14px 0; +} + +.el-card__header { + border-bottom: 0; + font-size: 17px; + font-weight: bold; + padding: 15px 20px 0px 20px; +} + +.el-dialog__title { + font-size: 17px; + font-weight: bold; +} + +.el-drawer__header > :first-child { + font-size: 17px; + font-weight: bold; +} + +.el-tree.menu .el-tree-node__content { + height: 36px; +} + +.el-tree.menu .el-tree-node__content .el-tree-node__label .icon { + margin-right: 5px; +} + +.el-progress__text { + font-size: 12px !important; +} + +.el-progress__text i { + font-size: 14.4px !important; +} + +.el-step.is-horizontal .el-step__line { + height: 1px; +} + +.el-step__title { + font-size: 14px; +} + +.drawerBG { + background: #f6f8f9; +} + +.el-button + .el-dropdown { + margin-left: 10px; +} + +.el-button-group + .el-dropdown { + margin-left: 10px; +} + +.el-tag + .el-tag { + margin-left: 10px; +} + +.el-button-group + .el-button-group { + margin-left: 10px; +} + +.el-tabs__nav-wrap::after { + height: 1px; +} + +.el-table th.is-sortable { + transition: 0.1s; +} + +.el-table th.is-sortable:hover { + background: #eee; +} + +.el-table .el-table__body-wrapper { + background: #f6f8f9; +} + +.el-col .el-card { + margin-bottom: 15px; +} + +.el-main { + flex-basis: 100%; +} + +.el-main > .scTable .el-table--border::before { + display: none; +} + +.el-main > .scTable .el-table--border::after { + display: none; +} + +.el-main > .scTable .el-table--border .el-table__inner-wrapper::after { + display: none; +} + +.el-main > .scTable .el-table__border-left-patch { + display: none; +} + +.el-main > .scTable .el-table--border .el-table__inner-wrapper tr:first-child td:first-child { + border-left: 0; +} + +.el-main > .scTable .el-table--border .el-table__inner-wrapper tr:first-child th:first-child { + border-left: 0; +} + +.el-table.el-table--large { + font-size: 14px; +} + +.el-table.el-table--small { + font-size: 12px; +} + +.el-table { + font-size: 12px; +} + +.el-radio-button__inner { + font-size: 12px; +} + +.el-checkbox-button__inner { + font-size: 12px; +} + +.el-sub-menu .el-icon { + font-size: 17px; +} + +.el-sub-menu .el-sub-menu__icon-arrow { + font-size: 12px; +} + +.aminui-side-split li.active { + background-color: var(--el-color-primary); +} + +.adminui-tags li:hover { + background-color: var(--el-color-primary-light-9); +} + +.adminui-tags li.active { + background-color: var(--el-color-primary) !important; +} + +.contextmenu li:hover { + background-color: var(--el-color-primary-light-9) !important; + color: var(--el-color-primary-light-2) !important; +} + +.data-box .item-background { + background-color: var(--el-color-primary) !important; +} + +.layout-setting, +.diy-grid-setting { + background-color: var(--el-color-primary) !important; +} + +/* 覆盖tinymce样式 */ +.sceditor .tox-tinymce { + border: 1px solid #dcdfe6; + border-radius: 0; +} + +body .tox-tinymce-aux { + z-index: 5700; +} + + +.el-descriptions__body .el-descriptions__table { + word-break: break-word; +} \ No newline at end of file diff --git a/src/frontend/admin/src/style/media.scss b/src/frontend/admin/src/style/media.scss new file mode 100644 index 00000000..a46770c2 --- /dev/null +++ b/src/frontend/admin/src/style/media.scss @@ -0,0 +1,141 @@ +@media (max-width: 992px) { + // 移动端样式覆盖 + .el-form-item { + display: block; + } + .el-form-item__label { + display: block; + text-align: left; + padding: 0 0 10px; + } + .el-dialog { + width: 90% !important; + } + .el-dialog.is-fullscreen { + width: 100% !important; + } + .el-drawer.rtl { + width: 90% !important; + } + .el-form-item__content { + margin-left: 0px !important; + } + + .adminui-main { + > .el-container { + display: block; + height: auto; + } + + > .el-container > .el-aside { + width: 100% !important; + border: 0; + } + } + .scTable { + .el-table, + .el-table__body-wrapper { + display: block !important; + height: auto !important; + } + + .el-scrollbar__wrap { + height: auto !important; + } + + .scTable-page { + padding: 0 5px !important; + } + + .el-pagination__total, + .el-pagination__jump, + .el-pagination__sizes { + display: none !important; + } + } + + .headerPublic { + height: auto !important; + display: block; + + .left-panel { + overflow: auto; + } + + .left-panel::-webkit-scrollbar { + display: none; + } + + .right-panel { + display: block; + border-top: 1px solid var(--el-border-color-light); + margin-top: 15px; + } + + .right-panel .right-panel-search { + display: block; + } + + } + .adminui-main > .el-container > *:first-child:not(.el-aside):not(.el-header) { + border: 0; + margin-top: 0; + } + .adminui-main > .el-container > *:first-child:not(.el-aside):not(.el-header) + .el-aside { + margin-top: 0; + } + .adminui-main > .el-container > .el-aside { + border-bottom: 1px solid var(--el-border-color-light) !important; + } + .adminui-main > .el-container > .el-container { + border-top: 1px solid var(--el-border-color-light); + border-bottom: 1px solid var(--el-border-color-light); + margin-top: 15px; + } + .adminui-main > .el-container > .el-container + .el-aside { + border-top: 1px solid var(--el-border-color-light); + margin-top: 15px; + } + .adminui-main > .el-container > .el-header { + @extend .headerPublic; + } + .adminui-main > .el-container > .el-main.nopadding { + border-top: 1px solid var(--el-border-color-light); + border-bottom: 1px solid var(--el-border-color-light); + margin-top: 15px; + } + .adminui-main > .el-container > .el-main + .el-aside { + border-left: 0 !important; + border-top: 1px solid var(--el-border-color-light); + margin-top: 15px; + } + .adminui-main > .el-container > .el-footer { + margin-top: 15px; + border-bottom: 1px solid var(--el-border-color-light); + } + .adminui-main > .el-container > .el-container > .el-header { + @extend .headerPublic; + } + .adminui-main > .el-container > .el-container > .el-header .left-panel { + display: block; + } + .adminui-main > .el-container > .el-container > .el-header .right-panel { + display: block; + margin-top: 15px; + } + + .sc-page { + width: 100%; + margin: 0; + } + + .common-main .el-form { + width: 100% !important; + } + .common-header-logo label { + display: none; + } + .common-header-title { + display: none; + } +} \ No newline at end of file diff --git a/src/frontend/admin/src/style/pages.scss b/src/frontend/admin/src/style/pages.scss new file mode 100644 index 00000000..a9c03dca --- /dev/null +++ b/src/frontend/admin/src/style/pages.scss @@ -0,0 +1,183 @@ +/* profile */ +.page-user { + .el-aside { + width: 20rem; + } + + .el-header { + display: block; + height: auto; + } + + .user-info-top { + text-align: center; + } + + + .user-info-top p { + display: flex; + justify-content: center; + margin: 1rem 0; + } + + .menu { + background: none; + } + + + .menu .el-menu-item-group { + border-top: 1px solid var(--el-border-color-light); + } + + .menu .el-menu-item-group:first-child { + border: 0; + } +} + +/*static-table*/ +.static-table { + border-collapse: collapse; + width: 100%; + font-size: 14px; + margin-bottom: 45px; + line-height: 1.5em; +} + +.static-table th { + text-align: left; + white-space: nowrap; + color: #909399; + font-weight: 400; + border-bottom: 1px solid #dcdfe6; + padding: 15px; + max-width: 250px; +} + +.static-table td { + border-bottom: 1px solid #dcdfe6; + padding: 15px; + max-width: 250px; + color: #606266; +} + +/*header-tabs*/ +.header-tabs { + padding: 10px 0 0 0; + display: block; + border: 0 !important; + height: 50px; + background: none; +} + +.header-tabs .el-tabs__header { + padding-left: 10px; + margin: 0; +} + +.header-tabs .el-tabs__content { + display: none; +} + +.header-tabs .el-tabs__nav { + border-radius: 0 !important; +} + +.header-tabs .el-tabs__item { + font-size: 13px; +} + +.header-tabs .el-tabs__item.is-active { + background-color: var(--el-bg-color-overlay); +} + +/*common-page*/ +.common-page { +} + +.common-header-left { + display: flex; + align-items: center; +} + +.common-header-logo { + display: flex; + align-items: center; +} + +.common-header-logo img { + height: 30px; + margin-right: 10px; + vertical-align: bottom; +} + +.common-header-logo label { + font-size: 20px; +} + +.common-header-title { + font-size: 16px; + border-left: 1px solid var(--el-border-color-light); + margin-left: 15px; + padding-left: 15px; +} + +.common-header-right { + display: flex; + align-items: center; +} + +.common-header-right a { + font-size: 14px; + color: var(--el-color-primary); + cursor: pointer; +} + +.common-header-right a:hover { + color: var(--el-color-primary-light-3); +} + +.common-container { + max-width: 1240px; + margin: 30px auto 30px auto; +} + +.common-main { + padding: 20px; +} + +.common-title { + font-size: 26px; + margin-bottom: 20px; + font-weight: normal; +} + +.common-main .el-form { + width: 40rem; + margin: 3rem auto; +} + +.common-main .el-steps .el-step__title { + font-size: 14px; +} + +.common-main .el-steps .el-step__icon { + border: 1px solid; +} + +.common-main .yzm { + display: flex; + width: 100%; +} + +.common-main .yzm .el-button { + margin-left: 10px; +} + +.common-main .link { + color: var(--el-color-primary); + cursor: pointer; +} + +.common-main .link:hover { + color: var(--el-color-primary-light-3); +} \ No newline at end of file diff --git a/src/frontend/admin/src/style/style.scss b/src/frontend/admin/src/style/style.scss new file mode 100644 index 00000000..8ca490da --- /dev/null +++ b/src/frontend/admin/src/style/style.scss @@ -0,0 +1,5 @@ +@import 'app.scss'; +@import 'fix.scss'; +@import 'pages.scss'; +@import 'media.scss'; +@import 'dark.scss'; \ No newline at end of file diff --git a/src/frontend/admin/src/utils/color.js b/src/frontend/admin/src/utils/color.js new file mode 100644 index 00000000..997f98cf --- /dev/null +++ b/src/frontend/admin/src/utils/color.js @@ -0,0 +1,29 @@ +export default { + //hex颜色转rgb颜色 + HexToRgb(str) { + str = str.replace('#', '') + var hxs = str.match(/../g) + for (var i = 0; i < 3; i++) hxs[i] = parseInt(hxs[i], 16) + return hxs + }, + //rgb颜色转hex颜色 + RgbToHex(a, b, c) { + var hexs = [a.toString(16), b.toString(16), c.toString(16)] + for (var i = 0; i < 3; i++) { + if (hexs[i].length === 1) hexs[i] = '0' + hexs[i] + } + return '#' + hexs.join('') + }, + //加深 + darken(color, level) { + var rgbc = this.HexToRgb(color) + for (var i = 0; i < 3; i++) rgbc[i] = Math.floor(rgbc[i] * (1 - level)) + return this.RgbToHex(rgbc[0], rgbc[1], rgbc[2]) + }, + //变淡 + lighten(color, level) { + var rgbc = this.HexToRgb(color) + for (var i = 0; i < 3; i++) rgbc[i] = Math.floor((255 - rgbc[i]) * level + rgbc[i]) + return this.RgbToHex(rgbc[0], rgbc[1], rgbc[2]) + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/utils/db.js b/src/frontend/admin/src/utils/db.js new file mode 100644 index 00000000..34a29520 --- /dev/null +++ b/src/frontend/admin/src/utils/db.js @@ -0,0 +1,309 @@ +//初始数据库结构 +const dbData = [ + { + dbName: 'masterDB', //数据库名称 + version: 1, //数据库版本号,当结构发生变化时 + tables: [ + //表 + { + name: 'SYS_favorites', //表名称 + keyPath: 'uid', //主键 + autoIncrement: false, //主键是否自增 + index: [ + //索引 + { + name: 'name_index', //索引名称 + key: 'name', //索引key + }, + ], + }, + { + name: 'SYS_keyword', + keyPath: 'id', + }, + ], + }, + { + dbName: 'guestDB', + version: 1, + tables: [ + { + name: 'MY_demo', + keyPath: 'id', + }, + ], + }, +] + +// 使用示例 +// import DB from '@/utils/db' + +// 初始化创建数据库 一般在项目启动时就执行了 +// await DB.create() + +// 打开某个数据库,返回数据库实例 +// const database = await DB.open("dbName") + +// 在打开的数据库中添加数据到tablenName表 +// await database.add("tablenName", data) + +// 查询 +// await database.get("tablenName", key) + +// 查询 根据索引 +// await database.indexGet("tablenName", "indexName", indexVal) + +// 修改 +// await database.put("tablenName", data) + +// 删除 +// await database.delete("tablenName", key) + +// 获取所有 +// await database.getAll("tablenName") + +// 清空某个表数据 +// await database.clear("tablenName") + +// 获取某个表信息 +// database.getTable("tablenName") + +// 获取所有表 +// database.getTables() + +// 关闭数据库连接 +// database.close() + +export default { + //建立数据库,表,初始数据 + create() { + var promiseArray = [] + const addDB = (db) => { + return new Promise((resolve, reject) => { + const request = indexedDB.open(db.dbName, db.version) + ;(request.onupgradeneeded = (e) => { + const thisDB = e.target.result + db.tables.forEach((item) => { + let table = null + if (thisDB.objectStoreNames.contains(item.name)) { + //已存在表,删除旧index + table = e.target.transaction.objectStore(item.name) + table.indexNames.length > 0 && + table.indexNames.forEach((indexName) => { + table.deleteIndex(indexName) + }) + } else { + //创建新的表 + table = thisDB.createObjectStore(item.name, { + keyPath: item.keyPath, + autoIncrement: item.autoIncrement, + }) + } + //建立index + item.index && + item.index.forEach((ind) => { + table.createIndex(ind.name, ind.key, { unique: false }) + }) + }) + }), + (request.onsuccess = (e) => { + return resolve(e.target.result) + }) + request.onerror = (e) => { + return reject(e) + } + }) + } + dbData.forEach((db) => { + promiseArray.push(addDB(db)) + }) + return new Promise((resolve, reject) => { + Promise.all(promiseArray) + .then((e) => { + resolve(e) + }) + .catch((e) => { + reject(e) + }) + }) + }, + //所有数据库 + databases() { + return indexedDB.databases() + }, + //打开数据库 + open(dbName) { + return new Promise((resolve, reject) => { + const request = indexedDB.open(dbName) + request.onsuccess = (e) => { + const database = new this.database(e.target.result) + resolve(database) + } + request.onerror = (e) => { + reject(e) + } + }) + }, + //删除数据库 + deleteDB(dbName) { + return indexedDB.deleteDatabase(dbName) + }, + //数据库类 + database: function (IDBDatabase) { + this.IDBDatabase = IDBDatabase + + /** + * 添加行数据 + * @param {string} tableName 表名 + * @param {object} data 数据 + * @returns {promise} + */ + this.add = (tableName, data) => { + return new Promise((resolve, reject) => { + const request = IDBDatabase.transaction([tableName], 'readwrite').objectStore(tableName).add(data) + request.onsuccess = (e) => { + resolve(e) + } + request.onerror = (e) => { + reject(e) + } + }) + } + + /** + * 修改行数据,未查询到就新增 + * @param {string} tableName 表名 + * @param {object} data 数据 + * @returns {promise} + */ + this.put = (tableName, data) => { + return new Promise((resolve, reject) => { + const request = IDBDatabase.transaction([tableName], 'readwrite').objectStore(tableName).put(data) + request.onsuccess = (e) => { + resolve(e) + } + request.onerror = (e) => { + reject(e) + } + }) + } + + /** + * 删除行 + * @param {string} tableName 表名 + * @param {string} key 主键 + * @returns {promise} + */ + this.delete = (tableName, key) => { + return new Promise((resolve, reject) => { + const request = IDBDatabase.transaction([tableName], 'readwrite').objectStore(tableName).delete(key) + request.onsuccess = (e) => { + resolve(e) + } + request.onerror = (e) => { + reject(e) + } + }) + } + + /** + * 根据主键获取行 + * @param {string} tableName 表名 + * @param {string} key 主键 + * @returns {promise} + */ + this.get = (tableName, key) => { + return new Promise((resolve, reject) => { + const request = IDBDatabase.transaction([tableName], 'readwrite').objectStore(tableName).get(key) + request.onsuccess = () => { + resolve(request.result || null) + } + request.onerror = (e) => { + reject(e) + } + }) + } + + /** + * 根据索引获取行 + * @param {string} tableName 表名 + * @param {string} indexName 索引库名称 + * @param {string} indexVal 索引值 + * @returns {promise} + */ + this.indexGet = (tableName, indexName, indexVal) => { + return new Promise((resolve, reject) => { + const request = IDBDatabase.transaction([tableName], 'readwrite').objectStore(tableName).index(indexName).get(indexVal) + request.onsuccess = () => { + resolve(request.result || null) + } + request.onerror = (e) => { + reject(e) + } + }) + } + + /** + * 获取所有行 + * @param {string} tableName 表名 + * @returns {promise} + */ + this.getAll = (tableName) => { + return new Promise((resolve, reject) => { + const request = IDBDatabase.transaction([tableName], 'readwrite').objectStore(tableName).getAll() + request.onsuccess = () => { + resolve(request.result || null) + } + request.onerror = (e) => { + reject(e) + } + }) + } + + /** + * 清空表 + * @param {string} tableName 表名 + * @returns {promise} + */ + this.clear = (tableName) => { + return new Promise((resolve, reject) => { + const request = IDBDatabase.transaction([tableName], 'readwrite').objectStore(tableName).clear() + request.onsuccess = (e) => { + resolve(e) + } + request.onerror = (err) => { + reject(err) + } + }) + } + + /** + * 获取表信息 + * @returns {IDBObjectStore} + */ + this.getTable = (tableName) => { + const request = IDBDatabase.transaction([tableName], 'readwrite').objectStore(tableName) + return request + } + + /** + * 获取所有的表 + * @returns {[IDBObjectStore]} + */ + this.getTables = () => { + const tables = [] + for (let item of IDBDatabase.objectStoreNames) { + tables.push(IDBDatabase.transaction([item], 'readwrite').objectStore(item)) + } + return tables + } + + /** + * 关闭数据库连接 + * @returns {} + */ + this.close = () => { + return IDBDatabase.close() + } + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/utils/errorHandler.js b/src/frontend/admin/src/utils/errorHandler.js new file mode 100644 index 00000000..c6f18bde --- /dev/null +++ b/src/frontend/admin/src/utils/errorHandler.js @@ -0,0 +1,33 @@ +/** + * 全局代码错误捕捉 + * 比如 null.length 就会被捕捉到 + */ + +export default (error, vm) => { + //过滤HTTP请求错误 + if (error.status || error.status === 0) { + return false + } + + var errorMap = { + InternalError: 'Javascript引擎内部错误', + ReferenceError: '未找到对象', + TypeError: '使用了错误的类型或对象', + RangeError: '使用内置对象时,参数超范围', + SyntaxError: '语法错误', + EvalError: '错误的使用了Eval', + URIError: 'URI错误', + } + var errorName = errorMap[error.name] || '未知错误' + + console.warn(`[SCUI error]: ${error}`) + console.error(error) + //throw error; + + vm.$nextTick(() => { + vm.$notify.error({ + title: errorName, + message: error, + }) + }) +} \ No newline at end of file diff --git a/src/frontend/admin/src/utils/load.js b/src/frontend/admin/src/utils/load.js new file mode 100644 index 00000000..24d75f3c --- /dev/null +++ b/src/frontend/admin/src/utils/load.js @@ -0,0 +1,60 @@ +/** + * loadJS 异步加载远程JS + * @constructor + * @param {string} src - 必填,需要加载的URL路径 + * @param {string} keyName - 必填,唯一key和JS返回的全局的对象名 + * @param {string} callbackName - 非必填,如果远程JS有callback,则可更有效的判断是否完成加载 + */ +export function loadJS(src, keyName, callbackName) { + return new Promise((resolve, reject) => { + let has = document.head.querySelector('script[loadKey=' + keyName + ']') + if (has) { + return resolve(window[keyName]) + } + let script = document.createElement('script') + script.type = 'text/javascript' + script.src = src + script.setAttribute('loadKey', keyName) + document.head.appendChild(script) + script.onload = () => { + if (callbackName) { + window[callbackName] = () => { + return resolve(window[keyName]) + } + } else { + setTimeout(() => { + return resolve(window[keyName]) + }, 50) + } + } + script.onerror = (err) => { + return reject(err) + } + }) +} + +/** + * loadCSS 异步加载远程css + * @constructor + * @param {string} src - 必填,需要加载的URL路径 + * @param {string} keyName - 必填,唯一key + */ +export function loadCSS(src, keyName) { + return new Promise((resolve, reject) => { + let has = document.head.querySelector('link[loadKey=' + keyName + ']') + if (has) { + return resolve() + } + let link = document.createElement('link') + link.rel = 'stylesheet' + link.href = src + link.setAttribute('loadKey', keyName) + document.head.appendChild(link) + link.onload = () => { + return resolve() + } + link.onerror = (err) => { + return reject(err) + } + }) +} \ No newline at end of file diff --git a/src/frontend/admin/src/utils/permission.js b/src/frontend/admin/src/utils/permission.js new file mode 100644 index 00000000..5ca773ca --- /dev/null +++ b/src/frontend/admin/src/utils/permission.js @@ -0,0 +1,55 @@ +import tool from '@/utils/tool' + +/** + * 是否含有不限分类,有则表示全部允许通过 + */ +export function permissionAll() { + const allPermissions = '*/*/*' + let permissions = tool.data.get('PERMISSIONS') + return permissions.includes(allPermissions) +} + +/** + * 比对两组数据是否一致 + * @param news + * @param old + * @returns {boolean} + */ +export function judementSameArr(news, old) { + // console.log(news) + // console.log(old) + let count = 0 + const leng = news.length + for (let i in news) { + for (let j in old) { + if (news[i] === old[j]) { + count++ + // console.log(news[i]) + } + } + } + // console.log('相同的数量', count) + return count === leng +} + +export function permission(data) { + let permissions = tool.data.get('PERMISSIONS') + if (!permissions) { + return false + } + let isHave = permissions.includes(data) + return isHave +} + +export function rolePermission(data) { + let userInfo = tool.data.get('USER_INFO') + if (!userInfo) { + return false + } + let role = userInfo.role + if (!role) { + return false + } + let isHave = role.includes(data) + return isHave +} \ No newline at end of file diff --git a/src/frontend/admin/src/utils/preload.js b/src/frontend/admin/src/utils/preload.js new file mode 100644 index 00000000..4b0d1ca7 --- /dev/null +++ b/src/frontend/admin/src/utils/preload.js @@ -0,0 +1,50 @@ +import Api from '@/api' + +export default { + async install(app, global) { + const preloads = await Promise.all([ + (async () => { + try { + return await Api.sys_menu.userMenus.post() + } catch { + // + } + })(), + (async () => { + try { + return await Api.sys_user.userInfo.post() + } catch { + // + } + })(), + (async () => { + try { + return await Api.sys_constant.getEnums.post() + } catch { + // + } + })(), + (async () => { + try { + return await Api.sys_constant.getNumbers.post() + } catch { + // + } + })(), + (async () => { + try { + return await Api.sys_constant.getChars.post() + } catch { + // + } + })(), + ]) + + if (!global) global = app.config.globalProperties.$GLOBAL + global.menu = preloads[0]?.data + global.user = preloads[1]?.data + global.enums = preloads[2]?.data + global.numbers = preloads[3]?.data + global.chars = preloads[4]?.data + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/utils/print.js b/src/frontend/admin/src/utils/print.js new file mode 100644 index 00000000..67a7f8c6 --- /dev/null +++ b/src/frontend/admin/src/utils/print.js @@ -0,0 +1,143 @@ +// 打印类属性、方法定义 +/* eslint-disable */ +const Print = function (dom, options) { + if (!(this instanceof Print)) return new Print(dom, options) + + this.options = this.extend( + { + noPrint: '.no-print', + }, + options, + ) + + if (typeof dom === 'string') { + try { + this.dom = document.querySelector(dom) + } catch { + var createDom = document.createElement('div') + createDom.innerHTML = dom + this.dom = createDom + } + } else { + this.isDOM(dom) + this.dom = this.isDOM(dom) ? dom : dom.$el + } + + this.init() +} +Print.prototype = { + init: function () { + var content = this.getStyle() + this.getHtml() + this.writeIframe(content) + }, + extend: function (obj, obj2) { + for (var k in obj2) { + obj[k] = obj2[k] + } + return obj + }, + + getStyle: function () { + var str = '', + styles = document.querySelectorAll('style,link') + for (var i = 0; i < styles.length; i++) { + str += styles[i].outerHTML + } + str += '' + str += '' + return str + }, + + getHtml: function () { + var inputs = document.querySelectorAll('input') + var textareas = document.querySelectorAll('textarea') + var selects = document.querySelectorAll('select') + + for (var k = 0; k < inputs.length; k++) { + if (inputs[k].type == 'checkbox' || inputs[k].type == 'radio') { + if (inputs[k].checked == true) { + inputs[k].setAttribute('checked', 'checked') + } else { + inputs[k].removeAttribute('checked') + } + } else if (inputs[k].type == 'text') { + inputs[k].setAttribute('value', inputs[k].value) + } else { + inputs[k].setAttribute('value', inputs[k].value) + } + } + + for (var k2 = 0; k2 < textareas.length; k2++) { + if (textareas[k2].type == 'textarea') { + textareas[k2].innerHTML = textareas[k2].value + } + } + + for (var k3 = 0; k3 < selects.length; k3++) { + if (selects[k3].type == 'select-one') { + var child = selects[k3].children + for (var i in child) { + if (child[i].tagName == 'OPTION') { + if (child[i].selected == true) { + child[i].setAttribute('selected', 'selected') + } else { + child[i].removeAttribute('selected') + } + } + } + } + } + + return this.dom.outerHTML + }, + + writeIframe: function (content) { + var w, + doc, + iframe = document.createElement('iframe'), + f = document.body.appendChild(iframe) + iframe.id = 'myIframe' + //iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;"; + iframe.setAttribute('style', 'position:absolute;width:0;height:0;top:-10px;left:-10px;') + w = f.contentWindow || f.contentDocument + doc = f.contentDocument || f.contentWindow.document + doc.open() + doc.write(content) + doc.close() + var _this = this + iframe.onload = function () { + _this.toPrint(w) + setTimeout(function () { + document.body.removeChild(iframe) + }, 100) + } + }, + + toPrint: function (frameWindow) { + try { + setTimeout(function () { + frameWindow.focus() + try { + if (!frameWindow.document.execCommand('print', false, null)) { + frameWindow.print() + } + } catch (e) { + frameWindow.print() + } + frameWindow.close() + }, 10) + } catch (err) { + console.log('err', err) + } + }, + isDOM: + typeof HTMLElement === 'object' + ? function (obj) { + return obj instanceof HTMLElement + } + : function (obj) { + return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string' + }, +} + +export default Print \ No newline at end of file diff --git a/src/frontend/admin/src/utils/request.js b/src/frontend/admin/src/utils/request.js new file mode 100644 index 00000000..7f48982a --- /dev/null +++ b/src/frontend/admin/src/utils/request.js @@ -0,0 +1,279 @@ +import axios from 'axios' +import { ElMessageBox, ElNotification } from 'element-plus' +import sysConfig from '@/config' +import tool from '@/utils/tool' +import router from '@/router' +import { h } from 'vue' + +axios.defaults.baseURL = '' + +axios.defaults.timeout = sysConfig.TIMEOUT + +// HTTP request 拦截器 +axios.interceptors.request.use( + (config) => { + let accessToken = tool.cookie.get('ACCESS-TOKEN') + let refreshToken = tool.cookie.get('X-ACCESS-TOKEN') + if (accessToken) { + config.headers['Authorization'] = accessToken + } + if (refreshToken) { + config.headers['X-Authorization'] = refreshToken + } + if (!sysConfig.REQUEST_CACHE && config.method === 'get') { + config.params = config.params || {} + config.params['_'] = new Date().getTime() + } + Object.assign(config.headers, sysConfig.HEADERS) + + function removeEmpty(reqData, level) { + let deleted = false + Object.keys(reqData).forEach((x) => { + if (!reqData[x] && reqData[x] !== 0 && reqData[x] !== false) { + delete reqData[x] + deleted = true + } else if (typeof reqData[x] === 'object') { + if (Object.keys(reqData[x]).length === 0) { + delete reqData[x] + deleted = true + } else return removeEmpty(reqData[x], ++level) + } + }) + return deleted + } + + for (let i = 0; i !== 2; ++i) + while (removeEmpty(config.data ? config.data : {}, 0)) { + // + } + + return config + }, + (error) => { + return Promise.reject(error) + }, +) + +//FIX 多个API同时401时疯狂弹窗BUG +let MessageBox_401_show = false + +// HTTP response 拦截器 +axios.interceptors.response.use( + (response) => { + function setCookie(name, value) { + tool.cookie.set(name, 'Bearer ' + value, { + expires: tool.data.get('AUTO_LOGIN') ? 24 * 60 * 60 : 0, + }) + } + + if (response.headers['access-token']) { + setCookie('ACCESS-TOKEN', response.headers['access-token']) + } + if (response.headers['x-access-token']) { + setCookie('X-ACCESS-TOKEN', response.headers['x-access-token']) + } + return response + }, + (error) => { + if (error.response) { + if (error.response.status === 404) { + ElNotification.error({ + title: '请求错误', + message: 'Status:404,正在请求不存在的服务器记录!', + }) + } else if (error.response.status === 500) { + ElNotification.error({ + title: '请求错误', + message: error.response.data.message || 'Status:500,服务器发生错误!', + }) + } else if ([401, 403].includes(error.response.status)) { + if (!MessageBox_401_show && window.location.href.indexOf('anonymous') < 0) { + MessageBox_401_show = true + ElMessageBox.confirm('当前用户已被登出或无权限访问当前资源,请尝试重新登录后再操作。', '无权限访问', { + type: 'error', + closeOnClickModal: false, + center: true, + confirmButtonText: '重新登录', + beforeClose: (action, instance, done) => { + MessageBox_401_show = false + done() + }, + }) + .then(() => { + router.replace({ path: '/anonymous/login' }) + }) + .catch(() => {}) + } + } else if (error.response.status === 900) { + function showErr(msg) { + const title = axios.defaults.app().config.globalProperties.$GLOBAL.enums.errorCodes[error.response.data.code][1] + + ElNotification.error({ + title: title, + message: h('p', msg), + }) + } + + //业务错误 + if (typeof error.response.data.msg === 'object') { + Object.keys(error.response.data.msg).forEach((x) => { + showErr(error.response.data.msg[x]) + }) + } else { + showErr(error.response.data.msg) + } + } else { + ElNotification.error({ + title: '请求错误', + message: error.message || `Status:${error.response.status},未知错误!`, + }) + } + } else { + ElNotification.error({ + title: '请求错误', + message: '请求服务器无响应!', + }) + } + + return Promise.reject(error.response) + }, +) + +export default { + // axios对象 + axios: axios.defaults, + + /** get 请求 + * @param {string} url 接口地址 + * @param {object} params 请求参数 + * @param {object} config 参数 + */ + get: function (url, params = {}, config = {}) { + return new Promise((resolve, reject) => { + axios({ + method: 'get', + url: url, + params: params, + ...config, + }) + .then((response) => { + resolve(response.data) + }) + .catch((error) => { + reject(error) + }) + }) + }, + + /** post 请求 + * @param {string} url 接口地址 + * @param {object} data 请求参数 + * @param {object} config 参数 + */ + post: function (url, data = {}, config = {}) { + return new Promise((resolve, reject) => { + axios({ + method: 'post', + url: url, + data: data, + ...config, + }) + .then((response) => { + resolve(response.data) + }) + .catch((error) => { + reject(error) + }) + }) + }, + + /** put 请求 + * @param {string} url 接口地址 + * @param {object} data 请求参数 + * @param {object} config 参数 + */ + put: function (url, data = {}, config = {}) { + return new Promise((resolve, reject) => { + axios({ + method: 'put', + url: url, + data: data, + ...config, + }) + .then((response) => { + resolve(response.data) + }) + .catch((error) => { + reject(error) + }) + }) + }, + + /** patch 请求 + * @param {string} url 接口地址 + * @param {object} data 请求参数 + * @param {object} config 参数 + */ + patch: function (url, data = {}, config = {}) { + return new Promise((resolve, reject) => { + axios({ + method: 'patch', + url: url, + data: data, + ...config, + }) + .then((response) => { + resolve(response.data) + }) + .catch((error) => { + reject(error) + }) + }) + }, + + /** delete 请求 + * @param {string} url 接口地址 + * @param {object} data 请求参数 + * @param {object} config 参数 + */ + delete: function (url, data = {}, config = {}) { + return new Promise((resolve, reject) => { + axios({ + method: 'delete', + url: url, + data: data, + ...config, + }) + .then((response) => { + resolve(response.data) + }) + .catch((error) => { + reject(error) + }) + }) + }, + + /** jsonp 请求 + * @param {string} url 接口地址 + * @param {string} name JSONP回调函数名称 + */ + jsonp: function (url, name = 'jsonp') { + return new Promise((resolve) => { + var script = document.createElement('script') + var _id = `jsonp${Math.ceil(Math.random() * 1000000)}` + script.id = _id + script.type = 'text/javascript' + script.src = url + window[name] = (response) => { + resolve(response) + document.getElementsByTagName('head')[0].removeChild(script) + try { + delete window[name] + } catch (e) { + window[name] = undefined + } + } + document.getElementsByTagName('head')[0].appendChild(script) + }) + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/utils/template.js b/src/frontend/admin/src/utils/template.js new file mode 100644 index 00000000..4c306aea --- /dev/null +++ b/src/frontend/admin/src/utils/template.js @@ -0,0 +1,337 @@ +/*! + * template.js v0.7.1 (https://github.com/yanhaijing/template.js) + * API https://github.com/yanhaijing/template.js/blob/master/doc/api.md + * Copyright 2015 yanhaijing. All Rights Reserved + * Licensed under MIT (https://github.com/yanhaijing/template.js/blob/master/MIT-LICENSE.txt) + */ +/* eslint-disable */ +export default (function (root, factory) { + var template = factory(root) + if (typeof define === 'function' && define.amd) { + // AMD + define('template', function () { + return template + }) + } else if (typeof exports === 'object') { + // Node.js + module.exports = template + } else { + // Browser globals + var _template = root.template + + template.noConflict = function () { + if (root.template === template) { + root.template = _template + } + + return template + } + root.template = template + } +})(this, function (root) { + 'use strict' + var o = { + sTag: '<%', //开始标签 + eTag: '%>', //结束标签 + compress: false, //是否压缩html + escape: true, //默认输出是否进行HTML转义 + error: function (e) {}, //错误回调 + } + var functionMap = {} //内部函数对象 + //修饰器前缀 + var modifierMap = { + '': function (param) { + return nothing(param) + }, + h: function (param) { + return encodeHTML(param) + }, + u: function (param) { + return encodeURI(param) + }, + } + + var toString = {}.toString + var slice = [].slice + + function type(x) { + if (x === null) { + return 'null' + } + + var t = typeof x + + if (t !== 'object') { + return t + } + + var c = toString.call(x).slice(8, -1).toLowerCase() + if (c !== 'object') { + return c + } + + if (x.constructor == Object) { + return c + } + + return 'unknown' + } + + function isObject(obj) { + return type(obj) === 'object' + } + + function isFunction(fn) { + return type(fn) === 'function' + } + + function isString(str) { + return type(str) === 'string' + } + + function extend() { + var target = arguments[0] || {} + var arrs = slice.call(arguments, 1) + var len = arrs.length + + for (var i = 0; i < len; i++) { + var arr = arrs[i] + for (var name in arr) { + target[name] = arr[name] + } + } + return target + } + + function clone() { + var args = slice.call(arguments) + return extend.apply(null, [{}].concat(args)) + } + + function nothing(param) { + return param + } + + function encodeHTML(source) { + return String(source) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/\\/g, '\') + .replace(/"/g, '"') + .replace(/'/g, ''') + } + + function compress(html) { + return html.replace(/\s+/g, ' ').replace(//g, '') + } + + function consoleAdapter(cmd, msg) { + typeof console !== 'undefined' && console[cmd] && console[cmd](msg) + } + + function handelError(e) { + var message = 'template.js error\n\n' + + for (var key in e) { + message += '<' + key + '>\n' + e[key] + '\n\n' + } + message += '\n' + e.message + '\n\n' + consoleAdapter('error', message) + + o.error(e) + + function error() { + return 'template.js error' + } + + error.toString = function () { + return '__code__ = "template.js error"' + } + return error + } + + function parse(tpl, opt) { + var code = '' + var sTag = opt.sTag + var eTag = opt.eTag + var escape = opt.escape + + function parsehtml(line) { + // 单双引号转义,换行符替换为空格 + line = line.replace(/('|")/g, '\\$1') + var lineList = line.split('\n') + var code = '' + for (var i = 0; i < lineList.length; i++) { + code += ';__code__ += ("' + lineList[i] + (i === lineList.length - 1 ? '")\n' : '\\n")\n') + } + return code + } + + function parsejs(line) { + //var reg = /^(:?)(.*?)=(.*)$/; + var reg = /^(?:=|(:.*?)=)(.*)$/ + var html + var arr + var modifier + + // = := :*= + // :h=123 [':h=123', 'h', '123'] + if ((arr = reg.exec(line))) { + html = arr[2] // 输出 + if (Boolean(arr[1])) { + // :开头 + modifier = arr[1].slice(1) + } else { + // = 开头 + modifier = escape ? 'h' : '' + } + + return ';__code__ += __modifierMap__["' + modifier + '"](typeof (' + html + ') !== "undefined" ? (' + html + ') : "")\n' + } + + //原生js + return ';' + line + '\n' + } + + var tokens = tpl.split(sTag) + + for (var i = 0, len = tokens.length; i < len; i++) { + var token = tokens[i].split(eTag) + + if (token.length === 1) { + code += parsehtml(token[0]) + } else { + code += parsejs(token[0], true) + if (token[1]) { + code += parsehtml(token[1]) + } + } + } + return code + } + + function compiler(tpl, opt) { + var mainCode = parse(tpl, opt) + + var headerCode = + '\n' + + ' var html = (function (__data__, __modifierMap__) {\n' + + ' var __str__ = "", __code__ = "";\n' + + ' for(var key in __data__) {\n' + + ' __str__+=("var " + key + "=__data__[\'" + key + "\'];");\n' + + ' }\n' + + ' eval(__str__);\n\n' + + var footerCode = '\n' + ' ;return __code__;\n' + ' }(__data__, __modifierMap__));\n' + ' return html;\n' + + var code = headerCode + mainCode + footerCode + code = code.replace(/[\r]/g, ' ') // ie 7 8 会报错,不知道为什么 + try { + var Render = new Function('__data__', '__modifierMap__', code) + Render.toString = function () { + return mainCode + } + return Render + } catch (e) { + e.temp = 'function anonymous(__data__, __modifierMap__) {' + code + '}' + throw e + } + } + + function compile(tpl, opt) { + opt = clone(o, opt) + + try { + var Render = compiler(tpl, opt) + } catch (e) { + e.name = 'CompileError' + e.tpl = tpl + e.render = e.temp + delete e.temp + return handelError(e) + } + + function render(data) { + data = clone(functionMap, data) + try { + var html = Render(data, modifierMap) + html = opt.compress ? compress(html) : html + return html + } catch (e) { + e.name = 'RenderError' + e.tpl = tpl + e.render = Render.toString() + return handelError(e)() + } + } + + render.toString = function () { + return Render.toString() + } + return render + } + + function template(tpl, data) { + if (typeof tpl !== 'string') { + return '' + } + + var fn = compile(tpl) + if (!isObject(data)) { + return fn + } + + return fn(data) + } + + template.config = function (option) { + if (isObject(option)) { + o = extend(o, option) + } + return clone(o) + } + + template.registerFunction = function (name, fn) { + if (!isString(name)) { + return clone(functionMap) + } + if (!isFunction(fn)) { + return functionMap[name] + } + + return (functionMap[name] = fn) + } + template.unregisterFunction = function (name) { + if (!isString(name)) { + return false + } + delete functionMap[name] + return true + } + + template.registerModifier = function (name, fn) { + if (!isString(name)) { + return clone(modifierMap) + } + if (!isFunction(fn)) { + return modifierMap[name] + } + + return (modifierMap[name] = fn) + } + template.unregisterModifier = function (name) { + if (!isString(name)) { + return false + } + delete modifierMap[name] + return true + } + + template.__encodeHTML = encodeHTML + template.__compress = compress + template.__handelError = handelError + template.__compile = compile + template.version = '0.7.1' + return template +}) \ No newline at end of file diff --git a/src/frontend/admin/src/utils/tool.js b/src/frontend/admin/src/utils/tool.js new file mode 100644 index 00000000..1d1d78f1 --- /dev/null +++ b/src/frontend/admin/src/utils/tool.js @@ -0,0 +1,288 @@ +/* + * @Descripttion: 工具集 + * @version: 1.2 + * @LastEditors: Xujianchen + * @LastEditTime: 2023-03-19 11:17:54 + */ + +import CryptoJS from 'crypto-js' +import sysConfig from '@/config' + +const tool = {} + +/* localStorage */ +tool.data = { + set(key, data, datetime = 0) { + //加密 + if (sysConfig.LS_ENCRYPTION === 'AES') { + data = tool.crypto.AES.encrypt(JSON.stringify(data), sysConfig.LS_ENCRYPTION_key) + } + let cacheValue = { + content: data, + datetime: parseInt(datetime) === 0 ? 0 : new Date().getTime() + parseInt(datetime) * 1000, + } + return localStorage.setItem(key, JSON.stringify(cacheValue)) + }, + get(key) { + try { + const value = JSON.parse(localStorage.getItem(key)) + if (value) { + let nowTime = new Date().getTime() + if (nowTime > value.datetime && value.datetime !== 0) { + localStorage.removeItem(key) + return null + } + //解密 + if (sysConfig.LS_ENCRYPTION === 'AES') { + value.content = JSON.parse(tool.crypto.AES.decrypt(value.content, sysConfig.LS_ENCRYPTION_key)) + } + return value.content + } + return null + } catch (err) { + return null + } + }, + remove(key) { + return localStorage.removeItem(key) + }, + clear() { + return localStorage.clear() + }, +} + +/*sessionStorage*/ +tool.session = { + set(table, settings) { + var _set = JSON.stringify(settings) + return sessionStorage.setItem(table, _set) + }, + get(table) { + var data = sessionStorage.getItem(table) + try { + data = JSON.parse(data) + } catch (err) { + return null + } + return data + }, + remove(table) { + return sessionStorage.removeItem(table) + }, + clear() { + return sessionStorage.clear() + }, +} + +/*cookie*/ +tool.cookie = { + set(name, value, config = {}) { + var cfg = { + expires: null, + path: null, + domain: null, + secure: false, + httpOnly: false, + ...config, + } + var cookieStr = `${name}=${escape(value)}` + if (cfg.expires) { + var exp = new Date() + exp.setTime(exp.getTime() + parseInt(cfg.expires) * 1000) + cookieStr += `;expires=${exp.toGMTString()}` + } + if (cfg.path) { + cookieStr += `;path=${cfg.path}` + } + if (cfg.domain) { + cookieStr += `;domain=${cfg.domain}` + } + document.cookie = cookieStr + }, + get(name) { + var arr = document.cookie.match(new RegExp('(^| )' + name + '=([^;]*)(;|$)')) + if (arr !== null) { + return unescape(arr[2]) + } else { + return null + } + }, + remove(name) { + var exp = new Date() + exp.setTime(exp.getTime() - 1) + document.cookie = `${name}=;expires=${exp.toGMTString()}` + }, + clear() { + const cookies = document.cookie.split(';') + const pastDate = new Date(0).toUTCString() + + cookies.forEach((cookie) => { + const [name, value] = cookie.split('=') + document.cookie = `${name.trim()}=${encodeURIComponent(value.trim())}; expires=${pastDate}; path=/` + }) + }, +} + +/* Fullscreen */ +tool.screen = function (element) { + var isFull = !!(document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement || document.fullscreenElement) + if (isFull) { + if (document.exitFullscreen) { + document.exitFullscreen() + } else if (document.msExitFullscreen) { + document.msExitFullscreen() + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen() + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen() + } + } else { + if (element.requestFullscreen) { + element.requestFullscreen() + } else if (element.msRequestFullscreen) { + element.msRequestFullscreen() + } else if (element.mozRequestFullScreen) { + element.mozRequestFullScreen() + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen() + } + } +} + +/* 复制对象 */ +tool.objCopy = function (obj) { + return JSON.parse(JSON.stringify(obj)) +} + +/* 日期格式化 */ +tool.dateFormat = function (date, fmt = 'yyyy-MM-dd hh:mm:ss') { + date = new Date(date) + var o = { + 'M+': date.getMonth() + 1, //月份 + 'd+': date.getDate(), //日 + 'h+': date.getHours(), //小时 + 'm+': date.getMinutes(), //分 + 's+': date.getSeconds(), //秒 + 'q+': Math.floor((date.getMonth() + 3) / 3), //季度 + S: date.getMilliseconds(), //毫秒 + } + if (/(y+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)) + } + for (var k in o) { + if (new RegExp('(' + k + ')').test(fmt)) { + fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)) + } + } + return fmt +} + +/* 千分符 */ +tool.groupSeparator = function (num) { + num = num + '' + if (!num.includes('.')) { + num += '.' + } + return num + .replace(/(\d)(?=(\d{3})+\.)/g, function ($0, $1) { + return $1 + ',' + }) + .replace(/\.$/, '') +} +// 属性排序 +tool.sortProperties = function (obj) { + const sortedKeys = Object.keys(obj).sort() + const sortedObject = {} + + for (const key of sortedKeys) { + sortedObject[key] = obj[key] + } + + return sortedObject +} + +//TAB 刷新 +tool.refreshTab = function (_this) { + _this.$parent.keepAliveList = [] + _this.contextMenuVisible = false + const tag = _this.$store.state.viewTags.viewTags.find((x) => x.fullPath === _this.$route.fullPath) + //判断是否当前路由,否的话跳转 + if (_this.$route.fullPath !== tag.fullPath) { + _this.$router.push({ + path: tag.fullPath, + query: tag.query, + }) + } + _this.$store.commit('refreshIframe', tag) + setTimeout(() => { + _this.$store.commit('removeKeepLive', tag.name) + _this.$store.commit('setRouteShow', false) + _this.$nextTick(() => { + _this.$store.commit('pushKeepLive', tag.name) + _this.$store.commit('setRouteShow', true) + + setTimeout(() => { + _this.$parent.keepAliveList = null + }, 100) + }) + }, 0) +} + +/* 常用加解密 */ +tool.crypto = { + stringToInt32(inputString) { + let int32Value = 0 + for (let i = 0; i < 4; i++) { + const charCode = inputString.charCodeAt(i) + int32Value <<= 8 // 左移8位 + int32Value += charCode + } + return int32Value + }, + generateDerivedKey(seed) { + const chars = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~' + let key = '' + for (let i = 0; i < 32; i++) { + key += chars[Math.floor(Math.abs(Math.sin(this.stringToInt32(seed) * (i + 1))) * chars.length)] + } + return key + }, + + //MD5加密 + MD5(data) { + return CryptoJS.MD5(data).toString() + }, + //BASE64加解密 + BASE64: { + encrypt(data) { + return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data)) + }, + decrypt(cipher) { + return CryptoJS.enc.Base64.parse(cipher).toString(CryptoJS.enc.Utf8) + }, + }, + //AES加解密 + AES: { + encrypt(data, secretKey, config = {}) { + if (secretKey.length % 8 !== 0) { + console.warn('[SCUI error]: 秘钥长度需为8的倍数,否则解密将会失败。') + } + const result = CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse(secretKey), { + iv: CryptoJS.enc.Utf8.parse(config.iv || ''), + mode: CryptoJS.mode[config.mode || 'ECB'], + padding: CryptoJS.pad[config.padding || 'Pkcs7'], + }) + return result.toString() + }, + decrypt(cipher, secretKey, config = {}) { + const result = CryptoJS.AES.decrypt(cipher, CryptoJS.enc.Utf8.parse(secretKey), { + iv: CryptoJS.enc.Utf8.parse(config.iv || ''), + mode: CryptoJS.mode[config.mode || 'ECB'], + padding: CryptoJS.pad[config.padding || 'Pkcs7'], + }) + return CryptoJS.enc.Utf8.stringify(result) + }, + }, +} + +export default tool \ No newline at end of file diff --git a/src/frontend/admin/src/utils/useTabs.js b/src/frontend/admin/src/utils/useTabs.js new file mode 100644 index 00000000..252dc7be --- /dev/null +++ b/src/frontend/admin/src/utils/useTabs.js @@ -0,0 +1,61 @@ +import { nextTick } from 'vue' +import NProgress from 'nprogress' +import 'nprogress/nprogress.css' +import router from '@/router' +import store from '@/store' + +export default { + //刷新标签 + refresh() { + NProgress.start() + const route = router.currentRoute.value + store.commit('removeKeepLive', route.name) + store.commit('setRouteShow', false) + nextTick(() => { + store.commit('pushKeepLive', route.name) + store.commit('setRouteShow', true) + NProgress.done() + }) + }, + //关闭标签 + close(tag) { + const route = tag || router.currentRoute.value + store.commit('removeViewTags', route) + store.commit('removeIframeList', route) + store.commit('removeKeepLive', route.name) + const tagList = store.state.viewTags.viewTags + const latestView = tagList.slice(-1)[0] + if (latestView) { + router.push(latestView) + } else { + router.push('/') + } + }, + //关闭标签后处理 + closeNext(next) { + const route = router.currentRoute.value + store.commit('removeViewTags', route) + store.commit('removeIframeList', route) + store.commit('removeKeepLive', route.name) + if (next) { + const tagList = store.state.viewTags.viewTags + next(tagList) + } + }, + //关闭其他 + closeOther() { + const route = router.currentRoute.value + const tagList = [...store.state.viewTags.viewTags] + tagList.forEach((tag) => { + if ((tag.meta && tag.meta.affix) || route.fullPath === tag.fullPath) { + return true + } else { + this.close(tag) + } + }) + }, + //设置标题 + setTitle(title) { + store.commit('updateViewTagsTitle', title) + }, +} \ No newline at end of file diff --git a/src/frontend/admin/src/utils/verificate.js b/src/frontend/admin/src/utils/verificate.js new file mode 100644 index 00000000..454586aa --- /dev/null +++ b/src/frontend/admin/src/utils/verificate.js @@ -0,0 +1,17 @@ +//验证手机号 +export function verifyPhone(rule, value, callback) { + let reg = /^[1][3, 4, 5, 6, 7, 8, 9][0-9]{9}$/ + if (!reg.test(value)) { + return callback(new Error('请输入正确的手机号码')) + } + callback() +} + +//车牌号码 +export function verifyCars(rule, value, callback) { + let reg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-HJ-NP-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$/ + if (!reg.test(value)) { + return callback(new Error('请输入正确的车牌号码')) + } + callback() +} \ No newline at end of file diff --git a/src/frontend/admin/src/views/anonymous/components/commonPage.vue b/src/frontend/admin/src/views/anonymous/components/commonPage.vue new file mode 100644 index 00000000..cd0cadee --- /dev/null +++ b/src/frontend/admin/src/views/anonymous/components/commonPage.vue @@ -0,0 +1,34 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/anonymous/components/passwordForm.vue b/src/frontend/admin/src/views/anonymous/components/passwordForm.vue new file mode 100644 index 00000000..a795c306 --- /dev/null +++ b/src/frontend/admin/src/views/anonymous/components/passwordForm.vue @@ -0,0 +1,72 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/anonymous/components/phoneForm.vue b/src/frontend/admin/src/views/anonymous/components/phoneForm.vue new file mode 100644 index 00000000..3aadbb0d --- /dev/null +++ b/src/frontend/admin/src/views/anonymous/components/phoneForm.vue @@ -0,0 +1,53 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/anonymous/login.vue b/src/frontend/admin/src/views/anonymous/login.vue new file mode 100644 index 00000000..031d066c --- /dev/null +++ b/src/frontend/admin/src/views/anonymous/login.vue @@ -0,0 +1,361 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/anonymous/register.vue b/src/frontend/admin/src/views/anonymous/register.vue new file mode 100644 index 00000000..724193ce --- /dev/null +++ b/src/frontend/admin/src/views/anonymous/register.vue @@ -0,0 +1,165 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/anonymous/resetPassword.vue b/src/frontend/admin/src/views/anonymous/resetPassword.vue new file mode 100644 index 00000000..9f8d3fca --- /dev/null +++ b/src/frontend/admin/src/views/anonymous/resetPassword.vue @@ -0,0 +1,92 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/dev/code/index.vue b/src/frontend/admin/src/views/dev/code/index.vue new file mode 100644 index 00000000..1ef94871 --- /dev/null +++ b/src/frontend/admin/src/views/dev/code/index.vue @@ -0,0 +1,175 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/dev/code/list.vue b/src/frontend/admin/src/views/dev/code/list.vue new file mode 100644 index 00000000..ce7a489b --- /dev/null +++ b/src/frontend/admin/src/views/dev/code/list.vue @@ -0,0 +1,310 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/home/index.vue b/src/frontend/admin/src/views/home/index.vue new file mode 100644 index 00000000..6d06dae7 --- /dev/null +++ b/src/frontend/admin/src/views/home/index.vue @@ -0,0 +1,45 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/home/widgets/components/about.vue b/src/frontend/admin/src/views/home/widgets/components/about.vue new file mode 100644 index 00000000..5ff4535c --- /dev/null +++ b/src/frontend/admin/src/views/home/widgets/components/about.vue @@ -0,0 +1,29 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/home/widgets/components/echarts.vue b/src/frontend/admin/src/views/home/widgets/components/echarts.vue new file mode 100644 index 00000000..fa72e929 --- /dev/null +++ b/src/frontend/admin/src/views/home/widgets/components/echarts.vue @@ -0,0 +1,97 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/home/widgets/components/index.js b/src/frontend/admin/src/views/home/widgets/components/index.js new file mode 100644 index 00000000..64c6f246 --- /dev/null +++ b/src/frontend/admin/src/views/home/widgets/components/index.js @@ -0,0 +1,16 @@ +/* + * @Author: Xujianchen + * @Date: 2023-02-28 14:12:15 + * @LastEditors: Xujianchen + * @LastEditTime: 2023-03-18 12:45:04 + * @Description: + */ +import {markRaw} from 'vue' + +const resultComps = {} +const files = import.meta.globEager('./*.vue') +Object.keys(files).forEach((fileName) => { + let comp = files[fileName] + resultComps[fileName.replace(/^\.\/(.*)\.\w+$/, '$1')] = comp.default +}) +export default markRaw(resultComps) \ No newline at end of file diff --git a/src/frontend/admin/src/views/home/widgets/components/progress.vue b/src/frontend/admin/src/views/home/widgets/components/progress.vue new file mode 100644 index 00000000..fb15efde --- /dev/null +++ b/src/frontend/admin/src/views/home/widgets/components/progress.vue @@ -0,0 +1,38 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/home/widgets/components/time.vue b/src/frontend/admin/src/views/home/widgets/components/time.vue new file mode 100644 index 00000000..63f193a0 --- /dev/null +++ b/src/frontend/admin/src/views/home/widgets/components/time.vue @@ -0,0 +1,51 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/home/widgets/components/ver.vue b/src/frontend/admin/src/views/home/widgets/components/ver.vue new file mode 100644 index 00000000..f1fe0c75 --- /dev/null +++ b/src/frontend/admin/src/views/home/widgets/components/ver.vue @@ -0,0 +1,41 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/home/widgets/components/welcome.vue b/src/frontend/admin/src/views/home/widgets/components/welcome.vue new file mode 100644 index 00000000..d94433b9 --- /dev/null +++ b/src/frontend/admin/src/views/home/widgets/components/welcome.vue @@ -0,0 +1,111 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/home/widgets/index.vue b/src/frontend/admin/src/views/home/widgets/index.vue new file mode 100644 index 00000000..21d344e5 --- /dev/null +++ b/src/frontend/admin/src/views/home/widgets/index.vue @@ -0,0 +1,486 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/home/work/components/myapp.vue b/src/frontend/admin/src/views/home/work/components/myapp.vue new file mode 100644 index 00000000..92195a86 --- /dev/null +++ b/src/frontend/admin/src/views/home/work/components/myapp.vue @@ -0,0 +1,226 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/home/work/index.vue b/src/frontend/admin/src/views/home/work/index.vue new file mode 100644 index 00000000..ccf20d70 --- /dev/null +++ b/src/frontend/admin/src/views/home/work/index.vue @@ -0,0 +1,30 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/other/about.vue b/src/frontend/admin/src/views/other/about.vue new file mode 100644 index 00000000..5cc1d957 --- /dev/null +++ b/src/frontend/admin/src/views/other/about.vue @@ -0,0 +1,73 @@ + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/other/directive.vue b/src/frontend/admin/src/views/other/directive.vue new file mode 100644 index 00000000..a117ca30 --- /dev/null +++ b/src/frontend/admin/src/views/other/directive.vue @@ -0,0 +1,59 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/other/fullpage.vue b/src/frontend/admin/src/views/other/fullpage.vue new file mode 100644 index 00000000..5bfe3da5 --- /dev/null +++ b/src/frontend/admin/src/views/other/fullpage.vue @@ -0,0 +1,27 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/other/loadJS.vue b/src/frontend/admin/src/views/other/loadJS.vue new file mode 100644 index 00000000..807a4587 --- /dev/null +++ b/src/frontend/admin/src/views/other/loadJS.vue @@ -0,0 +1,56 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/other/verificate.vue b/src/frontend/admin/src/views/other/verificate.vue new file mode 100644 index 00000000..5ab1ba79 --- /dev/null +++ b/src/frontend/admin/src/views/other/verificate.vue @@ -0,0 +1,126 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/other/viewTags.vue b/src/frontend/admin/src/views/other/viewTags.vue new file mode 100644 index 00000000..ee7ee559 --- /dev/null +++ b/src/frontend/admin/src/views/other/viewTags.vue @@ -0,0 +1,83 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/profile/index.vue b/src/frontend/admin/src/views/profile/index.vue new file mode 100644 index 00000000..b841cc4e --- /dev/null +++ b/src/frontend/admin/src/views/profile/index.vue @@ -0,0 +1,107 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/profile/user/account.vue b/src/frontend/admin/src/views/profile/user/account.vue new file mode 100644 index 00000000..a8a15421 --- /dev/null +++ b/src/frontend/admin/src/views/profile/user/account.vue @@ -0,0 +1,93 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/profile/user/logs.vue b/src/frontend/admin/src/views/profile/user/logs.vue new file mode 100644 index 00000000..3517e164 --- /dev/null +++ b/src/frontend/admin/src/views/profile/user/logs.vue @@ -0,0 +1,38 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/profile/user/pushSettings.vue b/src/frontend/admin/src/views/profile/user/pushSettings.vue new file mode 100644 index 00000000..1ac328ae --- /dev/null +++ b/src/frontend/admin/src/views/profile/user/pushSettings.vue @@ -0,0 +1,29 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/profile/user/setEmail.vue b/src/frontend/admin/src/views/profile/user/setEmail.vue new file mode 100644 index 00000000..19d9119d --- /dev/null +++ b/src/frontend/admin/src/views/profile/user/setEmail.vue @@ -0,0 +1,95 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/profile/user/setMobile.vue b/src/frontend/admin/src/views/profile/user/setMobile.vue new file mode 100644 index 00000000..02f3d14c --- /dev/null +++ b/src/frontend/admin/src/views/profile/user/setMobile.vue @@ -0,0 +1,107 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/profile/user/setPassword.vue b/src/frontend/admin/src/views/profile/user/setPassword.vue new file mode 100644 index 00000000..813793bb --- /dev/null +++ b/src/frontend/admin/src/views/profile/user/setPassword.vue @@ -0,0 +1,74 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/profile/user/settings.vue b/src/frontend/admin/src/views/profile/user/settings.vue new file mode 100644 index 00000000..f5dd3e5d --- /dev/null +++ b/src/frontend/admin/src/views/profile/user/settings.vue @@ -0,0 +1,99 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/profile/user/space.vue b/src/frontend/admin/src/views/profile/user/space.vue new file mode 100644 index 00000000..abbb8aaa --- /dev/null +++ b/src/frontend/admin/src/views/profile/user/space.vue @@ -0,0 +1,54 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/client/index.vue b/src/frontend/admin/src/views/setting/client/index.vue new file mode 100644 index 00000000..509adbda --- /dev/null +++ b/src/frontend/admin/src/views/setting/client/index.vue @@ -0,0 +1,126 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/client/save.vue b/src/frontend/admin/src/views/setting/client/save.vue new file mode 100644 index 00000000..aa29e92e --- /dev/null +++ b/src/frontend/admin/src/views/setting/client/save.vue @@ -0,0 +1,98 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/dept/index.vue b/src/frontend/admin/src/views/setting/dept/index.vue new file mode 100644 index 00000000..529651be --- /dev/null +++ b/src/frontend/admin/src/views/setting/dept/index.vue @@ -0,0 +1,150 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/dept/save.vue b/src/frontend/admin/src/views/setting/dept/save.vue new file mode 100644 index 00000000..57ef1c1f --- /dev/null +++ b/src/frontend/admin/src/views/setting/dept/save.vue @@ -0,0 +1,117 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/dic/dic.vue b/src/frontend/admin/src/views/setting/dic/dic.vue new file mode 100644 index 00000000..8c693df3 --- /dev/null +++ b/src/frontend/admin/src/views/setting/dic/dic.vue @@ -0,0 +1,98 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/dic/index.vue b/src/frontend/admin/src/views/setting/dic/index.vue new file mode 100644 index 00000000..77a1aaa3 --- /dev/null +++ b/src/frontend/admin/src/views/setting/dic/index.vue @@ -0,0 +1,383 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/dic/list.vue b/src/frontend/admin/src/views/setting/dic/list.vue new file mode 100644 index 00000000..e12cf662 --- /dev/null +++ b/src/frontend/admin/src/views/setting/dic/list.vue @@ -0,0 +1,104 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/log/index.vue b/src/frontend/admin/src/views/setting/log/index.vue new file mode 100644 index 00000000..8f76bef6 --- /dev/null +++ b/src/frontend/admin/src/views/setting/log/index.vue @@ -0,0 +1,165 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/log/info.vue b/src/frontend/admin/src/views/setting/log/info.vue new file mode 100644 index 00000000..3a3cd8a9 --- /dev/null +++ b/src/frontend/admin/src/views/setting/log/info.vue @@ -0,0 +1,57 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/menu/index.vue b/src/frontend/admin/src/views/setting/menu/index.vue new file mode 100644 index 00000000..36ce0837 --- /dev/null +++ b/src/frontend/admin/src/views/setting/menu/index.vue @@ -0,0 +1,209 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/menu/save.vue b/src/frontend/admin/src/views/setting/menu/save.vue new file mode 100644 index 00000000..ea5f03cf --- /dev/null +++ b/src/frontend/admin/src/views/setting/menu/save.vue @@ -0,0 +1,205 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/role/index.vue b/src/frontend/admin/src/views/setting/role/index.vue new file mode 100644 index 00000000..c48cf5fb --- /dev/null +++ b/src/frontend/admin/src/views/setting/role/index.vue @@ -0,0 +1,179 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/role/permission.vue b/src/frontend/admin/src/views/setting/role/permission.vue new file mode 100644 index 00000000..17d340a6 --- /dev/null +++ b/src/frontend/admin/src/views/setting/role/permission.vue @@ -0,0 +1,200 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/role/save.vue b/src/frontend/admin/src/views/setting/role/save.vue new file mode 100644 index 00000000..f8252eeb --- /dev/null +++ b/src/frontend/admin/src/views/setting/role/save.vue @@ -0,0 +1,98 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/system/index.vue b/src/frontend/admin/src/views/setting/system/index.vue new file mode 100644 index 00000000..281db42b --- /dev/null +++ b/src/frontend/admin/src/views/setting/system/index.vue @@ -0,0 +1,177 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/table/index.vue b/src/frontend/admin/src/views/setting/table/index.vue new file mode 100644 index 00000000..ad2b8bd3 --- /dev/null +++ b/src/frontend/admin/src/views/setting/table/index.vue @@ -0,0 +1,118 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/table/save.vue b/src/frontend/admin/src/views/setting/table/save.vue new file mode 100644 index 00000000..0be81cf7 --- /dev/null +++ b/src/frontend/admin/src/views/setting/table/save.vue @@ -0,0 +1,177 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/task/index.vue b/src/frontend/admin/src/views/setting/task/index.vue new file mode 100644 index 00000000..8dd635ed --- /dev/null +++ b/src/frontend/admin/src/views/setting/task/index.vue @@ -0,0 +1,229 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/task/logs.vue b/src/frontend/admin/src/views/setting/task/logs.vue new file mode 100644 index 00000000..949515eb --- /dev/null +++ b/src/frontend/admin/src/views/setting/task/logs.vue @@ -0,0 +1,111 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/task/save.vue b/src/frontend/admin/src/views/setting/task/save.vue new file mode 100644 index 00000000..02c57b89 --- /dev/null +++ b/src/frontend/admin/src/views/setting/task/save.vue @@ -0,0 +1,104 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/user/index.vue b/src/frontend/admin/src/views/setting/user/index.vue new file mode 100644 index 00000000..c588bf72 --- /dev/null +++ b/src/frontend/admin/src/views/setting/user/index.vue @@ -0,0 +1,217 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/setting/user/save.vue b/src/frontend/admin/src/views/setting/user/save.vue new file mode 100644 index 00000000..32767335 --- /dev/null +++ b/src/frontend/admin/src/views/setting/user/save.vue @@ -0,0 +1,159 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/api/index.vue b/src/frontend/admin/src/views/sys/api/index.vue new file mode 100644 index 00000000..6763ebcc --- /dev/null +++ b/src/frontend/admin/src/views/sys/api/index.vue @@ -0,0 +1,71 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/cache/index.vue b/src/frontend/admin/src/views/sys/cache/index.vue new file mode 100644 index 00000000..ac06d0ba --- /dev/null +++ b/src/frontend/admin/src/views/sys/cache/index.vue @@ -0,0 +1,148 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/config/index.vue b/src/frontend/admin/src/views/sys/config/index.vue new file mode 100644 index 00000000..75118948 --- /dev/null +++ b/src/frontend/admin/src/views/sys/config/index.vue @@ -0,0 +1,140 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/config/save.vue b/src/frontend/admin/src/views/sys/config/save.vue new file mode 100644 index 00000000..2bad2e69 --- /dev/null +++ b/src/frontend/admin/src/views/sys/config/save.vue @@ -0,0 +1,108 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/dept/index.vue b/src/frontend/admin/src/views/sys/dept/index.vue new file mode 100644 index 00000000..e9c3bdc7 --- /dev/null +++ b/src/frontend/admin/src/views/sys/dept/index.vue @@ -0,0 +1,167 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/dept/save.vue b/src/frontend/admin/src/views/sys/dept/save.vue new file mode 100644 index 00000000..5a7b7ce2 --- /dev/null +++ b/src/frontend/admin/src/views/sys/dept/save.vue @@ -0,0 +1,121 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/dic/index.vue b/src/frontend/admin/src/views/sys/dic/index.vue new file mode 100644 index 00000000..5aab81f3 --- /dev/null +++ b/src/frontend/admin/src/views/sys/dic/index.vue @@ -0,0 +1,158 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/dic/list/index.vue b/src/frontend/admin/src/views/sys/dic/list/index.vue new file mode 100644 index 00000000..0e8af6ce --- /dev/null +++ b/src/frontend/admin/src/views/sys/dic/list/index.vue @@ -0,0 +1,145 @@ + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/dic/list/save.vue b/src/frontend/admin/src/views/sys/dic/list/save.vue new file mode 100644 index 00000000..1b740ce4 --- /dev/null +++ b/src/frontend/admin/src/views/sys/dic/list/save.vue @@ -0,0 +1,88 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/dic/save.vue b/src/frontend/admin/src/views/sys/dic/save.vue new file mode 100644 index 00000000..c4f00d0a --- /dev/null +++ b/src/frontend/admin/src/views/sys/dic/save.vue @@ -0,0 +1,74 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/log/index.vue b/src/frontend/admin/src/views/sys/log/index.vue new file mode 100644 index 00000000..e565f963 --- /dev/null +++ b/src/frontend/admin/src/views/sys/log/index.vue @@ -0,0 +1,172 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/menu/index.vue b/src/frontend/admin/src/views/sys/menu/index.vue new file mode 100644 index 00000000..01326029 --- /dev/null +++ b/src/frontend/admin/src/views/sys/menu/index.vue @@ -0,0 +1,194 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/menu/save.vue b/src/frontend/admin/src/views/sys/menu/save.vue new file mode 100644 index 00000000..86df1126 --- /dev/null +++ b/src/frontend/admin/src/views/sys/menu/save.vue @@ -0,0 +1,163 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/role/index.vue b/src/frontend/admin/src/views/sys/role/index.vue new file mode 100644 index 00000000..471a04ae --- /dev/null +++ b/src/frontend/admin/src/views/sys/role/index.vue @@ -0,0 +1,221 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/role/save.vue b/src/frontend/admin/src/views/sys/role/save.vue new file mode 100644 index 00000000..bf30510a --- /dev/null +++ b/src/frontend/admin/src/views/sys/role/save.vue @@ -0,0 +1,177 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/user/index.vue b/src/frontend/admin/src/views/sys/user/index.vue new file mode 100644 index 00000000..e011e881 --- /dev/null +++ b/src/frontend/admin/src/views/sys/user/index.vue @@ -0,0 +1,162 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/sys/user/save.vue b/src/frontend/admin/src/views/sys/user/save.vue new file mode 100644 index 00000000..bce6c0b2 --- /dev/null +++ b/src/frontend/admin/src/views/sys/user/save.vue @@ -0,0 +1,344 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/layout/blank.vue b/src/frontend/admin/src/views/template/layout/blank.vue new file mode 100644 index 00000000..d1e15678 --- /dev/null +++ b/src/frontend/admin/src/views/template/layout/blank.vue @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/layout/layoutLCR.vue b/src/frontend/admin/src/views/template/layout/layoutLCR.vue new file mode 100644 index 00000000..d0021585 --- /dev/null +++ b/src/frontend/admin/src/views/template/layout/layoutLCR.vue @@ -0,0 +1,39 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/layout/layoutTCB.vue b/src/frontend/admin/src/views/template/layout/layoutTCB.vue new file mode 100644 index 00000000..0ff7128a --- /dev/null +++ b/src/frontend/admin/src/views/template/layout/layoutTCB.vue @@ -0,0 +1,23 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/list/crud/detail.vue b/src/frontend/admin/src/views/template/list/crud/detail.vue new file mode 100644 index 00000000..0e8df403 --- /dev/null +++ b/src/frontend/admin/src/views/template/list/crud/detail.vue @@ -0,0 +1,43 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/list/crud/index.vue b/src/frontend/admin/src/views/template/list/crud/index.vue new file mode 100644 index 00000000..d306b3ee --- /dev/null +++ b/src/frontend/admin/src/views/template/list/crud/index.vue @@ -0,0 +1,153 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/list/crud/info.vue b/src/frontend/admin/src/views/template/list/crud/info.vue new file mode 100644 index 00000000..c5f4d16e --- /dev/null +++ b/src/frontend/admin/src/views/template/list/crud/info.vue @@ -0,0 +1,30 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/list/crud/save.vue b/src/frontend/admin/src/views/template/list/crud/save.vue new file mode 100644 index 00000000..3d99db94 --- /dev/null +++ b/src/frontend/admin/src/views/template/list/crud/save.vue @@ -0,0 +1,109 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/list/son.vue b/src/frontend/admin/src/views/template/list/son.vue new file mode 100644 index 00000000..6ee1cd47 --- /dev/null +++ b/src/frontend/admin/src/views/template/list/son.vue @@ -0,0 +1,73 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/list/tab.vue b/src/frontend/admin/src/views/template/list/tab.vue new file mode 100644 index 00000000..aaefe268 --- /dev/null +++ b/src/frontend/admin/src/views/template/list/tab.vue @@ -0,0 +1,166 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/list/tree.vue b/src/frontend/admin/src/views/template/list/tree.vue new file mode 100644 index 00000000..a3159090 --- /dev/null +++ b/src/frontend/admin/src/views/template/list/tree.vue @@ -0,0 +1,136 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/list/width.vue b/src/frontend/admin/src/views/template/list/width.vue new file mode 100644 index 00000000..03be18cc --- /dev/null +++ b/src/frontend/admin/src/views/template/list/width.vue @@ -0,0 +1,76 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/template/other/stepform.vue b/src/frontend/admin/src/views/template/other/stepform.vue new file mode 100644 index 00000000..bd93c61f --- /dev/null +++ b/src/frontend/admin/src/views/template/other/stepform.vue @@ -0,0 +1,150 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/test/autocode/index.vue b/src/frontend/admin/src/views/test/autocode/index.vue new file mode 100644 index 00000000..f02fcbdc --- /dev/null +++ b/src/frontend/admin/src/views/test/autocode/index.vue @@ -0,0 +1,106 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/test/autocode/list.vue b/src/frontend/admin/src/views/test/autocode/list.vue new file mode 100644 index 00000000..b671804f --- /dev/null +++ b/src/frontend/admin/src/views/test/autocode/list.vue @@ -0,0 +1,232 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/test/codebug/index.vue b/src/frontend/admin/src/views/test/codebug/index.vue new file mode 100644 index 00000000..c6d1854f --- /dev/null +++ b/src/frontend/admin/src/views/test/codebug/index.vue @@ -0,0 +1,94 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/chart.vue b/src/frontend/admin/src/views/vab/chart.vue new file mode 100644 index 00000000..f48670e9 --- /dev/null +++ b/src/frontend/admin/src/views/vab/chart.vue @@ -0,0 +1,246 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/codeeditor.vue b/src/frontend/admin/src/views/vab/codeeditor.vue new file mode 100644 index 00000000..0335885f --- /dev/null +++ b/src/frontend/admin/src/views/vab/codeeditor.vue @@ -0,0 +1,85 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/contextmenu.vue b/src/frontend/admin/src/views/vab/contextmenu.vue new file mode 100644 index 00000000..2a09ad09 --- /dev/null +++ b/src/frontend/admin/src/views/vab/contextmenu.vue @@ -0,0 +1,117 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/cron.vue b/src/frontend/admin/src/views/vab/cron.vue new file mode 100644 index 00000000..588d7962 --- /dev/null +++ b/src/frontend/admin/src/views/vab/cron.vue @@ -0,0 +1,45 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/cropper.vue b/src/frontend/admin/src/views/vab/cropper.vue new file mode 100644 index 00000000..f11868c5 --- /dev/null +++ b/src/frontend/admin/src/views/vab/cropper.vue @@ -0,0 +1,102 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/dialog/dialog1.vue b/src/frontend/admin/src/views/vab/dialog/dialog1.vue new file mode 100644 index 00000000..ab58a656 --- /dev/null +++ b/src/frontend/admin/src/views/vab/dialog/dialog1.vue @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/dialog/dialog2.vue b/src/frontend/admin/src/views/vab/dialog/dialog2.vue new file mode 100644 index 00000000..8f238166 --- /dev/null +++ b/src/frontend/admin/src/views/vab/dialog/dialog2.vue @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/dialog/index.vue b/src/frontend/admin/src/views/vab/dialog/index.vue new file mode 100644 index 00000000..87453179 --- /dev/null +++ b/src/frontend/admin/src/views/vab/dialog/index.vue @@ -0,0 +1,97 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/drag.vue b/src/frontend/admin/src/views/vab/drag.vue new file mode 100644 index 00000000..15f9fef9 --- /dev/null +++ b/src/frontend/admin/src/views/vab/drag.vue @@ -0,0 +1,135 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/editor.vue b/src/frontend/admin/src/views/vab/editor.vue new file mode 100644 index 00000000..95814bd3 --- /dev/null +++ b/src/frontend/admin/src/views/vab/editor.vue @@ -0,0 +1,54 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/fileselect.vue b/src/frontend/admin/src/views/vab/fileselect.vue new file mode 100644 index 00000000..ff3ed0eb --- /dev/null +++ b/src/frontend/admin/src/views/vab/fileselect.vue @@ -0,0 +1,54 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/filterBar.vue b/src/frontend/admin/src/views/vab/filterBar.vue new file mode 100644 index 00000000..e4dad8b3 --- /dev/null +++ b/src/frontend/admin/src/views/vab/filterBar.vue @@ -0,0 +1,187 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/form.vue b/src/frontend/admin/src/views/vab/form.vue new file mode 100644 index 00000000..91bb8050 --- /dev/null +++ b/src/frontend/admin/src/views/vab/form.vue @@ -0,0 +1,410 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/formtable.vue b/src/frontend/admin/src/views/vab/formtable.vue new file mode 100644 index 00000000..66880ea9 --- /dev/null +++ b/src/frontend/admin/src/views/vab/formtable.vue @@ -0,0 +1,132 @@ + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/iconfont.vue b/src/frontend/admin/src/views/vab/iconfont.vue new file mode 100644 index 00000000..a37fab7f --- /dev/null +++ b/src/frontend/admin/src/views/vab/iconfont.vue @@ -0,0 +1,77 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/iconselect.vue b/src/frontend/admin/src/views/vab/iconselect.vue new file mode 100644 index 00000000..a0ada98f --- /dev/null +++ b/src/frontend/admin/src/views/vab/iconselect.vue @@ -0,0 +1,71 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/importexport.vue b/src/frontend/admin/src/views/vab/importexport.vue new file mode 100644 index 00000000..ea2123aa --- /dev/null +++ b/src/frontend/admin/src/views/vab/importexport.vue @@ -0,0 +1,213 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/mini.vue b/src/frontend/admin/src/views/vab/mini.vue new file mode 100644 index 00000000..a00e8dfb --- /dev/null +++ b/src/frontend/admin/src/views/vab/mini.vue @@ -0,0 +1,76 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/print.vue b/src/frontend/admin/src/views/vab/print.vue new file mode 100644 index 00000000..602eefc8 --- /dev/null +++ b/src/frontend/admin/src/views/vab/print.vue @@ -0,0 +1,68 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/qrcode.vue b/src/frontend/admin/src/views/vab/qrcode.vue new file mode 100644 index 00000000..794b9c42 --- /dev/null +++ b/src/frontend/admin/src/views/vab/qrcode.vue @@ -0,0 +1,49 @@ + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/select.vue b/src/frontend/admin/src/views/vab/select.vue new file mode 100644 index 00000000..2771bae9 --- /dev/null +++ b/src/frontend/admin/src/views/vab/select.vue @@ -0,0 +1,63 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/selectFilter.vue b/src/frontend/admin/src/views/vab/selectFilter.vue new file mode 100644 index 00000000..615aae13 --- /dev/null +++ b/src/frontend/admin/src/views/vab/selectFilter.vue @@ -0,0 +1,89 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/statistic.vue b/src/frontend/admin/src/views/vab/statistic.vue new file mode 100644 index 00000000..a1a2f43d --- /dev/null +++ b/src/frontend/admin/src/views/vab/statistic.vue @@ -0,0 +1,70 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/table/base.vue b/src/frontend/admin/src/views/vab/table/base.vue new file mode 100644 index 00000000..88326abb --- /dev/null +++ b/src/frontend/admin/src/views/vab/table/base.vue @@ -0,0 +1,55 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/table/column.vue b/src/frontend/admin/src/views/vab/table/column.vue new file mode 100644 index 00000000..0d53e34a --- /dev/null +++ b/src/frontend/admin/src/views/vab/table/column.vue @@ -0,0 +1,76 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/table/remote.vue b/src/frontend/admin/src/views/vab/table/remote.vue new file mode 100644 index 00000000..749a251f --- /dev/null +++ b/src/frontend/admin/src/views/vab/table/remote.vue @@ -0,0 +1,44 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/table/thead.vue b/src/frontend/admin/src/views/vab/table/thead.vue new file mode 100644 index 00000000..7a45d139 --- /dev/null +++ b/src/frontend/admin/src/views/vab/table/thead.vue @@ -0,0 +1,37 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/tableselect.vue b/src/frontend/admin/src/views/vab/tableselect.vue new file mode 100644 index 00000000..bd998004 --- /dev/null +++ b/src/frontend/admin/src/views/vab/tableselect.vue @@ -0,0 +1,104 @@ + + + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/upload.vue b/src/frontend/admin/src/views/vab/upload.vue new file mode 100644 index 00000000..4832f658 --- /dev/null +++ b/src/frontend/admin/src/views/vab/upload.vue @@ -0,0 +1,175 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/video.vue b/src/frontend/admin/src/views/vab/video.vue new file mode 100644 index 00000000..6fb9fd00 --- /dev/null +++ b/src/frontend/admin/src/views/vab/video.vue @@ -0,0 +1,60 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/watermark.vue b/src/frontend/admin/src/views/vab/watermark.vue new file mode 100644 index 00000000..55e0af6d --- /dev/null +++ b/src/frontend/admin/src/views/vab/watermark.vue @@ -0,0 +1,60 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/src/views/vab/workflow.vue b/src/frontend/admin/src/views/vab/workflow.vue new file mode 100644 index 00000000..00019cc3 --- /dev/null +++ b/src/frontend/admin/src/views/vab/workflow.vue @@ -0,0 +1,119 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/admin/vite.config.js b/src/frontend/admin/vite.config.js new file mode 100644 index 00000000..a1e640a7 --- /dev/null +++ b/src/frontend/admin/vite.config.js @@ -0,0 +1,79 @@ +import { defineConfig } from 'vite' +import path from 'path' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + base: './', + plugins: [vue()], + resolve: { + alias: { + // 设置路径 + '~': path.resolve(__dirname, './'), + // 设置别名 + '@': path.resolve(__dirname, './src'), + }, + extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'], + }, + // vite 相关配置 + server: { + port: 65020, + host: true, + open: false, + proxy: { + '/api': { + target: 'http://localhost:65010/api', + changeOrigin: true, + rewrite: (p) => p.replace(/^\/api/, ''), + }, + }, + }, + css: { + postcss: { + plugins: [ + { + postcssPlugin: 'internal:charset-removal', + AtRule: { + charset: (atRule) => { + if (atRule.name === 'charset') { + atRule.remove() + } + }, + }, + }, + ], + }, + }, + build: { + emptyOutDir: true, + outDir: 'dist', + assetsDir: 'assets', + minify: 'terser', + terserOptions: { + compress: { + drop_console: true, + drop_debugger: true, + }, + }, + rollupOptions: { + // 拆包 + output: { + chunkFileNames: 'js/[name]-[hash].js', + entryFileNames: 'js/[name]-[hash].js', + assetFileNames: '[ext]/[name]-[hash].[ext]', + manualChunks(id) { + if (id.includes('node_modules')) { + return id.split('/node_modules/').pop()?.split('/')[0] + } + }, + // 第三方库拆包 + // manualChunks: { + // xgplayer: ['xgplayer'], + // xlsx: ['xlsx'], + // tinymce: ['tinymce'], + // elicons: ['@element-plus/icons-vue'] + // } + }, + }, + }, +}) \ No newline at end of file diff --git a/src/frontend/h5/.editorconfig b/src/frontend/h5/.editorconfig new file mode 100644 index 00000000..b79317dd --- /dev/null +++ b/src/frontend/h5/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +ij_xml_attribute_wrap = off +ij_xml_text_wrap = off +indent_size = 4 +indent_style = space +insert_final_newline = false +trim_trailing_whitespace = true \ No newline at end of file diff --git a/src/frontend/h5/.eslintrc.cjs b/src/frontend/h5/.eslintrc.cjs new file mode 100644 index 00000000..c9f9b33d --- /dev/null +++ b/src/frontend/h5/.eslintrc.cjs @@ -0,0 +1,14 @@ +/* eslint-env node */ +require('@rushstack/eslint-patch/modern-module-resolution') + +module.exports = { + root: true, + 'extends': [ + 'plugin:vue/vue3-essential', + 'eslint:recommended', + '@vue/eslint-config-prettier/skip-formatting' + ], + parserOptions: { + ecmaVersion: 'latest' + } +} \ No newline at end of file diff --git a/src/frontend/h5/.gitignore b/src/frontend/h5/.gitignore new file mode 100644 index 00000000..38adffa6 --- /dev/null +++ b/src/frontend/h5/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/src/frontend/h5/.prettierrc.json b/src/frontend/h5/.prettierrc.json new file mode 100644 index 00000000..2998b24c --- /dev/null +++ b/src/frontend/h5/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "tabWidth": 2, + "singleQuote": true, + "printWidth": 100, + "trailingComma": "none" +} \ No newline at end of file diff --git a/src/frontend/h5/README.md b/src/frontend/h5/README.md new file mode 100644 index 00000000..280b3f39 --- /dev/null +++ b/src/frontend/h5/README.md @@ -0,0 +1,35 @@ +# ddf-app + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` \ No newline at end of file diff --git a/src/frontend/h5/index.html b/src/frontend/h5/index.html new file mode 100644 index 00000000..73c66b90 --- /dev/null +++ b/src/frontend/h5/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + \ No newline at end of file diff --git a/src/frontend/h5/package.json b/src/frontend/h5/package.json new file mode 100644 index 00000000..dba0eb56 --- /dev/null +++ b/src/frontend/h5/package.json @@ -0,0 +1,36 @@ +{ + "name": "ddf-app", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore", + "format": "prettier --write src/" + }, + "dependencies": { + "@vant/touch-emulator": "^1.4.0", + "axios": "^1.3.6", + "crypto-js": "^4.1.1", + "json-bigint": "^1.0.0", + "pinia": "^2.0.32", + "uuid": "^9.0.0", + "vant": "^4.2.0", + "vue": "^3.2.47", + "vue-router": "^4.1.6" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.2.0", + "@vitejs/plugin-vue": "^4.0.0", + "@vue/eslint-config-prettier": "^7.1.0", + "autoprefixer": "^10.4.14", + "eslint": "^8.34.0", + "eslint-plugin-vue": "^9.9.0", + "postcss": "^8.4.23", + "postcss-pxtorem": "^6.0.0", + "prettier": "^2.8.4", + "tailwindcss": "^3.3.2", + "vite": "^4.1.4" + } +} \ No newline at end of file diff --git a/src/frontend/h5/postcss.config.js b/src/frontend/h5/postcss.config.js new file mode 100644 index 00000000..f1f1f334 --- /dev/null +++ b/src/frontend/h5/postcss.config.js @@ -0,0 +1,10 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + 'postcss-pxtorem': { + rootValue: 16, + propList: ['*'] + } + } +} \ No newline at end of file diff --git a/src/frontend/h5/public/favicon.ico b/src/frontend/h5/public/favicon.ico new file mode 100644 index 00000000..df36fcfb Binary files /dev/null and b/src/frontend/h5/public/favicon.ico differ diff --git a/src/frontend/h5/src/App.vue b/src/frontend/h5/src/App.vue new file mode 100644 index 00000000..e126b7e7 --- /dev/null +++ b/src/frontend/h5/src/App.vue @@ -0,0 +1,28 @@ + + + \ No newline at end of file diff --git a/src/frontend/h5/src/NetAdmin.js b/src/frontend/h5/src/NetAdmin.js new file mode 100644 index 00000000..e8358f46 --- /dev/null +++ b/src/frontend/h5/src/NetAdmin.js @@ -0,0 +1,25 @@ +import config from './config' +import api from './api' +import tool from './utils/tool' +import http from './utils/request' + +export default { + async install(app) { + //挂载全局对象 + app.config.globalProperties.$CONFIG = config + app.config.globalProperties.$TOOL = tool + app.config.globalProperties.$HTTP = http + app.config.globalProperties.$API = api + const res = await Promise.all([ + api['sys/constant'].getChars.post(), + api['sys/constant'].getEnums.post(), + api['sys/constant'].getLocalizedStrings.post(), + api['sys/constant'].getNumbers.post() + ]) + + config.STRINGS = res[0].data + config.ENUMS = res[1].data + config.LOC_STRINGS = res[2].data + config.NUMBERS = res[3].data + } +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/biz/artcategory.js b/src/frontend/h5/src/api/biz/artcategory.js new file mode 100644 index 00000000..5e89f0cf --- /dev/null +++ b/src/frontend/h5/src/api/biz/artcategory.js @@ -0,0 +1,77 @@ +/** + * 文章分类服务 + * @module @/api/biz/art.category + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除文章分类 + */ +bulkDelete :{ + url: `${config.API_URL}/api/biz/art.category/bulk.delete`, + name: `批量删除文章分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建文章分类 + */ +create :{ + url: `${config.API_URL}/api/biz/art.category/create`, + name: `创建文章分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除文章分类 + */ +delete :{ + url: `${config.API_URL}/api/biz/art.category/delete`, + name: `删除文章分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询文章分类 + */ +pagedQuery :{ + url: `${config.API_URL}/api/biz/art.category/paged.query`, + name: `分页查询文章分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询文章分类 + */ +query :{ + url: `${config.API_URL}/api/biz/art.category/query`, + name: `查询文章分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新文章分类 + */ +update :{ + url: `${config.API_URL}/api/biz/art.category/update`, + name: `更新文章分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/biz/article.js b/src/frontend/h5/src/api/biz/article.js new file mode 100644 index 00000000..e1ba8fb4 --- /dev/null +++ b/src/frontend/h5/src/api/biz/article.js @@ -0,0 +1,77 @@ +/** + * 文章服务 + * @module @/api/biz/article + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除文章 + */ +bulkDelete :{ + url: `${config.API_URL}/api/biz/article/bulk.delete`, + name: `批量删除文章`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建文章 + */ +create :{ + url: `${config.API_URL}/api/biz/article/create`, + name: `创建文章`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除文章 + */ +delete :{ + url: `${config.API_URL}/api/biz/article/delete`, + name: `删除文章`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询文章 + */ +pagedQuery :{ + url: `${config.API_URL}/api/biz/article/paged.query`, + name: `分页查询文章`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询文章 + */ +query :{ + url: `${config.API_URL}/api/biz/article/query`, + name: `查询文章`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新文章 + */ +update :{ + url: `${config.API_URL}/api/biz/article/update`, + name: `更新文章`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/biz/articlecategory.js b/src/frontend/h5/src/api/biz/articlecategory.js new file mode 100644 index 00000000..dc8a76c8 --- /dev/null +++ b/src/frontend/h5/src/api/biz/articlecategory.js @@ -0,0 +1,77 @@ +/** + * 文章分类映射服务 + * @module @/api/biz/article.category + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除文章分类映射 + */ +bulkDelete :{ + url: `${config.API_URL}/api/biz/article.category/bulk.delete`, + name: `批量删除文章分类映射`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建文章分类映射 + */ +create :{ + url: `${config.API_URL}/api/biz/article.category/create`, + name: `创建文章分类映射`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除文章分类映射 + */ +delete :{ + url: `${config.API_URL}/api/biz/article.category/delete`, + name: `删除文章分类映射`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询文章分类映射 + */ +pagedQuery :{ + url: `${config.API_URL}/api/biz/article.category/paged.query`, + name: `分页查询文章分类映射`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询文章分类映射 + */ +query :{ + url: `${config.API_URL}/api/biz/article.category/query`, + name: `查询文章分类映射`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新文章分类映射 + */ +update :{ + url: `${config.API_URL}/api/biz/article.category/update`, + name: `更新文章分类映射`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/biz/articledetail.js b/src/frontend/h5/src/api/biz/articledetail.js new file mode 100644 index 00000000..793bfa97 --- /dev/null +++ b/src/frontend/h5/src/api/biz/articledetail.js @@ -0,0 +1,77 @@ +/** + * 文章详情服务 + * @module @/api/biz/article.detail + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除文章详情 + */ +bulkDelete :{ + url: `${config.API_URL}/api/biz/article.detail/bulk.delete`, + name: `批量删除文章详情`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建文章详情 + */ +create :{ + url: `${config.API_URL}/api/biz/article.detail/create`, + name: `创建文章详情`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除文章详情 + */ +delete :{ + url: `${config.API_URL}/api/biz/article.detail/delete`, + name: `删除文章详情`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询文章详情 + */ +pagedQuery :{ + url: `${config.API_URL}/api/biz/article.detail/paged.query`, + name: `分页查询文章详情`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询文章详情 + */ +query :{ + url: `${config.API_URL}/api/biz/article.detail/query`, + name: `查询文章详情`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新文章详情 + */ +update :{ + url: `${config.API_URL}/api/biz/article.detail/update`, + name: `更新文章详情`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/biz/member.js b/src/frontend/h5/src/api/biz/member.js new file mode 100644 index 00000000..25556b59 --- /dev/null +++ b/src/frontend/h5/src/api/biz/member.js @@ -0,0 +1,99 @@ +/** + * 会员服务 + * @module @/api/biz/member + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除会员 + */ +bulkDelete :{ + url: `${config.API_URL}/api/biz/member/bulk.delete`, + name: `批量删除会员`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建会员 + */ +create :{ + url: `${config.API_URL}/api/biz/member/create`, + name: `创建会员`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除会员 + */ +delete :{ + url: `${config.API_URL}/api/biz/member/delete`, + name: `删除会员`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 当前会员信息 + */ +memberInfo :{ + url: `${config.API_URL}/api/biz/member/member.info`, + name: `当前会员信息`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询会员 + */ +pagedQuery :{ + url: `${config.API_URL}/api/biz/member/paged.query`, + name: `分页查询会员`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询会员 + */ +query :{ + url: `${config.API_URL}/api/biz/member/query`, + name: `查询会员`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 会员注册 + */ +register :{ + url: `${config.API_URL}/api/biz/member/register`, + name: `会员注册`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新会员 + */ +update :{ + url: `${config.API_URL}/api/biz/member/update`, + name: `更新会员`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/biz/product.js b/src/frontend/h5/src/api/biz/product.js new file mode 100644 index 00000000..df0badf1 --- /dev/null +++ b/src/frontend/h5/src/api/biz/product.js @@ -0,0 +1,88 @@ +/** + * 商品服务 + * @module @/api/biz/product + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除商品 + */ +bulkDelete :{ + url: `${config.API_URL}/api/biz/product/bulk.delete`, + name: `批量删除商品`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建商品 + */ +create :{ + url: `${config.API_URL}/api/biz/product/create`, + name: `创建商品`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除商品 + */ +delete :{ + url: `${config.API_URL}/api/biz/product/delete`, + name: `删除商品`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 获取单个商品 + */ +get :{ + url: `${config.API_URL}/api/biz/product/get`, + name: `获取单个商品`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询商品 + */ +pagedQuery :{ + url: `${config.API_URL}/api/biz/product/paged.query`, + name: `分页查询商品`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询商品 + */ +query :{ + url: `${config.API_URL}/api/biz/product/query`, + name: `查询商品`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新商品 + */ +update :{ + url: `${config.API_URL}/api/biz/product/update`, + name: `更新商品`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/biz/productcategory.js b/src/frontend/h5/src/api/biz/productcategory.js new file mode 100644 index 00000000..22a77c10 --- /dev/null +++ b/src/frontend/h5/src/api/biz/productcategory.js @@ -0,0 +1,77 @@ +/** + * 商品分类服务 + * @module @/api/biz/product.category + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除商品分类 + */ +bulkDelete :{ + url: `${config.API_URL}/api/biz/product.category/bulk.delete`, + name: `批量删除商品分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建商品分类 + */ +create :{ + url: `${config.API_URL}/api/biz/product.category/create`, + name: `创建商品分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除商品分类 + */ +delete :{ + url: `${config.API_URL}/api/biz/product.category/delete`, + name: `删除商品分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询商品分类 + */ +pagedQuery :{ + url: `${config.API_URL}/api/biz/product.category/paged.query`, + name: `分页查询商品分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询商品分类 + */ +query :{ + url: `${config.API_URL}/api/biz/product.category/query`, + name: `查询商品分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新商品分类 + */ +update :{ + url: `${config.API_URL}/api/biz/product.category/update`, + name: `更新商品分类`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/biz/urlmap.js b/src/frontend/h5/src/api/biz/urlmap.js new file mode 100644 index 00000000..7079075a --- /dev/null +++ b/src/frontend/h5/src/api/biz/urlmap.js @@ -0,0 +1,77 @@ +/** + * 文章地址服务 + * @module @/api/biz/url.map + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除文章地址 + */ +bulkDelete :{ + url: `${config.API_URL}/api/biz/url.map/bulk.delete`, + name: `批量删除文章地址`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建文章地址 + */ +create :{ + url: `${config.API_URL}/api/biz/url.map/create`, + name: `创建文章地址`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除文章地址 + */ +delete :{ + url: `${config.API_URL}/api/biz/url.map/delete`, + name: `删除文章地址`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询文章地址 + */ +pagedQuery :{ + url: `${config.API_URL}/api/biz/url.map/paged.query`, + name: `分页查询文章地址`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询文章地址 + */ +query :{ + url: `${config.API_URL}/api/biz/url.map/query`, + name: `查询文章地址`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新文章地址 + */ +update :{ + url: `${config.API_URL}/api/biz/url.map/update`, + name: `更新文章地址`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/controllers/health.js b/src/frontend/h5/src/api/controllers/health.js new file mode 100644 index 00000000..9bad104e --- /dev/null +++ b/src/frontend/h5/src/api/controllers/health.js @@ -0,0 +1,22 @@ +/** + * 健康控制器 + * @module @/api/health + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 健康检查 + */ +check :{ + url: `${config.API_URL}/api/health/check`, + name: `健康检查`, + get:async function(data={}, config={}) { + return await http.get(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/index.js b/src/frontend/h5/src/api/index.js new file mode 100644 index 00000000..45fb1f9f --- /dev/null +++ b/src/frontend/h5/src/api/index.js @@ -0,0 +1,13 @@ +/** + * @description 自动import导入所有 api 模块 + */ + +const modules = {} + +const files = import.meta.glob('./**/*.js') +for await (const key of Object.keys(files)) { + const name = key.replace(/^\.\/(.*)\.\w+$/, '$1') + modules[name] = (await files[key]()).default +} + +export default modules \ No newline at end of file diff --git a/src/frontend/h5/src/api/model/auth.js b/src/frontend/h5/src/api/model/auth.js new file mode 100644 index 00000000..d8b8fbb0 --- /dev/null +++ b/src/frontend/h5/src/api/model/auth.js @@ -0,0 +1,12 @@ +import config from "@/config" +import http from "@/utils/request" + +export default { + token: { + url: `${config.API_URL}/token`, + name: "登录获取TOKEN", + post: async function (data = {}) { + return await http.post(this.url, data); + } + } +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/model/common.js b/src/frontend/h5/src/api/model/common.js new file mode 100644 index 00000000..46f62e5c --- /dev/null +++ b/src/frontend/h5/src/api/model/common.js @@ -0,0 +1,49 @@ +import config from "@/config" +import http from "@/utils/request" + +export default { + upload: { + url: `${config.API_URL}/upload`, + name: "文件上传", + post: async function (data, config = {}) { + return await http.post(this.url, data, config); + } + }, + uploadFile: { + url: `${config.API_URL}/uploadFile`, + name: "附件上传", + post: async function (data, config = {}) { + return await http.post(this.url, data, config); + } + }, + exportFile: { + url: `${config.API_URL}/fileExport`, + name: "导出附件", + get: async function (data, config = {}) { + return await http.get(this.url, data, config); + } + }, + importFile: { + url: `${config.API_URL}/fileImport`, + name: "导入附件", + post: async function (data, config = {}) { + return await http.post(this.url, data, config); + } + }, + file: { + menu: { + url: `${config.API_URL}/file/menu`, + name: "获取文件分类", + get: async function () { + return await http.get(this.url); + } + }, + list: { + url: `${config.API_URL}/file/list`, + name: "获取文件列表", + get: async function (params) { + return await http.get(this.url, params); + } + } + } +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/model/demo.js b/src/frontend/h5/src/api/model/demo.js new file mode 100644 index 00000000..828dab13 --- /dev/null +++ b/src/frontend/h5/src/api/model/demo.js @@ -0,0 +1,55 @@ +import config from "@/config" +import http from "@/utils/request" + +export default { + ver: { + url: `${config.API_URL}/demo/ver`, + name: "获取最新版本号", + get: async function (params) { + return await http.get(this.url, params); + } + }, + post: { + url: `${config.API_URL}/demo/post`, + name: "分页列表", + post: async function (data) { + return await http.post(this.url, data, { + headers: { + //'response-status': 401 + } + }); + } + }, + page: { + url: `${config.API_URL}/demo/page`, + name: "分页列表", + get: async function (params) { + return await http.get(this.url, params); + } + }, + list: { + url: `${config.API_URL}/demo/list`, + name: "数据列表", + get: async function (params) { + return await http.get(this.url, params); + } + }, + menu: { + url: `${config.API_URL}/demo/menu`, + name: "普通用户菜单", + get: async function () { + return await http.get(this.url); + } + }, + status: { + url: `${config.API_URL}/demo/status`, + name: "模拟无权限", + get: async function (code) { + return await http.get(this.url, {}, { + headers: { + "response-status": code + } + }); + } + } +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/model/system.js b/src/frontend/h5/src/api/model/system.js new file mode 100644 index 00000000..0698d31e --- /dev/null +++ b/src/frontend/h5/src/api/model/system.js @@ -0,0 +1,114 @@ +import config from "@/config" +import http from "@/utils/request" + +export default { + menu: { + myMenus: { + url: `${config.API_URL}/system/menu/my/1.6.1`, + name: "获取我的菜单", + get: async function () { + return await http.get(this.url); + } + }, + list: { + url: `${config.API_URL}/system/menu/list`, + name: "获取菜单", + get: async function () { + return await http.get(this.url); + } + } + }, + dic: { + tree: { + url: `${config.API_URL}/system/dic/tree`, + name: "获取字典树", + get: async function () { + return await http.get(this.url); + } + }, + list: { + url: `${config.API_URL}/system/dic/list`, + name: "字典明细", + get: async function (params) { + return await http.get(this.url, params); + } + }, + get: { + url: `${config.API_URL}/system/dic/get`, + name: "获取字典数据", + get: async function (params) { + return await http.get(this.url, params); + } + } + }, + role: { + list: { + url: `${config.API_URL}/system/role/list2`, + name: "获取角色列表", + get: async function (params) { + return await http.get(this.url, params); + } + } + }, + dept: { + list: { + url: `${config.API_URL}/system/dept/list`, + name: "获取部门列表", + get: async function (params) { + return await http.get(this.url, params); + } + } + }, + user: { + list: { + url: `${config.API_URL}/system/user/list`, + name: "获取用户列表", + get: async function (params) { + return await http.get(this.url, params); + } + } + }, + app: { + list: { + url: `${config.API_URL}/system/app/list`, + name: "应用列表", + get: async function () { + return await http.get(this.url); + } + } + }, + log: { + list: { + url: `${config.API_URL}/system/log/list`, + name: "日志列表", + get: async function (params) { + return await http.get(this.url, params); + } + } + }, + table: { + list: { + url: `${config.API_URL}/system/table/list`, + name: "表格列管理列表", + get: async function (params) { + return await http.get(this.url, params); + } + }, + info: { + url: `${config.API_URL}/system/table/info`, + name: "表格列管理详情", + get: async function (params) { + return await http.get(this.url, params); + } + } + }, + tasks: { + list: { + url: `${config.API_URL}/system/tasks/list`, + name: "系统任务管理", + get: async function (params) { + return await http.get(this.url, params); + } + } + } +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/api.js b/src/frontend/h5/src/api/sys/api.js new file mode 100644 index 00000000..0ba9a3a2 --- /dev/null +++ b/src/frontend/h5/src/api/sys/api.js @@ -0,0 +1,33 @@ +/** + * 接口服务 + * @module @/api/sys/api + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 查询接口 + */ +query :{ + url: `${config.API_URL}/api/sys/api/query`, + name: `查询接口`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 同步接口 + */ +sync :{ + url: `${config.API_URL}/api/sys/api/sync`, + name: `同步接口`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/cache.js b/src/frontend/h5/src/api/sys/cache.js new file mode 100644 index 00000000..a335522a --- /dev/null +++ b/src/frontend/h5/src/api/sys/cache.js @@ -0,0 +1,33 @@ +/** + * 缓存服务 + * @module @/api/sys/cache + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 缓存统计 + */ +cacheStatistics :{ + url: `${config.API_URL}/api/sys/cache/cache.statistics`, + name: `缓存统计`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 清空缓存 + */ +clear :{ + url: `${config.API_URL}/api/sys/cache/clear`, + name: `清空缓存`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/captcha.js b/src/frontend/h5/src/api/sys/captcha.js new file mode 100644 index 00000000..7136d98b --- /dev/null +++ b/src/frontend/h5/src/api/sys/captcha.js @@ -0,0 +1,33 @@ +/** + * 人机验证服务 + * @module @/api/sys/captcha + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 获取人机校验图 + */ +getCaptchaImage :{ + url: `${config.API_URL}/api/sys/captcha/get.captcha.image`, + name: `获取人机校验图`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 完成人机校验 + */ +verifyCaptcha :{ + url: `${config.API_URL}/api/sys/captcha/verify.captcha`, + name: `完成人机校验`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/config.js b/src/frontend/h5/src/api/sys/config.js new file mode 100644 index 00000000..cb4d0981 --- /dev/null +++ b/src/frontend/h5/src/api/sys/config.js @@ -0,0 +1,88 @@ +/** + * 配置服务 + * @module @/api/sys/config + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除配置 + */ +bulkDelete :{ + url: `${config.API_URL}/api/sys/config/bulk.delete`, + name: `批量删除配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建配置 + */ +create :{ + url: `${config.API_URL}/api/sys/config/create`, + name: `创建配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除配置 + */ +delete :{ + url: `${config.API_URL}/api/sys/config/delete`, + name: `删除配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 获取最新有效配置 + */ +getLatestConfig :{ + url: `${config.API_URL}/api/sys/config/get.latest.config`, + name: `获取最新有效配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询配置 + */ +pagedQuery :{ + url: `${config.API_URL}/api/sys/config/paged.query`, + name: `分页查询配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询配置 + */ +query :{ + url: `${config.API_URL}/api/sys/config/query`, + name: `查询配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新配置 + */ +update :{ + url: `${config.API_URL}/api/sys/config/update`, + name: `更新配置`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/constant.js b/src/frontend/h5/src/api/sys/constant.js new file mode 100644 index 00000000..42c8aae4 --- /dev/null +++ b/src/frontend/h5/src/api/sys/constant.js @@ -0,0 +1,55 @@ +/** + * 常量服务 + * @module @/api/sys/constant + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 获得常量字符串 + */ +getChars :{ + url: `${config.API_URL}/api/sys/constant/get.chars`, + name: `获得常量字符串`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 获得公共枚举值 + */ +getEnums :{ + url: `${config.API_URL}/api/sys/constant/get.enums`, + name: `获得公共枚举值`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 获得本地化字符串 + */ +getLocalizedStrings :{ + url: `${config.API_URL}/api/sys/constant/get.localized.strings`, + name: `获得本地化字符串`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 获得数字常量表 + */ +getNumbers :{ + url: `${config.API_URL}/api/sys/constant/get.numbers`, + name: `获得数字常量表`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/dept.js b/src/frontend/h5/src/api/sys/dept.js new file mode 100644 index 00000000..963b6e06 --- /dev/null +++ b/src/frontend/h5/src/api/sys/dept.js @@ -0,0 +1,66 @@ +/** + * 部门服务 + * @module @/api/sys/dept + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除部门 + */ +bulkDelete :{ + url: `${config.API_URL}/api/sys/dept/bulk.delete`, + name: `批量删除部门`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建部门 + */ +create :{ + url: `${config.API_URL}/api/sys/dept/create`, + name: `创建部门`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除部门 + */ +delete :{ + url: `${config.API_URL}/api/sys/dept/delete`, + name: `删除部门`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询部门 + */ +query :{ + url: `${config.API_URL}/api/sys/dept/query`, + name: `查询部门`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新部门 + */ +update :{ + url: `${config.API_URL}/api/sys/dept/update`, + name: `更新部门`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/dev.js b/src/frontend/h5/src/api/sys/dev.js new file mode 100644 index 00000000..fddc09c5 --- /dev/null +++ b/src/frontend/h5/src/api/sys/dev.js @@ -0,0 +1,44 @@ +/** + * 开发服务 + * @module @/api/sys/dev + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 生成后端代码 + */ +generateCsCode :{ + url: `${config.API_URL}/api/sys/dev/generate.cs.code`, + name: `生成后端代码`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 生成图标代码 + */ +generateIconCode :{ + url: `${config.API_URL}/api/sys/dev/generate.icon.code`, + name: `生成图标代码`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 生成接口代码 + */ +generateJsCode :{ + url: `${config.API_URL}/api/sys/dev/generate.js.code`, + name: `生成接口代码`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/dic.js b/src/frontend/h5/src/api/sys/dic.js new file mode 100644 index 00000000..9ccefda6 --- /dev/null +++ b/src/frontend/h5/src/api/sys/dic.js @@ -0,0 +1,143 @@ +/** + * 字典服务 + * @module @/api/sys/dic + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除字典目录 + */ +bulkDeleteCatalog :{ + url: `${config.API_URL}/api/sys/dic/bulk.delete.catalog`, + name: `批量删除字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 批量删除字典内容 + */ +bulkDeleteContent :{ + url: `${config.API_URL}/api/sys/dic/bulk.delete.content`, + name: `批量删除字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建字典目录 + */ +createCatalog :{ + url: `${config.API_URL}/api/sys/dic/create.catalog`, + name: `创建字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建字典内容 + */ +createContent :{ + url: `${config.API_URL}/api/sys/dic/create.content`, + name: `创建字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除字典目录 + */ +deleteCatalog :{ + url: `${config.API_URL}/api/sys/dic/delete.catalog`, + name: `删除字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除字典内容 + */ +deleteContent :{ + url: `${config.API_URL}/api/sys/dic/delete.content`, + name: `删除字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询字典目录 + */ +pagedQueryCatalog :{ + url: `${config.API_URL}/api/sys/dic/paged.query.catalog`, + name: `分页查询字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询字典内容 + */ +pagedQueryContent :{ + url: `${config.API_URL}/api/sys/dic/paged.query.content`, + name: `分页查询字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询字典目录 + */ +queryCatalog :{ + url: `${config.API_URL}/api/sys/dic/query.catalog`, + name: `查询字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询字典内容 + */ +queryContent :{ + url: `${config.API_URL}/api/sys/dic/query.content`, + name: `查询字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新字典目录 + */ +updateCatalog :{ + url: `${config.API_URL}/api/sys/dic/update.catalog`, + name: `更新字典目录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新字典内容 + */ +updateContent :{ + url: `${config.API_URL}/api/sys/dic/update.content`, + name: `更新字典内容`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/file.js b/src/frontend/h5/src/api/sys/file.js new file mode 100644 index 00000000..5b50ba66 --- /dev/null +++ b/src/frontend/h5/src/api/sys/file.js @@ -0,0 +1,22 @@ +/** + * 文件服务 + * @module @/api/sys/file + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 文件上传 + */ +upload :{ + url: `${config.API_URL}/api/sys/file/upload`, + name: `文件上传`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/log.js b/src/frontend/h5/src/api/sys/log.js new file mode 100644 index 00000000..054de945 --- /dev/null +++ b/src/frontend/h5/src/api/sys/log.js @@ -0,0 +1,33 @@ +/** + * 请求日志服务 + * @module @/api/sys/log + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 分页查询请求日志 + */ +pagedQuery :{ + url: `${config.API_URL}/api/sys/log/paged.query`, + name: `分页查询请求日志`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询请求日志 + */ +query :{ + url: `${config.API_URL}/api/sys/log/query`, + name: `查询请求日志`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/menu.js b/src/frontend/h5/src/api/sys/menu.js new file mode 100644 index 00000000..ea55a58f --- /dev/null +++ b/src/frontend/h5/src/api/sys/menu.js @@ -0,0 +1,77 @@ +/** + * 菜单服务 + * @module @/api/sys/menu + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除菜单 + */ +bulkDelete :{ + url: `${config.API_URL}/api/sys/menu/bulk.delete`, + name: `批量删除菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建菜单 + */ +create :{ + url: `${config.API_URL}/api/sys/menu/create`, + name: `创建菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除菜单 + */ +delete :{ + url: `${config.API_URL}/api/sys/menu/delete`, + name: `删除菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询菜单 + */ +query :{ + url: `${config.API_URL}/api/sys/menu/query`, + name: `查询菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新菜单 + */ +update :{ + url: `${config.API_URL}/api/sys/menu/update`, + name: `更新菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 当前用户菜单 + */ +userMenus :{ + url: `${config.API_URL}/api/sys/menu/user.menus`, + name: `当前用户菜单`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/position.js b/src/frontend/h5/src/api/sys/position.js new file mode 100644 index 00000000..43e5093b --- /dev/null +++ b/src/frontend/h5/src/api/sys/position.js @@ -0,0 +1,77 @@ +/** + * 岗位服务 + * @module @/api/sys/position + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除岗位 + */ +bulkDelete :{ + url: `${config.API_URL}/api/sys/position/bulk.delete`, + name: `批量删除岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建岗位 + */ +create :{ + url: `${config.API_URL}/api/sys/position/create`, + name: `创建岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除岗位 + */ +delete :{ + url: `${config.API_URL}/api/sys/position/delete`, + name: `删除岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询岗位 + */ +pagedQuery :{ + url: `${config.API_URL}/api/sys/position/paged.query`, + name: `分页查询岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询岗位 + */ +query :{ + url: `${config.API_URL}/api/sys/position/query`, + name: `查询岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新岗位 + */ +update :{ + url: `${config.API_URL}/api/sys/position/update`, + name: `更新岗位`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/role.js b/src/frontend/h5/src/api/sys/role.js new file mode 100644 index 00000000..1772d99f --- /dev/null +++ b/src/frontend/h5/src/api/sys/role.js @@ -0,0 +1,77 @@ +/** + * 角色服务 + * @module @/api/sys/role + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除角色 + */ +bulkDelete :{ + url: `${config.API_URL}/api/sys/role/bulk.delete`, + name: `批量删除角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建角色 + */ +create :{ + url: `${config.API_URL}/api/sys/role/create`, + name: `创建角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除角色 + */ +delete :{ + url: `${config.API_URL}/api/sys/role/delete`, + name: `删除角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询角色 + */ +pagedQuery :{ + url: `${config.API_URL}/api/sys/role/paged.query`, + name: `分页查询角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询角色 + */ +query :{ + url: `${config.API_URL}/api/sys/role/query`, + name: `查询角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新角色 + */ +update :{ + url: `${config.API_URL}/api/sys/role/update`, + name: `更新角色`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/sms.js b/src/frontend/h5/src/api/sys/sms.js new file mode 100644 index 00000000..acffb1e4 --- /dev/null +++ b/src/frontend/h5/src/api/sys/sms.js @@ -0,0 +1,55 @@ +/** + * 短信服务 + * @module @/api/sys/sms + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 分页查询短信 + */ +pagedQuery :{ + url: `${config.API_URL}/api/sys/sms/paged.query`, + name: `分页查询短信`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询短信 + */ +query :{ + url: `${config.API_URL}/api/sys/sms/query`, + name: `查询短信`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 发送短信验证码 + */ +sendSmsCode :{ + url: `${config.API_URL}/api/sys/sms/send.sms.code`, + name: `发送短信验证码`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 完成短信验证 + */ +verifySmsCode :{ + url: `${config.API_URL}/api/sys/sms/verify.sms.code`, + name: `完成短信验证`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/tools.js b/src/frontend/h5/src/api/sys/tools.js new file mode 100644 index 00000000..f42c06fa --- /dev/null +++ b/src/frontend/h5/src/api/sys/tools.js @@ -0,0 +1,33 @@ +/** + * 工具服务 + * @module @/api/sys/tools + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 服务器时间 + */ +getServerUtcTime :{ + url: `${config.API_URL}/api/sys/tools/get.server.utc.time`, + name: `服务器时间`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 版本信息 + */ +version :{ + url: `${config.API_URL}/api/sys/tools/version`, + name: `版本信息`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/sys/user.js b/src/frontend/h5/src/api/sys/user.js new file mode 100644 index 00000000..a477cb6b --- /dev/null +++ b/src/frontend/h5/src/api/sys/user.js @@ -0,0 +1,154 @@ +/** + * 用户服务 + * @module @/api/sys/user + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 检查手机号是否可用 + */ +checkMobileAvailable :{ + url: `${config.API_URL}/api/sys/user/check.mobile.available`, + name: `检查手机号是否可用`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 检查用户名是否可用 + */ +checkUserNameAvailable :{ + url: `${config.API_URL}/api/sys/user/check.user.name.available`, + name: `检查用户名是否可用`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建用户 + */ +create :{ + url: `${config.API_URL}/api/sys/user/create`, + name: `创建用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除用户 + */ +delete :{ + url: `${config.API_URL}/api/sys/user/delete`, + name: `删除用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 密码登录 + */ +loginByPwd :{ + url: `${config.API_URL}/api/sys/user/login.by.pwd`, + name: `密码登录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 短信登录 + */ +loginBySms :{ + url: `${config.API_URL}/api/sys/user/login.by.sms`, + name: `短信登录`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询用户 + */ +pagedQuery :{ + url: `${config.API_URL}/api/sys/user/paged.query`, + name: `分页查询用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询用户 + */ +query :{ + url: `${config.API_URL}/api/sys/user/query`, + name: `查询用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询用户档案 + */ +queryProfile :{ + url: `${config.API_URL}/api/sys/user/query.profile`, + name: `查询用户档案`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 注册用户 + */ +register :{ + url: `${config.API_URL}/api/sys/user/register`, + name: `注册用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 重设密码 + */ +resetPassword :{ + url: `${config.API_URL}/api/sys/user/reset.password`, + name: `重设密码`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新用户 + */ +update :{ + url: `${config.API_URL}/api/sys/user/update`, + name: `更新用户`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 当前用户信息 + */ +userInfo :{ + url: `${config.API_URL}/api/sys/user/user.info`, + name: `当前用户信息`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/tpl/example.js b/src/frontend/h5/src/api/tpl/example.js new file mode 100644 index 00000000..4b672530 --- /dev/null +++ b/src/frontend/h5/src/api/tpl/example.js @@ -0,0 +1,77 @@ +/** + * 示例服务 + * @module @/api/tpl/example + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + /** + * 批量删除示例 + */ +bulkDelete :{ + url: `${config.API_URL}/api/tpl/example/bulk.delete`, + name: `批量删除示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 创建示例 + */ +create :{ + url: `${config.API_URL}/api/tpl/example/create`, + name: `创建示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 删除示例 + */ +delete :{ + url: `${config.API_URL}/api/tpl/example/delete`, + name: `删除示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 分页查询示例 + */ +pagedQuery :{ + url: `${config.API_URL}/api/tpl/example/paged.query`, + name: `分页查询示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 查询示例 + */ +query :{ + url: `${config.API_URL}/api/tpl/example/query`, + name: `查询示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +/** + * 更新示例 + */ +update :{ + url: `${config.API_URL}/api/tpl/example/update`, + name: `更新示例`, + post:async function(data={}, config={}) { + return await http.post(this.url,data, config) + } +}, + +} \ No newline at end of file diff --git a/src/frontend/h5/src/api/tpl/inner.js b/src/frontend/h5/src/api/tpl/inner.js new file mode 100644 index 00000000..d4dfd800 --- /dev/null +++ b/src/frontend/h5/src/api/tpl/inner.js @@ -0,0 +1,10 @@ +//~/** +//~ * $actionDesc$ +//~ */ +//~$actionName$ :{ +//~ url: `${config.API_URL}/$actionPath$`, +//~ name: `$actionDesc$`, +//~ $actionMethod$:async function(data={}, config={}) { +//~ return await http.$actionMethod$(this.url,data, config) +//~ } +//~}, \ No newline at end of file diff --git a/src/frontend/h5/src/api/tpl/outer.js b/src/frontend/h5/src/api/tpl/outer.js new file mode 100644 index 00000000..15b6479b --- /dev/null +++ b/src/frontend/h5/src/api/tpl/outer.js @@ -0,0 +1,13 @@ +/** + * $controllerDesc$ + * @module @/$controllerPath$ + */ + +import config from "@/config" +import http from "@/utils/request" + +export default { + + //~$inner$ + +} \ No newline at end of file diff --git a/src/frontend/h5/src/assets/base.css b/src/frontend/h5/src/assets/base.css new file mode 100644 index 00000000..bd6213e1 --- /dev/null +++ b/src/frontend/h5/src/assets/base.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/src/frontend/h5/src/assets/logo.svg b/src/frontend/h5/src/assets/logo.svg new file mode 100644 index 00000000..112e8bcf --- /dev/null +++ b/src/frontend/h5/src/assets/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/h5/src/assets/main.css b/src/frontend/h5/src/assets/main.css new file mode 100644 index 00000000..187e5139 --- /dev/null +++ b/src/frontend/h5/src/assets/main.css @@ -0,0 +1,11 @@ +@import './base.css'; + + +:root:root { + font-size: 110%; + --van-primary-color: var(--van-green); + --van-back-top-background: var(--van-green); + --van-dropdown-menu-title-font-size: 0.875rem; + --van-dropdown-menu-height: 2.5rem; + --van-dropdown-menu-shadow: none; +} \ No newline at end of file diff --git a/src/frontend/h5/src/components/Avatar.vue b/src/frontend/h5/src/components/Avatar.vue new file mode 100644 index 00000000..01e4ad65 --- /dev/null +++ b/src/frontend/h5/src/components/Avatar.vue @@ -0,0 +1,33 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/h5/src/components/HelloWorld.vue b/src/frontend/h5/src/components/HelloWorld.vue new file mode 100644 index 00000000..aaf630a4 --- /dev/null +++ b/src/frontend/h5/src/components/HelloWorld.vue @@ -0,0 +1,43 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/h5/src/components/InfinityScroll.vue b/src/frontend/h5/src/components/InfinityScroll.vue new file mode 100644 index 00000000..f8ce526c --- /dev/null +++ b/src/frontend/h5/src/components/InfinityScroll.vue @@ -0,0 +1,33 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/h5/src/components/TheWelcome.vue b/src/frontend/h5/src/components/TheWelcome.vue new file mode 100644 index 00000000..f552ad51 --- /dev/null +++ b/src/frontend/h5/src/components/TheWelcome.vue @@ -0,0 +1,86 @@ + + + \ No newline at end of file diff --git a/src/frontend/h5/src/components/WelcomeItem.vue b/src/frontend/h5/src/components/WelcomeItem.vue new file mode 100644 index 00000000..073b9604 --- /dev/null +++ b/src/frontend/h5/src/components/WelcomeItem.vue @@ -0,0 +1,85 @@ + + + \ No newline at end of file diff --git a/src/frontend/h5/src/components/icons/IconCommunity.vue b/src/frontend/h5/src/components/icons/IconCommunity.vue new file mode 100644 index 00000000..c5041633 --- /dev/null +++ b/src/frontend/h5/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/h5/src/components/icons/IconDocumentation.vue b/src/frontend/h5/src/components/icons/IconDocumentation.vue new file mode 100644 index 00000000..4f7f91e8 --- /dev/null +++ b/src/frontend/h5/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/h5/src/components/icons/IconEcosystem.vue b/src/frontend/h5/src/components/icons/IconEcosystem.vue new file mode 100644 index 00000000..e9aba796 --- /dev/null +++ b/src/frontend/h5/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/h5/src/components/icons/IconSupport.vue b/src/frontend/h5/src/components/icons/IconSupport.vue new file mode 100644 index 00000000..c6e5c4cd --- /dev/null +++ b/src/frontend/h5/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/frontend/h5/src/components/icons/IconTooling.vue b/src/frontend/h5/src/components/icons/IconTooling.vue new file mode 100644 index 00000000..dda879ec --- /dev/null +++ b/src/frontend/h5/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + \ No newline at end of file diff --git a/src/frontend/h5/src/components/verifition/Verify.vue b/src/frontend/h5/src/components/verifition/Verify.vue new file mode 100644 index 00000000..79c5a79b --- /dev/null +++ b/src/frontend/h5/src/components/verifition/Verify.vue @@ -0,0 +1,449 @@ + + + \ No newline at end of file diff --git a/src/frontend/h5/src/components/verifition/Verify/VerifySlide.vue b/src/frontend/h5/src/components/verifition/Verify/VerifySlide.vue new file mode 100644 index 00000000..c2f94ca3 --- /dev/null +++ b/src/frontend/h5/src/components/verifition/Verify/VerifySlide.vue @@ -0,0 +1,466 @@ + + \ No newline at end of file diff --git a/src/frontend/h5/src/components/verifition/utils/ase.js b/src/frontend/h5/src/components/verifition/utils/ase.js new file mode 100644 index 00000000..551eed4f --- /dev/null +++ b/src/frontend/h5/src/components/verifition/utils/ase.js @@ -0,0 +1,15 @@ +import CryptoJS from "crypto-js"; + +/** + * @word 要加密的内容 + * @keyWord String 服务器随机返回的关键字 + * */ +export function aesEncrypt(word, keyWord = "1Z?f(2)%v?:X5NYRl+]PSi.rDf7Ip#lB") { + const key = CryptoJS.enc.Utf8.parse(keyWord); + const srcs = CryptoJS.enc.Utf8.parse(word); + const encrypted = CryptoJS.AES.encrypt(srcs, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7, + }); + return encrypted.toString(); +} \ No newline at end of file diff --git a/src/frontend/h5/src/components/verifition/utils/util.js b/src/frontend/h5/src/components/verifition/utils/util.js new file mode 100644 index 00000000..619384ee --- /dev/null +++ b/src/frontend/h5/src/components/verifition/utils/util.js @@ -0,0 +1,109 @@ +export function resetSize(vm) { + let img_width, img_height, bar_width, bar_height; //图片的宽度、高度,移动条的宽度、高度 + + const parentWidth = vm.$el.parentNode.offsetWidth || window.offsetWidth; + const parentHeight = vm.$el.parentNode.offsetHeight || window.offsetHeight; + if (vm.imgSize.width.indexOf("%") !== -1) { + img_width = (parseInt(vm.imgSize.width) / 100) * parentWidth + "px"; + } else { + img_width = vm.imgSize.width; + } + + if (vm.imgSize.height.indexOf("%") !== -1) { + img_height = (parseInt(vm.imgSize.height) / 100) * parentHeight + "px"; + } else { + img_height = vm.imgSize.height; + } + + if (vm.barSize.width.indexOf("%") !== -1) { + bar_width = (parseInt(vm.barSize.width) / 100) * parentWidth + "px"; + } else { + bar_width = vm.barSize.width; + } + + if (vm.barSize.height.indexOf("%") !== -1) { + bar_height = (parseInt(vm.barSize.height) / 100) * parentHeight + "px"; + } else { + bar_height = vm.barSize.height; + } + + return { + imgWidth: img_width, + imgHeight: img_height, + barWidth: bar_width, + barHeight: bar_height, + }; +} + +export const _code_chars = [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", +]; +export const _code_color1 = ["#fffff0", "#f0ffff", "#f0fff0", "#fff0f0"]; +export const _code_color2 = [ + "#FF0033", + "#006699", + "#993366", + "#FF9900", + "#66CC66", + "#FF33CC", +]; \ No newline at end of file diff --git a/src/frontend/h5/src/config/index.js b/src/frontend/h5/src/config/index.js new file mode 100644 index 00000000..45db190b --- /dev/null +++ b/src/frontend/h5/src/config/index.js @@ -0,0 +1,34 @@ +/* eslint-disable no-undef */ +const DEFAULT_CONFIG = { + //接口地址 + API_URL: '', + + //请求超时 + TIMEOUT: 100000, + + //追加其他头 + HEADERS: {}, + + //请求是否开启缓存 + REQUEST_CACHE: false, + + //是否加密localStorage, 为空不加密,可填写AES(模式ECB,移位Pkcs7)加密 + LS_ENCRYPTION: '', + + //localStorageAES加密秘钥,位数建议填写8的倍数 + LS_ENCRYPTION_key: '2XNN4K8LC0ELVWN4', + + //常量字符串 + STRINGS: null, + + //本地化常量字符串 + LOC_STRINGS: null, + + //常量枚举 + ENUMS: null, + + //数字常量表, + NUMBERS: null +} + +export default DEFAULT_CONFIG \ No newline at end of file diff --git a/src/frontend/h5/src/main.js b/src/frontend/h5/src/main.js new file mode 100644 index 00000000..2f804463 --- /dev/null +++ b/src/frontend/h5/src/main.js @@ -0,0 +1,15 @@ +import './assets/main.css' +import { createApp } from 'vue' +import App from './App.vue' +import { createPinia } from 'pinia' +import router from './router' +import ddf from '@/ddf' +import van from '@/van' +import '@vant/touch-emulator' + +const app = createApp(App) +app.use(createPinia()) +app.use(router) +app.use(van) +await ddf.install(app) +app.mount('#app') \ No newline at end of file diff --git a/src/frontend/h5/src/router/index.js b/src/frontend/h5/src/router/index.js new file mode 100644 index 00000000..9293601b --- /dev/null +++ b/src/frontend/h5/src/router/index.js @@ -0,0 +1,58 @@ +import {createRouter, createWebHistory} from 'vue-router' +import HomeView from '../views/HomeView.vue' + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'home', + component: HomeView + }, + { + path: '/about', + name: 'about', + // route level code-splitting + // this generates a separate chunk (About.[hash].js) for this route + // which is lazy-loaded when the route is visited. + component: () => import('../views/AboutView.vue') + }, + { + path: '/category', + name: 'category', + component: () => import('../views/CategoryView.vue') + }, + { + path: '/product', + name: 'product', + component: () => import('../views/ProductView.vue') + }, + { + path: '/account/register', + name: 'register', + component: () => import('../views/account/RegisterView.vue') + }, + { + path: '/account/login-by-pwd', + name: 'loginByPwd', + component: () => import('../views/account/LoginByPwdView.vue') + }, + { + path: '/account/login-by-sms', + name: 'loginBySms', + component: () => import('../views/account/LoginBySmsView.vue') + }, + { + path: '/account/reset-pwd', + name: 'resetPwd', + component: () => import('../views/account/ResetPwdView.vue') + }, + { + path: '/member', + name: 'memberIndex', + component: () => import('../views/member/IndexView.vue') + } + ] +}) + +export default router \ No newline at end of file diff --git a/src/frontend/h5/src/stores/counter.js b/src/frontend/h5/src/stores/counter.js new file mode 100644 index 00000000..b0935259 --- /dev/null +++ b/src/frontend/h5/src/stores/counter.js @@ -0,0 +1,12 @@ +import { ref, computed } from 'vue' +import { defineStore } from 'pinia' + +export const useCounterStore = defineStore('counter', () => { + const count = ref(0) + const doubleCount = computed(() => count.value * 2) + function increment() { + count.value++ + } + + return { count, doubleCount, increment } +}) \ No newline at end of file diff --git a/src/frontend/h5/src/utils/request.js b/src/frontend/h5/src/utils/request.js new file mode 100644 index 00000000..29dc4bd2 --- /dev/null +++ b/src/frontend/h5/src/utils/request.js @@ -0,0 +1,263 @@ +import axios from 'axios' +import jsonBigInt from 'json-bigint' +import sysConfig from '@/config' +import tool from '@/utils/tool' +import {showDialog, showFailToast} from 'vant' +import router from "@/router"; + +axios.defaults.baseURL = '' + +axios.defaults.timeout = sysConfig.TIMEOUT + +// HTTP request 拦截器 +axios.interceptors.request.use( + (config) => { + let token = tool.cookie.get('TOKEN') + if (token) { + config.headers['Authorization'] = `Bearer ${token}` + let expires = tool.cookie.get('TOKEN-EXP') + //accessToken 已过期或 5分钟内过期 带上刷新token + if (!expires || expires - new Date().getTime() < 300000) { + let refresh_token = tool.cookie.get('X-TOKEN') + if (refresh_token) { + config.headers['X-Authorization'] = `Bearer ${refresh_token}` + } + } + } + + if (!sysConfig.REQUEST_CACHE && config.method === 'get') { + config.params = config.params || {} + config.params['_'] = new Date().getTime() + } + Object.assign(config.headers, sysConfig.HEADERS) + return config + }, + (error) => { + return Promise.reject(error) + } +) + + +// 进行大数字处理 +axios.defaults.transformResponse = [ + (data) => { + try { + return jsonBigInt.parse(data) + } catch { + return data + } + } +] + +// HTTP response 拦截器 +axios.interceptors.response.use( + (response) => { + let token = response.headers['access-token'] + let refreshToken = response.headers['x-access-token'] + if (token || refreshToken) { + let cookieExpires = tool.data.get('REMEMBER_ME') ? 24 * 60 * 60 * 7 : 0 + if (token) { + // 保存访问令牌 + tool.cookie.set('TOKEN', token, { + expires: cookieExpires, + path: '/' + }) + + // 解析访问令牌,保存令牌的失效时间 + const jwt = tool.crypto.decryptJWT(token) + const secs = jwt.exp - jwt.iat + tool.cookie.set('TOKEN-EXP', new Date().getTime() + secs * 1000, { + expires: cookieExpires, + path: '/' + }) + } + + if (refreshToken) { + // 保存刷新令牌 + tool.cookie.set('X-TOKEN', token, { + expires: cookieExpires, + path: '/' + }) + } + } + return response + }, + (error) => { + if (error.response) { + if (error.response.status === 404) { + showFailToast('Status:404,正在请求不存在的服务器记录!') + } else if (error.response.status === 401 || error.response.status === 403) { + showDialog({ + title: '无权限访问', + message: + '当前用户已被登出或无权限访问当前资源,请尝试重新登录后再操作。', + + }) + .then(() => { + // on confirm + router.push('/account/login-by-pwd') + }) + } else if (error.response.data.code) { + if (typeof error.response.data.msg == 'object') { + let i = 0 + for (const item in error.response.data.msg) { + i += 100 + setTimeout( + (title, msg) => { + showFailToast(msg) + }, + i, + item, + error.response.data.msg[item] + ) + } + } else { + showFailToast(error.response.data.msg) + } + } else { + showFailToast(error.message || `Status:${error.response.status},未知错误!`) + } + } else { + showFailToast('请求服务器无响应!') + } + + return Promise.reject(error.response) + } +) + +const http = { + /** get 请求 + * @param {接口地址} url + * @param {请求参数} params + * @param {参数} config + */ + get: function (url, params = {}, config = {}) { + return new Promise((resolve, reject) => { + axios({ + method: 'get', + url: url, + params: params, + ...config + }) + .then((response) => { + resolve(response.data) + }) + .catch((error) => { + reject(error) + }) + }) + }, + + /** post 请求 + * @param {接口地址} url + * @param {请求参数} data + * @param {参数} config + */ + post: function (url, data = {}, config = {}) { + return new Promise((resolve, reject) => { + axios({ + method: 'post', + url: url, + data: data, + ...config + }) + .then((response) => { + resolve(response.data) + }) + .catch((error) => { + reject(error) + }) + }) + }, + + /** put 请求 + * @param {接口地址} url + * @param {请求参数} data + * @param {参数} config + */ + put: function (url, data = {}, config = {}) { + return new Promise((resolve, reject) => { + axios({ + method: 'put', + url: url, + data: data, + ...config + }) + .then((response) => { + resolve(response.data) + }) + .catch((error) => { + reject(error) + }) + }) + }, + + /** patch 请求 + * @param {接口地址} url + * @param {请求参数} data + * @param {参数} config + */ + patch: function (url, data = {}, config = {}) { + return new Promise((resolve, reject) => { + axios({ + method: 'patch', + url: url, + data: data, + ...config + }) + .then((response) => { + resolve(response.data) + }) + .catch((error) => { + reject(error) + }) + }) + }, + + /** delete 请求 + * @param {接口地址} url + * @param {请求参数} data + * @param {参数} config + */ + delete: function (url, data = {}, config = {}) { + return new Promise((resolve, reject) => { + axios({ + method: 'delete', + url: url, + data: data, + ...config + }) + .then((response) => { + resolve(response.data) + }) + .catch((error) => { + reject(error) + }) + }) + }, + + /** jsonp 请求 + * @param {接口地址} url + * @param {JSONP回调函数名称} name + */ + jsonp: function (url, name = 'jsonp') { + return new Promise((resolve) => { + const script = document.createElement('script') + script.id = `jsonp${Math.ceil(Math.random() * 1000000)}` + script.type = 'text/javascript' + script.src = url + window[name] = (response) => { + resolve(response) + document.getElementsByTagName('head')[0].removeChild(script) + try { + delete window[name] + } catch (e) { + window[name] = undefined + } + } + document.getElementsByTagName('head')[0].appendChild(script) + }) + } +} + +export default http \ No newline at end of file diff --git a/src/frontend/h5/src/utils/tool.js b/src/frontend/h5/src/utils/tool.js new file mode 100644 index 00000000..81ec4af9 --- /dev/null +++ b/src/frontend/h5/src/utils/tool.js @@ -0,0 +1,284 @@ +/* + * @Description: 工具集 + * @version: 1.2 + * @LastEditors: sakuya + * @LastEditTime: 2022年5月24日00:28:56 + */ + +import CryptoJS from "crypto-js"; +import sysConfig from "@/config"; + +const tool = {}; + +/* localStorage */ +tool.data = { + set(key, data, datetime = 0) { + //加密 + if (sysConfig.LS_ENCRYPTION === "AES") { + data = tool.crypto.AES.encrypt( + JSON.stringify(data), + sysConfig.LS_ENCRYPTION_key + ); + } + let cacheValue = { + content: data, + datetime: + parseInt(datetime) === 0 + ? 0 + : new Date().getTime() + parseInt(datetime) * 1000, + }; + return localStorage.setItem(key, JSON.stringify(cacheValue)); + }, + get(key) { + try { + const value = JSON.parse(localStorage.getItem(key)); + if (value) { + let nowTime = new Date().getTime(); + if (nowTime > value.datetime && value.datetime !== 0) { + localStorage.removeItem(key); + return null; + } + //解密 + if (sysConfig.LS_ENCRYPTION === "AES") { + value.content = JSON.parse( + tool.crypto.AES.decrypt( + value.content, + sysConfig.LS_ENCRYPTION_key + ) + ); + } + return value.content; + } + return null; + } catch (err) { + return null; + } + }, + remove(key) { + return localStorage.removeItem(key); + }, + clear() { + return localStorage.clear(); + }, +}; + +/*sessionStorage*/ +tool.session = { + set(table, settings) { + const _set = JSON.stringify(settings); + return sessionStorage.setItem(table, _set); + }, + get(table) { + let data = sessionStorage.getItem(table); + try { + data = JSON.parse(data); + } catch (err) { + return null; + } + return data; + }, + remove(table) { + return sessionStorage.removeItem(table); + }, + clear() { + return sessionStorage.clear(); + }, +}; + +/*cookie*/ +tool.cookie = { + set(name, value, config = {}) { + const cfg = { + expires: null, + path: null, + domain: null, + secure: false, + httpOnly: false, + ...config, + }; + let cookieStr = `${name}=${escape(value)}`; + if (cfg.expires) { + const exp = new Date(); + exp.setTime(exp.getTime() + parseInt(cfg.expires) * 1000); + cookieStr += `;expires=${exp.toGMTString()}`; + } + if (cfg.path) { + cookieStr += `;path=${cfg.path}`; + } + if (cfg.domain) { + cookieStr += `;domain=${cfg.domain}`; + } + document.cookie = cookieStr; + }, + get(name) { + const arr = document.cookie.match( + new RegExp("(^| )" + name + "=([^;]*)(;|$)") + ); + if (arr != null) { + return unescape(arr[2]); + } else { + return null; + } + }, + remove(name) { + const exp = new Date(); + exp.setTime(exp.getTime() - 1); + document.cookie = `${name}=;expires=${exp.toGMTString()}`; + }, +}; + +/* Fullscreen */ +tool.screen = function (element) { + const isFull = !!( + document.webkitIsFullScreen || + document.mozFullScreen || + document.msFullscreenElement || + document.fullscreenElement + ); + if (isFull) { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } + } else { + if (element.requestFullscreen) { + element.requestFullscreen(); + } else if (element.msRequestFullscreen) { + element.msRequestFullscreen(); + } else if (element.mozRequestFullScreen) { + element.mozRequestFullScreen(); + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + } + } +}; + +/* 复制对象 */ +tool.objCopy = function (obj) { + return JSON.parse(JSON.stringify(obj)); +}; + +/* 日期格式化 */ +tool.dateFormat = function (date, fmt = "yyyy-MM-dd hh:mm:ss") { + date = new Date(date); + const o = { + "M+": date.getMonth() + 1, //月份 + "d+": date.getDate(), //日 + "h+": date.getHours(), //小时 + "m+": date.getMinutes(), //分 + "s+": date.getSeconds(), //秒 + "q+": Math.floor((date.getMonth() + 3) / 3), //季度 + S: date.getMilliseconds(), //毫秒 + }; + if (/(y+)/.test(fmt)) { + fmt = fmt.replace( + RegExp.$1, + (date.getFullYear() + "").substr(4 - RegExp.$1.length) + ); + } + for (let k in o) { + if (new RegExp("(" + k + ")").test(fmt)) { + fmt = fmt.replace( + RegExp.$1, + RegExp.$1.length === 1 + ? o[k] + : ("00" + o[k]).substr(("" + o[k]).length) + ); + } + } + return fmt; +}; + +/* 千分符 */ +tool.groupSeparator = function (num) { + num = num + ""; + if (!num.includes(".")) { + num += "."; + } + return num + .replace(/(\d)(?=(\d{3})+\.)/g, function ($0, $1) { + return $1 + ","; + }) + .replace(/\.$/, ""); +}; + +/* 常用加解密 */ +tool.crypto = { + /** + * 解密 JWT token 的信息 + * @param token jwt token 字符串 + * @returns object + */ + decryptJWT(token) { + token = token.replace(/_/g, "/").replace(/-/g, "+"); + const json = decodeURIComponent( + escape(window.atob(token.split(".")[1])) + ); + return JSON.parse(json); + }, + + //MD5加密 + MD5(data) { + return CryptoJS.MD5(data).toString(); + }, + //BASE64加解密 + BASE64: { + encrypt(data) { + return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data)); + }, + decrypt(cipher) { + return CryptoJS.enc.Base64.parse(cipher).toString( + CryptoJS.enc.Utf8 + ); + }, + }, + //AES加解密 + AES: { + encrypt(data, secretKey, config = {}) { + if (secretKey.length % 8 !== 0) { + console.warn( + "[SCUI error]: 秘钥长度需为8的倍数,否则解密将会失败。" + ); + } + const result = CryptoJS.AES.encrypt( + data, + CryptoJS.enc.Utf8.parse(secretKey), + { + iv: CryptoJS.enc.Utf8.parse(config.iv || ""), + mode: CryptoJS.mode[config.mode || "ECB"], + padding: CryptoJS.pad[config.padding || "Pkcs7"], + } + ); + return result.toString(); + }, + decrypt(cipher, secretKey, config = {}) { + const result = CryptoJS.AES.decrypt( + cipher, + CryptoJS.enc.Utf8.parse(secretKey), + { + iv: CryptoJS.enc.Utf8.parse(config.iv || ""), + mode: CryptoJS.mode[config.mode || "ECB"], + padding: CryptoJS.pad[config.padding || "Pkcs7"], + } + ); + return CryptoJS.enc.Utf8.stringify(result); + }, + }, + hashCode(str) { + let hash = 0; + if (str.length === 0) return hash; + for (let i = 0; i < str.length; i++) { + const char = str.charCodeAt(i); + hash = (hash << 5) - hash + char; + hash = hash & hash; // Convert to 32bit integer + } + return hash; + }, +}; + +export default tool; \ No newline at end of file diff --git a/src/frontend/h5/src/van.js b/src/frontend/h5/src/van.js new file mode 100644 index 00000000..f887e34b --- /dev/null +++ b/src/frontend/h5/src/van.js @@ -0,0 +1,74 @@ +import 'vant/lib/index.css' +import { + ActionBar, + ActionBarButton, + ActionBarIcon, + BackTop, + Button, + Cell, + CellGroup, + Col, + ContactCard, + DropdownItem, + DropdownMenu, + Field, + Form, + Grid, + GridItem, + Icon, + Image, + Lazyload, + List, + Notify, + NumberKeyboard, + PasswordInput, + PullRefresh, + Row, + Search, + Step, + Steps, + Tab, + Tabbar, + TabbarItem, + Tabs, + Toast, + TreeSelect +} from 'vant' + +export default { + install(app) { + app.use(Button) + app.use(Form) + app.use(Field) + app.use(CellGroup) + app.use(Cell) + app.use(Steps) + app.use(Step) + app.use(PasswordInput) + app.use(NumberKeyboard) + app.use(Notify) + app.use(Toast) + app.use(ContactCard) + app.use(Row) + app.use(Col) + app.use(Icon) + app.use(Tabbar) + app.use(TabbarItem) + app.use(Grid) + app.use(GridItem) + app.use(Image) + app.use(Lazyload) + app.use(PullRefresh) + app.use(Search) + app.use(Tabs) + app.use(Tab) + app.use(TreeSelect) + app.use(ActionBar) + app.use(ActionBarButton) + app.use(ActionBarIcon) + app.use(List) + app.use(DropdownMenu) + app.use(DropdownItem) + app.use(BackTop) + } +} \ No newline at end of file diff --git a/src/frontend/h5/src/views/AboutView.vue b/src/frontend/h5/src/views/AboutView.vue new file mode 100644 index 00000000..571e1811 --- /dev/null +++ b/src/frontend/h5/src/views/AboutView.vue @@ -0,0 +1,15 @@ + + + \ No newline at end of file diff --git a/src/frontend/h5/src/views/CategoryView.vue b/src/frontend/h5/src/views/CategoryView.vue new file mode 100644 index 00000000..28f12303 --- /dev/null +++ b/src/frontend/h5/src/views/CategoryView.vue @@ -0,0 +1,30 @@ + + + \ No newline at end of file diff --git a/src/frontend/h5/src/views/HomeView.vue b/src/frontend/h5/src/views/HomeView.vue new file mode 100644 index 00000000..a3559dc6 --- /dev/null +++ b/src/frontend/h5/src/views/HomeView.vue @@ -0,0 +1,175 @@ + + + \ No newline at end of file diff --git a/src/frontend/h5/src/views/ProductView.vue b/src/frontend/h5/src/views/ProductView.vue new file mode 100644 index 00000000..ea7a4e4e --- /dev/null +++ b/src/frontend/h5/src/views/ProductView.vue @@ -0,0 +1,35 @@ + + + \ No newline at end of file diff --git a/src/frontend/h5/src/views/account/LoginByPwdView.vue b/src/frontend/h5/src/views/account/LoginByPwdView.vue new file mode 100644 index 00000000..a375b87d --- /dev/null +++ b/src/frontend/h5/src/views/account/LoginByPwdView.vue @@ -0,0 +1,70 @@ + + + + \ No newline at end of file diff --git a/src/frontend/h5/src/views/account/LoginBySmsView.vue b/src/frontend/h5/src/views/account/LoginBySmsView.vue new file mode 100644 index 00000000..fec0f149 --- /dev/null +++ b/src/frontend/h5/src/views/account/LoginBySmsView.vue @@ -0,0 +1,191 @@ + + + + \ No newline at end of file diff --git a/src/frontend/h5/src/views/account/RegisterView.vue b/src/frontend/h5/src/views/account/RegisterView.vue new file mode 100644 index 00000000..f7b20b81 --- /dev/null +++ b/src/frontend/h5/src/views/account/RegisterView.vue @@ -0,0 +1,220 @@ + + + + \ No newline at end of file diff --git a/src/frontend/h5/src/views/account/ResetPwdView.vue b/src/frontend/h5/src/views/account/ResetPwdView.vue new file mode 100644 index 00000000..cc5bdbf7 --- /dev/null +++ b/src/frontend/h5/src/views/account/ResetPwdView.vue @@ -0,0 +1,211 @@ + + + + \ No newline at end of file diff --git a/src/frontend/h5/src/views/member/IndexView.vue b/src/frontend/h5/src/views/member/IndexView.vue new file mode 100644 index 00000000..43cbb0c8 --- /dev/null +++ b/src/frontend/h5/src/views/member/IndexView.vue @@ -0,0 +1,33 @@ + + + \ No newline at end of file diff --git a/src/frontend/h5/tailwind.config.js b/src/frontend/h5/tailwind.config.js new file mode 100644 index 00000000..fa42665e --- /dev/null +++ b/src/frontend/h5/tailwind.config.js @@ -0,0 +1,991 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./src/**/*.{html,js,vue}'], + presets: [], + darkMode: 'media', // or 'class' + theme: { + accentColor: ({ theme }) => ({ + ...theme('colors'), + auto: 'auto' + }), + animation: { + none: 'none', + spin: 'spin 1s linear infinite', + ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + pulse: 'pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite', + bounce: 'bounce 1s infinite' + }, + aria: { + checked: 'checked="true"', + disabled: 'disabled="true"', + expanded: 'expanded="true"', + hidden: 'hidden="true"', + pressed: 'pressed="true"', + readonly: 'readonly="true"', + required: 'required="true"', + selected: 'selected="true"' + }, + aspectRatio: { + auto: 'auto', + square: '1 / 1', + video: '16 / 9' + }, + backdropBlur: ({ theme }) => theme('blur'), + backdropBrightness: ({ theme }) => theme('brightness'), + backdropContrast: ({ theme }) => theme('contrast'), + backdropGrayscale: ({ theme }) => theme('grayscale'), + backdropHueRotate: ({ theme }) => theme('hueRotate'), + backdropInvert: ({ theme }) => theme('invert'), + backdropOpacity: ({ theme }) => theme('opacity'), + backdropSaturate: ({ theme }) => theme('saturate'), + backdropSepia: ({ theme }) => theme('sepia'), + backgroundColor: ({ theme }) => theme('colors'), + backgroundImage: { + none: 'none', + 'gradient-to-t': 'linear-gradient(to top, var(--tw-gradient-stops))', + 'gradient-to-tr': 'linear-gradient(to top right, var(--tw-gradient-stops))', + 'gradient-to-r': 'linear-gradient(to right, var(--tw-gradient-stops))', + 'gradient-to-br': 'linear-gradient(to bottom right, var(--tw-gradient-stops))', + 'gradient-to-b': 'linear-gradient(to bottom, var(--tw-gradient-stops))', + 'gradient-to-bl': 'linear-gradient(to bottom left, var(--tw-gradient-stops))', + 'gradient-to-l': 'linear-gradient(to left, var(--tw-gradient-stops))', + 'gradient-to-tl': 'linear-gradient(to top left, var(--tw-gradient-stops))' + }, + backgroundOpacity: ({ theme }) => theme('opacity'), + backgroundPosition: { + bottom: 'bottom', + center: 'center', + left: 'left', + 'left-bottom': 'left bottom', + 'left-top': 'left top', + right: 'right', + 'right-bottom': 'right bottom', + 'right-top': 'right top', + top: 'top' + }, + backgroundSize: { + auto: 'auto', + cover: 'cover', + contain: 'contain' + }, + blur: { + 0: '0', + none: '0', + sm: '4px', + DEFAULT: '8px', + md: '12px', + lg: '16px', + xl: '24px', + '2xl': '40px', + '3xl': '64px' + }, + borderColor: ({ theme }) => ({ + ...theme('colors'), + DEFAULT: theme('colors.gray.200', 'currentColor') + }), + borderOpacity: ({ theme }) => theme('opacity'), + borderRadius: { + none: '0px', + sm: '0.125rem', + DEFAULT: '0.25rem', + md: '0.375rem', + lg: '0.5rem', + xl: '0.75rem', + '2xl': '1rem', + '3xl': '1.5rem', + full: '9999px' + }, + borderSpacing: ({ theme }) => ({ + ...theme('spacing') + }), + borderWidth: { + DEFAULT: '1px', + 0: '0px', + 2: '2px', + 4: '4px', + 8: '8px' + }, + boxShadow: { + sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)', + DEFAULT: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)', + md: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)', + lg: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)', + xl: '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)', + '2xl': '0 25px 50px -12px rgb(0 0 0 / 0.25)', + inner: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)', + none: 'none' + }, + boxShadowColor: ({ theme }) => theme('colors'), + brightness: { + 0: '0', + 50: '.5', + 75: '.75', + 90: '.9', + 95: '.95', + 100: '1', + 105: '1.05', + 110: '1.1', + 125: '1.25', + 150: '1.5', + 200: '2' + }, + caretColor: ({ theme }) => theme('colors'), + colors: ({ colors }) => ({ + inherit: colors.inherit, + current: colors.current, + transparent: colors.transparent, + black: colors.black, + white: colors.white, + slate: colors.slate, + gray: colors.gray, + zinc: colors.zinc, + neutral: colors.neutral, + stone: colors.stone, + red: colors.red, + orange: colors.orange, + amber: colors.amber, + yellow: colors.yellow, + lime: colors.lime, + green: colors.green, + emerald: colors.emerald, + teal: colors.teal, + cyan: colors.cyan, + sky: colors.sky, + blue: colors.blue, + indigo: colors.indigo, + violet: colors.violet, + purple: colors.purple, + fuchsia: colors.fuchsia, + pink: colors.pink, + rose: colors.rose + }), + columns: { + auto: 'auto', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12', + '3xs': '16rem', + '2xs': '18rem', + xs: '20rem', + sm: '24rem', + md: '28rem', + lg: '32rem', + xl: '36rem', + '2xl': '42rem', + '3xl': '48rem', + '4xl': '56rem', + '5xl': '64rem', + '6xl': '72rem', + '7xl': '80rem' + }, + container: {}, + content: { + none: 'none' + }, + contrast: { + 0: '0', + 50: '.5', + 75: '.75', + 100: '1', + 125: '1.25', + 150: '1.5', + 200: '2' + }, + cursor: { + auto: 'auto', + default: 'default', + pointer: 'pointer', + wait: 'wait', + text: 'text', + move: 'move', + help: 'help', + 'not-allowed': 'not-allowed', + none: 'none', + 'context-menu': 'context-menu', + progress: 'progress', + cell: 'cell', + crosshair: 'crosshair', + 'vertical-text': 'vertical-text', + alias: 'alias', + copy: 'copy', + 'no-drop': 'no-drop', + grab: 'grab', + grabbing: 'grabbing', + 'all-scroll': 'all-scroll', + 'col-resize': 'col-resize', + 'row-resize': 'row-resize', + 'n-resize': 'n-resize', + 'e-resize': 'e-resize', + 's-resize': 's-resize', + 'w-resize': 'w-resize', + 'ne-resize': 'ne-resize', + 'nw-resize': 'nw-resize', + 'se-resize': 'se-resize', + 'sw-resize': 'sw-resize', + 'ew-resize': 'ew-resize', + 'ns-resize': 'ns-resize', + 'nesw-resize': 'nesw-resize', + 'nwse-resize': 'nwse-resize', + 'zoom-in': 'zoom-in', + 'zoom-out': 'zoom-out' + }, + divideColor: ({ theme }) => theme('borderColor'), + divideOpacity: ({ theme }) => theme('borderOpacity'), + divideWidth: ({ theme }) => theme('borderWidth'), + dropShadow: { + sm: '0 1px 1px rgb(0 0 0 / 0.05)', + DEFAULT: ['0 1px 2px rgb(0 0 0 / 0.1)', '0 1px 1px rgb(0 0 0 / 0.06)'], + md: ['0 4px 3px rgb(0 0 0 / 0.07)', '0 2px 2px rgb(0 0 0 / 0.06)'], + lg: ['0 10px 8px rgb(0 0 0 / 0.04)', '0 4px 3px rgb(0 0 0 / 0.1)'], + xl: ['0 20px 13px rgb(0 0 0 / 0.03)', '0 8px 5px rgb(0 0 0 / 0.08)'], + '2xl': '0 25px 25px rgb(0 0 0 / 0.15)', + none: '0 0 #0000' + }, + fill: ({ theme }) => ({ + none: 'none', + ...theme('colors') + }), + flex: { + 1: '1 1 0%', + auto: '1 1 auto', + initial: '0 1 auto', + none: 'none' + }, + flexBasis: ({ theme }) => ({ + auto: 'auto', + ...theme('spacing'), + '1/2': '50%', + '1/3': '33.333333%', + '2/3': '66.666667%', + '1/4': '25%', + '2/4': '50%', + '3/4': '75%', + '1/5': '20%', + '2/5': '40%', + '3/5': '60%', + '4/5': '80%', + '1/6': '16.666667%', + '2/6': '33.333333%', + '3/6': '50%', + '4/6': '66.666667%', + '5/6': '83.333333%', + '1/12': '8.333333%', + '2/12': '16.666667%', + '3/12': '25%', + '4/12': '33.333333%', + '5/12': '41.666667%', + '6/12': '50%', + '7/12': '58.333333%', + '8/12': '66.666667%', + '9/12': '75%', + '10/12': '83.333333%', + '11/12': '91.666667%', + full: '100%' + }), + flexGrow: { + 0: '0', + DEFAULT: '1' + }, + flexShrink: { + 0: '0', + DEFAULT: '1' + }, + fontFamily: { + sans: [ + 'ui-sans-serif', + 'system-ui', + '-apple-system', + 'BlinkMacSystemFont', + '"Segoe UI"', + 'Roboto', + '"Helvetica Neue"', + 'Arial', + '"Noto Sans"', + 'sans-serif', + '"Apple Color Emoji"', + '"Segoe UI Emoji"', + '"Segoe UI Symbol"', + '"Noto Color Emoji"' + ], + serif: ['ui-serif', 'Georgia', 'Cambria', '"Times New Roman"', 'Times', 'serif'], + mono: [ + 'ui-monospace', + 'SFMono-Regular', + 'Menlo', + 'Monaco', + 'Consolas', + '"Liberation Mono"', + '"Courier New"', + 'monospace' + ] + }, + fontSize: { + xs: ['0.75rem', { lineHeight: '1rem' }], + sm: ['0.875rem', { lineHeight: '1.25rem' }], + base: ['1rem', { lineHeight: '1.5rem' }], + lg: ['1.125rem', { lineHeight: '1.75rem' }], + xl: ['1.25rem', { lineHeight: '1.75rem' }], + '2xl': ['1.5rem', { lineHeight: '2rem' }], + '3xl': ['1.875rem', { lineHeight: '2.25rem' }], + '4xl': ['2.25rem', { lineHeight: '2.5rem' }], + '5xl': ['3rem', { lineHeight: '1' }], + '6xl': ['3.75rem', { lineHeight: '1' }], + '7xl': ['4.5rem', { lineHeight: '1' }], + '8xl': ['6rem', { lineHeight: '1' }], + '9xl': ['8rem', { lineHeight: '1' }] + }, + fontWeight: { + thin: '100', + extralight: '200', + light: '300', + normal: '400', + medium: '500', + semibold: '600', + bold: '700', + extrabold: '800', + black: '900' + }, + gap: ({ theme }) => theme('spacing'), + gradientColorStops: ({ theme }) => theme('colors'), + gradientColorStopPositions: { + '0%': '0%', + '5%': '5%', + '10%': '10%', + '15%': '15%', + '20%': '20%', + '25%': '25%', + '30%': '30%', + '35%': '35%', + '40%': '40%', + '45%': '45%', + '50%': '50%', + '55%': '55%', + '60%': '60%', + '65%': '65%', + '70%': '70%', + '75%': '75%', + '80%': '80%', + '85%': '85%', + '90%': '90%', + '95%': '95%', + '100%': '100%' + }, + grayscale: { + 0: '0', + DEFAULT: '100%' + }, + gridAutoColumns: { + auto: 'auto', + min: 'min-content', + max: 'max-content', + fr: 'minmax(0, 1fr)' + }, + gridAutoRows: { + auto: 'auto', + min: 'min-content', + max: 'max-content', + fr: 'minmax(0, 1fr)' + }, + gridColumn: { + auto: 'auto', + 'span-1': 'span 1 / span 1', + 'span-2': 'span 2 / span 2', + 'span-3': 'span 3 / span 3', + 'span-4': 'span 4 / span 4', + 'span-5': 'span 5 / span 5', + 'span-6': 'span 6 / span 6', + 'span-7': 'span 7 / span 7', + 'span-8': 'span 8 / span 8', + 'span-9': 'span 9 / span 9', + 'span-10': 'span 10 / span 10', + 'span-11': 'span 11 / span 11', + 'span-12': 'span 12 / span 12', + 'span-full': '1 / -1' + }, + gridColumnEnd: { + auto: 'auto', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12', + 13: '13' + }, + gridColumnStart: { + auto: 'auto', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12', + 13: '13' + }, + gridRow: { + auto: 'auto', + 'span-1': 'span 1 / span 1', + 'span-2': 'span 2 / span 2', + 'span-3': 'span 3 / span 3', + 'span-4': 'span 4 / span 4', + 'span-5': 'span 5 / span 5', + 'span-6': 'span 6 / span 6', + 'span-full': '1 / -1' + }, + gridRowEnd: { + auto: 'auto', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7' + }, + gridRowStart: { + auto: 'auto', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7' + }, + gridTemplateColumns: { + none: 'none', + 1: 'repeat(1, minmax(0, 1fr))', + 2: 'repeat(2, minmax(0, 1fr))', + 3: 'repeat(3, minmax(0, 1fr))', + 4: 'repeat(4, minmax(0, 1fr))', + 5: 'repeat(5, minmax(0, 1fr))', + 6: 'repeat(6, minmax(0, 1fr))', + 7: 'repeat(7, minmax(0, 1fr))', + 8: 'repeat(8, minmax(0, 1fr))', + 9: 'repeat(9, minmax(0, 1fr))', + 10: 'repeat(10, minmax(0, 1fr))', + 11: 'repeat(11, minmax(0, 1fr))', + 12: 'repeat(12, minmax(0, 1fr))' + }, + gridTemplateRows: { + none: 'none', + 1: 'repeat(1, minmax(0, 1fr))', + 2: 'repeat(2, minmax(0, 1fr))', + 3: 'repeat(3, minmax(0, 1fr))', + 4: 'repeat(4, minmax(0, 1fr))', + 5: 'repeat(5, minmax(0, 1fr))', + 6: 'repeat(6, minmax(0, 1fr))' + }, + height: ({ theme }) => ({ + auto: 'auto', + ...theme('spacing'), + '1/2': '50%', + '1/3': '33.333333%', + '2/3': '66.666667%', + '1/4': '25%', + '2/4': '50%', + '3/4': '75%', + '1/5': '20%', + '2/5': '40%', + '3/5': '60%', + '4/5': '80%', + '1/6': '16.666667%', + '2/6': '33.333333%', + '3/6': '50%', + '4/6': '66.666667%', + '5/6': '83.333333%', + full: '100%', + screen: '100vh', + min: 'min-content', + max: 'max-content', + fit: 'fit-content' + }), + hueRotate: { + 0: '0deg', + 15: '15deg', + 30: '30deg', + 60: '60deg', + 90: '90deg', + 180: '180deg' + }, + inset: ({ theme }) => ({ + auto: 'auto', + ...theme('spacing'), + '1/2': '50%', + '1/3': '33.333333%', + '2/3': '66.666667%', + '1/4': '25%', + '2/4': '50%', + '3/4': '75%', + full: '100%' + }), + invert: { + 0: '0', + DEFAULT: '100%' + }, + keyframes: { + spin: { + to: { + transform: 'rotate(360deg)' + } + }, + ping: { + '75%, 100%': { + transform: 'scale(2)', + opacity: '0' + } + }, + pulse: { + '50%': { + opacity: '.5' + } + }, + bounce: { + '0%, 100%': { + transform: 'translateY(-25%)', + animationTimingFunction: 'cubic-bezier(0.8,0,1,1)' + }, + '50%': { + transform: 'none', + animationTimingFunction: 'cubic-bezier(0,0,0.2,1)' + } + } + }, + letterSpacing: { + tighter: '-0.05em', + tight: '-0.025em', + normal: '0em', + wide: '0.025em', + wider: '0.05em', + widest: '0.1em' + }, + lineHeight: { + none: '1', + tight: '1.25', + snug: '1.375', + normal: '1.5', + relaxed: '1.625', + loose: '2', + 3: '.75rem', + 4: '1rem', + 5: '1.25rem', + 6: '1.5rem', + 7: '1.75rem', + 8: '2rem', + 9: '2.25rem', + 10: '2.5rem' + }, + listStyleType: { + none: 'none', + disc: 'disc', + decimal: 'decimal' + }, + listStyleImage: { + none: 'none' + }, + margin: ({ theme }) => ({ + auto: 'auto', + ...theme('spacing') + }), + lineClamp: { + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6' + }, + maxHeight: ({ theme }) => ({ + ...theme('spacing'), + none: 'none', + full: '100%', + screen: '100vh', + min: 'min-content', + max: 'max-content', + fit: 'fit-content' + }), + maxWidth: ({ theme, breakpoints }) => ({ + none: 'none', + 0: '0rem', + xs: '20rem', + sm: '24rem', + md: '28rem', + lg: '32rem', + xl: '36rem', + '2xl': '42rem', + '3xl': '48rem', + '4xl': '56rem', + '5xl': '64rem', + '6xl': '72rem', + '7xl': '80rem', + full: '100%', + min: 'min-content', + max: 'max-content', + fit: 'fit-content', + prose: '65ch', + ...breakpoints(theme('screens')) + }), + minHeight: { + 0: '0px', + full: '100%', + screen: '100vh', + min: 'min-content', + max: 'max-content', + fit: 'fit-content' + }, + minWidth: { + 0: '0px', + full: '100%', + min: 'min-content', + max: 'max-content', + fit: 'fit-content' + }, + objectPosition: { + bottom: 'bottom', + center: 'center', + left: 'left', + 'left-bottom': 'left bottom', + 'left-top': 'left top', + right: 'right', + 'right-bottom': 'right bottom', + 'right-top': 'right top', + top: 'top' + }, + opacity: { + 0: '0', + 5: '0.05', + 10: '0.1', + 20: '0.2', + 25: '0.25', + 30: '0.3', + 40: '0.4', + 50: '0.5', + 60: '0.6', + 70: '0.7', + 75: '0.75', + 80: '0.8', + 90: '0.9', + 95: '0.95', + 100: '1' + }, + order: { + first: '-9999', + last: '9999', + none: '0', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12' + }, + outlineColor: ({ theme }) => theme('colors'), + outlineOffset: { + 0: '0px', + 1: '1px', + 2: '2px', + 4: '4px', + 8: '8px' + }, + outlineWidth: { + 0: '0px', + 1: '1px', + 2: '2px', + 4: '4px', + 8: '8px' + }, + padding: ({ theme }) => theme('spacing'), + placeholderColor: ({ theme }) => theme('colors'), + placeholderOpacity: ({ theme }) => theme('opacity'), + ringColor: ({ theme }) => ({ + DEFAULT: theme('colors.blue.500', '#3b82f6'), + ...theme('colors') + }), + ringOffsetColor: ({ theme }) => theme('colors'), + ringOffsetWidth: { + 0: '0px', + 1: '1px', + 2: '2px', + 4: '4px', + 8: '8px' + }, + ringOpacity: ({ theme }) => ({ + DEFAULT: '0.5', + ...theme('opacity') + }), + ringWidth: { + DEFAULT: '3px', + 0: '0px', + 1: '1px', + 2: '2px', + 4: '4px', + 8: '8px' + }, + rotate: { + 0: '0deg', + 1: '1deg', + 2: '2deg', + 3: '3deg', + 6: '6deg', + 12: '12deg', + 45: '45deg', + 90: '90deg', + 180: '180deg' + }, + saturate: { + 0: '0', + 50: '.5', + 100: '1', + 150: '1.5', + 200: '2' + }, + scale: { + 0: '0', + 50: '.5', + 75: '.75', + 90: '.9', + 95: '.95', + 100: '1', + 105: '1.05', + 110: '1.1', + 125: '1.25', + 150: '1.5' + }, + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px' + }, + scrollMargin: ({ theme }) => ({ + ...theme('spacing') + }), + scrollPadding: ({ theme }) => theme('spacing'), + sepia: { + 0: '0', + DEFAULT: '100%' + }, + skew: { + 0: '0deg', + 1: '1deg', + 2: '2deg', + 3: '3deg', + 6: '6deg', + 12: '12deg' + }, + space: ({ theme }) => ({ + ...theme('spacing') + }), + spacing: { + px: '1px', + 0: '0px', + 0.5: '0.125rem', + 1: '0.25rem', + 1.5: '0.375rem', + 2: '0.5rem', + 2.5: '0.625rem', + 3: '0.75rem', + 3.5: '0.875rem', + 4: '1rem', + 5: '1.25rem', + 6: '1.5rem', + 7: '1.75rem', + 8: '2rem', + 9: '2.25rem', + 10: '2.5rem', + 11: '2.75rem', + 12: '3rem', + 14: '3.5rem', + 16: '4rem', + 20: '5rem', + 24: '6rem', + 28: '7rem', + 32: '8rem', + 36: '9rem', + 40: '10rem', + 44: '11rem', + 48: '12rem', + 52: '13rem', + 56: '14rem', + 60: '15rem', + 64: '16rem', + 72: '18rem', + 80: '20rem', + 96: '24rem' + }, + stroke: ({ theme }) => ({ + none: 'none', + ...theme('colors') + }), + strokeWidth: { + 0: '0', + 1: '1', + 2: '2' + }, + supports: {}, + data: {}, + textColor: ({ theme }) => theme('colors'), + textDecorationColor: ({ theme }) => theme('colors'), + textDecorationThickness: { + auto: 'auto', + 'from-font': 'from-font', + 0: '0px', + 1: '1px', + 2: '2px', + 4: '4px', + 8: '8px' + }, + textIndent: ({ theme }) => ({ + ...theme('spacing') + }), + textOpacity: ({ theme }) => theme('opacity'), + textUnderlineOffset: { + auto: 'auto', + 0: '0px', + 1: '1px', + 2: '2px', + 4: '4px', + 8: '8px' + }, + transformOrigin: { + center: 'center', + top: 'top', + 'top-right': 'top right', + right: 'right', + 'bottom-right': 'bottom right', + bottom: 'bottom', + 'bottom-left': 'bottom left', + left: 'left', + 'top-left': 'top left' + }, + transitionDelay: { + 0: '0s', + 75: '75ms', + 100: '100ms', + 150: '150ms', + 200: '200ms', + 300: '300ms', + 500: '500ms', + 700: '700ms', + 1000: '1000ms' + }, + transitionDuration: { + DEFAULT: '150ms', + 0: '0s', + 75: '75ms', + 100: '100ms', + 150: '150ms', + 200: '200ms', + 300: '300ms', + 500: '500ms', + 700: '700ms', + 1000: '1000ms' + }, + transitionProperty: { + none: 'none', + all: 'all', + DEFAULT: + 'color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter', + colors: 'color, background-color, border-color, text-decoration-color, fill, stroke', + opacity: 'opacity', + shadow: 'box-shadow', + transform: 'transform' + }, + transitionTimingFunction: { + DEFAULT: 'cubic-bezier(0.4, 0, 0.2, 1)', + linear: 'linear', + in: 'cubic-bezier(0.4, 0, 1, 1)', + out: 'cubic-bezier(0, 0, 0.2, 1)', + 'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)' + }, + translate: ({ theme }) => ({ + ...theme('spacing'), + '1/2': '50%', + '1/3': '33.333333%', + '2/3': '66.666667%', + '1/4': '25%', + '2/4': '50%', + '3/4': '75%', + full: '100%' + }), + width: ({ theme }) => ({ + auto: 'auto', + ...theme('spacing'), + '1/2': '50%', + '1/3': '33.333333%', + '2/3': '66.666667%', + '1/4': '25%', + '2/4': '50%', + '3/4': '75%', + '1/5': '20%', + '2/5': '40%', + '3/5': '60%', + '4/5': '80%', + '1/6': '16.666667%', + '2/6': '33.333333%', + '3/6': '50%', + '4/6': '66.666667%', + '5/6': '83.333333%', + '1/12': '8.333333%', + '2/12': '16.666667%', + '3/12': '25%', + '4/12': '33.333333%', + '5/12': '41.666667%', + '6/12': '50%', + '7/12': '58.333333%', + '8/12': '66.666667%', + '9/12': '75%', + '10/12': '83.333333%', + '11/12': '91.666667%', + full: '100%', + screen: '100vw', + min: 'min-content', + max: 'max-content', + fit: 'fit-content' + }), + willChange: { + auto: 'auto', + scroll: 'scroll-position', + contents: 'contents', + transform: 'transform' + }, + zIndex: { + auto: 'auto', + 0: '0', + 10: '10', + 20: '20', + 30: '30', + 40: '40', + 50: '50' + } + }, + plugins: [] +} \ No newline at end of file diff --git a/src/frontend/h5/vite.config.js b/src/frontend/h5/vite.config.js new file mode 100644 index 00000000..e26fb91c --- /dev/null +++ b/src/frontend/h5/vite.config.js @@ -0,0 +1,22 @@ +import { fileURLToPath, URL } from 'node:url' +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue()], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + }, + server: { + host: '172.29.19.169', + proxy: { + '/api': { + target: 'http://172.29.19.169:65010', + changeOrigin: true + } + } + } +}) \ No newline at end of file diff --git a/tools/CloneProjectRefs.ps1 b/tools/CloneProjectRefs.ps1 new file mode 100644 index 00000000..7ebf9e56 --- /dev/null +++ b/tools/CloneProjectRefs.ps1 @@ -0,0 +1,6 @@ +$refs = ('https://github.com/nsnail/ns-ext.git', 'https://github.com/nsnail/Furion.git', 'https://github.com/nsnail/FreeSql.git') + +foreach ($item in $refs) +{ + git clone --depth 1 --config "http.proxy=http://127.0.0.1:1081" $item "../refs/$( [regex]::Match($item, '/([^/]+)\.git$').Groups[1] )" +} \ No newline at end of file diff --git a/tools/CodeCleanup.csx b/tools/CodeCleanup.csx new file mode 100644 index 00000000..cb98db8e --- /dev/null +++ b/tools/CodeCleanup.csx @@ -0,0 +1,44 @@ +using System.Text.RegularExpressions; +using System.Net.Http; +using System.Net.Http.Json; + + +{ + var files = string.Join( + ';', + Args[0] + .Split('\n', StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Replace('\\', '/').Trim()) + ); + + Console.WriteLine(files); + + using var p = Process.Start( + new ProcessStartInfo + { + CreateNoWindow = true, + FileName = "dotnet", + Arguments = $"jb cleanupcode --include=\"{files}\" --no-build ../NetAdmin.sln", + UseShellExecute = false, + RedirectStandardOutput = true + } + ); + p.WaitForExit(); + Console.WriteLine(p.StandardOutput.ReadToEnd()); + + using var p2 = Process.Start( + new ProcessStartInfo + { + CreateNoWindow = true, + FileName = "git", + Arguments = $"status", + UseShellExecute = false, + RedirectStandardOutput = true + } + ); + p2.WaitForExit(); + var content = p2.StandardOutput.ReadToEnd(); + Console.WriteLine(content); + + return content.Contains("working tree clean") ? 0 : 1; +} \ No newline at end of file diff --git a/tools/CodeCleanup.ps1 b/tools/CodeCleanup.ps1 new file mode 100644 index 00000000..4a6fc66f --- /dev/null +++ b/tools/CodeCleanup.ps1 @@ -0,0 +1,7 @@ +$files = $( foreach ($line in $( git diff head origin/dev --stat-width 200 ) | findstr '\|') +{ + $line.split('\|')[0].trim() +} ) -join ';' +echo $files +dotnet jb cleanupcode --no-build --include = "$files" ../NetAdmin.sln +dotnet script ../PushSign.csx \ No newline at end of file diff --git a/tools/CodeCleanupFull.ps1 b/tools/CodeCleanupFull.ps1 new file mode 100644 index 00000000..5e79a0a0 --- /dev/null +++ b/tools/CodeCleanupFull.ps1 @@ -0,0 +1 @@ +dotnet jb cleanupcode --no-build ../NetAdmin.sln \ No newline at end of file diff --git a/tools/DotClean.cmd b/tools/DotClean.cmd new file mode 100644 index 00000000..b396ab2b --- /dev/null +++ b/tools/DotClean.cmd @@ -0,0 +1,3 @@ +dot rbom ../ -w -e refs -e .git -e node_modules +dot trim ../ -w -e refs -e .git -e node_modules +dot tolf ../ -w -e refs -e .git -e node_modules \ No newline at end of file diff --git a/tools/GenerateLn.cmd b/tools/GenerateLn.cmd new file mode 100644 index 00000000..26ec0108 --- /dev/null +++ b/tools/GenerateLn.cmd @@ -0,0 +1,2 @@ +dotnet t4 ./GenerateLnResx.tt -o ../assets/resx/Ln.resx +dotnet t4 ./GenerateLnCs.tt -o ../dist/Server/NetAdmin.Infrastructure/Ln.cs \ No newline at end of file diff --git a/tools/GenerateLnCs.tt b/tools/GenerateLnCs.tt new file mode 100644 index 00000000..c36f2b30 --- /dev/null +++ b/tools/GenerateLnCs.tt @@ -0,0 +1,78 @@ +<#@ template language="C#" #> +<#@ assembly name="System.Xml" #> +<#@ output encoding="utf-8" extension="Designer.cs" #> +<#@ import namespace="System.Xml" #> + +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System.CodeDom.Compiler; +using System.Diagnostics.CodeAnalysis; +using System.Resources; +using System.Runtime.CompilerServices; + +namespace NetAdmin.Infrastructure.Languages; + +/// +/// A strongly-typed resource class, for looking up localized strings, etc. +/// + +// This class was auto-generated by the StronglyTypedResourceBuilder +// class via a tool like ResGen or Visual Studio. +// To add or remove a member, edit your .ResX file then rerun ResGen +// with the /str option, or rebuild your VS project. +[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] +[DebuggerNonUserCode] +[CompilerGenerated] +public sealed class Ln +{ + private static ResourceManager _resourceMan; + + /// + /// Initializes a new instance of the class. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public Ln() { } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [EditorBrowsable(EditorBrowsableState.Advanced)] + public static ResourceManager ResourceManager { + get { + if (ReferenceEquals(_resourceMan, null)) { + var temp = new ResourceManager("NetAdmin.Infrastructure.Languages.Ln", typeof(Ln).Assembly); + _resourceMan = temp; + } + + return _resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [EditorBrowsable(EditorBrowsableState.Advanced)] + public static CultureInfo Culture { get; set; } +<# + var xml = new XmlDocument(); + xml.Load("../assets/resx/Ln.resx"); + foreach (XmlNode data in xml.SelectNodes("//root/data")!) + { +#> + /// + /// <#= data.SelectSingleNode("value")?.InnerText #> + /// + public static string <#= + data.Attributes!["name"].Value.Replace(" ", "_") #> => ResourceManager.GetString("<#= data.Attributes!["name"].Value #>", Culture); +<# + } +#> +} \ No newline at end of file diff --git a/tools/GenerateLnResx.tt b/tools/GenerateLnResx.tt new file mode 100644 index 00000000..78e3648d --- /dev/null +++ b/tools/GenerateLnResx.tt @@ -0,0 +1,36 @@ +<#@ template language="C#" #> +<#@ output encoding="utf-8" extension="resx" #> + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + + + <# + var regex = new System.Text.RegularExpressions.Regex(@"^\d", System.Text.RegularExpressions.RegexOptions.Compiled); + foreach (var line in System.IO.File.ReadLines("../assets/resx/ln.txt")) + { +#> + <#= line #>" xml:space="preserve"><#= line #> +<# + } +#> + \ No newline at end of file diff --git a/tools/GitPR.ps1 b/tools/GitPR.ps1 new file mode 100644 index 00000000..705eb57d --- /dev/null +++ b/tools/GitPR.ps1 @@ -0,0 +1,26 @@ +$types = @{ + '1' = @('FEA', '新增特性') + '2' = @('REF', '项目重构') + '3' = @('FIX', '缺陷修复') + '4' = @('PER', '性能优化') + '5' = @('RVT', '还原变更') + '6' = @('FMT', '格式整理') + '7' = @('DOC', '文档变更') + '8' = @('TST', '单元测试') + '9' = @('BLD', '工程构建') +} +git add ../ +$prefix = '' +while ($null -eq $types[$prefix]) +{ + $prefix = Read-Host "请选择提交类型`n" $( & { param($i) $i | ForEach-Object { "$_ : $( $types[$_][0] )($( $types[$_][1] ))`n" } } $types.Keys | Sort-Object ) +} +git commit -m "[$($types[$prefix][0])] $(($(Read-Host '是否跳过自动构建?(y/N)') -eq 'y') ? '[SKIP CI] ': '')$(Read-Host '请输入提交消息')" +$branch = $(git branch --show-current) +& './DotClean.cmd' +git add ../ +git commit --amend --no-edit +git pull +git push --set-upstream origin $branch +Start-Process -FilePath "http://git.shequnpay.com/lingyun/NetAdmin/compare/dev...$branch" +Pause \ No newline at end of file diff --git a/tools/GitRecreate.ps1 b/tools/GitRecreate.ps1 new file mode 100644 index 00000000..f3910e20 --- /dev/null +++ b/tools/GitRecreate.ps1 @@ -0,0 +1,6 @@ +$branch = $(git branch --show-current) +git checkout dev +git pull +git branch -D $branch +git branch $branch +git checkout $branch \ No newline at end of file diff --git a/tools/IdGenerator.linq b/tools/IdGenerator.linq new file mode 100644 index 00000000..ee4f8175 --- /dev/null +++ b/tools/IdGenerator.linq @@ -0,0 +1,37 @@ + + Yitter.IdGenerator + Yitter.IdGenerator + + +void Main() +{ + //第1步,全局 初始化(应用程序启动时执行一次): + + // 创建 IdGeneratorOptions 对象,可在构造函数中输入 WorkerId: + var options = new IdGeneratorOptions(); + // options.WorkerIdBitLength = 10; // 默认值6,限定 WorkerId 最大值为2^6-1,即默认最多支持64个节点。 + // options.SeqBitLength = 6; // 默认值6,限制每毫秒生成的ID个数。若生成速度超过5万个/秒,建议加大 SeqBitLength 到 10。 + // options.BaseTime = Your_Base_Time; // 如果要兼容老系统的雪花算法,此处应设置为老系统的BaseTime。 + // ...... 其它参数参考 IdGeneratorOptions 定义。 + + // 保存参数(务必调用,否则参数设置不生效): + YitIdHelper.SetIdGenerator(options); + + // 以上过程只需全局一次,且应在生成ID之前完成。 + //第2步,生成ID: + + // 初始化后,在任何需要生成ID的地方,调用以下方法: + for (int i = 0; i < 20; i++) + { + var newId = YitIdHelper.NextId(); + Console.WriteLine(newId); + } + + for (int i = 0; i < 20; i++) + { + Console.WriteLine(Guid.NewGuid()); + } + +} + +// You can define other methods, fields, classes and namespaces here \ No newline at end of file diff --git a/tools/ImageOptimize.csx b/tools/ImageOptimize.csx new file mode 100644 index 00000000..ccbbeaa6 --- /dev/null +++ b/tools/ImageOptimize.csx @@ -0,0 +1,65 @@ +/* + for %%i in (*.png) do pngquant %%i --force --output %%i --skip-if-larger + for %%i in (*.jpg) do jpegtran -copy none -optimize -perfect %%i %%i + * + */ + + +var files = Directory + .EnumerateFiles( + ".", + "*.png", + new EnumerationOptions + { + RecurseSubdirectories = true, + AttributesToSkip = FileAttributes.ReparsePoint, + IgnoreInaccessible = true + } + ) + .ToArray(); + +Parallel.ForEach( + files, + file => + { + var startInfo = new ProcessStartInfo + { + FileName = "pngquant", + Arguments = $"\"{file}\" --force --output \"{file}\" --skip-if-larger" + }; + using var p = Process.Start(startInfo); + p.WaitForExit(); + Console.WriteLine($"{file}: {p.ExitCode}"); + } +); + +files = new[] { "*.jpg", "*.jpeg" } + .SelectMany( + x => + Directory.EnumerateFiles( + ".", + x, + new EnumerationOptions + { + RecurseSubdirectories = true, + AttributesToSkip = FileAttributes.ReparsePoint, + IgnoreInaccessible = true + } + ) + ) + .ToArray(); + +Parallel.ForEach( + files, + file => + { + var startInfo = new ProcessStartInfo + { + FileName = "jpegtran", + Arguments = $"-copy none -optimize -perfect \"{file}\" \"{file}\"" + }; + using var p = Process.Start(startInfo); + p.WaitForExit(); + Console.WriteLine($"{file}: {p.ExitCode}"); + } +); \ No newline at end of file diff --git a/tools/InstallAsTpl.ps1 b/tools/InstallAsTpl.ps1 new file mode 100644 index 00000000..ad933ddc --- /dev/null +++ b/tools/InstallAsTpl.ps1 @@ -0,0 +1,2 @@ +dotnet new uninstall ../ +dotnet new --install ../ \ No newline at end of file diff --git a/tools/Switcher.FreeSql.json b/tools/Switcher.FreeSql.json new file mode 100644 index 00000000..555178be --- /dev/null +++ b/tools/Switcher.FreeSql.json @@ -0,0 +1,22 @@ +{ + "solution": "../NetAdmin.sln", + "mappings": { + "FreeSql.NS": "../refs/FreeSql/FreeSql/FreeSql.csproj", + "FreeSql.DbContext.NS": "../refs/FreeSql/FreeSql.DbContext/FreeSql.DbContext.csproj" + }, + "restore": [ + { + "name": "NetAdmin.Infrastructure", + "packages": [ + { + "packageName": "FreeSql.NS", + "version": "3.2.700-preview20230726-ns1" + }, + { + "packageName": "FreeSql.DbContext.NS", + "version": "3.2.700-preview20230726-ns1" + } + ] + } + ] +} \ No newline at end of file diff --git a/tools/Switcher.Furion.json b/tools/Switcher.Furion.json new file mode 100644 index 00000000..0953e73c --- /dev/null +++ b/tools/Switcher.Furion.json @@ -0,0 +1,17 @@ +{ + "solution": "../NetAdmin.sln", + "mappings": { + "Furion.Pure.NS": "../refs/Furion/framework/Furion.Pure/Furion.Pure.csproj" + }, + "restore": [ + { + "name": "NetAdmin.Infrastructure", + "packages": [ + { + "packageName": "Furion.Pure.NS", + "version": "4.8.8.38-ns1" + } + ] + } + ] +} \ No newline at end of file diff --git a/tools/Switcher.NSExt.json b/tools/Switcher.NSExt.json new file mode 100644 index 00000000..6e04dea5 --- /dev/null +++ b/tools/Switcher.NSExt.json @@ -0,0 +1,17 @@ +{ + "solution": "../NetAdmin.sln", + "mappings": { + "NSExt": "../refs/ns-ext/src/NSExt/NSExt.csproj" + }, + "restore": [ + { + "name": "NetAdmin.Infrastructure", + "packages": [ + { + "packageName": "NSExt", + "version": "1.0.15-alpha.0.4" + } + ] + } + ] +} \ No newline at end of file diff --git a/tools/Switcher.ps1 b/tools/Switcher.ps1 new file mode 100644 index 00000000..54200367 --- /dev/null +++ b/tools/Switcher.ps1 @@ -0,0 +1,27 @@ +# https://github.com/RicoSuter/DNT#switch-to-projects +$targets = @{ + '1' = 'switch-to-projects' + '2' = 'switch-to-packages' +} +$key = '' +while ($null -eq $targets[$key]) +{ + $key = Read-Host '请选择:1(切换到项目引用) 2(切换到Nuget包引用)' +} +$files = Get-ChildItem Switcher.*.json +$file = 9999 +while ($null -eq $files[[int]$file - 1]) +{ + $i = 0 + Write-Host '请选择要切换的配置文件文件' + foreach ($file in $files) + { + $i++ + Write-Host $i $file.Name + } + $file = Read-Host +} +$file = [int]$file - 1 +Copy-Item $files[$file] 'switcher.json' -Force +dotnet dnt $targets[$key] +Remove-Item switcher.json \ No newline at end of file diff --git a/tools/SyncMetaFiles.csx b/tools/SyncMetaFiles.csx new file mode 100644 index 00000000..824b506c --- /dev/null +++ b/tools/SyncMetaFiles.csx @@ -0,0 +1,33 @@ +using System.Text.RegularExpressions; + +var slnFile = Directory.GetFiles(@"../", "*.sln").First(); +var content = File.ReadAllText(slnFile); + +content = Regex.Replace( + content, + "Project\\(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\"\\) = \"meta\", \"meta\", \"{5198A03D-0CAC-4828-A807-34A693F73859}\"(?:.|\n)*?EndProject", + $$""" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{5198A03D-0CAC-4828-A807-34A693F73859}" +{{'\t'}}ProjectSection(SolutionItems) = preProject +{{string.Join('\n', + Directory.GetFiles(@"../", "*").Where(x => !x.EndsWith(".sln") && !x.EndsWith(".user")) + .Select(x=>$"\t\t{Path.GetFileName(x)} = {Path.GetFileName(x)}") + )}} +{{'\t'}}EndProject +""" +); +content = Regex.Replace( + content, + "Project\\(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\"\\) = \"tools\", \"tools\", \"{2D81D62C-1B2E-4758-84C6-728343CB734F}\"(?:.|\n)*?EndProject", + $$""" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{2D81D62C-1B2E-4758-84C6-728343CB734F}" +{{'\t'}}ProjectSection(SolutionItems) = preProject +{{string.Join('\n', + Directory.GetFiles(@"../tools", "*").Where(x => !x.EndsWith(".sln") && !x.EndsWith(".user")) + .Select(x=>$"\t\t{Path.GetFileName(x)} = tools/{Path.GetFileName(x)}") + )}} +{{'\t'}}EndProject +""" +); +Console.WriteLine(content); +File.WriteAllText(slnFile, content); \ No newline at end of file