{it.bill_type}
-
Total Amount:
+
Total Amount:
{state.billTypeList.map((item, index) => {
- return (
-
+ return (
+
+
-
- onChange(v,index,'amount')} style={{width: 120}}/>
-
-
-
)
+
+ onChange(String(v), index, 'amount')} style={{width: 120}}/>
+
+
+
)
})}
-
-
+
+
>)
+}
+
+export const BillTypeConfirm: React.FC
= (props) => {
+ const {t} = useTranslation()
+ const [state, setState] = useSetState<{
+ confirm_application_number: string;
+ confirmed: {
+ [key: number]: ConfirmedBillDetail[]
+ }
+ }>({
+ confirm_application_number: '', confirmed: {}
+ })
+ const details = useMemo(() => {
+ const {details, detail_confirms} = props.bill;
+ if (!details) return [];
+ details.forEach(it => {
+ if (!detail_confirms) it.confirmed = [];
+ else it.confirmed = detail_confirms.filter(s => s.bill_detail_id == it.id)
+ })
+ return details;
+ }, [props.bill])
+
+ const onChange = (id: number, confirmedTypes: ConfirmedBillDetail[]) => {
+ const confirmed = {
+ ...state.confirmed
+ };
+ confirmed[id] = confirmedTypes
+ setState({confirmed})
+ // trigger
+ const allConfirmed: ConfirmedBillDetail[] = [];
+ Object.keys(confirmed).forEach(key => {
+ allConfirmed.push(...confirmed[Number(key)])
+ })
+ props.onChange?.(allConfirmed)
+ }
+
+ return (<>
+ Bill Type Confirm
+ {
+ details.map((it, idx) => ( onChange(it.id, confirmed)} data={it} key={idx}/>))
+ }
+ >)
+}
+
+export const BillTypeConfirmModal: React.FC = (props) => {
+ const {t} = useTranslation()
+ const [state, setState] = useSetState<{
+ confirm_application_number: string;
+ detail_confirms: ConfirmedBillDetail[];
+ loading?: boolean;
+ }>({
+ confirm_application_number: '',
+ detail_confirms: []
+ })
+
+ const onBillConfirm = () => {
+ setState({loading: true})
+ confirmBillType([{
+ id: props.bill.id,
+ confirm_student_number: props.bill.student_number,
+ ...state
+ }]).then(() => {
+ props.onClose?.(true)
+ }).finally(() => {
+ setState({loading: false})
+ })
+ }
+ return ( props.onClose?.()}
+ >
+
+
+ } title={t('manual.student_number')}
+ value={props.bill.student_number || '-'}/>
+ } title={t('base.bill_number')}
+ value={props.bill.application_number || '-'}/>
+ >}/>
+
+
+
Bill Number Confirm
+ {/*{*/}
+ {/* !state.confirmBill.student_number_confirm &&*/}
+ {/*
*/}
+ {/*}*/}
+ setState({confirm_application_number})}
+ bill={props.bill} type={'application_number'}/>
+
+ setState({detail_confirms})}/>
+
+
+
+ )
}
\ No newline at end of file
diff --git a/src/pages/bill/components/number_confirm.tsx b/src/pages/bill/components/number_confirm.tsx
index bb9ddd1..c32a6e2 100644
--- a/src/pages/bill/components/number_confirm.tsx
+++ b/src/pages/bill/components/number_confirm.tsx
@@ -1,55 +1,52 @@
-import {Button, Space, Tag, Input} from "@douyinfe/semi-ui";
-import React from "react";
+import {Space, Input} from "@douyinfe/semi-ui";
+import React, {useEffect} from "react";
import {useSetState} from "ahooks";
import {useTranslation} from "react-i18next";
type NumberConfirmProps = {
bill: BillModel;
- type: 'student_number' | 'application_number'
+ type: 'student_number' | 'application_number';
+ onChange: (value: string) => void;
}
-export const NumberConfirm: React.FC = (props) => {
+export const NumberConfirm: React.FC = ({bill, type, onChange}) => {
const {t} = useTranslation()
+
const [state, setState] = useSetState({
loading: false,
confirmed: false,
- confirmNumber: (props.type == 'application_number' ? props.bill.application_number : props.bill.student_number) || '',
+ confirmNumber: '',
})
- const onConfirm = () => {
- if (!state.confirmNumber.length) return
- setState({loading: true})
- setTimeout(() => {
- setState({loading: false, confirmed: true})
- }, 500)
-
- // confirmBillType({id:it.id,type:state.bill_type}).then(() => {
- // setState({loading:false})
- // setItem({...it,confirm_status:'CONFIRMED'})
- // }).catch(() => {
- // setState({loading:false})
- // })
+ const onValueChange = (confirmNumber: string) => {
+ setState({confirmNumber})
+ onChange(confirmNumber)
}
+ useEffect(() => {
+ const confirmNumber = (type == 'application_number' ? (bill.application_number_confirm || bill.application_number) : bill.student_number) || '';
+ onValueChange(confirmNumber)
+ }, [])
+
return
+ style={{marginBottom: 15, marginTop: 15}}>
-
{t(props.type == 'student_number' ? 'bill.confirm_student_number' : 'bill.confirm_bill_number')}
+
{t(type == 'student_number' ? 'bill.confirm_student_number' : 'bill.confirm_bill_number')}
diff --git a/src/pages/bill/query.tsx b/src/pages/bill/query.tsx
index 4781d89..c18df83 100644
--- a/src/pages/bill/query.tsx
+++ b/src/pages/bill/query.tsx
@@ -1,4 +1,4 @@
-import {Button, ButtonGroup, Divider, Modal, Notification, Popconfirm, Toast} from "@douyinfe/semi-ui";
+import {Button, ButtonGroup, Modal, Notification, Popconfirm, Space, Toast} from "@douyinfe/semi-ui";
import {useState} from "react";
import {useRequest, useSetState} from "ahooks";
import {useTranslation} from "react-i18next";
@@ -9,13 +9,10 @@ import BillDetail from "@/components/bill/detail.tsx";
import {billList, BillQueryParams, exportBillList, modifyBillStatus} from "@/service/api/bill.ts";
import {BillStatus, BizError} from "@/service/types.ts";
import {useDownloadReceiptPDF} from "@/service/generate-pdf.ts";
-import {BillDetailItems} from "@/components/bill";
import {BillPaidModal} from "@/pages/bill/components/bill_paid_modal.tsx";
-import {BillTypeConfirm} from "@/pages/bill/components/bill_type_confirm.tsx";
+import {BillTypeConfirmModal} from "@/pages/bill/components/bill_type_confirm.tsx";
import {saveAs} from "file-saver";
-import {IconStudentId} from "@/components/icons";
-import {BillDetailItem} from "@/components/bill/bill-detail-items.tsx";
-import {NumberConfirm} from "@/pages/bill/components/number_confirm.tsx";
+import {AddBillModal} from "@/pages/bill/components/add_bill_modal.tsx";
const DownloadButton = ({bill, text}: { bill: BillModel; text: string }) => {
@@ -116,12 +113,17 @@ const BillQuery = () => {
console.log(selectKeys)
}
+ const onBillConfirm = (reload?: boolean) => {
+ setState({confirmBill: undefined})
+ if (reload) refresh()
+ }
+
return (
+ beforeTotalAmount={
{
(selectKeys.length == 0) ? :
{
}
-
-
- }
+
+
+
+
+
+ }
onRowSelection={setSelectedKeys}
onPageChange={(page_number) => {
@@ -164,42 +169,7 @@ const BillQuery = () => {
refresh()
}}
/>
- {
- refresh()
- setState({confirmBill: undefined})
- }}
- width={550}
- footer={null}
- >
- {state.confirmBill && <>
-
- } title={t('manual.student_number')}
- value={state.confirmBill.student_number || '-'}/>
- } title={t('base.bill_number')}
- value={state.confirmBill.application_number || '-'}/>
- >}/>
-
- {
- !state.confirmBill.student_number_confirm &&
-
- }
- {
- !state.confirmBill.application_number_confirm &&
-
- }
- Bill Type Confirm
- {
- state.confirmBill.details.map((it, idx) => ())
- }
-
- >}
-
+ {state.confirmBill && }
)
}
export default BillQuery
\ No newline at end of file
diff --git a/src/pages/manual/index.tsx b/src/pages/manual/index.tsx
index ac0dc1c..0d352fa 100644
--- a/src/pages/manual/index.tsx
+++ b/src/pages/manual/index.tsx
@@ -3,7 +3,7 @@ import {useTranslation} from "react-i18next";
import {useRef, useState} from "react";
import {Card} from "@/components/card";
-import {BillTypes} from "@/service/bill-types.ts";
+import {useBillTypes} from "@/hooks/useBillTypes.ts";
import {BillDetailItems, useBillQRCode} from "@/components/bill";
import styles from './manual.module.less'
@@ -43,6 +43,7 @@ export default function Index() {
// useEffect(()=>{
// getBillDetail(100009).then(setBillInfo);
// },[])
+ const BillTypes = useBillTypes()
const BillInfo = ({bill}: { bill?: BillModel }) => {
if (!bill) return null;
diff --git a/src/routes/layout/dashboard-navigation.tsx b/src/routes/layout/dashboard-navigation.tsx
index 801035d..f43de70 100644
--- a/src/routes/layout/dashboard-navigation.tsx
+++ b/src/routes/layout/dashboard-navigation.tsx
@@ -3,7 +3,7 @@ import {useMemo} from "react";
import {useTranslation} from "react-i18next";
import useAuth from "@/hooks/useAuth.ts";
-import {IconQRCode, IconQuery, IconReconciliation} from "@/components/logo";
+import {IconPermission, IconQRCode, IconQuery, IconReconciliation} from "@/components/logo";
export const AllDashboardMenu = [
{
@@ -22,6 +22,12 @@ export const AllDashboardMenu = [
icon: ,
path: '/dashboard/reconciliation',
role: ['root', 'fo']
+ },
+ {
+ key: 'permission',
+ icon: ,
+ path: '/dashboard/permission',
+ role: ['root']
}
]
diff --git a/src/service/api/bill.ts b/src/service/api/bill.ts
index 50a82ee..0d32a2a 100644
--- a/src/service/api/bill.ts
+++ b/src/service/api/bill.ts
@@ -48,6 +48,10 @@ export function createManualBill(params: ManualCreateBillParam) {
return post('/manual_payment', params)
}
+export function selectBillTypeList(){
+ return get('/billing_types')
+}
+
// 获取账单详情
export function getBillDetail(id: number) {
return get('/bills/' + id)
@@ -66,8 +70,8 @@ export function modifyBillStatus(id: number,status: BillStatus) {
return put(`/bills/${id}/cancel`,{status})
}
-export function confirmBillType({id,type}: {id:number,type: string}) {
- return post(`/bill/detail/${id}/confirm`, {confirm_type:type})
+export function confirmBillType(bills:BillConfirmParams[]) {
+ return post(`/bills/confirm`, {bills})
}
export function confirmBills(bill_ids: number[]) {
diff --git a/src/service/generate-pdf.ts b/src/service/generate-pdf.ts
index cf7aba9..0dab758 100644
--- a/src/service/generate-pdf.ts
+++ b/src/service/generate-pdf.ts
@@ -61,7 +61,7 @@ export function GeneratePdf(bill: BillModel) {
...(bill.details.map(it=>{
return [
`#${it.id}`,
- dayjs(bill.paid_at).format('YYYY-MM-DD'),
+ bill.paid_at?dayjs(bill.paid_at).format('YYYY-MM-DD'):'',
it.bill_type,
`${bill.payment_channel}` + (bill.payment_method && bill.payment_channel != bill.payment_method ? `(${bill.payment_method})` : ''),
`${it.amount}`
diff --git a/src/types/bill.d.ts b/src/types/bill.d.ts
index c089235..5f7227b 100644
--- a/src/types/bill.d.ts
+++ b/src/types/bill.d.ts
@@ -13,8 +13,14 @@ declare type ManualCreateBillParam = {
declare type BillDetail = {
id: number;
bill_type: string;
- confirm_status: ConfirmStatus;
- confirm_type: string;
+ amount: decimal;
+ confirmed?: ConfirmedBillDetail[];
+}
+
+declare type ConfirmedBillDetail = {
+ id?: number;
+ bill_detail_id: number;
+ bill_type: string;
amount: decimal;
}
/**
@@ -38,6 +44,10 @@ declare type BillQueryParam = {
sort_field:string;
sort_order:SortOrderType;
}
+declare type BillType = {
+ type: string;
+ description: string;
+}
/**
* 账单模型
*/
@@ -46,7 +56,7 @@ declare type BillModel = {
student_number: string;
student_number_confirm?: string;
application_number: null | string;
- application_number_confirm?: null | string;
+ confirm_application_number?: null | string;
student_email: string;
student_tc_name?: string;
student_sc_name?: string;
@@ -80,6 +90,7 @@ declare type BillModel = {
remark: string;
confirm_status: ConfirmStatus;
details: BillDetail[]
+ detail_confirms: ConfirmedBillDetail[] | null
}
@@ -114,4 +125,10 @@ type BillUpdateParams = {
type BillTypeConfirm = {
bill_type: string;
amount: number;
+}
+type BillConfirmParams = {
+ id:number;
+ confirm_application_number:string;
+ confirm_student_number:string;
+ detail_confirms:ConfirmedBillDetail[]
}
\ No newline at end of file
diff --git a/vite.config.ts b/vite.config.ts
index 83e68da..3c7d82b 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -28,8 +28,8 @@ export default defineConfig(({mode}) => {
port:10086,
proxy: {
'/api': {
- // target: 'https://test-payment-be.hkchc.team', //
- target: 'http://127.0.0.1:50000', //
+ target: 'https://test-payment-be.hkchc.team', //
+ // target: 'http://127.0.0.1:50000', //
changeOrigin: true,
//rewrite: (path) => path.replace(/^\/api/, '')
}