feat(admin): 新增模板管理功能并完善用户认证

- 新增模板管理模块,包含模板列表和详情页面
- 重构用户认证逻辑,支持用户ID存储和API调用
- 新增排行榜API接口和类型定义
- 更新环境配置,添加开发环境配置
- 优化表格操作钩子,增强类型安全性
- 新增文件上传工具类和验证工具函数
- 更新路由配置,支持模板详情页面导航
- 修复登录表单默认值问题
This commit is contained in:
2026-01-27 09:48:42 +08:00
parent 264f600250
commit 5a48a65ef8
56 changed files with 2907 additions and 434 deletions

View File

@ -31,6 +31,21 @@ declare namespace Api {
*/
type EnableStatus = '1' | '2'
/** question ui type */
type QuestionUiType = '1' | '2' | '3' | '4' /** 文本输入 | 单选 | 多选 | 下拉选择 */
/** question time type */
type QuestionTimeType = 5 | 10 | 15 | 20 | 30 | 45 | 60 | 90 /** 5s | 10s | 15s | 20s | 30s | 45s | 60s | 90s */
/** question template id */
type QuestionTemplateId =
| 'TEMPLATE_DICTATION_HINT'
| 'TEMPLATE_DICTATION_HOMOPHONE'
| 'TEMPLATE_COMPONENT_ADD'
| 'TEMPLATE_WORD_DICTATION'
| 'TEMPLATE_IDIOM_TEXT_REQ'
| 'TEMPLATE_IDIOM_IMAGE' /** 汉字听写-提示 | 汉字听写-同音 | 汉字加一加 | 词语听写 | 成语-文字要求 | 成语-看图 */
/** question score type */
type QuestionScoreType = '1' | '2' /** 固定分数 | 答题个数 */

View File

@ -8,6 +8,7 @@ declare namespace Api {
interface LoginToken {
token: string
refreshToken: string
id: number
}
interface UserInfo {

View File

@ -7,21 +7,21 @@ declare namespace Api {
namespace Common {
/** common params of paginating */
interface PaginatingCommonParams {
/** current page number */
current: number
/** page size */
size: number
/** currentPage page number */
currentPage: number
/** page pageSize */
pageSize: number
/** total count */
total: number
}
/** common params of paginating query list data */
interface PaginatingQueryRecord<T = any> extends PaginatingCommonParams {
records: T[]
list: T[]
}
/** common search params of table */
type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'current' | 'size'>
type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'currentPage' | 'pageSize'>
/**
* enable status

View File

@ -0,0 +1,66 @@
/**
* Namespace Api
*
* All backend api type
*/
declare namespace Api {
namespace Question {
/** common params of paginating */
interface PaginatingCommonParams {
/** current page number */
current: number
/** page size */
size: number
/** total count */
total: number
}
/** common params of paginating query list data */
interface PaginatingQueryRecord<T = any> extends PaginatingCommonParams {
records: T[]
}
/** add params */
interface AddParams {
/** question id */
id: string
/** question name */
name: string
/** question content */
questionContent: string
}
/** common search params of table */
type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'current' | 'size'>
/**
* enable status
*
* - "1": enabled
* - "2": disabled
*/
type EnableStatus = '1' | '2'
/** question score type */
type QuestionScoreType = '1' | '2' /** 固定分数 | 答题个数 */
/** competition round type */
type CompetitionRoundType = '1' | '2' /** 题包环节 | 加时环节 */
/** common record */
type CommonRecord<T = any> = {
/** record id */
id: number
/** record creator */
createBy: string
/** record create time */
createTime: string
/** record updater */
updateBy: string
/** record update time */
updateTime: string
/** record status */
status: EnableStatus | null
} & T
}
}

64
apps/admin/src/typings/api/rank.d.ts vendored Normal file
View File

@ -0,0 +1,64 @@
/**
* Namespace Api
*
* All backend api type
*/
declare namespace Api {
namespace Rank {
/** common params of paginating */
interface PaginatingCommonParams {
/** currentPage page number */
currentPage: number
/** page pageSize */
pageSize: number
/** total count */
total?: number
}
/** user search params */
interface UserSearchParams extends PaginatingCommonParams {
/** competition activity name */
competitionActivityName?: string
/** publish status */
publishStatus?: EnableStatus
}
/** common params of paginating query list data */
interface PaginatingQueryRecord<T = any> extends PaginatingCommonParams {
records: T[]
}
/** common search params of table */
type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'currentPage' | 'pageSize'>
/**
* enable status
*
* - "1": enabled
* - "2": disabled
*/
type EnableStatus = '1' | '2'
/** question score type */
type QuestionScoreType = '1' | '2' /** 固定分数 | 答题个数 */
/** competition round type */
type CompetitionRoundType = '1' | '2' /** 题包环节 | 加时环节 */
/** common record */
type CommonRecord<T = any> = {
/** record id */
id: number
/** record creator */
createBy: string
/** record create time */
createTime: string
/** record updater */
updateBy: string
/** record update time */
updateTime: string
/** record status */
status: EnableStatus | null
} & T
}
}

View File

@ -0,0 +1,72 @@
/**
* Namespace Api
*
* All backend api type
*/
declare namespace Api {
namespace Template {
/** common params of paginating */
interface PaginatingCommonParams {
/** currentPage page number */
currentPage: number
/** page pageSize */
pageSize: number
/** total count */
total?: number
}
/** template search params */
interface TemplateSearchParams extends PaginatingCommonParams {
/** competition activity name */
competitionActivityName?: string
/** publish status */
publishStatus?: EnableStatus
/** template name */
templateName?: string
/** competition id */
competitionId?: string
/** size */
size?: string
/** status */
status?: EnableStatus | null
}
/** common params of paginating query list data */
interface PaginatingQueryRecord<T = any> extends PaginatingCommonParams {
records: T[]
}
/** common search params of table */
type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'currentPage' | 'pageSize'>
/**
* enable status
*
* - "1": enabled
* - "2": disabled
*/
type EnableStatus = '1' | '2'
/** question score type */
type QuestionScoreType = '1' | '2' /** 固定分数 | 答题个数 */
/** competition round type */
type CompetitionRoundType = '1' | '2' /** 题包环节 | 加时环节 */
/** common record */
type CommonRecord<T = any> = {
/** record id */
id: number
/** record creator */
createBy: string
/** record create time */
createTime: string
/** record updater */
updateBy: string
/** record update time */
updateTime: string
/** record status */
status: EnableStatus | null
} & T
}
}

View File

@ -99,6 +99,8 @@ declare module 'vue' {
NFormItemGi: typeof import('naive-ui')['NFormItemGi']
NGi: typeof import('naive-ui')['NGi']
NGrid: typeof import('naive-ui')['NGrid']
NImage: typeof import('naive-ui')['NImage']
NImageGroup: typeof import('naive-ui')['NImageGroup']
NInput: typeof import('naive-ui')['NInput']
NInputGroup: typeof import('naive-ui')['NInputGroup']
NInputNumber: typeof import('naive-ui')['NInputNumber']
@ -114,6 +116,7 @@ declare module 'vue' {
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
NPopover: typeof import('naive-ui')['NPopover']
NProgress: typeof import('naive-ui')['NProgress']
NRadio: typeof import('naive-ui')['NRadio']
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NScrollbar: typeof import('naive-ui')['NScrollbar']
@ -128,11 +131,17 @@ declare module 'vue' {
NTextarea: typeof import('naive-ui')['NTextarea']
NThing: typeof import('naive-ui')['NThing']
NTooltip: typeof import('naive-ui')['NTooltip']
NUpload: typeof import('naive-ui')['NUpload']
NWatermark: typeof import('naive-ui')['NWatermark']
PageHeader: typeof import('./../components/common/page-header.vue')['default']
PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
RestBasicEditor: typeof import('./../components/common/rest-basic-editor/rest-basic-editor.vue')['default']
RestHoverAciton: typeof import('./../components/common/rest-hover-aciton/rest-hover-aciton.vue')['default']
RestImgViewer: typeof import('./../components/common/rest-img-viewer/rest-img-viewer.vue')['default']
RestSelectFile: typeof import('./../components/common/rest-select-file/rest-select-file.vue')['default']
RestUpload: typeof import('./../components/common/rest-upload/rest-upload.vue')['default']
RestVideoViewer: typeof import('./../components/common/rest-video-viewer/rest-video-viewer.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SoybeanAvatar: typeof import('./../components/custom/soybean-avatar.vue')['default']
@ -235,6 +244,8 @@ declare global {
const NFormItemGi: typeof import('naive-ui')['NFormItemGi']
const NGi: typeof import('naive-ui')['NGi']
const NGrid: typeof import('naive-ui')['NGrid']
const NImage: typeof import('naive-ui')['NImage']
const NImageGroup: typeof import('naive-ui')['NImageGroup']
const NInput: typeof import('naive-ui')['NInput']
const NInputGroup: typeof import('naive-ui')['NInputGroup']
const NInputNumber: typeof import('naive-ui')['NInputNumber']
@ -250,6 +261,7 @@ declare global {
const NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
const NPopconfirm: typeof import('naive-ui')['NPopconfirm']
const NPopover: typeof import('naive-ui')['NPopover']
const NProgress: typeof import('naive-ui')['NProgress']
const NRadio: typeof import('naive-ui')['NRadio']
const NRadioGroup: typeof import('naive-ui')['NRadioGroup']
const NScrollbar: typeof import('naive-ui')['NScrollbar']
@ -264,11 +276,17 @@ declare global {
const NTextarea: typeof import('naive-ui')['NTextarea']
const NThing: typeof import('naive-ui')['NThing']
const NTooltip: typeof import('naive-ui')['NTooltip']
const NUpload: typeof import('naive-ui')['NUpload']
const NWatermark: typeof import('naive-ui')['NWatermark']
const PageHeader: typeof import('./../components/common/page-header.vue')['default']
const PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
const ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
const RestBasicEditor: typeof import('./../components/common/rest-basic-editor/rest-basic-editor.vue')['default']
const RestHoverAciton: typeof import('./../components/common/rest-hover-aciton/rest-hover-aciton.vue')['default']
const RestImgViewer: typeof import('./../components/common/rest-img-viewer/rest-img-viewer.vue')['default']
const RestSelectFile: typeof import('./../components/common/rest-select-file/rest-select-file.vue')['default']
const RestUpload: typeof import('./../components/common/rest-upload/rest-upload.vue')['default']
const RestVideoViewer: typeof import('./../components/common/rest-video-viewer/rest-video-viewer.vue')['default']
const RouterLink: typeof import('vue-router')['RouterLink']
const RouterView: typeof import('vue-router')['RouterView']
const SoybeanAvatar: typeof import('./../components/custom/soybean-avatar.vue')['default']

View File

@ -33,6 +33,8 @@ declare module "@elegant-router/types" {
"rank_rank-list": "/rank/rank-list";
"results": "/results";
"template": "/template";
"template_template-detail": "/template/template-detail";
"template_template-list": "/template/template-list";
"user": "/user";
};
@ -106,7 +108,8 @@ declare module "@elegant-router/types" {
| "rank_rank-detail"
| "rank_rank-list"
| "results"
| "template"
| "template_template-detail"
| "template_template-list"
| "user"
>;

View File

@ -39,5 +39,8 @@ declare namespace StorageType {
}
/** The last login user id */
lastLoginUserId: string
/** The user id */
userId: number
}
}