提交 39368c2a 作者: 曹云

Merge branch 'master' of ssh://git.mmcuav.cn:8222/iuav/csf-web into feature/chuck

import request, { Response } from "~/api/request";
import config from "./config";
import request, { Response } from '~/api/request'
import config from './config'
export interface RegionResp {
childInfo?: RegionResp[] | null;
id: number;
level: number;
name: string;
pid: number;
childInfo?: RegionResp[] | null
id: number
level: number
name: string
pid: number
}
export interface UserInfoResp {
id: number;
accountType: number;
uid: string;
phoneNum: string;
userName: string;
nickName: string;
userImg: string;
userSex: number;
email: string;
source: number;
accountStatus: number;
remark: string;
portType: number;
createTime: string;
companyAuthStatus: number;
token: string;
id: number
accountType: number
uid: string
phoneNum: string
userName: string
nickName: string
userImg: string
userSex: number
email: string
source: number
accountStatus: number
remark: string
portType: number
createTime: string
companyAuthStatus: number
token: string
cooperationTagId: number | null
}
export interface TestAppletLoginResp {
userAccountId: number;
token: string;
uid: string;
phoneNum?: string;
nickName: string;
sessionKey?: any;
userAccountId: number
token: string
uid: string
phoneNum?: string
nickName: string
sessionKey?: any
}
export default {
//获取区域数据
region: (): Promise<Response<Array<RegionResp>>> => {
return request("/pms/webDevice/getSecondDistrictInfo");
return request('/pms/webDevice/getSecondDistrictInfo')
},
//测试-小程序unionId登录-注册
testAppletLogin: (): Promise<Response<TestAppletLoginResp>> => {
let params = new URLSearchParams();
params.append("unionId", "oQZEd5hy0Qrwaj10BGtP8xq8vH--s88888");
let params = new URLSearchParams()
params.append('unionId', 'oQZEd5hy0Qrwaj10BGtP8xq8vH--s88888')
return request(
"/userapp/auth/testAppletLogin",
"post",
'/userapp/auth/testAppletLogin',
'post',
{},
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params,
}
);
)
},
//生成小程序码
getAppletQRCode: (params: { randomLoginCode: string }) => {
return request("/userapp/wx/getAppletQRCode", "get", {
page: "page-identity/identity-empower/index",
scene: "randomLoginCode=" + params.randomLoginCode,
});
return request('/userapp/wx/getAppletQRCode', 'get', {
page: 'page-identity/identity-empower/index',
scene: 'randomLoginCode=' + params.randomLoginCode,
})
},
//查询登录信息
getLoginInfo: (params: { randomLoginCode: string }) => {
return request("/userapp/temp-auth/getLoginInfo", "get", params, {
hideError: true //隐藏错误提示
});
return request('/userapp/temp-auth/getLoginInfo', 'get', params, {
hideError: true, //隐藏错误提示
})
},
//获取用户基本信息
userInfo: (): Promise<Response<UserInfoResp>> => {
return request("/userapp/user-account/info", "get");
return request('/userapp/user-account/info', 'get')
},
//图片上传地址
imgOss: () => {
return config.baseUrl + "/pms/upload/imgOss";
return config.baseUrl + '/pms/upload/imgOss'
},
};
}
import config from './config';
let loginTimeout: NodeJS.Timeout | undefined;
/**
* 请求封装
* @param url 请求url
......@@ -43,12 +45,31 @@ export default function request(url: string, method: String = 'get', data?: any,
}
}
/**
* 错误消息
* @param msg
*/
function errMsg(msg: string) {
if (!options.hideError) {
window.messageApi.error(msg);
}
}
/**
* 未登录消息展示,1.5秒内限制只展示一次
* @returns
*/
function loginErrorMsg(){
console.log('loginTimeout', loginTimeout)
if(loginTimeout){
return;
}
loginTimeout = setTimeout(() => {
errMsg('请先登录');
loginTimeout = undefined;
}, 1500)
}
return fetch(config.baseUrl + url, options)
.then((r) => {
try {
......@@ -84,8 +105,9 @@ export default function request(url: string, method: String = 'get', data?: any,
if (data.code !== '200') {
//未登录判断
if(data.code === '5008'){
errMsg('请先登录');
if(data.code === '5008' || data.code === '2014'){
loginErrorMsg();
window.logout();
}else{
errMsg(data.message || '请求出错');
}
......
......@@ -2,7 +2,7 @@ import React, { useContext, useEffect, useState } from "react";
import { Avatar, Button, Dropdown, Space, Tabs } from "antd";
import type { TabsProps } from "antd";
import styles from "./index.module.scss";
import { useRouter } from "next/router";
import { Router, useRouter } from "next/router";
import LoginModal from "~/components/loginModal";
import PublishModal from "./publishModal";
import JoinModal from "./joinModal";
......@@ -39,17 +39,21 @@ const items: TabsProps["items"] = [
},
];
export default function NavHeader() {
type Props = {
style?: React.CSSProperties;
};
export default function NavHeader(props: Props) {
const router = useRouter();
const [currentPath, setCurrentPath] = useState("");
const { userInfo, testLogin, logout, setNeedLogin, needLogin } =
useContext(UserContext);
useEffect(() => {
const routerTo = items?.filter(item=>router.route.includes(item.key))[0]
const routerTo = items?.filter((item) => router.route == item.key)[0];
if (routerTo) {
setCurrentPath(routerTo?.key!);
}else{
} else {
setCurrentPath(router.route);
}
console.log("currentHash", currentPath);
......@@ -75,7 +79,7 @@ export default function NavHeader() {
if (!userInfo) {
setOpenLoginModal(true);
} else {
setOpenPublishModal(true);
setOpenPublishModal(true);
}
}
......@@ -97,7 +101,7 @@ export default function NavHeader() {
}, [needLogin]);
return (
<div className={styles.navHeader}>
<div className={styles.navHeader} style={props.style}>
<div className={styles.nav}>
<div className={styles.logo}></div>
<Tabs
......@@ -120,6 +124,18 @@ export default function NavHeader() {
<Dropdown
menu={{
items: [
{
key: "2",
label: (
<div
onClick={() =>
router.push("/personalCenter/servicesOrders")
}
>
我的订单
</div>
),
},
{ key: "1", label: <div onClick={onLogout}>退出登录</div> },
],
}}
......
......@@ -23,7 +23,6 @@ export default function PublishModal(props: Props) {
const position = useGeolocation();
const { reloadRequirements, setReloadRequirements } =
useContext(CommonContext);
console.log("position", position);
useEffect(() => {
api.listType().then((res) => {
......
import request, { Response } from "~/api/request";
import request, { Response } from '~/api/request'
export interface FilterOptionResp {
id: number;
name?: string;
appName?: string;
id: number
name?: string
appName?: string
}
export interface RegionResp {
childInfo: RegionResp[] | null;
id: number;
level: number;
name: string;
pid: number;
childInfo: RegionResp[] | null
id: number
level: number
name: string
pid: number
}
export interface InfoList {
id: number
directoryId: number
name: string
icon: string
}
export interface TypesResp {
directoryId: number
name: string
categoriesInfoListDTO: InfoList[]
}
export default {
category: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/category");
return request('/pms/webProductMall/category')
},
categoryId: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/category");
return request('/pms/webDevice/category')
},
brand: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/brand");
return request('/pms/webDevice/brand')
},
model: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/model");
return request('/pms/webDevice/model')
},
part: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/parts");
return request('/pms/webProductMall/parts')
},
quality: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/quality");
return request('/pms/webProductMall/quality')
},
region: (): Promise<Response<Array<RegionResp>>> => {
return request("/pms/webDevice/getSecondDistrictInfo");
return request('/pms/webDevice/getSecondDistrictInfo')
},
industry: (): Promise<Response<Array<RegionResp>>> => {
return request("/release/work/listAllIndustry");
return request('/release/work/listAllIndustry')
},
appType: (): Promise<Response<Array<RegionResp>>> => {
return request("/release/work/listAllAppType");
return request('/release/work/listAllAppType')
},
deviceBrand: (): Promise<Response<Array<RegionResp>>> => {
return request("/pms/webDevice/deviceBrand");
return request('/pms/webDevice/deviceBrand')
},
deviceModel: (): Promise<Response<Array<RegionResp>>> => {
return request("/pms/webDevice/deviceModel");
return request('/pms/webDevice/deviceModel')
},
};
infoByType: (params: {
type: number
}): Promise<Response<Array<TypesResp>>> => {
return request('/pms/classify/queryCategoryInfoByType', 'get', params)
},
}
import { Space, Select } from "antd";
import { useEffect, useState } from "react";
import styles from "../../index.module.scss";
import api, { RegionResp } from "../../api";
import { Space, Select } from 'antd'
import { useEffect, useState } from 'react'
import styles from '../../index.module.scss'
import api, { RegionResp } from '../../api'
type Props = {
onChange: (item: RegionResp) => void;
};
onChange: (item: RegionResp) => void
}
export default function RegionItem(props: Props) {
const [provinceList, setProvinceList] = useState<RegionResp[]>([]);
const [cityList, setCityList] = useState<RegionResp[]>([]);
const [provinceList, setProvinceList] = useState<RegionResp[]>([])
const [cityList, setCityList] = useState<RegionResp[]>([])
const [selectCity, setSelectCity] = useState<number>()
useEffect(() => {
api.region().then((res) => {
setProvinceList(res?.result || []);
});
}, []);
setProvinceList(res?.result || [])
})
}, [])
const onProvinceChange = (value: number, item: any) => {
console.log("省", value, item);
setCityList(item.childInfo || []);
setSelectCity(undefined);
props.onChange(item);
};
console.log('省', value, item)
setCityList(item.childInfo || [])
setSelectCity(undefined)
props.onChange(item)
}
const onCityChange = (value: number, item: any) => {
console.log("市", value);
setSelectCity(value);
props.onChange(item);
};
console.log('市', value)
setSelectCity(value)
props.onChange(item)
}
return (
<div className={styles.filterItem}>
<div className={styles.filterItemTitle}>地域:</div>
......@@ -44,10 +44,10 @@ export default function RegionItem(props: Props) {
...item,
value: item.id,
label: item.name,
};
}
})}
/>
<Select
{/* <Select
value={selectCity}
bordered={false}
popupMatchSelectWidth={false}
......@@ -60,9 +60,9 @@ export default function RegionItem(props: Props) {
label: item.name,
};
})}
/>
/> */}
</Space>
</div>
</div>
);
)
}
import { Space, Tag } from "antd";
import { FilterResult } from "../..";
import styles from "../../index.module.scss";
import { Space, Tag } from 'antd'
import { FilterResult } from '../..'
import styles from '../../index.module.scss'
import { InfoList } from '../../api'
type Props = {
data: FilterResult;
onDel: (key: string) => void;
};
export default function ResultItem({data, onDel}: Props) {
data: FilterResult
onDel: (key: string | number) => void
}
export default function ResultItem({ data, onDel }: Props) {
return (
<div className={styles.filterItem}>
<div className={styles.filterItemTitle}>已选:</div>
<div className={styles.filterItemMain}>
<Space size={10}>
{data &&
Object.keys(data).map((key) => {
//@ts-ignore
let item = data[key];
{data.provinceId && (
// Object.keys(data).map((key) => {
// //@ts-ignore
// let item = data[key]
// return (
// <Tag
// closable
// onClose={(e: React.MouseEvent<HTMLElement, MouseEvent>) => {
// onDel(key)
// }}
// key={key}
// >
// {item?.name}
// </Tag>
// )
// })
<Tag
closable
onClose={(e: React.MouseEvent<HTMLElement, MouseEvent>) => {
onDel('provinceId')
}}
key={data.provinceId.id}
>
{data.provinceId.name}
</Tag>
)}
{data.categoryId &&
data.categoryId.map((item: InfoList, index) => {
return (
<Tag
closable
onClose={(e: React.MouseEvent<HTMLElement, MouseEvent>) => {
onDel(key);
onDel(item.id)
}}
key={key}
key={item.name}
>
{item?.name}
</Tag>
);
)
})}
</Space>
</div>
</div>
);
)
}
import { Space, Button, Select, Collapse } from 'antd'
import styles from '../../index.module.scss'
import api, { FilterOptionResp, InfoList } from '../../api'
import { useState, useEffect } from 'react'
type Props = {
onChange: (id: FilterOptionResp) => void
typeName: string
dataValue: InfoList[]
}
export default function CategoryItem(props: Props) {
const [data, setData] = useState<FilterOptionResp[]>([])
useEffect(() => {
setData(props.dataValue || [])
}, [])
const onClick = (item: FilterOptionResp) => {
props.onChange({
id: item.id,
name: `${props.typeName}:` + item.name,
})
}
const showCount = 12 //展示数量
return (
<div className={styles.filterItem}>
<div className={styles.filterItemTitle}>{props.typeName}</div>
<div
className={`${styles.filterItemMain} ${
data.length <= showCount && styles.disabled
}`}
>
<Collapse
ghost
collapsible="icon"
expandIconPosition="end"
style={{ width: '100%' }}
>
<Collapse.Panel
header={
<Space size={[40, 0]}>
{data.slice(0, showCount).map((item) => {
return (
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
)
})}
</Space>
}
key="1"
>
<Space size={40}>
{data.slice(showCount).map((item) => {
return (
<Button
type="link"
key={item.id}
onClick={(e) => onClick(item)}
>
{item.name}
</Button>
)
})}
</Space>
</Collapse.Panel>
</Collapse>
</div>
</div>
)
}
......@@ -31,6 +31,7 @@
flex: 1;
display: flex;
justify-content: space-between;
overflow: hidden;
&.disabled {
:global .ant-collapse-expand-icon {
......
......@@ -41,7 +41,9 @@ const footerStyle: React.CSSProperties = {
type Props = {
children?: React.ReactNode;
layoutStyle?: React.CSSProperties;
contentStyle?: React.CSSProperties;
hideFooter?: boolean;
headerStyle?: React.CSSProperties
};
export default function LayoutView(props: Props) {
......@@ -55,11 +57,19 @@ export default function LayoutView(props: Props) {
)}
>
<Header style={headerStyle}>
<NavHeader />
<NavHeader style={props.headerStyle} />
</Header>
<Content className={styles.content}>{props.children}</Content>
<Content className={styles.content} style={props.contentStyle}>
{props.children}
</Content>
{!props.hideFooter && (
<Footer style={ includesPage.includes(router.pathname) ? {...footerStyle,...homeStyle} : footerStyle}>
<Footer
style={
includesPage.includes(router.pathname)
? { ...footerStyle, ...homeStyle }
: footerStyle
}
>
<FooterView></FooterView>
</Footer>
)}
......
......@@ -35,6 +35,10 @@ const UserProvider = ({ children }: Props) => {
setUserInfo(
JSON.parse(window.localStorage.getItem("userInfo") || "") || undefined
);
window.setUserInfo = setUserInfo;
window.setNeedLogin = setNeedLogin;
window.logout = logout;
} catch (e) {}
}, []);
......
/** @type {import('next').NextConfig} */
let distDir = ".dev"; //默认输出目录
let distDir = '.dev' //默认输出目录
if (process.env.NODE_ENV === "production") {
if (process.env.NODE_ENV === 'production') {
//生产环境用另一个目录构建,防止与dev冲突
distDir = ".next";
distDir = '.next'
}
const nextConfig = {
distDir,
reactStrictMode: true,
transpilePackages: ["antd"],
output: "standalone",
transpilePackages: ['antd'],
output: 'standalone',
compiler: {
styledComponents: true,
},
redirects() {
return [
{
source: "/",
destination: "/home",
source: '/',
destination: '/home',
permanent: true,
},
];
]
},
async rewrites() {
return [
{
source: "/local/:path*",
source: '/local/:path*',
//destination: "https://iuav.mmcuav.cn/:path*",
destination: "https://test.iuav.mmcuav.cn/:path*",
destination: 'https://test.iuav.shop/:path*',
},
];
]
},
images: {
remotePatterns: [
{
protocol: "http",
hostname: "**",
protocol: 'http',
hostname: '**',
},
{
protocol: "https",
hostname: "**",
protocol: 'https',
hostname: '**',
},
],
},
pageExtensions: ["page.tsx", "page.ts", "page.jsx", "page.js"],
};
pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js'],
}
module.exports = nextConfig;
module.exports = nextConfig
......@@ -23,6 +23,7 @@ export default function App({ Component, pageProps }: AppProps) {
return withTheme(
<>
<Head>
<title>云享飞</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
......
......@@ -12,18 +12,22 @@ import {
} from "antd";
import type { UploadChangeParam } from "antd/es/upload";
import type { RcFile, UploadFile, UploadProps } from "antd/es/upload/interface";
import { useContext, useState } from "react";
import { useContext, useEffect, useState } from "react";
import Layout from "~/components/layout";
import api, { } from "./api";
import api from "./api";
import styles from "./index.module.scss";
import gApi from "~/api";
import Router from "next/router";
import { UserContext } from "~/lib/userProvider";
const beforeUpload = (file: RcFile) => {
const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png";
const isJpgOrPng =
file.type === "image/jpeg" ||
file.type === "image/png" ||
file.type === "image/bmp" ||
file.type === "image/gif"
if (!isJpgOrPng) {
message.error("You can only upload JPG/PNG file!");
message.error("请上传10M以内的JPG、JPEG、BMP、GIF、PNG格式图片");
}
//限制上传10M
const isLt2M = file.size / 1024 / 1024 < 10;
......@@ -55,6 +59,11 @@ export default function Certification() {
Array<EnterpriseOption>
>([]);
const [form] = Form.useForm();
const [token, setToken] = useState("");
useEffect(() => {
setToken(window.localStorage.getItem("token") || "");
}, []);
//上传change事件
const handleChange: UploadProps["onChange"] = (
......@@ -91,7 +100,11 @@ export default function Certification() {
});
}
setTimeout(() => {
Router.push("/");
if (Router.query.type == "back") {
Router.back();
} else {
Router.push("/");
}
}, 1000);
}
});
......@@ -209,6 +222,7 @@ export default function Certification() {
beforeUpload={beforeUpload}
onChange={handleChange}
maxCount={1}
headers={{ token: token }}
>
{imageUrl ? (
<Image
......
import request, { Response } from '~/api/request';
import request, { Response } from '~/api/request'
export interface ListPageDeviceInfoParams {
"brandId"?: number,
"districtId"?: number,
"modelId"?: number,
"pageNo": number,
"pageSize": number,
"partsId"?: number,
"productCategoryId"?: number,
"qualityId"?: number
brandId?: number
districtId?: number
modelId?: number
pageNo: number
pageSize: number
partsId?: number
productCategoryId?: number
qualityId?: number
}
export interface Device {
id: number,
wareNo: string,
wareTitle: string,
wareTypeId: number,
wareStatus: number,
minDeposit: number,
minRent: number,
totalStock: number,
totalSale: number,
propInfoId: null,
createTime: string,
wareImgs: [
{
id: number,
wareInfoId: number,
imgUrl: string,
imgType: number
}
],
tags: string[]
id: number
goodsName: string
images: string
price: number | null
}
export interface Advertisement {
id:number,
imageUrl:string
id: number
imageUrl: string
}
export interface ListPageDeviceInfoResp {
"pageNo": 1,
"pageSize": 10,
"list": Array<Device>,
"totalCount": 0,
"totalPage": 0
pageNo: 1
pageSize: 10
list: Array<Device>
totalCount: 0
totalPage: 0
}
export default {
//web-设备租赁-分页
listPageDeviceInfo: (params: ListPageDeviceInfoParams,options = {}): Promise<Response<ListPageDeviceInfoResp>> => {
return request('/pms/webDevice/deviceList', 'post', params, options)
listPageDeviceInfo: (
params: ListPageDeviceInfoParams,
options = {}
): Promise<Response<ListPageDeviceInfoResp>> => {
return request('/pms/product/mall/deviceList', 'post', params, options)
},
//web-设备租赁-广告
listAdvertisementInfo: (): Promise<Response<Array<Advertisement>>> => {
return request('/pms/webDevice/ad', 'get')
}
}
\ No newline at end of file
},
}
import request, { Response } from '~/api/request';
import request, { Response } from '~/api/request'
export interface GetWebDeviceDetailParams {
id:number
goodsId: number
type: 1
}
export interface GetLeaseGoodsParams {
leaseTerm: number //租赁时限:(输入0:1-7天、输入1:8-15天、输入2:16-30天、输入3:30天以上)
productSpecId: number
}
export interface WareImgsType {
id: number,
wareInfoId: number | null,
imgUrl: string,
id: number
imgUrl: string
imgType: number
}
export interface PriceType {
id: number
cooperationTag: number
price: number
productSpecId: number
leaseTerm: number
}
export interface GetLeaseGoodsResult {
productSpecId: number
type: number | null
leaseTerm: number
specPrice: PriceType[]
}
export interface GetWebDeviceDetailResult {
id: number,
wareNo: string,
wareTitle: string,
wareTypeId: number,
wareStatus: number,
payStatus: number,
minDeposit: number,
maxDeposit: number,
minRent: number,
maxRent: number,
totalStock: number,
totalSale: number,
skuNum: number,
tags: [
string,
string
],
wareImgs: Array<WareImgsType>,
warePropDTO: number | null,
wareDetailContent: string | TrustedHTML
id: number
images: {
id: number
imgUrl: string
imgType: number
}[]
goodsVideo: string
goodsVideoId: number
goodsName: string
goodsDetail: {
id: number
goodsDesc: string
content: string | null
remark: string | null
}
directoryId: number
categoryByOne: number
categoryByTwo: null
tag: null
shelfStatus: number
goodsSpec: {
productSpecList: GetWebDeviceWareSkuById[]
}[]
otherService?: {
id: number
saleServiceId: string
serviceName: string
}[]
price: number | null
goodsNo: string
}
export interface PriceList {
id: number,
wareInfoId: number,
skuInfoId: number,
rentPrice: number,
minDay: number,
maxDay: number,
id: number
wareInfoId: number
skuInfoId: number
rentPrice: number
minDay: number
maxDay: number
createTime: null
}
}
export interface GetWebDeviceWareSkuById {
id: number,
wareInfoId: number,
skuTitle: string,
rentPrice: number | null,
rentDeposit: number,
stockNum: number,
saleNum: number,
createTime: string,
updateTime: null,
skuPriceDTOList: Array<PriceList>,
id: number
productSpec: number
productSkuId: number
specName: string
specImage: string
partNo: string
versionDesc: string
createTime: string | null
productSpecCPQVO: string | null
}
export interface WebDeviceUpdateParams {
id?:number,
inventoryId?:number,
inventoryUsage?:string,
startDay?:string
endDay?:string,
id?: number
inventoryId?: number
inventoryUsage?: string
startDay?: string
endDay?: string
}
export default {
//web-设备租赁-详情
listDetailDeviceInfo: (params: GetWebDeviceDetailParams): Promise<Response<GetWebDeviceDetailResult>> => {
return request('/pms/webDevice/detail', 'get', params)
},
//web-设备租赁-商品
listWareSkuById: (params: GetWebDeviceDetailParams): Promise<Response<GetWebDeviceWareSkuById[]>> => {
return request('/pms/appDevice/listWareSkuById', 'get', params)
listDetailDeviceInfo: (
params: GetWebDeviceDetailParams
): Promise<Response<GetWebDeviceDetailResult>> => {
return request('/pms/product/mall/getLeaseGoodsDetail', 'get', params)
},
//web-设备租赁-立即租赁
listWareSkuUpdate: (params: WebDeviceUpdateParams): Promise<Response<number>> => {
listWareSkuUpdate: (
params: WebDeviceUpdateParams
): Promise<Response<number>> => {
return request('/pms/appDevice/update', 'post', params)
}
}
\ No newline at end of file
},
//web-设备租赁-详情-获取设备商品规格价格详情
GoodsPriceDetail: (
params: GetLeaseGoodsParams
): Promise<Response<GetLeaseGoodsResult>> => {
return request('/pms/product/mall/getLeaseGoodsPriceDetail', 'get', params)
},
}
import request, { Response } from '~/api/request'
export interface GetWebDeviceDetailParams {
actualPay: number
deposit: number
endDate: string
orderReceipt: {
detailAddress: string
receiptMethod: number
region: string
takeName: string
takePhone: number
}
rentPrice: number
returnDate: string
shouldPay: number
specsId: number
startDate: string
wareDescription: string
wareImg: string
wareInfoId: number
wareNo: string
wareNum: number
wareTitle: string
remark?: string
}
export interface WareImgsType {
id: number
imgUrl: string
imgType: number
}
export interface UserAddress {
id: number
takeName: string
takePhone: string
takeRegion: string
takeAddress: string
type: number
}
export interface GetOrderForGoods {
balance: number
nickName: string
orderNo: string
}
export default {
//web-地址管理-查询用户地址列表-条件查询
listUserAddress: (params: {}): Promise<Response<UserAddress[]>> => {
return request('/oms/user-address/selectList', 'POST', params)
},
//web-设备租赁-下单
FeignAddLease: (
params: GetWebDeviceDetailParams
): Promise<Response<GetOrderForGoods>> => {
return request('/oms/RentalOrders/feignAddLease', 'post', params)
},
//web-设备租赁-订单支付
OrderPayment: (params: {
orderNo: string
}): Promise<Response<GetOrderForGoods>> => {
return request(`/payment/repocash/orderPayment`, 'get', params)
},
}
import styled from 'styled-components'
export const OrderForGoodsBox = styled.div`
box-sizing: border-box;
width: 1000px;
.address {
.top {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e6e6e6;
height: 30px;
line-height: 30px;
margin-top: 30px;
.left {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #333333;
line-height: 18px;
}
.right {
.btn {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #007aff;
line-height: 19px;
}
}
}
.bottom {
.item {
display: flex;
justify-content: space-between;
align-items: center;
width: 1000px;
height: 48px;
border: 1px solid transparent;
margin-top: 8px;
&.active {
background: #fff1e8;
border-radius: 6px;
border: 1px solid #ff552d;
}
.left {
display: flex;
align-items: center;
justify-content: space-around;
.active {
margin-right: 18px;
display: flex;
.icon {
width: 15px;
height: 22px;
background: #ff552d;
margin-left: 17px;
}
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
margin-left: 18px;
}
}
}
.right {
margin-right: 22px;
}
}
}
}
.info {
margin-top: 30px;
.title {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #333333;
line-height: 18px;
}
.table {
.table-title {
display: flex;
align-items: center;
width: 1000px;
border-bottom: 1px solid #e6e6e6;
padding: 10px 0;
margin-top: 20px;
.table-item {
text-align: center;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
}
}
.table-body {
display: flex;
align-items: center;
height: 100px;
margin-top: 10px;
.body-item {
text-align: center;
&.article {
display: flex;
justify-content: space-between;
.image {
margin-right: 10px;
.image-box {
width: 80px;
height: 80px;
}
}
.right {
.top {
width: 171px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #141414;
line-height: 20px;
}
.bottom {
width: 171px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #929295;
line-height: 17px;
}
}
}
&.lease-term {
display: flex;
align-items: center;
justify-content: center;
.num {
width: 62px;
height: 24px;
background: #ff552d;
border-radius: 2px;
position: relative;
margin: 0 15px;
line-height: 24px;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #ffffff;
&::before {
content: '';
width: 10px;
height: 1px;
background-color: #ff552d;
position: absolute;
left: -10px;
top: 50%;
transform: translateY(-50%);
}
&::after {
content: '';
width: 10px;
height: 1px;
background-color: #ff552d;
position: absolute;
right: -10px;
top: 50%;
transform: translateY(-50%);
}
}
}
&.total-price {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff3100;
line-height: 18px;
}
}
}
}
}
.notes {
display: flex;
align-items: center;
justify-content: space-between;
width: 1000px;
height: 110px;
background: #e1efff;
border: 1px solid #d0eaf5;
padding: 0 22px 0 16px;
.left {
display: flex;
align-items: top;
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
margin-top: 4px;
}
}
.right {
width: 430px;
.top {
display: flex;
align-items: center;
justify-content: space-between;
}
.font {
display: flex;
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 18px;
}
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
margin-right: 12px;
}
.value {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #2b2b2b;
line-height: 20px;
}
.price {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff3100;
line-height: 18px;
}
}
}
.detail-box {
display: flex;
justify-content: flex-end;
margin-top: 26px;
.right-box {
.detail {
width: 477px;
height: 110px;
border: 1px solid #ff5001;
padding: 16px 19px 19px 19px;
.top {
display: flex;
justify-content: flex-end;
align-items: center;
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #474747;
line-height: 19px;
margin-right: 10px;
}
.price {
font-size: 26px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff552d;
line-height: 33px;
}
}
.bottom {
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 15px;
.value {
font-size: 12px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 15px;
margin-right: 10px;
}
.value-content {
font-size: 12px;
font-family: MicrosoftYaHei;
color: #333333;
line-height: 16px;
}
}
}
.detail-sumbit {
display: flex;
justify-content: flex-end;
.btn {
width: 182px;
height: 39px;
background: #ff552d;
border: 1px solid #ff5001;
border-radius: 0;
color: #ffffff;
}
}
}
}
.Payment {
.title {
text-align: center;
font-size: 26px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff552d;
}
}
.addAddress {
.title {
text-align: center;
height: 25px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 25px;
}
.image {
display: flex;
justify-content: center;
align-items: center;
padding: 48px 0 32px;
.addressImg {
width: 150px;
height: 150px;
}
}
.content {
text-align: center;
width: 311px;
height: 38px;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #3e454d;
line-height: 19px;
}
}
`
import React , {useState,useRef} from 'react'
import {Box} from './styled';
import { LeftOutlined , RightOutlined } from '@ant-design/icons';
import {WareImgsType} from '../../api';
import React, { useState, useRef } from 'react'
import { Box } from './styled'
import { LeftOutlined, RightOutlined } from '@ant-design/icons'
import { WareImgsType } from '../../api'
interface ImagesType{
interface ImagesType {
imgList: Array<WareImgsType>
}
export default function PicturePreview(props:ImagesType) {
const {imgList} = props
console.log(imgList);
const mask =useRef<HTMLDivElement>(null!)
const moveBox =useRef<HTMLDivElement>(null!)
const big =useRef<HTMLImageElement>(null!)
const [moveLeft,setMoveLeft] = useState(0) // 根据这个值设置图片列表向左偏移
// const imgList = [
// 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
// 'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
// 'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
// 'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
// 'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
// 'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
// 'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
// ]
export default function PicturePreview(props: ImagesType) {
const { imgList } = props
const [activeImgIndex,setActiveImgIndex] = useState(0)
const mask = useRef<HTMLDivElement>(null!)
const moveBox = useRef<HTMLDivElement>(null!)
const big = useRef<HTMLImageElement>(null!)
const [moveLeft, setMoveLeft] = useState(0) // 根据这个值设置图片列表向左偏移
// const imgList = [
// 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
// 'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
// 'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
// 'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
// 'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
// 'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
// 'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
// ]
// 改变预览图
const handleChangeImg = (index:number) => {
if (index <= moveLeft + 3) setActiveImgIndex(index)
}
// 移动缩略图
const handleSlide = (direction:string) => {
//左侧按钮
if (direction == 'left') {
moveLeft == 0 ? setMoveLeft(0) : setMoveLeft((props)=>props - 1)
} else { // 右侧按钮
if (imgList.length > 4) {
moveLeft >= imgList.length - 4 ? setMoveLeft(imgList.length - 4) : setMoveLeft((props)=>props + 1)
}
}
}
// 图片放大镜
const handleMouseMove = (event:React.MouseEvent<HTMLDivElement, MouseEvent>) => {
let left = event.nativeEvent.offsetX - mask.current.offsetWidth / 2;
let top = event.nativeEvent.offsetY - mask.current.offsetHeight / 2;
// 最右侧和最下侧的临界值
const maxLeft = moveBox.current.offsetWidth - mask.current.offsetWidth
const maxTop = moveBox.current.offsetHeight - mask.current.offsetHeight
//约束范围
if (left <= 0) left = 0;
if (left >= maxLeft) left = maxLeft
if (top <= 0) top = 0;
if (top >= maxTop) top = maxTop
// 设置放大范围遮罩层位置
mask.current.style.left = left + "px";
mask.current.style.top = top + "px";
// 设置大图图片位置,可以用background代替这个方案,有兴趣可以尝试
big.current.style.left = -3 * left + "px"; // 3这个值是 大图除以小图算出来的比例 这里大图是900px 小图是300px
big.current.style.top = -3 * top + "px";
const [activeImgIndex, setActiveImgIndex] = useState(0)
// 改变预览图
const handleChangeImg = (index: number) => {
if (index <= moveLeft + 3) setActiveImgIndex(index)
}
// 移动缩略图
const handleSlide = (direction: string) => {
//左侧按钮
if (direction == 'left') {
moveLeft == 0 ? setMoveLeft(0) : setMoveLeft((props) => props - 1)
} else {
// 右侧按钮
if (imgList.length > 4) {
moveLeft >= imgList.length - 4
? setMoveLeft(imgList.length - 4)
: setMoveLeft((props) => props + 1)
}
}
}
// 图片放大镜
const handleMouseMove = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>
) => {
let left = event.nativeEvent.offsetX - mask.current.offsetWidth / 2
let top = event.nativeEvent.offsetY - mask.current.offsetHeight / 2
// 最右侧和最下侧的临界值
const maxLeft = moveBox.current.offsetWidth - mask.current.offsetWidth
const maxTop = moveBox.current.offsetHeight - mask.current.offsetHeight
//约束范围
if (left <= 0) left = 0
if (left >= maxLeft) left = maxLeft
if (top <= 0) top = 0
if (top >= maxTop) top = maxTop
// 设置放大范围遮罩层位置
mask.current.style.left = left + 'px'
mask.current.style.top = top + 'px'
// 设置大图图片位置,可以用background代替这个方案,有兴趣可以尝试
big.current.style.left = -3 * left + 'px' // 3这个值是 大图除以小图算出来的比例 这里大图是900px 小图是300px
big.current.style.top = -3 * top + 'px'
}
return (
<Box>
<div className="img_wrapper">
<div className="img_wrapper">
<div className="img_content">
{/* <!-- 蒙层,绑定鼠标事件 --> */}
<div className="movebox"
onMouseMove={(e)=>handleMouseMove(e)}
ref={moveBox}>
</div>
{/* <!-- 主图 --> */}
<img src={imgList && imgList[activeImgIndex].imgUrl}
{/* <!-- 蒙层,绑定鼠标事件 --> */}
<div
className="movebox"
onMouseMove={(e) => handleMouseMove(e)}
ref={moveBox}
></div>
{/* <!-- 主图 --> */}
<img
src={imgList && imgList[activeImgIndex].imgUrl}
className="img_small"
alt=""/>
{/* <!-- 放大区域 --> */}
<div className="mask"
ref={mask}></div>
{/* <!-- 大图预览图 --> */}
<div className="img_big">
<img src={imgList && imgList[activeImgIndex].imgUrl}
ref={big}
alt=""/>
</div>
alt=""
/>
{/* <!-- 放大区域 --> */}
<div className="mask" ref={mask}></div>
{/* <!-- 大图预览图 --> */}
<div className="img_big">
<img
src={imgList && imgList[activeImgIndex].imgUrl}
ref={big}
alt=""
/>
</div>
</div>
{/* <!-- 缩略图列表 --> */}
<div className="img_list_wrapper">
{imgList?.length>4 && <LeftOutlined className="el-icon-arrow-left" onClick={()=>handleSlide('left')}/>}
<div className="img_list_content">
<div className="img_list"
style={{marginLeft: - moveLeft * 25 + '%'}}>
{
imgList?.map((item,index)=>(
<img
onMouseOver={()=>handleChangeImg(index)}
key={index}
className={`${activeImgIndex === index ? 'activeImg' : ''}`}
src={item.imgUrl}
alt="" />
))
}
</div>
</div>
{ imgList?.length>4 && <RightOutlined className="el-icon-arrow-right" onClick={()=>handleSlide('right')}/>}
</div>
</div>
{imgList?.length > 4 && (
<LeftOutlined
className="el-icon-arrow-left"
onClick={() => handleSlide('left')}
/>
)}
<div className="img_list_content">
<div
className="img_list"
style={{ marginLeft: -moveLeft * 25 + '%' }}
>
{imgList?.map((item, index) => (
<img
onMouseOver={() => handleChangeImg(index)}
key={index}
className={`${activeImgIndex === index ? 'activeImg' : ''}`}
src={item.imgUrl}
alt=""
/>
))}
</div>
</div>
{imgList?.length > 4 && (
<RightOutlined
className="el-icon-arrow-right"
onClick={() => handleSlide('right')}
/>
)}
</div>
</div>
</Box>
)
}
import React, { useEffect, useState , useRef } from "react";
import { useRouter } from "next/router";
import { Pagination } from "antd";
import { Box } from "./styled";
import Layout from "~/components/layout";
import ContentBox from "~/components/contentBox";
import Filter, { FilterResult, AdapterResult } from "~/components/filter";
import Image from "next/image";
import api, { Device, Advertisement } from "./api";
import { Pagination } from 'antd'
import Image from 'next/image'
import { useRouter } from 'next/router'
import { useContext, useEffect, useRef, useState } from 'react'
import ContentBox from '~/components/contentBox'
import Filter, { AdapterResult, FilterResult } from '~/components/filter'
import Layout from '~/components/layout'
import api, { Advertisement, Device } from './api'
import { Box } from './styled'
import { UserContext } from '~/lib/userProvider'
// 此函数在构建时被调用
export async function getStaticProps() {
//获取筛选数据,进行静态渲染
return {
props: {},
};
}
}
type Props = {};
type Props = {}
export default function EquipmentLeasing(props: Props) {
const router = useRouter();
const filter = useRef<any>()
const { userInfo } = useContext(UserContext)
const router = useRouter()
const [productList, setProductList] = useState(
Array<{ element: JSX.Element }>
);
)
const [rightProductList, setRightProductList] = useState(
Array<{ element: JSX.Element }>
);
)
const leftDom = (item: Device) => {
return (
......@@ -36,64 +37,62 @@ export default function EquipmentLeasing(props: Props) {
>
<div className="item-top">
<div className="item-top-image">
<Image
src={item.wareImgs[0].imgUrl}
alt="error"
fill
/>
<Image src={item.images} alt="error" fill />
</div>
</div>
<div className="item-bottom">
<div className="item-bottom-title" title={item.wareTitle}>
{item.wareTitle}
</div>
<div className="item-bottom-price">
<span className="money">¥{item.minRent}</span>
<span className="unit">/天起</span>
<div className="item-bottom-title" title={item.goodsName}>
{item.goodsName}
</div>
{userInfo?.cooperationTagId ? (
<div className="item-bottom-price">
<span className="money">¥{item.price}</span>
<span className="unit">/天起</span>
</div>
) : (
<div className="unit">暂无报价</div>
)}
</div>
</div>
);
};
)
}
const rightDom = (item: Advertisement) => {
return (
<div key={item.id} className="right-box-item right-item">
<Image src={item.imageUrl} alt="error" fill />
</div>
);
};
)
}
const [filterResult, setFilterResult] = useState<AdapterResult>({}); //筛选结果
const [count, setCount] = useState(0); //商品总数
const [abort, setAbort] = useState<AbortController | null>(null); //请求中断
const [filterResult, setFilterResult] = useState<AdapterResult>({}) //筛选结果
const [count, setCount] = useState(0) //商品总数
const [abort, setAbort] = useState<AbortController | null>(null) //请求中断
const [pageParams, setPageParams] = useState({
type: 1,
pageNo: 1,
pageSize: 15,
}); //分页器对象
}) //分页器对象
const onPageChange = (page: number, pageSize: number) => {
setPageParams({
...pageParams,
pageNo: page,
});
};
})
}
useEffect(() => {
//中断前一次列表请求
abort?.abort();
setAbort(new AbortController());
}, [filterResult, pageParams]);
abort?.abort()
setAbort(new AbortController())
}, [filterResult, pageParams])
//端口列表请求
useEffect(() => {
let queryVal = JSON.parse(JSON.stringify(router.query));
const idArr = filter.current.idArr
let queryVal = JSON.parse(JSON.stringify(router.query))
let rs
for (const key in queryVal) {
if (idArr.includes(key)) {
rs = {[key]:router.query[key]}
}
if (Object.keys(queryVal).length) {
rs = { categoryId: [Number(queryVal['categoryId'])] }
}
api
.listPageDeviceInfo(
......@@ -109,59 +108,55 @@ export default function EquipmentLeasing(props: Props) {
.then((res) => {
setProductList(
res.result?.list?.map((item) => {
return { element: leftDom(item) };
return { element: leftDom(item) }
}) || []
);
setCount(res.result?.totalCount || 0);
});
}, [abort]);
)
setCount(res.result?.totalCount || 0)
})
}, [abort])
const onFilterChange = (
filterResult: FilterResult,
adapterFilterResult: AdapterResult
) => {
console.log("filterResult", filterResult, adapterFilterResult);
setFilterResult(adapterFilterResult);
};
console.log('filterResult', filterResult, adapterFilterResult)
adapterFilterResult.categoryId = adapterFilterResult.categoryId?.map(
(item) => item.id
)
setFilterResult(adapterFilterResult)
}
useEffect(() => {
api.listAdvertisementInfo().then((res) => {
setRightProductList(
res.result?.map((item) => {
return { element: rightDom(item) };
return { element: rightDom(item) }
}) || []
);
});
}, []);
)
})
}, [])
useEffect(() => {
let queryVal = JSON.parse(JSON.stringify(router.query));
if (router.query) {
const idArr = filter.current.idArr
for (const key in queryVal) {
if (idArr.includes(key)) {
setFilterResult({ [key]:router.query[key] });
}
}
let queryVal = JSON.parse(JSON.stringify(router.query))
if (Object.keys(router.query).length) {
setFilterResult({ categoryId: [Number(queryVal['categoryId'])] })
}
}, [router]);
}, [router])
return (
<Layout>
<Box>
<Filter
types={["地域", "设备类目", "设备品牌", "设备型号"]}
types={['地域', '设备品牌', '设备型号']}
showResultItem
onChange={onFilterChange}
ref={filter}
></Filter>
<div style={{ paddingTop: 13 }}>
<ContentBox
boxIndex={5}
leftcontentstyle={{
width: "1010px",
margin: { top: 0, right: "12px", bottom: "12px", left: 0 },
width: '1010px',
margin: { top: 0, right: '12px', bottom: '12px', left: 0 },
}}
leftRenderDom={{
columns: productList,
......@@ -185,5 +180,5 @@ export default function EquipmentLeasing(props: Props) {
</div>
</Box>
</Layout>
);
)
}
import styled from "styled-components";
import styled from 'styled-components'
export default function Style() {
return <></>;
return <></>
}
export const Box = styled.div`
......@@ -54,14 +54,14 @@ export const Box = styled.div`
color: #ff552d;
line-height: 22px;
}
.unit {
width: 58px;
height: 22px;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #ff552d;
line-height: 22px;
}
}
.unit {
width: 58px;
height: 22px;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #ff552d;
line-height: 22px;
}
}
}
......@@ -76,4 +76,4 @@ export const Box = styled.div`
.pagination-page {
text-align: right;
}
`;
`
import request, { Response } from '~/api/request';
import request, { Response } from '~/api/request'
import { TypesResp } from '~/components/filter/api'
export interface ListPageFlyingInfoParams {
pageNo: number,
pageSize: number,
flightSkillsId?:number,
licenseId?:number,
regionId?:number
pageNo: number
pageSize: number
flightSkillsId?: number
licenseId?: number
regionId?: number
}
export interface Flying {
id: number,
price: number,
supplierName: string,
curriculumName: string,
free: 0 | 1,
curriculumDesc: string,
id: number
price: number
supplierName: string
curriculumName: string
free: 0 | 1
curriculumDesc: string
videoUrl: string
surfaceUrl: string
}
export interface ListPageFlyingInfoResp {
pageNo: 1,
pageSize: 10,
list: Array<Flying>,
totalCount: 0,
pageNo: 1
pageSize: 10
list: Array<Flying>
totalCount: 0
totalPage: 0
}
export interface SkillsType {
type: string;
id: number,
skillsName: string,
label:string | number,
value:string | number
type: string
id: number
skillsName: string
label: string | number
value: string | number
}
export interface RegionResp {
childInfo: RegionResp[] | null,
id: number,
level: number,
name: string,
childInfo: RegionResp[] | null
id: number
level: number
name: string
pid: number
}
export interface PilotRegistrationParams {
city?: number,
drivingLicense?: number,
industryAppAuth?: Array<number>,
province?: number,
remark?: string,
telephone?: string,
uavLicenseLevelOne?: number,
city?: number
drivingLicense?: number
industryAppAuth?: Array<number>
province?: number
remark?: string
telephone?: string
uavLicenseLevelOne?: number
uavLicenseLevelTwo?: number
}
export default {
//web-作业服务-分页
listPageJobServicesInfo: (params: ListPageFlyingInfoParams): Promise<Response<ListPageFlyingInfoResp>> => {
return request('/release/curriculum/queryCurriculumInfoList', 'post', params)
//web-飞手培训-分页
listPageJobServicesInfo: (
params: ListPageFlyingInfoParams
): Promise<Response<ListPageFlyingInfoResp>> => {
return request(
'/release/curriculum/queryCurriculumInfoList',
'post',
params
)
},
region: (): Promise<Response<Array<RegionResp>>> => {
return request('/pms/webDevice/getSecondDistrictInfo');
return request('/pms/webDevice/getSecondDistrictInfo')
},
PilotLicense: (): Promise<Response<Array<RegionResp>>> => {
return request('/release/curriculum/getDronePilotLicense');
return request('/release/curriculum/getDronePilotLicense')
},
IndustryFlightSkills: (): Promise<Response<Array<SkillsType>>> => {
return request('/release/curriculum/getIndustryFlightSkills');
return request('/release/curriculum/getIndustryFlightSkills')
},
PilotRegistrations: (params:PilotRegistrationParams): Promise<Response<Array<SkillsType>>> => {
return request('/release/curriculum/pilotRegistration',"post",params);
PilotRegistrations: (
params: PilotRegistrationParams
): Promise<Response<Array<SkillsType>>> => {
return request('/release/curriculum/pilotRegistration', 'post', params)
},
}
\ No newline at end of file
FlightSkills: (params: { type: 3 }): Promise<Response<Array<TypesResp>>> => {
return request('/pms/classify/queryCategoryInfoByType', 'get', params)
},
}
import React, { useEffect, useState } from "react";
import Layout from "~/components/layout";
import { Box } from "./styled";
import { Button } from "antd";
import { useRouter } from "next/router";
import { ParsedUrlQuery } from "querystring";
import React, { useEffect, useState } from 'react'
import Layout from '~/components/layout'
import { Box } from './styled'
import { Button, Tabs } from 'antd'
import { useRouter } from 'next/router'
import { ParsedUrlQuery } from 'querystring'
import type { TabsProps } from 'antd'
import api, { ListPageFlyingInfoResp } from './api'
interface RouterDetail {
videoUrl:string | '',
curriculumName:string
const contentStyle: React.CSSProperties = {
width: '100%',
}
export default function FlyingDetail() {
const router = useRouter();
const [detail,setDetail] =useState<ParsedUrlQuery | RouterDetail>()
useEffect(()=>{
setDetail(router.query)
},[router])
const router = useRouter()
const [detail, setDetail] = useState<ListPageFlyingInfoResp | null>()
const onChange = (key: string) => {
console.log(key)
}
const items: TabsProps['items'] = [
{
key: '1',
label: `介绍`,
children: (
<div className="body">
<div className="top">
<div className="title">课程简介</div>
<div className="content">{detail?.curriculumDesc}</div>
</div>
{/* <div className="bottom">详情</div> */}
{detail?.detailContent && (
<div
dangerouslySetInnerHTML={{ __html: detail?.detailContent }}
></div>
)}
</div>
),
},
]
useEffect(() => {
if (Object.keys(router.query).length) {
api
.listPageJobServicesInfo({ id: Number(router.query.id) })
.then((res) => {
console.log(res)
setDetail(res.result)
})
}
}, [router])
return (
<Layout>
<Layout contentStyle={contentStyle}>
<Box>
<div className="box-top">
<div className="left">{detail?.curriculumName}</div>
<div className="right">
{/* <Button
<div className="box">
<div className="box-body">
<video
className="body-video"
controls
src={detail?.videoUrl as string}
/>
</div>
<div className="box-bottom">
<div className="left">
<div className="top">{detail?.curriculumName}</div>
<div className="bottom">免费</div>
</div>
<div className="right">
{/* <Button
type="primary"
className="btn"
onClick={() =>
......@@ -32,12 +75,18 @@ export default function FlyingDetail() {
>
去考试
</Button> */}
</div>
</div>
</div>
<div className="box-body">
<video className="body-video" controls src={detail?.videoUrl as string} />
<div className="detail">
<Tabs
className="tabs"
defaultActiveKey="1"
items={items}
onChange={onChange}
/>
</div>
</Box>
</Layout>
);
)
}
import request, { Response } from '~/api/request'
export interface ListPageFlyingInfoParams {
id: number
}
export interface Flying {
id: number
price: number
supplierName: string
curriculumName: string
free: 0 | 1
curriculumDesc: string
videoUrl: string
}
export interface ListPageFlyingInfoResp {
id: number
price: number | null
supplierName: string
curriculumName: string
free: number
flightSkills: number
flightSkillsName1: string
flightSkillsName2: string
curriculumDesc: string
surfaceUrl: string | null
videoUrl: string
detailContent: null
}
export default {
//web-飞手培训-详情
listPageJobServicesInfo: (
params: ListPageFlyingInfoParams
): Promise<Response<ListPageFlyingInfoResp>> => {
return request('/release/curriculum/curriculumDetails', 'get', params)
},
}
import styled from "styled-components";
import styled from 'styled-components'
export default function Style() {
return <></>;
return <></>
}
export const Box = styled.div`
box-sizing: border-box;
.box-top {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
.left {
height: 25px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 25px;
.box {
background-color: #fff;
height: 586px;
padding-top: 20px;
.box-body {
margin: 0 auto;
display: flex;
width: 1200px;
height: 470px;
/* background: #111111; */
.body-video {
width: 1200px;
height: 470px;
}
/* .right-box {
width: 362px;
height: 470px;
background: #1b2128;
.tabs {
color: #fff;
}
} */
}
.right {
.btn {
width: 180px;
.box-bottom {
margin: 0 auto;
width: 1200px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 0 38px 0;
.left {
height: 50px;
background: linear-gradient(135deg, #278eff 0%, #0052da 100%);
border-radius: 6px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ffffff;
&:hover {
opacity: 0.8;
.top {
font-size: 24px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
margin-bottom: 10px;
}
.bottom {
font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff552d;
}
}
.right {
.btn {
width: 180px;
height: 50px;
background: linear-gradient(135deg, #278eff 0%, #0052da 100%);
border-radius: 6px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ffffff;
&:hover {
opacity: 0.8;
}
}
}
}
}
.box-body {
margin-top: 20px;
.detail {
margin: 0 auto;
width: 1200px;
height: 675px;
background: #111111;
.body-video {
width: 1200px;
height: 675px;
height: 420px;
background: #ffffff;
box-shadow: 0px 2px 6px 0px rgba(183, 188, 197, 0.1);
border-radius: 12px;
margin-top: 16px;
padding: 20px;
.tabs {
.body {
.top {
.title {
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
}
.content {
font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #27323f;
margin-top: 10px;
}
}
.bottom {
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
margin-top: 29px;
}
}
}
}
`;
`
......@@ -2,12 +2,13 @@ import { PlusOutlined } from "@ant-design/icons";
import { Form, Input, Modal, Upload, Image, Button, Row, Col } from "antd";
import type { RcFile, UploadProps } from "antd/es/upload";
import type { UploadFile } from "antd/es/upload/interface";
import { useContext, useState } from "react";
import { useContext, useEffect, useState } from "react";
import gApi from "~/api";
import NImage from "next/image";
import api from "./api";
import { useGeolocation } from "~/lib/hooks";
import { UserContext } from "~/lib/userProvider";
import { useToken } from "antd/es/theme/internal";
type Props = {
open: boolean;
......@@ -33,6 +34,11 @@ export default function PublishMessage(props: Props) {
const [form] = Form.useForm();
const { userInfo, setNeedLogin } = useContext(UserContext);
const position = useGeolocation();
const [token, setToken] = useState('');
useEffect(() => {
setToken(window.localStorage.getItem('token') || '');
}, [])
//预览关闭
const handlePreviewCancel = () => setPreviewOpen(false);
......@@ -155,6 +161,7 @@ export default function PublishMessage(props: Props) {
onPreview={handlePreview}
onChange={handleChange}
maxCount={1}
headers={{ token: token }}
>
{fileList.length >= 8 ? null : (
<div>
......
import request, { Response } from "~/api/request";
import request, { Response } from '~/api/request'
export interface AllType {
type?: string;
id?: number;
name?: string;
appName?: string;
createTime?: string;
industryIcon?: string;
shortName?: null;
industryType?: null;
propagate1?: string;
propagate2?: string;
image?: string;
video?: string;
newsTitle?: string;
newsAuthor?: string;
userAccountId?: number;
surfaceImg?: string;
newsContents?: string;
updateTime?: string | null;
tenderNewsId?: number;
tenderInfoNo?: string;
tenderContent?: string;
tenderPrice?: number;
apply?: number;
skillsName?: string;
categoryName: string
id: number
}
export interface FilterOptionResp {
type: string;
id: number;
name: string;
type: string
id: number
name: string
}
export interface RegionResp {
childInfo: RegionResp[] | null;
id: number;
level: number;
name: string;
pid: number;
childInfo: RegionResp[] | null
id: number
level: number
name: string
pid: number
}
export const equipmentLeasingApi = {
deviceBrand: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/deviceBrand");
},
deviceCategory: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/category");
return request('/pms/webDevice/deviceBrand')
},
// deviceCategory: (): Promise<Response<Array<FilterOptionResp>>> => {
// return request("/pms/webDevice/category");
// },
deviceModel: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/deviceModel");
return request('/pms/webDevice/deviceModel')
},
};
}
export interface AppType {
id: number;
name: string;
appName: string;
createTime: string;
type: string;
id: number
name: string
appName: string
createTime: string
type: string
}
export interface IndustryType {
id: number;
industryIcon: string;
name: string;
shortName: string;
industryType: string;
propagate1: string;
propagate2: string;
image: string;
video: string;
type: string;
appName: string;
id: number
industryIcon: string
name: string
shortName: string
industryType: string
propagate1: string
propagate2: string
image: string
video: string
type: string
appName: string
}
export const jobServicesApi = {
listAllAppType: (): Promise<Response<Array<AppType>>> => {
return request("/release/work/listAllAppType");
return request('/release/work/listAllAppType')
},
listAllIndustry: (): Promise<Response<Array<IndustryType>>> => {
return request("/release/work/listAllIndustry");
return request('/release/work/listAllIndustry')
},
};
}
export const mallApi = {
listAllBrand: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/brand");
return request('/pms/webDevice/brand')
},
listAllCategory: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/category");
return request('/pms/webProductMall/category')
},
listAllParts: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/parts");
return request('/pms/webProductMall/parts')
},
listAllModel: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/model");
return request('/pms/webDevice/model')
},
listAllQuality: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/quality");
return request('/pms/webProductMall/quality')
},
};
}
export interface SkillsType {
name: string;
type: string;
id: number;
skillsName: string;
licenseType:string
name: string
type: string
id: number
skillsName: string
licenseType: string
}
export const flightSkillsApi = {
IndustryFlightSkills: (): Promise<Response<Array<SkillsType>>> => {
return request("/release/curriculum/getIndustryFlightSkills");
return request('/release/curriculum/getIndustryFlightSkills')
},
InDronePilotLicense: (): Promise<Response<Array<SkillsType>>> => {
return request("/release/curriculum/getDronePilotLicense");
return request('/release/curriculum/getDronePilotLicense')
},
};
}
export interface NewsPageType {
id: number;
newsTitle: string;
newsAuthor: string;
userAccountId: number;
surfaceImg: string;
newsContents: string;
createTime: string;
updateTime: string | null;
id: number
newsTitle: string
newsAuthor: string
userAccountId: number
surfaceImg: string
newsContents: string
createTime: string
updateTime: string | null
}
export interface NewsTenderType {
id: number;
tenderNewsId: number;
tenderInfoNo: string;
tenderContent: string;
tenderPrice: number;
createTime: string;
apply: number;
id: number
tenderNewsId: number
tenderInfoNo: string
tenderContent: string
tenderPrice: number
createTime: string
apply: number
}
export interface ListPageNewsInfoResp {
pageNo: number;
pageSize: number;
list: Array<NewsPageType>;
totalCount: number;
totalPage: number;
pageNo: number
pageSize: number
list: Array<NewsPageType>
totalCount: number
totalPage: number
}
export interface ListTenderNewsInfoResp {
pageNo: number;
pageSize: number;
list: Array<NewsTenderType>;
totalCount: number;
totalPage: number;
pageNo: number
pageSize: number
list: Array<NewsTenderType>
totalCount: number
totalPage: number
}
interface ListPageNewsInfoParams {
pageNo: number;
pageSize: number;
cityCode?: number;
date?: string;
districtCode?: number;
provinceCode?: number;
pageNo: number
pageSize: number
cityCode?: number
date?: string
districtCode?: number
provinceCode?: number
}
interface ListTenderNewsInfoParams {
pageNo: number;
pageSize: number;
cityCode?: number;
date?: string;
districtCode?: number;
provinceCode?: number;
pageNo: number
pageSize: number
cityCode?: number
date?: string
districtCode?: number
provinceCode?: number
}
export interface TenderApplyType{
tenderInfoId: number,
tenderNewsId: number,
export interface TenderApplyType {
tenderInfoId: number
tenderNewsId: number
userAccountId: number
}
......@@ -185,16 +163,33 @@ export const listNewsApi = {
listNewsPage: (
params: ListPageNewsInfoParams
): Promise<Response<ListPageNewsInfoResp>> => {
return request("/release/industry-news/listNewsPage", "post", params);
return request('/release/industry-news/listNewsPage', 'post', params)
},
//招标列表
listNewTenderInfo: (
params: ListTenderNewsInfoParams
): Promise<Response<ListTenderNewsInfoResp>> => {
return request("/release/tender/listNewTenderInfo", "post", params);
return request('/release/tender/listNewTenderInfo', 'post', params)
},
//web-招标-合作申请提交
tenderApply: (params: TenderApplyType): Promise<Response<number>> => {
return request('/release/tender/apply', 'post', params)
}
},
}
export interface HomeCategoriesType {
type: 1 | 2 | 3 | 4
}
export interface ResHomeCategoriesType {
id: number
categoryName: string
}
export default {
//新闻列表
HomeCategories: (
params: HomeCategoriesType
): Promise<Response<ResHomeCategoriesType>> => {
return request('/pms/product/mall/getPageHomeCategories', 'get', params)
},
}
import request, { Response } from "~/api/request";
import request, { Response } from '~/api/request'
export interface PositioningInfoParams {
lat?: number;
lon?: number;
pageNo?:number,
pageSize?:number
lat: number
lon: number
pageNo: number
pageSize: number
}
export interface Entiy {
dizhi: string;
jd: number;
wd: number;
range: number;
dizhi: string
jd: number
wd: number
range: number
}
export interface ListPageJobInfoResp {
id: number;
adCode: string;
province: string;
locationList: Array<Entiy>;
export interface ListPageJobInfoType {
address: string
name: string
lon: number
lat: number
distance: number
}
export interface FlyerBitmapEntiy {
flyerName: string,
phoneNum: string,
lon: number,
lat: number,
flyerName: string
phoneNum: string
lon: number
lat: number
distance: number
}
export interface UavBitmapEntiy {
uavName: string,
online: number,
lon: number,
lat: number,
distance: number,
uavName: string
online: number
lon: number
lat: number
distance: number
id: string
}
export interface BitmapInfo<T> {
pageNo: number,
pageSize: number,
list: T[],
totalCount: number,
pageNo: number
pageSize: number
list: T[]
totalCount: number
totalPage: number
}
......@@ -48,19 +49,25 @@ export default {
//web-首页-地图-全国点位
listPositioningInfo: (
params: PositioningInfoParams
): Promise<Response<ListPageJobInfoResp[]>> => {
return request("/release/website/getWebsiteList", "get", params);
): Promise<Response<BitmapInfo<ListPageJobInfoType>>> => {
return request('/release/website/getWebsiteList', 'get', params)
},
//web-首页-地图-全国飞手
listFlyerBitmap: (
params: PositioningInfoParams
): Promise<Response<BitmapInfo<FlyerBitmapEntiy>>> => {
return request("/release/website/flyer/bitmap", "get", params);
return request('/release/website/flyer/bitmap', 'get', params)
},
//web-首页-地图-全国无人机
listUavBitmap: (
params: PositioningInfoParams
): Promise<Response<BitmapInfo<UavBitmapEntiy>>> => {
return request("/release/website/uav/bitmap", "get", params);
return request('/release/website/uav/bitmap', 'get', params)
},
};
//web-首页-地图-全国维修-海点数据
listMaintainBitmap: (
params: PositioningInfoParams
): Promise<Response<BitmapInfo<ListPageJobInfoType>>> => {
return request('/release/website/maintain/bitmap', 'get', params)
},
}
import styled from "styled-components";
import styled from 'styled-components'
export default function Style() {
return <></>;
return <></>
}
export const Box = styled.div`
......@@ -12,7 +12,7 @@ export const Box = styled.div`
position: relative;
padding: 0px;
margin: 0px;
width: 384px;
width: 100%;
height: 220px;
}
......@@ -46,9 +46,4 @@ export const Box = styled.div`
color: #ff552d;
}
}
#container {
padding: 0px;
margin: 0px;
width: 100%;
}
`;
`
import request, { Response } from '~/api/request';
import request, { Response } from '~/api/request'
export interface ListPageJobInfoParams {
pageNo:number,
pageSize:number,
appTypeId?:number,
industryId?:number,
inspectionName?:string,
string?:number,
regionId?:number,
pageNo: number
pageSize: number
appTypeId?: number
industryId?: number
inspectionName?: string
string?: number
regionId?: number
}
export interface Job {
id:number,
serviceName:string,
teamName:string,
price:number,
id: number
serviceName: string
teamName: string
price: number
}
export interface ListPageJobInfoResp {
pageNo: 1,
pageSize: 10,
list: Array<Job>,
totalCount: 0,
pageNo: 1
pageSize: 10
list: Array<Job>
totalCount: 0
totalPage: 0
}
export default {
//web-作业服务-分页
listPageJobServicesInfo: (params: ListPageJobInfoParams,option:{}): Promise<Response<ListPageJobInfoResp>> => {
return request('/release/work/queryTaskServiceList', 'post', params,option)
listPageJobServicesInfo: (
params: ListPageJobInfoParams,
option: {}
): Promise<Response<ListPageJobInfoResp>> => {
return request(
'/pms/backstage/work/queryWorkServiceList',
'post',
params,
option
)
},
}
\ No newline at end of file
}
import request, { Response } from '~/api/request';
import request, { Response } from '~/api/request'
import { RegionResp } from '~/components/filter/api'
export interface ListPageJobInfoParams {
pageNo:number,
pageSize:number,
appTypeId?:number,
industryId?:number,
inspectionName?:string,
string?:number,
regionId?:number,
pageNo: number
pageSize: number
appTypeId?: number
industryId?: number
inspectionName?: string
string?: number
regionId?: number
}
export interface JobDetail {
id?: number,
content?: string,
contentImgs?: string[] | null,
contentVideo?: string | null,
star?: number,
img?: string | null,
type?: number,
name?:string,
time?:number | string
id?: number
content?: string
contentImgs?: string[] | null
contentVideo?: string | null
star?: number
img?: string | null
type?: number
name?: string
time?: number | string
}
export interface ListPageJobInfoResp {
id: number,
serviceName: string,
pictureUrl: string,
videoUrl: string,
teamPoster:string,
evaluateInfo:Array<JobDetail>,
item:number
id: number
serviceName: string
pictureUrl: string
videoUrl: string
teamPoster: string
evaluateInfo: Array<JobDetail>
item: number
coverPlan: string
serviceIntroduction: string
inspComtList: []
}
export interface GetJobServicesDetailParams {
id: number
}
export interface GetOrderTaskParams {
address: string
city: string
endTime: string
images?: []
inspectionId: number
lat: number
lon: number
province: string
startTime: string
taskDescription?: string
}
export default {
//web-作业服务-详情
listDetailJobServicesInfo: (params:GetJobServicesDetailParams): Promise<Response<ListPageJobInfoResp>> => {
return request('/release/work/selectInspection', 'get', params)
listDetailJobServicesInfo: (
params: GetJobServicesDetailParams
): Promise<Response<ListPageJobInfoResp>> => {
return request('/pms/backstage/work/queryWorkService', 'get', params)
},
}
\ No newline at end of file
//web-作业服务-详情-立即预约
insertOrderTask: (params: GetOrderTaskParams): Promise<Response<null>> => {
return request('/oms/serviceOrderTask/insertOrderTask', 'post', params)
},
//区域
region: (): Promise<Response<Array<RegionResp>>> => {
return request('/pms/webDevice/getSecondDistrictInfo')
},
}
import React, {
Component,
Dispatch,
SetStateAction,
useEffect,
useState,
} from 'react'
import { message } from 'antd'
import { Box } from './styled'
import { useRouter } from 'next/router'
let MAP: any
let Amap: any
interface UserInfoType {
lat: number
lon: number
pageNo?: number
pageSize?: number
}
interface BoxProps {
setAddressContent: Dispatch<SetStateAction<any>>
setIsAddressMapShow: Dispatch<SetStateAction<boolean>>
}
export default function MapComponent(props: BoxProps) {
const { setAddressContent, setIsAddressMapShow } = props
const router = useRouter()
const [mapItem, setMapItem] = useState(0)
const [userPositioning, setUserPositioning] = useState<UserInfoType>()
const [markerCol, setMarkerCol] = useState<any>([])
//初始化地图
const init = async () => {
try {
const AMapLoader = await import(
/* webpackChunkName: "amap" */ '@amap/amap-jsapi-loader'
)
await AMapLoader.load({
key: '87b424e68754efc3ba9d11ae07475091', // 申请好的Web端开发者Key,首次调用 load 时必填
version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: [''], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
})
.then(async (AMap) => {
Amap = AMap
MAP = new AMap.Map('container', {
// 设置地图容器id
viewMode: '3D', // 是否为3D地图模式
zoom: 9, // 初始化地图级别
center: [113.93029, 22.53291], // 初始化地图中心点位置
})
//用户定位
AMap.plugin('AMap.Geolocation', function () {
const geolocation = new AMap.Geolocation({
enableHighAccuracy: true, //是否使用高精度定位,默认:true
timeout: 10000, //超过10秒后停止定位,默认:5s
position: 'RB', //定位按钮的停靠位置
offset: [10, 20], //定位按钮与设置的停靠位置的偏移量,默认:[10, 20]
zoomToAccuracy: true, //定位成功后是否自动调整地图视野到定位点
})
MAP.addControl(geolocation)
geolocation.getCurrentPosition(function (
status: string,
result: any
) {
if (status == 'complete') {
onComplete(result)
} else {
onError(result)
}
})
})
//解析定位结果
async function onComplete(data: any) {
console.log('定位成功')
setUserPositioning(data.position)
// return await mapEntiy(0,data.position);
}
//解析定位错误信息
async function onError(data: any) {
// message.error(`定位失败
// 失败原因排查信息:${data.message}
// 浏览器返回信息:${data.originMessage}
// `)
}
await mapEntiy(0)
})
.catch((e) => {
console.log(e)
})
} catch (error) {
console.log(error)
}
}
//选择点位
const mapEntiy = async (index: number, data?: UserInfoType) => {
MAP.on('click', mapGet)
setMapItem(index)
}
const mapGet = (e: any) => {
console.log(e)
// 在这里获取点位信息
const lnglat = e.lnglat
console.log(lnglat)
const geocoder = new Amap.Geocoder({
radius: 1000,
extensions: 'all',
})
geocoder.getAddress(lnglat, function (status: any, result: any) {
if (status === 'complete' && result.regeocode) {
const address = result.regeocode.addressComponent
const addressDteail =
address.province +
address.city +
address.district +
address.township +
address.street +
address.streetNumber
setAddressContent({
province: address.province,
city: address.city,
lon: lnglat.lng,
lat: lnglat.lat,
addressDteail,
})
setIsAddressMapShow(false)
// console.log(
// address.province +
// address.city +
// address.district +
// address.township +
// address.street +
// address.streetNumber
// ) // 打印省市区信息
}
})
// MAP.off('click', mapGet); // 移除click事件
}
const addEntiy = (lon: any, lat: any, name: string) => {
if (!Amap) return
const icons = new Amap.Icon({
size: new Amap.Size(60, 60), // 图标尺寸
imageSize: new Amap.Size(60, 60), // 根据所设置的大小拉伸或压缩图片
})
const marker = new Amap.Marker({
position: new Amap.LngLat(lon, lat),
offset: new Amap.Pixel(-10, -10),
icon: icons, // 添加 Icon 实例
title: name,
zoom: 13,
})
return marker
}
useEffect(() => {
;(async () => {
await init()
})()
return MAP && MAP.destroy()
}, [])
return (
<Box className="right-box-item">
<div id="container" className="map"></div>
</Box>
)
}
import styled from 'styled-components'
export default function Style() {
return <></>
}
export const Box = styled.div`
box-sizing: border-box;
width: 800px;
height: 800px;
#container {
position: relative;
padding: 0px;
margin: 0px;
width: 100%;
height: 800px;
}
.amap-logo {
//去除高德地图水印
display: none !important;
visibility: hidden !important;
}
.amap-copyright {
//去除高德地图水印
display: none !important;
visibility: hidden !important;
}
`
import styled from "styled-components"
import styled from 'styled-components'
export default function Style() {
return <></>;
return <></>
}
export const Box = styled.div`
box-sizing: border-box;
width: 1200px;
height: 1338px;
margin-top: 18px;
background-color: #FFFFFF;
.top{
display: flex;
height: 300px;
padding: 24px 0 0 24px;
&-image{
width: 300px;
height: 300px;
background-color: #F4F5F7;
border-radius: 6px;
margin-right: 32px;
position: relative;
box-sizing: border-box;
width: 1200px;
height: 1338px;
margin-top: 18px;
background-color: #ffffff;
.top {
display: flex;
height: 300px;
padding: 24px 0 0 24px;
&-image {
width: 300px;
height: 300px;
background-color: #f4f5f7;
border-radius: 6px;
margin-right: 32px;
position: relative;
}
&-right {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 300px;
.right-top {
.title {
height: 26px;
font-size: 28px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #090909;
line-height: 26px;
}
&-right{
display: flex;
flex-direction: column;
justify-content: space-between;
height: 300px;
.right-top{
.title{
height: 26px;
font-size: 28px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #090909;
line-height: 26px;
}
.detail{
display: flex;
margin-top: 27px;
.tab{
width: 64px;
height: 18px;
line-height: 18px;
text-align: center;
background: linear-gradient(270deg, #3E62E5 0%, #3588F7 100%);
border-radius: 9px;
font-size: 12px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #F6FDFE;
margin-right: 5px;
}
.content{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 20px;
}
}
.more{
display: flex;
margin-top: 25px;
.tab{
width: 131px;
height: 23px;
line-height: 23px;
text-align: center;
border-radius: 3px;
font-family: MicrosoftYaHei;
background-color: #F4F4F4;
color: #333333;
margin-right: 8px;
&.filst{
color: #6E411E;
background-color: #F9E3D1;
}
}
}
}
.right-bottom{
.bottom-btn{
.btn-left{
width: 207px;
height: 40px;
background-color: #FFE4D1;
border: 1px solid #EBBAAF;
font-family: MicrosoftYaHei;
color: #FF552D;
letter-spacing: 1px;
margin-right: 12px;
}
.btn-right{
width: 207px;
height: 40px;
background: #FF552D;
font-family: MicrosoftYaHei;
color: #FFFFFF;
letter-spacing: 1px;
}
}
.detail {
display: flex;
margin-top: 27px;
.tab {
width: 64px;
height: 18px;
line-height: 18px;
text-align: center;
background: linear-gradient(270deg, #3e62e5 0%, #3588f7 100%);
border-radius: 9px;
font-size: 12px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #f6fdfe;
margin-right: 5px;
}
.content {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 20px;
}
}
.more {
display: flex;
margin-top: 25px;
.tab {
width: 131px;
height: 23px;
line-height: 23px;
text-align: center;
border-radius: 3px;
font-family: MicrosoftYaHei;
background-color: #f4f4f4;
color: #333333;
margin-right: 8px;
&.filst {
color: #6e411e;
background-color: #f9e3d1;
}
}
}
}
.tabs{
padding: 0 24px;
margin-top: 69px;
.teamIntroduction{
width: 100%;
}
.right-bottom {
.bottom-btn {
.btn-left {
width: 207px;
height: 40px;
background-color: #ffe4d1;
border: 1px solid #ebbaaf;
font-family: MicrosoftYaHei;
color: #ff552d;
letter-spacing: 1px;
margin-right: 12px;
}
.btn-right {
width: 207px;
height: 40px;
background: #ff552d;
font-family: MicrosoftYaHei;
color: #ffffff;
letter-spacing: 1px;
}
}
}
}
}
.tabs {
padding: 0 24px;
margin-top: 69px;
.teamIntroduction {
width: 100%;
}
}
.reservation {
.title {
display: flex;
align-items: center;
padding-bottom: 25px;
.left {
width: 58px;
height: 58px;
background: #d8d8d8;
border-radius: 2px;
}
.right {
margin-left: 10px;
font-weight: 700;
font-size: 16px;
}
}
}
.form-data {
.address-map {
display: flex;
align-items: center;
.value {
margin-right: 20px;
}
}
`
\ No newline at end of file
}
`
import React, { useEffect, useState , useRef } from "react";
import { Box } from "./styled";
import { Pagination } from "antd";
import Layout from "~/components/layout";
import ContentBox from "~/components/contentBox";
import { useRouter } from "next/router";
import Filter, { FilterResult, AdapterResult } from "~/components/filter";
import api, { Job } from "./api";
import Image from "next/image";
import React, { useEffect, useState, useRef } from 'react'
import { Box } from './styled'
import { Pagination } from 'antd'
import Layout from '~/components/layout'
import ContentBox from '~/components/contentBox'
import { useRouter } from 'next/router'
import Filter, { FilterResult, AdapterResult } from '~/components/filter'
import api, { Job } from './api'
import Image from 'next/image'
// 此函数在构建时被调用
export async function getServerSideProps() {
return {
props: {},
};
}
}
interface ImageListType {}
export default function JobServices() {
const router = useRouter();
const filter = useRef<any>()
const router = useRouter()
const [list, setList] = useState([
"https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/540X844-2(1).jpg",
'https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/540X844-2(1).jpg',
// "https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/665512fd-12e6-49a9-93c1-f9dcd0e82083.jpg",
]);
])
const [productList, setProductList] = useState(
Array<{ element: JSX.Element }>
);
)
const [rightDomList, setRightDomList] = useState(
Array<{ element: JSX.Element }>
);
)
const leftDom = (item: Job) => {
return (
<div
......@@ -43,8 +42,9 @@ export default function JobServices() {
{/* <div className="com">{item.teamName}</div> */}
</div>
<div className="value-right">
<span className="money">¥{item.price}</span>{" "}
<span className="unit">/平</span>
{/* <span className="money">¥{item.price}</span> */}
{/* <span className="unit">/平</span> */}
<span className="money">获取报价</span>
</div>
</div>
</div>
......@@ -56,49 +56,46 @@ export default function JobServices() {
<div className="com">{item.teamName}</div>
</div>
</div>
);
};
)
}
const rightDom = (item: string) => {
return (
<div className="right-box-item advertisement" key={item}>
<Image src={item} alt="error" width={260} height={420} />
</div>
);
};
)
}
const [filterResult, setFilterResult] = useState<AdapterResult>({}); //筛选结果
const [filterResult, setFilterResult] = useState<AdapterResult>({}) //筛选结果
const [pageParams, setPageParams] = useState({
pageNo: 1,
pageSize: 14,
}); //分页器对象
}) //分页器对象
const [count, setCount] = useState(0); //商品总数
const [abort, setAbort] = useState<AbortController | null>(null); //请求中断
const [count, setCount] = useState(0) //商品总数
const [abort, setAbort] = useState<AbortController | null>(null) //请求中断
const onPageChange = (page: number, pageSize: number) => {
setPageParams({
...pageParams,
pageNo: page,
});
};
})
}
useEffect(() => {
//中断前一次列表请求
abort?.abort();
setAbort(new AbortController());
}, [filterResult, pageParams]);
abort?.abort()
setAbort(new AbortController())
}, [filterResult, pageParams])
//端口列表请求
useEffect(() => {
let queryVal = JSON.parse(JSON.stringify(router.query));
const idArr = filter.current.idArr
let queryVal = JSON.parse(JSON.stringify(router.query))
let rs
for (const key in queryVal) {
if (idArr.includes(key)) {
rs = {[key]:router.query[key]}
}
if (Object.keys(queryVal).length) {
rs = { categoryId: [Number(queryVal['categoryId'])] }
}
api
.listPageJobServicesInfo(
......@@ -114,49 +111,46 @@ export default function JobServices() {
.then((res) => {
setProductList(
res.result?.list?.map((item) => {
return { element: leftDom(item) };
return { element: leftDom(item) }
}) || []
);
setCount(res.result?.totalCount || 0);
});
}, [abort]);
)
setCount(res.result?.totalCount || 0)
})
}, [abort])
const onFilterChange = (
filterResult: FilterResult,
adapterFilterResult: AdapterResult
) => {
console.log("filterResult", filterResult, adapterFilterResult);
setFilterResult(adapterFilterResult);
};
console.log('filterResult', filterResult, adapterFilterResult)
adapterFilterResult.categoryId = adapterFilterResult.categoryId?.map(
(item) => item.id
)
setFilterResult(adapterFilterResult)
}
useEffect(() => {
setRightDomList(
list.map((item) => {
return { element: rightDom(item) };
return { element: rightDom(item) }
})
);
}, []);
)
}, [])
useEffect(() => {
let queryVal = JSON.parse(JSON.stringify(router.query));
if (router.query) {
const idArr = filter.current.idArr
for (const key in queryVal) {
if (idArr.includes(key)) {
setFilterResult({ [key]:router.query[key] });
}
}
let queryVal = JSON.parse(JSON.stringify(router.query))
if (Object.keys(router.query).length) {
setFilterResult({ categoryId: [Number(queryVal['categoryId'])] })
}
}, [router]);
}, [router])
return (
<Layout>
<Box>
<Filter
types={["地域", "行业", "应用"]}
types={['地域', '行业', '应用']}
showResultItem
onChange={onFilterChange}
ref={filter}
></Filter>
<div style={{ marginTop: 10 }}>
<ContentBox
......@@ -179,12 +173,12 @@ export default function JobServices() {
}}
rightRenderDom={{ columns: rightDomList }}
leftcontentstyle={{
width: "924px",
margin: { top: 0, right: "10px", bottom: "10px", left: 0 },
width: '924px',
margin: { top: 0, right: '10px', bottom: '10px', left: 0 },
}}
/>
</div>
</Box>
</Layout>
);
)
}
import request, { Response } from '~/api/request';
import request, { Response } from '~/api/request'
export interface ListPageGoodsInfoParams {
"brandId"?: number,
"districtId"?: number,
"modelId"?: number,
"pageNo": number,
"pageSize": number,
"partsId"?: number,
"productCategoryId"?: number,
"qualityId"?: number
export interface DeviceListParams {
categoryId?: any[];
pageNo: number;
pageSize: number;
provinceId?: number;
type: number;
}
export interface Goods {
"createTime": string,
"directoryId": number,
"directoryName": string,
"goodsName": string,
"goodsOneLevelTypeName": string,
"goodsTwoLevelTypeName": string,
"id": number,
"imgUrl": string,
"isCoupons": number,
"status": number
id: number;
goodsName: string;
images: string;
price?: any;
}
export interface ListPageGoodsInfoResp {
export interface DeviceListResp {
"pageNo": 1,
"pageSize": 10,
"list": Array<Goods>,
......@@ -33,17 +24,19 @@ export interface ListPageGoodsInfoResp {
}
export interface Ad {
id: number;
imageUrl: string;
id: number
bannerImg: string
}
export default {
//web-商品信息-分页
listPageGoodsInfo: (params: ListPageGoodsInfoParams, options = {}): Promise<Response<ListPageGoodsInfoResp>> => {
return request('/pms/webProductMall/listPageGoodsInfo', 'post', params, options)
deviceList: (params: DeviceListParams, options = {}): Promise<Response<DeviceListResp>> => {
return request('/pms/product/mall/deviceList', 'post', params, options)
},
//产品商城广告位
ad: (): Promise<Response<Array<Ad>>> => {
return request('/pms/webProductMall/ad')
}
}
\ No newline at end of file
listBannerImg: () => {
return request('/release/module/listBannerImg', 'get', {
moduleCode: 'PRODUCT_MARKETP'
})
},
}
......@@ -13,7 +13,7 @@ import { Navigation } from "swiper";
// Import Swiper styles
import "swiper/css";
import "swiper/css/navigation";
import api, { GetAppGoodsInfoDetailResult } from "./api";
import api, { GetLeaseGoodsDetailResp, ProductSpecList } from "./api";
import IntentionModal from "./components/intentionModal";
import { UserContext } from "~/lib/userProvider";
......@@ -22,11 +22,24 @@ export default function MallDetail() {
const [visible, setVisible] = useState(false); //商品图预览
const router = useRouter();
const [id, setId] = useState<number | null>(null);
const [detail, setDetail] = useState<GetAppGoodsInfoDetailResult | null>(
null
); //详情数据
const [detail, setDetail] = useState<GetLeaseGoodsDetailResp | null>(null); //详情数据
const [intentionModalOpen, setIntentionModalOpen] = useState(false); //意向弹窗
const [productImg, setProductImg] = useState(''); //展示的商品图
const [productImg, setProductImg] = useState(""); //展示的商品图
const [previewIndex, setPreviewIndex] = useState(0); //预览开始索引
const [checkItems, setCheckItems] = useState<ProductSpecList[]>([]); //选中的规格
const [specCount, setSpecCount] = useState(0); //规格数量
useEffect(() => {
if (detail) {
let count = 0;
detail.goodsSpec?.forEach((good) => {
good.productSpecList?.forEach((product) => {
count++;
});
});
setSpecCount(count);
}
}, [detail]);
//打开意向modal
const openIntentionModal = () => {
......@@ -53,8 +66,9 @@ export default function MallDetail() {
useEffect(() => {
if (id) {
api
.getAppGoodsInfoDetail({
id: id,
.getLeaseGoodsDetail({
goodsId: id,
type: 0,
})
.then((res) => {
setDetail(res.result || null);
......@@ -71,11 +85,16 @@ export default function MallDetail() {
detail={detail}
onOk={handleIntentionOk}
onCancel={handleIntentionCancel}
onChange={(items: ProductSpecList[]) => setCheckItems(items)}
></IntentionModal>
<div className="page" style={{ marginTop: 20, backgroundColor: "#fff" }}>
<div style={{ display: "none" }}>
<AImage.PreviewGroup
preview={{ visible, onVisibleChange: (vis) => setVisible(vis) }}
preview={{
visible,
onVisibleChange: (vis) => setVisible(vis),
current: previewIndex,
}}
>
{detail?.images?.map((item) => {
return <AImage key={item.id} src={item.imgUrl} />;
......@@ -106,7 +125,7 @@ export default function MallDetail() {
onSlideChange={() => console.log("slide change")}
onSwiper={(swiper) => console.log(swiper)}
>
{detail?.images?.map((item) => {
{detail?.images?.map((item, i) => {
return (
<SwiperSlide key={item.id}>
<AImage
......@@ -116,7 +135,9 @@ export default function MallDetail() {
src={item.imgUrl}
fallback={errImg}
style={{ cursor: "pointer" }}
onClick={() => setProductImg(item.imgUrl)}
onClick={() => {
setProductImg(item.imgUrl), setPreviewIndex(i);
}}
/>
</SwiperSlide>
);
......@@ -128,11 +149,8 @@ export default function MallDetail() {
<div className={`${styles.font1} ${styles.ellipsis}`}>
{detail?.goodsName}
</div>
<div
className={`${styles.font2} ${styles.ellipsis}`}
style={{ height: 22 }}
>
{detail?.goodsDesc}
<div className={`${styles.font2} ${styles.ellipsis2}`} style={{}}>
{detail?.goodsDetail?.goodsDesc}
</div>
<Space
size={24}
......@@ -149,14 +167,14 @@ export default function MallDetail() {
选择
</Col>
<Col flex="auto" className={styles.font4} style={{}}>
已选:1
已选:{checkItems.length}
</Col>
</Row>
</Col>
<Col>
<Row align="middle" style={{ cursor: "pointer" }}>
<Col className={styles.font4} onClick={openIntentionModal}>
3种可选
{specCount}种可选
</Col>
<Col style={{ marginLeft: 9 }}>
<DownOutlined
......
import request, { Response } from "~/api/request"
export interface GetAppGoodsInfoDetailParams {
id: number
export interface GetLeaseGoodsDetailParams {
goodsId: number,
type: 1 | 0, //租赁:1 销售商品:0
}
export interface GetAppGoodsInfoDetailResult {
export interface GetLeaseGoodsDetailResp {
id: number;
pid?: number;
goodsName?: string;
shareFlyServiceId?: number;
repoId?: number;
goodsSpec?: GoodsSpec[];
images?: Image[];
goodsVideo?: string;
goodsVideoId?: number;
goodsDetail?: GoodsDetail;
sortTypeId?: number;
masterTypeId?: number;
slaveTypeId?: number;
tag?: string;
shelfStatus?: number;
otherService?: OtherService[];
question?: Question[];
goodsDesc?: string
images: Image[];
goodsVideo?: any;
goodsVideoId?: any;
goodsName: string;
goodsNo: string;
goodsDetail: GoodsDetail;
directoryId: number;
categoryByOne: number;
categoryByTwo?: any;
tag?: any;
shelfStatus: number;
goodsSpec: GoodsSpec[];
otherService: OtherService[];
price?: any;
}
export interface GoodsDetail {
id: number;
goodsDesc: string;
content: string;
remark?: any;
}
export interface Image {
export interface OtherService {
id: number;
imgUrl: string;
imgType: number;
saleServiceId: number;
serviceName: string;
}
export interface GoodsSpec {
id: number;
goodsSpecName: string;
goodsTypeId: number;
categoryId: number;
typeName: string;
skuId: number;
brandInfoId: number;
brandInfoId?: any;
skuName: string;
productSpecList: ProductSpec[];
productSpecList: ProductSpecList[];
industrySpecList?: any;
chooseType: number;
skuUnitId: number;
unitName: string;
must: number;
flag?: any;
flag: number;
}
export interface ProductSpec {
export interface ProductSpecList {
id: number;
productSpec: number;
productSkuId: number;
......@@ -64,26 +55,46 @@ export interface ProductSpec {
partNo: string;
versionDesc: string;
createTime?: any;
productSpecCPQVO?: any;
productSpecCPQVO: ProductSpecCPQVO;
}
export interface Question {
answer: string,
id: number,
question: string
export interface ProductSpecCPQVO {
productSpecId: number;
type: number;
leaseTerm?: any;
specPrice: any[];
}
//其他服务: 1:免费配送,2:专业飞手培训2日, 3:半年保修, 4:一年保修
export interface OtherService {
id: number,
saleServiceId: number,
serviceName: string
export interface GoodsDetail {
id: number;
goodsDesc: string;
content: string;
remark?: any;
}
export interface Image {
id: number;
imgUrl: string;
imgType: number;
}
interface CommitMallOrderParams {
buyNum: number;
directoryId: number;
goodsInfoId: number;
mallSpecIds: any[];
remark: string;
userAddressId: number;
}
export default {
//web-获取商品详细信息--共多少种选择
getAppGoodsInfoDetail(params: GetAppGoodsInfoDetailParams): Promise<Response<GetAppGoodsInfoDetailResult>> {
return request('/pms/webProductMall/getAppGoodsInfoDetail', 'get', params)
getLeaseGoodsDetail(params: GetLeaseGoodsDetailParams): Promise<Response<GetLeaseGoodsDetailResp>> {
return request('/pms/product/mall/getLeaseGoodsDetail', 'get', params)
},
//提交订单V1.0.0
commitMallOrder(params: CommitMallOrderParams){
return request('/oms/app-order/commitMallOrder', 'post', params);
}
}
\ No newline at end of file
import request from '~/api/request'
interface CommitMallOrderParams {
buyNum: number
directoryId: number
goodsInfoId: number
mallSpecIds: any[]
remark?: string
userAddressId: number
}
export default {
//提交订单V1.0.0
commitMallOrder(params: CommitMallOrderParams) {
return request('/oms/app-order/confirmMallOrder', 'post', params)
},
}
......@@ -59,6 +59,23 @@
padding: 0 39px 0 38px;
height: 364px;
overflow-y: auto;
.numBox {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
.numLeft {
display: flex;
align-items: center;
.label {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #121212;
margin-right: 5px;
}
}
}
@include scrollbar();
}
import { Button, Col, Image, Modal, Row, Space } from "antd";
import { useState } from "react";
import { Button, Col, Image, message, Modal, Row, Space } from "antd";
import { useEffect, useState } from "react";
import errImg from "~/assets/errImg";
import { GetAppGoodsInfoDetailResult } from "../../api";
import { GetLeaseGoodsDetailResp, ProductSpecList } from "../../api";
import styles from "./index.module.scss";
import api from "./api";
import Item from "antd/es/list/Item";
type Props = {
open?: boolean;
onOk?: (e: React.MouseEvent<HTMLButtonElement>) => void;
onCancel: (e: React.MouseEvent<HTMLButtonElement>) => void;
detail: GetAppGoodsInfoDetailResult | null;
onOk?: () => void;
onCancel: () => void;
detail: GetLeaseGoodsDetailResp | null;
onChange?: (checkItems: ProductSpecList[]) => void;
};
export default function IntentionModal(props: Props) {
const [checkedMap, setCheckedMap] = useState<{ string?: boolean }>({}); //通过索引记录选中的产品规格 例: {'1,1': true|false}
const [checkedMap, setCheckedMap] = useState<{ string?: boolean }>({}); //通过索引记录选中的产品规格 例: {'1,1': true|false} props.detail?.goodsSpec[1].productSpecList[1]
const [checkItems, setCheckItems] = useState<ProductSpecList[]>([]); //选中的规格
const [loading, setLoading] = useState(false); //下单中
useEffect(() => {
let list: ProductSpecList[] = [];
Object.keys(checkedMap).forEach((key) => {
if (checkedMap[key as keyof typeof checkedMap]) {
let arr = key.split(",");
let item =
props.detail?.goodsSpec[Number(arr[0])].productSpecList[
Number(arr[1])
];
if (item) {
list.push(item);
}
}
});
setCheckItems(list);
props.onChange && props.onChange(list);
}, [checkedMap]);
//添加规格到购物车
function addProductSpec(goodsSpecIndex: number, productSpecIndex: number) {
......@@ -27,6 +50,58 @@ export default function IntentionModal(props: Props) {
});
}
//提交
function onSubmit() {
let buyNum = 0;
let mallSpecIds: number[] = [];
Object.keys(checkedMap).forEach((key) => {
if (checkedMap[key as keyof typeof checkedMap]) {
buyNum++;
let arr = key.split(",");
let specId =
props.detail?.goodsSpec[Number(arr[0])].productSpecList[
Number(arr[1])
].id;
if (specId) {
mallSpecIds.push(specId);
}
}
});
if (buyNum > 0) {
setLoading(true);
api
.commitMallOrder({
buyNum,
directoryId: 1,
goodsInfoId: props.detail!.id,
mallSpecIds,
userAddressId: 1,
})
.then((res) => {
if (res.code == "200") {
message.success("提交意向成功");
//重置为未选中
let temp = {
...checkedMap,
};
Object.keys(temp).forEach((key) => {
temp[key as keyof typeof temp] = false;
});
setCheckedMap(temp);
props.onCancel();
} else {
}
setLoading(false);
})
.catch((err) => {
message.error("提交意向失败");
console.log("err", err);
setLoading(false);
});
}
}
return (
<Modal
open={props.open}
......@@ -41,6 +116,9 @@ export default function IntentionModal(props: Props) {
type="primary"
className={styles.font5}
style={{ width: "100%", height: 44 }}
onClick={onSubmit}
loading={loading}
disabled={checkItems.length == 0}
>
提交意向
</Button>
......@@ -68,7 +146,12 @@ export default function IntentionModal(props: Props) {
className={`${styles.font2} ${styles.ellipsis2}`}
style={{ marginTop: 7 }}
>
已选:
已选:{" "}
{checkItems
.map((item) => {
return item.specName;
})
.join("+")}
</div>
</Col>
</Row>
......
import request, { Response } from '~/api/request'
export interface GetWebDeviceDetailParams {
buyNum: number
directoryId: number
goodsInfoId: number
mallSpecIds: number[]
remark?: string
userAddressId: number
}
export interface WareImgsType {
id: number
imgUrl: string
imgType: number
}
export interface UserAddress {
id: number
takeName: string
takePhone: string
takeRegion: string
takeAddress: string
type: number
}
export interface GetOrderForGoods {
realityAmount: number
orderNo: string
}
export default {
//web-地址管理-查询用户地址列表-条件查询
listUserAddress: (params: {}): Promise<Response<UserAddress[]>> => {
return request('/oms/user-address/selectList', 'POST', params)
},
//web-产品商城-下单
FeignAddLease: (
params: GetWebDeviceDetailParams
): Promise<Response<GetOrderForGoods>> => {
return request('/oms/app-order/commitMallOrder', 'post', params)
},
//web-产品商城-订单支付
OrderPayment: (params: {
orderNo: string
}): Promise<Response<GetOrderForGoods>> => {
return request(`/payment/repocash/orderPayment`, 'get', params)
},
}
import styled from 'styled-components'
export const OrderForGoodsBox = styled.div`
box-sizing: border-box;
width: 1000px;
.address {
.top {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e6e6e6;
height: 30px;
line-height: 30px;
margin-top: 30px;
.left {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #333333;
line-height: 18px;
}
.right {
.btn {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #007aff;
line-height: 19px;
}
}
}
.bottom {
.item {
display: flex;
justify-content: space-between;
align-items: center;
width: 1000px;
height: 48px;
border: 1px solid transparent;
margin-top: 8px;
&.active {
background: #fff1e8;
border-radius: 6px;
border: 1px solid #ff552d;
}
.left {
display: flex;
align-items: center;
justify-content: space-around;
.active {
margin-right: 18px;
display: flex;
.icon {
width: 15px;
height: 22px;
background: #ff552d;
margin-left: 17px;
}
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
margin-left: 18px;
}
}
}
.right {
margin-right: 22px;
}
}
}
}
.info {
margin-top: 30px;
.title {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #333333;
line-height: 18px;
}
.table {
.table-title {
display: flex;
align-items: center;
width: 1000px;
border-bottom: 1px solid #e6e6e6;
padding: 10px 0;
margin-top: 20px;
.table-item {
text-align: center;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
}
}
.table-body {
display: flex;
align-items: center;
height: 100px;
margin-top: 10px;
.body-item {
text-align: center;
&.article {
display: flex;
justify-content: space-between;
.image {
margin-right: 10px;
.image-box {
width: 80px;
height: 80px;
}
}
.right {
.top {
width: 171px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #141414;
line-height: 20px;
}
.bottom {
width: 171px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #929295;
line-height: 17px;
}
}
}
&.total-price {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff3100;
line-height: 18px;
}
}
}
}
}
.notes {
display: flex;
align-items: center;
justify-content: space-between;
width: 1000px;
height: 110px;
background: #e1efff;
border: 1px solid #d0eaf5;
padding: 0 22px 0 16px;
.left {
display: flex;
align-items: top;
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
margin-top: 4px;
}
}
.right {
width: 430px;
.top {
display: flex;
align-items: center;
justify-content: space-between;
}
.font {
display: flex;
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 18px;
}
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
margin-right: 12px;
}
.value {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #2b2b2b;
line-height: 20px;
}
.price {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff3100;
line-height: 18px;
}
}
}
.detail-box {
display: flex;
justify-content: flex-end;
margin-top: 26px;
.right-box {
.detail {
width: 477px;
height: 110px;
border: 1px solid #ff5001;
padding: 16px 19px 19px 19px;
.top {
display: flex;
justify-content: flex-end;
align-items: center;
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #474747;
line-height: 19px;
margin-right: 10px;
}
.price {
font-size: 26px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff552d;
line-height: 33px;
}
}
.bottom {
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 15px;
.value {
font-size: 12px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 15px;
margin-right: 10px;
}
.value-content {
font-size: 12px;
font-family: MicrosoftYaHei;
color: #333333;
line-height: 16px;
}
}
}
.detail-sumbit {
display: flex;
justify-content: flex-end;
.btn {
width: 182px;
height: 39px;
background: #ff552d;
border: 1px solid #ff5001;
border-radius: 0;
color: #ffffff;
}
}
}
}
.Payment {
.title {
text-align: center;
font-size: 26px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff552d;
}
}
.addAddress {
.title {
text-align: center;
height: 25px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 25px;
}
.image {
display: flex;
justify-content: center;
align-items: center;
padding: 48px 0 32px;
.addressImg {
width: 150px;
height: 150px;
}
}
.content {
text-align: center;
width: 311px;
height: 38px;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #3e454d;
line-height: 19px;
}
}
`
......@@ -4,6 +4,10 @@
@include ellipsis(1);
}
.ellipsis2 {
@include ellipsis(2);
}
.font1 {
font-size: 28px;
font-weight: bold;
......
import React, { useEffect, useState } from "react";
import { Empty, Pagination, Image, Spin } from "antd";
import Layout from "~/components/layout";
import styles from "./index.module.scss";
import { useRouter } from "next/router";
import Filter, { AdapterResult, FilterResult } from "~/components/filter";
import api, { Ad, Goods, ListPageGoodsInfoParams } from "./api";
import errImg from "~/assets/errImg";
import React, { useEffect, useState } from 'react'
import { Empty, Pagination, Image, Spin } from 'antd'
import Layout from '~/components/layout'
import styles from './index.module.scss'
import { useRouter } from 'next/router'
import Filter, { AdapterResult, FilterResult } from '~/components/filter'
import api, { Ad, Goods } from './api'
import errImg from '~/assets/errImg'
// 此函数在构建时被调用
export async function getServerSideProps() {
return {
props: {},
};
}
}
type Props = {};
type Props = {}
export default function Mall(props: Props) {
const router = useRouter();
const [productList, setProductList] = useState<Array<Goods>>([]); //商品列表
const [filterResult, setFilterResult] = useState<AdapterResult>({}); //筛选结果
const [pageParams, setPageParams] = useState({
const router = useRouter()
const [productList, setProductList] = useState<Array<Goods>>([]) //商品列表
const [filterResult, setFilterResult] = useState<AdapterResult>({}) //筛选结果
const [pageParams, setPageParams] = useState<{
pageNo: number
pageSize: number
}>({
pageNo: 1,
pageSize: 15,
}); //分页器对象
const [count, setCount] = useState(0); //商品总数
const [abort, setAbort] = useState<AbortController | null>(null); //请求中断对你
const [adList, setAdList] = useState<Array<Ad>>([]); //广告列表
const [loading, setLoading] = useState(false);
}) //分页器对象
const [count, setCount] = useState(0) //商品总数
const [abort, setAbort] = useState<AbortController | null>(null) //请求中断对象
const [adList, setAdList] = useState<Array<Ad>>([]) //广告列表
const [loading, setLoading] = useState(false)
useEffect(() => {
//中断前一次列表请求
abort?.abort();
setAbort(new AbortController());
}, [filterResult, pageParams]);
abort?.abort()
setAbort(new AbortController())
}, [filterResult, pageParams])
//端口列表请求
//商品列表请求
useEffect(() => {
if (!abort) {
return;
return
}
setLoading(true);
setLoading(true)
api
.listPageGoodsInfo(
.deviceList(
{
...filterResult,
type: 0,
...pageParams,
...filterResult,
},
{
signal: abort?.signal,
......@@ -56,34 +60,37 @@ export default function Mall(props: Props) {
setCount(res.result?.totalCount || 0);
setLoading(false);
});
}, [abort]);
}, [abort])
//广告请求
useEffect(() => {
api.ad().then((res) => {
api.listBannerImg().then((res) => {
setAdList(res.result || []);
});
}, []);
}, [])
const onFilterChange = (
filterResult: FilterResult,
adapterFilterResult: AdapterResult
) => {
console.log("filterResult", filterResult, adapterFilterResult);
setFilterResult(adapterFilterResult);
};
console.log('filterResult', filterResult, adapterFilterResult)
adapterFilterResult.categoryId = adapterFilterResult.categoryId?.map(
(item) => item.id
)
setFilterResult(adapterFilterResult)
}
const onPageChange = (page: number, pageSize: number) => {
setPageParams({
...pageParams,
pageNo: page,
});
};
})
}
return (
<Layout>
<div className="page" style={{ paddingTop: "18px" }}>
<Filter
types={["类目", "地域", "品牌", "部件", "型号", "成色"]}
types={["地域"]}
showResultItem
onChange={onFilterChange}
></Filter>
......@@ -91,42 +98,45 @@ export default function Mall(props: Props) {
<div className={styles.productList}>
<div className={styles.main}>
<div className={styles.listContent}>
<ul className={styles.listWrap}>
{productList.map((item, i) => {
return (
<li
key={i}
className={styles.item}
onClick={() => router.push("/mall/detail/" + item.id)}
>
<div className={styles.imgBox}>
<Image
alt=""
src={item.imgUrl}
className={styles.img}
width={116}
height={116}
preview={false}
></Image>
</div>
<div className={styles.title}>{item.goodsName}</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>
<Spin spinning={loading} delay={500}>
<ul className={styles.listWrap}>
{productList.map((item, i) => {
return (
<li
key={i}
className={styles.item}
onClick={() => router.push("/mall/detail/" + item.id)}
>
<div className={styles.imgBox}>
<Image
alt=""
src={item.images}
className={styles.img}
width={116}
height={116}
preview={false}
></Image>
</div>
<div className={styles.title}>{item.goodsName}</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>
</Spin>
<div className={styles.paginationPage}>
<Pagination
current={pageParams.pageNo}
......@@ -147,7 +157,7 @@ export default function Mall(props: Props) {
<Image
key={item.id}
className={styles.ad}
src={item.imageUrl}
src={item.bannerImg}
width={189}
height={295}
preview={false}
......
.Sider {
width: 129px;
background: #fafafa;
}
.menu {
width: 128px;
min-height: 507px;
background: #fafafa;
border-right: 0 !important;
:global .ant-menu-title-content {
font-size: 12px;
}
}
.title {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000;
line-height: 19px;
padding-top: 18px;
padding-left: 27px;
padding-bottom: 8px;
border-bottom: 1px solid #e5e5e5;
}
import LayoutView from "~/components/layout";
import React, { useState } from "react";
import type { MenuProps } from "antd";
import { Button, Menu } from "antd";
import styles from "./index.module.scss";
import Router from "next/router";
function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[],
type?: "group"
): MenuItem {
return {
key,
icon,
children,
label,
type,
} as MenuItem;
}
const items: MenuItem[] = [
getItem("我的订单", "1", undefined, [
getItem("服务订单", "/personalCenter/servicesOrders"),
getItem("租赁订单", "/personalCenter/leasingOrders"),
getItem("商城订单", "/personalCenter/mallOrders"),
// getItem("培训订单", "/personalCenter/trainOrders"),
]),
/* getItem("账户信息", "2"),
getItem("优惠券卡包", "3"),
getItem("福利活动", "4"),
getItem("身份认证", "5"),
getItem("客服中心", "6"),
getItem("推广海报", "7"),
getItem("副业赚钱", "8"), */
];
type MenuItem = Required<MenuProps>["items"][number];
type Props = {
style?: React.CSSProperties;
selectedKeys?: string[];
};
export default function Sider(props: Props) {
return (
<div className={styles.Sider} style={props.style}>
<div className={styles.title}>个人中心</div>
<Menu
selectedKeys={props.selectedKeys}
openKeys={["1"]}
mode="inline"
items={items}
className={styles.menu}
onClick={(info) => {
Router.push(info.key);
}}
/>
</div>
);
}
import request, { Response } from "~/api/request"
export interface ListPageWechatOrderParams {
buyerAccount?: string;
endTime?: string;
orderNo?: string;
pageNo: number;
pageSize: number;
startTime?: string;
tranStatus?: string;
wareNo?: string;
wareTitle?: string;
}
export interface ListPageWechatOrderResp {
pageNo: number;
pageSize: number;
list: LeasingList[];
totalCount: number;
totalPage: number;
}
export interface LeasingList {
id: number;
orderNo: string;
createTime?: any;
wareInfoId?: any;
wareNo?: any;
wareTitle: string;
wareImg: string;
skuInfoId?: any;
skuTitle?: any;
repoAccountId?: any;
uid?: any;
buyerName?: any;
buyerPhone?: any;
unitPrice?: any;
wareNum: number;
shouldPay: number;
actualPay: number;
orderType?: any;
deposit?: any;
rentPrice?: any;
startDate?: any;
endDate?: any;
payDay?: any;
tranStatus: string;
exWare?: any;
remark?: any;
pfRemark?: any;
shutReason?: any;
payNo?: any;
payTime?: any;
sendWareTime?: any;
receipt: Receipt;
orderRefund?: any;
express?: any;
refundExpress?: any;
vcus?: any;
returnTime?: any;
couponId?: any;
specsId?: any;
balance?: any;
doing?: any;
waiting?: any;
leaseOrderStatus?: any;
nickName?: any;
wareDescription?: any;
}
interface Receipt {
id: number;
receiptMethod: number;
takeName: string;
takePhone: string;
region: string;
detailAddress: string;
repoName?: any;
repoAddress?: any;
bookPhone?: any;
sendExCode?: any;
sendExNo?: any;
sendAddress?: any;
renMethod?: any;
renPhone?: any;
renName?: any;
renExCode?: any;
renExNo?: any;
renAddress?: any;
renRepoName?: any;
renRepoAddr?: any;
renRepoPhone?: any;
}
export interface ListTranStatusResp {
status: string;
doing: string;
waiting: string;
leaseOrderStatus: string;
}
export default {
//订单分页列表
listPageWechatOrder(params: ListPageWechatOrderParams, options?: any): Promise<Response<ListPageWechatOrderResp>> {
return request('/oms/RentalOrders/listPageWechatOrder', 'post', params, options)
},
//订单状态-字典
listTranStatus(): Promise<Response<ListTranStatusResp[]>> {
return request('/oms/RentalOrders/listTranStatus', 'get');
}
}
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论