Compare commits
7 Commits
82b287dd92
...
388599e840
| Author | SHA1 | Date |
|---|---|---|
|
|
388599e840 | |
|
|
d0e47266da | |
|
|
cc6dec3970 | |
|
|
8af15703f0 | |
|
|
3ffdce0ec5 | |
|
|
a87ad4ea7a | |
|
|
4809682076 |
|
|
@ -0,0 +1,23 @@
|
||||||
|
import request from '@/api/http/client'
|
||||||
|
|
||||||
|
// 后端就绪后置为 false 即可恢复真实请求。
|
||||||
|
const USE_MOCK = true
|
||||||
|
|
||||||
|
// 模拟场景列表数据(后端 /scene/list 就绪后删除)。
|
||||||
|
const MOCK_SCENES = [
|
||||||
|
{ id: 1, name: '家里' },
|
||||||
|
{ id: 2, name: '养老院' },
|
||||||
|
{ id: 3, name: '社区中心' }
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取场景列表。
|
||||||
|
* 约定:data 为数组,每项至少含 { id, name },多余字段不影响前端。
|
||||||
|
*/
|
||||||
|
export function getSceneList() {
|
||||||
|
if (USE_MOCK) {
|
||||||
|
// 模拟网络延迟,让 loading 态可见。
|
||||||
|
return new Promise((resolve) => setTimeout(() => resolve(MOCK_SCENES), 500))
|
||||||
|
}
|
||||||
|
return request.get('/scene/list')
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,8 @@ export const ROUTES = Object.freeze({
|
||||||
EVENT: '/pages/event/index',
|
EVENT: '/pages/event/index',
|
||||||
MINE: '/pages/mine/index',
|
MINE: '/pages/mine/index',
|
||||||
DEVICE_ADD: '/pages/device/add',
|
DEVICE_ADD: '/pages/device/add',
|
||||||
DEVICE_CONFIG: '/pages/device/config'
|
DEVICE_CONFIG: '/pages/device/config',
|
||||||
|
SCENE_SELECT: '/pages/scene/select'
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,12 @@
|
||||||
"style": {
|
"style": {
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/scene/select",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@
|
||||||
@click="goConfig"
|
@click="goConfig"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<view class="site-row" @click="goConfig">
|
<view class="site-row" @click="goSceneSelect">
|
||||||
<view class="site-left">
|
<view class="site-left">
|
||||||
<up-icon name="list" size="18" color="#26c996" />
|
<up-icon name="list" size="18" color="#26c996" />
|
||||||
<text class="site-text">请选择场所</text>
|
<text class="site-text">{{ sceneName || '请选择场所' }}</text>
|
||||||
</view>
|
</view>
|
||||||
<up-icon name="arrow-right" size="14" color="#26c996" />
|
<up-icon name="arrow-right" size="14" color="#26c996" />
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -33,8 +33,8 @@
|
||||||
<up-empty mode="list" text="暂无数据" />
|
<up-empty mode="list" text="暂无数据" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="fab-wrap">
|
<view class="fab-wrap" @click="goAdd">
|
||||||
<up-button type="success" shape="circle" text="添加设备" @click="goAdd" />
|
<up-icon name="plus" color="#ffffff" size="28" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -42,14 +42,28 @@
|
||||||
<script>
|
<script>
|
||||||
import { ROUTES } from '@/constants/routes'
|
import { ROUTES } from '@/constants/routes'
|
||||||
import { navigateTo } from '@/utils/navigation'
|
import { navigateTo } from '@/utils/navigation'
|
||||||
|
import { getCurrentScene } from '@/store/scene'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
noticeText: '点击选择场所后可进入设备配置流程'
|
noticeText: '点击选择场所后可进入设备配置流程',
|
||||||
|
sceneName: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onShow() {
|
||||||
|
this.refreshScene()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 从全局场景状态刷新回显文案。
|
||||||
|
refreshScene() {
|
||||||
|
const scene = getCurrentScene()
|
||||||
|
this.sceneName = scene ? scene.name : ''
|
||||||
|
},
|
||||||
|
// 进入场景选择页。
|
||||||
|
goSceneSelect() {
|
||||||
|
navigateTo(ROUTES.SCENE_SELECT)
|
||||||
|
},
|
||||||
// 进入设备添加页(后续会承接蓝牙配网流程入口)。
|
// 进入设备添加页(后续会承接蓝牙配网流程入口)。
|
||||||
goAdd() {
|
goAdd() {
|
||||||
navigateTo(ROUTES.DEVICE_ADD)
|
navigateTo(ROUTES.DEVICE_ADD)
|
||||||
|
|
@ -67,7 +81,6 @@ export default {
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-bottom: 180rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.banner {
|
.banner {
|
||||||
|
|
@ -139,8 +152,19 @@ export default {
|
||||||
|
|
||||||
.fab-wrap {
|
.fab-wrap {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 32rpx;
|
right: 40rpx;
|
||||||
bottom: 220rpx;
|
bottom: 60rpx;
|
||||||
width: 240rpx;
|
width: 112rpx;
|
||||||
|
height: 112rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(135deg, #1fca97 0%, #2dbf9c 100%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 8rpx 24rpx rgba(31, 202, 151, 0.4);
|
||||||
|
/* 点击态缩放反馈 */
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.92);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
<!-- 场景选择页:加载场景列表,点选后保存并返回首页 -->
|
||||||
|
<template>
|
||||||
|
<view class="page page-base">
|
||||||
|
<up-navbar title="选择场所" :fixed="false" :safe-area-inset-top="true" :border="false" />
|
||||||
|
|
||||||
|
<view v-if="loading" class="state-wrap">
|
||||||
|
<up-loading-icon mode="circle" size="48" text="加载中..." />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-else-if="loadError" class="state-wrap">
|
||||||
|
<up-empty mode="wifi" text="加载失败,请检查网络" />
|
||||||
|
<up-button type="success" shape="circle" text="重试" class="retry-btn" @click="loadScenes" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-else-if="sceneList.length === 0" class="state-wrap">
|
||||||
|
<up-empty mode="list" text="暂无场景" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-else class="scene-list">
|
||||||
|
<view
|
||||||
|
v-for="scene in sceneList"
|
||||||
|
:key="scene.id"
|
||||||
|
class="scene-item"
|
||||||
|
:class="{ 'scene-item--active': scene.id === currentSceneId }"
|
||||||
|
@click="selectScene(scene)"
|
||||||
|
>
|
||||||
|
<text class="scene-name">{{ scene.name }}</text>
|
||||||
|
<up-icon
|
||||||
|
:name="scene.id === currentSceneId ? 'checkmark' : 'arrow-right'"
|
||||||
|
:size="scene.id === currentSceneId ? '16' : '14'"
|
||||||
|
:color="scene.id === currentSceneId ? '#26c996' : '#c0c4cc'"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getSceneList } from '@/api/scene'
|
||||||
|
import { getCurrentScene, setCurrentScene } from '@/store/scene'
|
||||||
|
import { navigateBack } from '@/utils/navigation'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
loadError: false,
|
||||||
|
sceneList: [],
|
||||||
|
currentSceneId: getCurrentScene()?.id ?? null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.loadScenes()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 拉取场景列表;失败时切换错误态供重试,toast 由请求封装统一弹出。
|
||||||
|
async loadScenes() {
|
||||||
|
this.loading = true
|
||||||
|
this.loadError = false
|
||||||
|
try {
|
||||||
|
const data = await getSceneList()
|
||||||
|
this.sceneList = Array.isArray(data) ? data : []
|
||||||
|
} catch (error) {
|
||||||
|
this.loadError = true
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 选中场景:保存后返回,首页 onShow 回显。
|
||||||
|
selectScene(scene) {
|
||||||
|
setCurrentScene(scene)
|
||||||
|
navigateBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '@/styles/common.css';
|
||||||
|
|
||||||
|
.state-wrap {
|
||||||
|
margin-top: 120rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.retry-btn {
|
||||||
|
margin-top: 40rpx;
|
||||||
|
width: 240rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-list {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-item {
|
||||||
|
height: 104rpx;
|
||||||
|
padding: 0 32rpx;
|
||||||
|
margin-bottom: 2rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-item--active {
|
||||||
|
background: #e9fff3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-name {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #222;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-item--active .scene-name {
|
||||||
|
color: #26c996;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
* 当前场景全局状态:内存 + uni.storage 持久化。
|
||||||
|
* 项目未引入 Vuex/Pinia,采用轻量模块方案。
|
||||||
|
*/
|
||||||
|
const STORAGE_KEY = 'current_scene'
|
||||||
|
|
||||||
|
let currentScene = null
|
||||||
|
|
||||||
|
// 模块加载时从本地存储恢复上次选中的场景。
|
||||||
|
function initFromStorage() {
|
||||||
|
const cached = uni.getStorageSync(STORAGE_KEY)
|
||||||
|
if (cached && cached.id !== undefined) {
|
||||||
|
currentScene = cached
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initFromStorage()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前选中场景。
|
||||||
|
* @returns {{ id: *, name: string } | null}
|
||||||
|
*/
|
||||||
|
export function getCurrentScene() {
|
||||||
|
return currentScene
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前场景并持久化(仅保留 id/name,避免后端多余字段进缓存)。
|
||||||
|
* @param {{ id: *, name: string }} scene
|
||||||
|
*/
|
||||||
|
export function setCurrentScene(scene) {
|
||||||
|
currentScene = { id: scene.id, name: scene.name }
|
||||||
|
uni.setStorageSync(STORAGE_KEY, currentScene)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除当前场景(本地与持久化均清除)。
|
||||||
|
*/
|
||||||
|
export function clearCurrentScene() {
|
||||||
|
currentScene = null
|
||||||
|
uni.removeStorageSync(STORAGE_KEY)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue