作者 韩昌

首页样式

REACT_APP_NAME=why
REACT_APP_NAME=hachiman
REACT_APP_AGE=18
... ...
REACT_APP_NAME=kobe
REACT_APP_NAME=C
REACT_APP_AGE=30
... ...
... ... @@ -2,13 +2,10 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="icon" href="%PUBLIC_URL%/logo192.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
... ... @@ -24,7 +21,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>宠物问诊后台管理</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
... ...
... ... @@ -3,7 +3,6 @@ import { useRoutes } from 'react-router-dom'
import routes from './router'
import { useAppSelector, useAppDispatch, shallowEqualApp } from './store'
import { changeMessage } from './store/modules/counter'
import AppHeader from './components/appHeader'
function App() {
const { counter } = useAppSelector((state) => state, shallowEqualApp)
... ... @@ -11,9 +10,11 @@ function App() {
function changeMessageHandler() {
dispatch(changeMessage('hahah'))
}
const loginState: boolean = Boolean(localStorage.getItem('token'))
return (
<>
<AppHeader />
<Suspense fallback="loading...">
<div className="App">{useRoutes(routes)}</div>
</Suspense>
... ...
import hyRequest from "@/service";
export const getTopBanner = () => hyRequest.get({ url: '/banner' })
... ...
.flexX{
display: flex;
}
.flexJ {
display: flex;
... ...
[
{
"title": "发现音乐",
"type": "path",
"link": "/discover"
},
{
"title": "我的音乐",
"type": "path",
"link": "/mine"
},
{
"title": "关注",
"type": "path",
"link": "/focus"
},
{
"title": "商城",
"type": "link",
"link": "https://music.163.com/store/product"
},
{
"title": "音乐人",
"type": "link",
"link": "https://music.163.com/st/musician"
},
{
"title": "下载客户端",
"type": "path",
"link": "/download"
}
]
\ No newline at end of file
export const headerLinks = [
{
title: '发现音乐',
link: '/discover'
},
{
title: '我的音乐',
link: '/mine'
},
{
title: '朋友',
link: '/friend'
},
{
title: '商城',
link: 'https://music.163.com/store/product'
},
{
title: '音乐人',
link: 'https://music.163.com/nmusician/web/index#/'
},
{
title: '下载客户端',
link: 'https://music.163.com/#/download'
}
]
export const footerLinks = [
{
title: '服务条款',
link: 'https://st.music.163.com/official-terms/service'
},
{
title: '隐私政策',
link: 'https://st.music.163.com/official-terms/privacy'
},
{
title: '儿童隐私政策',
link: 'https://st.music.163.com/official-terms/children'
},
{
title: '版权投诉指引',
link: 'https://music.163.com/st/staticdeal/complaints.html'
},
{
title: '意见反馈',
link: '#'
}
]
export const footerImages = [
{
link: 'https://music.163.com/st/userbasic#/auth'
},
{
link: 'https://music.163.com/recruit'
},
{
link: 'https://music.163.com/web/reward'
},
{
link: 'https://music.163.com/uservideo#/plan'
}
]
// discover中的数据
export const discoverMenu = [
{
title: '推荐',
link: '/discover/recommend'
},
{
title: '排行榜',
link: '/discover/ranking'
},
{
title: '歌单',
link: '/discover/songs'
},
{
title: '主播电台',
link: '/discover/djradio'
},
{
title: '歌手',
link: '/discover/artist'
},
{
title: '新碟上架',
link: '/discover/album'
}
]
// 热门主播
export const hotRadios = [
{
picUrl:
'http://p1.music.126.net/H3QxWdf0eUiwmhJvA4vrMQ==/1407374893913311.jpg',
name: '陈立',
position: '心理学家、美食家陈立教授',
url: '/user/home?id=278438485'
},
{
picUrl:
'http://p1.music.126.net/y5-sM7tjnxnu_V9LWKgZlw==/7942872001461517.jpg',
name: 'DJ艳秋',
position: '著名音乐节目主持人',
url: '/user/home?id=91239965'
},
{
picUrl:
'http://p1.music.126.net/6cc6lgOfQTo6ovNnTHPyJg==/3427177769086282.jpg',
name: '国家大剧院古典音乐频道',
position: '国家大剧院古典音乐官方',
url: '/user/home?id=324314596'
},
{
picUrl:
'http://p1.music.126.net/xa1Uxrrn4J0pm_PJwkGYvw==/3130309604335651.jpg',
name: '谢谢收听',
position: '南京电台主持人王馨',
url: '/user/home?id=1611157'
},
{
picUrl:
'http://p1.music.126.net/slpd09Tf5Ju82Mv-h8MP4w==/3440371884651965.jpg',
name: 'DJ晓苏',
position: '独立DJ,CRI环球旅游广播特邀DJ',
url: '/user/home?id=2313954'
}
]
// 歌手类别
export const artistCategories = [
{
title: '推荐',
area: -1,
artists: [
{
name: '推荐歌手',
type: 1,
url: '/discover/artist',
id: 0
},
{
name: '入驻歌手',
type: 2,
url: '/discover/artist?cat=5001',
dataPath: '/artist/list?cat=5001'
}
]
},
{
title: '华语',
area: 7,
artists: [
{
name: '华语男歌手',
url: '/discover/artist?id=1001',
type: 1
},
{
name: '华语女歌手',
url: '/discover/artist?id=1002',
type: 2
},
{
name: '华语组合/乐队',
url: '/discover/artist?id=1003',
type: 3
}
]
},
{
title: '欧美',
area: 96,
artists: [
{
name: '欧美男歌手',
url: '/discover/artist?id=2001',
type: 1
},
{
name: '欧美女歌手',
url: '/discover/artist?id=2002',
type: 2
},
{
name: '欧美组合乐队',
url: '/discover/artist?id=2003',
type: 3
}
]
},
{
title: '日本',
area: 8,
artists: [
{
name: '日本男歌手',
url: '/discover/artist?id=6001',
type: 1
},
{
name: '日本女歌手',
url: '/discover/artist?id=6002',
type: 2
},
{
name: '日本组合/乐队',
url: '/discover/artist?id=6003',
type: 3
}
]
},
{
title: '韩国',
area: 16,
artists: [
{
name: '韩国男歌手',
url: '/discover/artist?id=7001',
type: 1
},
{
name: '韩国女歌手',
url: '/discover/artist?id=7002',
type: 2
},
{
name: '韩国组合/乐队',
url: '/discover/artist?id=7003',
type: 3
}
]
},
{
title: '其他',
area: 0,
artists: [
{
name: '其他男歌手',
url: '/discover/artist?id=4001',
type: 1
},
{
name: '其他女歌手',
url: '/discover/artist?id=4002',
type: 2
},
{
name: '其他组合乐队',
url: '/discover/artist?id=4003',
type: 3
}
]
}
]
... ... @@ -15,6 +15,7 @@ export const AppHeaderWrapper = styled.div`
width: 40px;
height: 40px;
margin-right: 16px;
cursor: pointer;
}
.username{
font-size: 20px;
... ... @@ -25,5 +26,6 @@ export const AppHeaderWrapper = styled.div`
.loginout{
font-size: 18px;
color: #fff;
cursor: pointer;
}
`
... ...
import React, { memo } from 'react'
import type { FC, ReactNode } from 'react'
import { Space, Spin } from 'antd'
interface IProps {
children?: ReactNode
}
const AppLoading: FC<IProps> = memo(() => {
return (
<Space size="middle">
<Spin size="large" />
</Space>
)
})
export default AppLoading
... ...
import React, { memo, useState } from 'react'
import {
SnippetsOutlined,
AppstoreOutlined,
ContainerOutlined,
DesktopOutlined,
MailOutlined,
MenuFoldOutlined,
MenuUnfoldOutlined,
PieChartOutlined
} from '@ant-design/icons'
import type { FC, ReactNode } from 'react'
import { useNavigate } from 'react-router-dom'
import type { MenuProps } from 'antd'
import { Button, Menu } from 'antd'
import { AppMenyWrapper } from './styled'
type MenuItem = Required<MenuProps>['items'][number]
interface IProps {
children?: ReactNode
}
function getItem(label: React.ReactNode, key: React.Key, icon?: React.ReactNode, children?: MenuItem[], type?: 'group'): MenuItem {
return {
key,
icon,
children,
label,
type
} as MenuItem
}
const items: MenuItem[] = [
getItem('我的订单', '1', <SnippetsOutlined />),
getItem('暂不开放', '2', <DesktopOutlined />)
// getItem('Option 3', '3', <ContainerOutlined />),
// getItem('Navigation One', 'sub1', <MailOutlined />, [getItem('Option 5', '5'), getItem('Option 6', '6'), getItem('Option 7', '7'), getItem('Option 8', '8')]),
// getItem('Navigation Two', 'sub2', <AppstoreOutlined />, [
// getItem('Option 9', '9'),
// getItem('Option 10', '10'),
// getItem('Submenu', 'sub3', null, [getItem('Option 11', '11'), getItem('Option 12', '12')])
// ])
]
type ObjectString = {
[key: string]: string
}
const navigateUrl: ObjectString = {
'1': '/discover/ConsultationOrder',
'2': '/discover/xx'
}
const AppMenu: FC<IProps> = memo(() => {
const navigate = useNavigate()
const [collapsed, setCollapsed] = useState(false)
const toggleCollapsed = () => {
setCollapsed(!collapsed)
}
const onselectHandler = (e: any) => {
console.log(e, 'eee')
navigate(navigateUrl[e.key])
}
return (
<AppMenyWrapper style={{ width: 256 }}>
<Menu
defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']}
mode="inline"
theme="dark"
inlineCollapsed={collapsed}
items={items}
onSelect={(e) => onselectHandler(e)}
/>
</AppMenyWrapper>
)
})
export default AppMenu
... ...
import styled from "styled-components";
export const AppMenyWrapper = styled.div`
height: calc(100vh - 65px);
background: #001529;
`
... ...
... ... @@ -2,22 +2,29 @@ import React, { lazy } from 'react'
import { Navigate } from 'react-router-dom'
import type { RouteObject } from 'react-router-dom'
const XX = lazy(() => import('@/views/discover/view/xx'))
// 路由懒加载
const Discover = lazy(() => import('@/views/discover'))
const Recommend = lazy(() => import('@/views/discover/view/recommend'))
const ConsultationOrder = lazy(() => import('@/views/discover/view/ConsultationOrder'))
const Login = lazy(() => import('@/views/login'))
const loginState = Boolean(localStorage.getItem('token'))
const path = loginState ? '/discover' : '/login'
const routes: RouteObject[] = [
{ path: '/', element: <Navigate to={'/login'} /> },
{ path: '/', element: <Navigate to={path} /> },
{ path: '/login', element: <Login /> },
{
path: '/discover',
element: <Discover />,
children: [
{ path: '/discover', element: <Navigate to={'/discover/recommend'} /> },
{ path: '/discover/recommend', element: <Recommend /> },
{ path: '/discover', element: <Navigate to={'/discover/ConsultationOrder'} /> },
{ path: '/discover/ConsultationOrder', element: <ConsultationOrder /> },
{ path: '/discover/xx', element: <XX /> }
]
},
}
]
export default routes
... ...
import { configureStore } from "@reduxjs/toolkit";
import { useSelector, useDispatch, TypedUseSelectorHook, shallowEqual } from 'react-redux'
import counterReducer from './modules/counter'
import orderReducer from './modules/order'
const store = configureStore({
reducer: {
counter: counterReducer
counter: counterReducer,
order: orderReducer
}
})
... ...
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import { getTopBanner } from '@/api'
export const fetchOrderDataAction = createAsyncThunk(
'fetchdata',
(payload, { dispatch }) => {
// 1.顶部的banners
getTopBanner().then((res: any) => {
dispatch(changeBannerAction(res.banners))
})
return null
}
)
const orderSlice = createSlice({
name: 'order',
initialState: {
count: 100,
message: 'hello Redux',
name: 'HachimanC',
bannersList: []
},
reducers: {
changeBannerAction(state, { payload }) {
state.bannersList = payload
}
}
})
export default orderSlice.reducer
export const { changeBannerAction } = orderSlice.actions
... ...
export * from './result'
... ...
export interface Result<ResultType> {
code: number
message: string
result: ResultType
success: boolean
timestamp: number
}
export interface PageListType<PageListItemType> {
records: PageListItemType[]
current: number
total: number
size: number
}
export interface ConsultationOrderRecordsType {
id: string;
order_no: string;
petId: string;
petName: string;
petClass: string;
petType: number;
petSec: number;
isSterilization: number;
isAgain: number;
age: number;
weight: string;
symptom: string;
supplement: string;
image: string[];
remainder: number;
consultationState: number;
consultationWay: number;
immuneStatus: string;
feedType: string;
batheFrequency: string;
timeFrame: string;
payAmount: number;
realityPayAmount: number;
payTime: string;
amount: number;
prescriptionForm: string;
prescriptionFile: string;
award: number;
user: User;
doctor: Doctor;
time: string;
consultationay: number;
orderState: number;
effect_award: number;
}
... ...
import { BASE_URL } from '@/service/request/config'
// immuneStatus: { 1:'',2:'',3: '',4: '' }
type ObjectString = {
[key: string]: {
[key: string]: string | number
}
}
const GlobalData: ObjectString = {
'examineState': { 0: '去认证', 10: '审核中', 30: '认证失败', 20: '认证成功' },
'incomeTypeList': { 1: '问诊订单', 2: '提现' },
'ReceivePatients': { 0: '暂不接诊', 1: '在线坐诊' },
'sexData': { 0: '未知', 1: '男', 2: '女' },
'MessageType': { 1: '系统通知', 2: '用户反馈' },
'consultationWay': { 10: '快速问诊', 21: '专家图文语音问诊', 22: '专家视频问诊', 23: '专家电话问诊' },
'isReply': { 0: '否', 1: '是' },
'orderState': { 20: '待问诊', 30: '问诊中', 40: '问诊结束', 50: '已取消' },
'state': { 0: '待发货', 1: '已发货', 2: '已完成', 3: '已退货' },
'isSterilization': { 0: '否', 1: '是' }, // 是否绝育
'petSec': { 0: '母', 1: '公' },
'immuneStatus': { 1: '已免疫', 2: '未免疫', 3: '免疫不全', 4: '免疫不详' },
'feedType': { 1: '配方粮', 2: '配方粮+零食', 3: '只吃人食物', 4: '自制犬猫粮' },
'batheFrequency': { 1: '一周一次(狗狗)', 2: '洗澡频次不规律', 3: '想起来才洗', 4: '定期洗澡(猫猫)' },
'timeFrame': { 1: '<7天', 2: '<1个月', 3: '<3个月', 4: '3个月以上' },
'petType': { 10: '猫', 20: '狗', 30: '异宠' },
'isAgain': { 1: '是', 0: '否' },
'symptom': { 1: '呕吐', 2: '软便拉稀', 3: '皮肤问题', 4: '眼睛问题', 5: '泌尿问题', 6: '绝育', 7: '疫苗', 8: '驱虫', 9: '养护问题', 10: '其他' }
}
export default {
optData(key: string) {
return GlobalData[key]
},
optObjectValue(object: string, key: string | number) {
return GlobalData[object][key] || ''
},
downFile(fileName: string) {
if (fileName == '' || fileName == undefined) return ''
if (fileName.indexOf(BASE_URL) > -1 || fileName.indexOf('http://') > -1 || fileName.indexOf('https://') > -1) return fileName
return BASE_URL + '/v1/public/downLoadPic?fileName=' + fileName
},
formatStr(str: string, val: string) {
if (str == null || str == undefined) return val || ''
return str
},
}
... ...
... ... @@ -2,7 +2,9 @@ import React, { Suspense, memo } from 'react'
import type { FC, ReactNode } from 'react'
import { NavLink, Outlet } from 'react-router-dom'
import { DiscoverWrapper } from './style'
import { discoverMenu } from '@/assets/data/local-data'
import AppHeader from '@/components/appHeader'
import AppMenu from '@/components/appMenu'
import AppLoading from '@/components/appLoading'
interface IProps {
children?: ReactNode
... ... @@ -11,9 +13,15 @@ interface IProps {
const Discover: FC<IProps> = memo(() => {
return (
<DiscoverWrapper>
<Suspense fallback="二级路由渲染">
<Outlet />
</Suspense>
<AppHeader />
<div className="flexX">
<AppMenu />
<Suspense fallback={<AppLoading />}>
<Outlet />
</Suspense>
</div>
</DiscoverWrapper>
)
})
... ...
import hyRequest from '@/service'
import React, { memo, useEffect, useState } from 'react'
import type { FC, ReactNode } from 'react'
import { Tabs, Avatar, Space, Divider, Button, Modal, Pagination } from 'antd'
import type { TabsProps } from 'antd'
import { ConsultationOrderWrapper, ConsultationOrderItemWrapper } from './styled'
import { useAppDispatch, useAppSelector, shallowEqualApp } from '@/store'
import { fetchOrderDataAction } from '@/store/modules/order'
interface IProps {
children?: ReactNode
orderList?: string[]
}
const url = 'https://p1.ssl.qhmsg.com/dr/270_500_/t010c2d50907f0a7b9c.png'
const ShowOrderComHandler: FC<IProps> = (props) => {
const { orderList } = props
const [open, setOpenHandler] = useState(false)
const [confirmLoading, setConfirmLoading] = useState(false)
const showModalHandler = (flag: number) => {
console.log(flag, '按钮状态')
setOpenHandler(true)
}
const handleOk = () => {
setConfirmLoading(true)
setTimeout(() => {
setOpenHandler(false)
setConfirmLoading(false)
}, 2000)
}
const handleCancel = () => {
console.log('Clicked cancel button')
setOpenHandler(false)
}
return (
<ConsultationOrderItemWrapper>
<Modal title="Title" open={open} onOk={handleOk} cancelText="关闭" okText="确认" confirmLoading={confirmLoading} onCancel={handleCancel}>
<p>132</p>
</Modal>
{orderList?.length &&
orderList.map((_, index) => (
<div className="orderItem " key={index}>
<div className="topinfo flexJ">
<div className=" flexA">
<Avatar size="large" src={<img src={url} alt="avatar" />} />
<div className="username">卡卡罗特</div>
<div className="statetag flexC">图文问诊</div>
<div className="time">2023.10.07</div>
</div>
<div className="stateText">待问诊</div>
</div>
<div className="contenttext">
<span>就诊宠物:</span>蓝猫/2岁/女绝/育/1kg
</div>
<div className="contenttext">
<span>病情描述:</span>即该不低加造年周消养明价切公没家管发七议性原提何们领从很己发战
</div>
<Divider />
<div className="flexJ">
<div className="moneytext">
预计收入
<span>¥26.00</span>
</div>
<div className="flexA">
<Space wrap>
<Button type="primary" shape="round" onClick={() => showModalHandler(1)}>
查看症状
</Button>
<Button type="primary" shape="round" onClick={() => showModalHandler(2)}>
发送处方单
</Button>
<Button type="primary" shape="round" onClick={() => showModalHandler(3)}>
查看处方单
</Button>
</Space>
</div>
</div>
</div>
))}
</ConsultationOrderItemWrapper>
)
}
const ConsultationOrder: FC<IProps> = memo(() => {
const dispatch = useAppDispatch()
useEffect(() => {
dispatch(fetchOrderDataAction())
}, [])
const { banners } = useAppSelector(
(state) => ({
banners: state.order.bannersList
}),
shallowEqualApp
)
useEffect(() => {
if (!banners.length) return
console.log(banners)
}, [banners])
const [text, setText] = useState<string[]>([])
const items: TabsProps['items'] = [
{ key: '0', label: '全部', children: ShowOrderComHandler({ orderList: text }) },
{ key: '1', label: '待处理', children: ShowOrderComHandler({ orderList: text }) },
{ key: '2', label: '处理中', children: ShowOrderComHandler({ orderList: text }) },
{ key: '3', label: '已处理', children: ShowOrderComHandler({ orderList: text }) }
]
const onChange = (key: string) => {
setText([key, '1', '2', '', '', '', ''])
}
return (
<ConsultationOrderWrapper>
<div className="title">问诊订单</div>
<Tabs defaultActiveKey="0" items={items} onChange={onChange} />;
<div className="paginationBox flexD">
<Pagination defaultCurrent={1} total={50} />
</div>
</ConsultationOrderWrapper>
)
})
export default ConsultationOrder
... ...
import styled from "styled-components"
export const ConsultationOrderWrapper = styled.div`
box-sizing: border-box;
padding: 16px 24px;
width: 100%;
height: calc(100vh - 65px);
overflow: auto;
position: relative;
.title{
font-size: 18px;
font-weight: 700;
margin-bottom: 16px;
}
.paginationBox{
/* position: absolute;
bottom: 20px;
right: 20px; */
}
`
export const ConsultationOrderItemWrapper = styled.div`
display: flex;
flex-wrap: wrap;
margin-right: -32px;
.orderItem{
margin-bottom: 16px;
margin-right: 16px;
box-sizing: border-box;
padding: 10px 12px;
border-radius: 20px;
background: #fff;
width: 48%;
.topinfo{
margin-bottom: 20px;
.username{
color: #323233;
font-size: 15px;
font-weight: 700;
margin: 0 10px;
}
.statetag{
box-sizing: border-box;
padding: 2px 6px;
border: 1px solid #05B8D2;
border-radius: 8px;
color: #05b8d2;
font-size: 11px;
font-weight: 700;
margin-right: 10px;
}
.time{
color: #999999;
font-size: 13px;
}
.stateText{
color: #05b8d2;
font-size: 14px;
font-weight: 700;
}
}
.contenttext{
color: #323233;
font-size: 14px;
font-weight: 700;
margin-bottom: 10px;
span{
color: #666666;
}
}
.moneytext{
color: #f33f2e;
font-size: 14px;
font-weight: 700;
}
}
`
... ...
import hyRequest from '@/service'
import React, { memo, useEffect } from 'react'
import type { FC, ReactNode } from 'react'
interface IProps {
children?: ReactNode
}
const Recommend: FC<IProps> = memo(() => {
useEffect(() => {
hyRequest.get({ url: '/banner' }).then((res) => {
console.log(res, 'banner')
})
}, [])
return <div>Recommend</div>
})
export default Recommend
import React, { memo } from 'react'
import type { FC, ReactNode } from 'react'
interface IProps {
children?: ReactNode
}
const xx: FC<IProps> = memo(() => {
return <div style={{ width: '100%' }}>暂不开放</div>
})
export default xx
... ...