Compare commits

...

60 Commits

Author SHA1 Message Date
yosheng 229dfbf5d1 Merge pull request 'develop' (#2) from develop into master
continuous-integration/drone/push Build is passing Details
Reviewed-on: #2
2023-10-06 10:31:16 +00:00
Yosheng 3253230f8d fix(CI): 修改数据库连线
continuous-integration/drone/pr Build is failing Details
2023-10-06 18:29:27 +08:00
Yosheng 3dfd6e1faf fix(CI): 返回原始删除配置, 目前手动删除 2023-10-06 18:20:54 +08:00
Yosheng 229de3b35a fix(CI): 返回原始删除配置, 目前手动删除 2023-10-06 18:20:36 +08:00
Yosheng 91e6fea106 fix(CI): 测试删除上次镜像
continuous-integration/drone/push Build is passing Details
2023-10-06 18:14:08 +08:00
Yosheng 752702f32e fix(CI): 测试删除上次镜像
continuous-integration/drone/push Build is passing Details
2023-10-06 18:12:29 +08:00
Yosheng 9531e71dfb fix(CI): 完善更换容器命令
continuous-integration/drone/push Build is passing Details
2023-10-06 17:21:44 +08:00
Yosheng 633c1ae5a8 fix(CI): 添加命令完成节点
continuous-integration/drone/push Build is passing Details
2023-10-06 17:14:27 +08:00
Yosheng eee1703356 fix(CI): plugins/docker 建议使用dockersock方式编译
continuous-integration/drone/push Build is passing Details
2023-10-06 17:04:32 +08:00
Yosheng 365b38a946 fix(CI): 尝试解决冗余镜像问题
continuous-integration/drone/push Build is passing Details
2023-10-06 16:58:39 +08:00
Yosheng 436f407da6 fix(CI): 调整docker run命令
continuous-integration/drone/push Build is passing Details
2023-10-06 16:48:53 +08:00
Yosheng 875c62217f fix(CI): 启用打包功能测试环境变量注入
continuous-integration/drone/push Build is passing Details
2023-10-06 16:45:11 +08:00
Yosheng 207d6edaba feat(Dockerfile): 添加连线字符串环境变量注入
continuous-integration/drone/push Build is passing Details
2023-10-06 16:41:21 +08:00
Yosheng 683e46aa55 fix(CI): 修复登入docker命令改为更安全的stdin
continuous-integration/drone/push Build is passing Details
2023-10-06 16:35:14 +08:00
Yosheng 59ae9c587c fix(CI): 测试ssh登入docker命令
continuous-integration/drone/push Build is passing Details
2023-10-06 16:29:22 +08:00
Yosheng 88f804538b fix(CI): 测试ssh登入docker命令
continuous-integration/drone/push Build is passing Details
2023-10-06 16:28:10 +08:00
Yosheng 574551de98 fix(CI): 测试ssh登入docker命令
continuous-integration/drone/push Build is passing Details
2023-10-06 16:26:18 +08:00
Yosheng 742cb0c10f fix(CI): 测试ssh换行命令
continuous-integration/drone/push Build is passing Details
2023-10-06 16:20:55 +08:00
Yosheng adee9af5ac fix(CI): 测试手动注入环境变量
continuous-integration/drone/push Build is passing Details
2023-10-06 16:18:36 +08:00
Yosheng 9dec9ceb79 fix(CI): 测试输出userame
continuous-integration/drone/push Build is passing Details
2023-10-06 15:56:04 +08:00
Yosheng 974c4e42f7 fix(CI): 测试添加docker登入方式
continuous-integration/drone/push Build is passing Details
2023-10-06 15:52:11 +08:00
Yosheng cddaa86ff2 fix(CI): 测试CI变量注入使用方式
continuous-integration/drone/push Build is passing Details
2023-10-06 15:40:54 +08:00
Yosheng c099e90c94 fix(CI): 测试调整环境变量注入方式
continuous-integration/drone/push Build is passing Details
2023-10-06 15:27:55 +08:00
Yosheng 6f8b04530d fix(CI): 调整部署命令
continuous-integration/drone/push Build is passing Details
2023-10-05 22:39:32 +08:00
Yosheng 06d3896228 fix(CI): 布署使用CI专属帐号
continuous-integration/drone/push Build is passing Details
2023-10-05 22:30:31 +08:00
Yosheng dbae3fbe2e fix(CI): 应用推送到Ubuntu
continuous-integration/drone/push Build encountered an error Details
2023-10-05 21:29:04 +08:00
Yosheng cde03b1615 fix(CI): 修复drone-ssh端口
continuous-integration/drone/push Build encountered an error Details
continuous-integration/drone Build is passing Details
2023-10-05 20:57:46 +08:00
Yosheng 82e4144b7a fix(CI): 启用测试
continuous-integration/drone/push Build encountered an error Details
continuous-integration/drone Build is failing Details
2023-10-03 22:20:57 +08:00
zhangyousheng 4d3b25c5e4 feat: 添加用户明细详情 2023-08-28 22:24:51 +08:00
zhangyousheng 20158c37d6 feat: 修该用户明细展示内容添加统计隐藏明细 2023-08-27 23:08:45 +08:00
zhangyousheng 32ea7191ee feat: Controller 统一添加api路由前坠 2023-08-27 17:36:10 +08:00
zhangyousheng ab9cd9f5b5 feat: 添加API Controller 2023-08-24 10:07:44 +08:00
zhangyousheng bb1a33824c fix(CI): 修改只有master可以触发并注释deploy节点 2023-08-23 20:39:44 +08:00
zhangyousheng a0b1bb7ace fix(CI): 调整drone-ssh使用官方
continuous-integration/drone/push Build encountered an error Details
2023-08-14 10:17:38 +08:00
zhangyousheng 0cb6db8622 fix(CI): 调整drone-ssh注释脚本
continuous-integration/drone/push Build encountered an error Details
2023-08-14 10:13:05 +08:00
zhangyousheng 1069c603d9 fix(CI): 调整drone-ssh添加明确版本
continuous-integration/drone/push Build encountered an error Details
2023-08-14 10:05:43 +08:00
zhangyousheng 53d47367b7 fix(CI): 调整drone-ssh配置
continuous-integration/drone/push Build encountered an error Details
2023-08-14 10:03:00 +08:00
zhangyousheng 93f213aaed fix(CI): 调整CI镜像
continuous-integration/drone/push Build encountered an error Details
2023-08-14 09:49:05 +08:00
zhangyousheng 18b8597876 fix(CI): 添加drone-ssh使用dockersock
continuous-integration/drone/push Build encountered an error Details
2023-08-14 09:35:04 +08:00
zhangyousheng 3fb73e4c14 fix(CI): 尝试明确指定ssh源
continuous-integration/drone/push Build encountered an error Details
2023-08-14 09:21:01 +08:00
zhangyousheng e78afba285 feat(CI): 添加环境变量参数及部署节点
continuous-integration/drone/push Build encountered an error Details
2023-08-06 08:29:54 +08:00
Yosheng 3d7fb11a13 fix(CI): 尝试移除 storage_driver
continuous-integration/drone/push Build is passing Details
2023-08-06 00:09:00 +08:00
Yosheng e2526d33d0 fix(CI): 修改帐号密码登入方式
continuous-integration/drone/push Build is passing Details
2023-08-06 00:03:59 +08:00
Yosheng a54e88f9d7 fix(CI): 移除build_args及custom_dns
continuous-integration/drone/push Build is failing Details
2023-08-05 21:19:16 +08:00
Yosheng 5402ce1d34 fix(CI): 尝试挂 docker.sock
continuous-integration/drone/push Build is failing Details
2023-08-05 21:13:53 +08:00
Yosheng 7173c9e093 fix(CI): 调整build_args参数
continuous-integration/drone/push Build was killed Details
2023-08-05 21:02:59 +08:00
Yosheng edf7a9a024 fix(CI): 尝试添加代理
continuous-integration/drone/push Build was killed Details
2023-08-05 20:55:44 +08:00
Yosheng 451dd07501 fix(CI): 添加dns
continuous-integration/drone/push Build was killed Details
2023-08-05 20:43:24 +08:00
Yosheng 6b33f4fa60 fix(CI): 添加docker build编译参数
continuous-integration/drone/push Build was killed Details
2023-08-05 20:35:53 +08:00
Yosheng 61a694c3b4 fix(CI): 添加镜像源下载
continuous-integration/drone/push Build was killed Details
2023-08-05 18:54:31 +08:00
Yosheng d0c1e6896e fix(CI): 拉取镜像错误
continuous-integration/drone/push Build was killed Details
2023-08-05 18:39:13 +08:00
Yosheng d3525884e8 feat(CI): 添加不存在则拉取
continuous-integration/drone/push Build is failing Details
2023-08-05 18:33:34 +08:00
Yosheng 582d45fbfa fix(CI): 修复验证判断Dockerfile方式
continuous-integration/drone Build is failing Details
2023-08-05 17:44:20 +08:00
Yosheng 9376c4b14e feat(CI): 测试推送到Nexus3
continuous-integration/drone Build is failing Details
2023-08-05 17:33:47 +08:00
Yosheng 8d75ec84e0 feat: 测试CI 2023-08-02 23:08:16 +08:00
Yosheng a2ad57e066 feat: 数据库中手机号可以为空 2023-07-30 21:41:49 +08:00
Yosheng a2dece29c8 feat: 手机号不是必填 2023-07-30 21:29:05 +08:00
zhangyousheng f2deb6ccd8 feat: 开发跟生产数据库分离 2023-07-30 20:23:08 +08:00
Yosheng 0c2371be7e fix: 修复Dockerfile及环境变量开发环境配置 2023-07-30 20:13:59 +08:00
zhangyousheng 71e9a40c07 feat: 添加打包配置 2023-07-30 16:37:08 +08:00
28 changed files with 459 additions and 46 deletions

69
.drone.yml 100644
View File

@ -0,0 +1,69 @@
kind: pipeline
type: docker
name: deployment
steps:
- name: check
image: alpine
commands:
- ls -la
- ls -la Dockerfile # 查看当前文件夹是否包含了Dockerfile
- name: publish
image: plugins/docker
settings:
username:
from_secret: nexus_username
password:
from_secret: nexus_password
pull: if-not-exists # 如果镜像不存在则拉取,免去每次都要重新下载
dockerfile: Dockerfile
tags: latest
# you need insecure: true since we don't have a TLS certificate
insecure: true
registry: 192.168.31.104:8082
repo: 192.168.31.104:8082/tiamo/user-point-management
volumes: # 将容器内目录挂载到宿主机仓库需要开启Trusted设置
- name: dockersock
path: /var/run/docker.sock
- name: deploy
pull: if-not-exists
image: appleboy/drone-ssh
environment:
Connection:
from_secret: connection
NEXUS_USER:
from_secret: nexus_username
NEXUS_PASSWORD:
from_secret: nexus_password
settings:
host: 192.168.31.225
port: 22
username: drone
password: dronepw
command_timeout: 2m
envs: [ NEXUS_USER, NEXUS_PASSWORD ]
script:
- echo $NEXUS_PASSWORD | docker login -u $NEXUS_USER --password-stdin 192.168.31.104:8082
- docker pull 192.168.31.104:8082/tiamo/user-point-management
- echo 开始停止容器
- docker stop user-point-management
- echo 开始强制清除停止容器
- docker container prune -f
- echo 开始清除镜像
- docker image prune -f
- echo 开始标签镜像
- docker tag 192.168.31.104:8082/tiamo/user-point-management tiamo/user-point-management:latest
- echo 开始运行容器
- docker run --name user-point-management -d -p 29029:5000
-e Connection__UserPointManagement="Server=192.168.31.225;Port=5432;UserId=postgres;Password=postgres;Database=tiamo;"
tiamo/user-point-management
- echo 执行完成
volumes:
- name: dockersock
host:
path: /var/run/docker.sock
trigger:
branch:
- master

26
Dockerfile 100644
View File

@ -0,0 +1,26 @@
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /docker
EXPOSE 5000
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /build
COPY . .
RUN dotnet restore src/UserPointManagement.Web/UserPointManagement.Web.csproj --configfile ./NuGet.Config
WORKDIR src/UserPointManagement.Web
RUN dotnet build UserPointManagement.Web.csproj -c Release
FROM build AS publish
RUN dotnet publish UserPointManagement.Web.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENV ASPNETCORE_URLS http://*:5000
ENV TZ Asia/Shanghai
ENV Connection__UserPointManagement=""
ENTRYPOINT ["dotnet", "UserPointManagement.Web.dll"]

7
NuGet.Config 100644
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="azure" value="https://nuget.cdn.azure.cn/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>

1
README.md 100644
View File

@ -0,0 +1 @@
## 会员积分管理系统

View File

@ -18,6 +18,15 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserPointManagement.Persist
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserPointManagement.Application.Tests", "test\UserPointManagement.Application.Tests\UserPointManagement.Application.Tests.csproj", "{5770D3E5-9B3E-40FC-8209-62F0B4B45BD4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{08F901D9-600A-4B4D-A942-AD2F61EDFE49}"
ProjectSection(SolutionItems) = preProject
Dockerfile = Dockerfile
README.md = README.md
NuGet.Config = NuGet.Config
.drone.yml = .drone.yml
.gitignore = .gitignore
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU

View File

@ -8,7 +8,7 @@ namespace UserPointManagement.Application.Services;
public interface IUserPointService
{
Task<PageResultDto<UserPointDto>> GetUserPoints(GetUserPointDto req);
Task<PageResultDto<UserPointInfoDto>> GetUserPoints(GetUserPointDto req);
Task CreateUserPoint(CreateUserPointDto input);
@ -24,26 +24,39 @@ public class UserPointService : IUserPointService
_dbContextFactory = dbContextFactory;
}
public async Task<PageResultDto<UserPointDto>> GetUserPoints(GetUserPointDto req)
public async Task<PageResultDto<UserPointInfoDto>> GetUserPoints(GetUserPointDto req)
{
await using var _userPointManagementDbContext = await _dbContextFactory.CreateDbContextAsync();
var queryable = from userPoint in _userPointManagementDbContext.UserPoints
join user in _userPointManagementDbContext.Users on userPoint.UserId equals user.Id
var queryable = _userPointManagementDbContext.Users
.Where(x => x.Id == req.UserId, req.UserId.HasValue);
// 分页筛选只能针对用户
var users = await queryable.OrderByDescending(x => x.Id).Paging(req).ToListAsync();
// 查出用户底下积分明细
var userPoints = await (from userPoint in _userPointManagementDbContext.UserPoints
where users.Select(x => x.Id).Contains(userPoint.UserId)
select new UserPointDto()
{
UserPointId = userPoint.Id,
UserId = user.Id,
Name = user.Name,
UserId = userPoint.UserId,
Point = userPoint.Point,
CreateTime = userPoint.CreateTime
};
}).ToListAsync();
queryable = queryable.Where(x => x.UserId == req.UserId, req.UserId.HasValue);
var data = userPoints.GroupBy(x => x.UserId)
.Select(x => new UserPointInfoDto()
{
UserId = x.Key,
Name = users.First(p => p.Id == x.Key).Name,
TotalPoint = x.Sum(p => p.Point),
Items = x.ToList()
}).ToList();
var count = queryable.Count();
var data = await queryable.OrderByDescending(x => x.CreateTime).Paging(req).ToListAsync().ConfigureAwait(false);
return new PageResultDto<UserPointDto>()
return new PageResultDto<UserPointInfoDto>()
{
Items = data,
TotalCount = count

View File

@ -37,7 +37,7 @@ public class UserService : IUserService
queryable = queryable.Where(x => x.Mobile.Contains(req.Keyword) || x.Name.Contains(req.Keyword),
!string.IsNullOrEmpty(req.Keyword));
var count = queryable.Count();
var data = await queryable.OrderByDescending(x => x.Id).Paging(req).ToListAsync().ConfigureAwait(false);
@ -63,7 +63,8 @@ public class UserService : IUserService
public async Task CreateUser(User input)
{
await using var _userPointManagementDbContext = await _dbContextFactory.CreateDbContextAsync();
if (_userPointManagementDbContext.Users.Any(x => x.Mobile == input.Mobile))
if (!string.IsNullOrWhiteSpace(input.Mobile) &&
_userPointManagementDbContext.Users.Any(x => x.Mobile == input.Mobile))
{
throw new ArgumentException("手机号不可重复!");
}
@ -72,6 +73,7 @@ public class UserService : IUserService
{
throw new ArgumentException("名称不可重复!");
}
_userPointManagementDbContext.Users.Add(input);
await _userPointManagementDbContext.SaveChangesAsync().ConfigureAwait(false);
}

View File

@ -2,5 +2,5 @@
public class GetUserDto : PageBase
{
public string Keyword { get; set; }
public string? Keyword { get; set; }
}

View File

@ -6,8 +6,6 @@ public class UserPointDto
public int UserId { get; set; }
public string Name { get; set; }
public int Point { get; set; }
public DateTime CreateTime { get; set; }

View File

@ -0,0 +1,12 @@
namespace UserPointManagement.Model.Dtos.UserPoint;
public class UserPointInfoDto
{
public int UserId { get; set; }
public string Name { get; set; }
public int TotalPoint { get; set; }
public List<UserPointDto> Items { get; set; }
}

View File

@ -6,5 +6,5 @@ public class User
public string Name { get; set; }
public string Mobile { get; set; }
public string? Mobile { get; set; }
}

View File

@ -9,10 +9,10 @@ public class UserConfiguration : IEntityTypeConfiguration<User>
public void Configure(EntityTypeBuilder<User> builder)
{
builder.HasKey(e => e.Id);
builder.Property(e => e.Id)
.HasComment("主键");
builder.Property(e => e.Name)
.HasComment("姓名")
.HasMaxLength(50);

View File

@ -0,0 +1,89 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using UserPointManagement.Persistence;
#nullable disable
namespace UserPointManagement.Persistence.Migrations
{
[DbContext(typeof(UserPointManagementDbContext))]
[Migration("20230730134035_ModifyUser")]
partial class ModifyUser
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("UserPointManagement.Model.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasComment("主键");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Mobile")
.HasMaxLength(30)
.HasColumnType("character varying(30)")
.HasColumnName("mobile")
.HasComment("手机号");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)")
.HasColumnName("name")
.HasComment("姓名");
b.HasKey("Id")
.HasName("pk_user");
b.ToTable("user", (string)null);
});
modelBuilder.Entity("UserPointManagement.Model.Entities.UserPoint", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasColumnName("id")
.HasComment("主键");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<DateTime>("CreateTime")
.HasColumnType("timestamp without time zone")
.HasColumnName("create_time")
.HasComment("新增时间");
b.Property<int>("Point")
.HasColumnType("integer")
.HasColumnName("point")
.HasComment("积分");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id")
.HasComment("用户Id");
b.HasKey("Id")
.HasName("pk_user_point");
b.ToTable("user_point", (string)null);
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,41 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace UserPointManagement.Persistence.Migrations
{
public partial class ModifyUser : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "mobile",
table: "user",
type: "character varying(30)",
maxLength: 30,
nullable: true,
comment: "手机号",
oldClrType: typeof(string),
oldType: "character varying(30)",
oldMaxLength: 30,
oldComment: "手机号");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "mobile",
table: "user",
type: "character varying(30)",
maxLength: 30,
nullable: false,
defaultValue: "",
comment: "手机号",
oldClrType: typeof(string),
oldType: "character varying(30)",
oldMaxLength: 30,
oldNullable: true,
oldComment: "手机号");
}
}
}

