2026-01-20 19:36:49 +08:00
|
|
|
|
<template>
|
2026-02-04 15:23:57 +08:00
|
|
|
|
<page-loading v-if="loading && teams.length === 0" />
|
|
|
|
|
|
<full-page v-else-if="teams.length && team" class="home-container" :pageStyle="pageStyle">
|
2026-04-03 11:24:59 +08:00
|
|
|
|
<!-- <template #header> -->
|
2026-05-19 19:26:16 +08:00
|
|
|
|
<team-head :team="team" :customers="customers" :teams="teams" @changeTeam="changeTeam" />
|
2026-04-03 11:24:59 +08:00
|
|
|
|
<!-- </template> -->
|
2026-02-03 15:42:32 +08:00
|
|
|
|
<view class="home-section home-section--first">
|
2026-05-13 20:38:12 +08:00
|
|
|
|
<customer-archive ref="archiveRef" :corpId="corpId" :corpUserIds="corpUserIds"
|
|
|
|
|
|
:referenceCustomerIds="referenceCustomerIds" :team="team" @update:customers="handleCustomersUpdate" />
|
2026-02-03 15:42:32 +08:00
|
|
|
|
</view>
|
2026-04-02 18:09:06 +08:00
|
|
|
|
<view class="home-section">
|
|
|
|
|
|
<team-guide :team="team" />
|
|
|
|
|
|
</view>
|
2026-02-03 15:42:32 +08:00
|
|
|
|
<view class="home-section">
|
2026-03-04 10:49:25 +08:00
|
|
|
|
<consult ref="consultRef" :corpId="corpId" :teamId="team.teamId" :team="team" :customers="customers" />
|
2026-02-03 15:42:32 +08:00
|
|
|
|
</view>
|
2026-02-05 10:27:20 +08:00
|
|
|
|
<!-- <view class="home-section">
|
2026-02-03 15:42:32 +08:00
|
|
|
|
<team-mate :team="team" />
|
2026-02-05 10:27:20 +08:00
|
|
|
|
</view> -->
|
2026-02-03 15:42:32 +08:00
|
|
|
|
<view class="home-section">
|
|
|
|
|
|
<article-list :team="team" />
|
|
|
|
|
|
</view>
|
2026-01-20 19:36:49 +08:00
|
|
|
|
</full-page>
|
|
|
|
|
|
<yc-home v-else />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
2026-02-12 10:45:53 +08:00
|
|
|
|
import { computed, ref, watch } from "vue";
|
2026-02-04 12:51:45 +08:00
|
|
|
|
import { storeToRefs } from "pinia";
|
2026-05-13 20:38:12 +08:00
|
|
|
|
import { onLoad, onShow, onShareAppMessage } from "@dcloudio/uni-app";
|
2026-02-10 11:08:00 +08:00
|
|
|
|
// import useGuard from "@/hooks/useGuard";
|
2026-02-04 12:51:45 +08:00
|
|
|
|
import useAccount from "@/store/account";
|
|
|
|
|
|
import api from "@/utils/api";
|
|
|
|
|
|
import { toast } from "@/utils/widget";
|
2026-06-23 13:04:28 +08:00
|
|
|
|
import { get, remove, set } from "@/utils/cache";
|
|
|
|
|
|
import { normalizeCorpId } from "@/utils/api-base-config";
|
2026-01-20 19:36:49 +08:00
|
|
|
|
|
2026-02-04 12:51:45 +08:00
|
|
|
|
import FullPage from "@/components/full-page.vue";
|
|
|
|
|
|
import articleList from "./article-list.vue";
|
|
|
|
|
|
import consult from "./consult.vue";
|
|
|
|
|
|
import customerArchive from "./customer-archive.vue";
|
|
|
|
|
|
import teamHead from "./team-head.vue";
|
2026-04-02 18:09:06 +08:00
|
|
|
|
import teamGuide from "./team-guide.vue";
|
|
|
|
|
|
// import teamMate from "./team-mate.vue";
|
2026-02-04 12:51:45 +08:00
|
|
|
|
import ycHome from "./yc-home.vue";
|
|
|
|
|
|
import pageLoading from "./loading.vue";
|
2026-01-20 19:36:49 +08:00
|
|
|
|
|
2026-02-10 11:08:00 +08:00
|
|
|
|
// const { useLoad, useShow } = useGuard();
|
2026-01-20 19:36:49 +08:00
|
|
|
|
const { account } = storeToRefs(useAccount());
|
2026-04-14 16:17:40 +08:00
|
|
|
|
const { login, getTeams } = useAccount();
|
2026-05-13 21:28:42 +08:00
|
|
|
|
const env = __VITE_ENV__;
|
2026-08-18 17:28:42 +08:00
|
|
|
|
const appid = env.MP_WX_APP_ID;
|
2026-05-13 20:38:12 +08:00
|
|
|
|
const shareAppVersion = env.MP_SHARE_WX_APP_VERSION;
|
2026-01-20 19:36:49 +08:00
|
|
|
|
|
|
|
|
|
|
const team = ref(null);
|
|
|
|
|
|
const teams = ref([]);
|
2026-02-10 11:08:00 +08:00
|
|
|
|
const loading = ref(false);
|
2026-01-28 13:38:05 +08:00
|
|
|
|
const customers = ref([]);
|
2026-03-04 17:19:52 +08:00
|
|
|
|
const consultRef = ref(null);
|
|
|
|
|
|
const archiveRef = ref(null);
|
2026-03-05 15:03:07 +08:00
|
|
|
|
const corpUserIds = ref({});
|
2026-05-13 20:38:12 +08:00
|
|
|
|
const referenceCustomerIds = ref({});
|
2026-08-18 17:28:42 +08:00
|
|
|
|
const pendingAction = ref(null);
|
|
|
|
|
|
const awaitingArchiveBinding = ref(false);
|
2026-06-23 13:04:28 +08:00
|
|
|
|
const HOME_CURRENT_TEAM_CACHE_KEY = "home-current-team-info";
|
2026-01-20 19:36:49 +08:00
|
|
|
|
|
|
|
|
|
|
const corpId = computed(() => team.value?.corpId);
|
|
|
|
|
|
|
2026-02-03 15:42:32 +08:00
|
|
|
|
// UI 两段式背景:顶部 281px 渐变 + 下方纯色(按 375 设计稿,281px ≈ 562rpx)
|
|
|
|
|
|
const pageStyle =
|
2026-02-04 12:51:45 +08:00
|
|
|
|
"background: linear-gradient(180deg, #065BD6 15.05%, #F6FAFA 95.37%) 0 0/100% 562rpx no-repeat, #F6FAFA;";
|
2026-02-03 09:59:49 +08:00
|
|
|
|
|
2026-01-28 13:38:05 +08:00
|
|
|
|
function handleCustomersUpdate(newCustomers) {
|
|
|
|
|
|
customers.value = newCustomers;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-23 13:04:28 +08:00
|
|
|
|
function getTeamIdentity(source = {}) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
teamId: source.teamId || "",
|
|
|
|
|
|
corpId: normalizeCorpId(source.corpId || ""),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function cacheCurrentTeam(currentTeam) {
|
|
|
|
|
|
if (!currentTeam || !currentTeam.teamId) return;
|
|
|
|
|
|
set(HOME_CURRENT_TEAM_CACHE_KEY, getTeamIdentity(currentTeam));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function isSameTeam(candidate, target = {}) {
|
|
|
|
|
|
const targetTeamId = target.teamId || "";
|
|
|
|
|
|
if (!candidate || !candidate.teamId || candidate.teamId !== targetTeamId) return false;
|
|
|
|
|
|
|
|
|
|
|
|
const targetCorpId = normalizeCorpId(target.corpId || "");
|
|
|
|
|
|
if (!targetCorpId) return true;
|
|
|
|
|
|
|
|
|
|
|
|
const teamCorpId = normalizeCorpId(candidate.corpId || "");
|
|
|
|
|
|
return targetCorpId === teamCorpId;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-20 19:36:49 +08:00
|
|
|
|
async function changeTeam({ teamId, corpId, corpName }) {
|
|
|
|
|
|
loading.value = true;
|
2026-08-18 17:28:42 +08:00
|
|
|
|
try {
|
|
|
|
|
|
const res = await api("getTeamData", { teamId, corpId });
|
|
|
|
|
|
if (res && res.data) {
|
|
|
|
|
|
team.value = {
|
|
|
|
|
|
...res.data,
|
|
|
|
|
|
corpId: normalizeCorpId(res.data.corpId || corpId),
|
|
|
|
|
|
};
|
|
|
|
|
|
team.value.corpName = corpName;
|
|
|
|
|
|
cacheCurrentTeam(team.value);
|
|
|
|
|
|
return team.value;
|
|
|
|
|
|
}
|
2026-02-04 12:51:45 +08:00
|
|
|
|
toast(res?.message || "获取团队信息失败");
|
2026-08-18 17:28:42 +08:00
|
|
|
|
return null;
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
loading.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function parsePendingAction(options = {}) {
|
|
|
|
|
|
const type = options.type || "";
|
|
|
|
|
|
if (type === "experienceCoupon" && options.issueId && options.corpId) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
type,
|
|
|
|
|
|
corpId: normalizeCorpId(options.corpId),
|
|
|
|
|
|
teamId: options.teamId || "",
|
|
|
|
|
|
issueId: options.issueId,
|
|
|
|
|
|
memberId: options.memberId || options.customerId || "",
|
|
|
|
|
|
couponId: options.couponId || "",
|
|
|
|
|
|
unionid: options.unionid || "",
|
|
|
|
|
|
externalUserId: options.externalUserId || "",
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
if (type === "appointmentRegistration" && options.customerId && options.corpId) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
type,
|
|
|
|
|
|
corpId: normalizeCorpId(options.corpId),
|
|
|
|
|
|
teamId: options.teamId || "",
|
|
|
|
|
|
customerId: options.customerId,
|
|
|
|
|
|
name: options.name || "",
|
|
|
|
|
|
corpName: options.corpName || "",
|
|
|
|
|
|
appointmentId: options.appointmentId || "",
|
|
|
|
|
|
month: options.month || "",
|
|
|
|
|
|
externalUserId: options.externalUserId || "",
|
|
|
|
|
|
corpUserId: options.corpUserId || "",
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function buildActionUrl(action) {
|
|
|
|
|
|
const params = Object.entries(action)
|
|
|
|
|
|
.filter(([key, value]) => key !== "type" && value)
|
|
|
|
|
|
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
|
|
|
|
|
.join("&");
|
|
|
|
|
|
const page = action.type === "experienceCoupon"
|
|
|
|
|
|
? "/pages/experience-coupon/claim"
|
|
|
|
|
|
: "/pages/record/appointment-record";
|
|
|
|
|
|
return `${page}?${params}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function buildArchiveBindUrl(action) {
|
|
|
|
|
|
const customerId = action.memberId || action.customerId;
|
|
|
|
|
|
return [
|
|
|
|
|
|
`/pages/archive/edit-archive?corpId=${encodeURIComponent(action.corpId)}`,
|
|
|
|
|
|
`teamId=${encodeURIComponent(team.value?.teamId || action.teamId)}`,
|
|
|
|
|
|
`bindCustomerId=${encodeURIComponent(customerId)}`,
|
|
|
|
|
|
`source=${encodeURIComponent(action.type)}`,
|
|
|
|
|
|
].join("&");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function continuePendingAction() {
|
|
|
|
|
|
const action = pendingAction.value;
|
|
|
|
|
|
if (!action || !account.value?.openid || !team.value?.teamId) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (action.teamId && action.teamId !== team.value.teamId) {
|
|
|
|
|
|
toast("未找到目标服务团队");
|
|
|
|
|
|
pendingAction.value = null;
|
|
|
|
|
|
return;
|
2026-01-20 19:36:49 +08:00
|
|
|
|
}
|
2026-08-18 17:28:42 +08:00
|
|
|
|
|
|
|
|
|
|
const customerId = action.memberId || action.customerId;
|
|
|
|
|
|
const customerRes = await api(
|
|
|
|
|
|
"getCustomerByCustomerId",
|
|
|
|
|
|
{ corpId: action.corpId, customerId },
|
|
|
|
|
|
false
|
|
|
|
|
|
);
|
|
|
|
|
|
const customer = customerRes?.success ? customerRes.data : null;
|
|
|
|
|
|
if (!customer) {
|
|
|
|
|
|
toast(customerRes?.message || "目标档案不存在");
|
|
|
|
|
|
pendingAction.value = null;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const archiveBound = String(customer.miniAppId || "") === String(account.value.openid);
|
|
|
|
|
|
if (!archiveBound) {
|
|
|
|
|
|
if (awaitingArchiveBinding.value) {
|
|
|
|
|
|
awaitingArchiveBinding.value = false;
|
|
|
|
|
|
pendingAction.value = null;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
awaitingArchiveBinding.value = true;
|
|
|
|
|
|
uni.navigateTo({ url: buildArchiveBindUrl(action) });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pendingAction.value = null;
|
|
|
|
|
|
awaitingArchiveBinding.value = false;
|
|
|
|
|
|
uni.navigateTo({ url: buildActionUrl(action) });
|
2026-01-20 19:36:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-23 13:04:28 +08:00
|
|
|
|
async function getMatchTeams(inviteTeam = null) {
|
2026-01-20 19:36:49 +08:00
|
|
|
|
loading.value = true;
|
2026-08-18 17:28:42 +08:00
|
|
|
|
try {
|
|
|
|
|
|
teams.value = await getTeams();
|
|
|
|
|
|
const inviteIdentity = typeof inviteTeam === "string" ? { teamId: inviteTeam } : (inviteTeam || {});
|
|
|
|
|
|
const cachedIdentity = get(HOME_CURRENT_TEAM_CACHE_KEY) || {};
|
|
|
|
|
|
const targetIdentity = getTeamIdentity({
|
|
|
|
|
|
teamId: inviteIdentity.teamId || team.value?.teamId || cachedIdentity.teamId,
|
|
|
|
|
|
corpId: inviteIdentity.corpId || team.value?.corpId || cachedIdentity.corpId,
|
|
|
|
|
|
});
|
|
|
|
|
|
let validTeam = teams.value.find(i => isSameTeam(i, targetIdentity));
|
|
|
|
|
|
|
|
|
|
|
|
if (!validTeam && pendingAction.value && targetIdentity.teamId && account.value?.openid) {
|
|
|
|
|
|
const bindRes = await api("bindWxappWithTeam", {
|
|
|
|
|
|
appid,
|
|
|
|
|
|
corpId: targetIdentity.corpId,
|
|
|
|
|
|
teamId: targetIdentity.teamId,
|
|
|
|
|
|
openid: account.value.openid,
|
|
|
|
|
|
});
|
|
|
|
|
|
if (bindRes?.success) {
|
|
|
|
|
|
teams.value = await getTeams();
|
|
|
|
|
|
validTeam = teams.value.find(i => isSameTeam(i, targetIdentity));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const firstTeam = teams.value[0];
|
|
|
|
|
|
if (validTeam || firstTeam) {
|
|
|
|
|
|
return await changeTeam(validTeam || firstTeam);
|
|
|
|
|
|
}
|
2026-01-20 19:36:49 +08:00
|
|
|
|
team.value = null;
|
2026-08-18 17:28:42 +08:00
|
|
|
|
return null;
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
loading.value = false;
|
2026-01-20 19:36:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-10 11:08:00 +08:00
|
|
|
|
// useLoad((opts) => {
|
|
|
|
|
|
// if (opts.teamId) {
|
|
|
|
|
|
// team.value = { teamId: opts.teamId, corpId: opts.corpId };
|
|
|
|
|
|
// }
|
|
|
|
|
|
// });
|
2026-01-20 19:36:49 +08:00
|
|
|
|
|
2026-08-18 17:28:42 +08:00
|
|
|
|
onLoad((options = {}) => {
|
|
|
|
|
|
pendingAction.value = parsePendingAction(options);
|
2026-02-10 16:44:01 +08:00
|
|
|
|
if (!account.value) login();
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
onShow(async () => {
|
|
|
|
|
|
if (!account.value) await login();
|
2026-03-05 15:03:07 +08:00
|
|
|
|
const inviteTeam = get('home-invite-team-info');
|
|
|
|
|
|
remove('home-invite-team-info');
|
|
|
|
|
|
if (inviteTeam && inviteTeam.teamId && inviteTeam.corpUserId) {
|
|
|
|
|
|
corpUserIds.value[inviteTeam.teamId] = inviteTeam.corpUserId;
|
|
|
|
|
|
}
|
2026-05-13 20:38:12 +08:00
|
|
|
|
if (inviteTeam && inviteTeam.teamId && inviteTeam.referenceCustomerId) {
|
|
|
|
|
|
referenceCustomerIds.value[inviteTeam.teamId] = inviteTeam.referenceCustomerId;
|
|
|
|
|
|
}
|
2026-02-10 11:08:00 +08:00
|
|
|
|
if (account.value && account.value.openid) {
|
2026-08-18 17:28:42 +08:00
|
|
|
|
const targetTeam = pendingAction.value?.teamId
|
|
|
|
|
|
? { teamId: pendingAction.value.teamId, corpId: pendingAction.value.corpId }
|
|
|
|
|
|
: null;
|
|
|
|
|
|
await getMatchTeams(targetTeam || (inviteTeam && inviteTeam.teamId ? inviteTeam : null));
|
|
|
|
|
|
await continuePendingAction();
|
2026-02-10 11:08:00 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
teams.value = [];
|
|
|
|
|
|
}
|
2026-03-04 10:49:25 +08:00
|
|
|
|
if (consultRef.value && typeof consultRef.value.getBadgeCount === 'function') {
|
|
|
|
|
|
consultRef.value.getBadgeCount()
|
|
|
|
|
|
}
|
2026-03-04 17:19:52 +08:00
|
|
|
|
if (archiveRef.value && typeof archiveRef.value.getCustomers === 'function') {
|
|
|
|
|
|
archiveRef.value.getCustomers()
|
|
|
|
|
|
}
|
2026-02-04 12:51:45 +08:00
|
|
|
|
});
|
2026-03-04 10:49:25 +08:00
|
|
|
|
|
2026-08-18 17:28:42 +08:00
|
|
|
|
onShareAppMessage(() => {
|
2026-05-19 19:26:16 +08:00
|
|
|
|
if (team.value && team.value.supportPatientForward === 'YES') {
|
2026-05-13 20:38:12 +08:00
|
|
|
|
const customer = customers.value[0];
|
|
|
|
|
|
const referenceCustomerId = customer ? customer._id : '';
|
|
|
|
|
|
return {
|
2026-05-28 16:41:53 +08:00
|
|
|
|
title: `【${team.value.name}】这个团队不错,推荐给你!`,
|
2026-05-13 20:38:12 +08:00
|
|
|
|
type: shareAppVersion || 0, // 0 正式版本 | 1 开发版本 | 2 体验版本
|
|
|
|
|
|
path: `/pages/login/redirect-page?teamId=${team.value.teamId}&corpId=${team.value.corpId}&type=archive&referenceCustomerId=${referenceCustomerId}`
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2026-08-18 17:28:42 +08:00
|
|
|
|
watch(account, async (n, o) => {
|
2026-02-12 10:45:53 +08:00
|
|
|
|
if (n && !o) {
|
2026-08-18 17:28:42 +08:00
|
|
|
|
if (!pendingAction.value) await getMatchTeams();
|
2026-02-12 10:45:53 +08:00
|
|
|
|
} else if (!n && o) {
|
|
|
|
|
|
teams.value = [];
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2026-04-14 16:17:40 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-01-20 19:36:49 +08:00
|
|
|
|
</script>
|
2026-02-03 09:59:49 +08:00
|
|
|
|
<style scoped>
|
|
|
|
|
|
.home-container {
|
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
|
}
|
2026-02-03 15:42:32 +08:00
|
|
|
|
|
|
|
|
|
|
.home-section {
|
|
|
|
|
|
margin-top: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.home-section--first {
|
|
|
|
|
|
margin-top: 0;
|
|
|
|
|
|
}
|
2026-02-03 09:59:49 +08:00
|
|
|
|
</style>
|