配置更新

This commit is contained in:
minimaxagent1 2025-08-13 11:10:19 +08:00
parent 1e2f8984e2
commit b07c3b769c
53 changed files with 5926 additions and 689 deletions

16
.eslintrc.js Normal file
View File

@ -0,0 +1,16 @@
module.exports = {
root: true,
env: {
node: true,
'vue/setup-compiler-macros': true,
},
extends: ['plugin:vue/vue3-essential', '@vue/eslint-config-prettier'],
parserOptions: {
ecmaVersion: 2020,
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'vue/multi-word-component-names': 'off',
},
}

4
.idea/.gitignore vendored
View File

@ -6,6 +6,6 @@
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
unpackage/
node_modules/
/unpackage/
/node_modules/

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EslintConfiguration">
<option name="fix-on-save" value="true" />
</component>
</project>

7
.idea/prettier.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PrettierConfiguration">
<option name="myConfigurationMode" value="AUTOMATIC" />
<option name="myRunOnSave" value="true" />
</component>
</project>

9
.prettierrc Normal file
View File

@ -0,0 +1,9 @@
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"bracketSpacing": true,
"arrowParens": "avoid"
}

24
App.vue
View File

@ -1,17 +1,17 @@
<script>
export default {
onLaunch: function () {
console.log('App Launch')
},
onShow: function () {
console.log('App Show')
},
onHide: function () {
console.log('App Hide')
},
}
export default {
onLaunch: function () {
console.log('App Launch')
},
onShow: function () {
console.log('App Show')
},
onHide: function () {
console.log('App Hide')
},
}
</script>
<style>
/*每个页面公共css */
/*每个页面公共css */
</style>

View File

@ -18,10 +18,45 @@
## 技术栈
- **框架**uni-app
- **框架**uni-app Vue3
- **状态管理**Vuex 4
- **样式**SCSS + CSS3
- **图标**SVG 矢量图标
- **动画**CSS3 动画效果
- **代码规范**ESLint + Prettier
## 依赖说明
### 核心依赖
- `@dcloudio/uni-app`: uni-app 框架核心包
- `vue`: Vue 3 框架
- `vuex`: 状态管理库
### 开发依赖
- `eslint`: 代码检查工具
- `eslint-plugin-vue`: Vue 代码检查插件
- `@vue/eslint-config-prettier`: ESLint 与 Prettier 集成
- `prettier`: 代码格式化工具
### 安装依赖
```bash
npm install
```
### 开发命令
```bash
# 格式化代码
npm run format
# 代码检查
npm run lint
# 开发模式
npm run dev
# 构建项目
npm run build
```
## 项目结构

View File

@ -0,0 +1,75 @@
<template>
<view class="announcement-bar" @click="onAnnouncementClick">
<image class="announcementIcon" :src="announcementIcon"></image>
<view class="announcement-box">
<text class="announcement-text">{{ announcementText }}</text>
</view>
</view>
</template>
<script>
export default {
name: 'AnnouncementBar',
props: {
announcementText: {
type: String,
default: '暂无更多公告! 暂无更多公告! 暂无更多公告!',
},
announcementIcon: {
type: String,
required: true,
},
},
methods: {
onAnnouncementClick() {
this.$emit('announcement-click')
},
},
}
</script>
<style lang="scss" scoped>
.announcement-bar {
background: white;
opacity: 0.5;
margin: 34rpx 19rpx 0 19rpx;
padding: 15rpx 30rpx;
display: flex;
align-items: center;
gap: 15rpx;
overflow: hidden;
height: 34rpx;
border-radius: 100rpx;
.announcementIcon {
height: 32rpx;
width: 32rpx;
flex-shrink: 0;
}
.announcement-box {
flex: 1;
overflow: hidden;
position: relative;
.announcement-text {
font-size: 13px;
opacity: 1;
color: black;
white-space: nowrap;
animation: scroll-text 10s linear infinite;
display: inline-block;
padding-left: 100%;
}
@keyframes scroll-text {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-100%);
}
}
}
}
</style>

View File

@ -0,0 +1,93 @@
<template>
<view class="banner-section">
<swiper
:autoplay="autoplay"
:duration="duration"
:indicator-dots="indicatorDots"
:interval="interval"
circular
class="swiper"
indicator-active-color="#FFFFFF"
indicator-color="rgba(255, 255, 255, 0.5)"
>
<swiper-item
v-for="(item, index) in bannerList"
:key="index"
@click="onBannerClick(item, index)"
>
<image :src="item.image" mode="aspectFill"></image>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
name: 'BannerSwiper',
props: {
bannerList: {
type: Array,
default: () => [],
},
indicatorDots: {
type: Boolean,
default: true,
},
autoplay: {
type: Boolean,
default: true,
},
interval: {
type: Number,
default: 2000,
},
duration: {
type: Number,
default: 500,
},
},
methods: {
onSwiperChange(e) {
this.$emit('change', e.detail.current)
},
onBannerClick(item, index) {
this.$emit('banner-click', { item, index })
},
},
}
</script>
<style lang="scss" scoped>
.banner-section {
padding: 30rpx;
}
.swiper {
height: 300rpx;
/* 通用指示器样式 - 覆盖所有可能的类名 */
:deep([class*='swiper-dot']) {
border-radius: 50% !important;
transition: all 0.3s ease !important;
}
:deep([class*='swiper-dot-active']) {
width: 82rpx !important;
height: 14rpx;
/* 选中时稍大 */
}
.swiper-item {
display: block;
height: 300rpx;
line-height: 300rpx;
text-align: center;
image {
width: 100%;
height: 100%;
border-radius: 20rpx;
}
}
}
</style>

View File

@ -0,0 +1,98 @@
<template>
<view class="bottom-nav">
<view
v-for="(nav, index) in navItems"
:key="index"
class="nav-item"
:class="{ active: index === activeIndex }"
@click="onNavClick(index)"
>
<image class="nav-icon" :src="getNavIcon(index)" mode="aspectFit"></image>
<text class="nav-text">{{ nav }}</text>
</view>
</view>
</template>
<script>
export default {
name: 'BottomNav',
props: {
navItems: {
type: Array,
default: () => ['首页', '申请租赁', '个人中心'],
},
activeIndex: {
type: Number,
default: 0,
},
iconConfig: {
type: Object,
required: true,
},
},
methods: {
onNavClick(index) {
this.$emit('nav-click', index)
},
getNavIcon(index) {
const isActive = index === this.activeIndex
const icons = this.iconConfig
switch (index) {
case 0: //
return isActive ? icons.HOME_ACTIVE : icons.HOME
case 1: //
return isActive ? icons.RENT_ACTIVE : icons.RENT
case 2: //
return isActive ? icons.PERSONAL_CENTER_ACTIVE : icons.PERSONAL_CENTER
default:
return icons.HOME
}
},
},
}
</script>
<style lang="scss" scoped>
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #fff;
display: flex;
justify-content: space-around;
align-items: center;
padding: 20rpx 0;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
padding: 10rpx;
transition: all 0.3s ease;
}
.nav-item:active {
transform: scale(0.95);
}
.nav-icon {
width: 48rpx;
height: 48rpx;
}
.nav-text {
font-size: 20rpx;
color: #999;
}
.nav-item.active .nav-text {
color: #ff9a9e;
}
</style>

View File

