refactor(frontend): Phase 3 质量整改——死状态清理、类型收口、路由收敛、上传统一

- stores: 移除未使用的 token/loading/locale 死状态;AdminCheckResult 统一收口 types/api.ts
- router: 移除全 Mock 的 SKU 页生产路由(源码保留待独立工程决策)
- api/request: 新增 requestRaw() 显式原始响应封装(替代 responseType hack)
- Manager.vue: SimpleUpload 弃用 XMLHttpRequest,改统一 axios upload + onUploadProgress(拦截器收益全覆盖)
This commit is contained in:
TermiNexus committed 2026-08-13 18:14:25 +08:00
1 parent 4d49e549b5
commit ce7a17d170
6 files changed
+38 -50

No files matched your search

+7
View File
@@ -171,6 +171,13 @@ export function patch<T = unknown>(url: string, data?: unknown, config?: AxiosRe
return request.patch(url, data, config) as unknown as Promise<T>
}
/** 原始响应请求:返回 AxiosResponse(绕过 {code,data} 解包),
* 供需要访问原始响应体(非标准结构/流式响应)的场景使用,
* 替代 responseType:'text' + 双重类型断言的 hack */
export function requestRaw<T = unknown>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
return request.request(config) as Promise<AxiosResponse<T>>
}
/** 上传文件 */
export function upload<T = unknown>(url: string, formData: FormData, config?: AxiosRequestConfig): Promise<T> {
return request.post(url, formData, {
+2 -7
View File
@@ -360,13 +360,8 @@ export const staticRoutes: RouteRecordRaw[] = [
component: () => import('@/views/LegacyPage.vue'),
meta: { title: '储值查看', requiresAuth: true, menuGuarded: true, legacySrc: '/pages/private/CreateE/StoreValue.html' },
},
// === 阶段 8:SKU(移动端 C 端,待决策是否拆分独立工程) ===
{
path: 'sku',
name: 'Sku',
component: () => import('@/views/SKU/Sku.vue'),
meta: { title: '商品详情', requiresAuth: false },
},
// === SKU(移动端 C 端):全 Mock 页面已从生产路由移除 ===
// Sku.vue 仍保留源码(1870 行 Mock 数据 + TODO),待决策是否拆分为独立移动端工程后再接入
// === 兜底:未匹配路由在 DefaultLayout 内显示 404(保留 menu/nav/tab) ===
// 作为 DefaultLayout 子路由,享有完整框架;requiresAuth: true 使其自动开 tab
{
+1 -4
View File
@@ -131,7 +131,7 @@ function applyPrimaryColor(color: string): void {
}
}
/** 应用状态:侧边栏折叠、主题、配色、语言等全局 UI 状态 */
/** 应用状态:侧边栏折叠、主题、配色等全局 UI 状态 */
export const useAppStore = defineStore('app', () => {
/** 侧边栏是否折叠 */
const sidebarCollapsed = ref(false)
@@ -139,8 +139,6 @@ export const useAppStore = defineStore('app', () => {
const theme = ref<ThemeMode>('default')
/** 自定义主色(hex);设置后覆盖预设配色,null 表示用预设 */
const customPrimary = ref<string | null>(null)
/** 当前语言 */
const locale = ref<'zh-CN' | 'en-US'>('zh-CN')
/** 切换侧边栏 */
function toggleSidebar(): void {
@@ -193,7 +191,6 @@ export const useAppStore = defineStore('app', () => {
sidebarCollapsed,
theme,
customPrimary,
locale,
toggleSidebar,
setTheme,
setCustomColor,
+5 -15
View File
@@ -32,8 +32,6 @@ export const useUserStore = defineStore('user', () => {
const userInfo = ref<UserInfo | null>(null)
const roles = ref<RoleItem[]>([])
const menus = ref<MenuItem[]>([])
const token = ref<string>('')
const loading = ref(false)
// CheckAdmin 结果(后端按当前角色权限码判定管理员,不依赖 GetELTUserInfo 的 IsAdmin 字段)
const adminCheck = ref<AdminCheckResult | null>(null)
// CheckAdmin 是否已加载完成(成功或失败都置 true,供页面区分"加载中"与"确实无权限")
@@ -114,16 +112,11 @@ export const useUserStore = defineStore('user', () => {
// === 动作 ===
/** 登录 */
async function login(params: LoginParams): Promise<void> {
loading.value = true
try {
await apiLogin(params)
await fetchUserInfo()
await fetchMenus()
await fetchRoles()
await fetchAdminCheck()
} finally {
loading.value = false
}
await apiLogin(params)
await fetchUserInfo()
await fetchMenus()
await fetchRoles()
await fetchAdminCheck()
}
/** 注销 */
@@ -243,7 +236,6 @@ export const useUserStore = defineStore('user', () => {
userInfo.value = null
roles.value = []
menus.value = []
token.value = ''
adminCheck.value = null
adminChecked.value = false
localStorage.removeItem(CACHE_KEY)
@@ -254,8 +246,6 @@ export const useUserStore = defineStore('user', () => {
userInfo,
roles,
menus,
token,
loading,
adminCheck,
adminChecked,
// 计算属性
+18 -3
View File
@@ -324,10 +324,25 @@ export interface RoleScope {
WorkgroupUUID?: string
}
/** CheckAdmin 接口返回结果 */
/** CheckAdmin 接口返回结果(对齐后端 /API/FormAPI/CheckAdmin) */
export interface AdminCheckResult {
/** 是否管理员 */
is_admin?: boolean
/** 用户作用域 */
role_scope?: RoleScope | null
is_superuser?: boolean
is_super_admin?: boolean
is_tenant_admin?: boolean
current_role_name?: string
current_role_uuid?: string
current_company_uuid?: string
current_tenant_uuid?: string
has_current_company?: boolean
/** 当前角色的数据作用域 */
role_scope?: {
Type?: string
TypeLabel?: string
IsAdmin?: boolean
IsDeptManager?: boolean
IsWorkgroupLead?: boolean
IsMember?: boolean
} | null
}
+5 -21
View File
@@ -525,7 +525,7 @@ async function UploadFiles(files: File[]): Promise<void> {
/**
* 简单上传:单 FormData
* 直接用 XHR 拿 onprogress 进度回调
* 走统一 axios 实例(拦截器注入时区/作用域参数/401 处理),onUploadProgress 拿进度
*/
async function SimpleUpload(
file: File,
@@ -533,26 +533,10 @@ async function SimpleUpload(
): Promise<void> {
const fd = new FormData()
fd.append('file', file)
// TODO: @/api/request 的 upload() 封装暂未暴露 onProgress 回调
// 若后续扩展 upload() 支持 onUploadProgress,可改回 upload('/API/Asset/Upload', fd, { onUploadProgress })
await new Promise<void>((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('POST', '/API/Asset/Upload')
xhr.withCredentials = true
xhr.upload.onprogress = (e) => {
if (e.lengthComputable) onProgress(Math.round((e.loaded / e.total) * 100))
}
xhr.onload = () => {
try {
const data = JSON.parse(xhr.responseText)
if (data.code === 0) resolve()
else reject(new Error(data.msg || '上传失败'))
} catch {
reject(new Error('解析响应失败'))
}
}
xhr.onerror = () => reject(new Error('网络错误'))
xhr.send(fd)
await upload('/API/Asset/Upload', fd, {
onUploadProgress: (e) => {
if (e.total) onProgress(Math.round((e.loaded / e.total) * 100))
},
})
}