Commit 90f8ac85 by 肖康

init

parent 51fba4dc
Showing with 13141 additions and 2 deletions
{
"extends": "next/core-web-vitals"
}
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
# next.js
/.next
#/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
#next-env.d.ts
/.next
a
\ No newline at end of file
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
import { useState, useEffect } from 'react'
import useRequest from "@/hooks/useRequest"
import { Modal, Table, TableColumnsType, Button } from 'antd';
// 定义子组件 props 类型
interface ChildComponentProps {
status: any;
onMessageChange: (data:any) => void;
}
const AddressSelector: React.FC<ChildComponentProps> = ({status, onMessageChange}) =>{
const [open, setOpen] = useState<any>('')
const { request: userRequest } = useRequest<any>({ manual: true, loading: true })
const [invoiceList, setInvoiceList] = useState<any>()
const columns: TableColumnsType<any> = [
{ title: '序号', dataIndex: 'name', key: 'name', render:(text, record, index) => { return <span>{index + 1}</span>}},
{ title: '联系人', dataIndex: 'consignee', key: 'consignee'},
{ title: '联系电话', dataIndex: 'telphone', key: 'telphone' },
{ title: '邮箱', dataIndex: 'email', key: 'email' },
{
title: '联系地址',
dataIndex: 'email',
key: 'email',
render:(text, record, index) => {
return <span>{record?.nation_id_cn}{record?.province_cn}{record?.city_cn}{record?.district_cn}{record?.detail_address}</span>
}
},
{
title: '操作',
dataIndex: 'goods_number',
key: 'goods_number',
width: 70,
render:(text, record, index) => {
return (
<Button
color="default"
size="small"
variant="text" onClick={() => handleLineDelete(record)}>
选择
</Button>
)
}
}
]
useEffect(() => {
setOpen(status)
}, [status])
useEffect(() => {
if(open){
handleInvoiceInit()
}
}, [open])
const handleInvoiceInit = async () => {
const res = await userRequest({
url: `/api/userInfo/userAddressList?limit=30&page=1`,
method: 'get'
})
if (res?.code === 0 && res.data.list.length) {
// setInvoiceList(res.data.list.filter((i:any) => i.audit_status))
setInvoiceList(res.data.list)
}
}
const handleLineDelete = (data: any) => {
onMessageChange(data)
}
const handleModal = (show:boolean) => {
setOpen(show)
onMessageChange(null)
}
return (
<>
<Modal
title="更改地址"
style={{maxHeight: "500px",overflowY: "auto"}}
open={open}
destroyOnClose
footer={null}
closeIcon={null}
centered
width={980}
onCancel={() => handleModal(false)}
>
<Table<any>
size="small"
bordered={true}
rowKey={(record) => record?.web_user_invoice_id}
columns={columns}
pagination={false}
dataSource={invoiceList}
/>
</Modal>
</>
)
}
export default AddressSelector
\ No newline at end of file
.breadcrumbs{
height:47px;
line-height: 47px;
font-size: 12px;
color: #000000;
a {
margin: 0 10px;
color: #000000;
&:first-child {
margin-left: 0;
}
&:hover{
color:#FF9A00;
}
}
i{
color: #000000;
font-size: 12px;
}
strong {
margin: 0 10px;
color: #919191;
font-weight: normal !important;
}
}
import { ReactNode } from 'react'
import styles from './index.module.scss'
import Link from 'next/link'
const BreadNav = (props:{children:ReactNode}) => {
return (
<>
<div className={`${styles.breadcrumbs} w1226`}>
<Link href='/'>首页</Link>
<i className="icon iconfont icon-xiangyou1"></i>
{props.children}
</div>
</>
)
}
export default BreadNav
\ No newline at end of file
.fixedBox{position:fixed;top:0px;left:0px;right:0px;height:60px;background:#fff;z-index:4;box-shadow:-3px 3px 7px 1px rgba(154,151,149,0.18)}.fixedBox .cons{width:1226px;height:60px;margin:0 auto;box-sizing:border-box;align-items:center;padding-left:80px}.fixedBox .cons .logoImg{height:50px;width:50px}.fixedBox .cons .searchInputBox{width:630px;height:40px;background:#FFFFFF;border-radius:2px;border:1px solid #FF9A00;margin-left:80px}.fixedBox .cons .searchInputBox .inputGoods{width:451px;height:38px;line-height:38px;padding:0 15px;border-right:1px solid #FF9A00}.fixedBox .cons .searchInputBox .inputNums{width:108px;height:38px;line-height:38px;padding:0 15px;border-right:1px solid #FF9A00}.fixedBox .cons .searchInputBox .searchbtn{width:70px;height:38px;cursor:pointer;background:#FF9A00}.fixedBox .cons .searchInputBox .searchbtn i{font-size:26px;color:#fff}.fixedBox .cons .searchInputBox .searchbtn:hover{background:#E18800}.fixedBox .cons .loginInfoBox{padding-left:50px}.fixedBox .cons .loginInfoBox .line{height:18px;background:#d1d1d1;width:1px;margin:0px 15px}.fixedBox .cons .loginInfoBox a{font-size:12px;color:#000}.fixedBox .cons .loginInfoBox a:hover{color:#FF9A00}
.fixedBox{
position: fixed;
top:0px;
left:0px;
right:0px;
height:60px;
background: #fff;
z-index: 4;
box-shadow: -3px 3px 7px 1px rgba(154,151,149,0.18);
.cons{
width:1226px;
height:60px;
margin:0 auto;
box-sizing: border-box;
align-items: center;
padding-left:80px;
.logoImg{
height:50px;
width:50px;
}
.searchInputBox{
width: 630px;
height: 40px;
background: #FFFFFF;
border-radius: 2px;
border: 1px solid #FF9A00;
margin-left: 80px;
.inputGoods{
width:451px;
height:38px;
line-height: 38px;
padding: 0 15px;
border-right: 1px solid #FF9A00;
}
.inputNums{
width:108px;
height:38px;
line-height: 38px;
padding: 0 15px;
border-right: 1px solid #FF9A00;
}
.searchbtn{
width:70px;
height:38px;
cursor: pointer;
background: #FF9A00;
i{
font-size: 26px;
color:#fff;
}
&:hover{
background: #E18800;
}
}
}
.loginInfoBox{
padding-left:50px;
.line {
height: 18px;
background: #d1d1d1;
width: 1px;
margin: 0px 15px;
}
a{
font-size: 12px;
color:#000;
&:hover{
color: #FF9A00;
}
}
}
}
}
\ No newline at end of file
import styles from './index.module.scss'
import { use, useEffect, useState } from 'react'
import { useToast } from '@/hooks/useToast'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useCookies } from '@/hooks/useCookies'
const FixedSearchTop = () => {
const router = useRouter()
const { query } = router
const { setCookie, getCookie } = useCookies()
let keywords = ''
let nums = '';
const [backUrl, setBackUrl] = useState('');
const [isFixed, setIsFixed] = useState(false);
useEffect(() => {
const handleScroll = () => {
if (window.scrollY > 200) {
setIsFixed(true);
document.querySelector('#cartFloatBoxs')!.classList.add('searchFixedTopC')
} else {
setIsFixed(false);
document.querySelector('#cartFloatBoxs')!.classList.remove('searchFixedTopC')
}
};
window.addEventListener('scroll', handleScroll);
// 清除事件监听器
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
useEffect(() => {
setBackUrl(encodeURIComponent(window.location.href));
}, [router.asPath]);
if (router.pathname === '/search/[keyword]') {
keywords = String(query.keyword) || ''
if (query.num) {
nums = String(query.num) || ''
}
}
const [key, setKey] = useState<string>(keywords)
const [num, setNum] = useState<string>(nums)
const { message } = useToast()
const goSearch = () => {
//encodeURIComponent()
//decodeURIComponent()
const keywordsStr = key.replace(/^\s+/, "").replace(/\s+$/, "")
if (keywordsStr.length < 2) {
message("请输入至少2个字符")
return
}
const words_ = encodeURIComponent(keywordsStr)
if (num) {
router.push(`/search/${words_}.html?num=${num}`)
} else {
router.push(`/search/${words_}.html`)
}
}
const handleKeyPress = (key: string) => {
if (key === 'Enter') {
goSearch()
}
};
const changeNum = ((e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
const numericValue = value.replace(/[^0-9]/g, '');
setNum(numericValue)
})
return (
<>
{
isFixed &&
<div className={styles.fixedBox}>
<div className={`${styles.cons} row botnSide`}>
<Link href='/'><img className={styles.logoImg} src='/images/logo.png' alt='' /></Link>
<div className={`${styles.searchInputBox} row boxsiz`}>
<input type='text' className={`${styles.inputGoods} boxsiz`} value={key} onKeyPress={(e) => { handleKeyPress(e.key) }} onChange={(e) => { setKey(e.target.value) }} placeholder='请输入元器件型号、参数查找' />
<input type='text' className={`${styles.inputNums} boxsiz`} value={num} placeholder='需求数量' onKeyPress={(e) => { handleKeyPress(e.key) }} onChange={(e) => { changeNum(e) }} />
<div className={`${styles.searchbtn} row rowCenter verCenter`} onClick={goSearch}><i className='icon iconfont icon-iconfontsousuo '></i></div>
</div>
<div className={`${styles.loginInfoBox} row`}>
{
getCookie("userId") ? <Link href='/customer'>{getCookie("userName")}</Link> :
<>
<Link href={'/login?type=1&backUrl=' + backUrl}>登录</Link>
<span className={styles.line}></span>
<Link href={'/login?type=2&backUrl=' + backUrl}>注册</Link>
</>
}
</div>
</div>
</div>
}
</>
)
}
export default FixedSearchTop
\ No newline at end of file
.mvFooterBox{height:160px;background:#F4F4F4}.mvFooterBox .cons{width:1226px;height:120px;margin:0 auto;padding-top:25px}.mvFooterBox .cons .img{height:90px;width:90px}.mvFooterBox .cons .navlink{margin-top:24px}.mvFooterBox .cons .navlink a{padding:0 40px;border-left:1px solid #d1d1d1;font-size:14px;color:#000;height:19px}.mvFooterBox .cons .navlink a:hover{color:#FF9A00}.mvFooterBox .cons .navlink a:first-child{border-left:0px}.mvFooterBox .cons .navlink a:last-child{padding-right:0px}.mvFooterBox .footerBot{height:40px;background:#FF9A00}.mvFooterBox .footerBot .consp{width:1226px;margin:0 auto;height:40px;line-height:40px;color:#FF9A00;font-size:14px;color:#fff}.mvFooterBox .footerBot .consp a{color:#fff;margin-left:30px}
.mvFooterBox {
height: 160px;
background: #F4F4F4;
.cons {
width: 1226px;
height: 120px;
margin: 0 auto;
padding-top: 25px;
.img {
height: 90px;
width: 90px;
}
.navlink {
margin-top: 24px;
a {
padding: 0 40px;
border-left: 1px solid #d1d1d1;
font-size: 14px;
color: #000;
height: 19px;
&:hover {
color: #FF9A00;
}
&:first-child {
border-left: 0px;
}
&:last-child {
padding-right: 0px;
}
}
}
}
.footerBot {
height: 40px;
background: #FF9A00;
.consp {
width: 1226px;
margin: 0 auto;
height: 40px;
line-height: 40px;
color: #FF9A00;
font-size: 14px;
color: #fff;
a {
color: #fff;
margin-left: 30px;
}
}
}
}
\ No newline at end of file
import footerCss from './index.module.scss'
import Link from "next/link"
const Footer = () => {
return (
<>
<div className={`${footerCss.mvFooterBox} `}>
<div className={`${footerCss.cons} boxsiz row bothSide`} >
<img src='/images/logo.png' alt='' className={`${footerCss.img} `}/>
<div className={`${footerCss.navlink} cons boxsiz row bothSide`}>
<Link href='/brands.html'>品牌馆</Link>
<Link href='/about.html'>关于我们</Link>
<Link href='/contact.html'>联系我们</Link>
</div>
</div>
<div className={footerCss.footerBot}>
<div className={`${footerCss.consp} row bothSide`}>
<span>©2024北京安捷高科电子有限公司 ALL RIGHTS RESERVED <a rel='noopener noreferrer' target='_blank' href='https://beian.miit.gov.cn/#/Integrated/index'>京ICP备2024055716号</a></span>
{/* <span>增值电信业务经营许可证:粤B2-20160350</span> */}
</div>
</div>
</div>
</>
)
}
export default Footer
\ No newline at end of file
export type ResponseType = {
success: boolean,
data: Array<{
shopId: string,
shopName: string,
cartList: Array<{
productId: string,
imgUrl: string,
weight: string,
title: string,
price: number,
count: number
}>
}>
}
\ No newline at end of file
.mvNavBig{height:38px;border-bottom:1px solid #FF9A00;background:#fff}.mvNavBig .navbox{margin:0 auto;width:1226px}.mvNavBig .navbox .classBoxs{position:relative;height:38px}.mvNavBig .navbox .classBoxs .titleLc{line-height:38px;height:38px;width:234px;height:38px;background:#FF9A00;color:#fff;font-weight:bold;font-size:18px;cursor:pointer;box-sizing:border-box;padding-left:14px;display:block}.mvNavBig .navbox .classBoxs .boxOneLeft{width:234px;height:460px;position:absolute;left:0px;top:39px;background:rgba(255,255,255,0.98);display:none;box-sizing:border-box;z-index:3;border-left:1px solid rgba(255,255,255,0)}.mvNavBig .navbox .classBoxs .boxOneLeft.indexPages{display:block}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons{width:234px;padding:20px 0;box-sizing:border-box;position:relative}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup{color:#313131;font-size:14px;padding-left:17px;padding-right:17px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .oneClassLink{display:block;width:100%;cursor:pointer;padding-bottom:5px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .oneClassLink .spann{color:#000;font-size:16px;display:block;height:35px;line-height:35px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .oneClassLink .spann span{transition:all 0.5s;display:inline-block;vertical-align:middle;width:0px;overflow:hidden}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .oneClassLink .spann span i{font-size:11px;color:#FF9A00;position:relative;top:-2px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup:hover .spann{color:#FF9A00}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup:hover .spann span{width:25px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight{background:#fff;box-sizing:border-box;display:block;height:460px;width:775px;position:absolute;left:234px;padding-top:25px;box-sizing:border-box;top:0px;display:none;border-left:0px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .classconsjk{width:775px;height:410px;box-sizing:border-box;overflow-y:auto;padding:0 24px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .classconsjk::-webkit-scrollbar{width:8px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .classconsjk::-webkit-scrollbar-thumb{border-radius:6px;background:#fff;-webkit-box-shadow:inset 0 0 8px rgba(0,0,0,0.2)}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .classconsjk::-webkit-scrollbar-track{border-radius:0;background:#f4f4f4}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup{margin-bottom:10px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup .twoClassLink{width:130px;color:#000;font-weight:bold;font-size:14px;height:35px;line-height:35px;flex-shrink:0;padding-right:10px;box-sizing:border-box;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup .twoClassLink:hover{color:#FF9A00}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup .threeClassGroup{flex-wrap:wrap;margin-bottom:5px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup .threeClassGroup .threeClassLink{flex-shrink:0;padding-right:20px;box-sizing:border-box;margin-bottom:5px;height:30px;line-height:30px;color:#888888;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup .threeClassGroup .threeClassLink:hover{color:#FF9A00}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup:hover .boxTwoRight{display:block}.mvNavBig .navbox .classBoxs:hover .boxOneLeft{display:block}.mvNavBig .navbox .haedNavBox{height:38px;line-height:38px}.mvNavBig .navbox .haedNavBox ul{box-sizing:border-box;padding-left:34px}.mvNavBig .navbox .haedNavBox li{margin-right:75px}.mvNavBig .navbox .haedNavBox li a{font-size:18px;color:#000}.mvNavBig .navbox .haedNavBox li.act a,.mvNavBig .navbox .haedNavBox li:hover a{color:#FF9A00}
.mvNavBig{height:38px;border-bottom:1px solid #FF9A00;background:#fff}.mvNavBig .navbox{margin:0 auto;width:1226px}.mvNavBig .navbox .classBoxs{position:relative;height:38px}.mvNavBig .navbox .classBoxs .titleLc{line-height:38px;height:38px;width:234px;height:38px;background:#FF9A00;color:#fff;font-weight:bold;font-size:18px;cursor:pointer;box-sizing:border-box;padding-left:14px;display:block}.mvNavBig .navbox .classBoxs .boxOneLeft{width:234px;height:460px;position:absolute;left:0px;top:39px;background:rgba(255,255,255,0.98);display:none;box-sizing:border-box;z-index:3;border-left:1px solid rgba(255,255,255,0)}.mvNavBig .navbox .classBoxs .boxOneLeft.indexPages{display:block}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons{width:234px;padding:20px 0;box-sizing:border-box;position:relative}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup{color:#313131;font-size:14px;padding-left:17px;padding-right:17px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .oneClassLink{display:block;width:100%;cursor:pointer;padding-bottom:5px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .oneClassLink .spann{color:#000;font-size:16px;display:block;height:35px;line-height:35px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:all 0.5s}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup:hover .spann{color:#FF9A00;padding-left:15px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight{background:#fff;box-sizing:border-box;display:block;height:460px;width:775px;position:absolute;left:234px;padding-top:25px;box-sizing:border-box;top:0px;display:none;border-left:0px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .classconsjk{width:775px;height:410px;box-sizing:border-box;overflow-y:auto;padding:0 24px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .classconsjk::-webkit-scrollbar{width:8px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .classconsjk::-webkit-scrollbar-thumb{border-radius:6px;background:#fff;-webkit-box-shadow:inset 0 0 8px rgba(0,0,0,0.2)}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .classconsjk::-webkit-scrollbar-track{border-radius:0;background:#f4f4f4}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup{margin-bottom:10px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup .twoClassLink{width:130px;color:#000;font-weight:bold;font-size:14px;height:35px;line-height:35px;flex-shrink:0;padding-right:10px;box-sizing:border-box;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup .twoClassLink:hover{color:#FF9A00}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup .threeClassGroup{flex-wrap:wrap;margin-bottom:5px}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup .threeClassGroup .threeClassLink{flex-shrink:0;padding-right:20px;box-sizing:border-box;margin-bottom:5px;height:30px;line-height:30px;color:#888888;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup .boxTwoRight .twoClassGroup .threeClassGroup .threeClassLink:hover{color:#FF9A00}.mvNavBig .navbox .classBoxs .boxOneLeft .classleftcons .oneClassGroup:hover .boxTwoRight{display:block}.mvNavBig .navbox .classBoxs:hover .boxOneLeft{display:block}.mvNavBig .navbox .haedNavBox{height:38px;line-height:38px}.mvNavBig .navbox .haedNavBox ul{box-sizing:border-box;padding-left:34px}.mvNavBig .navbox .haedNavBox li{margin-right:75px}.mvNavBig .navbox .haedNavBox li a{font-size:18px;color:#000}.mvNavBig .navbox .haedNavBox li.act a,.mvNavBig .navbox .haedNavBox li:hover a{color:#FF9A00}
.mvNavBig {
height:38px;
border-bottom: 1px solid #FF9A00;
background: #fff;
.navbox {
margin : 0 auto;
width : 1226px;
.classBoxs {
position: relative;
height : 38px;
.titleLc {
line-height : 38px;
height : 38px;
width : 234px;
height : 38px;
background : #FF9A00;
color : #fff;
font-weight : bold;
font-size : 18px;
cursor : pointer;
box-sizing : border-box;
padding-left: 14px;
display: block;
}
.boxOneLeft {
width : 234px;
height : 460px;
position : absolute;
left : 0px;
top : 39px;
background: rgba(255, 255, 255, 0.98);
display : none;
box-sizing : border-box;
z-index : 3;
border-left: 1px solid rgba(255, 255, 255, 0);
&.indexPages{
display: block;
}
.classleftcons {
width : 234px;
padding : 20px 0;
box-sizing: border-box;
position : relative;
.oneClassGroup {
color : #313131;
font-size : 14px;
padding-left : 17px;
padding-right: 17px;
.oneClassLink {
display : block;
width : 100%;
cursor : pointer;
padding-bottom: 5px;
.spann {
color : #000;
font-size : 16px;
display : block;
height : 35px;
line-height : 35px;
overflow : hidden;
text-overflow: ellipsis;
white-space : nowrap;
transition: all 0.5s;
}
}
&:hover {
.spann {
color: #FF9A00;
padding-left: 15px;
}
}
.boxTwoRight {
background : #fff;
box-sizing : border-box;
display : block;
height : 460px;
width : 775px;
position : absolute;
left : 234px;
padding-top: 25px;
box-sizing : border-box;
top : 0px;
display : none;
border-left: 0px;
.classconsjk {
width : 775px;
height : 410px;
box-sizing : border-box;
overflow-y : auto;
padding:0 24px;
&::-webkit-scrollbar {
width: 8px;
}
&::-webkit-scrollbar-thumb {
border-radius : 6px;
background : #fff;
-webkit-box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.2)
}
&::-webkit-scrollbar-track {
border-radius: 0;
background : #f4f4f4
}
}
.twoClassGroup {
margin-bottom: 10px;
.twoClassLink {
width : 130px;
color : #000;
font-weight : bold;
font-size : 14px;
height : 35px;
line-height : 35px;
flex-shrink : 0;
padding-right: 10px;
box-sizing : border-box;
overflow : hidden;
text-overflow: ellipsis;
white-space : nowrap;
&:hover {
color: #FF9A00;
}
}
.threeClassGroup {
flex-wrap : wrap;
margin-bottom: 5px;
.threeClassLink {
flex-shrink : 0;
// width:120px;
padding-right: 20px;
box-sizing : border-box;
margin-bottom: 5px;
height : 30px;
line-height : 30px;
color : #888888;
font-size : 12px;
&:hover {
color: #FF9A00;
}
overflow : hidden;
text-overflow: ellipsis;
white-space : nowrap;
}
}
}
}
&:hover {
.boxTwoRight {
display: block;
}
}
}
}
}
&:hover {
.boxOneLeft {
display: block;
}
}
}
.haedNavBox {
height : 38px;
line-height: 38px;
ul {
box-sizing : border-box;
padding-left: 34px;
}
li {
margin-right: 75px;
a {
font-size: 18px;
color : #000;
}
&.act,
&:hover {
a {
color: #FF9A00;
}
}
}
}
}
}
\ No newline at end of file
import styles from './index.module.scss'
import type { ResponseTypeCateList, classListType } from './types'
import { useRouter } from 'next/router'
import Link from 'next/link'
import { useAuth } from '@/hooks/useAuth'
const NavBig = (props: ResponseTypeCateList) => {
const router = useRouter()
const { userId }=useAuth()
const items = [{
url: '/',
name: '首页'
}, {
url: '/brands.html',
name: '品牌馆'
}, {
url: '/about.html',
name: '关于我们'
}, {
url: '/contact.html',
name: '联系我们'
}]
if (userId) items.push({
url: '/customer',
name: '会员中心'
})
const classLists = props.data?.nav_list || []
const userUrlArr=["/myOrder","/orderDetail","/basicData","/invoice","/address"]
const pathnameStr=userUrlArr.indexOf(router.pathname)!=-1?"/customer":router.pathname
return (
<>
<div className={styles.mvNavBig}>
<div className={`${styles.navbox} row`}>
<div className={styles.classBoxs}>
<Link className={styles.titleLc} href='/list.html'>查看全部</Link>
<div className={router.pathname === '/' ? `${styles.boxOneLeft} ${styles.indexPages}` : `${styles.boxOneLeft}`} >
<div className={styles.classleftcons}>
{
classLists.map(item => {
return (
<div className={styles.oneClassGroup} key={item.goods_type_id}>
<div className={styles.oneClassLink}>
<Link className={styles.spann} href={`/list/${item.goods_type_id}`}>
{item.goods_type_name}
</Link>
</div>
<div className={styles.boxTwoRight}>
<div className={styles.classconsjk}>
<div className={styles.twoClassGroup}>
<Link href={`/list/${item.goods_type_id}`} key={item.goods_type_id} className={styles.twoClassLink}>{item.goods_type_name}</Link>
<div className={`${styles.threeClassGroup} row`}>
{
(item.child || []).map((itemChild, index) => {
return (
<Link key={itemChild.goods_type_id + index} className={styles.threeClassLink} href={`/list/${item.goods_type_id}_${itemChild.goods_type_id}`}>{itemChild.goods_type_name}</Link>
)
})
}
</div>
</div>
</div>
</div>
</div>
)
})
}
</div>
</div>
</div>
<div className={styles.haedNavBox}>
<ul className='row'>
{
items.map((item, index) => {
return (
<li className={pathnameStr === item.url ? styles.act : ''} key={item.name + index}>
<Link href={item.url} >{item.name}</Link>
</li>
)
})
}
</ul>
</div>
</div>
</div>
</>
)
}
export default NavBig
\ No newline at end of file
export type ResponseTypeCateList = {
code: number | string;
data: {
nav_list: Array<classListType>
} | null;
msg: string;
titlex?:any;
keywordsx?:string;
descriptionx?:string;
}
export type classListType = {
goods_type_id: string,
goods_type_name: string,
child?: Array<{
goods_type_id: string,
goods_type_name: string,
}>
}
import ReactPaginate from 'react-paginate';
type paginateTy={
total:number,
currentPage:number,
limit?:number,
onPageChange:(selectedItem: { selected: number; })=>void
}
const Paginate = (props:paginateTy) => {
const limit=props.limit||10
const pageCount= Math.ceil(props. total/ limit)||0;
const currentPage=props.currentPage||1
return (
pageCount>1&&
<ReactPaginate
previousLabel={'<上一页'}
nextLabel={'下一页>'}
breakLabel={'...'}
pageCount={pageCount}
marginPagesDisplayed={5}
pageRangeDisplayed={5}
onPageChange={props.onPageChange}
forcePage={ pageCount > 0 ? currentPage - 1 : undefined}
containerClassName={'paginationxk'}
activeClassName={'activexk'}
/>
);
};
export default Paginate
\ No newline at end of file
.mvSearchBox{height:146px;background:#FFFFFF}.mvSearchBox .cons{width:1226px;margin:0 auto;padding-top:22px}.mvSearchBox .cons .logoImg{width:118px;height:118px;margin-left:54px;margin-top:-5px}.mvSearchBox .cons .searchInputBox{width:630px;height:40px;background:#FFFFFF;border-radius:2px;border:1px solid #FF9A00;margin-top:13px;margin-left:103px}.mvSearchBox .cons .searchInputBox .inputGoods{width:451px;height:38px;line-height:38px;padding:0 15px;border-right:1px solid #FF9A00}.mvSearchBox .cons .searchInputBox .inputNums{width:108px;height:38px;line-height:38px;padding:0 15px;border-right:1px solid #FF9A00}.mvSearchBox .cons .searchInputBox .searchbtn{width:70px;height:38px;cursor:pointer;background:#FF9A00}.mvSearchBox .cons .searchInputBox .searchbtn i{font-size:26px;color:#fff}.mvSearchBox .cons .searchInputBox .searchbtn:hover{background:#E18800}.mvSearchBox .cons .collectButton{width:70px;height:40px;background:#FFFFFF;border-radius:2px;margin-top:15px;border:1px solid #E0E0E0}
.mvSearchBox{
height: 146px;
background: #FFFFFF;
.cons{
width:1226px;
margin:0 auto;
padding-top: 22px;
.logoImg{
width: 118px;
height: 118px;
margin-left: 54px;
margin-top: -5px;
}
.searchInputBox{
width: 630px;
height: 40px;
background: #FFFFFF;
border-radius: 2px;
border: 1px solid #FF9A00;
margin-top: 13px;
margin-left: 103px;
.inputGoods{
width:451px;
height:38px;
line-height: 38px;
padding: 0 15px;
border-right: 1px solid #FF9A00;
}
.inputNums{
width:108px;
height:38px;
line-height: 38px;
padding: 0 15px;
border-right: 1px solid #FF9A00;
}
.searchbtn{
width:70px;
height:38px;
cursor: pointer;
background: #FF9A00;
i{
font-size: 26px;
color:#fff;
}
&:hover{
background: #E18800;
}
}
}
.collectButton {
width: 70px;
height: 40px;
background: #FFFFFF;
border-radius: 2px;
margin-top: 15px;
border: 1px solid #E0E0E0;
}
}
}
\ No newline at end of file
import styles from './index.module.scss'
import { useState } from 'react'
import { useToast } from '@/hooks/useToast'
import Link from 'next/link'
import { useRouter } from 'next/router'
import ShopCart from '../ShoppingCart'
import { useAuth } from '@/hooks/useAuth'
const SearchH = () => {
const router = useRouter()
const { query } = router
let keywords = ''
let nums = '';
if (router.pathname === '/search/[keyword]') {
keywords = String(query.keyword) || ''
if (query.num) {
nums = String(query.num) || ''
}
}
const [key, setKey] = useState<string>(keywords)
const [num, setNum] = useState<string>(nums)
const { userId } = useAuth()
const { message } = useToast()
const goSearch = () => {
//encodeURIComponent()
//decodeURIComponent()
const keywordsStr = key.replace(/^\s+/, "").replace(/\s+$/, "")
if (keywordsStr.length < 2) {
message("请输入至少2个字符")
return
}
const words_ = encodeURIComponent(keywordsStr)
if (num) {
router.push(`/search/${words_}.html?num=${num}`)
} else {
router.push(`/search/${words_}.html`)
}
}
const handleKeyPress = (key: string) => {
if (key === 'Enter') {
goSearch()
}
};
const changeNum = ((e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
const numericValue = value.replace(/[^0-9]/g, '');
setNum(numericValue)
})
return (
<>
<div className={styles.mvSearchBox}>
<div className={`${styles.cons} row bothSide boxsiz`}>
<Link href='/'><img className={styles.logoImg} src='/images/logo.png' alt='' /></Link>
<div className={`${styles.searchInputBox} row boxsiz`}>
<input type='text' className={`${styles.inputGoods} boxsiz`} value={key} onKeyPress={(e) => { handleKeyPress(e.key) }} onChange={(e) => { setKey(e.target.value) }} placeholder='请输入元器件型号、参数查找' />
<input type='text' className={`${styles.inputNums} boxsiz`} value={num} placeholder='需求数量' onKeyPress={(e) => { handleKeyPress(e.key) }} onChange={(e) => { changeNum(e) }} />
<div className={`${styles.searchbtn} row rowCenter verCenter`} onClick={goSearch}><i className='icon iconfont icon-iconfontsousuo '></i></div>
</div>
<>
<ShopCart></ShopCart>
{/* <div>
<button className={styles.collectButton}>我的收藏</button>
</div> */}
</>
</div>
</div>
</>
)
}
export default SearchH
\ No newline at end of file
.shopBox{width:115px;height:40px;margin-top:15px;position:relative}.shopBox :global .nodataTable .ant-table-cell{border-bottom:0px !important}.shopBox .shopButton{width:115px;height:40px;line-height:40px;background:#FFFFFF;font-size:12px;color:#000;border-radius:2px;text-align:left;padding:0 10px;box-sizing:border-box;border:1px solid #E0E0E0;cursor:pointer}.shopBox .shopButton span{width:31px;height:16px;background:#E3030E;border-radius:10px;font-size:12px;color:#FFFFFF;line-height:16px;text-align:center;position:relative;top:11px;left:3px}.shopBox .shopLayer{display:none;height:450px;width:790px;border:1px solid #FF9A00;position:absolute;right:calc(100% - 115px);background-color:#fff;box-sizing:border-box;padding:30px 25px;z-index:10}.shopBox .shopLayer .layerTop{height:30px;display:flex;align-items:center;margin-bottom:20px;position:relative}.shopBox .shopLayer .layerTop .placeButton{width:80px;height:26px;line-height:24px;background:#FFFFFF;border-radius:1px;border:1px solid #B0B0B0;cursor:pointer;margin-right:10px}.shopBox .shopLayer .layerTop .placeButton:hover{color:#fff;background-color:#FF9A00;border-color:#FF9A00}.shopBox .shopLayer .layerTop .sePlaceButton{color:#fff;background-color:#FF9A00;border-color:#FF9A00}.shopBox .shopLayer .layerTop .shopTotal{position:absolute;right:0;top:20px}.shopBox .shopLayer .layerFooter{width:calc(100% - 50px);position:absolute;bottom:30px;display:flex;align-items:center}.shopBox .shopLayer .layerFooter .replaceButton{width:86px;height:25px;background:#FFFFFF;border-radius:15px;border:1px solid #919191;margin-right:30px;cursor:pointer;color:#919191;font-size:12px}.shopBox .shopLayer .layerFooter .accountButton{position:absolute;right:0;width:102px;height:34px;color:#fff;background:#D0121B;border-radius:1px;cursor:pointer}.shopBox .shopLayer .keyNumbers{color:#CC0000}.shopBox:hover .shopButton{border-color:#FF9A00;border-bottom-color:#fff}.shopBox:hover .shopButton::after{content:"";position:absolute;position:absolute;top:39px;width:115px;height:2px;z-index:99;left:0;border-right:1px solid #FF9A00;border-left:1px solid #FF9A00;box-sizing:border-box;background-color:#fff}.shopBox:hover .shopLayer{display:block}
.shopBox {
width: 115px;
height: 40px;
margin-top: 15px;
position: relative;
:global {
.nodataTable .ant-table-cell{
border-bottom: 0px!important;
}
}
.shopButton {
width: 115px;
height: 40px;
line-height: 40px;
background: #FFFFFF;
font-size: 12px;
color:#000;
border-radius: 2px;
text-align: left;
padding: 0 10px;
box-sizing: border-box;
border: 1px solid #E0E0E0;
cursor: pointer;
span{
width: 31px;
height: 16px;
background: #E3030E;
border-radius: 10px;
font-size: 12px;
color: #FFFFFF;
line-height: 16px;
text-align: center;
position: relative;
top: 11px;
left: 3px;
}
}
.shopLayer {
display: none;
height: 450px;
width: 790px;
border: 1px solid #FF9A00;
position: absolute;
right: calc(100% - 115px);
background-color: #fff;
box-sizing: border-box;
padding: 30px 25px;
z-index: 10;
.layerTop {
height: 30px;
display: flex;
align-items: center;
margin-bottom: 20px;
position: relative;
.placeButton {
width: 80px;
height: 26px;
line-height: 24px;
background: #FFFFFF;
border-radius: 1px;
border: 1px solid #B0B0B0;
cursor: pointer;
margin-right: 10px;
&:hover {
color: #fff;
background-color: #FF9A00;
border-color:#FF9A00;
}
}
.sePlaceButton {
color: #fff;
background-color: #FF9A00;
border-color:#FF9A00;
}
.shopTotal {
position: absolute;
right: 0;
top: 20px;
}
}
.layerFooter {
width: calc(100% - 50px);
position: absolute;
bottom: 30px;
display: flex;
align-items: center;
.replaceButton {
width: 86px;
height: 25px;
background: #FFFFFF;
border-radius: 15px;
border: 1px solid #919191;
margin-right: 30px;
cursor: pointer;
color: #919191;
font-size: 12px;
}
.accountButton {
position: absolute;
right: 0;
width: 102px;
height: 34px;
color: #fff;
background: #D0121B;
border-radius: 1px;
cursor: pointer;
}
}
.keyNumbers {
color: #CC0000;
}
}
&:hover {
.shopButton {
border-color: #FF9A00;
border-bottom-color: #fff;
&::after {
content: "";
position: absolute;
position: absolute;
top: 39px;
width: 115px;
height: 2px;
z-index: 99;
left: 0;
border-right: 1px solid #FF9A00;
border-left: 1px solid #FF9A00;
box-sizing: border-box;
background-color: #fff;
}
}
.shopLayer {
display: block;
}
}
}
\ No newline at end of file
import styles from './index.module.scss'
import Link from 'next/link'
import { Table, TableColumnsType, TableProps } from "antd"
import { useState, useEffect } from 'react'
import { DataType } from "@/types/orderTypes"
import useRequest from "@/hooks/useRequest"
import { useToast } from '@/hooks/useToast'
import { useRouter } from 'next/router'
import { useCookies } from '@/hooks/useCookies'
const TopH=()=>{
const { message } = useToast()
const { getCookie } = useCookies()
const router = useRouter()
const [sePlace, setSePlace] = useState<any>('1')
const [shopList, setShopList] = useState<any>([])
const [disList, setDisList] = useState<any>([])
const [disCn, setDisCn] = useState<any>([])
const [disUs, setDisUs] = useState<any>([])
const [isHover, setIsHover] = useState<any>(false)
const [selectList, setSelectList] = useState<any>([])
const { request: userRequest } = useRequest<any>({ manual: true, loading: false })
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([])
const columns: TableColumnsType<DataType> = [
{ title: '型号/品牌', dataIndex: 'sku_name', key: 'sku_name',
render:(text, record, index) => {
return <span>{record.sku_name || record.goods_name}/{record.brand_name}</span>}
},
{ title: '渠道', dataIndex: 'supplier_name', key: 'supplier_name' },
{ title: '交货地', dataIndex: 'delivery_place_type_text', key: 'delivery_place_type_text' },
{ title: '单价', dataIndex: 'goods_price', key: 'goods_price',
render:(text, record, index) => {
const isHk = record.delivery_place_type === '2'
return <span style={{paddingLeft: isHk ? '3px' : ''}}>{isHk ? ' $ ' : '¥'}{record.goods_price}</span>
}
},
{ title: '购买量', dataIndex: 'goods_number', key: 'goods_number' },
{ title: '小计', dataIndex: 'goods_amount', key: 'goods_amount',
render:(text, record, index) => {
const isHk = record.delivery_place_type === '2'
return <span style={{paddingLeft: isHk ? '3px' : ''}}>{isHk ? ' $ ' : '¥'}{record.goods_amount}</span>
}
}
]
const rowSelection: TableProps<DataType>['rowSelection'] = {
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => {
setSelectList(selectedRows)
setSelectedRowKeys(selectedRowKeys)
}
}
useEffect(() => {
if(getCookie("userId")){
handleDataInit()
}
}, [])
useEffect(() => {
if (isHover) handleDataInit()
}, [isHover])
useEffect(() => {
let dataList:any = []
let keyList:any = []
shopList.forEach((shopItem:any) => {
if (sePlace == '0' || shopItem?.delivery_place_type == sePlace) {
dataList.push(
{
...shopItem,
key: `${shopItem.sku_id}_${shopItem.delivery_place_type}`
}
)
keyList.push(`${shopItem.sku_id}_${shopItem.delivery_place_type}`)
}
})
setDisList(dataList)
setSelectList(dataList)
setSelectedRowKeys(keyList)
}, [shopList, sePlace])
const handleSelectPlace = (place: any) => setSePlace(place)
const handleMouseEnter = (e: any) => {
setIsHover(true)
}
const handleMouseLeave = (e: any) => {
setIsHover(false)
}
const handleDataInit = async () => {
const shopListResopnse = await userRequest({
url: '/api/cart/cartList',
method: 'post'
})
if (shopListResopnse?.code === 0) {
setShopList(shopListResopnse.data.cart_list)
setDisCn(shopListResopnse.data.cart_amount_cn)
setDisUs(shopListResopnse.data.cart_amount_hk)
}
}
const handleDataRemove = async () => {
if (!selectList.length) return message('请选择商品!')
const shopListResopnse = await userRequest({
url: '/api/cart/cartEdit',
method: 'post',
data: {
goods_list: selectList.map((seItem:any) => {
return {
sku_id: seItem.sku_id,
status: -1,
delivery_place_type: seItem.delivery_place_type
}
})
}
})
if (shopListResopnse?.code === 0) message('删除成功!')
else message(shopListResopnse?.msg)
handleDataInit()
}
const handleToSettle = () => {
if (!selectList.length) return message('请选择商品!')
const idList:any[] = []
const noStockList:any[] = []
let areaArray:any[] = []
selectList.forEach((seItem:any) => {
if (Number(seItem.goods_number || 0) > seItem.stock) noStockList.push(seItem.sku_name || seItem.goods_name)
idList.push(seItem.sku_id)
areaArray.push(Number(seItem.delivery_place_type))
})
if (noStockList.length) {
return message(`${noStockList.join(',')}型号不能购买,库存不足!`)
}
const disArea = [...new Set(areaArray)]
if (disArea.length && disArea.length > 1) {
return message(`不同交货地不能一起结算,请重新选择!`)
}
router.push(`/orderSettle?sourceType=2&id=${idList.join(',')}&deliveryPlaceType=${disArea[0]}`)
}
return (
<div className={styles.shopBox} id="cartFloatBoxs" onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<Link href='/shoppingCart' >
<button className={`${styles.shopButton} row`}>我的购物车<span id="cartNumx">{shopList.length}</span></button>
</Link>
<div className={styles.shopLayer}>
<div className={styles.layerTop}>
交货地:
{/* <button
className={`${styles.placeButton} ${(sePlace ==='0') && styles.sePlaceButton}`}
onClick={() => handleSelectPlace('0')}>
全部
</button> */}
<button
className={`${styles.placeButton} ${(sePlace ==='1') && styles.sePlaceButton}`}
onClick={() => handleSelectPlace('1')}>
大陆
</button>
<button
className={`${styles.placeButton} ${(sePlace ==='2') && styles.sePlaceButton}`}
onClick={() => handleSelectPlace('2')}>
香港
</button>
<div className={styles.shopTotal}>
<span className={styles.keyNumbers}> {disList.length} </span>
件商品
</div>
</div>
<div className={styles.layerContain} key={isHover}>
<Table<DataType>
size="small"
bordered={ false }
rowKey={(record) => `${record?.sku_id}_${record?.delivery_place_type}`}
pagination={ false }
columns={columns}
scroll={
{ y: 260}
}
rowSelection={{ ...rowSelection }}
dataSource={disList}
className={disList.length==0?'nodataTable':''}
/>
</div>
<div className={styles.layerFooter}>
<button className={styles.replaceButton} onClick={handleDataRemove}>移除商品</button>
<div>
{(['0', '1'].includes(sePlace)) &&
(
<>
大陆总金额:
<span className={styles.keyNumbers} style={{marginRight: '20px'}}>
¥{disCn}
</span>
</>
)
}
{(['0', '2'].includes(sePlace)) &&
(
<>
香港总金额:
<span className={styles.keyNumbers}>
${disUs}
</span>
</>
)
}
</div>
<button className={styles.accountButton} onClick={handleToSettle}>去结算</button>
</div>
</div>
</div>
)
}
export default TopH
\ No newline at end of file
.mvTopBox{height:40px;background:#F4F4F4}.mvTopBox .con{width:1226px;margin:0 auto;height:40px}.mvTopBox .con .line{height:18px;background:#d1d1d1;width:1px;margin:0px 15px}.mvTopBox .con a{font-size:12px;color:#666}.mvTopBox .con a:hover{color:#FF9A00}.mvTopBox .con .rqq{margin-left:25px}
.mvTopBox{
height: 40px;
background: #F4F4F4;
.con{
width:1226px;
margin:0 auto;
height:40px;
.line {
height: 18px;
background: #d1d1d1;
width: 1px;
margin: 0px 15px;
}
a{
font-size: 12px;
color:#666;
&:hover{
color: #FF9A00;
}
}
.rqq{
margin-left: 25px;
}
}
}
\ No newline at end of file
import styles from './index.module.scss'
import QqIcon from '../../../QqIcon'
import Link from 'next/link'
import { useQq } from '@/hooks/useQq'
import { useAuth } from '@/hooks/useAuth'
import { useCookies } from '@/hooks/useCookies'
import { useToast } from '@/hooks/useToast';
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
const TopH=()=>{
const { QQURL} = useQq()
const { userId } = useAuth()
const { setCookie, getCookie } = useCookies()
const { message } = useToast()
const router = useRouter()
const [backUrl, setBackUrl] = useState('');
const [topheadtype, setTopheadtype] = useState('');
useEffect(() => {
setBackUrl(encodeURIComponent(window.location.href));
if(router.pathname=="/login"||router.pathname=="/passwordRecover"){
setTopheadtype("1")
}
}, [router.asPath]);
const handleLogOut = () => {
setCookie('token', '', 1)
setCookie('userId', '', 1)
setCookie('userName', '', 1)
message('退出账号成功!')
history.go(0)
}
return (
<>
<div className={styles.mvTopBox}>
<div className={`${styles.con} row bothSide verCenter`}>
<div ></div>
{
topheadtype=="1"?
<div className='row verCenter'>
<Link href='/about.html'>关于我们</Link>
<span className={styles.line}></span>
<Link href='/contact.html'>联系我们</Link>
<span className={styles.line}></span>
<Link href='/notice.html'>公告</Link>
<span className={styles.rqq}><QqIcon QQURL={QQURL}/></span>
</div>
:
<div className='row verCenter'>
{(!userId) ? (
<>
<Link href={'/login?type=1&backUrl='+backUrl}>立即登录</Link>
<span className={styles.line}></span>
<Link href={'/login?type=2&backUrl='+backUrl}>立即注册</Link>
<span className={styles.line}></span>
</>
) : (
<>
<Link href='/customer'>{getCookie("userName")}</Link>
<span className={styles.line}></span>
<span
onClick={handleLogOut}
style={{cursor: 'pointer', fontSize: '12px', color: '#666666'}}>
退出账号
</span>
<span className={styles.line}></span>
</>
)
}
<Link href='/about.html'>关于我们</Link>
<span className={styles.line}></span>
<Link href='/contact.html'>联系我们</Link>
<span className={styles.line}></span>
<Link href='/notice.html'>公告</Link>
<span className={styles.rqq}><QqIcon QQURL={QQURL}/></span>
</div>
}
</div>
</div>
</>
)
}
export default TopH
\ No newline at end of file
import TopH from "./components/TopH"
import SearchH from "./components/SearchH"
import NavBig from "./components/NavBig"
import { useSeoTitle } from "@/hooks/useSeoTitle"
import type {ResponseTypeCateList} from '@/components/Header/components/NavBig/types'
const Header = (props:ResponseTypeCateList) => {
const seoTitle=useSeoTitle({...props})
return (
<>
{seoTitle}
<div className="head-box">
<TopH />
<SearchH />
<NavBig {...props!}/>
</div>
</>
)
}
export default Header
\ No newline at end of file
export type ResponseType = {
success: boolean,
data: Array<{
shopId: string,
shopName: string,
cartList: Array<{
productId: string,
imgUrl: string,
weight: string,
title: string,
price: number,
count: number
}>
}>
}
\ No newline at end of file
import { useState, useEffect } from 'react'
import useRequest from "@/hooks/useRequest"
import { Modal, Table, TableColumnsType, Button } from 'antd';
// 定义子组件 props 类型
interface ChildComponentProps {
status: any;
onMessageChange: (data:any) => void;
}
const InvoiceSelector: React.FC<ChildComponentProps> = ({status, onMessageChange}) =>{
const [open, setOpen] = useState<any>('')
const { request: userRequest } = useRequest<any>({ manual: true, loading: true })
const [invoiceList, setInvoiceList] = useState<any>()
const columns: TableColumnsType<any> = [
{ title: '序号', dataIndex: 'name', key: 'name', render:(text, record, index) => { return <span>{index + 1}</span>}},
{ title: '发票抬头', dataIndex: 'tax_title', key: 'tax_title'},
{ title: '税务登记号', dataIndex: 'tax_no', key: 'tax_no' },
{ title: '注册电话', dataIndex: 'company_phone', key: 'company_phone' },
{
title: '开户银行',
dataIndex: 'bank_name',
key: 'bank_name'
},
{ title: '开户账号', dataIndex: 'bank_account', key: 'bank_account' },
{
title: '注册地址',
dataIndex: 'company_address',
key: 'company_address'
},
{
title: '操作',
dataIndex: 'goods_number',
key: 'goods_number',
width: 70,
render:(text, record, index) => {
return (
<Button
color="default"
size="small"
variant="text" onClick={() => handleLineDelete(record)}>
选择
</Button>
)
}
}
]
useEffect(() => {
setOpen(status)
}, [status])
useEffect(() => {
if(open){
handleInvoiceInit()
}
}, [open])
const handleInvoiceInit = async () => {
const res = await userRequest({
url: `/api/userInfo/userInvoiceList?limit=30&page=1`,
method: 'get'
})
if (res?.code === 0 && res.data.list.length) {
setInvoiceList(res.data.list)
}
}
const handleLineDelete = (data: any) => {
onMessageChange(data)
}
const handleModal = (show:boolean) => {
setOpen(show)
onMessageChange(null)
}
return (
<>
<Modal
style={{maxHeight: "500px",overflowY: "auto"}}
title="选择发票"
open={open}
destroyOnClose
footer={null}
closeIcon={null}
centered
width={980}
onCancel={() => handleModal(false)}
>
<Table<any>
size="small"
bordered={true}
rowKey={(record) => record?.web_user_invoice_id}
columns={columns}
dataSource={invoiceList}
pagination={false}
/>
</Modal>
</>
)
}
export default InvoiceSelector
\ No newline at end of file
.listsNoDatax{background:#fff;text-align:center;padding:40px;height:auto}.listsNoDatax img{width:116px;height:116px;display:block;margin:0 auto}.listsNoDatax p{font-size:14px;font-weight:bold;color:#313131;margin-top:32px}
.listsNoDatax{
background: #fff;
text-align: center;
padding: 40px;
height: auto;
img{
width: 116px;
height: 116px;
display: block;
margin: 0 auto;
}
p{
font-size: 14px;
font-weight: bold;
color: #313131;
margin-top: 32px;
}
}
\ No newline at end of file
import Styles from './index.module.scss'
const ListNoData=()=>{
return (
<>
<div className={Styles.listsNoDatax}>
<img src='/images/nodata.png' alt="" />
<p>很抱歉!暂无数据</p>
</div>
</>
)
}
export default ListNoData
\ No newline at end of file
.listGroupOneItem{padding:0px 27px;background:#fff}.listGroupOneItem .cons{border-top:1px solid #e7e7e7;padding:10px 0px}.listGroupOneItem .cons .item{margin-right:15px;box-sizing:border-box;flex-shrink:0}.listGroupOneItem .cons .item .phonecons{position:relative;cursor:pointer}.listGroupOneItem .cons .item .phonecons img{width:25px;height:25px}.listGroupOneItem .cons .item .phonecons div{position:absolute;background:#fff;top:28px;right:2px;border:1px solid #FF9A00;padding:4px 6px;border-radius:3px;display:none}.listGroupOneItem .cons .item .phonecons:hover div{display:block}.listGroupOneItem .cons .item:last-child{margin-right:0px}.listGroupOneItem .cons .item .goodsImg{width:92px;height:92px}.listGroupOneItem .cons .item .goodsName{font-weight:bold;font-size:14px;color:#000000;line-height:19px;height:38px;word-break:break-all;text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;margin-bottom:10px}.listGroupOneItem .cons .item .goodsName:hover{color:#FF9A00;cursor:pointer}.listGroupOneItem .cons .item .goodsName:hover b{color:#FF9A00 !important}.listGroupOneItem .cons .item p{font-size:12px;color:#000000;line-height:23px}.listGroupOneItem .cons .item .jtgroup{font-size:12px;color:#000000;line-height:23px}.listGroupOneItem .cons .item .jtgroup span,.listGroupOneItem .cons .item .jtgroup strong{width:33.33%}.listGroupOneItem .cons .item .actjt{color:#FF9A00}.listGroupOneItem .cons .item .ljxunj{display:block;cursor:pointer;width:100px;height:30px;background:#FF9A00;color:#fff;font-size:14px;text-align:center;line-height:30px}.listGroupOneItem .cons .item.w198{width:198px}.listGroupOneItem .cons .item.w345{width:345px}.listGroupOneItem .cons .item.w200{width:200px}.listGroupOneItem .cons .item.w145{width:145px}.listGroupOneItem .cons .item.w298{width:298px}.listGroupOneItem .cons .item .collectButton{display:block;width:100px;height:30px;font-size:14px;color:#FFFFFF;background:#FF9A00;cursor:pointer}.listGroupOneItem .cons .item .collectButton:hover{background:#E18800}.listGroupOneItem .cons .item .buyBtn{display:block;width:100px;height:30px;font-size:14px;color:#FF9A00;border:1px solid #FF9A00;margin-top:20px;cursor:pointer;background-color:#fff}.listGroupOneItem .cons .item .buyBtn:hover{background:#FFF7EC}
.listGroupOneItem{
padding:0px 27px;
background: #fff;
.cons{
border-top: 1px solid #e7e7e7;
padding:10px 0px;
.item{
margin-right: 15px;
box-sizing: border-box;
flex-shrink: 0;
.phonecons{
position: relative;
cursor: pointer;
img{
width:25px;
height:25px;
}
div{
position: absolute;
background: #fff;
top: 28px;
right: 2px;
border: 1px solid #FF9A00;
padding: 4px 6px;
border-radius: 3px;
display: none;
}
&:hover{
div{
display: block;
}
}
}
&:last-child{margin-right: 0px;}
.goodsImg{
width: 92px;
height: 92px;
}
.goodsName{
font-weight: bold;
font-size: 14px;
color: #000000;
line-height: 19px;
height:38px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
&:hover{
color:#FF9A00;
b{
color:#FF9A00!important;
}
cursor: pointer;
}
margin-bottom: 10px;
}
p{
font-size: 12px;
color: #000000;
line-height: 23px;
}
.jtgroup{
font-size: 12px;
color: #000000;
line-height: 23px;
span,strong{width:33.33%;}
}
.actjt{
color:#FF9A00;
}
.ljxunj{
display: block;
cursor: pointer;
width: 100px;
height: 30px;
background: #FF9A00;
color:#fff;
font-size: 14px;
text-align: center;
line-height: 30px;
}
&.w198{width:198px;}
&.w345{width:345px;}
&.w200{width:200px;}
&.w145{width:145px;}
&.w298{width:298px;}
.collectButton {
display: block;
width: 100px;
height: 30px;
font-size: 14px;
color: #FFFFFF;
background: #FF9A00;
cursor: pointer;
&:hover {
background: #E18800;
}
}
.buyBtn {
display: block;
width: 100px;
height: 30px;
font-size: 14px;
color: #FF9A00;
border: 1px solid #FF9A00;
margin-top: 20px;
cursor: pointer;
background-color: #fff;
&:hover {
background: #FFF7EC;
}
}
}
}
}
\ No newline at end of file
import { useEffect, useRef, useState } from "react"
import styles from './index.module.scss'
import Link from 'next/link'
import QqIcon from '../QqIcon'
import type { dataListItemType } from './types'
import { Checkbox, Input } from "antd"
import { useToast } from '@/hooks/useToast'
import useRequest from "@/hooks/useRequest"
import { useRouter } from 'next/router'
import { useCookies } from "@/hooks/useCookies"
const ListOneItem = (props: dataListItemType) => {
const itemInfoInit = { ...props! }
const [itemInfo, setItemInfo] = useState(itemInfoInit)
const changeNumTimer = useRef<any>()
const { QQURL, PHONE } = props!
const { getCookie,setCookie } = useCookies()
const router = useRouter()
const { message } = useToast()
const [purNum, setPurNum] = useState<any>(itemInfo.moq)
const [seArea, setSeArea] = useState('1')
const [seDeliverOption, setSeDeliverOption] = useState<any>([])
const { request: userRequest } = useRequest<any>({ manual: true, loading: true })
useEffect(() => {
setSeDeliverOption(
[
{
value: '1', label: `大陆:${itemInfo.cn_delivery_time}`,
},
{
value: '2', label: `香港:${itemInfo.hk_delivery_time}`,
}
]
)
}, [props])
const handleAddCart = async (data: any) => {
if (!getCookie("userId")) {
window.location.href = '/login?type=1&backUrl=' + encodeURIComponent(window.location.href)
return
}
let goodPrice = ''
const priceList = JSON.parse(JSON.stringify(data?.ladder_price || []))
priceList.sort((a: any, b: any) => b.purchases - a.purchases).some((item: any) => {
if (item.purchases <= Number(purNum || 0)) {
goodPrice = (seArea === '1') ? item.price_cn : item.price_us
return true
}
})
if (!goodPrice || !purNum) return message("请输入正确购买数量!")
const param = {
goods_list: [
{
...JSON.parse(JSON.stringify(data)),
delivery_place_type: seArea,
goods_number: Number(purNum),
goods_price: goodPrice,
remark: ''
}
]
}
const res = await userRequest({
url: '/api/cart/cartAdd',
method: 'post',
data: param
})
if (res?.code === 0){
message("加入购物车成功!")
const shopListResopnse = await userRequest({
url: '/api/cart/cartList',
method: 'post'
})
document.querySelector('#cartNumx')!.textContent = shopListResopnse.data.cart_list.length
} else {
message(res?.msg || '操作失败!')
}
}
const handleToSettle = () => {
if (!getCookie("userId")) {
window.location.href = '/login?type=1&backUrl=' + encodeURIComponent(window.location.href)
return
}
let goodPrice = ''
const priceList = JSON.parse(JSON.stringify(itemInfo?.ladder_price || []))
priceList.sort((a: any, b: any) => b.purchases - a.purchases).some((item: any) => {
if (item.purchases <= Number(purNum || 0)) {
goodPrice = (seArea === '1') ? item.price_cn : item.price_us
return true
}
})
if (!goodPrice || !purNum) return message("请输入正确购买数量!")
if (itemInfo.stock < Number(purNum || 0)) return message("该型号库存不足!")
router.push(`/orderSettle?sourceType=1&id=${itemInfo?.sku_id}&deliveryPlaceType=${seArea}&number=${purNum}`)
}
const handlecheckBoxChange = (type: any) => setSeArea(type)
const onePriceRow = () => {
const priceList =itemInfo.ladder_price
priceList.forEach((item:any, index:number) => {
item.checked = false
var value_ = Number(purNum)
var pus = Number(item.purchases || 0)
var next_pus = 0
var prev_pus = 0
if(index!=0){
prev_pus = Number(priceList[index - 1].purchases)
}
if(index!=priceList.length - 1){
next_pus = Number(priceList[index + 1].purchases)
}
if (index == 0) {
if (value_ < pus) {
item.checked = true
return false
}
}
if (index == priceList.length - 1) {
if (value_ > pus) {
item.checked = true
return false
}
}
if (value_ == pus) {
item.checked = true
return false
}
if (value_ > pus && value_ < next_pus) {
item.checked = true
return false
}
if (value_ < pus && value_ > prev_pus) {
priceList[index - 1].checked = true
return false
}
})
}
onePriceRow()
const changeNum = (e: any, min: number, max: number, itemInfo: any) => {
clearTimeout(changeNumTimer.current)
setPurNum(Number(e.target.value))
changeNumTimer.current = setTimeout(() => {
if (Number(e.target.value) > max) {
message("购买数量不能大于库存!")
setPurNum(max)
return
}
if (Number(e.target.value) < min) {
message("购买数量不能小于起订量!")
setPurNum(min)
return
}
}, 1000)
}
return (
<>
<div className={styles.listGroupOneItem}>
<div className={`${styles.cons} row`}>
<div className={styles.item}>
<Link href={`/item/${itemInfo.sku_id}.html`}><img
src={itemInfo.goods_images || '/images/default.jpg'}
className={styles.goodsImg} alt="{itemInfo.sku_name||itemInfo.goods_name}"
onError={(e) => {
e.currentTarget.src = '/images/default.jpg';
}}
/>
</Link>
</div>
<div className={`${styles.item} ${styles.w198}`}>
<Link className={styles.goodsName} replace href={`/item/${itemInfo.sku_id}.html`} >
<span dangerouslySetInnerHTML={{ __html: (itemInfo.sku_name_show! || itemInfo.goods_name_show!) || (itemInfo.sku_name || itemInfo.goods_name) }}></span>
</Link>
<p>品牌:{itemInfo.brand_name}</p>
<p>商品类别:{itemInfo.goods_type_name2 || '--'}</p>
</div>
<div className={`${styles.item} ${styles.w200} `}>
<p>库存:{itemInfo.stock}</p>
<p>起订量:{itemInfo.moq} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 增量:{itemInfo.multiple}</p>
{
itemInfo.batch_sn &&
<p className='row'><span>批次:</span><span dangerouslySetInnerHTML={{ __html: itemInfo.batch_sn }}></span></p>
}
</div>
<div className={`${styles.item} ${styles.w298}`}>
{
itemInfo.ladder_price.map((item, index) => {
return (
<div key={index + item.price_cn} className={`${styles.jtgroup} row ${item.checked ? styles.actjt : ''}`}>
<span>{item.purchases || item.purchase}+</span>
{
(item.price_cn && Number(item.price_cn) !== 0) ? <strong>¥{item.price_cn || '--'}</strong> : ''
}
{
(item.price_us && Number(item.price_us) !== 0) ? <strong>${item.price_us || '--'}</strong> : ''
}
</div>
)
})
}
</div>
<div className={`${styles.item}`} style={{ width: '160px' }}>
<>
<Input value={purNum || itemInfo.moq} style={{ width: 100,"borderColor":"#999" }} onChange={(e) => changeNum(e, Number(itemInfo.moq), Number(itemInfo.stock), itemInfo)} placeholder="请输入数量" />
{itemInfo.cn_delivery_time &&
<Checkbox checked={seArea === '1'} onChange={() => handlecheckBoxChange('1')} style={{ marginRight: '10px', marginTop: '10px' }}>
大陆:{itemInfo.cn_delivery_time}
</Checkbox>}
{itemInfo.hk_delivery_time &&
<Checkbox checked={seArea === '2'} onChange={() => handlecheckBoxChange('2')} style={{ marginRight: '10px' }}>
香港:{itemInfo.hk_delivery_time}
</Checkbox>}
</>
</div>
<div className={`${styles.item} row`}>
<div>
{(!itemInfo.stock || itemInfo.ladder_price.length == 0) ? (
<a href={QQURL} rel="noreferrer" className={styles.ljxunj} target='_blank'>立即询价</a>
) : (
<>
<button className={styles.collectButton} onClick={() => handleAddCart(itemInfo)}>加入购物车</button>
<button className={styles.buyBtn} onClick={handleToSettle}>立即购买</button>
</>
)}
</div>
<div style={{ marginLeft: '20px' }}>
<QqIcon QQURL={QQURL} />
<div className={`${styles.phonecons}`} >
<img src='/images/phonecom.png' alt='' />
<div>{PHONE}</div>
</div>
</div>
</div>
</div>
</div>
</>
)
}
export default ListOneItem
\ No newline at end of file
export type dataListItemType = {
QQURL:string;
PHONE:string;
sku_id:string|number;
sku_name: string;
sku_name_show?:string;
goods_name_show?:string;
brand_name: string;
brand_id: string|number;
supplier_brand_name:string;
supplier_brand_id:string|number;
goods_type_id?:string|number;
goods_type_id2?:string|number;
goods_type_name?:string;
goods_type_name2?:string;
batch_sn?:string,
cn_delivery_time: string;
hk_delivery_time: string;
goods_id: string|number;
goods_images: string;
goods_name: string;
moq: number;
multiple: number;
stock: number;
supplier_name: string;
ladder_price: Array<{
checked?:boolean;
price_cn: number;
price_cost_cn?: number;
price_us: number;
purchase?: string|number;
purchases?: string|number;
price_cost_us?: number;
}>
}
.sortRanksx{font-size:14px;color:#000000;padding:20px 0px}.sortRanksx .left .item{height:18px;line-height:18px;padding:0 30px;border-left:1px solid #d1d1d1;cursor:pointer;position:relative}.sortRanksx .left .item:first-child{padding-left:0px;border-left:0px}.sortRanksx .left .item .bottomiconx{width:0px;height:0px;border-style:solid;border-width:6px;border-color:#D8D8D8 transparent transparent transparent;position:absolute;top:10px;right:14px}.sortRanksx .left .item .topiconx{width:0px;height:0px;border-style:solid;border-width:6px;border-color:transparent transparent #D8D8D8 transparent;position:absolute;top:-4px;right:14px}.sortRanksx .left .item.act{color:#FF9A00}.sortRanksx .left .item.act.top .topiconx{border-color:transparent transparent #FF9A00 transparent}.sortRanksx .left .item.act.bottom .bottomiconx{border-color:#FF9A00 transparent transparent transparent}.sortRanksx .right .checkbox{height:18px;width:18px;border-radius:2px;background:#FFF;border:1px solid #ededed;position:relative;top:2px;margin-right:6px;text-align:center;line-height:18px;cursor:pointer}.sortRanksx .right .checkbox i{font-size:21px;position:relative;top:1px;left:-1px;color:transparent}.sortRanksx .right .checkbox.act{border-color:#FF9A00}.sortRanksx .right .checkbox.act i{color:#FF9A00}.sortRanksx .right span{margin-left:6px;cursor:pointer}.sortRanksx .right span.act{color:#FF9A00;cursor:pointer}
.sortRanksx {
font-size: 14px;
color : #000000;
padding : 20px 0px;
.left {
.item {
height : 18px;
line-height: 18px;
padding : 0 30px;
border-left: 1px solid #d1d1d1;
cursor : pointer;
position : relative;
&:first-child {
padding-left: 0px;
border-left : 0px;
}
.bottomiconx {
width : 0px;
height : 0px;
border-style: solid;
border-width: 6px;
border-color: #D8D8D8 transparent transparent transparent;
position : absolute;
top : 10px;
right : 14px;
}
.topiconx {
width : 0px;
height : 0px;
border-style: solid;
border-width: 6px;
border-color: transparent transparent #D8D8D8 transparent;
position : absolute;
top : -4px;
right : 14px;
}
&.act {
color: #FF9A00;
&.top {
.topiconx {
border-color: transparent transparent #FF9A00 transparent;
}
}
&.bottom {
.bottomiconx{
border-color: #FF9A00 transparent transparent transparent;
}
}
}
}
}
.right {
.checkbox {
height : 18px;
width : 18px;
border-radius: 2px;
background : #FFF;
border : 1px solid #ededed;
position : relative;
top : 2px;
margin-right : 6px;
text-align : center;
line-height : 18px;
cursor : pointer;
i {
font-size: 21px;
position : relative;
top : 1px;
left : -1px;
color : rgba(0, 0, 0, 0)
}
&.act {
i {
color: #FF9A00;
}
border-color:#FF9A00;
}
}
span {
margin-left: 6px;
cursor : pointer;
&.act {
color : #FF9A00;
cursor: pointer;
}
}
}
}
\ No newline at end of file
import { Dispatch, SetStateAction } from 'react';
import styles from './index.module.scss'
import type { ListSortType } from './types'
interface ListSortProps {
sortObj: ListSortType;
onChangeSort?: (T: ListSortType) => void; //自定义函数
setSortObj?: Dispatch<SetStateAction<ListSortType>>
}
const ListSort = (props: ListSortProps) => {
const { sortType, isStock, stockSort, priceSort } = props.sortObj
const changeSort = (sortType?: number) => {
const obj_ = { ...props.sortObj }
if (sortType) {
obj_.sortType = sortType
}
if (sortType === 2) {
if (obj_.stockSort === 'top') {
obj_.stockSort = 'bottom'
} else {
obj_.stockSort = 'top'
}
}
if (sortType === 3) {
if (obj_.priceSort === 'top') {
obj_.priceSort = 'bottom'
} else {
obj_.priceSort = 'top'
}
}
if (!sortType) {
obj_.isStock = !obj_.isStock
}
props.setSortObj && props.setSortObj(obj_)
props.onChangeSort && props.onChangeSort(obj_)
}
return (
<>
<div className={`${styles.sortRanksx} row bothSide`}>
<div className={`${styles.left} row`}>
<div className={sortType === 1 ? `${styles.item} ${styles.act}` : `${styles.item}`} onClick={() => { changeSort(1) }}>综合排序</div>
<div className={sortType === 2 ? (stockSort === `top` ? `${styles.item} ${styles.act} ${styles.top}` : `${styles.item} ${styles.act} ${styles.bottom}`) : `${styles.item}`} onClick={() => { changeSort(2) }}>库存<i className={styles.topiconx}></i><i className={styles.bottomiconx}></i></div>
<div className={sortType === 3 ? (priceSort === `bottom` ? `${styles.item} ${styles.act} ${styles.top}` : `${styles.item} ${styles.act} ${styles.bottom}`) : `${styles.item}`} onClick={() => { changeSort(3) }}>价格<i className={styles.topiconx}></i><i className={styles.bottomiconx}></i></div>
</div>
<div className={`${styles.right} row verCenter`}>
<div className={isStock ? `${styles.checkbox} ${styles.act}` : `${styles.checkbox} `} onClick={() => { changeSort() }}>
<i className='icon iconfont icon-B-fuxuankuang'></i>
</div>
<span className={isStock ? `${styles.act}` : ''} onClick={() => { changeSort() }}>仅显示有货</span>
</div>
</div>
</>
)
}
export default ListSort
\ No newline at end of file
export type ListSortType = {
sortType:number,//1 综合排序 2库存排序 3价格排序
isStock:boolean,//true 仅有货 false 全部
stockSort?:string, // top 升序 bottom 降序
priceSort?:string // top 升序 bottom 降序
}
const QqIcon = (props:{QQURL:string}) => {
const {QQURL}=props
return (
<>
<a href={QQURL} rel="noreferrer" target='_blank' title='QQ咨询'><img style={{width:'25px',height:'25px'}} src='/images/qq.png' alt='' /></a>
</>
)
}
export default QqIcon
\ No newline at end of file
.navigation{width:190px;padding-top:20px;background:#fff;overflow-x:hidden;box-sizing:border-box}.navigation .navTitle{height:36px;padding-left:15px;font-size:16px;line-height:20px;border-bottom:1px solid #F4F4F4;margin-bottom:25px;position:relative;cursor:pointer}.navigation .navTitle .title{padding-left:15px}.navigation .item{font-size:16px;margin-bottom:35px}.navigation .item .itemText{padding-left:25px}.navigation .item .itemChild{padding-left:40px;font-size:14px;color:#808080;cursor:pointer;margin-top:15px;position:relative}.navigation .item .itemChild:hover{color:#FF9A00}.navigation .itemSelected{color:#FF9A00 !important}.navigation .itemSelected::after{content:"";display:block;position:absolute;width:3px;height:20px;left:0;top:0;background-color:#FF9A00}
.navigation {
width: 190px;
padding-top: 20px;
background: #fff;
overflow-x: hidden;
box-sizing: border-box;
.navTitle {
height: 36px;
padding-left: 15px;
font-size: 16px;
line-height: 20px;
border-bottom: 1px solid #F4F4F4;
margin-bottom: 25px;
position: relative;
cursor: pointer;
.title {
padding-left: 15px;
}
}
.item {
font-size: 16px;
margin-bottom: 35px;
.itemText {
padding-left: 25px;
}
.itemChild {
padding-left: 40px;
font-size: 14px;
color: #808080;
cursor: pointer;
margin-top: 15px;
position: relative;
&:hover {
color: #FF9A00;
}
}
}
.itemSelected {
color: #FF9A00 !important;
&::after {
content: "";
display: block;
position: absolute;
width: 3px;
height: 20px;
left: 0;
top: 0;
background-color: #FF9A00;
}
}
}
\ No newline at end of file
const NavList = [
{
title: '订单中心',
key: 'orderCenter',
children: [
{
title: '我的订单',
key: 'OrderPage',
url: 'myOrder'
},
// {
// title: '我的售后',
// key: 'AfterSales'
// }
]
},
// {
// title: '我的钱包',
// key: 'myWallet',
// children: [
// {
// title: '我的优惠券',
// key: 'MyCoupons'
// }
// ]
// },
// {
// title: '我的信息',
// key: 'myInformation',
// children: [
// {
// title: '站内信',
// key: 'Mail'
// }
// ]
// },
{
title: '资料中心',
key: 'dataCenter',
children: [
{
title: '基础信息',
key: 'BasicData',
url: 'basicData'
},
{
title: '我的发票',
key: 'InvoicePage',
url: 'invoice'
},
{
title: '我的地址',
key: 'AddressPage',
url: 'address'
}
]
},
// {
// title: '我的关注',
// key: 'myFollow',
// children: [
// {
// title: '我的收藏',
// key: 'MyCollection'
// }
// ]
// }
]
import styles from './index.module.scss'
import {useState, useEffect} from 'react'
import { useRouter } from 'next/router'
const Nav = () => {
const router = useRouter()
const [ selectObj, setSelectObj ] = useState<any>();
const handleSelected = (url: any) => {
url && router.push(url)
}
useEffect(() => {
if (router.pathname !== '/orderDetail') setSelectObj(router.pathname)
else setSelectObj('/myOrder')
}, [router.pathname])
return (
<>
<div className={styles.navigation}>
<div className={`${styles.navTitle} ${(selectObj === '/customer') && styles.itemSelected}`}
onClick={() => handleSelected('customer')}>
<span className={styles.title}>首页</span>
</div>
{
NavList.map((item) => {
return (
<div className={styles.item} key={item.key}>
<span className={styles.itemText}>{item.title}</span>
{
item.children.map((itemChild) => {
return (
<div className={`${styles.itemChild} ${(selectObj === `/${itemChild.url}`) && styles.itemSelected}`}
key={itemChild.key} onClick={() => handleSelected(itemChild.url)}>
<span className={styles.childText}>{itemChild.title}</span>
</div>
)
})
}
</div>
)
})
}
</div>
</>
)
}
export default Nav
\ No newline at end of file
const os = require('os');
export const QQURL='https://wpa.qq.com/msgrd?v=3&amp;uin=1908059998&amp;site=qq&amp;menu=yes'
export const API_URL='http://api.chiplinks.net'
//export const API_URL='http://erpwebback.com'
\ No newline at end of file
import { useState, useEffect } from 'react'
import { useCookies } from "./useCookies"
export const useAuth = () => {
const [userId, setUserId] = useState<any>(null);
const {getCookie} = useCookies()
useEffect(() => {
setUserId(getCookie('userId'))
}, [])
return { userId, setUserId };
};
export const useCookies = () => {
const setCookie = (
name: string,
value: string | number,
time: number,
domain?: string
) => {
try {
let domainStr = domain ? `;domain=${domain}` : '';
const exp = new Date(); // 当前时间
exp.setTime(exp.getTime() + time * 24 * 60 * 60 * 1000); // 设置过期时间
document.cookie = `${name}=${encodeURIComponent(value)};expires=${exp.toUTCString()};path=/${domainStr}`;
return true;
} catch (error) {
return true;
}
}
const getCookie = (name: string): string | null => {
try {
const cookiesArray = document.cookie.split(';');
for (let i = 0; i < cookiesArray.length; i++) {
let cookiePair = cookiesArray[i].trim();
let cookieRegex = new RegExp(`${name}=`);
if (cookieRegex.test(cookiePair)) {
return decodeURIComponent(cookiePair.replace(cookieRegex, ''));
}
}
return null;
} catch (error) {
return null;
}
}
return { setCookie, getCookie }
}
import { useEffect, useState } from "react"
import useRequest from "./useRequest"
import { useCookies } from "./useCookies"
type getQQTypeResponse = {
code: number | string,
data: {
qq: number | string,
mobile:number | string,
},
msg: string
}
export const useQq = () => {
const { request: qqUrlRequest } = useRequest<getQQTypeResponse>({ manual: true,loading:false })
const {setCookie,getCookie}=useCookies()
const [QQURL,setQQURL]=useState<string>('')
const [PHONE,setPHONE]=useState<string>('')
useEffect(() => {
if(getCookie("QQMOBILEs")){
const aurl_:any=JSON.parse(getCookie("QQMOBILEs")!)
setQQURL(aurl_.qq)
setPHONE(aurl_.mobile)
}else{
qqUrlRequest({ url: '/api/contact/list' }).then(res => {
if (res?.code === 0) {
setQQURL(`${res.data.qq}`)
setPHONE(`${res.data.mobile}`)
setCookie('QQMOBILEs',`${JSON.stringify(res.data)}`,0.01)
}
})
}
}, [qqUrlRequest])
return { QQURL,PHONE }
}
import { useCallback, useEffect, useRef, useState } from 'react';
import axios, { AxiosRequestConfig } from "axios"
import { useToast } from './useToast';
import {API_URL} from '@/configReact'
import { useCookies } from "@/hooks/useCookies"
import { useRouter } from 'next/router';
// 默认请求参数
const defaultRequestConfig = {
url: '/', method: 'GET', data: {}, params: {}
}
function useRequest<T>(options: AxiosRequestConfig & { manual?: boolean,loading?:boolean|undefined } = defaultRequestConfig) {
const [data, setData] = useState<T | null>(null)
const [loaded, setLoaded] = useState(false)
const {loading,message}=useToast()
const loadingRef = useRef(loading);
const messageRef = useRef(message);
const {getCookie} = useCookies()
const router = useRouter()
const request = useCallback((requestOption?: AxiosRequestConfig) => {
setData(null)
setLoaded(false)
if(options.loading!==false){
loadingRef.current()
}
const headers = requestOption?.headers
const userId = getCookie("userId")
const token = getCookie("token")
return axios.request<T>({
baseURL:API_URL,
...requestOption,
headers: {
Authorization: token,
webUserId: userId,
...headers
}
}).then((response) => {
// if (response.data['code' as keyof typeof data] && response.data['code' as keyof typeof data] === 101) {
// router.push('login?type=1')
// return
// }
setData(response.data)
return response.data
}).catch((e: any) => {
messageRef.current(e.message)
}).finally(() => {
loadingRef.current(false)
setLoaded(true)
})
}, [options.loading])
useEffect(() => {
if (!options.manual) {
request(options).catch(e=> {
messageRef.current(e.message)
})
}
}, [options, request])
return { data,loaded, request }
}
export default useRequest
\ No newline at end of file
import Head from "next/head";
import { useRouter } from "next/router";
import { useEffect } from "react";
import { useCookies } from "./useCookies";
export const useSeoTitle = (props?:any) => {
const { getCookie } = useCookies()
const router=useRouter()
const getClassNameStr=(data:any, idStr:any)=> {
const ids = idStr.split('_');
const parentId = parseInt(ids[0], 10);
const childId = ids.length > 1 ? parseInt(ids[1], 10) : null;
for (let i = 0; i < data.length; i++) {
const item = data[i];
if (item.goods_type_id === parentId) {
if (childId !== null) {
const child = item.child.find((childItem:any )=> childItem.goods_type_id === childId);
if (child) {
return child.goods_type_name;
}
} else {
return item.goods_type_name;
}
}
}
return "";
}
let titlestr='404'
const titleKeywords:any = {
'/': { title: '首页' },
'/search/[keyword]': { title: '搜索结果' },
'/item/[sku_id]': { title: '商品详情' },
'/brands.html': { title: '品牌馆' },
'/brand/[brand_id]': { title: '品牌结果' },
'/list.html': { title: '分类地图' },
'/list/[class_id]': { title: '分类结果' },
'/about.html': { title: '关于我们' },
'/contact.html': { title: '联系我们' },
'/notice.html': { title: '公告' },
'/login': { title: '登录/注册' },
'/regChoose': { title: '注册发票' },
'/customer': { title: '会员中心' ,needLogin:true},
'/myOrder': { title: '我的订单',needLogin:true },
'/orderSettle': { title: '提交订单',needLogin:true },
'/orderResult':{ title: '提交订单成功',needLogin:true },
'/orderDetail': { title: '订单详情',needLogin:true },
'/basicData': { title: '基础信息',needLogin:true },
'/invoice': { title: '我的发票',needLogin:true },
'/address': { title: '我的地址' ,needLogin:true},
'/shoppingCart': { title: '购物车',needLogin:true },
}
if (Object.keys(titleKeywords).indexOf(router.pathname) !== -1) {
titlestr=titleKeywords[router.pathname]['title']
if(router.route=="/search/[keyword]"){
titlestr=`${router.query.keyword}现货_${router.query.keyword}期货_${router.query.keyword}报价`
}
if(router.route=="/list/[class_id]"){
let arr_=props?.data!.nav_list
const class_name_strs=getClassNameStr(arr_,router.query.class_id)
titlestr=`${class_name_strs}价格查询,${class_name_strs}库存查询`
}
}
useEffect(()=>{
if(titleKeywords[router.pathname]['needLogin']){
if(!getCookie("userId")){
window.location.href='/login?type=1&backUrl='+encodeURIComponent(window.location.href)
}
}
},[])
return (
<Head>
<title>{`${titlestr}_麒麟电子商城`}</title>
<link rel="icon" href="/images/logo.png" />
<meta name="keywords" content={`${titlestr}_麒麟电子商城`} />
<meta name="description" content={`${titlestr}_麒麟电子商城`} />
</Head>
)
}
import { createRoot } from "react-dom/client";
const tipStyle = {
textAlign: 'center' as const,
fontSize: '14px',
lineHeight: '32px',
fontWeight: 'bold',
position: 'fixed' as const,
top: '170px',
color: '#fff',
zIndex: '99999',
width: '500px',
left: '50%',
marginLeft: '-250px'
}
const tipTextStyle = {
background: 'rgba(0,0,0,0.5)',
paddingLeft: '20px',
paddingRight: '20px',
minWidth: '84px'
}
const loadindStyle = {
position: 'fixed' as const,
top: '0px',
left: '0px',
right: '0px',
bottom: '0px',
zIndex: '999999'
}
const loadindImgStyle = {
position: 'absolute' as const,
top: '50%',
left: '50%',
marginLeft: '-18px',
marginTop: '-18px',
}
export const useToast = () => {
const message = (message: string, timeout = 2000) => {
try {
let element = document.getElementById('toastmessagexk4600');
if (element) {
element.parentNode?.removeChild(element);
}
const elementMessage = document.createElement('div');
elementMessage.id = 'toastmessagexk4600'
const rootMessage = createRoot(elementMessage)
rootMessage.render(
<div style={tipStyle} className="row rowCenter">
<div style={tipTextStyle}>{message}</div>
</div>
);
if (!elementMessage.parentNode) {
document.body.appendChild(elementMessage);
setTimeout(() => {
elementMessage.parentNode && document.body.removeChild(elementMessage);
}, timeout);
}
} catch (error) {
}
}
const loading = ((show = true) => {
try {
let element = document.getElementById('toastloadingxk4600');
element && element.parentNode?.removeChild(element);
const elementLoading = document.createElement('div');
elementLoading.id = 'toastloadingxk4600'
const rootLoading = createRoot(elementLoading)
rootLoading.render(
<div style={loadindStyle} >
<img src='/images/loading.gif' alt="" style={loadindImgStyle} />
</div>
);
if (show) {
if (!elementLoading.parentNode) {
document.body.appendChild(elementLoading);
}
} else {
if (elementLoading.parentNode) {
document.body.removeChild(elementLoading);
}
}
} catch (error) {
}
})
return { message, loading };
}
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
/** @type {import('next').NextConfig} */
const nextConfig = {
// output: 'standalone',
// experimental: {
// prefetch: false,
// },
reactStrictMode: false, // 关闭 React 严格模式
// 配置代理
async rewrites() {
return [
// {
// source: '/api/:path*',
// destination: 'http://erpweb.liexindev.net/api/:path*',
// },
{
source: '/brand/:brand_id.html',
destination: '/brand/:brand_id',
},
{
source: '/item/:sku_id.html',
destination: '/item/:sku_id',
},
{
source: '/search/:keyword.html',
destination: '/search/:keyword',
},
];
},
async headers() {
return [
{
source: '/_next/data/:path*',
headers: [
{
key: 'Cache-Control',
value: 'public, max-age=3600, immutable'
},
],
},
];
},
};
export default nextConfig;
\ No newline at end of file
This diff could not be displayed because it is too large.
{
"name": "europa-web",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@ant-design/cssinjs": "^1.22.0",
"antd": "^5.21.6",
"axios": "^1.7.2",
"lodash": "^4.17.21",
"next": "^13.0.5",
"react": "^18",
"react-dom": "^18",
"react-paginate": "^8.2.0",
"react-redux": "^9.1.2",
"react-router-dom": "^6.27.0",
"redux": "^5.0.1",
"sass": "^1.77.8",
"swiper": "^11.1.5"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "12",
"typescript": "^5"
}
}
.page404{background:#fff;padding:80px 0}.page404 img{height:296px;width:360px;display:block;margin:0 auto}
.page404{
background: #fff;
padding:80px 0;
img{
height:296px;
width:360px;
display: block;
margin:0 auto;
}
}
\ No newline at end of file
import styles from './index.module.scss'
import BreadNav from '@/components/BreadNav';
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import { GetServerSideProps } from 'next';
import { getCateList } from "@/server/getCateList";
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
export const getStaticProps: GetServerSideProps = async () => {
return getCateList()
}
const Page = (props: { cateList: ResponseTypeCateList }) => {
return (
<>
<main>
<Header {...props.cateList} />
<BreadNav><strong>404</strong></BreadNav>
<div className={styles.page404}>
<img src='/images/p404.png' alt="" />
</div>
<Footer />
</main>
</>
)
}
export default Page
\ No newline at end of file
import '../public/styles/font/iconfont.css'
import '../public/styles/base.scss'
import type { AppProps } from 'next/app';
//antd中英输入框组件文组件
import zhCN from 'antd/locale/zh_CN';
import { ConfigProvider, Empty } from 'antd'
import theme from '@/public/antvTheme/theme'
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import type { GetProp } from 'antd';
dayjs.locale('zh-cn')
//组件CSS降级兼容
import { StyleProvider, legacyLogicalPropertiesTransformer } from '@ant-design/cssinjs';
const renderEmpty: GetProp<typeof ConfigProvider, 'renderEmpty'> = (componentName) => {
return <Empty image='/images/empty.png' description="数据为空" imageStyle={{width: '240px', margin: '20px auto 0'}} />
};
const MyApp= ({ Component, pageProps }:AppProps) => {
return (
<StyleProvider hashPriority="high" transformers={[legacyLogicalPropertiesTransformer]}>
<ConfigProvider locale={ zhCN } theme={theme} renderEmpty={renderEmpty}>
<Component {...pageProps} />
</ConfigProvider>
</StyleProvider>
)
};
export default MyApp;
\ No newline at end of file
.mvAboutPage .banner{height:231px;background:url(../../public/images/aboutUsBanner.png) no-repeat top center}.mvAboutPage .section{background:#fff}.mvAboutPage .section .cons{padding:0 143px;padding-top:111px;padding-bottom:119px}.mvAboutPage .section .cons .left{width:267px}.mvAboutPage .section .cons .left .title{border-bottom:1px solid #E7E7E7;font-weight:bold;font-size:20px;color:#313131}.mvAboutPage .section .cons .left .title span{display:inline-block;position:relative;border-bottom:3px solid #00C69F;padding-bottom:22px;top:2px}.mvAboutPage .section .cons .left p{padding-top:22px;font-weight:400;font-size:14px;color:#000000;line-height:30px}.mvAboutPage .section .cons img{width:245px;height:245px;position:relative;top:58px}
.mvAboutPage{
.banner{
height:231px;
background: url(../../public/images/aboutUsBanner.png) no-repeat top center;
}
.section{
background: #fff;
.cons{
padding: 0 143px;
padding-top: 111px;
padding-bottom: 119px;
.left{
width: 267px;
.title{
border-bottom: 1px solid #E7E7E7;
font-weight: bold;
font-size: 20px;
color: #313131;
span{
display: inline-block;
position: relative;
border-bottom: 3px solid #00C69F;
padding-bottom: 22px;
top:2px;
}
}
p{
padding-top: 22px;
font-weight: 400;
font-size: 14px;
color: #000000;
line-height: 30px;
}
}
img{
width: 245px;
height: 245px;
position: relative;
top:58px;
}
}
}
}
\ No newline at end of file
import style from './index.module.scss'
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import { GetServerSideProps } from 'next';
import { getCateList } from "@/server/getCateList";
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
export const getServerSideProps: GetServerSideProps = async (context) => {
return getCateList()
}
const Page = (props: { cateList: ResponseTypeCateList }) => {
const { cateList } = props
return (
<>
<main>
<Header {...cateList} />
<div className={style.mvAboutPage}>
<div className={style.banner}></div>
<div className={style.section}>
<div className={`${style.cons} boxsiz w1226 row bothSide`}>
<div className={style.left}>
<div className={`${style.title} boxsiz`}><span>关于我们</span></div>
<p>
麒麟电子商城(www.chiplinks.net)<br />
我们是一家小型的电子元器件商城 <br />
我们是龙年诞生哒!<br />
我们想为朋友们提供一些帮助,<br />
虽然可能只是一点点,<br />
但请给予我们小小的机会,<br />
请相信我们,<br />
我们会竭尽全力地成长,<br />
成为你们希望的模样哦!
</p>
</div>
<img src="/images/aboutad.png" alt="" />
</div>
</div>
</div>
<Footer />
</main>
</>
)
}
export default Page
\ No newline at end of file
.invoiceBox{width:1022px;margin-left:12px;box-sizing:border-box;background:#fff;padding:20px 30px 100px;position:relative}.invoiceBox .invoiceTitle{font-size:16px;height:32px;color:#1A1A1A;line-height:21px;width:100%;border-bottom:1px solid #F4F4F4}.invoiceBox .invoiceButton{left:120px;top:18px;position:absolute;width:80px;height:26px;background:#FFFFFF;border-radius:1px;color:#FF9A00;border:1px solid #FF9A00;cursor:pointer}.invoiceBox .invoiceButton:hover{color:#fff;background-color:#FF9A00}.invoiceBox .invoiceItem{height:240px;padding-top:20px;box-sizing:border-box;border-bottom:1px solid #F4F4F4}.invoiceBox .invoiceItem .invoiceStatus{width:100%;height:20px;display:flex;line-height:20px;text-align:center;justify-content:space-between}.invoiceBox .invoiceItem .invoiceStatus .invoiceCheck{display:flex;align-items:center}.invoiceBox .invoiceItem .invoiceStatus .invoiceCheck input{cursor:pointer;margin-right:8px}.invoiceBox .invoiceItem .invoiceStatus .rightPart{display:flex;align-items:center}.invoiceBox .invoiceItem .invoiceStatus .rightPart .editButton{width:75px;height:20px;font-size:12px;color:#595959;background:#FFFFFF;border-radius:1px;border:1px solid #B0B0B0;cursor:pointer}.invoiceBox .invoiceItem .invoiceStatus .rightPart .invalid{width:60px;height:20px;font-size:12px;color:#D0121B;background:#FDF5F5;border-radius:1px;margin-left:25px;border:1px solid #D0121B;cursor:pointer}.invoiceBox .invoiceItem .invoiceStatus .rightPart .invalid:hover{color:#fff;background-color:#D0121B}.invoiceBox .invoiceItem .invoiceDetail{margin-top:20px;font-size:14px;width:100%}.invoiceBox .invoiceItem .invoiceDetail .lineItem{width:calc(100% - 50px);margin-bottom:15px;margin-left:50px}.invoiceBox .pagination{position:absolute;right:30px;bottom:30px}.modalContent{padding:45px 0 !important;box-sizing:border-box;padding-top:15px}.modalContent :global .ant-form-item{margin-bottom:20px}.modalFooter{width:100%;display:flex;margin-top:40px;padding-bottom:25px;justify-content:space-around}.modalFooter .saveButton{width:195px;height:45px;color:#fff;background:#FF9A00;border-radius:1px;cursor:pointer}.modalFooter .cancelButton{width:195px;height:45px;color:#FF9A00;background:#fff;border-radius:1px;cursor:pointer;border:1px solid #FF9A00}
.invoiceBox {
width: 1022px;
margin-left: 12px;
box-sizing: border-box;
background: #fff;
padding: 20px 30px 100px;
position: relative;
.invoiceTitle {
font-size: 16px;
height: 32px;
color: #1A1A1A;
line-height: 21px;
width: 100%;
border-bottom: 1px solid #F4F4F4;
}
.invoiceButton {
left: 120px;
top: 18px;
position: absolute;
width: 80px;
height: 26px;
background: #FFFFFF;
border-radius: 1px;
color: #FF9A00;
border: 1px solid #FF9A00;
cursor: pointer;
&:hover {
color: #fff;
background-color: #FF9A00;
}
}
.invoiceItem {
height: 240px;
padding-top: 20px;
box-sizing: border-box;
border-bottom: 1px solid #F4F4F4;
.invoiceStatus {
width: 100%;
height: 20px;
display: flex;
line-height: 20px;
text-align: center;
justify-content: space-between;
.invoiceCheck {
display: flex;
align-items: center;
input {
cursor: pointer;
margin-right: 8px;
}
}
.rightPart {
display: flex;
align-items: center;
.editButton {
width: 75px;
height: 20px;
font-size: 12px;
color: #595959;
background: #FFFFFF;
border-radius: 1px;
border: 1px solid #B0B0B0;
cursor: pointer;
}
.invalid {
width: 60px;
height: 20px;
font-size: 12px;
color: #D0121B;
background: #FDF5F5;
border-radius: 1px;
margin-left: 25px;
border: 1px solid #D0121B;
cursor: pointer;
&:hover {
color: #fff;
background-color: #D0121B;
}
}
}
}
.invoiceDetail {
margin-top: 20px;
font-size: 14px;
width: 100%;
.lineItem {
width: calc(100% - 50px);
margin-bottom: 15px;
margin-left: 50px;
}
}
}
.pagination {
position: absolute;
right: 30px;
bottom: 30px;
}
}
.modalContent {
padding: 45px 0!important;
box-sizing: border-box;
padding-top: 15px;
:global {
.ant-form-item {
margin-bottom:20px;
}
}
}
.modalFooter {
width: 100%;
display: flex;
margin-top: 40px;
padding-bottom: 25px;
justify-content: space-around;
.saveButton {
width: 195px;
height: 45px;
color: #fff;
background: #FF9A00;
border-radius: 1px;
cursor: pointer;
}
.cancelButton {
width: 195px;
height: 45px;
color: #FF9A00;
background: #fff;
border-radius: 1px;
cursor: pointer;
border: 1px solid #FF9A00;
}
}
\ No newline at end of file
import styles from './index.module.scss'
import {useState, useEffect} from 'react'
import { Cascader , Modal, Form, Input, Pagination, message,Empty } from 'antd';
import useRequest from "@/hooks/useRequest"
interface Area {
region_id?: string | number | null;
region_name: React.ReactNode;
children?: Area[];
isLeaf?: boolean;
region_type?: number
}
const AddressPage = () => {
const [initstatus, setInitstatus] = useState(false);
const [modal, contextHolder1] = Modal.useModal();
const [open, setOpen] = useState(false)
const [invoiceList, setInvoiceList] = useState<any>([]);
const [formData, setFormData] = useState<any>({});
const [areaList, setAreaList] = useState<Area[]>([]);
const [current, setCurrent] = useState(1);
const [pageSize, setPageSize] = useState(5);
const [total, setTotal] = useState(0);
const [doSub, setDoSub] = useState(false);
const [isAdd, setIsAdd] = useState(false);
const [backAreaList, setBackAreaList] = useState<any>([]);
const [ form ] = Form.useForm()
const { request: userRequest } = useRequest<any>({ manual: true })
const [messageApi, contextHolder] = message.useMessage();
useEffect(() => {
handleDataInit()
handleAreaInit(0, 'parentRegionOption')
}, [])
useEffect(() => {
doSub && handleInvoiceSave()
}, [doSub])
const handleDataInit = async () => {
const invoiceListResponse = await userRequest({
url: `/api/userInfo/userAddressList?limit=${pageSize}&page=${current}`,
method: 'get'
})
if (invoiceListResponse.code === 0) {
setInitstatus(true)
setInvoiceList(invoiceListResponse.data.list)
setTotal(invoiceListResponse.data.list.length)
}
}
const handleAreaInit = async (parent_id:0, type:string) => {
const areaListResponse = await userRequest({
url: `/api/userInfo/getSelectOption?parent_id=${parent_id}&type=${type}`,
method: 'get'
})
if (areaListResponse.code === 0) {
const areaDisPlayList = areaListResponse.data.map((areaItem:any) => {
areaItem.isLeaf = false
return areaItem
})
setAreaList(areaDisPlayList)
}
}
const handleInvoiceSave = async () => {
if(isAdd) {
if (formData.contact_address.length !== 4) return
const [nation_id, province, city, district] = backAreaList.length ? backAreaList : formData.contact_address
formData.nation_id = nation_id
formData.province = province
formData.city = city
formData.district = district
}
const saveInvoiceResponse = await userRequest({
url: '/api/userInfo/saveAddress',
method: 'post',
data: formData
})
if (saveInvoiceResponse.code === 0) {
if (isAdd) {
form.resetFields()
handleModal(false)
}
setFormData(null)
handleDataInit()
messageApi.open({
type: 'success',
content: '操作成功!',
});
} else {
messageApi.open({
type: 'error',
content: saveInvoiceResponse.msg,
});
}
setDoSub(false)
setIsAdd(false)
}
const manualValidate = () => {
form.validateFields().then((value:any) => {
if (formData && formData.web_user_address_id) {
value = Object.assign(formData, value)
}
setFormData(value)
setDoSub(true)
setIsAdd(true)
}).catch((e) => {});
};
const handleModal = (show:boolean) => {
form.resetFields()
setFormData(null)
setOpen(show)
};
const handleInvoiceEdit = async (data:any, key:string) => {
if(key=="is_del"){
modal.confirm({
title:"确认",
content:"确认要删除当前地址吗",
okText: '确认',
cancelText: '取消',
onOk() {
data[key] = 1
const editForm = {
web_user_address_id: data.web_user_address_id
}
editForm[key as keyof typeof editForm] = 1
setFormData(editForm)
setDoSub(true)
setIsAdd(false)
},
});
}else{
if (key) {
data[key] = 1
const editForm = {
web_user_address_id: data.web_user_address_id
}
editForm[key as keyof typeof editForm] = 1
setFormData(editForm)
setDoSub(true)
setIsAdd(false)
} else {
const disData = JSON.parse(JSON.stringify(data))
disData['contact_address'] = [disData.nation_id_cn, disData.province_cn, disData.city_cn, disData.district_cn]
setFormData(disData)
form.setFieldsValue(disData)
setBackAreaList([disData.nation_id, disData.province, disData.city, disData.district])
setOpen(true)
}
}
}
const validateMessages = {
required: '${label}不能为空!'
};
const loadData = async (selectedOptions: Area[]) => {
setBackAreaList([])
const targetOption = selectedOptions[selectedOptions.length - 1];
const areaListResponse = await userRequest({
url: `/api/userInfo/getSelectOption?parent_id=${targetOption.region_id}&type=parentRegionOption`,
method: 'get'
})
if (areaListResponse.code !== 0) return
if (!areaListResponse.data || !areaListResponse.data.length) targetOption.isLeaf = true
else {
const areaDisPlayList = areaListResponse.data.map((areaItem:any) => {
areaItem.isLeaf = false
return areaItem
})
targetOption.children = areaDisPlayList
}
setAreaList([...areaList])
}
const handlePageChange = (page:number, pageSize:number) => {
setCurrent(page)
setPageSize(pageSize)
}
return (
<>
{contextHolder}
{contextHolder1}
<div className={styles.invoiceBox}>
<div className={styles.invoiceTitle}>我的地址</div>
<button className={styles.invoiceButton} onClick={() => handleModal(true)}>新增地址</button>
{
invoiceList.map((invoiceItem:any) => {
return (
<div className={styles.invoiceItem} key={invoiceItem.web_user_address_id}>
<div className={styles.invoiceStatus}>
<div className={styles.invoiceCheck}>
{ invoiceItem.is_default ? (<>默认地址</>) : (<><input type="checkbox" onClick={() => handleInvoiceEdit(invoiceItem, 'is_default')}/>设为默认</>)}
</div>
<div className={styles.rightPart}>
<button className={styles.editButton} onClick={() => handleInvoiceEdit(invoiceItem, '')}>编辑地址</button>
{ !invoiceItem.is_del && (
<button className={styles.invalid} onClick={() => handleInvoiceEdit(invoiceItem, 'is_del')}>删除</button>
)}
</div>
</div>
<div className={styles.invoiceDetail}>
<div className={styles.lineItem}>
<span>联系人:</span>
<span>{invoiceItem.consignee}</span>
</div>
<div className={styles.lineItem}>
<span>联系地址:</span>
<span>
{invoiceItem.nation_id_cn}{invoiceItem.province_cn}{invoiceItem.city_cn}{invoiceItem.district_cn}{invoiceItem.detail_address}
</span>
</div>
<div className={styles.lineItem}>
<span>联系电话:</span>
<span>{invoiceItem.telphone}</span>
</div>
<div className={styles.lineItem}>
<span>电子邮箱:</span>
<span>{invoiceItem.email}</span>
</div>
</div>
</div>
)
})
}
{invoiceList.length==0&&initstatus&&<Empty image='/images/empty.png' description="暂无地址" imageStyle={{width: '240px', margin: '100px auto 0'}} />}
<div className={styles.pagination}>
<Pagination
showQuickJumper
showSizeChanger
hideOnSinglePage={true}
current={current}
pageSize={pageSize}
pageSizeOptions={[5, 10]}
total={total}
showTotal={(total) => `共 ${total} 条记录`}
onChange={handlePageChange}/>
</div>
</div>
<Modal
title="新增地址"
open={open}
destroyOnClose
footer={null}
closeIcon={null}
centered
onCancel={() => handleModal(false)}
>
<Form
className={styles.modalContent}
validateMessages={validateMessages}
form={form}
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}>
<Form.Item
className={styles.lineItem}
key="consignee"
label="联系人"
name="consignee"
rules={[{ required: true }]}>
<Input/>
</Form.Item>
<Form.Item
className={styles.lineItem}
key="contact_address"
label="联系地址"
name="contact_address"
rules={[{ required: true }]}>
<Cascader
fieldNames={{ label: 'region_name', value: 'region_id', children: 'children' }}
options={areaList}
loadData={loadData}
changeOnSelect />
</Form.Item>
<Form.Item
className={styles.lineItem}
key="detail_address"
label="详细地址"
name="detail_address"
rules={[{ required: true }]}>
<Input/>
</Form.Item>
<Form.Item
className={styles.lineItem}
key="telphone"
label="联系电话"
name="telphone"
rules={[{ required: true }]}>
<Input/>
</Form.Item>
<Form.Item
className={styles.lineItem}
key="email"
label="联系邮箱"
name="email"
rules={[{ required: true }]}>
<Input/>
</Form.Item>
</Form>
<div className={styles.modalFooter}>
<button className={styles.saveButton} onClick={() => manualValidate()}>保存</button>
<button className={styles.cancelButton} onClick={() => handleModal(false)}>取消</button>
</div>
</Modal>
</>
)
}
export default AddressPage
\ No newline at end of file
.userCenter{padding:10px;width:1226px;margin:0 auto;display:flex}
.userCenter {
padding: 10px;
width: 1226px;
margin: 0 auto;
display: flex;
}
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import Nav from "@/components/navigation";
import style from './index.module.scss'
import { GetServerSideProps } from 'next';
import { getCateList } from "@/server/getCateList";
import BasicData from './component'
import type {ResponseTypeCateList} from '@/components/Header/components/NavBig/types'
export const getStaticProps: GetServerSideProps = async () => {
return getCateList()
}
const Page = (props:{cateList:ResponseTypeCateList}) => {
const {cateList}=props
return (
<>
<Header {...cateList}/>
<div className={style.userCenter}>
<Nav></Nav>
<BasicData/>
</div>
<Footer />
</>
)
}
export default Page
\ No newline at end of file
import styles from './index.module.scss'
import { useState, useEffect, useRef } from 'react'
import useRequest from "@/hooks/useRequest"
import { useToast } from '@/hooks/useToast';
const editTypeMap = {
'1': '更换手机',
'2': '更换邮箱',
'3': '绑定微信',
'4': '绑定QQ',
'5': '修改密码',
'6': '修改账号'
}
const authTypeMap = {
'1': '手机',
'2': '邮箱',
'3': '微信',
'4': 'QQ',
'5': '密码',
'6': '账号'
}
const BasicPage = () => {
const { message } = useToast()
const messageRef = useRef(message);
const [user, setUser] = useState<any>({});
const [isBaseEdit, setIsBaseEdit] = useState<Boolean>(false);
const [userName, setUserName] = useState<any>();
const [userPost, setUserPost] = useState<any>();
const { request: userRequest } = useRequest<any>({ manual: true, loading: true })
const [invoiceList, setInvoiceList] = useState<any>();
const [addressList, setAddressList] = useState<any>();
const [messageEdit, setMesaageEdit] = useState<Boolean>(false);
const [editType, setEditType] = useState<any>();
const [authType, setAuthType] = useState<any>('1');
const [code, setCode] = useState('');
const [newCount, setNewCount] = useState('');
const handleCodeChange = (e: any) => setCode(e.target.value);
const handleCountChange = (e: any) => setNewCount(e.target.value);
const codeTimer = useRef<any>();
const [codeText, setCodeText] = useState<string>("发送验证码")
const [codeTimeVal, setCodeTimeVal] = useState<number>(60)
useEffect(() => {
if (codeText === '发送验证码') {
return;
}
codeTimer.current = setInterval(() => {
setCodeTimeVal((prevCodeTimeVal) => {
const newTime = prevCodeTimeVal - 1;
if (newTime < 1) {
clearInterval(codeTimer.current);
setCodeText('发送验证码');
setCodeTimeVal(60);
return 60;
}
setCodeText(`重发(${newTime}S)`);
return newTime;
});
}, 1000);
return () => {
if (codeTimer.current) {
clearInterval(codeTimer.current);
}
};
}, [codeText, setCodeTimeVal]);
useEffect(() => {
handleUserInfo()
handleAddressInit()
handleInvoiceInit()
}, [])
const handleUserInfo = () => {
userRequest({
url: '/api/userInfo/userInfo',
method: 'get'
}).then(res => {
if (res?.code === 0) {
setUser(res.data)
setUserName(res.data.contacts_name)
setUserPost(res.data.contacts_name_post)
}
})
}
const handleInvoiceInit = async () => {
const invoiceListResponse = await userRequest({
url: `/api/userInfo/userInvoiceList?limit=10&page=1&is_default=1`,
method: 'get'
})
if (invoiceListResponse?.code === 0 && invoiceListResponse?.data?.list.length) {
setInvoiceList(invoiceListResponse.data.list[0])
}
}
const handleAddressInit = async () => {
const invoiceListResponse = await userRequest({
url: `/api/userInfo/userAddressList?limit=10&page=1&is_default=1`,
method: 'get'
})
if (invoiceListResponse?.code === 0 && invoiceListResponse?.data?.list.length) {
setAddressList(invoiceListResponse.data.list[0])
}
}
const handleBaseEdit = (status: Boolean) => {
if (status) {
setIsBaseEdit(status)
}else if(!userName || !userPost){
messageRef.current("请填写联系人和联系岗位")
return
}
else if (userName && userPost) {
userRequest({
url: '/api/userInfo/changeUserContract',
method: 'post',
data: {
contacts_name: userName,
contacts_name_post: userPost
}
}).then(res => {
if (res?.code === 0) {
setIsBaseEdit(status)
handleUserInfo()
} else {
message(res?.msg)
}
})
}
}
const handleNameChange = (e: any) => {
setUserName(e.target.value)
}
const handlePOSTChange = (e: any) => {
setUserPost(e.target.value)
}
const handleMessageEdit = (type: any) => {
setEditType(type)
setMesaageEdit(true)
}
const handleAuthTypeChange = () => {
if(!user?.contacts_email){
messageRef.current("当前用户邮箱为空,请先设置邮箱后再切换")
return
}
setAuthType(authType === '1' ? '2' : '1')
}
//发送验证码
const handleCodeSend = async (e: any) => {
if (codeText !== '发送验证码') {
return;
}
const count = authType === '1' ? user?.contacts_tel : user?.contacts_email
if (!count) return
const param = {
send_type: authType,
send_user: user?.web_user_id,
send_fun: 'changInfo'
}
const response = await userRequest({
url: '/sendMsgCode',
method: 'post',
data: param
})
if (response.code == 0) {
messageRef.current("发送成功")
setCodeText('重发(60S)')
} else {
messageRef.current(response.msg)
}
}
const handleEditConfirm = async () => {
if (!newCount || !code) return
const param = {
send_type: authType,
chang_type: editType,
new_value: newCount,
code: code,
send_user: user?.web_user_id
}
const response = await userRequest({
url: '/api/userInfo/changeUserInfo',
method: 'post',
data: param
})
if (response.code === 0) {
messageRef.current('操作成功!')
setCode('')
setNewCount('')
setMesaageEdit(false)
handleUserInfo()
} else messageRef.current(response.msg)
}
const handleEditCancel = () => {
setMesaageEdit(false)
setCode('')
setNewCount('')
}
return (
<>
{(!messageEdit) ? (
<div className={styles.basicBox}>
<div className={`${styles.basicModule} ${styles.basicHeight}`}>
<div className={styles.basicTitle}>基础信息</div>
<div className={styles.basicContent}>
<div className={styles.basicItem}>
<span>账号ID:</span>
<span>{user?.web_user_account}</span>
<button className={styles.basicButton} onClick={() => handleMessageEdit('6')}>修改账号</button>
</div>
<div className={styles.basicItem}>
<span>绑定手机:</span>
<span>{user?.contacts_tel}</span>
<button className={styles.basicButton} onClick={() => handleMessageEdit('1')}>更换手机</button>
</div>
<div className={styles.basicItem}>
<span>绑定邮箱:</span>
<span>{user?.contacts_email}</span>
<button className={styles.basicButton} onClick={() => handleMessageEdit('2')}>{user?.contacts_email?'更换邮箱':'设置邮箱'}</button>
</div>
<div className={styles.basicItem}>
<span>账号密码:</span>
<button className={styles.basicButton} onClick={() => handleMessageEdit('5')}>修改密码</button>
</div>
<div className={styles.basicItem}>
<span>联系人:</span>
{isBaseEdit ? (
<>
<input className={styles.basicInput} value={userName} onChange={handleNameChange} />
<button className={styles.basicConfirm} onClick={() => handleBaseEdit(false)}>确认</button>
</>
) : (
<>
<span>{user?.contacts_name}</span>
<button className={styles.basicButton} onClick={() => handleBaseEdit(true)}>修改基础信息</button>
</>
)}
</div>
<div className={styles.basicItem}>
<span>联系人岗位:</span>
{isBaseEdit ? (
<>
<input className={styles.basicInput} value={userPost} onChange={handlePOSTChange} />
</>
) : (
<>
<span>{user?.contacts_name_post}</span>
</>
)}
</div>
<div className={styles.basicItem}>
<span>专属客服:</span>
<span>{user?.sale_id_cn||""}</span>
</div>
</div>
</div>
<div className={styles.basicModule}>
<div className={styles.basicTitle}>默认发票</div>
<div style={{ padding: '20px 30px 0' }}>
<span>发票种类:</span>
<span>{invoiceList?.invoice_type_cn}</span>
</div>
<div className={styles.basicContent} style={{ height: 'calc(100% - 40px)' }}>
<div className={styles.basicItem}>
<span>发票抬头:</span>
<span>{invoiceList?.tax_title}</span>
</div>
<div className={styles.basicItem}>
<span>开户行:</span>
<span>{invoiceList?.bank_name}</span>
</div>
<div className={styles.basicItem}>
<span>公司电话:</span>
<span>{invoiceList?.company_phone}</span>
</div>
<div className={styles.basicItem}>
<span>统一税务号:</span>
<span>{invoiceList?.tax_no}</span>
</div>
<div className={styles.basicItem}>
<span>银行账号:</span>
<span>{invoiceList?.bank_account}</span>
</div>
<div className={styles.basicItem}>
<span>注册地址:</span>
<span>{invoiceList?.company_address}</span>
</div>
</div>
</div>
<div className={styles.basicModule}>
<div className={styles.basicTitle}>默认地址</div>
<div className={styles.basicContent}>
<div className={styles.basicItem}>
<span>联系人:</span>
<span>{addressList?.consignee}</span>
</div>
<div className={styles.basicItem}>
<span>联系地址:</span>
<span>{addressList?.nation_id_cn}{addressList?.province_cn}{addressList?.city_cn}{addressList?.district_cn}{addressList?.detail_address}</span>
</div>
<div className={styles.basicItem}>
<span>联系电话:</span>
<span>{addressList?.telphone}</span>
</div>
<div className={styles.basicItem}>
<span>联系邮箱:</span>
<span>{addressList?.email}</span>
</div>
</div>
</div>
</div>
) : (
<div className={styles.editBox}>
<div className={styles.editTitle}>{editTypeMap[editType as keyof typeof editTypeMap]}</div>
<div className={styles.editType}>
<div className={styles.typeLeft}>{authTypeMap[authType as keyof typeof authTypeMap]}</div>
<div className={styles.typRight}>{authType === '1' ? user?.contacts_tel : user?.contacts_email}</div>
<span className={styles.inputButton} onClick={handleAuthTypeChange}>切换{authType === '1' ? '邮箱' : '手机'}验证</span>
</div>
<div className={styles.editLines}>
<input className={styles.editInput} value={code} onChange={handleCodeChange} />
<span className={codeText == '发送验证码' ? `${styles.inputButton}` : `${styles.inputButton} ${styles.dis}`} onClick={handleCodeSend}>{codeText}</span>
</div>
<div className={styles.editLines}>
<input
className={styles.editInput}
value={newCount}
onChange={handleCountChange}
placeholder={`请输入新${authTypeMap[editType as keyof typeof authTypeMap]}`} />
</div>
<div className={styles.editButtons}>
<button className={styles.comfirmButton} onClick={handleEditConfirm}>确定</button>
<button className={styles.cancelButton} onClick={handleEditCancel}>取消</button>
</div>
</div>
)}
</>
)
}
export default BasicPage
\ No newline at end of file
.basicBox{width:1022px;margin-left:12px;box-sizing:border-box}.basicBox .basicModule{width:100%;height:265px;background-color:#fff;box-sizing:border-box;margin-bottom:10px;padding:20px 30px}.basicBox .basicModule .basicTitle{height:32px;font-size:16px;line-height:20px;border-bottom:1px solid #F4F4F4}.basicBox .basicModule .basicContent{padding:20px 30px;box-sizing:border-box;height:100%;display:flex;flex-direction:column;flex-wrap:wrap}.basicBox .basicModule .basicContent .basicItem{width:calc(50% - 5px);display:inline-flex;height:40px;align-items:center}.basicBox .basicModule .basicContent .basicItem .basicButton{width:75px;font-size:12px;height:20px;color:#595959;background:#FFFFFF;border-radius:1px;border:1px solid #B0B0B0;margin-left:10px;cursor:pointer}.basicBox .basicModule .basicContent .basicItem .basicButton:hover{color:#000}.basicBox .basicModule .basicInput{width:99px;height:30px;background:#FFFFFF;border-radius:2px;border:1px solid #000000;padding-left:5px}.basicBox .basicModule .basicConfirm{width:75px;height:20px;font-size:12px;color:#FF9A00;background:#FFF7EC;border-radius:1px;margin-left:5px;border:1px solid #FF9A00}.basicBox .basicHeight{height:340px}.editBox{width:1022px;height:630px;margin-left:12px;box-sizing:border-box;background-color:#fff;display:flex;flex-direction:column;justify-content:center;align-items:center}.editBox .editTitle{width:400px;font-size:20px;margin-bottom:80px;margin-top:-60px;text-align:center}.editBox .editInput{width:400px;height:45px;border-radius:1px;border:1px solid #e0e0e0;padding:0 50px 0 20px;box-sizing:border-box}.editBox .editInput:focus{border:1px solid #000}.editBox .editType{width:400px;height:45px;background:#F4F4F4;border-radius:1px;margin-bottom:25px;color:#808080;display:flex;align-items:center;position:relative}.editBox .editType .typeLeft{width:70px;height:23px;line-height:23px;text-align:center;position:relative;border-right:1px solid #E2E2E2}.editBox .editType .typRight{padding-left:20px}.editBox .editLines{margin-bottom:25px;position:relative}.editBox .editButtons{margin-top:55px}.editBox .inputButton{position:absolute;top:13px;right:15px;font-size:14px;color:#1969F9;cursor:pointer}.editBox .inputButton.dis{cursor:not-allowed;color:#999}.editBox .comfirmButton{font-size:14px;color:#FFFFFF;width:195px;height:45px;background:#FF9A00;border-radius:1px;margin-right:10px;cursor:pointer}.editBox .comfirmButton:hover{background:#E18800}.editBox .cancelButton{width:195px;height:45px;font-size:14px;color:#FF9A00;border-radius:1px;border:1px solid #FF9A00;cursor:pointer;background-color:#fff}.editBox .cancelButton:hover{background:#FFF7EC}
.basicBox {
width: 1022px;
margin-left: 12px;
box-sizing: border-box;
.basicModule {
width: 100%;
height: 265px;
background-color: #fff;
box-sizing: border-box;
margin-bottom: 10px;
padding: 20px 30px;
.basicTitle {
height: 32px;
font-size: 16px;
line-height: 20px;
border-bottom: 1px solid #F4F4F4;
}
.basicContent {
padding: 20px 30px;
box-sizing: border-box;
height: 100%;
display: flex;
flex-direction: column;
flex-wrap: wrap;
.basicItem {
width: calc(50% - 5px);
display: inline-flex;
height: 40px;
align-items: center;
.basicButton {
width: 75px;
font-size: 12px;
height: 20px;
color: #595959;
background: #FFFFFF;
border-radius: 1px;
border: 1px solid #B0B0B0;
margin-left: 10px;
cursor: pointer;
&:hover {
color: #000;
}
}
}
}
.basicInput {
width: 99px;
height: 30px;
background: #FFFFFF;
border-radius: 2px;
border: 1px solid #000000;
padding-left: 5px;
}
.basicConfirm {
width: 75px;
height: 20px;
font-size: 12px;
color: #FF9A00;
background: #FFF7EC;
border-radius: 1px;
margin-left: 5px;
border: 1px solid #FF9A00;
}
}
.basicHeight {
height: 340px;
}
}
.editBox {
width: 1022px;
height: 630px;
margin-left: 12px;
box-sizing: border-box;
background-color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.editTitle {
width: 400px;
font-size: 20px;
margin-bottom: 80px;
margin-top: -60px;
text-align: center;
}
.editInput {
width: 400px;
height: 45px;
border-radius: 1px;
border: 1px solid #e0e0e0;
padding: 0 50px 0 20px;
box-sizing: border-box;
&:focus{border: 1px solid #000;}
}
.editType {
width: 400px;
height: 45px;
background: #F4F4F4;
border-radius: 1px;
margin-bottom: 25px;
color: #808080;
display: flex;
align-items: center;
position: relative;
.typeLeft {
width: 70px;
height: 23px;
line-height: 23px;
text-align: center;
position: relative;
border-right: 1px solid #E2E2E2;
}
.typRight {
padding-left: 20px;
}
}
.editLines {
margin-bottom: 25px;
position: relative;
}
.editButtons {
margin-top: 55px;
}
.inputButton {
position: absolute;
top: 13px;
right: 15px;
font-size: 14px;
color: #1969F9;
cursor: pointer;
&.dis{
cursor: not-allowed;
color:#999;
}
}
.comfirmButton {
font-size: 14px;
color: #FFFFFF;
width: 195px;
height: 45px;
background: #FF9A00;
border-radius: 1px;
margin-right: 10px;
cursor: pointer;
&:hover {
background: #E18800;
}
}
.cancelButton {
width: 195px;
height: 45px;
font-size: 14px;
color: #FF9A00;
border-radius: 1px;
border: 1px solid #FF9A00;
cursor: pointer;
background-color: #fff;
&:hover {
background: #FFF7EC;
}
}
}
\ No newline at end of file
.userCenter {
padding: 10px;
width: 1226px;
margin: 0 auto;
display: flex;
}
\ No newline at end of file
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import Nav from "@/components/navigation";
import style from './index.module.scss'
import { GetServerSideProps } from 'next';
import { getCateList } from "@/server/getCateList";
import BasicData from './component/basicData'
import type {ResponseTypeCateList} from '@/components/Header/components/NavBig/types'
export const getStaticProps: GetServerSideProps = async () => {
return getCateList()
}
const Page = (props:{cateList:ResponseTypeCateList}) => {
const {cateList}=props
return (
<>
<Header {...cateList}/>
<div className={style.userCenter}>
<Nav></Nav>
<BasicData/>
</div>
<Footer />
</>
)
}
export default Page
\ No newline at end of file
import styles from './index.module.scss'
import BreadNav from '@/components/BreadNav';
import ListSort from '@/components/ListSort';
import { useEffect, useRef, useState } from 'react';
import type { ListSortType } from '@/components/ListSort/types'
import type { dataListItemType } from '@/components/ListOneItem/types'
import type { brandResponseType, requestDataType, brandInfoResponseType } from '@/types/brandTypes'
import ListOneItem from '@/components/ListOneItem';
import useRequest from '@/hooks/useRequest';
import { useRouter } from 'next/router';
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import { GetServerSideProps } from 'next';
import { getBrandListData } from "@/server/getBrandListData";
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
import { useQq } from '@/hooks/useQq';
import { Empty,Pagination } from 'antd';
export const getServerSideProps: GetServerSideProps = async (context) => {
const { query } = context;
return getBrandListData(query.brand_id)
}
const Page = (props: { cateList: ResponseTypeCateList,brandInfoData:brandInfoResponseType }) => {
const { QQURL,PHONE}=useQq()
const router = useRouter()
const { query } = router
const brandInfo=props.brandInfoData.data
const [shouNoData, setShouNoData] = useState(false)
const [page, setPage] = useState(1)
const [total, setTotal] = useState(0)
const [dataList, setDataList] = useState<dataListItemType[]>([])
const [sortObj, setSortObj] = useState<ListSortType>({
sortType: 1,
isStock: false,
stockSort: '',
priceSort: ''
})
const { request: brandListRequest } = useRequest<brandResponseType>({ manual: true })
const shouldResetPage = useRef(false);
useEffect(() => {
shouldResetPage.current = true;
setPage(1);
}, [sortObj,query.brand_id]);
useEffect(() => {
if (shouldResetPage.current && page !== 1) {
return
}
shouldResetPage.current = false;
let obj_: requestDataType = { page_size: 10, page: page, standard_brand_id: query.brand_id }
if (sortObj.isStock) {
obj_['stock/gt'] = 0
}
if (sortObj.sortType === 2) {
obj_['stock/sort'] = sortObj.stockSort === 'top' ? 'asc' : 'desc'
}
if (sortObj.sortType === 3) {
obj_['single_price/sort'] = sortObj.priceSort === 'top' ? 'asc' : 'desc'
}
brandListRequest({
url: '/api/search/searchByBrand',
method: 'post',
data: obj_,
}).then(res => {
if (res?.code === 0) {
setTotal(Number(res.data?.total))
setDataList(res.data?.lists || [])
if (res.data?.lists.length > 0) {
setShouNoData(false)
} else {
setShouNoData(true)
}
} else {
setShouNoData(true)
}
})
}, [brandListRequest, query.brand_id, page, sortObj])
const handlePageChange = (page:number, pageSize:number) => {
setPage(page)
}
return (
<>
<main>
<Header {...props.cateList} />
<BreadNav><strong>&quot;{brandInfo?.brand_name}&quot;的型号搜索结果</strong></BreadNav>
<div className={`${styles.mvBrandlistPage} w1226`} >
<div className={`${styles.brandheadsl} row boxsiz`}>
<img src={brandInfo?.brand_logo || '/images/default.jpg'} alt='' className={styles.brandimg} />
<div className={styles.brandInfo} >
<h2>{brandInfo?.brand_name}</h2>
<div className={styles.textBf}>
{brandInfo?.brand_desc}
</div>
{/* <div className='brandbox row '>
<span>分类:</span>
<div className='itembox row'>
<div className='item'>逻辑芯片(200)</div>
<div className='item'>逻辑芯片(200)</div>
</div>
</div> */}
</div>
</div>
<div className={styles.databox}>
<div className={styles.dataGroupSupplier}>
<div className={styles.sortbixjk}>
<ListSort sortObj={sortObj} setSortObj={setSortObj} />
</div>
{
dataList.map(item => {
return (
<ListOneItem key={item.sku_id} {...item} QQURL={QQURL} PHONE={PHONE} />
)
})
}
{shouNoData ? <Empty image='/images/emptyorder.png' description="数据为空!" imageStyle={{height: '183px', margin: '30px auto 0'}} /> : ''}
</div>
<Pagination
className='paginationxkant'
showQuickJumper
showSizeChanger
hideOnSinglePage={true}
current={page}
pageSize={10}
pageSizeOptions={[5, 10]}
total={total}
showTotal={(total) => `共 ${total} 条记录`}
onChange={handlePageChange}/>
</div>
</div>
<Footer />
</main>
</>
)
}
export default Page
\ No newline at end of file
.mvBrandlistPage{margin-bottom:56px}.mvBrandlistPage .brandheadsl{min-height:275px;background:#fff;padding:26px 60px}.mvBrandlistPage .brandheadsl .brandimg{width:222px;height:222px;background:#FFFFFF;border:1px solid #EDEFEF;margin-right:60px}.mvBrandlistPage .brandheadsl .brandinfo{width:822px}.mvBrandlistPage .brandheadsl .brandinfo h2{font-weight:bold;font-size:22px;color:#000000;line-height:29px;text-align:center;margin-bottom:20px}.mvBrandlistPage .brandheadsl .brandinfo .textBf{font-size:14px;color:#000000;line-height:25px;height:100px;word-break:break-all;text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4}.mvBrandlistPage .brandheadsl .brandinfo .brandbox span{font-size:12px;color:#888;line-height:20px;width:80px;flex-shrink:0}.mvBrandlistPage .brandheadsl .brandinfo .brandbox .itembox{flex-wrap:wrap}.mvBrandlistPage .brandheadsl .brandinfo .brandbox .itembox .item{height:20px;line-height:20px;font-size:12px;color:#000000;margin-right:40px;margin-bottom:15px}.mvBrandlistPage .databox{padding-top:24px}.mvBrandlistPage .databox .dataGroupSupplier{padding-bottom:20px;background:#fff;min-height:400px}.mvBrandlistPage .databox .dataGroupSupplier .sortbixjk{padding:0 27px;padding-top:25px}
.mvBrandlistPage{
margin-bottom: 56px;
.brandheadsl{
min-height: 275px;
background: #fff;
padding:26px 60px;
.brandimg{
width: 222px;
height: 222px;
background: #FFFFFF;
border: 1px solid #EDEFEF;
margin-right: 60px;
}
.brandinfo{
width:822px;
h2{
font-weight: bold;
font-size: 22px;
color: #000000;
line-height: 29px;
text-align: center;
margin-bottom: 20px;
}
.textBf{
font-size: 14px;
color: #000000;
line-height: 25px;
height: 100px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
}
.brandbox{
span{
font-size: 12px;
color: #888;
line-height: 20px;
width:80px;
flex-shrink: 0;
}
.itembox{
flex-wrap: wrap;
.item{
height:20px;
line-height: 20px;
font-size: 12px;
color: #000000;
margin-right: 40px;
margin-bottom: 15px;
}
}
}
}
}
.databox{
padding-top: 24px;
.dataGroupSupplier{
padding-bottom: 20px;
background: #fff;
min-height: 400px;
.sortbixjk{
padding:0 27px;
padding-top: 25px;
}
}
}
}
\ No newline at end of file
.mvBrandPage{padding-top:63px;margin-bottom:98px}.mvBrandPage .section{margin-bottom:70px}.mvBrandPage .section .title{text-align:center;font-size:24px;color:#000000;line-height:31px;margin-bottom:45px}.mvBrandPage .section .title img{display:block;margin:0 auto;margin-top:2px}.mvBrandPage .section .itembox{flex-wrap:wrap}.mvBrandPage .section .itembox .item{width:233px;height:80px;margin-bottom:15px;transition:all 0.5s;margin-right:15px;background:#fff}.mvBrandPage .section .itembox .item:nth-child(5n){margin-right:0px}.mvBrandPage .section .itembox .item:hover{box-shadow:4px 6px 7px 1px rgba(154,151,149,0.18);transform:translateY(-1px)}.mvBrandPage .section .itembox .item img{width:233px;height:80px;object-fit:contain;transform:scale(0.8)}
.mvBrandPage{
padding-top: 63px;
margin-bottom: 98px;
.section{
margin-bottom: 70px;
.title{
text-align: center;
font-size: 24px;
color: #000000;
line-height: 31px;
margin-bottom: 45px;
img{
display: block;
margin:0 auto;
margin-top: 2px;
}
}
.itembox{
flex-wrap: wrap;
.item{
width: 233px;
height: 80px;
margin-bottom: 15px;
transition: all 0.5s;
margin-right: 15px;
background: #fff;
&:nth-child(5n){
margin-right: 0px;
}
&:hover{
box-shadow: 4px 6px 7px 1px rgba(154,151,149,0.18);
transform: translateY(-1px);
}
img{
width: 233px;
height: 80px;
object-fit: contain;
transform: scale(0.8);
}
}
}
}
}
\ No newline at end of file
import styles from './index.module.scss'
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import { GetServerSideProps } from 'next';
import { getBrandMapData } from "@/server/getBrandMapData";
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
import type { brandMapResponseType } from '@/types/brandMapTypes';
import Link from 'next/link';
export const getServerSideProps: GetServerSideProps = async () => {
return getBrandMapData()
}
const BrandMap = (props: { cateList: ResponseTypeCateList, brandMapData: brandMapResponseType }) => {
const more_brand_list = props.brandMapData.data.more_brand_list
const popular_brand_list = props.brandMapData.data.popular_brand_list
return (
<>
<main>
<Header {...props.cateList} />
<div className={styles.mvBrandPage}>
<div className={`${styles.section} w1226`}>
<div className={styles.title}>
热门品牌
<img src='/images/Popular.png' alt="" />
</div>
<div className={`${styles.itembox} row`}>
{
more_brand_list.map((item, index) => {
return (
<Link href={`/brand/${item.goods_brand_id}.html`} className={styles.item} key={index + String(item.goods_brand_id)}>
<img src={item.brand_logo} alt={item.brand_name} />
</Link>
)
})
}
</div>
</div>
<div className={`${styles.section} w1226`}>
<div className={styles.title}>
更多品牌
<img src='images/More.png' alt="" />
</div>
<div className={`${styles.itembox} row`}>
{
popular_brand_list.map((item, index) => {
return (
<Link href={`/brand/${item.goods_brand_id}.html`} className={styles.item} key={index + String(item.goods_brand_id)}>
<img src={item.brand_logo} alt={item.brand_name} />
</Link>
)
})
}
</div>
</div>
</div>
<Footer />
</main>
</>
)
}
export default BrandMap
\ No newline at end of file
.mvContactPage .banner{height:231px;background:url(../../public/images/contactUsBanner.png) no-repeat top center}.mvContactPage .section{background:#fff}.mvContactPage .section .cons{padding:0 143px;padding-top:111px;padding-bottom:119px}.mvContactPage .section .cons .left .title{border-bottom:1px solid #E7E7E7;font-weight:bold;font-size:20px;color:#313131}.mvContactPage .section .cons .left .title span{display:inline-block;position:relative;border-bottom:3px solid #00C69F;padding-bottom:22px;top:2px}.mvContactPage .section .cons .left .lxbox{padding-top:30px;margin-bottom:25px}.mvContactPage .section .cons .left .lxbox span{width:44px;height:44px;border:1px solid #00C69F;margin-right:33px}.mvContactPage .section .cons .left .lxbox span i{color:#00C69F;font-size:40px}.mvContactPage .section .cons .left .lxbox span i.font30{font-size:22px}.mvContactPage .section .cons .left .lxbox .rxs{font-size:16px;color:#888888}.mvContactPage .section .cons .left .lxbox .rxs p{color:#000000;font-weight:bold;margin-top:7px}.mvContactPage .section .cons img{width:245px;height:245px;position:relative;top:58px}
.mvContactPage{
.banner{
height:231px;
background: url(../../public/images/contactUsBanner.png) no-repeat top center;
}
.section{
background: #fff;
.cons{
padding: 0 143px;
padding-top: 111px;
padding-bottom: 119px;
.left{
// width: 267px;
.title{
border-bottom: 1px solid #E7E7E7;
font-weight: bold;
font-size: 20px;
color: #313131;
span{
display: inline-block;
position: relative;
border-bottom: 3px solid #00C69F;
padding-bottom: 22px;
top:2px;
}
}
.lxbox{
padding-top: 30px;
margin-bottom: 25px;
span{
width:44px;
height:44px;
border:1px solid #00C69F;
i{
color:#00C69F;
font-size: 40px;
&.font30{
font-size: 22px;
}
}
margin-right: 33px;
}
.rxs{
font-size: 16px;
color: #888888;
p{
color:#000000;
font-weight: bold;
margin-top: 7px;
}
}
}
}
img{
width: 245px;
height: 245px;
position: relative;
top:58px;
}
}
}
}
\ No newline at end of file
import styles from './index.module.scss'
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import { GetServerSideProps } from 'next';
import { getCateList } from "@/server/getCateList";
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
export const getServerSideProps: GetServerSideProps = async (context) => {
return getCateList()
}
const Page = (props: { cateList: ResponseTypeCateList }) => {
const { cateList } = props
return (
<>
<main>
<Header {...cateList} />
<div className={styles.mvContactPage}>
<div className={styles.banner}></div>
<div className={styles.section}>
<div className={`${styles.cons} boxsiz w1226 row bothSide`}>
<div className={styles.left}>
<div className={`${styles.title} boxsiz`}><span>联系我们</span></div>
<div className={`${styles.lxbox} boxsiz flex`}>
<span className='row verCenter rowCenter'><i className='icon iconfont icon-phone '></i></span>
<div className={styles.rxs}>
热线<p>010-53680391</p>
</div>
</div>
<div className={`${styles.lxbox} flex`}>
<span className='row verCenter rowCenter'><i className='icon iconfont icon-email '></i></span>
<div className={styles.rxs}>
邮箱<p>sales@chiplinks.net</p>
</div>
</div>
<div className={`${styles.lxbox} flex`}>
<span className='row verCenter rowCenter'><i className={`${styles.font30} icon iconfont icon-dizhi`}></i></span>
<div className={styles.rxs}>
地址
<p>北京:北京市丰台区榴乡路88号院2号楼2005室</p>
<p> 廊坊:河北省廊坊市广阳区新开路街道永丰道122号新朝阳2期2号办公楼1603-1605室</p>
</div>
</div>
</div>
<img src="/images/aboutad.png" alt="" />
</div>
</div>
</div>
<Footer />
</main>
</>
)
}
export default Page
\ No newline at end of file
import styles from './index.module.scss'
import {API_URL} from '@/configReact'
import {useState, useEffect} from 'react'
import { Badge, Table, Pagination,Upload ,message} from "antd";
import type { TableColumnsType,UploadProps } from 'antd';
import useRequest from "@/hooks/useRequest"
import { DataType } from "@/types/orderTypes"
import { useRouter } from 'next/router'
import { useQq } from '@/hooks/useQq';
import Link from 'next/link';
import { useCookies } from '@/hooks/useCookies';
const CenterHome = () => {
const router = useRouter()
const {QQURL}=useQq()
const {getCookie} = useCookies()
const [user, setUser] = useState<any>({});
const [imghead, setImghead] = useState("/images/logo.png");
const { request: userRequest } = useRequest<any>({ manual: true })
const [statusSummaryMap, setStatusSummaryMap] = useState<any>({'1': {count: 0}, '2': {count: 0}, '3': {count: 0}, '4': {count: 0}})
const [goodsList, setGoodsList] = useState<any>([])
const [current, setCurrent] = useState(1)
const [pageSize, setPageSize] = useState(5)
const [total, setTotal] = useState(0)
const [messageApi, contextHolder] = message.useMessage();
const columns: TableColumnsType<DataType> = [
{ title: '序号', dataIndex: 'name', width:200,key: 'name', render:(text, record, index) => { return <span>{index + 1}</span>} },
{ title: '型号/品牌', dataIndex: 'sku_name', key: 'sku_name', render:(text, record, index) => { return <span>{record.goods_name}/{record.brand_name}</span>} },
{ title: '数量', dataIndex: 'goods_number', key: 'goods_number' },
{ title: '单价', dataIndex: 'goods_price', key: 'goods_price' , render:(text, record, index) => { return <span>{record.iso_code_text}{record.goods_price}</span>}},
{ title: '小计', dataIndex: 'goods_amount', key: 'goods_amount', render:(text, record, index) => { return <span>{record.iso_code_text}{record.goods_amount}</span>} },
{ title: '明细备注', dataIndex: 'web_order_remark', key: 'web_order_remark' }
]
useEffect(() => {
handleUserDetail()
}, [])
useEffect(() => {
handleDataInit()
}, [current, pageSize])
const handleUserDetail = () => {
userRequest({
url: '/api/userInfo/userInfo',
method: 'get'
}).then(res => {
if (res?.code === 0) {
setImghead(res.data?.head_img||"/images/logo.png")
setUser(res.data)
}else{
}
})
}
const handleDataInit = async () => {
const tatusSummaryResponse = await userRequest({
url: '/api/order/webOrderStatusSummary',
method: 'post'
})
if (tatusSummaryResponse.code === 0) {
setStatusSummaryMap(Object.assign(statusSummaryMap, tatusSummaryResponse.data))
}
const webOrderListResponse = await userRequest({
url: '/api/order/webOrderList',
method: 'post'
})
if (webOrderListResponse.code === 0) {
setTotal(webOrderListResponse.data.total)
const arr_=webOrderListResponse.data.list||[]
arr_.forEach((item:any)=>{
item.order_items.forEach((item1:any)=>{
item1.iso_code_text=item.iso_code=="CNY"?'¥':'$'
})
})
setGoodsList(arr_)
}
}
const handlePageChange = (page:number, pageSize:number) => {
setCurrent(page)
setPageSize(pageSize)
}
const handleOrderStatus = (status: any) => {
router.push(`/myOrder?status=${status}`)
}
const upProps: UploadProps = {
name: 'file',
action: API_URL+'/api/userInfo/changeUserImg',
showUploadList:false,
headers: {
Authorization: getCookie("token")!,
webUserId: getCookie("userId")!,
},
beforeUpload(file){
// messageApi.open({
// type: 'error',
// content: '狗蛋接口挂了',
// });
// return
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
messageApi.open({
type: 'error',
content: '请上传图片格式',
});
}
const isLt2M = file.size / 1024 / 1024 < 10;
if (!isLt2M) {
messageApi.open({
type: 'error',
content: '请上传图片格式',
});
}
return isJpgOrPng &&isLt2M
},
onChange(info) {
if (info.file.status === 'done') {
const response = info.file.response;
if(response?.code==0){
messageApi.open({
type: 'success',
content:"上传头像成功",
});
setImghead(response?.msg)
}else{
messageApi.open({
type: 'error',
content:response?.msg,
});
}
}
},
};
return (
<>
{contextHolder}
<div className={styles.centerBox}>
<div className={styles.basicBox}>
<div className={styles.baseTitle}>
基本信息
<button
className={styles.editButton}
onClick={() => {router.push(`/basicData`)}}>
修改资料
</button>
</div>
<div className={styles.contentBox}>
<Upload {...upProps}>
<div className={styles.headImgBox}>
<img className={styles.headImg} src={imghead}></img>
<div className={styles.headImgUptext}>更换头像</div>
</div>
</Upload>
<div className={styles.detailLines}>
<div className={styles.lineItem}>
<span>账号ID:</span>
<Link href="/basicData" className={styles.linkItemone}>{user?.web_user_account}</Link>
</div>
<div className={styles.lineItem}>
<span>绑定手机:</span>
<span>{user?.contacts_tel}</span>
</div>
<div className={styles.lineItem}>
<span>默认发票公司:</span>
<span>{user?.company_name}</span>
</div>
<div className={styles.lineItem}>
<span>绑定邮箱:</span>
<span>{user?.contacts_email}</span>
</div>
<div className={styles.lineItem}>
<span>税务登记号:</span>
<span>{user?.tax_no}</span>
</div>
<div className={styles.lineItem} style={{display:"block"}}>
<span>公司注册地址:</span>
<span>{user?.company_address}</span>
</div>
</div>
<a className={styles.myService} href={QQURL} target='_blank' rel="noreferrer">
<img src="images/customerService.png" />
<span>我的客服</span>
</a>
</div>
</div>
<div className={styles.bottomBox}>
<div className={styles.orderBox}>
<div className={styles.baseTitle}>我的订单</div>
<div className={styles.moreButton} onClick={() => {router.push(`/myOrder`)}}>
查看全部
<span style={{marginLeft: '5px'}}>{'>'}</span>
</div>
<div className={styles.statusBox}>
<div className={`${styles.statusItem} ${styles.pendPreview}`} onClick={() => handleOrderStatus('1')}>
<img src="/images/pendPreview.png"></img>
<div>
<Badge count={statusSummaryMap[1]['count']} offset={[20, 8]} size="small" showZero>
<span>待审核</span>
</Badge>
</div>
</div>
<div className={`${styles.statusItem} ${styles.pendPay}`} onClick={() => handleOrderStatus('2')}>
<img src="/images/pendPay.png"></img>
<div>
<Badge count={statusSummaryMap[2]['count']} offset={[20, 8]} size="small" showZero>
<span>待付款</span>
</Badge>
</div>
</div>
<div className={`${styles.statusItem} ${styles.pendDiliver}`} onClick={() => handleOrderStatus('3')}>
<img src="/images/pendDiliver.png"></img>
<div>
<Badge count={statusSummaryMap[3]['count']} offset={[20, 8]} size="small" showZero>
<span>待发货</span>
</Badge>
</div>
</div>
<div className={`${styles.statusItem} ${styles.completed}`} onClick={() => handleOrderStatus('4')}>
<img src="/images/completed.png"></img>
<div>
<Badge count={statusSummaryMap[4]['count']} offset={[20, 8]} size="small" showZero>
<span>已完成</span>
</Badge>
</div>
</div>
</div>
{
goodsList.map((goodItem:any,index:number) => {
return (
index<=2&&
<div key={goodItem.order_id}>
<div className={styles.orderTitle} onClick={() => router.push(`/orderDetail?order_id=${goodItem.order_id}`)}>
订单号:{goodItem.order_sn}
</div>
<Table<DataType>
size="small"
bordered={true}
pagination={false}
columns={columns}
rowKey={(record) => record?.rec_id}
expandable={{
expandIcon: (r) => null,
defaultExpandAllRows: true,
expandedRowRender: (record) => {
return (
<div style={{ fontSize: '12px' }}>
<span style={{ marginRight: '20px' }}>最新进度:{record.latest_log_time}</span>
<span style={{ marginRight: '20px' }}>状态:{record.latest_log_status_text}</span>
<span style={{ marginRight: '20px' }}>{record.latest_log}</span>
</div>
)
},
rowExpandable: (record) => record.name !== 'Not Expandable',
}}
dataSource={goodItem.order_items}
/>
</div>
)
})
}
{/* <div className={styles.pagination}>
<Pagination
size="small"
showQuickJumper
showSizeChanger
hideOnSinglePage={true}
current={current}
pageSize={pageSize}
pageSizeOptions={[5, 10]}
total={total}
showTotal={(total) => `共 ${total} 条记录`}
onChange={handlePageChange}/>
</div> */}
</div>
<div>
<div className={styles.infoBox}>
<div className={styles.baseTitle}>我的信息</div>
<div className={styles.moreButton}>
查看全部
<span style={{marginLeft: '5px'}}>{'>'}</span>
</div>
<div className={styles.messageTable}>
{/* <Table<DataType>
showHeader={false}
bordered={true}
pagination={false}
columns={columns}
dataSource={data}
/> */}
</div>
</div>
{/* <div className={styles.basicBox}><div className={styles.baseTitle}>我的收藏</div></div>
<div className={styles.basicBox}><div className={styles.baseTitle}>我的优惠券</div></div> */}
</div>
</div>
</div>
</>
)
}
export default CenterHome
\ No newline at end of file
.centerBox{width:1022px;margin-left:12px;box-sizing:border-box}.centerBox .baseTitle{font-size:16px;color:#808080}.centerBox .headImgBox{cursor:pointer;width:130px;height:130px;border:1px solid #E0E0E0;margin:20px 30px;position:relative}.centerBox .headImgBox .headImgUptext{width:110px;height:110px;line-height:110px;text-align:center;background:rgba(83,83,83,0.75);border:1px solid #E0E0E0;position:absolute;left:10px;top:10px;color:#fff;font-size:12px;display:none;border-radius:110px}.centerBox .headImgBox:hover .headImgUptext{display:block}.centerBox .contentBox{width:100%;height:calc(100% - 60px);display:flex}.centerBox .basicBox{width:100%;height:226px;padding:20px 15px;background-color:#fff;box-sizing:border-box;position:relative}.centerBox .basicBox .headImg{width:130px;height:130px}.centerBox .basicBox .editButton{width:75px;height:20px;background:#FFFFFF;border-radius:1px;border:1px solid #B0B0B0;font-size:12px;color:#595959;cursor:pointer;margin-left:12px}.centerBox .basicBox .editButton:hover{color:#000000}.centerBox .basicBox .detailLines{margin-top:20px;font-size:14px;width:calc(100% - 150px)}.centerBox .basicBox .detailLines .lineItem{width:calc(50% - 5px);display:inline-block;margin-bottom:15px;color:#000}.centerBox .basicBox .detailLines .lineItem:nth-child(odd){margin-right:10px}.centerBox .basicBox .detailLines .linkItemone{color:#000;cursor:pointer;font-weight:bold}.centerBox .basicBox .detailLines .linkItemone:hover{color:#FF9A00}.centerBox .basicBox .myService{position:absolute;right:15px;top:15px;color:#808080;font-size:12px;cursor:pointer}.centerBox .basicBox .myService span{position:relative;top:-6px}.centerBox .basicBox .myService:hover span{color:#FF9A00}.centerBox .basicBox .myService img{margin-right:3px}.centerBox .bottomBox{display:flex;margin-top:10px}.centerBox .bottomBox .orderBox{width:660px;padding:30px 15px 100px;background-color:#fff;box-sizing:border-box;position:relative}.centerBox .bottomBox .orderBox :global .ant-table-container{border-top:0px !important}.centerBox .bottomBox .orderBox .statusBox{width:100%;height:114px;display:flex;box-sizing:border-box;margin-top:30px;margin-left:25px}.centerBox .bottomBox .orderBox .statusBox .statusItem{width:106px;height:100%;border-radius:18px;margin-right:20px;padding:15px;box-sizing:border-box;cursor:pointer}.centerBox .bottomBox .orderBox .statusBox .pendPreview{background:linear-gradient(348deg, #F4F5F8 0%, #F3F8FF 100%)}.centerBox .bottomBox .orderBox .statusBox .pendPay{background:linear-gradient(348deg, #FFF0EE 0%, #FBF8F6 100%)}.centerBox .bottomBox .orderBox .statusBox .pendDiliver{background:linear-gradient(348deg, #F9F4FC 0%, #FDF8FF 100%)}.centerBox .bottomBox .orderBox .statusBox .completed{background:linear-gradient(348deg, #F4F5F8 0%, #F3F8FF 100%)}.centerBox .bottomBox .orderBox .orderTitle{height:32px;line-height:20px;font-weight:bold;font-size:14px;color:#313131;text-decoration-line:underline;margin-top:25px;cursor:pointer}.centerBox .bottomBox .orderBox .orderTitle::after{content:"";display:block;width:100%;height:1px;margin-top:10px;background-color:#F4F4F4}.centerBox .bottomBox .infoBox{width:354px;padding:30px 15px;background-color:#fff;box-sizing:border-box;position:relative;margin-left:10px}.centerBox .bottomBox .infoBox .messageTable{margin-top:20px}.centerBox .bottomBox .moreButton{position:absolute;right:10px;top:30px;color:#888888;cursor:pointer}.centerBox .bottomBox .moreButton:hover{color:#FF9A00}.centerBox .pagination{position:absolute;right:30px;bottom:30px}
.centerBox {
width: 1022px;
margin-left: 12px;
box-sizing: border-box;
.baseTitle {
font-size: 16px;
color: #808080;
}
.headImgBox{
cursor: pointer;
width: 130px;
height: 130px;
border: 1px solid #E0E0E0;
margin: 20px 30px;
position: relative;
.headImgUptext{
width: 110px;
height: 110px;
line-height: 110px;
text-align: center;
background: rgba(83,83,83,0.75);
border: 1px solid #E0E0E0;
position: absolute;
left:10px;
top:10px;
color:#fff;
font-size: 12px;
display: none;
border-radius: 110px;
}
&:hover{
.headImgUptext{display: block;}
}
}
.contentBox {
width: 100%;
height: calc(100% - 60px);
display: flex;
}
.basicBox {
width: 100%;
height: 226px;
padding: 20px 15px;
background-color: #fff;
box-sizing: border-box;
position: relative;
.headImg {
width: 130px;
height: 130px;
}
.editButton {
width: 75px;
height: 20px;
background: #FFFFFF;
border-radius: 1px;
border: 1px solid #B0B0B0;
font-size: 12px;
color: #595959;
cursor: pointer;
margin-left:12px;
&:hover {
color: #000000;
}
}
.detailLines {
margin-top: 20px;
font-size: 14px;
width: calc(100% - 150px);
.lineItem {
width: calc(50% - 5px);
display: inline-block;
margin-bottom: 15px;
color:#000;
&:nth-child(odd) {
margin-right: 10px;
}
}
.linkItemone{
color:#000;
cursor: pointer;
font-weight: bold;
&:hover{
color:#FF9A00;
}
}
}
.myService {
position: absolute;
right: 15px;
top: 15px;
color: #808080;
font-size: 12px;
cursor: pointer;
span{
position: relative;
top:-6px;
}
&:hover{
span{
color:#FF9A00;
}
}
img{
margin-right: 3px;
}
}
}
.bottomBox{
display: flex;
margin-top: 10px;
.orderBox {
width: 660px;
padding: 30px 15px 100px;
background-color: #fff;
box-sizing: border-box;
position: relative;
:global {
.ant-table-container{
border-top:0px!important;
}
}
.statusBox {
width: 100%;
height: 114px;
display: flex;
box-sizing: border-box;
margin-top: 30px;
margin-left: 25px;
.statusItem {
width: 106px;
height: 100%;
border-radius: 18px;
margin-right: 20px;
padding: 15px;
box-sizing: border-box;
cursor: pointer;
}
.pendPreview {
background: linear-gradient( 348deg, #F4F5F8 0%, #F3F8FF 100%);
}
.pendPay {
background: linear-gradient( 348deg, #FFF0EE 0%, #FBF8F6 100%);
}
.pendDiliver {
background: linear-gradient( 348deg, #F9F4FC 0%, #FDF8FF 100%);
}
.completed {
background: linear-gradient( 348deg, #F4F5F8 0%, #F3F8FF 100%);
}
}
.orderTitle {
height: 32px;
line-height: 20px;
font-weight: bold;
font-size: 14px;
color: #313131;
text-decoration-line: underline;
margin-top: 25px;
cursor: pointer;
&::after {
content: "";
display: block;
width: 100%;
height: 1px;
margin-top: 10px;
background-color: #F4F4F4;
}
}
}
.infoBox {
width: 354px;
padding: 30px 15px;
background-color: #fff;
box-sizing: border-box;
position: relative;
margin-left: 10px;
.messageTable {
margin-top: 20px;
}
}
.moreButton {
position: absolute;
right: 10px;
top: 30px;
color: #888888;
cursor: pointer;
&:hover{
color:#FF9A00;
}
}
}
.pagination {
position: absolute;
right: 30px;
bottom: 30px;
}
}
\ No newline at end of file
.userCenter {
padding: 10px;
width: 1226px;
margin: 0 auto;
display: flex;
}
\ No newline at end of file
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import Nav from "@/components/navigation";
import style from './index.module.scss'
import { GetServerSideProps } from 'next';
import { getCateList } from "@/server/getCateList";
import CenterHome from './centerHome/centerHome'
import type {ResponseTypeCateList} from '@/components/Header/components/NavBig/types'
export const getStaticProps: GetServerSideProps = async () => {
return getCateList()
}
const Page = (props:{cateList:ResponseTypeCateList}) => {
const {cateList}=props
return (
<>
<Header {...cateList}/>
<div className={style.userCenter}>
<Nav></Nav>
<CenterHome/>
</div>
<Footer />
</>
)
}
export default Page
\ No newline at end of file
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import HomeFloor1 from './index/components/HomeFloor1';
import HomeFloor2 from './index/components/HomeFloor2';
import HomeFloor3 from './index/components/HomeFloor3';
import HomeBanner from './index/components/HomeBanner';
import { GetServerSideProps } from 'next';
import { getHomeData } from "../server/getHomeData";
import type {ResponseTypeCateList} from '@/components/Header/components/NavBig/types'
import type {ResponseTypeHome} from '@/types/indexTypes'
const Page=(props:{cateList:ResponseTypeCateList,homepageList:ResponseTypeHome})=>{
const {cateList,homepageList}=props
return (
<main>
<Header {...cateList} />
<div className='indexPage'>
<div className='mvHomePage'>
<HomeBanner />
<HomeFloor1 {...homepageList!}/>
<HomeFloor2 {...homepageList!}/>
<HomeFloor3 {...homepageList!}/>
</div>
</div>
<Footer/>
</main>
);
}
//pro
export const getServerSideProps: GetServerSideProps = async () => {
return getHomeData()
}
export default Page
\ No newline at end of file
import styles from '../index.module.scss'
import { Swiper, SwiperSlide } from 'swiper/react';
import { Autoplay, Pagination } from 'swiper/modules';
import 'swiper/css';
import 'swiper/css/pagination';
import Image from 'next/image';
const HomeBanner = () => {
const bannerList = [
{
title: '麒麟电子商城',
url: '/',
image: 'https://img.ichunt.com/images/cms/202407/23/bf5066643b4ea643b8384999f6a98215.jpg',
},
{
title: '麒麟电子商城',
url: '/',
image: 'https://img.ichunt.com/images/cms/202407/23/7e700a9a1b4b2066738fce110d22f8d7.jpg',
},
]
return (
<>
<div className={`${styles.banneBox} w1226 boxsiz`}>
<div className={styles.swipers}>
<Swiper
modules={[Pagination, Autoplay]}
spaceBetween={50}
slidesPerView={1}
pagination={{ clickable: true, }}
autoplay={{ delay: 2500 }}
>
{
bannerList.map((item, index) => {
return (
<SwiperSlide key={index}>
<a href={item.url} key={index + item.title}>
<img src={item.image} alt={item.title} />
</a>
</SwiperSlide>
)
})
}
</Swiper>
</div>
</div>
</>
)
}
export default HomeBanner
\ No newline at end of file
import styles from '../index.module.scss'
import Link from 'next/link';
import type { ResponseTypeHome } from '@/types/indexTypes';
const HomeFloor1 = (props: ResponseTypeHome) => {
const on_sale_list = props!.data?.on_sale_list || []
return (
<>
<div className={`${styles.floor1} w1226 bothSide`}>
<div className={`${styles.cons} row bothSide`}>
{
on_sale_list.map(item => {
return (
<Link href={`/item/${item.sku_id}.html`} key={item.sku_id} className={`${styles.item} boxsiz row bothSide`}>
<img src={item.goods_images || '/images/default.jpg'} alt="" />
<div className={`${styles.rt} boxsiz `}>
<div className={styles.gos}>{item.sku_name}</div>
<div className={styles.nam}>{item.brand_name}</div>
<div className={styles.prs}>¥{item.single_price}</div>
</div>
</Link>
)
})
}
</div>
<Link href='/' className={styles.floor1ad}>
<img src="https://img.ichunt.com/images/cms/202407/23/3f69491bab8057ee2411eb09c0fb4f39.jpg" alt="" />
</Link>
</div>
</>
)
}
export default HomeFloor1
\ No newline at end of file
import Link from 'next/link';
import styles from '../index.module.scss'
import type { ResponseTypeHome } from '@/types/indexTypes';
const HomeFloor2 = (props: ResponseTypeHome) => {
const recommend_goods_list = props!.data?.recommend_goods_list || []
return (
<>
<div className={`${styles.floor2} w1226 boxsiz`}>
<div className={`${styles.title} row bothSide verCenter`}>
<span>力推型号</span>
{/* <Link to='/' className="more">更多<i className="icon iconfont icon-xiangyou1"></i></Link> */}
</div>
<div className={`${styles.itembox} row boxsiz bothSide`}>
{
recommend_goods_list.map(item => {
return (
<Link href={`/item/${item.sku_id}.html`} className={`${styles.item} boxsiz`} key={item.sku_id}>
<img src={item.goods_images || '/images/default1.jpg'} alt="" />
<div className={styles.gos}>{item.sku_name}</div>
<div className='row bothSide'>
<div className={styles.nam}>{item.brand_name}</div>
<div className={styles.prs}>¥{item.single_price}</div>
</div>
</Link>
)
})
}
</div>
</div>
</>
)
}
export default HomeFloor2
\ No newline at end of file
import Link from 'next/link';
import styles from '../index.module.scss'
import type { ResponseTypeHome } from '@/types/indexTypes';
const HomeFloor3 = (props: ResponseTypeHome) => {
const recommend_brand_list = props!.data?.recommend_brand_list || []
return (
<>
<div className={`${styles.floor3} boxsiz w1226`}>
<div className={`${styles.title} row bothSide verCenter`}>
<span>推荐品牌</span>
<Link href='/brands.html' className={styles.more}>更多<i className="icon iconfont icon-xiangyou1"></i></Link>
</div>
<div className={`${styles.itembox} row bothSide boxsiz`}>
{
recommend_brand_list.map(item => {
return (
<Link href={`/brand/${item.goods_brand_id}.html`} className={styles.item} key={item.goods_brand_id}>
<img src={item.brand_logo} alt="" />
</Link>
)
})
}
</div>
</div>
</>
)
}
export default HomeFloor3
\ No newline at end of file
.banneBox{padding-left:234px}.banneBox .swipers{height:460px;background:#ccc}.banneBox .swipers img{height:460px;width:992px}.banneBox .swipers .slick-dots{justify-content:end;bottom:17px;right:10px;left:auto}.banneBox .swipers .slick-dots li{width:6px;height:6px;border:1px solid #FFFFFF;border-radius:6px}.banneBox .swipers .slick-dots li.slick-active,.banneBox .swipers .slick-dots li:hover{background:#FFFFFF}.floor1{margin-top:20px}.floor1 .cons{height:252px}.floor1 .item{width:398px;height:252px;background:linear-gradient(155deg, #F6F6F6 0%, #E9F6FC 100%);border:1px solid #EDEFEF;cursor:pointer;transition:all 0.5s;padding:35px 20px}.floor1 .item:hover{box-shadow:4px 6px 7px 1px rgba(154,151,149,0.18);transform:translateY(-1px)}.floor1 .item:first-child{background:linear-gradient(155deg, #F6F6F6 0%, #FCF5E9 100%)}.floor1 .item:last-child{background:linear-gradient(147deg, #F6F6F6 0%, #FCE9E9 100%)}.floor1 .item img{width:182px;height:182px}.floor1 .item .rt{width:158px;height:182px;padding:20px 0}.floor1 .item .rt .gos{font-size:14px;color:#000000;line-height:25px;word-break:break-all;text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;height:50px;margin-bottom:40px}.floor1 .item .rt .nam{font-weight:normal;font-size:16px;color:#000000;line-height:18px;text-overflow:ellipsis;overflow:hidden;height:18px}.floor1 .item .rt .prs{font-size:16px;color:#FF0006;line-height:18px;margin-top:12px}.floor1 .floor1ad{display:block;height:118px;margin-top:20px}.floor1 .floor1ad img{width:1226px;height:118px}.floor2{margin-top:50px}.floor2 .title{margin-bottom:30px}.floor2 .title span{font-size:24px;color:#000000;line-height:31px}.floor2 .title .more{font-size:16px;color:#888888}.floor2 .title .more:hover{color:#FF9A00}.floor2 .itembox{flex-wrap:wrap}.floor2 .itembox .item{padding:34px 18px;width:233px;height:330px;background:#FFFFFF;transition:all 0.5s;margin-bottom:10px}.floor2 .itembox .item:hover{box-shadow:4px 6px 7px 1px rgba(154,151,149,0.18);transform:translateY(-1px)}.floor2 .itembox .item img{width:150px;height:109px;display:block;margin:0 auto;margin-bottom:60px}.floor2 .itembox .item .gos{font-size:14px;color:#000000;line-height:25px;word-break:break-all;text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;height:50px;margin-bottom:30px}.floor2 .itembox .item .nam{font-weight:normal;font-size:16px;color:#000000;line-height:18px;text-overflow:ellipsis;overflow:hidden;height:18px;max-width:110px}.floor2 .itembox .item .prs{font-size:16px;color:#FF0006;line-height:18px}.floor3{margin-top:50px;margin-bottom:65px}.floor3 .title{margin-bottom:30px}.floor3 .title span{font-size:24px;color:#000000;line-height:31px}.floor3 .title .more{font-size:16px;color:#888888}.floor3 .title .more:hover{color:#FF9A00}.floor3 .itembox{flex-wrap:wrap}.floor3 .itembox .item{width:233px;height:80px;transition:all 0.5s;margin-bottom:15px;background:#fff}.floor3 .itembox .item:hover{box-shadow:4px 6px 7px 1px rgba(154,151,149,0.18);transform:translateY(-1px)}.floor3 .itembox .item img{width:233px;height:80px;object-fit:contain;transform:scale(0.8)}
.banneBox{
padding-left: 234px;
.swipers{
height:460px;
background: #ccc;
img{
height:460px;
width:992px;
}
.slick-dots{
justify-content: end;
bottom:17px;
right:10px;
left:auto;
li{
width: 6px;
height: 6px;
border: 1px solid #FFFFFF;
border-radius: 6px;
&.slick-active,&:hover{
background: #FFFFFF;
}
}
}
}
}
.floor1{
margin-top: 20px;
.cons{
height:252px;
}
.item{
width: 398px;
height: 252px;
background: linear-gradient( 155deg, #F6F6F6 0%, #E9F6FC 100%);
border: 1px solid #EDEFEF;
cursor: pointer;
transition: all 0.5s;
&:hover{
box-shadow: 4px 6px 7px 1px rgba(154,151,149,0.18);
transform: translateY(-1px);
}
&:first-child{
background: linear-gradient( 155deg, #F6F6F6 0%, #FCF5E9 100%);
}
&:last-child{
background: linear-gradient( 147deg, #F6F6F6 0%, #FCE9E9 100%);
}
padding:35px 20px;
img{
width:182px;
height:182px;
}
.rt{
width:158px;
height:182px;
padding:20px 0;
.gos{
font-size: 14px;
color: #000000;
line-height: 25px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
height:50px;
margin-bottom: 40px;
}
.nam{
font-weight: normal;
font-size: 16px;
color: #000000;
line-height: 18px;
text-overflow: ellipsis;
overflow: hidden;
height:18px;
}
.prs{
font-size: 16px;
color: #FF0006;
line-height: 18px;
margin-top: 12px;
}
}
}
.floor1ad{
display: block;
height: 118px;
margin-top: 20px;
img{
width:1226px;
height: 118px;
}
}
}
.floor2{
margin-top: 50px;
.title{
margin-bottom: 30px;
span{
font-size: 24px;
color: #000000;
line-height: 31px;
}
.more{
font-size: 16px;
color: #888888;
&:hover{
color:#FF9A00;
}
}
}
.itembox{
flex-wrap: wrap;
.item{
padding: 34px 18px;
width: 233px;
height: 330px;
background: #FFFFFF;
transition: all 0.5s;
margin-bottom: 10px;
&:hover{
box-shadow: 4px 6px 7px 1px rgba(154,151,149,0.18);
transform: translateY(-1px);
}
img{
width: 150px;
height: 109px;
display: block;
margin: 0 auto;
margin-bottom: 60px;
}
.gos{
font-size: 14px;
color: #000000;
line-height: 25px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
height:50px;
margin-bottom: 30px;
}
.nam{
font-weight: normal;
font-size: 16px;
color: #000000;
line-height: 18px;
text-overflow: ellipsis;
overflow: hidden;
height:18px;
max-width: 110px;
}
.prs{
font-size: 16px;
color: #FF0006;
line-height: 18px;
}
}
}
}
.floor3{
margin-top: 50px;
margin-bottom: 65px;
.title{
margin-bottom: 30px;
span{
font-size: 24px;
color: #000000;
line-height: 31px;
}
.more{
font-size: 16px;
color: #888888;
&:hover{
color:#FF9A00;
}
}
}
.itembox{
flex-wrap: wrap;
.item{
width: 233px;
height: 80px;
transition: all 0.5s;
margin-bottom: 15px;
background: #fff;
&:hover{
box-shadow: 4px 6px 7px 1px rgba(154,151,149,0.18);
transform: translateY(-1px);
}
img{
width: 233px;
height: 80px;
object-fit: contain;
transform: scale(0.8);
}
}
}
}
\ No newline at end of file
.invoiceBox{width:1022px;margin-left:12px;box-sizing:border-box;background:#fff;padding:20px 30px 100px;position:relative}.invoiceBox .invoiceTitle{font-size:16px;height:32px;color:#1A1A1A;line-height:21px;width:100%;border-bottom:1px solid #F4F4F4}.invoiceBox .invoiceButton{left:120px;top:18px;position:absolute;width:80px;height:26px;background:#FFFFFF;border-radius:1px;color:#FF9A00;border:1px solid #FF9A00;cursor:pointer}.invoiceBox .invoiceButton:hover{color:#fff;background-color:#FF9A00}.invoiceBox .invoiceItem{padding-top:20px;padding-bottom:5px;box-sizing:border-box;border-bottom:1px solid #F4F4F4}.invoiceBox .invoiceItem .invoiceStatus{width:100%;height:20px;display:flex;line-height:20px;text-align:center;justify-content:space-between}.invoiceBox .invoiceItem .invoiceStatus .invoiceCheck{display:flex;align-items:center}.invoiceBox .invoiceItem .invoiceStatus .invoiceCheck input{cursor:pointer;margin-right:8px}.invoiceBox .invoiceItem .invoiceStatus .rightPart{display:flex;align-items:center}.invoiceBox .invoiceItem .invoiceStatus .rightPart .invoiceimg{display:inline-flex;align-items:center}.invoiceBox .invoiceItem .invoiceStatus .rightPart .invoiceimg img{margin-right:5px}.invoiceBox .invoiceItem .invoiceStatus .rightPart .invalid{width:60px;height:20px;font-size:12px;color:#D0121B;background:#FDF5F5;border-radius:1px;margin-left:25px;border:1px solid #D0121B;cursor:pointer}.invoiceBox .invoiceItem .invoiceStatus .rightPart .invalid:hover{color:#fff;background-color:#D0121B}.invoiceBox .invoiceItem .invoiceDetail{margin-top:20px;font-size:14px;width:100%}.invoiceBox .invoiceItem .invoiceDetail .lineItem{width:calc(50% - 50px);display:inline-block;margin-bottom:15px;margin-left:50px}.invoiceBox .invoiceItem .invoiceDetail .lineItem .itemTitle{display:inline-block;width:90px;text-align:right;margin-right:20px}.invoiceBox .pagination{position:absolute;right:30px;bottom:30px}.modalContent{padding:45px 0;box-sizing:border-box}.modalContent :global .ant-form-item{margin-bottom:20px}.radioBox{padding-top:15px;padding-bottom:40px}.modalFooter{width:100%;display:flex;margin-top:40px;padding-bottom:25px;justify-content:space-around}.modalFooter .saveButton{width:195px;height:45px;color:#fff;background:#FF9A00;border-radius:1px;cursor:pointer}.modalFooter .cancelButton{width:195px;height:45px;color:#FF9A00;background:#fff;border-radius:1px;cursor:pointer;border:1px solid #FF9A00}
.invoiceBox {
width: 1022px;
margin-left: 12px;
box-sizing: border-box;
background: #fff;
padding: 20px 30px 100px;
position: relative;
.invoiceTitle {
font-size: 16px;
height: 32px;
color: #1A1A1A;
line-height: 21px;
width: 100%;
border-bottom: 1px solid #F4F4F4;
}
.invoiceButton {
left: 120px;
top: 18px;
position: absolute;
width: 80px;
height: 26px;
background: #FFFFFF;
border-radius: 1px;
color: #FF9A00;
border: 1px solid #FF9A00;
cursor: pointer;
&:hover {
color: #fff;
background-color: #FF9A00;
}
}
.invoiceItem {
//height: 240px;
padding-top: 20px;
padding-bottom: 5px;
box-sizing: border-box;
border-bottom: 1px solid #F4F4F4;
.invoiceStatus {
width: 100%;
height: 20px;
display: flex;
line-height: 20px;
text-align: center;
justify-content: space-between;
.invoiceCheck {
display: flex;
align-items: center;
input {
cursor: pointer;
margin-right: 8px;
}
}
.rightPart {
display: flex;
align-items: center;
.invoiceimg {
display: inline-flex;
align-items: center;
img {
margin-right: 5px;
}
}
.invalid {
width: 60px;
height: 20px;
font-size: 12px;
color: #D0121B;
background: #FDF5F5;
border-radius: 1px;
margin-left: 25px;
border: 1px solid #D0121B;
cursor: pointer;
&:hover {
color: #fff;
background-color: #D0121B;
}
}
}
}
.invoiceDetail {
margin-top: 20px;
font-size: 14px;
width: 100%;
.lineItem {
width: calc(50% - 50px);
display: inline-block;
margin-bottom: 15px;
margin-left: 50px;
.itemTitle {
display: inline-block;
width: 90px;
text-align: right;
margin-right: 20px;
}
}
}
}
.pagination {
position: absolute;
right: 30px;
bottom: 30px;
}
}
.modalContent {
padding: 45px 0;
box-sizing: border-box;
:global {
.ant-form-item {
margin-bottom:20px;
}
}
}
.radioBox{
padding-top:15px;
padding-bottom: 40px;
}
.modalFooter {
width: 100%;
display: flex;
margin-top: 40px;
padding-bottom: 25px;
justify-content: space-around;
.saveButton {
width: 195px;
height: 45px;
color: #fff;
background: #FF9A00;
border-radius: 1px;
cursor: pointer;
}
.cancelButton {
width: 195px;
height: 45px;
color: #FF9A00;
background: #fff;
border-radius: 1px;
cursor: pointer;
border: 1px solid #FF9A00;
}
}
\ No newline at end of file
import styles from './index.module.scss'
import {useState, useEffect} from 'react'
import { Radio , Modal, Form, Input, Pagination, message,Empty} from 'antd'
import useRequest from "@/hooks/useRequest"
const InvoiceTitleList = [
{
text: '发票类型',
key: 'invoice_type_cn',
type: [2, 3, 4]
},
{
text: '统一税务号',
key: 'tax_no',
type: [3, 4]
},
{
text: '发票抬头',
key: 'tax_title',
type: [2, 3, 4]
},
{
text: '银行账号',
key: 'bank_account',
type: [3]
},
{
text: '开户行',
key: 'bank_name',
type: [3]
},
{
text: '注册地址',
key: 'company_address',
type: [3]
},
{
text: '公司电话',
key: 'company_phone',
type: [3]
}
]
const InvoicePage = () => {
const [initstatus, setInitstatus] = useState(false);
const [modal, contextHolder1] = Modal.useModal();
const [open, setOpen] = useState(false)
const [value, setValue] = useState(3);
const [invoiceList, setInvoiceList] = useState<any>([]);
const [formData, setFormData] = useState<any>({});
const [current, setCurrent] = useState(1);
const [pageSize, setPageSize] = useState(5);
const [total, setTotal] = useState(0);
const [doSub, setDoSub] = useState(false);
const [isAdd, setIsAdd] = useState(false);
const [ form ] = Form.useForm()
const { request: userRequest } = useRequest<any>({ manual: true })
const [messageApi, contextHolder] = message.useMessage();
useEffect(() => {
handleDataInit()
}, [ pageSize, current])
useEffect(() => {
if (doSub) handleInvoiceSave()
}, [ doSub ])
const handleDataInit = async () => {
const invoiceListResponse = await userRequest({
url: `/api/userInfo/userInvoiceList?limit=${pageSize}&page=${current}`,
method: 'get'
})
if (invoiceListResponse.code === 0) {
setInitstatus(true)
setInvoiceList(invoiceListResponse.data.list)
setTotal(invoiceListResponse.data.list.length)
}
}
const handleInvoiceSave = async () => {
if(isAdd) formData['invoice_type' as keyof typeof formData] = value
const saveInvoiceResponse = await userRequest({
url: '/api/userInfo/saveInvoice',
method: 'post',
data: formData
})
if (saveInvoiceResponse.code === 0) {
if (isAdd) {
form.resetFields()
handleModal(false)
setValue(3)
}
setFormData(null)
handleDataInit()
messageApi.open({
type: 'success',
content: '操作成功!',
});
} else {
messageApi.open({
type: 'error',
content: saveInvoiceResponse.msg,
});
}
setIsAdd(false)
setDoSub(false)
}
const manualValidate = () => {
form.validateFields().then((value:any) => {
setFormData(value)
setIsAdd(true)
setDoSub(true)
}).catch((e) => {});
}
const onChange = (e: any) => {
form.resetFields()
setValue(e.target.value)
}
const handleModal = (show:boolean) => {
setOpen(show);
setFormData(null)
}
const handleInvoiceEdit = (data:any, key:string) => {
if(key=="is_del"){
modal.confirm({
title:"确认",
content:"确认要作废当前发票吗",
okText: '确认',
cancelText: '取消',
onOk() {
setIsAdd(false)
data[key] = 1
const editForm = {
web_user_invoice_id: data.web_user_invoice_id
}
editForm[key as keyof typeof editForm] = 1
setFormData(editForm)
setDoSub(true)
},
});
}else{
setIsAdd(false)
data[key] = 1
const editForm = {
web_user_invoice_id: data.web_user_invoice_id
}
editForm[key as keyof typeof editForm] = 1
setFormData(editForm)
setDoSub(true)
}
}
const validateMessages = {
required: '${label}不能为空!'
}
const handlePageChange = (page:number, pageSize:number) => {
setCurrent(page)
setPageSize(pageSize)
}
return (
<>
{contextHolder}
{contextHolder1}
<div className={styles.invoiceBox}>
<div className={styles.invoiceTitle}>我的发票</div>
<button className={styles.invoiceButton} onClick={() => handleModal(true)}>新增发票</button>
{
invoiceList.map((invoiceItem:any) => {
return (
<div className={styles.invoiceItem} key={invoiceItem.web_user_invoice_id}>
<div className={styles.invoiceStatus}>
<div className={styles.invoiceCheck}>
{/* { invoiceItem.is_default ? (<>默认发票</>) : (
<>
<input type="checkbox" onClick={() => handleInvoiceEdit(invoiceItem, 'is_default')}/>
设为默认
</>)
} */}
</div>
<div className={styles.rightPart}>
<div className={styles.invoiceimg}>
<img src="/images/success.png"></img>
{invoiceItem.audit_status_cn}
</div>
{ !invoiceItem.is_del && (
<>
<button className={styles.invalid} onClick={() => handleInvoiceEdit(invoiceItem, 'is_del')}>作废</button>
</>)
}
</div>
</div>
<div className={styles.invoiceDetail}>
{ InvoiceTitleList.map(invoiceTitleItem => {
if (invoiceTitleItem.type.includes(invoiceItem.invoice_type))
return (
<div className={styles.lineItem} key={invoiceTitleItem.key}>
<span className={styles.itemTitle}>{invoiceTitleItem.text}</span>
<span>{invoiceItem[invoiceTitleItem.key as keyof typeof invoiceItem]}</span>
</div>
)
})}
</div>
</div>
)
})
}
{invoiceList.length==0&&initstatus&&<Empty image='/images/empty.png' description="暂无发票" imageStyle={{width: '240px', margin: '100px auto 0'}} />}
<div className={styles.pagination}>
<Pagination
showQuickJumper
showSizeChanger
hideOnSinglePage={true}
current={current}
pageSize={pageSize}
pageSizeOptions={[5, 10]}
total={total}
showTotal={(total) => `共 ${total} 条记录`}
onChange={handlePageChange}/>
</div>
</div>
<Modal
title="发票类型:"
open={open}
destroyOnClose
footer={null}
closeIcon={null}
centered
onCancel={() => handleModal(false)}
>
<div className={`${styles.radioBox}`}>
<Radio.Group onChange={onChange} value={value}>
<Radio value={3}>增值税专用发票</Radio>
<Radio value={4}>增值税普通发票</Radio>
<Radio value={2}>个人发票</Radio>
</Radio.Group>
</div>
<Form
className={styles.modalContent}
validateMessages={validateMessages}
form={form}
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}>
{ InvoiceTitleList.map(invoiceTitleItem => {
if(invoiceTitleItem.key=="invoice_type_cn"){return}
if (invoiceTitleItem.type.includes(value))
return (
<Form.Item
className={styles.lineItem}
key={invoiceTitleItem.key}
label={invoiceTitleItem.text}
name={invoiceTitleItem.key}
rules={[{ required: true }]}>
<Input/>
</Form.Item>
)
})}
</Form>
<div className={styles.modalFooter}>
<button className={styles.saveButton} onClick={() => manualValidate()}>保存</button>
<button className={styles.cancelButton} onClick={() => handleModal(false)}>取消</button>
</div>
</Modal>
</>
)
}
export default InvoicePage
\ No newline at end of file
.userCenter {
padding: 10px;
width: 1226px;
margin: 0 auto;
display: flex;
}
\ No newline at end of file
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import Nav from "@/components/navigation";
import style from './index.module.scss'
import { GetServerSideProps } from 'next';
import { getCateList } from "@/server/getCateList";
import BasicData from './component/invoice'
import type {ResponseTypeCateList} from '@/components/Header/components/NavBig/types'
export const getStaticProps: GetServerSideProps = async () => {
return getCateList()
}
const Page = (props:{cateList:ResponseTypeCateList}) => {
const {cateList}=props
return (
<>
<Header {...cateList}/>
<div className={style.userCenter}>
<Nav></Nav>
<BasicData/>
</div>
<Footer />
</>
)
}
export default Page
\ No newline at end of file
import styles from './index.module.scss'
import DetailHead from './components/DetailHead';
import DetailSection from './components/DetailSection';
import BreadNav from '../../components/BreadNav';
import type { DetailResponseType,skuInfoResponseType } from '@/types/detailTypes'
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import { GetServerSideProps } from 'next';
import { getDetailData } from "@/server/getDetailData";
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
import Link from 'next/link';
export const getServerSideProps: GetServerSideProps = async (context) => {
const { query } = context;
return getDetailData(String(query.sku_id))
}
const Page = (props: { cateList: ResponseTypeCateList, detailInfoData: DetailResponseType }) => {
const detailData = props?.detailInfoData
const sku_info:skuInfoResponseType=detailData.data?.sku_info!
return (
<>
<main>
<Header {...props.cateList} />
<div className={styles.mvDetailPage}>
{
sku_info ?
<>
<BreadNav >
{
sku_info.goods_type_name &&
<>
<Link href={`/list/${sku_info.goods_type_id}`}>{sku_info.goods_type_name}</Link>
<i className="icon iconfont icon-xiangyou1"></i>
</>
}
{
sku_info.goods_type_name2 &&
<>
<Link href={`/list/${sku_info.goods_type_id}_${sku_info.goods_type_id2}`}>{sku_info.goods_type_name2}</Link>
<i className="icon iconfont icon-xiangyou1"></i>
</>
}
<strong>{sku_info?.sku_name||sku_info?.goods_name}</strong>
</BreadNav>
<DetailHead {...sku_info} />
<DetailSection {...detailData} />
</>
:
<>
{
<>
<BreadNav > <strong>找不到型号数据</strong></BreadNav>
<div className={`${styles.datanos} w1226`}>
<img src='/images/p404.png' alt="" />
</div>
</>
}
</>
}
</div>
<Footer />
</main>
</>
)
}
export default Page
\ No newline at end of file
import QqIcon from "@/components/QqIcon"
import type { skuInfoResponseType } from '@/types/detailTypes'
import styles from '../index.module.scss'
import { Checkbox } from "antd"
import { useQq } from "@/hooks/useQq"
import { useRef, useState } from "react"
import { useToast } from '@/hooks/useToast'
import useRequest from "@/hooks/useRequest"
import { useRouter } from 'next/router'
import { useCookies } from "@/hooks/useCookies"
const DetailHead = (props: skuInfoResponseType) => {
const router = useRouter()
const { QQURL,PHONE}=useQq()
const { message }=useToast()
const { getCookie,setCookie } = useCookies()
const sku_info_init =props!
const [sku_info, setItemInfo] = useState(sku_info_init)
const changeNumTimer = useRef<any>()
const [purNum, setPurNum] = useState<any>('')
const [seArea, setSeArea] = useState<any>('1')
const { request: userRequest } = useRequest<any>({ manual: true, loading: true })
const handlecheckBoxChange = (type:any) => setSeArea(type)
const handleAddCart = async (data: any) => {
if (!getCookie("userId")) {
window.location.href = '/login?type=1&backUrl=' + encodeURIComponent(window.location.href)
return
}
let goodPrice = ''
const priceList = JSON.parse(JSON.stringify(data?.ladder_price || []))
priceList.sort((a:any, b:any) => b.purchases - a.purchases).some((item:any) => {
if (item.purchases <= Number(purNum || 0)) {
goodPrice = (seArea === '1') ? item.price_cn : item.price_us
return true
}
})
if (!goodPrice || !purNum) return message("请输入正确购买数量!")
const param = {
goods_list: [
{
...JSON.parse(JSON.stringify(data)),
delivery_place_type: seArea,
goods_number: Number(purNum),
goods_price: goodPrice,
remark: ''
}
]
}
const res = await userRequest({
url: '/api/cart/cartAdd',
method: 'post',
data: param
})
if(res?.code === 0) {
message("加入购物车成功!")
const shopListResopnse = await userRequest({
url: '/api/cart/cartList',
method: 'post'
})
document.querySelector('#cartNumx')!.textContent = shopListResopnse.data.cart_list.length
}else {message(res?.msg || '操作失败!')}
}
const handleToSettle = () => {
if (!getCookie("userId")) {
window.location.href = '/login?type=1&backUrl=' + encodeURIComponent(window.location.href)
return
}
let goodPrice = ''
const priceList = JSON.parse(JSON.stringify(sku_info?.ladder_price || []))
priceList.sort((a:any, b:any) => b.purchases - a.purchases).some((item:any) => {
if (item.purchases <= Number(purNum || 0)) {
goodPrice = (seArea === '1') ? item.price_cn : item.price_us
return true
}
})
if (!goodPrice || !purNum) return message("请输入正确购买数量!")
if (sku_info.stock < Number(purNum || 0)) return message("该型号库存不足!")
router.push(`/orderSettle?sourceType=1&&id=${sku_info?.sku_id}&&deliveryPlaceType=${seArea}&&number=${purNum}`)
}
const onePriceRow = () => {
const priceList =sku_info.ladder_price||[]
if(priceList.length==0){return}
priceList!.forEach((item:any, index:number) => {
item.checked = false
var value_ = Number(purNum)
var pus = Number(item.purchases || 0)
var next_pus = 0
var prev_pus = 0
if(index!=0){
prev_pus = Number(priceList[index - 1].purchases)
}
if(index!=priceList.length - 1){
next_pus = Number(priceList[index + 1].purchases)
}
if (index == 0) {
if (value_ < pus) {
item.checked = true
return false
}
}
if (index == priceList.length - 1) {
if (value_ > pus) {
item.checked = true
return false
}
}
if (value_ == pus) {
item.checked = true
return false
}
if (value_ > pus && value_ < next_pus) {
item.checked = true
return false
}
if (value_ < pus && value_ > prev_pus) {
priceList[index - 1].checked = true
return false
}
})
}
onePriceRow()
const changeNum = (e: any, min: number, max: number, itemInfo: any) => {
clearTimeout(changeNumTimer.current)
setPurNum(Number(e.target.value))
changeNumTimer.current = setTimeout(() => {
if (Number(e.target.value) > max) {
message("购买数量不能大于库存!")
setPurNum(max)
return
}
if (Number(e.target.value) < min) {
message("购买数量不能小于起订量!")
setPurNum(min)
return
}
}, 1000)
}
return (
<>
<div className={`${styles.detailHeaders} w1226 row bothSide boxsiz`}>
<div className={`${styles.l} row`}>
<img src={sku_info.goods_images || '/images/default.jpg'} className={styles.goodsimg} alt="" />
<div className={styles.info}>
<div className={styles.box}>
<h1>{sku_info.sku_name}</h1>
<p> 品牌: {sku_info.brand_name}</p>
<p>商品类别:{sku_info.goods_type_name2||'--'}</p>
<p>封装规格:{sku_info.encap||'--'}</p>
<p>描述:{sku_info.remark||'--'}</p>
</div>
<div className={`${styles.handle} row bothSide verCenter`}>
<div className="row">
<QqIcon QQURL={QQURL}/>
<div className={`${styles.phonecons}`} >
<img src='/images/phonecom.png' alt='' />
<div>{PHONE}</div>
</div>
</div>
{!(sku_info.ladder_price?.length>0&&sku_info.stock>0) &&
<a href={QQURL} rel="noreferrer" className={styles.btn} target='_blank'>立即询价</a>
}
</div>
</div>
</div>
<div className={`${styles.r} boxsiz`}>
<p className='row'>
<span className={styles.items}>库存:{sku_info.stock} </span>
<span className={styles.items}>
<Checkbox checked={seArea === '2'} onChange={() => handlecheckBoxChange('2')} style={{marginRight: '10px'}}></Checkbox>
交期(HK): {sku_info.hk_delivery_time||'--'}</span>
</p>
<p className='row'>
<span className={`${styles.items} row`}><strong>批次:</strong> <strong dangerouslySetInnerHTML={{ __html: sku_info.batch_sn||'--' }}></strong></span>
<span className={styles.items}>
<Checkbox checked={seArea === '1'} onChange={() => handlecheckBoxChange('1')} style={{marginRight: '10px'}}></Checkbox>
交期(大陆): {sku_info.cn_delivery_time||'--'}
</span>
</p>
<p className={`row`}>
<span className={styles.items}> 起订量: {sku_info.moq}</span>
<span className={styles.items}>递增: {sku_info.multiple}</span>
</p>
{(sku_info.ladder_price?.length>0&&sku_info.stock>0) &&
<div className="row">
<span className={styles.items}>
<input className={styles.numInput} value={purNum||sku_info.moq} onChange={(e) => changeNum(e, Number(sku_info.moq), Number(sku_info.stock), sku_info)} placeholder="请输入数量"/>
</span>
<span className={styles.items}>
<button className={styles.btn} onClick={() => handleAddCart(sku_info)}>加入购物车</button>
<button className={styles.buyBtn} onClick={handleToSettle}>立即购买</button>
</span>
</div>
}
{
(sku_info.ladder_price||[]).map((item,index) => {
return (
<p className={`${styles.jtgroup} row ${item.checked ? styles.actjt : ''}`} key={index}>
<span className={styles.items}> {item.purchases||item.purchase}+</span>
<span className={`${styles.items} row`}>
{
(item.price_cn&&Number(item.price_cn)!==0)?<span>¥{item.price_cn||'--'}</span>:''
}
{
(item.price_us&&Number(item.price_us)!==0)?<span>${item.price_us||'--'}</span>:''
}
</span>
</p>
)
})
}
</div>
</div>
</>
)
}
export default DetailHead
\ No newline at end of file
import Link from 'next/link'
import type { DetailResponseType } from '@/types/detailTypes'
import styles from '../index.module.scss'
import { Empty } from 'antd'
const DetailSection = (props: DetailResponseType) => {
const attrs = props.data?.sku_info!.attrs || []
const other_sku_list = props!.data?.other_sku_list || []
const goods_details = props.data?.sku_info!.goods_details
return (
<>
<div className={`${styles.detailSection} w1226 row bothSide`}>
<div className={`${styles.secl} boxsiz`}>
{
attrs.length > 0 &&
<div className={`${styles.lilistBox} row`}>
{
attrs.map((item, index) => {
return (
<p key={item.name + index}>
<b>{item.name}</b>
<span className={styles.ple0}>
<span>{item.value}</span>
</span>
</p>
)
})
}
{attrs.length % 2 === 1 &&
<p >
<b></b>
<span className={styles.ple0}>
<span></span>
</span>
</p>
}
</div>
}
{
goods_details ?
<div className={`${styles.goodsMask} row`}>
<div>介绍:</div>
<h4 >{goods_details}</h4>
</div> :
<Empty image='/images/emptyorder.png' description="数据为空!" imageStyle={{height: '183px', margin: '30px auto 0'}} />
}
</div>
<div className={styles.secr}>
{
other_sku_list.map(item => {
return (
<Link href={`/item/${item.sku_id}.html`} className={`${styles.item} boxsiz`} key={item.sku_id}>
<img src={item.goods_images || '/images/default.jpg'} alt="" />
<div className={styles.gos}>{item.sku_name}</div>
<div className='row bothSide'>
<div className={styles.nam}>{item.brand_name}</div>
<div className={styles.prs}>¥{item.single_price}</div>
</div>
</Link>
)
})
}
</div>
</div>
</>
)
}
export default DetailSection
\ No newline at end of file
.mvDetailPage{margin-bottom:47px;min-height:500px}.mvDetailPage .detailHeaders{min-height:304px;padding:40px 35px;background:#fff}.mvDetailPage .detailHeaders .goodsimg{width:222px;height:222px;margin-right:20px}.mvDetailPage .detailHeaders .actjt span{color:#FF9A00 !important}.mvDetailPage .detailHeaders .info .box{height:192px;width:420px}.mvDetailPage .detailHeaders .info .box h1{font-weight:bold;font-size:18px;color:#313131;line-height:24px;margin-bottom:12px}.mvDetailPage .detailHeaders .info .box p{font-size:12px;color:#000000;line-height:25px;max-height:50px;word-break:break-all;text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.mvDetailPage .detailHeaders .info .handle .phonecons{position:relative;cursor:pointer;margin-left:10px}.mvDetailPage .detailHeaders .info .handle .phonecons img{width:25px;height:25px}.mvDetailPage .detailHeaders .info .handle .phonecons div{position:absolute;background:#fff;top:28px;left:0px;border:1px solid #FF9A00;padding:4px 6px;border-radius:3px;display:none}.mvDetailPage .detailHeaders .info .handle .phonecons:hover div{display:block}.mvDetailPage .detailHeaders .btn{width:80px;height:30px;background:#FF9A00;line-height:30px;text-align:center;color:#fff;cursor:pointer}.mvDetailPage .detailHeaders .btn:hover{background:#E18800}.mvDetailPage .detailHeaders .r{width:452px;min-height:222px;background:#FFFCF8;padding:10px 30px}.mvDetailPage .detailHeaders .r .mb23{margin-bottom:24px}.mvDetailPage .detailHeaders .r .items{width:50%;font-size:12px;color:#000000;line-height:25px}.mvDetailPage .detailHeaders .r .items>span{width:50%}.mvDetailPage .detailHeaders .r .numInput{width:80px;height:30px;text-align:center;background:#FFFFFF;border:1px solid #999999;cursor:pointer;margin-top:10px}.mvDetailPage .detailHeaders .r .buyBtn{width:80px;height:30px;color:#FF9A00;margin-left:10px;background:#FFFFFF;border:1px solid #FF9A00;cursor:pointer;margin-top:10px;margin-bottom:15px}.mvDetailPage .detailHeaders .r .buyBtn:hover{background:#FFF7EC}.mvDetailPage .detailSection{margin-top:20px}.mvDetailPage .detailSection .secl{width:978px;min-height:330px;background:#FFFFFF;padding:30px}.mvDetailPage .detailSection .secl .lilistBox{border-top:1px solid #e5e5e5;font-size:14px;color:#313131;flex-shrink:0;flex-wrap:wrap;border-left:1px solid #e5e5e5}.mvDetailPage .detailSection .secl .lilistBox p{line-height:36px;width:50%;box-sizing:border-box;height:36px;border-right:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mvDetailPage .detailSection .secl .lilistBox p b{width:130px;float:left;display:block;border-right:1px solid #e5e5e5;padding-left:20px;background:#F5F5F5;margin-right:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mvDetailPage .detailSection .secl .lilistBox p span{padding-left:10px}.mvDetailPage .detailSection .secl .lilistBox p .ple0 span{padding-left:0px !important}.mvDetailPage .detailSection .secl .goodsMask{height:60px;line-height:30px;color:#313131;font-size:14px}.mvDetailPage .detailSection .secl .goodsMask div{width:130px;float:left;border-right:1px solid #e5e5e5;border-left:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;padding-left:20px;background:#F5F5F5;height:90px}.mvDetailPage .detailSection .secl .goodsMask h4{background:#fff;width:745px;height:90px;padding-left:10px;padding-right:10px;border-right:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;word-break:break-all;text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.mvDetailPage .detailSection .secr .item{padding:34px 18px;width:233px;height:330px;transition:all 0.5s;background:#fff;display:block;margin-bottom:20px}.mvDetailPage .detailSection .secr .item:last-child{margin-bottom:0px}.mvDetailPage .detailSection .secr .item:hover{box-shadow:4px 6px 7px 1px rgba(154,151,149,0.18);transform:translateY(-1px)}.mvDetailPage .detailSection .secr .item img{width:150px;height:109px;display:block;margin:0 auto;margin-bottom:60px}.mvDetailPage .detailSection .secr .item .gos{font-size:14px;color:#000000;line-height:25px;word-break:break-all;text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;height:50px;margin-bottom:30px}.mvDetailPage .detailSection .secr .item .nam{font-weight:normal;font-size:16px;color:#000000;line-height:18px;text-overflow:ellipsis;overflow:hidden;height:18px;max-width:110px}.mvDetailPage .detailSection .secr .item .prs{font-size:16px;color:#FF0006;line-height:18px}.mvDetailPage .datanos{background:#fff;padding:80px 0}.mvDetailPage .datanos img{height:296px;width:360px;display:block;margin:0 auto}
.mvDetailPage{
margin-bottom: 47px;
min-height: 500px;
.detailHeaders{
min-height: 304px;
padding:40px 35px;
background: #fff;
.goodsimg{
width:222px;
height:222px;
margin-right: 20px;
}
.actjt{
span{
color:#FF9A00!important;
}
}
.info{
.box{
height:192px;
width: 420px;
h1{
font-weight: bold;
font-size: 18px;
color: #313131;
line-height: 24px;
margin-bottom: 12px;
}
p{
font-size: 12px;
color: #000000;
line-height: 25px;
max-height: 50px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
}
.handle{
.phonecons{
position: relative;
cursor: pointer;
margin-left: 10px;
img{
width:25px;
height:25px;
}
div{
position: absolute;
background: #fff;
top: 28px;
left: 0px;
border: 1px solid #FF9A00;
padding: 4px 6px;
border-radius: 3px;
display: none;
}
&:hover{
div{
display: block;
}
}
}
}
}
.btn{
width: 80px;
height: 30px;
background: #FF9A00;
line-height: 30px;
text-align: center;
color:#fff;
cursor: pointer;
&:hover {
background: #E18800;
}
}
.r{
width: 452px;
min-height: 222px;
background: #FFFCF8;
padding: 10px 30px;
.mb23{
margin-bottom: 24px;
}
.items{
width: 50%;
font-size: 12px;
color: #000000;
line-height: 25px;
>span{
width:50%;
}
}
.numInput {
width: 80px;
height: 30px;
text-align: center;
background: #FFFFFF;
border: 1px solid #999999;
cursor: pointer;
margin-top: 10px;
}
.buyBtn {
width: 80px;
height: 30px;
color: #FF9A00;
margin-left: 10px;
background: #FFFFFF;
border: 1px solid #FF9A00;
cursor: pointer;
margin-top: 10px;
margin-bottom: 15px;
&:hover {
background: #FFF7EC;
}
}
}
}
.detailSection{
margin-top: 20px;
.secl{
width: 978px;
min-height: 330px;
background: #FFFFFF;
padding:30px;
.lilistBox {
border-top: 1px solid #e5e5e5;
font-size : 14px;
color:#313131;
flex-shrink: 0;
flex-wrap: wrap;
border-left: 1px solid #e5e5e5;
p {
line-height : 36px;
width : 50%;
box-sizing: border-box;
height : 36px;
border-right : 1px solid #e5e5e5;
border-bottom : 1px solid #e5e5e5;
overflow : hidden;
text-overflow: ellipsis;
white-space : nowrap;
b {
width : 130px;
float : left;
display : block;
border-right : 1px solid #e5e5e5;
padding-left : 20px;
background : #F5F5F5;
margin-right : 1px;
overflow : hidden;
text-overflow: ellipsis;
white-space : nowrap;
}
span {
padding-left: 10px;
}
.ple0 span {
padding-left: 0px !important;
}
}
}
.goodsMask {
height: 60px;
line-height: 30px;
color: #313131;
font-size: 14px;
div {
width: 130px;
float: left;
border-right: 1px solid #e5e5e5;
border-left: 1px solid #e5e5e5;
border-bottom: 1px solid #e5e5e5;
padding-left: 20px;
background: #F5F5F5;
height: 90px;
}
h4 {
background: #fff;
width: 745px;
height: 90px;
padding-left: 10px;
padding-right: 10px;
border-right: 1px solid #e5e5e5;
border-bottom: 1px solid #e5e5e5;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
}
}
.secr{
.item{
padding: 34px 18px;
width: 233px;
height: 330px;
transition: all 0.5s;
background: #fff;
display: block;
margin-bottom: 20px;
&:last-child{margin-bottom: 0px;}
&:hover{
box-shadow: 4px 6px 7px 1px rgba(154,151,149,0.18);
transform: translateY(-1px);
}
img{
width: 150px;
height: 109px;
display: block;
margin: 0 auto;
margin-bottom: 60px;
}
.gos{
font-size: 14px;
color: #000000;
line-height: 25px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
height:50px;
margin-bottom: 30px;
}
.nam{
font-weight: normal;
font-size: 16px;
color: #000000;
line-height: 18px;
text-overflow: ellipsis;
overflow: hidden;
height:18px;
max-width: 110px;
}
.prs{
font-size: 16px;
color: #FF0006;
line-height: 18px;
}
}
}
}
.datanos{
background: #fff;
padding:80px 0;
img{
height:296px;
width:360px;
display: block;
margin:0 auto;
}
}
}
\ No newline at end of file
.mvClassPage{margin-bottom:30px;min-height:520px}.mvClassPage h1{font-weight:bold;font-size:20px;color:#313131;line-height:26px;padding:30px 0px}.mvClassPage .itembox{margin-bottom:5px;background:#fff;padding:32px 28px}.mvClassPage .itembox .itemtitle{font-weight:bold;font-size:16px;color:#000000;line-height:35px;height:35px}.mvClassPage .itembox .itemtitle:hover{color:#FF9A00}.mvClassPage .itembox .itemlink{font-size:14px;color:#000000;margin-right:20px;margin-top:15px}.mvClassPage .itembox .itemlink:hover{color:#FF9A00}.mvClassPage .itembox .itemcons{flex-wrap:wrap}
.mvClassPage{
margin-bottom: 30px;
min-height: 520px;
h1{
font-weight: bold;
font-size: 20px;
color: #313131;
line-height: 26px;
padding:30px 0px;
}
.itembox{
margin-bottom: 5px;
background: #fff;
padding:32px 28px;
.itemtitle{
font-weight: bold;
font-size: 16px;
color: #000000;
line-height: 35px;
height:35px;
&:hover{
color:#FF9A00;
}
}
.itemlink{
font-size: 14px;
color: #000000;
margin-right: 20px;
margin-top: 15px;
&:hover{
color:#FF9A00;
}
}
.itemcons{
flex-wrap: wrap;
}
}
}
\ No newline at end of file
import styles from './index.module.scss'
import Link from 'next/link';
import { GetServerSideProps } from 'next';
import { getClassMapData } from "@/server/getClassMapData";
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import type { classMapResponseType } from '@/types/classMapTypes';
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
export const getServerSideProps: GetServerSideProps = async () => {
return getClassMapData()
}
const Page = (props: { cateList: ResponseTypeCateList, classMapData: classMapResponseType }) => {
const list = props.classMapData.data
return (
<>
<main>
<Header {...props.cateList} />
<div className={styles.mvClassPage}>
<div className='w1226'>
<h1>全部商品</h1>
{
list.map((item, index) => {
return (
<div className={`${styles.itembox} boxsiz`} key={String(item.goods_type_id) + index}>
<Link href={`/list/${item.goods_type_id}`} className={styles.itemtitle} >{item.goods_type_name}</Link>
<div className={`${styles.itemcons} flex`} >
{
(item.child || []).map((itemChild, indexChild) => {
return (
<Link key={String(itemChild.goods_type_id) + indexChild} href={`/list/${item.goods_type_id}_${itemChild.goods_type_id}`} className={styles.itemlink} >{itemChild.goods_type_name}</Link>
)
})
}
</div>
</div>
)
})
}
</div>
</div>
<Footer />
</main>
</>
)
}
export default Page
\ No newline at end of file
import styles from './index.module.scss'
import BreadNav from '@/components/BreadNav';
import ListSort from '@/components/ListSort';
import { useEffect, useRef, useState } from 'react';
import type { ListSortType } from '@/components/ListSort/types'
import type { dataListItemType } from '@/components/ListOneItem/types'
import type { classResponseType, requestDataType } from '@/types/categoryTypes'
import ListOneItem from '../../components/ListOneItem';
import useRequest from '../../hooks/useRequest';
import ListNoData from '../../components/ListNoData';
import { useRouter } from 'next/router';
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import { GetServerSideProps } from 'next';
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
import { getCateList } from "@/server/getCateList";
import { useQq } from '@/hooks/useQq';
import { Empty,Pagination } from 'antd';
export const getServerSideProps: GetServerSideProps = async () => {
return getCateList()
}
const Category = (props: { cateList: ResponseTypeCateList }) => {
const { QQURL,PHONE}=useQq()
const router = useRouter()
const { query } = router
const class_id1= String(query.class_id).split("_")[0]
const class_id2= String(query.class_id).split("_")[1]||''
const [shouNoData, setShouNoData] = useState(false)
const [page, setPage] = useState(1)
const [total, setTotal] = useState(0)
const [dataList, setDataList] = useState<dataListItemType[]>([])
const [sortObj, setSortObj] = useState<ListSortType>({
sortType: 1,
isStock: false,
stockSort: '',
priceSort: ''
})
const { request: classInfoRequest } = useRequest<classResponseType>({ manual: true })
const shouldResetPage = useRef(false);
useEffect(() => {
shouldResetPage.current = true;
setPage(1);
}, [sortObj,query.class_id]);
useEffect(() => {
if (shouldResetPage.current && page !== 1) {
return
}
shouldResetPage.current = false;
let obj_: requestDataType = { page_size: 10, page: page, class_id1: class_id1, class_id2: class_id2 }
if (sortObj.isStock) {
obj_['stock/gt'] = 0
}
if (sortObj.sortType === 2) {
obj_['stock/sort'] = sortObj.stockSort === 'top' ? 'asc' : 'desc'
}
if (sortObj.sortType === 3) {
obj_['single_price/sort'] = sortObj.priceSort === 'top' ? 'asc' : 'desc'
}
classInfoRequest({
url: '/api/search/searchByClass',
method: 'post',
data: obj_,
}).then(res => {
if (res?.code === 0) {
setTotal(Number(res.data?.total))
setDataList(res.data?.lists || [])
if (res.data?.lists.length > 0) {
setShouNoData(false)
} else {
setShouNoData(true)
}
console.log(setTotal)
} else {
setShouNoData(true)
}
})
}, [classInfoRequest, class_id2,class_id1, page, sortObj])
const handlePageChange = (page:number, pageSize:number) => {
setPage(page)
}
return (
<>
<main>
<Header {...props.cateList} />
<BreadNav><strong>分类搜索结果</strong></BreadNav>
<div className={`${styles.mvCategoryPage} w1226`} >
{/* <div className='categoryHead boxsiz'>
<h2>陶瓷电容</h2>
<div className='textBf'>
Lorem ipsum dolor sit amet, ci, sed rhoncus pronin sapien nunc accuan eget.
</div>
<div className='brandbox row '>
<span>品牌:</span>
<div className='itembox row'>
<div className='item'>ON</div>
<div className='item'>NPX</div>
</div>
</div>
</div> */}
<div className={`${styles.databox} w1226`}>
<div className={styles.dataGroupSupplier}>
<div className={styles.sortbixjk}>
<ListSort sortObj={sortObj} setSortObj={setSortObj} />
</div>
{
dataList.map(item => {
return (
<ListOneItem key={item.sku_id} {...item} QQURL={QQURL} PHONE={PHONE}/>
)
})
}
{shouNoData ? <Empty image='/images/emptyorder.png' description="数据为空!" imageStyle={{height: '183px', margin: '30px auto 0'}} />: ''}
</div>
<Pagination
className='paginationxkant'
showQuickJumper
showSizeChanger
hideOnSinglePage={true}
current={page}
pageSize={10}
pageSizeOptions={[5, 10]}
total={total}
showTotal={(total) => `共 ${total} 条记录`}
onChange={handlePageChange}/>
</div>
</div>
<Footer />
</main>
</>
)
}
export default Category
\ No newline at end of file
.mvCategoryPage{padding-bottom:54px}.mvCategoryPage .categoryHead{min-height:245px;background:#fff;padding:30px 50px}.mvCategoryPage .categoryHead h2{font-weight:bold;font-size:22px;color:#000000;line-height:29px;text-align:center;margin-bottom:20px}.mvCategoryPage .categoryHead .textBf{font-size:14px;color:#000000;line-height:25px;height:100px;word-break:break-all;text-overflow:ellipsis;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4}.mvCategoryPage .categoryHead .brandbox span{font-weight:bold;font-size:14px;color:#000000;line-height:20px;width:80px;flex-shrink:0}.mvCategoryPage .categoryHead .brandbox .itembox{flex-wrap:wrap}.mvCategoryPage .categoryHead .brandbox .itembox .item{height:20px;line-height:20px;font-size:14px;color:#000000;margin-right:40px;margin-bottom:15px}.mvCategoryPage .databox .dataGroupSupplier{padding-bottom:20px;background:#fff;min-height:400px}.mvCategoryPage .databox .dataGroupSupplier .sortbixjk{padding:0 27px;padding-top:25px}
.mvCategoryPage{
padding-bottom: 54px;
.categoryHead{
min-height:245px;
background: #fff;
padding:30px 50px;
h2{
font-weight: bold;
font-size: 22px;
color: #000000;
line-height: 29px;
text-align: center;
margin-bottom: 20px;
}
.textBf{
font-size: 14px;
color: #000000;
line-height: 25px;
height: 100px;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
}
.brandbox{
span{
font-weight: bold;
font-size: 14px;
color: #000000;
line-height: 20px;
width:80px;
flex-shrink: 0;
}
.itembox{
flex-wrap: wrap;
.item{
height:20px;
line-height: 20px;
font-size: 14px;
color: #000000;
margin-right: 40px;
margin-bottom: 15px;
}
}
}
}
.databox{
.dataGroupSupplier{
padding-bottom: 20px;
background: #fff;
min-height: 400px;
.sortbixjk{
padding:0 27px;
padding-top: 25px;
}
}
}
}
\ No newline at end of file
.loginPage{background:#fff;padding:80px 0;height:740px;width:100%;border-top:1px solid #FF9A00;position:relative}.loginPage .loginBox{width:400px;height:100%;position:absolute;left:50%;transform:translate(-50%);text-align:center}.loginPage .loginBox .typeBox{padding:10px 40px 50px;display:flex;justify-content:space-between}.loginPage .loginBox .typeBox .typeButton{color:#808080}.loginPage .loginBox .typeBox .typeButton:hover{color:#FF9A00}.loginPage .loginBox .typeBox .typeButtonChoosen{color:#FF9A00;font-weight:bold}.loginPage .loginBox .loginInput{width:378px;height:43px;background:#F8F8F8;border-radius:1px;border:1px solid #E2E2E2;margin-bottom:25px;padding-left:20px}.loginPage .loginBox .forgetButton{text-align:right;width:100%;margin-top:-10px;padding-right:50px;color:#808080}.loginPage .loginBox .loginButton{width:400px;height:43px;background:#FF9A00;border-radius:1px;font-size:20px;color:#FFFFFF;margin-top:100px;cursor:pointer}.loginPage .loginBox .registerButton{font-size:14px;margin-top:15px}.loginPage .loginBox .cursorPointer{cursor:pointer}.loginPage .loginBox .areaChoose{display:inline-block;width:145px;background:#F8F8F8;border-radius:1px;border:1px solid #E2E2E2;margin-bottom:25px;padding-left:10px;height:45px;vertical-align:bottom;cursor:pointer}.loginPage .loginBox .areaInput{display:inline-block;width:238px;background:#F8F8F8;border-radius:1px;border:1px solid #E2E2E2;margin-bottom:25px;padding-left:15px;height:43px}.loginPage .loginBox .codeButton{display:inline-block;width:100px;height:45px;background:#FF9A00;border-radius:1px;font-size:14px;color:#FFFFFF;cursor:pointer;vertical-align:center}.loginPage .loginBox .codeButton.dis{background:#ccc;cursor:not-allowed}.loginPage .loginBox .registerInput{width:278px;height:43px;background:#F8F8F8;border-radius:1px;border:1px solid #E2E2E2;margin-bottom:25px;padding-left:20px;vertical-align:top}.loginPage .loginBox .registerTips{text-align:left;width:100%;margin-top:-10px;color:#808080}.loginPage .loginBox .registerRule{height:20px;width:100%;display:flex;align-items:center;justify-content:left;margin-top:80px}.loginPage .loginBox .registerLoginButton{width:400px;height:43px;background:#FF9A00;border-radius:1px;font-size:20px;color:#FFFFFF;margin-top:15px;cursor:pointer}.loginPage .loginBox .registerCheck{width:20px;height:20px;background:#FFFFFF;border-radius:2px;border:1px solid #E0E0E0;cursor:pointer;margin-right:10px}.loginPage .loginBox .ruleText{font-size:12px;color:#808080}.loginPage .loginBox .ruleButton{font-size:12px;color:#000000;cursor:pointer;font-weight:bold}.loginPage .loginBox .showMsg{position:absolute;left:0;color:#D0121B;font-size:12px;line-height:16px;margin-top:10px}.loginPage .ruleDialog{position:absolute;z-index:9999;width:1120px;height:666px;top:25px;left:50%;transform:translate(-50%);box-shadow:0px 2px 15px 0px rgba(206,206,206,0.5);border:1px solid #E0E0E0;overflow:auto;background-color:#fff;padding:25px 0 0 25px;box-sizing:border-box}.loginPage .ruleDialog .ruleContext{width:calc(100% - 25px);height:576px;overflow:auto;padding-right:25px;font-size:14px}.loginPage .ruleDialog .ruleCloseButton{width:290px;height:45px;border-radius:1px;border:1px solid #E0E0E0;position:absolute;bottom:25px;left:50%;transform:translate(-50%);cursor:pointer}.loginPage .ruleDialog .ruleCloseButton:hover{color:#FF9A00}
.loginPage{
background: #fff;
padding:80px 0;
height: 740px;
width: 100%;
border-top: 1px solid #FF9A00;
position: relative;
.loginBox {
width: 400px;
height: 100%;
position: absolute;
left: 50%;
transform: translate(-50%);
text-align: center;
.typeBox {
padding: 10px 40px 50px;
display: flex;
justify-content: space-between;
.typeButton {
color: #808080;
&:hover {
color: #FF9A00;
}
}
.typeButtonChoosen {
color: #FF9A00;
font-weight: bold;
}
}
.loginInput{
width: 378px;
height: 43px;
background: #F8F8F8;
border-radius: 1px;
border: 1px solid #E2E2E2;
margin-bottom: 25px;
padding-left: 20px;
}
.forgetButton {
text-align: right;
width: 100%;
margin-top: -10px;
padding-right: 50px;
color: #808080;
}
.loginButton {
width: 400px;
height: 43px;
background: #FF9A00;
border-radius: 1px;
font-size: 20px;
color: #FFFFFF;
margin-top: 100px;
cursor: pointer;
}
.registerButton {
font-size: 14px;
margin-top: 15px;
}
.cursorPointer{
cursor: pointer;
}
.areaChoose {
display: inline-block;
width: 145px;
background: #F8F8F8;
border-radius: 1px;
border: 1px solid #E2E2E2;
margin-bottom: 25px;
padding-left: 10px;
height: 45px;
vertical-align: bottom;
cursor: pointer;
}
.areaInput {
display: inline-block;
width: 238px;
background: #F8F8F8;
border-radius: 1px;
border: 1px solid #E2E2E2;
margin-bottom: 25px;
padding-left: 15px;
height: 43px;
}
.codeButton {
display: inline-block;
width: 100px;
height: 45px;
background: #FF9A00;
border-radius: 1px;
font-size: 14px;
color: #FFFFFF;
cursor: pointer;
vertical-align: center;
&.dis{
background: #ccc;
cursor: not-allowed;
}
}
.registerInput{
width: 278px;
height: 43px;
background: #F8F8F8;
border-radius: 1px;
border: 1px solid #E2E2E2;
margin-bottom: 25px;
padding-left: 20px;
vertical-align: top;
}
.registerTips {
text-align: left;
width: 100%;
margin-top: -10px;
color: #808080;
}
.registerRule {
height: 20px;
width: 100%;
display: flex;
align-items: center;
justify-content: left;
margin-top: 80px;
}
.registerLoginButton {
width: 400px;
height: 43px;
background: #FF9A00;
border-radius: 1px;
font-size: 20px;
color: #FFFFFF;
margin-top: 15px;
cursor: pointer;
}
.registerCheck {
width: 20px;
height: 20px;
background: #FFFFFF;
border-radius: 2px;
border: 1px solid #E0E0E0;
cursor: pointer;
margin-right: 10px;
}
.ruleText {
font-size: 12px;
color: #808080;
}
.ruleButton {
font-size: 12px;
color: #000000;
cursor: pointer;
font-weight: bold;
}
.showMsg {
position: absolute;
left: 0;
color: #D0121B;
font-size: 12px;
line-height: 16px;
margin-top: 10px;
}
}
.ruleDialog {
position: absolute;
z-index: 9999;
width: 1120px;
height: 666px;
top: 25px;
left: 50%;
transform: translate(-50%);
box-shadow: 0px 2px 15px 0px rgba(206,206,206,0.5);
border: 1px solid #E0E0E0;
overflow: auto;
background-color: #fff;
padding: 25px 0 0 25px;
box-sizing: border-box;
.ruleContext {
width: calc(100% - 25px);
height: 576px;
overflow: auto;
padding-right: 25px;
font-size: 14px;
}
.ruleCloseButton {
width: 290px;
height: 45px;
border-radius: 1px;
border: 1px solid #E0E0E0;
position: absolute;
bottom: 25px;
left: 50%;
transform: translate(-50%);
cursor: pointer;
&:hover {
color: #FF9A00;
}
}
}
}
\ No newline at end of file
import React, { useEffect, useState, useRef } from 'react';
import useRequest from "@/hooks/useRequest"
import style from './index.module.scss'
import Footer from "@/components/Footer";
import TopH from "@/components/Header/components/TopH"
import SearchH from "@/components/Header/components/SearchH"
import Link from 'next/link'
import { useRouter } from 'next/router';
import { useToast } from '@/hooks/useToast';
import { useCookies } from '@/hooks/useCookies'
import { useSeoTitle } from '@/hooks/useSeoTitle';
const Page = () => {
const router = useRouter()
const { query } = router
const seoTitle=useSeoTitle()
const {setCookie} = useCookies()
const [loginType, setLoginType] = useState(query.type);
const [count, setCount] = useState('');
const [password, setPassword] = useState('');
const [area, setArea] = useState('0086');
const [code, setCode] = useState('');
const [showRule, setShowRule] = useState(false);
const [showMsg, setShowMsg] = useState(false);
const [msg, setMsg] = useState('');
const {message}=useToast()
const messageRef = useRef(message);
const handleCountChange = (e:any) => setCount(e.target.value);
const handlePasswordChange = (e:any) => setPassword(e.target.value);
const handleAreaChange = (e:any) => setArea(e.target.value);
const handleCodeChange = (e:any) => setCode(e.target.value);
const handleTypeChange = (type:string) => {
setLoginType(type)
setCount('')
setShowMsg(false)
setPassword('')
setCode('')
}
const codeTimer = useRef<any>();
const [codeText,setCodeText]=useState<string>("发送验证码")
const [codeTimeVal,setCodeTimeVal]=useState<number>(60)
useEffect(() => {
if (codeText === '发送验证码') {
return;
}
codeTimer.current = setInterval(() => {
setCodeTimeVal((prevCodeTimeVal) => {
const newTime = prevCodeTimeVal - 1;
if (newTime < 1) {
clearInterval(codeTimer.current);
setCodeText('发送验证码');
setCodeTimeVal(60);
return 60;
}
setCodeText(`重发(${newTime}S)`);
return newTime;
});
}, 1000);
return () => {
if (codeTimer.current) {
clearInterval(codeTimer.current);
}
};
}, [codeText, setCodeTimeVal]);
const { request: loginRequest } = useRequest<any>({ manual: true })
useEffect(() => {
setLoginType(query.type)
}, [query])
const regex = /^1[3-9]\d{9}$/;
//发送验证码
const handleCodeSend = async(e:any) => {
if (codeText !== '发送验证码') {
return;
}
if(!count) return false
e.preventDefault()
setShowMsg(false)
if (!regex.test(count)) {
setMsg('手机格式不正确,请重新输入!')
setShowMsg(true)
return false
}
const param = {
send_type: '1',
send_user: count,
send_fun: 'login'
}
loginRequest({
url: '/sendMsgCode',
method: 'post',
data: param,
}).then(res => {
if(res.code==0){
messageRef.current("发送成功")
setCodeText('重发(60S)')
}else{
messageRef.current(res.msg)
}
})
return false
}
// 登录
const handleSubmit = async (e:any) => {
e.preventDefault()
setShowMsg(false)
const param = {
contacts_tel: count,
type: loginType,
password: password,
code: code
}
const response = await loginRequest({
url: '/login',
method: 'post',
data: param,
})
if (response.code === 0) {
setCookie('token', response.data.token, 1)
setCookie('userId', response.data.user.web_user_id, 1)
setCookie('userName', count, 1)
messageRef.current("登录成功")
loginRequest({ url: '/api/userInfo/userInvoiceList?limit=100', method: 'get'}).then((res) => {
if (res?.code === 0) {
if(res?.data?.list.length>0){
if(query.backUrl){
window.location.href=String(query.backUrl)
return
}
router.push("/")
}else{
router.push("/regChoose?backUrl="+encodeURIComponent(String(query.backUrl)))
}
} else {
messageRef.current(res?.msg)
}
})
}
else {
setMsg(response.msg)
setShowMsg(true)
}
return false
};
const handleRuleShow = (type:string) => {
let doClose = true
switch (type) {
case 'Privacy':
break;
case 'user':
break;
case 'close':
doClose = false
}
setShowRule(doClose)
}
return (
<>
{seoTitle}
<TopH />
<SearchH />
<div className={style.loginPage}>
<div className={style.loginBox}>
<div className={style.typeBox}>
<span
className={`${style.typeButton} ${style.cursorPointer} ${(loginType === "1") && style.typeButtonChoosen}`}
onClick={() => handleTypeChange('1')}>
账号登录
</span>
<span
className={`${style.typeButton} ${style.cursorPointer} ${(loginType === '2') && style.typeButtonChoosen}`}
onClick={() => handleTypeChange('2')}>
免密登录/注册
</span>
</div>
<form onSubmit={handleSubmit}>
{loginType === "1" ? (
<>
<div>
<input type="contacts_tel" value={count} className={style.loginInput} placeholder='请输入账号' onChange={(handleCountChange)} required />
</div>
<div>
<input type="password" value={password} className={style.loginInput} placeholder='请输入登录密码' onChange={handlePasswordChange} required />
</div>
{ showMsg && (
<>
<p className={style.showMsg}>{msg}</p>
</>
)}
<div className={style.forgetButton}>
<Link href="/passwordRecover">
<span className={style.cursorPointer}>忘记密码?</span>
</Link>
</div>
<button type="submit" className={style.loginButton} >登录</button>
<div className={style.registerButton}>
<span className={style.cursorPointer} onClick={() => handleTypeChange('2')}>立即注册</span>
</div>
</>
) : (
<>
<div>
<select className={style.areaChoose} value={area} onChange={() => handleAreaChange} >
<option value="0086">0086(中国大陆)</option>
<option value="00852">00852(中国香港)</option>
<option value="00853">00853(中国澳门)</option>
<option value="00886">00886(中国台湾)</option>
</select>
<input type="contacts_tel" value={count} className={style.areaInput} placeholder='请输入手机号' onChange={handleCountChange} required />
</div>
<div>
<input type="password" value={code} className={style.registerInput} placeholder='请输入短信验证码' onChange={handleCodeChange} required />
<button className={codeText=='发送验证码'?`${style.codeButton }`:`${style.codeButton } ${style.dis}`} onClick={handleCodeSend}>{codeText}</button>
</div>
<div className={style.registerTips}>未注册的手机号将自动完成注册</div>
{ showMsg && (
<>
<p className={style.showMsg}>{msg}</p>
</>
)}
<div className={style.registerRule}>
<input type='checkbox' name="ruleCheck" className={style.registerCheck} required></input>
<span className={style.ruleText}>我已阅读并同意</span>
<span className={style.ruleButton} onClick={() => handleRuleShow('user')}>《用户注册协议》</span>
<span className={style.ruleButton} onClick={() => handleRuleShow('Privacy')}>《隐私保护协议》</span>
</div>
<button type="submit" className={style.registerLoginButton}>登录</button>
</>
)}
</form>
</div>
{showRule && (
<>
<div className={style.ruleDialog}>
<div className={style.ruleContext}>
</div>
<button className={style.ruleCloseButton} onClick={() => handleRuleShow('close')}>关闭本页</button>
</div>
</>
)}
</div>
<Footer />
</>
);
};
export default Page;
.orderBox{width:1022px;margin-left:12px;box-sizing:border-box;padding:20px 30px 50px;background-color:#fff;box-sizing:border-box;position:relative}.orderBox .baseTitle{font-size:16px;color:#1A1A1A}.orderBox .moreButton{position:absolute;right:30px;top:20px;color:#888888;font-size:12px;cursor:pointer;display:flex;align-items:center}.orderBox .moreButton img{margin-right:5px}.orderBox .statusBox{width:100%;height:90px;display:flex;box-sizing:border-box;padding:30px 0;margin-top:10px;border-top:1px solid #F4F4F4}.orderBox .statusBox .statusItem{height:20px;line-height:20px;box-sizing:border-box;border-left:1px solid #E2E2E2;padding-left:10px;cursor:pointer}.orderBox .statusBox .statusItem:first-child{border-left:none;padding-left:0}.orderBox .statusBox .statusItemSelected{color:#D0121B}.orderBox .orderTitle{display:flex;align-items:center;justify-content:space-between;height:60px;font-weight:bold;font-size:12px;color:#313131;border:1px solid #f0f0f0;border-bottom:none;padding:0 20px;cursor:pointer}.orderBox .orderTitle .payButton{width:65px;height:24px;background:#FDF5F5;border-radius:1px;border:1px solid #D0121B;cursor:pointer;color:#D0121B;font-size:12px}.orderBox .orderTitle .payButton:hover{color:#fff;background:#D0121B}.orderBox .orderTitle span{display:inline-block;max-width:190px;overflow:hidden;text-overflow:ellipsis}.orderBox .orderTitle span:first-child{font-weight:bold;text-decoration-line:underline}.orderBox .pagination{position:absolute;right:30px;bottom:30px}
.orderBox {
width: 1022px;
margin-left: 12px;
box-sizing: border-box;
padding: 20px 30px 50px;
background-color: #fff;
box-sizing: border-box;
position: relative;
.baseTitle {
font-size: 16px;
color: #1A1A1A;
}
.moreButton {
position: absolute;
right: 30px;
top: 20px;
color: #888888;
font-size: 12px;
cursor: pointer;
display: flex;
align-items: center;
img {
margin-right: 5px;
}
}
.statusBox {
width: 100%;
height: 90px;
display: flex;
box-sizing: border-box;
padding: 30px 0;
margin-top: 10px;
border-top: 1px solid #F4F4F4;
.statusItem {
height: 20px;
line-height: 20px;
box-sizing: border-box;
border-left: 1px solid #E2E2E2;
padding-left: 10px;
cursor: pointer;
&:first-child {
border-left: none;
padding-left: 0;
}
}
.statusItemSelected {
color: #D0121B;
}
}
.orderTitle {
display: flex;
align-items: center;
justify-content: space-between;
height: 60px;
font-weight: bold;
font-size: 12px;
color: #313131;
border: 1px solid #f0f0f0;
border-bottom: none;
padding: 0 20px;
cursor: pointer;
.payButton {
width: 65px;
height: 24px;
background: #FDF5F5;
border-radius: 1px;
border: 1px solid #D0121B;
cursor: pointer;
color: #D0121B;
font-size: 12px;
&:hover {
color: #fff;
background: #D0121B;
}
}
span{
display: inline-block;
max-width: 190px;
overflow: hidden;
text-overflow: ellipsis;
&:first-child {
font-weight: bold;
text-decoration-line: underline;
}
}
}
.pagination {
position: absolute;
right: 30px;
bottom: 30px;
}
}
import styles from './index.module.scss'
import {useState, useEffect} from 'react'
import { DatePicker, Table, Pagination ,Empty} from "antd"
import type { TableColumnsType } from 'antd'
import useRequest from "@/hooks/useRequest"
import { DataType } from "@/types/orderTypes"
import dayjs from 'dayjs'
import { useRouter } from 'next/router'
import { useQq } from '@/hooks/useQq'
const { RangePicker } = DatePicker
const OrderPage = () => {
const {QQURL}=useQq()
const [initstatus, setInitstatus] = useState(false);
const { request: userRequest } = useRequest<any>({ manual: true })
const [goodsList, setGoodsList] = useState<any>([])
const [timeRange, setTimeRange] = useState<any>([])
const [current, setCurrent] = useState(1);
const [pageSize, setPageSize] = useState(5);
const [total, setTotal] = useState(0);
const [status, setStatus] = useState(0);
const columns: TableColumnsType<DataType> = [
{ title: '序号', dataIndex: 'name', key: 'name',width:320, render:(text, record, index) => { return <span>{index + 1}</span>} },
{ title: '型号/品牌', dataIndex: 'sku_name',key: 'sku_name', render:(text, record, index) => { return <span>{record.goods_name}/{record.brand_name}</span>} },
{ title: '数量', dataIndex: 'goods_number', key: 'goods_number', },
{ title: '单价', dataIndex: 'goods_price', key: 'goods_price' , render:(text, record, index) => { return <span>{record.iso_code_text}{record.goods_price}</span>}},
{ title: '小计', dataIndex: 'goods_amount', key: 'goods_amount', render:(text, record, index) => { return <span>{record.iso_code_text}{record.goods_amount}</span>} },
{ title: '明细备注', dataIndex: 'web_order_remark', key: 'web_order_remark' },
]
const [statusSummaryMap, setStatusSummaryMap] = useState<any>({'0': {count: 0}, '1': {count: 0}, '2': {count: 0}, '3': {count: 0}, '4': {count: 0}, '5': {count: 0}})
const router = useRouter()
useEffect(() => {
handleDataInit()
}, [])
useEffect(() => {
handleOrderListInit()
}, [timeRange, current, pageSize, status])
useEffect(() => {
if (router.query?.status) setStatus(Number(router.query.status))
}, [router.query])
const handleDataInit = async () => {
const tatusSummaryResponse = await userRequest({
url: '/api/order/webOrderStatusSummary',
method: 'post'
})
if (tatusSummaryResponse.code === 0) setStatusSummaryMap(Object.assign(statusSummaryMap, tatusSummaryResponse.data))
}
const handleOrderListInit = async () => {
const orderParam = {
web_order_status: status,
create_time: (timeRange[0] && timeRange[1]) && `${dayjs(timeRange[0]).format('YYYY/MM/DD')}~${dayjs(timeRange[1]).format('YYYY/MM/DD')}`,
page: current,
limit: pageSize,
items_limit: 5
}
const webOrderListResponse = await userRequest({
url: `/api/order/webOrderList`,
method: 'post',
data: orderParam,
})
if (webOrderListResponse.code === 0) {
setInitstatus(true)
const arr_=webOrderListResponse.data.list||[]
arr_.forEach((item:any)=>{
item.order_items.forEach((item1:any)=>{
item1.iso_code_text=item.iso_code=="CNY"?'¥':'$'
})
})
setGoodsList(arr_)
setTotal(webOrderListResponse.data.total)
}
}
const handleTimeChange = (date:any, dateString:any) => {
setTimeRange(dateString)
handleDataInit()
}
const handlePageChange = (page:number, pageSize:number) => {
setCurrent(page)
setPageSize(pageSize)
}
const handleStatusChange = (status:number) => {
setStatus(status)
setCurrent(1)
}
const handleOrderDetail = (order: any) => {
router.push(`/orderDetail?order_id=${order.order_id}`)
}
const handlePayment = (order: any) => {
router.push(`/orderResult?type=2&orderId=${order?.order_id}`)
}
return (
<>
<div className={styles.orderBox}>
<div className={styles.baseTitle}>我的订单</div>
<a className={styles.moreButton} href={QQURL} target='_blank' rel="noreferrer">
<img src="images/customerService.png" />
我的客服
</a>
<div className={styles.statusBox}>
<div className={`${styles.statusItem} ${(status === 0) && styles.statusItemSelected}`} onClick={() => handleStatusChange(0)}>
全部订单({statusSummaryMap[0]['count']})
</div>
<div className={`${styles.statusItem} ${(status === 1) && styles.statusItemSelected}`} onClick={() => handleStatusChange(1)}>
待审核({statusSummaryMap[1]['count']})
</div>
<div className={`${styles.statusItem} ${(status === 2) && styles.statusItemSelected}`} onClick={() => handleStatusChange(2)}>
待付款({statusSummaryMap[2]['count']})
</div>
<div className={`${styles.statusItem} ${(status === 3) && styles.statusItemSelected}`} onClick={() => handleStatusChange(3)}>
待发货({statusSummaryMap[3]['count']})
</div>
<div className={`${styles.statusItem} ${(status === 4) && styles.statusItemSelected}`} onClick={() => handleStatusChange(4)}>
已完结({statusSummaryMap[4]['count']})
</div>
<div className={`${styles.statusItem} ${(status === 5) && styles.statusItemSelected}`} onClick={() => handleStatusChange(5)}>
已取消({statusSummaryMap[5]['count']})
</div>
<div style={{marginTop: '-5px', marginLeft: 'auto'}}>
下单时间:<RangePicker
onChange={(date:any, dateString:any) => handleTimeChange(date, dateString)}/>
</div>
</div>
{
goodsList.map((goodItem:any) => {
return (
<div key={goodItem.order_id} style={{marginBottom: '45px'}}>
<div className={styles.orderTitle}>
<span onClick={() => handleOrderDetail(goodItem)}>订单号:{goodItem.order_sn}</span>
<span>{goodItem.create_time}</span>
<span title={goodItem.order_invoice.tax_title}>发票抬头:{goodItem.order_invoice.tax_title}</span>
<span title={goodItem.web_order_remark}>订单备注:{goodItem.web_order_remark}</span>
<span>订单合计金额:{goodItem.iso_code=='CNY'?'¥':'$'}{goodItem.order_amount}</span>
{(goodItem.web_order_status === 2) && (<button className={styles.payButton} onClick={() => handlePayment(goodItem)}>立即付款</button>)}
</div>
<Table<DataType>
size="small"
bordered={true}
pagination={false}
columns={columns}
rowKey={(record) => record?.rec_id}
expandable={{
expandIcon: (r) => null,
defaultExpandAllRows: true,
expandedRowRender: (record) => {
return (
<div style={{ fontSize: '12px' }}>
<span style={{ marginRight: '20px' }}>最新进度:{record.latest_log_time}</span>
<span style={{ marginRight: '20px' }}>状态:{record.latest_log_status_text}</span>
<span style={{ marginRight: '20px' }}>{record.latest_log}</span>
</div>
)
},
rowExpandable: (record) => record.name !== 'Not Expandable',
}}
dataSource={goodItem.order_items}
/>
</div>
)
})
}
{goodsList.length==0&&initstatus&&<Empty image='/images/emptyorder.png' description="暂无订单" imageStyle={{height: '183px', margin: '50px auto 0'}} />}
<div className={styles.pagination}>
<Pagination
showQuickJumper
showSizeChanger
hideOnSinglePage={true}
current={current}
pageSize={pageSize}
pageSizeOptions={[5, 10]}
total={total}
showTotal={(total) => ` ${total} 条记录`}
onChange={handlePageChange}/>
</div>
</div>
</>
)
}
export default OrderPage
\ No newline at end of file
.userCenter {
padding: 10px;
width: 1226px;
margin: 0 auto;
display: flex;
}
\ No newline at end of file
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import Nav from "@/components/navigation";
import style from './index.module.scss'
import { GetServerSideProps } from 'next';
import { getCateList } from "@/server/getCateList";
import BasicData from './component/order'
import type {ResponseTypeCateList} from '@/components/Header/components/NavBig/types'
export const getStaticProps: GetServerSideProps = async () => {
return getCateList()
}
const Page = (props:{cateList:ResponseTypeCateList}) => {
const {cateList}=props
return (
<>
<Header {...cateList}/>
<div className={style.userCenter}>
<Nav></Nav>
<BasicData/>
</div>
<Footer />
</>
)
}
export default Page
\ No newline at end of file
const FilterDate = (prop: { time: string }) => {
const { time } = prop;
const dateObject = new Date(time);
const year: number = dateObject.getFullYear();
const month: number = dateObject.getMonth() + 1;
const day: number = dateObject.getDate();
return (
<>
<span>{day}/</span>
<p>{month}<br />{year}</p>
</>
)
}
export default FilterDate
\ No newline at end of file
.mvNoticePage{margin-bottom:54px}.mvNoticePage h1{font-weight:bold;font-size:20px;color:#000000;line-height:26px;height:26px;padding:35px 0}.mvNoticePage .itembox .item{margin-bottom:20px;background:#fff;min-height:224px;padding:34px 40px}.mvNoticePage .itembox .item .date{height:156px;padding-right:68px}.mvNoticePage .itembox .item .date span{font-size:32px;color:#000000;line-height:42px}.mvNoticePage .itembox .item .date p{font-size:14px;color:#808080;line-height:19px;margin-left:10px}.mvNoticePage .itembox .item .sxc{padding-left:40px;min-height:156px;border-left:1px solid #E7E7E7;width:990px}.mvNoticePage .itembox .item .sxc .titleo{font-size:16px;color:#000000;line-height:21px;height:21px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mvNoticePage .itembox .item .sxc .htmlbox{margin:20px 0px;height:75px;padding:7px 0;overflow:hidden;font-size:14px;color:#888888;line-height:30px}.mvNoticePage .itembox .item .sxc .htmlbox img{max-width:990px}.mvNoticePage .itembox .item .sxc .htmlbox.auto{height:auto;color:#000000}.mvNoticePage .itembox .item .sxc .ckmore{font-size:14px;color:#FF9A00;line-height:19px;cursor:pointer}
.mvNoticePage {
margin-bottom: 54px;
h1 {
font-weight: bold;
font-size : 20px;
color : #000000;
line-height: 26px;
height : 26px;
padding : 35px 0;
}
.itembox {
.item {
margin-bottom: 20px;
background : #fff;
min-height : 224px;
padding:34px 40px;
.date {
height:156px;
padding-right: 68px;
span {
font-size : 32px;
color : #000000;
line-height: 42px;
}
p {
font-size : 14px;
color : #808080;
line-height: 19px;
margin-left: 10px;
}
}
.sxc{
padding-left: 40px;
min-height: 156px;
border-left: 1px solid #E7E7E7;
width:990px;
.titleo{
font-size: 16px;
color: #000000;
line-height: 21px;
height: 21px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.htmlbox{
margin:20px 0px;
height:75px;
padding:7px 0;
overflow: hidden;
img{max-width: 990px;}
font-size: 14px;
color: #888888;
line-height: 30px;
&.auto{
height:auto;
color:#000000;
}
}
.ckmore{
font-size: 14px;
color: #FF9A00;
line-height: 19px;
cursor: pointer;
}
}
}
}
}
\ No newline at end of file
import styles from './index.module.scss'
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import { GetServerSideProps } from 'next';
import { getCateList } from "@/server/getCateList";
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
export const getServerSideProps: GetServerSideProps = async () => {
return getCateList()
}
import { useEffect, useState } from 'react';
import FilterDate from './FilterDate';
import useRequest from '../../hooks/useRequest';
import type { NoticeResponseType, listType } from '@/types/noticeTypes'
import { Empty,Pagination } from 'antd';
const Page = (props: { cateList: ResponseTypeCateList }) => {
const { cateList } = props
const [ntList, setNtList] = useState<listType>([])
const [page, setPage] = useState(1)
const [total, setTotal] = useState(0)
const [shouNoData, setShouNoData] = useState(false)
const { request: noticeRequest } = useRequest<NoticeResponseType>({ manual: true })
useEffect(() => {
noticeRequest({ url: '/api/article/articleList', params: { page: page, limit: 1 } }).then(res => {
if (res?.code === 0) {
const list_ = res.data.list || []
list_.forEach(item => {
item.isAuto = false
})
setTotal(res.data?.total)
setNtList(list_)
if (res.data?.list.length > 0) {
setShouNoData(false)
} else {
setShouNoData(true)
}
} else {
setShouNoData(true)
}
})
}, [noticeRequest, page])
const changeStatus = (article_id: number) => {
const newList = [...ntList]
newList.forEach((item) => {
if (item.article_id === article_id) {
item.isAuto = !item.isAuto
}
})
setNtList(newList)
}
const handlePageChange = (page:number, pageSize:number) => {
setPage(page)
}
return (
<>
<main>
<Header {...cateList} />
<div className={styles.mvNoticePage}>
<h1 className='w1226'>公告</h1>
<div className={`${styles.itembox} w1226`}>
{
ntList.map((item, index) => {
return (
<div className={`${styles.item} row boxsiz`} key={index + item.article_id + Math.random()}>
<div className={`${styles.date} row boxsiz`}>
<FilterDate time={item.create_time_cn} />
</div>
<div className={`${styles.sxc} boxsiz`}>
<div className={styles.titleo}>{item.article_title}</div>
<div className={item.isAuto ? `${styles.htmlbox} boxsiz auto` : `${styles.htmlbox} boxsiz`} dangerouslySetInnerHTML={{ __html: item.article_desc }}></div>
<div className={styles.ckmore} onClick={() => { changeStatus(item.article_id) }}>{item.isAuto ? '收起' : '查看详情'}</div>
</div>
</div>
)
})
}
{shouNoData ? <Empty image='/images/emptyorder.png' description="数据为空!" imageStyle={{height: '183px', margin: '30px auto 0'}} /> : ''}
<Pagination
className='paginationxkant'
showQuickJumper
showSizeChanger
hideOnSinglePage={true}
current={page}
pageSize={10}
pageSizeOptions={[5, 10]}
total={total}
showTotal={(total) => `共 ${total} 条记录`}
onChange={handlePageChange}/>
</div>
</div>
<Footer />
</main>
</>
)
}
export default Page
\ No newline at end of file
.userCenter{padding:10px;width:1226px;margin:0 auto;display:flex}.orderBox{width:1022px;margin-left:12px;box-sizing:border-box;padding:20px 30px 50px;background-color:#fff;box-sizing:border-box;position:relative}.orderBox .baseTitle{font-size:16px;color:#1A1A1A}.orderBox .moreButton{position:absolute;right:30px;top:20px;color:#888888;font-size:12px;cursor:pointer;display:flex;align-items:center}.orderBox .moreButton img{margin-right:5px}.orderBox .detailBox{height:400px;margin-top:10px;border-top:1px solid #F4F4F4}.orderBox .detailBox .orderSn{width:100%;height:24px;font-weight:bold;font-size:18px;color:#1A1A1A;line-height:24px;text-align:left;padding-top:40px}.orderBox .detailBox .orderDetail{width:calc(100% - 200px);height:100px;display:inline-flex;flex-wrap:wrap;flex-direction:column;padding-left:40px;box-sizing:border-box}.orderBox .detailBox .orderDetail div{height:20px;margin-top:10px;font-size:14px}.orderBox .detailBox .orderFunc{display:inline-flex;width:200px;height:100px;justify-content:space-around;flex-direction:column;align-items:center}.orderBox .detailBox .orderButton{width:195px;height:45px;background:#D0121B;border-radius:1px;color:#FFFFFF}.orderBox .detailBox .orderButton:hover{background:#A90008}.orderBox .detailBox .orderStatus{height:200px;width:100%;box-sizing:border-box;display:flex;align-items:center}.orderBox .detailBox .orderStatus :global .ant-steps-item-finish>.ant-steps-item-container>.ant-steps-item-tail::after{background-color:#FFC25F;position:relative;top:4px;left:15px;width:96%}.orderBox .detailBox .orderStatus :global .ant-steps-item-wait>.ant-steps-item-container>.ant-steps-item-tail::after{background-color:none;border-bottom:1px dashed #CECDCB;position:relative;top:4px;left:15px;width:96%}.orderBox .detailBox .orderStatus :global .ant-steps-item-icon{height:40px;width:40px;box-sizing:border-box;border:1px solid #FFC25F;border-radius:40px;background:#FFF9F0;line-height:40px;text-align:center;color:#937B54;font-size:14px}.orderBox .detailBox .orderStatus :global .ant-steps-item-wait .ant-steps-item-icon>.ant-steps-icon{color:#937B54}.orderBox .detailBox .orderStatus :global .ant-steps-item-finish .ant-steps-item-icon{background:url(../../public/images/stepx.png) no-repeat;background-size:100% 100%}.orderBox .detailBox .orderStatus :global .ant-steps-item-finish .ant-steps-item-icon .ant-steps-icon{display:none}.orderBox .detailBox .orderStatus :global .ant-steps-item>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title{font-size:14px;color:#000}.orderBox .detailBox .orderStatus :global .ant-steps-item>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title .ant-steps-item-subtitle{font-size:12px;color:#937B54;line-height:10px}.orderBox .pagination{margin-top:30px;display:flex;justify-content:flex-end}
.userCenter {
padding: 10px;
width: 1226px;
margin: 0 auto;
display: flex;
}
.orderBox {
width: 1022px;
margin-left: 12px;
box-sizing: border-box;
padding: 20px 30px 50px;
background-color: #fff;
box-sizing: border-box;
position: relative;
.baseTitle {
font-size: 16px;
color: #1A1A1A;
}
.moreButton {
position: absolute;
right: 30px;
top: 20px;
color: #888888;
font-size: 12px;
cursor: pointer;
display: flex;
align-items: center;
img {
margin-right: 5px;
}
}
.detailBox {
height: 400px;
margin-top: 10px;
border-top: 1px solid #F4F4F4;
.orderSn {
width: 100%;
height: 24px;
font-weight: bold;
font-size: 18px;
color: #1A1A1A;
line-height: 24px;
text-align: left;
padding-top: 40px;
}
.orderDetail {
width: calc(100% - 200px);
height: 100px;
display: inline-flex;
flex-wrap: wrap;
flex-direction: column;
padding-left: 40px;
box-sizing: border-box;
div {
height: 20px;
margin-top: 10px;
font-size: 14px;
}
}
.orderFunc {
display: inline-flex;
width: 200px;
height: 100px;
justify-content: space-around;
flex-direction: column;
align-items: center;
}
.orderButton {
width: 195px;
height: 45px;
background: #D0121B;
border-radius: 1px;
color: #FFFFFF;
&:hover {
background: #A90008;
}
}
.orderStatus {
height: 200px;
width: 100%;
box-sizing: border-box;
display: flex;
align-items: center;
:global {
.ant-steps-item-finish>.ant-steps-item-container>.ant-steps-item-tail::after {
background-color: #FFC25F;
position: relative;
top: 4px;
left: 15px;
width:96%;
}
.ant-steps-item-wait>.ant-steps-item-container>.ant-steps-item-tail::after {
background-color: none;
border-bottom:1px dashed #CECDCB;
position: relative;
top: 4px;
left: 15px;
width:96%;
}
.ant-steps-item-icon{
height:40px;
width:40px;
box-sizing: border-box;
border:1px solid #FFC25F;
border-radius: 40px;
background: #FFF9F0;
line-height: 40px;
text-align: center;
color:#937B54;
font-size: 14px;
}
.ant-steps-item-wait .ant-steps-item-icon >.ant-steps-icon{
color:#937B54;
}
.ant-steps-item-finish .ant-steps-item-icon {
background: url(../../public/images/stepx.png) no-repeat;
background-size: 100% 100%;
.ant-steps-icon{display: none;}
}
.ant-steps-item>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title{
font-size: 14px;
color:#000;
.ant-steps-item-subtitle{
font-size: 12px;
color:#937B54;
line-height: 10px;
}
}
}
}
}
.pagination {
margin-top:30px;
display: flex;
justify-content: flex-end;
}
}
import styles from './index.module.scss'
import {useState, useEffect} from 'react'
import { Table, Pagination, Steps } from "antd";
import type { TableColumnsType } from 'antd';
import useRequest from "@/hooks/useRequest"
import { DataType } from "@/types/orderTypes"
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import Nav from "@/components/navigation";
import style from './index.module.scss'
import { GetServerSideProps } from 'next';
import { getCateList } from "@/server/getCateList";
import type {ResponseTypeCateList} from '@/components/Header/components/NavBig/types'
import { useRouter } from 'next/router';
import { useQq } from '@/hooks/useQq';
export const getStaticProps: GetServerSideProps = async () => {
return getCateList()
}
const OrderDetail = (props:{cateList:ResponseTypeCateList}) => {
const router = useRouter()
const { query } = router
const { QQURL} = useQq()
const { cateList } = props
const { request: userRequest } = useRequest<any>({ manual: true })
const [goodsList, setGoodsList] = useState<any>([])
const [current, setCurrent] = useState(1);
const [pageSize, setPageSize] = useState(5);
const [total, setTotal] = useState(0);
const [status, setStatus] = useState(0);
const [orderDetail, setOrderDetail] = useState<any>({});
const [currency,setCurrency]=useState("¥")
const [ orderId, setOrderId ] = useState<any>();
const columns: TableColumnsType<DataType> = [
{ title: '序号', dataIndex: 'name', key: 'name', render:(text, record, index) => { return <span>{index + 1}</span>} },
{ title: '型号/品牌', dataIndex: 'sku_name', key: 'sku_name', render:(text, record, index) => { return <span>{record.goods_name}/{record.brand_name}</span>} },
{ title: '数量', dataIndex: 'goods_number', key: 'goods_number' },
{ title: '单价', dataIndex: 'goods_price', key: 'goods_price', render:(text, record, index) => { return <span>{currency}{record.goods_price}</span>} },
{ title: '小计', dataIndex: 'goods_amount', key: 'goods_amount' , render:(text, record, index) => { return <span>{currency}{record.goods_amount}</span>} },
{ title: '明细备注', dataIndex: 'web_order_remark', key: 'web_order_remark' }
]
const steps = [
{
key: '0',
subTitle: '2024-11-13 10:45:27',
title: '提交订单'
},
{
title: '待审核',
key: '1',
},
{
title: '待付款',
key: '2',
},
{
title: '待发货',
key: '3',
},
{
title: '已完成',
key: '4',
}
]
useEffect(() => {
setOrderId(query.order_id)
}, [query.order_id])
useEffect(() => {
handleOrderListInit()
}, [orderId, current, pageSize])
useEffect(() => {
handleDataInit()
}, [orderId])
const handleDataInit = async () => {
if(!orderId) return
const tatusSummaryResponse = await userRequest({
url: '/api/order/webOrderList',
method: 'post',
data: {
order_id: orderId
}
})
if (tatusSummaryResponse.code === 0 && tatusSummaryResponse.data.list && tatusSummaryResponse.data.list.length) {
setOrderDetail(tatusSummaryResponse.data.list[0])
setCurrency(tatusSummaryResponse.data.list[0].iso_code=='CNY'?'¥':'$')
setStatus(tatusSummaryResponse.data.list[0].web_order_status)
}
}
const handleOrderListInit = async () => {
const orderParam = {
order_id: orderId,
page: current,
limit: pageSize
}
if(!orderId){return}
const webOrderListResponse = await userRequest({
url: `/api/order/webOrderItemList`,
method: 'post',
data: orderParam,
})
if (webOrderListResponse.code === 0) {
setGoodsList(webOrderListResponse.data.list)
setTotal(webOrderListResponse.data.total)
}
}
const handlePageChange = (page:number, pageSize:number) => {
setCurrent(page)
setPageSize(pageSize)
}
const handlePayment = () => {
router.push(`/orderResult?type=2&orderId=${query.order_id}`)
}
return (
<>
<Header {...cateList}/>
<div className={style.userCenter}>
<Nav></Nav>
<div className={styles.orderBox}>
<div className={styles.baseTitle}>订单详情</div>
<a className={styles.moreButton} href={QQURL} target='_blank' rel="noreferrer">
<img src="images/customerService.png" />
我的客服
</a>
<div className={styles.detailBox}>
<div className={styles.orderSn}>
订单号:{orderDetail.order_sn}
</div>
<div className={styles.orderDetail}>
<div>下单时间:{orderDetail.create_time}</div>
<div>当前状态:{orderDetail.web_order_status_text}</div>
<div>订单货值:{currency+orderDetail.order_amount}</div>
<div>使用优惠:{currency}0.00</div>
<div>物流费用:{currency}0.00</div>
<div>其他费用:{currency}0.00</div>
</div>
<div className={styles.orderFunc}>
{(orderDetail.web_order_status === 2) && (<button className={styles.orderButton} onClick={() => handlePayment()}>立即付款</button>)}
<div>
订单合计金额:{currency+orderDetail.order_amount}
</div>
</div>
<div className={styles.orderStatus}>
<Steps
labelPlacement="vertical"
current={status}
items={steps}
status="finish"/>
</div>
</div>
<Table<DataType>
size="small"
bordered={true}
pagination={false}
columns={columns}
rowKey={(record) => record?.rec_id}
expandable={{
expandIcon: (r) => null,
defaultExpandAllRows: true,
expandedRowRender: (record) => {
return (
<div style={{ fontSize: '12px' }}>
<span style={{ marginRight: '20px' }}>最新进度:{record.latest_log_time}</span>
<span style={{ marginRight: '20px' }}>状态:{record.latest_log_status_text}</span>
<span style={{ marginRight: '20px' }}>{record.latest_log}</span>
</div>
)
},
rowExpandable: (record) => record.name !== 'Not Expandable',
}}
dataSource={goodsList}
/>
<div className={styles.pagination}>
<Pagination
showQuickJumper
showSizeChanger
current={current}
pageSize={pageSize}
pageSizeOptions={[5, 10]}
total={total}
showTotal={(total) => `共 ${total} 条记录`}
onChange={handlePageChange}/>
</div>
</div>
</div>
<Footer />
</>
)
}
export default OrderDetail
\ No newline at end of file
.resultBox {
padding: 10px;
width: 1226px;
margin: 0 auto;
.resultBottom {
width: 100%;
height: 130px;
background: #FFFFFF;
padding: 25px 60px;
font-size: 12px;
box-sizing: border-box;
margin-top: 20px;
}
.resultTop {
text-align: center;
padding: 80px;
background-color: #FFFFFF;
box-sizing: border-box;
.title {
margin-top: 35px;
font-weight: bold;
font-size: 22px;
color: #313131;
}
.subTitle {
width: 400px;
display: flex;
justify-content: space-between;
margin: 20px auto;
}
.status {
font-size: 18px;
color: #D0121B;
margin-top: 50px;
}
.centerButton {
width: 195px;
height: 45px;
background: #FF9A00;
border-radius: 1px;
color: #fff;
margin-top: 20px;
cursor: pointer;
}
}
.orderTop {
text-align: center;
padding: 35px 43px 60px;
background-color: #FFFFFF;
box-sizing: border-box;
.orderContent {
font-weight: bold;
font-size: 18px;
color: #313131;
margin-bottom: 20px;
> span {
margin-left: 10px;
color: #CC0000;
font-weight: bold;
}
}
.payType {
width: 100%;
padding-top: 45px;
text-align: left;
border-top: 1px solid #EEE;
}
.typeBox {
width: 100%;
text-align: center;
>span {
display: inline-flex;
width: 182px;
height: 74px;
background: #FDFBF7;
border-radius: 1px;
border: 1px solid #FF9A00;
align-items: center;
justify-content: space-around;
cursor: pointer;
}
}
.invoiceBox {
width: 802px;
height: 158px;
background: #FDFBF7;
border-radius: 1px;
margin: 30px auto;
font-weight: bold;
font-size: 18px;
color: #313131;
line-height: 20px;
padding: 20px;
box-sizing: border-box;
> div {
margin-bottom: 20px;
}
.left {
display: inline-block;
width: 30%;
text-align: right;
margin-right: 10px;
font-weight: bold;
}
.right {
display: inline-block;
width: 40%;
text-align: left;
font-weight: bold;
}
}
.uploadButtton {
width: 152px;
height: 68px;
background: #D0121B;
color: #fff;
cursor: pointer;
}
}
}
import {useState, useEffect} from 'react'
import { Upload } from "antd"
import useRequest from "@/hooks/useRequest"
import Footer from "@/components/Footer"
import Header from "@/components/Header"
import style from './index.module.scss'
import { GetServerSideProps } from 'next'
import { getCateList } from "@/server/getCateList"
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
import { useRouter } from 'next/router'
import { useToast } from '@/hooks/useToast'
export const getStaticProps: GetServerSideProps = async () => {
return getCateList()
}
const OrderDetail = (props:{cateList:ResponseTypeCateList}) => {
const router = useRouter()
const { query } = router
const { cateList } = props
const { request: userRequest } = useRequest<any>({ manual: true })
const [type, setType] = useState(0) // 1: 订单结算结果 2: 立即支付
const [orderDetail, setOrderDetail] = useState<any>({});
const [ orderId, setOrderId ] = useState<any>();
const { message }=useToast()
useEffect(() => {
if (query?.type) setType(Number(query.type))
if (query?.orderId) setOrderId(query.orderId)
}, [query])
useEffect(() => {
handleDataInit()
}, [orderId])
const handleDataInit = async () => {
if(!orderId) return
const isOrder = (type === 1)
const tatusSummaryResponse = await userRequest({
url: isOrder ? '/api/order/webOrderList' : '/api/order/webOrderPaymentDetail',
method: 'post',
data: {
order_id: orderId
}
})
if (tatusSummaryResponse.code === 0 && tatusSummaryResponse.data) {
if (!isOrder) setOrderDetail(tatusSummaryResponse.data)
else if (tatusSummaryResponse.data.list && tatusSummaryResponse.data.list.length) setOrderDetail(tatusSummaryResponse.data.list[0])
}
}
const handleGoCenter = () => {
router.push('/myOrder')
}
const handleUpload = async (file: any) => {
const param = {
order_id: orderId,
file: file.file
}
const res = await userRequest({
url: '/api/order/webOrderPaymentAttachmentUpload',
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
},
data: param
})
if (res.code === 0) {
message('上传成功!')
router.push('/myOrder')
} else message(res.msg || '上传失败,请重试!')
}
return (
<>
<Header {...cateList}/>
<div className={style.resultBox}>
{
(type === 1) ? (
<div className={style.resultTop}>
<img src="/images/result.png"/>
<div className={style.title}>您的订单已提交成功!</div>
<div className={style.subTitle}>
<span>订单号:{orderDetail?.order_sn}</span>
<span>订单金额:{orderDetail?.order_amount}</span>
</div>
<div className={style.status}>请等待订单审核</div>
<button className={style.centerButton} onClick={handleGoCenter}>订单中心</button>
</div>
) : (
<div className={style.orderTop}>
<div className={style.orderContent}>
订单已经审核通过,请尽快付款!订单号:
<span>
{orderDetail?.order_sn}
</span>
</div>
<div className={style.orderContent} style={{marginBottom: '32px'}}>
应付金额:
<span>
{orderDetail?.order_amount}
</span>
</div>
<div className={style.payType}>
<div>线上支付:</div>
</div>
<div className={style.typeBox}>
<span>
<img src="/images/wallet.png"/>
转账支付
</span>
</div>
<div className={style.invoiceBox}>
<div>
<span className={style.left}>公司名称:</span>
<span className={style.right}>{orderDetail?.com_name}</span>
</div>
<div>
<span className={style.left}>开户银行:</span>
<span className={style.right}>{orderDetail?.bank_name}</span>
</div>
<div>
<span className={style.left}>银行账号:</span>
<span className={style.right}>{orderDetail?.bank_account}</span>
</div>
</div>
<Upload customRequest={handleUpload} showUploadList={false}>
<button className={style.uploadButtton}>上传银行水单</button>
</Upload>
</div>
)
}
<div className={style.resultBottom}>
<div>
声明:
</div>
<div style={{marginTop: '10px'}}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. Proin gravida dolor sit amet lacus accumsan et viverra justo commodo. Proin sodales pulvinar sic tempor. Sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam fermentum, nulla luctus pharetra vulputate, felis tellus mollis orci, sed rhoncus pronin sapien nunc accuan eget.
</div>
</div>
</div>
<Footer />
</>
)
}
export default OrderDetail
\ No newline at end of file
.shopBox{margin:20px auto;width:1226px;position:relative}.shopLayer{width:1226px;background-color:#fff;box-sizing:border-box;padding:20px 25px}.shopLayer .basicModule{width:100%;height:175px;background-color:#fff;box-sizing:border-box}.shopLayer .basicModule .basicTitle{height:20px;font-size:14px;line-height:20px}.shopLayer .basicModule .subTitle{padding:10px 30px 0}.shopLayer .basicModule .subTitle>span{font-weight:bold;color:#000;margin-right:20px}.shopLayer .typeButton{width:115px;height:24px;background:#FFAE33;border-radius:1px;color:#FFFFFF;font-size:14px;cursor:pointer;margin-left:10px}.shopLayer .changeButton{width:75px;height:20px;font-size:12px;color:#595959;background:#FFFFFF;border-radius:1px;border:1px solid #B0B0B0;cursor:pointer}.shopLayer .changeButton:hover{color:#000}.shopLayer .basicContent{padding:10px 60px;box-sizing:border-box;height:100%;display:flex;flex-direction:column;flex-wrap:wrap;font-size:14px}.shopLayer .basicContent .basicItem{width:calc(50% - 5px);display:inline-flex;height:30px;align-items:center;color:#808080}.shopLayer .basicContent .basicItem>span:last-child{color:#000;margin-left:10px}.shopLayer .layerContain{margin-top:60px}.layerFooter{width:100%;height:300px;margin-top:20px;align-items:center;background-color:#fff;box-sizing:border-box;padding-left:45px;text-align:right;padding:20px 40px}.layerFooter .accountButton{width:170px;height:68px;background:#D0121B;margin-top:30px;color:#fff;font-weight:bold;cursor:pointer}.layerFooter .countLine{margin-bottom:10px}.disNumber{display:inline-block;width:100px;margin-left:15px;text-align:left}.keyNumbers{color:#CC0000;font-weight:bold;margin-top:20px}.announce{width:100%;height:130px;background:#FFFFFF;padding:25px 60px;font-size:12px;box-sizing:border-box;margin-top:20px}.invoiceType{display:inline-block;width:100px;text-align:right;margin-left:-10px}
.shopBox {
margin: 20px auto;
width: 1226px;
position: relative;
}
.shopLayer {
width: 1226px;
background-color: #fff;
box-sizing: border-box;
padding: 20px 25px;
.basicModule {
width: 100%;
height: 175px;
background-color: #fff;
box-sizing: border-box;
.basicTitle {
height: 20px;
font-size: 14px;
line-height: 20px;
}
.subTitle {
padding: 10px 30px 0;
> span {
font-weight: bold;
color:#000;
margin-right: 20px;
}
}
}
.typeButton {
width: 115px;
height: 24px;
background: #FFAE33;
border-radius: 1px;
color: #FFFFFF;
font-size: 14px;
cursor: pointer;
margin-left: 10px;
}
.changeButton {
width: 75px;
height: 20px;
font-size: 12px;
color: #595959;
background: #FFFFFF;
border-radius: 1px;
border: 1px solid #B0B0B0;
cursor: pointer;
&:hover{
color:#000;
}
}
.basicContent {
padding: 10px 60px;
box-sizing: border-box;
height: 100%;
display: flex;
flex-direction: column;
flex-wrap: wrap;
font-size: 14px;
.basicItem {
width: calc(50% - 5px);
display: inline-flex;
height: 30px;
align-items: center;
color:#808080;
>span:last-child {
color:#000;
margin-left: 10px;
}
}
}
.layerContain {
margin-top: 60px;
}
}
.layerFooter {
width: 100%;
height: 300px;
margin-top: 20px;
align-items: center;
background-color: #fff;
box-sizing: border-box;
padding-left: 45px;
text-align: right;
padding: 20px 40px;
.accountButton {
width: 170px;
height: 68px;
background: #D0121B;
margin-top: 30px;
color: #fff;
font-weight: bold;
cursor: pointer;
}
.countLine {
margin-bottom: 10px;
}
}
.disNumber {
display: inline-block;
width: 100px;
margin-left: 15px;
text-align: left;
}
.keyNumbers {
color: #CC0000;
font-weight: bold;
margin-top: 20px;
}
.announce {
width: 100%;
height: 130px;
background: #FFFFFF;
padding: 25px 60px;
font-size: 12px;
box-sizing: border-box;
margin-top: 20px;
}
.invoiceType{
display: inline-block;
width: 100px;
text-align: right;
margin-left: -10px;
}
\ No newline at end of file
import styles from './index.module.scss'
import { Table, TableColumnsType, Button } from "antd"
import { useState, useEffect } from 'react'
import Link from 'next/link'
import Footer from "@/components/Footer"
import Header from "@/components/Header"
import { DataType } from "@/types/orderTypes"
import useRequest from "@/hooks/useRequest"
import { useToast } from '@/hooks/useToast'
import { GetServerSideProps } from 'next'
import { getCateList } from "@/server/getCateList"
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
import { useRouter } from 'next/router'
import InvoiceSelector from '@/components/InvoiceSelector'
import AddressSelector from '@/components/AddressSelector'
export const getServerSideProps: GetServerSideProps = async () => {
return getCateList()
}
const TopH = (props: { cateList: ResponseTypeCateList }) =>{
const { message } = useToast()
const router = useRouter()
const [sePlace, setSePlace] = useState<any>('')
const [shopList, setShopList] = useState<any>([])
const [disList, setDisList] = useState<any>([])
const [disCn, setDisCn] = useState<any>([])
const [disUs, setDisUs] = useState<any>([])
const [disObj, setDisObj] = useState<any>()
const { request: userRequest } = useRequest<any>({ manual: true, loading: true })
const [defaultInvoice, setDefaultInvoice] = useState<any>();
const [defaultAddress, setDefaultAddress] = useState<any>();
const [arrInvoice, setArrInvoice] = useState<any>();
const [arrAddress, setArrAddress] = useState<any>();
const {query}=router
const [idList, setIdList] = useState<any>([])
const [sourceType, setSourceType] = useState<any>('') // 1 直接购买,2 购物车结算
const [showInvoice, setShowInvoice] = useState<any>(false)
const [showAddress, setShowAddress] = useState<any>(false)
const [goodNumber, setGoodNumber] = useState<any>(0)
const columns: TableColumnsType<DataType> = [
{ title: '序号', dataIndex: 'name', key: 'name', render:(text, record, index) => { return <span>{index + 1}</span>}},
{ title: '型号/品牌', dataIndex: 'sku_name', key: 'sku_name',
render:(text, record, index) => {
return <span>{record.sku_name || record.goods_name}/{record.brand_name}</span>}
},
{ title: '渠道', dataIndex: 'supplier_name', key: 'supplier_name' },
{ title: '单价', dataIndex: 'goods_price', key: 'goods_price',
render:(text, record, index) => {
return <span>{record.delivery_place_type === '2' ? '$' : '¥'}{record.goods_price}</span>
}
},
{
title: '数量',
dataIndex: 'goods_number',
key: 'goods_number',
width: 120
},
{ title: '小计', dataIndex: 'goods_amount', key: 'goods_amount',
render:(text, record, index) => {
return <span>{record.delivery_place_type === '2' ? '$' : '¥'}{record.goods_amount}</span>
}
},
{
title: '批次备注',
dataIndex: 'remark',
key: 'remark',
width: 120
}
]
useEffect(() => {
if (query?.sourceType) setSourceType(String(query?.sourceType))
if (query?.id) setIdList(String(query?.id).split(','))
if (query?.deliveryPlaceType) setSePlace(String(query?.deliveryPlaceType))
if (query?.number) setGoodNumber(Number(query?.number))
handleDataInit()
}, [query,sourceType])
useEffect(() => {
handleInvoiceInit()
handleAddressInit()
}, [query])
useEffect(() => {
const disArray:any[] = []
shopList.filter((shopItem:any) => {
const isIn = idList.includes(shopItem.sku_id)
if (isIn && sourceType === '1') {
shopItem.goods_number = Number(goodNumber)
shopItem.delivery_place_type = sePlace
disArray.push(shopItem)
} else if (isIn && sourceType === '2' && shopItem.delivery_place_type === sePlace) disArray.push(shopItem)
})
const param = {
goods_list: disArray,
delivery_place_type: sePlace
}
if(disArray.length>0){handleOrderCount(param)}
}, [shopList])
const handleOrderCount = async (param: any) => {
const res = await userRequest({
url: `/api/order/calculateOrder`,
method: 'post',
data: param
})
if (res?.code === 0 && res?.data) {
setDisObj(res.data)
res.data?.goods_list && setDisList(res.data.goods_list)
if (sePlace === '1') setDisCn(res.data?.order_amount)
else setDisUs(res.data?.order_amount)
}
}
const handleInvoiceInit = async () => {
const res = await userRequest({
url: `/api/userInfo/userInvoiceList?limit=50&page=1`,
method: 'get'
})
if (res?.code === 0 && res.data.list.length) {
setArrInvoice(res.data.list)
setDefaultInvoice(res.data.list[0])
}
}
const handleAddressInit = async () => {
const res = await userRequest({
url: `/api/userInfo/userAddressList?limit=50&page=1`,
method: 'get'
})
if (res?.code === 0 && res.data.list.length) {
setArrAddress(res.data.list)
setDefaultAddress(res.data.list[0])
}
}
const handleLineDelete = (data: any) => {
idList.splice(idList.findIndex((id:any) => id === data.sku_id), 1)
setIdList(JSON.parse(JSON.stringify(idList)))
}
const handleDataInit = async () => {
if (sourceType == '2') {
const res = await userRequest({
url: '/api/cart/cartList',
method: 'post'
})
if (res?.code === 0){
let arr_=res?.data?.cart_list||[]
const newArr=arr_.filter((item:any)=>{
if(idList.indexOf(item.sku_id)!=-1){
return item
}
})
setShopList(newArr)
}
} else if (sourceType == '1') {
const res = await userRequest({
url: `/api/goodsSku/getGoodsSkuDetail?sku_id=${idList[0]}&real_time=1`,
method: 'get'
})
if (res?.code === 0 && res?.data.sku_info) {
const newShopList=[res.data.sku_info]
setShopList(newShopList)
}else{
message('没有查询到相关商品!')
}
}
}
const handleOrderSubmit = async () => {
const param = {
goods_list: disList.map((disItem:any) => {
return {
...disItem,
web_order_remark: disItem.remark
}
}),
web_user_address: {
shipping_type: 1,
...defaultAddress
},
web_user_invoice: defaultInvoice,
web_order_remark: '',
source_type: sourceType,
delivery_place_type: sePlace
}
const res = await userRequest({
url: '/api/order/webOrderAdd',
method: 'post',
data: param
})
if (res?.code === 0) {
message('提交成功!')
router.push(`/orderResult?type=1&&orderId=${res?.data?.order_id}`)
} else message(res?.msg)
}
const handleInvoiceSelect = (data: any) => {
if (data) setDefaultInvoice(data)
setShowInvoice(false)
}
const handleAddressSelect = (data: any) => {
if (data) setDefaultAddress(data)
setShowAddress(false)
}
return (
<>
<Header {...props.cateList} />
<div className={styles.shopBox}>
<div className={styles.shopLayer}>
{sePlace === '1' && (
<div className={styles.basicModule}>
<div className={styles.basicTitle}>
发票信息
</div>
<div className={styles.subTitle}>
<span className={styles.invoiceType}>{defaultInvoice?.invoice_type_cn}</span>
<span>{defaultInvoice?.tax_title}</span>
{
arrInvoice?
<button className={styles.changeButton} onClick={() => setShowInvoice(true)}>更换发票</button>
: <Link href={`/invoice`}><button className={styles.changeButton} >设置发票</button></Link>
}
</div>
<div className={styles.basicContent} style={{height: 'calc(100% - 65px)'}}>
<div className={styles.basicItem} style={{marginLeft: '-14px'}}>
<span>税务登记号:</span>
<span>{defaultInvoice?.tax_no}</span>
</div>
<div className={styles.basicItem}>
<span>注册电话:</span>
<span>{defaultInvoice?.company_phone}</span>
</div>
<div className={styles.basicItem}>
<span>开户银行:</span>
<span>{defaultInvoice?.bank_name}</span>
</div>
<div className={styles.basicItem}>
<span>开户账号:</span>
<span>{defaultInvoice?.bank_account}</span>
</div>
<div className={styles.basicItem}>
<span>注册地址:</span>
<span>{defaultInvoice?.company_address}</span>
</div>
</div>
</div>
)}
<div className={styles.basicModule} style={{height: '150px'}}>
<div className={styles.basicTitle}>
地址信息
</div>
<div style={{marginLeft: '60px', marginTop: '10px'}}>
<span>配送方式:</span>
<button className={styles.typeButton}>快递配送</button>
</div>
<div className={styles.basicContent} style={{height: 'calc(100% - 30px)'}}>
<div className={styles.basicItem} style={{marginLeft: '14px'}}>
<span>联系人:</span>
<span>{defaultAddress?.consignee}</span>
</div>
<div className={styles.basicItem}>
<span>联系电话:</span>
<span>{defaultAddress?.telphone}</span>
</div>
<div className={styles.basicItem}>
<span>联系地址:</span>
<span style={{marginLeft: '10px',color:"#000"}}>
{defaultAddress?.nation_id_cn}
{defaultAddress?.province_cn}
{defaultAddress?.city_cn}
{defaultAddress?.district_cn}
{defaultAddress?.detail_address}
</span>
{
arrAddress?
<button
className={styles.changeButton}
style={{marginLeft: '20px'}}
onClick={() => setShowAddress(true)}>
更改地址
</button>
: <Link href={`/address`}><button className={styles.changeButton} >设置地址</button></Link>
}
</div>
<div className={styles.basicItem}>
<span>联系邮箱:</span>
<span>{defaultAddress?.email}</span>
</div>
</div>
</div>
<div className={styles.layerContain}>
<Table<DataType>
size="small"
bordered={true}
pagination={false}
rowKey={(record) => record?.sku_id}
columns={columns}
dataSource={disList}
/>
</div>
</div>
<div className={styles.layerFooter}>
<div className={styles.countLine}>
物料货值:
<span className={styles.disNumber} style={{fontWeight: 'bold'}}>
{(['0', '1'].includes(sePlace)) && (<> ¥{disCn} </>)}
{(['0', '2'].includes(sePlace)) && (<> ${disUs} </>)}
</span>
</div>
<div className={styles.countLine}>
优惠金额:
<span className={styles.disNumber} style={{fontWeight: 'bold'}}>{sePlace==2?'$':'¥'}{disObj?.discount_amount}</span>
</div>
<div className={styles.countLine}>
物流费用:
<span className={styles.disNumber} style={{fontWeight: 'bold'}}>{sePlace==2?'$':'¥'}{disObj?.logistics_amount}</span>
</div>
<div className={styles.countLine}>
订单合计金额:
<span className={`${styles.keyNumbers} ${styles.disNumber}`} style={{fontSize: '20px', fontWeight: 'bold'}}>
{(['0', '1'].includes(sePlace)) && (<> ¥{disCn} </>)}
{(['0', '2'].includes(sePlace)) && (<> ${disUs} </>)}
</span>
</div>
<button className={styles.accountButton} onClick={handleOrderSubmit}>提交订单</button>
</div>
<div className={styles.announce} style={{display:'none'}}>
<div>
声明:
</div>
<div style={{marginTop: '10px'}}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. Proin gravida dolor sit amet lacus accumsan et viverra justo commodo. Proin sodales pulvinar sic tempor. Sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam fermentum, nulla luctus pharetra vulputate, felis tellus mollis orci, sed rhoncus pronin sapien nunc accuan eget.
</div>
</div>
</div>
<Footer />
<InvoiceSelector status={showInvoice} onMessageChange={handleInvoiceSelect}/>
<AddressSelector status={showAddress} onMessageChange={handleAddressSelect}/>
</>
)
}
export default TopH
\ No newline at end of file
.loginPage{background:#fff;padding:80px 0;height:740px;width:100%;border-top:1px solid #FF9A00;position:relative}.loginPage .loginBox{width:400px;height:100%;position:absolute;left:50%;transform:translate(-50%);text-align:center}.loginPage .loginBox .typeBox{padding:10px 40px 50px;display:flex;justify-content:center}.loginPage .loginBox .loginInput{width:378px;height:43px;background:#F8F8F8;border-radius:1px;border:1px solid #E2E2E2;margin-bottom:25px;padding-left:20px}.loginPage .loginBox .cursorPointer{cursor:pointer}.loginPage .loginBox .areaChoose{display:inline-block;width:145px;background:#F8F8F8;border-radius:1px;border:1px solid #E2E2E2;margin-bottom:25px;padding-left:10px;height:45px;vertical-align:bottom;cursor:pointer}.loginPage .loginBox .areaInput{display:inline-block;width:238px;background:#F8F8F8;border-radius:1px;border:1px solid #E2E2E2;margin-bottom:25px;padding-left:15px;height:43px}.loginPage .loginBox .codeButton{display:inline-block;width:100px;height:45px;background:#FF9A00;border-radius:1px;font-size:14px;color:#FFFFFF;cursor:pointer;vertical-align:center}.loginPage .loginBox .codeButton.dis{background:#ccc;cursor:not-allowed}.loginPage .loginBox .registerInput{width:278px;height:43px;background:#F8F8F8;border-radius:1px;border:1px solid #E2E2E2;margin-bottom:25px;padding-left:20px;vertical-align:top}.loginPage .loginBox .registerLoginButton{width:400px;height:43px;background:#FF9A00;border-radius:1px;font-size:20px;color:#FFFFFF;margin-top:15px;cursor:pointer}.loginPage .loginBox .showMsg{position:absolute;left:0;color:#D0121B;font-size:12px;line-height:16px;margin-top:-15px}.loginPage .loginBox .completeBox{display:flex;align-items:flex-start;justify-content:center;height:140px}.loginPage .loginBox .completeBox::after{display:flex;content:"✔";width:75px;height:75px;background:#11AA66;color:#fff;font-size:60px;border-radius:50%;align-items:self-end;justify-content:center}
.loginPage{
background: #fff;
padding:80px 0;
height: 740px;
width: 100%;
border-top: 1px solid #FF9A00;
position: relative;
.loginBox {
width: 400px;
height: 100%;
position: absolute;
left: 50%;
transform: translate(-50%);
text-align: center;
.typeBox {
padding: 10px 40px 50px;
display: flex;
justify-content: center;
}
.loginInput{
width: 378px;
height: 43px;
background: #F8F8F8;
border-radius: 1px;
border: 1px solid #E2E2E2;
margin-bottom: 25px;
padding-left: 20px;
}
.cursorPointer{
cursor: pointer;
}
.areaChoose {
display: inline-block;
width: 145px;
background: #F8F8F8;
border-radius: 1px;
border: 1px solid #E2E2E2;
margin-bottom: 25px;
padding-left: 10px;
height: 45px;
vertical-align: bottom;
cursor: pointer;
}
.areaInput {
display: inline-block;
width: 238px;
background: #F8F8F8;
border-radius: 1px;
border: 1px solid #E2E2E2;
margin-bottom: 25px;
padding-left: 15px;
height: 43px;
}
.codeButton {
display: inline-block;
width: 100px;
height: 45px;
background: #FF9A00;
border-radius: 1px;
font-size: 14px;
color: #FFFFFF;
cursor: pointer;
vertical-align: center;
&.dis{
background: #ccc;
cursor: not-allowed;
}
}
.registerInput{
width: 278px;
height: 43px;
background: #F8F8F8;
border-radius: 1px;
border: 1px solid #E2E2E2;
margin-bottom: 25px;
padding-left: 20px;
vertical-align: top;
}
.registerLoginButton {
width: 400px;
height: 43px;
background: #FF9A00;
border-radius: 1px;
font-size: 20px;
color: #FFFFFF;
margin-top: 15px;
cursor: pointer;
}
.showMsg {
position: absolute;
left: 0;
color: #D0121B;
font-size: 12px;
line-height: 16px;
margin-top: -15px;
}
.completeBox {
display: flex;
align-items: flex-start;
justify-content: center;
height: 140px;
&::after {
display: flex;
content: "✔";
width: 75px;
height: 75px;
background: #11AA66;
color: #fff;
font-size: 60px;
border-radius: 50%;
align-items: self-end;
justify-content: center;
}
}
}
}
\ No newline at end of file
import React, { use, useState, useRef, useEffect } from 'react';
import useRequest from "@/hooks/useRequest"
import style from './index.module.scss'
import Footer from "@/components/Footer";
import TopH from "@/components/Header/components/TopH"
import SearchH from "@/components/Header/components/SearchH"
import { useRouter } from 'next/router';
import { useToast } from '@/hooks/useToast';
import { useCookies } from "@/hooks/useCookies"
const Page = () => {
const [user, setUser] = useState<any>();
const [count, setCount] = useState('');
const [password, setPassword] = useState('');
const [rePassword, setRePassword] = useState('');
const [area, setArea] = useState('0086');
const [code, setCode] = useState('');
const [step, setStep] = useState(1);
const [second, setSecond] = useState(5);
const [showMsg, setShowMsg] = useState(false);
const [msg, setMsg] = useState('');
const {message} = useToast()
const messageRef = useRef(message);
const {setCookie} = useCookies()
const handleCountChange = (e:any) => setCount(e.target.value);
const handlePasswordChange = (e:any) => setPassword(e.target.value);
const handleRePasswordChange = (e:any) => setRePassword(e.target.value);
const handleAreaChange = (e:any) => setArea(e.target.value);
const handleCodeChange = (e:any) => setCode(e.target.value);
const { request: loginRequest } = useRequest<any>({ manual: true })
const router = useRouter()
const codeTimer = useRef<any>();
const [codeText,setCodeText]=useState<string>("发送验证码")
const [codeTimeVal,setCodeTimeVal]=useState<number>(60)
useEffect(() => {
if (codeText === '发送验证码') {
return;
}
codeTimer.current = setInterval(() => {
setCodeTimeVal((prevCodeTimeVal) => {
const newTime = prevCodeTimeVal - 1;
if (newTime < 1) {
clearInterval(codeTimer.current);
setCodeText('发送验证码');
setCodeTimeVal(60);
return 60;
}
setCodeText(`重发(${newTime}S)`);
return newTime;
});
}, 1000);
return () => {
if (codeTimer.current) {
clearInterval(codeTimer.current);
}
};
}, [codeText, setCodeTimeVal]);
const regex = /^1[3-9]\d{9}$/;
//发送验证码
const handleCodeSend = async(e:any) => {
if (codeText !== '发送验证码') {
return;
}
if(!count) return
e.preventDefault()
if (!regex.test(count)) {
setMsg('手机格式不正确,请重新输入!')
setShowMsg(true)
return false
}
const testCount = await loginRequest({
url: '/checkIsRegister',
method: 'post',
data: {contacts_tel:count},
})
if(testCount.code!=0){
messageRef.current(testCount.msg)
return
}
const param = {
send_type: '1',
send_user: count,
send_fun: 'login'
}
const response = await loginRequest({
url: '/sendMsgCode',
method: 'post',
data: param,
})
if(testCount.code==0){
messageRef.current("发送成功")
setCodeText('重发(60S)')
}else{
messageRef.current(response.msg)
}
}
const handleGoLogin = () => {
router.push('login?type=1')
}
// 登录
const handleSubmit = async (e:any) => {
e.preventDefault()
setShowMsg(false)
switch (step) {
case 1:
const param = {
contacts_tel: count,
type: 2,
password: '',
code: code
}
const response = await loginRequest({
url: '/login',
method: 'post',
data: param,
})
if (response.code === 0) {
setCookie('token', response.data.token, 1)
setCookie('userId', response.data.user.web_user_id, 1)
setUser(response.data.user)
messageRef.current(response.msg)
setStep(2);
} else {
setMsg(response.msg)
setShowMsg(true)
}
break;
case 2:
if (password !== rePassword) {
setMsg('两次输入密码不一致,请重新输入!')
setShowMsg(true)
return
}
const result = await handleChangePassword()
if (result?.code === 0) {
messageRef.current(result?.msg)
setStep(3);
let disSecond = second
let secondeInter = setInterval(() => {
setSecond(disSecond--)
if (disSecond < 0) {
clearInterval(secondeInter)
handleGoLogin()
return
}
}, 1000)
} else {
setMsg(result.msg)
setShowMsg(true)
}
break;
}
return false
};
const handleChangePassword = async () => {
const param = {
send_type: 1,
chang_type: 5,
new_value: password,
send_user: user?.web_user_id
}
const response = await loginRequest({
url: '/api/userInfo/changeUserInfo',
method: 'post',
data: param,
headers: {
'webUserId': user?.web_user_id
}
})
return response
}
return (
<>
<TopH />
<SearchH />
<div className={style.loginPage}>
<div className={style.loginBox}>
<div className={style.typeBox}>
<img src={`/images/step${step}.png`} alt="" />
</div>
<form onSubmit={handleSubmit}>
{ step === 1 && (
<>
<div>
<select className={style.areaChoose} value={area} onChange={handleAreaChange} >
<option value="0086">0086(中国大陆)</option>
<option value="00852">00852(中国香港)</option>
<option value="00853">00853(中国澳门)</option>
<option value="00886">00886(中国台湾)</option>
</select>
<input type="contacts_tel" value={count} className={style.areaInput} placeholder='请输入手机号' onChange={handleCountChange} required />
</div>
<div>
<input type="password" value={code} className={style.registerInput} placeholder='请输入短信验证码' onChange={handleCodeChange} required />
<button className={codeText=='发送验证码'?`${style.codeButton }`:`${style.codeButton } ${style.dis}`} onClick={handleCodeSend}>{codeText}</button>
</div>
{ showMsg && (
<>
<p className={style.showMsg}>{msg}</p>
</>
)}
<button type="submit" className={style.registerLoginButton}>提交</button>
</>
)}
{step === 2 && (
<>
<div>
<input type="password" value={password} className={style.loginInput} placeholder='请设置登录密码(6-20个字符)' onChange={handlePasswordChange} required />
</div>
<div>
<input type="password" value={rePassword} className={style.loginInput} placeholder='再次输入登录密码' onChange={handleRePasswordChange} required />
</div>
{ showMsg && (
<>
<p className={style.showMsg}>{msg}</p>
</>
)}
<button type="submit" className={style.registerLoginButton} >保存</button>
</>
)}
{step === 3 && (
<>
<div className={style.completeBox}></div>
<button className={style.registerLoginButton} onClick={() => handleGoLogin()}>立即登录({second}</button>
</>
)}
</form>
</div>
</div>
<Footer />
</>
);
};
export default Page;
.loginPage {
background: #fff;
padding: 80px 0;
height: 740px;
width: 100%;
border-top: 1px solid #FF9A00;
position: relative;
}
.loginPage .loginBox {
width: 400px;
height: 100%;
position: absolute;
left: 50%;
transform: translate(-50%);
text-align: center;
}
.loginPage .loginBox .typeBox {
padding: 10px 98px 22px;
display: flex;
justify-content: space-between;
cursor: pointer;
}
.loginPage .loginBox .typeBox .typeButton {
color: #808080;
}
.loginPage .loginBox .typeBox .typeButton:hover {
color: #FF9A00;
}
.loginPage .loginBox .typeBox .typeButtonChoosen {
color: #FF9A00;
font-weight: bold;
}
.loginPage .loginButton {
width: 300px;
height: 36px;
background: #FF9A00;
border-radius: 1px;
font-size: 20px;
color: #FFFFFF;
cursor: pointer;
position: relative;
left: 50px;
}
.loginPage .modalContent {
padding: 45px 0;
box-sizing: border-box;
}
.loginPage .modalContent :global .ant-form-item {
margin-bottom: 20px;
}
.loginPage{background:#fff;padding:80px 0;height:740px;width:100%;border-top:1px solid #FF9A00;position:relative}.loginPage .loginBox{width:400px;height:100%;position:absolute;left:50%;transform:translate(-50%);text-align:center}.loginPage .loginBox .typeBox{padding:10px 98px 22px;display:flex;justify-content:space-between;cursor:pointer}.loginPage .loginBox .typeBox .typeButton{color:#808080}.loginPage .loginBox .typeBox .typeButton:hover{color:#FF9A00}.loginPage .loginBox .typeBox .typeButtonChoosen{color:#FF9A00;font-weight:bold}.loginPage .loginButton{width:300px;height:36px;background:#FF9A00;border-radius:1px;font-size:20px;color:#FFFFFF;cursor:pointer;position:relative;left:50px}.loginPage .modalContent{padding:45px 0;box-sizing:border-box}.loginPage .modalContent :global .ant-form-item{margin-bottom:20px}
.loginPage{
background: #fff;
padding:80px 0;
height: 740px;
width: 100%;
border-top: 1px solid #FF9A00;
position: relative;
.loginBox {
width: 400px;
height: 100%;
position: absolute;
left: 50%;
transform: translate(-50%);
text-align: center;
.typeBox {
padding: 10px 98px 22px;
display: flex;
justify-content: space-between;
cursor: pointer;
.typeButton {
color: #808080;
&:hover {
color: #FF9A00;
}
}
.typeButtonChoosen {
color: #FF9A00;
font-weight: bold;
}
}
}
.loginButton {
width: 300px;
height: 36px;
background: #FF9A00;
border-radius: 1px;
font-size: 20px;
color: #FFFFFF;
cursor: pointer;
position: relative;
left:50px;
}
.modalContent {
padding: 45px 0;
box-sizing: border-box;
:global {
.ant-form-item {
margin-bottom:20px;
}
}
}
}
\ No newline at end of file
import React, { useEffect, useState, useRef } from 'react';
import useRequest from "@/hooks/useRequest"
import style from './index.module.scss'
import Footer from "@/components/Footer";
import TopH from "@/components/Header/components/TopH"
import SearchH from "@/components/Header/components/SearchH"
import { useRouter } from 'next/router';
import { useCookies } from '@/hooks/useCookies'
import { Radio, Form, Input, message } from 'antd'
import { useToast } from '@/hooks/useToast';
import { useSeoTitle } from '@/hooks/useSeoTitle';
const InvoiceTitleList = [
{
text: '公司名称',
key: 'tax_title',
type: [3, 4]
},
{
text: '联系人',
key: 'contacts_name',
type: [2, 3, 4]
},
{
text: '岗位',
key: 'contacts_name_post',
type: [2, 3, 4]
}
]
const Page = () => {
const router = useRouter()
const seoTitle=useSeoTitle()
const { query } = router
const [messageApi, contextHolder] = message.useMessage();
const [form] = Form.useForm()
const { request: userRequest } = useRequest<any>({ manual: true })
const validateMessages = {
required: '${label}不能为空!'
}
const [type, setType] = useState("1");
const [value, setValue] = useState(3);
const handleTypeChange = (type: string) => {
setType(type)
}
const onChange = (e: any) => {
setValue(e.target.value)
}
const manualValidate = () => {
form.validateFields().then((value: any) => {
let params_ = { ...JSON.parse(JSON.stringify(value)) }
if (type == "2") {
console.log(8)
params_.invoice_type = 2
}
userRequest({ url: '/api/userInfo/saveInvoice', method: 'post', data: params_ }).then((res) => {
if (res?.code === 0) {
if (query.backUrl) {
window.location.href = String(query.backUrl)
return
}
router.push("/")
} else {
messageApi.open({
type: 'error',
content: res?.msg,
});
}
})
}).catch((e) => { });
}
return (
<>
{seoTitle}
<TopH />
<SearchH />
{contextHolder}
<div className={style.loginPage}>
<div className={style.loginBox}>
<div className={style.typeBox}>
<span
className={`${style.typeButton} ${style.cursorPointer} ${(type === "1") && style.typeButtonChoosen}`}
onClick={() => handleTypeChange('1')}>
公司
</span>
<span
className={`${style.typeButton} ${style.cursorPointer} ${(type === '2') && style.typeButtonChoosen}`}
onClick={() => handleTypeChange('2')}>
个人
</span>
</div>
<Form
className={style.modalContent}
validateMessages={validateMessages}
form={form}
labelCol={{ span: 6 }}
wrapperCol={{ span: 20 }}>
{
type == "1" && <Form.Item label="发票类型" className={style.lineItem} name="invoice_type" rules={[{ required: true }]}>
<Radio.Group onChange={onChange} value={value}>
<Radio value={3}>增值税专用发票</Radio>
<Radio value={4}>增值税普通发票</Radio>
</Radio.Group>
</Form.Item>
}
{InvoiceTitleList.map(invoiceTitleItem => {
if (invoiceTitleItem.key == "invoice_type_cn") { return }
if (type == "2" && invoiceTitleItem.key == "tax_title") { return }
if (invoiceTitleItem.type.includes(value))
return (
<Form.Item
className={style.lineItem}
key={invoiceTitleItem.key}
label={invoiceTitleItem.text}
name={invoiceTitleItem.key}
rules={[{ required: true }]}>
<Input />
</Form.Item>
)
})}
</Form>
<button type="submit" className={style.loginButton} onClick={() => manualValidate()}>提交</button>
</div>
</div>
<Footer />
</>
);
};
export default Page;
import styles from './index.module.scss'
import { useEffect, useReducer, useRef, useState } from 'react';
import type { ListSortType } from '../../components/ListSort/types'
import type { dataListItemType } from '../../components/ListOneItem/types'
import BreadNav from '../../components/BreadNav';
import ListSort from '../../components/ListSort';
import ListOneItem from '../../components/ListOneItem';
import { brandsAndClasssReducer, supplierDataReducer } from '@/reducers/searchReducers';
import type { ResponseTypeSearch, supplierDataType } from '@/types/searchTypes'
import useRequest from '../../hooks/useRequest';
import ListNoData from '../../components/ListNoData';
import { useRouter } from 'next/router';
import Footer from "@/components/Footer";
import Header from "@/components/Header";
import { GetServerSideProps } from 'next';
import { getCateList } from "@/server/getCateList";
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
import { useQq } from '@/hooks/useQq';
import { Empty } from 'antd';
import FixedSearchTop from '@/components/FixedSearchTop';
export const getServerSideProps: GetServerSideProps = async () => {
return getCateList()
}
const supplierIdS = ['', '24','73','102','57']
const Page = (props: { cateList: ResponseTypeCateList }) => {
const { QQURL,PHONE}=useQq()
const requestCount = useRef(0)
const router = useRouter()
const keyword = router.query.keyword || '';
const num = router.query.num || '';
const { request: getListRequest } = useRequest<ResponseTypeSearch>({ manual: true,loading:false })
const initSupplierList = useRef<supplierDataType[]>([])//初始化数据
const [supplierList, dispatchSupplierList] = useReducer(supplierDataReducer, [])
const [isFixedH, setIsFixedH] = useState(false);
useEffect(() => {
const handleScroll = () => {
let distanceFromTop = document.getElementById('tableboxfg')!.offsetTop;
if (window.scrollY > distanceFromTop) {
setIsFixedH(true);
} else {
setIsFixedH(false);
}
};
window.addEventListener('scroll', handleScroll);
// 清除事件监听器
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
useEffect(() => {
initSupplierList.current = []
requestCount.current = 0
supplierIdS.forEach(supplier_id => {
getListRequest({ url: '/api/search/goodsSearch', method: 'post', data: { keyword: keyword, num: num, supplier_id: supplier_id, page: 1, page_size: 10 } }).then((res) => {
requestCount.current = requestCount.current + 1
if (res?.code === 0) {
initSupplierList.current = [...initSupplierList.current, ...(res.data || [])]
}
getInitData()
})
})
}, [getListRequest, keyword, num])
const getInitData = () => {
let datasg: dataListItemType[] = [];
initSupplierList.current.forEach(item => {
item.data.forEach(child => {
datasg.push(child)
})
})
dispatchBrands({ type: 'brandsInit', value: JSON.parse(JSON.stringify(datasg)) })
dispatchclasss({ type: 'classsInit', value: JSON.parse(JSON.stringify(datasg)) })
dispatchSupplierList({ type: 'init', value: JSON.parse(JSON.stringify(initSupplierList.current)) })
if (requestCount.current >= supplierIdS.length) {
}
}
const [sortObj, setSortObj] = useState<ListSortType>({
sortType: 1,
isStock: false,
stockSort: '',
priceSort: ''
})
const [brandsR, dispatchBrands] = useReducer(brandsAndClasssReducer, [])
const [classsR, dispatchclasss] = useReducer(brandsAndClasssReducer, [])
//品牌分类盒子 UI
const brandListRef = useRef<HTMLDivElement>(null);
const classListRef = useRef<HTMLDivElement>(null);
const [brandListAll, setBrandListAll] = useState(false)
const [classListAll, setClassListAll] = useState(false)
//品牌,分类,排序发生变化
useEffect(() => {
dispatchSupplierList({ type: 'change', value: JSON.parse(JSON.stringify(initSupplierList.current)), brandsR: brandsR, classsR: classsR, sortObj: sortObj })
}, [brandsR, classsR, sortObj])
const updateBrandAndClass = (type: number, id?: string) => {
if (type === 1) {
dispatchBrands({ type: 'brandsUpdate', value: id })
}
if (type === 2) {
dispatchclasss({ type: 'classsUpdate', value: id })
}
}
return (
<>
<main>
<FixedSearchTop />
<Header {...props.cateList} />
<BreadNav><strong>&quot;{keyword}&quot;的型号搜索结果</strong></BreadNav>
<div className={`${styles.mvSearchPage} w1226`} >
{
initSupplierList.current.length > 0 &&
<div className={styles.shiftBox}>
<div className={`${styles.shiftGroup} row`} >
<span>品牌:</span>
<div className={brandListAll ? `${styles.itemBox} row` : `${styles.itemBox} row ${styles.overflowheight}`} ref={brandListRef}>
{
brandsR.map(item => {
return (
<div key={item.id + Math.random()} onClick={() => { updateBrandAndClass(1, item.id) }} className={item.checked ? `${styles.item} ${styles.act}` : `${styles.item}`} >{item.value}</div>
)
})
}
</div>
<div className={`${styles.shitrankbox} row`}>
<div className={brandsR.find(item => item.checked === true) ? `${styles.more} row verCenter rowCenter ${styles.shitrank} ${styles.shows}` : `${styles.more} row verCenter rowCenter ${styles.shitrank} ${styles.hides}`} onClick={() => { updateBrandAndClass(1) }}>清除条件</div>
<div className={`${styles.more} row verCenter rowCenter ${styles.shitrank}`} onClick={() => { setBrandListAll(!brandListAll) }}>
{brandListAll ? (<>收起<i className='icon iconfont icon-xiangshang2'></i></>) : (<>展开<i className='icon iconfont icon-xiangxia2'></i></>)}
</div>
</div>
</div>
{
classsR.length > 0 &&
<div className={`${styles.shiftGroup} row`}>
<span>分类:</span>
<div className={classListAll ? `${styles.itemBox} row` : `${styles.itemBox} row ${styles.overflowheight}`} ref={classListRef}>
{
classsR.map(item => {
return (
<div onClick={() => { updateBrandAndClass(2, item.id) }} key={item.id + Math.random()} className={item.checked ? `${styles.item} ${styles.act}` : `${styles.item}`} >{item.value}</div>
)
})
}
</div>
<div className={`${styles.shitrankbox} row`}>
<div className={classsR.find(item => item.checked === true) ? `${styles.more} row verCenter rowCenter ${styles.shitrank} ${styles.shows}` : `${styles.more} row verCenter rowCenter ${styles.shitrank} ${styles.hides}`} onClick={() => { updateBrandAndClass(2) }}>清除条件</div>
<div className={`${styles.more} row verCenter rowCenter ${styles.shitrank}`} onClick={() => { setClassListAll(!classListAll) }}>
{classListAll ? (<>收起<i className='icon iconfont icon-xiangshang2'></i></>) : (<>展开<i className='icon iconfont icon-xiangxia2'></i></>)}
</div>
</div>
</div>
}
</div>
}
<div className={styles.databox}>
<ListSort sortObj={sortObj} setSortObj={setSortObj} />
<div id="tableboxfg" className={styles.tableboxt}>
<div className={isFixedH?`${styles.tableTitle} ${styles.tableTitleFixed}`:`${styles.tableTitle}`}>
<span className={styles.boxInfo}>商品信息</span>
<span className={styles.boxCount}>库存及起订</span>
<span className={styles.boxJt}>阶梯</span>
<span className={styles.boxHk}>香港交货</span>
<span className={styles.boxMain}>大陆交货</span>
<span className={styles.boxTime}>交期</span>
<span className={styles.boxAction}>操作</span>
</div>
</div>
{
(supplierList.length == 0 &&requestCount.current != supplierIdS.length)&&
<div className={styles.searchLoadingBox}>
<img src="/images/searchLoading.gif" alt="" />
</div>
}
{
supplierList.length > 0 ?
supplierList.map((item, index) => {
return (
item.data.length > 0 &&
<div className={styles.dataGroupSupplier} key={String(item.supplier_id) + index + Math.random()}>
<div className={styles.dataListTitle}>{item.supplier_name || '其他'}</div>
<div className={styles.searchListDatas}>
{
item.data.map(child => {
return (
<ListOneItem key={String(child.sku_id) + Math.random()} {...child} QQURL={QQURL} PHONE={PHONE} />
)
})
}
</div>
{/* <div className={styles.dataListMore}>还有<b>32</b>个商品未显示,<b>点击加载更多</b></div> */}
</div>
)
})
: requestCount.current >= supplierIdS.length && <Empty image='/images/emptyorder.png' description="数据为空!" imageStyle={{height: '183px', margin: '30px auto 0'}} />
}
</div>
</div>
<Footer />
</main>
</>
)
}
export default Page
\ No newline at end of file
.mvSearchPage{margin-bottom:70px}.mvSearchPage .shiftBox{padding:24px 30px;background:#fff;padding-bottom:6px}.mvSearchPage .shiftBox .shiftGroup{border-bottom:1px solid #E7E7E7;margin-bottom:18px}.mvSearchPage .shiftBox .shiftGroup span{font-weight:bold;font-size:12px;color:#888888;padding-top:2px}.mvSearchPage .shiftBox .shiftGroup:last-child{border-bottom:0px;margin-bottom:0px}.mvSearchPage .shiftBox .shiftGroup .itemBox{width:1000px;flex-wrap:wrap;min-height:40px}.mvSearchPage .shiftBox .shiftGroup .itemBox.overflowheight{height:40px;overflow:hidden}.mvSearchPage .shiftBox .shiftGroup .itemBox .item{height:22px;border:1px solid transparent;line-height:20px;box-sizing:border-box;margin-left:45px;margin-bottom:18px;font-size:12px;color:#000;cursor:pointer;text-align:center;padding:0 15px}.mvSearchPage .shiftBox .shiftGroup .itemBox .item.act{background:#FFFBF5;border:1px solid #FF9A00}.mvSearchPage .shiftBox .shiftGroup .shitrankbox{width:130px;justify-content:flex-end}.mvSearchPage .shiftBox .shiftGroup .shitrank{margin-left:5px;height:22px;width:58px;border:1px solid #B0B0B0;box-sizing:border-box;color:#919191;font-size:12px;cursor:pointer}.mvSearchPage .shiftBox .shiftGroup .shitrank.shows{display:flex}.mvSearchPage .shiftBox .shiftGroup .shitrank.hides{display:none}.mvSearchPage .shiftBox .shiftGroup .shitrank:first-child{margin-left:0px}.mvSearchPage .shiftBox .shiftGroup .shitrank i{color:#919191;font-size:12px}.mvSearchPage .databox{padding-top:24px;min-height:290px}.mvSearchPage .databox .searchLoadingBox{padding-top:40px 0}.mvSearchPage .databox .searchLoadingBox img{width:220px;height:220px;display:block;margin:0 auto}.mvSearchPage .databox .dataGroupSupplier{border:1px solid #EDEFEF;margin-bottom:30px}.mvSearchPage .databox .dataGroupSupplier .searchListDatas .listGroupOneItem:first-child .cons{border-top:0px}.mvSearchPage .databox .dataGroupSupplier .dataListTitle{padding:0 27px;height:50px;line-height:50px;font-size:16px;color:#000000;background:#f6f6f6}.mvSearchPage .databox .dataGroupSupplier .dataListMore{height:48px;line-height:48px;color:#000;font-size:12px;text-align:center;background:#fff}.mvSearchPage .databox .dataGroupSupplier .dataListMore b{color:#FF9A00;cursor:pointer}.mvSearchPage .databox .tableboxt{width:1226px;height:34px}.mvSearchPage .databox .tableTitle{width:1226px;height:34px;background:#F2EEE6;border:1px solid #E5DFD3;line-height:34px;display:flex;box-sizing:border-box;padding-left:17px}.mvSearchPage .databox .tableTitle.tableTitleFixed{position:fixed;z-index:4;top:60px}.mvSearchPage .databox .tableTitle>span{padding-left:10px}.mvSearchPage .databox .tableTitle .boxInfo{width:310px}.mvSearchPage .databox .tableTitle .boxCount{width:204px}.mvSearchPage .databox .tableTitle .boxJt{width:89px}.mvSearchPage .databox .tableTitle .boxHk{width:89px}.mvSearchPage .databox .tableTitle .boxMain{width:105px}.mvSearchPage .databox .tableTitle .boxTime{width:168px}.mvSearchPage .databox .tableTitle .boxAction{flex:2}
.mvSearchPage{
margin-bottom: 70px;
.shiftBox{
padding:24px 30px;
background: #fff;
padding-bottom: 6px;
.shiftGroup{
border-bottom: 1px solid #E7E7E7;
margin-bottom: 18px;
span{
font-weight: bold;
font-size: 12px;
color: #888888;
padding-top: 2px;
}
&:last-child{border-bottom: 0px;margin-bottom: 0px;}
.itemBox{
width:1000px;
flex-wrap: wrap;
min-height:40px;
&.overflowheight{
height:40px;
overflow: hidden;
}
.item{
height: 22px;
border: 1px solid rgba(0,0,0,0);
line-height: 20px;
box-sizing: border-box;
margin-left: 45px;
margin-bottom: 18px;
font-size: 12px;
color:#000;
cursor: pointer;
text-align: center;
padding:0 15px;
&.act{
background: #FFFBF5;
border: 1px solid #FF9A00;
}
}
}
.shitrankbox{
width:130px;
justify-content: flex-end;
}
.shitrank{
margin-left: 5px;
height: 22px;
width:58px;
border: 1px solid #B0B0B0;
box-sizing: border-box;
color:#919191;
font-size: 12px;
cursor: pointer;
&.shows{
display: flex;
}
&.hides{
display: none;
}
&:first-child{margin-left: 0px;}
i{
color:#919191;
font-size: 12px;
}
}
}
}
.databox{
padding-top: 24px;
min-height: 290px;
.searchLoadingBox{
padding-top: 40px 0;
img{
width:220px;
height:220px;
display: block;
margin:0 auto;
}
}
.dataGroupSupplier{
border: 1px solid #EDEFEF;
margin-bottom: 30px;
.searchListDatas{
.listGroupOneItem:first-child{
.cons{
border-top: 0px;
}
}
}
.dataListTitle{
padding:0 27px;
height:50px;
line-height: 50px;
font-size: 16px;
color: #000000;
background: #f6f6f6;
}
.dataListMore{
height:48px;
line-height: 48px;
color:#000;
font-size: 12px;
text-align: center;
background: #fff;
b{color:#FF9A00;cursor: pointer;}
}
}
.tableboxt{
width: 1226px;
height: 34px;
}
.tableTitle {
width: 1226px;
height: 34px;
background: #F2EEE6;
border: 1px solid #E5DFD3;
line-height: 34px;
display: flex;
box-sizing: border-box;
padding-left:17px;
&.tableTitleFixed{
position: fixed;
z-index: 4;
top:60px;
}
>span {
padding-left: 10px;
}
.boxInfo {
width:310px;
}
.boxCount {
width:204px;
}
.boxJt {
width:89px;
}
.boxHk {
width:89px;
}
.boxMain {
width:105px;
}
.boxTime {
width:168px;
}
.boxAction {
flex: 2;
}
}
}
}
\ No newline at end of file
.shopBox{margin:20px auto;width:1226px;height:660px;position:relative}.shopLayer{width:1226px;height:580px;background-color:#fff;box-sizing:border-box;padding:30px 25px}.shopLayer .layerTop{height:30px;display:flex;align-items:center;margin-bottom:20px;position:relative}.shopLayer .layerTop .placeButton{width:90px;height:26px;line-height:24px;background:#FFFFFF;border-radius:1px;border:1px solid #B0B0B0;cursor:pointer;margin-right:10px}.shopLayer .layerTop .placeButton:hover{color:#fff;background-color:#FF9A00;border-color:#FF9A00}.shopLayer .layerTop .sePlaceButton{color:#fff;background-color:#FF9A00;border-color:#FF9A00}.shopLayer .layerFooter{width:100%;height:68px;position:absolute;bottom:0;display:flex;left:0;align-items:center;background-color:#fff;box-sizing:border-box;padding-left:45px}.shopLayer .layerFooter .replaceButton{margin-left:30px;cursor:pointer}.shopLayer .layerFooter .accountButton{position:absolute;right:0;width:170px;height:100%;color:#fff;background:#D0121B;border-radius:1px;cursor:pointer}.shopLayer .layerFooter .shopTotal{margin-left:400px;margin-right:70px}.shopLayer .keyNumbers{color:#CC0000}
.shopBox {
margin: 20px auto;
width: 1226px;
height: 660px;
position: relative;
}
.shopLayer {
width: 1226px;
height: 580px;
background-color: #fff;
box-sizing: border-box;
padding: 30px 25px;
.layerTop {
height: 30px;
display: flex;
align-items: center;
margin-bottom: 20px;
position: relative;
.placeButton {
width: 90px;
height: 26px;
line-height: 24px;
background: #FFFFFF;
border-radius: 1px;
border: 1px solid #B0B0B0;
cursor: pointer;
margin-right: 10px;
&:hover {
color: #fff;
background-color: #FF9A00;
border-color:#FF9A00;
}
}
.sePlaceButton {
color: #fff;
background-color: #FF9A00;
border-color:#FF9A00;
}
}
.layerFooter {
width: 100%;
height: 68px;
position: absolute;
bottom: 0;
display: flex;
left: 0;
align-items: center;
background-color: #fff;
box-sizing: border-box;
padding-left: 45px;
.replaceButton {
margin-left: 30px;
cursor: pointer;
}
.accountButton {
position: absolute;
right: 0;
width: 170px;
height: 100%;
color: #fff;
background: #D0121B;
border-radius: 1px;
cursor: pointer;
}
.shopTotal {
margin-left: 400px;
margin-right: 70px;
}
}
.keyNumbers {
color: #CC0000;
}
}
\ No newline at end of file
import styles from './index.module.scss'
import { useRouter } from 'next/router'
import { Checkbox, Table, Input, TableColumnsType, TableProps, Button } from "antd"
import { useState, useEffect } from 'react'
import Footer from "@/components/Footer"
import Header from "@/components/Header"
import { DataType } from "@/types/orderTypes"
import useRequest from "@/hooks/useRequest"
import { useToast } from '@/hooks/useToast'
import { GetServerSideProps } from 'next'
import { getCateList } from "@/server/getCateList"
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
export const getServerSideProps: GetServerSideProps = async () => {
return getCateList()
}
const TopH = (props: { cateList: ResponseTypeCateList }) =>{
const { message } = useToast()
const router = useRouter()
const [sePlace, setSePlace] = useState<any>('1')
const [shopList, setShopList] = useState<any>([])
const [disList, setDisList] = useState<any>([])
const [disCn, setDisCn] = useState<any>([])
const [disUs, setDisUs] = useState<any>([])
const [isSeAll, setIsSeAll] = useState<any>(false)
const [selectList, setSelectList] = useState<any>([])
const { request: userRequest } = useRequest<any>({ manual: true, loading: true })
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([])
const columns: TableColumnsType<DataType> = [
{ title: '序号', dataIndex: 'name', key: 'name', render:(text, record, index) => { return <span>{index + 1}</span>}},
{ title: '型号/品牌', dataIndex: 'sku_name', key: 'sku_name', render:(text, record, index) => {
return <span>{record.sku_name || record.goods_name}/{record.brand_name}</span>}
},
{ title: '渠道', dataIndex: 'supplier_name', key: 'supplier_name' },
{ title: '单价', dataIndex: 'goods_price', key: 'goods_price',
render:(text, record, index) => {
return <span>{record.delivery_place_type === '2' ? '$' : '¥'}{record.goods_price}</span>
}
},
{
title: '数量',
dataIndex: 'goods_number',
key: 'goods_number',
width: 120,
render:(text, record, index) => {
return (
<Input
size="small"
style={{width: '100px',"borderColor":"#999" }}
value={record.goods_number}
onBlur={(e) => handleInputCommit(record)}
onChange={(e) => handleNumberChange(e, record)}/>
)
}
},
{ title: '现有库存', dataIndex: 'stock', key: 'stock' },
{ title: '小计', dataIndex: 'goods_amount', key: 'goods_amount',
render:(text, record, index) => {
return <span>{record.delivery_place_type === '2' ? '$' : '¥'}{record.goods_amount}</span>
}
},
{
title: '批次备注',
dataIndex: 'remark',
key: 'remark',
width: 120,
render:(text, record, index) => {
return (
<Input
size="small"
style={{width: '100px',"borderColor":"#999" }}
value={record.remark}
onBlur={() => handleInputCommit(record)}
onChange={(e) => handleRemarkChange(e, record)}/>
)
}
},
{
title: '操作',
dataIndex: 'goods_number',
key: 'goods_number',
width: 70,
render:(text, record, index) => {
return (
<Button
color="default"
size="small"
variant="text" onClick={() => handleLineDelete(record)}>
删除
</Button>
)
}
}
]
useEffect(() => {
handleDataInit()
}, [])
useEffect(() => {
handleSelectAll()
}, [shopList, sePlace])
const handleSelectPlace = (place: any) => setSePlace(place)
const rowSelection: TableProps<DataType>['rowSelection'] = {
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => {
setSelectList(selectedRows)
setSelectedRowKeys(selectedRowKeys)
setIsSeAll(selectedRowKeys.length === disList.length)
}
}
const handleDataEdit = async (data: any) => {
const res = await userRequest({
url: '/api/cart/cartEdit',
method: 'post',
data: data
})
if (res?.code === 0) message('操作成功!')
else message(res?.msg)
handleDataInit()
}
const handleLineDelete = (data: any) => {
const param = {
goods_list: [
{
sku_id: data.sku_id,
status: -1,
delivery_place_type: data.delivery_place_type
}
]
}
handleDataEdit(param)
}
const handleNumberChange = (e:any, data:any) => {
const newData = [...disList]
const index = newData.findIndex((item) => data.key === item.key)
const item = newData[index]
item.goods_number = e.target.value
newData.splice(index, 1, {
...item,
...data,
});
setDisList(newData);
}
const handleRemarkChange = (e:any, data:any) => {
const newData = [...disList]
const index = newData.findIndex((item) => data.key === item.key)
const item = newData[index]
item.remark = e.target.value
newData.splice(index, 1, {
...item,
...data,
})
setDisList(newData)
}
const handleInputCommit = ( data:any) => {
if (data.goods_number > data.stock) return message('数量不能大于现有库存!')
const param = {
goods_list: [
{
sku_id: data.sku_id,
goods_number: data.goods_number,
remark: data.remark,
delivery_place_type: data.delivery_place_type
}
]
}
handleDataEdit(param)
}
const handleSelectAll = () => {
let dataList:any = []
let keyList:any = []
shopList.forEach((shopItem:any) => {
if (shopItem?.delivery_place_type === sePlace) {
dataList.push(
{
...shopItem,
key: `${shopItem.sku_id}_${shopItem.delivery_place_type}`
}
)
keyList.push(`${shopItem.sku_id}_${shopItem.delivery_place_type}`)
}
})
setDisList(dataList)
setSelectList(dataList)
setSelectedRowKeys(keyList)
setIsSeAll(dataList.length)
}
const handleDataInit = async () => {
const shopListResopnse = await userRequest({
url: '/api/cart/cartList',
method: 'post'
})
if (shopListResopnse?.code === 0) {
setShopList(shopListResopnse.data.cart_list)
setDisCn(shopListResopnse.data.cart_amount_cn)
setDisUs(shopListResopnse.data.cart_amount_hk)
}
}
const handleDataRemove = () => {
if (!selectList.length) return message('请选择商品!')
const param = {
goods_list: selectList.map((seItem:any) => {
return {
sku_id: seItem.sku_id,
status: -1,
delivery_place_type: sePlace
}
})
}
handleDataEdit(param)
}
const handleSelectAllChange = (e: any) => {
if (e.target.checked) handleSelectAll()
else {
setSelectedRowKeys([])
}
}
const handleDataClean = async () => {
const res = await userRequest({
url: '/api/cart/cartCleanUnShelf',
method: 'post'
})
if (res?.code === 0) message('清理成功!')
else message(res?.msg)
}
const handleToSettle = () => {
if (!selectList.length) return message('请选择商品!')
const idList:any[] = []
const noStockList:any[] = []
selectList.forEach((seItem:any) => {
if (Number(seItem.goods_number || 0) > seItem.stock) noStockList.push(seItem.sku_name || seItem.goods_name)
idList.push(seItem.sku_id)
})
if (noStockList.length) {
return message(`${noStockList.join(',')}型号不能购买,库存不足!`)
}
router.push(`orderSettle?sourceType=2&id=${idList.join(',')}&deliveryPlaceType=${sePlace}`)
}
return (
<>
<Header {...props.cateList} />
<div className={styles.shopBox}>
<div className={styles.shopLayer}>
<div className={styles.layerTop}>
<button
className={`${styles.placeButton} ${(sePlace ==='1') && styles.sePlaceButton}`}
onClick={() => handleSelectPlace('1')}>
大陆({shopList.filter((shopItem:any) => shopItem?.delivery_place_type === '1').length}
</button>
<button
className={`${styles.placeButton} ${(sePlace ==='2') && styles.sePlaceButton}`}
onClick={() => handleSelectPlace('2')}>
香港({shopList.filter((shopItem:any) => shopItem?.delivery_place_type === '2').length}
</button>
</div>
<div className={styles.layerContain}>
<Table<DataType>
size="small"
bordered={true}
rowKey={(record) => `${record.sku_id}_${record.delivery_place_type}`}
pagination={{
pageSize: 10,
total: disList.length,
position: ['bottomRight']
}}
columns={columns}
rowSelection={{ ...rowSelection }}
dataSource={disList}
/>
</div>
<div className={styles.layerFooter}>
<Checkbox checked={isSeAll} disabled={!disList.length} onChange={handleSelectAllChange}>全选</Checkbox>
<span className={styles.replaceButton} onClick={handleDataRemove}>批量删除</span>
<span className={styles.replaceButton} onClick={handleDataClean}>清除下架商品</span>
<div className={styles.shopTotal}>
<span className={styles.keyNumbers}> {disList.length} </span>
</div>
<div>
总金额:
<span className={styles.keyNumbers} style={{fontSize: '20px', fontWeight: 'bold'}}>
{(['0', '1'].includes(sePlace)) && (<> ¥{disCn} </>)}
{(['0', '2'].includes(sePlace)) && (<> ${disUs} </>)}
</span>
</div>
<button className={styles.accountButton} onClick={handleToSettle}>去结算</button>
</div>
</div>
</div>
<Footer />
</>
)
}
export default TopH
\ No newline at end of file
import type { ThemeConfig } from 'antd'
const theme: ThemeConfig = {
token: {
colorPrimary: '#FF9A00',
borderRadius: 0
},
components: {
Table: {
headerBorderRadius: 0
}
}
}
export default theme
\ No newline at end of file
/**
* 防抖函数
* @param fn
* @param delay
* @returns {Function}
*/
function debounce(fn, delay) {
// 定时器,用来 setTimeout
var timer
// 返回一个函数,这个函数会在一个时间区间结束后的 delay 毫秒时执行 fn 函数
return function () {
// 保存函数调用时的上下文和参数,传递给 fn
var context = this
var args = arguments
// 每次这个返回的函数被调用,就清除定时器,以保证不执行 fn
clearTimeout(timer)
// 当返回的函数被最后一次调用后(也就是用户停止了某个连续的操作),
// 再过 delay 毫秒就执行 fn
timer = setTimeout(function () {
fn.apply(context, args)
}, delay)
}
}
\ No newline at end of file
@charset "UTF-8";
/*全局样式*/
html,
body,
div,
iframe,
em,
img,
p,
a,
strong,
b,
i,
form,
label,
span,
h1,
h2,
h3,
h4,
h5,
h6,
dl,
dt,
dd,
ol,
ul,
li,
applet,
object,
blockquote,
big,
cite,
code,
del,
dfn,
abbr,
acronym,
address,
pre,
time,
mark,
audio,
video,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
nav,
section,
menu,
button,
input,
textarea {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
font-weight: normal;
list-style: none;
outline: none;
resize: none;
}
table,
tbody,
tfoot,
thead,
tr,
th,
td {
margin: 0;
padding: 0;
font-size: 100%;
font: inherit;
}
a {
text-decoration: none;
}
a:hover {
color: #FF9A00;
}
.f-red {
color: red;
}
table {
border-color: #ccc !important;
}
body,
html,
button,
input {
font-family: Arial, helvetica, PingFangSC-Regular, PingFang SC, "微软雅黑";
}
input::-webkit-input-placeholder {
/* WebKit, Blink, Edge */
color: #808080;
/* 修改字体颜色 */
}
.fw {
font-weight: bold;
}
.clr:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
.clr {
display: block;
min-height: 1%;
}
.clr {
clear: both;
}
.clr:after {
content: " ";
display: table;
clear: both;
}
.fl {
float: left;
}
.fr {
float: right;
}
.fw {
font-weight: bold;
}
.ta-c {
text-align: center;
}
.ta-r {
text-align: right;
}
.ta-l {
text-align: left;
}
.flex {
display: flex;
}
.column {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
}
.boxsiz {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
/* 两侧对齐 */
.bothSide {
justify-content: space-between;
}
/* 平均分布 */
.avarage {
justify-content: space-around;
}
/* 水平居中 */
.rowCenter {
justify-content: center;
}
/* 垂直居中 */
.verCenter {
align-items: center;
}
.searchFixedTopC {
position: fixed !important;
z-index: 4;
top: -4px;
transform: translateX(1112px);
}
/**公共UI样式**/
body,
html {
background: #fafafa;
font-size: 14px;
color: #333;
}
.w1226 {
width: 1226px;
margin: 0 auto;
}
.spinner {
display: none !important;
}
.paginationxk {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
.paginationxk li {
display: block;
background: #FBFBFB;
border-radius: 2px;
border: 1px solid #E8E8E8;
text-align: center;
line-height: 25px;
color: #616161;
position: relative;
transition: all 0.5s;
border-radius: 1px;
font-size: 12px;
cursor: pointer;
margin-left: 7px;
}
.paginationxk li.disabled {
cursor: not-allowed;
}
.paginationxk li.break a {
line-height: 19px;
}
.paginationxk li a {
color: #616161;
display: block;
box-sizing: border-box;
text-align: center;
padding: 0 7px;
height: 25px;
line-height: 26px;
min-width: 25px;
min-height: 25px;
}
.paginationxk li.activexk, .paginationxk li:hover {
background: linear-gradient(180deg, #FDFDFD 0%, #E2E2E2 100%);
border: 1px solid #A1A1A1;
color: #313131;
}
.ant-pagination {
display: flex;
justify-content: flex-end;
margin-top: 20px !important;
padding: 0 35px !important;
}
.ant-table-row-expand-icon-cell {
display: none !important;
}
.ant-empty-description {
margin-top: 30px !important;
color: #888 !important;
font-size: 14px !important;
}
.ant-table-cell {
color: #313131 !important;
font-weight: normal !important;
}
.ant-table-tbody > tr > td {
word-wrap: break-word;
word-break: break-all;
}
html,body,div,iframe,em,img,p,a,strong,b,i,form,label,span,h1,h2,h3,h4,h5,h6,dl,dt,dd,ol,ul,li,applet,object,blockquote,big,cite,code,del,dfn,abbr,acronym,address,pre,time,mark,audio,video,article,aside,canvas,details,embed,figure,figcaption,footer,header,nav,section,menu,button,input,textarea{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;font-weight:normal;list-style:none;outline:none;resize:none}table,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;font-size:100%;font:inherit}a{text-decoration:none}a:hover{color:#FF9A00}.f-red{color:red}table{border-color:#ccc !important}body,html,button,input{font-family:Arial, helvetica, PingFangSC-Regular, PingFang SC, "微软雅黑"}input::-webkit-input-placeholder{color:#808080}.fw{font-weight:bold}.clr:after{visibility:hidden;display:block;font-size:0;content:" ";clear:both;height:0}.clr{display:block;min-height:1%}.clr{clear:both}.clr:after{content:" ";display:table;clear:both}.fl{float:left}.fr{float:right}.fw{font-weight:bold}.ta-c{text-align:center}.ta-r{text-align:right}.ta-l{text-align:left}.flex{display:flex}.column{display:flex;flex-direction:column}.row{display:flex;flex-direction:row}.boxsiz{-webkit-box-sizing:border-box;box-sizing:border-box}.bothSide{justify-content:space-between}.avarage{justify-content:space-around}.rowCenter{justify-content:center}.verCenter{align-items:center}.searchFixedTopC{position:fixed !important;z-index:4;top:-4px;transform:translateX(1112px)}body,html{background:#fafafa;font-size:14px;color:#333}.w1226{width:1226px;margin:0 auto}.spinner{display:none !important}.paginationxk{margin-top:20px;display:flex;justify-content:flex-end}.paginationxk li{display:block;background:#FBFBFB;border-radius:2px;border:1px solid #E8E8E8;text-align:center;line-height:25px;color:#616161;position:relative;transition:all 0.5s;border-radius:1px;font-size:12px;cursor:pointer;margin-left:7px}.paginationxk li.disabled{cursor:not-allowed}.paginationxk li.break a{line-height:19px}.paginationxk li a{color:#616161;display:block;box-sizing:border-box;text-align:center;padding:0 7px;height:25px;line-height:26px;min-width:25px;min-height:25px}.paginationxk li.activexk,.paginationxk li:hover{background:linear-gradient(180deg, #FDFDFD 0%, #E2E2E2 100%);border:1px solid #A1A1A1;color:#313131}.ant-pagination{display:flex;justify-content:flex-end;margin-top:20px !important;padding:0 35px !important}.ant-table-row-expand-icon-cell{display:none !important}.ant-empty-description{margin-top:30px !important;color:#888 !important;font-size:14px !important}.ant-table-cell{color:#313131 !important;font-weight:normal !important}.ant-table-tbody>tr>td{word-wrap:break-word;word-break:break-all}
/*全局样式*/
@charset "utf-8";
html,
body,
div,
iframe,
em,
img,
p,
a,
strong,
b,
i,
form,
label,
span,
h1,
h2,
h3,
h4,
h5,
h6,
dl,
dt,
dd,
ol,
ul,
li,
applet,
object,
blockquote,
big,
cite,
code,
del,
dfn,
abbr,
acronym,
address,
pre,
time,
mark,
audio,
video,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
nav,
section,
menu,
button,
input,
textarea {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
font-weight: normal;
list-style: none;
outline: none;
resize: none;
}
table,
tbody,
tfoot,
thead,
tr,
th,
td {
margin: 0;
padding: 0;
font-size: 100%;
font: inherit;
}
a {
text-decoration: none;
&:hover {
color: #FF9A00;
}
}
.f-red{
color: red;
}
table {
border-color: #ccc !important;
}
body,
html,
button,
input {
font-family: Arial, helvetica, PingFangSC-Regular, PingFang SC, "微软雅黑";
}
input::-webkit-input-placeholder {
/* WebKit, Blink, Edge */
color: #808080;
/* 修改字体颜色 */
//font-size: 14px; /* 修改字体大小 */
}
.fw {
font-weight: bold;
}
.clr:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0
}
.clr {
display: block;
min-height: 1%;
}
.clr {
clear: both
}
.clr:after {
content: " ";
display: table;
clear: both
}
.fl {
float: left;
}
.fr {
float: right;
}
.fw {
font-weight: bold;
}
.ta-c {
text-align: center;
}
.ta-r {
text-align: right;
}
.ta-l {
text-align: left;
}
.flex {
display: flex;
}
.column {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
}
.boxsiz {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
/* 两侧对齐 */
.bothSide {
justify-content: space-between;
}
/* 平均分布 */
.avarage {
justify-content: space-around;
}
/* 水平居中 */
.rowCenter {
justify-content: center;
}
/* 垂直居中 */
.verCenter {
align-items: center;
}
.searchFixedTopC{
position: fixed!important;
z-index: 4;
top: -4px;
transform: translateX(1112px);
}
/**公共UI样式**/
body,
html {
background: #fafafa;
font-size: 14px;
color: #333;
}
.w1226 {
width: 1226px;
margin: 0 auto;
}
.spinner {
display: none !important;
}
.paginationxk{
margin-top: 20px;
display: flex;
justify-content: flex-end;
li{
display: block;
background: #FBFBFB;
border-radius: 2px;
border: 1px solid #E8E8E8;
text-align: center;
line-height: 25px;
color: #616161;
position: relative;
transition: all 0.5s;
border-radius: 1px;
font-size: 12px;
cursor: pointer;
margin-left: 7px;
&.disabled{
cursor: not-allowed;
}
&.break{
a{
line-height: 19px;
}
}
a{
color: #616161;
display: block;
box-sizing: border-box;
text-align: center;
padding: 0 7px;
height: 25px;
line-height: 26px;
min-width: 25px;
min-height: 25px;
}
&.activexk,&:hover{
background: linear-gradient(180deg, #FDFDFD 0%, #E2E2E2 100%);
border: 1px solid #A1A1A1;
color: #313131;
}
}
}
.ant-pagination{
display: flex;
justify-content: flex-end;
margin-top:20px!important;
padding:0 35px!important;
}
.ant-table-row-expand-icon-cell {
display: none !important;
}
.ant-empty-description{margin-top:30px!important;color: #888!important;font-size: 14px!important;}
.ant-table-cell{color:#313131!important;font-weight: normal!important;}
.ant-table-tbody > tr > td {
word-wrap: break-word;
word-break: break-all;
}
\ No newline at end of file
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=4599756" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe60c;</span>
<div class="name">地址</div>
<div class="code-name">&amp;#xe60c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe728;</span>
<div class="name">B-复选框</div>
<div class="code-name">&amp;#xe728;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe693;</span>
<div class="name">email</div>
<div class="code-name">&amp;#xe693;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe694;</span>
<div class="name">phone</div>
<div class="code-name">&amp;#xe694;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe637;</span>
<div class="name">三角形</div>
<div class="code-name">&amp;#xe637;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe610;</span>
<div class="name">sousuo</div>
<div class="code-name">&amp;#xe610;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe76e;</span>
<div class="name">向上2</div>
<div class="code-name">&amp;#xe76e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe772;</span>
<div class="name">向下2</div>
<div class="code-name">&amp;#xe772;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe775;</span>
<div class="name">向右1</div>
<div class="code-name">&amp;#xe775;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xeb15;</span>
<div class="name">向左</div>
<div class="code-name">&amp;#xeb15;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1724395740415') format('woff2'),
url('iconfont.woff?t=1724395740415') format('woff'),
url('iconfont.ttf?t=1724395740415') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-dizhi"></span>
<div class="name">
地址
</div>
<div class="code-name">.icon-dizhi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-B-fuxuankuang"></span>
<div class="name">
B-复选框
</div>
<div class="code-name">.icon-B-fuxuankuang
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-email"></span>
<div class="name">
email
</div>
<div class="code-name">.icon-email
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-phone"></span>
<div class="name">
phone
</div>
<div class="code-name">.icon-phone
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-sanjiaoxing"></span>
<div class="name">
三角形
</div>
<div class="code-name">.icon-sanjiaoxing
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-iconfontsousuo"></span>
<div class="name">
sousuo
</div>
<div class="code-name">.icon-iconfontsousuo
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xiangshang2"></span>
<div class="name">
向上2
</div>
<div class="code-name">.icon-xiangshang2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xiangxia2"></span>
<div class="name">
向下2
</div>
<div class="code-name">.icon-xiangxia2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xiangyou1"></span>
<div class="name">
向右1
</div>
<div class="code-name">.icon-xiangyou1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xiangzuo"></span>
<div class="name">
向左
</div>
<div class="code-name">.icon-xiangzuo
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-dizhi"></use>
</svg>
<div class="name">地址</div>
<div class="code-name">#icon-dizhi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-B-fuxuankuang"></use>
</svg>
<div class="name">B-复选框</div>
<div class="code-name">#icon-B-fuxuankuang</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-email"></use>
</svg>
<div class="name">email</div>
<div class="code-name">#icon-email</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-phone"></use>
</svg>
<div class="name">phone</div>
<div class="code-name">#icon-phone</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-sanjiaoxing"></use>
</svg>
<div class="name">三角形</div>
<div class="code-name">#icon-sanjiaoxing</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-iconfontsousuo"></use>
</svg>
<div class="name">sousuo</div>
<div class="code-name">#icon-iconfontsousuo</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xiangshang2"></use>
</svg>
<div class="name">向上2</div>
<div class="code-name">#icon-xiangshang2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xiangxia2"></use>
</svg>
<div class="name">向下2</div>
<div class="code-name">#icon-xiangxia2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xiangyou1"></use>
</svg>
<div class="name">向右1</div>
<div class="code-name">#icon-xiangyou1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xiangzuo"></use>
</svg>
<div class="name">向左</div>
<div class="code-name">#icon-xiangzuo</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>
@font-face {
font-family: "iconfont"; /* Project id 4599756 */
src: url('iconfont.woff2?t=1724395740415') format('woff2'),
url('iconfont.woff?t=1724395740415') format('woff'),
url('iconfont.ttf?t=1724395740415') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-dizhi:before {
content: "\e60c";
}
.icon-B-fuxuankuang:before {
content: "\e728";
}
.icon-email:before {
content: "\e693";
}
.icon-phone:before {
content: "\e694";
}
.icon-sanjiaoxing:before {
content: "\e637";
}
.icon-iconfontsousuo:before {
content: "\e610";
}
.icon-xiangshang2:before {
content: "\e76e";
}
.icon-xiangxia2:before {
content: "\e772";
}
.icon-xiangyou1:before {
content: "\e775";
}
.icon-xiangzuo:before {
content: "\eb15";
}
window._iconfont_svg_string_4599756='<svg><symbol id="icon-dizhi" viewBox="0 0 1024 1024"><path d="M512.768 1024H512a65.536 65.536 0 0 1-47.283-20.224c-9.677-10.112-97.434-102.656-184.73-219.904C162.15 625.664 102.4 499.456 102.4 408.909 102.4 183.424 286.157 0 512 0s409.6 183.424 409.6 408.883c0 54.784-21.12 121.907-62.746 199.45-40.166 74.777-100.556 161.638-179.532 258.201l-0.64 0.768-117.53 134.4A64.589 64.589 0 0 1 512.768 1024zM512 600.294c105.728 0 191.744-85.862 191.744-191.41S617.728 217.471 512 217.471s-191.744 85.862-191.744 191.411S406.272 600.294 512 600.294z" fill="#323232" ></path></symbol><symbol id="icon-B-fuxuankuang" viewBox="0 0 1024 1024"><path d="M850.6 63.9H173.7c-60.1 0-109.4 49.2-109.4 109.3v676.9c0 60.1 49.2 109.4 109.4 109.4h676.9c60.2 0 109.4-49.2 109.4-109.4V173.3c-0.1-60.1-49.3-109.4-109.4-109.4z m-49.4 278L469.6 764.5c-12.5 16-31.6 25.4-51.8 25.7h-1c-19.9 0-38.8-8.8-51.6-24.2L224.3 596.9c-23.8-28.5-19.9-70.8 8.6-94.6 28.5-23.8 70.8-19.9 94.6 8.6l87.7 105.3L695.5 259c22.9-29.3 65.2-34.2 94.3-11.4 29.2 22.9 34.3 65.2 11.4 94.3z" fill="#383838" ></path></symbol><symbol id="icon-email" viewBox="0 0 1024 1024"><path d="M314.181818 616.913455l130.536727-93.277091-130.536727-93.277091-7.633454-5.445818L279.272727 405.410909v236.357818l27.275637-19.479272 7.633454-5.399273z m209.454546-79.825455l209.454545-149.597091 4.375273-3.118545 25.623273-18.269091A34.909091 34.909091 0 0 0 733.090909 349.090909h-418.909091a34.909091 34.909091 0 0 0-28.416 14.615273L314.181818 387.490909l209.454546 149.620364z m48.872727 7.982545l-48.872727 34.909091-48.872728-34.909091-160.581818 114.711273-7.633454 6.283637-20.992 17.175272c6.283636 9.053091 16.779636 14.941091 28.625454 14.941091h418.909091c12.8 0 23.994182-6.865455 30.045091-17.128727L733.090909 659.781818l-160.581818-114.711273z m160.581818-114.711272L602.530909 523.636364l130.56 93.277091 34.909091 24.901818V405.457455l-34.909091 24.92509z" ></path></symbol><symbol id="icon-phone" viewBox="0 0 1024 1024"><path d="M727.994182 670.696727a30.347636 30.347636 0 0 1 0 42.845091l-21.410909 21.410909c-15.848727 15.848727-36.677818 25.483636-61.905455 28.695273-6.283636 0.768-12.567273 1.163636-18.874182 1.163636-18.385455 0-38.190545-3.118545-59.182545-9.285818-56.948364-16.756364-116.829091-54.481455-168.610909-106.263273-51.758545-51.781818-89.530182-111.662545-106.263273-168.610909-8.331636-28.392727-11.077818-54.621091-8.122182-78.033454 3.211636-25.250909 12.846545-46.08 28.672-61.905455l21.434182-21.410909a30.347636 30.347636 0 0 1 42.845091 0l94.301091 94.254546a30.347636 30.347636 0 0 1 0 42.868363l-21.434182 21.410909c-12.125091 12.125091-0.069818 51.386182 34.280727 85.713455 34.350545 34.327273 73.565091 46.429091 85.713455 34.280727l21.410909-21.410909a30.347636 30.347636 0 0 1 42.868364 0l94.277818 94.254546z m30.138182-338.315636a84.992 84.992 0 0 0-21.154909-26.949818c-18.222545-15.616-42.333091-24.203636-67.886546-24.203637-25.553455 0-49.664 8.587636-67.886545 24.203637a84.992 84.992 0 0 0-21.178182 26.949818 75.473455 75.473455 0 0 0 3.141818 73.099636c4.654545 7.656727 10.402909 14.545455 17.128727 20.433455a141.754182 141.754182 0 0 1-21.969454 14.429091 12.101818 12.101818 0 0 0 5.911272 22.690909c27.205818 0 50.315636-4.654545 67.258182-13.498182 5.818182 0.907636 11.706182 1.373091 17.594182 1.373091 25.553455 0 49.664-8.610909 67.886546-24.203636 9.053091-7.773091 16.151273-16.826182 21.178181-26.973091a75.543273 75.543273 0 0 0 0-67.351273z" ></path></symbol><symbol id="icon-sanjiaoxing" viewBox="0 0 1024 1024"><path d="M1024 512L0 1024V0z" ></path></symbol><symbol id="icon-iconfontsousuo" viewBox="0 0 1024 1024"><path d="M455.494979 805.069193c-194.888903 0-353.441893-158.552792-353.441893-353.434928 0-194.881113 158.55299-353.433905 353.441893-353.433905S808.944036 256.753152 808.944036 451.634265C808.944036 646.515378 650.383882 805.069193 455.494979 805.069193M455.494979 185.194516c-146.920627 0-266.44426 119.526018-266.44426 266.439749 0 146.914754 119.523633 266.440772 266.44426 266.440772s266.4504-119.526018 266.4504-266.440772C721.945379 304.720534 602.415606 185.194516 455.494979 185.194516" fill="#272636" ></path><path d="M868.304189 917.954991c-13.70566 0-27.402111-5.228061-37.85865-15.678043L645.790086 717.636039c-20.905916-20.906104-20.905916-54.804077 0-75.714274 20.914103-20.899964 54.806268-20.899964 75.718324 0l184.654429 184.640908c20.90694 20.906104 20.90694 54.804077 0 75.714274C895.705277 912.72693 882.008826 917.954991 868.304189 917.954991" fill="#272636" ></path></symbol><symbol id="icon-xiangshang2" viewBox="0 0 1024 1024"><path d="M887.328477 617.152318 533.951458 267.007553c-0.512619-0.512619-1.216181-0.672598-1.759763-1.152533-0.127295-0.127295-0.159978-0.319957-0.287273-0.447252-12.576374-12.416396-32.831716-12.352748-45.280796 0.192662L136.511544 618.944765c-12.447359 12.576374-12.352748 32.800753 0.192662 45.248112 6.239161 6.175514 14.399785 9.280473 22.527725 9.280473 8.224271 0 16.479505-3.168606 22.720387-9.471415L509.792985 333.185325l332.480043 329.407768c6.239161 6.175514 14.368821 9.280473 22.527725 9.280473 8.255235 0 16.479505-3.168606 22.720387-9.471415C899.968499 649.85674 899.872168 629.599677 887.328477 617.152318z" fill="#575B66" ></path></symbol><symbol id="icon-xiangxia2" viewBox="0 0 1024 1024"><path d="M890.335385 330.911222c-12.576374-12.416396-32.800753-12.352748-45.248112 0.192662L517.248327 661.951458 184.831931 332.512727c-12.576374-12.447359-32.800753-12.352748-45.280796 0.192662-12.447359 12.576374-12.352748 32.831716 0.192662 45.280796l353.311652 350.112082c0.543583 0.543583 1.247144 0.672598 1.792447 1.183497 0.127295 0.127295 0.159978 0.287273 0.287273 0.416288 6.239161 6.175514 14.399785 9.280473 22.527725 9.280473 8.224271 0 16.479505-3.168606 22.720387-9.471415l350.112082-353.311652C902.975407 363.615643 902.880796 343.360301 890.335385 330.911222z" fill="#575B66" ></path></symbol><symbol id="icon-xiangyou1" viewBox="0 0 1024 1024"><path d="M761.055557 532.128047c0.512619-0.992555 1.343475-1.823411 1.792447-2.848649 8.800538-18.304636 5.919204-40.703346-9.664077-55.424808L399.935923 139.743798c-19.264507-18.208305-49.631179-17.344765-67.872168 1.888778-18.208305 19.264507-17.375729 49.631179 1.888778 67.872168l316.960409 299.839269L335.199677 813.631716c-19.071845 18.399247-19.648112 48.767639-1.247144 67.872168 9.407768 9.791372 21.984142 14.688778 34.560516 14.688778 12.000108 0 24.000215-4.479398 33.311652-13.439914l350.048434-337.375729c0.672598-0.672598 0.927187-1.599785 1.599785-2.303346 0.512619-0.479935 1.056202-0.832576 1.567101-1.343475C757.759656 538.879828 759.199462 535.391265 761.055557 532.128047z" fill="#575B66" ></path></symbol><symbol id="icon-xiangzuo" viewBox="0 0 1024 1024"><path d="M401.066667 512l302.933333 302.933333-59.733333 59.733334L341.333333 571.733333 281.6 512 341.333333 452.266667l302.933334-302.933334 59.733333 59.733334L401.066667 512z" fill="#444444" ></path></symbol></svg>',(i=>{var t=(e=(e=document.getElementsByTagName("script"))[e.length-1]).getAttribute("data-injectcss"),e=e.getAttribute("data-disable-injectsvg");if(!e){var o,n,l,c,a,s=function(t,e){e.parentNode.insertBefore(t,e)};if(t&&!i.__iconfont__svg__cssinject__){i.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(t){console&&console.log(t)}}o=function(){var t,e=document.createElement("div");e.innerHTML=i._iconfont_svg_string_4599756,(e=e.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",e=e,(t=document.body).firstChild?s(e,t.firstChild):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(n=function(){document.removeEventListener("DOMContentLoaded",n,!1),o()},document.addEventListener("DOMContentLoaded",n,!1)):document.attachEvent&&(l=o,c=i.document,a=!1,m(),c.onreadystatechange=function(){"complete"==c.readyState&&(c.onreadystatechange=null,d())})}function d(){a||(a=!0,l())}function m(){try{c.documentElement.doScroll("left")}catch(t){return void setTimeout(m,50)}d()}})(window);
\ No newline at end of file
{
"id": "4599756",
"name": "木卫1.0",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "5093357",
"name": "地址",
"font_class": "dizhi",
"unicode": "e60c",
"unicode_decimal": 58892
},
{
"icon_id": "7193656",
"name": "B-复选框",
"font_class": "B-fuxuankuang",
"unicode": "e728",
"unicode_decimal": 59176
},
{
"icon_id": "40897190",
"name": "email",
"font_class": "email",
"unicode": "e693",
"unicode_decimal": 59027
},
{
"icon_id": "40897191",
"name": "phone",
"font_class": "phone",
"unicode": "e694",
"unicode_decimal": 59028
},
{
"icon_id": "39418529",
"name": "三角形",
"font_class": "sanjiaoxing",
"unicode": "e637",
"unicode_decimal": 58935
},
{
"icon_id": "552278",
"name": "sousuo",
"font_class": "iconfontsousuo",
"unicode": "e610",
"unicode_decimal": 58896
},
{
"icon_id": "577395",
"name": "向上2",
"font_class": "xiangshang2",
"unicode": "e76e",
"unicode_decimal": 59246
},
{
"icon_id": "577399",
"name": "向下2",
"font_class": "xiangxia2",
"unicode": "e772",
"unicode_decimal": 59250
},
{
"icon_id": "577402",
"name": "向右1",
"font_class": "xiangyou1",
"unicode": "e775",
"unicode_decimal": 59253
},
{
"icon_id": "5387613",
"name": "向左",
"font_class": "xiangzuo",
"unicode": "eb15",
"unicode_decimal": 60181
}
]
}
No preview for this file type
No preview for this file type
No preview for this file type
import type { BrandAndClassType, supplierDataType } from '@/types/searchTypes'
import type { ListSortType } from '@/components/ListSort/types'
export const brandsAndClasssReducer = (state: BrandAndClassType, action: any) => {
if (action.type === 'brandsInit' || action.type === 'classsInit') {
let newBrand: BrandAndClassType = []
const datasg = [...action.value]
datasg.forEach((item) => {
const id_ = action.type === 'brandsInit' ? String(item.brand_id) : String(item.goods_type_id2)
const name_ = action.type === 'brandsInit' ? String(item.brand_name) : String(item.goods_type_name2)
newBrand = [...newBrand, { id: id_, value: name_, checked: false }]
})
const uniqueBrand = newBrand.reduce((acc: BrandAndClassType, current) => {
if (!acc.some(item => item.id === current.id)) {
if(current.value){
acc.push(current);
}
}
return acc;
}, []);
return uniqueBrand
}
if (action.type === 'brandsUpdate' || action.type === 'classsUpdate') {
let newList = [...state]
if (!action.value) {
newList.forEach((item) => {
item.checked = false
})
} else {
const brandToUpdate = newList.find(item => item.id === action.value)
if (brandToUpdate) {
brandToUpdate.checked = !brandToUpdate.checked;
}
}
return newList
}
return state
}
export const supplierDataReducer = (state: Array<supplierDataType>, action: {type:string,value:Array<supplierDataType>,brandsR?:BrandAndClassType,classsR?:BrandAndClassType,sortObj?:ListSortType}) => {
switch (action.type) {
case 'init':
const newState=[...action.value]
return newState;
case 'change':
let initList=[...action.value]
const sorts_=action.sortObj
if(sorts_?.sortType===2){
initList.forEach(item=>{
item.data.sort((a, b) => {
const astock=sorts_?.stockSort!=='top'?(Number(a.stock)||0):(Number(b.stock)||0)
const bstock=sorts_?.stockSort!=='top'?(Number(b.stock)||0):(Number(a.stock)||0)
if (astock > bstock) {
return 1;
}
if (astock< bstock) {
return -1;
}
return 0;
})
})
}
if(sorts_?.sortType===3){
initList.forEach(item=>{
item.data.sort((a, b) => {
let aprice=0
if(a.ladder_price.length>0){
aprice=Number(a.ladder_price[a.ladder_price.length-1].price_cn)||0
}
let bprice=0
if(b.ladder_price.length>0){
bprice=Number(b.ladder_price[b.ladder_price.length-1].price_cn)||0
}
const aval=sorts_?.priceSort!=='top'?aprice:bprice
const bval=sorts_?.priceSort!=='top'?bprice:aprice
if (aval > bval) {
return 1;
}
if (aval< bval) {
return -1;
}
return 0;
})
})
}
if(sorts_?.isStock){
initList.forEach(item=>{
const data_=item.data.filter(itemChild=>
Number(itemChild.stock)>0
)
item.data=data_
})
}
let checkBrand=action.brandsR?.filter(item => item.checked).map(item => item.id)
let checkClass=action.classsR?.filter(item => item.checked).map(item => item.id)
// if(checkBrand?.length===0){
// checkBrand=action.brandsR?.map(item => item.id)
// }
// if(checkClass?.length===0){
// checkClass=action.classsR?.map(item => item.id)
// }
if(checkBrand!.length>0){
initList.forEach(item=>{
const data_=item.data.filter(itemChild=>
checkBrand?.indexOf(String(itemChild.brand_id))!==-1
)
item.data=data_
})
}
if(checkClass!.length>0){
initList.forEach(item=>{
const data_=item.data.filter(itemChild=>
checkClass?.indexOf(String(itemChild.goods_type_id2))!==-1
)
item.data=data_
})
}
// initList.forEach(item=>{
// const data_=item.data.filter(itemChild=>
// checkBrand?.indexOf(String(itemChild.brand_id))!==-1&&
// checkClass?.indexOf(String(itemChild.goods_type_id2))!==-1
// )
// item.data=data_
// })
initList=initList.filter(item=>item.data.length>0)
return initList;
default:
return state
}
}
import {API_URL} from '../configReact'
export async function getBrandListData(brand_id?:string | string[] | undefined) {
// 数据获取逻辑
// 在这里进行异步数据获取
const res = await fetch(API_URL+'/api/home/getCateList');
const res2 = await fetch(API_URL+'/api/brand/getBrandDetail?brand_id='+brand_id);
const [cateList, brandInfoData] = await Promise.all([
res.json(),
res2.json()
]);
// 将数据作为 props 返回
return { props: { cateList ,brandInfoData} };
}
\ No newline at end of file
import {API_URL} from '../configReact'
export async function getBrandMapData() {
// 数据获取逻辑
// 在这里进行异步数据获取
const res = await fetch(API_URL+'/api/home/getCateList');
const res2 = await fetch(API_URL+'/api/brand/getBrandList');
const [cateList, brandMapData] = await Promise.all([
res.json(),
res2.json()
]);
// 将数据作为 props 返回
return { props: { cateList ,brandMapData} };
}
\ No newline at end of file
import {API_URL} from '../configReact'
export async function getCateList() {
const res = await fetch(API_URL+'/api/home/getCateList');
const cateList = await res.json();
return { props: { cateList } };
}
import {API_URL} from '../configReact'
export async function getClassMapData() {
// 数据获取逻辑
// 在这里进行异步数据获取
const res = await fetch(API_URL+'/api/home/getCateList');
const res2 = await fetch(API_URL+'/api/goods/getGoodsType');
const [cateList, classMapData] = await Promise.all([
res.json(),
res2.json()
]);
// 将数据作为 props 返回
return { props: { cateList ,classMapData} };
}
\ No newline at end of file
import {API_URL} from '../configReact'
export async function getDetailData(sku_id?:string ) {
// 数据获取逻辑
// 在这里进行异步数据获取
const res = await fetch(API_URL+'/api/home/getCateList');
const res2 = await fetch(API_URL+'/api/goodsSku/getGoodsSkuDetail?sku_id='+sku_id?.split(".")[0]);
const [cateList, detailInfoData] = await Promise.all([
res.json(),
res2.json()
]);
// 将数据作为 props 返回
return { props: { cateList ,detailInfoData} };
}
\ No newline at end of file
import {API_URL} from '../configReact'
export async function getHeadData() {
// 数据获取逻辑
// 在这里进行异步数据获取
const res = await fetch(API_URL+'/shopping-project/mock/categoryAndTagList.json');
const res2 = await fetch(API_URL+'/shopping-project/mock/home.json');
const [data1, data2] = await Promise.all([
res.json(),
res2.json()
]);
// 将数据作为 props 返回
return { props: { data1 ,data2} };
}
\ No newline at end of file
import {API_URL} from '../configReact'
export async function getHomeData() {
// 数据获取逻辑
// 在这里进行异步数据获取
const res = await fetch(API_URL+'/api/home/getCateList');
const res2 = await fetch(API_URL+'/api/home/getHomepageList');
const [cateList, homepageList] = await Promise.all([
res.json(),
res2.json()
]);
// 将数据作为 props 返回
return { props: { cateList ,homepageList} };
}
\ No newline at end of file
{
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./*"
]
},
"target": "es2015",
"forceConsistentCasingInFileNames": true
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}
export type authResponseType = {
web_user_id?:number;
contacts_name?:string;
contacts_tel?:string;
contacts_email?:string;
contacts_qq?:string;
sale_id?:number;
customer_id?:number;
status?:number;
create_time?:number;
wechat_union_id?:string;
password?:string;
source?:number;
web_user_account?:string;
create_time_cn?:string;
company_name?:string;
tax_no?:string;
company_address?:string;
head_img?:string;
}
export type brandMapResponseType = {
code: number|string,
data: {
more_brand_list:Array<brandItenType>,
popular_brand_list:Array<brandItenType>
},
msg:string
}
export type brandItenType={
goods_brand_id:number|string,
brand_logo:string,
brand_name:string
}
import type { dataListItemType } from '@/components/ListOneItem/types'
export type brandResponseType = {
code: number | string,
data: {
lists: Array<dataListItemType>,
total: number|string
},
msg: string
}
export type requestDataType = {
page_size: number,
page: number,
standard_brand_id: string | string[] | undefined,
'stock/gt'?: number | string,
'stock/sort'?: 'asc' | 'desc',
'single_price/sort'?: 'asc' | 'desc'
}
export type brandInfoResponseType = {
code: number | string,
data: brandInfoType,
msg: string
}
export type brandInfoType = {
"goods_brand_id": string | number,
"brand_name": string,
"brand_logo": string,
"brand_name_cn": string,
"brand_code": string,
"region": 1,
"brand_desc": string
}
import type { dataListItemType } from '@/components/ListOneItem/types'
export type classResponseType = {
code: number|string,
data: {
lists:Array<dataListItemType>,
total:number|string
},
msg:string
}
export type requestDataType={
page_size:number,
page:number,
class_id1:string | string[] | undefined,
class_id2?:string | string[] | undefined,
'stock/gt'?:number|string,
'stock/sort'?:'asc'|'desc',
'single_price/sort'?:'asc'|'desc'
}
export type classMapResponseType = {
code: number | string,
data:classItemType[],
msg: string
}
export type classItemType = {
"goods_type_id": string | number,
"goods_type_name": string,
child?:classItemType[]
}
export type DetailResponseType = {
code: number|string,
data: {
sku_info:skuInfoResponseType,
other_sku_list:Array<{
sku_name:string,
sku_id:string|number,
brand_name:string,
goods_images:string,
single_price:string
}>
}|null,
msg:string
}
export type skuInfoResponseType = {
sku_name:string,
goods_name?:string,
brand_name?:string,
goods_images?:string,
encap:string,
batch_sn:string,
remark:string,
goods_type_name:string,
goods_type_name2:string,
goods_type_id?:string,
goods_type_id2?:string,
moq:number,
multiple:number,
stock:number,
cn_delivery_time:string,
hk_delivery_time:string,
goods_details:string;
attrs:Array<{name:string;value:string}>;
ladder_price:Array<{
price_cn:number,
price_us:number,
purchase?:string|number,
purchases?:string|number,
checked?:boolean;
}>,
sku_id: string
}|undefined|null
export type ResponseTypeHome = {
code: number|string,
data: {
on_sale_list?:Array<onSaleListType>,
recommend_brand_list?:Array<recommendBrandListType>,
recommend_goods_list?:Array<recommendGoodsListType>
}|null,
msg:string
}|null
export type onSaleListType = {
goods_images:string,
sku_id:string|number,
sku_name:string,
single_price:string,
brand_name:string
}
export type recommendBrandListType = {
brand_logo:string,
brand_name:string,
goods_brand_id:string|number
}
export type recommendGoodsListType = {
goods_images:string,
brand_name:string,
sku_id:string|number,
single_price:string|number,
sku_name:string
}
export type invoiceMapResponseType = {
code: number|string,
data: {
list:Array<invoiceItemType>
},
msg:string
}
export type invoiceItemType={
invoice_type: number,
tax_title:number|string,
tax_no:string,
bank_name:string,
bank_account:string,
company_phone:string,
company_address:string,
}
export type NoticeResponseType = {
code: number,
data: {list:listType,total:number},
msg:string
}
export type listType = Array<{
article_desc: string,
article_title: string,
article_id: number,
cat_id:number
isAuto?: boolean,
create_time_cn:string
}>
export interface DataType {
key: React.Key;
name: string;
goods_number: number;
address: string;
goods_price: string;
goods_amount: string;
latest_log: string;
latest_log_time: string;
latest_log_status_text: string;
rec_id: number,
goods_sn: string,
brand_name: string,
sku_id: number,
status: number,
delivery_place_type_text: string,
supplier_name: string,
remark: string,
sku_name: string,
goods_name: string,
delivery_place_type: string,
iso_code_text?:string;
}
\ No newline at end of file
import type { dataListItemType } from '@/components/ListOneItem/types'
export type ResponseTypeSearch = {
code: number | string,
data:Array<supplierDataType>,
msg: string
}
export type supplierDataType= {
supplier_name?: string,
supplier_id?:string|number,
data:Array<dataListItemType>
}
export type BrandAndClassType = Array<{
id: string,
value: string,
checked: boolean
}>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment