fix(order,encoding): 修复订单创建字段名不匹配和中文乱码问题

- 前端 productType/userInfo 改为 orderType/assessmentInfo 对齐后端 DTO
- 添加 gender/age/educationStage 数据格式转换(字符串转int)
- Program.cs 设置 Console.OutputEncoding = UTF8 解决日志中文乱码
- AddJsonOptions 配置 UnsafeRelaxedJsonEscaping 解决响应中文转义
- Dockerfile 添加 LANG/LC_ALL=C.UTF-8 环境变量
This commit is contained in:
zpc 2026-02-21 13:18:11 +08:00
parent 4bba7f8e53
commit f082f20fc8
7 changed files with 55 additions and 9 deletions

View File

@ -30,6 +30,9 @@ RUN dotnet publish MiAssessment.Admin.csproj -c $BUILD_CONFIGURATION -o /app/pub
# ==================== 阶段3: 最终运行镜像 ====================
FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble AS final
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
# 安装 SkiaSharp 原生依赖(用于验证码生成等图形处理)
RUN apt-get update && apt-get install -y \

View File

@ -5,6 +5,11 @@ using MiAssessment.Model.Data;
using Microsoft.EntityFrameworkCore;
using Scalar.AspNetCore;
using Serilog;
using System.Text;
// 设置控制台输出编码为 UTF-8解决中文乱码
Console.OutputEncoding = Encoding.UTF8;
Console.InputEncoding = Encoding.UTF8;
var builder = WebApplication.CreateBuilder(args);
@ -19,6 +24,11 @@ var mvcBuilder = builder.Services.AddControllers(options =>
{
options.Filters.Add<AdminExceptionFilter>();
options.Filters.Add<BusinessPermissionFilter>();
})
.AddJsonOptions(options =>
{
// 允许中文直接输出,不转义为 \uXXXX
options.JsonSerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApi();

View File

@ -2,6 +2,9 @@
# ==================== 阶段1: 基础运行环境 ====================
FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble AS base
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
USER $APP_UID
WORKDIR /app
EXPOSE 8080

View File

@ -19,6 +19,10 @@ using Serilog;
using System.Text;
// 设置控制台输出编码为 UTF-8解决中文乱码
Console.OutputEncoding = Encoding.UTF8;
Console.InputEncoding = Encoding.UTF8;
// 配置 Serilog
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(new ConfigurationBuilder()
@ -113,6 +117,11 @@ try
{
// 添加全局异常过滤器
options.Filters.Add<GlobalExceptionFilter>();
})
.AddJsonOptions(options =>
{
// 允许中文直接输出,不转义为 \uXXXX
options.JsonSerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
});
// 配置 OpenAPI.NET 10 内置支持)

View File

@ -28,9 +28,11 @@ export function getOrderDetail(orderId) {
/**
* 创建订单
* @param {Object} data - 订单数据
* @param {number} data.productType - 产品类型
* @param {number} data.orderType - 订单类型1测评订单 2规划订单
* @param {number} data.productId - 产品ID
* @param {Object} [data.userInfo] - 用户信息
* @param {Object} [data.assessmentInfo] - 测评信息测评订单时必填
* @param {Object} [data.plannerInfo] - 规划预约信息规划订单时必填
* @param {number} [data.inviteCodeId] - 邀请码ID
* @returns {Promise<Object>}
*/
export function createOrder(data) {

View File

@ -16,9 +16,11 @@ export function usePayment() {
/**
* 创建订单
* @param {Object} params - 订单参数
* @param {number} params.productType - 产品类型
* @param {number} params.orderType - 订单类型1测评订单 2规划订单
* @param {number} params.productId - 产品ID
* @param {Object} [params.userInfo] - 用户信息
* @param {Object} [params.assessmentInfo] - 测评信息测评订单时必填
* @param {Object} [params.plannerInfo] - 规划预约信息规划订单时必填
* @param {number} [params.inviteCodeId] - 邀请码ID
* @returns {Promise<Object|null>}
*/
async function handleCreateOrder(params) {

View File

@ -51,6 +51,23 @@ const genderOptions = ['男', '女']
const ageOptions = Array.from({ length: 41 }, (_, i) => `${i + 10}`)
const educationOptions = ['小学及以下', '初中', '高中', '大专', '本科', '研究生及以上']
/**
* 学业阶段文本转数值
* @param {string} label - 学业阶段文本
* @returns {number} 学段值1小学 2初中 3高中 4大学
*/
function getEducationStageValue(label) {
const map = {
'小学及以下': 1,
'初中': 2,
'高中': 3,
'大专': 4,
'本科': 4,
'研究生及以上': 4
}
return map[label] || 1
}
//
const genderIndex = ref(-1)
const ageIndex = ref(-1)
@ -184,14 +201,14 @@ async function handlePayAssessment() {
//
const result = await processPayment({
productType: 1, //
orderType: 1, //
productId: typeId.value,
userInfo: {
assessmentInfo: {
name: formData.value.name,
phone: formData.value.phone,
gender: formData.value.gender,
age: formData.value.age,
educationStage: formData.value.educationStage,
gender: formData.value.gender === '男' ? 1 : 2,
age: parseInt(formData.value.age) || 0,
educationStage: getEducationStageValue(formData.value.educationStage),
province: formData.value.province,
city: formData.value.city,
district: formData.value.district