View File

@ -33,7 +33,6 @@ namespace UserPointManagement.Persistence.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Mobile")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("character varying(30)")
.HasColumnName("mobile")

View File

@ -9,9 +9,9 @@ public class UserPointManagementDbContext : Microsoft.EntityFrameworkCore.DbCont
public UserPointManagementDbContext(DbContextOptions options) : base(options)
{
}
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<UserPoint> UserPoints { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)

View File

@ -10,7 +10,7 @@ public class UserPointManagementDbContextFactory : IDesignTimeDbContextFactory<U
{
var optionsBuilder = new DbContextOptionsBuilder<UserPointManagementDbContext>();
optionsBuilder
.UseNpgsql("Server=67.230.184.225;Port=58007;UserId=postgres;Password=postgres;Database=tiamo;")
.UseNpgsql("Server=67.230.184.225;Port=58007;UserId=postgres;Password=postgres;Database=tiamo_dev;")
.UseSnakeCaseNamingConvention();
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);

View File

@ -0,0 +1,31 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using UserPointManagement.Application.Services;
using UserPointManagement.Model;
using UserPointManagement.Model.Dtos.User;
using UserPointManagement.Model.Entities;
namespace UserPointManagement.Web.Controllers;
[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
/// <summary>
/// 获取用户
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
[HttpGet]
public async Task<PageResultDto<User>> GetUsers([FromQuery]GetUserDto req)
{
return await _userService.GetUsers(req).ConfigureAwait(false);
}
}

