usAppAuth.ts 9.9 KB
import type {
  AuthScopeCompanyOption,
  AuthScopeLocationOption,
  AuthScopeRegionOption,
  AuthScopeSelectLocationOutput,
  UsAppSelectAdminScopeLocationInput,
} from '../types/usAppAdminScope'
import type { UsAppBoundLocationDto } from '../types/usAppBound'
import { usAppApiRequest, unwrapApiPayload } from '../utils/usAppApiRequest'
import { fetchWithOfflineCache } from '../utils/sqliteSync'

/** GET /api/app/us-app-auth/my-profile → UsAppMyProfileOutputDto */
export interface UsAppMyProfileOutputDto {
  fullName: string
  email: string
  phone: string
  employeeId: string
  roleDisplay: string
  primaryRoleCode: string | null
}

export interface UsAppChangePasswordInput {
  currentPassword: string
  newPassword: string
  confirmNewPassword: string
}

/** GET /api/app/us-app-auth/location-detail/{locationId} */
export interface UsAppLocationDetailOutputDto {
  locationId: string
  locationName: string
  fullAddress: string
  storePhone: string
  operatingHours: string
  managerName: string
  managerPhone: string
}

export type { UsAppBoundLocationDto }

export interface UsAppLoginInput {
  email: string
  password: string
  uuid?: string
  code?: string
}

export interface UsAppLoginOutputDto {
  token: string
  refreshToken: string
  locations: UsAppBoundLocationDto[]
}

function normalizeLocation(raw: Record<string, unknown>): UsAppBoundLocationDto {
  return {
    id: String(raw.id ?? raw.Id ?? ''),
    locationCode: String(raw.locationCode ?? raw.LocationCode ?? ''),
    locationName: String(raw.locationName ?? raw.LocationName ?? ''),
    fullAddress: String(raw.fullAddress ?? raw.FullAddress ?? ''),
    state: raw.state !== false && raw.State !== false,
  }
}

function normalizeLoginOutput(raw: unknown): UsAppLoginOutputDto {
  const o = raw as Record<string, unknown>
  const locs = o.locations ?? o.Locations
  const arr = Array.isArray(locs) ? locs : []
  return {
    token: String(o.token ?? o.Token ?? ''),
    refreshToken: String(o.refreshToken ?? o.RefreshToken ?? ''),
    locations: arr.map((x) => normalizeLocation(x as Record<string, unknown>)),
  }
}

function normalizeLocationList(raw: unknown): UsAppBoundLocationDto[] {
  const arr = Array.isArray(raw) ? raw : []
  return arr.map((x) => normalizeLocation(x as Record<string, unknown>))
}

/** POST /api/app/us-app-auth/login(401 不触发全局跳转) */
export async function usAppLogin(input: UsAppLoginInput): Promise<UsAppLoginOutputDto> {
  const raw = await usAppApiRequest<unknown>({
    path: '/api/app/us-app-auth/login',
    method: 'POST',
    skipUnauthorizedRedirect: true,
    data: {
      email: input.email.trim(),
      password: input.password,
      ...(input.uuid ? { uuid: input.uuid } : {}),
      ...(input.code != null ? { code: input.code } : {}),
    },
  })
  return normalizeLoginOutput(raw)
}

/** GET /api/app/us-app-auth/my-locations */
export async function usAppFetchMyLocations(): Promise<UsAppBoundLocationDto[]> {
  return fetchWithOfflineCache('auth', 'my-locations', async () => {
    const raw = await usAppApiRequest<unknown>({
      path: '/api/app/us-app-auth/my-locations',
      method: 'GET',
      auth: true,
    })
    return normalizeLocationList(raw)
  })
}

