feat: 完善对象存储上传与真实条码二维码引擎,彻底剥离保底Mock数据

这个提交包含在:
xcbyy
2026-10-09 17:18:14 +08:00
父节点 6d3076cdb8
当前提交 d0f4050cdc
共有 329 个文件被更改,包括 54416 次插入 和 926 次删除

查看文件

@@ -1,7 +1,9 @@
export enum UserRoleFlag {
NONE = 0,
PLAYER = 1 << 0, // 1
EXPERT = 1 << 1, // 2
PLAYER = 1 << 0, // 1: 普通玩家/买家
EXPERT = 1 << 1, // 2: 陪玩大神/接单人
HOST = 1 << 2, // 4: 车队房主/局长
ADMIN = 1 << 3, // 8: 平台管理员/运营端
}
export enum WorkMode {
@@ -24,57 +26,181 @@ export interface UserAccount {
currentMode: WorkMode;
}
export interface ExpertCertRecord {
userId: number;
status: CertStatus;
realName?: string;
idCardNo?: string;
rejectReason?: string;
appliedAt: Date;
auditedAt?: Date;
auditedBy?: number;
}
export class AuthRoleManager {
private users = new Map<number, UserAccount>();
private certs = new Map<number, { status: CertStatus; realName?: string; idCardNo?: string }>();
private certs = new Map<number, ExpertCertRecord>();
private autoIncId = 1000;
registerUser(params: { openid: string; nickname: string }): UserAccount {
registerUser(params: { openid: string; nickname: string; initialRoles?: number }): UserAccount {
const id = ++this.autoIncId;
const user: UserAccount = {
id,
openid: params.openid,
nickname: params.nickname,
roleFlags: UserRoleFlag.PLAYER,
roleFlags: params.initialRoles ?? UserRoleFlag.PLAYER,
currentMode: WorkMode.PLAYER,
};
this.users.set(id, user);
this.certs.set(id, { status: CertStatus.NONE });
this.certs.set(id, {
userId: id,
status: CertStatus.NONE,
appliedAt: new Date(),
});
return user;
}
registerAdmin(params: { openid: string; nickname: string }): UserAccount {
return this.registerUser({
openid: params.openid,
nickname: params.nickname,
initialRoles: UserRoleFlag.PLAYER | UserRoleFlag.ADMIN,
});
}
getUser(userId: number): UserAccount {
const user = this.users.get(userId);
if (!user) throw new Error('用户不存在');
return user;
}
hasRole(userId: number, role: UserRoleFlag): boolean {
const user = this.users.get(userId);
if (!user) return false;
return (user.roleFlags & role) === role;
}
grantRole(userId: number, role: UserRoleFlag): void {
const user = this.getUser(userId);
user.roleFlags |= role;
}
revokeRole(userId: number, role: UserRoleFlag): void {
const user = this.getUser(userId);
user.roleFlags &= ~role;
}
isPlayer(userId: number): boolean {
return this.hasRole(userId, UserRoleFlag.PLAYER);
}
isExpert(userId: number): boolean {
return this.hasRole(userId, UserRoleFlag.EXPERT);
}
isHost(userId: number): boolean {
return this.hasRole(userId, UserRoleFlag.HOST);
}
isAdmin(userId: number): boolean {
return this.hasRole(userId, UserRoleFlag.ADMIN);
}
getCertStatus(userId: number): CertStatus {
return this.certs.get(userId)?.status ?? CertStatus.NONE;
}
submitExpertCert(userId: number, info: { realName: string; idCardNo: string }) {
this.certs.set(userId, {
status: CertStatus.PENDING,
realName: info.realName,
idCardNo: info.idCardNo,
});
getCertRecord(userId: number): ExpertCertRecord | undefined {
return this.certs.get(userId);
}
approveExpertCert(userId: number) {
submitExpertCert(userId: number, info: { realName: string; idCardNo: string }): ExpertCertRecord {
if (!info.realName || !info.realName.trim()) {
throw new Error('真实姓名不能为空');
}
if (!info.idCardNo || !info.idCardNo.trim()) {
throw new Error('身份证号不能为空');
}
const record: ExpertCertRecord = {
userId,
status: CertStatus.PENDING,
realName: info.realName.trim(),
idCardNo: info.idCardNo.trim(),
appliedAt: new Date(),
};
this.certs.set(userId, record);
return record;
}
approveExpertCert(userId: number, operatorAdminId?: number): ExpertCertRecord {
if (operatorAdminId !== undefined && !this.isAdmin(operatorAdminId)) {
throw new Error('只有平台管理员有权审核大神认证申请');
}
const cert = this.certs.get(userId);
if (!cert) throw new Error('未找到认证申请');
cert.status = CertStatus.APPROVED;
cert.auditedAt = new Date();
if (operatorAdminId !== undefined) {
cert.auditedBy = operatorAdminId;
}
const user = this.getUser(userId);
user.roleFlags |= UserRoleFlag.EXPERT;
return cert;
}
switchMode(userId: number, targetMode: WorkMode) {
rejectExpertCert(userId: number, reason: string, operatorAdminId?: number): ExpertCertRecord {
if (operatorAdminId !== undefined && !this.isAdmin(operatorAdminId)) {
throw new Error('只有平台管理员有权审核大神认证申请');
}
const cert = this.certs.get(userId);
if (!cert) throw new Error('未找到认证申请');
cert.status = CertStatus.REJECTED;
cert.rejectReason = reason;
cert.auditedAt = new Date();
if (operatorAdminId !== undefined) {
cert.auditedBy = operatorAdminId;
}
return cert;
}
switchMode(userId: number, targetMode: WorkMode): void {
const user = this.getUser(userId);
if (targetMode === WorkMode.EXPERT && !(user.roleFlags & UserRoleFlag.EXPERT)) {
throw new Error('尚未开通或通过大神认证,无法切换至接单模式');
}
user.currentMode = targetMode;
}
checkCanClaimOrder(userId: number): void {
const user = this.getUser(userId);
if (!(user.roleFlags & UserRoleFlag.EXPERT) || this.getCertStatus(userId) !== CertStatus.APPROVED) {
throw new Error('未认证大神无法接单');
}
}
checkCanAudit(operatorId: number): void {
if (!this.isAdmin(operatorId)) {
throw new Error('只有平台管理员有权审核大神认证申请');
}
}
checkCanArbitrate(operatorId: number): void {
if (!this.isAdmin(operatorId)) {
throw new Error('只有平台管理员有权执行争议仲裁');
}
}
checkCanAdjustPrice(operatorId: number, creatorId: number): void {
if (operatorId !== creatorId && !this.isAdmin(operatorId)) {
throw new Error('只有发起人有权调整活动出价');
}
}
checkCanDissolveActivity(operatorId: number, creatorId: number): void {
if (operatorId !== creatorId && !this.isAdmin(operatorId)) {
throw new Error('只有发起人有权解散此组局');
}
}
}