feat(web): 前端 SPA 化 + 工具页任务面板统一与历史批量删除

- SPA 化:22 个 MPA html 入口与 *-main.ts 合并为 index.html + vue-router(URL 无 .html 后缀),
  页面跳转全部 router-link,/new_web_source/xxx.html 旧路径归一为 /xxx
- 任务面板统一:共享 TaskCenterPanel/TaskItemCard/TaskStatCards/HistoryTaskLayer,
  16 个工具页右侧统一为统计卡 + 当前任务 + 历史任务弹层(任务ID/开始/结束/状态必展示)
- 历史记录支持单条删除 + 批量勾选删除(确认框/全选/失败提示)
- Java 7 模块(dedupe/convert/split/productrisk/shopmatch/pricetrack/deletebrand)
  history 接口补齐任务时间字段(VO+Service,复用 biz_file_task 列)
- 图片工作台/API 层(brand/permission/user)既有未提交改动一并提交
This commit is contained in:
2026-09-08 10:02:55 +08:00
parent abcfa5bef7
commit e248b6e43a
125 changed files with 7482 additions and 4304 deletions
@@ -0,0 +1,36 @@
export const ALLOWED_IMAGE_TYPES = ['image/jpeg', 'image/jpg', 'image/png', 'image/bmp']
/** 读取多个文件为 data URL,返回解析完的数组。 */
export function readFilesAsDataUrls(files: Blob[] | FileList): Promise<string[]> {
const list = Array.from(files)
return Promise.all(
list.map(
(file) =>
new Promise<string>((resolve, reject) => {
const reader = new FileReader()
reader.onload = () => resolve(String(reader.result || ''))
reader.onerror = () => reject(reader.error || new Error('读取文件失败'))
reader.readAsDataURL(file)
}),
),
)
}
/** 从剪贴板读取图片文件。 */
export async function pasteClipboardImages(): Promise<Blob[]> {
try {
const items = await navigator.clipboard.read()
const images: Blob[] = []
for (const item of items) {
if (item.types.includes('image/png')) {
images.push(await item.getType('image/png'))
} else if (item.types.includes('image/jpeg')) {
images.push(await item.getType('image/jpeg'))
}
}
return images
} catch (err) {
console.warn('粘贴图片失败:', err)
return []
}
}