wujingjing
2025-03-21 b8a912728dc9f46504626d3384b4314b9d75bde3
使用微信扫一扫登陆
已修改4个文件
已添加2个文件
392 ■■■■ 文件已修改
src/api/ai/user.ts 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/hooks/useLogin.ts 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.ts 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/global.ts 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index_yw.vue 183 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/ai/user.ts
@@ -33,3 +33,14 @@
        ...extraData,
    });
};
export const userBindingWechat = async (params, req: any = request) => {
    return req({
        url: '/user/user_bindingWeChat',
        method: 'POST',
        data: params,
    });
};
src/hooks/useLogin.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,95 @@
import { ElMessage } from 'element-plus';
import { storeToRefs } from 'pinia';
import { useRoute } from 'vue-router';
import router from '../router';
import { initBackEndControlRoutes } from '../router/backEnd';
import { initFrontEndControlRoutes } from '../router/frontEnd';
import { useUserInfo } from '../stores/userInfo';
import { NextLoading } from '../utils/loading';
import { accessSessionKey, clearAccessTokens } from '../utils/request';
import { Local } from '../utils/storage';
import profileMan from '/@/assets/profile/man.svg';
import { useThemeConfig } from '../stores/themeConfig';
import { formatAxis } from '/@/utils/formatTime';
import { nextTick } from 'vue';
const getQueryParams = (params: any) => {
    const paramsObj = JSON.parse(params) ?? {};
    const wechatKeys = ['isWxLogin', 'wxcode', 'wxstate'];
    const queryParams = {};
    for (const key in paramsObj) {
        if (Object.prototype.hasOwnProperty.call(paramsObj, key)) {
            const element = paramsObj[key];
            if (!wechatKeys.includes(key)) {
                queryParams[key] = element;
            }
        }
    }
    return queryParams;
};
export const useLogin = () => {
    const storesThemeConfig = useThemeConfig();
    const { themeConfig } = storeToRefs(storesThemeConfig);
    // ç™»å½•成功后的跳转
    const signInSuccess = (isNoPower: boolean | undefined, currentTime) => {
        if (isNoPower) {
            ElMessage.warning('您没有登录权限');
            clearAccessTokens();
        } else {
            // åˆå§‹åŒ–登录成功时间问候语
            const currentTimeInfo = currentTime;
            // ç™»å½•成功,跳到转首页
            // å¦‚果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
            // console.log(route.query, 199);
            const currentRoute = router.currentRoute.value;
            if (currentRoute.query?.redirect) {
                router.push({
                    path: <string>currentRoute.query?.redirect,
                    query: Object.keys(<string>currentRoute.query?.params).length > 0 ? getQueryParams(<string>currentRoute.query?.params) : '',
                });
                setTimeout(() => {
                    nextTick(() => {
                        NextLoading.done();
                    });
                }, 4000);
            } else {
                router.push('/');
            }
            // ç™»å½•成功提示
            const signInText = '欢迎回来!';
            ElMessage.success(`${currentTimeInfo},${signInText}`);
            // æ·»åŠ  loading,防止第一次进入界面时出现短暂空白
            // NextLoading.start();
        }
        // state.loading.signIn = false;
    };
    const handleAfterLogin = async (res) => {
        const currentTime = formatAxis(new Date());
        Local.set(accessSessionKey, res.hswatersession);
        await useUserInfo().setUserInfos({
            userName: res.name,
            phoneNumber: res.phone,
            photo: profileMan,
        }); //缓存用户信息
        // state.loading.signIn = true;
        if (!themeConfig.value.isRequestRoutes) {
            // å‰ç«¯æŽ§åˆ¶è·¯ç”±ï¼Œ2、请注意执行顺序
            const isNoPower = await initFrontEndControlRoutes();
            // console.log(isNoPower,172)
            signInSuccess(isNoPower, currentTime);
        } else {
            // æ¨¡æ‹ŸåŽç«¯æŽ§åˆ¶è·¯ç”±ï¼ŒisRequestRoutes ä¸º true,则开启后端控制路由
            // æ·»åŠ å®ŒåŠ¨æ€è·¯ç”±ï¼Œå†è¿›è¡Œ router è·³è½¬ï¼Œå¦åˆ™å¯èƒ½æŠ¥é”™ No match found for location with path "/"
            const isNoPower = await initBackEndControlRoutes();
            // æ‰§è¡Œå®Œ initBackEndControlRoutes,再执行 signInSuccess
            // console.log(isNoPower,178)
            signInSuccess(isNoPower, currentTime);
        }
    };
    return {
        handleAfterLogin,
    };
};
src/main.ts
@@ -13,6 +13,7 @@
import '/@/theme/index.scss';
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
import { gotoRoute } from '/@/utils/route';
import { checkWxOperate } from './utils/global';
const app = createApp(App);
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
@@ -29,3 +30,6 @@
    }
    gotoRoute({ name });
};
checkWxOperate();
src/utils/global.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,97 @@
import { ElMessage } from 'element-plus';
import { PostLogin, userBindingWechat } from '../api/ai/user';
import { SERVE_URL } from '../constants';
import { useLogin } from '../hooks/useLogin';
import { userInfoKey } from './request';
import { Local } from './storage';
const resolveWechatInfo = () => {
    const url = window.location.href;
    const hashParams = url.split('#')[1];
    if (!hashParams) return;
    const [path, queryString] = hashParams.split('?');
    if (!queryString) return;
    const params = new URLSearchParams(queryString);
    const wxcode = params.get('wxcode');
    const isLogin = params.get('isWxLogin');
    if (!wxcode) return;
    return { wxcode, isLogin };
};
export const checkWechatLogin = async (wxcode: string) => {
    const { handleAfterLogin } = useLogin();
    // const loadingInstance = ElLoadingService({
    //     // text: '加载中...',
    //     target: '.layout-parent',
    // });
    const res = await PostLogin(
        {
            weixin_code: wxcode,
        },
        {
            noAuth: true,
            handleFail: false,
        }
    );
    if (res?.json_ok) {
        handleAfterLogin(res);
        Local.remove('isWechatLogin');
        // ä½¿ç”¨æ–°åœ°å€æ›¿æ¢å½“前页面,移除微信登录参数
        // const newUrl = window.location.href.split('?')[0];
        // window.history.replaceState({}, '', SERVE_URL);
        // window.location.href = SERVE_URL;
        // window.location.reload();
    } else {
        // isShowLogin.value = true;
        Local.set('isWechatLogin', true);
        Local.set('wechatLoginMsgInfo', {
            type: 'error',
            value: res?.json_msg ?? '登录失败,请检查是否已绑定微信',
        });
        window.location.href = SERVE_URL;
    }
};
export const handleBindWechat = async (wxcode: string) => {
    const userInfo = Local.get(userInfoKey);
    const res = await userBindingWechat({
        weixin_code: wxcode,
        user_name: userInfo.userName,
    });
    if (res?.json_ok) {
        ElMessage.success('绑定成功');
        const userInfo = Local.get(userInfoKey);
        Local.set(userInfoKey, {
            ...userInfo,
            isBindWechat: true,
            wechatNickname: res.json_url,
        });
        setTimeout(() => {
            window.location.href = SERVE_URL;
        }, 700);
    } else {
        ElMessage.error(res?.json_msg ?? '绑定失败');
        setTimeout(() => {
            window.location.href = SERVE_URL;
        }, 2000);
    }
};
export const checkWxOperate = () => {
    const result = resolveWechatInfo();
    if (!result) return;
    if (result.isLogin === 'Y') {
        checkWechatLogin(result.wxcode);
    } else {
        handleBindWechat(result.wxcode);
    }
};
src/views/login/index_yw.vue
@@ -22,12 +22,27 @@
                        <div class="login-right-warp-main-title">{{ getThemeConfig.globalTitle }} æ¬¢è¿Žæ‚¨ï¼</div>
                        <div class="login-right-warp-main-form">
                            <div v-if="!state.isScan">
                                <el-tabs v-model="state.tabsActiveName">
                                <el-tabs v-model="state.tabsActiveName" @tab-change="handleTabChange">
                                    <el-tab-pane :label="$t('message.label.one1')" name="account">
                                        <Account  @login="handleAfterLogin"/>
                                        <Account @login="handleAfterLogin" />
                                    </el-tab-pane>
                                    <el-tab-pane :label="$t('message.label.two2')" name="mobile">
                                        <Mobile  @login="handleAfterLogin"/>
                                        <Mobile @login="handleAfterLogin" />
                                    </el-tab-pane>
                                    <el-tab-pane label="微信" name="wechat">
                                        <div id="wechat-login" class="flex justify-center items-center">
                                            <div class="flex flex-col items-center justify-center">
                                                <iframe
                                                    ref="wechatQrRef"
                                                    sandbox="allow-top-navigation allow-scripts"
                                                    style="width: 300px; height: 213px; overflow: hidden"
                                                    frameborder="0"
                                                ></iframe>
                                                <span class="relative top-[-10px]" :class="{ 'text-red-400': wechatTip.type === 'error' }">{{
                                                    wechatTip.value
                                                }}</span>
                                            </div>
                                        </div>
                                    </el-tab-pane>
                                </el-tabs>
                            </div>
