提交 e119ac70 作者: ZhangLingKun

功能:租赁详情

上级 532cfa47
流水线 #8006 已通过 于阶段
in 5 分 28 秒
......@@ -144,3 +144,70 @@ export type GetCompanyInfoByBUId = InterFunction<
city: string;
}
>;
// 租赁商品详情
export type LeaseGoodsDetailsType = InterFunction<
{
id: number;
},
{
id: number;
tradeName: string;
sellingPoint: string;
level: number;
shelfStatus: number;
productTypeId: number;
brandInfoId: number;
deviceModeId: number;
productParam: string;
resourcesList: Array<{
id: number;
url: string;
type: number;
}>;
specAttrList: Array<{
id: number;
specName: string;
specValuesList: Array<{
id: number;
specName: string;
}>;
}>;
priceStock: Array<{
id: number;
productSpec: string;
cashPledge: number;
threeDaysRental: number;
sevenDaysRental: null;
thirtyDaysRental: null;
ninetyDaysRental: null;
maxDaysRental: null;
skuImage: string;
stock: null;
stockOut: number;
}>;
productDetails: string;
minLeaseTerm: number;
maxLeaseTerm: number;
leasePartsList: Array<{
id: number;
name: string;
number: number;
price: number;
}>;
shipAddress: number;
returnAddress: number;
logisticsCompany: string;
modeOfDelivery: number;
showPrice: number;
createTime: string;
userAccountId: number;
cashPledgeRange: null;
rentalRange: null;
stock: null;
districtCode: null;
productTypeName: string;
brandName: string;
deviceModeName: string;
modeOfDeliveryInfo: string;
}
>;
......@@ -3,6 +3,7 @@ import {
GetAppCategoryInfo,
AppMallGoodsDetails,
GetCompanyInfoByBUId,
LeaseGoodsDetailsType,
} from '@/api/interface/mall';
import request from '../request';
......@@ -22,4 +23,8 @@ export class MallAPI {
// pc-后台用户id单位查询
static getCompanyInfoByBUId: GetCompanyInfoByBUId = (params) =>
request.get('/userapp/company/getCompanyInfoByBUId', { params });
// 租赁商品详情
static leaseGoodsDetails: LeaseGoodsDetailsType = (params) =>
request.get('/pms/app/lease/leaseGoodsDetails', { params });
}
......@@ -58,7 +58,11 @@ const BreadcrumbView: React.FC = () => {
{ name: '订单详情', path: 'product' },
],
},
{ name: '设备租赁', path: 'rent' },
{
name: '设备租赁',
path: 'rent',
children: [{ name: '租赁详情', path: 'detail' }],
},
{ name: '执照培训', path: 'train' },
{ name: '飞手约单', path: 'flyer' },
];
......
......@@ -22,7 +22,7 @@ const RentListItemView: React.FC<{
) as GlobalDataState;
// 跳转商品详情
const handleDetail = () => {
// router.push(`/service/detail/${detail?.id}`).then();
router.push(`/rent/detail/${detail?.id}`).then();
};
return (
<ProductItemWrap onClick={handleDetail}>
......
import React from 'react';
import { GetServerSidePropsContext } from 'next';
import styled from 'styled-components';
import { InterDataType } from '@/api/interface';
import {
LeaseGoodsDetailsType,
GetCompanyInfoByBUId,
} from '@/api/interface/mall';
import { MallAPI } from '@/api/modules/mall';
import BreadcrumbView from '@/components/breadcrumb';
import LayoutView from '@/components/layout';
import RentHeadView from '@/pages/rent/detail/comp/_detailHead';
import RentStoreView from '@/pages/rent/detail/comp/_detailStore';
// 商品详情类型
type DetailType = InterDataType<LeaseGoodsDetailsType>;
// 商城详情类型
type StoreType = InterDataType<GetCompanyInfoByBUId>;
// 每次加载页面都会执行
export async function getServerSideProps(context: GetServerSidePropsContext) {
// 商品id
const id: number = Number(context.params?.id);
// 商品详情
let productDetail: DetailType | undefined;
// 店铺详情
let storeDetail: StoreType | undefined;
// 获取商品详情
const getLeaseGoodsDetails = async () => {
const res = await MallAPI.leaseGoodsDetails({ id });
if (res && res.code === '200') {
productDetail = res.result;
// console.log('获取商品详情 --->', res);
}
};
// 获取店铺详情
const getCompanyInfoById = async () => {
const res = await MallAPI.getCompanyInfoByBUId({
backUserAccountId: Number(productDetail?.userAccountId),
});
if (res && res.code === '200') {
storeDetail = res.result;
// console.log('获取店铺详情 --->', res);
}
};
// 依次获取接口数据
await (async () => {
await getLeaseGoodsDetails();
await getCompanyInfoById();
})();
return { props: { id, productDetail, storeDetail } };
}
const RentDetailView: React.FC<{
id: number;
productDetail: DetailType;
storeDetail: StoreType;
}> = ({ productDetail, storeDetail }) => {
return (
<LayoutView>
<RentDetailWrap>
{/* 面包屑 */}
<BreadcrumbView />
<div className="flex w-full flex-nowrap items-start justify-start">
<RentHeadView detail={productDetail} />
<RentStoreView detail={productDetail} store={storeDetail} />
</div>
<div className="w-full">
{productDetail?.productDetails && (
<div
className="content-html"
dangerouslySetInnerHTML={{
__html: productDetail?.productDetails,
}}
/>
)}
</div>
</RentDetailWrap>
</LayoutView>
);
};
export default RentDetailView;
// 样式
const RentDetailWrap = styled.div`
position: relative;
max-width: 1190px;
box-sizing: border-box;
padding: 2rem 0 0 0;
margin: 0 auto;
.content-html {
width: 100%;
img {
width: 100%;
}
}
`;
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import styled from 'styled-components';
import { InterDataType } from '@/api/interface';
import { LeaseGoodsDetailsType } from '@/api/interface/mall';
import ProductSwiperView from '@/components/product-swiper';
import { GlobalDataState, setGlobalData } from '@/store/module/globalData';
import { UserInfoState } from '@/store/module/userInfo';
import { formatMoney } from '@/utils/money';
// 商品详情类型
type DetailType = InterDataType<LeaseGoodsDetailsType>;
const RentHeadView: React.FC<{ detail: DetailType }> = ({ detail }) => {
// 当前的路由数据
// const router = useRouter();
// store
const dispatch = useDispatch();
// userInfo
const userInfo = useSelector((state: any) => state.userInfo) as UserInfoState;
// globalData
const globalData = useSelector(
(state: any) => state.globalData,
) as GlobalDataState;
// 提交事件
const handleSubmit = async (type: number) => {
// 判断是否登录
if (!userInfo?.id) {
dispatch(
setGlobalData({
loginModalVisible: true,
}),
);
return;
}
// 立即购买
if (type === 1) {
dispatch(
setGlobalData({
qrcodeModalVisible: true,
qrcodeModalPath: 'page-service/service-flyer/index',
qrcodeModalScene: `id=${Number(detail?.id)}`,
}),
);
return;
}
// 在线沟通
if (type === 2) {
dispatch(
setGlobalData({
qrcodeModalVisible: true,
qrcodeModalPath: 'page-service/service-detail/index',
qrcodeModalScene: `id=${Number(detail?.id)}`,
}),
);
}
};
return (
<RentHeadWrap>
<div className="product-swiper">
<ProductSwiperView list={detail?.resourcesList} />
</div>
<div className="product-content">
<div className="content-title">{detail?.tradeName}</div>
<div className="content-price flex-start">
<div className="price-label">价格</div>
<div className="price-money">
{detail?.showPrice ? (
<>
<span className="label">¥</span>
<span
className="num"
title={`${formatMoney(detail?.showPrice)}元起每天`}
>
{formatMoney(detail?.showPrice)}
</span>
<span
className="unit text-ellipsis"
title={`${formatMoney(detail?.showPrice)}元起每天`}
>
起/天
</span>
</>
) : (
<span className="label">咨询报价</span>
)}
</div>
</div>
<div className="content-item flex-start">
<div className="item-label">团队</div>
<div className="item-content flex-start">
<img
className="team-label"
src="https://file.iuav.com/file/sharefly-service-label01.png"
alt="专业飞手"
/>
<div className="team-text">飞手已通过认证培训</div>
</div>
</div>
<div className="content-item flex-start item-bottom">
<div className="item-label">服务</div>
<div className="item-content flex-start">
<div className="item-tag">7x24小时服务</div>
<div className="item-tag">已售{Math.floor(detail.id * 2.22)}</div>
</div>
</div>
<div className="content-action flex-start select-none">
<div className="action-item" onClick={() => handleSubmit(2)}>
在线沟通
</div>
<div className="action-item" onClick={() => handleSubmit(1)}>
马上预约
</div>
</div>
</div>
</RentHeadWrap>
);
};
export default RentHeadView;
// 样式
const RentHeadWrap = styled.div`
position: relative;
width: calc((100% - 0.83rem) / 10 * 7.5);
min-height: 28rem;
background: #ffffff;
border: 0.04rem solid #e3e3e3;
box-sizing: border-box;
margin-right: 0.83rem;
display: flex;
align-items: flex-start;
justify-content: flex-start;
padding: 2rem 1rem 2rem 1rem;
.product-swiper {
position: relative;
width: 22rem;
height: 26rem;
box-sizing: border-box;
}
.product-content {
position: relative;
width: calc(100% - 22rem);
height: 100%;
box-sizing: border-box;
padding: 0 0 0 1rem;
//background: lightblue;
.content-title {
width: 100%;
font-size: 24px;
font-weight: 500;
color: #212121;
margin-bottom: 0.71rem;
// 双行省略
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
}
.content-desc {
font-weight: 400;
color: #666666;
margin-bottom: 0.71rem;
}
.content-price {
position: relative;
width: 100%;
background: #f3f3f3;
box-sizing: border-box;
padding: 0.8rem;
margin-bottom: 1rem;
align-items: baseline;
.price-label {
width: 2.5rem;
color: #999999;
text-align: justify;
text-align-last: justify;
margin-right: 1rem;
transform: translateY(-0.1rem);
}
.price-money {
font-size: 24px;
//line-height: 1;
color: #ff6700;
.label {
font-size: 18px;
}
.unit {
font-size: 13px;
color: #999999;
margin-left: 0.5rem;
}
}
}
.content-item {
margin-bottom: 1rem;
padding: 0 0.8rem;
//flex-wrap: nowrap;
.item-label {
width: 2.5rem;
color: #999999;
text-align: justify;
text-align-last: justify;
margin-right: 1rem;
}
.item-content {
width: calc(100% - 3.5rem);
.team-label {
height: 2rem;
width: 6rem;
object-fit: contain;
margin-right: 0.5rem;
}
.team-text {
color: #666666;
}
.item-tag {
box-sizing: border-box;
background: #f4f4f4;
border-radius: 0.13rem;
padding: 0 0.33rem 0 0.33rem;
color: #333333;
&:not(:last-child) {
margin-right: 0.5rem;
}
}
.content-address {
font-size: 12px;
&:first-child {
margin-bottom: 0.3rem;
.text {
color: #8e8e8e;
}
}
.text {
margin-left: 0.3rem;
font-weight: 400;
}
}
.content-spec {
//min-width: max-content;
height: 2rem;
background: #f2f2f2;
border-radius: 0.08rem;
text-align: center;
line-height: 2rem;
font-weight: 400;
box-sizing: border-box;
padding: 0 1rem;
border: 0.04rem solid #f2f2f2;
margin: 0 0.5rem 0.5rem 0;
&:last-child {
margin-right: 0;
}
}
.spec-active {
background: #ffede8;
border: 0.04rem solid #ff552d;
color: #ff552d;
}
}
}
.item-bottom {
margin-bottom: 6.8rem;
}
.content-action {
//position: absolute;
//left: 1rem;
//bottom: 0;
position: relative;
width: 100%;
margin-top: 2rem;
.action-item {
width: 8.63rem;
height: 2.33rem;
background: #fff0e5;
border: 0.04rem solid #ff552d;
text-align: center;
line-height: 2.33rem;
font-size: 13px;
font-weight: 400;
color: #ff552d;
cursor: pointer;
&:hover,
&:active {
filter: brightness(0.95);
}
}
.action-item:not(:last-child) {
margin-right: 0.8rem;
}
.action-item:last-child {
background: #ff552d;
color: #fff;
}
}
}
`;
import React from 'react';
import { PhoneOutlined, ShopOutlined } from '@ant-design/icons';
import { Button, Rate } from 'antd';
import styled from 'styled-components';
import { InterDataType } from '@/api/interface';
import {
GetCompanyInfoByBUId,
LeaseGoodsDetailsType,
} from '@/api/interface/mall';
import QrcodePopover from '@/components/qrcodePopover';
// 商品详情类型
type DetailType = InterDataType<LeaseGoodsDetailsType>;
// 商城详情类型
type StoreType = InterDataType<GetCompanyInfoByBUId>;
const RentStoreView: React.FC<{ detail: DetailType; store: StoreType }> = ({
store,
}) => {
return (
<RentStoreWrap>
<div className="store-card flex-start">
<img
className="image"
src={store?.brandLogo}
alt={store?.companyName}
/>
<div className="card-content">
<div className="title">{store?.companyName}</div>
<div className="star flex-start">
<div className="tag select-none">店铺星级</div>
<Rate allowHalf defaultValue={5} style={{ fontSize: '10px' }} />
</div>
<div className="text two-line-ellipsis" title={store?.content}>
{store?.content}
</div>
</div>
</div>
<div className="store-item flex-start">
<div className="item-label">地址:</div>
<div className="item-value">{store?.address}</div>
</div>
<div className="store-item flex-start">
<div className="item-label">电话:</div>
<div className="item-value">{store?.phoneNum || '18626051369'}</div>
</div>
<div className="store-action flex-start">
<QrcodePopover
path="page-service/service-store/index"
scene={`id=${Number(store?.id)}`}
>
<Button className="action-item flex-start">
<ShopOutlined style={{ color: '#FF552D' }} />
<div className="text">进店逛逛</div>
</Button>
</QrcodePopover>
<QrcodePopover
path="page-service/service-store/index"
scene={`id=${Number(store?.id)}`}
>
<Button className="action-item flex-start">
<PhoneOutlined
style={{ color: '#FF552D', transform: 'rotateY(180deg)' }}
/>
<div className="text">联系方式</div>
</Button>
</QrcodePopover>
</div>
</RentStoreWrap>
);
};
export default RentStoreView;
// 样式
const RentStoreWrap = styled.div`
position: relative;
width: calc((100% - 0.83rem) / 10 * 2.5);
min-height: 18rem;
//height: 100%;
background: #ffffff;
border: 0.04rem solid #e3e3e3;
box-sizing: border-box;
padding: 1rem;
.store-card {
width: 100%;
min-height: 8em;
background: linear-gradient(270deg, #5f5f5f 0%, #060606 100%);
border-radius: 0.33rem;
box-sizing: border-box;
padding: 0.58rem 1rem;
margin-bottom: 1rem;
align-items: flex-start;
.image {
width: 3.25rem;
height: 3.25rem;
border: 0.02rem solid #e3e3e3;
margin-right: 0.67rem;
}
.card-content {
position: relative;
width: calc(100% - 3.25rem - 0.67rem);
.title {
font-weight: 500;
color: #ffffff;
}
.star {
margin-bottom: 0.5rem;
.tag {
position: relative;
height: 1.2rem;
line-height: 1rem;
background: #fff3ee;
border-radius: 0.13rem;
border: 0.02rem solid #ff552d;
box-sizing: border-box;
padding: 0 0.33rem;
text-align: center;
font-size: 10px;
color: #ff552d;
margin-right: 0.25rem;
transform: scale(0.8);
}
}
.text {
font-size: 12px;
font-weight: 400;
color: rgba(255, 255, 255, 0.8);
}
}
}
.store-item {
align-items: flex-start;
flex-wrap: nowrap;
margin-bottom: 1rem;
.item-label {
width: 3rem;
color: #666666;
}
.item-value {
width: calc(100% - 3rem);
font-size: 12px;
font-weight: 400;
color: #666666;
}
}
.store-action {
position: relative;
width: 100%;
.action-item {
position: relative;
background: #ffffff;
box-sizing: border-box;
padding: 0 1rem;
border: 0.04rem solid #a8a8a8;
cursor: pointer;
margin-right: 0.83rem;
.text {
color: #a8a8a8;
font-weight: 400;
font-size: 12px;
margin-left: 0.33rem;
}
&:not(:last-child) {
margin-right: 0.83rem;
}
&:last-child {
border: 0.04rem solid #ff552d;
.text {
color: #ff552d;
}
}
&:hover {
filter: brightness(0.95);
}
}
}
`;
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论