diff --git a/package.json b/package.json index d32459a..1ee26a5 100644 --- a/package.json +++ b/package.json @@ -51,5 +51,6 @@ "eslint-plugin-react-refresh": "^0.4.6", "typescript": "^5.2.2", "vite": "^5.2.0" - } + }, + "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72" } diff --git a/src/components/bill/bill-detail-items.tsx b/src/components/bill/bill-detail-items.tsx index 82def98..e9e2a49 100644 --- a/src/components/bill/bill-detail-items.tsx +++ b/src/components/bill/bill-detail-items.tsx @@ -20,8 +20,8 @@ const BillDetailItems = (prop: { bill: BillModel }) => { } title={t('manual.bill_type')} value={billType}/> } title={t('manual.student_number')} value={prop.bill.student_number || prop.bill.application_number}/> } title={t('bill.title_student_name')} - value={`${prop.bill.student_english_name}/${prop.bill.student_chinese_name}`}/> - } title={'Email'} value={prop.bill.student_email}/> + value={`${prop.bill.student_english_name||'-'}${prop.bill.student_chinese_name?' / '+ prop.bill.student_chinese_name : ''}`}/> + } title={'Email'} value={prop.bill.student_email||'-'}/> } title={t('manual.amount')} value={}/> ) } diff --git a/src/components/bill/detail.tsx b/src/components/bill/detail.tsx index a631646..6cc5645 100644 --- a/src/components/bill/detail.tsx +++ b/src/components/bill/detail.tsx @@ -23,7 +23,7 @@ const BillDetail:BasicComponent = ({bill,onCancel})=>{
-
{t('manual.exp_time')} {dayjs(bill.expiration_time).format('HH:mm')}
+
{t('manual.exp_time')} {dayjs(bill.expiration_time).format('YYYY-MM-DD HH:mm')}
diff --git a/src/components/bill/list.tsx b/src/components/bill/list.tsx index a0645a3..3e92cf8 100644 --- a/src/components/bill/list.tsx +++ b/src/components/bill/list.tsx @@ -1,12 +1,13 @@ import {Table, Typography} from "@douyinfe/semi-ui"; import {ColumnProps} from "@douyinfe/semi-ui/lib/es/table"; -import React, {useMemo} from "react"; +import React, {useMemo, useState} from "react"; import {useTranslation} from "react-i18next"; import dayjs from "dayjs"; import MoneyFormat from "@/components/money-format.tsx"; import {Card} from "@/components/card"; import './bill.less' +import {BillStatus} from "@/service/types.ts"; type BillListProps = { type: 'query' | 'reconciliation'; @@ -20,6 +21,31 @@ type BillListProps = { export const BillList: React.FC = (props) => { const {t, i18n} = useTranslation() + const [currentTotalAmount,setCurrentTotalAmount] = useState(0) + + + const billStatusText = (billStatus: string) => { + switch (billStatus) { + case 'PENDING': + return t('bill.pay_status_pending') + case 'PAID': + return t('bill.pay_status_paid') + case 'CANCELLED': + return t('bill.pay_status_canceled') + default: + return billStatus + } + } + const applyStatusText = (status:string) => { + switch (status) { + case 'UNCHECKED': + return t('bill.reconciliation_status_pending') + case 'CHECKED': + return t('bill.reconciliation_status_submitted') + default: + return status + } + } const columns = useMemo[]>(() => { const cols: ColumnProps[] = [ @@ -138,7 +164,7 @@ export const BillList: React.FC = (props) => { title: t('bill.title_bill_status'), dataIndex: 'status', width: 150, - // render: value => dayjs(value).format('YYYY-MM-DD'), + render: value => billStatusText(value), }, ] if (props.type != 'reconciliation') { @@ -146,7 +172,7 @@ export const BillList: React.FC = (props) => { title: t('bill.title_reconciliation_status'), dataIndex: 'apply_status', width: 150, - // render: value => dayjs(value).format('YYYY-MM-DD'), + render: value => applyStatusText(value), }) } if (props.operationRender) { @@ -161,10 +187,20 @@ export const BillList: React.FC = (props) => { return cols; }, [props.operationRender, props.type, i18n.language]); - const currentTotalAmount = useMemo(() => { - // 计算当前列表总金额 - return props.source?.list.map(s => Number(s.amount)).reduce((s, c) => (s + c), 0) - }, [props.source]) + const isExpired = (bill: BillModel) => { + return bill.status == BillStatus.PENDING && dayjs(bill.expiration_time).isBefore(Date.now()) + } + const currentList = useMemo(()=>{ + const originList = props.source?.list || []; + originList.forEach(s => { + if(isExpired(s)){ + s.status = BillStatus.EXPIRED; + } + }) + const _total = originList.map(s=>Number(s.amount)).reduce((s, c) => (s + c), 0) + setCurrentTotalAmount(_total) + return originList; + },[props.source]) return = (props) => { bordered columns={columns} - dataSource={props.source?.list} + dataSource={currentList} rowKey={'id'} pagination={{ currentPage: props.source?.pagination.current, diff --git a/src/components/bill/search-form.tsx b/src/components/bill/search-form.tsx index a3e1d47..a08d92b 100644 --- a/src/components/bill/search-form.tsx +++ b/src/components/bill/search-form.tsx @@ -74,16 +74,16 @@ const SearchForm: React.FC = (props) => { onSubmit={formSubmit}> - - - diff --git a/src/contexts/auth/index.tsx b/src/contexts/auth/index.tsx index 698b91a..db47e7b 100644 --- a/src/contexts/auth/index.tsx +++ b/src/contexts/auth/index.tsx @@ -53,8 +53,6 @@ export const AuthProvider = ({children}: { children: React.ReactNode }) => { isLoggedIn: !!user, user:{ ...user, - // TODO 等待接口返回 - department:'root' } } }) @@ -71,7 +69,7 @@ export const AuthProvider = ({children}: { children: React.ReactNode }) => { const login = async (code: string, state: string) => { const user = await auth(code, state) // 保存token - setAuthToken(user.token, user.exp) + setAuthToken(user.token, user.expiration_time?(new Date(user.expiration_time)).getTime():-1); // dispatch({ action: 'login', @@ -79,8 +77,6 @@ export const AuthProvider = ({children}: { children: React.ReactNode }) => { isLoggedIn: true, user:{ ...user, - // TODO 等待接口返回 - department:'root' } } }) @@ -105,6 +101,7 @@ export const AuthProvider = ({children}: { children: React.ReactNode }) => { user: { id: 1, token: 'test-123123', + expiration_time: '', email: 'test@qq.com', department: 'root', exp: 1, @@ -125,7 +122,7 @@ export const AuthProvider = ({children}: { children: React.ReactNode }) => { user:{ ...state.user, ...user - } as any, + } as never, } }) diff --git a/src/pages/bill/external_create.tsx b/src/pages/bill/external_create.tsx index 5084d44..8f86e23 100644 --- a/src/pages/bill/external_create.tsx +++ b/src/pages/bill/external_create.tsx @@ -4,11 +4,14 @@ import {useSetState} from "ahooks"; import {useEffect} from "react"; import {createExternalBill} from "@/service/api/bill.ts"; import {IconLoading} from "@/components/icons"; +import {FailIcon} from "@/assets/images/pay/fail.tsx"; +import {PayLogo} from "@/pages/pay/component"; // 获取必填参数 const RequiredParams = [ // 'application_number','student_number', 可以不设置 - 'source', 'amount', + 'source', + 'amount', 'program_code', 'intake_year', 'intake_semester' @@ -36,39 +39,41 @@ const ExternalCreate = () => { setState({loading: false}) navigate(`/pay?bill=${ret.id}`, {replace: true}) }).catch(() => { - setState({loading: false, 'error': 'create pay order error'}) + setState({loading: false, 'error': 'create pay order failed'}) }) } useEffect(() => { if (searchParams) { const paramsContent = searchParams.get('params'); if (!paramsContent) { - return setState({error: 'params error'}) + return setState({error: 'params error',loading: false}) } + const params: ExternalCreateParamsType = JSON.parse(paramsContent); for (let i = 0; i < RequiredParams.length; i++) { const key = RequiredParams[i]; if (!params[key]) { - return setState({error: 'params error: require ' + key}) + return setState({error: 'params error: require ' + key,loading: false}) } - params[key] = searchParams.get(key) } if (!params.application_number && !params.student_number) { - return setState({error: 'params error: require application_number or student_number'}) + return setState({error: 'params error: require application_number or student_number',loading: false}) } if (!params.details || params.details.length == 0) { - return setState({error: 'params error: require detail'}) + return setState({error: 'params error: require detail',loading: false}) } createBill(params) return; } }, [searchParams]) return (
+ {state.loading &&
} {state.error &&
+

{state.error}

}
) diff --git a/src/pages/pay/index.tsx b/src/pages/pay/index.tsx index ae357a5..a1b7e58 100644 --- a/src/pages/pay/index.tsx +++ b/src/pages/pay/index.tsx @@ -83,7 +83,7 @@ const PayIndex = () => {
Bill Number: - {bill.application_number || bill.student_number} - {bill.student_english_name}/{bill.student_chinese_name} + {bill.application_number || bill.student_number} - {bill.student_english_name} / {bill.student_chinese_name}
Bill ID: @@ -91,7 +91,7 @@ const PayIndex = () => {
-
Your Email: {bill.student_email}
+ {bill.student_email &&
Your Email: {bill.student_email}
}
{ payChannel == 'asia_pay' && } diff --git a/src/service/types.ts b/src/service/types.ts index af6c526..220f253 100644 --- a/src/service/types.ts +++ b/src/service/types.ts @@ -16,6 +16,8 @@ export class BizError extends Error { export enum BillStatus { PENDING= 'PENDING', + // 已过期 + EXPIRED = 'EXPIRED', PAID = 'PAID', CANCELED = 'CANCELED', } diff --git a/src/types/auth.d.ts b/src/types/auth.d.ts index dcef3c7..e987199 100644 --- a/src/types/auth.d.ts +++ b/src/types/auth.d.ts @@ -5,6 +5,7 @@ declare type UserProfile = { username: string; department: string; exp: number; + expiration_time: string; iat: number; iss: string; nbf: number; diff --git a/vite.config.ts b/vite.config.ts index d0b7f9b..2f427ce 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -14,7 +14,7 @@ export default defineConfig(({mode}) => { API_PREFIX: process.env.APP_API_PREFIX || '/api', 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 || 'test_client_id', + SSO_AUTH_CLIENT_KEY: process.env.AUTH_CLIENT_KEY || 'payment', AUTH_TOKEN_KEY: process.env.AUTH_TOKEN_KEY || 'payment-auth-token', }), AppMode: JSON.stringify(mode) @@ -28,7 +28,7 @@ export default defineConfig(({mode}) => { port:10086, proxy: { '/api': { - target: 'http://43.136.175.109', // + target: 'https://test-payment-be.hkchc.team', // changeOrigin: true, //rewrite: (path) => path.replace(/^\/api/, '') }