diff --git a/package.json b/package.json
index 589cacb..657bc71 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "fw-h5app-template",
+ "name": "h5app-cas",
"version": "1.0.0",
"scripts": {
"reset": "npx rimraf ./**/node_modules",
@@ -27,11 +27,12 @@
"dependencies": {
"@ant-design/cssinjs": "^1.21.1",
"@ant-design/icons": "^5.4.0",
- "@feewee/h5app-common": "^0.1.138",
+ "@feewee/h5app-common": "^0.1.168",
"@modern-js/runtime": "~2.57.0",
"ahooks": "^3.8.0",
"antd": "^5.20.0",
"clsx": "^2.1.1",
+ "currency.js": "^2.0.4",
"dayjs": "^1.11.12",
"lodash": "^4.17.21",
"query-string": "^9.1.0",
@@ -44,8 +45,8 @@
"@modern-js-app/eslint-config": "~2.57.0",
"@modern-js/app-tools": "~2.57.0",
"@modern-js/eslint-config": "~2.57.0",
- "@modern-js/plugin-tailwindcss": "~2.57.0",
"@modern-js/plugin-polyfill": "~2.57.0",
+ "@modern-js/plugin-tailwindcss": "~2.57.0",
"@modern-js/tsconfig": "~2.57.0",
"@rsdoctor/rspack-plugin": "^0.3.11",
"@types/jest": "^29.5.12",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 832c634..f2389fa 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -15,8 +15,8 @@ importers:
specifier: ^5.4.0
version: 5.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@feewee/h5app-common':
- specifier: ^0.1.138
- version: 0.1.141(antd@5.20.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: ^0.1.168
+ version: 0.1.168(antd@5.20.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@modern-js/runtime':
specifier: ~2.57.0
version: 2.57.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -29,6 +29,9 @@ importers:
clsx:
specifier: ^2.1.1
version: 2.1.1
+ currency.js:
+ specifier: ^2.0.4
+ version: 2.0.4
dayjs:
specifier: ^1.11.12
version: 1.11.13
@@ -151,6 +154,13 @@ packages:
react: '>=16.0.0'
react-dom: '>=16.0.0'
+ '@ant-design/icons@5.5.1':
+ resolution: {integrity: sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==}
+ engines: {node: '>=8'}
+ peerDependencies:
+ react: '>=16.0.0'
+ react-dom: '>=16.0.0'
+
'@ant-design/react-slick@1.1.2':
resolution: {integrity: sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==}
peerDependencies:
@@ -1576,8 +1586,8 @@ packages:
engines: {node: '>=14', npm: '>=6'}
hasBin: true
- '@feewee/h5app-common@0.1.141':
- resolution: {integrity: sha512-21YZ5GqrRh4xzuQcfUzikvOsNVz4PxGMsL9V8H9ISGclkAe+VFjy1SWRDoVTSqSP4HCxjfGrBJJ0sysIMujZNQ==}
+ '@feewee/h5app-common@0.1.168':
+ resolution: {integrity: sha512-08x8IC2jaJGmM7UaQQcRmkBcJcb13prgOFVbSMkmeBq7+fj/rQxGOQTe2HwjU4NNOHCJOrv2Gjmnufy49GvI5g==}
engines: {node: '>=18', npm: '>=6.9.0'}
peerDependencies:
antd: '>=5'
@@ -1892,8 +1902,8 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
- '@nutui/icons-react@1.0.4':
- resolution: {integrity: sha512-nLFYpJvMBkKzT+PpfMaYoO6vJXMTM0yxAragTkEHt9HAFNjdTdvByCSRfUazHHdLdr1AJxS9h62VB1+jmBEtWA==}
+ '@nutui/icons-react@1.0.5':
+ resolution: {integrity: sha512-0TYl3Fk+sVz95DKqn/7isYAvaK5YGnaBwMMib4rqYLoqi9GGFwgU9rp2hYXu/X5IYdWgshj0xiuGMK75/vUYbQ==}
'@nutui/nutui-react@2.6.15':
resolution: {integrity: sha512-/xX4pB6HSXSWwqnumoJR+omirA9b8HznDvwFHFr/iu+KJn4D658VAVR47T4Z0ROEq9lmErmlcDxjqnxmJOzl6w==}
@@ -2338,14 +2348,14 @@ packages:
'@swc/plugin-styled-components@2.0.9':
resolution: {integrity: sha512-0aPv7lNed27qs8JBklLkVSlLhpPRU3YKRnKplObaAyhNWbpbOkCbVSTay5ArFT2Gz1rz844Np7l4DMozEtZRBg==}
- '@tanstack/react-virtual@3.10.6':
- resolution: {integrity: sha512-xaSy6uUxB92O8mngHZ6CvbhGuqxQ5lIZWCBy+FjhrbHmOwc6BnOnKkYm2FsB1/BpKw/+FVctlMbEtI+F6I1aJg==}
+ '@tanstack/react-virtual@3.10.9':
+ resolution: {integrity: sha512-OXO2uBjFqA4Ibr2O3y0YMnkrRWGVNqcvHQXmGvMu6IK8chZl3PrDxFXdGZ2iZkSrKh3/qUYoFqYe+Rx23RoU0g==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
- '@tanstack/virtual-core@3.10.6':
- resolution: {integrity: sha512-1giLc4dzgEKLMx5pgKjL6HlG5fjZMgCjzlKAlpr7yoUtetVPELgER1NtephAI910nMwfPTHNyWKSFmJdHkz2Cw==}
+ '@tanstack/virtual-core@3.10.9':
+ resolution: {integrity: sha512-kBknKOKzmeR7lN+vSadaKWXaLS0SZZG+oqpQ/k80Q6g9REn6zRHS/ZYdrIzHnpHgy/eWs00SujveUN/GJT2qTw==}
'@trysound/sax@0.2.0':
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
@@ -3403,6 +3413,10 @@ packages:
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+ currency.js@2.0.4:
+ resolution: {integrity: sha512-6/OplJYgJ0RUlli74d93HJ/OsKVBi8lB1+Z6eJYS1YZzBuIp4qKKHpJ7ad+GvTlWmLR/hLJOWTykN5Nm8NJ7+w==}
+ engines: {node: '>=4'}
+
current-script-polyfill@1.0.0:
resolution: {integrity: sha512-qv8s+G47V6Hq+g2kRE5th+ASzzrL7b6l+tap1DHKK25ZQJv3yIFhH96XaQ7NGL+zRW3t/RDbweJf/dJDe5Z5KA==}
@@ -5812,6 +5826,10 @@ packages:
resolution: {integrity: sha512-t6dqMECpCkqfyv2FfwVS1xcB6lgXW/0XZSaKdsCNGYkqMO76AFiJEg4vINzoDKcZa6MS7JX+OHIjwh06K5vczw==}
engines: {node: '>=18'}
+ query-string@9.1.1:
+ resolution: {integrity: sha512-MWkCOVIcJP9QSKU52Ngow6bsAWAPlPK2MludXvcrS2bGZSl+T1qX9MZvRIkqUIkGLJquMJHWfsT6eRqUpp4aWg==}
+ engines: {node: '>=18'}
+
querystring-es3@0.2.1:
resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==}
engines: {node: '>=0.4.x'}
@@ -6091,6 +6109,12 @@ packages:
react-is@18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+ react-photo-view@1.2.6:
+ resolution: {integrity: sha512-Fq17yxkMIv0oFp7HOJr39HgCZRP6A9K5T5rixJ4flSUYT2OO3V8vNxEExjhIKgIrfmTu+mDnHYEsI9RRWi1JHw==}
+ peerDependencies:
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+
react-refresh@0.14.2:
resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
engines: {node: '>=0.10.0'}
@@ -7360,6 +7384,16 @@ snapshots:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
+ '@ant-design/icons@5.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@ant-design/colors': 7.1.0
+ '@ant-design/icons-svg': 4.4.2
+ '@babel/runtime': 7.25.6
+ classnames: 2.5.1
+ rc-util: 5.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+
'@ant-design/react-slick@1.1.2(react@18.3.1)':
dependencies:
'@babel/runtime': 7.25.6
@@ -9243,13 +9277,13 @@ snapshots:
- jest
- supports-color
- '@feewee/h5app-common@0.1.141(antd@5.20.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@feewee/h5app-common@0.1.168(antd@5.20.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@ant-design/icons': 5.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@ant-design/icons': 5.5.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@feewee/helper-wasm': 0.2.7
- '@nutui/icons-react': 1.0.4
+ '@nutui/icons-react': 1.0.5
'@nutui/nutui-react': 2.6.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@tanstack/react-virtual': 3.10.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@tanstack/react-virtual': 3.10.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
ahooks: 3.8.1(react@18.3.1)
antd: 5.20.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
antd-mobile: 5.37.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -9260,9 +9294,10 @@ snapshots:
js-cookie: 3.0.5
localforage: 1.10.0
lodash: 4.17.21
- query-string: 9.1.0
+ query-string: 9.1.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
+ react-photo-view: 1.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
transitivePeerDependencies:
- debug
@@ -9964,12 +9999,12 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
- '@nutui/icons-react@1.0.4': {}
+ '@nutui/icons-react@1.0.5': {}
'@nutui/nutui-react@2.6.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@babel/runtime': 7.25.6
- '@nutui/icons-react': 1.0.4
+ '@nutui/icons-react': 1.0.5
'@nutui/touch-emulator': 1.0.0
'@react-spring/web': 9.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@use-gesture/react': 10.2.20(react@18.3.1)
@@ -10600,13 +10635,13 @@ snapshots:
dependencies:
'@swc/counter': 0.1.3
- '@tanstack/react-virtual@3.10.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@tanstack/react-virtual@3.10.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@tanstack/virtual-core': 3.10.6
+ '@tanstack/virtual-core': 3.10.9
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- '@tanstack/virtual-core@3.10.6': {}
+ '@tanstack/virtual-core@3.10.9': {}
'@trysound/sax@0.2.0': {}
@@ -11971,6 +12006,8 @@ snapshots:
csstype@3.1.3: {}
+ currency.js@2.0.4: {}
+
current-script-polyfill@1.0.0: {}
data-uri-to-buffer@3.0.1: {}
@@ -14490,6 +14527,12 @@ snapshots:
filter-obj: 5.1.0
split-on-first: 3.0.0
+ query-string@9.1.1:
+ dependencies:
+ decode-uri-component: 0.4.1
+ filter-obj: 5.1.0
+ split-on-first: 3.0.0
+
querystring-es3@0.2.1: {}
queue-microtask@1.2.3: {}
@@ -14827,7 +14870,7 @@ snapshots:
rc-util@5.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- '@babel/runtime': 7.24.5
+ '@babel/runtime': 7.25.6
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-is: 18.3.1
@@ -14861,6 +14904,11 @@ snapshots:
react-is@18.3.1: {}
+ react-photo-view@1.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ dependencies:
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+
react-refresh@0.14.2: {}
react-router-dom@6.22.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
diff --git a/src/components/CardView/index.tsx b/src/components/CardView/index.tsx
new file mode 100644
index 0000000..c62c1e3
--- /dev/null
+++ b/src/components/CardView/index.tsx
@@ -0,0 +1,15 @@
+import type React from 'react';
+import './style.less';
+
+interface Props {
+ style?: React.CSSProperties;
+ children: React.ReactNode;
+}
+
+export default function CardView({ style, children }: Props) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/components/CardView/style.less b/src/components/CardView/style.less
new file mode 100644
index 0000000..e595fb1
--- /dev/null
+++ b/src/components/CardView/style.less
@@ -0,0 +1,5 @@
+.card-view {
+ padding: 15px;
+ border-bottom: 1px solid #eee;
+ background-color: #fff;
+}
diff --git a/src/components/RowText/index.tsx b/src/components/RowText/index.tsx
new file mode 100644
index 0000000..209a39d
--- /dev/null
+++ b/src/components/RowText/index.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import type { CSSProperties } from 'react';
+import { Row } from '@feewee/h5app-common';
+
+import './style.less';
+
+interface ComponentProps {
+ title: string;
+ content: string | number;
+ rowStyle?: CSSProperties;
+ titleStyle?: CSSProperties;
+ contentStyle?: CSSProperties;
+}
+
+export default function RowText({ title, content, rowStyle, titleStyle, contentStyle }: ComponentProps) {
+ return (
+
+
+ {title}:
+
+
+ {content}
+
+
+ );
+}
diff --git a/src/components/RowText/style.less b/src/components/RowText/style.less
new file mode 100644
index 0000000..216d95e
--- /dev/null
+++ b/src/components/RowText/style.less
@@ -0,0 +1,29 @@
+.row-wrapper {
+ margin-bottom: 10px;
+}
+
+.label {
+ color: #666;
+ font-size: 14px;
+ line-height: 14px;
+ font-weight: 500;
+}
+
+.content {
+ color: #666;
+ font-size: 14px;
+ line-height: 14px;
+ font-weight: 500;
+ flex: 1;
+}
+
+.labelBold {
+ color: #333;
+ font-size: 15px;
+ font-weight: bold;
+}
+
+.contentBold {
+ .labelBold;
+ flex: 1;
+}
diff --git a/src/routes/ClaimReviewApprove/DetailList/page.tsx b/src/routes/ClaimReviewApprove/DetailList/page.tsx
new file mode 100644
index 0000000..b2f1297
--- /dev/null
+++ b/src/routes/ClaimReviewApprove/DetailList/page.tsx
@@ -0,0 +1,373 @@
+/* eslint-disable max-lines */
+import { useEffect, useState, useMemo } from 'react';
+import { helper, PageProvider, PoolTable, usePagination, useUrlParams, FilePreview } from '@feewee/h5app-common';
+import { useNavigate } from '@modern-js/runtime/router';
+import { cloneDeep } from 'lodash';
+import dayjs from 'dayjs';
+
+import type { DimensionEnum, QueryTypeEnum } from '../entity';
+import { QueryItemTypeEnum, QueryItemTypeNameMap } from '../entity';
+import { reviewListApi, type ReviewListResult } from '../service';
+import rmb from '@/utils/rmb';
+
+interface PageParams {
+ applyId: number;
+ queryType: QueryTypeEnum;
+ queryItemType: QueryItemTypeEnum;
+ type: DimensionEnum | QueryTypeEnum.USER_PUNISH;
+ typeId: number;
+}
+
+/**
+ * 单数明细
+ */
+const DetailList = () => {
+ const params = useUrlParams();
+ const navigate = useNavigate();
+
+ const { queryType, queryItemType } = params;
+
+ // 添加了动态数据后的 list 和 columns
+ const [assembledList, setAssembledList] = useState([]);
+
+ const [delay, setDelay] = useState(true);
+ const { list, param, setParams, loading, errMsg, resetParam, pagination } = usePagination(reviewListApi, params, delay);
+ const { current = 1, pageSize = 15 } = param;
+
+ useEffect(() => {
+ if (params.applyId) {
+ setDelay(false);
+ setParams({ ...params, pageSize: 50 }, true);
+ }
+ }, []);
+
+ function renderSecondaryAmount(val: number) {
+ return (
+
+ {rmb.p(val)}元
+
+ );
+ }
+
+ const columns = useMemo(() => {
+ let baseColumns = [
+ {
+ title: '索赔单号',
+ dataIndex: 'claimNo',
+ width: 120,
+ },
+ {
+ title: '附件',
+ dataIndex: 'fid',
+ width: 150,
+ render: val => {/* */}
,
+ },
+ {
+ title: '索赔类型',
+ dataIndex: 'claimTypeName',
+ render: text => text || '--',
+ },
+ ];
+
+ // 根据 queryItemType 展示不同列
+ if ([QueryItemTypeEnum.SYSTEM_TOTAL, QueryItemTypeEnum.SYSTEM_ONLY].includes(queryItemType)) {
+ baseColumns = baseColumns.concat([
+ {
+ title: '车牌号',
+ dataIndex: 'plateNo',
+ render: text => text || '--',
+ },
+ {
+ title: '车架号',
+ dataIndex: 'vin',
+ render: text => text || '--',
+ },
+ {
+ title: '车辆名称',
+ dataIndex: 'carName',
+ render: text => text || '--',
+ },
+ {
+ title: '系统生成金额',
+ dataIndex: 'totalFee',
+ align: 'right',
+ render: renderSecondaryAmount,
+ },
+ {
+ title: '差异原因',
+ dataIndex: 'differenceReason',
+ render: text => text || '--',
+ },
+ ]);
+ } else if (queryItemType === QueryItemTypeEnum.IMPORT_ONLY) {
+ baseColumns = baseColumns.concat([
+ {
+ title: '厂家兑现金额',
+ dataIndex: 'amount',
+ width: 100,
+ align: 'right',
+ render: renderSecondaryAmount,
+ },
+ ]);
+ } else if (queryItemType === QueryItemTypeEnum.DIFFERENCE_COUNT) {
+ baseColumns = baseColumns.concat([
+ {
+ title: '系统生成金额',
+ dataIndex: 'totalFee',
+ align: 'center',
+ children: [
+ {
+ title: '小计',
+ dataIndex: 'totalFee',
+ width: 100,
+ align: 'right',
+ render: renderSecondaryAmount,
+ },
+ {
+ title: '工时费',
+ dataIndex: 'systemManHoursFee',
+ width: 100,
+ align: 'right',
+ render: renderSecondaryAmount,
+ },
+ {
+ title: '材料费',
+ dataIndex: 'systemPartFee',
+ width: 100,
+ align: 'right',
+ render: renderSecondaryAmount,
+ },
+ ],
+ },
+ {
+ title: '提报金额',
+ dataIndex: 'submitAmount',
+ align: 'center',
+ children: [
+ {
+ title: '小计',
+ dataIndex: 'submitAmount',
+ width: 100,
+ align: 'right',
+ render: renderSecondaryAmount,
+ },
+ {
+ title: '工时费',
+ dataIndex: 'submitManHoursFee',
+ width: 100,
+ align: 'right',
+ render: renderSecondaryAmount,
+ },
+ {
+ title: '材料费',
+ dataIndex: 'submitPartFee',
+ width: 100,
+ align: 'right',
+ render: renderSecondaryAmount,
+ },
+ ],
+ },
+ {
+ title: '厂家兑现金额',
+ dataIndex: 'factoryAmount', // @note 前端定义,仅作数据查找
+ align: 'center',
+ children: [
+ {
+ title: '小计',
+ dataIndex: 'amount',
+ width: 100,
+ align: 'right',
+ render: renderSecondaryAmount,
+ },
+ // @slot 存放 importData 中的数据
+ ],
+ },
+ {
+ title: '差异金额',
+ dataIndex: 'claimNo',
+ align: 'center',
+ children: [
+ {
+ title: '系统生成与厂家兑现差异',
+ dataIndex: 'differenceAmount',
+ width: 100,
+ align: 'right',
+ render: val => (
+
+ {rmb.p(val)}元
+
+ ),
+ },
+ {
+ title: '索赔提报与厂家兑现差异',
+ dataIndex: 'differenceSubmitAmount',
+ width: 100,
+ align: 'right',
+ render: val => (
+
+ {rmb.p(val)}元
+
+ ),
+ },
+ ],
+ },
+ {
+ title: '车牌号',
+ dataIndex: 'plateNo',
+ render: text => text || '--',
+ },
+ {
+ title: '车架号',
+ dataIndex: 'vin',
+ render: text => text || '--',
+ },
+ {
+ title: '车辆名称',
+ dataIndex: 'carName',
+ render: text => text || '--',
+ },
+ ]);
+ } else {
+ baseColumns = baseColumns.concat([
+ {
+ title: '车牌号',
+ dataIndex: 'plateNo',
+ render: text => text || '--',
+ },
+ {
+ title: '车架号',
+ dataIndex: 'vin',
+ render: text => text || '--',
+ },
+ {
+ title: '车辆名称',
+ dataIndex: 'carName',
+ render: text => text || '--',
+ },
+ {
+ title: '厂家兑现金额',
+ dataIndex: 'amount',
+ align: 'right',
+ render: renderSecondaryAmount,
+ },
+ {
+ title: '系统生成金额',
+ dataIndex: 'totalFee',
+ align: 'right',
+ render: renderSecondaryAmount,
+ },
+ {
+ title: '差异金额',
+ dataIndex: 'differenceAmount',
+ align: 'right',
+ render: val => (
+
+ {rmb.p(val)}元
+
+ ),
+ },
+ ]);
+ }
+
+ // 动态列:工时费、配件费、救援费等,差异时放到厂家兑现列中,其余情况追加在列后面
+ const extraColumns = [];
+ // 添加额外动态列数据
+ const newList = cloneDeep(list);
+ if (newList.length > 0) {
+ // 构建表头
+ if (newList[0].importData && ![QueryItemTypeEnum.SYSTEM_TOTAL, QueryItemTypeEnum.SYSTEM_ONLY].includes(queryItemType)) {
+ const { importData } = newList[0];
+ if (importData) {
+ try {
+ // { "工时费": 10, "配件费": 20, "救援费": 30, ... }
+ const data = JSON.parse(importData);
+ for (const key in data) {
+ extraColumns.push({
+ title: key,
+ dataIndex: key,
+ align: 'right',
+ width: 100,
+ render: val => {val},
+ });
+ }
+ } catch (e) {
+ console.error('parse importData fail:', e);
+ }
+ }
+ }
+
+ // 构建表格数据
+ // 2. 解析数据,若数据列有 importData 则解析为对象形式
+ for (let i = 0; i < newList.length; i++) {
+ if (newList[i].importData) {
+ try {
+ const data = JSON.parse(newList[i].importData);
+ Object.assign(newList[i], data);
+ } catch (e) {
+ console.error('parse importData fail:', e);
+ }
+ }
+ }
+
+ // 处理分页数据
+ if (current === 1) {
+ setAssembledList(newList);
+ } else {
+ // 替换当前页数据
+ const start = (current - 1) * pageSize;
+ const end = start + pageSize;
+ const newPageList = [...assembledList];
+ newPageList.splice(start, end - start, ...newList);
+ setAssembledList(newPageList);
+ }
+ }
+
+ // 跟进差异类型,添加额外列
+ if (queryItemType === QueryItemTypeEnum.DIFFERENCE_COUNT) {
+ for (const column of baseColumns) {
+ // @ts-ignore
+ if (column.dataIndex === 'factoryAmount') {
+ // @ts-ignore
+ column.children = column.children.concat(extraColumns);
+ break;
+ }
+ }
+ } else {
+ baseColumns = baseColumns.concat(extraColumns);
+ }
+
+ // 添加提报信息
+ baseColumns = baseColumns.concat([
+ {
+ title: '提报人',
+ dataIndex: 'claimer',
+ width: 80,
+ render: val => val || '--',
+ },
+ {
+ title: '提报商家',
+ dataIndex: 'submitDealerName',
+ render: val => val || '--',
+ },
+ {
+ title: '提报时间',
+ dataIndex: 'commitTime',
+ render: val => dayjs(val).format('YYYY-MM-DD HH:mm:ss'),
+ },
+ ]);
+ return baseColumns;
+ }, [queryType, queryItemType, list]);
+
+ return (
+ helper.checkBack(() => navigate(-1))}
+ >
+
+
+ );
+};
+
+export default DetailList;
diff --git a/src/routes/ClaimReviewApprove/entity.ts b/src/routes/ClaimReviewApprove/entity.ts
new file mode 100644
index 0000000..0507d44
--- /dev/null
+++ b/src/routes/ClaimReviewApprove/entity.ts
@@ -0,0 +1,109 @@
+export enum MatchStatusEnum {
+ /** 匹配一致 */
+ MATCH = 1,
+ /** 无工单记录 */
+ NO_ORDER = 2,
+ /** 匹配不一致 */
+ NOT_MATCH = 3,
+}
+
+export enum MatchStatusName {
+ /** 匹配一致 */
+ 匹配一致 = 1,
+ /** 无工单记录 */
+ 无工单 = 2,
+ /** 匹配不一致 */
+ 匹配差异 = 3,
+}
+
+export enum DimensionEnum {
+ /** 索赔类型 */
+ CLAIM_TYPE = 1,
+ /** 索赔人员 */
+ CLAIM_USER = 2,
+ /** 施工门店 */
+ CLAIM_SHOP = 3,
+ /** 差异原因 */
+ DIFFERENCE_REASON = 4,
+}
+
+export const DimensionData = [
+ {
+ value: DimensionEnum.CLAIM_TYPE,
+ title: '索赔类型',
+ },
+ {
+ value: DimensionEnum.CLAIM_USER,
+ title: '索赔人员',
+ },
+ {
+ value: DimensionEnum.CLAIM_SHOP,
+ title: '施工门店',
+ },
+ {
+ value: DimensionEnum.DIFFERENCE_REASON,
+ title: '差异原因',
+ },
+];
+
+export const DimensionNamesMap: Record = {
+ [DimensionEnum.CLAIM_TYPE]: '索赔类型',
+ [DimensionEnum.CLAIM_USER]: '索赔人员',
+ [DimensionEnum.CLAIM_SHOP]: '施工门店',
+ [DimensionEnum.DIFFERENCE_REASON]: '差异原因',
+};
+
+export enum TypeEnum {
+ /** 奖励 */
+ REWARD = 1,
+ /** 处罚 */
+ PUNISH = 0,
+}
+
+export enum SubTypeEnum {
+ /** 门店分摊 */
+ APPORTION = 1,
+ /** 门店 */
+ SHOP = 2,
+ /** 人员 */
+ USER = 3,
+}
+
+export const SubTypeNameMap = {
+ [SubTypeEnum.APPORTION]: '门店分摊',
+ [SubTypeEnum.SHOP]: '门店',
+ [SubTypeEnum.USER]: '人员',
+};
+
+export enum QueryTypeEnum {
+ /** 索赔 */
+ REVIEW_BEFORE = 1,
+ /** 差异 */
+ REVIEW_AFTER = 2,
+ /** 人员处罚 */
+ USER_PUNISH = 3,
+}
+
+export enum QueryItemTypeEnum {
+ /** 霏车车系统 */
+ SYSTEM_TOTAL = 1,
+ /** 系统有,导入无 */
+ SYSTEM_ONLY = 2,
+ /** 导入合计 */
+ TOTAL_COUNT = 3,
+ /** 一致 */
+ MATCH_COUNT = 4,
+ /** 差异 */
+ DIFFERENCE_COUNT = 5,
+ /** 系统无,导入有 */
+ IMPORT_ONLY = 6,
+}
+
+export const QueryItemTypeNameMap = {
+ [QueryItemTypeEnum.SYSTEM_TOTAL]: '霏车车系统单数',
+ [QueryItemTypeEnum.SYSTEM_ONLY]: '系统有,导入无单数',
+ [QueryItemTypeEnum.TOTAL_COUNT]: '提报单数',
+ [QueryItemTypeEnum.MATCH_COUNT]: '匹配一致单数',
+ [QueryItemTypeEnum.DIFFERENCE_COUNT]: '匹配差异单数',
+ [QueryItemTypeEnum.IMPORT_ONLY]: '系统无,导入有单数',
+};
diff --git a/src/routes/ClaimReviewApprove/page.tsx b/src/routes/ClaimReviewApprove/page.tsx
new file mode 100644
index 0000000..109888a
--- /dev/null
+++ b/src/routes/ClaimReviewApprove/page.tsx
@@ -0,0 +1,32 @@
+import { Button, helper, Toast, PageProvider } from '@feewee/h5app-common';
+import { Helmet } from '@modern-js/runtime/head';
+import { useNavigate } from '@modern-js/runtime/router';
+
+// 索赔复核审批 todo 待迁移
+function Index() {
+ const navigate = useNavigate();
+
+ return (
+ helper.checkBack(() => navigate(-1))}>
+
+
+
+
+
+
+ );
+}
+
+export default Index;
diff --git a/src/routes/ClaimReviewApprove/service.ts b/src/routes/ClaimReviewApprove/service.ts
new file mode 100644
index 0000000..fbe38cc
--- /dev/null
+++ b/src/routes/ClaimReviewApprove/service.ts
@@ -0,0 +1,345 @@
+import type { PromisePageResp, PageBaseParams } from '@feewee/h5app-common';
+import { host, http } from '@feewee/h5app-common';
+
+import type { DimensionEnum, MatchStatusEnum, QueryItemTypeEnum, QueryTypeEnum, SubTypeEnum, TypeEnum } from './entity';
+
+export interface DetailResult {
+ // 申请id
+ applyId: number;
+ // 文件id
+ fid: string;
+ // 文件名称
+ fName: string;
+ // 文件大小,单位b
+ fSize: number;
+ // 品牌名称
+ brandName: string;
+ // 往来单位名称
+ contactUnits: string;
+ // 申报商家 id
+ applyDealerId: number;
+ // 申报商家名称
+ applyDealerName: string;
+ // 匹配结果的最早提报时间
+ beginTime: number;
+ // 匹配结果的最晚提报时间
+ endTime: number;
+ // 未复核单数
+ notReviewedCount: number;
+ // 未复核金额
+ notReviewedAmount: number;
+ // 超60天未复核单数
+ overtimeNotReviewedCount: number;
+ // 厂家审核金额
+ amount: number;
+}
+
+export interface ClaimBeforeData {
+ // 类型
+ type: DimensionEnum;
+ // 类型id
+ typeId: number;
+ // 类型名称
+ typeName: string;
+ // 系统单数
+ systemCount: number;
+ // 系统金额
+ systemAmount: number;
+ // 系统有,导入无单数
+ notExistsCount: number;
+ // 系统有,导入无金额
+ notExistsAmount: number;
+ // 本次导入 合计单数
+ total: number;
+ // 本次导入 合计金额
+ totalAmount: number;
+ // 本次导入 匹配一致单数
+ consistentCount: number;
+ // 本次导入 匹配一致金额
+ consistentAmount: number;
+ // 本次导入 匹配不一致单数
+ nonConsistentCount: number;
+ // 本次导入 匹配不一致金额
+ nonConsistentAmount: number;
+ // 本次导入,系统无,导入有单数
+ importNonSystemCount: number;
+ // 本次导入,系统无,导入有金额
+ importNonSystemAmount: number;
+}
+
+export interface ClaimAfterData {
+ // 类型id
+ typeId: number;
+ // 类型名称
+ typeName: string;
+ // 差异单数
+ nonConsistentCount: number;
+ // 差异金额
+ nonConsistentAmount: number;
+ // 系统金额
+ systemAmount: number;
+ // 厂家金额
+ factoryAmount: number;
+}
+
+export interface PunishData {
+ // 人员id
+ userId: number;
+ // 人员名称
+ userName: number;
+ // 提报单数
+ submitCount: number;
+ // 差异单数
+ nonConsistentCount: number;
+ // 差异金额
+ nonConsistentAmount: number;
+ // 差异金额占比
+ nonConsistentRate: number;
+ // 处罚金额
+ punishAmount: number;
+ // 处罚绩效得分率
+ punishRate: number;
+}
+
+export interface FactoryPunishOrRewardData {
+ // 合计金额
+ totalAmount: number;
+ //
+ items: FactoryPunishOrRewardItem[];
+}
+
+export interface FactoryPunishOrRewardItem {
+ // 厂家奖励/处罚id
+ id: number;
+ // 文件名称
+ fName: string;
+ // 文件id
+ fid: string;
+ // 兑现方式
+ cashType: number;
+ // 处罚类型
+ projectTypeName: string;
+ // 金额
+ amount: number;
+ // 是否门店分摊
+ apportion: boolean;
+ // 是否门店
+ shop: boolean;
+ // 是否人员
+ user: boolean;
+}
+
+export interface FactoryPunishOrRewardTypeDetail {
+ // 对象id
+ targetId: number;
+ // 对象名称
+ targetName: string;
+ // 金额
+ amount: number;
+ // 比例
+ proportion: number;
+ // 绩效得分率
+ scoringRate: number;
+ // 岗位名称
+ postName: string;
+ // 在职门店名称
+ shopName: string;
+}
+
+export interface ReviewListParams extends PageBaseParams {
+ applyId: number;
+ type: DimensionEnum | QueryTypeEnum.USER_PUNISH;
+ typeId: number;
+ queryType: QueryTypeEnum;
+ queryItemType: QueryItemTypeEnum;
+ keywords?: string;
+}
+
+export interface ReviewListResult {
+ // 导入数据id
+ importDataId: number;
+ // 索赔单号
+ claimNo: string;
+ // 索赔类型
+ claimType: number;
+ // 索赔类型名称
+ claimTypeName: string;
+ // 复核附件
+ fid: string;
+ // 厂家兑现金额
+ amount: number;
+ // 系统生成-总金额
+ totalFee: number;
+ // 系统生成-工时费
+ systemManHoursFee: number;
+ // 系统生成-材料费
+ systemPartFee: number;
+ // 系统生成与厂家差异金额
+ differenceAmount: number;
+ // 提报-总金额
+ submitAmount: number;
+ // 提报-工时费
+ submitManHoursFee: number;
+ // 提报-材料费
+ submitPartFee: number;
+ // 提报-与厂家差异金额
+ differenceSubmitAmount: number;
+ // 上传其他信息:json格式
+ importData: string;
+ // 提报人
+ claimer: string;
+ // 提报商家名称
+ submitDealerName: string;
+ // 提报时间
+ commitTime: number;
+ // VIN
+ vin: string;
+ // 车牌号
+ plateNo: string;
+ // 车辆
+ carName: string;
+ // 差异原因
+ differenceReasonId: number;
+ differenceReason: string;
+ // 是否已复核 1: 未填写差异原因,2: 已填写差异原因
+ reviewStatus: number;
+}
+
+export interface DetailListParams {
+ importDataNo: string; // 导入明细编号,同一文件一致
+ claimNo?: string; // 索赔单号
+ distributorName?: string; // 经销商
+ vin?: string;
+ claimType?: number; // 索赔类型
+ matchStatus?: MatchStatusEnum; // 匹配状态,1:匹配一致,2:无工单记录,3:匹配不一致
+ current?: number;
+ pageSize?: number;
+}
+
+export interface DetailListResult {
+ id: number; // 复核 id
+ createTime: number; // 创建时间
+ updateTime: number; // 更新时间
+ createBy: string; // 创建人
+ updateBy: string; // 更新人
+ groupId: number; // 集团id
+ importDataNo: string; // 导入明细编号,同一文件一致
+ reviewAmount: number; // 复核后金额
+ differenceReason: string; // 差异原因, 1.工时费,材料费差异:2.厂家拒绝:3.漏报:4.其他4s店支付:5.家直接打款到公司账户;6.同一工单分多次提报;7.多个工单一次提报(See: 索赔数据不一致原因)
+ differenceReasonName: string; // 差异原因名称
+ distributorName: string; // 经销商
+ claimNo: string; // 索赔单号
+ vin: string; // 车架号
+ claimType: string; // 索赔类型
+ manHoursFee: number; // 工时费
+ partFee: number; // 配件费
+ rescueFee: number; // 救援费
+ totalFee: number; // 总结算费用
+ remark: string; // 复核备注
+ fids: string; // 附件ids
+ matchStatus: number; // 匹配状态,1: 匹配一致,2: 匹配不一致,3: 无工单记录(See: 索赔匹配状
+}
+
+export interface ReviewDetailResult {
+ claimOrderReviewData: ReviewData; // 复核数据
+ claimOrders: ClaimOrder[]; // 索赔单信息
+ punishes: ReviewPunish[]; // 处罚信息
+}
+
+export interface ReviewData {
+ id: number; // 主键
+ createTime: number; // 创建时间
+ updateTime: number; // 更新时间
+ createBy: string; // 创建人
+ updateBy: string; // 更新人
+ groupId: number; // 集团id
+ importDataNo: string; // 导入明细编号,同一文件一致
+ reviewAmount: number; // 复核后金额
+ differenceReason: string; // 差异原因, 1.工时费,材料费差异;2.厂家拒绝;3.漏报;4.其他4s店支付;5.厂家直接打款到公司账户;6.同一工单分多次提报;7.多个工单一次提报(See: 索赔数据不一致原因)
+ differenceReasonName: string; // 差异原因名称
+ distributorName: string; // 经销商
+ claimNo: string; // 索赔单号
+ vin: string; // 车架号
+ claimType: number; // 索赔类型
+ manHoursFee: number; // 工时费
+ partFee: number; // 配件费
+ rescueFee: number; // 救援费
+ totalFee: number; // 总结算费用
+ remark: string; // 复核备注
+ fids: string; // 附件ids
+ matchStatus: number; // 匹配状态,1: 匹配一致,2: 匹配不一致,3: 无工单记录(See: 索赔匹配状态)
+}
+
+export interface ClaimOrder {
+ type: number; // 三包类型(1:首保 2: 三包件5: 市场行动)
+ claimUsername: number; // 索赔确认/提报员工姓名
+ claimSubmitAmount: number; // 提报金额
+ claimOrderId: number; // 索赔单id
+ orderNo: number; // 工单号
+ ownerName: number; // 车主姓名
+ carName: number; // 车辆名称
+ vin: number; // 车辆vin码
+ plateNo: number; // 车牌号
+ specCode: number; // 车型代码
+ receiverName: number; // 接车人姓名
+ judgeNames: number; // 故障判断员
+}
+
+export interface ReviewPunish {
+ id: number; // 复核id
+ createTime: number; // 创建时间
+ updateTime: number; // 更新时间
+ dataId: number; // 索赔复核导入数据id
+ punishUserId: number; // 处罚人员id
+ punishUsername: string; // 处罚人员
+ punishAmount: number; // 处罚金额
+ achievements: number; // 处罚绩效
+ punishId: number; // 绩效系统id
+ shopId: number;
+ shopName: string;
+}
+
+// 详情
+export function detailApi(applyId: number): Promise {
+ return http.get(`${host.cas}/erp/claim/review/apply/detail`, { applyId });
+}
+
+// 复核前数据
+export function dataBeforeReviewApi(params: { applyId: number; type: DimensionEnum }): Promise {
+ return http.get(`${host.cas}/erp/claim/review/apply/before/review`, params);
+}
+
+// 复核后数据
+export function dataAfterReviewApi(params: { applyId: number; type: DimensionEnum }): Promise {
+ return http.get(`${host.cas}/erp/claim/review/apply/after/review`, params);
+}
+
+// 处罚信息
+export function punishListApi(applyId: number): Promise {
+ return http.get(`${host.cas}/erp/claim/review/apply/punish/list`, { applyId });
+}
+
+// 厂家处罚/奖励信息 1:奖励 2:处罚
+export function factoryPunishOrRewardListApi(params: { applyId: number; type: TypeEnum }): Promise {
+ return http.get(`${host.cas}/erp/claim/review/apply/factory/info`, params);
+}
+
+// 厂家处罚/奖励类型详情 1:门店分摊,2:门店,3:人员
+export function factoryPunishOrRewardTypeDetailApi(params: { id: number; type: SubTypeEnum }): Promise {
+ return http.get(`${host.cas}/erp/claim/review/apply/factory/info/detail`, params);
+}
+
+// 复核列表
+export function reviewListApi(params: ReviewListParams): PromisePageResp {
+ return http.get(`${host.cas}/erp/claim/review/apply/import/data/page`, params);
+}
+
+// 详情明细
+export function detailListApi(params: DetailListParams): PromisePageResp {
+ return http.get(`${host.cas}/erp/claim/order/review/data/list`, params);
+}
+
+// 复核详情
+export function reviewDetailApi(id: number): Promise {
+ return http.get(`${host.cas}/erp/claim/order/review/data/${id}`);
+}
diff --git a/src/routes/demo/page.tsx b/src/routes/demo/page.tsx
deleted file mode 100644
index 71797fa..0000000
--- a/src/routes/demo/page.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Helmet } from '@modern-js/runtime/head';
-import { ListRow, Button, Icon, IconFont, Space, PageProvider } from '@feewee/h5app-common';
-import { useSafeState } from 'ahooks';
-import { useEffect } from 'react';
-
-const Index = () => {
- const [loading, setLoading] = useSafeState(true);
-
- useEffect(() => {
- setTimeout(() => setLoading(false), 2500);
- }, []);
-
- return (
- <>
-
- {/* 这里面可以映入外部的一些样式或者js之类的,如果有需要的话。也可以调整head里的信息 */}
-
-
-
-
- demo 页面
- console.info('点击事件')} />
-
-
-
-
-
-
-
- >
- );
-};
-
-export default Index;
diff --git a/src/routes/page.tsx b/src/routes/page.tsx
index d9f165c..fa5ea5c 100644
--- a/src/routes/page.tsx
+++ b/src/routes/page.tsx
@@ -1,20 +1,21 @@
-import { Button, Toast } from '@feewee/h5app-common';
-import { Helmet } from '@modern-js/runtime/head';
+import { Button, PageProvider, Toast } from '@feewee/h5app-common';
import { useNavigate } from '@modern-js/runtime/router';
function Index() {
const navigate = useNavigate();
return (
- <>
-
-
-
+
- 这是首页
-
- >
+
);
}
diff --git a/src/style/global.scss b/src/style/global.scss
index aa857d8..ab87728 100644
--- a/src/style/global.scss
+++ b/src/style/global.scss
@@ -51,3 +51,7 @@ body {
height: 100%;
}
}
+
+.bg-color {
+ background-color: #f4f6fa;
+}
diff --git a/src/utils/rmb.ts b/src/utils/rmb.ts
new file mode 100644
index 0000000..133ef46
--- /dev/null
+++ b/src/utils/rmb.ts
@@ -0,0 +1,30 @@
+import currency from 'currency.js';
+
+type RMBOption = { price?: number; symbol?: boolean; precision?: boolean };
+
+// 人民币格式化
+const RMB = ({ price = 0, symbol = true, precision = true }: RMBOption) => {
+ return currency(price, {
+ symbol: symbol ? '¥' : '',
+ precision: precision ? 2 : 0,
+ }).format();
+};
+
+// 人民币格式化-不包含符号和小数
+const rmb = (price?: number) => RMB({ price, symbol: false, precision: false });
+
+// 人民币格式化-包含符号,不包含小数
+const rmbS = (price?: number) => RMB({ price, precision: false });
+
+// 人民币格式化-包含小数,不包含符号
+const rmbP = (price?: number) => RMB({ price, symbol: false });
+
+// 人民币格式化-包含符号和小数
+const rmbSP = (price?: number) => RMB({ price });
+
+export default {
+ _: rmb,
+ s: rmbS,
+ p: rmbP,
+ sp: rmbSP,
+};