diff --git a/main.js b/main.js index 1b5d59a..5a92cf7 100644 --- a/main.js +++ b/main.js @@ -13,12 +13,14 @@ const { const path = require('node:path') const fs = require('fs'); const https = require('https'); +const Registry = require('winreg'); const { autoUpdater, CancellationToken } = require('electron-updater'); const cancellationToken = new CancellationToken() app.allowRendererProcessReuse = false; let mainWindow = null; let isMaximized = false; let env; +let regKey; class AppWindow extends BrowserWindow { constructor(config) { @@ -134,6 +136,10 @@ app.on('ready', () => { updateHandle() // 每一小时检查更新 }, 1000 * 60 * 60) createTray() + regKey = new Registry({ + hive: Registry.HKCU, + key: '\\Software\\ZhiHuiXiang' + }); // 获取当前脚本所在目录的绝对路径 const currentDirectory = __dirname; // 获取安装父目录 @@ -272,7 +278,28 @@ app.on('ready', () => { const y = Math.round((display.workArea.height - mainWindow.getSize()[1]) / 2); mainWindow.setPosition(x, y); }); - + // 写入注册表 + ipcMain.handle('setRegistry', (event, uuid) => { + regKey.create((err) => { + if (err) { + return; + } + // 设置键和值 + regKey.set('uuid', Registry.REG_SZ, uuid, (err) => { + if (err) { + return; + } + }); + }); + }); + // 读取注册表 + ipcMain.handle('getRegistry', async () => { + return new Promise((resolve, reject) => { + regKey.get('uuid', (err, item) => { + resolve(item) + }) + }); + }); // 监听渲染进程请求应用数据目录 ipcMain.handle('get-user-data-path', () => { return app.getPath('userData'); @@ -360,8 +387,6 @@ function quitAndInstall() { autoUpdater.quitAndInstall(); } - - // 下载文件 function downloadFile(url, dest) { return new Promise((resolve, reject) => { diff --git a/package-lock.json b/package-lock.json index 7753fb3..651ba4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "WGShare.Metting", - "version": "0.1.14", + "version": "0.3.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "WGShare.Metting", - "version": "0.1.14", + "version": "0.3.5", "dependencies": { "@ant-design/icons": "^5.3.7", "@microsoft/signalr": "^8.0.0", @@ -29,10 +29,12 @@ "react-router-dom": "^6.23.1", "sass": "^1.77.5", "tldraw": "^2.2.0", - "webm-duration-fix-buffer": "^1.0.0" + "uuid": "^10.0.0", + "webm-duration-fix-buffer": "^1.0.0", + "winreg": "^1.2.5" }, "devDependencies": { - "@types/react": "^17.0.33", + "@types/react": "^18.0.0", "@types/react-dom": "^17.0.25", "@vitejs/plugin-react": "^1.0.7", "concurrently": "^7.6.0", @@ -2506,13 +2508,12 @@ "devOptional": true }, "node_modules/@types/react": { - "version": "17.0.80", - "resolved": "https://registry.npmmirror.com/@types/react/-/react-17.0.80.tgz", - "integrity": "sha512-LrgHIu2lEtIo8M7d1FcI3BdwXWoRQwMoXOZ7+dPTW0lYREjmlHl3P0U1VD0i/9tppOuv8/sam7sOjx34TxSFbA==", + "version": "18.3.9", + "resolved": "https://registry.npmmirror.com/@types/react/-/react-18.3.9.tgz", + "integrity": "sha512-+BpAVyTpJkNWWSSnaLBk6ePpHLOGJKnEQNbINNovPWzvEUyAe3e+/d494QdEh71RekM/qV7lw6jzf1HGrJyAtQ==", "devOptional": true, "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "^0.16", "csstype": "^3.0.2" } }, @@ -2525,6 +2526,17 @@ "@types/react": "^17" } }, + "node_modules/@types/react-dom/node_modules/@types/react": { + "version": "17.0.82", + "resolved": "https://registry.npmmirror.com/@types/react/-/react-17.0.82.tgz", + "integrity": "sha512-wTW8Lu/PARGPFE8tOZqCvprOKg5sen/2uS03yKn2xbCDFP9oLncm7vMDQ2+dEQXHVIXrOpW6u72xUXEXO0ypSw==", + "devOptional": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "^0.16", + "csstype": "^3.0.2" + } + }, "node_modules/@types/responselike": { "version": "1.0.3", "resolved": "https://registry.npmmirror.com/@types/responselike/-/responselike-1.0.3.tgz", @@ -11808,6 +11820,18 @@ "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8flags": { "version": "3.2.0", "resolved": "https://registry.npmmirror.com/v8flags/-/v8flags-3.2.0.tgz", @@ -12038,6 +12062,11 @@ "resolved": "https://registry.npmmirror.com/which-module/-/which-module-1.0.0.tgz", "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==" }, + "node_modules/winreg": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/winreg/-/winreg-1.2.5.tgz", + "integrity": "sha512-uf7tHf+tw0B1y+x+mKTLHkykBgK2KMs3g+KlzmyMbLvICSHQyB/xOFjTT8qZ3oeTFyU7Bbj4FzXitGG6jvKhYw==" + }, "node_modules/winston": { "version": "3.13.1", "resolved": "https://registry.npmmirror.com/winston/-/winston-3.13.1.tgz", @@ -13813,13 +13842,12 @@ "devOptional": true }, "@types/react": { - "version": "17.0.80", - "resolved": "https://registry.npmmirror.com/@types/react/-/react-17.0.80.tgz", - "integrity": "sha512-LrgHIu2lEtIo8M7d1FcI3BdwXWoRQwMoXOZ7+dPTW0lYREjmlHl3P0U1VD0i/9tppOuv8/sam7sOjx34TxSFbA==", + "version": "18.3.9", + "resolved": "https://registry.npmmirror.com/@types/react/-/react-18.3.9.tgz", + "integrity": "sha512-+BpAVyTpJkNWWSSnaLBk6ePpHLOGJKnEQNbINNovPWzvEUyAe3e+/d494QdEh71RekM/qV7lw6jzf1HGrJyAtQ==", "devOptional": true, "requires": { "@types/prop-types": "*", - "@types/scheduler": "^0.16", "csstype": "^3.0.2" } }, @@ -13830,6 +13858,19 @@ "devOptional": true, "requires": { "@types/react": "^17" + }, + "dependencies": { + "@types/react": { + "version": "17.0.82", + "resolved": "https://registry.npmmirror.com/@types/react/-/react-17.0.82.tgz", + "integrity": "sha512-wTW8Lu/PARGPFE8tOZqCvprOKg5sen/2uS03yKn2xbCDFP9oLncm7vMDQ2+dEQXHVIXrOpW6u72xUXEXO0ypSw==", + "devOptional": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "^0.16", + "csstype": "^3.0.2" + } + } } }, "@types/responselike": { @@ -20805,6 +20846,11 @@ "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==" + }, "v8flags": { "version": "3.2.0", "resolved": "https://registry.npmmirror.com/v8flags/-/v8flags-3.2.0.tgz", @@ -20983,6 +21029,11 @@ "resolved": "https://registry.npmmirror.com/which-module/-/which-module-1.0.0.tgz", "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==" }, + "winreg": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/winreg/-/winreg-1.2.5.tgz", + "integrity": "sha512-uf7tHf+tw0B1y+x+mKTLHkykBgK2KMs3g+KlzmyMbLvICSHQyB/xOFjTT8qZ3oeTFyU7Bbj4FzXitGG6jvKhYw==" + }, "winston": { "version": "3.13.1", "resolved": "https://registry.npmmirror.com/winston/-/winston-3.13.1.tgz", diff --git a/package.json b/package.json index b6b9ec4..5b5766d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "WGShare.Metting", "private": true, - "version": "0.3.10", + "version": "0.4.3", "main": "main.js", "authors": "yj", "description": "智汇享", @@ -44,10 +44,12 @@ "react-router-dom": "^6.23.1", "sass": "^1.77.5", "tldraw": "^2.2.0", - "webm-duration-fix-buffer": "^1.0.0" + "uuid": "^10.0.0", + "webm-duration-fix-buffer": "^1.0.0", + "winreg": "^1.2.5" }, - "devDependencies": { - "@types/react": "^17.0.33", + "devDependencies": { + "@types/react": "^18.0.0", "@types/react-dom": "^17.0.25", "@vitejs/plugin-react": "^1.0.7", "concurrently": "^7.6.0", diff --git a/preload.js b/preload.js index 0e9d0b1..51c897d 100644 --- a/preload.js +++ b/preload.js @@ -64,5 +64,13 @@ window.electron = { // 下载文件 downFile: (callback) => { ipcRenderer.on('downFile', callback) - } + }, + // 读取注册表 + getRegistry: () => { + return ipcRenderer.invoke('getRegistry') + }, + // 写入注册表 + setRegistry: (uuid) => { + ipcRenderer.invoke('setRegistry', uuid) + }, } diff --git a/src/App.tsx b/src/App.tsx index ffb48d8..92a36d8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,7 +9,7 @@ import Meeting from '@/page/Meeting/index' import NotFound from '@/page/NotFound/index' import { storage } from '@/utils' import { message, Spin } from "antd"; -import { onOtherSignalr, onReconnected, onStart, onStop, startSignalr } from "@/utils/package/signalr"; +import { onOtherSignalr, onReconnected, onStop, startSignalr } from "@/utils/package/signalr"; import JoinMeetingModal from "@/components/JoinMeetingModal"; import UpdateModal from "@/components/UpdateModal"; import * as CryptoJS from 'crypto-js'; @@ -35,7 +35,7 @@ const App: React.FC = () => { useEffect(() => { let userInfo = JSON.parse(storage.getItem('user') as string) let loginInfo = JSON.parse(storage.getItem('login') as string) - if (userInfo) { + if (userInfo && Number(userInfo.perms)) { if (loginInfo && loginInfo.isAutoLogin) { PostLogin({ account: loginInfo.account, @@ -160,13 +160,10 @@ const App: React.FC = () => { width: window.innerWidth, height: window.innerHeight, }); - try { - window.electron.getIsMaximized().then((res: boolean) => { - const dom = document.getElementById('root') as HTMLElement; - dom.style.borderRadius = res ? '0px' : '10px' - }) - } catch { - } + window.electron.getIsMaximized().then((res: boolean) => { + const dom = document.getElementById('root') as HTMLElement; + dom.style.borderRadius = res ? '0px' : '10px' + }) }; const onEventSignalr = (): void => { @@ -196,7 +193,6 @@ const App: React.FC = () => { window.electron.getWindowSize().then((res: any) => { switch (path) { case '/login': - storage.removeItem('user') storage.setItem('userLogin', false) navigate('/login') break; @@ -230,6 +226,7 @@ const App: React.FC = () => { } } else if (e.key === 'userLogin') { if (!Boolean(e.value)) { + storage.removeItem('user') navigate('/login') } } diff --git a/src/api/Login/index.ts b/src/api/Login/index.ts index 6783156..ce1a034 100644 --- a/src/api/Login/index.ts +++ b/src/api/Login/index.ts @@ -15,4 +15,11 @@ export const PostRefresh = (refreshToken: string) => request({ url: `auth/refresh?refreshToken=${refreshToken}`, method: 'post', + }) + +export const PostAnonLogin = (data: any) => + request({ + url: `/auth/anon-login`, + method: 'post', + data, }) \ No newline at end of file diff --git a/src/components/Operation/index.tsx b/src/components/Operation/index.tsx index 4bd1986..2ebc3dd 100644 --- a/src/components/Operation/index.tsx +++ b/src/components/Operation/index.tsx @@ -66,11 +66,9 @@ const Operation: React.FC = () => { }, []); const getIsMaximized = (): void => { - try { - window.electron.getIsMaximized().then((res: boolean) => { - changeOperationList(res ? 'maximize' : 'unmaximize') - }) - } catch { } + window.electron.getIsMaximized().then((res: boolean) => { + changeOperationList(res ? 'maximize' : 'unmaximize') + }) } const changeOperationList = (str: OperationKeyType): void => { diff --git a/src/components/SharedFilesModel/index.tsx b/src/components/SharedFilesModel/index.tsx index 097e9fa..7288ff1 100644 --- a/src/components/SharedFilesModel/index.tsx +++ b/src/components/SharedFilesModel/index.tsx @@ -196,7 +196,7 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => { setIsUpFile(false) setUploadProgress(100) message.success('上传成功') - }).catch(error => { + }).catch(_error => { setIsUpFile(false) message.error('上传失败') }); diff --git a/src/components/UpdateModal/index.module.scss b/src/components/UpdateModal/index.module.scss index 45afa0a..f1a5778 100644 --- a/src/components/UpdateModal/index.module.scss +++ b/src/components/UpdateModal/index.module.scss @@ -16,7 +16,6 @@ .buttons { width: 100%; - margin-top: 10px; text-align: center; .button2 { diff --git a/src/page/Home/index.tsx b/src/page/Home/index.tsx index 05afb2c..1e202d1 100644 --- a/src/page/Home/index.tsx +++ b/src/page/Home/index.tsx @@ -139,7 +139,6 @@ const Home: React.FC = () => { title="提示" description="确认退出吗?" onConfirm={() => { - storage.removeItem('user') storage.setItem('userLogin', false) }} onCancel={() => { diff --git a/src/page/Login/index.module.scss b/src/page/Login/index.module.scss index 4a220f3..df56c51 100644 --- a/src/page/Login/index.module.scss +++ b/src/page/Login/index.module.scss @@ -22,7 +22,7 @@ display: flex; flex-direction: column; - @for $i from 1 through 3 { + @for $i from 1 through 5 { >div:nth-child(#{$i}) { @if $i ==1 { flex-shrink: 0; @@ -66,6 +66,66 @@ } @else if $i ==3 { + flex-shrink: 0; + margin-bottom: 20px; + color: #ccc; + font-size: 16px; + display: flex; + align-items: center; + + >div { + flex-grow: 1; + height: 1px; + background-color: #3F3F3F; + } + + >span { + flex-shrink: 0; + margin: 0 4px; + color: #7A7A7A; + font-size: 12px; + } + } + + @else if $i ==4 { + display: flex; + align-items: center; + margin-bottom: 10px; + + @for $i from 1 through 2 { + >div:nth-child(#{$i}) { + @if $i ==1 { + flex-grow: 1; + } + + @else if $i ==2 { + flex-shrink: 0; + cursor: pointer; + height: 44px; + line-height: 44px; + display: flex; + justify-content: center; + align-items: center; + background-color: #3A1457; + box-shadow: none; + border-radius: 10px; + width: 56px; + margin-left: 4px; + transition: 0.3s; + + &:hover { + background-color: lighten(#3A1457, 5%) !important; + } + + &:active { + background-color: darken(#3A1457, 5%) !important; + } + } + } + } + } + + @else if $i ==5 { flex-shrink: 0; color: #ccc; text-align: right; @@ -75,12 +135,6 @@ } } - // 登录页固定大小不允许放大缩小,固需要单独写样式~! - .loginInput { - height: 44px; - line-height: 44px; - } - .loginInputIcon { :global { .ant-input { diff --git a/src/page/Login/index.tsx b/src/page/Login/index.tsx index 6c38c2f..20d88fb 100644 --- a/src/page/Login/index.tsx +++ b/src/page/Login/index.tsx @@ -2,12 +2,14 @@ import styles from '@/page/Login/index.module.scss' import { useEffect, useState } from "react"; import { useNavigate } from 'react-router-dom'; -import { Input, Button, Checkbox, message } from "antd" +import { Input, Button, Checkbox, message, Modal } from "antd" import { storage } from '@/utils' -import { GetCheckUser, PostLogin } from '@/api/Login' +import { GetCheckUser, PostAnonLogin, PostLogin } from '@/api/Login' import * as CryptoJS from 'crypto-js'; import ImageUrl from '@/utils/package/imageUrl' import { startSignalr } from '@/utils/package/signalr'; +import { v4 as uuidv4 } from 'uuid'; +import { GetCheckoutRoomNum, GetRoomInfo, GetRoomRtcToken } from '@/api/Home/Index'; const Login: React.FC = () => { const navigate = useNavigate(); const [accountPasswordStatus, setAccountPasswordStatus] = useState(false); @@ -30,17 +32,19 @@ const Login: React.FC = () => { ], optionsValue: [] }); + const [anonInfo, setAnonInfo] = useState({ + deviceId: '', + nickName: '', + roomNum: '', + }) + const [nameModal, setNameModal] = useState(false) useEffect(() => { - try { - window.electron.setMainWindowSize({ - width: 752, - height: 520, - key: 'login' - }) - } catch { - - } + window.electron.setMainWindowSize({ + width: 752, + height: 520, + key: 'login' + }) if (storage.getItem('login')) { const login = JSON.parse(storage.getItem('login') as string); const data = { @@ -119,7 +123,20 @@ const Login: React.FC = () => { optionsValue: checkedValues, })) }; - + const getRoomRtcToken = async (roomNum: string, callBack: Function): Promise => { + Promise.all([GetRoomRtcToken(roomNum), GetRoomRtcToken(roomNum + 'a')]).then(res => { + if (res[0].code === 200 && res[1].code === 200) { + callBack({ + token: res[0].data, + tokenA: res[1].data, + }) + } else { + storage.setItem('loading', false) + } + }).catch(() => { + storage.setItem('loading', false) + }) + } // 登录 const loginClick = (): void => { if (operation.password === '') { @@ -141,16 +158,12 @@ const Login: React.FC = () => { })) storage.setItem('user', JSON.stringify(res.data)) storage.setItem('userLogin', true) - try { - window.electron.getWindowSize().then((res: any) => { - window.electron.setMainWindowSize({ - width: Math.ceil(res.width / 1.5), - height: Math.ceil(res.height / 1.3), - }) + window.electron.getWindowSize().then((res: any) => { + window.electron.setMainWindowSize({ + width: Math.ceil(res.width / 1.5), + height: Math.ceil(res.height / 1.3), }) - } catch { - - } + }) startSignalr() navigate('/home') } @@ -228,11 +241,127 @@ const Login: React.FC = () => { : null} +
+
+ 游客登录 +
+
+
+
+ { + setAnonInfo({ + ...anonInfo, + roomNum: e.target.value + }) + }} /> +
+
{ + if (!anonInfo.roomNum) { + return message.error('请输入房间号!') + } + GetCheckoutRoomNum(anonInfo.roomNum).then(res => { + if (res.code === 200) { + if (res.data) { + window.electron.getRegistry().then(async (res: any) => { + const uuid = uuidv4(); + if (!res) { + window.electron.setRegistry(uuid) + } + setAnonInfo({ + ...anonInfo, + deviceId: res ? res.value : uuid, + nickName: storage.getItem('nickName') || '' + }) + storage.getItem('nickName') + setNameModal(true) + }) + } else { + message.error('房间号不存在!') + } + } + }) + }} + >
+
版本号:{version}
+ +
+
+ { + setAnonInfo({ + ...anonInfo, + nickName: e.target.value + }) + storage.setItem('nickName', e.target.value) + }} + /> +
+
+ + +
+
+
) } diff --git a/src/page/Meeting/index.tsx b/src/page/Meeting/index.tsx index 1073263..8141d4d 100644 --- a/src/page/Meeting/index.tsx +++ b/src/page/Meeting/index.tsx @@ -188,15 +188,11 @@ const Meeting: React.FC = () => { let time: NodeJS.Timeout; // let getDesktopCapturerVideoTime: NodeJS.Timeout; setUser(userInfo) - setTimeout(() => { - if (location.hash.indexOf('/login') === -1) { - window.electron.getIsMaximized().then((res: boolean) => { - if (!res) { - window.electron.setViewStatus('maximize') - } - }) + window.electron.getIsMaximized().then((res: boolean) => { + if (!res) { + window.electron.setViewStatus('maximize') } - }, 1000) + }) setMeetingMode('StandardMode'); agoraInit() storage.setItem('noViewChatList', 0) @@ -667,8 +663,8 @@ const Meeting: React.FC = () => { // 声网初始化 const agoraInit = async () => { - await getJoin(state.enableMicr, state.enableCamera) await agora.init(true) + await getJoin(state.enableMicr, state.enableCamera) agora.registerEventHandler({ onJoinChannelSuccess: async (connection: RtcConnection, _elapsed: number) => { if (connection.channelId === state.channelId) { @@ -1215,8 +1211,12 @@ const Meeting: React.FC = () => { if (bool) { await getLeave() } - agora.leaveChannel() - navigate('/home/index') + await agora.leaveChannel() + if (Number(user.perms)) { + navigate('/home/index') + } else { + storage.setItem('userLogin', false) + } } // 分享屏幕 const clickSharedScreen = async (): Promise => { diff --git a/src/render.d.ts b/src/render.d.ts index 2146c05..46fb8cb 100644 --- a/src/render.d.ts +++ b/src/render.d.ts @@ -16,6 +16,8 @@ export interface IElectronAPI { downFile: (callBack: Function) => void; quitAndInstall: (callBack: Function) => void; getVersion: () => Promise; + setRegistry: (uuid: string) => any; + getRegistry: () => any; } declare global { diff --git a/src/shims-react.d.ts b/src/shims-react.d.ts index efafa2a..cad1cfa 100644 --- a/src/shims-react.d.ts +++ b/src/shims-react.d.ts @@ -1,2 +1,3 @@ declare module 'react-dom/client'; -declare module 'crypto-js'; \ No newline at end of file +declare module 'crypto-js'; +declare module 'uuid'; \ No newline at end of file diff --git a/src/utils/package/signalr.ts b/src/utils/package/signalr.ts index f2ab22a..b31353e 100644 --- a/src/utils/package/signalr.ts +++ b/src/utils/package/signalr.ts @@ -10,7 +10,7 @@ export const startSignalr = async () => { accessTokenFactory: () => user.token }) .build(); - onStart() + await onStart() storage.setItem('isSignalr', true) connection.onclose(async () => { await onStart() diff --git a/src/utils/request/request.ts b/src/utils/request/request.ts index 11eba68..490b9e6 100644 --- a/src/utils/request/request.ts +++ b/src/utils/request/request.ts @@ -112,7 +112,6 @@ class Request { } } function toLogin() { - storage.removeItem('user') storage.setItem('userLogin', false) } function updatePostRefresh() {