buddhism/pages/memorial/adminMemorial.vue

565 lines
16 KiB
Vue
Raw Normal View History

<template>
2025-10-14 15:48:58 +08:00
<view class="page">
<base-background />
<!-- 使用自定义导航栏组件 -->
<custom-navbar ref="customNavbar" title="牌位管理" />
<view class="header">
<!-- 状态展示 -->
<status-display v-if="loading" loading-text="加载中..." type="loading" />
<!-- 状态栏 -->
<StatusBar
v-if="selectedUnitId"
ref="statusBar"
:unit-id="selectedUnitId"
@view-details="handleViewDetails"
/>
<!-- 楼层选择器 -->
<view class="floor-selector-container">
<FloorSelector
ref="floorSelector"
:default-area-id="defaultAreaId"
:default-floor-id="defaultFloorId"
:default-unit-id="defaultUnitId"
@selection-change="handleSelectionChange"
/>
</view>
</view>
<view class="bottom">
<view class="btn-grid">
2025-10-14 16:43:15 +08:00
<view class="grid-btn" @click="handleAllOpen">全部开启</view>
<view class="grid-btn" @click="handleAllClose">全部关闭</view>
2025-10-14 15:48:58 +08:00
<view class="grid-btn" @click="handleForceOpen">强制开启</view>
<view class="grid-btn" @click="handleForceClose">强制关闭</view>
<view class="grid-btn" @click="handleResetDuration">时长归零</view>
<view class="grid-btn" @click="handleIncreaseDuration">增加时长</view>
2025-10-15 16:49:36 +08:00
<view class="grid-btn" @click="handleSearchMemorial">寻找牌位</view>
2025-11-25 11:13:46 +08:00
<view class="grid-btn" @click="handleAddMemorial">添加牌位</view>
<!-- <view class="grid-btn add-memorial-btn" @click="handleAddMemorial"-->
<!-- >添加牌位-->
<!-- </view>-->
2025-11-19 17:58:14 +08:00
<view class="grid-btn" @click="handleNfcPairing">NFC 配对</view>
2025-10-14 15:48:58 +08:00
</view>
</view>
</view>
</template>
2025-10-14 15:48:58 +08:00
<script>
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/enshrinedListIndex.vue";
import FloorSelector from "./compositons/floorSelector.vue";
import StatusBar from "./compositons/statusBar.vue";
// import BottomButton from "../../components/bottom-button/bottom-button.vue";
export default {
components: {
// BottomButton,
SearchBox,
StatusDisplay,
EnshrinedList,
FloorSelector,
StatusBar,
},
data() {
return {
CommonEnum,
searchName: "",
loading: false,
memorialId: "16", // 默认往生殿ID可以从路由参数获取
// 楼层选择器默认值
defaultFloorId: "",
defaultAreaId: "",
defaultUnitId: "",
// 当前选中的楼层信息
currentSelection: {
floor: null,
area: null,
unit: null,
},
// 当前选中的单元ID用于状态栏查询
selectedUnitId: "",
};
},
onLoad(options) {
// 从路由参数获取往生殿ID
if (options.id) {
this.memorialId = options.id;
}
this.initPage();
},
onShow() {
// 返回该页面时,刷新状态栏数据,避免与供奉页操作不一致
if (
this.selectedUnitId &&
this.$refs.statusBar &&
typeof this.$refs.statusBar.loadUnitData === "function"
) {
this.$refs.statusBar.loadUnitData(this.selectedUnitId);
}
2025-10-17 11:28:16 +08:00
this.$refs.floorSelector.loadTreeData();
2025-10-14 15:48:58 +08:00
},
methods: {
// 校验是否已选择单元
ensureUnitSelected() {
if (!this.selectedUnitId) {
uni.showToast({ title: "请先选择单元", icon: "none" });
return false;
}
return true;
},
2025-10-15 17:11:04 +08:00
// 确认提示封装,返回是否确认
async confirmAction(message) {
const res = await new Promise((resolve) => {
uni.showModal({
title: "确认操作",
content: message,
confirmText: "确认",
cancelText: "取消",
success: (r) => resolve(r),
});
});
return !!(res && res.confirm);
},
// 通用 PUT 请求封装:包含 Loading 与结果提示
async performPut(url, data, logTag = "performPut") {
uni.showLoading({ title: "处理中...", mask: true });
2025-10-14 15:48:58 +08:00
try {
const res = await this.$request.put(url, data);
2025-10-14 15:48:58 +08:00
if (res && (res.code === 200 || res.status === 200)) {
uni.showToast({ title: res.msg || "操作成功", icon: "success" });
} else {
2025-10-14 16:43:15 +08:00
uni.showToast({
title: (res && res.msg) || "操作失败",
icon: "none",
});
2025-10-14 15:48:58 +08:00
}
return res;
2025-10-14 15:48:58 +08:00
} catch (error) {
uni.showToast({ title: "请求失败", icon: "none" });
console.error(`${logTag} error`, error);
throw error;
} finally {
uni.hideLoading();
2025-10-14 15:48:58 +08:00
}
},
2025-10-14 17:54:52 +08:00
// 统一构建网关命令负载
buildGatewayPayload(command, reason) {
// 使用子组件提供的 getCurrentSelection 获取最新的楼层信息
let selection = this.currentSelection;
if (
this.$refs.floorSelector &&
typeof this.$refs.floorSelector.getCurrentSelection === "function"
) {
selection = this.$refs.floorSelector.getCurrentSelection();
}
const floorId = selection?.floor?.label;
if (!floorId) {
uni.showToast({ title: "请先选择楼层", icon: "none" });
return false;
}
console.log("floodr", floorId);
2025-10-15 16:49:36 +08:00
let templeId = uni.getStorageSync("templeId");
2025-10-14 17:54:52 +08:00
return {
// 兼容字段:同时传 floorId 与后端现用的 regionId
// regionId: String(floorId),
2025-10-15 16:49:36 +08:00
templeId: templeId,
2025-10-14 17:54:52 +08:00
command, // open | close
2025-10-23 17:48:08 +08:00
mac: "000000000000",
2025-10-14 17:54:52 +08:00
timeout: "11",
reason,
};
},
2025-10-14 16:43:15 +08:00
// 选择单位并输入时长
async promptDurationAndUnit() {
// 1:天 2:小时 3:分钟 4:秒
const unitOptions = [
{ name: "天", value: "1" },
{ name: "小时", value: "2" },
{ name: "分钟", value: "3" },
{ name: "秒", value: "4" },
];
// 先选择单位
const unitRes = await new Promise((resolve, reject) => {
uni.showActionSheet({
itemList: unitOptions.map((o) => o.name),
success: (res) => resolve(res),
fail: (err) => reject(err),
});
});
const chosen = unitOptions[unitRes.tapIndex];
// 再输入时长数值(支持小数)
const inputRes = await new Promise((resolve) => {
uni.showModal({
title: `输入时长(单位:${chosen.name}`,
editable: true,
placeholderText: "请输入时长数值:",
success: (res) => resolve(res),
});
});
if (!inputRes || !inputRes.confirm) {
throw new Error("UserCancelled");
}
const value = String((inputRes.content || "").trim());
// 基础校验:数字与小数
if (!/^\d+(\.\d+)?$/.test(value)) {
uni.showToast({ title: "请输入有效的数字", icon: "none" });
throw new Error("InvalidNumber");
}
return { amount: value, unit: chosen.value };
},
2025-10-15 16:49:36 +08:00
// 输入寻找牌位所需参数:闪烁类型 与 超时时间
async promptSearchParams() {
// 输入闪烁类型(后端自定义字符串/代码)
const typeRes = await new Promise((resolve) => {
uni.showModal({
title: "输入闪烁类型",
editable: true,
placeholderText: "请输入类型代码或名称",
success: (res) => resolve(res),
});
});
if (!typeRes || !typeRes.confirm) {
throw new Error("UserCancelled");
}
const type = String((typeRes.content || "").trim());
if (!type) {
uni.showToast({ title: "闪烁类型不能为空", icon: "none" });
throw new Error("InvalidType");
}
return { type };
},
2025-10-14 16:43:15 +08:00
async handleAllOpen() {
2025-10-15 17:11:04 +08:00
const ok = await this.confirmAction("确定要全部开启吗?");
if (!ok) return;
2025-10-14 17:54:52 +08:00
const payload = this.buildGatewayPayload("open", "全开");
await this.performPut(
`/app/memorial/sendCommandGateway`,
payload,
"handleAllOpen",
);
},
async handleAllClose() {
2025-10-15 17:11:04 +08:00
const ok = await this.confirmAction("确定要全部关闭吗?");
if (!ok) return;
2025-10-14 17:54:52 +08:00
const payload = this.buildGatewayPayload("close", "全关");
2025-10-14 16:43:15 +08:00
await this.performPut(
`/app/memorial/sendCommandGateway`,
2025-10-14 17:54:52 +08:00
payload,
"handleAllClose",
2025-10-14 16:43:15 +08:00
);
},
// 底部按钮:强制开启
async handleForceOpen() {
if (!this.ensureUnitSelected()) return;
2025-10-16 16:23:01 +08:00
const ok = await this.confirmAction("确定要强制开启该牌位吗?");
2025-10-15 17:11:04 +08:00
if (!ok) return;
2025-10-14 16:43:15 +08:00
await this.performPut(
`/bst/memorial/open/${this.selectedUnitId}`,
null,
"handleForceOpen",
);
},
2025-10-14 15:48:58 +08:00
// 底部按钮:强制关闭
async handleForceClose() {
if (!this.ensureUnitSelected()) return;
2025-10-16 16:23:01 +08:00
const ok = await this.confirmAction("确定要强制关闭该牌位吗?");
2025-10-15 17:11:04 +08:00
if (!ok) return;
2025-10-14 16:43:15 +08:00
await this.performPut(
`/bst/memorial/close/${this.selectedUnitId}`,
null,
"handleForceClose",
);
2025-10-14 15:48:58 +08:00
},
// 底部按钮:时长归零
async handleResetDuration() {
if (!this.ensureUnitSelected()) return;
2025-10-16 16:23:01 +08:00
const ok = await this.confirmAction("确定要将该牌位时长归零吗?");
2025-10-15 17:11:04 +08:00
if (!ok) return;
2025-10-14 16:43:15 +08:00
await this.performPut(
`/bst/memorial/reset/${this.selectedUnitId}`,
null,
"handleResetDuration",
);
2025-10-14 15:48:58 +08:00
},
2025-10-15 16:49:36 +08:00
// 底部按钮:寻找牌位(闪烁)
async handleSearchMemorial() {
if (!this.ensureUnitSelected()) return;
try {
2025-10-16 14:23:11 +08:00
// const { type } = await this.promptSearchParams();
2025-10-15 16:49:36 +08:00
const payload = {
memorialId: String(this.selectedUnitId),
2025-11-25 11:51:00 +08:00
// type: "3",
// timeout: "11",
2025-10-15 16:49:36 +08:00
};
await this.performPut(
2025-11-25 11:51:00 +08:00
`/app/memorial/searchMemorail/${this.selectedUnitId}`,
// payload,
// "handleSearchMemorial",
2025-10-15 16:49:36 +08:00
);
} catch (e) {
if (
e &&
e.message !== "UserCancelled" &&
e.message !== "InvalidNumber" &&
e.message !== "InvalidType"
) {
console.error("handleSearchMemorial prompt error", e);
}
}
},
2025-10-14 15:48:58 +08:00
// 底部按钮:增加时长
async handleIncreaseDuration() {
if (!this.ensureUnitSelected()) return;
2025-10-14 16:43:15 +08:00
try {
const { amount, unit } = await this.promptDurationAndUnit();
const payload = {
memorialId: String(this.selectedUnitId),
seconds: amount,
unit,
};
await this.performPut(
`/bst/memorial/addTime`,
payload,
"handleIncreaseDuration",
);
} catch (e) {
// 用户取消或输入无效时,不再抛出
if (
e &&
e.message !== "UserCancelled" &&
e.message !== "InvalidNumber"
) {
console.error("handleIncreaseDuration prompt error", e);
}
}
2025-10-14 15:48:58 +08:00
},
// 初始化页面
async initPage() {
this.loading = true;
try {
// 页面初始化逻辑
console.log("往生殿页面初始化ID:", this.memorialId);
} catch (error) {
console.error("页面初始化失败:", error);
uni.showToast({
title: "页面加载失败",
icon: "none",
});
} finally {
this.loading = false;
}
},
// 处理搜索
handleSearch(value) {
console.log("搜索内容:", value);
this.searchName = value;
// 跳转到往生者搜索页面并传递搜索关键词
uni.navigateTo({
url: `/pages/memorial/deceasedSearch?keyword=${encodeURIComponent(value)}`,
success: () => {
console.log("跳转到搜索页面成功");
},
fail: (error) => {
console.error("跳转失败:", error);
uni.showToast({
title: "页面跳转失败",
icon: "none",
});
},
});
},
// 处理列表项点击
handleItemClick(item) {
console.log("点击供奉记录:", item);
// 可以跳转到详情页或执行其他操作
uni.showToast({
title: `查看 ${item.worshiperName} 的供奉记录`,
icon: "none",
});
},
// 处理楼层选择变化
handleSelectionChange(selection) {
console.log("楼层选择变化:", selection);
this.currentSelection = selection;
// 当选中单元时更新selectedUnitId触发状态栏查询
if (selection.unit) {
console.log(
"选中单元:",
selection.unit.label,
"ID:",
selection.unit.id,
);
this.selectedUnitId = selection.unit.id;
} else {
// 如果没有选中单元,清空状态栏
this.selectedUnitId = "";
}
},
// 跳转到往生大殿页面的通用方法
navigateToMemorialHall(unitId) {
console.log("跳转到往生大殿页面ID:", unitId);
uni.navigateTo({
url: `/pages/memorial/memorialHall?id=${unitId}`,
success: () => {
console.log("跳转成功");
},
fail: (error) => {
console.error("跳转失败:", error);
uni.showToast({
title: "页面跳转失败",
icon: "none",
});
},
});
},
// 处理查看详情
handleViewDetails(unitData) {
console.log("查看单元详情:", unitData);
this.navigateToMemorialHall(unitData.id);
},
// 提交供奉 - 跳转到往生大殿页面
submitPrayer() {
console.log("提交供奉跳转到往生大殿页面ID:", this.selectedUnitId);
this.navigateToMemorialHall(this.selectedUnitId);
},
2025-10-16 17:34:44 +08:00
// 跳转到添加牌位页面
handleAddMemorial() {
console.log("跳转到添加牌位页面");
uni.navigateTo({
url: "/pages/memorial/addMemorial",
success: () => {
console.log("跳转到添加牌位页面成功");
},
fail: (error) => {
console.error("跳转失败:", error);
uni.showToast({
title: "页面跳转失败",
icon: "none",
});
},
});
},
2025-11-19 17:58:14 +08:00
// 跳转到NFC配对页面
handleNfcPairing() {
if (!this.ensureUnitSelected()) return;
const unitId = this.selectedUnitId;
uni.navigateTo({
url: `/pages/memorial/nfcPairing?unitId=${unitId}`,
success: () => {
console.log("跳转到NFC配对页面成功");
},
fail: (error) => {
console.error("跳转失败:", error);
uni.showToast({
title: "页面跳转失败",
icon: "none",
});
},
});
},
2025-10-14 15:48:58 +08:00
},
};
</script>
<style lang="scss" scoped>
2025-10-14 15:48:58 +08:00
.page {
width: 100%;
min-height: 100vh;
}
.header {
width: 100%;
min-height: 100vh;
display: flex;
align-items: center;
flex-direction: column;
padding-bottom: 180rpx;
box-sizing: border-box;
}
.floor-selector-container {
margin-bottom: 30rpx;
display: flex;
justify-content: center;
}
// 状态栏容器样式
:deep(.status-bar) {
width: 100%;
max-width: 750rpx;
}
.bottom {
position: fixed;
left: 0;
2025-10-14 16:43:15 +08:00
bottom: 10rpx;
2025-10-14 15:48:58 +08:00
width: 100%;
background: #fffbf5;
2025-10-15 16:49:36 +08:00
height: 300rpx;
2025-10-14 15:48:58 +08:00
}
.btn-grid {
display: grid;
2025-10-14 16:43:15 +08:00
grid-template-columns: 1fr 1fr 1fr;
2025-10-15 16:49:36 +08:00
grid-template-rows: 1fr 1fr 1fr;
2025-10-14 15:48:58 +08:00
gap: 20rpx;
padding: 20rpx 32rpx;
height: 100%;
box-sizing: border-box;
}
.grid-btn {
display: flex;
align-items: center;
justify-content: center;
background: #a24242;
color: #ffffff;
border-radius: 12rpx;
font-size: 28rpx;
}
2025-10-16 17:34:44 +08:00
.add-memorial-btn {
background: #4a90e2 !important;
font-weight: bold;
box-shadow: 0 4rpx 8rpx rgba(74, 144, 226, 0.3);
}
</style>