ykt-team-wxapp/pages/record/treatment-record.vue
2026-07-30 16:37:11 +08:00

334 lines
9.4 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>
<full-page pageClass="record-page" :customScroll="true">
<view class="page-body">
<view class="profile-card" @click="switchArchive">
<view class="avatar-wrap">
<view class="avatar-placeholder">{{ avatarText }}</view>
</view>
<view class="profile-main">
<view class="profile-title">{{ customerName || "请选择档案" }}</view>
<view class="profile-sub">所属机构{{ corpName || "-" }}</view>
</view>
<view class="profile-arrow">&gt;</view>
</view>
<picker mode="date" fields="month" :value="selectedMonth" @change="handleMonthChange">
<view class="month-bar">
<text>{{ monthText }}</text>
<text class="month-arrow"></text>
</view>
</picker>
<view v-if="loading" class="empty">加载中...</view>
<view v-else-if="!records.length" class="empty">暂无治疗记录</view>
<view v-else class="record-list">
<view v-for="item in records" :key="item._id" class="record-card">
<view class="record-status">已治疗</view>
<view class="record-row">
<text class="row-label">项目名称</text>
<text class="row-value strong">{{ item.projectName || "未命名项目" }}</text>
</view>
<view class="record-row">
<text class="row-label">治疗日期</text>
<text class="row-value">{{ formatDate(item.treatmentTime) }}</text>
</view>
<view class="record-row">
<text class="row-label">治疗时间</text>
<text class="row-value">{{ formatTimeOnly(item.treatmentTime) }}</text>
</view>
<view class="record-row">
<text class="row-label">治疗医生</text>
<text class="row-value strong">{{ item.treatmentDoctorName || item.doctorName || staffText(item.treatmentDoctorUserId) }}</text>
</view>
<view v-if="assistantText(item)" class="record-row">
<text class="row-label">配台</text>
<text class="row-value">{{ assistantText(item) }}</text>
</view>
<view class="record-row">
<text class="row-label">治疗科室</text>
<text class="row-value">{{ item.treatmentDeptName || "-" }}</text>
</view>
<view class="record-row">
<text class="row-label">治疗数</text>
<text class="row-value">{{ item.deductUsageCount || 0 }}</text>
</view>
<view v-if="item.treatmentArea" class="record-row">
<text class="row-label">治疗部位</text>
<text class="row-value">{{ item.treatmentArea }}</text>
</view>
<view v-if="item.treatmentRemark" class="record-row">
<text class="row-label">治疗备注</text>
<text class="row-value">{{ item.treatmentRemark }}</text>
</view>
<view v-if="item.packageName" class="record-row">
<text class="row-label">所属套餐</text>
<text class="row-value">{{ item.packageName }}</text>
</view>
</view>
</view>
</view>
</full-page>
</template>
<script setup>
import { computed, ref } from "vue";
import { onLoad, onShow } from "@dcloudio/uni-app";
import api from "@/utils/api";
import { normalizeCorpId } from "@/utils/api-base-config";
import { toast } from "@/utils/widget";
import FullPage from "@/components/full-page.vue";
const corpId = ref("");
const teamId = ref("");
const customerId = ref("");
const customerName = ref("");
const corpName = ref("");
const selectedMonth = ref(formatMonth(Date.now()));
const records = ref([]);
const staffNameMap = ref({});
const loading = ref(false);
const avatarText = computed(() => (customerName.value || "档案").slice(0, 1));
const monthText = computed(() => selectedMonth.value.replace("-", "年") + "月");
function pad(value) {
return String(value).padStart(2, "0");
}
function toDate(ts) {
if (!ts) return null;
const d = new Date(Number(ts));
return Number.isNaN(d.getTime()) ? null : d;
}
function formatMonth(ts) {
const d = toDate(ts) || new Date();
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}`;
}
function monthRange(month) {
const [year, monthIndex] = String(month || "").split("-").map(Number);
const start = new Date(year, monthIndex - 1, 1);
const end = new Date(year, monthIndex, 0);
return [
`${start.getFullYear()}-${pad(start.getMonth() + 1)}-01`,
`${end.getFullYear()}-${pad(end.getMonth() + 1)}-${pad(end.getDate())}`,
];
}
function formatDate(ts) {
const d = toDate(ts);
if (!d) return "-";
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
}
function formatTimeOnly(ts) {
const d = toDate(ts);
if (!d) return "-";
return `${pad(d.getHours())}:${pad(d.getMinutes())}`;
}
function staffText(userid) {
if (!userid) return "-";
return staffNameMap.value[userid] || userid;
}
function assistantText(item) {
const assistants = item?.assistantDoctors;
if (!Array.isArray(assistants) || !assistants.length) return "";
return assistants.map((staff) => staffText(staff?.userid || staff?.userId || staff)).filter(Boolean).join("、");
}
async function loadStaffNameMap() {
if (!corpId.value) {
staffNameMap.value = {};
return;
}
const res = await api("getAllCorpMemberIncludeDeleted", { corpId: corpId.value }, false);
const list = res?.success && Array.isArray(res.data) ? res.data : [];
staffNameMap.value = list.reduce((map, staff) => {
if (staff?.userid) {
map[staff.userid] = staff.anotherName || staff.name || staff.userid;
}
return map;
}, {});
}
function switchArchive() {
const corp = encodeURIComponent(corpId.value || "");
const team = encodeURIComponent(teamId.value || "");
const customer = encodeURIComponent(customerId.value || "");
uni.navigateTo({
url: `/pages/experience-coupon/select-rights-archive?mode=target&target=treatment&corpId=${corp}&teamId=${team}&customerId=${customer}`,
});
}
async function loadRecords() {
if (!corpId.value || !customerId.value) {
records.value = [];
return;
}
loading.value = true;
try {
const res = await api(
"getDeductRecord",
{
corpId: corpId.value,
customerId: customerId.value,
deductStatus: ["deducted"],
treatmentTimeDates: monthRange(selectedMonth.value),
page: 1,
pageSize: 200,
},
false
);
if (!res?.success) {
toast(res?.message || "加载治疗记录失败");
records.value = [];
return;
}
const list = res.data?.list || res.list || [];
records.value = Array.isArray(list)
? list.sort((a, b) => Number(b.treatmentTime || b.createTime || 0) - Number(a.treatmentTime || a.createTime || 0))
: [];
} finally {
loading.value = false;
}
}
async function handleMonthChange(event) {
selectedMonth.value = event?.detail?.value || selectedMonth.value;
await loadRecords();
}
onLoad(async (options = {}) => {
uni.setNavigationBarTitle({ title: "治疗记录" });
corpId.value = normalizeCorpId(options.corpId || "");
teamId.value = options.teamId || "";
customerId.value = options.customerId || options.id || "";
customerName.value = options.name ? decodeURIComponent(options.name) : "";
corpName.value = options.corpName ? decodeURIComponent(options.corpName) : "";
if (options.month) selectedMonth.value = options.month;
await loadStaffNameMap();
await loadRecords();
});
onShow(() => {
if (corpId.value && customerId.value) loadRecords();
});
</script>
<style scoped>
.page-body {
min-height: 100%;
box-sizing: border-box;
background: #e9edf3;
border-top: 8rpx solid #0b63d8;
}
.profile-card {
display: flex;
align-items: center;
gap: 18rpx;
padding: 20rpx 24rpx;
background: #fff;
border-bottom: 1rpx solid #d7dce5;
}
.avatar-wrap {
width: 72rpx;
height: 72rpx;
border-radius: 50%;
background: #d2d5da;
overflow: hidden;
flex-shrink: 0;
}
.avatar-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 30rpx;
font-weight: 600;
}
.profile-main {
flex: 1;
min-width: 0;
}
.profile-title {
font-size: 31rpx;
font-weight: 700;
color: #333;
line-height: 40rpx;
}
.profile-sub {
margin-top: 4rpx;
font-size: 24rpx;
color: #9aa0a8;
line-height: 34rpx;
}
.profile-arrow {
flex-shrink: 0;
color: #b4b7bf;
font-size: 32rpx;
}
.month-bar {
display: flex;
align-items: center;
gap: 8rpx;
height: 70rpx;
padding: 0 24rpx;
background: #e2e6ec;
color: #333;
font-size: 30rpx;
font-weight: 700;
border-bottom: 1rpx solid #d4d9e2;
}
.month-arrow {
font-size: 18rpx;
color: #333;
}
.record-list {
padding: 0rpx 10rpx 12rpx 10rpx;
}
.record-card {
position: relative;
padding: 22rpx 24rpx 22rpx 34rpx;
background: #fff;
border-top: 14rpx solid #e9edf3;
border-bottom: 1rpx solid #d7dce5;
}
.record-status {
position: absolute;
top: 24rpx;
right: 24rpx;
color: #333;
font-size: 26rpx;
}
.record-row {
display: flex;
align-items: flex-start;
padding: 7rpx 112rpx 7rpx 0;
font-size: 27rpx;
line-height: 38rpx;
}
.row-label {
flex-shrink: 0;
color: #6b7280;
font-weight: 700;
}
.row-value {
min-width: 0;
color: #333;
word-break: break-all;
}
.strong {
font-weight: 700;
}
.empty {
padding: 120rpx 0;
text-align: center;
font-size: 28rpx;
color: #999;
}
</style>