新增个人中心页面与用户资料自助修改接口

- 新增 GET/PUT /api/me:登录用户可查看并修改自己的 nickname/gender/birthday,空串清空、缺省保持不变,生日校验格式与未来日期
- users 表新增 gender/birthday 字段(迁移 v6)及 model.Date 日期类型,管理员用户接口同步支持
- 前端新增 /profile 个人中心页面、头像下拉入口与登录守卫,保存后同步会话用户信息
- 静态服务对未命中的无扩展名路径回退 index.html,避免刷新前端路由 404
- 重新生成 Swagger 文档,补充 /api/me 与资料字段相关测试
This commit is contained in:
2026-09-21 16:05:23 +08:00
parent 2d7f4a63fe
commit 1fec77e81f
22 files changed
+1302 -18

No files matched your search

+152 -2
View File
@@ -151,6 +151,104 @@ const docTemplate = `{
}
}
},
"/me": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Return the authenticated user's profile, including groups.",
"produces": [
"application/json"
],
"tags": [
"profile"
],
"summary": "Get current user profile",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/model.User"
}
},
"401": {
"description": "unauthorized or session expired",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
},
"403": {
"description": "account disabled",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
}
}
},
"put": {
"security": [
{
"BearerAuth": []
}
],
"description": "Update the authenticated user's nickname, gender, and birthday. birthday accepts YYYY-MM-DD, an empty string clears it, and omitting it keeps the current value.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"profile"
],
"summary": "Update current user profile",
"parameters": [
{
"description": "Fields to update",
"name": "profile",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/auth.UpdateProfileRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/model.User"
}
},
"400": {
"description": "invalid request",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
},
"401": {
"description": "unauthorized or session expired",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
},
"403": {
"description": "account disabled",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
}
}
}
},
"/notes": {
"get": {
"security": [
@@ -873,7 +971,7 @@ const docTemplate = `{
"BearerAuth": []
}
],
"description": "Create a user and assign groups. username and email are unique; password is 6-72 chars; defaults to the regular user group (id 1) when group_ids is omitted.",
"description": "Create a user and assign groups. username and email are unique; password is 6-72 chars; gender is male/female/other; birthday is YYYY-MM-DD and cannot be in the future; defaults to the regular user group (id 1) when group_ids is omitted.",
"consumes": [
"application/json"
],
@@ -1005,7 +1103,7 @@ const docTemplate = `{
"BearerAuth": []
}
],
"description": "Update user fields. group_ids replaces all groups; a non-empty password resets the password.",
"description": "Update user fields. group_ids replaces all groups; a non-empty password resets the password; birthday accepts YYYY-MM-DD, an empty string clears it, and omitting it keeps the current value.",
"consumes": [
"application/json"
],
@@ -1210,6 +1308,24 @@ const docTemplate = `{
}
}
},
"auth.UpdateProfileRequest": {
"type": "object",
"properties": {
"birthday": {
"type": "string",
"example": "1995-06-15"
},
"gender": {
"type": "string",
"example": "male"
},
"nickname": {
"type": "string",
"maxLength": 50,
"example": "Alice"
}
}
},
"httpx.ErrorResponse": {
"type": "object",
"properties": {
@@ -1245,12 +1361,20 @@ const docTemplate = `{
"avatar": {
"type": "string"
},
"birthday": {
"type": "string",
"example": "1995-06-15"
},
"created_at": {
"type": "string"
},
"email": {
"type": "string"
},
"gender": {
"type": "string",
"example": "male"
},
"groups": {
"type": "array",
"items": {
@@ -1350,11 +1474,24 @@ const docTemplate = `{
"maxLength": 255,
"example": "https://example.com/avatar.png"
},
"birthday": {
"type": "string",
"example": "1995-06-15"
},
"email": {
"type": "string",
"maxLength": 255,
"example": "alice@example.com"
},
"gender": {
"type": "string",
"enum": [
"male",
"female",
"other"
],
"example": "male"
},
"group_ids": {
"type": "array",
"items": {
@@ -1421,6 +1558,19 @@ const docTemplate = `{
"maxLength": 255,
"example": "https://example.com/avatar.png"
},
"birthday": {
"type": "string",
"example": "1995-06-15"
},
"gender": {
"type": "string",
"enum": [
"male",
"female",
"other"
],
"example": "male"
},
"group_ids": {
"type": "array",
"items": {
+152 -2
View File
@@ -144,6 +144,104 @@
}
}
},
"/me": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Return the authenticated user's profile, including groups.",
"produces": [
"application/json"
],
"tags": [
"profile"
],
"summary": "Get current user profile",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/model.User"
}
},
"401": {
"description": "unauthorized or session expired",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
},
"403": {
"description": "account disabled",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
}
}
},
"put": {
"security": [
{
"BearerAuth": []
}
],
"description": "Update the authenticated user's nickname, gender, and birthday. birthday accepts YYYY-MM-DD, an empty string clears it, and omitting it keeps the current value.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"profile"
],
"summary": "Update current user profile",
"parameters": [
{
"description": "Fields to update",
"name": "profile",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/auth.UpdateProfileRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/model.User"
}
},
"400": {
"description": "invalid request",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
},
"401": {
"description": "unauthorized or session expired",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
},
"403": {
"description": "account disabled",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/httpx.ErrorResponse"
}
}
}
}
},
"/notes": {
"get": {
"security": [
@@ -866,7 +964,7 @@
"BearerAuth": []
}
],
"description": "Create a user and assign groups. username and email are unique; password is 6-72 chars; defaults to the regular user group (id 1) when group_ids is omitted.",
"description": "Create a user and assign groups. username and email are unique; password is 6-72 chars; gender is male/female/other; birthday is YYYY-MM-DD and cannot be in the future; defaults to the regular user group (id 1) when group_ids is omitted.",
"consumes": [
"application/json"
],
@@ -998,7 +1096,7 @@
"BearerAuth": []
}
],
"description": "Update user fields. group_ids replaces all groups; a non-empty password resets the password.",
"description": "Update user fields. group_ids replaces all groups; a non-empty password resets the password; birthday accepts YYYY-MM-DD, an empty string clears it, and omitting it keeps the current value.",
"consumes": [
"application/json"
],
@@ -1203,6 +1301,24 @@
}
}
},
"auth.UpdateProfileRequest": {
"type": "object",
"properties": {
"birthday": {
"type": "string",
"example": "1995-06-15"
},
"gender": {
"type": "string",
"example": "male"
},
"nickname": {
"type": "string",
"maxLength": 50,
"example": "Alice"
}
}
},
"httpx.ErrorResponse": {
"type": "object",
"properties": {
@@ -1238,12 +1354,20 @@
"avatar": {
"type": "string"
},
"birthday": {
"type": "string",
"example": "1995-06-15"
},
"created_at": {
"type": "string"
},
"email": {
"type": "string"
},
"gender": {
"type": "string",
"example": "male"
},
"groups": {
"type": "array",
"items": {
@@ -1343,11 +1467,24 @@
"maxLength": 255,
"example": "https://example.com/avatar.png"
},
"birthday": {
"type": "string",
"example": "1995-06-15"
},
"email": {
"type": "string",
"maxLength": 255,
"example": "alice@example.com"
},
"gender": {
"type": "string",
"enum": [
"male",
"female",
"other"
],
"example": "male"
},
"group_ids": {
"type": "array",
"items": {
@@ -1414,6 +1551,19 @@
"maxLength": 255,
"example": "https://example.com/avatar.png"
},
"birthday": {
"type": "string",
"example": "1995-06-15"
},
"gender": {
"type": "string",
"enum": [
"male",
"female",
"other"
],
"example": "male"
},
"group_ids": {
"type": "array",
"items": {
+108 -3
View File
@@ -53,6 +53,19 @@ definitions:
- password
- username
type: object
auth.UpdateProfileRequest:
properties:
birthday:
example: "1995-06-15"
type: string
gender:
example: male
type: string
nickname:
example: Alice
maxLength: 50
type: string
type: object
httpx.ErrorResponse:
properties:
error:
@@ -76,10 +89,16 @@ definitions:
properties:
avatar:
type: string
birthday:
example: "1995-06-15"
type: string
created_at:
type: string
email:
type: string
gender:
example: male
type: string
groups:
items:
$ref: '#/definitions/model.UserGroup'
@@ -144,10 +163,20 @@ definitions:
example: https://example.com/avatar.png
maxLength: 255
type: string
birthday:
example: "1995-06-15"
type: string
email:
example: alice@example.com
maxLength: 255
type: string
gender:
enum:
- male
- female
- other
example: male
type: string
group_ids:
example:
- 1
@@ -200,6 +229,16 @@ definitions:
example: https://example.com/avatar.png
maxLength: 255
type: string
birthday:
example: "1995-06-15"
type: string
gender:
enum:
- male
- female
- other
example: male
type: string
group_ids:
example:
- 1
@@ -353,6 +392,70 @@ paths:
summary: Health check
tags:
- system
/me:
get:
description: Return the authenticated user's profile, including groups.
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/model.User'
"401":
description: unauthorized or session expired
schema:
$ref: '#/definitions/httpx.ErrorResponse'
"403":
description: account disabled
schema:
$ref: '#/definitions/httpx.ErrorResponse'
security:
- BearerAuth: []
summary: Get current user profile
tags:
- profile
put:
consumes:
- application/json
description: Update the authenticated user's nickname, gender, and birthday.
birthday accepts YYYY-MM-DD, an empty string clears it, and omitting it keeps
the current value.
parameters:
- description: Fields to update
in: body
name: profile
required: true
schema:
$ref: '#/definitions/auth.UpdateProfileRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/model.User'
"400":
description: invalid request
schema:
$ref: '#/definitions/httpx.ErrorResponse'
"401":
description: unauthorized or session expired
schema:
$ref: '#/definitions/httpx.ErrorResponse'
"403":
description: account disabled
schema:
$ref: '#/definitions/httpx.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/httpx.ErrorResponse'
security:
- BearerAuth: []
summary: Update current user profile
tags:
- profile
/notes:
get:
description: List notes ordered by id DESC. page starts at 1; page_size is 1-100,
@@ -827,8 +930,9 @@ paths:
consumes:
- application/json
description: Create a user and assign groups. username and email are unique;
password is 6-72 chars; defaults to the regular user group (id 1) when group_ids
is omitted.
password is 6-72 chars; gender is male/female/other; birthday is YYYY-MM-DD
and cannot be in the future; defaults to the regular user group (id 1) when
group_ids is omitted.
parameters:
- description: User payload
in: body
@@ -954,7 +1058,8 @@ paths:
consumes:
- application/json
description: Update user fields. group_ids replaces all groups; a non-empty
password resets the password.
password resets the password; birthday accepts YYYY-MM-DD, an empty string
clears it, and omitting it keeps the current value.
parameters:
- description: User ID
example: 1