function normalizeMyProfile(raw: unknown): UsAppMyProfileOutputDto {
  const o = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>
  const pr = o.primaryRoleCode ?? o.PrimaryRoleCode
  return {
    fullName: String(o.fullName ?? o.FullName ?? ''),
    email: String(o.email ?? o.Email ?? ''),
    phone: String(o.phone ?? o.Phone ?? ''),
    employeeId: String(o.employeeId ?? o.EmployeeId ?? ''),
    roleDisplay: String(o.roleDisplay ?? o.RoleDisplay ?? ''),
    primaryRoleCode: pr == null || pr === '' ? null : String(pr),
  }
}

/** GET /api/app/us-app-auth/my-profile */
export async function usAppFetchMyProfile(): Promise<UsAppMyProfileOutputDto> {
  return fetchWithOfflineCache('auth', 'my-profile', async () => {
    const raw = await usAppApiRequest<unknown>({
      path: '/api/app/us-app-auth/my-profile',
      method: 'GET',
      auth: true,
    })
    return normalizeMyProfile(unwrapIfNeeded(raw))
  })
}

function unwrapIfNeeded(raw: unknown): unknown {
  if (raw == null || typeof raw !== 'object') return raw
  const o = raw as Record<string, unknown>
  if ('result' in o && o.result !== undefined) return o.result
  if (o.data !== undefined) return o.data
  if (o.Data !== undefined) return o.Data
  return raw
}

function normalizeLocationDetail(raw: unknown): UsAppLocationDetailOutputDto {
  const o = (unwrapIfNeeded(raw) ?? {}) as Record<string, unknown>
  return {
    locationId: String(o.locationId ?? o.LocationId ?? ''),
    locationName: String(o.locationName ?? o.LocationName ?? ''),
    fullAddress: String(o.fullAddress ?? o.FullAddress ?? ''),
    storePhone: String(o.storePhone ?? o.StorePhone ?? ''),
    operatingHours: String(o.operatingHours ?? o.OperatingHours ?? ''),
    managerName: String(o.managerName ?? o.ManagerName ?? ''),
    managerPhone: String(o.managerPhone ?? o.ManagerPhone ?? ''),
  }
}

/**
 * GET /api/app/us-app-auth/location-detail/{locationId}
 * 文档:locationId 为路径参数;需当前用户已绑定该门店。
 */
export async function usAppFetchLocationDetail(locationId: string): Promise<UsAppLocationDetailOutputDto> {
  const id = (locationId || '').trim()
  return fetchWithOfflineCache('auth', `location-detail:${id}`, async () => {
    const raw = await usAppApiRequest<unknown>({
      path: `/api/app/us-app-auth/location-detail/${encodeURIComponent(id)}`,
      method: 'GET',
      auth: true,
    })
    return normalizeLocationDetail(raw)
  })
}

/** POST /api/app/us-app-auth/change-password */
function normalizeCompanyOption(raw: Record<string, unknown>): AuthScopeCompanyOption {
  return {
    id: String(raw.id ?? raw.Id ?? '').trim(),
    partnerName: String(raw.partnerName ?? raw.PartnerName ?? '').trim(),
    state: raw.state !== false && raw.State !== false,
  }
}

function normalizeRegionOption(raw: Record<string, unknown>): AuthScopeRegionOption {
  return {
    id: String(raw.id ?? raw.Id ?? '').trim(),
    groupName: String(raw.groupName ?? raw.GroupName ?? '').trim(),
    partnerId: String(raw.partnerId ?? raw.PartnerId ?? '').trim(),
    state: raw.state !== false && raw.State !== false,
  }
}

function normalizeScopeLocationOption(raw: Record<string, unknown>): AuthScopeLocationOption {
  return {
    id: String(raw.id ?? raw.Id ?? '').trim(),
    locationCode: String(raw.locationCode ?? raw.LocationCode ?? '').trim(),
    locationName: String(raw.locationName ?? raw.LocationName ?? '').trim(),
    fullAddress: String(raw.fullAddress ?? raw.FullAddress ?? '').trim(),
    state: raw.state !== false && raw.State !== false,
    partnerId: String(raw.partnerId ?? raw.PartnerId ?? '').trim() || undefined,
    groupId: String(raw.groupId ?? raw.GroupId ?? '').trim() || undefined,
    groupName: String(raw.groupName ?? raw.GroupName ?? '').trim() || undefined,
  }
}