View File

@ -0,0 +1,45 @@
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Routing;
namespace UserPointManagement.Web;
public static class MvcOptionsExtensions
{
private static void UseGeneralRoutePrefix(this MvcOptions opts, IRouteTemplateProvider routeAttribute)
{
opts.Conventions.Add(new RoutePrefixConvention(routeAttribute));
}
public static void UseGeneralRoutePrefix(this MvcOptions opts, string
prefix)
{
opts.UseGeneralRoutePrefix(new RouteAttribute(prefix));
}
}
public class RoutePrefixConvention : IApplicationModelConvention
{
private readonly AttributeRouteModel _routePrefix;
public RoutePrefixConvention(IRouteTemplateProvider route)
{
_routePrefix = new AttributeRouteModel(route);
}
public void Apply(ApplicationModel application)
{
foreach (var selector in application.Controllers.SelectMany(c => c.Selectors))
{
if (selector.AttributeRouteModel != null)
{
selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_routePrefix, selector.AttributeRouteModel);
}
else
{
selector.AttributeRouteModel = _routePrefix;
}
}
}
}

View File

@ -92,7 +92,7 @@
<FormItem Label="姓名" Rules=@(new FormValidationRule[] { new FormValidationRule { Required = true, Message = "名称不可为空!" }, new FormValidationRule() { Len = 50, Message = "名称上限50字" } })>
<Input @bind-Value="@context.Name"/>
</FormItem>
<FormItem Label="手机号" Rules="@(new FormValidationRule[] { new FormValidationRule { Type = FormFieldType.Regexp, Pattern = @"^1\d{10}$", Message = "请输入正确手机号", Required = true } })">
<FormItem Label="手机号" Rules="@(new FormValidationRule[] { new FormValidationRule { Type = FormFieldType.Regexp, Pattern = @"^1\d{10}$", Message = "请输入正确手机号", Required = false } })">
<Input @bind-Value="@context.Mobile"/>
</FormItem>
</Form>

