提交 e898a067 作者: 翁进城

Merge remote-tracking branch 'origin/caoyun'

/** @type {import('next').NextConfig} */
let distDir = ".dev"; //默认输出目录
let distDir = '.dev' //默认输出目录
if (process.env.NODE_ENV === "production") {
if (process.env.NODE_ENV === 'production') {
//生产环境用另一个目录构建,防止与dev冲突
distDir = ".next";
distDir = '.next'
}
const nextConfig = {
distDir,
reactStrictMode: true,
transpilePackages: ["antd"],
output: "standalone",
transpilePackages: ['antd'],
output: 'standalone',
compiler: {
styledComponents: true,
},
redirects() {
return [
{
source: "/",
destination: "/home",
source: '/',
destination: '/home',
permanent: true,
},
];
]
},
async rewrites() {
return [
{
source: "/local/:path*",
source: '/local/:path*',
//destination: "https://iuav.mmcuav.cn/:path*",
destination: "https://test.iuav.shop/:path*",
destination: 'https://test.iuav.shop/:path*',
},
];
]
},
images: {
remotePatterns: [
{
protocol: "http",
hostname: "**",
protocol: 'http',
hostname: '**',
},
{
protocol: "https",
hostname: "**",
protocol: 'https',
hostname: '**',
},
],
},
pageExtensions: ["page.tsx", "page.ts", "page.jsx", "page.js"],
};
pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js'],
}
module.exports = nextConfig;
module.exports = nextConfig
import request, { Response } from '~/api/request';
import request, { Response } from '~/api/request'
export interface ListPageDeviceInfoParams {
"brandId"?: number,
"districtId"?: number,
"modelId"?: number,
"pageNo": number,
"pageSize": number,
"partsId"?: number,
"productCategoryId"?: number,
"qualityId"?: number
brandId?: number
districtId?: number
modelId?: number
pageNo: number
pageSize: number
partsId?: number
productCategoryId?: number
qualityId?: number
}
export interface Device {
id: number,
wareNo: string,
wareTitle: string,
wareTypeId: number,
wareStatus: number,
minDeposit: number,
minRent: number,
totalStock: number,
totalSale: number,
propInfoId: null,
createTime: string,
wareImgs: [
{
id: number,
wareInfoId: number,
imgUrl: string,
imgType: number
}
],
tags: string[]
id: number
goodsName: string
images: string
price: number | null
}
export interface Advertisement {
id:number,
imageUrl:string
id: number
imageUrl: string
}
export interface ListPageDeviceInfoResp {
"pageNo": 1,
"pageSize": 10,
"list": Array<Device>,
"totalCount": 0,
"totalPage": 0
pageNo: 1
pageSize: 10
list: Array<Device>
totalCount: 0
totalPage: 0
}
export default {
//web-设备租赁-分页
listPageDeviceInfo: (params: ListPageDeviceInfoParams,options = {}): Promise<Response<ListPageDeviceInfoResp>> => {
return request('/pms/webDevice/deviceList', 'post', params, options)
listPageDeviceInfo: (
params: ListPageDeviceInfoParams,
options = {}
): Promise<Response<ListPageDeviceInfoResp>> => {
return request('/pms/product/mall/deviceList', 'post', params, options)
},
//web-设备租赁-广告
listAdvertisementInfo: (): Promise<Response<Array<Advertisement>>> => {
return request('/pms/webDevice/ad', 'get')
}
}
\ No newline at end of file
},
}
import request, { Response } from '~/api/request';
import request, { Response } from '~/api/request'
export interface GetWebDeviceDetailParams {
id:number
goodsId: number
}
export interface WareImgsType {
id: number,
wareInfoId: number | null,
imgUrl: string,
id: number
imgUrl: string
imgType: number
}
export interface GetWebDeviceDetailResult {
id: number,
wareNo: string,
wareTitle: string,
wareTypeId: number,
wareStatus: number,
payStatus: number,
minDeposit: number,
maxDeposit: number,
minRent: number,
maxRent: number,
totalStock: number,
totalSale: number,
skuNum: number,
tags: [
string,
string
],
wareImgs: Array<WareImgsType>,
warePropDTO: number | null,
wareDetailContent: string | TrustedHTML
id: number
images: {
id: number
imgUrl: string
imgType: number
}[]
goodsVideo: string
goodsVideoId: number
goodsName: string
goodsDetail: {
id: number
goodsDesc: string
content: string | null
remark: string | null
}
directoryId: number
categoryByOne: number
categoryByTwo: null
tag: null
shelfStatus: number
goodsSpec: {
productSpecList: GetWebDeviceWareSkuById[]
}[]
otherService?: {
id: number
saleServiceId: string
serviceName: string
}[]
price: number | null
goodsNo: string
}
export interface PriceList {
id: number,
wareInfoId: number,
skuInfoId: number,
rentPrice: number,
minDay: number,
maxDay: number,
id: number
wareInfoId: number
skuInfoId: number
rentPrice: number
minDay: number
maxDay: number
createTime: null
}
}
export interface GetWebDeviceWareSkuById {
id: number,
wareInfoId: number,
skuTitle: string,
rentPrice: number | null,
rentDeposit: number,
stockNum: number,
saleNum: number,
createTime: string,
updateTime: null,
skuPriceDTOList: Array<PriceList>,
id: number
productSpec: number
productSkuId: number
specName: string
specImage: string
partNo: string
versionDesc: string
createTime: string | null
productSpecCPQVO: string | null
}
export interface WebDeviceUpdateParams {
id?:number,
inventoryId?:number,
inventoryUsage?:string,
startDay?:string
endDay?:string,
id?: number
inventoryId?: number
inventoryUsage?: string
startDay?: string
endDay?: string
}
export default {
//web-设备租赁-详情
listDetailDeviceInfo: (params: GetWebDeviceDetailParams): Promise<Response<GetWebDeviceDetailResult>> => {
return request('/pms/webDevice/detail', 'get', params)
},
//web-设备租赁-商品
listWareSkuById: (params: GetWebDeviceDetailParams): Promise<Response<GetWebDeviceWareSkuById[]>> => {
return request('/pms/appDevice/listWareSkuById', 'get', params)
listDetailDeviceInfo: (
params: GetWebDeviceDetailParams
): Promise<Response<GetWebDeviceDetailResult>> => {
return request('/pms/product/mall/getLeaseGoodsDetail', 'get', params)
},
//web-设备租赁-立即租赁
listWareSkuUpdate: (params: WebDeviceUpdateParams): Promise<Response<number>> => {
listWareSkuUpdate: (
params: WebDeviceUpdateParams
): Promise<Response<number>> => {
return request('/pms/appDevice/update', 'post', params)
}
}
\ No newline at end of file
},
}
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 GetWebDeviceWareSkuById {
balance: number
nickName: string
}
export default {
//web-地址管理-查询用户地址列表-条件查询
listUserAddress: (params: {}): Promise<Response<UserAddress[]>> => {
return request('/oms/user-address/selectList', 'POST', params)
},
//web-设备租赁-下单
FeignAddLease: (
params: GetWebDeviceDetailParams
): Promise<Response<GetWebDeviceWareSkuById[]>> => {
return request('/pms/appDevice/listWareSkuById', 'post', params)
},
}
import React, { useEffect, useState } from 'react'
import { OrderForGoodsBox } from './styled'
import type { FormInstance, RadioChangeEvent } from 'antd'
import { Button, Radio, Space, Input, message } from 'antd'
import api, { UserAddress } from './api'
import moment from 'moment'
import { ShopDetail } from '../../[id].page'
import { GetWebDeviceDetailResult } from '../../api'
const { TextArea } = Input
interface PropsBox {
setIsorderForGoods: (boolean: boolean) => void
detailData?: GetWebDeviceDetailResult | null
days?: number
shopDetail?: ShopDetail
}
export default function OrderForGoods(props: PropsBox) {
const { setIsorderForGoods, shopDetail, days, detailData } = props
const [value, setValue] = useState(1)
const [areaValue, setAreaValue] = useState<string>()
const [list, setList] = useState<Array<UserAddress> | null>()
const [detail, setDetail] = useState<ShopDetail>()
const onChange = (e: RadioChangeEvent) => {
console.log('radio checked', e.target.value)
setValue(e.target.value)
}
const onChangeValue = (index: number) => {
setValue(index)
}
const detailSumbit = () => {
message.success('提交成功')
console.log(shopDetail)
console.log(list![value])
console.log(areaValue)
console.log(detailData)
console.log(list![value].takeAddress)
console.log(list![value].takeRegion)
console.log(list![value].takeName)
console.log(Number(list![value].takePhone))
if (detailData && shopDetail && list) {
const pushList = {
actualPay: shopDetail.num * detailData.price!,
deposit: 0,
endDate: moment(new Date(shopDetail.dateDetail[1])).format(
'YYYY-MM-DD'
),
orderReceipt: {
detailAddress: list[value].takeAddress,
receiptMethod: 0,
region: list[value].takeRegion,
takeName: list[value].takeName,
takePhone: Number(list[value].takePhone),
},
rentPrice: shopDetail.num * detailData.price!,
returnDate: moment(new Date(shopDetail.dateDetail[1])).format(
'YYYY-MM-DD'
),
shouldPay: shopDetail.num * detailData.price!,
specsId: shopDetail.id,
startDate: moment(new Date(shopDetail.dateDetail[0]!)).format(
'YYYY-MM-DD'
),
wareDescription: detailData.goodsName,
wareImg: detailData.images[0].imgUrl,
wareInfoId: shopDetail.id,
wareNo: detailData.goodsNo,
wareNum: shopDetail.num,
wareTitle: detailData.goodsName,
remark: areaValue,
}
api.FeignAddLease(pushList).then((res) => {
console.log(res)
})
}
// setIsorderForGoods(false)
}
useEffect(() => {
console.log(days)
api
.listUserAddress({})
.then((res) => {
console.log(res)
setList(res.result)
res.result?.map((item, index) => {
if (item.type === 0) {
setValue(index)
}
})
})
.catch((err) => {
console.log(err)
})
if (shopDetail) {
setDetail(shopDetail)
}
}, [])
return (
<OrderForGoodsBox>
<div className="address">
<div className="top">
<div className="left">确认收货地址</div>
<div className="right">
<Button type="link" style={{ color: '#007aff' }}>
管理收货地址
</Button>
</div>
</div>
<div className="bottom">
{list?.map((item, index) => (
<div
key={item.id}
className={`item ${value === index ? 'active' : ''}`}
onClick={() => onChangeValue(index)}
>
<div className="left">
<div className="active">
<div className="icon"></div>
<div className="label">寄送至</div>
</div>
<Radio.Group onChange={onChange} value={value}>
<Space direction="vertical">
<Radio value={index}>{item.takeAddress}</Radio>
</Space>
</Radio.Group>
</div>
{value === index ? (
<div className="right">
<Button type="link" style={{ color: '#007aff' }}>
修改地址
</Button>
</div>
) : null}
</div>
))}
</div>
</div>
<div className="info">
<div className="title">确认订单信息</div>
<div className="table">
<div className="table-title">
<div className="table-item" style={{ width: 290 }}>
宝贝
</div>
<div className="table-item" style={{ width: 130 }}>
单价
</div>
<div className="table-item" style={{ width: 130 }}>
数量
</div>
<div className="table-item" style={{ width: 300 }}>
租期
</div>
<div className="table-item" style={{ width: 135 }}>
合计
</div>
</div>
<div className="table-body">
<div className="body-item article" style={{ width: 290 }}>
<div className="image"></div>
<div className="right">
<div className="top">
智多星航电版智多星航电版智多星航电版智多
</div>
<div className="bottom">
商品简介商品简介商品简介商品简介商品简介
</div>
</div>
</div>
<div className="body-item" style={{ width: 130 }}>
800.00/天
</div>
<div className="body-item" style={{ width: 130 }}>
1
</div>
<div className="body-item lease-term" style={{ width: 300 }}>
{moment(new Date(shopDetail?.dateDetail[0]!)).format(
'YYYY/MM/DD'
)}
<div className="num">{days}</div>
{moment(new Date(shopDetail?.dateDetail[1]!)).format(
'YYYY/MM/DD'
)}
</div>
<div className="body-item total-price" style={{ width: 135 }}>
800.00
</div>
</div>
</div>
</div>
<div className="notes">
<div className="left">
<div className="label">备注:</div>
<TextArea
value={areaValue}
onChange={(e) => setAreaValue(e.target.value)}
placeholder="请输入备注"
autoSize={{ minRows: 3, maxRows: 5 }}
style={{ width: 385, height: 72 }}
/>
</div>
<div className="right">
<div className="top">
<div className="font">
<div className="label">运费:</div>
<div className="value">邮寄到付,由客户自己承担</div>
</div>
<div className="price">200.00</div>
</div>
<div className="bottom">
<div className="font">
<div className="label">押金:</div>
<div className="value">渠道商可免押金</div>
</div>
<div className="price">1000.00</div>
</div>
</div>
</div>
<div className="detail-box">
<div className="right-box">
<div className="detail">
<div className="top">
<div className="label">实付款</div>
<div className="price">¥20000.00</div>
</div>
<div className="bottom">
<div className="value">寄送至</div>
<div className="value-content">
广东省深圳市南山区国际创谷6栋国际创谷6
</div>
</div>
</div>
<div className="detail-sumbit">
<Button className="btn" onClick={detailSumbit}>
提交订单
</Button>
</div>
</div>
</div>
</OrderForGoodsBox>
)
}
import styled from 'styled-components'
export const OrderForGoodsBox = styled.div`
box-sizing: border-box;
width: 1000px;
.address {
.top {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e6e6e6;
height: 30px;
line-height: 30px;
margin-top: 30px;
.left {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #333333;
line-height: 18px;
}
.right {
.btn {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #007aff;
line-height: 19px;
}
}
}
.bottom {
.item {
display: flex;
justify-content: space-between;
align-items: center;
width: 1000px;
height: 48px;
border: 1px solid transparent;
margin-top: 8px;
&.active {
background: #fff1e8;
border-radius: 6px;
border: 1px solid #ff552d;
}
.left {
display: flex;
align-items: center;
justify-content: space-around;
.active {
margin-right: 18px;
display: flex;
.icon {
width: 15px;
height: 22px;
background: #ff552d;
margin-left: 17px;
}
.label {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
margin-left: 18px;
}
}
}
.right {
margin-right: 22px;
}
}
}
}
.info {
margin-top: 30px;
.title {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #333333;
line-height: 18px;
}
.table {
.table-title {
display: flex;
align-items: center;
width: 1000px;
border-bottom: 1px solid #e6e6e6;
padding: 10px 0;
margin-top: 20px;
.table-item {
text-align: center;
font-size: 14px;
font-family: MicrosoftYaHei;
color: #000000;
line-height: 19px;
}
}
.table-body {
display: flex;
align-items: center;
height: 100px;
margin-top: 10px;
.body-item {
text-align: center;
&.article {
display: flex;
justify-content: space-between;
.image {
width: 80px;
height: 80px;
background-color: pink;
margin-right: 10px;
}
.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;
}
}
}
}
`
import React , {useState,useRef} from 'react'
import {Box} from './styled';
import { LeftOutlined , RightOutlined } from '@ant-design/icons';
import {WareImgsType} from '../../api';
import React, { useState, useRef } from 'react'
import { Box } from './styled'
import { LeftOutlined, RightOutlined } from '@ant-design/icons'
import { WareImgsType } from '../../api'
interface ImagesType{
interface ImagesType {
imgList: Array<WareImgsType>
}
export default function PicturePreview(props:ImagesType) {
const {imgList} = props
console.log(imgList);
const mask =useRef<HTMLDivElement>(null!)
const moveBox =useRef<HTMLDivElement>(null!)
const big =useRef<HTMLImageElement>(null!)
const [moveLeft,setMoveLeft] = useState(0) // 根据这个值设置图片列表向左偏移
// const imgList = [
// 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
// 'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
// 'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
// 'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
// 'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
// 'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
// 'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
// ]
export default function PicturePreview(props: ImagesType) {
const { imgList } = props
const [activeImgIndex,setActiveImgIndex] = useState(0)
const mask = useRef<HTMLDivElement>(null!)
const moveBox = useRef<HTMLDivElement>(null!)
const big = useRef<HTMLImageElement>(null!)
const [moveLeft, setMoveLeft] = useState(0) // 根据这个值设置图片列表向左偏移
// const imgList = [
// 'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
// 'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
// 'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
// 'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
// 'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
// 'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
// 'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
// ]
// 改变预览图
const handleChangeImg = (index:number) => {
if (index <= moveLeft + 3) setActiveImgIndex(index)
}
// 移动缩略图
const handleSlide = (direction:string) => {
//左侧按钮
if (direction == 'left') {
moveLeft == 0 ? setMoveLeft(0) : setMoveLeft((props)=>props - 1)
} else { // 右侧按钮
if (imgList.length > 4) {
moveLeft >= imgList.length - 4 ? setMoveLeft(imgList.length - 4) : setMoveLeft((props)=>props + 1)
}
}
}
// 图片放大镜
const handleMouseMove = (event:React.MouseEvent<HTMLDivElement, MouseEvent>) => {
let left = event.nativeEvent.offsetX - mask.current.offsetWidth / 2;
let top = event.nativeEvent.offsetY - mask.current.offsetHeight / 2;
// 最右侧和最下侧的临界值
const maxLeft = moveBox.current.offsetWidth - mask.current.offsetWidth
const maxTop = moveBox.current.offsetHeight - mask.current.offsetHeight
//约束范围
if (left <= 0) left = 0;
if (left >= maxLeft) left = maxLeft
if (top <= 0) top = 0;
if (top >= maxTop) top = maxTop
// 设置放大范围遮罩层位置
mask.current.style.left = left + "px";
mask.current.style.top = top + "px";
// 设置大图图片位置,可以用background代替这个方案,有兴趣可以尝试
big.current.style.left = -3 * left + "px"; // 3这个值是 大图除以小图算出来的比例 这里大图是900px 小图是300px
big.current.style.top = -3 * top + "px";
const [activeImgIndex, setActiveImgIndex] = useState(0)
// 改变预览图
const handleChangeImg = (index: number) => {
if (index <= moveLeft + 3) setActiveImgIndex(index)
}
// 移动缩略图
const handleSlide = (direction: string) => {
//左侧按钮
if (direction == 'left') {
moveLeft == 0 ? setMoveLeft(0) : setMoveLeft((props) => props - 1)
} else {
// 右侧按钮
if (imgList.length > 4) {
moveLeft >= imgList.length - 4
? setMoveLeft(imgList.length - 4)
: setMoveLeft((props) => props + 1)
}
}
}
// 图片放大镜
const handleMouseMove = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>
) => {
let left = event.nativeEvent.offsetX - mask.current.offsetWidth / 2
let top = event.nativeEvent.offsetY - mask.current.offsetHeight / 2
// 最右侧和最下侧的临界值
const maxLeft = moveBox.current.offsetWidth - mask.current.offsetWidth
const maxTop = moveBox.current.offsetHeight - mask.current.offsetHeight
//约束范围
if (left <= 0) left = 0
if (left >= maxLeft) left = maxLeft
if (top <= 0) top = 0
if (top >= maxTop) top = maxTop
// 设置放大范围遮罩层位置
mask.current.style.left = left + 'px'
mask.current.style.top = top + 'px'
// 设置大图图片位置,可以用background代替这个方案,有兴趣可以尝试
big.current.style.left = -3 * left + 'px' // 3这个值是 大图除以小图算出来的比例 这里大图是900px 小图是300px
big.current.style.top = -3 * top + 'px'
}
return (
<Box>
<div className="img_wrapper">
<div className="img_wrapper">
<div className="img_content">
{/* <!-- 蒙层,绑定鼠标事件 --> */}
<div className="movebox"
onMouseMove={(e)=>handleMouseMove(e)}
ref={moveBox}>
</div>
{/* <!-- 主图 --> */}
<img src={imgList && imgList[activeImgIndex].imgUrl}
{/* <!-- 蒙层,绑定鼠标事件 --> */}
<div
className="movebox"
onMouseMove={(e) => handleMouseMove(e)}
ref={moveBox}
></div>
{/* <!-- 主图 --> */}
<img
src={imgList && imgList[activeImgIndex].imgUrl}
className="img_small"
alt=""/>
{/* <!-- 放大区域 --> */}
<div className="mask"
ref={mask}></div>
{/* <!-- 大图预览图 --> */}
<div className="img_big">
<img src={imgList && imgList[activeImgIndex].imgUrl}
ref={big}
alt=""/>
</div>
alt=""
/>
{/* <!-- 放大区域 --> */}
<div className="mask" ref={mask}></div>
{/* <!-- 大图预览图 --> */}
<div className="img_big">
<img
src={imgList && imgList[activeImgIndex].imgUrl}
ref={big}
alt=""
/>
</div>
</div>
{/* <!-- 缩略图列表 --> */}
<div className="img_list_wrapper">
{imgList?.length>4 && <LeftOutlined className="el-icon-arrow-left" onClick={()=>handleSlide('left')}/>}
<div className="img_list_content">
<div className="img_list"
style={{marginLeft: - moveLeft * 25 + '%'}}>
{
imgList?.map((item,index)=>(
<img
onMouseOver={()=>handleChangeImg(index)}
key={index}
className={`${activeImgIndex === index ? 'activeImg' : ''}`}
src={item.imgUrl}
alt="" />
))
}
</div>
</div>
{ imgList?.length>4 && <RightOutlined className="el-icon-arrow-right" onClick={()=>handleSlide('right')}/>}
</div>
</div>
{imgList?.length > 4 && (
<LeftOutlined
className="el-icon-arrow-left"
onClick={() => handleSlide('left')}
/>
)}
<div className="img_list_content">
<div
className="img_list"
style={{ marginLeft: -moveLeft * 25 + '%' }}
>
{imgList?.map((item, index) => (
<img
onMouseOver={() => handleChangeImg(index)}
key={index}
className={`${activeImgIndex === index ? 'activeImg' : ''}`}
src={item.imgUrl}
alt=""
/>
))}
</div>
</div>
{imgList?.length > 4 && (
<RightOutlined
className="el-icon-arrow-right"
onClick={() => handleSlide('right')}
/>
)}
</div>
</div>
</Box>
)
}
......@@ -11,7 +11,7 @@ import { Box } from './styled'
export async function getStaticProps() {
//获取筛选数据,进行静态渲染
return {
props: {}
props: {},
}
}
......@@ -20,23 +20,31 @@ type Props = {}
export default function EquipmentLeasing(props: Props) {
const router = useRouter()
const filter = useRef<any>()
const [productList, setProductList] = useState(Array<{ element: JSX.Element }>)
const [rightProductList, setRightProductList] = useState(Array<{ element: JSX.Element }>)
const [productList, setProductList] = useState(
Array<{ element: JSX.Element }>
)
const [rightProductList, setRightProductList] = useState(
Array<{ element: JSX.Element }>
)
const leftDom = (item: Device) => {
return (
<div key={item.id} className="item" onClick={() => router.push(`/equipmentLeasing/detail/${item.id}`)}>
<div
key={item.id}
className="item"
onClick={() => router.push(`/equipmentLeasing/detail/${item.id}`)}
>
<div className="item-top">
<div className="item-top-image">
<Image src={item.wareImgs[0].imgUrl} alt="error" fill />
<Image src={item.images} alt="error" fill />
</div>
</div>
<div className="item-bottom">
<div className="item-bottom-title" title={item.wareTitle}>
{item.wareTitle}
<div className="item-bottom-title" title={item.goodsName}>
{item.goodsName}
</div>
<div className="item-bottom-price">
<span className="money">¥{item.minRent}</span>
<span className="money">¥{item.price}</span>
<span className="unit">/天起</span>
</div>
</div>
......@@ -56,14 +64,15 @@ export default function EquipmentLeasing(props: Props) {
const [count, setCount] = useState(0) //商品总数
const [abort, setAbort] = useState<AbortController | null>(null) //请求中断
const [pageParams, setPageParams] = useState({
type: 1,
pageNo: 1,
pageSize: 15
pageSize: 15,
}) //分页器对象
const onPageChange = (page: number, pageSize: number) => {
setPageParams({
...pageParams,
pageNo: page
pageNo: page,
})
}
......@@ -88,15 +97,15 @@ export default function EquipmentLeasing(props: Props) {
{
...filterResult,
...pageParams,
...rs
...rs,
},
{
signal: abort?.signal
signal: abort?.signal,
}
)
.then(res => {
.then((res) => {
setProductList(
res.result?.list?.map(item => {
res.result?.list?.map((item) => {
return { element: leftDom(item) }
}) || []
)
......@@ -104,15 +113,18 @@ export default function EquipmentLeasing(props: Props) {
})
}, [abort])
const onFilterChange = (filterResult: FilterResult, adapterFilterResult: AdapterResult) => {
const onFilterChange = (
filterResult: FilterResult,
adapterFilterResult: AdapterResult
) => {
console.log('filterResult', filterResult, adapterFilterResult)
setFilterResult(adapterFilterResult)
}
useEffect(() => {
api.listAdvertisementInfo().then(res => {
api.listAdvertisementInfo().then((res) => {
setRightProductList(
res.result?.map(item => {
res.result?.map((item) => {
return { element: rightDom(item) }
}) || []
)
......@@ -134,21 +146,35 @@ export default function EquipmentLeasing(props: Props) {
return (
<Layout>
<Box>
<Filter types={['地域', '设备品牌', '设备型号']} showResultItem onChange={onFilterChange} ref={filter}></Filter>
<Filter
types={['地域', '设备品牌', '设备型号']}
showResultItem
onChange={onFilterChange}
ref={filter}
></Filter>
<div style={{ paddingTop: 13 }}>
<ContentBox
boxIndex={5}
leftcontentstyle={{
width: '1010px',
margin: { top: 0, right: '12px', bottom: '12px', left: 0 }
margin: { top: 0, right: '12px', bottom: '12px', left: 0 },
}}
leftRenderDom={{
columns: productList,
pagination: (
<div className="pagination-page">
<Pagination current={pageParams.pageNo} pageSize={pageParams.pageSize} showSizeChanger={false} showQuickJumper total={count} onChange={onPageChange} hideOnSinglePage={true} style={{ marginTop: 20 }} />
<Pagination
current={pageParams.pageNo}
pageSize={pageParams.pageSize}
showSizeChanger={false}
showQuickJumper
total={count}
onChange={onPageChange}
hideOnSinglePage={true}
style={{ marginTop: 20 }}
/>
</div>
)
),
}}
rightRenderDom={{ columns: rightProductList }}
/>
......
import React, { useEffect, useState } from "react";
import Layout from "~/components/layout";
import { Box } from "./styled";
import { Button } from "antd";
import { useRouter } from "next/router";
import { ParsedUrlQuery } from "querystring";
import React, { useEffect, useState } from 'react'
import Layout from '~/components/layout'
import { Box } from './styled'
import { Button, Tabs } from 'antd'
import { useRouter } from 'next/router'
import { ParsedUrlQuery } from 'querystring'
import type { TabsProps } from 'antd'
import api, { ListPageFlyingInfoResp } from './api'
interface RouterDetail {
videoUrl:string | '',
curriculumName:string
const contentStyle: React.CSSProperties = {
width: '100%',
}
export default function FlyingDetail() {
const router = useRouter();
const [detail,setDetail] =useState<ParsedUrlQuery | RouterDetail>()
useEffect(()=>{
setDetail(router.query)
},[router])
const router = useRouter()
const [detail, setDetail] = useState<ListPageFlyingInfoResp | null>()
const onChange = (key: string) => {
console.log(key)
}
const items: TabsProps['items'] = [
{
key: '1',
label: `介绍`,
children: (
<div className="body">
<div className="top">
<div className="title">课程简介</div>
<div className="content">{detail?.curriculumDesc}</div>
</div>
{/* <div className="bottom">详情</div> */}
</div>
),
},
]
useEffect(() => {
if (Object.keys(router.query).length) {
api
.listPageJobServicesInfo({ id: Number(router.query.id) })
.then((res) => {
console.log(res)
setDetail(res.result)
})
}
}, [router])
return (
<Layout>
<Layout contentStyle={contentStyle}>
<Box>
<div className="box-top">
<div className="left">{detail?.curriculumName}</div>
<div className="right">
{/* <Button
<div className="box">
<div className="box-body">
<video
className="body-video"
controls
src={detail?.videoUrl as string}
/>
</div>
<div className="box-bottom">
<div className="left">
<div className="top">{detail?.curriculumName}</div>
<div className="bottom">免费</div>
</div>
<div className="right">
{/* <Button
type="primary"
className="btn"
onClick={() =>
......@@ -32,12 +70,18 @@ export default function FlyingDetail() {
>
去考试
</Button> */}
</div>
</div>
</div>
<div className="box-body">
<video className="body-video" controls src={detail?.videoUrl as string} />
<div className="detail">
<Tabs
className="tabs"
defaultActiveKey="1"
items={items}
onChange={onChange}
/>
</div>
</Box>
</Layout>
);
)
}
import request, { Response } from '~/api/request'
export interface ListPageFlyingInfoParams {
id: number
}
export interface Flying {
id: number
price: number
supplierName: string
curriculumName: string
free: 0 | 1
curriculumDesc: string
videoUrl: string
}
export interface ListPageFlyingInfoResp {
id: number
price: number | null
supplierName: string
curriculumName: string
free: number
flightSkills: number
flightSkillsName1: string
flightSkillsName2: string
curriculumDesc: string
surfaceUrl: string | null
videoUrl: string
detailContent: null
}
export default {
//web-飞手培训-详情
listPageJobServicesInfo: (
params: ListPageFlyingInfoParams
): Promise<Response<ListPageFlyingInfoResp>> => {
return request('/release/curriculum/curriculumDetails', 'get', params)
},
}
import styled from "styled-components";
import styled from 'styled-components'
export default function Style() {
return <></>;
return <></>
}
export const Box = styled.div`
box-sizing: border-box;
.box-top {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
.left {
height: 25px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 25px;
.box {
background-color: #fff;
height: 586px;
padding-top: 20px;
.box-body {
margin: 0 auto;
display: flex;
width: 1200px;
height: 470px;
/* background: #111111; */
.body-video {
width: 1200px;
height: 470px;
}
/* .right-box {
width: 362px;
height: 470px;
background: #1b2128;
.tabs {
color: #fff;
}
} */
}
.right {
.btn {
width: 180px;
.box-bottom {
margin: 0 auto;
width: 1200px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 0 38px 0;
.left {
height: 50px;
background: linear-gradient(135deg, #278eff 0%, #0052da 100%);
border-radius: 6px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ffffff;
&:hover {
opacity: 0.8;
.top {
font-size: 24px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
margin-bottom: 10px;
}
.bottom {
font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff552d;
}
}
.right {
.btn {
width: 180px;
height: 50px;
background: linear-gradient(135deg, #278eff 0%, #0052da 100%);
border-radius: 6px;
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #ffffff;
&:hover {
opacity: 0.8;
}
}
}
}
}
.box-body {
margin-top: 20px;
.detail {
margin: 0 auto;
width: 1200px;
height: 675px;
background: #111111;
.body-video {
width: 1200px;
height: 675px;
height: 420px;
background: #ffffff;
box-shadow: 0px 2px 6px 0px rgba(183, 188, 197, 0.1);
border-radius: 12px;
margin-top: 16px;
padding: 20px;
.tabs {
.body {
.top {
.title {
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
}
.content {
font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #27323f;
margin-top: 10px;
}
}
.bottom {
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
margin-top: 29px;
}
}
}
}
`;
`
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论