供应商过坐台地区回显
This commit is contained in:
@ -3,18 +3,64 @@ import { Cascader, Spin } from 'antd';
|
||||
import type { DefaultOptionType } from 'antd/es/cascader';
|
||||
import { getChild } from './services';
|
||||
|
||||
// 只用函数式组件的 props,不声明泛型
|
||||
const DictRegionSelect: React.FC<Partial<import('antd').CascaderProps<DefaultOptionType>>> = (props) => {
|
||||
const [options, setOptions] = useState<DefaultOptionType[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// 处理回显的所有级联节点
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
fetchRegionOptions('0').then(data => {
|
||||
setOptions(data);
|
||||
setLoading(false);
|
||||
});
|
||||
}, []);
|
||||
let destroyed = false;
|
||||
// 只在有初始值时触发自动懒加载
|
||||
async function loadAllLevels() {
|
||||
setLoading(true);
|
||||
// props.value 是 [省, 市, 区] 的 id 数组
|
||||
const path = (props.value as string[]) || [];
|
||||
let currentPid = '0';
|
||||
let currentOptions: DefaultOptionType[] = [];
|
||||
let optionLevel = [];
|
||||
let parentOptions = currentOptions;
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
// 拉取本级所有 children
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const children = await fetchRegionOptions(currentPid);
|
||||
// 新建 option 节点
|
||||
const optionNodes = children.map(child => ({
|
||||
...child,
|
||||
children: undefined, // 只有下一步才补
|
||||
}));
|
||||
// 当前级别节点加入到 options 树
|
||||
if (i === 0) {
|
||||
// 顶级直接 set
|
||||
currentOptions = optionNodes;
|
||||
} else {
|
||||
// 找到父节点,挂到父节点 children
|
||||
let parent = parentOptions.find(opt => opt.value === path[i - 1]);
|
||||
if (parent) parent.children = optionNodes;
|
||||
}
|
||||
// 记录本级 option,下一轮用于找 parent
|
||||
parentOptions = optionNodes;
|
||||
currentPid = path[i];
|
||||
}
|
||||
if (!destroyed) {
|
||||
setOptions(currentOptions);
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有 value,并且是懒加载(options 为空或只有顶级)
|
||||
if (Array.isArray(props.value) && props.value.length > 0) {
|
||||
loadAllLevels();
|
||||
} else {
|
||||
// 首次只拉顶级
|
||||
setLoading(true);
|
||||
fetchRegionOptions('0').then(data => {
|
||||
setOptions(data);
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
return () => { destroyed = true; };
|
||||
// eslint-disable-next-line
|
||||
}, [props.value]);
|
||||
|
||||
const loadData = async (selectedOptions: DefaultOptionType[]) => {
|
||||
const targetOption = selectedOptions[selectedOptions.length - 1];
|
||||
@ -26,8 +72,6 @@ const DictRegionSelect: React.FC<Partial<import('antd').CascaderProps<DefaultOpt
|
||||
};
|
||||
|
||||
const fetchRegionOptions = async (pId: string | number): Promise<DefaultOptionType[]> => {
|
||||
console.log(pId,'pId');
|
||||
|
||||
const res = await getChild({ pId });
|
||||
if (res && res.code === 200 && Array.isArray(res.data)) {
|
||||
return res.data.map((item: any) => ({
|
||||
@ -39,11 +83,10 @@ const DictRegionSelect: React.FC<Partial<import('antd').CascaderProps<DefaultOpt
|
||||
return [];
|
||||
};
|
||||
|
||||
// 明确指定 loadData 类型,解决 ts 推断
|
||||
const cascaderProps = {
|
||||
changeOnSelect: true,
|
||||
options,
|
||||
loadData: loadData as (selectedOptions: DefaultOptionType[]) => void, // 关键类型断言!
|
||||
loadData: loadData as (selectedOptions: DefaultOptionType[]) => void,
|
||||
placeholder: "请选择地区",
|
||||
...props,
|
||||
};
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Modal, Form, Input, message, Row, Col, Descriptions, Select } from 'antd';
|
||||
import { getDictList } from '@/servers/api/dicts';
|
||||
import { bankView, bankAdd, bankEdit } from '../services';
|
||||
import { bankView, bankAdd, bankEdit } from '../services';
|
||||
import type { DictItem } from '@/servers/api/dicts';
|
||||
import DictRegionSelect from '@/components/CommonSelect/DictRegionSelect'
|
||||
|
||||
import { dictRegion } from '@/servers/api/user'
|
||||
interface props {
|
||||
visible: boolean;
|
||||
onOk: () => void;
|
||||
@ -49,6 +49,11 @@ const InvoiceFormModal: React.FC<props> = ({
|
||||
//提交防抖
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [currency, setCurrency] = useState<DictItem[]>([]);
|
||||
//币种
|
||||
const [currencyMap, setCurrencyMap] = useState<{ [code: string]: string }>({});
|
||||
const [nationName, setNationName] = useState('');
|
||||
const [provinceName, setProvinceName] = useState('');
|
||||
const [cityName, setCityName] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
@ -60,23 +65,36 @@ const InvoiceFormModal: React.FC<props> = ({
|
||||
...data,
|
||||
id: data.id ? data.id : null,
|
||||
address: [
|
||||
Number(data.nation),
|
||||
Number(data.province),
|
||||
Number(data.city),
|
||||
]
|
||||
data.nation ? String(data.nation) : undefined,
|
||||
data.province ? String(data.province) : undefined,
|
||||
data.city ? String(data.city) : undefined,
|
||||
]
|
||||
};
|
||||
console.log(fields);
|
||||
|
||||
form.setFieldsValue(fields);
|
||||
setViewData(fields);
|
||||
|
||||
if (data.nation) dictRegion(data.nation).then(r => setNationName(r?.data?.name || ''));
|
||||
if (data.province) dictRegion(data.province).then(r => setProvinceName(r?.data?.name || ''));
|
||||
if (data.city) dictRegion(data.city).then(r => setCityName(r?.data?.name || ''));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
setViewData({});
|
||||
setNationName('');
|
||||
setProvinceName('');
|
||||
setCityName('');
|
||||
}
|
||||
|
||||
getDictList('currency').then((res) => {
|
||||
if (res.code === 200) {
|
||||
const map: { [code: string]: string } = {};
|
||||
res.data.forEach((item: { code: string, dicName: string }) => {
|
||||
map[item.code] = item.dicName;
|
||||
});
|
||||
setCurrencyMap(map);
|
||||
setCurrency(res.data);
|
||||
}
|
||||
});
|
||||
@ -121,7 +139,13 @@ const InvoiceFormModal: React.FC<props> = ({
|
||||
setSubmitting(false); // 无论成功失败都解锁
|
||||
}
|
||||
};
|
||||
|
||||
const fetchRegionNames = async (codes: string) => {
|
||||
console.log(codes,'codes');
|
||||
|
||||
const { data } = await dictRegion(codes);
|
||||
console.log(data);
|
||||
|
||||
};
|
||||
return (
|
||||
<Modal
|
||||
title={readOnly ? '查看' : initialValues ? '修改' : '新增'}
|
||||
@ -143,17 +167,17 @@ const InvoiceFormModal: React.FC<props> = ({
|
||||
<Descriptions.Item label="账户名称">{viewData.accountName}</Descriptions.Item>
|
||||
<Descriptions.Item label="开户银行">{viewData.bank}</Descriptions.Item>
|
||||
<Descriptions.Item label="联行号">{viewData.interbankNumber}</Descriptions.Item>
|
||||
<Descriptions.Item label="国家/地区">{viewData.nationName}</Descriptions.Item>
|
||||
<Descriptions.Item label="省份">{viewData.provinceName}</Descriptions.Item>
|
||||
<Descriptions.Item label="城市">{viewData.cityName}</Descriptions.Item>
|
||||
<Descriptions.Item label="币种">{viewData.currency}</Descriptions.Item>
|
||||
<Descriptions.Item label="国家/地区">{nationName || viewData.nation}</Descriptions.Item>
|
||||
<Descriptions.Item label="省份">{provinceName || viewData.province}</Descriptions.Item>
|
||||
<Descriptions.Item label="城市">{cityName || viewData.city}</Descriptions.Item>
|
||||
<Descriptions.Item label="币种">{currencyMap[viewData.currency as string] || viewData.currency}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
) : (
|
||||
<Form form={form} labelCol={{ flex: '120px' }} wrapperCol={{ flex: 1 }}>
|
||||
<Row gutter={24}>
|
||||
<Col span={24}>
|
||||
<Form.Item name="account" label="开户账号" rules={[{ required: true }]}>
|
||||
<Input placeholder='请输入开户账号' />
|
||||
<Input placeholder='请输入开户账号' />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
|
@ -1,9 +1,11 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Table, Button, message, Switch } from 'antd';
|
||||
import { Table, Button, message, Switch, Spin } from 'antd';
|
||||
import type { ColumnsType, TablePaginationConfig } from 'antd/es/table';
|
||||
import { bankGetPage, bankEdit } from '../services';
|
||||
import { useIntl } from 'umi';
|
||||
import BankFormModal from './BankFormModal';
|
||||
import { dictRegion } from '@/servers/api/user'
|
||||
import { getDictList } from '@/servers/api/dicts';
|
||||
|
||||
interface BankInfo {
|
||||
id: string;
|
||||
@ -23,6 +25,24 @@ interface Props {
|
||||
viewType?: boolean;
|
||||
record?: string;
|
||||
}
|
||||
|
||||
const codeNameCache = new Map<string, string>();
|
||||
const fetchRegionNames = async (codes: string[]) => {
|
||||
const waitCodes = codes.filter(code => code && !codeNameCache.has(code));
|
||||
if (waitCodes.length === 0) return;
|
||||
// 批量接口推荐你后端支持,单个请求也兼容如下
|
||||
await Promise.all(waitCodes.map(async (code) => {
|
||||
try {
|
||||
const { code: status, data } = await dictRegion(code);
|
||||
if (status === 200 && data && data.name) {
|
||||
codeNameCache.set(code, data.name);
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
}));
|
||||
};
|
||||
|
||||
|
||||
|
||||
const BankInfoTab: React.FC<Props> = (props) => {
|
||||
const userId = sessionStorage.getItem('userId') || '';
|
||||
const { viewType = false, record = userId } = props;
|
||||
@ -34,6 +54,8 @@ const BankInfoTab: React.FC<Props> = (props) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
//列表分页
|
||||
const [pagination, setPagination] = useState<TablePaginationConfig>({ current: 1, pageSize: 10, total: 0 });
|
||||
//币种
|
||||
const [currencyMap, setCurrencyMap] = useState<{ [code: string]: string }>({});
|
||||
//列表方法
|
||||
const getList = async (pageNo: number = 1, pageSize: number = 10) => {
|
||||
setLoading(true);
|
||||
@ -74,10 +96,11 @@ const BankInfoTab: React.FC<Props> = (props) => {
|
||||
setIsViewMode(true);
|
||||
setFormVisible(true);
|
||||
};
|
||||
|
||||
//是否作废
|
||||
const handleObsoleteChange = async (checked: boolean, id:string) => {
|
||||
const handleObsoleteChange = async (checked: boolean, id: string) => {
|
||||
// 调用你的作废接口
|
||||
const res = await bankEdit( { id, delFlag: checked? 'normal':'deleted' } );
|
||||
const res = await bankEdit({ id, delFlag: checked ? 'normal' : 'deleted' });
|
||||
if (res.code === 200) {
|
||||
message.success('操作成功');
|
||||
getList(pagination.current, pagination.pageSize); // 刷新列表
|
||||
@ -87,10 +110,48 @@ const BankInfoTab: React.FC<Props> = (props) => {
|
||||
}
|
||||
//初始化
|
||||
useEffect(() => {
|
||||
if(record) {
|
||||
if (record) {
|
||||
getDictList('currency').then((res) => {
|
||||
if (res.code === 200) {
|
||||
const map: { [code: string]: string } = {};
|
||||
res.data.forEach((item: { code:string, dicName: string }) => {
|
||||
map[item.code] = item.dicName;
|
||||
});
|
||||
setCurrencyMap(map);
|
||||
}
|
||||
});
|
||||
getList();
|
||||
}
|
||||
}, [record]);
|
||||
|
||||
const [regionLoading, setRegionLoading] = useState(false);
|
||||
const [, forceUpdate] = useState({}); // 用于触发重新渲染
|
||||
|
||||
// 新增一个 effect,当 data 变化时批量请求
|
||||
useEffect(() => {
|
||||
// 收集所有 nation、province、city 的 code
|
||||
const codes: string[] = [];
|
||||
data.forEach(item => {
|
||||
if (item.nation) codes.push(item.nation);
|
||||
if (item.province) codes.push(item.province);
|
||||
if (item.city) codes.push(item.city);
|
||||
});
|
||||
// 查缓存,没有再查接口
|
||||
setRegionLoading(true);
|
||||
fetchRegionNames(codes).then(() => {
|
||||
setRegionLoading(false);
|
||||
forceUpdate({}); // 强制刷新
|
||||
});
|
||||
}, [data]);
|
||||
// 通用渲染
|
||||
const renderRegionName = (code: string) => {
|
||||
if (!code) return '';
|
||||
if (codeNameCache.has(code)) {
|
||||
return codeNameCache.get(code);
|
||||
}
|
||||
return <Spin size="small" />;
|
||||
};
|
||||
|
||||
// 表格头部
|
||||
const columns: ColumnsType<BankInfo> = [
|
||||
{
|
||||
@ -123,23 +184,27 @@ const BankInfoTab: React.FC<Props> = (props) => {
|
||||
},
|
||||
{
|
||||
title: 'page.workbench.bank.currency',
|
||||
dataIndex: 'currencyName',
|
||||
key: 'currency', ellipsis: true
|
||||
dataIndex: 'currency',
|
||||
key: 'currency', ellipsis: true,
|
||||
render: (code: string) => currencyMap[code] || code
|
||||
},
|
||||
{
|
||||
title: 'page.workbench.bank.nation',
|
||||
dataIndex: 'nationName',
|
||||
key: 'nation', ellipsis: true
|
||||
dataIndex: 'nation',
|
||||
key: 'nation', ellipsis: true,
|
||||
render: renderRegionName,
|
||||
},
|
||||
{
|
||||
title: 'page.workbench.bank.province',
|
||||
dataIndex: 'provinceName',
|
||||
key: 'province', ellipsis: true
|
||||
dataIndex: 'province',
|
||||
key: 'province', ellipsis: true,
|
||||
render: renderRegionName,
|
||||
},
|
||||
{
|
||||
title: 'page.workbench.bank.city',
|
||||
dataIndex: 'cityName',
|
||||
key: 'city', ellipsis: true
|
||||
dataIndex: 'city',
|
||||
key: 'city', ellipsis: true,
|
||||
render: renderRegionName,
|
||||
},
|
||||
{
|
||||
title: 'page.workbench.bank.updateTime',
|
||||
@ -172,8 +237,8 @@ const BankInfoTab: React.FC<Props> = (props) => {
|
||||
<>
|
||||
<a style={{ marginRight: 8 }} onClick={() => handleView(record)}>查看</a>
|
||||
{record.delFlag === 'normal' && (
|
||||
<a onClick={() => handleEdit(record)}>修改</a>
|
||||
)}
|
||||
<a onClick={() => handleEdit(record)}>修改</a>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
},
|
||||
|
@ -4,7 +4,7 @@ import type { ColumnsType, TablePaginationConfig } from 'antd/es/table';
|
||||
import { invoiceGetPage, invoiceEdit } from '../services';
|
||||
import { useIntl } from 'umi';
|
||||
import InvoiceFormModal from './InvoiceFormModal';
|
||||
|
||||
import { getDictList } from '@/servers/api/dicts';
|
||||
interface InvoiceInfo {
|
||||
id: string;
|
||||
taxpayerType: string;
|
||||
@ -76,10 +76,10 @@ const InvoiceTab: React.FC<InvoiceTabProps> = (props) => {
|
||||
setIsViewMode(true);
|
||||
setFormVisible(true);
|
||||
};
|
||||
//是否作废
|
||||
const handleObsoleteChange = async (checked: boolean, id:string) => {
|
||||
//是否作废
|
||||
const handleObsoleteChange = async (checked: boolean, id: string) => {
|
||||
// 调用你的作废接口
|
||||
const res = await invoiceEdit( { id, delFlag: checked? 'normal':'deleted' } );
|
||||
const res = await invoiceEdit({ id, delFlag: checked ? 'normal' : 'deleted' });
|
||||
if (res.code === 200) {
|
||||
message.success('操作成功');
|
||||
getList(pagination.current, pagination.pageSize); // 刷新列表
|
||||
@ -87,16 +87,27 @@ const InvoiceTab: React.FC<InvoiceTabProps> = (props) => {
|
||||
message.error('操作失败');
|
||||
}
|
||||
}
|
||||
const [taxpayerTypeMap, setTaxpayerTypeMap] = useState<{ [code: string]: string }>({});
|
||||
//初始化
|
||||
useEffect(() => {
|
||||
if(record) {
|
||||
if (record) {
|
||||
getDictList('taxpayer_type').then((res) => {
|
||||
if (res.code === 200) {
|
||||
const map: { [code: string]: string } = {};
|
||||
res.data.forEach((item: { code: string, dicName: string }) => {
|
||||
map[item.code] = item.dicName;
|
||||
});
|
||||
setTaxpayerTypeMap(map);
|
||||
}
|
||||
});
|
||||
getList();
|
||||
}
|
||||
}, [record]);
|
||||
|
||||
|
||||
const columns: ColumnsType<InvoiceInfo> = [
|
||||
{ title: 'page.workbench.invoice.index', dataIndex: 'index', width: 80, key: 'index', render: (_: any, __: any, index: number) => index + 1 },
|
||||
{ title: 'page.workbench.invoice.taxpayerType', dataIndex: 'taxpayerTypeCn', ellipsis: true },
|
||||
{ title: 'page.workbench.invoice.taxpayerType', dataIndex: 'taxpayerType', ellipsis: true, render: (code: string) => taxpayerTypeMap[code] || code },
|
||||
{ title: 'page.workbench.invoice.taxpayerCode', dataIndex: 'taxpayerCode', ellipsis: true },
|
||||
{ title: 'page.workbench.invoice.head', dataIndex: 'head', ellipsis: true },
|
||||
{ title: 'page.workbench.invoice.address', dataIndex: 'address', ellipsis: true },
|
||||
@ -136,8 +147,8 @@ const InvoiceTab: React.FC<InvoiceTabProps> = (props) => {
|
||||
<>
|
||||
<a style={{ marginRight: 8 }} onClick={() => handleView(record)}>查看</a>
|
||||
{record.delFlag === 'normal' && (
|
||||
<a onClick={() => handleEdit(record)}>修改</a>
|
||||
)}
|
||||
<a onClick={() => handleEdit(record)}>修改</a>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
},
|
||||
|
@ -11,3 +11,23 @@ export async function getUserList(params: API.UserListRequest) {
|
||||
params,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 获取全国列表
|
||||
* @param params 查询参数
|
||||
* @returns 全国列表响应
|
||||
*/
|
||||
export async function dictRegion(code:string) {
|
||||
return request(`/v1/dictRegion/${code}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 获取全球列表
|
||||
* @param params 查询参数
|
||||
* @returns 全球列表响应
|
||||
*/
|
||||
export async function dictRegionInternational(code:string) {
|
||||
return request(`/v1/dictRegionInternational/${code}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user