feat: 注册绑定所属顾问与岗位职级字典种子
支持 AdvisorCode 写入 CustomerService=Account;补充 employee_position/employee_job_level 初始 SQL。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
7e9a5d4ae0
commit
eba1fa4867
80
sql/migrate_dict_employee_position.sql
Normal file
80
sql/migrate_dict_employee_position.sql
Normal file
@ -0,0 +1,80 @@
|
||||
-- 员工档案「岗位 / 职级」字典初始数据(幂等:已存在同 DictType+DictCode 则跳过)
|
||||
-- dictType: employee_position / employee_job_level
|
||||
-- MySQL 5.7+ / 8.0
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- ========== 岗位 employee_position ==========
|
||||
INSERT INTO `t_dict_type` (`DictType`, `Remark`, `TypeSort`, `IsDeleted`, `CreateUserId`)
|
||||
SELECT 'employee_position', '员工岗位', 0, 0, 0
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM `t_dict_type` WHERE `DictType` = 'employee_position' AND `IsDeleted` = 0
|
||||
);
|
||||
|
||||
INSERT INTO `t_dict` (`DictType`, `DictSort`, `DictCode`, `DictName`, `IsDeleted`, `CreateUserId`)
|
||||
SELECT v.`DictType`, v.`DictSort`, v.`DictCode`, v.`DictName`, 0, 0
|
||||
FROM (
|
||||
SELECT 'employee_position' AS DictType, 1 AS DictSort, 'generalManager' AS DictCode, '总经理' AS DictName
|
||||
UNION ALL SELECT 'employee_position', 2, 'deputyGeneralManager', '副总经理'
|
||||
UNION ALL SELECT 'employee_position', 3, 'logisticsAdvisor', '物流顾问'
|
||||
UNION ALL SELECT 'employee_position', 4, 'csManager', '客服主管'
|
||||
UNION ALL SELECT 'employee_position', 5, 'csSpecialist', '客服专员'
|
||||
UNION ALL SELECT 'employee_position', 6, 'opsManager', '运营经理'
|
||||
UNION ALL SELECT 'employee_position', 7, 'opsSpecialist', '运营专员'
|
||||
UNION ALL SELECT 'employee_position', 8, 'financeManager', '财务经理'
|
||||
UNION ALL SELECT 'employee_position', 9, 'financeSpecialist', '财务专员'
|
||||
UNION ALL SELECT 'employee_position', 10, 'warehouseManager', '仓储主管'
|
||||
UNION ALL SELECT 'employee_position', 11, 'warehouseClerk', '仓管员'
|
||||
UNION ALL SELECT 'employee_position', 12, 'customsSpecialist', '关务专员'
|
||||
UNION ALL SELECT 'employee_position', 13, 'productManager', '产品经理'
|
||||
UNION ALL SELECT 'employee_position', 14, 'techEngineer', '技术工程师'
|
||||
UNION ALL SELECT 'employee_position', 15, 'hrAdmin', '人事行政'
|
||||
UNION ALL SELECT 'employee_position', 16, 'marketingSpecialist', '市场专员'
|
||||
UNION ALL SELECT 'employee_position', 17, 'dispatcher', '调度员'
|
||||
) AS v
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM `t_dict` d
|
||||
WHERE d.`DictType` = v.`DictType`
|
||||
AND d.`DictCode` = v.`DictCode`
|
||||
AND d.`IsDeleted` = 0
|
||||
);
|
||||
|
||||
UPDATE `t_dict`
|
||||
SET `IsDeleted` = 1,
|
||||
`UpdateTime` = NOW()
|
||||
WHERE `DictType` = 'employee_position'
|
||||
AND `DictCode` IN (
|
||||
'salesDirector',
|
||||
'salesManager',
|
||||
'salesSpecialist',
|
||||
'logisticsAdvisorDirector',
|
||||
'logisticsAdvisorManager'
|
||||
)
|
||||
AND `IsDeleted` = 0;
|
||||
|
||||
-- ========== 职级 employee_job_level(一级~五级) ==========
|
||||
INSERT INTO `t_dict_type` (`DictType`, `Remark`, `TypeSort`, `IsDeleted`, `CreateUserId`)
|
||||
SELECT 'employee_job_level', '员工职级', 0, 0, 0
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM `t_dict_type` WHERE `DictType` = 'employee_job_level' AND `IsDeleted` = 0
|
||||
);
|
||||
|
||||
INSERT INTO `t_dict` (`DictType`, `DictSort`, `DictCode`, `DictName`, `IsDeleted`, `CreateUserId`)
|
||||
SELECT v.`DictType`, v.`DictSort`, v.`DictCode`, v.`DictName`, 0, 0
|
||||
FROM (
|
||||
SELECT 'employee_job_level' AS DictType, 1 AS DictSort, '1' AS DictCode, '一级' AS DictName
|
||||
UNION ALL SELECT 'employee_job_level', 2, '2', '二级'
|
||||
UNION ALL SELECT 'employee_job_level', 3, '3', '三级'
|
||||
UNION ALL SELECT 'employee_job_level', 4, '4', '四级'
|
||||
UNION ALL SELECT 'employee_job_level', 5, '5', '五级'
|
||||
) AS v
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM `t_dict` d
|
||||
WHERE d.`DictType` = v.`DictType`
|
||||
AND d.`DictCode` = v.`DictCode`
|
||||
AND d.`IsDeleted` = 0
|
||||
);
|
||||
@ -118,4 +118,10 @@ public class CreateCustomerInput
|
||||
[StringLength(16)]
|
||||
public string? InviteCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 顾问邀请码(所属顾问绑定,值为员工 Account;仅 CustomerService 为空时生效)。
|
||||
/// </summary>
|
||||
[StringLength(64)]
|
||||
public string? AdvisorCode { get; set; }
|
||||
|
||||
}
|
||||
|
||||
@ -233,6 +233,10 @@ public class CustomerService : ApplicationService
|
||||
input.InviteCode,
|
||||
ReferralCodeRepository,
|
||||
CustomerRepository);
|
||||
await StaffAdvisorBinder.BindAdvisorOnCreateAsync(
|
||||
entity,
|
||||
input.AdvisorCode,
|
||||
RbacDbContext);
|
||||
await CustomerRepository.InsertAsync(entity);
|
||||
try
|
||||
{
|
||||
|
||||
67
src/Oms.Application/Shared/StaffAdvisorBinder.cs
Normal file
67
src/Oms.Application/Shared/StaffAdvisorBinder.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using Fake.Rbac.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Oms.Domain.CustomersAggregate.Entities;
|
||||
|
||||
namespace Oms.Application.Shared;
|
||||
|
||||
/// <summary>
|
||||
/// 顾问邀请绑定:注册时把所属顾问(CustomerService)写成员工登录账号。
|
||||
/// </summary>
|
||||
public static class StaffAdvisorBinder
|
||||
{
|
||||
/// <summary>
|
||||
/// 仅在 CustomerService 为空时绑定;advisorCode 为员工 Account(来自 ?advisor=)。
|
||||
/// 无效账号静默跳过,不阻断注册。
|
||||
/// </summary>
|
||||
public static async Task BindAdvisorOnCreateAsync(
|
||||
Customer entity,
|
||||
string? advisorCode,
|
||||
FakeRbacDbContext rbacDbContext,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(entity.CustomerService))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var key = advisorCode?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var account = await ResolveStaffAccountAsync(rbacDbContext, key, cancellationToken);
|
||||
if (string.IsNullOrWhiteSpace(account))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
entity.CustomerService = account;
|
||||
}
|
||||
|
||||
private static async Task<string?> ResolveStaffAccountAsync(
|
||||
FakeRbacDbContext rbacDbContext,
|
||||
string key,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
const string sql = """
|
||||
SELECT u.`Account` AS `Account`
|
||||
FROM `user` u
|
||||
WHERE u.`IsDeleted` = 0
|
||||
AND u.`Account` = {0}
|
||||
ORDER BY u.`CreateTime` ASC
|
||||
LIMIT 1
|
||||
""";
|
||||
|
||||
var row = await rbacDbContext.Database
|
||||
.SqlQueryRaw<AccountRow>(sql, key)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
return string.IsNullOrWhiteSpace(row?.Account) ? null : row.Account.Trim();
|
||||
}
|
||||
|
||||
private sealed class AccountRow
|
||||
{
|
||||
public string? Account { get; set; }
|
||||
}
|
||||
}
|
||||
@ -96,6 +96,11 @@ public class WeChatCustomerRegisterInput
|
||||
/// </summary>
|
||||
public string? InviteCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 顾问邀请码(可选)。来自 ?advisor=,值为员工登录账号;注册时写入所属顾问 CustomerService。
|
||||
/// </summary>
|
||||
public string? AdvisorCode { get; set; }
|
||||
|
||||
[Required]
|
||||
public WeChatProfileInput Wechat { get; set; } = new();
|
||||
}
|
||||
|
||||
@ -164,6 +164,11 @@ public class WeChatCustomerService(
|
||||
{
|
||||
entity.ReferralChannel = "wechat";
|
||||
}
|
||||
await StaffAdvisorBinder.BindAdvisorOnCreateAsync(
|
||||
entity,
|
||||
input.AdvisorCode,
|
||||
rbacDbContext,
|
||||
cancellationToken);
|
||||
await customerRepository.InsertAsync(entity);
|
||||
|
||||
try
|
||||
|
||||
Loading…
Reference in New Issue
Block a user