Commit 794a6e44 by 肖康

commit

parent 48c1320e
Showing with 4103 additions and 0 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
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.
.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
.mvFooterBox {
height: 160px;
background: #F4F4F4;
.cons {
width: 1226px;
height: 120px;
margin: 0 auto;
padding-top: 25px;
.img {
height: 70px;
width: 70px;
border-radius: 70px;
}
.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/qq.png' alt='' className={`${footerCss.img} `}/>
<div className={`${footerCss.navlink} cons boxsiz row bothSide`}>
<Link href='/brandMap'>品牌馆</Link>
<Link href='/about'>关于我们</Link>
<Link href='/contact'>联系我们</Link>
</div>
</div>
<div className={footerCss.footerBot}>
<div className={`${footerCss.consp} row bothSide`}>
<span>©2021深圳市猎芯科技有限公司 ALL RIGHTS RESERVED <a rel='noopener noreferrer' target='_blank' href='https://beian.miit.gov.cn/#/Integrated/index'>粤ICP备17064931号</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;
.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;
span {
transition : all 0.5s;
display : inline-block;
vertical-align: middle;
width : 0px;
overflow : hidden;
i {
font-size: 11px;
color : #FF9A00;
position : relative;
top : -2px;
}
}
}
}
&:hover {
.spann {
color: #FF9A00;
span {
width: 25px;
}
}
}
.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'
const NavBig = (props: ResponseTypeCateList) => {
const router = useRouter()
const items = [{
url: '/',
name: '首页'
}, {
url: '/brandMap',
name: '品牌馆'
}, {
url: '/about',
name: '关于我们'
}, {
url: '/contact',
name: '联系我们'
}]
const classLists = props.data?.nav_list || []
return (
<>
<div className={styles.mvNavBig}>
<div className={`${styles.navbox} row`}>
<div className={styles.classBoxs}>
<Link className={styles.titleLc} href='/classMap'>查看全部</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={`/category/${item.goods_type_id}`}>
<span><i className='icon iconfont icon-sanjiaoxing'></i></span>
{item.goods_type_name}
</Link>
</div>
<div className={styles.boxTwoRight}>
<div className={styles.classconsjk}>
<div className={styles.twoClassGroup}>
<Link href={`/category/${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={`/category/${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={router.pathname === 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
}
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);
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 img{width:117px;height:97px}.mvSearchBox .cons .searchInputBox{width:794px;height:40px;background:#FFFFFF;border-radius:2px;border:1px solid #FF9A00;margin-top:13px}.mvSearchBox .cons .searchInputBox .inputGoods{width:588px;height:38px;line-height:38px;padding:0 15px;border-right:1px solid #FF9A00}.mvSearchBox .cons .searchInputBox .inputNums{width:133px;height:38px;line-height:38px;padding:0 15px;border-right:1px solid #FF9A00}.mvSearchBox .cons .searchInputBox .searchbtn{width:71px;height:38px;cursor:pointer;color:#FF9A00}.mvSearchBox .cons .searchInputBox .searchbtn i{font-size:26px}
.mvSearchBox{
height: 146px;
background: #FFFFFF;
.cons{
width:1226px;
margin:0 auto;
padding-top: 22px;
img{
width: 117px;
height: 97px;
}
.searchInputBox{
width: 794px;
height: 40px;
background: #FFFFFF;
border-radius: 2px;
border: 1px solid #FF9A00;
margin-top: 13px;
.inputGoods{
width:588px;
height:38px;
line-height: 38px;
padding: 0 15px;
border-right: 1px solid #FF9A00;
}
.inputNums{
width:133px;
height:38px;
line-height: 38px;
padding: 0 15px;
border-right: 1px solid #FF9A00;
}
.searchbtn{
width:71px;
height:38px;
cursor: pointer;
i{
font-size: 26px;
}
color:#FF9A00;
}
}
}
}
\ 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'
const SearchH = () => {
const router=useRouter()
const {query}=router
let keywords=''
let nums ='';
if(router.pathname==='/search'){
keywords=String(query.keyword)||''
nums = String(query.num)||''
}
const [key,setKey]=useState<string>(keywords)
const [num,setNum]=useState<string>(nums)
const {message}=useToast()
const goSearch=()=>{
if(key.trim().length<2){
message("请输入至少2个字符")
return
}
router.push(`/search?keyword=${key}&num=${num}`)
}
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 src='/images/qq.png' alt='' /></Link>
<div className={`${styles.searchInputBox} row boxsiz`}>
<input type='text' className={`${styles.inputGoods} boxsiz`} value={key} onChange={(e)=>{setKey(e.target.value)}} placeholder='请输入元器件型号、参数查找' />
<input type='text' className={`${styles.inputNums} boxsiz`} value={num} placeholder='需求数量' onChange={(e)=>{changeNum(e)}}/>
<div className={`${styles.searchbtn} row rowCenter verCenter`} onClick={goSearch}><i className='icon iconfont icon-iconfontsousuo '></i></div>
</div>
</div>
</div>
</>
)
}
export default SearchH
\ 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'
const TopH=()=>{
return (
<>
<div className={styles.mvTopBox}>
<div className={`${styles.con} row bothSide verCenter`}>
<div ></div>
<div className='row verCenter'>
<Link href='/about'>关于我们</Link>
<span className={styles.line}></span>
<Link href='/contact'>联系我们</Link>
<span className={styles.line}></span>
<Link href='/notice'>公告</Link>
<span className={styles.rqq}><QqIcon /></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()
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
.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:20px;box-sizing:border-box;flex-shrink:0}.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 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 .ljxunj{cursor:pointer;width:80px;height:30px;background:#FF9A00;color:#fff;font-size:14px;margin-right:30px;text-align:center;line-height:30px}.listGroupOneItem .cons .item.pt48{padding-top:48px}.listGroupOneItem .cons .item.w198{width:198px}.listGroupOneItem .cons .item.w345{width:345px}.listGroupOneItem .cons .item.w322{width:322px}
.listGroupOneItem{
padding:0px 27px;
background: #fff;
.cons{
border-top: 1px solid #e7e7e7;
padding:10px 0px;
.item{
margin-right: 20px;
box-sizing: border-box;
flex-shrink: 0;
&: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;
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%;}
}
.ljxunj{
cursor: pointer;
width: 80px;
height: 30px;
background: #FF9A00;
color:#fff;
font-size: 14px;
margin-right: 30px;
text-align: center;
line-height: 30px;
}
&.pt48{padding-top: 48px;}
&.w198{width:198px;}
&.w345{width:345px;}
&.w322{width:322px;}
}
}
}
\ No newline at end of file
import styles from './index.module.scss'
import Link from 'next/link'
import QqIcon from '../QqIcon'
import type {dataListItemType} from './types'
import { QQURL } from '@/configReact'
const ListOneItem = (props:dataListItemType) => {
const itemInfo={...props!}
return (
<>
<div className={styles.listGroupOneItem}>
<div className={`${styles.cons} row`}>
<div className={styles.item}>
<Link href={`/detail/${itemInfo.goods_id}`}><img
src={itemInfo.goods_images||'http://static.ichunt.com//dist/res/home/images/goods_default.png'}
className={styles.goodsImg} alt=""
onError={(e) => {
e.currentTarget.src = 'http://static.ichunt.com//dist/res/home/images/goods_default.png';
}}
/>
</Link>
</div>
<div className={`${styles.item} ${styles.w198}`}>
<Link className={styles.goodsName} href={`/detail/${itemInfo.goods_id}`}>{itemInfo.goods_name}</Link>
<p>品牌:{itemInfo.brand_name}</p>
<p>参数:{itemInfo.class_name}</p>
</div>
<div className={`${styles.item} ${styles.w345} ${styles.pt48}`}>
<p>库存:{itemInfo.stock}</p>
<p>起订量:{itemInfo.moq} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 递增:{itemInfo.multiple}</p>
</div>
<div className={`${styles.item} ${styles.w322}`}>
{
itemInfo.ladder_price.map((item,index)=>{
return (
<div key={index+item.price_cn} className={`${styles.jtgroup} row`}><span>{item.purchases}+</span><strong>¥{item.price_cn||'--'}</strong><strong>¥{item.price_us||'--'}</strong></div>
)
})
}
</div>
<div className={`${styles.item} row`}>
<a href={QQURL} rel="noreferrer" className={styles.ljxunj} target='_blank'>立即询价</a>
<QqIcon />
</div>
</div>
</div>
</>
)
}
export default ListOneItem
\ No newline at end of file
export type dataListItemType = {
sku_name: string;
brand_name: string;
brand_id: string|number;
class_id2?:string|number;
class_id1?:string|number;
class_name2?:string;
class_name: string;
cn_delivery_time: string;
hk_delivery_time: string;
goods_id: string;
goods_images: string;
goods_name: string;
moq: number;
multiple: number;
stock: number;
supplier_name: string;
ladder_price: Array<{
price_cn: number;
price_cost_cn: number;
price_us: number;
purchases: 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 降序
}
import { QQURL } from "@/configReact";
import { useContext } from "react";
const QqIcon = () => {
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
export const QQURL='https://url.cn/uia2no5Z?_type=wpa&amp;qidian=true'
export const API_URL='http://erpweb.liexindev.net'
export const useCookies = () => {
const setCookie = (
name: string,
value: string | number,
time: number,
domain?: string
) => {
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;
}
const getCookie = (name: string): string | null => {
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;
}
return { setCookie, getCookie }
}
import { useCallback, useEffect, useRef, useState } from 'react';
import axios, { AxiosRequestConfig } from "axios"
import { useToast } from './useToast';
// 默认请求参数
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 controllerRef = useRef(new AbortController())
const cancel = () => {
controllerRef.current.abort()
}
const request = useCallback((requestOption?: AxiosRequestConfig) => {
setData(null)
setLoaded(false)
if(options.loading!==false){
loadingRef.current()
}
return axios.request<T>({
baseURL:'http://erpweb.liexindev.net',
...requestOption,
signal: controllerRef.current.signal,
headers: localStorage.getItem("token") ? {
token: localStorage.getItem("token")
} : {}
}).then((response) => {
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, cancel }
}
export default useRequest
\ No newline at end of file
import Head from "next/head";
import { useRouter } from "next/router";
export const useSeoTitle = () => {
const router=useRouter()
let titlestr='404'
const titleKeywords:any = {
'/': { title: '首页' },
'/search': { title: '搜索结果' },
'/detail': { title: '商品详情' },
'/brandMap': { title: '品牌馆' },
'/Brand': { title: '品牌结果' },
'/classMap': { title: '分类地图' },
'/category': { title: '分类结果' },
'/about': { title: '关于我们' },
'/contact': { title: '联系我们' },
'/notice': { title: '公告' },
}
if (Object.keys(titleKeywords).indexOf(router.pathname) !== -1) {
titlestr=titleKeywords[router.pathname]['title']
}
if(router.pathname.indexOf('/detail/')!==-1){
titlestr='商品详情'
}
if(router.pathname.indexOf('/brand/')!==-1){
titlestr='品牌结果'
}
if(router.pathname.indexOf('/category/')!==-1){
titlestr='分类结果'
}
return (
<Head>
<title>{`麒麟电子商城-${titlestr}`}</title>
<meta name="keywords" content="" />
<meta name="description" content="" />
</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) => {
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);
}
}
const loading = ((show=true) => {
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);
}
}
})
return { message,loading };
}
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false, // 关闭 React 严格模式
// 配置代理
async rewrites() {
return [{
source: '/api/:path*',
destination: 'http://erpweb.liexindev.net/api/:path*',
}, ];
},
};
export default nextConfig;
\ No newline at end of file
This diff could not be displayed because it is too large.
{
"name": "reactdemo",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"axios": "^1.7.2",
"next": "14.2.5",
"react": "^18",
"react-dom": "^18",
"react-paginate": "^8.2.0",
"sass": "^1.77.8",
"swiper": "^11.1.5"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.2.5",
"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
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 '../public/styles/font/iconfont.css'
import '../public/styles/base.scss'
import type { AppProps } from 'next/app';
const MyApp= ({ Component, pageProps }:AppProps) => {
return <Component {...pageProps} />
};
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:296px;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: 296px;
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 getStaticProps: GetServerSideProps = async () => {
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="https://img.ichunt.com/test/images/cms/202405/30/a263b85bf297ae7d85f68a01b5db320d.jpg" alt="" />
</div>
</div>
</div>
<Footer />
</main>
</>
)
}
export default Page
\ 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 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, brandInfoType } from './types'
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 { getBrandListData } from "@/server/getBrandListData";
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
import Paginate from '@/components/Header/components/Pagination';
export const getServerSideProps: GetServerSideProps = async (context) => {
const { query } = context;
return getBrandListData(query.brand_id)
}
const Page = (props: { cateList: ResponseTypeCateList,brandInfoData:brandInfoResponseType }) => {
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 onChange = (selectedItem: { selected: number; }) => {
setPage(selectedItem.selected + 1)
}
return (
<>
<main>
<Header {...props.cateList} />
<BreadNav><strong>"{brandInfo?.brand_name}"的型号搜索结果</strong></BreadNav>
<div className={`${styles.mvBrandlistPage} w1226`} >
<div className={`${styles.brandheadsl} row boxsiz`}>
<img src={brandInfo?.brand_logo || 'http://static.ichunt.com//dist/res/home/images/goods_default.png'} 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.goods_id} {...item} />
)
})
}
{shouNoData ? <ListNoData /> : ''}
</div>
<Paginate total={total} currentPage={page} onPageChange={onChange} />
</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
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
}
.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}.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;
&: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';
import Link from 'next/link';
export const getStaticProps: 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}`} 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}`} 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
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 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'
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 Paginate from '@/components/Header/components/Pagination';
import { getCateList } from "@/server/getCateList";
export const getServerSideProps: GetServerSideProps = async () => {
return getCateList()
}
const Category = (props: { cateList: ResponseTypeCateList }) => {
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)
}
} else {
setShouNoData(true)
}
})
}, [classInfoRequest, class_id2,class_id1, page, sortObj])
const onChange = (selectedItem: { selected: number; }) => {
setPage(selectedItem.selected + 1)
}
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.goods_id} {...item} />
)
})
}
{shouNoData ? <ListNoData /> : ''}
</div>
<Paginate total={total} currentPage={page} onPageChange={onChange} />
</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
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'
}
.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';
import type { ResponseTypeCateList } from '@/components/Header/components/NavBig/types'
export const getStaticProps: 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={`/category/${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={`/category/${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
export type classMapResponseType = {
code: number | string,
data:classItemType[],
msg: string
}
export type classItemType = {
"goods_type_id": string | number,
"goods_type_name": string,
child?:classItemType[]
}
\ 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{width:267px}.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 .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:296px;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;
}
margin-right: 33px;
}
.rxs{
font-size: 16px;
color: #888888;
p{
color:#000000;
font-weight: bold;
margin-top: 7px;
}
}
}
}
img{
width: 296px;
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 getStaticProps: GetServerSideProps = async () => {
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>
<img src="https://img.ichunt.com/test/images/cms/202405/30/a263b85bf297ae7d85f68a01b5db320d.jpg" alt="" />
</div>
</div>
</div>
<Footer />
</main>
</>
)
}
export default Page
\ 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 styles from './index.module.scss'
import DetailHead from './components/DetailHead';
import DetailSection from './components/DetailSection';
import BreadNav from '../../components/BreadNav';
import type { DetailResponseType } from './types'
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'
export const getServerSideProps: GetServerSideProps = async (context) => {
const { query } = context;
return getDetailData(query.sku_id)
}
const Page = (props: { cateList: ResponseTypeCateList, brandInfoData: DetailResponseType }) => {
const detailData = props.brandInfoData
return (
<>
<main>
<Header {...props.cateList} />
<div className={styles.mvDetailPage}>
{
detailData && detailData.data?.sku_info ?
<>
<BreadNav > <strong>{detailData.data?.sku_info?.sku_name}</strong></BreadNav>
<DetailHead {...detailData} />
<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 { DetailResponseType } from '../types'
import styles from '../index.module.scss'
import { QQURL } from "@/configReact";
const DetailHead = (props: DetailResponseType) => {
const sku_info = props!.data?.sku_info!
return (
<>
<div className={`${styles.detailHeaders} w1226 row bothSide boxsiz`}>
<div className={`${styles.l} row`}>
<img src={sku_info.goods_images || 'http://static.ichunt.com//dist/res/home/images/goods_default.png'} 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>商品类别:低压差线性稳压(LDO)</p>
<p>封装规格:{sku_info.encap}</p>
<p>描述:{sku_info.remark}</p>
</div>
<div className={`${styles.handle} row bothSide verCenter`}>
<QqIcon />
<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}>交期:HK {sku_info.hk_delivery_time}</span>
</p>
<p className='row'>
<span className={styles.items}> 批次:{sku_info.batch_sn}</span>
<span className={styles.items}>交期:大陆 {sku_info.cn_delivery_time}</span>
</p>
<p className={`${styles.mb23} row`}>
<span className={styles.items}> 起订量: {sku_info.moq}</span>
<span className={styles.items}>递增: {sku_info.multiple}</span>
</p>
{
sku_info.ladder_price.map((item,index) => {
return (
<p className='row' key={index}>
<span className={styles.items}> {item.purchase}+</span>
<span className={`${styles.items} row`}><span>¥ {item.price_cn||0}</span><span>$ {item.price_us||0}</span></span>
</p>
)
})
}
</div>
</div>
</>
)
}
export default DetailHead
\ No newline at end of file
import Link from 'next/link'
import type { DetailResponseType } from '../types'
import styles from '../index.module.scss'
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`}>
<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>
<div className={`${styles.goodsMask} row`}>
<div>介绍:</div>
<h4 >{goods_details}</h4>
</div>
</div>
<div className={styles.secr}>
{
other_sku_list.map(item => {
return (
<Link href={`/detail/${item.sku_id}`} className={`${styles.item} boxsiz`} key={item.sku_id}>
<img src={item.goods_images || 'http://static.ichunt.com//dist/res/home/images/goods_default.png'} 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 .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 .btn{width:80px;height:30px;background:#FF9A00;line-height:30px;text-align:center;color:#fff}.mvDetailPage .detailHeaders .r{width:452px;min-height:222px;background:#FFFCF8;padding:10px 50px}.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 .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;
}
.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{
.btn{
width: 80px;
height: 30px;
background: #FF9A00;
line-height: 30px;
text-align: center;
color:#fff;
}
}
}
.r{
width: 452px;
min-height: 222px;
background: #FFFCF8;
padding: 10px 50px;
.mb23{
margin-bottom: 24px;
}
.items{
width: 50%;
font-size: 12px;
color: #000000;
line-height: 25px;
span{
width:50%;
}
}
}
}
.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
export type DetailResponseType = {
code: number|string,
data: {
sku_info:skuInfoResponseType|null,
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,
brand_name?:string,
goods_images:string,
encap:string,
batch_sn:string,
remark:string,
goods_type_name: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:number
}>
}
\ 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 './index/types'
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>
);
}
//getServerSideProps
export const getStaticProps: 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';
const HomeBanner = () => {
const bannerList = [
{
title: '图片1',
url: '/',
image: 'https://img.ichunt.com/test/images/cms/202405/30/3b8eeac7cba38f1361586f25b0f95a6b.jpg',
},
{
title: '图片2',
url: '/',
image: 'https://img.ichunt.com/test/images/cms/202405/30/a263b85bf297ae7d85f68a01b5db320d.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';
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={`/detail/${item.sku_id}`} key={item.sku_id} className={`${styles.item} boxsiz row bothSide`}>
<img src={item.goods_images || 'http://static.ichunt.com//dist/res/home/images/goods_default.png'} 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>
<a href='/' className={styles.floor1ad}>
<img src="https://img.ichunt.com/test/images/cms/202405/30/a263b85bf297ae7d85f68a01b5db320d.jpg" alt="" />
</a>
</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';
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={`/detail/${item.sku_id}`} className={`${styles.item} boxsiz`} key={item.sku_id}>
<img src={item.goods_images || 'http://static.ichunt.com//dist/res/home/images/goods_default.png'} 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';
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='/brandMap' 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}`} 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}.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}.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;
&: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;
&: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
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
}
\ 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 Paginate from '@/components/Header/components/Pagination';
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()
}
import { useEffect, useState } from 'react';
import FilterDate from './FilterDate';
import useRequest from '../../hooks/useRequest';
import type { NoticeResponseType, listType } from './types'
const Page = (props: { cateList: ResponseTypeCateList }) => {
const { cateList } = props
const [ntList, setNtList] = useState<listType>([])
const [page, setPage] = useState(1)
const [total, setTotal] = useState(0)
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_)
}
})
}, [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 onChange = (selectedItem: { selected: number; }) => {
setPage(selectedItem.selected + 1)
}
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>
)
})
}
<Paginate total={total} currentPage={page} onPageChange={onChange} />
</div>
</div>
<Footer />
</main>
</>
)
}
export default Page
\ No newline at end of file
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
}>
.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 .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 33px;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{
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;
.dataGroupSupplier{
border: 1px solid #EDEFEF;
margin-bottom: 30px;
.searchListDatas{
.listGroupOneItem:first-child{
.cons{
border-top: 0px;
}
}
}
.dataListTitle{
padding:0 33px;
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;}
}
}
}
}
\ No newline at end of file
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 './reducer';
import type { ResponseTypeSearch, supplierDataType } from './types'
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'
export const getStaticProps: GetServerSideProps = async () => {
return getCateList()
}
const supplierIdS = ['', '24']
const Page = (props: { cateList: ResponseTypeCateList }) => {
const requestCount = useRef(0)
const router = useRouter()
const keyword = router.query.keyword || '';
const num = router.query.num || '';
const { request: getListRequest } = useRequest<ResponseTypeSearch>({ manual: true })
const initSupplierList = useRef<supplierDataType[]>([])//初始化数据
const [supplierList, dispatchSupplierList] = useReducer(supplierDataReducer, [])
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 } }).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: datasg })
dispatchclasss({ type: 'classsInit', value: 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>
<Header {...props.cateList} />
<BreadNav><strong>"{keyword}"的型号搜索结果</strong></BreadNav>
<div className={`${styles.mvSearchPage} w1226`} >
<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} onClick={() => { updateBrandAndClass(1, item.id) }} className={item.checked ? `${styles.item} 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>
<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} className={item.checked ? `${styles.item} 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} />
{
supplierList.length > 0 ?
supplierList.map((item, index) => {
return (
item.data.length > 0 &&
<div className={styles.dataGroupSupplier} key={String(item.supplier_id) + index}>
<div className={styles.dataListTitle}>{item.supplier_name || '其他'}</div>
<div className={styles.searchListDatas}>
{
item.data.map(child => {
return (
<ListOneItem key={child.goods_id} {...child} />
)
})
}
</div>
{/* <div className={styles.dataListMore}>还有<b>32</b>个商品未显示,<b>点击加载更多</b></div> */}
</div>
)
})
: requestCount.current >= supplierIdS.length && <ListNoData />
}
</div>
</div>
<Footer />
</main>
</>
)
}
export default Page
\ No newline at end of file
import type { BrandAndClassType, supplierDataType } from './types'
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.class_id2)
const name_ = action.type === 'brandsInit' ? String(item.brand_name) : String(item.class_name)
newBrand = [...newBrand, { id: id_, value: name_, checked: false }]
})
const uniqueBrand = newBrand.reduce((acc: BrandAndClassType, current) => {
if (!acc.some(item => item.id === current.id)) {
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':
return [...action.value];
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[0].price_cn)||0
}
let bprice=0
if(b.ladder_price.length>0){
bprice=Number(b.ladder_price[0].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)
}
initList.forEach(item=>{
const data_=item.data.filter(itemChild=>
checkBrand?.indexOf(String(itemChild.brand_id))!==-1&&
checkClass?.indexOf(String(itemChild.class_id2))!==-1
)
item.data=data_
})
initList=initList.filter(item=>item.data.length>0)
return initList;
default:
return state
}
}
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>,
msg: string
}
export type BrandAndClassType = Array<{
id: string,
value: string,
checked: boolean
}>
No preview for this file type
No preview for this file type
No preview for this file type
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