mirror of https://gitee.com/answerdev/answer.git
Merge remote-tracking branch 'github/feat/1.1.2/ui' into feat/1.1.2/user-center
This commit is contained in:
commit
1d3f61e8a6
|
@ -8,6 +8,12 @@ export const CAPTCHA_CODE_STORAGE_KEY = '_a_captcha_';
|
|||
export const DRAFT_QUESTION_STORAGE_KEY = '_a_dq_';
|
||||
export const DRAFT_ANSWER_STORAGE_KEY = '_a_da_';
|
||||
export const DRAFT_TIMESIGH_STORAGE_KEY = '|_a_t_s_|';
|
||||
export const USER_AGENT_NAMES = {
|
||||
SegmentFault: 'SegmentFault',
|
||||
WeChat: 'WeChat',
|
||||
WeCom: 'WeCom',
|
||||
DingTalk: 'DingTalk',
|
||||
};
|
||||
|
||||
export const IGNORE_PATH_LIST = [
|
||||
'/users/login',
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
const pattern = {
|
||||
email:
|
||||
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+\.)+[a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{2,}))$/,
|
||||
wx: /micromessenger/,
|
||||
wxwork: /wxwork/,
|
||||
dingtalk: /dingtalk/,
|
||||
uaWeChat: /micromessenger/i,
|
||||
uaWeCom: /wxwork/i,
|
||||
uaDingTalk: /dingtalk/i,
|
||||
};
|
||||
|
||||
export default pattern;
|
||||
|
|
|
@ -6,7 +6,7 @@ import type * as Type from '@/common/interface';
|
|||
interface Props {
|
||||
type: 'radio' | 'checkbox';
|
||||
fieldName: string;
|
||||
onChange: (evt: React.ChangeEvent<HTMLInputElement>, ...rest) => void;
|
||||
onChange?: (fd: Type.FormDataType) => void;
|
||||
enumValues: (string | boolean | number)[];
|
||||
enumNames: string[];
|
||||
formData: Type.FormDataType;
|
||||
|
@ -20,6 +20,24 @@ const Index: FC<Props> = ({
|
|||
formData,
|
||||
}) => {
|
||||
const fieldObject = formData[fieldName];
|
||||
const handleCheck = (
|
||||
evt: React.ChangeEvent<HTMLInputElement>,
|
||||
index: number,
|
||||
) => {
|
||||
const { name, checked } = evt.currentTarget;
|
||||
const freshVal = checked ? enumValues?.[index] : '';
|
||||
const state = {
|
||||
...formData,
|
||||
[name]: {
|
||||
...formData[name],
|
||||
value: freshVal,
|
||||
isInvalid: false,
|
||||
},
|
||||
};
|
||||
if (typeof onChange === 'function') {
|
||||
onChange(state);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Stack direction="horizontal">
|
||||
{enumValues?.map((item, index) => {
|
||||
|
@ -36,7 +54,7 @@ const Index: FC<Props> = ({
|
|||
feedback={fieldObject?.errorMsg}
|
||||
feedbackType="invalid"
|
||||
isInvalid={fieldObject?.isInvalid}
|
||||
onChange={(evt) => onChange(evt, index)}
|
||||
onChange={(evt) => handleCheck(evt, index)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
|
|
@ -7,7 +7,7 @@ interface Props {
|
|||
type: string | undefined;
|
||||
placeholder: string | undefined;
|
||||
fieldName: string;
|
||||
onChange: (evt: React.ChangeEvent<HTMLInputElement>, ...rest) => void;
|
||||
onChange?: (fd: Type.FormDataType) => void;
|
||||
formData: Type.FormDataType;
|
||||
readOnly: boolean;
|
||||
}
|
||||
|
@ -20,13 +20,28 @@ const Index: FC<Props> = ({
|
|||
readOnly = false,
|
||||
}) => {
|
||||
const fieldObject = formData[fieldName];
|
||||
const handleChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = evt.currentTarget;
|
||||
const state = {
|
||||
...formData,
|
||||
[name]: {
|
||||
...formData[name],
|
||||
value,
|
||||
isInvalid: false,
|
||||
},
|
||||
};
|
||||
if (typeof onChange === 'function') {
|
||||
onChange(state);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form.Control
|
||||
name={fieldName}
|
||||
placeholder={placeholder}
|
||||
type={type}
|
||||
value={fieldObject?.value || ''}
|
||||
onChange={onChange}
|
||||
onChange={handleChange}
|
||||
readOnly={readOnly}
|
||||
isInvalid={fieldObject?.isInvalid}
|
||||
style={type === 'color' ? { width: '6rem' } : {}}
|
||||
|
|
|
@ -6,7 +6,7 @@ import type * as Type from '@/common/interface';
|
|||
interface Props {
|
||||
desc: string | undefined;
|
||||
fieldName: string;
|
||||
onChange: (evt: React.ChangeEvent<HTMLSelectElement>) => void;
|
||||
onChange?: (fd: Type.FormDataType) => void;
|
||||
enumValues: (string | boolean | number)[];
|
||||
enumNames: string[];
|
||||
formData: Type.FormDataType;
|
||||
|
@ -20,12 +20,26 @@ const Index: FC<Props> = ({
|
|||
formData,
|
||||
}) => {
|
||||
const fieldObject = formData[fieldName];
|
||||
const handleChange = (evt: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const { name, value } = evt.currentTarget;
|
||||
const state = {
|
||||
...formData,
|
||||
[name]: {
|
||||
...formData[name],
|
||||
value,
|
||||
isInvalid: false,
|
||||
},
|
||||
};
|
||||
if (typeof onChange === 'function') {
|
||||
onChange(state);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Form.Select
|
||||
aria-label={desc}
|
||||
name={fieldName}
|
||||
value={fieldObject?.value || ''}
|
||||
onChange={onChange}
|
||||
onChange={handleChange}
|
||||
isInvalid={fieldObject?.isInvalid}>
|
||||
{enumValues?.map((item, index) => {
|
||||
return (
|
||||
|
|
|
@ -7,11 +7,25 @@ interface Props {
|
|||
title: string;
|
||||
label: string | undefined;
|
||||
fieldName: string;
|
||||
onChange: (evt: React.ChangeEvent<HTMLInputElement>, ...rest) => void;
|
||||
onChange?: (fd: Type.FormDataType) => void;
|
||||
formData: Type.FormDataType;
|
||||
}
|
||||
const Index: FC<Props> = ({ title, fieldName, onChange, label, formData }) => {
|
||||
const fieldObject = formData[fieldName];
|
||||
const handleChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, checked } = evt.currentTarget;
|
||||
const state = {
|
||||
...formData,
|
||||
[name]: {
|
||||
...formData[name],
|
||||
value: checked,
|
||||
isInvalid: false,
|
||||
},
|
||||
};
|
||||
if (typeof onChange === 'function') {
|
||||
onChange(state);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Form.Check
|
||||
required
|
||||
|
@ -23,7 +37,7 @@ const Index: FC<Props> = ({ title, fieldName, onChange, label, formData }) => {
|
|||
feedback={fieldObject?.errorMsg}
|
||||
feedbackType="invalid"
|
||||
isInvalid={fieldObject.isInvalid}
|
||||
onChange={onChange}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ interface Props {
|
|||
rows: number | undefined;
|
||||
className: classnames.Argument;
|
||||
fieldName: string;
|
||||
onChange: (evt: React.ChangeEvent<HTMLInputElement>, ...rest) => void;
|
||||
onChange?: (fd: Type.FormDataType) => void;
|
||||
formData: Type.FormDataType;
|
||||
}
|
||||
const Index: FC<Props> = ({
|
||||
|
@ -22,13 +22,28 @@ const Index: FC<Props> = ({
|
|||
formData,
|
||||
}) => {
|
||||
const fieldObject = formData[fieldName];
|
||||
const handleChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = evt.currentTarget;
|
||||
const state = {
|
||||
...formData,
|
||||
[name]: {
|
||||
...formData[name],
|
||||
value,
|
||||
isInvalid: false,
|
||||
},
|
||||
};
|
||||
if (typeof onChange === 'function') {
|
||||
onChange(state);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form.Control
|
||||
as="textarea"
|
||||
name={fieldName}
|
||||
placeholder={placeholder}
|
||||
value={fieldObject?.value || ''}
|
||||
onChange={onChange}
|
||||
onChange={handleChange}
|
||||
isInvalid={fieldObject?.isInvalid}
|
||||
rows={rows}
|
||||
className={classnames(className)}
|
||||
|
|
|
@ -5,17 +5,31 @@ import TimeZonePicker from '@/components/TimeZonePicker';
|
|||
|
||||
interface Props {
|
||||
fieldName: string;
|
||||
onChange: (evt: React.ChangeEvent<HTMLSelectElement>, ...rest) => void;
|
||||
onChange?: (fd: Type.FormDataType) => void;
|
||||
formData: Type.FormDataType;
|
||||
}
|
||||
const Index: FC<Props> = ({ fieldName, onChange, formData }) => {
|
||||
const fieldObject = formData[fieldName];
|
||||
const handleChange = (evt: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const { name, value } = evt.currentTarget;
|
||||
const state = {
|
||||
...formData,
|
||||
[name]: {
|
||||
...formData[name],
|
||||
value,
|
||||
isInvalid: false,
|
||||
},
|
||||
};
|
||||
if (typeof onChange === 'function') {
|
||||
onChange(state);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<TimeZonePicker
|
||||
value={fieldObject?.value || ''}
|
||||
isInvalid={fieldObject?.isInvalid}
|
||||
name={fieldName}
|
||||
onChange={onChange}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ interface Props {
|
|||
type: Type.UploadType | undefined;
|
||||
acceptType: string | undefined;
|
||||
fieldName: string;
|
||||
onChange: (key, val) => void;
|
||||
onChange?: (fd: Type.FormDataType) => void;
|
||||
formData: Type.FormDataType;
|
||||
}
|
||||
const Index: FC<Props> = ({
|
||||
|
@ -19,13 +19,26 @@ const Index: FC<Props> = ({
|
|||
formData,
|
||||
}) => {
|
||||
const fieldObject = formData[fieldName];
|
||||
const handleChange = (name: string, value: string) => {
|
||||
console.log('upload: ', name, value);
|
||||
const state = {
|
||||
...formData,
|
||||
[name]: {
|
||||
...formData[name],
|
||||
value,
|
||||
},
|
||||
};
|
||||
if (typeof onChange === 'function') {
|
||||
onChange(state);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<BrandUpload
|
||||
type={type}
|
||||
acceptType={acceptType}
|
||||
value={fieldObject?.value}
|
||||
onChange={(value) => onChange(fieldName, value)}
|
||||
onChange={(value) => handleChange(fieldName, value)}
|
||||
/>
|
||||
<Form.Control
|
||||
name={fieldName}
|
||||
|
|
|
@ -148,7 +148,6 @@ interface IRef {
|
|||
* TODO:
|
||||
* - Normalize and document `formData[key].hidden && 'd-none'`
|
||||
* - Normalize and document `hiddenSubmit`
|
||||
* - `handleXXChange` methods are placed in the concrete component
|
||||
* - Improving field hints for `formData`
|
||||
* - Optimise form data updates
|
||||
* * Automatic field type conversion
|
||||
|
@ -210,38 +209,6 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
|
|||
useEffect(() => {
|
||||
setDefaultValueAsDomBehaviour();
|
||||
}, [formData]);
|
||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target;
|
||||
const data = {
|
||||
...formData,
|
||||
[name]: { ...formData[name], value, isInvalid: false },
|
||||
};
|
||||
if (onChange instanceof Function) {
|
||||
onChange(data);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const { name, value } = e.target;
|
||||
const data = {
|
||||
...formData,
|
||||
[name]: { ...formData[name], value, isInvalid: false },
|
||||
};
|
||||
if (onChange instanceof Function) {
|
||||
onChange(data);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSwitchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, checked } = e.target;
|
||||
const data = {
|
||||
...formData,
|
||||
[name]: { ...formData[name], value: checked, isInvalid: false },
|
||||
};
|
||||
if (onChange instanceof Function) {
|
||||
onChange(data);
|
||||
}
|
||||
};
|
||||
|
||||
const requiredValidator = () => {
|
||||
const errors: string[] = [];
|
||||
|
@ -351,32 +318,6 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
|
|||
}
|
||||
};
|
||||
|
||||
const handleUploadChange = (name: string, value: string) => {
|
||||
const data = { ...formData, [name]: { ...formData[name], value } };
|
||||
if (onChange instanceof Function) {
|
||||
onChange(data);
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputCheck = (
|
||||
e: React.ChangeEvent<HTMLInputElement>,
|
||||
index: number,
|
||||
) => {
|
||||
const { name, checked } = e.currentTarget;
|
||||
const freshVal = checked ? schema.properties[name]?.enum?.[index] : '';
|
||||
const data = {
|
||||
...formData,
|
||||
[name]: {
|
||||
...formData[name],
|
||||
value: freshVal,
|
||||
isInvalid: false,
|
||||
},
|
||||
};
|
||||
if (onChange instanceof Function) {
|
||||
onChange(data);
|
||||
}
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
validator,
|
||||
}));
|
||||
|
@ -422,7 +363,7 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
|
|||
<Select
|
||||
desc={description}
|
||||
fieldName={key}
|
||||
onChange={handleSelectChange}
|
||||
onChange={onChange}
|
||||
enumValues={enumValues}
|
||||
enumNames={enumNames}
|
||||
formData={formData}
|
||||
|
@ -432,7 +373,7 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
|
|||
<Check
|
||||
type={widget}
|
||||
fieldName={key}
|
||||
onChange={handleInputCheck}
|
||||
onChange={onChange}
|
||||
enumValues={enumValues}
|
||||
enumNames={enumNames}
|
||||
formData={formData}
|
||||
|
@ -443,14 +384,14 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
|
|||
title={title}
|
||||
label={uiOpt && 'label' in uiOpt ? uiOpt.label : ''}
|
||||
fieldName={key}
|
||||
onChange={handleSwitchChange}
|
||||
onChange={onChange}
|
||||
formData={formData}
|
||||
/>
|
||||
) : null}
|
||||
{widget === 'timezone' ? (
|
||||
<Timezone
|
||||
fieldName={key}
|
||||
onChange={handleSelectChange}
|
||||
onChange={onChange}
|
||||
formData={formData}
|
||||
/>
|
||||
) : null}
|
||||
|
@ -463,7 +404,7 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
|
|||
uiOpt && 'acceptType' in uiOpt ? uiOpt.acceptType : ''
|
||||
}
|
||||
fieldName={key}
|
||||
onChange={handleUploadChange}
|
||||
onChange={onChange}
|
||||
formData={formData}
|
||||
/>
|
||||
) : null}
|
||||
|
@ -475,7 +416,7 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
|
|||
rows={uiOpt && 'rows' in uiOpt ? uiOpt.rows : 3}
|
||||
className={uiOpt && 'className' in uiOpt ? uiOpt.className : ''}
|
||||
fieldName={key}
|
||||
onChange={handleInputChange}
|
||||
onChange={onChange}
|
||||
formData={formData}
|
||||
/>
|
||||
) : null}
|
||||
|
@ -486,7 +427,7 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
|
|||
uiOpt && 'placeholder' in uiOpt ? uiOpt.placeholder : ''
|
||||
}
|
||||
fieldName={key}
|
||||
onChange={handleInputChange}
|
||||
onChange={onChange}
|
||||
formData={formData}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
|
|
|
@ -5,9 +5,10 @@ import { useTranslation } from 'react-i18next';
|
|||
import QrCode from 'qrcode';
|
||||
|
||||
import { userCenterStore } from '@/stores';
|
||||
import { guard, getUserAgentType } from '@/utils';
|
||||
import { guard, getUaType, floppyNavigation } from '@/utils';
|
||||
import { USER_AGENT_NAMES } from '@/common/constants';
|
||||
|
||||
import { getLoginConf, checkLoginResult } from './wecom.service';
|
||||
import { getLoginConf, checkLoginResult } from './service';
|
||||
|
||||
let checkTimer: NodeJS.Timeout;
|
||||
const Index: FC = () => {
|
||||
|
@ -47,12 +48,14 @@ const Index: FC = () => {
|
|||
return;
|
||||
}
|
||||
getLoginConf().then((res) => {
|
||||
if (getUserAgentType() === 'wxwork') {
|
||||
window.location.replace(res?.redirect_url);
|
||||
if (getUaType() === USER_AGENT_NAMES.WeCom) {
|
||||
floppyNavigation.navigate(res?.redirect_url, {
|
||||
handler: 'replace',
|
||||
});
|
||||
} else {
|
||||
handleQrCode(res?.redirect_url);
|
||||
handleLoginResult(res?.key);
|
||||
}
|
||||
handleLoginResult(res?.key);
|
||||
});
|
||||
}, [agentName]);
|
||||
useEffect(() => {
|
||||
|
@ -60,7 +63,7 @@ const Index: FC = () => {
|
|||
clearTimeout(checkTimer);
|
||||
};
|
||||
}, []);
|
||||
if (/WeCom/i.test(agentName) && getUserAgentType() !== 'wxwork') {
|
||||
if (getUaType() !== USER_AGENT_NAMES.WeCom) {
|
||||
return (
|
||||
<Card className="text-center">
|
||||
<Card.Body>
|
|
@ -0,0 +1,28 @@
|
|||
import { memo } from 'react';
|
||||
import { Container, Col } from 'react-bootstrap';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { userCenterStore } from '@/stores';
|
||||
import { USER_AGENT_NAMES } from '@/common/constants';
|
||||
|
||||
import WeComAuth from './components/WeCom';
|
||||
|
||||
const Index = () => {
|
||||
const [searchParam] = useSearchParams();
|
||||
const { agent: ucAgent } = userCenterStore();
|
||||
let agentName = ucAgent?.agent_info.name || '';
|
||||
if (searchParam.get('agent_name')) {
|
||||
agentName = searchParam.get('agent_name') || '';
|
||||
}
|
||||
return (
|
||||
<Container style={{ paddingTop: '5rem', paddingBottom: '5rem' }}>
|
||||
<Col md={4} className="mx-auto">
|
||||
{USER_AGENT_NAMES.WeCom.toLowerCase() === agentName.toLowerCase() ? (
|
||||
<WeComAuth />
|
||||
) : null}
|
||||
</Col>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(Index);
|
|
@ -3,6 +3,7 @@ import { Container } from 'react-bootstrap';
|
|||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { userCenterStore } from '@/stores';
|
||||
import { USER_AGENT_NAMES } from '@/common/constants';
|
||||
|
||||
import WeCom from './components/WeCom';
|
||||
|
||||
|
@ -13,7 +14,13 @@ const Index = () => {
|
|||
if (searchParam.get('agent_name')) {
|
||||
agentName = searchParam.get('agent_name') || '';
|
||||
}
|
||||
return <Container>{/^WeCom/i.test(agentName) ? <WeCom /> : null}</Container>;
|
||||
return (
|
||||
<Container>
|
||||
{USER_AGENT_NAMES.WeCom.toLowerCase() === agentName.toLowerCase() ? (
|
||||
<WeCom />
|
||||
) : null}
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(Index);
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
userCenterStore,
|
||||
} from '@/stores';
|
||||
import { guard, handleFormError } from '@/utils';
|
||||
import { login, checkImgCode } from '@/services';
|
||||
import { login, checkImgCode, UcAgent } from '@/services';
|
||||
import { PicAuthCodeModal } from '@/components/Modal';
|
||||
|
||||
const Index: React.FC = () => {
|
||||
|
@ -28,8 +28,12 @@ const Index: React.FC = () => {
|
|||
const { user: storeUser, update: updateUser } = loggedUserInfoStore((_) => _);
|
||||
const loginSetting = loginSettingStore((state) => state.login);
|
||||
const ucAgent = userCenterStore().agent;
|
||||
const ucLoginRedirect =
|
||||
ucAgent?.enabled && ucAgent?.agent_info?.login_redirect_url;
|
||||
let ucAgentInfo: UcAgent['agent_info'] | undefined;
|
||||
if (ucAgent?.enabled && ucAgent?.agent_info) {
|
||||
ucAgentInfo = ucAgent.agent_info;
|
||||
}
|
||||
const canOriginalLogin =
|
||||
!ucAgentInfo || ucAgentInfo.enabled_original_user_system;
|
||||
|
||||
const [formData, setFormData] = useState<FormDataType>({
|
||||
e_mail: {
|
||||
|
@ -61,7 +65,7 @@ const Index: React.FC = () => {
|
|||
};
|
||||
|
||||
const getImgCode = () => {
|
||||
if (ucLoginRedirect) {
|
||||
if (!canOriginalLogin) {
|
||||
return;
|
||||
}
|
||||
checkImgCode({
|
||||
|
@ -171,14 +175,13 @@ const Index: React.FC = () => {
|
|||
return (
|
||||
<Container style={{ paddingTop: '4rem', paddingBottom: '5rem' }}>
|
||||
<WelcomeTitle />
|
||||
{ucLoginRedirect && step === 1 && (
|
||||
<Col className="mx-auto" md={4}>
|
||||
<PluginUcLogin />
|
||||
</Col>
|
||||
)}
|
||||
{step === 1 && !ucLoginRedirect && (
|
||||
{step === 1 && canOriginalLogin ? (
|
||||
<Col className="mx-auto" md={3}>
|
||||
<PluginOauth className="mb-5" />
|
||||
{ucAgentInfo ? (
|
||||
<PluginUcLogin className="mb-5" />
|
||||
) : (
|
||||
<PluginOauth className="mb-5" />
|
||||
)}
|
||||
<Form noValidate onSubmit={handleSubmit}>
|
||||
<Form.Group controlId="email" className="mb-3">
|
||||
<Form.Label>{t('email.label')}</Form.Label>
|
||||
|
@ -250,7 +253,7 @@ const Index: React.FC = () => {
|
|||
</div>
|
||||
)}
|
||||
</Col>
|
||||
)}
|
||||
) : null}
|
||||
|
||||
{step === 2 && <Unactivate visible={step === 2} />}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { FC } from 'react';
|
||||
import { Container, Row, Col, Button } from 'react-bootstrap';
|
||||
import { Container, Row, Col } from 'react-bootstrap';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
import { useParams, useSearchParams, Link } from 'react-router-dom';
|
||||
|
||||
import { usePageTags } from '@/hooks';
|
||||
import { Pagination, FormatTime, Empty } from '@/components';
|
||||
|
@ -73,12 +73,11 @@ const Personal: FC = () => {
|
|||
className="d-flex justify-content-start justify-content-md-end">
|
||||
{isSelf && (
|
||||
<div className="mb-3">
|
||||
<Button
|
||||
variant="outline-secondary"
|
||||
href="/users/settings/profile"
|
||||
className="btn">
|
||||
<Link
|
||||
className="btn btn-outline-secondary"
|
||||
to="/users/settings/profile">
|
||||
{t('edit_profile')}
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</Col>
|
||||
|
|
|
@ -2,28 +2,29 @@ import { memo, FC } from 'react';
|
|||
import { Button } from 'react-bootstrap';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { SvgIcon } from '@/components';
|
||||
import { userCenterStore } from '@/stores';
|
||||
|
||||
import WeComLogin from './WeCom';
|
||||
|
||||
const Index: FC = () => {
|
||||
interface Props {
|
||||
className?: classnames.Argument;
|
||||
}
|
||||
const Index: FC<Props> = ({ className }) => {
|
||||
const { t } = useTranslation('translation', { keyPrefix: 'plugins.oauth' });
|
||||
const ucAgent = userCenterStore().agent;
|
||||
const agentName = ucAgent?.agent_info?.name || '';
|
||||
const ucLoginRedirect =
|
||||
ucAgent?.enabled && ucAgent?.agent_info?.login_redirect_url;
|
||||
if (/WeCom/i.test(agentName)) {
|
||||
return <WeComLogin />;
|
||||
}
|
||||
|
||||
if (ucLoginRedirect) {
|
||||
return (
|
||||
<Button
|
||||
className="w-100"
|
||||
className={classnames('w-100', className)}
|
||||
variant="outline-secondary"
|
||||
href={ucAgent?.agent_info.login_redirect_url}>
|
||||
<SvgIcon base64={ucAgent?.agent_info.icon} />
|
||||
<span>{t('connect', { auth_name: ucAgent?.agent_info.name })}</span>
|
||||
<span>{t('connect', { auth_name: agentName })}</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -240,8 +240,8 @@ const routes: RouteNode[] = [
|
|||
page: 'pages/Users/OauthBindEmail',
|
||||
},
|
||||
{
|
||||
path: '/users/oauth',
|
||||
page: 'pages/Users/OauthCallback',
|
||||
path: '/users/auth-landing',
|
||||
page: 'pages/Users/AuthCallback',
|
||||
},
|
||||
{
|
||||
path: '/posts/:qid/timeline',
|
||||
|
@ -362,6 +362,10 @@ const routes: RouteNode[] = [
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/user-center/auth',
|
||||
page: 'pages/UserCenter/Auth',
|
||||
},
|
||||
{
|
||||
path: '/user-center/auth-failed',
|
||||
page: 'pages/UserCenter/AuthFailed',
|
||||
|
|
|
@ -14,6 +14,7 @@ export interface UcAgent {
|
|||
login_redirect_url: string;
|
||||
sign_up_redirect_url: string;
|
||||
control_center: UcAgentControl[];
|
||||
enabled_original_user_system: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import i18next from 'i18next';
|
||||
|
||||
import pattern from '@/common/pattern';
|
||||
import { USER_AGENT_NAMES } from '@/common/constants';
|
||||
|
||||
const Diff = require('diff');
|
||||
|
||||
|
@ -258,18 +259,17 @@ function base64ToSvg(base64: string) {
|
|||
|
||||
// Determine whether the user is in WeChat or Enterprise WeChat or DingTalk, and return the corresponding type
|
||||
|
||||
function getUserAgentType() {
|
||||
function getUaType() {
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
if (pattern.wxwork.test(ua)) {
|
||||
return 'wxwork';
|
||||
if (pattern.uaWeCom.test(ua)) {
|
||||
return USER_AGENT_NAMES.WeCom;
|
||||
}
|
||||
if (pattern.uaWeChat.test(ua)) {
|
||||
return USER_AGENT_NAMES.WeChat;
|
||||
}
|
||||
if (pattern.uaDingTalk.test(ua)) {
|
||||
return USER_AGENT_NAMES.DingTalk;
|
||||
}
|
||||
// if (pattern.wx.test(ua)) {
|
||||
// return 'weixin';
|
||||
// }
|
||||
|
||||
// if (pattern.dingtalk.test(ua)) {
|
||||
// return 'dingtalk';
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -289,5 +289,5 @@ export {
|
|||
handleFormError,
|
||||
diffText,
|
||||
base64ToSvg,
|
||||
getUserAgentType,
|
||||
getUaType,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue