作者 韩昌

登录接口和问诊订单样式

@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 "name": "react18-tsx-neteasemusic", 8 "name": "react18-tsx-neteasemusic",
9 "version": "0.1.0", 9 "version": "0.1.0",
10 "dependencies": { 10 "dependencies": {
  11 + "@ant-design/icons": "^5.2.6",
11 "@reduxjs/toolkit": "^1.9.5", 12 "@reduxjs/toolkit": "^1.9.5",
12 "@testing-library/jest-dom": "^5.17.0", 13 "@testing-library/jest-dom": "^5.17.0",
13 "@testing-library/react": "^13.4.0", 14 "@testing-library/react": "^13.4.0",
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 "version": "0.1.0", 3 "version": "0.1.0",
4 "private": true, 4 "private": true,
5 "dependencies": { 5 "dependencies": {
  6 + "@ant-design/icons": "^5.2.6",
6 "@reduxjs/toolkit": "^1.9.5", 7 "@reduxjs/toolkit": "^1.9.5",
7 "@testing-library/jest-dom": "^5.17.0", 8 "@testing-library/jest-dom": "^5.17.0",
8 "@testing-library/react": "^13.4.0", 9 "@testing-library/react": "^13.4.0",
1 import hyRequest from "@/service"; 1 import hyRequest from "@/service";
  2 +import { Send_prescription_formType } from '@/types'
2 3
3 export const getTopBanner = () => hyRequest.get({ url: '/banner' }) 4 export const getTopBanner = () => hyRequest.get({ url: '/banner' })
  5 +
  6 +// 公共
  7 +export const getSendMessage = (params: { phoneNum: string }) => hyRequest.get({ url: '/pet/login/sendMessage', params }) // 发送验证码
  8 +export const getMessageLogin = (params: any) => hyRequest.get({ url: '/pet/login/messageLogin', params }) // 验证码登录
  9 +export const updateSend_prescription_form = (params: Send_prescription_formType) => hyRequest.post({ url: '/veterinary/send_prescription_form', params }) // 发送处方单
1 body, textarea, select, input, button { 1 body, textarea, select, input, button {
2 - font-size: 12px;  
3 - color: #333;  
4 - font-family: Arial, Helvetica, sans-serif;  
5 - background-color: #f5f5f5; 2 + // font-size: 12px;
  3 + // color: #333;
  4 + // font-family: Arial, Helvetica, sans-serif;
  5 + // background-color: #f5f5f5;
6 } 6 }
7 7
8 .wrap-v1 { 8 .wrap-v1 {
@@ -60,10 +60,10 @@ body, textarea, select, input, button { @@ -60,10 +60,10 @@ body, textarea, select, input, button {
60 } 60 }
61 61
62 .ant-message .ant-message-notice-content { 62 .ant-message .ant-message-notice-content {
63 - position: fixed;  
64 - left: 50%;  
65 - transform: translateX(-50%);  
66 - bottom: 60px;  
67 - background-color: rgba(0, 0, 0, .7);  
68 - color: #fff; 63 + // position: fixed;
  64 + // left: 50%;
  65 + // transform: translateX(-50%);
  66 + // bottom: 60px;
  67 + // background-color: rgba(0, 0, 0, .7);
  68 + // color: #fff;
69 } 69 }
  1 +import React, { useRef, useImperativeHandle, Ref } from 'react'
  2 +
  3 +// 定义子组件的接口
  4 +interface ChildComponentProps {
  5 + // 定义子组件暴露给父组件的方法
  6 + increment: () => void
  7 + getCount: () => number
  8 +}
  9 +
  10 +const ChildComponent = React.forwardRef((props: ChildComponentProps, ref: Ref<any>) => {
  11 + const internalState = {
  12 + count: 0
  13 + }
  14 +
  15 + const incrementCount = () => {
  16 + internalState.count += 1
  17 + }
  18 +
  19 + useImperativeHandle(ref, () => ({
  20 + increment: incrementCount,
  21 + getCount: () => internalState.count
  22 + }))
  23 +
  24 + return (
  25 + <div>
  26 + <p>Count: {internalState.count}</p>
  27 + </div>
  28 + )
  29 +})
  30 +
  31 +const ParentComponent = () => {
  32 + const childRef = useRef<ChildComponentProps | null>(null)
  33 +
  34 + const handleIncrement = () => {
  35 + if (childRef.current) {
  36 + childRef.current.increment()
  37 + }
  38 + }
  39 +
  40 + const handleGetCount = () => {
  41 + if (childRef.current) {
  42 + const count = childRef.current.getCount()
  43 + alert('Count from child component: ' + count)
  44 + }
  45 + }
  46 +
  47 + return (
  48 + <div>
  49 + <h2>Parent Component</h2>
  50 + <button onClick={handleIncrement}>Increment Count in Child</button>
  51 + <button onClick={handleGetCount}>Get Count from Child</button>
  52 + <ChildComponent
  53 + ref={childRef}
  54 + increment={function (): void {
  55 + throw new Error('Function not implemented.')
  56 + }}
  57 + getCount={function (): number {
  58 + throw new Error('Function not implemented.')
  59 + }}
  60 + />
  61 + </div>
  62 + )
  63 +}
  64 +
  65 +export default ParentComponent
@@ -6,6 +6,9 @@ export const AppHeaderWrapper = styled.div` @@ -6,6 +6,9 @@ export const AppHeaderWrapper = styled.div`
6 font-size: 14px; 6 font-size: 14px;
7 box-sizing: border-box; 7 box-sizing: border-box;
8 padding: 20px 32px; 8 padding: 20px 32px;
  9 + box-shadow: 5px 5px 15px rgba(0,0,0,0.4);
  10 + z-index: 9999999999;
  11 + position: relative;
9 .title{ 12 .title{
10 color: #fff; 13 color: #fff;
11 font-size: 22px; 14 font-size: 22px;
@@ -8,9 +8,11 @@ interface IProps { @@ -8,9 +8,11 @@ interface IProps {
8 8
9 const AppLoading: FC<IProps> = memo(() => { 9 const AppLoading: FC<IProps> = memo(() => {
10 return ( 10 return (
11 - <Space size="middle">  
12 - <Spin size="large" />  
13 - </Space> 11 + <div className="flexC" style={{ width: '100%' }}>
  12 + <Space size="middle">
  13 + <Spin size="large" />
  14 + </Space>
  15 + </div>
14 ) 16 )
15 }) 17 })
16 18
  1 +// 按钮点击防抖
  2 +/**
  3 + * @使用方法
  4 + * @vue2
  5 + * 点击事件名:DebounceBy(function(args){ 写你自己的业务代码 },3000)
  6 + * @vue3
  7 + * const 点击事件名 = DebounceBy(async (args) => { 写你自己的业务代码 }, 3000)
  8 + */
  9 +export const DebounceBy = (fn: any, t: number = 500) => {
  10 + let delay = t || 500
  11 + let timer: any
  12 + return function () {
  13 + let args = arguments
  14 + if (timer) {
  15 + clearTimeout(timer)
  16 + }
  17 +
  18 + let callNow = !timer
  19 +
  20 + timer = setTimeout(() => {
  21 + timer = null
  22 + }, delay)
  23 +
  24 + if (callNow) fn(args)
  25 + // if (callNow) fn.apply(this, args)
  26 + }
  27 +}
  28 +
  29 +// 节流:防止高频触发
  30 +export const Throttle = (fn: any, delay: number) => {
  31 + let flag = true
  32 + return function () {
  33 + if (flag) {
  34 + setTimeout(() => {
  35 + // fn.call(this)
  36 + flag = true
  37 + }, delay)
  38 + }
  39 + flag = false
  40 + }
  41 +}
  1 +import { useRef, useState } from 'react'
  2 +
  3 +/**
  4 + * @import import useTimeHandler from '../../hooks/useTimeChange'
  5 + * @use const [ countdown, startCountdown ] = useTimeHandler() startCountdown(handler)
  6 + * @param executeHandler function
  7 + * @returns countdown , startCountDown => void
  8 + */
  9 +
  10 +type ExecuteHandlerType = () => void
  11 +
  12 +type useCountdownType = [number, (fn: ExecuteHandlerType) => void]
  13 +
  14 +const useCountdown = (): useCountdownType => {
  15 + let [countdown, setCountdown] = useState(60)
  16 + const newC = useRef(60)
  17 +
  18 + const timeHandler = () => {
  19 + let timer = setInterval(() => {
  20 + console.log(countdown, '倒计时')
  21 + // let newC = countdown - 1
  22 + setCountdown(newC.current--)
  23 + if (newC.current === 0) {
  24 + newC.current = 60
  25 + setCountdown(60)
  26 + clearInterval(timer)
  27 + }
  28 + }, 1000)
  29 + }
  30 +
  31 + const startCountdown = (executeHandler: ExecuteHandlerType) => {
  32 + if (countdown !== 60) return
  33 + executeHandler()
  34 + timeHandler()
  35 + }
  36 +
  37 + return [countdown, startCountdown]
  38 +}
  39 +
  40 +export default useCountdown
  1 +import { useRef, useState } from 'react'
  2 +
  3 +/**
  4 + * @import import useTimeHandler from '../../hooks/useTimeChange'
  5 + * @use const [ countdown, startCountdown ] = useTimeHandler() startCountdown(handler)
  6 + * @param executeHandler function
  7 + * @returns countdown , startCountDown => void
  8 + */
  9 +
  10 +type ExecuteHandlerType = () => void
  11 +
  12 +type useCountdownType = [number, (fn: ExecuteHandlerType) => void]
  13 +
  14 +const useCountdown = (): useCountdownType => {
  15 + let [countdown, setCountdown] = useState(60)
  16 +
  17 + const timeHandler = () => {
  18 + let timer = setInterval(() => {
  19 + let newC = countdown -= 1
  20 + setCountdown(newC--)
  21 + if (countdown === 0) {
  22 + setCountdown(60)
  23 + clearInterval(timer)
  24 + }
  25 + }, 1000)
  26 + }
  27 +
  28 + const startCountdown = (executeHandler: ExecuteHandlerType) => {
  29 + if (countdown !== 60) return
  30 + timeHandler()
  31 + executeHandler()
  32 + }
  33 +
  34 + return [countdown, startCountdown]
  35 +}
  36 +
  37 +export default useCountdown
@@ -5,7 +5,9 @@ import { BASE_URL, TIME_OUT } from './request/config' @@ -5,7 +5,9 @@ import { BASE_URL, TIME_OUT } from './request/config'
5 const hyRequest = new HYRequest({ 5 const hyRequest = new HYRequest({
6 baseURL: BASE_URL, 6 baseURL: BASE_URL,
7 timeout: TIME_OUT, 7 timeout: TIME_OUT,
8 - headers: {}, 8 + headers: {
  9 + 'X-Access-Token': localStorage.getItem('token') || ''
  10 + },
9 interceptors: { 11 interceptors: {
10 requestInterceptor: (config) => { 12 requestInterceptor: (config) => {
11 return config 13 return config
1 -const BASE_URL = 'http://codercba.com:9002/' 1 +// const BASE_URL = 'http://codercba.com:9002/'
  2 +const BASE_URL = 'http://192.168.10.63:8080/jeecg-boot'
  3 +
2 const TIME_OUT = 10000 4 const TIME_OUT = 10000
3 5
4 console.log(process.env) 6 console.log(process.env)
1 export * from './result' 1 export * from './result'
  2 +export * from './params'
  1 +export interface PhoneCodeLoginParamsType {
  2 + phoneNum: string
  3 + code: string
  4 +}
  5 +
  6 +export interface Send_prescription_formType {
  7 + /**
  8 + * 处方药
  9 + */
  10 + drugList: DrugList[];
  11 + /**
  12 + * 问诊订单id
  13 + */
  14 + id?: string;
  15 + /**
  16 + * 处方单金额
  17 + */
  18 + prescriptionAmount: number;
  19 + /**
  20 + * 处方单文件
  21 + */
  22 + prescriptionFile?: string;
  23 + /**
  24 + * 问诊病情描述
  25 + */
  26 + prescriptionForm: string;
  27 + [property: string]: any;
  28 +}
  29 +
  30 +export interface DrugList {
  31 + /**
  32 + * 单价
  33 + */
  34 + amount: string;
  35 + /**
  36 + * 说明
  37 + */
  38 + des: string;
  39 + /**
  40 + * 药物名称
  41 + */
  42 + name: string;
  43 + /**
  44 + * 数量
  45 + */
  46 + num: string;
  47 + [property: string]: any;
  48 +}
@@ -13,6 +13,12 @@ export interface PageListType<PageListItemType> { @@ -13,6 +13,12 @@ export interface PageListType<PageListItemType> {
13 size: number 13 size: number
14 } 14 }
15 15
  16 +export interface PhoneCodeLoginType {
  17 + im_token: string
  18 + userId: string
  19 + token: string
  20 +}
  21 +
16 export interface ConsultationOrderRecordsType { 22 export interface ConsultationOrderRecordsType {
17 id: string; 23 id: string;
18 order_no: string; 24 order_no: string;
  1 +import React, { memo, useState, forwardRef, useImperativeHandle } from 'react'
  2 +import type { FC, ReactNode } from 'react'
  3 +import { Input, Modal, Upload } from 'antd'
  4 +import { MinusCircleOutlined, PlusCircleOutlined, PlusOutlined } from '@ant-design/icons'
  5 +import type { RcFile, UploadProps } from 'antd/es/upload'
  6 +import type { UploadFile } from 'antd/es/upload/interface'
  7 +import { SendPrescriptionWrapper } from '../style'
  8 +import { BASE_URL } from '@/service/request/config'
  9 +import type { Send_prescription_formType, DrugList } from '@/types'
  10 +// /sys/common/appUpload
  11 +const { TextArea } = Input
  12 +
  13 +interface IProps {
  14 + children?: ReactNode
  15 + ref?: any
  16 +}
  17 +
  18 +const getBase64 = (file: RcFile): Promise<string> =>
  19 + new Promise((resolve, reject) => {
  20 + const reader = new FileReader()
  21 + reader.readAsDataURL(file)
  22 + reader.onload = () => resolve(reader.result as string)
  23 + reader.onerror = (error) => reject(error)
  24 + })
  25 +
  26 +const SendPrescription: FC<IProps> = memo(
  27 + forwardRef<HTMLDivElement, IProps>((props, ref) => {
  28 + const [previewOpen, setPreviewOpen] = useState(false)
  29 + const [previewImage, setPreviewImage] = useState('')
  30 + const [previewTitle, setPreviewTitle] = useState('')
  31 + const [fileList, setFileList] = useState<UploadFile[]>([])
  32 +
  33 + const [Send_prescription_formData, setSend_prescription_formTypeData] = useState<Send_prescription_formType>({
  34 + drugList: [{ amount: '', des: '', name: '', num: '' }],
  35 + prescriptionForm: '',
  36 + prescriptionAmount: 0
  37 + })
  38 +
  39 + const addFormItemHandler = () => {
  40 + const setdata = { ...Send_prescription_formData, drugList: [...Send_prescription_formData.drugList, { amount: '', des: '', name: '', num: '' }] }
  41 +
  42 + setSend_prescription_formTypeData(setdata)
  43 + }
  44 +
  45 + const removeFormItemHandler = (index: number) => {
  46 + if (Send_prescription_formData.drugList.length <= 1) return
  47 +
  48 + const setdata = { ...Send_prescription_formData, drugList: [...Send_prescription_formData.drugList].filter((_, idx) => idx !== index) }
  49 +
  50 + setSend_prescription_formTypeData(setdata)
  51 + }
  52 +
  53 + const changeFormItemValueHandler = (index: number, value: string | number, key: string) => {
  54 + const setdata = {
  55 + ...Send_prescription_formData,
  56 + drugList: Send_prescription_formData.drugList.map((_, idx) => (idx === index ? { ..._, [key]: value } : _))
  57 + }
  58 +
  59 + setSend_prescription_formTypeData(setdata)
  60 + }
  61 +
  62 + const handleCancel = () => setPreviewOpen(false)
  63 +
  64 + const handlePreview = async (file: UploadFile) => {
  65 + if (!file.url && !file.preview) {
  66 + file.preview = await getBase64(file.originFileObj as RcFile)
  67 + }
  68 +
  69 + setPreviewImage(file.url || (file.preview as string))
  70 + setPreviewOpen(true)
  71 + setPreviewTitle(file.name || file.url!.substring(file.url!.lastIndexOf('/') + 1))
  72 + }
  73 +
  74 + const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => setFileList(newFileList)
  75 +
  76 + useImperativeHandle<HTMLDivElement, any>(ref, () => ({
  77 + Send_prescription_formData,
  78 + fileList
  79 + }))
  80 +
  81 + const uploadButton = (
  82 + <div>
  83 + <PlusOutlined />
  84 + <div style={{ marginTop: 8 }}>上传证明</div>
  85 + </div>
  86 + )
  87 +
  88 + return (
  89 + <SendPrescriptionWrapper ref={ref}>
  90 + <div className="title">问诊病情</div>
  91 + <TextArea
  92 + value={Send_prescription_formData.prescriptionForm}
  93 + onChange={(e) => setSend_prescription_formTypeData({ ...Send_prescription_formData, prescriptionForm: e.target.value })}
  94 + placeholder="请输入问诊病情"
  95 + autoSize={{ minRows: 3, maxRows: 6 }}
  96 + className="title"
  97 + />
  98 + <div className="title">处方药</div>
  99 + {Send_prescription_formData.drugList.map((_, index) => (
  100 + <div className="flexX" key={index}>
  101 + <div className="lefticon" onClick={() => removeFormItemHandler(index)}>
  102 + <MinusCircleOutlined className="grayIcon" />
  103 + </div>
  104 + <div>
  105 + <Input
  106 + value={Send_prescription_formData.drugList[index].name}
  107 + onChange={(e) => changeFormItemValueHandler(index, e.target.value, 'name')}
  108 + className="title"
  109 + placeholder="请输入药品名称"
  110 + />
  111 + <div className="flexA">
  112 + <Input
  113 + value={Send_prescription_formData.drugList[index].amount}
  114 + onChange={(e) => changeFormItemValueHandler(index, e.target.value, 'amount')}
  115 + className="title"
  116 + placeholder="请输入药品价格"
  117 + />
  118 + <Input
  119 + value={Send_prescription_formData.drugList[index].num}
  120 + onChange={(e) => changeFormItemValueHandler(index, e.target.value, 'num')}
  121 + className="title"
  122 + placeholder="请输入药品数量"
  123 + />
  124 + </div>
  125 + <TextArea
  126 + value={Send_prescription_formData.drugList[index].des}
  127 + onChange={(e) => changeFormItemValueHandler(index, e.target.value, 'des')}
  128 + className="title"
  129 + placeholder="请输入说明"
  130 + autoSize={{ minRows: 3, maxRows: 6 }}
  131 + />
  132 + </div>
  133 + </div>
  134 + ))}
  135 + <div className="add flexC" onClick={addFormItemHandler}>
  136 + <PlusCircleOutlined className="blueIcon" />
  137 + <span>添加处方药</span>
  138 + </div>
  139 + <div className="title">处方单证明:</div>
  140 + <Upload action={BASE_URL + '/sys/common/appUpload'} listType="picture-card" fileList={fileList} onPreview={handlePreview} onChange={handleChange}>
  141 + {fileList.length >= 3 ? null : uploadButton}
  142 + </Upload>
  143 + <Modal open={previewOpen} title={previewTitle} footer={null} onCancel={handleCancel}>
  144 + <img alt="example" style={{ width: '100%' }} src={previewImage} />
  145 + </Modal>
  146 + <div className="title">总金额:¥{Send_prescription_formData.prescriptionAmount}</div>
  147 + </SendPrescriptionWrapper>
  148 + )
  149 + })
  150 +)
  151 +
  152 +export default SendPrescription
  1 +import React, { memo } from 'react'
  2 +import type { FC, ReactNode } from 'react'
  3 +import { Image } from 'antd'
  4 +import { ViewPrescriptionWrapper } from '../style'
  5 +
  6 +interface IProps {
  7 + children?: ReactNode
  8 +}
  9 +
  10 +const ViewPrescription: FC<IProps> = memo(() => {
  11 + return (
  12 + <ViewPrescriptionWrapper>
  13 + <div className="title">问诊病情:</div>
  14 + <div className="content">即该不低加造年周消养明价切公没家管发七议性原提何们领从很己发战</div>
  15 + <div className="title">处方药:</div>
  16 + <div className="listbox">
  17 + <div className="itemo">
  18 + <div className="flexJ black">
  19 + <div>药品名称</div>
  20 + <div>¥3.00</div>
  21 + </div>
  22 + <div className="flexJ gray">
  23 + <div>外用,一日3次,每次10毫升</div>
  24 + <div>x2</div>
  25 + </div>
  26 + </div>
  27 + </div>
  28 + <div className="title">处方单证明:</div>
  29 + <Image width={120} src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" className="title" />
  30 + <div className="black">总金额:¥26.00</div>
  31 + </ViewPrescriptionWrapper>
  32 + )
  33 +})
  34 +
  35 +export default ViewPrescription
  1 +import React, { memo } from 'react'
  2 +import type { FC, ReactNode } from 'react'
  3 +import { Avatar, Image } from 'antd'
  4 +import { ViewSymptomWrapper } from '../style'
  5 +
  6 +interface IProps {
  7 + children?: ReactNode
  8 +}
  9 +
  10 +const url = 'https://p1.ssl.qhmsg.com/dr/270_500_/t010c2d50907f0a7b9c.png'
  11 +
  12 +const ViewSymptom: FC<IProps> = memo(() => {
  13 + return (
  14 + <ViewSymptomWrapper>
  15 + <div className="flexJ">
  16 + <div className="flexA top">
  17 + <Avatar size="large" src={<img src={url} alt="avatar" />} />
  18 + <div className="username">卡卡罗特</div>
  19 + <div className="tag">图文问诊</div>
  20 + </div>
  21 + <div className="money">预计收入:¥26.00</div>
  22 + </div>
  23 + <div className="row">
  24 + 就诊宠物:<span>蓝猫/2岁/女/绝育/1kg</span>
  25 + </div>
  26 + <div className="row">
  27 + 免疫情况:<span>不详</span>
  28 + </div>
  29 + <div className="row">
  30 + 喂养方式:<span>自制杂粮</span>
  31 + </div>
  32 + <div className="row">
  33 + 洗澡频次:<span>一周一次</span>
  34 + </div>
  35 + <div className="row">
  36 + 出现症状:<span>其他</span>
  37 + </div>
  38 + <div className="row">
  39 + 症状时间:<span>{`<7天`}</span>
  40 + </div>
  41 + <div className="row">
  42 + 症状描述:<span>快死了哦快死了哦快死了哦快死了哦快死了哦快死了哦快死了哦快死了哦快死了哦快死了哦快死了哦快死了哦快死了哦快死了哦快死了哦快死了哦</span>
  43 + </div>
  44 + <div className="row">
  45 + <div>上传图片</div>
  46 + <Image width={120} src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" />
  47 + </div>
  48 + </ViewSymptomWrapper>
  49 + )
  50 +})
  51 +
  52 +export default ViewSymptom
  1 +import styled from "styled-components";
  2 +
  3 +export const SendPrescriptionWrapper = styled.div`
  4 + max-height: 440px;
  5 + overflow: auto;
  6 + .title{
  7 + color: #323233;
  8 + font-size: 15px;
  9 + font-weight: 700;
  10 + margin: 4px 0;
  11 + }
  12 + .lefticon{
  13 + padding-top: 10px;
  14 + box-sizing: border-box;
  15 + margin-right: 5px;
  16 + }
  17 + .grayIcon{
  18 + font-size: 18px;
  19 + color: #000;
  20 + }
  21 + .add{
  22 + width: 100%;
  23 + box-sizing: border-box;
  24 + padding: 13px 0;
  25 + background: #F3FFFF;
  26 + .blueIcon{
  27 + font-size: 18px;
  28 + color: #09b9d3;
  29 + margin-right: 3px;
  30 + }
  31 + span{
  32 + color: #05b8d2;
  33 + font-size: 15px;
  34 + font-weight: 700;
  35 + }
  36 + }
  37 +`
  38 +
  39 +export const ViewPrescriptionWrapper = styled.div`
  40 + max-height: 440px;
  41 + overflow: auto;
  42 + .title{
  43 + color: #323233;
  44 + font-size: 14px;
  45 + font-weight: 700;
  46 + margin-bottom: 8px;
  47 + }
  48 + .content{
  49 + color: #323233;
  50 + font-size: 14px;
  51 + }
  52 + .itemo{
  53 + margin-bottom: 20px;
  54 + }
  55 + .listbox{
  56 + box-sizing: border-box;
  57 + padding: 16px 14px;
  58 + background: #F8F8FA;
  59 + border-radius: 24px;
  60 + margin-bottom: 12px;
  61 + }
  62 + .black{
  63 + color: #323233;
  64 + font-size: 14px;
  65 + font-weight: 700;
  66 + margin-bottom: 4px;
  67 + }
  68 + .gray{
  69 + color: #999999;
  70 + font-size: 12px;
  71 + font-weight: 700;
  72 + }
  73 +`
  74 +
  75 +export const ViewSymptomWrapper = styled.div`
  76 + max-height: 440px;
  77 + overflow: auto;
  78 + .top{
  79 + margin-bottom: 12px;
  80 + }
  81 + .username{
  82 + color: #242424;
  83 + font-size: 16px;
  84 + font-weight: 700;
  85 + margin: 0 10px;
  86 + }
  87 + .tag{
  88 + border-radius: 12px;
  89 + background: #05B8D2;
  90 + color: #fff;
  91 + font-size: 12px;
  92 + font-weight: 700;
  93 + box-sizing: border-box;
  94 + padding: 2px 7px;
  95 + }
  96 + .money{
  97 + color: #f33f2e;
  98 + font-size: 15px;
  99 + font-weight: 700;
  100 + }
  101 + .row{
  102 + margin-bottom: 12px;
  103 + color: #323233;
  104 + font-size: 28rpx;
  105 + font-weight: 700;
  106 + span{
  107 + color:#666666;
  108 + }
  109 + }
  110 +`
1 -import hyRequest from '@/service'  
2 -import React, { memo, useEffect, useState } from 'react' 1 +import React, { memo, useEffect, useState, useRef, ElementRef } from 'react'
3 import type { FC, ReactNode } from 'react' 2 import type { FC, ReactNode } from 'react'
4 -import { Tabs, Avatar, Space, Divider, Button, Modal, Pagination } from 'antd' 3 +import { Tabs, Avatar, Space, Divider, Button, Modal, Pagination, Carousel } from 'antd'
5 import type { TabsProps } from 'antd' 4 import type { TabsProps } from 'antd'
6 import { ConsultationOrderWrapper, ConsultationOrderItemWrapper } from './styled' 5 import { ConsultationOrderWrapper, ConsultationOrderItemWrapper } from './styled'
7 import { useAppDispatch, useAppSelector, shallowEqualApp } from '@/store' 6 import { useAppDispatch, useAppSelector, shallowEqualApp } from '@/store'
  7 +import { updateSend_prescription_form } from '@/api'
  8 +import { Send_prescription_formType } from '@/types'
8 import { fetchOrderDataAction } from '@/store/modules/order' 9 import { fetchOrderDataAction } from '@/store/modules/order'
  10 +import SendPrescription from '../../com/SendPrescription'
  11 +import ViewPrescription from '../../com/ViewPrescription'
  12 +import ViewSymptom from '../../com/ViewSymptom'
9 13
10 interface IProps { 14 interface IProps {
11 children?: ReactNode 15 children?: ReactNode
@@ -18,13 +22,28 @@ const ShowOrderComHandler: FC<IProps> = (props) => { @@ -18,13 +22,28 @@ const ShowOrderComHandler: FC<IProps> = (props) => {
18 const { orderList } = props 22 const { orderList } = props
19 const [open, setOpenHandler] = useState(false) 23 const [open, setOpenHandler] = useState(false)
20 const [confirmLoading, setConfirmLoading] = useState(false) 24 const [confirmLoading, setConfirmLoading] = useState(false)
  25 + const [modalTitle, setModalTitle] = useState<string>(' ')
  26 + const [modalFlag, setModalFlag] = useState<number>(0)
  27 +
  28 + const SendPrescriptionRef = useRef<ElementRef<typeof SendPrescription> | null>(null)
21 29
22 const showModalHandler = (flag: number) => { 30 const showModalHandler = (flag: number) => {
23 console.log(flag, '按钮状态') 31 console.log(flag, '按钮状态')
  32 + setModalFlag(flag)
  33 + setModalTitle({ 1: '查看症状', 2: '发送处方单', 3: '查看处方单' }[flag] as string)
24 setOpenHandler(true) 34 setOpenHandler(true)
25 } 35 }
26 36
27 - const handleOk = () => { 37 + const handleOk = async () => {
  38 + if (modalFlag === 2) {
  39 + const instance = SendPrescriptionRef.current as any
  40 + await updateSend_prescription_form({
  41 + ...instance.Send_prescription_formData,
  42 + drugList: JSON.stringify(instance.Send_prescription_formData.drugList),
  43 + prescriptionFile: instance.fileList.map((_: any) => _.response.message).join()
  44 + })
  45 + }
  46 + console.log(SendPrescriptionRef.current, 'SendPrescription 子组件实例')
28 setConfirmLoading(true) 47 setConfirmLoading(true)
29 setTimeout(() => { 48 setTimeout(() => {
30 setOpenHandler(false) 49 setOpenHandler(false)
@@ -34,12 +53,14 @@ const ShowOrderComHandler: FC<IProps> = (props) => { @@ -34,12 +53,14 @@ const ShowOrderComHandler: FC<IProps> = (props) => {
34 53
35 const handleCancel = () => { 54 const handleCancel = () => {
36 console.log('Clicked cancel button') 55 console.log('Clicked cancel button')
  56 +
37 setOpenHandler(false) 57 setOpenHandler(false)
38 } 58 }
  59 +
39 return ( 60 return (
40 <ConsultationOrderItemWrapper> 61 <ConsultationOrderItemWrapper>
41 - <Modal title="Title" open={open} onOk={handleOk} cancelText="关闭" okText="确认" confirmLoading={confirmLoading} onCancel={handleCancel}>  
42 - <p>132</p> 62 + <Modal title={modalTitle} open={open} onOk={handleOk} cancelText="关闭" okText="确认" confirmLoading={confirmLoading} onCancel={handleCancel}>
  63 + {{ 1: <ViewSymptom />, 2: <SendPrescription ref={SendPrescriptionRef} />, 3: <ViewPrescription /> }[modalFlag]}
43 </Modal> 64 </Modal>
44 {orderList?.length && 65 {orderList?.length &&
45 orderList.map((_, index) => ( 66 orderList.map((_, index) => (
@@ -89,7 +110,7 @@ const ConsultationOrder: FC<IProps> = memo(() => { @@ -89,7 +110,7 @@ const ConsultationOrder: FC<IProps> = memo(() => {
89 const dispatch = useAppDispatch() 110 const dispatch = useAppDispatch()
90 111
91 useEffect(() => { 112 useEffect(() => {
92 - dispatch(fetchOrderDataAction()) 113 + // dispatch(fetchOrderDataAction())
93 }, []) 114 }, [])
94 115
95 const { banners } = useAppSelector( 116 const { banners } = useAppSelector(
@@ -7,6 +7,7 @@ export const ConsultationOrderWrapper = styled.div` @@ -7,6 +7,7 @@ export const ConsultationOrderWrapper = styled.div`
7 height: calc(100vh - 65px); 7 height: calc(100vh - 65px);
8 overflow: auto; 8 overflow: auto;
9 position: relative; 9 position: relative;
  10 + background: #f5f5f5;
10 .title{ 11 .title{
11 font-size: 18px; 12 font-size: 18px;
12 font-weight: 700; 13 font-weight: 700;
1 import React, { memo, useState } from 'react' 1 import React, { memo, useState } from 'react'
2 import type { FC, ReactNode } from 'react' 2 import type { FC, ReactNode } from 'react'
3 import { LoginWrapper } from './style' 3 import { LoginWrapper } from './style'
4 -import { Input, Button } from 'antd' 4 +import { Input, Button, message } from 'antd'
5 import { useNavigate } from 'react-router-dom' 5 import { useNavigate } from 'react-router-dom'
6 - 6 +import useTimeHandler from '@/hooks/useTimeChange'
  7 +import { DebounceBy } from '@/hooks/debounceBy'
  8 +import { getSendMessage, getMessageLogin } from '@/api'
  9 +import { PhoneCodeLoginParamsType, PhoneCodeLoginType } from '@/types'
  10 +message.config({
  11 + top: 400
  12 +})
7 interface IProps { 13 interface IProps {
8 children?: ReactNode 14 children?: ReactNode
9 } 15 }
@@ -11,26 +17,71 @@ interface IProps { @@ -11,26 +17,71 @@ interface IProps {
11 const Login: FC<IProps> = memo(() => { 17 const Login: FC<IProps> = memo(() => {
12 const naviate = useNavigate() 18 const naviate = useNavigate()
13 19
14 - const loginHandler = () => { 20 + const [loadingState, setLoadingState] = useState<boolean>(false)
  21 +
  22 + const [messageApi, contextHolder] = message.useMessage()
  23 +
  24 + const [form, setForm] = useState<PhoneCodeLoginParamsType>({ phoneNum: '', code: '10086' })
  25 +
  26 + const [countdown, startCountdown] = useTimeHandler()
  27 +
  28 + const warning = (content: string) => messageApi.open({ type: 'warning', content: content })
  29 +
  30 + const success = (content: string) => messageApi.open({ type: 'success', content: content })
  31 +
  32 + const sendCodeHandler = DebounceBy(() => {
  33 + if (!/^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[1589]))\d{8}$/.test(form.phoneNum))
  34 + return warning('请填写正确的手机号')
  35 +
  36 + startCountdown(async () => {
  37 + await getSendMessage({ phoneNum: form.phoneNum })
  38 +
  39 + success('发送成功')
  40 + })
  41 + }, 500)
  42 +
  43 + const loginHandler = async () => {
  44 + if (!/^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[1589]))\d{8}$/.test(form.phoneNum))
  45 + return warning('请填写正确的手机号')
  46 +
15 setLoadingState(true) 47 setLoadingState(true)
16 48
17 - setTimeout(() => {  
18 - setLoadingState(false) 49 + const { result }: { result: PhoneCodeLoginType } = await getMessageLogin(form)
  50 +
  51 + localStorage.setItem('token', result.token)
  52 +
  53 + localStorage.setItem('userId', result.userId)
  54 +
  55 + localStorage.setItem('im_token', result.im_token)
19 56
  57 + success('登录成功')
  58 +
  59 + setTimeout(() => {
20 naviate('/discover') 60 naviate('/discover')
21 - }, 2000)  
22 - }  
23 61
24 - const [loadingState, setLoadingState] = useState<boolean>(false) 62 + setLoadingState(false)
  63 + }, 1000)
  64 + }
25 65
26 return ( 66 return (
27 <LoginWrapper> 67 <LoginWrapper>
  68 + {contextHolder}
28 <div className="loginBox"> 69 <div className="loginBox">
29 <div className="title flexC">宠物问诊-兽医端</div> 70 <div className="title flexC">宠物问诊-兽医端</div>
30 <div className="subtitle">账号</div> 71 <div className="subtitle">账号</div>
31 - <Input placeholder="请输入手机号" className="inputbox" /> 72 + <Input placeholder="请输入手机号" className="inputbox" value={form.phoneNum} onChange={(e) => setForm({ ...form, phoneNum: e.target.value })} />
32 <div className="subtitle">验证码</div> 73 <div className="subtitle">验证码</div>
33 - <Input placeholder="请输入密码" className="inputbox" suffix={<div style={{ color: '#05b8d2', fontSize: '17px' }}>获取验证码</div>} /> 74 + <Input
  75 + placeholder="请输入密码"
  76 + className="inputbox"
  77 + value={form.code}
  78 + onChange={(e) => setForm({ ...form, code: e.target.value })}
  79 + suffix={
  80 + <div style={{ color: '#05b8d2', fontSize: '17px', cursor: 'pointer' }} onClick={sendCodeHandler}>
  81 + {countdown === 60 ? '获取验证码' : `${countdown}秒后可重新获取`}
  82 + </div>
  83 + }
  84 + />
34 <Button className="loginbtn" onClick={loginHandler} loading={loadingState}> 85 <Button className="loginbtn" onClick={loginHandler} loading={loadingState}>
35 登录 86 登录
36 </Button> 87 </Button>