feat: 登录
This commit is contained in:
@@ -52,13 +52,18 @@ const toggleDropDown = (isShow) => {
|
||||
}
|
||||
};
|
||||
|
||||
const logout = async() => {
|
||||
const logout = async () => {
|
||||
RemoveInfo(); // 目前先强制清除用户信息,后面接口通了再调
|
||||
const res = await toLogout();
|
||||
await reqCatch(devLogout, {}); // 清除社区登录
|
||||
if (!res.error) {
|
||||
RemoveInfo();
|
||||
// 有权限刷新当前页,无权限需要登录返回首页
|
||||
if (route.meta?.needLogin || (route.meta?.type === 'repo' && repoInfo.value?.visibility === 'private') || orgInfo.value?.visibility === 'private') {
|
||||
if (
|
||||
route.meta?.needLogin ||
|
||||
(route.meta?.type === 'repo' && repoInfo.value?.visibility === 'private') ||
|
||||
orgInfo.value?.visibility === 'private'
|
||||
) {
|
||||
router.push('/');
|
||||
} else {
|
||||
router.go(0);
|
||||
@@ -84,11 +89,10 @@ const DEFAULT_ROUTER_PARAMS = Object.freeze({
|
||||
params: {
|
||||
namespace: accountInfo.value.username
|
||||
},
|
||||
query: {
|
||||
}
|
||||
query: {}
|
||||
});
|
||||
// 获取router跳转参数
|
||||
const getRouterLink = params => {
|
||||
const getRouterLink = (params) => {
|
||||
if (typeof params === 'string') {
|
||||
return {
|
||||
...DEFAULT_ROUTER_PARAMS,
|
||||
@@ -103,15 +107,18 @@ const getRouterLink = params => {
|
||||
};
|
||||
|
||||
const blockList = ref([
|
||||
[
|
||||
{ id: 'myPage', label: '我的主页', to: getRouterLink('homepage') }
|
||||
],
|
||||
[{ id: 'myPage', label: '我的主页', to: getRouterLink('homepage') }],
|
||||
[
|
||||
{ id: 'dashboard', label: '工作台', icon: 'gt-member-c', to: getRouterLink('dashboard') },
|
||||
{ id: 'myIssues', label: '我的 Issue', icon: 'gt-issue-c', to: getRouterLink('issues') },
|
||||
{ id: 'myDiscuss', label: '我的讨论', icon: 'gt-comment-c', to: getRouterLink('discussionCreated') },
|
||||
{ id: 'myMR', label: '我的合并请求', icon: 'gt-me-merge-c', to: getRouterLink('merge') },
|
||||
{ id: 'notice', label: '消息通知', icon: 'gt-remind-c', to: getRouterLink({ name: 'notice', query: { status: 'all' }}) }
|
||||
{
|
||||
id: 'notice',
|
||||
label: '消息通知',
|
||||
icon: 'gt-remind-c',
|
||||
to: getRouterLink({ name: 'notice', query: { status: 'all' } })
|
||||
}
|
||||
],
|
||||
[
|
||||
{ id: 'myOrg', label: '我的组织', icon: 'gt-organizations-c', to: getRouterLink({ name: 'settingOrganization' }) },
|
||||
@@ -120,11 +127,14 @@ const blockList = ref([
|
||||
],
|
||||
[
|
||||
{ id: 'personalSetting', label: '个人设置', icon: 'gt-setting-c', to: getRouterLink('setting') },
|
||||
{ id: 'help', label: '帮助文档', icon: 'gt-file-c', href: 'https://gitcode.com/Gitcode-offical-team/GitCode-Docs/wiki' }
|
||||
{
|
||||
id: 'help',
|
||||
label: '帮助文档',
|
||||
icon: 'gt-file-c',
|
||||
href: 'https://gitcode.com/Gitcode-offical-team/GitCode-Docs/wiki'
|
||||
}
|
||||
],
|
||||
[
|
||||
{ id: 'logout', label: '退出登录', icon: 'gt-exit', action: logout }
|
||||
]
|
||||
[{ id: 'logout', label: '退出登录', icon: 'gt-exit', action: logout }]
|
||||
]);
|
||||
</script>
|
||||
|
||||
@@ -156,7 +166,7 @@ const blockList = ref([
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #2D2D2E;
|
||||
color: #2d2d2e;
|
||||
line-height: 20px;
|
||||
.close-icon {
|
||||
cursor: pointer;
|
||||
@@ -164,7 +174,7 @@ const blockList = ref([
|
||||
}
|
||||
&-id {
|
||||
font-size: 12px;
|
||||
color: #707A87;
|
||||
color: #707a87;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
@@ -183,7 +193,6 @@ const blockList = ref([
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -7,14 +7,37 @@ import GTitle from './widget/title.vue';
|
||||
import { useModel } from '@/utils/hooks/useModel';
|
||||
import type { GLoginModalProps, GLogoProps } from './types';
|
||||
import { TransAssetsUrl } from '@/utils/asset';
|
||||
import { computed, ref, watch, reactive, onBeforeUnmount, nextTick, watchEffect, shallowRef, getCurrentInstance, type ComponentInternalInstance } from 'vue';
|
||||
import {
|
||||
computed,
|
||||
ref,
|
||||
watch,
|
||||
reactive,
|
||||
onBeforeUnmount,
|
||||
nextTick,
|
||||
watchEffect,
|
||||
shallowRef,
|
||||
getCurrentInstance,
|
||||
type ComponentInternalInstance,
|
||||
onMounted,
|
||||
onUnmounted
|
||||
} from 'vue';
|
||||
import { Modal } from 'vue-devui/modal';
|
||||
import { Button } from 'vue-devui/button';
|
||||
import { Icon } from 'vue-devui/icon';
|
||||
import { Tooltip } from 'vue-devui/tooltip';
|
||||
import { Message } from 'vue-devui/message';
|
||||
import { verifyRegisterCode, getQuickLoginMsg, getMobileEmailCode, resetUserPassword, checkUsername, registerByMobile, loginByMobile, toLogin } from '@/api/user';
|
||||
import {
|
||||
verifyRegisterCode,
|
||||
getQuickLoginMsg,
|
||||
getMobileEmailCode,
|
||||
resetUserPassword,
|
||||
checkUsername,
|
||||
registerByMobile,
|
||||
loginByMobile,
|
||||
toLogin
|
||||
} from '@/api/user';
|
||||
import { FormRules, isMobileEmail } from './form';
|
||||
import { useAccountStore } from '@/stores/user';
|
||||
|
||||
/**
|
||||
* TODO: 待集成入该hook
|
||||
@@ -34,7 +57,7 @@ const IconB = TransAssetsUrl(IconSource, 'logo-back');
|
||||
// 表单验证结果
|
||||
const formErrors = reactive<Record<string, string>>({});
|
||||
// 额外验证参数
|
||||
const extraErrors = reactive<{ agreement: string, requestInfo: string }>({
|
||||
const extraErrors = reactive<{ agreement: string; requestInfo: string }>({
|
||||
agreement: '',
|
||||
requestInfo: ''
|
||||
});
|
||||
@@ -45,7 +68,13 @@ const disabled = ref(true);
|
||||
const loading = ref(false);
|
||||
|
||||
const isRegister = ref(false);
|
||||
const cacheForm = reactive<{ mobile: string, verificationcode: string, countdownSecond: number, user_id: string, mask: string }>({
|
||||
const cacheForm = reactive<{
|
||||
mobile: string;
|
||||
verificationcode: string;
|
||||
countdownSecond: number;
|
||||
user_id: string;
|
||||
mask: string;
|
||||
}>({
|
||||
mobile: '',
|
||||
verificationcode: '',
|
||||
countdownSecond: 59,
|
||||
@@ -53,7 +82,7 @@ const cacheForm = reactive<{ mobile: string, verificationcode: string, countdown
|
||||
mask: ''
|
||||
});
|
||||
let timer: any = null;
|
||||
let interval:any = null;
|
||||
let interval: any = null;
|
||||
|
||||
const logos = reactive<GLogoProps[]>([
|
||||
{
|
||||
@@ -99,7 +128,7 @@ const VerifyForm = reactive<FormListProps[]>([
|
||||
required: true,
|
||||
rules: FormRules.codes,
|
||||
props: {
|
||||
'autocomplete': true,
|
||||
autocomplete: true,
|
||||
countdown: false,
|
||||
second: 59,
|
||||
aliasKey: 'mobile'
|
||||
@@ -121,13 +150,13 @@ const PasswordForm = reactive<FormListProps[]>([
|
||||
required: true,
|
||||
props: {
|
||||
'show-password': true,
|
||||
'autocomplete': true,
|
||||
'maxlength': 30
|
||||
autocomplete: true,
|
||||
maxlength: 30
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
const VerifyPassword:FormListProps[] = [
|
||||
const VerifyPassword: FormListProps[] = [
|
||||
{
|
||||
type: 'input',
|
||||
key: 'password',
|
||||
@@ -137,8 +166,8 @@ const VerifyPassword:FormListProps[] = [
|
||||
help: '密码最少包含一个大写字母、一个小写字母、一个数字, 长度为8~30之间',
|
||||
props: {
|
||||
'show-password': true,
|
||||
'autocomplete': true,
|
||||
'maxlength': 30
|
||||
autocomplete: true,
|
||||
maxlength: 30
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -175,15 +204,15 @@ const VerifyPassword:FormListProps[] = [
|
||||
],
|
||||
props: {
|
||||
'show-password': true,
|
||||
'autocomplete': true,
|
||||
'maxlength': 30
|
||||
autocomplete: true,
|
||||
maxlength: 30
|
||||
}
|
||||
}
|
||||
];
|
||||
/** 检测用户是否存在 */
|
||||
const requestCheck = {
|
||||
trigger: 'change',
|
||||
validator: async(_: any, val: string, cb: Function) => {
|
||||
validator: async (_: any, val: string, cb: Function) => {
|
||||
const res = await checkUsername(val);
|
||||
if (!res.error) {
|
||||
if (res.data.data.result) {
|
||||
@@ -223,7 +252,7 @@ const RegisterForm = reactive<FormListProps[]>([
|
||||
required: true,
|
||||
rules: FormRules.codes,
|
||||
props: {
|
||||
'autocomplete': true,
|
||||
autocomplete: true,
|
||||
countdown: false,
|
||||
second: 59,
|
||||
aliasKey: 'mobile'
|
||||
@@ -261,17 +290,21 @@ const FormRef = shallowRef<any>(null);
|
||||
const tabPanel = ref<'verifyCode' | 'password'>('password');
|
||||
const formType = ref<'login' | 'register' | 'forget'>(props.defaultType);
|
||||
|
||||
const FormConfig = computed<{ dict: FormListProps[], showLabel: boolean, layout: 'horizontal' | 'vertical', title: string, showBack: boolean, button?: string }>(() => {
|
||||
const FormConfig = computed<{
|
||||
dict: FormListProps[];
|
||||
showLabel: boolean;
|
||||
layout: 'horizontal' | 'vertical';
|
||||
title: string;
|
||||
showBack: boolean;
|
||||
button?: string;
|
||||
}>(() => {
|
||||
if (formType.value === 'register') {
|
||||
return {
|
||||
dict: RegisterForm.map(item => {
|
||||
dict: RegisterForm.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
defaultValue: item.key === 'mobile'
|
||||
? cacheForm.mobile
|
||||
: item.key === 'verificationcode'
|
||||
? cacheForm.verificationcode
|
||||
: ''
|
||||
defaultValue:
|
||||
item.key === 'mobile' ? cacheForm.mobile : item.key === 'verificationcode' ? cacheForm.verificationcode : ''
|
||||
};
|
||||
}),
|
||||
showLabel: true,
|
||||
@@ -291,7 +324,7 @@ const FormConfig = computed<{ dict: FormListProps[], showLabel: boolean, layout:
|
||||
}
|
||||
if (tabPanel.value === 'verifyCode') {
|
||||
return {
|
||||
dict: VerifyForm.map(item => {
|
||||
dict: VerifyForm.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
defaultValue: item.key === 'mobile' ? cacheForm.mobile : ''
|
||||
@@ -299,7 +332,7 @@ const FormConfig = computed<{ dict: FormListProps[], showLabel: boolean, layout:
|
||||
}),
|
||||
showLabel: false,
|
||||
layout: 'vertical',
|
||||
title: '欢迎登录你的GitCode账号',
|
||||
title: '欢迎登录你的GitCode账号1',
|
||||
showBack: false
|
||||
};
|
||||
} else {
|
||||
@@ -322,7 +355,7 @@ const catchFormErrors = (conf: { errors: Record<string, any[]> }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleResetPassword = async() => {
|
||||
const handleResetPassword = async () => {
|
||||
if (FormRef.value) {
|
||||
const formData = await FormRef.value.ValidateForm();
|
||||
if (formData.type === 'success') {
|
||||
@@ -347,7 +380,7 @@ const handleResetPassword = async() => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirm = async() => {
|
||||
const handleConfirm = async () => {
|
||||
let agreementFlag = false;
|
||||
if (formType.value === 'forget') {
|
||||
handleResetPassword();
|
||||
@@ -397,10 +430,13 @@ const handleConfirm = async() => {
|
||||
extraErrors.requestInfo = result.error.error_message;
|
||||
}
|
||||
} else {
|
||||
const data = tabPanel.value === 'password' ? res : {
|
||||
mobile: res.mobile,
|
||||
code: res.code
|
||||
};
|
||||
const data =
|
||||
tabPanel.value === 'password'
|
||||
? res
|
||||
: {
|
||||
mobile: res.mobile,
|
||||
code: res.code
|
||||
};
|
||||
const result = tabPanel.value === 'password' ? await toLogin(res) : await loginByMobile(data);
|
||||
if (!result.error) {
|
||||
const { user_id, mask, mobile } = result.data.data;
|
||||
@@ -425,7 +461,7 @@ const handleConfirm = async() => {
|
||||
/**
|
||||
* 绑定华为云
|
||||
* @deprecated at 精简单注册登录
|
||||
*/
|
||||
*/
|
||||
// const handleBind = (res: any) => {
|
||||
// if (!res.error) {
|
||||
// emits('login', res.data.data);
|
||||
@@ -440,8 +476,10 @@ const handleClose = (close: Function) => {
|
||||
};
|
||||
/** 外链url */
|
||||
const links = {
|
||||
'agreement': 'https://gitcode.com/Gitcode-offical-team/GitCode-Docs/blob/main/%E7%94%A8%E6%88%B7%E5%8D%8F%E8%AE%AE%2F%E6%9C%8D%E5%8A%A1%E6%9D%A1%E6%AC%BE.md',
|
||||
'privacy': 'https://gitcode.com/Gitcode-offical-team/GitCode-Docs/blob/main/%E7%94%A8%E6%88%B7%E5%8D%8F%E8%AE%AE%2F%E9%9A%90%E7%A7%81%E6%94%BF%E7%AD%96.md'
|
||||
agreement:
|
||||
'https://gitcode.com/Gitcode-offical-team/GitCode-Docs/blob/main/%E7%94%A8%E6%88%B7%E5%8D%8F%E8%AE%AE%2F%E6%9C%8D%E5%8A%A1%E6%9D%A1%E6%AC%BE.md',
|
||||
privacy:
|
||||
'https://gitcode.com/Gitcode-offical-team/GitCode-Docs/blob/main/%E7%94%A8%E6%88%B7%E5%8D%8F%E8%AE%AE%2F%E9%9A%90%E7%A7%81%E6%94%BF%E7%AD%96.md'
|
||||
};
|
||||
|
||||
const links_hw = {
|
||||
@@ -485,22 +523,20 @@ const clearFormError = (key?: string) => {
|
||||
}
|
||||
};
|
||||
/** 发送短信相关 */
|
||||
const handleCountDown = async(conf: { key: string, value: any, sourceKey: string }) => {
|
||||
const handleCountDown = async (conf: { key: string; value: any; sourceKey: string }) => {
|
||||
const formData = await FormRef.value.ValidateFormKeys([conf.key]);
|
||||
if (formData.type === 'success') {
|
||||
clearFormError(conf.key);
|
||||
if (tabPanel.value === 'verifyCode' || formType.value === 'register' || formType.value === 'forget') {
|
||||
const res = formType.value === 'login'
|
||||
? await getQuickLoginMsg({ mobile: conf.value })
|
||||
: formType.value === 'forget'
|
||||
const res =
|
||||
formType.value === 'login'
|
||||
? await getQuickLoginMsg({ mobile: conf.value })
|
||||
: formType.value === 'forget'
|
||||
? await getMobileEmailCode(conf.value)
|
||||
: await verifyRegisterCode({ mobile: conf.value, type: 'REGISTER' });
|
||||
if (!res.error) {
|
||||
const source = formType.value === 'register'
|
||||
? RegisterForm
|
||||
: formType.value === 'forget'
|
||||
? ForgetPasswordForm
|
||||
: VerifyForm;
|
||||
const source =
|
||||
formType.value === 'register' ? RegisterForm : formType.value === 'forget' ? ForgetPasswordForm : VerifyForm;
|
||||
cacheForm.mobile = conf.value;
|
||||
if (Number(res?.data.data.type === 1)) {
|
||||
isRegister.value = true;
|
||||
@@ -510,7 +546,7 @@ const handleCountDown = async(conf: { key: string, value: any, sourceKey: string
|
||||
const message = isMobileEmail(conf.value);
|
||||
dealLog(`验证码已发送到你的${message}, 请注意查收`, 'success');
|
||||
}
|
||||
source.forEach(item => {
|
||||
source.forEach((item) => {
|
||||
if (item.key === conf.sourceKey) {
|
||||
if (item.props) {
|
||||
item.props.countdown = true;
|
||||
@@ -564,15 +600,16 @@ const toCountDown = () => {
|
||||
};
|
||||
/** 刷新倒计时的状态 */
|
||||
const refreshCountDown = (tab: string, menu: string) => {
|
||||
const source = menu === 'register'
|
||||
? RegisterForm
|
||||
: formType.value === 'forget'
|
||||
const source =
|
||||
menu === 'register'
|
||||
? RegisterForm
|
||||
: formType.value === 'forget'
|
||||
? ForgetPasswordForm
|
||||
: tab === 'verifyCode'
|
||||
? VerifyForm
|
||||
: null;
|
||||
? VerifyForm
|
||||
: null;
|
||||
if (source) {
|
||||
const countdown = source.find(item => item.props);
|
||||
const countdown = source.find((item) => item.props);
|
||||
if (countdown?.props && Object.prototype.hasOwnProperty.call(countdown.props, 'countdown')) {
|
||||
if (cacheForm.countdownSecond !== 59 && menu === 'register' && isRegister.value) {
|
||||
countdown.props.second = cacheForm.countdownSecond;
|
||||
@@ -584,7 +621,7 @@ const refreshCountDown = (tab: string, menu: string) => {
|
||||
}
|
||||
};
|
||||
/** 表单字段change事件 */
|
||||
const handleFormChange = (conf: { key: string, errors: Record<string, any> | null, source: Record<string, any> }) => {
|
||||
const handleFormChange = (conf: { key: string; errors: Record<string, any> | null; source: Record<string, any> }) => {
|
||||
const { key, errors } = conf;
|
||||
if (errors) {
|
||||
setFormErrorKey({ errors });
|
||||
@@ -595,9 +632,9 @@ const handleFormChange = (conf: { key: string, errors: Record<string, any> | nul
|
||||
const keys = Object.keys(formErrors);
|
||||
const currentForm = FormConfig.value.dict;
|
||||
if (currentForm?.length) {
|
||||
const obj = currentForm.find(item => keys.includes(item.key) && formErrors[item.key]);
|
||||
const obj = currentForm.find((item) => keys.includes(item.key) && formErrors[item.key]);
|
||||
if (FormRef.value) {
|
||||
const filterKeys = keys.filter(k => k !== obj?.key && formErrors[k]);
|
||||
const filterKeys = keys.filter((k) => k !== obj?.key && formErrors[k]);
|
||||
if (filterKeys.length) {
|
||||
FormRef.value?.ClearFormFields(filterKeys);
|
||||
} else {
|
||||
@@ -617,9 +654,9 @@ const errorMsg = computed(() => {
|
||||
const keys = Object.keys(formErrors);
|
||||
const currentForm = FormConfig.value.dict;
|
||||
if (currentForm?.length) {
|
||||
const obj = currentForm.find(item => keys.includes(item.key) && formErrors[item.key]);
|
||||
const obj = currentForm.find((item) => keys.includes(item.key) && formErrors[item.key]);
|
||||
if (FormRef.value) {
|
||||
const filterKeys = keys.filter(key => key !== obj?.key && formErrors[key]);
|
||||
const filterKeys = keys.filter((key) => key !== obj?.key && formErrors[key]);
|
||||
filterKeys.length && FormRef.value?.ClearFormFields(filterKeys);
|
||||
hackMsgError(obj?.key === 'verificationcode' || obj?.key === 'code');
|
||||
}
|
||||
@@ -644,25 +681,28 @@ const hackMsgError = (show_error: boolean) => {
|
||||
}
|
||||
};
|
||||
|
||||
watch(() => [tabPanel.value, formType.value], (newVal, oldVal) => {
|
||||
if (FormRef.value) {
|
||||
FormRef.value.ClearForm();
|
||||
clearFormError();
|
||||
disabled.value = true;
|
||||
}
|
||||
const [tab, menu] = newVal;
|
||||
const [_, prev_menu] = oldVal;
|
||||
if (menu !== 'register') {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
interval = null;
|
||||
watch(
|
||||
() => [tabPanel.value, formType.value],
|
||||
(newVal, oldVal) => {
|
||||
if (FormRef.value) {
|
||||
FormRef.value.ClearForm();
|
||||
clearFormError();
|
||||
disabled.value = true;
|
||||
}
|
||||
const [tab, menu] = newVal;
|
||||
const [_, prev_menu] = oldVal;
|
||||
if (menu !== 'register') {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
interval = null;
|
||||
}
|
||||
}
|
||||
if (prev_menu === 'register') {
|
||||
isRegister.value = false;
|
||||
}
|
||||
refreshCountDown(tab, menu);
|
||||
}
|
||||
if (prev_menu === 'register') {
|
||||
isRegister.value = false;
|
||||
}
|
||||
refreshCountDown(tab, menu);
|
||||
});
|
||||
);
|
||||
|
||||
// 移除参数
|
||||
localStorage.removeItem('loginReturnUrl');
|
||||
@@ -684,7 +724,9 @@ const handleAuthLogin = (type: 'csdn' | 'gitee' | 'github') => {
|
||||
// 保存注册上报类型和ref
|
||||
sessionStorage.setItem('loginType', props.triggerType || '');
|
||||
// window.open('http://localhost:5173/oauth/callback', '_blank', 'width=800, height=800, left=200, top=200');
|
||||
const url = `${(import.meta as any).env.VITE_API_HOST}${(import.meta as any).env.VITE_PASSPORT_PREFIX || ''}/api/v1/oauth/login/${type}`;
|
||||
const url = `${(import.meta as any).env.VITE_API_HOST}${
|
||||
(import.meta as any).env.VITE_PASSPORT_PREFIX || ''
|
||||
}/api/v1/oauth/login/${type}`;
|
||||
window.open(url, '_blank', 'width=800, height=800, left=400, top=200');
|
||||
}
|
||||
};
|
||||
@@ -707,6 +749,27 @@ onBeforeUnmount(() => {
|
||||
clearInterval(interval);
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
const orgin = 'https://test.gitcode.net';
|
||||
window.addEventListener('message', async (event) => {
|
||||
if (event.origin !== orgin) {
|
||||
return; // 安全起见,检查消息来源
|
||||
}
|
||||
if (!event?.data?.access_token) return;
|
||||
const { access_token, refresh_token } = event.data;
|
||||
if (access_token && refresh_token) {
|
||||
const account = useAccountStore();
|
||||
await account.checkIsLogin(access_token, refresh_token);
|
||||
Message.success('登录成功');
|
||||
emits('close', true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('message', () => {});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -720,95 +783,8 @@ onBeforeUnmount(() => {
|
||||
:append-to-body="appendToBody"
|
||||
:class="['login-modal', formType === 'login' ? 'login-modal-l' : 'login-modal-r']"
|
||||
>
|
||||
<template #header>
|
||||
<GTitle :icon="IconB" :title="FormConfig.title" @back="formType = 'login'" :show-back="FormConfig.showBack" class="login-modal-title" />
|
||||
<div v-if="formType === 'register'" class="text-[14px] leading-[20px] text-G900 font-normal">
|
||||
GitCode 与华为云共同为用户提供代码托管服务,在使用代码托管相关服务时,将同步授权并开通华为云服务,并与重庆开源共创科技有限公司(GitCode的运营主体)关联及共享。
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<div class="flex items-center justify-center mb-[24px] mt-[-2px]" v-if="formType === 'login'">
|
||||
<div :class="['login-modal-tab mr-[18px]', tabPanel === 'password' ? 'login-modal-tab-active' : 'login-modal-tab-inactive' ]" @click.stop="tabPanel = 'password'">密码登录</div>
|
||||
<div :class="['login-modal-tab ml-[18px]', tabPanel === 'verifyCode' ? 'login-modal-tab-active' : 'login-modal-tab-inactive' ]" @click.stop="tabPanel = 'verifyCode'">短信登录</div>
|
||||
</div>
|
||||
<div class="text-G900 my-[24px] text-[13px] leading-[18px] px-[8px] tracking-[.5px]" v-if="formType === 'forget'">请通过账号绑定手机号/邮箱重置你的账号密码</div>
|
||||
<GForm
|
||||
:DataList="FormConfig.dict"
|
||||
:show-label="FormConfig.showLabel"
|
||||
ref="FormRef"
|
||||
@count-down="handleCountDown"
|
||||
@change="handleFormChange"
|
||||
@complete="handleFormInput"
|
||||
:layout="FormConfig.layout"
|
||||
size="lg"
|
||||
message-type="none"
|
||||
:class="formType === 'register' ? 'mt-[20px] login-form-register-cell' : 'login-form-common-cell'"
|
||||
>
|
||||
<template #submit>
|
||||
<div class="login-modal-info h-[20px]" v-if="formType === 'login'">
|
||||
<div class="login-modal-info-left">
|
||||
{{ errorMsg }}
|
||||
</div>
|
||||
<div
|
||||
class="login-modal-info-right"
|
||||
@click.stop="formType = 'forget'"
|
||||
v-show="tabPanel === 'password' && formType === 'login'"
|
||||
>
|
||||
忘记密码?
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="formType === 'login'">
|
||||
<div class="mt-[24px]">
|
||||
<Button
|
||||
color="primary"
|
||||
variant="solid"
|
||||
size="lg"
|
||||
@click="handleConfirm"
|
||||
:loading="loading"
|
||||
:disabled="disabled"
|
||||
class="login-modal-button"
|
||||
>
|
||||
登 录
|
||||
</Button>
|
||||
<div class="text-[13px] text-[#2562C4] text-center mt-[12px] cursor-pointer leading-[32px]" @click.stop="formType = 'register'">
|
||||
注册新账号
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</GForm>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="login-modal-footer" v-if="formType === 'login'">
|
||||
<GAuth :logos="logos" @auth="handleAuthLogin" />
|
||||
<div :class="['login-modal-footer-args', AgreementWarn ? 'shaking-box' : '']">
|
||||
<GAgreement v-model="status" @declares="(typ) => handleDisplay(typ)" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="formType === 'register' || formType === 'forget'">
|
||||
<Tooltip position="bottom" :content="errorMsg" :mouse-enter-delay="350" :disabled="!(formType === 'register' && formErrors?.username?.length > 42 )">
|
||||
<div class="text-[#F2050D] text-[14px] break-all box-border leading-[20px] pl-[101px] h-[40px] login-modal-ellipsis" :class="formType === 'register' && formErrors?.username?.length > 42 ? 'cursor-pointer' : ''">
|
||||
{{ errorMsg }}
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div :class="[AgreementWarn ? 'shaking-box' : '']" v-if="formType === 'register'">
|
||||
<GAgreements v-model="hwStatus" @declares="(typ) => handleDisplay(typ, 'huawei')" agreement-text="《华为云用户协议》" privacy-text="《华为云隐私政策声明》" />
|
||||
<GAgreements v-model="status" @declares="(typ) => handleDisplay(typ)" agreement-text="《GitCode用户协议》" privacy-text="《GitCode隐私政策》"/>
|
||||
</div>
|
||||
<div :class="formType === 'forget' ? ' mt-[44px]' : 'mt-[24px]'">
|
||||
<Button
|
||||
color="primary"
|
||||
variant="solid"
|
||||
size="md"
|
||||
@click="handleConfirm"
|
||||
:disabled="disabled"
|
||||
:loading="loading"
|
||||
class="w-[100%]"
|
||||
>
|
||||
{{ formType === 'forget' ? '修改密码' : '确 认' }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<iframe src="https://test.gitcode.net/login/?be_nested=1"></iframe>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
@@ -818,6 +794,11 @@ $active-title: var(--color-CG900);
|
||||
$active-color: var(--color-CG800);
|
||||
$inactive-title: var(--color-CG500);
|
||||
$active-panel: var(--color-G800);
|
||||
iframe {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
height: 60vh;
|
||||
}
|
||||
.login-modal {
|
||||
box-sizing: border-box;
|
||||
padding: 24px 28px 24px;
|
||||
@@ -869,7 +850,7 @@ $active-panel: var(--color-G800);
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top:36px;
|
||||
top: 36px;
|
||||
border-radius: 2px;
|
||||
border-bottom: 2px solid $active-panel;
|
||||
left: -4px;
|
||||
@@ -893,7 +874,7 @@ $active-panel: var(--color-G800);
|
||||
height: 20px;
|
||||
}
|
||||
&-left {
|
||||
color: #F2050D;
|
||||
color: #f2050d;
|
||||
max-width: 240px;
|
||||
min-width: 240px;
|
||||
overflow: hidden;
|
||||
@@ -994,7 +975,8 @@ $active-panel: var(--color-G800);
|
||||
animation: shaking 0.25s ease-in-out;
|
||||
}
|
||||
@keyframes shaking {
|
||||
0%, 100% {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
25% {
|
||||
|
||||
@@ -59,29 +59,29 @@ export const useAccountStore = defineStore('accountInfo', () => {
|
||||
}
|
||||
};
|
||||
// 可能有从博客跳转过来的,通过接口判断是否登陆
|
||||
const checkIsLogin = async () => {
|
||||
const { data, error } = await getUserToken();
|
||||
if (data?.data) {
|
||||
const { access_token, refresh_token } = data.data;
|
||||
localStorage.setItem('access_token', access_token);
|
||||
localStorage.setItem('refresh_token', refresh_token);
|
||||
saveStatus(true);
|
||||
const userRes = await getUserInfo();
|
||||
if (userRes.data?.data) {
|
||||
localStorage.setItem('userInfo', JSON.stringify(userRes.data?.data));
|
||||
saveAccountInfo({
|
||||
access_token: localStorage.getItem('access_token') || '',
|
||||
refresh_token: localStorage.getItem('refresh_token') || '',
|
||||
...userRes.data?.data
|
||||
});
|
||||
}
|
||||
const checkIsLogin = async (access_token: string, refresh_token: string) => {
|
||||
// const { data, error } = await getUserToken();
|
||||
// if (data?.data) {
|
||||
// const { access_token, refresh_token } = data.data;
|
||||
localStorage.setItem('access_token', access_token);
|
||||
localStorage.setItem('refresh_token', refresh_token);
|
||||
saveStatus(true);
|
||||
const userRes = await getUserInfo();
|
||||
if (userRes.data?.data) {
|
||||
localStorage.setItem('userInfo', JSON.stringify(userRes.data?.data));
|
||||
saveAccountInfo({
|
||||
access_token: localStorage.getItem('access_token') || '',
|
||||
refresh_token: localStorage.getItem('refresh_token') || '',
|
||||
...userRes.data?.data
|
||||
});
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
localStorage.removeItem('access_token');
|
||||
localStorage.removeItem('refresh_token');
|
||||
localStorage.removeItem('userInfo');
|
||||
saveAccountInfo({});
|
||||
return false;
|
||||
// localStorage.removeItem('access_token');
|
||||
// localStorage.removeItem('refresh_token');
|
||||
// localStorage.removeItem('userInfo');
|
||||
// saveAccountInfo({});
|
||||
// return false;
|
||||
};
|
||||
const saveAtomgitUserName = (username: string) => {
|
||||
accountInfo.atomgit_username = username;
|
||||
|
||||
51
src/views/Jyh/Version/Detail/CommunityInfo.vue
Normal file
51
src/views/Jyh/Version/Detail/CommunityInfo.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div class="version-info">
|
||||
<Card simple class="jyh-card mb-4">
|
||||
<div class="card-title">基本信息</div>
|
||||
<d-row class="mb-3">
|
||||
<d-col :span="8">
|
||||
<span class="card-key width-90">社区名称</span>
|
||||
<span class="card-val">开发者社区</span>
|
||||
</d-col>
|
||||
<d-col :span="8">
|
||||
<span class="card-key width-90">官网地址</span>
|
||||
<span class="card-val">https://www.huaweicloud.com</span>
|
||||
</d-col>
|
||||
<d-col :span="8">
|
||||
<span class="card-key width-90">联系方式</span>
|
||||
<span class="card-val">950808-1</span>
|
||||
</d-col>
|
||||
</d-row>
|
||||
<d-row>
|
||||
<d-col :span="24">
|
||||
<div class="flex">
|
||||
<span class="card-key width-90 flex-shrink-0">社区描述</span>
|
||||
<span class="card-val flex-grow-1"
|
||||
>华为开发者社区致力于打造华为开发者专属的官方技术交流平台,帮助开发者探索开发实践、交流心得经验、获悉业界动态、解决开发问题。汇聚华为云社区“华为云”领域博
|
||||
客、问答、视频等精彩内容,形成开发者和技术爱好者交流与分享主阵地。</span
|
||||
>
|
||||
</div>
|
||||
</d-col>
|
||||
</d-row>
|
||||
</Card>
|
||||
<Card simple class="jyh-card mb-4">
|
||||
<div class="card-title">贡献者分布</div>
|
||||
<p class="card-desc">有关Pull Request创建者的公司信息和地区分布(使用公共GitHub信息进行分析)</p>
|
||||
<d-row class="mt-3">
|
||||
<d-col :span="12">
|
||||
<p>国家/地球分布</p>
|
||||
</d-col>
|
||||
<d-col :span="12">
|
||||
<p>组织/公司分布</p>
|
||||
</d-col>
|
||||
</d-row>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.card-desc {
|
||||
font-size: 12px;
|
||||
color: #808080;
|
||||
}
|
||||
</style>
|
||||
@@ -27,11 +27,13 @@
|
||||
<d-tab id="bbxx" title="版本信息"></d-tab>
|
||||
<d-tab id="ylgx" title="依赖关系"></d-tab>
|
||||
<d-tab id="ldxx" title="漏洞信息"></d-tab>
|
||||
<d-tab id="communityInfo" title="开发者社区信息"></d-tab>
|
||||
</d-tabs>
|
||||
</div>
|
||||
<div class="version-detail-content">
|
||||
<version-info v-if="selectTab === 'bbxx'"></version-info>
|
||||
<vulnerabilities-list v-else-if="selectTab === 'ldxx'"></vulnerabilities-list>
|
||||
<community-info v-else-if="selectTab === 'communityInfo'"></community-info>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -41,6 +43,7 @@ import { ref, reactive } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { getOrgInfo } from '@/views/Org/hooks/orgInfo';
|
||||
import VulnerabilitiesList from './VulnerabilitiesList.vue';
|
||||
import CommunityInfo from './CommunityInfo.vue';
|
||||
import VersionInfo from './VersionInfo.vue';
|
||||
const { namespace } = getOrgInfo();
|
||||
const avatarUrl = '/src/assets/imgs/jyh/工程首字母图标.png';
|
||||
|
||||
Reference in New Issue
Block a user