diff --git a/package.json b/package.json index 0c32b0a369dc935bb3eb0f1dba56b3da4e96e6d1..f5f5b6a30d32ae7a6a14953f70764759bc885636 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "antd-img-crop": "^4.5.2", "antd-mobile": "^5.1.4", "crypto-js": "^4.1.1", + "echarts": "^5.4.1", + "echarts-for-react": "^3.0.2", "umi-request": "^1.4.0" }, "devDependencies": { diff --git a/src/app.jsx b/src/app.jsx index 0fd722a49bd0545665214bdf2128a50aaed87c28..d1fdc5b3d2f52efcaf2e9c388fa83ace958d0b9c 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -16,6 +16,10 @@ import { theme } from 'antd'; export const antd = (memo) => { memo.theme ||= {}; memo.theme.algorithm = theme.darkAlgorithm; + memo.theme.token = { + colorPrimary: '#3878e4', + + } return memo; }; diff --git a/src/components/AutoTable/index.jsx b/src/components/AutoTable/index.jsx index db40da73579e39e8edea37c57a3c3bb6475aa9f0..a159c57c5653278af04e491cf28f781606a98c55 100644 --- a/src/components/AutoTable/index.jsx +++ b/src/components/AutoTable/index.jsx @@ -96,7 +96,7 @@ export default (props) => { <div className={styles.header}> <div className="center"> <div className={styles.left}> - <div + {/* <div className="center" style={{ width: 30, height: 30, marginRight: 8 }} onClick={() => { @@ -104,7 +104,7 @@ export default (props) => { }} > <FilterFilled /> - </div> + </div> */} <SearchBar style={{ flex: 1 }} @@ -141,11 +141,13 @@ export default (props) => { await reFresh(); }} > - <Empty - style={{ padding: '64px 0' }} - imageStyle={{ width: '30vw' }} - description="æš‚æ— æ•°æ®" - /> + <div style={{ minHeight: 'calc(100vh - 172px)' }}> + <Empty + style={{ padding: '64px 0' }} + imageStyle={{ width: '30vw' }} + description="æš‚æ— æ•°æ®" + /> + </div> </PullToRefresh> )} </> diff --git a/src/components/AutoTable/index.less b/src/components/AutoTable/index.less index 0a1d5b0ea83a33f88ac9c0029740105e03f19ec9..eec853b1289348c68cecb51581fd4e712679d726 100644 --- a/src/components/AutoTable/index.less +++ b/src/components/AutoTable/index.less @@ -1,7 +1,6 @@ /* stylelint-disable rule-empty-line-before */ .header { - background-color: rgb(18 19 33 / 50%); display: flex; align-items: center; position: sticky; diff --git a/src/global.less b/src/global.less index 92e7170b0063e58018bd5ba17e23a7b51615e8f7..0888deefecef72b4fdb918c4e25d1d9f02483859 100644 --- a/src/global.less +++ b/src/global.less @@ -29,19 +29,60 @@ body, } } a { - color: #4ddaec; + color: #3878e4; } :root:root { - --adm-color-primary: #4ddaec; - --adm-color-background: #0d0e1f; + --adm-color-primary: #3878e4; + --adm-color-background: #0d2152; +} +.adm-list-item{ + background-color: transparent; + a:hover{ + color: #fff !important; + } } .adm-list-item-content { border: none !important; } - +.adm-search-bar-input-box { + background-color: #0d2152 !important; + input { + color: #f0f0f0; + } +} +.adm-list { + background-color: transparent !important; +} .adm-list-body { - border-top: 1px solid #2c2d4a; - border-bottom: 1px solid #2c2d4a; + border-top: none !important; + border-bottom: none !important; border-radius: 0; + background-color: transparent !important; + } + +.ant-input-affix-wrapper, +.ant-checkbox-inner { + background-color: #0d2152 !important ; + input { + background-color: transparent !important; + } +} +.split{ + padding: 6px 0; + margin: 0px 12px; + border-top: 1px dashed #f0f0f01d; + border-bottom: 1px dashed #f0f0f01a; +} +.ant-drawer-content{ + background: linear-gradient(to bottom, #142f4d, #657b90) !important; +} +*:focus { + outline: none; +} +.spread{ + display: flex; + justify-content: space-between; + align-items: center; +} \ No newline at end of file diff --git a/src/layouts/BasicLayout.jsx b/src/layouts/BasicLayout.jsx index 2a55c31989b5887eae945000bdfc0cf57d74f0a8..a00463bc2b1df20fe1649f1e7d5d05f0cc51ec85 100644 --- a/src/layouts/BasicLayout.jsx +++ b/src/layouts/BasicLayout.jsx @@ -1,17 +1,27 @@ import React, { useState, useEffect } from 'react'; import { Outlet, history, useLocation, useAppData } from '@umijs/max'; -import { NavBar, TabBar } from 'antd-mobile'; +import { NavBar, TabBar, List } from 'antd-mobile'; import { AppOutline, MessageOutline, UnorderedListOutline, UserOutline, + PayCircleOutline, + SetOutline, } from 'antd-mobile-icons'; import './index.less'; import { useMemo } from 'react'; -import { MenuOutlined, ArrowLeftOutlined } from '@ant-design/icons'; -import { Drawer } from 'antd'; - +import { + MenuOutlined, + ArrowLeftOutlined, + EditOutlined, + UsergroupAddOutlined, + HomeOutlined, + LogoutOutlined, + LockOutlined +} from '@ant-design/icons'; +import { Drawer, Avatar, Button, Divider } from 'antd'; +import { UserOutlined } from '@ant-design/icons'; /* menulist ä¸çš„表示主路由èœå•上左上角是打开 drawer å¦åˆ™ä¸ºè¿”回上一页 @@ -60,6 +70,30 @@ function BasicLayout() { const [drawer, setdrawer] = useState({ open: false }); + const [startX, setStartX] = useState(null); + const [startY, setStartY] = useState(null); + + function handleTouchStart(event) { + setStartX(event.touches[0].clientX); + setStartY(event.touches[0].clientY); + } + + function handleTouchMove(event) { + const { clientX, clientY } = event.touches[0]; + const distance = clientX - startX; + const distancey = clientY - startY; + if (distancey > 10 || distancey < -10) { + return; + } + if (distance > 20) { + // 执行左滑æ“作 + setdrawer((s) => ({ + ...s, + open: true, + })); + } + } + return ( <div className="container"> <Drawer @@ -73,7 +107,32 @@ function BasicLayout() { {...drawer} width={'80%'} placement="left" - ></Drawer> + > + <div className="userinfo" style={{position:"relative",height:"100%"}}> + <Avatar size={56} icon={<UserOutlined />}></Avatar> + <div className="spread" style={{ alignItems: 'flex-end',paddingBottom:8 }}> + <div> + <h2>UserName</h2> + <p style={{ margin: 0 }}>13512555441</p> + </div> + <Button + style={{ color: '#fff', borderColor: '#fff' }} + ghost + type="primary" + icon={<EditOutlined />} + ></Button> + </div> + <Divider></Divider> + <List header="个人信æ¯" style={{marginLeft:-12}}> + <List.Item prefix={<UserOutline />} extra="æŽç¿°æž—">用户å</List.Item> + <List.Item prefix={<UsergroupAddOutlined />} extra="维修部">组织</List.Item> + <List.Item prefix={<HomeOutlined style={{fontSize:14,paddingLeft:3}}/>} extra="天åŽé™¢">å…¬å¸</List.Item> + <List.Item prefix={<LockOutlined/>} onClick={()=>{}} style={{backgroundColor:"rgba(0,0,0,0.2)",borderRadius:8}}>修改密ç </List.Item> + + </List> + <Button icon={<LogoutOutlined/>} size='large' style={{width:"100%",marginTop:12,position:"absolute",bottom:0,left:0,right:0,backgroundColor:"rgba(0,0,0,0.2)"}} type="ghost">退出</Button> + </div> + </Drawer> <div className="top"> <NavBar backArrow={ @@ -98,8 +157,10 @@ function BasicLayout() { </NavBar> </div> <div style={{ height: 45 }}></div> + <div onTouchStart={handleTouchStart} onTouchMove={handleTouchMove}> + <Outlet></Outlet> + </div> - <Outlet></Outlet> <div style={{ height: 66 }}></div> <div className="bottom"> <TabBar diff --git a/src/layouts/index.less b/src/layouts/index.less index b7e828c9cb81f1e2d5f82766b99c5d4d31e05543..1709a44243ec19b64978c950d5f0eaf85ba1aeeb 100644 --- a/src/layouts/index.less +++ b/src/layouts/index.less @@ -1,6 +1,6 @@ .container { - background-color: #0e0e1f; - + background: linear-gradient(to bottom, #142f4d, #657b90) !important; + min-height: 100vh; div { color: #fff; } @@ -12,7 +12,7 @@ z-index: 999; left: 0; width: 100%; - background-color: rgb(18 19 33 / 50%); + background-color: rgb(18 19 33 / 0%); right: 0; margin: auto; backdrop-filter: blur(2px); @@ -23,8 +23,8 @@ bottom: 0; z-index: 999; left: 0; - width: 96%; - background-color: #121321; + width: 100%; + background: linear-gradient(to bottom, #324d6b, #395471) !important; right: 0; margin: auto; height: 66px; @@ -32,8 +32,13 @@ justify-content: center; align-items: center; border-radius: 12px 12px 0 0; + box-shadow: 0px -2px 16px rgba(0, 0, 0, 0.8); > div { width: 100%; } } + +.userinfo{ + color: #fff; +} \ No newline at end of file diff --git a/src/pages/home/index.jsx b/src/pages/home/index.jsx index 6bd9386ffb648449331e04c03046ab34cc3ffb1d..dc986083193f8bad98ef1dff22aa6758c197cf59 100644 --- a/src/pages/home/index.jsx +++ b/src/pages/home/index.jsx @@ -4,39 +4,101 @@ import DrawerPro from '@/components/DrawerPro'; import AutoTable from '@/components/AutoTable'; import PremButton from '@/components/PremButton'; import getcolumns from './columns'; -import { useRequest } from 'ahooks'; +import { useAsyncEffect, useRequest } from 'ahooks'; import { doFetch } from '@/utils/doFetch'; -import { List } from 'antd-mobile'; - -const Extra = ({ it, item }) => { - return ( - <div>{it?.render?.(item[it?.dataIndex], item) ?? item[it?.dataIndex]}</div> - ); -}; +import ReactECharts from 'echarts-for-react'; +function cropImage(url) { + return new Promise(resolve => { + const img = new Image(); + img.crossOrigin = 'Anonymous'; + img.src = url; + img.onload = () => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + const size = Math.min(img.width, img.height); + canvas.width = size; + canvas.height = size; + ctx.beginPath(); + ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI); + ctx.clip(); + ctx.drawImage(img, (img.width - size) / 2, (img.height - size) / 2, size, size, 0, 0, size, size); + canvas.toBlob(blob => { + const reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onloadend = () => { + resolve(reader.result); + }; + }, 'image/png'); + }; + }); +} const Cards = ({ item, columns }) => { + const [option, setoption] = useState({}); + + useAsyncEffect(async ()=>{ + const image = await cropImage("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fci.xiaohongshu.com%2F5fa1e703-a04f-b373-0e3f-f0afd5e12a9d%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fci.xiaohongshu.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1679472844&t=e0db0d99ce81259343ab29af461e7722") + const options = { + series: [ + { + type: 'pie', + radius: ['50%', '70%'], + avoidLabelOverlap: false, + label: { + show: false, + position: 'center' + }, + data: [ + { value: 335, name: '直接访问' }, + { value: 310, name: '邮件è¥é”€' }, + { value: 234, name: 'è”盟广告' }, + { value: 135, name: '视频广告' }, + { value: 1548, name: 'æœç´¢å¼•擎' }, + ], + }, + ], + graphic: { + elements: [ + { + type: 'image', + style: { + image: image, + width: 56, + height: 56, + }, + left:"center", + top:"center" + }, + ], + }, + }; + + setoption(options) + },[item]) + + + return ( - <List - mode="card" - key={item.dataIndex} - onClick={() => { - alert(0); - }} - > - {columns - ?.filter((it) => !(it.valueType === 'split' || it?.hideInTable)) - ?.map((it) => { - return ( - <List.Item - key={it?.dataIndex} - extra={<Extra it={it} item={item} />} - arrow={false} - > - {it?.title} - </List.Item> - ); - })} - </List> + <div className="split"> + <div className="spread" style={{justifyContent:"flex-start"}}> + <div style={{width:120,height:120,flexShrink:0}}> + <ReactECharts option={option} style={{height:"100%"}}/> + </div> + + <div style={{flex:1}}> + {columns + ?.filter((it) => !(it.valueType === 'split' || it?.hideInTable)) + ?.map((it) => { + return ( + <div key={it?.dataIndex} arrow={false} style={{fontSize:15}}> + {it?.title} + {item[it?.dataIndex]} + </div> + ); + })} + </div> + </div> + </div> ); }; @@ -61,91 +123,11 @@ function Home(props) { }, }); - const detail = (text, row, _, action) => { - return ( - <PremButton - btn={{ - size: 'small', - type: 'link', - onClick: () => { - setdrawer((s) => ({ - ...s, - open: true, - item: row, - title: '详情', - val: 'detail', - title: '详细信æ¯', - })); - }, - }} - > - 详情 - </PremButton> - ); - }; - - const edit = (text, row, _, action) => { - return ( - <PremButton - btn={{ - size: 'small', - onClick: () => { - setdrawer((s) => ({ - ...s, - open: true, - item: row, - title: '编辑', - val: 'edit', - })); - }, - }} - > - 编辑 - </PremButton> - ); - }; - - const remove = (text, row, _, action) => { - return ( - <PremButton - pop={{ - title: '是å¦åˆ 除?', - okText: '确认', - cancelText: 'å–æ¶ˆ', - onConfirm: () => { - run({ - url: pathconfig?.delete || '/delete', - params: { id: row?.id }, - }); - }, - }} - btn={{ - size: 'small', - type: 'danger', - }} - > - åˆ é™¤ - </PremButton> - ); - }; - const columns = useMemo(() => { let defcolumn = getcolumns(setdrawer).filter( (it) => it.key === activeTabKey, )[0]?.columns; - let defpath = - getcolumns(setdrawer).filter((it) => it.key === activeTabKey)[0] - ?.pathconfig ?? {}; - return defcolumn.concat({ - title: 'æ“作', - valueType: 'option', - width: 150, - render: (text, row, _, action) => [ - defpath?.enabledetail && detail(text, row, _, action), - defpath?.enableedit && edit(text, row, _, action), - defpath?.enabledelete && remove(text, row, _, action), - ], - }); + return defcolumn; }, [activeTabKey]); const pathconfig = useMemo(() => { diff --git a/src/pages/login/index.less b/src/pages/login/index.less index 9c699421e69c1cabd0cc4caefb3e71c4dcc624ac..2b4b88d625ee9e8743a017235f4afcde706c05de 100644 --- a/src/pages/login/index.less +++ b/src/pages/login/index.less @@ -177,7 +177,7 @@ height: 116px; object-fit: cover; } - h2{ - color: #fff + h2 { + color: #fff; } }