floorSelector.vue模块设计
This commit is contained in:
parent
9bfa797f44
commit
56cd2882d9
|
|
@ -73,4 +73,14 @@ export function getMemorialDetail(id) {
|
|||
return get(`/app/memorial/${id}`, {}, {
|
||||
showLoading: false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取楼层树形结构
|
||||
* @returns {Promise} 返回楼层树形数据
|
||||
*/
|
||||
export function getMemorialTree() {
|
||||
return get('/app/memorial/listTree', {}, {
|
||||
showLoading: false
|
||||
})
|
||||
}
|
||||
145
pages/memorial/compositons/README.md
Normal file
145
pages/memorial/compositons/README.md
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
# 楼层选择组件 (FloorSelector)
|
||||
|
||||
## 功能描述
|
||||
|
||||
楼层选择组件是一个三层级联选择器,用于选择楼层、区域和单元。组件会根据接口返回的树形数据自动渲染选择项。
|
||||
|
||||
## 接口数据格式
|
||||
|
||||
组件期望的接口返回格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"msg": "操作成功",
|
||||
"code": 200,
|
||||
"data": [
|
||||
{
|
||||
"id": "12",
|
||||
"label": "寒山寺",
|
||||
"type": 1,
|
||||
"children": [
|
||||
{
|
||||
"id": "1",
|
||||
"label": "1F",
|
||||
"type": 2,
|
||||
"children": [
|
||||
{
|
||||
"id": "23",
|
||||
"label": "A区",
|
||||
"type": 3,
|
||||
"children": [
|
||||
{
|
||||
"id": "16",
|
||||
"label": "A01",
|
||||
"type": 4,
|
||||
"children": null
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 组件属性 (Props)
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| defaultFloorId | String | '' | 默认选中的楼层ID |
|
||||
| defaultAreaId | String | '' | 默认选中的区域ID |
|
||||
| defaultUnitId | String | '' | 默认选中的单元ID |
|
||||
|
||||
## 事件 (Events)
|
||||
|
||||
| 事件名 | 参数 | 说明 |
|
||||
|--------|------|------|
|
||||
| selection-change | { floor, area, unit } | 选择发生变化时触发 |
|
||||
|
||||
## 方法 (Methods)
|
||||
|
||||
| 方法名 | 参数 | 返回值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| getCurrentSelection | - | Object | 获取当前选中信息 |
|
||||
| resetSelection | - | - | 重置选择到默认状态 |
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 基础使用
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<FloorSelector @selection-change="handleSelectionChange" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FloorSelector from './compositons/floorSelector.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FloorSelector
|
||||
},
|
||||
methods: {
|
||||
handleSelectionChange(selection) {
|
||||
console.log('选择变化:', selection)
|
||||
// selection 包含 { floor, area, unit }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 设置默认选中项
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<FloorSelector
|
||||
:default-floor-id="'1'"
|
||||
:default-area-id="'23'"
|
||||
:default-unit-id="'16'"
|
||||
@selection-change="handleSelectionChange"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 获取当前选择
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<FloorSelector ref="floorSelector" />
|
||||
<button @click="getSelection">获取选择</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
getSelection() {
|
||||
const selection = this.$refs.floorSelector.getCurrentSelection()
|
||||
console.log('当前选择:', selection)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 样式定制
|
||||
|
||||
组件使用了以下主要颜色:
|
||||
|
||||
- 背景色: `#FFFBF5`
|
||||
- 边框色: `#C7A26D`
|
||||
- 未选中按钮: `#F5E6D3`
|
||||
- 选中按钮: `#8B4513`
|
||||
- 文字颜色: `#695347`
|
||||
|
||||
可以通过修改组件的样式来调整外观。
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 组件会自动调用 `/app/memorial/listTree` 接口获取数据
|
||||
2. 选择楼层时会自动选中第一个区域
|
||||
3. 选择区域时会自动选中第一个单元
|
||||
4. 如果接口返回空数据,会显示空状态
|
||||
5. 网络异常时会显示错误提示
|
||||
381
pages/memorial/compositons/floorSelector.vue
Normal file
381
pages/memorial/compositons/floorSelector.vue
Normal file
|
|
@ -0,0 +1,381 @@
|
|||
<template>
|
||||
<view class="floor-selector">
|
||||
<!-- 楼层选择 -->
|
||||
<view class="floor-section">
|
||||
<text class="section-label">楼层:</text>
|
||||
<view class="floor-buttons">
|
||||
<view
|
||||
v-for="floor in floors"
|
||||
:key="floor.id"
|
||||
class="floor-btn"
|
||||
:class="{ active: selectedFloor && selectedFloor.id === floor.id }"
|
||||
@click="selectFloor(floor)"
|
||||
>
|
||||
{{ floor.label }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<view class="divider"></view>
|
||||
|
||||
<view class="content-section">
|
||||
<!-- 区域选择 -->
|
||||
<view class="area-section">
|
||||
<view
|
||||
v-for="area in areas"
|
||||
:key="area.id"
|
||||
class="area-btn"
|
||||
:class="{ active: selectedArea && selectedArea.id === area.id }"
|
||||
@click="selectArea(area)"
|
||||
>
|
||||
{{ area.label }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<view class="vertical-divider"></view>
|
||||
|
||||
<!-- 单元选择 -->
|
||||
<view class="unit-section">
|
||||
<view class="unit-grid">
|
||||
<view
|
||||
v-for="unit in units"
|
||||
:key="unit.id"
|
||||
class="unit-btn"
|
||||
:class="{ active: selectedUnit && selectedUnit.id === unit.id }"
|
||||
@click="selectUnit(unit)"
|
||||
>
|
||||
{{ unit.label }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getMemorialTree } from '@/api/memorial/index.js'
|
||||
|
||||
export default {
|
||||
name: 'FloorSelector',
|
||||
props: {
|
||||
// 默认选中的楼层ID
|
||||
defaultFloorId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 默认选中的区域ID
|
||||
defaultAreaId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 默认选中的单元ID
|
||||
defaultUnitId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
treeData: [],
|
||||
selectedFloor: null,
|
||||
selectedArea: null,
|
||||
selectedUnit: null,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 楼层列表
|
||||
floors() {
|
||||
if (!this.treeData.length) return []
|
||||
const memorial = this.treeData[0]
|
||||
return memorial && memorial.children ? memorial.children : []
|
||||
},
|
||||
// 当前选中楼层的区域列表
|
||||
areas() {
|
||||
if (!this.selectedFloor) return []
|
||||
return this.selectedFloor.children ? this.selectedFloor.children : []
|
||||
},
|
||||
// 当前选中区域的单元列表
|
||||
units() {
|
||||
if (!this.selectedArea) return []
|
||||
return this.selectedArea.children ? this.selectedArea.children : []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听选中变化,向父组件发送事件
|
||||
selectedUnit: {
|
||||
handler(newUnit) {
|
||||
this.$emit('selection-change', {
|
||||
floor: this.selectedFloor,
|
||||
area: this.selectedArea,
|
||||
unit: newUnit
|
||||
})
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadTreeData()
|
||||
},
|
||||
methods: {
|
||||
// 加载树形数据
|
||||
async loadTreeData() {
|
||||
this.loading = true
|
||||
try {
|
||||
const response = await getMemorialTree()
|
||||
console.log('楼层树形数据:', response)
|
||||
|
||||
if (response && response.code === 200) {
|
||||
this.treeData = response.data || []
|
||||
|
||||
// 设置默认选中项
|
||||
this.setDefaultSelection()
|
||||
} else {
|
||||
console.error('获取楼层数据失败:', response)
|
||||
uni.showToast({
|
||||
title: '获取楼层数据失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载楼层数据失败:', error)
|
||||
uni.showToast({
|
||||
title: '网络异常,请稍后重试',
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 设置默认选中项
|
||||
setDefaultSelection() {
|
||||
// 设置默认楼层
|
||||
if (this.defaultFloorId) {
|
||||
const floor = this.floors.find(f => f.id === this.defaultFloorId)
|
||||
if (floor) {
|
||||
this.selectFloor(floor)
|
||||
}
|
||||
} else if (this.floors.length > 0) {
|
||||
// 默认选中第一个楼层
|
||||
this.selectFloor(this.floors[0])
|
||||
}
|
||||
|
||||
// 设置默认区域
|
||||
if (this.defaultAreaId && this.selectedFloor) {
|
||||
const area = this.areas.find(a => a.id === this.defaultAreaId)
|
||||
if (area) {
|
||||
this.selectArea(area)
|
||||
}
|
||||
} else if (this.areas.length > 0) {
|
||||
// 默认选中第一个区域
|
||||
this.selectArea(this.areas[0])
|
||||
}
|
||||
|
||||
// 设置默认单元
|
||||
if (this.defaultUnitId && this.selectedArea) {
|
||||
const unit = this.units.find(u => u.id === this.defaultUnitId)
|
||||
if (unit) {
|
||||
this.selectUnit(unit)
|
||||
}
|
||||
} else if (this.units.length > 0) {
|
||||
// 默认选中第一个单元
|
||||
this.selectUnit(this.units[0])
|
||||
}
|
||||
},
|
||||
|
||||
// 选择楼层
|
||||
selectFloor(floor) {
|
||||
this.selectedFloor = floor
|
||||
this.selectedArea = null
|
||||
this.selectedUnit = null
|
||||
|
||||
// 自动选中第一个区域
|
||||
if (this.areas.length > 0) {
|
||||
this.selectArea(this.areas[0])
|
||||
}
|
||||
},
|
||||
|
||||
// 选择区域
|
||||
selectArea(area) {
|
||||
this.selectedArea = area
|
||||
this.selectedUnit = null
|
||||
|
||||
// 自动选中第一个单元
|
||||
if (this.units.length > 0) {
|
||||
this.selectUnit(this.units[0])
|
||||
}
|
||||
},
|
||||
|
||||
// 选择单元
|
||||
selectUnit(unit) {
|
||||
this.selectedUnit = unit
|
||||
},
|
||||
|
||||
// 获取当前选中信息
|
||||
getCurrentSelection() {
|
||||
return {
|
||||
floor: this.selectedFloor,
|
||||
area: this.selectedArea,
|
||||
unit: this.selectedUnit
|
||||
}
|
||||
},
|
||||
|
||||
// 重置选择
|
||||
resetSelection() {
|
||||
this.selectedFloor = null
|
||||
this.selectedArea = null
|
||||
this.selectedUnit = null
|
||||
this.setDefaultSelection()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.floor-selector {
|
||||
padding: 42rpx 44rpx 30rpx 44rpx;
|
||||
width: 750rpx;
|
||||
background-color: #FFFBF5;
|
||||
border-radius: 20rpx;
|
||||
border: 1rpx solid #C7A26D;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.floor-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 26rpx;
|
||||
border:1rpx solid #C7A26D;
|
||||
}
|
||||
|
||||
.section-label {
|
||||
margin-right: 10rpx;
|
||||
width: 96rpx;
|
||||
height: 44rpx;
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #3D3D3D;
|
||||
line-height: 44rpx;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.floor-buttons {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.floor-btn {
|
||||
padding: 4rpx 49rpx;
|
||||
color: #A24242;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
width: 134rpx;
|
||||
height: 52rpx;
|
||||
background: #FFF1DD;
|
||||
border: 1rpx solid #A24242;
|
||||
|
||||
&.active {
|
||||
background-color: #A24242;
|
||||
color: #FFF1DD;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1rpx;
|
||||
background: repeating-linear-gradient(
|
||||
to right,
|
||||
#A24242 0,
|
||||
#A24242 8rpx,
|
||||
transparent 8rpx,
|
||||
transparent 16rpx
|
||||
);
|
||||
margin: 26rpx 0 30rpx 0;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
display: flex;
|
||||
height: calc(100% - 120rpx);
|
||||
}
|
||||
|
||||
.area-section {
|
||||
width: 180rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
|
||||
border: 1rpx solid #A24242;
|
||||
}
|
||||
|
||||
.area-btn {
|
||||
padding: 4rpx 40rpx;
|
||||
color: #A24242;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-sizing: border-box;
|
||||
width: 134rpx;
|
||||
height: 52rpx;
|
||||
background: #FFF1DD;
|
||||
border: 1rpx solid #A24242;
|
||||
|
||||
&.active {
|
||||
background-color: #A24242;
|
||||
color: #FFF1DD;
|
||||
}
|
||||
}
|
||||
|
||||
.vertical-divider {
|
||||
width: 1rpx;
|
||||
background: repeating-linear-gradient(
|
||||
to bottom,
|
||||
#C7A26D 0,
|
||||
#C7A26D 4rpx,
|
||||
transparent 4rpx,
|
||||
transparent 8rpx
|
||||
);
|
||||
margin: 0 48rpx 0 0;
|
||||
}
|
||||
|
||||
.unit-section {
|
||||
border: 1rpx solid #f47fef;
|
||||
flex: 1;
|
||||
margin-top: 34rpx;
|
||||
}
|
||||
|
||||
.unit-grid {
|
||||
border: 1rpx solid #f47fef;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.unit-btn {
|
||||
padding: 16rpx 12rpx;
|
||||
color: #A24242;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 134rpx;
|
||||
height: 52rpx;
|
||||
background: #FFF1DD;
|
||||
border: 1rpx solid #A24242;
|
||||
|
||||
&.active {
|
||||
background-color: #A24242;
|
||||
color: #FFF1DD;
|
||||
border-color: #A24242;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -29,6 +29,16 @@
|
|||
@item-click="handleItemClick"
|
||||
ref="enshrinedList"
|
||||
/>
|
||||
<!-- 楼层选择器 -->
|
||||
<view class="floor-selector-container">
|
||||
<FloorSelector
|
||||
ref="floorSelector"
|
||||
:default-floor-id="defaultFloorId"
|
||||
:default-area-id="defaultAreaId"
|
||||
:default-unit-id="defaultUnitId"
|
||||
@selection-change="handleSelectionChange"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<bottom-button
|
||||
title="供奉"
|
||||
|
|
@ -43,6 +53,7 @@ import {CommonEnum} from '@/enum/common.js'
|
|||
import SearchBox from "../../components/search-box/search-box.vue"
|
||||
import StatusDisplay from "../../components/status-display/status-display.vue"
|
||||
import EnshrinedList from "./compositons/enshrinedList.vue"
|
||||
import FloorSelector from "./compositons/floorSelector.vue"
|
||||
import BottomButton from "../../components/bottom-button/bottom-button.vue";
|
||||
|
||||
export default {
|
||||
|
|
@ -50,14 +61,25 @@ export default {
|
|||
BottomButton,
|
||||
SearchBox,
|
||||
StatusDisplay,
|
||||
EnshrinedList
|
||||
EnshrinedList,
|
||||
FloorSelector
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
CommonEnum,
|
||||
searchName: '',
|
||||
loading: false,
|
||||
memorialId: '16' // 默认往生殿ID,可以从路由参数获取
|
||||
memorialId: '16', // 默认往生殿ID,可以从路由参数获取
|
||||
// 楼层选择器默认值
|
||||
defaultFloorId: '',
|
||||
defaultAreaId: '',
|
||||
defaultUnitId: '',
|
||||
// 当前选中的楼层信息
|
||||
currentSelection: {
|
||||
floor: null,
|
||||
area: null,
|
||||
unit: null
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
|
|
@ -100,7 +122,22 @@ export default {
|
|||
title: `查看 ${item.worshiperName} 的供奉记录`,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 处理楼层选择变化
|
||||
handleSelectionChange(selection) {
|
||||
console.log('楼层选择变化:', selection)
|
||||
this.currentSelection = selection
|
||||
|
||||
// 可以根据选中的楼层信息进行相关操作
|
||||
// 例如:根据选中的单元ID查询对应的供奉记录
|
||||
if (selection.unit) {
|
||||
console.log('选中单元:', selection.unit.label, 'ID:', selection.unit.id)
|
||||
// 这里可以触发查询该单元的供奉记录
|
||||
// this.queryEnshrinedByUnit(selection.unit.id)
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -117,7 +154,13 @@ export default {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding: 0 15rpx 40rpx 15rpx;
|
||||
padding-bottom: 40rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.floor-selector-container {
|
||||
margin: 30rpx 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user