feat: add role template and tenant role apis
This commit is contained in:
@@ -0,0 +1,217 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using TakeoutSaaS.Application.Identity.Commands;
|
||||||
|
using TakeoutSaaS.Application.Identity.Contracts;
|
||||||
|
using TakeoutSaaS.Application.Identity.Queries;
|
||||||
|
using TakeoutSaaS.Module.Authorization.Attributes;
|
||||||
|
using TakeoutSaaS.Shared.Abstractions.Results;
|
||||||
|
using TakeoutSaaS.Shared.Web.Api;
|
||||||
|
|
||||||
|
namespace TakeoutSaaS.AdminApi.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色模板管理(平台蓝本)。
|
||||||
|
/// </summary>
|
||||||
|
[ApiVersion("1.0")]
|
||||||
|
[Authorize]
|
||||||
|
[Route("api/admin/v{version:apiVersion}/role-templates")]
|
||||||
|
public sealed class RoleTemplatesController(IMediator mediator) : BaseApiController
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 分页查询角色模板。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="isActive">是否启用筛选。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>角色模板列表。</returns>
|
||||||
|
[HttpGet]
|
||||||
|
[PermissionAuthorize("identity:role:read")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<RoleTemplateDto>>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ApiResponse<IReadOnlyList<RoleTemplateDto>>> List([FromQuery] bool? isActive, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 构造查询参数
|
||||||
|
var query = new ListRoleTemplatesQuery { IsActive = isActive };
|
||||||
|
|
||||||
|
// 2. 查询模板集合
|
||||||
|
var result = await mediator.Send(query, cancellationToken);
|
||||||
|
|
||||||
|
// 3. 返回模板列表
|
||||||
|
return ApiResponse<IReadOnlyList<RoleTemplateDto>>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 克隆角色模板。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="templateCode">源模板编码。</param>
|
||||||
|
/// <param name="command">克隆命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>新模板详情。</returns>
|
||||||
|
[HttpPost("{templateCode}/clone")]
|
||||||
|
[PermissionAuthorize("role-template:create")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<RoleTemplateDto>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ApiResponse<RoleTemplateDto>> Clone(
|
||||||
|
string templateCode,
|
||||||
|
[FromBody, Required] CloneRoleTemplateCommand command,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 绑定源模板编码
|
||||||
|
command = command with { SourceTemplateCode = templateCode };
|
||||||
|
|
||||||
|
// 2. 执行克隆
|
||||||
|
var result = await mediator.Send(command, cancellationToken);
|
||||||
|
|
||||||
|
// 3. 返回新模板
|
||||||
|
return ApiResponse<RoleTemplateDto>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取角色模板详情。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="templateCode">模板编码。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>角色模板详情。</returns>
|
||||||
|
[HttpGet("{templateCode}")]
|
||||||
|
[PermissionAuthorize("identity:role:read")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<RoleTemplateDto>), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<RoleTemplateDto>), StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ApiResponse<RoleTemplateDto>> Detail(string templateCode, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 查询模板详情
|
||||||
|
var result = await mediator.Send(new GetRoleTemplateQuery { TemplateCode = templateCode }, cancellationToken);
|
||||||
|
|
||||||
|
// 2. 返回模板或 404
|
||||||
|
return result is null
|
||||||
|
? ApiResponse<RoleTemplateDto>.Error(StatusCodes.Status404NotFound, "角色模板不存在")
|
||||||
|
: ApiResponse<RoleTemplateDto>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建角色模板。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="command">创建命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>创建后的模板。</returns>
|
||||||
|
[HttpPost]
|
||||||
|
[PermissionAuthorize("role-template:create")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<RoleTemplateDto>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ApiResponse<RoleTemplateDto>> Create([FromBody, Required] CreateRoleTemplateCommand command, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 创建模板
|
||||||
|
var result = await mediator.Send(command, cancellationToken);
|
||||||
|
|
||||||
|
// 2. 返回创建结果
|
||||||
|
return ApiResponse<RoleTemplateDto>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取模板的权限列表。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="templateCode">模板编码。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>权限集合。</returns>
|
||||||
|
[HttpGet("{templateCode}/permissions")]
|
||||||
|
[PermissionAuthorize("identity:role:read")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<PermissionTemplateDto>>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ApiResponse<IReadOnlyList<PermissionTemplateDto>>> GetPermissions(string templateCode, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 查询模板权限
|
||||||
|
var result = await mediator.Send(new RoleTemplatePermissionsQuery { TemplateCode = templateCode }, cancellationToken);
|
||||||
|
|
||||||
|
// 2. 返回权限集合
|
||||||
|
return ApiResponse<IReadOnlyList<PermissionTemplateDto>>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新角色模板。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="templateCode">模板编码。</param>
|
||||||
|
/// <param name="command">更新命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>更新后的模板。</returns>
|
||||||
|
[HttpPut("{templateCode}")]
|
||||||
|
[PermissionAuthorize("role-template:update")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<RoleTemplateDto>), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<RoleTemplateDto>), StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ApiResponse<RoleTemplateDto>> Update(
|
||||||
|
string templateCode,
|
||||||
|
[FromBody, Required] UpdateRoleTemplateCommand command,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 绑定模板编码
|
||||||
|
command = command with { TemplateCode = templateCode };
|
||||||
|
|
||||||
|
// 2. 执行更新
|
||||||
|
var result = await mediator.Send(command, cancellationToken);
|
||||||
|
|
||||||
|
// 3. 返回更新结果或 404
|
||||||
|
return result is null
|
||||||
|
? ApiResponse<RoleTemplateDto>.Error(StatusCodes.Status404NotFound, "角色模板不存在")
|
||||||
|
: ApiResponse<RoleTemplateDto>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除角色模板。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="templateCode">模板编码。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>删除结果。</returns>
|
||||||
|
[HttpDelete("{templateCode}")]
|
||||||
|
[PermissionAuthorize("role-template:delete")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<bool>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ApiResponse<bool>> Delete(string templateCode, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 执行删除
|
||||||
|
var result = await mediator.Send(new DeleteRoleTemplateCommand { TemplateCode = templateCode }, cancellationToken);
|
||||||
|
|
||||||
|
// 2. 返回执行结果
|
||||||
|
return ApiResponse<bool>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为当前租户批量初始化预置角色模板。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="command">初始化命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>生成的租户角色列表。</returns>
|
||||||
|
[HttpPost("init")]
|
||||||
|
[PermissionAuthorize("identity:role:create")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<RoleDto>>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ApiResponse<IReadOnlyList<RoleDto>>> Initialize(
|
||||||
|
[FromBody] InitializeRoleTemplatesCommand? command,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 确保命令存在
|
||||||
|
command ??= new InitializeRoleTemplatesCommand();
|
||||||
|
|
||||||
|
// 2. 初始化模板到租户
|
||||||
|
var result = await mediator.Send(command, cancellationToken);
|
||||||
|
|
||||||
|
// 3. 返回新建的角色列表
|
||||||
|
return ApiResponse<IReadOnlyList<RoleDto>>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将单个模板初始化到当前租户。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="templateCode">模板编码。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>生成的角色列表。</returns>
|
||||||
|
[HttpPost("{templateCode}/initialize-tenant")]
|
||||||
|
[PermissionAuthorize("identity:role:create")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<RoleDto>>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ApiResponse<IReadOnlyList<RoleDto>>> InitializeSingle(string templateCode, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 构造初始化命令
|
||||||
|
var command = new InitializeRoleTemplatesCommand
|
||||||
|
{
|
||||||
|
TemplateCodes = new[] { templateCode }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. 初始化模板到租户
|
||||||
|
var result = await mediator.Send(command, cancellationToken);
|
||||||
|
|
||||||
|
// 3. 返回生成的角色列表
|
||||||
|
return ApiResponse<IReadOnlyList<RoleDto>>.Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using TakeoutSaaS.Application.Identity.Commands;
|
||||||
|
using TakeoutSaaS.Application.Identity.Contracts;
|
||||||
|
using TakeoutSaaS.Application.Identity.Queries;
|
||||||
|
using TakeoutSaaS.Module.Authorization.Attributes;
|
||||||
|
using TakeoutSaaS.Shared.Abstractions.Results;
|
||||||
|
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||||
|
using TakeoutSaaS.Shared.Web.Api;
|
||||||
|
|
||||||
|
namespace TakeoutSaaS.AdminApi.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 租户角色管理(实例层)。
|
||||||
|
/// </summary>
|
||||||
|
[ApiVersion("1.0")]
|
||||||
|
[Authorize]
|
||||||
|
[Route("api/admin/v{version:apiVersion}/tenants/{tenantId:long}/roles")]
|
||||||
|
public sealed class TenantRolesController(IMediator mediator, ITenantProvider tenantProvider) : BaseApiController
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 租户角色分页。
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet]
|
||||||
|
[PermissionAuthorize("identity:role:read")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<PagedResult<RoleDto>>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ApiResponse<PagedResult<RoleDto>>> List(
|
||||||
|
long tenantId,
|
||||||
|
[FromQuery] SearchRolesQuery query,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 校验路由租户与上下文一致
|
||||||
|
var currentTenantId = tenantProvider.GetCurrentTenantId();
|
||||||
|
if (tenantId != currentTenantId)
|
||||||
|
{
|
||||||
|
return ApiResponse<PagedResult<RoleDto>>.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 查询角色分页
|
||||||
|
var result = await mediator.Send(query, cancellationToken);
|
||||||
|
|
||||||
|
// 3. 返回分页数据
|
||||||
|
return ApiResponse<PagedResult<RoleDto>>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色详情(含权限)。
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("{roleId:long}")]
|
||||||
|
[PermissionAuthorize("identity:role:read")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<RoleDetailDto>), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<RoleDetailDto>), StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ApiResponse<RoleDetailDto>> Detail(long tenantId, long roleId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 校验租户上下文
|
||||||
|
var currentTenantId = tenantProvider.GetCurrentTenantId();
|
||||||
|
if (tenantId != currentTenantId)
|
||||||
|
{
|
||||||
|
return ApiResponse<RoleDetailDto>.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 查询角色详情
|
||||||
|
var result = await mediator.Send(new RoleDetailQuery { RoleId = roleId }, cancellationToken);
|
||||||
|
|
||||||
|
// 3. 返回数据或 404
|
||||||
|
return result is null
|
||||||
|
? ApiResponse<RoleDetailDto>.Error(StatusCodes.Status404NotFound, "角色不存在")
|
||||||
|
: ApiResponse<RoleDetailDto>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建角色。
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost]
|
||||||
|
[PermissionAuthorize("identity:role:create")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<RoleDto>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ApiResponse<RoleDto>> Create(
|
||||||
|
long tenantId,
|
||||||
|
[FromBody, Required] CreateRoleCommand command,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 校验租户上下文
|
||||||
|
var currentTenantId = tenantProvider.GetCurrentTenantId();
|
||||||
|
if (tenantId != currentTenantId)
|
||||||
|
{
|
||||||
|
return ApiResponse<RoleDto>.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 创建角色
|
||||||
|
var result = await mediator.Send(command, cancellationToken);
|
||||||
|
|
||||||
|
// 3. 返回创建结果
|
||||||
|
return ApiResponse<RoleDto>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新角色。
|
||||||
|
/// </summary>
|
||||||
|
[HttpPut("{roleId:long}")]
|
||||||
|
[PermissionAuthorize("identity:role:update")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<RoleDto>), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<RoleDto>), StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ApiResponse<RoleDto>> Update(
|
||||||
|
long tenantId,
|
||||||
|
long roleId,
|
||||||
|
[FromBody, Required] UpdateRoleCommand command,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 校验租户上下文
|
||||||
|
var currentTenantId = tenantProvider.GetCurrentTenantId();
|
||||||
|
if (tenantId != currentTenantId)
|
||||||
|
{
|
||||||
|
return ApiResponse<RoleDto>.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 绑定角色 ID
|
||||||
|
command = command with { RoleId = roleId };
|
||||||
|
|
||||||
|
// 3. 执行更新
|
||||||
|
var result = await mediator.Send(command, cancellationToken);
|
||||||
|
|
||||||
|
// 4. 返回结果或 404
|
||||||
|
return result is null
|
||||||
|
? ApiResponse<RoleDto>.Error(StatusCodes.Status404NotFound, "角色不存在")
|
||||||
|
: ApiResponse<RoleDto>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除角色。
|
||||||
|
/// </summary>
|
||||||
|
[HttpDelete("{roleId:long}")]
|
||||||
|
[PermissionAuthorize("identity:role:delete")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<bool>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ApiResponse<bool>> Delete(long tenantId, long roleId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 校验租户上下文
|
||||||
|
var currentTenantId = tenantProvider.GetCurrentTenantId();
|
||||||
|
if (tenantId != currentTenantId)
|
||||||
|
{
|
||||||
|
return ApiResponse<bool>.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 执行删除
|
||||||
|
var command = new DeleteRoleCommand { RoleId = roleId };
|
||||||
|
var result = await mediator.Send(command, cancellationToken);
|
||||||
|
|
||||||
|
// 3. 返回结果
|
||||||
|
return ApiResponse<bool>.Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取角色权限列表。
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("{roleId:long}/permissions")]
|
||||||
|
[PermissionAuthorize("identity:role:read")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<PermissionDto>>), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<PermissionDto>>), StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ApiResponse<IReadOnlyList<PermissionDto>>> GetPermissions(
|
||||||
|
long tenantId,
|
||||||
|
long roleId,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 校验租户上下文
|
||||||
|
var currentTenantId = tenantProvider.GetCurrentTenantId();
|
||||||
|
if (tenantId != currentTenantId)
|
||||||
|
{
|
||||||
|
return ApiResponse<IReadOnlyList<PermissionDto>>.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 查询角色详情并提取权限
|
||||||
|
var detail = await mediator.Send(new RoleDetailQuery { RoleId = roleId }, cancellationToken);
|
||||||
|
if (detail is null)
|
||||||
|
{
|
||||||
|
return ApiResponse<IReadOnlyList<PermissionDto>>.Error(StatusCodes.Status404NotFound, "角色不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 返回权限集合
|
||||||
|
return ApiResponse<IReadOnlyList<PermissionDto>>.Ok(detail.Permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 覆盖角色权限。
|
||||||
|
/// </summary>
|
||||||
|
[HttpPut("{roleId:long}/permissions")]
|
||||||
|
[PermissionAuthorize("identity:role:bind-permission")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<bool>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ApiResponse<bool>> BindPermissions(
|
||||||
|
long tenantId,
|
||||||
|
long roleId,
|
||||||
|
[FromBody, Required] BindRolePermissionsCommand command,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 校验租户上下文
|
||||||
|
var currentTenantId = tenantProvider.GetCurrentTenantId();
|
||||||
|
if (tenantId != currentTenantId)
|
||||||
|
{
|
||||||
|
return ApiResponse<bool>.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 绑定角色 ID
|
||||||
|
command = command with { RoleId = roleId };
|
||||||
|
|
||||||
|
// 3. 覆盖授权
|
||||||
|
var result = await mediator.Send(command, cancellationToken);
|
||||||
|
return ApiResponse<bool>.Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using MediatR;
|
||||||
|
using TakeoutSaaS.Application.Identity.Contracts;
|
||||||
|
|
||||||
|
namespace TakeoutSaaS.Application.Identity.Commands;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 克隆角色模板。
|
||||||
|
/// </summary>
|
||||||
|
public sealed record CloneRoleTemplateCommand : IRequest<RoleTemplateDto>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 源模板编码。
|
||||||
|
/// </summary>
|
||||||
|
public string SourceTemplateCode { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 新模板编码。
|
||||||
|
/// </summary>
|
||||||
|
public string NewTemplateCode { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 新模板名称(为空则沿用源模板)。
|
||||||
|
/// </summary>
|
||||||
|
public string? Name { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 新模板描述(为空则沿用源模板)。
|
||||||
|
/// </summary>
|
||||||
|
public string? Description { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用(为空则沿用源模板)。
|
||||||
|
/// </summary>
|
||||||
|
public bool? IsActive { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 权限编码集合(为空则沿用源模板权限)。
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<string>? PermissionCodes { get; init; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
namespace TakeoutSaaS.Application.Identity.Contracts;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色详情 DTO。
|
||||||
|
/// </summary>
|
||||||
|
public sealed record RoleDetailDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 角色 ID。
|
||||||
|
/// </summary>
|
||||||
|
public long Id { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 租户 ID。
|
||||||
|
/// </summary>
|
||||||
|
public long TenantId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色名称。
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色编码。
|
||||||
|
/// </summary>
|
||||||
|
public string Code { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 描述。
|
||||||
|
/// </summary>
|
||||||
|
public string? Description { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 权限列表。
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<PermissionDto> Permissions { get; init; } = [];
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
using MediatR;
|
||||||
|
using TakeoutSaaS.Application.Identity.Commands;
|
||||||
|
using TakeoutSaaS.Application.Identity.Contracts;
|
||||||
|
using TakeoutSaaS.Domain.Identity.Entities;
|
||||||
|
using TakeoutSaaS.Domain.Identity.Repositories;
|
||||||
|
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||||
|
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||||
|
|
||||||
|
namespace TakeoutSaaS.Application.Identity.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色模板克隆处理器。
|
||||||
|
/// </summary>
|
||||||
|
public sealed class CloneRoleTemplateCommandHandler(IRoleTemplateRepository roleTemplateRepository)
|
||||||
|
: IRequestHandler<CloneRoleTemplateCommand, RoleTemplateDto>
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<RoleTemplateDto> Handle(CloneRoleTemplateCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 校验源模板是否存在
|
||||||
|
var source = await roleTemplateRepository.FindByCodeAsync(request.SourceTemplateCode, cancellationToken)
|
||||||
|
?? throw new BusinessException(ErrorCodes.NotFound, $"角色模板 {request.SourceTemplateCode} 不存在");
|
||||||
|
|
||||||
|
// 2. 校验新模板编码是否冲突
|
||||||
|
var exists = await roleTemplateRepository.FindByCodeAsync(request.NewTemplateCode, cancellationToken);
|
||||||
|
if (exists is not null)
|
||||||
|
{
|
||||||
|
throw new BusinessException(ErrorCodes.Conflict, $"角色模板编码 {request.NewTemplateCode} 已存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 获取源模板权限
|
||||||
|
var sourcePermissions = await roleTemplateRepository.GetPermissionsAsync(source.Id, cancellationToken);
|
||||||
|
var permissionCodes = request.PermissionCodes is not null && request.PermissionCodes.Count > 0
|
||||||
|
? request.PermissionCodes.Distinct(StringComparer.OrdinalIgnoreCase).ToArray()
|
||||||
|
: sourcePermissions
|
||||||
|
.Select(x => x.PermissionCode)
|
||||||
|
.Where(code => !string.IsNullOrWhiteSpace(code))
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
// 4. 构造新模板实体
|
||||||
|
var target = new RoleTemplate
|
||||||
|
{
|
||||||
|
TemplateCode = request.NewTemplateCode.Trim(),
|
||||||
|
Name = string.IsNullOrWhiteSpace(request.Name) ? source.Name : request.Name.Trim(),
|
||||||
|
Description = request.Description ?? source.Description,
|
||||||
|
IsActive = request.IsActive ?? source.IsActive
|
||||||
|
};
|
||||||
|
|
||||||
|
// 5. 持久化新模板与权限
|
||||||
|
await roleTemplateRepository.AddAsync(target, permissionCodes, cancellationToken);
|
||||||
|
await roleTemplateRepository.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
// 6. 映射返回 DTO
|
||||||
|
var permissionDtos = permissionCodes
|
||||||
|
.Select(code => new PermissionTemplateDto
|
||||||
|
{
|
||||||
|
Code = code,
|
||||||
|
Name = code,
|
||||||
|
Description = code
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return new RoleTemplateDto
|
||||||
|
{
|
||||||
|
TemplateCode = target.TemplateCode,
|
||||||
|
Name = target.Name,
|
||||||
|
Description = target.Description,
|
||||||
|
IsActive = target.IsActive,
|
||||||
|
Permissions = permissionDtos
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
using MediatR;
|
||||||
|
using TakeoutSaaS.Application.Identity.Contracts;
|
||||||
|
using TakeoutSaaS.Application.Identity.Queries;
|
||||||
|
using TakeoutSaaS.Domain.Identity.Repositories;
|
||||||
|
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||||
|
|
||||||
|
namespace TakeoutSaaS.Application.Identity.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色详情查询处理器。
|
||||||
|
/// </summary>
|
||||||
|
public sealed class RoleDetailQueryHandler(
|
||||||
|
IRoleRepository roleRepository,
|
||||||
|
IRolePermissionRepository rolePermissionRepository,
|
||||||
|
IPermissionRepository permissionRepository,
|
||||||
|
ITenantProvider tenantProvider)
|
||||||
|
: IRequestHandler<RoleDetailQuery, RoleDetailDto?>
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<RoleDetailDto?> Handle(RoleDetailQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 获取租户上下文并查询角色
|
||||||
|
var tenantId = tenantProvider.GetCurrentTenantId();
|
||||||
|
var role = await roleRepository.FindByIdAsync(request.RoleId, tenantId, cancellationToken);
|
||||||
|
if (role is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 查询角色权限关系
|
||||||
|
var relations = await rolePermissionRepository.GetByRoleIdsAsync(tenantId, new[] { role.Id }, cancellationToken);
|
||||||
|
var permissionIds = relations.Select(x => x.PermissionId).ToArray();
|
||||||
|
|
||||||
|
// 3. 拉取权限实体
|
||||||
|
var permissions = permissionIds.Length == 0
|
||||||
|
? Array.Empty<Domain.Identity.Entities.Permission>()
|
||||||
|
: await permissionRepository.GetByIdsAsync(tenantId, permissionIds, cancellationToken);
|
||||||
|
|
||||||
|
// 4. 映射 DTO
|
||||||
|
var permissionDtos = permissions
|
||||||
|
.Select(x => new PermissionDto
|
||||||
|
{
|
||||||
|
Id = x.Id,
|
||||||
|
Code = x.Code,
|
||||||
|
Name = x.Name,
|
||||||
|
Description = x.Description
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return new RoleDetailDto
|
||||||
|
{
|
||||||
|
Id = role.Id,
|
||||||
|
TenantId = role.TenantId,
|
||||||
|
Name = role.Name,
|
||||||
|
Code = role.Code,
|
||||||
|
Description = role.Description,
|
||||||
|
Permissions = permissionDtos
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using MediatR;
|
||||||
|
using TakeoutSaaS.Application.Identity.Contracts;
|
||||||
|
using TakeoutSaaS.Application.Identity.Queries;
|
||||||
|
using TakeoutSaaS.Domain.Identity.Repositories;
|
||||||
|
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||||
|
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||||
|
|
||||||
|
namespace TakeoutSaaS.Application.Identity.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色模板权限查询处理器。
|
||||||
|
/// </summary>
|
||||||
|
public sealed class RoleTemplatePermissionsQueryHandler(IRoleTemplateRepository roleTemplateRepository)
|
||||||
|
: IRequestHandler<RoleTemplatePermissionsQuery, IReadOnlyList<PermissionTemplateDto>>
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<IReadOnlyList<PermissionTemplateDto>> Handle(RoleTemplatePermissionsQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 校验模板存在
|
||||||
|
var template = await roleTemplateRepository.FindByCodeAsync(request.TemplateCode, cancellationToken)
|
||||||
|
?? throw new BusinessException(ErrorCodes.NotFound, $"角色模板 {request.TemplateCode} 不存在");
|
||||||
|
|
||||||
|
// 2. 查询模板权限
|
||||||
|
var permissions = await roleTemplateRepository.GetPermissionsAsync(template.Id, cancellationToken);
|
||||||
|
|
||||||
|
// 3. 映射 DTO
|
||||||
|
var dto = permissions
|
||||||
|
.Where(x => !string.IsNullOrWhiteSpace(x.PermissionCode))
|
||||||
|
.Select(x => new PermissionTemplateDto
|
||||||
|
{
|
||||||
|
Code = x.PermissionCode,
|
||||||
|
Name = x.PermissionCode,
|
||||||
|
Description = x.PermissionCode
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// 4. 返回权限列表
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using MediatR;
|
||||||
|
using TakeoutSaaS.Application.Identity.Contracts;
|
||||||
|
|
||||||
|
namespace TakeoutSaaS.Application.Identity.Queries;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询角色详情(含权限)。
|
||||||
|
/// </summary>
|
||||||
|
public sealed class RoleDetailQuery : IRequest<RoleDetailDto?>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 角色 ID。
|
||||||
|
/// </summary>
|
||||||
|
public long RoleId { get; init; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using MediatR;
|
||||||
|
using TakeoutSaaS.Application.Identity.Contracts;
|
||||||
|
|
||||||
|
namespace TakeoutSaaS.Application.Identity.Queries;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询角色模板权限列表。
|
||||||
|
/// </summary>
|
||||||
|
public sealed class RoleTemplatePermissionsQuery : IRequest<IReadOnlyList<PermissionTemplateDto>>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 模板编码。
|
||||||
|
/// </summary>
|
||||||
|
public string TemplateCode { get; init; } = string.Empty;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,544 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TakeoutSaaS.Infrastructure.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddTenantVerificationProfile : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "StoreId",
|
||||||
|
table: "queue_tickets",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: false,
|
||||||
|
comment: "获取或设置所属门店 ID。",
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "BatchConsumeStrategy",
|
||||||
|
table: "inventory_items",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0,
|
||||||
|
comment: "批次扣减策略。");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsPresale",
|
||||||
|
table: "inventory_items",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false,
|
||||||
|
comment: "是否预售商品。");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsSoldOut",
|
||||||
|
table: "inventory_items",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false,
|
||||||
|
comment: "是否标记售罄。");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "MaxQuantityPerOrder",
|
||||||
|
table: "inventory_items",
|
||||||
|
type: "integer",
|
||||||
|
nullable: true,
|
||||||
|
comment: "单品限购(覆盖商品级 MaxQuantityPerOrder)。");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "PresaleCapacity",
|
||||||
|
table: "inventory_items",
|
||||||
|
type: "integer",
|
||||||
|
nullable: true,
|
||||||
|
comment: "预售名额(上限)。");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "PresaleEndTime",
|
||||||
|
table: "inventory_items",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: true,
|
||||||
|
comment: "预售结束时间(UTC)。");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "PresaleLocked",
|
||||||
|
table: "inventory_items",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0,
|
||||||
|
comment: "当前预售已锁定数量。");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "PresaleStartTime",
|
||||||
|
table: "inventory_items",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: true,
|
||||||
|
comment: "预售开始时间(UTC)。");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<byte[]>(
|
||||||
|
name: "RowVersion",
|
||||||
|
table: "inventory_items",
|
||||||
|
type: "bytea",
|
||||||
|
rowVersion: true,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new byte[0],
|
||||||
|
comment: "并发控制字段。");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<byte[]>(
|
||||||
|
name: "RowVersion",
|
||||||
|
table: "inventory_batches",
|
||||||
|
type: "bytea",
|
||||||
|
rowVersion: true,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new byte[0],
|
||||||
|
comment: "并发控制字段。");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "OrderId",
|
||||||
|
table: "delivery_orders",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: false,
|
||||||
|
comment: "获取或设置关联订单 ID。",
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "inventory_lock_records",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
StoreId = table.Column<long>(type: "bigint", nullable: false, comment: "门店 ID。"),
|
||||||
|
ProductSkuId = table.Column<long>(type: "bigint", nullable: false, comment: "SKU ID。"),
|
||||||
|
Quantity = table.Column<int>(type: "integer", nullable: false, comment: "锁定数量。"),
|
||||||
|
IsPresale = table.Column<bool>(type: "boolean", nullable: false, comment: "是否预售锁定。"),
|
||||||
|
IdempotencyKey = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false, comment: "幂等键。"),
|
||||||
|
ExpiresAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "过期时间(UTC)。"),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false, comment: "锁定状态。"),
|
||||||
|
RowVersion = table.Column<byte[]>(type: "bytea", rowVersion: true, nullable: false, comment: "并发控制字段。"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||||
|
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||||
|
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||||
|
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_inventory_lock_records", x => x.Id);
|
||||||
|
},
|
||||||
|
comment: "库存锁定记录。");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "merchant_audit_logs",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
MerchantId = table.Column<long>(type: "bigint", nullable: false, comment: "商户标识。"),
|
||||||
|
Action = table.Column<int>(type: "integer", nullable: false, comment: "动作类型。"),
|
||||||
|
Title = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false, comment: "标题。"),
|
||||||
|
Description = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true, comment: "详情描述。"),
|
||||||
|
OperatorId = table.Column<long>(type: "bigint", nullable: true, comment: "操作人 ID。"),
|
||||||
|
OperatorName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true, comment: "操作人名称。"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||||
|
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||||
|
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||||
|
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_merchant_audit_logs", x => x.Id);
|
||||||
|
},
|
||||||
|
comment: "商户入驻审核日志。");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "merchant_categories",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Name = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false, comment: "类目名称。"),
|
||||||
|
DisplayOrder = table.Column<int>(type: "integer", nullable: false, defaultValue: 0, comment: "显示顺序,越小越靠前。"),
|
||||||
|
IsActive = table.Column<bool>(type: "boolean", nullable: false, comment: "是否可用。"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||||
|
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||||
|
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||||
|
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_merchant_categories", x => x.Id);
|
||||||
|
},
|
||||||
|
comment: "商户可选类目。");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "store_pickup_settings",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
StoreId = table.Column<long>(type: "bigint", nullable: false, comment: "门店标识。"),
|
||||||
|
AllowToday = table.Column<bool>(type: "boolean", nullable: false, comment: "是否允许当天自提。"),
|
||||||
|
AllowDaysAhead = table.Column<int>(type: "integer", nullable: false, comment: "可预约天数(含当天)。"),
|
||||||
|
DefaultCutoffMinutes = table.Column<int>(type: "integer", nullable: false, defaultValue: 30, comment: "默认截单分钟(开始前多少分钟截止)。"),
|
||||||
|
MaxQuantityPerOrder = table.Column<int>(type: "integer", nullable: true, comment: "单笔自提最大份数。"),
|
||||||
|
RowVersion = table.Column<byte[]>(type: "bytea", rowVersion: true, nullable: false, comment: "并发控制字段。"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||||
|
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||||
|
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||||
|
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_store_pickup_settings", x => x.Id);
|
||||||
|
},
|
||||||
|
comment: "门店自提配置。");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "store_pickup_slots",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
StoreId = table.Column<long>(type: "bigint", nullable: false, comment: "门店标识。"),
|
||||||
|
Name = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false, comment: "档期名称。"),
|
||||||
|
StartTime = table.Column<TimeSpan>(type: "interval", nullable: false, comment: "当天开始时间(UTC)。"),
|
||||||
|
EndTime = table.Column<TimeSpan>(type: "interval", nullable: false, comment: "当天结束时间(UTC)。"),
|
||||||
|
CutoffMinutes = table.Column<int>(type: "integer", nullable: false, defaultValue: 30, comment: "截单分钟(开始前多少分钟截止)。"),
|
||||||
|
Capacity = table.Column<int>(type: "integer", nullable: false, comment: "容量(份数)。"),
|
||||||
|
ReservedCount = table.Column<int>(type: "integer", nullable: false, comment: "已占用数量。"),
|
||||||
|
Weekdays = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false, comment: "适用星期(逗号分隔 1-7)。"),
|
||||||
|
IsEnabled = table.Column<bool>(type: "boolean", nullable: false, comment: "是否启用。"),
|
||||||
|
RowVersion = table.Column<byte[]>(type: "bytea", rowVersion: true, nullable: false, comment: "并发控制字段。"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||||
|
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||||
|
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||||
|
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_store_pickup_slots", x => x.Id);
|
||||||
|
},
|
||||||
|
comment: "门店自提档期。");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "tenant_announcement_reads",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
AnnouncementId = table.Column<long>(type: "bigint", nullable: false, comment: "公告 ID。"),
|
||||||
|
UserId = table.Column<long>(type: "bigint", nullable: true, comment: "已读用户 ID(后台账号),为空表示租户级已读。"),
|
||||||
|
ReadAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "已读时间。"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||||
|
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||||
|
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||||
|
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_tenant_announcement_reads", x => x.Id);
|
||||||
|
},
|
||||||
|
comment: "租户公告已读记录。");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "tenant_announcements",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
Title = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false, comment: "公告标题。"),
|
||||||
|
Content = table.Column<string>(type: "text", nullable: false, comment: "公告正文(可为 Markdown/HTML,前端自行渲染)。"),
|
||||||
|
AnnouncementType = table.Column<int>(type: "integer", nullable: false, comment: "公告类型。"),
|
||||||
|
Priority = table.Column<int>(type: "integer", nullable: false, comment: "展示优先级,数值越大越靠前。"),
|
||||||
|
EffectiveFrom = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "生效时间(UTC)。"),
|
||||||
|
EffectiveTo = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "失效时间(UTC),为空表示长期有效。"),
|
||||||
|
IsActive = table.Column<bool>(type: "boolean", nullable: false, comment: "是否启用。"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||||
|
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||||
|
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||||
|
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_tenant_announcements", x => x.Id);
|
||||||
|
},
|
||||||
|
comment: "租户公告。");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "tenant_audit_logs",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "关联的租户标识。"),
|
||||||
|
Action = table.Column<int>(type: "integer", nullable: false, comment: "操作类型。"),
|
||||||
|
Title = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false, comment: "日志标题。"),
|
||||||
|
Description = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true, comment: "详细描述。"),
|
||||||
|
OperatorId = table.Column<long>(type: "bigint", nullable: true, comment: "操作人 ID。"),
|
||||||
|
OperatorName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true, comment: "操作人名称。"),
|
||||||
|
PreviousStatus = table.Column<int>(type: "integer", nullable: true, comment: "原状态。"),
|
||||||
|
CurrentStatus = table.Column<int>(type: "integer", nullable: true, comment: "新状态。"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||||
|
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||||
|
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_tenant_audit_logs", x => x.Id);
|
||||||
|
},
|
||||||
|
comment: "租户运营审核日志。");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "tenant_subscription_histories",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "租户标识。"),
|
||||||
|
TenantSubscriptionId = table.Column<long>(type: "bigint", nullable: false, comment: "对应的订阅 ID。"),
|
||||||
|
FromPackageId = table.Column<long>(type: "bigint", nullable: false, comment: "原套餐 ID。"),
|
||||||
|
ToPackageId = table.Column<long>(type: "bigint", nullable: false, comment: "新套餐 ID。"),
|
||||||
|
ChangeType = table.Column<int>(type: "integer", nullable: false, comment: "变更类型。"),
|
||||||
|
EffectiveFrom = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "生效时间。"),
|
||||||
|
EffectiveTo = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "到期时间。"),
|
||||||
|
Amount = table.Column<decimal>(type: "numeric", nullable: true, comment: "相关费用。"),
|
||||||
|
Currency = table.Column<string>(type: "character varying(8)", maxLength: 8, nullable: true, comment: "币种。"),
|
||||||
|
Notes = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true, comment: "备注。"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||||
|
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||||
|
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_tenant_subscription_histories", x => x.Id);
|
||||||
|
},
|
||||||
|
comment: "租户套餐订阅变更记录。");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "tenant_verification_profiles",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "对应的租户标识。"),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false, comment: "实名状态。"),
|
||||||
|
BusinessLicenseNumber = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true, comment: "营业执照编号。"),
|
||||||
|
BusinessLicenseUrl = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true, comment: "营业执照文件地址。"),
|
||||||
|
LegalPersonName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true, comment: "法人姓名。"),
|
||||||
|
LegalPersonIdNumber = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true, comment: "法人身份证号。"),
|
||||||
|
LegalPersonIdFrontUrl = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true, comment: "法人身份证正面。"),
|
||||||
|
LegalPersonIdBackUrl = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true, comment: "法人身份证反面。"),
|
||||||
|
BankAccountName = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true, comment: "开户名。"),
|
||||||
|
BankAccountNumber = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true, comment: "银行账号。"),
|
||||||
|
BankName = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true, comment: "银行名称。"),
|
||||||
|
AdditionalDataJson = table.Column<string>(type: "text", nullable: true, comment: "附加资料(JSON)。"),
|
||||||
|
SubmittedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "提交时间。"),
|
||||||
|
ReviewedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "审核时间。"),
|
||||||
|
ReviewedBy = table.Column<long>(type: "bigint", nullable: true, comment: "审核人 ID。"),
|
||||||
|
ReviewedByName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true, comment: "审核人姓名。"),
|
||||||
|
ReviewRemarks = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true, comment: "审核备注。"),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||||
|
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||||
|
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||||
|
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_tenant_verification_profiles", x => x.Id);
|
||||||
|
},
|
||||||
|
comment: "租户实名认证资料。");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_inventory_lock_records_TenantId_IdempotencyKey",
|
||||||
|
table: "inventory_lock_records",
|
||||||
|
columns: new[] { "TenantId", "IdempotencyKey" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_inventory_lock_records_TenantId_StoreId_ProductSkuId_Status",
|
||||||
|
table: "inventory_lock_records",
|
||||||
|
columns: new[] { "TenantId", "StoreId", "ProductSkuId", "Status" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_merchant_audit_logs_TenantId_MerchantId",
|
||||||
|
table: "merchant_audit_logs",
|
||||||
|
columns: new[] { "TenantId", "MerchantId" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_merchant_categories_TenantId_Name",
|
||||||
|
table: "merchant_categories",
|
||||||
|
columns: new[] { "TenantId", "Name" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_store_pickup_settings_TenantId_StoreId",
|
||||||
|
table: "store_pickup_settings",
|
||||||
|
columns: new[] { "TenantId", "StoreId" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_store_pickup_slots_TenantId_StoreId_Name",
|
||||||
|
table: "store_pickup_slots",
|
||||||
|
columns: new[] { "TenantId", "StoreId", "Name" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_tenant_announcement_reads_TenantId_AnnouncementId_UserId",
|
||||||
|
table: "tenant_announcement_reads",
|
||||||
|
columns: new[] { "TenantId", "AnnouncementId", "UserId" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_tenant_announcements_TenantId_AnnouncementType_IsActive",
|
||||||
|
table: "tenant_announcements",
|
||||||
|
columns: new[] { "TenantId", "AnnouncementType", "IsActive" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_tenant_announcements_TenantId_EffectiveFrom_EffectiveTo",
|
||||||
|
table: "tenant_announcements",
|
||||||
|
columns: new[] { "TenantId", "EffectiveFrom", "EffectiveTo" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_tenant_audit_logs_TenantId",
|
||||||
|
table: "tenant_audit_logs",
|
||||||
|
column: "TenantId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_tenant_subscription_histories_TenantId_TenantSubscriptionId",
|
||||||
|
table: "tenant_subscription_histories",
|
||||||
|
columns: new[] { "TenantId", "TenantSubscriptionId" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_tenant_verification_profiles_TenantId",
|
||||||
|
table: "tenant_verification_profiles",
|
||||||
|
column: "TenantId",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "inventory_lock_records");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "merchant_audit_logs");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "merchant_categories");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "store_pickup_settings");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "store_pickup_slots");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "tenant_announcement_reads");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "tenant_announcements");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "tenant_audit_logs");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "tenant_subscription_histories");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "tenant_verification_profiles");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "BatchConsumeStrategy",
|
||||||
|
table: "inventory_items");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsPresale",
|
||||||
|
table: "inventory_items");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsSoldOut",
|
||||||
|
table: "inventory_items");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "MaxQuantityPerOrder",
|
||||||
|
table: "inventory_items");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PresaleCapacity",
|
||||||
|
table: "inventory_items");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PresaleEndTime",
|
||||||
|
table: "inventory_items");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PresaleLocked",
|
||||||
|
table: "inventory_items");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PresaleStartTime",
|
||||||
|
table: "inventory_items");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "RowVersion",
|
||||||
|
table: "inventory_items");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "RowVersion",
|
||||||
|
table: "inventory_batches");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "StoreId",
|
||||||
|
table: "queue_tickets",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint",
|
||||||
|
oldComment: "获取或设置所属门店 ID。");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<long>(
|
||||||
|
name: "OrderId",
|
||||||
|
table: "delivery_orders",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(long),
|
||||||
|
oldType: "bigint",
|
||||||
|
oldComment: "获取或设置关联订单 ID。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -960,7 +960,8 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
|||||||
.HasComment("异常原因。");
|
.HasComment("异常原因。");
|
||||||
|
|
||||||
b.Property<long>("OrderId")
|
b.Property<long>("OrderId")
|
||||||
.HasColumnType("bigint");
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("获取或设置关联订单 ID。");
|
||||||
|
|
||||||
b.Property<DateTime?>("PickedUpAt")
|
b.Property<DateTime?>("PickedUpAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
@@ -1883,6 +1884,13 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
|||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasComment("剩余数量。");
|
.HasComment("剩余数量。");
|
||||||
|
|
||||||
|
b.Property<byte[]>("RowVersion")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAddOrUpdate()
|
||||||
|
.HasColumnType("bytea")
|
||||||
|
.HasComment("并发控制字段。");
|
||||||
|
|
||||||
b.Property<long>("StoreId")
|
b.Property<long>("StoreId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("bigint")
|
||||||
.HasComment("门店标识。");
|
.HasComment("门店标识。");
|
||||||
@@ -1919,6 +1927,10 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
|||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("BatchConsumeStrategy")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("批次扣减策略。");
|
||||||
|
|
||||||
b.Property<string>("BatchNumber")
|
b.Property<string>("BatchNumber")
|
||||||
.HasMaxLength(64)
|
.HasMaxLength(64)
|
||||||
.HasColumnType("character varying(64)")
|
.HasColumnType("character varying(64)")
|
||||||
@@ -1944,11 +1956,39 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
|||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasComment("过期日期。");
|
.HasComment("过期日期。");
|
||||||
|
|
||||||
|
b.Property<bool>("IsPresale")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasComment("是否预售商品。");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSoldOut")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasComment("是否标记售罄。");
|
||||||
|
|
||||||
b.Property<string>("Location")
|
b.Property<string>("Location")
|
||||||
.HasMaxLength(64)
|
.HasMaxLength(64)
|
||||||
.HasColumnType("character varying(64)")
|
.HasColumnType("character varying(64)")
|
||||||
.HasComment("储位或仓位信息。");
|
.HasComment("储位或仓位信息。");
|
||||||
|
|
||||||
|
b.Property<int?>("MaxQuantityPerOrder")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("单品限购(覆盖商品级 MaxQuantityPerOrder)。");
|
||||||
|
|
||||||
|
b.Property<int?>("PresaleCapacity")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("预售名额(上限)。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("PresaleEndTime")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("预售结束时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<int>("PresaleLocked")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("当前预售已锁定数量。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("PresaleStartTime")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("预售开始时间(UTC)。");
|
||||||
|
|
||||||
b.Property<long>("ProductSkuId")
|
b.Property<long>("ProductSkuId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("bigint")
|
||||||
.HasComment("SKU 标识。");
|
.HasComment("SKU 标识。");
|
||||||
@@ -1961,6 +2001,13 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
|||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasComment("已锁定库存(订单占用)。");
|
.HasComment("已锁定库存(订单占用)。");
|
||||||
|
|
||||||
|
b.Property<byte[]>("RowVersion")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAddOrUpdate()
|
||||||
|
.HasColumnType("bytea")
|
||||||
|
.HasComment("并发控制字段。");
|
||||||
|
|
||||||
b.Property<int?>("SafetyStock")
|
b.Property<int?>("SafetyStock")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasComment("安全库存阈值。");
|
.HasComment("安全库存阈值。");
|
||||||
@@ -1991,6 +2038,93 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Inventory.Entities.InventoryLockRecord", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpiresAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("过期时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<string>("IdempotencyKey")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("幂等键。");
|
||||||
|
|
||||||
|
b.Property<bool>("IsPresale")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasComment("是否预售锁定。");
|
||||||
|
|
||||||
|
b.Property<long>("ProductSkuId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("SKU ID。");
|
||||||
|
|
||||||
|
b.Property<int>("Quantity")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("锁定数量。");
|
||||||
|
|
||||||
|
b.Property<byte[]>("RowVersion")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAddOrUpdate()
|
||||||
|
.HasColumnType("bytea")
|
||||||
|
.HasComment("并发控制字段。");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("锁定状态。");
|
||||||
|
|
||||||
|
b.Property<long>("StoreId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("门店 ID。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "IdempotencyKey")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "StoreId", "ProductSkuId", "Status");
|
||||||
|
|
||||||
|
b.ToTable("inventory_lock_records", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("库存锁定记录。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TakeoutSaaS.Domain.Membership.Entities.MemberGrowthLog", b =>
|
modelBuilder.Entity("TakeoutSaaS.Domain.Membership.Entities.MemberGrowthLog", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("Id")
|
b.Property<long>("Id")
|
||||||
@@ -2441,6 +2575,145 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Merchants.Entities.MerchantAuditLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("Action")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("动作类型。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasComment("详情描述。");
|
||||||
|
|
||||||
|
b.Property<long>("MerchantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("商户标识。");
|
||||||
|
|
||||||
|
b.Property<long?>("OperatorId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("操作人 ID。");
|
||||||
|
|
||||||
|
b.Property<string>("OperatorName")
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("操作人名称。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("标题。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "MerchantId");
|
||||||
|
|
||||||
|
b.ToTable("merchant_audit_logs", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("商户入驻审核日志。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Merchants.Entities.MerchantCategory", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<int>("DisplayOrder")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasDefaultValue(0)
|
||||||
|
.HasComment("显示顺序,越小越靠前。");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasComment("是否可用。");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("类目名称。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("merchant_categories", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("商户可选类目。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TakeoutSaaS.Domain.Merchants.Entities.MerchantContract", b =>
|
modelBuilder.Entity("TakeoutSaaS.Domain.Merchants.Entities.MerchantContract", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("Id")
|
b.Property<long>("Id")
|
||||||
@@ -4489,7 +4762,8 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
|||||||
.HasComment("状态。");
|
.HasComment("状态。");
|
||||||
|
|
||||||
b.Property<long>("StoreId")
|
b.Property<long>("StoreId")
|
||||||
.HasColumnType("bigint");
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("获取或设置所属门店 ID。");
|
||||||
|
|
||||||
b.Property<long>("TenantId")
|
b.Property<long>("TenantId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("bigint")
|
||||||
@@ -5086,6 +5360,179 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Stores.Entities.StorePickupSetting", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("AllowDaysAhead")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("可预约天数(含当天)。");
|
||||||
|
|
||||||
|
b.Property<bool>("AllowToday")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasComment("是否允许当天自提。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<int>("DefaultCutoffMinutes")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasDefaultValue(30)
|
||||||
|
.HasComment("默认截单分钟(开始前多少分钟截止)。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<int?>("MaxQuantityPerOrder")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("单笔自提最大份数。");
|
||||||
|
|
||||||
|
b.Property<byte[]>("RowVersion")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAddOrUpdate()
|
||||||
|
.HasColumnType("bytea")
|
||||||
|
.HasComment("并发控制字段。");
|
||||||
|
|
||||||
|
b.Property<long>("StoreId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("门店标识。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "StoreId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("store_pickup_settings", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("门店自提配置。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Stores.Entities.StorePickupSlot", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("Capacity")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("容量(份数)。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<int>("CutoffMinutes")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasDefaultValue(30)
|
||||||
|
.HasComment("截单分钟(开始前多少分钟截止)。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<TimeSpan>("EndTime")
|
||||||
|
.HasColumnType("interval")
|
||||||
|
.HasComment("当天结束时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasComment("是否启用。");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("档期名称。");
|
||||||
|
|
||||||
|
b.Property<int>("ReservedCount")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("已占用数量。");
|
||||||
|
|
||||||
|
b.Property<byte[]>("RowVersion")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAddOrUpdate()
|
||||||
|
.HasColumnType("bytea")
|
||||||
|
.HasComment("并发控制字段。");
|
||||||
|
|
||||||
|
b.Property<TimeSpan>("StartTime")
|
||||||
|
.HasColumnType("interval")
|
||||||
|
.HasComment("当天开始时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long>("StoreId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("门店标识。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("Weekdays")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("character varying(32)")
|
||||||
|
.HasComment("适用星期(逗号分隔 1-7)。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "StoreId", "Name");
|
||||||
|
|
||||||
|
b.ToTable("store_pickup_slots", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("门店自提档期。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TakeoutSaaS.Domain.Stores.Entities.StoreTable", b =>
|
modelBuilder.Entity("TakeoutSaaS.Domain.Stores.Entities.StoreTable", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("Id")
|
b.Property<long>("Id")
|
||||||
@@ -5380,6 +5827,225 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.TenantAnnouncement", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("AnnouncementType")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("公告类型。");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasComment("公告正文(可为 Markdown/HTML,前端自行渲染)。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("EffectiveFrom")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("生效时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("EffectiveTo")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("失效时间(UTC),为空表示长期有效。");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasComment("是否启用。");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("展示优先级,数值越大越靠前。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("公告标题。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "AnnouncementType", "IsActive");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "EffectiveFrom", "EffectiveTo");
|
||||||
|
|
||||||
|
b.ToTable("tenant_announcements", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("租户公告。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.TenantAnnouncementRead", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<long>("AnnouncementId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("公告 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("ReadAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("已读时间。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UserId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("已读用户 ID(后台账号),为空表示租户级已读。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "AnnouncementId", "UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("tenant_announcement_reads", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("租户公告已读记录。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.TenantAuditLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("Action")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("操作类型。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<int?>("CurrentStatus")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("新状态。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasComment("详细描述。");
|
||||||
|
|
||||||
|
b.Property<long?>("OperatorId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("操作人 ID。");
|
||||||
|
|
||||||
|
b.Property<string>("OperatorName")
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("操作人名称。");
|
||||||
|
|
||||||
|
b.Property<int?>("PreviousStatus")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("原状态。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("关联的租户标识。");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("日志标题。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
|
b.ToTable("tenant_audit_logs", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("租户运营审核日志。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.TenantBillingStatement", b =>
|
modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.TenantBillingStatement", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("Id")
|
b.Property<long>("Id")
|
||||||
@@ -5782,6 +6448,214 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.TenantSubscriptionHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<decimal?>("Amount")
|
||||||
|
.HasColumnType("numeric")
|
||||||
|
.HasComment("相关费用。");
|
||||||
|
|
||||||
|
b.Property<int>("ChangeType")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("变更类型。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("Currency")
|
||||||
|
.HasMaxLength(8)
|
||||||
|
.HasColumnType("character varying(8)")
|
||||||
|
.HasComment("币种。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("EffectiveFrom")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("生效时间。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("EffectiveTo")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("到期时间。");
|
||||||
|
|
||||||
|
b.Property<long>("FromPackageId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("原套餐 ID。");
|
||||||
|
|
||||||
|
b.Property<string>("Notes")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)")
|
||||||
|
.HasComment("备注。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("租户标识。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantSubscriptionId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("对应的订阅 ID。");
|
||||||
|
|
||||||
|
b.Property<long>("ToPackageId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("新套餐 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "TenantSubscriptionId");
|
||||||
|
|
||||||
|
b.ToTable("tenant_subscription_histories", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("租户套餐订阅变更记录。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.TenantVerificationProfile", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AdditionalDataJson")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasComment("附加资料(JSON)。");
|
||||||
|
|
||||||
|
b.Property<string>("BankAccountName")
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("开户名。");
|
||||||
|
|
||||||
|
b.Property<string>("BankAccountNumber")
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("银行账号。");
|
||||||
|
|
||||||
|
b.Property<string>("BankName")
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("银行名称。");
|
||||||
|
|
||||||
|
b.Property<string>("BusinessLicenseNumber")
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("营业执照编号。");
|
||||||
|
|
||||||
|
b.Property<string>("BusinessLicenseUrl")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)")
|
||||||
|
.HasComment("营业执照文件地址。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("LegalPersonIdBackUrl")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)")
|
||||||
|
.HasComment("法人身份证反面。");
|
||||||
|
|
||||||
|
b.Property<string>("LegalPersonIdFrontUrl")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)")
|
||||||
|
.HasComment("法人身份证正面。");
|
||||||
|
|
||||||
|
b.Property<string>("LegalPersonIdNumber")
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("character varying(32)")
|
||||||
|
.HasComment("法人身份证号。");
|
||||||
|
|
||||||
|
b.Property<string>("LegalPersonName")
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("法人姓名。");
|
||||||
|
|
||||||
|
b.Property<string>("ReviewRemarks")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)")
|
||||||
|
.HasComment("审核备注。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ReviewedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("审核时间。");
|
||||||
|
|
||||||
|
b.Property<long?>("ReviewedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("审核人 ID。");
|
||||||
|
|
||||||
|
b.Property<string>("ReviewedByName")
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("审核人姓名。");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("实名状态。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("SubmittedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("提交时间。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("对应的租户标识。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("tenant_verification_profiles", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("租户实名认证资料。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TakeoutSaaS.Domain.Orders.Entities.OrderItem", b =>
|
modelBuilder.Entity("TakeoutSaaS.Domain.Orders.Entities.OrderItem", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("TakeoutSaaS.Domain.Orders.Entities.Order", null)
|
b.HasOne("TakeoutSaaS.Domain.Orders.Entities.Order", null)
|
||||||
|
|||||||
Reference in New Issue
Block a user