View File

@ -36,23 +36,36 @@
</Space>
</GridCol>
</GridRow>
<Table TItem="UserPointDto" DataSource="@_userPoints"
<Table TItem="UserPointInfoDto" DataSource="@_userPoints"
Total="_total"
Loading="_loading"
PageIndex="@_pageIndex"
PageSize="@_pageSize"
OnExpand="OnRowExpand"
OnPageIndexChange="OnPageIndexChanged"
OnPageSizeChange="OnPageSizeChange">
<PropertyColumn Property="c => c.Name" title="用户姓名"/>
<PropertyColumn Property="c => c.Point" title="积分"/>
<PropertyColumn Property="c => c.CreateTime" title="新增时间" Format="yyyy-MM-dd HH:mm"/>
<ActionColumn Title="操作" Width="220">
<Space Size=@("middle")>
<SpaceItem>
<Button Danger OnClick="()=>Delete(context.UserPointId)">删除</Button>
</SpaceItem>
</Space>
</ActionColumn>
<ChildContent Context="data">
<PropertyColumn Property="c => c.Name" title="用户姓名"/>
<PropertyColumn Property="c => c.TotalPoint" title="总积分"/>
<ActionColumn Title="操作" Width="220">
<Button Type="Primary" OnClick="() => Add(data.UserId)">新增积分</Button>
</ActionColumn>
</ChildContent>
<ExpandTemplate Context="rowData">
<Table DataSource="rowData.Data.Items" Loading="rowData.Data.Items == null" HidePagination>
<ChildContent Context="data">
<PropertyColumn Property="c => c.Point" title="积分"/>
<PropertyColumn Property="c => c.CreateTime" title="新增时间" Format="yyyy-MM-dd HH:mm"/>
<ActionColumn Title="Action">
<Space Size="@("middle")">
<SpaceItem>
<Button Danger OnClick="() => Delete(data.UserPointId)">删除积分</Button>
</SpaceItem>
</Space>
</ActionColumn>
</ChildContent>
</Table>
</ExpandTemplate>
</Table>
</PageContainer>
@ -68,7 +81,7 @@
@ref="@_form">
<FormItem Label="姓名">
<Select TItem="UserDto"
TItemValue="int"
TItemValue="int?"
Mode="default"
DataSource="@_users"
@bind-Value="@context.UserId"
@ -93,10 +106,10 @@
public class Model
{
[Required]
public int UserId { get; set; }
public int? UserId { get; set; }
[Required]
public int Point { get; set; }
public int? Point { get; set; }
}
private Model model = new Model();
@ -123,6 +136,8 @@
private void HandleCancel(MouseEventArgs e)
{
model.UserId = null;
model.Point = null;
_visible = false;
}
@ -155,10 +170,16 @@
_form.Submit();
await UserPointService.CreateUserPoint(new CreateUserPointDto()
{
UserId = model.UserId,
Point = model.Point
UserId = model.UserId.Value,
Point = model.Point.Value
}).ConfigureAwait(false);
await RefreshTable().ConfigureAwait(false);
}
private async Task Add(int userId)
{
model.UserId = userId;
_visible = true;
}
}