@ -16,19 +16,28 @@
<view
class="navbar-left"
@click="handleBack"
:style="{ height: capsuleHeight + 'px', lineHeight: capsuleHeight + 'px' }"
:style="{
height: capsuleHeight + 'px',
lineHeight: capsuleHeight + 'px',
}"
>
<image :src="backIcon" mode="aspectFit" class="back-icon"></image>
</view>
<view
class="navbar-title"
:style="{ height: capsuleHeight + 'px', lineHeight: capsuleHeight + 'px' }"
:style="{
height: capsuleHeight + 'px',
lineHeight: capsuleHeight + 'px',
}"
>
{{ title }}
</view>
<view
class="navbar-right"
:style="{ height: capsuleHeight + 'px', lineHeight: capsuleHeight + 'px' }"
:style="{
height: capsuleHeight + 'px',
lineHeight: capsuleHeight + 'px',
}"
>
<slot name="right"></slot>
</view>
@ -37,173 +46,179 @@
</template>
<script>
import CommonEnum from '../../enum/common'
import CommonEnum from '../../enum/common'
export default {
name: 'CustomNavbar',
props: {
title: {
type: String,
default: '',
},
backIcon: {
type: String,
default: CommonEnum.BACK_BUTTON,
},
showBack: {
type: Boolean,
default: true,
},
//
backgroundColor: {
type: String,
default: CommonEnum.BASE_COLOR, // 使
},
scrollThreshold: {
type: Number,
default: 20, //
},
enableScrollEffect: {
type: Boolean,
default: true, //
},
export default {
name: 'CustomNavbar',
props: {
title: {
type: String,
default: '',
},
data() {
return {
statusBarHeight: 0,
navBarHeight: 0,
menuButtonInfo: null,
capsuleHeight: 0,
//
isScrolled: false,
scrollTop: 0,
lastScrollTop: 0,
backIcon: {
type: String,
default: CommonEnum.BACK_BUTTON,
},
showBack: {
type: Boolean,
default: true,
},
//
backgroundColor: {
type: String,
default: CommonEnum.BASE_COLOR, // 使
},
scrollThreshold: {
type: Number,
default: 20, //
},
enableScrollEffect: {
type: Boolean,
default: true, //
},
},
data() {
return {
statusBarHeight: 0,
navBarHeight: 0,
menuButtonInfo: null,
capsuleHeight: 0,
//
isScrolled: false,
scrollTop: 0,
lastScrollTop: 0,
}
},
mounted() {
this.getSystemInfo()
},
methods: {
getSystemInfo() {
//
const systemInfo = uni.getSystemInfoSync()
//
this.statusBarHeight = systemInfo.statusBarHeight
//
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
//
this.capsuleHeight = this.menuButtonInfo.height
//
this.navBarHeight = this.menuButtonInfo.bottom + 8
},
handleBack() {
if (this.showBack) {
//
this.$emit('back')
//
uni.navigateBack({
delta: 1,
})
}
},
mounted() {
this.getSystemInfo()
},
methods: {
getSystemInfo() {
//
const systemInfo = uni.getSystemInfoSync()
//
this.statusBarHeight = systemInfo.statusBarHeight
//
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
//
handlePageScroll(e) {
if (!this.enableScrollEffect) return
//
this.capsuleHeight = this.menuButtonInfo.height
this.scrollTop = e.scrollTop
//
this.navBarHeight = this.menuButtonInfo.bottom + 8
},
handleBack() {
if (this.showBack) {
//
this.$emit('back')
//
uni.navigateBack({
delta: 1,
//
if (this.scrollTop > this.scrollThreshold) {
if (!this.isScrolled) {
this.isScrolled = true
this.$emit('scroll-change', {
isScrolled: true,
scrollTop: this.scrollTop,
})
}
},
//
handlePageScroll(e) {
if (!this.enableScrollEffect) return
this.scrollTop = e.scrollTop
//
if (this.scrollTop > this.scrollThreshold) {
if (!this.isScrolled) {
this.isScrolled = true
this.$emit('scroll-change', { isScrolled: true, scrollTop: this.scrollTop })
}
} else {
if (this.isScrolled) {
this.isScrolled = false
this.$emit('scroll-change', { isScrolled: false, scrollTop: this.scrollTop })
}
} else {
if (this.isScrolled) {
this.isScrolled = false
this.$emit('scroll-change', {
isScrolled: false,
scrollTop: this.scrollTop,
})
}
}
//
this.$emit('scroll', {
scrollTop: this.scrollTop,
isScrolled: this.isScrolled,
})
},
//
setScrollState(scrollTop) {
if (!this.enableScrollEffect) return
this.scrollTop = scrollTop
this.isScrolled = scrollTop > this.scrollThreshold
},
//
this.$emit('scroll', {
scrollTop: this.scrollTop,
isScrolled: this.isScrolled,
})
},
}
//
setScrollState(scrollTop) {
if (!this.enableScrollEffect) return
this.scrollTop = scrollTop
this.isScrolled = scrollTop > this.scrollThreshold
},
},
}
</script>
<style lang="scss" scoped>
/* 填充区样式 */
.navbar-placeholder {
width: 100%;
background-color: transparent;
}
/* 填充区样式 */
.navbar-placeholder {
width: 100%;
background-color: transparent;
}
/* 自定义导航栏样式 */
.custom-navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
padding-top: 0;
background-color: transparent;
display: flex;
align-items: center;
justify-content: space-between;
padding-left: 30rpx;
padding-right: 30rpx;
box-sizing: border-box;
transition: background-color 0.3s ease; /* 添加过渡动画 */
}
/* 自定义导航栏样式 */
.custom-navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
padding-top: 0;
background-color: transparent;
display: flex;
align-items: center;
justify-content: space-between;
padding-left: 30rpx;
padding-right: 30rpx;
box-sizing: border-box;
transition: background-color 0.3s ease; /* 添加过渡动画 */
}
/* 滚动状态样式 */
.navbar-scrolled {
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1); /* 滚动时添加阴影 */
}
/* 滚动状态样式 */
.navbar-scrolled {
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1); /* 滚动时添加阴影 */
}
.navbar-left {
display: flex;
align-items: center;
justify-content: center;
width: 60rpx;
.navbar-left {
display: flex;
align-items: center;
justify-content: center;
width: 60rpx;
.back-icon {
width: 56rpx;
height: 56rpx;
}
.back-icon {
width: 56rpx;
height: 56rpx;
}
}
.navbar-title {
font-size: 36rpx;
font-weight: bold;
color: #695347;
flex: 1;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.navbar-title {
font-size: 36rpx;
font-weight: bold;
color: #695347;
flex: 1;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.navbar-right {
width: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
.navbar-right {
width: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
</style>

View File

@ -0,0 +1,189 @@
<template>
<view class="equipment-section">
<view class="section-title">{{ title }}</view>
<view class="equipment-list">
<view
v-for="equipment in equipmentList"
:key="equipment.id"
class="equipment-item"
@click="onEquipmentClick(equipment)"
>
<image class="equipment-image" :src="equipment.image" mode="aspectFit"></image>
<view class="equipment-info">
<view class="equipment-header">
<text class="equipment-name">{{ equipment.name }}</text>
<text class="status-badge" :class="equipment.status">
{{ getStatusText(equipment.status) }}
</text>
</view>
<view class="equipment-details">
<view class="detail-item-row">
<text class="detail-item-time">租赁时间:</text>
<text class="detail-item">{{ equipment.startTime }}</text>
</view>
<view class="detail-item-row">
<text class="detail-item-time">到期时间:</text>
<text class="detail-item">{{ equipment.endTime }}</text>
</view>
</view>
<button class="renew-btn" @click.stop="onRenew(equipment)">去续费</button>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'EquipmentList',
props: {
title: {
type: String,
default: '我的租赁设备',
},
equipmentList: {
type: Array,
default: () => [],
},
},
methods: {
getStatusText(status) {
const statusMap = {
normal: '正常',
warning: '警告',
error: '异常',
}
return statusMap[status] || '未知'
},
onEquipmentClick(equipment) {
this.$emit('equipment-click', equipment)
},
onRenew(equipment) {
this.$emit('renew', equipment)
},
},
}
</script>
<style lang="scss" scoped>
.equipment-section {
padding: 0 30rpx;
}
.section-title {
width: 180rpx;
height: 33rpx;
background: #ffffff;
font-size: 14px;
font-weight: 400;
color: #3d3d3d;
margin-bottom: 20rpx;
padding: 14rpx 20rpx;
border-radius: 4px;
}
.equipment-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.equipment-item {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
display: flex;
gap: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
justify-content: center;
align-items: center;
.equipment-image {
width: 160rpx;
height: 106rpx;
border-radius: 10rpx;
background-color: #f8f9fa;
flex-shrink: 0;
}
}
.equipment-item:active {
transform: scale(0.98);
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.15);
}
.equipment-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.equipment-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15rpx;
}
.equipment-name {
font-size: 16px;
font-weight: 500;
color: #3d3d3d;
}
.status-badge {
padding: 4rpx 26rpx;
border-radius: 5rpx;
font-size: 24rpx;
color: #40c186;
&.normal {
background-color: #ebfff6;
}
&.warning {
background-color: #faad14;
}
&.error {
background-color: #ff4d4f;
}
}
.equipment-details {
display: flex;
flex-direction: column;
gap: 8rpx;
margin-bottom: 15rpx;
}
.detail-item-row {
display: flex;
justify-content: space-between;
.detail-item-time {
color: #817f7f;
font-size: 26rpx;
}
.detail-item {
font-size: 24rpx;
color: #666;
}
}
.renew-btn {
margin-right: 0;
background: #f15a04;
color: #fff;
border-radius: 5px;
padding: 0 57rpx;
font-size: 32rpx;
font-weight: 500;
margin-top: 10rpx;
}
</style>

View File

@ -0,0 +1,64 @@
<template>
<view class="header">
<view class="location-info" @click="onLocationClick">
<image class="location" :src="locationIcon"></image>
<text class="company-name">{{ companyName }}</text>
<text class="arrow">></text>
</view>
</view>
</template>
<script>
export default {
name: 'HomeHeader',
props: {
companyName: {
type: String,
default: '福鼎创特物联科技有限公司',
},
locationIcon: {
type: String,
required: true,
},
},
methods: {
onLocationClick() {
this.$emit('location-click')
},
},
}
</script>
<style lang="scss" scoped>
.header {
padding: 106rpx 30rpx 20rpx 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
background: #ffddca;
z-index: 999;
.location-info {
display: flex;
align-items: center;
gap: 10rpx;
flex: 1;
.location {
width: 27rpx;
height: 31rpx;
}
.company-name {
color: #3d3d3d;
font-size: 16px;
font-weight: 500;
}
.arrow {
font-size: 24rpx;
color: #666;
}
}
}
</style>

3995
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

35
package.json Normal file
View File

@ -0,0 +1,35 @@
{
"name": "homelease",
"version": "1.0.0",
"description": "HomeLease - 房屋租赁应用",
"main": "main.js",
"scripts": {
"dev": "uni",
"build": "uni build",
"format": "prettier --write \"**/*.{js,vue,json,scss,css}\"",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
},
"keywords": [
"uni-app",
"vue3",
"房屋租赁",
"小程序"
],
"author": "",
"license": "MIT",
"devDependencies": {
"@vue/eslint-config-prettier": "^8.0.0",
"eslint": "^8.45.0",
"eslint-plugin-vue": "^9.15.1",
"prettier": "^3.0.0"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-4070520250711001",
"vue": "^3.3.0",
"vuex": "^4.0.0"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
}
}

View File

@ -44,148 +44,142 @@
</template>
<script>
import commonEnum from '../../enum/commonEnum'
import HomeHeader from '../../components/home-header/home-header.vue'
import AnnouncementBar from '../../components/announcement-bar/announcement-bar.vue'
import BannerSwiper from '../../components/banner-swiper/banner-swiper.vue'
import EquipmentList from '../../components/equipment-list/equipment-list.vue'
import BottomNav from '../../components/bottom-nav/bottom-nav.vue'
import commonEnum from '../../enum/commonEnum'
import HomeHeader from '../../components/home-header/home-header.vue'
import AnnouncementBar from '../../components/announcement-bar/announcement-bar.vue'
import BannerSwiper from '../../components/banner-swiper/banner-swiper.vue'
import EquipmentList from '../../components/equipment-list/equipment-list.vue'
import BottomNav from '../../components/bottom-nav/bottom-nav.vue'
export default {
components: {
HomeHeader,
AnnouncementBar,
BannerSwiper,
EquipmentList,
BottomNav,
},
data() {
return {
//
indicatorDots: true,
autoplay: true,
interval: 2000,
duration: 500,
commonEnum: commonEnum,
export default {
components: {
HomeHeader,
AnnouncementBar,
BannerSwiper,
EquipmentList,
BottomNav,
},
data() {
return {
//
indicatorDots: true,
autoplay: true,
interval: 2000,
duration: 500,
commonEnum: commonEnum,
//
companyName: '福鼎创特物联科技有限公司',
announcementText: '暂无更多公告! 暂无更多公告! 暂无更多公告!',
equipmentTitle: '我的租赁设备',
navItems: ['首页', '申请租赁', '个人中心'],
activeNavIndex: 0,
//
companyName: '福鼎创特物联科技有限公司',
announcementText: '暂无更多公告! 暂无更多公告! 暂无更多公告!',
equipmentTitle: '我的租赁设备',
navItems: ['首页', '申请租赁', '个人中心'],
activeNavIndex: 0,
//
currentBannerIndex: 0,
bannerList: [
{
image: commonEnum.TEMP1,
},
{
image: commonEnum.TEMP2,
},
{
image: commonEnum.TEMP3,
},
{
image: commonEnum.TEMP2,
},
],
//
currentBannerIndex: 0,
bannerList: [
{
image: commonEnum.TEMP1,
},
{
image: commonEnum.TEMP2,
},
{
image: commonEnum.TEMP3,
},
{
image: commonEnum.TEMP2,
},
],
//
equipmentList: [
{
id: 1,
name: '商用节能灶',
status: 'normal',
startTime: '2025-07-25 13:23:59',
endTime: '2026-07-25 13:23:59',
image: commonEnum.TEMP2,
},
{
id: 2,
name: '节能燃烧器',
status: 'normal',
startTime: '2025-07-25 13:23:59',
endTime: '2026-07-25 13:23:59',
image: commonEnum.TEMP3,
},
],
}
//
equipmentList: [
{
id: 1,
name: '商用节能灶',
status: 'normal',
startTime: '2025-07-25 13:23:59',
endTime: '2026-07-25 13:23:59',
image: commonEnum.TEMP2,
},
{
id: 2,
name: '节能燃烧器',
status: 'normal',
startTime: '2025-07-25 13:23:59',
endTime: '2026-07-25 13:23:59',
image: commonEnum.TEMP3,
},
],
}
},
methods: {
//
onLocationClick() {
uni.showToast({
title: '选择位置',
icon: 'none',
})
},
methods: {
//
onLocationClick() {
uni.showToast({
title: '选择位置',
icon: 'none',
})
},
//
onAnnouncementClick() {
uni.showToast({
title: '查看公告详情',
icon: 'none',
})
},
//
onBannerChange(index) {
this.currentBannerIndex = index
},
//
onBannerClick({ item, index }) {
uni.showToast({
title: `查看${item.name}详情`,
icon: 'none',
})
},
//
onEquipmentClick(equipment) {
uni.showToast({
title: `查看${equipment.name}详情`,
icon: 'none',
})
},
//
onRenew(equipment) {
uni.showToast({
title: `正在处理${equipment.name}的续费`,
icon: 'none',
})
},
//
onNavClick(index) {
this.activeNavIndex = index
const navItems = ['首页', '申请租赁', '个人中心']
uni.showToast({
title: `切换到${navItems[index]}`,
icon: 'none',
})
},
//
onAnnouncementClick() {
uni.showToast({
title: '查看公告详情',
icon: 'none',
})
},
}
//
onBannerChange(index) {
this.currentBannerIndex = index
},
//
onBannerClick({ item, index }) {
uni.showToast({
title: `查看${item.name}详情`,
icon: 'none',
})
},
//
onEquipmentClick(equipment) {
uni.showToast({
title: `查看${equipment.name}详情`,
icon: 'none',
})
},
//
onRenew(equipment) {
uni.showToast({
title: `正在处理${equipment.name}的续费`,
icon: 'none',
})
},
//
onNavClick(index) {
this.activeNavIndex = index
const navItems = ['首页', '申请租赁', '个人中心']
uni.showToast({
title: `切换到${navItems[index]}`,
icon: 'none',
})
},
},
}
</script>
<style lang="scss" scoped>
.home-container {
background: linear-gradient(
to bottom,
#ffddca 0px,
#ffddca 450rpx,
#f5f5f5 450rpx,
#f5f5f5 100%
);
.home-container {
background: linear-gradient(to bottom, #ffddca 0px, #ffddca 450rpx, #f5f5f5 450rpx, #f5f5f5 100%);
padding-bottom: 120rpx; /* 为底部导航留出空间 */
max-width: 750rpx;
margin: 0 auto;
z-index: -2;
}
padding-bottom: 120rpx; /* 为底部导航留出空间 */
max-width: 750rpx;
margin: 0 auto;
z-index: -2;
}
</style>

View File

@ -74,444 +74,444 @@
</template>
<script>
import { navigateToPage } from '@/utils/router.js'
import { wxLogin } from '@/api/auth/auth.js'
import { forceHideLoading, AutoLoadingManager } from '@/utils/request.js'
import { getServiceTerms, getPrivacyPolicy } from '@/api/article/article.js'
import { commonEnum } from '../../enum/commonEnum'
import { navigateToPage } from '@/utils/router.js'
import { wxLogin } from '@/api/auth/auth.js'
import { forceHideLoading, AutoLoadingManager } from '@/utils/request.js'
import { getServiceTerms, getPrivacyPolicy } from '@/api/article/article.js'
import { commonEnum } from '../../enum/commonEnum'
export default {
data() {
return {
loginLoading: false,
hasAgreed: false,
hasReadServiceTerms: false,
hasReadPrivacyPolicy: false,
showServiceTermsPopup: false,
showPrivacyPolicyPopup: false,
serviceTermsContent: '',
privacyPolicyContent: '',
scrollTop: 0,
export default {
data() {
return {
loginLoading: false,
hasAgreed: false,
hasReadServiceTerms: false,
hasReadPrivacyPolicy: false,
showServiceTermsPopup: false,
showPrivacyPolicyPopup: false,
serviceTermsContent: '',
privacyPolicyContent: '',
scrollTop: 0,
}
},
computed: {
CommonEnum() {
return commonEnum
},
},
onLoad() {
this.pageLoading = new AutoLoadingManager()
},
onUnload() {
forceHideLoading()
if (this.pageLoading) {
this.pageLoading.destroy()
}
},
methods: {
toggleAgreement() {
if (this.hasReadServiceTerms && this.hasReadPrivacyPolicy) {
this.hasAgreed = !this.hasAgreed
} else {
uni.showToast({
title: '请先阅读服务条款和隐私政策',
icon: 'none',
})
}
},
computed: {
CommonEnum() {
return commonEnum
},
},
onLoad() {
this.pageLoading = new AutoLoadingManager()
},
onUnload() {
forceHideLoading()
if (this.pageLoading) {
this.pageLoading.destroy()
}
},
methods: {
toggleAgreement() {
if (this.hasReadServiceTerms && this.hasReadPrivacyPolicy) {
this.hasAgreed = !this.hasAgreed
async showServiceTerms() {
try {
const res = await getServiceTerms()
if (res.code === 200 && res.data) {
let content = res.data.content || '暂无服务条款内容'
content = content.replace(/\n/g, '<br/>')
content = `<div style="word-wrap: break-word; word-break: break-all; line-height: 1.8; font-size: 28rpx; color: #333; padding: 0; margin: 0;">${content}</div>`
this.serviceTermsContent = content
this.showServiceTermsPopup = true
this.scrollTop = 0
} else {
uni.showToast({
title: '请先阅读服务条款和隐私政策',
icon: 'none',
})
}
},
async showServiceTerms() {
try {
const res = await getServiceTerms()
if (res.code === 200 && res.data) {
let content = res.data.content || '暂无服务条款内容'
content = content.replace(/\n/g, '<br/>')
content = `<div style="word-wrap: break-word; word-break: break-all; line-height: 1.8; font-size: 28rpx; color: #333; padding: 0; margin: 0;">${content}</div>`
this.serviceTermsContent = content
this.showServiceTermsPopup = true
this.scrollTop = 0
} else {
uni.showToast({
title: '获取服务条款失败',
icon: 'none',
})
}
} catch (error) {
console.error('获取服务条款失败:', error)
uni.showToast({
title: '获取服务条款失败',
icon: 'none',
})
}
},
} catch (error) {
console.error('获取服务条款失败:', error)
uni.showToast({
title: '获取服务条款失败',
icon: 'none',
})
}
},
async showPrivacyPolicy() {
try {
const res = await getPrivacyPolicy()
if (res.code === 200 && res.data) {
let content = res.data.content || '暂无隐私政策内容'
content = content.replace(/\n/g, '<br/>')
content = `<div style="word-wrap: break-word; word-break: break-all; line-height: 1.8; font-size: 28rpx; color: #333; padding: 0; margin: 0;">${content}</div>`
this.privacyPolicyContent = content
this.showPrivacyPolicyPopup = true
this.scrollTop = 0
} else {
uni.showToast({
title: '获取隐私政策失败',
icon: 'none',
})
}
} catch (error) {
console.error('获取隐私政策失败:', error)
async showPrivacyPolicy() {
try {
const res = await getPrivacyPolicy()
if (res.code === 200 && res.data) {
let content = res.data.content || '暂无隐私政策内容'
content = content.replace(/\n/g, '<br/>')
content = `<div style="word-wrap: break-word; word-break: break-all; line-height: 1.8; font-size: 28rpx; color: #333; padding: 0; margin: 0;">${content}</div>`
this.privacyPolicyContent = content
this.showPrivacyPolicyPopup = true
this.scrollTop = 0
} else {
uni.showToast({
title: '获取隐私政策失败',
icon: 'none',
})
}
},
} catch (error) {
console.error('获取隐私政策失败:', error)
uni.showToast({
title: '获取隐私政策失败',
icon: 'none',
})
}
},
closeServiceTermsPopup() {
this.showServiceTermsPopup = false
},
closeServiceTermsPopup() {
this.showServiceTermsPopup = false
},
closePrivacyPolicyPopup() {
this.showPrivacyPolicyPopup = false
},
closePrivacyPolicyPopup() {
this.showPrivacyPolicyPopup = false
},
async agreeServiceTerms() {
this.hasReadServiceTerms = true
this.closeServiceTermsPopup()
this.checkAgreementStatus()
async agreeServiceTerms() {
this.hasReadServiceTerms = true
this.closeServiceTermsPopup()
this.checkAgreementStatus()
if (!this.hasReadPrivacyPolicy) {
setTimeout(() => {
this.showPrivacyPolicy()
}, 500)
}
},
if (!this.hasReadPrivacyPolicy) {
setTimeout(() => {
this.showPrivacyPolicy()
}, 500)
}
},
async agreePrivacyPolicy() {
this.hasReadPrivacyPolicy = true
this.closePrivacyPolicyPopup()
this.checkAgreementStatus()
async agreePrivacyPolicy() {
this.hasReadPrivacyPolicy = true
this.closePrivacyPolicyPopup()
this.checkAgreementStatus()
if (!this.hasReadServiceTerms) {
setTimeout(() => {
this.showServiceTerms()
}, 500)
}
},
if (!this.hasReadServiceTerms) {
setTimeout(() => {
this.showServiceTerms()
}, 500)
}
},
checkAgreementStatus() {
if (this.hasReadServiceTerms && this.hasReadPrivacyPolicy) {
this.hasAgreed = true
}
},
checkAgreementStatus() {
if (this.hasReadServiceTerms && this.hasReadPrivacyPolicy) {
this.hasAgreed = true
}
},
async showUnreadTerms() {
if (!this.hasReadServiceTerms) {
await this.showServiceTerms()
return
}
async showUnreadTerms() {
if (!this.hasReadServiceTerms) {
await this.showServiceTerms()
return
}
if (!this.hasReadPrivacyPolicy) {
await this.showPrivacyPolicy()
return
}
},
if (!this.hasReadPrivacyPolicy) {
await this.showPrivacyPolicy()
return
}
},
getPhoneNumber() {
if (!this.hasReadServiceTerms || !this.hasReadPrivacyPolicy) {
uni.showToast({
title: '请先阅读服务条款和隐私政策',
icon: 'none',
duration: 2000,
})
getPhoneNumber() {
if (!this.hasReadServiceTerms || !this.hasReadPrivacyPolicy) {
uni.showToast({
title: '请先阅读服务条款和隐私政策',
icon: 'none',
duration: 2000,
})
this.showUnreadTerms()
return
}
this.showUnreadTerms()
return
}
const that = this
uni.login({
success(res) {
if (res.code) {
console.log('登录!', res)
const data = {
loginCode: res.code,
appId: 1,
}
const that = this
uni.login({
success(res) {
if (res.code) {
console.log('登录!', res)
const data = {
loginCode: res.code,
appId: 1,
}
if (that.pageLoading) {
that.pageLoading.show('登录中...')
}
if (that.pageLoading) {
that.pageLoading.show('登录中...')
}
wxLogin(data)
.then(res => {
if (that.pageLoading) {
that.pageLoading.hide()
}
forceHideLoading()
wxLogin(data)
.then(res => {
if (that.pageLoading) {
that.pageLoading.hide()
}
forceHideLoading()
if (res.code == 200) {
console.log(res, 'resres')
uni.setStorageSync('token', res.token)
uni.showToast({
title: '登录成功',
icon: 'success',
duration: 1500,
})
setTimeout(() => {
that.ceshi()
}, 1500)
} else {
uni.showToast({
title: res.msg || '登录失败',
icon: 'none',
})
}
})
.catch(error => {
if (that.pageLoading) {
that.pageLoading.hide()
}
forceHideLoading()
console.error('登录失败:', error)
if (res.code == 200) {
console.log(res, 'resres')
uni.setStorageSync('token', res.token)
uni.showToast({
title: '登录失败',
title: '登录成功',
icon: 'success',
duration: 1500,
})
setTimeout(() => {
that.ceshi()
}, 1500)
} else {
uni.showToast({
title: res.msg || '登录失败',
icon: 'none',
})
})
}
},
fail(err) {
console.error('微信登录失败:', err)
uni.showToast({
title: '微信登录失败',
icon: 'none',
})
},
})
},
}
})
.catch(error => {
if (that.pageLoading) {
that.pageLoading.hide()
}
forceHideLoading()
async ceshi() {
if (this.pageLoading) {
this.pageLoading.hide()
}
forceHideLoading()
navigateToPage('index')
},
console.error('登录失败:', error)
uni.showToast({
title: '登录失败',
icon: 'none',
})
})
}
},
fail(err) {
console.error('微信登录失败:', err)
uni.showToast({
title: '微信登录失败',
icon: 'none',
})
},
})
},
}
async ceshi() {
if (this.pageLoading) {
this.pageLoading.hide()
}
forceHideLoading()
navigateToPage('index')
},
},
}
</script>
<style lang="scss">
page {
background: #ffffff;
}
page {
background: #ffffff;
}
.login-container {
padding-bottom: 40rpx;
max-width: 750rpx;
background: #ffffff;
}
.login-container {
padding-bottom: 40rpx;
max-width: 750rpx;
background: #ffffff;
}
.logo-section {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 80rpx;
width: 100%;
margin-top: 330rpx;
//border:green 1px solid;
}
.logo-section {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 80rpx;
width: 100%;
margin-top: 330rpx;
//border:green 1px solid;
}
.logo-image {
width: 276rpx;
height: 276rpx;
}
.logo-image {
width: 276rpx;
height: 276rpx;
}
.main-content {
padding: 0 53rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 654rpx;
//border: red 1px solid;
}
.main-content {
padding: 0 53rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 654rpx;
//border: red 1px solid;
}
.login-btn {
width: 100%;
height: 98rpx;
background: #f15a04;
border-radius: 10rpx;
border: none;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
box-shadow: 0 4rpx 12rpx rgba(255, 107, 53, 0.3);
}
.login-btn {
width: 100%;
height: 98rpx;
background: #f15a04;
border-radius: 10rpx;
border: none;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
box-shadow: 0 4rpx 12rpx rgba(255, 107, 53, 0.3);
}
.login-btn:active {
transform: translateY(2rpx);
box-shadow: 0 2rpx 8rpx rgba(255, 107, 53, 0.3);
}
.login-btn:active {
transform: translateY(2rpx);
box-shadow: 0 2rpx 8rpx rgba(255, 107, 53, 0.3);
}
.login-btn:disabled {
background: #ccc;
box-shadow: none;
}
.login-btn:disabled {
background: #ccc;
box-shadow: none;
}
.btn-text {
font-size: 32rpx;
font-weight: 600;
color: #fff;
}
.btn-text {
font-size: 32rpx;
font-weight: 600;
color: #fff;
}
.agreement-section {
display: flex;
align-items: center;
justify-content: center;
gap: 8rpx;
padding: 30rpx;
margin-top: 40rpx;
flex-wrap: wrap;
}
.agreement-section {
display: flex;
align-items: center;
justify-content: center;
gap: 8rpx;
padding: 30rpx;
margin-top: 40rpx;
flex-wrap: wrap;
}
.agreement-checkbox {
display: flex;
align-items: center;
}
.agreement-checkbox {
display: flex;
align-items: center;
}
.checkbox {
width: 28rpx;
height: 28rpx;
border: 2rpx solid #ff6b35;
border-radius: 6rpx;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
transition: all 0.3s ease;
}
.checkbox {
width: 28rpx;
height: 28rpx;
border: 2rpx solid #ff6b35;
border-radius: 6rpx;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
transition: all 0.3s ease;
}
.checkbox.checked {
background: #ff6b35;
border-color: #ff6b35;
}
.checkbox.checked {
background: #ff6b35;
border-color: #ff6b35;
}
.checkmark {
color: #fff;
font-size: 18rpx;
font-weight: bold;
}
.checkmark {
color: #fff;
font-size: 18rpx;
font-weight: bold;
}
.agreement-text {
font-size: 24rpx;
color: #666;
}
.agreement-text {
font-size: 24rpx;
color: #666;
}
.agreement-link {
font-size: 24rpx;
color: #ff6b35;
text-decoration: underline;
}
.agreement-link {
font-size: 24rpx;
color: #ff6b35;
text-decoration: underline;
}
.popup-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx;
box-sizing: border-box;
}
.popup-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx;
box-sizing: border-box;
}
.popup-content {
background: #fff;
border-radius: 20rpx;
overflow: hidden;
display: flex;
flex-direction: column;
width: 100%;
max-width: 680rpx;
height: 85vh;
max-height: 900rpx;
min-height: 600rpx;
margin: 0;
}
.popup-content {
background: #fff;
border-radius: 20rpx;
overflow: hidden;
display: flex;
flex-direction: column;
width: 100%;
max-width: 680rpx;
height: 85vh;
max-height: 900rpx;
min-height: 600rpx;
margin: 0;
}
.popup-header {
padding: 30rpx;
border-bottom: 1rpx solid #eee;
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
}
.popup-header {
padding: 30rpx;
border-bottom: 1rpx solid #eee;
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
}
.popup-title {
font-size: 32rpx;
font-weight: 500;
color: #333;
}
.popup-title {
font-size: 32rpx;
font-weight: 500;
color: #333;
}
.popup-close {
font-size: 40rpx;
color: #999;
cursor: pointer;
padding: 10rpx;
}
.popup-close {
font-size: 40rpx;
color: #999;
cursor: pointer;
padding: 10rpx;
}
.popup-body {
flex: 1;
padding: 30rpx;
overflow: hidden;
position: relative;
height: 0;
}
.popup-body {
flex: 1;
padding: 30rpx;
overflow: hidden;
position: relative;
height: 0;
}
.terms-content {
line-height: 1.8;
font-size: 28rpx;
color: #333;
word-wrap: break-word;
word-break: break-all;
padding-bottom: 20rpx;
}
.terms-content {
line-height: 1.8;
font-size: 28rpx;
color: #333;
word-wrap: break-word;
word-break: break-all;
padding-bottom: 20rpx;
}
.popup-footer {
padding: 30rpx;
border-top: 1rpx solid #eee;
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
}
.popup-footer {
padding: 30rpx;
border-top: 1rpx solid #eee;
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
}
.popup-tip {
font-size: 24rpx;
color: #999;
margin-bottom: 20rpx;
text-align: center;
}
.popup-tip {
font-size: 24rpx;
color: #999;
margin-bottom: 20rpx;
text-align: center;
}
.popup-btn {
width: 200rpx;
height: 70rpx;
background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
border-radius: 35rpx;
font-size: 28rpx;
color: #ffffff;
border: none;
}
.popup-btn {
width: 200rpx;
height: 70rpx;
background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
border-radius: 35rpx;
font-size: 28rpx;
color: #ffffff;
border: none;
}
</style>

View File

@ -5,4 +5,4 @@
"browserHash": "88121bc0",
"optimized": {},
"chunks": {}
}
}

View File

@ -1 +1 @@
{"version":3,"file":"app.js","sources":["App.vue","main.js"],"sourcesContent":["<script>\n export default {\n onLaunch: function () {\n console.log('App Launch')\n },\n onShow: function () {\n console.log('App Show')\n },\n onHide: function () {\n console.log('App Hide')\n },\n }\n</script>\n\n<style>\n /*每个页面公共css */\n</style>\n","import App from './App'\n\n// #ifndef VUE3\nimport Vue from 'vue'\nimport './uni.promisify.adaptor'\nVue.config.productionTip = false\nApp.mpType = 'app'\nconst app = new Vue({\n ...App,\n})\napp.$mount()\n// #endif\n\n// #ifdef VUE3\nimport { createSSRApp } from 'vue'\nimport PageScrollMixin from './mixins/page-scroll-mixin.js'\n\nexport function createApp() {\n const app = createSSRApp(App)\n\n // 注册全局 mixin (Vue3 方式)\n app.mixin(PageScrollMixin)\n\n return {\n app,\n }\n}\n// #endif\n"],"names":["uni","createSSRApp","App","PageScrollMixin"],"mappings":";;;;;;;;AACE,MAAK,YAAU;AAAA,EACb,UAAU,WAAY;AACpBA,kBAAAA,MAAA,MAAA,OAAA,gBAAY,YAAY;AAAA,EACzB;AAAA,EACD,QAAQ,WAAY;AAClBA,kBAAAA,mCAAY,UAAU;AAAA,EACvB;AAAA,EACD,QAAQ,WAAY;AAClBA,kBAAAA,oCAAY,UAAU;AAAA,EACvB;AACH;ACMK,SAAS,YAAY;AAC1B,QAAM,MAAMC,cAAY,aAACC,SAAG;AAG5B,MAAI,MAAMC,sCAAe;AAEzB,SAAO;AAAA,IACL;AAAA,EACD;AACH;;;"}
{"version":3,"file":"app.js","sources":["App.vue","main.js"],"sourcesContent":["<script>\nexport default {\n onLaunch: function () {\n console.log('App Launch')\n },\n onShow: function () {\n console.log('App Show')\n },\n onHide: function () {\n console.log('App Hide')\n },\n}\n</script>\n\n<style>\n/*每个页面公共css */\n</style>\n","import App from './App'\n\n// #ifndef VUE3\nimport Vue from 'vue'\nimport './uni.promisify.adaptor'\nVue.config.productionTip = false\nApp.mpType = 'app'\nconst app = new Vue({\n ...App,\n})\napp.$mount()\n// #endif\n\n// #ifdef VUE3\nimport { createSSRApp } from 'vue'\nimport PageScrollMixin from './mixins/page-scroll-mixin.js'\n\nexport function createApp() {\n const app = createSSRApp(App)\n\n // 注册全局 mixin (Vue3 方式)\n app.mixin(PageScrollMixin)\n\n return {\n app,\n }\n}\n// #endif\n"],"names":["uni","createSSRApp","App","PageScrollMixin"],"mappings":";;;;;;;;AACA,MAAK,YAAU;AAAA,EACb,UAAU,WAAY;AACpBA,kBAAAA,MAAY,MAAA,OAAA,gBAAA,YAAY;AAAA,EACzB;AAAA,EACD,QAAQ,WAAY;AAClBA,kBAAAA,MAAA,MAAA,OAAA,gBAAY,UAAU;AAAA,EACvB;AAAA,EACD,QAAQ,WAAY;AAClBA,kBAAAA,MAAA,MAAA,OAAA,iBAAY,UAAU;AAAA,EACvB;AACH;ACMO,SAAS,YAAY;AAC1B,QAAM,MAAMC,cAAY,aAACC,SAAG;AAG5B,MAAI,MAAMC,sCAAe;AAEzB,SAAO;AAAA,IACL;AAAA,EACD;AACH;;;"}

View File

@ -0,0 +1 @@
{"version":3,"file":"announcement-bar.js","sources":["components/announcement-bar/announcement-bar.vue","C:/Users/Administrator/Downloads/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovd29yay9IQnVpbGRlclByb2plY3RzL0hvbWVMZWFzZS9jb21wb25lbnRzL2Fubm91bmNlbWVudC1iYXIvYW5ub3VuY2VtZW50LWJhci52dWU"],"sourcesContent":["<template>\n <view class=\"announcement-bar\" @click=\"onAnnouncementClick\">\n <image class=\"announcementIcon\" :src=\"announcementIcon\"></image>\n <view class=\"announcement-box\">\n <text class=\"announcement-text\">{{ announcementText }}</text>\n </view>\n </view>\n</template>\n\n<script>\nexport default {\n name: 'AnnouncementBar',\n props: {\n announcementText: {\n type: String,\n default: '暂无更多公告! 暂无更多公告! 暂无更多公告!',\n },\n announcementIcon: {\n type: String,\n required: true,\n },\n },\n methods: {\n onAnnouncementClick() {\n this.$emit('announcement-click')\n },\n },\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.announcement-bar {\n background: white;\n opacity: 0.5;\n margin: 34rpx 19rpx 0 19rpx;\n padding: 15rpx 30rpx;\n display: flex;\n align-items: center;\n gap: 15rpx;\n overflow: hidden;\n height: 34rpx;\n border-radius: 100rpx;\n\n .announcementIcon {\n height: 32rpx;\n width: 32rpx;\n flex-shrink: 0;\n }\n\n .announcement-box {\n flex: 1;\n overflow: hidden;\n position: relative;\n\n .announcement-text {\n font-size: 13px;\n opacity: 1;\n color: black;\n white-space: nowrap;\n animation: scroll-text 10s linear infinite;\n display: inline-block;\n padding-left: 100%;\n }\n\n @keyframes scroll-text {\n 0% {\n transform: translateX(0);\n }\n 100% {\n transform: translateX(-100%);\n }\n }\n }\n}\n</style>\n","import Component from 'D:/work/HBuilderProjects/HomeLease/components/announcement-bar/announcement-bar.vue'\nwx.createComponent(Component)"],"names":[],"mappings":";;AAUA,MAAK,YAAU;AAAA,EACb,MAAM;AAAA,EACN,OAAO;AAAA,IACL,kBAAkB;AAAA,MAChB,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA,IACD,kBAAkB;AAAA,MAChB,MAAM;AAAA,MACN,UAAU;AAAA,IACX;AAAA,EACF;AAAA,EACD,SAAS;AAAA,IACP,sBAAsB;AACpB,WAAK,MAAM,oBAAoB;AAAA,IAChC;AAAA,EACF;AACH;;;;;;;;;AC1BA,GAAG,gBAAgB,SAAS;"}

View File

@ -0,0 +1 @@
{"version":3,"file":"banner-swiper.js","sources":["components/banner-swiper/banner-swiper.vue","C:/Users/Administrator/Downloads/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovd29yay9IQnVpbGRlclByb2plY3RzL0hvbWVMZWFzZS9jb21wb25lbnRzL2Jhbm5lci1zd2lwZXIvYmFubmVyLXN3aXBlci52dWU"],"sourcesContent":["<template>\n <view class=\"banner-section\">\n <swiper\n :autoplay=\"autoplay\"\n :duration=\"duration\"\n :indicator-dots=\"indicatorDots\"\n :interval=\"interval\"\n circular\n class=\"swiper\"\n indicator-active-color=\"#FFFFFF\"\n indicator-color=\"rgba(255, 255, 255, 0.5)\"\n >\n <swiper-item\n v-for=\"(item, index) in bannerList\"\n :key=\"index\"\n @click=\"onBannerClick(item, index)\"\n >\n <image :src=\"item.image\" mode=\"aspectFill\"></image>\n </swiper-item>\n </swiper>\n </view>\n</template>\n\n<script>\nexport default {\n name: 'BannerSwiper',\n props: {\n bannerList: {\n type: Array,\n default: () => [],\n },\n indicatorDots: {\n type: Boolean,\n default: true,\n },\n autoplay: {\n type: Boolean,\n default: true,\n },\n interval: {\n type: Number,\n default: 2000,\n },\n duration: {\n type: Number,\n default: 500,\n },\n },\n methods: {\n onSwiperChange(e) {\n this.$emit('change', e.detail.current)\n },\n onBannerClick(item, index) {\n this.$emit('banner-click', { item, index })\n },\n },\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.banner-section {\n padding: 30rpx;\n}\n\n.swiper {\n height: 300rpx;\n /* 通用指示器样式 - 覆盖所有可能的类名 */\n\n :deep([class*='swiper-dot']) {\n border-radius: 50% !important;\n transition: all 0.3s ease !important;\n }\n\n :deep([class*='swiper-dot-active']) {\n width: 82rpx !important;\n height: 14rpx;\n /* 选中时稍大 */\n }\n\n .swiper-item {\n display: block;\n height: 300rpx;\n line-height: 300rpx;\n text-align: center;\n\n image {\n width: 100%;\n height: 100%;\n border-radius: 20rpx;\n }\n }\n}\n</style>\n","import Component from 'D:/work/HBuilderProjects/HomeLease/components/banner-swiper/banner-swiper.vue'\nwx.createComponent(Component)"],"names":[],"mappings":";;AAwBA,MAAK,YAAU;AAAA,EACb,MAAM;AAAA,EACN,OAAO;AAAA,IACL,YAAY;AAAA,MACV,MAAM;AAAA,MACN,SAAS,MAAM,CAAE;AAAA,IAClB;AAAA,IACD,eAAe;AAAA,MACb,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA,IACD,UAAU;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA,IACD,UAAU;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA,IACD,UAAU;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA,EACF;AAAA,EACD,SAAS;AAAA,IACP,eAAe,GAAG;AAChB,WAAK,MAAM,UAAU,EAAE,OAAO,OAAO;AAAA,IACtC;AAAA,IACD,cAAc,MAAM,OAAO;AACzB,WAAK,MAAM,gBAAgB,EAAE,MAAM,OAAO;AAAA,IAC3C;AAAA,EACF;AACH;;;;;;;;;;;;;;;;;ACvDA,GAAG,gBAAgB,SAAS;"}

View File

@ -0,0 +1 @@
{"version":3,"file":"bottom-nav.js","sources":["components/bottom-nav/bottom-nav.vue","C:/Users/Administrator/Downloads/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovd29yay9IQnVpbGRlclByb2plY3RzL0hvbWVMZWFzZS9jb21wb25lbnRzL2JvdHRvbS1uYXYvYm90dG9tLW5hdi52dWU"],"sourcesContent":["<template>\n <view class=\"bottom-nav\">\n <view\n v-for=\"(nav, index) in navItems\"\n :key=\"index\"\n class=\"nav-item\"\n :class=\"{ active: index === activeIndex }\"\n @click=\"onNavClick(index)\"\n >\n <image class=\"nav-icon\" :src=\"getNavIcon(index)\" mode=\"aspectFit\"></image>\n <text class=\"nav-text\">{{ nav }}</text>\n </view>\n </view>\n</template>\n\n<script>\nexport default {\n name: 'BottomNav',\n props: {\n navItems: {\n type: Array,\n default: () => ['首页', '申请租赁', '个人中心'],\n },\n activeIndex: {\n type: Number,\n default: 0,\n },\n iconConfig: {\n type: Object,\n required: true,\n },\n },\n methods: {\n onNavClick(index) {\n this.$emit('nav-click', index)\n },\n\n getNavIcon(index) {\n const isActive = index === this.activeIndex\n const icons = this.iconConfig\n\n switch (index) {\n case 0: // 首页\n return isActive ? icons.HOME_ACTIVE : icons.HOME\n case 1: // 申请租赁\n return isActive ? icons.RENT_ACTIVE : icons.RENT\n case 2: // 个人中心\n return isActive ? icons.PERSONAL_CENTER_ACTIVE : icons.PERSONAL_CENTER\n default:\n return icons.HOME\n }\n },\n },\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.bottom-nav {\n position: fixed;\n bottom: 0;\n left: 0;\n right: 0;\n background: #fff;\n display: flex;\n justify-content: space-around;\n align-items: center;\n padding: 20rpx 0;\n box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);\n z-index: 1000;\n}\n\n.nav-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8rpx;\n padding: 10rpx;\n transition: all 0.3s ease;\n}\n\n.nav-item:active {\n transform: scale(0.95);\n}\n\n.nav-icon {\n width: 48rpx;\n height: 48rpx;\n}\n\n.nav-text {\n font-size: 20rpx;\n color: #999;\n}\n\n.nav-item.active .nav-text {\n color: #ff9a9e;\n}\n</style>\n","import Component from 'D:/work/HBuilderProjects/HomeLease/components/bottom-nav/bottom-nav.vue'\nwx.createComponent(Component)"],"names":[],"mappings":";;AAgBA,MAAK,YAAU;AAAA,EACb,MAAM;AAAA,EACN,OAAO;AAAA,IACL,UAAU;AAAA,MACR,MAAM;AAAA,MACN,SAAS,MAAM,CAAC,MAAM,QAAQ,MAAM;AAAA,IACrC;AAAA,IACD,aAAa;AAAA,MACX,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA,IACD,YAAY;AAAA,MACV,MAAM;AAAA,MACN,UAAU;AAAA,IACX;AAAA,EACF;AAAA,EACD,SAAS;AAAA,IACP,WAAW,OAAO;AAChB,WAAK,MAAM,aAAa,KAAK;AAAA,IAC9B;AAAA,IAED,WAAW,OAAO;AAChB,YAAM,WAAW,UAAU,KAAK;AAChC,YAAM,QAAQ,KAAK;AAEnB,cAAQ,OAAK;AAAA,QACX,KAAK;AACH,iBAAO,WAAW,MAAM,cAAc,MAAM;AAAA,QAC9C,KAAK;AACH,iBAAO,WAAW,MAAM,cAAc,MAAM;AAAA,QAC9C,KAAK;AACH,iBAAO,WAAW,MAAM,yBAAyB,MAAM;AAAA,QACzD;AACE,iBAAO,MAAM;AAAA,MACjB;AAAA,IACD;AAAA,EACF;AACH;;;;;;;;;;;;;;;ACpDA,GAAG,gBAAgB,SAAS;"}

View File

@ -0,0 +1 @@
{"version":3,"file":"equipment-list.js","sources":["components/equipment-list/equipment-list.vue","C:/Users/Administrator/Downloads/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovd29yay9IQnVpbGRlclByb2plY3RzL0hvbWVMZWFzZS9jb21wb25lbnRzL2VxdWlwbWVudC1saXN0L2VxdWlwbWVudC1saXN0LnZ1ZQ"],"sourcesContent":["<template>\n <view class=\"equipment-section\">\n <view class=\"section-title\">{{ title }}</view>\n <view class=\"equipment-list\">\n <view\n v-for=\"equipment in equipmentList\"\n :key=\"equipment.id\"\n class=\"equipment-item\"\n @click=\"onEquipmentClick(equipment)\"\n >\n <image class=\"equipment-image\" :src=\"equipment.image\" mode=\"aspectFit\"></image>\n <view class=\"equipment-info\">\n <view class=\"equipment-header\">\n <text class=\"equipment-name\">{{ equipment.name }}</text>\n <text class=\"status-badge\" :class=\"equipment.status\">\n {{ getStatusText(equipment.status) }}\n </text>\n </view>\n <view class=\"equipment-details\">\n <view class=\"detail-item-row\">\n <text class=\"detail-item-time\">租赁时间:</text>\n <text class=\"detail-item\">{{ equipment.startTime }}</text>\n </view>\n <view class=\"detail-item-row\">\n <text class=\"detail-item-time\">到期时间:</text>\n <text class=\"detail-item\">{{ equipment.endTime }}</text>\n </view>\n </view>\n <button class=\"renew-btn\" @click.stop=\"onRenew(equipment)\">去续费</button>\n </view>\n </view>\n </view>\n </view>\n</template>\n\n<script>\nexport default {\n name: 'EquipmentList',\n props: {\n title: {\n type: String,\n default: '我的租赁设备',\n },\n equipmentList: {\n type: Array,\n default: () => [],\n },\n },\n methods: {\n getStatusText(status) {\n const statusMap = {\n normal: '正常',\n warning: '警告',\n error: '异常',\n }\n return statusMap[status] || '未知'\n },\n\n onEquipmentClick(equipment) {\n this.$emit('equipment-click', equipment)\n },\n\n onRenew(equipment) {\n this.$emit('renew', equipment)\n },\n },\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.equipment-section {\n padding: 0 30rpx;\n}\n\n.section-title {\n width: 180rpx;\n height: 33rpx;\n background: #ffffff;\n font-size: 14px;\n font-weight: 400;\n color: #3d3d3d;\n margin-bottom: 20rpx;\n padding: 14rpx 20rpx;\n border-radius: 4px;\n}\n\n.equipment-list {\n display: flex;\n flex-direction: column;\n gap: 20rpx;\n}\n\n.equipment-item {\n background: #fff;\n border-radius: 20rpx;\n padding: 30rpx;\n display: flex;\n gap: 30rpx;\n box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);\n transition: all 0.3s ease;\n justify-content: center;\n align-items: center;\n\n .equipment-image {\n width: 160rpx;\n height: 106rpx;\n border-radius: 10rpx;\n background-color: #f8f9fa;\n flex-shrink: 0;\n }\n}\n\n.equipment-item:active {\n transform: scale(0.98);\n box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.15);\n}\n\n.equipment-info {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n}\n\n.equipment-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 15rpx;\n}\n\n.equipment-name {\n font-size: 16px;\n font-weight: 500;\n color: #3d3d3d;\n}\n\n.status-badge {\n padding: 4rpx 26rpx;\n border-radius: 5rpx;\n font-size: 24rpx;\n color: #40c186;\n\n &.normal {\n background-color: #ebfff6;\n }\n\n &.warning {\n background-color: #faad14;\n }\n\n &.error {\n background-color: #ff4d4f;\n }\n}\n\n.equipment-details {\n display: flex;\n flex-direction: column;\n gap: 8rpx;\n margin-bottom: 15rpx;\n}\n\n.detail-item-row {\n display: flex;\n justify-content: space-between;\n\n .detail-item-time {\n color: #817f7f;\n font-size: 26rpx;\n }\n\n .detail-item {\n font-size: 24rpx;\n color: #666;\n }\n}\n\n.renew-btn {\n margin-right: 0;\n background: #f15a04;\n color: #fff;\n border-radius: 5px;\n padding: 0 57rpx;\n font-size: 32rpx;\n font-weight: 500;\n margin-top: 10rpx;\n}\n</style>\n","import Component from 'D:/work/HBuilderProjects/HomeLease/components/equipment-list/equipment-list.vue'\nwx.createComponent(Component)"],"names":[],"mappings":";;AAoCA,MAAK,YAAU;AAAA,EACb,MAAM;AAAA,EACN,OAAO;AAAA,IACL,OAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA,IACD,eAAe;AAAA,MACb,MAAM;AAAA,MACN,SAAS,MAAM,CAAE;AAAA,IAClB;AAAA,EACF;AAAA,EACD,SAAS;AAAA,IACP,cAAc,QAAQ;AACpB,YAAM,YAAY;AAAA,QAChB,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AACA,aAAO,UAAU,MAAM,KAAK;AAAA,IAC7B;AAAA,IAED,iBAAiB,WAAW;AAC1B,WAAK,MAAM,mBAAmB,SAAS;AAAA,IACxC;AAAA,IAED,QAAQ,WAAW;AACjB,WAAK,MAAM,SAAS,SAAS;AAAA,IAC9B;AAAA,EACF;AACH;;;;;;;;;;;;;;;;;;;;ACjEA,GAAG,gBAAgB,SAAS;"}

View File

@ -0,0 +1 @@
{"version":3,"file":"home-header.js","sources":["components/home-header/home-header.vue","C:/Users/Administrator/Downloads/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RDovd29yay9IQnVpbGRlclByb2plY3RzL0hvbWVMZWFzZS9jb21wb25lbnRzL2hvbWUtaGVhZGVyL2hvbWUtaGVhZGVyLnZ1ZQ"],"sourcesContent":["<template>\n <view class=\"header\">\n <view class=\"location-info\" @click=\"onLocationClick\">\n <image class=\"location\" :src=\"locationIcon\"></image>\n <text class=\"company-name\">{{ companyName }}</text>\n <text class=\"arrow\">></text>\n </view>\n </view>\n</template>\n\n<script>\nexport default {\n name: 'HomeHeader',\n props: {\n companyName: {\n type: String,\n default: '福鼎创特物联科技有限公司',\n },\n locationIcon: {\n type: String,\n required: true,\n },\n },\n methods: {\n onLocationClick() {\n this.$emit('location-click')\n },\n },\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.header {\n padding: 106rpx 30rpx 20rpx 30rpx;\n display: flex;\n justify-content: space-between;\n align-items: center;\n background: #ffddca;\n z-index: 999;\n\n .location-info {\n display: flex;\n align-items: center;\n gap: 10rpx;\n flex: 1;\n\n .location {\n width: 27rpx;\n height: 31rpx;\n }\n\n .company-name {\n color: #3d3d3d;\n font-size: 16px;\n font-weight: 500;\n }\n\n .arrow {\n font-size: 24rpx;\n color: #666;\n }\n }\n}\n</style>\n","import Component from 'D:/work/HBuilderProjects/HomeLease/components/home-header/home-header.vue'\nwx.createComponent(Component)"],"names":[],"mappings":";;AAWA,MAAK,YAAU;AAAA,EACb,MAAM;AAAA,EACN,OAAO;AAAA,IACL,aAAa;AAAA,MACX,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA,IACD,cAAc;AAAA,MACZ,MAAM;AAAA,MACN,UAAU;AAAA,IACX;AAAA,EACF;AAAA,EACD,SAAS;AAAA,IACP,kBAAkB;AAChB,WAAK,MAAM,gBAAgB;AAAA,IAC5B;AAAA,EACF;AACH;;;;;;;;;AC3BA,GAAG,gBAAgB,SAAS;"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,5 @@
{
"pages": [
"pages/index/index",
"pages/login/login"
],
"pages": ["pages/index/index", "pages/login/login"],
"window": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "设备租赁",
@ -10,4 +7,4 @@
"backgroundColor": "#F8F8F8"
},
"usingComponents": {}
}
}

View File

@ -1,3 +1,3 @@
/*每个页面公共css */
/*每个页面公共css */
page{--status-bar-height:25px;--top-window-height:0px;--window-top:0px;--window-bottom:0px;--window-left:0px;--window-right:0px;--window-magin:0px}[data-c-h="true"]{display: none !important;}

View File

@ -0,0 +1,30 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
const _sfc_main = {
name: "AnnouncementBar",
props: {
announcementText: {
type: String,
default: "暂无更多公告! 暂无更多公告! 暂无更多公告!"
},
announcementIcon: {
type: String,
required: true
}
},
methods: {
onAnnouncementClick() {
this.$emit("announcement-click");
}
}
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return {
a: $props.announcementIcon,
b: common_vendor.t($props.announcementText),
c: common_vendor.o((...args) => $options.onAnnouncementClick && $options.onAnnouncementClick(...args))
};
}
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-3c038241"]]);
wx.createComponent(Component);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/components/announcement-bar/announcement-bar.js.map

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1 @@
<view class="announcement-bar data-v-3c038241" bindtap="{{c}}"><image class="announcementIcon data-v-3c038241" src="{{a}}"></image><view class="announcement-box data-v-3c038241"><text class="announcement-text data-v-3c038241">{{b}}</text></view></view>

View File

@ -0,0 +1,64 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
/* 文字基本颜色 */
/* 背景颜色 */
/* 边框颜色 */
/* 尺寸变量 */
/* 文字尺寸 */
/* 图片尺寸 */
/* Border Radius */
/* 水平间距 */
/* 垂直间距 */
/* 透明度 */
/* 文章场景相关 */
.announcement-bar.data-v-3c038241 {
background: white;
opacity: 0.5;
margin: 34rpx 19rpx 0 19rpx;
padding: 15rpx 30rpx;
display: flex;
align-items: center;
gap: 15rpx;
overflow: hidden;
height: 34rpx;
border-radius: 100rpx;
}
.announcement-bar .announcementIcon.data-v-3c038241 {
height: 32rpx;
width: 32rpx;
flex-shrink: 0;
}
.announcement-bar .announcement-box.data-v-3c038241 {
flex: 1;
overflow: hidden;
position: relative;
}
.announcement-bar .announcement-box .announcement-text.data-v-3c038241 {
font-size: 13px;
opacity: 1;
color: black;
white-space: nowrap;
animation: scroll-text-3c038241 10s linear infinite;
display: inline-block;
padding-left: 100%;
}
@keyframes scroll-text-3c038241 {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-100%);
}
}

View File

@ -0,0 +1,53 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
const _sfc_main = {
name: "BannerSwiper",
props: {
bannerList: {
type: Array,
default: () => []
},
indicatorDots: {
type: Boolean,
default: true
},
autoplay: {
type: Boolean,
default: true
},
interval: {
type: Number,
default: 2e3
},
duration: {
type: Number,
default: 500
}
},
methods: {
onSwiperChange(e) {
this.$emit("change", e.detail.current);
},
onBannerClick(item, index) {
this.$emit("banner-click", { item, index });
}
}
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return {
a: common_vendor.f($props.bannerList, (item, index, i0) => {
return {
a: item.image,
b: index,
c: common_vendor.o(($event) => $options.onBannerClick(item, index), index)
};
}),
b: $props.autoplay,
c: $props.duration,
d: $props.indicatorDots,
e: $props.interval
};
}
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-f6b62634"]]);
wx.createComponent(Component);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/components/banner-swiper/banner-swiper.js.map

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1 @@
<view class="banner-section data-v-f6b62634"><swiper autoplay="{{b}}" duration="{{c}}" indicator-dots="{{d}}" interval="{{e}}" circular class="swiper data-v-f6b62634" indicator-active-color="#FFFFFF" indicator-color="rgba(255, 255, 255, 0.5)"><swiper-item wx:for="{{a}}" wx:for-item="item" wx:key="b" class="data-v-f6b62634" bindtap="{{item.c}}"><image class="data-v-f6b62634" src="{{item.a}}" mode="aspectFill"></image></swiper-item></swiper></view>

View File

@ -0,0 +1,52 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
/* 文字基本颜色 */
/* 背景颜色 */
/* 边框颜色 */
/* 尺寸变量 */
/* 文字尺寸 */
/* 图片尺寸 */
/* Border Radius */
/* 水平间距 */
/* 垂直间距 */
/* 透明度 */
/* 文章场景相关 */
.banner-section.data-v-f6b62634 {
padding: 30rpx;
}
.swiper.data-v-f6b62634 {
height: 300rpx;
/* 通用指示器样式 - 覆盖所有可能的类名 */
}
.swiper.data-v-f6b62634 [class*="swiper-dot"] {
border-radius: 50% !important;
transition: all 0.3s ease !important;
}
.swiper.data-v-f6b62634 [class*="swiper-dot-active"] {
width: 82rpx !important;
height: 14rpx;
/* 选中时稍大 */
}
.swiper .swiper-item.data-v-f6b62634 {
display: block;
height: 300rpx;
line-height: 300rpx;
text-align: center;
}
.swiper .swiper-item image.data-v-f6b62634 {
width: 100%;
height: 100%;
border-radius: 20rpx;
}

View File

@ -0,0 +1,54 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
const _sfc_main = {
name: "BottomNav",
props: {
navItems: {
type: Array,
default: () => ["首页", "申请租赁", "个人中心"]
},
activeIndex: {
type: Number,
default: 0
},
iconConfig: {
type: Object,
required: true
}
},
methods: {
onNavClick(index) {
this.$emit("nav-click", index);
},
getNavIcon(index) {
const isActive = index === this.activeIndex;
const icons = this.iconConfig;
switch (index) {
case 0:
return isActive ? icons.HOME_ACTIVE : icons.HOME;
case 1:
return isActive ? icons.RENT_ACTIVE : icons.RENT;
case 2:
return isActive ? icons.PERSONAL_CENTER_ACTIVE : icons.PERSONAL_CENTER;
default:
return icons.HOME;
}
}
}
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return {
a: common_vendor.f($props.navItems, (nav, index, i0) => {
return {
a: $options.getNavIcon(index),
b: common_vendor.t(nav),
c: index,
d: index === $props.activeIndex ? 1 : "",
e: common_vendor.o(($event) => $options.onNavClick(index), index)
};
})
};
}
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-55d8123a"]]);
wx.createComponent(Component);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/components/bottom-nav/bottom-nav.js.map

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1 @@
<view class="bottom-nav data-v-55d8123a"><view wx:for="{{a}}" wx:for-item="nav" wx:key="c" class="{{['nav-item', 'data-v-55d8123a', nav.d && 'active']}}" bindtap="{{nav.e}}"><image class="nav-icon data-v-55d8123a" src="{{nav.a}}" mode="aspectFit"></image><text class="nav-text data-v-55d8123a">{{nav.b}}</text></view></view>

View File

@ -0,0 +1,60 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
/* 文字基本颜色 */
/* 背景颜色 */
/* 边框颜色 */
/* 尺寸变量 */
/* 文字尺寸 */
/* 图片尺寸 */
/* Border Radius */
/* 水平间距 */
/* 垂直间距 */
/* 透明度 */
/* 文章场景相关 */
.bottom-nav.data-v-55d8123a {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #fff;
display: flex;
justify-content: space-around;
align-items: center;
padding: 20rpx 0;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.nav-item.data-v-55d8123a {
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
padding: 10rpx;
transition: all 0.3s ease;
}
.nav-item.data-v-55d8123a:active {
transform: scale(0.95);
}
.nav-icon.data-v-55d8123a {
width: 48rpx;
height: 48rpx;
}
.nav-text.data-v-55d8123a {
font-size: 20rpx;
color: #999;
}
.nav-item.active .nav-text.data-v-55d8123a {
color: #ff9a9e;
}

View File

@ -0,0 +1,52 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
const _sfc_main = {
name: "EquipmentList",
props: {
title: {
type: String,
default: "我的租赁设备"
},
equipmentList: {
type: Array,
default: () => []
}
},
methods: {
getStatusText(status) {
const statusMap = {
normal: "正常",
warning: "警告",
error: "异常"
};
return statusMap[status] || "未知";
},
onEquipmentClick(equipment) {
this.$emit("equipment-click", equipment);
},
onRenew(equipment) {
this.$emit("renew", equipment);
}
}
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return {
a: common_vendor.t($props.title),
b: common_vendor.f($props.equipmentList, (equipment, k0, i0) => {
return {
a: equipment.image,
b: common_vendor.t(equipment.name),
c: common_vendor.t($options.getStatusText(equipment.status)),
d: common_vendor.n(equipment.status),
e: common_vendor.t(equipment.startTime),
f: common_vendor.t(equipment.endTime),
g: common_vendor.o(($event) => $options.onRenew(equipment), equipment.id),
h: equipment.id,
i: common_vendor.o(($event) => $options.onEquipmentClick(equipment), equipment.id)
};
})
};
}
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-401af284"]]);
wx.createComponent(Component);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/components/equipment-list/equipment-list.js.map

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1 @@
<view class="equipment-section data-v-401af284"><view class="section-title data-v-401af284">{{a}}</view><view class="equipment-list data-v-401af284"><view wx:for="{{b}}" wx:for-item="equipment" wx:key="h" class="equipment-item data-v-401af284" bindtap="{{equipment.i}}"><image class="equipment-image data-v-401af284" src="{{equipment.a}}" mode="aspectFit"></image><view class="equipment-info data-v-401af284"><view class="equipment-header data-v-401af284"><text class="equipment-name data-v-401af284">{{equipment.b}}</text><text class="{{['status-badge', 'data-v-401af284', equipment.d]}}">{{equipment.c}}</text></view><view class="equipment-details data-v-401af284"><view class="detail-item-row data-v-401af284"><text class="detail-item-time data-v-401af284">租赁时间:</text><text class="detail-item data-v-401af284">{{equipment.e}}</text></view><view class="detail-item-row data-v-401af284"><text class="detail-item-time data-v-401af284">到期时间:</text><text class="detail-item data-v-401af284">{{equipment.f}}</text></view></view><button class="renew-btn data-v-401af284" catchtap="{{equipment.g}}">去续费</button></view></view></view></view>

View File

@ -0,0 +1,126 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
/* 文字基本颜色 */
/* 背景颜色 */
/* 边框颜色 */
/* 尺寸变量 */
/* 文字尺寸 */
/* 图片尺寸 */
/* Border Radius */
/* 水平间距 */
/* 垂直间距 */
/* 透明度 */
/* 文章场景相关 */
.equipment-section.data-v-401af284 {
padding: 0 30rpx;
}
.section-title.data-v-401af284 {
width: 180rpx;
height: 33rpx;
background: #ffffff;
font-size: 14px;
font-weight: 400;
color: #3d3d3d;
margin-bottom: 20rpx;
padding: 14rpx 20rpx;
border-radius: 4px;
}
.equipment-list.data-v-401af284 {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.equipment-item.data-v-401af284 {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
display: flex;
gap: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
justify-content: center;
align-items: center;
}
.equipment-item .equipment-image.data-v-401af284 {
width: 160rpx;
height: 106rpx;
border-radius: 10rpx;
background-color: #f8f9fa;
flex-shrink: 0;
}
.equipment-item.data-v-401af284:active {
transform: scale(0.98);
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.15);
}
.equipment-info.data-v-401af284 {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.equipment-header.data-v-401af284 {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15rpx;
}
.equipment-name.data-v-401af284 {
font-size: 16px;
font-weight: 500;
color: #3d3d3d;
}
.status-badge.data-v-401af284 {
padding: 4rpx 26rpx;
border-radius: 5rpx;
font-size: 24rpx;
color: #40c186;
}
.status-badge.normal.data-v-401af284 {
background-color: #ebfff6;
}
.status-badge.warning.data-v-401af284 {
background-color: #faad14;
}
.status-badge.error.data-v-401af284 {
background-color: #ff4d4f;
}
.equipment-details.data-v-401af284 {
display: flex;
flex-direction: column;
gap: 8rpx;
margin-bottom: 15rpx;
}
.detail-item-row.data-v-401af284 {
display: flex;
justify-content: space-between;
}
.detail-item-row .detail-item-time.data-v-401af284 {
color: #817f7f;
font-size: 26rpx;
}
.detail-item-row .detail-item.data-v-401af284 {
font-size: 24rpx;
color: #666;
}
.renew-btn.data-v-401af284 {
margin-right: 0;
background: #f15a04;
color: #fff;
border-radius: 5px;
padding: 0 57rpx;
font-size: 32rpx;
font-weight: 500;
margin-top: 10rpx;
}

View File

@ -0,0 +1,30 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
const _sfc_main = {
name: "HomeHeader",
props: {
companyName: {
type: String,
default: "福鼎创特物联科技有限公司"
},
locationIcon: {
type: String,
required: true
}
},
methods: {
onLocationClick() {
this.$emit("location-click");
}
}
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return {
a: $props.locationIcon,
b: common_vendor.t($props.companyName),
c: common_vendor.o((...args) => $options.onLocationClick && $options.onLocationClick(...args))
};
}
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-e1c5b648"]]);
wx.createComponent(Component);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/components/home-header/home-header.js.map

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1 @@
<view class="header data-v-e1c5b648"><view class="location-info data-v-e1c5b648" bindtap="{{c}}"><image class="location data-v-e1c5b648" src="{{a}}"></image><text class="company-name data-v-e1c5b648">{{b}}</text><text class="arrow data-v-e1c5b648">></text></view></view>

View File

@ -0,0 +1,52 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
/* 文字基本颜色 */
/* 背景颜色 */
/* 边框颜色 */
/* 尺寸变量 */
/* 文字尺寸 */
/* 图片尺寸 */
/* Border Radius */
/* 水平间距 */
/* 垂直间距 */
/* 透明度 */
/* 文章场景相关 */
.header.data-v-e1c5b648 {
padding: 106rpx 30rpx 20rpx 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
background: #ffddca;
z-index: 999;
}
.header .location-info.data-v-e1c5b648 {
display: flex;
align-items: center;
gap: 10rpx;
flex: 1;
}
.header .location-info .location.data-v-e1c5b648 {
width: 27rpx;
height: 31rpx;
}
.header .location-info .company-name.data-v-e1c5b648 {
color: #3d3d3d;
font-size: 16px;
font-weight: 500;
}
.header .location-info .arrow.data-v-e1c5b648 {
font-size: 24rpx;
color: #666;
}

View File

@ -8,4 +8,4 @@
"equipment-list": "../../components/equipment-list/equipment-list",
"bottom-nav": "../../components/bottom-nav/bottom-nav"
}
}
}

View File

@ -1,4 +1,4 @@
{
"navigationStyle": "custom",
"usingComponents": {}
}
}

View File

@ -33,4 +33,4 @@
"list": []
}
}
}
}

View File

@ -19,4 +19,4 @@
]
}
}
}
}