412 lines
10 KiB
Vue
Raw Normal View History

2026-07-29 11:25:29 +08:00
<template>
<full-page pageClass="rights-page" :customScroll="true">
<view class="page-body">
<view class="user-card" @click="toSelectPage">
<view class="avatar">
<uni-icons type="person-filled" size="36" color="#c0c4cc" />
</view>
<view class="user-main">
<view class="user-name">{{ customerName || "未选择档案" }}</view>
<view class="user-corp">所属机构{{ corpName || "-" }}</view>
</view>
<uni-icons type="right" size="16" color="#c0c4cc" />
</view>
<view class="summary">
以下为<text class="summary-name">{{ customerName || "-" }}</text>的所有剩余权益
</view>
<view v-if="loading" class="empty">加载中...</view>
<view v-else-if="!groups.length" class="empty">暂无权益</view>
<view v-else class="group-list">
<view v-for="group in groups" :key="group.key" class="group-card">
<view class="group-head">
<view class="group-badge">{{ group.badge }}</view>
<view class="group-title">{{ group.title }}</view>
</view>
<view class="table-head">
<text class="col col-name">项目名称</text>
<text class="col col-num">总次数</text>
<text class="col col-num">剩余次数</text>
<text class="col col-date">有效期至</text>
</view>
<view v-for="row in group.rows" :key="row._id" class="table-row">
<text class="col col-name">{{ row.projectName }}</text>
<text class="col col-num">{{ row.usageCount }}</text>
<text class="col col-num col-rest">{{ row.restUsageCount }}</text>
<text class="col col-date">{{ row.validText }}</text>
</view>
</view>
</view>
</view>
</full-page>
</template>
<script setup>
import { computed, ref } from "vue";
import { onLoad, onShow } from "@dcloudio/uni-app";
import { storeToRefs } from "pinia";
import useAccount from "@/store/account";
import api from "@/utils/api";
import { get, remove } from "@/utils/cache";
import { toast } from "@/utils/widget";
import { normalizeCorpId } from "@/utils/api-base-config";
import FullPage from "@/components/full-page.vue";
const HOME_CURRENT_TEAM_CACHE_KEY = "home-current-team-info";
const RIGHTS_SELECTION_CACHE_KEY = "experience-coupon-rights-selection";
const { account } = storeToRefs(useAccount());
const { getTeams } = useAccount();
const corpId = ref("");
const teamId = ref("");
const customerId = ref("");
const customerName = ref("");
const corpName = ref("");
const teams = ref([]);
const records = ref([]);
const loading = ref(false);
function formatDate(ts) {
if (!ts) return "无限期";
const d = new Date(Number(ts));
if (Number.isNaN(d.getTime())) return "无限期";
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
}
function pickCorpName(team = {}) {
return team.licenseHospitalName || team.leaderCorp || team.corpName || "-";
}
const groups = computed(() => {
const list = Array.isArray(records.value) ? records.value : [];
const valid = list.filter((item) => {
const status = String(item.treatmentStatus || "");
return !["void", "canceled", "cancel"].includes(status);
});
const packageMap = {};
const singleGroups = [];
valid.forEach((item) => {
const row = {
_id: item._id,
projectName: item.projectName || "-",
usageCount: Number(item.usageCount || 0),
restUsageCount: Number(item.restUsageCount || 0),
validText: formatDate(item.validTime),
};
if (item.packageId) {
const key = String(item.packageId);
if (!packageMap[key]) {
packageMap[key] = {
key: `pkg_${key}`,
badge: "套",
title: `套餐(${item.packageName || "未命名套餐"}`,
rows: [],
};
}
packageMap[key].rows.push(row);
return;
}
singleGroups.push({
key: `single_${item._id}`,
badge: "项",
title: "单项目",
rows: [row],
});
});
return [...singleGroups, ...Object.values(packageMap)];
});
function applySelection(selection = {}) {
corpId.value = normalizeCorpId(selection.corpId || corpId.value || "");
teamId.value = selection.teamId || teamId.value || "";
customerId.value = selection.customerId || selection.memberId || customerId.value || "";
customerName.value = selection.name || customerName.value || "";
if (selection.corpName) {
corpName.value = selection.corpName;
return;
}
const matched = teams.value.find(
(team) =>
normalizeCorpId(team.corpId) === corpId.value &&
(!teamId.value || team.teamId === teamId.value)
);
corpName.value = pickCorpName(matched || {});
}
async function resolveContext(options = {}) {
const cached = get(HOME_CURRENT_TEAM_CACHE_KEY) || {};
try {
teams.value = (await getTeams()) || [];
} catch (e) {
console.warn(e);
teams.value = [];
}
const incoming = {
corpId: options.corpId || corpId.value || cached.corpId || "",
teamId: options.teamId || teamId.value || cached.teamId || "",
customerId: options.customerId || options.memberId || customerId.value || "",
name: options.name ? decodeURIComponent(options.name) : customerName.value,
};
applySelection(incoming);
const matched =
teams.value.find(
(team) =>
team.teamId === teamId.value &&
normalizeCorpId(team.corpId) === corpId.value
) ||
teams.value.find((team) => team.teamId === teamId.value) ||
teams.value.find((team) => normalizeCorpId(team.corpId) === corpId.value) ||
teams.value[0] ||
null;
if (!corpId.value) corpId.value = normalizeCorpId(matched?.corpId || "");
if (!teamId.value) teamId.value = matched?.teamId || "";
if (!corpName.value) corpName.value = pickCorpName(matched || {});
if (customerId.value) return true;
const miniAppId = account.value?.openid || uni.getStorageSync("openid") || "";
if (!miniAppId || !corpId.value) return false;
const res = await api("getMiniAppCustomers", { miniAppId, corpId: corpId.value }, false);
const customers = res?.success && Array.isArray(res.data) ? res.data : [];
const preferred = customers.find((item) => item.relationship === "本人") || customers[0];
customerId.value = preferred?._id || "";
customerName.value = preferred?.name || customerName.value || "";
return !!customerId.value;
}
async function loadRights() {
if (!corpId.value || !customerId.value) {
records.value = [];
return;
}
loading.value = true;
try {
const res = await api(
"getTreatmentRecord",
{
corpId: corpId.value,
customerId: customerId.value,
page: 1,
pageSize: 200,
},
false
);
if (!res?.success) {
toast(res?.message || "加载权益失败");
records.value = [];
return;
}
records.value = res.list || res.data?.list || [];
} finally {
loading.value = false;
}
}
async function syncSelectedProfile() {
const selected = get(RIGHTS_SELECTION_CACHE_KEY);
if (!selected) return false;
remove(RIGHTS_SELECTION_CACHE_KEY);
applySelection(selected);
await loadRights();
return true;
}
function toSelectPage() {
const params = [
`corpId=${encodeURIComponent(corpId.value || "")}`,
`teamId=${encodeURIComponent(teamId.value || "")}`,
`customerId=${encodeURIComponent(customerId.value || "")}`,
`name=${encodeURIComponent(customerName.value || "")}`,
].join("&");
uni.navigateTo({
url: `/pages/experience-coupon/select-rights-archive?${params}`,
});
}
onLoad(async (options = {}) => {
uni.setNavigationBarTitle({ title: "我的权益" });
const ok = await resolveContext(options);
if (!ok) {
toast("请先绑定档案");
return;
}
await loadRights();
});
onShow(async () => {
const changed = await syncSelectedProfile();
if (changed) return;
if (corpId.value && customerId.value) {
await loadRights();
}
});
</script>
<style scoped>
.page-body {
min-height: 100%;
padding: 0 0 40rpx;
box-sizing: border-box;
background: #f5f5f5;
}
.user-card {
display: flex;
align-items: center;
background: #fff;
border-radius: 0;
padding: 24rpx 30rpx;
border-bottom: 1px solid #eceff4;
}
.avatar {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background: #f0f2f5;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
flex-shrink: 0;
}
.user-main {
min-width: 0;
flex: 1;
}
.user-name {
font-size: 32rpx;
font-weight: 600;
color: #222;
margin-bottom: 8rpx;
}
.user-corp {
font-size: 24rpx;
color: #888;
}
.summary {
padding: 18rpx 30rpx;
font-size: 26rpx;
color: #666;
background: #f0f2f5;
border-top: 1px solid #eceff4;
border-bottom: 1px solid #eceff4;
}
.summary-name {
color: #065bd6;
font-weight: 600;
}
.group-list {
padding-top: 12rpx;
}
.group-card {
margin-bottom: 16rpx;
background: #fff;
border-top: 1px solid #eceff4;
border-bottom: 1px solid #eceff4;
}
.group-head {
display: flex;
align-items: center;
padding: 18rpx 24rpx;
border-bottom: 1px solid #eceff4;
}
.group-badge {
width: 36rpx;
height: 36rpx;
border-radius: 50%;
background: #2f7df6;
color: #fff;
font-size: 22rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12rpx;
flex-shrink: 0;
}
.group-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
.table-head,
.table-row {
display: flex;
align-items: flex-start;
padding: 18rpx 24rpx;
}
.table-head {
color: #666;
font-size: 24rpx;
font-weight: 600;
background: #f5f9fc;
border-bottom: 1px solid #eceff4;
}
.table-row {
color: #333;
font-size: 26rpx;
border-bottom: 1px solid #f1f3f6;
}
.table-row:last-child {
border-bottom: none;
}
.col {
text-align: center;
word-break: break-all;
line-height: 1.5;
}
.col-name {
flex: 1.35;
text-align: left;
padding-right: 16rpx;
}
.col-num {
flex: 0.7;
}
.col-date {
flex: 1;
}
.col-rest {
color: #ff9800;
font-weight: 600;
}
.empty {
padding: 120rpx 0;
text-align: center;
color: #999;
font-size: 28rpx;
}
</style>