main.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. import axios from "axios"
  2. import { defineStore } from "pinia";
  3. import { api } from "@/api"
  4. import router from "@/router"
  5. import { getLocalToken, removeLocalToken, saveLocalToken } from "@/utils";
  6. import type { AppNotification } from '@/interfaces';
  7. import type { IUserProfile, IUserProfileCreate, IUserProfileUpdate, MainState, Video, VideoCreate, ArticleCreate, Image, ImageDownload, VideoUploaded, YTViewsUserData } from '@/interfaces';
  8. import i18n from '@/plugins/i18n'
  9. import { wsUrl } from "@/env";
  10. const defaultState: MainState = {
  11. isLoggedIn: null,
  12. token: '',
  13. logInError: false,
  14. userProfile: null,
  15. dashboardMiniDrawer: false,
  16. dashboardShowDrawer: true,
  17. notifications: [],
  18. videos: [],
  19. images: [],
  20. videosWebSocket: new WebSocket(`${wsUrl}/api/v1/videos`)
  21. };
  22. export const useMainStore = defineStore("MainStoreId", {
  23. state: () => defaultState,
  24. getters: {
  25. readhasAdminAccess: (state) =>
  26. state.userProfile && state.userProfile.is_superuser && state.userProfile.is_active,
  27. readLoginError: (state) => state.logInError,
  28. readDashboardShowDrawer: (state) => state.dashboardShowDrawer,
  29. readDashboardMiniDrawer: (state) => state.dashboardMiniDrawer,
  30. readUserProfile: (state) => state.userProfile,
  31. readToken: (state) => state.token,
  32. readIsLoggedIn: (state) => state.isLoggedIn,
  33. readFirstNotification: (state) => state.notifications.length > 0 && state.notifications[0],
  34. readVideos: (state) => state.videos,
  35. },
  36. actions: {
  37. // setters
  38. setToken(payload: string) { this.token = payload; },
  39. setLoggedIn(payload: boolean) { this.isLoggedIn = payload; },
  40. setLogInError(payload: boolean) { this.logInError = payload; },
  41. setUserProfile(payload: IUserProfile) { this.userProfile = payload },
  42. setDashboardMiniDrawer(payload: boolean) { this.dashboardMiniDrawer = payload; },
  43. setDashboardShowDrawer(payload: boolean) { this.dashboardShowDrawer = payload; },
  44. setVideos(payload: Video[]) { this.videos = payload },
  45. addNotification(payload: AppNotification) { this.notifications.push(payload); },
  46. removeNotification(payload: AppNotification) {
  47. if (payload) {
  48. this.notifications = this.notifications.filter(
  49. (notification) => notification !== payload,
  50. );
  51. }
  52. },
  53. // actions
  54. async logIn(username: string, password: string) {
  55. try {
  56. const response = await api.logInGetToken(username, password);
  57. const token: string = response.data.access_token;
  58. if (token) {
  59. saveLocalToken(token);
  60. this.setToken(token);
  61. this.setLoggedIn(true);
  62. this.setLogInError(false);
  63. await this.getUserProfile();
  64. await this.routeLoggedIn();
  65. this.addNotification({ content: i18n.global.t("loggedIn"), color: "success" });
  66. } else {
  67. await this.logOut();
  68. }
  69. } catch (err) {
  70. this.addNotification({ content: i18n.global.t("loggedError"), color: "error" });
  71. this.setLogInError(true);
  72. await this.logOut();
  73. }
  74. },
  75. async qrLogIn(username: string, password: string, ser_no: string) {
  76. try {
  77. const response = await api.qrLogInGetToken(username, password, ser_no);
  78. return response;
  79. } catch (error) {
  80. console.log('error', error);
  81. }
  82. },
  83. async googleLogin(username: string) {
  84. try {
  85. const response = await api.googleLogin(username);
  86. const token: string = response.data.access_token;
  87. if (token) {
  88. saveLocalToken(token);
  89. this.setToken(token);
  90. this.setLoggedIn(true);
  91. this.setLogInError(false);
  92. await this.getUserProfile();
  93. await this.routeLoggedIn();
  94. this.addNotification({ content: i18n.global.t("loggedIn"), color: "success" });
  95. } else {
  96. await this.logOut();
  97. }
  98. } catch (err) {
  99. this.setLogInError(true);
  100. await this.logOut();
  101. }
  102. },
  103. async qrGoogleLogin(username: string, ser_no: string) {
  104. try {
  105. const response = await api.qrGoogleLogin(username, ser_no);
  106. return response;
  107. } catch (error) {
  108. console.log('error', error);
  109. }
  110. },
  111. async qrAddTime(code: string) {
  112. try {
  113. const response = await api.qrAddTime(this.token, code);
  114. return response;
  115. } catch (error) {
  116. console.log('error', error);
  117. return error;
  118. }
  119. },
  120. async getUserProfile() {
  121. try {
  122. const response = await api.getMe(this.token);
  123. if (response.data) {
  124. this.setUserProfile(response.data);
  125. }
  126. } catch (error) {
  127. await this.checkApiError(error);
  128. }
  129. },
  130. async updateUserProfile(payload: IUserProfileUpdate) {
  131. try {
  132. const loadingNotification = { content: i18n.global.t("saving"), showProgress: true };
  133. await this.addNotification(loadingNotification);
  134. const response = (
  135. await Promise.all([
  136. api.updateMe(this.token, payload),
  137. await new Promise<void>((resolve, _) => setTimeout(() => resolve(), 500)),
  138. ])
  139. )[0];
  140. this.setUserProfile(response.data);
  141. this.removeNotification(loadingNotification);
  142. this.addNotification({
  143. content: i18n.global.t("profileUpdated"),
  144. color: "success",
  145. });
  146. } catch (error) {
  147. await this.checkApiError(error);
  148. }
  149. },
  150. async checkLoggedIn() {
  151. if (!this.isLoggedIn) {
  152. let token = this.token;
  153. if (!token) {
  154. const localToken = getLocalToken();
  155. if (localToken) {
  156. this.setToken(localToken);
  157. token = localToken;
  158. }
  159. }
  160. if (token) {
  161. try {
  162. const response = await api.getMe(token);
  163. this.setLoggedIn(true);
  164. this.setUserProfile(response.data);
  165. router.push("/main/dashboard");
  166. } catch (error) {
  167. await this.removeLogIn();
  168. }
  169. } else {
  170. await this.removeLogIn();
  171. }
  172. }
  173. },
  174. async qrCheckLoggedIn() {
  175. if (!this.isLoggedIn) {
  176. let token = this.token;
  177. if (!token) {
  178. const localToken = getLocalToken();
  179. if (localToken) {
  180. this.setToken(localToken);
  181. token = localToken;
  182. }
  183. }
  184. if (token) {
  185. try {
  186. const response = await api.getMe(token);
  187. this.setLoggedIn(true);
  188. this.setUserProfile(response.data);
  189. // router.push("/main/dashboard");
  190. } catch (error) {
  191. await this.removeLogIn();
  192. }
  193. } else {
  194. await this.removeLogIn();
  195. }
  196. }
  197. },
  198. async removeLogIn() {
  199. removeLocalToken();
  200. this.setToken("");
  201. this.setLoggedIn(false);
  202. },
  203. async logOut() {
  204. await this.removeLogIn();
  205. this.routeLogOut();
  206. },
  207. async userLogOut() {
  208. await this.logOut();
  209. this.addNotification({ content: "Logged out", color: "success" });
  210. },
  211. routeLogOut() {
  212. if (router.currentRoute.value.path !== "/login") {
  213. router.push("/login");
  214. }
  215. },
  216. async checkApiError(payload: unknown) {
  217. if (axios.isAxiosError(payload)) {
  218. if (payload.response?.status === 401) {
  219. await this.logOut();
  220. }
  221. }
  222. },
  223. routeLoggedIn() {
  224. if (router.currentRoute.value.path === "/login" || router.currentRoute.value.path === "/") {
  225. router.push("/main/dashboard");
  226. }
  227. },
  228. async dispatchRemoveNotification(payload: { notification: AppNotification; timeout: number },) {
  229. return new Promise((resolve, _) => {
  230. setTimeout(() => {
  231. this.removeNotification(payload.notification);
  232. resolve(true);
  233. }, payload.timeout);
  234. });
  235. },
  236. async register(payload: IUserProfileCreate) {
  237. const loadingNotification = {
  238. content: i18n.global.t("signingUp"),
  239. showProgress: true,
  240. };
  241. try {
  242. this.addNotification(loadingNotification);
  243. const response = (
  244. await Promise.all([
  245. api.registerUser(payload),
  246. await new Promise<void>((resolve, _) => setTimeout(() => resolve(), 500)),
  247. ])
  248. )[0];
  249. this.removeNotification(loadingNotification);
  250. this.addNotification({
  251. content: i18n.global.t("registerSuccess"),
  252. color: "success",
  253. });
  254. setTimeout(() => {
  255. router.push("/login")
  256. }, 2000)
  257. } catch (error) {
  258. this.addNotification({ content: i18n.global.t("registerError"), color: "error" });
  259. await this.checkApiError(error);
  260. }
  261. },
  262. async passwordRecovery(username: string) {
  263. const loadingNotification = {
  264. content: i18n.global.t("sendingEmail"),
  265. showProgress: true,
  266. };
  267. try {
  268. this.addNotification(loadingNotification);
  269. await Promise.all([
  270. api.passwordRecovery(username),
  271. await new Promise<void>((resolve, _) => setTimeout(() => resolve(), 500)),
  272. ]);
  273. this.removeNotification(loadingNotification);
  274. this.addNotification({
  275. content: i18n.global.t("passwordMailSent"),
  276. color: "success",
  277. });
  278. await this.logOut();
  279. } catch (error) {
  280. this.removeNotification(loadingNotification);
  281. this.addNotification({ color: "error", content: i18n.global.t("incorrectUsername") });
  282. }
  283. },
  284. async resetPassword(password: string, token: string) {
  285. const loadingNotification = { content: "Resetting password", showProgress: true };
  286. try {
  287. this.addNotification(loadingNotification);
  288. await Promise.all([
  289. api.resetPassword(token, password),
  290. await new Promise<void>((resolve, _) => setTimeout(() => resolve(), 500)),
  291. ]);
  292. this.removeNotification(loadingNotification);
  293. this.addNotification({
  294. content: "Password successfully reset",
  295. color: "success",
  296. });
  297. await this.logOut();
  298. } catch (error) {
  299. this.removeNotification(loadingNotification);
  300. this.addNotification({
  301. color: "error",
  302. content: "Error resetting password",
  303. });
  304. }
  305. },
  306. async uploadPlot(video_data: VideoCreate, file: File) {
  307. const mainStore = useMainStore();
  308. try {
  309. const loadingNotification = { content: i18n.global.t("sending"), showProgress: true };
  310. mainStore.addNotification(loadingNotification);
  311. const response = (
  312. await Promise.all([
  313. await api.uploadPlot(mainStore.token, video_data, file),
  314. await new Promise<void>((resolve, _) => setTimeout(() => resolve(), 0)),
  315. ])
  316. );
  317. mainStore.removeNotification(loadingNotification);
  318. if (response[0].data.accepted !== false) {
  319. mainStore.addNotification({
  320. content: i18n.global.t("fileReceived"),
  321. color: "success",
  322. })
  323. } else {
  324. mainStore.addNotification({
  325. content: i18n.global.t("uploadFailed"),
  326. color: "error",
  327. })
  328. }
  329. // mainStore.removeNotification(loadingNotification);
  330. // mainStore.addNotification({
  331. // content: i18n.global.t("fileReceived"),
  332. // color: "success",
  333. // })
  334. this.actionGetVideos();
  335. return response[0].data;
  336. } catch (error) {
  337. await mainStore.checkApiError(error);
  338. }
  339. const ret: VideoUploaded = { accepted: false, error_message: "api error", video_info: null }
  340. return ret
  341. },
  342. async uploadImage(file: File[]) {
  343. const mainStore = useMainStore();
  344. try {
  345. // const loadingNotification = { content: i18n.global.t("sending"), showProgress: true };
  346. // mainStore.addNotification(loadingNotification);
  347. const response = (
  348. await Promise.all([
  349. api.uploadImage(mainStore.token, file),
  350. await new Promise<void>((resolve, _) => setTimeout(() => resolve(), 0)),
  351. ]).then(data => {
  352. for (let i = 0; i < data[0].data.filenames.length; i++) {
  353. const element = data[0].data.filenames[i];
  354. const tmpImage: Image = {
  355. file_name: file[i].name,
  356. stored_file_name: element,
  357. content: "sr",
  358. state: "subscribe",
  359. link: ""
  360. };
  361. this.addImage(tmpImage);
  362. }
  363. // localStorage.setItem('imagesList', JSON.stringify(this.images));
  364. })
  365. );
  366. // mainStore.removeNotification(loadingNotification);
  367. mainStore.addNotification({
  368. content: i18n.global.t("fileReceived"),
  369. color: "success",
  370. })
  371. // this.actionGetVideos();
  372. } catch (error) {
  373. await mainStore.checkApiError(error);
  374. }
  375. },
  376. // async getImage(data: ImageDownload) {
  377. // const mainStore = useMainStore();
  378. // try {
  379. // const response = (
  380. // await Promise.all([
  381. // api.getImage(mainStore.token, data),
  382. // await new Promise<void>((resolve, _) => setTimeout(() => resolve(), 0)),
  383. // ])
  384. // );
  385. // } catch (error) {
  386. // await mainStore.checkApiError(error);
  387. // }
  388. // },
  389. addImage(payload: Image) {
  390. this.images.push(payload);
  391. },
  392. async finishImage(payload: ImageDownload) {
  393. const WS = new WebSocket(`${wsUrl}/api/v1/images/sr`);
  394. let image = this.images.filter(e => {
  395. return payload.stored_file_name.includes(e.stored_file_name)
  396. });
  397. const mainStore = useMainStore();
  398. try {
  399. const response = await api.downloadImage(mainStore.token, payload);
  400. if (image) {
  401. image.map(e => {
  402. e.state = "completed";
  403. e.link = response.data;
  404. })
  405. }
  406. } catch (error) {
  407. await mainStore.checkApiError(error);
  408. }
  409. // 全部完成後回傳 WebSocket
  410. let processing = this.images.find(e => e.state !== "completed");
  411. if (!processing) {
  412. setTimeout(() => {
  413. // WS.close();
  414. WS.send("unsubscribe");
  415. }, 1000)
  416. }
  417. return !this.images.some(e => e.state === "completed")
  418. },
  419. async uploadArticle(article_data: ArticleCreate) {
  420. const mainStore = useMainStore();
  421. try {
  422. const loadingNotification = { content: i18n.global.t("sending"), showProgress: true };
  423. mainStore.addNotification(loadingNotification);
  424. const response = (
  425. await Promise.all([
  426. api.uploadArticle(mainStore.token, article_data),
  427. await new Promise<void>((resolve, _) => setTimeout(() => resolve(), 0)),
  428. ])
  429. );
  430. mainStore.removeNotification(loadingNotification);
  431. mainStore.addNotification({
  432. content: i18n.global.t("fileReceived"),
  433. color: "success",
  434. })
  435. // this.actionGetVideos();
  436. } catch (error) {
  437. await mainStore.checkApiError(error);
  438. }
  439. },
  440. async actionGetVideos() {
  441. const mainStore = useMainStore();
  442. try {
  443. const response = await api.getVideos(mainStore.token)
  444. if (response) {
  445. this.setVideos(response.data);
  446. }
  447. } catch (error) {
  448. await mainStore.checkApiError(error);
  449. }
  450. },
  451. async ecpayPaymentHTML(amount: number) {
  452. const mainStore = useMainStore();
  453. try {
  454. const response = await api.ecpayPaymentHTML(mainStore.token, amount)
  455. if (response) {
  456. return response.data;
  457. }
  458. } catch (error) {
  459. await mainStore.checkApiError(error);
  460. }
  461. },
  462. async YTViewsTestPayment(user_data: YTViewsUserData) {
  463. const mainStore = useMainStore();
  464. try {
  465. const response = (
  466. await Promise.all([
  467. api.YTViewsTestPayment(user_data),
  468. await new Promise<void>((resolve, _) => setTimeout(() => resolve(), 0)),
  469. ])
  470. );
  471. if (response[0]) {
  472. return response[0].data;
  473. }
  474. } catch (error) {
  475. await mainStore.checkApiError(error);
  476. }
  477. },
  478. async YTViewsPayment(user_data: YTViewsUserData) {
  479. const mainStore = useMainStore();
  480. try {
  481. const response = (
  482. await Promise.all([
  483. api.YTViewsPayment(user_data),
  484. await new Promise<void>((resolve, _) => setTimeout(() => resolve(), 0)),
  485. ])
  486. );
  487. if (response[0]) {
  488. return response[0].data;
  489. }
  490. } catch (error) {
  491. await mainStore.checkApiError(error);
  492. }
  493. },
  494. }
  495. });