首页列表 装备详情 订单等页面完善

This commit is contained in:
BianLzhaoMin 2024-12-18 18:05:02 +08:00
parent e783dbbd96
commit 2d2244ab55
19 changed files with 1277 additions and 300 deletions

764
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,8 @@
<script> <script>
export default { export default {
onLaunch: function () { onLaunch: function () {},
console.log('App Launch') onShow: function () {},
}, onHide: function () {},
onShow: function () {
console.log('App Show')
},
onHide: function () {
console.log('App Hide')
},
} }
</script> </script>
@ -20,4 +14,31 @@ page {
font-size: 14px; font-size: 14px;
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
view,
navigator,
input,
scroll-view {
box-sizing: border-box;
}
button::after {
border: none;
}
swiper,
scroll-view {
flex: 1;
height: 100%;
overflow: hidden;
}
.van-nav-bar__content {
background-color: $uni-navbar-bg-color;
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style> </style>

View File

@ -0,0 +1,100 @@
<template>
<!-- 装修卡片 -->
<view class="items-card">
<van-image fit="cover" :src="goodsInfo.picUrl" />
<view class="goods-info">
<view class="device-title">
<text> {{ goodsInfo.deviceName }} </text>
<text> ({{ goodsInfo.typeName }}) </text>
</view>
<view class="address-box">
<text>{{ goodsInfo.companyName }}</text>
</view>
<view> {{ goodsInfo.companyName }}</view>
<view class="flex-row-start phone-price">
<view>
<van-icon name="phone-o" />
{{ goodsInfo.personPhone }}
</view>
<view class="price-box">
<text></text>
<text class="price">{{ goodsInfo.dayLeasePrice }}</text>
<text>/</text>
</view>
</view>
</view>
</view>
</template>
<script setup>
const props = defineProps({
goodsInfo: {
type: Object,
default: () => {},
},
})
</script>
<style lang="scss" scoped>
.items-card {
display: flex;
flex-direction: column;
width: 100%;
font-size: 12px;
background-color: #f9f9f9;
.goods-info {
flex: 1;
}
.van-image {
width: 100%;
height: 120px;
}
view {
padding: 3px 0;
box-sizing: border-box;
letter-spacing: 2px;
color: #636262;
}
.device-title text:first-child {
color: #000;
font-size: 16px;
font-weight: bold;
}
.address-box {
display: flex;
align-items: center;
text {
width: 100%;
display: block;
border: 1px solid $el-color-primary;
box-sizing: border-box;
color: $el-color-primary;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: center;
}
}
.phone-price {
justify-content: space-between;
.price-box {
color: #fe4700;
.price {
margin: 0 1px;
font-size: 14px;
font-weight: bold;
}
}
view {
padding: 0 !important;
}
}
}
</style>

View File

@ -36,41 +36,54 @@
"style": { "style": {
"navigationBarTitleText": "我的" "navigationBarTitleText": "我的"
} }
},
{
"path": "pages/goods-details/index",
"style": {
"navigationBarTitleText": "装备详情"
}
},
{
"path": "pages/order/index",
"style": {
"navigationBarTitleText": "订单结算"
}
} }
], ],
"tabBar": { // "tabBar": {
"color": "#2c2c2c", // "color": "#2c2c2c",
"selectedColor": "#00ad9d", // "selectedColor": "#00ad9d",
"borderStyle": "black", // "borderStyle": "black",
"backgroundColor": "#FFFFFF", // "backgroundColor": "#FFFFFF",
"iconWidth": "24px", // "iconWidth": "24px",
"list": [ // "list": [
{ // {
"pagePath": "pages/index/index", // "pagePath": "pages/index/index",
"text": "首页" // "text": "首页"
}, // },
{ // {
"pagePath": "pages/lease-demand/index", // "pagePath": "pages/lease-demand/index",
"text": "租赁需求" // "text": "租赁需求"
}, // },
{ // {
"pagePath": "pages/cart/index", // "pagePath": "pages/cart/index",
"text": "预约车" // "text": "预约车"
}, // },
{ // {
"pagePath": "pages/message/index", // "pagePath": "pages/message/index",
"text": "消息" // "text": "消息"
}, // },
{ // {
"pagePath": "pages/my/index", // "pagePath": "pages/my/index",
"text": "我的" // "text": "我的"
} // }
] // ]
}, // },
"globalStyle": { "globalStyle": {
"navigationBarTextStyle": "#fff", "navigationBarTextStyle": "#fff",
"navigationBarTitleText": "uni-app", "navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#00a288", "navigationBarBackgroundColor": "#00a288",
"backgroundColor": "#00a288" "backgroundColor": "#00a288",
"navigationStyle": "custom"
} }
} }

