master
ceruIean 2021-10-19 06:29:11 +08:00
commit 60131e4608
131 changed files with 46479 additions and 0 deletions

25
.dockerignore 100644
View File

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

47
.drone.yml 100644
View File

@ -0,0 +1,47 @@
kind: pipeline
type: docker
name: build
steps:
- name: build
image: docker
commands:
- docker build -t eva-nx-backend .
volumes:
- name: cache
path: /var/run/docker.sock
trigger:
branch:
- master
- dev
event:
- push
- pull_request
- rollback
volumes:
- name: cache
host:
path: /var/run/docker.sock
---
kind: pipeline
type: exec
name: deploy
platform:
os: linux
arзуh: amd64
steps:
- name: deploy
commands:
- cd /app/dockerapps/joinus-backend-2021/
- docker-compose up -d
- docker image prune -f
depends_on:
- build

63
.gitattributes vendored 100644
View File

@ -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

349
.gitignore vendored 100644
View File

@ -0,0 +1,349 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# 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
# 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/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# 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
# 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
# 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
*- Backup*.rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
assets/*
exports/*
exports
photos
students.zip
photos/*

View File

@ -0,0 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>_2021_backend</RootNamespace>
<UserSecretsId>2023ab1c-9547-4989-a343-cd3428e085fe</UserSecretsId>
<StartupObject>_2021_backend.Program</StartupObject>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<WarningLevel>0</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Compile Remove="exports\**" />
<Content Remove="exports\**" />
<EmbeddedResource Remove="exports\**" />
<None Remove="exports\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="itext7" Version="7.1.16" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.2" />
<PackageReference Include="Nancy" Version="2.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.7" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="1.1.0" />
<PackageReference Include="NPOI" Version="2.5.4" />
<PackageReference Include="TencentCloudSDK" Version="3.0.362" />
</ItemGroup>
</Project>

25
2021-backend.sln 100644
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31612.314
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "2021-backend", "2021-backend.csproj", "{879DE3A8-39AB-47D1-A39A-448477C1285A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{879DE3A8-39AB-47D1-A39A-448477C1285A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{879DE3A8-39AB-47D1-A39A-448477C1285A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{879DE3A8-39AB-47D1-A39A-448477C1285A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{879DE3A8-39AB-47D1-A39A-448477C1285A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {25338145-8695-4879-B267-5940D14DEE33}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,83 @@
using _2021_backend.Data;
using _2021_backend.Models;
using _2021_backend.Utils;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
namespace _2021_backend.Controllers
{
[Route("api/submit")]
public class SubmissionController : Controller
{
public BackendContext Context;
public SubmissionController(BackendContext context)
{
Context = context;
}
[HttpPost]
public async Task<IActionResult> Post([FromForm] string dto)
{
var aDto = JsonSerializer.Deserialize<SubmissionDto>(dto);
string ip = Request.Headers["X-Real-IP"].FirstOrDefault();
if (aDto.Iscomplete() == false)
return StatusCode(400, ApiResponse.Error("TICKET_INFO_INCOMPLETE"));
if (aDto.Check() == false)
return StatusCode(400, ApiResponse.Error("TICKET_NOT_LEGEAL"));
Submission sub = new Submission(aDto, ip);
foreach (var tm in Context.Sessions)
{
if (aDto.Timelist.Any(it => it.Day.Day == tm.Day.Day && it.BeginTime.TimeOfDay == tm.BeginTime.TimeOfDay))
{
sub.Timelist.Add(tm.Guid);
}
}
var q = Context.Students.Where(stu => (stu.Name == aDto.Name || stu.Stuid == aDto.Stuid));
Student stu;
if (q.Count() == 0)
{
stu = Student.create(sub);
stu.Status = status.;
Context.Students.Add(stu);
}
else
{
stu = q.FirstOrDefault();
stu.Update(sub);
}
sub.Host = stu.Guid;
Context.Submissions.Add(sub);
Context.SaveChanges();
//await TencentSMS.Send(Context, SMSType.Signed, stu, _2021_backend.Models.User.Bot.stuID);
return Ok(ApiResponse.Success("success"));
}
}
[ApiController]
[Route("api/sessionlist")]
public class SessionlistContoller : Controller
{
private readonly BackendContext _context;
public SessionlistContoller(BackendContext context)
{
_context = context;
}
[HttpGet]
public IActionResult GetSessions()
{
var query = _context.Sessions.OrderBy(r => r.Day).ThenBy(r => r.BeginTime).ThenBy(r => r.Place).Where(e => e.Capacity > e.Students.Count + 1).Select(r => new SessionDto
{
BeginTime = r.BeginTime,
Day = r.Day,
});
return Ok(ApiResponse.Success(query.ToList().FindAll(it => it.Day.Add(it.BeginTime.TimeOfDay).CompareTo(DateTime.Now) > 0).Distinct(new SessionDtoComparer()).ToList()));
//return Ok(ApiResponse.Success("报名结束了"));
}
}
}

View File

@ -0,0 +1,33 @@
using _2021_backend.Models;
using Microsoft.EntityFrameworkCore;
namespace _2021_backend.Data
{
public class BackendContext : DbContext
{
public BackendContext(DbContextOptions<BackendContext> options)
: base(options)
{
}
public DbSet<User> Users { get; set; }
public DbSet<Submission> Submissions { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<Session> Sessions { get; set; }
public DbSet<Student> Students { get; set; }
public DbSet<SMS> SMS { get; set; }
protected override void OnModelCreating(ModelBuilder mb)
{
mb.Entity<Submission>()
.HasKey(r => r.Guid);
mb.Entity<User>()
.HasKey(u => u.Guid);
mb.Entity<Comment>()
.HasKey(u => u.Guid);
mb.Entity<Session>()
.HasKey(u => u.Guid);
mb.Entity<SMS>()
.HasKey(u => u.Guid);
}
}
}

27
Dockerfile 100644
View File

@ -0,0 +1,27 @@
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["2021-backend.csproj", ""]
RUN dotnet restore "./2021-backend.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "2021-backend.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "2021-backend.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
ENTRYPOINT ["dotnet", "2021-backend.dll"]

View File

@ -0,0 +1,251 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using _2021_backend.Data;
namespace _2021_backend.Migrations
{
[DbContext(typeof(BackendContext))]
[Migration("20211018220015_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("ProductVersion", "5.0.9")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
modelBuilder.Entity("_2021_backend.Models.Comment", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("AddTime")
.HasColumnType("timestamp without time zone");
b.Property<string>("Content")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("Operator")
.HasColumnType("uuid");
b.Property<Guid>("Student")
.HasColumnType("uuid");
b.HasKey("Guid");
b.ToTable("Comments");
});
modelBuilder.Entity("_2021_backend.Models.SMS", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<List<string>>("Data")
.HasColumnType("text[]");
b.Property<Guid>("Host")
.HasColumnType("uuid");
b.Property<DateTime>("SendTime")
.HasColumnType("timestamp without time zone");
b.Property<string>("Sender")
.HasColumnType("text");
b.Property<string>("Tel")
.HasColumnType("text");
b.Property<int>("Type")
.HasColumnType("integer");
b.HasKey("Guid");
b.ToTable("SMS");
});
modelBuilder.Entity("_2021_backend.Models.Session", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("BeginTime")
.HasColumnType("timestamp without time zone");
b.Property<int>("Capacity")
.HasColumnType("integer");
b.Property<List<Guid>>("Chiefs")
.HasColumnType("uuid[]");
b.Property<DateTime>("Day")
.HasColumnType("timestamp without time zone");
b.Property<string>("Place")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("SendSMS")
.HasColumnType("boolean");
b.Property<List<Guid>>("Students")
.HasColumnType("uuid[]");
b.HasKey("Guid");
b.ToTable("Sessions");
});
modelBuilder.Entity("_2021_backend.Models.Student", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<List<Guid>>("Comments")
.HasColumnType("uuid[]");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<int>("Exp")
.HasColumnType("integer");
b.Property<int>("Grade")
.HasColumnType("integer");
b.Property<Guid>("InterviewTime")
.HasColumnType("uuid");
b.Property<DateTime>("LastSubmission")
.HasColumnType("timestamp without time zone");
b.Property<string>("Major")
.HasColumnType("text");
b.Property<List<Guid>>("Messages")
.HasColumnType("uuid[]");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<DateTime>("RegisterTime")
.HasColumnType("timestamp without time zone");
b.Property<int>("Score")
.HasColumnType("integer");
b.Property<int>("Sex")
.HasColumnType("integer");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<string>("Stuid")
.HasColumnType("text");
b.Property<List<Guid>>("Submissions")
.HasColumnType("uuid[]");
b.Property<string>("Tel")
.HasColumnType("text");
b.Property<List<Guid>>("Timelist")
.HasColumnType("uuid[]");
b.Property<int>("Yard")
.HasColumnType("integer");
b.HasKey("Guid");
b.ToTable("Students");
});
modelBuilder.Entity("_2021_backend.Models.Submission", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Address")
.HasColumnType("text");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<int>("Exp")
.HasColumnType("integer");
b.Property<int>("Grade")
.HasColumnType("integer");
b.Property<Guid>("Host")
.HasColumnType("uuid");
b.Property<string>("Major")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<int>("Sex")
.HasColumnType("integer");
b.Property<string>("Stuid")
.HasColumnType("text");
b.Property<DateTime>("SubmitTime")
.HasColumnType("timestamp without time zone");
b.Property<string>("Tel")
.HasColumnType("text");
b.Property<List<Guid>>("Timelist")
.HasColumnType("uuid[]");
b.Property<int>("Yard")
.HasColumnType("integer");
b.HasKey("Guid");
b.ToTable("Submissions");
});
modelBuilder.Entity("_2021_backend.Models.User", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Secret")
.HasColumnType("text");
b.Property<bool>("isManager")
.HasColumnType("boolean");
b.Property<string>("stuID")
.HasColumnType("text");
b.HasKey("Guid");
b.ToTable("Users");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace _2021_backend.Migrations
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Comments",
columns: table => new
{
Guid = table.Column<Guid>(type: "uuid", nullable: false),
Operator = table.Column<Guid>(type: "uuid", nullable: false),
Content = table.Column<string>(type: "text", nullable: false),
AddTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Student = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Comments", x => x.Guid);
});
migrationBuilder.CreateTable(
name: "Sessions",
columns: table => new
{
Guid = table.Column<Guid>(type: "uuid", nullable: false),
Day = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
BeginTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Place = table.Column<string>(type: "text", nullable: false),
Chiefs = table.Column<List<Guid>>(type: "uuid[]", nullable: true),
Capacity = table.Column<int>(type: "integer", nullable: false),
SendSMS = table.Column<bool>(type: "boolean", nullable: false),
Students = table.Column<List<Guid>>(type: "uuid[]", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Sessions", x => x.Guid);
});
migrationBuilder.CreateTable(
name: "SMS",
columns: table => new
{
Guid = table.Column<Guid>(type: "uuid", nullable: false),
Host = table.Column<Guid>(type: "uuid", nullable: false),
Tel = table.Column<string>(type: "text", nullable: true),
Data = table.Column<List<string>>(type: "text[]", nullable: true),
Type = table.Column<int>(type: "integer", nullable: false),
Sender = table.Column<string>(type: "text", nullable: true),
SendTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SMS", x => x.Guid);
});
migrationBuilder.CreateTable(
name: "Students",
columns: table => new
{
Guid = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: true),
Stuid = table.Column<string>(type: "text", nullable: true),
Sex = table.Column<int>(type: "integer", nullable: false),
Grade = table.Column<int>(type: "integer", nullable: false),
Yard = table.Column<int>(type: "integer", nullable: false),
Major = table.Column<string>(type: "text", nullable: true),
Email = table.Column<string>(type: "text", nullable: true),
Tel = table.Column<string>(type: "text", nullable: true),
Exp = table.Column<int>(type: "integer", nullable: false),
InterviewTime = table.Column<Guid>(type: "uuid", nullable: false),
Submissions = table.Column<List<Guid>>(type: "uuid[]", nullable: true),
Messages = table.Column<List<Guid>>(type: "uuid[]", nullable: true),
Timelist = table.Column<List<Guid>>(type: "uuid[]", nullable: true),
Comments = table.Column<List<Guid>>(type: "uuid[]", nullable: true),
Score = table.Column<int>(type: "integer", nullable: false),
Status = table.Column<int>(type: "integer", nullable: false),
LastSubmission = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
RegisterTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Students", x => x.Guid);
});
migrationBuilder.CreateTable(
name: "Submissions",
columns: table => new
{
Guid = table.Column<Guid>(type: "uuid", nullable: false),
Host = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: true),
Stuid = table.Column<string>(type: "text", nullable: true),
Sex = table.Column<int>(type: "integer", nullable: false),
Yard = table.Column<int>(type: "integer", nullable: false),
Grade = table.Column<int>(type: "integer", nullable: false),
Major = table.Column<string>(type: "text", nullable: true),
Email = table.Column<string>(type: "text", nullable: true),
Tel = table.Column<string>(type: "text", nullable: true),
Exp = table.Column<int>(type: "integer", nullable: false),
Timelist = table.Column<List<Guid>>(type: "uuid[]", nullable: true),
Address = table.Column<string>(type: "text", nullable: true),
SubmitTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Submissions", x => x.Guid);
});
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Guid = table.Column<Guid>(type: "uuid", nullable: false),
stuID = table.Column<string>(type: "text", nullable: true),
Name = table.Column<string>(type: "text", nullable: true),
Secret = table.Column<string>(type: "text", nullable: true),
isManager = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Guid);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Comments");
migrationBuilder.DropTable(
name: "Sessions");
migrationBuilder.DropTable(
name: "SMS");
migrationBuilder.DropTable(
name: "Students");
migrationBuilder.DropTable(
name: "Submissions");
migrationBuilder.DropTable(
name: "Users");
}
}
}

View File

@ -0,0 +1,249 @@
// <auto-generated />
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using _2021_backend.Data;
namespace _2021_backend.Migrations
{
[DbContext(typeof(BackendContext))]
partial class BackendContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("ProductVersion", "5.0.9")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
modelBuilder.Entity("_2021_backend.Models.Comment", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("AddTime")
.HasColumnType("timestamp without time zone");
b.Property<string>("Content")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("Operator")
.HasColumnType("uuid");
b.Property<Guid>("Student")
.HasColumnType("uuid");
b.HasKey("Guid");
b.ToTable("Comments");
});
modelBuilder.Entity("_2021_backend.Models.SMS", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<List<string>>("Data")
.HasColumnType("text[]");
b.Property<Guid>("Host")
.HasColumnType("uuid");
b.Property<DateTime>("SendTime")
.HasColumnType("timestamp without time zone");
b.Property<string>("Sender")
.HasColumnType("text");
b.Property<string>("Tel")
.HasColumnType("text");
b.Property<int>("Type")
.HasColumnType("integer");
b.HasKey("Guid");
b.ToTable("SMS");
});
modelBuilder.Entity("_2021_backend.Models.Session", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("BeginTime")
.HasColumnType("timestamp without time zone");
b.Property<int>("Capacity")
.HasColumnType("integer");
b.Property<List<Guid>>("Chiefs")
.HasColumnType("uuid[]");
b.Property<DateTime>("Day")
.HasColumnType("timestamp without time zone");
b.Property<string>("Place")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("SendSMS")
.HasColumnType("boolean");
b.Property<List<Guid>>("Students")
.HasColumnType("uuid[]");
b.HasKey("Guid");
b.ToTable("Sessions");
});
modelBuilder.Entity("_2021_backend.Models.Student", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<List<Guid>>("Comments")
.HasColumnType("uuid[]");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<int>("Exp")
.HasColumnType("integer");
b.Property<int>("Grade")
.HasColumnType("integer");
b.Property<Guid>("InterviewTime")
.HasColumnType("uuid");
b.Property<DateTime>("LastSubmission")
.HasColumnType("timestamp without time zone");
b.Property<string>("Major")
.HasColumnType("text");
b.Property<List<Guid>>("Messages")
.HasColumnType("uuid[]");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<DateTime>("RegisterTime")
.HasColumnType("timestamp without time zone");
b.Property<int>("Score")
.HasColumnType("integer");
b.Property<int>("Sex")
.HasColumnType("integer");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<string>("Stuid")
.HasColumnType("text");
b.Property<List<Guid>>("Submissions")
.HasColumnType("uuid[]");
b.Property<string>("Tel")
.HasColumnType("text");
b.Property<List<Guid>>("Timelist")
.HasColumnType("uuid[]");
b.Property<int>("Yard")
.HasColumnType("integer");
b.HasKey("Guid");
b.ToTable("Students");
});
modelBuilder.Entity("_2021_backend.Models.Submission", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Address")
.HasColumnType("text");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<int>("Exp")
.HasColumnType("integer");
b.Property<int>("Grade")
.HasColumnType("integer");
b.Property<Guid>("Host")
.HasColumnType("uuid");
b.Property<string>("Major")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<int>("Sex")
.HasColumnType("integer");
b.Property<string>("Stuid")
.HasColumnType("text");
b.Property<DateTime>("SubmitTime")
.HasColumnType("timestamp without time zone");
b.Property<string>("Tel")
.HasColumnType("text");
b.Property<List<Guid>>("Timelist")
.HasColumnType("uuid[]");
b.Property<int>("Yard")
.HasColumnType("integer");
b.HasKey("Guid");
b.ToTable("Submissions");
});
modelBuilder.Entity("_2021_backend.Models.User", b =>
{
b.Property<Guid>("Guid")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Secret")
.HasColumnType("text");
b.Property<bool>("isManager")
.HasColumnType("boolean");
b.Property<string>("stuID")
.HasColumnType("text");
b.HasKey("Guid");
b.ToTable("Users");
});
#pragma warning restore 612, 618
}
}
}

42
Models/Comment.cs 100644
View File

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace _2021_backend.Models
{
public class Comment
{
public Comment()
{
Guid = Guid.NewGuid();
AddTime = DateTime.Now;
}
[Key]
public Guid Guid { get; set; }
[Required()]
[Display(Name ="评论者")]
public Guid Operator { get; set; }
[Required()]
[Display(Name ="内容")]
public string Content { get; set; }
[Display(Name = "评论时间")]
[DataType(DataType.DateTime)]
public DateTime AddTime { get; set; }
[Display(Name ="被评论者")]
public Guid Student { get; set; }
public Comment(Guid opid,string content, Guid stuguid)
{
Guid = Guid.NewGuid();
Operator = opid;
Content = content;
Student = stuguid;
AddTime = DateTime.Now;
}
}
}

79
Models/SMS.cs 100644
View File

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace _2021_backend.Models
{
public enum SMSType
{
Accept,
Reject,
TimeSelect,
TimeSet,
Signed,
Reply
}
public class SMS
{
public SMS()
{
Guid = Guid.NewGuid();
Tel = "";
Data = new List<string> { };
Type = SMSType.Accept;
Sender = "";
SendTime = DateTime.Now;
}
public SMS(SMSPartialDto dto, Guid host)
{
Guid = Guid.NewGuid();
Tel = dto.SubscriberNumber;
Host = host;
Sender = dto.SubscriberNumber.ToString();
Data = (new string[] { dto.ReplyContent }).ToList<string>();
Type = SMSType.Reply;
var tm = (new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddSeconds(dto.ReplyTime).ToLocalTime();
SendTime = tm;
}
[Key]
public Guid Guid { get; set; }
[Display(Name ="Host")]
public Guid Host { get; set; }
[Display(Name ="电话号码")]
public string Tel { get; set; }
[Display(Name ="短信内容")]
public List<string> Data { get; set; }
[Display(Name ="短信类型")]
public SMSType Type { get; set; }
[Display(Name ="发送者")]
public string Sender { get; set; }
[Display(Name = "发送时间")]
[DisplayFormat(DataFormatString = "{0:g}", ApplyFormatInEditMode = true)]
public DateTime SendTime { get; set; }
}
public class SMSResponseDto
{
public class error
{
public string Code;
public string Message;
}
public List<SMSPartialDto> PullSmsReplyStatusSet { get; set; }
public string RequestId { get; set; }
error Error { get; set; }
}
public class SMSPartialDto
{
public string CountryCode { get; set; }
public string ReplyContent { get; set; }
public string SubscriberNumber { get; set; }
public string ExtendCode { get; set; }
public ulong ReplyTime { get; set; }
public string PhoneNumber { get; set; }
public string SignName { get; set; }
}
}

70
Models/Session.cs 100644
View File

@ -0,0 +1,70 @@
using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Models
{
public class Session
{
public Session()
{
Guid = Guid.NewGuid();
}
[Key]
[Required()]
[Display(Name = "场次GUID")]
public Guid Guid { get; set; }
[Required()]
[Display(Name = "活动日期")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime Day { get; set; }
[Display(Name = "开始时间")]
[DataType(DataType.Time)]
[DisplayFormat(DataFormatString = "{0:t}", ApplyFormatInEditMode = true)]
[Required()]
public DateTime BeginTime { get; set; }
[RegularExpression(@"^20[04]$", ErrorMessage = "200204")]
[Display(Name = "地点")]
[Required()]
public string Place { get; set; }
[Display(Name = "主活动官")]
public List<Guid> Chiefs { get; set; }
[Display(Name = "可容纳人数")]
public int Capacity { get; set; }
[Display(Name = "短信通知")]
public bool SendSMS { get; set; }
[Display(Name = "活动的人")]
public List<Guid> Students { get; set; }
}
public class SessionDto
{
public DateTime Day { get; set; }
public DateTime BeginTime { get; set; }
}
public class SessionDtoComparer : IEqualityComparer<SessionDto>
{
#region IEqualityComparer<user> Members
public bool Equals(SessionDto a,SessionDto b)
{
return a.Day == b.Day && a.BeginTime == b.BeginTime;
}
public int GetHashCode(SessionDto a)
{
return a.Day.GetHashCode() + a.BeginTime.GetHashCode();
}
#endregion
}
}

145
Models/Student.cs 100644
View File

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Models
{
public enum status
{
,
,
,
,
,
,
,
}
public enum yard
{
= 0,
= 1,
= 2,
= 3,
= 4,
= 5,
}
public enum sex
{
Boy = 1,
Girl = 0,
Unknown = 2
}
public enum grade
{
= 0,
= 1,
= 2,
= 3,
= 4,
}
public enum experience
{
= 0,
= 1,
= 2,
= 3,
= 4
}
public class Student
{
public void Update(Submission sub)
{
Name = sub.Name;
Email = sub.Email;
Tel = sub.Tel;
Stuid = sub.Stuid;
Sex = sub.Sex;
Grade = sub.Grade;
Major = sub.Major;
Yard = sub.Yard;
Exp = sub.Exp;
Timelist = sub.Timelist;
Submissions.Add(sub.Guid);
}
public Student()
{
Guid = Guid.NewGuid();
Comments = new List<Guid>();
Messages = new List<Guid>();
Submissions = new List<Guid>();
Timelist = new List<Guid>();
}
public static Student create(Submission sub)
{
Student student = new Student();
student.Guid = Guid.NewGuid();
student.Name = sub.Name;
student.Email = sub.Email;
student.Tel = sub.Tel;
student.Stuid = sub.Stuid;
student.Sex = sub.Sex;
student.Grade = sub.Grade;
student.Major = sub.Major;
student.Yard = sub.Yard;
student.Exp = sub.Exp;
student.Timelist = sub.Timelist;
student.Submissions.Add(sub.Guid);
student.RegisterTime = sub.SubmitTime;
return student;
}
[Key]
[Display(Name = "ID")]
public Guid Guid { get; set; }
[Display(Name = "姓名")]
public string Name { get; set; }
[Display(Name = "学号")]
public string Stuid { get; set; }
[Display(Name = "性别")]
public sex Sex { get; set; }
[Display(Name = "年级")]
public grade Grade { get; set; }
[Display(Name = "学园")]
public yard Yard { get; set; }
[Display(Name = "专业")]
public string Major { get; set; }
[Display(Name = "电子邮件")]
public string Email { get; set; }
[Display(Name = "电话")]
public string Tel { get; set; }
[Display(Name = "经验程度")]
public experience Exp { get; set; }
[Display(Name = "最终场次")]
public Guid InterviewTime { get; set; }
[Display(Name = "提交记录")]
public List<Guid> Submissions { get; set; }
[Display(Name = "短信记录")]
public List<Guid> Messages { get; set; }
[Display(Name = "可选场次")]
public List<Guid> Timelist { get; set; }
[Display(Name = "评论")]
public List<Guid> Comments { get; set; }
[Display(Name = "打分")]
public int Score { get; set; }
[Display(Name = "状态")]
public status Status { get; set; }
[Display(Name = "最近一次提交时间")]
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:g}", ApplyFormatInEditMode = true)]
public DateTime LastSubmission { get; set; }
[Display(Name = "报名时间")]
[DataType(DataType.DateTime)]
public DateTime RegisterTime { get; set; }
}
}

View File

@ -0,0 +1,133 @@
using Microsoft.AspNetCore.Mvc.Rendering;
using Org.BouncyCastle.Asn1.Cms;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace _2021_backend.Models
{
public class Submission
{
public Submission() {
Guid = Guid.NewGuid();
SubmitTime = DateTime.Now;
}
public Submission(SubmissionDto Dto, string ip)
{
Email = Dto.Email;
Grade = (grade)(Dto.Grade);
Sex = (sex)Dto.Sex;
Stuid = Dto.Stuid;
Major = Dto.Major;
Name = Dto.Name;
Tel = Dto.Tel;
Exp = (experience)Dto.Exp;
Yard = (yard)Dto.Yard;
Timelist = new List<Guid>();
Guid = System.Guid.NewGuid();
SubmitTime = DateTime.Now;
Address = ip;
}
[Key]
[Display(Name = "ID")]
public Guid Guid { get; set; }
[Display(Name ="Host")]
public Guid Host { get; set; }
[Display(Name = "姓名")]
public string Name { get; set; }
[Display(Name = "学号")]
public string Stuid { get; set; }
[Display(Name = "性别")]
public sex Sex { get; set; }
[Display(Name = "学园")]
public yard Yard { get; set; }
[Display(Name = "年级")]
public grade Grade { get; set; }
[Display(Name = "专业")]
public string Major { get; set; }
[Display(Name = "电子邮件")]
public string Email { get; set; }
[Display(Name = "电话")]
public string Tel { get; set; }
[Display(Name = "经验程度")]
public experience Exp { get; set; }
[Display(Name = "时间列表")]
public List<Guid> Timelist { get; set; }
[Display(Name ="Ip Address")]
public string Address { get; set; }
[Display(Name = "提交时间")]
[DisplayFormat(DataFormatString = "{0:g}", ApplyFormatInEditMode = true)]
public DateTime SubmitTime { get; set; }
//活动场次ID
}
public class TimeSpec
{
public DateTime Day { get; set; }
public DateTime BeginTime { get; set; }
}
public class SubmissionDto
{
[Required()]
public string Name { get; set; }
[Required()]
public string Stuid { get; set; }
[Required()]
public int Sex { get; set; }
[Required()]
public int Grade { get; set; }
[Required()]
public int Yard { get; set; }
[Required()]
public string Major { get; set; }
[Required()]
public string Email { get; set; }
[Required()]
public string Tel { get; set; }
[Required()]
public int Exp { get; set; }
[Required()]
public List<TimeSpec> Timelist { get; set; }
public static Regex r = new Regex("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$");
public static Regex phone_regex = new Regex("^1\\d{10}$");
public bool Iscomplete() => Name != null && Stuid != null && (Sex == 0 || Sex == 1) && Major != null && Email != null && Tel != null && Yard > 0 && Yard < 6;
public bool Check()
{
if (Name.Length > 15)
return false;
if (Regex.Matches(Name, @"\d").Count > 0)
return false;
if (Stuid.Length > 10 || Stuid.Length < 7)
return false;
if (Sex > 1 || Sex < 0)
return false;
if (Grade < 0 || Grade > 4)
return false;
if (Major.Length > 20)
return false;
if (Yard >= 6 && Yard <= 0) return false;
if(Exp >= 5 && Exp <= 0) return false;
if (!r.IsMatch(Email))
{
return false;
}
if (!phone_regex.IsMatch(Tel))
{
return false;
}
return true;
}
}
}

56
Models/User.cs 100644
View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Mvc.Rendering;
using Newtonsoft.Json;
using Microsoft.EntityFrameworkCore.Internal;
namespace _2021_backend.Models
{
public class User
{
public User()
{
Guid = Guid.NewGuid();
}
public static User Bot;
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Name ="ID")]
public Guid Guid { get; set; }
[Display(Name = "学号")]
public string stuID { get; set; }
[Display(Name ="姓名")]
public string Name { get; set; }
[Display(Name ="密码")]
public string Secret { get; set; }
[Display(Name ="是否管理员")]
public bool isManager { get; set; }
}
public class Login
{
private readonly string[] Manager = { "3200102610", "3190104611", "3190104698", "3190103719", "3190104143", "3190100494", "3190103301", "3190102034", "3190100151", "3190103577", "3190105399", "3190100133" };
[JsonProperty("username")]
public string id_student { get; set; }
[JsonProperty("password")]
public string Password { get; set; }
public Login(string name,string pwd)
{
id_student = name;
Password = pwd;
}
public string GetSHASecret() => _2021_backend.Utils.EvaCryptoHelper.Password2Secret(Password);
public bool isManager()
{
if (Array.IndexOf(Manager,id_student) != -1)
return true;
return false;
}
}
}

View File

@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
namespace _2021_backend.OldModels
{
public class InterviewTime
{
public int ID { get; set; }
public string Day { get; set; }
public string BeginTime { get; set; }
public string Place { get; set; }
public string Chief { get; set; }
public int TakenNum { get; set; }
public int NowNum { get; set; }
public bool SendSMS { get; set; }
public List<int> Students { get; set; }
}
public class Notes
{
public int ID { get; set; }
public string OperatorId { get; set; }
public string OperatorName { get; set; }
public string Content { get; set; }
public DateTime AddTime { get; set; }
public int RecordId { get; set; }
public Notes() { }
}
public enum Status
{
Pending,
Pass,
Fail
}
public enum Department
{
= 1,
= 2,
,
,
}
public enum Grade
{
= 1,
= 2,
,
}
public class Record
{
public int rid { get; set; }
public string name { get; set; }
public string id_student { get; set; }
public bool sex { get; set; }
public int grade { get; set; }
public string major { get; set; }
public string email { get; set; }
public string phone { get; set; }
public int firstWish { get; set; }
public int secondWish { get; set; }
public int thirdWish { get; set; }
public bool adjustment { get; set; }
public string firstReason { get; set; }
public string secondReason { get; set; }
public string thirdReason { get; set; }
public string question1 { get; set; }
public string question2 { get; set; }
public string strguid { get; set; }
public List<int> Times { get; set; }
public DateTime addedDate { get; set; }
public Status status { get; set; }
public string ip { get; set; }
//活动场次ID
public int InterviewID { get; set; }
public string InterviewTime { get; set; }
public int FinalResult { get; set; }
}
public class SMS
{
public int ID { get; set; }
public string id_student { get; set; }
public DateTime sendTime { get; set; }
public string type { get; set; }
public string OperatorName { get; set; }
public int Status { get; set; }
public SMS() { }
}
public class User
{
public string Uid { get; set; }
public long stuID { get; set; }
public string Name { get; set; }
public string Secret { get; set; }
public bool isManager { get; set; }
}
}

View File

@ -0,0 +1,8 @@
@page
@model _2021_backend.Pages.Account.AccessDeniedModel
@{
ViewData["Title"] = "认证失败";
}
<h1>权限不足</h1>
<h3>认证失败,您没有足够的权限进行操作,请联系系统管理员</h3>

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace _2021_backend.Pages.Account
{
public class AccessDeniedModel : PageModel
{
public void OnGet()
{
}
}
}

View File

@ -0,0 +1,9 @@
@page
@model _2021_backend.Pages.Account.DeniedModel
@{
ViewData["Title"] = "登录";
}
<h1>登录</h1>
<h3>认证失败,请重新登录或联系系统管理员</h3>
<button class="btn btn-primary" asp-area="/" asp-page="/Account/Login">重新登录</button>

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace _2021_backend.Pages.Account
{
public class DeniedModel : PageModel
{
public void OnGet()
{
}
}
}

View File

@ -0,0 +1,35 @@
@page
@model _2021_backend.Pages.Account.LoginModel
@{
ViewData["Title"] = "登录";
}
<h1>登录</h1>
<div class="row">
<div class="col-md-8">
<section>
<form asp-controller="Account" asp-action="Login" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-md-2 control-label">学号</label>
<div class="col-md-10">
<input type="text" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">密码</label>
<div class="col-md-10">
<input type="password" name="password" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-primary">冲!</button>
</div>
</div>
</form>
</section>
</div>
</div>

View File

@ -0,0 +1,148 @@
using _2021_backend.Data;
using _2021_backend.Models;
using _2021_backend.Utils;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace _2021_backend.Pages.Account
{
public class LoginModel : PageModel
{
private readonly string LoginURL = "https://xms.zjueva.net/api/auth/login";
private readonly IConfiguration config;
private readonly BackendContext context;
public LoginModel(IConfiguration configuration, BackendContext context)
{
config = configuration;
this.context = context;
}
public IActionResult OnGet(string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
return Page();
}
[BindProperty]
public string username { get; set; }
[BindProperty]
public string password { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var NowSecret = EvaCryptoHelper.Password2Secret(password);
string stuID = username;
var query = from _user in context.Users
where _user.stuID == stuID
select _user;
var user = await query.AsNoTracking().FirstOrDefaultAsync();
//need use xms login service
if (user == null)
{
Login login_Stu = new Login(username, password);
//post login information to xms.zjueva.net and receive the response with string
string ansString = LoginHelper.PostMoths(LoginURL, login_Stu);
JObject ansJson = (JObject)JsonConvert.DeserializeObject(ansString);
//error and Denied
if (ansJson["status"].ToString() == "error")
{
return RedirectToPage("/Account/Denied");
}
else if (ansJson["status"].ToString() == "success")
{
User add_user = new User()
{
stuID = ansJson["data"]["stuid"].ToString(),
Name = ansJson["data"]["name"].ToString(),
Secret = login_Stu.GetSHASecret(),
isManager = login_Stu.isManager()
};
context.Users.Add(add_user);
await context.SaveChangesAsync();
//add new user to DB and now continue to create cookie;
user = add_user;
//this user is correct and don't use the follow "else"
}
}
if (user.Secret == NowSecret)
{
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme, ClaimTypes.Name, ClaimTypes.Role);
identity.AddClaim(new Claim(ClaimTypes.Name, user.Name));
identity.AddClaim(new Claim(ClaimTypes.Sid, user.Guid.ToString()));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, username));
if (user.isManager)
{
identity.AddClaim(new Claim(EvaClaimTypes.IsManager, "true"));
identity.AddClaim(new Claim(ClaimTypes.Role, "manager"));
}
else
{
identity.AddClaim(new Claim(ClaimTypes.Role, "user"));
}
var Iprinciple = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
Iprinciple,
new AuthenticationProperties
{
IsPersistent = true,
AllowRefresh = true
}
);
return RedirectToPage("/Students/Index");
}
//if user change his secret in XMS
else
{
Login login_Stu = new Login(username, password);
//post login information to xms.zjueva.net and receive the response with string
string ansString = LoginHelper.PostMoths(LoginURL, login_Stu);
JObject ansJson = (JObject)JsonConvert.DeserializeObject(ansString);
//error and Denied
if (ansJson["status"].ToString() == "error")
{
return RedirectToPage("/Account/Denied");
}
else
{
//change the secret in DB
user = await context.Users.FirstOrDefaultAsync(r => r.stuID == stuID);
user.Secret = login_Stu.GetSHASecret();
context.Attach(user).State = EntityState.Modified;
try
{
await context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
return NotFound();
}
return RedirectToPage("/Index");
}
}
}
}
}

View File

@ -0,0 +1,8 @@
@page
@model _2021_backend.Pages.Account.LogoutModel
@{
ViewData["Title"] = "登出";
}
<h1>正在登出</h1>
<h3>请稍后</h3>

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
namespace _2021_backend.Pages.Account
{
public class LogoutModel : PageModel
{
public async Task<IActionResult> OnGet()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return RedirectToPage("/Index");
}
}
}

26
Pages/Error.cshtml 100644
View File

@ -0,0 +1,26 @@
@page
@model ErrorModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

View File

@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Pages
{
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class ErrorModel : PageModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
private readonly ILogger<ErrorModel> _logger;
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
}

10
Pages/Index.cshtml 100644
View File

@ -0,0 +1,10 @@
@page
@model IndexModel
@{
ViewData["Title"] = "首页";
}
<div class="text-center">
<h1 class="display-4">欢迎使用</h1>
</div>

View File

@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Pages
{
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}

View File

@ -0,0 +1,113 @@
@page
@model _2021_backend.Pages.Message.IndexModel
@{
}
@{
ViewData["Title"] = "发送短信";
}
<h5 class="text-red">
<strong>@Html.DisplayFor(model => Model.Errmsg)</strong>
</h5>
<h3><strong>发送短信</strong></h3>
<form method="post">
<input type="hidden" asp-for="pageid" />
<input type="submit" value="拉取5天内的回复短信" class="btn btn-primary" asp-page-handler="Pull" />
<input type="submit" value="发送报名确认短信" class="btn btn-primary" asp-page-handler="Sign" />
<input type="submit" value="发送确认短信" class="btn btn-primary" asp-page-handler="ResultAccept" />
<input type="submit" value="发送拒绝短信" class="btn btn-primary" asp-page-handler="ResultReject" />
</form>
<br />
<h3><strong>短信记录</strong></h3>
<hr />
<form method="post" class="form-inline">
<input type="hidden" asp-for="pageid" />
<div class="m-2">
<label class="form-check-label">
<input class="form-check-input" asp-for="showSend" />发出的短信
</label>
</div>
<div class="m-2">
<label class="form-check-label">
<input class="form-check-input" asp-for="showReceive" /> 收到的短信
</label>
</div>
<label asp-for="SearchString" class="control-label">按名字筛选</label>
<div class="m-2">
<input type="text" class="form-control" id="searchString" placeholder="输入部分姓名" asp-for="SearchString" name="SearchString">
</div>
<input type="submit" class="btn btn-primary" value="Go!" />
</form>
<table class="table">
<thead>
<tr>
<th>
发送者
</th>
<th>
学生姓名
</th>
<th>
发送时间
</th>
<th>
短信类型
</th>
<th>
短信内容
</th>
</tr>
</thead>
<tbody>
@if (Model.Messages.Count == 0)
{
@:暂无短信
}
else
{
@foreach (var e in Model.Messages)
{
<tr>
<td>
@Html.DisplayFor(it => e.Sender)
</td>
<td>
@{
var stu = Model.Context.Students.Find(e.Host);
string name = stu.Name;
@Html.DisplayFor(it => name)
}
</td>
<td>
@{
var str = e.SendTime.ToString("MM月dd日 hh:mm:ss");
@Html.DisplayFor(it => str)
}
</td>
<td>
@Html.DisplayFor(it => e.Type)
</td>
<td>
@if (e.Type == _2021_backend.Models.SMSType.Reply)
{
@Html.DisplayFor(it => e.Data[0])
}
</td>
</tr>
}
}
</tbody>
</table>
<nav>
<ul class="pagination">
<li class="page-item @(Model.pageid==0 ? "disabled" : "")"><a class="page-link" asp-route-pageId="@(Model.pageid-1) " >Prev</a></li>
@for (int i = 0; i < Model.PageCount; i++)
{
<li class="page-item @(Model.pageid==i ? "active" : "")"><a class="page-link" asp-route-pageId="@i" >@i</a></li>
}
<li class="page-item @(Model.pageid>=Model.PageCount -1? "disabled" : "")"><a class="page-link" asp-route-pageId="@(Model.pageid+1)" >Next</a></li>
</ul>
</nav>

View File

@ -0,0 +1,135 @@
using _2021_backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace _2021_backend.Pages.Message
{
public class IndexModel : PageModel
{
public readonly _2021_backend.Data.BackendContext Context;
[BindProperty]
public string Errmsg { get; set; }
[BindProperty]
public string SearchString { get; set; }
[BindProperty]
public bool showSend { get; set; }
[BindProperty]
public bool showReceive { get; set; }
[BindProperty]
public int pageid { get; set; }
public static int pageSize = 30;
public List<SMS> Messages { get; set; }
public int PageCount { get; set; }
public IndexModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
public IActionResult Construct(int PageId)
{
List<Guid> stus;
IQueryable<Guid> q;
if (!String.IsNullOrEmpty(SearchString)) q = from e in Context.Students where e.Name.Contains(SearchString) select e.Guid;
else q = from e in Context.Students select e.Guid;
stus = q.ToList();
var q2 = from e in Context.SMS where stus.Contains(e.Host) select e;
if (showReceive && !showSend) q2 = from e in q2 where e.Type == SMSType.Reply select e;
else if (!showReceive && showSend) q2 = from e in q2 where e.Type != SMSType.Reply select e;
Messages = q2.ToList();
Messages.Sort((SMS a, SMS b) => b.SendTime.CompareTo(a.SendTime));
int cnt = Messages.Count;
PageCount = (int)Math.Ceiling((double)cnt / (double)pageSize);
if (PageId >= PageCount) PageId = PageCount - 1;
if (PageId < 0) PageId = 0;
pageid = PageId;
int count = (PageId + 1) * pageSize > cnt ? (cnt - PageId * pageSize) : pageSize;
Messages = Messages.GetRange(PageId * pageSize, count);
return Page();
}
public async Task<IActionResult> OnGetAsync(int PageId)
{
return Construct(PageId);
}
public async Task<IActionResult> OnPostAsync(int PageId)
{
return Construct(PageId);
}
public async void OnPostPullAsync(int PageId)
{
var stu = Context.Students.ToList();
foreach (var e in stu)
{
await Utils.TencentSMS.Pull(Context, e, true);
}
Construct(PageId);
}
public async Task<IActionResult> OnPostSignAsync(int PageId)
{
var stu = Context.Students.ToList();
foreach (var e in stu)
{
if (e.Status == status.)
await Utils.TencentSMS.Send(Context, SMSType.Signed, e, Context.Users.Find(Guid.Parse(User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Sid).Value)).Name);
}
return Construct(PageId);
}
public async Task<IActionResult> OnPostResultRejectAsync(int PageId)
{
var stu = Context.Students.ToList();
foreach (var e in stu)
{
if (e.Status == status.)
{
if (!Context.SMS.Any(it => it.Host == e.Guid && it.Type == SMSType.Reject))
await Utils.TencentSMS.Send(Context, SMSType.Reject, e, Context.Users.Find(Guid.Parse(User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Sid).Value)).Name);
}
}
return Construct(PageId);
}
public async Task<IActionResult> OnPostResultAccpetAsync(int PageId)
{
var stu = Context.Students.ToList();
foreach (var e in stu)
{
if (e.Status == status.)
{
if (!Context.SMS.Any(it => it.Host == e.Guid && it.Type == SMSType.Accept))
await Utils.TencentSMS.Send(Context, SMSType.Accept, e, Context.Users.Find(Guid.Parse(User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Sid).Value)).Name);
}
}
return Construct(PageId);
}
}
}

View File

@ -0,0 +1,10 @@
@page
@model _2021_backend.Pages.MigrateModel
@{
ViewData["Title"] = "Migrate";
}
<h1>Migrate</h1>
<form method="post">
<input type="submit" value="Migrate" class="btn btn-danger"/>
</form>

View File

@ -0,0 +1,29 @@
using _2021_backend.Data;
using _2021_backend.Models;
using _2021_backend.Utils;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using NPOI.HPSF;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Pages
{
public class MigrateModel : PageModel
{
private readonly BackendContext _context;
public MigrateModel(BackendContext context)
{
_context = context;
}
public async Task<IActionResult> OnPost(string value)
{
_context.Database.Migrate();
return RedirectToPage("./Index");
}
}
}

View File

@ -0,0 +1,8 @@
@page
@model PrivacyModel
@{
ViewData["Title"] = "关于";
}
<h1>@ViewData["Title"]</h1>
<p>该后端由<a href="https://itszzz.top">Azuk 443</a>设计开发2021技术小组合作贡献使用问题请联系EVA Tech</p>

View File

@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}

View File

@ -0,0 +1,64 @@
@page
@model _2021_backend.Pages.Sessions.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>InterviewTime</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="InterviewTime.Day" class="control-label"></label>
<input asp-for="InterviewTime.Day" class="form-control" />
<span asp-validation-for="InterviewTime.Day" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="InterviewTime.BeginTime" class="control-label"></label>
<input asp-for="InterviewTime.BeginTime" class="form-control" />
<span asp-validation-for="InterviewTime.BeginTime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="InterviewTime.Place" class="control-label"></label>
<select asp-for="InterviewTime.Place" class="form-control">
<option value="200">200</option>
<option value="204">204</option>
</select>
<span asp-validation-for="InterviewTime.Place" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="InterviewTime.Capacity" class="control-label"></label>
<input asp-for="InterviewTime.Capacity" class="form-control" />
<span asp-validation-for="InterviewTime.Capacity" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="InterviewTime.SendSMS" /> @Html.DisplayNameFor(model => model.InterviewTime.SendSMS)
</label>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="CreateTwo" /> @Html.DisplayNameFor(model => model.CreateTwo)
</label>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@ -0,0 +1,80 @@
using _2021_backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Pages.Sessions
{
public class CreateModel : PageModel
{
private readonly _2021_backend.Data.BackendContext Context;
[Display(Name = "同时创建200和204场次")]
[BindProperty]
public bool CreateTwo { get; set; }
[BindProperty]
public Session InterviewTime { get; set; }
[BindProperty]
[Display(Name = "活动官")]
public string ChiefGuid { get; set; }
public List<SelectListItem> ChiefList { get; set; }
public CreateModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
public async Task<IActionResult> OnGet()
{
var qlst = from e in Context.Users select (new SelectListItem { Value = e.Guid.ToString(), Text = e.Name, Selected = false, Disabled = false });
var lst = qlst.ToList().Distinct().ToList();
ChiefList = lst;
return Page();
}
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
InterviewTime.Students = new List<Guid>();
InterviewTime.Chiefs = new List<Guid>();
Session interviewTimeSecond = new Session();
if (CreateTwo)
{
string anotherPlace = InterviewTime.Place == "200" ? "204" : "200";
Session tmp = Context.Sessions.FirstOrDefault(r => r.Place == anotherPlace && r.Day == InterviewTime.Day && InterviewTime.BeginTime == r.BeginTime);
if (tmp == null)
{
interviewTimeSecond = new Session()
{
Day = InterviewTime.Day,
BeginTime = InterviewTime.BeginTime,
Place = anotherPlace,
Chiefs = new List<Guid>(),
SendSMS = InterviewTime.SendSMS,
Students = new List<Guid>(),
Capacity = InterviewTime.Capacity
};
Context.Add(interviewTimeSecond);
Context.SaveChanges();
}
}
Context.Sessions.Add(InterviewTime);
Context.SaveChanges();
return RedirectToPage("./Index");
}
}
}

View File

@ -0,0 +1,41 @@
@page
@model _2021_backend.Pages.Sessions.DeleteModel
@{
ViewData["Title"] = "Delete";
}
<h1>Delete</h1>
<h3>你确定要把这场删掉吗?</h3>
<div>
<h4>删除场次</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.InterviewTime.Day)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.InterviewTime.Day)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.InterviewTime.BeginTime)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.InterviewTime.BeginTime)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.InterviewTime.Capacity)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.InterviewTime.Capacity)
</dd>
</dl>
<form method="post">
<input type="hidden" asp-for="InterviewTime.Guid" />
<input type="submit" value="确定删除" class="btn btn-danger" /> |
<a asp-page="./Index">Back to List</a>
</form>
</div>

View File

@ -0,0 +1,77 @@
using _2021_backend.Data;
using _2021_backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Pages.Sessions
{
public class DeleteModel : PageModel
{
private readonly _2021_backend.Data.BackendContext Context;
public DeleteModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
[BindProperty]
public Session InterviewTime { get; set; }
public async Task<IActionResult> OnGetAsync(string? id)
{
Guid guid = Guid.Parse(id);
if (id == null)
{
return NotFound();
}
InterviewTime = Context.Sessions.Find(guid);
if (InterviewTime == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(string? id)
{
Guid guid = Guid.Parse(id);
if (id == null)
{
return NotFound();
}
InterviewTime = await Context.Sessions.FindAsync(guid);
if (InterviewTime != null)
{
if (InterviewTime.Students.Count > 0)
{
foreach (var x in InterviewTime.Students)
{
Student stu = Context.Students.Find(x);
if (stu != null)
{
stu.InterviewTime = Guid.Empty;
stu.Timelist.RemoveAll(it => it == guid);
}
Context.SaveChanges();
}
}
foreach(var x in Context.Students)
{
x.Timelist.RemoveAll(it => it == guid);
}
Context.Sessions.Remove(InterviewTime);
Context.SaveChanges();
}
return RedirectToPage("./Index");
}
}
}

View File

@ -0,0 +1,69 @@
@page
@model _2021_backend.Pages.Sessions.DetailsModel
@{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>InterviewTime</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.CurSession.Day)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.CurSession.Day)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.CurSession.BeginTime)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.CurSession.BeginTime)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.CurSession.Place)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.CurSession.Place)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.CurSession.Chiefs)
</dt>
<dd class="col-sm-10">
@{
var nm = "";
foreach (var e in Model.CurSession.Chiefs)
{
nm += Model.Context.Users.Find(e).Name + " ";
}
@Html.DisplayFor(model => nm);
}
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.CurSession.Capacity)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.CurSession.Capacity)
</dd>
<dt class="col-sm-2">
已经报名人数
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.CurSession.Students.Count)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.CurSession.SendSMS)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.CurSession.SendSMS)
</dd>
</dl>
</div>
<div>
<a asp-page="./Edit" asp-route-id="@Model.CurSession.Guid">Edit</a> |
<a asp-page="./Index">Back to List</a>
</div>

View File

@ -0,0 +1,39 @@
using _2021_backend.Data;
using _2021_backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Pages.Sessions
{
public class DetailsModel : PageModel
{
public _2021_backend.Data.BackendContext Context;
public DetailsModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
public Session CurSession { get; set; }
public async Task<IActionResult> OnGetAsync(string? id)
{
Guid guid = Guid.Parse(id);
if (id == null)
{
return NotFound();
}
CurSession = Context.Sessions.Find(guid);
if (CurSession == null)
{
return NotFound();
}
return Page();
}
}
}

View File

@ -0,0 +1,152 @@
@page
@model _2021_backend.Pages.Sessions.EditModel
@{
ViewData["Title"] = "Edit";
}
<h1>编辑</h1>
<h4>InterviewTime</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="CurSession.Guid" />
<input type="hidden" asp-for="CurGuid">
<div class="form-group">
<label asp-for="newDay" class="control-label"></label>
<input asp-for="newDay" class="form-control" />
<span asp-validation-for="CurSession.Day" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="newTime" class="control-label"></label>
<input asp-for="newTime" class="form-control" />
<span asp-validation-for="CurSession.BeginTime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="newPlace" class="control-label"></label>
<input asp-for="newPlace" class="form-control" />
<span asp-validation-for="CurSession.Place" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="newCapacity" class="control-label"></label>
<input asp-for="newCapacity" class="form-control" />
<span asp-validation-for="CurSession.Capacity" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="CurSession.SendSMS" /> @Html.DisplayNameFor(model => model.CurSession.SendSMS)
</label>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<hr />
<h4>该时段的活动者</h4>
<form method="post">
<label class="col-sm-2">添加一个</label>
<select asp-items=Model.Stulist id="stuselect" asp-for="addedStu" class="col-sm-2"></select>
<input type="hidden" asp-for="CurGuid" />
<input type="submit" value="Go!" class="btn btn-primary" style="margin-left:5px" asp-page-handler="Add" />
</form>
<br />
<table class="table">
<thead>
<tr>
<th>学号</th>
<th>姓名</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@foreach (var it in Model.CurSession.Students)
{
<tr>
@{
var stu = Model.Context.Students.Find(it);
if (stu != null)
{
var id = stu.Stuid;
<td>@Html.DisplayFor(model=>id)</td>
<td>@Html.DisplayFor(model=>stu.Name)</td>
<td>
<a asp-page="/Students/Details" asp-route-idstr=@stu.Guid.ToString() class="btn btn-primary">详细信息</a>
<div style="float:left">
<form method="post">
<input type="hidden" asp-for="CurGuid">
<input type="submit" value="删除" class="btn btn-danger" asp-page-handler="Delete" asp-route-id=@stu.Guid.ToString() />
</form>
</div>
</td>
}
}
</tr>
}
</tbody>
</table>
<hr />
<h4>活动官们</h4>
<form method="post">
<label class="col-sm-2">添加一个</label>
<select id="chiefselect"asp-items=Model.ChiefList asp-for="addedChief" class="col-sm-2"></select>
<input type="hidden" asp-for="CurGuid" />
<input type="submit" value="Go!" class="btn btn-primary" style="margin-left:5px" asp-page-handler="AddChief" />
</form>
<br />
<table class="table">
<thead>
<tr>
<th>姓名</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@foreach (var it in Model.CurSession.Chiefs)
{
<tr>
@{
var chf = Model.Context.Users.Find(it);
if (chf != null)
{
<td>@Html.DisplayFor(model=>chf.Name)</td>
<td>
<div style="float:left">
<form method="post">
<input type="hidden" asp-for="CurGuid">
<input type="submit" value="删除" class="btn btn-danger" asp-page-handler="DeleteChief" asp-route-id=@chf.Guid.ToString() />
</form>
</div>
</td>
}
}
</tr>
}
</tbody>
</table>
<div>
<a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script type="text/javascirpt" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" />
<script>
$(function(){
$("#chiefselect").select2();
$("#stuselect").select2();
});
</script>
}

View File

@ -0,0 +1,188 @@
using _2021_backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Pages.Sessions
{
public class EditModel : PageModel
{
public _2021_backend.Data.BackendContext Context;
public EditModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
[BindProperty]
public Session CurSession { get; set; }
[BindProperty]
public string CurGuid { get; set; }
[BindProperty]
public string ChiefSearch { get; set; }
public List<SelectListItem> ChiefList { get; set; }
public List<SelectListItem> Stulist { get; set; }
[BindProperty]
public Guid addedChief { get; set; }
[BindProperty]
public string addedStu { get; set; }
[BindProperty]
public string ChiefName { get; set; }
[BindProperty]
[Display(Name ="活动地点")]
[RegularExpression(@"^20[04]$", ErrorMessage = "200204")]
[Required()]
public string newPlace { get; set; }
[BindProperty]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[Required()]
public DateTime newDay { get; set; }
[BindProperty]
[DataType(DataType.Time)]
[DisplayFormat(DataFormatString = "{0:t}", ApplyFormatInEditMode = true)]
[Required()]
public DateTime newTime { get; set; }
[BindProperty]
[Required()]
public bool sendSMS { get; set; }
[BindProperty]
public int newCapacity { get; set; }
public IActionResult Construct(string id)
{
Guid guid = Guid.Parse(id);
if (id == null)
{
return NotFound();
}
CurGuid = id;
CurSession = Context.Sessions.Find(guid);
newDay = CurSession.Day;
newTime = CurSession.BeginTime;
newCapacity = CurSession.Capacity;
sendSMS = CurSession.SendSMS;
newPlace = CurSession.Place;
if (CurSession == null) return RedirectToPage("./Index", new { errmsg = "未找到该活动场次" });
var qlst = from e in Context.Users select (new SelectListItem { Value = e.Guid.ToString(), Text = e.Name, Selected = false, Disabled = false });
ChiefList = qlst.ToList().Distinct().ToList();
var slst = from e in Context.Students where e.InterviewTime == Guid.Empty select new SelectListItem { Value = e.Guid.ToString(), Text = e.Name, Selected = false, Disabled = false };
Stulist = slst.ToList().Distinct().ToList();
return Page();
}
public async Task<IActionResult> OnGetAsync(string id)
{
return Construct(id);
}
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
var ssn = Context.Sessions.Find(Guid.Parse(CurGuid));
ssn.SendSMS = sendSMS;
ssn.Day = newDay;
ssn.BeginTime = newTime;
ssn.Capacity = newCapacity;
ssn.Place = newPlace;
Context.SaveChanges();
return RedirectToPage("./Index");
}
public async Task<IActionResult> OnPostDeleteAsync(string id)
{
CurSession = Context.Sessions.Find(Guid.Parse(CurGuid));
var guid = Guid.Parse(id);
if (!string.IsNullOrEmpty(id))
{
if (Context.Students.Any(it => it.Guid == guid))
{
Context.Students.Find(guid).InterviewTime = Guid.Empty;
CurSession.Students.RemoveAll(it => it == guid);
}
Context.SaveChanges();
}
return Construct(CurGuid);
}
public async Task<IActionResult> OnPostAddAsync()
{
CurSession = Context.Sessions.Find(Guid.Parse(CurGuid));
var guid = Guid.Parse(addedStu);
if (!string.IsNullOrEmpty(addedStu))
{
if (Context.Students.Any(it => it.Guid == guid))
{
var stu = Context.Students.Find(guid);
if(stu.InterviewTime != Guid.Empty)
{
var oldtime = Context.Sessions.Find(stu.InterviewTime);
if(oldtime != null)
{
oldtime.Students.RemoveAll(s => s == stu.Guid);
Context.SaveChanges();
}
}
stu.InterviewTime = CurSession.Guid;
stu.Status = status.;
CurSession.Students.Add(guid);
}
Context.SaveChanges();
}
return Construct(CurGuid);
}
public async Task<IActionResult> OnPostAddChiefAsync()
{
CurSession = Context.Sessions.Find(Guid.Parse(CurGuid));
if (Context.Users.Any(it => it.Guid == addedChief))
{
CurSession.Chiefs.Add(addedChief);
}
Context.SaveChanges();
return Construct(CurGuid);
}
public async Task<IActionResult> OnPostDeleteChiefAsync(string id)
{
var guid = Guid.Parse(id);
CurSession = Context.Sessions.Find(Guid.Parse(CurGuid));
if (CurSession.Chiefs.Contains(guid))
{
CurSession.Chiefs.Remove(guid);
}
Context.SaveChanges();
return Construct(CurGuid);
}
private bool InterviewTimeExists(Guid id)
{
return Context.Sessions.Any(e => e.Guid == id);
}
}
}

View File

@ -0,0 +1,167 @@
@page
@model _2021_backend.Pages.Sessions.IndexModel
@{
ViewData["Title"] = "活动时间管理";
}
<h5 class="text-red">
<strong>@Html.DisplayFor(model => Model.Errmsg)</strong>
</h5>
<h5><strong>全部活动场次</strong></h5>
<a asp-page="./Create" class="btn btn-outline-info m-2">创建新的场次</a>
<a asp-page="./Export" class="btn btn-outline-info m-2">导出</a>
<form class="form-inline" method="post">
<div class="m-2">
筛选日期
<select asp-for="Day" asp-items="Model.DayList" class="form-control">
<option value="">全部</option>
</select>
</div>
<div class="m-2">
筛选场次
<select asp-for="Room" class="form-control">
<option value="">全部</option>
<option value="200">200</option>
<option value="204">204</option>
</select>
</div>
<div class="m-2">
<label class="form-check-label">
只显示未满场次
<input class="form-check-input" asp-for="onlyShowUnFull" />
</label>
</div>
<input type="submit" value="筛选" class="btn btn-outline-primary m-2" />
<input type="submit" value="自动生成新的排班" class="btn btn-outline-warning m-2" asp-page-handler="Arrange" />
<input type="submit" value="全部清空" class="btn btn-outline-danger m-2" asp-page-handler="ClearAll" />
<input type="submit" value="整理一下" class="btn btn-outline-info m-2" asp-page-handler="Tidy" />
<input type="submit" value="重置全部场次" class="btn btn-outline-danger m-2" asp-page-handler="ResetAll" />
<input type="submit" value="保存当前结果" class="btn btn-outline-danger m-2" asp-page-handler="Save" />
<div class="m-2">
加载存档
<select asp-for="savename" class="form-control" asp-items="Model.Files">
</select>
</div>
<input type="submit" value="Go!" class="btn btn-outline-danger m-2" asp-page-handler="Load" />
@*<input type="submit" value="保存这个结果!" class="btn btn-outline-warning m-2" asp-page-handler="Save"/>
<div class="m-2">
加载以前的结果
<select asp-for="TargetIndex" class="form-control" asp-items="@Model.SaveNames">
</select>
</div>*@
@*<input type="submit" value="Load!" class="btn btn-outline-primary m-2" asp-page-handler="Load"/>*@
</form>
<table class="table">
<thead>
<tr>
<th>
序号
</th>
<th>
@Html.DisplayNameFor(model => model.LoadedSessions[0].Day)
</th>
<th>
@Html.DisplayNameFor(model => model.LoadedSessions[0].BeginTime)
</th>
<th>
@Html.DisplayNameFor(model => model.LoadedSessions[0].Place)
</th>
<th>
@Html.DisplayNameFor(model => model.LoadedSessions[0].Chiefs)
</th>
<th>
剩余可用人数
</th>
<th>
容量
</th>
<th>
@Html.DisplayNameFor(model => model.LoadedSessions[0].SendSMS)
</th>
<th>
参与者
</th>
<th>
操作
</th>
</tr>
</thead>
<tbody>
@{
var idx = 0;
}
@foreach (var item in Model.LoadedSessions)
{
<tr class="@{
if (item.Day.Date.Add(item.BeginTime.TimeOfDay).CompareTo(DateTime.Now) < 0)
@("table-secondary")
else if (item.Students.Count == item.Capacity)
@("table-warning")
else if(item.Place=="200")
@("table-success")
else
@("table-info")
} ">
<td>
@{
idx++;
@Html.DisplayFor(mi => idx)
}
</td>
<td>
@Html.DisplayFor(modelItem => item.Day)
</td>
<td>
@Html.DisplayFor(modelItem => item.BeginTime)
</td>
<td>
@Html.DisplayFor(modelItem => item.Place)
</td>
<td>
@{
var str = "";
foreach (var i in item.Chiefs)
{
str += Model.Context.Users.Find(i).Name + " ";
}
@Html.DisplayFor(modelItem => str)
;
}
</td>
<td>
@Html.DisplayFor(modelItem => item.Capacity)
</td>
<td>
@{
var cnt = item.Capacity - item.Students.Count;
@Html.DisplayFor(modelItem => cnt)
}
</td>
<td>
@Html.DisplayFor(modelItem => item.SendSMS)
</td>
<td>
@foreach (var it in item.Students)
{
var q = Model.Context.Students.Find(it);
var s = q.Name;
<a asp-page="/Students/Details" asp-route-idstr=@it.ToString()>@Html.DisplayFor(modelItem => s)</a>
@:&nbsp
}
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Guid">编辑</a> |
<a asp-page="./Delete" asp-route-id="@item.Guid">删除</a> |
<a asp-page-handler="Reset" asp-route-id="@item.Guid">重置</a>
</td>
</tr>
}
</tbody>
</table>

View File

@ -0,0 +1,283 @@
using _2021_backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Text.Json;
using System.IO;
namespace _2021_backend.Pages.Sessions
{
public class IndexModel : PageModel
{
public readonly _2021_backend.Data.BackendContext Context;
public IndexModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
public List<Session> LoadedSessions { get; set; }
public SelectList DayList { get; set; }
[BindProperty(SupportsGet = true)]
public string Room { get; set; }
[BindProperty]
public string Errmsg { get;set; }
[BindProperty]
public string savename { get; set; }
[BindProperty(SupportsGet = true)]
public bool onlyShowUnFull { get; set; }
[BindProperty(SupportsGet = true)]
public DateTime Day { get; set; }
[BindProperty]
public int TargetIndex { get; set; }
public SelectList Files { get; set; }
public IActionResult Construct(string errmsg)
{
Errmsg = errmsg;
var q = from s in Context.Sessions select s;
if (Day != DateTime.MinValue)
{
q = from t in q where t.Day == Day select t;
}
if (Room == "200" || Room == "204")
{
q = from t in q where t.Place == Room select t;
}
if (onlyShowUnFull)
{
q = from t in q where t.Capacity != t.Students.Count select t;
}
LoadedSessions = q.ToList();
LoadedSessions.Sort((Session a, Session b) =>
{
var x = a.Day.Date.Add(a.BeginTime.TimeOfDay).CompareTo(DateTime.Now);
var y = b.Day.Date.Add(b.BeginTime.TimeOfDay).CompareTo(DateTime.Now);
if (x != y) return y - x;
else
{
var z = a.Day.Date.Add(a.BeginTime.TimeOfDay).CompareTo(b.Day.Date.Add(b.BeginTime.TimeOfDay));
if (z != 0) return z;
else
{
if (a.BeginTime < b.BeginTime) return -1;
else if (a.BeginTime > b.BeginTime) return 1;
else if (a.Place == "200") return -1;
else if (a.Place == "204") return 1;
return 0;
}
}
});
var l = from it in LoadedSessions select it.Day;
DayList = new SelectList(l.Distinct());
if (!Directory.Exists("./saves")) Directory.CreateDirectory("./saves");
Files = new SelectList(Directory.GetFiles("./saves").ToList());
//Console.WriteLine(Files);
return Page();
}
public async Task<IActionResult> OnGetAsync(string errmsg)
{
return Construct(errmsg);
}
public async Task<IActionResult> OnGetResetAsync(Guid id)
{
if(Context.Sessions.Any(it => it.Guid == id))
{
var s = Context.Sessions.Find(id);
foreach(var st in s.Students)
{
var e = Context.Students.Find(st);
e.Status = status.;
e.InterviewTime = Guid.Empty;
}
s.Students.Clear();
}
Context.SaveChanges();
return Construct("");
}
public async Task<IActionResult> OnPost()
{
return Construct("");
}
//public async Task<IActionResult> OnPostLoadAsync()
//{
// return Construct("");
//}
//public async Task<IActionResult> OnPostSaveAsync()
//{
// return Construct("");
//}
public async Task<IActionResult> OnPostArrangeAsync()
{
if (Utils.Arranger.Arrange(Context)) return Construct("");
else return Construct("排班失败,无法满足条件");
}
public async Task<IActionResult> OnPostClearAllAsync()
{
foreach(var s in Context.Students)
{
s.InterviewTime = Guid.Empty;
s.Status = status.;
s.Timelist.Clear();
}
Context.SaveChanges();
foreach(var s in Context.Sessions)
{
Context.Sessions.Remove(s);
}
Context.SaveChanges();
return Construct("");
}
public async Task<IActionResult> OnPostResetAllAsync()
{
var stus = Context.Students.ToList();
foreach (var s in stus)
{
if(s.Status == status.)
{
s.InterviewTime = Guid.Empty;
s.Timelist.RemoveAll(it => !Context.Sessions.Any(k => k.Guid == it));
s.Timelist.Sort((Guid a, Guid b) =>
{
var x = Context.Sessions.Find(a);
var y = Context.Sessions.Find(b);
var k1 = x.Day.CompareTo(y.Day);
var k2 = x.BeginTime.CompareTo(y.BeginTime);
return k1 != 0 ? k1 : k2;
});
}
}
Context.SaveChanges();
foreach (var s in Context.Sessions)
{
s.Students.Clear();
}
Context.SaveChanges();
return Construct("");
}
public async Task<IActionResult> OnPostSaveAsync()
{
var lst = Context.Sessions.ToList();
var str = JsonSerializer.Serialize(lst);
Console.WriteLine("Saving arrangement: " + str);
if(!Directory.Exists("./saves")) Directory.CreateDirectory("./saves/");
System.IO.File.WriteAllText($"./saves/{DateTime.Now.ToString("MM-dd-hh-mm-ss")}.txt", str);
return Construct("");
}
public async Task<IActionResult> OnPostTidyAsync()
{
var stus = Context.Students.ToList();
var sess = Context.Sessions.ToList();
foreach(var i in stus)
{
var tm = i.Timelist;
var ntm = new List<Session>();
foreach(var j in tm)
{
var k = sess.Find(it => it.Guid == j);
ntm.Add(k);
}
ntm.Sort((Session a,Session b) =>
{
var x = a.Day.CompareTo(b.Day);
var y = a.BeginTime.CompareTo(b.BeginTime);
return x != 0 ? x : y;
});
List<Guid> nl = new List<Guid>();
foreach(var j in ntm)
{
if(i.Status != status. && i.Status != status. && i.Status != status.)
{
if (j.Day.Date.Add(j.BeginTime.TimeOfDay).CompareTo(DateTime.Now) < 0 || (j.Students.Count >= j.Capacity && !j.Students.Any(k => k ==i.Guid) )) continue;
nl.Add(j.Guid);
}
else
{
nl.Add(j.Guid);
}
}
i.Timelist = nl;
}
Context.SaveChanges();
return Construct("");
}
public async Task<IActionResult> OnPostLoadAsync()
{
var str = "";
List<Session> loads = new List<Session>();
if (!string.IsNullOrEmpty(savename)) str = System.IO.File.ReadAllText(savename);
loads = JsonSerializer.Deserialize<List<Session>>(str);
var stus = Context.Students.ToList();
foreach (var s in stus)
{
if (s.Status == status.)
{
s.InterviewTime = Guid.Empty;
s.Timelist.RemoveAll(it => !Context.Sessions.Any(k => k.Guid == it));
s.Timelist.Sort((Guid a, Guid b) =>
{
var x = Context.Sessions.Find(a);
var y = Context.Sessions.Find(b);
var k1 = x.Day.CompareTo(y.Day);
var k2 = x.BeginTime.CompareTo(y.BeginTime);
return k1 != 0 ? k1 : k2;
});
}
}
Context.SaveChanges();
foreach (var s in Context.Sessions)
{
s.Students.Clear();
}
Context.SaveChanges();
foreach(var item in loads)
{
Session s = Context.Sessions.Find(item.Guid);
if(s != null)
{
s.BeginTime = item.BeginTime;
s.Day = item.Day;
s.Capacity = item.Capacity;
s.SendSMS = item.SendSMS;
s.Chiefs = item.Chiefs;
s.Students = new List<Guid>();
foreach(var s2 in item.Students)
{
if (Context.Students.Any(k => k.Guid == s2))
{
Context.Students.Find(s2).InterviewTime = item.Guid;
s.Students.Add(s2);
}
}
}
}
Context.SaveChanges();
return Construct("");
}
}
}

View File

@ -0,0 +1,86 @@
@using _2021_backend.Utils;
@using System.Security.Claims;
@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - 2021 精品活动后台</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-page="/Index">2021纳新后台</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
@if (HttpContextAccessor.HttpContext.User.Identity.IsAuthenticated)
{
<div class="form-inline my-2 my-lg-0 nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Account/Logout">登出</a>
</div>
}
else
{
<div class="form-inline my-2 my-lg-0 nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Account/Login">登录</a>
</div>
}
@if (HttpContextAccessor.HttpContext.User.Identity.IsAuthenticated)
{
<div class="form-inline my-2 my-lg-0">
<span class="nav-item">欢迎您,@(HttpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.Name).Value)</span>
</div>
}
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Index">首页</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">已报名学生</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Submissions/Index">提交记录</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Message/Index">短信</a>
</li>
@if (HttpContextAccessor.HttpContext.User.HasClaim(EvaClaimTypes.IsManager, "true"))
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Users/Index">后台用户管理</a>
</li>
}
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Sessions/Index">活动排班</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container-fluid">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
&copy; 2021-backend <a asp-area="" asp-page="/Privacy">关于</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>

View File

@ -0,0 +1,2 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

View File

@ -0,0 +1,79 @@
@page
@model _2021_backend.Pages.Students.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>创建</h1>
<h4>学生</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Student.Name" class="control-label"></label>
<input asp-for="Student.Name" class="form-control" />
<span asp-validation-for="Student.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Stuid" class="control-label"></label>
<input asp-for="Student.Stuid" class="form-control" />
<span asp-validation-for="Student.Stuid" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Sex" class="control-label"></label>
<select asp-for="Student.Sex" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.sex))"></select>
<span asp-validation-for="Student.Sex" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Yard" class="control-label"></label>
<select asp-for="Student.Yard" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.yard))"></select>
<span asp-validation-for="Student.Yard" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Grade" class="control-label"></label>
<select asp-for="Student.Grade" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.grade))"></select>
<span asp-validation-for="Student.Grade" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Major" class="control-label"></label>
<input asp-for="Student.Major" class="form-control" />
<span asp-validation-for="Student.Major" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Email" class="control-label"></label>
<input asp-for="Student.Email" class="form-control" />
<span asp-validation-for="Student.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Tel" class="control-label"></label>
<input asp-for="Student.Tel" class="form-control" />
<span asp-validation-for="Student.Tel" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Status" class="control-label"></label>
<select asp-for="Student.Status" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.status))"></select>
<span asp-validation-for="Student.Status" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.RegisterTime" class="control-label"></label>
<input asp-for="Student.RegisterTime" class="form-control" />
<span asp-validation-for="Student.RegisterTime" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">返回列表</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@ -0,0 +1,48 @@
using _2021_backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Pages.Students
{
public class CreateModel : PageModel
{
private readonly _2021_backend.Data.BackendContext Context;
public CreateModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
public IActionResult OnGet()
{
Student = new Student();
return Page();
}
[BindProperty]
[Required(ErrorMessage = "该项不能为空")]
public Student Student { get; set; }
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
if (Context.Students.Any(t => (t.Name == Student.Name || t.Stuid == Student.Stuid || t.Tel == Student.Tel)))
{
return RedirectToPage("./Index", new { pageId = 0, errInfo = "该学生已经存在" });
}
Context.Students.Add(Student);
await Context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}

View File

@ -0,0 +1,82 @@
@page
@model _2021_backend.Pages.Students.DeleteModel
@{
ViewData["Title"] = "Delete";
}
<h1>删除</h1>
<h3>你确定要删除该项目吗?</h3>
<div>
<h4>学生</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Name)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Name)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Stuid)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Stuid)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Sex)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Sex)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Grade)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Grade)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Major)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Major)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Email)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Email)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Tel)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Tel)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Status)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Status)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.LastSubmission)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.LastSubmission)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.RegisterTime)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.RegisterTime)
</dd>
</dl>
<form method="post">
<input type="hidden" asp-for="Student.Guid" />
<input type="submit" value="删除" class="btn btn-danger" /> |
<a asp-page="./Index">返回列表</a>
</form>
</div>

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using _2021_backend.Data;
using _2021_backend.Models;
namespace _2021_backend.Pages.Students
{
public class DeleteModel : PageModel
{
private readonly _2021_backend.Data.BackendContext Context;
public DeleteModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
[BindProperty]
public Student Student { get; set; }
public async Task<IActionResult> OnGetAsync(string? idstr)
{
if (idstr == null)
{
return NotFound();
}
Guid id = Guid.Parse(idstr);
Student = await Context.Students.FirstOrDefaultAsync(m => m.Guid == id);
if (Student == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(string? idstr)
{
if (idstr == null)
{
return NotFound();
}
Guid id = Guid.Parse(idstr);
Student = await Context.Students.FindAsync(id);
if (Student != null)
{
var q = from e in Context.Sessions where e.Students.Contains(id) select e;
var lst = q.ToList();
foreach(var it in lst)
{
it.Students.RemoveAll(k => k == id);
}
Context.Students.Remove(Student);
Context.SaveChanges();
}
return RedirectToPage("./Index");
}
}
}

View File

@ -0,0 +1,370 @@
@page
@model _2021_backend.Pages.Students.DetailsModel
@{
ViewData["Title"] = "Details";
}
<h1>@Html.DisplayFor(model=> Model.Student.Name)</h1>
<div>
<h4>详细信息</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Name)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Name)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Stuid)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Stuid)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Sex)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Sex)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Grade)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Grade)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Major)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Major)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Email)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Email)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Tel)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Tel)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.Status)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.Status)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Student.RegisterTime)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Student.RegisterTime)
</dd>
</dl>
</div>
<h5>此人的最终得分 @Html.DisplayFor(model => model.Student.Score)</h5>
<form method="post" class="form-inline m-2">
<input type="hidden" asp-for="Student.Guid" />
<div class="mb-2">
操作
</div>
<div class="mb-2">
<input type="submit" value="通过" class="btn btn-info" style="margin:5px" asp-page-handler="Accept" />
</div>
<div class="mb-2">
<input type="submit" value="拒绝" class="btn btn-danger" style="margin:5px" asp-page-handler="Reject" />
</div>
<div class="mb-2">
给他打分
<input asp-for="score" class="form-control"/>
<input type="submit" value="打" class="btn btn-warning" style="margin:5px" asp-page-handler="Rank" />
</div>
</form>
<br />
<h4>
看看大家怎么说
</h4>
<table class="table">
<thead>
<tr>
<th> @Html.DisplayNameFor(model => model.CommentSample.Operator)</th>
<th> @Html.DisplayNameFor(model => model.CommentSample.Content)</th>
<th> @Html.DisplayNameFor(model => model.CommentSample.AddTime)</th>
</tr>
</thead>
<tbody>
@foreach (var cmt in Model.CurComments)
{
<tr>
@{
var usr = Model.Context.Users.Find(cmt.Operator);
<td>
@Html.DisplayFor(model => usr.Name)
</td>
<td>
@Html.DisplayFor(model => cmt.Content)
</td>
<td>
@Html.DisplayFor(model => cmt.AddTime)
</td>
}
</tr>
}
</tbody>
</table>
<h4>
添加评论
</h4>
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<textarea asp-for="NewComment" class="form-control" rows="5"></textarea>
<span asp-validation-for="NewComment" class="text-danger"></span>
</div>
<div class="form-group">
<input type="hidden" asp-for="Student.Guid" />
<input type="submit" value="→" class="btn btn-primary btn-sm" />
</div>
</form>
<br />
<h4>
场次
</h4>
<h4>
最终场次 : @{
if (Model.Interviewtime == null)
{
<div class="text-danger">尚未确定活动场次</div>
<hr />
}
else
{
<div class="text-info">
@{
var val = Model.Interviewtime.Place + " " + Model.Interviewtime.Day.ToString("MM月dd日") + " " + Model.Interviewtime.BeginTime.ToString("hh:mm");
@Html.DisplayFor(model => val)
}
</div>
}
}
</h4>
<table class="table">
<thead>
<tr >
<th>地点</th>
<th>日期</th>
<th>时间</th>
<th>总容量</th>
<th>剩余人数</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@for (int i = 0; i < Model.Student.Timelist.Count; i++)
{
var it = Model.Student.Timelist[i];
var dt = Model.Context.Sessions.Find(it);
if (dt.Capacity > dt.Students.Count || dt.Students.Contains(Model.Student.Guid))
{
<tr>
<td>
@{
@Html.DisplayFor(model => dt.Place)
}
</td>
<td>
@{
var s1 = dt.Day.ToString("MM-dd");
@Html.DisplayFor(model => s1)
}
</td>
<td>
@{
var s2 = dt.BeginTime.ToString("hh-mm");
@Html.DisplayFor(model => s2)
}
</td>
<td>
@{
var s4 = dt.Capacity.ToString();
@Html.DisplayFor(model => s4)
}
</td>
<td>
@{
var num = (dt.Capacity - dt.Students.Count()).ToString();
@Html.DisplayFor(model => num)
}
</td>
<td>
<form method="post" class="form-inline">
<input type="hidden" asp-for="Student.Guid" />
<a asp-page="/Sessions/Edit" asp-route-id="@it.ToString()" class="btn btn-sm btn-primary">场次详情</a>
<input type="submit" asp-page-handler="Select" asp-route-stu="@Model.Student.Guid" asp-route-time="@it.ToString()" class="btn btn-sm btn-warning" value="选择这个" />
</form>
</td>
</tr>
}
}
</tbody>
</table>
<h4>
Ta的短信
</h4>
<form method="post">
<input type="hidden" asp-for="Student.Guid" />
<input type="submit" value="拉取5天内的回复短信" class="btn btn-primary" asp-page-handler="Pull" />
<input type="submit" value="发送报名确认短信" class="btn btn-primary" asp-page-handler="Sign" />
<input type="submit" value="发送活动场次确认短信" class="btn btn-primary" asp-page-handler="Time" />
<input type="submit" value="发送活动结果短信" class="btn btn-primary" asp-page-handler="Result" />
</form>
<table class="table">
<thead>
<tr>
<th>
发送时间
</th>
<th>
短信类型
</th>
<th>
短信内容
</th>
</tr>
</thead>
<tbody>
@foreach (var msg in Model.Messages)
{
<tr>
<td>
@{
var str = msg.SendTime.ToString("MM-dd hh:mm:ss");
@Html.DisplayFor(it => str)
}
</td>
<td>
@{
var s = Enum.GetName(typeof(_2021_backend.Models.SMSType), msg.Type);
@Html.DisplayFor(it=> s)
}
</td>
<td>
@{
string s2 = "";
foreach (var e in msg.Data)
{
if (!string.IsNullOrEmpty(e)) s2 += " " + e;
}
@Html.DisplayFor(it => s2)
}
</td>
</tr>
}
</tbody>
</table>
<h4>
Ta的提交记录
</h4>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.SubmissionSample.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.SubmissionSample.Stuid)
</th>
<th>
@Html.DisplayNameFor(model => model.SubmissionSample.Sex)
</th>
<th>
@Html.DisplayNameFor(model => model.SubmissionSample.Yard)
</th>
<th>
@Html.DisplayNameFor(model => model.SubmissionSample.Grade)
</th>
<th>
@Html.DisplayNameFor(model => model.SubmissionSample.Major)
</th>
<th>
@Html.DisplayNameFor(model => model.SubmissionSample.Email)
</th>
<th>
@Html.DisplayNameFor(model => model.SubmissionSample.Tel)
</th>
<th>
@Html.DisplayNameFor(model => model.SubmissionSample.Address)
</th>
<th>
@Html.DisplayNameFor(model => model.SubmissionSample.SubmitTime)
</th>
<th>
Operation
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Student.Submissions)
{
var sub = Model.Context.Submissions.Find(item);
<tr>
<td>
@Html.DisplayFor(modelItem => sub.Name)
</td>
<td>
@Html.DisplayFor(modelItem => sub.Stuid)
</td>
<td>
@Html.DisplayFor(modelItem => sub.Sex)
</td>
<td>
@Html.DisplayFor(modelItem => sub.Yard)
</td>
<td>
@Html.DisplayFor(modelItem => sub.Grade)
</td>
<td>
@Html.DisplayFor(modelItem => sub.Major)
</td>
<td>
@Html.DisplayFor(modelItem => sub.Email)
</td>
<td>
@Html.DisplayFor(modelItem => sub.Tel)
</td>
<td>
@Html.DisplayFor(modelItem => sub.Address)
</td>
<td>
@Html.DisplayFor(modelItem => sub.SubmitTime)
</td>
<td>
<a asp-page="/Submissions/Edit" asp-route-strid="@sub.Guid">Edit</a> |
<a asp-page="/Submissions/Details" asp-route-strid="@sub.Guid">Details</a>
</td>
</tr>
}
</tbody>
</table>
<div>
<a asp-page="./Edit" asp-route-idstr="@Model.Student.Guid">编辑信息</a> |
<a asp-page="./Index">返回列表</a>
</div>

View File

@ -0,0 +1,204 @@
using _2021_backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace _2021_backend.Pages.Students
{
public class DetailsModel : PageModel
{
public _2021_backend.Data.BackendContext Context;
public DetailsModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
[BindProperty]
public Student Student { get; set; }
[BindProperty]
public int score { get; set; }
public List<Session> Sessions { get; set; }
public List<Submission> Submissions { get; set; }
public List<Comment> CurComments { get; set; }
public Session Interviewtime { get; set; }
public Comment CommentSample { get; set; }
public Submission SubmissionSample { get; set; }
[Display(Name = "评论内容")]
[BindProperty]
[Required(ErrorMessage = "该项不能为空")]
public string NewComment { get; set; }
public List<SMS> Messages { get; set; }
public IActionResult Construct(string? idstr)
{
if (idstr == null)
{
return NotFound();
}
Guid id = Guid.Parse(idstr);
Student = Context.Students.Find(id);
if (Student == null)
{
Console.WriteLine("Student not found.");
return NotFound();
}
Sessions = new List<Session>();
Submissions = new List<Submission>();
Interviewtime = Context.Sessions.Find(Student.InterviewTime);
foreach (var it in Student.Timelist)
{
var tm = Context.Sessions.Find(it);
if (tm == null) Console.WriteLine("null encountered in timelist!");
Sessions.Add(tm);
}
Messages = Context.SMS.Where(it => it.Host == id).ToList();
CurComments = Context.Comments.Where(cmt => cmt.Student == Student.Guid).ToList();
Sessions.Sort((Session a, Session b) => {
var x = a.Day.CompareTo(b.Day);
var y = a.BeginTime.CompareTo(b.BeginTime);
var z = a.Place.CompareTo(b.Place);
return (x != 0 ? x : y != 0 ? y : z != 0 ? z : 0);
});
Console.WriteLine("Page construction finished.");
return Page();
}
public async Task<IActionResult> OnGetAsync(string? idstr)
{
Console.WriteLine("getting student " + idstr);
return Construct(idstr);
}
public async Task<IActionResult> OnPostAsync()
{
if (!string.IsNullOrWhiteSpace(NewComment))
{
var cmt = new Comment();
cmt.Student = Student.Guid;
cmt.Content = NewComment;
cmt.Operator = Guid.Parse(User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Sid).Value);
var stu = Context.Students.Find(Student.Guid);
stu.Comments.Add(cmt.Guid);
Context.Comments.Add(cmt);
Context.SaveChanges();
}
Construct(Student.Guid.ToString());
return RedirectToPage(new { idstr = Student.Guid.ToString() });
}
public async Task<IActionResult> OnPostAcceptAsync()
{
Student = Context.Students.Find(Student.Guid);
Student.Status = status.;
Context.SaveChanges();
CurComments = Context.Comments.Where(cmt => cmt.Student == Student.Guid).ToList();
Messages = Context.SMS.Where(it => it.Host == Student.Guid).ToList();
Construct(Student.Guid.ToString());
return RedirectToPage(new { idstr = Student.Guid.ToString() });
}
public async Task<IActionResult> OnPostRejectAsync()
{
Student = Context.Students.Find(Student.Guid);
Student.Status = status.;
Context.SaveChanges();
Student.Score = 0;
CurComments = Context.Comments.Where(cmt => cmt.Student == Student.Guid).ToList();
Messages = Context.SMS.Where(it => it.Host == Student.Guid).ToList();
Construct(Student.Guid.ToString());
return RedirectToPage(new { idstr = Student.Guid.ToString() });
}
public async Task<IActionResult> OnPostSelectAsync(Guid stu, Guid time)
{
var st = Context.Students.Find(stu);
if (st != null)
{
if (Context.Sessions.Any(it => it.Guid == time))
{
var tm = Context.Sessions.Find(time);
if (tm.Students.Count < tm.Capacity)
{
if (st.InterviewTime != Guid.Empty)
{
var tmold = Context.Sessions.Find(st.InterviewTime);
if (tmold != null)
{
tmold.Students.RemoveAll(it => it == st.Guid);
Context.SaveChanges();
}
}
tm.Students.Add(stu);
st.InterviewTime = time;
if (st.Status != status. && st.Status != status.) st.Status = status.;
Context.SaveChanges();
}
}
}
return Construct(Student.Guid.ToString());
}
public async Task<IActionResult> OnPostPullAsync()
{
await Utils.TencentSMS.Pull(Context, Context.Students.Find(Student.Guid), true);
return Construct(Student.Guid.ToString());
}
public async Task<IActionResult> OnPostRankAsync()
{
var s = Context.Students.Find(Student.Guid);
s.Score = score;
s.Status = status.;
Context.SaveChanges();
return Construct(Student.Guid.ToString());
}
public async Task<IActionResult> OnPostResultAsync()
{
var stu = Context.Students.Find(Student.Guid);
if (stu.Status == status.)
await Utils.TencentSMS.Send(Context, SMSType.Accept, stu, Context.Users.Find(Guid.Parse(User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Sid).Value)).Name);
else if (stu.Status == status.)
await Utils.TencentSMS.Send(Context, SMSType.Reject, stu, Context.Users.Find(Guid.Parse(User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Sid).Value)).Name);
return Construct(Student.Guid.ToString());
}
public async Task<IActionResult> OnPostSignAsync()
{
var stu = Context.Students.Find(Student.Guid);
await Utils.TencentSMS.Send(Context, SMSType.Signed, stu, Context.Users.Find(Guid.Parse(User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Sid).Value)).Name);
return Construct(Student.Guid.ToString());
}
public async Task<IActionResult> OnPostSelectTimeAsync()
{
var stu = Context.Students.Find(Student.Guid);
await Utils.TencentSMS.Send(Context, SMSType.TimeSelect, stu, Context.Users.Find(Guid.Parse(User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Sid).Value)).Name);
stu.Status = status.;
return Construct(Student.Guid.ToString());
}
public async Task<IActionResult> OnPostTimeAsync()
{
var stu = Context.Students.Find(Student.Guid);
await Utils.TencentSMS.Send(Context, SMSType.TimeSet, stu, Context.Users.Find(Guid.Parse(User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Sid).Value)).Name);
stu.Status = status.;
Context.SaveChanges();
return Construct(Student.Guid.ToString());
}
}
}

View File

@ -0,0 +1,80 @@
@page
@model _2021_backend.Pages.Students.EditModel
@{
ViewData["Title"] = "Edit";
}
<h1>编辑详细信息</h1>
<h4>学生</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Student.Guid" />
<div class="form-group">
<label asp-for="Student.Name" class="control-label"></label>
<input asp-for="Student.Name" class="form-control" />
<span asp-validation-for="Student.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Stuid" class="control-label"></label>
<input asp-for="Student.Stuid" class="form-control" />
<span asp-validation-for="Student.Stuid" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Sex" class="control-label"></label>
<select asp-for="Student.Sex" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.sex))"></select>
<span asp-validation-for="Student.Sex" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Yard" class="control-label"></label>
<select asp-for="Student.Yard" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.yard))"></select>
<span asp-validation-for="Student.Yard" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Grade" class="control-label"></label>
<select asp-for="Student.Grade" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.grade))"></select>
<span asp-validation-for="Student.Grade" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Major" class="control-label"></label>
<input asp-for="Student.Major" class="form-control" />
<span asp-validation-for="Student.Major" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Email" class="control-label"></label>
<input asp-for="Student.Email" class="form-control" />
<span asp-validation-for="Student.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Tel" class="control-label"></label>
<input asp-for="Student.Tel" class="form-control" />
<span asp-validation-for="Student.Tel" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.RegisterTime" class="control-label"></label>
<input asp-for="Student.RegisterTime" class="form-control" />
<span asp-validation-for="Student.RegisterTime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Student.Status" class="control-label"></label>
<select asp-for="Student.Status" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.status))"></select>
<span asp-validation-for="Student.Status" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="./Index">返回列表</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@ -0,0 +1,61 @@
using _2021_backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Pages.Students
{
public class EditModel : PageModel
{
public readonly _2021_backend.Data.BackendContext Context;
public EditModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
[BindProperty]
public Student Student { get; set; }
public async Task<IActionResult> OnGetAsync(string? idstr)
{
if (idstr == null)
{
return NotFound();
}
Guid id = Guid.Parse(idstr);
Student = await Context.Students.AsNoTracking().FirstOrDefaultAsync(m => m.Guid == id);
if (Student == null)
{
return NotFound();
}
return Page();
}
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
var stu = Context.Students.Find(Student.Guid);
stu.Status = Student.Status;
stu.Email = Student.Email;
stu.Name = Student.Name;
stu.Stuid = Student.Stuid;
stu.Tel = Student.Tel;
stu.Grade = Student.Grade;
stu.Sex = Student.Sex;
stu.Yard = Student.Yard;
Context.SaveChanges();
return RedirectToPage("./Index");
}
private bool StudentExists(Guid id)
{
return Context.Students.Any(e => e.Guid == id);
}
}
}

View File

@ -0,0 +1,155 @@
@page
@model _2021_backend.Pages.Students.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>报了名的xpy们</h1>
<p>
<a asp-page="Create">手动添加一个</a>
</p>
<h5 class="text-red">
<strong>@Html.DisplayFor(model => Model.errmsg)</strong>
</h5>
<form class="form-inline m-2" method="post">
<div class="form-group mx-sm-0 m-2">
<input type="text" class="form-control" id="searchString" placeholder="输入部分学号或姓名" asp-for="SearchString" name="SearchString">
</div>
<div class="form-group mx-sm-0 m-2">
<input type="text" class="form-control" id="SearchTel" placeholder="电话号码" asp-for="SearchTel" name="SearchTel">
</div>
<div class="form-group mx-sm-0 m-2">
<input type="text" class="form-control" id="SearchQQ" placeholder="QQ号码" asp-for="SearchQQ" name="SearchQQ">
</div>
<div class="m-2">
年级
<select asp-for="Grade" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.grade))" class="form-control">
</select>
</div>
<div class="m-2">
状态
<select asp-for="StatusSel" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.status))" class="form-control">
</select>
</div>
<button type="submit" class="btn btn-outline-primary m-2">搜索</button>
</form>
<table class="table">
<thead>
<tr>
<th>
Index
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].Stuid)
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].Sex)
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].Yard)
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].Grade)
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].Major)
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].Status)
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].Exp)
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].Score)
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].RegisterTime)
</th>
<th></th>
</tr>
</thead>
<tbody>
@{
var n = 0;
@foreach (var item in Model.Student)
{
n++;
<tr class="@{
switch(item.Status){
case _2021_backend.Models.status.不通过:
@("table-danger")
break;
case _2021_backend.Models.status.通过:
@("table-success")
break;
case _2021_backend.Models.status.刚报名:
@("")
break;
case _2021_backend.Models.status.已评分:
@("table-primary")
break;
}
}">
<td>
@{
var s = (Model.PageId * IndexModel.PageSize + n).ToString();
@Html.DisplayFor(it => s)
}
</td>
<td>
<a asp-page="./Details" asp-route-idstr="@item.Guid.ToString()"> @Html.DisplayFor(modelItem => item.Name)</a>
</td>
<td>
<a asp-page="./Details" asp-route-idstr="@item.Guid.ToString()"> @Html.DisplayFor(modelItem => item.Stuid)</a>
</td>
<td>
@Html.DisplayFor(modelItem => item.Sex)
</td>
<td>
@Html.DisplayFor(modelItem => item.Yard)
</td>
<td>
@Html.DisplayFor(modelItem => item.Grade)
</td>
<td>
@Html.DisplayFor(modelItem => item.Major)
</td>
<td>
@Html.DisplayFor(modelItem => item.Status)
</td>
<td>
@Html.DisplayFor(modelItem => item.Exp)
</td>
<td>
@Html.DisplayFor(modelItem => item.Score)
</td>
<th>
@Html.DisplayFor(modelItem => item.RegisterTime)
</th>
<td>
<a asp-page="./Edit" asp-route-idstr="@item.Guid.ToString()">编辑资料</a> |
<a asp-page="./Details" asp-route-idstr="@item.Guid.ToString()">审阅</a> |
<a asp-page="./Delete" asp-route-idstr="@item.Guid.ToString()">删除</a>
</td>
</tr>
}
}
</tbody>
</table>
<nav>
<ul class="pagination">
<li class="page-item @(Model.PageId==0 ? "disabled" : "")"><a class="page-link" asp-route-pageId="@(Model.PageId-1) " asp-route-Grade="@Model.Grade" asp-route-SearchString="@Model.SearchString" asp-route-StatusSel="@Model.StatusSel" asp-route-SearchQQ="@Model.SearchQQ">Prev</a></li>
@for (int i = 0; i < Model.PageCount; i++)
{
<li class="page-item @(Model.PageId==i ? "active" : "")"><a class="page-link" asp-route-pageId="@i" asp-route-Grade="@Model.Grade" asp-route-SearchString="@Model.SearchString" asp-route-StatusSel="@Model.StatusSel" asp-route-SearchQQ="@Model.SearchQQ">@i</a></li>
}
<li class="page-item @(Model.PageId>=Model.PageCount -1? "disabled" : "")"><a class="page-link" asp-route-pageId="@(Model.PageId+1)" asp-route-Grade="@Model.Grade" asp-route-SearchString="@Model.SearchString" asp-route-StatusSel="@Model.StatusSel" asp-route-SearchQQ="@Model.SearchQQ">Next</a></li>
</ul>
</nav>

View File

@ -0,0 +1,97 @@
using _2021_backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System;
using System.IO.Compression;
using System.Collections.Generic;
using System.Linq;
using _2021_backend.Utils;
using System.Threading.Tasks;
namespace _2021_backend.Pages.Students
{
public class IndexModel : PageModel
{
private readonly _2021_backend.Data.BackendContext Context;
public static int PageSize { get; set; }
public int PageCount { get; set; }
public int PageId { get; set; }
public string errmsg { get; set; }
[BindProperty(SupportsGet = true)]
public string SearchString { get; set; }
[BindProperty(SupportsGet = true)]
public grade Grade { get; set; }
[BindProperty(SupportsGet = true)]
public string SearchQQ { get; set; }
[BindProperty(SupportsGet = true)]
public string SearchTel { get; set; }
[BindProperty(SupportsGet = true)]
public status StatusSel { get; set; } = status.;
public IndexModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
public List<Student> Student { get; set; }
public IActionResult Construct(int pageId, string errInfo)
{
PageSize = 30;
if (string.IsNullOrEmpty(errInfo))
{
errmsg = "";
}
else
{
errmsg = errInfo;
}
if (pageId == null) pageId = 0;
IQueryable<Student> q;
if (!string.IsNullOrEmpty(SearchString))
{
q = Context.Students.Where(s => (s.Name.Contains(SearchString) || s.Stuid.Contains(SearchString)));
}
else
{
q = Context.Students;
}
if (Grade != grade.) q = q.Where(it => it.Grade == Grade);
if (StatusSel != status.) q = q.Where(it => it.Status == StatusSel);
if (!String.IsNullOrEmpty(SearchTel)) q = q.Where(it => it.Tel.Contains(SearchTel));
if (!String.IsNullOrEmpty(SearchQQ)) q = q.Where(it => it.Email.Contains(SearchQQ));
Student = q.ToList();
Student.Sort((Student a, Student b) =>
{
return -a.RegisterTime.CompareTo(b.RegisterTime);
});
int cnt = Student.Count;
PageCount = (int)Math.Ceiling((double)cnt / (double)PageSize);
if (pageId >= PageCount) pageId = PageCount - 1;
if (pageId < 0) pageId = 0;
PageId = (int)pageId;
int count = (PageId + 1) * PageSize > cnt ? (cnt - PageId * PageSize) : PageSize;
Student = Student.GetRange(PageId * PageSize, count);
return Page();
}
public async Task<IActionResult> OnGetAsync(int? pageId, string errInfo)
{
if (pageId == null) pageId = 0;
return Construct((int)pageId, errInfo);
}
public async Task<IActionResult> OnPostAsync(int? pageId, string errInfo)
{
if (pageId == null) pageId = 0;
return Construct((int)pageId, errInfo);
}
}
}

View File

@ -0,0 +1,74 @@
@page
@model _2021_backend.Pages.Submissions.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>创建</h1>
<h4>提交记录</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Submission.Name" class="control-label"></label>
<input asp-for="Submission.Name" class="form-control" />
<span asp-validation-for="Submission.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Stuid" class="control-label"></label>
<input asp-for="Submission.Stuid" class="form-control" />
<span asp-validation-for="Submission.Stuid" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Sex" class="control-label"></label>
<select asp-for="Submission.Sex" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.sex))"></select>
<span asp-validation-for="Submission.Sex" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Yard" class="control-label"></label>
<select asp-for="Submission.Yard" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.yard))"></select>
<span asp-validation-for="Submission.Yard" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Grade" class="control-label"></label>
<select asp-for="Submission.Grade" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.grade))"></select>
<span asp-validation-for="Submission.Grade" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Major" class="control-label"></label>
<input asp-for="Submission.Major" class="form-control" />
<span asp-validation-for="Submission.Major" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Email" class="control-label"></label>
<input asp-for="Submission.Email" class="form-control" />
<span asp-validation-for="Submission.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Tel" class="control-label"></label>
<input asp-for="Submission.Tel" class="form-control" />
<span asp-validation-for="Submission.Tel" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Address" class="control-label"></label>
<input asp-for="Submission.Address" class="form-control" />
<span asp-validation-for="Submission.Address" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">返回列表</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@ -0,0 +1,57 @@
using _2021_backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Pages.Submissions
{
public class CreateModel : PageModel
{
private readonly _2021_backend.Data.BackendContext Context;
public CreateModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
public IActionResult OnGet()
{
Submission = new Submission();
return Page();
}
[BindProperty]
public Submission Submission { get; set; }
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var q = Context.Students.Where(stu => (stu.Name == Submission.Name || stu.Tel == Submission.Tel || stu.Stuid == Submission.Stuid));
Student stu;
if (q.Count() == 0)
{
stu = Student.create(Submission);
stu.Status = status.;
var q2 = from e in Context.Sessions select e.Guid;
var lst = q2.ToList();
stu.Timelist = lst;
Context.Students.Add(stu);
}
else
{
stu = q.FirstOrDefault();
stu.Update(Submission);
}
Submission.Host = stu.Guid;
Context.Submissions.Add(Submission);
Context.SaveChanges();
return RedirectToPage("./Index");
}
}
}

View File

@ -0,0 +1,76 @@
@page
@model _2021_backend.Pages.Submissions.DeleteModel
@{
ViewData["Title"] = "Delete";
}
<h1>删除</h1>
<h3>你确定要删除该项目吗?</h3>
<div>
<h4>提交记录</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Name)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Name)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Stuid)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Stuid)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Sex)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Sex)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Grade)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Grade)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Major)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Major)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Email)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Email)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Tel)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Tel)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Address)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Address)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.SubmitTime)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.SubmitTime)
</dd>
</dl>
<form method="post">
<input type="hidden" asp-for="Submission.Guid" />
<input type="submit" value="删除" class="btn btn-danger" asp-route-id="@Model.Submission.Guid.ToString()"/> |
<a asp-page="./Index">返回列表</a>
</form>
</div>

View File

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using _2021_backend.Data;
using _2021_backend.Models;
namespace _2021_backend.Pages.Submissions
{
public class DeleteModel : PageModel
{
private readonly _2021_backend.Data.BackendContext Context;
public DeleteModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
[BindProperty]
public Submission Submission { get; set; }
public async Task<IActionResult> OnGetAsync(string? strid)
{
Guid id = Guid.Parse(strid);
if (id == null)
{
return NotFound();
}
Submission = Context.Submissions.FirstOrDefault(m => m.Guid == id);
if (Submission == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(Guid? id)
{
if (id == null)
{
return NotFound();
}
Submission = Context.Submissions.Find(id);
if (Submission != null)
{
var stu = Context.Students.Find(Submission.Host);
if (stu != null)
{
stu.Submissions.Remove(Submission.Guid);
}
Context.Submissions.Remove(Submission);
Context.SaveChanges();
}
return RedirectToPage("./Index");
}
}
}

View File

@ -0,0 +1,79 @@
@page
@model _2021_backend.Pages.Submissions.DetailsModel
@{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>Submission</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Name)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Name)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Stuid)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Stuid)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Sex)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Sex)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Yard)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Yard)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Grade)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Grade)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Major)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Major)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Email)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Email)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Tel)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Tel)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.Address)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.Address)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Submission.SubmitTime)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Submission.SubmitTime)
</dd>
</dl>
</div>
<div>
<a asp-page="./Edit" asp-route-id="@Model.Submission.Guid">Edit</a> |
<a asp-page="./Index">返回列表</a>
</div>

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using _2021_backend.Data;
using _2021_backend.Models;
namespace _2021_backend.Pages.Submissions
{
public class DetailsModel : PageModel
{
private readonly _2021_backend.Data.BackendContext _context;
public DetailsModel(_2021_backend.Data.BackendContext context)
{
_context = context;
}
public Submission Submission { get; set; }
public async Task<IActionResult> OnGetAsync(string? strid)
{
if (strid == null)
{
return NotFound();
}
Guid id = Guid.Parse(strid);
Submission = await _context.Submissions.FirstOrDefaultAsync(m => m.Guid == id);
if (Submission == null)
{
return NotFound();
}
return Page();
}
}
}

View File

@ -0,0 +1,75 @@
@page
@model _2021_backend.Pages.Submissions.EditModel
@{
ViewData["Title"] = "Edit";
}
<h1>编辑详细信息</h1>
<h4>提交记录</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Submission.Guid" />
<div class="form-group">
<label asp-for="Submission.Name" class="control-label"></label>
<input asp-for="Submission.Name" class="form-control" />
<span asp-validation-for="Submission.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Stuid" class="control-label"></label>
<input asp-for="Submission.Stuid" class="form-control" />
<span asp-validation-for="Submission.Stuid" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Sex" class="control-label"></label>
<select asp-for="Submission.Sex" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.sex))"></select>
<span asp-validation-for="Submission.Sex" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Grade" class="control-label"></label>
<select asp-for="Submission.Grade" class="form-control" asp-items="@Html.GetEnumSelectList(typeof(_2021_backend.Models.grade))"></select>
<span asp-validation-for="Submission.Grade" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Major" class="control-label"></label>
<input asp-for="Submission.Major" class="form-control" />
<span asp-validation-for="Submission.Major" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Email" class="control-label"></label>
<input asp-for="Submission.Email" class="form-control" />
<span asp-validation-for="Submission.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Tel" class="control-label"></label>
<input asp-for="Submission.Tel" class="form-control" />
<span asp-validation-for="Submission.Tel" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.Address" class="control-label"></label>
<input asp-for="Submission.Address" class="form-control" />
<span asp-validation-for="Submission.Address" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Submission.SubmitTime" class="control-label"></label>
<input asp-for="Submission.SubmitTime" class="form-control" />
<span asp-validation-for="Submission.SubmitTime" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="./Index">返回列表</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using _2021_backend.Data;
using _2021_backend.Models;
namespace _2021_backend.Pages.Submissions
{
public class EditModel : PageModel
{
public readonly _2021_backend.Data.BackendContext Context;
public EditModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
[BindProperty]
public Submission Submission { get; set; }
public async Task<IActionResult> OnGetAsync(string? strid)
{
Guid id = Guid.Parse(strid);
if (id == null)
{
return NotFound();
}
Submission = await Context.Submissions.FirstOrDefaultAsync(m => m.Guid == id);
if (Submission == null)
{
return NotFound();
}
return Page();
}
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
Context.Attach(Submission).State = EntityState.Modified;
try
{
await Context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!SubmissionExists(Submission.Guid))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool SubmissionExists(Guid id)
{
return Context.Submissions.Any(e => e.Guid == id);
}
}
}

View File

@ -0,0 +1,95 @@
@page
@model _2021_backend.Pages.Submissions.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>全部提交记录</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Submission[0].Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Submission[0].Stuid)
</th>
<th>
@Html.DisplayNameFor(model => model.Submission[0].Sex)
</th>
<th>
@Html.DisplayNameFor(model => model.Submission[0].Grade)
</th>
<th>
@Html.DisplayNameFor(model => model.Submission[0].Major)
</th>
<th>
@Html.DisplayNameFor(model => model.Submission[0].Email)
</th>
<th>
@Html.DisplayNameFor(model => model.Submission[0].Tel)
</th>
<th>
@Html.DisplayNameFor(model => model.Submission[0].Address)
</th>
<th>
@Html.DisplayNameFor(model => model.Submission[0].SubmitTime)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Submission)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Stuid)
</td>
<td>
@Html.DisplayFor(modelItem => item.Sex)
</td>
<td>
@Html.DisplayFor(modelItem => item.Grade)
</td>
<td>
@Html.DisplayFor(modelItem => item.Major)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.DisplayFor(modelItem => item.Tel)
</td>
<td>
@Html.DisplayFor(modelItem => item.Address)
</td>
<td>
@Html.DisplayFor(modelItem => item.SubmitTime)
</td>
<td>
<a asp-page="./Edit" asp-route-strid="@item.Guid.ToString()">编辑</a> |
<a asp-page="./Details" asp-route-strid="@item.Guid.ToString()">详细信息</a> |
<a asp-page="./Delete" asp-route-strid="@item.Guid.ToString()">删除</a>
</td>
</tr>
}
</tbody>
</table>
<nav>
<ul class="pagination">
<li class="page-item @(Model.PageId==0 ? "disabled" : "")"><a class="page-link" asp-route-pageId="@(Model.PageId-1) ">Prev</a></li>
@for (int i = 0; i < Model.PageCount; i++)
{
<li class="page-item @(Model.PageId==i ? "active" : "")"><a class="page-link" asp-route-pageId="@i">@i</a></li>
}
<li class="page-item @(Model.PageId>=Model.PageCount -1? "disabled" : "")"><a class="page-link" asp-route-pageId="@(Model.PageId+1)" >Next</a></li>
</ul>
</nav>

View File

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using _2021_backend.Data;
using _2021_backend.Models;
namespace _2021_backend.Pages.Submissions
{
public class IndexModel : PageModel
{
private readonly _2021_backend.Data.BackendContext Context;
public static int PageSize = 30;
public int PageCount { get; set; }
public int PageId { get; set; }
public IndexModel(_2021_backend.Data.BackendContext context)
{
Context = context;
}
public List<Submission> Submission { get;set; }
public async Task OnGetAsync(int pageId)
{
var q = from e in Context.Submissions orderby e.SubmitTime select e;
Submission = await q.ToListAsync();
Submission.Sort((a,b)=>b.SubmitTime.CompareTo(a.SubmitTime));
int cnt = Submission.Count;
PageCount = (int)Math.Ceiling((double)cnt / (double)PageSize);
if (pageId >= PageCount) pageId = PageCount - 1;
if (pageId < 0) pageId = 0;
PageId = (int)pageId;
int count = (PageId + 1) * PageSize > cnt ? (cnt - PageId * PageSize) : PageSize;
Submission = Submission.GetRange(PageId * PageSize, count);
}
}
}

View File

@ -0,0 +1,49 @@
@page
@model _2021_backend.Pages.Users.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="NowUser.stuID" class="control-label"></label>
<input asp-for="NowUser.stuID" class="form-control" />
<span asp-validation-for="NowUser.stuID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="NowUser.Name" class="control-label"></label>
<input asp-for="NowUser.Name" class="form-control" />
<span asp-validation-for="NowUser.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="NowUser.Secret" class="control-label"></label>
<input asp-for="NowUser.Secret" class="form-control" />
<span asp-validation-for="NowUser.Secret" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="NowUser.isManager" /> @Html.DisplayNameFor(model => model.NowUser.isManager)
</label>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using _2021_backend.Data;
using _2021_backend.Models;
using Microsoft.EntityFrameworkCore;
namespace _2021_backend.Pages.Users
{
public class CreateModel : PageModel
{
private readonly _2021_backend.Data.BackendContext _context;
public IList<Submission> Record { get; set; }
public int PageCount { get; set; }
public int PageId { get; set; }
[BindProperty(SupportsGet =true,Name ="search")]
public string SearchString { get; set; }
public CreateModel(_2021_backend.Data.BackendContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public User NowUser { get; set; }
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
if (await _context.Users.AsNoTracking().Where(u => u.stuID == NowUser.stuID).FirstOrDefaultAsync() != null)
{
}
else
{
NowUser.Secret = Utils.EvaCryptoHelper.Password2Secret(NowUser.Secret);
_context.Users.Add(NowUser);
await _context.SaveChangesAsync();
}
return RedirectToPage("./Index");
}
}
}

View File

@ -0,0 +1,41 @@
@page
@model _2021_backend.Pages.Users.DeleteModel
@{
ViewData["Title"] = "Delete";
}
<h1>Delete</h1>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>User</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.User.stuID)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.User.stuID)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.User.Name)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.User.Name)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.User.isManager)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.User.isManager)
</dd>
</dl>
<form method="post">
<input type="hidden" asp-for="User.Guid" />
<input type="submit" value="Delete" class="btn btn-danger" /> |
<a asp-page="./Index">Back to List</a>
</form>
</div>

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using _2021_backend.Data;
using _2021_backend.Models;
namespace _2021_backend.Pages.Users
{
public class DeleteModel : PageModel
{
private readonly _2021_backend.Data.BackendContext _context;
public DeleteModel(_2021_backend.Data.BackendContext context)
{
_context = context;
}
[BindProperty]
public new User User { get; set; }
public async Task<IActionResult> OnGetAsync(string id)
{
Guid guid = Guid.Parse(id);
if (id == null)
{
return NotFound();
}
User = _context.Users.Find(guid);
if (User == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(string id)
{
Guid guid = Guid.Parse(id);
if (id == null)
{
return NotFound();
}
User = _context.Users.Find(id);
if (User != null)
{
_context.Users.Remove(User);
await _context.SaveChangesAsync();
}
return RedirectToPage("./Index");
}
}
}

View File

@ -0,0 +1,43 @@
@page
@model _2021_backend.Pages.Users.DetailsModel
@{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>User</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.User.stuID)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.User.stuID)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.User.Name)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.User.Name)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.User.Secret)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model=>model.SECRET)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.User.isManager)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.User.isManager)
</dd>
</dl>
</div>
<div>
<a asp-page="./Edit" asp-route-id="@Model.User.Guid">Edit</a> |
<a asp-page="./Index">Back to List</a>
</div>

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using _2021_backend.Data;
using _2021_backend.Models;
namespace _2021_backend.Pages.Users
{
public class DetailsModel : PageModel
{
private readonly _2021_backend.Data.BackendContext _context;
public DetailsModel(_2021_backend.Data.BackendContext context)
{
_context = context;
}
public string SECRET = "EVa N13 @!@";
public new User User { get; set; }
public async Task<IActionResult> OnGetAsync(string id)
{
Guid guid = Guid.Parse(id);
if (id == null)
{
return NotFound();
}
User = _context.Users.Find(guid);
if (User == null)
{
return NotFound();
}
return Page();
}
}
}

View File

@ -0,0 +1,50 @@
@page
@model _2021_backend.Pages.Users.EditModel
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>User</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="USER.Guid" />
<div class="form-group">
<label asp-for="USER.stuID" class="control-label"></label>
<input asp-for="USER.stuID" class="form-control" />
<span asp-validation-for="USER.stuID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="USER.Name" class="control-label"></label>
<input asp-for="USER.Name" class="form-control" />
<span asp-validation-for="USER.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="USER.Secret" class="control-label"></label>
<input asp-for="USER.Secret" class="form-control" />
<span asp-validation-for="USER.Secret" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="USER.isManager" /> @Html.DisplayNameFor(model => model.USER.isManager)
</label>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using _2021_backend.Data;
using _2021_backend.Models;
namespace _2021_backend.Pages.Users
{
public class EditModel : PageModel
{
private readonly _2021_backend.Data.BackendContext _context;
public EditModel(_2021_backend.Data.BackendContext context)
{
_context = context;
}
[BindProperty]
public new User USER { get; set; }
private string _secret { get; set; }
public async Task<IActionResult> OnGetAsync(string? id)
{
if (id == null)
{
return NotFound();
}
Guid guid = Guid.Parse(id);
USER = _context.Users.Find(guid);
if (USER == null)
{
return NotFound();
}
_secret = USER.Secret;
USER.Secret = string.Empty;
return Page();
}
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
if (await _context.Users.AsNoTracking().Where(u => u.stuID == USER.stuID).CountAsync() > 0
&& (await _context.Users.AsNoTracking().Where(u => u.stuID == USER.stuID).FirstOrDefaultAsync()).Guid != USER.Guid
)
return new ConflictResult();
if (USER.Secret == null || USER.Secret == String.Empty)
{
var user = await _context.Users.AsNoTracking().Where(u => u.Guid == USER.Guid).FirstOrDefaultAsync();
user.Name = USER.Name;
user.stuID = USER.stuID;
user.isManager = USER.isManager;
_context.Attach(user).State = EntityState.Modified;
}
else
{
var user = await _context.Users.AsNoTracking().Where(u => u.Guid == USER.Guid).FirstOrDefaultAsync();
user.Name = USER.Name;
user.stuID = USER.stuID;
user.isManager = USER.isManager;
user.Secret = Utils.EvaCryptoHelper.Password2Secret(USER.Secret);
_context.Attach(user).State = EntityState.Modified;
}
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!UserExists(USER.Guid))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool UserExists(Guid id)
{
return _context.Users.Any(e => e.Guid == id);
}
}
}

View File

@ -0,0 +1,50 @@
@page
@model _2021_backend.Pages.Users.IndexModel
@{
ViewData["Title"] = "Index";
}
<h4>用户管理</h4>
<p>
<a asp-page="Create">新加一个好兄弟</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.User[0].stuID)
</th>
<th>
@Html.DisplayNameFor(model => model.User[0].Name)
</th>
<th>
@Html.DisplayNameFor(model => model.User[0].isManager)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.User) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.stuID)
</td>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.isManager)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Guid">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Guid">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Guid">Delete</a>
</td>
</tr>
}
</tbody>
</table>

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using _2021_backend.Data;
using _2021_backend.Models;
namespace _2021_backend.Pages.Users
{
public class IndexModel : PageModel
{
private readonly _2021_backend.Data.BackendContext _context;
public IndexModel(_2021_backend.Data.BackendContext context)
{
_context = context;
}
public string SECRET = "EVa N13 @!@";
public new IList<User> User { get;set; }
public async Task OnGetAsync()
{
User = await _context.Users.ToListAsync();
}
}
}

View File

@ -0,0 +1,3 @@
@using _2021_backend
@namespace _2021_backend.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

78
Program.cs 100644
View File

@ -0,0 +1,78 @@
using _2021_backend.Data;
using _2021_backend.Models;
using _2021_backend.Utils;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using System;
using System.Linq;
namespace _2021_backend
{
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<BackendContext>();
context.Database.Migrate();
var config = host.Services.GetRequiredService<IConfiguration>();
TencentSMS.Init(config["TENCENT_ID"], config["TENCENT_KEY"], config["SMS_APPID"], config["SMS_ID_ACCEPT"], config["SMS_ID_REJECT"], config["SMS_ID_TIMESET"], config["SMS_ID_SUBMITTED"], config["SMS_ID_TIMESELECT"]);
var botname = config["SMSBOT_NAME"];
var q = context.Users.Where(it => it.Name == botname);
if (q.Count() == 0)
{
var botusr = new User();
botusr.Name = botname;
botusr.Guid = Guid.NewGuid();
botusr.isManager = true;
botusr.Secret = config["SMSBOT_SECRET"];
botusr.stuID = config["SMSBOT_STUID"];
User.Bot = botusr;
context.Users.Add(botusr);
}
else
{
User.Bot = q.FirstOrDefault();
//do nothing cause I 've already got a bot
}
var id = Guid.Parse("4c20c535-3661-40c7-b4db-ce479675bbd7");
while (context.Users.Any(e => e.Guid == id))
{
context.Users.Remove(context.Users.Find(id));
context.SaveChanges();
}
var usr = new User();
usr.Guid = id;
usr.Name = config["ADMIN_USERNAME"];
usr.isManager = true;
usr.Secret = EvaCryptoHelper.Password2Secret(config["ADMIN_PASSWORD"]);
usr.stuID = "zjueva";
Console.WriteLine(usr.Guid.ToString());
context.Users.Add(usr);
context.SaveChanges();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

View File

@ -0,0 +1,34 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:4000",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"_2021_backend": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:4001;http://localhost:4000"
},
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
"publishAllPorts": true,
"useSSL": true
}
}
}

111
Startup.cs 100644
View File

@ -0,0 +1,111 @@
using _2021_backend.Data;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Security.Claims;
namespace _2021_backend
{
public class Startup
{
//
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
#if DEBUG
Configuration["X-Real-IP"] = "10.10.10.10";
Configuration["DB_HOST"] = "localhost";
Configuration["DB_NAME"] = "jphd_db";
Configuration["DB_USER"] = "jphd";
Configuration["DB_PASSWORD"] = "jphdtest";
Configuration["ADMIN_USERNAME"] = "zjueva";
Configuration["ADMIN_PASSWORD"] = "a";
#endif
if (Configuration["DB_PORT"] == string.Empty)
Configuration["DB_PORT"] = "5432";
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>()
.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin();
});
}).AddAuthentication(options =>
{
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}
)
.AddCookie(options =>
{
options.AccessDeniedPath = "/Account/AccessDenied";
options.LoginPath = "/Account/Login";
options.LogoutPath = "/Account/Logout";
}
);
services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy => policy.RequireClaim(ClaimTypes.Role, "admin"));
options.AddPolicy("ManagerAndHigher", policy => policy.RequireClaim(ClaimTypes.Role, "admin", "manager"));
});
services.AddRazorPages(options =>
{
options.Conventions.AllowAnonymousToFolder("/Account");
options.Conventions.AllowAnonymousToPage("/api/submit");
options.Conventions.AllowAnonymousToPage("/api/sessionlist");
options.Conventions.AuthorizeFolder("/Submissions");
options.Conventions.AuthorizeFolder("/Students");
options.Conventions.AuthorizeFolder("/Result");
options.Conventions.AuthorizeFolder("/Sessions");
options.Conventions.AuthorizeFolder("/Message");
options.Conventions.AuthorizeFolder("/Users", "ManagerAndHigher");
options.Conventions.AllowAnonymousToPage("/Privacy");
});
services.AddDbContext<BackendContext>(options =>
options.UseNpgsql($"Host={Configuration["DB_HOST"]};Port={Configuration["DB_PORT"]};Database={Configuration["DB_NAME"]};Username={Configuration["DB_USER"]};Password={Configuration["DB_PASSWORD"]}"));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseCors();
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
});
}
}
}

View File

@ -0,0 +1,49 @@
using _2021_backend.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading.Tasks;
namespace _2021_backend.Utils
{
public abstract class ResponseDto
{
[DataMember]
public string Status;
}
[DataContract]
public class SuccessResponseDto : ResponseDto
{
[DataMember]
public new string Status { get; set; }
[DataMember(EmitDefaultValue = false)]
public object Data { get; set; }
public SuccessResponseDto()
{
Status = "success";
}
}
[DataContract]
public class ErrorResponseDto : ResponseDto
{
[DataMember]
public new string Status { get; set; }
[DataMember(EmitDefaultValue = false)]
public string ErrorMsg { get; set; }
public ErrorResponseDto()
{
Status = "error";
}
}
public static class ApiResponse
{
public static SuccessResponseDto Success(object data) => new SuccessResponseDto { Data = data };
public static ErrorResponseDto Error(string errorMsg) => new ErrorResponseDto { ErrorMsg = errorMsg };
public static ErrorResponseDto Error(string errorMsg, status stat)
{
return new ErrorResponseDto { ErrorMsg = errorMsg, Status = Enum.GetName(typeof(status), stat) };
}
}
}

112
Utils/Arranger.cs 100644
View File

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;
using _2021_backend.Data;
using _2021_backend.Models;
using System.IO;
using System.Threading.Tasks;
namespace _2021_backend.Utils
{
public class Arranger
{
static BackendContext Context;
static List<Student> students;
static List<Session> sessions;
public static bool Arrange(BackendContext context)
{
Context = context;
students = context.Students.Where(it => it.Status != status. && it.Status != status. && it.Timelist.Count != 0 && it.InterviewTime == Guid.Empty && it.Status != status.).OrderBy(it => it.Timelist.Count).ToList();
sessions = context.Sessions.OrderBy(it => it.Day).ThenByDescending(it => it.Capacity - it.Students.Count).ThenBy(it => it.BeginTime).ThenBy(it => it.Place).ToList();
students.Sort((Student a, Student b) =>
{
var capa = 0;
var capb = 0;
foreach (var tm in a.Timelist)
{
var t = sessions.Find(x => x.Guid == tm);
capa += t.Capacity - t.Students.Count;
}
foreach (var tm in b.Timelist)
{
var t = sessions.Find(x => x.Guid == tm);
capb += t.Capacity - t.Students.Count;
}
return capa - capb;
});
#if DEBUG
var str = "";
foreach(var st in students)
{
var cap = 0;
var tmstr = "";
foreach (var tm in st.Timelist)
{
var t = sessions.Find(x => x.Guid == tm);
cap += t.Capacity - t.Students.Count;
tmstr += t.Day.ToString("dd") + "-" + t.BeginTime.ToString("HH:mm-") + t.Place + " ";
}
str += st.Name + "\t" + st.Timelist.Count.ToString() + "\t" + cap.ToString() + "\t"+ tmstr+ "\n";
}
File.WriteAllText("./students.txt", str);
#endif
var res = DFS(0);
context.SaveChanges();
return res;
}
static bool DFS(int m)
{
if (m >= students.Count) return true;
var lst = students[m].Timelist;
var stu = students[m];
if (stu.Timelist.Contains(stu.InterviewTime) || stu.Timelist.Count() == 0 || stu.InterviewTime != Guid.Empty || stu.Status != status.)
{
return m >= students.Count - 1 ? true : DFS(m + 1);
}
else
{
var tm = Context.Sessions.Find(stu.InterviewTime);
if (tm != null)
{
tm.Students.RemoveAll(it => it == stu.Guid);
}
stu.InterviewTime = Guid.Empty;
}
bool depth = false;
foreach (var i in lst)
{
var tm = sessions.Find(s => s.Guid == i);
if (tm.Students.Count < tm.Capacity && tm.Day.CompareTo(DateTime.Now.AddHours(-14)) > 0)
{
status prev = students[m].Status;
Guid prevs = students[m].InterviewTime;
students[m].Status = status.;
students[m].InterviewTime = tm.Guid;
tm.Students.Add(students[m].Guid);
if (m == students.Count - 1)
{
return true;
}
else
{
depth = true;
if (!DFS(m + 1))
{
students[m].Status = prev;
students[m].InterviewTime = prevs;
tm.Students.Remove(students[m].Guid);
continue;
}
else return true;
}
}
}
if (!depth) Console.WriteLine("Unable to find an arrangement. Stack trace:");
Console.WriteLine(stu.Name + " " + stu.Stuid);
return false;
}
}
}

View File

@ -0,0 +1,85 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace _2021_backend.Utils
{
public static class EvaClaimTypes
{
public const string IsManager = "IsManager";
}
public static class LoginHelper
{
public static string PostMoths(string url, object obj_model)
{
string param = JsonConvert.SerializeObject(obj_model);
System.Net.HttpWebRequest request;
request = (System.Net.HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/json;charset=UTF-8";
/* if (dic != null && dic.Count != 0)
{
foreach (var item in dic)
{
request.Headers.Add(item.Key, item.Value);
}
}*/
byte[] payload;
payload = System.Text.Encoding.UTF8.GetBytes(param);
request.ContentLength = payload.Length;
string strValue = "";
try
{
Stream writer = request.GetRequestStream();
writer.Write(payload, 0, payload.Length);
writer.Close();
System.Net.HttpWebResponse response;
response = (System.Net.HttpWebResponse)request.GetResponse();
System.IO.Stream s;
s = response.GetResponseStream();
string StrDate = "";
StreamReader Reader = new StreamReader(s, Encoding.UTF8);
while ((StrDate = Reader.ReadLine()) != null)
{
strValue += StrDate;
}
}
catch (Exception e)
{
strValue = e.Message;
}
return strValue;
}
}
public static class EvaCryptoHelper
{
public static string SHA1(string content)
{
try
{
using (var sha1 = new SHA1CryptoServiceProvider())
{
byte[] bytes_in = Encoding.UTF8.GetBytes(content);
byte[] bytes_out = sha1.ComputeHash(bytes_in);
string result = BitConverter.ToString(bytes_out);
result = result.Replace("-", "");
return result;
}
}
catch (Exception)
{
return string.Empty;
}
}
public static string Password2Secret(string password)
{
return EvaCryptoHelper.SHA1("W5D1" + EvaCryptoHelper.SHA1("EVa" + password + "n13@!@") + "D1X1AnsH3ng");
}
}
}