function normalizeScopeLocationList(raw: unknown): AuthScopeLocationOption[] {
  const arr = Array.isArray(raw) ? raw : []
  return arr
    .map((x) => normalizeScopeLocationOption(x as Record<string, unknown>))
    .filter((x) => x.id)
}

/** GET /api/app/us-app-auth/admin-scope-companies */
export async function usAppFetchAdminScopeCompanies(): Promise<AuthScopeCompanyOption[]> {
  const raw = await usAppApiRequest<unknown>({
    path: '/api/app/us-app-auth/admin-scope-companies',
    method: 'GET',
    auth: true,
  })
  const list = unwrapApiPayload<unknown>(raw)
  const arr = Array.isArray(list) ? list : []
  return arr
    .map((x) => normalizeCompanyOption(x as Record<string, unknown>))
    .filter((x) => x.id)
}

/** GET /api/app/us-app-auth/admin-scope-regions */
export async function usAppFetchAdminScopeRegions(partnerId: string): Promise<AuthScopeRegionOption[]> {
  const pid = partnerId.trim()
  const raw = await usAppApiRequest<unknown>({
    path: '/api/app/us-app-auth/admin-scope-regions',
    method: 'GET',
    auth: true,
    data: { partnerId: pid },
  })
  const list = unwrapApiPayload<unknown>(raw)
  const arr = Array.isArray(list) ? list : []
  return arr
    .map((x) => normalizeRegionOption(x as Record<string, unknown>))
    .filter((x) => x.id)
}

/** GET /api/app/us-app-auth/admin-scope-locations */
export async function usAppFetchAdminScopeLocations(
  partnerId: string,
  groupId: string,
): Promise<AuthScopeLocationOption[]> {
  const raw = await usAppApiRequest<unknown>({
    path: '/api/app/us-app-auth/admin-scope-locations',
    method: 'GET',
    auth: true,
    data: {
      partnerId: partnerId.trim(),
      groupId: groupId.trim(),
    },
  })
  return normalizeScopeLocationList(unwrapApiPayload(raw))
}

/** POST /api/app/us-app-auth/select-admin-scope-location */
export async function usAppSelectAdminScopeLocation(
  input: UsAppSelectAdminScopeLocationInput,
): Promise<AuthScopeSelectLocationOutput> {
  const raw = await usAppApiRequest<unknown>({
    path: '/api/app/us-app-auth/select-admin-scope-location',
    method: 'POST',
    auth: true,
    data: {
      partnerId: input.partnerId.trim(),
      groupId: input.groupId.trim(),
      locationId: input.locationId.trim(),
    },
  })
  const o = (unwrapApiPayload(raw) ?? {}) as Record<string, unknown>
  const locRaw = (o.location ?? o.Location ?? {}) as Record<string, unknown>
  return {
    partnerId: String(o.partnerId ?? o.PartnerId ?? '').trim(),
    partnerName: String(o.partnerName ?? o.PartnerName ?? '').trim(),
    groupId: String(o.groupId ?? o.GroupId ?? '').trim(),
    groupName: String(o.groupName ?? o.GroupName ?? '').trim(),
    location: normalizeLocation(locRaw),
  }
}

export async function usAppChangePassword(input: UsAppChangePasswordInput): Promise<void> {
  await usAppApiRequest<unknown>({
    path: '/api/app/us-app-auth/change-password',
    method: 'POST',
    auth: true,
    data: {
      currentPassword: input.currentPassword,
      newPassword: input.newPassword,
      confirmNewPassword: input.confirmNewPassword,
    },
  })
}