添加牌位-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>
|
||||
</view>
|
||||
<picker
|
||||
:range="regionOptions"
|
||||
:value="regionIndex"
|
||||
class="picker"
|
||||
@change="onRegionChange"
|
||||
>
|
||||
<view class="picker" @click="showRegionSelect">
|
||||
<view class="picker-text">
|
||||
{{ regionOptions[regionIndex] || "请选择区域" }}
|
||||
{{ selectedRegionText || "请选择区域" }}
|
||||
</view>
|
||||
</picker>
|
||||
<view class="picker-arrow">></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -78,6 +74,15 @@
|
|||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 区域选择器 -->
|
||||
<u-select
|
||||
v-model="showRegionPicker"
|
||||
:list="regionList"
|
||||
mode="mutil-column-auto"
|
||||
@cancel="onRegionCancel"
|
||||
@confirm="onRegionConfirm"
|
||||
></u-select>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
|
@ -100,9 +105,11 @@ export default {
|
|||
orderNum: "",
|
||||
remark: "",
|
||||
},
|
||||
// 区域选项
|
||||
regionOptions: ["A区", "B区", "C区", "D区"],
|
||||
regionIndex: -1,
|
||||
// 区域相关数据
|
||||
regionList: [], // 区域树形数据
|
||||
showRegionPicker: false, // 控制区域选择器显示
|
||||
selectedRegion: null, // 选中的区域信息
|
||||
selectedRegionText: "", // 选中的区域显示文本
|
||||
// 加载状态
|
||||
loading: false,
|
||||
};
|
||||
|
|
@ -114,10 +121,16 @@ export default {
|
|||
this.deviceInfo.sn &&
|
||||
this.deviceInfo.mac &&
|
||||
this.formData.code.trim() &&
|
||||
this.formData.regionId
|
||||
this.selectedRegion
|
||||
);
|
||||
},
|
||||
},
|
||||
async onLoad() {
|
||||
// 页面加载时获取区域数据
|
||||
await this.loadRegionData();
|
||||
// 尝试从缓存中恢复区域选择
|
||||
this.loadCachedRegion();
|
||||
},
|
||||
methods: {
|
||||
// 扫码获取SN
|
||||
async handleScanCode() {
|
||||
|
|
@ -231,10 +244,114 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
// 区域选择
|
||||
onRegionChange(e) {
|
||||
this.regionIndex = e.detail.value;
|
||||
this.formData.regionId = this.regionOptions[this.regionIndex];
|
||||
// 加载区域数据
|
||||
async loadRegionData() {
|
||||
try {
|
||||
// 从缓存中获取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
|
||||
code: this.formData.code,
|
||||
name: this.formData.name,
|
||||
regionId: this.getRegionId(this.formData.regionId),
|
||||
regionId: this.selectedRegion ? this.selectedRegion.areaId : "",
|
||||
orderNum: this.formData.orderNum || "1",
|
||||
sn: this.deviceInfo.sn,
|
||||
mac: this.deviceInfo.mac,
|
||||
|
|
@ -312,7 +429,7 @@ export default {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!this.formData.regionId) {
|
||||
if (!this.selectedRegion) {
|
||||
uni.showToast({
|
||||
title: "请选择所属区域",
|
||||
icon: "none",
|
||||
|
|
@ -502,6 +619,12 @@ export default {
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
.picker-arrow {
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.textarea {
|
||||
width: 100%;
|
||||
min-height: 120rpx;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user