提交 39368c2a 作者: 曹云

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

import request, { Response } from "~/api/request"; import request, { Response } from '~/api/request'
import config from "./config"; import config from './config'
export interface RegionResp { export interface RegionResp {
childInfo?: RegionResp[] | null; childInfo?: RegionResp[] | null
id: number; id: number
level: number; level: number
name: string; name: string
pid: number; pid: number
} }
export interface UserInfoResp { export interface UserInfoResp {
id: number; id: number
accountType: number; accountType: number
uid: string; uid: string
phoneNum: string; phoneNum: string
userName: string; userName: string
nickName: string; nickName: string
userImg: string; userImg: string
userSex: number; userSex: number
email: string; email: string
source: number; source: number
accountStatus: number; accountStatus: number
remark: string; remark: string
portType: number; portType: number
createTime: string; createTime: string
companyAuthStatus: number; companyAuthStatus: number
token: string; token: string
cooperationTagId: number | null
} }
export interface TestAppletLoginResp { export interface TestAppletLoginResp {
userAccountId: number; userAccountId: number
token: string; token: string
uid: string; uid: string
phoneNum?: string; phoneNum?: string
nickName: string; nickName: string
sessionKey?: any; sessionKey?: any
} }
export default { export default {
//获取区域数据 //获取区域数据
region: (): Promise<Response<Array<RegionResp>>> => { region: (): Promise<Response<Array<RegionResp>>> => {
return request("/pms/webDevice/getSecondDistrictInfo"); return request('/pms/webDevice/getSecondDistrictInfo')
}, },
//测试-小程序unionId登录-注册 //测试-小程序unionId登录-注册
testAppletLogin: (): Promise<Response<TestAppletLoginResp>> => { testAppletLogin: (): Promise<Response<TestAppletLoginResp>> => {
let params = new URLSearchParams(); let params = new URLSearchParams()
params.append("unionId", "oQZEd5hy0Qrwaj10BGtP8xq8vH--s88888"); params.append('unionId', 'oQZEd5hy0Qrwaj10BGtP8xq8vH--s88888')
return request( return request(
"/userapp/auth/testAppletLogin", '/userapp/auth/testAppletLogin',
"post", 'post',
{}, {},
{ {
headers: { headers: {
"Content-Type": "application/x-www-form-urlencoded", 'Content-Type': 'application/x-www-form-urlencoded',
}, },
body: params, body: params,
} }
); )
}, },
//生成小程序码 //生成小程序码
getAppletQRCode: (params: { randomLoginCode: string }) => { getAppletQRCode: (params: { randomLoginCode: string }) => {
return request("/userapp/wx/getAppletQRCode", "get", { return request('/userapp/wx/getAppletQRCode', 'get', {
page: "page-identity/identity-empower/index", page: 'page-identity/identity-empower/index',
scene: "randomLoginCode=" + params.randomLoginCode, scene: 'randomLoginCode=' + params.randomLoginCode,
}); })
}, },
//查询登录信息 //查询登录信息
getLoginInfo: (params: { randomLoginCode: string }) => { getLoginInfo: (params: { randomLoginCode: string }) => {
return request("/userapp/temp-auth/getLoginInfo", "get", params, { return request('/userapp/temp-auth/getLoginInfo', 'get', params, {
hideError: true //隐藏错误提示 hideError: true, //隐藏错误提示
}); })
}, },
//获取用户基本信息 //获取用户基本信息
userInfo: (): Promise<Response<UserInfoResp>> => { userInfo: (): Promise<Response<UserInfoResp>> => {
return request("/userapp/user-account/info", "get"); return request('/userapp/user-account/info', 'get')
}, },
//图片上传地址 //图片上传地址
imgOss: () => { imgOss: () => {
return config.baseUrl + "/pms/upload/imgOss"; return config.baseUrl + '/pms/upload/imgOss'
}, },
}; }
import config from './config'; import config from './config';
let loginTimeout: NodeJS.Timeout | undefined;
/** /**
* 请求封装 * 请求封装
* @param url 请求url * @param url 请求url
...@@ -43,12 +45,31 @@ export default function request(url: string, method: String = 'get', data?: any, ...@@ -43,12 +45,31 @@ export default function request(url: string, method: String = 'get', data?: any,
} }
} }
/**
* 错误消息
* @param msg
*/
function errMsg(msg: string) { function errMsg(msg: string) {
if (!options.hideError) { if (!options.hideError) {
window.messageApi.error(msg); 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) return fetch(config.baseUrl + url, options)
.then((r) => { .then((r) => {
try { try {
...@@ -84,8 +105,9 @@ export default function request(url: string, method: String = 'get', data?: any, ...@@ -84,8 +105,9 @@ export default function request(url: string, method: String = 'get', data?: any,
if (data.code !== '200') { if (data.code !== '200') {
//未登录判断 //未登录判断
if(data.code === '5008'){ if(data.code === '5008' || data.code === '2014'){
errMsg('请先登录'); loginErrorMsg();
window.logout();
}else{ }else{
errMsg(data.message || '请求出错'); errMsg(data.message || '请求出错');
} }
......
...@@ -2,7 +2,7 @@ import React, { useContext, useEffect, useState } from "react"; ...@@ -2,7 +2,7 @@ import React, { useContext, useEffect, useState } from "react";
import { Avatar, Button, Dropdown, Space, Tabs } from "antd"; import { Avatar, Button, Dropdown, Space, Tabs } from "antd";
import type { TabsProps } from "antd"; import type { TabsProps } from "antd";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
import { useRouter } from "next/router"; import { Router, useRouter } from "next/router";
import LoginModal from "~/components/loginModal"; import LoginModal from "~/components/loginModal";
import PublishModal from "./publishModal"; import PublishModal from "./publishModal";
import JoinModal from "./joinModal"; import JoinModal from "./joinModal";
...@@ -39,17 +39,21 @@ const items: TabsProps["items"] = [ ...@@ -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 router = useRouter();
const [currentPath, setCurrentPath] = useState(""); const [currentPath, setCurrentPath] = useState("");
const { userInfo, testLogin, logout, setNeedLogin, needLogin } = const { userInfo, testLogin, logout, setNeedLogin, needLogin } =
useContext(UserContext); useContext(UserContext);
useEffect(() => { useEffect(() => {
const routerTo = items?.filter(item=>router.route.includes(item.key))[0] const routerTo = items?.filter((item) => router.route == item.key)[0];
if (routerTo) { if (routerTo) {
setCurrentPath(routerTo?.key!); setCurrentPath(routerTo?.key!);
}else{ } else {
setCurrentPath(router.route); setCurrentPath(router.route);
} }
console.log("currentHash", currentPath); console.log("currentHash", currentPath);
...@@ -97,7 +101,7 @@ export default function NavHeader() { ...@@ -97,7 +101,7 @@ export default function NavHeader() {
}, [needLogin]); }, [needLogin]);
return ( return (
<div className={styles.navHeader}> <div className={styles.navHeader} style={props.style}>
<div className={styles.nav}> <div className={styles.nav}>
<div className={styles.logo}></div> <div className={styles.logo}></div>
<Tabs <Tabs
...@@ -120,6 +124,18 @@ export default function NavHeader() { ...@@ -120,6 +124,18 @@ export default function NavHeader() {
<Dropdown <Dropdown
menu={{ menu={{
items: [ items: [
{
key: "2",
label: (
<div
onClick={() =>
router.push("/personalCenter/servicesOrders")
}
>
我的订单
</div>
),
},
{ key: "1", label: <div onClick={onLogout}>退出登录</div> }, { key: "1", label: <div onClick={onLogout}>退出登录</div> },
], ],
}} }}
......
...@@ -23,7 +23,6 @@ export default function PublishModal(props: Props) { ...@@ -23,7 +23,6 @@ export default function PublishModal(props: Props) {
const position = useGeolocation(); const position = useGeolocation();
const { reloadRequirements, setReloadRequirements } = const { reloadRequirements, setReloadRequirements } =
useContext(CommonContext); useContext(CommonContext);
console.log("position", position);
useEffect(() => { useEffect(() => {
api.listType().then((res) => { api.listType().then((res) => {
......
import request, { Response } from "~/api/request"; import request, { Response } from '~/api/request'
export interface FilterOptionResp { export interface FilterOptionResp {
id: number; id: number
name?: string; name?: string
appName?: string; appName?: string
} }
export interface RegionResp { export interface RegionResp {
childInfo: RegionResp[] | null; childInfo: RegionResp[] | null
id: number; id: number
level: number; level: number
name: string; name: string
pid: number; pid: number
}
export interface InfoList {
id: number
directoryId: number
name: string
icon: string
}
export interface TypesResp {
directoryId: number
name: string
categoriesInfoListDTO: InfoList[]
} }
export default { export default {
category: (): Promise<Response<Array<FilterOptionResp>>> => { category: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/category"); return request('/pms/webProductMall/category')
}, },
categoryId: (): Promise<Response<Array<FilterOptionResp>>> => { categoryId: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/category"); return request('/pms/webDevice/category')
}, },
brand: (): Promise<Response<Array<FilterOptionResp>>> => { brand: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/brand"); return request('/pms/webDevice/brand')
}, },
model: (): Promise<Response<Array<FilterOptionResp>>> => { model: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/model"); return request('/pms/webDevice/model')
}, },
part: (): Promise<Response<Array<FilterOptionResp>>> => { part: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/parts"); return request('/pms/webProductMall/parts')
}, },
quality: (): Promise<Response<Array<FilterOptionResp>>> => { quality: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/quality"); return request('/pms/webProductMall/quality')
}, },
region: (): Promise<Response<Array<RegionResp>>> => { region: (): Promise<Response<Array<RegionResp>>> => {
return request("/pms/webDevice/getSecondDistrictInfo"); return request('/pms/webDevice/getSecondDistrictInfo')
}, },
industry: (): Promise<Response<Array<RegionResp>>> => { industry: (): Promise<Response<Array<RegionResp>>> => {
return request("/release/work/listAllIndustry"); return request('/release/work/listAllIndustry')
}, },
appType: (): Promise<Response<Array<RegionResp>>> => { appType: (): Promise<Response<Array<RegionResp>>> => {
return request("/release/work/listAllAppType"); return request('/release/work/listAllAppType')
}, },
deviceBrand: (): Promise<Response<Array<RegionResp>>> => { deviceBrand: (): Promise<Response<Array<RegionResp>>> => {
return request("/pms/webDevice/deviceBrand"); return request('/pms/webDevice/deviceBrand')
}, },
deviceModel: (): Promise<Response<Array<RegionResp>>> => { 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 { Space, Select } from 'antd'
import { useEffect, useState } from "react"; import { useEffect, useState } from 'react'
import styles from "../../index.module.scss"; import styles from '../../index.module.scss'
import api, { RegionResp } from "../../api"; import api, { RegionResp } from '../../api'
type Props = { type Props = {
onChange: (item: RegionResp) => void; onChange: (item: RegionResp) => void
}; }
export default function RegionItem(props: Props) { export default function RegionItem(props: Props) {
const [provinceList, setProvinceList] = useState<RegionResp[]>([]); const [provinceList, setProvinceList] = useState<RegionResp[]>([])
const [cityList, setCityList] = useState<RegionResp[]>([]); const [cityList, setCityList] = useState<RegionResp[]>([])
const [selectCity, setSelectCity] = useState<number>() const [selectCity, setSelectCity] = useState<number>()
useEffect(() => { useEffect(() => {
api.region().then((res) => { api.region().then((res) => {
setProvinceList(res?.result || []); setProvinceList(res?.result || [])
}); })
}, []); }, [])
const onProvinceChange = (value: number, item: any) => { const onProvinceChange = (value: number, item: any) => {
console.log("省", value, item); console.log('省', value, item)
setCityList(item.childInfo || []); setCityList(item.childInfo || [])
setSelectCity(undefined); setSelectCity(undefined)
props.onChange(item); props.onChange(item)
}; }
const onCityChange = (value: number, item: any) => { const onCityChange = (value: number, item: any) => {
console.log("市", value); console.log('市', value)
setSelectCity(value); setSelectCity(value)
props.onChange(item); props.onChange(item)
}; }
return ( return (
<div className={styles.filterItem}> <div className={styles.filterItem}>
<div className={styles.filterItemTitle}>地域:</div> <div className={styles.filterItemTitle}>地域:</div>
...@@ -44,10 +44,10 @@ export default function RegionItem(props: Props) { ...@@ -44,10 +44,10 @@ export default function RegionItem(props: Props) {
...item, ...item,
value: item.id, value: item.id,
label: item.name, label: item.name,
}; }
})} })}
/> />
<Select {/* <Select
value={selectCity} value={selectCity}
bordered={false} bordered={false}
popupMatchSelectWidth={false} popupMatchSelectWidth={false}
...@@ -60,9 +60,9 @@ export default function RegionItem(props: Props) { ...@@ -60,9 +60,9 @@ export default function RegionItem(props: Props) {
label: item.name, label: item.name,
}; };
})} })}
/> /> */}
</Space> </Space>
</div> </div>
</div> </div>
); )
} }
import { Space, Tag } from "antd"; import { Space, Tag } from 'antd'
import { FilterResult } from "../.."; import { FilterResult } from '../..'
import styles from "../../index.module.scss"; import styles from '../../index.module.scss'
import { InfoList } from '../../api'
type Props = { type Props = {
data: FilterResult; data: FilterResult
onDel: (key: string) => void; onDel: (key: string | number) => void
}; }
export default function ResultItem({data, onDel}: Props) { export default function ResultItem({ data, onDel }: Props) {
return ( return (
<div className={styles.filterItem}> <div className={styles.filterItem}>
<div className={styles.filterItemTitle}>已选:</div> <div className={styles.filterItemTitle}>已选:</div>
<div className={styles.filterItemMain}> <div className={styles.filterItemMain}>
<Space size={10}> <Space size={10}>
{data && {data.provinceId && (
Object.keys(data).map((key) => { // Object.keys(data).map((key) => {
//@ts-ignore // //@ts-ignore
let item = data[key]; // 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 ( return (
<Tag <Tag
closable closable
onClose={(e: React.MouseEvent<HTMLElement, MouseEvent>) => { onClose={(e: React.MouseEvent<HTMLElement, MouseEvent>) => {
onDel(key); onDel(item.id)
}} }}
key={key} key={item.name}
> >
{item?.name} {item?.name}
</Tag> </Tag>
); )
})} })}
</Space> </Space>
</div> </div>
</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 @@ ...@@ -31,6 +31,7 @@
flex: 1; flex: 1;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
overflow: hidden;
&.disabled { &.disabled {
:global .ant-collapse-expand-icon { :global .ant-collapse-expand-icon {
......
...@@ -41,7 +41,9 @@ const footerStyle: React.CSSProperties = { ...@@ -41,7 +41,9 @@ const footerStyle: React.CSSProperties = {
type Props = { type Props = {
children?: React.ReactNode; children?: React.ReactNode;
layoutStyle?: React.CSSProperties; layoutStyle?: React.CSSProperties;
contentStyle?: React.CSSProperties;
hideFooter?: boolean; hideFooter?: boolean;
headerStyle?: React.CSSProperties
}; };
export default function LayoutView(props: Props) { export default function LayoutView(props: Props) {
...@@ -55,11 +57,19 @@ export default function LayoutView(props: Props) { ...@@ -55,11 +57,19 @@ export default function LayoutView(props: Props) {
)} )}
> >
<Header style={headerStyle}> <Header style={headerStyle}>
<NavHeader /> <NavHeader style={props.headerStyle} />
</Header> </Header>
<Content className={styles.content}>{props.children}</Content> <Content className={styles.content} style={props.contentStyle}>
{props.children}
</Content>
{!props.hideFooter && ( {!props.hideFooter && (
<Footer style={ includesPage.includes(router.pathname) ? {...footerStyle,...homeStyle} : footerStyle}> <Footer
style={
includesPage.includes(router.pathname)
? { ...footerStyle, ...homeStyle }
: footerStyle
}
>
<FooterView></FooterView> <FooterView></FooterView>
</Footer> </Footer>
)} )}
......
...@@ -35,6 +35,10 @@ const UserProvider = ({ children }: Props) => { ...@@ -35,6 +35,10 @@ const UserProvider = ({ children }: Props) => {
setUserInfo( setUserInfo(
JSON.parse(window.localStorage.getItem("userInfo") || "") || undefined JSON.parse(window.localStorage.getItem("userInfo") || "") || undefined
); );
window.setUserInfo = setUserInfo;
window.setNeedLogin = setNeedLogin;
window.logout = logout;
} catch (e) {} } catch (e) {}
}, []); }, []);
......
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
let distDir = ".dev"; //默认输出目录 let distDir = '.dev' //默认输出目录
if (process.env.NODE_ENV === "production") { if (process.env.NODE_ENV === 'production') {
//生产环境用另一个目录构建,防止与dev冲突 //生产环境用另一个目录构建,防止与dev冲突
distDir = ".next"; distDir = '.next'
} }
const nextConfig = { const nextConfig = {
distDir, distDir,
reactStrictMode: true, reactStrictMode: true,
transpilePackages: ["antd"], transpilePackages: ['antd'],
output: "standalone", output: 'standalone',
compiler: { compiler: {
styledComponents: true, styledComponents: true,
}, },
redirects() { redirects() {
return [ return [
{ {
source: "/", source: '/',
destination: "/home", destination: '/home',
permanent: true, permanent: true,
}, },
]; ]
}, },
async rewrites() { async rewrites() {
return [ return [
{ {
source: "/local/:path*", source: '/local/:path*',
//destination: "https://iuav.mmcuav.cn/:path*", //destination: "https://iuav.mmcuav.cn/:path*",
destination: "https://test.iuav.mmcuav.cn/:path*", destination: 'https://test.iuav.shop/:path*',
}, },
]; ]
}, },
images: { images: {
remotePatterns: [ remotePatterns: [
{ {
protocol: "http", protocol: 'http',
hostname: "**", hostname: '**',
}, },
{ {
protocol: "https", protocol: 'https',
hostname: "**", 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) { ...@@ -23,6 +23,7 @@ export default function App({ Component, pageProps }: AppProps) {
return withTheme( return withTheme(
<> <>
<Head> <Head>
<title>云享飞</title>
<meta <meta
name="viewport" name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
......
...@@ -12,18 +12,22 @@ import { ...@@ -12,18 +12,22 @@ import {
} from "antd"; } from "antd";
import type { UploadChangeParam } from "antd/es/upload"; import type { UploadChangeParam } from "antd/es/upload";
import type { RcFile, UploadFile, UploadProps } from "antd/es/upload/interface"; 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 Layout from "~/components/layout";
import api, { } from "./api"; import api from "./api";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
import gApi from "~/api"; import gApi from "~/api";
import Router from "next/router"; import Router from "next/router";
import { UserContext } from "~/lib/userProvider"; import { UserContext } from "~/lib/userProvider";
const beforeUpload = (file: RcFile) => { 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) { if (!isJpgOrPng) {
message.error("You can only upload JPG/PNG file!"); message.error("请上传10M以内的JPG、JPEG、BMP、GIF、PNG格式图片");
} }
//限制上传10M //限制上传10M
const isLt2M = file.size / 1024 / 1024 < 10; const isLt2M = file.size / 1024 / 1024 < 10;
...@@ -55,6 +59,11 @@ export default function Certification() { ...@@ -55,6 +59,11 @@ export default function Certification() {
Array<EnterpriseOption> Array<EnterpriseOption>
>([]); >([]);
const [form] = Form.useForm(); const [form] = Form.useForm();
const [token, setToken] = useState("");
useEffect(() => {
setToken(window.localStorage.getItem("token") || "");
}, []);
//上传change事件 //上传change事件
const handleChange: UploadProps["onChange"] = ( const handleChange: UploadProps["onChange"] = (
...@@ -91,7 +100,11 @@ export default function Certification() { ...@@ -91,7 +100,11 @@ export default function Certification() {
}); });
} }
setTimeout(() => { setTimeout(() => {
if (Router.query.type == "back") {
Router.back();
} else {
Router.push("/"); Router.push("/");
}
}, 1000); }, 1000);
} }
}); });
...@@ -209,6 +222,7 @@ export default function Certification() { ...@@ -209,6 +222,7 @@ export default function Certification() {
beforeUpload={beforeUpload} beforeUpload={beforeUpload}
onChange={handleChange} onChange={handleChange}
maxCount={1} maxCount={1}
headers={{ token: token }}
> >
{imageUrl ? ( {imageUrl ? (
<Image <Image
......
import request, { Response } from '~/api/request'; import request, { Response } from '~/api/request'
export interface ListPageDeviceInfoParams { export interface ListPageDeviceInfoParams {
"brandId"?: number, brandId?: number
"districtId"?: number, districtId?: number
"modelId"?: number, modelId?: number
"pageNo": number, pageNo: number
"pageSize": number, pageSize: number
"partsId"?: number, partsId?: number
"productCategoryId"?: number, productCategoryId?: number
"qualityId"?: number qualityId?: number
} }
export interface Device { export interface Device {
id: number, id: number
wareNo: string, goodsName: string
wareTitle: string, images: string
wareTypeId: number, price: number | null
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[]
} }
export interface Advertisement { export interface Advertisement {
id:number, id: number
imageUrl:string imageUrl: string
} }
export interface ListPageDeviceInfoResp { export interface ListPageDeviceInfoResp {
"pageNo": 1, pageNo: 1
"pageSize": 10, pageSize: 10
"list": Array<Device>, list: Array<Device>
"totalCount": 0, totalCount: 0
"totalPage": 0 totalPage: 0
} }
export default { export default {
//web-设备租赁-分页 //web-设备租赁-分页
listPageDeviceInfo: (params: ListPageDeviceInfoParams,options = {}): Promise<Response<ListPageDeviceInfoResp>> => { listPageDeviceInfo: (
return request('/pms/webDevice/deviceList', 'post', params, options) params: ListPageDeviceInfoParams,
options = {}
): Promise<Response<ListPageDeviceInfoResp>> => {
return request('/pms/product/mall/deviceList', 'post', params, options)
}, },
//web-设备租赁-广告 //web-设备租赁-广告
listAdvertisementInfo: (): Promise<Response<Array<Advertisement>>> => { listAdvertisementInfo: (): Promise<Response<Array<Advertisement>>> => {
return request('/pms/webDevice/ad', 'get') return request('/pms/webDevice/ad', 'get')
} },
} }
import request, { Response } from '~/api/request'; import request, { Response } from '~/api/request'
export interface GetWebDeviceDetailParams { 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 { export interface WareImgsType {
id: number, id: number
wareInfoId: number | null, imgUrl: string
imgUrl: string,
imgType: number 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 { export interface GetWebDeviceDetailResult {
id: number, id: number
wareNo: string, images: {
wareTitle: string, id: number
wareTypeId: number, imgUrl: string
wareStatus: number, imgType: number
payStatus: number, }[]
minDeposit: number, goodsVideo: string
maxDeposit: number, goodsVideoId: number
minRent: number, goodsName: string
maxRent: number, goodsDetail: {
totalStock: number, id: number
totalSale: number, goodsDesc: string
skuNum: number, content: string | null
tags: [ remark: string | null
string, }
string directoryId: number
], categoryByOne: number
wareImgs: Array<WareImgsType>, categoryByTwo: null
warePropDTO: number | null, tag: null
wareDetailContent: string | TrustedHTML shelfStatus: number
goodsSpec: {
productSpecList: GetWebDeviceWareSkuById[]
}[]
otherService?: {
id: number
saleServiceId: string
serviceName: string
}[]
price: number | null
goodsNo: string
} }
export interface PriceList { export interface PriceList {
id: number, id: number
wareInfoId: number, wareInfoId: number
skuInfoId: number, skuInfoId: number
rentPrice: number, rentPrice: number
minDay: number, minDay: number
maxDay: number, maxDay: number
createTime: null createTime: null
} }
export interface GetWebDeviceWareSkuById { export interface GetWebDeviceWareSkuById {
id: number, id: number
wareInfoId: number, productSpec: number
skuTitle: string, productSkuId: number
rentPrice: number | null, specName: string
rentDeposit: number, specImage: string
stockNum: number, partNo: string
saleNum: number, versionDesc: string
createTime: string, createTime: string | null
updateTime: null, productSpecCPQVO: string | null
skuPriceDTOList: Array<PriceList>,
} }
export interface WebDeviceUpdateParams { export interface WebDeviceUpdateParams {
id?:number, id?: number
inventoryId?:number, inventoryId?: number
inventoryUsage?:string, inventoryUsage?: string
startDay?:string startDay?: string
endDay?:string, endDay?: string
} }
export default { export default {
//web-设备租赁-详情 //web-设备租赁-详情
listDetailDeviceInfo: (params: GetWebDeviceDetailParams): Promise<Response<GetWebDeviceDetailResult>> => { listDetailDeviceInfo: (
return request('/pms/webDevice/detail', 'get', params) params: GetWebDeviceDetailParams
}, ): Promise<Response<GetWebDeviceDetailResult>> => {
//web-设备租赁-商品 return request('/pms/product/mall/getLeaseGoodsDetail', 'get', params)
listWareSkuById: (params: GetWebDeviceDetailParams): Promise<Response<GetWebDeviceWareSkuById[]>> => {
return request('/pms/appDevice/listWareSkuById', 'get', params)
}, },
//web-设备租赁-立即租赁 //web-设备租赁-立即租赁
listWareSkuUpdate: (params: WebDeviceUpdateParams): Promise<Response<number>> => { listWareSkuUpdate: (
params: WebDeviceUpdateParams
): Promise<Response<number>> => {
return request('/pms/appDevice/update', 'post', params) return request('/pms/appDevice/update', 'post', params)
} },
//web-设备租赁-详情-获取设备商品规格价格详情
GoodsPriceDetail: (
params: GetLeaseGoodsParams
): Promise<Response<GetLeaseGoodsResult>> => {
return request('/pms/product/mall/getLeaseGoodsPriceDetail', 'get', params)
},
} }
import request, { Response } from '~/api/request'
export interface GetWebDeviceDetailParams {
actualPay: number
deposit: number
endDate: string
orderReceipt: {
detailAddress: string
receiptMethod: number
region: string
takeName: string
takePhone: number
}
rentPrice: number
returnDate: string
shouldPay: number
specsId: number
startDate: string
wareDescription: string
wareImg: string
wareInfoId: number
wareNo: string
wareNum: number
wareTitle: string
remark?: string
}
export interface WareImgsType {
id: number
imgUrl: string
imgType: number
}
export interface UserAddress {
id: number
takeName: string
takePhone: string
takeRegion: string
takeAddress: string
type: number
}
export interface GetOrderForGoods {
balance: number
nickName: string
orderNo: string
}
export default {
//web-地址管理-查询用户地址列表-条件查询
listUserAddress: (params: {}): Promise<Response<UserAddress[]>> => {
return request('/oms/user-address/selectList', 'POST', params)
},
//web-设备租赁-下单
FeignAddLease: (
params: GetWebDeviceDetailParams
): Promise<Response<GetOrderForGoods>> => {
return request('/oms/RentalOrders/feignAddLease', 'post', params)
},
//web-设备租赁-订单支付
OrderPayment: (params: {
orderNo: string
}): Promise<Response<GetOrderForGoods>> => {
return request(`/payment/repocash/orderPayment`, 'get', params)
},
}
import styled from 'styled-components'
export const OrderForGoodsBox = styled.div`
box-sizing: border-box;
width: 1000px;
.address {
.top {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e6e6e6;
height: 30px;
line-height: 30px;
margin-top: 30px;
.left {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #333333;
line-height: 18px;
}
.right {
.btn {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #007aff;
line-height: 19px;
}
}
}
.bottom {
.item {
display: flex;
justify-content: space-between;
align-items: center;
width: 1000px;
height: 48px;
border: 1px solid transparent;
margin-top: 8px;
&.active {
background: #fff1e8;
border-radius: 6px;
border: 1px solid #ff552d;
}
.left {
display: flex;
align-items: center;
justify-content: space-around;
.active {
margin-right: 18px;
display: flex;
.icon {
width: 15px;
height: 22px;
background: #ff552d;
margin-left: 17px;
}
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
margin-left: 18px;
}
}
}
.right {
margin-right: 22px;
}
}
}
}
.info {
margin-top: 30px;
.title {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #333333;
line-height: 18px;
}
.table {
.table-title {
display: flex;
align-items: center;
width: 1000px;
border-bottom: 1px solid #e6e6e6;
padding: 10px 0;
margin-top: 20px;
.table-item {
text-align: center;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
}
}
.table-body {
display: flex;
align-items: center;
height: 100px;
margin-top: 10px;
.body-item {
text-align: center;
&.article {
display: flex;
justify-content: space-between;
.image {
margin-right: 10px;
.image-box {
width: 80px;
height: 80px;
}
}
.right {
.top {
width: 171px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #141414;
line-height: 20px;
}
.bottom {
width: 171px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #929295;
line-height: 17px;
}
}
}
&.lease-term {
display: flex;
align-items: center;
justify-content: center;
.num {
width: 62px;
height: 24px;
background: #ff552d;
border-radius: 2px;
position: relative;
margin: 0 15px;
line-height: 24px;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #ffffff;
&::before {
content: '';
width: 10px;
height: 1px;
background-color: #ff552d;
position: absolute;
left: -10px;
top: 50%;
transform: translateY(-50%);
}
&::after {
content: '';
width: 10px;
height: 1px;
background-color: #ff552d;
position: absolute;
right: -10px;
top: 50%;
transform: translateY(-50%);
}
}
}
&.total-price {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff3100;
line-height: 18px;
}
}
}
}
}
.notes {
display: flex;
align-items: center;
justify-content: space-between;
width: 1000px;
height: 110px;
background: #e1efff;
border: 1px solid #d0eaf5;
padding: 0 22px 0 16px;
.left {
display: flex;
align-items: top;
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
margin-top: 4px;
}
}
.right {
width: 430px;
.top {
display: flex;
align-items: center;
justify-content: space-between;
}
.font {
display: flex;
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 18px;
}
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
margin-right: 12px;
}
.value {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #2b2b2b;
line-height: 20px;
}
.price {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff3100;
line-height: 18px;
}
}
}
.detail-box {
display: flex;
justify-content: flex-end;
margin-top: 26px;
.right-box {
.detail {
width: 477px;
height: 110px;
border: 1px solid #ff5001;
padding: 16px 19px 19px 19px;
.top {
display: flex;
justify-content: flex-end;
align-items: center;
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #474747;
line-height: 19px;
margin-right: 10px;
}
.price {
font-size: 26px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff552d;
line-height: 33px;
}
}
.bottom {
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 15px;
.value {
font-size: 12px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 15px;
margin-right: 10px;
}
.value-content {
font-size: 12px;
font-family: MicrosoftYaHei;
color: #333333;
line-height: 16px;
}
}
}
.detail-sumbit {
display: flex;
justify-content: flex-end;
.btn {
width: 182px;
height: 39px;
background: #ff552d;
border: 1px solid #ff5001;
border-radius: 0;
color: #ffffff;
}
}
}
}
.Payment {
.title {
text-align: center;
font-size: 26px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff552d;
}
}
.addAddress {
.title {
text-align: center;
height: 25px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 25px;
}
.image {
display: flex;
justify-content: center;
align-items: center;
padding: 48px 0 32px;
.addressImg {
width: 150px;
height: 150px;
}
}
.content {
text-align: center;
width: 311px;
height: 38px;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #3e454d;
line-height: 19px;
}
}
`
import React , {useState,useRef} from 'react' import React, { useState, useRef } from 'react'
import {Box} from './styled'; import { Box } from './styled'
import { LeftOutlined , RightOutlined } from '@ant-design/icons'; import { LeftOutlined, RightOutlined } from '@ant-design/icons'
import {WareImgsType} from '../../api'; import { WareImgsType } from '../../api'
interface ImagesType{ interface ImagesType {
imgList: Array<WareImgsType> imgList: Array<WareImgsType>
} }
export default function PicturePreview(props:ImagesType) { export default function PicturePreview(props: ImagesType) {
const {imgList} = props const { imgList } = props
console.log(imgList);
const mask =useRef<HTMLDivElement>(null!) const mask = useRef<HTMLDivElement>(null!)
const moveBox =useRef<HTMLDivElement>(null!) const moveBox = useRef<HTMLDivElement>(null!)
const big =useRef<HTMLImageElement>(null!) const big = useRef<HTMLImageElement>(null!)
const [moveLeft,setMoveLeft] = useState(0) // 根据这个值设置图片列表向左偏移 const [moveLeft, setMoveLeft] = useState(0) // 根据这个值设置图片列表向左偏移
// const imgList = [ // const imgList = [
// 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg', // 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
// 'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg', // 'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
...@@ -24,84 +23,104 @@ export default function PicturePreview(props:ImagesType) { ...@@ -24,84 +23,104 @@ export default function PicturePreview(props:ImagesType) {
// 'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg' // 'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
// ] // ]
const [activeImgIndex,setActiveImgIndex] = useState(0) const [activeImgIndex, setActiveImgIndex] = useState(0)
// 改变预览图 // 改变预览图
const handleChangeImg = (index:number) => { const handleChangeImg = (index: number) => {
if (index <= moveLeft + 3) setActiveImgIndex(index) if (index <= moveLeft + 3) setActiveImgIndex(index)
} }
// 移动缩略图 // 移动缩略图
const handleSlide = (direction:string) => { const handleSlide = (direction: string) => {
//左侧按钮 //左侧按钮
if (direction == 'left') { if (direction == 'left') {
moveLeft == 0 ? setMoveLeft(0) : setMoveLeft((props)=>props - 1) moveLeft == 0 ? setMoveLeft(0) : setMoveLeft((props) => props - 1)
} else { // 右侧按钮 } else {
// 右侧按钮
if (imgList.length > 4) { if (imgList.length > 4) {
moveLeft >= imgList.length - 4 ? setMoveLeft(imgList.length - 4) : setMoveLeft((props)=>props + 1) moveLeft >= imgList.length - 4
? setMoveLeft(imgList.length - 4)
: setMoveLeft((props) => props + 1)
} }
} }
} }
// 图片放大镜 // 图片放大镜
const handleMouseMove = (event:React.MouseEvent<HTMLDivElement, MouseEvent>) => { const handleMouseMove = (
let left = event.nativeEvent.offsetX - mask.current.offsetWidth / 2; event: React.MouseEvent<HTMLDivElement, MouseEvent>
let top = event.nativeEvent.offsetY - mask.current.offsetHeight / 2; ) => {
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 maxLeft = moveBox.current.offsetWidth - mask.current.offsetWidth
const maxTop = moveBox.current.offsetHeight - mask.current.offsetHeight const maxTop = moveBox.current.offsetHeight - mask.current.offsetHeight
//约束范围 //约束范围
if (left <= 0) left = 0; if (left <= 0) left = 0
if (left >= maxLeft) left = maxLeft if (left >= maxLeft) left = maxLeft
if (top <= 0) top = 0; if (top <= 0) top = 0
if (top >= maxTop) top = maxTop if (top >= maxTop) top = maxTop
// 设置放大范围遮罩层位置 // 设置放大范围遮罩层位置
mask.current.style.left = left + "px"; mask.current.style.left = left + 'px'
mask.current.style.top = top + "px"; mask.current.style.top = top + 'px'
// 设置大图图片位置,可以用background代替这个方案,有兴趣可以尝试 // 设置大图图片位置,可以用background代替这个方案,有兴趣可以尝试
big.current.style.left = -3 * left + "px"; // 3这个值是 大图除以小图算出来的比例 这里大图是900px 小图是300px big.current.style.left = -3 * left + 'px' // 3这个值是 大图除以小图算出来的比例 这里大图是900px 小图是300px
big.current.style.top = -3 * top + "px"; big.current.style.top = -3 * top + 'px'
} }
return ( return (
<Box> <Box>
<div className="img_wrapper"> <div className="img_wrapper">
<div className="img_content"> <div className="img_content">
{/* <!-- 蒙层,绑定鼠标事件 --> */} {/* <!-- 蒙层,绑定鼠标事件 --> */}
<div className="movebox" <div
onMouseMove={(e)=>handleMouseMove(e)} className="movebox"
ref={moveBox}> onMouseMove={(e) => handleMouseMove(e)}
</div> ref={moveBox}
></div>
{/* <!-- 主图 --> */} {/* <!-- 主图 --> */}
<img src={imgList && imgList[activeImgIndex].imgUrl} <img
src={imgList && imgList[activeImgIndex].imgUrl}
className="img_small" className="img_small"
alt=""/> alt=""
/>
{/* <!-- 放大区域 --> */} {/* <!-- 放大区域 --> */}
<div className="mask" <div className="mask" ref={mask}></div>
ref={mask}></div>
{/* <!-- 大图预览图 --> */} {/* <!-- 大图预览图 --> */}
<div className="img_big"> <div className="img_big">
<img src={imgList && imgList[activeImgIndex].imgUrl} <img
src={imgList && imgList[activeImgIndex].imgUrl}
ref={big} ref={big}
alt=""/> alt=""
/>
</div> </div>
</div> </div>
{/* <!-- 缩略图列表 --> */} {/* <!-- 缩略图列表 --> */}
<div className="img_list_wrapper"> <div className="img_list_wrapper">
{imgList?.length>4 && <LeftOutlined className="el-icon-arrow-left" onClick={()=>handleSlide('left')}/>} {imgList?.length > 4 && (
<LeftOutlined
className="el-icon-arrow-left"
onClick={() => handleSlide('left')}
/>
)}
<div className="img_list_content"> <div className="img_list_content">
<div className="img_list" <div
style={{marginLeft: - moveLeft * 25 + '%'}}> className="img_list"
{ style={{ marginLeft: -moveLeft * 25 + '%' }}
imgList?.map((item,index)=>( >
{imgList?.map((item, index) => (
<img <img
onMouseOver={()=>handleChangeImg(index)} onMouseOver={() => handleChangeImg(index)}
key={index} key={index}
className={`${activeImgIndex === index ? 'activeImg' : ''}`} className={`${activeImgIndex === index ? 'activeImg' : ''}`}
src={item.imgUrl} src={item.imgUrl}
alt="" /> alt=""
)) />
} ))}
</div> </div>
</div> </div>
{ imgList?.length>4 && <RightOutlined className="el-icon-arrow-right" onClick={()=>handleSlide('right')}/>} {imgList?.length > 4 && (
<RightOutlined
className="el-icon-arrow-right"
onClick={() => handleSlide('right')}
/>
)}
</div> </div>
</div> </div>
</Box> </Box>
......
import styled from "styled-components" import styled from 'styled-components'
export const Box = styled.div` export const Box = styled.div`
box-sizing: border-box; box-sizing: border-box;
width: 1200px; width: 1200px;
background-color: #fff; background-color: #fff;
padding: 42px 0 24px 24px; padding: 42px 0 24px 24px;
.item{ .item {
display: flex; display: flex;
&-right{ &-right {
height: 300px; height: 300px;
margin-left: 30px; margin-left: 30px;
.title{ .title {
height: 26px; height: 26px;
font-size: 28px; font-size: 28px;
margin-top: 5px; margin-top: 5px;
...@@ -19,119 +19,121 @@ export const Box = styled.div` ...@@ -19,119 +19,121 @@ export const Box = styled.div`
color: #090909; color: #090909;
line-height: 26px; line-height: 26px;
} }
.function{ .function {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-evenly; justify-content: space-evenly;
width: 375px; width: 375px;
height: 45px; height: 45px;
margin-top: 17px; margin-top: 17px;
background: linear-gradient(90deg, #D7F7F5 0%, #EEFDE9 100%); background: linear-gradient(90deg, #d7f7f5 0%, #eefde9 100%);
&.not{ &.not {
background: none; background: none;
} }
&-item{ &-item {
} }
} }
.menoy{ .menoy {
margin-top: 17px; margin-top: 17px;
&-left{ font-size: 32px;
color: #ef2e00;
&-left {
width: 79px; width: 79px;
height: 41px; height: 41px;
font-size: 32px; font-size: 32px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI; font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold; font-weight: bold;
color: #EF2E00; color: #ef2e00;
line-height: 41px; line-height: 41px;
} }
&-right{ &-right {
width: 40px; width: 40px;
height: 20px; height: 20px;
font-size: 16px; font-size: 16px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI; font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold; font-weight: bold;
color: #EF2E00; color: #ef2e00;
line-height: 20px; line-height: 20px;
} }
} }
.classification{ .classification {
margin-top: 28px; margin-top: 28px;
width: 375px; width: 375px;
height: 50px; height: 50px;
.label{ .label {
height: 21px; height: 21px;
font-size: 16px; font-size: 16px;
font-family: MicrosoftYaHei; font-family: MicrosoftYaHei;
color: #9A9A9A; color: #9a9a9a;
line-height: 21px; line-height: 21px;
margin-right: 36px; margin-right: 36px;
} }
.value{ .value {
height: 21px; height: 21px;
font-size: 16px; font-size: 16px;
font-family: MicrosoftYaHei; font-family: MicrosoftYaHei;
color: #151515; color: #151515;
line-height: 21px; line-height: 21px;
} }
.top{ .top {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
.left{ .left {
} }
.right{ .right {
.selectItem{ .selectItem {
.ant-select-selection-placeholder { .ant-select-selection-placeholder {
color: #000; color: #000;
} }
} }
} }
} }
.bottom{ .bottom {
margin-top: 5px; margin-top: 5px;
} }
} }
.botton-btn{ .botton-btn {
margin-top: 30px; margin-top: 30px;
.btn-left{ .btn-left {
width: 207px; width: 207px;
height: 40px; height: 40px;
background-color: #FFE4D1; background-color: #ffe4d1;
border: 1px solid #EBBAAF; border: 1px solid #ebbaaf;
font-family: MicrosoftYaHei; font-family: MicrosoftYaHei;
color: #FF552D; color: #ff552d;
letter-spacing: 1px; letter-spacing: 1px;
margin-right: 12px; margin-right: 12px;
} }
.btn-right{ .btn-right {
width: 207px; width: 207px;
height: 40px; height: 40px;
background: #FF552D; background: #ff552d;
font-family: MicrosoftYaHei; font-family: MicrosoftYaHei;
color: #FFFFFF; color: #ffffff;
letter-spacing: 1px; letter-spacing: 1px;
} }
} }
} }
} }
.flow-path{ .flow-path {
width: 100%; width: 100%;
height: 192px; height: 192px;
text-align: center; text-align: center;
margin-top: 72px; margin-top: 72px;
position: relative; position: relative;
.image{ .image {
margin: 0 auto; margin: 0 auto;
} }
} }
.prompt{ .prompt {
width: 420px; width: 420px;
height: 25px; height: 25px;
font-size: 20px; font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI; font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold; font-weight: bold;
color: #2B2B2B; color: #2b2b2b;
line-height: 25px; line-height: 25px;
margin: 30px auto 58px auto; margin: 30px auto 58px auto;
} }
...@@ -155,40 +157,40 @@ export const Box = styled.div` ...@@ -155,40 +157,40 @@ export const Box = styled.div`
color: #989898; color: #989898;
} }
} }
.application{ .application {
.title{ .title {
display: flex; display: flex;
align-items: center; align-items: center;
padding-bottom: 25px; padding-bottom: 25px;
.left{ .left {
width: 58px; width: 58px;
height: 58px; height: 58px;
background: #D8D8D8; background: #d8d8d8;
border-radius: 2px; border-radius: 2px;
} }
.right{ .right {
margin-left: 15px; margin-left: 15px;
.top{ .top {
.tag{ .tag {
font-size: 14px; font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC; font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400; font-weight: 400;
color: #FF0F0F; color: #ff0f0f;
} }
.money{ .money {
font-size: 22px; font-size: 22px;
font-family: PingFangSC-Medium, PingFang SC; font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500; font-weight: 500;
color: #FF0F0F; color: #ff0f0f;
} }
.unit{ .unit {
font-size: 12px; font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC; font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400; font-weight: 400;
color: #FF0F0F; color: #ff0f0f;
} }
} }
.bottom{ .bottom {
width: 65px; width: 65px;
height: 18px; height: 18px;
font-size: 13px; font-size: 13px;
...@@ -199,5 +201,85 @@ export const Box = styled.div` ...@@ -199,5 +201,85 @@ export const Box = styled.div`
} }
} }
} }
.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: #121212;
margin-right: 5px;
}
}
}
}
}
.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;
}
}
}
} }
` `
import React, { useEffect, useState , useRef } from "react"; import { Pagination } from 'antd'
import { useRouter } from "next/router"; import Image from 'next/image'
import { Pagination } from "antd"; import { useRouter } from 'next/router'
import { Box } from "./styled"; import { useContext, useEffect, useRef, useState } from 'react'
import Layout from "~/components/layout"; import ContentBox from '~/components/contentBox'
import ContentBox from "~/components/contentBox"; import Filter, { AdapterResult, FilterResult } from '~/components/filter'
import Filter, { FilterResult, AdapterResult } from "~/components/filter"; import Layout from '~/components/layout'
import Image from "next/image"; import api, { Advertisement, Device } from './api'
import api, { Device, Advertisement } from "./api"; import { Box } from './styled'
import { UserContext } from '~/lib/userProvider'
// 此函数在构建时被调用 // 此函数在构建时被调用
export async function getStaticProps() { export async function getStaticProps() {
//获取筛选数据,进行静态渲染 //获取筛选数据,进行静态渲染
return { return {
props: {}, props: {},
}; }
} }
type Props = {}; type Props = {}
export default function EquipmentLeasing(props: Props) { export default function EquipmentLeasing(props: Props) {
const router = useRouter(); const { userInfo } = useContext(UserContext)
const filter = useRef<any>() const router = useRouter()
const [productList, setProductList] = useState( const [productList, setProductList] = useState(
Array<{ element: JSX.Element }> Array<{ element: JSX.Element }>
); )
const [rightProductList, setRightProductList] = useState( const [rightProductList, setRightProductList] = useState(
Array<{ element: JSX.Element }> Array<{ element: JSX.Element }>
); )
const leftDom = (item: Device) => { const leftDom = (item: Device) => {
return ( return (
...@@ -36,64 +37,62 @@ export default function EquipmentLeasing(props: Props) { ...@@ -36,64 +37,62 @@ export default function EquipmentLeasing(props: Props) {
> >
<div className="item-top"> <div className="item-top">
<div className="item-top-image"> <div className="item-top-image">
<Image <Image src={item.images} alt="error" fill />
src={item.wareImgs[0].imgUrl}
alt="error"
fill
/>
</div> </div>
</div> </div>
<div className="item-bottom"> <div className="item-bottom">
<div className="item-bottom-title" title={item.wareTitle}> <div className="item-bottom-title" title={item.goodsName}>
{item.wareTitle} {item.goodsName}
</div> </div>
{userInfo?.cooperationTagId ? (
<div className="item-bottom-price"> <div className="item-bottom-price">
<span className="money">¥{item.minRent}</span> <span className="money">¥{item.price}</span>
<span className="unit">/天起</span> <span className="unit">/天起</span>
</div> </div>
) : (
<div className="unit">暂无报价</div>
)}
</div> </div>
</div> </div>
); )
}; }
const rightDom = (item: Advertisement) => { const rightDom = (item: Advertisement) => {
return ( return (
<div key={item.id} className="right-box-item right-item"> <div key={item.id} className="right-box-item right-item">
<Image src={item.imageUrl} alt="error" fill /> <Image src={item.imageUrl} alt="error" fill />
</div> </div>
); )
}; }
const [filterResult, setFilterResult] = useState<AdapterResult>({}); //筛选结果 const [filterResult, setFilterResult] = useState<AdapterResult>({}) //筛选结果
const [count, setCount] = useState(0); //商品总数 const [count, setCount] = useState(0) //商品总数
const [abort, setAbort] = useState<AbortController | null>(null); //请求中断 const [abort, setAbort] = useState<AbortController | null>(null) //请求中断
const [pageParams, setPageParams] = useState({ const [pageParams, setPageParams] = useState({
type: 1,
pageNo: 1, pageNo: 1,
pageSize: 15, pageSize: 15,
}); //分页器对象 }) //分页器对象
const onPageChange = (page: number, pageSize: number) => { const onPageChange = (page: number, pageSize: number) => {
setPageParams({ setPageParams({
...pageParams, ...pageParams,
pageNo: page, pageNo: page,
}); })
}; }
useEffect(() => { useEffect(() => {
//中断前一次列表请求 //中断前一次列表请求
abort?.abort(); abort?.abort()
setAbort(new AbortController()); setAbort(new AbortController())
}, [filterResult, pageParams]); }, [filterResult, pageParams])
//端口列表请求 //端口列表请求
useEffect(() => { useEffect(() => {
let queryVal = JSON.parse(JSON.stringify(router.query)); let queryVal = JSON.parse(JSON.stringify(router.query))
const idArr = filter.current.idArr
let rs let rs
for (const key in queryVal) { if (Object.keys(queryVal).length) {
if (idArr.includes(key)) { rs = { categoryId: [Number(queryVal['categoryId'])] }
rs = {[key]:router.query[key]}
}
} }
api api
.listPageDeviceInfo( .listPageDeviceInfo(
...@@ -109,59 +108,55 @@ export default function EquipmentLeasing(props: Props) { ...@@ -109,59 +108,55 @@ export default function EquipmentLeasing(props: Props) {
.then((res) => { .then((res) => {
setProductList( setProductList(
res.result?.list?.map((item) => { res.result?.list?.map((item) => {
return { element: leftDom(item) }; return { element: leftDom(item) }
}) || [] }) || []
); )
setCount(res.result?.totalCount || 0); setCount(res.result?.totalCount || 0)
}); })
}, [abort]); }, [abort])
const onFilterChange = ( const onFilterChange = (
filterResult: FilterResult, filterResult: FilterResult,
adapterFilterResult: AdapterResult adapterFilterResult: AdapterResult
) => { ) => {
console.log("filterResult", filterResult, adapterFilterResult); console.log('filterResult', filterResult, adapterFilterResult)
setFilterResult(adapterFilterResult); adapterFilterResult.categoryId = adapterFilterResult.categoryId?.map(
}; (item) => item.id
)
setFilterResult(adapterFilterResult)
}
useEffect(() => { useEffect(() => {
api.listAdvertisementInfo().then((res) => { api.listAdvertisementInfo().then((res) => {
setRightProductList( setRightProductList(
res.result?.map((item) => { res.result?.map((item) => {
return { element: rightDom(item) }; return { element: rightDom(item) }
}) || [] }) || []
); )
}); })
}, []); }, [])
useEffect(() => { useEffect(() => {
let queryVal = JSON.parse(JSON.stringify(router.query)); let queryVal = JSON.parse(JSON.stringify(router.query))
if (router.query) { if (Object.keys(router.query).length) {
const idArr = filter.current.idArr setFilterResult({ categoryId: [Number(queryVal['categoryId'])] })
for (const key in queryVal) {
if (idArr.includes(key)) {
setFilterResult({ [key]:router.query[key] });
} }
} }, [router])
}
}, [router]);
return ( return (
<Layout> <Layout>
<Box> <Box>
<Filter <Filter
types={["地域", "设备类目", "设备品牌", "设备型号"]} types={['地域', '设备品牌', '设备型号']}
showResultItem showResultItem
onChange={onFilterChange} onChange={onFilterChange}
ref={filter}
></Filter> ></Filter>
<div style={{ paddingTop: 13 }}> <div style={{ paddingTop: 13 }}>
<ContentBox <ContentBox
boxIndex={5} boxIndex={5}
leftcontentstyle={{ leftcontentstyle={{
width: "1010px", width: '1010px',
margin: { top: 0, right: "12px", bottom: "12px", left: 0 }, margin: { top: 0, right: '12px', bottom: '12px', left: 0 },
}} }}
leftRenderDom={{ leftRenderDom={{
columns: productList, columns: productList,
...@@ -185,5 +180,5 @@ export default function EquipmentLeasing(props: Props) { ...@@ -185,5 +180,5 @@ export default function EquipmentLeasing(props: Props) {
</div> </div>
</Box> </Box>
</Layout> </Layout>
); )
} }
import styled from "styled-components"; import styled from 'styled-components'
export default function Style() { export default function Style() {
return <></>; return <></>
} }
export const Box = styled.div` export const Box = styled.div`
...@@ -54,6 +54,7 @@ export const Box = styled.div` ...@@ -54,6 +54,7 @@ export const Box = styled.div`
color: #ff552d; color: #ff552d;
line-height: 22px; line-height: 22px;
} }
}
.unit { .unit {
width: 58px; width: 58px;
height: 22px; height: 22px;
...@@ -64,7 +65,6 @@ export const Box = styled.div` ...@@ -64,7 +65,6 @@ export const Box = styled.div`
} }
} }
} }
}
.right-item { .right-item {
width: 180px; width: 180px;
height: 295px; height: 295px;
...@@ -76,4 +76,4 @@ export const Box = styled.div` ...@@ -76,4 +76,4 @@ export const Box = styled.div`
.pagination-page { .pagination-page {
text-align: right; text-align: right;
} }
`; `
import request, { Response } from '~/api/request'; import request, { Response } from '~/api/request'
import { TypesResp } from '~/components/filter/api'
export interface ListPageFlyingInfoParams { export interface ListPageFlyingInfoParams {
pageNo: number, pageNo: number
pageSize: number, pageSize: number
flightSkillsId?:number, flightSkillsId?: number
licenseId?:number, licenseId?: number
regionId?:number regionId?: number
} }
export interface Flying { export interface Flying {
id: number, id: number
price: number, price: number
supplierName: string, supplierName: string
curriculumName: string, curriculumName: string
free: 0 | 1, free: 0 | 1
curriculumDesc: string, curriculumDesc: string
videoUrl: string videoUrl: string
surfaceUrl: string
} }
export interface ListPageFlyingInfoResp { export interface ListPageFlyingInfoResp {
pageNo: 1, pageNo: 1
pageSize: 10, pageSize: 10
list: Array<Flying>, list: Array<Flying>
totalCount: 0, totalCount: 0
totalPage: 0 totalPage: 0
} }
export interface SkillsType { export interface SkillsType {
type: string; type: string
id: number, id: number
skillsName: string, skillsName: string
label:string | number, label: string | number
value:string | number value: string | number
} }
export interface RegionResp { export interface RegionResp {
childInfo: RegionResp[] | null, childInfo: RegionResp[] | null
id: number, id: number
level: number, level: number
name: string, name: string
pid: number pid: number
} }
export interface PilotRegistrationParams { export interface PilotRegistrationParams {
city?: number, city?: number
drivingLicense?: number, drivingLicense?: number
industryAppAuth?: Array<number>, industryAppAuth?: Array<number>
province?: number, province?: number
remark?: string, remark?: string
telephone?: string, telephone?: string
uavLicenseLevelOne?: number, uavLicenseLevelOne?: number
uavLicenseLevelTwo?: number uavLicenseLevelTwo?: number
} }
export default { export default {
//web-作业服务-分页 //web-飞手培训-分页
listPageJobServicesInfo: (params: ListPageFlyingInfoParams): Promise<Response<ListPageFlyingInfoResp>> => { listPageJobServicesInfo: (
return request('/release/curriculum/queryCurriculumInfoList', 'post', params) params: ListPageFlyingInfoParams
): Promise<Response<ListPageFlyingInfoResp>> => {
return request(
'/release/curriculum/queryCurriculumInfoList',
'post',
params
)
}, },
region: (): Promise<Response<Array<RegionResp>>> => { region: (): Promise<Response<Array<RegionResp>>> => {
return request('/pms/webDevice/getSecondDistrictInfo'); return request('/pms/webDevice/getSecondDistrictInfo')
}, },
PilotLicense: (): Promise<Response<Array<RegionResp>>> => { PilotLicense: (): Promise<Response<Array<RegionResp>>> => {
return request('/release/curriculum/getDronePilotLicense'); return request('/release/curriculum/getDronePilotLicense')
}, },
IndustryFlightSkills: (): Promise<Response<Array<SkillsType>>> => { 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>>> => { FlightSkills: (params: { type: 3 }): Promise<Response<Array<TypesResp>>> => {
return request('/release/curriculum/pilotRegistration',"post",params); return request('/pms/classify/queryCategoryInfoByType', 'get', params)
}, },
} }
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from 'react'
import Layout from "~/components/layout"; import Layout from '~/components/layout'
import { Box } from "./styled"; import { Box } from './styled'
import { Button } from "antd"; import { Button, Tabs } from 'antd'
import { useRouter } from "next/router"; import { useRouter } from 'next/router'
import { ParsedUrlQuery } from "querystring"; import { ParsedUrlQuery } from 'querystring'
import type { TabsProps } from 'antd'
import api, { ListPageFlyingInfoResp } from './api'
interface RouterDetail { const contentStyle: React.CSSProperties = {
videoUrl:string | '', width: '100%',
curriculumName:string
} }
export default function FlyingDetail() { export default function FlyingDetail() {
const router = useRouter()
const [detail, setDetail] = useState<ListPageFlyingInfoResp | null>()
const onChange = (key: string) => {
console.log(key)
}
const router = useRouter(); const items: TabsProps['items'] = [
const [detail,setDetail] =useState<ParsedUrlQuery | RouterDetail>() {
useEffect(()=>{ key: '1',
setDetail(router.query) label: `介绍`,
},[router]) 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 ( return (
<Layout> <Layout contentStyle={contentStyle}>
<Box> <Box>
<div className="box-top"> <div className="box">
<div className="left">{detail?.curriculumName}</div> <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"> <div className="right">
{/* <Button {/* <Button
type="primary" type="primary"
...@@ -34,10 +77,16 @@ export default function FlyingDetail() { ...@@ -34,10 +77,16 @@ export default function FlyingDetail() {
</Button> */} </Button> */}
</div> </div>
</div> </div>
<div className="box-body"> </div>
<video className="body-video" controls src={detail?.videoUrl as string} /> <div className="detail">
<Tabs
className="tabs"
defaultActiveKey="1"
items={items}
onChange={onChange}
/>
</div> </div>
</Box> </Box>
</Layout> </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() { export default function Style() {
return <></>; return <></>
} }
export const Box = styled.div` export const Box = styled.div`
box-sizing: border-box; box-sizing: border-box;
.box-top { .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;
}
} */
}
.box-bottom {
margin: 0 auto;
width: 1200px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 10px 0; padding: 16px 0 38px 0;
.left { .left {
height: 25px; height: 50px;
font-size: 20px; .top {
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI; font-size: 24px;
font-weight: bold; font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #000000; color: #000000;
line-height: 25px; margin-bottom: 10px;
}
.bottom {
font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff552d;
}
} }
.right { .right {
.btn { .btn {
...@@ -35,14 +68,41 @@ export const Box = styled.div` ...@@ -35,14 +68,41 @@ export const Box = styled.div`
} }
} }
} }
.box-body { }
margin-top: 20px; .detail {
width: 1200px; margin: 0 auto;
height: 675px;
background: #111111;
.body-video {
width: 1200px; width: 1200px;
height: 675px; height: 420px;
background: #ffffff;
box-shadow: 0px 2px 6px 0px rgba(183, 188, 197, 0.1);
border-radius: 12px;
margin-top: 16px;
padding: 20px;
.tabs {
.body {
.top {
.title {
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
}
.content {
font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #27323f;
margin-top: 10px;
}
}
.bottom {
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
margin-top: 29px;
}
}
} }
} }
`; `
...@@ -2,12 +2,13 @@ import { PlusOutlined } from "@ant-design/icons"; ...@@ -2,12 +2,13 @@ import { PlusOutlined } from "@ant-design/icons";
import { Form, Input, Modal, Upload, Image, Button, Row, Col } from "antd"; import { Form, Input, Modal, Upload, Image, Button, Row, Col } from "antd";
import type { RcFile, UploadProps } from "antd/es/upload"; import type { RcFile, UploadProps } from "antd/es/upload";
import type { UploadFile } from "antd/es/upload/interface"; import type { UploadFile } from "antd/es/upload/interface";
import { useContext, useState } from "react"; import { useContext, useEffect, useState } from "react";
import gApi from "~/api"; import gApi from "~/api";
import NImage from "next/image"; import NImage from "next/image";
import api from "./api"; import api from "./api";
import { useGeolocation } from "~/lib/hooks"; import { useGeolocation } from "~/lib/hooks";
import { UserContext } from "~/lib/userProvider"; import { UserContext } from "~/lib/userProvider";
import { useToken } from "antd/es/theme/internal";
type Props = { type Props = {
open: boolean; open: boolean;
...@@ -33,6 +34,11 @@ export default function PublishMessage(props: Props) { ...@@ -33,6 +34,11 @@ export default function PublishMessage(props: Props) {
const [form] = Form.useForm(); const [form] = Form.useForm();
const { userInfo, setNeedLogin } = useContext(UserContext); const { userInfo, setNeedLogin } = useContext(UserContext);
const position = useGeolocation(); const position = useGeolocation();
const [token, setToken] = useState('');
useEffect(() => {
setToken(window.localStorage.getItem('token') || '');
}, [])
//预览关闭 //预览关闭
const handlePreviewCancel = () => setPreviewOpen(false); const handlePreviewCancel = () => setPreviewOpen(false);
...@@ -155,6 +161,7 @@ export default function PublishMessage(props: Props) { ...@@ -155,6 +161,7 @@ export default function PublishMessage(props: Props) {
onPreview={handlePreview} onPreview={handlePreview}
onChange={handleChange} onChange={handleChange}
maxCount={1} maxCount={1}
headers={{ token: token }}
> >
{fileList.length >= 8 ? null : ( {fileList.length >= 8 ? null : (
<div> <div>
......
import request, { Response } from "~/api/request"; import request, { Response } from '~/api/request'
export interface AllType { export interface AllType {
type?: string; categoryName: string
id?: number; 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;
} }
export interface FilterOptionResp { export interface FilterOptionResp {
type: string; type: string
id: number; id: number
name: string; name: string
} }
export interface RegionResp { export interface RegionResp {
childInfo: RegionResp[] | null; childInfo: RegionResp[] | null
id: number; id: number
level: number; level: number
name: string; name: string
pid: number; pid: number
} }
export const equipmentLeasingApi = { export const equipmentLeasingApi = {
deviceBrand: (): Promise<Response<Array<FilterOptionResp>>> => { deviceBrand: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/deviceBrand"); return request('/pms/webDevice/deviceBrand')
},
deviceCategory: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/category");
}, },
// deviceCategory: (): Promise<Response<Array<FilterOptionResp>>> => {
// return request("/pms/webDevice/category");
// },
deviceModel: (): Promise<Response<Array<FilterOptionResp>>> => { deviceModel: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/deviceModel"); return request('/pms/webDevice/deviceModel')
}, },
}; }
export interface AppType { export interface AppType {
id: number; id: number
name: string; name: string
appName: string; appName: string
createTime: string; createTime: string
type: string; type: string
} }
export interface IndustryType { export interface IndustryType {
id: number; id: number
industryIcon: string; industryIcon: string
name: string; name: string
shortName: string; shortName: string
industryType: string; industryType: string
propagate1: string; propagate1: string
propagate2: string; propagate2: string
image: string; image: string
video: string; video: string
type: string; type: string
appName: string; appName: string
} }
export const jobServicesApi = { export const jobServicesApi = {
listAllAppType: (): Promise<Response<Array<AppType>>> => { listAllAppType: (): Promise<Response<Array<AppType>>> => {
return request("/release/work/listAllAppType"); return request('/release/work/listAllAppType')
}, },
listAllIndustry: (): Promise<Response<Array<IndustryType>>> => { listAllIndustry: (): Promise<Response<Array<IndustryType>>> => {
return request("/release/work/listAllIndustry"); return request('/release/work/listAllIndustry')
}, },
}; }
export const mallApi = { export const mallApi = {
listAllBrand: (): Promise<Response<Array<FilterOptionResp>>> => { listAllBrand: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/brand"); return request('/pms/webDevice/brand')
}, },
listAllCategory: (): Promise<Response<Array<FilterOptionResp>>> => { listAllCategory: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/category"); return request('/pms/webProductMall/category')
}, },
listAllParts: (): Promise<Response<Array<FilterOptionResp>>> => { listAllParts: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/parts"); return request('/pms/webProductMall/parts')
}, },
listAllModel: (): Promise<Response<Array<FilterOptionResp>>> => { listAllModel: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webDevice/model"); return request('/pms/webDevice/model')
}, },
listAllQuality: (): Promise<Response<Array<FilterOptionResp>>> => { listAllQuality: (): Promise<Response<Array<FilterOptionResp>>> => {
return request("/pms/webProductMall/quality"); return request('/pms/webProductMall/quality')
}, },
}; }
export interface SkillsType { export interface SkillsType {
name: string; name: string
type: string; type: string
id: number; id: number
skillsName: string; skillsName: string
licenseType:string licenseType: string
} }
export const flightSkillsApi = { export const flightSkillsApi = {
IndustryFlightSkills: (): Promise<Response<Array<SkillsType>>> => { IndustryFlightSkills: (): Promise<Response<Array<SkillsType>>> => {
return request("/release/curriculum/getIndustryFlightSkills"); return request('/release/curriculum/getIndustryFlightSkills')
}, },
InDronePilotLicense: (): Promise<Response<Array<SkillsType>>> => { InDronePilotLicense: (): Promise<Response<Array<SkillsType>>> => {
return request("/release/curriculum/getDronePilotLicense"); return request('/release/curriculum/getDronePilotLicense')
}, },
}; }
export interface NewsPageType { export interface NewsPageType {
id: number; id: number
newsTitle: string; newsTitle: string
newsAuthor: string; newsAuthor: string
userAccountId: number; userAccountId: number
surfaceImg: string; surfaceImg: string
newsContents: string; newsContents: string
createTime: string; createTime: string
updateTime: string | null; updateTime: string | null
} }
export interface NewsTenderType { export interface NewsTenderType {
id: number; id: number
tenderNewsId: number; tenderNewsId: number
tenderInfoNo: string; tenderInfoNo: string
tenderContent: string; tenderContent: string
tenderPrice: number; tenderPrice: number
createTime: string; createTime: string
apply: number; apply: number
} }
export interface ListPageNewsInfoResp { export interface ListPageNewsInfoResp {
pageNo: number; pageNo: number
pageSize: number; pageSize: number
list: Array<NewsPageType>; list: Array<NewsPageType>
totalCount: number; totalCount: number
totalPage: number; totalPage: number
} }
export interface ListTenderNewsInfoResp { export interface ListTenderNewsInfoResp {
pageNo: number; pageNo: number
pageSize: number; pageSize: number
list: Array<NewsTenderType>; list: Array<NewsTenderType>
totalCount: number; totalCount: number
totalPage: number; totalPage: number
} }
interface ListPageNewsInfoParams { interface ListPageNewsInfoParams {
pageNo: number; pageNo: number
pageSize: number; pageSize: number
cityCode?: number; cityCode?: number
date?: string; date?: string
districtCode?: number; districtCode?: number
provinceCode?: number; provinceCode?: number
} }
interface ListTenderNewsInfoParams { interface ListTenderNewsInfoParams {
pageNo: number; pageNo: number
pageSize: number; pageSize: number
cityCode?: number; cityCode?: number
date?: string; date?: string
districtCode?: number; districtCode?: number
provinceCode?: number; provinceCode?: number
} }
export interface TenderApplyType{ export interface TenderApplyType {
tenderInfoId: number, tenderInfoId: number
tenderNewsId: number, tenderNewsId: number
userAccountId: number userAccountId: number
} }
...@@ -185,16 +163,33 @@ export const listNewsApi = { ...@@ -185,16 +163,33 @@ export const listNewsApi = {
listNewsPage: ( listNewsPage: (
params: ListPageNewsInfoParams params: ListPageNewsInfoParams
): Promise<Response<ListPageNewsInfoResp>> => { ): Promise<Response<ListPageNewsInfoResp>> => {
return request("/release/industry-news/listNewsPage", "post", params); return request('/release/industry-news/listNewsPage', 'post', params)
}, },
//招标列表 //招标列表
listNewTenderInfo: ( listNewTenderInfo: (
params: ListTenderNewsInfoParams params: ListTenderNewsInfoParams
): Promise<Response<ListTenderNewsInfoResp>> => { ): Promise<Response<ListTenderNewsInfoResp>> => {
return request("/release/tender/listNewTenderInfo", "post", params); return request('/release/tender/listNewTenderInfo', 'post', params)
}, },
//web-招标-合作申请提交 //web-招标-合作申请提交
tenderApply: (params: TenderApplyType): Promise<Response<number>> => { tenderApply: (params: TenderApplyType): Promise<Response<number>> => {
return request('/release/tender/apply', 'post', params) 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 { export interface PositioningInfoParams {
lat?: number; lat: number
lon?: number; lon: number
pageNo?:number, pageNo: number
pageSize?:number pageSize: number
} }
export interface Entiy { export interface Entiy {
dizhi: string; dizhi: string
jd: number; jd: number
wd: number; wd: number
range: number; range: number
} }
export interface ListPageJobInfoResp { export interface ListPageJobInfoType {
id: number; address: string
adCode: string; name: string
province: string; lon: number
locationList: Array<Entiy>; lat: number
distance: number
} }
export interface FlyerBitmapEntiy { export interface FlyerBitmapEntiy {
flyerName: string, flyerName: string
phoneNum: string, phoneNum: string
lon: number, lon: number
lat: number, lat: number
distance: number distance: number
} }
export interface UavBitmapEntiy { export interface UavBitmapEntiy {
uavName: string, uavName: string
online: number, online: number
lon: number, lon: number
lat: number, lat: number
distance: number, distance: number
id: string id: string
} }
export interface BitmapInfo<T> { export interface BitmapInfo<T> {
pageNo: number, pageNo: number
pageSize: number, pageSize: number
list: T[], list: T[]
totalCount: number, totalCount: number
totalPage: number totalPage: number
} }
...@@ -48,19 +49,25 @@ export default { ...@@ -48,19 +49,25 @@ export default {
//web-首页-地图-全国点位 //web-首页-地图-全国点位
listPositioningInfo: ( listPositioningInfo: (
params: PositioningInfoParams params: PositioningInfoParams
): Promise<Response<ListPageJobInfoResp[]>> => { ): Promise<Response<BitmapInfo<ListPageJobInfoType>>> => {
return request("/release/website/getWebsiteList", "get", params); return request('/release/website/getWebsiteList', 'get', params)
}, },
//web-首页-地图-全国飞手 //web-首页-地图-全国飞手
listFlyerBitmap: ( listFlyerBitmap: (
params: PositioningInfoParams params: PositioningInfoParams
): Promise<Response<BitmapInfo<FlyerBitmapEntiy>>> => { ): Promise<Response<BitmapInfo<FlyerBitmapEntiy>>> => {
return request("/release/website/flyer/bitmap", "get", params); return request('/release/website/flyer/bitmap', 'get', params)
}, },
//web-首页-地图-全国无人机 //web-首页-地图-全国无人机
listUavBitmap: ( listUavBitmap: (
params: PositioningInfoParams params: PositioningInfoParams
): Promise<Response<BitmapInfo<UavBitmapEntiy>>> => { ): Promise<Response<BitmapInfo<UavBitmapEntiy>>> => {
return request("/release/website/uav/bitmap", "get", params); return request('/release/website/uav/bitmap', 'get', params)
}, },
}; //web-首页-地图-全国维修-海点数据
listMaintainBitmap: (
params: PositioningInfoParams
): Promise<Response<BitmapInfo<ListPageJobInfoType>>> => {
return request('/release/website/maintain/bitmap', 'get', params)
},
}
import styled from "styled-components"; import styled from 'styled-components'
export default function Style() { export default function Style() {
return <></>; return <></>
} }
export const Box = styled.div` export const Box = styled.div`
...@@ -12,7 +12,7 @@ export const Box = styled.div` ...@@ -12,7 +12,7 @@ export const Box = styled.div`
position: relative; position: relative;
padding: 0px; padding: 0px;
margin: 0px; margin: 0px;
width: 384px; width: 100%;
height: 220px; height: 220px;
} }
...@@ -46,9 +46,4 @@ export const Box = styled.div` ...@@ -46,9 +46,4 @@ export const Box = styled.div`
color: #ff552d; color: #ff552d;
} }
} }
#container { `
padding: 0px;
margin: 0px;
width: 100%;
}
`;
import request, { Response } from '~/api/request'; import request, { Response } from '~/api/request'
export interface ListPageJobInfoParams { export interface ListPageJobInfoParams {
pageNo:number, pageNo: number
pageSize:number, pageSize: number
appTypeId?:number, appTypeId?: number
industryId?:number, industryId?: number
inspectionName?:string, inspectionName?: string
string?:number, string?: number
regionId?:number, regionId?: number
} }
export interface Job { export interface Job {
id:number, id: number
serviceName:string, serviceName: string
teamName:string, teamName: string
price:number, price: number
} }
export interface ListPageJobInfoResp { export interface ListPageJobInfoResp {
pageNo: 1, pageNo: 1
pageSize: 10, pageSize: 10
list: Array<Job>, list: Array<Job>
totalCount: 0, totalCount: 0
totalPage: 0 totalPage: 0
} }
export default { export default {
//web-作业服务-分页 //web-作业服务-分页
listPageJobServicesInfo: (params: ListPageJobInfoParams,option:{}): Promise<Response<ListPageJobInfoResp>> => { listPageJobServicesInfo: (
return request('/release/work/queryTaskServiceList', 'post', params,option) params: ListPageJobInfoParams,
option: {}
): Promise<Response<ListPageJobInfoResp>> => {
return request(
'/pms/backstage/work/queryWorkServiceList',
'post',
params,
option
)
}, },
} }
import request, { Response } from '~/api/request'; import request, { Response } from '~/api/request'
import { RegionResp } from '~/components/filter/api'
export interface ListPageJobInfoParams { export interface ListPageJobInfoParams {
pageNo:number, pageNo: number
pageSize:number, pageSize: number
appTypeId?:number, appTypeId?: number
industryId?:number, industryId?: number
inspectionName?:string, inspectionName?: string
string?:number, string?: number
regionId?:number, regionId?: number
} }
export interface JobDetail { export interface JobDetail {
id?: number, id?: number
content?: string, content?: string
contentImgs?: string[] | null, contentImgs?: string[] | null
contentVideo?: string | null, contentVideo?: string | null
star?: number, star?: number
img?: string | null, img?: string | null
type?: number, type?: number
name?:string, name?: string
time?:number | string time?: number | string
} }
export interface ListPageJobInfoResp { export interface ListPageJobInfoResp {
id: number, id: number
serviceName: string, serviceName: string
pictureUrl: string, pictureUrl: string
videoUrl: string, videoUrl: string
teamPoster:string, teamPoster: string
evaluateInfo:Array<JobDetail>, evaluateInfo: Array<JobDetail>
item:number item: number
coverPlan: string
serviceIntroduction: string
inspComtList: []
} }
export interface GetJobServicesDetailParams { export interface GetJobServicesDetailParams {
id: number 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 { export default {
//web-作业服务-详情 //web-作业服务-详情
listDetailJobServicesInfo: (params:GetJobServicesDetailParams): Promise<Response<ListPageJobInfoResp>> => { listDetailJobServicesInfo: (
return request('/release/work/selectInspection', 'get', params) params: GetJobServicesDetailParams
): Promise<Response<ListPageJobInfoResp>> => {
return request('/pms/backstage/work/queryWorkService', 'get', params)
},
//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() { export default function Style() {
return <></>; return <></>
} }
export const Box = styled.div` export const Box = styled.div`
...@@ -9,26 +9,26 @@ export const Box = styled.div` ...@@ -9,26 +9,26 @@ export const Box = styled.div`
width: 1200px; width: 1200px;
height: 1338px; height: 1338px;
margin-top: 18px; margin-top: 18px;
background-color: #FFFFFF; background-color: #ffffff;
.top{ .top {
display: flex; display: flex;
height: 300px; height: 300px;
padding: 24px 0 0 24px; padding: 24px 0 0 24px;
&-image{ &-image {
width: 300px; width: 300px;
height: 300px; height: 300px;
background-color: #F4F5F7; background-color: #f4f5f7;
border-radius: 6px; border-radius: 6px;
margin-right: 32px; margin-right: 32px;
position: relative; position: relative;
} }
&-right{ &-right {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
height: 300px; height: 300px;
.right-top{ .right-top {
.title{ .title {
height: 26px; height: 26px;
font-size: 28px; font-size: 28px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI; font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
...@@ -36,23 +36,23 @@ export const Box = styled.div` ...@@ -36,23 +36,23 @@ export const Box = styled.div`
color: #090909; color: #090909;
line-height: 26px; line-height: 26px;
} }
.detail{ .detail {
display: flex; display: flex;
margin-top: 27px; margin-top: 27px;
.tab{ .tab {
width: 64px; width: 64px;
height: 18px; height: 18px;
line-height: 18px; line-height: 18px;
text-align: center; text-align: center;
background: linear-gradient(270deg, #3E62E5 0%, #3588F7 100%); background: linear-gradient(270deg, #3e62e5 0%, #3588f7 100%);
border-radius: 9px; border-radius: 9px;
font-size: 12px; font-size: 12px;
font-family: PingFangSC-Medium, PingFang SC; font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500; font-weight: 500;
color: #F6FDFE; color: #f6fdfe;
margin-right: 5px; margin-right: 5px;
} }
.content{ .content {
font-size: 14px; font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC; font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400; font-weight: 400;
...@@ -60,55 +60,82 @@ export const Box = styled.div` ...@@ -60,55 +60,82 @@ export const Box = styled.div`
line-height: 20px; line-height: 20px;
} }
} }
.more{ .more {
display: flex; display: flex;
margin-top: 25px; margin-top: 25px;
.tab{ .tab {
width: 131px; width: 131px;
height: 23px; height: 23px;
line-height: 23px; line-height: 23px;
text-align: center; text-align: center;
border-radius: 3px; border-radius: 3px;
font-family: MicrosoftYaHei; font-family: MicrosoftYaHei;
background-color: #F4F4F4; background-color: #f4f4f4;
color: #333333; color: #333333;
margin-right: 8px; margin-right: 8px;
&.filst{ &.filst {
color: #6E411E; color: #6e411e;
background-color: #F9E3D1; background-color: #f9e3d1;
} }
} }
} }
} }
.right-bottom{ .right-bottom {
.bottom-btn{ .bottom-btn {
.btn-left{ .btn-left {
width: 207px; width: 207px;
height: 40px; height: 40px;
background-color: #FFE4D1; background-color: #ffe4d1;
border: 1px solid #EBBAAF; border: 1px solid #ebbaaf;
font-family: MicrosoftYaHei; font-family: MicrosoftYaHei;
color: #FF552D; color: #ff552d;
letter-spacing: 1px; letter-spacing: 1px;
margin-right: 12px; margin-right: 12px;
} }
.btn-right{ .btn-right {
width: 207px; width: 207px;
height: 40px; height: 40px;
background: #FF552D; background: #ff552d;
font-family: MicrosoftYaHei; font-family: MicrosoftYaHei;
color: #FFFFFF; color: #ffffff;
letter-spacing: 1px; letter-spacing: 1px;
} }
} }
} }
} }
} }
.tabs{ .tabs {
padding: 0 24px; padding: 0 24px;
margin-top: 69px; margin-top: 69px;
.teamIntroduction{ .teamIntroduction {
width: 100%; 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;
}
}
}
` `
import React, { useEffect, useState , useRef } from "react"; import React, { useEffect, useState, useRef } from 'react'
import { Box } from "./styled"; import { Box } from './styled'
import { Pagination } from "antd"; import { Pagination } from 'antd'
import Layout from "~/components/layout"; import Layout from '~/components/layout'
import ContentBox from "~/components/contentBox"; import ContentBox from '~/components/contentBox'
import { useRouter } from "next/router"; import { useRouter } from 'next/router'
import Filter, { FilterResult, AdapterResult } from "~/components/filter"; import Filter, { FilterResult, AdapterResult } from '~/components/filter'
import api, { Job } from "./api"; import api, { Job } from './api'
import Image from "next/image"; import Image from 'next/image'
// 此函数在构建时被调用 // 此函数在构建时被调用
export async function getServerSideProps() { export async function getServerSideProps() {
return { return {
props: {}, props: {},
}; }
} }
interface ImageListType {} interface ImageListType {}
export default function JobServices() { export default function JobServices() {
const router = useRouter(); const router = useRouter()
const filter = useRef<any>()
const [list, setList] = useState([ 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", // "https://pad-video-x.oss-cn-shenzhen.aliyuncs.com/file/665512fd-12e6-49a9-93c1-f9dcd0e82083.jpg",
]); ])
const [productList, setProductList] = useState( const [productList, setProductList] = useState(
Array<{ element: JSX.Element }> Array<{ element: JSX.Element }>
); )
const [rightDomList, setRightDomList] = useState( const [rightDomList, setRightDomList] = useState(
Array<{ element: JSX.Element }> Array<{ element: JSX.Element }>
); )
const leftDom = (item: Job) => { const leftDom = (item: Job) => {
return ( return (
<div <div
...@@ -43,8 +42,9 @@ export default function JobServices() { ...@@ -43,8 +42,9 @@ export default function JobServices() {
{/* <div className="com">{item.teamName}</div> */} {/* <div className="com">{item.teamName}</div> */}
</div> </div>
<div className="value-right"> <div className="value-right">
<span className="money">¥{item.price}</span>{" "} {/* <span className="money">¥{item.price}</span> */}
<span className="unit">/平</span> {/* <span className="unit">/平</span> */}
<span className="money">获取报价</span>
</div> </div>
</div> </div>
</div> </div>
...@@ -56,49 +56,46 @@ export default function JobServices() { ...@@ -56,49 +56,46 @@ export default function JobServices() {
<div className="com">{item.teamName}</div> <div className="com">{item.teamName}</div>
</div> </div>
</div> </div>
); )
}; }
const rightDom = (item: string) => { const rightDom = (item: string) => {
return ( return (
<div className="right-box-item advertisement" key={item}> <div className="right-box-item advertisement" key={item}>
<Image src={item} alt="error" width={260} height={420} /> <Image src={item} alt="error" width={260} height={420} />
</div> </div>
); )
}; }
const [filterResult, setFilterResult] = useState<AdapterResult>({}); //筛选结果 const [filterResult, setFilterResult] = useState<AdapterResult>({}) //筛选结果
const [pageParams, setPageParams] = useState({ const [pageParams, setPageParams] = useState({
pageNo: 1, pageNo: 1,
pageSize: 14, pageSize: 14,
}); //分页器对象 }) //分页器对象
const [count, setCount] = useState(0); //商品总数 const [count, setCount] = useState(0) //商品总数
const [abort, setAbort] = useState<AbortController | null>(null); //请求中断 const [abort, setAbort] = useState<AbortController | null>(null) //请求中断
const onPageChange = (page: number, pageSize: number) => { const onPageChange = (page: number, pageSize: number) => {
setPageParams({ setPageParams({
...pageParams, ...pageParams,
pageNo: page, pageNo: page,
}); })
}; }
useEffect(() => { useEffect(() => {
//中断前一次列表请求 //中断前一次列表请求
abort?.abort(); abort?.abort()
setAbort(new AbortController()); setAbort(new AbortController())
}, [filterResult, pageParams]); }, [filterResult, pageParams])
//端口列表请求 //端口列表请求
useEffect(() => { useEffect(() => {
let queryVal = JSON.parse(JSON.stringify(router.query)); let queryVal = JSON.parse(JSON.stringify(router.query))
const idArr = filter.current.idArr
let rs let rs
for (const key in queryVal) { if (Object.keys(queryVal).length) {
if (idArr.includes(key)) { rs = { categoryId: [Number(queryVal['categoryId'])] }
rs = {[key]:router.query[key]}
}
} }
api api
.listPageJobServicesInfo( .listPageJobServicesInfo(
...@@ -114,49 +111,46 @@ export default function JobServices() { ...@@ -114,49 +111,46 @@ export default function JobServices() {
.then((res) => { .then((res) => {
setProductList( setProductList(
res.result?.list?.map((item) => { res.result?.list?.map((item) => {
return { element: leftDom(item) }; return { element: leftDom(item) }
}) || [] }) || []
); )
setCount(res.result?.totalCount || 0); setCount(res.result?.totalCount || 0)
}); })
}, [abort]); }, [abort])
const onFilterChange = ( const onFilterChange = (
filterResult: FilterResult, filterResult: FilterResult,
adapterFilterResult: AdapterResult adapterFilterResult: AdapterResult
) => { ) => {
console.log("filterResult", filterResult, adapterFilterResult); console.log('filterResult', filterResult, adapterFilterResult)
setFilterResult(adapterFilterResult); adapterFilterResult.categoryId = adapterFilterResult.categoryId?.map(
}; (item) => item.id
)
setFilterResult(adapterFilterResult)
}
useEffect(() => { useEffect(() => {
setRightDomList( setRightDomList(
list.map((item) => { list.map((item) => {
return { element: rightDom(item) }; return { element: rightDom(item) }
}) })
); )
}, []); }, [])
useEffect(() => { useEffect(() => {
let queryVal = JSON.parse(JSON.stringify(router.query)); let queryVal = JSON.parse(JSON.stringify(router.query))
if (router.query) { if (Object.keys(router.query).length) {
const idArr = filter.current.idArr setFilterResult({ categoryId: [Number(queryVal['categoryId'])] })
for (const key in queryVal) {
if (idArr.includes(key)) {
setFilterResult({ [key]:router.query[key] });
}
} }
} }, [router])
}, [router]);
return ( return (
<Layout> <Layout>
<Box> <Box>
<Filter <Filter
types={["地域", "行业", "应用"]} types={['地域', '行业', '应用']}
showResultItem showResultItem
onChange={onFilterChange} onChange={onFilterChange}
ref={filter}
></Filter> ></Filter>
<div style={{ marginTop: 10 }}> <div style={{ marginTop: 10 }}>
<ContentBox <ContentBox
...@@ -179,12 +173,12 @@ export default function JobServices() { ...@@ -179,12 +173,12 @@ export default function JobServices() {
}} }}
rightRenderDom={{ columns: rightDomList }} rightRenderDom={{ columns: rightDomList }}
leftcontentstyle={{ leftcontentstyle={{
width: "924px", width: '924px',
margin: { top: 0, right: "10px", bottom: "10px", left: 0 }, margin: { top: 0, right: '10px', bottom: '10px', left: 0 },
}} }}
/> />
</div> </div>
</Box> </Box>
</Layout> </Layout>
); )
} }
import request, { Response } from '~/api/request'; import request, { Response } from '~/api/request'
export interface ListPageGoodsInfoParams { export interface DeviceListParams {
"brandId"?: number, categoryId?: any[];
"districtId"?: number, pageNo: number;
"modelId"?: number, pageSize: number;
"pageNo": number, provinceId?: number;
"pageSize": number, type: number;
"partsId"?: number,
"productCategoryId"?: number,
"qualityId"?: number
} }
export interface Goods { export interface Goods {
"createTime": string, id: number;
"directoryId": number, goodsName: string;
"directoryName": string, images: string;
"goodsName": string, price?: any;
"goodsOneLevelTypeName": string,
"goodsTwoLevelTypeName": string,
"id": number,
"imgUrl": string,
"isCoupons": number,
"status": number
} }
export interface ListPageGoodsInfoResp { export interface DeviceListResp {
"pageNo": 1, "pageNo": 1,
"pageSize": 10, "pageSize": 10,
"list": Array<Goods>, "list": Array<Goods>,
...@@ -33,17 +24,19 @@ export interface ListPageGoodsInfoResp { ...@@ -33,17 +24,19 @@ export interface ListPageGoodsInfoResp {
} }
export interface Ad { export interface Ad {
id: number; id: number
imageUrl: string; bannerImg: string
} }
export default { export default {
//web-商品信息-分页 //web-商品信息-分页
listPageGoodsInfo: (params: ListPageGoodsInfoParams, options = {}): Promise<Response<ListPageGoodsInfoResp>> => { deviceList: (params: DeviceListParams, options = {}): Promise<Response<DeviceListResp>> => {
return request('/pms/webProductMall/listPageGoodsInfo', 'post', params, options) return request('/pms/product/mall/deviceList', 'post', params, options)
}, },
//产品商城广告位 //产品商城广告位
ad: (): Promise<Response<Array<Ad>>> => { listBannerImg: () => {
return request('/pms/webProductMall/ad') return request('/release/module/listBannerImg', 'get', {
} moduleCode: 'PRODUCT_MARKETP'
})
},
} }
...@@ -13,7 +13,7 @@ import { Navigation } from "swiper"; ...@@ -13,7 +13,7 @@ import { Navigation } from "swiper";
// Import Swiper styles // Import Swiper styles
import "swiper/css"; import "swiper/css";
import "swiper/css/navigation"; import "swiper/css/navigation";
import api, { GetAppGoodsInfoDetailResult } from "./api"; import api, { GetLeaseGoodsDetailResp, ProductSpecList } from "./api";
import IntentionModal from "./components/intentionModal"; import IntentionModal from "./components/intentionModal";
import { UserContext } from "~/lib/userProvider"; import { UserContext } from "~/lib/userProvider";
...@@ -22,11 +22,24 @@ export default function MallDetail() { ...@@ -22,11 +22,24 @@ export default function MallDetail() {
const [visible, setVisible] = useState(false); //商品图预览 const [visible, setVisible] = useState(false); //商品图预览
const router = useRouter(); const router = useRouter();
const [id, setId] = useState<number | null>(null); const [id, setId] = useState<number | null>(null);
const [detail, setDetail] = useState<GetAppGoodsInfoDetailResult | null>( const [detail, setDetail] = useState<GetLeaseGoodsDetailResp | null>(null); //详情数据
null
); //详情数据
const [intentionModalOpen, setIntentionModalOpen] = useState(false); //意向弹窗 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 //打开意向modal
const openIntentionModal = () => { const openIntentionModal = () => {
...@@ -53,8 +66,9 @@ export default function MallDetail() { ...@@ -53,8 +66,9 @@ export default function MallDetail() {
useEffect(() => { useEffect(() => {
if (id) { if (id) {
api api
.getAppGoodsInfoDetail({ .getLeaseGoodsDetail({
id: id, goodsId: id,
type: 0,
}) })
.then((res) => { .then((res) => {
setDetail(res.result || null); setDetail(res.result || null);
...@@ -71,11 +85,16 @@ export default function MallDetail() { ...@@ -71,11 +85,16 @@ export default function MallDetail() {
detail={detail} detail={detail}
onOk={handleIntentionOk} onOk={handleIntentionOk}
onCancel={handleIntentionCancel} onCancel={handleIntentionCancel}
onChange={(items: ProductSpecList[]) => setCheckItems(items)}
></IntentionModal> ></IntentionModal>
<div className="page" style={{ marginTop: 20, backgroundColor: "#fff" }}> <div className="page" style={{ marginTop: 20, backgroundColor: "#fff" }}>
<div style={{ display: "none" }}> <div style={{ display: "none" }}>
<AImage.PreviewGroup <AImage.PreviewGroup
preview={{ visible, onVisibleChange: (vis) => setVisible(vis) }} preview={{
visible,
onVisibleChange: (vis) => setVisible(vis),
current: previewIndex,
}}
> >
{detail?.images?.map((item) => { {detail?.images?.map((item) => {
return <AImage key={item.id} src={item.imgUrl} />; return <AImage key={item.id} src={item.imgUrl} />;
...@@ -106,7 +125,7 @@ export default function MallDetail() { ...@@ -106,7 +125,7 @@ export default function MallDetail() {
onSlideChange={() => console.log("slide change")} onSlideChange={() => console.log("slide change")}
onSwiper={(swiper) => console.log(swiper)} onSwiper={(swiper) => console.log(swiper)}
> >
{detail?.images?.map((item) => { {detail?.images?.map((item, i) => {
return ( return (
<SwiperSlide key={item.id}> <SwiperSlide key={item.id}>
<AImage <AImage
...@@ -116,7 +135,9 @@ export default function MallDetail() { ...@@ -116,7 +135,9 @@ export default function MallDetail() {
src={item.imgUrl} src={item.imgUrl}
fallback={errImg} fallback={errImg}
style={{ cursor: "pointer" }} style={{ cursor: "pointer" }}
onClick={() => setProductImg(item.imgUrl)} onClick={() => {
setProductImg(item.imgUrl), setPreviewIndex(i);
}}
/> />
</SwiperSlide> </SwiperSlide>
); );
...@@ -128,11 +149,8 @@ export default function MallDetail() { ...@@ -128,11 +149,8 @@ export default function MallDetail() {
<div className={`${styles.font1} ${styles.ellipsis}`}> <div className={`${styles.font1} ${styles.ellipsis}`}>
{detail?.goodsName} {detail?.goodsName}
</div> </div>
<div <div className={`${styles.font2} ${styles.ellipsis2}`} style={{}}>
className={`${styles.font2} ${styles.ellipsis}`} {detail?.goodsDetail?.goodsDesc}
style={{ height: 22 }}
>
{detail?.goodsDesc}
</div> </div>
<Space <Space
size={24} size={24}
...@@ -149,14 +167,14 @@ export default function MallDetail() { ...@@ -149,14 +167,14 @@ export default function MallDetail() {
选择 选择
</Col> </Col>
<Col flex="auto" className={styles.font4} style={{}}> <Col flex="auto" className={styles.font4} style={{}}>
已选:1 已选:{checkItems.length}
</Col> </Col>
</Row> </Row>
</Col> </Col>
<Col> <Col>
<Row align="middle" style={{ cursor: "pointer" }}> <Row align="middle" style={{ cursor: "pointer" }}>
<Col className={styles.font4} onClick={openIntentionModal}> <Col className={styles.font4} onClick={openIntentionModal}>
3种可选 {specCount}种可选
</Col> </Col>
<Col style={{ marginLeft: 9 }}> <Col style={{ marginLeft: 9 }}>
<DownOutlined <DownOutlined
......
import request, { Response } from "~/api/request" import request, { Response } from "~/api/request"
export interface GetAppGoodsInfoDetailParams { export interface GetLeaseGoodsDetailParams {
id: number goodsId: number,
type: 1 | 0, //租赁:1 销售商品:0
} }
export interface GetAppGoodsInfoDetailResult { export interface GetLeaseGoodsDetailResp {
id: number; id: number;
pid?: number; images: Image[];
goodsName?: string; goodsVideo?: any;
shareFlyServiceId?: number; goodsVideoId?: any;
repoId?: number; goodsName: string;
goodsSpec?: GoodsSpec[]; goodsNo: string;
images?: Image[]; goodsDetail: GoodsDetail;
goodsVideo?: string; directoryId: number;
goodsVideoId?: number; categoryByOne: number;
goodsDetail?: GoodsDetail; categoryByTwo?: any;
sortTypeId?: number; tag?: any;
masterTypeId?: number; shelfStatus: number;
slaveTypeId?: number; goodsSpec: GoodsSpec[];
tag?: string; otherService: OtherService[];
shelfStatus?: number; price?: any;
otherService?: OtherService[];
question?: Question[];
goodsDesc?: string
} }
export interface GoodsDetail { export interface OtherService {
id: number;
goodsDesc: string;
content: string;
remark?: any;
}
export interface Image {
id: number; id: number;
imgUrl: string; saleServiceId: number;
imgType: number; serviceName: string;
} }
export interface GoodsSpec { export interface GoodsSpec {
id: number; id: number;
goodsSpecName: string; goodsSpecName: string;
goodsTypeId: number; categoryId: number;
typeName: string; typeName: string;
skuId: number; skuId: number;
brandInfoId: number; brandInfoId?: any;
skuName: string; skuName: string;
productSpecList: ProductSpec[]; productSpecList: ProductSpecList[];
industrySpecList?: any; industrySpecList?: any;
chooseType: number; chooseType: number;
skuUnitId: number; skuUnitId: number;
unitName: string; unitName: string;
must: number; must: number;
flag?: any; flag: number;
} }
export interface ProductSpec { export interface ProductSpecList {
id: number; id: number;
productSpec: number; productSpec: number;
productSkuId: number; productSkuId: number;
...@@ -64,26 +55,46 @@ export interface ProductSpec { ...@@ -64,26 +55,46 @@ export interface ProductSpec {
partNo: string; partNo: string;
versionDesc: string; versionDesc: string;
createTime?: any; createTime?: any;
productSpecCPQVO?: any; productSpecCPQVO: ProductSpecCPQVO;
} }
export interface Question { export interface ProductSpecCPQVO {
answer: string, productSpecId: number;
id: number, type: number;
question: string leaseTerm?: any;
specPrice: any[];
} }
//其他服务: 1:免费配送,2:专业飞手培训2日, 3:半年保修, 4:一年保修 export interface GoodsDetail {
export interface OtherService { id: number;
id: number, goodsDesc: string;
saleServiceId: number, content: string;
serviceName: 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 { export default {
//web-获取商品详细信息--共多少种选择 //web-获取商品详细信息--共多少种选择
getAppGoodsInfoDetail(params: GetAppGoodsInfoDetailParams): Promise<Response<GetAppGoodsInfoDetailResult>> { getLeaseGoodsDetail(params: GetLeaseGoodsDetailParams): Promise<Response<GetLeaseGoodsDetailResp>> {
return request('/pms/webProductMall/getAppGoodsInfoDetail', 'get', params) 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 @@ ...@@ -59,6 +59,23 @@
padding: 0 39px 0 38px; padding: 0 39px 0 38px;
height: 364px; height: 364px;
overflow-y: auto; 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(); @include scrollbar();
} }
import { Button, Col, Image, Modal, Row, Space } from "antd"; import { Button, Col, Image, message, Modal, Row, Space } from "antd";
import { useState } from "react"; import { useEffect, useState } from "react";
import errImg from "~/assets/errImg"; import errImg from "~/assets/errImg";
import { GetAppGoodsInfoDetailResult } from "../../api"; import { GetLeaseGoodsDetailResp, ProductSpecList } from "../../api";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
import api from "./api";
import Item from "antd/es/list/Item";
type Props = { type Props = {
open?: boolean; open?: boolean;
onOk?: (e: React.MouseEvent<HTMLButtonElement>) => void; onOk?: () => void;
onCancel: (e: React.MouseEvent<HTMLButtonElement>) => void; onCancel: () => void;
detail: GetAppGoodsInfoDetailResult | null; detail: GetLeaseGoodsDetailResp | null;
onChange?: (checkItems: ProductSpecList[]) => void;
}; };
export default function IntentionModal(props: Props) { 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) { function addProductSpec(goodsSpecIndex: number, productSpecIndex: number) {
...@@ -27,6 +50,58 @@ export default function IntentionModal(props: Props) { ...@@ -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 ( return (
<Modal <Modal
open={props.open} open={props.open}
...@@ -41,6 +116,9 @@ export default function IntentionModal(props: Props) { ...@@ -41,6 +116,9 @@ export default function IntentionModal(props: Props) {
type="primary" type="primary"
className={styles.font5} className={styles.font5}
style={{ width: "100%", height: 44 }} style={{ width: "100%", height: 44 }}
onClick={onSubmit}
loading={loading}
disabled={checkItems.length == 0}
> >
提交意向 提交意向
</Button> </Button>
...@@ -68,7 +146,12 @@ export default function IntentionModal(props: Props) { ...@@ -68,7 +146,12 @@ export default function IntentionModal(props: Props) {
className={`${styles.font2} ${styles.ellipsis2}`} className={`${styles.font2} ${styles.ellipsis2}`}
style={{ marginTop: 7 }} style={{ marginTop: 7 }}
> >
已选: 已选:{" "}
{checkItems
.map((item) => {
return item.specName;
})
.join("+")}
</div> </div>
</Col> </Col>
</Row> </Row>
......
import request, { Response } from '~/api/request'
export interface GetWebDeviceDetailParams {
buyNum: number
directoryId: number
goodsInfoId: number
mallSpecIds: number[]
remark?: string
userAddressId: number
}
export interface WareImgsType {
id: number
imgUrl: string
imgType: number
}
export interface UserAddress {
id: number
takeName: string
takePhone: string
takeRegion: string
takeAddress: string
type: number
}
export interface GetOrderForGoods {
realityAmount: number
orderNo: string
}
export default {
//web-地址管理-查询用户地址列表-条件查询
listUserAddress: (params: {}): Promise<Response<UserAddress[]>> => {
return request('/oms/user-address/selectList', 'POST', params)
},
//web-产品商城-下单
FeignAddLease: (
params: GetWebDeviceDetailParams
): Promise<Response<GetOrderForGoods>> => {
return request('/oms/app-order/commitMallOrder', 'post', params)
},
//web-产品商城-订单支付
OrderPayment: (params: {
orderNo: string
}): Promise<Response<GetOrderForGoods>> => {
return request(`/payment/repocash/orderPayment`, 'get', params)
},
}
import styled from 'styled-components'
export const OrderForGoodsBox = styled.div`
box-sizing: border-box;
width: 1000px;
.address {
.top {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e6e6e6;
height: 30px;
line-height: 30px;
margin-top: 30px;
.left {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #333333;
line-height: 18px;
}
.right {
.btn {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #007aff;
line-height: 19px;
}
}
}
.bottom {
.item {
display: flex;
justify-content: space-between;
align-items: center;
width: 1000px;
height: 48px;
border: 1px solid transparent;
margin-top: 8px;
&.active {
background: #fff1e8;
border-radius: 6px;
border: 1px solid #ff552d;
}
.left {
display: flex;
align-items: center;
justify-content: space-around;
.active {
margin-right: 18px;
display: flex;
.icon {
width: 15px;
height: 22px;
background: #ff552d;
margin-left: 17px;
}
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
margin-left: 18px;
}
}
}
.right {
margin-right: 22px;
}
}
}
}
.info {
margin-top: 30px;
.title {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #333333;
line-height: 18px;
}
.table {
.table-title {
display: flex;
align-items: center;
width: 1000px;
border-bottom: 1px solid #e6e6e6;
padding: 10px 0;
margin-top: 20px;
.table-item {
text-align: center;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
}
}
.table-body {
display: flex;
align-items: center;
height: 100px;
margin-top: 10px;
.body-item {
text-align: center;
&.article {
display: flex;
justify-content: space-between;
.image {
margin-right: 10px;
.image-box {
width: 80px;
height: 80px;
}
}
.right {
.top {
width: 171px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #141414;
line-height: 20px;
}
.bottom {
width: 171px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #929295;
line-height: 17px;
}
}
}
&.total-price {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff3100;
line-height: 18px;
}
}
}
}
}
.notes {
display: flex;
align-items: center;
justify-content: space-between;
width: 1000px;
height: 110px;
background: #e1efff;
border: 1px solid #d0eaf5;
padding: 0 22px 0 16px;
.left {
display: flex;
align-items: top;
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
margin-top: 4px;
}
}
.right {
width: 430px;
.top {
display: flex;
align-items: center;
justify-content: space-between;
}
.font {
display: flex;
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 18px;
}
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
margin-right: 12px;
}
.value {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #2b2b2b;
line-height: 20px;
}
.price {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff3100;
line-height: 18px;
}
}
}
.detail-box {
display: flex;
justify-content: flex-end;
margin-top: 26px;
.right-box {
.detail {
width: 477px;
height: 110px;
border: 1px solid #ff5001;
padding: 16px 19px 19px 19px;
.top {
display: flex;
justify-content: flex-end;
align-items: center;
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #474747;
line-height: 19px;
margin-right: 10px;
}
.price {
font-size: 26px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff552d;
line-height: 33px;
}
}
.bottom {
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 15px;
.value {
font-size: 12px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 15px;
margin-right: 10px;
}
.value-content {
font-size: 12px;
font-family: MicrosoftYaHei;
color: #333333;
line-height: 16px;
}
}
}
.detail-sumbit {
display: flex;
justify-content: flex-end;
.btn {
width: 182px;
height: 39px;
background: #ff552d;
border: 1px solid #ff5001;
border-radius: 0;
color: #ffffff;
}
}
}
}
.Payment {
.title {
text-align: center;
font-size: 26px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ff552d;
}
}
.addAddress {
.title {
text-align: center;
height: 25px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 25px;
}
.image {
display: flex;
justify-content: center;
align-items: center;
padding: 48px 0 32px;
.addressImg {
width: 150px;
height: 150px;
}
}
.content {
text-align: center;
width: 311px;
height: 38px;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #3e454d;
line-height: 19px;
}
}
`
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
@include ellipsis(1); @include ellipsis(1);
} }
.ellipsis2 {
@include ellipsis(2);
}
.font1 { .font1 {
font-size: 28px; font-size: 28px;
font-weight: bold; font-weight: bold;
......
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from 'react'
import { Empty, Pagination, Image, Spin } from "antd"; import { Empty, Pagination, Image, Spin } from 'antd'
import Layout from "~/components/layout"; import Layout from '~/components/layout'
import styles from "./index.module.scss"; import styles from './index.module.scss'
import { useRouter } from "next/router"; import { useRouter } from 'next/router'
import Filter, { AdapterResult, FilterResult } from "~/components/filter"; import Filter, { AdapterResult, FilterResult } from '~/components/filter'
import api, { Ad, Goods, ListPageGoodsInfoParams } from "./api"; import api, { Ad, Goods } from './api'
import errImg from "~/assets/errImg"; import errImg from '~/assets/errImg'
// 此函数在构建时被调用 // 此函数在构建时被调用
export async function getServerSideProps() { export async function getServerSideProps() {
return { return {
props: {}, props: {},
}; }
} }
type Props = {}; type Props = {}
export default function Mall(props: Props) { export default function Mall(props: Props) {
const router = useRouter(); const router = useRouter()
const [productList, setProductList] = useState<Array<Goods>>([]); //商品列表 const [productList, setProductList] = useState<Array<Goods>>([]) //商品列表
const [filterResult, setFilterResult] = useState<AdapterResult>({}); //筛选结果 const [filterResult, setFilterResult] = useState<AdapterResult>({}) //筛选结果
const [pageParams, setPageParams] = useState({ const [pageParams, setPageParams] = useState<{
pageNo: number
pageSize: number
}>({
pageNo: 1, pageNo: 1,
pageSize: 15, pageSize: 15,
}); //分页器对象 }) //分页器对象
const [count, setCount] = useState(0); //商品总数 const [count, setCount] = useState(0) //商品总数
const [abort, setAbort] = useState<AbortController | null>(null); //请求中断对你 const [abort, setAbort] = useState<AbortController | null>(null) //请求中断对象
const [adList, setAdList] = useState<Array<Ad>>([]); //广告列表 const [adList, setAdList] = useState<Array<Ad>>([]) //广告列表
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false)
useEffect(() => { useEffect(() => {
//中断前一次列表请求 //中断前一次列表请求
abort?.abort(); abort?.abort()
setAbort(new AbortController()); setAbort(new AbortController())
}, [filterResult, pageParams]); }, [filterResult, pageParams])
//端口列表请求 //商品列表请求
useEffect(() => { useEffect(() => {
if (!abort) { if (!abort) {
return; return
} }
setLoading(true); setLoading(true)
api api
.listPageGoodsInfo( .deviceList(
{ {
...filterResult, type: 0,
...pageParams, ...pageParams,
...filterResult,
}, },
{ {
signal: abort?.signal, signal: abort?.signal,
...@@ -56,34 +60,37 @@ export default function Mall(props: Props) { ...@@ -56,34 +60,37 @@ export default function Mall(props: Props) {
setCount(res.result?.totalCount || 0); setCount(res.result?.totalCount || 0);
setLoading(false); setLoading(false);
}); });
}, [abort]); }, [abort])
//广告请求 //广告请求
useEffect(() => { useEffect(() => {
api.ad().then((res) => { api.listBannerImg().then((res) => {
setAdList(res.result || []); setAdList(res.result || []);
}); });
}, []); }, [])
const onFilterChange = ( const onFilterChange = (
filterResult: FilterResult, filterResult: FilterResult,
adapterFilterResult: AdapterResult adapterFilterResult: AdapterResult
) => { ) => {
console.log("filterResult", filterResult, adapterFilterResult); console.log('filterResult', filterResult, adapterFilterResult)
setFilterResult(adapterFilterResult); adapterFilterResult.categoryId = adapterFilterResult.categoryId?.map(
}; (item) => item.id
)
setFilterResult(adapterFilterResult)
}
const onPageChange = (page: number, pageSize: number) => { const onPageChange = (page: number, pageSize: number) => {
setPageParams({ setPageParams({
...pageParams, ...pageParams,
pageNo: page, pageNo: page,
}); })
}; }
return ( return (
<Layout> <Layout>
<div className="page" style={{ paddingTop: "18px" }}> <div className="page" style={{ paddingTop: "18px" }}>
<Filter <Filter
types={["类目", "地域", "品牌", "部件", "型号", "成色"]} types={["地域"]}
showResultItem showResultItem
onChange={onFilterChange} onChange={onFilterChange}
></Filter> ></Filter>
...@@ -91,6 +98,7 @@ export default function Mall(props: Props) { ...@@ -91,6 +98,7 @@ export default function Mall(props: Props) {
<div className={styles.productList}> <div className={styles.productList}>
<div className={styles.main}> <div className={styles.main}>
<div className={styles.listContent}> <div className={styles.listContent}>
<Spin spinning={loading} delay={500}>
<ul className={styles.listWrap}> <ul className={styles.listWrap}>
{productList.map((item, i) => { {productList.map((item, i) => {
return ( return (
...@@ -102,7 +110,7 @@ export default function Mall(props: Props) { ...@@ -102,7 +110,7 @@ export default function Mall(props: Props) {
<div className={styles.imgBox}> <div className={styles.imgBox}>
<Image <Image
alt="" alt=""
src={item.imgUrl} src={item.images}
className={styles.img} className={styles.img}
width={116} width={116}
height={116} height={116}
...@@ -127,6 +135,8 @@ export default function Mall(props: Props) { ...@@ -127,6 +135,8 @@ export default function Mall(props: Props) {
></Empty> ></Empty>
)} )}
</ul> </ul>
</Spin>
<div className={styles.paginationPage}> <div className={styles.paginationPage}>
<Pagination <Pagination
current={pageParams.pageNo} current={pageParams.pageNo}
...@@ -147,7 +157,7 @@ export default function Mall(props: Props) { ...@@ -147,7 +157,7 @@ export default function Mall(props: Props) {
<Image <Image
key={item.id} key={item.id}
className={styles.ad} className={styles.ad}
src={item.imageUrl} src={item.bannerImg}
width={189} width={189}
height={295} height={295}
preview={false} 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>
);
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论