123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- /*
- * @Author: code4eat awesomedema@gmail.com
- * @Date: 2024-03-06 10:43:05
- * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-06-20 21:03:12
- * @FilePath: /CostAccountingSys/src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/match.tsx
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
- import { KCIMTable } from "@/components/KCIMTable";
- import ProgressModal from "@/components/ProgressModal";
- import { createFromIconfontCN } from "@ant-design/icons";
- import { ProColumns, ProFormText } from "@ant-design/pro-components";
- import { Progress, message, Modal, Skeleton } from 'antd';
- import { useEffect, useState } from "react";
- import { getAllNeedMatchItems, getMatchCount, getReferralMatch, getSingleItem, mapItemAndStandItem, matchRequest } from "../service";
- import './style.less';
- const IconFont = createFromIconfontCN({
- scriptUrl: '',
- });
- interface SignalBarProps {
- level: number; // 信号强度级别,通常在0-4之间
- }
- const SignalBar: React.FC<SignalBarProps> = ({ level }) => {
- const maxLevel = 5;
- const signalLevel = Math.round(level * maxLevel); // 现在signalLevel是0到4之间的整数
- const signalBars = [];
- for (let i = 0; i < maxLevel; i++) {
- signalBars.push(
- <div
- key={i}
- className={`signal-bar ${i < signalLevel ? 'active' : ''}`}
- style={{
- marginLeft: i > 0 ? '2px' : undefined,
- height: `${8 + (i * 2)}px`, // 使每个条更高一些
- // 定义更多样式...
- }}
- />
- );
- }
- return <div className="signal-container">{signalBars}</div>;
- };
- export const MatchPage = (props: any) => {
- const { record, single = true, closeDrawer, switchBatchHandle } = props;
- const [matchItemInfo, set_matchItemInfo] = useState<undefined | any>(undefined);
- const [allNeedMatchList, set_allNeedMatchList] = useState<any[]>([]);
- const [allStandItem, set_allStandItem] = useState<any[]>([]);
- const [matchStandItem, set_matchStandItem] = useState<any[]>([]);
- const [dataSource, set_dataSource] = useState<any[]>([]);
- const [chargeItemTabledataSource, set_chargeItemTabledataSource] = useState<any[]>([]);
- const [searchText, setSearchText] = useState('');
- const [chargeItemSearchText, setChargeItemSearchText] = useState('');
- const [countInfo, set_countInfo] = useState<undefined | any>(undefined);
- const [currentTablePage, set_currentTablePage] = useState(1);
- const [openTable, set_openTable] = useState(false);
- const [isProgressModalVisible, set_isProgressModalVisible] = useState(false);
- const [loading, set_loading] = useState(true);
- const leftTableColumns = [
- {
- title: '标准项目编码',
- dataIndex: 'code',
- },
- {
- title: '标准项目名称',
- dataIndex: 'name',
- },
- {
- title: '康程分类',
- dataIndex: 'kcClassName',
- },
- {
- title: '操作',
- key: 'option',
- width: 80,
- valueType: 'option',
- render: (_: any, data: any) => {
- const { code } = data;
- return code != matchItemInfo?.standItemCode ? [
- <span key='btn' onClick={() => matchRequestHandle(data,1)} style={{
- display: 'inline-block', width: 56, height: 24, cursor: 'pointer',
- backgroundColor: '#FAFCFF', borderRadius: 4, border: '1px solid #DAE2F2', textAlign: 'center', color: '#17181A'
- }}>匹配</span>
- ] : [
- <span key='btn' style={{ fontWeight: 500, fontSize: 14, color: '#00BF8F' }}>当前匹配</span>
- ]
- },
- },
- ];
- const chargeTableColumns: ProColumns[] = [
- {
- title: '编号',
- width: 80,
- dataIndex: 'id',
- },
- {
- title: '收费项目编码',
- dataIndex: 'code',
- },
- {
- title: '收费项目名称',
- dataIndex: 'name',
- },
- {
- title: '状态',
- dataIndex: 'match',
- width: 90,
- renderText(bool, record, index, action) {
- return <>{bool ? <span style={{ fontSize: 14, color: '#17181A' }}>已匹配</span> : <span style={{ fontSize: 14, color: '#FF8C19' }}>待匹配</span>}{matchItemInfo?.code == record.code && <IconFont style={{ color: '#3377FF', display: 'inline-block', marginLeft: 16 }} type="iconqueren" />}</>
- },
- },
- ]
- const getMatchInfo = async () => {
- const { code } = record;
- const resp = await getSingleItem(code,record.departmentCode);
- if (resp) {
- set_matchItemInfo(resp);
- }
- }
- const getNeedMatchList = async () => {
- const resp = await getAllNeedMatchItems();
- if (resp) {
- set_allNeedMatchList(resp);
- }
- }
- const getReferralMatchHandle = async () => {
- set_loading(true);
- const { code,departmentCode } = matchItemInfo;
- const resp = await getReferralMatch(code,single?record.departmentCode:departmentCode);
- if (resp) {
- const { allStandItem: all = [], matchStandItem: match = [] } = resp;
- const temp = [...all];
- const index = temp.findIndex((item: any) => item.code == matchItemInfo.standItemCode);
- if (index !== -1) {
- // 如果找到了符合条件的项,先将其从数组中移除
- const [item] = temp.splice(index, 1);
- // 然后将其添加到数组的开头
- temp.unshift(item);
- }
- set_allStandItem([...temp]);
- set_matchStandItem(match?Array.from(new Map(match.map((a: any) => [a.code, a])).values()):[]);
- set_dataSource([...all]);
- set_loading(false);
- }
- }
- const switchNeddMatchItem = async (flag: number) => {
- const currentIndex = allNeedMatchList.findIndex((a) => a.code == matchItemInfo.code);
- if ((currentIndex == allNeedMatchList.length - 1) && flag > 0) {
- message.info('已经是最后一项!');
- return;
- }
- if ((currentIndex == 0) && flag < 0) {
- message.info('没有上一项!');
- return;
- }
-
- let next = undefined;
- if (flag > 0) {
- for (const item of [...allNeedMatchList].splice(currentIndex + 1, allNeedMatchList.length)) {
- if (!item.match) {
- next = item
- break; // 满足条件后退出循环
- }
- }
- }
- if (flag < 0) {
- for (const item of ([...allNeedMatchList].splice(0, currentIndex)).reverse()) {
- if (!item.match) {
- next = item
- break; // 满足条件后退出循环
- }
- }
- }
- // console.log({switchNeddMatchItem,currentIndex,next});
- if (next) {
- set_matchItemInfo(next);
- } else {
- message.info('未找到未匹配项!');
- getMatchInfo();
- getNeedMatchList();
- }
- }
- const matchRequestHandle = async (data: any,type:number) => {
-
- try {
- const { code: itemCode,departmentCode } = matchItemInfo;
- const { code: standItemCode } = data;
- const resp = await matchRequest(itemCode, standItemCode,type,departmentCode);
- if (resp) {
- if (!single) {
- switchNeddMatchItem(1);
- getNeedMatchList();
- } else {
- getMatchInfo();
- getNeedMatchList();
- }
- }
- } catch (error) {
- console.log('matchRequestHandle_error', error);
- }
- }
- const getRightsInfo = async () => {
- const resp = await getMatchCount();
- if (resp) {
- set_countInfo(resp);
- }
- }
- const openTableHandle = (bool: boolean) => {
- if (bool) {
- const currentIndex = allNeedMatchList.findIndex((a) => a.code == matchItemInfo.code);
- set_currentTablePage(Math.ceil((currentIndex + 1) / 10));
- set_chargeItemTabledataSource([...allNeedMatchList]);
- }
- set_openTable(bool);
- }
- const startBatchCalc = async () => {
- set_isProgressModalVisible(true);
- const resp = await mapItemAndStandItem();
- if (resp) {
- set_isProgressModalVisible(false);
- }
- }
- const mapBtnHandle = async () => {
- Modal.confirm({
- title: '注意',
- content: '对照操作只会自动匹配未对照的项目,是否继续操作?',
- okText: '确定',
- cancelText: '取消',
- onOk: (...args) => {
- startBatchCalc();
- },
- })
- }
- const goMatch = () => {
- getReferralMatchHandle()
- }
- useEffect(() => {
- if (matchItemInfo) {
- getReferralMatchHandle();
- getRightsInfo();
- }
- }, [matchItemInfo]);
- useEffect(() => {
- const filteredData = allStandItem.filter((item) => {
- return item.code.includes(searchText) || item.name.includes(searchText);
- });
- set_dataSource(filteredData);
- }, [searchText, allStandItem]);
- useEffect(() => {
- const filteredData = allNeedMatchList.filter((item) => {
- return item.code.includes(chargeItemSearchText) || item.name.includes(chargeItemSearchText);
- });
- set_chargeItemTabledataSource(filteredData);
- }, [chargeItemSearchText]);
- useEffect(() => {
- if (!single) getRightsInfo();
- }, [single]);
- useEffect(() => {
- if (record) {
- getMatchInfo();
- getNeedMatchList();
- }
- }, [record])
- return (
- <div className="matchPage">
- <ProgressModal
- title="正在匹配"
- type={'ITEM_BATCH_MATCH'}
- onComplete={() => {
- getMatchInfo();
- getNeedMatchList();
- }}
- visible={isProgressModalVisible}
- />
- {
- single && (
- <div className="header">
- <div className="title">{record ? record.standItemName : '项目'}</div>
- <div className="btnGroup">
- <IconFont onClick={() => { closeDrawer() }} type="iconquxiao" style={{ color: '#17181A', marginRight: 8, cursor: 'pointer', fontSize: 21 }} />
- </div>
- </div>
- )
- }
- <div className="content" style={{ padding: single ? 16 : 0 }}>
- <div className="left">
- <div className="leftRowOne">
- {
- !single && (
- <div className="leftRowOneHeader">
- <div className="menu">
- <IconFont type="iconliebiao" style={{ color: '#17181A', marginRight: 8, cursor: 'pointer' }} onClick={() => openTableHandle(!openTable)} />
- 当前项目:{matchItemInfo?.id}
- </div>
- <div className="btnGroup">
- <div className="backPrev btns" onClick={() => { switchBatchHandle && switchBatchHandle(false) }}>返回上一层</div>
- <div className="line"></div>
- <div className="prev btns" onClick={() => switchNeddMatchItem(-1)}>上一项</div>
- <div className="next btns" onClick={() => switchNeddMatchItem(1)}>下一项</div>
- </div>
- {
- openTable && (
- <div className="floatTable" style={{ width: 432 }}>
- <div style={{ marginBottom: 12 }}>
- <div style={{ marginBottom: 12 }}>
- <ProFormText noStyle placeholder={'收费项目编码、名称'}
- fieldProps={{
- // value: keyword,
- suffix: <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" />,
- onChange: (e) => {
- if (e.target.value.length != 0) {
- setChargeItemSearchText(e.target.value);
- } else {
- setChargeItemSearchText('');
- }
- }
- }}
- />
- </div>
- <KCIMTable columns={chargeTableColumns}
- options={{
- density: true,
- setting: {
- listsHeight: 100,
- },
- }}
- dataSource={[...chargeItemTabledataSource]}
- rowKey={'id'}
- onRow={(record) => {
- return {
- onClick: () => { set_matchItemInfo(record); set_openTable(false) }
- }
- }}
- tableAlertRender={false}
- rowClassName={(record) => record.code == matchItemInfo.code ? 'match' : ''}
- pagination={{ showTitle: false, showSizeChanger: true, simple: true, defaultPageSize: 10, defaultCurrent: currentTablePage }}
- />
- </div>
- </div>
- )
- }
- </div>
- )
- }
- <div className="leftRowOneContent">
- <div className="blocks">
- <div className="value">{matchItemInfo?.code}</div>
- <div className="label">项目编码</div>
- </div>
- <div className="blocks">
- <div className="value">{matchItemInfo?.name}</div>
- <div className="label">项目名称</div>
- </div>
- <div className="blocks">
- <div className="value">{matchItemInfo?.type}</div>
- <div className="label">项目类别</div>
- </div>
- <div className="blocks">
- <div className="value">{(matchItemInfo?.match) ? '已匹配' : '未匹配'}</div>
- <div className="label">匹配状态</div>
- </div>
- </div>
- </div>
- <div className="leftTable">
- <div className="leftTableTitle">手动匹配</div>
- <div style={{ marginBottom: 12 }}>
- <ProFormText noStyle placeholder={'标准项目编码、名称'}
- fieldProps={{
- // value: keyword,
- suffix: <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" />,
- onChange: (e) => {
- if (e.target.value.length != 0) {
- setSearchText(e.target.value);
- } else {
- setSearchText('');
- }
- }
- }}
- />
- </div>
- <KCIMTable columns={leftTableColumns}
- options={{
- density: true,
- setting: {
- listsHeight: 100,
- },
- }}
- loading={loading}
- dataSource={[...dataSource]}
- rowKey={'id'}
- tableAlertRender={false}
- pagination={{ showTitle: false, showSizeChanger: true, simple: true, defaultPageSize: 12 }}
- />
- </div>
- </div>
- <div className="right">
- {
- !single && (
- <div className="rightRowOne">
- <div className="processCycle">
- <Progress type="circle" format={percent => <span style={{ color: '52c41a !important' }}>{`${percent}%`}</span>} percent={countInfo ? Math.floor((countInfo.trueMatch / countInfo.allCount) * 100) : 0} width={64} />
- <div className="processInfo">
- <div className="total">全部项目:{countInfo ? countInfo.allCount : 0}</div>
- <div className="subInfo">
- <span>已匹配:<a>{countInfo ? countInfo.trueMatch : 0}</a></span> <span>待匹配:<a>{countInfo ? countInfo.falseMatch : 0}</a></span>
- </div>
- </div>
- </div>
- <div className="btn" onClick={() => mapBtnHandle()}>
- <IconFont style={{ color: '#fff',fontSize:14,marginRight:4 }} type="iconshuoming" />智能匹配
- <div className="description">
- <img src={require('../../../../../../static/tanhao.png')} alt="" style={{ width: 16, height: 16, marginRight: 4 }} />
- <div className="detail">
- <div className="detailTitle">匹配规则</div>
- <div className="detailContent">
- 1、逐个匹配未匹配的项目,已匹配的项目会自动跳过<br />
- 2、与标准项目国家编码精准匹配的项目状态设置成已匹配<br />
- 3、未精准匹配的项目会通过智能匹配算法形成推荐项,需用户逐个选择匹配项
- </div>
- </div>
- </div>
- </div>
- </div>
- )
- }
- <div className="rightContent">
- <div className="rightContentHeader">
- <span className="title">推荐匹配</span>
- <span className="btn" onClick={()=>switchNeddMatchItem(1)}><IconFont style={{ color: '#3376FE',paddingRight:4 }} type="iconshuangyou" />跳过该项</span>
- </div>
- <div className="content">
- {
- loading && (
- <Skeleton active />
- )
- }
- {
- !loading && matchStandItem.map((item, index) => {
- const { code } = item;
- return (
- <div className="list" key={index}>
- <div className="leftDetail">
- <div className="rowOne">
- <div className="title">{item.name}</div>
- <div className="Signal"><SignalBar level={item.percent ? item.percent : 0} />{item.percentDisplay}</div>
- </div>
- <div className="rowTwo">
- <div className="code">普通门诊诊察费</div>
- <div className="type">康程分类:诊察费/西医诊察费</div>
- </div>
- </div>
- {code != matchItemInfo?.standItemCode ? <div className="btn" onClick={() => matchRequestHandle(item,2)}>匹配</div> : <div className="btnText">当前匹配</div>}
- </div>
- )
- })
- }
- {
- !loading && matchStandItem.length == 0 && (
- <div className="empty">
- <img src={require('../../../../../../static/empty.png')} alt="" />
- <div className="title">暂无推荐项目</div>
- <div className="titleSub">当前暂无推荐匹配项目,您可尝试进行对照或</div>
- <a className="btn" onClick={() => goMatch()}>去匹配</a>
- </div>
- )
- }
- </div>
- </div>
- </div>
- </div>
- </div>
- )
- }
|