View File

@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AntDesign;
using AntDesign.TableModels;
using Microsoft.AspNetCore.Components;
using UserPointManagement.Application.Services;
using UserPointManagement.Model.Dtos.User;
@ -15,7 +17,7 @@ public class UserPointDetailBase : ComponentBase
[Inject] private IUserService UserService { get; set; }
[Inject] private MessageService MessageService { get; set; }
protected List<UserPointDto> _userPoints;
protected List<UserPointInfoDto> _userPoints;
protected List<UserDto> _users;
protected int _pageIndex = 1;
protected int _pageSize = 20;
@ -72,4 +74,12 @@ public class UserPointDetailBase : ComponentBase
await MessageService.Success("删除成功!");
await RefreshTable();
}
protected async Task OnRowExpand(RowData<UserPointInfoDto> rowData)
{
if (rowData.Data.Items != null)
{
return;
}
}
}

View File

@ -5,9 +5,12 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using UserPointManagement.Persistence;
namespace UserPointManagement.Web
{
@ -15,7 +18,13 @@ namespace UserPointManagement.Web
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
var host = CreateHostBuilder(args).Build();
using (var serviceScope = host.Services.CreateScope())
{
var context = serviceScope.ServiceProvider.GetRequiredService<UserPointManagementDbContext>();
context.Database.Migrate();
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>

View File

@ -19,7 +19,8 @@
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
"ASPNETCORE_ENVIRONMENT": "Development",
"Connection:UserPointManagement": "Server=67.230.184.225;Port=58007;UserId=postgres;Password=postgres;Database=tiamo;"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}

View File

@ -1,4 +1,6 @@
using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using AntDesign.ProLayout;
using Microsoft.AspNetCore.Builder;
@ -26,6 +28,20 @@ namespace UserPointManagement.Web
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.UseGeneralRoutePrefix("/api");
});
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(options =>
{
Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.xml").ToList().ForEach(file =>
{
options.IncludeXmlComments(file, true);
});
});
services.AddRouting(options => options.LowercaseUrls = true);
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddAntDesign();
@ -46,6 +62,7 @@ namespace UserPointManagement.Web
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -54,6 +71,16 @@ namespace UserPointManagement.Web
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger(o =>
{
// o.RouteTemplate = $"/api/swagger/{{documentName}}/swagger.json";
});
app.UseSwaggerUI(c =>
{
// c.RoutePrefix = $"/api/swagger";
// c.SwaggerEndpoint($"/api/swagger/v1/swagger.json",
// "UserPointManagement.Api API V1");
});
}
else
{
@ -69,6 +96,7 @@ namespace UserPointManagement.Web
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});

View File

@ -9,6 +9,7 @@
<PackageReference Include="AntDesign.Charts" Version="0.2.3" />
<PackageReference Include="AntDesign.ProLayout" Version="0.12.4" />
<PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
<ItemGroup>

View File

@ -4,7 +4,8 @@
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.EntityFrameworkCore.Database": "Information"
}
},
"ProSettings": {
@ -22,5 +23,6 @@
"MenuRender": true,
"MenuHeaderRender": true,
"HeaderHeight": 48
}
},
"Connection:UserPointManagement": "Server=67.230.184.225;Port=58007;UserId=postgres;Password=postgres;Database=tiamo_dev;"
}

View File

@ -22,6 +22,5 @@
"MenuRender": true,
"MenuHeaderRender": true,
"HeaderHeight": 48
},
"Connection:UserPointManagement": "Server=67.230.184.225;Port=58007;UserId=postgres;Password=postgres;Database=tiamo;"
}
}