feat(template): 新增答题卡模板编辑器及相关功能

- 新增模板详情页面,支持上传PDF/图片作为底稿,并生成可拖拽调整的区域
- 新增模板类型定义、上传钩子及画布组件,支持批量生成区域、旋转、对齐参考线等功能
- 更新模板列表页,适配新的API接口并增加删除功能
- 更新OSS工具函数,修复上传凭证处理逻辑
- 更新公共类型定义,调整分页查询返回结构
- 移除旧的书籍相关API文件,替换为模板API
- 更新依赖项,添加pdfjs-dist、vue3-draggable-resizable等库
- 隐藏页面底部,优化界面显示
This commit is contained in:
2026-01-28 18:00:17 +08:00
parent 78e51d96f6
commit 16d7ecd172
17 changed files with 1207 additions and 266 deletions

View File

@ -1,219 +0,0 @@
import { request } from '../request';
export interface BookPageQuestionAddInput {
bookId: number;
bookPageId: number;
no: string;
type: number;
score: number;
subjectId?: number;
answerTime: number;
}
export interface BookReviewInput {
bookId: number;
bookPageId: number;
id?: number; // questionId
[key: string]: any;
}
export interface QuestionFromInfo {
[key: string]: any;
}
export interface BookPageQuestion {
id: number;
type?: number;
[key: string]: any;
}
export interface QuestionsImages {
[key: string]: any;
}
export interface BookCatalog {
name: string;
type: number;
url?: string;
}
export interface BookCatalogImportInput {
bookId: number;
bookCatalogs: BookCatalog[];
index: number;
pdfUrl: string;
}
export interface BookBaseData {
width?: number;
height?: number;
}
export interface CatalogTree {
id: number;
name: string;
type: number;
verifyStatus?: number;
childs?: CatalogTree[];
[key: string]: any;
}
export function importBookPageAxios(data: BookCatalogImportInput) {
return request<any>({
url: '/admin/v1/book/page/import',
method: 'post',
data,
});
}
export function editBookCatalogAxios(data: any) {
return request<any>({
url: '/admin/v1/book/catalog/edit',
method: 'post',
data,
});
}
export function getBookCatalogTreeAxios(params: { bookId: number }) {
return request<any>({
url: '/admin/v1/book/catalog/tree',
method: 'get',
params,
});
}
export function getBookBaseInfoAxios(params: { id: number }) {
return request<any>({
url: '/admin/v1/book/base/info',
method: 'get',
params,
});
}
export function getBookPageDetailAxios(params: { pageId: number }) {
return request<any>({
url: '/admin/v1/book/page/detail',
method: 'get',
params,
});
}
export function setStartPageAxios(data: any) {
return request<any>({
url: '/admin/v1/book/page/start/set',
method: 'post',
data,
});
}
export function addBookQuestionAxios(data: BookPageQuestionAddInput) {
return request<any>({
url: '/admin/v1/book/question/add',
method: 'post',
data,
});
}
export function delBookQuestionAxios(id: number) {
return request<any>({
url: `/admin/v1/book/question/delete`,
method: 'post',
data: { id },
});
}
export function updateBookPageLayoutAxios(data: { id: number; layout: string; questionsImages?: any[] }) {
return request<any>({
url: '/admin/v1/book/page/layout/update',
method: 'post',
data,
});
}
export function getQuestionInfoAxios(id: number) {
return request<any>({
url: `/admin/v1/book/question/info`,
method: 'get',
params: { id },
});
}
export function editQuestionInfoAxios(data: any) {
return request<any>({
url: '/admin/v1/book/question/edit',
method: 'post',
data,
});
}
export function getQuestionBankNavAxios() {
return request<any>({
url: '/admin/v1/book/question/nav',
method: 'get',
});
}
export function getKnowledgePointDetailsAxios(params: any) {
return request<any>({
url: '/admin/v1/knowledge/point/details',
method: 'get',
params,
});
}
export function updateKeywordAnalysisAxios(data: any) {
return request<any>({
url: '/admin/v1/book/question/analysis/update',
method: 'post',
data,
});
}
export function releaseTaskAxios(data: any) {
return request<any>({
url: '/admin/v1/book/task/release',
method: 'post',
data,
});
}
export function fetchBookCategoryList(params: any) {
return request<any>({
url: '/admin/v1/book/category/list',
method: 'post', // Assuming post based on usage pattern, or get? Original didn't specify method in prop, usually list is get or post. Let's assume post for list with search params.
data: params,
});
}
export function addBookAreaAxios(data: any) {
return request<any>({
url: '/admin/v1/book/area/add',
method: 'post',
data,
});
}
export function updateBookAreaAxios(data: any) {
return request<any>({
url: '/admin/v1/book/area/update',
method: 'post',
data,
});
}
export function delBookAreaAxios(id: number) {
return request<any>({
url: '/admin/v1/book/area/delete',
method: 'post',
data: { id },
});
}
export function fetchSubjectList(params: any) {
return request<any>({
url: '/admin/v1/subject/pagelist',
method: 'post',
data: params,
});
}

View File

@ -1,10 +1,43 @@
import { request } from '../request'
/** get template list */
/**
* 获取模板列表
*/
export function fetchTemplateList(data?: Api.Template.TemplateSearchParams) {
return request<Api.Common.PaginatingQueryRecord<Api.Template.CommonRecord>>({
url: '/admin/v1/book/list',
return request<App.Service.Response<Api.Common.PaginatingQueryRecord<Api.Template.CommonRecord>>>({
url: '/Base/ActivityMain/GetTemplete_Pag',
method: 'get',
params: data || {},
})
}
/**
* 新增模板
*/
export function fetchAddTemplate(data?: Api.Template.AddTemplateParams) {
return request<App.Service.Response<Api.Common.PaginatingQueryRecord<Api.Template.CommonRecord>>>({
url: '/Base/ActivityMain/AddOrUpdateTemplete_Pag',
method: 'post',
data: data || {},
})
}
/**
* 获取模板详情
*/
export function fetchTemplateDetail(id: number) {
return request<App.Service.Response<Api.Common.PaginatingQueryRecord<Api.Template.CommonRecord>>>({
url: `/Base/ActivityMain/GetTemplete_PagByID?id=${id}`,
method: 'get',
})
}
/**
* 删除模板
*/
export function fetchDeleteTemplate(id: number) {
return request<App.Service.Response<Api.Common.PaginatingQueryRecord<Api.Template.CommonRecord>>>({
url: `/Base/ActivityMain/DeleteTemplete_Pag?id=${id}`,
method: 'post',
})
}

View File

@ -15,7 +15,7 @@ export interface AliOssSTS {
/** 得到上传的token */
export function getAliOssTokenAxios() {
return request<AliOssSTS>({
return request<App.Service.Response<AliOssSTS>>({
url: `${import.meta.env.VITE_BASE_UPLOAD_URL}/admin/v1/oss/sts`,
method: 'get',
})
@ -23,7 +23,7 @@ export function getAliOssTokenAxios() {
/** 删除阿里云oss 文件 */
export function deleteAliOssFileAxios(data: ReqDeleteAliOssFile) {
return request<boolean>({
return request<App.Service.Response<boolean>>({
url: `${import.meta.env.VITE_BASE_UPLOAD_URL}/admin/v1/oss/delete`,
method: 'post',
data,