Compare commits
13 Commits
362b13ac43
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e420897878 | ||
|
|
d451cb1172 | ||
|
|
e37d605e38 | ||
|
|
debed766d5 | ||
|
|
abc0a6051d | ||
|
|
513e113ea9 | ||
|
|
07c74c956e | ||
|
|
29f6a6e696 | ||
|
|
e2158286be | ||
|
|
db6a8bc97f | ||
|
|
41ce02512a | ||
|
|
d09bfc4ec6 | ||
|
|
f75e19cf85 |
@@ -1,5 +1,7 @@
|
|||||||
# React + TypeScript + Vite
|
# React + TypeScript + Vite
|
||||||
|
|
||||||
|
`cp node_modules/pdfjs-dist/build/pdf.worker.min.mjs public/pdf.worker.min.mjs`
|
||||||
|
|
||||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||||
|
|
||||||
Currently, two official plugins are available:
|
Currently, two official plugins are available:
|
||||||
|
|||||||
2542
package-lock.json
generated
2542
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,14 +4,14 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "export NODE_ENV=development && vite --host 0.0.0.0",
|
"dev": "export NODE_ENV=development && vite --host 0.0.0.0 --port 5777",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"pdfjs-dist": "^5.4.449",
|
"pdfjs-dist": "^4.4.168",
|
||||||
"react": "^19.2.0",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "^19.2.0",
|
||||||
"react-router-dom": "^7.9.6"
|
"react-router-dom": "^7.9.6"
|
||||||
|
|||||||
21
public/pdf.worker.min.js
vendored
Normal file
21
public/pdf.worker.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -4,7 +4,11 @@ import { RouterProvider } from 'react-router-dom';
|
|||||||
import { router } from './router';
|
import { router } from './router';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return <RouterProvider router={router} />;
|
return (
|
||||||
|
<div className='h-screen max-h-screen overflow-hidden'>
|
||||||
|
<RouterProvider router={router} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -6,13 +6,10 @@ const API_CONFIG = {
|
|||||||
// 内网地址(HTTP)
|
// 内网地址(HTTP)
|
||||||
INTERNAL_URL: 'http://10.1.5.118:8077/platform-api',
|
INTERNAL_URL: 'http://10.1.5.118:8077/platform-api',
|
||||||
// 外网地址(HTTPS)
|
// 外网地址(HTTPS)
|
||||||
EXTERNAL_URL: 'https://apihis.circleharmonyhospital.cn:8982/platform-api',
|
EXTERNAL_URL: 'http://apihis.circleharmonyhospital.cn:8982/platform-api',
|
||||||
// 默认使用外网地址,可根据环境变量切换
|
BASE_URL: import.meta.env.MODE === 'development'
|
||||||
// 开发环境使用内网,生产环境使用外网
|
? '/platform-api'
|
||||||
BASE_URL: import.meta.env.NODE_ENV === 'development'
|
: '/platform-api',
|
||||||
? 'http://10.1.5.118:8077/platform-api'
|
|
||||||
: 'http://apihis.circleharmonyhospital.cn:8982/platform-api',
|
|
||||||
// 请求超时时间(120秒)
|
|
||||||
TIMEOUT: 120000,
|
TIMEOUT: 120000,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,7 +60,10 @@ request.interceptors.response.use(
|
|||||||
localStorage.removeItem('operatorName');
|
localStorage.removeItem('operatorName');
|
||||||
localStorage.removeItem('operatorUsername');
|
localStorage.removeItem('operatorUsername');
|
||||||
// 跳转到首页并添加登录参数
|
// 跳转到首页并添加登录参数
|
||||||
window.location.href = '/home?login=true';
|
const baseUrl = import.meta.env.MODE === 'development' ? '/' : '/tijian-zongkong/';
|
||||||
|
window.location.href = `${baseUrl}#/home?login=true`;
|
||||||
|
// navigate('/home?login=true');
|
||||||
|
// return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 403:
|
case 403:
|
||||||
|
|||||||
@@ -548,6 +548,8 @@ export interface InputPhysicalExamAddItem {
|
|||||||
scrm_account_name?: string | null;
|
scrm_account_name?: string | null;
|
||||||
/** 项目名称(默认空值,传入项目名称过滤数据) */
|
/** 项目名称(默认空值,传入项目名称过滤数据) */
|
||||||
item_name?: string;
|
item_name?: string;
|
||||||
|
/** 折扣率 */
|
||||||
|
discount_rate?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -720,11 +722,11 @@ export type PhysicalExamQrcodeCreateResponse = CommonActionResult<string>;
|
|||||||
*/
|
*/
|
||||||
export interface InputAddItemCombinationInfo {
|
export interface InputAddItemCombinationInfo {
|
||||||
/** 体检组合项目代码 */
|
/** 体检组合项目代码 */
|
||||||
combination_item_code: string;
|
combination_item_code?: string | null;
|
||||||
/** 体检组合项目价格 */
|
/** 体检组合项目价格 */
|
||||||
combination_item_price: number;
|
combination_item_price?: number | null;
|
||||||
/** 折扣比例 */
|
/** 折扣比例 */
|
||||||
discount_rate: number;
|
discount_rate?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -741,6 +743,8 @@ export interface InputOrderPaymentInfo {
|
|||||||
pay_type: number;
|
pay_type: number;
|
||||||
/** 挂账公司ID(挂账公司传对应的ID,其他传0) */
|
/** 挂账公司ID(挂账公司传对应的ID,其他传0) */
|
||||||
company_id: number;
|
company_id: number;
|
||||||
|
/** 订单总金额 */
|
||||||
|
orderAmount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1396,6 +1400,15 @@ export interface InputCustomSettlementApplyApprove {
|
|||||||
add_item_id?: string;
|
add_item_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 体检加项自定义结算申请-加项组合项
|
||||||
|
*/
|
||||||
|
export interface OutputCustomSettlementApplyApproveItem {
|
||||||
|
combination_item_code?: string | null;
|
||||||
|
combination_item_price?: number | null;
|
||||||
|
discount_rate?: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 体检加项自定义结算申请状态编辑出参
|
* 体检加项自定义结算申请状态编辑出参
|
||||||
*/
|
*/
|
||||||
@@ -1408,6 +1421,12 @@ export interface OutputCustomSettlementApplyApprove {
|
|||||||
apply_status_name?: string | null;
|
apply_status_name?: string | null;
|
||||||
/** 最终结算金额 */
|
/** 最终结算金额 */
|
||||||
final_settlement_price?: number | null;
|
final_settlement_price?: number | null;
|
||||||
|
/** 申请理由 */
|
||||||
|
apply_reason?: string;
|
||||||
|
/** 折扣 */
|
||||||
|
discount_ratio?: number | null;
|
||||||
|
/** 加项组合列表 */
|
||||||
|
listAddItemCombination?: OutputCustomSettlementApplyApproveItem[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1427,6 +1446,8 @@ export interface InputAddItemCustomSettlementDetail {
|
|||||||
original_price: number;
|
original_price: number;
|
||||||
/** 结算金额 */
|
/** 结算金额 */
|
||||||
settlement_price: number;
|
settlement_price: number;
|
||||||
|
/** 折扣率 */
|
||||||
|
discount_ratio?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1447,6 +1468,8 @@ export interface InputCustomSettlementApply {
|
|||||||
final_settlement_price?: number;
|
final_settlement_price?: number;
|
||||||
/** 申请理由 */
|
/** 申请理由 */
|
||||||
apply_reason?: string;
|
apply_reason?: string;
|
||||||
|
/** 申请人 */
|
||||||
|
apply_user: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1470,6 +1493,8 @@ export interface InputCustomSettlementApplyCancel {
|
|||||||
physical_exam_id: number;
|
physical_exam_id: number;
|
||||||
/** 体检加项组合ID(多个逗号分隔,例如:123,456) */
|
/** 体检加项组合ID(多个逗号分隔,例如:123,456) */
|
||||||
add_item_id: string;
|
add_item_id: string;
|
||||||
|
/** 申请人 */
|
||||||
|
cancel_user: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
21
src/assets/pdf.worker.min.mjs
Normal file
21
src/assets/pdf.worker.min.mjs
Normal file
File diff suppressed because one or more lines are too long
BIN
src/assets/sign.png
Normal file
BIN
src/assets/sign.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
File diff suppressed because it is too large
Load Diff
@@ -113,70 +113,70 @@ export const ExamDeliveryPanel = ({ client }: { client: ExamClient }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{viewMode === 'form' ? (
|
{viewMode === 'form' ? (
|
||||||
<>
|
<div className='overflow-y-auto overflow-x-hidden max-h-[clamp(260px,calc(100vh-520px),560px)] pr-1'>
|
||||||
{infoLoading && (
|
{infoLoading && (
|
||||||
<div className='mb-3 text-xs text-gray-500'>正在加载地址信息...</div>
|
<div className='mb-3 text-xs text-gray-500'>正在加载地址信息...</div>
|
||||||
)}
|
)}
|
||||||
<div className='grid grid-cols-2 gap-3 mb-3'>
|
<div className='grid grid-cols-2 gap-x-3 gap-y-1.5 mb-2'>
|
||||||
<div>
|
<div>
|
||||||
收件人姓名
|
<span className='text-[11px] text-gray-500'>收件人姓名</span>
|
||||||
<Input
|
<Input
|
||||||
placeholder='请输入收件人姓名'
|
placeholder='请输入收件人姓名'
|
||||||
className='mt-1'
|
className='mt-0.5 h-8 text-xs'
|
||||||
value={addressContact}
|
value={addressContact}
|
||||||
onChange={(e) => setAddressContact(e.target.value)}
|
onChange={(e) => setAddressContact(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
联系电话
|
<span className='text-[11px] text-gray-500'>联系电话</span>
|
||||||
<Input
|
<Input
|
||||||
placeholder='用于快递联系'
|
placeholder='用于快递联系'
|
||||||
className='mt-1'
|
className='mt-0.5 h-8 text-xs'
|
||||||
value={addressMobile}
|
value={addressMobile}
|
||||||
onChange={(e) => setAddressMobile(e.target.value)}
|
onChange={(e) => setAddressMobile(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
省份
|
<span className='text-[11px] text-gray-500'>省份</span>
|
||||||
<Input
|
<Input
|
||||||
placeholder='例如:上海市'
|
placeholder='例如:上海市'
|
||||||
className='mt-1'
|
className='mt-0.5 h-8 text-xs'
|
||||||
value={provinceName}
|
value={provinceName}
|
||||||
onChange={(e) => setProvinceName(e.target.value)}
|
onChange={(e) => setProvinceName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
城市
|
<span className='text-[11px] text-gray-500'>城市</span>
|
||||||
<Input
|
<Input
|
||||||
placeholder='例如:上海市'
|
placeholder='例如:上海市'
|
||||||
className='mt-1'
|
className='mt-0.5 h-8 text-xs'
|
||||||
value={cityName}
|
value={cityName}
|
||||||
onChange={(e) => setCityName(e.target.value)}
|
onChange={(e) => setCityName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
区县
|
<span className='text-[11px] text-gray-500'>区县</span>
|
||||||
<Input
|
<Input
|
||||||
placeholder='例如:浦东新区'
|
placeholder='例如:浦东新区'
|
||||||
className='mt-1'
|
className='mt-0.5 h-8 text-xs'
|
||||||
value={countryName}
|
value={countryName}
|
||||||
onChange={(e) => setCountryName(e.target.value)}
|
onChange={(e) => setCountryName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='col-span-2'>
|
<div className='col-span-2'>
|
||||||
详细地址
|
<span className='text-[11px] text-gray-500'>详细地址</span>
|
||||||
<Input
|
<Input
|
||||||
placeholder='请输入详细寄送地址'
|
placeholder='请输入详细寄送地址'
|
||||||
className='mt-1'
|
className='mt-0.5 h-8 text-xs'
|
||||||
value={addressContent}
|
value={addressContent}
|
||||||
onChange={(e) => setAddressContent(e.target.value)}
|
onChange={(e) => setAddressContent(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='space-y-2'>
|
<div className='space-y-1'>
|
||||||
<div>备注说明</div>
|
<div className='text-[11px] text-gray-500'>备注说明</div>
|
||||||
<textarea
|
<textarea
|
||||||
className='w-full rounded-2xl border px-3 py-2 text-xs outline-none focus:ring-2 focus:ring-gray-200 min-h-[80px]'
|
className='w-full rounded-xl border px-3 py-1.5 text-xs outline-none focus:ring-2 focus:ring-gray-200 min-h-[60px] resize-none'
|
||||||
placeholder='如需多份报告、加急寄送等,请在此备注'
|
placeholder='如需多份报告、加急寄送等,请在此备注'
|
||||||
value={addressRemark}
|
value={addressRemark}
|
||||||
onChange={(e) => setAddressRemark(e.target.value)}
|
onChange={(e) => setAddressRemark(e.target.value)}
|
||||||
@@ -190,12 +190,12 @@ export const ExamDeliveryPanel = ({ client }: { client: ExamClient }) => {
|
|||||||
{saveMessage}
|
{saveMessage}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className='mt-4 flex items-center justify-between text-[11px] text-gray-500'>
|
<div className='mt-2 flex items-center justify-between text-[10px] text-gray-500'>
|
||||||
<div>
|
<div className='truncate mr-2'>
|
||||||
当前客户:<span className='font-medium text-gray-800'>{client.name}</span>(体检号:{client.id})
|
当前客户:<span className='font-medium text-gray-800'>{client.name}</span> ({client.id})
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
className='px-4 py-1.5 text-xs'
|
className='px-4 py-1.5 h-8 text-xs flex-shrink-0'
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const physical_exam_id = Number(client.id);
|
const physical_exam_id = Number(client.id);
|
||||||
if (!physical_exam_id) {
|
if (!physical_exam_id) {
|
||||||
@@ -261,7 +261,7 @@ export const ExamDeliveryPanel = ({ client }: { client: ExamClient }) => {
|
|||||||
{saveLoading ? '保存中...' : '保存寄送信息'}
|
{saveLoading ? '保存中...' : '保存寄送信息'}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className='flex flex-col items-center justify-center py-8'>
|
<div className='flex flex-col items-center justify-center py-8'>
|
||||||
{qrcodeLoading ? (
|
{qrcodeLoading ? (
|
||||||
@@ -271,7 +271,7 @@ export const ExamDeliveryPanel = ({ client }: { client: ExamClient }) => {
|
|||||||
<img
|
<img
|
||||||
src={qrcodeUrl.startsWith('data:') ? qrcodeUrl : `data:image/png;base64,${qrcodeUrl}`}
|
src={qrcodeUrl.startsWith('data:') ? qrcodeUrl : `data:image/png;base64,${qrcodeUrl}`}
|
||||||
alt='报告寄送登记二维码'
|
alt='报告寄送登记二维码'
|
||||||
className='max-w-full max-h-[400px] object-contain'
|
className='max-w-full max-h-[clamp(240px,calc(100vh-520px),400px)] object-contain'
|
||||||
/>
|
/>
|
||||||
<div className='text-xs text-gray-500'>请扫描二维码进行报告寄送登记</div>
|
<div className='text-xs text-gray-500'>请扫描二维码进行报告寄送登记</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ interface ExamDetailPanelProps {
|
|||||||
addItemInfoList: CustomerExamAddItem[] | null;
|
addItemInfoList: CustomerExamAddItem[] | null;
|
||||||
progressList: PhysicalExamProgressItem[] | null;
|
progressList: PhysicalExamProgressItem[] | null;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
onCustomerUpdated?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMaritalCodeFromText = (text: string): number => {
|
const getMaritalCodeFromText = (text: string): number => {
|
||||||
@@ -33,6 +34,7 @@ export const ExamDetailPanel = ({
|
|||||||
addItemInfoList,
|
addItemInfoList,
|
||||||
progressList,
|
progressList,
|
||||||
loading,
|
loading,
|
||||||
|
onCustomerUpdated,
|
||||||
}: ExamDetailPanelProps) => {
|
}: ExamDetailPanelProps) => {
|
||||||
const basePhone = customerInfo?.phone || (client['mobile' as keyof ExamClient] as string | undefined) || '';
|
const basePhone = customerInfo?.phone || (client['mobile' as keyof ExamClient] as string | undefined) || '';
|
||||||
const baseMaritalText =
|
const baseMaritalText =
|
||||||
@@ -108,6 +110,7 @@ export const ExamDetailPanel = ({
|
|||||||
if (res.Status === 200) {
|
if (res.Status === 200) {
|
||||||
setEditMessage('保存成功');
|
setEditMessage('保存成功');
|
||||||
setPhoneEditing(false);
|
setPhoneEditing(false);
|
||||||
|
onCustomerUpdated?.();
|
||||||
setTimeout(() => setEditMessage(null), 2000);
|
setTimeout(() => setEditMessage(null), 2000);
|
||||||
} else {
|
} else {
|
||||||
setEditMessage(res.Message || '保存失败');
|
setEditMessage(res.Message || '保存失败');
|
||||||
@@ -140,6 +143,7 @@ export const ExamDetailPanel = ({
|
|||||||
if (res.Status === 200) {
|
if (res.Status === 200) {
|
||||||
setEditMessage('保存成功');
|
setEditMessage('保存成功');
|
||||||
setMaritalEditing(false);
|
setMaritalEditing(false);
|
||||||
|
onCustomerUpdated?.();
|
||||||
setTimeout(() => setEditMessage(null), 2000);
|
setTimeout(() => setEditMessage(null), 2000);
|
||||||
} else {
|
} else {
|
||||||
setEditMessage(res.Message || '保存失败');
|
setEditMessage(res.Message || '保存失败');
|
||||||
|
|||||||
@@ -76,6 +76,16 @@ export const ExamModal = ({ client, tab, onTabChange, onClose }: ExamModalProps)
|
|||||||
.finally(() => setDetailLoading(false));
|
.finally(() => setDetailLoading(false));
|
||||||
}, [client.id]);
|
}, [client.id]);
|
||||||
|
|
||||||
|
const refetchDetail = () => {
|
||||||
|
const physical_exam_id = Number(client.id);
|
||||||
|
if (!physical_exam_id) return;
|
||||||
|
getCustomerDetail({ physical_exam_id }).then((detailRes) => {
|
||||||
|
setCustomerInfo(detailRes.Data?.customerInfo ?? null);
|
||||||
|
setAppointmentInfo(detailRes.Data?.appointmentInfo ?? null);
|
||||||
|
setAddItemInfoList(detailRes.Data?.addItemInfoList ?? null);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='fixed inset-0 z-40 flex items-center justify-center bg-black/50'
|
className='fixed inset-0 z-40 flex items-center justify-center bg-black/50'
|
||||||
@@ -153,6 +163,7 @@ export const ExamModal = ({ client, tab, onTabChange, onClose }: ExamModalProps)
|
|||||||
addItemInfoList={addItemInfoList}
|
addItemInfoList={addItemInfoList}
|
||||||
progressList={progressList}
|
progressList={progressList}
|
||||||
loading={detailLoading}
|
loading={detailLoading}
|
||||||
|
onCustomerUpdated={refetchDetail}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{tab === 'sign' && <ExamSignPanel examId={Number(client.id)} onBusyChange={setSignBusy} />}
|
{tab === 'sign' && <ExamSignPanel examId={Number(client.id)} onBusyChange={setSignBusy} />}
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import * as pdfjsLib from 'pdfjs-dist';
|
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.mjs';
|
||||||
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?url';
|
|
||||||
|
|
||||||
import { getDaojiandanPdf as getDaojiandanPdfApi, submitDaojiandanSign, editDaojiandanPrintStatus } from '../../api';
|
import { getDaojiandanPdf as getDaojiandanPdfApi, submitDaojiandanSign, editDaojiandanPrintStatus } from '../../api';
|
||||||
import type { ExamClient } from '../../data/mockData';
|
import type { ExamClient } from '../../data/mockData';
|
||||||
import type { SignaturePadHandle } from '../ui';
|
import type { SignaturePadHandle } from '../ui';
|
||||||
import { Button, SignaturePad } from '../ui';
|
import { Button, SignaturePad } from '../ui';
|
||||||
|
|
||||||
// Polyfill for Promise.withResolvers
|
|
||||||
if (typeof (Promise as any).withResolvers === 'undefined') {
|
if (typeof (Promise as any).withResolvers === 'undefined') {
|
||||||
(Promise as any).withResolvers = function <T>() {
|
(Promise as any).withResolvers = function <T>() {
|
||||||
let resolve!: (value: T | PromiseLike<T>) => void;
|
let resolve!: (value: T | PromiseLike<T>) => void;
|
||||||
@@ -20,8 +18,14 @@ if (typeof (Promise as any).withResolvers === 'undefined') {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置 PDF.js worker
|
if (typeof (Promise as any).try === 'undefined') {
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
(Promise as any).try = function (fn: () => any) {
|
||||||
|
return new Promise((resolve) => resolve(fn()));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = import.meta.env.MODE === 'development' ? '/pdf.worker.min.js' : '/tijian-zongkong/pdf.worker.min.js';
|
||||||
|
|
||||||
|
|
||||||
export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
|
export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
|
||||||
const [pdfUrl, setPdfUrl] = useState<string | null>(null);
|
const [pdfUrl, setPdfUrl] = useState<string | null>(null);
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ export const ExamSection = ({
|
|||||||
const hasMore = displayCount < filteredClients.length;
|
const hasMore = displayCount < filteredClients.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='space-y-4'>
|
<div className='space-y-4 h-full overflow-y-auto p-4 pb-10'>
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>今日体检进度</CardHeader>
|
<CardHeader>今日体检进度</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import * as pdfjsLib from 'pdfjs-dist';
|
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.mjs';
|
||||||
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?url';
|
|
||||||
|
|
||||||
import type { OutputTongyishuFileInfo, OutputTijianPdfFileInfo, OutputPhysicalExamItemInfo } from '../../api';
|
import type { OutputTongyishuFileInfo, OutputTijianPdfFileInfo, OutputPhysicalExamItemInfo } from '../../api';
|
||||||
import {
|
import {
|
||||||
@@ -20,7 +19,6 @@ import {
|
|||||||
import type { SignaturePadHandle } from '../ui';
|
import type { SignaturePadHandle } from '../ui';
|
||||||
import { Button, SignaturePad } from '../ui';
|
import { Button, SignaturePad } from '../ui';
|
||||||
|
|
||||||
// Polyfill for Promise.withResolvers
|
|
||||||
if (typeof (Promise as any).withResolvers === 'undefined') {
|
if (typeof (Promise as any).withResolvers === 'undefined') {
|
||||||
(Promise as any).withResolvers = function <T>() {
|
(Promise as any).withResolvers = function <T>() {
|
||||||
let resolve!: (value: T | PromiseLike<T>) => void;
|
let resolve!: (value: T | PromiseLike<T>) => void;
|
||||||
@@ -33,8 +31,13 @@ if (typeof (Promise as any).withResolvers === 'undefined') {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置 PDF.js worker
|
if (typeof (Promise as any).try === 'undefined') {
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
(Promise as any).try = function (fn: () => any) {
|
||||||
|
return new Promise((resolve) => resolve(fn()));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = import.meta.env.MODE === 'development' ? '/pdf.worker.min.js' : '/tijian-zongkong/pdf.worker.min.js';
|
||||||
|
|
||||||
interface ExamSignPanelProps {
|
interface ExamSignPanelProps {
|
||||||
examId?: number;
|
examId?: number;
|
||||||
@@ -418,7 +421,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
}, [examId, optionalConfirmed]);
|
}, [examId, optionalConfirmed]);
|
||||||
|
|
||||||
const handlePickFile = () => {
|
const handlePickFile = () => {
|
||||||
// 有可选项目但尚未确认时,禁止拍照并提示先确认项目
|
|
||||||
if (optionalItemList.length > 0 && !optionalConfirmed) {
|
if (optionalItemList.length > 0 && !optionalConfirmed) {
|
||||||
setMessage('请先确认体检项目');
|
setMessage('请先确认体检项目');
|
||||||
setShowOptionalConfirmTip(true);
|
setShowOptionalConfirmTip(true);
|
||||||
@@ -465,24 +467,25 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
|
|
||||||
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const file = e.target.files?.[0];
|
const file = e.target.files?.[0];
|
||||||
if (!file) return;
|
if (!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setMessage(null);
|
setMessage(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const jpgFile = await convertToJpg(file);
|
const jpgFile = await convertToJpg(file);
|
||||||
setIdCardFile(jpgFile);
|
setIdCardFile(jpgFile);
|
||||||
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = (event) => {
|
reader.onload = (event) => {
|
||||||
setPreviewImage(event.target?.result as string);
|
setPreviewImage(event.target?.result as string);
|
||||||
};
|
};
|
||||||
reader.readAsDataURL(jpgFile);
|
reader.readAsDataURL(jpgFile);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
alert('err: ' + String(err));
|
||||||
console.error('图片转换失败', err);
|
console.error('图片转换失败', err);
|
||||||
setMessage('图片处理失败,请重试');
|
setMessage('图片处理失败,请重试');
|
||||||
}
|
}
|
||||||
|
|
||||||
e.target.value = '';
|
e.target.value = '';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2053,7 +2056,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
<span className='truncate'>{item.pdf_name.length > 10 ? item.pdf_name.slice(0, 10) + "..." : item.pdf_name}</span>
|
<span className='truncate'>{item.pdf_name.length > 10 ? item.pdf_name.slice(0, 10) + "..." : item.pdf_name}</span>
|
||||||
{item.combination_code !== undefined && signedCombinationCodes.includes(Number(item.combination_code)) && (
|
{item.combination_code !== undefined && signedCombinationCodes.includes(Number(item.combination_code)) && (
|
||||||
<img
|
<img
|
||||||
src='/sign.png'
|
src={import.meta.env.MODE === 'development' ? '/sign.png' : '/tijian-zongkong/sign.png'}
|
||||||
alt='已签名'
|
alt='已签名'
|
||||||
className='w-16 h-16 absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none select-none'
|
className='w-16 h-16 absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none select-none'
|
||||||
loading='lazy'
|
loading='lazy'
|
||||||
@@ -2105,7 +2108,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
<span className='truncate'>导检单</span>
|
<span className='truncate'>导检单</span>
|
||||||
{isDaojiandanSigned && (
|
{isDaojiandanSigned && (
|
||||||
<img
|
<img
|
||||||
src='/sign.png'
|
src={import.meta.env.MODE === 'development' ? '/sign.png' : '/tijian-zongkong/sign.png'}
|
||||||
alt='已签名'
|
alt='已签名'
|
||||||
className='w-16 h-16 absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none select-none'
|
className='w-16 h-16 absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none select-none'
|
||||||
loading='lazy'
|
loading='lazy'
|
||||||
@@ -2228,7 +2231,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
)}
|
)}
|
||||||
{isSigned && (
|
{isSigned && (
|
||||||
<img
|
<img
|
||||||
src='/sign.png'
|
src={import.meta.env.MODE === 'development' ? '/sign.png' : '/tijian-zongkong/sign.png'}
|
||||||
alt='已签名'
|
alt='已签名'
|
||||||
className='w-16 h-16 absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none select-none'
|
className='w-16 h-16 absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none select-none'
|
||||||
loading='lazy'
|
loading='lazy'
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ export const HomeSection = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className='grid grid-cols-2 gap-4'>
|
<div className='grid grid-cols-2 gap-4 pb-10'>
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>B1 服务看板</CardHeader>
|
<CardHeader>B1 服务看板</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
|
|||||||
@@ -22,10 +22,18 @@ const NAV_ITEMS = [
|
|||||||
{ key: 'support', icon: IconSupport, label: '客服咨询' },
|
{ key: 'support', icon: IconSupport, label: '客服咨询' },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
const toggleFullscreen = () => {
|
||||||
|
if (!document.fullscreenElement) {
|
||||||
|
document.documentElement.requestFullscreen?.();
|
||||||
|
} else {
|
||||||
|
document.exitFullscreen?.();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const Sidebar = ({ active, onNavigate, onQuickAction }: SidebarProps) => (
|
export const Sidebar = ({ active, onNavigate, onQuickAction }: SidebarProps) => (
|
||||||
<aside className='bg-white border-r p-4 flex flex-col gap-4'>
|
<aside className='h-screen max-h-screen bg-white border-r p-4 flex flex-col gap-4 overflow-hidden'>
|
||||||
<div>
|
<div>
|
||||||
<div className='text-base font-semibold'>圆和医疗 · 体检中心</div>
|
<button type='button' onClick={toggleFullscreen} className='text-base font-semibold cursor-pointer hover:opacity-80 text-left'>圆和医疗 · 体检中心</button>
|
||||||
<div className='text-xs text-gray-500 mt-1'></div>
|
<div className='text-xs text-gray-500 mt-1'></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -73,13 +81,13 @@ export const Sidebar = ({ active, onNavigate, onQuickAction }: SidebarProps) =>
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className='mt-auto p-3 rounded-2xl border bg-gray-50/70 text-xs flex flex-col gap-2'>
|
{/* <section className='mt-auto p-3 rounded-2xl border bg-gray-50/70 text-xs flex flex-col gap-2'>
|
||||||
<div className='text-sm font-medium flex items-center gap-2'>
|
<div className='text-sm font-medium flex items-center gap-2'>
|
||||||
<span>💻</span>
|
<span>💻</span>
|
||||||
<span>客服 / IT 支持</span>
|
<span>客服 / IT 支持</span>
|
||||||
</div>
|
</div>
|
||||||
<div className='text-gray-600'>遇到系统问题可一键联系 IT / 运营支持。</div>
|
<div className='text-gray-600'>遇到系统问题可一键联系 IT / 运营支持。</div>
|
||||||
</section>
|
</section> */}
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ interface TopBarProps {
|
|||||||
onLogout?: () => void;
|
onLogout?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TopBar = ({ enableSearch = true, operatorName, onLoginClick, onLogout }: TopBarProps) => {
|
export const TopBar = ({ operatorName, onLoginClick, onLogout }: TopBarProps) => {
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
const [displayName, setDisplayName] = useState(operatorName || '');
|
const [displayName, setDisplayName] = useState(operatorName || '');
|
||||||
|
|
||||||
@@ -28,18 +28,18 @@ export const TopBar = ({ enableSearch = true, operatorName, onLoginClick, onLogo
|
|||||||
return (
|
return (
|
||||||
<header className='flex items-center gap-3 p-2 border-b bg-white'>
|
<header className='flex items-center gap-3 p-2 border-b bg-white'>
|
||||||
<div className='flex-1 flex items-center gap-3'>
|
<div className='flex-1 flex items-center gap-3'>
|
||||||
{enableSearch ? (
|
{/* {enableSearch ? (
|
||||||
<div className='w-[420px] max-w-[60vw] h-[36px] flex items-center'>
|
<div className='w-[420px] max-w-[60vw] h-[36px] flex items-center'>
|
||||||
{/* <Input
|
<Input
|
||||||
placeholder='搜索 姓名 / 证件号 / 手机号'
|
placeholder='搜索 姓名 / 证件号 / 手机号'
|
||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => onSearch(e.target.value)}
|
onChange={(e) => onSearch(e.target.value)}
|
||||||
className='text-sm'
|
className='text-sm'
|
||||||
/> */}
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className='text-sm text-gray-500 flex items-center p-[9px] pl-[14px]'>圆和医疗 · 体检驾驶舱</div>
|
<div className='text-sm text-gray-500 flex items-center p-[9px] pl-[14px]'>圆和医疗 · 体检驾驶舱</div>
|
||||||
)}
|
)} */}
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center gap-3 text-xs relative'>
|
<div className='flex items-center gap-3 text-xs relative'>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -95,9 +95,9 @@ export const NoteModal = ({ noteText, onNoteChange, onClose }: NoteModalProps) =
|
|||||||
{saving ? '保存中...' : '保存'}
|
{saving ? '保存中...' : '保存'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className='text-right text-[11px] text-gray-500'>
|
{/* <div className='text-right text-[11px] text-gray-500'>
|
||||||
备注内容会同步至客户详情页,供前台和导检护士查看。
|
备注内容会同步至客户详情页,供前台和导检护士查看。
|
||||||
</div>
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Card, CardContent, CardHeader } from '../ui';
|
import { Card, CardContent } from '../ui';
|
||||||
|
|
||||||
export const SupportSection = () => (
|
export const SupportSection = () => (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>客服咨询 · 圆圆客服台卡</CardHeader>
|
{/* <CardHeader>客服咨询 · 圆圆客服台卡</CardHeader> */}
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className='grid grid-cols-[1.2fr_1fr] gap-6 items-center'>
|
<div className='items-center'>
|
||||||
<div className='space-y-3 text-sm text-gray-700'>
|
{/* <div className='space-y-3 text-sm text-gray-700'>
|
||||||
<p>通过「圆圆客服」二维码,客户可获得一站式健康服务:包含体检预约、报告查询、报告解读等。</p>
|
<p>通过「圆圆客服」二维码,客户可获得一站式健康服务:包含体检预约、报告查询、报告解读等。</p>
|
||||||
<ul className='list-disc ml-5 space-y-1 text-xs text-gray-600'>
|
<ul className='list-disc ml-5 space-y-1 text-xs text-gray-600'>
|
||||||
<li>支持体检当天现场扫码添加,绑定客户信息</li>
|
<li>支持体检当天现场扫码添加,绑定客户信息</li>
|
||||||
@@ -13,19 +13,19 @@ export const SupportSection = () => (
|
|||||||
<li>提供一对一健康咨询与报告解读服务</li>
|
<li>提供一对一健康咨询与报告解读服务</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className='text-xs text-gray-500'>注:实际系统中可上传设计好的「圆圆客服二维码台卡」图片,用于前台展示与打印。</div>
|
<div className='text-xs text-gray-500'>注:实际系统中可上传设计好的「圆圆客服二维码台卡」图片,用于前台展示与打印。</div>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<div className='h-64 rounded-3xl overflow-hidden shadow-inner flex items-center justify-center bg-gradient-to-b from-[#152749] to-[#c73545]'>
|
<div className='h-[70vh] rounded-3xl overflow-hidden shadow-inner flex items-center justify-center bg-gradient-to-b from-[#152749] to-[#c73545]'>
|
||||||
<div className='flex flex-col items-center gap-3 text-white'>
|
<div className='flex flex-col items-center gap-5 text-white'>
|
||||||
<div className='text-[11px] tracking-[0.2em] opacity-80'>CIRCLE HARMONY · 圆和医疗</div>
|
<div className='text-base tracking-[0.2em] opacity-80'>CIRCLE HARMONY · 圆和医疗</div>
|
||||||
<div className='text-sm font-medium'>圆圆客服 · 一站式健康服务</div>
|
<div className='text-lg font-medium'>圆圆客服 · 一站式健康服务</div>
|
||||||
<div className='w-28 h-28 bg-none flex items-center justify-center'>
|
<div className='w-72 h-72 bg-none flex items-center justify-center'>
|
||||||
<div className='w-30 h-30 rounded-md overflow-hidden'>
|
<div className='w-72 h-72 rounded-md overflow-hidden'>
|
||||||
<img src="https://datacenter-open.oss-cn-hangzhou.aliyuncs.com/his/kefu-zixun.png" alt='圆圆客服二维码' className='w-full h-full object-cover' />
|
<img src="https://datacenter-open.oss-cn-hangzhou.aliyuncs.com/his/kefu-zixun.png" alt='圆圆客服二维码' className='w-full h-full object-cover' />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='text-sm font-semibold'>一对一专属服务</div>
|
<div className='text-lg font-semibold'>一对一专属服务</div>
|
||||||
<div className='px-4 py-1.5 rounded-full border border-white/70 text-[11px] flex gap-2'>
|
<div className='px-6 py-2 rounded-full border border-white/70 text-sm flex gap-2'>
|
||||||
<span>服务预约</span>
|
<span>服务预约</span>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span>报告查询</span>
|
<span>报告查询</span>
|
||||||
|
|||||||
@@ -7,17 +7,21 @@
|
|||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
scrollbar-color: #cbd5e1 #f8fafc;
|
scrollbar-color: #cbd5e1 #f8fafc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-scroll::-webkit-scrollbar {
|
.custom-scroll::-webkit-scrollbar {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-scroll::-webkit-scrollbar-track {
|
.custom-scroll::-webkit-scrollbar-track {
|
||||||
background: #f8fafc;
|
background: #f8fafc;
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-scroll::-webkit-scrollbar-thumb {
|
.custom-scroll::-webkit-scrollbar-thumb {
|
||||||
background: #cbd5e1;
|
background: #cbd5e1;
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-scroll::-webkit-scrollbar-thumb:hover {
|
.custom-scroll::-webkit-scrollbar-thumb:hover {
|
||||||
background: #94a3b8;
|
background: #94a3b8;
|
||||||
}
|
}
|
||||||
@@ -30,9 +34,13 @@
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
html,
|
||||||
|
body,
|
||||||
|
#root {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
min-height: 100vh;
|
height: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
background-color: #f8fafc;
|
background-color: #f8fafc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import type { ExamClient, ExamModalTab } from '../data/mockData';
|
import type { ExamClient, ExamModalTab } from '../data/mockData';
|
||||||
import { EXAM_TAGS } from '../data/mockData';
|
import { EXAM_TAGS } from '../data/mockData';
|
||||||
@@ -17,11 +18,14 @@ export const ExamPage = () => {
|
|||||||
const [examFilterTags, setExamFilterTags] = useState<Set<(typeof EXAM_TAGS)[number]>>(new Set(['全部']));
|
const [examFilterTags, setExamFilterTags] = useState<Set<(typeof EXAM_TAGS)[number]>>(new Set(['全部']));
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [refreshSeq, setRefreshSeq] = useState(0);
|
const [refreshSeq, setRefreshSeq] = useState(0);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
// 进入页面时获取用户菜单权限
|
// 进入页面时获取用户菜单权限
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = localStorage.getItem('accessToken');
|
const token = localStorage.getItem('accessToken');
|
||||||
if (!token) {
|
if (!token) {
|
||||||
|
// 跳转登录
|
||||||
|
navigate('/home');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getUserOwnedMenus({ app_id: APP_ID })
|
getUserOwnedMenus({ app_id: APP_ID })
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createBrowserRouter, Navigate } from 'react-router-dom';
|
import { createHashRouter, Navigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { MainLayout } from './layouts/MainLayout';
|
import { MainLayout } from './layouts/MainLayout';
|
||||||
import { HomePage } from './pages/HomePage';
|
import { HomePage } from './pages/HomePage';
|
||||||
@@ -6,7 +6,7 @@ import { ExamPage } from './pages/ExamPage';
|
|||||||
import { BookingPage } from './pages/BookingPage';
|
import { BookingPage } from './pages/BookingPage';
|
||||||
import { SupportPage } from './pages/SupportPage';
|
import { SupportPage } from './pages/SupportPage';
|
||||||
|
|
||||||
export const router = createBrowserRouter([
|
export const router = createHashRouter([
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
element: <MainLayout />,
|
element: <MainLayout />,
|
||||||
|
|||||||
6
src/vite-env.d.ts
vendored
Normal file
6
src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
declare module '*?url' {
|
||||||
|
const src: string;
|
||||||
|
export default src;
|
||||||
|
}
|
||||||
@@ -3,5 +3,12 @@ import react from '@vitejs/plugin-react-swc'
|
|||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
base: "./",
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
|
server: {
|
||||||
|
allowedHosts: ['ipad.shenynet.com'],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
dedupe: ['react', 'react-dom']
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user