bug修复
This commit is contained in:
parent
92fe63f308
commit
9f5331cd3b
@ -194,8 +194,12 @@ async function getResponsiblePerson() {
|
|||||||
return res && res.data ? res.data : ''
|
return res && res.data ? res.data : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldBackAfterArchiveBound() {
|
||||||
|
return ['experienceCoupon', 'appointmentRegistration'].includes(source.value)
|
||||||
|
}
|
||||||
|
|
||||||
function backAfterArchiveBound() {
|
function backAfterArchiveBound() {
|
||||||
if (source.value === 'experienceCoupon') {
|
if (shouldBackAfterArchiveBound()) {
|
||||||
uni.navigateBack()
|
uni.navigateBack()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -228,8 +232,8 @@ async function init() {
|
|||||||
const res = bindCustomerId.value ? await getExperienceCouponBindArchive() : await getArchives();
|
const res = bindCustomerId.value ? await getExperienceCouponBindArchive() : await getArchives();
|
||||||
if (res.length > 0) {
|
if (res.length > 0) {
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
} else if (source.value === 'experienceCoupon') {
|
} else if (bindCustomerId.value || shouldBackAfterArchiveBound()) {
|
||||||
await toast('体验券发放档案不存在或已绑定');
|
await toast('指定绑定档案不存在或已绑定');
|
||||||
uni.navigateBack();
|
uni.navigateBack();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -211,14 +211,21 @@ function openArchiveBindPage() {
|
|||||||
uni.navigateTo({ url: buildArchiveBindUrl() });
|
uni.navigateTo({ url: buildArchiveBindUrl() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toTimestamp(value) {
|
||||||
|
if (!value) return 0;
|
||||||
|
const numeric = Number(value);
|
||||||
|
if (Number.isFinite(numeric)) return numeric;
|
||||||
|
const parsed = new Date(value).getTime();
|
||||||
|
return Number.isNaN(parsed) ? 0 : parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIssueExpireAt() {
|
||||||
|
return toTimestamp(issue.value?.activityEndTime || issue.value?.displayExpireTime);
|
||||||
|
}
|
||||||
|
|
||||||
function isExpiredIssue() {
|
function isExpiredIssue() {
|
||||||
const expireAt = Number(issue.value?.projectExpireTime || 0);
|
const expireAt = getIssueExpireAt();
|
||||||
if (expireAt && Date.now() > expireAt) return true;
|
return Boolean(expireAt && Date.now() > expireAt);
|
||||||
const rule = issue.value?.projectValidRuleSnapshot || {};
|
|
||||||
if (rule.type === "fixedDate" && rule.fixedDate && Date.now() > Number(rule.fixedDate)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function acceptCoupon() {
|
async function acceptCoupon() {
|
||||||
|
|||||||
@ -9,12 +9,13 @@
|
|||||||
>
|
>
|
||||||
<view class="page-body">
|
<view class="page-body">
|
||||||
<view v-if="loading" class="empty">加载中...</view>
|
<view v-if="loading" class="empty">加载中...</view>
|
||||||
<view v-else-if="!list.length" class="empty">暂无待领取体验券</view>
|
<view v-else-if="!list.length" class="empty">暂无体验券</view>
|
||||||
<view v-else class="coupon-list">
|
<view v-else class="coupon-list">
|
||||||
<view
|
<view
|
||||||
v-for="item in list"
|
v-for="item in list"
|
||||||
:key="item._id"
|
:key="item._id"
|
||||||
class="coupon-card"
|
class="coupon-card"
|
||||||
|
:class="item.cardClass"
|
||||||
@click="openPoster(item)"
|
@click="openPoster(item)"
|
||||||
>
|
>
|
||||||
<image
|
<image
|
||||||
@ -25,7 +26,14 @@
|
|||||||
/>
|
/>
|
||||||
<view v-else class="coupon-poster coupon-poster--empty">体验券</view>
|
<view v-else class="coupon-poster coupon-poster--empty">体验券</view>
|
||||||
<view class="coupon-body">
|
<view class="coupon-body">
|
||||||
<view class="coupon-title">{{ item.activityName || "体验券" }}</view>
|
<view class="coupon-title-row">
|
||||||
|
<view class="coupon-title">{{ item.activityName || "体验券" }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="coupon-state-row">
|
||||||
|
<view class="coupon-status" :class="item.statusClass">
|
||||||
|
{{ item.displayStatusText }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<view class="coupon-info-grid">
|
<view class="coupon-info-grid">
|
||||||
<view class="coupon-info-row coupon-info-row--projects">
|
<view class="coupon-info-row coupon-info-row--projects">
|
||||||
<text class="coupon-info-label">项目</text>
|
<text class="coupon-info-label">项目</text>
|
||||||
@ -43,14 +51,20 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="coupon-info-row">
|
<view class="coupon-info-row">
|
||||||
<text class="coupon-info-label">项目有效期</text>
|
<text class="coupon-info-label">项目有效期</text>
|
||||||
<text>{{ item.validText }}</text>
|
<text>{{ item.projectValidText }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="coupon-info-row">
|
<view class="coupon-info-row">
|
||||||
<text class="coupon-info-label">活动有效期</text>
|
<text class="coupon-info-label">体验券有效期</text>
|
||||||
<text>{{ item.activityValidText }}</text>
|
<text>{{ item.couponValidText }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="coupon-info-row">
|
||||||
|
<text class="coupon-info-label">发送时间</text>
|
||||||
|
<text>{{ item.issueTimeText }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="coupon-action">点击查看海报领取</view>
|
<view class="coupon-action" :class="{ disabled: item.displayStatus !== 'issued' }">
|
||||||
|
{{ item.actionText }}
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -102,9 +116,18 @@ const posterVisible = ref(false);
|
|||||||
const current = ref(null);
|
const current = ref(null);
|
||||||
const claiming = ref(false);
|
const claiming = ref(false);
|
||||||
|
|
||||||
|
function toTimestamp(value) {
|
||||||
|
if (!value) return 0;
|
||||||
|
const numeric = Number(value);
|
||||||
|
if (Number.isFinite(numeric)) return numeric;
|
||||||
|
const parsed = new Date(value).getTime();
|
||||||
|
return Number.isNaN(parsed) ? 0 : parsed;
|
||||||
|
}
|
||||||
|
|
||||||
function formatDate(ts) {
|
function formatDate(ts) {
|
||||||
if (!ts) return "";
|
const time = toTimestamp(ts);
|
||||||
const d = new Date(Number(ts));
|
if (!time) return "";
|
||||||
|
const d = new Date(time);
|
||||||
if (Number.isNaN(d.getTime())) return "";
|
if (Number.isNaN(d.getTime())) return "";
|
||||||
const y = d.getFullYear();
|
const y = d.getFullYear();
|
||||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||||
@ -112,15 +135,26 @@ function formatDate(ts) {
|
|||||||
return `${y}-${m}-${day}`;
|
return `${y}-${m}-${day}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatDateTime(ts) {
|
||||||
|
const time = toTimestamp(ts);
|
||||||
|
if (!time) return "-";
|
||||||
|
const d = new Date(time);
|
||||||
|
if (Number.isNaN(d.getTime())) return "-";
|
||||||
|
const h = String(d.getHours()).padStart(2, "0");
|
||||||
|
const min = String(d.getMinutes()).padStart(2, "0");
|
||||||
|
return `${formatDate(time)} ${h}:${min}`;
|
||||||
|
}
|
||||||
|
|
||||||
function projectText(projects) {
|
function projectText(projects) {
|
||||||
const arr = Array.isArray(projects) ? projects : [];
|
const arr = Array.isArray(projects) ? projects : [];
|
||||||
if (!arr.length) return "未配置项目";
|
if (!arr.length) return "未配置项目";
|
||||||
return arr.map((p) => `${p.projectName || "项目"}×${p.usageCount || 1}`).join("、");
|
return arr.map((p) => `${p.projectName || "项目"}×${p.usageCount || 1}`).join("、");
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildValidText(item) {
|
function buildProjectValidText(item) {
|
||||||
const rule = item.projectValidRuleSnapshot || {};
|
const rule = item.projectValidRuleSnapshot || {};
|
||||||
if (item.projectExpireTime) return `有效期至 ${formatDate(item.projectExpireTime)}`;
|
const projectExpireAt = toTimestamp(item.projectExpireTime);
|
||||||
|
if (projectExpireAt) return `有效期至 ${formatDate(projectExpireAt)}`;
|
||||||
if (rule.type === "fixedDate" && rule.fixedDate) {
|
if (rule.type === "fixedDate" && rule.fixedDate) {
|
||||||
return `有效期至 ${formatDate(rule.fixedDate)}`;
|
return `有效期至 ${formatDate(rule.fixedDate)}`;
|
||||||
}
|
}
|
||||||
@ -130,23 +164,20 @@ function buildValidText(item) {
|
|||||||
return "领取后按活动规则生效";
|
return "领取后按活动规则生效";
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildActivityValidText(item) {
|
function getCouponExpireAt(item) {
|
||||||
|
return toTimestamp(item.activityEndTime || item.displayExpireTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCouponValidText(item) {
|
||||||
const start = formatDate(item.activityStartTime) || "-";
|
const start = formatDate(item.activityStartTime) || "-";
|
||||||
const end = formatDate(item.activityEndTime) || "-";
|
const expireAt = getCouponExpireAt(item);
|
||||||
|
const end = formatDate(expireAt) || "-";
|
||||||
|
if (start === "-" && end === "-") return "未配置有效期";
|
||||||
return `${start} 至 ${end}`;
|
return `${start} 至 ${end}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExpireAt(item) {
|
|
||||||
if (item.projectExpireTime) return Number(item.projectExpireTime);
|
|
||||||
const rule = item.projectValidRuleSnapshot || {};
|
|
||||||
if (rule.type === "fixedDate" && rule.fixedDate) {
|
|
||||||
return Number(rule.fixedDate);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isExpired(item) {
|
function isExpired(item) {
|
||||||
const expireAt = getExpireAt(item);
|
const expireAt = getCouponExpireAt(item);
|
||||||
if (!expireAt) return false;
|
if (!expireAt) return false;
|
||||||
return Date.now() > expireAt;
|
return Date.now() > expireAt;
|
||||||
}
|
}
|
||||||
@ -184,20 +215,33 @@ async function resolveContext(options = {}) {
|
|||||||
return !!customerId.value;
|
return !!customerId.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function voidExpired(item) {
|
function resolveDisplayStatus(item) {
|
||||||
try {
|
const status = item.displayStatus || item.status || "issued";
|
||||||
await api(
|
if (status === "claimed") {
|
||||||
"voidExperienceCouponIssue",
|
return {
|
||||||
{
|
displayStatus: "claimed",
|
||||||
corpId: corpId.value,
|
displayStatusText: "已领取",
|
||||||
issueId: item._id,
|
actionText: "已领取",
|
||||||
voidReason: "有效期内未领取,自动失效",
|
cardClass: "coupon-card--claimed",
|
||||||
},
|
statusClass: "coupon-status--claimed",
|
||||||
false
|
};
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("auto void failed", e);
|
|
||||||
}
|
}
|
||||||
|
if (status === "expired" || status === "void" || isExpired(item)) {
|
||||||
|
return {
|
||||||
|
displayStatus: "expired",
|
||||||
|
displayStatusText: "已过期",
|
||||||
|
actionText: "已过期",
|
||||||
|
cardClass: "coupon-card--expired",
|
||||||
|
statusClass: "coupon-status--expired",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
displayStatus: "issued",
|
||||||
|
displayStatusText: "待领取",
|
||||||
|
actionText: "点击查看海报领取",
|
||||||
|
cardClass: "coupon-card--issued",
|
||||||
|
statusClass: "coupon-status--issued",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadCoupons(options = {}) {
|
async function loadCoupons(options = {}) {
|
||||||
@ -213,7 +257,6 @@ async function loadCoupons(options = {}) {
|
|||||||
{
|
{
|
||||||
corpId: corpId.value,
|
corpId: corpId.value,
|
||||||
customerId: customerId.value,
|
customerId: customerId.value,
|
||||||
status: "issued",
|
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
},
|
},
|
||||||
@ -225,20 +268,19 @@ async function loadCoupons(options = {}) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const raw = res.list || res.data?.list || [];
|
const raw = res.list || res.data?.list || [];
|
||||||
const valid = [];
|
list.value = raw
|
||||||
for (const item of raw) {
|
.map((item) => {
|
||||||
if (isExpired(item)) {
|
const status = resolveDisplayStatus(item);
|
||||||
voidExpired(item);
|
return {
|
||||||
continue;
|
...item,
|
||||||
}
|
...status,
|
||||||
valid.push({
|
projectText: projectText(item.projectSnapshot),
|
||||||
...item,
|
projectValidText: buildProjectValidText(item),
|
||||||
projectText: projectText(item.projectSnapshot),
|
couponValidText: buildCouponValidText(item),
|
||||||
validText: buildValidText(item),
|
issueTimeText: formatDateTime(item.issueTime || item.createTime),
|
||||||
activityValidText: buildActivityValidText(item),
|
};
|
||||||
});
|
})
|
||||||
}
|
.sort((a, b) => Number(b.issueTime || b.createTime || 0) - Number(a.issueTime || a.createTime || 0));
|
||||||
list.value = valid;
|
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
@ -255,6 +297,10 @@ async function refreshCoupons() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openPoster(item) {
|
function openPoster(item) {
|
||||||
|
if (item?.displayStatus !== "issued") {
|
||||||
|
toast(item?.displayStatusText || "当前体验券不可领取");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!item?.posterUrl) {
|
if (!item?.posterUrl) {
|
||||||
toast("该体验券暂无海报");
|
toast("该体验券暂无海报");
|
||||||
return;
|
return;
|
||||||
@ -338,6 +384,11 @@ onShow(async () => {
|
|||||||
box-shadow: 0 8rpx 10rpx 0 rgba(60, 169, 145, 0.06);
|
box-shadow: 0 8rpx 10rpx 0 rgba(60, 169, 145, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.coupon-card--claimed,
|
||||||
|
.coupon-card--expired {
|
||||||
|
opacity: 0.78;
|
||||||
|
}
|
||||||
|
|
||||||
.coupon-poster {
|
.coupon-poster {
|
||||||
width: 160rpx;
|
width: 160rpx;
|
||||||
height: 160rpx;
|
height: 160rpx;
|
||||||
@ -359,11 +410,48 @@ onShow(async () => {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.coupon-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16rpx;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coupon-state-row {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.coupon-title {
|
.coupon-title {
|
||||||
|
min-width: 0;
|
||||||
|
flex: 1;
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #222;
|
color: #222;
|
||||||
margin-bottom: 8rpx;
|
}
|
||||||
|
|
||||||
|
.coupon-status {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 4rpx 12rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coupon-status--issued {
|
||||||
|
color: #ff8a00;
|
||||||
|
background: rgba(255, 138, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.coupon-status--claimed {
|
||||||
|
color: #0f766e;
|
||||||
|
background: rgba(15, 118, 110, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.coupon-status--expired {
|
||||||
|
color: #909399;
|
||||||
|
background: #f0f2f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-info-grid {
|
.coupon-info-grid {
|
||||||
@ -416,6 +504,10 @@ onShow(async () => {
|
|||||||
color: #ff8a00;
|
color: #ff8a00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.coupon-action.disabled {
|
||||||
|
color: #a8abb2;
|
||||||
|
}
|
||||||
|
|
||||||
.empty {
|
.empty {
|
||||||
padding: 120rpx 0;
|
padding: 120rpx 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@ -143,24 +143,47 @@ async function bindTeam({ corpUserId, externalUserId }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePlainOptions(options = {}) {
|
||||||
|
return Object.keys(options || {}).reduce((acc, key) => {
|
||||||
|
acc[key] = typeof options[key] === 'string' ? safeDecode(options[key]) : options[key];
|
||||||
|
return acc;
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
if (options.q) {
|
const normalizedOptions = normalizePlainOptions(options);
|
||||||
opts.value = JSON.stringify(options)
|
if (normalizedOptions.q) {
|
||||||
changeTeam(parseInviteOptions(options));
|
opts.value = JSON.stringify(normalizedOptions)
|
||||||
} else if (options.type === 'experienceCoupon' && options.issueId && options.corpId) {
|
changeTeam(parseInviteOptions(normalizedOptions));
|
||||||
|
} else if (normalizedOptions.type === 'experienceCoupon' && normalizedOptions.issueId && normalizedOptions.corpId) {
|
||||||
const params = [
|
const params = [
|
||||||
`corpId=${encodeURIComponent(options.corpId || "")}`,
|
`corpId=${encodeURIComponent(normalizedOptions.corpId || "")}`,
|
||||||
`issueId=${encodeURIComponent(options.issueId || "")}`,
|
`issueId=${encodeURIComponent(normalizedOptions.issueId || "")}`,
|
||||||
options.memberId ? `memberId=${encodeURIComponent(options.memberId)}` : "",
|
normalizedOptions.memberId ? `memberId=${encodeURIComponent(normalizedOptions.memberId)}` : "",
|
||||||
options.couponId ? `couponId=${encodeURIComponent(options.couponId)}` : "",
|
normalizedOptions.couponId ? `couponId=${encodeURIComponent(normalizedOptions.couponId)}` : "",
|
||||||
options.unionid ? `unionid=${encodeURIComponent(options.unionid)}` : "",
|
normalizedOptions.unionid ? `unionid=${encodeURIComponent(normalizedOptions.unionid)}` : "",
|
||||||
options.externalUserId ? `externalUserId=${encodeURIComponent(options.externalUserId)}` : "",
|
normalizedOptions.externalUserId ? `externalUserId=${encodeURIComponent(normalizedOptions.externalUserId)}` : "",
|
||||||
].filter(Boolean).join("&");
|
].filter(Boolean).join("&");
|
||||||
uni.redirectTo({
|
uni.redirectTo({
|
||||||
url: `/pages/experience-coupon/claim?${params}`,
|
url: `/pages/experience-coupon/claim?${params}`,
|
||||||
});
|
});
|
||||||
} else if (options.type === 'archive' || (options.teamId && options.corpId)) {
|
} else if (normalizedOptions.type === 'appointmentRegistration' && normalizedOptions.customerId && normalizedOptions.corpId) {
|
||||||
changeTeam(options);
|
const params = [
|
||||||
|
`corpId=${encodeURIComponent(normalizedOptions.corpId || "")}`,
|
||||||
|
normalizedOptions.teamId ? `teamId=${encodeURIComponent(normalizedOptions.teamId)}` : "",
|
||||||
|
`customerId=${encodeURIComponent(normalizedOptions.customerId || "")}`,
|
||||||
|
normalizedOptions.name ? `name=${encodeURIComponent(normalizedOptions.name)}` : "",
|
||||||
|
normalizedOptions.corpName ? `corpName=${encodeURIComponent(normalizedOptions.corpName)}` : "",
|
||||||
|
normalizedOptions.appointmentId ? `appointmentId=${encodeURIComponent(normalizedOptions.appointmentId)}` : "",
|
||||||
|
normalizedOptions.month ? `month=${encodeURIComponent(normalizedOptions.month)}` : "",
|
||||||
|
normalizedOptions.externalUserId ? `externalUserId=${encodeURIComponent(normalizedOptions.externalUserId)}` : "",
|
||||||
|
normalizedOptions.corpUserId ? `corpUserId=${encodeURIComponent(normalizedOptions.corpUserId)}` : "",
|
||||||
|
].filter(Boolean).join("&");
|
||||||
|
uni.redirectTo({
|
||||||
|
url: `/pages/record/appointment-record?${params}`,
|
||||||
|
});
|
||||||
|
} else if (normalizedOptions.type === 'archive' || (normalizedOptions.teamId && normalizedOptions.corpId)) {
|
||||||
|
changeTeam(normalizedOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -61,11 +61,19 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
|
import useAccount from "@/store/account";
|
||||||
import api from "@/utils/api";
|
import api from "@/utils/api";
|
||||||
import { normalizeCorpId } from "@/utils/api-base-config";
|
import { normalizeCorpId } from "@/utils/api-base-config";
|
||||||
import { toast } from "@/utils/widget";
|
import { set } from "@/utils/cache";
|
||||||
|
import { hideLoading, loading as showLoading, toast } from "@/utils/widget";
|
||||||
import FullPage from "@/components/full-page.vue";
|
import FullPage from "@/components/full-page.vue";
|
||||||
|
|
||||||
|
const env = __VITE_ENV__;
|
||||||
|
const appid = env.MP_WX_APP_ID;
|
||||||
|
const { account, externalUserId } = storeToRefs(useAccount());
|
||||||
|
const { getTeams, getExternalUserId, login } = useAccount();
|
||||||
|
|
||||||
const corpId = ref("");
|
const corpId = ref("");
|
||||||
const teamId = ref("");
|
const teamId = ref("");
|
||||||
const customerId = ref("");
|
const customerId = ref("");
|
||||||
@ -76,6 +84,10 @@ const records = ref([]);
|
|||||||
const staffNameMap = ref({});
|
const staffNameMap = ref({});
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const refreshing = ref(false);
|
const refreshing = ref(false);
|
||||||
|
const corpUserId = ref("");
|
||||||
|
const routeExternalUserId = ref("");
|
||||||
|
const authPending = ref(false);
|
||||||
|
const initialized = ref(false);
|
||||||
|
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
pending: { label: "未到院" },
|
pending: { label: "未到院" },
|
||||||
@ -86,6 +98,124 @@ const statusMap = {
|
|||||||
const avatarText = computed(() => (customerName.value || "档案").slice(0, 1));
|
const avatarText = computed(() => (customerName.value || "档案").slice(0, 1));
|
||||||
const monthText = computed(() => selectedMonth.value.replace("-", "年") + "月");
|
const monthText = computed(() => selectedMonth.value.replace("-", "年") + "月");
|
||||||
|
|
||||||
|
function buildCurrentUrl() {
|
||||||
|
const params = [
|
||||||
|
`corpId=${encodeURIComponent(corpId.value || "")}`,
|
||||||
|
`teamId=${encodeURIComponent(teamId.value || "")}`,
|
||||||
|
customerId.value ? `customerId=${encodeURIComponent(customerId.value)}` : "",
|
||||||
|
customerName.value ? `name=${encodeURIComponent(customerName.value)}` : "",
|
||||||
|
corpName.value ? `corpName=${encodeURIComponent(corpName.value)}` : "",
|
||||||
|
corpUserId.value ? `corpUserId=${encodeURIComponent(corpUserId.value)}` : "",
|
||||||
|
routeExternalUserId.value ? `externalUserId=${encodeURIComponent(routeExternalUserId.value)}` : "",
|
||||||
|
selectedMonth.value ? `month=${encodeURIComponent(selectedMonth.value)}` : "",
|
||||||
|
].filter(Boolean).join("&");
|
||||||
|
return `/pages/record/appointment-record?${params}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTeamLoginUrl() {
|
||||||
|
const query = [
|
||||||
|
"source=teamInvite",
|
||||||
|
`redirectUrl=${encodeURIComponent(buildCurrentUrl())}`,
|
||||||
|
].join("&");
|
||||||
|
return `/pages/login/login?${query}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureLogin() {
|
||||||
|
if (!account.value) await login();
|
||||||
|
if (!account.value) {
|
||||||
|
uni.navigateTo({ url: "/pages/login/login" });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensurePhoneAuthorized() {
|
||||||
|
if (account.value?.mobile) return true;
|
||||||
|
await ensureCustomerContext();
|
||||||
|
if (!corpId.value || !teamId.value) {
|
||||||
|
toast("预约团队信息缺失,暂无法查看预约记录");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
set("invite-team-info", {
|
||||||
|
corpId: corpId.value,
|
||||||
|
teamId: teamId.value,
|
||||||
|
corpUserId: corpUserId.value || "",
|
||||||
|
externalUserId: routeExternalUserId.value || externalUserId.value || "",
|
||||||
|
corpName: corpName.value || "",
|
||||||
|
teamName: "",
|
||||||
|
avatars: [],
|
||||||
|
});
|
||||||
|
uni.navigateTo({ url: buildTeamLoginUrl() });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureCustomerContext() {
|
||||||
|
if (!corpId.value || !customerId.value) return null;
|
||||||
|
const res = await api("getCustomerByCustomerId", { corpId: corpId.value, customerId: customerId.value }, false);
|
||||||
|
const customer = res?.success && res.data ? res.data : null;
|
||||||
|
if (!customer) return null;
|
||||||
|
if (!customerName.value && customer.name) customerName.value = customer.name;
|
||||||
|
const teamIds = Array.isArray(customer.teamId) ? customer.teamId : [customer.teamId].filter(Boolean);
|
||||||
|
if (!teamId.value) teamId.value = teamIds.find(Boolean) || "";
|
||||||
|
return customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureTeamAdded() {
|
||||||
|
await ensureCustomerContext();
|
||||||
|
if (!corpId.value || !teamId.value) {
|
||||||
|
toast("预约团队信息缺失,暂无法查看预约记录");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const teams = await getTeams();
|
||||||
|
const linked = (teams || []).some(
|
||||||
|
(team) => normalizeCorpId(team.corpId) === corpId.value && String(team.teamId) === String(teamId.value)
|
||||||
|
);
|
||||||
|
if (linked) return true;
|
||||||
|
showLoading("添加团队中...");
|
||||||
|
try {
|
||||||
|
const res = await api("bindWxappWithTeam", {
|
||||||
|
appid,
|
||||||
|
corpId: corpId.value,
|
||||||
|
teamId: teamId.value,
|
||||||
|
openid: account.value?.openid || "",
|
||||||
|
}, false);
|
||||||
|
if (!res?.success) {
|
||||||
|
toast(res?.message || "添加团队失败");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
await getTeams();
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureArchiveBound() {
|
||||||
|
const miniAppId = account.value?.openid || "";
|
||||||
|
if (!miniAppId || !corpId.value || !customerId.value) return false;
|
||||||
|
const customer = await ensureCustomerContext();
|
||||||
|
if (customer && String(customer.miniAppId || "") === String(miniAppId)) return true;
|
||||||
|
authPending.value = true;
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/archive/edit-archive?corpId=${encodeURIComponent(corpId.value)}&teamId=${encodeURIComponent(teamId.value)}&bindCustomerId=${encodeURIComponent(customerId.value)}&source=appointmentRegistration`,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureAccessReady() {
|
||||||
|
const okLogin = await ensureLogin();
|
||||||
|
if (!okLogin) return false;
|
||||||
|
const okPhone = await ensurePhoneAuthorized();
|
||||||
|
if (!okPhone) return false;
|
||||||
|
await ensureCustomerContext();
|
||||||
|
if (corpId.value) await getExternalUserId(corpId.value);
|
||||||
|
const okTeam = await ensureTeamAdded();
|
||||||
|
if (!okTeam) return false;
|
||||||
|
const okArchive = await ensureArchiveBound();
|
||||||
|
if (!okArchive) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
async function loadCorpName() {
|
async function loadCorpName() {
|
||||||
if (!corpId.value) {
|
if (!corpId.value) {
|
||||||
corpName.value = "";
|
corpName.value = "";
|
||||||
@ -136,13 +266,13 @@ function statusText(item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function appointmentTypeText(item) {
|
function appointmentTypeText(item) {
|
||||||
if (item?.appointmentType === "schedule") return item?.scheduleTtile || "排班";
|
if (item?.appointmentType === "followup") return "复诊预约";
|
||||||
if (item?.appointmentType === "medical") return "复诊预约";
|
if (item?.appointmentType === "treatment") return "治疗预约";
|
||||||
return "治疗预约";
|
return "其他预约";
|
||||||
}
|
}
|
||||||
|
|
||||||
function practitionerLabel(item) {
|
function practitionerLabel(item) {
|
||||||
return item?.appointmentType === "medical" ? "医生" : "治疗师";
|
return item?.appointmentType === "treatment" ? "治疗师" : "医生";
|
||||||
}
|
}
|
||||||
|
|
||||||
function practitionerText(item) {
|
function practitionerText(item) {
|
||||||
@ -252,14 +382,29 @@ onLoad(async (options = {}) => {
|
|||||||
teamId.value = options.teamId || "";
|
teamId.value = options.teamId || "";
|
||||||
customerId.value = options.customerId || options.id || "";
|
customerId.value = options.customerId || options.id || "";
|
||||||
customerName.value = options.name ? decodeURIComponent(options.name) : "";
|
customerName.value = options.name ? decodeURIComponent(options.name) : "";
|
||||||
|
corpName.value = options.corpName ? decodeURIComponent(options.corpName) : "";
|
||||||
|
corpUserId.value = options.corpUserId || "";
|
||||||
|
routeExternalUserId.value = options.externalUserId || "";
|
||||||
if (options.month) selectedMonth.value = options.month;
|
if (options.month) selectedMonth.value = options.month;
|
||||||
await loadCorpName();
|
await loadCorpName();
|
||||||
|
const ready = await ensureAccessReady();
|
||||||
|
if (!ready) return;
|
||||||
|
initialized.value = true;
|
||||||
await loadStaffNameMap();
|
await loadStaffNameMap();
|
||||||
await loadRecords();
|
await loadRecords();
|
||||||
});
|
});
|
||||||
|
|
||||||
onShow(() => {
|
onShow(async () => {
|
||||||
if (corpId.value && customerId.value) loadRecords();
|
if (authPending.value) {
|
||||||
|
authPending.value = false;
|
||||||
|
const ready = await ensureAccessReady();
|
||||||
|
if (!ready) return;
|
||||||
|
initialized.value = true;
|
||||||
|
await loadStaffNameMap();
|
||||||
|
await loadRecords();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (initialized.value && corpId.value && customerId.value) loadRecords();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -47,18 +47,6 @@
|
|||||||
<text class="row-value strong">{{ item.treatmentDoctorName || item.doctorName ||
|
<text class="row-value strong">{{ item.treatmentDoctorName || item.doctorName ||
|
||||||
staffText(item.treatmentDoctorUserId) }}</text>
|
staffText(item.treatmentDoctorUserId) }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="assistantText(item)" class="record-row">
|
|
||||||
<text class="row-label">【配台】</text>
|
|
||||||
<text class="row-value">{{ assistantText(item) }}</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>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user