提交 5239364a 作者: 曹云

Merge branch 'master' of ssh://git.mmcuav.cn:8222/root/sharefly-web-nextjs into caoyun

......@@ -13,7 +13,7 @@
/out/
# production
/build
/.dist/
# misc
.DS_Store
......
const dev = {
baseUrl: ''
baseUrl: 'local'
}
const prod = {
baseUrl: 'http://120.77.247.178'
baseUrl: 'https://iuav.mmcuav.cn'
}
export default process.env.NODE_ENV === 'development' ? dev : prod;
\ No newline at end of file
......@@ -5,10 +5,10 @@ import config from './config';
* @param url 请求url
* @param method 请求方法类型
* @param data 请求的参数
* @param options 额外参数
* @returns Promise<Response>
*/
export default function request(url: string, method: String = 'get', data?: any): Promise<Response<any>> {
let options = {};
export default function request(url: string, method: String = 'get', data?: any, options = {}): Promise<Response<any>> {
switch (method.toLowerCase()) {
case 'get':
......@@ -24,6 +24,7 @@ export default function request(url: string, method: String = 'get', data?: any)
case 'post':
options = {
...options,
method: 'POST',
headers: {
'Content-Type': 'application/json'
......@@ -48,6 +49,19 @@ export default function request(url: string, method: String = 'get', data?: any)
})
.then((data) => {
return data;
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('请求已中断');
console.log(error);
} else {
console.error('请求出错', error);
}
return {
code: '-1',
message: '请求失败',
result: null
}
});
}
......@@ -55,5 +69,5 @@ export default function request(url: string, method: String = 'get', data?: any)
export interface Response<T> {
code: string,
message: string,
result: T
result?: T | null
}
\ No newline at end of file
import { Space, Button, Select } from 'antd';
import styles from '../../index.module.scss';
import { Space, Button, Select, Collapse } from "antd";
import styles from "../../index.module.scss";
import api, { FilterOptionResp } from "../../api";
import { useEffect, useState } from "react";
......@@ -8,13 +8,13 @@ type Props = {
};
export default function BrandItem(props: Props) {
const [data, setData] = useState<FilterOptionResp[]>([])
const [data, setData] = useState<FilterOptionResp[]>([]);
useEffect(() => {
api.brand().then(res => {
api.brand().then((res) => {
setData(res?.result || []);
});
}, [])
}, []);
const onClick = (item: FilterOptionResp) => {
props.onChange({
......@@ -26,14 +26,46 @@ export default function BrandItem(props: Props) {
return (
<div className={styles.filterItem}>
<div className={styles.filterItemTitle}>品牌:</div>
<div className={styles.filterItemMain}>
<div className={`${styles.filterItemMain} ${data.length <= 10 && styles.disabled}`}>
<Collapse
ghost
collapsible="icon"
expandIconPosition="end"
>
<Collapse.Panel
header={
<Space size={40}>
{
data.map(item => {
return <Button type="link" key={item.id} onClick={(e) => onClick(item)}>{item.name}</Button>;
})
{data.slice(0, 10).map((item) => {
return (
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
);
})}
</Space>
}
key="1"
>
<Space size={40}>
{data.slice(10).map((item) => {
return (
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
);
})}
</Space>
</Collapse.Panel>
</Collapse>
</div>
</div>
);
......
import { Space, Button, Select } from 'antd';
import { Space, Button, Select, Collapse } from 'antd';
import styles from '../../index.module.scss';
import api, { FilterOptionResp } from "../../api";
import { useState, useEffect } from 'react';
......@@ -26,14 +26,45 @@ export default function CategoryItem(props: Props) {
return (
<div className={styles.filterItem}>
<div className={styles.filterItemTitle}>类目:</div>
<div className={styles.filterItemMain}>
<div
className={`${styles.filterItemMain} ${
data.length <= 10 && styles.disabled
}`}
>
<Collapse ghost collapsible="icon" expandIconPosition="end">
<Collapse.Panel
header={
<Space size={40}>
{
data.map(item => {
return <Button type="link" key={item.id} onClick={(e) => onClick(item)}>{item.name}</Button>;
})
{data.slice(0, 10).map((item) => {
return (
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
);
})}
</Space>
}
key="1"
>
<Space size={40}>
{data.slice(10).map((item) => {
return (
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
);
})}
</Space>
</Collapse.Panel>
</Collapse>
</div>
</div>
);
......
import { Space, Button, Select } from 'antd';
import { Space, Button, Select, Collapse } from 'antd';
import styles from '../../index.module.scss';
import api, { FilterOptionResp } from "../../api";
import { useEffect, useState } from 'react';
......@@ -26,14 +26,45 @@ export default function ModelItem(props: Props) {
return (
<div className={styles.filterItem}>
<div className={styles.filterItemTitle}>型号:</div>
<div className={styles.filterItemMain}>
<div
className={`${styles.filterItemMain} ${
data.length <= 10 && styles.disabled
}`}
>
<Collapse ghost collapsible="icon" expandIconPosition="end">
<Collapse.Panel
header={
<Space size={40}>
{
data?.map(item => {
return <Button type="link" key={item.id} onClick={(e) => onClick(item)}>{item.name}</Button>;
})
{data.slice(0, 10).map((item) => {
return (
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
);
})}
</Space>
}
key="1"
>
<Space size={40}>
{data.slice(10).map((item) => {
return (
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
);
})}
</Space>
</Collapse.Panel>
</Collapse>
</div>
</div>
);
......
import { Space, Button, Select } from 'antd';
import { Space, Button, Select, Collapse } from 'antd';
import styles from '../../index.module.scss';
import api, { FilterOptionResp } from "../../api";
import { useState, useEffect } from 'react';
......@@ -26,16 +26,45 @@ export default function PartItem(props: Props) {
return (
<div className={styles.filterItem}>
<div className={styles.filterItemTitle}>部件:</div>
<div className={styles.filterItemMain}>
<div
className={`${styles.filterItemMain} ${
data.length <= 10 && styles.disabled
}`}
>
<Collapse ghost collapsible="icon" expandIconPosition="end">
<Collapse.Panel
header={
<Space size={40}>
{data?.map((item) => {
{data.slice(0, 10).map((item) => {
return (
<Button type="link" key={item.id} onClick={(e) => onClick(item)}>
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
);
})}
</Space>
}
key="1"
>
<Space size={40}>
{data.slice(10).map((item) => {
return (
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
);
})}
</Space>
</Collapse.Panel>
</Collapse>
</div>
</div>
);
......
import { Space, Button, Select } from 'antd';
import { Space, Button, Select, Collapse } from 'antd';
import styles from '../../index.module.scss';
import api, { FilterOptionResp } from "../../api";
import { useState, useEffect } from 'react';
......@@ -26,16 +26,45 @@ export default function QualityItem(props: Props) {
return (
<div className={styles.filterItem}>
<div className={styles.filterItemTitle}>成色:</div>
<div className={styles.filterItemMain}>
<div
className={`${styles.filterItemMain} ${
data.length <= 10 && styles.disabled
}`}
>
<Collapse ghost collapsible="icon" expandIconPosition="end">
<Collapse.Panel
header={
<Space size={40}>
{data?.map((item) => {
{data.slice(0, 10).map((item) => {
return (
<Button type="link" key={item.id} onClick={(e) => onClick(item)}>
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
);
})}
</Space>
}
key="1"
>
<Space size={40}>
{data.slice(10).map((item) => {
return (
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
);
})}
</Space>
</Collapse.Panel>
</Collapse>
</div>
</div>
);
......
......@@ -9,27 +9,47 @@
}
.filterItem {
height: 42px;
min-height: 42px;
border-bottom: 1px dashed RGBA(222, 222, 222, 1);
display: flex;
align-items: center;
&:nth-last-child(1) {
border-bottom: none;
}
.filterItemTitle {
flex-shrink: 0;
width: 80px;
margin-right: 8px;
font-family: MicrosoftYaHei;
color: rgba(153, 153, 153, 1);
line-height: 20px;
height: auto;
margin-top: 10px;
}
.filterItemMain {
flex: 1;
display: flex;
justify-content: space-between;
&.disabled {
:global .ant-collapse-expand-icon {
display: none;
}
}
:global .ant-collapse-item {
.ant-collapse-expand-icon {
margin-top: 10px;
}
.ant-collapse-header {
padding: 0;
height: 42px;
line-height: 42px;
}
}
}
:global .ant-select-selector {
......
/** @type {import('next').NextConfig} */
let distDir = ".next"; //默认输出目录
if (process.env.NODE_ENV === "production") {
//生产环境用另一个目录构建,防止与dev冲突
distDir = ".dist";
}
const nextConfig = {
distDir,
reactStrictMode: true,
transpilePackages: ["antd"],
redirects() {
......@@ -14,8 +22,8 @@ const nextConfig = {
async rewrites() {
return [
{
source: "/:path*",
destination: "http://120.77.247.178/:path*",
source: "/local/:path*",
destination: "https://iuav.mmcuav.cn/:path*",
},
];
},
......
......@@ -46,7 +46,7 @@ export default function FlyingHandService() {
pageSize: 10,
})
.then((res) => {
setProductList(res.result?.list.map(item=>{return { element:leftDom(item) }}))
setProductList(res.result?.list.map(item=>{return { element:leftDom(item) }}) || [])
});
}, []);
......
import request, { Response } from "~/api/request";
export interface DynamicListParams {
pageNo: number,
pageSize: number,
userId: number
}
export interface Dynamic {
userId: number;
id: number;
title: string;
description: string;
location: string;
lat: number;
lon: number;
mediaVO: {
picture: string[];
videoUrl: string;
};
likesCount: number;
commentCount: number;
likes: boolean;
}
export interface DynamicListResp {
pageNo: 1;
pageSize: 10;
list: Array<Dynamic>;
totalCount: 0;
totalPage: 0;
}
export default {
/**
* 论坛动态列表
* @param params
* @returns
*/
dynamicList(params: DynamicListParams): Promise<Response<DynamicListResp>> {
return request("/release/dynamic/dynamicList", "get", params);
},
};
......@@ -30,6 +30,7 @@
.item {
padding: 18px 0 0;
background: #ffffff;
width: 100%;
.headImg {
margin-left: 16px;
......
......@@ -3,18 +3,57 @@ import Layout from "~/components/layout";
import styles from "./index.module.scss";
import errImg from "~/assets/errImg";
import { RightOutlined } from "@ant-design/icons";
import { useState } from "react";
import PublishMessage from './components/publishMessage'
import { useEffect, useState } from "react";
import PublishMessage from "./components/publishMessage";
import api, { Dynamic } from "./api";
interface Item extends Dynamic {
openComment?: boolean; //是否开启评论
showCommentAll?: boolean; //是否展示全部评论
}
export default function Forum() {
const [isModalOpen, setIsModalOpen] = useState(false);
const [list, setList] = useState<Array<Item>>([]);
const [pageParams, setPageParams] = useState({
pageNo: 1,
pageSize: 16,
});
useEffect(() => {
api
.dynamicList({
userId: 1,
...pageParams,
})
.then((res) => {
setList(res.result?.list || []);
});
}, []);
/**
* 展示发布模态框
*/
const showModal = () => {
setIsModalOpen(true);
};
/**
* 取消发布
*/
const onPublishCancel = () => {
setIsModalOpen(false);
};
/**
* 打开评论
* @param item 当前点击项
*/
const openComment = (item: Item) => {
item.openComment = true;
const temp = [...list];
setList(temp);
};
return (
<Layout>
<div className={styles.forum}>
......@@ -25,14 +64,14 @@ export default function Forum() {
</Button>
</div>
<Space direction="vertical" size={8}>
<div className={styles.item}>
{list.map((item) => {
return (
<div key={item.id} className={styles.item}>
<Space size={10} align="start">
<Image alt="" className={styles.headImg}></Image>
<div className={styles.info}>
<div className={styles.name}>给**的</div>
<div className={styles.desc}>
今天飞的航拍效果,喜欢的给我点个赞
</div>
<div className={styles.desc}>{item.title}</div>
<div className={styles.imgs}>
<Image.PreviewGroup
preview={{
......@@ -43,14 +82,19 @@ export default function Forum() {
}}
>
<Space size={6} wrap>
{item?.mediaVO?.picture.map((img) => {
return (
<Image
key={img}
alt=""
className="img"
width={132}
height={132}
src="error"
src={img}
fallback={errImg}
/>
);
})}
</Space>
</Image.PreviewGroup>
</div>
......@@ -58,18 +102,22 @@ export default function Forum() {
<div className={styles.ctrlsItem}>
<div
className={`${styles.ctrlsItemIcon} ${styles.iconComment}`}
onClick={() => openComment(item)}
></div>
15评论
{item.commentCount}评论
</div>
<div className={styles.ctrlsItem}>
<div
className={`${styles.ctrlsItemIcon} ${styles.iconPraise} ${styles.active}`}
className={`${styles.ctrlsItemIcon} ${
styles.iconPraise
} ${item.likes && styles.active}`}
></div>
11
{item.likesCount}
</div>
</div>
</div>
</Space>
{item.openComment && (
<div className={styles.commentWrap}>
<div className={styles.draftWrap}>
<div className={styles.commentHeadImg}>自已</div>
......@@ -113,12 +161,17 @@ export default function Forum() {
</div>
</div>
</div>
{!item.showCommentAll && (
<div className={styles.showAll}>
查看全部15条评论
<RightOutlined size={14} />
</div>
)}
</div>
)}
</div>
);
})}
</Space>
</div>
<PublishMessage
......
......@@ -35,7 +35,7 @@ export interface ListPageGoodsInfoResp {
export default {
//web-商品信息-分页
listPageGoodsInfo: (params: ListPageGoodsInfoParams): Promise<Response<ListPageGoodsInfoResp>> => {
return request('/pms/webProductMall/listPageGoodsInfo', 'post', params)
listPageGoodsInfo: (params: ListPageGoodsInfoParams, options = {}): Promise<Response<ListPageGoodsInfoResp>> => {
return request('/pms/webProductMall/listPageGoodsInfo', 'post', params, options)
}
}
\ No newline at end of file
......@@ -24,11 +24,15 @@
}
}
.listContent{
width: 100%;
}
.listWrap {
display: flex;
flex-wrap: wrap;
gap: 12px;
height: fit-content;
height: 856px;
.item {
cursor: pointer;
......
import React, { useEffect, useState } from "react";
import { Button, Pagination, Select, Space, Tag } from "antd";
import { Button, Empty, Pagination, Select, Space, Tag } from "antd";
import Layout from "~/components/layout";
import styles from "./index.module.scss";
import { useRouter } from "next/router";
......@@ -25,10 +25,18 @@ export default function Mall(props: Props) {
pageSize: 16,
});
const [count, setCount] = useState(0);
const [abort, setAbort] = useState<AbortController | null>(null);
useEffect(() => {
//中断前一次请求
abort?.abort();
setAbort(new AbortController());
}, [filterResult, pageParams]);
useEffect(() => {
api
.listPageGoodsInfo({
.listPageGoodsInfo(
{
brandId: filterResult.brand?.id,
districtId: filterResult.region?.id,
modelId: filterResult.model?.id,
......@@ -36,12 +44,16 @@ export default function Mall(props: Props) {
productCategoryId: filterResult.category?.id,
qualityId: filterResult.quality?.id,
...pageParams,
})
},
{
signal: abort?.signal,
}
)
.then((res) => {
setProductList(res.result?.list || []);
setCount(res.result?.totalCount);
setCount(res.result?.totalCount || 0);
});
}, [filterResult, pageParams]);
}, [abort]);
const onFilterChange = (filterResult: FilterResult) => {
console.log("filterResult", filterResult);
......@@ -52,8 +64,8 @@ export default function Mall(props: Props) {
setPageParams({
...pageParams,
pageNo: page,
})
}
});
};
return (
<Layout>
<div className="page" style={{ paddingTop: "18px" }}>
......@@ -65,6 +77,7 @@ export default function Mall(props: Props) {
<div className={styles.productList}>
<div className={styles.title}>四旋翼无人机</div>
<div className={styles.main}>
<div className={styles.listContent}>
<ul className={styles.listWrap}>
{productList.map((item, i) => {
return (
......@@ -83,18 +96,28 @@ export default function Mall(props: Props) {
></Image>
</div>
<div className={styles.title}>{item.goodsName}</div>
<div className={styles.sellCount}>半年售{(Math.floor(Math.random() * 901) + 100).toFixed(0)}</div>
<div className={styles.sellCount}>
半年售
{(Math.floor(Math.random() * 901) + 100).toFixed(0)}
</div>
</li>
);
})}
{productList.length === 0 && (
<Empty style={{ paddingTop: 20, width: '100%', textAlign: "center" }}></Empty>
)}
</ul>
<Pagination
current={pageParams.pageNo}
showSizeChanger={false}
showQuickJumper
total={count}
onChange={onPageChange}
hideOnSinglePage={true}
style={{marginTop: 20}}
/>
</ul>
</div>
<div className={styles.adList}>
<div className={styles.ad}></div>
<div className={styles.ad}></div>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论