From 9079f39014b48abeb403a4e2631ae7263b357686 Mon Sep 17 00:00:00 2001 From: wuyize Date: Mon, 2 Jan 2023 22:49:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90=E5=8F=91?= =?UTF-8?q?=E7=A5=A8=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/models/Staff.ts | 1 + src/models/store.ts | 1 + .../Invoice/{mine => }/InvoiceDetailModal.tsx | 34 +- .../Invoice/management/InvoiceManagement.tsx | 374 +++++++++++++++++- src/pages/Invoice/mine/InvoiceListView.tsx | 120 +++--- src/pages/Invoice/mine/InvoiceUploadView.tsx | 5 +- 6 files changed, 471 insertions(+), 64 deletions(-) rename src/pages/Invoice/{mine => }/InvoiceDetailModal.tsx (75%) diff --git a/src/models/Staff.ts b/src/models/Staff.ts index 643d293..70b4f68 100644 --- a/src/models/Staff.ts +++ b/src/models/Staff.ts @@ -12,6 +12,7 @@ export interface Staff { staffDepartments: Department[]; staffName: string; staffBase: string; + staffId: string|null|undefined; } export interface Department { diff --git a/src/models/store.ts b/src/models/store.ts index b5adacd..9f55eeb 100644 --- a/src/models/store.ts +++ b/src/models/store.ts @@ -27,6 +27,7 @@ const tokenSlice = createSlice({ const staffSlice = createSlice({ name: 'staff', initialState: { + staffId: "", staffName: "", managingDepartment: null as Department|null, staffDepartments: [{ departmentId: 0, diff --git a/src/pages/Invoice/mine/InvoiceDetailModal.tsx b/src/pages/Invoice/InvoiceDetailModal.tsx similarity index 75% rename from src/pages/Invoice/mine/InvoiceDetailModal.tsx rename to src/pages/Invoice/InvoiceDetailModal.tsx index 6173c24..8b69432 100644 --- a/src/pages/Invoice/mine/InvoiceDetailModal.tsx +++ b/src/pages/Invoice/InvoiceDetailModal.tsx @@ -6,12 +6,13 @@ import { invoiceItemsMap, invoiceTypeExtraItemsMap, invoiceTypeItemsMap, invoiceTypeNameMap, invoiceTypeShowItemsMap -} from "../../../models/Invoice"; -import axiosInstance from "../../../utils/axiosInstance"; +} from "../../models/Invoice"; +import axiosInstance from "../../utils/axiosInstance"; import TextArea from "antd/es/input/TextArea"; import dayjs, {Dayjs} from "dayjs"; +import qs from "qs"; -const {Text, Paragraph } = Typography; +const {Text, Paragraph} = Typography; function InvoiceDetailModal(props: any) { //const [open, setOpen] = useState(false) @@ -77,28 +78,47 @@ function InvoiceDetailModal(props: any) { refreshFormItems(value) } + const withDraw = () => { + setLoading(true) + axiosInstance({ + url: 'common/invoice/' + props.invoiceDetail.invoiceId, + method: 'delete', + }).then(response => { + console.log(response.data) + setLoading(false) + props.onClose() + props.needRefresh() + }).catch(function (error) { + console.log(error) + setLoading(false) + }) + } + return ( + 打回 + : null} > { -
- {invoiceTypeNameMap.get(props.invoiceDetail?.invoiceKind) } + {invoiceTypeNameMap.get(props.invoiceDetail?.invoiceKind)} {formItems} - {props.invoiceDetail?.invoiceNote } + {props.invoiceDetail?.invoiceNote}
} diff --git a/src/pages/Invoice/management/InvoiceManagement.tsx b/src/pages/Invoice/management/InvoiceManagement.tsx index f310b03..9cb19d1 100644 --- a/src/pages/Invoice/management/InvoiceManagement.tsx +++ b/src/pages/Invoice/management/InvoiceManagement.tsx @@ -1,6 +1,374 @@ -function InvoiceManagement() { - return( -
发票管理
+import { + Card, + Dropdown, + List, + Row, + Input, + Button, + Radio, + Col, + Divider, + DatePicker, + Form, + TimePicker, + Select, + Checkbox, + Pagination, theme, Tag, Badge +} from "antd"; +import type {MenuProps, PaginationProps} from 'antd'; +import {DownOutlined, UploadOutlined} from '@ant-design/icons'; +import React, { + ReactElement, + JSXElementConstructor, + ReactFragment, + ReactPortal, + useState, + useEffect, + ReactNode +} from "react"; +import {InvoiceDetail, InvoiceSearchOption} from "../../../models/Invoice" +import {Space, Typography} from 'antd'; +import {SizeType} from "antd/es/config-provider/SizeContext"; +import axios from "axios"; +import axiosInstance, {baseUrl} from "../../../utils/axiosInstance"; +import {Simulate} from "react-dom/test-utils"; +import change = Simulate.change; +import {useNavigate, useSearchParams} from "react-router-dom"; +import {useAppDispatch} from "../../../models/hooks"; +import { + Invoice, + invoiceItemsMap, + invoiceTypeExtraItemsMap, + invoiceTypeItemsMap, + invoiceTypeNameMap +} from "../../../models/Invoice"; +import {RadioButtonProps} from "antd/es/radio/radioButton"; +import qs from "qs"; +import InvoiceDetailModal from "../InvoiceDetailModal"; +import dayjs from "dayjs"; + + +const {Text, Paragraph} = Typography; +const {Meta} = Card; +const {Search} = Input; +const {Option} = Select +let invoices: Array +const {RangePicker} = DatePicker; + +const config = { + rules: [{type: 'object' as const, required: false, message: 'Please select time!'}], +}; +const rangeConfig = { + rules: [{type: 'array' as const, required: false, message: 'Please select time!'}], +}; + +function InvoiceSearch(props: { handleSearchData: any; }) { + const { + token: {colorBgContainer, colorPrimary}, + } = theme.useToken(); + + const [activatedOption, setActivatedOption] = useState('发票代码') + const [complexEnabled, setComplexEnabled] = useState(false) + const [invoiceSearchOption, setInvoiceSearchOption] = useState(new InvoiceSearchOption()) + + const items: MenuProps['items'] = [ + { + key: '1', + label: ( { + invoiceSearchOption.clear(); + setActivatedOption("发票代码") + }}> + 发票代码 + ) + }, + { + key: '2', + label: ( { + invoiceSearchOption.clear(); + setActivatedOption("发票编号") + + }}> + 发票编号 + ) + } + ]; + const onValuesChange = (changedValues: any, allValues: any) => { + invoiceSearchOption.clear() + + console.log(allValues) + if (allValues['upload-time-picker'] !== null && allValues['upload-time-picker'] !== undefined) { + invoiceSearchOption.invoiceUploadTimeStart = allValues['upload-time-picker'][0].format('YYYY-MM-DDtHH:mm:ss') + invoiceSearchOption.invoiceUploadTimeEnd = allValues['upload-time-picker'][1].format('YYYY-MM-DDtHH:mm:ss') + } + if (allValues['invoice-time-picker'] !== null && allValues['invoice-time-picker'] !== undefined) { + invoiceSearchOption.invoiceDateStart = allValues['invoice-time-picker'][0].format('YYYY-MM-DD') + invoiceSearchOption.invoiceDateEnd = allValues['invoice-time-picker'][1].format('YYYY-MM-DD') + } + if (allValues['invoice-state'] !== "全部") { + invoiceSearchOption.invoiceStates = [allValues['invoice-state']] + } + if (allValues['invoice-kind'] !== "全部") { + invoiceSearchOption.invoiceKinds = [allValues['invoice-kind']] + } + if (allValues['invoice-uploader'] !== null && allValues['invoice-uploader'] !== undefined && allValues['invoice-uploader'].trim() !== "") { + invoiceSearchOption.invoiceUploaderId = allValues['invoice-uploader'].trim() + } + props.handleSearchData(invoiceSearchOption) + } + + const onSearch = (value: string) => { + if (!complexEnabled) + invoiceSearchOption.clear() + console.log(invoiceSearchOption) + if (activatedOption === "发票代码") { + invoiceSearchOption.invoiceCode = value; + invoiceSearchOption.invoiceNo = null; + } else { + invoiceSearchOption.invoiceNo = value; + invoiceSearchOption.invoiceCode = null; + } + + props.handleSearchData(invoiceSearchOption) + + } + + const getInvoiceKindsRadioButtons: any = () => { + let options: any[] = [] + invoiceTypeNameMap.forEach(function (value, key, map) { + options.push({value}) + }) + return options + } + + return ( +
+
+ + + + {activatedOption} + + + + } + placeholder={'请在此输入'} + allowClear + onSearch={(value) => onSearch(value)} + style={{width: 404}} + enterButton + /> + { + setComplexEnabled(e.target.checked) + }}>高级搜索 +
+ {complexEnabled && +
+
+ + + + 全部 + {getInvoiceKindsRadioButtons()} + + + +
+ + + + + + + +
+ + + 全部 + 未使用 + 报销中 + 已报销 + + + +
+
} +
) } + +function InvoiceItem(props: { invoice: Invoice, onClick(invoice: Invoice): void }) { + const { + token: {colorBgContainer, colorPrimary, colorSuccess, colorWarning}, + } = theme.useToken(); + + const onClick = () => { + props.onClick(props.invoice) + } + return ( +
+ + + + } + > +
+
+ ¥{(props.invoice.invoiceAmount / 100.0).toFixed(2)} + {props.invoice.invoiceUploader.staffName } +
+
+ {invoiceTypeNameMap.get(props.invoice.invoiceKind)} + {props.invoice.invoiceUploader.staffId } +
+
  • {props.invoice.invoiceNo}
  • +
  • {props.invoice.invoiceDate}
  • +
    +
    +
    +
    + + + ) + +} + + +function InvoiceManagement(props: {}) { + const [totalNum, setTotalNum] = useState(0) + const [invoices, setInvoices] = useState([] as any[]) + const [search, setSearch] = useSearchParams() + const [invoiceSearchOption, setInvoiceSearchOption] = useState(new InvoiceSearchOption()) + const [detailModalOpen, setDetailModalOpen] = useState(false) + const [invoiceDetail, setInvoiceDetail] = useState(null as InvoiceDetail | null) + const navigate = useNavigate() + + const handleInvoiceSearchInfo = (invoiceSearch: InvoiceSearchOption) => { + //setInvoiceSearchOption(invoiceSearch) + searchInvoiceContent(invoiceSearch) + } + const searchInvoiceContent = (invoiceSearch: InvoiceSearchOption) => { + setInvoices([]) + let params: any = invoiceSearch + Object.keys(params).forEach(key => { + if (params[key] != null && params[key] !== undefined && params[key] === "") { + params[key] = null + } + }) + if (search.get('currentPage')) + params.pageNum = Number(search.get('currentPage')) - 1 + else + params.pageNum = 0 + if (search.get('pageSize')) + params.pageSize = Number(search.get('pageSize')) + else + params.pageSize = 10 + axiosInstance({ + url: 'common/invoice?' + qs.stringify(params, {skipNulls: true, arrayFormat: 'indices'}), + method: 'get', + }).then(response => { + console.log(response.data) + setTotalNum(response.data.total) + setInvoices([...response.data.records]) + }).catch(function (error) { + console.log(error) + }) + } + const onChange = (pageCurrentNum: Number, pageCurrentSize: Number) => { + console.log(pageCurrentNum, pageCurrentSize) + navigate('/invoice/management?currentPage=' + pageCurrentNum + '&pageSize=' + pageCurrentSize) + } + + const onItemClick = (invoice: Invoice) => { + console.log(invoice) + axiosInstance({ + url: 'common/invoice/' + invoice.invoiceId, + method: 'get', + }).then(response => { + console.log(response.data) + let detail: InvoiceDetail = response.data + detail.invoiceAmount /= 100. + setInvoiceDetail(detail) + setDetailModalOpen(true) + }).catch(function (error) { + console.log(error) + }) + + } + + useEffect(() => { + console.log(search.get('currentPage')) + console.log(search.get('pageSize')) + searchInvoiceContent(invoiceSearchOption) + }, [search]); + + console.log(invoices) + return ( +
    + +
    +
    + {invoices.map((item: Invoice, index: number) => + + )} +
    + `共 ${total} 项`} + current={Number(search.get('currentPage') ? search.get('currentPage') : 1)} + pageSize={Number(search.get('pageSize') ? search.get('pageSize') : 10)} + total={totalNum} onChange={onChange}/> +
    + { searchInvoiceContent(invoiceSearchOption)}} invoiceDetail={invoiceDetail} open={detailModalOpen} onClose={() => { + setDetailModalOpen(false) + }} showFooter={true}/> +
    + + ) +} + export default InvoiceManagement \ No newline at end of file diff --git a/src/pages/Invoice/mine/InvoiceListView.tsx b/src/pages/Invoice/mine/InvoiceListView.tsx index 5f579dd..67dfb89 100644 --- a/src/pages/Invoice/mine/InvoiceListView.tsx +++ b/src/pages/Invoice/mine/InvoiceListView.tsx @@ -13,7 +13,7 @@ import { TimePicker, Select, Checkbox, - Pagination, theme + Pagination, theme, Tag, Badge } from "antd"; import type {MenuProps, PaginationProps} from 'antd'; import {DownOutlined, UploadOutlined} from '@ant-design/icons'; @@ -45,8 +45,9 @@ import { } from "../../../models/Invoice"; import {RadioButtonProps} from "antd/es/radio/radioButton"; import qs from "qs"; -import InvoiceDetailModal from "./InvoiceDetailModal"; +import InvoiceDetailModal from "../InvoiceDetailModal"; import dayjs from "dayjs"; +import {store} from "../../../models/store"; const {Meta} = Card; @@ -132,10 +133,10 @@ function InvoiceSearch(props: { handleSearchData: any; }) { } - const getInvoiceKindsRadioButtons: any = () =>{ + const getInvoiceKindsRadioButtons: any = () => { let options: any[] = [] invoiceTypeNameMap.forEach(function (value, key, map) { - options.push( {value}) + options.push({value}) }) return options } @@ -174,10 +175,16 @@ function InvoiceSearch(props: { handleSearchData: any; }) { { setComplexEnabled(e.target.checked) }}>高级搜索 - + {props.handleSearchData(invoiceSearchOption)}} /> {complexEnabled && -
    +
    -
    - +
    + @@ -217,46 +225,49 @@ function InvoiceSearch(props: { handleSearchData: any; }) { ) } -class InvoiceItem extends React.Component { - constructor(props: { invoice: Invoice }) { - super(props); - this.state = { - invoiceThumbnailUri: baseUrl + props.invoice.invoiceThumbnailUri, - invoiceKind: props.invoice.invoiceKind, - invoiceAmount: props.invoice.invoiceAmount, - invoiceDate: props.invoice.invoiceDate, - invoiceNo: props.invoice.invoiceNo, - } - console.log(this.state.invoiceThumbnailUri) +function InvoiceItem(props: { invoice: Invoice, onClick(invoice: Invoice): void }) { + const { + token: {colorBgContainer, colorPrimary, colorSuccess, colorWarning}, + } = theme.useToken(); + + const onClick = () => { + props.onClick(props.invoice) } + return ( +
    + + + + } + > +
    +
  • ¥{(props.invoice.invoiceAmount / 100.0).toFixed(2)}
  • +
  • {invoiceTypeNameMap.get(props.invoice.invoiceKind)}
  • +
  • {props.invoice.invoiceNo}
  • +
  • {props.invoice.invoiceDate}
  • +
    +
    +
    +
    - onClick = () => { - this.props.onClick(this.props.invoice) - } - render() { - return ( - } - > -
    -
  • ¥{(this.state.invoiceAmount / 100.0).toFixed(2)}
  • -
  • {invoiceTypeNameMap.get(this.state.invoiceKind)}
  • -
  • {this.state.invoiceNo}
  • -
  • {this.state.invoiceDate}
  • -
    -
    - ) - } + ) + } @@ -266,7 +277,7 @@ function InvoiceListView(props: {}) { const [search, setSearch] = useSearchParams() const [invoiceSearchOption, setInvoiceSearchOption] = useState(new InvoiceSearchOption()) const [detailModalOpen, setDetailModalOpen] = useState(false) - const [invoiceDetail, setInvoiceDetail] = useState(null as InvoiceDetail|null) + const [invoiceDetail, setInvoiceDetail] = useState(null as InvoiceDetail | null) const navigate = useNavigate() const handleInvoiceSearchInfo = (invoiceSearch: InvoiceSearchOption) => { @@ -289,8 +300,11 @@ function InvoiceListView(props: {}) { params.pageSize = Number(search.get('pageSize')) else params.pageSize = 10 + + params.invoiceUploaderId = store.getState().token.staffId + axiosInstance({ - url: 'common/invoice?'+qs.stringify( params,{skipNulls:true, arrayFormat: 'indices'}), + url: 'common/invoice?' + qs.stringify(params, {skipNulls: true, arrayFormat: 'indices'}), method: 'get', }).then(response => { console.log(response.data) @@ -305,15 +319,15 @@ function InvoiceListView(props: {}) { navigate('/invoice/mine?currentPage=' + pageCurrentNum + '&pageSize=' + pageCurrentSize) } - const onItemClick = (invoice: Invoice) =>{ + const onItemClick = (invoice: Invoice) => { console.log(invoice) axiosInstance({ - url: 'common/invoice/'+invoice.invoiceId, + url: 'common/invoice/' + invoice.invoiceId, method: 'get', }).then(response => { console.log(response.data) - let detail:InvoiceDetail = response.data - detail.invoiceAmount/=100. + let detail: InvoiceDetail = response.data + detail.invoiceAmount /= 100. setInvoiceDetail(detail) setDetailModalOpen(true) }).catch(function (error) { @@ -345,7 +359,9 @@ function InvoiceListView(props: {}) { pageSize={Number(search.get('pageSize') ? search.get('pageSize') : 10)} total={totalNum} onChange={onChange}/>
    - {setDetailModalOpen(false)}}/> + { + setDetailModalOpen(false) + }}/>
    ) diff --git a/src/pages/Invoice/mine/InvoiceUploadView.tsx b/src/pages/Invoice/mine/InvoiceUploadView.tsx index 99d81fc..f7f777f 100644 --- a/src/pages/Invoice/mine/InvoiceUploadView.tsx +++ b/src/pages/Invoice/mine/InvoiceUploadView.tsx @@ -132,6 +132,7 @@ function FormModal(props: any) { console.log(response.data) setLoading(false) props.onClose() + props.needRefresh() //setOpen(false) }).catch(function (error) { console.log(error) @@ -240,7 +241,7 @@ function FormModal(props: any) { class InvoiceUploadView extends React.Component { - constructor(props: {}) { + constructor(props: any) { super(props); this.state = { uploadModalOpen: false, @@ -281,7 +282,7 @@ class InvoiceUploadView extends React.Component { 上传 - { this.props.needRefresh()}} open={this.state.formModalOpen} onClose={this.handleClose} invoiceIdentifyResponse={this.state.invoiceIdentifyResponse}/> );