auth.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // 工厂管理后台认证状态管理
  2. import { defineStore } from 'pinia';
  3. import { ref, computed } from 'vue';
  4. import type { User } from '@smartcut/types';
  5. import { AuthApi, createApiClient } from '@smartcut/api-client';
  6. import {
  7. STORAGE_KEYS,
  8. setSessionStorage,
  9. getSessionStorage,
  10. removeSessionStorage
  11. } from '@smartcut/shared-utils';
  12. import { getApiBaseUrl } from '@/apiConfig';
  13. export const useAuthStore = defineStore('auth', () => {
  14. // 状态定义
  15. const token = ref<string | null>(getSessionStorage<string>(STORAGE_KEYS.FACTORY_TOKEN));
  16. const user = ref<User | null>(getSessionStorage<User>(STORAGE_KEYS.FACTORY_USER));
  17. const currentFactoryId = ref<string | null>(
  18. getSessionStorage<string>(STORAGE_KEYS.CURRENT_FACTORY_ID)
  19. );
  20. const isLoggedIn = computed(() => !!token.value && !!user.value && !!currentFactoryId.value);
  21. // 创建API客户端(factory_id 由后端从 Token 自动提取)
  22. const apiClient = createApiClient({
  23. baseURL: getApiBaseUrl(),
  24. tokenKey: STORAGE_KEYS.FACTORY_TOKEN
  25. });
  26. const authApi = new AuthApi(apiClient);
  27. /**
  28. * 工厂管理员登录
  29. * factoryId 通过 Query 参数传递给后端
  30. */
  31. async function login(username: string, password: string, factoryId: string) {
  32. try {
  33. // 登录时传递 factoryId 作为 Query 参数
  34. const response = await authApi.login(
  35. { username, password },
  36. factoryId
  37. );
  38. // 存储Token、用户信息、factory_id到SessionStorage
  39. token.value = response.token;
  40. user.value = response.user as User;
  41. currentFactoryId.value = factoryId;
  42. setSessionStorage(STORAGE_KEYS.FACTORY_TOKEN, response.token);
  43. setSessionStorage(STORAGE_KEYS.FACTORY_USER, response.user);
  44. setSessionStorage(STORAGE_KEYS.CURRENT_FACTORY_ID, factoryId);
  45. return response;
  46. } catch (error) {
  47. console.error('登录失败:', error);
  48. throw error;
  49. }
  50. }
  51. /**
  52. * 登出
  53. */
  54. async function logout() {
  55. // P1: best-effort 调后端撤销 jti,失败不阻塞本地登出
  56. try {
  57. await authApi.logout();
  58. } catch (e) { /* 忽略 */ }
  59. token.value = null;
  60. user.value = null;
  61. // 保留 currentFactoryId,便于重新登录同一工厂
  62. removeSessionStorage(STORAGE_KEYS.FACTORY_TOKEN);
  63. removeSessionStorage(STORAGE_KEYS.FACTORY_USER);
  64. }
  65. /**
  66. * 获取用户信息
  67. */
  68. async function fetchProfile() {
  69. if (!token.value || !currentFactoryId.value) return;
  70. try {
  71. const profile = await authApi.getProfile();
  72. user.value = profile as User;
  73. setSessionStorage(STORAGE_KEYS.FACTORY_USER, profile);
  74. } catch (error) {
  75. console.error('获取用户信息失败:', error);
  76. logout();
  77. }
  78. }
  79. /**
  80. * 修改密码
  81. */
  82. async function changePassword(oldPassword: string, newPassword: string) {
  83. try {
  84. await authApi.changePassword({
  85. old_password: oldPassword,
  86. new_password: newPassword
  87. });
  88. if (user.value) {
  89. user.value.must_change_password = false;
  90. setSessionStorage(STORAGE_KEYS.FACTORY_USER, user.value);
  91. }
  92. } catch (error) {
  93. console.error('修改密码失败:', error);
  94. throw error;
  95. }
  96. }
  97. /**
  98. * 从URL Query参数设置factory_id
  99. */
  100. function setFactoryIdFromQuery(factoryId: string) {
  101. currentFactoryId.value = factoryId;
  102. setSessionStorage(STORAGE_KEYS.CURRENT_FACTORY_ID, factoryId);
  103. }
  104. return {
  105. token,
  106. user,
  107. currentFactoryId,
  108. isLoggedIn,
  109. login,
  110. logout,
  111. fetchProfile,
  112. changePassword,
  113. setFactoryIdFromQuery
  114. };
  115. });