提交 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 {
......
import CategoryItem from "./compoents/categoryItem";
import Category from "./compoents/category";
import { FilterOptionResp, RegionResp } from "./api";
import ResultItem from "./compoents/resultItem";
import RegionItem from "./compoents/regionItem";
import styles from "./index.module.scss";
import React, { useEffect, useState, forwardRef, useImperativeHandle, Ref } from "react";
import { useRouter } from "next/router";
import BrandItem from "./compoents/brandItem";
import ModelItem from "./compoents/modelItem";
import PartItem from "./compoents/partItem";
import QualityItem from "./compoents/qualityItem";
import Industry from "./compoents/industry";
import AppType from "./compoents/appType";
import DeviceBrand from "./compoents/deviceBrand";
import DeviceModel from "./compoents/deviceModel";
import CategoryItem from './compoents/categoryItem'
import Category from './compoents/category'
import { FilterOptionResp, RegionResp } from './api'
import ResultItem from './compoents/resultItem'
import RegionItem from './compoents/regionItem'
import styles from './index.module.scss'
import React, {
useEffect,
useState,
forwardRef,
useImperativeHandle,
Ref,
} from 'react'
import { useRouter } from 'next/router'
import BrandItem from './compoents/brandItem'
import ModelItem from './compoents/modelItem'
import PartItem from './compoents/partItem'
import QualityItem from './compoents/qualityItem'
import Industry from './compoents/industry'
import AppType from './compoents/appType'
import DeviceBrand from './compoents/deviceBrand'
import DeviceModel from './compoents/deviceModel'
import TypeInfo from './compoents/typeInfo'
import api, { TypesResp, InfoList } from './api'
export type AdapterResult = {
brandId?: number;
districtId?: number;
modelId?: number;
partsId?: number;
productCategoryId?: number;
qualityId?: number;
industryId?: number;
appTypeId?: number;
categoryId?: number;
};
// brandId?: number
// districtId?: number
// modelId?: number
// partsId?: number
// productCategoryId?: number
// qualityId?: number
// industryId?: number
// appTypeId?: number
categoryId?: any[]
provinceId?: number
}
export type FilterResult = {
region?: RegionResp;
brand?: FilterOptionResp;
category?: FilterOptionResp;
part?: FilterOptionResp;
model?: FilterOptionResp;
quality?: FilterOptionResp;
industryId?: FilterOptionResp;
appTypeId?: FilterOptionResp;
categoryId?: FilterOptionResp;
};
// region?: RegionResp
// brand?: FilterOptionResp
// category?: FilterOptionResp
// part?: FilterOptionResp
// model?: FilterOptionResp
// quality?: FilterOptionResp
// industryId?: FilterOptionResp
// appTypeId?: FilterOptionResp
categoryId?: InfoList[]
provinceId?: FilterOptionResp
}
type itemType =
| "类目"
| "地域"
| "品牌"
| "部件"
| "型号"
| "成色"
| "行业"
| "应用"
| "设备品牌"
| "设备型号"
| "设备类目";
| '类目'
| '地域'
| '品牌'
| '部件'
| '型号'
| '成色'
| '行业'
| '应用'
| '设备品牌'
| '设备型号'
| '设备类目'
type Props = {
types: itemType[]; //需要包含的筛选条件项
showResultItem: Boolean; //显示结果栏
types: itemType[] //需要包含的筛选条件项
showResultItem: Boolean //显示结果栏
onChange: (
filterResult: FilterResult,
adapterFilterResult: AdapterResult //适配器,直接用于接口请求
) => void; //筛选条件更改事件
};
) => void //筛选条件更改事件
}
const idArr = [
"brandId",
"categoryId",
"modelId",
"partsId",
"productCategoryId",
"qualityId",
"industryId",
"appTypeId",
];
const nameArr: any = {
brandId: {
type: "brandId",
typeObj: "brand",
typeName: "品牌:",
},
// districtId: {
// type:"districtId",
// typeObj:"region",
// typeName:"地域:",
// },
modelId: {
type: "modelId",
typeObj: "model",
typeName: "型号:",
},
partsId: {
type: "partsId",
typeObj: "part",
typeName: "部件:",
},
productCategoryId: {
type: "productCategoryId",
typeObj: "category",
typeName: "类目:",
},
qualityId: {
type: "qualityId",
typeObj: "quality",
typeName: "成色:",
},
industryId: {
type: "industryId",
typeObj: "industryId",
typeName: "行业:",
},
appTypeId: {
type: "appTypeId",
typeObj: "appTypeId",
typeName: "应用:",
},
categoryId: {
type: "categoryId",
typeObj: "categoryId",
typeName: "类目:",
},
};
// const idArr = [
// 'brandId',
// 'categoryId',
// 'modelId',
// 'partsId',
// 'productCategoryId',
// 'qualityId',
// 'industryId',
// 'appTypeId',
// ]
// const nameArr: any = {
// brandId: {
// type: 'brandId',
// typeObj: 'brand',
// typeName: '品牌:',
// },
// // districtId: {
// // type:"districtId",
// // typeObj:"region",
// // typeName:"地域:",
// // },
// modelId: {
// type: 'modelId',
// typeObj: 'model',
// typeName: '型号:',
// },
// partsId: {
// type: 'partsId',
// typeObj: 'part',
// typeName: '部件:',
// },
// productCategoryId: {
// type: 'productCategoryId',
// typeObj: 'category',
// typeName: '类目:',
// },
// qualityId: {
// type: 'qualityId',
// typeObj: 'quality',
// typeName: '成色:',
// },
// industryId: {
// type: 'industryId',
// typeObj: 'industryId',
// typeName: '行业:',
// },
// appTypeId: {
// type: 'appTypeId',
// typeObj: 'appTypeId',
// typeName: '应用:',
// },
// categoryId: {
// type: 'categoryId',
// typeObj: 'categoryId',
// typeName: '类目:',
// },
// }
const Filter = (props: Props, ref: Ref<any>) => {
const router = useRouter();
const router = useRouter()
useImperativeHandle(ref, () => ({
idArr: idArr,
clearRouter: clearRouter,
}));
const [result, setResult] = useState<FilterResult>({});
}))
const [result, setResult] = useState<FilterResult>({})
const onChange = (item: FilterOptionResp, type: string) => {
clearRouter();
let data: { [key: string]: FilterOptionResp } = {};
data[type] = item;
setResult({ ...result, ...data });
};
clearRouter()
let data: { [key: string]: FilterOptionResp[] | FilterOptionResp } = {}
if (type === 'categoryId') {
if (result.categoryId) {
data[type] = [...result.categoryId, item]
const map = new Map()
//去重
data[type] = (data[type] as InfoList[]).filter(
(v) => !map.has(v.id) && map.set(v.id, 1)
)
} else {
data[type] = [item]
}
} else {
data[type] = item
}
setResult({ ...result, ...data })
}
useEffect(() => {
props.onChange(result, {
brandId: result.brand?.id,
districtId: result.region?.id,
modelId: result.model?.id,
partsId: result.part?.id,
productCategoryId: result.category?.id,
qualityId: result.quality?.id,
industryId: result.industryId?.id,
appTypeId: result.appTypeId?.id,
categoryId: result.categoryId?.id,
});
}, [result]);
// brandId: result.brand?.id,
// districtId: result.region?.id,
// modelId: result.model?.id,
// partsId: result.part?.id,
// productCategoryId: result.category?.id,
// qualityId: result.quality?.id,
// industryId: result.industryId?.id,
// appTypeId: result.appTypeId?.id,
categoryId: result.categoryId,
provinceId: result.provinceId?.id,
})
}, [result])
useEffect(() => {
let queryVal = JSON.parse(JSON.stringify(router.query));
const clearRouter = () => {
if (Object.keys(router.query).length) {
for (const key in queryVal) {
if (idArr.includes(key)) {
onChange(
{ id: queryVal[key], name: nameArr[key].typeName + queryVal.name },
nameArr[key].typeObj
);
}
}
router.query = {}
router.replace(router.pathname)
}
}, [router]);
}
const onDel = (key: string | number) => {
clearRouter()
console.log(key)
const clearRouter = () => {
if (Object.keys(router.query).length) {
router.query = {};
router.replace(router.pathname);
if (Object.prototype.toString.call(key) === '[object String]') {
//@ts-ignore
delete result[key]
} else {
if (result.categoryId?.length! === 1) {
result.categoryId = undefined
} else if (result.categoryId?.length! >= 2) {
result.categoryId?.map((item, index) => {
if (item.id === key) {
result.categoryId?.splice(index, 1)
}
})
}
}
};
const onDel = (key: string) => {
clearRouter();
//@ts-ignore
delete result[key];
setResult({
...result,
});
};
})
}
const routerList = [
'/jobServices',
'/equipmentLeasing',
'/flyingHandService',
'/mall',
]
const [typeInfo, setTypeInfo] = useState<Array<TypesResp> | null>()
useEffect(() => {
if (routerList.indexOf(router.pathname) > -1) {
;(async () => {
const res = await api.infoByType({
type: routerList.indexOf(router.pathname) + 1,
})
setTypeInfo(res.result)
//首页跳转自定筛选选中
let queryVal = JSON.parse(JSON.stringify(router.query))
if (Object.keys(router.query).length) {
//获取类型的id
const idOfType = res.result
?.map((item) => item.categoriesInfoListDTO)
.flat()
.filter(
(item) => item && item.id === Number(queryVal['categoryId'])
)[0]?.directoryId
//获取类型的名称然后拼接
const TypeName = res.result?.filter(
(item) => item.directoryId === idOfType
)[0]?.name
onChange(
{
id: Number(queryVal['categoryId']),
name: `${
TypeName ? TypeName + ':' + queryVal.name : queryVal.name
}`,
},
'categoryId'
)
}
})()
}
}, [router])
return (
<>
{props.types.includes("地域") && (
{props.types.includes('地域') && (
<div
className={styles.filterWrap}
style={{
......@@ -187,68 +252,79 @@ const Filter = (props: Props, ref: Ref<any>) => {
}}
>
<RegionItem
onChange={(item: FilterOptionResp) => onChange(item, "region")}
onChange={(item: FilterOptionResp) => onChange(item, 'provinceId')}
></RegionItem>
</div>
)}
<div className={styles.filterWrap}>
{props.types.includes("品牌") && (
{/* {props.types.includes('品牌') && (
<BrandItem
onChange={(item: FilterOptionResp) => onChange(item, "brand")}
onChange={(item: FilterOptionResp) => onChange(item, 'brand')}
></BrandItem>
)}
{props.types.includes("设备品牌") && (
{props.types.includes('设备品牌') && (
<DeviceBrand
onChange={(item: FilterOptionResp) => onChange(item, "brand")}
onChange={(item: FilterOptionResp) => onChange(item, 'brand')}
></DeviceBrand>
)}
{props.types.includes("类目") && (
{props.types.includes('类目') && (
<CategoryItem
onChange={(item: FilterOptionResp) => onChange(item, "category")}
onChange={(item: FilterOptionResp) => onChange(item, 'category')}
></CategoryItem>
)}
{props.types.includes("设备类目") && (
{props.types.includes('设备类目') && (
<Category
onChange={(item: FilterOptionResp) => onChange(item, "categoryId")}
onChange={(item: FilterOptionResp) => onChange(item, 'categoryId')}
></Category>
)}
{props.types.includes("部件") && (
{props.types.includes('部件') && (
<PartItem
onChange={(item: FilterOptionResp) => onChange(item, "part")}
onChange={(item: FilterOptionResp) => onChange(item, 'part')}
></PartItem>
)}
{props.types.includes("型号") && (
{props.types.includes('型号') && (
<ModelItem
onChange={(item: FilterOptionResp) => onChange(item, "model")}
onChange={(item: FilterOptionResp) => onChange(item, 'model')}
></ModelItem>
)}
{props.types.includes("设备型号") && (
{props.types.includes('设备型号') && (
<DeviceModel
onChange={(item: FilterOptionResp) => onChange(item, "model")}
onChange={(item: FilterOptionResp) => onChange(item, 'model')}
></DeviceModel>
)}
{props.types.includes("成色") && (
{props.types.includes('成色') && (
<QualityItem
onChange={(item: FilterOptionResp) => onChange(item, "quality")}
onChange={(item: FilterOptionResp) => onChange(item, 'quality')}
></QualityItem>
)}
{props.types.includes("行业") && (
{props.types.includes('行业') && (
<Industry
onChange={(item: FilterOptionResp) => onChange(item, "industryId")}
onChange={(item: FilterOptionResp) => onChange(item, 'industryId')}
></Industry>
)}
{props.types.includes("应用") && (
{props.types.includes('应用') && (
<AppType
onChange={(item: FilterOptionResp) => onChange(item, "appTypeId")}
onChange={(item: FilterOptionResp) => onChange(item, 'appTypeId')}
></AppType>
)}
)} */}
{typeInfo?.length &&
typeInfo?.map((item) => (
<TypeInfo
key={item.directoryId}
typeName={item.name}
dataValue={item.categoriesInfoListDTO}
onChange={(item: FilterOptionResp) =>
onChange(item, 'categoryId')
}
></TypeInfo>
))}
{props.showResultItem && (
<ResultItem data={result} onDel={onDel}></ResultItem>
)}
</div>
</>
);
};
)
}
export default forwardRef(Filter);
export default forwardRef(Filter)
......@@ -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 React, { useEffect , useState , useContext } from 'react'
import {useRouter} from 'next/router';
import Layout from "~/components/layout";
import {Box} from './styled';
import ImagePreview from './components/picture-preview';
import { Button , Image as AImage , Divider , Select,Modal ,Tag,Space,Form,message} from 'antd';
import Image from 'next/image';
import errImg from "~/assets/errImg";
import api,{GetWebDeviceDetailResult,GetWebDeviceWareSkuById} from './api';
import { UserContext } from "~/lib/userProvider";
import React, { useEffect, useState, useContext } from 'react'
import { useRouter } from 'next/router'
import Layout from '~/components/layout'
import { Box } from './styled'
import ImagePreview from './components/picture-preview'
import OrderForGoods from './components/orderForGoods'
import moment from 'moment'
import {
Button,
Image as AImage,
Divider,
Select,
Modal,
Tag,
Space,
Form,
message,
InputNumber,
DatePicker,
} from 'antd'
import Image from 'next/image'
import errImg from '~/assets/errImg'
import api, {
GetWebDeviceDetailResult,
GetWebDeviceWareSkuById,
GetLeaseGoodsResult,
} from './api'
import { UserContext } from '~/lib/userProvider'
import flowPat from './assets/flow-path.png'
import { RangePickerProps } from 'antd/es/date-picker'
const { RangePicker } = DatePicker
const { CheckableTag } = Tag
export interface ShopDetail {
dateDetail: Array<Date>
num: number
id: number
}
export default function EquipmentLeasingDetail() {
const router = useRouter();
const { userInfo, setNeedLogin } = useContext(UserContext);
const [id, setId] = useState<number | null>(null);
const [detail,setDetail] = useState<GetWebDeviceDetailResult | null>()
const [wareSkuList,setWareSkuList] = useState<GetWebDeviceWareSkuById[] | undefined>()
const router = useRouter()
const { userInfo, setNeedLogin } = useContext(UserContext)
const [id, setId] = useState<number | null>(null)
useEffect(()=>{
const [detail, setDetail] = useState<GetWebDeviceDetailResult | null>()
const [wareSkuList, setWareSkuList] = useState<
GetWebDeviceWareSkuById[] | undefined
>()
useEffect(() => {
setId(Number(router.query.id))
},[router])
}, [router])
useEffect(()=>{
useEffect(() => {
if (id) {
api
.listDetailDeviceInfo({
id:id
goodsId: id,
type: 1,
})
.then((res) => {
setDetail(res.result || null);
});
api
.listWareSkuById({
id:id
setDetail(res.result || null)
const wareList = res.result?.goodsSpec.map(
(item) => item.productSpecList
)
if (wareList) {
const List: GetWebDeviceWareSkuById[] = wareList.flat()
setWareSkuList(List)
}
})
.then((res) => {
res.result?.map(item=>{
return item
})
setWareSkuList(res.result || undefined);
});
}
},[id])
}, [id])
//租赁弹框
const [isModalOpen, setIsModalOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
const tagsData = ['3-7天', '8-15天', '16-30天', '30天以上'];
const [selectedTags, setSelectedTags] = useState<number>();
const [selectedTagsData, setSelectedTagsData] = useState<string>();
const [visible, setVisible] = useState(false)
const [isModalOpen, setIsModalOpen] = useState(false)
const [isModalDateOpen, setIsModalDateOpen] = useState(false)
const [loading, setLoading] = useState(false)
const [isorderForGoods, setIsorderForGoods] = useState(false)
const [form] = Form.useForm()
const [formDate] = Form.useForm()
const tagsData = [
{ id: 0, label: '1-7天', disable: false },
{ id: 1, label: '8-15天', disable: false },
{ id: 2, label: '16-30天', disable: false },
{ id: 3, label: '30天以上', disable: false },
]
const [discount, setDiscount] = useState<GetLeaseGoodsResult | null>()
const [selectedTags, setSelectedTags] = useState<number>()
const [selectedTagsData, setSelectedTagsData] = useState<number>()
const [shopDetail, setShopDetail] = useState<ShopDetail>()
const showModal = () => {
if (userInfo) {
setIsModalOpen(true);
setIsModalOpen(true)
if (wareSkuList?.length) {
setSelectedTags(wareSkuList[0].id);
form.setFieldValue("id",wareSkuList[0].id)
setSelectedTagsData("3-7天")
form.setFieldValue("date","3-7天")
setSelectedTags(wareSkuList[0].id)
form.setFieldValue('id', wareSkuList[0].id)
setSelectedTagsData(0)
form.setFieldValue('date', 0)
getPrice(0)
}
}else{
} else {
setNeedLogin(true)
}
};
}
const handleOk = () => {
setLoading(true);
setLoading(true)
form
.validateFields()
.then(async (values) => {
form.resetFields()
message.success("租赁成功")
setLoading(false);
setIsModalOpen(false);
// try{
// const res = await api.listWareSkuUpdate(values)
// if (res.code === "200") {
// setLoading(false);
// setIsModalOpen(false);
// form.resetFields()
// message.success('租赁成功')
// }else{
// setLoading(false);
// message.error(res.message)
// }
// }catch(e:any){
// message.error(e.message)
// }
}).catch((err) => {
message
.warning({
content: err.errorFields[0].errors[0],
})
.then();
setLoading(false);
});
};
.validateFields()
.then(async (values) => {
setLoading(false)
setIsModalOpen(false)
setIsModalDateOpen(true)
})
.catch((err) => {
message
.warning({
content: err.errorFields[0].errors[0],
})
.then()
setLoading(false)
})
}
const [days, setDays] = useState<number>()
const handleOkDate = async () => {
setLoading(true)
try {
const result = await Promise.all([
form.validateFields(),
formDate.validateFields(),
])
if (result) {
setLoading(false)
setIsModalOpen(false)
setIsModalDateOpen(false)
setIsorderForGoods(true)
setShopDetail({ ...result[0], ...result[1] })
}
} catch (error) {
setLoading(false)
}
}
const handleCancel = () => {
setIsModalOpen(false);
};
const handleChange = (tag: number, checked: boolean) => {
if (checked) {
const nextWareSkuList = checked
? tag
: wareSkuList?.filter((t) => t.id !== tag)[0].id;
console.log('You are interested in: ', nextWareSkuList);
setSelectedTags(nextWareSkuList);
form.setFieldValue("id",tag)
}
};
setIsModalOpen(false)
setIsModalDateOpen(false)
form.resetFields()
formDate.resetFields()
}
const handleChangeDate = (tag: string, checked: boolean) => {
const handleChange = (tag: number, checked: boolean) => {
if (checked) {
const nextWareSkuList = checked
? tag
: wareSkuList?.filter((t) => t.id !== tag)[0].id
setSelectedTags(nextWareSkuList)
form.setFieldValue('id', tag)
}
}
const handleChangeDate = (
tag: number,
checked: boolean,
disable: boolean
) => {
if (checked && !disable) {
const nextSelectedTags = checked
? tag
: tagsData.filter((t) => t !== tag)[0];
console.log('You are interested in: ', nextSelectedTags);
setSelectedTagsData(nextSelectedTags);
form.setFieldValue("date",tag)
? tag
: tagsData.filter((t) => t.id !== tag)[0].id
setSelectedTagsData(nextSelectedTags)
form.setFieldValue('date', tag)
getPrice(tag)
}
}
const getPrice = (tag: number) => {
const Id = wareSkuList?.filter(
(item) => item.id === form.getFieldValue('id')
)[0].productSpec
if (Id) {
api
.GoodsPriceDetail({ leaseTerm: tag, productSpecId: Id })
.then((res) => {
setDiscount(res.result)
})
}
}
const onChangeNum = (value: number | string | null) => {
console.log('changed', value)
}
const goBack = () => {
setIsModalDateOpen(false)
setIsModalOpen(true)
}
const onchanges = (values: any) => {
if (values) {
const day = new Date(values[1]).getTime() - new Date(values[0]).getTime()
const totalDays = Math.floor(day / (1000 * 3600 * 24))
setDays(totalDays)
} else {
setDays(undefined)
}
};
}
const disabledDate: RangePickerProps['disabledDate'] = (current) => {
return current && current < moment().endOf('day')
}
return (
<Layout>
<Box>
<div className='item'>
<ImagePreview imgList={detail?.wareImgs!}/>
<div className='item-right'>
<div className='title'>{detail?.wareTitle}</div>
{
detail?.tags?.length ?
(<div className='function'>
{detail?.tags?.map(item=>(<div key={item} className='function-item'>{item}</div>))}
</div>) : (<div className='function not'></div>)
}
<div className='menoy'>
<span className='menoy-left'>{`¥${detail?.minRent}`}</span>
<span className='menoy-right'>/天起</span>
</div>
<div className='classification'>
<div className='top'>
<div className='left'>
<span className='label'>选择</span>
<span className='value'>商品分类</span>
{!isorderForGoods ? (
<Box>
<div className="item">
<ImagePreview imgList={detail?.images!} />
<div className="item-right">
<div className="title">{detail?.goodsName}</div>
{detail?.otherService?.length ? (
<div className="function">
{detail?.otherService?.map((item) => (
<div key={item.id} className="function-item">
{item.serviceName}
</div>
))}
</div>
) : (
<div className="function not"></div>
)}
{userInfo?.cooperationTagId ? (
<div className="menoy">
<span className="menoy-left">{`¥${detail?.price! | 0}`}</span>
<span className="menoy-right">/天起</span>
</div>
) : (
<div className="menoy">暂无报价</div>
)}
<div className="classification">
<div className="top">
<div className="left">
<span className="label">选择</span>
<span className="value">商品分类</span>
</div>
<div className="right">
<Select
className="selectItem"
defaultActiveFirstOption
defaultValue={wareSkuList}
style={{ width: 120 }}
bordered={false}
options={wareSkuList}
fieldNames={{ label: 'specName', value: 'id' }}
placeholder="选择商品"
/>
</div>
</div>
<div className='right'>
<Select
className="selectItem"
defaultActiveFirstOption
defaultValue={wareSkuList}
style={{ width: 120 }}
bordered={false}
options={wareSkuList}
fieldNames={{label:"skuTitle",value:"id"}}
placeholder="选择商品"
/>
<div className="bottom">
<span className="label">发货</span>
<span className="value">顺丰到付</span>
</div>
</div>
<div className='bottom'>
<span className='label'>发货</span>
<span className='value'>顺丰到付</span>
<div className="botton-btn">
{/* <Button className='btn-left' size='small' type="primary">成为渠道商</Button> */}
<Button
className="btn-right"
size="small"
type="primary"
onClick={showModal}
>
立即租赁
</Button>
</div>
</div>
<div className='botton-btn'>
{/* <Button className='btn-left' size='small' type="primary">成为渠道商</Button> */}
<Button className='btn-right' size='small' type="primary" onClick={showModal}>立即租赁</Button>
</div>
</div>
</div>
<div className='flow-path'>
<Image className='image' fill src={flowPat.src} alt="" />
</div>
<div className='prompt'>
更多租金规则请前往【云享飞】微信小程序查
</div>
<Divider className='divider'>商品详情</Divider>
{
detail?.wareDetailContent ? <div style={{ textAlign: "center" }} dangerouslySetInnerHTML={{ __html: detail?.wareDetailContent}}>
</div> : <div style={{ textAlign: "center" }} ></div>
}
{/* 立即租赁 */}
<Modal
wrapClassName='application'
open={isModalOpen}
onOk={handleOk}
onCancel={handleCancel}
getContainer={false}
footer={[
<Button
style={{ width: "100%" ,height: 44 }}
key="submit"
type="primary"
loading={loading}
onClick={handleOk}
>
立即租赁
</Button>,
]}
>
<div className='title'>
<div className="left"></div>
<div className="right">
<div className="top">
<span className='tag'>¥</span>
<span className='money'>{detail?.minRent}</span>
<span className='unit'>/天</span>
</div>
<div className="bottom">渠道免押金</div>
<div className="flow-path">
<Image className="image" fill src={flowPat.src} alt="" />
</div>
</div>
<Form
form={form}
layout="vertical"
name="application"
initialValues={{ modifier: 'public' }}
>
<Form.Item style={{flex:1,marginRight:16}} name="id" label="选择商品">
<Space size={[0, 8]} wrap>
{wareSkuList?.map((tag) => (
<CheckableTag
style={{height:28,lineHeight:"28px"}}
key={tag.id}
checked={wareSkuList?.some(item=>tag.id === selectedTags)}
onChange={(checked) => handleChange(tag.id, checked)}
>
{tag.skuTitle}
</CheckableTag>
))}
</Space>
</Form.Item>
<Form.Item style={{flex:1,marginRight:16}} name="date" label="租期天数(拿到和归还当天不算入租期)">
<Space size={[0, 8]} wrap>
{tagsData.map((tag) => (
<CheckableTag
key={tag}
checked={tag === selectedTagsData}
onChange={(checked) => handleChangeDate(tag, checked)}
<div className="prompt">更多租金规则请前往【云享飞】微信小程序查</div>
<Divider className="divider">商品详情</Divider>
{detail?.goodsDetail.content ? (
<div
style={{ textAlign: 'center' }}
dangerouslySetInnerHTML={{ __html: detail?.goodsDetail.content }}
></div>
) : null}
{/* 立即租赁 */}
<Modal
wrapClassName="application"
open={isModalOpen}
onOk={handleOk}
onCancel={handleCancel}
getContainer={false}
maskClosable={false}
footer={[
<Button
style={{ width: '100%', height: 44 }}
key="submit"
type="primary"
loading={loading}
onClick={handleOk}
>
立即租赁
</Button>,
]}
>
{tag}
</CheckableTag>
))}
</Space>
</Form.Item>
</Form>
</Modal>
</Box>
<div className="title">
<div className="left">
<AImage
preview={{ visible: false }}
src={detail?.images[0].imgUrl}
onClick={() => setVisible(true)}
/>
<div style={{ display: 'none' }}>
<AImage.PreviewGroup
preview={{
visible,
onVisibleChange: (vis) => setVisible(vis),
}}
>
{detail?.images.map((item) => (
<AImage key={item.id} src={item.imgUrl} />
))}
</AImage.PreviewGroup>
</div>
</div>
<div className="right">
<div className="top">
<span className="tag">¥</span>
<span className="money">
{discount?.specPrice[0]?.price || 0}
</span>
<span className="unit">/天</span>
</div>
<div className="bottom">渠道免押金</div>
</div>
</div>
<Form
form={form}
layout="vertical"
name="application"
initialValues={{ num: 1 }}
className="form-data"
>
<Form.Item
style={{ flex: 1, marginRight: 16 }}
name="id"
label="选择商品"
>
<Space size={[0, 8]} wrap>
{wareSkuList?.map((tag) => (
<CheckableTag
style={{ height: 28, lineHeight: '28px' }}
key={tag.id}
checked={wareSkuList?.some(
(item) => tag.id === selectedTags
)}
onChange={(checked) => handleChange(tag.id, checked)}
>
{tag.specName}
</CheckableTag>
))}
</Space>
</Form.Item>
<Form.Item
style={{ flex: 1, marginRight: 16 }}
name="date"
label="租期天数(拿到和归还当天不算入租期)"
>
<Space size={[0, 8]} wrap>
{tagsData.map((tag) => (
<CheckableTag
key={tag.id}
checked={tag.id === selectedTagsData}
onChange={(checked) =>
handleChangeDate(tag.id, checked, tag.disable)
}
className={`tagsData ${
tag.disable ? 'disable tagsDisable' : ''
}`}
>
{tag.label}
</CheckableTag>
))}
</Space>
</Form.Item>
<div className="num-box">
<div className="num-left">
<div className="label">租赁数量</div>
</div>
<div className="num-right">
<Form.Item style={{ flex: 1, marginRight: 16 }} name="num">
<InputNumber min={1} max={100} onChange={onChangeNum} />
</Form.Item>
</div>
</div>
</Form>
</Modal>
<Modal
wrapClassName="applicationDate"
open={isModalDateOpen}
onOk={handleOkDate}
onCancel={handleCancel}
getContainer={false}
maskClosable={false}
width={420}
footer={[
<Button
style={{ width: '100%', height: 44 }}
key="submit"
type="primary"
loading={loading}
onClick={handleOkDate}
>
确认租期{days ? `${days}天` : null}
</Button>,
]}
>
<div className="title">
<div className="left" onClick={goBack}>
{'<'}
</div>
<div className="right">选择租期</div>
</div>
<Form
form={formDate}
layout="vertical"
name="applicationDate"
initialValues={{ modifier: 'public' }}
className="form-data"
>
<Form.Item
style={{ flex: 1, marginRight: 16 }}
name="dateDetail"
rules={[{ required: true, message: '请选择日期' }]}
>
<RangePicker
style={{ width: 376, marginTop: 10 }}
disabledDate={disabledDate}
onChange={onchanges}
/>
</Form.Item>
</Form>
<div className="bottom-item">
<div className="label">租金合计</div>
<div className="price">
<div className="left">
¥
{discount?.specPrice[0]?.price! *
days! *
form.getFieldValue('num') || 0}
</div>
{/* <div className="right">(日均175)</div> */}
</div>
</div>
</Modal>
</Box>
) : (
<OrderForGoods
setIsorderForGoods={setIsorderForGoods}
shopDetail={shopDetail}
days={days}
detailData={detail}
discount={discount}
wareSkuList={wareSkuList?.filter(
(item) => item.id === form.getFieldValue('id')
)}
/>
)}
</Layout>
)
}
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 React, { useContext, useEffect, useState } from 'react'
import { OrderForGoodsBox } from './styled'
import type { FormInstance, RadioChangeEvent } from 'antd'
import { Button, Radio, Space, Input, message, Modal, Image } from 'antd'
import api, { UserAddress, GetOrderForGoods } from './api'
import moment from 'moment'
import { ShopDetail } from '../../[id].page'
import {
GetWebDeviceDetailResult,
GetWebDeviceWareSkuById,
GetLeaseGoodsResult,
} from '../../api'
import { UserContext } from '~/lib/userProvider'
const { TextArea } = Input
interface PropsBox {
setIsorderForGoods: (boolean: boolean) => void
detailData?: GetWebDeviceDetailResult | null
days?: number
shopDetail?: ShopDetail
wareSkuList?: GetWebDeviceWareSkuById[]
discount?: GetLeaseGoodsResult | null
}
export default function OrderForGoods(props: PropsBox) {
const {
setIsorderForGoods,
shopDetail,
days,
detailData,
wareSkuList,
discount,
} = props
const [value, setValue] = useState(1)
const [areaValue, setAreaValue] = useState<string>()
const [list, setList] = useState<Array<UserAddress> | null>()
const [detail, setDetail] = useState<ShopDetail>()
const onChange = (e: RadioChangeEvent) => {
console.log('radio checked', e.target.value)
setValue(e.target.value)
}
const onChangeValue = (index: number) => {
setValue(index)
}
const detailSumbit = () => {
if (detailData && shopDetail && list && wareSkuList) {
const pushList = {
actualPay:
discount?.specPrice[0]?.price! * shopDetail?.num! * days! || 0,
deposit: 0,
endDate: moment(new Date(shopDetail.dateDetail[1])).format(
'YYYY-MM-DD'
),
orderReceipt: {
detailAddress: list[value]?.takeAddress,
receiptMethod: 0,
region: list[value].takeRegion,
takeName: list[value].takeName,
takePhone: Number(list[value].takePhone),
},
rentPrice:
discount?.specPrice[0]?.price! * shopDetail?.num! * days! || 0,
returnDate: moment(
new Date(shopDetail.dateDetail[1]).getTime() + 864e5
).format('YYYY-MM-DD'),
shouldPay:
discount?.specPrice[0]?.price! * shopDetail?.num! * days! || 0,
specsId: wareSkuList[0].productSpec,
startDate: moment(new Date(shopDetail.dateDetail[0]!)).format(
'YYYY-MM-DD'
),
wareDescription: detailData.goodsName,
wareImg: detailData.images[0].imgUrl,
wareInfoId: shopDetail.id,
wareNo: detailData.goodsNo,
wareNum: shopDetail.num,
wareTitle: detailData.goodsName,
remark: areaValue,
}
api.FeignAddLease(pushList).then((res) => {
if (res.code === '200') {
message.success('提交成功')
setPaymentDetail(res.result)
setIsPaymentOpen(true)
} else {
message.error(res.message)
}
})
}
}
useEffect(() => {
api
.listUserAddress({})
.then((res) => {
console.log(res)
setList(res.result)
res.result?.map((item, index) => {
if (item.type === 0) {
setValue(index)
}
})
})
.catch((err) => {
console.log(err)
})
if (shopDetail) {
setDetail(shopDetail)
}
}, [])
//图片预览
const [visible, setVisible] = useState(false)
//付款
const { userInfo } = useContext(UserContext)
const [loading, setLoading] = useState(false)
const [isPaymentOpen, setIsPaymentOpen] = useState(false)
const [paymentDetail, setPaymentDetail] = useState<GetOrderForGoods | null>()
const handleCancel = () => {
setIsPaymentOpen(false)
}
const handleOkPayment = () => {
setLoading(true)
if (paymentDetail?.orderNo) {
api.OrderPayment({ orderNo: paymentDetail?.orderNo }).then((res) => {
if (res.code === '200') {
message.success('付款成功')
setLoading(false)
setIsorderForGoods(false)
handleCancel()
} else {
message.error(res.message)
setLoading(false)
}
})
} else {
message.error('出错了')
setLoading(false)
}
}
//扫码管理地址
const [isAddAddressOpen, setIsAddAddressOpen] = useState(false)
const [addressVisible, setAddressVisible] = useState(false)
return (
<OrderForGoodsBox>
<div className="address">
<div className="top">
<div className="left">确认收货地址</div>
<div className="right">
<Button
onClick={() => setIsAddAddressOpen(true)}
type="link"
style={{ color: '#007aff' }}
>
管理收货地址
</Button>
</div>
</div>
<div className="bottom">
{list?.length ? (
list?.map((item, index) => (
<div
key={item.id}
className={`item ${value === index ? 'active' : ''}`}
onClick={() => onChangeValue(index)}
>
<div className="left">
<div className="active">
<div className="icon"></div>
<div className="label">寄送至</div>
</div>
<Radio.Group onChange={onChange} value={value}>
<Space direction="vertical">
<Radio value={index}>{item.takeAddress}</Radio>
</Space>
</Radio.Group>
</div>
{value === index ? (
<div className="right">
<Button
onClick={() => setIsAddAddressOpen(true)}
type="link"
style={{ color: '#007aff' }}
>
修改地址
</Button>
</div>
) : null}
</div>
))
) : (
<div className="item active">
<div className="left">
<div className="active">
<div className="icon"></div>
<div className="label">
暂无地址,请打开手机端【云享飞】微信小程序,【我的】-【个人设置】-【地址管理】添加
</div>
</div>
</div>
<div className="right">
<Button
onClick={() => setIsAddAddressOpen(true)}
type="link"
style={{ color: '#007aff' }}
>
添加地址
</Button>
</div>
</div>
)}
</div>
</div>
<div className="info">
<div className="title">确认订单信息</div>
<div className="table">
<div className="table-title">
<div className="table-item" style={{ width: 290 }}>
宝贝
</div>
<div className="table-item" style={{ width: 130 }}>
单价
</div>
<div className="table-item" style={{ width: 130 }}>
数量
</div>
<div className="table-item" style={{ width: 300 }}>
租期
</div>
<div className="table-item" style={{ width: 135 }}>
合计
</div>
</div>
<div className="table-body">
<div className="body-item article" style={{ width: 290 }}>
<div className="image">
<Image
className="image-box"
preview={{ visible: false }}
src={(wareSkuList && wareSkuList![0].specImage) || ''}
onClick={() => setVisible(true)}
/>
<div style={{ display: 'none' }}>
<Image.PreviewGroup
preview={{
visible,
onVisibleChange: (vis) => setVisible(vis),
}}
>
<Image
src={(wareSkuList && wareSkuList![0].specImage) || ''}
/>
</Image.PreviewGroup>
</div>
</div>
<div className="right">
<div className="top">
{(wareSkuList && wareSkuList![0].specName) || ''}
</div>
<div className="bottom">
{(wareSkuList && wareSkuList![0].versionDesc) || ''}
</div>
</div>
</div>
<div className="body-item" style={{ width: 130 }}>
{discount?.specPrice[0]?.price || 0}
</div>
<div className="body-item" style={{ width: 130 }}>
{shopDetail?.num || 1}
</div>
<div className="body-item lease-term" style={{ width: 300 }}>
{moment(new Date(shopDetail?.dateDetail[0]!)).format(
'YYYY/MM/DD'
)}
<div className="num">{days}</div>
{moment(new Date(shopDetail?.dateDetail[1]!)).format(
'YYYY/MM/DD'
)}
</div>
<div className="body-item total-price" style={{ width: 135 }}>
{discount?.specPrice[0]?.price! * shopDetail?.num! * days! || 0}
</div>
</div>
</div>
</div>
<div className="notes">
<div className="left">
<div className="label">备注:</div>
<TextArea
value={areaValue}
onChange={(e) => setAreaValue(e.target.value)}
placeholder="请输入备注"
autoSize={{ minRows: 3, maxRows: 5 }}
style={{ width: 385, height: 72 }}
/>
</div>
<div className="right">
<div className="top">
<div className="font">
<div className="label">运费:</div>
<div className="value">邮寄到付,由客户自己承担</div>
</div>
<div className="price">0.00</div>
</div>
<div className="bottom">
<div className="font">
<div className="label">押金:</div>
<div className="value">渠道商可免押金</div>
</div>
<div className="price">0.00</div>
</div>
</div>
</div>
<div className="detail-box">
<div className="right-box">
<div className="detail">
<div className="top">
<div className="label">实付款</div>
<div className="price">
¥
{discount?.specPrice[0]?.price! * shopDetail?.num! * days! || 0}
</div>
</div>
<div className="bottom">
<div className="value">寄送至</div>
{list ? (
<div className="value-content">{list![value]?.takeAddress}</div>
) : null}
</div>
</div>
<div className="detail-sumbit">
<Button className="btn" onClick={detailSumbit}>
提交订单
</Button>
</div>
</div>
</div>
<Modal
wrapClassName="Payment"
open={isPaymentOpen}
onOk={handleOkPayment}
onCancel={handleCancel}
getContainer={false}
maskClosable={false}
width={420}
footer={[
<Button
style={{ width: '100%', height: 44 }}
key="submit"
type="primary"
loading={loading}
onClick={handleOkPayment}
>
立即付款
</Button>,
]}
>
<div className="title">
{discount?.specPrice[0]?.price! * shopDetail?.num! * days! || 0}
</div>
<div>云享飞账号: {userInfo?.uid}</div>
<div>付款方式: 可用(¥{paymentDetail?.balance})</div>
</Modal>
<Modal
wrapClassName="addAddress"
open={isAddAddressOpen}
onCancel={() => setIsAddAddressOpen(false)}
getContainer={false}
maskClosable={false}
width={420}
footer={false}
>
<div className="title">扫码管理地址</div>
<div className="image">
<Image
className="addressImg"
preview={{ visible: false }}
src={
window.location.href.includes('https://test.iuav.shop/')
? 'https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/image/app-iuav-trial.jpg'
: 'https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/image/app-iuav-formal.jpg' ||
''
}
onClick={() => setAddressVisible(true)}
/>
<div style={{ display: 'none' }}>
<Image.PreviewGroup
preview={{
visible: addressVisible,
onVisibleChange: (vis) => setAddressVisible(vis),
}}
>
<Image
src={
window.location.href.includes('https://test.iuav.shop/')
? 'https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/image/app-iuav-trial.jpg'
: 'https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/image/app-iuav-formal.jpg' ||
''
}
/>
</Image.PreviewGroup>
</div>
</div>
<div className="content">
【打开微信扫一扫】-进入云享飞【我的】- 【个人设置】-【地址管理】
</div>
</Modal>
</OrderForGoodsBox>
)
}
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 styled from "styled-components"
import styled from 'styled-components'
export const Box = styled.div`
box-sizing: border-box;
width: 1200px;
background-color: #fff;
padding: 42px 0 24px 24px;
.item{
box-sizing: border-box;
width: 1200px;
background-color: #fff;
padding: 42px 0 24px 24px;
.item {
display: flex;
&-right {
height: 300px;
margin-left: 30px;
.title {
height: 26px;
font-size: 28px;
margin-top: 5px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #090909;
line-height: 26px;
}
.function {
display: flex;
&-right{
height: 300px;
margin-left: 30px;
.title{
height: 26px;
font-size: 28px;
margin-top: 5px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #090909;
line-height: 26px;
}
.function{
display: flex;
align-items: center;
justify-content: space-evenly;
width: 375px;
height: 45px;
margin-top: 17px;
background: linear-gradient(90deg, #D7F7F5 0%, #EEFDE9 100%);
&.not{
background: none;
}
&-item{
}
}
.menoy{
margin-top: 17px;
&-left{
width: 79px;
height: 41px;
font-size: 32px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #EF2E00;
line-height: 41px;
}
&-right{
width: 40px;
height: 20px;
font-size: 16px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #EF2E00;
line-height: 20px;
}
}
.classification{
margin-top: 28px;
width: 375px;
height: 50px;
.label{
height: 21px;
font-size: 16px;
font-family: MicrosoftYaHei;
color: #9A9A9A;
line-height: 21px;
margin-right: 36px;
}
.value{
height: 21px;
font-size: 16px;
font-family: MicrosoftYaHei;
color: #151515;
line-height: 21px;
}
.top{
display: flex;
justify-content: space-between;
align-items: center;
.left{
}
.right{
.selectItem{
.ant-select-selection-placeholder {
color: #000;
}
}
}
}
.bottom{
margin-top: 5px;
}
}
.botton-btn{
margin-top: 30px;
.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;
}
align-items: center;
justify-content: space-evenly;
width: 375px;
height: 45px;
margin-top: 17px;
background: linear-gradient(90deg, #d7f7f5 0%, #eefde9 100%);
&.not {
background: none;
}
&-item {
}
}
.menoy {
margin-top: 17px;
font-size: 32px;
color: #ef2e00;
&-left {
width: 79px;
height: 41px;
font-size: 32px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ef2e00;
line-height: 41px;
}
&-right {
width: 40px;
height: 20px;
font-size: 16px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ef2e00;
line-height: 20px;
}
}
.classification {
margin-top: 28px;
width: 375px;
height: 50px;
.label {
height: 21px;
font-size: 16px;
font-family: MicrosoftYaHei;
color: #9a9a9a;
line-height: 21px;
margin-right: 36px;
}
.value {
height: 21px;
font-size: 16px;
font-family: MicrosoftYaHei;
color: #151515;
line-height: 21px;
}
.top {
display: flex;
justify-content: space-between;
align-items: center;
.left {
}
.right {
.selectItem {
.ant-select-selection-placeholder {
color: #000;
}
}
}
}
.bottom {
margin-top: 5px;
}
}
.botton-btn {
margin-top: 30px;
.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;
}
}
}
}
.flow-path{
width: 100%;
height: 192px;
text-align: center;
margin-top: 72px;
position: relative;
.image{
margin: 0 auto;
}
.flow-path {
width: 100%;
height: 192px;
text-align: center;
margin-top: 72px;
position: relative;
.image {
margin: 0 auto;
}
.prompt{
width: 420px;
height: 25px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #2B2B2B;
line-height: 25px;
margin: 30px auto 58px auto;
}
.prompt {
width: 420px;
height: 25px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #2b2b2b;
line-height: 25px;
margin: 30px auto 58px auto;
}
.divider {
display: flex;
justify-content: center;
margin: 46px 0 30px !important;
&::before {
width: 65px !important;
}
.divider {
display: flex;
justify-content: center;
margin: 46px 0 30px !important;
&::before {
width: 65px !important;
}
&::after {
width: 65px !important;
}
&::after {
width: 65px !important;
.ant-divider-inner-text {
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #989898;
}
}
.application {
.title {
display: flex;
align-items: center;
padding-bottom: 25px;
.left {
width: 58px;
height: 58px;
background: #d8d8d8;
border-radius: 2px;
}
.right {
margin-left: 15px;
.top {
.tag {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff0f0f;
}
.money {
font-size: 22px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #ff0f0f;
}
.unit {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff0f0f;
}
}
.ant-divider-inner-text {
font-size: 16px;
.bottom {
width: 65px;
height: 18px;
font-size: 13px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #121212;
line-height: 18px;
}
}
}
.form-data {
.tagsData {
position: relative;
&.disable {
cursor: no-drop;
}
&.tagsDisable::after {
content: '缺货';
position: absolute;
top: -10px;
right: -10px;
border-radius: 5px 0;
width: 37px;
height: 14px;
line-height: 14px;
text-align: center;
background-color: #ccc;
font-size: 12px;
color: rgb(248, 248, 248);
}
}
.num-box {
display: flex;
justify-content: space-between;
align-items: center;
.num-left {
display: flex;
align-items: center;
.label {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #989898;
color: #121212;
margin-right: 5px;
}
}
}
}
.application{
.title{
display: flex;
align-items: center;
padding-bottom: 25px;
.left{
width: 58px;
height: 58px;
background: #D8D8D8;
border-radius: 2px;
}
.right{
margin-left: 15px;
.top{
.tag{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FF0F0F;
}
.money{
font-size: 22px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #FF0F0F;
}
.unit{
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FF0F0F;
}
}
.bottom{
width: 65px;
height: 18px;
font-size: 13px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #121212;
line-height: 18px;
}
}
}
.applicationDate {
.title {
display: flex;
align-items: center;
.left {
width: 10px;
cursor: pointer;
}
.right {
flex: 1;
text-align: center;
}
}
.bottom-item {
display: flex;
justify-content: space-between;
align-items: center;
height: 50px;
line-height: 50px;
border-bottom: 1px solid #d9d9d9;
.label {
font-size: 14px;
font-family: ArialMT;
color: #2f2f2f;
}
.price {
display: flex;
.left {
font-size: 14px;
font-family: Arial-BoldMT, Arial;
font-weight: normal;
color: #ff552d;
margin-right: 4px;
}
.right {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
color: #959595;
}
}
}
`
\ No newline at end of file
}
`
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;
}
}
}
}
`;
`
import React, { useEffect, useState , useContext} from "react";
import { Box } from "./styled";
import Image from "next/image";
import { Button, Select, Space, Pagination, Cascader, Modal , Form ,Input,Checkbox, message} from "antd";
import type { CheckboxValueType } from 'antd/es/checkbox/Group';
import Layout from "~/components/layout";
import ContentBox from "~/components/contentBox";
import api, { Flying, SkillsType, RegionResp } from "./api";
import { useRouter } from "next/router";
import { UserContext } from "~/lib/userProvider";
import {phoneNumber} from '~/lib/validateUtils'
import {
Button,
Cascader,
Checkbox,
Form,
Input,
Modal,
Pagination,
Select,
Space,
message,
} from 'antd'
import type { CheckboxValueType } from 'antd/es/checkbox/Group'
import Image from 'next/image'
import { useRouter } from 'next/router'
import { useContext, useEffect, useState } from 'react'
import ContentBox from '~/components/contentBox'
import Layout from '~/components/layout'
import { UserContext } from '~/lib/userProvider'
import { phoneNumber } from '~/lib/validateUtils'
import api, { Flying, RegionResp, SkillsType } from './api'
import { Box } from './styled'
import { TypesResp } from '~/components/filter/api'
interface FilterInfoParams {
regionId?: number;
flightSkillsId?: number;
licenseId?: number;
provinceId?: number
categoryId?: any[]
}
export default function FlyingHandService() {
const {Option} = Select
const router = useRouter();
const { userInfo, setNeedLogin } = useContext(UserContext);
const { Option } = Select
const router = useRouter()
const { userInfo, setNeedLogin } = useContext(UserContext)
const [list, setList] = useState([
"https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/540X844-1(1).jpg",
"https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/540X844(1).jpg",
]);
'https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/540X844-1(1).jpg',
'https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/540X844(1).jpg',
])
const [productList, setProductList] = useState(
Array<{ element: JSX.Element }>
);
)
const [rightDomList, setRightDomList] = useState(
Array<{ element: JSX.Element }>
);
)
const [secondDistrictInfo, setSecondDistrictInfo] = useState(
Array<RegionResp>
);
const [skills, setSkills] = useState(
Array<RegionResp>
);
const [skillsDefault, setSkillsDefault] = useState<Array<number>>();
const [flightSkillsList, setFlightSkillsList] = useState(Array<SkillsType>);
const [flightDefault, setFlightDefault] = useState<number | null>();
)
const [skills, setSkills] = useState(Array<RegionResp>)
const [skillsDefault, setSkillsDefault] = useState<Array<number>>()
const [flightSkillsList, setFlightSkillsList] = useState<Array<SkillsType>>()
const [flightDefault, setFlightDefault] = useState<number | null>()
const [selectOption, setSelectOption] = useState<Array<TypesResp> | null>()
const [selectDefault, setSelectDefault] = useState<number | null>()
const leftDom = (item: Flying) => {
return (
<div
className="item"
key={item.id}
onClick={() => {
userInfo ? router.push({
pathname: `/flyingHandService/detail/${item.id}`,
query: {
videoUrl: item.videoUrl ,
curriculumName: item.curriculumName
},
}) : setNeedLogin(true)
} }
userInfo
? router.push({
pathname: `/flyingHandService/detail/${item.id}`,
})
: setNeedLogin(true)
}}
>
<div className="item-top">
<Image
src={`${item.videoUrl}?x-oss-process=video/snapshot,t_1000,m_fast`}
src={
item.videoUrl
? `${item.videoUrl}?x-oss-process=video/snapshot,t_1000,m_fast`
: item.surfaceUrl
}
alt="#"
fill
/>
......@@ -72,7 +85,7 @@ export default function FlyingHandService() {
<div className="price-right-label">{item.price}</div>
) : (
<div>
<span className="price-right-label">限免</span>
<span className="price-right-label">免费听课</span>
{/* <span className='price-right-money'>{`¥${item.price}`}</span> */}
</div>
)}
......@@ -80,47 +93,47 @@ export default function FlyingHandService() {
</div>
</div>
</div>
);
};
)
}
const rightDom = (item: string) => {
return (
<div className="right-box-item right-item" key={item}>
<Image src={item} alt="error" fill />
</div>
);
};
)
}
const [pageParams, setPageParams] = useState({
pageNo: 1,
pageSize: 12,
}); //分页器对象
}) //分页器对象
const [filterParams, setFilterParams] = useState<FilterInfoParams>();
const [filterParams, setFilterParams] = useState<FilterInfoParams>()
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());
}, [filterParams, pageParams]);
abort?.abort()
setAbort(new AbortController())
}, [filterParams, pageParams])
//端口列表请求
useEffect(() => {
console.log(router);
let queryVal = JSON.parse(JSON.stringify(router.query));
console.log(router)
let queryVal = JSON.parse(JSON.stringify(router.query))
for (const key in queryVal) {
queryVal[key] = Number(queryVal[key]);
queryVal[key] = Number(queryVal[key])
}
api
.listPageJobServicesInfo({
......@@ -131,13 +144,13 @@ export default function FlyingHandService() {
.then((res) => {
setProductList(
res.result?.list?.map((item) => {
return { element: leftDom(item) };
return { element: leftDom(item) }
}) || []
);
setCount(res.result?.totalCount || 0);
)
setCount(res.result?.totalCount || 0)
clearRouter()
});
}, [abort]);
})
}, [abort])
const clearRouter = () => {
if (Object.keys(router.query).length) {
......@@ -146,138 +159,172 @@ export default function FlyingHandService() {
}
}
const onProvinceChange = (value: number) => {
const onSelectChange = (value: number, item: TypesResp) => {
clearRouter()
console.log(value)
if (value) {
setFlightDefault(value)
}else{
setFlightDefault(null)
setSelectDefault(value)
} else {
setSelectDefault(undefined)
}
setFilterParams((props) => {
setFilterParams((props) => {
if (props?.categoryId && value) {
return {
...props,
licenseId: Number(value),
};
});
};
categoryId: [...props.categoryId, Number(value)],
}
}
return {
...props,
categoryId: value ? [Number(value)] : undefined,
}
})
}
const onProvinceChange = (value: number) => {
clearRouter()
if (value) {
setFlightDefault(value)
} else {
setFlightDefault(undefined)
}
setFilterParams((props) => {
return {
...props,
licenseId: Number(value),
}
})
}
const onChange = (value: any) => {
clearRouter()
if (value) {
setSkillsDefault([value])
}else{
} else {
setSkillsDefault([])
}
setFilterParams((props) => {
return {
...props,
flightSkillsId: (value && value[value.length - 1]) || undefined,
};
});
};
}
})
}
const onChangeRegion = (value: any) => {
clearRouter()
// setFilterParams((props) => {
// return {
// ...props,
// regionId: (value && value[value.length - 1]) || undefined,
// };
// });
setFilterParams((props) => {
return {
...props,
regionId: (value && value[value.length - 1]) || undefined,
};
});
};
provinceId: value || undefined,
}
})
}
useEffect(() => {
setRightDomList(
list.map((item: string) => {
return { element: rightDom(item) };
return { element: rightDom(item) }
})
);
)
api.region().then((res) => {
setSecondDistrictInfo(res.result || []);
});
api.PilotLicense().then((res) => {
setSkills(res.result || []);
});
api.IndustryFlightSkills().then((res) => {
const list = res.result?.map((item)=>{
item.label = item.skillsName
item.value = item.id
return item
})
setFlightSkillsList(list || []);
});
}, []);
setSecondDistrictInfo(res.result || [])
})
// api.PilotLicense().then((res) => {
// setSkills(res.result || [])
// })
// api.IndustryFlightSkills().then((res) => {
// const list = res.result?.map((item) => {
// item.label = item.skillsName
// item.value = item.id
// return item
// })
// setFlightSkillsList(list || [])
// })
api.FlightSkills({ type: 3 }).then((res) => {
console.log(res)
setSelectOption(res.result)
})
}, [])
useEffect(() => {
if (Object.keys(router.query).length) {
let queryVal = JSON.parse(JSON.stringify(router.query));
let queryVal = JSON.parse(JSON.stringify(router.query))
for (const key in queryVal) {
queryVal[key] = Number(queryVal[key]);
queryVal[key] = Number(queryVal[key])
}
if (queryVal.flightSkillsId) {
setSkillsDefault([queryVal.flightSkillsId])
}else{
} else {
setFlightDefault(queryVal.licenseId)
}
setFilterParams((props) => {
return {
...props,
...queryVal,
};
});
}
})
}
}, [router]);
}, [router])
//报名
const [isModalOpen, setIsModalOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false)
const [loading, setLoading] = useState(false)
const handleOk = async (values: any) => {
form
.validateFields()
.then(async (values) => {
setLoading(true);
try{
const res = await api.PilotRegistrations({
...values,
city: values.city[values.city.length - 1] || undefined,
province: values.city[0] || undefined,
uavLicenseLevelOne: values.uavLicenseLevelOne && values.uavLicenseLevelOne[0],
uavLicenseLevelTow: values.uavLicenseLevelOne && values.uavLicenseLevelOne[1],
uavLicenseLevelThree: values.uavLicenseLevelOne && values.uavLicenseLevelOne[2]
});
if (res.code === "200") {
setLoading(false);
setIsModalOpen(false);
form.resetFields()
message.success('报名成功')
}else{
setLoading(false);
message.error(res.message)
}
}catch(e:any){
message.error(e.message)
}
}).catch((err) => {
message
.warning({
content: err.errorFields[0].errors[0],
form
.validateFields()
.then(async (values) => {
setLoading(true)
try {
const res = await api.PilotRegistrations({
...values,
city: values.city[values.city.length - 1] || undefined,
province: values.city[0] || undefined,
uavLicenseLevelOne:
values.uavLicenseLevelOne && values.uavLicenseLevelOne[0],
uavLicenseLevelTow:
values.uavLicenseLevelOne && values.uavLicenseLevelOne[1],
uavLicenseLevelThree:
values.uavLicenseLevelOne && values.uavLicenseLevelOne[2],
})
if (res.code === '200') {
setLoading(false)
setIsModalOpen(false)
form.resetFields()
message.success('报名成功')
} else {
setLoading(false)
message.error(res.message)
}
} catch (e: any) {
message.error(e.message)
}
})
.then();
});
};
.catch((err) => {
message
.warning({
content: err.errorFields[0].errors[0],
})
.then()
})
}
const handleCancel = () => {
setIsModalOpen(false);
};
setIsModalOpen(false)
}
const [form] = Form.useForm();
const [form] = Form.useForm()
const onChangeCheck = (checkedValues: CheckboxValueType[]) => {
console.log('checked = ', checkedValues);
};
console.log('checked = ', checkedValues)
}
return (
<Layout>
......@@ -285,7 +332,7 @@ export default function FlyingHandService() {
<div className="flyingTop">
<div className="flyingTop-left">
<Space>
<Cascader
{/* <Cascader
allowClear
placeholder="地域"
bordered={false}
......@@ -299,41 +346,40 @@ export default function FlyingHandService() {
options={secondDistrictInfo}
onChange={onChangeRegion}
changeOnSelect
/>
<Cascader
allowClear
placeholder="考证"
bordered={false}
className="selectItem"
size="large"
fieldNames={{
label: "licenseType",
value: "id",
children: "childLicenses",
}}
options={skills}
onChange={(value)=>onChange(value)}
changeOnSelect
value={skillsDefault}
/>
<Select
/> */}
{/* <Select
className="selectItem"
bordered={false}
popupMatchSelectWidth={false}
placeholder="技能"
placeholder="省份"
size="large"
onChange={(value) => onProvinceChange(value)}
options={flightSkillsList}
fieldNames={{ value: "id", label: "skillsName" }}
onChange={onChangeRegion}
options={secondDistrictInfo}
fieldNames={{ value: 'id', label: 'name' }}
allowClear
value={flightDefault}
/>
/> */}
{/* {selectOption?.map((item) => (
<Select
key={item.directoryId}
className="selectItem"
bordered={false}
popupMatchSelectWidth={false}
placeholder={item.name}
size="large"
onChange={(value) => onSelectChange(value, item)}
options={item.categoriesInfoListDTO}
fieldNames={{ value: 'id', label: 'name' }}
allowClear
/>
))} */}
</Space>
</div>
<Button
type="primary"
className="btn"
onClick={() => userInfo ? setIsModalOpen(true) : setNeedLogin(true)}
onClick={() =>
userInfo ? setIsModalOpen(true) : setNeedLogin(true)
}
>
报名学习课程
</Button>
......@@ -346,7 +392,11 @@ export default function FlyingHandService() {
getContainer={false}
footer={[
<Button
style={{ width: "100%" ,background: "linear-gradient(135deg, #278EFF 0%, #0052DA 100%)",height: 40 }}
style={{
width: '100%',
background: 'linear-gradient(135deg, #278EFF 0%, #0052DA 100%)',
height: 40,
}}
key="submit"
type="primary"
loading={loading}
......@@ -357,81 +407,91 @@ export default function FlyingHandService() {
]}
>
<Form
form={form}
layout="vertical"
name="application"
initialValues={{ modifier: 'public' }}
>
<div style={{display:"flex",justifyContent:"space-between"}}>
<Form.Item style={{flex:1,marginRight:16}}
name="name"
rules={[{ required: true, message: '请输入姓名!' }]}
form={form}
layout="vertical"
name="application"
initialValues={{ modifier: 'public' }}
>
<Input placeholder="姓名" />
</Form.Item>
<Form.Item style={{flex:1}} name="telephone" rules={[{ required: true, message: '请输入手机号!' }]}>
<Input onInput={phoneNumber} allowClear maxLength={11} placeholder="手机号" />
</Form.Item>
</div>
<Form.Item
name="city"
rules={[{ required: true, message: '请选择城市!' }]}
>
<Cascader
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<Form.Item
style={{ flex: 1, marginRight: 16 }}
name="name"
rules={[{ required: true, message: '请输入姓名!' }]}
>
<Input placeholder="姓名" />
</Form.Item>
<Form.Item
style={{ flex: 1 }}
name="telephone"
rules={[{ required: true, message: '请输入手机号!' }]}
>
<Input
onInput={phoneNumber}
allowClear
maxLength={11}
placeholder="手机号"
/>
</Form.Item>
</div>
<Form.Item
name="city"
rules={[{ required: true, message: '请选择城市!' }]}
>
<Cascader
allowClear
placeholder="城市"
className="selectItem"
fieldNames={{
label: "name",
value: "id",
children: "childInfo",
label: 'name',
value: 'id',
children: 'childInfo',
}}
options={secondDistrictInfo}
changeOnSelect
/>
</Form.Item>
<Form.Item
name="drivingLicense"
>
<Select allowClear placeholder="是否有驾照">
<Option value="0"></Option>
<Option value="1"></Option>
</Select>
</Form.Item>
<Form.Item
name="uavLicenseLevelOne"
>
<Cascader
</Form.Item>
<Form.Item name="drivingLicense">
<Select allowClear placeholder="是否有驾照">
<Option value="0"></Option>
<Option value="1"></Option>
</Select>
</Form.Item>
<Form.Item name="uavLicenseLevelOne">
<Cascader
allowClear
placeholder="是否有无人机执照"
className="selectItem"
fieldNames={{
label: "licenseType",
value: "id",
children: "childLicenses",
label: 'licenseType',
value: 'id',
children: 'childLicenses',
}}
options={skills}
changeOnSelect
/>
</Form.Item>
<Form.Item name="industryAppAuth" label="行业应用认证(多选)" className="collection-create-form_last-form-item">
<Checkbox.Group
options={flightSkillsList}
onChange={onChangeCheck}
/>
</Form.Item>
<Form.Item name="remark">
<Input placeholder="备注" />
</Form.Item>
</Form>
</Form.Item>
<Form.Item
name="industryAppAuth"
label="行业应用认证(多选)"
className="collection-create-form_last-form-item"
>
<Checkbox.Group
options={flightSkillsList}
onChange={onChangeCheck}
/>
</Form.Item>
<Form.Item name="remark">
<Input placeholder="备注" />
</Form.Item>
</Form>
</Modal>
<ContentBox
boxIndex={4}
leftcontentstyle={{
width: "925px",
margin: { top: 0, right: "10px", bottom: "10px", left: 0 },
width: '925px',
margin: { top: 0, right: '10px', bottom: '10px', left: 0 },
}}
leftRenderDom={{
columns: productList,
......@@ -454,5 +514,5 @@ export default function FlyingHandService() {
/>
</Box>
</Layout>
);
)
}
......@@ -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 React, { Component, useEffect, useState } from "react";
import { message } from 'antd';
import { Box } from "./styled";
import api from "./api";
import React, { Component, useEffect, useState } from 'react'
import { message } from 'antd'
import { Box } from './styled'
import api from './api'
import icon from './assets/img.png'
import {useRouter} from 'next/router'
let MAP :any ;
let Amap:any;
import { useRouter } from 'next/router'
let MAP: any
let Amap: any
interface UserInfoType {
lat: number;
lon: number;
pageNo?:number,
pageSize?:number
}
lat: number
lon: number
pageNo?: number
pageSize?: number
}
export default function MapComponent() {
const router = useRouter()
const [mapItem, setMapItem] = useState(0);
const [userPositioning, setUserPositioning] = useState<UserInfoType>();
const [markerCol, setMarkerCol] = useState<any>([]);
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'等
/* 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", {
MAP = new AMap.Map('container', {
// 设置地图容器id
viewMode: "3D", // 是否为3D地图模式
viewMode: '3D', // 是否为3D地图模式
zoom: 9, // 初始化地图级别
center: [113.93029, 22.53291], // 初始化地图中心点位置
});
})
//用户定位
AMap.plugin('AMap.Geolocation', function() {
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('定位成功');
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) {
}
//解析定位错误信息
async function onError(data: any) {
// message.error(`定位失败
// 失败原因排查信息:${data.message}
// 浏览器返回信息:${data.originMessage}
// `)
}
}
await mapEntiy(0)
})
.catch((e) => {
console.log(e);
});
console.log(e)
})
} catch (error) {
console.log(error);
console.log(error)
}
};
const showPositioningInfo = async (index:number,data?:UserInfoType) => {
}
const showPositioningInfo = async (index: number, data?: UserInfoType) => {
const res = await api.listPositioningInfo({
lon: userPositioning?.lon || data?.lon || 113.93029,
lat: userPositioning?.lat || data?.lat || 22.53291,
});
const list = res.result
?.map((item) => item.locationList)
.flat()
.filter((item: { dizhi: string }) => item.dizhi.includes("省"));
const markerList: any = [];
pageNo: 1,
pageSize: 10,
})
const list = res.result?.list
const markerList: any = []
if (list?.length) {
list?.map((item) => {
const EntiyValue = addEntiy(item.jd, item.wd, item.dizhi);
markerList.push(EntiyValue);
});
if(markerList.length) MAP?.add(markerList);setMarkerCol([...markerList]);
const EntiyValue = addEntiy(item.lon, item.lat, item.name)
markerList.push(EntiyValue)
})
if (markerList.length) MAP?.add(markerList)
setMarkerCol([...markerList])
}
//自适应显示多个点位
MAP?.setFitView();
MAP?.setFitView()
}
const showFlyerBitmap = async (index:number,data?:UserInfoType,pageSize?:number) => {
const showFlyerBitmap = async (
index: number,
data?: UserInfoType,
pageSize?: number
) => {
const res = await api.listFlyerBitmap({
lon: userPositioning?.lon || data?.lon || 113.93029,
lat: userPositioning?.lat || data?.lat || 22.53291,
pageNo:1,
pageSize: pageSize || 40
});
lon: userPositioning?.lon || data?.lon || 113.93029,
lat: userPositioning?.lat || data?.lat || 22.53291,
pageNo: 1,
pageSize: pageSize || 40,
})
const list = res.result?.list
const markerList: any = [];
const markerList: any = []
if (list?.length) {
list?.map((item) => {
const EntiyValue = addEntiy(item.lon, item.lat, item.flyerName);
markerList.push(EntiyValue);
});
if(markerList.length) MAP?.add(markerList);setMarkerCol(markerList)
const EntiyValue = addEntiy(item.lon, item.lat, item.flyerName)
markerList.push(EntiyValue)
})
if (markerList.length) MAP?.add(markerList)
setMarkerCol(markerList)
}
//自适应显示多个点位
MAP?.setFitView();
//自适应显示多个点位
MAP?.setFitView()
}
const showUavBitmap = async (index:number,data?:UserInfoType) => {
const showUavBitmap = async (index: number, data?: UserInfoType) => {
const res = await api.listUavBitmap({
lon: userPositioning?.lon || data?.lon || 113.93029,
lat: userPositioning?.lat || data?.lat || 22.53291,
pageNo:1,
pageSize: 40
});
lon: userPositioning?.lon || data?.lon || 113.93029,
lat: userPositioning?.lat || data?.lat || 22.53291,
pageNo: 1,
pageSize: 40,
})
const list = res.result?.list
const markerList: any = [];
const markerList: any = []
if (list?.length) {
list?.map((item) => {
const EntiyValue = addEntiy(item.lon, item.lat, item.uavName);
markerList.push(EntiyValue);
});
if(markerList.length) MAP?.add(markerList);setMarkerCol(markerList)
const EntiyValue = addEntiy(item.lon, item.lat, item.uavName)
markerList.push(EntiyValue)
})
if (markerList.length) MAP?.add(markerList)
setMarkerCol(markerList)
}
//自适应显示多个点位
MAP?.setFitView();
MAP?.setFitView()
}
//添加点位
const mapEntiy = async (index: number, data?: UserInfoType) => {
MAP?.remove(markerCol)
if (index === 0) {
showPositioningInfo(index, data)
} else if (index === 1) {
showFlyerBitmap(index, data, 30)
} else if (index === 2) {
showUavBitmap(index, data)
} else {
router.push('/home/waterfallFlowBody/components/map/moreServicePoints')
}
setMapItem(index)
}
//添加点位
const mapEntiy = async (index: number,data?:UserInfoType) => {
MAP?.remove(markerCol);
if (index === 0) {
showPositioningInfo(index,data)
}else if (index === 1) {
showFlyerBitmap(index,data,30)
} else if(index === 2) {
showUavBitmap(index,data)
}else{
router.push('/home/waterfallFlowBody/components/map/moreServicePoints')
}
setMapItem(index);
};
const addEntiy = ( lon: any, lat: any, name: string) => {
if (!Amap) return;
const icons = new Amap.Icon({
size: new Amap.Size(60, 60), // 图标尺寸
image: icon.src, // Icon的图像
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();
}, []);
const addEntiy = (lon: any, lat: any, name: string) => {
if (!Amap) return
const icons = new Amap.Icon({
size: new Amap.Size(60, 60), // 图标尺寸
image: icon.src, // Icon的图像
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>
<div className="map-dosome">
<div
className={`itemBox ${mapItem === 0 ? "active" : ""}`}
className={`itemBox ${mapItem === 0 ? 'active' : ''}`}
onClick={() => mapEntiy(0)}
>
服务网点
</div>
<div
className={`itemBox ${mapItem === 1 ? "active" : ""}`}
className={`itemBox ${mapItem === 1 ? 'active' : ''}`}
onClick={() => mapEntiy(1)}
>
租赁网点
</div>
<div
className={`itemBox ${mapItem === 2 ? "active" : ""}`}
className={`itemBox ${mapItem === 2 ? 'active' : ''}`}
onClick={() => mapEntiy(2)}
>
培训网点
</div>
<div
className={`${mapItem === 3 ? "active" : ""}`}
className={`${mapItem === 3 ? 'active' : ''}`}
onClick={() => mapEntiy(3)}
>
更多网点
</div>
</div>
</Box>
);
)
}
import React,{useState,useEffect} from 'react'
import Layout from "~/components/layout";
import {Box} from './styled'
import api from "../api";
import { message } from 'antd'
import { useEffect, useState } from 'react'
import Layout from '~/components/layout'
import api from '../api'
import icon from '../assets/img.png'
import { message } from 'antd';
let MAP :any ;
let Amap:any;
import { Box } from './styled'
let MAP: any
let Amap: any
interface UserInfoType {
lat: number;
lon: number;
pageNo?:number,
pageSize?:number
}
lat: number
lon: number
pageNo?: number
pageSize?: number
}
export default function MoreServicePoints() {
const [mapItem, setMapItem] = useState(0);
const [userPositioning, setUserPositioning] = useState<UserInfoType>();
const [markerCol, setMarkerCol] = useState<any>([]);
const [servicePoints, setServicePoints] = useState<any>([]);
const [mapItem, setMapItem] = useState(0)
const [userPositioning, setUserPositioning] = useState<UserInfoType>()
const [markerCol, setMarkerCol] = useState<any>([])
const [servicePoints, setServicePoints] = useState<any>([])
//初始化地图
const init = async () => {
try {
const AMapLoader = await import(
/* webpackChunkName: "amap" */ "@amap/amap-jsapi-loader"
);
/* webpackChunkName: "amap" */ '@amap/amap-jsapi-loader'
)
await AMapLoader.load({
key: "87b424e68754efc3ba9d11ae07475091", // 申请好的Web端开发者Key,首次调用 load 时必填
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: [""], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
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", {
Amap = AMap
MAP = new AMap.Map('container', {
// 设置地图容器id
viewMode: "3D", // 是否为3D地图模式
viewMode: '3D', // 是否为3D地图模式
zoom: 9, // 初始化地图级别
center: [113.93029, 22.53291], // 初始化地图中心点位置
});
})
//用户定位
AMap.plugin("AMap.Geolocation", function () {
AMap.plugin('AMap.Geolocation', function () {
const geolocation = new AMap.Geolocation({
enableHighAccuracy: true, //是否使用高精度定位,默认:true
timeout: 10000, //超过10秒后停止定位,默认:5s
position: "RB", //定位按钮的停靠位置
position: 'RB', //定位按钮的停靠位置
offset: [10, 20], //定位按钮与设置的停靠位置的偏移量,默认:[10, 20]
zoomToAccuracy: true, //定位成功后是否自动调整地图视野到定位点
});
MAP.addControl(geolocation);
})
MAP.addControl(geolocation)
geolocation.getCurrentPosition(function (
status: string,
result: any
) {
console.log(result);
console.log(result)
if (status == "complete") {
onComplete(result);
if (status == 'complete') {
onComplete(result)
} else {
onError(result);
onError(result)
}
});
});
})
})
//解析定位结果
async function onComplete(data: any) {
console.log("定位成功");
setUserPositioning(data.position);
console.log('定位成功')
setUserPositioning(data.position)
// return await mapEntiy(0,data.position);
}
//解析定位错误信息
......@@ -74,37 +74,36 @@ export default function MoreServicePoints() {
// 浏览器返回信息:${data.originMessage}
// `)
}
await mapEntiy(0);
await mapEntiy(0)
})
.catch((e) => {
console.log(e);
});
console.log(e)
})
} catch (error) {
console.log(error);
console.log(error)
}
};
}
const showPositioningInfo = async (index: number, data?: UserInfoType) => {
const res = await api.listPositioningInfo({
lon: userPositioning?.lon || data?.lon || 113.93029,
lat: userPositioning?.lat || data?.lat || 22.53291,
});
const list = res.result
?.map((item) => item.locationList)
.flat()
.filter((item: { dizhi: string }) => item.dizhi.includes("省"));
const markerList: any = [];
pageNo: 1,
pageSize: 10,
})
const list = res.result?.list
const markerList: any = []
if (list?.length) {
list?.map((item) => {
const EntiyValue = addEntiy(item.jd, item.wd, item.dizhi);
markerList.push(EntiyValue);
});
setServicePoints(list);
if (markerList.length) MAP?.add(markerList);
setMarkerCol([...markerList]);
const EntiyValue = addEntiy(item.lon, item.lat, item.name)
markerList.push(EntiyValue)
})
setServicePoints(list)
if (markerList.length) MAP?.add(markerList)
setMarkerCol([...markerList])
}
//自适应显示多个点位
MAP?.setFitView();
};
//自适应显示多个点位
MAP?.setFitView()
}
const showFlyerBitmap = async (
index: number,
data?: UserInfoType,
......@@ -115,99 +114,124 @@ export default function MoreServicePoints() {
lat: userPositioning?.lat || data?.lat || 22.53291,
pageNo: 1,
pageSize: pageSize || 40,
});
const list = res.result?.list;
const markerList: any = [];
})
const list = res.result?.list
const markerList: any = []
if (list?.length) {
list?.map((item) => {
const EntiyValue = addEntiy(item.lon, item.lat, item.flyerName);
markerList.push(EntiyValue);
});
setServicePoints(list);
if (markerList.length) MAP?.add(markerList);
setMarkerCol(markerList);
const EntiyValue = addEntiy(item.lon, item.lat, item.flyerName)
markerList.push(EntiyValue)
})
setServicePoints(list)
if (markerList.length) MAP?.add(markerList)
setMarkerCol(markerList)
}
//自适应显示多个点位
MAP?.setFitView();
};
//自适应显示多个点位
MAP?.setFitView()
}
const showMaintainBitmap = async (
index: number,
data?: UserInfoType,
pageSize?: number
) => {
const res = await api.listMaintainBitmap({
lon: userPositioning?.lon || data?.lon || 113.93029,
lat: userPositioning?.lat || data?.lat || 22.53291,
pageNo: 1,
pageSize: pageSize || 40,
})
const list = res.result?.list
const markerList: any = []
if (list?.length) {
list?.map((item) => {
const EntiyValue = addEntiy(item.lon, item.lat, item.name)
markerList.push(EntiyValue)
})
setServicePoints(list)
if (markerList.length) MAP?.add(markerList)
setMarkerCol(markerList)
}
//自适应显示多个点位
MAP?.setFitView()
}
const showUavBitmap = async (index: number, data?: UserInfoType) => {
const res = await api.listUavBitmap({
lon: userPositioning?.lon || data?.lon || 113.93029,
lat: userPositioning?.lat || data?.lat || 22.53291,
pageNo: 1,
pageSize: 40,
});
const list = res.result?.list;
const markerList: any = [];
})
const list = res.result?.list
const markerList: any = []
if (list?.length) {
list?.map((item) => {
const EntiyValue = addEntiy(item.lon, item.lat, item.uavName);
markerList.push(EntiyValue);
});
setServicePoints(list);
if (markerList.length) MAP?.add(markerList);
setMarkerCol(markerList);
const EntiyValue = addEntiy(item.lon, item.lat, item.uavName)
markerList.push(EntiyValue)
})
setServicePoints(list)
if (markerList.length) MAP?.add(markerList)
setMarkerCol(markerList)
}
//自适应显示多个点位
MAP?.setFitView();
};
MAP?.setFitView()
}
//添加点位
const mapEntiy = async (index: number, data?: UserInfoType) => {
MAP?.remove(markerCol);
MAP?.remove(markerCol)
if (userPositioning) {
MAP?.setCenter([userPositioning.lon, userPositioning.lat]);
MAP?.setCenter([userPositioning.lon, userPositioning.lat])
}
if (index === 0) {
showPositioningInfo(index, data);
showPositioningInfo(index, data)
} else if (index === 1) {
showFlyerBitmap(index, data, 30);
showFlyerBitmap(index, data, 30)
} else if (index === 2) {
showUavBitmap(index, data);
showUavBitmap(index, data)
} else {
showFlyerBitmap(index, data, 30);
showMaintainBitmap(index, data, 30)
}
setMapItem(index);
};
setMapItem(index)
}
const addEntiy = (lon: any, lat: any, name: string) => {
if (!Amap) return;
if (!Amap) return
const icons = new Amap.Icon({
size: new Amap.Size(60, 60), // 图标尺寸
image: icon.src, // Icon的图像
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;
};
})
return marker
}
const moveTo = (item: any,index:number) => {
// const p = markerCol[index].getPosition()
// var infoWindow = new Amap.InfoWindow({
// position: p,
// offset: new Amap.Pixel(20, -10),
// content: item.dizhi
// });
// infoWindow.open(MAP);
const moveTo = (item: any, index: number) => {
const p = markerCol[index].getPosition()
var infoWindow = new Amap.InfoWindow({
position: p,
offset: new Amap.Pixel(20, -10),
content: item.dizhi || item.flyerName || item.uavName || item.name,
})
infoWindow.open(MAP)
if (item.dizhi) {
return MAP?.setCenter([item.jd, item.wd]);
} else if (item.flyerName || item.uavName) {
return MAP?.setCenter([item.lon, item.lat]);
return MAP?.setCenter([item.jd, item.wd])
} else if (item.flyerName || item.uavName || item.name) {
return MAP?.setCenter([item.lon, item.lat])
}
return message.warning("暂无位置信息");
};
return message.warning('暂无位置信息')
}
useEffect(() => {
(async () => {
await init();
})();
return MAP && MAP.destroy();
}, []);
;(async () => {
await init()
})()
return MAP && MAP.destroy()
}, [])
return (
<Layout>
......@@ -215,41 +239,46 @@ export default function MoreServicePoints() {
<div className="title">
<div
onClick={() => mapEntiy(0)}
className={`item ${mapItem === 0 ? "active" : ""}`}
className={`item ${mapItem === 0 ? 'active' : ''}`}
>
服务网点
</div>
<div
onClick={() => mapEntiy(1)}
className={`item ${mapItem === 1 ? "active" : ""}`}
className={`item ${mapItem === 1 ? 'active' : ''}`}
>
培训网点
</div>
<div
onClick={() => mapEntiy(2)}
className={`item ${mapItem === 2 ? "active" : ""}`}
className={`item ${mapItem === 2 ? 'active' : ''}`}
>
租赁网点
</div>
<div
onClick={() => mapEntiy(3)}
className={`item ${mapItem === 3 ? "active" : ""}`}
className={`item ${mapItem === 3 ? 'active' : ''}`}
>
机构网点
维修网点
</div>
</div>
<div className="content">
<div className="left">
<div className="left-title">服务网点</div>
{mapItem === 0 && <div className="left-title">服务网点</div>}
{mapItem === 1 && <div className="left-title">培训网点</div>}
{mapItem === 2 && <div className="left-title">租赁网点</div>}
{mapItem === 3 && <div className="left-title">维修网点</div>}
<div className="left-content">
{servicePoints.map((item: any,index:number) => (
{servicePoints.map((item: any, index: number) => (
<div
key={item.id}
onClick={() => moveTo(item,index)}
onClick={() => moveTo(item, index)}
className="left-content-item"
title={item.dizhi || item.flyerName || item.uavName}
title={
item.dizhi || item.flyerName || item.uavName || item.name
}
>
{item.dizhi || item.flyerName || item.uavName}
{item.dizhi || item.flyerName || item.uavName || item.name}
</div>
))}
</div>
......@@ -260,5 +289,5 @@ export default function MoreServicePoints() {
</div>
</Box>
</Layout>
);
)
}
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 React, { useEffect, useState , useContext } from "react";
import { Space, Select, Button, message } from "antd";
import Image from "next/image";
import { useRouter } from "next/router";
import { Box } from "./styled";
import ContentBox from "~/components/contentBox";
import RotationChart from "./components/rotationChart";
import Map from "./components/map";
import { Select, Space, message } from 'antd'
import { useRouter } from 'next/router'
import { useContext, useEffect, useState } from 'react'
import ContentBox from '~/components/contentBox'
import Map from './components/map'
import RotationChart from './components/rotationChart'
import { Box } from './styled'
import {
FilterOptionResp,
RegionResp,
import { UserContext } from '~/lib/userProvider'
import api, {
AllType,
AppType,
IndustryType,
SkillsType,
NewsPageType,
NewsTenderType,
equipmentLeasingApi,
jobServicesApi,
mallApi,
flightSkillsApi,
jobServicesApi,
listNewsApi,
} from "./api";
import { BaseOptionType, DefaultOptionType } from "antd/es/select";
import { UserContext } from "~/lib/userProvider";
mallApi,
} from './api'
interface ColumnsType {
title: string;
router: string;
title: string
router: string
}
export default function WaterfallFlowBody() {
const router = useRouter();
const { userInfo, setNeedLogin } = useContext(UserContext);
const router = useRouter()
const { userInfo, setNeedLogin } = useContext(UserContext)
const [list, setList] = useState([
"中国人寿",
"中国平安",
"中国人保",
"太平洋保险",
"新华保险",
"中国太平",
"泰康保险",
"华夏保险",
"阳光保险",
"富德生命人寿",
"中邮人寿",
"前海人寿",
"百年人寿",
"国华人寿",
"工银安盛人寿",
"恒大人寿",
"君康人寿",
"友邦保险",
"建信人寿",
"大家人寿",
"农银人寿",
"中信保城人寿",
"合众人寿",
]);
'中国人寿',
'中国平安',
'中国人保',
'太平洋保险',
'新华保险',
'中国太平',
'泰康保险',
'华夏保险',
'阳光保险',
'富德生命人寿',
'中邮人寿',
'前海人寿',
'百年人寿',
'国华人寿',
'工银安盛人寿',
'恒大人寿',
'君康人寿',
'友邦保险',
'建信人寿',
'大家人寿',
'农银人寿',
'中信保城人寿',
'合众人寿',
])
const [list2, setList2] = useState([
"天目将PAAS平台",
"天目将公安平台",
"天目将应急平台",
"天目将城管平台",
"天目将电力平台",
"天目将石油平台",
"SESP-U1无人机仿真软件",
"云享飞服务号",
"无人机商城",
"云飞手",
"云仓",
"云享飞",
"科比特智教",
]);
'天目将PAAS平台',
'天目将公安平台',
'天目将应急平台',
'天目将城管平台',
'天目将电力平台',
'天目将石油平台',
'SESP-U1无人机仿真软件',
'云享飞服务号',
'无人机商城',
'云飞手',
'云仓',
'云享飞',
'科比特智教',
])
const columns = [
{
title: "无人机出租",
router: "/equipmentLeasing",
title: '无人机出租',
router: '/equipmentLeasing',
},
{
title: "无人机销售",
router: "/mall",
title: '无人机销售',
router: '/mall',
},
{
title: "无人机保险",
router: "",
title: '无人机保险',
router: '',
},
{
title: "无人机培训",
router: "flyingHandService",
title: '无人机培训',
router: 'flyingHandService',
},
{
title: "无人机服务",
router: "/jobServices",
title: '无人机服务',
router: '/jobServices',
},
{
title: "无人机工具软件",
router: "",
title: '无人机工具软件',
router: '',
},
];
]
const [leftDomList, setLeftDomList] = useState(
Array<{ element: JSX.Element; type?: string }>
);
)
const [rightTopDomList, setRightTopDomList] = useState<JSX.Element>();
const [rightBottomDomList, setRightBottomDomList] = useState<JSX.Element>();
const [rightTopDomList, setRightTopDomList] = useState<JSX.Element>()
const [rightBottomDomList, setRightBottomDomList] = useState<JSX.Element>()
const { deviceBrand , deviceCategory, deviceModel } = equipmentLeasingApi;
const eqApiTypeList = ["brandId", "categoryId", "modelId"];
// const { deviceBrand, deviceModel } = equipmentLeasingApi
// const eqApiTypeList = ['brandId', 'categoryId', 'modelId']
const { listAllModel , listAllBrand , listAllCategory, listAllParts, listAllQuality } = mallApi;
const mallApiTypeList = [
"brandId",
"productCategoryId",
"partsId",
"modelId",
"qualityId",
];
const { IndustryFlightSkills , InDronePilotLicense} = flightSkillsApi;
const flightApiTypeList = ["licenseId", "flightSkillsId"];
// const {
// listAllModel,
// listAllBrand,
// listAllCategory,
// listAllParts,
// listAllQuality,
// } = mallApi
// const mallApiTypeList = [
// 'brandId',
// 'productCategoryId',
// 'partsId',
// 'modelId',
// 'qualityId',
// ]
// const { IndustryFlightSkills, InDronePilotLicense } = flightSkillsApi
// const flightApiTypeList = ['licenseId', 'flightSkillsId']
const { listAllIndustry, listAllAppType } = jobServicesApi;
const jobApiTypeList = ["industryId", "appTypeId"];
// const { listAllIndustry, listAllAppType } = jobServicesApi
// const jobApiTypeList = ['industryId', 'appTypeId']
const onMoreChange = (
value: { value: string; label: number },
index: number,
option: []
) => {
const [item] = option.filter((item: any) => item.name === value.value);
routerPath(index, item);
};
const [item] = option.filter((item: any) => item.name === value.value)
routerPath(index, item)
}
useEffect(() => {
(async () => {
let res1 = await Promise.all([
deviceBrand(),
deviceCategory(),
deviceModel(),
]);
let res2 = await Promise.all([
listAllBrand(),
listAllCategory(),
listAllParts(),
listAllModel(),
listAllQuality(),
]);
let res3 = await Promise.all([IndustryFlightSkills(),InDronePilotLicense()]);
let res4 = await Promise.all([listAllIndustry(), listAllAppType()]);
// let res4 = await Promise.all([deviceCategory(),deviceBrand(),deviceModel()])
// let res6 = await Promise.all([deviceCategory(),deviceBrand(),deviceModel()])
const resValuelist1 = res1
.map((item, index) => {
if (item.code === "200") {
return item.result?.map((it) => {
it.type = eqApiTypeList[index];
return it;
});
}
return {}
})
.flat();
const resValuelist2 = res2
.map((item, index) => {
if (item.code === "200") {
return item.result?.map((it) => {
it.type = mallApiTypeList[index];
return it;
});
}
return {}
})
.flat();
const resValuelist3 = res3
.map((item, index) => {
if (item.code === "200") {
return item.result?.map((it) => {
it.type = flightApiTypeList[index];
it.name = it.name || it.skillsName || it.licenseType;
return it;
});
}
return {}
})
.flat();
const resValuelist4 = res4
.map((item, index) => {
if (item.code === "200") {
return item.result?.map((it) => {
it.type = jobApiTypeList[index];
it.name = it.name || it.appName;
return it;
});
}
return {}
})
.flat();
// useEffect(() => {
// ;(async () => {
// let res1 = await Promise.all([deviceBrand(), deviceModel()])
// let res2 = await Promise.all([listAllBrand(), listAllCategory(), listAllParts(), listAllModel(), listAllQuality()])
// let res3 = await Promise.all([IndustryFlightSkills(), InDronePilotLicense()])
// let res4 = await Promise.all([listAllIndustry(), listAllAppType()])
// // let res4 = await Promise.all([deviceCategory(),deviceBrand(),deviceModel()])
// // let res6 = await Promise.all([deviceCategory(),deviceBrand(),deviceModel()])
let res7 = await listNewsApi.listNewsPage({ pageNo: 1, pageSize: 5 });
let res8 = await listNewsApi.listNewTenderInfo({
pageNo: 1,
pageSize: 6,
});
const listValue: any = [
resValuelist1,
resValuelist2,
[],
resValuelist3,
resValuelist4,
[],
];
// const resValuelist1 = res1
// .map((item, index) => {
// if (item.code === '200') {
// return item.result?.map(it => {
// it.type = eqApiTypeList[index]
// return it
// })
// }
// return {}
// })
// .flat()
// const resValuelist2 = res2
// .map((item, index) => {
// if (item.code === '200') {
// return item.result?.map(it => {
// it.type = mallApiTypeList[index]
// return it
// })
// }
// return {}
// })
// .flat()
// const resValuelist3 = res3
// .map((item, index) => {
// if (item.code === '200') {
// return item.result?.map(it => {
// it.type = flightApiTypeList[index]
// it.name = it.name || it.skillsName || it.licenseType
// return it
// })
// }
// return {}
// })
// .flat()
// const resValuelist4 = res4
// .map((item, index) => {
// if (item.code === '200') {
// return item.result?.map(it => {
// it.type = jobApiTypeList[index]
// it.name = it.name || it.appName
// return it
// })
// }
// return {}
// })
// .flat()
// let res7 = await listNewsApi.listNewsPage({ pageNo: 1, pageSize: 5 })
// let res8 = await listNewsApi.listNewTenderInfo({
// pageNo: 1,
// pageSize: 6
// })
// const listValue: any = [resValuelist1, resValuelist2, [], resValuelist3, resValuelist4, []]
// const listOption = JSON.parse(JSON.stringify(list)).map((item: string, index: number) => {
// return { id: index, name: item, value: index }
// })
// const list2Option = JSON.parse(JSON.stringify(list2)).map((item: string, index: number) => {
// return { id: index, name: item, value: index }
// })
// const optionList = [resValuelist1, resValuelist2, listOption, resValuelist3, resValuelist4, list2Option]
// setLeftDomList(
// columns.map((item, index) => {
// if (index < 3) {
// return {
// element: leftDom(item, index, listValue, optionList[index]),
// type: 'left'
// }
// }
// return {
// element: leftDom(item, index, listValue, optionList[index]),
// type: 'right'
// }
// })
// )
// setRightTopDomList(rightDom(res7.result?.list!))
// setRightBottomDomList(rightDom2(res8.result?.list!))
// })()
// }, [])
useEffect(() => {
;(async () => {
const res2 = await api.HomeCategories({ type: 2 }) //无人机培训
const res4 = await api.HomeCategories({ type: 4 }) //无人机销售
const res1 = await api.HomeCategories({ type: 1 }) //无人机出租
const res3 = await api.HomeCategories({ type: 3 }) //无人机服务
console.log(res1, res2, res3, res4)
const listOption = JSON.parse(JSON.stringify(list)).map(
(item: string, index: number) => {
return { id: index, name: item, value: index };
return { id: index, categoryName: item, value: index }
}
);
)
const list2Option = JSON.parse(JSON.stringify(list2)).map(
(item: string, index: number) => {
return { id: index, name: item, value: index };
return { id: index, categoryName: item, value: index }
}
);
)
const optionList = [
resValuelist1,
resValuelist2,
res2.result,
res4.result,
listOption,
resValuelist3,
resValuelist4,
res3.result,
res1.result,
list2Option,
];
]
const listValue: any = [
res2.result,
res4.result,
[],
res3.result,
res1.result,
[],
]
setLeftDomList(
columns.map((item, index) => {
if (index < 3) {
return {
element: leftDom(item, index, listValue, optionList[index]),
type: "left",
};
type: 'left',
}
}
return {
element: leftDom(item, index, listValue, optionList[index]),
type: "right",
};
type: 'right',
}
})
);
setRightTopDomList(rightDom(res7.result?.list!));
setRightBottomDomList(rightDom2(res8.result?.list!));
})();
}, []);
)
let res7 = await listNewsApi.listNewsPage({ pageNo: 1, pageSize: 5 })
let res8 = await listNewsApi.listNewTenderInfo({
pageNo: 1,
pageSize: 6,
})
setRightTopDomList(rightDom(res7.result?.list!))
setRightBottomDomList(rightDom2(res8.result?.list!))
})()
}, [])
const routerPath = (index: number, item?: AllType) => {
if ( item && (index === 0 || index === 1 || index === 3 || index === 4) ) {
if (item && (index === 0 || index === 1 || index === 3 || index === 4)) {
router.push({
pathname: columns[index].router,
query: { [item?.type!]: item?.id! , name: item?.name || item?.appName || item?.skillsName },
});
}else{
query: {
categoryId: item.id,
name: item.categoryName,
},
})
} else {
router.push({
pathname: columns[index].router,
});
})
}
};
}
const handleTenderApply = async (item:NewsTenderType)=>{
if (item.apply) return;
const handleTenderApply = async (item: NewsTenderType) => {
if (item.apply) return
if (userInfo) {
let res = await listNewsApi.tenderApply({
tenderInfoId: item.id,
tenderNewsId: item.tenderNewsId,
userAccountId: userInfo.id,
tenderNewsId: item.tenderNewsId,
userAccountId: userInfo.id,
})
try {
if (res.code === '200') {
message.success('申请成功')
let res8 = await listNewsApi.listNewTenderInfo({
pageNo: 1,
pageSize: 6,
})
try{
if (res.code==="200") {
message.success("申请成功")
let res8 = await listNewsApi.listNewTenderInfo({
pageNo: 1,
pageSize: 6,
});
setRightBottomDomList(rightDom2(res8.result?.list!));
}else{
setRightBottomDomList(rightDom2(res8.result?.list!))
} else {
message.error(res.message)
}
}catch(e){
console.log(e);
} catch (e) {
console.log(e)
}
}else{
} else {
setNeedLogin(true)
}
}
......@@ -319,8 +350,8 @@ export default function WaterfallFlowBody() {
dropdownMatchSelectWidth={false}
options={option}
fieldNames={{
value: "name",
label: "name",
value: 'categoryName',
label: 'categoryName',
}}
/>
</div>
......@@ -332,7 +363,7 @@ export default function WaterfallFlowBody() {
<div
key={item}
className={`item-bubble ${
index === 0 || index === 1 || index === 2 ? "active" : ""
index === 0 || index === 1 || index === 2 ? 'active' : ''
}`}
>
{item}
......@@ -343,7 +374,7 @@ export default function WaterfallFlowBody() {
<div
key={item}
className={`item-bubble ${
index === 0 || index === 1 || index === 2 ? "active" : ""
index === 0 || index === 1 || index === 2 ? 'active' : ''
}`}
>
{item}
......@@ -352,43 +383,47 @@ export default function WaterfallFlowBody() {
: resultList[index].map((item, indexer) => {
return (
<div
key={item?.name || item?.appName || item?.skillsName}
key={item.categoryName}
className={`item-bubble ${
indexer === 0 || indexer === 1 || indexer === 2
? "active"
: ""
? 'active'
: ''
}`}
onClick={() => routerPath(index, item)}
>
{item?.name || item?.appName || item?.skillsName}
{item.categoryName}
</div>
);
)
})}
</Space>
</div>
</div>
);
};
)
}
const rightDom = (list: Array<NewsPageType>) => {
if(!list?.length) return;
if (!list?.length) return
return (
<div key={1009} className="right-box-item right-item">
<div className="title">
<div
className="title-label"
onClick={() => router.push("/projectInfo")}
onClick={() => router.push('/projectInfo')}
>
行业新闻
</div>
</div>
<div className="body">
{list?.map((item, index) => (
<div key={item.id} className="body-item" onClick={()=>router.push(`/projectInfo/newsArticle/${item.id}`)}>
<div
key={item.id}
className="body-item"
onClick={() => router.push(`/projectInfo/newsArticle/${item.id}`)}
>
<div
className={`item-ranking ${index === 0 ? "one" : ""} ${
index === 1 ? "two" : ""
} ${index === 2 ? "san" : ""}`}
className={`item-ranking ${index === 0 ? 'one' : ''} ${
index === 1 ? 'two' : ''
} ${index === 2 ? 'san' : ''}`}
>
{index + 1}
</div>
......@@ -399,18 +434,18 @@ export default function WaterfallFlowBody() {
))}
</div>
</div>
);
};
)
}
const rightDom2 = (list: Array<NewsTenderType>) => {
if(!list?.length) return;
if (!list?.length) return
return (
<div key={1008} className="right-box-item right-item-second">
<div className="item-box">
<div className="title">
<div
className="title-label"
onClick={() => router.push("/projectInfo")}
onClick={() => router.push('/projectInfo')}
>
招标快讯
</div>
......@@ -422,28 +457,34 @@ export default function WaterfallFlowBody() {
{item.tenderContent}
<div className="label-bottom">{item.tenderPrice}</div>
</div>
<div className={`item-right ${item.apply ? 'apply' : ''}`} onClick={()=>handleTenderApply(item)}>
<div className="left">{`${item.tenderPrice}W`}</div>
{
item.apply ? <div className="right">已申请</div> : <>
<div className="right">申请合作</div></>
}
<div
className={`item-right ${item.apply ? 'apply' : ''}`}
onClick={() => handleTenderApply(item)}
>
<div className="left">{`${item.tenderPrice}W`}</div>
{item.apply ? (
<div className="right">已申请</div>
) : (
<>
<div className="right">申请合作</div>
</>
)}
</div>
</div>
))}
</div>
</div>
</div>
);
};
)
}
return (
<Box>
<ContentBox
boxIndex={1} //分为左右两列,每列一个,从上而下
leftcontentstyle={{
width: "806px",
margin: { top: 0, right: "10px", bottom: "10px", left: 0 },
width: '806px',
margin: { top: 0, right: '10px', bottom: '10px', left: 0 },
}}
leftWaterfallDom={{
columns: [
......@@ -459,7 +500,6 @@ export default function WaterfallFlowBody() {
],
}}
/>
</Box>
);
)
}
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 React,{useEffect, useState} from 'react'
import Layout from "~/components/layout";
import {Box} from './styled';
import { Tabs , Button } from 'antd';
import type { TabsProps } from 'antd';
import Evaluate from './components/evaluate';
import { useRouter } from "next/router";
import api , {ListPageJobInfoResp} from './api';
import Image from 'next/image';
import React, { useEffect, useState } from 'react'
import Layout from '~/components/layout'
import { Box } from './styled'
import moment from 'moment'
import {
Tabs,
Modal,
Button,
Form,
message,
DatePicker,
Image as AImage,
Input,
Cascader,
} from 'antd'
import { RangePickerProps } from 'antd/es/date-picker'
import type { TabsProps } from 'antd'
import Evaluate from './components/evaluate'
import { useRouter } from 'next/router'
import api, { ListPageJobInfoResp } from './api'
import Image from 'next/image'
import { RegionResp } from '~/components/filter/api'
import AddressMap from './components/map'
const { RangePicker } = DatePicker
const { TextArea } = Input
export default function JobServicesDetail() {
const router = useRouter();
const router = useRouter()
const [id, setId] = useState<number | null>(null)
const [id, setId] = useState<number | null>(null);
const [detail,setDetail] = useState<ListPageJobInfoResp | null>()
const [sale,setSale] = useState<string | null>()
const [detail, setDetail] = useState<ListPageJobInfoResp | null>()
const [sale, setSale] = useState<string | null>()
const onChange = (key: string) => {
console.log(key);
};
console.log(key)
}
const items: TabsProps['items'] = [
{
key: '1',
label: `团队介绍`,
children: <div className='teamIntroduction'>
{/* <Image width={1100} height={800} src={detail?.teamPoster ? detail?.teamPoster : ''} alt='error'/> */}
<img style={{width:"100%"}} src={detail?.teamPoster ? detail?.teamPoster : ''} alt="error" />
</div>,
children: (
<div className="teamIntroduction">
{/* <Image width={1100} height={800} src={detail?.teamPoster ? detail?.teamPoster : ''} alt='error'/> */}
{/* <img
style={{ width: '100%' }}
src={detail?.teamPoster ? detail?.teamPoster : ''}
alt="error"
/> */}
{detail?.serviceIntroduction ? (
<div
dangerouslySetInnerHTML={{ __html: detail?.serviceIntroduction }}
></div>
) : null}
</div>
),
},
{
key: '2',
label: `团队评价`,
children: <Evaluate evaluateInfo={detail?.evaluateInfo || []}/>,
children: <Evaluate evaluateInfo={detail?.inspComtList || []} />,
},
];
useEffect(()=>{
]
useEffect(() => {
setId(Number(router.query.id))
},[router])
}, [router])
useEffect(() => {
if (id) {
api
.listDetailJobServicesInfo({id})
.then((res) => {
setDetail(res.result || null);
});
api.listDetailJobServicesInfo({ id }).then((res) => {
setDetail(res.result || null)
})
}
}, [id]);
}, [id])
useEffect(()=>{
useEffect(() => {
setSale((Math.floor(Math.random() * 901) + 100).toFixed(0))
},[])
}, [])
//预约弹框
const [visible, setVisible] = useState(false)
const [formDate] = Form.useForm()
const [isModalOpen, setIsModalOpen] = useState(false)
const [loading, setLoading] = useState(false)
const [provinceList, setProvinceList] = useState<RegionResp[]>([])
const [isAddressMapShow, setIsAddressMapShow] = useState(false)
const [addressContent, setAddressContent] = useState<any>()
useEffect(() => {
api.region().then((res) => {
console.log(res)
console.log(res?.result?.map((item) => item.childInfo).flat())
setProvinceList(res?.result || [])
})
}, [])
const disabledDate: RangePickerProps['disabledDate'] = (current) => {
return current && current < moment().endOf('day')
}
useEffect(() => {
//选择地点后重新验证
formDate.setFieldValue('latitudeAndLongitude', addressContent)
formDate.validateFields()
}, [addressContent])
const handleOk = () => {
setLoading(true)
formDate
.validateFields()
.then(async (values) => {
console.log(values)
if (!addressContent) {
return message.warning('请选择地点')
}
const res = await api.insertOrderTask({
address: addressContent.addressDteail,
taskDescription: values.taskDescription,
city: addressContent.city,
inspectionId: detail?.id || 1,
lat: addressContent.lat,
lon: addressContent.lon,
province: addressContent.province,
startTime: moment(new Date(values.dateDetail[0])).format(
'YYYY-MM-DD HH:MM:SS'
),
endTime: moment(new Date(values.dateDetail[1])).format(
'YYYY-MM-DD HH:MM:SS'
),
})
console.log(res)
if (res.code === '200') {
message.success('提交成功')
formDate.resetFields()
setAddressContent(undefined)
setLoading(false)
setIsModalOpen(false)
} else {
message.error(res.message)
setLoading(false)
}
})
.catch((err) => {
message
.warning({
content: err.errorFields[0].errors[0],
})
.then()
setLoading(false)
})
}
const handleCancel = () => {
setAddressContent(undefined)
setIsModalOpen(false)
formDate.resetFields()
}
return (
<Layout>
<Box>
<div className='top'>
<div className="top">
<div className="top-image">
<Image fill src={detail?.pictureUrl ? detail?.pictureUrl : ''} alt='error'/>
<Image
fill
src={detail?.coverPlan ? detail?.coverPlan : ''}
alt="error"
/>
</div>
<div className='top-right'>
<div className='right-top'>
<div className='title'>
{detail?.serviceName}
</div>
<div className='detail'>
<div className='tab'>专业飞手</div>
<span className='content'>飞手需通过认证培训才可作业</span>
</div>
<div className='more'>
<div className='tab filst'>测绘场景榜第1名</div>
<div className='tab'>7x24小时服务</div>
<div className='tab'>{`月售${sale}`}</div>
</div>
<div className="top-right">
<div className="right-top">
<div className="title">{detail?.serviceName}</div>
<div className="detail">
<div className="tab">专业飞手</div>
<span className="content">飞手需通过认证培训才可作业</span>
</div>
<div className='right-bottom'>
<div className='bottom-btn'>
<Button className='btn-left' size='small' type="primary">电话沟通</Button>
<Button className='btn-right' size='small' type="primary">立即预约</Button>
</div>
<div className="more">
<div className="tab filst">测绘场景榜第1名</div>
<div className="tab">7x24小时服务</div>
<div className="tab">{`月售${sale}`}</div>
</div>
</div>
<div className="right-bottom">
<div className="bottom-btn">
<Button className="btn-left" size="small" type="primary">
电话沟通
</Button>
<Button
onClick={() => setIsModalOpen(true)}
className="btn-right"
size="small"
type="primary"
>
立即预约
</Button>
</div>
</div>
</div>
</div>
<Tabs className='tabs' defaultActiveKey="1" items={items} onChange={onChange} />
<Tabs
className="tabs"
defaultActiveKey="1"
items={items}
onChange={onChange}
/>
<Modal
wrapClassName="reservation"
open={isModalOpen}
onOk={handleOk}
onCancel={handleCancel}
getContainer={false}
maskClosable={false}
width={420}
footer={[
<Button
style={{ width: '100%', height: 44 }}
key="submit"
type="primary"
loading={loading}
onClick={handleOk}
>
立即预约
</Button>,
]}
>
<div className="title">
<div className="left">
<AImage
preview={{ visible: false }}
src={detail?.coverPlan ? detail?.coverPlan : ''}
onClick={() => setVisible(true)}
style={{ width: 58, height: 58 }}
/>
<div style={{ display: 'none' }}>
<AImage.PreviewGroup
preview={{
visible,
onVisibleChange: (vis) => setVisible(vis),
}}
>
<AImage src={detail?.coverPlan ? detail?.coverPlan : ''} />
</AImage.PreviewGroup>
</div>
</div>
<div className="right">{detail?.serviceName}</div>
</div>
<Form
form={formDate}
layout="vertical"
name="reservationForm"
initialValues={{ modifier: 'public' }}
className="form-data"
>
<Form.Item
label="选择日期"
style={{ flex: 1, marginRight: 16 }}
name="dateDetail"
rules={[{ required: true, message: '请选择日期' }]}
>
<RangePicker
style={{ width: 376, marginTop: 10 }}
disabledDate={disabledDate}
/>
</Form.Item>
<Form.Item
label="选择地点"
style={{ flex: 1, marginRight: 16 }}
name="latitudeAndLongitude"
rules={[{ required: true, message: '请选择地点' }]}
>
{addressContent ? (
<div className="address-map">
<div className="value">
已选择:{addressContent.addressDteail}
</div>
<Button
onClick={() => setIsAddressMapShow(true)}
type="primary"
>
修改位置
</Button>
</div>
) : (
<Button onClick={() => setIsAddressMapShow(true)} type="text">
点击从地图选择地点
</Button>
)}
</Form.Item>
<div>
任务描述(选填) 项目号、 业务负责人、
客户名称、演示设备(注明飞机、挂载、地面站)、现场联系人及电话
</div>
<Form.Item
style={{ flex: 1, marginRight: 16 }}
name="taskDescription"
>
<TextArea
placeholder="补充描述有助于方案沟通更高效哦~"
autoSize={{ minRows: 3, maxRows: 5 }}
style={{ width: 385, height: 72 }}
/>
</Form.Item>
</Form>
</Modal>
{isAddressMapShow ? (
<Modal
wrapClassName="reservation"
open={isAddressMapShow}
onCancel={() => setIsAddressMapShow(false)}
getContainer={false}
maskClosable={false}
width={850}
footer={false}
>
<div style={{ textAlign: 'center', fontWeight: '700' }}>
选择地点
</div>
<AddressMap
setAddressContent={setAddressContent}
setIsAddressMapShow={setIsAddressMapShow}
/>
</Modal>
) : null}
</Box>
</Layout>
)
......
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 React, { useContext, useEffect, useState } from 'react'
import { OrderForGoodsBox } from './styled'
import type { FormInstance, RadioChangeEvent } from 'antd'
import { Button, Radio, Space, Input, message, Modal, Image } from 'antd'
import api, { UserAddress, GetOrderForGoods } from './api'
import moment from 'moment'
// import { ShopDetail } from '../../[id].page'
// import {
// GetWebDeviceDetailResult,
// GetWebDeviceWareSkuById,
// GetLeaseGoodsResult,
// } from '../../api'
import { UserContext } from '~/lib/userProvider'
const { TextArea } = Input
interface PropsBox {
setIsorderForGoods: (boolean: boolean) => void
mallDetail?: any
detailData?: any
shopDetail?: any
wareSkuList?: any
discount?: any
}
export default function OrderForGoods(props: PropsBox) {
const {
setIsorderForGoods,
shopDetail,
detailData,
wareSkuList,
discount,
mallDetail,
} = props
const [value, setValue] = useState(1)
const [areaValue, setAreaValue] = useState<string>()
const [list, setList] = useState<Array<UserAddress> | null>()
const onChange = (e: RadioChangeEvent) => {
console.log('radio checked', e.target.value)
setValue(e.target.value)
}
const onChangeValue = (index: number) => {
setValue(index)
}
const detailSumbit = () => {
if (!list?.length && !value) return message.warning('暂无地址信息')
if (list?.length && !value) return message.warning('请选择地址')
if (detailData && list && mallDetail) {
const pushList = {
buyNum: mallDetail.buyNum,
directoryId: mallDetail.directoryId,
goodsInfoId: mallDetail.goodsInfoId,
mallSpecIds: mallDetail.mallSpecIds,
userAddressId: value,
remark: areaValue,
}
api.FeignAddLease(pushList).then((res) => {
if (res.code === '200') {
message.success('提交成功')
setIsorderForGoods(false)
} else {
message.error(res.message)
}
})
}
}
useEffect(() => {
api
.listUserAddress({})
.then((res) => {
console.log(res)
setList(res.result)
res.result?.map((item, index) => {
if (item.type === 0) {
setValue(item.id)
}
})
})
.catch((err) => {
console.log(err)
})
}, [])
//图片预览
const [visible, setVisible] = useState(false)
//扫码管理地址
const [isAddAddressOpen, setIsAddAddressOpen] = useState(false)
const [addressVisible, setAddressVisible] = useState(false)
return (
<OrderForGoodsBox>
<div className="address">
<div className="top">
<div className="left">确认收货地址</div>
<div className="right">
<Button
onClick={() => setIsAddAddressOpen(true)}
type="link"
style={{ color: '#007aff' }}
>
管理收货地址
</Button>
</div>
</div>
<div className="bottom">
{list?.length ? (
list?.map((item, index) => (
<div
key={item.id}
className={`item ${value === item.id ? 'active' : ''}`}
onClick={() => onChangeValue(item.id)}
>
<div className="left">
<div className="active">
<div className="icon"></div>
<div className="label">寄送至</div>
</div>
<Radio.Group onChange={onChange} value={value}>
<Space direction="vertical">
<Radio value={item.id}>{item.takeAddress}</Radio>
</Space>
</Radio.Group>
</div>
{value === item.id ? (
<div className="right">
<Button
onClick={() => setIsAddAddressOpen(true)}
type="link"
style={{ color: '#007aff' }}
>
修改地址
</Button>
</div>
) : null}
</div>
))
) : (
<div className="item active">
<div className="left">
<div className="active">
<div className="icon"></div>
<div className="label">
暂无地址,请打开手机端【云享飞】微信小程序,【我的】-【个人设置】-【地址管理】添加
</div>
</div>
</div>
<div className="right">
<Button
onClick={() => setIsAddAddressOpen(true)}
type="link"
style={{ color: '#007aff' }}
>
添加地址
</Button>
</div>
</div>
)}
</div>
</div>
<div className="info">
<div className="title">确认订单信息</div>
<div className="table">
<div className="table-title">
<div className="table-item" style={{ width: 290 }}>
宝贝
</div>
<div className="table-item" style={{ width: 130 }}>
单价
</div>
<div className="table-item" style={{ width: 130 }}>
数量
</div>
<div className="table-item" style={{ width: 435 }}>
合计
</div>
</div>
{mallDetail.orderGoodsProdDetailDTOS.map((item: any) => (
<div className="table-body" key={item.id}>
<div className="body-item article" style={{ width: 290 }}>
<div className="image">
<Image
className="image-box"
preview={{ visible: false }}
src={item.prodSkuSpecImage || ''}
onClick={() => setVisible(true)}
/>
<div style={{ display: 'none' }}>
<Image.PreviewGroup
preview={{
visible,
onVisibleChange: (vis) => setVisible(vis),
}}
>
<Image src={item.prodSkuSpecImage || ''} />
</Image.PreviewGroup>
</div>
</div>
<div className="right">
<div className="top">
{`【${item.productName}】${item.specName}` || ''}
</div>
<div className="bottom">版本:{item.versionDesc || ''}</div>
<div className="bottom">料号:{item.partNo || ''}</div>
</div>
</div>
<div className="body-item" style={{ width: 130 }}>
{item.unitPrice || 0}
</div>
<div className="body-item" style={{ width: 130 }}>
{item.buyNum || 1}
</div>
<div className="body-item total-price" style={{ width: 435 }}>
{item.skuSpecAmount}
</div>
</div>
))}
</div>
</div>
<div className="notes">
<div className="left">
<div className="label">备注:</div>
<TextArea
value={areaValue}
onChange={(e) => setAreaValue(e.target.value)}
placeholder="请输入备注"
autoSize={{ minRows: 3, maxRows: 5 }}
style={{ width: 385, height: 72 }}
/>
</div>
<div className="right">
<div className="top">
<div className="font">
<div className="label">运费:</div>
<div className="value">邮寄到付,由客户自己承担</div>
</div>
<div className="price">0.00</div>
</div>
<div className="bottom">
<div className="font">
<div className="label">押金:</div>
<div className="value">渠道商可免押金</div>
</div>
<div className="price">0.00</div>
</div>
</div>
</div>
<div className="detail-box">
<div className="right-box">
<div className="detail">
<div className="top">
<div className="label">实付款</div>
<div className="price">¥{mallDetail.orderAmount}</div>
</div>
<div className="bottom">
<div className="value">寄送至</div>
{list ? (
<div className="value-content">{list![value]?.takeAddress}</div>
) : null}
</div>
</div>
<div className="detail-sumbit">
<Button className="btn" onClick={detailSumbit}>
提交订单
</Button>
</div>
</div>
</div>
<Modal
wrapClassName="addAddress"
open={isAddAddressOpen}
onCancel={() => setIsAddAddressOpen(false)}
getContainer={false}
maskClosable={false}
width={420}
footer={false}
>
<div className="title">扫码管理地址</div>
<div className="image">
<Image
className="addressImg"
preview={{ visible: false }}
src={
window.location.href.includes('https://test.iuav.shop/')
? 'https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/image/app-iuav-trial.jpg'
: 'https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/image/app-iuav-formal.jpg' ||
''
}
onClick={() => setAddressVisible(true)}
/>
<div style={{ display: 'none' }}>
<Image.PreviewGroup
preview={{
visible: addressVisible,
onVisibleChange: (vis) => setAddressVisible(vis),
}}
>
<Image
src={
window.location.href.includes('https://test.iuav.shop/')
? 'https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/image/app-iuav-trial.jpg'
: 'https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/image/app-iuav-formal.jpg' ||
''
}
/>
</Image.PreviewGroup>
</div>
</div>
<div className="content">
【打开微信扫一扫】-进入云享飞【我的】- 【个人设置】-【地址管理】
</div>
</Modal>
</OrderForGoodsBox>
)
}
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
import request, { Response } from "~/api/request"
export interface OrderDetailResp {
id: number;
orderNo: string;
createTime: number;
wareInfoId: number;
wareNo: string;
wareTitle: string;
wareImg: string;
skuInfoId?: any;
skuTitle?: any;
repoAccountId: number;
uid: string;
buyerName?: any;
buyerPhone: string;
unitPrice: number;
wareNum: number;
shouldPay: number; //应付款金额
actualPay: number; //实收款金额
orderType?: any;
deposit: number;
rentPrice: number;
startDate: number;
endDate: number;
payDay: number;
tranStatus: string;
exWare?: any;
remark: string;
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: string;
waiting: string;
leaseOrderStatus: string;
nickName: string;
wareDescription: string;
}
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 default {
//订单详情
orderDetail(params: {
orderNo: string
}): Promise<Response<OrderDetailResp>>{
return request('/oms/RentalOrders/orderDetail', 'get', params);
}
}
\ No newline at end of file
.font1 {
font-size: 36px;
font-family: Arial-BoldMT, Arial;
font-weight: normal;
color: #ff440e;
line-height: 42px;
}
.font2 {
font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff440e;
line-height: 25px;
}
.font3 {
font-size: 15px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #959595;
line-height: 21px;
}
.font4 {
font-size: 15px;
font-family: ArialMT;
color: #282828;
line-height: 21px;
}
.font5 {
font-size: 18px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #000000;
line-height: 25px;
}
.btn {
background: linear-gradient(90deg, #ff552d 0%, #ff812d 100%);
border-radius: 6px;
height: 40px;
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ffffff;
line-height: 22px;
width: 100%;
}
import { Button, Col, Divider, Modal, Row } from "antd";
import { useContext, useEffect, useState } from "react";
import { UserContext } from "~/lib/userProvider";
import api, { OrderDetailResp } from "./api";
import styles from "./index.module.scss";
function formatNumber(num: number) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
type Props = {
open?: boolean;
onOk?: () => void;
onCancel?: () => void;
orderNo?: string;
};
export default function PayModal(props: Props) {
const [data, setData] = useState<OrderDetailResp | null>(null);
const { userInfo } = useContext(UserContext);
useEffect(() => {
if (props.orderNo) {
api.orderDetail({ orderNo: props.orderNo }).then((res) => {
setData(res.result || null);
});
} else {
setData(null);
}
}, [props.orderNo]);
return (
<>
<Modal
width={420}
open={props.open}
onOk={props.onOk}
onCancel={props.onCancel}
title={
<>
<div style={{ textAlign: "center" }} className={styles.font5}>
租赁付款
</div>
</>
}
footer={
<Button
type="primary"
className={styles.btn}
style={{ marginTop: 43 }}
>
立即付款
</Button>
}
>
<div
style={{ marginTop: 16, marginBottom: 34, textAlign: "center" }}
className={styles.font1}
>
{formatNumber(data?.shouldPay || 0)}{" "}
<span
className={styles.font2}
style={{ transform: "translateY(-3px)", display: "inline-block" }}
>
</span>
</div>
<Row gutter={[0, 16]}>
<Col span={6} className={styles.font3}>
云仓账号
</Col>
<Col span={18} className={styles.font4}>
UID{userInfo?.uid}
</Col>
<Col span={6} className={styles.font3}>
付款方式
</Col>
<Col span={18} className={styles.font4}>
充值余额(可用:¥2000000)
</Col>
</Row>
</Modal>
</>
);
}
import request, { Response } from "~/api/request"
export interface OrderDetailResp {
id: number;
orderNo: string;
createTime: number;
wareInfoId: number;
wareNo: string;
wareTitle: string;
wareImg: string;
skuInfoId?: any;
skuTitle?: any;
repoAccountId: number;
uid: string;
buyerName?: any;
buyerPhone: string;
unitPrice: number;
wareNum: number;
shouldPay: number; //应付款金额
actualPay: number; //实收款金额
orderType?: any;
deposit: number;
rentPrice: number;
startDate: number;
endDate: number;
payDay: number;
tranStatus: string;
exWare?: any;
remark: string;
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: string;
waiting: string;
leaseOrderStatus: string;
nickName: string;
wareDescription: string;
}
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 UserWalletResp {
id: number;
repoAccountId: number;
cashAmt: number;
cashPaid: number;
cashFreeze: number;
remark?: any;
phoneNum?: any;
userName?: any;
nickName?: any;
portType?: any;
uid?: any;
}
export default {
//订单详情
orderDetail(params: {
orderNo: string
}): Promise<Response<OrderDetailResp>> {
return request('/oms/RentalOrders/orderDetail', 'get', params);
},
//获取用户钱包
userWallet(): Promise<Response<UserWalletResp>> {
return request('/payment/repocash/userWallet')
},
//租赁——订单支付
orderPayment(params: { orderNo: string }) {
return request('/payment/repocash/orderPayment', 'post', params)
}
}
\ No newline at end of file
.font1 {
font-size: 36px;
font-family: Arial-BoldMT, Arial;
font-weight: normal;
color: #ff440e;
line-height: 42px;
}
.font2 {
font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff440e;
line-height: 25px;
}
.font3 {
font-size: 15px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #959595;
line-height: 21px;
}
.font4 {
font-size: 15px;
font-family: ArialMT;
color: #282828;
line-height: 21px;
}
.font5 {
font-size: 18px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #000000;
line-height: 25px;
}
.btn {
background: linear-gradient(90deg, #ff552d 0%, #ff812d 100%);
border-radius: 6px;
height: 40px;
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ffffff;
line-height: 22px;
width: 100%;
}
import { Button, Col, Divider, message, Modal, Row } from "antd";
import { useContext, useEffect, useState } from "react";
import { UserContext } from "~/lib/userProvider";
import api, { OrderDetailResp, UserWalletResp } from "./api";
import styles from "./index.module.scss";
function formatNumber(num: number) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
type Props = {
open?: boolean;
onOk?: () => void;
onCancel?: () => void;
orderNo?: string;
};
export default function PayModal(props: Props) {
const [data, setData] = useState<OrderDetailResp | null>(null);
const { userInfo } = useContext(UserContext);
const [wallet, setWallet] = useState<UserWalletResp | null>(null); //钱包
const [loading, setLoading] = useState(false); //付款按钮loading
useEffect(() => {
if (props.open) {
api.userWallet().then((res) => {
setWallet(res.result || null);
});
}
}, [props.open]);
useEffect(() => {
if (props.orderNo) {
api.orderDetail({ orderNo: props.orderNo }).then((res) => {
setData(res.result || null);
});
} else {
setData(null);
}
}, [props.orderNo]);
function onPay() {
if (props.orderNo) {
setLoading(true);
api
.orderPayment({
orderNo: props.orderNo,
})
.then((res) => {
if (res.code == "200") {
message.success("付款成功");
setTimeout(() => {
props.onCancel && props.onCancel();
setLoading(false);
}, 1000);
}else{
res.message && message.error(res.message);
setLoading(false);
}
}).catch(err=> {
setLoading(false);
});
}
}
return (
<>
<Modal
width={420}
open={props.open}
onOk={props.onOk}
onCancel={props.onCancel}
title={
<>
<div style={{ textAlign: "center" }} className={styles.font5}>
租赁付款
</div>
</>
}
footer={
<Button
type="primary"
className={styles.btn}
style={{ marginTop: 43 }}
onClick={onPay}
loading={loading}
>
立即付款
</Button>
}
>
<div
style={{ marginTop: 16, marginBottom: 34, textAlign: "center" }}
className={styles.font1}
>
{formatNumber(data?.shouldPay || 0)}{" "}
<span
className={styles.font2}
style={{ transform: "translateY(-3px)", display: "inline-block" }}
>
</span>
</div>
<Row gutter={[0, 16]}>
<Col span={6} className={styles.font3}>
云仓账号
</Col>
<Col span={18} className={styles.font4}>
UID{userInfo?.uid}
</Col>
<Col span={6} className={styles.font3}>
付款方式
</Col>
<Col span={18} className={styles.font4}>
充值余额(可用:¥{wallet?.cashAmt}
</Col>
</Row>
</Modal>
</>
);
}
import request, { Response } from "~/api/request"
export interface OrderDetailResp {
id: number;
orderNo: string;
createTime: number;
wareInfoId: number;
wareNo: string;
wareTitle: string;
wareImg: string;
skuInfoId?: any;
skuTitle?: any;
repoAccountId: number;
uid: string;
buyerName?: any;
buyerPhone: string;
unitPrice: number;
wareNum: number;
shouldPay: number; //应付款金额
actualPay: number; //实收款金额
orderType?: any;
deposit: number;
rentPrice: number;
startDate: number;
endDate: number;
payDay: number;
tranStatus: string;
exWare?: any;
remark: string;
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: string;
waiting: string;
leaseOrderStatus: string;
nickName: string;
wareDescription: string;
}
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 UserWalletResp {
id: number;
repoAccountId: number;
cashAmt: number;
cashPaid: number;
cashFreeze: number;
remark?: any;
phoneNum?: any;
userName?: any;
nickName?: any;
portType?: any;
uid?: any;
}
export default {
//订单详情
orderDetail(params: {
orderNo: string
}): Promise<Response<OrderDetailResp>> {
return request('/oms/RentalOrders/orderDetail', 'get', params);
},
//获取用户钱包
userWallet(): Promise<Response<UserWalletResp>> {
return request('/payment/repocash/userWallet')
},
//租赁——订单支付
orderPayment(params: { orderNo: string }) {
return request('/payment/repocash/orderPayment', 'post', params)
}
}
\ No newline at end of file
.font1 {
font-size: 36px;
font-family: Arial-BoldMT, Arial;
font-weight: normal;
color: #ff440e;
line-height: 42px;
}
.font2 {
font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff440e;
line-height: 25px;
}
.font3 {
font-size: 15px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #959595;
line-height: 21px;
}
.font4 {
font-size: 15px;
font-family: ArialMT;
color: #282828;
line-height: 21px;
}
.font5 {
font-size: 18px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #000000;
line-height: 25px;
}
.btn {
background: linear-gradient(90deg, #ff552d 0%, #ff812d 100%);
border-radius: 6px;
height: 40px;
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ffffff;
line-height: 22px;
width: 100%;
}
import { Button, Col, Divider, message, Modal, Row } from "antd";
import { useContext, useEffect, useState } from "react";
import { UserContext } from "~/lib/userProvider";
import api, { OrderDetailResp, UserWalletResp } from "./api";
import styles from "./index.module.scss";
function formatNumber(num: number) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
type Props = {
open?: boolean;
onOk?: () => void;
onCancel?: () => void;
orderNo?: string;
};
export default function RefundModal(props: Props) {
const [data, setData] = useState<OrderDetailResp | null>(null);
const { userInfo } = useContext(UserContext);
const [wallet, setWallet] = useState<UserWalletResp | null>(null); //钱包
const [loading, setLoading] = useState(false); //付款按钮loading
useEffect(() => {
if (props.open) {
api.userWallet().then((res) => {
setWallet(res.result || null);
});
}
}, [props.open]);
useEffect(() => {
if (props.orderNo) {
api.orderDetail({ orderNo: props.orderNo }).then((res) => {
setData(res.result || null);
});
} else {
setData(null);
}
}, [props.orderNo]);
function onPay() {
if (props.orderNo) {
setLoading(true);
api
.orderPayment({
orderNo: props.orderNo,
})
.then((res) => {
if (res.code == "200") {
message.success("付款成功");
setTimeout(() => {
props.onCancel && props.onCancel();
setLoading(false);
}, 1000);
} else {
res.message && message.error(res.message);
setLoading(false);
}
})
.catch((err) => {
setLoading(false);
});
}
}
return (
<>
<Modal
width={420}
open={props.open}
onOk={props.onOk}
onCancel={props.onCancel}
title={
<>
<div style={{ textAlign: "center" }} className={styles.font5}>
租赁付款
</div>
</>
}
footer={
<Button
type="primary"
className={styles.btn}
style={{ marginTop: 43 }}
onClick={onPay}
loading={loading}
>
立即付款
</Button>
}
>
<div
style={{ marginTop: 16, marginBottom: 34, textAlign: "center" }}
className={styles.font1}
>
{formatNumber(data?.shouldPay || 0)}{" "}
<span
className={styles.font2}
style={{ transform: "translateY(-3px)", display: "inline-block" }}
>
</span>
</div>
<Row gutter={[0, 16]}>
<Col span={6} className={styles.font3}>
云仓账号
</Col>
<Col span={18} className={styles.font4}>
UID{userInfo?.uid}
</Col>
<Col span={6} className={styles.font3}>
付款方式
</Col>
<Col span={18} className={styles.font4}>
充值余额(可用:¥{wallet?.cashAmt}
</Col>
</Row>
</Modal>
</>
);
}
@import "~/styles/mixins.scss";
.font1 {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #9b9b9b;
line-height: 19px;
}
.font2 {
font-size: 12px;
font-family: Arial-BoldMT, Arial;
font-weight: normal;
color: #626262;
line-height: 14px;
}
.font3 {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6c6c6c;
line-height: 20px;
}
.font4 {
font-size: 14px;
font-family: ArialMT;
color: #141414;
line-height: 16px;
}
.font5 {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #929295;
line-height: 17px;
}
.font6 {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #070707;
line-height: 20px;
}
.font7 {
font-size: 13px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #070707;
line-height: 16px;
}
.btn1 {
border-radius: 16px;
border: 1px solid #ff552d;
padding: 6px 16px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff552d;
line-height: 20px;
}
.btn2 {
border-radius: 16px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ffffff;
line-height: 20px;
padding: 6px 16px;
}
import {
TabsProps,
Tabs,
Row,
Col,
Image,
Space,
Button,
Pagination,
Empty,
Spin,
} from "antd";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import errImg from "~/assets/errImg";
import LayoutView from "~/components/layout";
import Sider from "../components/sider";
import styles from "./index.module.scss";
import api, { LeasingList, ListTranStatusResp } from "./api";
import moment from "moment";
import PayModal from "./components/payModal";
import RefundModal from "./components/refundModal";
import Moment from 'moment';
const items: TabsProps["items"] = [
{
key: "",
label: `全部`,
},
{
key: "100",
label: `待付款`,
},
{
key: "200",
label: `待发货`,
},
{
key: "400",
label: `租赁中`,
},
{
key: "500",
label: `归还中`,
},
{
key: "600",
label: `已完成`,
},
{
key: "700",
label: `退款/售后`,
},
{
key: "999",
label: `已关闭`,
},
];
export default function LeasingOrders() {
const router = useRouter();
const [pageParams, setPageParams] = useState({
pageNo: 1,
pageSize: 5,
}); //分页器对象
const [total, setTotal] = useState(0); //总数
const [abort, setAbort] = useState<AbortController | null>(null); //请求中断对你
const [tabKey, setTabKey] = useState("");
const [orderList, setOrderList] = useState<LeasingList[]>([]);
const [loading, setLoading] = useState(false);
const [tranStatusMap, setTranStatusMap] = useState<ListTranStatusResp[]>([]); //订单状态字典
const [openPayModal, setOpenPayModal] = useState(false); //支付弹窗
const [openRefundModal, setOpenRefundModal] = useState(false); //退款弹窗
const [orderNo, setOrderNo] = useState<string | undefined>();
//获取订单状态字典
useEffect(() => {
api.listTranStatus().then((res) => {
setTranStatusMap(res.result || []);
});
}, []);
useEffect(() => {
//中断前一次列表请求
abort?.abort();
setAbort(new AbortController());
}, [pageParams]);
//商品列表请求
useEffect(() => {
if (!abort) {
return;
}
setLoading(true);
api
.listPageWechatOrder(
{
...pageParams,
tranStatus: tabKey,
},
{
signal: abort?.signal,
}
)
.then((res) => {
setOrderList(res.result?.list || []);
setTotal(res.result?.totalCount || 0);
setLoading(false);
});
}, [abort]);
const onPageChange = (page: number, pageSize: number) => {
setPageParams({
...pageParams,
pageNo: page,
});
};
const onTabsChange = (key: string) => {
setTabKey(key);
setPageParams({
...pageParams,
pageNo: 1,
});
setTotal(0);
};
// 交易状态对应的按钮渲染
const statusBtn = function (item: LeasingList) {
switch (item.tranStatus) {
case "100":
return (
<Button
className={styles.btn2}
type="primary"
onClick={() => {
setOrderNo(item.orderNo);
setOpenPayModal(true);
}}
>
立即付款
</Button>
);
case "200":
return (
<Button
className={styles.btn1}
onClick={() => {
setOrderNo(item.orderNo);
setOpenRefundModal(true);
}}
>
申请退款
</Button>
);
case "300":
return (
<Space size={0} direction="vertical" align="center">
<Button className={styles.btn2} type="primary">
确认收货
</Button>
<Button type="link" style={{ fontSize: 10 }}>
查看物流
</Button>
</Space>
);
case "400":
return (
<Space size={0} direction="vertical" align="center">
<Button className={styles.btn2} type="primary">
商品归还
</Button>
<Button type="link" style={{ fontSize: 10 }}>
查看物流
</Button>
</Space>
);
case "500":
<Button type="link" style={{ marginTop: 10 }}>
查看物流
</Button>;
case "600":
return <Button className={styles.btn1}>再来一单</Button>;
}
};
return (
<>
<LayoutView
layoutStyle={{ backgroundColor: "#fff" }}
contentStyle={{ width: 1000, marginLeft: 526 }}
headerStyle={{ borderBottom: "1px solid #e2e2e2" }}
>
<Sider
style={{
position: "absolute",
left: -37,
top: 15,
transform: "translateX(-100%)",
}}
selectedKeys={[router.pathname]}
></Sider>
<div style={{ paddingTop: 19 }}>
<div className={styles.font1}>租赁订单</div>
<Tabs activeKey={tabKey} items={items} onChange={onTabsChange} />
<Spin spinning={loading} delay={500}>
<ul className={styles.orderList} style={{ minHeight: 650 }}>
{orderList.map((item) => {
return (
<li key={item.id} className={styles.orderItem}>
<Row
justify="space-between"
align="middle"
style={{
height: 30,
padding: "0 26px 0 16px",
background: "#EBF8FF",
}}
>
<div className={styles.font2}>
<Space size={10}>
<div>
{Moment(item.startDate).format("YYYY-MM-DD")}{" "}
{Moment(item.endDate).format("YYYY-MM-DD")}
</div>
<div>订单编号: {item.orderNo}</div>
</Space>{" "}
</div>
<div className={styles.font3}>
{
tranStatusMap.find(
(sItem) => sItem.status === item.tranStatus
)?.waiting
}
</div>
</Row>
<Row
style={{ minHeight: 100, border: "1px solid #D0EAF5" }}
>
<Col style={{ width: 380 }}>
<Row>
<div style={{ margin: "10px 10px 0 16px" }}>
<Image
width={80}
height={80}
preview={false}
fallback={errImg}
src={item.wareImg}
></Image>
</div>
<div style={{ marginTop: 12 }}>
<div className={`ellipsis1 ${styles.font4}`}>
{item.wareTitle}
</div>
<div
className={`${styles.font5} ${styles.ellipse2}`}
style={{ marginTop: 5 }}
>
{item.wareDescription}
</div>
</div>
</Row>
</Col>
<Col
style={{
width: 270,
borderLeft: "1px solid #D0EAF5",
borderRight: "1px solid #D0EAF5",
}}
>
<Row
justify={"center"}
align="middle"
style={{ height: "100%" }}
>
<div style={{ textAlign: "center" }}>
<div
className={styles.font7}
style={{ marginBottom: 7 }}
>
¥{item.shouldPay}
</div>
<div className={styles.font6}>
租期:{" "}
{moment(item.endDate).diff(
item.startDate,
"days"
)}
</div>
<div className={styles.font6}>
数量: {item.wareNum}
</div>
</div>
</Row>
</Col>
<Col flex={"auto"} style={{}}>
<Space
size={7}
style={{
float: "right",
marginTop: 20,
marginRight: 24,
}}
>
{statusBtn(item)}
</Space>
</Col>
</Row>
</li>
);
})}
{orderList.length === 0 && (
<Empty
style={{
paddingTop: 20,
width: "100%",
textAlign: "center",
}}
></Empty>
)}
</ul>
</Spin>
<Pagination
current={pageParams.pageNo}
showSizeChanger={false}
showQuickJumper
total={total}
pageSize={pageParams.pageSize}
onChange={onPageChange}
hideOnSinglePage={true}
style={{ marginTop: 20 }}
></Pagination>
</div>
</LayoutView>
<PayModal
open={openPayModal}
onCancel={() => setOpenPayModal(false)}
orderNo={orderNo}
></PayModal>
<RefundModal
open={openRefundModal}
onCancel={() => setOpenRefundModal(false)}
orderNo={orderNo}
></RefundModal>
</>
);
}
import request, { Response } from "~/api/request"
export interface ListPageParams {
keyword?: string,
showType: number,
pageNo: number;
pageSize: number;
}
export interface ListPageResp {
pageNo: number;
pageSize: number;
list: OrderList[];
totalCount: number;
totalPage: number;
}
export interface OrderList {
id: number;
orderNo: string;
orderMainImg: string;
orderName: string;
totalBuyNum: number;
orderAmount: number;
statusCode: number;
signStatus?: any;
operationName?: any;
operationId?: any;
deliveryTime?: any;
contractNo?: any;
userAccountId: number;
uid?: any;
userName?: any;
phoneNum?: any;
payMethod: number;
contractSignedWay?: any;
createTime: string;
recMallUserName?: any;
ogSkuSpecDTOList: OgSkuSpecDTOList[];
remark: string;
creditPeriod?: any;
entName?: any;
saleId?: any;
saleName?: any;
tagName?: any;
realNameAuth?: any;
realPayAmount?: any;
subAmount?: any;
shareId?: any;
shareStatus: number;
deductAmount?: any;
discountAmount?: any;
realityAmount?: any;
shutReason?: any;
mallOrderProdListDTOList: MallOrderProdListDTOList[];
mremark?: any;
}
interface MallOrderProdListDTOList {
id: number;
goodsInfoId: number;
productName: string;
model?: any;
prodSkuSpecName: string;
prodSkuSpecImage: string;
partNo: string;
versionDesc: string;
buyNum: number;
unitPrice: number;
skuSpecAmount: number;
}
interface OgSkuSpecDTOList {
id: number;
directoryId: number;
shopCarId?: any;
skuSpecName: string;
}
export interface ListStatusResp {
status: string;
code: number;
nextCode: number;
}
export default {
//v1.0.0订单列表-查询
listPage(params: ListPageParams, options: any): Promise<Response<ListPageResp>> {
return request('/oms/app-order/listPage', 'get', params, options)
},
//订单状态-字典
listStatus(): Promise<Response<ListStatusResp[]>> {
return request('/oms/mallorder/listStatus', 'get');
}
}
\ No newline at end of file
@import "~/styles/mixins.scss";
.font1 {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #9b9b9b;
line-height: 19px;
}
.font2 {
font-size: 12px;
font-family: Arial-BoldMT, Arial;
font-weight: normal;
color: #626262;
line-height: 14px;
}
.font3 {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6c6c6c;
line-height: 20px;
}
.font4 {
font-size: 14px;
font-family: ArialMT;
color: #141414;
line-height: 16px;
}
.font5 {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #929295;
line-height: 17px;
}
.btn1 {
border-radius: 16px;
border: 1px solid #ff552d;
padding: 6px 16px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff552d;
line-height: 20px;
}
.btn2 {
border-radius: 16px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ffffff;
line-height: 20px;
padding: 6px 16px;
}
import {
TabsProps,
Tabs,
Row,
Col,
Image,
Space,
Button,
Spin,
Pagination,
Empty,
} from "antd";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import errImg from "~/assets/errImg";
import Right from "~/components/contentBox/right";
import LayoutView from "~/components/layout";
import Sider from "../components/sider";
import api, { OrderList, ListStatusResp } from "./api";
import styles from "./index.module.scss";
const items: TabsProps["items"] = [
{
key: "",
label: `全部`,
},
{
key: "0",
label: `意向沟通`,
},
{
key: "1",
label: `签约付款`,
},
{
key: "2",
label: `待发货`,
},
{
key: "3",
label: `待收货`,
},
];
export default function LeasingOrder() {
const router = useRouter();
const [pageParams, setPageParams] = useState({
pageNo: 1,
pageSize: 5,
}); //分页器对象
const [total, setTotal] = useState(0); //总数
const [abort, setAbort] = useState<AbortController | null>(null); //请求中断对你
const [tabKey, setTabKey] = useState("");
const [orderList, setOrderList] = useState<OrderList[]>([]);
const [loading, setLoading] = useState(false);
const [orderNo, setOrderNo] = useState<string | undefined>();
const [tranStatusMap, setTranStatusMap] = useState<ListStatusResp[]>([]); //订单状态字典
//获取订单状态字典
useEffect(() => {
api.listStatus().then((res) => {
setTranStatusMap(res.result || []);
});
}, []);
useEffect(() => {
//中断前一次列表请求
abort?.abort();
setAbort(new AbortController());
}, [pageParams]);
//商品列表请求
useEffect(() => {
if (!abort) {
return;
}
setLoading(true);
api
.listPage(
{
...pageParams,
showType: Number(tabKey),
},
{
signal: abort?.signal,
}
)
.then((res) => {
setOrderList(res.result?.list || []);
setTotal(res.result?.totalCount || 0);
setLoading(false);
});
}, [abort]);
const onPageChange = (page: number, pageSize: number) => {
setPageParams({
...pageParams,
pageNo: page,
});
};
const onTabsChange = (key: string) => {
setTabKey(key);
setPageParams({
...pageParams,
pageNo: 1,
});
setTotal(0);
};
return (
<>
<LayoutView
layoutStyle={{ backgroundColor: "#fff" }}
contentStyle={{ width: 1000, marginLeft: 526 }}
headerStyle={{ borderBottom: "1px solid #e2e2e2" }}
>
<Sider
style={{
position: "absolute",
left: -37,
top: 15,
transform: "translateX(-100%)",
}}
selectedKeys={[router.pathname]}
></Sider>
<div style={{ paddingTop: 19 }}>
<div className={styles.font1}>商城订单</div>
<Tabs activeKey={tabKey} items={items} onChange={onTabsChange} />
<Spin spinning={loading} delay={500}>
<ul className={styles.orderList} style={{ minHeight: 650 }}>
{orderList.map((item) => {
return (
<li key={item.id} className={styles.orderItem}>
<Row
justify="space-between"
align="middle"
style={{
height: 30,
padding: "0 26px 0 16px",
background: "#EBF8FF",
}}
>
<div className={styles.font2}>
<Space size={10}>
<div>{item.createTime}</div>
<div>订单编号: {item.orderNo}</div>
</Space>
</div>
<div className={styles.font3}>
{
tranStatusMap.find(
(status) => status.code === item.statusCode
)?.status
}
</div>
</Row>
<Row
style={{ minHeight: 100, border: "1px solid #D0EAF5" }}
>
<Col style={{ width: 380 }}>
<Row>
<div style={{ margin: "10px 10px 0 16px" }}>
<Image
width={80}
height={80}
preview={false}
fallback={errImg}
src={item.orderMainImg}
></Image>
</div>
<div style={{ marginTop: 12 }}>
<div className={`ellipsis1 ${styles.font4}`}>
{item.orderName}
</div>
{item.mallOrderProdListDTOList.map((spec) => {
return (
<div
key={spec.id}
className={styles.font5}
style={{ marginTop: 5 }}
>
{spec.prodSkuSpecName}: {spec.productName}
</div>
);
})}
</div>
</Row>
</Col>
<Col
style={{
width: 270,
borderLeft: "1px solid #D0EAF5",
borderRight: "1px solid #D0EAF5",
}}
>
<Row
justify={"center"}
align="middle"
style={{ height: "100%" }}
>
数量: {item.totalBuyNum}
</Row>
</Col>
<Col flex={"auto"} style={{}}>
<Space
size={7}
style={{
float: "right",
marginTop: 20,
marginRight: 24,
}}
>
<Button className={styles.btn1}>取消订单</Button>
<Button className={styles.btn2} type="primary">
查看合同
</Button>
</Space>
</Col>
</Row>
</li>
);
})}
{orderList.length === 0 && (
<Empty
style={{
paddingTop: 20,
width: "100%",
textAlign: "center",
}}
></Empty>
)}
</ul>
</Spin>
<Pagination
current={pageParams.pageNo}
showSizeChanger={false}
showQuickJumper
total={total}
pageSize={pageParams.pageSize}
onChange={onPageChange}
hideOnSinglePage={true}
style={{ marginTop: 20 }}
></Pagination>
</div>
</LayoutView>
</>
);
}
import request, { Response } from "~/api/request"
export interface QueryOrderTaskListParams {
orderStatus?: number;
pageNo: number;
pageSize: number;
}
export interface QueryOrderTaskListResp {
pageNo: number;
pageSize: number;
list: OrderList[];
totalCount: number;
totalPage: number;
}
export interface OrderList {
id: number;
address: string;
city: string;
endTime: string;
images: any[];
inspectionId: number;
lat: number;
lon: number;
orderAmt: number;
orderName: string;
orderStatus: number,
orderNo: string;
province: string;
startTime: string;
taskDescription: string;
coverPlan: string;
}
export interface GetServiceOrderStatusResp {
id: number;
orderStatus: number;
userPort: string;
flyerPort: string;
managePort: string;
}
export default {
//查询服务订单列表
queryOrderTaskList(params: QueryOrderTaskListParams, options: any): Promise<Response<QueryOrderTaskListResp>> {
return request('/oms/serviceOrderTask/queryOrderTaskList', 'post', params, options)
},
//订单状态-字典
getServiceOrderStatus(): Promise<Response<GetServiceOrderStatusResp[]>> {
return request('/oms/serviceOrderTask/getServiceOrderStatus', 'POST');
}
}
\ No newline at end of file
@import "~/styles/mixins.scss";
.font1 {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #9b9b9b;
line-height: 19px;
}
.font2 {
font-size: 12px;
font-family: Arial-BoldMT, Arial;
font-weight: normal;
color: #626262;
line-height: 14px;
}
.font3 {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6c6c6c;
line-height: 20px;
}
.font4 {
font-size: 14px;
font-family: ArialMT;
color: #141414;
line-height: 16px;
}
.font5 {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #929295;
line-height: 17px;
}
.font6 {
font-size: 13px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #070707;
line-height: 16px;
}
.btn1 {
border-radius: 16px;
border: 1px solid #ff552d;
padding: 6px 16px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff552d;
line-height: 20px;
}
.btn2 {
border-radius: 16px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ffffff;
line-height: 20px;
padding: 6px 16px;
}
import {
TabsProps,
Tabs,
Row,
Col,
Image,
Space,
Button,
Spin,
Pagination,
Empty,
} from "antd";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import errImg from "~/assets/errImg";
import Right from "~/components/contentBox/right";
import LayoutView from "~/components/layout";
import Sider from "../components/sider";
import api, { OrderList, GetServiceOrderStatusResp } from "./api";
import styles from "./index.module.scss";
import Moment from "moment";
const items: TabsProps["items"] = [
{
key: "",
label: `全部`,
},
{
key: "200",
label: `待付款`,
},
{
key: "575",
label: `待验收`,
},
{
key: "700",
label: `已完成`,
},
{
key: "900",
label: `已取消`,
},
];
export default function ServicesOrder() {
const router = useRouter();
const [pageParams, setPageParams] = useState({
pageNo: 1,
pageSize: 5,
}); //分页器对象
const [total, setTotal] = useState(0); //总数
const [abort, setAbort] = useState<AbortController | null>(null); //请求中断对你
const [tabKey, setTabKey] = useState("");
const [orderList, setOrderList] = useState<OrderList[]>([]);
const [loading, setLoading] = useState(false);
const [orderNo, setOrderNo] = useState<string | undefined>();
const [tranStatusMap, setTranStatusMap] = useState<
GetServiceOrderStatusResp[]
>([]); //订单状态字典
//获取订单状态字典
useEffect(() => {
api.getServiceOrderStatus().then((res) => {
setTranStatusMap(res.result || []);
});
}, []);
useEffect(() => {
//中断前一次列表请求
abort?.abort();
setAbort(new AbortController());
}, [pageParams]);
//商品列表请求
useEffect(() => {
if (!abort) {
return;
}
setLoading(true);
api
.queryOrderTaskList(
{
...pageParams,
orderStatus: Number(tabKey),
},
{
signal: abort?.signal,
}
)
.then((res) => {
console.log(", res.result?.list", res.result?.list);
setOrderList(res.result?.list || []);
setTotal(res.result?.totalCount || 0);
setLoading(false);
});
}, [abort]);
const onPageChange = (page: number, pageSize: number) => {
setPageParams({
...pageParams,
pageNo: page,
});
};
const onTabsChange = (key: string) => {
setTabKey(key);
setPageParams({
...pageParams,
pageNo: 1,
});
setTotal(0);
};
return (
<>
<LayoutView
layoutStyle={{ backgroundColor: "#fff" }}
contentStyle={{ width: 1000, marginLeft: 526 }}
headerStyle={{ borderBottom: "1px solid #e2e2e2" }}
>
<Sider
style={{
position: "absolute",
left: -37,
top: 15,
transform: "translateX(-100%)",
}}
selectedKeys={[router.pathname]}
></Sider>
<div style={{ paddingTop: 19 }}>
<div className={styles.font1}>服务订单</div>
<Tabs activeKey={tabKey} items={items} onChange={onTabsChange} />
<Spin spinning={loading} delay={500}>
<ul className={styles.orderList} style={{ minHeight: 650 }}>
{orderList.map((item) => {
return (
<li key={item.id} className={styles.orderItem}>
<Row
justify="space-between"
align="middle"
style={{
height: 30,
padding: "0 26px 0 16px",
background: "#EBF8FF",
}}
>
<div className={styles.font2}>
<Space size={10}>
<div>
{Moment(item.startTime).format("YYYY-MM-DD")}{" "}
{Moment(item.endTime).format("YYYY-MM-DD")}
</div>
<div>订单编号: {item.orderNo}</div>
</Space>
</div>
<div className={styles.font3}>
{
tranStatusMap.find(
(status) => status.orderStatus === item.orderStatus
)?.userPort
}
</div>
</Row>
<Row
style={{ minHeight: 100, border: "1px solid #D0EAF5" }}
>
<Col style={{ width: 380 }}>
<Row>
<div style={{ margin: "10px 10px 0 16px" }}>
<Image
width={80}
height={80}
preview={false}
fallback={errImg}
src={item.coverPlan}
></Image>
</div>
<div style={{ marginTop: 12 }}>
<div className={`ellipsis1 ${styles.font4}`}>
{item.orderName}
</div>
</div>
</Row>
</Col>
<Col
style={{
width: 270,
borderLeft: "1px solid #D0EAF5",
borderRight: "1px solid #D0EAF5",
}}
>
<Row
justify={"center"}
align="middle"
style={{ height: "100%" }}
>
预付金额:{" "}
<span className={styles.font6}>¥{item.orderAmt}</span>
</Row>
</Col>
<Col flex={"auto"} style={{}}>
<Space
size={7}
style={{
float: "right",
marginTop: 20,
marginRight: 24,
}}
>
<Space direction="vertical" size={0} align="center">
<Button className={styles.btn2} type="primary">
预付款
</Button>
<Button type="text">取消订单</Button>
</Space>
</Space>
</Col>
</Row>
</li>
);
})}
{orderList.length === 0 && (
<Empty
style={{
paddingTop: 20,
width: "100%",
textAlign: "center",
}}
></Empty>
)}
</ul>
</Spin>
<Pagination
current={pageParams.pageNo}
showSizeChanger={false}
showQuickJumper
total={total}
pageSize={pageParams.pageSize}
onChange={onPageChange}
hideOnSinglePage={true}
style={{ marginTop: 20 }}
></Pagination>
</div>
</LayoutView>
</>
);
}
import request, { Response } from "~/api/request"
export interface ListPageParams {
keyword?: string,
showType: number,
pageNo: number;
pageSize: number;
}
export interface ListPageResp {
pageNo: number;
pageSize: number;
list: OrderList[];
totalCount: number;
totalPage: number;
}
export interface OrderList {
id: number;
orderNo: string;
orderMainImg: string;
orderName: string;
totalBuyNum: number;
orderAmount: number;
statusCode: number;
signStatus?: any;
operationName?: any;
operationId?: any;
deliveryTime?: any;
contractNo?: any;
userAccountId: number;
uid?: any;
userName?: any;
phoneNum?: any;
payMethod: number;
contractSignedWay?: any;
createTime: string;
recMallUserName?: any;
ogSkuSpecDTOList: OgSkuSpecDTOList[];
remark: string;
creditPeriod?: any;
entName?: any;
saleId?: any;
saleName?: any;
tagName?: any;
realNameAuth?: any;
realPayAmount?: any;
subAmount?: any;
shareId?: any;
shareStatus: number;
deductAmount?: any;
discountAmount?: any;
realityAmount?: any;
shutReason?: any;
mallOrderProdListDTOList: MallOrderProdListDTOList[];
mremark?: any;
}
interface MallOrderProdListDTOList {
id: number;
goodsInfoId: number;
productName: string;
model?: any;
prodSkuSpecName: string;
prodSkuSpecImage: string;
partNo: string;
versionDesc: string;
buyNum: number;
unitPrice: number;
skuSpecAmount: number;
}
interface OgSkuSpecDTOList {
id: number;
directoryId: number;
shopCarId?: any;
skuSpecName: string;
}
export interface ListStatusResp {
status: string;
code: number;
nextCode: number;
}
export default {
//v1.0.0订单列表-查询
listPage(params: ListPageParams, options: any): Promise<Response<ListPageResp>> {
return request('/oms/app-order/listPage', 'get', params, options)
},
//订单状态-字典
listStatus(): Promise<Response<ListStatusResp[]>> {
return request('/oms/mallorder/listStatus', 'get');
}
}
\ No newline at end of file
@import "~/styles/mixins.scss";
.font1 {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #9b9b9b;
line-height: 19px;
}
.font2 {
font-size: 12px;
font-family: Arial-BoldMT, Arial;
font-weight: normal;
color: #626262;
line-height: 14px;
}
.font3 {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6c6c6c;
line-height: 20px;
}
.font4 {
font-size: 14px;
font-family: ArialMT;
color: #141414;
line-height: 16px;
}
.font5 {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #929295;
line-height: 17px;
}
.font6 {
font-size: 13px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #070707;
line-height: 16px;
}
.btn1 {
border-radius: 16px;
border: 1px solid #ff552d;
padding: 6px 16px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff552d;
line-height: 20px;
}
.btn2 {
border-radius: 16px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ffffff;
line-height: 20px;
padding: 6px 16px;
}
import {
TabsProps,
Tabs,
Row,
Col,
Image,
Space,
Button,
Spin,
Pagination,
Empty,
} from "antd";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import errImg from "~/assets/errImg";
import Right from "~/components/contentBox/right";
import LayoutView from "~/components/layout";
import Sider from "../components/sider";
import api, { OrderList, ListStatusResp } from "./api";
import styles from "./index.module.scss";
const items: TabsProps["items"] = [
{
key: "",
label: `全部`,
},
{
key: "0",
label: `待付款`,
},
{
key: "1",
label: `待验收`,
},
{
key: "2",
label: `已完成`,
},
{
key: "3",
label: `已取消`,
},
];
export default function TrainOrder() {
const router = useRouter();
const [pageParams, setPageParams] = useState({
pageNo: 1,
pageSize: 5,
}); //分页器对象
const [total, setTotal] = useState(0); //总数
const [abort, setAbort] = useState<AbortController | null>(null); //请求中断对你
const [tabKey, setTabKey] = useState("");
const [orderList, setOrderList] = useState<OrderList[]>([]);
const [loading, setLoading] = useState(false);
const [orderNo, setOrderNo] = useState<string | undefined>();
const [tranStatusMap, setTranStatusMap] = useState<ListStatusResp[]>([]); //订单状态字典
//获取订单状态字典
useEffect(() => {
api.listStatus().then((res) => {
setTranStatusMap(res.result || []);
});
}, []);
useEffect(() => {
//中断前一次列表请求
abort?.abort();
setAbort(new AbortController());
}, [pageParams]);
//商品列表请求
useEffect(() => {
if (!abort) {
return;
}
setLoading(true);
api
.listPage(
{
...pageParams,
showType: Number(tabKey),
},
{
signal: abort?.signal,
}
)
.then((res) => {
setOrderList(res.result?.list || []);
setTotal(res.result?.totalCount || 0);
setLoading(false);
});
}, [abort]);
const onPageChange = (page: number, pageSize: number) => {
setPageParams({
...pageParams,
pageNo: page,
});
};
const onTabsChange = (key: string) => {
setTabKey(key);
setPageParams({
...pageParams,
pageNo: 1,
});
setTotal(0);
};
return (
<>
<LayoutView
layoutStyle={{ backgroundColor: "#fff" }}
contentStyle={{ width: 1000, marginLeft: 526 }}
headerStyle={{ borderBottom: "1px solid #e2e2e2" }}
>
<Sider
style={{
position: "absolute",
left: -37,
top: 15,
transform: "translateX(-100%)",
}}
selectedKeys={[router.pathname]}
></Sider>
<div style={{ paddingTop: 19 }}>
<div className={styles.font1}>培训订单</div>
<Tabs activeKey={tabKey} items={items} onChange={onTabsChange} />
<Spin spinning={loading} delay={500}>
<ul className={styles.orderList} style={{ minHeight: 650 }}>
{orderList.map((item) => {
return (
<li key={item.id} className={styles.orderItem}>
<Row
justify="space-between"
align="middle"
style={{
height: 30,
padding: "0 26px 0 16px",
background: "#EBF8FF",
}}
>
<div className={styles.font2}>{item.createTime}</div>
<div className={styles.font3}>
{
tranStatusMap.find(
(status) => status.code === item.statusCode
)?.status
}
</div>
</Row>
<Row
style={{ minHeight: 100, border: "1px solid #D0EAF5" }}
>
<Col style={{ width: 380 }}>
<Row>
<div style={{ margin: "10px 10px 0 16px" }}>
<Image
width={80}
height={80}
preview={false}
fallback={errImg}
src={item.orderMainImg}
></Image>
</div>
<div style={{ marginTop: 12 }}>
<div className={`ellipsis1 ${styles.font4}`}>
{item.orderName}
</div>
</div>
</Row>
</Col>
<Col
style={{
width: 270,
borderLeft: "1px solid #D0EAF5",
borderRight: "1px solid #D0EAF5",
}}
>
<Row
justify={"center"}
align="middle"
style={{ height: "100%" }}
>
预付金额:{" "}
<span className={styles.font6}>
¥{item.totalBuyNum}
</span>
</Row>
</Col>
<Col flex={"auto"} style={{}}>
<Space
size={7}
style={{
float: "right",
marginTop: 20,
marginRight: 24,
}}
>
<Button className={styles.btn1}>取消订单</Button>
<Button className={styles.btn2} type="primary">
查看合同
</Button>
</Space>
</Col>
</Row>
</li>
);
})}
{orderList.length === 0 && (
<Empty
style={{
paddingTop: 20,
width: "100%",
textAlign: "center",
}}
></Empty>
)}
</ul>
</Spin>
<Pagination
current={pageParams.pageNo}
showSizeChanger={false}
showQuickJumper
total={total}
pageSize={pageParams.pageSize}
onChange={onPageChange}
hideOnSinglePage={true}
style={{ marginTop: 20 }}
></Pagination>
</div>
</LayoutView>
</>
);
}
......@@ -101,7 +101,7 @@ export default function Bids(props: Props) {
<Button type="primary" className={styles.btn}>
<div className={styles.text1}>{item.tenderPrice}</div>
<div className={styles.text2} onClick={() => onApply(item)}>
申请合作
商务合作
</div>
</Button>
)}
......
......@@ -86,7 +86,7 @@ export default function Cases(props: Props) {
Router.push("/projectInfo/caseArticle/" + item.id)
}
>
申请合作
联系品牌厂家
</Button>
</div>
);
......
......@@ -2,10 +2,11 @@ import { RightOutlined } from "@ant-design/icons";
import { Button, Col, Empty, Pagination, Row, Spin } from "antd";
import styles from "./index.module.scss";
import Image from "next/image";
import { useState, useEffect } from "react";
import { useState, useEffect, useContext } from "react";
import api, { Item } from "./api";
import { useRouter } from "next/router";
import Router from "next/router";
import Moment from "moment";
import { UserContext } from "~/lib/userProvider";
type Props = {
params?: {
......@@ -25,7 +26,7 @@ export default function News(props: Props) {
});
const [count, setCount] = useState(0);
const [abort, setAbort] = useState<AbortController | null>(null);
const router = useRouter();
const { userInfo, setNeedLogin } = useContext(UserContext);
useEffect(() => {
//中断前一次请求
......@@ -62,6 +63,19 @@ export default function News(props: Props) {
});
};
//获取产品信息事件
const onGetInfo = () => {
if(userInfo){
if(userInfo.companyAuthStatus){
}else{
Router.push("/certification?type=back");
}
}else{
setNeedLogin(true);
}
}
return (
<Spin spinning={loading} delay={500}>
<Row justify="space-between" style={{ height: 606 }}>
......@@ -86,11 +100,9 @@ export default function News(props: Props) {
<Button
type="primary"
style={{ width: 120, height: 40, flexShrink: 0 }}
onClick={() =>
router.push("/projectInfo/newsArticle/" + item.id)
}
onClick={onGetInfo}
>
申请合作
获取产品资料
</Button>
</div>
);
......
......@@ -23,7 +23,7 @@ export interface Params {
}
const items = (params: any) =>
["项目需求", "招投标项目", "业务案例", "行业新闻"].map((value) => {
[/* "项目需求", */ "招投标项目", "项目案例", "行业新闻"].map((value) => {
let children: JSX.Element | string = <></>;
switch (value) {
......@@ -35,7 +35,7 @@ const items = (params: any) =>
children = <Bids params={params}></Bids>;
break;
case "业务案例":
case "项目案例":
children = <Cases params={params}></Cases>;
break;
......@@ -120,7 +120,7 @@ export default function ProjectInfo() {
fieldNames={{
label: "name",
value: "id",
children: "childInfo",
// children: "childInfo",
}}
changeOnSelect
/>
......
No preview for this file type
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1000px" height="1000px" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 23</title>
<defs>
<linearGradient x1="89.4147753%" y1="100%" x2="64.5402719%" y2="5.55111512e-15%" id="linearGradient-1">
<stop stop-color="#FF8C34" offset="0%"></stop>
<stop stop-color="#FF552D" offset="50.7965867%"></stop>
<stop stop-color="#FFB901" offset="100%"></stop>
</linearGradient>
<rect id="path-2" x="0" y="0" width="1000" height="1000"></rect>
<path d="M346.945354,0 C386.719769,0 424.111509,15.4918955 452.243311,43.6191849 L452.243311,43.6191849 L668.850064,260.225938 L669.378577,260.759024 C685.499975,277.165176 693.679438,298.905285 693.755328,320.632146 L693.755328,320.632146 L693.755328,321.259403 L693.749893,321.968758 C693.503246,343.01181 685.65584,363.934192 670.054939,379.887631 L670.054939,379.887631 L669.208947,380.745878 C641.197349,408.940964 603.918354,424.546483 564.22449,424.720716 L564.22449,424.720716 L562.848135,424.720716 L562.536762,424.71846 L562.536762,424.71846 L562.22539,424.716203 L561.151236,424.702813 C525.720382,424.127444 491.914522,410.350076 465.167514,387.328975 L465.167514,387.328975 L522.762347,329.734142 L523.561943,330.330355 C550.060988,349.786544 587.60227,347.578297 611.507939,323.569875 L611.507939,323.569875 L611.65903,323.409559 C613.117482,321.77607 613.003516,319.25317 611.435737,317.685392 L611.435737,317.685392 L605.962112,312.212485 C604.081727,310.332275 601.913507,308.16421 599.487729,305.738569 L593.18685,299.437987 C590.932053,297.183279 588.527921,294.779225 585.989953,292.241326 L582.084563,288.336033 C579.416635,285.668167 576.622623,282.874207 573.718028,279.969657 L569.280136,275.531828 C568.52731,274.779011 567.768058,274.019768 567.00262,273.254339 L555.08747,261.339293 C553.445009,259.696842 551.782652,258.034494 550.102338,256.354188 L526.503749,232.755656 C524.701055,230.952963 522.889123,229.141032 521.06989,227.3218 L510.082391,216.334302 C507.321366,213.573277 504.552634,210.804545 501.782735,208.034647 L496.24332,202.495233 C494.397621,200.649535 492.553341,198.805257 490.712419,196.964336 L431.47928,137.731678 C428.464352,134.716815 425.551983,131.80452 422.757675,129.010295 L407.532556,113.785804 C404.707478,110.960885 402.11531,108.368895 399.786328,106.040113 L397.119817,103.373852 L397.119817,103.373852 L395.884942,102.139109 L395.396582,101.654979 C383.462415,89.9310903 367.835648,82.3510579 351.128572,81.3538863 L351.128572,81.3538863 L350.474754,81.3176927 C331.089139,80.3348518 312.694862,87.4364746 299.079774,101.051563 L299.079774,101.051563 L82.4685085,317.662828 L82.3102468,317.829667 C80.7826169,319.528117 80.9032045,322.108071 82.5452234,323.741355 L82.5452234,323.741355 L83.0084174,324.198689 C96.3385297,337.237535 114.117369,344.130503 132.892756,343.443545 L132.892756,343.443545 L133.621979,343.412939 C147.222113,342.762603 160.140238,337.694678 171.015544,329.621326 L171.015544,329.621326 L228.727706,387.333488 L227.916248,388.028387 C201.067045,410.866015 167.196496,424.381095 131.769108,424.711691 L131.769108,424.711691 L130.646618,424.718138 C93.6249819,424.795304 58.653995,411.454726 31.2725999,386.999552 L31.2725999,386.999552 L30.705499,386.489199 C12.0584465,369.581573 0.0893502856,346.158485 0,320.975107 L0,320.975107 L0,320.392976 L0.00529311546,319.668015 C0.261972172,297.20897 9.12417541,276.133428 25.0361305,260.225938 L25.0361305,260.225938 L241.642883,43.6191849 L242.489476,42.7791597 C270.518336,15.1836068 307.564215,0 346.945354,0 Z M346.940841,169.797131 L347.451262,169.800734 C356.468282,169.928032 365.450607,173.428804 372.328958,180.311584 L372.328958,180.311584 L458.7009,266.679014 L458.0109,266.633924 C457.091332,266.572696 456.172919,266.512046 455.24873,266.512046 L455.24873,266.512046 L454.601521,266.515806 C440.376087,266.681183 427.031996,272.296511 416.958974,282.373978 L416.958974,282.373978 L388.236016,311.092424 L314.892067,237.748474 L314.47565,237.325256 C300.872694,223.273967 301.0115,200.857321 314.892067,186.976754 L314.892067,186.976754 L321.557237,180.311584 C328.565368,173.29894 337.753105,169.797131 346.940841,169.797131 L346.940841,169.797131 Z" id="path-4"></path>
</defs>
<g id="第一版" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-23">
<g id="编组-14">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<use id="矩形" fill="url(#linearGradient-1)" xlink:href="#path-2"></use>
</g>
<g id="Group-10" transform="translate(152.777778, 250.000000)">
<g id="Clip-6">
<mask id="mask-5" fill="white">
<use xlink:href="#path-4"></use>
</mask>
<use id="Clip-7" fill="#FFFFFF" xlink:href="#path-4"></use>
</g>
<path d="M426.525772,291.945289 L394.806421,323.669153 C368.416498,350.063588 325.469697,350.063588 299.079774,323.669153 L299.079774,323.669153 L267.35591,291.945289 C251.498491,276.08787 225.780951,276.08787 209.919019,291.945289 L209.919019,291.945289 L181.200574,320.663734 L239.792701,379.251348 C268.195261,407.653909 306.494043,424.648514 346.661057,424.720716 L346.661057,424.720716 L347.107809,424.720716 C386.823559,424.67559 424.156636,409.192719 452.243311,381.106044 L452.243311,381.106044 L512.685621,320.663734 L483.967176,291.945289 C476.033953,284.016579 465.641342,280.049968 455.244218,280.049968 L455.244218,280.049968 C444.851606,280.049968 434.458995,284.016579 426.525772,291.945289" id="Fill-7" fill="#FFFFFF"></path>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="31" fill="none"><g opacity=".9"><path fill="url(#a)" d="M13 .4v29.3H7V6.3h-.2L0 10.5V5L7.2.4H13Z"/><path fill="url(#b)" d="M28.8 30.1c-2.2 0-4-.3-5.7-1-1.7-.8-3-1.8-4-3.1a7.7 7.7 0 0 1-1.4-4.6h6.2c0 .8.3 1.4.7 2 .4.5 1 .9 1.7 1.2.7.3 1.6.4 2.5.4 1 0 1.7-.2 2.5-.5.7-.3 1.3-.8 1.7-1.4.4-.6.6-1.2.6-2s-.2-1.5-.7-2.1c-.4-.6-1-1-1.8-1.4-.8-.4-1.8-.5-2.9-.5h-2.7v-4.6h2.7a6 6 0 0 0 2.5-.5 4 4 0 0 0 1.7-1.3c.4-.6.6-1.3.6-2a3.5 3.5 0 0 0-2-3.3 5.6 5.6 0 0 0-4.5 0 4 4 0 0 0-1.7 1.2c-.4.6-.6 1.2-.6 2h-6c0-1.7.6-3.2 1.5-4.5 1-1.3 2.2-2.3 3.8-3C25 .4 26.8 0 28.8 0s3.8.4 5.3 1.1c1.5.7 2.7 1.7 3.6 3a7.2 7.2 0 0 1 1.2 4.2c0 1.6-.5 3-1.5 4a7 7 0 0 1-4 2.2v.2c2.2.3 3.8 1 5 2.2a6.4 6.4 0 0 1 1.6 4.6c0 1.7-.5 3.1-1.4 4.4a9.7 9.7 0 0 1-4 3.1c-1.7.8-3.7 1.1-5.8 1.1Z"/></g><defs><linearGradient id="a" x1="20" x2="20" y1="0" y2="30.1" gradientUnits="userSpaceOnUse"><stop/><stop offset="1" stop-color="#3D3D3D"/></linearGradient><linearGradient id="b" x1="20" x2="20" y1="0" y2="30.1" gradientUnits="userSpaceOnUse"><stop/><stop offset="1" stop-color="#3D3D3D"/></linearGradient></defs></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>
\ No newline at end of file
@import "./reset.scss";
@import "./mixins.scss";
body {
background-color: rgb(248, 248, 248)
......@@ -75,3 +76,19 @@ body {
.ant-tag-close-icon {
font-size: 10px !important;
}
.ellipsis1{
@include ellipsis(1);
}
.ellipsis2{
@include ellipsis(2);
}
.ellipsis3{
@include ellipsis(3);
}
.ellipsis4{
@include ellipsis(4);
}
\ No newline at end of file
......@@ -18,7 +18,8 @@
"paths": {
"~/*": ["./*"]
},
"typeRoots": ["./typings"]
"typeRoots": ["./typings"],
"noEmitOnError": false
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
......
......@@ -5,6 +5,9 @@ declare global {
messageApi: MessageInstance; //全局消息提示api
WxLogin: any; //微信登录对象
_AMapSecurityConfig: { securityJsCode: string }; //高德地图api密钥配置
AMap:any
AMap: any;
setUserInfo: Dispatch<SetStateAction<UserInfoResp | null | undefined>>; //设置userInfo
setNeedLogin: Dispatch<SetStateAction<Boolean>>; //需要登录操作
logout: () => void; //退出登录
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论