View File

@ -0,0 +1,167 @@
<template>
<!-- 装备详情 -->
<view class="swiper-container">
<van-swipe :autoplay="5000" lazy-render :show-indicators="false" @change="onSwiperChange">
<van-swipe-item v-for="image in images" :key="image.id">
<van-image fit="cover" position="center" :src="image.fileUrl" />
</van-swipe-item>
</van-swipe>
<view class="count-tip"> {{ activeIndex }}/{{ goodsPicCount }} </view>
</view>
<view class="goods-name card-style">
<view class="box_1">
<text style="color: #2cb0a0"> {{ deviceInfo.deviceName }} </text>
<view style="color: #fff">
<text class="no-bold"></text>
<text> {{ deviceInfo.dayLeasePrice }}</text>
<text class="no-bold">/ </text>
</view>
</view>
<view class="text-right"> {{ deviceInfo.personPhone }} <van-icon name="phone-o" /></view>
<view class="text-right">
<text> 发布时间{{ deviceInfo.createTime?.slice(0, 10) }} </text>
<text> 更新时间{{ deviceInfo.updateTime?.slice(0, 10) }}</text>
<text> 浏览次数{{ deviceInfo.searchNum }} </text>
</view>
</view>
<view class="card-style goods-company">
<h4>安徽送变电公司</h4>
<view>
<text> 入驻时间{{ deviceInfo.companyCreateTime }} </text>
<text> 上架数量{{ deviceInfo.devUapNum }} </text>
<text> 访问量{{ deviceInfo.companyVisitNum }} </text>
</view>
<view>
<van-icon name="location-o" />
<text> 合肥市 </text>
</view>
</view>
<view class="card-style goods-details">
<h3>装备详情</h3>
<view v-for="item in goodsLabel" :key="item.goods_label">
<text> {{ item.goods_label }}{{ deviceInfo[item.label_content] }}</text>
</view>
</view>
<van-action-bar>
<van-action-bar-icon icon="chat-o" text="在线聊" />
<van-action-bar-icon icon="shop-o" text="预约车" />
<van-action-bar-button color="#ffc758" type="warning" text="加入预约车" />
<van-action-bar-button color="#22ab9b" type="danger" text="立即租用" @click="onRentNow" />
</van-action-bar>
</template>
<script setup>
import { computed, ref } from 'vue'
import { getDeviceDetailsAPI } from '@/services/goods/index.js'
import { onLoad } from '@dcloudio/uni-app'
const images = ref([])
const activeIndex = ref(1)
const deviceInfo = ref({})
const props = defineProps({
maId: {
type: [String, Number],
default: () => '',
},
})
const goodsLabel = ref([
{ goods_label: '装备编号:', label_content: 'code' },
{ goods_label: '装备类目:', label_content: 'groupName' },
{ goods_label: '装备型号:', label_content: 'typeName' },
{ goods_label: '规格:', label_content: '' },
{ goods_label: '品牌:', label_content: 'brand' },
{ goods_label: '出厂日期:', label_content: 'productionDate' },
{ goods_label: '功能特点:', label_content: '' },
])
const goodsPicCount = computed(() => {
return images.value.length
})
const onSwiperChange = (e) => {
activeIndex.value = e + 1
}
const getDeviceDetailsData = async () => {
const { data: res } = await getDeviceDetailsAPI(props.maId)
deviceInfo.value = res
images.value = res.detailsFileList
console.log(res, '装备详情')
}
const onRentNow = () => {
uni.navigateTo({ url: '/pages/order/index' })
}
onLoad(() => {
getDeviceDetailsData()
})
</script>
<style lang="scss" scoped>
.swiper-container {
position: relative !important;
.count-tip {
position: absolute;
top: 10px;
right: 20px;
padding: 2px 8px;
border-radius: 2px;
background-color: #bcbcbc;
color: #fff;
}
}
.van-swipe {
width: 100%;
height: 40vh;
.van-image {
width: 100%;
height: 100%;
}
}
.card-style {
width: 97%;
margin: 5px auto 0;
border-radius: 6px;
padding: 8px 12px;
box-sizing: border-box;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
.goods-name {
color: #fff;
background: linear-gradient(to right, #e8f4f3, #93dad1, #5fb0a5);
.box_1 {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 18px;
font-weight: bold;
letter-spacing: 2px;
.no-bold {
font-size: 13px;
font-weight: normal;
}
}
.text-right {
margin-top: 6px;
font-size: 12px;
text-align: right;
}
}
.goods-company text,
.goods-details text {
margin-right: 16px;
font-size: 13px;
color: #5c5b5b;
}
.goods-company view,
.goods-details view,
.goods-company h4 {
padding: 2px 0;
}
</style>

View File

@ -0,0 +1,51 @@
<template>
<!-- 装备详情页面 -->
<view class="h5-container">
<view class="tabs-container">
<van-icon name="arrow-left" @click="onHandleBack" />
<van-tabs v-model:active="activeTabs" swipeable color="#00a288" background="#c9ead4">
<van-tab v-for="(t, i) in tabList" :title="t.tab_name"> </van-tab>
</van-tabs>
</view>
<scroll-view scroll-y class="tabs-content">
<DetailsModel :maId="maId" />
</scroll-view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import DetailsModel from './components/details-model.vue'
import { onLoad } from '@dcloudio/uni-app'
const activeTabs = ref(0)
const maId = ref('')
const tabList = ref([
{ tab_name: '装备详情' },
{ tab_name: '装备外观' },
{ tab_name: '证书展示' },
{ tab_name: '出租记录' },
])
const onHandleBack = () => {
uni.navigateBack()
}
onLoad((options) => {
maId.value = options.id
})
</script>
<style lang="scss" scoped>
.tabs-container {
display: flex;
align-items: center;
background-color: #c8ead5;
.van-tabs {
flex: 1;
}
}
.tabs-content {
background-color: #fff;
}
</style>

View File

@ -1,18 +1,126 @@
<template> <template>
<!-- 首页 --> <!-- 首页 -->
<view class="content"> <view class="h5-container">
<van-empty description="首页欢迎您" /> <van-nav-bar title="机械化装备平台" />
<view class="search-index flex-row-start">
<van-field placeholder="搜索" />
<van-button square type="primary" icon="search" />
</view>
<view class="goods-items">
<view class="filter-box">
<view class="flex-row-start">
<view>
使用年限
<van-icon name="sort" />
</view>
<view>
租金
<van-icon name="sort" />
</view>
<view>
上架时间
<van-icon name="sort" />
</view>
</view>
</view>
</view>
<scroll-view scroll-y class="scroll-item" @scrolltolower="onScrollTolower">
<van-grid :column-num="2" :border="false">
<van-grid-item
v-for="(item, index) in deviceList"
:key="index"
@click="onViewGoodsDetails(item)"
>
<GoodsItems :goodsInfo="item" />
</van-grid-item>
</van-grid>
</scroll-view>
<!-- <van-empty description="首页欢迎您" /> -->
<van-tabbar v-model="active">
<van-tabbar-item icon="home-o">首页</van-tabbar-item>
<van-tabbar-item icon="search">租赁</van-tabbar-item>
<van-tabbar-item icon="friends-o">消息</van-tabbar-item>
<van-tabbar-item icon="setting-o">我的</van-tabbar-item>
</van-tabbar>
</view> </view>
</template> </template>
<script setup> <script setup>
import GoodsItems from '@/components/GoodsItems'
import { getDeviceListAPI } from '@/services/index/index.js'
import { onLoad } from '@dcloudio/uni-app'
import { ref } from 'vue' import { ref } from 'vue'
const active = ref('')
const deviceList = ref([])
const onScrollTolower = () => {
console.log('滚动触底')
}
const getDeviceListData = async () => {
const { data: result } = await getDeviceListAPI({})
deviceList.value = result.rows
console.log(res, '装备列表')
}
const onViewGoodsDetails = (item) => {
uni.navigateTo({ url: `/pages/goods-details/index?id=${item.maId}` })
}
onLoad(() => {
getDeviceListData()
})
</script> </script>
<style> <style lang="scss" scoped>
.content { .search-index {
width: 100%; height: 80px;
height: 100%; justify-content: center;
text-align: center;
.van-field {
width: 65%;
padding: 0;
height: 36px;
line-height: 36px;
border: 1px solid #22ab9b;
border-top-left-radius: 18px;
border-bottom-left-radius: 18px;
padding-left: 18px;
}
.van-button {
height: 36px;
width: 70px;
line-height: 36px;
background: #22ab9b;
border: none;
border-top-right-radius: 18px;
border-bottom-right-radius: 18px;
font-size: 18px;
}
}
.goods-items {
padding: 10px;
box-sizing: border-box;
border-top-left-radius: 20px;
border-top-right-radius: 20px;
background: $uni-bg-color;
}
.flex-row-start view {
margin-right: 6px;
}
.van-tabbar {
height: 70px;
}
.scroll-item {
background-color: $uni-bg-color;
padding-bottom: 70px;
.van-grid-item {
border: none;
}
} }
</style> </style>

View File

@ -5,13 +5,13 @@
<view class="login-title"> 欢迎登录 </view> <view class="login-title"> 欢迎登录 </view>
<van-cell-group> <van-cell-group>
<van-field <van-field
v-model="username" v-model="loginForm.username"
name="用户名" name="用户名"
placeholder="用户名" placeholder="用户名"
:rules="[{ required: true, message: '请填写用户名' }]" :rules="[{ required: true, message: '请填写用户名' }]"
/> />
<van-field <van-field
v-model="password" v-model="loginForm.password"
type="password" type="password"
name="密码" name="密码"
placeholder="密码" placeholder="密码"
@ -34,15 +34,31 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted, reactive } from 'vue'
const memberStore = useMemberStore()
import { useMemberStore } from '@/stores/index.js' import { useMemberStore } from '@/stores/index.js'
import { appLoginAPI, getUserInfoAPI } from '@/services/login/index.js'
const memberStore = useMemberStore()
const loginForm = reactive({
username: '',
password: '',
code: '',
phoneUuid: '',
uuid: '',
verificationCode: '',
loginType: 'USERNAME_PASSWORD',
})
const username = ref('') const onSubmitLogin = async () => {
const password = ref('') const { data: result } = await appLoginAPI(loginForm)
const onSubmitLogin = () => { memberStore.setToken(result.access_token)
uni.switchTab({ url: '/pages/index/index' }) const userResult = await getUserInfoAPI()
memberStore.setUserInfo({ token: '996', userName: username.value }) memberStore.setUserInfo(userResult.user)
if (userResult.code === 200) {
showToast('登录成功')
setTimeout(() => {
uni.navigateTo({ url: '/pages/index/index' })
}, 500)
}
} }
const navBarHeight = ref(0) const navBarHeight = ref(0)
@ -50,11 +66,10 @@ const navBarHeight = ref(0)
onMounted(() => { onMounted(() => {
uni.getSystemInfo({ uni.getSystemInfo({
success: (res) => { success: (res) => {
console.log(res, '当前设备--')
// //
const statusBarHeight = res.statusBarHeight // const statusBarHeight = res.statusBarHeight
// // 44px // // // 44px
navBarHeight.value = statusBarHeight // navBarHeight.value = statusBarHeight
}, },
}) })
}) })

175
src/pages/order/index.vue Normal file
View File

@ -0,0 +1,175 @@
<template>
<!-- 订单结算 -->
<view class="h5-container">
<view class="nav-header">
<van-icon name="arrow-left" />
<text> 订单确认 </text>
<text> (1) </text>
</view>
<view class="order-set">
<van-row>
<van-col span="13">
<view class="company-box">
<van-image fit="cover" width="1.5rem" height="1.2rem" :src="companyImg" />
<view class="company-name">
<view> 安徽省合肥市 </view>
<van-image fit="cover" height="0.5rem" :src="companyBg" />
</view>
</view>
</van-col>
<van-col span="11" class="contacts"> 联系人李世民 13656235623 </van-col>
</van-row>
<van-row>
<van-col span="18">
<view class="items-info">
<van-image fit="cover" height="4rem" width="4rem" :src="companyBg" />
<view class="info">
<view>牵张机</view>
<view>装备编号</view>
<view>装备型号</view>
<view>
租赁金额
<text> 2000/ </text>
</view>
<view class="items-info">
开始日期
<van-image fit="cover" width="1rem" height="1rem" :src="dateIcon" />
结束日期
<van-image fit="cover" width="1rem" height="1rem" :src="dateIcon" />
</view>
</view>
</view>
</van-col>
<van-col span="6">
<van-stepper button-size="16" />
</van-col>
</van-row>
<van-row style="margin-top: 14px">
总金额
<text> 30000 </text>
</van-row>
<van-row style="padding: 10px 0; margin-top: 10px; border-top: 1px solid #ccc">
<van-checkbox-group v-model="checked" shape="square" icon-size="16px">
<van-checkbox name="1">
我已阅读并同意
<text class="protocol" @click.stop="onViewProtocol"> xxx公司协议 </text>
</van-checkbox>
</van-checkbox-group>
</van-row>
</view>
<!-- <van-date-picker title="选择日期" /> -->
<van-submit-bar
button-color="#579d92"
:price="3050"
button-text="提交"
@submit="onSubmitOrder"
>
<template #default>
<view class="amount"> 共计一件装备 </view>
</template>
</van-submit-bar>
</view>
</template>
<script setup>
import companyImg from '@/static/goods/company-img.png'
import companyBg from '@/static/goods/company-bg.png'
import dateIcon from '@/static/goods/date-icon.png'
import { ref } from 'vue'
const checked = ref(['1'])
const onSubmitOrder = () => {}
const onViewProtocol = () => {}
</script>
<style lang="scss" scoped>
.order-set {
padding: 10px;
box-sizing: border-box;
.van-row {
padding: 2px 0;
display: flex;
align-items: center;
}
}
.nav-header {
height: 40px;
padding: 0 10px;
display: flex;
align-items: center;
background-color: $uni-navbar-bg-color;
text:nth-child(2) {
margin-left: 8px;
color: #0292f9;
font-size: 16px;
font-weight: bold;
font-style: italic;
}
}
.amount {
margin-left: 50px;
font-size: 13px;
color: #ccc;
}
.company-box {
display: flex;
align-items: center;
width: 100%;
.company-name {
width: 100%;
display: flex;
flex-direction: column;
view {
padding-left: 6px;
font-size: 13px;
font-weight: bold;
}
.van-image {
width: 100%;
}
}
}
.contacts {
font-size: 12px;
}
.items-info {
display: flex;
align-items: center;
.info {
font-size: 12px;
view {
padding: 1px 0 1px 10px;
font-size: 12px;
color: #6f6f6f;
.van-image {
margin: 0 4px;
}
}
& view:first-child {
font-size: 13px;
font-weight: bold;
}
}
}
.protocol {
font-size: 13px;
color: #1989fa;
}
</style>

View File

@ -0,0 +1,11 @@
import { http } from '@/utils/http'
/**
* 装备 获取装备详情
*/
export const getDeviceDetailsAPI = (id) => {
return http({
method: 'GET',
url: `/material-mall/dev/getInfo/${id}?isHome=true`,
})
}

View File

@ -0,0 +1,12 @@
import { http } from '@/utils/http'
/**
* 首页 获取装备列表
*/
export const getDeviceListAPI = (data) => {
return http({
method: 'POST',
url: '/material-mall/dev/list',
data,
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

View File

@ -5,7 +5,7 @@ export const useMemberStore = defineStore(
'member', 'member',
() => { () => {
// 定义用户信息 // 定义用户信息
const userInfo = ref({ token: '', userName: '' }) const userInfo = ref({})
const token = ref('') const token = ref('')
// 存储用户信息 // 存储用户信息
const setUserInfo = (val) => { const setUserInfo = (val) => {

View File

@ -7,6 +7,13 @@
} }
.h5-container {
height: 100%;
display: flex;
flex-direction: column;
background-color: $uni-bg-color-grey;
}
.flex-row-start { .flex-row-start {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -29,7 +29,8 @@ $uni-text-color-placeholder: #808080;
$uni-text-color-disable: #c0c0c0; $uni-text-color-disable: #c0c0c0;
/* 背景颜色 */ /* 背景颜色 */
$uni-bg-color: #eeeff6; $uni-bg-color: #fff;
$uni-navbar-bg-color: #bde1d4;
$uni-bg-color-grey: #f8f8f8; $uni-bg-color-grey: #f8f8f8;
$uni-bg-color-hover: #f1f1f1; // 点击状态颜色 $uni-bg-color-hover: #f1f1f1; // 点击状态颜色
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色 $uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色

View File

@ -6,8 +6,7 @@ import { useMemberStore } from '@/stores'
* baseURL 设置请求ip地址和端口 * baseURL 设置请求ip地址和端口
*/ */
const ENV = process.env.NODE_ENV const ENV = process.env.NODE_ENV
export const baseURL = ENV === 'development' ? 'http://192.168.2.246:18080' : '***' export const baseURL = ENV === 'development' ? '/api' : '***'
// export const baseURL = ENV === 'development' ? '/api' : '***'
/** /**
* httpInterceptor 分别拦截 request uploadFile 请求 * httpInterceptor 分别拦截 request uploadFile 请求
*/ */
@ -32,8 +31,6 @@ const httpInterceptor = {
// 4. 增加 token 请求头标识 // 4. 增加 token 请求头标识
const memberStore = useMemberStore() const memberStore = useMemberStore()
const token = memberStore.token const token = memberStore.token
// const token = "eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX2tleSI6IjQ2NDdmYjlkLWI5OTItNDRiNy05MTdkLTMwZjg0ZjUxYzM5MCIsInVzZXJuYW1lIjoiYWRtaW4ifQ.9xM5bFhrmHK09-4ZgL5SS8WraNIJjIijuB-1P0lJF-n0KlVM5Bglvyjltk1NQbdqgi1hwRocZS1OU41cLiwuig"
if (token) { if (token) {
options.header.Authorization = token options.header.Authorization = token
} }

View File

@ -1,6 +1,5 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni' import uni from '@dcloudio/vite-plugin-uni'
// import styleImport, { VantResolve } from 'vite-plugin-style-import'
import AutoImport from 'unplugin-auto-import/vite' import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite' import Components from 'unplugin-vue-components/vite'
import { VantResolver } from '@vant/auto-import-resolver' import { VantResolver } from '@vant/auto-import-resolver'
@ -32,9 +31,7 @@ export default defineConfig({
proxy: { proxy: {
// 在此处编写代理规则 // 在此处编写代理规则
'/api': { '/api': {
// target: 'http://192.168.2.76:18080', target: 'ttp://192.168.0.244:28580',
// target: 'http://192.168.2.246:18080',
target: 'http://localhost:18080',
changeOrigin: true, changeOrigin: true,
rewrite: (path) => { rewrite: (path) => {
return path.replace(/\/api/, '') return path.replace(/\/api/, '')