diff --git a/.env.development b/.env.development index 7c281ac..89fb9a9 100644 --- a/.env.development +++ b/.env.development @@ -16,4 +16,4 @@ VITE_TITLE_NAME='五味子云相册' VITE_APP_TOKEN_KEY='Bearer' # the websocket url -VITE_WEB_SOCKET_URL='ws://127.0.0.1:8080/api/ws/socket' +VITE_WEB_SOCKET_URL='ws://127.0.0.1:8080/api/ws/gws' diff --git a/.env.production b/.env.production index fc46c40..6bd4ec8 100644 --- a/.env.production +++ b/.env.production @@ -15,4 +15,4 @@ VITE_TITLE_NAME='五味子云相册' VITE_APP_TOKEN_KEY='Bearer' # the websocket url -VITE_WEB_SOCKET_URL='ws://127.0.0.1:8080/api/ws/socket' +VITE_WEB_SOCKET_URL='ws://127.0.0.1:8080/api/ws/gws' diff --git a/components.d.ts b/components.d.ts index f3c8183..bae23a2 100644 --- a/components.d.ts +++ b/components.d.ts @@ -7,6 +7,7 @@ export {} /* prettier-ignore */ declare module 'vue' { export interface GlobalComponents { + 3DCard: typeof import('./src/components/3DCard/3DCard.vue')['default'] AButton: typeof import('ant-design-vue/es')['Button'] AButtonGroup: typeof import('ant-design-vue/es')['ButtonGroup'] ACard: typeof import('ant-design-vue/es')['Card'] @@ -27,7 +28,9 @@ declare module 'vue' { ATimePicker: typeof import('ant-design-vue/es')['TimePicker'] ATooltip: typeof import('ant-design-vue/es')['Tooltip'] BoxDog: typeof import('./src/components/BoxDog/BoxDog.vue')['default'] + Card3D: typeof import('./src/components/3DCard/Card3D.vue')['default'] DynamicTitle: typeof import('./src/components/DynamicTitle/DynamicTitle.vue')['default'] + EffectsCard: typeof import('./src/components/EffectsCard/EffectsCard.vue')['default'] ForgetPage: typeof import('./src/views/Forget/ForgetPage.vue')['default'] LandingPage: typeof import('./src/views/Landing/LandingPage.vue')['default'] LockOutlined: typeof import('@ant-design/icons-vue')['LockOutlined'] diff --git a/eslint.config.js b/eslint.config.js index b40a888..cb124f2 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -17,6 +17,7 @@ export default [ "@typescript-eslint/no-explicit-any": "off", // "no-unused-vars": "off", // "@typescript-eslint/no-unused-vars": ["off"], + "vue/multi-word-component-names":"off", } } ]; diff --git a/src/App.vue b/src/App.vue index 91dab37..4897802 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,7 +1,23 @@ - + diff --git a/src/api/oauth/github.ts b/src/api/oauth/github.ts index 85f7252..d2dec7f 100644 --- a/src/api/oauth/github.ts +++ b/src/api/oauth/github.ts @@ -3,9 +3,12 @@ import {service} from "@/utils/alova/service.ts"; /** * Get Github OAuth URL */ -export const getGithubUrl = () => { +export const getGithubUrl = (state: string) => { return service.Get('/api/oauth/github/get_url', { + params: { + state: state + }, meta: { ignoreToken: true, }, diff --git a/src/api/oauth/qq.ts b/src/api/oauth/qq.ts new file mode 100644 index 0000000..bcb69b0 --- /dev/null +++ b/src/api/oauth/qq.ts @@ -0,0 +1,18 @@ +import {service} from "@/utils/alova/service.ts"; + +export const getQQUrl = (state: string) => { + return service.Get('/api/oauth/qq/get_url', + { + params: { + state: state + }, + meta: { + ignoreToken: true, + }, + cacheFor: { + mode: "restore", + expire: 1000 * 60 * 60 * 24 * 30 // 30 days + } + } + ); +}; diff --git a/src/api/oauth/wechat.ts b/src/api/oauth/wechat.ts index 7bf5e1f..1166df9 100644 --- a/src/api/oauth/wechat.ts +++ b/src/api/oauth/wechat.ts @@ -4,7 +4,7 @@ import {service} from "@/utils/alova/service.ts"; * 生成客户端id */ export const generateClientId = () => { - return service.Get('/api/oauth/generate_client_id', + return service.Get('/api/oauth/wechat/generate_client_id', { meta: { ignoreToken: true, @@ -21,7 +21,7 @@ export const generateClientId = () => { * @param clientId */ export const generateQrCode = (clientId: string) => { - return service.Get('/api/oauth/get_temp_qrcode', + return service.Get('/api/oauth/wechat/get_temp_qrcode', { params: { client_id: clientId diff --git a/src/assets/images/logo-schisandra.png b/src/assets/images/logo-schisandra.png new file mode 100644 index 0000000..efc805f Binary files /dev/null and b/src/assets/images/logo-schisandra.png differ diff --git a/src/assets/svgs/gitee.svg b/src/assets/svgs/gitee.svg new file mode 100644 index 0000000..cc8b7d3 --- /dev/null +++ b/src/assets/svgs/gitee.svg @@ -0,0 +1 @@ + diff --git a/src/components/3DCard/Card3D.vue b/src/components/3DCard/Card3D.vue new file mode 100644 index 0000000..bb4f176 --- /dev/null +++ b/src/components/3DCard/Card3D.vue @@ -0,0 +1,241 @@ + + + diff --git a/src/components/EffectsCard/EffectsCard.vue b/src/components/EffectsCard/EffectsCard.vue new file mode 100644 index 0000000..55a9b2b --- /dev/null +++ b/src/components/EffectsCard/EffectsCard.vue @@ -0,0 +1,373 @@ + + + diff --git a/src/layout/Landing/Content/Content.vue b/src/layout/Landing/Content/Content.vue new file mode 100644 index 0000000..41f272a --- /dev/null +++ b/src/layout/Landing/Content/Content.vue @@ -0,0 +1,12 @@ + + + diff --git a/src/layout/Landing/Footer/Footer.vue b/src/layout/Landing/Footer/Footer.vue new file mode 100644 index 0000000..f458972 --- /dev/null +++ b/src/layout/Landing/Footer/Footer.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/layout/Landing/Header/Header.vue b/src/layout/Landing/Header/Header.vue new file mode 100644 index 0000000..a3853a5 --- /dev/null +++ b/src/layout/Landing/Header/Header.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/layout/Landing/Header/index.scss b/src/layout/Landing/Header/index.scss new file mode 100644 index 0000000..9dbd309 --- /dev/null +++ b/src/layout/Landing/Header/index.scss @@ -0,0 +1,118 @@ +.landing-header { + height: 100px; + width: 80%; + //background-color: #767779; + display: flex; + align-items: center; + justify-content: space-between; + + .landing-header-logo { + display: inline-block; + margin-right: 1rem; + width: 50px; + height: 50px; + padding: 1rem; + } + + .toggle-box-label-left:empty { + margin-left: -10px; + } + + .toggle-box-label-left:before, + .toggle-box-label-left:after { + box-sizing: border-box; + margin: 0; + padding: 0; + /*transition*/ + -webkit-transition: 0.25s ease-in-out; + -moz-transition: 0.25s ease-in-out; + -o-transition: 0.25s ease-in-out; + transition: 0.25s ease-in-out; + outline: none; + } + + .toggle-box input[type=checkbox], + .toggle-box input[type=checkbox]:active { + position: absolute; + top: -5000px; + height: 0; + width: 0; + opacity: 0; + border: none; + outline: none; + } + + .toggle-box label { + display: inline-block; + position: relative; + padding: 0px; + margin-bottom: 20px; + font-size: 14px; + line-height: 16px; + cursor: pointer; + color: rgba(149, 149, 149, 0.51); + font-weight: normal; + } + + .toggle-box-label-left:before { + content: ''; + display: block; + position: absolute; + z-index: 1; + line-height: 34px; + text-indent: 40px; + height: 16px; + width: 16px; + margin: 4px; + /*border-radius*/ + -webkit-border-radius: 100%; + -moz-border-radius: 100%; + border-radius: 100%; + right: 26px; + bottom: 0px; + background: #FFB200; + transform: rotate(-45deg); + box-shadow: 0 0 10px white; + } + + .toggle-box-label-left:after { + content: ""; + display: inline-block; + width: 40px; + height: 24px; + /*border-radius*/ + -webkit-border-radius: 16px; + -moz-border-radius: 16px; + border-radius: 16px; + background: rgba(255, 255, 255, 0.15); + vertical-align: middle; + margin: 0 10px; + border: 2px solid #FFB200; + } + + .toggle-box input[type=checkbox]:checked + .toggle-box-label-left:before { + right: 17px; + box-shadow: 5px 5px 0 0 #eee; + background: transparent; + } + + .toggle-box input[type=checkbox]:checked + .toggle-box-label-left:after { + background: rgba(0, 0, 0, 0.15); + border: 2px solid white; + } + + .toggle-box input[type=checkbox] + .toggle-box-label-left { + color: rgba(250, 250, 250, 0.51); + font-weight: bold; + } + + .toggle-box input[type=checkbox]:checked + .toggle-box-label-left { + color: rgba(149, 149, 149, 0.51); + font-weight: normal; + } + + .toggle-box input[type=checkbox]:checked + .toggle-box-label-left + .toggle-box-label { + color: rgba(250, 250, 250, 0.51); + font-weight: bold; + } +} diff --git a/src/layout/Landing/index.vue b/src/layout/Landing/index.vue new file mode 100644 index 0000000..8bc2f15 --- /dev/null +++ b/src/layout/Landing/index.vue @@ -0,0 +1,154 @@ + + + diff --git a/src/layout/default/DefaultLayout.vue b/src/layout/default/DefaultLayout.vue deleted file mode 100644 index 4897802..0000000 --- a/src/layout/default/DefaultLayout.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/src/locales/language/zh.ts b/src/locales/language/zh.ts index 035b4d5..f337319 100644 --- a/src/locales/language/zh.ts +++ b/src/locales/language/zh.ts @@ -23,7 +23,7 @@ export default { passwordRule: "密码要6~18位字符,且必须包含字母、数字和特殊符号!", phoneLoginAndRegister: "短信注册/登录", open: "请打开", - scan: "扫码登录", + scan: "扫码关注公众号", wechat: "微信", repassword: "确认密码", repasswordValidate: "请输入确认密码", diff --git a/src/store/index.ts b/src/store/index.ts index 32de4f1..5fff0eb 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,20 +1,10 @@ import {useAuthStore} from '@/store/modules/userStore.ts'; import {useThemeStore} from "@/store/modules/themeStore.ts"; import {langStore} from "@/store/modules/langStore.ts"; -import {useAuthSessionStore} from "@/store/modules/userSessionStore.ts"; export default function useStore() { - // 是否自动登录 默认自动化登录 - function isAutoLogin() { - const result: string | null = localStorage.getItem('auto_login'); - if (result) { - return result === 'true'; - } - return true; - } - return { - user: isAutoLogin() ? useAuthStore() : useAuthSessionStore(), // 自动登录时使用 useAuthStore,否则使用 useAuthSessionStore + user: useAuthStore(), theme: useThemeStore(), lang: langStore(), }; diff --git a/src/store/modules/userSessionStore.ts b/src/store/modules/userSessionStore.ts deleted file mode 100644 index c729581..0000000 --- a/src/store/modules/userSessionStore.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {defineStore} from 'pinia'; -import {reactive} from 'vue'; - - -export const useAuthSessionStore = defineStore( - 'user', - () => { - const user: any = reactive({ - accessToken: '', - uid: '', - refreshToken: '', - expiresAt: 0, - }); - - return { - user, - }; - }, - { - // 开启数据持久化 - persist: { - key: 'user', - storage: sessionStorage, - paths: ['user'], - } - } -); diff --git a/src/types/user.d.ts b/src/types/user.d.ts index 501d1db..406c015 100644 --- a/src/types/user.d.ts +++ b/src/types/user.d.ts @@ -1,11 +1,13 @@ export interface AccountLogin { account?: string password?: string; + auto_login?: boolean; } export interface PhoneLogin { phone?: string captcha?: string; + auto_login?: boolean; } export interface ResetPassword { diff --git a/src/views/Landing/LandingPage.vue b/src/views/Landing/LandingPage.vue index c72c369..1e20832 100644 --- a/src/views/Landing/LandingPage.vue +++ b/src/views/Landing/LandingPage.vue @@ -1,17 +1,11 @@ - - - + diff --git a/src/views/Login/LoginFooter.vue b/src/views/Login/LoginFooter.vue index d87c0fe..301d701 100644 --- a/src/views/Login/LoginFooter.vue +++ b/src/views/Login/LoginFooter.vue @@ -6,7 +6,13 @@ router.push('/qrlogin') }" class="login-form-bottom-button" :icon="h(QrcodeOutlined)">{{ t("login.qrLogin") }} - + + + + @@ -20,17 +26,22 @@ import {getGithubUrl} from "@/api/oauth/github.ts"; import {getGiteeUrl} from "@/api/oauth/gitee.ts"; import useStore from "@/store"; import {message} from "ant-design-vue"; +import gitee from "@/assets/svgs/gitee.svg"; +import {generateClientId} from "@/api/oauth/wechat.ts"; +import {getQQUrl} from "@/api/oauth/qq.ts"; const router = useRouter(); const {t} = useI18n(); const githubRedirectUrl = ref(''); const giteeRedirectUrl = ref(''); +const qqRedirectUrl = ref(''); /** * Get the redirect url of Github OAuth */ async function getGithubRedirectUrl() { - const res: any = await getGithubUrl(); + const clientId: string = getLocalClientId() as string; + const res: any = await getGithubUrl(clientId); if (res.code === 0 && res.data) { githubRedirectUrl.value = res.data; } @@ -46,6 +57,43 @@ async function getGiteeRedirectUrl() { } } +/** + * Get the redirect url of QQ OAuth + */ +async function getQQRedirectUrl() { + const clientId: string = getLocalClientId() as string; + const res: any = await getQQUrl(clientId); + if (res.code === 0 && res.data) { + qqRedirectUrl.value = res.data; + } +} + +/** + * 获取client_id + */ +async function getClientId() { + const id: string | null = localStorage.getItem('client_id'); + if (!id) { + const res: any = await generateClientId(); + if (res.code === 0 && res.data) { + localStorage.setItem('client_id', res.data); + } + } +} + +/** + * 获取本地client_id + */ +function getLocalClientId(): string | null { + const clientID: string | null = localStorage.getItem('client_id'); + if (clientID) { + return clientID; + } else { + getClientId(); + return localStorage.getItem('client_id'); + } +} + /** * Open the Github OAuth page in a new window */ @@ -106,6 +154,7 @@ const openGiteeUrl = () => { onMounted(() => { getGithubRedirectUrl(); getGiteeRedirectUrl(); + getQQRedirectUrl(); });