feat(release): v3.4.13 experience optimizations across admin, mini-user, and H5 login

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-05 22:34:29 +08:00
parent 490c26a7e1
commit 1c4b986924
29 changed files with 617 additions and 23 deletions
@@ -116,6 +116,15 @@ export const SYSTEM_CONFIG_FIELDS: SystemConfigFieldMeta[] = [
requiresRestart: false,
description: '小程序商品首页底部 footer,建议比例 15:4;上传后需点击右上角「保存」',
},
{
key: 'MINI_USER_MIN_VERSION',
label: '小程序最低版本',
group: G.wechat_mini,
type: 'string',
requiresRestart: false,
placeholder: '3.4.13',
description: 'semver 格式;客户端低于此版本时提示更新',
},
{ key: 'OSS_ACCESS_KEY_ID', label: 'OSS AccessKey ID', group: G.oss, type: 'password', secret: true, requiresRestart: true },
{ key: 'OSS_ACCESS_KEY_SECRET', label: 'OSS AccessKey Secret', group: G.oss, type: 'password', secret: true, requiresRestart: true },
@@ -11,6 +11,7 @@ export class ClientConfigController {
const cfg = this.systemConfig.getAppConfig();
const env = this.systemConfig.getMergedEnv();
const footer = (env.MINI_HOME_FOOTER_URL ?? '').trim();
const minClientVersion = (env.MINI_USER_MIN_VERSION ?? '').trim() || null;
return {
mockPay: cfg.mockPay,
wechatPayEnabled: cfg.wechatPayEnabled,
@@ -19,6 +20,7 @@ export class ClientConfigController {
wxAuthorize: cfg.wxAuthorize,
/** 可选暴露;选点已改为服务端 /common/lbs,前端可不依赖此字段 */
tencentLbsKey: cfg.tencentLbsKey || undefined,
minClientVersion,
miniHome: {
banners: parseMiniHomeBanners(env.MINI_HOME_BANNERS),
footerUrl: footer || null,
@@ -11,6 +11,10 @@ export class SupportTicketListQueryDto {
@IsIn(['PENDING_REVIEW', 'REJECTED', 'DEVELOPING', 'TESTING', 'PASSED'])
status?: string;
@IsOptional()
@IsIn(['LOW', 'NORMAL', 'HIGH', 'URGENT'])
priority?: string;
@IsOptional()
@Type(() => Number)
@IsInt()
@@ -46,6 +50,10 @@ export class CreateSupportTicketDto {
@IsArray()
@IsString({ each: true })
attachmentUrls?: string[];
@IsOptional()
@IsIn(['LOW', 'NORMAL', 'HIGH', 'URGENT'])
priority?: string;
}
export class UpdateSupportTicketDto {
@@ -72,6 +80,10 @@ export class UpdateSupportTicketDto {
@IsArray()
@IsString({ each: true })
attachmentUrls?: string[];
@IsOptional()
@IsIn(['LOW', 'NORMAL', 'HIGH', 'URGENT'])
priority?: string;
}
export class BatchUpdateSupportTicketStatusDto {
@@ -3,7 +3,7 @@ import {
Injectable,
NotFoundException,
} from '@nestjs/common';
import type { SupportTicketStatus, SupportTicketType } from '@prisma/client';
import type { SupportTicketStatus, SupportTicketType, SupportTicketPriority } from '@prisma/client';
import { Prisma } from '@prisma/client';
import type { CreateDevPlanTaskFromTicketInput } from '@dukang/shared-types';
import { mapSupportTicketTypeToDevPlanTask } from '@dukang/shared-types';
@@ -68,6 +68,7 @@ export class SupportTicketService {
title: dto.title.trim(),
content: dto.content?.trim() || null,
remark: dto.remark?.trim() || null,
priority: (dto.priority as SupportTicketPriority | undefined) ?? 'NORMAL',
attachmentUrls: dto.attachmentUrls?.length
? (dto.attachmentUrls.map((u) => u.trim()).filter(Boolean) as unknown as Prisma.InputJsonValue)
: undefined,
@@ -178,6 +179,7 @@ export class SupportTicketService {
const urls = dto.attachmentUrls.map((u) => u.trim()).filter(Boolean);
data.attachmentUrls = urls.length ? (urls as unknown as Prisma.InputJsonValue) : Prisma.JsonNull;
}
if (dto.priority != null) data.priority = dto.priority as SupportTicketPriority;
const updated = await this.prisma.commonSupportTicket.update({ where: { id }, data });
return serializeBigInt(mapSupportTicketRow(updated));
}
@@ -247,6 +249,9 @@ export class SupportTicketService {
if (query.status) {
where.status = query.status as SupportTicketStatus;
}
if (query.priority) {
where.priority = query.priority as SupportTicketPriority;
}
const [items, total] = await Promise.all([
this.prisma.commonSupportTicket.findMany({
@@ -1692,6 +1692,10 @@ export class AuthService {
throw new BadRequestException('首次登录请使用手机验证码,登录后将自动关联微信');
}
if (account.status !== 'ACTIVE') {
throw new BadRequestException('合伙人账号已停用');
}
account = await this.prisma.partnerAccount.update({
where: { id: account.id },
data: {