Merge remote-tracking branch 'origin/master'
# Conflicts: # src/components/Header/UserAvatar.vue
This commit is contained in:
@@ -52,13 +52,18 @@ const toggleDropDown = (isShow) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const logout = async() => {
|
const logout = async () => {
|
||||||
|
RemoveInfo(); // 目前先强制清除用户信息,后面接口通了再调
|
||||||
const res = await toLogout();
|
const res = await toLogout();
|
||||||
await reqCatch(devLogout, {}); // 清除社区登录
|
await reqCatch(devLogout, {}); // 清除社区登录
|
||||||
if (!res.error) {
|
if (!res.error) {
|
||||||
RemoveInfo();
|
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('/');
|
router.push('/');
|
||||||
} else {
|
} else {
|
||||||
router.go(0);
|
router.go(0);
|
||||||
@@ -84,11 +89,10 @@ const DEFAULT_ROUTER_PARAMS = Object.freeze({
|
|||||||
params: {
|
params: {
|
||||||
namespace: accountInfo.value.username
|
namespace: accountInfo.value.username
|
||||||
},
|
},
|
||||||
query: {
|
query: {}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// 获取router跳转参数
|
// 获取router跳转参数
|
||||||
const getRouterLink = params => {
|
const getRouterLink = (params) => {
|
||||||
if (typeof params === 'string') {
|
if (typeof params === 'string') {
|
||||||
return {
|
return {
|
||||||
...DEFAULT_ROUTER_PARAMS,
|
...DEFAULT_ROUTER_PARAMS,
|
||||||
@@ -156,7 +160,7 @@ const blockList = ref([
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #2D2D2E;
|
color: #2d2d2e;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
.close-icon {
|
.close-icon {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -164,7 +168,7 @@ const blockList = ref([
|
|||||||
}
|
}
|
||||||
&-id {
|
&-id {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #707A87;
|
color: #707a87;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,7 +187,6 @@ const blockList = ref([
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -7,14 +7,37 @@ import GTitle from './widget/title.vue';
|
|||||||
import { useModel } from '@/utils/hooks/useModel';
|
import { useModel } from '@/utils/hooks/useModel';
|
||||||
import type { GLoginModalProps, GLogoProps } from './types';
|
import type { GLoginModalProps, GLogoProps } from './types';
|
||||||
import { TransAssetsUrl } from '@/utils/asset';
|
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 { Modal } from 'vue-devui/modal';
|
||||||
import { Button } from 'vue-devui/button';
|
import { Button } from 'vue-devui/button';
|
||||||
import { Icon } from 'vue-devui/icon';
|
import { Icon } from 'vue-devui/icon';
|
||||||
import { Tooltip } from 'vue-devui/tooltip';
|
import { Tooltip } from 'vue-devui/tooltip';
|
||||||
import { Message } from 'vue-devui/message';
|
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 { FormRules, isMobileEmail } from './form';
|
||||||
|
import { useAccountStore } from '@/stores/user';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: 待集成入该hook
|
* TODO: 待集成入该hook
|
||||||
@@ -34,7 +57,7 @@ const IconB = TransAssetsUrl(IconSource, 'logo-back');
|
|||||||
// 表单验证结果
|
// 表单验证结果
|
||||||
const formErrors = reactive<Record<string, string>>({});
|
const formErrors = reactive<Record<string, string>>({});
|
||||||
// 额外验证参数
|
// 额外验证参数
|
||||||
const extraErrors = reactive<{ agreement: string, requestInfo: string }>({
|
const extraErrors = reactive<{ agreement: string; requestInfo: string }>({
|
||||||
agreement: '',
|
agreement: '',
|
||||||
requestInfo: ''
|
requestInfo: ''
|
||||||
});
|
});
|
||||||
@@ -45,7 +68,13 @@ const disabled = ref(true);
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
const isRegister = 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: '',
|
mobile: '',
|
||||||
verificationcode: '',
|
verificationcode: '',
|
||||||
countdownSecond: 59,
|
countdownSecond: 59,
|
||||||
@@ -53,7 +82,7 @@ const cacheForm = reactive<{ mobile: string, verificationcode: string, countdown
|
|||||||
mask: ''
|
mask: ''
|
||||||
});
|
});
|
||||||
let timer: any = null;
|
let timer: any = null;
|
||||||
let interval:any = null;
|
let interval: any = null;
|
||||||
|
|
||||||
const logos = reactive<GLogoProps[]>([
|
const logos = reactive<GLogoProps[]>([
|
||||||
{
|
{
|
||||||
@@ -99,7 +128,7 @@ const VerifyForm = reactive<FormListProps[]>([
|
|||||||
required: true,
|
required: true,
|
||||||
rules: FormRules.codes,
|
rules: FormRules.codes,
|
||||||
props: {
|
props: {
|
||||||
'autocomplete': true,
|
autocomplete: true,
|
||||||
countdown: false,
|
countdown: false,
|
||||||
second: 59,
|
second: 59,
|
||||||
aliasKey: 'mobile'
|
aliasKey: 'mobile'
|
||||||
@@ -121,13 +150,13 @@ const PasswordForm = reactive<FormListProps[]>([
|
|||||||
required: true,
|
required: true,
|
||||||
props: {
|
props: {
|
||||||
'show-password': true,
|
'show-password': true,
|
||||||
'autocomplete': true,
|
autocomplete: true,
|
||||||
'maxlength': 30
|
maxlength: 30
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const VerifyPassword:FormListProps[] = [
|
const VerifyPassword: FormListProps[] = [
|
||||||
{
|
{
|
||||||
type: 'input',
|
type: 'input',
|
||||||
key: 'password',
|
key: 'password',
|
||||||
@@ -137,8 +166,8 @@ const VerifyPassword:FormListProps[] = [
|
|||||||
help: '密码最少包含一个大写字母、一个小写字母、一个数字, 长度为8~30之间',
|
help: '密码最少包含一个大写字母、一个小写字母、一个数字, 长度为8~30之间',
|
||||||
props: {
|
props: {
|
||||||
'show-password': true,
|
'show-password': true,
|
||||||
'autocomplete': true,
|
autocomplete: true,
|
||||||
'maxlength': 30
|
maxlength: 30
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -175,15 +204,15 @@ const VerifyPassword:FormListProps[] = [
|
|||||||
],
|
],
|
||||||
props: {
|
props: {
|
||||||
'show-password': true,
|
'show-password': true,
|
||||||
'autocomplete': true,
|
autocomplete: true,
|
||||||
'maxlength': 30
|
maxlength: 30
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
/** 检测用户是否存在 */
|
/** 检测用户是否存在 */
|
||||||
const requestCheck = {
|
const requestCheck = {
|
||||||
trigger: 'change',
|
trigger: 'change',
|
||||||
validator: async(_: any, val: string, cb: Function) => {
|
validator: async (_: any, val: string, cb: Function) => {
|
||||||
const res = await checkUsername(val);
|
const res = await checkUsername(val);
|
||||||
if (!res.error) {
|
if (!res.error) {
|
||||||
if (res.data.data.result) {
|
if (res.data.data.result) {
|
||||||
@@ -223,7 +252,7 @@ const RegisterForm = reactive<FormListProps[]>([
|
|||||||
required: true,
|
required: true,
|
||||||
rules: FormRules.codes,
|
rules: FormRules.codes,
|
||||||
props: {
|
props: {
|
||||||
'autocomplete': true,
|
autocomplete: true,
|
||||||
countdown: false,
|
countdown: false,
|
||||||
second: 59,
|
second: 59,
|
||||||
aliasKey: 'mobile'
|
aliasKey: 'mobile'
|
||||||
@@ -261,17 +290,21 @@ const FormRef = shallowRef<any>(null);
|
|||||||
const tabPanel = ref<'verifyCode' | 'password'>('password');
|
const tabPanel = ref<'verifyCode' | 'password'>('password');
|
||||||
const formType = ref<'login' | 'register' | 'forget'>(props.defaultType);
|
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') {
|
if (formType.value === 'register') {
|
||||||
return {
|
return {
|
||||||
dict: RegisterForm.map(item => {
|
dict: RegisterForm.map((item) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
defaultValue: item.key === 'mobile'
|
defaultValue:
|
||||||
? cacheForm.mobile
|
item.key === 'mobile' ? cacheForm.mobile : item.key === 'verificationcode' ? cacheForm.verificationcode : ''
|
||||||
: item.key === 'verificationcode'
|
|
||||||
? cacheForm.verificationcode
|
|
||||||
: ''
|
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
showLabel: true,
|
showLabel: true,
|
||||||
@@ -291,7 +324,7 @@ const FormConfig = computed<{ dict: FormListProps[], showLabel: boolean, layout:
|
|||||||
}
|
}
|
||||||
if (tabPanel.value === 'verifyCode') {
|
if (tabPanel.value === 'verifyCode') {
|
||||||
return {
|
return {
|
||||||
dict: VerifyForm.map(item => {
|
dict: VerifyForm.map((item) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
defaultValue: item.key === 'mobile' ? cacheForm.mobile : ''
|
defaultValue: item.key === 'mobile' ? cacheForm.mobile : ''
|
||||||
@@ -299,7 +332,7 @@ const FormConfig = computed<{ dict: FormListProps[], showLabel: boolean, layout:
|
|||||||
}),
|
}),
|
||||||
showLabel: false,
|
showLabel: false,
|
||||||
layout: 'vertical',
|
layout: 'vertical',
|
||||||
title: '欢迎登录你的GitCode账号',
|
title: '欢迎登录你的GitCode账号1',
|
||||||
showBack: false
|
showBack: false
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@@ -322,7 +355,7 @@ const catchFormErrors = (conf: { errors: Record<string, any[]> }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleResetPassword = async() => {
|
const handleResetPassword = async () => {
|
||||||
if (FormRef.value) {
|
if (FormRef.value) {
|
||||||
const formData = await FormRef.value.ValidateForm();
|
const formData = await FormRef.value.ValidateForm();
|
||||||
if (formData.type === 'success') {
|
if (formData.type === 'success') {
|
||||||
@@ -347,7 +380,7 @@ const handleResetPassword = async() => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleConfirm = async() => {
|
const handleConfirm = async () => {
|
||||||
let agreementFlag = false;
|
let agreementFlag = false;
|
||||||
if (formType.value === 'forget') {
|
if (formType.value === 'forget') {
|
||||||
handleResetPassword();
|
handleResetPassword();
|
||||||
@@ -397,10 +430,13 @@ const handleConfirm = async() => {
|
|||||||
extraErrors.requestInfo = result.error.error_message;
|
extraErrors.requestInfo = result.error.error_message;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const data = tabPanel.value === 'password' ? res : {
|
const data =
|
||||||
mobile: res.mobile,
|
tabPanel.value === 'password'
|
||||||
code: res.code
|
? res
|
||||||
};
|
: {
|
||||||
|
mobile: res.mobile,
|
||||||
|
code: res.code
|
||||||
|
};
|
||||||
const result = tabPanel.value === 'password' ? await toLogin(res) : await loginByMobile(data);
|
const result = tabPanel.value === 'password' ? await toLogin(res) : await loginByMobile(data);
|
||||||
if (!result.error) {
|
if (!result.error) {
|
||||||
const { user_id, mask, mobile } = result.data.data;
|
const { user_id, mask, mobile } = result.data.data;
|
||||||
@@ -425,7 +461,7 @@ const handleConfirm = async() => {
|
|||||||
/**
|
/**
|
||||||
* 绑定华为云
|
* 绑定华为云
|
||||||
* @deprecated at 精简单注册登录
|
* @deprecated at 精简单注册登录
|
||||||
*/
|
*/
|
||||||
// const handleBind = (res: any) => {
|
// const handleBind = (res: any) => {
|
||||||
// if (!res.error) {
|
// if (!res.error) {
|
||||||
// emits('login', res.data.data);
|
// emits('login', res.data.data);
|
||||||
@@ -440,8 +476,10 @@ const handleClose = (close: Function) => {
|
|||||||
};
|
};
|
||||||
/** 外链url */
|
/** 外链url */
|
||||||
const links = {
|
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',
|
agreement:
|
||||||
'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'
|
'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 = {
|
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]);
|
const formData = await FormRef.value.ValidateFormKeys([conf.key]);
|
||||||
if (formData.type === 'success') {
|
if (formData.type === 'success') {
|
||||||
clearFormError(conf.key);
|
clearFormError(conf.key);
|
||||||
if (tabPanel.value === 'verifyCode' || formType.value === 'register' || formType.value === 'forget') {
|
if (tabPanel.value === 'verifyCode' || formType.value === 'register' || formType.value === 'forget') {
|
||||||
const res = formType.value === 'login'
|
const res =
|
||||||
? await getQuickLoginMsg({ mobile: conf.value })
|
formType.value === 'login'
|
||||||
: formType.value === 'forget'
|
? await getQuickLoginMsg({ mobile: conf.value })
|
||||||
|
: formType.value === 'forget'
|
||||||
? await getMobileEmailCode(conf.value)
|
? await getMobileEmailCode(conf.value)
|
||||||
: await verifyRegisterCode({ mobile: conf.value, type: 'REGISTER' });
|
: await verifyRegisterCode({ mobile: conf.value, type: 'REGISTER' });
|
||||||
if (!res.error) {
|
if (!res.error) {
|
||||||
const source = formType.value === 'register'
|
const source =
|
||||||
? RegisterForm
|
formType.value === 'register' ? RegisterForm : formType.value === 'forget' ? ForgetPasswordForm : VerifyForm;
|
||||||
: formType.value === 'forget'
|
|
||||||
? ForgetPasswordForm
|
|
||||||
: VerifyForm;
|
|
||||||
cacheForm.mobile = conf.value;
|
cacheForm.mobile = conf.value;
|
||||||
if (Number(res?.data.data.type === 1)) {
|
if (Number(res?.data.data.type === 1)) {
|
||||||
isRegister.value = true;
|
isRegister.value = true;
|
||||||
@@ -510,7 +546,7 @@ const handleCountDown = async(conf: { key: string, value: any, sourceKey: string
|
|||||||
const message = isMobileEmail(conf.value);
|
const message = isMobileEmail(conf.value);
|
||||||
dealLog(`验证码已发送到你的${message}, 请注意查收`, 'success');
|
dealLog(`验证码已发送到你的${message}, 请注意查收`, 'success');
|
||||||
}
|
}
|
||||||
source.forEach(item => {
|
source.forEach((item) => {
|
||||||
if (item.key === conf.sourceKey) {
|
if (item.key === conf.sourceKey) {
|
||||||
if (item.props) {
|
if (item.props) {
|
||||||
item.props.countdown = true;
|
item.props.countdown = true;
|
||||||
@@ -564,15 +600,16 @@ const toCountDown = () => {
|
|||||||
};
|
};
|
||||||
/** 刷新倒计时的状态 */
|
/** 刷新倒计时的状态 */
|
||||||
const refreshCountDown = (tab: string, menu: string) => {
|
const refreshCountDown = (tab: string, menu: string) => {
|
||||||
const source = menu === 'register'
|
const source =
|
||||||
? RegisterForm
|
menu === 'register'
|
||||||
: formType.value === 'forget'
|
? RegisterForm
|
||||||
|
: formType.value === 'forget'
|
||||||
? ForgetPasswordForm
|
? ForgetPasswordForm
|
||||||
: tab === 'verifyCode'
|
: tab === 'verifyCode'
|
||||||
? VerifyForm
|
? VerifyForm
|
||||||
: null;
|
: null;
|
||||||
if (source) {
|
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 (countdown?.props && Object.prototype.hasOwnProperty.call(countdown.props, 'countdown')) {
|
||||||
if (cacheForm.countdownSecond !== 59 && menu === 'register' && isRegister.value) {
|
if (cacheForm.countdownSecond !== 59 && menu === 'register' && isRegister.value) {
|
||||||
countdown.props.second = cacheForm.countdownSecond;
|
countdown.props.second = cacheForm.countdownSecond;
|
||||||
@@ -584,7 +621,7 @@ const refreshCountDown = (tab: string, menu: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
/** 表单字段change事件 */
|
/** 表单字段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;
|
const { key, errors } = conf;
|
||||||
if (errors) {
|
if (errors) {
|
||||||
setFormErrorKey({ errors });
|
setFormErrorKey({ errors });
|
||||||
@@ -595,9 +632,9 @@ const handleFormChange = (conf: { key: string, errors: Record<string, any> | nul
|
|||||||
const keys = Object.keys(formErrors);
|
const keys = Object.keys(formErrors);
|
||||||
const currentForm = FormConfig.value.dict;
|
const currentForm = FormConfig.value.dict;
|
||||||
if (currentForm?.length) {
|
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) {
|
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) {
|
if (filterKeys.length) {
|
||||||
FormRef.value?.ClearFormFields(filterKeys);
|
FormRef.value?.ClearFormFields(filterKeys);
|
||||||
} else {
|
} else {
|
||||||
@@ -617,9 +654,9 @@ const errorMsg = computed(() => {
|
|||||||
const keys = Object.keys(formErrors);
|
const keys = Object.keys(formErrors);
|
||||||
const currentForm = FormConfig.value.dict;
|
const currentForm = FormConfig.value.dict;
|
||||||
if (currentForm?.length) {
|
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) {
|
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);
|
filterKeys.length && FormRef.value?.ClearFormFields(filterKeys);
|
||||||
hackMsgError(obj?.key === 'verificationcode' || obj?.key === 'code');
|
hackMsgError(obj?.key === 'verificationcode' || obj?.key === 'code');
|
||||||
}
|
}
|
||||||
@@ -644,25 +681,28 @@ const hackMsgError = (show_error: boolean) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(() => [tabPanel.value, formType.value], (newVal, oldVal) => {
|
watch(
|
||||||
if (FormRef.value) {
|
() => [tabPanel.value, formType.value],
|
||||||
FormRef.value.ClearForm();
|
(newVal, oldVal) => {
|
||||||
clearFormError();
|
if (FormRef.value) {
|
||||||
disabled.value = true;
|
FormRef.value.ClearForm();
|
||||||
}
|
clearFormError();
|
||||||
const [tab, menu] = newVal;
|
disabled.value = true;
|
||||||
const [_, prev_menu] = oldVal;
|
|
||||||
if (menu !== 'register') {
|
|
||||||
if (interval) {
|
|
||||||
clearInterval(interval);
|
|
||||||
interval = null;
|
|
||||||
}
|
}
|
||||||
|
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');
|
localStorage.removeItem('loginReturnUrl');
|
||||||
@@ -684,7 +724,9 @@ const handleAuthLogin = (type: 'csdn' | 'gitee' | 'github') => {
|
|||||||
// 保存注册上报类型和ref
|
// 保存注册上报类型和ref
|
||||||
sessionStorage.setItem('loginType', props.triggerType || '');
|
sessionStorage.setItem('loginType', props.triggerType || '');
|
||||||
// window.open('http://localhost:5173/oauth/callback', '_blank', 'width=800, height=800, left=200, top=200');
|
// 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');
|
window.open(url, '_blank', 'width=800, height=800, left=400, top=200');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -707,6 +749,27 @@ onBeforeUnmount(() => {
|
|||||||
clearInterval(interval);
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -720,95 +783,8 @@ onBeforeUnmount(() => {
|
|||||||
:append-to-body="appendToBody"
|
:append-to-body="appendToBody"
|
||||||
:class="['login-modal', formType === 'login' ? 'login-modal-l' : 'login-modal-r']"
|
: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>
|
<template #default>
|
||||||
<div class="flex items-center justify-center mb-[24px] mt-[-2px]" v-if="formType === 'login'">
|
<iframe src="https://test.gitcode.net/login/?be_nested=1"></iframe>
|
||||||
<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>
|
|
||||||
</template>
|
</template>
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
@@ -818,6 +794,11 @@ $active-title: var(--color-CG900);
|
|||||||
$active-color: var(--color-CG800);
|
$active-color: var(--color-CG800);
|
||||||
$inactive-title: var(--color-CG500);
|
$inactive-title: var(--color-CG500);
|
||||||
$active-panel: var(--color-G800);
|
$active-panel: var(--color-G800);
|
||||||
|
iframe {
|
||||||
|
border: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 60vh;
|
||||||
|
}
|
||||||
.login-modal {
|
.login-modal {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 24px 28px 24px;
|
padding: 24px 28px 24px;
|
||||||
@@ -869,7 +850,7 @@ $active-panel: var(--color-G800);
|
|||||||
&::after {
|
&::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
content: '';
|
content: '';
|
||||||
top:36px;
|
top: 36px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
border-bottom: 2px solid $active-panel;
|
border-bottom: 2px solid $active-panel;
|
||||||
left: -4px;
|
left: -4px;
|
||||||
@@ -893,7 +874,7 @@ $active-panel: var(--color-G800);
|
|||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
&-left {
|
&-left {
|
||||||
color: #F2050D;
|
color: #f2050d;
|
||||||
max-width: 240px;
|
max-width: 240px;
|
||||||
min-width: 240px;
|
min-width: 240px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -994,7 +975,8 @@ $active-panel: var(--color-G800);
|
|||||||
animation: shaking 0.25s ease-in-out;
|
animation: shaking 0.25s ease-in-out;
|
||||||
}
|
}
|
||||||
@keyframes shaking {
|
@keyframes shaking {
|
||||||
0%, 100% {
|
0%,
|
||||||
|
100% {
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
}
|
}
|
||||||
25% {
|
25% {
|
||||||
|
|||||||
@@ -59,29 +59,29 @@ export const useAccountStore = defineStore('accountInfo', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// 可能有从博客跳转过来的,通过接口判断是否登陆
|
// 可能有从博客跳转过来的,通过接口判断是否登陆
|
||||||
const checkIsLogin = async () => {
|
const checkIsLogin = async (access_token: string, refresh_token: string) => {
|
||||||
const { data, error } = await getUserToken();
|
// const { data, error } = await getUserToken();
|
||||||
if (data?.data) {
|
// if (data?.data) {
|
||||||
const { access_token, refresh_token } = data.data;
|
// const { access_token, refresh_token } = data.data;
|
||||||
localStorage.setItem('access_token', access_token);
|
localStorage.setItem('access_token', access_token);
|
||||||
localStorage.setItem('refresh_token', refresh_token);
|
localStorage.setItem('refresh_token', refresh_token);
|
||||||
saveStatus(true);
|
saveStatus(true);
|
||||||
const userRes = await getUserInfo();
|
const userRes = await getUserInfo();
|
||||||
if (userRes.data?.data) {
|
if (userRes.data?.data) {
|
||||||
localStorage.setItem('userInfo', JSON.stringify(userRes.data?.data));
|
localStorage.setItem('userInfo', JSON.stringify(userRes.data?.data));
|
||||||
saveAccountInfo({
|
saveAccountInfo({
|
||||||
access_token: localStorage.getItem('access_token') || '',
|
access_token: localStorage.getItem('access_token') || '',
|
||||||
refresh_token: localStorage.getItem('refresh_token') || '',
|
refresh_token: localStorage.getItem('refresh_token') || '',
|
||||||
...userRes.data?.data
|
...userRes.data?.data
|
||||||
});
|
});
|
||||||
}
|
// }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
localStorage.removeItem('access_token');
|
// localStorage.removeItem('access_token');
|
||||||
localStorage.removeItem('refresh_token');
|
// localStorage.removeItem('refresh_token');
|
||||||
localStorage.removeItem('userInfo');
|
// localStorage.removeItem('userInfo');
|
||||||
saveAccountInfo({});
|
// saveAccountInfo({});
|
||||||
return false;
|
// return false;
|
||||||
};
|
};
|
||||||
const saveAtomgitUserName = (username: string) => {
|
const saveAtomgitUserName = (username: string) => {
|
||||||
accountInfo.atomgit_username = username;
|
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="bbxx" title="版本信息"></d-tab>
|
||||||
<d-tab id="ylgx" title="依赖关系"></d-tab>
|
<d-tab id="ylgx" title="依赖关系"></d-tab>
|
||||||
<d-tab id="ldxx" title="漏洞信息"></d-tab>
|
<d-tab id="ldxx" title="漏洞信息"></d-tab>
|
||||||
|
<d-tab id="communityInfo" title="开发者社区信息"></d-tab>
|
||||||
</d-tabs>
|
</d-tabs>
|
||||||
</div>
|
</div>
|
||||||
<div class="version-detail-content">
|
<div class="version-detail-content">
|
||||||
<version-info v-if="selectTab === 'bbxx'"></version-info>
|
<version-info v-if="selectTab === 'bbxx'"></version-info>
|
||||||
<vulnerabilities-list v-else-if="selectTab === 'ldxx'"></vulnerabilities-list>
|
<vulnerabilities-list v-else-if="selectTab === 'ldxx'"></vulnerabilities-list>
|
||||||
|
<community-info v-else-if="selectTab === 'communityInfo'"></community-info>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -41,6 +43,7 @@ import { ref, reactive } from 'vue';
|
|||||||
import { useRouter, useRoute } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router';
|
||||||
import { getOrgInfo } from '@/views/Org/hooks/orgInfo';
|
import { getOrgInfo } from '@/views/Org/hooks/orgInfo';
|
||||||
import VulnerabilitiesList from './VulnerabilitiesList.vue';
|
import VulnerabilitiesList from './VulnerabilitiesList.vue';
|
||||||
|
import CommunityInfo from './CommunityInfo.vue';
|
||||||
import VersionInfo from './VersionInfo.vue';
|
import VersionInfo from './VersionInfo.vue';
|
||||||
const { namespace } = getOrgInfo();
|
const { namespace } = getOrgInfo();
|
||||||
const avatarUrl = '/src/assets/imgs/jyh/工程首字母图标.png';
|
const avatarUrl = '/src/assets/imgs/jyh/工程首字母图标.png';
|
||||||
|
|||||||
Reference in New Issue
Block a user