添加牌位-1
This commit is contained in:
parent
e658ea335b
commit
07040fed26
79
docs/adminMemorial-确认操作说明.md
Normal file
79
docs/adminMemorial-确认操作说明.md
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
## adminMemorial 确认操作说明
|
||||||
|
|
||||||
|
本文档说明在 `pages/memorial/adminMemorial.vue` 中新增的确认封装与其使用方式。
|
||||||
|
|
||||||
|
### 目的
|
||||||
|
- 在高风险操作(全部开启、全部关闭、强制开启、强制关闭、时长归零)前弹出确认,避免误触。
|
||||||
|
- 通过 Promise 封装让调用处可以使用 async/await,编写更清晰的顺序代码。
|
||||||
|
|
||||||
|
### 核心封装:confirmAction
|
||||||
|
```javascript
|
||||||
|
// 确认提示封装,返回是否确认
|
||||||
|
async function confirmAction(message) {
|
||||||
|
const res = await new Promise((resolve) => {
|
||||||
|
uni.showModal({
|
||||||
|
title: "确认操作",
|
||||||
|
content: message,
|
||||||
|
confirmText: "确认",
|
||||||
|
cancelText: "取消",
|
||||||
|
success: (r) => resolve(r),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return !!(res && res.confirm);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 为何需要 Promise 包装
|
||||||
|
- `uni.showModal` 使用回调(success/fail),不能直接 `await`。
|
||||||
|
- 用 `new Promise` 将回调转换为 Promise,调用方即可:
|
||||||
|
```javascript
|
||||||
|
const ok = await confirmAction("确定要全部关闭吗?");
|
||||||
|
if (!ok) return; // 用户取消则中断后续流程
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关于 `!!(res && res.confirm)`
|
||||||
|
- `res && res.confirm`:若存在回调结果再读取 `confirm`,否则为 `false`。
|
||||||
|
- `!!value`:将任意值强制转为布尔,等价 `Boolean(value)`。
|
||||||
|
- 语义:仅当用户点击“确认”时返回 `true`,其他情况均为 `false`。
|
||||||
|
|
||||||
|
### 已接入的高风险操作
|
||||||
|
- `handleAllOpen`:全部开启
|
||||||
|
- `handleAllClose`:全部关闭
|
||||||
|
- `handleForceOpen`:强制开启(需选中单元)
|
||||||
|
- `handleForceClose`:强制关闭(需选中单元)
|
||||||
|
- `handleResetDuration`:时长归零(需选中单元)
|
||||||
|
|
||||||
|
接入方式统一如下(示例):
|
||||||
|
```javascript
|
||||||
|
const ok = await this.confirmAction("确定要全部开启吗?");
|
||||||
|
if (!ok) return;
|
||||||
|
// 继续调用接口
|
||||||
|
```
|
||||||
|
|
||||||
|
### 可定制项(如需)
|
||||||
|
- 通过 `uni.showModal` 的参数可定制:
|
||||||
|
- `title`:标题
|
||||||
|
- `content`:正文
|
||||||
|
- `showCancel`:是否显示取消按钮
|
||||||
|
- `confirmText` / `cancelText`:按钮文案
|
||||||
|
- `confirmColor` / `cancelColor`:按钮颜色
|
||||||
|
|
||||||
|
若需要让“取消”成为更显眼的默认选择,可调整按钮文案与颜色,或在交互上将危险操作改为二次输入确认。
|
||||||
|
|
||||||
|
### 错误处理(可选增强)
|
||||||
|
如需捕获弹窗失败(极少见),可在封装中补充 `fail` 并 `reject(err)`,调用方用 `try/catch` 处理:
|
||||||
|
```javascript
|
||||||
|
try {
|
||||||
|
const ok = await confirmAction("确定继续吗?");
|
||||||
|
if (!ok) return;
|
||||||
|
// ...
|
||||||
|
} catch (e) {
|
||||||
|
// 统一错误上报或提示
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
71
docs/memorialHall-扫码导航修复说明.md
Normal file
71
docs/memorialHall-扫码导航修复说明.md
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
# memorialHall 扫码导航修复说明
|
||||||
|
|
||||||
|
## 问题描述
|
||||||
|
用户通过扫码直接进入 `memorialHall.vue` 页面时,如果没有上一页(即页面栈中只有当前页面),点击返回按钮会卡在当前页面,无法正常返回。
|
||||||
|
|
||||||
|
## 解决方案
|
||||||
|
|
||||||
|
### 1. 导入路由工具函数
|
||||||
|
在 `memorialHall.vue` 中导入 `navigateBack` 函数:
|
||||||
|
```javascript
|
||||||
|
import { navigateBack } from "../../utils/router.js";
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 监听导航栏返回事件
|
||||||
|
为自定义导航栏添加 `@back` 事件监听:
|
||||||
|
```vue
|
||||||
|
<custom-navbar ref="customNavbar" title="往生大殿" @back="handleNavbarBack" />
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 实现返回处理方法
|
||||||
|
添加 `handleNavbarBack` 方法,使用 `navigateBack` 函数处理返回逻辑:
|
||||||
|
```javascript
|
||||||
|
// 处理导航栏返回事件
|
||||||
|
handleNavbarBack() {
|
||||||
|
// 使用路由工具函数,如果没有上一页会自动跳转到首页
|
||||||
|
navigateBack();
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 优化自定义导航栏组件
|
||||||
|
修改 `custom-navbar.vue` 的 `handleBack` 方法,支持父组件完全控制返回逻辑:
|
||||||
|
```javascript
|
||||||
|
handleBack() {
|
||||||
|
if (this.showBack) {
|
||||||
|
// 触发自定义事件,让父组件处理返回逻辑
|
||||||
|
this.$emit("back");
|
||||||
|
// 如果父组件没有监听 back 事件,则执行默认返回逻辑
|
||||||
|
if (!this.$listeners.back) {
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1,
|
||||||
|
fail: () => {
|
||||||
|
// 如果没有上一页,跳转到首页
|
||||||
|
uni.switchTab({
|
||||||
|
url: "/pages/index/index",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
## 工作原理
|
||||||
|
|
||||||
|
1. **路由工具函数**:`navigateBack` 函数会先尝试 `uni.navigateBack`,如果失败(没有上一页),会自动调用 `reLaunchToPage("index")` 跳转到首页。
|
||||||
|
|
||||||
|
2. **事件驱动**:自定义导航栏通过 `@back` 事件将返回控制权交给父组件,父组件可以使用自己的返回逻辑。
|
||||||
|
|
||||||
|
3. **向下兼容**:如果父组件没有监听 `@back` 事件,导航栏组件会执行默认的返回逻辑,确保不会破坏现有功能。
|
||||||
|
|
||||||
|
## 测试场景
|
||||||
|
|
||||||
|
- ✅ 正常页面跳转后返回(有上一页)
|
||||||
|
- ✅ 扫码直接进入后返回(无上一页,自动跳转首页)
|
||||||
|
- ✅ 其他页面使用自定义导航栏(向下兼容)
|
||||||
|
|
||||||
|
## 相关文件
|
||||||
|
|
||||||
|
- `pages/memorial/memorialHall.vue` - 主要修改页面
|
||||||
|
- `components/custom-navbar/custom-navbar.vue` - 导航栏组件优化
|
||||||
|
- `utils/router.js` - 路由工具函数(已存在)
|
||||||
|
|
@ -53,16 +53,12 @@
|
||||||
>所属区域
|
>所属区域
|
||||||
<text class="required">*</text>
|
<text class="required">*</text>
|
||||||
</view>
|
</view>
|
||||||
<picker
|
<view class="picker" @click="showRegionSelect">
|
||||||
:range="regionOptions"
|
|
||||||
:value="regionIndex"
|
|
||||||
class="picker"
|
|
||||||
@change="onRegionChange"
|
|
||||||
>
|
|
||||||
<view class="picker-text">
|
<view class="picker-text">
|
||||||
{{ regionOptions[regionIndex] || "请选择区域" }}
|
{{ selectedRegionText || "请选择区域" }}
|
||||||
</view>
|
</view>
|
||||||
</picker>
|
<view class="picker-arrow">></view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -78,6 +74,15 @@
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 区域选择器 -->
|
||||||
|
<u-select
|
||||||
|
v-model="showRegionPicker"
|
||||||
|
:list="regionList"
|
||||||
|
mode="mutil-column-auto"
|
||||||
|
@cancel="onRegionCancel"
|
||||||
|
@confirm="onRegionConfirm"
|
||||||
|
></u-select>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -100,9 +105,11 @@ export default {
|
||||||
orderNum: "",
|
orderNum: "",
|
||||||
remark: "",
|
remark: "",
|
||||||
},
|
},
|
||||||
// 区域选项
|
// 区域相关数据
|
||||||
regionOptions: ["A区", "B区", "C区", "D区"],
|
regionList: [], // 区域树形数据
|
||||||
regionIndex: -1,
|
showRegionPicker: false, // 控制区域选择器显示
|
||||||
|
selectedRegion: null, // 选中的区域信息
|
||||||
|
selectedRegionText: "", // 选中的区域显示文本
|
||||||
// 加载状态
|
// 加载状态
|
||||||
loading: false,
|
loading: false,
|
||||||
};
|
};
|
||||||
|
|
@ -114,10 +121,16 @@ export default {
|
||||||
this.deviceInfo.sn &&
|
this.deviceInfo.sn &&
|
||||||
this.deviceInfo.mac &&
|
this.deviceInfo.mac &&
|
||||||
this.formData.code.trim() &&
|
this.formData.code.trim() &&
|
||||||
this.formData.regionId
|
this.selectedRegion
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
async onLoad() {
|
||||||
|
// 页面加载时获取区域数据
|
||||||
|
await this.loadRegionData();
|
||||||
|
// 尝试从缓存中恢复区域选择
|
||||||
|
this.loadCachedRegion();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 扫码获取SN
|
// 扫码获取SN
|
||||||
async handleScanCode() {
|
async handleScanCode() {
|
||||||
|
|
@ -231,10 +244,114 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 区域选择
|
// 加载区域数据
|
||||||
onRegionChange(e) {
|
async loadRegionData() {
|
||||||
this.regionIndex = e.detail.value;
|
try {
|
||||||
this.formData.regionId = this.regionOptions[this.regionIndex];
|
// 从缓存中获取templeId,如果没有则使用默认值
|
||||||
|
const templeId = uni.getStorageSync("templeId") || "12";
|
||||||
|
|
||||||
|
const res = await this.$request.get(`/bst/region/listTree/${templeId}`);
|
||||||
|
|
||||||
|
if (res && res.data) {
|
||||||
|
// 转换数据格式为u-select需要的格式
|
||||||
|
this.regionList = this.transformRegionData(res.data);
|
||||||
|
console.log("区域数据加载成功:", this.regionList);
|
||||||
|
} else {
|
||||||
|
throw new Error("获取区域数据失败");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("加载区域数据失败:", error);
|
||||||
|
uni.showToast({
|
||||||
|
title: "加载区域数据失败",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 转换区域数据格式
|
||||||
|
transformRegionData(data) {
|
||||||
|
if (!data || !data.children) return [];
|
||||||
|
|
||||||
|
return data.children.map((floor) => ({
|
||||||
|
label: floor.label,
|
||||||
|
value: floor.id,
|
||||||
|
children: floor.children
|
||||||
|
? floor.children.map((area) => ({
|
||||||
|
label: area.label,
|
||||||
|
value: area.id,
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
// 显示区域选择器
|
||||||
|
showRegionSelect() {
|
||||||
|
if (this.regionList.length === 0) {
|
||||||
|
uni.showToast({
|
||||||
|
title: "区域数据加载中,请稍后",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.showRegionPicker = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 区域选择确认
|
||||||
|
onRegionConfirm(e) {
|
||||||
|
console.log("区域选择结果:", e);
|
||||||
|
if (e && e.length >= 2) {
|
||||||
|
const [floorIndex, areaIndex] = e;
|
||||||
|
const floor = this.regionList[floorIndex];
|
||||||
|
const area = floor.children[areaIndex];
|
||||||
|
|
||||||
|
this.selectedRegion = {
|
||||||
|
floorId: floor.value,
|
||||||
|
floorName: floor.label,
|
||||||
|
areaId: area.value,
|
||||||
|
areaName: area.label,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.selectedRegionText = `${floor.label} - ${area.label}`;
|
||||||
|
this.formData.regionId = area.value;
|
||||||
|
|
||||||
|
// 缓存区域选择
|
||||||
|
this.cacheRegionSelection();
|
||||||
|
|
||||||
|
uni.showToast({
|
||||||
|
title: "区域选择成功",
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 区域选择取消
|
||||||
|
onRegionCancel() {
|
||||||
|
this.showRegionPicker = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 缓存区域选择
|
||||||
|
cacheRegionSelection() {
|
||||||
|
if (this.selectedRegion) {
|
||||||
|
uni.setStorageSync("lastSelectedRegion", this.selectedRegion);
|
||||||
|
uni.setStorageSync("lastSelectedRegionText", this.selectedRegionText);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 从缓存加载区域选择
|
||||||
|
loadCachedRegion() {
|
||||||
|
try {
|
||||||
|
const cachedRegion = uni.getStorageSync("lastSelectedRegion");
|
||||||
|
const cachedRegionText = uni.getStorageSync("lastSelectedRegionText");
|
||||||
|
|
||||||
|
if (cachedRegion && cachedRegionText) {
|
||||||
|
this.selectedRegion = cachedRegion;
|
||||||
|
this.selectedRegionText = cachedRegionText;
|
||||||
|
this.formData.regionId = cachedRegion.areaId;
|
||||||
|
console.log("已恢复缓存的区域选择:", cachedRegion);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("加载缓存区域失败:", error);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 取消操作
|
// 取消操作
|
||||||
|
|
@ -265,7 +382,7 @@ export default {
|
||||||
id: this.deviceInfo.id, // 使用设备ID
|
id: this.deviceInfo.id, // 使用设备ID
|
||||||
code: this.formData.code,
|
code: this.formData.code,
|
||||||
name: this.formData.name,
|
name: this.formData.name,
|
||||||
regionId: this.getRegionId(this.formData.regionId),
|
regionId: this.selectedRegion ? this.selectedRegion.areaId : "",
|
||||||
orderNum: this.formData.orderNum || "1",
|
orderNum: this.formData.orderNum || "1",
|
||||||
sn: this.deviceInfo.sn,
|
sn: this.deviceInfo.sn,
|
||||||
mac: this.deviceInfo.mac,
|
mac: this.deviceInfo.mac,
|
||||||
|
|
@ -312,7 +429,7 @@ export default {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.formData.regionId) {
|
if (!this.selectedRegion) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: "请选择所属区域",
|
title: "请选择所属区域",
|
||||||
icon: "none",
|
icon: "none",
|
||||||
|
|
@ -502,6 +619,12 @@ export default {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.picker-arrow {
|
||||||
|
color: #999;
|
||||||
|
font-size: 24rpx;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
.textarea {
|
.textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 120rpx;
|
min-height: 120rpx;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user