Forráskód Böngészése

chore: 移动端同步主仓库最新代码

yangjingjing 2 napja
szülő
commit
bb4ea4c0ee

+ 12 - 3
src/api/auth.ts

@@ -56,11 +56,20 @@ export interface UserInfoResult {
   deptName?: string
 }
 
+/**
+ * /system/user/getInfo 实际响应是 { user: {...}, roles, permissions } 嵌套结构
+ */
+export interface GetInfoResponse {
+  user: UserInfoResult
+  roles: string[]
+  permissions: string[]
+}
+
 export function getInfo(): Promise<UserInfoResult> {
-  return request<UserInfoResult>({
-    url: '/getInfo',
+  return request<GetInfoResponse>({
+    url: '/system/user/getInfo',
     method: 'GET'
-  })
+  }).then((res) => res.user)
 }
 
 /** 注销登录 */

+ 53 - 3
src/api/inspection.ts

@@ -4,7 +4,7 @@
  * - 后端 TableDataInfo(列表)和 R<T>(详情/提交) 由 request 解析后已剥离外层
  *   所以这里直接拿到 data(即列表项数组 / 详情对象)
  */
-import type { InspectionListQuery, PunchSubmitPayload } from '@/types/inspection'
+import type { InspectionListQuery, InspectionTask, PunchSubmitPayload } from '@/types/inspection'
 import { request, uploadFile } from '@/utils/request'
 
 // ===== 列表分页响应(对应后端 TableDataInfo) =====
@@ -15,18 +15,68 @@ export interface PageResult<T> {
   pageSize: number
 }
 
+// ===== 后端 punchStatus(PENDING/PUNCHED/OVERDUE/FINISHED) → 前端 PENDING/DONE/EXPIRED =====
+function normalizePunchStatus(s: string): 'PENDING' | 'DONE' | 'EXPIRED' {
+  if (s === 'PUNCHED' || s === 'FINISHED' || s === 'DONE') return 'DONE'
+  if (s === 'OVERDUE' || s === 'EXPIRED') return 'EXPIRED'
+  return 'PENDING'
+}
+
+// ===== 后端 punchResult('0'/'1') → 前端 NORMAL/ABNORMAL =====
+function normalizePunchResult(r?: string | null): 'NORMAL' | 'ABNORMAL' | null {
+  if (r === '0') return 'NORMAL'
+  if (r === '1') return 'ABNORMAL'
+  return null
+}
+
+// ===== 后端 punchType → 前端 punchTypeName =====
+function punchTypeName(t?: string | null): string {
+  if (t === 'SCAN') return '扫码打卡'
+  return '常规打卡'
+}
+
+// ===== 后端 VO → 前端 InspectionTask 字段映射 =====
+function mapRow(raw: any): InspectionTask {
+  return {
+    // 后端 Java Long 可能超过 JS Number 安全整数(2^53),保留原始字符串
+    id: raw.id,
+    taskCode: raw.taskCode || '',
+    taskName: raw.taskName || '',
+    inspectionType: raw.taskTypeName || raw.taskType || '',
+    inspectionTypeCode: raw.taskType || '',
+    punchType: (raw.punchType === 'SCAN' ? 'SCAN' : 'NORMAL') as InspectionTask['punchType'],
+    punchTypeName: punchTypeName(raw.punchType),
+    storeName: raw.storeName || '',
+    punchLocation: raw.location || '',
+    longitude: raw.lng != null ? Number(raw.lng) : undefined,
+    latitude: raw.lat != null ? Number(raw.lat) : undefined,
+    completeTime: raw.planEndTime || '',
+    actualPunchTime: raw.punchTime,
+    punchStatus: normalizePunchStatus(raw.punchStatus || 'PENDING'),
+    punchResult: normalizePunchResult(raw.punchResult),
+    needPhoto: false,
+    items: Array.isArray(raw.items) ? raw.items : []
+  }
+}
+
 // ===== 巡检任务列表 =====
 // 后端从 Sa-Token 取当前登录用户作为 inspectorId(已移除前端传参)
-export function listInspectionTasks(query: InspectionListQuery): Promise<PageResult<any>> {
+export function listInspectionTasks(query: InspectionListQuery): Promise<PageResult<InspectionTask>> {
   return request<PageResult<any>>({
     url: '/risk/inspectionTask/mobileList',
     method: 'GET',
     data: query
+  }).then((res: any) => {
+    const rows = (res?.rows ?? []) as any[]
+    return {
+      ...res,
+      rows: rows.map(mapRow)
+    } as PageResult<InspectionTask>
   })
 }
 
 // ===== 任务详情(含巡检项目) =====
-export function getInspectionTaskDetail(id: number): Promise<any> {
+export function getInspectionTaskDetail(id: string | number): Promise<any> {
   return request<any>({
     url: `/risk/inspectionTask/mobileDetail/${id}`,
     method: 'GET'

+ 7 - 4
src/api/qualityInspection.ts

@@ -43,7 +43,8 @@ function resultLabel(r?: string | null): string {
 function mapRow(raw: any): QualityInspectionTask {
   const punchStatus = normalizePunchStatus(raw.punchStatus || 'PENDING')
   return {
-    id: Number(raw.id),
+    // 后端 Java Long 可能超过 JS Number 安全整数(2^53),保留原始字符串
+    id: raw.id,
     taskCode: raw.taskCode || '',
     taskName: raw.taskName || '',
     taskType: raw.taskType || '',
@@ -102,7 +103,8 @@ export { punchTypeName, resultLabel }
 function mapDetail(raw: any): QualityInspectionTaskDetail {
   const punchStatus = normalizePunchStatus(raw.punchStatus || 'PENDING')
   return {
-    id: Number(raw.id),
+    // 后端 Java Long 可能超过 JS Number 安全整数(2^53),保留原始字符串
+    id: raw.id,
     taskCode: raw.taskCode || '',
     taskName: raw.taskName || '',
     taskType: raw.taskType || '',
@@ -124,7 +126,8 @@ function mapDetail(raw: any): QualityInspectionTaskDetail {
     taskStatus: raw.taskStatus,
     items: Array.isArray(raw.items)
       ? raw.items.map((it: any) => ({
-          id: Number(it.id),
+          // 后端 Java Long 可能超过 JS Number 安全整数,保留字符串
+          id: it.id,
           itemCategory: it.itemCategory || '',
           itemContent: it.itemContent || '',
           itemStandard: it.itemStandard || '',
@@ -136,7 +139,7 @@ function mapDetail(raw: any): QualityInspectionTaskDetail {
 }
 
 // ===== 任务详情(含巡检项目) =====
-export function getQualityTaskDetail(id: number): Promise<QualityInspectionTaskDetail> {
+export function getQualityTaskDetail(id: string | number): Promise<QualityInspectionTaskDetail> {
   return request<any>({
     url: `/quality/inspectionTask/mobileDetail/${id}`,
     method: 'GET'

+ 4 - 2
src/pages/qualityInspection/check/index.vue

@@ -121,7 +121,8 @@ import { request } from '@/utils/request'
 import { getToken } from '@/utils/auth'
 import { getCurrentLocation, ensureLocationAuth } from '@/utils/location'
 
-const taskId = ref<number>(0)
+// 后端 Java Long > JS Number 安全整数,这里必须保留字符串
+const taskId = ref<string>('')
 const readonly = ref<boolean>(false)
 const task = ref<Partial<QualityInspectionTaskDetail>>({})
 const items = ref<QualityInspectionItem[]>([])
@@ -132,7 +133,8 @@ const pickedLocation = ref<string>('')
 const pickedCoord = ref<{ lng: number; lat: number } | null>(null)
 
 onLoad((q) => {
-  taskId.value = Number(q?.taskId || 0)
+  // 保留 taskId 原始字符串,避免 JS Number 安全整数上限导致后端查询不到(Long 超过 2^53 会被截断)
+  taskId.value = String(q?.taskId || '')
   readonly.value = q?.readonly === '1'
   // 扫码页会带 lng/lat 过来,作为初值
   if (q?.lng && q?.lat) {

+ 2 - 1
src/types/inspection.ts

@@ -12,7 +12,8 @@ export type PunchResult = 'NORMAL' | 'ABNORMAL' | null
 
 // ===== 巡检任务(列表项) =====
 export interface InspectionTask {
-  id: number
+  // 任务ID(后端 Java Long 序列化后超过 JS Number 安全整数,必须保留字符串)
+  id: string | number
   taskCode: string                // 任务编号
   taskName: string                // 巡检任务名称
   inspectionType: string          // 巡检类型(字典名)

+ 6 - 3
src/types/qualityInspection.ts

@@ -17,7 +17,8 @@ export type PunchResult = '0' | '1' | null  // 0 正常 / 1 异常 / null 未打
 // ===== 品控巡检任务(列表项) =====
 // 字段名直接对齐后端返回,避免后端/前端字段名不一致问题
 export interface QualityInspectionTask {
-  id: number
+  // 后端 Java Long > JS Number 安全整数,必须保留字符串
+  id: string | number
   taskCode: string                // 任务编号
   taskName: string                // 巡检任务名称
   taskType: string                // 巡检类型(后端字段名)
@@ -52,7 +53,8 @@ export interface QualityListQuery {
 
 // ===== 巡检项目 =====
 export interface QualityInspectionItem {
-  id: number                                 // 项目ID
+  // 后端 Java Long > JS Number 安全整数,保留字符串
+  id: string | number                                 // 项目ID
   itemCategory: string                       // 项目大类
   itemContent: string                        // 巡检内容
   itemStandard: string                       // 巡检标准
@@ -85,7 +87,8 @@ export interface QualityPunchItemResult {
 
 // ===== 提交打卡 - 整体 payload =====
 export interface QualityPunchSubmitPayload {
-  taskId: number                             // 任务ID
+  // 后端 Java Long > JS Number 安全整数,保留字符串
+  taskId: string | number                             // 任务ID
   taskName?: string                          // 任务名称(冗余)
   storeId?: number                           // 门店ID
   storeName?: string                         // 门店名称

+ 16 - 1
src/utils/request.ts

@@ -68,6 +68,9 @@ function buildUrl(url: string): string {
 
 export function request<T = any>(opts: RequestOptions): Promise<T> {
   const header: Record<string, string> = { ...(opts.header || {}) }
+  // 必须带上 clientid, 后端 Sa-Token 通过 token + clientid 双重校验才能识别登录态;
+  // 移动端登录时使用的是 MOBILE_CLIENT_ID(对应 sys_client.device_type=android)
+  header['clientid'] = '428a8310cd442757ae699df5d894f051'
   if (!opts.skipAuth) {
     const token = getToken()
     if (token) header['Authorization'] = `Bearer ${token}`
@@ -99,6 +102,15 @@ export function request<T = any>(opts: RequestOptions): Promise<T> {
           resolve(res.data as any)
           return
         }
+        // RuoYi-Vue-Plus 分页接口返回 TableDataInfo 结构 {total, rows, code, msg}
+        // 顶层就有 code+msg+rows,与 R<T> 同形,容易误判:
+        //   - R<T> 形态: {code, msg, data}
+        //   - TableDataInfo 形态: {code, msg, total, rows}
+        // 通过是否同时含 rows+total 且不含 data 来识别 TableDataInfo,直接返回原数据
+        if ('rows' in body && 'total' in body && !('data' in body)) {
+          resolve(res.data as any)
+          return
+        }
         if (body.code === 200) {
           resolve(body.data as T)
         } else {
@@ -127,7 +139,10 @@ export function uploadFile<T = any>(opts: {
   formData?: Record<string, any>
   skipAuth?: boolean
 }): Promise<T> {
-  const header: Record<string, string> = {}
+  const header: Record<string, string> = {
+    // 必须带上 clientid, 否则后端 Sa-Token 无法识别 token
+    clientid: '428a8310cd442757ae699df5d894f051'
+  }
   if (!opts.skipAuth) {
     const token = getToken()
     if (token) header['Authorization'] = `Bearer ${token}`