@@ -46,20 +61,22 @@
</template>
<script setup lang="ts" name="loginIndex">
import { storeToRefs } from 'pinia';
import { computed, defineAsyncComponent, onMounted, reactive } from 'vue';
import { useRoute } from 'vue-router';
import { useThemeConfig } from '/@/stores/themeConfig';
import { NextLoading } from '/@/utils/loading';
import { ElMessage } from 'element-plus';
import { storeToRefs } from 'pinia';
import { computed, defineAsyncComponent, nextTick, onMounted, reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import profileMan from '/@/assets/profile/man.svg';
import router from '/@/router';
import { initBackEndControlRoutes } from '/@/router/backEnd';
import { initFrontEndControlRoutes } from '/@/router/frontEnd';
import { useThemeConfig } from '/@/stores/themeConfig';
import { useUserInfo } from '/@/stores/userInfo';
import { clearAccessTokens, accessSessionKey } from '/@/utils/request';
import { NextLoading } from '/@/utils/loading';
import { accessSessionKey, clearAccessTokens } from '/@/utils/request';
import { Local } from '/@/utils/storage';
import profileMan from '/@/assets/profile/man.svg';
import { SERVE_URL } from '/@/constants';
import { useLogin } from '/@/hooks/useLogin';
const storesThemeConfig = useThemeConfig();
const { themeConfig } = storeToRefs(storesThemeConfig);
@@ -71,12 +88,23 @@
const LayoutFooter = defineAsyncComponent(() => import('/@/layout/footer/index.vue'));
const route = useRoute();
// è®¾ç½® footer æ˜¾ç¤º/隐藏
const isFooter = computed(() => {
    return themeConfig.value.isFooter && !route.meta.isIframe;
});
const getActiveLoginName = () => {
    const isWechatLogin = Local.get('isWechatLogin');
    if (isWechatLogin) {
        Local.remove('isWechatLogin');
        return 'wechat';
    }
    return 'account';
};
const state = reactive({
    tabsActiveName: 'account',
    tabsActiveName: getActiveLoginName(),
    isScan: false,
});
@@ -87,66 +115,97 @@
const loginMain = window.globalConfig.SoftWareInfo.loginMain;
const logoMini = window.globalConfig.SoftWareInfo.logoMini;
const loginBg = window.globalConfig.SoftWareInfo.loginBg;
const { t } = useI18n();
// ç™»å½•成功后的跳转
const signInSuccess = (isNoPower: boolean | undefined, currentTime) => {
    if (isNoPower) {
        ElMessage.warning('您没有登录权限');
        clearAccessTokens();
    } else {
        // åˆå§‹åŒ–登录成功时间问候语
        let currentTimeInfo = currentTime;
        // ç™»å½•成功,跳到转首页
        // å¦‚果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
        // console.log(route.query, 199);
        if (route.query?.redirect) {
            router.push({
                path: <string>route.query?.redirect,
                query: Object.keys(<string>route.query?.params).length > 0 ? JSON.parse(<string>route.query?.params) : '',
            });
        } else {
            router.push('/');
        }
        // ç™»å½•成功提示
        const signInText = t('message.signInText');
        ElMessage.success(`${currentTimeInfo},${signInText}`);
        // æ·»åŠ  loading,防止第一次进入界面时出现短暂空白
        NextLoading.start();
    }
    // state.loading.signIn = false;
};
const handleAfterLogin = async (res, currentTime) => {
    Local.set(accessSessionKey, res.hswatersession);
    await useUserInfo().setUserInfos({
        userName: res.name,
        phoneNumber: res.phone,
        photo: profileMan,
    }); //缓存用户信息
    // state.loading.signIn = true;
    if (!themeConfig.value.isRequestRoutes) {
        // å‰ç«¯æŽ§åˆ¶è·¯ç”±ï¼Œ2、请注意执行顺序
        const isNoPower = await initFrontEndControlRoutes();
        // console.log(isNoPower,172)
        signInSuccess(isNoPower, currentTime);
    } else {
        // æ¨¡æ‹ŸåŽç«¯æŽ§åˆ¶è·¯ç”±ï¼ŒisRequestRoutes ä¸º true,则开启后端控制路由
        // æ·»åŠ å®ŒåŠ¨æ€è·¯ç”±ï¼Œå†è¿›è¡Œ router è·³è½¬ï¼Œå¦åˆ™å¯èƒ½æŠ¥é”™ No match found for location with path "/"
        const isNoPower = await initBackEndControlRoutes();
        // æ‰§è¡Œå®Œ initBackEndControlRoutes,再执行 signInSuccess
        // console.log(isNoPower,178)
        signInSuccess(isNoPower, currentTime);
    }
};
const { handleAfterLogin } = useLogin();
// é¡µé¢åŠ è½½æ—¶
onMounted(() => {
    NextLoading.done();
    if (state.tabsActiveName === 'wechat') {
        nextTick(() => {
            openWechatLogin();
        });
    }
});
const scanClick = () => {
    // state.isScan = !state.isScan;
    return;
};
//#region ====================== å¾®ä¿¡ç™»é™† ======================
//切换用户登录页面
const handleTabChange = (item) => {
    resetWechatTip();
    switch (item) {
        case 'wechat':
            // getWechartQrCode();
            openWechatLogin();
            break;
        case 'accountUser':
            break;
        case 'phoneUser':
            break;
    }
};
const getWechatTipInfo = () => {
    const wechatLoginMsgInfo = Local.get('wechatLoginMsgInfo');
    if (wechatLoginMsgInfo) {
        Local.remove('wechatLoginMsgInfo');
        return wechatLoginMsgInfo;
    }
    return { type: 'info', value: '使用微信扫一扫登陆' };
};
const wechatTip = ref(getWechatTipInfo());
const resetWechatTip = () => {
    wechatTip.value = {
        type: 'info',
        value: '使用微信扫一扫登陆',
    };
};
const wechatQrRef = ref<HTMLIFrameElement>();
const openWechatLogin = () => {
    if (!wechatQrRef.value) return;
    const url = `${SERVE_URL}JJJHHH/home?isWxLogin=Y`;
    const appid = 'wx4ea2dca37170074c';
    const state = (new Date().getTime() / 1000).toString();
    const base64 = btoa(`
    .impowerBox .title {display:none;}
    .impowerBox .status.status_browser  p:nth-of-type(2){
        display: none;
    }
    .impowerBox .qrcode {
    width: 170px;
    margin-top:0;
    }
    .impowerBox .status{
    }
        .info{
        display: none;
    }
    #tpl_for_iframe{
        height:100%;
        overflow: hidden;
            display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
    }
    `);
    const wechatAuthUrl = `https://open.weixin.qq.com/connect/qrconnect?appid=${appid}&redirect_uri=${encodeURIComponent(
        `http://apiv3.xpump.net/User/wxUserLoginCB.html?from=wi&url=${url}`
    )}&response_type=code&scope=snsapi_login&state=${state}&href=data:text/css;base64,${base64}#wechat_redirect`;
    wechatQrRef.value.src = wechatAuthUrl;
};
//#endregion
</script>
<style scoped lang="scss">
vite.config.ts
@@ -45,7 +45,7 @@
            host: '0.0.0.0',
            port: env.VITE_PORT as unknown as number,
            open: JSON.parse(env.VITE_OPEN),
            hmr: true,
            hmr: false,
            proxy: {
                '/gitee': {
                    target: 'https://gitee.com',