update api fields and add sso
This commit is contained in:
parent
b288cad771
commit
4d917a7e41
@ -50,7 +50,10 @@
|
|||||||
.money-format{
|
.money-format{
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
.btn-auth-login{
|
||||||
|
box-sizing: border-box;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
.page-content-container {
|
.page-content-container {
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
width: 1400px;
|
width: 1400px;
|
||||||
|
@ -28,7 +28,7 @@ const SearchForm: React.FC<SearchFormProps> = (props) => {
|
|||||||
params.end_date = dayjs(value.dateRange[1]).format('YYYY-MM-DD');
|
params.end_date = dayjs(value.dateRange[1]).format('YYYY-MM-DD');
|
||||||
}
|
}
|
||||||
if (value.student_number) {
|
if (value.student_number) {
|
||||||
params.student_name = value.student_number;
|
params.student_number = value.student_number;
|
||||||
}
|
}
|
||||||
// 对账状态
|
// 对账状态
|
||||||
if (value.apply_status) {
|
if (value.apply_status) {
|
||||||
@ -48,16 +48,16 @@ const SearchForm: React.FC<SearchFormProps> = (props) => {
|
|||||||
// 根据语言变化更新订单状态options
|
// 根据语言变化更新订单状态options
|
||||||
const billStatusOptions = useMemo(() => {
|
const billStatusOptions = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{value: `${i18n.language}pending`, label: t('bill.pay_status_pending')},
|
{value: `PENDING`, label: t('bill.pay_status_pending')},
|
||||||
{value: 'paid', label: t('bill.pay_status_paid')},
|
{value: 'PAID', label: t('bill.pay_status_paid')},
|
||||||
{value: 'canceled', label: t('bill.pay_status_canceled')}
|
{value: 'CANCELLED', label: t('bill.pay_status_canceled')}
|
||||||
]
|
]
|
||||||
}, [i18n.language])
|
}, [i18n.language])
|
||||||
// 根据语言变化更新对账状态options
|
// 根据语言变化更新对账状态options
|
||||||
const applyStatusOptions = useMemo(() => {
|
const applyStatusOptions = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{value: 'pending', label: t('bill.reconciliation_status_pending')},
|
{value: 'UNCHECKED', label: t('bill.reconciliation_status_pending')},
|
||||||
{value: 'submitted', label: t('bill.reconciliation_status_submitted')}
|
{value: 'CHECKED', label: t('bill.reconciliation_status_submitted')}
|
||||||
]
|
]
|
||||||
}, [i18n.language])
|
}, [i18n.language])
|
||||||
return (<Card style={{marginBottom: 20}}>
|
return (<Card style={{marginBottom: 20}}>
|
||||||
@ -81,9 +81,9 @@ const SearchForm: React.FC<SearchFormProps> = (props) => {
|
|||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
<Form.Select showClear field="pay_method" label={t('bill.title_pay_method')}
|
<Form.Select showClear field="pay_method" label={t('bill.title_pay_method')}
|
||||||
placeholder={t('base.please_select')} style={{width: '100%'}}>
|
placeholder={t('base.please_select')} style={{width: '100%'}}>
|
||||||
<Form.Select.Option value="operate">AsiaPay</Form.Select.Option>
|
<Form.Select.Option value="ASIAPAY">AsiaPay</Form.Select.Option>
|
||||||
<Form.Select.Option value="rd">FlyWire</Form.Select.Option>
|
<Form.Select.Option value="FLYWIRE">FlyWire</Form.Select.Option>
|
||||||
<Form.Select.Option value="pm">PPS</Form.Select.Option>
|
<Form.Select.Option value="PPS">PPS</Form.Select.Option>
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import Loader from "@/components/loader";
|
import Loader from "@/components/loader";
|
||||||
import React, {createContext, useEffect, useReducer} from "react";
|
import React, {createContext, useEffect, useReducer} from "react";
|
||||||
|
import {auth, getUserInfo} from "@/service/api/user.ts";
|
||||||
|
import {setAuthToken} from "@/hooks/useAuth.ts";
|
||||||
|
|
||||||
|
|
||||||
const AuthContext = createContext<AuthContextType | null>(null)
|
const AuthContext = createContext<AuthContextType | null>(null)
|
||||||
@ -43,45 +45,69 @@ export const AuthProvider = ({children}: { children: React.ReactNode }) => {
|
|||||||
|
|
||||||
// MOCK INIT DATA
|
// MOCK INIT DATA
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
setTimeout(() => {
|
getUserInfo().then(user => {
|
||||||
|
dispatch({
|
||||||
|
action: 'init',
|
||||||
|
payload: {
|
||||||
|
isInitialized: true,
|
||||||
|
isLoggedIn: !!user,
|
||||||
|
user
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).finally(() => {
|
||||||
dispatch({
|
dispatch({
|
||||||
payload: {
|
payload: {
|
||||||
isInitialized: true,
|
isInitialized: true,
|
||||||
isLoggedIn: true,
|
|
||||||
user: {
|
|
||||||
id: 1,
|
|
||||||
nickname: 'TU',
|
|
||||||
department: 'root',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, 300)
|
})
|
||||||
return 'initialized'
|
return 'initialized'
|
||||||
}
|
}
|
||||||
// 登录
|
// 登录
|
||||||
const login = async () => {
|
const login = async (code: string, state: string) => {
|
||||||
|
const user = await auth(code, state)
|
||||||
|
// 保存token
|
||||||
|
setAuthToken(user.token, user.exp)
|
||||||
|
//
|
||||||
|
dispatch({
|
||||||
|
action: 'login',
|
||||||
|
payload: {
|
||||||
|
isLoggedIn: true,
|
||||||
|
user
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 登出
|
||||||
|
const logout = async () => {
|
||||||
|
setAuthToken(null)
|
||||||
|
dispatch({
|
||||||
|
action: 'logout',
|
||||||
|
payload: {
|
||||||
|
isLoggedIn: false,
|
||||||
|
user: null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const mockLogin = async () => {
|
||||||
|
setAuthToken('test-123123', Date.now() + 36000 * 1000)
|
||||||
dispatch({
|
dispatch({
|
||||||
action: 'login',
|
action: 'login',
|
||||||
payload: {
|
payload: {
|
||||||
isLoggedIn: true,
|
isLoggedIn: true,
|
||||||
user: {
|
user: {
|
||||||
id: 1,
|
id: 1,
|
||||||
nickname: 'TU',
|
token: 'test-123123',
|
||||||
department: 'root',
|
email: 'test@qq.com',
|
||||||
|
exp: 1,
|
||||||
|
iat: 1,
|
||||||
|
iss: "Hong Kong Chu Hai College",
|
||||||
|
nbf: 1,
|
||||||
|
type: "id_token",
|
||||||
|
username: 'test-123123',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 登出
|
|
||||||
const logout = async () => {
|
|
||||||
dispatch({
|
|
||||||
action: 'logout',
|
|
||||||
payload: {
|
|
||||||
isLoggedIn: false,
|
|
||||||
user: null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
init().then(console.log)
|
init().then(console.log)
|
||||||
}, [])
|
}, [])
|
||||||
@ -92,7 +118,8 @@ export const AuthProvider = ({children}: { children: React.ReactNode }) => {
|
|||||||
}
|
}
|
||||||
return (<AuthContext.Provider value={{
|
return (<AuthContext.Provider value={{
|
||||||
...state,
|
...state,
|
||||||
login, logout
|
login, logout,
|
||||||
|
mockLogin
|
||||||
}}>{children}</AuthContext.Provider>)
|
}}>{children}</AuthContext.Provider>)
|
||||||
}
|
}
|
||||||
export default AuthContext
|
export default AuthContext
|
@ -1,4 +1,4 @@
|
|||||||
import { useContext } from 'react';
|
import {useContext} from 'react';
|
||||||
|
|
||||||
// auth provider
|
// auth provider
|
||||||
import AuthContext from '@/contexts/auth';
|
import AuthContext from '@/contexts/auth';
|
||||||
@ -13,4 +13,30 @@ const useAuth = () => {
|
|||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setAuthToken = (token: string | null, expiry_time = -1) => {
|
||||||
|
if (!token) {
|
||||||
|
localStorage.removeItem(AppConfig.AUTH_TOKEN_KEY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
localStorage.setItem(AppConfig.AUTH_TOKEN_KEY, JSON.stringify({
|
||||||
|
token, expiry_time
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getAuthToken = () => {
|
||||||
|
const data = localStorage.getItem(AppConfig.AUTH_TOKEN_KEY);
|
||||||
|
if (!data) return;
|
||||||
|
try {
|
||||||
|
const {token, expiry_time} = JSON.parse(data) as { token: string, expiry_time: number };
|
||||||
|
if (expiry_time != -1 && expiry_time < Date.now()) {
|
||||||
|
localStorage.removeItem(AppConfig.AUTH_TOKEN_KEY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
} catch (_e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export default useAuth;
|
export default useAuth;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"student_number": "学号"
|
"student_number": "学号"
|
||||||
},
|
},
|
||||||
"bill": {
|
"bill": {
|
||||||
"bill_date": "日期",
|
"bill_date": "支付日期",
|
||||||
"bill_number": "账单编号",
|
"bill_number": "账单编号",
|
||||||
"cancel": "作废",
|
"cancel": "作废",
|
||||||
"cancel_confirm": "确定作废此账单",
|
"cancel_confirm": "确定作废此账单",
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"student_number": "學號"
|
"student_number": "學號"
|
||||||
},
|
},
|
||||||
"bill": {
|
"bill": {
|
||||||
"bill_date": "日期",
|
"bill_date": "支付日期",
|
||||||
"bill_number": "帳單編號",
|
"bill_number": "帳單編號",
|
||||||
"cancel": "作廢",
|
"cancel": "作廢",
|
||||||
"cancel_confirm": "確定作廢此帳單",
|
"cancel_confirm": "確定作廢此帳單",
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import {Button, Space, Typography} from "@douyinfe/semi-ui";
|
import {Button, Space, Spin, Typography} from "@douyinfe/semi-ui";
|
||||||
import {useTranslation} from 'react-i18next';
|
import {useTranslation} from 'react-i18next';
|
||||||
import useConfig from "@/hooks/useConfig.ts";
|
import {useEffect} from "react";
|
||||||
|
import {useSetState} from "ahooks";
|
||||||
import styled from "@emotion/styled";
|
import styled from "@emotion/styled";
|
||||||
|
import {useNavigate, useSearchParams} from "react-router-dom";
|
||||||
|
|
||||||
|
import useConfig from "@/hooks/useConfig.ts";
|
||||||
import AppLogo from "@/assets/AppLogo";
|
import AppLogo from "@/assets/AppLogo";
|
||||||
import {useNavigate} from "react-router-dom";
|
|
||||||
import useAuth from "@/hooks/useAuth.ts";
|
import useAuth from "@/hooks/useAuth.ts";
|
||||||
|
import {getAppUrl} from "@/hooks/useAppUrl";
|
||||||
|
|
||||||
|
|
||||||
const LoginContainer = styled.div({
|
const LoginContainer = styled.div({
|
||||||
@ -22,14 +26,49 @@ const SubmitContainer = styled.div({
|
|||||||
width: 300,
|
width: 300,
|
||||||
margin: '70px auto 20px'
|
margin: '70px auto 20px'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const LoginURL = getAppUrl() + '/login?action=auth'
|
||||||
const AuthLogin = () => {
|
const AuthLogin = () => {
|
||||||
const { login } = useAuth();
|
const {login, mockLogin} = useAuth();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [state, setState] = useSetState({
|
||||||
|
showLogin: false,
|
||||||
|
loading: false
|
||||||
|
})
|
||||||
|
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const {appName} = useConfig()
|
const {appName} = useConfig()
|
||||||
|
const [query] = useSearchParams()
|
||||||
|
|
||||||
const showDashboard = ()=> {
|
useEffect(() => {
|
||||||
login().then(()=>{
|
const code = query.get('code'),
|
||||||
|
state = query.get('state');
|
||||||
|
|
||||||
|
if (query.get('action') == 'auth' && state && code) {
|
||||||
|
setState({loading: true})
|
||||||
|
// 授权回调
|
||||||
|
login(code, state).then(() => {
|
||||||
|
navigate('/dashboard')
|
||||||
|
}).catch(() => {
|
||||||
|
// 获取登录凭证失败 重新显示登录按钮
|
||||||
|
setTimeout(() => {
|
||||||
|
setState({showLogin: true})
|
||||||
|
}, 2000)
|
||||||
|
}).finally(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
setState({loading: false})
|
||||||
|
}, 2000)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 正常登录 - 显示登录按钮
|
||||||
|
setState({
|
||||||
|
showLogin: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleMockLogin = () => {
|
||||||
|
mockLogin().then(() => {
|
||||||
navigate('/dashboard')
|
navigate('/dashboard')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -42,10 +81,19 @@ const AuthLogin = () => {
|
|||||||
</Space>
|
</Space>
|
||||||
</LogoContainer>
|
</LogoContainer>
|
||||||
<SubmitContainer>
|
<SubmitContainer>
|
||||||
<Button theme='solid' type='primary' block onClick={showDashboard}>{t('login.submit')}</Button>
|
{state.loading && <Space>
|
||||||
<Button style={{marginTop:10}} theme='solid' type='primary' block onClick={()=>{
|
<Spin/><span>Authing ...</span>
|
||||||
navigate('/pay')
|
</Space>}
|
||||||
}}>支付</Button>
|
{state.showLogin && <div style={{marginTop: 5}}>
|
||||||
|
<a
|
||||||
|
className="btn-auth-login semi-button semi-button-primary semi-button-block"
|
||||||
|
href={`${AppConfig.SSO_AUTH_URL}/authorize?response_type=code&scope=openid%20profile%20email&client_id=${AppConfig.SSO_AUTH_CLIENT_KEY}&state=${Date.now()}&redirect_uri=${encodeURIComponent(LoginURL)}`}
|
||||||
|
>
|
||||||
|
<span className="semi-button-content" x-semi-prop="children">{t('login.submit')}</span>
|
||||||
|
</a>
|
||||||
|
<Button theme='solid' type='warning' block onClick={handleMockLogin} style={{marginTop: 5}}>MOCK
|
||||||
|
LOGIN</Button>
|
||||||
|
</div>}
|
||||||
</SubmitContainer>
|
</SubmitContainer>
|
||||||
</LoginContainer>)
|
</LoginContainer>)
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ const BillQuery = () => {
|
|||||||
<Button size={'small'} theme={'solid'} type={'primary'}>{t('bill.cancel')}</Button>
|
<Button size={'small'} theme={'solid'} type={'primary'}>{t('bill.cancel')}</Button>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
<Button onClick={() => setShowBill(bill)} size={'small'} theme={'solid'} type={'primary'}>{t('base.qr-code')}</Button>
|
<Button onClick={() => setShowBill(bill)} size={'small'} theme={'solid'} type={'primary'}>{t('base.qr-code')}</Button>
|
||||||
|
{AppMode == 'development' && <a href={`/pay?bill=${bill.id}`} target={'_blank'}>Payment</a>}
|
||||||
</>}
|
</>}
|
||||||
{
|
{
|
||||||
bill.status == BillStatus.PAID
|
bill.status == BillStatus.PAID
|
||||||
|
@ -40,8 +40,8 @@ const BillReconciliation = () => {
|
|||||||
|
|
||||||
<SearchForm searchHeader={(
|
<SearchForm searchHeader={(
|
||||||
<Tabs className={'no-border'} onChange={(apply_status) => setBillQueryParams({apply_status})}>
|
<Tabs className={'no-border'} onChange={(apply_status) => setBillQueryParams({apply_status})}>
|
||||||
<TabPane tab={<span>{t('bill.reconciliation_status_pending')}</span>} itemKey="pending"/>
|
<TabPane tab={<span>{t('bill.reconciliation_status_pending')}</span>} itemKey="UNCHECKED"/>
|
||||||
<TabPane tab={<span>{t('bill.reconciliation_status_submitted')}</span>} itemKey="confirmed"/>
|
<TabPane tab={<span>{t('bill.reconciliation_status_submitted')}</span>} itemKey="CHECKED"/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
)} loading={loading} onSearch={setBillQueryParams}/>
|
)} loading={loading} onSearch={setBillQueryParams}/>
|
||||||
<BillList
|
<BillList
|
||||||
|
@ -28,6 +28,7 @@ const HeaderUserProfile = styled.div({
|
|||||||
export const HeaderUserAvatar = () => {
|
export const HeaderUserAvatar = () => {
|
||||||
const {t} = useTranslation()
|
const {t} = useTranslation()
|
||||||
const {user, logout} = useAuth()
|
const {user, logout} = useAuth()
|
||||||
|
// const UserAvatar = () => (<Avatar color="orange" size="small">{user?.username.substring(0, 3)}</Avatar>)
|
||||||
return (<Dropdown
|
return (<Dropdown
|
||||||
position={'bottomRight'}
|
position={'bottomRight'}
|
||||||
trigger={'click'}
|
trigger={'click'}
|
||||||
@ -35,11 +36,12 @@ export const HeaderUserAvatar = () => {
|
|||||||
<>
|
<>
|
||||||
<HeaderUserProfile>
|
<HeaderUserProfile>
|
||||||
<Space>
|
<Space>
|
||||||
<Avatar color="orange" size="small">{user?.nickname}</Avatar>
|
<Avatar color="orange" size="small">{user?.username.substring(0, 3)}</Avatar>
|
||||||
<div>
|
<div>
|
||||||
<Typography.Title heading={6}>{user?.nickname}</Typography.Title>
|
<Typography.Title heading={6}>{user?.username}</Typography.Title>
|
||||||
<Typography.Text type="quaternary"
|
<Typography.Text
|
||||||
size={'small'}>DEPT:{user?.department?.toUpperCase()}</Typography.Text>
|
type="quaternary"
|
||||||
|
size={'small'}>{user?.iss?.toUpperCase()}</Typography.Text>
|
||||||
</div>
|
</div>
|
||||||
</Space>
|
</Space>
|
||||||
</HeaderUserProfile>
|
</HeaderUserProfile>
|
||||||
@ -51,7 +53,7 @@ export const HeaderUserAvatar = () => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
||||||
<Avatar color="orange" size="small">{user?.nickname}</Avatar>
|
<Avatar color="orange" size="small">{user?.username.substring(0, 3)}</Avatar>
|
||||||
</Dropdown>)
|
</Dropdown>)
|
||||||
}
|
}
|
||||||
export const CommonHeader: React.FC<CommonHeaderProps> = ({children, title, rightExtra}) => {
|
export const CommonHeader: React.FC<CommonHeaderProps> = ({children, title, rightExtra}) => {
|
||||||
@ -97,7 +99,7 @@ type LayoutProps = {
|
|||||||
|
|
||||||
const LayoutContentContainer = styled.div({
|
const LayoutContentContainer = styled.div({
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
marginTop:20
|
marginTop: 20
|
||||||
})
|
})
|
||||||
export const BaseLayout: React.FC<LayoutProps> = ({children}) => {
|
export const BaseLayout: React.FC<LayoutProps> = ({children}) => {
|
||||||
const {t} = useTranslation()
|
const {t} = useTranslation()
|
||||||
|
@ -47,9 +47,9 @@ export function cancelBill(id: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function confirmBills(bill_ids: number[]) {
|
export function confirmBills(bill_ids: number[]) {
|
||||||
return post(`/api/bills/apply`, {bill_ids})
|
return post(`/bills/apply`, {bill_ids})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateBillPaymentSuccess(billId: number, merchant_ref: string,peyment_channel:string) {
|
export function updateBillPaymentSuccess(billId: number, merchant_ref: string,payment_channel:string) {
|
||||||
return post(`api/bills/${billId}/finish`, {merchant_ref,peyment_channel})
|
return post(`/bills/${billId}/finish`, {merchant_ref,payment_channel})
|
||||||
}
|
}
|
||||||
|
14
src/service/api/user.ts
Normal file
14
src/service/api/user.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import {get} from "@/service/request.ts";
|
||||||
|
|
||||||
|
export function getUserInfo() {
|
||||||
|
return get<UserProfile>('/userinfo')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 sso 返回的code、state换取登录凭证或用户信息
|
||||||
|
* @param code
|
||||||
|
* @param state
|
||||||
|
*/
|
||||||
|
export function auth(code:string,state:string){
|
||||||
|
return get<UserProfile>('/auth', {code, state})
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import {stringify} from 'qs'
|
import {stringify} from 'qs'
|
||||||
import {BizError} from './types';
|
import {BizError} from './types';
|
||||||
|
import {getAuthToken} from "@/hooks/useAuth.ts";
|
||||||
|
|
||||||
const JSON_FORMAT: string = 'application/json';
|
const JSON_FORMAT: string = 'application/json';
|
||||||
const REQUEST_TIMEOUT = 300000; // 超时时长5min
|
const REQUEST_TIMEOUT = 300000; // 超时时长5min
|
||||||
@ -14,7 +15,7 @@ const Axios = axios.create({
|
|||||||
|
|
||||||
// 请求前拦截
|
// 请求前拦截
|
||||||
Axios.interceptors.request.use(config => {
|
Axios.interceptors.request.use(config => {
|
||||||
const token = localStorage.getItem('payment_front_token');
|
const token = getAuthToken();
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers['Authorization'] = `Bearer ${token}`;
|
config.headers['Authorization'] = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
|
13
src/types/auth.d.ts
vendored
13
src/types/auth.d.ts
vendored
@ -1,7 +1,13 @@
|
|||||||
declare type UserProfile = {
|
declare type UserProfile = {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
nickname: string;
|
token: string;
|
||||||
department: string;
|
email: string;
|
||||||
|
exp: number;
|
||||||
|
iat: number;
|
||||||
|
iss: string;
|
||||||
|
nbf: number;
|
||||||
|
type: string;
|
||||||
|
username: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare interface AuthProps {
|
declare interface AuthProps {
|
||||||
@ -16,5 +22,6 @@ declare type AuthContextType = {
|
|||||||
isInitialized?: boolean;
|
isInitialized?: boolean;
|
||||||
user?: UserProfile | null | undefined;
|
user?: UserProfile | null | undefined;
|
||||||
logout: () => Promise<void>;
|
logout: () => Promise<void>;
|
||||||
login: () => Promise<void>;
|
mockLogin: () => Promise<void>;
|
||||||
|
login: (code:string,state:string) => Promise<void>;
|
||||||
};
|
};
|
2
src/types/bill.d.ts
vendored
2
src/types/bill.d.ts
vendored
@ -21,7 +21,7 @@ declare type BillQueryParam = {
|
|||||||
page_number:int;
|
page_number:int;
|
||||||
status:string;
|
status:string;
|
||||||
apply_status:string;
|
apply_status:string;
|
||||||
student_name:string;
|
student_number:string;
|
||||||
payment_method:string;
|
payment_method:string;
|
||||||
start_date:string;
|
start_date:string;
|
||||||
end_date:string;
|
end_date:string;
|
||||||
|
0
src/types/user.d.ts
vendored
Normal file
0
src/types/user.d.ts
vendored
Normal file
7
src/vite-env.d.ts
vendored
7
src/vite-env.d.ts
vendored
@ -12,7 +12,14 @@ declare const AppConfig: {
|
|||||||
API_PREFIX: string;
|
API_PREFIX: string;
|
||||||
// flywire 支付网关
|
// flywire 支付网关
|
||||||
FIY_WIRE_GATEWAY: string;
|
FIY_WIRE_GATEWAY: string;
|
||||||
|
// sso 认证地址
|
||||||
|
SSO_AUTH_URL: string;
|
||||||
|
// sso 认证客户端 key
|
||||||
|
SSO_AUTH_CLIENT_KEY: string;
|
||||||
|
// 登录凭证 token key
|
||||||
|
AUTH_TOKEN_KEY: string;
|
||||||
};
|
};
|
||||||
|
declare const AppMode: 'test' | 'production' | 'development';
|
||||||
|
|
||||||
declare type BasicComponentProps = {
|
declare type BasicComponentProps = {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
@ -13,7 +13,11 @@ export default defineConfig(({mode}) => {
|
|||||||
SITE_URL: process.env.APP_SITE_URL || null,
|
SITE_URL: process.env.APP_SITE_URL || null,
|
||||||
API_PREFIX: process.env.APP_API_PREFIX || '/api',
|
API_PREFIX: process.env.APP_API_PREFIX || '/api',
|
||||||
FIY_WIRE_GATEWAY: process.env.FIY_WIRE_GATEWAY || 'https://gateway.flywire.com/v1/transfers',
|
FIY_WIRE_GATEWAY: process.env.FIY_WIRE_GATEWAY || 'https://gateway.flywire.com/v1/transfers',
|
||||||
|
SSO_AUTH_URL: process.env.SSO_AUTH_URL || 'https://portal.chuhai.edu.hk',
|
||||||
|
SSO_AUTH_CLIENT_KEY: process.env.AUTH_CLIENT_KEY || '',
|
||||||
|
AUTH_TOKEN_KEY: process.env.AUTH_TOKEN_KEY || 'payment-auth-token',
|
||||||
}),
|
}),
|
||||||
|
AppMode: JSON.stringify(mode)
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user