buddhism/pages/memorial/adminMemorial.vue
2025-11-19 17:58:14 +08:00

563 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<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">
<view class="grid-btn" @click="handleAllOpen">全部开启</view>
<view class="grid-btn" @click="handleAllClose">全部关闭</view>
<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>
<view class="grid-btn" @click="handleSearchMemorial">寻找牌位</view>
<view class="grid-btn" @click="handleNfcPairing">NFC 配对</view>
<view class="grid-btn add-memorial-btn" @click="handleAddMemorial"
>添加牌位
</view>
</view>
</view>
</view>
</template>
<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);
}
this.$refs.floorSelector.loadTreeData();
},
methods: {
// 校验是否已选择单元
ensureUnitSelected() {
if (!this.selectedUnitId) {
uni.showToast({ title: "请先选择单元", icon: "none" });
return false;
}
return true;
},
// 确认提示封装,返回是否确认
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 });
try {
const res = await this.$request.put(url, data);
if (res && (res.code === 200 || res.status === 200)) {
uni.showToast({ title: res.msg || "操作成功", icon: "success" });
} else {
uni.showToast({
title: (res && res.msg) || "操作失败",
icon: "none",
});
}
return res;
} catch (error) {
uni.showToast({ title: "请求失败", icon: "none" });
console.error(`${logTag} error`, error);
throw error;
} finally {
uni.hideLoading();
}
},
// 统一构建网关命令负载
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);
let templeId = uni.getStorageSync("templeId");
return {
// 兼容字段:同时传 floorId 与后端现用的 regionId
// regionId: String(floorId),
templeId: templeId,
command, // open | close
mac: "000000000000",
timeout: "11",
reason,
};
},
// 选择单位并输入时长
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 };
},
// 输入寻找牌位所需参数:闪烁类型 与 超时时间
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 };
},
async handleAllOpen() {
const ok = await this.confirmAction("确定要全部开启吗?");
if (!ok) return;
const payload = this.buildGatewayPayload("open", "全开");
await this.performPut(
`/app/memorial/sendCommandGateway`,
payload,
"handleAllOpen",
);
},
async handleAllClose() {
const ok = await this.confirmAction("确定要全部关闭吗?");
if (!ok) return;
const payload = this.buildGatewayPayload("close", "全关");
await this.performPut(
`/app/memorial/sendCommandGateway`,
payload,
"handleAllClose",
);
},
// 底部按钮:强制开启
async handleForceOpen() {
if (!this.ensureUnitSelected()) return;
const ok = await this.confirmAction("确定要强制开启该牌位吗?");
if (!ok) return;
await this.performPut(
`/bst/memorial/open/${this.selectedUnitId}`,
null,
"handleForceOpen",
);
},
// 底部按钮:强制关闭
async handleForceClose() {
if (!this.ensureUnitSelected()) return;
const ok = await this.confirmAction("确定要强制关闭该牌位吗?");
if (!ok) return;
await this.performPut(
`/bst/memorial/close/${this.selectedUnitId}`,
null,
"handleForceClose",
);
},
// 底部按钮:时长归零
async handleResetDuration() {
if (!this.ensureUnitSelected()) return;
const ok = await this.confirmAction("确定要将该牌位时长归零吗?");
if (!ok) return;
await this.performPut(
`/bst/memorial/reset/${this.selectedUnitId}`,
null,
"handleResetDuration",
);
},
// 底部按钮:寻找牌位(闪烁)
async handleSearchMemorial() {
if (!this.ensureUnitSelected()) return;
try {
// const { type } = await this.promptSearchParams();
const payload = {
memorialId: String(this.selectedUnitId),
type: "3",
timeout: "11",
};
await this.performPut(
`/app/memorial/searchMemorail`,
payload,
"handleSearchMemorial",
);
} catch (e) {
if (
e &&
e.message !== "UserCancelled" &&
e.message !== "InvalidNumber" &&
e.message !== "InvalidType"
) {
console.error("handleSearchMemorial prompt error", e);
}
}
},
// 底部按钮:增加时长
async handleIncreaseDuration() {
if (!this.ensureUnitSelected()) return;
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);
}
}
},
// 初始化页面
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);
},
// 跳转到添加牌位页面
handleAddMemorial() {
console.log("跳转到添加牌位页面");
uni.navigateTo({
url: "/pages/memorial/addMemorial",
success: () => {
console.log("跳转到添加牌位页面成功");
},
fail: (error) => {
console.error("跳转失败:", error);
uni.showToast({
title: "页面跳转失败",
icon: "none",
});
},
});
},
// 跳转到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",
});
},
});
},
},
};
</script>
<style lang="scss" scoped>
.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;
bottom: 10rpx;
width: 100%;
background: #fffbf5;
height: 300rpx;
}
.btn-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
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;
}
.add-memorial-btn {
background: #4a90e2 !important;
font-weight: bold;
box-shadow: 0 4rpx 8rpx rgba(74, 144, 226, 0.3);
}
</style>