View File

@ -0,0 +1,75 @@
using _2021_backend.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace _2021_backend.Utils
{
public class DateHelper
{
public static bool CheckDate()
{
if (DateTime.Now.CompareTo(new DateTime(2021, 9, 28)) < 0) return true;
return false;
}
public static string GetDay(int day)
{
switch (day)
{
case 1:
return "24日";
case 2:
return "25日";
case 3:
return "26日";
case 4:
return "27日";
case 5:
return "28日";
case 6:
return "29日";
case 7:
return "30日";
default:
return "暂无";
}
}
public static string GetGrade(int grade)
{
switch (grade)
{
case 1:
return "大一";
case 2:
return "大二";
case 3:
return "大三";
case 4:
return "大四";
default:
return "暂缺";
}
}
public static string GetEtc(int etc)
{
switch (etc)
{
case 1:
return "第一场";
case 2:
return "第二场";
case 3:
return "第三场";
case 4:
return "第四场";
case 5:
return "第五场";
default:
return "暂无";
}
}
}
}

168
Utils/TencentSMS.cs 100644
View File

@ -0,0 +1,168 @@
using _2021_backend.Data;
using _2021_backend.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using TencentCloud.Common;
using TencentCloud.Common.Profile;
using TencentCloud.Sms.V20210111;
using TencentCloud.Sms.V20210111.Models;
namespace _2021_backend.Utils
{
public class TencentSMS
{
public static string Tencent_id { get; set; }
public static string Tencent_key { get; set; }
public static string SMS_appid { get; set; }
public static string SMSID_accept { get; set; }
public static string SMSID_reject { get; set; }
public static string SMSID_timeSet { get; set; }
public static string SMSID_signed { get; set; }
private static bool Initialized = false;
private static string SMSID_timeSelect { get; set; }
public static void Init(string tencentid, string tencentKey, string appid, string ID_accept, string ID_reject, string ID_timeSet, string ID_submitted, string ID_timeSelect)
{
Tencent_id = tencentid;
Tencent_key = tencentKey;
SMS_appid = appid;
SMSID_accept = ID_accept;
SMSID_reject = ID_reject;
SMSID_timeSet = ID_timeSet;
SMSID_signed = ID_submitted;
SMSID_timeSelect = ID_timeSelect;
Initialized = true;
}
public static async Task<bool> Pull(BackendContext Context, Student stu, bool fullPull)
{
if (!Initialized) return false;
try
{
Credential cred = new Credential
{
SecretId = Tencent_id,
SecretKey = Tencent_key
};
ClientProfile clientProfile = new ClientProfile();
HttpProfile httpProfile = new HttpProfile();
httpProfile.Endpoint = ("sms.tencentcloudapi.com");
clientProfile.HttpProfile = httpProfile;
SmsClient client = new SmsClient(cred, "ap-nanjing", clientProfile);
PullSmsReplyStatusByPhoneNumberRequest req = new PullSmsReplyStatusByPhoneNumberRequest();
//var it = Context.SMS.Find(stu.Messages.LastOrDefault()).SendTime;
req.BeginTime = (ulong)DateTimeOffset.UtcNow.AddDays(-5).ToUnixTimeSeconds();
req.EndTime = (ulong)DateTimeOffset.UtcNow.AddSeconds(-1).ToUnixTimeSeconds();
req.Offset = 0;
req.Limit = 100;
req.PhoneNumber = "+86" + stu.Tel;
req.SmsSdkAppId = SMS_appid;
foreach (var msg in stu.Messages)
{
var sms = Context.SMS.Find(msg);
if (sms.SendTime.CompareTo(DateTime.Now.AddDays(-5)) > 0)
{
stu.Messages.Remove(msg);
Context.SMS.Remove(sms);
}
}
Context.SaveChanges();
PullSmsReplyStatusByPhoneNumberResponse resp = client.PullSmsReplyStatusByPhoneNumberSync(req);
var str = AbstractModel.ToJsonString(resp);
Console.WriteLine(resp);
SMSResponseDto obj = JsonSerializer.Deserialize<SMSResponseDto>(str, new JsonSerializerOptions { PropertyNameCaseInsensitive = false });
var lst = obj.PullSmsReplyStatusSet;
foreach (var item in lst)
{
var msg = new SMS(item, stu.Guid);
Context.Add<SMS>(msg);
stu.Messages.Add(msg.Guid);
}
Context.SaveChanges();
return true;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return false;
}
}
public static async Task<bool> Send(BackendContext Context, SMSType type, Student stu, string sender)
{
if (!Initialized) return false;
try
{
Credential cred = new Credential
{
SecretId = Tencent_id,
SecretKey = Tencent_key
};
ClientProfile cp = new ClientProfile();
HttpProfile hp = new HttpProfile();
hp.Endpoint = ("sms.tencentcloudapi.com");
cp.HttpProfile = hp;
SmsClient client = new SmsClient(cred, "ap-nanjing", cp);
SendSmsRequest req = new SendSmsRequest();
req.PhoneNumberSet = new string[] { "" };
req.PhoneNumberSet[0] = "+86" + stu.Tel;
req.SmsSdkAppId = SMS_appid;
req.SignName = "ZJUEVA";
Guid index = stu.InterviewTime;
SMS sms = new SMS();
switch (type)
{
case SMSType.Accept:
sms.Type = SMSType.Accept;
req.TemplateId = SMSID_accept;
req.TemplateParamSet = new string[] { stu.Name };
break;
case SMSType.Reject:
sms.Type = SMSType.Reject;
req.TemplateId = SMSID_reject;
req.TemplateParamSet = new string[] { stu.Name };
break;
case SMSType.TimeSelect:
sms.Type = SMSType.TimeSelect;
req.TemplateId = SMSID_timeSelect;
req.TemplateParamSet = new string[] { stu.Name, stu.Stuid };
break;
case SMSType.TimeSet:
sms.Type = SMSType.TimeSet;
var q = from e in Context.Sessions where e.Guid == index select e;
var time = await q.FirstOrDefaultAsync();
req.TemplateParamSet = new string[] { stu.Name, time.Day.ToString("MM-dd") + " " + time.BeginTime.ToString("HH:mm"), time.Place };
req.TemplateId = SMSID_timeSet;
break;
case SMSType.Signed:
sms.Type = SMSType.Signed;
req.TemplateParamSet = new string[] { stu.Name, stu.Stuid };
req.TemplateId = SMSID_signed;
break;
}
sms.Tel = stu.Tel;
sms.Host = stu.Guid;
var query = from e in Context.Users where e.stuID == sender select e;
var usr = await query.FirstOrDefaultAsync();
sms.Sender = usr == null ? "null" : usr.Name;
sms.Data = req.TemplateParamSet.ToList<string>();
SendSmsResponse resp = client.SendSmsSync(req);
Console.WriteLine(AbstractModel.ToJsonString(resp));
Context.Add(sms);
Context.SaveChanges();
return true;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return false;
}
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

23
appsettings.json 100644
View File

@ -0,0 +1,23 @@
{
"AllowedHosts": "*",
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ADMIN_USERNAME": "zjueva",
"ADMIN_PASSWORD": "a",
"SMS_APPID": "1400562126",
"SMS_ID_ACCEPT": "1089597",
"SMS_ID_REJECT": "1089595",
"SMS_ID_SUBMITTED": "1089587",
"SMS_ID_TIMESET": "1131089",
"SMS_ID_TIMESELECT": "1131090",
"TENCENT_ID": "AKIDYv5JGwKSJtCE0VjhOpyqSotgDTSaYIsF",
"TENCENT_KEY": "mPzSimdGenpdCWcT5TcWBboreAQQ9bmh",
"SMSBOT_NAME": "msgbot",
"SMSBOT_SECRET": "msgbotAenpdCWcT5",
"SMSBOT_STUID": "114514666"
}

View File

@ -0,0 +1 @@
[{"Guid":"58972a75-4ed3-48fe-a767-d01f79365642","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T19:30:00","Place":"204","Chiefs":[],"Capacity":5,"SendSMS":false,"Students":["74b1c82d-c9d0-4a5a-935c-f793b07c4e08","ddff5cc4-359c-4048-bbaa-97f685c15de4","e33db63d-fba4-4bf1-9557-388a52d19d7c","e5845df4-e85c-4a1f-8e27-8a52b75a3249","e662636c-1a0a-4743-86ab-fd782d070338"]},{"Guid":"9df79c51-927a-4f92-a96b-cb0964b38888","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T18:30:00","Place":"200","Chiefs":[],"Capacity":10,"SendSMS":false,"Students":["4fd5dc6b-e5d9-4cec-b018-2a5a95224625","9f16f687-7501-4586-8bee-8fe261663b1a","aeb3c3d7-bf7b-445e-9a83-78a6c7b77e99","b595a0a9-0f2e-4173-be66-c6505627b812","bce57baa-d603-4707-a886-3dde8bb8a9b8","c1159c36-a25a-4fd9-b2df-fa5d32a80bc4","c194bb19-6a47-4291-a710-4a9de1d7704b","c600ab43-d83b-473d-a994-980c11ec04ad","16515a4e-609f-4180-aff8-de78de16bd1f","1a5a891c-430a-4c40-a762-7f911c236f67"]},{"Guid":"9ffe792f-2ca8-4a5d-a324-7df90eb466b7","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T18:30:00","Place":"204","Chiefs":[],"Capacity":10,"SendSMS":false,"Students":["1f053368-3f2f-404a-b5a7-ad0ca1e11303","32f739d6-688d-4589-9a7b-28518488b416","36f4c4bd-565a-4b2a-91e9-59673274654a","38057670-0ff7-48a6-bbcf-660ad020ea01","49d9257b-46e2-4457-a557-6290a80cd183","4b3a3857-ae4a-4b2b-896a-7f6c12432734","4b5277b2-c902-4f2c-a495-dfe962fccd57","cd14f3a4-59a0-4585-afe2-3c2a35308a26","694b8e51-3a15-4430-8743-91d22a5b252b","69fd8b07-a166-40c8-88be-b7681800d72e"]},{"Guid":"db86a266-8716-46c8-9134-82b6ef616bbc","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T20:30:00","Place":"200","Chiefs":[],"Capacity":10,"SendSMS":false,"Students":["ed6de5a9-52c4-41b4-be1d-eebd69c03427","f3197a78-3986-4a96-a473-164588f16500","f7122b98-7e01-4c4f-8bbc-dace4d8a28f8","f7a43695-b492-467b-b7a4-672d4e91b8b5"]},{"Guid":"f3f4f185-ca37-44fe-896c-35ae0f408b81","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T19:30:00","Place":"200","Chiefs":[],"Capacity":5,"SendSMS":false,"Students":["81e3b732-4f80-472c-989f-ccb372cff1d1","8e5dd4a6-5460-4857-ae03-eb1f9f4e7de7","5104ce03-66f1-441e-8f04-d3f908c27c53","6afefe68-7845-4f91-84b2-dd52714cbe8a","702e7de5-12cc-4143-9a7e-ed099610d906"]},{"Guid":"f5621221-5222-47ad-bd3e-414a28848427","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T20:30:00","Place":"204","Chiefs":[],"Capacity":10,"SendSMS":false,"Students":[]}]

View File

@ -0,0 +1 @@
[{"Guid":"9ffe792f-2ca8-4a5d-a324-7df90eb466b7","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T18:30:00","Place":"204","Chiefs":[],"Capacity":10,"SendSMS":false,"Students":["1f053368-3f2f-404a-b5a7-ad0ca1e11303","32f739d6-688d-4589-9a7b-28518488b416","36f4c4bd-565a-4b2a-91e9-59673274654a","38057670-0ff7-48a6-bbcf-660ad020ea01","49d9257b-46e2-4457-a557-6290a80cd183","4b3a3857-ae4a-4b2b-896a-7f6c12432734","4b5277b2-c902-4f2c-a495-dfe962fccd57","cd14f3a4-59a0-4585-afe2-3c2a35308a26","694b8e51-3a15-4430-8743-91d22a5b252b","69fd8b07-a166-40c8-88be-b7681800d72e"]},{"Guid":"db86a266-8716-46c8-9134-82b6ef616bbc","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T20:30:00","Place":"200","Chiefs":[],"Capacity":10,"SendSMS":false,"Students":["ed6de5a9-52c4-41b4-be1d-eebd69c03427","f3197a78-3986-4a96-a473-164588f16500","f7122b98-7e01-4c4f-8bbc-dace4d8a28f8","f7a43695-b492-467b-b7a4-672d4e91b8b5"]},{"Guid":"f3f4f185-ca37-44fe-896c-35ae0f408b81","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T19:30:00","Place":"200","Chiefs":[],"Capacity":5,"SendSMS":false,"Students":["81e3b732-4f80-472c-989f-ccb372cff1d1","8e5dd4a6-5460-4857-ae03-eb1f9f4e7de7","5104ce03-66f1-441e-8f04-d3f908c27c53","6afefe68-7845-4f91-84b2-dd52714cbe8a","702e7de5-12cc-4143-9a7e-ed099610d906"]},{"Guid":"9df79c51-927a-4f92-a96b-cb0964b38888","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T18:30:00","Place":"200","Chiefs":[],"Capacity":10,"SendSMS":false,"Students":[]},{"Guid":"58972a75-4ed3-48fe-a767-d01f79365642","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T19:30:00","Place":"204","Chiefs":[],"Capacity":5,"SendSMS":false,"Students":["74b1c82d-c9d0-4a5a-935c-f793b07c4e08","ddff5cc4-359c-4048-bbaa-97f685c15de4","e33db63d-fba4-4bf1-9557-388a52d19d7c","e5845df4-e85c-4a1f-8e27-8a52b75a3249","e662636c-1a0a-4743-86ab-fd782d070338"]},{"Guid":"f5621221-5222-47ad-bd3e-414a28848427","Day":"2021-09-21T00:00:00","BeginTime":"2021-09-21T20:30:00","Place":"204","Chiefs":[],"Capacity":10,"SendSMS":false,"Students":[]}]

File diff suppressed because one or more lines are too long

0
students.txt 100644
View File

View File

@ -0,0 +1,119 @@
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */
a.navbar-brand {
white-space: normal;
text-align: center;
word-break: break-all;
}
/* Provide sufficient contrast against white background */
a {
color: #0366d6;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
/* Sticky footer styles
-------------------------------------------------- */
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
/* Sticky footer styles
-------------------------------------------------- */
html {
position: relative;
min-height: 100%;
}
body {
/* Margin bottom by footer height */
margin-bottom: 60px;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px; /* Vertically center the text there */
}
.table-submitted,
.table-submitted > th,
.table-submitted > td {
background-color: rgb(255 255 255 / 0.66);
}
.table-arranged,
.table-arranged > th,
.table-arranged > td {
background-color: rgb(255 216 63);
}
.table-rearrange,
.table-rearrange > th,
.table-rearrange > td {
background-color: rgb(255 157 63);
}
.table-confirmed,
.table-confirmed > th,
.table-confirmed > td {
background-color: rgb(215 162 247 / 0.74);
}
.table-interviewed,
.table-interviewed > th,
.table-interviewed > td {
background-color: rgb(0 27 117 / 0.67);
}
.table-accepted,
.table-accepted > th,
.table-accepted > td {
background-color: rgb(1 200 29 / 0.62);
}
.table-rejected,
.table-rejected > th,
.table-rejected > td {
background-color: rgb(200 0 0 / 0.58);
}
.text-red{
color:rgb(255,0,0);
}

BIN
wwwroot/favicon.ico 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -0,0 +1,4 @@
// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
// Write your Javascript code.

View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2011-2018 Twitter, Inc.
Copyright (c) 2011-2018 The Bootstrap Authors
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.

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More